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