add keywords from metadata for files
[oweals/gnunet.git] / src / util / network.c
index 2707e94329f037fed187027275a3bef2aad4dd4a..08121928db6ee69312b571f4c48878ab68aeebeb 100644 (file)
 
 #ifndef INVALID_SOCKET
 #define INVALID_SOCKET -1
-#endif /*  */
+#endif
+
+
 struct GNUNET_NETWORK_Handle
 {
+#ifndef MINGW
   int fd;
+
+#else
+  SOCKET fd;
+#endif
+
+  /**
+   * Address family / domain.
+   */
+  int af;
 };
+
+
 struct GNUNET_NETWORK_FDSet
 {
 
-  /* socket descriptors */
+  /**
+   * Maximum number of any socket socket descriptor in the set (plus one)
+   */
   int nsds;
+
+  /**
+   * Bitset with the descriptors.
+   */
   fd_set sds;
 
 #ifdef WINDOWS
-  /* handles */
+  /**
+   * Linked list of handles
+   */
   struct GNUNET_CONTAINER_SList *handles;
+#endif
 
-#endif                          /*  */
 };
 
 #ifndef FD_COPY
 #define FD_COPY(s, d) (memcpy ((d), (s), sizeof (fd_set)))
-#endif /*  */
+#endif
+
 
 /**
  * Set if a socket should use blocking or non-blocking IO.
@@ -78,7 +101,7 @@ socket_set_blocking (struct GNUNET_NETWORK_Handle *fd, int doBlock)
     }
   return GNUNET_OK;
 
-#else /*  */
+#else
   /* not MINGW */
   int flags = fcntl (fd->fd, F_GETFL);
   if (flags == -1)
@@ -99,8 +122,7 @@ socket_set_blocking (struct GNUNET_NETWORK_Handle *fd, int doBlock)
       return GNUNET_SYSERR;
     }
   return GNUNET_OK;
-
-#endif /*  */
+#endif
 }
 
 
@@ -116,16 +138,20 @@ static int
 socket_set_inheritable (const struct GNUNET_NETWORK_Handle *h)
 {
   int i;
-  i = fcntl (h->fd, F_GETFD);
+
+  i = fcntl (h->fd, F_GETFD);  
+  if (i < 0)
+    return GNUNET_SYSERR;
   if (i == (i | FD_CLOEXEC))
     return GNUNET_OK;
-  return (fcntl (h->fd, F_SETFD, i | FD_CLOEXEC) == 0)
-    ? GNUNET_OK : GNUNET_SYSERR;
+  i |= FD_CLOEXEC;
+  if (fcntl (h->fd, F_SETFD, i) < 0)
+    return GNUNET_SYSERR;
+  return GNUNET_OK;
 }
+#endif
 
 
-#endif /*  */
-
 #ifdef DARWIN
 /**
  * The MSG_NOSIGNAL equivalent on Mac OS X
@@ -135,15 +161,14 @@ socket_set_inheritable (const struct GNUNET_NETWORK_Handle *h)
 static void
 socket_set_nosigpipe (const struct GNUNET_NETWORK_Handle *h)
 {
-  int value = 1;
+  int abs_value = 1;
   if (0 !=
-      setsockopt (h->fd, SOL_SOCKET, SO_NOSIGPIPE, &value, sizeof (value)))
+      setsockopt (h->fd, SOL_SOCKET, SO_NOSIGPIPE, &abs_value, sizeof (abs_value)))
     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "setsockopt");
 }
+#endif
 
 
-#endif /*  */
-
 /**
  * Disable delays when sending data via the socket.
  * (GNUnet makes sure that messages are as big as
@@ -154,10 +179,15 @@ socket_set_nosigpipe (const struct GNUNET_NETWORK_Handle *h)
 static void
 socket_set_nodelay (const struct GNUNET_NETWORK_Handle *h)
 {
+#ifndef WINDOWS  
   int value = 1;
-  if (0 !=
-      setsockopt (h->fd, IPPROTO_TCP, TCP_NODELAY, &value, sizeof (value)))
+  if (0 != setsockopt (h->fd, IPPROTO_TCP, TCP_NODELAY, &value, sizeof (value)))
     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "setsockopt");
+#else
+  const char * abs_value = "1";
+  if (0 != setsockopt (h->fd, IPPROTO_TCP, TCP_NODELAY, abs_value, sizeof (abs_value)))
+    GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "setsockopt");
+#endif 
 }
 
 
@@ -175,31 +205,27 @@ GNUNET_NETWORK_socket_accept (const struct GNUNET_NETWORK_Handle *desc,
                               socklen_t * address_len)
 {
   struct GNUNET_NETWORK_Handle *ret;
+
   ret = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle));
   ret->fd = accept (desc->fd, address, address_len);
+  ret->af = address->sa_family;
   if (ret->fd == INVALID_SOCKET)
-
     {
-
 #ifdef MINGW
       SetErrnoFromWinsockError (WSAGetLastError ());
-
-#endif /*  */
+#endif
       GNUNET_free (ret);
       return NULL;
     }
