the big core API/protocol change, breaks all testcases using core, since the code...
[oweals/gnunet.git] / src / dv / test_transport_api_dv.c
index 50eeeb60c240a05dd53b9da62832fa7e1342dcda..d4c7eef2caa41bcf0dd540f0e7495cd843ff4bc7 100644 (file)
@@ -4,7 +4,7 @@
 
      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
      Boston, MA 02111-1307, USA.
 */
 /**
      Boston, MA 02111-1307, USA.
 */
 /**
- * @file transport/test_transport_api_dv.c
- * @brief base test case for dv transport (separated from other transport
- * testcases for two reasons. 1) dv-service relies on core and other
- * transport plugins, dv plugin relies on dv-service, so dv-plugin needs
- * to live here, and 2) a dv plugin testcase is different from other
- * tranport plugin testcases because we need at least three peer to test
- * it.
- *
- * This test case tests DV functionality.  Specifically it starts three
- * peers connected in a line (1 <-> 2 <-> 3).  Then a message is transmitted
- * from peer 1 to peer 3.  Assuming that DV is working, peer 2 should have
- * gossiped about peer 3 to 1, and should then forward a message from one
- * to 3.
+ * @file dv/test_transport_api_dv.c
+ * @brief base testcase for testing distance vector transport
  */
 #include "platform.h"
  */
 #include "platform.h"
-#include "gnunet_common.h"
-#include "gnunet_hello_lib.h"
-#include "gnunet_getopt_lib.h"
-#include "gnunet_os_lib.h"
-#include "gnunet_program_lib.h"
-#include "gnunet_scheduler_lib.h"
-#include "gnunet_transport_service.h"
-#include "../transport/transport.h"
+#include "gnunet_testing_lib.h"
+#include "gnunet_core_service.h"
 
 
-#define VERBOSE GNUNET_YES
+#define VERBOSE GNUNET_NO
 
 
-#define VERBOSE_ARM GNUNET_NO
+#define TEST_ALL GNUNET_NO
 
 
-#define START_ARM GNUNET_YES
+/**
+ * How long until we fail the whole testcase?
+ */
+#define TEST_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 600)
 
 /**
 
 /**
- * How long until we give up on transmitting the message?
+ * How long until we give up on starting the peers?
  */
  */
-#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 50)
+#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 500)
 
 
-#define MTYPE 12345
+#define DEFAULT_NUM_PEERS 4
+
+#define DEFAULT_ADDITIONAL_MESSAGES 2
+
+#define MAX_OUTSTANDING_CONNECTIONS 100
+
+static float fail_percentage = 0.00;
+
+static int ok;
+
+static unsigned long long num_additional_messages;
+
+static unsigned long long num_peers;
 
 
-static int num_wanted = 2;
+static unsigned int total_connections;
 
 
-static int num_received = 0;
+static unsigned int failed_connections;
+
+static unsigned int total_server_connections;
+
+static unsigned int total_messages_received;
+
+static unsigned int total_other_expected_messages;
+
+static unsigned int temp_total_other_messages;
+
+static unsigned int total_other_messages;
+
+static unsigned int expected_messages;
+
+static unsigned int expected_connections;
+
+static unsigned long long peers_left;
+
+static struct GNUNET_TESTING_PeerGroup *pg;
+
+const struct GNUNET_CONFIGURATION_Handle *main_cfg;
+
+GNUNET_SCHEDULER_TaskIdentifier die_task;
+
+static char *dotOutFileName = "topology.dot";
+
+static FILE *dotOutFile;
+
+static char *blacklist_transports;
+
+static int transmit_ready_scheduled;
+
+static int transmit_ready_failed;
+
+static int transmit_ready_called;
+
+static enum GNUNET_TESTING_Topology topology;
+
+static enum GNUNET_TESTING_Topology blacklist_topology = GNUNET_TESTING_TOPOLOGY_NONE; /* Don't do any blacklisting */
+
+static enum GNUNET_TESTING_Topology connection_topology = GNUNET_TESTING_TOPOLOGY_NONE; /* NONE actually means connect all allowed peers */
+
+static enum GNUNET_TESTING_TopologyOption connect_topology_option = GNUNET_TESTING_TOPOLOGY_OPTION_ALL;
+
+static double connect_topology_option_modifier = 0.0;
+
+static char *test_directory;
+
+struct GNUNET_CONTAINER_MultiHashMap *peer_daemon_hash;
+
+#define MTYPE 12345
+
+struct GNUNET_TestMessage
+{
+  /**
+   * Header of the message
+   */
+  struct GNUNET_MessageHeader header;
+
+  /**
+   * Unique identifier for this message.
+   */
+  uint32_t uid;
+};
 
 struct PeerContext
 {
 
 struct PeerContext
 {
-  struct GNUNET_CONFIGURATION_Handle *cfg;
-  struct GNUNET_TRANSPORT_Handle *th;
-  struct GNUNET_PeerIdentity id;
-  const char *cfg_file;
-  struct GNUNET_HELLO_Message *hello;
-#if START_ARM
-  pid_t arm_pid;
-#endif
+  /* This is a linked list */
+  struct PeerContext *next;
+
+  /**
+   * Handle to the daemon
+   */
+  struct GNUNET_TESTING_Daemon *daemon;
+
+  /* Handle to the peer core */
+  struct GNUNET_CORE_Handle *peer_handle;
 };
 
 };
 
-static struct PeerContext p1;
+static struct PeerContext *all_peers;
 
 
-static struct PeerContext p2;
+struct TestMessageContext
+{
+  /* This is a linked list */
+  struct TestMessageContext *next;
 
 
-static struct PeerContext p3;
+  /* Handle to the sending peer core */
+  struct GNUNET_CORE_Handle *peer1handle;
 
 
-static struct PeerContext p4;
+  /* Handle to the receiving peer core */
+  struct GNUNET_CORE_Handle *peer2handle;
 
 
-static struct GNUNET_SCHEDULER_Handle *sched;
+  /* Handle to the sending peer daemon */
+  struct GNUNET_TESTING_Daemon *peer1;
 
 
-static int ok;
+  /* Handle to the receiving peer daemon */
+  struct GNUNET_TESTING_Daemon *peer2;
 
 
-GNUNET_SCHEDULER_TaskIdentifier die_task;
+  /* Identifier for this message, so we don't disconnect other peers! */
+  uint32_t uid;
+
+  /* Task for disconnecting cores, allow task to be cancelled on shutdown */
+  GNUNET_SCHEDULER_TaskIdentifier disconnect_task;
+};
 
 
+static struct TestMessageContext *test_messages;
+
+static struct TestMessageContext *other_test_messages;
+
+/**
+ * Check whether peers successfully shut down.
+ */
+void shutdown_callback (void *cls,
+                        const char *emsg)
+{
+  if (emsg != NULL)
+    {
 #if VERBOSE
 #if VERBOSE
-#define OKPP do { ok++; fprintf (stderr, "Now at stage %u at %s:%u\n", ok, __FILE__, __LINE__); } while (0)
-#else
-#define OKPP do { ok++; } while (0)
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                  "Shutdown of peers failed!\n");
 #endif
 #endif
-
+      if (ok == 0)
+        ok = 666;
+    }
+  else
+    {
+#if VERBOSE
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                  "All peers successfully shut down!\n");
+#endif
+    }
+}
 
 static void
 
 static void
