fixes
[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
32 /**
33  * Generic loggins shorthand
34  */
35 #define LOG(kind,...)                                           \
36   GNUNET_log_from (kind, "testbed-api-testbed", __VA_ARGS__)
37
38 /**
39  * Opaque handle to an abstract operation to be executed by the testing framework.
40  */
41 struct GNUNET_TESTBED_Testbed
42 {
43   // FIXME!
44 };
45
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    * Peers have been started
91    */
92   RC_PEERS_STARTED,
93
94   /**
95    * Peers are stopped
96    */
97   RC_PEERS_STOPPED,
98
99   /**
100    * Peers are destroyed
101    */
102   RC_PEERS_DESTROYED
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  * Task for starting peers
187  *
188  * @param cls the RunHandle
189  * @param tc the task context from scheduler
190  */
191 static void
192 start_peers_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
193 {
194   struct RunContext *rc = cls;
195   struct DLLOperation *dll_op;
196   unsigned int peer;
197
198   LOG (GNUNET_ERROR_TYPE_DEBUG, "Starting Peers\n");
199   for (peer = 0; peer < rc->num_peers; peer++)
200   {
201     dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
202     dll_op->op = GNUNET_TESTBED_peer_start (rc->peers[peer], NULL, NULL);
203     dll_op->cls = rc->peers[peer];
204     GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail, dll_op);
205   }
206   rc->peer_count = 0;
207 }
208
209
210 /**
211  * Functions of this signature are called when a peer has been successfully
212  * created
213  *
214  * @param cls the closure from GNUNET_TESTBED_peer_create()
215  * @param peer the handle for the created peer; NULL on any error during
216  *          creation
217  * @param emsg NULL if peer is not NULL; else MAY contain the error description
218  */
219 static void
220 peer_create_cb (void *cls, struct GNUNET_TESTBED_Peer *peer, const char *emsg)
221 {
222   struct DLLOperation *dll_op = cls;
223   struct RunContext *rc;
224
225   GNUNET_assert (NULL != dll_op);
226   rc = dll_op->rc;
227   GNUNET_assert (NULL != rc);
228   GNUNET_CONTAINER_DLL_remove (rc->dll_op_head, rc->dll_op_tail, dll_op);
229   GNUNET_TESTBED_operation_done (dll_op->op);
230   GNUNET_free (dll_op);
231   if (NULL == peer)
232   {
233     if (NULL != emsg)
234       LOG (GNUNET_ERROR_TYPE_WARNING, "Error while creating a peer: %s\n",
235            emsg);
236     /* FIXME: GNUNET_TESTBED_shutdown_run()? */
237     return;
238   }
239   rc->peers[rc->peer_count] = peer;
240   rc->peer_count++;
241   if (rc->peer_count < rc->num_peers)
242     return;
243   LOG (GNUNET_ERROR_TYPE_DEBUG, "Required peers created successfully\n");
244   GNUNET_SCHEDULER_add_now (&start_peers_task, rc);
245 }
246
247
248 /**
249  * Assuming all peers have been destroyed cleanup run handle
250  *
251  * @param cls the run handle
252  * @param tc the task context from scheduler
253  */
254 static void
255 cleanup_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
256 {
257   struct RunContext *rc = cls;
258   struct DLLOperation *dll_op;
259
260   GNUNET_assert (NULL == rc->peers);
261   GNUNET_assert (RC_PEERS_DESTROYED == rc->state);
262   if (NULL != rc->c)
263     GNUNET_TESTBED_controller_disconnect (rc->c);
264   if (NULL != rc->cproc)
265     GNUNET_TESTBED_controller_stop (rc->cproc);
266   if (NULL != rc->h)
267     GNUNET_TESTBED_host_destroy (rc->h);
268   if (NULL != rc->dll_op_head)
269   {
270     LOG (GNUNET_ERROR_TYPE_WARNING,
271          _("Some operations are still pending. Cancelling them\n"));
272     while (NULL != (dll_op = rc->dll_op_head))
273     {
274       GNUNET_TESTBED_operation_cancel (dll_op->op);
275       GNUNET_CONTAINER_DLL_remove (rc->dll_op_head, rc->dll_op_tail, dll_op);
276       GNUNET_free (dll_op);
277     }
278   }
279   GNUNET_free (rc);
280 }
281
282
283 /**
284  * Signature of the event handler function called by the
285  * respective event controller.
286  *
287  * @param cls closure
288  * @param event information about the event
289  */
290 static void
291 event_cb (void *cls, const struct GNUNET_TESTBED_EventInformation *event)
292 {
293   struct RunContext *rc = cls;
294   struct DLLOperation *dll_op;
295   unsigned int peer_id;
296
297
298   if ((RC_INIT != rc->state) &&
299       ((GNUNET_TESTBED_ET_OPERATION_FINISHED == event->type) ||
300        (GNUNET_TESTBED_ET_PEER_STOP == event->type)))
301   {
302     for (dll_op = rc->dll_op_head; NULL != dll_op; dll_op = dll_op->next)
303     {
304       if ((GNUNET_TESTBED_ET_OPERATION_FINISHED == event->type) &&
305           (event->details.operation_finished.operation == dll_op->op))
306         break;
307       if ((GNUNET_TESTBED_ET_PEER_STOP == event->type) &&
308           (event->details.peer_stop.peer == dll_op->cls))
309         break;
310     }
311     if (NULL == dll_op)
312       goto call_cc;
313     GNUNET_CONTAINER_DLL_remove (rc->dll_op_head, rc->dll_op_tail, dll_op);
314     GNUNET_TESTBED_operation_done (dll_op->op);
315     GNUNET_free (dll_op);
316     rc->peer_count++;
317     if (rc->peer_count < rc->num_peers)
318       return;
319     switch (rc->state)
320     {
321     case RC_PEERS_STARTED:
322       rc->state = RC_PEERS_STOPPED;
323       rc->peer_count = 0;
324       for (peer_id = 0; peer_id < rc->num_peers; peer_id++)
325       {
326         dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
327         dll_op->op = GNUNET_TESTBED_peer_destroy (rc->peers[peer_id]);
328         GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail,
329                                           dll_op);
330       }
331       break;
332     case RC_PEERS_STOPPED:
333       rc->state = RC_PEERS_DESTROYED;
334       GNUNET_free (rc->peers);
335       rc->peers = NULL;
336       LOG (GNUNET_ERROR_TYPE_DEBUG, "All peers successfully destroyed\n");
337       GNUNET_SCHEDULER_add_now (&cleanup_task, rc);
338       break;
339     default:
340       GNUNET_assert (0);
341     }
342     return;
343   }
344
345 call_cc:
346   if ((0 != (rc->event_mask && (1LL << event->type))) && (NULL != rc->cc))
347     rc->cc (rc->cc_cls, event);
348   if (GNUNET_TESTBED_ET_PEER_START != event->type)
349     return;
350   for (dll_op = rc->dll_op_head; NULL != dll_op; dll_op = dll_op->next)
351     if ((NULL != dll_op->cls) &&
352         (event->details.peer_start.peer == dll_op->cls))
353       break;
354   GNUNET_assert (NULL != dll_op);
355   GNUNET_CONTAINER_DLL_remove (rc->dll_op_head, rc->dll_op_tail, dll_op);
356   GNUNET_TESTBED_operation_done (dll_op->op);
357   GNUNET_free (dll_op);
358   rc->peer_count++;
359   if (rc->peer_count < rc->num_peers)
360     return;
361   LOG (GNUNET_ERROR_TYPE_DEBUG, "Peers started successfully\n");
362   rc->state = RC_PEERS_STARTED;
363   if (NULL != rc->master)
364     GNUNET_SCHEDULER_add_continuation (rc->master, rc->master_cls,
365                                        GNUNET_SCHEDULER_REASON_PREREQ_DONE);
366 }
367
368
369
370 /**
371  * Callback to signal successfull startup of the controller process
372  *
373  * @param cls the closure from GNUNET_TESTBED_controller_start()
374  * @param cfg the configuration with which the controller has been started;
375  *          NULL if status is not GNUNET_OK
376  * @param status GNUNET_OK if the startup is successfull; GNUNET_SYSERR if not,
377  *          GNUNET_TESTBED_controller_stop() shouldn't be called in this case
378  */
379 static void
380 controller_status_cb (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg,
381                       int status)
382 {
383   struct RunContext *rc = cls;
384   struct DLLOperation *dll_op;
385   uint64_t event_mask;
386   unsigned int peer;
387
388   if (status != GNUNET_OK)
389   {
390     GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Testbed startup failed\n");
391     return;
392   }
393   event_mask = rc->event_mask;
394   event_mask |= (1LL << GNUNET_TESTBED_ET_PEER_STOP);
395   event_mask |= (1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED);
396   rc->c =
397       GNUNET_TESTBED_controller_connect (cfg, rc->h, event_mask, &event_cb, rc);
398   rc->peers =
399       GNUNET_malloc (sizeof (struct GNUNET_TESTBED_Peer *) * rc->num_peers);
400   GNUNET_assert (NULL != rc->c);
401   rc->peer_count = 0;
402   for (peer = 0; peer < rc->num_peers; peer++)
403   {
404     dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
405     dll_op->rc = rc;
406     dll_op->op =
407         GNUNET_TESTBED_peer_create (rc->c, rc->h, cfg, peer_create_cb, dll_op);
408     GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail, dll_op);
409   }
410 }
411
412
413 /**
414  * Stops the testbed run and releases any used resources
415  *
416  * @param cls the tesbed run handle
417  * @param tc the task context from scheduler
418  */
419 void
420 shutdown_run_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
421 {
422   struct RunContext *rc = cls;
423   struct DLLOperation *dll_op;
424   unsigned int peer;
425
426   if (NULL != rc->c)
427   {
428     if (NULL != rc->peers)
429     {
430       rc->peer_count = 0;
431       /* Check if some peers are stopped */
432       for (peer = 0; peer < rc->num_peers; peer++)
433       {
434         if (PS_STOPPED != rc->peers[peer]->state)
435           break;
436       }
437       if (peer == rc->num_peers)
438       {
439         /* All peers are stopped */
440         rc->state = RC_PEERS_STOPPED;
441         for (peer = 0; peer < rc->num_peers; peer++)
442         {
443           dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
444           dll_op->op = GNUNET_TESTBED_peer_destroy (rc->peers[peer]);
445           GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail,
446                                             dll_op);
447         }
448         return;
449       }
450       /* Some peers are stopped */
451       for (peer = 0; peer < rc->num_peers; peer++)
452       {
453         if (PS_STARTED != rc->peers[peer]->state)
454         {
455           rc->peer_count++;
456           continue;
457         }
458         dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
459         dll_op->op = GNUNET_TESTBED_peer_stop (rc->peers[peer], NULL, NULL);
460         dll_op->cls = rc->peers[peer];
461         GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail,
462                                           dll_op);
463       }
464       if (rc->peer_count != rc->num_peers)
465         return;
466     }
467   }
468   rc->state = RC_PEERS_DESTROYED;       /* No peers are present so we consider the
469                                          * state where all peers are destroyed  */
470   GNUNET_SCHEDULER_add_now (&cleanup_task, rc);
471 }
472
473
474 /**
475  * Convenience method for running a testbed with
476  * a single call.  Underlay and overlay topology
477  * are configured using the "UNDERLAY" and "OVERLAY"
478  * options in the "[testbed]" section of the configuration\
479  * (with possible options given in "UNDERLAY_XXX" and/or
480  * "OVERLAY_XXX").
481  *
482  * The testbed is to be terminated using a call to
483  * "GNUNET_SCHEDULER_shutdown".
484  *
485  * @param host_filename name of the file with the 'hosts', NULL
486  *        to run everything on 'localhost'
487  * @param cfg configuration to use (for testbed, controller and peers)
488  * @param num_peers number of peers to start; FIXME: maybe put that ALSO into cfg?
489  * @param event_mask bit mask with set of events to call 'cc' for;
490  *                   or-ed values of "1LL" shifted by the
491  *                   respective 'enum GNUNET_TESTBED_EventType'
492  *                   (i.e.  "(1LL << GNUNET_TESTBED_ET_CONNECT) || ...")
493  * @param cc controller callback to invoke on events; This callback is called
494  *          for all peer start events even if GNUNET_TESTBED_ET_PEER_START isn't
495  *          set in the event_mask as this is the only way get access to the
496  *          handle of each peer
497  * @param cc_cls closure for cc
498  * @param master task to run once the testbed is ready
499  * @param master_cls
500  */
501 void
502 GNUNET_TESTBED_run (const char *host_filename,
503                     const struct GNUNET_CONFIGURATION_Handle *cfg,
504                     unsigned int num_peers, uint64_t event_mask,
505                     GNUNET_TESTBED_ControllerCallback cc, void *cc_cls,
506                     GNUNET_SCHEDULER_Task master, void *master_cls)
507 {
508   struct RunContext *rc;
509
510   GNUNET_break (NULL == host_filename); /* Currently we do not support host
511                                          * files */
512   GNUNET_assert (NULL != cc);
513   GNUNET_assert (num_peers > 0);
514   host_filename = NULL;
515   rc = GNUNET_malloc (sizeof (struct RunContext));
516   rc->h = GNUNET_TESTBED_host_create (NULL, NULL, 0);
517   GNUNET_assert (NULL != rc->h);
518   rc->cproc =
519       GNUNET_TESTBED_controller_start ("127.0.0.1", rc->h, cfg,
520                                        &controller_status_cb, rc);
521   GNUNET_assert (NULL != rc->cproc);
522   rc->num_peers = num_peers;
523   rc->event_mask = event_mask;
524   rc->event_mask |= (1LL << GNUNET_TESTBED_ET_PEER_START);
525   rc->cc = cc;
526   rc->cc_cls = cc_cls;
527   rc->master = master;
528   rc->master_cls = master_cls;
529   rc->state = RC_INIT;
530   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
531                                 &shutdown_run_task, rc);
532 }
533
534
535 /**
536  * Configure and run a testbed using the given
537  * master controller on 'num_hosts' starting
538  * 'num_peers' using the given peer configuration.
539  *
540  * @param controller master controller for the testbed
541  *                   (must not be destroyed until after the
542  *                    testbed is destroyed).
543  * @param num_hosts number of hosts in 'hosts', 0 to only
544  *        use 'localhost'
545  * @param hosts list of hosts to use for the testbed
546  * @param num_peers number of peers to start
547  * @param peer_cfg peer configuration template to use
548  * @param underlay_topology underlay topology to create
549  * @param va topology-specific options
550  * @return handle to the testbed
551  */
552 struct GNUNET_TESTBED_Testbed *
553 GNUNET_TESTBED_create_va (struct GNUNET_TESTBED_Controller *controller,
554                           unsigned int num_hosts,
555                           struct GNUNET_TESTBED_Host **hosts,
556                           unsigned int num_peers,
557                           const struct GNUNET_CONFIGURATION_Handle *peer_cfg,
558                           enum GNUNET_TESTBED_TopologyOption underlay_topology,
559                           va_list va)
560 {
561   GNUNET_break (0);
562   return NULL;
563 }
564
565
566 /**
567  * Configure and run a testbed using the given
568  * master controller on 'num_hosts' starting
569  * 'num_peers' using the given peer configuration.
570  *
571  * @param controller master controller for the testbed
572  *                   (must not be destroyed until after the
573  *                    testbed is destroyed).
574  * @param num_hosts number of hosts in 'hosts', 0 to only
575  *        use 'localhost'
576  * @param hosts list of hosts to use for the testbed
577  * @param num_peers number of peers to start
578  * @param peer_cfg peer configuration template to use
579  * @param underlay_topology underlay topology to create
580  * @param ... topology-specific options
581  */
582 struct GNUNET_TESTBED_Testbed *
583 GNUNET_TESTBED_create (struct GNUNET_TESTBED_Controller *controller,
584                        unsigned int num_hosts,
585                        struct GNUNET_TESTBED_Host **hosts,
586                        unsigned int num_peers,
587                        const struct GNUNET_CONFIGURATION_Handle *peer_cfg,
588                        enum GNUNET_TESTBED_TopologyOption underlay_topology,
589                        ...)
590 {
591   GNUNET_break (0);
592   return NULL;
593 }
594
595
596 /**
597  * Destroy a testbed.  Stops all running peers and then
598  * destroys all peers.  Does NOT destroy the master controller.
599  *
600  * @param testbed testbed to destroy
601  */
602 void
603 GNUNET_TESTBED_destroy (struct GNUNET_TESTBED_Testbed *testbed)
604 {
605   GNUNET_break (0);
606 }
607
608
609 /* end of testbed_api_testbed.c */