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