d889fa94bde1cb022464cd8ef9a1ad3a986d409f
[oweals/gnunet.git] / src / util / network.c
1 /*
2      This file is part of GNUnet.
3      (C) 2009 Christian Grothoff (and other contributing authors)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 2, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20
21 /**
22  * @file util/network.c
23  * @brief basic, low-level networking interface
24  * @author Nils Durner
25  */
26
27 #include "platform.h"
28 #include "gnunet_disk_lib.h"
29 #include "disk.h"
30 #include "gnunet_container_lib.h"
31
32 #define DEBUG_NETWORK GNUNET_NO
33
34 #ifndef INVALID_SOCKET
35 #define INVALID_SOCKET -1
36 #endif
37
38
39 struct GNUNET_NETWORK_Handle
40 {
41   int fd;
42 };
43
44
45 struct GNUNET_NETWORK_FDSet
46 {
47
48   /**
49    * Maximum number of any socket socket descriptor in the set
50    */
51   int nsds;
52
53   /**
54    * Bitset with the descriptors.
55    */
56   fd_set sds;
57
58 #ifdef WINDOWS
59   /**
60    * Linked list of handles 
61    */
62   struct GNUNET_CONTAINER_SList *handles;
63 #endif
64
65 };
66
67 #ifndef FD_COPY
68 #define FD_COPY(s, d) (memcpy ((d), (s), sizeof (fd_set)))
69 #endif
70
71
72 /**
73  * Set if a socket should use blocking or non-blocking IO.
74  * @param fd socket
75  * @param doBlock blocking mode
76  * @return GNUNET_OK on success, GNUNET_SYSERR on error
77  */
78 static int
79 socket_set_blocking (struct GNUNET_NETWORK_Handle *fd, int doBlock)
80 {
81
82 #if MINGW
83   u_long mode;
84   mode = !doBlock;
85   if (ioctlsocket (fd->fd, FIONBIO, &mode) == SOCKET_ERROR)
86
87     {
88       SetErrnoFromWinsockError (WSAGetLastError ());
89       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "ioctlsocket");
90       return GNUNET_SYSERR;
91     }
92   return GNUNET_OK;
93
94 #else
95   /* not MINGW */
96   int flags = fcntl (fd->fd, F_GETFL);
97   if (flags == -1)
98
99     {
100       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "fcntl");
101       return GNUNET_SYSERR;
102     }
103   if (doBlock)
104     flags &= ~O_NONBLOCK;
105
106   else
107     flags |= O_NONBLOCK;
108   if (0 != fcntl (fd->fd, F_SETFL, flags))
109
110     {
111       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "fcntl");
112       return GNUNET_SYSERR;
113     }
114   return GNUNET_OK;
115 #endif
116 }
117
118
119 #ifndef MINGW
120 /**
121  * Make a socket non-inheritable to child processes
122  *
123  * @param h the socket to make non-inheritable
124  * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
125  * @warning Not implemented on Windows
126  */
127 static int
128 socket_set_inheritable (const struct GNUNET_NETWORK_Handle *h)
129 {
130   int i;
131   i = fcntl (h->fd, F_GETFD);
132   if (i == (i | FD_CLOEXEC))
133     return GNUNET_OK;
134   return (fcntl (h->fd, F_SETFD, i | FD_CLOEXEC) == 0)
135     ? GNUNET_OK : GNUNET_SYSERR;
136 }
137 #endif
138
139
140 #ifdef DARWIN
141 /**
142  * The MSG_NOSIGNAL equivalent on Mac OS X
143  *
144  * @param h the socket to make non-delaying
145  */
146 static void
147 socket_set_nosigpipe (const struct GNUNET_NETWORK_Handle *h)
148 {
149   int value = 1;
150   if (0 !=
151       setsockopt (h->fd, SOL_SOCKET, SO_NOSIGPIPE, &value, sizeof (value)))
152     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "setsockopt");
153 }
154 #endif
155
156
157 /**
158  * Disable delays when sending data via the socket.
159  * (GNUnet makes sure that messages are as big as
160  * possible already).
161  *
162  * @param h the socket to make non-delaying
163  */
164 static void
165 socket_set_nodelay (const struct GNUNET_NETWORK_Handle *h)
166 {
167   int value = 1;
168   if (0 !=
169       setsockopt (h->fd, IPPROTO_TCP, TCP_NODELAY, &value, sizeof (value)))
170     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "setsockopt");
171 }
172
173
174 /**
175  * accept a new connection on a socket
176  *
177  * @param desc bound socket
178  * @param address address of the connecting peer, may be NULL
179  * @param address_len length of address
180  * @return client socket
181  */
182 struct GNUNET_NETWORK_Handle *
183 GNUNET_NETWORK_socket_accept (const struct GNUNET_NETWORK_Handle *desc,
184                               struct sockaddr *address,
185                               socklen_t * address_len)
186 {
187   struct GNUNET_NETWORK_Handle *ret;
188   ret = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle));
189   ret->fd = accept (desc->fd, address, address_len);
190   if (ret->fd == INVALID_SOCKET)
191     {
192 #ifdef MINGW
193       SetErrnoFromWinsockError (WSAGetLastError ());
194 #endif
195       GNUNET_free (ret);
196       return NULL;
197     }
198 #ifndef MINGW
199   if (ret->fd >= FD_SETSIZE)
200     {
201       GNUNET_break (0 == close (ret->fd));
202       GNUNET_free (ret);
203       errno = EMFILE;
204       return NULL;
205     }
206 #endif
207   if (GNUNET_SYSERR == socket_set_blocking (ret, GNUNET_NO))
208
209     {
210
211       /* we might want to treat this one as fatal... */
212       GNUNET_break (0);
213       GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (ret));
214       return NULL;
215     }
216
217 #ifndef MINGW
218   if (GNUNET_OK != socket_set_inheritable (ret))
219     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
220                          "socket_set_inheritable");
221 #endif
222 #ifdef DARWIN
223   socket_set_nosigpipe (ret);
224 #endif
225   socket_set_nodelay (ret);
226   return ret;
227 }
228
229
230 /**
231  * Bind to a connected socket
232  * @param desc socket
233  * @param address address to be bound
234  * @param address_len length of address
235  * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
236  */
237 int
238 GNUNET_NETWORK_socket_bind (struct GNUNET_NETWORK_Handle *desc,
239                             const struct sockaddr *address,
240                             socklen_t address_len)
241 {
242   int ret;
243
244   ret = bind (desc->fd, address, address_len);
245 #ifdef MINGW
246   if (SOCKET_ERROR == ret)
247     SetErrnoFromWinsockError (WSAGetLastError ());
248 #endif
249   return ret == 0 ? GNUNET_OK : GNUNET_SYSERR;
250 }
251
252
253 /**
254  * Close a socket
255  * @param desc socket
256  * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
257  */
258 int
259 GNUNET_NETWORK_socket_close (struct GNUNET_NETWORK_Handle *desc)
260 {
261   int ret;
262   int eno;
263
264 #ifdef MINGW
265   ret = closesocket (desc->fd);
266   SetErrnoFromWinsockError (WSAGetLastError ());
267 #else
268   ret = close (desc->fd);
269 #endif
270   eno = errno;
271   GNUNET_free (desc);
272   errno = eno;
273   return (ret == 0) ? GNUNET_OK : GNUNET_SYSERR;
274 }
275
276
277 /**
278  * Connect a socket
279  * @param desc socket
280  * @param address peer address
281  * @param address_len length of address
282  * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
283  */
284 int
285 GNUNET_NETWORK_socket_connect (const struct GNUNET_NETWORK_Handle *desc,
286                                const struct sockaddr *address,
287                                socklen_t address_len)
288 {
289   int ret;
290   ret = connect (desc->fd, address, address_len);
291
292 #ifdef MINGW
293   if (SOCKET_ERROR == ret)
294
295     {
296       SetErrnoFromWinsockError (WSAGetLastError ());
297       if (errno == EWOULDBLOCK)
298         errno = EINPROGRESS;
299     }
300 #endif
301   return ret == 0 ? GNUNET_OK : GNUNET_SYSERR;
302 }
303
304
305 /**
306  * Get socket options
307  *
308  * @param desc socket
309  * @param level protocol level of the option
310  * @param optname identifier of the option
311  * @param optval options
312  * @param optlen length of optval
313  * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
314  */
315 int
316 GNUNET_NETWORK_socket_getsockopt (const struct GNUNET_NETWORK_Handle *desc,
317                                   int level, int optname, void *optval,
318                                   socklen_t * optlen)
319 {
320   int ret;
321   ret = getsockopt (desc->fd, level, optname, optval, optlen);
322
323 #ifdef MINGW
324   if (ret == 0 && level == SOL_SOCKET && optname == SO_ERROR)
325     *((int *) optval) = GetErrnoFromWinsockError (*((int *) optval));
326
327   else if (SOCKET_ERROR == ret)
328     SetErrnoFromWinsockError (WSAGetLastError ());
329
330 #endif
331   return ret == 0 ? GNUNET_OK : GNUNET_SYSERR;
332 }
333
334
335 /**
336  * Listen on a socket
337  * @param desc socket
338  * @param backlog length of the listen queue
339  * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
340  */
341 int
342 GNUNET_NETWORK_socket_listen (const struct GNUNET_NETWORK_Handle *desc,
343                               int backlog)
344 {
345   int ret;
346   ret = listen (desc->fd, backlog);
347
348 #ifdef MINGW
349   if (SOCKET_ERROR == ret)
350     SetErrnoFromWinsockError (WSAGetLastError ());
351
352 #endif
353   return ret == 0 ? GNUNET_OK : GNUNET_SYSERR;
354 }
355
356
357 /**
358  * Read data from a connected socket (always non-blocking).
359  * @param desc socket
360  * @param buffer buffer
361  * @param length length of buffer
362  */
363 ssize_t
364 GNUNET_NETWORK_socket_recv (const struct GNUNET_NETWORK_Handle * desc,
365                             void *buffer, size_t length)
366 {
367   int ret;
368   int flags;
369   flags = 0;
370
371 #ifdef MSG_DONTWAIT
372   flags |= MSG_DONTWAIT;
373
374 #endif /*  */
375   ret = recv (desc->fd, buffer, length, flags);
376
377 #ifdef MINGW
378   if (SOCKET_ERROR == ret)
379     SetErrnoFromWinsockError (WSAGetLastError ());
380
381 #endif /*  */
382   return ret;
383 }
384
385
386 /**
387  * Send data (always non-blocking).
388  *
389  * @param desc socket
390  * @param buffer data to send
391  * @param length size of the buffer
392  * @return number of bytes sent, GNUNET_SYSERR on error
393  */
394 ssize_t
395 GNUNET_NETWORK_socket_send (const struct GNUNET_NETWORK_Handle * desc,
396                             const void *buffer, size_t length)
397 {
398   int ret;
399   int flags;
400   flags = 0;
401
402 #ifdef MSG_DONTWAIT
403   flags |= MSG_DONTWAIT;
404
405 #endif /*  */
406 #ifdef MSG_NOSIGNAL
407   flags |= MSG_NOSIGNAL;
408
409 #endif /*  */
410   ret = send (desc->fd, buffer, length, flags);
411
412 #ifdef MINGW
413   if (SOCKET_ERROR == ret)
414     SetErrnoFromWinsockError (WSAGetLastError ());
415
416 #endif /*  */
417   return ret;
418 }
419
420
421 /**
422  * Send data to a particular destination (always non-blocking).
423  * This function only works for UDP sockets.
424  *
425  * @param desc socket
426  * @param message data to send
427  * @param length size of the data
428  * @param dest_addr destination address
429  * @param dest_len length of address
430  * @return number of bytes sent, GNUNET_SYSERR on error
431  */
432 ssize_t
433 GNUNET_NETWORK_socket_sendto (const struct GNUNET_NETWORK_Handle * desc,
434                               const void *message, size_t length,
435                               const struct sockaddr * dest_addr,
436                               socklen_t dest_len)
437 {
438   int ret;
439   int flags;
440   flags = 0;
441
442 #ifdef MSG_DONTWAIT
443   flags |= MSG_DONTWAIT;
444 #endif
445 #ifdef MSG_NOSIGNAL
446   flags |= MSG_NOSIGNAL;
447 #endif
448   ret = sendto (desc->fd, message, length, flags, dest_addr, dest_len);
449 #ifdef MINGW
450   if (SOCKET_ERROR == ret)
451     SetErrnoFromWinsockError (WSAGetLastError ());
452 #endif
453   return ret;
454 }
455
456
457 /**
458  * Set socket option
459  * @param fd socket
460  * @param level protocol level of the option
461  * @param option_name option identifier
462  * @param option_value value to set
463  * @param option_len size of option_value
464  * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
465  */
466 int
467 GNUNET_NETWORK_socket_setsockopt (struct GNUNET_NETWORK_Handle *fd,
468                                   int level, int option_name,
469                                   const void *option_value,
470                                   socklen_t option_len)
471 {
472   int ret;
473
474   ret = setsockopt (fd->fd, level, option_name, option_value, option_len);
475 #ifdef MINGW
476   if (SOCKET_ERROR == ret)
477     SetErrnoFromWinsockError (WSAGetLastError ());
478 #endif
479   return ret == 0 ? GNUNET_OK : GNUNET_SYSERR;
480 }
481
482
483 /**
484  * Create a new socket.  Configure it for non-blocking IO and
485  * mark it as non-inheritable to child processes (set the
486  * close-on-exec flag).
487  *
488  * @param domain domain of the socket
489  * @param type socket type
490  * @param protocol network protocol
491  * @return new socket, NULL on error
492  */
493 struct GNUNET_NETWORK_Handle *
494 GNUNET_NETWORK_socket_create (int domain, int type, int protocol)
495 {
496   struct GNUNET_NETWORK_Handle *ret;
497   ret = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle));
498   ret->fd = socket (domain, type, protocol);
499   if (INVALID_SOCKET == ret->fd)
500     {
501 #ifdef MINGW
502       SetErrnoFromWinsockError (WSAGetLastError ());
503 #endif
504       GNUNET_free (ret);
505       return NULL;
506     }
507
508 #ifndef MINGW
509   if (ret->fd >= FD_SETSIZE)
510     {
511       GNUNET_break (0 == close (ret->fd));
512       GNUNET_free (ret);
513       errno = EMFILE;
514       return NULL;
515     }
516
517 #endif
518   if (GNUNET_SYSERR == socket_set_blocking (ret, GNUNET_NO))
519     {
520       /* we might want to treat this one as fatal... */
521       GNUNET_break (0);
522       GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (ret));
523       return NULL;
524     }
525
526 #ifndef MINGW
527   if (GNUNET_OK != socket_set_inheritable (ret))
528     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
529                          "socket_set_inheritable");
530 #endif
531 #ifdef DARWIN
532   socket_set_nosigpipe (ret);
533 #endif
534   if (type == SOCK_STREAM)
535     socket_set_nodelay (ret);
536   return ret;
537 }
538
539
540 /**
541  * Shut down socket operations
542  * @param desc socket
543  * @param how type of shutdown
544  * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
545  */
546 int
547 GNUNET_NETWORK_socket_shutdown (struct GNUNET_NETWORK_Handle *desc, int how)
548 {
549   int ret;
550
551   ret = shutdown (desc->fd, how);
552 #ifdef MINGW
553   if (ret != 0)
554     SetErrnoFromWinsockError (WSAGetLastError ());
555 #endif
556   return ret == 0 ? GNUNET_OK : GNUNET_SYSERR;
557 }
558
559
560 /**
561  * Reset FD set
562  * @param fds fd set
563  */
564 void
565 GNUNET_NETWORK_fdset_zero (struct GNUNET_NETWORK_FDSet *fds)
566 {
567   FD_ZERO (&fds->sds);
568   fds->nsds = 0;
569 #ifdef MINGW
570   GNUNET_CONTAINER_slist_clear (fds->handles);
571 #endif
572 }
573
574 /**
575  * Add a socket to the FD set
576  * @param fds fd set
577  * @param desc socket to add
578  */
579 void
580 GNUNET_NETWORK_fdset_set (struct GNUNET_NETWORK_FDSet *fds,
581                           const struct GNUNET_NETWORK_Handle *desc)
582 {
583   FD_SET (desc->fd, &fds->sds);
584   if (desc->fd + 1 > fds->nsds)
585     fds->nsds = desc->fd + 1;
586 }
587
588
589 /**
590  * Check whether a socket is part of the fd set
591  * @param fds fd set
592  * @param desc socket
593  * @return 0 if the FD is not set
594  */
595 int
596 GNUNET_NETWORK_fdset_isset (const struct GNUNET_NETWORK_FDSet *fds,
597                             const struct GNUNET_NETWORK_Handle *desc)
598 {
599   return FD_ISSET (desc->fd, &fds->sds);
600 }
601
602
603 /**
604  * Add one fd set to another
605  * @param dst the fd set to add to
606  * @param src the fd set to add from
607  */
608 void
609 GNUNET_NETWORK_fdset_add (struct GNUNET_NETWORK_FDSet *dst,
610                           const struct GNUNET_NETWORK_FDSet *src)
611 {
612   int nfds;
613   for (nfds = src->nsds; nfds > 0; nfds--)
614     if (FD_ISSET (nfds, &src->sds))
615
616       {
617         FD_SET (nfds, &dst->sds);
618         if (nfds + 1 > dst->nsds)
619           dst->nsds = nfds + 1;
620       }
621 #ifdef MINGW
622   GNUNET_CONTAINER_slist_append (dst->handles, src->handles);
623 #endif
624 }
625
626
627 /**
628  * Copy one fd set to another
629  *
630  * @param to destination
631  * @param from source
632  */
633 void
634 GNUNET_NETWORK_fdset_copy (struct GNUNET_NETWORK_FDSet *to,
635                            const struct GNUNET_NETWORK_FDSet *from)
636 {
637   FD_COPY (&from->sds, &to->sds);
638   to->nsds = from->nsds;
639
640 #ifdef MINGW
641   GNUNET_CONTAINER_slist_clear (to->handles);
642   GNUNET_CONTAINER_slist_append (to->handles, from->handles);
643 #endif
644 }
645
646 /**
647  * Copy a native fd set
648  *
649  * @param to destination
650  * @param from native source set
651  * @param nfds the biggest socket number in from + 1
652  */
653 void
654 GNUNET_NETWORK_fdset_copy_native (struct GNUNET_NETWORK_FDSet *to,
655                                   const fd_set * from, int nfds)
656 {
657   FD_COPY (from, &to->sds);
658   to->nsds = nfds;
659 }
660
661 /**
662  * Add a file handle to the fd set
663  * @param fds fd set
664  * @param h the file handle to add
665  */
666 void
667 GNUNET_NETWORK_fdset_handle_set (struct GNUNET_NETWORK_FDSet *fds,
668                                  const struct GNUNET_DISK_FileHandle *h)
669 {
670
671 #ifdef MINGW
672   HANDLE hw;
673   GNUNET_DISK_internal_file_handle_ (h, &hw, sizeof (HANDLE));
674   GNUNET_CONTAINER_slist_add (fds->handles, GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT, &hw, sizeof (HANDLE));
675
676 #else
677   int fd;
678   GNUNET_DISK_internal_file_handle_ (h, &fd, sizeof (int));
679   FD_SET (fd, &fds->sds);
680   if (fd + 1 > fds->nsds)
681     fds->nsds = fd + 1;
682
683 #endif
684 }
685
686
687 /**
688  * Check if a file handle is part of an fd set
689  * @param fds fd set
690  * @param h file handle
691  * @return GNUNET_YES if the file handle is part of the set
692  */
693 int
694 GNUNET_NETWORK_fdset_handle_isset (const struct GNUNET_NETWORK_FDSet *fds,
695                                    const struct GNUNET_DISK_FileHandle *h)
696 {
697
698 #ifdef MINGW
699   return GNUNET_CONTAINER_slist_contains (fds->handles, &h->h,
700                                           sizeof (HANDLE));
701 #else
702   return FD_ISSET (h->fd, &fds->sds);
703 #endif
704 }
705
706
707 /**
708  * Checks if two fd sets overlap
709  * @param fds1 first fd set
710  * @param fds2 second fd set
711  * @return GNUNET_YES if they do overlap, GNUNET_NO otherwise
712  */
713 int
714 GNUNET_NETWORK_fdset_overlap (const struct GNUNET_NETWORK_FDSet *fds1,
715                               const struct GNUNET_NETWORK_FDSet *fds2)
716 {
717   int nfds;
718   nfds = fds1->nsds;
719   if (nfds < fds2->nsds)
720     nfds = fds2->nsds;
721   for (; nfds >= 0; nfds--)
722     if (FD_ISSET (nfds, &fds1->sds) && FD_ISSET (nfds, &fds2->sds))
723       return GNUNET_YES;
724 #ifdef MINGW
725   {
726       struct GNUNET_CONTAINER_SList_Iterator *it;
727
728       for(it = GNUNET_CONTAINER_slist_begin (fds1->handles); GNUNET_CONTAINER_slist_end (it) != GNUNET_YES; GNUNET_CONTAINER_slist_next (it))
729         {
730           HANDLE *h;
731
732           h = GNUNET_CONTAINER_slist_get (it, NULL);
733           if (GNUNET_CONTAINER_slist_contains (fds2->handles, h, sizeof (HANDLE)))
734             {
735               GNUNET_CONTAINER_slist_iter_destroy (it);
736               return GNUNET_YES;
737             }
738         }
739       GNUNET_CONTAINER_slist_iter_destroy (it);
740   }
741 #endif
742   return GNUNET_NO;
743 }
744
745
746 /**
747  * Creates an fd set
748  * @return a new fd set
749  */
750 struct GNUNET_NETWORK_FDSet *
751 GNUNET_NETWORK_fdset_create ()
752 {
753   struct GNUNET_NETWORK_FDSet *fds;
754   fds = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_FDSet));
755 #ifdef MINGW
756   fds->handles = GNUNET_CONTAINER_slist_create ();
757 #endif
758   GNUNET_NETWORK_fdset_zero (fds);
759   return fds;
760 }
761
762
763 /**
764  * Releases the associated memory of an fd set
765  * @param fds fd set
766  */
767 void
768 GNUNET_NETWORK_fdset_destroy (struct GNUNET_NETWORK_FDSet *fds)
769 {
770 #ifdef MINGW
771   GNUNET_CONTAINER_slist_destroy (fds->handles);
772 #endif
773   GNUNET_free (fds);
774 }
775
776 /**
777  * Check if sockets meet certain conditions
778  * @param rfds set of sockets to be checked for readability
779  * @param wfds set of sockets to be checked for writability
780  * @param efds set of sockets to be checked for exceptions
781  * @param timeout relative value when to return
782  * @return number of selected sockets, GNUNET_SYSERR on error
783  */
784 int
785 GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds,
786                               struct GNUNET_NETWORK_FDSet *wfds,
787                               struct GNUNET_NETWORK_FDSet *efds,
788                               const struct GNUNET_TIME_Relative timeout)
789 {
790   int nfds;
791 #ifdef MINGW
792   int handles;
793 #endif
794   nfds = 0;
795 #ifdef MINGW
796   handles = 0;
797 #endif
798   if (NULL != rfds)
799     {
800       nfds = rfds->nsds;
801 #ifdef MINGW
802       handles = GNUNET_CONTAINER_slist_count (rfds->handles);
803 #endif
804     }
805   if (NULL != wfds)
806     {
807       nfds = GNUNET_MAX (nfds, wfds->nsds);
808 #ifdef MINGW
809       handles += GNUNET_CONTAINER_slist_count (wfds->handles);
810 #endif
811     }
812   if (NULL != efds)
813     {
814       nfds = GNUNET_MAX (nfds, efds->nsds);
815 #ifdef MINGW
816       handles += GNUNET_CONTAINER_slist_count (efds->handles);
817 #endif
818     }
819
820   struct timeval tv;
821   tv.tv_sec = timeout.value / GNUNET_TIME_UNIT_SECONDS.value;
822   tv.tv_usec =
823     1000 * (timeout.value - (tv.tv_sec * GNUNET_TIME_UNIT_SECONDS.value));
824   if ((nfds == 0) && (timeout.value == GNUNET_TIME_UNIT_FOREVER_REL.value)
825 #ifdef MINGW
826       && handles == 0
827 #endif
828     )
829     {
830       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
831                   _
832                   ("Fatal internal logic error, process hangs in `%s' (abort with CTRL-C)!\n"),
833                   "select");
834       GNUNET_break (0);
835     }
836 #ifndef MINGW
837   return select (nfds + 1,
838                  (rfds != NULL) ? &rfds->sds : NULL,
839                  (wfds != NULL) ? &wfds->sds : NULL,
840                  (efds != NULL) ? &efds->sds : NULL,
841                  (timeout.value == GNUNET_TIME_UNIT_FOREVER_REL.value)
842                  ? NULL : &tv);
843
844 #else
845   DWORD limit;
846   fd_set sock_read, sock_write, sock_except;
847   fd_set aread, awrite, aexcept;
848   struct GNUNET_CONTAINER_SList *handles_read, *handles_write, *handles_except;
849
850   int i;
851   struct timeval tvslice;
852   int retcode;
853   DWORD ms_total;
854
855 #define SAFE_FD_ISSET(fd, set)  (set != NULL && FD_ISSET(fd, set))
856
857   /* calculate how long we need to wait in milliseconds */
858   if (timeout.value == GNUNET_TIME_UNIT_FOREVER_REL.value)
859     ms_total = INFINITE;
860
861   else
862     ms_total = timeout.value / GNUNET_TIME_UNIT_MILLISECONDS.value;
863
864   /* select() may be used as a portable way to sleep */
865   if (!(rfds || wfds || efds))
866
867     {
868       Sleep (ms_total);
869       return 0;
870     }
871
872   handles_read = GNUNET_CONTAINER_slist_create ();
873   handles_write = GNUNET_CONTAINER_slist_create ();
874   handles_except = GNUNET_CONTAINER_slist_create ();
875
876   if (rfds)
877     sock_read = rfds->sds;
878   else
879     FD_ZERO (&sock_read);
880   if (wfds)
881     sock_write = wfds->sds;
882   else
883     FD_ZERO (&sock_write);
884   if (efds)
885     sock_except = efds->sds;
886   else
887     FD_ZERO (&sock_except);
888
889   /* multiplex between winsock select() and waiting on the handles */
890   FD_ZERO (&aread);
891   FD_ZERO (&awrite);
892   FD_ZERO (&aexcept);
893   limit = GetTickCount () + ms_total;
894
895   do
896     {
897       retcode = 0;
898       if (nfds > 0)
899
900         {
901
902           /* overwrite the zero'd sets here; the select call
903            * will clear those that are not active */
904           FD_COPY (&sock_read, &aread);
905           FD_COPY (&sock_write, &awrite);
906           FD_COPY (&sock_except, &aexcept);
907           tvslice.tv_sec = 0;
908           tvslice.tv_usec = 100000;
909           if ((retcode =
910                select (nfds + 1, &aread, &awrite, &aexcept,
911                        &tvslice)) == SOCKET_ERROR)
912
913             {
914               SetErrnoFromWinsockError (WSAGetLastError ());
915               if (errno == ENOTSOCK)
916                 errno = EBADF;
917
918 #if DEBUG_NETWORK
919               GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "select");
920
921 #endif
922               goto select_loop_end;
923             }
924         }
925
926       /* Poll read pipes */
927       if (rfds)
928
929         {
930           struct GNUNET_CONTAINER_SList_Iterator *i;
931           for (i = GNUNET_CONTAINER_slist_begin (rfds->handles);
932                GNUNET_CONTAINER_slist_end (i) != GNUNET_YES;
933                GNUNET_CONTAINER_slist_next (i))
934
935             {
936               HANDLE h;
937               DWORD dwBytes;
938               h = *(HANDLE *) GNUNET_CONTAINER_slist_get (i, NULL);
939               if (!PeekNamedPipe (h, NULL, 0, NULL, &dwBytes, NULL))
940                 {
941                   retcode = -1;
942                   SetErrnoFromWinError (GetLastError ());
943
944 #if DEBUG_NETWORK
945                   GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
946                                        "PeekNamedPipe");
947
948 #endif
949                   goto select_loop_end;
950                 }
951               else if (dwBytes)
952
953                 {
954                   GNUNET_CONTAINER_slist_add (handles_read,
955                       GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT, &h,
956                       sizeof (HANDLE));
957                   retcode++;
958                 }
959             }
960           GNUNET_CONTAINER_slist_iter_destroy (i);
961         }
962
963       /* Poll for faulty pipes */
964       if (efds)
965
966         {
967           struct GNUNET_CONTAINER_SList_Iterator *i;
968           for (i = GNUNET_CONTAINER_slist_begin (efds->handles);
969                GNUNET_CONTAINER_slist_end (i) != GNUNET_YES;
970                GNUNET_CONTAINER_slist_next (i))
971
972             {
973               HANDLE h;
974               DWORD dwBytes;
975               h = *(HANDLE *) GNUNET_CONTAINER_slist_get (i, NULL);
976               if (!PeekNamedPipe (h, NULL, 0, NULL, &dwBytes, NULL))
977
978                 {
979                   GNUNET_CONTAINER_slist_add (handles_except,
980                       GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT, &h,
981                       sizeof (HANDLE));
982                   retcode++;
983                 }
984             }
985           GNUNET_CONTAINER_slist_iter_destroy (i);
986         }
987
988       if (wfds)
989         {
990           GNUNET_CONTAINER_slist_append (handles_write, wfds->handles);
991           retcode += GNUNET_CONTAINER_slist_count (wfds->handles);
992         }
993
994       /* Check for closed sockets */
995       for (i = 0; i < nfds; i++)
996
997         {
998           if (SAFE_FD_ISSET (i, &sock_read))
999
1000             {
1001               struct sockaddr addr;
1002               int len;
1003               if (getpeername (i, &addr, &len) == SOCKET_ERROR)
1004
1005                 {
1006                   int err, len;
1007                   len = sizeof (err);
1008                   if (getsockopt
1009                       (i, SOL_SOCKET, SO_ERROR, (char *) &err, &len) == 0
1010                       && err == WSAENOTCONN)
1011
1012                     {
1013                       if (!SAFE_FD_ISSET (i, &aread))
1014
1015                         {
1016                           FD_SET (i, &aread);
1017                           retcode++;
1018                         }
1019                     }
1020                 }
1021             }
1022         }
1023     select_loop_end:
1024       if (retcode == 0 && nfds == 0)
1025         Sleep (GNUNET_MIN (100, limit - GetTickCount ()));
1026     }
1027   while (retcode == 0 && (ms_total == INFINITE || GetTickCount () < limit));
1028
1029   if (retcode != -1)
1030
1031     {
1032       if (rfds)
1033
1034         {
1035           GNUNET_NETWORK_fdset_zero (rfds);
1036           GNUNET_NETWORK_fdset_copy_native (rfds, &aread, retcode);
1037           GNUNET_CONTAINER_slist_clear (rfds->handles);
1038           GNUNET_CONTAINER_slist_append (rfds->handles, handles_read);
1039
1040         }
1041       if (wfds)
1042
1043         {
1044           GNUNET_NETWORK_fdset_zero (wfds);
1045           GNUNET_NETWORK_fdset_copy_native (wfds, &awrite, retcode);
1046           GNUNET_CONTAINER_slist_clear (wfds->handles);
1047           GNUNET_CONTAINER_slist_append (wfds->handles, handles_write);
1048         }
1049       if (efds)
1050
1051         {
1052           GNUNET_NETWORK_fdset_zero (efds);
1053           GNUNET_NETWORK_fdset_copy_native (efds, &aexcept, retcode);
1054           GNUNET_CONTAINER_slist_clear (efds->handles);
1055           GNUNET_CONTAINER_slist_append (efds->handles, handles_except);
1056         }
1057     }
1058
1059   GNUNET_CONTAINER_slist_destroy (handles_read);
1060   GNUNET_CONTAINER_slist_destroy (handles_write);
1061   GNUNET_CONTAINER_slist_destroy (handles_except);
1062
1063   return retcode;
1064 #endif
1065 }
1066
1067
1068 /* end of network.c */