-fix fix
[oweals/gnunet.git] / src / mesh / gnunet-regex-profiler.c
index 7d1ad103546aaa9949619cbbcb4429d9ffd24163..49eb2b91c817f6f117dcf66b26478494d274914d 100644 (file)
@@ -1,4 +1,4 @@
-/*
+/**
      This file is part of GNUnet.
      (C) 2011, 2012 Christian Grothoff (and other contributing authors)
 
@@ -92,11 +92,6 @@ enum State
    */
   STATE_PEERS_LINKING,
 
-  /**
-   * Announcing regexes
-   */
-  STATE_ANNOUNCE_REGEX,
-
   /**
    * Matching strings against announced regexes
    */
@@ -110,11 +105,6 @@ enum State
 };
 
 
-/**
- * An array of hosts loaded from the hostkeys file
- */
-static struct GNUNET_TESTBED_Host **hosts;
-
 /**
  * Peer handles.
  */
@@ -125,6 +115,11 @@ struct RegexPeer
    */
   unsigned int id;
 
+  /**
+   * Peer configuration handle.
+   */
+  struct GNUNET_CONFIGURATION_Handle *cfg;
+
   /**
    * The actual testbed peer handle.
    */
@@ -145,6 +140,14 @@ struct RegexPeer
    */
   const char *search_str;
 
+  /**
+   * Set to GNUNET_YES if the peer successfully matched the above
+   * search string. GNUNET_NO if the string could not be matched
+   * during the profiler run. GNUNET_SYSERR if the string matching
+   * timed out. Undefined if search_str is NULL
+   */
+  int search_str_matched;
+
   /**
    * Peer's mesh handle.
    */
@@ -176,11 +179,17 @@ struct RegexPeer
   struct GNUNET_TIME_Absolute prof_start_time;
 };
 
+
+/**
+ * An array of hosts loaded from the hostkeys file
+ */
+static struct GNUNET_TESTBED_Host **hosts;
+
 /**
  * Array of peer handles used to pass to
  * GNUNET_TESTBED_overlay_configure_topology
  */
-struct GNUNET_TESTBED_Peer **peer_handles;
+static struct GNUNET_TESTBED_Peer **peer_handles;
 
 /**
  * The array of peers; we fill this as the peers are given to us by the testbed
@@ -195,32 +204,32 @@ static struct GNUNET_TESTBED_HostRegistrationHandle *reg_handle;
 /**
  * Handle to the master controller process
  */
-struct GNUNET_TESTBED_ControllerProc *mc_proc;
+static struct GNUNET_TESTBED_ControllerProc *mc_proc;
 
 /**
  * Handle to the master controller
  */
-struct GNUNET_TESTBED_Controller *mc;
+static struct GNUNET_TESTBED_Controller *mc;
 
 /**
  * Handle to global configuration
  */
-struct GNUNET_CONFIGURATION_Handle *cfg;
+static struct GNUNET_CONFIGURATION_Handle *cfg;
 
 /**
  * Head of the operations list
  */
-struct DLLOperation *dll_op_head;
+static struct DLLOperation *dll_op_head;
 
 /**
  * Tail of the operations list
  */
-struct DLLOperation *dll_op_tail;
+static struct DLLOperation *dll_op_tail;
 
 /**
  * Peer linking - topology operation
  */
-struct GNUNET_TESTBED_Operation *topology_op;
+static struct GNUNET_TESTBED_Operation *topology_op;
 
 /**
  * Abort task identifier
@@ -235,22 +244,17 @@ static GNUNET_SCHEDULER_TaskIdentifier register_hosts_task;
 /**
  * Global event mask for all testbed events
  */
-uint64_t event_mask;
+static uint64_t event_mask;
 
 /**
  * The starting time of a profiling step
  */
-struct GNUNET_TIME_Absolute prof_start_time;
+static struct GNUNET_TIME_Absolute prof_start_time;
 
 /**
  * Duration profiling step has taken
  */
-struct GNUNET_TIME_Relative prof_time;
-
-/**
- * Current peer id
- */
-unsigned int peer_id;
+static struct GNUNET_TIME_Relative prof_time;
 
 /**
  * Number of peers to be started by the profiler
@@ -272,11 +276,6 @@ static unsigned int linking_factor;
  */
 static unsigned int num_links;
 
-/**
- * Number of timeout failures to tolerate
- */
-static unsigned int num_cont_fails;
-
 /**
  * Number of times we try overlay connect operations
  */
@@ -338,6 +337,11 @@ static struct GNUNET_TIME_Relative search_timeout = { 60000 };
  */
 static struct GNUNET_TIME_Relative search_delay = { 60000 };
 
+/**
+ * Delay to wait before starting to configure the overlay topology
+ */
+static struct GNUNET_TIME_Relative conf_topo_delay = { 10000 };
+
 /**
  * File to log statistics to.
  */
@@ -353,11 +357,6 @@ static char *data_filename;
  */
 static unsigned int max_path_compression;
 
-/**
- * Delay before setting mesh service op as done.
- */
-static struct GNUNET_TIME_Relative mesh_done_delay = { 1000 };
-
 /******************************************************************************/
 /******************************  DECLARATIONS  ********************************/
 /******************************************************************************/
@@ -371,7 +370,7 @@ static struct GNUNET_TIME_Relative mesh_done_delay = { 1000 };
  * @param atsi performance data for the connection
  *
  */
