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