WiP
[oweals/gnunet.git] / src / util / network.c
index 37e40aa1a2244ec1d7b88f895c9d0684c99d9ca5..d23f1a23d7726da871c06360a69aa485f23272d7 100644 (file)
@@ -41,18 +41,14 @@ struct GNUNET_NETWORK_Handle
 #ifndef MINGW
   int fd;
 
-#ifndef LINUX
-  /**
-   * For UNIX domain listen sockets, underlying filename to be removed
-   * on close.
-   */
-  char *filename;
-#endif
-
 #else
   SOCKET fd;
 #endif
 
+  /**
+   * Address family / domain.
+   */
+  int af;
 };
 
 
@@ -60,7 +56,7 @@ struct GNUNET_NETWORK_FDSet
 {
 
   /**
-   * Maximum number of any socket socket descriptor in the set
+   * Maximum number of any socket socket descriptor in the set (plus one)
    */
   int nsds;
 
@@ -165,9 +161,9 @@ 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
@@ -183,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 
 }
 
 
@@ -207,6 +208,7 @@ GNUNET_NETWORK_socket_accept (const struct GNUNET_NETWORK_Handle *desc,
 
   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
@@ -263,7 +265,20 @@ 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)
@@ -273,7 +288,10 @@ GNUNET_NETWORK_socket_bind (struct GNUNET_NETWORK_Handle *desc,
   if ( (ret == 0) && (address->sa_family == AF_UNIX))
     {
       const struct sockaddr_un *un = (const struct sockaddr_un*) address;
-      desc->filename = GNUNET_strdup (un->sun_path);
+      if (0 != unlink (un->sun_path))
+       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
+                                 "unlink",
+                                 un->sun_path);
     }
 #endif
 #endif
@@ -296,16 +314,6 @@ GNUNET_NETWORK_socket_close (struct GNUNET_NETWORK_Handle *desc)
   SetErrnoFromWinsockError (WSAGetLastError ());
 #else
   ret = close (desc->fd);
-#ifndef LINUX
-  if (NULL != desc->filename)
-    {
-      if (0 != unlink (desc->filename))
-       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
-                                 "unlink",
-                                 desc->filename);
-      GNUNET_free (desc->filename);
-    }
-#endif
 #endif
   GNUNET_free (desc);
   return (ret == 0) ? GNUNET_OK : GNUNET_SYSERR;
@@ -330,6 +338,7 @@ GNUNET_NETWORK_socket_box_native (int fd)
     return NULL; /* invalid FD */
   ret = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle)); 
   ret->fd = fd;
+  ret->af = AF_UNSPEC;
   return ret;
 #endif
 }