-void
+static void
 mesh_peer_connect_handler (void *cls,
                            const struct GNUNET_PeerIdentity* peer_id,
                            const struct GNUNET_ATS_Information * atsi);
@@ -387,7 +386,7 @@ mesh_peer_connect_handler (void *cls,
  * @param cls closure
  * @param peer_id peer identity the tunnel stopped working with
  */
-void
+static void
 mesh_peer_disconnect_handler (void *cls,
                               const struct GNUNET_PeerIdentity * peer_id);
 
@@ -399,7 +398,7 @@ mesh_peer_disconnect_handler (void *cls,
  * @param ca_result connect adapter result.
  * @param emsg error message.
  */
-void
+static void
 mesh_connect_cb (void *cls, struct GNUNET_TESTBED_Operation *op,
                  void *ca_result, const char *emsg);
 
@@ -411,7 +410,7 @@ mesh_connect_cb (void *cls, struct GNUNET_TESTBED_Operation *op,
  *
  * @return
  */
-void *
+static void *
 mesh_ca (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg);
 
 
@@ -422,7 +421,7 @@ mesh_ca (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg);
  * @param cls closure
  * @param op_result service handle returned from the connect adapter
  */
-void
+static void
 mesh_da (void *cls, void *op_result);
 
 
@@ -441,26 +440,56 @@ static void
 do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
   struct DLLOperation *dll_op;
+  struct RegexPeer *peer;
   unsigned int nhost;
   unsigned int peer_cnt;
   unsigned int search_str_cnt;
+  char output_buffer[512];
+  size_t size;
+
+  if (GNUNET_SCHEDULER_NO_TASK != abort_task)
+    GNUNET_SCHEDULER_cancel (abort_task);
+  if (GNUNET_SCHEDULER_NO_TASK != register_hosts_task)
+    GNUNET_SCHEDULER_cancel (register_hosts_task);
 
   for (peer_cnt = 0; peer_cnt < num_peers; peer_cnt++)
   {
+    peer = &peers[peer_cnt];
+
+    if (GNUNET_YES != peer->search_str_matched && NULL != data_file)
+    {
+      prof_time = GNUNET_TIME_absolute_get_duration (peer->prof_start_time);
+      size =
+        GNUNET_snprintf (output_buffer,
+                         sizeof (output_buffer),
+                         "Search string not found: %s (%d)\nOn peer: %u (%p)\nWith policy file: %s\nAfter: %s\n",
+                         peer->search_str,
+                         peer->search_str_matched,
+                         peer->id,
+                         peer,
+                         peer->policy_file,
+                         GNUNET_STRINGS_relative_time_to_string (prof_time, GNUNET_NO));
+      if (size != GNUNET_DISK_file_write (data_file, output_buffer, size))
+        GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Unable to write to file!\n");
+    }
+
     if (NULL != peers[peer_cnt].mesh_op_handle)
       GNUNET_TESTBED_operation_done (peers[peer_cnt].mesh_op_handle);
     if (NULL != peers[peer_cnt].stats_op_handle)
       GNUNET_TESTBED_operation_done (peers[peer_cnt].stats_op_handle);
   }
-  for (search_str_cnt = 0; search_str_cnt < num_search_strings; search_str_cnt++)
+
+  if (NULL != data_file)
+    GNUNET_DISK_file_close (data_file);
+
+  for (search_str_cnt = 0;
+       search_str_cnt < num_search_strings && NULL != search_strings;
+       search_str_cnt++)
   {
-    GNUNET_free (search_strings[search_str_cnt]);
+    GNUNET_free_non_null (search_strings[search_str_cnt]);
   }
-  GNUNET_free (search_strings);
-  if (GNUNET_SCHEDULER_NO_TASK != abort_task)
-    GNUNET_SCHEDULER_cancel (abort_task);
-  if (GNUNET_SCHEDULER_NO_TASK != register_hosts_task)
-    GNUNET_SCHEDULER_cancel (register_hosts_task);
+  GNUNET_free_non_null (search_strings);
+
   if (NULL != reg_handle)
     GNUNET_TESTBED_cancel_registration (reg_handle);
   if (NULL != topology_op)
@@ -469,6 +498,7 @@ do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
     if (NULL != hosts[nhost])
       GNUNET_TESTBED_host_destroy (hosts[nhost]);
   GNUNET_free_non_null (hosts);
+
   while (NULL != (dll_op = dll_op_head))
   {
     GNUNET_TESTBED_operation_done (dll_op->op);
@@ -481,8 +511,6 @@ do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
     GNUNET_TESTBED_controller_stop (mc_proc);
   if (NULL != cfg)
     GNUNET_CONFIGURATION_destroy (cfg);
-  if (NULL != data_file)
-    GNUNET_DISK_file_close (data_file);
 
   GNUNET_SCHEDULER_shutdown ();        /* Stop scheduler to shutdown testbed run */
 }
@@ -535,12 +563,17 @@ stats_ca (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg)
 static void
 stats_da (void *cls, void *op_result)
 {
-  GNUNET_STATISTICS_destroy (op_result, GNUNET_NO);
+  struct RegexPeer *peer = cls;
+
+  GNUNET_assert (op_result == peer->stats_handle);
+
+  GNUNET_STATISTICS_destroy (peer->stats_handle, GNUNET_NO);
+  peer->stats_handle = NULL;
 }
 
 
 /**
- * Process statistic values.
+ * Process statistic values. Write all values to global 'data_file', if present.
  *
  * @param cls closure
  * @param subsystem name of subsystem that created the statistic
@@ -578,7 +611,8 @@ stats_iterator (void *cls, const char *subsystem, const char *name,
 
 
 /**
- * Stats callback.
+ * Stats callback. Finish the stats testbed operation and when all stats have
+ * been iterated, shutdown the profiler.
  *
  * @param cls closure
  * @param success GNUNET_OK if statistics were
@@ -604,13 +638,15 @@ stats_cb (void *cls,
 
   if (++peer_cnt == num_search_strings)
   {
-    GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
+    struct GNUNET_TIME_Relative delay = { 100 };
+    GNUNET_SCHEDULER_add_delayed (delay, &do_shutdown, NULL);
   }
 }
 
 
 /**
- * Function called by testbed once we are connected to stats service.
+ * Function called by testbed once we are connected to stats service. Create a
+ * mesh tunnel and try to match the peer's string.
  *
  * @param cls the 'struct RegexPeer' for which we connected to stats
  * @param op connect operation handle
@@ -641,12 +677,13 @@ stats_connect_cb (void *cls,
 
   peer->mesh_tunnel_handle = GNUNET_MESH_tunnel_create (peer->mesh_handle,
                                                         NULL,
-                                                       &mesh_peer_connect_handler,
+                                                        &mesh_peer_connect_handler,
                                                         &mesh_peer_disconnect_handler,
                                                         peer);
 
   peer->prof_start_time = GNUNET_TIME_absolute_get ();
 
+  peer->search_str_matched = GNUNET_NO;
   GNUNET_MESH_peer_request_connect_by_string (peer->mesh_tunnel_handle,
                                               peer->search_str);
 }
@@ -656,52 +693,6 @@ stats_connect_cb (void *cls,
 /************************  MESH SERVICE CONNECTIONS  **************************/
 /******************************************************************************/
 
-/**
- * Method called whenever another peer has added us to a tunnel
- * the other peer initiated.
- * Only called (once) upon reception of data with a message type which was
- * subscribed to in GNUNET_MESH_connect. A call to GNUNET_MESH_tunnel_destroy
- * causes te tunnel to be ignored and no further notifications are sent about
- * the same tunnel.
- *
- * @param cls closure
- * @param tunnel new handle to the tunnel
- * @param initiator peer that started the tunnel
- * @param atsi performance information for the tunnel
- * @return initial tunnel context for the tunnel
- *         (can be NULL -- that's not an error)
- */
-void *
-mesh_inbound_tunnel_handler (void *cls, struct GNUNET_MESH_Tunnel *tunnel,
-                             const struct GNUNET_PeerIdentity *initiator,
-                             const struct GNUNET_ATS_Information *atsi)
-{
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Mesh inbound tunnel handler.\n");
-
-  return NULL;
-}
-
-
-/**
- * Function called whenever an inbound tunnel is destroyed.  Should clean up
- * any associated state.  This function is NOT called if the client has
- * explicitly asked for the tunnel to be destroyed using
- * GNUNET_MESH_tunnel_destroy. It must NOT call GNUNET_MESH_tunnel_destroy on
- * the tunnel.
- *
- * @param cls closure (set from GNUNET_MESH_connect)
- * @param tunnel connection to the other end (henceforth invalid)
- * @param tunnel_ctx place where local state associated
- *                   with the tunnel is stored
- */
-void
-mesh_tunnel_end_handler (void *cls, const struct GNUNET_MESH_Tunnel *tunnel,
-                         void *tunnel_ctx)
-{
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Mesh tunnel end handler.\n");
-}
-
-
 /**
  * Method called whenever a peer has disconnected from the tunnel.
  * Implementations of this callback must NOT call
@@ -712,7 +703,7 @@ mesh_tunnel_end_handler (void *cls, const struct GNUNET_MESH_Tunnel *tunnel,
  * @param cls closure
  * @param peer_id peer identity the tunnel stopped working with
  */
-void
+static void
 mesh_peer_disconnect_handler (void *cls,
                               const struct GNUNET_PeerIdentity * peer_id)
 {
@@ -721,14 +712,16 @@ mesh_peer_disconnect_handler (void *cls,
 
 
 /**
- * Method called whenever a peer has connected to the tunnel.
+ * Method called when the mesh connection succeeded (or timed out), which means
+ * we've found a peer that announced a regex that matches our search string. Now
+ * get the statistics.
  *
  * @param cls closure
  * @param peer_id peer identity the tunnel was created to, NULL on timeout
  * @param atsi performance data for the connection
  *
  */
-void
+static void
 mesh_peer_connect_handler (void *cls,
                            const struct GNUNET_PeerIdentity* peer_id,
                            const struct GNUNET_ATS_Information * atsi)
@@ -744,6 +737,11 @@ mesh_peer_connect_handler (void *cls,
     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
                 "String matching timed out for string %s on peer %u (%i/%i)\n",
                 peer->search_str, peer->id, peers_found, num_search_strings);
+
+    printf ("String matching timed out for string %s on peer %u (%i/%i)\n",
+            peer->search_str, peer->id, peers_found, num_search_strings);
+
+    peer->search_str_matched = GNUNET_SYSERR;
   }
   else
   {
@@ -754,10 +752,12 @@ mesh_peer_connect_handler (void *cls,
                 peers_found, num_search_strings);
 
     printf ("String %s successfully matched on peer %u after %s (%i/%i)\n",
-           peer->search_str, peer->id, GNUNET_STRINGS_relative_time_to_string (prof_time, GNUNET_NO),
-           peers_found, num_search_strings);
+            peer->search_str, peer->id, GNUNET_STRINGS_relative_time_to_string (prof_time, GNUNET_NO),
+            peers_found, num_search_strings);
     fflush (stdout);
 
+    peer->search_str_matched = GNUNET_YES;
+
     if (NULL != data_file)
     {
       size =
@@ -778,7 +778,7 @@ mesh_peer_connect_handler (void *cls,
     if (NULL == peer->stats_handle)
     {
       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                 "Cannot get statistics for peer %u, stats handle is NULL!\n");
+                  "Cannot get statistics for peer %u, stats handle is NULL!\n");
       return;
     }
 
@@ -790,6 +790,14 @@ mesh_peer_connect_handler (void *cls,
       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                   "Could not get mesh statistics of peer %u!\n", peer->id);
     }
+    if (NULL == GNUNET_STATISTICS_get (peer->stats_handle, "regexprofiler", NULL,
+                                       GNUNET_TIME_UNIT_FOREVER_REL,
+                                       NULL,
+                                       &stats_iterator, peer))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                  "Could not get regexprofiler statistics of peer %u!\n", peer->id);
+    }
     if (NULL == GNUNET_STATISTICS_get (peer->stats_handle, "transport", NULL,
                                        GNUNET_TIME_UNIT_FOREVER_REL,
                                        NULL,
@@ -824,7 +832,8 @@ mesh_peer_connect_handler (void *cls,
 
 
 /**
- * Connect by string timeout task
+ * Connect by string timeout task. This will cancel the profiler after the
+ * specified timeout 'search_timeout'.
  *
  * @param cls NULL
  * @param tc the task context
@@ -844,7 +853,9 @@ do_connect_by_string_timeout (void *cls,
 
 
 /**
- * Connect by string task that is run to search for a string in the NFA
+ * Connect by string task that is run to search for a string in the NFA. It
+ * first connects to the mesh service, then connects to the stats service of
+ * this peer and then it starts the string search.
  *
  * @param cls NULL
  * @param tc the task context
@@ -863,6 +874,7 @@ do_connect_by_string (void *cls,
   {
     peer = &peers[search_cnt % num_peers];
     peer->search_str = search_strings[search_cnt];
+    peer->search_str_matched = GNUNET_NO;
 
     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
                 "Searching for string \"%s\" on peer %d with file %s\n",
@@ -887,170 +899,53 @@ do_connect_by_string (void *cls,
 
 
 /**
- * Delayed operation done for mesh service disconnects.
- *
- * @param cls NULL
- * @param tc the task context
- */
-static void
-do_mesh_op_done (void *cls,
-                const struct GNUNET_SCHEDULER_TaskContext * tc)
-{
-  struct RegexPeer *peer = cls;
-  GNUNET_TESTBED_operation_done (peer->mesh_op_handle);
-  peer->mesh_op_handle = NULL;
-}
-
-
-/**
- * Mesh connect callback.
+ * Mesh connect callback. Called when we are connected to the mesh service for
+ * the peer in 'cls'. If successfull we connect to the stats service of this
+ * peer and then try to match the search string of this peer.
  *
  * @param cls internal peer id.
  * @param op operation handle.
  * @param ca_result connect adapter result.
  * @param emsg error message.
  */
-void
+static void
 mesh_connect_cb (void *cls, struct GNUNET_TESTBED_Operation *op,
                  void *ca_result, const char *emsg)
 {
-  static unsigned int peer_cnt;
   struct RegexPeer *peer = (struct RegexPeer *) cls;
-  char *regex;
-  char *data;
-  char *buf;
-  uint64_t filesize;
-  unsigned int offset;
 
   if (NULL != emsg || NULL == op || NULL == ca_result)
   {
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Mesh connect failed: %s\n", emsg);
     GNUNET_assert (0);
   }
-  
+
   GNUNET_assert (peer->mesh_handle != NULL);
   GNUNET_assert (peer->mesh_op_handle == op);
   GNUNET_assert (peer->mesh_handle == ca_result);
-  GNUNET_assert (NULL != peer->policy_file);
-
-  switch (state)
-  {
-  case STATE_ANNOUNCE_REGEX:
-    {
-      static unsigned int num_files_announced;
 
-      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                 "Announcing regexes for peer %u with file %s\n",
-                 peer->id, peer->policy_file);
-      
-      if (GNUNET_YES != GNUNET_DISK_file_test (peer->policy_file))
-      {
-       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                   "Could not find policy file %s\n", peer->policy_file);
-       return;
-      }
-      if (GNUNET_OK != GNUNET_DISK_file_size (peer->policy_file, &filesize, GNUNET_YES, GNUNET_YES))
-       filesize = 0;
-      if (0 == filesize)
-      {
-       GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Policy file %s is empty.\n", peer->policy_file);
-       return;
-      }
-      data = GNUNET_malloc (filesize);
-      if (filesize != GNUNET_DISK_fn_read (peer->policy_file, data, filesize))
-      {
-       GNUNET_free (data);
-       GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Could not read policy file %s.\n",
-                   peer->policy_file);
-       return;
-      }
-      buf = data;
-      offset = 0;
-      regex = NULL;
-      while (offset < (filesize - 1))
-      {
-       offset++;
-       if (((data[offset] == '\n')) && (buf != &data[offset]))
-       {
-         data[offset] = '\0';
-         regex = buf;
-         GNUNET_assert (NULL != regex);
-         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Announcing regex: %s on peer %u \n",
-                 regex, peer->id);
-         GNUNET_MESH_announce_regex (peer->mesh_handle, regex, max_path_compression);
-         buf = &data[offset + 1];
-       }
-       else if ((data[offset] == '\n') || (data[offset] == '\0'))
-         buf = &data[offset + 1];
-      }
-      GNUNET_free (data);
-
-      GNUNET_SCHEDULER_add_delayed (mesh_done_delay, &do_mesh_op_done, peer);
-      
-      if (++peer_cnt < num_peers)
-      {
-         peers[peer_cnt].mesh_op_handle =
-           GNUNET_TESTBED_service_connect (NULL,
-                                           peers[peer_cnt].peer_handle,
-                                           "mesh",
-                                           &mesh_connect_cb,
-                                           &peers[peer_cnt],
-                                           &mesh_ca,
-                                           &mesh_da,
-                                           &peers[peer_cnt]);
-      }
-
-      if (++num_files_announced == num_peers)
-      {
-       state = STATE_SEARCH_REGEX;
-
-       prof_time = GNUNET_TIME_absolute_get_duration (prof_start_time);
-       
-       printf ("All files announced in %s.\n",
-               GNUNET_STRINGS_relative_time_to_string (prof_time, GNUNET_NO));
-       printf ("Waiting %s before starting to search.\n", 
-               GNUNET_STRINGS_relative_time_to_string (search_delay, GNUNET_YES));
-       fflush (stdout);
-       
-       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                   "All regexes announced in %s. Waiting %s before starting to search.\n",
-                   GNUNET_STRINGS_relative_time_to_string (prof_time, GNUNET_NO),
-                   GNUNET_STRINGS_relative_time_to_string (search_delay, GNUNET_NO));
-       
-       search_task = GNUNET_SCHEDULER_add_delayed (search_delay,
-                                                   &do_connect_by_string, NULL);    
-      }
-      break;
-    }
-  case STATE_SEARCH_REGEX:
-    {
-      /* First connect to the stats service, then start to search */
-      peer->stats_op_handle =
-       GNUNET_TESTBED_service_connect (NULL,
-                                       peers->peer_handle,
-                                       "statistics",
-                                       &stats_connect_cb,
-                                       peer,
-                                       &stats_ca,
-                                       &stats_da,
-                                       peer);
-      break;
-    }
-  default:
-    GNUNET_break (0);
-  }
+  /* First connect to the stats service, then start to search */
+  peer->stats_op_handle =
+    GNUNET_TESTBED_service_connect (NULL,
+                                    peers->peer_handle,
+                                    "statistics",
+                                    &stats_connect_cb,
+                                    peer,
+                                    &stats_ca,
+                                    &stats_da,
+                                    peer);
 }
 
 
 /**
- * Mesh connect adapter.
+ * Mesh connect adapter. Opens a connection to the mesh service.
  *
  * @param cls not used.
  * @param cfg configuration handle.
  *
  * @return
  */
