-typo
[oweals/gnunet.git] / src / util / server.c
index 3f1edf3eaa22cc481508730f0b5c9276cf57e075..663661fea06f77a693203f179a9ed92265a30b17 100644 (file)
@@ -322,6 +322,17 @@ struct GNUNET_SERVER_Client
 };
 
 
+/**
+ * Scheduler says our listen socket is ready.  Process it!
+ *
+ * @param cls handle to our server for which we are processing the listen
+ *        socket
+ * @param tc reason why we are running right now
+ */
+static void
+process_listen_socket (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
+
+
 /**
  * Scheduler says our listen socket is ready.  Process it!
  *
@@ -335,22 +346,13 @@ process_listen_socket (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
   struct GNUNET_SERVER_Handle *server = cls;
   struct GNUNET_CONNECTION_Handle *sock;
   struct GNUNET_SERVER_Client *client;
-  struct GNUNET_NETWORK_FDSet *r;
   unsigned int i;
 
   server->listen_task = GNUNET_SCHEDULER_NO_TASK;
-  r = GNUNET_NETWORK_fdset_create ();
-  i = 0;
-  while (NULL != server->listen_sockets[i])
-    GNUNET_NETWORK_fdset_set (r, server->listen_sockets[i++]);
   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
   {
     /* ignore shutdown, someone else will take care of it! */
-    server->listen_task =
-        GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH,
-                                     GNUNET_TIME_UNIT_FOREVER_REL, r, NULL,
-                                     &process_listen_socket, server);
-    GNUNET_NETWORK_fdset_destroy (r);
+    GNUNET_SERVER_resume (server);
     return;
   }
   i = 0;
@@ -373,11 +375,7 @@ process_listen_socket (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
     i++;
   }
   /* listen for more! */
-  server->listen_task =
-      GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH,
-                                   GNUNET_TIME_UNIT_FOREVER_REL, r, NULL,
-                                   &process_listen_socket, server);
-  GNUNET_NETWORK_fdset_destroy (r);
+  GNUNET_SERVER_resume (server);
 }
 
 
@@ -391,7 +389,6 @@ process_listen_socket (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
 static struct GNUNET_NETWORK_Handle *
 open_listen_socket (const struct sockaddr *serverAddr, socklen_t socklen)
 {
-  static int on = 1;
   struct GNUNET_NETWORK_Handle *sock;
   uint16_t port;
   int eno;
@@ -419,20 +416,6 @@ open_listen_socket (const struct sockaddr *serverAddr, socklen_t socklen)
     errno = 0;
     return NULL;
   }
-  if (0 != port)
-  {
-    if (GNUNET_NETWORK_socket_setsockopt
-        (sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) != GNUNET_OK)
-      LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
-                    "setsockopt");
-#ifdef IPV6_V6ONLY
-    if ((AF_INET6 == serverAddr->sa_family) &&
-        (GNUNET_NETWORK_socket_setsockopt
-         (sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof (on)) != GNUNET_OK))
-      LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
-                    "setsockopt");
-#endif
-  }
   /* bind the socket */
   if (GNUNET_OK != GNUNET_NETWORK_socket_bind (sock, serverAddr, socklen))
   {
@@ -458,10 +441,17 @@ open_listen_socket (const struct sockaddr *serverAddr, socklen_t socklen)
              "bind", port,
              (AF_INET == serverAddr->sa_family) ? "IPv4" : "IPv6");
       else if (AF_UNIX == serverAddr->sa_family)
-        LOG (GNUNET_ERROR_TYPE_WARNING,
-             _("`%s' failed for `%s': address already in use\n"), "bind",
-             ((const struct sockaddr_un *) serverAddr)->sun_path);
+      {
+       const struct sockaddr_un *un = (const struct sockaddr_un *) serverAddr;
+       unsigned int off = 0;
 
+       if ('\0' == un->sun_path[0])
+         off = 1; /* some UNIXPATHs start with 0 */
+        LOG (GNUNET_ERROR_TYPE_WARNING,
+             _("`%s' failed for `%.*s': address already in use\n"), "bind",
+            (int) ((sizeof (un->sun_path) - off)),
+            (&un->sun_path[off]));
+      }
     }
     GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
     errno = eno;
@@ -501,8 +491,6 @@ GNUNET_SERVER_create_with_sockets (GNUNET_CONNECTION_AccessCheck access,
                                    int require_found)
 {
   struct GNUNET_SERVER_Handle *server;
-  struct GNUNET_NETWORK_FDSet *r;
-  int i;
 
   server = GNUNET_malloc (sizeof (struct GNUNET_SERVER_Handle));
   server->idle_timeout = idle_timeout;
@@ -511,17 +499,7 @@ GNUNET_SERVER_create_with_sockets (GNUNET_CONNECTION_AccessCheck access,
   server->access_cls = access_cls;
   server->require_found = require_found;
   if (NULL != lsocks)
-  {
-    r = GNUNET_NETWORK_fdset_create ();
-    i = 0;
-    while (NULL != server->listen_sockets[i])
-      GNUNET_NETWORK_fdset_set (r, server->listen_sockets[i++]);
-    server->listen_task =
-        GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH,
-                                     GNUNET_TIME_UNIT_FOREVER_REL, r, NULL,
-                                     &process_listen_socket, server);
-    GNUNET_NETWORK_fdset_destroy (r);
-  }
+    GNUNET_SERVER_resume (server);
   return server;
 }
 
@@ -655,6 +633,60 @@ test_monitor_clients (struct GNUNET_SERVER_Handle *server)
 }
 
 
