5ba849138039aac36b079c8c7ccfbf7f3cf27fdd
[oweals/gnunet.git] / src / util / network.c
1 /*\r
2      This file is part of GNUnet.\r
3      (C) 2009 Christian Grothoff (and other contributing authors)\r
4 \r
5      GNUnet is free software; you can redistribute it and/or modify\r
6      it under the terms of the GNU General Public License as published\r
7      by the Free Software Foundation; either version 2, or (at your\r
8      option) any later version.\r
9 \r
10      GNUnet is distributed in the hope that it will be useful, but\r
11      WITHOUT ANY WARRANTY; without even the implied warranty of\r
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
13      General Public License for more details.\r
14 \r
15      You should have received a copy of the GNU General Public License\r
16      along with GNUnet; see the file COPYING.  If not, write to the\r
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,\r
18      Boston, MA 02111-1307, USA.\r
19 */\r
20 \r
21 /**\r
22  * @file util/network.c\r
23  * @brief basic, low-level networking interface\r
24  * @author Nils Durner\r
25  */\r
26 \r
27 #include "platform.h"\r
28 #include "gnunet_disk_lib.h"\r
29 #include "disk.h"\r
30 #include "gnunet_container_lib.h"\r
31 \r
32 #define DEBUG_SOCK GNUNET_NO\r
33 \r
34 #ifndef INVALID_SOCKET\r
35 #define INVALID_SOCKET -1\r
36 #endif\r
37 \r
38 struct GNUNET_NETWORK_Handle\r
39 {\r
40   int fd;\r
41 };\r
42 \r
43 struct GNUNET_NETWORK_FDSet\r
44 {\r
45   /* socket descriptors */\r
46   int nsds;\r
47   fd_set sds;\r
48 #ifdef WINDOWS\r
49   /* handles */\r
50   struct GNUNET_CONTAINER_SList *handles;\r
51 #endif\r
52 };\r
53 \r
54 #ifndef FD_COPY\r
55 #define FD_COPY(s, d) (memcpy ((d), (s), sizeof (fd_set)))\r
56 #endif\r
57 \r
58 \r
59 \r
60 /**\r
61  * Set if a socket should use blocking or non-blocking IO.\r
62  * @param fd socket\r
63  * @param doBlock blocking mode\r
64  * @return GNUNET_OK on success, GNUNET_SYSERR on error\r
65  */\r
66 static int\r
67 socket_set_blocking (struct GNUNET_NETWORK_Handle *fd,\r
68                      int doBlock)\r
69 {\r
70 #if MINGW\r
71   u_long mode;\r
72   mode = !doBlock;\r
73   if (ioctlsocket (fd->fd, FIONBIO, &mode) == SOCKET_ERROR)\r
74     {\r
75       SetErrnoFromWinsockError (WSAGetLastError ());\r
76       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "ioctlsocket");\r
77       return GNUNET_SYSERR;\r
78     }\r
79   return GNUNET_OK;\r
80 \r
81 #else\r
82   /* not MINGW */\r
83   int flags = fcntl (fd->fd, F_GETFL);\r
84   if (flags == -1)\r
85     {\r
86       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "fcntl");\r
87       return GNUNET_SYSERR;\r
88     }\r
89   if (doBlock)\r
90     flags &= ~O_NONBLOCK;\r
91   else\r
92     flags |= O_NONBLOCK;\r
93   if (0 != fcntl (fd->fd, F_SETFL, flags))\r
94     {\r
95       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "fcntl");\r
96       return GNUNET_SYSERR;\r
97     }\r
98   return GNUNET_OK;\r
99 #endif\r
100 }\r
101 \r
102 \r
103 #ifndef MINGW\r
104 /**\r
105  * Make a non-inheritable to child processes\r
106  *\r
107  * @param h the socket to make non-inheritable\r
108  * @return GNUNET_OK on success, GNUNET_SYSERR otherwise\r
109  * @warning Not implemented on Windows\r
110  */\r
111 static int\r
112 socket_set_inheritable (const struct GNUNET_NETWORK_Handle\r
113                                        *h)\r
114 {\r
115   int i;\r
116 \r
117   i = fcntl (h->fd, F_GETFD);\r
118   if (i == (i | FD_CLOEXEC))\r
119     return GNUNET_OK;\r
120   return (fcntl (h->fd, F_SETFD, i | FD_CLOEXEC) == 0)\r
121     ? GNUNET_OK : GNUNET_SYSERR;\r
122 }\r
123 #endif\r
124 \r
125 \r
126 \r
127 /**\r
128  * accept a new connection on a socket\r
129  *\r
130  * @param desc bound socket\r
131  * @param address address of the connecting peer, may be NULL\r
132  * @param address_len length of address\r
133  * @return client socket\r
134  */\r
135 struct GNUNET_NETWORK_Handle *\r
136 GNUNET_NETWORK_socket_accept (const struct GNUNET_NETWORK_Handle *desc,\r
137                               struct sockaddr *address,\r
138                               socklen_t * address_len)\r
139 {\r
140   struct GNUNET_NETWORK_Handle *ret;\r
141 \r
142   ret = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle));\r
143   ret->fd = accept (desc->fd, address, address_len);\r
144   if (ret->fd == INVALID_SOCKET)\r
145     {\r
146 #ifdef MINGW\r
147       SetErrnoFromWinsockError (WSAGetLastError ());\r
148 #endif\r
149       GNUNET_free (ret);\r
150       return NULL;\r
151     }\r
152 #ifndef MINGW\r
153   if (ret->fd >= FD_SETSIZE)\r
154     {\r
155       close (desc->fd);\r
156       GNUNET_free (ret);\r
157       errno = EMFILE;\r
158       return NULL;\r
159     }\r
160 #endif\r
161   if (GNUNET_SYSERR == socket_set_blocking (ret, GNUNET_NO))\r
162     {\r
163       /* we might want to treat this one as fatal... */\r
164       GNUNET_break (0);\r
165       GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (ret));\r
166       return NULL; \r
167     }\r
168 #ifndef MINGW\r
169   if (GNUNET_OK != socket_set_inheritable (ret))\r
170     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,\r
171                          "socket_set_inheritable");\r
172 #endif\r
173   return ret;\r
174 }\r
175 \r
176 /**\r
177  * Bind to a connected socket\r
178  * @param desc socket\r
179  * @param address address to be bound\r
180  * @param address_len length of address\r
181  * @return GNUNET_OK on success, GNUNET_SYSERR otherwise\r
182  */\r
183 int\r
184 GNUNET_NETWORK_socket_bind (struct GNUNET_NETWORK_Handle *desc,\r
185                             const struct sockaddr *address,\r
186                             socklen_t address_len)\r
187 {\r
188   int ret;\r
189 \r
190   ret = bind (desc->fd, address, address_len);\r
191 #ifdef MINGW\r
192   if (SOCKET_ERROR == ret)\r
193     SetErrnoFromWinsockError (WSAGetLastError ());\r
194 #endif\r
195   return ret == 0 ? GNUNET_OK : GNUNET_SYSERR;\r
196 }\r
197 \r
198 \r
199 /**\r
200  * Close a socket\r
201  * @param desc socket\r
202  * @return GNUNET_OK on success, GNUNET_SYSERR otherwise\r
203  */\r
204 int\r
205 GNUNET_NETWORK_socket_close (struct GNUNET_NETWORK_Handle *desc)\r
206 {\r
207   int ret;\r
208   int eno;\r
209 \r
210 #ifdef MINGW\r
211   ret = closesocket (desc->fd);\r
212   SetErrnoFromWinsockError (WSAGetLastError ());  \r
213 #else\r
214   ret = close (desc->fd);\r
215 #endif  \r
216   eno = errno;\r
217   GNUNET_free (desc);\r
218   errno = eno;\r
219   return (ret == 0) ? GNUNET_OK : GNUNET_SYSERR;\r
220 }\r
221 \r
222 /**\r
223  * Connect a socket\r
224  * @param desc socket\r
225  * @param address peer address\r
226  * @param address_len length of address\r
227  * @return GNUNET_OK on success, GNUNET_SYSERR otherwise\r
228  */\r
229 int\r
230 GNUNET_NETWORK_socket_connect (const struct GNUNET_NETWORK_Handle *desc,\r
231                                const struct sockaddr *address,\r
232                                socklen_t address_len)\r
233 {\r
234   int ret;\r
235 \r
236   ret = connect (desc->fd, address, address_len);\r
237 #ifdef MINGW\r
238   if (SOCKET_ERROR == ret)\r
239     {\r
240       SetErrnoFromWinsockError (WSAGetLastError ());\r
241       if (errno == EWOULDBLOCK)\r
242         errno = EINPROGRESS;\r
243     }\r
244 #endif\r
245   return ret == 0 ? GNUNET_OK : GNUNET_SYSERR;\r
246 }\r
247 \r
248 /**\r
249  * Get socket options\r
250  *\r
251  * @param desc socket\r
252  * @param level protocol level of the option\r
253  * @param optname identifier of the option\r
254  * @param optval options\r
255  * @param optlen length of optval\r
256  * @return GNUNET_OK on success, GNUNET_SYSERR otherwise\r
257  */\r
258 int\r
259 GNUNET_NETWORK_socket_getsockopt (const struct GNUNET_NETWORK_Handle *desc,\r
260                                   int level, int optname, void *optval,\r
261                                   socklen_t * optlen)\r
262 {\r
263   int ret;\r
264 \r
265   ret = getsockopt (desc->fd, level, optname, optval, optlen);\r
266 #ifdef MINGW\r
267   if (ret == 0 && level == SOL_SOCKET && optname == SO_ERROR)\r
268     *((int *) optval) = GetErrnoFromWinsockError (*((int *) optval));\r
269   else if (SOCKET_ERROR == ret)\r
270     SetErrnoFromWinsockError (WSAGetLastError ());\r
271 #endif\r
272   return ret == 0 ? GNUNET_OK : GNUNET_SYSERR;\r
273 }\r
274 \r
275 /**\r
276  * Listen on a socket\r
277  * @param desc socket\r
278  * @param backlog length of the listen queue\r
279  * @return GNUNET_OK on success, GNUNET_SYSERR otherwise\r
280  */\r
281 int\r
282 GNUNET_NETWORK_socket_listen (const struct GNUNET_NETWORK_Handle *desc,\r
283                               int backlog)\r
284 {\r
285   int ret;\r
286 \r
287   ret = listen (desc->fd, backlog);\r
288 #ifdef MINGW\r
289   if (SOCKET_ERROR == ret)\r
290     SetErrnoFromWinsockError (WSAGetLastError ());\r
291 #endif\r
292 \r
293   return ret == 0 ? GNUNET_OK : GNUNET_SYSERR;\r
294 }\r
295 \r
296 /**\r
297  * Read data from a connected socket (always non-blocking).\r
298  * @param desc socket\r
299  * @param buffer buffer\r
300  * @param length length of buffer\r
301  */\r
302 ssize_t\r
303 GNUNET_NETWORK_socket_recv (const struct GNUNET_NETWORK_Handle * desc,\r
304                             void *buffer, size_t length)\r
305 {\r
306   int ret;\r
307   int flags;\r
308 \r
309   flags = 0;\r
310 #ifdef MSG_DONTWAIT\r
311   flags |= MSG_DONTWAIT;\r
312 #endif\r
313   ret = recv (desc->fd, buffer, length, flags);\r
314 #ifdef MINGW\r
315   if (SOCKET_ERROR == ret)\r
316     SetErrnoFromWinsockError (WSAGetLastError ());\r
317 #endif\r
318 \r
319   return ret;\r
320 }\r
321 \r
322 /**\r
323  * Send data (always non-blocking).\r
324  *\r
325  * @param desc socket\r
326  * @param buffer data to send\r
327  * @param length size of the buffer\r
328  * @return number of bytes sent, GNUNET_SYSERR on error\r
329  */\r
330 ssize_t\r
331 GNUNET_NETWORK_socket_send (const struct GNUNET_NETWORK_Handle * desc,\r
332                             const void *buffer, size_t length)\r
333 {\r
334   int ret;\r
335   int flags;\r
336 #ifdef OSX\r
337   int no_sigpipe;\r
338   no_sigpipe = 1;\r
339   /* shouldn't matter if this fails as there's a SIGPIPE handler */\r
340   ret = setsockopt (desc->fd, SOL_SOCKET, SO_NOSIGPIPE,\r
341                     (void *) &no_sigpipe, sizeof (no_sigpipe));\r
342 #endif\r
343 \r
344   flags = 0;\r
345 #ifdef MSG_DONTWAIT\r
346   flags |= MSG_DONTWAIT;\r
347 #endif\r
348 #ifdef MSG_NOSIGNAL\r
349   flags |= MSG_NOSIGNAL;\r
350 #endif\r
351   ret = send (desc->fd, buffer, length, flags);\r
352 #ifdef MINGW\r
353   if (SOCKET_ERROR == ret)\r
354     SetErrnoFromWinsockError (WSAGetLastError ());\r
355 #endif\r
356 \r
357   return ret;\r
358 }\r
359 \r
360 \r
361 /**\r
362  * Send data to a particular destination (always non-blocking).\r
363  * This function only works for UDP sockets.\r
364  *\r
365  * @param desc socket\r
366  * @param message data to send\r
367  * @param length size of the data\r
368  * @param dest_addr destination address\r
369  * @param dest_len length of address\r
370  * @return number of bytes sent, GNUNET_SYSERR on error\r
371  */\r
372 ssize_t\r
373 GNUNET_NETWORK_socket_sendto (const struct GNUNET_NETWORK_Handle * desc,\r
374                               const void *message, size_t length,\r
375                               const struct sockaddr * dest_addr,\r
376                               socklen_t dest_len)\r
377 {\r
378   int ret;\r
379   int flags;\r
380 #ifdef OSX\r
381   int no_sigpipe;\r
382   no_sigpipe = 1;\r
383   /* shouldn't matter if this fails as there's a SIGPIPE handler */\r
384   ret = setsockopt (desc->fd, SOL_SOCKET, SO_NOSIGPIPE,\r
385                     (void *) &no_sigpipe, sizeof (no_sigpipe));\r
386 #endif\r
387 \r
388   flags = 0;\r
389 #ifdef MSG_DONTWAIT\r
390   flags |= MSG_DONTWAIT;\r
391 #endif\r
392 #ifdef MSG_NOSIGNAL\r
393   flags |= MSG_NOSIGNAL;\r
394 #endif\r
395   ret = sendto (desc->fd, message, length, flags, dest_addr, dest_len);\r
396 #ifdef MINGW\r
397   if (SOCKET_ERROR == ret)\r
398     SetErrnoFromWinsockError (WSAGetLastError ());\r
399 #endif\r
400 \r
401   return ret;\r
402 }\r
403 \r
404 /**\r
405  * Set socket option\r
406  * @param fd socket\r
407  * @param level protocol level of the option\r
408  * @param option_name option identifier\r
409  * @param option_value value to set\r
410  * @param option_len size of option_value\r
411  * @return GNUNET_OK on success, GNUNET_SYSERR otherwise\r
412  */\r
413 int\r
414 GNUNET_NETWORK_socket_setsockopt (struct GNUNET_NETWORK_Handle *fd,\r
415                                   int level, int option_name,\r
416                                   const void *option_value,\r
417                                   socklen_t option_len)\r
418 {\r
419   int ret;\r
420 \r
421   ret = setsockopt (fd->fd, level, option_name, option_value, option_len);\r
422 #ifdef MINGW\r
423   if (SOCKET_ERROR == ret)\r
424     SetErrnoFromWinsockError (WSAGetLastError ());\r
425 #endif\r
426 \r
427   return ret == 0 ? GNUNET_OK : GNUNET_SYSERR;\r
428 }\r
429 \r
430 \r
431 \r
432 /**\r
433  * Create a new socket.  Configure it for non-blocking IO and\r
434  * mark it as non-inheritable to child processes (set the\r
435  * close-on-exec flag).\r
436  *\r
437  * @param domain domain of the socket\r
438  * @param type socket type\r
439  * @param protocol network protocol\r
440  * @return new socket, NULL on error\r
441  */\r
442 struct GNUNET_NETWORK_Handle *\r
443 GNUNET_NETWORK_socket_create (int domain, int type, int protocol)\r
444 {\r
445   struct GNUNET_NETWORK_Handle *ret;\r
446 \r
447   ret = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle));\r
448   ret->fd = socket (domain, type, protocol);\r
449   if (INVALID_SOCKET == ret->fd)\r
450     {\r
451 #ifdef MINGW\r
452       SetErrnoFromWinsockError (WSAGetLastError ());\r
453 #endif\r
454       GNUNET_free (ret);\r
455       return NULL;\r
456     }\r
457 #ifndef MINGW\r
458   if (ret->fd >= FD_SETSIZE)\r
459     {\r
460       close (ret->fd);\r
461       GNUNET_free (ret);\r
462       errno = EMFILE;\r
463       return NULL;\r
464     }\r
465 #endif\r
466 \r
467   if (GNUNET_SYSERR == socket_set_blocking (ret, GNUNET_NO))\r
468     {\r
469       /* we might want to treat this one as fatal... */\r
470       GNUNET_break (0);\r
471       GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (ret));\r
472       return NULL; \r
473     }\r
474 #ifndef MINGW\r
475   if (GNUNET_OK != socket_set_inheritable (ret))\r
476     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,\r
477                          "socket_set_inheritable");\r
478 #endif\r
479 \r
480   return ret;\r
481 }\r
482 \r
483 /**\r
484  * Shut down socket operations\r
485  * @param desc socket\r
486  * @param how type of shutdown\r
487  * @return GNUNET_OK on success, GNUNET_SYSERR otherwise\r
488  */\r
489 int\r
490 GNUNET_NETWORK_socket_shutdown (struct GNUNET_NETWORK_Handle *desc,\r
491                                 int how)\r
492 {\r
493   int ret;\r
494 \r
495   ret = shutdown (desc->fd, how);\r
496 #ifdef MINGW\r
497   if (ret != 0)\r
498     SetErrnoFromWinsockError (WSAGetLastError ());\r
499 #endif\r
500 \r
501   return ret == 0 ? GNUNET_OK : GNUNET_SYSERR;\r
502 }\r
503 \r
504 \r
505 /**\r
506  * Reset FD set\r
507  * @param fds fd set\r
508  */\r
509 void\r
510 GNUNET_NETWORK_fdset_zero (struct GNUNET_NETWORK_FDSet *fds)\r
511 {\r
512   FD_ZERO (&fds->sds);\r
513   fds->nsds = 0;\r
514 #ifdef MINGW\r
515   GNUNET_CONTAINER_slist_clear (fds->handles);\r
516 #endif\r
517 }\r
518 \r
519 \r
520 /**\r
521  * Add a socket to the FD set\r
522  * @param fds fd set\r
523  * @param desc socket to add\r
524  */\r
525 void\r
526 GNUNET_NETWORK_fdset_set (struct GNUNET_NETWORK_FDSet *fds,\r
527                           const struct GNUNET_NETWORK_Handle *desc)\r
528 {\r
529   FD_SET (desc->fd, &fds->sds);\r
530 \r
531   if (desc->fd + 1 > fds->nsds)\r
532     fds->nsds = desc->fd + 1;\r
533 }\r
534 \r
535 \r
536 /**\r
537  * Check whether a socket is part of the fd set\r
538  * @param fds fd set\r
539  * @param desc socket\r
540  * @return 0 if the FD is not set\r
541  */\r
542 int\r
543 GNUNET_NETWORK_fdset_isset (const struct GNUNET_NETWORK_FDSet *fds,\r
544                             const struct GNUNET_NETWORK_Handle *desc)\r
545 {\r
546   return FD_ISSET (desc->fd, &fds->sds);\r
547 }\r
548 \r
549 \r
550 /**\r
551  * Add one fd set to another\r
552  * @param dst the fd set to add to\r
553  * @param src the fd set to add from\r
554  */\r
555 void\r
556 GNUNET_NETWORK_fdset_add (struct GNUNET_NETWORK_FDSet *dst,\r
557                           const struct GNUNET_NETWORK_FDSet *src)\r
558 {\r
559   int nfds;\r
560 \r
561   for (nfds = src->nsds; nfds > 0; nfds--)\r
562     if (FD_ISSET (nfds, &src->sds))\r
563       {\r
564         FD_SET (nfds, &dst->sds);\r
565         if (nfds + 1 > dst->nsds)\r
566           dst->nsds = nfds + 1;\r
567       }\r
568 }\r
569 \r
570 \r
571 /**\r
572  * Copy one fd set to another\r
573  * @param to destination\r
574  * @param from source\r
575  */\r
576 void\r
577 GNUNET_NETWORK_fdset_copy (struct GNUNET_NETWORK_FDSet *to,\r
578                            const struct GNUNET_NETWORK_FDSet *from)\r
579 {\r
580   FD_COPY (&from->sds, &to->sds);\r
581   to->nsds = from->nsds;\r
582 #ifdef MINGW\r
583   struct GNUNET_CONTAINER_SList_Iterator *iter;\r
584 \r
585 \r
586   GNUNET_CONTAINER_slist_clear (to->handles);\r
587 \r
588   for (iter = GNUNET_CONTAINER_slist_begin (from->handles);\r
589       GNUNET_CONTAINER_slist_end (iter) != GNUNET_YES; GNUNET_CONTAINER_slist_next (iter))\r
590     {\r
591       void *handle;\r
592       size_t len;\r
593 \r
594       handle = GNUNET_CONTAINER_slist_get (iter, &len);\r
595       GNUNET_CONTAINER_slist_add (to->handles, GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT, handle, len);\r
596     }\r
597 #endif\r
598 }\r
599 \r
600 \r
601 /**\r
602  * Copy a native fd set\r
603  * @param to destination\r
604  * @param from native source set\r
605  * @param nfds the biggest socket number in from + 1\r
606  */\r
607 void\r
608 GNUNET_NETWORK_fdset_copy_native (struct GNUNET_NETWORK_FDSet *to,\r
609                                   const fd_set * from, int nfds)\r
610 {\r
611   FD_COPY (from, &to->sds);\r
612   to->nsds = nfds;\r
613 }\r
614 \r
615 \r
616 /**\r
617  * Add a file handle to the fd set\r
618  * @param fds fd set\r
619  * @param h the file handle to add\r
620  */\r
621 void\r
622 GNUNET_NETWORK_fdset_handle_set (struct GNUNET_NETWORK_FDSet *fds,\r
623                                  const struct GNUNET_DISK_FileHandle *h)\r
624 {\r
625 #ifdef MINGW\r
626   HANDLE hw;\r
627 \r
628   GNUNET_DISK_internal_file_handle_ (h, &hw, sizeof (HANDLE));\r
629   GNUNET_CONTAINER_slist_add (fds->handles, GNUNET_NO, &hw, sizeof (HANDLE));\r
630 #else\r
631   int fd;\r
632 \r
633   GNUNET_DISK_internal_file_handle_ (h, &fd, sizeof (int));\r
634   FD_SET (fd, &fds->sds);\r
635   if (fd + 1 > fds->nsds)\r
636     fds->nsds = fd + 1;\r
637 #endif\r
638 }\r
639 \r
640 /**\r
641  * Check if a file handle is part of an fd set\r
642  * @param fds fd set\r
643  * @param h file handle\r
644  * @return GNUNET_YES if the file handle is part of the set\r
645  */\r
646 int\r
647 GNUNET_NETWORK_fdset_handle_isset (const struct GNUNET_NETWORK_FDSet *fds,\r
648                                    const struct GNUNET_DISK_FileHandle *h)\r
649 {\r
650 #ifdef MINGW\r
651   return GNUNET_CONTAINER_slist_contains (fds->handles, h->h, sizeof (HANDLE));\r
652 #else\r
653   return FD_ISSET (h->fd, &fds->sds);\r
654 #endif\r
655 }\r
656 \r
657 /**\r
658  * Checks if two fd sets overlap\r
659  * @param fds1 first fd set\r
660  * @param fds2 second fd set\r
661  * @return GNUNET_YES if they do overlap, GNUNET_NO otherwise\r
662  */\r
663 int\r
664 GNUNET_NETWORK_fdset_overlap (const struct GNUNET_NETWORK_FDSet *fds1,\r
665                               const struct GNUNET_NETWORK_FDSet *fds2)\r
666 {\r
667   int nfds;\r
668 \r
669   nfds = fds1->nsds;\r
670   if (nfds < fds2->nsds)\r
671     nfds = fds2->nsds;\r
672 \r
673   for (; nfds >= 0; nfds--)\r
674     if (FD_ISSET (nfds, &fds1->sds) && FD_ISSET (nfds, &fds2->sds))\r
675       return GNUNET_YES;\r
676 \r
677   return GNUNET_NO;\r
678 }\r
679 \r
680 /**\r
681  * Creates an fd set\r
682  * @return a new fd set\r
683  */\r
684 struct GNUNET_NETWORK_FDSet *\r
685 GNUNET_NETWORK_fdset_create ()\r
686 {\r
687   struct GNUNET_NETWORK_FDSet *fds;\r
688 \r
689   fds = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_FDSet));\r
690 #ifdef MINGW\r
691   fds->handles = GNUNET_CONTAINER_slist_create ();\r
692 #endif\r
693   GNUNET_NETWORK_fdset_zero (fds);\r
694   return fds;\r
695 }\r
696 \r
697 \r
698 /**\r
699  * Releases the associated memory of an fd set\r
700  * @param fds fd set\r
701  */\r
702 void\r
703 GNUNET_NETWORK_fdset_destroy (struct GNUNET_NETWORK_FDSet *fds)\r
704 {\r
705 #ifdef MINGW\r
706   GNUNET_CONTAINER_slist_destroy (fds->handles);\r
707 #endif\r
708   GNUNET_free (fds);\r
709 }\r
710 \r
711 \r
712 /**\r
713  * Check if sockets meet certain conditions\r
714  * @param rfds set of sockets to be checked for readability\r
715  * @param wfds set of sockets to be checked for writability\r
716  * @param efds set of sockets to be checked for exceptions\r
717  * @param timeout relative value when to return\r
718  * @return number of selected sockets, GNUNET_SYSERR on error\r
719  */\r
720 int\r
721 GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds,\r
722                               struct GNUNET_NETWORK_FDSet *wfds,\r
723                               struct GNUNET_NETWORK_FDSet *efds,\r
724                               const struct GNUNET_TIME_Relative timeout)\r
725 {\r
726   int nfds;\r
727 \r
728   nfds = 0;\r
729   if (NULL != rfds)\r
730     nfds = rfds->nsds;\r
731   if (NULL != wfds)\r
732     nfds = GNUNET_MAX (nfds, wfds->nsds);\r
733   if (NULL != efds)\r
734     nfds = GNUNET_MAX (nfds, efds->nsds);\r
735 \r
736 #ifndef MINGW\r
737   struct timeval tv;\r
738 \r
739   tv.tv_sec = timeout.value / GNUNET_TIME_UNIT_SECONDS.value;\r
740   tv.tv_usec = 1000 * (timeout.value - (tv.tv_sec * GNUNET_TIME_UNIT_SECONDS.value));\r
741   if ( (nfds == 0) &&\r
742        (timeout.value == GNUNET_TIME_UNIT_FOREVER_REL.value) )\r
743     {\r
744       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,\r
745                   _("Fatal internal logic error, process hangs in `%s' (abort with CTRL-C)!\n"),\r
746                   "select");\r
747       GNUNET_break (0);\r
748     }\r
749   return select (nfds + 1, \r
750                  (rfds != NULL) ? &rfds->sds : NULL, \r
751                  (wfds != NULL) ? &wfds->sds : NULL,\r
752                  (efds != NULL) ? &efds->sds : NULL, \r
753                  (timeout.value == GNUNET_TIME_UNIT_FOREVER_REL.value) \r
754                  ? NULL \r
755                  : &tv);\r
756 #else\r
757   DWORD limit;\r
758   fd_set sock_read, sock_write, sock_except;\r
759   fd_set aread, awrite, aexcept;\r
760   int i;\r
761   struct timeval tvslice;\r
762   int retcode;\r
763   DWORD ms_total;\r
764 \r
765 #define SAFE_FD_ISSET(fd, set)  (set != NULL && FD_ISSET(fd, set))\r
766 \r
767   /* calculate how long we need to wait in milliseconds */\r
768   if (timeout.value == GNUNET_TIME_UNIT_FOREVER_REL.value)\r
769     ms_total = INFINITE;\r
770   else\r
771     ms_total = timeout.value / GNUNET_TIME_UNIT_MILLISECONDS.value;\r
772 \r
773   /* select() may be used as a portable way to sleep */\r
774   if (!(rfds || wfds || efds))\r
775     {\r
776       Sleep (ms_total);\r
777       return 0;\r
778     }\r
779 \r
780   if (rfds)\r
781     sock_read = rfds->sds;\r
782   else\r
783     FD_ZERO(&sock_read);\r
784 \r
785   if (wfds)\r
786     sock_write = wfds->sds;\r
787   else\r
788     FD_ZERO(&sock_write);\r
789 \r
790   if (efds)\r
791     sock_except = efds->sds;\r
792   else\r
793     FD_ZERO(&sock_except);\r
794 \r
795   /* multiplex between winsock select() and waiting on the handles */\r
796 \r
797   FD_ZERO (&aread);\r
798   FD_ZERO (&awrite);\r
799   FD_ZERO (&aexcept);\r
800 \r
801   limit = GetTickCount () + ms_total;\r
802   do\r
803     {\r
804       retcode = 0;\r
805 \r
806       if (nfds > 0)\r
807         {\r
808           /* overwrite the zero'd sets here; the select call\r
809            * will clear those that are not active */\r
810 \r
811           FD_COPY (&sock_read, &aread);\r
812           FD_COPY (&sock_write, &awrite);\r
813           FD_COPY (&sock_except, &aexcept);\r
814 \r
815           tvslice.tv_sec = 0;\r
816           tvslice.tv_usec = 100000;\r
817 \r
818           if ((retcode =\r
819                select (nfds + 1, &aread, &awrite, &aexcept,\r
820                        &tvslice)) == SOCKET_ERROR)\r
821             {\r
822               SetErrnoFromWinsockError (WSAGetLastError ());\r
823               if (errno == ENOTSOCK)\r
824                 errno = EBADF;\r
825 \r
826 #if DEBUG_SOCK\r
827             GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "select");\r
828 #endif\r
829 \r
830               goto select_loop_end;\r
831             }\r
832         }\r
833 \r
834       /* Poll read pipes */\r
835       if (rfds)\r
836         {\r
837           struct GNUNET_CONTAINER_SList_Iterator *i;\r
838           int on_next;\r
839 \r
840           on_next = GNUNET_NO;\r
841           for (i = GNUNET_CONTAINER_slist_begin (rfds->handles);\r
842                     GNUNET_CONTAINER_slist_end (i) != GNUNET_YES;\r
843                     on_next || GNUNET_CONTAINER_slist_next (i))\r
844             {\r
845               HANDLE h;\r
846               DWORD dwBytes;\r
847 \r
848               h = *(HANDLE *) GNUNET_CONTAINER_slist_get (i, NULL);\r
849               on_next = GNUNET_NO;\r
850 \r
851               if (!PeekNamedPipe (h, NULL, 0, NULL, &dwBytes, NULL))\r
852                 {\r
853                   GNUNET_CONTAINER_slist_erase (i);\r
854                   on_next = GNUNET_YES;\r
855 \r
856                   retcode = -1;\r
857                   SetErrnoFromWinError (GetLastError ());\r
858 #if DEBUG_SOCK\r
859                   GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "PeekNamedPipe");\r
860 #endif\r
861                   goto select_loop_end;\r
862                 }\r
863               else if (dwBytes)\r
864                 {\r
865                   retcode++;\r
866                 }\r
867               else\r
868                 {\r
869                   GNUNET_CONTAINER_slist_erase (i);\r
870                   on_next = GNUNET_YES;\r
871                 }\r
872             }\r
873         }\r
874 \r
875       /* Poll for faulty pipes */\r
876       if (efds)\r
877         {\r
878           struct GNUNET_CONTAINER_SList_Iterator *i;\r
879           int on_next;\r
880 \r
881           on_next = GNUNET_NO;\r
882           for (i = GNUNET_CONTAINER_slist_begin (efds->handles);\r
883                     GNUNET_CONTAINER_slist_end (i) != GNUNET_YES;\r
884                     on_next || GNUNET_CONTAINER_slist_next (i))\r
885             {\r
886               HANDLE h;\r
887               DWORD dwBytes;\r
888 \r
889               h = *(HANDLE *) GNUNET_CONTAINER_slist_get (i, NULL);\r
890 \r
891               if (PeekNamedPipe (h, NULL, 0, NULL, &dwBytes, NULL))\r
892                 {\r
893                   GNUNET_CONTAINER_slist_erase (i);\r
894                   on_next = GNUNET_YES;\r
895 \r
896                   retcode++;\r
897                 }\r
898               else\r
899                 on_next = GNUNET_NO;\r
900             }\r
901         }\r
902 \r
903       /* FIXME */\r
904       if (wfds)\r
905         GNUNET_assert (GNUNET_CONTAINER_slist_count (wfds->handles) == 0);\r
906 \r
907       /* Check for closed sockets */\r
908       for (i = 0; i < nfds; i++)\r
909         {\r
910           if (SAFE_FD_ISSET (i, &sock_read))\r
911             {\r
912               struct sockaddr addr;\r
913               int len;\r
914 \r
915               if (getpeername (i, &addr, &len) == SOCKET_ERROR)\r
916                 {\r
917                   int err, len;\r
918 \r
919                   len = sizeof (err);\r
920                   if (getsockopt\r
921                       (i, SOL_SOCKET, SO_ERROR, (char *) &err, &len) == 0\r
922                       && err == WSAENOTCONN)\r
923                     {\r
924                       if (!SAFE_FD_ISSET (i, &aread))\r
925                         {\r
926                           FD_SET (i, &aread);\r
927                           retcode++;\r
928                         }\r
929                     }\r
930                 }\r
931             }\r
932         }\r
933 \r
934     select_loop_end:;\r
935     }\r
936   while (retcode == 0 && (ms_total == INFINITE || GetTickCount () < limit));\r
937 \r
938   if (retcode != -1)\r
939     {\r
940       if (rfds)\r
941         {\r
942           GNUNET_NETWORK_fdset_zero (rfds);\r
943           GNUNET_NETWORK_fdset_copy_native (rfds, &aread, retcode);\r
944         }\r
945 \r
946       if (wfds)\r
947         {\r
948           GNUNET_NETWORK_fdset_zero (wfds);\r
949           GNUNET_NETWORK_fdset_copy_native (wfds, &awrite, retcode);\r
950         }\r
951 \r
952       if (efds)\r
953         {\r
954           GNUNET_NETWORK_fdset_zero (efds);\r
955           GNUNET_NETWORK_fdset_copy_native (efds, &aexcept, retcode);\r
956         }\r
957     }\r
958 \r
959   return retcode;\r
960 #endif\r
961 }\r
962 \r
963 \r
964 /* end of network.c */\r