-void *
+static void *
 mesh_ca (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg)
 {
   GNUNET_MESH_ApplicationType app;
@@ -1063,7 +958,7 @@ mesh_ca (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg)
   app = (GNUNET_MESH_ApplicationType)0;
 
   peer->mesh_handle =
-    GNUNET_MESH_connect (cfg, cls, NULL, NULL, handlers, &app);
+    GNUNET_MESH_connect (cfg, peer, NULL, NULL, handlers, &app);
 
   return peer->mesh_handle;
 }
@@ -1076,7 +971,7 @@ mesh_ca (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg)
  * @param cls closure
  * @param op_result service handle returned from the connect adapter
  */
-void
+static void
 mesh_da (void *cls, void *op_result)
 {
   struct RegexPeer *peer = (struct RegexPeer *) cls;
@@ -1102,6 +997,41 @@ mesh_da (void *cls, void *op_result)
 /******************************************************************************/
 
 
+/**
+ * Configure the peer overlay topology.
+ *
+ * @param cls NULL
+ * @param tc the task context
+ */
+static void
+do_configure_topology (void *cls,
+                       const struct GNUNET_SCHEDULER_TaskContext * tc)
+{
+  /*
+    if (0 == linking_factor)
+    linking_factor = 1;
+    num_links = linking_factor * num_peers;
+  */
+  /* num_links = num_peers - 1; */
+  num_links = linking_factor;
+
+  /* Do overlay connect */
+  prof_start_time = GNUNET_TIME_absolute_get ();
+  topology_op =
+    GNUNET_TESTBED_overlay_configure_topology (NULL, num_peers, peer_handles,
+                                               GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI,
+                                               num_links,
+                                               GNUNET_TESTBED_TOPOLOGY_DISABLE_AUTO_RETRY,
+                                               GNUNET_TESTBED_TOPOLOGY_OPTION_END);
+  if (NULL == topology_op)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Cannot create topology, op handle was NULL\n");
+    GNUNET_assert (0);
+  }
+}
+
+
 /**
  * Functions of this signature are called when a peer has been successfully
  * started or stopped.
@@ -1143,28 +1073,16 @@ peer_churn_cb (void *cls, const char *emsg)
     for (peer_cnt = 0; peer_cnt < num_peers; peer_cnt++)
       peer_handles[peer_cnt] = peers[peer_cnt].peer_handle;
 
-    /*
-    if (0 == linking_factor)
-      linking_factor = 1;
-    num_links = linking_factor * num_peers;
-    */
-    /* num_links = num_peers - 1; */
-    num_links = linking_factor;
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                "Waiting %s before starting to link peers\n",
+                GNUNET_STRINGS_relative_time_to_string (conf_topo_delay, GNUNET_YES));
+
+    printf ("Waiting %s before starting to link peers\n",
+            GNUNET_STRINGS_relative_time_to_string (conf_topo_delay, GNUNET_YES));
+    fflush (stdout);
+
     state = STATE_PEERS_LINKING;
