fixing 1753
[oweals/gnunet.git] / src / util / network.c
1 /*
2      This file is part of GNUnet.
3      (C) 2009 Christian Grothoff (and other contributing authors)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 2, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20
21 /**
22  * @file util/network.c
23  * @brief basic, low-level networking interface
24  * @author Nils Durner
25  */
26
27 #include "platform.h"
28 #include "gnunet_disk_lib.h"
29 #include "disk.h"
30 #include "gnunet_container_lib.h"
31
32 #define DEBUG_NETWORK GNUNET_NO
33
34 #define DEBUG_W32_CYCLES GNUNET_NO
35
36 #ifndef INVALID_SOCKET
37 #define INVALID_SOCKET -1
38 #endif
39
40
41 struct GNUNET_NETWORK_Handle
42 {
43 #ifndef MINGW
44   int fd;
45
46 #else
47   SOCKET fd;
48 #endif
49
50   /**
51    * Address family / domain.
52    */
53   int af;
54
55   /**
56    * Number of bytes in addr.
57    */
58   socklen_t addrlen;
59
60   /**
61    * Address we were bound to, or NULL.
62    */
63   struct sockaddr *addr;
64
65 };
66
67
68 #ifndef FD_COPY
69 #define FD_COPY(s, d) (memcpy ((d), (s), sizeof (fd_set)))
70 #endif
71
72
73 /**
74  * Set if a socket should use blocking or non-blocking IO.
75  * @param fd socket
76  * @param doBlock blocking mode
77  * @return GNUNET_OK on success, GNUNET_SYSERR on error
78  */
79 static int
80 socket_set_blocking (struct GNUNET_NETWORK_Handle *fd, int doBlock)
81 {
82
83 #if MINGW
84   u_long mode;
85
86   mode = !doBlock;
87   if (ioctlsocket (fd->fd, FIONBIO, &mode) == SOCKET_ERROR)
88
89   {
90     SetErrnoFromWinsockError (WSAGetLastError ());
91     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "ioctlsocket");
92     return GNUNET_SYSERR;
93   }
94   return GNUNET_OK;
95
96 #else
97   /* not MINGW */
98   int flags = fcntl (fd->fd, F_GETFL);
99
100   if (flags == -1)
101
102   {
103     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "fcntl");
104     return GNUNET_SYSERR;
105   }
106   if (doBlock)
107     flags &= ~O_NONBLOCK;
108
109   else
110     flags |= O_NONBLOCK;
111   if (0 != fcntl (fd->fd, F_SETFL, flags))
112
113   {
114     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "fcntl");
115     return GNUNET_SYSERR;
116   }
117   return GNUNET_OK;
118 #endif
119 }
120
121
122 #ifndef MINGW
123 /**
124  * Make a socket non-inheritable to child processes
125  *
126  * @param h the socket to make non-inheritable
127  * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
128  * @warning Not implemented on Windows
129  */
130 static int
131 socket_set_inheritable (const struct GNUNET_NETWORK_Handle *h)
132 {
133   int i;
134
135   i = fcntl (h->fd, F_GETFD);
136   if (i < 0)
137     return GNUNET_SYSERR;
138   if (i == (i | FD_CLOEXEC))
139     return GNUNET_OK;
140   i |= FD_CLOEXEC;
141   if (fcntl (h->fd, F_SETFD, i) < 0)
142     return GNUNET_SYSERR;
143   return GNUNET_OK;
144 }
145 #endif
146
147
148 #ifdef DARWIN
149 /**
150  * The MSG_NOSIGNAL equivalent on Mac OS X
151  *
152  * @param h the socket to make non-delaying
153  */
154 static void
155 socket_set_nosigpipe (const struct GNUNET_NETWORK_Handle *h)
156 {
157   int abs_value = 1;
158
159   if (0 !=
160       setsockopt (h->fd, SOL_SOCKET, SO_NOSIGPIPE, &abs_value,
161                   sizeof (abs_value)))
162     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "setsockopt");
163 }
164 #endif
165
166
167 /**
168  * Disable delays when sending data via the socket.
169  * (GNUnet makes sure that messages are as big as
170  * possible already).
171  *
172  * @param h the socket to make non-delaying
173  */
174 static void
175 socket_set_nodelay (const struct GNUNET_NETWORK_Handle *h)
176 {
177 #ifndef WINDOWS
178   int value = 1;
179
180   if (0 != setsockopt (h->fd, IPPROTO_TCP, TCP_NODELAY, &value, sizeof (value)))
181     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "setsockopt");
182 #else
183   const char *abs_value = "1";
184
185   if (0 !=
186       setsockopt (h->fd, IPPROTO_TCP, TCP_NODELAY, abs_value,
187                   sizeof (abs_value)))
188     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "setsockopt");
189 #endif
190 }
191
192
193 /**
194  * accept a new connection on a socket
195  *
196  * @param desc bound socket
197  * @param address address of the connecting peer, may be NULL
198  * @param address_len length of address
199  * @return client socket
200  */
201 struct GNUNET_NETWORK_Handle *
202 GNUNET_NETWORK_socket_accept (const struct GNUNET_NETWORK_Handle *desc,
203                               struct sockaddr *address, socklen_t * address_len)
204 {
205   struct GNUNET_NETWORK_Handle *ret;
206
207   ret = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle));
208 #if DEBUG_NETWORK
209   {
210     struct sockaddr name;
211     int namelen = sizeof (name);
212     int gsn = getsockname (desc->fd, &name, &namelen);
213
214     if (gsn == 0)
215       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Accepting connection on `%s'\n",
216                   GNUNET_a2s (&name, namelen));
217   }
218 #endif
219   ret->fd = accept (desc->fd, address, address_len);
220   if (address != NULL)
221     ret->af = address->sa_family;
222   else
223     ret->af = desc->af;
224   if (ret->fd == INVALID_SOCKET)
225   {
226 #ifdef MINGW
227     SetErrnoFromWinsockError (WSAGetLastError ());
228 #endif
229     GNUNET_free (ret);
230     return NULL;
231   }
232 #ifndef MINGW
233   if (ret->fd >= FD_SETSIZE)
234   {
235     GNUNET_break (0 == close (ret->fd));
236     GNUNET_free (ret);
237     errno = EMFILE;
238     return NULL;
239   }
240 #endif
241   if (GNUNET_SYSERR == socket_set_blocking (ret, GNUNET_NO))
242
243   {
244
245     /* we might want to treat this one as fatal... */
246     GNUNET_break (0);
247     GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (ret));
248     return NULL;
249   }
250
251 #ifndef MINGW
252   if (GNUNET_OK != socket_set_inheritable (ret))
253     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
254                          "socket_set_inheritable");
255 #endif
256 #ifdef DARWIN
257   socket_set_nosigpipe (ret);
258 #endif
259 #ifdef AF_UNIX
260   if (ret->af != AF_UNIX)
261 #endif
262     socket_set_nodelay (ret);
263   return ret;
264 }
265
266
267 /**
268  * Bind to a connected socket
269  * @param desc socket
270  * @param address address to be bound
271  * @param address_len length of address
272  * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
273  */
274 int
275 GNUNET_NETWORK_socket_bind (struct GNUNET_NETWORK_Handle *desc,
276                             const struct sockaddr *address,
277                             socklen_t address_len)
278 {
279   int ret;
280
281 #ifdef IPV6_V6ONLY
282 #ifdef IPPROTO_IPV6
283   const int on = 1;
284
285   if (desc->af == AF_INET6)
286     if (0 != setsockopt (desc->fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof (on)))
287       GNUNET_log_strerror (GNUNET_ERROR_TYPE_DEBUG, "setsockopt");
288 #if 0
289   /* is this needed or desired? or done elsewhere? */
290   if (0 != setsockopt (desc->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)))
291     GNUNET_log_strerror (GNUNET_ERROR_TYPE_DEBUG, "setsockopt");
292 #endif
293 #endif
294 #endif
295 #ifndef LINUX
296 #ifndef MINGW
297   if (address->sa_family == AF_UNIX)
298   {
299     const struct sockaddr_un *un = (const struct sockaddr_un *) address;
300
301     (void) unlink (un->sun_path);
302   }
303 #endif
304 #endif
305   ret = bind (desc->fd, address, address_len);
306 #ifdef MINGW
307   if (SOCKET_ERROR == ret)
308     SetErrnoFromWinsockError (WSAGetLastError ());
309 #endif
310   if (ret != 0)
311     return GNUNET_SYSERR;
312 #ifndef MINGW
313 #ifndef LINUX
314   desc->addr = GNUNET_malloc (address_len);
315   memcpy (desc->addr, address, address_len);
316   desc->addrlen = address_len;
317 #endif
318 #endif
319   return GNUNET_OK;
320 }
321
322
323 /**
324  * Close a socket
325  * @param desc socket
326  * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
327  */
328 int
329 GNUNET_NETWORK_socket_close (struct GNUNET_NETWORK_Handle *desc)
330 {
331   int ret;
332
333 #ifdef MINGW
334   DWORD error = 0;
335
336 #if DEBUG_NETWORK
337   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "GNUNET_NETWORK_socket_close",
338                    "Closing 0x%x\n", desc->fd);
339 #endif
340   SetLastError (0);
341   ret = closesocket (desc->fd);
342   error = WSAGetLastError ();
343   SetErrnoFromWinsockError (error);
344 #if DEBUG_NETWORK
345   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "GNUNET_NETWORK_socket_close",
346                    "Closed 0x%x, closesocket() returned %d, GLE is %u\n",
347                    desc->fd, ret, error);
348 #endif
349 #else
350   ret = close (desc->fd);
351 #endif
352 #ifndef LINUX
353 #ifndef MINGW
354   if ((desc->af == AF_UNIX) && (NULL != desc->addr))
355   {
356     const struct sockaddr_un *un = (const struct sockaddr_un *) desc->addr;
357
358     if (0 != unlink (un->sun_path))
359       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink",
360                                 un->sun_path);
361   }
362 #endif
363 #endif
364   GNUNET_free_non_null (desc->addr);
365   GNUNET_free (desc);
366   return (ret == 0) ? GNUNET_OK : GNUNET_SYSERR;
367 }
368
369
370 /**
371  * Box a native socket (and check that it is a socket).
372  *
373  * @param fd socket to box
374  * @return NULL on error (including not supported on target platform)
375  */
376 struct GNUNET_NETWORK_Handle *
377 GNUNET_NETWORK_socket_box_native (int fd)
378 {
379 #if MINGW
380   return NULL;
381 #else
382   struct GNUNET_NETWORK_Handle *ret;
383
384   if (fcntl (fd, F_GETFD) < 0)
385     return NULL;                /* invalid FD */
386   ret = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle));
387   ret->fd = fd;
388   ret->af = AF_UNSPEC;
389   return ret;
390 #endif
391 }
392
393
394 /**
395  * Connect a socket
396  * @param desc socket
397  * @param address peer address
398  * @param address_len length of address
399  * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
400  */
401 int
402 GNUNET_NETWORK_socket_connect (const struct GNUNET_NETWORK_Handle *desc,
403                                const struct sockaddr *address,
404                                socklen_t address_len)
405 {
406   int ret;
407
408   ret = connect (desc->fd, address, address_len);
409
410 #ifdef MINGW
411   if (SOCKET_ERROR == ret)
412   {
413     SetErrnoFromWinsockError (WSAGetLastError ());
414     if (errno == EWOULDBLOCK)
415       errno = EINPROGRESS;
416   }
417 #endif
418   return ret == 0 ? GNUNET_OK : GNUNET_SYSERR;
419 }
420
421
422 /**
423  * Get socket options
424  *
425  * @param desc socket
426  * @param level protocol level of the option
427  * @param optname identifier of the option
428  * @param optval options
429  * @param optlen length of optval
430  * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
431  */
432 int
433 GNUNET_NETWORK_socket_getsockopt (const struct GNUNET_NETWORK_Handle *desc,
434                                   int level, int optname, void *optval,
435                                   socklen_t * optlen)
436 {
437   int ret;
438
439   ret = getsockopt (desc->fd, level, optname, optval, optlen);
440
441 #ifdef MINGW
442   if (ret == 0 && level == SOL_SOCKET && optname == SO_ERROR)
443     *((int *) optval) = GetErrnoFromWinsockError (*((int *) optval));
444
445   else if (SOCKET_ERROR == ret)
446     SetErrnoFromWinsockError (WSAGetLastError ());
447 #endif
448   return ret == 0 ? GNUNET_OK : GNUNET_SYSERR;
449 }
450
451
452 /**
453  * Listen on a socket
454  * @param desc socket
455  * @param backlog length of the listen queue
456  * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
457  */
458 int
459 GNUNET_NETWORK_socket_listen (const struct GNUNET_NETWORK_Handle *desc,
460                               int backlog)
461 {
462   int ret;
463
464   ret = listen (desc->fd, backlog);
465
466 #ifdef MINGW
467   if (SOCKET_ERROR == ret)
468     SetErrnoFromWinsockError (WSAGetLastError ());
469
470 #endif
471   return ret == 0 ? GNUNET_OK : GNUNET_SYSERR;
472 }
473
474
475 /**
476  * How much data is available to be read on this descriptor?
477  *
478  * Returns GNUNET_NO if no data is available, or on error!
479  * @param desc socket
480  */
481 ssize_t
482 GNUNET_NETWORK_socket_recvfrom_amount (const struct GNUNET_NETWORK_Handle *
483                                        desc)
484 {
485   int error;
486
487   /* How much is there to be read? */
488 #ifndef WINDOWS
489   int pending;
490
491   error = ioctl (desc->fd, FIONREAD, &pending);
492   if (error == 0)
493 #else
494   u_long pending;
495
496   error = ioctlsocket (desc->fd, FIONREAD, &pending);
497   if (error != SOCKET_ERROR)
498 #endif
499     return pending;
500   else
501     return GNUNET_NO;
502 }
503
504
505 /**
506  * Read data from a connected socket (always non-blocking).
507  * @param desc socket
508  * @param buffer buffer
509  * @param length length of buffer
510  * @param src_addr either the source to recv from, or all zeroes
511  *        to be filled in by recvfrom
512  * @param addrlen length of the addr
513  */
514 ssize_t
515 GNUNET_NETWORK_socket_recvfrom (const struct GNUNET_NETWORK_Handle * desc,
516                                 void *buffer, size_t length,
517                                 struct sockaddr * src_addr, socklen_t * addrlen)
518 {
519   int ret;
520   int flags;
521
522   flags = 0;
523
524 #ifdef MSG_DONTWAIT
525   flags |= MSG_DONTWAIT;
526
527 #endif
528   ret = recvfrom (desc->fd, buffer, length, flags, src_addr, addrlen);
529 #ifdef MINGW
530   if (SOCKET_ERROR == ret)
531     SetErrnoFromWinsockError (WSAGetLastError ());
532 #endif
533   return ret;
534 }
535
536
537 /**
538  * Read data from a connected socket (always non-blocking).
539  * @param desc socket
540  * @param buffer buffer
541  * @param length length of buffer
542  */
543 ssize_t
544 GNUNET_NETWORK_socket_recv (const struct GNUNET_NETWORK_Handle * desc,
545                             void *buffer, size_t length)
546 {
547   int ret;
548   int flags;
549
550   flags = 0;
551
552 #ifdef MSG_DONTWAIT
553   flags |= MSG_DONTWAIT;
554 #endif
555   ret = recv (desc->fd, buffer, length, flags);
556 #ifdef MINGW
557   if (SOCKET_ERROR == ret)
558     SetErrnoFromWinsockError (WSAGetLastError ());
559 #endif
560   return ret;
561 }
562
563
564 /**
565  * Send data (always non-blocking).
566  *
567  * @param desc socket
568  * @param buffer data to send
569  * @param length size of the buffer
570  * @return number of bytes sent, GNUNET_SYSERR on error
571  */
572 ssize_t
573 GNUNET_NETWORK_socket_send (const struct GNUNET_NETWORK_Handle * desc,
574                             const void *buffer, size_t length)
575 {
576   int ret;
577   int flags;
578
579   flags = 0;
580
581 #ifdef MSG_DONTWAIT
582   flags |= MSG_DONTWAIT;
583
584 #endif
585 #ifdef MSG_NOSIGNAL
586   flags |= MSG_NOSIGNAL;
587
588 #endif
589   ret = send (desc->fd, buffer, length, flags);
590
591 #ifdef MINGW
592   if (SOCKET_ERROR == ret)
593     SetErrnoFromWinsockError (WSAGetLastError ());
594
595 #endif
596   return ret;
597 }
598
599
600 /**
601  * Send data to a particular destination (always non-blocking).
602  * This function only works for UDP sockets.
603  *
604  * @param desc socket
605  * @param message data to send
606  * @param length size of the data
607  * @param dest_addr destination address
608  * @param dest_len length of address
609  * @return number of bytes sent, GNUNET_SYSERR on error
610  */
611 ssize_t
612 GNUNET_NETWORK_socket_sendto (const struct GNUNET_NETWORK_Handle * desc,
613                               const void *message, size_t length,
614                               const struct sockaddr * dest_addr,
615                               socklen_t dest_len)
616 {
617   int ret;
618   int flags;
619
620   flags = 0;
621
622 #ifdef MSG_DONTWAIT
623   flags |= MSG_DONTWAIT;
624 #endif
625 #ifdef MSG_NOSIGNAL
626   flags |= MSG_NOSIGNAL;
627 #endif
628   ret = sendto (desc->fd, message, length, flags, dest_addr, dest_len);
629 #ifdef MINGW
630   if (SOCKET_ERROR == ret)
631     SetErrnoFromWinsockError (WSAGetLastError ());
632 #endif
633   return ret;
634 }
635
636
637 /**
638  * Set socket option
639  * @param fd socket
640  * @param level protocol level of the option
641  * @param option_name option identifier
642  * @param option_value value to set
643  * @param option_len size of option_value
644  * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
645  */
646 int
647 GNUNET_NETWORK_socket_setsockopt (struct GNUNET_NETWORK_Handle *fd, int level,
648                                   int option_name, const void *option_value,
649                                   socklen_t option_len)
650 {
651   int ret;
652
653   ret = setsockopt (fd->fd, level, option_name, option_value, option_len);
654 #ifdef MINGW
655   if (SOCKET_ERROR == ret)
656     SetErrnoFromWinsockError (WSAGetLastError ());
657 #endif
658   return ret == 0 ? GNUNET_OK : GNUNET_SYSERR;
659 }
660
661
662 /**
663  * Create a new socket.  Configure it for non-blocking IO and
664  * mark it as non-inheritable to child processes (set the
665  * close-on-exec flag).
666  *
667  * @param domain domain of the socket
668  * @param type socket type
669  * @param protocol network protocol
670  * @return new socket, NULL on error
671  */
672 struct GNUNET_NETWORK_Handle *
673 GNUNET_NETWORK_socket_create (int domain, int type, int protocol)
674 {
675   struct GNUNET_NETWORK_Handle *ret;
676
677   ret = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle));
678   ret->af = domain;
679   ret->fd = socket (domain, type, protocol);
680   if (INVALID_SOCKET == ret->fd)
681   {
682 #ifdef MINGW
683     SetErrnoFromWinsockError (WSAGetLastError ());
684 #endif
685     GNUNET_free (ret);
686     return NULL;
687   }
688
689 #ifndef MINGW
690   if (ret->fd >= FD_SETSIZE)
691   {
692     GNUNET_break (0 == close (ret->fd));
693     GNUNET_free (ret);
694     errno = EMFILE;
695     return NULL;
696   }
697
698 #endif
699   if (GNUNET_SYSERR == socket_set_blocking (ret, GNUNET_NO))
700   {
701     /* we might want to treat this one as fatal... */
702     GNUNET_break (0);
703     GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (ret));
704     return NULL;
705   }
706
707 #ifndef MINGW
708   if (GNUNET_OK != socket_set_inheritable (ret))
709     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
710                          "socket_set_inheritable");
711 #endif
712 #ifdef DARWIN
713   socket_set_nosigpipe (ret);
714 #endif
715   if ((type == SOCK_STREAM)
716 #ifdef AF_UNIX
717       && (domain != AF_UNIX)
718 #endif
719       )
720     socket_set_nodelay (ret);
721   return ret;
722 }
723
724
725 /**
726  * Shut down socket operations
727  * @param desc socket
728  * @param how type of shutdown
729  * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
730  */
731 int
732 GNUNET_NETWORK_socket_shutdown (struct GNUNET_NETWORK_Handle *desc, int how)
733 {
734   int ret;
735
736   ret = shutdown (desc->fd, how);
737 #ifdef MINGW
738   if (ret != 0)
739     SetErrnoFromWinsockError (WSAGetLastError ());
740 #endif
741   return ret == 0 ? GNUNET_OK : GNUNET_SYSERR;
742 }
743
744
745 /**
746  * Disable the "CORK" feature for communication with the given socket,
747  * forcing the OS to immediately flush the buffer on transmission
748  * instead of potentially buffering multiple messages.  Essentially
749  * reduces the OS send buffers to zero.
750  *
751  * @param desc socket
752  * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
753  */
754 int
755 GNUNET_NETWORK_socket_disable_corking (struct GNUNET_NETWORK_Handle *desc)
756 {
757   int value = 0;
758   int ret = 0;
759
760 #if WINDOWS
761   if (0 !=
762       (ret =
763        setsockopt (desc->fd, SOL_SOCKET, SO_SNDBUF, (char *) &value,
764                    sizeof (value))))
765     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "setsockopt");
766   if (0 !=
767       (ret =
768        setsockopt (desc->fd, SOL_SOCKET, SO_RCVBUF, (char *) &value,
769                    sizeof (value))))
770     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "setsockopt");
771 #else
772   if (0 !=
773       (ret =
774        setsockopt (desc->fd, SOL_SOCKET, SO_SNDBUF, &value, sizeof (value))))
775     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "setsockopt");
776   if (0 !=
777       (ret =
778        setsockopt (desc->fd, SOL_SOCKET, SO_RCVBUF, &value, sizeof (value))))
779     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "setsockopt");
780 #endif
781
782   return ret == 0 ? GNUNET_OK : GNUNET_SYSERR;
783 }
784
785
786 /**
787  * Reset FD set
788  * @param fds fd set
789  */
790 void
791 GNUNET_NETWORK_fdset_zero (struct GNUNET_NETWORK_FDSet *fds)
792 {
793   FD_ZERO (&fds->sds);
794   fds->nsds = 0;
795 #ifdef MINGW
796   GNUNET_CONTAINER_slist_clear (fds->handles);
797 #endif
798 }
799
800 /**
801  * Add a socket to the FD set
802  * @param fds fd set
803  * @param desc socket to add
804  */
805 void
806 GNUNET_NETWORK_fdset_set (struct GNUNET_NETWORK_FDSet *fds,
807                           const struct GNUNET_NETWORK_Handle *desc)
808 {
809   FD_SET (desc->fd, &fds->sds);
810   if (desc->fd + 1 > fds->nsds)
811     fds->nsds = desc->fd + 1;
812 }
813
814
815 /**
816  * Check whether a socket is part of the fd set
817  * @param fds fd set
818  * @param desc socket
819  * @return 0 if the FD is not set
820  */
821 int
822 GNUNET_NETWORK_fdset_isset (const struct GNUNET_NETWORK_FDSet *fds,
823                             const struct GNUNET_NETWORK_Handle *desc)
824 {
825   return FD_ISSET (desc->fd, &fds->sds);
826 }
827
828
829 /**
830  * Add one fd set to another
831  * @param dst the fd set to add to
832  * @param src the fd set to add from
833  */
834 void
835 GNUNET_NETWORK_fdset_add (struct GNUNET_NETWORK_FDSet *dst,
836                           const struct GNUNET_NETWORK_FDSet *src)
837 {
838   int nfds;
839
840   for (nfds = src->nsds; nfds > 0; nfds--)
841     if (FD_ISSET (nfds, &src->sds))
842
843     {
844       FD_SET (nfds, &dst->sds);
845       if (nfds + 1 > dst->nsds)
846         dst->nsds = nfds + 1;
847     }
848 #ifdef MINGW
849   GNUNET_CONTAINER_slist_append (dst->handles, src->handles);
850 #endif
851 }
852
853
854 /**
855  * Copy one fd set to another
856  *
857  * @param to destination
858  * @param from source
859  */
860 void
861 GNUNET_NETWORK_fdset_copy (struct GNUNET_NETWORK_FDSet *to,
862                            const struct GNUNET_NETWORK_FDSet *from)
863 {
864   FD_COPY (&from->sds, &to->sds);
865   to->nsds = from->nsds;
866
867 #ifdef MINGW
868   GNUNET_CONTAINER_slist_clear (to->handles);
869   GNUNET_CONTAINER_slist_append (to->handles, from->handles);
870 #endif
871 }
872
873
874 /**
875  * Return file descriptor for this network handle
876  *
877  * @param desc wrapper to process
878  * @return POSIX file descriptor
879  */
880 int
881 GNUNET_NETWORK_get_fd (struct GNUNET_NETWORK_Handle *desc)
882 {
883   return desc->fd;
884 }
885
886
887 /**
888  * Copy a native fd set
889  *
890  * @param to destination
891  * @param from native source set
892  * @param nfds the biggest socket number in from + 1
893  */
894 void
895 GNUNET_NETWORK_fdset_copy_native (struct GNUNET_NETWORK_FDSet *to,
896                                   const fd_set * from, int nfds)
897 {
898   FD_COPY (from, &to->sds);
899   to->nsds = nfds;
900 }
901
902
903 /**
904  * Set a native fd in a set
905  *
906  * @param to destination
907  * @param nfd native FD to set
908  */
909 void
910 GNUNET_NETWORK_fdset_set_native (struct GNUNET_NETWORK_FDSet *to, int nfd)
911 {
912   GNUNET_assert ((nfd >= 0) && (nfd < FD_SETSIZE));
913   FD_SET (nfd, &to->sds);
914   to->nsds = GNUNET_MAX (nfd + 1, to->nsds);
915 }
916
917
918 /**
919  * Test native fd in a set
920  *
921  * @param to set to test, NULL for empty set
922  * @param nfd native FD to test, or -1 for none
923  * @return GNUNET_YES if FD is set in the set
924  */
925 int
926 GNUNET_NETWORK_fdset_test_native (const struct GNUNET_NETWORK_FDSet *to,
927                                   int nfd)
928 {
929   if ((nfd == -1) || (to == NULL))
930     return GNUNET_NO;
931   return FD_ISSET (nfd, &to->sds) ? GNUNET_YES : GNUNET_NO;
932 }
933
934
935 /**
936  * Add a file handle to the fd set
937  * @param fds fd set
938  * @param h the file handle to add
939  */
940 void
941 GNUNET_NETWORK_fdset_handle_set (struct GNUNET_NETWORK_FDSet *fds,
942                                  const struct GNUNET_DISK_FileHandle *h)
943 {
944 #ifdef MINGW
945   GNUNET_CONTAINER_slist_add (fds->handles,
946                               GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT, h,
947                               sizeof (struct GNUNET_DISK_FileHandle));
948
949 #else
950   int fd;
951
952   GNUNET_DISK_internal_file_handle_ (h, &fd, sizeof (int));
953   FD_SET (fd, &fds->sds);
954   if (fd + 1 > fds->nsds)
955     fds->nsds = fd + 1;
956
957 #endif
958 }
959
960
961 /**
962  * Check if a file handle is part of an fd set
963  * @param fds fd set
964  * @param h file handle
965  * @return GNUNET_YES if the file handle is part of the set
966  */
967 int
968 GNUNET_NETWORK_fdset_handle_isset (const struct GNUNET_NETWORK_FDSet *fds,
969                                    const struct GNUNET_DISK_FileHandle *h)
970 {
971
972 #ifdef MINGW
973   return GNUNET_CONTAINER_slist_contains (fds->handles, h,
974                                           sizeof (struct
975                                                   GNUNET_DISK_FileHandle));
976 #else
977   return FD_ISSET (h->fd, &fds->sds);
978 #endif
979 }
980
981
982 /**
983  * Checks if two fd sets overlap
984  * @param fds1 first fd set
985  * @param fds2 second fd set
986  * @return GNUNET_YES if they do overlap, GNUNET_NO otherwise
987  */
988 int
989 GNUNET_NETWORK_fdset_overlap (const struct GNUNET_NETWORK_FDSet *fds1,
990                               const struct GNUNET_NETWORK_FDSet *fds2)
991 {
992 #ifndef MINGW
993   int nfds;
994
995   nfds = fds1->nsds;
996   if (nfds > fds2->nsds)
997     nfds = fds2->nsds;
998   while (nfds > 0)
999   {
1000     nfds--;
1001     if (FD_ISSET (nfds, &fds1->sds) && FD_ISSET (nfds, &fds2->sds))
1002       return GNUNET_YES;
1003   }
1004 #else
1005   struct GNUNET_CONTAINER_SList_Iterator *it;
1006   struct GNUNET_DISK_FileHandle *h;
1007   int i;
1008   int j;
1009
1010   /*This code is somewhat hacky, we are not supposed to know what's
1011    * inside of fd_set; also the O(n^2) is really bad... */
1012
1013   for (i = 0; i < fds1->sds.fd_count; i++)
1014   {
1015     for (j = 0; j < fds2->sds.fd_count; j++)
1016     {
1017       if (fds1->sds.fd_array[i] == fds2->sds.fd_array[j])
1018         return GNUNET_YES;
1019     }
1020   }
1021   it = GNUNET_CONTAINER_slist_begin (fds1->handles);
1022   while (GNUNET_CONTAINER_slist_end (it) != GNUNET_YES)
1023   {
1024 #if DEBUG_NETWORK
1025     struct GNUNET_CONTAINER_SList_Iterator *t;
1026 #endif
1027     h = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (it, NULL);
1028 #if DEBUG_NETWORK
1029     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1030                 "Checking that FD 0x%x is in another set:\n", h->h);
1031     for (t = GNUNET_CONTAINER_slist_begin (fds2->handles);
1032          GNUNET_CONTAINER_slist_end (t) != GNUNET_YES;
1033          GNUNET_CONTAINER_slist_next (t))
1034     {
1035       struct GNUNET_DISK_FileHandle *fh;
1036
1037       fh = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (t,
1038                                                                          NULL);
1039       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "0x%x\n", fh->h);
1040     }
1041 #endif
1042     if (GNUNET_CONTAINER_slist_contains
1043         (fds2->handles, h, sizeof (struct GNUNET_DISK_FileHandle)))
1044     {
1045 #if DEBUG_NETWORK
1046       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Match!\n");
1047 #endif
1048       GNUNET_CONTAINER_slist_iter_destroy (it);
1049       return GNUNET_YES;
1050     }
1051     GNUNET_CONTAINER_slist_next (it);
1052   }
1053   GNUNET_CONTAINER_slist_iter_destroy (it);
1054 #endif
1055   return GNUNET_NO;
1056 }
1057
1058
1059 /**
1060  * Creates an fd set
1061  * @return a new fd set
1062  */
1063 struct GNUNET_NETWORK_FDSet *
1064 GNUNET_NETWORK_fdset_create ()
1065 {
1066   struct GNUNET_NETWORK_FDSet *fds;
1067
1068   fds = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_FDSet));
1069 #ifdef MINGW
1070   fds->handles = GNUNET_CONTAINER_slist_create ();
1071 #endif
1072   GNUNET_NETWORK_fdset_zero (fds);
1073   return fds;
1074 }
1075
1076
1077 /**
1078  * Releases the associated memory of an fd set
1079  * @param fds fd set
1080  */
1081 void
1082 GNUNET_NETWORK_fdset_destroy (struct GNUNET_NETWORK_FDSet *fds)
1083 {
1084 #ifdef MINGW
1085   GNUNET_CONTAINER_slist_destroy (fds->handles);
1086 #endif
1087   GNUNET_free (fds);
1088 }
1089
1090 /**
1091  * Check if sockets meet certain conditions
1092  * @param rfds set of sockets to be checked for readability
1093  * @param wfds set of sockets to be checked for writability
1094  * @param efds set of sockets to be checked for exceptions
1095  * @param timeout relative value when to return
1096  * @return number of selected sockets, GNUNET_SYSERR on error
1097  */
1098 int
1099 GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds,
1100                               struct GNUNET_NETWORK_FDSet *wfds,
1101                               struct GNUNET_NETWORK_FDSet *efds,
1102                               const struct GNUNET_TIME_Relative timeout)
1103 {
1104   int nfds = 0;
1105
1106 #ifdef MINGW
1107   int handles = 0;
1108   int ex_handles = 0;
1109   int read_handles = 0;
1110   int write_handles = 0;
1111
1112   int i = 0;
1113   int retcode = 0;
1114   DWORD ms_total = 0;
1115
1116   int nsock = 0, nhandles = 0, nSockEvents = 0;
1117
1118   static HANDLE hEventRead = 0;
1119   static HANDLE hEventWrite = 0;
1120   static HANDLE hEventException = 0;
1121   static HANDLE hEventPipeWrite = 0;
1122   static HANDLE hEventReadReady = 0;
1123
1124   int readPipes = 0;
1125   int writePipePos = 0;
1126
1127   HANDLE handle_array[FD_SETSIZE + 2];
1128   int returncode = -1;
1129   DWORD newretcode = 0;
1130   int returnedpos = 0;
1131
1132   struct GNUNET_CONTAINER_SList *handles_read, *handles_write, *handles_except;
1133
1134   fd_set aread, awrite, aexcept;
1135
1136 #if DEBUG_NETWORK
1137   fd_set bread, bwrite, bexcept;
1138 #endif
1139
1140   /* TODO: Make this growable */
1141   struct GNUNET_DISK_FileHandle *readArray[50];
1142 #else
1143   struct timeval tv;
1144 #endif
1145   if (NULL != rfds)
1146   {
1147     nfds = rfds->nsds;
1148 #ifdef MINGW
1149     handles += read_handles = GNUNET_CONTAINER_slist_count (rfds->handles);
1150 #if DEBUG_NETWORK
1151     {
1152       struct GNUNET_CONTAINER_SList_Iterator *t;
1153
1154       for (t = GNUNET_CONTAINER_slist_begin (rfds->handles);
1155            GNUNET_CONTAINER_slist_end (t) != GNUNET_YES;
1156            GNUNET_CONTAINER_slist_next (t))
1157       {
1158         struct GNUNET_DISK_FileHandle *fh;
1159
1160         fh = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (t,
1161                                                                            NULL);
1162         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "FD 0x%x (0x%x) is SET in rfds\n",
1163                     fh->h, fh);
1164       }
1165     }
1166 #endif
1167 #endif
1168   }
1169   if (NULL != wfds)
1170   {
1171     nfds = GNUNET_MAX (nfds, wfds->nsds);
1172 #ifdef MINGW
1173     handles += write_handles = GNUNET_CONTAINER_slist_count (wfds->handles);
1174 #endif
1175   }
1176   if (NULL != efds)
1177   {
1178     nfds = GNUNET_MAX (nfds, efds->nsds);
1179 #ifdef MINGW
1180     handles += ex_handles = GNUNET_CONTAINER_slist_count (efds->handles);
1181 #endif
1182   }
1183
1184   if ((nfds == 0) &&
1185       (timeout.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
1186 #ifdef MINGW
1187       && handles == 0
1188 #endif
1189       )
1190   {
1191     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1192                 _
1193                 ("Fatal internal logic error, process hangs in `%s' (abort with CTRL-C)!\n"),
1194                 "select");
1195     GNUNET_break (0);
1196   }
1197 #ifndef MINGW
1198   tv.tv_sec = timeout.rel_value / GNUNET_TIME_UNIT_SECONDS.rel_value;
1199   tv.tv_usec =
1200       1000 * (timeout.rel_value -
1201               (tv.tv_sec * GNUNET_TIME_UNIT_SECONDS.rel_value));
1202   return select (nfds, (rfds != NULL) ? &rfds->sds : NULL,
1203                  (wfds != NULL) ? &wfds->sds : NULL,
1204                  (efds != NULL) ? &efds->sds : NULL,
1205                  (timeout.rel_value ==
1206                   GNUNET_TIME_UNIT_FOREVER_REL.rel_value) ? NULL : &tv);
1207
1208 #else
1209 #define SAFE_FD_ISSET(fd, set)  (set != NULL && FD_ISSET(fd, set))
1210   /* calculate how long we need to wait in milliseconds */
1211   if (timeout.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
1212     ms_total = INFINITE;
1213   else
1214     ms_total = timeout.rel_value / GNUNET_TIME_UNIT_MILLISECONDS.rel_value;
1215   /* select() may be used as a portable way to sleep */
1216   if (!(rfds || wfds || efds))
1217   {
1218     Sleep (ms_total);
1219     return 0;
1220   }
1221
1222   /* Events for sockets */
1223   if (!hEventRead)
1224     hEventRead = CreateEvent (NULL, TRUE, FALSE, NULL);
1225   else
1226     ResetEvent (hEventRead);
1227   if (!hEventReadReady)
1228     hEventReadReady = CreateEvent (NULL, TRUE, TRUE, NULL);
1229   if (!hEventWrite)
1230     hEventWrite = CreateEvent (NULL, TRUE, FALSE, NULL);
1231   else
1232     ResetEvent (hEventWrite);
1233   if (!hEventException)
1234     hEventException = CreateEvent (NULL, TRUE, FALSE, NULL);
1235   else
1236     ResetEvent (hEventException);
1237
1238   /* Event for pipes */
1239   if (!hEventPipeWrite)
1240     hEventPipeWrite = CreateEvent (NULL, TRUE, TRUE, NULL);
1241   readPipes = 0;
1242   writePipePos = -1;
1243
1244   handles_read = GNUNET_CONTAINER_slist_create ();
1245   handles_write = GNUNET_CONTAINER_slist_create ();
1246   handles_except = GNUNET_CONTAINER_slist_create ();
1247   FD_ZERO (&aread);
1248   FD_ZERO (&awrite);
1249   FD_ZERO (&aexcept);
1250 #if DEBUG_NETWORK
1251   FD_ZERO (&bread);
1252   FD_ZERO (&bwrite);
1253   FD_ZERO (&bexcept);
1254 #endif
1255   if (rfds)
1256   {
1257     FD_COPY (&rfds->sds, &aread);
1258 #if DEBUG_NETWORK
1259     FD_COPY (&rfds->sds, &bread);
1260 #endif
1261   }
1262   if (wfds)
1263   {
1264     FD_COPY (&wfds->sds, &awrite);
1265 #if DEBUG_NETWORK
1266     FD_COPY (&wfds->sds, &bwrite);
1267 #endif
1268   }
1269   if (efds)
1270   {
1271     FD_COPY (&efds->sds, &aexcept);
1272 #if DEBUG_NETWORK
1273     FD_COPY (&efds->sds, &bexcept);
1274 #endif
1275   }
1276   /* We will first Add the PIPES to the events */
1277   /* Read Pipes */
1278   if (rfds && read_handles)
1279   {
1280     struct GNUNET_CONTAINER_SList_Iterator *i;
1281
1282     for (i = GNUNET_CONTAINER_slist_begin (rfds->handles);
1283          GNUNET_CONTAINER_slist_end (i) != GNUNET_YES;
1284          GNUNET_CONTAINER_slist_next (i))
1285     {
1286       struct GNUNET_DISK_FileHandle *fh;
1287
1288       fh = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (i,
1289                                                                          NULL);
1290       if (fh->type == GNUNET_PIPE)
1291       {
1292         /* Read zero bytes to check the status of the pipe */
1293 #if DEBUG_NETWORK
1294         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1295                     "Reading 0 bytes from the pipe 0x%x\n", fh->h);
1296 #endif
1297         if (!ReadFile (fh->h, NULL, 0, NULL, fh->oOverlapRead))
1298         {
1299           DWORD error_code = GetLastError ();
1300
1301           if (error_code == ERROR_IO_PENDING)
1302           {
1303 #if DEBUG_NETWORK
1304             GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1305                         "Adding the pipe's 0x%x overlapped event to the array as %d\n",
1306                         fh->h, nhandles);
1307 #endif
1308             handle_array[nhandles++] = fh->oOverlapRead->hEvent;
1309             readArray[readPipes++] = fh;
1310           }
1311           /*
1312            * else
1313            * {
1314            * SetErrnoFromWinError (error_code);
1315            * }
1316            */
1317         }
1318         else
1319         {
1320 #if DEBUG_NETWORK
1321           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1322                       "Adding the read ready event to the array as %d\n",
1323                       nhandles);
1324 #endif
1325           handle_array[nhandles++] = hEventReadReady;
1326           readArray[readPipes++] = fh;
1327         }
1328       }
1329       else
1330       {
1331         GNUNET_CONTAINER_slist_add (handles_read,
1332                                     GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT,
1333                                     fh, sizeof (struct GNUNET_DISK_FileHandle));
1334       }
1335     }
1336     GNUNET_CONTAINER_slist_iter_destroy (i);
1337   }
1338   if (wfds && write_handles)
1339   {
1340 #if DEBUG_NETWORK
1341     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1342                 "Adding the write ready event to the array as %d\n", nhandles);
1343 #endif
1344     handle_array[nhandles++] = hEventPipeWrite;
1345     writePipePos = nhandles;
1346   }
1347   if (efds && ex_handles)
1348   {
1349     struct GNUNET_CONTAINER_SList_Iterator *i;
1350
1351     for (i = GNUNET_CONTAINER_slist_begin (efds->handles);
1352          GNUNET_CONTAINER_slist_end (i) != GNUNET_YES;
1353          GNUNET_CONTAINER_slist_next (i))
1354     {
1355       struct GNUNET_DISK_FileHandle *fh;
1356       DWORD dwBytes;
1357
1358       fh = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (i,
1359                                                                          NULL);
1360       if (fh->type == GNUNET_PIPE)
1361       {
1362         if (!PeekNamedPipe (fh->h, NULL, 0, NULL, &dwBytes, NULL))
1363         {
1364           GNUNET_CONTAINER_slist_add (handles_except,
1365                                       GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT,
1366                                       fh,
1367                                       sizeof (struct GNUNET_DISK_FileHandle));
1368           newretcode++;
1369         }
1370       }
1371     }
1372     GNUNET_CONTAINER_slist_iter_destroy (i);
1373   }
1374   if (nfds > 0)
1375   {
1376     if (rfds)
1377     {
1378 #if DEBUG_NETWORK
1379       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1380                   "Adding the socket read event to the array as %d\n",
1381                   nhandles);
1382 #endif
1383       handle_array[nhandles++] = hEventRead;
1384       nSockEvents++;
1385       for (i = 0; i < rfds->sds.fd_count; i++)
1386       {
1387         WSAEventSelect (rfds->sds.fd_array[i], hEventRead,
1388                         FD_ACCEPT | FD_READ | FD_CLOSE);
1389         nsock++;
1390       }
1391     }
1392     if (wfds)
1393     {
1394       int wakeup = 0;
1395
1396 #if DEBUG_NETWORK
1397       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1398                   "Adding the socket write event to the array as %d\n",
1399                   nhandles);
1400 #endif
1401       handle_array[nhandles++] = hEventWrite;
1402       nSockEvents++;
1403       for (i = 0; i < wfds->sds.fd_count; i++)
1404       {
1405         DWORD error;
1406         int status;
1407
1408         status = send (wfds->sds.fd_array[i], NULL, 0, 0);
1409         error = GetLastError ();
1410 #if DEBUG_NETWORK
1411         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1412                     "pre-send to the socket %d returned %d (%u)\n", i, status,
1413                     error);
1414 #endif
1415         if (status == 0 || (error != WSAEWOULDBLOCK && error != WSAENOTCONN))
1416           wakeup = 1;
1417         WSAEventSelect (wfds->sds.fd_array[i], hEventWrite,
1418                         FD_WRITE | FD_CONNECT | FD_CLOSE);
1419         nsock++;
1420       }
1421       if (wakeup)
1422         SetEvent (hEventWrite);
1423     }
1424     if (efds)
1425     {
1426 #if DEBUG_NETWORK
1427       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1428                   "Adding the socket error event to the array as %d\n",
1429                   nhandles);
1430 #endif
1431       handle_array[nhandles++] = hEventException;
1432       nSockEvents++;
1433       for (i = 0; i < efds->sds.fd_count; i++)
1434       {
1435         WSAEventSelect (efds->sds.fd_array[i], hEventException,
1436                         FD_OOB | FD_CLOSE);
1437         nsock++;
1438       }
1439     }
1440   }
1441
1442   handle_array[nhandles] = NULL;
1443
1444 #if DEBUG_NETWORK
1445   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Number nfds : %d\n", nfds);
1446   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Number of handles : %d\n", nhandles);
1447   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "retcode : %d\n", newretcode);
1448   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Will wait : %d\n", ms_total);
1449 #endif
1450
1451   if (nhandles)
1452     returncode =
1453         WaitForMultipleObjects (nhandles, handle_array, FALSE, ms_total);
1454 #if DEBUG_NETWORK
1455   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "WaitForMultipleObjects Returned : %d\n",
1456               returncode);
1457 #endif
1458
1459   returnedpos = returncode - WAIT_OBJECT_0;
1460 #if DEBUG_NETWORK
1461   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "return pos is : %d\n", returnedpos);
1462 #endif
1463
1464   /* FIXME: THIS LINE IS WRONG !! We should add to handles only handles that fired the events, not all ! */
1465   /*
1466    * if(rfds)
1467    * GNUNET_CONTAINER_slist_append (handles_read, rfds->handles);
1468    */
1469   if (nhandles && (returnedpos < nhandles))
1470   {
1471     DWORD waitstatus;
1472
1473     /* Do the select */
1474     if (nfds)
1475     {
1476       struct timeval tvslice;
1477
1478       tvslice.tv_sec = 0;
1479       tvslice.tv_usec = 10;
1480       retcode = select (nfds, &aread, &awrite, &aexcept, &tvslice);
1481       if (retcode == -1)
1482         retcode = 0;
1483 #if DEBUG_NETWORK
1484       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Select retcode : %d\n", retcode);
1485 #endif
1486     }
1487     /* FIXME: <= writePipePos? Really? */
1488     if ((writePipePos != -1) && (returnedpos <= writePipePos))
1489     {
1490       GNUNET_CONTAINER_slist_append (handles_write, wfds->handles);
1491       retcode += write_handles;
1492 #if DEBUG_NETWORK
1493       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Added write pipe\n");
1494 #endif
1495     }
1496 #if DEBUG_NETWORK
1497     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ReadPipes is : %d\n", readPipes);
1498 #endif
1499     /* We have some pipes ready for read. */
1500     /* FIXME: it is supposed to work !! Only choose the Pipes who fired the event, but it is not working */
1501
1502     if (returnedpos < readPipes)
1503     {
1504       /*
1505        * for (i = 0; i < readPipes; i++)
1506        * {
1507        * waitstatus = WaitForSingleObject (handle_array[i], 0);
1508        * GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Read pipe %d wait status is : %d\n", i, waitstatus);
1509        * if (waitstatus != WAIT_OBJECT_0)
1510        * continue;
1511        * GNUNET_CONTAINER_slist_add (handles_read,
1512        * GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT,
1513        * readArray[i], sizeof (struct GNUNET_DISK_FileHandle));
1514        * retcode++;
1515        * GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Added read Pipe\n");
1516        * }
1517        */
1518       for (i = 0; i < readPipes; i++)
1519       {
1520         DWORD error;
1521         BOOL bret;
1522
1523         SetLastError (0);
1524         waitstatus = 0;
1525         bret =
1526             PeekNamedPipe (readArray[i]->h, NULL, 0, NULL, &waitstatus, NULL);
1527         error = GetLastError ();
1528 #if DEBUG_NETWORK
1529         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1530                     "Peek at read pipe %d (0x%x) returned %d (%d bytes available) GLE %u\n",
1531                     i, readArray[i]->h, bret, waitstatus, error);
1532 #endif
1533         if (bret == 0 || waitstatus <= 0)
1534           continue;
1535         GNUNET_CONTAINER_slist_add (handles_read,
1536                                     GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT,
1537                                     readArray[i],
1538                                     sizeof (struct GNUNET_DISK_FileHandle));
1539         retcode++;
1540 #if DEBUG_NETWORK
1541         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Added read Pipe 0x%x (0x%x)\n",
1542                     readArray[i], readArray[i]->h);
1543 #endif
1544       }
1545     }
1546     waitstatus = WaitForSingleObject (hEventWrite, 0);
1547 #if DEBUG_NETWORK
1548     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1549                 "Wait for the write event returned %d\n", waitstatus);
1550 #endif
1551     if (waitstatus == WAIT_OBJECT_0)
1552     {
1553       for (i = 0; i < wfds->sds.fd_count; i++)
1554       {
1555         DWORD error;
1556         int status;
1557         int so_error = 0;
1558         int sizeof_so_error = sizeof (so_error);
1559         int gso_result =
1560             getsockopt (wfds->sds.fd_array[i], SOL_SOCKET, SO_ERROR,
1561                         (char *) &so_error, &sizeof_so_error);
1562
1563         status = send (wfds->sds.fd_array[i], NULL, 0, 0);
1564         error = GetLastError ();
1565 #if DEBUG_NETWORK
1566         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1567                     "send to the socket %d returned %d (%u)\n", i, status,
1568                     error);
1569 #endif
1570         if (status == 0 || (error != WSAEWOULDBLOCK && error != WSAENOTCONN) ||
1571             (status == -1 && gso_result == 0 && error == WSAENOTCONN &&
1572              so_error == WSAECONNREFUSED))
1573         {
1574           FD_SET (wfds->sds.fd_array[i], &awrite);
1575           retcode += 1;
1576         }
1577       }
1578     }
1579   }
1580 #if DEBUG_NETWORK
1581   if (!nhandles || (returnedpos >= nhandles))
1582     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1583                 "Returning from _select() with nothing!\n");
1584 #endif
1585   if (rfds)
1586   {
1587     struct GNUNET_CONTAINER_SList_Iterator *t;
1588
1589     for (i = 0; i < rfds->sds.fd_count; i++)
1590     {
1591       WSAEventSelect (rfds->sds.fd_array[i], hEventRead, 0);
1592       nsock++;
1593     }
1594     for (t = GNUNET_CONTAINER_slist_begin (rfds->handles);
1595          GNUNET_CONTAINER_slist_end (t) != GNUNET_YES;
1596          GNUNET_CONTAINER_slist_next (t))
1597     {
1598       struct GNUNET_DISK_FileHandle *fh;
1599
1600       fh = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (t,
1601                                                                          NULL);
1602       if (fh->type == GNUNET_PIPE)
1603       {
1604         CancelIo (fh->h);
1605       }
1606     }
1607     GNUNET_CONTAINER_slist_iter_destroy (t);
1608 #if DEBUG_NETWORK
1609     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Zeroing rfds\n");
1610 #endif
1611     GNUNET_NETWORK_fdset_zero (rfds);
1612     if (retcode != -1 && nhandles && (returnedpos < nhandles))
1613       GNUNET_NETWORK_fdset_copy_native (rfds, &aread, retcode);
1614     GNUNET_CONTAINER_slist_append (rfds->handles, handles_read);
1615   }
1616   if (wfds)
1617   {
1618     for (i = 0; i < wfds->sds.fd_count; i++)
1619     {
1620       WSAEventSelect (wfds->sds.fd_array[i], hEventWrite, 0);
1621       nsock++;
1622     }
1623 #if DEBUG_NETWORK
1624     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Zeroing wfds\n");
1625 #endif
1626     GNUNET_NETWORK_fdset_zero (wfds);
1627     if (retcode != -1 && nhandles && (returnedpos < nhandles))
1628       GNUNET_NETWORK_fdset_copy_native (wfds, &awrite, retcode);
1629     GNUNET_CONTAINER_slist_append (wfds->handles, handles_write);
1630   }
1631   if (efds)
1632   {
1633     for (i = 0; i < efds->sds.fd_count; i++)
1634     {
1635       WSAEventSelect (efds->sds.fd_array[i], hEventException, 0);
1636       nsock++;
1637     }
1638 #if DEBUG_NETWORK
1639     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Zeroing efds\n");
1640 #endif
1641     GNUNET_NETWORK_fdset_zero (efds);
1642     if (retcode != -1 && nhandles && (returnedpos < nhandles))
1643       GNUNET_NETWORK_fdset_copy_native (efds, &aexcept, retcode);
1644     GNUNET_CONTAINER_slist_append (efds->handles, handles_except);
1645   }
1646   GNUNET_CONTAINER_slist_destroy (handles_read);
1647   GNUNET_CONTAINER_slist_destroy (handles_write);
1648   GNUNET_CONTAINER_slist_destroy (handles_except);
1649 #if DEBUG_NETWORK
1650   if (rfds)
1651   {
1652     struct GNUNET_CONTAINER_SList_Iterator *t;
1653
1654     for (i = 0; i < bread.fd_count; i++)
1655     {
1656       if (bread.fd_array[i] != 0)
1657         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "FD 0x%x is %s in rfds\n",
1658                     bread.fd_array[i],
1659                     (SAFE_FD_ISSET (bread.fd_array[i], rfds)) ? "SET" :
1660                     "NOT SET");
1661     }
1662     for (t = GNUNET_CONTAINER_slist_begin (rfds->handles);
1663          GNUNET_CONTAINER_slist_end (t) != GNUNET_YES;
1664          GNUNET_CONTAINER_slist_next (t))
1665     {
1666       struct GNUNET_DISK_FileHandle *fh;
1667
1668       fh = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (t,
1669                                                                          NULL);
1670       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "FD 0x%x is SET in rfds\n", fh->h);
1671     }
1672   }
1673   if (wfds)
1674   {
1675     for (i = 0; i < bwrite.fd_count; i++)
1676     {
1677       if (bwrite.fd_array[i] != 0)
1678         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "FD 0x%x is %s in wfds\n",
1679                     bwrite.fd_array[i],
1680                     (SAFE_FD_ISSET (bwrite.fd_array[i], rfds)) ? "SET" :
1681                     "NOT SET");
1682     }
1683   }
1684   if (efds)
1685   {
1686     for (i = 0; i < bexcept.fd_count; i++)
1687     {
1688       if (bexcept.fd_array[i] != 0)
1689         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "FD 0x%x is %s in efds\n",
1690                     bexcept.fd_array[i],
1691                     (SAFE_FD_ISSET (bexcept.fd_array[i], rfds)) ? "SET" :
1692                     "NOT SET");
1693     }
1694   }
1695   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Returning %d or 0\n", retcode);
1696 #endif
1697   if (nhandles && (returnedpos < nhandles))
1698     return retcode;
1699   else
1700 #endif
1701     return 0;
1702 }
1703
1704 /* end of network.c */