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 }