+ return;
+ }
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Starting daemon %u\n", next_search);
+ peer = &peers[next_search];
+ peer->daemon_op =
+ GNUNET_TESTBED_peer_manage_service (NULL,
+ peer->peer_handle,
+ "regexprofiler",
+ &daemon_started,
+ peer,
+ 1);
+ next_search++;
+ parallel_searches++;
+}
+
+/**
+ * DHT connect callback. Called when we are connected to the dht 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.
+ */
+static void
+dht_connect_cb (void *cls, struct GNUNET_TESTBED_Operation *op,
+ void *ca_result, const char *emsg)
+{
+ struct RegexPeer *peer = (struct RegexPeer *) cls;
+
+ if (NULL != emsg || NULL == op || NULL == ca_result)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "DHT connect failed: %s\n", emsg);
+ GNUNET_abort ();
+ }
+
+ GNUNET_assert (NULL != peer->dht_handle);
+ GNUNET_assert (peer->op_handle == op);
+ GNUNET_assert (peer->dht_handle == ca_result);
+
+ peer->search_str_matched = GNUNET_NO;
+ peer->search_handle = REGEX_INTERNAL_search (peer->dht_handle,
+ peer->search_str,
+ ®ex_found_handler, peer,
+ NULL);
+ peer->prof_start_time = GNUNET_TIME_absolute_get ();
+}
+
+
+/**
+ * DHT connect adapter. Opens a connection to the dht service.
+ *
+ * @param cls Closure (peer).
+ * @param cfg Configuration handle.
+ *
+ * @return
+ */
+static void *
+dht_ca (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ struct RegexPeer *peer = cls;
+
+ peer->dht_handle = GNUNET_DHT_connect (cfg, 32);
+
+ return peer->dht_handle;
+}
+
+
+/**
+ * Adapter function called to destroy a connection to the dht service.
+ *
+ * @param cls Closure (peer).
+ * @param op_result Service handle returned from the connect adapter.
+ */
+static void
+dht_da (void *cls, void *op_result)
+{
+ struct RegexPeer *peer = (struct RegexPeer *) cls;
+
+ GNUNET_assert (peer->dht_handle == op_result);
+
+ if (NULL != peer->search_handle)
+ {
+ REGEX_INTERNAL_search_cancel (peer->search_handle);
+ peer->search_handle = NULL;
+ }
+
+ if (NULL != peer->dht_handle)
+ {
+ GNUNET_DHT_disconnect (peer->dht_handle);
+ peer->dht_handle = NULL;
+ }
+}
+
+
+/**
+ * Signature of a main function for a testcase.
+ *
+ * @param cls NULL
+ * @param num_peers_ number of peers in 'peers'
+ * @param testbed_peers handle to peers run in the testbed. NULL upon timeout (see
+ * GNUNET_TESTBED_test_run()).
+ * @param links_succeeded the number of overlay link connection attempts that
+ * succeeded
+ * @param links_failed the number of overlay link connection attempts that
+ * failed
+ */
+static void
+test_master (void *cls,
+ unsigned int num_peers_,
+ struct GNUNET_TESTBED_Peer **testbed_peers,
+ unsigned int links_succeeded,
+ unsigned int links_failed)
+{
+ unsigned int i;
+
+ GNUNET_assert (num_peers_ == num_peers);
+
+ prof_time = GNUNET_TIME_absolute_get_duration (prof_start_time);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Testbed started in %s\n",
+ GNUNET_STRINGS_relative_time_to_string (prof_time, GNUNET_NO));
+
+ if (GNUNET_SCHEDULER_NO_TASK != abort_task)
+ {
+ GNUNET_SCHEDULER_cancel (abort_task);
+ abort_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+
+ for (i = 0; i < num_peers; i++)
+ {
+ peers[i].peer_handle = testbed_peers[i];
+ }
+ if (GNUNET_NO ==
+ GNUNET_CONFIGURATION_get_value_yesno (cfg, "DHT", "DISABLE_TRY_CONNECT"))
+ {
+ struct GNUNET_TIME_Relative settle_time;
+
+ settle_time =
+ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS,
+ 10 * num_peers);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Waiting for DHT for %s to settle new connections.\n\n",
+ GNUNET_STRINGS_relative_time_to_string(settle_time, GNUNET_NO));
+ GNUNET_SCHEDULER_add_delayed (settle_time, &do_announce, NULL);
+ }
+ else
+ {
+ GNUNET_SCHEDULER_add_now (&do_announce, NULL);
+ }
+ search_timeout_task =
+ GNUNET_SCHEDULER_add_delayed (search_timeout_time, &search_timed_out, NULL);
+}
+
+/**
+ * Function that will be called whenever something in the testbed changes.
+ *
+ * @param cls closure, NULL
+ * @param event information on what is happening
+ */
+static void
+master_controller_cb (void *cls,
+ const struct GNUNET_TESTBED_EventInformation *event)
+{
+ switch (event->type)
+ {
+ case GNUNET_TESTBED_ET_CONNECT:
+ printf(".");
+ break;
+ case GNUNET_TESTBED_ET_PEER_START:
+ printf("#");
+ break;
+ default:
+ break;
+ }
+ fflush(stdout);
+}
+
+
+/******************************************************************************/
+/*************************** TESTBED PEER SETUP *****************************/
+/******************************************************************************/
+
+
+/**
+ * Load search strings from given filename. One search string per line.
+ *
+ * @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
+load_search_strings (const char *filename, char ***strings, unsigned int limit)
+{
+ char *data;
+ char *buf;
+ uint64_t filesize;
+ unsigned int offset;
+ int str_cnt;
+ unsigned int i;
+
+ if (NULL == filename)
+ {
+ return GNUNET_SYSERR;
+ }
+
+ if (GNUNET_YES != GNUNET_DISK_file_test (filename))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Could not find search strings file %s\n", filename);
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK != GNUNET_DISK_file_size (filename, &filesize, GNUNET_YES, GNUNET_YES))
+ filesize = 0;
+ if (0 == filesize)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Search strings file %s is empty.\n", filename);
+ return GNUNET_SYSERR;
+ }
+ data = GNUNET_malloc (filesize);
+ if (filesize != GNUNET_DISK_fn_read (filename, data, filesize))
+ {
+ GNUNET_free (data);
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Could not read search strings file %s.\n",
+ filename);
+ return GNUNET_SYSERR;
+ }
+ buf = data;
+ offset = 0;
+ str_cnt = 0;
+ while (offset < (filesize - 1) && str_cnt < limit)
+ {
+ offset++;
+ if (((data[offset] == '\n')) && (buf != &data[offset]))