Merge branch 'master' of ssh://gnunet.org/gnunet
[oweals/gnunet.git] / src / dht / test_dht_topo.c
index 205f6b99a8b6cb2a3d092914c10b34d80ed07ed0..8be3064f722f36dd8f7c6021142c2aa5fe6f3899 100644 (file)
@@ -1,6 +1,6 @@
 /*
      This file is part of GNUnet.
-     Copyright (C) 2012 GNUnet e.V.
+     Copyright (C) 2012, 2016 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
@@ -71,12 +71,17 @@ static int ok = 1;
 /**
  * Task to do DHT_puts
  */
-static struct GNUNET_SCHEDULER_Task * put_task;
+static struct GNUNET_SCHEDULER_Task *put_task;
+
+/**
+ * Task to do DHT_gets
+ */
+static struct GNUNET_SCHEDULER_Task *get_task;
 
 /**
  * Task to time out / regular shutdown.
  */
-static struct GNUNET_SCHEDULER_Task * timeout_task;
+static struct GNUNET_SCHEDULER_Task *timeout_task;
 
 /**
  * Head of list of active GET operations.
@@ -147,6 +152,39 @@ static struct
 };
 
 
+static struct GNUNET_DHT_TEST_Context *
+stop_ops ()
+{
+  struct GetOperation *get_op;
+  struct GNUNET_DHT_TEST_Context *ctx = NULL;
+
+  if (NULL != timeout_task)
+  {
+    ctx = GNUNET_SCHEDULER_cancel (timeout_task);
+    timeout_task = NULL;
+  }
+  if (NULL != put_task)
+  {
+    GNUNET_SCHEDULER_cancel (put_task);
+    put_task = NULL;
+  }
+  if (NULL != get_task)
+  {
+    GNUNET_SCHEDULER_cancel (get_task);
+    get_task = NULL;
+  }
+  while (NULL != (get_op = get_tail))
+  {
+    GNUNET_DHT_get_stop (get_op->get);
+    GNUNET_CONTAINER_DLL_remove (get_head,
+                                get_tail,
+                                get_op);
+    GNUNET_free (get_op);
+  }
+  return ctx;
+}
+
+
 /**
  * Function called once we're done processing stats.
  *
@@ -163,10 +201,11 @@ stats_finished (void *cls,
   unsigned int i;
 
   if (NULL != op)
-    GNUNET_TESTBED_operation_done (op); // needed?
+    GNUNET_TESTBED_operation_done (op);
   if (NULL != emsg)
   {
-    fprintf (stderr, _("Gathering statistics failed: %s\n"),
+    fprintf (stderr,
+             _("Gathering statistics failed: %s\n"),
             emsg);
     GNUNET_SCHEDULER_cancel (put_task);
     GNUNET_DHT_TEST_cleanup (ctx);
@@ -178,8 +217,8 @@ stats_finished (void *cls,
             stats[i].subsystem,
             stats[i].name,
             stats[i].total);
-  GNUNET_SCHEDULER_cancel (put_task);
   GNUNET_DHT_TEST_cleanup (ctx);
+  GNUNET_SCHEDULER_shutdown ();
 }
 
 
@@ -191,8 +230,8 @@ stats_finished (void *cls,
  * @param subsystem name of subsystem that created the statistic
  * @param name the name of the datum
  * @param value the current value
- * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not
- * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration
+ * @param is_persistent #GNUNET_YES if the value is persistent, #GNUNET_NO if not
+ * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration
  */
 static int
 handle_stats (void *cls,
@@ -215,32 +254,31 @@ handle_stats (void *cls,
 
 
 /**
- * Task run on success or timeout to clean up.
- * Terminates active get operations and shuts down
- * the testbed.
+ * Task run on shutdown to clean up.  Terminates active get operations
+ * and shuts down the testbed.
  *
  * @param cls the 'struct GNUNET_DHT_TestContext'
  */
 static void
 shutdown_task (void *cls)
 {
-  struct GNUNET_DHT_TEST_Context *ctx = cls;
-  struct GetOperation *get_op;
+  (void) stop_ops ();
+}
 
-  while (NULL != (get_op = get_tail))
-  {
-    GNUNET_DHT_get_stop (get_op->get);
-    GNUNET_CONTAINER_DLL_remove (get_head,
-                                get_tail,
-                                get_op);
-    GNUNET_free (get_op);
-  }
-  (void) GNUNET_TESTBED_get_statistics (NUM_PEERS,
-                                       my_peers,
-                                        NULL, NULL,
-                                       &handle_stats,
-                                       &stats_finished,
-                                       ctx);
+
+/**
+ * Task run on timeout to clean up.  Terminates active get operations
+ * and shuts down the testbed.
+ *
+ * @param cls the `struct GNUNET_DHT_TestContext`
+ */
+static void
+timeout_cb (void *cls)
+{
+  timeout_task = NULL;
+  GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+              "Timeout\n");
+  GNUNET_SCHEDULER_shutdown ();
 }
 
 
@@ -252,33 +290,40 @@ shutdown_task (void *cls)
  * @param exp when will this value expire
  * @param key key of the result
  * @param get_path peers on reply path (or NULL if not recorded)
- * @param get_path_length number of entries in get_path
+ * @param get_path_length number of entries in @a get_path
  * @param put_path peers on the PUT path (or NULL if not recorded)
- * @param put_path_length number of entries in get_path
+ * @param put_path_length number of entries in @a put_path
  * @param type type of the result
- * @param size number of bytes in data
+ * @param size number of bytes in @a data
  * @param data pointer to the result data
  */
 static void
-dht_get_handler (void *cls, struct GNUNET_TIME_Absolute exp,
-                const struct GNUNET_HashCode * key,
+dht_get_handler (void *cls,
+                 struct GNUNET_TIME_Absolute exp,
+                const struct GNUNET_HashCode *key,
                 const struct GNUNET_PeerIdentity *get_path,
                 unsigned int get_path_length,
                 const struct GNUNET_PeerIdentity *put_path,
-                unsigned int put_path_length, enum GNUNET_BLOCK_Type type,
-                size_t size, const void *data)
+                unsigned int put_path_length,
+                 enum GNUNET_BLOCK_Type type,
+                size_t size,
+                 const void *data)
 {
   struct GetOperation *get_op = cls;
   struct GNUNET_HashCode want;
-  struct GNUNET_DHT_TestContext *ctx;
+  struct GNUNET_DHT_TEST_Context *ctx;
 
   if (sizeof (struct GNUNET_HashCode) != size)
   {
     GNUNET_break (0);
     return;
   }
-  GNUNET_CRYPTO_hash (key, sizeof (*key), &want);
-  if (0 != memcmp (&want, data, sizeof (want)))
+  GNUNET_CRYPTO_hash (key,
+                      sizeof (*key),
+                      &want);
+  if (0 != memcmp (&want,
+                   data,
+                   sizeof (want)))
   {
     GNUNET_break (0);
     return;
@@ -289,14 +334,19 @@ dht_get_handler (void *cls, struct GNUNET_TIME_Absolute exp,
   {
     int i;
 
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "PATH: (get %u, put %u)\n",
-               get_path_length, put_path_length);
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "  LOCAL\n");
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "PATH: (get %u, put %u)\n",
+               get_path_length,
+                put_path_length);
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "  LOCAL\n");
     for (i = get_path_length - 1; i >= 0; i--)
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "  %s\n",
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                  "  %s\n",
                  GNUNET_i2s (&get_path[i]));
     for (i = put_path_length - 1; i >= 0; i--)
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "  %s\n",
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                  "  %s\n",
                  GNUNET_i2s (&put_path[i]));
   }
 #endif
