-fix (C) notices
[oweals/gnunet.git] / src / util / server_nc.c
index 66c69123992c0f0375b3a6aeb7d1c4dcf24199e1..75c9e1bc2054e41e56ef361a579e25b64bb9347a 100644 (file)
@@ -1,10 +1,10 @@
 /*
      This file is part of GNUnet.
 /*
      This file is part of GNUnet.
-     (C) 2010 Christian Grothoff (and other contributing authors)
+     Copyright (C) 2010 GNUnet e.V.
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
 
      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
      option) any later version.
 
      GNUnet is distributed in the hope that it will be useful, but
 
      You should have received a copy of the GNU General Public License
      along with GNUnet; see the file COPYING.  If not, write to the
 
      You should have received a copy of the GNU General Public License
      along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-     Boston, MA 02111-1307, USA.
+     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
 */
 
 /**
  * @file util/server_nc.c
  * @brief convenience functions for transmission of
 */
 
 /**
  * @file util/server_nc.c
  * @brief convenience functions for transmission of
- *        a notification stream 
+ *        a notification stream
  * @author Christian Grothoff
  */
 
 #include "platform.h"
  * @author Christian Grothoff
  */
 
 #include "platform.h"
-#include "gnunet_common.h"
-#include "gnunet_connection_lib.h"
-#include "gnunet_container_lib.h"
-#include "gnunet_scheduler_lib.h"
-#include "gnunet_server_lib.h"
-#include "gnunet_time_lib.h"
+#include "gnunet_util_lib.h"
 
 
+#define LOG(kind,...) GNUNET_log_from (kind, "util-server-nc", __VA_ARGS__)
 
 
-#define DEBUG_SERVER_NC GNUNET_NO
 
 /**
  * Entry in list of messages pending to be transmitted.
 
 /**
  * Entry in list of messages pending to be transmitted.
@@ -44,12 +39,12 @@ struct PendingMessageList
 
   /**
    * This is a doubly-linked list.
 
   /**
    * This is a doubly-linked list.
-   */ 
+   */
   struct PendingMessageList *next;
 
   /**
    * This is a doubly-linked list.
   struct PendingMessageList *next;
 
   /**
    * This is a doubly-linked list.
-   */ 
+   */
   struct PendingMessageList *prev;
 
   /**
   struct PendingMessageList *prev;
 
   /**
@@ -60,7 +55,7 @@ struct PendingMessageList
 
   /**
    * Can this message be dropped?
 
   /**
    * Can this message be dropped?
-   */ 
+   */
   int can_drop;
 
 };
   int can_drop;
 
 };
