dae364699a3a06136660e37793428fdd0583abd2
[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  * @param tc the task context from scheduler
440  */
441 static void
442 cleanup (void *cls)
443 {
444   struct RunContext *rc = cls;
445   unsigned int hid;
446
447   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == rc->register_hosts_task);
448   GNUNET_assert (NULL == rc->reg_handle);
449   GNUNET_assert (NULL == rc->peers);
450   GNUNET_assert (NULL == rc->hclist);
451   GNUNET_assert (RC_PEERS_SHUTDOWN == rc->state);
452   GNUNET_assert (0 == GNUNET_CONTAINER_multihashmap32_size (rc->rcop_map));
453   GNUNET_CONTAINER_multihashmap32_destroy (rc->rcop_map);
454   if (NULL != rc->c)
455     GNUNET_TESTBED_controller_disconnect (rc->c);
456   if (NULL != rc->cproc)
457     GNUNET_TESTBED_controller_stop (rc->cproc);
458   if (NULL != rc->h)
459     GNUNET_TESTBED_host_destroy (rc->h);
460   for (hid = 0; hid < rc->num_hosts; hid++)
461     GNUNET_TESTBED_host_destroy (rc->hosts[hid]);
462   GNUNET_free_non_null (rc->hosts);
463   if (NULL != rc->cfg)
464     GNUNET_CONFIGURATION_destroy (rc->cfg);
465   GNUNET_free_non_null (rc->topo_file);
466   GNUNET_free_non_null (rc->trusted_ip);
467   GNUNET_free (rc);
468 }
469
470
471 /**
472  * Iterator for cleaning up elements from rcop_map 
473  *
474  * @param cls the RunContext
475  * @param key the 32-bit key
476  * @param value the RunContextOperation element
477  * @return always GNUNET_YES
478  */
479 static int
480 rcop_cleanup_iterator (void *cls, uint32_t key, void *value)
481 {
482   struct RunContext *rc = cls;
483   struct RunContextOperation *rcop = value;
484
485   GNUNET_assert (rc == rcop->rc);
486   remove_rcop (rc, rcop);
487   GNUNET_TESTBED_operation_done (rcop->op);
488   GNUNET_free (rcop);
489   return GNUNET_YES;
490 }
491
492
493 /**
494  * Cancels operations and tasks which are assigned to the given run context
495  *
496  * @param rc the RunContext
497  */
498 static void
499 rc_cleanup_operations (struct RunContext *rc)
500 {
501   struct CompatibilityCheckContext *hc;
502   unsigned int nhost;
503
504   if (NULL != rc->hclist)
505   {
506     for (nhost = 0; nhost < rc->num_hosts; nhost++)
507     {
508       hc = &rc->hclist[nhost];
509       if (NULL != hc->h)
510         GNUNET_TESTBED_is_host_habitable_cancel (hc->h);
511     }
512     GNUNET_free (rc->hclist);
513     rc->hclist = NULL;
514   }
515   /* Stop register hosts task if it is running */
516   if (GNUNET_SCHEDULER_NO_TASK != rc->register_hosts_task)
517   {
518     GNUNET_SCHEDULER_cancel (rc->register_hosts_task);
519     rc->register_hosts_task = GNUNET_SCHEDULER_NO_TASK;
520   }
521   if (GNUNET_SCHEDULER_NO_TASK != rc->timeout_task)
522   {
523     GNUNET_SCHEDULER_cancel (rc->timeout_task);
524     rc->timeout_task = GNUNET_SCHEDULER_NO_TASK;
525   }
526   if (NULL != rc->reg_handle)
527   {
528     GNUNET_TESTBED_cancel_registration (rc->reg_handle);
529     rc->reg_handle = NULL;
530   }
531   if (NULL != rc->topology_operation)
532   {
533     GNUNET_TESTBED_operation_done (rc->topology_operation);
534     rc->topology_operation = NULL;
535   }
536   /* cancel any exiting operations */
537   GNUNET_assert (GNUNET_SYSERR != 
538                  GNUNET_CONTAINER_multihashmap32_iterate (rc->rcop_map,
539                                                           &rcop_cleanup_iterator,
540                                                           rc));
541 }
542
543
544 /**
545  * Cancels the scheduled interrupt task
546  *
547  * @param rc the run context
548  */
549 static void
550 cancel_interrupt_task (struct RunContext *rc)
551 {
552   GNUNET_SCHEDULER_cancel (rc->interrupt_task);
553   rc->interrupt_task = GNUNET_SCHEDULER_NO_TASK;
554 }
555
556
557 /**
558  * This callback will be called when all the operations are completed
559  * (done/cancelled) 
560  *
561  * @param cls run context
562  * @param tc scheduler task context
563  */
564 static void
565 wait_op_completion (void *cls)
566 {
567   struct RunContext *rc = cls;
568   struct RunContextOperation *rcop;
569
570   if ( (NULL == rc->cproc)
571        || (NULL == rc->c)
572        || (GNUNET_YES == rc->shutdown) )
573   {
574     if (NULL != rc->peers)
575     {
576       GNUNET_free (rc->peers);
577       rc->peers = NULL;
578     }
579     goto cleanup_;
580   }
581   if (NULL == rc->peers)
582     goto cleanup_;
583   rc->shutdown = GNUNET_YES;
584   rcop = GNUNET_malloc (sizeof (struct RunContextOperation));
585   rcop->rc = rc;
586   rcop->op = GNUNET_TESTBED_shutdown_peers (rc->c, rcop, NULL, NULL);
587   GNUNET_assert (NULL != rcop->op);
588   DEBUG ("Shutting down peers\n");
589   rc->pstart_time = GNUNET_TIME_absolute_get ();
590   insert_rcop (rc, rcop);
591   return;
592
593  cleanup_:
594   rc->state = RC_PEERS_SHUTDOWN;
595   cancel_interrupt_task (rc);
596   cleanup (rc);
597 }
598
599
600 /**
601  * Task run upon interrupts (SIGINT, SIGTERM) and upon scheduler shutdown.
602  *
603  * @param cls the RunContext which has to be acted upon
604  * @param tc the scheduler task context
605  */
606 static void
607 interrupt (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
608 {
609   struct RunContext *rc = cls;
610   struct GNUNET_TESTBED_Controller *c = rc->c;
611   unsigned int size;
612
613   /* reschedule */
614   rc->interrupt_task = GNUNET_SCHEDULER_add_delayed
615       (GNUNET_TIME_UNIT_FOREVER_REL, &interrupt, rc);
616   rc_cleanup_operations (rc);  
617   if ( (GNUNET_NO == rc->shutdown)
618        && (NULL != c) 
619        && (0 != (size = GNUNET_CONTAINER_multihashmap32_size (c->opc_map))))
620   {
621     LOG (GNUNET_ERROR_TYPE_WARNING, "Shutdown postponed as there are "
622          "%u operations currently active\n", size);
623     c->opcq_empty_cb = &wait_op_completion;
624     c->opcq_empty_cls = rc;
625     return;
626   }
627   wait_op_completion (rc);
628 }
629
630
631 /**
632  * Function to return the string representation of the duration between current
633  * time and `pstart_time' in `RunContext'
634  *
635  * @param rc the RunContext
636  * @return the representation string; this is NOT reentrant
637  */
638 static const char *
639 prof_time (struct RunContext *rc)
640 {
641   struct GNUNET_TIME_Relative ptime;
642
643   ptime = GNUNET_TIME_absolute_get_duration (rc->pstart_time);
644   return GNUNET_STRINGS_relative_time_to_string (ptime, GNUNET_YES);
645 }
646
647
648 /**
649  * Task for starting peers
650  *
651  * @param cls the RunHandle
652  * @param tc the task context from scheduler
653  */
654 static void
655 start_peers_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
656 {
657   struct RunContext *rc = cls;
658   struct RunContextOperation *rcop;
659   unsigned int peer;
660
661   DEBUG ("Starting Peers\n");
662   rc->pstart_time = GNUNET_TIME_absolute_get ();
663   for (peer = 0; peer < rc->num_peers; peer++)
664   {
665     rcop = GNUNET_malloc (sizeof (struct RunContextOperation));
666     rcop->rc = rc;
667     rcop->op  = GNUNET_TESTBED_peer_start (NULL, rc->peers[peer], NULL, NULL);
668     GNUNET_assert (NULL != rcop->op);
669     rcop->cls = rc->peers[peer];
670     insert_rcop (rc, rcop);
671   }
672   rc->peer_count = 0;
673 }
674
675
676 /**
677  * Functions of this signature are called when a peer has been successfully
678  * created
679  *
680  * @param cls the closure from GNUNET_TESTBED_peer_create()
681  * @param peer the handle for the created peer; NULL on any error during
682  *          creation
683  * @param emsg NULL if peer is not NULL; else MAY contain the error description
684  */
685 static void
686 peer_create_cb (void *cls, struct GNUNET_TESTBED_Peer *peer, const char *emsg)
687 {
688   struct RunContextOperation *rcop = cls;
689   struct RunContext *rc;
690
691   GNUNET_assert (NULL != rcop);
692   GNUNET_assert (NULL != (rc = rcop->rc));
693   remove_rcop (rc, rcop);
694   GNUNET_TESTBED_operation_done (rcop->op);
695   GNUNET_free (rcop);
696   if (NULL == peer)
697   {
698     if (NULL != emsg)
699       LOG (GNUNET_ERROR_TYPE_ERROR, "Error while creating a peer: %s\n",
700            emsg);
701     GNUNET_SCHEDULER_shutdown ();
702     return;
703   }
704   rc->peers[rc->peer_count] = peer;
705   rc->peer_count++;
706   if (rc->peer_count < rc->num_peers)
707     return;
708   DEBUG ("%u peers created in %s\n", rc->num_peers, prof_time (rc));
709   rc->state = RC_PEERS_CREATED;
710   GNUNET_SCHEDULER_add_now (&start_peers_task, rc);
711 }
712
713
714 /**
715  * call test master callback
716  *
717  * @param rc the RunContext
718  */
719 static void
720 call_master (struct RunContext *rc)
721 {
722   GNUNET_SCHEDULER_cancel (rc->timeout_task);
723   rc->timeout_task = GNUNET_SCHEDULER_NO_TASK;
724   if (NULL != rc->test_master)
725     rc->test_master (rc->test_master_cls, rc->num_peers, rc->peers,
726                      rc->links_succeeded, rc->links_failed);
727 }
728
729
730 /**
731  * Callbacks of this type are called when topology configuration is completed
732  *
733  * @param cls the operation closure given to
734  *          GNUNET_TESTBED_overlay_configure_topology_va() and
735  *          GNUNET_TESTBED_overlay_configure() calls
736  * @param nsuccess the number of successful overlay connects
737  * @param nfailures the number of overlay connects which failed
738  */
739 static void
740 topology_completion_callback (void *cls, unsigned int nsuccess,
741                               unsigned int nfailures)
742 {
743   struct RunContext *rc = cls;
744
745   DEBUG ("Overlay topology generated in %s\n", prof_time (rc));
746   GNUNET_TESTBED_operation_done (rc->topology_operation);
747   rc->topology_operation = NULL;
748   rc->links_succeeded = nsuccess;
749   rc->links_failed = nfailures;
750   rc->state = RC_READY;
751   call_master (rc);
752 }
753
754
755 /**
756  * Function to create peers
757  *
758  * @param rc the RunContext
759  */
760 static void
761 create_peers (struct RunContext *rc)
762 {
763   struct RunContextOperation *rcop;
764   unsigned int peer;
765
766   DEBUG ("Creating peers\n");
767   rc->pstart_time = GNUNET_TIME_absolute_get ();
768   rc->peers =
769       GNUNET_malloc (sizeof (struct GNUNET_TESTBED_Peer *) * rc->num_peers);
770   GNUNET_assert (NULL != rc->c);
771   rc->peer_count = 0;
772   for (peer = 0; peer < rc->num_peers; peer++)
773   {
774     rcop = GNUNET_malloc (sizeof (struct RunContextOperation));
775     rcop->rc = rc;
776     rcop->op =
777         GNUNET_TESTBED_peer_create (rc->c,
778                                     (0 ==
779                                      rc->num_hosts) ? rc->h : rc->hosts[peer %
780                                                                         rc->num_hosts],
781                                     rc->cfg, &peer_create_cb, rcop);
782     GNUNET_assert (NULL != rcop->op);
783     insert_rcop (rc, rcop);
784   }
785 }
786
787
788 /**
789  * Signature of the event handler function called by the
790  * respective event controller.
791  *
792  * @param cls closure
793  * @param event information about the event
794  */
795 static void
796 event_cb (void *cls, const struct GNUNET_TESTBED_EventInformation *event)
797 {
798   struct RunContext *rc = cls;
799   struct RunContextOperation *rcop;
800
801   if (RC_INIT == rc->state)
802   {
803     switch (event->type)
804     {
805     case GNUNET_TESTBED_ET_OPERATION_FINISHED:
806       rcop = event->op_cls;
807       if (NULL != event->details.operation_finished.emsg)
808       {
809         LOG (GNUNET_ERROR_TYPE_ERROR, _("Linking controllers failed. Exiting"));
810         GNUNET_SCHEDULER_shutdown ();
811       }
812       else
813         rc->reg_hosts++;
814       GNUNET_assert (event->op == rcop->op);
815       remove_rcop (rc, rcop);
816       GNUNET_TESTBED_operation_done (rcop->op);
817       GNUNET_free (rcop);
818       if (rc->reg_hosts == rc->num_hosts)
819       {
820         rc->state = RC_LINKED;
821         create_peers (rc);
822       }
823       return;
824     default:
825       GNUNET_break (0);
826       GNUNET_SCHEDULER_shutdown ();
827       return;
828     }
829   }
830   if (GNUNET_TESTBED_ET_OPERATION_FINISHED != event->type)
831     goto call_cc;
832   if (NULL == (rcop = search_rcop (rc, event->op)))
833     goto call_cc;
834   remove_rcop (rc, rcop);
835   GNUNET_TESTBED_operation_done (rcop->op);
836   GNUNET_free (rcop);
837   if ( (GNUNET_NO == rc->shutdown)
838        && (NULL != event->details.operation_finished.emsg) )
839   {
840     LOG (GNUNET_ERROR_TYPE_ERROR, "A operation has failed with error: %s\n",
841          event->details.operation_finished.emsg);
842     GNUNET_SCHEDULER_shutdown ();
843     return;
844   }
845   GNUNET_assert (GNUNET_YES == rc->shutdown);
846   switch (rc->state)
847   {
848   case RC_LINKED:
849   case RC_PEERS_CREATED:
850   case RC_READY:
851     rc->state = RC_PEERS_SHUTDOWN;
852     GNUNET_free_non_null (rc->peers);
853     rc->peers = NULL;
854     DEBUG ("Peers shut down in %s\n", prof_time (rc));
855     GNUNET_SCHEDULER_shutdown ();
856     break;
857   default:
858     GNUNET_assert (0);
859   }
860   return;
861
862 call_cc:
863   if ((0 != (rc->event_mask & (1LL << event->type))) && (NULL != rc->cc))
864     rc->cc (rc->cc_cls, event);
865   if (GNUNET_TESTBED_ET_PEER_START != event->type)
866     return;
867   if (NULL == (rcop = search_rcop (rc, event->op))) /* Not our operation */
868     return;
869   remove_rcop (rc, rcop);
870   GNUNET_TESTBED_operation_done (rcop->op);
871   GNUNET_free (rcop);
872   rc->peer_count++;
873   if (rc->peer_count < rc->num_peers)
874     return;
875   DEBUG ("%u peers started in %s\n", rc->num_peers, prof_time (rc));
876   if (GNUNET_TESTBED_TOPOLOGY_NONE != rc->topology)
877   {
878     if ((GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI == rc->topology) ||
879         (GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD_RING == rc->topology) ||
880         (GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD == rc->topology))
881     {
882       rc->topology_operation =
883           GNUNET_TESTBED_overlay_configure_topology (NULL, rc->num_peers,
884                                                      rc->peers, &rc->num_oc,
885                                                      &topology_completion_callback,
886                                                      rc,
887                                                      rc->topology,
888                                                      rc->random_links,
889                                                      GNUNET_TESTBED_TOPOLOGY_OPTION_END);
890     }
891     else if (GNUNET_TESTBED_TOPOLOGY_FROM_FILE == rc->topology)
892     {
893       GNUNET_assert (NULL != rc->topo_file);
894       rc->topology_operation =
895           GNUNET_TESTBED_overlay_configure_topology (NULL, rc->num_peers,
896                                                      rc->peers, &rc->num_oc,
897                                                      &topology_completion_callback,
898                                                      rc,
899                                                      rc->topology,
900                                                      rc->topo_file,
901                                                      GNUNET_TESTBED_TOPOLOGY_OPTION_END);
902     }
903     else
904       rc->topology_operation =
905           GNUNET_TESTBED_overlay_configure_topology (NULL, rc->num_peers,
906                                                      rc->peers, &rc->num_oc,
907                                                      &topology_completion_callback,
908                                                      rc,
909                                                      rc->topology,
910                                                      GNUNET_TESTBED_TOPOLOGY_OPTION_END);
911     if (NULL == rc->topology_operation)
912       LOG (GNUNET_ERROR_TYPE_WARNING,
913            "Not generating topology. Check number of peers\n");
914     else
915     {
916       DEBUG ("Creating overlay topology\n");
917       rc->pstart_time = GNUNET_TIME_absolute_get ();
918       return;
919     }
920   }
921   rc->state = RC_READY;
922   call_master (rc);
923 }
924
925
926 /**
927  * Task to register all hosts available in the global host list
928  *
929  * @param cls the RunContext
930  * @param tc the scheduler task context
931  */
932 static void
933 register_hosts (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
934
935
936 /**
937  * Callback which will be called to after a host registration succeeded or failed
938  *
939  * @param cls the closure
940  * @param emsg the error message; NULL if host registration is successful
941  */
942 static void
943 host_registration_completion (void *cls, const char *emsg)
944 {
945   struct RunContext *rc = cls;
946
947   rc->reg_handle = NULL;
948   if (NULL != emsg)
949   {
950     LOG (GNUNET_ERROR_TYPE_WARNING,
951          _("Host registration failed for a host. Error: %s\n"), emsg);
952     GNUNET_SCHEDULER_shutdown ();
953     return;
954   }
955   rc->register_hosts_task = GNUNET_SCHEDULER_add_now (&register_hosts, rc);
956 }
957
958
959 /**
960  * Task to register all hosts available in the global host list
961  *
962  * @param cls RunContext
963  * @param tc the scheduler task context
964  */
965 static void
966 register_hosts (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
967 {
968   struct RunContext *rc = cls;
969   struct RunContextOperation *rcop;
970   unsigned int slave;
971
972   rc->register_hosts_task = GNUNET_SCHEDULER_NO_TASK;
973   if (rc->reg_hosts == rc->num_hosts)
974   {
975     DEBUG ("All hosts successfully registered\n");
976     /* Start slaves */
977     for (slave = 0; slave < rc->num_hosts; slave++)
978     {
979       rcop = GNUNET_malloc (sizeof (struct RunContextOperation));
980       rcop->rc = rc;
981       rcop->op =
982           GNUNET_TESTBED_controller_link (rcop, rc->c, rc->hosts[slave],
983                                           rc->h, GNUNET_YES);
984       GNUNET_assert (NULL != rcop->op);
985       insert_rcop (rc, rcop);
986     }
987     rc->reg_hosts = 0;
988     return;
989   }
990   rc->reg_handle =
991       GNUNET_TESTBED_register_host (rc->c, rc->hosts[rc->reg_hosts],
992                                     host_registration_completion, rc);
993   rc->reg_hosts++;
994 }
995
996
997 /**
998  * Callback to signal successfull startup of the controller process
999  *
1000  * @param cls the closure from GNUNET_TESTBED_controller_start()
1001  * @param cfg the configuration with which the controller has been started;
1002  *          NULL if status is not GNUNET_OK
1003  * @param status GNUNET_OK if the startup is successfull; GNUNET_SYSERR if not,
1004  *          GNUNET_TESTBED_controller_stop() shouldn't be called in this case
1005  */
1006 static void
1007 controller_status_cb (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg,
1008                       int status)
1009 {
1010   struct RunContext *rc = cls;
1011   uint64_t event_mask;
1012
1013   if (status != GNUNET_OK)
1014   {
1015     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1016                 _("Controller crash detected. Shutting down.\n"));
1017     GNUNET_SCHEDULER_shutdown ();
1018     return;
1019   }
1020   GNUNET_CONFIGURATION_destroy (rc->cfg);
1021   rc->cfg = GNUNET_CONFIGURATION_dup (cfg);
1022   event_mask = rc->event_mask;
1023   event_mask |= (1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED);
1024   event_mask |= (1LL << GNUNET_TESTBED_ET_PEER_START);
1025   if (rc->topology < GNUNET_TESTBED_TOPOLOGY_NONE)
1026     event_mask |= GNUNET_TESTBED_ET_CONNECT;
1027   rc->c =
1028       GNUNET_TESTBED_controller_connect (rc->h, event_mask, &event_cb, rc);
1029   if (0 < rc->num_hosts)
1030   {
1031     rc->reg_hosts = 0;
1032     rc->register_hosts_task = GNUNET_SCHEDULER_add_now (&register_hosts, rc);
1033     return;
1034   }
1035   rc->state = RC_LINKED;
1036   create_peers (rc);
1037 }
1038
1039
1040 /**
1041  * Callback function invoked for each interface found.
1042  *
1043  * @param cls closure
1044  * @param name name of the interface (can be NULL for unknown)
1045  * @param isDefault is this presumably the default interface
1046  * @param addr address of this interface (can be NULL for unknown or unassigned)
1047  * @param broadcast_addr the broadcast address (can be NULL for unknown or unassigned)
1048  * @param netmask the network mask (can be NULL for unknown or unassigned))
1049  * @param addrlen length of the address
1050  * @return GNUNET_OK to continue iteration, GNUNET_SYSERR to abort
1051  */
1052 static int
1053 netint_proc (void *cls, const char *name, int isDefault,
1054              const struct sockaddr *addr, const struct sockaddr *broadcast_addr,
1055              const struct sockaddr *netmask, socklen_t addrlen)
1056 {
1057   struct RunContext *rc = cls;
1058   char hostip[NI_MAXHOST];
1059   char *buf;
1060
1061   if (sizeof (struct sockaddr_in) != addrlen)
1062     return GNUNET_OK;           /* Only consider IPv4 for now */
1063   if (0 !=
1064       getnameinfo (addr, addrlen, hostip, NI_MAXHOST, NULL, 0, NI_NUMERICHOST))
1065     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "getnameinfo");
1066   if (NULL == rc->trusted_ip)
1067   {
1068     rc->trusted_ip = GNUNET_strdup (hostip);
1069     return GNUNET_YES;
1070   }
1071   (void) GNUNET_asprintf (&buf, "%s; %s", rc->trusted_ip, hostip);
1072   GNUNET_free (rc->trusted_ip);
1073   rc->trusted_ip = buf;
1074   return GNUNET_YES;
1075 }
1076
1077
1078 /**
1079  * Callbacks of this type are called by GNUNET_TESTBED_is_host_habitable to
1080  * inform whether the given host is habitable or not. The Handle returned by
1081  * GNUNET_TESTBED_is_host_habitable() is invalid after this callback is called
1082  *
1083  * @param cls NULL
1084  * @param host the host whose status is being reported; will be NULL if the host
1085  *          given to GNUNET_TESTBED_is_host_habitable() is NULL
1086  * @param status GNUNET_YES if it is habitable; GNUNET_NO if not
1087  */
1088 static void
1089 host_habitable_cb (void *cls, const struct GNUNET_TESTBED_Host *host,
1090                    int status)
1091 {
1092   struct CompatibilityCheckContext *hc = cls;
1093   struct RunContext *rc;
1094   struct GNUNET_TESTBED_Host **old_hosts;
1095   unsigned int nhost;
1096
1097   GNUNET_assert (NULL != (rc = hc->rc));
1098   nhost = hc->index;
1099   GNUNET_assert (nhost <= rc->num_hosts);
1100   GNUNET_assert (host == rc->hosts[nhost]);
1101   hc->h = NULL;
1102   if (GNUNET_NO == status)
1103   {
1104     if ((NULL != host) && (NULL != GNUNET_TESTBED_host_get_hostname (host)))
1105       LOG (GNUNET_ERROR_TYPE_ERROR, _("Host %s cannot start testbed\n"),
1106            GNUNET_TESTBED_host_get_hostname (host));
1107     else
1108       LOG (GNUNET_ERROR_TYPE_ERROR,
1109            _("Testbed cannot be started on localhost\n"));
1110     GNUNET_SCHEDULER_shutdown ();
1111     return;
1112   }
1113   rc->reg_hosts++;
1114   if (rc->reg_hosts < rc->num_hosts)
1115     return;
1116   GNUNET_free (rc->hclist);
1117   rc->hclist = NULL;
1118   rc->h = rc->hosts[0];
1119   rc->num_hosts--;
1120   if (0 < rc->num_hosts)
1121   {
1122     old_hosts = rc->hosts;
1123     rc->hosts =
1124         GNUNET_malloc (sizeof (struct GNUNET_TESTBED_Host *) * rc->num_hosts);
1125     memcpy (rc->hosts, &old_hosts[1],
1126             (sizeof (struct GNUNET_TESTBED_Host *) * rc->num_hosts));
1127     GNUNET_free (old_hosts);
1128   }
1129   else
1130   {
1131     GNUNET_free (rc->hosts);
1132     rc->hosts = NULL;
1133   }
1134   GNUNET_TESTBED_host_resolve_ (rc->h);
1135   for (nhost = 0; nhost < rc->num_hosts; nhost++)
1136     GNUNET_TESTBED_host_resolve_ (rc->hosts[nhost]);
1137   GNUNET_OS_network_interfaces_list (netint_proc, rc);
1138   if (NULL == rc->trusted_ip)
1139     rc->trusted_ip = GNUNET_strdup ("127.0.0.1");
1140   rc->cproc =
1141       GNUNET_TESTBED_controller_start (rc->trusted_ip, rc->h,
1142                                        &controller_status_cb, rc);
1143   GNUNET_free (rc->trusted_ip);
1144   rc->trusted_ip = NULL;
1145   if (NULL == rc->cproc)
1146   {
1147     LOG (GNUNET_ERROR_TYPE_ERROR, _("Cannot start the master controller"));
1148     GNUNET_SCHEDULER_shutdown ();
1149   }
1150 }
1151
1152
1153 /**
1154  * Task run upon timeout while setting up the testbed
1155  *
1156  * @param cls the RunContext
1157  * @param tc the task context
1158  */
1159 static void
1160 timeout_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1161 {
1162   struct RunContext *rc = cls;
1163   
1164   rc->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1165   LOG (GNUNET_ERROR_TYPE_ERROR, _("Shutting down testbed due to timeout while setup.\n"));
1166    GNUNET_SCHEDULER_shutdown ();
1167    if (NULL != rc->test_master)
1168      rc->test_master (rc->test_master_cls, 0, NULL, 0, 0);
1169    rc->test_master = NULL;
1170 }
1171
1172
1173 /**
1174  * Convenience method for running a testbed with
1175  * a single call.  Underlay and overlay topology
1176  * are configured using the "UNDERLAY" and "OVERLAY"
1177  * options in the "[testbed]" section of the configuration\
1178  * (with possible options given in "UNDERLAY_XXX" and/or
1179  * "OVERLAY_XXX").
1180  *
1181  * The testbed is to be terminated using a call to
1182  * "GNUNET_SCHEDULER_shutdown".
1183  *
1184  * @param host_filename name of the file with the 'hosts', NULL
1185  *        to run everything on 'localhost'
1186  * @param cfg configuration to use (for testbed, controller and peers)
1187  * @param num_peers number of peers to start; FIXME: maybe put that ALSO into cfg?
1188  * @param event_mask bit mask with set of events to call 'cc' for;
1189  *                   or-ed values of "1LL" shifted by the
1190  *                   respective 'enum GNUNET_TESTBED_EventType'
1191  *                   (i.e.  "(1LL << GNUNET_TESTBED_ET_CONNECT) || ...")
1192  * @param cc controller callback to invoke on events; This callback is called
1193  *          for all peer start events even if GNUNET_TESTBED_ET_PEER_START isn't
1194  *          set in the event_mask as this is the only way get access to the
1195  *          handle of each peer
1196  * @param cc_cls closure for cc
1197  * @param test_master this callback will be called once the test is ready
1198  * @param test_master_cls closure for 'test_master'.
1199  */
1200 void
1201 GNUNET_TESTBED_run (const char *host_filename,
1202                     const struct GNUNET_CONFIGURATION_Handle *cfg,
1203                     unsigned int num_peers, uint64_t event_mask,
1204                     GNUNET_TESTBED_ControllerCallback cc, void *cc_cls,
1205                     GNUNET_TESTBED_TestMaster test_master,
1206                     void *test_master_cls)
1207 {
1208   struct RunContext *rc;
1209   char *topology;
1210   struct CompatibilityCheckContext *hc;      
1211   struct GNUNET_TIME_Relative timeout;
1212   unsigned long long random_links;
1213   unsigned int hid;
1214   unsigned int nhost;
1215
1216   GNUNET_assert (num_peers > 0);
1217   rc = GNUNET_malloc (sizeof (struct RunContext));
1218   rc->cfg = GNUNET_CONFIGURATION_dup (cfg);
1219 #if ENABLE_LL
1220   rc->num_hosts = GNUNET_TESTBED_hosts_load_from_loadleveler (rc->cfg,
1221                                                               &rc->hosts);
1222   if (0 == rc->num_hosts)
1223   {
1224     LOG (GNUNET_ERROR_TYPE_WARNING,
1225            _("No hosts loaded from LoadLeveler. Need at least one host\n"));
1226     goto error_cleanup;
1227   }
1228 #else
1229   if (NULL != host_filename)
1230   {
1231     rc->num_hosts =
1232         GNUNET_TESTBED_hosts_load_from_file (host_filename, rc->cfg,
1233                                              &rc->hosts);
1234     if (0 == rc->num_hosts)
1235     {
1236       LOG (GNUNET_ERROR_TYPE_WARNING,
1237            _("No hosts loaded. Need at least one host\n"));
1238       goto error_cleanup;
1239     }
1240   }
1241   else
1242     rc->h = GNUNET_TESTBED_host_create (NULL, NULL, rc->cfg, 0);
1243 #endif
1244   rc->num_peers = num_peers;
1245   rc->event_mask = event_mask;
1246   rc->cc = cc;
1247   rc->cc_cls = cc_cls;
1248   rc->test_master = test_master;
1249   rc->test_master_cls = test_master_cls;
1250   rc->state = RC_INIT;
1251   rc->topology = GNUNET_TESTBED_TOPOLOGY_NONE;
1252   if (GNUNET_OK ==
1253       GNUNET_CONFIGURATION_get_value_string (rc->cfg, "testbed",
1254                                              "OVERLAY_TOPOLOGY", &topology))
1255   {
1256     if (GNUNET_NO == GNUNET_TESTBED_topology_get_ (&rc->topology, topology))
1257     {
1258       GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, "testbed",
1259                                  "OVERLAY_TOPLOGY",
1260                                  _
1261                                  ("Specified topology must be supported by testbed"));
1262     }
1263     GNUNET_free (topology);
1264   }
1265   switch (rc->topology)
1266   {
1267   case GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI:
1268   case GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD_RING:
1269   case GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD:
1270     if (GNUNET_OK !=
1271         GNUNET_CONFIGURATION_get_value_number (rc->cfg, "testbed",
1272                                                "OVERLAY_RANDOM_LINKS",
1273                                                &random_links))
1274     {
1275       /* OVERLAY option RANDOM & SMALL_WORLD_RING requires OVERLAY_RANDOM_LINKS
1276        * option to be set to the number of random links to be established  */
1277       GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "testbed",
1278                                  "OVERLAY_RANDOM_LINKS");
1279       goto error_cleanup;
1280     }
1281     if (random_links > UINT32_MAX)
1282     {
1283       GNUNET_break (0);         /* Too big number */
1284       goto error_cleanup;
1285     }
1286     rc->random_links = (unsigned int) random_links;
1287     break;
1288   case GNUNET_TESTBED_TOPOLOGY_FROM_FILE:
1289     if (GNUNET_OK !=
1290         GNUNET_CONFIGURATION_get_value_string (rc->cfg, "testbed",
1291                                                "OVERLAY_TOPOLOGY_FILE",
1292                                                &rc->topo_file))
1293     {
1294       GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "testbed",
1295                                  "OVERLAY_TOPOLOGY_FILE");
1296       goto error_cleanup;
1297     }
1298     break;
1299   default:
1300     /* Warn if OVERLAY_RANDOM_LINKS is present that it will be ignored */
1301     if (GNUNET_YES ==
1302         GNUNET_CONFIGURATION_have_value (rc->cfg, "testbed",
1303                                          "OVERLAY_RANDOM_LINKS"))
1304       LOG (GNUNET_ERROR_TYPE_WARNING,
1305            "Ignoring value of `OVERLAY_RANDOM_LINKS' in given configuration\n");
1306     break;
1307   }
1308   if (0 != rc->num_hosts)
1309   {
1310     rc->hclist = GNUNET_malloc (sizeof (struct CompatibilityCheckContext)
1311                                 * rc->num_hosts);
1312     for (nhost = 0; nhost < rc->num_hosts; nhost++)
1313     {
1314       hc = &rc->hclist[nhost];
1315       hc->index = nhost;
1316       hc->rc = rc;
1317       hc->h = GNUNET_TESTBED_is_host_habitable (rc->hosts[nhost], rc->cfg,
1318                                                 &host_habitable_cb, hc);
1319       if (NULL == hc->h)
1320       {
1321         GNUNET_break (0);
1322         for (nhost = 0; nhost < rc->num_hosts; nhost++)
1323         {
1324           hc = &rc->hclist[nhost];
1325           if (NULL != hc->h)
1326             GNUNET_TESTBED_is_host_habitable_cancel (hc->h);
1327         }
1328         GNUNET_free (rc->hclist);
1329         rc->hclist = NULL;
1330         goto error_cleanup;
1331       }
1332     }
1333   }
1334   else
1335     rc->cproc =
1336         GNUNET_TESTBED_controller_start ("127.0.0.1", rc->h,
1337                                          &controller_status_cb, rc);
1338   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (cfg, "TESTBED",
1339                                                         "SETUP_TIMEOUT",
1340                                                         &timeout))
1341   {
1342     timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
1343                                              DEFAULT_SETUP_TIMEOUT);
1344   }
1345   rc->rcop_map = GNUNET_CONTAINER_multihashmap32_create (256);
1346   rc->timeout_task =
1347       GNUNET_SCHEDULER_add_delayed (timeout, &timeout_task, rc);
1348   rc->interrupt_task =
1349       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &interrupt,
1350                                     rc);
1351   return;
1352
1353 error_cleanup:
1354   if (NULL != rc->h)
1355     GNUNET_TESTBED_host_destroy (rc->h);
1356   if (NULL != rc->hosts)
1357   {
1358     for (hid = 0; hid < rc->num_hosts; hid++)
1359       if (NULL != rc->hosts[hid])
1360         GNUNET_TESTBED_host_destroy (rc->hosts[hid]);
1361     GNUNET_free (rc->hosts);
1362   }
1363   if (NULL != rc->cfg)
1364     GNUNET_CONFIGURATION_destroy (rc->cfg);
1365   GNUNET_free (rc);
1366 }
1367
1368
1369 /* end of testbed_api_testbed.c */