@@ -307,10 +357,18 @@ dht_get_handler (void *cls, struct GNUNET_TIME_Absolute exp,
   GNUNET_free (get_op);
   if (NULL != get_head)
     return;
-  /* all DHT GET operations successful; terminate! */
+  /* all DHT GET operations successful; get stats! */
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              "All DHT operations successful. Obtaining stats!\n");
   ok = 0;
-  ctx = GNUNET_SCHEDULER_cancel (timeout_task);
-  timeout_task = GNUNET_SCHEDULER_add_now (&shutdown_task, ctx);
+  ctx = stop_ops ();
+  GNUNET_assert (NULL != ctx);
+  (void) GNUNET_TESTBED_get_statistics (NUM_PEERS,
+                                       my_peers,
+                                        NULL, NULL,
+                                       &handle_stats,
+                                       &stats_finished,
+                                       ctx);
 }
 
 
@@ -328,55 +386,52 @@ do_puts (void *cls)
   struct GNUNET_HashCode value;
   unsigned int i;
 
+  put_task = NULL;
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Putting values into DHT\n");
   for (i = 0; i < NUM_PEERS; i++)
   {
-    GNUNET_CRYPTO_hash (&i, sizeof (i), &key);
-    GNUNET_CRYPTO_hash (&key, sizeof (key), &value);
-    GNUNET_DHT_put (hs[i], &key, 10U,
+    GNUNET_CRYPTO_hash (&i,
+                        sizeof (i),
+                        &key);
+    GNUNET_CRYPTO_hash (&key,
+                        sizeof (key),
+                        &value);
+    GNUNET_DHT_put (hs[i],
+                    &key,
+                    10U,
                     GNUNET_DHT_RO_RECORD_ROUTE |
                     GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
                     GNUNET_BLOCK_TYPE_TEST,
-                   sizeof (value), &value,
+                   sizeof (value),
+                    &value,
                    GNUNET_TIME_UNIT_FOREVER_ABS,
-                   NULL, NULL);
+                   NULL,
+                    NULL);
   }
   put_task = GNUNET_SCHEDULER_add_delayed (PUT_FREQUENCY,
-                                          &do_puts, hs);
+                                          &do_puts,
+                                           hs);
 }
 
 
 /**
- * Main function of the test.
- *
- * @param cls closure (NULL)
- * @param ctx argument to give to GNUNET_DHT_TEST_cleanup on test end
- * @param num_peers number of peers that are running
- * @param peers array of peers
- * @param dhts handle to each of the DHTs of the peers
+ * Start GET operations.
  */
 static void