@@ -73,12 +68,17 @@ struct ClientList
 {
 
   /**
 {
 
   /**
-   * This is a linked list.
-   */ 
+   * This is a doubly linked list.
+   */
   struct ClientList *next;
 
   /**
   struct ClientList *next;
 
   /**
-   * Overall context this client belongs to. 
+   * This is a doubly linked list.
+   */
+  struct ClientList *prev;
+
+  /**
+   * Overall context this client belongs to.
    */
   struct GNUNET_SERVER_NotificationContext *nc;
 
    */
   struct GNUNET_SERVER_NotificationContext *nc;
 
@@ -90,16 +90,16 @@ struct ClientList
   /**
    * Handle for pending transmission request to the client (or NULL).
    */
   /**
    * Handle for pending transmission request to the client (or NULL).
    */
-  struct GNUNET_CONNECTION_TransmitHandle *th;
+  struct GNUNET_SERVER_TransmitHandle *th;
 
   /**
    * Head of linked list of requests queued for transmission.
 
   /**
    * Head of linked list of requests queued for transmission.
-   */ 
+   */
   struct PendingMessageList *pending_head;
 
   /**
    * Tail of linked list of requests queued for transmission.
   struct PendingMessageList *pending_head;
 
   /**
    * Tail of linked list of requests queued for transmission.
-   */ 
+   */
   struct PendingMessageList *pending_tail;
 
   /**
   struct PendingMessageList *pending_tail;
 
   /**
@@ -127,9 +127,14 @@ struct GNUNET_SERVER_NotificationContext
   struct GNUNET_SERVER_Handle *server;
 
   /**
   struct GNUNET_SERVER_Handle *server;
 
   /**
-   * List of clients receiving notifications.
+   * Head of list of clients receiving notifications.
    */
    */
-  struct ClientList *clients;
+  struct ClientList *clients_head;
+
+  /**
+   * Tail of list of clients receiving notifications.
+   */
+  struct ClientList *clients_tail;
 
   /**
    * Maximum number of optional messages to queue per client.
 
   /**
    * Maximum number of optional messages to queue per client.
@@ -142,56 +147,48 @@ struct GNUNET_SERVER_NotificationContext
 /**
  * Client has disconnected, clean up.
  *
 /**
  * Client has disconnected, clean up.
  *
- * @param cls our 'struct GNUNET_SERVER_NotificationContext *'
+ * @param cls our `struct GNUNET_SERVER_NotificationContext *`
  * @param client handle of client that disconnected
  */
 static void
 handle_client_disconnect (void *cls,
  * @param client handle of client that disconnected
  */
 static void
 handle_client_disconnect (void *cls,
-                         struct GNUNET_SERVER_Client *client)
+                          struct GNUNET_SERVER_Client *client)
 {
   struct GNUNET_SERVER_NotificationContext *nc = cls;
   struct ClientList *pos;
 {
   struct GNUNET_SERVER_NotificationContext *nc = cls;
   struct ClientList *pos;
-  struct ClientList *prev;
   struct PendingMessageList *pml;
 
   struct PendingMessageList *pml;
 
-  if (client == NULL)
-    {
-      nc->server = NULL;
-      return;
-    }
-  prev = NULL;
-  pos = nc->clients;
-  while (NULL != pos)
-    {
-      if (pos->client == client)
-       break;
-      prev = pos;
-      pos = pos->next;
-    }
-  if (pos == NULL)
+  if (NULL == client)
+  {
+    nc->server = NULL;
     return;
     return;
-#if DEBUG_SERVER_NC
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-             "Client disconnected, cleaning up %u messages in NC queue\n",
-             pos->num_pending);
-#endif
-  if (prev == NULL)
-    nc->clients = pos->next;
-  else
-    prev->next = pos->next;
+  }
+  for (pos = nc->clients_head; NULL != pos; pos = pos->next)
+    if (pos->client == client)
+      break;
+  if (NULL == pos)
+    return;
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Client disconnected, cleaning up %u messages in NC queue\n",
+       pos->num_pending);
+  GNUNET_CONTAINER_DLL_remove (nc->clients_head,
+                              nc->clients_tail,
+                              pos);
   while (NULL != (pml = pos->pending_head))
   while (NULL != (pml = pos->pending_head))
-    {
-      GNUNET_CONTAINER_DLL_remove (pos->pending_head,
-                                  pos->pending_tail,
-                                  pml);
-      GNUNET_free (pml);
-    }
+  {
+    GNUNET_CONTAINER_DLL_remove (pos->pending_head,
+                                 pos->pending_tail,
+                                 pml);
+    GNUNET_free (pml);
+    pos->num_pending--;
+  }
+  if (NULL != pos->th)
+  {
+    GNUNET_SERVER_notify_transmit_ready_cancel (pos->th);
+    pos->th = NULL;
+  }
   GNUNET_SERVER_client_drop (client);
   GNUNET_SERVER_client_drop (client);
-  if (pos->th != NULL)
-    {
-      GNUNET_CONNECTION_notify_transmit_ready_cancel (pos->th);
-      pos->th = NULL;
-    }
+  GNUNET_assert (0 == pos->num_pending);
   GNUNET_free (pos);
 }
 
   GNUNET_free (pos);
 }
 
