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 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
;
82 socket_server_fd
= socket(af
, SOCK_STREAM
, 0);
85 if( socket_server_fd
==-1 ) {
86 // mp_msg(MSGT_NETWORK,MSGL_ERR,"Failed to create %s socket:\n", af2String(af));
87 return TCP_ERROR_FATAL
;
90 #if defined(SO_RCVTIMEO) && defined(SO_SNDTIMEO)
93 setsockopt(socket_server_fd
, SOL_SOCKET
, SO_RCVTIMEO
, &tv
, sizeof(tv
));
94 setsockopt(socket_server_fd
, SOL_SOCKET
, SO_SNDTIMEO
, &tv
, sizeof(tv
));
98 case AF_INET
: our_s_addr
= (void *) &server_address
.four
.sin_addr
; break;
100 case AF_INET6
: our_s_addr
= (void *) &server_address
.six
.sin6_addr
; break;
103 mp_msg(MSGT_NETWORK
,MSGL_ERR
, MSGTR_MPDEMUX_NW_UnknownAF
, af
);
104 return TCP_ERROR_FATAL
;
108 memset(&server_address
, 0, sizeof(server_address
));
110 #ifndef HAVE_WINSOCK2
112 if (inet_aton(host
, our_s_addr
)!=1)
114 if (inet_pton(af
, host
, our_s_addr
)!=1)
117 if ( inet_addr(host
)==INADDR_NONE
)
120 if(verb
) mp_msg(MSGT_NETWORK
,MSGL_STATUS
,MSGTR_MPDEMUX_NW_ResolvingHostForAF
, host
, af2String(af
));
122 #ifdef HAVE_GETHOSTBYNAME2
123 hp
=(struct hostent
*)gethostbyname2( host
, af
);
125 hp
=(struct hostent
*)gethostbyname( host
);
128 if(verb
) mp_msg(MSGT_NETWORK
,MSGL_ERR
,MSGTR_MPDEMUX_NW_CantResolv
, af2String(af
), host
);
129 return TCP_ERROR_FATAL
;
132 memcpy( our_s_addr
, (void*)hp
->h_addr_list
[0], hp
->h_length
);
136 unsigned long addr
= inet_addr(host
);
137 memcpy( our_s_addr
, (void*)&addr
, sizeof(addr
) );
143 server_address
.four
.sin_family
=af
;
144 server_address
.four
.sin_port
=htons(port
);
145 server_address_size
= sizeof(server_address
.four
);
149 server_address
.six
.sin6_family
=af
;
150 server_address
.six
.sin6_port
=htons(port
);
151 server_address_size
= sizeof(server_address
.six
);
155 mp_msg(MSGT_NETWORK
,MSGL_ERR
, MSGTR_MPDEMUX_NW_UnknownAF
, af
);
156 return TCP_ERROR_FATAL
;
159 #if defined(USE_ATON) || defined(HAVE_WINSOCK2)
160 strncpy( buf
, inet_ntoa( *((struct in_addr
*)our_s_addr
) ), 255);
162 inet_ntop(af
, our_s_addr
, buf
, 255);
164 if(verb
) mp_msg(MSGT_NETWORK
,MSGL_STATUS
,MSGTR_MPDEMUX_NW_ConnectingToServer
, host
, buf
, port
);
166 // Turn the socket as non blocking so we can timeout on the connection
167 #ifndef HAVE_WINSOCK2
168 fcntl( socket_server_fd
, F_SETFL
, fcntl(socket_server_fd
, F_GETFL
) | O_NONBLOCK
);
171 ioctlsocket( socket_server_fd
, FIONBIO
, &val
);
173 if( connect( socket_server_fd
, (struct sockaddr
*)&server_address
, server_address_size
)==-1 ) {
174 #ifndef HAVE_WINSOCK2
175 if( errno
!=EINPROGRESS
) {
177 if( (WSAGetLastError() != WSAEINPROGRESS
) && (WSAGetLastError() != WSAEWOULDBLOCK
) ) {
179 if(verb
) mp_msg(MSGT_NETWORK
,MSGL_ERR
,MSGTR_MPDEMUX_NW_CantConnect2Server
, af2String(af
));
180 closesocket(socket_server_fd
);
181 return TCP_ERROR_PORT
;
187 FD_SET( socket_server_fd
, &set
);
188 // When the connection will be made, we will have a writable fd
189 while((ret
= select(socket_server_fd
+1, NULL
, &set
, NULL
, &tv
)) == 0) {
190 if( ret
<0 ) mp_msg(MSGT_NETWORK
,MSGL_ERR
,MSGTR_MPDEMUX_NW_SelectFailed
);
191 else if(ret
> 0) break;
192 else if(count
> 30 || mp_input_check_interrupt(500)) {
194 mp_msg(MSGT_NETWORK
,MSGL_ERR
,MSGTR_MPDEMUX_NW_ConnTimeout
);
196 mp_msg(MSGT_NETWORK
,MSGL_V
,"Connection interuppted by user\n");
197 return TCP_ERROR_TIMEOUT
;
201 FD_SET( socket_server_fd
, &set
);
206 // Turn back the socket as blocking
207 #ifndef HAVE_WINSOCK2
208 fcntl( socket_server_fd
, F_SETFL
, fcntl(socket_server_fd
, F_GETFL
) & ~O_NONBLOCK
);
211 ioctlsocket( socket_server_fd
, FIONBIO
, &val
);
213 // Check if there were any error
214 err_len
= sizeof(int);
215 ret
= getsockopt(socket_server_fd
,SOL_SOCKET
,SO_ERROR
,&err
,&err_len
);
217 mp_msg(MSGT_NETWORK
,MSGL_ERR
,MSGTR_MPDEMUX_NW_GetSockOptFailed
,strerror(errno
));
218 return TCP_ERROR_FATAL
;
221 mp_msg(MSGT_NETWORK
,MSGL_ERR
,MSGTR_MPDEMUX_NW_ConnectError
,strerror(err
));
222 return TCP_ERROR_PORT
;
225 return socket_server_fd
;
228 // Connect to a server using a TCP connection
229 // return -2 for fatal error, like unable to resolve name, connection timeout...
230 // return -1 is unable to connect to a particular port
234 connect2Server(char *host
, int port
, int verb
) {
237 int s
= TCP_ERROR_FATAL
;
239 r
= connect2Server_with_af(host
, port
, network_prefer_ipv4
? AF_INET
:AF_INET6
,verb
);
240 if (r
>= 0) return r
;
242 s
= connect2Server_with_af(host
, port
, network_prefer_ipv4
? AF_INET6
:AF_INET
,verb
);
243 if (s
== TCP_ERROR_FATAL
) return r
;
246 return connect2Server_with_af(host
, port
, AF_INET
,verb
);