-
 #ifndef MINGW
   if (ret->fd >= FD_SETSIZE)
-
     {
       GNUNET_break (0 == close (ret->fd));
       GNUNET_free (ret);
       errno = EMFILE;
       return NULL;
     }
-
-#endif /*  */
+#endif
   if (GNUNET_SYSERR == socket_set_blocking (ret, GNUNET_NO))
 
     {
@@ -214,13 +240,14 @@ GNUNET_NETWORK_socket_accept (const struct GNUNET_NETWORK_Handle *desc,
   if (GNUNET_OK != socket_set_inheritable (ret))
     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
                          "socket_set_inheritable");
-
-#endif /*  */
+#endif
 #ifdef DARWIN
   socket_set_nosigpipe (ret);
-
-#endif /*  */
-  socket_set_nodelay (ret);
+#endif
+#ifdef AF_UNIX
+  if (address->sa_family != AF_UNIX)
+#endif
+    socket_set_nodelay (ret);
   return ret;
 }
 
@@ -238,13 +265,36 @@ GNUNET_NETWORK_socket_bind (struct GNUNET_NETWORK_Handle *desc,
                             socklen_t address_len)
 {
   int ret;
+  
+#ifdef IPV6_V6ONLY 
+#ifdef IPPROTO_IPV6
+  const int on = 1;
+  if (desc->af == AF_INET6)
+    if (0 != setsockopt (desc->fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof (on)))
+      GNUNET_log_strerror (GNUNET_ERROR_TYPE_DEBUG, "setsockopt");
+#if 0
+  /* is this needed or desired? or done elsewhere? */
+  if (0 != setsockopt (desc->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)))
+    GNUNET_log_strerror (GNUNET_ERROR_TYPE_DEBUG, "setsockopt");
+#endif
+#endif
+#endif
   ret = bind (desc->fd, address, address_len);
-
 #ifdef MINGW
   if (SOCKET_ERROR == ret)
     SetErrnoFromWinsockError (WSAGetLastError ());
-
-#endif /*  */
+#else
+#ifndef LINUX
+  if ( (ret == 0) && (address->sa_family == AF_UNIX))
+    {
+      const struct sockaddr_un *un = (const struct sockaddr_un*) address;
+      if (0 != unlink (un->sun_path))
+       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
+                                 "unlink",
+                                 un->sun_path);
+    }
+#endif
+#endif
   return ret == 0 ? GNUNET_OK : GNUNET_SYSERR;
 }
 
@@ -258,23 +308,42 @@ int
 GNUNET_NETWORK_socket_close (struct GNUNET_NETWORK_Handle *desc)
 {
   int ret;
-  int eno;
 
 #ifdef MINGW
   ret = closesocket (desc->fd);
   SetErrnoFromWinsockError (WSAGetLastError ());
-
-#else /*  */
+#else
   ret = close (desc->fd);
-
-#endif /*  */
-  eno = errno;
+#endif
   GNUNET_free (desc);
-  errno = eno;
   return (ret == 0) ? GNUNET_OK : GNUNET_SYSERR;
 }
 
 
