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