-    /* Do overlay connect */
-    prof_start_time = GNUNET_TIME_absolute_get ();
-    topology_op =
-        GNUNET_TESTBED_overlay_configure_topology (NULL, num_peers, peer_handles,
-                                                  GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI,
-                                                  num_links,
-                                                  GNUNET_TESTBED_TOPOLOGY_DISABLE_AUTO_RETRY,
-                                                   GNUNET_TESTBED_TOPOLOGY_OPTION_END);
-    if (NULL == topology_op)
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                  "Cannot create topology, op handle was NULL\n");
-      GNUNET_assert (0);
-    }
+    GNUNET_SCHEDULER_add_delayed (conf_topo_delay, &do_configure_topology, NULL);
   }
 }
 
@@ -1201,6 +1119,8 @@ peer_create_cb (void *cls, struct GNUNET_TESTBED_Peer *peer, const char *emsg)
 
   peer_ptr = dll_op->cls;
   GNUNET_assert (NULL == peer_ptr->peer_handle);
+  GNUNET_CONFIGURATION_destroy (peer_ptr->cfg);
+  peer_ptr->cfg = NULL;
   peer_ptr->peer_handle = peer;
   GNUNET_TESTBED_operation_done (dll_op->op);
   GNUNET_CONTAINER_DLL_remove (dll_op_head, dll_op_tail, dll_op);
