-ensure stats queues do not grow too big
[oweals/gnunet.git] / src / testbed / gnunet-service-testbed.c
index f3d629f5f8b63064a544d8b420694b6a628b893b..8a286742c60688c369dbc56394dafd4e1468ead9 100644 (file)
@@ -1,10 +1,10 @@
 /*
   This file is part of GNUnet.
-  (C) 2008--2013 Christian Grothoff (and other contributing authors)
+  Copyright (C) 2008--2013 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
-  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
@@ -14,8 +14,8 @@
 
   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.
 */
 
 /**
@@ -25,7 +25,8 @@
  */
 
 #include "gnunet-service-testbed.h"
-
+#include "gnunet-service-testbed_barriers.h"
+#include "gnunet-service-testbed_connectionpool.h"
 
 /***********/
 /* Globals */
@@ -34,7 +35,7 @@
 /**
  * Our configuration
  */
-struct GNUNET_CONFIGURATION_Handle *our_config;
+struct GNUNET_CONFIGURATION_Handle *GST_config;
 
 /**
  * The master context; generated with the first INIT message
@@ -128,12 +129,6 @@ static struct MessageQueue *mq_head;
 static struct MessageQueue *mq_tail;
 
 
-/**
- * The shutdown task handle
- */
-static GNUNET_SCHEDULER_TaskIdentifier shutdown_task_id;
-
-
 /**
  * Function called to notify a client about the connection begin ready to queue
  * more data.  "buf" will be NULL and "size" zero if the connection was closed
@@ -190,7 +185,7 @@ GST_queue_message (struct GNUNET_SERVER_Client *client,
   size = ntohs (msg->size);
   GNUNET_assert ((GNUNET_MESSAGE_TYPE_TESTBED_INIT <= type) &&
                  (GNUNET_MESSAGE_TYPE_TESTBED_MAX > type));
-  mq_entry = GNUNET_malloc (sizeof (struct MessageQueue));
+  mq_entry = GNUNET_new (struct MessageQueue);
   mq_entry->msg = msg;
   mq_entry->client = client;
   GNUNET_SERVER_client_keep (client);
@@ -363,7 +358,7 @@ GST_queue_host_registration (struct Slave *slave,
        "Queueing host registration for host %u at %u\n",
        GNUNET_TESTBED_host_get_id_ (host),
        GNUNET_TESTBED_host_get_id_ (GST_host_list[slave->host_id]));
-  hr = GNUNET_malloc (sizeof (struct HostRegistration));
+  hr = GNUNET_new (struct HostRegistration);
   hr->cb = cb;
   hr->cb_cls = cb_cls;
   hr->host = host;
@@ -404,11 +399,9 @@ GST_forwarded_operation_reply_relay (void *cls,
  * Task to free resources when forwarded operation has been timedout
  *
  * @param cls the ForwardedOperationContext
- * @param tc the task context from scheduler
  */
 void
-GST_forwarded_operation_timeout (void *cls,
-                                 const struct GNUNET_SCHEDULER_TaskContext *tc)
+GST_forwarded_operation_timeout (void *cls)
 {
   struct ForwardedOperationContext *fopc = cls;
 
@@ -445,7 +438,7 @@ parse_shared_services (char *ss_str, struct GNUNET_CONFIGURATION_Handle *cfg)
     (void) memcpy (&slist[n - 1], &ss,                                  \
                    sizeof (struct GNUNET_TESTING_SharedService));       \
   } while (0)
-  
+
   slist = NULL;
   n = 0;
   ss.cfg = cfg;
@@ -473,48 +466,6 @@ parse_shared_services (char *ss_str, struct GNUNET_CONFIGURATION_Handle *cfg)
 }
 
 