+/**
+ * Box a native socket (and check that it is a socket).
+ *
+ * @param fd socket to box
+ * @return NULL on error (including not supported on target platform)
+ */
+struct GNUNET_NETWORK_Handle *
+GNUNET_NETWORK_socket_box_native (int fd)
+{
+#if MINGW
+  return NULL;
+#else
+  struct GNUNET_NETWORK_Handle *ret;
+
+  if (fcntl (fd, F_GETFD) < 0)
+    return NULL; /* invalid FD */
+  ret = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle)); 
+  ret->fd = fd;
+  ret->af = AF_UNSPEC;
+  return ret;
+#endif
+}
+
+
 /**
  * Connect a socket
  * @param desc socket
@@ -298,8 +367,7 @@ GNUNET_NETWORK_socket_connect (const struct GNUNET_NETWORK_Handle *desc,
       if (errno == EWOULDBLOCK)
         errno = EINPROGRESS;
     }
-
-#endif /*  */
+#endif
   return ret == 0 ? GNUNET_OK : GNUNET_SYSERR;
 }
 
@@ -329,7 +397,7 @@ GNUNET_NETWORK_socket_getsockopt (const struct GNUNET_NETWORK_Handle *desc,
   else if (SOCKET_ERROR == ret)
     SetErrnoFromWinsockError (WSAGetLastError ());
 
-#endif /*  */
+#endif
   return ret == 0 ? GNUNET_OK : GNUNET_SYSERR;
 }
 
@@ -351,11 +419,70 @@ GNUNET_NETWORK_socket_listen (const struct GNUNET_NETWORK_Handle *desc,
   if (SOCKET_ERROR == ret)
     SetErrnoFromWinsockError (WSAGetLastError ());
 
-#endif /*  */
+#endif
   return ret == 0 ? GNUNET_OK : GNUNET_SYSERR;
 }
 
 
+/**
+ * How much data is available to be read on this descriptor?
+ *
+ * Returns GNUNET_NO if no data is available, or on error!
+ * @param desc socket
+ */
+ssize_t
+GNUNET_NETWORK_socket_recvfrom_amount (const struct GNUNET_NETWORK_Handle
+                                       *desc)
+{
+  int error;
+
+  /* How much is there to be read? */
+#ifndef WINDOWS
+  int pending;
+  error = ioctl (desc->fd, FIONREAD, &pending);
+  if (error == 0)
+#else
+  u_long pending;
+  error = ioctlsocket (desc->fd, FIONREAD, &pending);
+  if (error != SOCKET_ERROR)
+#endif
+    return pending;
+  else
+    return GNUNET_NO;
+}
+
+/**
+ * Read data from a connected socket (always non-blocking).
+ * @param desc socket
+ * @param buffer buffer
+ * @param length length of buffer
+ * @param src_addr either the source to recv from, or all zeroes
+ *        to be filled in by recvfrom
+ * @param addrlen length of the addr
+ */
+ssize_t
+GNUNET_NETWORK_socket_recvfrom (const struct GNUNET_NETWORK_Handle * desc,
+                                void *buffer, size_t length,
+                                struct sockaddr * src_addr,
+                                socklen_t * addrlen)
+{
+  int ret;
+  int flags;
+  flags = 0;
+
+#ifdef MSG_DONTWAIT
+  flags |= MSG_DONTWAIT;
+
+#endif
+  ret = recvfrom (desc->fd, buffer, length, flags, src_addr, addrlen);
+#ifdef MINGW
+  if (SOCKET_ERROR == ret)
+    SetErrnoFromWinsockError (WSAGetLastError ());
+#endif 
+  return ret;
+}
+
+
 /**
  * Read data from a connected socket (always non-blocking).
  * @param desc socket
@@ -372,15 +499,12 @@ GNUNET_NETWORK_socket_recv (const struct GNUNET_NETWORK_Handle * desc,
 
 #ifdef MSG_DONTWAIT
   flags |= MSG_DONTWAIT;
-
-#endif /*  */
+#endif
   ret = recv (desc->fd, buffer, length, flags);
-
 #ifdef MINGW
   if (SOCKET_ERROR == ret)
     SetErrnoFromWinsockError (WSAGetLastError ());
-
-#endif /*  */
+#endif
   return ret;
 }
 
