free in proper place
[oweals/gnunet.git] / src / testing / testing_group.c
index 88408e871fed388b6d68ffe67bd9413b8624ade1..f9b3cc3fc51eeb8c6dfac8da260999525c387d3e 100644 (file)
@@ -44,7 +44,7 @@
  * enough to not conflict with client-ports (typically starting around
  * 32k).
  */
-#define LOW_PORT 10000
+#define LOW_PORT 12000
 
 /**
  * Highest port used for GNUnet testing.  Should be low enough to not
@@ -56,8 +56,6 @@
 /* Maximum time to delay connect attempt */
 #define MAX_CONNECT_DELAY 300
 
-#define MAX_CONCURRENT_HOSTKEYS 500
-
 /**
  * Which list of peers do we need to modify?
  */
@@ -365,6 +363,23 @@ struct ChurnRestartContext
   struct GNUNET_TIME_Relative timeout;
 };
 
+struct OutstandingSSH
+{
+  struct OutstandingSSH *next;
+
+  struct OutstandingSSH *prev;
+
+  /**
+   * Number of current ssh connections.
+   */
+  uint32_t outstanding;
+
+  /**
+   * The hostname of this peer.
+   */
+  const char *hostname;
+};
+
 /**
  * Data we keep per peer.
  */
@@ -655,6 +670,11 @@ struct GNUNET_TESTING_PeerGroup
    */
   unsigned int max_outstanding_connections;
 
+  /**
+   * Number of ssh connections to peers (max).
+   */
+  unsigned int max_concurrent_ssh;
+
   /**
    * Number of connects we are waiting on, allows us to rate limit
    * connect attempts.
@@ -670,6 +690,18 @@ struct GNUNET_TESTING_PeerGroup
    * Hostkeys loaded from a file.
    */
   char *hostkey_data;
+
+  /**
+   * Head of DLL to keep track of the number of outstanding
+   * ssh connections per peer.
+   */
+  struct OutstandingSSH *ssh_head;
+
+  /**
+   * Tail of DLL to keep track of the number of outstanding
+   * ssh connections per peer.
+   */
+  struct OutstandingSSH *ssh_tail;
 };
 
 struct UpdateContext