-run (void *cls,
-     struct GNUNET_DHT_TEST_Context *ctx,
-     unsigned int num_peers,
-     struct GNUNET_TESTBED_Peer **peers,
-     struct GNUNET_DHT_Handle **dhts)
+start_get (void *cls)
 {
+  struct GNUNET_DHT_Handle **dhts = cls;
   unsigned int i;
   unsigned int j;
   struct GNUNET_HashCode key;
   struct GetOperation *get_op;
 
-  GNUNET_assert (NUM_PEERS == num_peers);
-  my_peers = peers;
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-             "Peers setup, starting test\n");
-  put_task = GNUNET_SCHEDULER_add_now (&do_puts, dhts);
-  for (i=0;i<num_peers;i++)
+  get_task = NULL;
+  for (i=0;i<NUM_PEERS;i++)
   {
     GNUNET_CRYPTO_hash (&i, sizeof (i), &key);
-    for (j=0;j<num_peers;j++)
+    for (j=0;j<NUM_PEERS;j++)
     {
       get_op = GNUNET_new (struct GetOperation);
       GNUNET_CONTAINER_DLL_insert (get_head,
@@ -389,11 +444,43 @@ run (void *cls,
                                          GNUNET_DHT_RO_RECORD_ROUTE | GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
                                          NULL,        /* xquery */
                                          0,      /* xquery bits */
-                                         &dht_get_handler, get_op);
+                                         &dht_get_handler,
+                                          get_op);
     }
   }
+}
+
+
+/**
+ * Main function of the test.
+ *
+ * @param cls closure (NULL)
+ * @param ctx argument to give to #GNUNET_DHT_TEST_cleanup on test end
+ * @param num_peers number of @a peers that are running
+ * @param peers array of peers
+ * @param dhts handle to each of the DHTs of the peers
+ */
+static void
+run (void *cls,
+     struct GNUNET_DHT_TEST_Context *ctx,
+     unsigned int num_peers,
+     struct GNUNET_TESTBED_Peer **peers,
+     struct GNUNET_DHT_Handle **dhts)
+{
+  GNUNET_assert (NUM_PEERS == num_peers);
+  my_peers = peers;
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Peers setup, starting test\n");
+  put_task = GNUNET_SCHEDULER_add_now (&do_puts,
+                                       dhts);
+  get_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
+                                           &start_get,
+                                           dhts);
   timeout_task = GNUNET_SCHEDULER_add_delayed (GET_TIMEOUT,
-                                              &shutdown_task, ctx);
+                                              &timeout_cb,
+                                               ctx);
+  GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
+                                 ctx);
 }