-end ()
+finish_testing ()
 {
 {
-  /* do work here */
-  GNUNET_SCHEDULER_cancel (sched, die_task);
+  GNUNET_assert (pg != NULL);
+  struct PeerContext *peer_pos;
+  struct PeerContext *free_peer_pos;
+  struct TestMessageContext *pos;
+  struct TestMessageContext *free_pos;
 
 
-  if (p1.th != NULL)
+#if VERBOSE
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Called finish testing, stopping daemons.\n");
+#endif
+  peer_pos = all_peers;
+  while (peer_pos != NULL)
     {
     {
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting from transport 1!\n");
-      GNUNET_TRANSPORT_disconnect (p1.th);
-      p1.th = NULL;
+      if (peer_pos->peer_handle != NULL)
+        GNUNET_CORE_disconnect(peer_pos->peer_handle);
+      free_peer_pos = peer_pos;
+      peer_pos = peer_pos->next;
+      GNUNET_free(free_peer_pos);
     }
     }
+  all_peers = NULL;
 
 
-  if (p2.th != NULL)
+  pos = test_messages;
+  while (pos != NULL)
     {
     {
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting from transport 2!\n");
-      GNUNET_TRANSPORT_disconnect (p2.th);
-      p2.th = NULL;
+      if (pos->peer1handle != NULL)
+        {
+          GNUNET_CORE_disconnect(pos->peer1handle);
+          pos->peer1handle = NULL;
+        }
+      if (pos->peer2handle != NULL)
+        {
+          GNUNET_CORE_disconnect(pos->peer2handle);
+          pos->peer2handle = NULL;
+        }
+      free_pos = pos;
+      pos = pos->next;
+      if (free_pos->disconnect_task != GNUNET_SCHEDULER_NO_TASK)
+        {
+          GNUNET_SCHEDULER_cancel(free_pos->disconnect_task);
+        }
+      GNUNET_free(free_pos);
     }
 
     }
 
-  if (p3.th != NULL)
+  pos = other_test_messages;
+  while (pos != NULL)
     {
     {
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting from transport 3!\n");
-      GNUNET_TRANSPORT_disconnect (p3.th);
-      p3.th = NULL;
+      if (pos->peer1handle != NULL)
+        {
+          GNUNET_CORE_disconnect(pos->peer1handle);
+          pos->peer1handle = NULL;
+        }
+      if (pos->peer2handle != NULL)
+        {
+          GNUNET_CORE_disconnect(pos->peer2handle);
+          pos->peer2handle = NULL;
+        }
+      free_pos = pos;
+      pos = pos->next;
+      if (free_pos->disconnect_task != GNUNET_SCHEDULER_NO_TASK)
+        {
+          GNUNET_SCHEDULER_cancel(free_pos->disconnect_task);
+        }
+      GNUNET_free(free_pos);
     }
     }
+#if VERBOSE
+          GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                      "transmit_ready's scheduled %d, failed %d, transmit_ready's called %d\n", transmit_ready_scheduled, transmit_ready_failed, transmit_ready_called);
+#endif
 
 
-  if (p4.th != NULL)
+#if VERBOSE
+          GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                      "Calling daemons_stop\n");
+#endif
+  GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL);
+#if VERBOSE
+          GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                      "daemons_stop finished\n");
+#endif
+  if (dotOutFile != NULL)
     {
     {
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting from transport 4!\n");
-      GNUNET_TRANSPORT_disconnect (p4.th);
-      p4.th = NULL;
+      fprintf(dotOutFile, "}");
+      fclose(dotOutFile);
     }
 
     }
 
-  die_task = GNUNET_SCHEDULER_NO_TASK;
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transports disconnected, returning success!\n");
-  sleep(2);
   ok = 0;
 }
 
   ok = 0;
 }
 
-static void
-stop_arm (struct PeerContext *p)
-{
-#if START_ARM
-  p->arm_pid = GNUNET_OS_start_process (NULL, NULL, "gnunet-arm",
-                                        "gnunet-arm",
-#if VERBOSE
-                                        "-L", "DEBUG",
-#endif
-                                        "-c", p->cfg_file, "-e", "-q", NULL);
-
-  GNUNET_OS_process_wait (p->arm_pid);
-#endif
-  GNUNET_CONFIGURATION_destroy (p->cfg);
-}
-
 
 static void
 
 static void
-restart_transport (struct PeerContext *p)
+disconnect_cores (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
 {
 {
-#if START_ARM
-  p->arm_pid = GNUNET_OS_start_process (NULL, NULL, "gnunet-arm",
-                                        "gnunet-arm",
-#if VERBOSE
-                                        "-L", "DEBUG",
-#endif
-                                        "-c", p->cfg_file, "-k", "transport", "-q", NULL);
+  struct TestMessageContext *pos = cls;
 
 
-  GNUNET_OS_process_wait (p->arm_pid);
-#endif
-
-#if START_ARM
-  p->arm_pid = GNUNET_OS_start_process (NULL, NULL, "gnunet-arm",
-                                        "gnunet-arm",
+  /* Disconnect from the respective cores */
 #if VERBOSE
 #if VERBOSE
-                                        "-L", "DEBUG",
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Disconnecting from peer 1 `%4s'\n", GNUNET_i2s (&pos->peer1->id));
 #endif
 #endif
-                                        "-c", p->cfg_file, "-i", "transport", "-q", NULL);
-
-  GNUNET_OS_process_wait (p->arm_pid);
+  if (pos->peer1handle != NULL)
+    GNUNET_CORE_disconnect(pos->peer1handle);
+#if VERBOSE
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Disconnecting from peer 2 `%4s'\n", GNUNET_i2s (&pos->peer2->id));
 #endif
 #endif
+  if (pos->peer2handle != NULL)
+    GNUNET_CORE_disconnect(pos->peer2handle);
+  /* Set handles to NULL so test case can be ended properly */
+  pos->peer1handle = NULL;
+  pos->peer2handle = NULL;
+  pos->disconnect_task = GNUNET_SCHEDULER_NO_TASK;
+  /* Decrement total connections so new can be established */
+  total_server_connections -= 2;
 }
 
 }
 
-
 static void
 static void
-end_badly ()
+end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
 {
 {
-  /* do work here */
-#if VERBOSE
-  fprintf(stderr, "Ending on an unhappy note.\n");
-#endif
+  char *msg = cls;
+  GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+              "End badly was called (%s)... stopping daemons.\n", msg);
+  struct TestMessageContext *pos;
+  struct TestMessageContext *free_pos;
+  struct PeerContext * peer_pos;
+  struct PeerContext * free_peer_pos;
+
+  peer_pos = all_peers;
+  while (peer_pos != NULL)
+    {
+      if (peer_pos->peer_handle != NULL)
+        GNUNET_CORE_disconnect(peer_pos->peer_handle);
+      free_peer_pos = peer_pos;
+      peer_pos = peer_pos->next;
+      GNUNET_free(free_peer_pos);
+    }
+  all_peers = NULL;
 
 
-  if (p1.th != NULL)
+  pos = test_messages;
+  while (pos != NULL)
     {
     {
-      GNUNET_TRANSPORT_disconnect (p1.th);
-      p1.th = NULL;
+      if (pos->peer1handle != NULL)
+        {
+          GNUNET_CORE_disconnect(pos->peer1handle);
+          pos->peer1handle = NULL;
+        }
+      if (pos->peer2handle != NULL)
+        {
+          GNUNET_CORE_disconnect(pos->peer2handle);
+          pos->peer2handle = NULL;
+        }
+      free_pos = pos;
+      pos = pos->next;
+      GNUNET_free(free_pos);
     }
 
     }
 
-  if (p2.th != NULL)
+  pos = other_test_messages;
+  while (pos != NULL)
     {
     {
-      GNUNET_TRANSPORT_disconnect (p2.th);
-      p2.th = NULL;
+      if (pos->peer1handle != NULL)
+        {
+          GNUNET_CORE_disconnect(pos->peer1handle);
+          pos->peer1handle = NULL;
+        }
+      if (pos->peer2handle != NULL)
+        {
+          GNUNET_CORE_disconnect(pos->peer2handle);
+          pos->peer2handle = NULL;
+        }
+      free_pos = pos;
+      pos = pos->next;
+      if (free_pos->disconnect_task != GNUNET_SCHEDULER_NO_TASK)
+        {
+          GNUNET_SCHEDULER_cancel(free_pos->disconnect_task);
+        }
+      GNUNET_free(free_pos);
     }
 
     }
 
-  if (p3.th != NULL)
+  if (pg != NULL)
     {
     {
-      GNUNET_TRANSPORT_disconnect (p3.th);
-      p3.th = NULL;
+      GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL);
+      ok = 7331;                /* Opposite of leet */
     }
     }
+  else
+    ok = 401;                   /* Never got peers started */
 
 
-  if (p4.th != NULL)
+  if (dotOutFile != NULL)
     {
     {
-      GNUNET_TRANSPORT_disconnect (p4.th);
-      p4.th = NULL;
+      fprintf(dotOutFile, "}");
+      fclose(dotOutFile);
     }
     }
-  sleep(2);
-  ok = 1;
-  return;
 }
 
 static void
 }
 
 static void
