diff options
author | Martin Schanzenbach <schanzen@gnunet.org> | 2023-10-18 13:37:38 +0200 |
---|---|---|
committer | Martin Schanzenbach <schanzen@gnunet.org> | 2023-10-18 13:37:38 +0200 |
commit | 9ef4abad615bea12d13be542b8ae5fbeb2dfee32 (patch) | |
tree | 8875a687e004d331c9ea6a1d511a328c72b88113 /src/util/network.c | |
parent | e95236b3ed78cd597c15f34b89385295702b627f (diff) | |
download | gnunet-9ef4abad615bea12d13be542b8ae5fbeb2dfee32.tar.gz gnunet-9ef4abad615bea12d13be542b8ae5fbeb2dfee32.zip |
NEWS: Refactoring components under src/ into lib/, plugin/, cli/ and service/
This also includes a necessary API refactoring of crypto from IDENTITY
to UTIL.
Diffstat (limited to 'src/util/network.c')
-rw-r--r-- | src/util/network.c | 1311 |
1 files changed, 0 insertions, 1311 deletions
diff --git a/src/util/network.c b/src/util/network.c deleted file mode 100644 index 8c74c5626..000000000 --- a/src/util/network.c +++ /dev/null | |||
@@ -1,1311 +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_common.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 | void | ||
565 | GNUNET_NETWORK_socket_free_memory_only_ (struct GNUNET_NETWORK_Handle *desc) | ||
566 | { | ||
567 | GNUNET_free (desc->addr); | ||
568 | GNUNET_free (desc); | ||
569 | } | ||
570 | |||
571 | |||
572 | /** | ||
573 | * Box a native socket (and check that it is a socket). | ||
574 | * | ||
575 | * @param fd socket to box | ||
576 | * @return NULL on error (including not supported on target platform) | ||
577 | */ | ||
578 | struct GNUNET_NETWORK_Handle * | ||
579 | GNUNET_NETWORK_socket_box_native (int fd) | ||
580 | { | ||
581 | struct GNUNET_NETWORK_Handle *ret; | ||
582 | |||
583 | if (fcntl (fd, F_GETFD) < 0) | ||
584 | return NULL; /* invalid FD */ | ||
585 | ret = GNUNET_new (struct GNUNET_NETWORK_Handle); | ||
586 | ret->fd = fd; | ||
587 | ret->af = AF_UNSPEC; | ||
588 | return ret; | ||
589 | } | ||
590 | |||
591 | |||
592 | /** | ||
593 | * Connect a socket to some remote address. | ||
594 | * | ||
595 | * @param desc socket | ||
596 | * @param address peer address | ||
597 | * @param address_len length of @a address | ||
598 | * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise | ||
599 | */ | ||
600 | enum GNUNET_GenericReturnValue | ||
601 | GNUNET_NETWORK_socket_connect (const struct GNUNET_NETWORK_Handle *desc, | ||
602 | const struct sockaddr *address, | ||
603 | socklen_t address_len) | ||
604 | { | ||
605 | int ret; | ||
606 | |||
607 | ret = connect (desc->fd, | ||
608 | address, | ||
609 | address_len); | ||
610 | |||
611 | return ret == 0 ? GNUNET_OK : GNUNET_SYSERR; | ||
612 | } | ||
613 | |||
614 | |||
615 | /** | ||
616 | * Get socket options | ||
617 | * | ||
618 | * @param desc socket | ||
619 | * @param level protocol level of the option | ||
620 | * @param optname identifier of the option | ||
621 | * @param optval options | ||
622 | * @param optlen length of @a optval | ||
623 | * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise | ||
624 | */ | ||
625 | enum GNUNET_GenericReturnValue | ||
626 | GNUNET_NETWORK_socket_getsockopt (const struct GNUNET_NETWORK_Handle *desc, | ||
627 | int level, | ||
628 | int optname, | ||
629 | void *optval, | ||
630 | socklen_t *optlen) | ||
631 | { | ||
632 | int ret; | ||
633 | |||
634 | ret = getsockopt (desc->fd, | ||
635 | level, | ||
636 | optname, | ||
637 | optval, optlen); | ||
638 | |||
639 | return ret == 0 ? GNUNET_OK : GNUNET_SYSERR; | ||
640 | } | ||
641 | |||
642 | |||
643 | /** | ||
644 | * Listen on a socket | ||
645 | * | ||
646 | * @param desc socket | ||
647 | * @param backlog length of the listen queue | ||
648 | * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise | ||
649 | */ | ||
650 | enum GNUNET_GenericReturnValue | ||
651 | GNUNET_NETWORK_socket_listen (const struct GNUNET_NETWORK_Handle *desc, | ||
652 | int backlog) | ||
653 | { | ||
654 | int ret; | ||
655 | |||
656 | ret = listen (desc->fd, | ||
657 | backlog); | ||
658 | |||
659 | return ret == 0 ? GNUNET_OK : GNUNET_SYSERR; | ||
660 | } | ||
661 | |||
662 | |||
663 | /** | ||
664 | * How much data is available to be read on this descriptor? | ||
665 | * | ||
666 | * @param desc socket | ||
667 | * @returns #GNUNET_SYSERR if no data is available, or on error! | ||
668 | */ | ||
669 | ssize_t | ||
670 | GNUNET_NETWORK_socket_recvfrom_amount (const struct GNUNET_NETWORK_Handle *desc) | ||
671 | { | ||
672 | int error; | ||
673 | |||
674 | /* How much is there to be read? */ | ||
675 | int pending; | ||
676 | |||
677 | error = ioctl (desc->fd, | ||
678 | FIONREAD, | ||
679 | &pending); | ||
680 | if (0 == error) | ||
681 | return (ssize_t) pending; | ||
682 | return GNUNET_SYSERR; | ||
683 | } | ||
684 | |||
685 | |||
686 | ssize_t | ||
687 | GNUNET_NETWORK_socket_recvfrom (const struct GNUNET_NETWORK_Handle *desc, | ||
688 | void *buffer, | ||
689 | size_t length, | ||
690 | struct sockaddr *src_addr, | ||
691 | socklen_t *addrlen) | ||
692 | { | ||
693 | int flags = 0; | ||
694 | |||
695 | #ifdef MSG_DONTWAIT | ||
696 | flags |= MSG_DONTWAIT; | ||
697 | #endif | ||
698 | return recvfrom (desc->fd, | ||
699 | buffer, | ||
700 | length, | ||
701 | flags, | ||
702 | src_addr, | ||
703 | addrlen); | ||
704 | } | ||
705 | |||
706 | |||
707 | /** | ||
708 | * Read data from a connected socket (always non-blocking). | ||
709 | * | ||
710 | * @param desc socket | ||
711 | * @param buffer buffer | ||
712 | * @param length length of @a buffer | ||
713 | * @return number of bytes received, -1 on error | ||
714 | */ | ||
715 | ssize_t | ||
716 | GNUNET_NETWORK_socket_recv (const struct GNUNET_NETWORK_Handle *desc, | ||
717 | void *buffer, | ||
718 | size_t length) | ||
719 | { | ||
720 | int ret; | ||
721 | int flags; | ||
722 | |||
723 | flags = 0; | ||
724 | |||
725 | #ifdef MSG_DONTWAIT | ||
726 | flags |= MSG_DONTWAIT; | ||
727 | #endif | ||
728 | ret = recv (desc->fd, | ||
729 | buffer, | ||
730 | length, | ||
731 | flags); | ||
732 | return ret; | ||
733 | } | ||
734 | |||
735 | |||
736 | ssize_t | ||
737 | GNUNET_NETWORK_socket_send (const struct GNUNET_NETWORK_Handle *desc, | ||
738 | const void *buffer, | ||
739 | size_t length) | ||
740 | { | ||
741 | int ret; | ||
742 | int flags; | ||
743 | |||
744 | flags = 0; | ||
745 | #ifdef MSG_DONTWAIT | ||
746 | flags |= MSG_DONTWAIT; | ||
747 | #endif | ||
748 | #ifdef MSG_NOSIGNAL | ||
749 | flags |= MSG_NOSIGNAL; | ||
750 | #endif | ||
751 | ret = send (desc->fd, | ||
752 | buffer, | ||
753 | length, | ||
754 | flags); | ||
755 | return ret; | ||
756 | } | ||
757 | |||
758 | |||
759 | /** | ||
760 | * Send data to a particular destination (always non-blocking). | ||
761 | * This function only works for UDP sockets. | ||
762 | * | ||
763 | * @param desc socket | ||
764 | * @param message data to send | ||
765 | * @param length size of the @a message | ||
766 | * @param dest_addr destination address | ||
767 | * @param dest_len length of @a address | ||
768 | * @return number of bytes sent, #GNUNET_SYSERR on error | ||
769 | */ | ||
770 | ssize_t | ||
771 | GNUNET_NETWORK_socket_sendto (const struct GNUNET_NETWORK_Handle *desc, | ||
772 | const void *message, | ||
773 | size_t length, | ||
774 | const struct sockaddr *dest_addr, | ||
775 | socklen_t dest_len) | ||
776 | { | ||
777 | int flags = 0; | ||
778 | |||
779 | #ifdef MSG_DONTWAIT | ||
780 | flags |= MSG_DONTWAIT; | ||
781 | #endif | ||
782 | #ifdef MSG_NOSIGNAL | ||
783 | flags |= MSG_NOSIGNAL; | ||
784 | #endif | ||
785 | return sendto (desc->fd, | ||
786 | message, | ||
787 | length, | ||
788 | flags, | ||
789 | dest_addr, | ||
790 | dest_len); | ||
791 | } | ||
792 | |||
793 | |||
794 | /** | ||
795 | * Set socket option | ||
796 | * | ||
797 | * @param fd socket | ||
798 | * @param level protocol level of the option | ||
799 | * @param option_name option identifier | ||
800 | * @param option_value value to set | ||
801 | * @param option_len size of @a option_value | ||
802 | * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise | ||
803 | */ | ||
804 | int | ||
805 | GNUNET_NETWORK_socket_setsockopt (struct GNUNET_NETWORK_Handle *fd, | ||
806 | int level, | ||
807 | int option_name, | ||
808 | const void *option_value, | ||
809 | socklen_t option_len) | ||
810 | { | ||
811 | return (0 == setsockopt (fd->fd, | ||
812 | level, | ||
813 | option_name, | ||
814 | option_value, | ||
815 | option_len)) | ||
816 | ? GNUNET_OK | ||
817 | : GNUNET_SYSERR; | ||
818 | } | ||
819 | |||
820 | |||
821 | /** | ||
822 | * Create a new socket. Configure it for non-blocking IO and | ||
823 | * mark it as non-inheritable to child processes (set the | ||
824 | * close-on-exec flag). | ||
825 | * | ||
826 | * @param domain domain of the socket | ||
827 | * @param type socket type | ||
828 | * @param protocol network protocol | ||
829 | * @return new socket, NULL on error | ||
830 | */ | ||
831 | struct GNUNET_NETWORK_Handle * | ||
832 | GNUNET_NETWORK_socket_create (int domain, | ||
833 | int type, | ||
834 | int protocol) | ||
835 | { | ||
836 | struct GNUNET_NETWORK_Handle *ret; | ||
837 | int fd; | ||
838 | |||
839 | fd = socket (domain, type, protocol); | ||
840 | if (-1 == fd) | ||
841 | return NULL; | ||
842 | ret = GNUNET_new (struct GNUNET_NETWORK_Handle); | ||
843 | ret->fd = fd; | ||
844 | if (GNUNET_OK != | ||
845 | initialize_network_handle (ret, | ||
846 | domain, | ||
847 | type)) | ||
848 | return NULL; | ||
849 | return ret; | ||
850 | } | ||
851 | |||
852 | |||
853 | /** | ||
854 | * Shut down socket operations | ||
855 | * @param desc socket | ||
856 | * @param how type of shutdown | ||
857 | * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise | ||
858 | */ | ||
859 | enum GNUNET_GenericReturnValue | ||
860 | GNUNET_NETWORK_socket_shutdown (struct GNUNET_NETWORK_Handle *desc, | ||
861 | int how) | ||
862 | { | ||
863 | int ret; | ||
864 | |||
865 | ret = shutdown (desc->fd, how); | ||
866 | |||
867 | return (0 == ret) ? GNUNET_OK : GNUNET_SYSERR; | ||
868 | } | ||
869 | |||
870 | |||
871 | /** | ||
872 | * Disable the "CORK" feature for communication with the given socket, | ||
873 | * forcing the OS to immediately flush the buffer on transmission | ||
874 | * instead of potentially buffering multiple messages. Essentially | ||
875 | * reduces the OS send buffers to zero. | ||
876 | * | ||
877 | * @param desc socket | ||
878 | * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise | ||
879 | */ | ||
880 | enum GNUNET_GenericReturnValue | ||
881 | GNUNET_NETWORK_socket_disable_corking (struct GNUNET_NETWORK_Handle *desc) | ||
882 | { | ||
883 | int ret = 0; | ||
884 | |||
885 | #ifdef __linux__ | ||
886 | int value = 0; | ||
887 | |||
888 | if (0 != | ||
889 | (ret = | ||
890 | setsockopt (desc->fd, | ||
891 | SOL_SOCKET, | ||
892 | SO_SNDBUF, | ||
893 | &value, | ||
894 | sizeof(value)))) | ||
895 | LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, | ||
896 | "setsockopt"); | ||
897 | if (0 != | ||
898 | (ret = | ||
899 | setsockopt (desc->fd, | ||
900 | SOL_SOCKET, | ||
901 | SO_RCVBUF, | ||
902 | &value, | ||
903 | sizeof(value)))) | ||
904 | LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, | ||
905 | "setsockopt"); | ||
906 | #endif | ||
907 | return ret == 0 ? GNUNET_OK : GNUNET_SYSERR; | ||
908 | } | ||
909 | |||
910 | |||
911 | /** | ||
912 | * Reset FD set | ||
913 | * | ||
914 | * @param fds fd set | ||
915 | */ | ||
916 | void | ||
917 | GNUNET_NETWORK_fdset_zero (struct GNUNET_NETWORK_FDSet *fds) | ||
918 | { | ||
919 | FD_ZERO (&fds->sds); | ||
920 | fds->nsds = 0; | ||
921 | } | ||
922 | |||
923 | |||
924 | /** | ||
925 | * Add a socket to the FD set | ||
926 | * | ||
927 | * @param fds fd set | ||
928 | * @param desc socket to add | ||
929 | */ | ||
930 | void | ||
931 | GNUNET_NETWORK_fdset_set (struct GNUNET_NETWORK_FDSet *fds, | ||
932 | const struct GNUNET_NETWORK_Handle *desc) | ||
933 | { | ||
934 | FD_SET (desc->fd, | ||
935 | &fds->sds); | ||
936 | fds->nsds = GNUNET_MAX (fds->nsds, | ||
937 | desc->fd + 1); | ||
938 | } | ||
939 | |||
940 | |||
941 | /** | ||
942 | * Check whether a socket is part of the fd set | ||
943 | * | ||
944 | * @param fds fd set | ||
945 | * @param desc socket | ||
946 | * @return 0 if the FD is not set | ||
947 | */ | ||
948 | int | ||
949 | GNUNET_NETWORK_fdset_isset (const struct GNUNET_NETWORK_FDSet *fds, | ||
950 | const struct GNUNET_NETWORK_Handle *desc) | ||
951 | { | ||
952 | return FD_ISSET (desc->fd, | ||
953 | &fds->sds); | ||
954 | } | ||
955 | |||
956 | |||
957 | /** | ||
958 | * Add one fd set to another | ||
959 | * | ||
960 | * @param dst the fd set to add to | ||
961 | * @param src the fd set to add from | ||
962 | */ | ||
963 | void | ||
964 | GNUNET_NETWORK_fdset_add (struct GNUNET_NETWORK_FDSet *dst, | ||
965 | const struct GNUNET_NETWORK_FDSet *src) | ||
966 | { | ||
967 | int nfds; | ||
968 | |||
969 | for (nfds = src->nsds; nfds >= 0; nfds--) | ||
970 | if (FD_ISSET (nfds, &src->sds)) | ||
971 | FD_SET (nfds, &dst->sds); | ||
972 | dst->nsds = GNUNET_MAX (dst->nsds, | ||
973 | src->nsds); | ||
974 | } | ||
975 | |||
976 | |||
977 | /** | ||
978 | * Copy one fd set to another | ||
979 | * | ||
980 | * @param to destination | ||
981 | * @param from source | ||
982 | */ | ||
983 | void | ||
984 | GNUNET_NETWORK_fdset_copy (struct GNUNET_NETWORK_FDSet *to, | ||
985 | const struct GNUNET_NETWORK_FDSet *from) | ||
986 | { | ||
987 | FD_COPY (&from->sds, | ||
988 | &to->sds); | ||
989 | to->nsds = from->nsds; | ||
990 | } | ||
991 | |||
992 | |||
993 | /** | ||
994 | * Return file descriptor for this network handle | ||
995 | * | ||
996 | * @param desc wrapper to process | ||
997 | * @return POSIX file descriptor | ||
998 | */ | ||
999 | int | ||
1000 | GNUNET_NETWORK_get_fd (const struct GNUNET_NETWORK_Handle *desc) | ||
1001 | { | ||
1002 | return desc->fd; | ||
1003 | } | ||
1004 | |||
1005 | |||
1006 | /** | ||
1007 | * Return sockaddr for this network handle | ||
1008 | * | ||
1009 | * @param desc wrapper to process | ||
1010 | * @return sockaddr | ||
1011 | */ | ||
1012 | struct sockaddr* | ||
1013 | GNUNET_NETWORK_get_addr (const struct GNUNET_NETWORK_Handle *desc) | ||
1014 | { | ||
1015 | return desc->addr; | ||
1016 | } | ||
1017 | |||
1018 | |||
1019 | /** | ||
1020 | * Return sockaddr length for this network handle | ||
1021 | * | ||
1022 | * @param desc wrapper to process | ||
1023 | * @return socklen_t for sockaddr | ||
1024 | */ | ||
1025 | socklen_t | ||
1026 | GNUNET_NETWORK_get_addrlen (const struct GNUNET_NETWORK_Handle *desc) | ||
1027 | { | ||
1028 | return desc->addrlen; | ||
1029 | } | ||
1030 | |||
1031 | |||
1032 | /** | ||
1033 | * Copy a native fd set | ||
1034 | * | ||
1035 | * @param to destination | ||
1036 | * @param from native source set | ||
1037 | * @param nfds the biggest socket number in from + 1 | ||
1038 | */ | ||
1039 | void | ||
1040 | GNUNET_NETWORK_fdset_copy_native (struct GNUNET_NETWORK_FDSet *to, | ||
1041 | const fd_set *from, | ||
1042 | int nfds) | ||
1043 | { | ||
1044 | FD_COPY (from, | ||
1045 | &to->sds); | ||
1046 | to->nsds = nfds; | ||
1047 | } | ||
1048 | |||
1049 | |||
1050 | /** | ||
1051 | * Set a native fd in a set | ||
1052 | * | ||
1053 | * @param to destination | ||
1054 | * @param nfd native FD to set | ||
1055 | */ | ||
1056 | void | ||
1057 | GNUNET_NETWORK_fdset_set_native (struct GNUNET_NETWORK_FDSet *to, | ||
1058 | int nfd) | ||
1059 | { | ||
1060 | GNUNET_assert ((nfd >= 0) && (nfd < FD_SETSIZE)); | ||
1061 | FD_SET (nfd, &to->sds); | ||
1062 | to->nsds = GNUNET_MAX (nfd + 1, | ||
1063 | to->nsds); | ||
1064 | } | ||
1065 | |||
1066 | |||
1067 | /** | ||
1068 | * Test native fd in a set | ||
1069 | * | ||
1070 | * @param to set to test, NULL for empty set | ||
1071 | * @param nfd native FD to test, or -1 for none | ||
1072 | * @return #GNUNET_YES if FD is set in the set | ||
1073 | */ | ||
1074 | int | ||
1075 | GNUNET_NETWORK_fdset_test_native (const struct GNUNET_NETWORK_FDSet *to, | ||
1076 | int nfd) | ||
1077 | { | ||
1078 | if ((-1 == nfd) || | ||
1079 | (NULL == to)) | ||
1080 | return GNUNET_NO; | ||
1081 | return FD_ISSET (nfd, &to->sds) ? GNUNET_YES : GNUNET_NO; | ||
1082 | } | ||
1083 | |||
1084 | |||
1085 | /** | ||
1086 | * Add a file handle to the fd set | ||
1087 | * @param fds fd set | ||
1088 | * @param h the file handle to add | ||
1089 | */ | ||
1090 | void | ||
1091 | GNUNET_NETWORK_fdset_handle_set (struct GNUNET_NETWORK_FDSet *fds, | ||
1092 | const struct GNUNET_DISK_FileHandle *h) | ||
1093 | { | ||
1094 | int fd; | ||
1095 | |||
1096 | GNUNET_assert (GNUNET_OK == | ||
1097 | GNUNET_DISK_internal_file_handle_ (h, | ||
1098 | &fd, | ||
1099 | sizeof(int))); | ||
1100 | FD_SET (fd, | ||
1101 | &fds->sds); | ||
1102 | fds->nsds = GNUNET_MAX (fd + 1, | ||
1103 | fds->nsds); | ||
1104 | } | ||
1105 | |||
1106 | |||
1107 | /** | ||
1108 | * Add a file handle to the fd set | ||
1109 | * @param fds fd set | ||
1110 | * @param h the file handle to add | ||
1111 | */ | ||
1112 | void | ||
1113 | GNUNET_NETWORK_fdset_handle_set_first (struct GNUNET_NETWORK_FDSet *fds, | ||
1114 | const struct GNUNET_DISK_FileHandle *h) | ||
1115 | { | ||
1116 | GNUNET_NETWORK_fdset_handle_set (fds, h); | ||
1117 | } | ||
1118 | |||
1119 | |||
1120 | /** | ||
1121 | * Check if a file handle is part of an fd set | ||
1122 | * | ||
1123 | * @param fds fd set | ||
1124 | * @param h file handle | ||
1125 | * @return #GNUNET_YES if the file handle is part of the set | ||
1126 | */ | ||
1127 | int | ||
1128 | GNUNET_NETWORK_fdset_handle_isset (const struct GNUNET_NETWORK_FDSet *fds, | ||
1129 | const struct GNUNET_DISK_FileHandle *h) | ||
1130 | { | ||
1131 | return FD_ISSET (h->fd, | ||
1132 | &fds->sds); | ||
1133 | } | ||
1134 | |||
1135 | |||
1136 | /** | ||
1137 | * Checks if two fd sets overlap | ||
1138 | * | ||
1139 | * @param fds1 first fd set | ||
1140 | * @param fds2 second fd set | ||
1141 | * @return #GNUNET_YES if they do overlap, #GNUNET_NO otherwise | ||
1142 | */ | ||
1143 | int | ||
1144 | GNUNET_NETWORK_fdset_overlap (const struct GNUNET_NETWORK_FDSet *fds1, | ||
1145 | const struct GNUNET_NETWORK_FDSet *fds2) | ||
1146 | { | ||
1147 | int nfds; | ||
1148 | |||
1149 | nfds = GNUNET_MIN (fds1->nsds, | ||
1150 | fds2->nsds); | ||
1151 | while (nfds > 0) | ||
1152 | { | ||
1153 | nfds--; | ||
1154 | if ((FD_ISSET (nfds, | ||
1155 | &fds1->sds)) && | ||
1156 | (FD_ISSET (nfds, | ||
1157 | &fds2->sds))) | ||
1158 | return GNUNET_YES; | ||
1159 | } | ||
1160 | return GNUNET_NO; | ||
1161 | } | ||
1162 | |||
1163 | |||
1164 | /** | ||
1165 | * Creates an fd set | ||
1166 | * | ||
1167 | * @return a new fd set | ||
1168 | */ | ||
1169 | struct GNUNET_NETWORK_FDSet * | ||
1170 | GNUNET_NETWORK_fdset_create () | ||
1171 | { | ||
1172 | struct GNUNET_NETWORK_FDSet *fds; | ||
1173 | |||
1174 | fds = GNUNET_new (struct GNUNET_NETWORK_FDSet); | ||
1175 | GNUNET_NETWORK_fdset_zero (fds); | ||
1176 | return fds; | ||
1177 | } | ||
1178 | |||
1179 | |||
1180 | /** | ||
1181 | * Releases the associated memory of an fd set | ||
1182 | * | ||
1183 | * @param fds fd set | ||
1184 | */ | ||
1185 | void | ||
1186 | GNUNET_NETWORK_fdset_destroy (struct GNUNET_NETWORK_FDSet *fds) | ||
1187 | { | ||
1188 | GNUNET_free (fds); | ||
1189 | } | ||
1190 | |||
1191 | |||
1192 | /** | ||
1193 | * Test if the given @a port is available. | ||
1194 | * | ||
1195 | * @param ipproto transport protocol to test (e.g. IPPROTO_TCP) | ||
1196 | * @param port port number to test | ||
1197 | * @return #GNUNET_OK if the port is available, #GNUNET_NO if not | ||
1198 | */ | ||
1199 | int | ||
1200 | GNUNET_NETWORK_test_port_free (int ipproto, | ||
1201 | uint16_t port) | ||
1202 | { | ||
1203 | struct GNUNET_NETWORK_Handle *socket; | ||
1204 | int bind_status; | ||
1205 | int socktype; | ||
1206 | char open_port_str[6]; | ||
1207 | struct addrinfo hint; | ||
1208 | struct addrinfo *ret; | ||
1209 | struct addrinfo *ai; | ||
1210 | |||
1211 | GNUNET_snprintf (open_port_str, | ||
1212 | sizeof(open_port_str), | ||
1213 | "%u", | ||
1214 | (unsigned int) port); | ||
1215 | socktype = (IPPROTO_TCP == ipproto) ? SOCK_STREAM : SOCK_DGRAM; | ||
1216 | ret = NULL; | ||
1217 | memset (&hint, 0, sizeof(hint)); | ||
1218 | hint.ai_family = AF_UNSPEC; /* IPv4 and IPv6 */ | ||
1219 | hint.ai_socktype = socktype; | ||
1220 | hint.ai_protocol = ipproto; | ||
1221 | hint.ai_addrlen = 0; | ||
1222 | hint.ai_addr = NULL; | ||
1223 | hint.ai_canonname = NULL; | ||
1224 | hint.ai_next = NULL; | ||
1225 | hint.ai_flags = AI_PASSIVE | AI_NUMERICSERV; /* Wild card address */ | ||
1226 | GNUNET_assert (0 == getaddrinfo (NULL, | ||
1227 | open_port_str, | ||
1228 | &hint, | ||
1229 | &ret)); | ||
1230 | bind_status = GNUNET_NO; | ||
1231 | for (ai = ret; NULL != ai; ai = ai->ai_next) | ||
1232 | { | ||
1233 | socket = GNUNET_NETWORK_socket_create (ai->ai_family, | ||
1234 | ai->ai_socktype, | ||
1235 | ai->ai_protocol); | ||
1236 | if (NULL == socket) | ||
1237 | continue; | ||
1238 | bind_status = GNUNET_NETWORK_socket_bind (socket, | ||
1239 | ai->ai_addr, | ||
1240 | ai->ai_addrlen); | ||
1241 | GNUNET_NETWORK_socket_close (socket); | ||
1242 | if (GNUNET_OK != bind_status) | ||
1243 | break; | ||
1244 | } | ||
1245 | freeaddrinfo (ret); | ||
1246 | return bind_status; | ||
1247 | } | ||
1248 | |||
1249 | |||
1250 | /** | ||
1251 | * Check if sockets or pipes meet certain conditions | ||
1252 | * | ||
1253 | * @param rfds set of sockets or pipes to be checked for readability | ||
1254 | * @param wfds set of sockets or pipes to be checked for writability | ||
1255 | * @param efds set of sockets or pipes to be checked for exceptions | ||
1256 | * @param timeout relative value when to return | ||
1257 | * @return number of selected sockets or pipes, #GNUNET_SYSERR on error | ||
1258 | */ | ||
1259 | int | ||
1260 | GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds, | ||
1261 | struct GNUNET_NETWORK_FDSet *wfds, | ||
1262 | struct GNUNET_NETWORK_FDSet *efds, | ||
1263 | const struct GNUNET_TIME_Relative timeout) | ||
1264 | { | ||
1265 | int nfds; | ||
1266 | struct timeval tv; | ||
1267 | |||
1268 | if (NULL != rfds) | ||
1269 | nfds = rfds->nsds; | ||
1270 | else | ||
1271 | nfds = 0; | ||
1272 | if (NULL != wfds) | ||
1273 | nfds = GNUNET_MAX (nfds, | ||
1274 | wfds->nsds); | ||
1275 | if (NULL != efds) | ||
1276 | nfds = GNUNET_MAX (nfds, | ||
1277 | efds->nsds); | ||
1278 | if ((0 == nfds) && | ||
1279 | (timeout.rel_value_us == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)) | ||
1280 | { | ||
1281 | GNUNET_break (0); | ||
1282 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
1283 | _ ( | ||
1284 | "Fatal internal logic error, process hangs in `%s' (abort with CTRL-C)!\n"), | ||
1285 | "select"); | ||
1286 | } | ||
1287 | if (timeout.rel_value_us / GNUNET_TIME_UNIT_SECONDS.rel_value_us > (unsigned | ||
1288 | long long) | ||
1289 | LONG_MAX) | ||
1290 | { | ||
1291 | tv.tv_sec = LONG_MAX; | ||
1292 | tv.tv_usec = 999999L; | ||
1293 | } | ||
1294 | else | ||
1295 | { | ||
1296 | tv.tv_sec = (long) (timeout.rel_value_us | ||
1297 | / GNUNET_TIME_UNIT_SECONDS.rel_value_us); | ||
1298 | tv.tv_usec = | ||
1299 | (timeout.rel_value_us | ||
1300 | - (tv.tv_sec * GNUNET_TIME_UNIT_SECONDS.rel_value_us)); | ||
1301 | } | ||
1302 | return select (nfds, | ||
1303 | (NULL != rfds) ? &rfds->sds : NULL, | ||
1304 | (NULL != wfds) ? &wfds->sds : NULL, | ||
1305 | (NULL != efds) ? &efds->sds : NULL, | ||
1306 | (timeout.rel_value_us == | ||
1307 | GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us) ? NULL : &tv); | ||
1308 | } | ||
1309 | |||
1310 | |||
1311 | /* end of network.c */ | ||