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