-notify_receive (void *cls,
-                const struct GNUNET_PeerIdentity *peer,
-                const struct GNUNET_MessageHeader *message,
-                struct GNUNET_TIME_Relative latency,
-               uint32_t distance)
-{
-  if (ntohs(message->type) != MTYPE)
-    return;
+send_other_messages (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc);
 
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received message of type %d from peer (%p) distance %d latency %u!\n",
-                ntohs(message->type), cls, distance, latency.value);
+static int
+process_mtype (void *cls,
+               const struct GNUNET_PeerIdentity *peer,
+               const struct GNUNET_MessageHeader *message,
+               struct GNUNET_TIME_Relative latency,
+               uint32_t distance)
+{
+  struct TestMessageContext *pos = cls;
+  struct GNUNET_TestMessage *msg = (struct GNUNET_TestMessage *)message;
+  if (pos->uid != ntohl(msg->uid))
+    return GNUNET_OK;
 
 
-  GNUNET_assert (MTYPE == ntohs (message->type));
-  GNUNET_assert (sizeof (struct GNUNET_MessageHeader) ==
-                 ntohs (message->size));
-  num_received++;
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received %d of %d messages.\n", num_received, num_wanted);
+  GNUNET_assert(0 == memcmp(peer, &pos->peer1->id, sizeof(struct GNUNET_PeerIdentity)));
+  if (total_other_expected_messages == 0)
+    {
+      total_messages_received++;
+#if VERBOSE
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                  "Received message from `%4s', type %d, uid %u, distance %u.\n", GNUNET_i2s (peer), ntohs(message->type), ntohl(msg->uid), distance);
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                  "Total messages received %d, expected %d.\n", total_messages_received, expected_messages);
+#endif
+    }
+  else
+    {
+      total_other_messages++;
+#if VERBOSE
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                  "Received message from `%4s', type %d, uid %u, distance %u.\n", GNUNET_i2s (peer), ntohs(message->type), ntohl(msg->uid), distance);
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                  "Total messages received %d, expected %d.\n", total_other_messages, total_other_expected_messages);
+#endif
+    }
 
 
-  if (num_wanted == num_received)
+  if ((total_messages_received == expected_messages) && (total_other_messages == 0))
+    {
+      GNUNET_SCHEDULER_cancel (die_task);
+      die_task = GNUNET_SCHEDULER_add_delayed (TEST_TIMEOUT,
+                                               &end_badly, "waiting for DV peers to connect!");
+      /*
+      if ((num_peers == 3) && (total_other_expected_messages == 2))
+        {
+          GNUNET_SCHEDULER_add_now (&send_other_messages, NULL);
+        }
+      else
+        {
+          GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 20), &send_other_messages, NULL);
+        }*/
+    }
+  else if ((total_other_expected_messages > 0) && (total_other_messages == total_other_expected_messages))
     {
     {
-      end ();
+      GNUNET_SCHEDULER_cancel (die_task);
+      GNUNET_SCHEDULER_add_now (&finish_testing, NULL);
+    }
+  else
+    {
+      pos->disconnect_task = GNUNET_SCHEDULER_add_now(&disconnect_cores, pos);
     }
     }
-}
 
 
+  return GNUNET_OK;
+}
 
 static size_t
 
 static size_t
-notify_ready (void *cls, size_t size, void *buf)
+transmit_ready (void *cls, size_t size, void *buf)
 {
 {
-  struct GNUNET_MessageHeader *hdr;
-
+  struct GNUNET_TestMessage *m;
+  struct TestMessageContext *pos = cls;
+
+  GNUNET_assert (buf != NULL);
+  m = (struct GNUNET_TestMessage *) buf;
+  m->header.type = htons (MTYPE);
+  m->header.size = htons (sizeof (struct GNUNET_TestMessage));
+  m->uid = htonl(pos->uid);
+  transmit_ready_called++;
+#if VERBOSE
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Transmitting message to peer (%p) - %u!\n", cls, size);
-  GNUNET_assert (size >= 256);
+              "transmit ready for peer %s\ntransmit_ready's scheduled %d, transmit_ready's called %d\n", GNUNET_i2s(&pos->peer1->id), transmit_ready_scheduled, transmit_ready_called);
+#endif
+  return sizeof (struct GNUNET_TestMessage);
+}
 
 
-  if (buf != NULL)
-  {
-    hdr = buf;
-    hdr->size = htons (sizeof (struct GNUNET_MessageHeader));
-    hdr->type = htons (MTYPE);
-  }
 
 
-  return sizeof (struct GNUNET_MessageHeader);
-}
+static struct GNUNET_CORE_MessageHandler no_handlers[] = {
+  {NULL, 0, 0}
+};
 
 
+static struct GNUNET_CORE_MessageHandler handlers[] = {
+  {&process_mtype, MTYPE, sizeof (struct GNUNET_TestMessage)},
+  {NULL, 0, 0}
+};
 
 static void
 
 static void
