361012d77811a88dbc4756f0156069ebf2fd684d
[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 }
640
641
642 /**
643  * Copy one fd set to another
644  * @param to destination
645  * @param from source
646  */
647 void
648 GNUNET_NETWORK_fdset_copy (struct GNUNET_NETWORK_FDSet *to,
649                            const struct GNUNET_NETWORK_FDSet *from)
650 {
651   FD_COPY (&from->sds, &to->sds);
652   to->nsds = from->nsds;
653
654 #ifdef MINGW
655   struct GNUNET_CONTAINER_SList_Iterator *iter;
656   GNUNET_CONTAINER_slist_clear (to->handles);
657   for (iter = GNUNET_CONTAINER_slist_begin (from->handles);
658        GNUNET_CONTAINER_slist_end (iter) != GNUNET_YES;
659        GNUNET_CONTAINER_slist_next (iter))
660
661     {
662       void *handle;
663       size_t len;
664       handle = GNUNET_CONTAINER_slist_get (iter, &len);
665       GNUNET_CONTAINER_slist_add (to->handles,
666                                   GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT,
667                                   handle, len);
668     }
669   GNUNET_CONTAINER_slist_iter_destroy (iter);
670 #endif /*  */
671 }
672
673 /**
674  * Copy a native fd set
675  * @param to destination
676  * @param from native source set
677  * @param nfds the biggest socket number in from + 1
678  */
679 void
680 GNUNET_NETWORK_fdset_copy_native (struct GNUNET_NETWORK_FDSet *to,
681                                   const fd_set * from, int nfds)
682 {
683   FD_COPY (from, &to->sds);
684   to->nsds = nfds;
685 }
686
687 /**
688  * Add a file handle to the fd set
689  * @param fds fd set
690  * @param h the file handle to add
691  */
692 void
693 GNUNET_NETWORK_fdset_handle_set (struct GNUNET_NETWORK_FDSet *fds,
694                                  const struct GNUNET_DISK_FileHandle *h)
695 {
696
697 #ifdef MINGW
698   HANDLE hw;
699   GNUNET_DISK_internal_file_handle_ (h, &hw, sizeof (HANDLE));
700   GNUNET_CONTAINER_slist_add (fds->handles, GNUNET_NO, &hw, sizeof (HANDLE));
701
702 #else /*  */
703   int fd;
704   GNUNET_DISK_internal_file_handle_ (h, &fd, sizeof (int));
705   FD_SET (fd, &fds->sds);
706   if (fd + 1 > fds->nsds)
707     fds->nsds = fd + 1;
708
709 #endif /*  */
710 }
711
712
713 /**
714  * Check if a file handle is part of an fd set
715  * @param fds fd set
716  * @param h file handle
717  * @return GNUNET_YES if the file handle is part of the set
718  */
719 int
720 GNUNET_NETWORK_fdset_handle_isset (const struct GNUNET_NETWORK_FDSet *fds,
721                                    const struct GNUNET_DISK_FileHandle *h)
722 {
723
724 #ifdef MINGW
725   return GNUNET_CONTAINER_slist_contains (fds->handles, h->h,
726                                           sizeof (HANDLE));
727
728 #else /*  */
729   return FD_ISSET (h->fd, &fds->sds);
730
731 #endif /*  */
732 }
733
734
735 /**
736  * Checks if two fd sets overlap
737  * @param fds1 first fd set
738  * @param fds2 second fd set
739  * @return GNUNET_YES if they do overlap, GNUNET_NO otherwise
740  */
741 int
742 GNUNET_NETWORK_fdset_overlap (const struct GNUNET_NETWORK_FDSet *fds1,
743                               const struct GNUNET_NETWORK_FDSet *fds2)
744 {
745   int nfds;
746   nfds = fds1->nsds;
747   if (nfds < fds2->nsds)
748     nfds = fds2->nsds;
749   for (; nfds >= 0; nfds--)
750     if (FD_ISSET (nfds, &fds1->sds) && FD_ISSET (nfds, &fds2->sds))
751       return GNUNET_YES;
752   return GNUNET_NO;
753 }
754
755
756 /**
757  * Creates an fd set
758  * @return a new fd set
759  */
760 struct GNUNET_NETWORK_FDSet *
761 GNUNET_NETWORK_fdset_create ()
762 {
763   struct GNUNET_NETWORK_FDSet *fds;
764   fds = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_FDSet));
765
766 #ifdef MINGW
767   fds->handles = GNUNET_CONTAINER_slist_create ();
768
769 #endif /*  */
770   GNUNET_NETWORK_fdset_zero (fds);
771   return fds;
772 }
773
774
775 /**
776  * Releases the associated memory of an fd set
777  * @param fds fd set
778  */
779 void
780 GNUNET_NETWORK_fdset_destroy (struct GNUNET_NETWORK_FDSet *fds)
781 {
782
783 #ifdef MINGW
784   GNUNET_CONTAINER_slist_destroy (fds->handles);
785
786 #endif /*  */
787   GNUNET_free (fds);
788 }
789
790 /**
791  * Check if sockets meet certain conditions
792  * @param rfds set of sockets to be checked for readability
793  * @param wfds set of sockets to be checked for writability
794  * @param efds set of sockets to be checked for exceptions
795  * @param timeout relative value when to return
796  * @return number of selected sockets, GNUNET_SYSERR on error
797  */
798 int
799 GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds,
800                               struct GNUNET_NETWORK_FDSet *wfds,
801                               struct GNUNET_NETWORK_FDSet *efds,
802                               const struct GNUNET_TIME_Relative timeout)
803 {
804   int nfds;
805   nfds = 0;
806   if (NULL != rfds)
807     nfds = rfds->nsds;
808   if (NULL != wfds)
809     nfds = GNUNET_MAX (nfds, wfds->nsds);
810   if (NULL != efds)
811     nfds = GNUNET_MAX (nfds, efds->nsds);
812
813 #ifndef MINGW
814   struct timeval tv;
815   tv.tv_sec = timeout.value / GNUNET_TIME_UNIT_SECONDS.value;
816   tv.tv_usec =
817     1000 * (timeout.value - (tv.tv_sec * GNUNET_TIME_UNIT_SECONDS.value));
818   if ((nfds == 0) && (timeout.value == GNUNET_TIME_UNIT_FOREVER_REL.value))
819
820     {
821       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
822                   _
823                   ("Fatal internal logic error, process hangs in `%s' (abort with CTRL-C)!\n"),
824                   "select");
825       GNUNET_break (0);
826     }
827   return select (nfds + 1,
828                  (rfds != NULL) ? &rfds->sds : NULL,
829                  (wfds != NULL) ? &wfds->sds : NULL,
830                  (efds != NULL) ? &efds->sds : NULL,
831                  (timeout.value == GNUNET_TIME_UNIT_FOREVER_REL.value)
832                  ? NULL : &tv);
833
834 #else /*  */
835   DWORD limit;
836   fd_set sock_read, sock_write, sock_except;
837   fd_set aread, awrite, aexcept;
838   int i;
839   struct timeval tvslice;
840   int retcode;
841   DWORD ms_total;
842
843 #define SAFE_FD_ISSET(fd, set)  (set != NULL && FD_ISSET(fd, set))
844
845   /* calculate how long we need to wait in milliseconds */
846   if (timeout.value == GNUNET_TIME_UNIT_FOREVER_REL.value)
847     ms_total = INFINITE;
848
849   else
850     ms_total = timeout.value / GNUNET_TIME_UNIT_MILLISECONDS.value;
851
852   /* select() may be used as a portable way to sleep */
853   if (!(rfds || wfds || efds))
854
855     {
856       Sleep (ms_total);
857       return 0;
858     }
859   if (rfds)
860     sock_read = rfds->sds;
861
862   else
863     FD_ZERO (&sock_read);
864   if (wfds)
865     sock_write = wfds->sds;
866
867   else
868     FD_ZERO (&sock_write);
869   if (efds)
870     sock_except = efds->sds;
871
872   else
873     FD_ZERO (&sock_except);
874
875   /* multiplex between winsock select() and waiting on the handles */
876   FD_ZERO (&aread);
877   FD_ZERO (&awrite);
878   FD_ZERO (&aexcept);
879   limit = GetTickCount () + ms_total;
880
881   do
882
883     {
884       retcode = 0;
885       if (nfds > 0)
886
887         {
888
889           /* overwrite the zero'd sets here; the select call
890            * will clear those that are not active */
891           FD_COPY (&sock_read, &aread);
892           FD_COPY (&sock_write, &awrite);
893           FD_COPY (&sock_except, &aexcept);
894           tvslice.tv_sec = 0;
895           tvslice.tv_usec = 100000;
896           if ((retcode =
897                select (nfds + 1, &aread, &awrite, &aexcept,
898                        &tvslice)) == SOCKET_ERROR)
899
900             {
901               SetErrnoFromWinsockError (WSAGetLastError ());
902               if (errno == ENOTSOCK)
903                 errno = EBADF;
904
905 #if DEBUG_NETWORK
906               GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "select");
907
908 #endif /*  */
909               goto select_loop_end;
910             }
911         }
912
913       /* Poll read pipes */
914       if (rfds)
915
916         {
917           struct GNUNET_CONTAINER_SList_Iterator *i;
918           int on_next;
919           on_next = GNUNET_NO;
920           for (i = GNUNET_CONTAINER_slist_begin (rfds->handles);
921                GNUNET_CONTAINER_slist_end (i) != GNUNET_YES;
922                on_next || GNUNET_CONTAINER_slist_next (i))
923
924             {
925               HANDLE h;
926               DWORD dwBytes;
927               h = *(HANDLE *) GNUNET_CONTAINER_slist_get (i, NULL);
928               on_next = GNUNET_NO;
929               if (!PeekNamedPipe (h, NULL, 0, NULL, &dwBytes, NULL))
930
931                 {
932                   GNUNET_CONTAINER_slist_erase (i);
933                   on_next = GNUNET_YES;
934                   retcode = -1;
935                   SetErrnoFromWinError (GetLastError ());
936
937 #if DEBUG_NETWORK
938                   GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
939                                        "PeekNamedPipe");
940
941 #endif /*  */
942                   goto select_loop_end;
943                 }
944
945               else if (dwBytes)
946
947                 {
948                   retcode++;
949                 }
950
951               else
952
953                 {
954                   GNUNET_CONTAINER_slist_erase (i);
955                   on_next = GNUNET_YES;
956                 }
957             }
958            GNUNET_CONTAINER_slist_iter_destroy (i);
959         }
960
961       /* Poll for faulty pipes */
962       if (efds)
963
964         {
965           struct GNUNET_CONTAINER_SList_Iterator *i;
966           int on_next;
967           on_next = GNUNET_NO;
968           for (i = GNUNET_CONTAINER_slist_begin (efds->handles);
969                GNUNET_CONTAINER_slist_end (i) != GNUNET_YES;
970                on_next || 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_erase (i);
980                   on_next = GNUNET_YES;
981                   retcode++;
982                 }
983
984               else
985                 on_next = GNUNET_NO;
986             }
987           GNUNET_CONTAINER_slist_iter_destroy (i);
988         }
989
990       /* FIXME */
991       if (wfds)
992         GNUNET_assert (GNUNET_CONTAINER_slist_count (wfds->handles) == 0);
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     }
1025   while (retcode == 0 && (ms_total == INFINITE || GetTickCount () < limit));
1026   if (retcode != -1)
1027
1028     {
1029       if (rfds)
1030
1031         {
1032           GNUNET_NETWORK_fdset_zero (rfds);
1033           GNUNET_NETWORK_fdset_copy_native (rfds, &aread, retcode);
1034         }
1035       if (wfds)
1036
1037         {
1038           GNUNET_NETWORK_fdset_zero (wfds);
1039           GNUNET_NETWORK_fdset_copy_native (wfds, &awrite, retcode);
1040         }
1041       if (efds)
1042
1043         {
1044           GNUNET_NETWORK_fdset_zero (efds);
1045           GNUNET_NETWORK_fdset_copy_native (efds, &aexcept, retcode);
1046         }
1047     }
1048   return retcode;
1049
1050 #endif /*  */
1051 }
1052
1053
1054 /* end of network.c */