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