@@ -443,19 +567,15 @@ GNUNET_NETWORK_socket_sendto (const struct GNUNET_NETWORK_Handle * desc,
 
 #ifdef MSG_DONTWAIT
   flags |= MSG_DONTWAIT;
-
-#endif /*  */
+#endif
 #ifdef MSG_NOSIGNAL
   flags |= MSG_NOSIGNAL;
-
-#endif /*  */
+#endif
   ret = sendto (desc->fd, message, length, flags, dest_addr, dest_len);
-
 #ifdef MINGW
   if (SOCKET_ERROR == ret)
     SetErrnoFromWinsockError (WSAGetLastError ());
-
-#endif /*  */
+#endif
   return ret;
 }
 
@@ -476,13 +596,12 @@ GNUNET_NETWORK_socket_setsockopt (struct GNUNET_NETWORK_Handle *fd,
                                   socklen_t option_len)
 {
   int ret;
-  ret = setsockopt (fd->fd, level, option_name, option_value, option_len);
 
+  ret = setsockopt (fd->fd, level, option_name, option_value, option_len);
 #ifdef MINGW
   if (SOCKET_ERROR == ret)
     SetErrnoFromWinsockError (WSAGetLastError ());
-
-#endif /*  */
+#endif
   return ret == 0 ? GNUNET_OK : GNUNET_SYSERR;
 }
 
@@ -502,22 +621,19 @@ GNUNET_NETWORK_socket_create (int domain, int type, int protocol)
 {
   struct GNUNET_NETWORK_Handle *ret;
   ret = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle));
+  ret->af = domain;
   ret->fd = socket (domain, type, protocol);
   if (INVALID_SOCKET == ret->fd)
-
     {
-
 #ifdef MINGW
       SetErrnoFromWinsockError (WSAGetLastError ());
-
-#endif /*  */
+#endif
       GNUNET_free (ret);
       return NULL;
     }
 
 #ifndef MINGW
   if (ret->fd >= FD_SETSIZE)
-
     {
       GNUNET_break (0 == close (ret->fd));
       GNUNET_free (ret);
@@ -525,11 +641,9 @@ GNUNET_NETWORK_socket_create (int domain, int type, int protocol)
       return NULL;
     }
 
-#endif /*  */
+#endif
   if (GNUNET_SYSERR == socket_set_blocking (ret, GNUNET_NO))
-
     {
-
       /* we might want to treat this one as fatal... */
       GNUNET_break (0);
       GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (ret));
@@ -540,13 +654,15 @@ GNUNET_NETWORK_socket_create (int domain, int type, int protocol)
   if (GNUNET_OK != socket_set_inheritable (ret))
     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
                          "socket_set_inheritable");
-
-#endif /*  */
+#endif
 #ifdef DARWIN
   socket_set_nosigpipe (ret);
-
-#endif /*  */
-  if (type == SOCK_STREAM)
+#endif
+  if ( (type == SOCK_STREAM) 
+#ifdef AF_UNIX
+       && (domain != AF_UNIX) 
+#endif
+       )
     socket_set_nodelay (ret);
   return ret;
 }
@@ -562,13 +678,12 @@ int
 GNUNET_NETWORK_socket_shutdown (struct GNUNET_NETWORK_Handle *desc, int how)
 {
   int ret;
-  ret = shutdown (desc->fd, how);
 
+  ret = shutdown (desc->fd, how);
 #ifdef MINGW
   if (ret != 0)
     SetErrnoFromWinsockError (WSAGetLastError ());
-
-#endif /*  */
+#endif
   return ret == 0 ? GNUNET_OK : GNUNET_SYSERR;
 }
 
@@ -582,11 +697,9 @@ GNUNET_NETWORK_fdset_zero (struct GNUNET_NETWORK_FDSet *fds)
 {
   FD_ZERO (&fds->sds);
   fds->nsds = 0;
-
 #ifdef MINGW
   GNUNET_CONTAINER_slist_clear (fds->handles);
-
-#endif /*  */
+#endif
 }
 
 /**
@@ -636,11 +749,15 @@ GNUNET_NETWORK_fdset_add (struct GNUNET_NETWORK_FDSet *dst,
         if (nfds + 1 > dst->nsds)
           dst->nsds = nfds + 1;
       }
+#ifdef MINGW
+  GNUNET_CONTAINER_slist_append (dst->handles, src->handles);
+#endif
 }
 
 
 /**
  * Copy one fd set to another
+ *
  * @param to destination
  * @param from source
  */