-/**
- * Callback function invoked for each interface found.
- *
- * @param cls NULL
- * @param name name of the interface (can be NULL for unknown)
- * @param isDefault is this presumably the default interface
- * @param addr address of this interface (can be NULL for unknown or unassigned)
- * @param broadcast_addr the broadcast address (can be NULL for unknown or unassigned)
- * @param netmask the network mask (can be NULL for unknown or unassigned))
- * @param addrlen length of the address
- * @return GNUNET_OK to continue iteration, GNUNET_SYSERR to abort
- */
-static int 
-addr_proc (void *cls, const char *name, int isDefault,
-           const struct sockaddr *addr,
-           const struct sockaddr *broadcast_addr,
-           const struct sockaddr *netmask, socklen_t addrlen)
-{
-  struct Context *ctx = cls;
-  const struct sockaddr_in *in_addr;
-  char *ipaddr;
-  char *tmp;  
-
-  if (sizeof (struct sockaddr_in) != addrlen)
-    return GNUNET_OK;
-  in_addr = (const struct sockaddr_in *) addr;
-  if (NULL == (ipaddr = inet_ntoa (in_addr->sin_addr)))
-    return GNUNET_OK;
-  if (NULL == ctx->master_ips)
-  {
-    ctx->master_ips = GNUNET_strdup (ipaddr);
-    return GNUNET_OK;
-  }
-  tmp = NULL;
-  (void) GNUNET_asprintf (&tmp, "%s; %s", ctx->master_ips, ipaddr);
-  GNUNET_free (ctx->master_ips);
-  ctx->master_ips = tmp;
-  return GNUNET_OK;
-}
-
-
-
 /**
  * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_INIT messages
  *
@@ -523,16 +474,17 @@ addr_proc (void *cls, const char *name, int isDefault,
  * @param message the actual message
  */
 static void
