Changed default options
[mplayer/kovensky.git] / stream / tcp.c
blobc7205faf858a59f596278099002057d242624009
1 /*
2 * Network layer for MPlayer
3 * by Bertrand BAUDET <bertrand_baudet@yahoo.com>
4 * (C) 2001, MPlayer team.
5 */
7 #include <stdlib.h>
8 #include <string.h>
9 #include <unistd.h>
11 #include <errno.h>
12 #include <ctype.h>
14 #include <fcntl.h>
15 #include <sys/time.h>
16 #include <sys/types.h>
18 #include "config.h"
20 #include "mp_msg.h"
21 #include "help_mp.h"
23 #if !HAVE_WINSOCK2_H
24 #include <netdb.h>
25 #include <netinet/in.h>
26 #include <sys/socket.h>
27 #include <arpa/inet.h>
28 #else
29 #include <winsock2.h>
30 #include <ws2tcpip.h>
31 #endif
33 #include "network.h"
34 #include "stream.h"
35 #include "tcp.h"
36 #include "libavutil/avstring.h"
38 /* IPv6 options */
39 int network_prefer_ipv4 =
40 #ifdef _WIN32
42 #else
44 #endif
47 // Converts an address family constant to a string
49 static const char *af2String(int af) {
50 switch (af) {
51 case AF_INET: return "AF_INET";
53 #ifdef HAVE_AF_INET6
54 case AF_INET6: return "AF_INET6";
55 #endif
56 default: return "Unknown address family!";
62 // Connect to a server using a TCP connection, with specified address family
63 // return -2 for fatal error, like unable to resolve name, connection timeout...
64 // return -1 is unable to connect to a particular port
66 static int
67 connect2Server_with_af(char *host, int port, int af,int verb) {
68 int socket_server_fd;
69 int err;
70 socklen_t err_len;
71 int ret,count = 0;
72 fd_set set;
73 struct timeval tv;
74 union {
75 struct sockaddr_in four;
76 #ifdef HAVE_AF_INET6
77 struct sockaddr_in6 six;
78 #endif
79 } server_address;
80 size_t server_address_size;
81 void *our_s_addr; // Pointer to sin_addr or sin6_addr
82 struct hostent *hp=NULL;
83 char buf[255];
85 #if HAVE_WINSOCK2_H
86 unsigned long val;
87 int to;
88 #else
89 struct timeval to;
90 #endif
92 socket_server_fd = socket(af, SOCK_STREAM, 0);
95 if( socket_server_fd==-1 ) {
96 // mp_msg(MSGT_NETWORK,MSGL_ERR,"Failed to create %s socket:\n", af2String(af));
97 return TCP_ERROR_FATAL;
100 #if defined(SO_RCVTIMEO) && defined(SO_SNDTIMEO)
101 #if HAVE_WINSOCK2_H
102 /* timeout in milliseconds */
103 to = 10 * 1000;
104 #else
105 to.tv_sec = 10;
106 to.tv_usec = 0;
107 #endif
108 setsockopt(socket_server_fd, SOL_SOCKET, SO_RCVTIMEO, &to, sizeof(to));
109 setsockopt(socket_server_fd, SOL_SOCKET, SO_SNDTIMEO, &to, sizeof(to));
110 #endif
112 switch (af) {
113 case AF_INET: our_s_addr = (void *) &server_address.four.sin_addr; break;
114 #ifdef HAVE_AF_INET6
115 case AF_INET6: our_s_addr = (void *) &server_address.six.sin6_addr; break;
116 #endif
117 default:
118 mp_tmsg(MSGT_NETWORK,MSGL_ERR, "Unknown address family %d\n", af);
119 return TCP_ERROR_FATAL;
123 memset(&server_address, 0, sizeof(server_address));
125 #if HAVE_INET_PTON
126 if (inet_pton(af, host, our_s_addr)!=1)
127 #elif HAVE_INET_ATON
128 if (inet_aton(host, our_s_addr)!=1)
129 #elif HAVE_WINSOCK2_H
130 if ( inet_addr(host)==INADDR_NONE )
131 #endif
133 if(verb) mp_tmsg(MSGT_NETWORK,MSGL_STATUS,"Resolving %s for %s...\n", host, af2String(af));
135 #ifdef HAVE_GETHOSTBYNAME2
136 hp=(struct hostent*)gethostbyname2( host, af );
137 #else
138 hp=(struct hostent*)gethostbyname( host );
139 #endif
140 if( hp==NULL ) {
141 if(verb) mp_tmsg(MSGT_NETWORK,MSGL_ERR,"Couldn't resolve name for %s: %s\n", af2String(af), host);
142 return TCP_ERROR_FATAL;
145 memcpy( our_s_addr, (void*)hp->h_addr_list[0], hp->h_length );
147 #if HAVE_WINSOCK2_H
148 else {
149 unsigned long addr = inet_addr(host);
150 memcpy( our_s_addr, (void*)&addr, sizeof(addr) );
152 #endif
154 switch (af) {
155 case AF_INET:
156 server_address.four.sin_family=af;
157 server_address.four.sin_port=htons(port);
158 server_address_size = sizeof(server_address.four);
159 break;
160 #ifdef HAVE_AF_INET6
161 case AF_INET6:
162 server_address.six.sin6_family=af;
163 server_address.six.sin6_port=htons(port);
164 server_address_size = sizeof(server_address.six);
165 break;
166 #endif
167 default:
168 mp_tmsg(MSGT_NETWORK,MSGL_ERR, "Unknown address family %d\n", af);
169 return TCP_ERROR_FATAL;
172 #if HAVE_INET_ATON || defined(HAVE_WINSOCK2_H)
173 av_strlcpy( buf, inet_ntoa( *((struct in_addr*)our_s_addr) ), 255);
174 #else
175 inet_ntop(af, our_s_addr, buf, 255);
176 #endif
177 if(verb) mp_tmsg(MSGT_NETWORK,MSGL_STATUS,"Connecting to server %s[%s]: %d...\n", host, buf , port );
179 // Turn the socket as non blocking so we can timeout on the connection
180 #if !HAVE_WINSOCK2_H
181 fcntl( socket_server_fd, F_SETFL, fcntl(socket_server_fd, F_GETFL) | O_NONBLOCK );
182 #else
183 val = 1;
184 ioctlsocket( socket_server_fd, FIONBIO, &val );
185 #endif
186 if( connect( socket_server_fd, (struct sockaddr*)&server_address, server_address_size )==-1 ) {
187 #if !HAVE_WINSOCK2_H
188 if( errno!=EINPROGRESS ) {
189 #else
190 if( (WSAGetLastError() != WSAEINPROGRESS) && (WSAGetLastError() != WSAEWOULDBLOCK) ) {
191 #endif
192 if(verb) mp_tmsg(MSGT_NETWORK,MSGL_ERR,"Failed to connect to server with %s\n", af2String(af));
193 closesocket(socket_server_fd);
194 return TCP_ERROR_PORT;
197 tv.tv_sec = 0;
198 tv.tv_usec = 500000;
199 FD_ZERO( &set );
200 FD_SET( socket_server_fd, &set );
201 // When the connection will be made, we will have a writeable fd
202 while((ret = select(socket_server_fd+1, NULL, &set, NULL, &tv)) == 0) {
203 if(count > 30 || stream_check_interrupt(500)) {
204 if(count > 30)
205 mp_tmsg(MSGT_NETWORK,MSGL_ERR,"connection timeout\n");
206 else
207 mp_msg(MSGT_NETWORK,MSGL_V,"Connection interrupted by user\n");
208 return TCP_ERROR_TIMEOUT;
210 count++;
211 FD_ZERO( &set );
212 FD_SET( socket_server_fd, &set );
213 tv.tv_sec = 0;
214 tv.tv_usec = 500000;
216 if (ret < 0) mp_tmsg(MSGT_NETWORK,MSGL_ERR,"Select failed.\n");
218 // Turn back the socket as blocking
219 #if !HAVE_WINSOCK2_H
220 fcntl( socket_server_fd, F_SETFL, fcntl(socket_server_fd, F_GETFL) & ~O_NONBLOCK );
221 #else
222 val = 0;
223 ioctlsocket( socket_server_fd, FIONBIO, &val );
224 #endif
225 // Check if there were any errors
226 err_len = sizeof(int);
227 ret = getsockopt(socket_server_fd,SOL_SOCKET,SO_ERROR,&err,&err_len);
228 if(ret < 0) {
229 mp_tmsg(MSGT_NETWORK,MSGL_ERR,"getsockopt failed: %s\n",strerror(errno));
230 return TCP_ERROR_FATAL;
232 if(err > 0) {
233 mp_tmsg(MSGT_NETWORK,MSGL_ERR,"connect error: %s\n",strerror(err));
234 return TCP_ERROR_PORT;
237 return socket_server_fd;
240 // Connect to a server using a TCP connection
241 // return -2 for fatal error, like unable to resolve name, connection timeout...
242 // return -1 is unable to connect to a particular port
246 connect2Server(char *host, int port, int verb) {
247 #ifdef HAVE_AF_INET6
248 int r;
249 int s = TCP_ERROR_FATAL;
251 r = connect2Server_with_af(host, port, network_prefer_ipv4 ? AF_INET:AF_INET6,verb);
252 if (r >= 0) return r;
254 s = connect2Server_with_af(host, port, network_prefer_ipv4 ? AF_INET6:AF_INET,verb);
255 if (s == TCP_ERROR_FATAL) return r;
256 return s;
257 #else
258 return connect2Server_with_af(host, port, AF_INET,verb);
259 #endif