more fixes
[oweals/gnunet.git] / src / util / network.c
1 /*\r
2      This file is part of GNUnet.\r
3      (C) 2009 Christian Grothoff (and other contributing authors)\r
4 \r
5      GNUnet is free software; you can redistribute it and/or modify\r
6      it under the terms of the GNU General Public License as published\r
7      by the Free Software Foundation; either version 2, or (at your\r
8      option) any later version.\r
9 \r
10      GNUnet is distributed in the hope that it will be useful, but\r
11      WITHOUT ANY WARRANTY; without even the implied warranty of\r
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
13      General Public License for more details.\r
14 \r
15      You should have received a copy of the GNU General Public License\r
16      along with GNUnet; see the file COPYING.  If not, write to the\r
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,\r
18      Boston, MA 02111-1307, USA.\r
19 */\r
20 \r
21 /**\r
22  * @file util/sock.c\r
23  * @brief basic, low-level networking interface\r
24  * @author Nils Durner\r
25  */\r
26 \r
27 #include "platform.h"\r
28 #include "gnunet_disk_lib.h"\r
29 #include "disk.h"\r
30 #include "gnunet_container_lib.h"\r
31 \r
32 #define DEBUG_SOCK GNUNET_NO\r
33 \r
34 struct GNUNET_NETWORK_Descriptor\r
35 {\r
36   int fd;\r
37 };\r
38 \r
39 struct GNUNET_NETWORK_FDSet\r
40 {\r
41   /* socket descriptors */\r
42   int nsds;\r
43   fd_set sds;\r
44 #ifdef WINDOWS\r
45   /* handles */\r
46   struct GNUNET_CONTAINER_Vector *handles;\r
47 #endif\r
48 };\r
49 \r
50 #ifndef FD_COPY\r
51 #define FD_COPY(s, d) (memcpy ((d), (s), sizeof (fd_set)))\r
52 #endif\r
53 \r
54 struct GNUNET_NETWORK_Descriptor *\r
55 GNUNET_NETWORK_socket_accept (const struct GNUNET_NETWORK_Descriptor *desc,\r
56                               struct sockaddr *address,\r
57                               socklen_t * address_len)\r
58 {\r
59   struct GNUNET_NETWORK_Descriptor *ret;\r
60 \r
61   ret = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Descriptor));\r
62   ret->fd = accept (desc->fd, address, address_len);\r
63 #ifdef MINGW\r
64   if (INVALID_SOCKET == ret->fd)\r
65     SetErrnoFromWinsockError (WSAGetLastError ());\r
66 #endif\r
67   return ret;\r
68 }\r
69 \r
70 int\r
71 GNUNET_NETWORK_socket_bind (struct GNUNET_NETWORK_Descriptor *desc,\r
72                             const struct sockaddr *address,\r
73                             socklen_t address_len)\r
74 {\r
75   int ret;\r
76 \r
77   ret = bind (desc->fd, address, address_len);\r
78 #ifdef MINGW\r
79   if (SOCKET_ERROR == ret)\r
80     SetErrnoFromWinsockError (WSAGetLastError ());\r
81 #endif\r
82   return ret;\r
83 }\r
84 \r
85 /**\r
86  * Set if a socket should use blocking or non-blocking IO.\r
87  *\r
88  * @return GNUNET_OK on success, GNUNET_SYSERR on error\r
89  */\r
90 int\r
91 GNUNET_NETWORK_socket_set_blocking (struct GNUNET_NETWORK_Descriptor *fd,\r
92                                     int doBlock)\r
93 {\r
94 #if MINGW\r
95   u_long mode;\r
96   mode = !doBlock;\r
97   if (ioctlsocket (fd->fd, FIONBIO, &mode) == SOCKET_ERROR)\r
98     {\r
99       SetErrnoFromWinsockError (WSAGetLastError ());\r
100       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "ioctlsocket");\r
101       return GNUNET_SYSERR;\r
102     }\r
103   return GNUNET_OK;\r
104 \r
105 #else\r
106   /* not MINGW */\r
107   int flags = fcntl (fd->fd, F_GETFL);\r
108   if (flags == -1)\r
109     {\r
110       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "fcntl");\r
111       return GNUNET_SYSERR;\r
112     }\r
113   if (doBlock)\r
114     flags &= ~O_NONBLOCK;\r
115   else\r
116     flags |= O_NONBLOCK;\r
117   if (0 != fcntl (fd->fd, F_SETFL, flags))\r
118     {\r
119       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "fcntl");\r
120       return GNUNET_SYSERR;\r
121     }\r
122   return GNUNET_OK;\r
123 #endif\r
124 }\r
125 \r
126 int\r
127 GNUNET_NETWORK_socket_close (struct GNUNET_NETWORK_Descriptor *desc)\r
128 {\r
129   int ret;\r
130 #ifdef MINGW\r
131   ret = closesocket (desc->fd);\r
132   if (SOCKET_ERROR != ret)\r
133     GNUNET_free (desc);\r
134   else\r
135     SetErrnoFromWinsockError (WSAGetLastError ());\r
136 #else\r
137   ret = close (desc->fd);\r
138   if (-1 == ret)\r
139     {\r
140       GNUNET_free (desc);\r
141     }\r
142 #endif\r
143 \r
144   return ret;\r
145 }\r
146 \r
147 int\r
148 GNUNET_NETWORK_socket_connect (const struct GNUNET_NETWORK_Descriptor *desc,\r
149                                const struct sockaddr *address,\r
150                                socklen_t address_len)\r
151 {\r
152   int ret;\r
153 \r
154   ret = connect (desc->fd, address, address_len);\r
155 #ifdef MINGW\r
156   if (SOCKET_ERROR == ret)\r
157     SetErrnoFromWinsockError (WSAGetLastError ());\r
158 #endif\r
159   return ret;\r
160 }\r
161 \r
162 int\r
163 GNUNET_NETWORK_socket_getsockopt (const struct GNUNET_NETWORK_Descriptor *desc,\r
164                                   int level, int optname, void *optval,\r
165                                   socklen_t * optlen)\r
166 {\r
167   int ret;\r
168 \r
169   ret = getsockopt (desc->fd, level, optname, optval, optlen);\r
170 #ifdef MINGW\r
171   if (ret == 0 && level == SOL_SOCKET && optname == SO_ERROR)\r
172     *((int *) optval) = GetErrnoFromWinsockError (*((int *) optval));\r
173   else if (SOCKET_ERROR == ret)\r
174     SetErrnoFromWinsockError (WSAGetLastError ());\r
175 #endif\r
176   return ret;\r
177 }\r
178 \r
179 int\r
180 GNUNET_NETWORK_socket_listen (const struct GNUNET_NETWORK_Descriptor *desc,\r
181                               int backlog)\r
182 {\r
183   int ret;\r
184 \r
185   ret = listen (desc->fd, backlog);\r
186 #ifdef MINGW\r
187   if (SOCKET_ERROR == ret)\r
188     SetErrnoFromWinsockError (WSAGetLastError ());\r
189 #endif\r
190 \r
191   return ret;\r
192 }\r
193 \r
194 ssize_t\r
195 GNUNET_NETWORK_socket_recv (const struct GNUNET_NETWORK_Descriptor * desc,\r
196                             void *buffer, size_t length, int flags)\r
197 {\r
198   int ret;\r
199 \r
200   ret = recv (desc->fd, buffer, length, flags);\r
201 #ifdef MINGW\r
202   if (SOCKET_ERROR == ret)\r
203     SetErrnoFromWinsockError (WSAGetLastError ());\r
204 #endif\r
205 \r
206   return ret;\r
207 }\r
208 \r
209 ssize_t\r
210 GNUNET_NETWORK_socket_send (const struct GNUNET_NETWORK_Descriptor * desc,\r
211                             const void *buffer, size_t length, int flags)\r
212 {\r
213   int ret;\r
214 \r
215   ret = send (desc->fd, buffer, length, flags);\r
216 #ifdef MINGW\r
217   if (SOCKET_ERROR == ret)\r
218     SetErrnoFromWinsockError (WSAGetLastError ());\r
219 #endif\r
220 \r
221   return ret;\r
222 }\r
223 \r
224 ssize_t\r
225 GNUNET_NETWORK_socket_sendto (const struct GNUNET_NETWORK_Descriptor * desc,\r
226                               const void *message, size_t length, int flags,\r
227                               const struct sockaddr * dest_addr,\r
228                               socklen_t dest_len)\r
229 {\r
230   int ret;\r
231 \r
232   ret = sendto (desc->fd, message, length, flags, dest_addr, dest_len);\r
233 #ifdef MINGW\r
234   if (SOCKET_ERROR == ret)\r
235     SetErrnoFromWinsockError (WSAGetLastError ());\r
236 #endif\r
237 \r
238   return ret;\r
239 }\r
240 \r
241 int\r
242 GNUNET_NETWORK_socket_setsockopt (struct GNUNET_NETWORK_Descriptor *fd,\r
243                                   int level, int option_name,\r
244                                   const void *option_value,\r
245                                   socklen_t option_len)\r
246 {\r
247   int ret;\r
248 \r
249   ret = setsockopt (fd->fd, level, option_name, option_value, option_len);\r
250 #ifdef MINGW\r
251   if (SOCKET_ERROR == ret)\r
252     SetErrnoFromWinsockError (WSAGetLastError ());\r
253 #endif\r
254 \r
255   return ret;\r
256 }\r
257 \r
258 struct GNUNET_NETWORK_Descriptor *\r
259 GNUNET_NETWORK_socket_socket (int domain, int type, int protocol)\r
260 {\r
261   struct GNUNET_NETWORK_Descriptor *ret;\r
262 \r
263   ret = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Descriptor));\r
264   ret->fd = socket (domain, type, protocol);\r
265 #ifdef MINGW\r
266   if (INVALID_SOCKET == ret->fd)\r
267     SetErrnoFromWinsockError (WSAGetLastError ());\r
268 #endif\r
269 \r
270   if (ret->fd < 0)\r
271     {\r
272       GNUNET_free (ret);\r
273       ret = NULL;\r
274     }\r
275 \r
276   return ret;\r
277 }\r
278 \r
279 int\r
280 GNUNET_NETWORK_socket_shutdown (struct GNUNET_NETWORK_Descriptor *desc,\r
281                                 int how)\r
282 {\r
283   int ret;\r
284 \r
285   ret = shutdown (desc->fd, how);\r
286 #ifdef MINGW\r
287   if (ret != 0)\r
288     SetErrnoFromWinsockError (WSAGetLastError ());\r
289 #endif\r
290 \r
291   return ret;\r
292 }\r
293 \r
294 int\r
295 GNUNET_NETWORK_socket_set_inheritable (const struct GNUNET_NETWORK_Descriptor\r
296                                        *desc)\r
297 {\r
298 #ifdef MINGW\r
299   errno = ENOSYS;\r
300   return GNUNET_SYSERR;\r
301 #else\r
302   return fcntl (desc->fd, F_SETFD,\r
303                 fcntl (desc->fd,\r
304                        F_GETFD) | FD_CLOEXEC) ==\r
305     0 ? GNUNET_OK : GNUNET_SYSERR;\r
306 #endif\r
307 }\r
308 \r
309 void\r
310 GNUNET_NETWORK_fdset_zero (struct GNUNET_NETWORK_FDSet *fds)\r
311 {\r
312   FD_ZERO (&fds->sds);\r
313   fds->nsds = 0;\r
314 #ifdef MINGW\r
315   if (fds->handles)\r
316     GNUNET_CONTAINER_vector_destroy (fds->handles);\r
317   fds->handles = GNUNET_CONTAINER_vector_create (2);\r
318 #endif\r
319 }\r
320 \r
321 void\r
322 GNUNET_NETWORK_fdset_set (struct GNUNET_NETWORK_FDSet *fds,\r
323                           const struct GNUNET_NETWORK_Descriptor *desc)\r
324 {\r
325   FD_SET (desc->fd, &fds->sds);\r
326 \r
327   if (desc->fd + 1 > fds->nsds)\r
328     fds->nsds = desc->fd + 1;\r
329 }\r
330 \r
331 int\r
332 GNUNET_NETWORK_fdset_isset (const struct GNUNET_NETWORK_FDSet *fds,\r
333                             const struct GNUNET_NETWORK_Descriptor *desc)\r
334 {\r
335   return FD_ISSET (desc->fd, &fds->sds);\r
336 }\r
337 \r
338 void\r
339 GNUNET_NETWORK_fdset_add (struct GNUNET_NETWORK_FDSet *dst,\r
340                           const struct GNUNET_NETWORK_FDSet *src)\r
341 {\r
342   int nfds;\r
343 \r
344   for (nfds = src->nsds; nfds > 0; nfds--)\r
345     if (FD_ISSET (nfds, &src->sds))\r
346       {\r
347         FD_SET (nfds, &dst->sds);\r
348         if (nfds + 1 > dst->nsds)\r
349           dst->nsds = nfds + 1;\r
350       }\r
351 }\r
352 \r
353 void\r
354 GNUNET_NETWORK_fdset_copy (struct GNUNET_NETWORK_FDSet *to,\r
355                            const struct GNUNET_NETWORK_FDSet *from)\r
356 {\r
357   FD_COPY (&from->sds, &to->sds);\r
358   to->nsds = from->nsds;\r
359 #ifdef MINGW\r
360   void *obj;\r
361 \r
362   if (to->handles)\r
363     GNUNET_CONTAINER_vector_destroy (to->handles);\r
364   to->handles = GNUNET_CONTAINER_vector_create (2);\r
365   for (obj = GNUNET_CONTAINER_vector_get_first (from->handles); obj != NULL;\r
366        obj = GNUNET_CONTAINER_vector_get_next (from->handles))\r
367     {\r
368       GNUNET_CONTAINER_vector_insert_last (to->handles, obj);\r
369     }\r
370 #endif\r
371 }\r
372 \r
373 void\r
374 GNUNET_NETWORK_fdset_copy_native (struct GNUNET_NETWORK_FDSet *to,\r
375                                   const fd_set * from, int nfds)\r
376 {\r
377   FD_COPY (from, &to->sds);\r
378   to->nsds = nfds;\r
379 }\r
380 \r
381 void\r
382 GNUNET_NETWORK_fdset_handle_set (struct GNUNET_NETWORK_FDSet *fds,\r
383                                  const struct GNUNET_DISK_FileHandle *h)\r
384 {\r
385 #ifdef MINGW\r
386   HANDLE hw;\r
387 \r
388   GNUNET_internal_disk_file_handle (h, &hw, sizeof (HANDLE));\r
389   GNUNET_CONTAINER_vector_insert_last (fds->handles, h);\r
390 #else\r
391   int fd;\r
392 \r
393   GNUNET_internal_disk_file_handle (h, &fd, sizeof (int));\r
394   FD_SET (fd, &fds->sds);\r
395   if (fd + 1 > fds->nsds)\r
396     fds->nsds = fd + 1;\r
397 #endif\r
398 }\r
399 \r
400 int\r
401 GNUNET_NETWORK_fdset_handle_isset (const struct GNUNET_NETWORK_FDSet *fds,\r
402                                    const struct GNUNET_DISK_FileHandle *h)\r
403 {\r
404 #ifdef MINGW\r
405   return GNUNET_CONTAINER_vector_index_of (fds->handles, h->h) !=\r
406     (unsigned int) -1;\r
407 #else\r
408   return FD_ISSET (h->fd, &fds->sds);\r
409 #endif\r
410 }\r
411 \r
412 int\r
413 GNUNET_NETWORK_fdset_overlap (const struct GNUNET_NETWORK_FDSet *fds1,\r
414                               const struct GNUNET_NETWORK_FDSet *fds2)\r
415 {\r
416   int nfds;\r
417 \r
418   nfds = fds1->nsds;\r
419   if (nfds < fds2->nsds)\r
420     nfds = fds2->nsds;\r
421 \r
422   for (; nfds >= 0; nfds--)\r
423     if (FD_ISSET (nfds, &fds1->sds) && FD_ISSET (nfds, &fds2->sds))\r
424       return GNUNET_YES;\r
425 \r
426   return GNUNET_NO;\r
427 }\r
428 \r
429 struct GNUNET_NETWORK_FDSet *\r
430 GNUNET_NETWORK_fdset_create ()\r
431 {\r
432   struct GNUNET_NETWORK_FDSet *fds;\r
433 \r
434   fds = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_FDSet));\r
435 #ifdef MINGW\r
436   fds->handles = NULL;\r
437 #endif\r
438   GNUNET_NETWORK_fdset_zero (fds);\r
439 \r
440   return fds;\r
441 }\r
442 \r
443 void\r
444 GNUNET_NETWORK_fdset_destroy (struct GNUNET_NETWORK_FDSet *fds)\r
445 {\r
446 #ifdef MINGW\r
447   GNUNET_CONTAINER_vector_destroy (fds->handles);\r
448 #endif\r
449   GNUNET_free (fds);\r
450 }\r
451 \r
452 int\r
453 GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds,\r
454                               struct GNUNET_NETWORK_FDSet *wfds,\r
455                               struct GNUNET_NETWORK_FDSet *efds,\r
456                               const struct GNUNET_TIME_Relative timeout)\r
457 {\r
458   int nfds;\r
459 \r
460   nfds = 0;\r
461 \r
462   if (rfds)\r
463     nfds = rfds->nsds;\r
464   if (wfds && wfds->nsds > nfds)\r
465     nfds = wfds->nsds;\r
466   if (efds && efds->nsds > nfds)\r
467     nfds = efds->nsds;\r
468 \r
469 #ifndef MINGW\r
470   struct timeval tv;\r
471 \r
472   tv.tv_sec = timeout.value / GNUNET_TIME_UNIT_SECONDS.value;\r
473   tv.tv_usec = (timeout.value - (tv.tv_sec * GNUNET_TIME_UNIT_SECONDS.value))\r
474     / GNUNET_TIME_UNIT_MILLISECONDS.value;\r
475 \r
476   return select (nfds + 1, rfds ? &rfds->sds : NULL, wfds ? &wfds->sds : NULL,\r
477       efds ? &efds->sds : NULL, timeout.value\r
478           == GNUNET_TIME_UNIT_FOREVER_REL.value ? NULL : &tv);\r
479 #else\r
480   DWORD limit;\r
481   fd_set sock_read, sock_write, sock_except;\r
482   fd_set aread, awrite, aexcept;\r
483   int i;\r
484   struct timeval tvslice;\r
485   int retcode;\r
486   DWORD ms_total;\r
487 \r
488 #define SAFE_FD_ISSET(fd, set)  (set != NULL && FD_ISSET(fd, set))\r
489 \r
490   /* calculate how long we need to wait in milliseconds */\r
491   if (timeout.value == GNUNET_TIME_UNIT_FOREVER_REL.value)\r
492     ms_total = INFINITE;\r
493   else\r
494     ms_total = timeout.value / GNUNET_TIME_UNIT_MILLISECONDS.value;\r
495 \r
496   /* select() may be used as a portable way to sleep */\r
497   if (!(rfds || wfds || efds))\r
498     {\r
499       Sleep (ms_total);\r
500 \r
501       return 0;\r
502     }\r
503 \r
504   if (rfds)\r
505     sock_read = rfds->sds;\r
506   else\r
507     FD_ZERO(&sock_read);\r
508 \r
509   if (wfds)\r
510     sock_write = wfds->sds;\r
511   else\r
512     FD_ZERO(&sock_write);\r
513 \r
514   if (efds)\r
515     sock_except = efds->sds;\r
516   else\r
517     FD_ZERO(&sock_except);\r
518 \r
519   /*\r
520   if (rfds)\r
521     FD_COPY (&rfds->sds, &sock_read);\r
522   else\r
523     FD_ZERO(&sock_read);\r
524 \r
525   if (wfds)\r
526     FD_COPY (&wfds->sds, &sock_write);\r
527   else\r
528     FD_ZERO(&sock_write);\r
529 \r
530   if (efds)\r
531     FD_COPY (&efds->sds, &sock_except);\r
532   else\r
533     FD_ZERO(&sock_except);\r
534 */\r
535 \r
536   /* multiplex between winsock select() and waiting on the handles */\r
537 \r
538   FD_ZERO (&aread);\r
539   FD_ZERO (&awrite);\r
540   FD_ZERO (&aexcept);\r
541 \r
542   limit = GetTickCount () + ms_total;\r
543   do\r
544     {\r
545       retcode = 0;\r
546 \r
547       if (nfds > 0)\r
548         {\r
549           /* overwrite the zero'd sets here; the select call\r
550            * will clear those that are not active */\r
551 \r
552           FD_COPY (&sock_read, &aread);\r
553           FD_COPY (&sock_write, &awrite);\r
554           FD_COPY (&sock_except, &aexcept);\r
555 \r
556           tvslice.tv_sec = 0;\r
557           tvslice.tv_usec = 100000;\r
558 \r
559           if ((retcode =\r
560                select (nfds + 1, &aread, &awrite, &aexcept,\r
561                        &tvslice)) == SOCKET_ERROR)\r
562             {\r
563               SetErrnoFromWinsockError (WSAGetLastError ());\r
564               if (errno == ENOTSOCK)\r
565                 errno = EBADF;\r
566 \r
567 #if DEBUG_SOCK\r
568             GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "select");\r
569 #endif\r
570 \r
571               goto select_loop_end;\r
572             }\r
573         }\r
574 \r
575       /* Poll read pipes */\r
576       if (rfds)\r
577         for (i = GNUNET_CONTAINER_vector_size (rfds->handles) - 1; i >= 0; i--)\r
578           {\r
579             DWORD dwBytes;\r
580 \r
581             if (!PeekNamedPipe\r
582                 (GNUNET_CONTAINER_vector_get_at (rfds->handles, i), NULL, 0,\r
583                  NULL, &dwBytes, NULL))\r
584               {\r
585                 GNUNET_CONTAINER_vector_remove_at (rfds->handles, i);\r
586 \r
587                 retcode = -1;\r
588                 SetErrnoFromWinError (GetLastError ());\r
589 #if DEBUG_SOCK\r
590             GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "PeekNamedPipe");\r
591 #endif\r
592                goto select_loop_end;\r
593               }\r
594             else if (dwBytes)\r
595               {\r
596                 retcode++;\r
597               }\r
598             else\r
599               GNUNET_CONTAINER_vector_remove_at (rfds->handles, i);\r
600           }\r
601 \r
602       /* Poll for faulty pipes */\r
603       if (efds)\r
604         for (i = GNUNET_CONTAINER_vector_size (efds->handles); i >= 0; i--)\r
605           {\r
606             DWORD dwBytes;\r
607 \r
608             if (PeekNamedPipe\r
609                 (GNUNET_CONTAINER_vector_get_at (rfds->handles, i), NULL, 0,\r
610                  NULL, &dwBytes, NULL))\r
611               {\r
612                 GNUNET_CONTAINER_vector_remove_at (efds->handles, i);\r
613 \r
614                 retcode++;\r
615               }\r
616           }\r
617 \r
618       /* FIXME */\r
619       if (wfds)\r
620         GNUNET_assert (GNUNET_CONTAINER_vector_size (wfds->handles) == 0);\r
621 \r
622       /* Check for closed sockets */\r
623       for (i = 0; i < nfds; i++)\r
624         {\r
625           if (SAFE_FD_ISSET (i, &sock_read))\r
626             {\r
627               struct sockaddr addr;\r
628               int len;\r
629 \r
630               if (getpeername (i, &addr, &len) == SOCKET_ERROR)\r
631                 {\r
632                   int err, len;\r
633 \r
634                   len = sizeof (err);\r
635                   if (getsockopt\r
636                       (i, SOL_SOCKET, SO_ERROR, (char *) &err, &len) == 0\r
637                       && err == WSAENOTCONN)\r
638                     {\r
639                       if (!SAFE_FD_ISSET (i, &aread))\r
640                         {\r
641                           FD_SET (i, &aread);\r
642                           retcode++;\r
643                         }\r
644                     }\r
645                 }\r
646             }\r
647         }\r
648 \r
649     select_loop_end:;\r
650     }\r
651   while (retcode == 0 && (ms_total == INFINITE || GetTickCount () < limit));\r
652 \r
653   if (retcode != -1)\r
654     {\r
655       if (rfds)\r
656         {\r
657           GNUNET_NETWORK_fdset_zero (rfds);\r
658           GNUNET_NETWORK_fdset_copy_native (rfds, &aread, retcode);\r
659         }\r
660 \r
661       if (wfds)\r
662         {\r
663           GNUNET_NETWORK_fdset_zero (wfds);\r
664           GNUNET_NETWORK_fdset_copy_native (wfds, &awrite, retcode);\r
665         }\r
666 \r
667       if (efds)\r
668         {\r
669           GNUNET_NETWORK_fdset_zero (efds);\r
670           GNUNET_NETWORK_fdset_copy_native (efds, &aexcept, retcode);\r
671         }\r
672     }\r
673 \r
674   return retcode;\r
675 #endif\r
676 }\r
677 \r
678 /* end of network_socket.c */\r