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