@@ -202,21 +199,21 @@ handle_client_disconnect (void *cls,
  * @param server server for which this function creates the context
  * @param queue_length maximum number of messages to keep in
  *        the notification queue; optional messages are dropped
  * @param server server for which this function creates the context
  * @param queue_length maximum number of messages to keep in
  *        the notification queue; optional messages are dropped
- *        it the queue gets longer than this number of messages
+ *        if the queue gets longer than this number of messages
  * @return handle to the notification context
  */
 struct GNUNET_SERVER_NotificationContext *
 GNUNET_SERVER_notification_context_create (struct GNUNET_SERVER_Handle *server,
  * @return handle to the notification context
  */
 struct GNUNET_SERVER_NotificationContext *
 GNUNET_SERVER_notification_context_create (struct GNUNET_SERVER_Handle *server,
-                                          unsigned int queue_length)
+                                           unsigned int queue_length)
 {
   struct GNUNET_SERVER_NotificationContext *ret;
 
 {
   struct GNUNET_SERVER_NotificationContext *ret;
 
-  ret = GNUNET_malloc (sizeof (struct GNUNET_SERVER_NotificationContext));
+  ret = GNUNET_new (struct GNUNET_SERVER_NotificationContext);
   ret->server = server;
   ret->queue_length = queue_length;
   GNUNET_SERVER_disconnect_notify (server,
   ret->server = server;
   ret->queue_length = queue_length;
   GNUNET_SERVER_disconnect_notify (server,
-                                  &handle_client_disconnect,
-                                  ret);
+                                   &handle_client_disconnect,
+                                   ret);
   return ret;
 }
 
   return ret;
 }
 
@@ -232,24 +229,32 @@ GNUNET_SERVER_notification_context_destroy (struct GNUNET_SERVER_NotificationCon
   struct ClientList *pos;
   struct PendingMessageList *pml;
 
   struct ClientList *pos;
   struct PendingMessageList *pml;
 
-  while (NULL != (pos = nc->clients))
+  while (NULL != (pos = nc->clients_head))
+  {
+    GNUNET_CONTAINER_DLL_remove (nc->clients_head,
+                                nc->clients_tail,
+                                pos);
+    if (NULL != pos->th)
+    {
+      GNUNET_SERVER_notify_transmit_ready_cancel (pos->th);
+      pos->th = NULL;
+    }
+    GNUNET_SERVER_client_drop (pos->client);
+    while (NULL != (pml = pos->pending_head))
     {
     {
-      nc->clients = pos->next;
-      GNUNET_SERVER_client_drop (pos->client); 
-      GNUNET_SERVER_receive_done (pos->client, GNUNET_NO);
-      while (NULL != (pml = pos->pending_head))
-       {
-         GNUNET_CONTAINER_DLL_remove (pos->pending_head,
-                                      pos->pending_tail,
-                                      pml);
-         GNUNET_free (pml);
-       }
-      GNUNET_free (pos);
+      GNUNET_CONTAINER_DLL_remove (pos->pending_head,
+                                   pos->pending_tail,
+                                   pml);
+      GNUNET_free (pml);
+      pos->num_pending--;
     }
     }
-  if (nc->server != NULL)
+    GNUNET_assert (0 == pos->num_pending);
+    GNUNET_free (pos);
+  }
+  if (NULL != nc->server)
     GNUNET_SERVER_disconnect_notify_cancel (nc->server,
     GNUNET_SERVER_disconnect_notify_cancel (nc->server,
-                                           &handle_client_disconnect,
-                                           nc);
+                                            &handle_client_disconnect,
+                                            nc);
   GNUNET_free (nc);
 }
 
   GNUNET_free (nc);
 }
 
