-use blocking wait as the pipe might be faster than the process cleanup
[oweals/gnunet.git] / src / testbed / test_testbed_api_2peers_2controllers.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/test_testbed_api_2peers_2controllers.c
23  * @brief testcases for the testbed api: 2 peers are configured, started and
24  *          connected together. Each peer resides on its own controller
25  * @author Sree Harsha Totakura
26  */
27
28 #include "platform.h"
29 #include "gnunet_util_lib.h"
30 #include "gnunet_testing_lib-new.h"
31 #include "gnunet_testbed_service.h"
32
33
34 /**
35  * Generic logging shortcut
36  */
37 #define LOG(kind,...)                           \
38   GNUNET_log (kind, __VA_ARGS__)
39
40 /**
41  * Relative time seconds shorthand
42  */
43 #define TIME_REL_SECS(sec) \
44   GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, sec)
45
46
47 /**
48  * Peer context
49  */
50 struct PeerContext
51 {
52   /**
53    * The peer handle
54    */
55   struct GNUNET_TESTBED_Peer *peer;
56
57   /**
58    * Operations involving this peer
59    */
60   struct GNUNET_TESTBED_Operation *operation;
61
62   /**
63    * set to GNUNET_YES when peer is started
64    */
65   int is_running;
66 };
67
68 /**
69  * Our localhost
70  */
71 static struct GNUNET_TESTBED_Host *host;
72
73 /**
74  * The controller process of one controller
75  */
76 static struct GNUNET_TESTBED_ControllerProc *cp1;
77
78 /**
79  * The controller process of another controller
80  */
81 static struct GNUNET_TESTBED_ControllerProc *cp2;
82
83 /**
84  * A neighbouring host
85  */
86 static struct GNUNET_TESTBED_Host *neighbour;
87
88 /**
89  * Handle for neighbour registration
90  */
91 static struct GNUNET_TESTBED_HostRegistrationHandle *reg_handle;
92
93 /**
94  * The controller handle of one controller
95  */
96 static struct GNUNET_TESTBED_Controller *controller1;
97
98 /**
99  * The controller handle of another controller
100  */
101 static struct GNUNET_TESTBED_Controller *controller2;
102
103 /**
104  * peer 1
105  */
106 static struct PeerContext peer1;
107
108 /**
109  * peer2
110  */
111 static struct PeerContext peer2;
112
113 /**
114  * Handle to starting configuration
115  */
116 static struct GNUNET_CONFIGURATION_Handle *cfg;
117
118 /**
119  * Handle to controller2 configuration, used to establish lateral link from
120  * controller 1
121  */
122 static struct GNUNET_CONFIGURATION_Handle *cfg2;
123
124 /**
125  * Handle to operations involving both peers
126  */
127 static struct GNUNET_TESTBED_Operation *common_operation;
128
129 /**
130  * Abort task identifier
131  */
132 static GNUNET_SCHEDULER_TaskIdentifier abort_task;
133
134 /**
135  * Delayed connect job identifier
136  */
137 static GNUNET_SCHEDULER_TaskIdentifier delayed_connect_task;
138
139 /**
140  * Different stages in testing
141  */
142 enum Stage
143 {
144
145   /**
146    * Initial stage
147    */
148   INIT,
149
150   /**
151    * Controller 1 has started
152    */
153   CONTROLLER1_UP,
154
155   /**
156    * peer1 is created
157    */
158   PEER1_CREATED,
159
160   /**
161    * peer1 is started
162    */
163   PEER1_STARTED,
164
165   /**
166    * Controller 2 has started
167    */
168   CONTROLLER2_UP,
169
170   /**
171    * peer2 is created
172    */
173   PEER2_CREATED,
174
175   /**
176    * peer2 is started
177    */
178   PEER2_STARTED,
179
180   /**
181    * peers are connected
182    */
183   PEERS_CONNECTED,
184
185   /**
186    * Peers are connected once again (this should not fail as they are already connected)
187    */
188   PEERS_CONNECTED_2,
189
190   /**
191    * peers are stopped
192    */
193   PEERS_STOPPED,
194
195   /**
196    * Final success stage
197    */
198   SUCCESS
199 };
200
201 /**
202  * The testing result
203  */
204 static enum Stage result;
205
206
207 /**
208  * Shutdown nicely
209  *
210  * @param cls NULL
211  * @param tc the task context
212  */
213 static void
214 do_shutdown (void *cls, const const struct GNUNET_SCHEDULER_TaskContext *tc)
215 {
216   if (GNUNET_SCHEDULER_NO_TASK != abort_task)
217     GNUNET_SCHEDULER_cancel (abort_task);
218   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == delayed_connect_task);
219   if (NULL != reg_handle)
220     GNUNET_TESTBED_cancel_registration (reg_handle);
221   if (NULL != controller1)
222     GNUNET_TESTBED_controller_disconnect (controller1);
223   if (NULL != controller2)
224   GNUNET_TESTBED_controller_disconnect (controller2);
225   GNUNET_CONFIGURATION_destroy (cfg);
226   if (NULL != cfg2)
227     GNUNET_CONFIGURATION_destroy (cfg2);
228   if (NULL != cp1)
229     GNUNET_TESTBED_controller_stop (cp1);
230   if (NULL != cp2)
231     GNUNET_TESTBED_controller_stop (cp2);
232   GNUNET_TESTBED_host_destroy (host);
233   GNUNET_TESTBED_host_destroy (neighbour);
234 }
235
236
237 /**
238  * abort task to run on test timed out
239  *
240  * @param cls NULL
241  * @param tc the task context
242  */
243 static void
244 do_abort (void *cls, const const struct GNUNET_SCHEDULER_TaskContext *tc)
245 {
246   LOG (GNUNET_ERROR_TYPE_WARNING, "Test timedout -- Aborting\n");
247   abort_task = GNUNET_SCHEDULER_NO_TASK;
248   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == delayed_connect_task);
249   do_shutdown (cls, tc);
250 }
251
252
253 /**
254  * Callback to be called when an operation is completed
255  *
256  * @param cls the callback closure from functions generating an operation
257  * @param op the operation that has been finished
258  * @param emsg error message in case the operation has failed; will be NULL if
259  *          operation has executed successfully.
260  */
261 static void 
262 op_comp_cb (void *cls, struct GNUNET_TESTBED_Operation *op, const char *emsg);
263
264
265 /**
266  * task for delaying a connect
267  *
268  * @param cls NULL
269  * @param tc the task context
270  */
271 static void
272 do_delayed_connect (void *cls, const const struct GNUNET_SCHEDULER_TaskContext *tc)
273 {
274   delayed_connect_task = GNUNET_SCHEDULER_NO_TASK;
275   GNUNET_assert (NULL == common_operation);
276   common_operation = GNUNET_TESTBED_overlay_connect (NULL, &op_comp_cb, NULL, 
277                                                      peer1.peer, peer2.peer);
278 }
279
280
281 /**
282  * Callback to be called when an operation is completed
283  *
284  * @param cls the callback closure from functions generating an operation
285  * @param op the operation that has been finished
286  * @param emsg error message in case the operation has failed; will be NULL if
287  *          operation has executed successfully.
288  */
289 static void 
290 op_comp_cb (void *cls, struct GNUNET_TESTBED_Operation *op, const char *emsg)
291 {
292   GNUNET_assert (common_operation == op);
293   switch(result)
294   {
295   case PEER2_STARTED:
296     GNUNET_assert (NULL == peer1.operation);
297     GNUNET_assert (NULL == peer2.operation);
298     GNUNET_assert (NULL != common_operation);
299     GNUNET_TESTBED_operation_done (common_operation);
300     common_operation = NULL;
301     result = PEERS_CONNECTED;
302     LOG (GNUNET_ERROR_TYPE_DEBUG, "Peers connected\n");
303     delayed_connect_task =
304         GNUNET_SCHEDULER_add_delayed (TIME_REL_SECS (3),
305                                       &do_delayed_connect, NULL);
306     break;
307   case PEERS_CONNECTED:
308     GNUNET_assert (NULL == peer1.operation);
309     GNUNET_assert (NULL == peer2.operation);
310     GNUNET_assert (NULL != common_operation);
311     GNUNET_TESTBED_operation_done (common_operation);
312     common_operation = NULL;
313     result = PEERS_CONNECTED_2;
314     LOG (GNUNET_ERROR_TYPE_DEBUG, "Peers connected again\n");
315     peer1.operation = GNUNET_TESTBED_peer_stop (peer1.peer, NULL, NULL);
316     peer2.operation = GNUNET_TESTBED_peer_stop (peer2.peer, NULL, NULL);
317     break;
318   default:
319     GNUNET_assert (0);
320   }
321 }
322
323
324 /**
325  * Functions of this signature are called when a peer has been successfully
326  * created
327  *
328  * @param cls NULL
329  * @param peer the handle for the created peer; NULL on any error during
330  *          creation
331  * @param emsg NULL if peer is not NULL; else MAY contain the error description
332  */
333 static void
334 peer_create_cb (void *cls, struct GNUNET_TESTBED_Peer *peer, const char *emsg)
335 {
336   switch (result)
337   {
338   case CONTROLLER1_UP:
339     GNUNET_assert (NULL != peer1.operation);
340     GNUNET_assert (NULL != peer);
341     GNUNET_assert (NULL == peer1.peer);
342     peer1.peer = peer;
343     GNUNET_TESTBED_operation_done (peer1.operation);
344     result = PEER1_CREATED;
345     peer1.operation = GNUNET_TESTBED_peer_start (peer, NULL, NULL);
346     break;
347   case CONTROLLER2_UP:
348     GNUNET_assert (NULL != peer2.operation);
349     GNUNET_assert (NULL != peer);
350     GNUNET_assert (NULL == peer2.peer);
351     peer2.peer = peer;
352     GNUNET_TESTBED_operation_done (peer2.operation);
353     result = PEER2_CREATED;
354     peer2.operation = GNUNET_TESTBED_peer_start (peer, NULL, NULL);
355     break;
356   default:
357     GNUNET_assert (0);
358   }  
359 }
360
361
362 /**
363  * Callback to signal successfull startup of the controller process
364  *
365  * @param cls the closure from GNUNET_TESTBED_controller_start()
366  * @param cfg the configuration with which the controller has been started;
367  *          NULL if status is not GNUNET_OK
368  * @param status GNUNET_OK if the startup is successfull; GNUNET_SYSERR if not,
369  *          GNUNET_TESTBED_controller_stop() shouldn't be called in this case
370  */
371 static void
372 status_cb (void *cls, const struct GNUNET_CONFIGURATION_Handle *config, int status);
373
374
375 /**
376  * Signature of the event handler function called by the
377  * respective event controller.
378  *
379  * @param cls closure
380  * @param event information about the event
381  */
382 static void
383 controller_cb (void *cls, const struct GNUNET_TESTBED_EventInformation *event)
384 {
385   switch (event->type)
386   {
387   case GNUNET_TESTBED_ET_OPERATION_FINISHED:
388     GNUNET_assert (NULL == event->details.operation_finished.op_cls);
389     GNUNET_assert (NULL == event->details.operation_finished.emsg);
390     GNUNET_assert (NULL == event->details.operation_finished.generic);
391     switch (result)
392     {
393     case PEERS_STOPPED:
394       if (event->details.operation_finished.operation == peer1.operation)
395       {
396         GNUNET_TESTBED_operation_done (peer1.operation);
397         peer1.operation = NULL;
398         peer1.peer = NULL;
399       }
400       else if (event->details.operation_finished.operation == peer2.operation)
401       {
402         GNUNET_TESTBED_operation_done (peer2.operation);
403         peer2.operation = NULL;
404         peer2.peer = NULL;
405       }
406       else
407         GNUNET_assert (0);
408       if ((NULL == peer1.peer) && (NULL == peer2.peer))
409       {
410         result = SUCCESS;
411         GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
412       }
413       break;
414     case PEER1_STARTED:
415       GNUNET_assert (NULL != common_operation);
416       GNUNET_TESTBED_operation_done (common_operation);
417       common_operation = NULL;
418       result = CONTROLLER2_UP;
419       peer2.operation =
420           GNUNET_TESTBED_peer_create (controller1, neighbour, cfg, &peer_create_cb,
421                                       NULL);
422       GNUNET_assert (NULL != peer2.operation);
423       break;
424     default:
425       GNUNET_assert (0);
426     }
427     break;
428   case GNUNET_TESTBED_ET_PEER_START:    
429     switch (result)
430     {
431     case PEER1_CREATED:
432       GNUNET_assert (event->details.peer_start.host == host);
433       peer1.is_running = GNUNET_YES;
434       GNUNET_TESTBED_operation_done (peer1.operation);
435       peer1.operation = NULL;
436       result = PEER1_STARTED;
437       common_operation =
438           GNUNET_TESTBED_controller_link (controller1, neighbour, NULL, cfg, GNUNET_YES);
439       break;
440     case PEER2_CREATED:
441       GNUNET_assert (event->details.peer_start.host == neighbour);
442       peer2.is_running = GNUNET_YES;
443       GNUNET_TESTBED_operation_done (peer2.operation);
444       peer2.operation = NULL;
445       result = PEER2_STARTED;
446       common_operation =
447           GNUNET_TESTBED_overlay_connect (NULL, &op_comp_cb, NULL, peer1.peer,
448                                           peer2.peer);
449       break;
450     default:
451       GNUNET_assert (0);
452     }    
453     break;
454   case GNUNET_TESTBED_ET_PEER_STOP:
455     GNUNET_assert (PEERS_CONNECTED_2 == result);
456     if (event->details.peer_stop.peer == peer1.peer)
457     {
458       peer1.is_running = GNUNET_NO;
459       GNUNET_TESTBED_operation_done (peer1.operation);
460     }
461     else if (event->details.peer_stop.peer == peer2.peer)
462     {
463       peer2.is_running = GNUNET_NO;
464       GNUNET_TESTBED_operation_done (peer2.operation);
465     }
466     else
467       GNUNET_assert (0);
468     if ((GNUNET_NO == peer1.is_running) && (GNUNET_NO == peer2.is_running))
469     {
470       result = PEERS_STOPPED;
471       peer1.operation = GNUNET_TESTBED_peer_destroy (peer1.peer);
472       peer2.operation = GNUNET_TESTBED_peer_destroy (peer2.peer);
473     }
474     break;
475   case GNUNET_TESTBED_ET_CONNECT:
476     switch (result)
477     {
478     case PEER2_STARTED:
479     case PEERS_CONNECTED:
480       GNUNET_assert (NULL == peer1.operation);
481       GNUNET_assert (NULL == peer2.operation);
482       GNUNET_assert (NULL != common_operation);
483       GNUNET_assert ((event->details.peer_connect.peer1 == peer1.peer) &&
484                      (event->details.peer_connect.peer2 == peer2.peer));
485       break;
486     default:
487       GNUNET_assert (0);
488     }
489     break;
490   default:
491     GNUNET_assert (0);
492   };
493 }
494
495
496 /**
497  * Callback which will be called to after a host registration succeeded or failed
498  *
499  * @param cls the host which has been registered
500  * @param emsg the error message; NULL if host registration is successful
501  */
502 static void
503 registration_comp (void *cls, const char *emsg)
504 {
505   GNUNET_assert (cls == neighbour);
506   reg_handle = NULL;
507   peer1.operation =
508       GNUNET_TESTBED_peer_create (controller1, host, cfg, &peer_create_cb,
509                                   &peer1);
510   GNUNET_assert (NULL != peer1.operation);
511 }
512
513
514 /**
515  * Callback to signal successfull startup of the controller process
516  *
517  * @param cls the closure from GNUNET_TESTBED_controller_start()
518  * @param cfg the configuration with which the controller has been started;
519  *          NULL if status is not GNUNET_OK
520  * @param status GNUNET_OK if the startup is successfull; GNUNET_SYSERR if not,
521  *          GNUNET_TESTBED_controller_stop() shouldn't be called in this case
522  */
523 static void
524 status_cb (void *cls, const struct GNUNET_CONFIGURATION_Handle *config, int status)
525 {
526   uint64_t event_mask;
527   
528   GNUNET_assert (GNUNET_OK == status);
529   event_mask = 0;
530   event_mask |= (1L << GNUNET_TESTBED_ET_PEER_START);
531   event_mask |= (1L << GNUNET_TESTBED_ET_PEER_STOP);
532   event_mask |= (1L << GNUNET_TESTBED_ET_CONNECT);
533   event_mask |= (1L << GNUNET_TESTBED_ET_OPERATION_FINISHED);
534   switch (result)
535   {
536   case INIT:
537     controller1 =
538         GNUNET_TESTBED_controller_connect (config, host, event_mask, &controller_cb,
539                                            NULL);
540     GNUNET_assert (NULL != controller1);
541     result = CONTROLLER1_UP;
542     neighbour = GNUNET_TESTBED_host_create ("127.0.0.1", NULL, 0);
543     GNUNET_assert (NULL != neighbour);
544     reg_handle =
545         GNUNET_TESTBED_register_host (controller1, neighbour, &registration_comp,
546                                       neighbour);
547     GNUNET_assert (NULL != reg_handle);    
548     break;
549   default:
550     GNUNET_assert (0);
551   }
552   
553 }
554
555
556
557 /**
558  * Main run function.
559  *
560  * @param cls NULL
561  * @param args arguments passed to GNUNET_PROGRAM_run
562  * @param cfgfile the path to configuration file
563  * @param cfg the configuration file handle
564  */
565 static void
566 run (void *cls, char *const *args, const char *cfgfile,
567      const struct GNUNET_CONFIGURATION_Handle *config)
568 {
569   host = GNUNET_TESTBED_host_create (NULL, NULL, 0);
570   GNUNET_assert (NULL != host);
571   cfg = GNUNET_CONFIGURATION_dup (config);
572   cp1 = GNUNET_TESTBED_controller_start ("127.0.0.1", host, cfg, status_cb,
573                                         NULL);
574   abort_task =
575       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
576                                     (GNUNET_TIME_UNIT_MINUTES, 3), &do_abort,
577                                     NULL);
578 }
579
580
581 /**
582  * Main function
583  */
584 int
585 main (int argc, char **argv)
586 {
587   int ret;
588
589   char *const argv2[] = { "test_testbed_api_2peers_2controllers",
590     "-c", "test_testbed_api.conf",
591     NULL
592   };
593   struct GNUNET_GETOPT_CommandLineOption options[] = {
594     GNUNET_GETOPT_OPTION_END
595   };
596   char *const remote_args[] = {
597     "ssh", "-o", "BatchMode=yes", "127.0.0.1", "echo", "SSH", "works", NULL
598   };
599   struct GNUNET_OS_Process *auxp;
600   enum GNUNET_OS_ProcessStatusType type;
601   unsigned long code;
602
603   auxp =
604       GNUNET_OS_start_process_vap (GNUNET_NO, GNUNET_OS_INHERIT_STD_ALL, NULL,
605                                    NULL, "ssh", remote_args);
606   GNUNET_assert (NULL != auxp);
607   do
608   {
609     ret = GNUNET_OS_process_status (auxp, &type, &code);
610     GNUNET_assert (GNUNET_SYSERR != ret);
611     (void) usleep (300);
612   }
613   while (GNUNET_NO == ret);
614   GNUNET_OS_process_destroy (auxp);
615   if (0 != code)
616   {
617     (void) printf ("Unable to run the test as this system is not configured "
618                    "to use password less SSH logins to localhost.\n"
619                    "Marking test as successful\n");
620     return 0;
621   }
622   result = INIT;
623   ret =
624       GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, argv2,
625                           "test_testbed_api_2peers_2controllers", "nohelp",
626                           options, &run, NULL);
627   if ((GNUNET_OK != ret) || (SUCCESS != result))
628     return 1;
629   return 0;
630 }
631
632 /* end of test_testbed_api_2peers_2controllers.c */