@@ -652,26 +769,20 @@ GNUNET_NETWORK_fdset_copy (struct GNUNET_NETWORK_FDSet *to,
   to->nsds = from->nsds;
 
 #ifdef MINGW
-  struct GNUNET_CONTAINER_SList_Iterator *iter;
   GNUNET_CONTAINER_slist_clear (to->handles);
-  for (iter = GNUNET_CONTAINER_slist_begin (from->handles);
-       GNUNET_CONTAINER_slist_end (iter) != GNUNET_YES;
-       GNUNET_CONTAINER_slist_next (iter))
+  GNUNET_CONTAINER_slist_append (to->handles, from->handles);
+#endif
+}
 
-    {
-      void *handle;
-      size_t len;
-      handle = GNUNET_CONTAINER_slist_get (iter, &len);
-      GNUNET_CONTAINER_slist_add (to->handles,
-                                  GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT,
-                                  handle, len);
-    }
-  GNUNET_CONTAINER_slist_iter_destroy (iter);
-#endif /*  */
+int
+GNUNET_NETWORK_get_fd (struct GNUNET_NETWORK_Handle *desc)
+{
+  return desc->fd;
 }
 
 /**
  * Copy a native fd set
+ *
  * @param to destination
  * @param from native source set
  * @param nfds the biggest socket number in from + 1
@@ -684,6 +795,38 @@ GNUNET_NETWORK_fdset_copy_native (struct GNUNET_NETWORK_FDSet *to,
   to->nsds = nfds;
 }
 
+
+/**
+ * Set a native fd in a set
+ *
+ * @param to destination
+ * @param nfd native FD to set
+ */
+void GNUNET_NETWORK_fdset_set_native (struct GNUNET_NETWORK_FDSet *to,
+                                     int nfd)
+{
+  FD_SET (nfd, &to->sds);
+  to->nsds = GNUNET_MAX (nfd + 1, to->nsds);
+}
+
+
+/**
+ * Test native fd in a set
+ *
+ * @param to set to test, NULL for empty set
+ * @param nfd native FD to test, or -1 for none
+ * @return GNUNET_YES if FD is set in the set
+ */
+int 
+GNUNET_NETWORK_fdset_test_native (const struct GNUNET_NETWORK_FDSet *to,
+                                 int nfd)
+{
+  if ( (nfd == -1) || (to == NULL) )
+    return GNUNET_NO;
+  return FD_ISSET (nfd, &to->sds) ? GNUNET_YES : GNUNET_NO;
+}
+
+
 /**
  * Add a file handle to the fd set
  * @param fds fd set
@@ -693,20 +836,19 @@ void
 GNUNET_NETWORK_fdset_handle_set (struct GNUNET_NETWORK_FDSet *fds,
                                  const struct GNUNET_DISK_FileHandle *h)
 {
-
 #ifdef MINGW
-  HANDLE hw;
-  GNUNET_DISK_internal_file_handle_ (h, &hw, sizeof (HANDLE));
-  GNUNET_CONTAINER_slist_add (fds->handles, GNUNET_NO, &hw, sizeof (HANDLE));
+  GNUNET_CONTAINER_slist_add (fds->handles,
+                              GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT,
+                              h, sizeof (struct GNUNET_DISK_FileHandle));
 
-#else /*  */
+#else
   int fd;
   GNUNET_DISK_internal_file_handle_ (h, &fd, sizeof (int));
   FD_SET (fd, &fds->sds);
   if (fd + 1 > fds->nsds)
     fds->nsds = fd + 1;
 
-#endif /*  */
+#endif
 }
 
 