-notify_connect (void *cls,
-                const struct GNUNET_PeerIdentity *peer,
-                struct GNUNET_TIME_Relative latency,
-               uint32_t distance)
+init_notify_peer2 (void *cls,
+             struct GNUNET_CORE_Handle *server,
+             const struct GNUNET_PeerIdentity *my_identity,
+             const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *publicKey)
 {
 {
-  int peer_num = 0;
-  int connect_num = 0;
-  struct PeerContext *from_peer = cls;
-  char *from_peer_str;
-
-  if (cls == &p1)
-    peer_num = 1;
-  else if (cls == &p2)
-    peer_num = 2;
-  else if (cls == &p3)
-    peer_num = 3;
-  else if (cls == &p4)
-    peer_num = 4;
-
-  if (memcmp(peer, &p1.id, sizeof(struct GNUNET_PeerIdentity)) == 0)
-    connect_num = 1;
-  else if (memcmp(peer, &p2.id, sizeof(struct GNUNET_PeerIdentity)) == 0)
-    connect_num = 2;
-  else if (memcmp(peer, &p3.id, sizeof(struct GNUNET_PeerIdentity)) == 0)
-    connect_num = 3;
-  else if (memcmp(peer, &p4.id, sizeof(struct GNUNET_PeerIdentity)) == 0)
-    connect_num = 4;
-  else
-    connect_num = -1;
+  struct TestMessageContext *pos = cls;
 
 
-  if ((cls == &p1) && (memcmp(peer, &p3.id, sizeof(struct GNUNET_PeerIdentity)) == 0))
+#if VERBOSE
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Core connection to `%4s' established, scheduling message send\n",
+              GNUNET_i2s (my_identity));
+#endif
+  total_server_connections++;
+
+  if (NULL == GNUNET_CORE_notify_transmit_ready (pos->peer1handle,
+                                                 0,
+                                                 TIMEOUT,
+                                                 &pos->peer2->id,
+                                                 sizeof (struct GNUNET_TestMessage),
+                                                 &transmit_ready, pos))
     {
     {
-      GNUNET_TRANSPORT_notify_transmit_ready (p1.th,
-                                             &p3.id,
-                                             256, 0, TIMEOUT, &notify_ready,
-                                             &p1);
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                  "RECEIVED NULL when asking core (1) for transmission to peer `%4s'\n",
+                  GNUNET_i2s (&pos->peer2->id));
+      transmit_ready_failed++;
     }
     }
-
-  if ((cls == &p4) && (memcmp(peer, &p1.id, sizeof(struct GNUNET_PeerIdentity)) == 0))
+  else
     {
     {
-
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                 "Peer 4 notified about connection to peer 1, distance %u!\n", distance);
-
-      GNUNET_TRANSPORT_notify_transmit_ready (p4.th,
-                                              &p1.id,
-                                              256, 0, TIMEOUT, &notify_ready,
-                                              &p4);
+      transmit_ready_scheduled++;
     }
     }
-
-  GNUNET_asprintf(&from_peer_str, "%s", GNUNET_i2s(&from_peer->id));
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Peer `%d' %4s connected to peer `%d' %4s distance %d!\n", peer_num, from_peer_str, connect_num, GNUNET_i2s(peer), distance);
 }
 
 
 static void
 }
 
 
 static void
-notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
+init_notify_peer1 (void *cls,
+             struct GNUNET_CORE_Handle *server,
+             const struct GNUNET_PeerIdentity *my_identity,
+             const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *publicKey)
 {
 {
+  struct TestMessageContext *pos = cls;
+  total_server_connections++;
+
+#if VERBOSE
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Peer `%4s' disconnected (%p)!\n",
-             GNUNET_i2s (peer), cls);
+              "Core connection to `%4s' established, setting up handles\n",
+              GNUNET_i2s (my_identity));
+#endif
+
+  /*
+   * Connect to the receiving peer
+   */
+  pos->peer2handle = GNUNET_CORE_connect (pos->peer2->cfg,
+                                         1, 
+                                         TIMEOUT,
+                                         pos,
+                                         &init_notify_peer2,
+                                         NULL,
+                                         NULL,
+                                         NULL, NULL,
+                                         GNUNET_YES, NULL, GNUNET_YES, handlers);
+
 }
 
 
 static void
 }
 
 
 static void
-setup_peer (struct PeerContext *p, const char *cfgname)
+send_test_messages (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
 {
 {
-  p->cfg = GNUNET_CONFIGURATION_create ();
-  p->cfg_file = strdup(cfgname);
-#if START_ARM
-  p->arm_pid = GNUNET_OS_start_process (NULL, NULL, "gnunet-arm",
-                                        "gnunet-arm",
-#if VERBOSE_ARM
-                                        "-L", "DEBUG",
-#endif
-                                        "-c", cfgname, "-s", "-q", NULL);
-#endif
-  GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname));
-}
+  struct TestMessageContext *pos = cls;
 
 
+  if ((tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN) || (cls == NULL))
+    return;
 
 
-static void blacklist_peer(struct GNUNET_DISK_FileHandle *file, struct PeerContext *peer)
-{
-  struct GNUNET_CRYPTO_HashAsciiEncoded peer_enc;
-  char *buf;
-  size_t size;
-
-  GNUNET_CRYPTO_hash_to_enc(&peer->id.hashPubKey, &peer_enc);
-  size = GNUNET_asprintf(&buf, "%s:%s\n", "tcp", (char *)&peer_enc);
-  GNUNET_DISK_file_write(file, buf, size);
-  GNUNET_free_non_null(buf);
+  if (die_task == GNUNET_SCHEDULER_NO_TASK)
+    {
+      die_task = GNUNET_SCHEDULER_add_delayed (TEST_TIMEOUT,
+                                               &end_badly, "from create topology (timeout)");
+    }
+
+  if (total_server_connections >= MAX_OUTSTANDING_CONNECTIONS)
+    {
+      GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1),
+                                    &send_test_messages, pos);
+      return; /* Otherwise we'll double schedule messages here! */
+    }
+#if VERBOSE
+  GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Attempting to send test message from %s to %s\n", pos->peer1->shortname, pos->peer2->shortname);
+#endif
+  /*
+   * Connect to the sending peer
+   */
+  pos->peer1handle = GNUNET_CORE_connect (pos->peer1->cfg,
+                                         1,
+                                          TIMEOUT,
+                                          pos,
+                                          &init_notify_peer1,
+                                          NULL, NULL,
+                                          NULL,
+                                          NULL,
+                                          GNUNET_NO, NULL, GNUNET_NO, no_handlers);
+
+  GNUNET_assert(pos->peer1handle != NULL);
+
+  if (total_server_connections < MAX_OUTSTANDING_CONNECTIONS)
+    {
+      GNUNET_SCHEDULER_add_now (&send_test_messages, pos->next);
+    }
+  else
+    {
+      GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1),
+                                    &send_test_messages, pos->next);
+    }
 }
 
 static void
 }
 
 static void
