2 * Network layer for MPlayer
3 * by Bertrand BAUDET <bertrand_baudet@yahoo.com>
4 * (C) 2001, MPlayer team.
16 #include <sys/types.h>
22 #include "input/input.h"
26 #include <netinet/in.h>
27 #include <sys/socket.h>
28 #include <arpa/inet.h>
29 #define closesocket close
38 int network_prefer_ipv4
= 0;
40 // Converts an address family constant to a string
42 static const char *af2String(int af
) {
44 case AF_INET
: return "AF_INET";
47 case AF_INET6
: return "AF_INET6";
49 default: return "Unknown address family!";
55 // Connect to a server using a TCP connection, with specified address family
56 // return -2 for fatal error, like unable to resolve name, connection timeout...
57 // return -1 is unable to connect to a particular port
60 connect2Server_with_af(char *host
, int port
, int af
,int verb
) {
68 struct sockaddr_in four
;
70 struct sockaddr_in6 six
;
73 size_t server_address_size
;
74 void *our_s_addr
; // Pointer to sin_addr or sin6_addr
75 struct hostent
*hp
=NULL
;
85 socket_server_fd
= socket(af
, SOCK_STREAM
, 0);
88 if( socket_server_fd
==-1 ) {
89 // mp_msg(MSGT_NETWORK,MSGL_ERR,"Failed to create %s socket:\n", af2String(af));
90 return TCP_ERROR_FATAL
;
93 #if defined(SO_RCVTIMEO) && defined(SO_SNDTIMEO)
95 /* timeout in milliseconds */
101 setsockopt(socket_server_fd
, SOL_SOCKET
, SO_RCVTIMEO
, &to
, sizeof(to
));
102 setsockopt(socket_server_fd
, SOL_SOCKET
, SO_SNDTIMEO
, &to
, sizeof(to
));
106 case AF_INET
: our_s_addr
= (void *) &server_address
.four
.sin_addr
; break;
108 case AF_INET6
: our_s_addr
= (void *) &server_address
.six
.sin6_addr
; break;
111 mp_msg(MSGT_NETWORK
,MSGL_ERR
, MSGTR_MPDEMUX_NW_UnknownAF
, af
);
112 return TCP_ERROR_FATAL
;
116 memset(&server_address
, 0, sizeof(server_address
));
118 #ifndef HAVE_WINSOCK2
120 if (inet_aton(host
, our_s_addr
)!=1)
122 if (inet_pton(af
, host
, our_s_addr
)!=1)
125 if ( inet_addr(host
)==INADDR_NONE
)
128 if(verb
) mp_msg(MSGT_NETWORK
,MSGL_STATUS
,MSGTR_MPDEMUX_NW_ResolvingHostForAF
, host
, af2String(af
));
130 #ifdef HAVE_GETHOSTBYNAME2
131 hp
=(struct hostent
*)gethostbyname2( host
, af
);
133 hp
=(struct hostent
*)gethostbyname( host
);
136 if(verb
) mp_msg(MSGT_NETWORK
,MSGL_ERR
,MSGTR_MPDEMUX_NW_CantResolv
, af2String(af
), host
);
137 return TCP_ERROR_FATAL
;
140 memcpy( our_s_addr
, (void*)hp
->h_addr_list
[0], hp
->h_length
);
144 unsigned long addr
= inet_addr(host
);
145 memcpy( our_s_addr
, (void*)&addr
, sizeof(addr
) );
151 server_address
.four
.sin_family
=af
;
152 server_address
.four
.sin_port
=htons(port
);
153 server_address_size
= sizeof(server_address
.four
);
157 server_address
.six
.sin6_family
=af
;
158 server_address
.six
.sin6_port
=htons(port
);
159 server_address_size
= sizeof(server_address
.six
);
163 mp_msg(MSGT_NETWORK
,MSGL_ERR
, MSGTR_MPDEMUX_NW_UnknownAF
, af
);
164 return TCP_ERROR_FATAL
;
167 #if defined(USE_ATON) || defined(HAVE_WINSOCK2)
168 strncpy( buf
, inet_ntoa( *((struct in_addr
*)our_s_addr
) ), 255);
170 inet_ntop(af
, our_s_addr
, buf
, 255);
172 if(verb
) mp_msg(MSGT_NETWORK
,MSGL_STATUS
,MSGTR_MPDEMUX_NW_ConnectingToServer
, host
, buf
, port
);
174 // Turn the socket as non blocking so we can timeout on the connection
175 #ifndef HAVE_WINSOCK2
176 fcntl( socket_server_fd
, F_SETFL
, fcntl(socket_server_fd
, F_GETFL
) | O_NONBLOCK
);
179 ioctlsocket( socket_server_fd
, FIONBIO
, &val
);
181 if( connect( socket_server_fd
, (struct sockaddr
*)&server_address
, server_address_size
)==-1 ) {
182 #ifndef HAVE_WINSOCK2
183 if( errno
!=EINPROGRESS
) {
185 if( (WSAGetLastError() != WSAEINPROGRESS
) && (WSAGetLastError() != WSAEWOULDBLOCK
) ) {
187 if(verb
) mp_msg(MSGT_NETWORK
,MSGL_ERR
,MSGTR_MPDEMUX_NW_CantConnect2Server
, af2String(af
));
188 closesocket(socket_server_fd
);
189 return TCP_ERROR_PORT
;
195 FD_SET( socket_server_fd
, &set
);
196 // When the connection will be made, we will have a writeable fd
197 while((ret
= select(socket_server_fd
+1, NULL
, &set
, NULL
, &tv
)) == 0) {
198 if(count
> 30 || mp_input_check_interrupt(500)) {
200 mp_msg(MSGT_NETWORK
,MSGL_ERR
,MSGTR_MPDEMUX_NW_ConnTimeout
);
202 mp_msg(MSGT_NETWORK
,MSGL_V
,"Connection interrupted by user\n");
203 return TCP_ERROR_TIMEOUT
;
207 FD_SET( socket_server_fd
, &set
);
211 if (ret
< 0) mp_msg(MSGT_NETWORK
,MSGL_ERR
,MSGTR_MPDEMUX_NW_SelectFailed
);
213 // Turn back the socket as blocking
214 #ifndef HAVE_WINSOCK2
215 fcntl( socket_server_fd
, F_SETFL
, fcntl(socket_server_fd
, F_GETFL
) & ~O_NONBLOCK
);
218 ioctlsocket( socket_server_fd
, FIONBIO
, &val
);
220 // Check if there were any errors
221 err_len
= sizeof(int);
222 ret
= getsockopt(socket_server_fd
,SOL_SOCKET
,SO_ERROR
,&err
,&err_len
);
224 mp_msg(MSGT_NETWORK
,MSGL_ERR
,MSGTR_MPDEMUX_NW_GetSockOptFailed
,strerror(errno
));
225 return TCP_ERROR_FATAL
;
228 mp_msg(MSGT_NETWORK
,MSGL_ERR
,MSGTR_MPDEMUX_NW_ConnectError
,strerror(err
));
229 return TCP_ERROR_PORT
;
232 return socket_server_fd
;
235 // Connect to a server using a TCP connection
236 // return -2 for fatal error, like unable to resolve name, connection timeout...
237 // return -1 is unable to connect to a particular port
241 connect2Server(char *host
, int port
, int verb
) {
244 int s
= TCP_ERROR_FATAL
;
246 r
= connect2Server_with_af(host
, port
, network_prefer_ipv4
? AF_INET
:AF_INET6
,verb
);
247 if (r
>= 0) return r
;
249 s
= connect2Server_with_af(host
, port
, network_prefer_ipv4
? AF_INET6
:AF_INET
,verb
);
250 if (s
== TCP_ERROR_FATAL
) return r
;
253 return connect2Server_with_af(host
, port
, AF_INET
,verb
);