@@ -722,13 +864,11 @@ GNUNET_NETWORK_fdset_handle_isset (const struct GNUNET_NETWORK_FDSet *fds,
 {
 
 #ifdef MINGW
-  return GNUNET_CONTAINER_slist_contains (fds->handles, h->h,
-                                          sizeof (HANDLE));
-
-#else /*  */
+  return GNUNET_CONTAINER_slist_contains (fds->handles, h,
+                                          sizeof (struct GNUNET_DISK_FileHandle));
+#else
   return FD_ISSET (h->fd, &fds->sds);
-
-#endif /*  */
+#endif
 }
 
 
@@ -742,13 +882,49 @@ int
 GNUNET_NETWORK_fdset_overlap (const struct GNUNET_NETWORK_FDSet *fds1,
                               const struct GNUNET_NETWORK_FDSet *fds2)
 {
+#ifndef MINGW
   int nfds;
+
   nfds = fds1->nsds;
-  if (nfds < fds2->nsds)
+  if (nfds > fds2->nsds)
     nfds = fds2->nsds;
-  for (; nfds >= 0; nfds--)
-    if (FD_ISSET (nfds, &fds1->sds) && FD_ISSET (nfds, &fds2->sds))
-      return GNUNET_YES;
+  while (nfds > 0)
+    {
+      nfds--;
+      if (FD_ISSET (nfds, &fds1->sds) && FD_ISSET (nfds, &fds2->sds))
+       return GNUNET_YES;
+    }
+#else
+  struct GNUNET_CONTAINER_SList_Iterator *it;
+  struct GNUNET_DISK_FileHandle *h;
+  int i;
+  int j;
+
+  /*This code is somewhat hacky, we are not supposed to know what's
+    inside of fd_set; also the O(n^2) is really bad... */
+
+  for (i = 0; i < fds1->sds.fd_count; i++)
+  {
+    for (j = 0; j < fds2->sds.fd_count; j++)
+    {
+      if (fds1->sds.fd_array[i] == fds2->sds.fd_array[j])
+        return GNUNET_YES;
+    }
+  }
+  it = GNUNET_CONTAINER_slist_begin (fds1->handles);
+  while (GNUNET_CONTAINER_slist_end (it) != GNUNET_YES)
+    {
+      h = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (it, NULL);
+      if (GNUNET_CONTAINER_slist_contains
+          (fds2->handles, h, sizeof (struct GNUNET_DISK_FileHandle)))
+        {
+          GNUNET_CONTAINER_slist_iter_destroy (it);
+          return GNUNET_YES;
+        }
+      GNUNET_CONTAINER_slist_next (it);
+    }
+  GNUNET_CONTAINER_slist_iter_destroy (it);
+#endif
   return GNUNET_NO;
 }
 
@@ -762,11 +938,9 @@ GNUNET_NETWORK_fdset_create ()
 {
   struct GNUNET_NETWORK_FDSet *fds;
   fds = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_FDSet));
-
 #ifdef MINGW
   fds->handles = GNUNET_CONTAINER_slist_create ();
-
-#endif /*  */
+#endif
   GNUNET_NETWORK_fdset_zero (fds);
   return fds;
 }
@@ -779,11 +953,9 @@ GNUNET_NETWORK_fdset_create ()
 void
 GNUNET_NETWORK_fdset_destroy (struct GNUNET_NETWORK_FDSet *fds)
 {
-
 #ifdef MINGW
   GNUNET_CONTAINER_slist_destroy (fds->handles);
-
-#endif /*  */
+#endif
   GNUNET_free (fds);
 }
 
@@ -832,10 +1004,10 @@ GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds,
     }
 
   struct timeval tv;
-  tv.tv_sec = timeout.value / GNUNET_TIME_UNIT_SECONDS.value;
+  tv.tv_sec = timeout.rel_value / GNUNET_TIME_UNIT_SECONDS.rel_value;
   tv.tv_usec =