@@ -1229,15 +1149,21 @@ peer_create_cb (void *cls, struct GNUNET_TESTBED_Peer *peer, const char *emsg)
   }
 }
 
+
 /**
- * Function called with a filename.
+ * Function called with a filename for each file in the policy directory. Create
+ * a peer for each filename and update the peer's configuration to include the
+ * max_path_compression specified as a command line argument as well as the
+ * policy_file for this peer. The gnunet-service-regexprofiler service is
+ * automatically started on this peer. The service reads the configurration and
+ * announces the regexes stored in the policy file 'filename'.
  *
  * @param cls closure
  * @param filename complete filename (absolute path)
  * @return GNUNET_OK to continue to iterate,
  *  GNUNET_SYSERR to abort iteration with error!
  */
-int
+static int
 policy_filename_cb (void *cls, const char *filename)
 {
   static unsigned int peer_cnt;
@@ -1246,28 +1172,31 @@ policy_filename_cb (void *cls, const char *filename)
 
   GNUNET_assert (NULL != peer);
 
-  peer->id = peer_cnt;
   peer->policy_file = GNUNET_strdup (filename);
-  /* Do not start peers on hosts[0] (master controller) */
-  peer->host_handle = hosts[1 + (peer_cnt % (num_hosts -1))];
-  peer->mesh_handle = NULL;
-  peer->mesh_tunnel_handle = NULL;
-  peer->stats_handle = NULL;
-  peer->stats_op_handle = NULL;
 
   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Creating peer %i on host %s for policy file %s\n",
               peer->id,
               GNUNET_TESTBED_host_get_hostname (peer->host_handle),
               filename);
 