@@ -262,33 +267,37 @@ GNUNET_SERVER_notification_context_destroy (struct GNUNET_SERVER_NotificationCon
  */
 void
 GNUNET_SERVER_notification_context_add (struct GNUNET_SERVER_NotificationContext *nc,
  */
 void
 GNUNET_SERVER_notification_context_add (struct GNUNET_SERVER_NotificationContext *nc,
-                                       struct GNUNET_SERVER_Client *client)
+                                        struct GNUNET_SERVER_Client *client)
 {
   struct ClientList *cl;
 
 {
   struct ClientList *cl;
 
-  cl = GNUNET_malloc (sizeof (struct ClientList));
-  cl->next = nc->clients;
+  for (cl = nc->clients_head; NULL != cl; cl = cl->next)
+    if (cl->client == client)
+      return; /* already present */
+  cl = GNUNET_new (struct ClientList);
+  GNUNET_CONTAINER_DLL_insert (nc->clients_head,
+                              nc->clients_tail,
+                              cl);
   cl->nc = nc;
   cl->client = client;
   GNUNET_SERVER_client_keep (client);
   cl->nc = nc;
   cl->client = client;
   GNUNET_SERVER_client_keep (client);
-  nc->clients = cl;
 }
 
 
 /**
  * Function called to notify a client about the socket begin ready to
 }
 
 
 /**
  * Function called to notify a client about the socket begin ready to
- * queue more data.  "buf" will be NULL and "size" zero if the socket
+ * queue more data.  @a buf will be NULL and @a size zero if the socket
  * was closed for writing in the meantime.
  *
  * was closed for writing in the meantime.
  *
- * @param cls the 'struct ClientList *'
- * @param size number of bytes available in buf
+ * @param cls the `struct ClientList *`
+ * @param size number of bytes available in @a buf
  * @param buf where the callee should write the message
  * @return number of bytes written to buf
  */
 static size_t
 transmit_message (void *cls,
  * @param buf where the callee should write the message
  * @return number of bytes written to buf
  */
 static size_t
 transmit_message (void *cls,
-                 size_t size,
-                 void *buf)
+                  size_t size,
+                  void *buf)
 {
   struct ClientList *cl = cls;
   char *cbuf = buf;
 {
   struct ClientList *cl = cls;
   char *cbuf = buf;
@@ -297,51 +306,47 @@ transmit_message (void *cls,
   size_t ret;
 
   cl->th = NULL;
   size_t ret;
 
   cl->th = NULL;
-  if (buf == NULL)
-    {
-      /* 'cl' should be freed via disconnect notification shortly */
-#if DEBUG_SERVER_NC
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                 "Failed to transmit message from NC queue to client\n");
-#endif
-      return 0;
-    }
+  if (NULL == buf)
+  {
+    /* 'cl' should be freed via disconnect notification shortly */
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Failed to transmit message from NC queue to client\n");
+    return 0;
+  }
   ret = 0;
   ret = 0;
-  while (NULL != (pml = cl->pending_head) )
-    {
-      msize = ntohs (pml->msg->size);
-      if (size < msize)
-       break;
-      GNUNET_CONTAINER_DLL_remove (cl->pending_head,
-                                  cl->pending_tail,
-                                  pml);
-#if DEBUG_SERVER_NC
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                 "Copying message of type %u and size %u from pending queue to transmission buffer\n",
-                 ntohs (pml->msg->type),
-                 msize);
-#endif
-      memcpy (&cbuf[ret], pml->msg, msize);
-      ret += msize;
-      size -= msize;
-      GNUNET_free (pml);
-      cl->num_pending--;
-    }
-  if (pml != NULL)    
-    {
-#if DEBUG_SERVER_NC
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                 "Have %u messages left in NC queue, will try transmission again\n",
-                 cl->num_pending);
-#endif
-      cl->th = GNUNET_SERVER_notify_transmit_ready (cl->client,
-                                                   ntohs (pml->msg->size),
-                                                   GNUNET_TIME_UNIT_FOREVER_REL,
-                                                   &transmit_message,
-                                                   cl);
-    }
+  while (NULL != (pml = cl->pending_head))
+  {
+    msize = ntohs (pml->msg->size);
+    if (size < msize)
+      break;
+    GNUNET_CONTAINER_DLL_remove (cl->pending_head,
+                                 cl->pending_tail,
+                                 pml);
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Copying message of type %u and size %u from pending queue to transmission buffer\n",
+         ntohs (pml->msg->type),
+         msize);
+    memcpy (&cbuf[ret], pml->msg, msize);
+    ret += msize;
+    size -= msize;
+    GNUNET_free (pml);
+    cl->num_pending--;
+  }
+  if (NULL != pml)
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Have %u messages left in NC queue, will try transmission again\n",
+         cl->num_pending);
+    cl->th =
+        GNUNET_SERVER_notify_transmit_ready (cl->client,
+                                             ntohs (pml->msg->size),
+                                             GNUNET_TIME_UNIT_FOREVER_REL,
+                                             &transmit_message, cl);
+  }
   else
   else
