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