Add a third default.
[oweals/gnunet.git] / src / util / network.c
1 /*
2      This file is part of GNUnet.
3      (C) 2009-2013 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 3, 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  * @author Christian Grothoff
26  */
27 #include "platform.h"
28 #include "gnunet_util_lib.h"
29 #include "disk.h"
30
31 #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
32 #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
33 #define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall)
34
35 #define DEBUG_NETWORK GNUNET_EXTRA_LOGGING
36
37
38 #ifndef INVALID_SOCKET
39 #define INVALID_SOCKET -1
40 #endif
41
42
43 struct GNUNET_NETWORK_Handle
44 {
45 #ifndef MINGW
46   int fd;
47 #else
48   SOCKET fd;
49 #endif
50
51   /**
52    * Address family / domain.
53    */
54   int af;
55
56   /**
57    * Type of the socket
58    */
59   int type;
60
61   /**
62    * Number of bytes in addr.
63    */
64   socklen_t addrlen;
65
66   /**
67    * Address we were bound to, or NULL.
68    */
69   struct sockaddr *addr;
70
71 };
72
73
74 /**
75  * Test if the given protocol family is supported by this system.
76  *
77  * @param pf protocol family to test (PF_INET, PF_INET6, PF_UNIX)
78  * @return #GNUNET_OK if the PF is supported
79  */
80 int
81 GNUNET_NETWORK_test_pf (int pf)
82 {
83   int s;
84
85   s = socket (pf, SOCK_STREAM, 0);
86   if (-1 == s)
87   {
88     if (EAFNOSUPPORT == errno)
89       return GNUNET_NO;
90     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
91                 "Failed to create test socket: %s\n",
92                 STRERROR (errno));
93     return GNUNET_SYSERR;
94   }
95 #if WINDOWS
96   closesocket (s);
97 #else
98   close (s);
99 #endif
100   return GNUNET_OK;
101 }
102
103
104 /**
105  * Given a unixpath that is too long (larger than UNIX_PATH_MAX),
106  * shorten it to an acceptable length while keeping it unique
107  * and making sure it remains a valid filename (if possible).
108  *
109  * @param unixpath long path, will be freed (or same pointer returned
110  *        with moved 0-termination).
111  * @return shortened unixpath, NULL on error
112  */
113 char *
114 GNUNET_NETWORK_shorten_unixpath (char *unixpath)
115 {
116   struct sockaddr_un dummy;
117   size_t slen;
118   char *end;
119   struct GNUNET_HashCode sh;
120   struct GNUNET_CRYPTO_HashAsciiEncoded ae;
121   size_t upm;
122
123   upm = sizeof (dummy.sun_path);
124   slen = strlen (unixpath);
125   if (slen < upm)
126     return unixpath; /* no shortening required */
127   GNUNET_CRYPTO_hash (unixpath, slen, &sh);
128   while (16 +
129          strlen (unixpath) >= upm)
130   {
131     if (NULL == (end = strrchr (unixpath, '/')))
132     {
133       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
134                   _("Unable to shorten unix path `%s' while keeping name unique\n"),
135                   unixpath);
136       GNUNET_free (unixpath);
137       return NULL;
138     }
139     *end = '\0';
140   }
141   GNUNET_CRYPTO_hash_to_enc (&sh, &ae);
142   strncat (unixpath, (char*) ae.encoding, 16);
143   return unixpath;
144 }
145
146
147 #ifndef FD_COPY
148 #define FD_COPY(s, d) (memcpy ((d), (s), sizeof (fd_set)))
149 #endif
150
151
152 /**
153  * Set if a socket should use blocking or non-blocking IO.
154  *
155  * @param fd socket
156  * @param doBlock blocking mode
157  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
158  */
159 int
160 GNUNET_NETWORK_socket_set_blocking (struct GNUNET_NETWORK_Handle *fd, int doBlock)
161 {
162
163 #if MINGW
164   u_long mode;
165
166   mode = !doBlock;
167   if (ioctlsocket (fd->fd, FIONBIO, &mode) == SOCKET_ERROR)
168
169   {
170     SetErrnoFromWinsockError (WSAGetLastError ());
171     LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "ioctlsocket");
172     return GNUNET_SYSERR;
173   }
174   return GNUNET_OK;
175
176 #else
177   /* not MINGW */
178   int flags = fcntl (fd->fd, F_GETFL);
179
180   if (flags == -1)
181
182   {
183     LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "fcntl");
184     return GNUNET_SYSERR;
185   }
186   if (doBlock)
187     flags &= ~O_NONBLOCK;
188
189   else
190     flags |= O_NONBLOCK;
191   if (0 != fcntl (fd->fd, F_SETFL, flags))
192
193   {
194     LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "fcntl");
195     return GNUNET_SYSERR;
196   }
197   return GNUNET_OK;
198 #endif
199 }
200
201
202 /**
203  * Make a socket non-inheritable to child processes
204  *
205  * @param h the socket to make non-inheritable
206  * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
207  * @warning Not implemented on Windows
208  */
209 static int
210 socket_set_inheritable (const struct GNUNET_NETWORK_Handle *h)
211 {
212 #ifndef MINGW
213   int i;
214   i = fcntl (h->fd, F_GETFD);
215   if (i < 0)
216     return GNUNET_SYSERR;
217   if (i == (i | FD_CLOEXEC))
218     return GNUNET_OK;
219   i |= FD_CLOEXEC;
220   if (fcntl (h->fd, F_SETFD, i) < 0)
221     return GNUNET_SYSERR;
222 #else
223   BOOL b;
224   SetLastError (0);
225   b = SetHandleInformation ((HANDLE) h->fd, HANDLE_FLAG_INHERIT, 0);
226   if (!b)
227   {
228     SetErrnoFromWinsockError (WSAGetLastError ());
229     return GNUNET_SYSERR;
230   }
231 #endif
232   return GNUNET_OK;
233 }
234
235
236 #ifdef DARWIN
237 /**
238  * The MSG_NOSIGNAL equivalent on Mac OS X
239  *
240  * @param h the socket to make non-delaying
241  */
242 static void
243 socket_set_nosigpipe (const struct GNUNET_NETWORK_Handle *h)
244 {
245   int abs_value = 1;
246
247   if (0 !=
248       setsockopt (h->fd, SOL_SOCKET, SO_NOSIGPIPE,
249                   (const void *) &abs_value,
250                   sizeof (abs_value)))
251     LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "setsockopt");
252 }
253 #endif
254
255
256 /**
257  * Disable delays when sending data via the socket.
258  * (GNUnet makes sure that messages are as big as
259  * possible already).
260  *
261  * @param h the socket to make non-delaying
262  */
263 static void
264 socket_set_nodelay (const struct GNUNET_NETWORK_Handle *h)
265 {
266 #ifndef WINDOWS
267   int value = 1;
268
269   if (0 != setsockopt (h->fd, IPPROTO_TCP, TCP_NODELAY, &value, sizeof (value)))
270     LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "setsockopt");
271 #else
272   const char *abs_value = "1";
273
274   if (0 !=
275       setsockopt (h->fd, IPPROTO_TCP, TCP_NODELAY,
276                   (const void *) abs_value,
277                   sizeof (abs_value)))
278     LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "setsockopt");
279 #endif
280 }
281
282
283 /**
284  * Perform proper canonical initialization for a network handle.
285  * Set it to non-blocking, make it non-inheritable to child
286  * processes, disable SIGPIPE, enable "nodelay" (if non-UNIX
287  * stream socket) and check that it is smaller than FD_SETSIZE.
288  *
289  * @param h socket to initialize
290  * @param af address family of the socket
291  * @param type socket type
292  * @return #GNUNET_OK on success, #GNUNET_SYSERR if initialization
293  *         failed and the handle was destroyed
294  */
295 static int
296 initialize_network_handle (struct GNUNET_NETWORK_Handle *h,
297                            int af, int type)
298 {
299   h->af = af;
300   h->type = type;
301   if (h->fd == INVALID_SOCKET)
302   {
303 #ifdef MINGW
304     SetErrnoFromWinsockError (WSAGetLastError ());
305 #endif
306     GNUNET_free (h);
307     return GNUNET_SYSERR;
308   }
309 #ifndef MINGW
310   if (h->fd >= FD_SETSIZE)
311   {
312     GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (h));
313     errno = EMFILE;
314     return GNUNET_SYSERR;
315   }
316 #endif
317   if (GNUNET_OK != socket_set_inheritable (h))
318     LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
319                   "socket_set_inheritable");
320
321   if (GNUNET_SYSERR == GNUNET_NETWORK_socket_set_blocking (h, GNUNET_NO))
322   {
323     GNUNET_break (0);
324     GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (h));
325     return GNUNET_SYSERR;
326   }
327 #ifdef DARWIN
328   socket_set_nosigpipe (h);
329 #endif
330   if ( (type == SOCK_STREAM)
331 #ifdef AF_UNIX
332        && (af != AF_UNIX)
333 #endif
334        )
335     socket_set_nodelay (h);
336   return GNUNET_OK;
337 }
338
339
340 /**
341  * accept a new connection on a socket
342  *
343  * @param desc bound socket
344  * @param address address of the connecting peer, may be NULL
345  * @param address_len length of @a address
346  * @return client socket
347  */
348 struct GNUNET_NETWORK_Handle *
349 GNUNET_NETWORK_socket_accept (const struct GNUNET_NETWORK_Handle *desc,
350                               struct sockaddr *address,
351                               socklen_t *address_len)
352 {
353   struct GNUNET_NETWORK_Handle *ret;
354
355   ret = GNUNET_new (struct GNUNET_NETWORK_Handle);
356 #if DEBUG_NETWORK
357   {
358     struct sockaddr name;
359     socklen_t namelen = sizeof (name);
360     int gsn = getsockname (desc->fd, &name, &namelen);
361
362     if (gsn == 0)
363       LOG (GNUNET_ERROR_TYPE_DEBUG,
364            "Accepting connection on `%s'\n",
365            GNUNET_a2s (&name, namelen));
366   }
367 #endif
368   ret->fd = accept (desc->fd, address, address_len);
369   if (-1 == ret->fd)
370   {
371     GNUNET_free (ret);
372     return NULL;
373   }
374   if (GNUNET_OK != initialize_network_handle (ret,
375                                               (NULL != address) ? address->sa_family : desc->af,
376                                               SOCK_STREAM))
377     return NULL;
378   return ret;
379 }
380
381
382 /**
383  * Bind a socket to a particular address.
384  *
385  * @param desc socket to bind
386  * @param address address to be bound
387  * @param address_len length of @a address
388  * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
389  */
390 int
391 GNUNET_NETWORK_socket_bind (struct GNUNET_NETWORK_Handle *desc,
392                             const struct sockaddr *address,
393                             socklen_t address_len)
394 {
395   int ret;
396
397 #ifdef IPV6_V6ONLY
398 #ifdef IPPROTO_IPV6
399   {
400     const int on = 1;
401
402     if (AF_INET6 == desc->af)
403       if (setsockopt (desc->fd, IPPROTO_IPV6, IPV6_V6ONLY,
404                       (const void *) &on,
405                       sizeof (on)))
406         LOG_STRERROR (GNUNET_ERROR_TYPE_DEBUG, "setsockopt");
407   }
408 #endif
409 #endif
410 #ifndef WINDOWS
411   {
412     const int on = 1;
413
414     /* This is required here for TCP sockets, but only on UNIX */
415     if ((SOCK_STREAM == desc->type)
416         && (0 != setsockopt (desc->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on))))
417       LOG_STRERROR (GNUNET_ERROR_TYPE_DEBUG, "setsockopt");
418   }
419 #endif
420 #ifndef WINDOWS
421   {
422     /* set permissions of newly created UNIX domain socket to "user-only"; applications
423        can choose to relax this later */
424     mode_t old_mask = 0; /* assigned to make compiler happy */
425
426     if (AF_UNIX == address->sa_family)
427       old_mask = umask (S_IWGRP | S_IRGRP | S_IXGRP | S_IWOTH | S_IROTH | S_IXOTH);
428 #endif
429
430     ret = bind (desc->fd, address, address_len);
431 #ifndef WINDOWS
432     if (AF_UNIX == address->sa_family)
433       (void) umask (old_mask);
434   }
435 #endif
436 #ifdef MINGW
437   if (SOCKET_ERROR == ret)
438     SetErrnoFromWinsockError (WSAGetLastError ());
439 #endif
440   if (ret != 0)
441     return GNUNET_SYSERR;
442 #ifndef MINGW
443   desc->addr = GNUNET_malloc (address_len);
444   memcpy (desc->addr, address, address_len);
445   desc->addrlen = address_len;
446 #endif
447   return GNUNET_OK;
448 }
449
450
451 /**
452  * Close a socket
453  *
454  * @param desc socket
455  * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
456  */
457 int
458 GNUNET_NETWORK_socket_close (struct GNUNET_NETWORK_Handle *desc)
459 {
460   int ret;
461
462 #ifdef MINGW
463   DWORD error = 0;
464
465   SetLastError (0);
466   ret = closesocket (desc->fd);
467   error = WSAGetLastError ();
468   SetErrnoFromWinsockError (error);
469   LOG (GNUNET_ERROR_TYPE_DEBUG,
470        "Closed 0x%x, closesocket() returned %d, GLE is %u\n", desc->fd, ret,
471        error);
472 #else
473   ret = close (desc->fd);
474 #endif
475 #ifndef MINGW
476   if ((desc->af == AF_UNIX) && (NULL != desc->addr))
477   {
478     const struct sockaddr_un *un = (const struct sockaddr_un *) desc->addr;
479
480     if (0 != unlink (un->sun_path))
481       LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING,
482                          "unlink",
483                          un->sun_path);
484   }
485 #endif
486   GNUNET_NETWORK_socket_free_memory_only_ (desc);
487   return (ret == 0) ? GNUNET_OK : GNUNET_SYSERR;
488 }
489
490
491 /**
492  * Only free memory of a socket, keep the file descriptor untouched.
493  *
494  * @param desc socket
495  */
496 void
497 GNUNET_NETWORK_socket_free_memory_only_ (struct GNUNET_NETWORK_Handle *desc)
498 {
499   GNUNET_free_non_null (desc->addr);
500   GNUNET_free (desc);
501 }
502
503
504 /**
505  * Box a native socket (and check that it is a socket).
506  *
507  * @param fd socket to box
508  * @return NULL on error (including not supported on target platform)
509  */
510 struct GNUNET_NETWORK_Handle *
511 GNUNET_NETWORK_socket_box_native (SOCKTYPE fd)
512 {
513   struct GNUNET_NETWORK_Handle *ret;
514 #if MINGW
515   unsigned long i;
516   DWORD d;
517   /* FIXME: Find a better call to check that FD is valid */
518   if (WSAIoctl (fd, FIONBIO, (void *) &i, sizeof (i), NULL, 0, &d, NULL, NULL) != 0)
519     return NULL;                /* invalid FD */
520   ret = GNUNET_new (struct GNUNET_NETWORK_Handle);
521   ret->fd = fd;
522   ret->af = AF_UNSPEC;
523   return ret;
524 #else
525   if (fcntl (fd, F_GETFD) < 0)
526     return NULL;                /* invalid FD */
527   ret = GNUNET_new (struct GNUNET_NETWORK_Handle);
528   ret->fd = fd;
529   ret->af = AF_UNSPEC;
530   return ret;
531 #endif
532 }
533
534
535 /**
536  * Connect a socket to some remote address.
537  *
538  * @param desc socket
539  * @param address peer address
540  * @param address_len length of @a address
541  * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
542  */
543 int
544 GNUNET_NETWORK_socket_connect (const struct GNUNET_NETWORK_Handle *desc,
545                                const struct sockaddr *address,
546                                socklen_t address_len)
547 {
548   int ret;
549
550   ret = connect (desc->fd, address, address_len);
551
552 #ifdef MINGW
553   if (SOCKET_ERROR == ret)
554   {
555     SetErrnoFromWinsockError (WSAGetLastError ());
556     if (errno == EWOULDBLOCK)
557       errno = EINPROGRESS;
558   }
559 #endif
560   return ret == 0 ? GNUNET_OK : GNUNET_SYSERR;
561 }
562
563
564 /**
565  * Get socket options
566  *
567  * @param desc socket
568  * @param level protocol level of the option
569  * @param optname identifier of the option
570  * @param optval options
571  * @param optlen length of @a optval
572  * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
573  */
574 int
575 GNUNET_NETWORK_socket_getsockopt (const struct GNUNET_NETWORK_Handle *desc,
576                                   int level, int optname, void *optval,
577                                   socklen_t *optlen)
578 {
579   int ret;
580
581   ret = getsockopt (desc->fd, level, optname, optval, optlen);
582
583 #ifdef MINGW
584   if (ret == 0 && level == SOL_SOCKET && optname == SO_ERROR)
585     *((int *) optval) = GetErrnoFromWinsockError (*((int *) optval));
586
587   else if (SOCKET_ERROR == ret)
588     SetErrnoFromWinsockError (WSAGetLastError ());
589 #endif
590   return ret == 0 ? GNUNET_OK : GNUNET_SYSERR;
591 }
592
593
594 /**
595  * Listen on a socket
596  *
597  * @param desc socket
598  * @param backlog length of the listen queue
599  * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
600  */
601 int
602 GNUNET_NETWORK_socket_listen (const struct GNUNET_NETWORK_Handle *desc,
603                               int backlog)
604 {
605   int ret;
606
607   ret = listen (desc->fd, backlog);
608
609 #ifdef MINGW
610   if (SOCKET_ERROR == ret)
611     SetErrnoFromWinsockError (WSAGetLastError ());
612
613 #endif
614   return ret == 0 ? GNUNET_OK : GNUNET_SYSERR;
615 }
616
617
618 /**
619  * How much data is available to be read on this descriptor?
620  *
621  * @param desc socket
622  * @returns #GNUNET_NO if no data is available, or on error!
623  */
624 ssize_t
625 GNUNET_NETWORK_socket_recvfrom_amount (const struct GNUNET_NETWORK_Handle *
626                                        desc)
627 {
628   int error;
629
630   /* How much is there to be read? */
631 #ifndef WINDOWS
632   int pending;
633
634   error = ioctl (desc->fd, FIONREAD, &pending);
635   if (error == 0)
636     return (ssize_t) pending;
637   return GNUNET_NO;
638 #else
639   u_long pending;
640
641   error = ioctlsocket (desc->fd, FIONREAD, &pending);
642   if (error != SOCKET_ERROR)
643     return (ssize_t) pending;
644   return GNUNET_NO;
645 #endif
646 }
647
648
649 /**
650  * Read data from a socket (always non-blocking).
651  *
652  * @param desc socket
653  * @param buffer buffer
654  * @param length length of @a buffer
655  * @param src_addr either the source to recv from, or all zeroes
656  *        to be filled in by recvfrom
657  * @param addrlen length of the @a src_addr
658  */
659 ssize_t
660 GNUNET_NETWORK_socket_recvfrom (const struct GNUNET_NETWORK_Handle *desc,
661                                 void *buffer, size_t length,
662                                 struct sockaddr *src_addr, socklen_t *addrlen)
663 {
664   int ret;
665   int flags;
666
667   flags = 0;
668
669 #ifdef MSG_DONTWAIT
670   flags |= MSG_DONTWAIT;
671
672 #endif
673   ret = recvfrom (desc->fd, buffer, length, flags, src_addr, addrlen);
674 #ifdef MINGW
675   if (SOCKET_ERROR == ret)
676     SetErrnoFromWinsockError (WSAGetLastError ());
677 #endif
678   return ret;
679 }
680
681
682 /**
683  * Read data from a connected socket (always non-blocking).
684  *
685  * @param desc socket
686  * @param buffer buffer
687  * @param length length of @a buffer
688  */
689 ssize_t
690 GNUNET_NETWORK_socket_recv (const struct GNUNET_NETWORK_Handle * desc,
691                             void *buffer, size_t length)
692 {
693   int ret;
694   int flags;
695
696   flags = 0;
697
698 #ifdef MSG_DONTWAIT
699   flags |= MSG_DONTWAIT;
700 #endif
701   ret = recv (desc->fd, buffer, length, flags);
702 #ifdef MINGW
703   if (SOCKET_ERROR == ret)
704     SetErrnoFromWinsockError (WSAGetLastError ());
705 #endif
706   return ret;
707 }
708
709
710 /**
711  * Send data (always non-blocking).
712  *
713  * @param desc socket
714  * @param buffer data to send
715  * @param length size of the @a buffer
716  * @return number of bytes sent, #GNUNET_SYSERR on error
717  */
718 ssize_t
719 GNUNET_NETWORK_socket_send (const struct GNUNET_NETWORK_Handle * desc,
720                             const void *buffer, size_t length)
721 {
722   int ret;
723   int flags;
724
725   flags = 0;
726
727 #ifdef MSG_DONTWAIT
728   flags |= MSG_DONTWAIT;
729
730 #endif
731 #ifdef MSG_NOSIGNAL
732   flags |= MSG_NOSIGNAL;
733
734 #endif
735   ret = send (desc->fd, buffer, length, flags);
736
737 #ifdef MINGW
738   if (SOCKET_ERROR == ret)
739     SetErrnoFromWinsockError (WSAGetLastError ());
740
741 #endif
742   return ret;
743 }
744
745
746 /**
747  * Send data to a particular destination (always non-blocking).
748  * This function only works for UDP sockets.
749  *
750  * @param desc socket
751  * @param message data to send
752  * @param length size of the data
753  * @param dest_addr destination address
754  * @param dest_len length of @a address
755  * @return number of bytes sent, #GNUNET_SYSERR on error
756  */
757 ssize_t
758 GNUNET_NETWORK_socket_sendto (const struct GNUNET_NETWORK_Handle * desc,
759                               const void *message, size_t length,
760                               const struct sockaddr * dest_addr,
761                               socklen_t dest_len)
762 {
763   int ret;
764   int flags;
765
766   flags = 0;
767
768 #ifdef MSG_DONTWAIT
769   flags |= MSG_DONTWAIT;
770 #endif
771 #ifdef MSG_NOSIGNAL
772   flags |= MSG_NOSIGNAL;
773 #endif
774   ret = sendto (desc->fd, message, length, flags, dest_addr, dest_len);
775 #ifdef MINGW
776   if (SOCKET_ERROR == ret)
777     SetErrnoFromWinsockError (WSAGetLastError ());
778 #endif
779   return ret;
780 }
781
782
783 /**
784  * Set socket option
785  *
786  * @param fd socket
787  * @param level protocol level of the option
788  * @param option_name option identifier
789  * @param option_value value to set
790  * @param option_len size of option_value
791  * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
792  */
793 int
794 GNUNET_NETWORK_socket_setsockopt (struct GNUNET_NETWORK_Handle *fd, int level,
795                                   int option_name, const void *option_value,
796                                   socklen_t option_len)
797 {
798   int ret;
799
800   ret = setsockopt (fd->fd, level, option_name, option_value, option_len);
801 #ifdef MINGW
802   if (SOCKET_ERROR == ret)
803     SetErrnoFromWinsockError (WSAGetLastError ());
804 #endif
805   return ret == 0 ? GNUNET_OK : GNUNET_SYSERR;
806 }
807
808
809 /**
810  * Create a new socket.  Configure it for non-blocking IO and
811  * mark it as non-inheritable to child processes (set the
812  * close-on-exec flag).
813  *
814  * @param domain domain of the socket
815  * @param type socket type
816  * @param protocol network protocol
817  * @return new socket, NULL on error
818  */
819 struct GNUNET_NETWORK_Handle *
820 GNUNET_NETWORK_socket_create (int domain, int type, int protocol)
821 {
822   struct GNUNET_NETWORK_Handle *ret;
823
824   ret = GNUNET_new (struct GNUNET_NETWORK_Handle);
825   ret->fd = socket (domain, type, protocol);
826   if (-1 == ret->fd)
827   {
828     GNUNET_free (ret);
829     return NULL;
830   }
831   if (GNUNET_OK !=
832       initialize_network_handle (ret, domain, type))
833     return NULL;
834   return ret;
835 }
836
837
838 /**
839  * Shut down socket operations
840  * @param desc socket
841  * @param how type of shutdown
842  * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
843  */
844 int
845 GNUNET_NETWORK_socket_shutdown (struct GNUNET_NETWORK_Handle *desc, int how)
846 {
847   int ret;
848
849   ret = shutdown (desc->fd, how);
850 #ifdef MINGW
851   if (ret != 0)
852     SetErrnoFromWinsockError (WSAGetLastError ());
853 #endif
854   return ret == 0 ? GNUNET_OK : GNUNET_SYSERR;
855 }
856
857
858 /**
859  * Disable the "CORK" feature for communication with the given socket,
860  * forcing the OS to immediately flush the buffer on transmission
861  * instead of potentially buffering multiple messages.  Essentially
862  * reduces the OS send buffers to zero.
863  *
864  * @param desc socket
865  * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
866  */
867 int
868 GNUNET_NETWORK_socket_disable_corking (struct GNUNET_NETWORK_Handle *desc)
869 {
870   int ret = 0;
871
872 #if WINDOWS
873   int value = 0;
874
875   if (0 !=
876       (ret =
877        setsockopt (desc->fd, SOL_SOCKET, SO_SNDBUF, (char *) &value,
878                    sizeof (value))))
879     LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "setsockopt");
880   if (0 !=
881       (ret =
882        setsockopt (desc->fd, SOL_SOCKET, SO_RCVBUF, (char *) &value,
883                    sizeof (value))))
884     LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "setsockopt");
885 #elif LINUX
886   int value = 0;
887
888   if (0 !=
889       (ret =
890        setsockopt (desc->fd, SOL_SOCKET, SO_SNDBUF, &value, sizeof (value))))
891     LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "setsockopt");
892   if (0 !=
893       (ret =
894        setsockopt (desc->fd, SOL_SOCKET, SO_RCVBUF, &value, sizeof (value))))
895     LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "setsockopt");
896 #endif
897   return ret == 0 ? GNUNET_OK : GNUNET_SYSERR;
898 }
899
900
901 /**
902  * Reset FD set
903  *
904  * @param fds fd set
905  */
906 void
907 GNUNET_NETWORK_fdset_zero (struct GNUNET_NETWORK_FDSet *fds)
908 {
909   FD_ZERO (&fds->sds);
910   fds->nsds = 0;
911 #ifdef MINGW
912   GNUNET_CONTAINER_slist_clear (fds->handles);
913 #endif
914 }
915
916
917 /**
918  * Add a socket to the FD set
919  *
920  * @param fds fd set
921  * @param desc socket to add
922  */
923 void
924 GNUNET_NETWORK_fdset_set (struct GNUNET_NETWORK_FDSet *fds,
925                           const struct GNUNET_NETWORK_Handle *desc)
926 {
927   FD_SET (desc->fd, &fds->sds);
928   if (desc->fd + 1 > fds->nsds)
929     fds->nsds = desc->fd + 1;
930 }
931
932
933 /**
934  * Check whether a socket is part of the fd set
935  *
936  * @param fds fd set
937  * @param desc socket
938  * @return 0 if the FD is not set
939  */
940 int
941 GNUNET_NETWORK_fdset_isset (const struct GNUNET_NETWORK_FDSet *fds,
942                             const struct GNUNET_NETWORK_Handle *desc)
943 {
944   return FD_ISSET (desc->fd, &fds->sds);
945 }
946
947
948 /**
949  * Add one fd set to another
950  *
951  * @param dst the fd set to add to
952  * @param src the fd set to add from
953  */
954 void
955 GNUNET_NETWORK_fdset_add (struct GNUNET_NETWORK_FDSet *dst,
956                           const struct GNUNET_NETWORK_FDSet *src)
957 {
958 #ifndef MINGW
959   int nfds;
960
961   for (nfds = src->nsds; nfds > 0; nfds--)
962     if (FD_ISSET (nfds, &src->sds))
963
964     {
965       FD_SET (nfds, &dst->sds);
966       if (nfds + 1 > dst->nsds)
967         dst->nsds = nfds + 1;
968     }
969 #else
970   /* This is MinGW32-specific implementation that relies on the code that
971    * winsock2.h defines for FD_SET. Namely, it relies on FD_SET checking
972    * that fd being added is not already in the set.
973    * Also relies on us knowing what's inside fd_set (fd_count and fd_array).
974    */
975   int i;
976   for (i = 0; i < src->sds.fd_count; i++)
977     FD_SET (src->sds.fd_array[i], &dst->sds);
978   if (src->nsds > dst->nsds)
979     dst->nsds = src->nsds;
980
981   GNUNET_CONTAINER_slist_append (dst->handles, src->handles);
982 #endif
983 }
984
985
986 /**
987  * Copy one fd set to another
988  *
989  * @param to destination
990  * @param from source
991  */
992 void
993 GNUNET_NETWORK_fdset_copy (struct GNUNET_NETWORK_FDSet *to,
994                            const struct GNUNET_NETWORK_FDSet *from)
995 {
996   FD_COPY (&from->sds, &to->sds);
997   to->nsds = from->nsds;
998
999 #ifdef MINGW
1000   GNUNET_CONTAINER_slist_clear (to->handles);
1001   GNUNET_CONTAINER_slist_append (to->handles, from->handles);
1002 #endif
1003 }
1004
1005
1006 /**
1007  * Return file descriptor for this network handle
1008  *
1009  * @param desc wrapper to process
1010  * @return POSIX file descriptor
1011  */
1012 int
1013 GNUNET_NETWORK_get_fd (struct GNUNET_NETWORK_Handle *desc)
1014 {
1015   return desc->fd;
1016 }
1017
1018
1019 /**
1020  * Return sockaddr for this network handle
1021  *
1022  * @param desc wrapper to process
1023  * @return sockaddr
1024  */
1025 struct sockaddr*
1026 GNUNET_NETWORK_get_addr (struct GNUNET_NETWORK_Handle *desc)
1027 {
1028   return desc->addr;
1029 }
1030
1031
1032 /**
1033  * Return sockaddr length for this network handle
1034  *
1035  * @param desc wrapper to process
1036  * @return socklen_t for sockaddr
1037  */
1038 socklen_t
1039 GNUNET_NETWORK_get_addrlen (struct GNUNET_NETWORK_Handle *desc)
1040 {
1041   return desc->addrlen;
1042 }
1043
1044
1045 /**
1046  * Copy a native fd set
1047  *
1048  * @param to destination
1049  * @param from native source set
1050  * @param nfds the biggest socket number in from + 1
1051  */
1052 void
1053 GNUNET_NETWORK_fdset_copy_native (struct GNUNET_NETWORK_FDSet *to,
1054                                   const fd_set * from, int nfds)
1055 {
1056   FD_COPY (from, &to->sds);
1057   to->nsds = nfds;
1058 }
1059
1060
1061 /**
1062  * Set a native fd in a set
1063  *
1064  * @param to destination
1065  * @param nfd native FD to set
1066  */
1067 void
1068 GNUNET_NETWORK_fdset_set_native (struct GNUNET_NETWORK_FDSet *to, int nfd)
1069 {
1070   GNUNET_assert ((nfd >= 0) && (nfd < FD_SETSIZE));
1071   FD_SET (nfd, &to->sds);
1072   to->nsds = GNUNET_MAX (nfd + 1, to->nsds);
1073 }
1074
1075
1076 /**
1077  * Test native fd in a set
1078  *
1079  * @param to set to test, NULL for empty set
1080  * @param nfd native FD to test, or -1 for none
1081  * @return #GNUNET_YES if FD is set in the set
1082  */
1083 int
1084 GNUNET_NETWORK_fdset_test_native (const struct GNUNET_NETWORK_FDSet *to,
1085                                   int nfd)
1086 {
1087   if ((nfd == -1) || (to == NULL))
1088     return GNUNET_NO;
1089   return FD_ISSET (nfd, &to->sds) ? GNUNET_YES : GNUNET_NO;
1090 }
1091
1092
1093 /**
1094  * Add a file handle to the fd set
1095  * @param fds fd set
1096  * @param h the file handle to add
1097  */
1098 void
1099 GNUNET_NETWORK_fdset_handle_set (struct GNUNET_NETWORK_FDSet *fds,
1100                                  const struct GNUNET_DISK_FileHandle *h)
1101 {
1102 #ifdef MINGW
1103   GNUNET_CONTAINER_slist_add (fds->handles,
1104                               GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT, h,
1105                               sizeof (struct GNUNET_DISK_FileHandle));
1106
1107 #else
1108   int fd;
1109
1110   GNUNET_DISK_internal_file_handle_ (h, &fd, sizeof (int));
1111   FD_SET (fd, &fds->sds);
1112   if (fd + 1 > fds->nsds)
1113     fds->nsds = fd + 1;
1114
1115 #endif
1116 }
1117
1118
1119 /**
1120  * Check if a file handle is part of an fd set
1121  * @param fds fd set
1122  * @param h file handle
1123  * @return #GNUNET_YES if the file handle is part of the set
1124  */
1125 int
1126 GNUNET_NETWORK_fdset_handle_isset (const struct GNUNET_NETWORK_FDSet *fds,
1127                                    const struct GNUNET_DISK_FileHandle *h)
1128 {
1129
1130 #ifdef MINGW
1131   return GNUNET_CONTAINER_slist_contains (fds->handles, h,
1132                                           sizeof (struct
1133                                                   GNUNET_DISK_FileHandle));
1134 #else
1135   return FD_ISSET (h->fd, &fds->sds);
1136 #endif
1137 }
1138
1139
1140 /**
1141  * Checks if two fd sets overlap
1142  * @param fds1 first fd set
1143  * @param fds2 second fd set
1144  * @return #GNUNET_YES if they do overlap, #GNUNET_NO otherwise
1145  */
1146 int
1147 GNUNET_NETWORK_fdset_overlap (const struct GNUNET_NETWORK_FDSet *fds1,
1148                               const struct GNUNET_NETWORK_FDSet *fds2)
1149 {
1150 #ifndef MINGW
1151   int nfds;
1152
1153   nfds = fds1->nsds;
1154   if (nfds > fds2->nsds)
1155     nfds = fds2->nsds;
1156   while (nfds > 0)
1157   {
1158     nfds--;
1159     if (FD_ISSET (nfds, &fds1->sds) && FD_ISSET (nfds, &fds2->sds))
1160       return GNUNET_YES;
1161   }
1162 #else
1163   struct GNUNET_CONTAINER_SList_Iterator it;
1164   struct GNUNET_DISK_FileHandle *h;
1165   int i;
1166   int j;
1167
1168   /*This code is somewhat hacky, we are not supposed to know what's
1169    * inside of fd_set; also the O(n^2) is really bad... */
1170
1171   for (i = 0; i < fds1->sds.fd_count; i++)
1172   {
1173     for (j = 0; j < fds2->sds.fd_count; j++)
1174     {
1175       if (fds1->sds.fd_array[i] == fds2->sds.fd_array[j])
1176         return GNUNET_YES;
1177     }
1178   }
1179   it = GNUNET_CONTAINER_slist_begin (fds1->handles);
1180   while (GNUNET_CONTAINER_slist_end (&it) != GNUNET_YES)
1181   {
1182 #if DEBUG_NETWORK
1183     struct GNUNET_CONTAINER_SList_Iterator t;
1184 #endif
1185     h = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (&it,
1186                                                                       NULL);
1187 #if DEBUG_NETWORK
1188     LOG (GNUNET_ERROR_TYPE_DEBUG, "Checking that FD 0x%x is in another set:\n",
1189          h->h);
1190     for (t = GNUNET_CONTAINER_slist_begin (fds2->handles);
1191          GNUNET_CONTAINER_slist_end (&t) != GNUNET_YES;
1192          GNUNET_CONTAINER_slist_next (&t))
1193     {
1194       struct GNUNET_DISK_FileHandle *fh;
1195
1196       fh = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (&t,
1197                                                                          NULL);
1198       LOG (GNUNET_ERROR_TYPE_DEBUG, "0x%x\n", fh->h);
1199     }
1200 #endif
1201     if (GNUNET_CONTAINER_slist_contains
1202         (fds2->handles, h, sizeof (struct GNUNET_DISK_FileHandle)))
1203     {
1204       return GNUNET_YES;
1205     }
1206     GNUNET_CONTAINER_slist_next (&it);
1207   }
1208 #endif
1209   return GNUNET_NO;
1210 }
1211
1212
1213 /**
1214  * Creates an fd set
1215  *
1216  * @return a new fd set
1217  */
1218 struct GNUNET_NETWORK_FDSet *
1219 GNUNET_NETWORK_fdset_create ()
1220 {
1221   struct GNUNET_NETWORK_FDSet *fds;
1222
1223   fds = GNUNET_new (struct GNUNET_NETWORK_FDSet);
1224 #ifdef MINGW
1225   fds->handles = GNUNET_CONTAINER_slist_create ();
1226 #endif
1227   GNUNET_NETWORK_fdset_zero (fds);
1228   return fds;
1229 }
1230
1231
1232 /**
1233  * Releases the associated memory of an fd set
1234  *
1235  * @param fds fd set
1236  */
1237 void
1238 GNUNET_NETWORK_fdset_destroy (struct GNUNET_NETWORK_FDSet *fds)
1239 {
1240 #ifdef MINGW
1241   GNUNET_CONTAINER_slist_destroy (fds->handles);
1242 #endif
1243   GNUNET_free (fds);
1244 }
1245
1246 #if MINGW
1247 struct _select_params
1248 {
1249   fd_set *r;
1250   fd_set *w;
1251   fd_set *e;
1252   struct timeval *tv;
1253   HANDLE wakeup;
1254   HANDLE standby;
1255   SOCKET wakeup_socket;
1256   int status;
1257 };
1258
1259 static DWORD WINAPI
1260 _selector (LPVOID p)
1261 {
1262   struct _select_params *sp = p;
1263
1264   while (1)
1265   {
1266     WaitForSingleObject (sp->standby, INFINITE);
1267     ResetEvent (sp->standby);
1268     sp->status = select (1, sp->r, sp->w, sp->e, sp->tv);
1269     if (FD_ISSET (sp->wakeup_socket, sp->r))
1270     {
1271       FD_CLR (sp->wakeup_socket, sp->r);
1272       sp->status -= 1;
1273     }
1274     SetEvent (sp->wakeup);
1275   }
1276   return 0;
1277 }
1278 #endif
1279
1280
1281 /**
1282  * Check if sockets or pipes meet certain conditions
1283  * @param rfds set of sockets or pipes to be checked for readability
1284  * @param wfds set of sockets or pipes to be checked for writability
1285  * @param efds set of sockets or pipes to be checked for exceptions
1286  * @param timeout relative value when to return
1287  * @return number of selected sockets or pipes, #GNUNET_SYSERR on error
1288  */
1289 int
1290 GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds,
1291                               struct GNUNET_NETWORK_FDSet *wfds,
1292                               struct GNUNET_NETWORK_FDSet *efds,
1293                               const struct GNUNET_TIME_Relative timeout)
1294 {
1295   int nfds = 0;
1296 #ifdef MINGW
1297   int handles = 0;
1298   int ex_handles = 0;
1299   int read_handles = 0;
1300   int write_handles = 0;
1301
1302   int i = 0;
1303   int retcode = 0;
1304   uint64_t mcs_total = 0;
1305   DWORD ms_rounded = 0;
1306
1307   int nhandles = 0;
1308
1309   static HANDLE hEventPipeWrite = 0;
1310   static HANDLE hEventReadReady = 0;
1311
1312   static struct _select_params sp;
1313   static HANDLE select_thread = NULL;
1314   static HANDLE select_finished_event = NULL;
1315   static HANDLE select_standby_event = NULL;
1316   static SOCKET select_wakeup_socket = -1;
1317   static SOCKET select_send_socket = -1;
1318   static struct timeval select_timeout;
1319
1320   int readPipes = 0;
1321   int writePipePos = 0;
1322
1323   HANDLE handle_array[FD_SETSIZE + 2];
1324   int returncode = -1;
1325   int returnedpos = 0;
1326
1327   struct GNUNET_CONTAINER_SList *handles_read;
1328   struct GNUNET_CONTAINER_SList *handles_write;
1329   struct GNUNET_CONTAINER_SList *handles_except;
1330
1331   int selectret = 0;
1332
1333   fd_set aread;
1334   fd_set awrite;
1335   fd_set aexcept;
1336
1337 #if DEBUG_NETWORK
1338   fd_set bread;
1339   fd_set bwrite;
1340   fd_set bexcept;
1341 #endif
1342
1343   /* TODO: Make this growable */
1344   struct GNUNET_DISK_FileHandle *readArray[50];
1345 #else
1346   struct timeval tv;
1347 #endif
1348   if (NULL != rfds)
1349   {
1350     nfds = rfds->nsds;
1351 #ifdef MINGW
1352     handles += read_handles = GNUNET_CONTAINER_slist_count (rfds->handles);
1353 #if DEBUG_NETWORK
1354     {
1355       struct GNUNET_CONTAINER_SList_Iterator t;
1356
1357       for (t = GNUNET_CONTAINER_slist_begin (rfds->handles);
1358            GNUNET_CONTAINER_slist_end (&t) != GNUNET_YES;
1359            GNUNET_CONTAINER_slist_next (&t))
1360       {
1361         struct GNUNET_DISK_FileHandle *fh;
1362
1363         fh = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (&t,
1364                                                                            NULL);
1365         LOG (GNUNET_ERROR_TYPE_DEBUG, "FD 0x%x (0x%x) is SET in rfds\n", fh->h,
1366              fh);
1367       }
1368     }
1369 #endif
1370 #endif
1371   }
1372   if (NULL != wfds)
1373   {
1374     nfds = GNUNET_MAX (nfds, wfds->nsds);
1375 #ifdef MINGW
1376     handles += write_handles = GNUNET_CONTAINER_slist_count (wfds->handles);
1377 #endif
1378   }
1379   if (NULL != efds)
1380   {
1381     nfds = GNUNET_MAX (nfds, efds->nsds);
1382 #ifdef MINGW
1383     handles += ex_handles = GNUNET_CONTAINER_slist_count (efds->handles);
1384 #endif
1385   }
1386
1387   if ((nfds == 0) &&
1388       (timeout.rel_value_us == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
1389 #ifdef MINGW
1390       && handles == 0
1391 #endif
1392       )
1393   {
1394     GNUNET_break (0);
1395     LOG (GNUNET_ERROR_TYPE_ERROR,
1396          _
1397          ("Fatal internal logic error, process hangs in `%s' (abort with CTRL-C)!\n"),
1398          "select");
1399   }
1400 #ifndef MINGW
1401   tv.tv_sec = timeout.rel_value_us / GNUNET_TIME_UNIT_SECONDS.rel_value_us;
1402   tv.tv_usec =
1403     (timeout.rel_value_us -
1404      (tv.tv_sec * GNUNET_TIME_UNIT_SECONDS.rel_value_us));
1405   return select (nfds,
1406                  (NULL != rfds) ? &rfds->sds : NULL,
1407                  (NULL != wfds) ? &wfds->sds : NULL,
1408                  (NULL != efds) ? &efds->sds : NULL,
1409                  (timeout.rel_value_us ==
1410                   GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us) ? NULL : &tv);
1411
1412 #else
1413 #define SAFE_FD_ISSET(fd, set)  (set != NULL && FD_ISSET(fd, set))
1414   /* calculate how long we need to wait in microseconds */
1415   if (timeout.rel_value_us == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
1416   {
1417     mcs_total = INFINITE;
1418     ms_rounded = INFINITE;
1419   }
1420   else
1421   {
1422     mcs_total = timeout.rel_value_us / GNUNET_TIME_UNIT_MICROSECONDS.rel_value_us;
1423     ms_rounded = (DWORD) (mcs_total / GNUNET_TIME_UNIT_MILLISECONDS.rel_value_us);
1424     if (mcs_total > 0 && ms_rounded == 0)
1425       ms_rounded = 1;
1426   }
1427   /* select() may be used as a portable way to sleep */
1428   if (!(rfds || wfds || efds))
1429   {
1430     Sleep (ms_rounded);
1431     return 0;
1432   }
1433
1434   if (NULL == select_thread)
1435   {
1436     SOCKET select_listening_socket = -1;
1437     struct sockaddr_in s_in;
1438     int alen;
1439     int res;
1440     unsigned long p;
1441
1442     select_standby_event = CreateEvent (NULL, TRUE, FALSE, NULL);
1443     select_finished_event = CreateEvent (NULL, TRUE, FALSE, NULL);
1444
1445     select_wakeup_socket = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
1446
1447     select_listening_socket = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
1448
1449     p = 1;
1450     res = ioctlsocket (select_wakeup_socket, FIONBIO, &p);
1451     LOG (GNUNET_ERROR_TYPE_DEBUG, "Select thread initialization: ioctlsocket() returns %d\n", res);
1452
1453     alen = sizeof (s_in);
1454     s_in.sin_family = AF_INET;
1455     s_in.sin_port = 0;
1456     s_in.sin_addr.S_un.S_un_b.s_b1 = 127;
1457     s_in.sin_addr.S_un.S_un_b.s_b2 = 0;
1458     s_in.sin_addr.S_un.S_un_b.s_b3 = 0;
1459     s_in.sin_addr.S_un.S_un_b.s_b4 = 1;
1460     res = bind (select_listening_socket, (const struct sockaddr *) &s_in, sizeof (s_in));
1461     LOG (GNUNET_ERROR_TYPE_DEBUG, "Select thread initialization: bind() returns %d\n", res);
1462
1463     res = getsockname (select_listening_socket, (struct sockaddr *) &s_in, &alen);
1464     LOG (GNUNET_ERROR_TYPE_DEBUG, "Select thread initialization: getsockname() returns %d\n", res);
1465
1466     res = listen (select_listening_socket, SOMAXCONN);
1467     LOG (GNUNET_ERROR_TYPE_DEBUG, "Select thread initialization: listen() returns %d\n", res);
1468
1469     res = connect (select_wakeup_socket, (const struct sockaddr *) &s_in, sizeof (s_in));
1470     LOG (GNUNET_ERROR_TYPE_DEBUG, "Select thread initialization: connect() returns %d\n", res);
1471
1472     select_send_socket = accept (select_listening_socket, (struct sockaddr *) &s_in, &alen);
1473
1474     closesocket (select_listening_socket);
1475
1476     sp.wakeup = select_finished_event;
1477     sp.standby = select_standby_event;
1478     sp.wakeup_socket = select_wakeup_socket;
1479
1480     select_thread = CreateThread (NULL, 0, _selector, &sp, 0, NULL);
1481   }
1482
1483
1484   handles_read = GNUNET_CONTAINER_slist_create ();
1485   handles_write = GNUNET_CONTAINER_slist_create ();
1486   handles_except = GNUNET_CONTAINER_slist_create ();
1487   FD_ZERO (&aread);
1488   FD_ZERO (&awrite);
1489   FD_ZERO (&aexcept);
1490 #if DEBUG_NETWORK
1491   FD_ZERO (&bread);
1492   FD_ZERO (&bwrite);
1493   FD_ZERO (&bexcept);
1494 #endif
1495   if (rfds)
1496   {
1497     FD_COPY (&rfds->sds, &aread);
1498 #if DEBUG_NETWORK
1499     FD_COPY (&rfds->sds, &bread);
1500 #endif
1501   }
1502   if (wfds)
1503   {
1504     FD_COPY (&wfds->sds, &awrite);
1505 #if DEBUG_NETWORK
1506     FD_COPY (&wfds->sds, &bwrite);
1507 #endif
1508   }
1509   if (efds)
1510   {
1511     FD_COPY (&efds->sds, &aexcept);
1512 #if DEBUG_NETWORK
1513     FD_COPY (&efds->sds, &bexcept);
1514 #endif
1515   }
1516
1517   /* Start by doing a fast check on sockets and pipes (without waiting). It is cheap, and is sufficient most of the time.
1518      By profiling we detected that to be true in 90% of the cases.
1519   */
1520
1521   /* Do the select now */
1522   select_timeout.tv_sec = 0;
1523   select_timeout.tv_usec = 0;
1524
1525   /* Copy all the writes to the except, so we can detect connect() errors */
1526   for (i = 0; i < awrite.fd_count; i++)
1527     FD_SET (awrite.fd_array[i], &aexcept);
1528   if (aread.fd_count > 0 || awrite.fd_count > 0 || aexcept.fd_count > 0)
1529     selectret = select (1, (rfds != NULL) ? &aread : NULL,
1530         (wfds != NULL) ? &awrite : NULL, &aexcept, &select_timeout);
1531   else
1532     selectret = 0;
1533   if (selectret == -1)
1534   {
1535     /* Throw an error early on, while we still have the context. */
1536     LOG (GNUNET_ERROR_TYPE_ERROR, "W32 select(%d, %d, %d) failed: %lu\n",
1537         rfds ? aread.fd_count : 0, wfds ? awrite.fd_count : 0, aexcept.fd_count, GetLastError ());
1538     GNUNET_abort ();
1539   }
1540
1541   /* Check aexcept, add its contents to awrite
1542      This is technically wrong (aexcept might have its own descriptors), we should
1543      have checked that descriptors were in awrite originally before re-adding them from
1544      aexcept. Luckily, GNUnet never uses aexcept for anything, so this does not become a problem (yet). */
1545   for (i = 0; i < aexcept.fd_count; i++)
1546     FD_SET (aexcept.fd_array[i], &awrite);
1547
1548   /* If our select returned something or is a 0-timed request, then also check the pipes and get out of here! */
1549   /* Sadly, it means code duplication :( */
1550   if ((selectret > 0) || (mcs_total == 0))
1551   {
1552     /* Read Pipes */
1553     if (rfds && read_handles)
1554     {
1555       struct GNUNET_CONTAINER_SList_Iterator i;
1556       int c;
1557
1558       for (c = 0, i = GNUNET_CONTAINER_slist_begin (rfds->handles);
1559           GNUNET_CONTAINER_slist_end (&i) != GNUNET_YES;
1560           GNUNET_CONTAINER_slist_next (&i), c++)
1561       {
1562         struct GNUNET_DISK_FileHandle *fh;
1563
1564         fh = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (&i,NULL);
1565         if (fh->type == GNUNET_DISK_HANLDE_TYPE_PIPE)
1566         {
1567           DWORD error;
1568           BOOL bret;
1569
1570           SetLastError (0);
1571           DWORD waitstatus = 0;
1572           bret = PeekNamedPipe (fh->h, NULL, 0, NULL, &waitstatus, NULL);
1573           error = GetLastError ();
1574           LOG (GNUNET_ERROR_TYPE_DEBUG, "Peek at read pipe %d (0x%x) returned %d (%d bytes available) GLE %u\n",
1575               c, fh->h, bret, waitstatus, error);
1576           if (bret == 0)
1577           {
1578             /* TODO: either add more errors to this condition, or eliminate it
1579              * entirely (failed to peek -> pipe is in serious trouble, should
1580              * be selected as readable).
1581              */
1582             if (error != ERROR_BROKEN_PIPE && error != ERROR_INVALID_HANDLE)
1583               continue;
1584           }
1585           else if (waitstatus <= 0)
1586             continue;
1587           GNUNET_CONTAINER_slist_add (handles_read, GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT,
1588               fh, sizeof (struct GNUNET_DISK_FileHandle));
1589           retcode++;
1590           LOG (GNUNET_ERROR_TYPE_DEBUG, "Added read Pipe 0x%x (0x%x)\n",
1591               fh, fh->h);
1592         }
1593         else
1594         {
1595           GNUNET_CONTAINER_slist_add (handles_read, GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT,
1596               fh, sizeof (struct GNUNET_DISK_FileHandle));
1597           retcode++;
1598         }
1599       }
1600     }
1601     if (wfds && write_handles)
1602     {
1603       LOG (GNUNET_ERROR_TYPE_DEBUG,
1604           "Adding the write ready event to the array as %d\n", nhandles);
1605       GNUNET_CONTAINER_slist_append (handles_write, wfds->handles);
1606       retcode += write_handles;
1607     }
1608     if (efds && ex_handles)
1609     {
1610       struct GNUNET_CONTAINER_SList_Iterator i;
1611
1612       for (i = GNUNET_CONTAINER_slist_begin (efds->handles);
1613           GNUNET_CONTAINER_slist_end (&i) != GNUNET_YES;
1614           GNUNET_CONTAINER_slist_next (&i))
1615       {
1616         struct GNUNET_DISK_FileHandle *fh;
1617         DWORD dwBytes;
1618
1619         fh = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (&i, NULL);
1620         if (fh->type == GNUNET_DISK_HANLDE_TYPE_PIPE)
1621         {
1622           if (PeekNamedPipe (fh->h, NULL, 0, NULL, &dwBytes, NULL))
1623             continue;
1624           GNUNET_CONTAINER_slist_add (handles_except, GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT,
1625               fh, sizeof (struct GNUNET_DISK_FileHandle));
1626           retcode++;
1627         }
1628       }
1629     }
1630
1631     /* Add our select() result.*/
1632     if (selectret >= 0)
1633       retcode += selectret;
1634
1635     if (rfds)
1636     {
1637       GNUNET_NETWORK_fdset_zero (rfds);
1638       if (selectret != -1)
1639         GNUNET_NETWORK_fdset_copy_native (rfds, &aread, selectret);
1640       GNUNET_CONTAINER_slist_append (rfds->handles, handles_read);
1641     }
1642     if (wfds)
1643     {
1644       GNUNET_NETWORK_fdset_zero (wfds);
1645       if (selectret != -1)
1646         GNUNET_NETWORK_fdset_copy_native (wfds, &awrite, selectret);
1647       GNUNET_CONTAINER_slist_append (wfds->handles, handles_write);
1648     }
1649     if (efds)
1650     {
1651       GNUNET_NETWORK_fdset_zero (efds);
1652       if (selectret != -1)
1653         GNUNET_NETWORK_fdset_copy_native (efds, &aexcept, selectret);
1654       GNUNET_CONTAINER_slist_append (efds->handles, handles_except);
1655     }
1656     GNUNET_CONTAINER_slist_destroy (handles_read);
1657     GNUNET_CONTAINER_slist_destroy (handles_write);
1658     GNUNET_CONTAINER_slist_destroy (handles_except);
1659
1660     if (selectret == -1)
1661       return -1;
1662     return retcode;
1663   }
1664
1665   /* If we got this far, use slower implementation that is able to do a waiting select
1666      on both sockets and pipes simultaneously */
1667
1668   /* Events for pipes */
1669   if (!hEventReadReady)
1670     hEventReadReady = CreateEvent (NULL, TRUE, TRUE, NULL);
1671   if (!hEventPipeWrite)
1672     hEventPipeWrite = CreateEvent (NULL, TRUE, TRUE, NULL);
1673   readPipes = 0;
1674   writePipePos = -1;
1675
1676   retcode = 0;
1677
1678   FD_ZERO (&aread);
1679   FD_ZERO (&awrite);
1680   FD_ZERO (&aexcept);
1681 #if DEBUG_NETWORK
1682   FD_ZERO (&bread);
1683   FD_ZERO (&bwrite);
1684   FD_ZERO (&bexcept);
1685 #endif
1686   if (rfds)
1687   {
1688     FD_COPY (&rfds->sds, &aread);
1689 #if DEBUG_NETWORK
1690     FD_COPY (&rfds->sds, &bread);
1691 #endif
1692   }
1693   if (wfds)
1694   {
1695     FD_COPY (&wfds->sds, &awrite);
1696 #if DEBUG_NETWORK
1697     FD_COPY (&wfds->sds, &bwrite);
1698 #endif
1699   }
1700   if (efds)
1701   {
1702     FD_COPY (&efds->sds, &aexcept);
1703 #if DEBUG_NETWORK
1704     FD_COPY (&efds->sds, &bexcept);
1705 #endif
1706   }
1707   /* We will first Add the PIPES to the events */
1708   /* Read Pipes */
1709   if (rfds && read_handles)
1710   {
1711     struct GNUNET_CONTAINER_SList_Iterator i;
1712
1713     for (i = GNUNET_CONTAINER_slist_begin (rfds->handles);
1714          GNUNET_CONTAINER_slist_end (&i) != GNUNET_YES;
1715          GNUNET_CONTAINER_slist_next (&i))
1716     {
1717       struct GNUNET_DISK_FileHandle *fh;
1718
1719       fh = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (&i,
1720                                                                          NULL);
1721       if (fh->type == GNUNET_DISK_HANLDE_TYPE_PIPE)
1722       {
1723         /* Read zero bytes to check the status of the pipe */
1724         LOG (GNUNET_ERROR_TYPE_DEBUG, "Reading 0 bytes from the pipe 0x%x\n",
1725              fh->h);
1726         if (!ReadFile (fh->h, NULL, 0, NULL, fh->oOverlapRead))
1727         {
1728           DWORD error_code = GetLastError ();
1729
1730           if (error_code == ERROR_IO_PENDING)
1731           {
1732             LOG (GNUNET_ERROR_TYPE_DEBUG,
1733                  "Adding the pipe's 0x%x overlapped event to the array as %d\n",
1734                  fh->h, nhandles);
1735             handle_array[nhandles++] = fh->oOverlapRead->hEvent;
1736             readArray[readPipes++] = fh;
1737           }
1738           else
1739           {
1740             LOG (GNUNET_ERROR_TYPE_DEBUG,
1741                  "Read failed, adding the read ready event to the array as %d\n", nhandles);
1742             handle_array[nhandles++] = hEventReadReady;
1743             readArray[readPipes++] = fh;
1744           }
1745         }
1746         else
1747         {
1748           LOG (GNUNET_ERROR_TYPE_DEBUG,
1749                "Adding the read ready event to the array as %d\n", nhandles);
1750           handle_array[nhandles++] = hEventReadReady;
1751           readArray[readPipes++] = fh;
1752         }
1753       }
1754       else
1755       {
1756         GNUNET_CONTAINER_slist_add (handles_read,
1757                                     GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT,
1758                                     fh, sizeof (struct GNUNET_DISK_FileHandle));
1759       }
1760     }
1761   }
1762   if (wfds && write_handles)
1763   {
1764     LOG (GNUNET_ERROR_TYPE_DEBUG,
1765          "Adding the write ready event to the array as %d\n", nhandles);
1766     handle_array[nhandles++] = hEventPipeWrite;
1767     writePipePos = nhandles;
1768   }
1769   if (efds && ex_handles)
1770   {
1771     struct GNUNET_CONTAINER_SList_Iterator i;
1772
1773     for (i = GNUNET_CONTAINER_slist_begin (efds->handles);
1774          GNUNET_CONTAINER_slist_end (&i) != GNUNET_YES;
1775          GNUNET_CONTAINER_slist_next (&i))
1776     {
1777       struct GNUNET_DISK_FileHandle *fh;
1778       DWORD dwBytes;
1779
1780       fh = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (&i,
1781                                                                          NULL);
1782       if (fh->type == GNUNET_DISK_HANLDE_TYPE_PIPE)
1783       {
1784         if (!PeekNamedPipe (fh->h, NULL, 0, NULL, &dwBytes, NULL))
1785         {
1786           GNUNET_CONTAINER_slist_add (handles_except,
1787                                       GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT,
1788                                       fh,
1789                                       sizeof (struct GNUNET_DISK_FileHandle));
1790         }
1791       }
1792     }
1793   }
1794
1795   sp.status = 0;
1796
1797   if (nfds > 0)
1798   {
1799     LOG (GNUNET_ERROR_TYPE_DEBUG,
1800          "Adding the socket event to the array as %d\n",
1801          nhandles);
1802     handle_array[nhandles++] = select_finished_event;
1803     if (timeout.rel_value_us == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
1804       sp.tv = NULL;
1805     else
1806     {
1807       select_timeout.tv_sec = timeout.rel_value_us / GNUNET_TIME_UNIT_SECONDS.rel_value_us;
1808       select_timeout.tv_usec =(timeout.rel_value_us -
1809           (select_timeout.tv_sec * GNUNET_TIME_UNIT_SECONDS.rel_value_us));
1810       sp.tv = &select_timeout;
1811     }
1812     FD_SET (select_wakeup_socket, &aread);
1813     do
1814     {
1815       i = recv (select_wakeup_socket, (char *) &returnedpos, 1, 0);
1816     } while (i == 1);
1817     sp.r = &aread;
1818     sp.w = &awrite;
1819     sp.e = &aexcept;
1820     /* Failed connections cause sockets to be set in errorfds on W32,
1821      * but on POSIX it should set them in writefds.
1822      * First copy all awrite sockets to aexcept, later we'll
1823      * check aexcept and set its contents in awrite as well
1824      * Sockets are also set in errorfds when OOB data is available,
1825      * but we don't use OOB data.
1826      */
1827     for (i = 0; i < awrite.fd_count; i++)
1828       FD_SET (awrite.fd_array[i], &aexcept);
1829     ResetEvent (select_finished_event);
1830     SetEvent (select_standby_event);
1831   }
1832
1833   handle_array[nhandles] = NULL;
1834   LOG (GNUNET_ERROR_TYPE_DEBUG, "nfds: %d, handles: %d, will wait: %llu mcs\n",
1835        nfds, nhandles, mcs_total);
1836   if (nhandles)
1837   {
1838     returncode =
1839         WaitForMultipleObjects (nhandles, handle_array, FALSE, ms_rounded);
1840     LOG (GNUNET_ERROR_TYPE_DEBUG, "WaitForMultipleObjects Returned : %d\n", returncode);
1841   }
1842   else if (nfds > 0)
1843   {
1844     GNUNET_break (0); /* This branch shouldn't actually be executed...*/
1845     i = (int) WaitForSingleObject (select_finished_event, INFINITE);
1846     returncode = WAIT_TIMEOUT;
1847   }
1848   else
1849   {
1850     /* Shouldn't come this far. If it does - investigate. */
1851     GNUNET_assert (0);
1852   }
1853
1854   if (nfds > 0)
1855   {
1856     /* Don't wake up select-thread when delay is 0, it should return immediately
1857      * and wake up by itself.
1858      */
1859     if (mcs_total != 0)
1860       i = send (select_send_socket, (const char *) &returnedpos, 1, 0);
1861     i = (int) WaitForSingleObject (select_finished_event, INFINITE);
1862     LOG (GNUNET_ERROR_TYPE_DEBUG, "Finished waiting for the select thread: %d %d\n", i, sp.status);
1863     if (mcs_total != 0)
1864     {
1865       do
1866       {
1867         i = recv (select_wakeup_socket, (char *) &returnedpos, 1, 0);
1868       } while (i == 1);
1869     }
1870     /* Check aexcept, add its contents to awrite */
1871     for (i = 0; i < aexcept.fd_count; i++)
1872       FD_SET (aexcept.fd_array[i], &awrite);
1873   }
1874
1875   returnedpos = returncode - WAIT_OBJECT_0;
1876   LOG (GNUNET_ERROR_TYPE_DEBUG, "return pos is : %d\n", returnedpos);
1877
1878   if (nhandles && (returnedpos < nhandles))
1879   {
1880     DWORD waitstatus;
1881
1882     if (sp.status > 0)
1883       retcode += sp.status;
1884
1885     if ((writePipePos != -1) && (returnedpos < writePipePos))
1886     {
1887       GNUNET_CONTAINER_slist_append (handles_write, wfds->handles);
1888       retcode += write_handles;
1889       LOG (GNUNET_ERROR_TYPE_DEBUG, "Added write pipe\n");
1890     }
1891     LOG (GNUNET_ERROR_TYPE_DEBUG, "ReadPipes is : %d\n", readPipes);
1892     /* We have some pipes ready for read. */
1893     if (returnedpos < readPipes)
1894     {
1895       for (i = 0; i < readPipes; i++)
1896       {
1897         DWORD error;
1898         BOOL bret;
1899
1900         SetLastError (0);
1901         waitstatus = 0;
1902         bret =
1903             PeekNamedPipe (readArray[i]->h, NULL, 0, NULL, &waitstatus, NULL);
1904         error = GetLastError ();
1905         LOG (GNUNET_ERROR_TYPE_DEBUG,
1906              "Peek at read pipe %d (0x%x) returned %d (%d bytes available) GLE %u\n",
1907              i, readArray[i]->h, bret, waitstatus, error);
1908         if (bret == 0)
1909         {
1910           /* TODO: either add more errors to this condition, or eliminate it
1911            * entirely (failed to peek -> pipe is in serious trouble, should
1912            * be selected as readable).
1913            */
1914           if (error != ERROR_BROKEN_PIPE && error != ERROR_INVALID_HANDLE)
1915             continue;
1916         }
1917         else if (waitstatus <= 0)
1918           continue;
1919         GNUNET_CONTAINER_slist_add (handles_read,
1920                                     GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT,
1921                                     readArray[i],
1922                                     sizeof (struct GNUNET_DISK_FileHandle));
1923         retcode++;
1924         LOG (GNUNET_ERROR_TYPE_DEBUG, "Added read Pipe 0x%x (0x%x)\n",
1925              readArray[i], readArray[i]->h);
1926       }
1927     }
1928   }
1929   if (!nhandles || (returnedpos >= nhandles))
1930     LOG (GNUNET_ERROR_TYPE_DEBUG, "Returning from _select() with nothing!\n");
1931   if (rfds)
1932   {
1933     struct GNUNET_CONTAINER_SList_Iterator t;
1934
1935     for (t = GNUNET_CONTAINER_slist_begin (rfds->handles);
1936          GNUNET_CONTAINER_slist_end (&t) != GNUNET_YES;
1937          GNUNET_CONTAINER_slist_next (&t))
1938     {
1939       struct GNUNET_DISK_FileHandle *fh;
1940
1941       fh = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (&t,
1942                                                                          NULL);
1943       if (fh->type == GNUNET_DISK_HANLDE_TYPE_PIPE)
1944       {
1945         CancelIo (fh->h);
1946       }
1947     }
1948     LOG (GNUNET_ERROR_TYPE_DEBUG, "Zeroing rfds%s\n", (retcode != -1 && nhandles && (returnedpos < nhandles)) ? ", copying fdset" : "");
1949     GNUNET_NETWORK_fdset_zero (rfds);
1950     if (retcode != -1 && nhandles && (returnedpos < nhandles))
1951       GNUNET_NETWORK_fdset_copy_native (rfds, &aread, retcode);
1952     GNUNET_CONTAINER_slist_append (rfds->handles, handles_read);
1953   }
1954   if (wfds)
1955   {
1956     LOG (GNUNET_ERROR_TYPE_DEBUG, "Zeroing wfds%s\n", (retcode != -1 && nhandles && (returnedpos < nhandles)) ? ", copying fdset" : "");
1957     GNUNET_NETWORK_fdset_zero (wfds);
1958     if (retcode != -1 && nhandles && (returnedpos < nhandles))
1959       GNUNET_NETWORK_fdset_copy_native (wfds, &awrite, retcode);
1960     GNUNET_CONTAINER_slist_append (wfds->handles, handles_write);
1961   }
1962   if (efds)
1963   {
1964     LOG (GNUNET_ERROR_TYPE_DEBUG, "Zeroing efds%s\n", (retcode != -1 && nhandles && (returnedpos < nhandles)) ? ", copying fdset" : "");
1965     GNUNET_NETWORK_fdset_zero (efds);
1966     if (retcode != -1 && nhandles && (returnedpos < nhandles))
1967       GNUNET_NETWORK_fdset_copy_native (efds, &aexcept, retcode);
1968     GNUNET_CONTAINER_slist_append (efds->handles, handles_except);
1969   }
1970   GNUNET_CONTAINER_slist_destroy (handles_read);
1971   GNUNET_CONTAINER_slist_destroy (handles_write);
1972   GNUNET_CONTAINER_slist_destroy (handles_except);
1973 #if DEBUG_NETWORK
1974   if (rfds)
1975   {
1976     struct GNUNET_CONTAINER_SList_Iterator t;
1977
1978     LOG (GNUNET_ERROR_TYPE_DEBUG, "rfds:\n");
1979     for (i = 0; i < rfds->sds.fd_count; i++)
1980     {
1981       LOG (GNUNET_ERROR_TYPE_DEBUG, "%d\n", rfds->sds.fd_array[i]);
1982     }
1983     for (t = GNUNET_CONTAINER_slist_begin (rfds->handles);
1984          GNUNET_CONTAINER_slist_end (&t) != GNUNET_YES;
1985          GNUNET_CONTAINER_slist_next (&t))
1986     {
1987       struct GNUNET_DISK_FileHandle *fh;
1988
1989       fh = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (&t,
1990                                                                          NULL);
1991       LOG (GNUNET_ERROR_TYPE_DEBUG, "%d\n", fh->h);
1992     }
1993   }
1994   if (wfds)
1995   {
1996     LOG (GNUNET_ERROR_TYPE_DEBUG, "wfds:\n");
1997     for (i = 0; i < wfds->sds.fd_count; i++)
1998     {
1999       LOG (GNUNET_ERROR_TYPE_DEBUG, "%d\n", wfds->sds.fd_array[i]);
2000     }
2001   }
2002   if (efds)
2003   {
2004     LOG (GNUNET_ERROR_TYPE_DEBUG, "efds:\n");
2005     for (i = 0; i < efds->sds.fd_count; i++)
2006     {
2007       LOG (GNUNET_ERROR_TYPE_DEBUG, "%d\n", efds->sds.fd_array[i]);
2008     }
2009   }
2010   LOG (GNUNET_ERROR_TYPE_DEBUG, "Returning %d or 0\n", retcode);
2011 #endif
2012   if (nhandles && (returnedpos < nhandles))
2013     return retcode;
2014   else
2015 #endif
2016     return 0;
2017 }
2018
2019 /* end of network.c */