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>
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
));
119 if (inet_pton(af
, host
, our_s_addr
)!=1)
121 if (inet_aton(host
, our_s_addr
)!=1)
122 #elif HAVE_WINSOCK2_H
123 if ( inet_addr(host
)==INADDR_NONE
)
126 if(verb
) mp_msg(MSGT_NETWORK
,MSGL_STATUS
,MSGTR_MPDEMUX_NW_ResolvingHostForAF
, host
, af2String(af
));
128 #ifdef HAVE_GETHOSTBYNAME2
129 hp
=(struct hostent
*)gethostbyname2( host
, af
);
131 hp
=(struct hostent
*)gethostbyname( host
);
134 if(verb
) mp_msg(MSGT_NETWORK
,MSGL_ERR
,MSGTR_MPDEMUX_NW_CantResolv
, af2String(af
), host
);
135 return TCP_ERROR_FATAL
;
138 memcpy( our_s_addr
, (void*)hp
->h_addr_list
[0], hp
->h_length
);
142 unsigned long addr
= inet_addr(host
);
143 memcpy( our_s_addr
, (void*)&addr
, sizeof(addr
) );
149 server_address
.four
.sin_family
=af
;
150 server_address
.four
.sin_port
=htons(port
);
151 server_address_size
= sizeof(server_address
.four
);
155 server_address
.six
.sin6_family
=af
;
156 server_address
.six
.sin6_port
=htons(port
);
157 server_address_size
= sizeof(server_address
.six
);
161 mp_msg(MSGT_NETWORK
,MSGL_ERR
, MSGTR_MPDEMUX_NW_UnknownAF
, af
);
162 return TCP_ERROR_FATAL
;
165 #if HAVE_INET_ATON || defined(HAVE_WINSOCK2_H)
166 strncpy( buf
, inet_ntoa( *((struct in_addr
*)our_s_addr
) ), 255);
168 inet_ntop(af
, our_s_addr
, buf
, 255);
170 if(verb
) mp_msg(MSGT_NETWORK
,MSGL_STATUS
,MSGTR_MPDEMUX_NW_ConnectingToServer
, host
, buf
, port
);
172 // Turn the socket as non blocking so we can timeout on the connection
174 fcntl( socket_server_fd
, F_SETFL
, fcntl(socket_server_fd
, F_GETFL
) | O_NONBLOCK
);
177 ioctlsocket( socket_server_fd
, FIONBIO
, &val
);
179 if( connect( socket_server_fd
, (struct sockaddr
*)&server_address
, server_address_size
)==-1 ) {
181 if( errno
!=EINPROGRESS
) {
183 if( (WSAGetLastError() != WSAEINPROGRESS
) && (WSAGetLastError() != WSAEWOULDBLOCK
) ) {
185 if(verb
) mp_msg(MSGT_NETWORK
,MSGL_ERR
,MSGTR_MPDEMUX_NW_CantConnect2Server
, af2String(af
));
186 closesocket(socket_server_fd
);
187 return TCP_ERROR_PORT
;
193 FD_SET( socket_server_fd
, &set
);
194 // When the connection will be made, we will have a writeable fd
195 while((ret
= select(socket_server_fd
+1, NULL
, &set
, NULL
, &tv
)) == 0) {
196 if(count
> 30 || stream_check_interrupt(500)) {
198 mp_msg(MSGT_NETWORK
,MSGL_ERR
,MSGTR_MPDEMUX_NW_ConnTimeout
);
200 mp_msg(MSGT_NETWORK
,MSGL_V
,"Connection interrupted by user\n");
201 return TCP_ERROR_TIMEOUT
;
205 FD_SET( socket_server_fd
, &set
);
209 if (ret
< 0) mp_msg(MSGT_NETWORK
,MSGL_ERR
,MSGTR_MPDEMUX_NW_SelectFailed
);
211 // Turn back the socket as blocking
213 fcntl( socket_server_fd
, F_SETFL
, fcntl(socket_server_fd
, F_GETFL
) & ~O_NONBLOCK
);
216 ioctlsocket( socket_server_fd
, FIONBIO
, &val
);
218 // Check if there were any errors
219 err_len
= sizeof(int);
220 ret
= getsockopt(socket_server_fd
,SOL_SOCKET
,SO_ERROR
,&err
,&err_len
);
222 mp_msg(MSGT_NETWORK
,MSGL_ERR
,MSGTR_MPDEMUX_NW_GetSockOptFailed
,strerror(errno
));
223 return TCP_ERROR_FATAL
;
226 mp_msg(MSGT_NETWORK
,MSGL_ERR
,MSGTR_MPDEMUX_NW_ConnectError
,strerror(err
));
227 return TCP_ERROR_PORT
;
230 return socket_server_fd
;
233 // Connect to a server using a TCP connection
234 // return -2 for fatal error, like unable to resolve name, connection timeout...
235 // return -1 is unable to connect to a particular port
239 connect2Server(char *host
, int port
, int verb
) {
242 int s
= TCP_ERROR_FATAL
;
244 r
= connect2Server_with_af(host
, port
, network_prefer_ipv4
? AF_INET
:AF_INET6
,verb
);
245 if (r
>= 0) return r
;
247 s
= connect2Server_with_af(host
, port
, network_prefer_ipv4
? AF_INET6
:AF_INET
,verb
);
248 if (s
== TCP_ERROR_FATAL
) return r
;
251 return connect2Server_with_af(host
, port
, AF_INET
,verb
);