check if peer has already been stopped before attempting to stop it again
[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
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 =
467       GNUNET_TESTBED_controller_connect (cfg, rc->h, rc->event_mask, &event_cb,
468                                          rc);
469   rc->peers =
470       GNUNET_malloc (sizeof (struct GNUNET_TESTBED_Peer *) * rc->num_peers);
471   GNUNET_assert (NULL != rc->c);
472   rc->peer_count = 0;
473   for (peer = 0; peer < rc->num_peers; peer++)
474   {
475     dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
476     dll_op->rc = rc;
477     dll_op->op =
478         GNUNET_TESTBED_peer_create (rc->c, rc->h, cfg, peer_create_cb, dll_op);
479     GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail, dll_op);
480   }
481 }
482
483
484 /**
485  * Stops the testbed run and releases any used resources
486  *
487  * @param rc the tesbed run handle
488  * @param tc the task context from scheduler
489  */
490 void
491 shutdown_run_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
492 {
493   struct RunContext *rc = cls;
494   struct DLLOperation *dll_op;
495   unsigned int peer;
496
497   if (NULL != rc->c)
498   {
499     if (NULL != rc->peers)
500     {
501       rc->peer_count = 0;
502       for (peer = 0; peer < rc->num_peers; peer++)
503       {
504         if (PS_STARTED != rc->peers[peer]->state)
505         {
506           rc->peer_count++;
507           continue;
508         }
509         dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
510         dll_op->op = GNUNET_TESTBED_peer_stop (rc->peers[peer]);
511         dll_op->cls = rc->peers[peer];
512         GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail,
513                                           dll_op);
514       }
515       if (rc->peer_count != rc->num_peers)
516         return;
517     }
518   }
519   rc->state = RC_PEERS_DESTROYED;       /* No peers are present so we consider the
520                                          * state where all peers are destroyed  */
521   GNUNET_SCHEDULER_add_now (&cleanup_task, rc);
522 }
523
524
525 /**
526  * Convenience method for running a testbed with
527  * a single call.  Underlay and overlay topology
528  * are configured using the "UNDERLAY" and "OVERLAY"
529  * options in the "[testbed]" section of the configuration\
530  * (with possible options given in "UNDERLAY_XXX" and/or
531  * "OVERLAY_XXX").
532  *
533  * The testbed is to be terminated using a call to
534  * "GNUNET_SCHEDULER_shutdown".
535  *
536  * @param host_filename name of the file with the 'hosts', NULL
537  *        to run everything on 'localhost'
538  * @param cfg configuration to use (for testbed, controller and peers)
539  * @param num_peers number of peers to start; FIXME: maybe put that ALSO into cfg?
540  * @param event_mask bit mask with set of events to call 'cc' for;
541  *                   or-ed values of "1LL" shifted by the
542  *                   respective 'enum GNUNET_TESTBED_EventType'
543  *                   (i.e.  "(1LL << GNUNET_TESTBED_ET_CONNECT) || ...")
544  * @param cc controller callback to invoke on events
545  * @param cc_cls closure for cc
546  * @param master task to run once the testbed is ready
547  */
548 void
549 GNUNET_TESTBED_run (const char *host_filename,
550                     const struct GNUNET_CONFIGURATION_Handle *cfg,
551                     unsigned int num_peers, uint64_t event_mask,
552                     GNUNET_TESTBED_ControllerCallback cc, void *cc_cls,
553                     GNUNET_SCHEDULER_Task master, void *master_cls)
554 {
555   struct RunContext *rc;
556
557   event_mask |= (1LL << GNUNET_TESTBED_ET_PEER_START);
558   rc = GNUNET_malloc (sizeof (struct RunContext));
559   GNUNET_break (NULL == host_filename); /* Currently we do not support host
560                                          * files */
561   host_filename = NULL;
562   rc->h = GNUNET_TESTBED_host_create (NULL, NULL, 0);
563   GNUNET_assert (NULL != rc->h);
564   rc->cproc =
565       GNUNET_TESTBED_controller_start ("127.0.0.1", rc->h, cfg,
566                                        &controller_status_cb, rc);
567   GNUNET_assert (NULL != rc->cproc);
568   rc->num_peers = num_peers;
569   rc->event_mask = event_mask;
570   rc->cc = cc;
571   rc->cc_cls = cc_cls;
572   rc->master = master;
573   rc->master_cls = master_cls;
574   rc->state = RC_INIT;
575   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
576                                 &shutdown_run_task, rc);
577 }
578
579 /* end of testbed_api_testbed.c */