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