-    1000 * (timeout.value - (tv.tv_sec * GNUNET_TIME_UNIT_SECONDS.value));
-  if ((nfds == 0) && (timeout.value == GNUNET_TIME_UNIT_FOREVER_REL.value)
+    1000 * (timeout.rel_value - (tv.tv_sec * GNUNET_TIME_UNIT_SECONDS.rel_value));
+  if ((nfds == 0) && (timeout.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
 #ifdef MINGW
       && handles == 0
 #endif
@@ -848,17 +1020,20 @@ GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds,
       GNUNET_break (0);
     }
 #ifndef MINGW
-  return select (nfds + 1,
+  return select (nfds,
                  (rfds != NULL) ? &rfds->sds : NULL,
                  (wfds != NULL) ? &wfds->sds : NULL,
                  (efds != NULL) ? &efds->sds : NULL,
-                 (timeout.value == GNUNET_TIME_UNIT_FOREVER_REL.value)
+                 (timeout.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
                  ? NULL : &tv);
 
-#else /*  */
+#else
   DWORD limit;
   fd_set sock_read, sock_write, sock_except;
   fd_set aread, awrite, aexcept;
+  struct GNUNET_CONTAINER_SList *handles_read, *handles_write,
+    *handles_except;
+
   int i;
   struct timeval tvslice;
   int retcode;
@@ -867,11 +1042,11 @@ GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds,
 #define SAFE_FD_ISSET(fd, set)  (set != NULL && FD_ISSET(fd, set))
 
   /* calculate how long we need to wait in milliseconds */
-  if (timeout.value == GNUNET_TIME_UNIT_FOREVER_REL.value)
+  if (timeout.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
     ms_total = INFINITE;
 
   else
-    ms_total = timeout.value / GNUNET_TIME_UNIT_MILLISECONDS.value;
+    ms_total = timeout.rel_value / GNUNET_TIME_UNIT_MILLISECONDS.rel_value;
 
   /* select() may be used as a portable way to sleep */
   if (!(rfds || wfds || efds))
@@ -880,6 +1055,11 @@ GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds,
       Sleep (ms_total);
       return 0;
     }
+
+  handles_read = GNUNET_CONTAINER_slist_create ();
+  handles_write = GNUNET_CONTAINER_slist_create ();
+  handles_except = GNUNET_CONTAINER_slist_create ();
+
   if (rfds)
     sock_read = rfds->sds;
   else
@@ -900,7 +1080,6 @@ GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds,
   limit = GetTickCount () + ms_total;
 
   do
-
     {
       retcode = 0;
       if (nfds > 0)
@@ -926,7 +1105,7 @@ GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds,
 #if DEBUG_NETWORK
               GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "select");
 
-#endif /*  */
+#endif
               goto select_loop_end;
             }
         }
@@ -936,47 +1115,46 @@ GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds,
 
         {
           struct GNUNET_CONTAINER_SList_Iterator *i;
-          int on_next;
-          on_next = GNUNET_NO;
           for (i = GNUNET_CONTAINER_slist_begin (rfds->handles);
                GNUNET_CONTAINER_slist_end (i) != GNUNET_YES;
-               on_next || GNUNET_CONTAINER_slist_next (i))
+               GNUNET_CONTAINER_slist_next (i))
 
             {
-              HANDLE h;
+              struct GNUNET_DISK_FileHandle *fh;
               DWORD dwBytes;
-              h = *(HANDLE *) GNUNET_CONTAINER_slist_get (i, NULL);
-              on_next = GNUNET_NO;
-              if (!PeekNamedPipe (h, NULL, 0, NULL, &dwBytes, NULL))
-
+              fh = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (i, NULL);
+              if (fh->type == GNUNET_PIPE)
                 {
-                  GNUNET_CONTAINER_slist_erase (i);
-                  on_next = GNUNET_YES;
-                  retcode = -1;
-                  SetErrnoFromWinError (GetLastError ());
-
-#if DEBUG_NETWORK
-                  GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
-                                       "PeekNamedPipe");
+                  if (!PeekNamedPipe (fh->h, NULL, 0, NULL, &dwBytes, NULL))
+                    {
+                      retcode = -1;
+                      SetErrnoFromWinError (GetLastError ());
 
-#endif /*  */
-                  goto select_loop_end;
-                }
+    #if DEBUG_NETWORK
+                      GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
+                                           "PeekNamedPipe");
 
-              else if (dwBytes)
+    #endif
+                      goto select_loop_end;
+                    }
+                  else if (dwBytes)
 
-                {
-                  retcode++;
+                    {
+                      GNUNET_CONTAINER_slist_add (handles_read,
+                                                  GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT,
+                                                  fh, sizeof (struct GNUNET_DISK_FileHandle));
+                      retcode++;
+                    }
                 }
-
               else
-
                 {
-                  GNUNET_CONTAINER_slist_erase (i);
-                  on_next = GNUNET_YES;
+                  /* Should we wait for more bytes to read here (in case of previous EOF)? */
+                  GNUNET_CONTAINER_slist_add (handles_read,
+                                              GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT,
+                                              fh, sizeof (struct GNUNET_DISK_FileHandle));
                 }
             }
