diff options
Diffstat (limited to 'common/socket.c')
-rw-r--r-- | common/socket.c | 1169 |
1 files changed, 0 insertions, 1169 deletions
diff --git a/common/socket.c b/common/socket.c deleted file mode 100644 index 99a96b1..0000000 --- a/common/socket.c +++ /dev/null | |||
@@ -1,1169 +0,0 @@ | |||
1 | /* | ||
2 | * socket.c | ||
3 | * | ||
4 | * Copyright (C) 2012-2020 Nikias Bassen <nikias@gmx.li> | ||
5 | * Copyright (C) 2012 Martin Szulecki <m.szulecki@libimobiledevice.org> | ||
6 | * | ||
7 | * This library is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU Lesser General Public | ||
9 | * License as published by the Free Software Foundation; either | ||
10 | * version 2.1 of the License, or (at your option) any later version. | ||
11 | * | ||
12 | * This library 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 GNU | ||
15 | * Lesser General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU Lesser General Public | ||
18 | * License along with this library; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
20 | */ | ||
21 | |||
22 | #ifdef HAVE_CONFIG_H | ||
23 | #include <config.h> | ||
24 | #endif | ||
25 | #include <stdio.h> | ||
26 | #include <stddef.h> | ||
27 | #include <stdlib.h> | ||
28 | #include <string.h> | ||
29 | #include <unistd.h> | ||
30 | #include <errno.h> | ||
31 | #include <sys/time.h> | ||
32 | #include <sys/stat.h> | ||
33 | #ifdef WIN32 | ||
34 | #include <winsock2.h> | ||
35 | #include <ws2tcpip.h> | ||
36 | #include <windows.h> | ||
37 | #ifndef HAVE_GETIFADDRS | ||
38 | #include <iphlpapi.h> | ||
39 | #endif | ||
40 | static int wsa_init = 0; | ||
41 | #ifndef IFF_RUNNING | ||
42 | #define IFF_RUNNING IFF_UP | ||
43 | #endif | ||
44 | #ifndef AI_NUMERICSERV | ||
45 | #define AI_NUMERICSERV 0 | ||
46 | #endif | ||
47 | #else | ||
48 | #include <sys/socket.h> | ||
49 | #include <sys/un.h> | ||
50 | #include <netinet/in.h> | ||
51 | #include <netinet/tcp.h> | ||
52 | #include <netdb.h> | ||
53 | #include <arpa/inet.h> | ||
54 | #include <fcntl.h> | ||
55 | #ifdef AF_INET6 | ||
56 | #include <net/if.h> | ||
57 | #include <ifaddrs.h> | ||
58 | #endif | ||
59 | #endif | ||
60 | #include "socket.h" | ||
61 | |||
62 | #define RECV_TIMEOUT 20000 | ||
63 | #define SEND_TIMEOUT 10000 | ||
64 | #define CONNECT_TIMEOUT 5000 | ||
65 | |||
66 | #ifndef EAFNOSUPPORT | ||
67 | #define EAFNOSUPPORT 102 | ||
68 | #endif | ||
69 | #ifndef ECONNRESET | ||
70 | #define ECONNRESET 108 | ||
71 | #endif | ||
72 | #ifndef ETIMEDOUT | ||
73 | #define ETIMEDOUT 138 | ||
74 | #endif | ||
75 | |||
76 | static int verbose = 0; | ||
77 | |||
78 | void socket_set_verbose(int level) | ||
79 | { | ||
80 | verbose = level; | ||
81 | } | ||
82 | |||
83 | const char *socket_addr_to_string(struct sockaddr *addr, char *addr_out, size_t addr_out_size) | ||
84 | { | ||
85 | #ifdef WIN32 | ||
86 | WSADATA wsa_data; | ||
87 | if (!wsa_init) { | ||
88 | if (WSAStartup(MAKEWORD(2,2), &wsa_data) != ERROR_SUCCESS) { | ||
89 | fprintf(stderr, "WSAStartup failed!\n"); | ||
90 | ExitProcess(-1); | ||
91 | } | ||
92 | wsa_init = 1; | ||
93 | } | ||
94 | DWORD addr_out_len = addr_out_size; | ||
95 | DWORD addrlen = 0; | ||
96 | |||
97 | if (addr->sa_family == AF_INET) { | ||
98 | addrlen = sizeof(struct sockaddr_in); | ||
99 | } | ||
100 | #ifdef AF_INET6 | ||
101 | else if (addr->sa_family == AF_INET6) { | ||
102 | addrlen = sizeof(struct sockaddr_in6); | ||
103 | } | ||
104 | #endif | ||
105 | else { | ||
106 | errno = EAFNOSUPPORT; | ||
107 | return NULL; | ||
108 | } | ||
109 | |||
110 | if (WSAAddressToString(addr, addrlen, NULL, addr_out, &addr_out_len) == 0) { | ||
111 | return addr_out; | ||
112 | } | ||
113 | #else | ||
114 | const void *addrdata = NULL; | ||
115 | |||
116 | if (addr->sa_family == AF_INET) { | ||
117 | addrdata = &((struct sockaddr_in*)addr)->sin_addr; | ||
118 | } | ||
119 | #ifdef AF_INET6 | ||
120 | else if (addr->sa_family == AF_INET6) { | ||
121 | addrdata = &((struct sockaddr_in6*)addr)->sin6_addr; | ||
122 | } | ||
123 | #endif | ||
124 | else { | ||
125 | errno = EAFNOSUPPORT; | ||
126 | return NULL; | ||
127 | } | ||
128 | |||
129 | if (inet_ntop(addr->sa_family, addrdata, addr_out, addr_out_size)) { | ||
130 | return addr_out; | ||
131 | } | ||
132 | #endif | ||
133 | return NULL; | ||
134 | } | ||
135 | |||
136 | #ifndef WIN32 | ||
137 | int socket_create_unix(const char *filename) | ||
138 | { | ||
139 | struct sockaddr_un name; | ||
140 | int sock; | ||
141 | #ifdef SO_NOSIGPIPE | ||
142 | int yes = 1; | ||
143 | #endif | ||
144 | |||
145 | // remove if still present | ||
146 | unlink(filename); | ||
147 | |||
148 | /* Create the socket. */ | ||
149 | sock = socket(PF_UNIX, SOCK_STREAM, 0); | ||
150 | if (sock < 0) { | ||
151 | perror("socket"); | ||
152 | return -1; | ||
153 | } | ||
154 | |||
155 | #ifdef SO_NOSIGPIPE | ||
156 | if (setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, (void*)&yes, sizeof(int)) == -1) { | ||
157 | perror("setsockopt()"); | ||
158 | socket_close(sock); | ||
159 | return -1; | ||
160 | } | ||
161 | #endif | ||
162 | |||
163 | /* Bind a name to the socket. */ | ||
164 | name.sun_family = AF_UNIX; | ||
165 | strncpy(name.sun_path, filename, sizeof(name.sun_path)); | ||
166 | name.sun_path[sizeof(name.sun_path) - 1] = '\0'; | ||
167 | |||
168 | if (bind(sock, (struct sockaddr*)&name, sizeof(name)) < 0) { | ||
169 | perror("bind"); | ||
170 | socket_close(sock); | ||
171 | return -1; | ||
172 | } | ||
173 | |||
174 | if (listen(sock, 100) < 0) { | ||
175 | perror("listen"); | ||
176 | socket_close(sock); | ||
177 | return -1; | ||
178 | } | ||
179 | |||
180 | return sock; | ||
181 | } | ||
182 | |||
183 | int socket_connect_unix(const char *filename) | ||
184 | { | ||
185 | struct sockaddr_un name; | ||
186 | int sfd = -1; | ||
187 | struct stat fst; | ||
188 | #ifdef SO_NOSIGPIPE | ||
189 | int yes = 1; | ||
190 | #endif | ||
191 | int bufsize = 0x20000; | ||
192 | |||
193 | // check if socket file exists... | ||
194 | if (stat(filename, &fst) != 0) { | ||
195 | if (verbose >= 2) | ||
196 | fprintf(stderr, "%s: stat '%s': %s\n", __func__, filename, | ||
197 | strerror(errno)); | ||
198 | return -1; | ||
199 | } | ||
200 | // ... and if it is a unix domain socket | ||
201 | if (!S_ISSOCK(fst.st_mode)) { | ||
202 | if (verbose >= 2) | ||
203 | fprintf(stderr, "%s: File '%s' is not a socket!\n", __func__, | ||
204 | filename); | ||
205 | return -1; | ||
206 | } | ||
207 | // make a new socket | ||
208 | if ((sfd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { | ||
209 | if (verbose >= 2) | ||
210 | fprintf(stderr, "%s: socket: %s\n", __func__, strerror(errno)); | ||
211 | return -1; | ||
212 | } | ||
213 | |||
214 | if (setsockopt(sfd, SOL_SOCKET, SO_SNDBUF, (void*)&bufsize, sizeof(int)) == -1) { | ||
215 | perror("Could not set send buffer for socket"); | ||
216 | } | ||
217 | |||
218 | if (setsockopt(sfd, SOL_SOCKET, SO_RCVBUF, (void*)&bufsize, sizeof(int)) == -1) { | ||
219 | perror("Could not set receive buffer for socket"); | ||
220 | } | ||
221 | |||
222 | #ifdef SO_NOSIGPIPE | ||
223 | if (setsockopt(sfd, SOL_SOCKET, SO_NOSIGPIPE, (void*)&yes, sizeof(int)) == -1) { | ||
224 | perror("setsockopt()"); | ||
225 | socket_close(sfd); | ||
226 | return -1; | ||
227 | } | ||
228 | #endif | ||
229 | // and connect to 'filename' | ||
230 | name.sun_family = AF_UNIX; | ||
231 | strncpy(name.sun_path, filename, sizeof(name.sun_path)); | ||
232 | name.sun_path[sizeof(name.sun_path) - 1] = 0; | ||
233 | |||
234 | int flags = fcntl(sfd, F_GETFL, 0); | ||
235 | fcntl(sfd, F_SETFL, flags | O_NONBLOCK); | ||
236 | |||
237 | do { | ||
238 | if (connect(sfd, (struct sockaddr*)&name, sizeof(name)) != -1) { | ||
239 | break; | ||
240 | } | ||
241 | if (errno == EINPROGRESS) { | ||
242 | fd_set fds; | ||
243 | FD_ZERO(&fds); | ||
244 | FD_SET(sfd, &fds); | ||
245 | |||
246 | struct timeval timeout; | ||
247 | timeout.tv_sec = CONNECT_TIMEOUT / 1000; | ||
248 | timeout.tv_usec = (CONNECT_TIMEOUT - (timeout.tv_sec * 1000)) * 1000; | ||
249 | if (select(sfd + 1, NULL, &fds, NULL, &timeout) == 1) { | ||
250 | int so_error; | ||
251 | socklen_t len = sizeof(so_error); | ||
252 | getsockopt(sfd, SOL_SOCKET, SO_ERROR, (void*)&so_error, &len); | ||
253 | if (so_error == 0) { | ||
254 | break; | ||
255 | } | ||
256 | } | ||
257 | } | ||
258 | socket_close(sfd); | ||
259 | sfd = -1; | ||
260 | } while (0); | ||
261 | |||
262 | if (sfd < 0) { | ||
263 | if (verbose >= 2) | ||
264 | fprintf(stderr, "%s: connect: %s\n", __func__, strerror(errno)); | ||
265 | return -1; | ||
266 | } | ||
267 | |||
268 | return sfd; | ||
269 | } | ||
270 | #endif | ||
271 | |||
272 | int socket_create(const char* addr, uint16_t port) | ||
273 | { | ||
274 | int sfd = -1; | ||
275 | int yes = 1; | ||
276 | struct addrinfo hints; | ||
277 | struct addrinfo *result, *rp; | ||
278 | char portstr[8]; | ||
279 | int res; | ||
280 | #ifdef WIN32 | ||
281 | WSADATA wsa_data; | ||
282 | if (!wsa_init) { | ||
283 | if (WSAStartup(MAKEWORD(2,2), &wsa_data) != ERROR_SUCCESS) { | ||
284 | fprintf(stderr, "WSAStartup failed!\n"); | ||
285 | ExitProcess(-1); | ||
286 | } | ||
287 | wsa_init = 1; | ||
288 | } | ||
289 | #endif | ||
290 | |||
291 | memset(&hints, '\0', sizeof(struct addrinfo)); | ||
292 | hints.ai_family = AF_UNSPEC; | ||
293 | hints.ai_socktype = SOCK_STREAM; | ||
294 | hints.ai_flags = AI_PASSIVE | AI_NUMERICSERV; | ||
295 | hints.ai_protocol = IPPROTO_TCP; | ||
296 | |||
297 | sprintf(portstr, "%d", port); | ||
298 | |||
299 | if (!addr) { | ||
300 | addr = "localhost"; | ||
301 | } | ||
302 | res = getaddrinfo(addr, portstr, &hints, &result); | ||
303 | if (res != 0) { | ||
304 | fprintf(stderr, "%s: getaddrinfo: %s\n", __func__, gai_strerror(res)); | ||
305 | return -1; | ||
306 | } | ||
307 | |||
308 | for (rp = result; rp != NULL; rp = rp->ai_next) { | ||
309 | sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); | ||
310 | if (sfd == -1) { | ||
311 | continue; | ||
312 | } | ||
313 | |||
314 | if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (void*)&yes, sizeof(int)) == -1) { | ||
315 | perror("setsockopt()"); | ||
316 | socket_close(sfd); | ||
317 | continue; | ||
318 | } | ||
319 | |||
320 | #ifdef SO_NOSIGPIPE | ||
321 | if (setsockopt(sfd, SOL_SOCKET, SO_NOSIGPIPE, (void*)&yes, sizeof(int)) == -1) { | ||
322 | perror("setsockopt()"); | ||
323 | socket_close(sfd); | ||
324 | continue; | ||
325 | } | ||
326 | #endif | ||
327 | |||
328 | #if defined(AF_INET6) && defined(IPV6_V6ONLY) | ||
329 | if (rp->ai_family == AF_INET6) { | ||
330 | if (setsockopt(sfd, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&yes, sizeof(int)) == -1) { | ||
331 | perror("setsockopt() IPV6_V6ONLY"); | ||
332 | } | ||
333 | } | ||
334 | #endif | ||
335 | |||
336 | if (bind(sfd, rp->ai_addr, rp->ai_addrlen) < 0) { | ||
337 | perror("bind()"); | ||
338 | socket_close(sfd); | ||
339 | continue; | ||
340 | } | ||
341 | |||
342 | if (listen(sfd, 100) < 0) { | ||
343 | perror("listen()"); | ||
344 | socket_close(sfd); | ||
345 | continue; | ||
346 | } | ||
347 | break; | ||
348 | } | ||
349 | |||
350 | freeaddrinfo(result); | ||
351 | |||
352 | if (rp == NULL) { | ||
353 | return -1; | ||
354 | } | ||
355 | |||
356 | return sfd; | ||
357 | } | ||
358 | |||
359 | #ifdef AF_INET6 | ||
360 | static uint32_t _in6_addr_scope(struct in6_addr* addr) | ||
361 | { | ||
362 | uint32_t scope = 0; | ||
363 | |||
364 | if (IN6_IS_ADDR_MULTICAST(addr)) { | ||
365 | if (IN6_IS_ADDR_MC_NODELOCAL(addr)) { | ||
366 | scope = 1; | ||
367 | } else if (IN6_IS_ADDR_MC_LINKLOCAL(addr)) { | ||
368 | scope = 2; | ||
369 | } else if (IN6_IS_ADDR_MC_SITELOCAL(addr)) { | ||
370 | scope = 5; | ||
371 | } | ||
372 | |||
373 | return scope; | ||
374 | } | ||
375 | |||
376 | if (IN6_IS_ADDR_LINKLOCAL(addr)) { | ||
377 | scope = 2; | ||
378 | } else if (IN6_IS_ADDR_LOOPBACK(addr)) { | ||
379 | scope = 2; | ||
380 | } else if (IN6_IS_ADDR_SITELOCAL(addr)) { | ||
381 | scope = 5; | ||
382 | } else if (IN6_IS_ADDR_UNSPECIFIED(addr)) { | ||
383 | scope = 0; | ||
384 | } | ||
385 | |||
386 | return scope; | ||
387 | } | ||
388 | |||
389 | #ifndef HAVE_GETIFADDRS | ||
390 | #ifdef WIN32 | ||
391 | |||
392 | struct ifaddrs { | ||
393 | struct ifaddrs *ifa_next; /* Next item in list */ | ||
394 | char *ifa_name; /* Name of interface */ | ||
395 | unsigned int ifa_flags; /* Flags from SIOCGIFFLAGS */ | ||
396 | struct sockaddr *ifa_addr; /* Address of interface */ | ||
397 | struct sockaddr *ifa_netmask; /* Netmask of interface */ | ||
398 | union { | ||
399 | struct sockaddr *ifu_broadaddr; /* Broadcast address of interface */ | ||
400 | struct sockaddr *ifu_dstaddr; /* Point-to-point destination address */ | ||
401 | } ifa_ifu; | ||
402 | #define ifa_broadaddr ifa_ifu.ifu_broadaddr | ||
403 | #define ifa_dstaddr ifa_ifu.ifu_dstaddr | ||
404 | void *ifa_data; /* Address-specific data */ | ||
405 | }; | ||
406 | |||
407 | #define WORKING_BUFFER_SIZE 15000 | ||
408 | #define MAX_TRIES 3 | ||
409 | |||
410 | static void freeifaddrs(struct ifaddrs *ifa) | ||
411 | { | ||
412 | if (!ifa) { | ||
413 | return; | ||
414 | } | ||
415 | free(ifa->ifa_name); | ||
416 | free(ifa->ifa_addr); | ||
417 | free(ifa->ifa_netmask); | ||
418 | free(ifa->ifa_dstaddr); | ||
419 | freeifaddrs(ifa->ifa_next); | ||
420 | free(ifa); | ||
421 | } | ||
422 | |||
423 | /* | ||
424 | * getifaddrs() reference implementation for win32. | ||
425 | * Heavily based on openpgm's implementation found here: | ||
426 | * https://github.com/steve-o/openpgm/blob/master/openpgm/pgm/getifaddrs.c | ||
427 | */ | ||
428 | static int getifaddrs(struct ifaddrs** ifap) | ||
429 | { | ||
430 | struct ifaddrs* ifa = NULL; | ||
431 | |||
432 | DWORD dwRetVal = 0; | ||
433 | |||
434 | PIP_ADAPTER_ADDRESSES pAddresses = NULL; | ||
435 | ULONG outBufLen = 0; | ||
436 | ULONG Iterations = 0; | ||
437 | |||
438 | ULONG flags = GAA_FLAG_INCLUDE_PREFIX | | ||
439 | GAA_FLAG_SKIP_ANYCAST | | ||
440 | GAA_FLAG_SKIP_DNS_SERVER | | ||
441 | GAA_FLAG_SKIP_FRIENDLY_NAME | | ||
442 | GAA_FLAG_SKIP_MULTICAST; | ||
443 | |||
444 | PIP_ADAPTER_ADDRESSES adapter = NULL; | ||
445 | |||
446 | if (!ifap) { | ||
447 | errno = EINVAL; | ||
448 | return -1; | ||
449 | } | ||
450 | *ifap = NULL; | ||
451 | |||
452 | outBufLen = WORKING_BUFFER_SIZE; | ||
453 | do { | ||
454 | pAddresses = (IP_ADAPTER_ADDRESSES*)malloc(outBufLen); | ||
455 | if (pAddresses == NULL) { | ||
456 | printf("Memory allocation failed for IP_ADAPTER_ADDRESSES struct\n"); | ||
457 | return -1; | ||
458 | } | ||
459 | dwRetVal = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, pAddresses, &outBufLen); | ||
460 | if (dwRetVal == ERROR_BUFFER_OVERFLOW) { | ||
461 | free(pAddresses); | ||
462 | pAddresses = NULL; | ||
463 | } else { | ||
464 | break; | ||
465 | } | ||
466 | Iterations++; | ||
467 | } while ((dwRetVal == ERROR_BUFFER_OVERFLOW) && (Iterations < MAX_TRIES)); | ||
468 | |||
469 | if (dwRetVal != NO_ERROR) { | ||
470 | free(pAddresses); | ||
471 | return -1; | ||
472 | } | ||
473 | |||
474 | for (adapter = pAddresses; adapter; adapter = adapter->Next) { | ||
475 | int unicastIndex = 0; | ||
476 | for (IP_ADAPTER_UNICAST_ADDRESS *unicast = adapter->FirstUnicastAddress; unicast; unicast = unicast->Next, ++unicastIndex) { | ||
477 | /* ensure IP adapter */ | ||
478 | if (AF_INET != unicast->Address.lpSockaddr->sa_family && AF_INET6 != unicast->Address.lpSockaddr->sa_family) { | ||
479 | continue; | ||
480 | } | ||
481 | |||
482 | if (!ifa) { | ||
483 | ifa = malloc(sizeof(struct ifaddrs)); | ||
484 | if (!ifa) { | ||
485 | errno = ENOMEM; | ||
486 | free(pAddresses); | ||
487 | return -1; | ||
488 | } | ||
489 | *ifap = ifa; | ||
490 | ifa->ifa_next = NULL; | ||
491 | } else { | ||
492 | struct ifaddrs* ifanew = malloc(sizeof(struct ifaddrs)); | ||
493 | if (!ifanew) { | ||
494 | freeifaddrs(*ifap); | ||
495 | free(pAddresses); | ||
496 | errno = ENOMEM; | ||
497 | return -1; | ||
498 | } | ||
499 | ifa->ifa_next = ifanew; | ||
500 | ifa = ifanew; | ||
501 | ifa->ifa_next = NULL; | ||
502 | } | ||
503 | |||
504 | /* name */ | ||
505 | ifa->ifa_name = strdup(adapter->AdapterName); | ||
506 | |||
507 | /* flags */ | ||
508 | ifa->ifa_flags = 0; | ||
509 | if (IfOperStatusUp == adapter->OperStatus) | ||
510 | ifa->ifa_flags |= IFF_UP; | ||
511 | if (IF_TYPE_SOFTWARE_LOOPBACK == adapter->IfType) | ||
512 | ifa->ifa_flags |= IFF_LOOPBACK; | ||
513 | if (!(adapter->Flags & IP_ADAPTER_NO_MULTICAST)) | ||
514 | ifa->ifa_flags |= IFF_MULTICAST; | ||
515 | |||
516 | /* address */ | ||
517 | ifa->ifa_addr = (struct sockaddr*)malloc(sizeof(struct sockaddr_storage)); | ||
518 | memcpy(ifa->ifa_addr, unicast->Address.lpSockaddr, unicast->Address.iSockaddrLength); | ||
519 | |||
520 | /* netmask */ | ||
521 | ifa->ifa_netmask = (struct sockaddr*)malloc(sizeof(struct sockaddr_storage)); | ||
522 | memset(ifa->ifa_netmask, 0, sizeof(struct sockaddr_storage)); | ||
523 | |||
524 | /* pre-Vista must hunt for matching prefix in linked list, otherwise use | ||
525 | * OnLinkPrefixLength from IP_ADAPTER_UNICAST_ADDRESS structure. | ||
526 | * FirstPrefix requires Windows XP SP1, from SP1 to pre-Vista provides a | ||
527 | * single adapter prefix for each IP address. Vista and later provides | ||
528 | * host IP address prefix, subnet IP address, and subnet broadcast IP | ||
529 | * address. In addition there is a multicast and broadcast address prefix. | ||
530 | */ | ||
531 | ULONG prefixLength = 0; | ||
532 | |||
533 | #if defined( _WIN32 ) && ( _WIN32_WINNT >= 0x0600 ) | ||
534 | /* For a unicast IPv4 address, any value greater than 32 is an illegal | ||
535 | * value. For a unicast IPv6 address, any value greater than 128 is an | ||
536 | * illegal value. A value of 255 is commonly used to represent an illegal | ||
537 | * value. | ||
538 | * | ||
539 | * Windows 7 SP1 returns 64 for Teredo links which is incorrect. | ||
540 | */ | ||
541 | |||
542 | #define IN6_IS_ADDR_TEREDO(addr) \ | ||
543 | (((const uint32_t *)(addr))[0] == ntohl (0x20010000)) | ||
544 | |||
545 | if (AF_INET6 == unicast->Address.lpSockaddr->sa_family && | ||
546 | /* TunnelType only applies to one interface on the adapter and no | ||
547 | * convenient method is provided to determine which. | ||
548 | */ | ||
549 | TUNNEL_TYPE_TEREDO == adapter->TunnelType && | ||
550 | /* Test the interface with the known Teredo network prefix. | ||
551 | */ | ||
552 | IN6_IS_ADDR_TEREDO( &((struct sockaddr_in6*)(unicast->Address.lpSockaddr))->sin6_addr) && | ||
553 | /* Test that this version is actually wrong, subsequent releases from Microsoft | ||
554 | * may resolve the issue. | ||
555 | */ | ||
556 | 32 != unicast->OnLinkPrefixLength) | ||
557 | { | ||
558 | prefixLength = 32; | ||
559 | } | ||
560 | else | ||
561 | prefixLength = unicast->OnLinkPrefixLength; | ||
562 | #else | ||
563 | /* The order of linked IP_ADAPTER_UNICAST_ADDRESS structures pointed to by | ||
564 | * the FirstUnicastAddress member does not have any relationship with the | ||
565 | * order of linked IP_ADAPTER_PREFIX structures pointed to by the FirstPrefix | ||
566 | * member. | ||
567 | * | ||
568 | * Example enumeration: | ||
569 | * [ no subnet ] | ||
570 | * ::1/128 - address | ||
571 | * ff00::%1/8 - multicast (no IPv6 broadcast) | ||
572 | * 127.0.0.0/8 - subnet | ||
573 | * 127.0.0.1/32 - address | ||
574 | * 127.255.255.255/32 - subnet broadcast | ||
575 | * 224.0.0.0/4 - multicast | ||
576 | * 255.255.255.255/32 - broadcast | ||
577 | * | ||
578 | * Which differs from most adapters listing three IPv6: | ||
579 | * fe80::%10/64 - subnet | ||
580 | * fe80::51e9:5fe5:4202:325a%10/128 - address | ||
581 | * ff00::%10/8 - multicast | ||
582 | * | ||
583 | * !IfOperStatusUp IPv4 addresses are skipped: | ||
584 | * fe80::%13/64 - subnet | ||
585 | * fe80::d530:946d:e8df:8c91%13/128 - address | ||
586 | * ff00::%13/8 - multicast | ||
587 | * [ no subnet ] | ||
588 | * [ no address ] | ||
589 | * 224.0.0.0/4 - multicast | ||
590 | * 255.255.255.255/32 - broadcast | ||
591 | * | ||
592 | * On PTP links no multicast or broadcast addresses are returned: | ||
593 | * [ no subnet ] | ||
594 | * fe80::5efe:10.203.9.30/128 - address | ||
595 | * [ no multicast ] | ||
596 | * [ no multicast ] | ||
597 | * [ no broadcast ] | ||
598 | * | ||
599 | * Active primary IPv6 interfaces are a bit overloaded: | ||
600 | * ::/0 - default route | ||
601 | * 2001::/32 - global subnet | ||
602 | * 2001:0:4137:9e76:2443:d6:ba87:1a2a/128 - global address | ||
603 | * fe80::/64 - link-local subnet | ||
604 | * fe80::2443:d6:ba87:1a2a/128 - link-local address | ||
605 | * ff00::/8 - multicast | ||
606 | */ | ||
607 | |||
608 | #define IN_LINKLOCAL(a) ((((uint32_t) (a)) & 0xaffff0000) == 0xa9fe0000) | ||
609 | |||
610 | for (IP_ADAPTER_PREFIX *prefix = adapter->FirstPrefix; prefix; prefix = prefix->Next) { | ||
611 | LPSOCKADDR lpSockaddr = prefix->Address.lpSockaddr; | ||
612 | if (lpSockaddr->sa_family != unicast->Address.lpSockaddr->sa_family) | ||
613 | continue; | ||
614 | /* special cases */ | ||
615 | /* RFC2863: IPv4 interface not up */ | ||
616 | if (AF_INET == lpSockaddr->sa_family && adapter->OperStatus != IfOperStatusUp) { | ||
617 | /* RFC3927: link-local IPv4 always has 16-bit CIDR */ | ||
618 | if (IN_LINKLOCAL( ntohl (((struct sockaddr_in*)(unicast->Address.lpSockaddr))->sin_addr.s_addr))) { | ||
619 | prefixLength = 16; | ||
620 | } | ||
621 | break; | ||
622 | } | ||
623 | /* default IPv6 route */ | ||
624 | if (AF_INET6 == lpSockaddr->sa_family && 0 == prefix->PrefixLength && IN6_IS_ADDR_UNSPECIFIED( &((struct sockaddr_in6*)(lpSockaddr))->sin6_addr)) { | ||
625 | continue; | ||
626 | } | ||
627 | /* Assume unicast address for first prefix of operational adapter */ | ||
628 | if (AF_INET == lpSockaddr->sa_family) | ||
629 | if (IN_MULTICAST( ntohl (((struct sockaddr_in*)(lpSockaddr))->sin_addr.s_addr))) { | ||
630 | fprintf(stderr, "FATAL: first prefix is non a unicast address\n"); | ||
631 | break; | ||
632 | } | ||
633 | if (AF_INET6 == lpSockaddr->sa_family) | ||
634 | if (IN6_IS_ADDR_MULTICAST( &((struct sockaddr_in6*)(lpSockaddr))->sin6_addr)) { | ||
635 | fprintf(stderr, "FATAL: first prefix is not a unicast address\n"); | ||
636 | break; | ||
637 | } | ||
638 | /* Assume subnet or host IP address for XP backward compatibility */ | ||
639 | |||
640 | prefixLength = prefix->PrefixLength; | ||
641 | break; | ||
642 | } | ||
643 | #endif /* defined( _WIN32 ) && ( _WIN32_WINNT >= 0x0600 ) */ | ||
644 | |||
645 | /* map prefix to netmask */ | ||
646 | ifa->ifa_netmask->sa_family = unicast->Address.lpSockaddr->sa_family; | ||
647 | switch (unicast->Address.lpSockaddr->sa_family) { | ||
648 | case AF_INET: | ||
649 | if (0 == prefixLength || prefixLength > 32) { | ||
650 | prefixLength = 32; | ||
651 | } | ||
652 | #if defined( _WIN32) && ( _WIN32_WINNT >= 0x0600 ) | ||
653 | /* Added in Vista, but no IPv6 equivalent. */ | ||
654 | { | ||
655 | ULONG Mask; | ||
656 | ConvertLengthToIpv4Mask (prefixLength, &Mask); | ||
657 | ((struct sockaddr_in*)ifa->ifa_netmask)->sin_addr.s_addr = Mask; /* network order */ | ||
658 | } | ||
659 | #else | ||
660 | /* NB: left-shift of full bit-width is undefined in C standard. */ | ||
661 | ((struct sockaddr_in*)ifa->ifa_netmask)->sin_addr.s_addr = htonl( 0xffffffffU << ( 32 - prefixLength ) ); | ||
662 | #endif | ||
663 | break; | ||
664 | |||
665 | case AF_INET6: | ||
666 | if (0 == prefixLength || prefixLength > 128) { | ||
667 | prefixLength = 128; | ||
668 | } | ||
669 | for (LONG i = prefixLength, j = 0; i > 0; i -= 8, ++j) { | ||
670 | ((struct sockaddr_in6*)ifa->ifa_netmask)->sin6_addr.s6_addr[ j ] = i >= 8 ? 0xff : (ULONG)(( 0xffU << ( 8 - i ) ) & 0xffU ); | ||
671 | } | ||
672 | break; | ||
673 | default: | ||
674 | break; | ||
675 | } | ||
676 | } | ||
677 | } | ||
678 | free(pAddresses); | ||
679 | |||
680 | return 0; | ||
681 | } | ||
682 | #else | ||
683 | #error No reference implementation for getifaddrs available for this platform. | ||
684 | #endif | ||
685 | #endif | ||
686 | |||
687 | static int32_t _sockaddr_in6_scope_id(struct sockaddr_in6* addr) | ||
688 | { | ||
689 | int32_t res = -1; | ||
690 | struct ifaddrs *ifaddr = NULL, *ifa = NULL; | ||
691 | uint32_t addr_scope; | ||
692 | |||
693 | /* get scope for requested address */ | ||
694 | addr_scope = _in6_addr_scope(&addr->sin6_addr); | ||
695 | if (addr_scope == 0) { | ||
696 | /* global scope doesn't need a specific scope id */ | ||
697 | return addr_scope; | ||
698 | } | ||
699 | |||
700 | /* get interfaces */ | ||
701 | if (getifaddrs(&ifaddr) == -1) { | ||
702 | perror("getifaddrs"); | ||
703 | return res; | ||
704 | } | ||
705 | |||
706 | /* loop over interfaces */ | ||
707 | for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { | ||
708 | /* skip if no address is available */ | ||
709 | if (ifa->ifa_addr == NULL) { | ||
710 | continue; | ||
711 | } | ||
712 | |||
713 | /* skip if wrong family */ | ||
714 | if (ifa->ifa_addr->sa_family != AF_INET6) { | ||
715 | continue; | ||
716 | } | ||
717 | |||
718 | /* skip if not up */ | ||
719 | if ((ifa->ifa_flags & IFF_UP) == 0) { | ||
720 | continue; | ||
721 | } | ||
722 | |||
723 | /* skip if not running */ | ||
724 | if ((ifa->ifa_flags & IFF_RUNNING) == 0) { | ||
725 | continue; | ||
726 | } | ||
727 | |||
728 | struct sockaddr_in6* addr_in = (struct sockaddr_in6*)ifa->ifa_addr; | ||
729 | |||
730 | /* skip if scopes do not match */ | ||
731 | if (_in6_addr_scope(&addr_in->sin6_addr) != addr_scope) { | ||
732 | continue; | ||
733 | } | ||
734 | |||
735 | /* use if address is equal */ | ||
736 | if (memcmp(&addr->sin6_addr.s6_addr, &addr_in->sin6_addr.s6_addr, sizeof(addr_in->sin6_addr.s6_addr)) == 0) { | ||
737 | /* if scope id equals the requested one then assume it was valid */ | ||
738 | if (addr->sin6_scope_id == addr_in->sin6_scope_id) { | ||
739 | res = addr_in->sin6_scope_id; | ||
740 | break; | ||
741 | } | ||
742 | |||
743 | if ((addr_in->sin6_scope_id > addr->sin6_scope_id) && (res >= 0)) { | ||
744 | // use last valid scope id as we're past the requested scope id | ||
745 | break; | ||
746 | } | ||
747 | res = addr_in->sin6_scope_id; | ||
748 | continue; | ||
749 | } | ||
750 | |||
751 | /* skip loopback interface if not already matched exactly above */ | ||
752 | if ((ifa->ifa_flags & IFF_LOOPBACK) != 0) { | ||
753 | continue; | ||
754 | } | ||
755 | |||
756 | if ((addr_in->sin6_scope_id > addr->sin6_scope_id) && (res >= 0)) { | ||
757 | // use last valid scope id as we're past the requested scope id | ||
758 | break; | ||
759 | } | ||
760 | |||
761 | res = addr_in->sin6_scope_id; | ||
762 | |||
763 | /* if scope id equals the requested one then assume it was valid */ | ||
764 | if (addr->sin6_scope_id == addr_in->sin6_scope_id) { | ||
765 | /* set the scope id of this interface as most likely candidate */ | ||
766 | break; | ||
767 | } | ||
768 | } | ||
769 | |||
770 | freeifaddrs(ifaddr); | ||
771 | |||
772 | return res; | ||
773 | } | ||
774 | #endif | ||
775 | |||
776 | int socket_connect_addr(struct sockaddr* addr, uint16_t port) | ||
777 | { | ||
778 | int sfd = -1; | ||
779 | int yes = 1; | ||
780 | int bufsize = 0x20000; | ||
781 | int addrlen = 0; | ||
782 | #ifdef WIN32 | ||
783 | u_long l_yes = 1; | ||
784 | WSADATA wsa_data; | ||
785 | if (!wsa_init) { | ||
786 | if (WSAStartup(MAKEWORD(2,2), &wsa_data) != ERROR_SUCCESS) { | ||
787 | fprintf(stderr, "WSAStartup failed!\n"); | ||
788 | ExitProcess(-1); | ||
789 | } | ||
790 | wsa_init = 1; | ||
791 | } | ||
792 | #endif | ||
793 | |||
794 | if (addr->sa_family == AF_INET) { | ||
795 | struct sockaddr_in* addr_in = (struct sockaddr_in*)addr; | ||
796 | addr_in->sin_port = htons(port); | ||
797 | addrlen = sizeof(struct sockaddr_in); | ||
798 | } | ||
799 | #ifdef AF_INET6 | ||
800 | else if (addr->sa_family == AF_INET6) { | ||
801 | struct sockaddr_in6* addr_in = (struct sockaddr_in6*)addr; | ||
802 | addr_in->sin6_port = htons(port); | ||
803 | |||
804 | /* | ||
805 | * IPv6 Routing Magic: | ||
806 | * | ||
807 | * If the scope of the address is a link-local one, IPv6 requires the | ||
808 | * scope id set to an interface number to allow proper routing. However, | ||
809 | * as the provided sockaddr might contain a wrong scope id, we must find | ||
810 | * a scope id from a suitable interface on this system or routing might | ||
811 | * fail. An IPv6 guru should have another look though... | ||
812 | */ | ||
813 | addr_in->sin6_scope_id = _sockaddr_in6_scope_id(addr_in); | ||
814 | |||
815 | addrlen = sizeof(struct sockaddr_in6); | ||
816 | } | ||
817 | #endif | ||
818 | else { | ||
819 | fprintf(stderr, "ERROR: Unsupported address family"); | ||
820 | return -1; | ||
821 | } | ||
822 | |||
823 | sfd = socket(addr->sa_family, SOCK_STREAM, IPPROTO_TCP); | ||
824 | if (sfd == -1) { | ||
825 | perror("socket()"); | ||
826 | return -1; | ||
827 | } | ||
828 | |||
829 | #ifdef SO_NOSIGPIPE | ||
830 | if (setsockopt(sfd, SOL_SOCKET, SO_NOSIGPIPE, (void*)&yes, sizeof(int)) == -1) { | ||
831 | perror("setsockopt()"); | ||
832 | socket_close(sfd); | ||
833 | return -1; | ||
834 | } | ||
835 | #endif | ||
836 | |||
837 | if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (void*)&yes, sizeof(int)) == -1) { | ||
838 | perror("setsockopt()"); | ||
839 | socket_close(sfd); | ||
840 | return -1; | ||
841 | } | ||
842 | |||
843 | #ifdef WIN32 | ||
844 | ioctlsocket(sfd, FIONBIO, &l_yes); | ||
845 | #else | ||
846 | int flags = fcntl(sfd, F_GETFL, 0); | ||
847 | fcntl(sfd, F_SETFL, flags | O_NONBLOCK); | ||
848 | #endif | ||
849 | |||
850 | do { | ||
851 | if (connect(sfd, addr, addrlen) != -1) { | ||
852 | break; | ||
853 | } | ||
854 | #ifdef WIN32 | ||
855 | if (WSAGetLastError() == WSAEWOULDBLOCK) | ||
856 | #else | ||
857 | if (errno == EINPROGRESS) | ||
858 | #endif | ||
859 | { | ||
860 | fd_set fds; | ||
861 | FD_ZERO(&fds); | ||
862 | FD_SET(sfd, &fds); | ||
863 | |||
864 | struct timeval timeout; | ||
865 | timeout.tv_sec = CONNECT_TIMEOUT / 1000; | ||
866 | timeout.tv_usec = (CONNECT_TIMEOUT - (timeout.tv_sec * 1000)) * 1000; | ||
867 | if (select(sfd + 1, NULL, &fds, NULL, &timeout) == 1) { | ||
868 | int so_error; | ||
869 | socklen_t len = sizeof(so_error); | ||
870 | getsockopt(sfd, SOL_SOCKET, SO_ERROR, (void*)&so_error, &len); | ||
871 | if (so_error == 0) { | ||
872 | errno = 0; | ||
873 | break; | ||
874 | } | ||
875 | errno = so_error; | ||
876 | } | ||
877 | } | ||
878 | socket_close(sfd); | ||
879 | sfd = -1; | ||
880 | } while (0); | ||
881 | |||
882 | if (sfd < 0) { | ||
883 | if (verbose >= 2) { | ||
884 | char addrtxt[48]; | ||
885 | socket_addr_to_string(addr, addrtxt, sizeof(addrtxt)); | ||
886 | fprintf(stderr, "%s: Could not connect to %s port %d\n", __func__, addrtxt, port); | ||
887 | } | ||
888 | return -1; | ||
889 | } | ||
890 | |||
891 | if (setsockopt(sfd, IPPROTO_TCP, TCP_NODELAY, (void*)&yes, sizeof(int)) == -1) { | ||
892 | perror("Could not set TCP_NODELAY on socket"); | ||
893 | } | ||
894 | |||
895 | if (setsockopt(sfd, SOL_SOCKET, SO_SNDBUF, (void*)&bufsize, sizeof(int)) == -1) { | ||
896 | perror("Could not set send buffer for socket"); | ||
897 | } | ||
898 | |||
899 | if (setsockopt(sfd, SOL_SOCKET, SO_RCVBUF, (void*)&bufsize, sizeof(int)) == -1) { | ||
900 | perror("Could not set receive buffer for socket"); | ||
901 | } | ||
902 | |||
903 | return sfd; | ||
904 | } | ||
905 | |||
906 | int socket_connect(const char *addr, uint16_t port) | ||
907 | { | ||
908 | int sfd = -1; | ||
909 | int yes = 1; | ||
910 | int bufsize = 0x20000; | ||
911 | struct addrinfo hints; | ||
912 | struct addrinfo *result, *rp; | ||
913 | char portstr[8]; | ||
914 | int res; | ||
915 | #ifdef WIN32 | ||
916 | u_long l_yes = 1; | ||
917 | WSADATA wsa_data; | ||
918 | if (!wsa_init) { | ||
919 | if (WSAStartup(MAKEWORD(2,2), &wsa_data) != ERROR_SUCCESS) { | ||
920 | fprintf(stderr, "WSAStartup failed!\n"); | ||
921 | ExitProcess(-1); | ||
922 | } | ||
923 | wsa_init = 1; | ||
924 | } | ||
925 | #else | ||
926 | int flags = 0; | ||
927 | #endif | ||
928 | |||
929 | if (!addr) { | ||
930 | errno = EINVAL; | ||
931 | return -1; | ||
932 | } | ||
933 | |||
934 | memset(&hints, '\0', sizeof(struct addrinfo)); | ||
935 | hints.ai_family = AF_UNSPEC; | ||
936 | hints.ai_socktype = SOCK_STREAM; | ||
937 | hints.ai_flags = AI_NUMERICSERV; | ||
938 | hints.ai_protocol = IPPROTO_TCP; | ||
939 | |||
940 | sprintf(portstr, "%d", port); | ||
941 | |||
942 | res = getaddrinfo(addr, portstr, &hints, &result); | ||
943 | if (res != 0) { | ||
944 | fprintf(stderr, "%s: getaddrinfo: %s\n", __func__, gai_strerror(res)); | ||
945 | return -1; | ||
946 | } | ||
947 | |||
948 | for (rp = result; rp != NULL; rp = rp->ai_next) { | ||
949 | sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); | ||
950 | if (sfd == -1) { | ||
951 | continue; | ||
952 | } | ||
953 | |||
954 | #ifdef SO_NOSIGPIPE | ||
955 | if (setsockopt(sfd, SOL_SOCKET, SO_NOSIGPIPE, (void*)&yes, sizeof(int)) == -1) { | ||
956 | perror("setsockopt()"); | ||
957 | socket_close(sfd); | ||
958 | return -1; | ||
959 | } | ||
960 | #endif | ||
961 | |||
962 | if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (void*)&yes, sizeof(int)) == -1) { | ||
963 | perror("setsockopt()"); | ||
964 | socket_close(sfd); | ||
965 | continue; | ||
966 | } | ||
967 | |||
968 | #ifdef WIN32 | ||
969 | ioctlsocket(sfd, FIONBIO, &l_yes); | ||
970 | #else | ||
971 | flags = fcntl(sfd, F_GETFL, 0); | ||
972 | fcntl(sfd, F_SETFL, flags | O_NONBLOCK); | ||
973 | #endif | ||
974 | |||
975 | if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1) { | ||
976 | break; | ||
977 | } | ||
978 | #ifdef WIN32 | ||
979 | if (WSAGetLastError() == WSAEWOULDBLOCK) | ||
980 | #else | ||
981 | if (errno == EINPROGRESS) | ||
982 | #endif | ||
983 | { | ||
984 | fd_set fds; | ||
985 | FD_ZERO(&fds); | ||
986 | FD_SET(sfd, &fds); | ||
987 | |||
988 | struct timeval timeout; | ||
989 | timeout.tv_sec = CONNECT_TIMEOUT / 1000; | ||
990 | timeout.tv_usec = (CONNECT_TIMEOUT - (timeout.tv_sec * 1000)) * 1000; | ||
991 | if (select(sfd + 1, NULL, &fds, NULL, &timeout) == 1) { | ||
992 | int so_error; | ||
993 | socklen_t len = sizeof(so_error); | ||
994 | getsockopt(sfd, SOL_SOCKET, SO_ERROR, (void*)&so_error, &len); | ||
995 | if (so_error == 0) { | ||
996 | break; | ||
997 | } | ||
998 | } | ||
999 | } | ||
1000 | socket_close(sfd); | ||
1001 | } | ||
1002 | |||
1003 | freeaddrinfo(result); | ||
1004 | |||
1005 | if (rp == NULL) { | ||
1006 | if (verbose >= 2) | ||
1007 | fprintf(stderr, "%s: Could not connect to %s:%d\n", __func__, addr, port); | ||
1008 | return -1; | ||
1009 | } | ||
1010 | |||
1011 | if (setsockopt(sfd, IPPROTO_TCP, TCP_NODELAY, (void*)&yes, sizeof(int)) == -1) { | ||
1012 | perror("Could not set TCP_NODELAY on socket"); | ||
1013 | } | ||
1014 | |||
1015 | if (setsockopt(sfd, SOL_SOCKET, SO_SNDBUF, (void*)&bufsize, sizeof(int)) == -1) { | ||
1016 | perror("Could not set send buffer for socket"); | ||
1017 | } | ||
1018 | |||
1019 | if (setsockopt(sfd, SOL_SOCKET, SO_RCVBUF, (void*)&bufsize, sizeof(int)) == -1) { | ||
1020 | perror("Could not set receive buffer for socket"); | ||
1021 | } | ||
1022 | |||
1023 | return sfd; | ||
1024 | } | ||
1025 | |||
1026 | int socket_check_fd(int fd, fd_mode fdm, unsigned int timeout) | ||
1027 | { | ||
1028 | fd_set fds; | ||
1029 | int sret; | ||
1030 | int eagain; | ||
1031 | struct timeval to; | ||
1032 | struct timeval *pto; | ||
1033 | |||
1034 | if (fd < 0) { | ||
1035 | if (verbose >= 2) | ||
1036 | fprintf(stderr, "ERROR: invalid fd in check_fd %d\n", fd); | ||
1037 | return -1; | ||
1038 | } | ||
1039 | |||
1040 | FD_ZERO(&fds); | ||
1041 | FD_SET(fd, &fds); | ||
1042 | |||
1043 | sret = -1; | ||
1044 | |||
1045 | do { | ||
1046 | if (timeout > 0) { | ||
1047 | to.tv_sec = (time_t) (timeout / 1000); | ||
1048 | to.tv_usec = (time_t) ((timeout - (to.tv_sec * 1000)) * 1000); | ||
1049 | pto = &to; | ||
1050 | } else { | ||
1051 | pto = NULL; | ||
1052 | } | ||
1053 | eagain = 0; | ||
1054 | switch (fdm) { | ||
1055 | case FDM_READ: | ||
1056 | sret = select(fd + 1, &fds, NULL, NULL, pto); | ||
1057 | break; | ||
1058 | case FDM_WRITE: | ||
1059 | sret = select(fd + 1, NULL, &fds, NULL, pto); | ||
1060 | break; | ||
1061 | case FDM_EXCEPT: | ||
1062 | sret = select(fd + 1, NULL, NULL, &fds, pto); | ||
1063 | break; | ||
1064 | default: | ||
1065 | return -1; | ||
1066 | } | ||
1067 | |||
1068 | if (sret < 0) { | ||
1069 | switch (errno) { | ||
1070 | case EINTR: | ||
1071 | // interrupt signal in select | ||
1072 | if (verbose >= 2) | ||
1073 | fprintf(stderr, "%s: EINTR\n", __func__); | ||
1074 | eagain = 1; | ||
1075 | break; | ||
1076 | case EAGAIN: | ||
1077 | if (verbose >= 2) | ||
1078 | fprintf(stderr, "%s: EAGAIN\n", __func__); | ||
1079 | break; | ||
1080 | default: | ||
1081 | if (verbose >= 2) | ||
1082 | fprintf(stderr, "%s: select failed: %s\n", __func__, | ||
1083 | strerror(errno)); | ||
1084 | return -1; | ||
1085 | } | ||
1086 | } else if (sret == 0) { | ||
1087 | return -ETIMEDOUT; | ||
1088 | } | ||
1089 | } while (eagain); | ||
1090 | |||
1091 | return sret; | ||
1092 | } | ||
1093 | |||
1094 | int socket_accept(int fd, uint16_t port) | ||
1095 | { | ||
1096 | #ifdef WIN32 | ||
1097 | int addr_len; | ||
1098 | #else | ||
1099 | socklen_t addr_len; | ||
1100 | #endif | ||
1101 | int result; | ||
1102 | struct sockaddr_storage addr; | ||
1103 | addr_len = sizeof(addr); | ||
1104 | |||
1105 | result = accept(fd, (struct sockaddr*)&addr, &addr_len); | ||
1106 | |||
1107 | return result; | ||
1108 | } | ||
1109 | |||
1110 | int socket_shutdown(int fd, int how) | ||
1111 | { | ||
1112 | return shutdown(fd, how); | ||
1113 | } | ||
1114 | |||
1115 | int socket_close(int fd) { | ||
1116 | #ifdef WIN32 | ||
1117 | return closesocket(fd); | ||
1118 | #else | ||
1119 | return close(fd); | ||
1120 | #endif | ||
1121 | } | ||
1122 | |||
1123 | int socket_receive(int fd, void *data, size_t length) | ||
1124 | { | ||
1125 | return socket_receive_timeout(fd, data, length, 0, RECV_TIMEOUT); | ||
1126 | } | ||
1127 | |||
1128 | int socket_peek(int fd, void *data, size_t length) | ||
1129 | { | ||
1130 | return socket_receive_timeout(fd, data, length, MSG_PEEK, RECV_TIMEOUT); | ||
1131 | } | ||
1132 | |||
1133 | int socket_receive_timeout(int fd, void *data, size_t length, int flags, | ||
1134 | unsigned int timeout) | ||
1135 | { | ||
1136 | int res; | ||
1137 | int result; | ||
1138 | |||
1139 | // check if data is available | ||
1140 | res = socket_check_fd(fd, FDM_READ, timeout); | ||
1141 | if (res <= 0) { | ||
1142 | return res; | ||
1143 | } | ||
1144 | // if we get here, there _is_ data available | ||
1145 | result = recv(fd, data, length, flags); | ||
1146 | if (res > 0 && result == 0) { | ||
1147 | // but this is an error condition | ||
1148 | if (verbose >= 3) | ||
1149 | fprintf(stderr, "%s: fd=%d recv returned 0\n", __func__, fd); | ||
1150 | return -ECONNRESET; | ||
1151 | } | ||
1152 | if (result < 0) { | ||
1153 | return -errno; | ||
1154 | } | ||
1155 | return result; | ||
1156 | } | ||
1157 | |||
1158 | int socket_send(int fd, void *data, size_t length) | ||
1159 | { | ||
1160 | int flags = 0; | ||
1161 | int res = socket_check_fd(fd, FDM_WRITE, SEND_TIMEOUT); | ||
1162 | if (res <= 0) { | ||
1163 | return res; | ||
1164 | } | ||
1165 | #ifdef MSG_NOSIGNAL | ||
1166 | flags |= MSG_NOSIGNAL; | ||
1167 | #endif | ||
1168 | return send(fd, data, length, flags); | ||
1169 | } | ||