input checks
[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]);
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 rc 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       for (peer = 0; peer < rc->num_peers; peer++)
432       {
433         if (PS_STARTED != rc->peers[peer]->state)
434         {
435           rc->peer_count++;
436           continue;
437         }
438         dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
439         dll_op->op = GNUNET_TESTBED_peer_stop (rc->peers[peer]);
440         dll_op->cls = rc->peers[peer];
441         GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail,
442                                           dll_op);
443       }
444       if (rc->peer_count != rc->num_peers)
445         return;
446     }
447   }
448   rc->state = RC_PEERS_DESTROYED;       /* No peers are present so we consider the
449                                          * state where all peers are destroyed  */
450   GNUNET_SCHEDULER_add_now (&cleanup_task, rc);
451 }
452
453
454 /**
455  * Convenience method for running a testbed with
456  * a single call.  Underlay and overlay topology
457  * are configured using the "UNDERLAY" and "OVERLAY"
458  * options in the "[testbed]" section of the configuration\
459  * (with possible options given in "UNDERLAY_XXX" and/or
460  * "OVERLAY_XXX").
461  *
462  * The testbed is to be terminated using a call to
463  * "GNUNET_SCHEDULER_shutdown".
464  *
465  * @param host_filename name of the file with the 'hosts', NULL
466  *        to run everything on 'localhost'
467  * @param cfg configuration to use (for testbed, controller and peers)
468  * @param num_peers number of peers to start; FIXME: maybe put that ALSO into cfg?
469  * @param event_mask bit mask with set of events to call 'cc' for;
470  *                   or-ed values of "1LL" shifted by the
471  *                   respective 'enum GNUNET_TESTBED_EventType'
472  *                   (i.e.  "(1LL << GNUNET_TESTBED_ET_CONNECT) || ...")
473  * @param cc controller callback to invoke on events
474  * @param cc_cls closure for cc
475  * @param master task to run once the testbed is ready
476  */
477 void
478 GNUNET_TESTBED_run (const char *host_filename,
479                     const struct GNUNET_CONFIGURATION_Handle *cfg,
480                     unsigned int num_peers, uint64_t event_mask,
481                     GNUNET_TESTBED_ControllerCallback cc, void *cc_cls,
482                     GNUNET_SCHEDULER_Task master, void *master_cls)
483 {
484   struct RunContext *rc;
485
486   GNUNET_break (NULL == host_filename); /* Currently we do not support host
487                                          * files */
488   GNUNET_assert (NULL != cc);
489   GNUNET_assert (num_peers > 0);
490   host_filename = NULL;
491   rc = GNUNET_malloc (sizeof (struct RunContext));
492   rc->h = GNUNET_TESTBED_host_create (NULL, NULL, 0);
493   GNUNET_assert (NULL != rc->h);
494   rc->cproc =
495       GNUNET_TESTBED_controller_start ("127.0.0.1", rc->h, cfg,
496                                        &controller_status_cb, rc);
497   GNUNET_assert (NULL != rc->cproc);
498   rc->num_peers = num_peers;
499   rc->event_mask = event_mask;
500   rc->event_mask |= (1LL << GNUNET_TESTBED_ET_PEER_START);
501   rc->cc = cc;
502   rc->cc_cls = cc_cls;
503   rc->master = master;
504   rc->master_cls = master_cls;
505   rc->state = RC_INIT;
506   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
507                                 &shutdown_run_task, rc);
508 }
509
510
511 /**
512  * Configure and run a testbed using the given
513  * master controller on 'num_hosts' starting
514  * 'num_peers' using the given peer configuration.
515  *
516  * @param controller master controller for the testbed
517  *                   (must not be destroyed until after the
518  *                    testbed is destroyed).
519  * @param num_hosts number of hosts in 'hosts', 0 to only
520  *        use 'localhost'
521  * @param hosts list of hosts to use for the testbed
522  * @param num_peers number of peers to start
523  * @param peer_cfg peer configuration template to use
524  * @param underlay_topology underlay topology to create
525  * @param va topology-specific options
526  * @return handle to the testbed
527  */
528 struct GNUNET_TESTBED_Testbed *
529 GNUNET_TESTBED_create_va (struct GNUNET_TESTBED_Controller *controller,
530                           unsigned int num_hosts,
531                           struct GNUNET_TESTBED_Host **hosts,
532                           unsigned int num_peers,
533                           const struct GNUNET_CONFIGURATION_Handle *peer_cfg,
534                           enum GNUNET_TESTBED_TopologyOption underlay_topology,
535                           va_list va)
536 {
537   GNUNET_break (0);
538   return NULL;
539 }
540
541
542 /**
543  * Configure and run a testbed using the given
544  * master controller on 'num_hosts' starting
545  * 'num_peers' using the given peer configuration.
546  *
547  * @param controller master controller for the testbed
548  *                   (must not be destroyed until after the
549  *                    testbed is destroyed).
550  * @param num_hosts number of hosts in 'hosts', 0 to only
551  *        use 'localhost'
552  * @param hosts list of hosts to use for the testbed
553  * @param num_peers number of peers to start
554  * @param peer_cfg peer configuration template to use
555  * @param underlay_topology underlay topology to create
556  * @param ... topology-specific options
557  */
558 struct GNUNET_TESTBED_Testbed *
559 GNUNET_TESTBED_create (struct GNUNET_TESTBED_Controller *controller,
560                        unsigned int num_hosts,
561                        struct GNUNET_TESTBED_Host **hosts,
562                        unsigned int num_peers,
563                        const struct GNUNET_CONFIGURATION_Handle *peer_cfg,
564                        enum GNUNET_TESTBED_TopologyOption underlay_topology,
565                        ...)
566 {
567   GNUNET_break (0);
568   return NULL;
569 }
570
571
572 /**
573  * Destroy a testbed.  Stops all running peers and then
574  * destroys all peers.  Does NOT destroy the master controller.
575  *
576  * @param testbed testbed to destroy
577  */
578 void
579 GNUNET_TESTBED_destroy (struct GNUNET_TESTBED_Testbed *testbed)
580 {
581   GNUNET_break (0);
582 }
583
584
585 /* end of testbed_api_testbed.c */