-           GNUNET_CONTAINER_slist_iter_destroy (i);
+          GNUNET_CONTAINER_slist_iter_destroy (i);
         }
 
       /* Poll for faulty pipes */
@@ -984,33 +1162,35 @@ GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds,
 
         {
           struct GNUNET_CONTAINER_SList_Iterator *i;
-          int on_next;
-          on_next = GNUNET_NO;
           for (i = GNUNET_CONTAINER_slist_begin (efds->handles);
                GNUNET_CONTAINER_slist_end (i) != GNUNET_YES;
-               on_next || GNUNET_CONTAINER_slist_next (i))
+               GNUNET_CONTAINER_slist_next (i))
 
             {
-              HANDLE h;
+              struct GNUNET_DISK_FileHandle *fh;
               DWORD dwBytes;
-              h = *(HANDLE *) GNUNET_CONTAINER_slist_get (i, NULL);
-              if (PeekNamedPipe (h, NULL, 0, NULL, &dwBytes, NULL))
 
+              fh = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (i, NULL);
+              if (fh->type == GNUNET_PIPE)
                 {
-                  GNUNET_CONTAINER_slist_erase (i);
-                  on_next = GNUNET_YES;
-                  retcode++;
-                }
+                  if (!PeekNamedPipe (fh->h, NULL, 0, NULL, &dwBytes, NULL))
 
-              else
-                on_next = GNUNET_NO;
+                    {
+                      GNUNET_CONTAINER_slist_add (handles_except,
+                                                  GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT,
+                                                  fh, sizeof (struct GNUNET_DISK_FileHandle));
+                      retcode++;
+                    }
+                }
             }
           GNUNET_CONTAINER_slist_iter_destroy (i);
         }
 
-      /* FIXME */
       if (wfds)
-        GNUNET_assert (GNUNET_CONTAINER_slist_count (wfds->handles) == 0);
+        {
+          GNUNET_CONTAINER_slist_append (handles_write, wfds->handles);
+          retcode += GNUNET_CONTAINER_slist_count (wfds->handles);
+        }
 
       /* Check for closed sockets */
       for (i = 0; i < nfds; i++)
@@ -1043,34 +1223,41 @@ GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds,
         }
     select_loop_end:
       if (retcode == 0 && nfds == 0)
-        Sleep(GNUNET_MIN(100, limit - GetTickCount()));
+        Sleep (GNUNET_MIN (100, limit - GetTickCount ()));
     }
   while (retcode == 0 && (ms_total == INFINITE || GetTickCount () < limit));
-  if (retcode != -1)
 
+  if (retcode != -1)
     {
       if (rfds)
-
         {
           GNUNET_NETWORK_fdset_zero (rfds);
           GNUNET_NETWORK_fdset_copy_native (rfds, &aread, retcode);
+          GNUNET_CONTAINER_slist_clear (rfds->handles);
+          GNUNET_CONTAINER_slist_append (rfds->handles, handles_read);
         }
       if (wfds)
-
         {
           GNUNET_NETWORK_fdset_zero (wfds);
           GNUNET_NETWORK_fdset_copy_native (wfds, &awrite, retcode);
+          GNUNET_CONTAINER_slist_clear (wfds->handles);
+          GNUNET_CONTAINER_slist_append (wfds->handles, handles_write);
         }
       if (efds)
-
         {
           GNUNET_NETWORK_fdset_zero (efds);
           GNUNET_NETWORK_fdset_copy_native (efds, &aexcept, retcode);
+          GNUNET_CONTAINER_slist_clear (efds->handles);
+          GNUNET_CONTAINER_slist_append (efds->handles, handles_except);
         }
     }
-  return retcode;
 
-#endif /*  */
+  GNUNET_CONTAINER_slist_destroy (handles_read);
+  GNUNET_CONTAINER_slist_destroy (handles_write);
+  GNUNET_CONTAINER_slist_destroy (handles_except);
+
+  return retcode;
+#endif
 }