19542
|
1 /*
|
|
2 * Network layer for MPlayer
|
|
3 * by Bertrand BAUDET <bertrand_baudet@yahoo.com>
|
|
4 * (C) 2001, MPlayer team.
|
|
5 */
|
|
6
|
|
7 #include <stdlib.h>
|
|
8 #include <string.h>
|
|
9 #include <unistd.h>
|
|
10
|
|
11 #include <errno.h>
|
|
12 #include <ctype.h>
|
|
13
|
|
14 #include <fcntl.h>
|
|
15 #include <sys/time.h>
|
|
16 #include <sys/types.h>
|
|
17
|
|
18 #include "config.h"
|
|
19
|
|
20 #include "mp_msg.h"
|
|
21 #include "help_mp.h"
|
|
22
|
|
23 #ifndef HAVE_WINSOCK2
|
|
24 #include <netdb.h>
|
|
25 #include <netinet/in.h>
|
|
26 #include <sys/socket.h>
|
|
27 #include <arpa/inet.h>
|
|
28 #define closesocket close
|
|
29 #else
|
|
30 #include <winsock2.h>
|
|
31 #include <ws2tcpip.h>
|
|
32 #endif
|
|
33
|
|
34 #include "tcp.h"
|
|
35
|
|
36 /* IPv6 options */
|
|
37 int network_prefer_ipv4 = 0;
|
|
38
|
|
39 // Converts an address family constant to a string
|
|
40
|
|
41 const char *af2String(int af) {
|
|
42 switch (af) {
|
|
43 case AF_INET: return "AF_INET";
|
|
44
|
|
45 #ifdef HAVE_AF_INET6
|
|
46 case AF_INET6: return "AF_INET6";
|
|
47 #endif
|
|
48 default: return "Unknown address family!";
|
|
49 }
|
|
50 }
|
|
51
|
|
52
|
|
53
|
|
54 // Connect to a server using a TCP connection, with specified address family
|
|
55 // return -2 for fatal error, like unable to resolve name, connection timeout...
|
|
56 // return -1 is unable to connect to a particular port
|
|
57
|
|
58 int
|
|
59 connect2Server_with_af(char *host, int port, int af,int verb) {
|
|
60 int socket_server_fd;
|
|
61 int err;
|
|
62 socklen_t err_len;
|
|
63 int ret,count = 0;
|
|
64 fd_set set;
|
|
65 struct timeval tv;
|
|
66 union {
|
|
67 struct sockaddr_in four;
|
|
68 #ifdef HAVE_AF_INET6
|
|
69 struct sockaddr_in6 six;
|
|
70 #endif
|
|
71 } server_address;
|
|
72 size_t server_address_size;
|
|
73 void *our_s_addr; // Pointer to sin_addr or sin6_addr
|
|
74 struct hostent *hp=NULL;
|
|
75 char buf[255];
|
|
76
|
|
77 #ifdef HAVE_WINSOCK2
|
|
78 u_long val;
|
|
79 #endif
|
|
80
|
|
81 socket_server_fd = socket(af, SOCK_STREAM, 0);
|
|
82
|
|
83
|
|
84 if( socket_server_fd==-1 ) {
|
|
85 // mp_msg(MSGT_NETWORK,MSGL_ERR,"Failed to create %s socket:\n", af2String(af));
|
|
86 return -2;
|
|
87 }
|
|
88
|
|
89 switch (af) {
|
|
90 case AF_INET: our_s_addr = (void *) &server_address.four.sin_addr; break;
|
|
91 #ifdef HAVE_AF_INET6
|
|
92 case AF_INET6: our_s_addr = (void *) &server_address.six.sin6_addr; break;
|
|
93 #endif
|
|
94 default:
|
|
95 mp_msg(MSGT_NETWORK,MSGL_ERR, MSGTR_MPDEMUX_NW_UnknownAF, af);
|
|
96 return -2;
|
|
97 }
|
|
98
|
|
99
|
|
100 memset(&server_address, 0, sizeof(server_address));
|
|
101
|
|
102 #ifndef HAVE_WINSOCK2
|
|
103 #ifdef USE_ATON
|
|
104 if (inet_aton(host, our_s_addr)!=1)
|
|
105 #else
|
|
106 if (inet_pton(af, host, our_s_addr)!=1)
|
|
107 #endif
|
|
108 #else
|
|
109 if ( inet_addr(host)==INADDR_NONE )
|
|
110 #endif
|
|
111 {
|
|
112 if(verb) mp_msg(MSGT_NETWORK,MSGL_STATUS,MSGTR_MPDEMUX_NW_ResolvingHostForAF, host, af2String(af));
|
|
113
|
|
114 #ifdef HAVE_GETHOSTBYNAME2
|
|
115 hp=(struct hostent*)gethostbyname2( host, af );
|
|
116 #else
|
|
117 hp=(struct hostent*)gethostbyname( host );
|
|
118 #endif
|
|
119 if( hp==NULL ) {
|
|
120 if(verb) mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_NW_CantResolv, af2String(af), host);
|
|
121 return -2;
|
|
122 }
|
|
123
|
|
124 memcpy( our_s_addr, (void*)hp->h_addr_list[0], hp->h_length );
|
|
125 }
|
|
126 #ifdef HAVE_WINSOCK2
|
|
127 else {
|
|
128 unsigned long addr = inet_addr(host);
|
|
129 memcpy( our_s_addr, (void*)&addr, sizeof(addr) );
|
|
130 }
|
|
131 #endif
|
|
132
|
|
133 switch (af) {
|
|
134 case AF_INET:
|
|
135 server_address.four.sin_family=af;
|
|
136 server_address.four.sin_port=htons(port);
|
|
137 server_address_size = sizeof(server_address.four);
|
|
138 break;
|
|
139 #ifdef HAVE_AF_INET6
|
|
140 case AF_INET6:
|
|
141 server_address.six.sin6_family=af;
|
|
142 server_address.six.sin6_port=htons(port);
|
|
143 server_address_size = sizeof(server_address.six);
|
|
144 break;
|
|
145 #endif
|
|
146 default:
|
|
147 mp_msg(MSGT_NETWORK,MSGL_ERR, MSGTR_MPDEMUX_NW_UnknownAF, af);
|
|
148 return -2;
|
|
149 }
|
|
150
|
|
151 #if defined(USE_ATON) || defined(HAVE_WINSOCK2)
|
|
152 strncpy( buf, inet_ntoa( *((struct in_addr*)our_s_addr) ), 255);
|
|
153 #else
|
|
154 inet_ntop(af, our_s_addr, buf, 255);
|
|
155 #endif
|
|
156 if(verb) mp_msg(MSGT_NETWORK,MSGL_STATUS,MSGTR_MPDEMUX_NW_ConnectingToServer, host, buf , port );
|
|
157
|
|
158 // Turn the socket as non blocking so we can timeout on the connection
|
|
159 #ifndef HAVE_WINSOCK2
|
|
160 fcntl( socket_server_fd, F_SETFL, fcntl(socket_server_fd, F_GETFL) | O_NONBLOCK );
|
|
161 #else
|
|
162 val = 1;
|
|
163 ioctlsocket( socket_server_fd, FIONBIO, &val );
|
|
164 #endif
|
|
165 if( connect( socket_server_fd, (struct sockaddr*)&server_address, server_address_size )==-1 ) {
|
|
166 #ifndef HAVE_WINSOCK2
|
|
167 if( errno!=EINPROGRESS ) {
|
|
168 #else
|
|
169 if( (WSAGetLastError() != WSAEINPROGRESS) && (WSAGetLastError() != WSAEWOULDBLOCK) ) {
|
|
170 #endif
|
|
171 if(verb) mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_NW_CantConnect2Server, af2String(af));
|
|
172 closesocket(socket_server_fd);
|
|
173 return -1;
|
|
174 }
|
|
175 }
|
|
176 tv.tv_sec = 0;
|
|
177 tv.tv_usec = 500000;
|
|
178 FD_ZERO( &set );
|
|
179 FD_SET( socket_server_fd, &set );
|
|
180 // When the connection will be made, we will have a writable fd
|
|
181 while((ret = select(socket_server_fd+1, NULL, &set, NULL, &tv)) == 0) {
|
|
182 if( ret<0 ) mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_NW_SelectFailed);
|
|
183 else if(ret > 0) break;
|
|
184 else if(count > 30 || mp_input_check_interrupt(500)) {
|
|
185 if(count > 30)
|
|
186 mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_NW_ConnTimeout);
|
|
187 else
|
|
188 mp_msg(MSGT_NETWORK,MSGL_V,"Connection interuppted by user\n");
|
|
189 return -3;
|
|
190 }
|
|
191 count++;
|
|
192 FD_ZERO( &set );
|
|
193 FD_SET( socket_server_fd, &set );
|
|
194 tv.tv_sec = 0;
|
|
195 tv.tv_usec = 500000;
|
|
196 }
|
|
197
|
|
198 // Turn back the socket as blocking
|
|
199 #ifndef HAVE_WINSOCK2
|
|
200 fcntl( socket_server_fd, F_SETFL, fcntl(socket_server_fd, F_GETFL) & ~O_NONBLOCK );
|
|
201 #else
|
|
202 val = 0;
|
|
203 ioctlsocket( socket_server_fd, FIONBIO, &val );
|
|
204 #endif
|
|
205 // Check if there were any error
|
|
206 err_len = sizeof(int);
|
|
207 ret = getsockopt(socket_server_fd,SOL_SOCKET,SO_ERROR,&err,&err_len);
|
|
208 if(ret < 0) {
|
|
209 mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_NW_GetSockOptFailed,strerror(errno));
|
|
210 return -2;
|
|
211 }
|
|
212 if(err > 0) {
|
|
213 mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_NW_ConnectError,strerror(err));
|
|
214 return -1;
|
|
215 }
|
|
216
|
|
217 return socket_server_fd;
|
|
218 }
|
|
219
|
|
220 // Connect to a server using a TCP connection
|
|
221 // return -2 for fatal error, like unable to resolve name, connection timeout...
|
|
222 // return -1 is unable to connect to a particular port
|
|
223
|
|
224
|
|
225 int
|
|
226 connect2Server(char *host, int port, int verb) {
|
|
227 #ifdef HAVE_AF_INET6
|
|
228 int r;
|
|
229 int s = -2;
|
|
230
|
|
231 r = connect2Server_with_af(host, port, network_prefer_ipv4 ? AF_INET:AF_INET6,verb);
|
|
232 if (r > -1) return r;
|
|
233
|
|
234 s = connect2Server_with_af(host, port, network_prefer_ipv4 ? AF_INET6:AF_INET,verb);
|
|
235 if (s == -2) return r;
|
|
236 return s;
|
|
237 #else
|
|
238 return connect2Server_with_af(host, port, AF_INET,verb);
|
|
239 #endif
|
|
240
|
|
241
|
|
242 }
|