-testbed host registration cancel
[oweals/gnunet.git] / src / testbed / testbed_api.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.c
23  * @brief API for accessing the GNUnet testing service.
24  *        This library is supposed to make it easier to write
25  *        testcases and script large-scale benchmarks.
26  * @author Christian Grothoff
27  */
28 #include "platform.h"
29 #include "gnunet_testbed_service.h"
30 #include "gnunet_core_service.h"
31 #include "gnunet_constants.h"
32 #include "gnunet_transport_service.h"
33 #include "gnunet_hello_lib.h"
34
35 #include "testbed.h"
36 #include "testbed_api_hosts.h"
37
38 /**
39  * Generic logging shorthand
40  */
41 #define LOG(kind, ...)                          \
42   GNUNET_log_from (kind, "testbed-api", __VA_ARGS__);
43
44 /**
45  * Debug logging
46  */
47 #define LOG_DEBUG(...)                          \
48   LOG (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__);
49
50
51 /**
52  * The message queue for sending messages to the controller service
53  */
54 struct MessageQueue
55 {
56   /**
57    * The message to be sent
58    */
59   struct GNUNET_MessageHeader *msg;
60
61   /**
62    * next pointer for DLL
63    */
64   struct MessageQueue *next;
65   
66   /**
67    * prev pointer for DLL
68    */
69   struct MessageQueue *prev;
70 };
71
72
73 /**
74  * Structure for a controller link
75  */
76 struct ControllerLink
77 {
78   /**
79    * The next ptr for DLL
80    */
81   struct ControllerLink *next;
82
83   /**
84    * The prev ptr for DLL
85    */
86   struct ControllerLink *prev;
87
88   /**
89    * The host which will be referred in the peer start request. This is the
90    * host where the peer should be started
91    */
92   struct GNUNET_TESTBED_Host *delegated_host;
93
94   /**
95    * The host which will contacted to delegate the peer start request
96    */
97   struct GNUNET_TESTBED_Host *slave_host;
98
99   /**
100    * The configuration to be used to connect to slave host
101    */
102   const struct GNUNET_CONFIGURATION_Handle *slave_cfg;
103
104   /**
105    * GNUNET_YES if the slave should be started (and stopped) by us; GNUNET_NO
106    * if we are just allowed to use the slave via TCP/IP
107    */
108   int is_subordinate;
109 };
110
111
112 /**
113  * Handle to interact with a GNUnet testbed controller.  Each
114  * controller has at least one master handle which is created when the
115  * controller is created; this master handle interacts with the
116  * controller process, destroying it destroys the controller (by
117  * closing stdin of the controller process).  Additionally,
118  * controllers can interact with each other (in a P2P fashion); those
119  * links are established via TCP/IP on the controller's service port.
120  */
121 struct GNUNET_TESTBED_Controller
122 {
123
124   /**
125    * The host where the controller is running
126    */
127   const struct GNUNET_TESTBED_Host *host;
128
129   /**
130    * The helper handle
131    */
132   struct GNUNET_TESTBED_HelperHandle *helper;
133
134   /**
135    * The controller callback
136    */
137   GNUNET_TESTBED_ControllerCallback cc;
138
139   /**
140    * The closure for controller callback
141    */
142   void *cc_cls;
143
144   /**
145    * The configuration to use while connecting to controller
146    */
147   struct GNUNET_CONFIGURATION_Handle *cfg;
148
149   /**
150    * The client connection handle to the controller service
151    */
152   struct GNUNET_CLIENT_Connection *client;
153   
154   /**
155    * The head of the message queue
156    */
157   struct MessageQueue *mq_head;
158
159   /**
160    * The tail of the message queue
161    */
162   struct MessageQueue *mq_tail;
163
164   /**
165    * The head of the ControllerLink list
166    */
167   struct ControllerLink *cl_head;
168
169   /**
170    * The tail of the ControllerLink list
171    */
172   struct ControllerLink *cl_tail;
173
174   /**
175    * The client transmit handle
176    */
177   struct GNUNET_CLIENT_TransmitHandle *th;
178
179   /**
180    * The host registration handle; NULL if no current registration requests are
181    * present 
182    */
183   struct GNUNET_TESTBED_HostRegistrationHandle *rh;
184
185   /**
186    * The controller event mask
187    */
188   uint64_t event_mask;
189
190   /**
191    * Did we start the receive loop yet?
192    */
193   int in_receive;
194 };
195
196
197 /**
198  * handle for host registration
199  */
200 struct GNUNET_TESTBED_HostRegistrationHandle
201 {
202   /**
203    * The host being registered
204    */
205   struct GNUNET_TESTBED_Host *host;
206
207   /**
208    * The controller at which this host is being registered
209    */
210   struct GNUNET_TESTBED_Controller *c;
211
212   /**
213    * The Registartion completion callback
214    */
215   GNUNET_TESTBED_HostRegistrationCompletion cc;
216
217   /**
218    * The closure for above callback
219    */
220   void *cc_cls;
221 };
222
223
224 /**
225  * Handler for GNUNET_MESSAGE_TYPE_TESTBED_ADDHOSTCONFIRM message from
226  * controller (testbed service)
227  *
228  * @param c the controller handler
229  * @param msg message received
230  * @return GNUNET_YES if we can continue receiving from service; GNUNET_NO if
231  *           not
232  */
233 static int
234 handle_addhostconfirm (struct GNUNET_TESTBED_Controller *c,
235                        const struct GNUNET_TESTBED_HostConfirmedMessage *msg)
236 {
237   struct GNUNET_TESTBED_HostRegistrationHandle *rh;
238   char *emsg;
239   uint16_t msg_size;
240
241   rh = c->rh;
242   if (NULL == rh)
243   {  
244     return GNUNET_OK;    
245   }
246   if (GNUNET_TESTBED_host_get_id_ (rh->host) != ntohl (msg->host_id))
247   {
248     LOG_DEBUG ("Mismatch in host id's %u, %u of host confirm msg\n",
249                GNUNET_TESTBED_host_get_id_ (rh->host), ntohl (msg->host_id));
250     return GNUNET_OK;
251   }
252   c->rh = NULL;
253   msg_size = ntohs (msg->header.size);
254   if (sizeof (struct GNUNET_TESTBED_HostConfirmedMessage) == msg_size)
255   {
256     LOG_DEBUG ("Host %u successfully registered\n", ntohl (msg->host_id));
257     GNUNET_TESTBED_mark_host_as_registered_  (rh->host);
258     rh->cc (rh->cc_cls, NULL);
259     GNUNET_free (rh);
260     return GNUNET_OK;
261   } 
262   /* We have an error message */
263   emsg = (char *) &msg[1];
264   if ('\0' != emsg[msg_size - 
265                    sizeof (struct GNUNET_TESTBED_HostConfirmedMessage)])
266   {
267     GNUNET_break (0);
268     GNUNET_free (rh);
269     return GNUNET_NO;
270   }  
271   LOG (GNUNET_ERROR_TYPE_ERROR, _("Adding host %u failed with error: %s\n"),
272        ntohl (msg->host_id), emsg);
273   rh->cc (rh->cc_cls, emsg);
274   GNUNET_free (rh);
275   return GNUNET_OK;
276 }
277
278
279 /**
280  * Handler for messages from controller (testbed service)
281  *
282  * @param cls the controller handler
283  * @param msg message received, NULL on timeout or fatal error
284  */
285 static void 
286 message_handler (void *cls, const struct GNUNET_MessageHeader *msg)
287 {
288   struct GNUNET_TESTBED_Controller *c = cls;  
289   int status;
290
291   /* FIXME: Add checks for message integrity */
292   if (NULL == msg)
293   {
294     LOG_DEBUG ("Receive timed out or connection to service dropped\n");
295     return;
296   }
297   status = GNUNET_OK;
298   switch (ntohs (msg->type))
299   {
300   case GNUNET_MESSAGE_TYPE_TESTBED_ADDHOSTCONFIRM:
301     status =
302       handle_addhostconfirm (c, (const struct
303                                  GNUNET_TESTBED_HostConfirmedMessage *) msg);   
304     break;
305   default:
306     GNUNET_break (0);
307   }
308   if (GNUNET_OK == status)
309     GNUNET_CLIENT_receive (c->client, &message_handler, c,
310                            GNUNET_TIME_UNIT_FOREVER_REL);
311 }
312
313
314 /**
315  * Function called to notify a client about the connection begin ready to queue
316  * more data.  "buf" will be NULL and "size" zero if the connection was closed
317  * for writing in the meantime.
318  *
319  * @param cls closure
320  * @param size number of bytes available in buf
321  * @param buf where the callee should write the message
322  * @return number of bytes written to buf
323  */
324 static size_t
325 transmit_ready_notify (void *cls, size_t size, void *buf)
326 {
327   struct GNUNET_TESTBED_Controller *c = cls;
328   struct MessageQueue *mq_entry;
329
330   c->th = NULL;
331   mq_entry = c->mq_head;
332   GNUNET_assert (NULL != mq_entry);
333   GNUNET_assert (ntohs (mq_entry->msg->size) <= size);
334   size = ntohs (mq_entry->msg->size);
335   memcpy (buf, mq_entry->msg, size);
336   GNUNET_free (mq_entry->msg);
337   GNUNET_CONTAINER_DLL_remove (c->mq_head, c->mq_tail, mq_entry);
338   GNUNET_free (mq_entry);
339   mq_entry = c->mq_head;
340   if (NULL != mq_entry)
341     c->th = 
342       GNUNET_CLIENT_notify_transmit_ready (c->client,
343                                            ntohs (mq_entry->msg->size),
344                                            GNUNET_TIME_UNIT_FOREVER_REL,
345                                            GNUNET_NO, &transmit_ready_notify,
346                                            c);
347   if ( (GNUNET_NO == c->in_receive) &&
348        (size > 0) )
349   {
350     c->in_receive = GNUNET_YES;
351     GNUNET_CLIENT_receive (c->client, &message_handler, c,
352                            GNUNET_TIME_UNIT_FOREVER_REL);
353   }
354   return size;
355 }
356
357
358 /**
359  * Queues a message in send queue for sending to the service
360  *
361  * @param controller the handle to the controller
362  * @param msg the message to queue
363  */
364 static void
365 queue_message (struct GNUNET_TESTBED_Controller *controller,
366                struct GNUNET_MessageHeader *msg)
367 {
368   struct MessageQueue *mq_entry;
369   uint16_t type;
370   uint16_t size;
371
372   type = ntohs (msg->type);
373   size = ntohs (msg->size);
374   GNUNET_assert ((GNUNET_MESSAGE_TYPE_TESTBED_INIT <= type) &&
375                  (GNUNET_MESSAGE_TYPE_TESTBED_MAX > type));                 
376   mq_entry = GNUNET_malloc (sizeof (struct MessageQueue));
377   mq_entry->msg = msg;
378   LOG (GNUNET_ERROR_TYPE_DEBUG,
379        "Queueing message of type %u, size %u for sending\n", type,
380        ntohs (msg->size));
381   GNUNET_CONTAINER_DLL_insert_tail (controller->mq_head, controller->mq_tail,
382                                     mq_entry);
383   if (NULL == controller->th)
384     controller->th = 
385       GNUNET_CLIENT_notify_transmit_ready (controller->client, size,
386                                            GNUNET_TIME_UNIT_FOREVER_REL,
387                                            GNUNET_NO, &transmit_ready_notify,
388                                            controller);
389 }
390
391
392 /**
393  * Start a controller process using the given configuration at the
394  * given host.
395  *
396  * @param cfg configuration to use
397  * @param host host to run the controller on, NULL for 'localhost'
398  * @param event_mask bit mask with set of events to call 'cc' for;
399  *                   or-ed values of "1LL" shifted by the
400  *                   respective 'enum GNUNET_TESTBED_EventType'
401  *                   (i.e.  "(1LL << GNUNET_TESTBED_ET_CONNECT) | ...")
402  * @param cc controller callback to invoke on events
403  * @param cc_cls closure for cc
404  * @return handle to the controller
405  */
406 struct GNUNET_TESTBED_Controller *
407 GNUNET_TESTBED_controller_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
408                                  struct GNUNET_TESTBED_Host *host,
409                                  uint64_t event_mask,
410                                  GNUNET_TESTBED_ControllerCallback cc,
411                                  void *cc_cls)
412 {
413   struct GNUNET_TESTBED_Controller *controller;
414   char * const binary_argv[] = {
415     "gnunet-service-testbed",
416     "gnunet-service-testbed",
417     NULL
418   };
419   struct GNUNET_TESTBED_InitMessage *msg;
420
421   controller = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_Controller));
422   controller->helper = GNUNET_TESTBED_host_run_ (host, binary_argv);
423   if (NULL == controller->helper)
424   {
425     GNUNET_free (controller);
426     return NULL;
427   }
428   controller->host = host;
429   controller->cc = cc;
430   controller->cc_cls = cc_cls;
431   controller->event_mask = event_mask;
432   controller->cfg = GNUNET_CONFIGURATION_dup (cfg);
433   controller->client = GNUNET_CLIENT_connect ("testbed", controller->cfg);
434   if (NULL == controller->client)
435   {
436     GNUNET_TESTBED_controller_stop (controller);
437     return NULL;
438   }  
439   msg = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_InitMessage));
440   msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_INIT);
441   msg->header.size = htons (sizeof (struct GNUNET_TESTBED_InitMessage));
442   msg->host_id = htonl (GNUNET_TESTBED_host_get_id_ (controller->host));
443   msg->event_mask = GNUNET_htonll (controller->event_mask);
444   queue_message (controller, (struct GNUNET_MessageHeader *) msg);
445   return controller;
446 }
447
448
449 /**
450  * Configure shared services at a controller.  Using this function,
451  * you can specify that certain services (such as "resolver")
452  * should not be run for each peer but instead be shared
453  * across N peers on the specified host.  This function
454  * must be called before any peers are created at the host.
455  * 
456  * @param controller controller to configure
457  * @param service_name name of the service to share
458  * @param num_peers number of peers that should share one instance
459  *        of the specified service (1 for no sharing is the default),
460  *        use 0 to disable the service
461  */
462 void
463 GNUNET_TESTBED_controller_configure_sharing (struct GNUNET_TESTBED_Controller *controller,
464                                              const char *service_name,
465                                              uint32_t num_peers)
466 {
467   struct GNUNET_TESTBED_ConfigureSharedServiceMessage *msg;
468   uint16_t service_name_size;
469   uint16_t msg_size;
470   
471   service_name_size = strlen (service_name) + 1;
472   msg_size = sizeof (struct GNUNET_TESTBED_ConfigureSharedServiceMessage)
473     + service_name_size;
474   msg = GNUNET_malloc (msg_size);
475   msg->header.size = htons (msg_size);
476   msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_SERVICESHARE);
477   msg->host_id = htonl (GNUNET_TESTBED_host_get_id_ (controller->host));
478   msg->num_peers = htonl (num_peers);
479   memcpy (&msg[1], service_name, service_name_size);
480   queue_message (controller, (struct GNUNET_MessageHeader *) msg);
481 }
482
483
484 /**
485  * Stop the given controller (also will terminate all peers and
486  * controllers dependent on this controller).  This function 
487  * blocks until the testbed has been fully terminated (!).
488  *
489  * @param controller handle to controller to stop
490  */
491 void
492 GNUNET_TESTBED_controller_stop (struct GNUNET_TESTBED_Controller *controller)
493 {
494   struct MessageQueue *mq_entry;
495
496   if (NULL != controller->th)
497     GNUNET_CLIENT_notify_transmit_ready_cancel (controller->th);
498  /* Clear the message queue */
499   while (NULL != (mq_entry = controller->mq_head))
500   {
501     GNUNET_CONTAINER_DLL_remove (controller->mq_head,
502                                  controller->mq_tail,
503                                  mq_entry);
504     GNUNET_free (mq_entry->msg);
505     GNUNET_free (mq_entry);
506   }
507   if (NULL != controller->client)
508     GNUNET_CLIENT_disconnect (controller->client);
509   GNUNET_TESTBED_host_stop_ (controller->helper);
510   GNUNET_CONFIGURATION_destroy (controller->cfg);
511   GNUNET_free (controller);
512 }
513
514
515 /**
516  * Register a host with the controller
517  *
518  * @param controller the controller handle
519  * @param host the host to register
520  * @param cc the completion callback to call to inform the status of
521  *          registration. After calling this callback the registration handle
522  *          will be invalid. Cannot be NULL.
523  * @param cc_cls the closure for the cc
524  * @return handle to the host registration which can be used to cancel the
525  *           registration 
526  */
527 struct GNUNET_TESTBED_HostRegistrationHandle *
528 GNUNET_TESTBED_register_host (struct GNUNET_TESTBED_Controller *controller,
529                               struct GNUNET_TESTBED_Host *host,
530                               GNUNET_TESTBED_HostRegistrationCompletion cc,
531                               void *cc_cls)
532 {
533   struct GNUNET_TESTBED_HostRegistrationHandle *rh;
534   struct GNUNET_TESTBED_AddHostMessage *msg;
535   const char *username;
536   const char *hostname;
537   uint16_t msg_size;
538   uint16_t user_name_length;
539
540   if (NULL != controller->rh)
541     return NULL;
542   hostname = GNUNET_TESTBED_host_get_hostname_ (host);
543   if (GNUNET_YES == GNUNET_TESTBED_is_host_registered_ (host))
544   {
545     LOG (GNUNET_ERROR_TYPE_WARNING,
546          "Host hostname: %s already registered\n",
547          (NULL == hostname) ? "localhost" : hostname);
548     return NULL;
549   }  
550   rh = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_HostRegistrationHandle));
551   rh->host = host;
552   rh->c = controller;
553   GNUNET_assert (NULL != cc);
554   rh->cc = cc;
555   rh->cc_cls = cc_cls;
556   controller->rh = rh;
557   username = GNUNET_TESTBED_host_get_username_ (host);
558   msg_size = (sizeof (struct GNUNET_TESTBED_AddHostMessage));
559   user_name_length = 0;
560   if (NULL != username)
561   {
562     user_name_length = strlen (username) + 1;
563     msg_size += user_name_length;
564   }
565   /* FIXME: what happens when hostname is NULL? localhost */
566   GNUNET_assert (NULL != hostname);
567   msg_size += strlen (hostname) + 1;
568   msg = GNUNET_malloc (msg_size);
569   msg->header.size = htons (msg_size);
570   msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST);
571   msg->host_id = htonl (GNUNET_TESTBED_host_get_id_ (host));
572   msg->ssh_port = htons (GNUNET_TESTBED_host_get_ssh_port_ (host));
573   msg->user_name_length = htons (user_name_length);
574   if (NULL != username)
575     memcpy (&msg[1], username, user_name_length);
576   strcpy (((void *) msg) + user_name_length, hostname);
577   queue_message (controller, (struct GNUNET_MessageHeader *) msg);
578   return rh;
579 }
580
581
582 /**
583  * Cancel the pending registration. Note that if the registration message is
584  * already sent to the service the cancellation has only the effect that the
585  * registration completion callback for the registration is never called.
586  *
587  * @param handle the registration handle to cancel
588  */
589 void
590 GNUNET_TESTBED_cancel_registration (struct GNUNET_TESTBED_HostRegistrationHandle
591                                     *handle)
592 {
593   if (handle != handle->c->rh)
594   {
595     GNUNET_break (0);
596     return;
597   }
598   handle->c->rh = NULL;
599   GNUNET_free (handle);  
600 }
601
602
603 /**
604  * Create a link from a 'master' controller to a slave controller.
605  * Whenever the master controller is asked to start a peer at the
606  * given 'delegated_host', it will delegate the request to the
607  * specified slave controller.  Note that the slave controller runs at
608  * the 'slave_host', which may or may not be the same host as the
609  * 'delegated_host' (for hierarchical delegations).  The configuration
610  * of the slave controller is given and to be used to either create
611  * the slave controller or to connect to an existing slave controller
612  * process.  'is_subordinate' specifies if the given slave controller
613  * should be started and managed by the master controller, or if the
614  * slave already has a master and this is just a secondary master that
615  * is also allowed to use the existing slave.
616  *
617  * @param master handle to the master controller who creates the association
618  * @param delegated_host requests to which host should be delegated
619  * @param slave_host which host is used to run the slave controller 
620  * @param slave_cfg configuration to use for the slave controller
621  * @param is_subordinate GNUNET_YES if the slave should be started (and stopped)
622  *                       by the master controller; GNUNET_NO if we are just
623  *                       allowed to use the slave via TCP/IP
624  */
625 void
626 GNUNET_TESTBED_controller_link (struct GNUNET_TESTBED_Controller *master,
627                                 struct GNUNET_TESTBED_Host *delegated_host,
628                                 struct GNUNET_TESTBED_Host *slave_host,
629                                 const struct GNUNET_CONFIGURATION_Handle *slave_cfg,
630                                 int is_subordinate)
631 {
632   GNUNET_break (0);
633 }
634
635
636 /**
637  * Ask the testbed controller to write the current overlay topology to
638  * a file.  Naturally, the file will only contain a snapshot as the
639  * topology may evolve all the time.
640  *
641  * @param controller overlay controller to inspect
642  * @param filename name of the file the topology should
643  *        be written to.
644  */
645 void
646 GNUNET_TESTBED_overlay_write_topology_to_file (struct GNUNET_TESTBED_Controller *controller,
647                                                const char *filename)
648 {
649   GNUNET_break (0);
650 }
651
652
653
654 /* end of testbed_api.c */