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