@@ -1125,6 +1157,7 @@ update_config (void *cls,
  * out of "*port" numbers, return NULL.
  *
  * @param cfg template configuration
+ * @param off the current peer offset
  * @param port port numbers to use, update to reflect
  *             port numbers that were used
  * @param upnum number to make unix domain socket names unique
@@ -1136,6 +1169,7 @@ update_config (void *cls,
  */
 static struct GNUNET_CONFIGURATION_Handle *
 make_config (const struct GNUNET_CONFIGURATION_Handle *cfg,
+             uint32_t off,
              uint16_t * port,
              uint32_t * upnum, const char *hostname, uint32_t * fdnum)
 {
@@ -1143,6 +1177,7 @@ make_config (const struct GNUNET_CONFIGURATION_Handle *cfg,
   uint16_t orig;
   char *control_host;
   char *allowed_hosts;
+  unsigned long long temp_port;
 
   orig = *port;
   uc.nport = *port;
@@ -1171,20 +1206,28 @@ make_config (const struct GNUNET_CONFIGURATION_Handle *cfg,
 
       GNUNET_CONFIGURATION_set_value_string (uc.ret, "core", "ACCEPT_FROM",
                                              allowed_hosts);
-      GNUNET_CONFIGURATION_set_value_string (uc.ret, "core", "UNIXPATH",
-                                             "");
       GNUNET_CONFIGURATION_set_value_string (uc.ret, "transport",
                                              "ACCEPT_FROM", allowed_hosts);
-      GNUNET_CONFIGURATION_set_value_string (uc.ret, "transport", "UNIXPATH",
-                                             "");
       GNUNET_CONFIGURATION_set_value_string (uc.ret, "dht", "ACCEPT_FROM",
                                              allowed_hosts);
-      GNUNET_CONFIGURATION_set_value_string (uc.ret, "dht", "UNIXPATH",
-                                             "");
       GNUNET_CONFIGURATION_set_value_string (uc.ret, "statistics",
                                              "ACCEPT_FROM", allowed_hosts);
-      GNUNET_CONFIGURATION_set_value_string (uc.ret, "statistics", "UNIXPATH",
-                                             "");
+
+      GNUNET_CONFIGURATION_set_value_string (uc.ret, "core", "UNIXPATH", "");
+      GNUNET_CONFIGURATION_set_value_string (uc.ret, "transport", "UNIXPATH", "");
+      GNUNET_CONFIGURATION_set_value_string (uc.ret, "dht", "UNIXPATH", "");
+      GNUNET_CONFIGURATION_set_value_string (uc.ret, "statistics", "UNIXPATH", "");
+
+
+      if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(uc.orig, "statistics", "port", &temp_port) &&
+          (temp_port != 0) &&
+          (GNUNET_YES !=
+              GNUNET_CONFIGURATION_get_value_yesno (uc.orig, "testing",
+                                                    "single_statistics_per_host")))
+        {
+          GNUNET_CONFIGURATION_set_value_number (uc.ret, "statistics", "port", temp_port + off);
+        }
+
       GNUNET_free_non_null (control_host);
       GNUNET_free (allowed_hosts);
     }
@@ -2496,11 +2539,15 @@ create_and_copy_friend_files (struct GNUNET_TESTING_PeerGroup *pg)
   struct GNUNET_OS_Process **procarr;
   char *arg;
   char *mytemp;
+#if NOT_STUPID
   enum GNUNET_OS_ProcessStatusType type;
   unsigned long return_code;
   int count;
-  int ret;
   int max_wait = 10;
+#endif
+  int ret;
+
+  ret = GNUNET_OK;
 #if OLD
   struct GNUNET_CRYPTO_HashAsciiEncoded peer_enc;
   struct PeerConnection *conn_iter;
@@ -2572,6 +2619,11 @@ create_and_copy_friend_files (struct GNUNET_TESTING_PeerGroup *pg)
             GNUNET_OS_start_process (NULL, NULL, "scp", "scp", mytemp, arg,
                                      NULL);
 
+          ret = GNUNET_OS_process_wait(procarr[pg_iter]); /* FIXME: schedule this, throttle! */
+          GNUNET_OS_process_close (procarr[pg_iter]);
+          if (ret != GNUNET_OK)
+            return ret;
+          procarr[pg_iter] = NULL;
 #if VERBOSE_TESTING
           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                       _("Copying file with command scp %s %s\n"), mytemp,
@@ -2583,6 +2635,7 @@ create_and_copy_friend_files (struct GNUNET_TESTING_PeerGroup *pg)
       GNUNET_free (mytemp);
     }
 
+#if NOT_STUPID
   count = 0;
   ret = GNUNET_SYSERR;
   while ((count < max_wait) && (ret != GNUNET_OK))
@@ -2628,6 +2681,7 @@ create_and_copy_friend_files (struct GNUNET_TESTING_PeerGroup *pg)
 #if VERBOSE_TESTING
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               _("Finished copying all friend files!\n"));
+#endif
 #endif
   GNUNET_free (procarr);
   return ret;
@@ -2763,6 +2817,8 @@ create_and_copy_blacklist_files (struct GNUNET_TESTING_PeerGroup *pg,
             GNUNET_OS_start_process (NULL, NULL, "scp", "scp", mytemp, arg,
                                      NULL);
 
+          GNUNET_OS_process_wait(procarr[pg_iter]); /* FIXME: add scheduled blacklist file copy that parallelizes file copying! */
+
 #if VERBOSE_TESTING
           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                       _("Copying file with command scp %s %s\n"), mytemp,
@@ -3064,9 +3120,6 @@ connect_topology (struct GNUNET_TESTING_PeerGroup *pg,
   struct ConnectTopologyContext *ct_ctx;
 #if OLD
   struct PeerConnection *connection_iter;
-#else
-  struct ConnectContext *connect_context;
-  int ret;
 #endif
 
   total = 0;
@@ -3100,53 +3153,12 @@ connect_topology (struct GNUNET_TESTING_PeerGroup *pg,
   ct_ctx->remaining_connections = total;
   ct_ctx->remaining_connects_to_schedule = total;
 
-
-  /**
-   * FIXME: iterating over peer lists in this way means that a single peer will have
-   * all of its connections scheduled basically at once.  This means a single peer
-   * will have a lot of work to do, and may slow down the connection process.  If
-   * we could choose a connection *randomly* that would work much better.
-   *
-   * Even using the hashmap method we still choose all of a single peers connections.
-   *
-   * Will we incur a serious performance penalty iterating over the lists a bunch of
-   * times?  Probably not compared to the delays in connecting peers.  Can't hurt
-   * to try anyhow...
-   */
   for (pg_iter = 0; pg_iter < pg->max_outstanding_connections; pg_iter++)
   {
     preschedule_connect(ct_ctx);
   }
   return total;
 
-#if SLOW
-  total = 0;
-  for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
-    {
-#if OLD
-      connection_iter = pg->peers[pg_iter].connect_peers_head;
-      while (connection_iter != NULL)
-        {
-          GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Scheduling connect of peer %d to peer %d\n", pg_iter, connection_iter->index);
-          connect_context = GNUNET_malloc (sizeof (struct ConnectContext));
-          connect_context->first = pg->peers[pg_iter].daemon;
-          connect_context->second = pg->peers[connection_iter->index].daemon;
-          connect_context->ct_ctx = ct_ctx;
-          GNUNET_SCHEDULER_add_now (&schedule_connect, connect_context);
-          connection_iter = connection_iter->next;
-          total++;
-        }
-#else
-      ret =
-        GNUNET_CONTAINER_multihashmap_iterate (pg->
-                                               peers[pg_iter].connect_peers,
-                                               &connect_iterator, ct_ctx);
-      GNUNET_assert (GNUNET_SYSERR != ret && ret >= 0);
-      total = total + ret;
-#endif
-    }
-  return total;
-#endif
 }
 
 
@@ -4594,6 +4606,63 @@ GNUNET_TESTING_connect_topology (struct GNUNET_TESTING_PeerGroup *pg,
   return connect_topology (pg, connect_timeout, connect_attempts, notify_callback, notify_cls);
 }
 
+/**
+ * Lookup and return the number of SSH connections to a host.
+ *
+ * @param hostname the hostname to lookup in the list
+ * @param pg the peergroup that the host belongs to
+ *
+ * @return the number of current ssh connections to the host
+ */
+static unsigned int
+count_outstanding_at_host(const char *hostname, struct GNUNET_TESTING_PeerGroup *pg)
+{
+  struct OutstandingSSH *pos;
+  pos = pg->ssh_head;
+  while ((pos != NULL) && (strcmp(pos->hostname, hostname) != 0))
+    pos = pos->next;
+  GNUNET_assert(pos != NULL);
+  return pos->outstanding;
+}
+
+
+/**
+ * Increment the number of SSH connections to a host by one.
+ *
+ * @param hostname the hostname to lookup in the list
+ * @param pg the peergroup that the host belongs to
+ *
+ */
+static void
+increment_outstanding_at_host(const char *hostname, struct GNUNET_TESTING_PeerGroup *pg)
+{
+  struct OutstandingSSH *pos;
+  pos = pg->ssh_head;
+  while ((pos != NULL) && (strcmp(pos->hostname, hostname) != 0))
+    pos = pos->next;
+  GNUNET_assert(pos != NULL);
+  pos->outstanding++;
+}
+
+/**
+ * Decrement the number of SSH connections to a host by one.
+ *
+ * @param hostname the hostname to lookup in the list
+ * @param pg the peergroup that the host belongs to
+ *
+ */
+static void
+decrement_outstanding_at_host(const char *hostname, struct GNUNET_TESTING_PeerGroup *pg)
+{
+  struct OutstandingSSH *pos;
+  pos = pg->ssh_head;
+  while ((pos != NULL) && (strcmp(pos->hostname, hostname) != 0))
+    pos = pos->next;
+  GNUNET_assert(pos != NULL);
+  pos->outstanding--;
+}
+
+
 /**
  * Callback that is called whenever a hostkey is generated
  * for a peer.  Call the real callback and decrement the
@@ -4612,6 +4681,8 @@ internal_hostkey_callback (void *cls,
   struct InternalStartContext *internal_context = cls;
   internal_context->peer->pg->starting--;
   internal_context->peer->pg->started++;
+  if (internal_context->hostname != NULL)
+    decrement_outstanding_at_host(internal_context->hostname, internal_context->peer->pg);
   if (internal_context->hostkey_callback != NULL)
     internal_context->hostkey_callback (internal_context->hostkey_cls, id, d,
                                         emsg);
@@ -4642,6 +4713,8 @@ internal_startup_callback (void *cls,
 {
   struct InternalStartContext *internal_context = cls;
   internal_context->peer->pg->starting--;
+  if (internal_context->hostname != NULL)
+    decrement_outstanding_at_host(internal_context->hostname, internal_context->peer->pg);
   if (internal_context->start_cb != NULL)
     internal_context->start_cb (internal_context->start_cb_cls, id, cfg, d,
                                 emsg);
@@ -4658,8 +4731,12 @@ internal_continue_startup (void *cls,
       return;
     }
 
-  if (internal_context->peer->pg->starting < internal_context->peer->pg->max_outstanding_connections)
+  if ((internal_context->peer->pg->starting < internal_context->peer->pg->max_concurrent_ssh) ||
+      ((internal_context->hostname != NULL) &&
+       (count_outstanding_at_host(internal_context->hostname, internal_context->peer->pg) < internal_context->peer->pg->max_concurrent_ssh)))
     {
+      if (internal_context->hostname != NULL)
+        increment_outstanding_at_host(internal_context->hostname, internal_context->peer->pg);
       internal_context->peer->pg->starting++;
       GNUNET_TESTING_daemon_continue_startup (internal_context->peer->daemon);
     }
@@ -4741,7 +4818,7 @@ schedule_churn_restart (void *cls,
   struct ChurnRestartContext *startup_ctx =
     peer_restart_ctx->churn_restart_ctx;
 
-  if (startup_ctx->outstanding > startup_ctx->pg->max_outstanding_connections)
+  if (startup_ctx->outstanding > startup_ctx->pg->max_concurrent_ssh)
     GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
                                   (GNUNET_TIME_UNIT_MILLISECONDS, 100),
                                   &schedule_churn_restart, peer_restart_ctx);
@@ -4755,6 +4832,8 @@ schedule_churn_restart (void *cls,
     }
 }
 
+
+
 static void
 internal_start (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
@@ -4765,8 +4844,12 @@ internal_start (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
       return;
     }
 
-  if (internal_context->peer->pg->starting < MAX_CONCURRENT_HOSTKEYS)
+  if ((internal_context->peer->pg->starting < internal_context->peer->pg->max_concurrent_ssh) ||
+      ((internal_context->hostname != NULL) &&
+       (count_outstanding_at_host(internal_context->hostname, internal_context->peer->pg) < internal_context->peer->pg->max_concurrent_ssh)))
     {
+      if (internal_context->hostname != NULL)
+        increment_outstanding_at_host(internal_context->hostname, internal_context->peer->pg);
       internal_context->peer->pg->starting++;
       internal_context->peer->daemon =
         GNUNET_TESTING_daemon_start (internal_context->peer->cfg,
@@ -4818,7 +4901,9 @@ GNUNET_TESTING_daemons_continue_startup (struct GNUNET_TESTING_PeerGroup *pg)
  * @param cfg configuration template to use
  * @param total number of daemons to start
  * @param max_concurrent_connections for testing, how many peers can
- *                                   we connect to simultaneously
+*                                   we connect to simultaneously
+ * @param max_concurrent_ssh when starting with ssh, how many ssh
+ *        connections will we allow at once (based on remote hosts allowed!)
  * @param timeout total time allowed for peers to start
  * @param hostkey_callback function to call on each peers hostkey generation
  *        if NULL, peers will be started by this call, if non-null,
@@ -4838,6 +4923,7 @@ struct GNUNET_TESTING_PeerGroup *
 GNUNET_TESTING_daemons_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
                               unsigned int total,
                               unsigned int max_concurrent_connections,
+                              unsigned int max_concurrent_ssh,
                               struct GNUNET_TIME_Relative timeout,
                               GNUNET_TESTING_NotifyHostkeyCreated
                               hostkey_callback, void *hostkey_cls,
@@ -4891,6 +4977,7 @@ GNUNET_TESTING_daemons_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
   pg->max_timeout = GNUNET_TIME_relative_to_absolute (timeout);
   pg->peers = GNUNET_malloc (total * sizeof (struct PeerData));
   pg->max_outstanding_connections = max_concurrent_connections;
+  pg->max_concurrent_ssh = max_concurrent_ssh;
   if (NULL != hostnames)
     {
       off = 0;
@@ -4979,7 +5066,10 @@ GNUNET_TESTING_daemons_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
                                                                     &baseservicehome));
   for (i = 0; i < pg->num_hosts; i++)
     {
-
+      struct OutstandingSSH *ssh_entry;
+      ssh_entry = GNUNET_malloc(sizeof(struct OutstandingSSH));
+      ssh_entry->hostname = pg->hosts[i].hostname; /* Don't free! */
+      GNUNET_CONTAINER_DLL_insert(pg->ssh_head, pg->ssh_tail, ssh_entry);
       if (NULL != pg->hosts[i].username)
         GNUNET_asprintf (&arg, "%s@%s", pg->hosts[i].username, pg->hosts[i].hostname);
       else
@@ -5047,6 +5137,7 @@ GNUNET_TESTING_daemons_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
           username = pg->hosts[off % hostcnt].username;
           sshport = pg->hosts[off % hostcnt].sshport;
           pcfg = make_config (cfg,
+                              off,
                               &pg->hosts[off % hostcnt].minport,
                               &upnum, hostname, &fdnum);
         }
@@ -5055,7 +5146,7 @@ GNUNET_TESTING_daemons_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
           hostname = NULL;
           username = NULL;
           sshport = 0;
-          pcfg = make_config (cfg, &minport, &upnum, hostname, &fdnum);
+          pcfg = make_config (cfg, off, &minport, &upnum, hostname, &fdnum);
         }
 
       if (NULL == pcfg)
@@ -5296,7 +5387,7 @@ schedule_churn_shutdown_task (void *cls,
   shutdown_ctx = peer_shutdown_ctx->shutdown_ctx;
   GNUNET_assert (shutdown_ctx != NULL);
   churn_ctx = (struct ChurnContext *)shutdown_ctx->cb_cls;
-  if (shutdown_ctx->outstanding > churn_ctx->pg->max_outstanding_connections)
+  if (shutdown_ctx->outstanding > churn_ctx->pg->max_concurrent_ssh)
     GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
                                   (GNUNET_TIME_UNIT_MILLISECONDS, 100),
                                   &schedule_churn_shutdown_task,
@@ -5603,6 +5694,7 @@ void
 internal_shutdown_callback (void *cls, const char *emsg)
 {
   struct ShutdownContext *shutdown_ctx = cls;
+  unsigned int off;
 
   shutdown_ctx->outstanding--;
   if (emsg == NULL)
@@ -5623,6 +5715,17 @@ internal_shutdown_callback (void *cls, const char *emsg)
                           "Not all peers successfully shut down!");
       else
         shutdown_ctx->cb (shutdown_ctx->cb_cls, NULL);
+
+      GNUNET_free (shutdown_ctx->pg->peers);
+      GNUNET_free_non_null(shutdown_ctx->pg->hostkey_data);
+      for (off = 0; off < shutdown_ctx->pg->num_hosts; off++)
+        {
+          GNUNET_free (shutdown_ctx->pg->hosts[off].hostname);
+          GNUNET_free_non_null (shutdown_ctx->pg->hosts[off].username);
+        }
+      GNUNET_free_non_null (shutdown_ctx->pg->hosts);
+      GNUNET_free (shutdown_ctx->pg);
+
       GNUNET_free (shutdown_ctx);
     }
 }
@@ -5646,7 +5749,7 @@ schedule_shutdown_task (void *cls,
   shutdown_ctx = peer_shutdown_ctx->shutdown_ctx;
   GNUNET_assert (shutdown_ctx != NULL);
 
-  if (shutdown_ctx->outstanding > shutdown_ctx->pg->max_outstanding_connections)
+  if (shutdown_ctx->outstanding > shutdown_ctx->pg->max_concurrent_ssh)
     GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
                                   (GNUNET_TIME_UNIT_MILLISECONDS, 100),
                                   &schedule_shutdown_task, peer_shutdown_ctx);
@@ -5744,15 +5847,7 @@ GNUNET_TESTING_daemons_stop (struct GNUNET_TESTING_PeerGroup *pg,
                                                peers[off].blacklisted_peers);
 #endif
     }
-  GNUNET_free (pg->peers);
-  GNUNET_free_non_null(pg->hostkey_data);
-  for (off = 0; off < pg->num_hosts; off++)
-    {
-      GNUNET_free (pg->hosts[off].hostname);
-      GNUNET_free_non_null (pg->hosts[off].username);
-    }
-  GNUNET_free_non_null (pg->hosts);
-  GNUNET_free (pg);
+
 }