2 * Network layer for MPlayer
3 * by Bertrand BAUDET <bertrand_baudet@yahoo.com>
4 * (C) 2001, MPlayer team.
16 #include <sys/types.h>
25 #include <netinet/in.h>
26 #include <sys/socket.h>
27 #include <arpa/inet.h>
36 #include "libavutil/avstring.h"
39 int network_prefer_ipv4
= 0;
41 // Converts an address family constant to a string
43 static const char *af2String(int af
) {
45 case AF_INET
: return "AF_INET";
48 case AF_INET6
: return "AF_INET6";
50 default: return "Unknown address family!";
56 // Connect to a server using a TCP connection, with specified address family
57 // return -2 for fatal error, like unable to resolve name, connection timeout...
58 // return -1 is unable to connect to a particular port
61 connect2Server_with_af(char *host
, int port
, int af
,int verb
) {
69 struct sockaddr_in four
;
71 struct sockaddr_in6 six
;
74 size_t server_address_size
;
75 void *our_s_addr
; // Pointer to sin_addr or sin6_addr
76 struct hostent
*hp
=NULL
;
86 socket_server_fd
= socket(af
, SOCK_STREAM
, 0);
89 if( socket_server_fd
==-1 ) {
90 // mp_msg(MSGT_NETWORK,MSGL_ERR,"Failed to create %s socket:\n", af2String(af));
91 return TCP_ERROR_FATAL
;
94 #if defined(SO_RCVTIMEO) && defined(SO_SNDTIMEO)
96 /* timeout in milliseconds */
102 setsockopt(socket_server_fd
, SOL_SOCKET
, SO_RCVTIMEO
, &to
, sizeof(to
));
103 setsockopt(socket_server_fd
, SOL_SOCKET
, SO_SNDTIMEO
, &to
, sizeof(to
));
107 case AF_INET
: our_s_addr
= (void *) &server_address
.four
.sin_addr
; break;
109 case AF_INET6
: our_s_addr
= (void *) &server_address
.six
.sin6_addr
; break;
112 mp_tmsg(MSGT_NETWORK
,MSGL_ERR
, "Unknown address family %d\n", af
);
113 return TCP_ERROR_FATAL
;
117 memset(&server_address
, 0, sizeof(server_address
));
120 if (inet_pton(af
, host
, our_s_addr
)!=1)
122 if (inet_aton(host
, our_s_addr
)!=1)
123 #elif HAVE_WINSOCK2_H
124 if ( inet_addr(host
)==INADDR_NONE
)
127 if(verb
) mp_tmsg(MSGT_NETWORK
,MSGL_STATUS
,"Resolving %s for %s...\n", host
, af2String(af
));
129 #ifdef HAVE_GETHOSTBYNAME2
130 hp
=(struct hostent
*)gethostbyname2( host
, af
);
132 hp
=(struct hostent
*)gethostbyname( host
);
135 if(verb
) mp_tmsg(MSGT_NETWORK
,MSGL_ERR
,"Couldn't resolve name for %s: %s\n", af2String(af
), host
);
136 return TCP_ERROR_FATAL
;
139 memcpy( our_s_addr
, (void*)hp
->h_addr_list
[0], hp
->h_length
);
143 unsigned long addr
= inet_addr(host
);
144 memcpy( our_s_addr
, (void*)&addr
, sizeof(addr
) );
150 server_address
.four
.sin_family
=af
;
151 server_address
.four
.sin_port
=htons(port
);
152 server_address_size
= sizeof(server_address
.four
);
156 server_address
.six
.sin6_family
=af
;
157 server_address
.six
.sin6_port
=htons(port
);
158 server_address_size
= sizeof(server_address
.six
);
162 mp_tmsg(MSGT_NETWORK
,MSGL_ERR
, "Unknown address family %d\n", af
);
163 return TCP_ERROR_FATAL
;
166 #if HAVE_INET_ATON || defined(HAVE_WINSOCK2_H)
167 av_strlcpy( buf
, inet_ntoa( *((struct in_addr
*)our_s_addr
) ), 255);
169 inet_ntop(af
, our_s_addr
, buf
, 255);
171 if(verb
) mp_tmsg(MSGT_NETWORK
,MSGL_STATUS
,"Connecting to server %s[%s]: %d...\n", host
, buf
, port
);
173 // Turn the socket as non blocking so we can timeout on the connection
175 fcntl( socket_server_fd
, F_SETFL
, fcntl(socket_server_fd
, F_GETFL
) | O_NONBLOCK
);
178 ioctlsocket( socket_server_fd
, FIONBIO
, &val
);
180 if( connect( socket_server_fd
, (struct sockaddr
*)&server_address
, server_address_size
)==-1 ) {
182 if( errno
!=EINPROGRESS
) {
184 if( (WSAGetLastError() != WSAEINPROGRESS
) && (WSAGetLastError() != WSAEWOULDBLOCK
) ) {
186 if(verb
) mp_tmsg(MSGT_NETWORK
,MSGL_ERR
,"Failed to connect to server with %s\n", af2String(af
));
187 closesocket(socket_server_fd
);
188 return TCP_ERROR_PORT
;
194 FD_SET( socket_server_fd
, &set
);
195 // When the connection will be made, we will have a writeable fd
196 while((ret
= select(socket_server_fd
+1, NULL
, &set
, NULL
, &tv
)) == 0) {
197 if(count
> 30 || stream_check_interrupt(500)) {
199 mp_tmsg(MSGT_NETWORK
,MSGL_ERR
,"connection timeout\n");
201 mp_msg(MSGT_NETWORK
,MSGL_V
,"Connection interrupted by user\n");
202 return TCP_ERROR_TIMEOUT
;
206 FD_SET( socket_server_fd
, &set
);
210 if (ret
< 0) mp_tmsg(MSGT_NETWORK
,MSGL_ERR
,"Select failed.\n");
212 // Turn back the socket as blocking
214 fcntl( socket_server_fd
, F_SETFL
, fcntl(socket_server_fd
, F_GETFL
) & ~O_NONBLOCK
);
217 ioctlsocket( socket_server_fd
, FIONBIO
, &val
);
219 // Check if there were any errors
220 err_len
= sizeof(int);
221 ret
= getsockopt(socket_server_fd
,SOL_SOCKET
,SO_ERROR
,&err
,&err_len
);
223 mp_tmsg(MSGT_NETWORK
,MSGL_ERR
,"getsockopt failed: %s\n",strerror(errno
));
224 return TCP_ERROR_FATAL
;
227 mp_tmsg(MSGT_NETWORK
,MSGL_ERR
,"connect error: %s\n",strerror(err
));
228 return TCP_ERROR_PORT
;
231 return socket_server_fd
;
234 // Connect to a server using a TCP connection
235 // return -2 for fatal error, like unable to resolve name, connection timeout...
236 // return -1 is unable to connect to a particular port
240 connect2Server(char *host
, int port
, int verb
) {
243 int s
= TCP_ERROR_FATAL
;
245 r
= connect2Server_with_af(host
, port
, network_prefer_ipv4
? AF_INET
:AF_INET6
,verb
);
246 if (r
>= 0) return r
;
248 s
= connect2Server_with_af(host
, port
, network_prefer_ipv4
? AF_INET6
:AF_INET
,verb
);
249 if (s
== TCP_ERROR_FATAL
) return r
;
252 return connect2Server_with_af(host
, port
, AF_INET
,verb
);