1136614e7b3b9c8f191e8c7ec77211cff93da77d
[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_NETWORK GNUNET_YES\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 socket 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 #ifdef DARWIN\r
128 /**\r
129  * The MSG_NOSIGNAL equivalent on Mac OS X\r
130  *\r
131  * @param h the socket to make non-delaying\r
132  */\r
133 static void\r
134 socket_set_nosigpipe (const struct GNUNET_NETWORK_Handle\r
135                     *h)\r
136 {\r
137   int value = 1;\r
138   if (0 != setsockopt (h->fd, SOL_SOCKET, SO_NOSIGPIPE, &value, sizeof(value)))\r
139     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,\r
140                          "setsockopt");\r
141 }\r
142 #endif\r
143 \r
144 \r
145 \r
146 /**\r
147  * Disable delays when sending data via the socket.\r
148  * (GNUnet makes sure that messages are as big as\r
149  * possible already).\r
150  *\r
151  * @param h the socket to make non-delaying\r
152  */\r
153 static void\r
154 socket_set_nodelay (const struct GNUNET_NETWORK_Handle\r
155                     *h)\r
156 {\r
157   int value = 1;\r
158   if (0 != setsockopt (h->fd, IPPROTO_TCP, TCP_NODELAY, &value, sizeof(value)))\r
159     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,\r
160                          "setsockopt");\r
161 \r
162 }\r
163 \r
164 \r
165 \r
166 /**\r
167  * accept a new connection on a socket\r
168  *\r
169  * @param desc bound socket\r
170  * @param address address of the connecting peer, may be NULL\r
171  * @param address_len length of address\r
172  * @return client socket\r
173  */\r
174 struct GNUNET_NETWORK_Handle *\r
175 GNUNET_NETWORK_socket_accept (const struct GNUNET_NETWORK_Handle *desc,\r
176                               struct sockaddr *address,\r
177                               socklen_t * address_len)\r
178 {\r
179   struct GNUNET_NETWORK_Handle *ret;\r
180 \r
181   ret = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle));\r
182   ret->fd = accept (desc->fd, address, address_len);\r
183   if (ret->fd == INVALID_SOCKET)\r
184     {\r
185 #ifdef MINGW\r
186       SetErrnoFromWinsockError (WSAGetLastError ());\r
187 #endif\r
188       GNUNET_free (ret);\r
189       return NULL;\r
190     }\r
191 #ifndef MINGW\r
192   if (ret->fd >= FD_SETSIZE)\r
193     {\r
194       GNUNET_break (0 == close (ret->fd));\r
195       GNUNET_free (ret);\r
196       errno = EMFILE;\r
197       return NULL;\r
198     }\r
199 #endif\r
200   if (GNUNET_SYSERR == socket_set_blocking (ret, GNUNET_NO))\r
201     {\r
202       /* we might want to treat this one as fatal... */\r
203       GNUNET_break (0);\r
204       GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (ret));\r
205       return NULL; \r
206     }\r
207 #ifndef MINGW\r
208   if (GNUNET_OK != socket_set_inheritable (ret))\r
209     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,\r
210                          "socket_set_inheritable");\r
211 #endif\r
212 #ifdef DARWIN\r
213   socket_set_nosigpipe (ret);  \r
214 #endif\r
215   socket_set_nodelay (ret);\r
216   return ret;\r
217 }\r
218 \r
219 /**\r
220  * Bind to a connected socket\r
221  * @param desc socket\r
222  * @param address address to be bound\r
223  * @param address_len length of address\r
224  * @return GNUNET_OK on success, GNUNET_SYSERR otherwise\r
225  */\r
226 int\r
227 GNUNET_NETWORK_socket_bind (struct GNUNET_NETWORK_Handle *desc,\r
228                             const struct sockaddr *address,\r
229                             socklen_t address_len)\r
230 {\r
231   int ret;\r
232 \r
233   ret = bind (desc->fd, address, address_len);\r
234 #ifdef MINGW\r
235   if (SOCKET_ERROR == ret)\r
236     SetErrnoFromWinsockError (WSAGetLastError ());\r
237 #endif\r
238   return ret == 0 ? GNUNET_OK : GNUNET_SYSERR;\r
239 }\r
240 \r
241 \r
242 /**\r
243  * Close a socket\r
244  * @param desc socket\r
245  * @return GNUNET_OK on success, GNUNET_SYSERR otherwise\r
246  */\r
247 int\r
248 GNUNET_NETWORK_socket_close (struct GNUNET_NETWORK_Handle *desc)\r
249 {\r
250   int ret;\r
251   int eno;\r
252 \r
253 #ifdef MINGW\r
254   ret = closesocket (desc->fd);\r
255   SetErrnoFromWinsockError (WSAGetLastError ());  \r
256 #else\r
257   ret = close (desc->fd);\r
258 #endif  \r
259   eno = errno;\r
260   GNUNET_free (desc);\r
261   errno = eno;\r
262   return (ret == 0) ? GNUNET_OK : GNUNET_SYSERR;\r
263 }\r
264 \r
265 /**\r
266  * Connect a socket\r
267  * @param desc socket\r
268  * @param address peer address\r
269  * @param address_len length of address\r
270  * @return GNUNET_OK on success, GNUNET_SYSERR otherwise\r
271  */\r
272 int\r
273 GNUNET_NETWORK_socket_connect (const struct GNUNET_NETWORK_Handle *desc,\r
274                                const struct sockaddr *address,\r
275                                socklen_t address_len)\r
276 {\r
277   int ret;\r
278 \r
279   ret = connect (desc->fd, address, address_len);\r
280 #ifdef MINGW\r
281   if (SOCKET_ERROR == ret)\r
282     {\r
283       SetErrnoFromWinsockError (WSAGetLastError ());\r
284       if (errno == EWOULDBLOCK)\r
285         errno = EINPROGRESS;\r
286     }\r
287 #endif\r
288   return ret == 0 ? GNUNET_OK : GNUNET_SYSERR;\r
289 }\r
290 \r
291 /**\r
292  * Get socket options\r
293  *\r
294  * @param desc socket\r
295  * @param level protocol level of the option\r
296  * @param optname identifier of the option\r
297  * @param optval options\r
298  * @param optlen length of optval\r
299  * @return GNUNET_OK on success, GNUNET_SYSERR otherwise\r
300  */\r
301 int\r
302 GNUNET_NETWORK_socket_getsockopt (const struct GNUNET_NETWORK_Handle *desc,\r
303                                   int level, int optname, void *optval,\r
304                                   socklen_t * optlen)\r
305 {\r
306   int ret;\r
307 \r
308   ret = getsockopt (desc->fd, level, optname, optval, optlen);\r
309 #ifdef MINGW\r
310   if (ret == 0 && level == SOL_SOCKET && optname == SO_ERROR)\r
311     *((int *) optval) = GetErrnoFromWinsockError (*((int *) optval));\r
312   else if (SOCKET_ERROR == ret)\r
313     SetErrnoFromWinsockError (WSAGetLastError ());\r
314 #endif\r
315   return ret == 0 ? GNUNET_OK : GNUNET_SYSERR;\r
316 }\r
317 \r
318 /**\r
319  * Listen on a socket\r
320  * @param desc socket\r
321  * @param backlog length of the listen queue\r
322  * @return GNUNET_OK on success, GNUNET_SYSERR otherwise\r
323  */\r
324 int\r
325 GNUNET_NETWORK_socket_listen (const struct GNUNET_NETWORK_Handle *desc,\r
326                               int backlog)\r
327 {\r
328   int ret;\r
329 \r
330   ret = listen (desc->fd, backlog);\r
331 #ifdef MINGW\r
332   if (SOCKET_ERROR == ret)\r
333     SetErrnoFromWinsockError (WSAGetLastError ());\r
334 #endif\r
335 \r
336   return ret == 0 ? GNUNET_OK : GNUNET_SYSERR;\r
337 }\r
338 \r
339 /**\r
340  * Read data from a connected socket (always non-blocking).\r
341  * @param desc socket\r
342  * @param buffer buffer\r
343  * @param length length of buffer\r
344  */\r
345 ssize_t\r
346 GNUNET_NETWORK_socket_recv (const struct GNUNET_NETWORK_Handle * desc,\r
347                             void *buffer, size_t length)\r
348 {\r
349   int ret;\r
350   int flags;\r
351 \r
352   flags = 0;\r
353 #ifdef MSG_DONTWAIT\r
354   flags |= MSG_DONTWAIT;\r
355 #endif\r
356   ret = recv (desc->fd, buffer, length, flags);\r
357 #ifdef MINGW\r
358   if (SOCKET_ERROR == ret)\r
359     SetErrnoFromWinsockError (WSAGetLastError ());\r
360 #endif\r
361 \r
362   return ret;\r
363 }\r
364 \r
365 /**\r
366  * Send data (always non-blocking).\r
367  *\r
368  * @param desc socket\r
369  * @param buffer data to send\r
370  * @param length size of the buffer\r
371  * @return number of bytes sent, GNUNET_SYSERR on error\r
372  */\r
373 ssize_t\r
374 GNUNET_NETWORK_socket_send (const struct GNUNET_NETWORK_Handle * desc,\r
375                             const void *buffer, size_t length)\r
376 {\r
377   int ret;\r
378   int flags;\r
379 \r
380   flags = 0;\r
381 #ifdef MSG_DONTWAIT\r
382   flags |= MSG_DONTWAIT;\r
383 #endif\r
384 #ifdef MSG_NOSIGNAL\r
385   flags |= MSG_NOSIGNAL;\r
386 #endif\r
387   ret = send (desc->fd, buffer, length, flags);\r
388 #ifdef MINGW\r
389   if (SOCKET_ERROR == ret)\r
390     SetErrnoFromWinsockError (WSAGetLastError ());\r
391 #endif\r
392 \r
393   return ret;\r
394 }\r
395 \r
396 \r
397 /**\r
398  * Send data to a particular destination (always non-blocking).\r
399  * This function only works for UDP sockets.\r
400  *\r
401  * @param desc socket\r
402  * @param message data to send\r
403  * @param length size of the data\r
404  * @param dest_addr destination address\r
405  * @param dest_len length of address\r
406  * @return number of bytes sent, GNUNET_SYSERR on error\r
407  */\r
408 ssize_t\r
409 GNUNET_NETWORK_socket_sendto (const struct GNUNET_NETWORK_Handle * desc,\r
410                               const void *message, size_t length,\r
411                               const struct sockaddr * dest_addr,\r
412                               socklen_t dest_len)\r
413 {\r
414   int ret;\r
415   int flags;\r
416 \r
417   flags = 0;\r
418 #ifdef MSG_DONTWAIT\r
419   flags |= MSG_DONTWAIT;\r
420 #endif\r
421 #ifdef MSG_NOSIGNAL\r
422   flags |= MSG_NOSIGNAL;\r
423 #endif\r
424   ret = sendto (desc->fd, message, length, flags, dest_addr, dest_len);\r
425 #ifdef MINGW\r
426   if (SOCKET_ERROR == ret)\r
427     SetErrnoFromWinsockError (WSAGetLastError ());\r
428 #endif\r
429 \r
430   return ret;\r
431 }\r
432 \r
433 /**\r
434  * Set socket option\r
435  * @param fd socket\r
436  * @param level protocol level of the option\r
437  * @param option_name option identifier\r
438  * @param option_value value to set\r
439  * @param option_len size of option_value\r
440  * @return GNUNET_OK on success, GNUNET_SYSERR otherwise\r
441  */\r
442 int\r
443 GNUNET_NETWORK_socket_setsockopt (struct GNUNET_NETWORK_Handle *fd,\r
444                                   int level, int option_name,\r
445                                   const void *option_value,\r
446                                   socklen_t option_len)\r
447 {\r
448   int ret;\r
449 \r
450   ret = setsockopt (fd->fd, level, option_name, option_value, option_len);\r
451 #ifdef MINGW\r
452   if (SOCKET_ERROR == ret)\r
453     SetErrnoFromWinsockError (WSAGetLastError ());\r
454 #endif\r
455 \r
456   return ret == 0 ? GNUNET_OK : GNUNET_SYSERR;\r
457 }\r
458 \r
459 \r
460 \r
461 /**\r
462  * Create a new socket.  Configure it for non-blocking IO and\r
463  * mark it as non-inheritable to child processes (set the\r
464  * close-on-exec flag).\r
465  *\r
466  * @param domain domain of the socket\r
467  * @param type socket type\r
468  * @param protocol network protocol\r
469  * @return new socket, NULL on error\r
470  */\r
471 struct GNUNET_NETWORK_Handle *\r
472 GNUNET_NETWORK_socket_create (int domain, int type, int protocol)\r
473 {\r
474   struct GNUNET_NETWORK_Handle *ret;\r
475 \r
476   ret = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle));\r
477   ret->fd = socket (domain, type, protocol);\r
478   if (INVALID_SOCKET == ret->fd)\r
479     {\r
480 #ifdef MINGW\r
481       SetErrnoFromWinsockError (WSAGetLastError ());\r
482 #endif\r
483       GNUNET_free (ret);\r
484       return NULL;\r
485     }\r
486 #ifndef MINGW\r
487   if (ret->fd >= FD_SETSIZE)\r
488     {\r
489       GNUNET_break (0 == close (ret->fd));\r
490       GNUNET_free (ret);\r
491       errno = EMFILE;\r
492       return NULL;\r
493     }\r
494 #endif\r
495 \r
496   if (GNUNET_SYSERR == socket_set_blocking (ret, GNUNET_NO))\r
497     {\r
498       /* we might want to treat this one as fatal... */\r
499       GNUNET_break (0);\r
500       GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (ret));\r
501       return NULL; \r
502     }\r
503 #ifndef MINGW\r
504   if (GNUNET_OK != socket_set_inheritable (ret))\r
505     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,\r
506                          "socket_set_inheritable");\r
507 #endif\r
508 #ifdef DARWIN\r
509   socket_set_nosigpipe (ret);  \r
510 #endif\r
511   if (type == SOCK_STREAM)\r
512     socket_set_nodelay (ret);\r
513 \r
514   return ret;\r
515 }\r
516 \r
517 /**\r
518  * Shut down socket operations\r
519  * @param desc socket\r
520  * @param how type of shutdown\r
521  * @return GNUNET_OK on success, GNUNET_SYSERR otherwise\r
522  */\r
523 int\r
524 GNUNET_NETWORK_socket_shutdown (struct GNUNET_NETWORK_Handle *desc,\r
525                                 int how)\r
526 {\r
527   int ret;\r
528 \r
529   ret = shutdown (desc->fd, how);\r
530 #ifdef MINGW\r
531   if (ret != 0)\r
532     SetErrnoFromWinsockError (WSAGetLastError ());\r
533 #endif\r
534 \r
535   return ret == 0 ? GNUNET_OK : GNUNET_SYSERR;\r
536 }\r
537 \r
538 \r
539 /**\r
540  * Reset FD set\r
541  * @param fds fd set\r
542  */\r
543 void\r
544 GNUNET_NETWORK_fdset_zero (struct GNUNET_NETWORK_FDSet *fds)\r
545 {\r
546   FD_ZERO (&fds->sds);\r
547   fds->nsds = 0;\r
548 #ifdef MINGW\r
549   GNUNET_CONTAINER_slist_clear (fds->handles);\r
550 #endif\r
551 }\r
552 \r
553 \r
554 /**\r
555  * Add a socket to the FD set\r
556  * @param fds fd set\r
557  * @param desc socket to add\r
558  */\r
559 void\r
560 GNUNET_NETWORK_fdset_set (struct GNUNET_NETWORK_FDSet *fds,\r
561                           const struct GNUNET_NETWORK_Handle *desc)\r
562 {\r
563   FD_SET (desc->fd, &fds->sds);\r
564 \r
565   if (desc->fd + 1 > fds->nsds)\r
566     fds->nsds = desc->fd + 1;\r
567 }\r
568 \r
569 \r
570 /**\r
571  * Check whether a socket is part of the fd set\r
572  * @param fds fd set\r
573  * @param desc socket\r
574  * @return 0 if the FD is not set\r
575  */\r
576 int\r
577 GNUNET_NETWORK_fdset_isset (const struct GNUNET_NETWORK_FDSet *fds,\r
578                             const struct GNUNET_NETWORK_Handle *desc)\r
579 {\r
580   return FD_ISSET (desc->fd, &fds->sds);\r
581 }\r
582 \r
583 \r
584 /**\r
585  * Add one fd set to another\r
586  * @param dst the fd set to add to\r
587  * @param src the fd set to add from\r
588  */\r
589 void\r
590 GNUNET_NETWORK_fdset_add (struct GNUNET_NETWORK_FDSet *dst,\r
591                           const struct GNUNET_NETWORK_FDSet *src)\r
592 {\r
593   int nfds;\r
594 \r
595   for (nfds = src->nsds; nfds > 0; nfds--)\r
596     if (FD_ISSET (nfds, &src->sds))\r
597       {\r
598         FD_SET (nfds, &dst->sds);\r
599         if (nfds + 1 > dst->nsds)\r
600           dst->nsds = nfds + 1;\r
601       }\r
602 }\r
603 \r
604 \r
605 /**\r
606  * Copy one fd set to another\r
607  * @param to destination\r
608  * @param from source\r
609  */\r
610 void\r
611 GNUNET_NETWORK_fdset_copy (struct GNUNET_NETWORK_FDSet *to,\r
612                            const struct GNUNET_NETWORK_FDSet *from)\r
613 {\r
614   FD_COPY (&from->sds, &to->sds);\r
615   to->nsds = from->nsds;\r
616 #ifdef MINGW\r
617   struct GNUNET_CONTAINER_SList_Iterator *iter;\r
618 \r
619 \r
620   GNUNET_CONTAINER_slist_clear (to->handles);\r
621 \r
622   for (iter = GNUNET_CONTAINER_slist_begin (from->handles);\r
623       GNUNET_CONTAINER_slist_end (iter) != GNUNET_YES; GNUNET_CONTAINER_slist_next (iter))\r
624     {\r
625       void *handle;\r
626       size_t len;\r
627 \r
628       handle = GNUNET_CONTAINER_slist_get (iter, &len);\r
629       GNUNET_CONTAINER_slist_add (to->handles, GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT, handle, len);\r
630     }\r
631 #endif\r
632 }\r
633 \r
634 \r
635 /**\r
636  * Copy a native fd set\r
637  * @param to destination\r
638  * @param from native source set\r
639  * @param nfds the biggest socket number in from + 1\r
640  */\r
641 void\r
642 GNUNET_NETWORK_fdset_copy_native (struct GNUNET_NETWORK_FDSet *to,\r
643                                   const fd_set * from, int nfds)\r
644 {\r
645   FD_COPY (from, &to->sds);\r
646   to->nsds = nfds;\r
647 }\r
648 \r
649 \r
650 /**\r
651  * Add a file handle to the fd set\r
652  * @param fds fd set\r
653  * @param h the file handle to add\r
654  */\r
655 void\r
656 GNUNET_NETWORK_fdset_handle_set (struct GNUNET_NETWORK_FDSet *fds,\r
657                                  const struct GNUNET_DISK_FileHandle *h)\r
658 {\r
659 #ifdef MINGW\r
660   HANDLE hw;\r
661 \r
662   GNUNET_DISK_internal_file_handle_ (h, &hw, sizeof (HANDLE));\r
663   GNUNET_CONTAINER_slist_add (fds->handles, GNUNET_NO, &hw, sizeof (HANDLE));\r
664 #else\r
665   int fd;\r
666 \r
667   GNUNET_DISK_internal_file_handle_ (h, &fd, sizeof (int));\r
668   FD_SET (fd, &fds->sds);\r
669   if (fd + 1 > fds->nsds)\r
670     fds->nsds = fd + 1;\r
671 #endif\r
672 }\r
673 \r
674 /**\r
675  * Check if a file handle is part of an fd set\r
676  * @param fds fd set\r
677  * @param h file handle\r
678  * @return GNUNET_YES if the file handle is part of the set\r
679  */\r
680 int\r
681 GNUNET_NETWORK_fdset_handle_isset (const struct GNUNET_NETWORK_FDSet *fds,\r
682                                    const struct GNUNET_DISK_FileHandle *h)\r
683 {\r
684 #ifdef MINGW\r
685   return GNUNET_CONTAINER_slist_contains (fds->handles, h->h, sizeof (HANDLE));\r
686 #else\r
687   return FD_ISSET (h->fd, &fds->sds);\r
688 #endif\r
689 }\r
690 \r
691 /**\r
692  * Checks if two fd sets overlap\r
693  * @param fds1 first fd set\r
694  * @param fds2 second fd set\r
695  * @return GNUNET_YES if they do overlap, GNUNET_NO otherwise\r
696  */\r
697 int\r
698 GNUNET_NETWORK_fdset_overlap (const struct GNUNET_NETWORK_FDSet *fds1,\r
699                               const struct GNUNET_NETWORK_FDSet *fds2)\r
700 {\r
701   int nfds;\r
702 \r
703   nfds = fds1->nsds;\r
704   if (nfds < fds2->nsds)\r
705     nfds = fds2->nsds;\r
706 \r
707   for (; nfds >= 0; nfds--)\r
708     if (FD_ISSET (nfds, &fds1->sds) && FD_ISSET (nfds, &fds2->sds))\r
709       return GNUNET_YES;\r
710 \r
711   return GNUNET_NO;\r
712 }\r
713 \r
714 /**\r
715  * Creates an fd set\r
716  * @return a new fd set\r
717  */\r
718 struct GNUNET_NETWORK_FDSet *\r
719 GNUNET_NETWORK_fdset_create ()\r
720 {\r
721   struct GNUNET_NETWORK_FDSet *fds;\r
722 \r
723   fds = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_FDSet));\r
724 #ifdef MINGW\r
725   fds->handles = GNUNET_CONTAINER_slist_create ();\r
726 #endif\r
727   GNUNET_NETWORK_fdset_zero (fds);\r
728   return fds;\r
729 }\r
730 \r
731 \r
732 /**\r
733  * Releases the associated memory of an fd set\r
734  * @param fds fd set\r
735  */\r
736 void\r
737 GNUNET_NETWORK_fdset_destroy (struct GNUNET_NETWORK_FDSet *fds)\r
738 {\r
739 #ifdef MINGW\r
740   GNUNET_CONTAINER_slist_destroy (fds->handles);\r
741 #endif\r
742   GNUNET_free (fds);\r
743 }\r
744 \r
745 \r
746 /**\r
747  * Check if sockets meet certain conditions\r
748  * @param rfds set of sockets to be checked for readability\r
749  * @param wfds set of sockets to be checked for writability\r
750  * @param efds set of sockets to be checked for exceptions\r
751  * @param timeout relative value when to return\r
752  * @return number of selected sockets, GNUNET_SYSERR on error\r
753  */\r
754 int\r
755 GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds,\r
756                               struct GNUNET_NETWORK_FDSet *wfds,\r
757                               struct GNUNET_NETWORK_FDSet *efds,\r
758                               const struct GNUNET_TIME_Relative timeout)\r
759 {\r
760   int nfds;\r
761 \r
762   nfds = 0;\r
763   if (NULL != rfds)\r
764     nfds = rfds->nsds;\r
765   if (NULL != wfds)\r
766     nfds = GNUNET_MAX (nfds, wfds->nsds);\r
767   if (NULL != efds)\r
768     nfds = GNUNET_MAX (nfds, efds->nsds);\r
769 \r
770 #ifndef MINGW\r
771   struct timeval tv;\r
772 \r
773   tv.tv_sec = timeout.value / GNUNET_TIME_UNIT_SECONDS.value;\r
774   tv.tv_usec = 1000 * (timeout.value - (tv.tv_sec * GNUNET_TIME_UNIT_SECONDS.value));\r
775   if ( (nfds == 0) &&\r
776        (timeout.value == GNUNET_TIME_UNIT_FOREVER_REL.value) )\r
777     {\r
778       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,\r
779                   _("Fatal internal logic error, process hangs in `%s' (abort with CTRL-C)!\n"),\r
780                   "select");\r
781       GNUNET_break (0);\r
782     }\r
783   return select (nfds + 1, \r
784                  (rfds != NULL) ? &rfds->sds : NULL, \r
785                  (wfds != NULL) ? &wfds->sds : NULL,\r
786                  (efds != NULL) ? &efds->sds : NULL, \r
787                  (timeout.value == GNUNET_TIME_UNIT_FOREVER_REL.value) \r
788                  ? NULL \r
789                  : &tv);\r
790 #else\r
791   DWORD limit;\r
792   fd_set sock_read, sock_write, sock_except;\r
793   fd_set aread, awrite, aexcept;\r
794   int i;\r
795   struct timeval tvslice;\r
796   int retcode;\r
797   DWORD ms_total;\r
798 \r
799 #define SAFE_FD_ISSET(fd, set)  (set != NULL && FD_ISSET(fd, set))\r
800 \r
801   /* calculate how long we need to wait in milliseconds */\r
802   if (timeout.value == GNUNET_TIME_UNIT_FOREVER_REL.value)\r
803     ms_total = INFINITE;\r
804   else\r
805     ms_total = timeout.value / GNUNET_TIME_UNIT_MILLISECONDS.value;\r
806 \r
807   /* select() may be used as a portable way to sleep */\r
808   if (!(rfds || wfds || efds))\r
809     {\r
810       Sleep (ms_total);\r
811       return 0;\r
812     }\r
813 \r
814   if (rfds)\r
815     sock_read = rfds->sds;\r
816   else\r
817     FD_ZERO(&sock_read);\r
818 \r
819   if (wfds)\r
820     sock_write = wfds->sds;\r
821   else\r
822     FD_ZERO(&sock_write);\r
823 \r
824   if (efds)\r
825     sock_except = efds->sds;\r
826   else\r
827     FD_ZERO(&sock_except);\r
828 \r
829   /* multiplex between winsock select() and waiting on the handles */\r
830 \r
831   FD_ZERO (&aread);\r
832   FD_ZERO (&awrite);\r
833   FD_ZERO (&aexcept);\r
834 \r
835   limit = GetTickCount () + ms_total;\r
836   do\r
837     {\r
838       retcode = 0;\r
839 \r
840       if (nfds > 0)\r
841         {\r
842           /* overwrite the zero'd sets here; the select call\r
843            * will clear those that are not active */\r
844 \r
845           FD_COPY (&sock_read, &aread);\r
846           FD_COPY (&sock_write, &awrite);\r
847           FD_COPY (&sock_except, &aexcept);\r
848 \r
849           tvslice.tv_sec = 0;\r
850           tvslice.tv_usec = 100000;\r
851 \r
852           if ((retcode =\r
853                select (nfds + 1, &aread, &awrite, &aexcept,\r
854                        &tvslice)) == SOCKET_ERROR)\r
855             {\r
856               SetErrnoFromWinsockError (WSAGetLastError ());\r
857               if (errno == ENOTSOCK)\r
858                 errno = EBADF;\r
859 \r
860 #if DEBUG_NETWORK\r
861             GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "select");\r
862 #endif\r
863 \r
864               goto select_loop_end;\r
865             }\r
866         }\r
867 \r
868       /* Poll read pipes */\r
869       if (rfds)\r
870         {\r
871           struct GNUNET_CONTAINER_SList_Iterator *i;\r
872           int on_next;\r
873 \r
874           on_next = GNUNET_NO;\r
875           for (i = GNUNET_CONTAINER_slist_begin (rfds->handles);\r
876                     GNUNET_CONTAINER_slist_end (i) != GNUNET_YES;\r
877                     on_next || GNUNET_CONTAINER_slist_next (i))\r
878             {\r
879               HANDLE h;\r
880               DWORD dwBytes;\r
881 \r
882               h = *(HANDLE *) GNUNET_CONTAINER_slist_get (i, NULL);\r
883               on_next = GNUNET_NO;\r
884 \r
885               if (!PeekNamedPipe (h, NULL, 0, NULL, &dwBytes, NULL))\r
886                 {\r
887                   GNUNET_CONTAINER_slist_erase (i);\r
888                   on_next = GNUNET_YES;\r
889 \r
890                   retcode = -1;\r
891                   SetErrnoFromWinError (GetLastError ());\r
892 #if DEBUG_NETWORK\r
893                   GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "PeekNamedPipe");\r
894 #endif\r
895                   goto select_loop_end;\r
896                 }\r
897               else if (dwBytes)\r
898                 {\r
899                   retcode++;\r
900                 }\r
901               else\r
902                 {\r
903                   GNUNET_CONTAINER_slist_erase (i);\r
904                   on_next = GNUNET_YES;\r
905                 }\r
906             }\r
907         }\r
908 \r
909       /* Poll for faulty pipes */\r
910       if (efds)\r
911         {\r
912           struct GNUNET_CONTAINER_SList_Iterator *i;\r
913           int on_next;\r
914 \r
915           on_next = GNUNET_NO;\r
916           for (i = GNUNET_CONTAINER_slist_begin (efds->handles);\r
917                     GNUNET_CONTAINER_slist_end (i) != GNUNET_YES;\r
918                     on_next || GNUNET_CONTAINER_slist_next (i))\r
919             {\r
920               HANDLE h;\r
921               DWORD dwBytes;\r
922 \r
923               h = *(HANDLE *) GNUNET_CONTAINER_slist_get (i, NULL);\r
924 \r
925               if (PeekNamedPipe (h, NULL, 0, NULL, &dwBytes, NULL))\r
926                 {\r
927                   GNUNET_CONTAINER_slist_erase (i);\r
928                   on_next = GNUNET_YES;\r
929 \r
930                   retcode++;\r
931                 }\r
932               else\r
933                 on_next = GNUNET_NO;\r
934             }\r
935         }\r
936 \r
937       /* FIXME */\r
938       if (wfds)\r
939         GNUNET_assert (GNUNET_CONTAINER_slist_count (wfds->handles) == 0);\r
940 \r
941       /* Check for closed sockets */\r
942       for (i = 0; i < nfds; i++)\r
943         {\r
944           if (SAFE_FD_ISSET (i, &sock_read))\r
945             {\r
946               struct sockaddr addr;\r
947               int len;\r
948 \r
949               if (getpeername (i, &addr, &len) == SOCKET_ERROR)\r
950                 {\r
951                   int err, len;\r
952 \r
953                   len = sizeof (err);\r
954                   if (getsockopt\r
955                       (i, SOL_SOCKET, SO_ERROR, (char *) &err, &len) == 0\r
956                       && err == WSAENOTCONN)\r
957                     {\r
958                       if (!SAFE_FD_ISSET (i, &aread))\r
959                         {\r
960                           FD_SET (i, &aread);\r
961                           retcode++;\r
962                         }\r
963                     }\r
964                 }\r
965             }\r
966         }\r
967 \r
968     select_loop_end:;\r
969     }\r
970   while (retcode == 0 && (ms_total == INFINITE || GetTickCount () < limit));\r
971 \r
972   if (retcode != -1)\r
973     {\r
974       if (rfds)\r
975         {\r
976           GNUNET_NETWORK_fdset_zero (rfds);\r
977           GNUNET_NETWORK_fdset_copy_native (rfds, &aread, retcode);\r
978         }\r
979 \r
980       if (wfds)\r
981         {\r
982           GNUNET_NETWORK_fdset_zero (wfds);\r
983           GNUNET_NETWORK_fdset_copy_native (wfds, &awrite, retcode);\r
984         }\r
985 \r
986       if (efds)\r
987         {\r
988           GNUNET_NETWORK_fdset_zero (efds);\r
989           GNUNET_NETWORK_fdset_copy_native (efds, &aexcept, retcode);\r
990         }\r
991     }\r
992 \r
993   return retcode;\r
994 #endif\r
995 }\r
996 \r
997 \r
998 /* end of network.c */\r