+/**
+ * Suspend accepting connections from the listen socket temporarily.
+ *
+ * @param server server to stop accepting connections.
+ */
+void
+GNUNET_SERVER_suspend (struct GNUNET_SERVER_Handle *server)
+{
+  if (GNUNET_SCHEDULER_NO_TASK != server->listen_task)
+  {
+    GNUNET_SCHEDULER_cancel (server->listen_task);
+    server->listen_task = GNUNET_SCHEDULER_NO_TASK;
+  }
+}
+
+
+/**
+ * Resume accepting connections from the listen socket.
+ *
+ * @param server server to stop accepting connections.
+ */
+void
+GNUNET_SERVER_resume (struct GNUNET_SERVER_Handle *server)
+{
+  struct GNUNET_NETWORK_FDSet *r;
+  unsigned int i;
+
+  if (NULL == server->listen_sockets)
+    return;
+  if (NULL == server->listen_sockets[0])
+    return; /* nothing to do, no listen sockets! */
+  if (NULL == server->listen_sockets[1])
+  {
+    /* simplified method: no fd set needed; this is then much simpler and
+       much more efficient */
+    server->listen_task =
+      GNUNET_SCHEDULER_add_read_net_with_priority (GNUNET_TIME_UNIT_FOREVER_REL,
+                                                  GNUNET_SCHEDULER_PRIORITY_HIGH,
+                                                  server->listen_sockets[0],
+                                                  &process_listen_socket, server);
+    return;
+  }
+  r = GNUNET_NETWORK_fdset_create ();
+  i = 0;
+  while (NULL != server->listen_sockets[i])
+    GNUNET_NETWORK_fdset_set (r, server->listen_sockets[i++]);
+  server->listen_task =
+    GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH,
+                                GNUNET_TIME_UNIT_FOREVER_REL, r, NULL,
+                                &process_listen_socket, server);
+  GNUNET_NETWORK_fdset_destroy (r);
+}
+
+
 /**
  * Stop the listen socket and get ready to shutdown the server
  * once only 'monitor' clients are left.
@@ -794,6 +826,7 @@ warn_no_receive_done (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
   struct GNUNET_SERVER_Client *client = cls;
 
+  GNUNET_break (0 != client->warn_type); /* type should never be 0 here, as we don't use 0 */
   client->warn_task =
       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
                                     &warn_no_receive_done, client);
@@ -878,9 +911,11 @@ GNUNET_SERVER_inject (struct GNUNET_SERVER_Handle *server,
         }
         if (NULL != sender)
         {
-          if (0 == sender->suspended)
+          if ( (0 == sender->suspended) &&
+              (GNUNET_SCHEDULER_NO_TASK == sender->warn_task) )
           {
-            sender->warn_start = GNUNET_TIME_absolute_get ();
+           GNUNET_break (0 != type); /* type should never be 0 here, as we don't use 0 */
+            sender->warn_start = GNUNET_TIME_absolute_get ();      
             sender->warn_task =
                 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
                                               &warn_no_receive_done, sender);
@@ -991,25 +1026,11 @@ process_incoming (void *cls, const void *buf, size_t available,
                   const struct sockaddr *addr, socklen_t addrlen, int errCode)
 {
   struct GNUNET_SERVER_Client *client = cls;
-  struct GNUNET_SERVER_Client *tmp;
   struct GNUNET_SERVER_Handle *server = client->server;
   struct GNUNET_TIME_Absolute end;
   struct GNUNET_TIME_Absolute now;
   int ret;
 
-  /* Check if this client is still valid */
-  for (tmp = server->clients_head; NULL != tmp; tmp = tmp->next)
-  {
-    if (tmp == client)
-      break;
-  }
-
-  if (NULL == tmp)
-  {
-    GNUNET_break (0);
-    return;
-  }
-
   GNUNET_assert (GNUNET_YES == client->receive_pending);
   client->receive_pending = GNUNET_NO;
   now = GNUNET_TIME_absolute_get ();
@@ -1349,16 +1370,6 @@ GNUNET_SERVER_client_disconnect (struct GNUNET_SERVER_Client *client)
     GNUNET_CONTAINER_DLL_remove (server->clients_head,
                                 server->clients_tail,
                                 client);
-    if (GNUNET_SCHEDULER_NO_TASK != client->restart_task)
-    {
-      GNUNET_SCHEDULER_cancel (client->restart_task);
-      client->restart_task = GNUNET_SCHEDULER_NO_TASK;
-    }
-    if (GNUNET_SCHEDULER_NO_TASK != client->warn_task)
-    {
-      GNUNET_SCHEDULER_cancel (client->warn_task);
-      client->warn_task = GNUNET_SCHEDULER_NO_TASK;
-    }
     if (NULL != server->mst_destroy)
       server->mst_destroy (server->mst_cls, client->mst);
     else
@@ -1387,6 +1398,18 @@ GNUNET_SERVER_client_disconnect (struct GNUNET_SERVER_Client *client)
     GNUNET_SERVER_notify_transmit_ready_cancel (&client->th);
   (void) GNUNET_SCHEDULER_add_now (&destroy_connection,
                                   client->connection);
+  /* need to cancel again, as it might have been re-added
+     in the meantime (i.e. during callbacks) */
+  if (GNUNET_SCHEDULER_NO_TASK != client->warn_task)
+  {
+    GNUNET_SCHEDULER_cancel (client->warn_task);
+    client->warn_task = GNUNET_SCHEDULER_NO_TASK;
+  }
+  if (GNUNET_YES == client->receive_pending)
+  {
+    GNUNET_CONNECTION_receive_cancel (client->connection);
+    client->receive_pending = GNUNET_NO;
+  }
   GNUNET_free (client);
   /* we might be in soft-shutdown, test if we're done */
   if (NULL != server)