Mercurial > mplayer.hg
comparison stream/tcp.c @ 19335:2a9d669e5ff6
isolated tcp socket code from network.c to a dedicated file
author | ben |
---|---|
date | Sat, 05 Aug 2006 10:30:06 +0000 |
parents | |
children | 3f19764369ac |
comparison
equal
deleted
inserted
replaced
19334:c95db0988ded | 19335:2a9d669e5ff6 |
---|---|
1 /* | |
2 * Copyright (C) 2001 Bertrand BAUDET, 2006 Benjamin Zores | |
3 * Network helpers for TCP connections | |
4 * (originally borrowed from network.c, | |
5 * by Bertrand BAUDET <bertrand_baudet@yahoo.com>). | |
6 * | |
7 * This program is free software; you can redistribute it and/or modify | |
8 * it under the terms of the GNU General Public License as published by | |
9 * the Free Software Foundation; either version 2 of the License, or | |
10 * (at your option) any later version. | |
11 * | |
12 * This program is distributed in the hope that it will be useful, | |
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 * GNU General Public License for more details. | |
16 * | |
17 * You should have received a copy of the GNU General Public License | |
18 * along with this program; if not, write to the Free Software Foundation, | |
19 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
20 */ | |
21 | |
22 #include "config.h" | |
23 | |
24 #include <stdlib.h> | |
25 #include <string.h> | |
26 #include <errno.h> | |
27 #include <unistd.h> | |
28 #include <stdlib.h> | |
29 #include <sys/types.h> | |
30 #include <ctype.h> | |
31 #include <netdb.h> | |
32 #include <unistd.h> | |
33 #include <fcntl.h> | |
34 | |
35 #ifndef HAVE_WINSOCK2 | |
36 #include <netinet/in.h> | |
37 #include <sys/socket.h> | |
38 #include <arpa/inet.h> | |
39 #define closesocket close | |
40 #else | |
41 #include <winsock2.h> | |
42 #include <ws2tcpip.h> | |
43 #endif | |
44 | |
45 #include "mp_msg.h" | |
46 #include "help_mp.h" | |
47 #include "tcp.h" | |
48 | |
49 /* IPv6 options */ | |
50 int network_prefer_ipv4 = 0; | |
51 | |
52 /* Converts an address family constant to a string */ | |
53 static const char * | |
54 af2String (int af) | |
55 { | |
56 switch (af) | |
57 { | |
58 case AF_INET: | |
59 return "AF_INET"; | |
60 #ifdef HAVE_AF_INET6 | |
61 case AF_INET6: | |
62 return "AF_INET6"; | |
63 #endif | |
64 default: | |
65 return "Unknown address family!"; | |
66 } | |
67 } | |
68 | |
69 static int | |
70 connect2Server_with_af (char *host, int port, int af ,int verb) | |
71 { | |
72 int socket_server_fd; | |
73 int err; | |
74 socklen_t err_len; | |
75 int ret, count = 0; | |
76 fd_set set; | |
77 struct timeval tv; | |
78 | |
79 union { | |
80 struct sockaddr_in four; | |
81 #ifdef HAVE_AF_INET6 | |
82 struct sockaddr_in6 six; | |
83 #endif | |
84 } server_address; | |
85 | |
86 size_t server_address_size; | |
87 void *our_s_addr; /* Pointer to sin_addr or sin6_addr */ | |
88 struct hostent *hp = NULL; | |
89 char buf[255]; | |
90 | |
91 #ifdef HAVE_WINSOCK2 | |
92 u_long val; | |
93 #endif | |
94 | |
95 socket_server_fd = socket (af, SOCK_STREAM, 0); | |
96 if (socket_server_fd == -1) | |
97 return TCP_ERROR_FATAL; | |
98 | |
99 switch (af) | |
100 { | |
101 case AF_INET: | |
102 our_s_addr = (void *) &server_address.four.sin_addr; | |
103 break; | |
104 #ifdef HAVE_AF_INET6 | |
105 case AF_INET6: | |
106 our_s_addr = (void *) &server_address.six.sin6_addr; | |
107 break; | |
108 #endif | |
109 default: | |
110 mp_msg (MSGT_NETWORK, MSGL_ERR, MSGTR_MPDEMUX_NW_UnknownAF, af); | |
111 return TCP_ERROR_FATAL; | |
112 } | |
113 | |
114 memset (&server_address, 0, sizeof (server_address)); | |
115 | |
116 #ifndef HAVE_WINSOCK2 | |
117 #ifdef USE_ATON | |
118 if (inet_aton (host, our_s_addr) !=1) | |
119 #else | |
120 if (inet_pton (af, host, our_s_addr) !=1) | |
121 #endif /* USE_ATON */ | |
122 #else | |
123 if (inet_addr (host) == INADDR_NONE) | |
124 #endif /* HAVE_WINSOCK2 */ | |
125 { | |
126 if (verb) | |
127 mp_msg (MSGT_NETWORK, MSGL_STATUS, | |
128 MSGTR_MPDEMUX_NW_ResolvingHostForAF, host, af2String (af)); | |
129 | |
130 #ifdef HAVE_GETHOSTBYNAME2 | |
131 hp = (struct hostent *) gethostbyname2 (host, af); | |
132 #else | |
133 hp = (struct hostent *) gethostbyname (host); | |
134 #endif /* HAVE_GETHOSTBYNAME2 */ | |
135 | |
136 if (!hp) | |
137 { | |
138 if (verb) | |
139 mp_msg (MSGT_NETWORK, MSGL_ERR, | |
140 MSGTR_MPDEMUX_NW_CantResolv, af2String (af), host); | |
141 return TCP_ERROR_FATAL; | |
142 } | |
143 | |
144 memcpy (our_s_addr, (void *) hp->h_addr_list[0], hp->h_length); | |
145 } | |
146 #ifdef HAVE_WINSOCK2 | |
147 else | |
148 { | |
149 unsigned long addr = inet_addr (host); | |
150 memcpy (our_s_addr, (void *) &addr, sizeof (addr)); | |
151 } | |
152 #endif /* HAVE_WINSOCK2 */ | |
153 | |
154 switch (af) | |
155 { | |
156 case AF_INET: | |
157 server_address.four.sin_family = af; | |
158 server_address.four.sin_port = htons (port); | |
159 server_address_size = sizeof (server_address.four); | |
160 break; | |
161 #ifdef HAVE_AF_INET6 | |
162 case AF_INET6: | |
163 server_address.six.sin6_family = af; | |
164 server_address.six.sin6_port = htons (port); | |
165 server_address_size = sizeof (server_address.six); | |
166 break; | |
167 #endif /* HAVE_AF_INET6 */ | |
168 default: | |
169 mp_msg (MSGT_NETWORK, MSGL_ERR, MSGTR_MPDEMUX_NW_UnknownAF, af); | |
170 return TCP_ERROR_FATAL; | |
171 } | |
172 | |
173 #if defined(USE_ATON) || defined(HAVE_WINSOCK2) | |
174 strncpy (buf, inet_ntoa (*((struct in_addr *) our_s_addr)), 255); | |
175 #else | |
176 inet_ntop (af, our_s_addr, buf, 255); | |
177 #endif /* USE_ATON || HAVE_WINSOCK2 */ | |
178 | |
179 if (verb) | |
180 mp_msg (MSGT_NETWORK, MSGL_STATUS, | |
181 MSGTR_MPDEMUX_NW_ConnectingToServer, host, buf, port); | |
182 | |
183 /* Turn the socket as non blocking so we can timeout on the connection */ | |
184 #ifndef HAVE_WINSOCK2 | |
185 fcntl (socket_server_fd, F_SETFL, | |
186 fcntl (socket_server_fd, F_GETFL) | O_NONBLOCK); | |
187 #else | |
188 val = 1; | |
189 ioctlsocket (socket_server_fd, FIONBIO, &val); | |
190 #endif /* HAVE_WINSOCK2 */ | |
191 | |
192 if (connect (socket_server_fd, (struct sockaddr *) &server_address, | |
193 server_address_size) == -1) | |
194 { | |
195 #ifndef HAVE_WINSOCK2 | |
196 if (errno != EINPROGRESS) | |
197 #else | |
198 if ((WSAGetLastError () != WSAEINPROGRESS) | |
199 && (WSAGetLastError () != WSAEWOULDBLOCK)) | |
200 #endif /* HAVE_WINSOCK2 */ | |
201 { | |
202 if (verb) | |
203 mp_msg (MSGT_NETWORK, MSGL_ERR, | |
204 MSGTR_MPDEMUX_NW_CantConnect2Server, af2String (af)); | |
205 | |
206 closesocket (socket_server_fd); | |
207 return TCP_ERROR_PORT; | |
208 } | |
209 } | |
210 | |
211 tv.tv_sec = 0; | |
212 tv.tv_usec = 500000; | |
213 | |
214 FD_ZERO (&set); | |
215 FD_SET (socket_server_fd, &set); | |
216 | |
217 /* When the connection will be made, we will have a writable fd */ | |
218 while ((ret = select (socket_server_fd + 1, NULL, &set, NULL, &tv)) == 0) | |
219 { | |
220 if (ret < 0) | |
221 mp_msg (MSGT_NETWORK, MSGL_ERR, MSGTR_MPDEMUX_NW_SelectFailed); | |
222 else if (ret > 0) | |
223 break; | |
224 else if (count > 30 || mp_input_check_interrupt (500)) | |
225 { | |
226 if (count > 30) | |
227 mp_msg (MSGT_NETWORK, MSGL_ERR, MSGTR_MPDEMUX_NW_ConnTimeout); | |
228 else | |
229 mp_msg (MSGT_NETWORK, MSGL_V, "Connection interuppted by user\n"); | |
230 return TCP_ERROR_TIMEOUT; | |
231 } | |
232 | |
233 count++; | |
234 FD_ZERO (&set); | |
235 FD_SET (socket_server_fd, &set); | |
236 tv.tv_sec = 0; | |
237 tv.tv_usec = 500000; | |
238 } | |
239 | |
240 /* Turn back the socket as blocking */ | |
241 #ifndef HAVE_WINSOCK2 | |
242 fcntl (socket_server_fd, F_SETFL, | |
243 fcntl (socket_server_fd, F_GETFL) & ~O_NONBLOCK); | |
244 #else | |
245 val = 0; | |
246 ioctlsocket (socket_server_fd, FIONBIO, &val); | |
247 #endif /* HAVE_WINSOCK2 */ | |
248 | |
249 /* Check if there were any error */ | |
250 err_len = sizeof (int); | |
251 ret = getsockopt (socket_server_fd, SOL_SOCKET, SO_ERROR, &err, &err_len); | |
252 if (ret < 0) | |
253 { | |
254 mp_msg (MSGT_NETWORK, MSGL_ERR, | |
255 MSGTR_MPDEMUX_NW_GetSockOptFailed, strerror (errno)); | |
256 return TCP_ERROR_FATAL; | |
257 } | |
258 | |
259 if (err > 0) | |
260 { | |
261 mp_msg (MSGT_NETWORK, MSGL_ERR, | |
262 MSGTR_MPDEMUX_NW_ConnectError, strerror (err)); | |
263 return TCP_ERROR_PORT; | |
264 } | |
265 | |
266 return socket_server_fd; | |
267 } | |
268 | |
269 int | |
270 connect2Server (char *host, int port, int verb) | |
271 { | |
272 #ifdef HAVE_AF_INET6 | |
273 int r; | |
274 int s = TCP_ERROR_FATAL; | |
275 | |
276 r = connect2Server_with_af (host, port, | |
277 network_prefer_ipv4 ? AF_INET:AF_INET6, verb); | |
278 if (r > TCP_ERROR_PORT) | |
279 return r; | |
280 | |
281 s = connect2Server_with_af (host, port, | |
282 network_prefer_ipv4 ? AF_INET6:AF_INET, verb); | |
283 if (s == TCP_ERROR_FATAL) | |
284 return r; | |
285 | |
286 return s; | |
287 #else | |
288 return connect2Server_with_af (host, port, AF_INET,verb); | |
289 #endif /* HAVE_AF_INET6 */ | |
290 } |