diff options
Diffstat (limited to 'src/util/network.c')
-rw-r--r-- | src/util/network.c | 1334 |
1 files changed, 0 insertions, 1334 deletions
diff --git a/src/util/network.c b/src/util/network.c deleted file mode 100644 index 2f77bc54e..000000000 --- a/src/util/network.c +++ /dev/null | |||
@@ -1,1334 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2009-2013 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file util/network.c | ||
23 | * @brief basic, low-level networking interface | ||
24 | * @author Nils Durner | ||
25 | * @author Christian Grothoff | ||
26 | */ | ||
27 | #include "platform.h" | ||
28 | #include "gnunet_util_lib.h" | ||
29 | #include "disk.h" | ||
30 | |||
31 | #define LOG(kind, ...) GNUNET_log_from (kind, "util-network", __VA_ARGS__) | ||
32 | #define LOG_STRERROR_FILE(kind, syscall, \ | ||
33 | filename) GNUNET_log_from_strerror_file (kind, \ | ||
34 | "util-network", \ | ||
35 | syscall, \ | ||
36 | filename) | ||
37 | #define LOG_STRERROR(kind, syscall) GNUNET_log_from_strerror (kind, \ | ||
38 | "util-network", \ | ||
39 | syscall) | ||
40 | |||
41 | #define DEBUG_NETWORK GNUNET_EXTRA_LOGGING | ||
42 | |||
43 | |||
44 | #ifndef INVALID_SOCKET | ||
45 | #define INVALID_SOCKET -1 | ||
46 | #endif | ||
47 | |||
48 | |||
49 | /** | ||
50 | * @brief handle to a socket | ||
51 | */ | ||
52 | struct GNUNET_NETWORK_Handle | ||
53 | { | ||
54 | int fd; | ||
55 | |||
56 | /** | ||
57 | * Address family / domain. | ||
58 | */ | ||
59 | int af; | ||
60 | |||
61 | /** | ||
62 | * Type of the socket | ||
63 | */ | ||
64 | int type; | ||
65 | |||
66 | /** | ||
67 | * Number of bytes in addr. | ||
68 | */ | ||
69 | socklen_t addrlen; | ||
70 | |||
71 | /** | ||
72 | * Address we were bound to, or NULL. | ||
73 | */ | ||
74 | struct sockaddr *addr; | ||
75 | }; | ||
76 | |||
77 | |||
78 | enum GNUNET_GenericReturnValue | ||
79 | GNUNET_NETWORK_test_pf (int pf) | ||
80 | { | ||
81 | static int cache_v4 = -1; | ||
82 | static int cache_v6 = -1; | ||
83 | static int cache_un = -1; | ||
84 | int s; | ||
85 | int ret; | ||
86 | |||
87 | switch (pf) | ||
88 | { | ||
89 | case PF_INET: | ||
90 | if (-1 != cache_v4) | ||
91 | return cache_v4; | ||
92 | break; | ||
93 | |||
94 | case PF_INET6: | ||
95 | if (-1 != cache_v6) | ||
96 | return cache_v6; | ||
97 | break; | ||
98 | |||
99 | #ifdef PF_UNIX | ||
100 | case PF_UNIX: | ||
101 | if (-1 != cache_un) | ||
102 | return cache_un; | ||
103 | break; | ||
104 | #endif | ||
105 | } | ||
106 | s = socket (pf, SOCK_STREAM, 0); | ||
107 | if (-1 == s) | ||
108 | { | ||
109 | if (EAFNOSUPPORT != errno) | ||
110 | { | ||
111 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, | ||
112 | "socket"); | ||
113 | return GNUNET_SYSERR; | ||
114 | } | ||
115 | ret = GNUNET_NO; | ||
116 | } | ||
117 | else | ||
118 | { | ||
119 | GNUNET_break (0 == close (s)); | ||
120 | ret = GNUNET_OK; | ||
121 | } | ||
122 | switch (pf) | ||
123 | { | ||
124 | case PF_INET: | ||
125 | cache_v4 = ret; | ||
126 | break; | ||
127 | |||
128 | case PF_INET6: | ||
129 | cache_v6 = ret; | ||
130 | break; | ||
131 | |||
132 | #ifdef PF_UNIX | ||
133 | case PF_UNIX: | ||
134 | cache_un = ret; | ||
135 | break; | ||
136 | #endif | ||
137 | } | ||
138 | return ret; | ||
139 | } | ||
140 | |||
141 | |||
142 | char * | ||
143 | GNUNET_NETWORK_shorten_unixpath (char *unixpath) | ||
144 | { | ||
145 | struct sockaddr_un dummy; | ||
146 | size_t slen; | ||
147 | char *end; | ||
148 | struct GNUNET_HashCode sh; | ||
149 | struct GNUNET_CRYPTO_HashAsciiEncoded ae; | ||
150 | size_t upm; | ||
151 | |||
152 | upm = sizeof(dummy.sun_path); | ||
153 | slen = strlen (unixpath); | ||
154 | if (slen < upm) | ||
155 | return unixpath; /* no shortening required */ | ||
156 | GNUNET_CRYPTO_hash (unixpath, slen, &sh); | ||
157 | while (16 + strlen (unixpath) >= upm) | ||
158 | { | ||
159 | if (NULL == (end = strrchr (unixpath, '/'))) | ||
160 | { | ||
161 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
162 | _ ( | ||
163 | "Unable to shorten unix path `%s' while keeping name unique\n"), | ||
164 | unixpath); | ||
165 | GNUNET_free (unixpath); | ||
166 | return NULL; | ||
167 | } | ||
168 | *end = '\0'; | ||
169 | } | ||
170 | GNUNET_CRYPTO_hash_to_enc (&sh, &ae); | ||
171 | ae.encoding[16] = '\0'; | ||
172 | strcat (unixpath, (char *) ae.encoding); | ||
173 | return unixpath; | ||
174 | } | ||
175 | |||
176 | |||
177 | void | ||
178 | GNUNET_NETWORK_unix_precheck (const struct sockaddr_un *un) | ||
179 | { | ||
180 | int s; | ||
181 | int eno; | ||
182 | struct stat sbuf; | ||
183 | int ret; | ||
184 | |||
185 | s = socket (AF_UNIX, SOCK_STREAM, 0); | ||
186 | if (-1 == s) | ||
187 | { | ||
188 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, | ||
189 | "Failed to open AF_UNIX socket"); | ||
190 | return; | ||
191 | } | ||
192 | ret = connect (s, | ||
193 | (struct sockaddr *) un, | ||
194 | sizeof(struct sockaddr_un)); | ||
195 | eno = errno; | ||
196 | GNUNET_break (0 == close (s)); | ||
197 | if (0 == ret) | ||
198 | return; /* another process is listening, do not remove! */ | ||
199 | if (ECONNREFUSED != eno) | ||
200 | return; /* some other error, likely "no such file or directory" -- all well */ | ||
201 | /* should unlink, but sanity checks first */ | ||
202 | if (0 != stat (un->sun_path, | ||
203 | &sbuf)) | ||
204 | return; /* failed to 'stat', likely does not exist after all */ | ||
205 | if (S_IFSOCK != (S_IFMT & sbuf.st_mode)) | ||
206 | return; /* refuse to unlink anything except sockets */ | ||
207 | /* finally, really unlink */ | ||
208 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
209 | "Removing left-over `%s' from previous exeuction\n", | ||
210 | un->sun_path); | ||
211 | if (0 != unlink (un->sun_path)) | ||
212 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, | ||
213 | "unlink", | ||
214 | un->sun_path); | ||
215 | } | ||
216 | |||
217 | |||
218 | #ifndef FD_COPY | ||
219 | #define FD_COPY(s, d) do { GNUNET_memcpy ((d), (s), sizeof(fd_set)); } while (0) | ||
220 | #endif | ||
221 | |||
222 | |||
223 | enum GNUNET_GenericReturnValue | ||
224 | GNUNET_NETWORK_socket_set_blocking (struct GNUNET_NETWORK_Handle *fd, | ||
225 | int doBlock) | ||
226 | { | ||
227 | int flags = fcntl (fd->fd, F_GETFL); | ||
228 | |||
229 | if (flags == -1) | ||
230 | { | ||
231 | LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, | ||
232 | "fcntl"); | ||
233 | return GNUNET_SYSERR; | ||
234 | } | ||
235 | if (doBlock) | ||
236 | flags &= ~O_NONBLOCK; | ||
237 | |||
238 | else | ||
239 | flags |= O_NONBLOCK; | ||
240 | if (0 != fcntl (fd->fd, | ||
241 | F_SETFL, | ||
242 | flags)) | ||
243 | |||
244 | { | ||
245 | LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, | ||
246 | "fcntl"); | ||
247 | return GNUNET_SYSERR; | ||
248 | } | ||
249 | return GNUNET_OK; | ||
250 | } | ||
251 | |||
252 | |||
253 | /** | ||
254 | * Make a socket non-inheritable to child processes | ||
255 | * | ||
256 | * @param h the socket to make non-inheritable | ||
257 | * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise | ||
258 | * @warning Not implemented on Windows | ||
259 | */ | ||
260 | static int | ||
261 | socket_set_inheritable (const struct GNUNET_NETWORK_Handle *h) | ||
262 | { | ||
263 | int i; | ||
264 | i = fcntl (h->fd, F_GETFD); | ||
265 | if (i < 0) | ||
266 | return GNUNET_SYSERR; | ||
267 | if (i == (i | FD_CLOEXEC)) | ||
268 | return GNUNET_OK; | ||
269 | i |= FD_CLOEXEC; | ||
270 | if (fcntl (h->fd, F_SETFD, i) < 0) | ||
271 | return GNUNET_SYSERR; | ||
272 | |||
273 | return GNUNET_OK; | ||
274 | } | ||
275 | |||
276 | |||
277 | #ifdef DARWIN | ||
278 | /** | ||
279 | * The MSG_NOSIGNAL equivalent on Mac OS X | ||
280 | * | ||
281 | * @param h the socket to make non-delaying | ||
282 | */ | ||
283 | static int | ||
284 | socket_set_nosigpipe (const struct GNUNET_NETWORK_Handle *h) | ||
285 | { | ||
286 | int abs_value = 1; | ||
287 | |||
288 | if (0 != | ||
289 | setsockopt (h->fd, SOL_SOCKET, SO_NOSIGPIPE, | ||
290 | (const void *) &abs_value, | ||
291 | sizeof(abs_value))) | ||
292 | return GNUNET_SYSERR; | ||
293 | return GNUNET_OK; | ||
294 | } | ||
295 | |||
296 | |||
297 | #endif | ||
298 | |||
299 | |||
300 | /** | ||
301 | * Disable delays when sending data via the socket. | ||
302 | * (GNUnet makes sure that messages are as big as | ||
303 | * possible already). | ||
304 | * | ||
305 | * @param h the socket to make non-delaying | ||
306 | */ | ||
307 | static void | ||
308 | socket_set_nodelay (const struct GNUNET_NETWORK_Handle *h) | ||
309 | { | ||
310 | int value = 1; | ||
311 | |||
312 | if (0 != | ||
313 | setsockopt (h->fd, | ||
314 | IPPROTO_TCP, | ||
315 | TCP_NODELAY, | ||
316 | &value, sizeof(value))) | ||
317 | LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, | ||
318 | "setsockopt"); | ||
319 | } | ||
320 | |||
321 | |||
322 | /** | ||
323 | * Perform proper canonical initialization for a network handle. | ||
324 | * Set it to non-blocking, make it non-inheritable to child | ||
325 | * processes, disable SIGPIPE, enable "nodelay" (if non-UNIX | ||
326 | * stream socket) and check that it is smaller than FD_SETSIZE. | ||
327 | * | ||
328 | * @param h socket to initialize | ||
329 | * @param af address family of the socket | ||
330 | * @param type socket type | ||
331 | * @return #GNUNET_OK on success, #GNUNET_SYSERR if initialization | ||
332 | * failed and the handle was destroyed | ||
333 | */ | ||
334 | static int | ||
335 | initialize_network_handle (struct GNUNET_NETWORK_Handle *h, | ||
336 | int af, | ||
337 | int type) | ||
338 | { | ||
339 | int eno; | ||
340 | |||
341 | h->af = af; | ||
342 | h->type = type; | ||
343 | if (h->fd == INVALID_SOCKET) | ||
344 | { | ||
345 | eno = errno; | ||
346 | GNUNET_free (h); | ||
347 | errno = eno; | ||
348 | return GNUNET_SYSERR; | ||
349 | } | ||
350 | |||
351 | if (h->fd >= FD_SETSIZE) | ||
352 | { | ||
353 | GNUNET_break (GNUNET_OK == | ||
354 | GNUNET_NETWORK_socket_close (h)); | ||
355 | errno = EMFILE; | ||
356 | return GNUNET_SYSERR; | ||
357 | } | ||
358 | |||
359 | if (GNUNET_OK != socket_set_inheritable (h)) | ||
360 | LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
361 | "socket_set_inheritable"); | ||
362 | |||
363 | if (GNUNET_SYSERR == GNUNET_NETWORK_socket_set_blocking (h, GNUNET_NO)) | ||
364 | { | ||
365 | eno = errno; | ||
366 | GNUNET_break (0); | ||
367 | GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (h)); | ||
368 | errno = eno; | ||
369 | return GNUNET_SYSERR; | ||
370 | } | ||
371 | #ifdef DARWIN | ||
372 | if (GNUNET_SYSERR == socket_set_nosigpipe (h)) | ||
373 | { | ||
374 | eno = errno; | ||
375 | GNUNET_break (0); | ||
376 | GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (h)); | ||
377 | errno = eno; | ||
378 | return GNUNET_SYSERR; | ||
379 | } | ||
380 | #endif | ||
381 | if ((type == SOCK_STREAM) | ||
382 | #ifdef AF_UNIX | ||
383 | && (af != AF_UNIX) | ||
384 | #endif | ||
385 | ) | ||
386 | socket_set_nodelay (h); | ||
387 | return GNUNET_OK; | ||
388 | } | ||
389 | |||
390 | |||
391 | struct GNUNET_NETWORK_Handle * | ||
392 | GNUNET_NETWORK_socket_accept (const struct GNUNET_NETWORK_Handle *desc, | ||
393 | struct sockaddr *address, | ||
394 | socklen_t *address_len) | ||
395 | { | ||
396 | struct GNUNET_NETWORK_Handle *ret; | ||
397 | int eno; | ||
398 | |||
399 | ret = GNUNET_new (struct GNUNET_NETWORK_Handle); | ||
400 | #if DEBUG_NETWORK | ||
401 | { | ||
402 | struct sockaddr_storage name; | ||
403 | socklen_t namelen = sizeof(name); | ||
404 | |||
405 | int gsn = getsockname (desc->fd, | ||
406 | (struct sockaddr *) &name, | ||
407 | &namelen); | ||
408 | |||
409 | if (0 == gsn) | ||
410 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
411 | "Accepting connection on `%s'\n", | ||
412 | GNUNET_a2s ((const struct sockaddr *) &name, | ||
413 | namelen)); | ||
414 | } | ||
415 | #endif | ||
416 | ret->fd = accept (desc->fd, | ||
417 | address, | ||
418 | address_len); | ||
419 | if (-1 == ret->fd) | ||
420 | { | ||
421 | eno = errno; | ||
422 | GNUNET_free (ret); | ||
423 | errno = eno; | ||
424 | return NULL; | ||
425 | } | ||
426 | if (GNUNET_OK != | ||
427 | initialize_network_handle (ret, | ||
428 | (NULL != address) ? address->sa_family : | ||
429 | desc->af, | ||
430 | SOCK_STREAM)) | ||
431 | { | ||
432 | return NULL; | ||
433 | } | ||
434 | return ret; | ||
435 | } | ||
436 | |||
437 | |||
438 | enum GNUNET_GenericReturnValue | ||
439 | GNUNET_NETWORK_socket_bind (struct GNUNET_NETWORK_Handle *desc, | ||
440 | const struct sockaddr *address, | ||
441 | socklen_t address_len) | ||
442 | { | ||
443 | int ret; | ||
444 | |||
445 | #ifdef IPV6_V6ONLY | ||
446 | #ifdef IPPROTO_IPV6 | ||
447 | { | ||
448 | const int on = 1; | ||
449 | |||
450 | if (AF_INET6 == desc->af) | ||
451 | if (setsockopt (desc->fd, | ||
452 | IPPROTO_IPV6, | ||
453 | IPV6_V6ONLY, | ||
454 | (const void *) &on, | ||
455 | sizeof(on))) | ||
456 | LOG_STRERROR (GNUNET_ERROR_TYPE_DEBUG, | ||
457 | "setsockopt"); | ||
458 | } | ||
459 | #endif | ||
460 | #endif | ||
461 | if (AF_UNIX == address->sa_family) | ||
462 | GNUNET_NETWORK_unix_precheck ((const struct sockaddr_un *) address); | ||
463 | |||
464 | { | ||
465 | const int on = 1; | ||
466 | |||
467 | if ( (SOCK_STREAM == desc->type) && | ||
468 | (0 != setsockopt (desc->fd, | ||
469 | SOL_SOCKET, | ||
470 | SO_REUSEADDR, | ||
471 | &on, sizeof(on))) ) | ||
472 | LOG_STRERROR (GNUNET_ERROR_TYPE_DEBUG, | ||
473 | "setsockopt"); | ||
474 | } | ||
475 | { | ||
476 | /* set permissions of newly created non-abstract UNIX domain socket to | ||
477 | "user-only"; applications can choose to relax this later */ | ||
478 | mode_t old_mask = 0; /* assigned to make compiler happy */ | ||
479 | const struct sockaddr_un *un = (const struct sockaddr_un *) address; | ||
480 | int not_abstract = 0; | ||
481 | |||
482 | if ((AF_UNIX == address->sa_family) | ||
483 | && ('\0' != un->sun_path[0])) /* Not an abstract socket */ | ||
484 | not_abstract = 1; | ||
485 | if (not_abstract) | ||
486 | old_mask = umask (S_IWGRP | S_IRGRP | S_IXGRP | S_IWOTH | S_IROTH | ||
487 | | S_IXOTH); | ||
488 | |||
489 | ret = bind (desc->fd, | ||
490 | address, | ||
491 | address_len); | ||
492 | |||
493 | if (not_abstract) | ||
494 | (void) umask (old_mask); | ||
495 | } | ||
496 | if (0 != ret) | ||
497 | return GNUNET_SYSERR; | ||
498 | |||
499 | desc->addr = GNUNET_malloc (address_len); | ||
500 | GNUNET_memcpy (desc->addr, address, address_len); | ||
501 | desc->addrlen = address_len; | ||
502 | |||
503 | return GNUNET_OK; | ||
504 | } | ||
505 | |||
506 | |||
507 | enum GNUNET_GenericReturnValue | ||
508 | GNUNET_NETWORK_socket_close (struct GNUNET_NETWORK_Handle *desc) | ||
509 | { | ||
510 | int ret; | ||
511 | |||
512 | ret = close (desc->fd); | ||
513 | |||
514 | const struct sockaddr_un *un = (const struct sockaddr_un *) desc->addr; | ||
515 | |||
516 | /* Cleanup the UNIX domain socket and its parent directories in case of non | ||
517 | abstract sockets */ | ||
518 | if ((AF_UNIX == desc->af) && | ||
519 | (NULL != desc->addr) && | ||
520 | ('\0' != un->sun_path[0])) | ||
521 | { | ||
522 | char *dirname = GNUNET_strndup (un->sun_path, | ||
523 | sizeof(un->sun_path)); | ||
524 | |||
525 | if (0 != unlink (dirname)) | ||
526 | { | ||
527 | LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, | ||
528 | "unlink", | ||
529 | dirname); | ||
530 | } | ||
531 | else | ||
532 | { | ||
533 | size_t len; | ||
534 | |||
535 | len = strlen (dirname); | ||
536 | while ((len > 0) && (dirname[len] != DIR_SEPARATOR)) | ||
537 | len--; | ||
538 | dirname[len] = '\0'; | ||
539 | if ((0 != len) && (0 != rmdir (dirname))) | ||
540 | { | ||
541 | switch (errno) | ||
542 | { | ||
543 | case EACCES: | ||
544 | case ENOTEMPTY: | ||
545 | case EPERM: | ||
546 | /* these are normal and can just be ignored */ | ||
547 | break; | ||
548 | |||
549 | default: | ||
550 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, | ||
551 | "rmdir", | ||
552 | dirname); | ||
553 | break; | ||
554 | } | ||
555 | } | ||
556 | } | ||
557 | GNUNET_free (dirname); | ||
558 | } | ||
559 | GNUNET_NETWORK_socket_free_memory_only_ (desc); | ||
560 | return (ret == 0) ? GNUNET_OK : GNUNET_SYSERR; | ||
561 | } | ||
562 | |||
563 | |||
564 | /** | ||
565 | * Only free memory of a socket, keep the file descriptor untouched. | ||
566 | * | ||
567 | * @param desc socket | ||
568 | */ | ||
569 | void | ||
570 | GNUNET_NETWORK_socket_free_memory_only_ (struct GNUNET_NETWORK_Handle *desc) | ||
571 | { | ||
572 | GNUNET_free (desc->addr); | ||
573 | GNUNET_free (desc); | ||
574 | } | ||
575 | |||
576 | |||
577 | /** | ||
578 | * Box a native socket (and check that it is a socket). | ||
579 | * | ||
580 | * @param fd socket to box | ||
581 | * @return NULL on error (including not supported on target platform) | ||
582 | */ | ||
583 | struct GNUNET_NETWORK_Handle * | ||
584 | GNUNET_NETWORK_socket_box_native (int fd) | ||
585 | { | ||
586 | struct GNUNET_NETWORK_Handle *ret; | ||
587 | |||
588 | if (fcntl (fd, F_GETFD) < 0) | ||
589 | return NULL; /* invalid FD */ | ||
590 | ret = GNUNET_new (struct GNUNET_NETWORK_Handle); | ||
591 | ret->fd = fd; | ||
592 | ret->af = AF_UNSPEC; | ||
593 | return ret; | ||
594 | } | ||
595 | |||
596 | |||
597 | /** | ||
598 | * Connect a socket to some remote address. | ||
599 | * | ||
600 | * @param desc socket | ||
601 | * @param address peer address | ||
602 | * @param address_len length of @a address | ||
603 | * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise | ||
604 | */ | ||
605 | int | ||
606 | GNUNET_NETWORK_socket_connect (const struct GNUNET_NETWORK_Handle *desc, | ||
607 | const struct sockaddr *address, | ||
608 | socklen_t address_len) | ||
609 | { | ||
610 | int ret; | ||
611 | |||
612 | ret = connect (desc->fd, | ||
613 | address, | ||
614 | address_len); | ||
615 | |||
616 | return ret == 0 ? GNUNET_OK : GNUNET_SYSERR; | ||
617 | } | ||
618 | |||
619 | |||
620 | /** | ||
621 | * Get socket options | ||
622 | * | ||
623 | * @param desc socket | ||
624 | * @param level protocol level of the option | ||
625 | * @param optname identifier of the option | ||
626 | * @param optval options | ||
627 | * @param optlen length of @a optval | ||
628 | * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise | ||
629 | */ | ||
630 | int | ||
631 | GNUNET_NETWORK_socket_getsockopt (const struct GNUNET_NETWORK_Handle *desc, | ||
632 | int level, | ||
633 | int optname, | ||
634 | void *optval, | ||
635 | socklen_t *optlen) | ||
636 | { | ||
637 | int ret; | ||
638 | |||
639 | ret = getsockopt (desc->fd, | ||
640 | level, | ||
641 | optname, | ||
642 | optval, optlen); | ||
643 | |||
644 | return ret == 0 ? GNUNET_OK : GNUNET_SYSERR; | ||
645 | } | ||
646 | |||
647 | |||
648 | /** | ||
649 | * Listen on a socket | ||
650 | * | ||
651 | * @param desc socket | ||
652 | * @param backlog length of the listen queue | ||
653 | * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise | ||
654 | */ | ||
655 | int | ||
656 | GNUNET_NETWORK_socket_listen (const struct GNUNET_NETWORK_Handle *desc, | ||
657 | int backlog) | ||
658 | { | ||
659 | int ret; | ||
660 | |||
661 | ret = listen (desc->fd, | ||
662 | backlog); | ||
663 | |||
664 | return ret == 0 ? GNUNET_OK : GNUNET_SYSERR; | ||
665 | } | ||
666 | |||
667 | |||
668 | /** | ||
669 | * How much data is available to be read on this descriptor? | ||
670 | * | ||
671 | * @param desc socket | ||
672 | * @returns #GNUNET_SYSERR if no data is available, or on error! | ||
673 | */ | ||
674 | ssize_t | ||
675 | GNUNET_NETWORK_socket_recvfrom_amount (const struct GNUNET_NETWORK_Handle *desc) | ||
676 | { | ||
677 | int error; | ||
678 | |||
679 | /* How much is there to be read? */ | ||
680 | int pending; | ||
681 | |||
682 | error = ioctl (desc->fd, | ||
683 | FIONREAD, | ||
684 | &pending); | ||
685 | if (0 == error) | ||
686 | return (ssize_t) pending; | ||
687 | return GNUNET_SYSERR; | ||
688 | } | ||
689 | |||
690 | |||
691 | /** | ||
692 | * Read data from a socket (always non-blocking). | ||
693 | * | ||
694 | * @param desc socket | ||
695 | * @param buffer buffer | ||
696 | * @param length length of @a buffer | ||
697 | * @param src_addr either the source to recv from, or all zeroes | ||
698 | * to be filled in by recvfrom | ||
699 | * @param addrlen length of the @a src_addr | ||
700 | */ | ||
701 | ssize_t | ||
702 | GNUNET_NETWORK_socket_recvfrom (const struct GNUNET_NETWORK_Handle *desc, | ||
703 | void *buffer, | ||
704 | size_t length, | ||
705 | struct sockaddr *src_addr, | ||
706 | socklen_t *addrlen) | ||
707 | { | ||
708 | int flags = 0; | ||
709 | |||
710 | #ifdef MSG_DONTWAIT | ||
711 | flags |= MSG_DONTWAIT; | ||
712 | #endif | ||
713 | return recvfrom (desc->fd, | ||
714 | buffer, | ||
715 | length, | ||
716 | flags, | ||
717 | src_addr, | ||
718 | addrlen); | ||
719 | } | ||
720 | |||
721 | |||
722 | /** | ||
723 | * Read data from a connected socket (always non-blocking). | ||
724 | * | ||
725 | * @param desc socket | ||
726 | * @param buffer buffer | ||
727 | * @param length length of @a buffer | ||
728 | * @return number of bytes received, -1 on error | ||
729 | */ | ||
730 | ssize_t | ||
731 | GNUNET_NETWORK_socket_recv (const struct GNUNET_NETWORK_Handle *desc, | ||
732 | void *buffer, | ||
733 | size_t length) | ||
734 | { | ||
735 | int ret; | ||
736 | int flags; | ||
737 | |||
738 | flags = 0; | ||
739 | |||
740 | #ifdef MSG_DONTWAIT | ||
741 | flags |= MSG_DONTWAIT; | ||
742 | #endif | ||
743 | ret = recv (desc->fd, | ||
744 | buffer, | ||
745 | length, | ||
746 | flags); | ||
747 | return ret; | ||
748 | } | ||
749 | |||
750 | |||
751 | /** | ||
752 | * Send data (always non-blocking). | ||
753 | * | ||
754 | * @param desc socket | ||
755 | * @param buffer data to send | ||
756 | * @param length size of the @a buffer | ||
757 | * @return number of bytes sent, #GNUNET_SYSERR on error | ||
758 | */ | ||
759 | ssize_t | ||
760 | GNUNET_NETWORK_socket_send (const struct GNUNET_NETWORK_Handle *desc, | ||
761 | const void *buffer, | ||
762 | size_t length) | ||
763 | { | ||
764 | int ret; | ||
765 | int flags; | ||
766 | |||
767 | flags = 0; | ||
768 | #ifdef MSG_DONTWAIT | ||
769 | flags |= MSG_DONTWAIT; | ||
770 | #endif | ||
771 | #ifdef MSG_NOSIGNAL | ||
772 | flags |= MSG_NOSIGNAL; | ||
773 | #endif | ||
774 | ret = send (desc->fd, | ||
775 | buffer, | ||
776 | length, | ||
777 | flags); | ||
778 | return ret; | ||
779 | } | ||
780 | |||
781 | |||
782 | /** | ||
783 | * Send data to a particular destination (always non-blocking). | ||
784 | * This function only works for UDP sockets. | ||
785 | * | ||
786 | * @param desc socket | ||
787 | * @param message data to send | ||
788 | * @param length size of the @a message | ||
789 | * @param dest_addr destination address | ||
790 | * @param dest_len length of @a address | ||
791 | * @return number of bytes sent, #GNUNET_SYSERR on error | ||
792 | */ | ||
793 | ssize_t | ||
794 | GNUNET_NETWORK_socket_sendto (const struct GNUNET_NETWORK_Handle *desc, | ||
795 | const void *message, | ||
796 | size_t length, | ||
797 | const struct sockaddr *dest_addr, | ||
798 | socklen_t dest_len) | ||
799 | { | ||
800 | int flags = 0; | ||
801 | |||
802 | #ifdef MSG_DONTWAIT | ||
803 | flags |= MSG_DONTWAIT; | ||
804 | #endif | ||
805 | #ifdef MSG_NOSIGNAL | ||
806 | flags |= MSG_NOSIGNAL; | ||
807 | #endif | ||
808 | return sendto (desc->fd, | ||
809 | message, | ||
810 | length, | ||
811 | flags, | ||
812 | dest_addr, | ||
813 | dest_len); | ||
814 | } | ||
815 | |||
816 | |||
817 | /** | ||
818 | * Set socket option | ||
819 | * | ||
820 | * @param fd socket | ||
821 | * @param level protocol level of the option | ||
822 | * @param option_name option identifier | ||
823 | * @param option_value value to set | ||
824 | * @param option_len size of @a option_value | ||
825 | * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise | ||
826 | */ | ||
827 | int | ||
828 | GNUNET_NETWORK_socket_setsockopt (struct GNUNET_NETWORK_Handle *fd, | ||
829 | int level, | ||
830 | int option_name, | ||
831 | const void *option_value, | ||
832 | socklen_t option_len) | ||
833 | { | ||
834 | return (0 == setsockopt (fd->fd, | ||
835 | level, | ||
836 | option_name, | ||
837 | option_value, | ||
838 | option_len)) | ||
839 | ? GNUNET_OK | ||
840 | : GNUNET_SYSERR; | ||
841 | } | ||
842 | |||
843 | |||
844 | /** | ||
845 | * Create a new socket. Configure it for non-blocking IO and | ||
846 | * mark it as non-inheritable to child processes (set the | ||
847 | * close-on-exec flag). | ||
848 | * | ||
849 | * @param domain domain of the socket | ||
850 | * @param type socket type | ||
851 | * @param protocol network protocol | ||
852 | * @return new socket, NULL on error | ||
853 | */ | ||
854 | struct GNUNET_NETWORK_Handle * | ||
855 | GNUNET_NETWORK_socket_create (int domain, | ||
856 | int type, | ||
857 | int protocol) | ||
858 | { | ||
859 | struct GNUNET_NETWORK_Handle *ret; | ||
860 | int fd; | ||
861 | |||
862 | fd = socket (domain, type, protocol); | ||
863 | if (-1 == fd) | ||
864 | return NULL; | ||
865 | ret = GNUNET_new (struct GNUNET_NETWORK_Handle); | ||
866 | ret->fd = fd; | ||
867 | if (GNUNET_OK != | ||
868 | initialize_network_handle (ret, | ||
869 | domain, | ||
870 | type)) | ||
871 | return NULL; | ||
872 | return ret; | ||
873 | } | ||
874 | |||
875 | |||
876 | /** | ||
877 | * Shut down socket operations | ||
878 | * @param desc socket | ||
879 | * @param how type of shutdown | ||
880 | * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise | ||
881 | */ | ||
882 | int | ||
883 | GNUNET_NETWORK_socket_shutdown (struct GNUNET_NETWORK_Handle *desc, | ||
884 | int how) | ||
885 | { | ||
886 | int ret; | ||
887 | |||
888 | ret = shutdown (desc->fd, how); | ||
889 | |||
890 | return (0 == ret) ? GNUNET_OK : GNUNET_SYSERR; | ||
891 | } | ||
892 | |||
893 | |||
894 | /** | ||
895 | * Disable the "CORK" feature for communication with the given socket, | ||
896 | * forcing the OS to immediately flush the buffer on transmission | ||
897 | * instead of potentially buffering multiple messages. Essentially | ||
898 | * reduces the OS send buffers to zero. | ||
899 | * | ||
900 | * @param desc socket | ||
901 | * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise | ||
902 | */ | ||
903 | int | ||
904 | GNUNET_NETWORK_socket_disable_corking (struct GNUNET_NETWORK_Handle *desc) | ||
905 | { | ||
906 | int ret = 0; | ||
907 | |||
908 | #ifdef __linux__ | ||
909 | int value = 0; | ||
910 | |||
911 | if (0 != | ||
912 | (ret = | ||
913 | setsockopt (desc->fd, | ||
914 | SOL_SOCKET, | ||
915 | SO_SNDBUF, | ||
916 | &value, | ||
917 | sizeof(value)))) | ||
918 | LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, | ||
919 | "setsockopt"); | ||
920 | if (0 != | ||
921 | (ret = | ||
922 | setsockopt (desc->fd, | ||
923 | SOL_SOCKET, | ||
924 | SO_RCVBUF, | ||
925 | &value, | ||
926 | sizeof(value)))) | ||
927 | LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, | ||
928 | "setsockopt"); | ||
929 | #endif | ||
930 | return ret == 0 ? GNUNET_OK : GNUNET_SYSERR; | ||
931 | } | ||
932 | |||
933 | |||
934 | /** | ||
935 | * Reset FD set | ||
936 | * | ||
937 | * @param fds fd set | ||
938 | */ | ||
939 | void | ||
940 | GNUNET_NETWORK_fdset_zero (struct GNUNET_NETWORK_FDSet *fds) | ||
941 | { | ||
942 | FD_ZERO (&fds->sds); | ||
943 | fds->nsds = 0; | ||
944 | } | ||
945 | |||
946 | |||
947 | /** | ||
948 | * Add a socket to the FD set | ||
949 | * | ||
950 | * @param fds fd set | ||
951 | * @param desc socket to add | ||
952 | */ | ||
953 | void | ||
954 | GNUNET_NETWORK_fdset_set (struct GNUNET_NETWORK_FDSet *fds, | ||
955 | const struct GNUNET_NETWORK_Handle *desc) | ||
956 | { | ||
957 | FD_SET (desc->fd, | ||
958 | &fds->sds); | ||
959 | fds->nsds = GNUNET_MAX (fds->nsds, | ||
960 | desc->fd + 1); | ||
961 | } | ||
962 | |||
963 | |||
964 | /** | ||
965 | * Check whether a socket is part of the fd set | ||
966 | * | ||
967 | * @param fds fd set | ||
968 | * @param desc socket | ||
969 | * @return 0 if the FD is not set | ||
970 | */ | ||
971 | int | ||
972 | GNUNET_NETWORK_fdset_isset (const struct GNUNET_NETWORK_FDSet *fds, | ||
973 | const struct GNUNET_NETWORK_Handle *desc) | ||
974 | { | ||
975 | return FD_ISSET (desc->fd, | ||
976 | &fds->sds); | ||
977 | } | ||
978 | |||
979 | |||
980 | /** | ||
981 | * Add one fd set to another | ||
982 | * | ||
983 | * @param dst the fd set to add to | ||
984 | * @param src the fd set to add from | ||
985 | */ | ||
986 | void | ||
987 | GNUNET_NETWORK_fdset_add (struct GNUNET_NETWORK_FDSet *dst, | ||
988 | const struct GNUNET_NETWORK_FDSet *src) | ||
989 | { | ||
990 | int nfds; | ||
991 | |||
992 | for (nfds = src->nsds; nfds >= 0; nfds--) | ||
993 | if (FD_ISSET (nfds, &src->sds)) | ||
994 | FD_SET (nfds, &dst->sds); | ||
995 | dst->nsds = GNUNET_MAX (dst->nsds, | ||
996 | src->nsds); | ||
997 | } | ||
998 | |||
999 | |||
1000 | /** | ||
1001 | * Copy one fd set to another | ||
1002 | * | ||
1003 | * @param to destination | ||
1004 | * @param from source | ||
1005 | */ | ||
1006 | void | ||
1007 | GNUNET_NETWORK_fdset_copy (struct GNUNET_NETWORK_FDSet *to, | ||
1008 | const struct GNUNET_NETWORK_FDSet *from) | ||
1009 | { | ||
1010 | FD_COPY (&from->sds, | ||
1011 | &to->sds); | ||
1012 | to->nsds = from->nsds; | ||
1013 | } | ||
1014 | |||
1015 | |||
1016 | /** | ||
1017 | * Return file descriptor for this network handle | ||
1018 | * | ||
1019 | * @param desc wrapper to process | ||
1020 | * @return POSIX file descriptor | ||
1021 | */ | ||
1022 | int | ||
1023 | GNUNET_NETWORK_get_fd (const struct GNUNET_NETWORK_Handle *desc) | ||
1024 | { | ||
1025 | return desc->fd; | ||
1026 | } | ||
1027 | |||
1028 | |||
1029 | /** | ||
1030 | * Return sockaddr for this network handle | ||
1031 | * | ||
1032 | * @param desc wrapper to process | ||
1033 | * @return sockaddr | ||
1034 | */ | ||
1035 | struct sockaddr* | ||
1036 | GNUNET_NETWORK_get_addr (const struct GNUNET_NETWORK_Handle *desc) | ||
1037 | { | ||
1038 | return desc->addr; | ||
1039 | } | ||
1040 | |||
1041 | |||
1042 | /** | ||
1043 | * Return sockaddr length for this network handle | ||
1044 | * | ||
1045 | * @param desc wrapper to process | ||
1046 | * @return socklen_t for sockaddr | ||
1047 | */ | ||
1048 | socklen_t | ||
1049 | GNUNET_NETWORK_get_addrlen (const struct GNUNET_NETWORK_Handle *desc) | ||
1050 | { | ||
1051 | return desc->addrlen; | ||
1052 | } | ||
1053 | |||
1054 | |||
1055 | /** | ||
1056 | * Copy a native fd set | ||
1057 | * | ||
1058 | * @param to destination | ||
1059 | * @param from native source set | ||
1060 | * @param nfds the biggest socket number in from + 1 | ||
1061 | */ | ||
1062 | void | ||
1063 | GNUNET_NETWORK_fdset_copy_native (struct GNUNET_NETWORK_FDSet *to, | ||
1064 | const fd_set *from, | ||
1065 | int nfds) | ||
1066 | { | ||
1067 | FD_COPY (from, | ||
1068 | &to->sds); | ||
1069 | to->nsds = nfds; | ||
1070 | } | ||
1071 | |||
1072 | |||
1073 | /** | ||
1074 | * Set a native fd in a set | ||
1075 | * | ||
1076 | * @param to destination | ||
1077 | * @param nfd native FD to set | ||
1078 | */ | ||
1079 | void | ||
1080 | GNUNET_NETWORK_fdset_set_native (struct GNUNET_NETWORK_FDSet *to, | ||
1081 | int nfd) | ||
1082 | { | ||
1083 | GNUNET_assert ((nfd >= 0) && (nfd < FD_SETSIZE)); | ||
1084 | FD_SET (nfd, &to->sds); | ||
1085 | to->nsds = GNUNET_MAX (nfd + 1, | ||
1086 | to->nsds); | ||
1087 | } | ||
1088 | |||
1089 | |||
1090 | /** | ||
1091 | * Test native fd in a set | ||
1092 | * | ||
1093 | * @param to set to test, NULL for empty set | ||
1094 | * @param nfd native FD to test, or -1 for none | ||
1095 | * @return #GNUNET_YES if FD is set in the set | ||
1096 | */ | ||
1097 | int | ||
1098 | GNUNET_NETWORK_fdset_test_native (const struct GNUNET_NETWORK_FDSet *to, | ||
1099 | int nfd) | ||
1100 | { | ||
1101 | if ((-1 == nfd) || | ||
1102 | (NULL == to)) | ||
1103 | return GNUNET_NO; | ||
1104 | return FD_ISSET (nfd, &to->sds) ? GNUNET_YES : GNUNET_NO; | ||
1105 | } | ||
1106 | |||
1107 | |||
1108 | /** | ||
1109 | * Add a file handle to the fd set | ||
1110 | * @param fds fd set | ||
1111 | * @param h the file handle to add | ||
1112 | */ | ||
1113 | void | ||
1114 | GNUNET_NETWORK_fdset_handle_set (struct GNUNET_NETWORK_FDSet *fds, | ||
1115 | const struct GNUNET_DISK_FileHandle *h) | ||
1116 | { | ||
1117 | int fd; | ||
1118 | |||
1119 | GNUNET_assert (GNUNET_OK == | ||
1120 | GNUNET_DISK_internal_file_handle_ (h, | ||
1121 | &fd, | ||
1122 | sizeof(int))); | ||
1123 | FD_SET (fd, | ||
1124 | &fds->sds); | ||
1125 | fds->nsds = GNUNET_MAX (fd + 1, | ||
1126 | fds->nsds); | ||
1127 | } | ||
1128 | |||
1129 | |||
1130 | /** | ||
1131 | * Add a file handle to the fd set | ||
1132 | * @param fds fd set | ||
1133 | * @param h the file handle to add | ||
1134 | */ | ||
1135 | void | ||
1136 | GNUNET_NETWORK_fdset_handle_set_first (struct GNUNET_NETWORK_FDSet *fds, | ||
1137 | const struct GNUNET_DISK_FileHandle *h) | ||
1138 | { | ||
1139 | GNUNET_NETWORK_fdset_handle_set (fds, h); | ||
1140 | } | ||
1141 | |||
1142 | |||
1143 | /** | ||
1144 | * Check if a file handle is part of an fd set | ||
1145 | * | ||
1146 | * @param fds fd set | ||
1147 | * @param h file handle | ||
1148 | * @return #GNUNET_YES if the file handle is part of the set | ||
1149 | */ | ||
1150 | int | ||
1151 | GNUNET_NETWORK_fdset_handle_isset (const struct GNUNET_NETWORK_FDSet *fds, | ||
1152 | const struct GNUNET_DISK_FileHandle *h) | ||
1153 | { | ||
1154 | return FD_ISSET (h->fd, | ||
1155 | &fds->sds); | ||
1156 | } | ||
1157 | |||
1158 | |||
1159 | /** | ||
1160 | * Checks if two fd sets overlap | ||
1161 | * | ||
1162 | * @param fds1 first fd set | ||
1163 | * @param fds2 second fd set | ||
1164 | * @return #GNUNET_YES if they do overlap, #GNUNET_NO otherwise | ||
1165 | */ | ||
1166 | int | ||
1167 | GNUNET_NETWORK_fdset_overlap (const struct GNUNET_NETWORK_FDSet *fds1, | ||
1168 | const struct GNUNET_NETWORK_FDSet *fds2) | ||
1169 | { | ||
1170 | int nfds; | ||
1171 | |||
1172 | nfds = GNUNET_MIN (fds1->nsds, | ||
1173 | fds2->nsds); | ||
1174 | while (nfds > 0) | ||
1175 | { | ||
1176 | nfds--; | ||
1177 | if ((FD_ISSET (nfds, | ||
1178 | &fds1->sds)) && | ||
1179 | (FD_ISSET (nfds, | ||
1180 | &fds2->sds))) | ||
1181 | return GNUNET_YES; | ||
1182 | } | ||
1183 | return GNUNET_NO; | ||
1184 | } | ||
1185 | |||
1186 | |||
1187 | /** | ||
1188 | * Creates an fd set | ||
1189 | * | ||
1190 | * @return a new fd set | ||
1191 | */ | ||
1192 | struct GNUNET_NETWORK_FDSet * | ||
1193 | GNUNET_NETWORK_fdset_create () | ||
1194 | { | ||
1195 | struct GNUNET_NETWORK_FDSet *fds; | ||
1196 | |||
1197 | fds = GNUNET_new (struct GNUNET_NETWORK_FDSet); | ||
1198 | GNUNET_NETWORK_fdset_zero (fds); | ||
1199 | return fds; | ||
1200 | } | ||
1201 | |||
1202 | |||
1203 | /** | ||
1204 | * Releases the associated memory of an fd set | ||
1205 | * | ||
1206 | * @param fds fd set | ||
1207 | */ | ||
1208 | void | ||
1209 | GNUNET_NETWORK_fdset_destroy (struct GNUNET_NETWORK_FDSet *fds) | ||
1210 | { | ||
1211 | GNUNET_free (fds); | ||
1212 | } | ||
1213 | |||
1214 | |||
1215 | /** | ||
1216 | * Test if the given @a port is available. | ||
1217 | * | ||
1218 | * @param ipproto transport protocol to test (e.g. IPPROTO_TCP) | ||
1219 | * @param port port number to test | ||
1220 | * @return #GNUNET_OK if the port is available, #GNUNET_NO if not | ||
1221 | */ | ||
1222 | int | ||
1223 | GNUNET_NETWORK_test_port_free (int ipproto, | ||
1224 | uint16_t port) | ||
1225 | { | ||
1226 | struct GNUNET_NETWORK_Handle *socket; | ||
1227 | int bind_status; | ||
1228 | int socktype; | ||
1229 | char open_port_str[6]; | ||
1230 | struct addrinfo hint; | ||
1231 | struct addrinfo *ret; | ||
1232 | struct addrinfo *ai; | ||
1233 | |||
1234 | GNUNET_snprintf (open_port_str, | ||
1235 | sizeof(open_port_str), | ||
1236 | "%u", | ||
1237 | (unsigned int) port); | ||
1238 | socktype = (IPPROTO_TCP == ipproto) ? SOCK_STREAM : SOCK_DGRAM; | ||
1239 | ret = NULL; | ||
1240 | memset (&hint, 0, sizeof(hint)); | ||
1241 | hint.ai_family = AF_UNSPEC; /* IPv4 and IPv6 */ | ||
1242 | hint.ai_socktype = socktype; | ||
1243 | hint.ai_protocol = ipproto; | ||
1244 | hint.ai_addrlen = 0; | ||
1245 | hint.ai_addr = NULL; | ||
1246 | hint.ai_canonname = NULL; | ||
1247 | hint.ai_next = NULL; | ||
1248 | hint.ai_flags = AI_PASSIVE | AI_NUMERICSERV; /* Wild card address */ | ||
1249 | GNUNET_assert (0 == getaddrinfo (NULL, | ||
1250 | open_port_str, | ||
1251 | &hint, | ||
1252 | &ret)); | ||
1253 | bind_status = GNUNET_NO; | ||
1254 | for (ai = ret; NULL != ai; ai = ai->ai_next) | ||
1255 | { | ||
1256 | socket = GNUNET_NETWORK_socket_create (ai->ai_family, | ||
1257 | ai->ai_socktype, | ||
1258 | ai->ai_protocol); | ||
1259 | if (NULL == socket) | ||
1260 | continue; | ||
1261 | bind_status = GNUNET_NETWORK_socket_bind (socket, | ||
1262 | ai->ai_addr, | ||
1263 | ai->ai_addrlen); | ||
1264 | GNUNET_NETWORK_socket_close (socket); | ||
1265 | if (GNUNET_OK != bind_status) | ||
1266 | break; | ||
1267 | } | ||
1268 | freeaddrinfo (ret); | ||
1269 | return bind_status; | ||
1270 | } | ||
1271 | |||
1272 | |||
1273 | /** | ||
1274 | * Check if sockets or pipes meet certain conditions | ||
1275 | * | ||
1276 | * @param rfds set of sockets or pipes to be checked for readability | ||
1277 | * @param wfds set of sockets or pipes to be checked for writability | ||
1278 | * @param efds set of sockets or pipes to be checked for exceptions | ||
1279 | * @param timeout relative value when to return | ||
1280 | * @return number of selected sockets or pipes, #GNUNET_SYSERR on error | ||
1281 | */ | ||
1282 | int | ||
1283 | GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds, | ||
1284 | struct GNUNET_NETWORK_FDSet *wfds, | ||
1285 | struct GNUNET_NETWORK_FDSet *efds, | ||
1286 | const struct GNUNET_TIME_Relative timeout) | ||
1287 | { | ||
1288 | int nfds; | ||
1289 | struct timeval tv; | ||
1290 | |||
1291 | if (NULL != rfds) | ||
1292 | nfds = rfds->nsds; | ||
1293 | else | ||
1294 | nfds = 0; | ||
1295 | if (NULL != wfds) | ||
1296 | nfds = GNUNET_MAX (nfds, | ||
1297 | wfds->nsds); | ||
1298 | if (NULL != efds) | ||
1299 | nfds = GNUNET_MAX (nfds, | ||
1300 | efds->nsds); | ||
1301 | if ((0 == nfds) && | ||
1302 | (timeout.rel_value_us == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)) | ||
1303 | { | ||
1304 | GNUNET_break (0); | ||
1305 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
1306 | _ ( | ||
1307 | "Fatal internal logic error, process hangs in `%s' (abort with CTRL-C)!\n"), | ||
1308 | "select"); | ||
1309 | } | ||
1310 | if (timeout.rel_value_us / GNUNET_TIME_UNIT_SECONDS.rel_value_us > (unsigned | ||
1311 | long long) | ||
1312 | LONG_MAX) | ||
1313 | { | ||
1314 | tv.tv_sec = LONG_MAX; | ||
1315 | tv.tv_usec = 999999L; | ||
1316 | } | ||
1317 | else | ||
1318 | { | ||
1319 | tv.tv_sec = (long) (timeout.rel_value_us | ||
1320 | / GNUNET_TIME_UNIT_SECONDS.rel_value_us); | ||
1321 | tv.tv_usec = | ||
1322 | (timeout.rel_value_us | ||
1323 | - (tv.tv_sec * GNUNET_TIME_UNIT_SECONDS.rel_value_us)); | ||
1324 | } | ||
1325 | return select (nfds, | ||
1326 | (NULL != rfds) ? &rfds->sds : NULL, | ||
1327 | (NULL != wfds) ? &wfds->sds : NULL, | ||
1328 | (NULL != efds) ? &efds->sds : NULL, | ||
1329 | (timeout.rel_value_us == | ||
1330 | GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us) ? NULL : &tv); | ||
1331 | } | ||
1332 | |||
1333 | |||
1334 | /* end of network.c */ | ||