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