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
=
47 // Converts an address family constant to a string
49 static const char *af2String(int af
) {
51 case AF_INET
: return "AF_INET";
54 case AF_INET6
: return "AF_INET6";
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
67 connect2Server_with_af(char *host
, int port
, int af
,int verb
) {
75 struct sockaddr_in four
;
77 struct sockaddr_in6 six
;
80 size_t server_address_size
;
81 void *our_s_addr
; // Pointer to sin_addr or sin6_addr
82 struct hostent
*hp
=NULL
;
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)
102 /* timeout in milliseconds */
108 setsockopt(socket_server_fd
, SOL_SOCKET
, SO_RCVTIMEO
, &to
, sizeof(to
));
109 setsockopt(socket_server_fd
, SOL_SOCKET
, SO_SNDTIMEO
, &to
, sizeof(to
));
113 case AF_INET
: our_s_addr
= (void *) &server_address
.four
.sin_addr
; break;
115 case AF_INET6
: our_s_addr
= (void *) &server_address
.six
.sin6_addr
; break;
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
));
126 if (inet_pton(af
, host
, our_s_addr
)!=1)
128 if (inet_aton(host
, our_s_addr
)!=1)
129 #elif HAVE_WINSOCK2_H
130 if ( inet_addr(host
)==INADDR_NONE
)
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
);
138 hp
=(struct hostent
*)gethostbyname( host
);
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
);
149 unsigned long addr
= inet_addr(host
);
150 memcpy( our_s_addr
, (void*)&addr
, sizeof(addr
) );
156 server_address
.four
.sin_family
=af
;
157 server_address
.four
.sin_port
=htons(port
);
158 server_address_size
= sizeof(server_address
.four
);
162 server_address
.six
.sin6_family
=af
;
163 server_address
.six
.sin6_port
=htons(port
);
164 server_address_size
= sizeof(server_address
.six
);
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);
175 inet_ntop(af
, our_s_addr
, buf
, 255);
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
181 fcntl( socket_server_fd
, F_SETFL
, fcntl(socket_server_fd
, F_GETFL
) | O_NONBLOCK
);
184 ioctlsocket( socket_server_fd
, FIONBIO
, &val
);
186 if( connect( socket_server_fd
, (struct sockaddr
*)&server_address
, server_address_size
)==-1 ) {
188 if( errno
!=EINPROGRESS
) {
190 if( (WSAGetLastError() != WSAEINPROGRESS
) && (WSAGetLastError() != WSAEWOULDBLOCK
) ) {
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
;
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)) {
205 mp_tmsg(MSGT_NETWORK
,MSGL_ERR
,"connection timeout\n");
207 mp_msg(MSGT_NETWORK
,MSGL_V
,"Connection interrupted by user\n");
208 return TCP_ERROR_TIMEOUT
;
212 FD_SET( socket_server_fd
, &set
);
216 if (ret
< 0) mp_tmsg(MSGT_NETWORK
,MSGL_ERR
,"Select failed.\n");
218 // Turn back the socket as blocking
220 fcntl( socket_server_fd
, F_SETFL
, fcntl(socket_server_fd
, F_GETFL
) & ~O_NONBLOCK
);
223 ioctlsocket( socket_server_fd
, FIONBIO
, &val
);
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
);
229 mp_tmsg(MSGT_NETWORK
,MSGL_ERR
,"getsockopt failed: %s\n",strerror(errno
));
230 return TCP_ERROR_FATAL
;
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
) {
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
;
258 return connect2Server_with_af(host
, port
, AF_INET
,verb
);