+  /* Set configuration options specific for this peer
+     (max_path_compression and policy_file */
+  peer->cfg = GNUNET_CONFIGURATION_dup (cfg);
+  GNUNET_CONFIGURATION_set_value_number (peer->cfg, "REGEXPROFILER",
+                                         "MAX_PATH_COMPRESSION",
+                                         (unsigned long long)max_path_compression);
+  GNUNET_CONFIGURATION_set_value_string (peer->cfg, "REGEXPROFILER",
+                                         "POLICY_FILE", filename);
+
   dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
   dll_op->cls = &peers[peer_cnt];
   dll_op->op = GNUNET_TESTBED_peer_create (mc,
                                            peer->host_handle,
-                                           cfg,
+                                           peer->cfg,
                                            &peer_create_cb,
                                            dll_op);
   GNUNET_CONTAINER_DLL_insert_tail (dll_op_head, dll_op_tail, dll_op);
+
   peer_cnt++;
 
   return GNUNET_OK;
@@ -1286,6 +1215,7 @@ controller_event_cb (void *cls,
 {
   struct DLLOperation *dll_op;
   struct GNUNET_TESTBED_Operation *op;
+  int ret;
 
   switch (state)
   {
@@ -1295,6 +1225,7 @@ controller_event_cb (void *cls,
     case GNUNET_TESTBED_ET_OPERATION_FINISHED:
       {
         static unsigned int slaves_started;
+        unsigned int peer_cnt;
 
         dll_op = event->details.operation_finished.op_cls;
         GNUNET_CONTAINER_DLL_remove (dll_op_head, dll_op_tail, dll_op);
@@ -1320,11 +1251,35 @@ controller_event_cb (void *cls,
           state = STATE_PEERS_CREATING;
           prof_start_time = GNUNET_TIME_absolute_get ();
 
-          num_peers = GNUNET_DISK_directory_scan (policy_dir,
-                                                  NULL,
-                                                  NULL);
+          if (-1 == (ret = GNUNET_DISK_directory_scan (policy_dir,
+                                                       NULL,
+                                                       NULL)))
+          {
+            GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                        _("No files found in `%s'\n"),
+                        policy_dir);
+            GNUNET_SCHEDULER_shutdown ();
+            return;
+          }
+          num_peers = (unsigned int) ret;
           peers = GNUNET_malloc (sizeof (struct RegexPeer) * num_peers);
 
+          /* Initialize peers */
+          for (peer_cnt = 0; peer_cnt < num_peers; peer_cnt++)
+          {
+            struct RegexPeer *peer = &peers[peer_cnt];
+            peer->id = peer_cnt;
+            peer->policy_file = NULL;
+            /* Do not start peers on hosts[0] (master controller) */
+            peer->host_handle = hosts[1 + (peer_cnt % (num_hosts -1))];
+            peer->mesh_handle = NULL;
+            peer->mesh_tunnel_handle = NULL;
+            peer->stats_handle = NULL;
+            peer->stats_op_handle = NULL;
+            peer->search_str = NULL;
+            peer->search_str_matched = GNUNET_NO;
+          }
+
           GNUNET_DISK_directory_scan (policy_dir,
                                       &policy_filename_cb,
                                       NULL);
@@ -1356,18 +1311,10 @@ controller_event_cb (void *cls,
      if (NULL != event->details.operation_finished.emsg)
      {
        GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                  _("An operation has failed while linking\n"));
+                   _("An operation has failed while linking\n"));
        printf ("F");
        fflush (stdout);
        retry_links++;
-       
-       if (++cont_fails > num_cont_fails)
-       {
-        GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                    "We have a very high peer linking failure rate: %u (threshold: %u)\n",
-                    cont_fails,
-                    num_cont_fails);
-       }
      }
      /* We do no retries, consider this link as established */
      /* break; */
@@ -1375,7 +1322,7 @@ controller_event_cb (void *cls,
    {
      char output_buffer[512];
      size_t size;
-     
+
      if (0 == established_links)
        printf ("Establishing links .");
      else
@@ -1388,46 +1335,43 @@ controller_event_cb (void *cls,
        fflush (stdout);
        prof_time = GNUNET_TIME_absolute_get_duration (prof_start_time);
        GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                  "%u links established in %s\n",
-                  num_links,
-                  GNUNET_STRINGS_relative_time_to_string (prof_time, GNUNET_NO));
+                   "%u links established in %s\n",
+                   num_links,
+                   GNUNET_STRINGS_relative_time_to_string (prof_time, GNUNET_NO));
        result = GNUNET_OK;
        GNUNET_free (peer_handles);
-       
+
        if (NULL != data_file)
        {
-        size =
-          GNUNET_snprintf (output_buffer,
-                           sizeof (output_buffer),
-                           "# of peers: %u\n# of links established: %u\n"
-                           "Time to establish links: %s\nLinking failures: %u\n"
-                           "path compression length: %u\n",
-                           num_peers,
-                           (established_links - cont_fails),
-                           GNUNET_STRINGS_relative_time_to_string (prof_time, GNUNET_NO),
-                           cont_fails,
-                           max_path_compression);
-
-        if (size != GNUNET_DISK_file_write (data_file, output_buffer, size))
-          GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Unable to write to file!\n");
+         size =
+           GNUNET_snprintf (output_buffer,
+                            sizeof (output_buffer),
+                            "# of peers: %u\n# of links established: %u\n"
+                            "Time to establish links: %s\nLinking failures: %u\n"
+                            "path compression length: %u\n# of search strings: %u\n",
+                            num_peers,
+                            (established_links - cont_fails),
+                            GNUNET_STRINGS_relative_time_to_string (prof_time, GNUNET_NO),
+                            cont_fails,
+                            max_path_compression,
+                            num_search_strings);
+
+         if (size != GNUNET_DISK_file_write (data_file, output_buffer, size))
+           GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Unable to write to file!\n");
        }
-       
-       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                  "Connecting to mesh service and start announcing regex...\n");
-       printf ("\nStarting to connect to mesh services and announce regex\n");
+
+       printf ("\nWaiting %s before starting to search.\n",
+               GNUNET_STRINGS_relative_time_to_string (search_delay, GNUNET_YES));
        fflush (stdout);
-       
-       prof_start_time = GNUNET_TIME_absolute_get ();
-       peers[0].mesh_op_handle =
-        GNUNET_TESTBED_service_connect (NULL,
-                                        peers[0].peer_handle,
-                                        "mesh",
-                                        &mesh_connect_cb,
-                                        &peers[0],
-                                        &mesh_ca,
-                                        &mesh_da,
-                                        &peers[0]);
-       state = STATE_ANNOUNCE_REGEX;
+
+       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                   "Waiting %s before starting to search.\n",
+                   GNUNET_STRINGS_relative_time_to_string (search_delay, GNUNET_NO));
+
+       state = STATE_SEARCH_REGEX;
+
+       search_task = GNUNET_SCHEDULER_add_delayed (search_delay,
+                                                   &do_connect_by_string, NULL);
      }
    }
    break;
