added libgnunetstatistics to regex profiler dependencies
[oweals/gnunet.git] / src / mesh / gnunet-regex-profiler.c
1 /*
2      This file is part of GNUnet.
3      (C) 2011, 2012 Christian Grothoff (and other contributing authors)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20
21 /**
22  * @file mesh/gnunet-regex-profiler.c
23  * @brief Regex profiler for testing distributed regex use.
24  * @author Bart Polot
25  * @author Max Szengel
26  *
27  * TODO:
28  * - Connect to statistics service
29  */
30
31 #include <string.h>
32
33 #include "platform.h"
34 #include "gnunet_applications.h"
35 #include "gnunet_util_lib.h"
36 #include "gnunet_mesh_service.h"
37 #include "gnunet_stream_lib.h"
38 #include "gnunet_testbed_service.h"
39
40 /**
41  * DLL of operations
42  */
43 struct DLLOperation
44 {
45   /**
46    * The testbed operation handle
47    */
48   struct GNUNET_TESTBED_Operation *op;
49
50   /**
51    * Closure
52    */
53   void *cls;
54
55   /**
56    * The next pointer for DLL
57    */
58   struct DLLOperation *next;
59
60   /**
61    * The prev pointer for DLL
62    */
63   struct DLLOperation *prev;
64 };
65
66
67 /**
68  * Available states during profiling
69  */
70 enum State
71 {
72   /**
73    * Initial state
74    */
75   STATE_INIT = 0,
76
77   /**
78    * Starting slaves
79    */
80   STATE_SLAVES_STARTING,
81
82   /**
83    * Creating peers
84    */
85   STATE_PEERS_CREATING,
86
87   /**
88    * Starting peers
89    */
90   STATE_PEERS_STARTING,
91
92   /**
93    * Linking peers
94    */
95   STATE_PEERS_LINKING,
96
97   /**
98    * Destroying peers; we can do this as the controller takes care of stopping a
99    * peer if it is running
100    */
101   STATE_PEERS_DESTROYING
102 };
103
104
105 /**
106  * An array of hosts loaded from the hostkeys file
107  */
108 static struct GNUNET_TESTBED_Host **hosts;
109
110 /**
111  * Peer handles.
112  */
113 struct RegexPeer
114 {
115   /**
116    * Peer id.
117    */
118   unsigned int id;
119
120   /**
121    * The actual testbed peer handle.
122    */
123   struct GNUNET_TESTBED_Peer *peer_handle;
124
125   /**
126    * Host on which the peer is running.
127    */
128   struct GNUNET_TESTBED_Host *host_handle;
129
130   /**
131    * Filename of the peer's policy file.
132    */
133   char *policy_file;
134
135   /**
136    * Peers search string.
137    */
138   const char *search_str;
139
140   /**
141    * Peer's mesh handle.
142    */
143   struct GNUNET_MESH_Handle *mesh_handle;
144
145   /**
146    * Peer's mesh tunnel handle.
147    */
148   struct GNUNET_MESH_Tunnel *mesh_tunnel_handle;
149
150   /**
151    * Testbed operation handle for the mesh service.
152    */
153   struct GNUNET_TESTBED_Operation *mesh_op_handle;
154
155   /**
156    * Peers's statistics handle.
157    */
158   struct GNUNET_STATISTICS_Handle *stats_handle;
159
160   /**
161    * Testbed operation handle for the statistics service.
162    */
163   struct GNUNET_TESTBED_Operation *stats_op_handle;
164 };
165
166 /**
167  * Array of peer handles used to pass to
168  * GNUNET_TESTBED_overlay_configure_topology
169  */
170 struct GNUNET_TESTBED_Peer **peer_handles;
171
172 /**
173  * The array of peers; we fill this as the peers are given to us by the testbed
174  */
175 static struct RegexPeer *peers;
176
177 /**
178  * Host registration handle
179  */
180 static struct GNUNET_TESTBED_HostRegistrationHandle *reg_handle;
181
182 /**
183  * Handle to the master controller process
184  */
185 struct GNUNET_TESTBED_ControllerProc *mc_proc;
186
187 /**
188  * Handle to the master controller
189  */
190 struct GNUNET_TESTBED_Controller *mc;
191
192 /**
193  * Handle to global configuration
194  */
195 struct GNUNET_CONFIGURATION_Handle *cfg;
196
197 /**
198  * Head of the operations list
199  */
200 struct DLLOperation *dll_op_head;
201
202 /**
203  * Tail of the operations list
204  */
205 struct DLLOperation *dll_op_tail;
206
207 /**
208  * Peer linking - topology operation
209  */
210 struct GNUNET_TESTBED_Operation *topology_op;
211
212 /**
213  * Abort task identifier
214  */
215 static GNUNET_SCHEDULER_TaskIdentifier abort_task;
216
217 /**
218  * Host registration task identifier
219  */
220 static GNUNET_SCHEDULER_TaskIdentifier register_hosts_task;
221
222 /**
223  * Global event mask for all testbed events
224  */
225 uint64_t event_mask;
226
227 /**
228  * The starting time of a profiling step
229  */
230 struct GNUNET_TIME_Absolute prof_start_time;
231
232 /**
233  * Duration profiling step has taken
234  */
235 struct GNUNET_TIME_Relative prof_time;
236
237 /**
238  * Current peer id
239  */
240 unsigned int peer_id;
241
242 /**
243  * Number of peers to be started by the profiler
244  */
245 static unsigned int num_peers;
246
247 /**
248  * Number of hosts in the hosts array
249  */
250 static unsigned int num_hosts;
251
252 /**
253  * Number of random links to be established between peers
254  */
255 static unsigned int num_links;
256
257 /**
258  * Number of timeout failures to tolerate
259  */
260 static unsigned int num_cont_fails;
261
262 /**
263  * Number of times we try overlay connect operations
264  */
265 static unsigned int retry_links;
266
267 /**
268  * Continuous failures during overlay connect operations
269  */
270 static unsigned int cont_fails;
271
272 /**
273  * Global testing status
274  */
275 static int result;
276
277 /**
278  * current state of profiling
279  */
280 enum State state;
281
282 /**
283  * Folder where policy files are stored.
284  */
285 static char * policy_dir;
286
287 /**
288  * Search strings.
289  */
290 static char **search_strings;
291
292 /**
293  * Number of search strings.
294  */
295 static int num_search_strings;
296
297 /**
298  * Number of peers found with search strings.
299  */
300 static unsigned int peers_found;
301
302 /**
303  * Search task identifier
304  */
305 static GNUNET_SCHEDULER_TaskIdentifier search_task;
306
307 /**
308  * Search timeout task identifier.
309  */
310 static GNUNET_SCHEDULER_TaskIdentifier search_timeout_task;
311
312 /**
313  * Search timeout in seconds.
314  */
315 static struct GNUNET_TIME_Relative search_timeout = { 60000 };
316
317 /**
318  * How long do we wait before starting the search?
319  * Default: 1 m.
320  */
321 static struct GNUNET_TIME_Relative search_delay = { 60000 };
322
323 /**
324  * File to log statistics to.
325  */
326 static struct GNUNET_DISK_FileHandle *data_file;
327
328 /**
329  * Filename to log statistics to.
330  */
331 static char *data_filename;
332
333
334 /**
335  * Shutdown nicely
336  *
337  * @param cls NULL
338  * @param tc the task context
339  */
340 static void
341 do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
342 {
343   struct DLLOperation *dll_op;
344   unsigned int nhost;
345   unsigned int peer_cnt;
346   unsigned int search_str_cnt;
347
348   for (peer_cnt = 0; peer_cnt < num_peers; peer_cnt++)
349   {
350     if (NULL != peers[peer_cnt].mesh_op_handle)
351       GNUNET_TESTBED_operation_cancel (peers[peer_cnt].mesh_op_handle);
352     if (NULL != peers[peer_cnt].stats_op_handle)
353       GNUNET_TESTBED_operation_cancel (peers[peer_cnt].stats_op_handle);
354   }
355   for (search_str_cnt = 0; search_str_cnt < num_search_strings; search_str_cnt++)
356   {
357     GNUNET_free (search_strings[search_str_cnt]);
358   }
359   GNUNET_free (search_strings);
360   if (GNUNET_SCHEDULER_NO_TASK != abort_task)
361     GNUNET_SCHEDULER_cancel (abort_task);
362   if (GNUNET_SCHEDULER_NO_TASK != register_hosts_task)
363     GNUNET_SCHEDULER_cancel (register_hosts_task);
364   if (NULL != reg_handle)
365     GNUNET_TESTBED_cancel_registration (reg_handle);
366   if (NULL != topology_op)
367     GNUNET_TESTBED_operation_cancel (topology_op);
368   for (nhost = 0; nhost < num_hosts; nhost++)
369     if (NULL != hosts[nhost])
370       GNUNET_TESTBED_host_destroy (hosts[nhost]);
371   GNUNET_free_non_null (hosts);
372   while (NULL != (dll_op = dll_op_head))
373   {
374     GNUNET_TESTBED_operation_cancel (dll_op->op);
375     GNUNET_CONTAINER_DLL_remove (dll_op_head, dll_op_tail, dll_op);
376     GNUNET_free (dll_op);
377   }
378   if (NULL != mc)
379     GNUNET_TESTBED_controller_disconnect (mc);
380   if (NULL != mc_proc)
381     GNUNET_TESTBED_controller_stop (mc_proc);
382   if (NULL != cfg)
383     GNUNET_CONFIGURATION_destroy (cfg);
384   if (NULL != data_file)
385     GNUNET_DISK_file_close (data_file);
386
387   GNUNET_SCHEDULER_shutdown (); /* Stop scheduler to shutdown testbed run */
388 }
389
390
391 /**
392  * abort task to run on test timed out
393  *
394  * @param cls NULL
395  * @param tc the task context
396  */
397 static void
398 do_abort (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
399 {
400   GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Aborting\n");
401   abort_task = GNUNET_SCHEDULER_NO_TASK;
402   result = GNUNET_SYSERR;
403   GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
404 }
405
406
407 /******************************************************************************/
408 /*********************  STATISTICS SERVICE CONNECTIONS  ***********************/
409 /******************************************************************************/
410
411 /**
412  * Adapter function called to establish a connection to
413  * statistics service.
414  *
415  * @param cls closure
416  * @param cfg configuration of the peer to connect to; will be available until
417  *          GNUNET_TESTBED_operation_done() is called on the operation returned
418  *          from GNUNET_TESTBED_service_connect()
419  * @return service handle to return in 'op_result', NULL on error
420  */
421 static void *
422 stats_ca (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg)
423 {
424   return GNUNET_STATISTICS_create ("<driver>", cfg);
425 }
426
427
428 /**
429  * Adapter function called to destroy a connection to
430  * statistics service.
431  *
432  * @param cls closure
433  * @param op_result service handle returned from the connect adapter
434  */
435 static void
436 stats_da (void *cls, void *op_result)
437 {
438   GNUNET_STATISTICS_destroy (op_result, GNUNET_NO);
439 }
440
441
442 /**
443  * Process statistic values.
444  *
445  * @param cls closure
446  * @param subsystem name of subsystem that created the statistic
447  * @param name the name of the datum
448  * @param value the current value
449  * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not
450  * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration
451  */
452 static int
453 stats_iterator (void *cls, const char *subsystem, const char *name,
454                 uint64_t value, int is_persistent)
455 {
456   struct RegexPeer *peer = cls;
457   char output_buffer[512];
458   size_t size;
459
460   if (NULL == data_file)
461   {
462     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
463                 "%p -> %s [%s]: %llu\n",
464                 peer, subsystem, name, value);
465     return GNUNET_OK;
466   }
467   size =
468     GNUNET_snprintf (output_buffer,
469                      sizeof (output_buffer),
470                      "%p [%s] %s %llu\n",
471                      peer,
472                      subsystem, name, value);
473   if (size != GNUNET_DISK_file_write (data_file, output_buffer, size))
474     GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Unable to write to file!\n");
475
476   return GNUNET_OK;
477 }
478
479
480 /**
481  * Stats callback.
482  *
483  * @param cls closure
484  * @param success GNUNET_OK if statistics were
485  *        successfully obtained, GNUNET_SYSERR if not.
486  */
487 static void
488 stats_cb (void *cls,
489           int success)
490 {
491   static unsigned int peer_cnt;
492   struct RegexPeer *peer = cls;
493
494   if (GNUNET_OK != success)
495   {
496     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
497                 "Getting statistics for peer %u failed!\n",
498                 peer->id);
499     return;
500   }
501
502   if (++peer_cnt == num_peers)
503   {
504     GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
505   }
506 }
507
508
509 /**
510  * Function called by testbed once we are connected to stats service.
511  *
512  * @param cls the 'struct RegexPeer' for which we connected to stats
513  * @param op connect operation handle
514  * @param ca_result handle to stats service
515  * @param emsg error message on failure
516  */
517 static void
518 stats_connect_cb (void *cls,
519                   struct GNUNET_TESTBED_Operation *op,
520                   void *ca_result,
521                   const char *emsg)
522 {
523   struct RegexPeer *peer = cls;
524
525   if (NULL == ca_result)
526   {
527     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
528                 "Failed to connect to statistics service on peer %u: %s\n",
529                 peer->id, emsg);
530     GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
531     return;
532   }
533
534   peer->stats_handle = ca_result;
535 }
536
537
538 /******************************************************************************/
539 /************************  MESH SERVICE CONNECTIONS  **************************/
540 /******************************************************************************/
541
542 /**
543  * Method called whenever another peer has added us to a tunnel
544  * the other peer initiated.
545  * Only called (once) upon reception of data with a message type which was
546  * subscribed to in GNUNET_MESH_connect. A call to GNUNET_MESH_tunnel_destroy
547  * causes te tunnel to be ignored and no further notifications are sent about
548  * the same tunnel.
549  *
550  * @param cls closure
551  * @param tunnel new handle to the tunnel
552  * @param initiator peer that started the tunnel
553  * @param atsi performance information for the tunnel
554  * @return initial tunnel context for the tunnel
555  *         (can be NULL -- that's not an error)
556  */
557 void *
558 mesh_inbound_tunnel_handler (void *cls, struct GNUNET_MESH_Tunnel *tunnel,
559                              const struct GNUNET_PeerIdentity *initiator,
560                              const struct GNUNET_ATS_Information *atsi)
561 {
562   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Mesh inbound tunnel handler.\n");
563
564   return NULL;
565 }
566
567
568 /**
569  * Function called whenever an inbound tunnel is destroyed.  Should clean up
570  * any associated state.  This function is NOT called if the client has
571  * explicitly asked for the tunnel to be destroyed using
572  * GNUNET_MESH_tunnel_destroy. It must NOT call GNUNET_MESH_tunnel_destroy on
573  * the tunnel.
574  *
575  * @param cls closure (set from GNUNET_MESH_connect)
576  * @param tunnel connection to the other end (henceforth invalid)
577  * @param tunnel_ctx place where local state associated
578  *                   with the tunnel is stored
579  */
580 void
581 mesh_tunnel_end_handler (void *cls, const struct GNUNET_MESH_Tunnel *tunnel,
582                          void *tunnel_ctx)
583 {
584   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Mesh tunnel end handler.\n");
585 }
586
587
588 /**
589  * Method called whenever a peer has disconnected from the tunnel.
590  * Implementations of this callback must NOT call
591  * GNUNET_MESH_tunnel_destroy immediately, but instead schedule those
592  * to run in some other task later.  However, calling
593  * "GNUNET_MESH_notify_transmit_ready_cancel" is allowed.
594  *
595  * @param cls closure
596  * @param peer_id peer identity the tunnel stopped working with
597  */
598 void
599 mesh_peer_disconnect_handler (void *cls,
600                               const struct GNUNET_PeerIdentity * peer_id)
601 {
602   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Mesh peer disconnect handler.\n");
603 }
604
605
606 /**
607  * Method called whenever a peer has connected to the tunnel.
608  *
609  * @param cls closure
610  * @param peer_id peer identity the tunnel was created to, NULL on timeout
611  * @param atsi performance data for the connection
612  *
613  */
614 void
615 mesh_peer_connect_handler (void *cls,
616                            const struct GNUNET_PeerIdentity* peer_id,
617                            const struct GNUNET_ATS_Information * atsi)
618 {
619   struct RegexPeer *peer = cls;
620
621   peers_found++;
622
623   if (NULL == peer_id)
624   {
625     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
626                 "String matching timed out for string %s on peer %u (%i/%i)\n",
627                 peer->search_str, peer->id, peers_found, num_search_strings);
628   }
629   else
630   {
631     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
632                 "String %s successfully matched on peer %u (%i/%i)\n",
633                 peer->search_str, peer->id, peers_found, num_search_strings);
634
635     if (NULL == GNUNET_STATISTICS_get (peer->stats_handle, "mesh", NULL,
636                                        GNUNET_TIME_UNIT_FOREVER_REL,
637                                        &stats_cb,
638                                        &stats_iterator, peer))
639     {
640       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
641                   "Could not get statistics of peer %u!\n", peer->id);
642     }
643   }
644
645   if (peers_found == num_search_strings)
646   {
647
648     prof_time = GNUNET_TIME_absolute_get_duration (prof_start_time);
649     printf ("\nAll strings successfully matched in %.2f minutes\n", ((double)prof_time.rel_value / 1000.0 / 60.0));
650
651     if (GNUNET_SCHEDULER_NO_TASK != search_timeout_task)
652       GNUNET_SCHEDULER_cancel (search_timeout_task);
653
654     /*
655     GNUNET_TESTBED_get_statistics (num_peers, 
656                                    peer_handles,                                 
657                                    &statistics_iterator,
658                                    &stats_finished_callback,
659                                    peer);
660     */
661   }
662 }
663
664
665 /**
666  * Connect by string timeout task
667  *
668  * @param cls NULL
669  * @param tc the task context
670  */
671 static void
672 do_connect_by_string_timeout (void *cls,
673                               const struct GNUNET_SCHEDULER_TaskContext * tc)
674 {
675   printf ("Searching for all strings did not succeed after %s.\n",
676           GNUNET_STRINGS_relative_time_to_string (search_timeout, GNUNET_NO));
677   printf ("Found %i of %i strings\n", peers_found, num_search_strings);
678
679   GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
680 }
681
682
683 /**
684  * Connect by string task that is run to search for a string in the NFA
685  *
686  * @param cls NULL
687  * @param tc the task context
688  */
689 static void
690 do_connect_by_string (void *cls,
691                       const struct GNUNET_SCHEDULER_TaskContext * tc)
692 {
693   unsigned int search_cnt;
694   struct RegexPeer *peer;
695
696   for (search_cnt = 0; search_cnt < num_search_strings; search_cnt++)
697   {
698     peer = &peers[search_cnt % num_peers];
699     peer->search_str = search_strings[search_cnt];
700
701     printf ("Searching for string \"%s\" on peer %d with file %s\n",
702             peer->search_str, (search_cnt % num_peers), peer->policy_file);
703
704     peer->mesh_tunnel_handle = GNUNET_MESH_tunnel_create (peer->mesh_handle,
705                                                           NULL,
706                                                           &mesh_peer_connect_handler,
707                                                           &mesh_peer_disconnect_handler,
708                                                           peer);
709
710     GNUNET_MESH_peer_request_connect_by_string (peer->mesh_tunnel_handle,
711                                                 peer->search_str);
712   }
713
714   prof_start_time = GNUNET_TIME_absolute_get ();
715
716   search_timeout_task = GNUNET_SCHEDULER_add_delayed (search_timeout,
717                                                       &do_connect_by_string_timeout, NULL);
718 }
719
720
721 /**
722  * Mesh connect callback.
723  *
724  * @param cls internal peer id.
725  * @param op operation handle.
726  * @param ca_result connect adapter result.
727  * @param emsg error message.
728  */
729 void
730 mesh_connect_cb (void *cls, struct GNUNET_TESTBED_Operation *op,
731                  void *ca_result, const char *emsg)
732 {
733   static unsigned int connected_mesh_handles;
734   struct RegexPeer *peer = (struct RegexPeer *) cls;
735   char *regex;
736   char *data;
737   char *buf;
738   uint64_t filesize;
739   unsigned int offset;
740
741   if (NULL != emsg)
742   {
743     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Mesh connect failed: %s\n", emsg);
744     GNUNET_assert (0);
745   }
746
747   GNUNET_assert (peer->mesh_op_handle == op);
748   GNUNET_assert (peer->mesh_handle == ca_result);
749   GNUNET_assert (NULL != peer->policy_file);
750
751   printf ("Announcing regexes for peer with file %s\n", peer->policy_file);
752   fflush (stdout);
753
754   if (GNUNET_YES != GNUNET_DISK_file_test (peer->policy_file))
755   {
756     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
757                 "Could not find policy file %s\n", peer->policy_file);
758     return;
759   }
760   if (GNUNET_OK != GNUNET_DISK_file_size (peer->policy_file, &filesize, GNUNET_YES, GNUNET_YES))
761     filesize = 0;
762   if (0 == filesize)
763   {
764     GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Policy file %s is empty.\n", peer->policy_file);
765     return;
766   }
767   data = GNUNET_malloc (filesize);
768   if (filesize != GNUNET_DISK_fn_read (peer->policy_file, data, filesize))
769   {
770     GNUNET_free (data);
771     GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Could not read policy file %s.\n",
772          peer->policy_file);
773     return;
774   }
775   buf = data;
776   offset = 0;
777   regex = NULL;
778   while (offset < (filesize - 1))
779   {
780     offset++;
781     if (((data[offset] == '\n')) && (buf != &data[offset]))
782     {
783       data[offset] = '\0';
784       regex = buf;
785       GNUNET_assert (NULL != regex);
786       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Announcing regex: %s on peer\n", regex);
787       GNUNET_MESH_announce_regex (peer->mesh_handle, regex);
788       buf = &data[offset + 1];
789     }
790     else if ((data[offset] == '\n') || (data[offset] == '\0'))
791       buf = &data[offset + 1];
792   }
793   GNUNET_free (data);
794
795   if (++connected_mesh_handles == num_peers)
796   {
797     printf ("\nAll mesh handles connected.\nWaiting %s before starting to search.\n",
798             GNUNET_STRINGS_relative_time_to_string (search_delay, GNUNET_YES));
799
800     search_task = GNUNET_SCHEDULER_add_delayed (search_delay,
801                                                 &do_connect_by_string, NULL);
802   }
803 }
804
805
806 /**
807  * Mesh connect adapter.
808  *
809  * @param cls not used.
810  * @param cfg configuration handle.
811  *
812  * @return
813  */
814 void *
815 mesh_ca (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg)
816 {
817   GNUNET_MESH_ApplicationType app;
818   struct RegexPeer *peer = cls;
819
820   static struct GNUNET_MESH_MessageHandler handlers[] = {
821     {NULL, 0, 0}
822   };
823
824   app = (GNUNET_MESH_ApplicationType)0;
825
826   peer->mesh_handle =
827     GNUNET_MESH_connect (cfg, cls, NULL, NULL, handlers, &app);
828
829   return peer->mesh_handle;
830 }
831
832
833 /**
834  * Adapter function called to destroy a connection to
835  * the mesh service
836  *
837  * @param cls closure
838  * @param op_result service handle returned from the connect adapter
839  */
840 void
841 mesh_da (void *cls, void *op_result)
842 {
843   struct RegexPeer *peer = (struct RegexPeer *) cls;
844
845   GNUNET_assert (peer->mesh_handle == op_result);
846
847   if (NULL != peer->mesh_tunnel_handle)
848   {
849     GNUNET_MESH_tunnel_destroy (peer->mesh_tunnel_handle);
850     peer->mesh_tunnel_handle = NULL;
851   }
852
853   if (NULL != peer->mesh_handle)
854   {
855     GNUNET_MESH_disconnect (peer->mesh_handle);
856     peer->mesh_handle = NULL;
857   }
858 }
859
860
861 /******************************************************************************/
862 /***************************  TESTBED PEER SETUP  *****************************/
863 /******************************************************************************/
864
865
866 /**
867  * Functions of this signature are called when a peer has been successfully
868  * started or stopped.
869  *
870  * @param cls the closure from GNUNET_TESTBED_peer_start/stop()
871  * @param emsg NULL on success; otherwise an error description
872  */
873 static void
874 peer_churn_cb (void *cls, const char *emsg)
875 {
876   struct DLLOperation *dll_op = cls;
877   struct GNUNET_TESTBED_Operation *op;
878   static unsigned int started_peers;
879   unsigned int peer_cnt;
880
881   op = dll_op->op;
882   GNUNET_CONTAINER_DLL_remove (dll_op_head, dll_op_tail, dll_op);
883   GNUNET_free (dll_op);
884   if (NULL != emsg)
885   {
886     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
887          _("An operation has failed while starting peers\n"));
888     GNUNET_TESTBED_operation_done (op);
889     if (GNUNET_SCHEDULER_NO_TASK != abort_task)
890       GNUNET_SCHEDULER_cancel (abort_task);
891     abort_task = GNUNET_SCHEDULER_add_now (&do_abort, NULL);
892     return;
893   }
894   GNUNET_TESTBED_operation_done (op);
895   if (++started_peers == num_peers)
896   {
897     prof_time = GNUNET_TIME_absolute_get_duration (prof_start_time);
898     printf ("All peers started successfully in %.2f seconds\n",
899             ((double) prof_time.rel_value) / 1000.00);
900     result = GNUNET_OK;
901
902     if (0 == num_links)
903       num_links = num_peers * 5;
904
905     peer_handles = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_Peer *) * num_peers);
906     for (peer_cnt = 0; peer_cnt < num_peers; peer_cnt++)
907       peer_handles[peer_cnt] = peers[peer_cnt].peer_handle;
908
909     state = STATE_PEERS_LINKING;
910     /* Do overlay connect */
911     prof_start_time = GNUNET_TIME_absolute_get ();
912     topology_op =
913         GNUNET_TESTBED_overlay_configure_topology (NULL, num_peers, peer_handles,
914                                                    GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI,
915                                                    num_links,
916                                                    GNUNET_TESTBED_TOPOLOGY_OPTION_END);
917     if (NULL == topology_op)
918     {
919       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
920                   "Cannot create topology, op handle was NULL\n");
921       GNUNET_assert (0);
922     }
923   }
924 }
925
926
927 /**
928  * Functions of this signature are called when a peer has been successfully
929  * created
930  *
931  * @param cls the closure from GNUNET_TESTBED_peer_create()
932  * @param peer the handle for the created peer; NULL on any error during
933  *          creation
934  * @param emsg NULL if peer is not NULL; else MAY contain the error description
935  */
936 static void
937 peer_create_cb (void *cls, struct GNUNET_TESTBED_Peer *peer, const char *emsg)
938 {
939   struct DLLOperation *dll_op = cls;
940   struct RegexPeer *peer_ptr;
941   static unsigned int created_peers;
942   unsigned int peer_cnt;
943
944   if (NULL != emsg)
945   {
946     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
947          _("Creating a peer failed. Error: %s\n"), emsg);
948     GNUNET_TESTBED_operation_done (dll_op->op);
949     GNUNET_CONTAINER_DLL_remove (dll_op_head, dll_op_tail, dll_op);
950     GNUNET_free (dll_op);
951     if (GNUNET_SCHEDULER_NO_TASK != abort_task)
952       GNUNET_SCHEDULER_cancel (abort_task);
953     abort_task = GNUNET_SCHEDULER_add_now (&do_abort, NULL);
954     return;
955   }
956
957   peer_ptr = dll_op->cls;
958   GNUNET_assert (NULL == peer_ptr->peer_handle);
959   peer_ptr->peer_handle = peer;
960   GNUNET_TESTBED_operation_done (dll_op->op);
961   GNUNET_CONTAINER_DLL_remove (dll_op_head, dll_op_tail, dll_op);
962   GNUNET_free (dll_op);
963
964   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %i created on host %s\n",
965               peer_ptr->id,
966               GNUNET_TESTBED_host_get_hostname (peer_ptr->host_handle));
967
968   if (++created_peers == num_peers)
969   {
970     prof_time = GNUNET_TIME_absolute_get_duration (prof_start_time);
971     printf ("All peers created successfully in %.2f seconds\n",
972             ((double) prof_time.rel_value) / 1000.00);
973     /* Now peers are to be started */
974     state = STATE_PEERS_STARTING;
975     prof_start_time = GNUNET_TIME_absolute_get ();
976     for (peer_cnt = 0; peer_cnt < num_peers; peer_cnt++)
977     {
978       dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
979       dll_op->op = GNUNET_TESTBED_peer_start (dll_op, peers[peer_cnt].peer_handle,
980                                               &peer_churn_cb, dll_op);
981       GNUNET_CONTAINER_DLL_insert_tail (dll_op_head, dll_op_tail, dll_op);
982     }
983   }
984 }
985
986 /**
987  * Function called with a filename.
988  *
989  * @param cls closure
990  * @param filename complete filename (absolute path)
991  * @return GNUNET_OK to continue to iterate,
992  *  GNUNET_SYSERR to abort iteration with error!
993  */
994 int
995 policy_filename_cb (void *cls, const char *filename)
996 {
997   static unsigned int peer_cnt;
998   struct DLLOperation *dll_op;
999
1000   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating peer %i on host %s for policy file %s\n",
1001               peer_cnt,
1002               GNUNET_TESTBED_host_get_hostname (hosts[peer_cnt % num_hosts]),
1003               filename);
1004
1005   peers[peer_cnt].id = peer_cnt;
1006   peers[peer_cnt].policy_file = GNUNET_strdup (filename);
1007   peers[peer_cnt].host_handle = hosts[peer_cnt % num_hosts];
1008   peers[peer_cnt].mesh_handle = NULL;
1009   peers[peer_cnt].mesh_tunnel_handle = NULL;
1010   peers[peer_cnt].stats_handle = NULL;
1011   peers[peer_cnt].stats_op_handle = NULL;
1012
1013   dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
1014   dll_op->cls = &peers[peer_cnt];
1015   dll_op->op = GNUNET_TESTBED_peer_create (mc,
1016                                            hosts[peer_cnt % num_hosts],
1017                                            cfg,
1018                                            &peer_create_cb,
1019                                            dll_op);
1020   GNUNET_CONTAINER_DLL_insert_tail (dll_op_head, dll_op_tail, dll_op);
1021   peer_cnt++;
1022
1023   return GNUNET_OK;
1024 }
1025
1026
1027 /**
1028  * Controller event callback.
1029  *
1030  * @param cls NULL
1031  * @param event the controller event
1032  */
1033 static void
1034 controller_event_cb (void *cls,
1035                      const struct GNUNET_TESTBED_EventInformation *event)
1036 {
1037   struct DLLOperation *dll_op;
1038   struct GNUNET_TESTBED_Operation *op;
1039
1040   switch (state)
1041   {
1042   case STATE_SLAVES_STARTING:
1043     switch (event->type)
1044     {
1045     case GNUNET_TESTBED_ET_OPERATION_FINISHED:
1046       {
1047         static unsigned int slaves_started;
1048
1049         dll_op = event->details.operation_finished.op_cls;
1050         GNUNET_CONTAINER_DLL_remove (dll_op_head, dll_op_tail, dll_op);
1051         GNUNET_free (dll_op);
1052         op = event->details.operation_finished.operation;
1053         if (NULL != event->details.operation_finished.emsg)
1054         {
1055           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1056                _("An operation has failed while starting slaves\n"));
1057           GNUNET_TESTBED_operation_done (op);
1058           if (GNUNET_SCHEDULER_NO_TASK != abort_task)
1059             GNUNET_SCHEDULER_cancel (abort_task);
1060           abort_task = GNUNET_SCHEDULER_add_now (&do_abort, NULL);
1061           return;
1062         }
1063         GNUNET_TESTBED_operation_done (op);
1064         /* Proceed to start peers */
1065         if (++slaves_started == num_hosts - 1)
1066         {
1067           printf ("All slaves started successfully\n");
1068
1069           state = STATE_PEERS_CREATING;
1070           prof_start_time = GNUNET_TIME_absolute_get ();
1071
1072           num_peers = GNUNET_DISK_directory_scan (policy_dir,
1073                                                   NULL,
1074                                                   NULL);
1075           peers = GNUNET_malloc (sizeof (struct RegexPeer) * num_peers);
1076
1077           GNUNET_DISK_directory_scan (policy_dir,
1078                                       &policy_filename_cb,
1079                                       NULL);
1080         }
1081       }
1082       break;
1083     default:
1084       GNUNET_assert (0);
1085     }
1086     break;
1087   case STATE_PEERS_STARTING:
1088     switch (event->type)
1089     {
1090     case GNUNET_TESTBED_ET_OPERATION_FINISHED:
1091       /* Control reaches here when peer start fails */
1092     case GNUNET_TESTBED_ET_PEER_START:
1093       /* we handle peer starts in peer_churn_cb */
1094       break;
1095     default:
1096       GNUNET_assert (0);
1097     }
1098     break;
1099   case STATE_PEERS_LINKING:
1100    switch (event->type)
1101     {
1102     case GNUNET_TESTBED_ET_OPERATION_FINISHED:
1103       /* Control reaches here when a peer linking operation fails */
1104       if (NULL != event->details.operation_finished.emsg)
1105       {
1106         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1107              _("An operation has failed while linking\n"));
1108         retry_links++;
1109         if (++cont_fails > num_cont_fails)
1110         {
1111           printf ("\nAborting due to very high failure rate");
1112           if (GNUNET_SCHEDULER_NO_TASK != abort_task)
1113             GNUNET_SCHEDULER_cancel (abort_task);
1114           abort_task = GNUNET_SCHEDULER_add_now (&do_abort, NULL);
1115         }
1116       }
1117       break;
1118     case GNUNET_TESTBED_ET_CONNECT:
1119       {
1120         static unsigned int established_links;
1121         unsigned int peer_cnt;
1122
1123         if (0 == established_links)
1124           printf ("Establishing links\n .");
1125         else
1126         {
1127           printf (".");
1128           fflush (stdout);
1129         }
1130         if (++established_links == num_links)
1131         {
1132           prof_time = GNUNET_TIME_absolute_get_duration (prof_start_time);
1133           printf ("\n%u links established in %.2f seconds\n",
1134                   num_links, ((double) prof_time.rel_value) / 1000.00);
1135           result = GNUNET_OK;
1136           GNUNET_free (peer_handles);
1137           printf ("\nConnecting to mesh and statistics service...\n");
1138           for (peer_cnt = 0; peer_cnt < num_peers; peer_cnt++)
1139           {
1140             peers[peer_cnt].mesh_op_handle =
1141               GNUNET_TESTBED_service_connect (NULL,
1142                                               peers[peer_cnt].peer_handle,
1143                                               "mesh",
1144                                               &mesh_connect_cb,
1145                                               &peers[peer_cnt],
1146                                               &mesh_ca,
1147                                               &mesh_da,
1148                                               &peers[peer_cnt]);
1149
1150             peers[peer_cnt].stats_op_handle =
1151               GNUNET_TESTBED_service_connect (NULL,
1152                                               peers[peer_cnt].peer_handle,
1153                                               "statistics",
1154                                               &stats_connect_cb,
1155                                               &peers[peer_cnt],
1156                                               &stats_ca,
1157                                               &stats_da,
1158                                               &peers[peer_cnt]);
1159           }
1160         }
1161       }
1162       break;
1163     default:
1164       GNUNET_assert (0);
1165     }
1166     break;
1167   default:
1168     GNUNET_assert (0);
1169   }
1170 }
1171
1172
1173 /**
1174  * Task to register all hosts available in the global host list
1175  *
1176  * @param cls NULL
1177  * @param tc the scheduler task context
1178  */
1179 static void
1180 register_hosts (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
1181
1182
1183 /**
1184  * Callback which will be called to after a host registration succeeded or failed
1185  *
1186  * @param cls the closure
1187  * @param emsg the error message; NULL if host registration is successful
1188  */
1189 static void
1190 host_registration_completion (void *cls, const char *emsg)
1191 {
1192   reg_handle = NULL;
1193   if (NULL != emsg)
1194   {
1195     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1196                 _("Host registration failed for a host. Error: %s\n"), emsg);
1197     if (GNUNET_SCHEDULER_NO_TASK != abort_task)
1198       GNUNET_SCHEDULER_cancel (abort_task);
1199     abort_task = GNUNET_SCHEDULER_add_now (&do_abort, NULL);
1200     return;
1201   }
1202   register_hosts_task = GNUNET_SCHEDULER_add_now (&register_hosts, NULL);
1203 }
1204
1205
1206 /**
1207  * Task to register all hosts available in the global host list
1208  *
1209  * @param cls NULL
1210  * @param tc the scheduler task context
1211  */
1212 static void
1213 register_hosts (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1214 {
1215   struct DLLOperation *dll_op;
1216   static unsigned int reg_host;
1217   unsigned int slave;
1218
1219   register_hosts_task = GNUNET_SCHEDULER_NO_TASK;
1220   if (reg_host == num_hosts - 1)
1221   {
1222     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1223                 "All hosts successfully registered\n");
1224     /* Start slaves */
1225     state = STATE_SLAVES_STARTING;
1226     for (slave = 1; slave < num_hosts; slave++)
1227     {
1228       dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
1229       dll_op->op = GNUNET_TESTBED_controller_link (dll_op,
1230                                                    mc,
1231                                                    hosts[slave],
1232                                                    hosts[0],
1233                                                    cfg,
1234                                                    GNUNET_YES);
1235       GNUNET_CONTAINER_DLL_insert_tail (dll_op_head, dll_op_tail, dll_op);
1236     }
1237     return;
1238   }
1239   reg_handle = GNUNET_TESTBED_register_host (mc, hosts[++reg_host],
1240                                              host_registration_completion,
1241                                              NULL);
1242 }
1243
1244
1245 /**
1246  * Callback to signal successfull startup of the controller process
1247  *
1248  * @param cls the closure from GNUNET_TESTBED_controller_start()
1249  * @param config the configuration with which the controller has been started;
1250  *          NULL if status is not GNUNET_OK
1251  * @param status GNUNET_OK if the startup is successfull; GNUNET_SYSERR if not,
1252  *          GNUNET_TESTBED_controller_stop() shouldn't be called in this case
1253  */
1254 static void
1255 status_cb (void *cls, const struct GNUNET_CONFIGURATION_Handle *config, int status)
1256 {
1257   if (GNUNET_SCHEDULER_NO_TASK != abort_task)
1258     GNUNET_SCHEDULER_cancel (abort_task);
1259   if (GNUNET_OK != status)
1260   {
1261     mc_proc = NULL;
1262     abort_task = GNUNET_SCHEDULER_add_now (&do_abort, NULL);
1263     return;
1264   }
1265   event_mask = 0;
1266   event_mask |= (1LL << GNUNET_TESTBED_ET_PEER_START);
1267   event_mask |= (1LL << GNUNET_TESTBED_ET_PEER_STOP);
1268   event_mask |= (1LL << GNUNET_TESTBED_ET_CONNECT);
1269   event_mask |= (1LL << GNUNET_TESTBED_ET_DISCONNECT);
1270   event_mask |= (1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED);
1271   mc = GNUNET_TESTBED_controller_connect (config, hosts[0], event_mask,
1272                                           &controller_event_cb, NULL);
1273   if (NULL == mc)
1274   {
1275     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1276                 _("Unable to connect to master controller -- Check config\n"));
1277     abort_task = GNUNET_SCHEDULER_add_now (&do_abort, NULL);
1278     return;
1279   }
1280   register_hosts_task = GNUNET_SCHEDULER_add_now (&register_hosts, NULL);
1281   abort_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
1282                                              &do_abort, NULL);
1283 }
1284
1285 /**
1286  * Load search strings from given filename. One search string per line.
1287  *
1288  * @param filename filename of the file containing the search strings.
1289  * @param strings set of strings loaded from file. Caller needs to free this
1290  *                if number returned is greater than zero.
1291  * @return number of strings found in the file. GNUNET_SYSERR on error.
1292  */
1293 static int
1294 load_search_strings (const char *filename, char ***strings)
1295 {
1296   char *data;
1297   char *buf;
1298   uint64_t filesize;
1299   unsigned int offset;
1300   int str_cnt;
1301   unsigned int i;
1302
1303   if (NULL == filename)
1304   {
1305     return GNUNET_SYSERR;
1306   }
1307
1308   if (GNUNET_YES != GNUNET_DISK_file_test (filename))
1309   {
1310     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1311                 "Could not find search strings file %s\n", filename);
1312     return GNUNET_SYSERR;
1313   }
1314   if (GNUNET_OK != GNUNET_DISK_file_size (filename, &filesize, GNUNET_YES, GNUNET_YES))
1315     filesize = 0;
1316   if (0 == filesize)
1317   {
1318     GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Search strings file %s is empty.\n", filename);
1319     return GNUNET_SYSERR;
1320   }
1321   data = GNUNET_malloc (filesize);
1322   if (filesize != GNUNET_DISK_fn_read (filename, data, filesize))
1323   {
1324     GNUNET_free (data);
1325     GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Could not read search strings file %s.\n",
1326          filename);
1327     return GNUNET_SYSERR;
1328   }
1329   buf = data;
1330   offset = 0;
1331   str_cnt = 0;
1332   while (offset < (filesize - 1))
1333   {
1334     offset++;
1335     if (((data[offset] == '\n')) && (buf != &data[offset]))
1336     {
1337       data[offset] = '\0';
1338       str_cnt++;
1339       buf = &data[offset + 1];
1340     }
1341     else if ((data[offset] == '\n') || (data[offset] == '\0'))
1342       buf = &data[offset + 1];
1343   }
1344   *strings = GNUNET_malloc (sizeof (char *) * str_cnt);
1345   offset = 0;
1346   for (i = 0; i < str_cnt; i++)
1347   {
1348     (*strings)[i] = GNUNET_strdup (&data[offset]);
1349     offset += strlen ((*strings)[i]) + 1;
1350   }
1351   free (data);
1352   return str_cnt;
1353 }
1354
1355 /**
1356  * Main function that will be run by the scheduler.
1357  *
1358  * @param cls closure
1359  * @param args remaining command-line arguments
1360  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
1361  * @param config configuration
1362  */
1363 static void
1364 run (void *cls, char *const *args, const char *cfgfile,
1365      const struct GNUNET_CONFIGURATION_Handle *config)
1366 {
1367   unsigned int nhost;
1368
1369   if (NULL == args[0])
1370   {
1371     fprintf (stderr, _("No hosts-file specified on command line. Exiting.\n"));
1372     return;
1373   }
1374   if (NULL == args[1])
1375   {
1376     fprintf (stderr, _("No policy directory specified on command line. Exiting.\n"));
1377     return;
1378   }
1379   num_hosts = GNUNET_TESTBED_hosts_load_from_file (args[0], &hosts);
1380   if (0 == num_hosts)
1381   {
1382     fprintf (stderr, _("No hosts loaded. Need at least one host\n"));
1383     return;
1384   }
1385   for (nhost = 0; nhost < num_hosts; nhost++)
1386   {
1387     if (GNUNET_YES != GNUNET_TESTBED_is_host_habitable (hosts[nhost]))
1388     {
1389       fprintf (stderr, _("Host %s cannot start testbed\n"),
1390                          GNUNET_TESTBED_host_get_hostname (hosts[nhost]));
1391       break;
1392     }
1393   }
1394   if (num_hosts != nhost)
1395   {
1396     fprintf (stderr, _("Exiting\n"));
1397     GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
1398     return;
1399   }
1400   if (NULL == config)
1401   {
1402     fprintf (stderr, _("No configuration file given. Exiting\n"));
1403     GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
1404     return;
1405   }
1406   if ( (NULL != data_filename) &&
1407        (NULL == (data_file = 
1408                  GNUNET_DISK_file_open (data_filename,
1409                                         GNUNET_DISK_OPEN_READWRITE |
1410                                         GNUNET_DISK_OPEN_TRUNCATE |
1411                                         GNUNET_DISK_OPEN_CREATE,
1412                                         GNUNET_DISK_PERM_USER_READ |
1413                                         GNUNET_DISK_PERM_USER_WRITE))) )
1414     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
1415                               "open",
1416                               data_filename);
1417   if (GNUNET_YES != GNUNET_DISK_directory_test (args[1]))
1418   {
1419     fprintf (stderr, _("Specified policies directory does not exist. Exiting.\n"));
1420     GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
1421     return;
1422   }
1423   policy_dir = args[1];
1424   if (GNUNET_YES != GNUNET_DISK_file_test (args[2]))
1425   {
1426     fprintf (stderr, _("No search strings file given. Exiting.\n"));
1427     GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
1428     return;
1429   }
1430   num_search_strings = load_search_strings (args[2], &search_strings);
1431   if (0 >= num_search_strings || NULL == search_strings)
1432   {
1433     fprintf (stderr, _("Error loading search strings. Exiting.\n"));
1434     GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
1435     return;
1436   }
1437   unsigned int i;
1438   for (i = 0; i < num_search_strings; i++)
1439     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "search string: %s\n", search_strings[i]);
1440   cfg = GNUNET_CONFIGURATION_dup (config);
1441   mc_proc =
1442       GNUNET_TESTBED_controller_start (GNUNET_TESTBED_host_get_hostname
1443                                        (hosts[0]),
1444                                        hosts[0],
1445                                        cfg,
1446                                        status_cb,
1447                                        NULL);
1448   abort_task =
1449       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
1450                                     (GNUNET_TIME_UNIT_SECONDS, 5), &do_abort,
1451                                     NULL);
1452 }
1453
1454
1455 /**
1456  * Main function.
1457  *
1458  * @param argc argument count
1459  * @param argv argument values
1460  * @return 0 on success
1461  */
1462 int
1463 main (int argc, char *const *argv)
1464 {
1465   static const struct GNUNET_GETOPT_CommandLineOption options[] = {
1466     {'d', "details", "FILENAME",
1467      gettext_noop ("name of the file for writing statistics"),
1468      1, &GNUNET_GETOPT_set_string, &data_filename},
1469     { 'n', "num-links", "COUNT",
1470       gettext_noop ("create COUNT number of random links"),
1471       GNUNET_YES, &GNUNET_GETOPT_set_uint, &num_links },
1472     { 'e', "num-errors", "COUNT",
1473       gettext_noop ("tolerate COUNT number of continious timeout failures"),
1474       GNUNET_YES, &GNUNET_GETOPT_set_uint, &num_cont_fails },
1475     { 't', "matching-timeout", "TIMEOUT",
1476       gettext_noop ("wait TIMEOUT seconds before considering a string match as failed"),
1477       GNUNET_YES, &GNUNET_GETOPT_set_relative_time, &search_timeout },
1478     { 's', "search-delay", "DELAY",
1479       gettext_noop ("wait DELAY minutes before starting string search"),
1480       GNUNET_YES, &GNUNET_GETOPT_set_relative_time, &search_delay },
1481     GNUNET_GETOPT_OPTION_END
1482   };
1483   int ret;
1484
1485   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
1486     return 2;
1487
1488   result = GNUNET_SYSERR;
1489   ret =
1490       GNUNET_PROGRAM_run (argc, argv, "gnunet-regex-profiler [OPTIONS] hosts-file policy-dir search-strings-file",
1491                           _("Profiler for regex/mesh"),
1492                           options, &run, NULL);
1493   if (GNUNET_OK != ret)
1494     return ret;
1495   if (GNUNET_OK != result)
1496     return 1;
1497   return 0;
1498 }