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