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