-testbed service reply queue and host success reply
[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 #define LOG(kind, ...)                          \
40   GNUNET_log_from (kind, "testbed-api", __VA_ARGS__);
41
42
43 /**
44  * The message queue for sending messages to the controller service
45  */
46 struct MessageQueue
47 {
48   /**
49    * The message to be sent
50    */
51   struct GNUNET_MessageHeader *msg;
52
53   /**
54    * next pointer for DLL
55    */
56   struct MessageQueue *next;
57   
58   /**
59    * prev pointer for DLL
60    */
61   struct MessageQueue *prev;
62 };
63
64
65 /**
66  * Handle to interact with a GNUnet testbed controller.  Each
67  * controller has at least one master handle which is created when the
68  * controller is created; this master handle interacts with the
69  * controller process, destroying it destroys the controller (by
70  * closing stdin of the controller process).  Additionally,
71  * controllers can interact with each other (in a P2P fashion); those
72  * links are established via TCP/IP on the controller's service port.
73  */
74 struct GNUNET_TESTBED_Controller
75 {
76
77   /**
78    * The host where the controller is running
79    */
80   const struct GNUNET_TESTBED_Host *host;
81
82   /**
83    * The helper handle
84    */
85   struct GNUNET_TESTBED_HelperHandle *helper;
86
87   /**
88    * The controller callback
89    */
90   GNUNET_TESTBED_ControllerCallback cc;
91
92   /**
93    * The closure for controller callback
94    */
95   void *cc_cls;
96
97   /**
98    * The configuration to use while connecting to controller
99    */
100   struct GNUNET_CONFIGURATION_Handle *cfg;
101
102   /**
103    * The client connection handle to the controller service
104    */
105   struct GNUNET_CLIENT_Connection *client;
106   
107   /**
108    * The head of the message queue
109    */
110   struct MessageQueue *mq_head;
111
112   /**
113    * The tail of the message queue
114    */
115   struct MessageQueue *mq_tail;
116
117   /**
118    * The client transmit handle
119    */
120   struct GNUNET_CLIENT_TransmitHandle *th;
121
122   /**
123    * The controller event mask
124    */
125   uint64_t event_mask;
126
127   /**
128    * Did we start the receive loop yet?
129    */
130   int in_receive;
131 };
132
133
134
135 /**
136  * Handler for messages from controller (testbed service)
137  *
138  * @param cls the controller handler
139  * @param msg message received, NULL on timeout or fatal error
140  */
141 static void 
142 message_handler (void *cls, const struct GNUNET_MessageHeader *msg)
143 {
144   struct GNUNET_TESTBED_Controller *c = cls;
145
146   /* FIXME: Add checks for message integrity */
147   switch (ntohs (msg->type))
148   {
149   default:
150     GNUNET_break (0);
151   }
152   GNUNET_CLIENT_receive (c->client, &message_handler, c,
153                          GNUNET_TIME_UNIT_FOREVER_REL);
154 }
155
156
157 /**
158  * Function called to notify a client about the connection begin ready to queue
159  * more data.  "buf" will be NULL and "size" zero if the connection was closed
160  * for writing in the meantime.
161  *
162  * @param cls closure
163  * @param size number of bytes available in buf
164  * @param buf where the callee should write the message
165  * @return number of bytes written to buf
166  */
167 static size_t
168 transmit_ready_notify (void *cls, size_t size, void *buf)
169 {
170   struct GNUNET_TESTBED_Controller *c = cls;
171   struct MessageQueue *mq_entry;
172
173   c->th = NULL;
174   mq_entry = c->mq_head;
175   GNUNET_assert (NULL != mq_entry);
176   GNUNET_assert (ntohs (mq_entry->msg->size) <= size);
177   size = ntohs (mq_entry->msg->size);
178   memcpy (buf, mq_entry->msg, size);
179   GNUNET_free (mq_entry->msg);
180   GNUNET_CONTAINER_DLL_remove (c->mq_head, c->mq_tail, mq_entry);
181   GNUNET_free (mq_entry);
182   mq_entry = c->mq_head;
183   if (NULL != mq_entry)
184     c->th = 
185       GNUNET_CLIENT_notify_transmit_ready (c->client,
186                                            ntohs (mq_entry->msg->size),
187                                            GNUNET_TIME_UNIT_FOREVER_REL,
188                                            GNUNET_NO, &transmit_ready_notify,
189                                            c);
190   if ( (GNUNET_NO == c->in_receive) &&
191        (size > 0) )
192   {
193     c->in_receive = GNUNET_YES;
194     GNUNET_CLIENT_receive (c->client, &message_handler, c,
195                            GNUNET_TIME_UNIT_FOREVER_REL);
196   }
197   return size;
198 }
199
200
201 /**
202  * Queues a message in send queue for sending to the service
203  *
204  * @param controller the handle to the controller
205  * @param msg the message to queue
206  */
207 static void
208 queue_message (struct GNUNET_TESTBED_Controller *controller,
209                struct GNUNET_MessageHeader *msg)
210 {
211   struct MessageQueue *mq_entry;
212   uint16_t type;
213   uint16_t size;
214
215   type = ntohs (msg->type);
216   size = ntohs (msg->size);
217   GNUNET_assert ((GNUNET_MESSAGE_TYPE_TESTBED_INIT <= type) &&
218                  (GNUNET_MESSAGE_TYPE_TESTBED_MAX > type));                 
219   mq_entry = GNUNET_malloc (sizeof (struct MessageQueue));
220   mq_entry->msg = msg;
221   LOG (GNUNET_ERROR_TYPE_DEBUG,
222        "Queueing message of type %u, size %u for sending\n", type,
223        ntohs (msg->size));
224   GNUNET_CONTAINER_DLL_insert_tail (controller->mq_head, controller->mq_tail,
225                                     mq_entry);
226   if (NULL == controller->th)
227     controller->th = 
228       GNUNET_CLIENT_notify_transmit_ready (controller->client, size,
229                                            GNUNET_TIME_UNIT_FOREVER_REL,
230                                            GNUNET_NO, &transmit_ready_notify,
231                                            controller);
232 }
233
234
235 /**
236  * Start a controller process using the given configuration at the
237  * given host.
238  *
239  * @param cfg configuration to use
240  * @param host host to run the controller on, NULL for 'localhost'
241  * @param event_mask bit mask with set of events to call 'cc' for;
242  *                   or-ed values of "1LL" shifted by the
243  *                   respective 'enum GNUNET_TESTBED_EventType'
244  *                   (i.e.  "(1LL << GNUNET_TESTBED_ET_CONNECT) | ...")
245  * @param cc controller callback to invoke on events
246  * @param cc_cls closure for cc
247  * @return handle to the controller
248  */
249 struct GNUNET_TESTBED_Controller *
250 GNUNET_TESTBED_controller_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
251                                  struct GNUNET_TESTBED_Host *host,
252                                  uint64_t event_mask,
253                                  GNUNET_TESTBED_ControllerCallback cc,
254                                  void *cc_cls)
255 {
256   struct GNUNET_TESTBED_Controller *controller;
257   char * const binary_argv[] = {
258     "gnunet-service-testbed",
259     "gnunet-service-testbed",
260     NULL
261   };
262   struct GNUNET_TESTBED_InitMessage *msg;
263
264   controller = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_Controller));
265   controller->helper = GNUNET_TESTBED_host_run_ (host, binary_argv);
266   if (NULL == controller->helper)
267   {
268     GNUNET_free (controller);
269     return NULL;
270   }
271   controller->host = host;
272   controller->cc = cc;
273   controller->cc_cls = cc_cls;
274   controller->event_mask = event_mask;
275   controller->cfg = GNUNET_CONFIGURATION_dup (cfg);
276   controller->client = GNUNET_CLIENT_connect ("testbed", controller->cfg);
277   if (NULL == controller->client)
278   {
279     GNUNET_TESTBED_controller_stop (controller);
280     return NULL;
281   }  
282   msg = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_InitMessage));
283   msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_INIT);
284   msg->header.size = htons (sizeof (struct GNUNET_TESTBED_InitMessage));
285   msg->host_id = htonl (GNUNET_TESTBED_host_get_id_ (controller->host));
286   msg->event_mask = GNUNET_htonll (controller->event_mask);
287   queue_message (controller, (struct GNUNET_MessageHeader *) msg);
288   return controller;
289 }
290
291
292 /**
293  * Configure shared services at a controller.  Using this function,
294  * you can specify that certain services (such as "resolver")
295  * should not be run for each peer but instead be shared
296  * across N peers on the specified host.  This function
297  * must be called before any peers are created at the host.
298  * 
299  * @param controller controller to configure
300  * @param service_name name of the service to share
301  * @param num_peers number of peers that should share one instance
302  *        of the specified service (1 for no sharing is the default),
303  *        use 0 to disable the service
304  */
305 void
306 GNUNET_TESTBED_controller_configure_sharing (struct GNUNET_TESTBED_Controller *controller,
307                                              const char *service_name,
308                                              uint32_t num_peers)
309 {
310   GNUNET_break (0);
311 }
312
313
314 /**
315  * Stop the given controller (also will terminate all peers and
316  * controllers dependent on this controller).  This function 
317  * blocks until the testbed has been fully terminated (!).
318  *
319  * @param controller handle to controller to stop
320  */
321 void
322 GNUNET_TESTBED_controller_stop (struct GNUNET_TESTBED_Controller *controller)
323 {
324   struct MessageQueue *mq_entry;
325
326   if (NULL != controller->th)
327     GNUNET_CLIENT_notify_transmit_ready_cancel (controller->th);
328   for (mq_entry = controller->mq_head; /* Clear the message queue */
329        NULL != mq_entry; mq_entry = controller->mq_head)
330   {
331     GNUNET_free (mq_entry->msg);
332     GNUNET_free (mq_entry);
333   }
334   if (NULL != controller->client)
335     GNUNET_CLIENT_disconnect (controller->client);
336   GNUNET_TESTBED_host_stop_ (controller->helper);
337   GNUNET_CONFIGURATION_destroy (controller->cfg);
338   GNUNET_free (controller);
339 }
340
341
342 /**
343  * Create a link from a 'master' controller to a slave controller.
344  * Whenever the master controller is asked to start a peer at the
345  * given 'delegated_host', it will delegate the request to the
346  * specified slave controller.  Note that the slave controller runs at
347  * the 'slave_host', which may or may not be the same host as the
348  * 'delegated_host' (for hierarchical delegations).  The configuration
349  * of the slave controller is given and to be used to either create
350  * the slave controller or to connect to an existing slave controller
351  * process.  'is_subordinate' specifies if the given slave controller
352  * should be started and managed by the master controller, or if the
353  * slave already has a master and this is just a secondary master that
354  * is also allowed to use the existing slave.
355  *
356  * @param master handle to the master controller who creates the association
357  * @param delegated_host requests to which host should be delegated
358  * @param slave_host which host is used to run the slave controller 
359  * @param slave_cfg configuration to use for the slave controller
360  * @param is_subordinate GNUNET_YES if the slave should be started (and stopped)
361  *                       by the master controller; GNUNET_NO if we are just
362  *                       allowed to use the slave via TCP/IP
363  */
364 void
365 GNUNET_TESTBED_controller_link (struct GNUNET_TESTBED_Controller *master,
366                                 struct GNUNET_TESTBED_Host *delegated_host,
367                                 struct GNUNET_TESTBED_Host *slave_host,
368                                 const struct GNUNET_CONFIGURATION_Handle *slave_cfg,
369                                 int is_subordinate)
370 {
371   GNUNET_break (0);
372 }
373
374
375 /**
376  * Ask the testbed controller to write the current overlay topology to
377  * a file.  Naturally, the file will only contain a snapshot as the
378  * topology may evolve all the time.
379  *
380  * @param controller overlay controller to inspect
381  * @param filename name of the file the topology should
382  *        be written to.
383  */
384 void
385 GNUNET_TESTBED_overlay_write_topology_to_file (struct GNUNET_TESTBED_Controller *controller,
386                                                const char *filename)
387 {
388   GNUNET_break (0);
389 }
390
391
392
393 /* end of testbed_api.c */