-    GNUNET_assert (cl->num_pending == 0);
+  {
+    GNUNET_assert (0 == cl->num_pending);
+  }
   return ret;
 }
 
   return ret;
 }
 
@@ -356,52 +361,49 @@ transmit_message (void *cls,
  */
 static void
 do_unicast (struct GNUNET_SERVER_NotificationContext *nc,
  */
 static void
 do_unicast (struct GNUNET_SERVER_NotificationContext *nc,
-           struct ClientList *client,
-           const struct GNUNET_MessageHeader *msg,
-           int can_drop)
+            struct ClientList *client,
+            const struct GNUNET_MessageHeader *msg,
+            int can_drop)
 {
   struct PendingMessageList *pml;
   uint16_t size;
 
   if ( (client->num_pending > nc->queue_length) &&
        (GNUNET_YES == can_drop) )
 {
   struct PendingMessageList *pml;
   uint16_t size;
 
   if ( (client->num_pending > nc->queue_length) &&
        (GNUNET_YES == can_drop) )
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                 "Dropping message of type %u and size %u due to full queue (%u entries)\n",
-                 ntohs (msg->type),
-                 ntohs (msg->size),
-                 (unsigned int) nc->queue_length);
-      return; /* drop! */
-    }
+  {
+    LOG (GNUNET_ERROR_TYPE_INFO,
+         "Dropping message of type %u and size %u due to full queue (%u entries)\n",
+         ntohs (msg->type), ntohs (msg->size), (unsigned int) nc->queue_length);
+    return;                     /* drop! */
+  }
   if (client->num_pending > nc->queue_length)
   if (client->num_pending > nc->queue_length)
-    {
-      /* FIXME: consider checking for other messages in the
-        queue that are 'droppable' */
-    }
+  {
+    /* FIXME: consider checking for other messages in the
+     * queue that are 'droppable' */
+  }
   client->num_pending++;
   size = ntohs (msg->size);
   pml = GNUNET_malloc (sizeof (struct PendingMessageList) + size);
   client->num_pending++;
   size = ntohs (msg->size);
   pml = GNUNET_malloc (sizeof (struct PendingMessageList) + size);
-  pml->msg = (const struct GNUNET_MessageHeader*) &pml[1];
-  pml->can_drop = can_drop; 
-#if DEBUG_SERVER_NC
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-             "Adding message of type %u and size %u to pending queue (which has %u entries)\n",
-             ntohs (msg->type),
-             ntohs (msg->size),
-             (unsigned int) nc->queue_length);
-#endif
+  pml->msg = (const struct GNUNET_MessageHeader *) &pml[1];
+  pml->can_drop = can_drop;
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Adding message of type %u and size %u to pending queue (which has %u entries)\n",
+       ntohs (msg->type),
+       ntohs (msg->size),
+       (unsigned int) nc->queue_length);
   memcpy (&pml[1], msg, size);
   /* append */
   GNUNET_CONTAINER_DLL_insert_tail (client->pending_head,
   memcpy (&pml[1], msg, size);
   /* append */
   GNUNET_CONTAINER_DLL_insert_tail (client->pending_head,
-                                   client->pending_tail,
-                                   pml);
-  if (client->th == NULL)
-    client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
-                                                     ntohs (client->pending_head->msg->size),
-                                                     GNUNET_TIME_UNIT_FOREVER_REL,
-                                                     &transmit_message,
-                                                     client);
-} 
+                                    client->pending_tail,
+                                    pml);
+  if (NULL == client->th)
+    client->th =
+        GNUNET_SERVER_notify_transmit_ready (client->client,
+                                             ntohs (client->pending_head->
+                                                    msg->size),
+                                             GNUNET_TIME_UNIT_FOREVER_REL,
+                                             &transmit_message, client);
+}
 
 
 /**
 
 
 /**
@@ -415,21 +417,17 @@ do_unicast (struct GNUNET_SERVER_NotificationContext *nc,
  */
 void
 GNUNET_SERVER_notification_context_unicast (struct GNUNET_SERVER_NotificationContext *nc,
  */
 void
 GNUNET_SERVER_notification_context_unicast (struct GNUNET_SERVER_NotificationContext *nc,
-                                           struct GNUNET_SERVER_Client *client,
-                                           const struct GNUNET_MessageHeader *msg,
-                                           int can_drop)
+                                            struct GNUNET_SERVER_Client *client,
+                                            const struct GNUNET_MessageHeader *msg,
+                                            int can_drop)
 {
   struct ClientList *pos;
 {
   struct ClientList *pos;
-  
-  pos = nc->clients;
-  while (NULL != pos)
-    {
-      if (pos->client == client)
-       break;
-      pos = pos->next;
-    }
-  GNUNET_assert (pos != NULL);
-  do_unicast (nc, pos, msg, can_drop); 
+
+  for (pos = nc->clients_head; NULL != pos; pos = pos->next)
+    if (pos->client == client)
+      break;
+  GNUNET_assert (NULL != pos);
+  do_unicast (nc, pos, msg, can_drop);
 }
 
 
 }
 
 