-setup_blacklists (void *cls,
-                  const struct GNUNET_SCHEDULER_TaskContext *tc)
+send_other_messages (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
 {
 {
-  char *blacklist_filename;
-  struct GNUNET_DISK_FileHandle *file;
-  int i;
-
-  for (i = 1; i <= 4; i++)
+  struct TestMessageContext *pos;
+  struct TestMessageContext *free_pos;
+  struct PeerContext *peer_pos;
+#if TEST_ALL
+  struct PeerContext *inner_peer_pos;
+  struct TestMessageContext *temp_context;
+#endif
+  peer_pos = all_peers;
+  while (peer_pos != NULL)
     {
     {
-      GNUNET_asprintf(&blacklist_filename, "/tmp/test-gnunetd-transport-peer-%d/blacklist", i);
-      if (blacklist_filename != NULL)
+      if (peer_pos->peer_handle != NULL)
+        {
+          GNUNET_CORE_disconnect(peer_pos->peer_handle);
+          peer_pos->peer_handle = NULL;
+        }
+#if TEST_ALL
+      inner_peer_pos = all_peers;
+      while (inner_peer_pos != NULL)
         {
         {
-          file = GNUNET_DISK_file_open(blacklist_filename, GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_TRUNCATE | GNUNET_DISK_OPEN_CREATE,
-                                       GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE);
-          GNUNET_free(blacklist_filename);
-
-          if (file == NULL)
-            {
-              GNUNET_SCHEDULER_cancel(sched, die_task);
-              GNUNET_SCHEDULER_add_now(sched, &end_badly, NULL);
-              return;
-            }
-          switch (i)
+          if (inner_peer_pos != peer_pos)
           {
           {
-            case 1:
-              blacklist_peer(file, &p3);
-              blacklist_peer(file, &p4);
-              break;
-            case 2:
-              blacklist_peer(file, &p4);
-              break;
-            case 3:
-              blacklist_peer(file, &p1);
-              break;
-            case 4:
-              blacklist_peer(file, &p1);
-              blacklist_peer(file, &p2);
-              break;
+            temp_total_other_messages++;
+            temp_context = GNUNET_malloc(sizeof(struct TestMessageContext));
+            temp_context->peer1 = peer_pos->daemon;
+            temp_context->peer2 = inner_peer_pos->daemon;
+            temp_context->next = other_test_messages;
+            temp_context->uid = total_connections + temp_total_other_messages;
+            temp_context->disconnect_task = GNUNET_SCHEDULER_NO_TASK;
+            other_test_messages = temp_context;
           }
           }
+          inner_peer_pos = inner_peer_pos->next;
         }
         }
+#endif
+      peer_pos = peer_pos->next;
     }
     }
+  all_peers = NULL;
 
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Disconnecting transports...\n");
-
-  if (p1.th != NULL)
+  pos = test_messages;
+  while (pos != NULL)
     {
     {
-      GNUNET_TRANSPORT_disconnect (p1.th);
-      p1.th = NULL;
+      if (pos->peer1handle != NULL)
+        {
+          GNUNET_CORE_disconnect(pos->peer1handle);
+          pos->peer1handle = NULL;
+        }
+      if (pos->peer2handle != NULL)
+        {
+          GNUNET_CORE_disconnect(pos->peer2handle);
+          pos->peer2handle = NULL;
+        }
+      free_pos = pos;
+      pos = pos->next;
+      if (free_pos->disconnect_task != GNUNET_SCHEDULER_NO_TASK)
+        {
+          GNUNET_SCHEDULER_cancel(free_pos->disconnect_task);
+        }
+      GNUNET_free(free_pos);
     }
     }
+  test_messages = NULL;
 
 
-  if (p2.th != NULL)
+  total_other_expected_messages = temp_total_other_messages;
+  if (total_other_expected_messages == 0)
     {
     {
-      GNUNET_TRANSPORT_disconnect (p2.th);
-      p2.th = NULL;
+      GNUNET_SCHEDULER_add_now (&end_badly, "send_other_messages had 0 messages to send, no DV connections made!");
     }
     }
+#if VERBOSE
+  GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Preparing to send %d other test messages\n", total_other_expected_messages);
+#endif
+
+  GNUNET_SCHEDULER_add_now (&send_test_messages, other_test_messages);
+  GNUNET_SCHEDULER_cancel(die_task);
+  die_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 250), &end_badly, "from send_other_messages");
+}
 
 
-  if (p3.th != NULL)
+void
+topology_callback (void *cls,
+                   const struct GNUNET_PeerIdentity *first,
+                   const struct GNUNET_PeerIdentity *second,
+                   uint32_t distance,
+                   const struct GNUNET_CONFIGURATION_Handle *first_cfg,
+                   const struct GNUNET_CONFIGURATION_Handle *second_cfg,
+                   struct GNUNET_TESTING_Daemon *first_daemon,
+                   struct GNUNET_TESTING_Daemon *second_daemon,
+                   const char *emsg)
+{
+  struct TestMessageContext *temp_context;
+  if (emsg == NULL)
     {
     {
-      GNUNET_TRANSPORT_disconnect (p3.th);
-      p3.th = NULL;
-    }
+      total_connections++;
+#if VERBOSE
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "connected peer %s to peer %s, distance %u\n",
+               first_daemon->shortname,
+               second_daemon->shortname,
+               distance);
+#endif
+      temp_context = GNUNET_malloc(sizeof(struct TestMessageContext));
+      temp_context->peer1 = first_daemon;
+      temp_context->peer2 = second_daemon;
+      temp_context->next = test_messages;
+      temp_context->uid = total_connections;
+      temp_context->disconnect_task = GNUNET_SCHEDULER_NO_TASK;
+      test_messages = temp_context;
+
+      expected_messages++;
 
 
-  if (p4.th != NULL)
+    }
+#if VERBOSE
+  else
     {
     {
-      GNUNET_TRANSPORT_disconnect (p4.th);
-      p4.th = NULL;
+      failed_connections++;
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to connect peer %s to peer %s with error :\n%s\n",
+               first_daemon->shortname,
+               second_daemon->shortname, emsg);
     }
     }