@@ -426,13 +435,14 @@ GNUNET_NETWORK_socket_recvfrom_amount (const struct GNUNET_NETWORK_Handle
                                        *desc)
 {
   int error;
-  int pending;
 
   /* 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
@@ -441,6 +451,7 @@ GNUNET_NETWORK_socket_recvfrom_amount (const struct GNUNET_NETWORK_Handle
     return GNUNET_NO;
 }
 
+
 /**
  * Read data from a connected socket (always non-blocking).
  * @param desc socket
@@ -611,6 +622,7 @@ 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)
     {
@@ -763,12 +775,20 @@ GNUNET_NETWORK_fdset_copy (struct GNUNET_NETWORK_FDSet *to,
 #endif
 }
 
+
+/**
+ * Return file descriptor for this network handle
+ *
+ * @param desc wrapper to process
+ * @return POSIX file descriptor
+ */
 int
 GNUNET_NETWORK_get_fd (struct GNUNET_NETWORK_Handle *desc)
 {
   return desc->fd;
 }
 
+
 /**
  * Copy a native fd set
  *
@@ -794,6 +814,7 @@ GNUNET_NETWORK_fdset_copy_native (struct GNUNET_NETWORK_FDSet *to,
 void GNUNET_NETWORK_fdset_set_native (struct GNUNET_NETWORK_FDSet *to,
                                      int nfd)
 {
+  GNUNET_assert(nfd >= 0);
   FD_SET (nfd, &to->sds);
   to->nsds = GNUNET_MAX (nfd + 1, to->nsds);
 }
@@ -825,13 +846,10 @@ 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_CONTAINER_SLIST_DISPOSITION_TRANSIENT,
-                              &hw, sizeof (HANDLE));
+                              h, sizeof (struct GNUNET_DISK_FileHandle));
 
 #else
   int fd;
@@ -856,8 +874,8 @@ GNUNET_NETWORK_fdset_handle_isset (const struct GNUNET_NETWORK_FDSet *fds,
 {
 
 #ifdef MINGW
-  return GNUNET_CONTAINER_slist_contains (fds->handles, &h->h,
-                                          sizeof (HANDLE));
+  return GNUNET_CONTAINER_slist_contains (fds->handles, h,
+                                          sizeof (struct GNUNET_DISK_FileHandle));
 #else
   return FD_ISSET (h->fd, &fds->sds);
 #endif
@@ -874,33 +892,48 @@ 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;
-#ifdef MINGW
-  {
-    struct GNUNET_CONTAINER_SList_Iterator *it;
+  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;
 
-    for (it = GNUNET_CONTAINER_slist_begin (fds1->handles);
-         GNUNET_CONTAINER_slist_end (it) != GNUNET_YES;
-         GNUNET_CONTAINER_slist_next (it))
-      {
-        HANDLE *h;
-
-        h = GNUNET_CONTAINER_slist_get (it, NULL);
-        if (GNUNET_CONTAINER_slist_contains
-            (fds2->handles, h, sizeof (HANDLE)))
-          {
-            GNUNET_CONTAINER_slist_iter_destroy (it);
-            return GNUNET_YES;
-          }
-      }
-    GNUNET_CONTAINER_slist_iter_destroy (it);
+  /*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;
 }
@@ -981,10 +1014,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
@@ -997,11 +1030,11 @@ 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
@@ -1019,11 +1052,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))
@@ -1097,28 +1130,49 @@ GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds,
                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)
                 {
-                  retcode = -1;
-                  SetErrnoFromWinError (GetLastError ());
-
-#if DEBUG_NETWORK
-                  GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
-                                       "PeekNamedPipe");
+                  if (!PeekNamedPipe (fh->h, NULL, 0, NULL, &dwBytes, NULL))
+                    {
+                      DWORD error_code = GetLastError ();
+                      switch (error_code)
+                      {
+                      case ERROR_BROKEN_PIPE:
+                        GNUNET_CONTAINER_slist_add (handles_read,
+                                                  GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT,
+                                                  fh, sizeof (struct GNUNET_DISK_FileHandle));
+                        retcode++;
+                        break;
+                      default:
+                        retcode = -1;
+                        SetErrnoFromWinError (error_code);
+
+    #if DEBUG_NETWORK
+                        GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
+                                             "PeekNamedPipe");
+
+    #endif
+                        goto select_loop_end;
+                      }
+                    }
+                  else if (dwBytes)
 
-#endif
-                  goto select_loop_end;
+                    {
+                      GNUNET_CONTAINER_slist_add (handles_read,
+                                                  GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT,
+                                                  fh, sizeof (struct GNUNET_DISK_FileHandle));
+                      retcode++;
+                    }
                 }
-              else if (dwBytes)
-
+              else
                 {
+                  /* 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,
-                                              &h, sizeof (HANDLE));
-                  retcode++;
+                                              fh, sizeof (struct GNUNET_DISK_FileHandle));
                 }
             }
           GNUNET_CONTAINER_slist_iter_destroy (i);
@@ -1134,16 +1188,20 @@ GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds,
                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_add (handles_except,
-                                              GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT,
-                                              &h, sizeof (HANDLE));
-                  retcode++;
+                  if (!PeekNamedPipe (fh->h, NULL, 0, NULL, &dwBytes, NULL))
+
+                    {
+                      GNUNET_CONTAINER_slist_add (handles_except,
+                                                  GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT,
+                                                  fh, sizeof (struct GNUNET_DISK_FileHandle));
+                      retcode++;
+                    }
                 }
             }
           GNUNET_CONTAINER_slist_iter_destroy (i);