- test for external iterator
[oweals/gnunet.git] / src / util / network.c
index 69db7cd25af973c5792fddf7ce8b6c52121a50df..8398b9fab80ab9ed9067ba5a61baa857bbb133a7 100644 (file)
@@ -1,10 +1,10 @@
 /*
      This file is part of GNUnet.
-     (C) 2009, 2012 Christian Grothoff (and other contributing authors)
+     (C) 2009-2013 Christian Grothoff (and other contributing authors)
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 2, or (at your
+     by the Free Software Foundation; either version 3, or (at your
      option) any later version.
 
      GNUnet is distributed in the hope that it will be useful, but
@@ -144,12 +144,13 @@ GNUNET_NETWORK_shorten_unixpath (char *unixpath)
 
 /**
  * Set if a socket should use blocking or non-blocking IO.
+ *
  * @param fd socket
  * @param doBlock blocking mode
  * @return GNUNET_OK on success, GNUNET_SYSERR on error
  */
-static int
-socket_set_blocking (struct GNUNET_NETWORK_Handle *fd, int doBlock)
+int
+GNUNET_NETWORK_socket_set_blocking (struct GNUNET_NETWORK_Handle *fd, int doBlock)
 {
 
 #if MINGW
@@ -214,7 +215,7 @@ socket_set_inheritable (const struct GNUNET_NETWORK_Handle *h)
 #else
   BOOL b;
   SetLastError (0);
-  b = SetHandleInformation (h->fd, HANDLE_FLAG_INHERIT, 0);
+  b = SetHandleInformation ((HANDLE) h->fd, HANDLE_FLAG_INHERIT, 0);
   if (!b)
   {
     SetErrnoFromWinsockError (WSAGetLastError ());
@@ -237,7 +238,8 @@ socket_set_nosigpipe (const struct GNUNET_NETWORK_Handle *h)
   int abs_value = 1;
 
   if (0 !=
-      setsockopt (h->fd, SOL_SOCKET, SO_NOSIGPIPE, &abs_value,
+      setsockopt (h->fd, SOL_SOCKET, SO_NOSIGPIPE, 
+                 (const void *) &abs_value,
                   sizeof (abs_value)))
     LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "setsockopt");
 }
@@ -263,7 +265,8 @@ socket_set_nodelay (const struct GNUNET_NETWORK_Handle *h)
   const char *abs_value = "1";
 
   if (0 !=
-      setsockopt (h->fd, IPPROTO_TCP, TCP_NODELAY, abs_value,
+      setsockopt (h->fd, IPPROTO_TCP, TCP_NODELAY, 
+                 (const void *) abs_value,
                   sizeof (abs_value)))
     LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "setsockopt");
 #endif
@@ -307,7 +310,7 @@ initialize_network_handle (struct GNUNET_NETWORK_Handle *h,
     LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
                   "socket_set_inheritable");
 
-  if (GNUNET_SYSERR == socket_set_blocking (h, GNUNET_NO))
+  if (GNUNET_SYSERR == GNUNET_NETWORK_socket_set_blocking (h, GNUNET_NO))
   {
     GNUNET_break (0);
     GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (h));
@@ -363,35 +366,46 @@ GNUNET_NETWORK_socket_accept (const struct GNUNET_NETWORK_Handle *desc,
 
 /**
  * Bind to a connected socket
- * @param desc socket
+ *
+ * @param desc socket to bind
  * @param address address to be bound
  * @param address_len length of address
+ * @param flags flags affecting bind behaviour
  * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
  */
 int
 GNUNET_NETWORK_socket_bind (struct GNUNET_NETWORK_Handle *desc,
                             const struct sockaddr *address,
-                            socklen_t address_len)
+                            socklen_t address_len,
+                            int flags)
 {
   int ret;
 
 #ifdef IPV6_V6ONLY
 #ifdef IPPROTO_IPV6
-  const int on = 1;
+  {
+    const int on = 1;
 
-  if (desc->af == AF_INET6)
-    if (0 != setsockopt (desc->fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof (on)))
-      LOG_STRERROR (GNUNET_ERROR_TYPE_DEBUG, "setsockopt");
+    if (desc->af == AF_INET6)
+      if (setsockopt (desc->fd, IPPROTO_IPV6, IPV6_V6ONLY, 
+                     (const void *) &on, 
+                     sizeof (on)))
+        LOG_STRERROR (GNUNET_ERROR_TYPE_DEBUG, "setsockopt");
+  }
 #endif
 #endif
 #ifndef WINDOWS
-  /* This is required, and required here, but only on UNIX */
-  if (0 != setsockopt (desc->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)))
-    LOG_STRERROR (GNUNET_ERROR_TYPE_DEBUG, "setsockopt");
+  {
+    const int on = 1;
+  
+    /* This is required, and required here, but only on UNIX */
+    if (0 != setsockopt (desc->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)))
+      LOG_STRERROR (GNUNET_ERROR_TYPE_DEBUG, "setsockopt");
+  }
 #endif
 #ifndef LINUX
 #ifndef MINGW