+#endif
 
 
-  sleep(1);
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "Restarting transport service (%p) with gnunet-arm -c %s -L DEBUG -k transport!\n", p1.arm_pid, p1.cfg_file);
-  restart_transport(&p1);
+  if (total_connections == expected_connections)
+    {
+#if VERBOSE
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                  "Created %u total connections, which is our target number!  Calling send messages.\n",
+                  total_connections);
+#endif
 
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "Restarting transport service (%p) with gnunet-arm -c %s -L DEBUG -k transport!\n", p2.arm_pid, p2.cfg_file);
-  restart_transport(&p2);
+      GNUNET_SCHEDULER_cancel (die_task);
+      die_task = GNUNET_SCHEDULER_NO_TASK;
+      GNUNET_SCHEDULER_add_now (&send_test_messages, test_messages);
+    }
+  else if (total_connections + failed_connections == expected_connections)
+    {
+      if (failed_connections < (unsigned int)(fail_percentage * total_connections))
+        {
+          GNUNET_SCHEDULER_cancel (die_task);
+          die_task = GNUNET_SCHEDULER_NO_TASK;
+          GNUNET_SCHEDULER_add_now (&send_test_messages, test_messages);
+        }
+      else
+        {
+          GNUNET_SCHEDULER_cancel (die_task);
+          die_task = GNUNET_SCHEDULER_add_now (&end_badly, "from topology_callback (too many failed connections)");
+        }
+    }
+  else
+    {
+#if VERBOSE
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                  "Have %d total connections, %d failed connections, Want %d (at least %d)\n",
+                  total_connections, failed_connections, expected_connections, expected_connections - (unsigned int)(fail_percentage * expected_connections));
+#endif
+    }
+}
 
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "Restarting transport service (%p) with gnunet-arm -c %s -L DEBUG -k transport!\n", p3.arm_pid, p3.cfg_file);
-  restart_transport(&p3);
+static void
+connect_topology ()
+{
+  expected_connections = -1;
+  if ((pg != NULL) && (peers_left == 0))
+    {
+      expected_connections = GNUNET_TESTING_connect_topology (pg, connection_topology, connect_topology_option, connect_topology_option_modifier, NULL, NULL);
+#if VERBOSE
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                  "Have %d expected connections\n", expected_connections);
+#endif
+    }
 
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "Restarting transport service (%p) with gnunet-arm -c %s -L DEBUG -k transport!\n", p4.arm_pid, p4.cfg_file);
-  restart_transport(&p4);
-
-  p1.th = GNUNET_TRANSPORT_connect (sched, p1.cfg,
-                                    &p1,
-                                    &notify_receive,
-                                    &notify_connect, &notify_disconnect);
-
-  p2.th = GNUNET_TRANSPORT_connect (sched, p2.cfg,
-                                    &p2,
-                                    &notify_receive,
-                                    &notify_connect, &notify_disconnect);
-
-  p3.th = GNUNET_TRANSPORT_connect (sched, p3.cfg,
-                                    &p3,
-                                    &notify_receive,
-                                    &notify_connect, &notify_disconnect);
-
-  p4.th = GNUNET_TRANSPORT_connect (sched, p4.cfg,
-                                    &p4,
-                                    &notify_receive,
-                                    &notify_connect, &notify_disconnect);
-  GNUNET_assert(p1.th != NULL);
-  GNUNET_assert(p2.th != NULL);
-  GNUNET_assert(p3.th != NULL);
-  GNUNET_assert(p4.th != NULL);
-
-  GNUNET_TRANSPORT_offer_hello (p1.th, GNUNET_HELLO_get_header(p2.hello));
-  GNUNET_TRANSPORT_offer_hello (p2.th, GNUNET_HELLO_get_header(p3.hello));
-  GNUNET_TRANSPORT_offer_hello (p3.th, GNUNET_HELLO_get_header(p4.hello));
+  GNUNET_SCHEDULER_cancel (die_task);
+  if (expected_connections == GNUNET_SYSERR)
+    {
+      die_task = GNUNET_SCHEDULER_add_now (&end_badly, "from connect topology (bad return)");
+    }
 
 
+  die_task = GNUNET_SCHEDULER_add_delayed (TEST_TIMEOUT,
+                                           &end_badly, "from connect topology (timeout)");
 }
 
 }
 
-
 static void
 static void
-get_hello_fourth (void *cls,
-                const struct GNUNET_MessageHeader *message)
+create_topology ()
 {
 {
-  struct PeerContext *me = cls;
+  peers_left = num_peers; /* Reset counter */
+  if (GNUNET_TESTING_create_topology (pg, topology, blacklist_topology, blacklist_transports) != GNUNET_SYSERR)
+    {
+#if VERBOSE
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                  "Topology set up, now starting peers!\n");
+#endif
+      GNUNET_TESTING_daemons_continue_startup(pg);
+    }
+  else
+    {
+      GNUNET_SCHEDULER_cancel (die_task);
+      die_task = GNUNET_SCHEDULER_add_now (&end_badly, "from create topology (bad return)");
+    }
+  GNUNET_SCHEDULER_cancel (die_task);
+  die_task = GNUNET_SCHEDULER_add_delayed (TEST_TIMEOUT,
+                                           &end_badly, "from continue startup (timeout)");
+}
 
 
-  GNUNET_TRANSPORT_get_hello_cancel (me->th, &get_hello_fourth, me);
+/**
+ * Method called whenever a given peer connects.
+ *
+ * @param cls closure
+ * @param peer peer identity this notification is about
+ * @param latency reported latency of the connection with 'other'
+ * @param distance reported distance (DV) to 'other'
+ */
+static void all_connect_handler (void *cls,
+                                 const struct
+                                 GNUNET_PeerIdentity * peer,
+                                 struct GNUNET_TIME_Relative latency,
+                                 uint32_t distance)
+{
+  struct GNUNET_TESTING_Daemon *d = cls;
+  struct GNUNET_TESTING_Daemon *second_daemon;
+  char *second_shortname = strdup(GNUNET_i2s(peer));
+#if !TEST_ALL
+  struct TestMessageContext *temp_context;
+#endif
+#if VERBOSE
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "connected peer %s to peer %s, distance %u\n",
+           d->shortname,
+           second_shortname,
+           distance);
+#endif
 
 
-  GNUNET_assert (message != NULL);
-  GNUNET_assert (GNUNET_OK ==
-                 GNUNET_HELLO_get_id ((const struct GNUNET_HELLO_Message *)
-                                      message, &me->id));
+  second_daemon = GNUNET_CONTAINER_multihashmap_get(peer_daemon_hash, &peer->hashPubKey);
 
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Received HELLO size %d\n", GNUNET_HELLO_size((const struct GNUNET_HELLO_Message *)message));
+  if (second_daemon == NULL)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Couldn't find second peer!\n");
+      GNUNET_free(second_shortname);
+      return;
+    }
+#if !TEST_ALL
+  if (distance > 1)
+    {
+      temp_total_other_messages++;
+      temp_context = GNUNET_malloc(sizeof(struct TestMessageContext));
+      temp_context->peer1 = d;
+      temp_context->peer2 = second_daemon;
+      temp_context->next = other_test_messages;
+      temp_context->uid = total_connections + temp_total_other_messages;
+      temp_context->disconnect_task = GNUNET_SCHEDULER_NO_TASK;
+      other_test_messages = temp_context;
+    }
+#endif
 
 
-  me->hello = GNUNET_malloc(GNUNET_HELLO_size((const struct GNUNET_HELLO_Message *)message));
-  memcpy(me->hello, message, GNUNET_HELLO_size((const struct GNUNET_HELLO_Message *)message));
 
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "All HELLO's received, setting up blacklists!\n");
+  if (dotOutFile != NULL)
+    {
+      if (distance == 1)
+        fprintf(dotOutFile, "\tn%s -- n%s;\n", d->shortname, second_shortname);
+      else if (distance == 2)
+        fprintf(dotOutFile, "\tn%s -- n%s [color=blue];\n", d->shortname, second_shortname);
+      else if (distance == 3)
+        fprintf(dotOutFile, "\tn%s -- n%s [color=red];\n", d->shortname, second_shortname);
+      else if (distance == 4)
+        fprintf(dotOutFile, "\tn%s -- n%s [color=green];\n", d->shortname, second_shortname);
+      else
+        fprintf(dotOutFile, "\tn%s -- n%s [color=brown];\n", d->shortname, second_shortname);
+    }
+  GNUNET_free(second_shortname);
 
 
-  GNUNET_SCHEDULER_add_now(sched, &setup_blacklists, NULL);
+  if (temp_total_other_messages == num_additional_messages)
+    {
+      GNUNET_SCHEDULER_add_now (&send_other_messages, NULL);
+    }
 }
 
 }
 
-
 static void
 static void