@@ -441,19 +439,34 @@ GNUNET_SERVER_notification_context_unicast (struct GNUNET_SERVER_NotificationCon
  * @param can_drop can this message be dropped due to queue length limitations
  */
 void
  * @param can_drop can this message be dropped due to queue length limitations
  */
 void
-GNUNET_SERVER_notification_context_broadcast (struct GNUNET_SERVER_NotificationContext *nc,
-                                             const struct GNUNET_MessageHeader *msg,
-                                             int can_drop)
+GNUNET_SERVER_notification_context_broadcast (struct
+                                              GNUNET_SERVER_NotificationContext *nc,
+                                              const struct GNUNET_MessageHeader *msg,
+                                              int can_drop)
 {
   struct ClientList *pos;
 {
   struct ClientList *pos;
-  
-  pos = nc->clients;
-  while (NULL != pos)
-    {
-      do_unicast (nc, pos, msg, can_drop);
-      pos = pos->next;
-    }
+
+  for (pos = nc->clients_head; NULL != pos; pos = pos->next)
+    do_unicast (nc, pos, msg, can_drop);
 }
 
 
 }
 
 
+/**
+ * Return active number of subscribers in this context.
+ *
+ * @param nc context to query
+ * @return number of current subscribers
+ */
+unsigned int
+GNUNET_SERVER_notification_context_get_size (struct GNUNET_SERVER_NotificationContext *nc)
+{
+  unsigned int num;
+  struct ClientList *pos;
+
+  num = 0;
+  for (pos = nc->clients_head; NULL != pos; pos = pos->next)
+    num++;
+  return num;
+}
+
 /* end of server_nc.c */
 /* end of server_nc.c */