-  if (address->sa_family == AF_UNIX)
+  if (address->sa_family == AF_UNIX && (flags & GNUNET_BIND_EXCLUSIVE) == 0)
   {
     const struct sockaddr_un *un = (const struct sockaddr_un *) address;
 
@@ -1195,7 +1209,7 @@ static DWORD WINAPI
 _selector (LPVOID p)
 {
   struct _select_params *sp = p;
-  int i;
+
   while (1)
   {
     WaitForSingleObject (sp->standby, INFINITE);
@@ -1318,7 +1332,7 @@ GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds,
   }
 
   if ((nfds == 0) &&
-      (timeout.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
+      (timeout.rel_value_us == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
 #ifdef MINGW
       && handles == 0
 #endif
@@ -1331,25 +1345,26 @@ GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds,
          "select");
   }
 #ifndef MINGW
-  tv.tv_sec = timeout.rel_value / GNUNET_TIME_UNIT_SECONDS.rel_value;
+  tv.tv_sec = timeout.rel_value_us / GNUNET_TIME_UNIT_SECONDS.rel_value_us;
   tv.tv_usec =
-      1000 * (timeout.rel_value -
-              (tv.tv_sec * GNUNET_TIME_UNIT_SECONDS.rel_value));
-  return select (nfds, (rfds != NULL) ? &rfds->sds : NULL,
-                 (wfds != NULL) ? &wfds->sds : NULL,
-                 (efds != NULL) ? &efds->sds : NULL,
-                 (timeout.rel_value ==
-                  GNUNET_TIME_UNIT_FOREVER_REL.rel_value) ? NULL : &tv);
+    (timeout.rel_value_us -
+     (tv.tv_sec * GNUNET_TIME_UNIT_SECONDS.rel_value_us));
+  return select (nfds, 
+                (NULL != rfds) ? &rfds->sds : NULL,
+                 (NULL != wfds) ? &wfds->sds : NULL,
+                 (NULL != efds) ? &efds->sds : NULL,
+                 (timeout.rel_value_us ==
+                  GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us) ? NULL : &tv);
 
 #else
 #define SAFE_FD_ISSET(fd, set)  (set != NULL && FD_ISSET(fd, set))
   /* calculate how long we need to wait in milliseconds */
-  if (timeout.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
+  if (timeout.rel_value_us == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
     ms_total = INFINITE;
   else
   {
-    ms_total = timeout.rel_value / GNUNET_TIME_UNIT_MILLISECONDS.rel_value;
-    if (timeout.rel_value / GNUNET_TIME_UNIT_MILLISECONDS.rel_value > 0xFFFFFFFFLL - 1)
+    ms_total = timeout.rel_value_us / GNUNET_TIME_UNIT_MILLISECONDS.rel_value_us;
+    if (timeout.rel_value_us / GNUNET_TIME_UNIT_MILLISECONDS.rel_value_us > 0xFFFFFFFFLL - 1)
     {
       GNUNET_break (0);
       ms_total = 0xFFFFFFFF - 1;
@@ -1362,7 +1377,7 @@ GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds,
     return 0;
   }
 
-  if (select_thread == NULL)
+  if (NULL == select_thread)
   {
     SOCKET select_listening_socket = -1;
     struct sockaddr_in s_in;
@@ -1379,6 +1394,7 @@ GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds,
 
     p = 1;
     res = ioctlsocket (select_wakeup_socket, FIONBIO, &p);
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "Select thread initialization: ioctlsocket() returns %d\n", res);
 
     alen = sizeof (s_in);
     s_in.sin_family = AF_INET;
@@ -1388,12 +1404,16 @@ GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds,
     s_in.sin_addr.S_un.S_un_b.s_b3 = 0;
     s_in.sin_addr.S_un.S_un_b.s_b4 = 1;
     res = bind (select_listening_socket, (const struct sockaddr *) &s_in, sizeof (s_in));
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "Select thread initialization: bind() returns %d\n", res);
 
     res = getsockname (select_listening_socket, (struct sockaddr *) &s_in, &alen);
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "Select thread initialization: getsockname() returns %d\n", res);
 
     res = listen (select_listening_socket, SOMAXCONN);
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "Select thread initialization: listen() returns %d\n", res);
 
     res = connect (select_wakeup_socket, (const struct sockaddr *) &s_in, sizeof (s_in));
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "Select thread initialization: connect() returns %d\n", res);
 
     select_send_socket = accept (select_listening_socket, (struct sockaddr *) &s_in, &alen);
 
@@ -1479,10 +1499,11 @@ GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds,
     if (rfds && read_handles)
     {
       struct GNUNET_CONTAINER_SList_Iterator i;
+      int c;
 
-      for (i = GNUNET_CONTAINER_slist_begin (rfds->handles);
+      for (c = 0, i = GNUNET_CONTAINER_slist_begin (rfds->handles);
           GNUNET_CONTAINER_slist_end (&i) != GNUNET_YES;
-          GNUNET_CONTAINER_slist_next (&i))
+          GNUNET_CONTAINER_slist_next (&i), c++)
       {
         struct GNUNET_DISK_FileHandle *fh;
 
@@ -1497,7 +1518,7 @@ GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds,
           bret = PeekNamedPipe (fh->h, NULL, 0, NULL, &waitstatus, NULL);
           error = GetLastError ();
           LOG (GNUNET_ERROR_TYPE_DEBUG, "Peek at read pipe %d (0x%x) returned %d (%d bytes available) GLE %u\n",
-              i, fh->h, bret, waitstatus, error);
+              c, fh->h, bret, waitstatus, error);
           if (bret == 0)
           {
             /* TODO: either add more errors to this condition, or eliminate it
@@ -1722,15 +1743,16 @@ GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds,
   if (nfds > 0)
   {
     LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Adding the socket event to the array as %d\n", nhandles);
+         "Adding the socket event to the array as %d\n",
+        nhandles);
     handle_array[nhandles++] = select_finished_event;
-    if (timeout.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
+    if (timeout.rel_value_us == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
       sp.tv = NULL;
     else
     {
-      select_timeout.tv_sec = timeout.rel_value / GNUNET_TIME_UNIT_SECONDS.rel_value;
-      select_timeout.tv_usec = 1000 * (timeout.rel_value -
-          (select_timeout.tv_sec * GNUNET_TIME_UNIT_SECONDS.rel_value));
+      select_timeout.tv_sec = timeout.rel_value_us / GNUNET_TIME_UNIT_SECONDS.rel_value_us;
+      select_timeout.tv_usec =(timeout.rel_value_us -
+          (select_timeout.tv_sec * GNUNET_TIME_UNIT_SECONDS.rel_value_us));
       sp.tv = &select_timeout;
     }
     FD_SET (select_wakeup_socket, &aread);