-nicer name
[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
129 /**
130  * Function called to notify a client about the connection begin ready to queue
131  * more data.  "buf" will be NULL and "size" zero if the connection was closed
132  * for writing in the meantime.
133  *
134  * @param cls closure
135  * @param size number of bytes available in buf
136  * @param buf where the callee should write the message
137  * @return number of bytes written to buf
138  */
139 static size_t
140 transmit_ready_notify (void *cls, size_t size, void *buf)
141 {
142   struct GNUNET_TESTBED_Controller *c = cls;
143   struct MessageQueue *mq_entry;
144
145   c->th = NULL;
146   mq_entry = c->mq_head;
147   GNUNET_assert (NULL != mq_entry);
148   GNUNET_assert (ntohs (mq_entry->msg->size) <= size);
149   size = ntohs (mq_entry->msg->size);
150   memcpy (buf, mq_entry->msg, size);
151   GNUNET_free (mq_entry->msg);
152   GNUNET_CONTAINER_DLL_remove (c->mq_head, c->mq_tail, mq_entry);
153   GNUNET_free (mq_entry);
154   mq_entry = c->mq_head;
155   if (NULL != mq_entry)
156     c->th = 
157       GNUNET_CLIENT_notify_transmit_ready (c->client,
158                                            ntohs (mq_entry->msg->size),
159                                            GNUNET_TIME_UNIT_FOREVER_REL,
160                                            GNUNET_NO, &transmit_ready_notify,
161                                            c);
162   return size;
163 }
164
165
166 /**
167  * Queues a message in send queue for sending to the service
168  *
169  * @param controller the handle to the controller
170  * @param msg the message to queue
171  */
172 static void
173 queue_message (struct GNUNET_TESTBED_Controller *controller,
174                struct GNUNET_MessageHeader *msg)
175 {
176   struct MessageQueue *mq_entry;
177   uint16_t type;
178   uint16_t size;
179
180   type = ntohs (msg->type);
181   size = ntohs (msg->size);
182   GNUNET_assert ((GNUNET_MESSAGE_TYPE_TESTBED_INIT <= type) &&
183                  (GNUNET_MESSAGE_TYPE_TESTBED_MAX > type));                 
184   mq_entry = GNUNET_malloc (sizeof (struct MessageQueue));
185   mq_entry->msg = msg;
186   LOG (GNUNET_ERROR_TYPE_DEBUG,
187        "Queueing message of type %u, size %u for sending\n", type,
188        ntohs (msg->size));
189   GNUNET_CONTAINER_DLL_insert_tail (controller->mq_head, controller->mq_tail,
190                                     mq_entry);
191   if (NULL == controller->th)
192     controller->th = 
193       GNUNET_CLIENT_notify_transmit_ready (controller->client, size,
194                                            GNUNET_TIME_UNIT_FOREVER_REL,
195                                            GNUNET_NO, &transmit_ready_notify,
196                                            controller);
197  }
198
199
200 /**
201  * Handler for messages from controller (testbed service)
202  *
203  * @param cls the controller handler
204  * @param msg message received, NULL on timeout or fatal error
205  */
206 static void 
207 message_handler (void *cls, const struct GNUNET_MessageHeader *msg)
208 {
209   struct GNUNET_TESTBED_Controller *c = cls;
210
211   /* FIXME: Add checks for message integrity */
212   switch (ntohs (msg->type))
213   {
214   default:
215     GNUNET_break (0);
216   }
217   GNUNET_CLIENT_receive (c->client, &message_handler, c,
218                          GNUNET_TIME_UNIT_FOREVER_REL);
219 }
220
221
222 /**
223  * ?Callback for messages recevied from server? 
224  *
225  * Do not call GNUNET_SERVER_mst_destroy in callback
226  *
227  * @param cls closure
228  * @param client identification of the client
229  * @param message the actual message
230  *
231  * @return GNUNET_OK on success, GNUNET_SYSERR to stop further processing
232  */
233 static int 
234 server_mst_cb (void *cls, void *client,
235                const struct GNUNET_MessageHeader *message)
236 {
237   struct GNUNET_TESTBED_Controller *c = cls;
238   struct GNUNET_TESTBED_InitMessage *msg;
239   
240   c->client = GNUNET_CLIENT_connect ("testbed", c->cfg);
241   if (NULL == c->client)
242     return GNUNET_SYSERR;       /* FIXME: Call controller startup_cb ? */
243   GNUNET_CLIENT_receive (c->client, &message_handler, c,
244                          GNUNET_TIME_UNIT_FOREVER_REL);
245   msg = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_InitMessage));
246   msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_INIT);
247   msg->header.size = htons (sizeof (struct GNUNET_TESTBED_InitMessage));
248   msg->host_id = htonl (GNUNET_TESTBED_host_get_id_ (c->host));
249   msg->event_mask = GNUNET_htonll (c->event_mask);
250   queue_message (c, (struct GNUNET_MessageHeader *) msg);
251   return GNUNET_OK;
252 }
253
254
255 /**
256  * Start a controller process using the given configuration at the
257  * given host.
258  *
259  * @param cfg configuration to use
260  * @param host host to run the controller on, NULL for 'localhost'
261  * @param event_mask bit mask with set of events to call 'cc' for;
262  *                   or-ed values of "1LL" shifted by the
263  *                   respective 'enum GNUNET_TESTBED_EventType'
264  *                   (i.e.  "(1LL << GNUNET_TESTBED_ET_CONNECT) | ...")
265  * @param cc controller callback to invoke on events
266  * @param cc_cls closure for cc
267  * @return handle to the controller
268  */
269 struct GNUNET_TESTBED_Controller *
270 GNUNET_TESTBED_controller_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
271                                  struct GNUNET_TESTBED_Host *host,
272                                  uint64_t event_mask,
273                                  GNUNET_TESTBED_ControllerCallback cc,
274                                  void *cc_cls)
275 {
276   struct GNUNET_TESTBED_Controller *controller;
277   char * const binary_argv[] = {
278     "gnunet-service-testbed",
279     "gnunet-service-testbed",
280     NULL
281   };
282   controller = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_Controller));
283   controller->helper = GNUNET_TESTBED_host_run_ (host, binary_argv,
284                                                  &server_mst_cb, controller);
285   if (NULL == controller->helper)
286   {
287     GNUNET_free (controller);
288     return NULL;
289   }
290   controller->host = host;
291   controller->cc = cc;
292   controller->cc_cls = cc_cls;
293   controller->event_mask = event_mask;
294   controller->cfg = GNUNET_CONFIGURATION_dup (cfg);
295   return controller;
296 }
297
298
299 /**
300  * Configure shared services at a controller.  Using this function,
301  * you can specify that certain services (such as "resolver")
302  * should not be run for each peer but instead be shared
303  * across N peers on the specified host.  This function
304  * must be called before any peers are created at the host.
305  * 
306  * @param controller controller to configure
307  * @param service_name name of the service to share
308  * @param num_peers number of peers that should share one instance
309  *        of the specified service (1 for no sharing is the default),
310  *        use 0 to disable the service
311  */
312 void
313 GNUNET_TESTBED_controller_configure_sharing (struct GNUNET_TESTBED_Controller *controller,
314                                              const char *service_name,
315                                              uint32_t num_peers)
316 {
317   GNUNET_break (0);
318 }
319
320
321 /**
322  * Stop the given controller (also will terminate all peers and
323  * controllers dependent on this controller).  This function 
324  * blocks until the testbed has been fully terminated (!).
325  *
326  * @param controller handle to controller to stop
327  */
328 void
329 GNUNET_TESTBED_controller_stop (struct GNUNET_TESTBED_Controller *controller)
330 {
331   struct MessageQueue *mq_entry;
332
333   if (NULL != controller->th)
334     GNUNET_CLIENT_notify_transmit_ready_cancel (controller->th);
335   for (mq_entry = controller->mq_head; /* Clear the message queue */
336        NULL != mq_entry; mq_entry = controller->mq_head)
337   {
338     GNUNET_free (mq_entry->msg);
339     GNUNET_free (mq_entry);
340   }
341   GNUNET_CLIENT_disconnect (controller->client);
342   GNUNET_TESTBED_host_stop_ (controller->helper);
343   GNUNET_CONFIGURATION_destroy (controller->cfg);
344   GNUNET_free (controller);
345 }
346
347
348 /**
349  * Create a link from a 'master' controller to a slave controller.
350  * Whenever the master controller is asked to start a peer at the
351  * given 'delegated_host', it will delegate the request to the
352  * specified slave controller.  Note that the slave controller runs at
353  * the 'slave_host', which may or may not be the same host as the
354  * 'delegated_host' (for hierarchical delegations).  The configuration
355  * of the slave controller is given and to be used to either create
356  * the slave controller or to connect to an existing slave controller
357  * process.  'is_subordinate' specifies if the given slave controller
358  * should be started and managed by the master controller, or if the
359  * slave already has a master and this is just a secondary master that
360  * is also allowed to use the existing slave.
361  *
362  * @param master handle to the master controller who creates the association
363  * @param delegated_host requests to which host should be delegated
364  * @param slave_host which host is used to run the slave controller 
365  * @param slave_cfg configuration to use for the slave controller
366  * @param is_subordinate GNUNET_YES if the slave should be started (and stopped)
367  *                       by the master controller; GNUNET_NO if we are just
368  *                       allowed to use the slave via TCP/IP
369  */
370 void
371 GNUNET_TESTBED_controller_link (struct GNUNET_TESTBED_Controller *master,
372                                 struct GNUNET_TESTBED_Host *delegated_host,
373                                 struct GNUNET_TESTBED_Host *slave_host,
374                                 const struct GNUNET_CONFIGURATION_Handle *slave_cfg,
375                                 int is_subordinate)
376 {
377   GNUNET_break (0);
378 }
379
380
381 /**
382  * Ask the testbed controller to write the current overlay topology to
383  * a file.  Naturally, the file will only contain a snapshot as the
384  * topology may evolve all the time.
385  *
386  * @param controller overlay controller to inspect
387  * @param filename name of the file the topology should
388  *        be written to.
389  */
390 void
391 GNUNET_TESTBED_overlay_write_topology_to_file (struct GNUNET_TESTBED_Controller *controller,
392                                                const char *filename)
393 {
394 }
395
396
397
398 /* end of testbed_api.c */