@@ -1435,11 +1379,6 @@ controller_event_cb (void *cls,
      GNUNET_assert (0);
    }
    break;
-  case STATE_ANNOUNCE_REGEX:
-  {
-    /* Handled in service connect callback */
-    break;
-  }
   case STATE_SEARCH_REGEX:
   {
     /* Handled in service connect callback */
@@ -1453,7 +1392,7 @@ controller_event_cb (void *cls,
       break;
     default:
       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                 "Unexpected controller_cb with state %i!\n", state);
+                  "Unexpected controller_cb with state %i!\n", state);
     }
     GNUNET_assert (0);
   }
@@ -1461,7 +1400,7 @@ controller_event_cb (void *cls,
 
 
 /**
- * Task to register all hosts available in the global host list
+ * Task to register all hosts available in the global host list.
  *
  * @param cls NULL
  * @param tc the scheduler task context
@@ -1494,7 +1433,7 @@ host_registration_completion (void *cls, const char *emsg)
 
 
 /**
- * Task to register all hosts available in the global host list
+ * Task to register all hosts available in the global host list.
  *
  * @param cls NULL
  * @param tc the scheduler task context
@@ -1533,7 +1472,7 @@ register_hosts (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
 
 
 /**
- * Callback to signal successfull startup of the controller process
+ * Callback to signal successfull startup of the controller process.
  *
  * @param cls the closure from GNUNET_TESTBED_controller_start()
  * @param config the configuration with which the controller has been started;
@@ -1579,6 +1518,7 @@ status_cb (void *cls, const struct GNUNET_CONFIGURATION_Handle *config, int stat
  * @param filename filename of the file containing the search strings.
  * @param strings set of strings loaded from file. Caller needs to free this
  *                if number returned is greater than zero.
+ * @param limit upper limit on the number of strings read from the file
  * @return number of strings found in the file. GNUNET_SYSERR on error.
  */
 static int
@@ -1657,6 +1597,7 @@ run (void *cls, char *const *args, const char *cfgfile,
      const struct GNUNET_CONFIGURATION_Handle *config)
 {
   unsigned int nhost;
+  unsigned int nsearchstrs;
 
   if (NULL == args[0])
   {
@@ -1676,7 +1617,7 @@ run (void *cls, char *const *args, const char *cfgfile,
   }
   for (nhost = 0; nhost < num_hosts; nhost++)
   {
-    if (GNUNET_YES != GNUNET_TESTBED_is_host_habitable (hosts[nhost]))
+    if (GNUNET_YES != GNUNET_TESTBED_is_host_habitable (hosts[nhost], config))
     {
       fprintf (stderr, _("Host %s cannot start testbed\n"),
                          GNUNET_TESTBED_host_get_hostname (hosts[nhost]));
@@ -1719,8 +1660,10 @@ run (void *cls, char *const *args, const char *cfgfile,
     GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
     return;
   }
-  if (num_search_strings != load_search_strings (args[2], &search_strings, num_search_strings))
+  nsearchstrs = load_search_strings (args[2], &search_strings, num_search_strings);
+  if (num_search_strings != nsearchstrs)
   {
+    num_search_strings = nsearchstrs;
     fprintf (stderr, _("Error loading search strings. Given file does not contain enough strings. Exiting.\n"));
     GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
     return;
@@ -1763,12 +1706,9 @@ main (int argc, char *const *argv)
     {'d', "details", "FILENAME",
      gettext_noop ("name of the file for writing statistics"),
      1, &GNUNET_GETOPT_set_string, &data_filename},
-    {'n', "linking-factor", "FACTOR",
-      gettext_noop ("create FACTOR times number of peers random links"),
+    {'n', "num-links", "COUNT",
+      gettext_noop ("create COUNT number of random links between peers"),
       GNUNET_YES, &GNUNET_GETOPT_set_uint, &linking_factor },
-    {'e', "num-errors", "COUNT",
-      gettext_noop ("tolerate COUNT number of continious timeout failures"),
-      GNUNET_YES, &GNUNET_GETOPT_set_uint, &num_cont_fails },
     {'t', "matching-timeout", "TIMEOUT",
       gettext_noop ("wait TIMEOUT before considering a string match as failed"),
       GNUNET_YES, &GNUNET_GETOPT_set_relative_time, &search_timeout },
@@ -1793,6 +1733,7 @@ main (int argc, char *const *argv)
       GNUNET_PROGRAM_run (argc, argv, "gnunet-regex-profiler [OPTIONS] hosts-file policy-dir search-strings-file",
                           _("Profiler for regex/mesh"),
                           options, &run, NULL);
+  GNUNET_free ((void*) argv);
   if (GNUNET_OK != ret)
     return ret;
   if (GNUNET_OK != result)