-get_hello_third (void *cls,
-                const struct GNUNET_MessageHeader *message)
+peers_started_callback (void *cls,
+       const struct GNUNET_PeerIdentity *id,
+       const struct GNUNET_CONFIGURATION_Handle *cfg,
+       struct GNUNET_TESTING_Daemon *d, const char *emsg)
 {
 {
-  struct PeerContext *me = cls;
-
-  GNUNET_TRANSPORT_get_hello_cancel (me->th, &get_hello_third, me);
-
-  GNUNET_assert (message != NULL);
-  GNUNET_assert (GNUNET_OK ==
-                 GNUNET_HELLO_get_id ((const struct GNUNET_HELLO_Message *)
-                                      message, &me->id));
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Received HELLO size %d\n", GNUNET_HELLO_size((const struct GNUNET_HELLO_Message *)message));
+  struct PeerContext *new_peer;
+  if (emsg != NULL)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to start daemon with error: `%s'\n",
+                  emsg);
+      return;
+    }
+  GNUNET_assert (id != NULL);
+#if VERBOSE
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Started daemon %llu out of %llu\n",
+              (num_peers - peers_left) + 1, num_peers);
+#endif
+  GNUNET_assert(GNUNET_SYSERR != GNUNET_CONTAINER_multihashmap_put(peer_daemon_hash, &id->hashPubKey, d, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
+
+  new_peer = GNUNET_malloc(sizeof(struct PeerContext));
+  new_peer->peer_handle = GNUNET_CORE_connect(cfg, 
+                                             1,
+                                             GNUNET_TIME_UNIT_FOREVER_REL,
+                                             d, NULL,
+                                             &all_connect_handler, 
+                                             NULL, NULL, NULL, 
+                                             GNUNET_NO, NULL, GNUNET_NO,
+                                             no_handlers);
+  new_peer->daemon = d;
+  new_peer->next = all_peers;
+  all_peers = new_peer;
+  peers_left--;
+
+  if (peers_left == 0)
+    {
+#if VERBOSE
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                  "All %d daemons started, now creating topology!\n",
+                  num_peers);
+#endif
+      GNUNET_SCHEDULER_cancel (die_task);
+      /* Set up task in case topology creation doesn't finish
+       * within a reasonable amount of time */
+      die_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
+                                               (GNUNET_TIME_UNIT_MINUTES, 5),
+                                               &end_badly, "from peers_started_callback");
+
+      connect_topology ();
+      ok = 0;
+    }
+}
 
 
-  me->hello = GNUNET_malloc(GNUNET_HELLO_size((const struct GNUNET_HELLO_Message *)message));
-  memcpy(me->hello, message, GNUNET_HELLO_size((const struct GNUNET_HELLO_Message *)message));
+/**
+ * Callback indicating that the hostkey was created for a peer.
+ *
+ * @param cls NULL
+ * @param id the peer identity
+ * @param d the daemon handle (pretty useless at this point, remove?)
+ * @param emsg non-null on failure
+ */
+void hostkey_callback (void *cls,
+                       const struct GNUNET_PeerIdentity *id,
+                       struct GNUNET_TESTING_Daemon *d,
+                       const char *emsg)
+{
+  if (emsg != NULL)
+    {
+      GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Hostkey callback received error: %s\n", emsg);
+    }
 
 
-  GNUNET_TRANSPORT_get_hello (p4.th, &get_hello_fourth, &p4);
+#if VERBOSE
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Hostkey created for peer `%s'\n",
+                GNUNET_i2s(id));
+#endif
+    peers_left--;
+    if (peers_left == 0)
+      {
+#if VERBOSE
+        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                    "All %d hostkeys created, now creating topology!\n",
+                    num_peers);
+#endif
+        GNUNET_SCHEDULER_cancel (die_task);
+        /* Set up task in case topology creation doesn't finish
+         * within a reasonable amount of time */
+        die_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
+                                                 (GNUNET_TIME_UNIT_MINUTES, 5),
+                                                 &end_badly, "from hostkey_callback");
+        GNUNET_SCHEDULER_add_now(&create_topology, NULL);
+        ok = 0;
+      }
 }
 
 }
 
-
 static void
 static void