-handle_init (void *cls, struct GNUNET_SERVER_Client *client,
+handle_init (void *cls,
+            struct GNUNET_SERVER_Client *client,
              const struct GNUNET_MessageHeader *message)
 {
   const struct GNUNET_TESTBED_InitMessage *msg;
   struct GNUNET_TESTBED_Host *host;
+  const char *controller_hostname;
   char *ss_str;
   struct GNUNET_TESTING_SharedService *ss;
-  char *hostname;
   unsigned int cnt;
-  unsigned int len;
+  uint16_t msize;
 
   if (NULL != GST_context)
   {
@@ -541,40 +493,39 @@ handle_init (void *cls, struct GNUNET_SERVER_Client *client,
     return;
   }
   msg = (const struct GNUNET_TESTBED_InitMessage *) message;
-  len = GNUNET_OS_get_hostname_max_length ();
-  hostname = GNUNET_malloc (len);
-  if (0 != gethostname (hostname, len))
+  msize = ntohs (message->size);
+  if (msize <= sizeof (struct GNUNET_TESTBED_InitMessage))
+  {
+    GNUNET_break (0);
+    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+    return;
+  }
+  msize -= sizeof (struct GNUNET_TESTBED_InitMessage);
+  controller_hostname = (const char *) &msg[1];
+  if ('\0' != controller_hostname[msize - 1])
   {
-    GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "gethostname");
+    GNUNET_break (0);
     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
     return;
   }
   ss_str = NULL;
   ss = NULL;
-  if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (our_config, "TESTBED",
+  if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (GST_config, "TESTBED",
                                                           "SHARED_SERVICES",
                                                           &ss_str))
   {
-    ss = parse_shared_services (ss_str, our_config);
+    ss = parse_shared_services (ss_str, GST_config);
     GNUNET_free (ss_str);
     ss_str = NULL;
   }
-  GST_context = GNUNET_malloc (sizeof (struct Context));
+  GST_context = GNUNET_new (struct Context);
   GNUNET_SERVER_client_keep (client);
   GST_context->client = client;
   GST_context->host_id = ntohl (msg->host_id);
-  GNUNET_OS_network_interfaces_list (&addr_proc, GST_context);
-  if (NULL == GST_context->master_ips)
-  {
-    LOG (GNUNET_ERROR_TYPE_ERROR, 
-         "Testbed needs networking, but no network interfaces are found on this host.  Exiting\n");
-    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
-    GNUNET_SCHEDULER_shutdown ();
-    return;
-  }
-  LOG_DEBUG ("Our IP addresses: %s\n", GST_context->master_ips);
+  GST_context->master_ip = GNUNET_strdup (controller_hostname);
+  LOG_DEBUG ("Our IP: %s\n", GST_context->master_ip);
   GST_context->system =
-      GNUNET_TESTING_system_create ("testbed", GST_context->master_ips,
+      GNUNET_TESTING_system_create ("testbed", GST_context->master_ip,
                                     hostname, ss);
   if (NULL != ss)
   {
@@ -586,9 +537,10 @@ handle_init (void *cls, struct GNUNET_SERVER_Client *client,
     GNUNET_free (ss);
     ss = NULL;
   }
-
-  host = GNUNET_TESTBED_host_create_with_id (GST_context->host_id, hostname,
-                                             NULL, our_config, 0);
+  host =
+      GNUNET_TESTBED_host_create_with_id (GST_context->host_id,
+                                          GST_context->master_ip, NULL,
+                                          GST_config, 0);
   host_list_add (host);
   LOG_DEBUG ("Created master context with host ID: %u\n", GST_context->host_id);
   GNUNET_SERVER_receive_done (client, GNUNET_OK);
@@ -596,14 +548,15 @@ handle_init (void *cls, struct GNUNET_SERVER_Client *client,
 
 
 /**
- * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST messages
+ * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST messages
  *
  * @param cls NULL
  * @param client identification of the client
  * @param message the actual message
  */
 static void
-handle_add_host (void *cls, struct GNUNET_SERVER_Client *client,
+handle_add_host (void *cls,
+                struct GNUNET_SERVER_Client *client,
                  const struct GNUNET_MessageHeader *message)
 {
   struct GNUNET_TESTBED_Host *host;
@@ -631,7 +584,7 @@ handle_add_host (void *cls, struct GNUNET_SERVER_Client *client,
   username_length = ntohs (msg->username_length);
   hostname_length = ntohs (msg->hostname_length);
   /* msg must contain hostname */
-  if ((msize <= (sizeof (struct GNUNET_TESTBED_AddHostMessage) + 
+  if ((msize <= (sizeof (struct GNUNET_TESTBED_AddHostMessage) +
                  username_length))
       || (0 == hostname_length))
   {
@@ -658,7 +611,6 @@ handle_add_host (void *cls, struct GNUNET_SERVER_Client *client,
   }
   hostname = GNUNET_malloc (hostname_length + 1);
   strncpy (hostname, ptr, hostname_length);
-  ptr += hostname_length;
   if (NULL == (host_cfg = GNUNET_TESTBED_extract_config_ (message)))
   {
     GNUNET_free_non_null (username);
@@ -713,14 +665,15 @@ handle_add_host (void *cls, struct GNUNET_SERVER_Client *client,
 
 
 /**
- * Handler for GNUNET_MESSAGE_TYPE_TESTBED_GETSLAVECONFIG messages
+ * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_GETSLAVECONFIG messages
  *
  * @param cls NULL
  * @param client identification of the client
  * @param message the actual message
  */
 static void
-handle_slave_get_config (void *cls, struct GNUNET_SERVER_Client *client,
+handle_slave_get_config (void *cls,
+                        struct GNUNET_SERVER_Client *client,
                          const struct GNUNET_MessageHeader *message)
 {
   struct GNUNET_TESTBED_SlaveGetConfigurationMessage *msg;
@@ -773,12 +726,12 @@ void
 GST_clear_fopcq ()
 {
   struct ForwardedOperationContext *fopc;
-  
+
   while (NULL != (fopc = fopcq_head))
   {
     GNUNET_CONTAINER_DLL_remove (fopcq_head, fopcq_tail, fopc);
     GNUNET_TESTBED_forward_operation_msg_cancel_ (fopc->opc);
-    if (GNUNET_SCHEDULER_NO_TASK != fopc->timeout_task)
+    if (NULL != fopc->timeout_task)
       GNUNET_SCHEDULER_cancel (fopc->timeout_task);
     GNUNET_SERVER_client_drop (fopc->client);
     switch (fopc->type)
@@ -789,7 +742,7 @@ GST_clear_fopcq ()
     case OP_SHUTDOWN_PEERS:
       {
         struct HandlerContext_ShutdownPeers *hc = fopc->cls;
-        
+
         GNUNET_assert (0 < hc->nslaves);
         hc->nslaves--;
         if (0 == hc->nslaves)
@@ -818,15 +771,13 @@ GST_clear_fopcq ()
  * Task to clean up and shutdown nicely
  *
  * @param cls NULL
- * @param tc the TaskContext from scheduler
  */
 static void
-shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+shutdown_task (void *cls)
 {
   struct MessageQueue *mq_entry;
   uint32_t id;
 
-  shutdown_task_id = GNUNET_SCHEDULER_NO_TASK;
   LOG_DEBUG ("Shutting down testbed service\n");
   /* cleanup any remaining forwarded operations */
   GST_clear_fopcq ();
@@ -850,7 +801,7 @@ shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
   GNUNET_free_non_null (GST_host_list);
   if (NULL != GST_context)
   {
-    GNUNET_free_non_null (GST_context->master_ips);
+    GNUNET_free_non_null (GST_context->master_ip);
     if (NULL != GST_context->system)
       GNUNET_TESTING_system_destroy (GST_context->system, GNUNET_YES);
     GNUNET_SERVER_client_drop (GST_context->client);
@@ -867,12 +818,14 @@ shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
     GNUNET_free (mq_entry);
   }
   GNUNET_free_non_null (hostname);
-  GNUNET_CONFIGURATION_destroy (our_config);
   /* Free hello cache */
   GST_cache_clear ();
+  GST_connection_pool_destroy ();
   GNUNET_TESTBED_operation_queue_destroy_ (GST_opq_openfds);
   GST_opq_openfds = NULL;
   GST_stats_destroy ();
+  GST_barriers_destroy ();
+  GNUNET_CONFIGURATION_destroy (GST_config);
 }
 
 
@@ -912,8 +865,7 @@ testbed_run (void *cls, struct GNUNET_SERVER_Handle *server,
              const struct GNUNET_CONFIGURATION_Handle *cfg)
 {
   static const struct GNUNET_SERVER_MessageHandler message_handlers[] = {
-    {&handle_init, NULL, GNUNET_MESSAGE_TYPE_TESTBED_INIT,
-     sizeof (struct GNUNET_TESTBED_InitMessage)},
+    {&handle_init, NULL, GNUNET_MESSAGE_TYPE_TESTBED_INIT, 0},
     {&handle_add_host, NULL, GNUNET_MESSAGE_TYPE_TESTBED_ADD_HOST, 0},
     {&GST_handle_link_controllers, NULL,
      GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS,
@@ -926,7 +878,7 @@ testbed_run (void *cls, struct GNUNET_SERVER_Handle *server,
     {&GST_handle_peer_stop, NULL, GNUNET_MESSAGE_TYPE_TESTBED_STOP_PEER,
      sizeof (struct GNUNET_TESTBED_PeerStopMessage)},
     {&GST_handle_peer_get_config, NULL,
-     GNUNET_MESSAGE_TYPE_TESTBED_GET_PEER_CONFIGURATION,
+     GNUNET_MESSAGE_TYPE_TESTBED_GET_PEER_INFORMATION,
      sizeof (struct GNUNET_TESTBED_PeerGetConfigurationMessage)},
     {&GST_handle_overlay_connect, NULL,
      GNUNET_MESSAGE_TYPE_TESTBED_OVERLAY_CONNECT,
@@ -940,8 +892,14 @@ testbed_run (void *cls, struct GNUNET_SERVER_Handle *server,
      sizeof (struct GNUNET_TESTBED_SlaveGetConfigurationMessage)},
     {&GST_handle_shutdown_peers, NULL, GNUNET_MESSAGE_TYPE_TESTBED_SHUTDOWN_PEERS,
      sizeof (struct GNUNET_TESTBED_ShutdownPeersMessage)},
-    {&GST_handle_peer_reconfigure, NULL, 
+    {&GST_handle_peer_reconfigure, NULL,
      GNUNET_MESSAGE_TYPE_TESTBED_RECONFIGURE_PEER, 0},
+    {&GST_handle_barrier_init, NULL,
+     GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_INIT, 0},
+    {&GST_handle_barrier_cancel, NULL,
+     GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_CANCEL, 0},
+    {&GST_handle_barrier_status, NULL,
+     GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_STATUS, 0},
     {NULL, NULL, 0, 0}
   };
   char *logfile;
@@ -959,10 +917,12 @@ testbed_run (void *cls, struct GNUNET_SERVER_Handle *server,
                  GNUNET_CONFIGURATION_get_value_number (cfg, "TESTBED",
                                                         "CACHE_SIZE", &num));
   GST_cache_init ((unsigned int) num);
+  GST_connection_pool_init ((unsigned int) num);
   GNUNET_assert (GNUNET_OK ==
                  GNUNET_CONFIGURATION_get_value_number (cfg, "TESTBED",
                                                         "MAX_OPEN_FDS", &num));
-  GST_opq_openfds = GNUNET_TESTBED_operation_queue_create_ ((unsigned int) num);
+  GST_opq_openfds = GNUNET_TESTBED_operation_queue_create_
+      (OPERATION_QUEUE_TYPE_FIXED, (unsigned int) num);
   GNUNET_assert (GNUNET_OK ==
                  GNUNET_CONFIGURATION_get_value_time (cfg, "TESTBED",
                                                       "OPERATION_TIMEOUT",
@@ -972,15 +932,13 @@ testbed_run (void *cls, struct GNUNET_SERVER_Handle *server,
   GNUNET_assert (GNUNET_OK ==
                  GNUNET_CONFIGURATION_get_value_string (cfg, "testbed",
                                                         "HOSTNAME", &hostname));
-  our_config = GNUNET_CONFIGURATION_dup (cfg);
+  GST_config = GNUNET_CONFIGURATION_dup (cfg);
   GNUNET_SERVER_add_handlers (server, message_handlers);
   GNUNET_SERVER_disconnect_notify (server, &client_disconnect_cb, NULL);
-  shutdown_task_id =
-      GNUNET_SCHEDULER_add_delayed_with_priority (GNUNET_TIME_UNIT_FOREVER_REL,
-                                                  GNUNET_SCHEDULER_PRIORITY_IDLE,
-                                                  &shutdown_task, NULL);
+  GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
   LOG_DEBUG ("Testbed startup complete\n");
-  GST_stats_init (our_config);
+  GST_stats_init (GST_config);
+  GST_barriers_init (GST_config);
 }
 
 
@@ -990,9 +948,10 @@ testbed_run (void *cls, struct GNUNET_SERVER_Handle *server,
 int
 main (int argc, char *const *argv)
 {
-  //sleep (15);                 /* Debugging */
   return (GNUNET_OK ==
-          GNUNET_SERVICE_run (argc, argv, "testbed", GNUNET_SERVICE_OPTION_NONE,
+          GNUNET_SERVICE_run (argc, argv,
+                             "testbed",
+                             GNUNET_SERVICE_OPTION_NONE,
                               &testbed_run, NULL)) ? 0 : 1;
 }