914523780e3c7af8f8e76fc3ef463f61fa4a9d65
[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
31 /**
32  * Generic loggins shorthand
33  */
34 #define LOG(kind,...)                                   \
35   GNUNET_log_from (kind, "testbed-api-testbed", __VA_ARGS__)
36
37 /**
38  * Opaque handle to an abstract operation to be executed by the testing framework.
39  */
40 struct GNUNET_TESTBED_Testbed
41 {
42   // FIXME!
43 };
44
45
46 /**
47  * DLL of operations
48  */
49 struct DLLOperation
50 {
51   /**
52    * The testbed operation handle
53    */
54   struct GNUNET_TESTBED_Operation *op;
55
56   /**
57    * Context information for GNUNET_TESTBED_run()
58    */
59   struct RunContext *rc;
60
61   /**
62    * Closure
63    */
64   void *cls;  
65   
66   /**
67    * The next pointer for DLL
68    */
69   struct DLLOperation *next;
70   
71   /**
72    * The prev pointer for DLL
73    */
74   struct DLLOperation *prev;
75 };
76
77
78 /**
79  * States of RunContext
80  */
81 enum State 
82 {
83   /**
84    * Initial state
85    */
86   RC_INIT = 0,
87   
88   /**
89    * Peers have been started
90    */
91   RC_PEERS_STARTED,
92
93   /**
94    * Peers are stopped
95    */
96   RC_PEERS_STOPPED,
97   
98   /**
99    * Peers are destroyed
100    */
101   RC_PEERS_DESTROYED
102
103 };
104
105
106 /**
107  * Testbed Run Handle
108  */
109 struct RunContext
110 {
111   /**
112    * The controller handle
113    */
114   struct GNUNET_TESTBED_Controller *c;
115
116   /**
117    * Handle to the host on which the controller runs
118    */
119   struct GNUNET_TESTBED_Host *h;
120
121   /**
122    * The handle to the controller process
123    */
124   struct GNUNET_TESTBED_ControllerProc *cproc;
125
126   /**
127    * The callback to use as controller callback
128    */
129   GNUNET_TESTBED_ControllerCallback cc;
130   
131   /**
132    * The pointer to the controller callback
133    */
134   void *cc_cls;
135   
136   /**
137    * Master task to call when testbed initialization is done
138    */
139   GNUNET_SCHEDULER_Task master;
140   
141   /**
142    * The closure for the master task
143    */
144   void *master_cls;
145
146   /**
147    * The head element of DLL operations
148    */
149   struct DLLOperation *dll_op_head;
150   
151   /**
152    * The tail element of DLL operations
153    */
154   struct DLLOperation *dll_op_tail;
155
156   /**
157    * Array of peers which we create
158    */
159   struct GNUNET_TESTBED_Peer **peers;
160   
161   /**
162    * The event mask for the controller
163    */
164   uint64_t event_mask;
165
166   /**
167    * State of this context
168    */
169   enum State state;
170
171   /**
172    * Current peer count for an operation; Set this to 0 and increment for each
173    * successful operation on a peer
174    */
175   unsigned int peer_count;
176   
177   /**
178    * number of peers to start
179    */
180   unsigned int num_peers;
181
182 };
183
184
185
186
187 /**
188  * Configure and run a testbed using the given
189  * master controller on 'num_hosts' starting
190  * 'num_peers' using the given peer configuration.
191  *
192  * @param controller master controller for the testbed
193  *                   (must not be destroyed until after the
194  *                    testbed is destroyed).
195  * @param num_hosts number of hosts in 'hosts', 0 to only
196  *        use 'localhost'
197  * @param hosts list of hosts to use for the testbed
198  * @param num_peers number of peers to start
199  * @param peer_cfg peer configuration template to use
200  * @param underlay_topology underlay topology to create
201  * @param va topology-specific options
202  * @return handle to the testbed
203  */
204 struct GNUNET_TESTBED_Testbed *
205 GNUNET_TESTBED_create_va (struct GNUNET_TESTBED_Controller *controller,
206                                   unsigned int num_hosts,
207                                   struct GNUNET_TESTBED_Host **hosts,
208                                   unsigned int num_peers,
209                                   const struct GNUNET_CONFIGURATION_Handle *peer_cfg,
210                                   enum GNUNET_TESTBED_TopologyOption underlay_topology,
211                                   va_list va)
212 {
213   GNUNET_break (0);
214   return NULL;
215 }
216
217
218 /**
219  * Configure and run a testbed using the given
220  * master controller on 'num_hosts' starting
221  * 'num_peers' using the given peer configuration.
222  *
223  * @param controller master controller for the testbed
224  *                   (must not be destroyed until after the
225  *                    testbed is destroyed).
226  * @param num_hosts number of hosts in 'hosts', 0 to only
227  *        use 'localhost'
228  * @param hosts list of hosts to use for the testbed
229  * @param num_peers number of peers to start
230  * @param peer_cfg peer configuration template to use
231  * @param underlay_topology underlay topology to create
232  * @param ... topology-specific options
233  */
234 struct GNUNET_TESTBED_Testbed *
235 GNUNET_TESTBED_create (struct GNUNET_TESTBED_Controller *controller,
236                        unsigned int num_hosts,
237                        struct GNUNET_TESTBED_Host **hosts,
238                        unsigned int num_peers,
239                        const struct GNUNET_CONFIGURATION_Handle *peer_cfg,
240                        enum GNUNET_TESTBED_TopologyOption underlay_topology,
241                        ...)
242 {
243   GNUNET_break (0);
244   return NULL;
245 }
246
247
248 /**
249  * Destroy a testbed.  Stops all running peers and then
250  * destroys all peers.  Does NOT destroy the master controller.
251  *
252  * @param testbed testbed to destroy
253  */
254 void
255 GNUNET_TESTBED_destroy (struct GNUNET_TESTBED_Testbed *testbed)
256 {
257   GNUNET_break (0);
258 }
259
260
261 /**
262  * Task for starting peers
263  *
264  * @param cls the RunHandle
265  * @param tc the task context from scheduler
266  */
267 static void
268 start_peers_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
269 {
270   struct RunContext *rc = cls;
271   struct DLLOperation *dll_op;  
272   unsigned int peer;
273   
274   LOG (GNUNET_ERROR_TYPE_DEBUG, "Starting Peers\n");  
275   for (peer = 0; peer < rc->num_peers; peer++)
276   {
277     dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
278     dll_op->op = GNUNET_TESTBED_peer_start (rc->peers[peer]);
279     dll_op->cls = rc->peers[peer];    
280     GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail, dll_op);
281   }
282   rc->peer_count = 0;  
283 }
284
285
286 /**
287  * Functions of this signature are called when a peer has been successfully
288  * created
289  *
290  * @param cls the closure from GNUNET_TESTBED_peer_create()
291  * @param peer the handle for the created peer; NULL on any error during
292  *          creation
293  * @param emsg NULL if peer is not NULL; else MAY contain the error description
294  */
295 static void 
296 peer_create_cb (void *cls, struct GNUNET_TESTBED_Peer *peer, const char *emsg)
297
298   struct DLLOperation *dll_op = cls;
299   struct RunContext *rc;
300   
301   GNUNET_assert (NULL != dll_op);  
302   rc = dll_op->rc;
303   GNUNET_assert (NULL != rc);
304   GNUNET_CONTAINER_DLL_remove (rc->dll_op_head, rc->dll_op_tail, dll_op);
305   GNUNET_TESTBED_operation_done (dll_op->op); 
306   GNUNET_free (dll_op);
307   if (NULL == peer)
308   {
309     if (NULL != emsg)
310       LOG (GNUNET_ERROR_TYPE_WARNING, "Error while creating a peer: %s\n",
311            emsg);
312     /* FIXME: GNUNET_TESTBED_shutdown_run()? */
313     return;
314   }
315   rc->peers[rc->peer_count] = peer;
316   rc->peer_count++;
317   if (rc->peer_count < rc->num_peers)
318     return;
319   LOG (GNUNET_ERROR_TYPE_DEBUG, "Required peers created successfully\n");  
320   GNUNET_SCHEDULER_add_now (&start_peers_task, rc);
321 }
322
323
324 /**
325  * Assuming all peers have been destroyed cleanup run handle
326  *
327  * @param cls the run handle
328  * @param tc the task context from scheduler
329  */
330 static void
331 cleanup_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
332 {
333   struct RunContext *rc = cls;
334   struct DLLOperation *dll_op;  
335   
336   GNUNET_assert (NULL == rc->peers);
337   GNUNET_assert (RC_PEERS_DESTROYED == rc->state);
338   if (NULL != rc->c)
339     GNUNET_TESTBED_controller_disconnect (rc->c);
340   if (NULL != rc->cproc)
341     GNUNET_TESTBED_controller_stop (rc->cproc);
342   if (NULL != rc->h)
343     GNUNET_TESTBED_host_destroy (rc->h);
344   if (NULL != rc->dll_op_head)
345   {
346     LOG (GNUNET_ERROR_TYPE_WARNING,
347          _("Some operations are still pending. Cancelling them\n"));
348     while (NULL != (dll_op = rc->dll_op_head))
349     {
350       GNUNET_TESTBED_operation_cancel (dll_op->op);
351       GNUNET_CONTAINER_DLL_remove (rc->dll_op_head, rc->dll_op_tail, dll_op);
352       GNUNET_free (dll_op);
353     }
354   }
355   GNUNET_free (rc);
356 }
357
358
359 /**
360  * Signature of the event handler function called by the
361  * respective event controller.
362  *
363  * @param cls closure
364  * @param event information about the event
365  */
366 static void 
367 event_cb (void *cls, const struct GNUNET_TESTBED_EventInformation *event)
368 {
369   struct RunContext *rc = cls;
370   struct DLLOperation *dll_op;
371   unsigned int peer_id;
372   
373
374   if ((RC_INIT != rc->state) && 
375       ((GNUNET_TESTBED_ET_OPERATION_FINISHED == event->type)||
376        (GNUNET_TESTBED_ET_PEER_STOP == event->type)))
377   {
378     for (dll_op = rc->dll_op_head; NULL != dll_op; dll_op = dll_op->next)
379     {
380       if ((GNUNET_TESTBED_ET_OPERATION_FINISHED == event->type) && 
381           (event->details.operation_finished.operation == dll_op->op))
382         break;
383       if ((GNUNET_TESTBED_ET_PEER_STOP == event->type) &&
384           (event->details.peer_stop.peer == dll_op->cls))
385         break;
386     }
387     if (NULL == dll_op)
388       goto call_cc;
389     GNUNET_CONTAINER_DLL_remove (rc->dll_op_head, rc->dll_op_tail, dll_op);
390     GNUNET_TESTBED_operation_done (dll_op->op);
391     GNUNET_free (dll_op);
392     rc->peer_count++;
393     if (rc->peer_count < rc->num_peers)
394       return;
395     switch (rc->state)
396     {
397     case RC_PEERS_STARTED:
398       rc->state = RC_PEERS_STOPPED;
399       rc->peer_count = 0;
400       for (peer_id = 0; peer_id < rc->num_peers; peer_id++)
401       {
402         dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
403         dll_op->op = GNUNET_TESTBED_peer_destroy (rc->peers[peer_id]);
404         GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail,
405                                           dll_op);
406       }
407       break;
408     case RC_PEERS_STOPPED:
409       rc->state = RC_PEERS_DESTROYED;
410       GNUNET_free (rc->peers);
411       rc->peers = NULL;
412       LOG (GNUNET_ERROR_TYPE_DEBUG, "All peers successfully destroyed\n");
413       GNUNET_SCHEDULER_add_now (&cleanup_task, rc);
414       break;
415     default:
416       GNUNET_assert (0);
417     }
418     return;
419   }
420
421  call_cc:
422   rc->cc (rc->cc_cls, event);
423   if (GNUNET_TESTBED_ET_PEER_START != event->type)
424     return;
425   for (dll_op = rc->dll_op_head; NULL != dll_op; dll_op = dll_op->next)
426     if ((NULL != dll_op->cls) && 
427         (event->details.peer_start.peer == dll_op->cls))
428       break;
429   GNUNET_assert (NULL != dll_op);
430   GNUNET_CONTAINER_DLL_remove (rc->dll_op_head, rc->dll_op_tail, dll_op);
431   GNUNET_TESTBED_operation_done (dll_op->op);
432   GNUNET_free (dll_op);
433   rc->peer_count++;
434   if (rc->peer_count < rc->num_peers)
435     return;
436   LOG (GNUNET_ERROR_TYPE_DEBUG, "Peers started successfully\n");
437   rc->state = RC_PEERS_STARTED;
438   GNUNET_SCHEDULER_add_continuation (rc->master, rc->master_cls,
439                                      GNUNET_SCHEDULER_REASON_PREREQ_DONE);  
440 }
441
442
443
444 /**
445  * Callback to signal successfull startup of the controller process
446  *
447  * @param cls the closure from GNUNET_TESTBED_controller_start()
448  * @param cfg the configuration with which the controller has been started;
449  *          NULL if status is not GNUNET_OK
450  * @param status GNUNET_OK if the startup is successfull; GNUNET_SYSERR if not,
451  *          GNUNET_TESTBED_controller_stop() shouldn't be called in this case
452  */
453 static void 
454 controller_status_cb (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg,
455                       int status)
456 {  
457   struct RunContext *rc = cls;
458   struct DLLOperation *dll_op;
459   unsigned int peer;
460   
461   if (status != GNUNET_OK)
462   {
463     GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Testbed startup failed\n");
464     return;
465   }
466   rc->c = GNUNET_TESTBED_controller_connect (cfg, rc->h, rc->event_mask,
467                                              &event_cb, rc);
468   rc->peers = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_Peer *)
469                              * rc->num_peers);
470   GNUNET_assert (NULL != rc->c);
471   rc->peer_count = 0; 
472   for (peer = 0; peer < rc->num_peers; peer++)
473   {
474     dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
475     dll_op->rc = rc;    
476     dll_op->op = GNUNET_TESTBED_peer_create (rc->c, rc->h, cfg, peer_create_cb,
477                                              dll_op);
478     GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail, dll_op);    
479   }
480 }
481
482
483 /**
484  * Stops the testbed run and releases any used resources
485  *
486  * @param rc the tesbed run handle
487  * @param tc the task context from scheduler
488  */
489 void
490 shutdown_run_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
491 {  
492   struct RunContext *rc = cls;
493   struct DLLOperation *dll_op;
494   unsigned int peer;
495   
496   if (NULL != rc->c)
497   {
498     if (NULL != rc->peers)
499     {
500       rc->peer_count = 0;
501       for (peer = 0; peer < rc->num_peers; peer++)
502       {
503         dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
504         dll_op->op = GNUNET_TESTBED_peer_stop (rc->peers[peer]);
505         dll_op->cls = rc->peers[peer];
506         GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail,
507                                           dll_op);
508       }
509       return;
510     }
511   }
512   rc->state = RC_PEERS_DESTROYED; /* No peers are present so we consider the
513                                      state where all peers are destroyed  */
514   GNUNET_SCHEDULER_add_now (&cleanup_task, rc);
515 }
516
517
518 /**
519  * Convenience method for running a testbed with
520  * a single call.  Underlay and overlay topology
521  * are configured using the "UNDERLAY" and "OVERLAY"
522  * options in the "[testbed]" section of the configuration\
523  * (with possible options given in "UNDERLAY_XXX" and/or
524  * "OVERLAY_XXX").
525  *
526  * The testbed is to be terminated using a call to
527  * "GNUNET_SCHEDULER_shutdown".
528  *
529  * @param host_filename name of the file with the 'hosts', NULL
530  *        to run everything on 'localhost'
531  * @param cfg configuration to use (for testbed, controller and peers)
532  * @param num_peers number of peers to start; FIXME: maybe put that ALSO into cfg?
533  * @param event_mask bit mask with set of events to call 'cc' for;
534  *                   or-ed values of "1LL" shifted by the
535  *                   respective 'enum GNUNET_TESTBED_EventType'
536  *                   (i.e.  "(1LL << GNUNET_TESTBED_ET_CONNECT) || ...")
537  * @param cc controller callback to invoke on events
538  * @param cc_cls closure for cc
539  * @param master task to run once the testbed is ready
540  */
541 void
542 GNUNET_TESTBED_run (const char *host_filename,
543                     const struct GNUNET_CONFIGURATION_Handle *cfg,
544                     unsigned int num_peers,
545                     uint64_t event_mask,
546                     GNUNET_TESTBED_ControllerCallback cc,
547                     void *cc_cls,
548                     GNUNET_SCHEDULER_Task master,
549                     void *master_cls)
550 {
551   struct RunContext *rc;
552
553   event_mask |= (1LL << GNUNET_TESTBED_ET_PEER_START);  
554   rc = GNUNET_malloc (sizeof (struct RunContext));
555   GNUNET_break (NULL == host_filename); /* Currently we do not support host
556                                            files */
557   host_filename = NULL;
558   rc->h = GNUNET_TESTBED_host_create (NULL, NULL, 0);
559   GNUNET_assert (NULL != rc->h);
560   rc->cproc = GNUNET_TESTBED_controller_start ("127.0.0.1", rc->h, cfg,
561                                                &controller_status_cb, rc);
562   GNUNET_assert (NULL != rc->cproc);
563   rc->num_peers = num_peers;
564   rc->event_mask = event_mask;
565   rc->cc = cc;
566   rc->cc_cls = cc_cls;
567   rc->master = master;
568   rc->master_cls = master_cls;
569   rc->state = RC_INIT;
570   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
571                                 &shutdown_run_task, rc);
572 }
573
574 /* end of testbed_api_testbed.c */