-get_hello_second (void *cls,
-                const struct GNUNET_MessageHeader *message)
+run (void *cls,
+     char *const *args,
+     const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg)
 {
 {
-  struct PeerContext *me = cls;
-
-  GNUNET_TRANSPORT_get_hello_cancel (me->th, &get_hello_second, me);
+  char * topology_str;
+  char * connect_topology_str;
+  char * blacklist_topology_str;
+  char * connect_topology_option_str;
+  char * connect_topology_option_modifier_string;
+  ok = 1;
 
 
-  GNUNET_assert (message != NULL);
-  GNUNET_assert (GNUNET_OK ==
-                 GNUNET_HELLO_get_id ((const struct GNUNET_HELLO_Message *)
-                                      message, &me->id));
+  dotOutFile = fopen (dotOutFileName, "w");
+  if (dotOutFile != NULL)
+    {
+      fprintf (dotOutFile, "strict graph G {\n");
+    }
 
 
+#if VERBOSE
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Received HELLO size %d\n", GNUNET_HELLO_size((const struct GNUNET_HELLO_Message *)message));
+              "Starting daemons based on config file %s\n", cfgfile);
+#endif
 
 
-  me->hello = GNUNET_malloc(GNUNET_HELLO_size((const struct GNUNET_HELLO_Message *)message));
-  memcpy(me->hello, message, GNUNET_HELLO_size((const struct GNUNET_HELLO_Message *)message));
+  if (GNUNET_YES != GNUNET_CONFIGURATION_get_value_string(cfg, "paths", "servicehome", &test_directory))
+    {
+      ok = 404;
+      return;
+    }
 
 
-  GNUNET_TRANSPORT_get_hello (p3.th, &get_hello_third, &p3);
-}
+  if ((GNUNET_YES ==
+      GNUNET_CONFIGURATION_get_value_string(cfg, "testing", "topology",
+                                            &topology_str)) && (GNUNET_NO == GNUNET_TESTING_topology_get(&topology, topology_str)))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                  "Invalid topology `%s' given for section %s option %s\n", topology_str, "TESTING", "TOPOLOGY");
+      topology = GNUNET_TESTING_TOPOLOGY_CLIQUE; /* Defaults to NONE, so set better default here */
+    }
 
 
+  if ((GNUNET_YES ==
+      GNUNET_CONFIGURATION_get_value_string(cfg, "testing", "connect_topology",
+                                            &connect_topology_str)) && (GNUNET_NO == GNUNET_TESTING_topology_get(&connection_topology, connect_topology_str)))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                  "Invalid connect topology `%s' given for section %s option %s\n", connect_topology_str, "TESTING", "CONNECT_TOPOLOGY");
+    }
+  GNUNET_free_non_null(connect_topology_str);
+  if ((GNUNET_YES ==
+      GNUNET_CONFIGURATION_get_value_string(cfg, "testing", "connect_topology_option",
+                                            &connect_topology_option_str)) && (GNUNET_NO == GNUNET_TESTING_topology_option_get(&connect_topology_option, connect_topology_option_str)))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                  "Invalid connect topology option `%s' given for section %s option %s\n", connect_topology_option_str, "TESTING", "CONNECT_TOPOLOGY_OPTION");
+      connect_topology_option = GNUNET_TESTING_TOPOLOGY_OPTION_ALL; /* Defaults to NONE, set to ALL */
+    }
+  GNUNET_free_non_null(connect_topology_option_str);
+  if (GNUNET_YES ==
+        GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "connect_topology_option_modifier",
+                                               &connect_topology_option_modifier_string))
+    {
+      if (sscanf(connect_topology_option_modifier_string, "%lf", &connect_topology_option_modifier) != 1)
+      {
+        GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+        _("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
+        connect_topology_option_modifier_string,
+        "connect_topology_option_modifier",
+        "TESTING");
+      }
+      GNUNET_free (connect_topology_option_modifier_string);
+    }
 
 
-static void
-get_hello_first (void *cls,
-                const struct GNUNET_MessageHeader *message)
-{
-  struct PeerContext *me = cls;
+  if (GNUNET_YES != GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "blacklist_transports",
+                                         &blacklist_transports))
+    blacklist_transports = NULL;
 
 
-  GNUNET_TRANSPORT_get_hello_cancel (me->th, &get_hello_first, me);
+  if ((GNUNET_YES ==
+      GNUNET_CONFIGURATION_get_value_string(cfg, "testing", "blacklist_topology",
+                                            &blacklist_topology_str)) && (GNUNET_NO == GNUNET_TESTING_topology_get(&blacklist_topology, blacklist_topology_str)))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                  "Invalid topology `%s' given for section %s option %s\n", topology_str, "TESTING", "BLACKLIST_TOPOLOGY");
+    }
+  GNUNET_free_non_null(topology_str);
+  GNUNET_free_non_null(blacklist_topology_str);
+  if (GNUNET_SYSERR ==
+      GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "num_peers",
+                                             &num_peers))
+    num_peers = DEFAULT_NUM_PEERS;
 
 
-  GNUNET_assert (message != NULL);
-  GNUNET_assert (GNUNET_OK ==
-                 GNUNET_HELLO_get_id ((const struct GNUNET_HELLO_Message *)
-                                      message, &me->id));
+  if (GNUNET_SYSERR ==
+      GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "additional_messages",
+                                             &num_additional_messages))
+    num_additional_messages = DEFAULT_ADDITIONAL_MESSAGES;
 
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Received HELLO size %d\n", GNUNET_HELLO_size((const struct GNUNET_HELLO_Message *)message));
+  main_cfg = cfg;
 
 
-  me->hello = GNUNET_malloc(GNUNET_HELLO_size((const struct GNUNET_HELLO_Message *)message));
-  memcpy(me->hello, message, GNUNET_HELLO_size((const struct GNUNET_HELLO_Message *)message));
+  GNUNET_assert(num_peers > 0 && num_peers < (unsigned int)-1);
+  peers_left = num_peers;
 
 
-  GNUNET_TRANSPORT_get_hello (p2.th, &get_hello_second, &p2);
-}
+  /* Set up a task to end testing if peer start fails */
+  die_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
+                                           (GNUNET_TIME_UNIT_MINUTES, 5),
+                                           &end_badly, "didn't start all daemons in reasonable amount of time!!!");
+
+  peer_daemon_hash = GNUNET_CONTAINER_multihashmap_create(peers_left);
+  pg = GNUNET_TESTING_daemons_start (cfg,
+                                     peers_left, TIMEOUT, &hostkey_callback, NULL, &peers_started_callback, NULL,
+                                     &topology_callback, NULL, NULL);
 
 
-static void
-run (void *cls,
-     struct GNUNET_SCHEDULER_Handle *s,
-     char *const *args,
-     const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg)
-{
-  GNUNET_assert (ok == 1);
-  OKPP;
-  sched = s;
-
-  die_task = GNUNET_SCHEDULER_add_delayed (sched,
-      GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 5), &end_badly, NULL);
-
-  setup_peer (&p1, "test_transport_api_dv_peer1.conf");
-  setup_peer (&p2, "test_transport_api_dv_peer2.conf");
-  setup_peer (&p3, "test_transport_api_dv_peer3.conf");
-  setup_peer (&p4, "test_transport_api_dv_peer4.conf");
-
-  p1.th = GNUNET_TRANSPORT_connect (sched, p1.cfg,
-                                    &p1,
-                                    &notify_receive,
-                                    &notify_connect, &notify_disconnect);
-
-  p2.th = GNUNET_TRANSPORT_connect (sched, p2.cfg,
-                                    &p2,
-                                    &notify_receive,
-                                    &notify_connect, &notify_disconnect);
-
-  p3.th = GNUNET_TRANSPORT_connect (sched, p3.cfg,
-                                    &p3,
-                                    &notify_receive,
-                                    &notify_connect, &notify_disconnect);
-
-  p4.th = GNUNET_TRANSPORT_connect (sched, p4.cfg,
-                                    &p4,
-                                    &notify_receive,
-                                    &notify_connect, &notify_disconnect);
-  GNUNET_assert(p1.th != NULL);
-  GNUNET_assert(p2.th != NULL);
-  GNUNET_assert(p3.th != NULL);
-  GNUNET_assert(p4.th != NULL);
-
-  GNUNET_TRANSPORT_get_hello (p1.th, &get_hello_first, &p1);
 }
 
 static int
 check ()
 {
 }
 
 static int
 check ()
 {
-
-  char *const argv[] = { "test-transport-api",
+  int ret;
+  char *const argv[] = {"test-transport-dv",
     "-c",
     "-c",
-    "test_transport_api_data.conf",
+    "test_transport_dv_data.conf",
 #if VERBOSE
     "-L", "DEBUG",
 #endif
     NULL
   };
 #if VERBOSE
     "-L", "DEBUG",
 #endif
     NULL
   };
-
   struct GNUNET_GETOPT_CommandLineOption options[] = {
     GNUNET_GETOPT_OPTION_END
   };
   struct GNUNET_GETOPT_CommandLineOption options[] = {
     GNUNET_GETOPT_OPTION_END
   };
-
-  ok = 1;
-  GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1,
-                      argv, "test-transport-api", "nohelp",
+  ret = GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1,
+                      argv, "test-transport-dv", "nohelp",
                       options, &run, &ok);
                       options, &run, &ok);
-  stop_arm (&p1);
-  stop_arm (&p2);
-  stop_arm (&p3);
-  stop_arm (&p4);
+  if (ret != GNUNET_OK)
+    {
+      GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "`test-transport-dv': Failed with error code %d\n", ret);
+    }
   return ok;
 }
 
   return ok;
 }
 
-
 int
 main (int argc, char *argv[])
 {
   int ret;
 int
 main (int argc, char *argv[])
 {
   int ret;
-#ifdef MINGW
-  return GNUNET_SYSERR;
-#endif
 
 
-  GNUNET_log_setup ("test-transport-api-dv",
+  GNUNET_log_setup ("test-transport-dv",
 #if VERBOSE
                     "DEBUG",
 #else
 #if VERBOSE
                     "DEBUG",
 #else
@@ -656,12 +1104,15 @@ main (int argc, char *argv[])
 #endif
                     NULL);
   ret = check ();
 #endif
                     NULL);
   ret = check ();
-  GNUNET_DISK_directory_remove ("/tmp/test-gnunetd-transport-peer-1");
-  GNUNET_DISK_directory_remove ("/tmp/test-gnunetd-transport-peer-2");
-  GNUNET_DISK_directory_remove ("/tmp/test-gnunetd-transport-peer-3");
-  GNUNET_DISK_directory_remove ("/tmp/test-gnunetd-transport-peer-4");
+  /**
+   * Need to remove base directory, subdirectories taken care
+   * of by the testing framework.
+   */
+  if (GNUNET_DISK_directory_remove (test_directory) != GNUNET_OK)
+    {
+      GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Failed to remove testing directory %s\n", test_directory);
+    }
   return ret;
 }
 
 /* end of test_transport_api_dv.c */
   return ret;
 }
 
 /* end of test_transport_api_dv.c */
-