- fix crashes in testbed_api_testbed upon interrupts
[oweals/gnunet.git] / src / testbed / testbed_api_testbed.c
1 /*
2   This file is part of GNUnet
3   (C) 2008--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 testbed/testbed_api_testbed.c
23  * @brief high-level testbed management
24  * @author Christian Grothoff
25  * @author Sree Harsha Totakura
26  */
27
28 #include "platform.h"
29 #include "gnunet_util_lib.h"
30 #include "gnunet_testbed_service.h"
31 #include "testbed_api_peers.h"
32 #include "testbed_api_hosts.h"
33 #include "testbed_api_topology.h"
34
35 /**
36  * Generic loggins shorthand
37  */
38 #define LOG(kind,...)                                           \
39   GNUNET_log_from (kind, "testbed-api-testbed", __VA_ARGS__)
40
41 /**
42  * Debug logging shortcut
43  */
44 #define DEBUG(...)                              \
45   LOG (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
46
47 /**
48  * The default setup timeout in seconds
49  */
50 #define DEFAULT_SETUP_TIMEOUT 300
51
52 /**
53  * DLL of operations
54  */
55 struct DLLOperation
56 {
57   /**
58    * The testbed operation handle
59    */
60   struct GNUNET_TESTBED_Operation *op;
61
62   /**
63    * Context information for GNUNET_TESTBED_run()
64    */
65   struct RunContext *rc;
66
67   /**
68    * Closure
69    */
70   void *cls;
71
72   /**
73    * The next pointer for DLL
74    */
75   struct DLLOperation *next;
76
77   /**
78    * The prev pointer for DLL
79    */
80   struct DLLOperation *prev;
81 };
82
83
84 /**
85  * States of RunContext
86  */
87 enum State
88 {
89   /**
90    * Initial state
91    */
92   RC_INIT = 0,
93
94   /**
95    * Controllers on given hosts started and linked
96    */
97   RC_LINKED,
98
99   /**
100    * Peers are created
101    */
102   RC_PEERS_CREATED,
103
104   /**
105    * The testbed run is ready and the master callback can be called now. At this
106    * time the peers are all started and if a topology is provided in the
107    * configuration the topology would have been attempted
108    */
109   RC_READY,
110
111   /* /\** */
112   /*  * Peers are stopped */
113   /*  *\/ */
114   /* RC_PEERS_STOPPED, */
115
116   /* /\** */
117   /*  * Peers are destroyed */
118   /*  *\/ */
119   /* RC_PEERS_DESTROYED */
120
121   /**
122    * All peers shutdown (stopped and destroyed)
123    */
124   RC_PEERS_SHUTDOWN
125 };
126
127
128 /**
129  * Testbed Run Handle
130  */
131 struct RunContext
132 {
133   /**
134    * The controller handle
135    */
136   struct GNUNET_TESTBED_Controller *c;
137
138   /**
139    * The configuration of the controller. This is based on the cfg given to the
140    * function GNUNET_TESTBED_run(). We also use this config as a template while
141    * for peers
142    */
143   struct GNUNET_CONFIGURATION_Handle *cfg;
144
145   /**
146    * Handle to the host on which the controller runs
147    */
148   struct GNUNET_TESTBED_Host *h;
149
150   /**
151    * The handle to the controller process
152    */
153   struct GNUNET_TESTBED_ControllerProc *cproc;
154
155   /**
156    * The callback to use as controller callback
157    */
158   GNUNET_TESTBED_ControllerCallback cc;
159
160   /**
161    * The pointer to the controller callback
162    */
163   void *cc_cls;
164
165   /**
166    * The trusted IP string
167    */
168   char *trusted_ip;
169
170   /**
171    * TestMaster callback to call when testbed initialization is done
172    */
173   GNUNET_TESTBED_TestMaster test_master;
174
175   /**
176    * The closure for the TestMaster callback
177    */
178   void *test_master_cls;
179
180   /**
181    * The head element of DLL operations
182    */
183   struct DLLOperation *dll_op_head;
184
185   /**
186    * The tail element of DLL operations
187    */
188   struct DLLOperation *dll_op_tail;
189
190   /**
191    * An array of hosts loaded from the hostkeys file
192    */
193   struct GNUNET_TESTBED_Host **hosts;
194
195   /**
196    * The handle for whether a host is habitable or not
197    */
198   struct GNUNET_TESTBED_HostHabitableCheckHandle **hc_handles;
199
200   /**
201    * Array of peers which we create
202    */
203   struct GNUNET_TESTBED_Peer **peers;
204
205   /**
206    * The topology generation operation. Will be null if no topology is set in
207    * the configuration
208    */
209   struct GNUNET_TESTBED_Operation *topology_operation;
210
211   /**
212    * The file containing topology data. Only used if the topology is set to 'FROM_FILE'
213    */
214   char *topo_file;
215
216   /**
217    * Host registration handle
218    */
219   struct GNUNET_TESTBED_HostRegistrationHandle *reg_handle;
220
221   /**
222    * Profiling start time
223    */
224   struct GNUNET_TIME_Absolute pstart_time;
225
226   /**
227    * Host registration task
228    */
229   GNUNET_SCHEDULER_TaskIdentifier register_hosts_task;
230
231   /**
232    * Task to be run while shutting down
233    */
234   GNUNET_SCHEDULER_TaskIdentifier shutdown_run_task;
235
236   /**
237    * Task to be run of a timeout
238    */
239   GNUNET_SCHEDULER_TaskIdentifier timeout_task;
240
241   /**
242    * Task run upon shutdown interrupts
243    */
244   GNUNET_SCHEDULER_TaskIdentifier interrupt_task;
245
246   /**
247    * The event mask for the controller
248    */
249   uint64_t event_mask;
250
251   /**
252    * State of this context
253    */
254   enum State state;
255
256   /**
257    * The topology which has to be achieved with the peers started in this context
258    */
259   enum GNUNET_TESTBED_TopologyOption topology;
260
261   /**
262    * Have we already shutdown
263    */
264   int shutdown;
265
266   /**
267    * Number of hosts in the given host file
268    */
269   unsigned int num_hosts;
270
271   /**
272    * Number of registered hosts. Also used as a counter while checking
273    * habitabillity of hosts
274    */
275   unsigned int reg_hosts;
276
277   /**
278    * Current peer count for an operation; Set this to 0 and increment for each
279    * successful operation on a peer
280    */
281   unsigned int peer_count;
282
283   /**
284    * number of peers to start
285    */
286   unsigned int num_peers;
287
288   /**
289    * Expected overlay connects. Should be zero if no topology is relavant
290    */
291   unsigned int num_oc;
292
293   /**
294    * Number of random links to established
295    */
296   unsigned int random_links;
297
298 };
299
300
301 /**
302  * Assuming all peers have been destroyed cleanup run handle
303  *
304  * @param cls the run handle
305  * @param tc the task context from scheduler
306  */
307 static void
308 cleanup_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
309 {
310   struct RunContext *rc = cls;
311   unsigned int hid;
312
313   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == rc->register_hosts_task);
314   GNUNET_assert (NULL == rc->reg_handle);
315   GNUNET_assert (NULL == rc->peers);
316   GNUNET_assert (NULL == rc->hc_handles);
317   GNUNET_assert (RC_PEERS_SHUTDOWN == rc->state);
318   GNUNET_assert (NULL == rc->dll_op_head);
319   if (NULL != rc->c)
320     GNUNET_TESTBED_controller_disconnect (rc->c);
321   if (NULL != rc->cproc)
322     GNUNET_TESTBED_controller_stop (rc->cproc);
323   if (NULL != rc->h)
324     GNUNET_TESTBED_host_destroy (rc->h);
325   for (hid = 0; hid < rc->num_hosts; hid++)
326     GNUNET_TESTBED_host_destroy (rc->hosts[hid]);
327   GNUNET_free_non_null (rc->hosts);
328   if (NULL != rc->cfg)
329     GNUNET_CONFIGURATION_destroy (rc->cfg);
330   GNUNET_free_non_null (rc->topo_file);
331   GNUNET_free_non_null (rc->trusted_ip);
332   GNUNET_free (rc);
333 }
334
335 static void
336 cleanup (struct RunContext *rc)
337 {
338   struct DLLOperation *dll_op;
339   unsigned int nhost;
340
341   if (NULL != rc->hc_handles)
342   {
343     for (nhost = 0; nhost < rc->num_hosts; nhost++)
344       if (NULL != rc->hc_handles[nhost])
345         GNUNET_TESTBED_is_host_habitable_cancel (rc->hc_handles[nhost]);
346     GNUNET_free (rc->hc_handles);
347     rc->hc_handles = NULL;
348   }
349   /* Stop register hosts task if it is running */
350   if (GNUNET_SCHEDULER_NO_TASK != rc->register_hosts_task)
351   {
352     GNUNET_SCHEDULER_cancel (rc->register_hosts_task);
353     rc->register_hosts_task = GNUNET_SCHEDULER_NO_TASK;
354   }
355   if (GNUNET_SCHEDULER_NO_TASK != rc->timeout_task)
356   {
357     GNUNET_SCHEDULER_cancel (rc->timeout_task);
358     rc->timeout_task = GNUNET_SCHEDULER_NO_TASK;
359   }
360   if (GNUNET_SCHEDULER_NO_TASK != rc->interrupt_task)
361   {
362     GNUNET_SCHEDULER_cancel (rc->interrupt_task);
363     rc->interrupt_task = GNUNET_SCHEDULER_NO_TASK;
364   }
365   if (NULL != rc->reg_handle)
366   {
367     GNUNET_TESTBED_cancel_registration (rc->reg_handle);
368     rc->reg_handle = NULL;
369   }
370   if (NULL != rc->topology_operation)
371   {
372     GNUNET_TESTBED_operation_done (rc->topology_operation);
373     rc->topology_operation = NULL;
374   }
375   /* cancel any exiting operations */
376   while (NULL != (dll_op = rc->dll_op_head))
377   {
378     GNUNET_TESTBED_operation_done (dll_op->op);
379     GNUNET_CONTAINER_DLL_remove (rc->dll_op_head, rc->dll_op_tail, dll_op);
380     GNUNET_free (dll_op);
381   }
382 }
383
384
385 /**
386  * Stops the testbed run and releases any used resources
387  *
388  * @param cls the tesbed run handle
389  * @param tc the task context from scheduler
390  */
391 static void
392 shutdown_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
393 {
394   struct RunContext *rc = cls;
395   struct DLLOperation *dll_op;
396
397   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != rc->shutdown_run_task);
398   rc->shutdown_run_task = GNUNET_SCHEDULER_NO_TASK;
399   GNUNET_assert (GNUNET_NO == rc->shutdown);
400   rc->shutdown = GNUNET_YES;
401   cleanup (rc);
402   if (NULL != rc->c)
403   {
404     if (NULL != rc->peers)
405     {
406       dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
407       dll_op->op = GNUNET_TESTBED_shutdown_peers (rc->c, dll_op, NULL, NULL);
408       GNUNET_assert (NULL != dll_op->op);
409       DEBUG ("Shutting down peers\n");
410       rc->pstart_time = GNUNET_TIME_absolute_get ();
411       GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail,
412                                         dll_op);
413       return;
414     }
415   }
416   rc->state = RC_PEERS_SHUTDOWN;       /* No peers are present so we consider the
417                                         * state where all peers are SHUTDOWN  */
418   GNUNET_SCHEDULER_add_now (&cleanup_task, rc);
419 }
420
421
422 /**
423  * Function to shutdown now
424  *
425  * @param rc the RunContext
426  */
427 static void
428 shutdown_now (struct RunContext *rc)
429 {
430   if (GNUNET_YES == rc->shutdown)
431     return;
432   if (GNUNET_SCHEDULER_NO_TASK != rc->shutdown_run_task)
433     GNUNET_SCHEDULER_cancel (rc->shutdown_run_task);
434   GNUNET_SCHEDULER_shutdown (); /* Trigger shutdown in programs using this API */
435   rc->shutdown_run_task = GNUNET_SCHEDULER_add_now (&shutdown_run, rc);
436 }
437
438
439 static void
440 interrupt (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
441 {
442   struct RunContext *rc = cls;
443
444   rc->interrupt_task = GNUNET_SCHEDULER_NO_TASK;
445   shutdown_now (rc);
446 }
447
448
449 /**
450  * Function to return the string representation of the duration between current
451  * time and `pstart_time' in `RunContext'
452  *
453  * @param rc the RunContext
454  * @return the representation string; this is NOT reentrant
455  */
456 static const char *
457 prof_time (struct RunContext *rc)
458 {
459   struct GNUNET_TIME_Relative ptime;
460
461   ptime = GNUNET_TIME_absolute_get_duration (rc->pstart_time);
462   return GNUNET_STRINGS_relative_time_to_string (ptime, GNUNET_YES);
463 }
464
465
466 /**
467  * Task for starting peers
468  *
469  * @param cls the RunHandle
470  * @param tc the task context from scheduler
471  */
472 static void
473 start_peers_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
474 {
475   struct RunContext *rc = cls;
476   struct DLLOperation *dll_op;
477   unsigned int peer;
478
479   DEBUG ("Starting Peers\n");
480   rc->pstart_time = GNUNET_TIME_absolute_get ();
481   for (peer = 0; peer < rc->num_peers; peer++)
482   {
483     dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
484     dll_op->op = GNUNET_TESTBED_peer_start (NULL, rc->peers[peer], NULL, NULL);
485     GNUNET_assert (NULL != dll_op->op);
486     dll_op->cls = rc->peers[peer];
487     GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail, dll_op);
488   }
489   rc->peer_count = 0;
490 }
491
492
493 /**
494  * Functions of this signature are called when a peer has been successfully
495  * created
496  *
497  * @param cls the closure from GNUNET_TESTBED_peer_create()
498  * @param peer the handle for the created peer; NULL on any error during
499  *          creation
500  * @param emsg NULL if peer is not NULL; else MAY contain the error description
501  */
502 static void
503 peer_create_cb (void *cls, struct GNUNET_TESTBED_Peer *peer, const char *emsg)
504 {
505   struct DLLOperation *dll_op = cls;
506   struct RunContext *rc;
507
508   GNUNET_assert (NULL != dll_op);
509   rc = dll_op->rc;
510   GNUNET_assert (NULL != rc);
511   GNUNET_CONTAINER_DLL_remove (rc->dll_op_head, rc->dll_op_tail, dll_op);
512   GNUNET_TESTBED_operation_done (dll_op->op);
513   GNUNET_free (dll_op);
514   if (NULL == peer)
515   {
516     if (NULL != emsg)
517       LOG (GNUNET_ERROR_TYPE_ERROR, "Error while creating a peer: %s\n",
518            emsg);
519     shutdown_now (rc);
520     return;
521   }
522   rc->peers[rc->peer_count] = peer;
523   rc->peer_count++;
524   if (rc->peer_count < rc->num_peers)
525     return;
526   DEBUG ("%u peers created in %s\n", rc->num_peers, prof_time (rc));
527   rc->state = RC_PEERS_CREATED;
528   GNUNET_SCHEDULER_add_now (&start_peers_task, rc);
529 }
530
531
532 /**
533  * call test master callback
534  *
535  * @param rc the RunContext
536  */
537 static void
538 call_master (struct RunContext *rc)
539 {
540   GNUNET_SCHEDULER_cancel (rc->timeout_task);
541   rc->timeout_task = GNUNET_SCHEDULER_NO_TASK;
542   if (NULL != rc->test_master)
543     rc->test_master (rc->test_master_cls, rc->num_peers, rc->peers);
544 }
545
546
547 /**
548  * Callbacks of this type are called when topology configuration is completed
549  *
550  * @param cls the operation closure given to
551  *          GNUNET_TESTBED_overlay_configure_topology_va() and
552  *          GNUNET_TESTBED_overlay_configure() calls
553  * @param nsuccess the number of successful overlay connects
554  * @param nfailures the number of overlay connects which failed
555  */
556 static void
557 topology_completion_callback (void *cls, unsigned int nsuccess,
558                               unsigned int nfailures)
559 {
560   struct RunContext *rc = cls;
561
562   DEBUG ("Overlay topology generated in %s\n", prof_time (rc));
563   GNUNET_TESTBED_operation_done (rc->topology_operation);
564   rc->topology_operation = NULL;
565   rc->state = RC_READY;
566   call_master (rc);
567 }
568
569
570 /**
571  * Function to create peers
572  *
573  * @param rc the RunContext
574  */
575 static void
576 create_peers (struct RunContext *rc)
577 {
578   struct DLLOperation *dll_op;
579   unsigned int peer;
580
581   DEBUG ("Creating peers\n");
582   rc->pstart_time = GNUNET_TIME_absolute_get ();
583   rc->peers =
584       GNUNET_malloc (sizeof (struct GNUNET_TESTBED_Peer *) * rc->num_peers);
585   GNUNET_assert (NULL != rc->c);
586   rc->peer_count = 0;
587   for (peer = 0; peer < rc->num_peers; peer++)
588   {
589     dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
590     dll_op->rc = rc;
591     dll_op->op =
592         GNUNET_TESTBED_peer_create (rc->c,
593                                     (0 ==
594                                      rc->num_hosts) ? rc->h : rc->hosts[peer %
595                                                                         rc->num_hosts],
596                                     rc->cfg, peer_create_cb, dll_op);    
597     GNUNET_assert (NULL != dll_op->op);
598     GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail, dll_op);
599   }
600 }
601
602
603 /**
604  * Signature of the event handler function called by the
605  * respective event controller.
606  *
607  * @param cls closure
608  * @param event information about the event
609  */
610 static void
611 event_cb (void *cls, const struct GNUNET_TESTBED_EventInformation *event)
612 {
613   struct RunContext *rc = cls;
614   struct DLLOperation *dll_op;
615
616   if (RC_INIT == rc->state)
617   {
618     switch (event->type)
619     {
620     case GNUNET_TESTBED_ET_OPERATION_FINISHED:
621       dll_op = event->op_cls;
622       if (NULL != event->details.operation_finished.emsg)
623       {
624         LOG (GNUNET_ERROR_TYPE_ERROR, _("Linking controllers failed. Exiting"));
625         shutdown_now (rc);
626       }
627       else
628         rc->reg_hosts++;
629       GNUNET_assert (event->op == dll_op->op);
630       GNUNET_CONTAINER_DLL_remove (rc->dll_op_head, rc->dll_op_tail, dll_op);
631       GNUNET_TESTBED_operation_done (dll_op->op);
632       GNUNET_free (dll_op);
633       if (rc->reg_hosts == rc->num_hosts)
634       {
635         rc->state = RC_LINKED;
636         create_peers (rc);
637       }
638       return;
639     default:
640       GNUNET_break (0);
641       shutdown_now (rc);
642       return;
643     }
644   }
645   for (dll_op = rc->dll_op_head; NULL != dll_op; dll_op = dll_op->next)
646   {
647     if ((GNUNET_TESTBED_ET_OPERATION_FINISHED == event->type) &&
648         (event->op == dll_op->op))
649       break;
650   }
651   if (NULL == dll_op)
652     goto call_cc;
653   GNUNET_CONTAINER_DLL_remove (rc->dll_op_head, rc->dll_op_tail, dll_op);
654   GNUNET_TESTBED_operation_done (dll_op->op);
655   GNUNET_free (dll_op);
656   if ( (GNUNET_NO == rc->shutdown)
657        && (NULL != event->details.operation_finished.emsg) )
658   {
659     LOG (GNUNET_ERROR_TYPE_ERROR, "A operation has failed with error: %s\n",
660          event->details.operation_finished.emsg);
661     shutdown_now (rc);
662     return;
663   }
664   GNUNET_assert (GNUNET_YES == rc->shutdown);
665   switch (rc->state)
666   {
667   case RC_LINKED:
668   case RC_PEERS_CREATED:
669   case RC_READY:
670     rc->state = RC_PEERS_SHUTDOWN;
671     GNUNET_free_non_null (rc->peers);
672     rc->peers = NULL;
673     DEBUG ("Peers shut down in %s\n", prof_time (rc));
674     GNUNET_SCHEDULER_add_now (&cleanup_task, rc);
675     break;
676   default:
677     GNUNET_assert (0);
678   }
679   return;
680
681 call_cc:
682   if ((0 != (rc->event_mask & (1LL << event->type))) && (NULL != rc->cc))
683     rc->cc (rc->cc_cls, event);
684   if (GNUNET_TESTBED_ET_PEER_START != event->type)
685     return;
686   for (dll_op = rc->dll_op_head; NULL != dll_op; dll_op = dll_op->next)
687     if ((NULL != dll_op->cls) &&
688         (event->details.peer_start.peer == dll_op->cls))
689       break;
690   if (NULL == dll_op)           /* Not our operation */
691     return;
692   GNUNET_CONTAINER_DLL_remove (rc->dll_op_head, rc->dll_op_tail, dll_op);
693   GNUNET_TESTBED_operation_done (dll_op->op);
694   GNUNET_free (dll_op);
695   rc->peer_count++;
696   if (rc->peer_count < rc->num_peers)
697     return;
698   DEBUG ("%u peers started in %s\n", rc->num_peers, prof_time (rc));
699   if (GNUNET_TESTBED_TOPOLOGY_NONE != rc->topology)
700   {
701     if ((GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI == rc->topology) ||
702         (GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD_RING == rc->topology) ||
703         (GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD == rc->topology))
704     {
705       rc->topology_operation =
706           GNUNET_TESTBED_overlay_configure_topology (NULL, rc->num_peers,
707                                                      rc->peers, &rc->num_oc,
708                                                      &topology_completion_callback,
709                                                      rc,
710                                                      rc->topology,
711                                                      rc->random_links,
712                                                      GNUNET_TESTBED_TOPOLOGY_OPTION_END);
713     }
714     else if (GNUNET_TESTBED_TOPOLOGY_FROM_FILE == rc->topology)
715     {
716       GNUNET_assert (NULL != rc->topo_file);
717       rc->topology_operation =
718           GNUNET_TESTBED_overlay_configure_topology (NULL, rc->num_peers,
719                                                      rc->peers, &rc->num_oc,
720                                                      &topology_completion_callback,
721                                                      rc,
722                                                      rc->topology,
723                                                      rc->topo_file,
724                                                      GNUNET_TESTBED_TOPOLOGY_OPTION_END);
725     }
726     else
727       rc->topology_operation =
728           GNUNET_TESTBED_overlay_configure_topology (NULL, rc->num_peers,
729                                                      rc->peers, &rc->num_oc,
730                                                      &topology_completion_callback,
731                                                      rc,
732                                                      rc->topology,
733                                                      GNUNET_TESTBED_TOPOLOGY_OPTION_END);
734     if (NULL == rc->topology_operation)
735       LOG (GNUNET_ERROR_TYPE_WARNING,
736            "Not generating topology. Check number of peers\n");
737     else
738     {
739       DEBUG ("Creating overlay topology\n");
740       rc->pstart_time = GNUNET_TIME_absolute_get ();
741       return;
742     }
743   }
744   rc->state = RC_READY;
745   call_master (rc);
746 }
747
748
749 /**
750  * Task to register all hosts available in the global host list
751  *
752  * @param cls the RunContext
753  * @param tc the scheduler task context
754  */
755 static void
756 register_hosts (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
757
758
759 /**
760  * Callback which will be called to after a host registration succeeded or failed
761  *
762  * @param cls the closure
763  * @param emsg the error message; NULL if host registration is successful
764  */
765 static void
766 host_registration_completion (void *cls, const char *emsg)
767 {
768   struct RunContext *rc = cls;
769
770   rc->reg_handle = NULL;
771   if (NULL != emsg)
772   {
773     LOG (GNUNET_ERROR_TYPE_WARNING,
774          _("Host registration failed for a host. Error: %s\n"), emsg);
775     shutdown_now (rc);
776     return;
777   }
778   rc->register_hosts_task = GNUNET_SCHEDULER_add_now (&register_hosts, rc);
779 }
780
781
782 /**
783  * Task to register all hosts available in the global host list
784  *
785  * @param cls RunContext
786  * @param tc the scheduler task context
787  */
788 static void
789 register_hosts (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
790 {
791   struct RunContext *rc = cls;
792   struct DLLOperation *dll_op;
793   unsigned int slave;
794
795   rc->register_hosts_task = GNUNET_SCHEDULER_NO_TASK;
796   if (rc->reg_hosts == rc->num_hosts)
797   {
798     DEBUG ("All hosts successfully registered\n");
799     /* Start slaves */
800     for (slave = 0; slave < rc->num_hosts; slave++)
801     {
802       dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
803       dll_op->rc = rc;
804       dll_op->op =
805           GNUNET_TESTBED_controller_link (dll_op, rc->c, rc->hosts[slave],
806                                           rc->h, rc->cfg, GNUNET_YES);
807       GNUNET_assert (NULL != dll_op->op);
808       GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail,
809                                         dll_op);
810     }
811     rc->reg_hosts = 0;
812     return;
813   }
814   rc->reg_handle =
815       GNUNET_TESTBED_register_host (rc->c, rc->hosts[rc->reg_hosts],
816                                     host_registration_completion, rc);
817   rc->reg_hosts++;
818 }
819
820
821 /**
822  * Callback to signal successfull startup of the controller process
823  *
824  * @param cls the closure from GNUNET_TESTBED_controller_start()
825  * @param cfg the configuration with which the controller has been started;
826  *          NULL if status is not GNUNET_OK
827  * @param status GNUNET_OK if the startup is successfull; GNUNET_SYSERR if not,
828  *          GNUNET_TESTBED_controller_stop() shouldn't be called in this case
829  */
830 static void
831 controller_status_cb (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg,
832                       int status)
833 {
834   struct RunContext *rc = cls;
835   uint64_t event_mask;
836
837   if (status != GNUNET_OK)
838   {
839     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
840                 _("Controller crash detected. Shutting down.\n"));
841     rc->cproc = NULL;
842     cleanup (rc);
843     if (NULL != rc->peers)
844     {
845       GNUNET_free (rc->peers);
846       rc->peers = NULL;
847     }
848     if (GNUNET_YES == rc->shutdown)
849     {
850       rc->state = RC_PEERS_SHUTDOWN;
851       GNUNET_SCHEDULER_add_now (&cleanup_task, rc);
852     }
853     else
854       shutdown_now (rc);
855     return;
856   }
857   GNUNET_CONFIGURATION_destroy (rc->cfg);
858   rc->cfg = GNUNET_CONFIGURATION_dup (cfg);
859   event_mask = rc->event_mask;
860   event_mask |= (1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED);
861   event_mask |= (1LL << GNUNET_TESTBED_ET_PEER_START);
862   if (rc->topology < GNUNET_TESTBED_TOPOLOGY_NONE)
863     event_mask |= GNUNET_TESTBED_ET_CONNECT;
864   rc->c =
865       GNUNET_TESTBED_controller_connect (rc->cfg, rc->h, event_mask, &event_cb,
866                                          rc);
867   if (0 < rc->num_hosts)
868   {
869     rc->reg_hosts = 0;
870     rc->register_hosts_task = GNUNET_SCHEDULER_add_now (&register_hosts, rc);
871     return;
872   }
873   rc->state = RC_LINKED;
874   create_peers (rc);
875 }
876
877
878 /**
879  * Callback function invoked for each interface found.
880  *
881  * @param cls closure
882  * @param name name of the interface (can be NULL for unknown)
883  * @param isDefault is this presumably the default interface
884  * @param addr address of this interface (can be NULL for unknown or unassigned)
885  * @param broadcast_addr the broadcast address (can be NULL for unknown or unassigned)
886  * @param netmask the network mask (can be NULL for unknown or unassigned))
887  * @param addrlen length of the address
888  * @return GNUNET_OK to continue iteration, GNUNET_SYSERR to abort
889  */
890 static int
891 netint_proc (void *cls, const char *name, int isDefault,
892              const struct sockaddr *addr, const struct sockaddr *broadcast_addr,
893              const struct sockaddr *netmask, socklen_t addrlen)
894 {
895   struct RunContext *rc = cls;
896   char hostip[NI_MAXHOST];
897   char *buf;
898
899   if (sizeof (struct sockaddr_in) != addrlen)
900     return GNUNET_OK;           /* Only consider IPv4 for now */
901   if (0 !=
902       getnameinfo (addr, addrlen, hostip, NI_MAXHOST, NULL, 0, NI_NUMERICHOST))
903     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "getnameinfo");
904   if (NULL == rc->trusted_ip)
905   {
906     rc->trusted_ip = GNUNET_strdup (hostip);
907     return GNUNET_YES;
908   }
909   (void) GNUNET_asprintf (&buf, "%s; %s", rc->trusted_ip, hostip);
910   GNUNET_free (rc->trusted_ip);
911   rc->trusted_ip = buf;
912   return GNUNET_YES;
913 }
914
915
916 /**
917  * Callbacks of this type are called by GNUNET_TESTBED_is_host_habitable to
918  * inform whether the given host is habitable or not. The Handle returned by
919  * GNUNET_TESTBED_is_host_habitable() is invalid after this callback is called
920  *
921  * @param cls NULL
922  * @param host the host whose status is being reported; will be NULL if the host
923  *          given to GNUNET_TESTBED_is_host_habitable() is NULL
924  * @param status GNUNET_YES if it is habitable; GNUNET_NO if not
925  */
926 static void
927 host_habitable_cb (void *cls, const struct GNUNET_TESTBED_Host *host,
928                    int status)
929 {
930   struct RunContext *rc = cls;
931   struct GNUNET_TESTBED_Host **old_hosts;
932   unsigned int nhost;
933
934   for (nhost = 0; nhost < rc->num_hosts; nhost++)
935   {
936     if (host == rc->hosts[nhost])
937       break;
938   }
939   GNUNET_assert (nhost != rc->num_hosts);
940   rc->hc_handles[nhost] = NULL;
941   if (GNUNET_NO == status)
942   {
943     if ((NULL != host) && (NULL != GNUNET_TESTBED_host_get_hostname (host)))
944       LOG (GNUNET_ERROR_TYPE_ERROR, _("Host %s cannot start testbed\n"),
945            GNUNET_TESTBED_host_get_hostname (host));
946     else
947       LOG (GNUNET_ERROR_TYPE_ERROR,
948            _("Testbed cannot be started on localhost\n"));
949     shutdown_now (rc);
950     return;
951   }
952   rc->reg_hosts++;
953   if (rc->reg_hosts < rc->num_hosts)
954     return;
955   GNUNET_free (rc->hc_handles);
956   rc->hc_handles = NULL;
957   rc->h = rc->hosts[0];
958   rc->num_hosts--;
959   if (0 < rc->num_hosts)
960   {
961     old_hosts = rc->hosts;
962     rc->hosts =
963         GNUNET_malloc (sizeof (struct GNUNET_TESTBED_Host *) * rc->num_hosts);
964     memcpy (rc->hosts, &old_hosts[1],
965             (sizeof (struct GNUNET_TESTBED_Host *) * rc->num_hosts));
966     GNUNET_free (old_hosts);
967   }
968   else
969   {
970     GNUNET_free (rc->hosts);
971     rc->hosts = NULL;
972   }
973   GNUNET_OS_network_interfaces_list (netint_proc, rc);
974   if (NULL == rc->trusted_ip)
975     rc->trusted_ip = GNUNET_strdup ("127.0.0.1");
976   rc->cproc =
977       GNUNET_TESTBED_controller_start (rc->trusted_ip, rc->h, rc->cfg,
978                                        &controller_status_cb, rc);
979   GNUNET_free (rc->trusted_ip);
980   rc->trusted_ip = NULL;
981   if (NULL == rc->cproc)
982   {
983     LOG (GNUNET_ERROR_TYPE_ERROR, _("Cannot start the master controller"));
984     shutdown_now (rc);
985   }
986 }
987
988
989 /**
990  * Task run upon timeout while setting up the testbed
991  *
992  * @param cls the RunContext
993  * @param tc the task context
994  */
995 static void
996 timeout_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
997 {
998   struct RunContext *rc = cls;
999   
1000   rc->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1001   LOG (GNUNET_ERROR_TYPE_ERROR, _("Shutting down testbed due to timeout while setup.\n"));
1002   shutdown_now (rc);
1003    if (NULL != rc->test_master)
1004     rc->test_master (rc->test_master_cls, 0, NULL);
1005    rc->test_master = NULL;
1006 }
1007
1008
1009 /**
1010  * Convenience method for running a testbed with
1011  * a single call.  Underlay and overlay topology
1012  * are configured using the "UNDERLAY" and "OVERLAY"
1013  * options in the "[testbed]" section of the configuration\
1014  * (with possible options given in "UNDERLAY_XXX" and/or
1015  * "OVERLAY_XXX").
1016  *
1017  * The testbed is to be terminated using a call to
1018  * "GNUNET_SCHEDULER_shutdown".
1019  *
1020  * @param host_filename name of the file with the 'hosts', NULL
1021  *        to run everything on 'localhost'
1022  * @param cfg configuration to use (for testbed, controller and peers)
1023  * @param num_peers number of peers to start; FIXME: maybe put that ALSO into cfg?
1024  * @param event_mask bit mask with set of events to call 'cc' for;
1025  *                   or-ed values of "1LL" shifted by the
1026  *                   respective 'enum GNUNET_TESTBED_EventType'
1027  *                   (i.e.  "(1LL << GNUNET_TESTBED_ET_CONNECT) || ...")
1028  * @param cc controller callback to invoke on events; This callback is called
1029  *          for all peer start events even if GNUNET_TESTBED_ET_PEER_START isn't
1030  *          set in the event_mask as this is the only way get access to the
1031  *          handle of each peer
1032  * @param cc_cls closure for cc
1033  * @param test_master this callback will be called once the test is ready
1034  * @param test_master_cls closure for 'test_master'.
1035  */
1036 void
1037 GNUNET_TESTBED_run (const char *host_filename,
1038                     const struct GNUNET_CONFIGURATION_Handle *cfg,
1039                     unsigned int num_peers, uint64_t event_mask,
1040                     GNUNET_TESTBED_ControllerCallback cc, void *cc_cls,
1041                     GNUNET_TESTBED_TestMaster test_master,
1042                     void *test_master_cls)
1043 {
1044   struct RunContext *rc;
1045   char *topology;
1046   struct GNUNET_TIME_Relative timeout;
1047   unsigned long long random_links;
1048   unsigned int hid;
1049   unsigned int nhost;
1050
1051   GNUNET_assert (num_peers > 0);
1052   rc = GNUNET_malloc (sizeof (struct RunContext));
1053   rc->cfg = GNUNET_CONFIGURATION_dup (cfg);
1054 #if ENABLE_LL
1055   rc->num_hosts = GNUNET_TESTBED_hosts_load_from_loadleveler (rc->cfg,
1056                                                               &rc->hosts);
1057   if (0 == rc->num_hosts)
1058   {
1059     LOG (GNUNET_ERROR_TYPE_WARNING,
1060            _("No hosts loaded from LoadLeveler. Need at least one host\n"));
1061     goto error_cleanup;
1062   }
1063 #else
1064   if (NULL != host_filename)
1065   {
1066     rc->num_hosts =
1067         GNUNET_TESTBED_hosts_load_from_file (host_filename, rc->cfg,
1068                                              &rc->hosts);
1069     if (0 == rc->num_hosts)
1070     {
1071       LOG (GNUNET_ERROR_TYPE_WARNING,
1072            _("No hosts loaded. Need at least one host\n"));
1073       goto error_cleanup;
1074     }
1075   }
1076   else
1077     rc->h = GNUNET_TESTBED_host_create (NULL, NULL, rc->cfg, 0);
1078 #endif
1079   rc->num_peers = num_peers;
1080   rc->event_mask = event_mask;
1081   rc->cc = cc;
1082   rc->cc_cls = cc_cls;
1083   rc->test_master = test_master;
1084   rc->test_master_cls = test_master_cls;
1085   rc->state = RC_INIT;
1086   rc->topology = GNUNET_TESTBED_TOPOLOGY_NONE;
1087   if (GNUNET_OK ==
1088       GNUNET_CONFIGURATION_get_value_string (rc->cfg, "testbed",
1089                                              "OVERLAY_TOPOLOGY", &topology))
1090   {
1091     if (GNUNET_NO == GNUNET_TESTBED_topology_get_ (&rc->topology, topology))
1092     {
1093       GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, "testbed",
1094                                  "OVERLAY_TOPLOGY",
1095                                  _
1096                                  ("Specified topology must be supported by testbed"));
1097     }
1098     GNUNET_free (topology);
1099   }
1100   switch (rc->topology)
1101   {
1102   case GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI:
1103   case GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD_RING:
1104   case GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD:
1105     if (GNUNET_OK !=
1106         GNUNET_CONFIGURATION_get_value_number (rc->cfg, "testbed",
1107                                                "OVERLAY_RANDOM_LINKS",
1108                                                &random_links))
1109     {
1110       /* OVERLAY option RANDOM & SMALL_WORLD_RING requires OVERLAY_RANDOM_LINKS
1111        * option to be set to the number of random links to be established  */
1112       GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "testbed",
1113                                  "OVERLAY_RANDOM_LINKS");
1114       goto error_cleanup;
1115     }
1116     if (random_links > UINT32_MAX)
1117     {
1118       GNUNET_break (0);         /* Too big number */
1119       goto error_cleanup;
1120     }
1121     rc->random_links = (unsigned int) random_links;
1122     break;
1123   case GNUNET_TESTBED_TOPOLOGY_FROM_FILE:
1124     if (GNUNET_OK !=
1125         GNUNET_CONFIGURATION_get_value_string (rc->cfg, "testbed",
1126                                                "OVERLAY_TOPOLOGY_FILE",
1127                                                &rc->topo_file))
1128     {
1129       GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "testbed",
1130                                  "OVERLAY_TOPOLOGY_FILE");
1131       goto error_cleanup;
1132     }
1133   default:
1134     /* Warn if OVERLAY_RANDOM_LINKS is present that it will be ignored */
1135     if (GNUNET_YES ==
1136         GNUNET_CONFIGURATION_have_value (rc->cfg, "testbed",
1137                                          "OVERLAY_RANDOM_LINKS"))
1138       LOG (GNUNET_ERROR_TYPE_WARNING,
1139            "Ignoring value of `OVERLAY_RANDOM_LINKS' in given configuration\n");
1140     break;
1141   }
1142   if (0 != rc->num_hosts)
1143   {
1144     rc->hc_handles =
1145         GNUNET_malloc (sizeof (struct GNUNET_TESTBED_HostHabitableCheckHandle *)
1146                        * rc->num_hosts);
1147     for (nhost = 0; nhost < rc->num_hosts; nhost++)
1148     {
1149       if (NULL ==
1150           (rc->hc_handles[nhost] =
1151            GNUNET_TESTBED_is_host_habitable (rc->hosts[nhost], rc->cfg,
1152                                              &host_habitable_cb, rc)))
1153       {
1154         GNUNET_break (0);
1155         for (nhost = 0; nhost < rc->num_hosts; nhost++)
1156           if (NULL != rc->hc_handles[nhost])
1157             GNUNET_TESTBED_is_host_habitable_cancel (rc->hc_handles[nhost]);
1158         GNUNET_free (rc->hc_handles);
1159         rc->hc_handles = NULL;
1160         goto error_cleanup;
1161       }
1162     }
1163   }
1164   else
1165     rc->cproc =
1166         GNUNET_TESTBED_controller_start ("127.0.0.1", rc->h, rc->cfg,
1167                                          &controller_status_cb, rc);
1168   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (cfg, "TESTBED",
1169                                                         "SETUP_TIMEOUT",
1170                                                         &timeout))
1171   {
1172     timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
1173                                              DEFAULT_SETUP_TIMEOUT);
1174   }
1175   rc->timeout_task =
1176       GNUNET_SCHEDULER_add_delayed (timeout, &timeout_task, rc);
1177   rc->interrupt_task =
1178       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &interrupt,
1179                                     rc);
1180   return;
1181
1182 error_cleanup:
1183   if (NULL != rc->h)
1184     GNUNET_TESTBED_host_destroy (rc->h);
1185   if (NULL != rc->hosts)
1186   {
1187     for (hid = 0; hid < rc->num_hosts; hid++)
1188       if (NULL != rc->hosts[hid])
1189         GNUNET_TESTBED_host_destroy (rc->hosts[hid]);
1190     GNUNET_free (rc->hosts);
1191   }
1192   if (NULL != rc->cfg)
1193     GNUNET_CONFIGURATION_destroy (rc->cfg);
1194   GNUNET_free (rc);
1195 }
1196
1197
1198 /* end of testbed_api_testbed.c */