peer destroy with new operations handling
[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  * @author Sree Harsha Totakura
28  */
29
30
31 #include "platform.h"
32 #include "gnunet_testbed_service.h"
33 #include "gnunet_core_service.h"
34 #include "gnunet_constants.h"
35 #include "gnunet_transport_service.h"
36 #include "gnunet_hello_lib.h"
37 #include <zlib.h>
38
39 #include "testbed.h"
40 #include "testbed_api.h"
41 #include "testbed_api_hosts.h"
42 #include "testbed_api_peers.h"
43 #include "testbed_api_operations.h"
44
45 /**
46  * Generic logging shorthand
47  */
48 #define LOG(kind, ...)                          \
49   GNUNET_log_from (kind, "testbed-api", __VA_ARGS__);
50
51 /**
52  * Debug logging
53  */
54 #define LOG_DEBUG(...)                          \
55   LOG (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__);
56
57 /**
58  * Relative time seconds shorthand
59  */
60 #define TIME_REL_SECS(sec) \
61   GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, sec)
62
63
64 /**
65  * Default server message sending retry timeout
66  */
67 #define TIMEOUT_REL TIME_REL_SECS(1)
68
69
70 /**
71  * The message queue for sending messages to the controller service
72  */
73 struct MessageQueue
74 {
75   /**
76    * The message to be sent
77    */
78   struct GNUNET_MessageHeader *msg;
79
80   /**
81    * next pointer for DLL
82    */
83   struct MessageQueue *next;
84   
85   /**
86    * prev pointer for DLL
87    */
88   struct MessageQueue *prev;
89 };
90
91
92 /**
93  * Structure for a controller link
94  */
95 struct ControllerLink
96 {
97   /**
98    * The next ptr for DLL
99    */
100   struct ControllerLink *next;
101
102   /**
103    * The prev ptr for DLL
104    */
105   struct ControllerLink *prev;
106
107   /**
108    * The host which will be referred in the peer start request. This is the
109    * host where the peer should be started
110    */
111   struct GNUNET_TESTBED_Host *delegated_host;
112
113   /**
114    * The host which will contacted to delegate the peer start request
115    */
116   struct GNUNET_TESTBED_Host *slave_host;
117
118   /**
119    * The configuration to be used to connect to slave host
120    */
121   const struct GNUNET_CONFIGURATION_Handle *slave_cfg;
122
123   /**
124    * GNUNET_YES if the slave should be started (and stopped) by us; GNUNET_NO
125    * if we are just allowed to use the slave via TCP/IP
126    */
127   int is_subordinate;
128 };
129
130
131 /**
132  * handle for host registration
133  */
134 struct GNUNET_TESTBED_HostRegistrationHandle
135 {
136   /**
137    * The host being registered
138    */
139   struct GNUNET_TESTBED_Host *host;
140
141   /**
142    * The controller at which this host is being registered
143    */
144   struct GNUNET_TESTBED_Controller *c;
145
146   /**
147    * The Registartion completion callback
148    */
149   GNUNET_TESTBED_HostRegistrationCompletion cc;
150
151   /**
152    * The closure for above callback
153    */
154   void *cc_cls;
155 };
156
157
158 /**
159  * Handler for GNUNET_MESSAGE_TYPE_TESTBED_ADDHOSTCONFIRM message from
160  * controller (testbed service)
161  *
162  * @param c the controller handler
163  * @param msg message received
164  * @return GNUNET_YES if we can continue receiving from service; GNUNET_NO if
165  *           not
166  */
167 static int
168 handle_addhostconfirm (struct GNUNET_TESTBED_Controller *c,
169                        const struct GNUNET_TESTBED_HostConfirmedMessage *msg)
170 {
171   struct GNUNET_TESTBED_HostRegistrationHandle *rh;
172   char *emsg;
173   uint16_t msg_size;
174
175   rh = c->rh;
176   if (NULL == rh)
177   {  
178     return GNUNET_OK;    
179   }
180   if (GNUNET_TESTBED_host_get_id_ (rh->host) != ntohl (msg->host_id))
181   {
182     LOG_DEBUG ("Mismatch in host id's %u, %u of host confirm msg\n",
183                GNUNET_TESTBED_host_get_id_ (rh->host), ntohl (msg->host_id));
184     return GNUNET_OK;
185   }
186   c->rh = NULL;
187   msg_size = ntohs (msg->header.size);
188   if (sizeof (struct GNUNET_TESTBED_HostConfirmedMessage) == msg_size)
189   {
190     LOG_DEBUG ("Host %u successfully registered\n", ntohl (msg->host_id));
191     GNUNET_TESTBED_mark_host_registered_at_  (rh->host, c);
192     rh->cc (rh->cc_cls, NULL);
193     GNUNET_free (rh);
194     return GNUNET_OK;
195   } 
196   /* We have an error message */
197   emsg = (char *) &msg[1];
198   if ('\0' != emsg[msg_size - 
199                    sizeof (struct GNUNET_TESTBED_HostConfirmedMessage)])
200   {
201     GNUNET_break (0);
202     GNUNET_free (rh);
203     return GNUNET_NO;
204   }  
205   LOG (GNUNET_ERROR_TYPE_ERROR, _("Adding host %u failed with error: %s\n"),
206        ntohl (msg->host_id), emsg);
207   rh->cc (rh->cc_cls, emsg);
208   GNUNET_free (rh);
209   return GNUNET_OK;
210 }
211
212
213 /**
214  * Handler for GNUNET_MESSAGE_TYPE_TESTBED_ADDHOSTCONFIRM message from
215  * controller (testbed service)
216  *
217  * @param c the controller handler
218  * @param msg message received
219  * @return GNUNET_YES if we can continue receiving from service; GNUNET_NO if
220  *           not
221  */
222 static int
223 handle_opsuccess (struct GNUNET_TESTBED_Controller *c,
224                   const struct
225                   GNUNET_TESTBED_GenericOperationSuccessEventMessage *msg)
226 {
227   struct OperationContext *opc;
228   struct GNUNET_TESTBED_EventInformation *event;
229   uint64_t op_id;
230   
231   op_id = GNUNET_ntohll (msg->operation_id);
232   LOG_DEBUG ("Operation %ul successful\n", op_id);
233   for (opc = c->ocq_head; NULL != opc; opc = opc->next)
234   {
235     if (opc->id == op_id)
236       break;
237   }
238   if (NULL == opc)
239   {
240     LOG_DEBUG ("Operation not found\n");
241     return GNUNET_YES;
242   }
243   event = NULL;
244   if (0 != (c->event_mask & (1L << GNUNET_TESTBED_ET_OPERATION_FINISHED)))
245     event = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_EventInformation));
246   if (NULL != event)
247     event->type = GNUNET_TESTBED_ET_OPERATION_FINISHED; 
248   switch (opc->type)
249   {
250   case OP_PEER_DESTROY:
251     {
252       struct GNUNET_TESTBED_Peer *peer;
253       
254       if (NULL != event)
255       {
256         event->details.operation_finished.operation = opc->op;
257         event->details.operation_finished.op_cls = NULL;
258         event->details.operation_finished.emsg = NULL;
259         event->details.operation_finished.pit = GNUNET_TESTBED_PIT_GENERIC;
260         event->details.operation_finished.op_result.generic = NULL;
261       }
262       peer = opc->data;
263       GNUNET_free (peer);
264       opc->data = NULL;
265       //PEERDESTROYDATA
266     }
267     break;
268   default:
269     GNUNET_assert (0);
270   }  
271   if (NULL != event)
272   {
273     if (NULL != c->cc)
274       c->cc (c->cc_cls, event);
275     GNUNET_free (event);
276   }
277   return GNUNET_YES;  
278 }
279
280
281 /**
282  * Handler for GNUNET_MESSAGE_TYPE_TESTBED_PEERCREATESUCCESS message from
283  * controller (testbed service)
284  *
285  * @param c the controller handler
286  * @param msg message received
287  * @return GNUNET_YES if we can continue receiving from service; GNUNET_NO if
288  *           not
289  */
290 static int
291 handle_peer_create_success (struct GNUNET_TESTBED_Controller *c,
292                             const struct
293                             GNUNET_TESTBED_PeerCreateSuccessEventMessage *msg)
294 {
295   struct OperationContext *opc;
296   struct PeerCreateData *data;
297   struct GNUNET_TESTBED_Peer *peer;
298   GNUNET_TESTBED_PeerCreateCallback cb;
299   void *cls;
300   uint64_t op_id;
301
302   GNUNET_assert (sizeof (struct GNUNET_TESTBED_PeerCreateSuccessEventMessage)
303                  == ntohs (msg->header.size));
304   op_id = GNUNET_ntohll (msg->operation_id);
305   for (opc = c->ocq_head; NULL != opc; opc = opc->next)
306   {
307     if (opc->id == op_id)
308       break;
309   }
310   if (NULL == opc)
311   {
312     LOG_DEBUG ("Operation context for PeerCreateSuccessEvent not found\n");
313     return GNUNET_YES;
314   }
315   GNUNET_assert (OP_PEER_CREATE == opc->type);
316   GNUNET_assert (NULL != opc->data);
317   data = opc->data;
318   GNUNET_assert (NULL != data->peer);
319   peer = data->peer;
320   GNUNET_assert (peer->unique_id == ntohl (msg->peer_id));
321   peer->state = PS_CREATED;
322   cb = data->cb;
323   cls = data->cls;  
324   if (NULL != cb)
325     cb (cls, peer, NULL);
326   return GNUNET_YES;
327 }
328
329
330 /**
331  * Handler for GNUNET_MESSAGE_TYPE_TESTBED_PEEREVENT message from
332  * controller (testbed service)
333  *
334  * @param c the controller handler
335  * @param msg message received
336  * @return GNUNET_YES if we can continue receiving from service; GNUNET_NO if
337  *           not
338  */
339 static int
340 handle_peer_event (struct GNUNET_TESTBED_Controller *c,
341                    const struct GNUNET_TESTBED_PeerEventMessage *msg)
342 {
343   struct GNUNET_TESTBED_Operation *op;
344   struct GNUNET_TESTBED_Peer *peer;
345   struct GNUNET_TESTBED_EventInformation event;
346   uint64_t op_id;
347
348   GNUNET_assert (sizeof (struct GNUNET_TESTBED_PeerEventMessage)
349                  == ntohs (msg->header.size));
350   op_id = GNUNET_ntohll (msg->operation_id);
351   for (op = c->op_head; NULL != op; op = op->next)
352   {
353     if (op->operation_id == op_id)
354       break;
355   }
356   if (NULL == op)
357   {
358     LOG_DEBUG ("Operation not found\n");
359     return GNUNET_YES;
360   }
361   GNUNET_assert ((OP_PEER_START == op->type) || (OP_PEER_STOP == op->type));
362   peer = op->data;
363   GNUNET_assert (NULL != peer);
364   event.type = (enum GNUNET_TESTBED_EventType) ntohl (msg->event_type);
365   switch (event.type)
366   {
367   case GNUNET_TESTBED_ET_PEER_START:
368     peer->state = PS_STARTED;
369     event.details.peer_start.host = peer->host;
370     event.details.peer_start.peer = peer;
371     break;
372   case GNUNET_TESTBED_ET_PEER_STOP:
373     peer->state = PS_STOPPED;    
374     event.details.peer_stop.peer = peer;  
375     break;
376   default:
377     GNUNET_assert (0);          /* We should never reach this state */
378   }
379   GNUNET_CONTAINER_DLL_remove (c->op_head, c->op_tail, op);
380   if (0 != ((GNUNET_TESTBED_ET_PEER_START | GNUNET_TESTBED_ET_PEER_STOP)
381             & c->event_mask))
382   {
383     if (NULL != c->cc)
384       c->cc (c->cc_cls, &event);
385   }
386   return GNUNET_YES;
387 }
388
389
390 /**
391  * Handler for GNUNET_MESSAGE_TYPE_TESTBED_PEERCONFIG message from
392  * controller (testbed service)
393  *
394  * @param c the controller handler
395  * @param msg message received
396  * @return GNUNET_YES if we can continue receiving from service; GNUNET_NO if
397  *           not
398  */
399 static int
400 handle_peer_config (struct GNUNET_TESTBED_Controller *c,
401                     const struct GNUNET_TESTBED_PeerConfigurationInformationMessage *msg)
402 {
403   struct GNUNET_TESTBED_Operation *op;
404   struct GNUNET_TESTBED_Peer *peer;
405   struct PeerInfoData *data;
406   struct PeerInfoData2 *response_data;
407   struct GNUNET_TESTBED_EventInformation info;
408   uint64_t op_id;
409   
410   op_id = GNUNET_ntohll (msg->operation_id);
411   for (op = c->op_head; NULL != op; op = op->next)
412   {
413     if (op->operation_id == op_id)
414       break;
415   }
416   if (NULL == op)
417   {
418     LOG_DEBUG ("Operation not found");
419     return GNUNET_YES;
420   }
421   data = op->data;
422   GNUNET_assert (NULL != data);
423   peer = data->peer;
424   GNUNET_assert (NULL != peer);
425   GNUNET_assert (ntohl (msg->peer_id) == peer->unique_id);
426   if (0 == (c->event_mask & (1L << GNUNET_TESTBED_ET_OPERATION_FINISHED)))
427   {
428     LOG_DEBUG ("Skipping operation callback as flag not set\n");
429     GNUNET_CONTAINER_DLL_remove (c->op_head, c->op_tail, op);
430     return GNUNET_YES;
431   }
432   response_data = GNUNET_malloc (sizeof (struct PeerInfoData2));
433   response_data->pit = data->pit;
434   GNUNET_free (data);
435   info.type = GNUNET_TESTBED_ET_OPERATION_FINISHED;
436   info.details.operation_finished.operation = op;
437   info.details.operation_finished.op_cls = NULL;
438   info.details.operation_finished.emsg = NULL;
439   info.details.operation_finished.pit = response_data->pit;
440   switch (response_data->pit)
441   {
442   case GNUNET_TESTBED_PIT_IDENTITY:
443     {
444       struct GNUNET_PeerIdentity *peer_identity;
445
446       peer_identity = GNUNET_malloc (sizeof (struct GNUNET_PeerIdentity));
447       (void) memcpy (peer_identity, &msg->peer_identity, 
448                      sizeof (struct GNUNET_PeerIdentity));
449       response_data->details.peer_identity = peer_identity;      
450       info.details.operation_finished.op_result.pid = peer_identity;
451     }
452     break;
453   case GNUNET_TESTBED_PIT_CONFIGURATION:
454     {
455       struct GNUNET_CONFIGURATION_Handle *cfg;
456       char *config;
457       uLong config_size;
458       int ret;
459       uint16_t msize;
460       
461       config_size = (uLong) ntohs (msg->config_size);
462       config = GNUNET_malloc (config_size);
463       msize = ntohs (msg->header.size);
464       msize -= sizeof (struct GNUNET_TESTBED_PeerConfigurationInformationMessage);
465       if (Z_OK != (ret = uncompress ((Bytef *) config, &config_size,
466                                      (const Bytef *) &msg[1], (uLong) msize)))
467         GNUNET_assert (0);
468       cfg = GNUNET_CONFIGURATION_create ();
469       GNUNET_assert (GNUNET_OK == 
470                      GNUNET_CONFIGURATION_deserialize (cfg, config,
471                                                        (size_t) config_size,
472                                                        GNUNET_NO));
473       GNUNET_free (config);
474       response_data->details.cfg = cfg;
475       info.details.operation_finished.op_result.cfg = cfg;
476     }
477     break;
478   case GNUNET_TESTBED_PIT_GENERIC:
479     GNUNET_assert (0);          /* never reach here */
480     break;
481   }
482   op->data = response_data;
483   GNUNET_CONTAINER_DLL_remove (c->op_head, c->op_tail, op);
484   c->cc (c->cc_cls, &info);
485   return GNUNET_YES;
486 }
487
488
489 /**
490  * Handler for messages from controller (testbed service)
491  *
492  * @param cls the controller handler
493  * @param msg message received, NULL on timeout or fatal error
494  */
495 static void 
496 message_handler (void *cls, const struct GNUNET_MessageHeader *msg)
497 {
498   struct GNUNET_TESTBED_Controller *c = cls;
499   int status;
500   uint16_t msize;
501
502   c->in_receive = GNUNET_NO;
503   /* FIXME: Add checks for message integrity */
504   if (NULL == msg)
505   {
506     LOG_DEBUG ("Receive timed out or connection to service dropped\n");
507     return;
508   }
509   status = GNUNET_OK;
510   msize = ntohs (msg->size);
511   switch (ntohs (msg->type))
512   {
513   case GNUNET_MESSAGE_TYPE_TESTBED_ADDHOSTCONFIRM:
514     GNUNET_assert (msize >= sizeof (struct
515                                     GNUNET_TESTBED_HostConfirmedMessage));
516     status =
517       handle_addhostconfirm (c, (const struct GNUNET_TESTBED_HostConfirmedMessage *) msg);
518     break;
519   case GNUNET_MESSAGE_TYPE_TESTBED_GENERICOPSUCCESS:
520     GNUNET_assert 
521       (msize == sizeof (struct GNUNET_TESTBED_GenericOperationSuccessEventMessage));
522     status =
523       handle_opsuccess (c, (const struct
524                             GNUNET_TESTBED_GenericOperationSuccessEventMessage
525                             *) msg);
526     break;
527   case GNUNET_MESSAGE_TYPE_TESTBED_PEERCREATESUCCESS:
528     GNUNET_assert (msize == 
529                    sizeof (struct GNUNET_TESTBED_PeerCreateSuccessEventMessage));
530     status =
531       handle_peer_create_success 
532       (c, (const struct GNUNET_TESTBED_PeerCreateSuccessEventMessage *)msg);
533     break;
534   case GNUNET_MESSAGE_TYPE_TESTBED_PEEREVENT:
535     GNUNET_assert (msize == sizeof (struct GNUNET_TESTBED_PeerEventMessage));
536     status =
537       handle_peer_event (c, (const struct GNUNET_TESTBED_PeerEventMessage *) msg);
538     
539     break;
540   case GNUNET_MESSAGE_TYPE_TESTBED_PEERCONFIG:
541     GNUNET_assert (msize >= 
542                    sizeof (struct GNUNET_TESTBED_PeerConfigurationInformationMessage));
543     status = 
544       handle_peer_config 
545       (c, (const struct GNUNET_TESTBED_PeerConfigurationInformationMessage *)
546   msg);
547     break;
548   default:
549     GNUNET_break (0);
550   }
551   if ((GNUNET_OK == status) && (GNUNET_NO == c->in_receive))
552   {
553     c->in_receive = GNUNET_YES;
554     GNUNET_CLIENT_receive (c->client, &message_handler, c,
555                            GNUNET_TIME_UNIT_FOREVER_REL);    
556   }
557 }
558
559
560 /**
561  * Function called to notify a client about the connection begin ready to queue
562  * more data.  "buf" will be NULL and "size" zero if the connection was closed
563  * for writing in the meantime.
564  *
565  * @param cls closure
566  * @param size number of bytes available in buf
567  * @param buf where the callee should write the message
568  * @return number of bytes written to buf
569  */
570 static size_t
571 transmit_ready_notify (void *cls, size_t size, void *buf)
572 {
573   struct GNUNET_TESTBED_Controller *c = cls;
574   struct MessageQueue *mq_entry;
575
576   c->th = NULL;
577   mq_entry = c->mq_head;
578   GNUNET_assert (NULL != mq_entry);
579   if ((0 == size) && (NULL == buf)) /* Timeout */
580   {
581     LOG_DEBUG ("Message sending timed out -- retrying\n");
582     c->th =
583       GNUNET_CLIENT_notify_transmit_ready (c->client,
584                                            ntohs (mq_entry->msg->size),
585                                            TIMEOUT_REL,
586                                            GNUNET_YES, &transmit_ready_notify,
587                                            c);
588     return 0;
589   }
590   GNUNET_assert (ntohs (mq_entry->msg->size) <= size);
591   size = ntohs (mq_entry->msg->size);  
592   memcpy (buf, mq_entry->msg, size);
593   LOG_DEBUG ("Message of type: %u and size: %u sent\n",
594              ntohs (mq_entry->msg->type), size);
595   GNUNET_free (mq_entry->msg);
596   GNUNET_CONTAINER_DLL_remove (c->mq_head, c->mq_tail, mq_entry);
597   GNUNET_free (mq_entry);
598   mq_entry = c->mq_head;
599   if (NULL != mq_entry)
600     c->th = 
601       GNUNET_CLIENT_notify_transmit_ready (c->client,
602                                            ntohs (mq_entry->msg->size),
603                                            TIMEOUT_REL,
604                                            GNUNET_YES, &transmit_ready_notify,
605                                            c);
606   if (GNUNET_NO == c->in_receive)
607   {
608     c->in_receive = GNUNET_YES;
609     GNUNET_CLIENT_receive (c->client, &message_handler, c,
610                            GNUNET_TIME_UNIT_FOREVER_REL);
611   }
612   return size;
613 }
614
615
616 /**
617  * Queues a message in send queue for sending to the service
618  *
619  * @param controller the handle to the controller
620  * @param msg the message to queue
621  */
622 void
623 GNUNET_TESTBED_queue_message_ (struct GNUNET_TESTBED_Controller *controller,
624                                struct GNUNET_MessageHeader *msg)
625 {
626   struct MessageQueue *mq_entry;
627   uint16_t type;
628   uint16_t size;
629
630   type = ntohs (msg->type);
631   size = ntohs (msg->size);
632   GNUNET_assert ((GNUNET_MESSAGE_TYPE_TESTBED_INIT <= type) &&
633                  (GNUNET_MESSAGE_TYPE_TESTBED_MAX > type));                 
634   mq_entry = GNUNET_malloc (sizeof (struct MessageQueue));
635   mq_entry->msg = msg;
636   LOG (GNUNET_ERROR_TYPE_DEBUG,
637        "Queueing message of type %u, size %u for sending\n", type,
638        ntohs (msg->size));
639   GNUNET_CONTAINER_DLL_insert_tail (controller->mq_head, controller->mq_tail,
640                                     mq_entry);
641   if (NULL == controller->th)
642     controller->th = 
643       GNUNET_CLIENT_notify_transmit_ready (controller->client, size,
644                                            TIMEOUT_REL,
645                                            GNUNET_YES, &transmit_ready_notify,
646                                            controller);
647 }
648
649
650 /**
651  * Handle for controller process
652  */
653 struct GNUNET_TESTBED_ControllerProc
654 {
655   /**
656    * The process handle
657    */
658   struct GNUNET_HELPER_Handle *helper;
659
660   /**
661    * The host where the helper is run
662    */
663   struct GNUNET_TESTBED_Host *host;
664
665   /**
666    * The controller error callback
667    */
668   GNUNET_TESTBED_ControllerStatusCallback cb;
669
670   /**
671    * The closure for the above callback
672    */
673   void *cls;
674
675   /**
676    * The send handle for the helper
677    */
678   struct GNUNET_HELPER_SendHandle *shandle;
679
680   /**
681    * The message corresponding to send handle
682    */
683   struct GNUNET_MessageHeader *msg;
684
685   /**
686    * The port number for ssh; used for helpers starting ssh
687    */
688   char *port;
689
690   /**
691    * The ssh destination string; used for helpers starting ssh
692    */
693   char *dst;
694
695   /**
696    * The configuration of the running testbed service
697    */
698   struct GNUNET_CONFIGURATION_Handle *cfg;
699
700 };
701
702
703 /**
704  * Functions with this signature are called whenever a
705  * complete message is received by the tokenizer.
706  *
707  * Do not call GNUNET_SERVER_mst_destroy in callback
708  *
709  * @param cls closure
710  * @param client identification of the client
711  * @param message the actual message
712  *
713  * @return GNUNET_OK on success, GNUNET_SYSERR to stop further processing
714  */
715 static int helper_mst (void *cls, void *client,
716                        const struct GNUNET_MessageHeader *message)
717 {
718   struct GNUNET_TESTBED_ControllerProc *cp = cls;
719   const struct GNUNET_TESTBED_HelperReply *msg;
720   const char *hostname;
721   char *config;
722   uLongf config_size;
723   uLongf xconfig_size;
724     
725   msg = (const struct GNUNET_TESTBED_HelperReply *) message;
726   GNUNET_assert (sizeof (struct GNUNET_TESTBED_HelperReply) 
727                  < ntohs (msg->header.size));
728   GNUNET_assert (GNUNET_MESSAGE_TYPE_TESTBED_HELPER_REPLY 
729                  == ntohs (msg->header.type));
730   config_size = (uLongf) ntohs (msg->config_size);
731   xconfig_size = (uLongf) (ntohs (msg->header.size)
732                            - sizeof (struct GNUNET_TESTBED_HelperReply));
733   config = GNUNET_malloc (config_size);
734   GNUNET_assert (Z_OK == uncompress ((Bytef *) config, &config_size,
735                                      (const Bytef *) &msg[1], xconfig_size));
736   GNUNET_assert (NULL == cp->cfg);
737   cp->cfg = GNUNET_CONFIGURATION_create ();
738   GNUNET_assert (GNUNET_CONFIGURATION_deserialize (cp->cfg, config, 
739                                                    config_size, GNUNET_NO));
740   GNUNET_free (config);
741   if ((NULL == cp->host) || 
742       (NULL == (hostname = GNUNET_TESTBED_host_get_hostname_ (cp->host))))
743     hostname = "localhost";
744   /* Change the hostname so that we can connect to it */
745   GNUNET_CONFIGURATION_set_value_string (cp->cfg, "testbed", "hostname", 
746                                          hostname);
747   cp->cb (cp->cls, cp->cfg, GNUNET_OK);
748   return GNUNET_OK;
749 }
750
751
752 /**
753  * Continuation function from GNUNET_HELPER_send()
754  * 
755  * @param cls closure
756  * @param result GNUNET_OK on success,
757  *               GNUNET_NO if helper process died
758  *               GNUNET_SYSERR during GNUNET_HELPER_stop
759  */
760 static void 
761 clear_msg (void *cls, int result)
762 {
763   struct GNUNET_TESTBED_ControllerProc *cp = cls;
764   
765   GNUNET_assert (NULL != cp->shandle);
766   cp->shandle = NULL;
767   GNUNET_free (cp->msg);
768 }
769
770
771 /**
772  * Callback that will be called when the helper process dies. This is not called
773  * when the helper process is stoped using GNUNET_HELPER_stop()
774  *
775  * @param cls the closure from GNUNET_HELPER_start()
776  */
777 static void 
778 helper_exp_cb (void *cls)
779 {
780   struct GNUNET_TESTBED_ControllerProc *cp = cls;
781   GNUNET_TESTBED_ControllerStatusCallback cb;
782   void *cb_cls;
783
784   cb = cp->cb;
785   cb_cls = cp->cls;
786   GNUNET_TESTBED_controller_stop (cp);
787   if (NULL != cb)
788     cb (cb_cls, NULL, GNUNET_SYSERR);
789 }
790
791
792 /**
793  * Starts a controller process at the host. FIXME: add controller start callback
794  * with the configuration with which the controller is started
795  *
796  * @param controller_ip the ip address of the controller. Will be set as TRUSTED
797  *          host when starting testbed controller at host
798  * @param host the host where the controller has to be started; NULL for
799  *          localhost
800  * @param cfg template configuration to use for the remote controller; the
801  *          remote controller will be started with a slightly modified
802  *          configuration (port numbers, unix domain sockets and service home
803  *          values are changed as per TESTING library on the remote host)
804  * @param cb function called when the controller is successfully started or
805  *          dies unexpectedly; GNUNET_TESTBED_controller_stop shouldn't be
806  *          called if cb is called with GNUNET_SYSERR as status. Will never be
807  *          called in the same task as 'GNUNET_TESTBED_controller_start'
808  *          (synchronous errors will be signalled by returning NULL). This
809  *          parameter cannot be NULL.
810  * @param cls closure for above callbacks
811  * @return the controller process handle, NULL on errors
812  */
813 struct GNUNET_TESTBED_ControllerProc *
814 GNUNET_TESTBED_controller_start (const char *controller_ip,
815                                  struct GNUNET_TESTBED_Host *host,
816                                  const struct GNUNET_CONFIGURATION_Handle *cfg,
817                                  GNUNET_TESTBED_ControllerStatusCallback cb,
818                                  void *cls)
819 {
820   struct GNUNET_TESTBED_ControllerProc *cp;
821   struct GNUNET_TESTBED_HelperInit *msg;
822   
823   cp = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_ControllerProc));
824   if ((NULL == host) || (0 == GNUNET_TESTBED_host_get_id_ (host)))
825   {
826     char * const binary_argv[] = {
827       "gnunet-testbed-helper", NULL
828     };
829
830     cp->helper = GNUNET_HELPER_start ("gnunet-testbed-helper", binary_argv, 
831                                       &helper_mst, &helper_exp_cb, cp);
832   }
833   else
834   {
835     char *remote_args[6 + 1];
836     unsigned int argp;
837     const char *username;
838     const char *hostname;
839
840     username = GNUNET_TESTBED_host_get_username_ (host);
841     hostname = GNUNET_TESTBED_host_get_hostname_ (host);
842     GNUNET_asprintf (&cp->port, "%u", GNUNET_TESTBED_host_get_ssh_port_ (host));
843     if (NULL == username)
844       GNUNET_asprintf (&cp->dst, "%s", hostname);
845     else 
846       GNUNET_asprintf (&cp->dst, "%s@%s", hostname, username);
847     argp = 0;
848     remote_args[argp++] = "ssh";
849     remote_args[argp++] = "-p";
850     remote_args[argp++] = cp->port;
851     remote_args[argp++] = "-q";
852     remote_args[argp++] = cp->dst;
853     remote_args[argp++] = "gnunet-testbed-helper";
854     remote_args[argp++] = NULL;
855     GNUNET_assert (argp == 6 + 1);
856     cp->helper = GNUNET_HELPER_start ("ssh", remote_args,
857                                       &helper_mst, &helper_exp_cb, cp);
858   }
859   if (NULL == cp->helper)
860   {
861     GNUNET_free_non_null (cp->port);
862     GNUNET_free_non_null (cp->dst);
863     GNUNET_free (cp);
864     return NULL;
865   }
866   cp->host = host;
867   cp->cb = cb;
868   cp->cls = cls;
869   msg = GNUNET_TESTBED_create_helper_init_msg_ (controller_ip, cfg);
870   cp->msg = &msg->header;
871   cp->shandle = GNUNET_HELPER_send (cp->helper, &msg->header, GNUNET_NO,
872                                     &clear_msg, cp);
873   if (NULL == cp->shandle)
874   {
875     GNUNET_free (msg);
876     GNUNET_TESTBED_controller_stop (cp);
877     return NULL;
878   }
879   return cp;
880 }
881
882
883 /**
884  * Stop the controller process (also will terminate all peers and controllers
885  * dependent on this controller).  This function blocks until the testbed has
886  * been fully terminated (!).
887  *
888  * @param cproc the controller process handle
889  */
890 void
891 GNUNET_TESTBED_controller_stop (struct GNUNET_TESTBED_ControllerProc *cproc)
892 {
893   if (NULL != cproc->shandle)
894     GNUNET_HELPER_send_cancel (cproc->shandle);
895   GNUNET_HELPER_stop (cproc->helper);
896   if (NULL != cproc->cfg)
897     GNUNET_CONFIGURATION_destroy (cproc->cfg);
898   GNUNET_free_non_null (cproc->port);
899   GNUNET_free_non_null (cproc->dst);
900   GNUNET_free (cproc);
901 }
902
903
904 /**
905  * Start a controller process using the given configuration at the
906  * given host.
907  *
908  * @param cfg configuration to use
909  * @param host host to run the controller on; This should be the same host if
910  *          the controller was previously started with
911  *          GNUNET_TESTBED_controller_start; NULL for localhost
912  * @param event_mask bit mask with set of events to call 'cc' for;
913  *                   or-ed values of "1LL" shifted by the
914  *                   respective 'enum GNUNET_TESTBED_EventType'
915  *                   (i.e.  "(1LL << GNUNET_TESTBED_ET_CONNECT) | ...")
916  * @param cc controller callback to invoke on events
917  * @param cc_cls closure for cc
918  * @return handle to the controller
919  */
920 struct GNUNET_TESTBED_Controller *
921 GNUNET_TESTBED_controller_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
922                                    struct GNUNET_TESTBED_Host *host,
923                                    uint64_t event_mask,
924                                    GNUNET_TESTBED_ControllerCallback cc,
925                                    void *cc_cls)
926 {
927   struct GNUNET_TESTBED_Controller *controller;
928   struct GNUNET_TESTBED_InitMessage *msg;
929   unsigned long long max_parallel_peer_create;
930
931   if (GNUNET_OK !=
932       GNUNET_CONFIGURATION_get_value_number (cfg, "testbed",
933                                              "MAX_PARALLEL_PEER_CREATE",
934                                              &max_parallel_peer_create))
935   {
936     GNUNET_break (0);
937     return NULL;
938   }                                                          
939   controller = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_Controller));
940   controller->cc = cc;
941   controller->cc_cls = cc_cls;
942   controller->event_mask = event_mask;
943   controller->cfg = GNUNET_CONFIGURATION_dup (cfg);
944   controller->client = GNUNET_CLIENT_connect ("testbed", controller->cfg);  
945   if (NULL == controller->client)
946   {
947     GNUNET_TESTBED_controller_disconnect (controller);
948     return NULL;
949   }
950   if (NULL == host)
951   {
952     host = GNUNET_TESTBED_host_create_by_id_ (0);
953     if (NULL == host)
954     {
955       LOG (GNUNET_ERROR_TYPE_WARNING,
956            "Treating NULL host as localhost. Multiple references to localhost "
957            "may break when localhost freed before calling disconnect \n");
958       host = GNUNET_TESTBED_host_lookup_by_id_ (0);
959     }
960     else
961     {
962       controller->aux_host = GNUNET_YES;
963     }
964   }
965   GNUNET_assert (NULL != host);
966   controller->opq_peer_create =
967     GNUNET_TESTBED_operation_queue_create_ ((unsigned int)
968                                             max_parallel_peer_create);
969   msg = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_InitMessage));
970   msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_INIT);
971   msg->header.size = htons (sizeof (struct GNUNET_TESTBED_InitMessage));
972   msg->host_id = htonl (GNUNET_TESTBED_host_get_id_ (host));
973   msg->event_mask = GNUNET_htonll (controller->event_mask);
974   GNUNET_TESTBED_queue_message_ (controller, (struct GNUNET_MessageHeader *)
975                                  msg);
976   
977   return controller;
978 }
979
980
981 /**
982  * Configure shared services at a controller.  Using this function,
983  * you can specify that certain services (such as "resolver")
984  * should not be run for each peer but instead be shared
985  * across N peers on the specified host.  This function
986  * must be called before any peers are created at the host.
987  * 
988  * @param controller controller to configure
989  * @param service_name name of the service to share
990  * @param num_peers number of peers that should share one instance
991  *        of the specified service (1 for no sharing is the default),
992  *        use 0 to disable the service
993  */
994 void
995 GNUNET_TESTBED_controller_configure_sharing (struct GNUNET_TESTBED_Controller *controller,
996                                              const char *service_name,
997                                              uint32_t num_peers)
998 {
999   struct GNUNET_TESTBED_ConfigureSharedServiceMessage *msg;
1000   uint16_t service_name_size;
1001   uint16_t msg_size;
1002   
1003   service_name_size = strlen (service_name) + 1;
1004   msg_size = sizeof (struct GNUNET_TESTBED_ConfigureSharedServiceMessage)
1005     + service_name_size;
1006   msg = GNUNET_malloc (msg_size);
1007   msg->header.size = htons (msg_size);
1008   msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_SERVICESHARE);
1009   msg->host_id = htonl (GNUNET_TESTBED_host_get_id_ (controller->host));
1010   msg->num_peers = htonl (num_peers);
1011   memcpy (&msg[1], service_name, service_name_size);
1012   GNUNET_TESTBED_queue_message_ (controller, (struct GNUNET_MessageHeader *) msg);
1013 }
1014
1015
1016 /**
1017  * disconnects from the controller.
1018  *
1019  * @param controller handle to controller to stop
1020  */
1021 void
1022 GNUNET_TESTBED_controller_disconnect (struct GNUNET_TESTBED_Controller *controller)
1023 {
1024   struct MessageQueue *mq_entry;
1025
1026   if (NULL != controller->th)
1027     GNUNET_CLIENT_notify_transmit_ready_cancel (controller->th);
1028  /* Clear the message queue */
1029   while (NULL != (mq_entry = controller->mq_head))
1030   {
1031     GNUNET_CONTAINER_DLL_remove (controller->mq_head,
1032                                  controller->mq_tail,
1033                                  mq_entry);
1034     GNUNET_free (mq_entry->msg);
1035     GNUNET_free (mq_entry);
1036   }
1037   if (NULL != controller->client)
1038     GNUNET_CLIENT_disconnect (controller->client);
1039   GNUNET_CONFIGURATION_destroy (controller->cfg);
1040   if (GNUNET_YES == controller->aux_host)
1041     GNUNET_TESTBED_host_destroy (controller->host);
1042   GNUNET_TESTBED_operation_queue_destroy_ (controller->opq_peer_create);
1043   GNUNET_free (controller);
1044 }
1045
1046
1047 /**
1048  * Register a host with the controller
1049  *
1050  * @param controller the controller handle
1051  * @param host the host to register
1052  * @param cc the completion callback to call to inform the status of
1053  *          registration. After calling this callback the registration handle
1054  *          will be invalid. Cannot be NULL.
1055  * @param cc_cls the closure for the cc
1056  * @return handle to the host registration which can be used to cancel the
1057  *           registration 
1058  */
1059 struct GNUNET_TESTBED_HostRegistrationHandle *
1060 GNUNET_TESTBED_register_host (struct GNUNET_TESTBED_Controller *controller,
1061                               struct GNUNET_TESTBED_Host *host,
1062                               GNUNET_TESTBED_HostRegistrationCompletion cc,
1063                               void *cc_cls)
1064 {
1065   struct GNUNET_TESTBED_HostRegistrationHandle *rh;
1066   struct GNUNET_TESTBED_AddHostMessage *msg;
1067   const char *username;
1068   const char *hostname;
1069   uint16_t msg_size;
1070   uint16_t user_name_length;
1071
1072   if (NULL != controller->rh)
1073     return NULL;
1074   hostname = GNUNET_TESTBED_host_get_hostname_ (host);
1075   if (GNUNET_YES == GNUNET_TESTBED_is_host_registered_ (host, controller))
1076   {
1077     LOG (GNUNET_ERROR_TYPE_WARNING,
1078          "Host hostname: %s already registered\n",
1079          (NULL == hostname) ? "localhost" : hostname);
1080     return NULL;
1081   }  
1082   rh = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_HostRegistrationHandle));
1083   rh->host = host;
1084   rh->c = controller;
1085   GNUNET_assert (NULL != cc);
1086   rh->cc = cc;
1087   rh->cc_cls = cc_cls;
1088   controller->rh = rh;
1089   username = GNUNET_TESTBED_host_get_username_ (host);
1090   msg_size = (sizeof (struct GNUNET_TESTBED_AddHostMessage));
1091   user_name_length = 0;
1092   if (NULL != username)
1093   {
1094     user_name_length = strlen (username) + 1;
1095     msg_size += user_name_length;
1096   }
1097   /* FIXME: what happens when hostname is NULL? localhost */
1098   GNUNET_assert (NULL != hostname);
1099   msg_size += strlen (hostname) + 1;
1100   msg = GNUNET_malloc (msg_size);
1101   msg->header.size = htons (msg_size);
1102   msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST);
1103   msg->host_id = htonl (GNUNET_TESTBED_host_get_id_ (host));
1104   msg->ssh_port = htons (GNUNET_TESTBED_host_get_ssh_port_ (host));
1105   msg->user_name_length = htons (user_name_length);
1106   if (NULL != username)
1107     memcpy (&msg[1], username, user_name_length);
1108   strcpy (((void *) &msg[1]) + user_name_length, hostname);
1109   GNUNET_TESTBED_queue_message_ (controller, (struct GNUNET_MessageHeader *) msg);
1110   return rh;
1111 }
1112
1113
1114 /**
1115  * Cancel the pending registration. Note that if the registration message is
1116  * already sent to the service the cancellation has only the effect that the
1117  * registration completion callback for the registration is never called.
1118  *
1119  * @param handle the registration handle to cancel
1120  */
1121 void
1122 GNUNET_TESTBED_cancel_registration (struct GNUNET_TESTBED_HostRegistrationHandle
1123                                     *handle)
1124 {
1125   if (handle != handle->c->rh)
1126   {
1127     GNUNET_break (0);
1128     return;
1129   }
1130   handle->c->rh = NULL;
1131   GNUNET_free (handle);  
1132 }
1133
1134
1135 /**
1136  * Same as the GNUNET_TESTBED_controller_link, however expects configuration in
1137  * serialized and compressed
1138  *
1139  * @param master handle to the master controller who creates the association
1140  * @param delegated_host requests to which host should be delegated; cannot be NULL
1141  * @param slave_host which host is used to run the slave controller; use NULL to
1142  *          make the master controller connect to the delegated host
1143  * @param sxcfg serialized and compressed configuration
1144  * @param sxcfg_size the size scfg
1145  * @param scfg_size the size of uncompressed serialized configuration
1146  * @param is_subordinate GNUNET_YES if the controller at delegated_host should
1147  *          be started by the master controller; GNUNET_NO if we are just
1148  *          allowed to use the slave via TCP/IP
1149  */
1150 void
1151 GNUNET_TESTBED_controller_link_2 (struct GNUNET_TESTBED_Controller *master,
1152                                   struct GNUNET_TESTBED_Host *delegated_host,
1153                                   struct GNUNET_TESTBED_Host *slave_host,
1154                                   const char *sxcfg,
1155                                   size_t sxcfg_size,
1156                                   size_t scfg_size,
1157                                   int is_subordinate)
1158 {
1159   struct GNUNET_TESTBED_ControllerLinkMessage *msg;
1160   uint16_t msg_size;
1161
1162   GNUNET_assert (GNUNET_YES == 
1163                  GNUNET_TESTBED_is_host_registered_ (delegated_host, master));
1164   if ((NULL != slave_host) && (0 != GNUNET_TESTBED_host_get_id_ (slave_host)))
1165     GNUNET_assert (GNUNET_YES == 
1166                    GNUNET_TESTBED_is_host_registered_ (slave_host, master));
1167   msg_size = sxcfg_size + sizeof (struct GNUNET_TESTBED_ControllerLinkMessage);
1168   msg = GNUNET_malloc (msg_size);
1169   msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_LCONTROLLERS);  
1170   msg->header.size = htons (msg_size);
1171   msg->delegated_host_id = htonl (GNUNET_TESTBED_host_get_id_ (delegated_host));
1172   msg->slave_host_id = htonl (GNUNET_TESTBED_host_get_id_ 
1173                               ((NULL != slave_host) ? slave_host : master->host));
1174   msg->config_size = htons ((uint16_t) scfg_size);
1175   msg->is_subordinate = (GNUNET_YES == is_subordinate) ? 1 : 0;
1176   memcpy (&msg[1], sxcfg, sxcfg_size);
1177   GNUNET_TESTBED_queue_message_ (master, (struct GNUNET_MessageHeader *) msg);
1178 }
1179
1180
1181 /**
1182  * Compresses given configuration using zlib compress
1183  *
1184  * @param config the serialized configuration
1185  * @param size the size of config
1186  * @param xconfig will be set to the compressed configuration (memory is fresly
1187  *          allocated) 
1188  * @return the size of the xconfig
1189  */
1190 size_t
1191 GNUNET_TESTBED_compress_config_ (const char *config, size_t size,
1192                                  char **xconfig)
1193 {
1194   size_t xsize;
1195   
1196   xsize = compressBound ((uLong) size);
1197   *xconfig = GNUNET_malloc (xsize);
1198   GNUNET_assert (Z_OK ==
1199                  compress2 ((Bytef *)* xconfig, (uLongf *) &xsize,
1200                             (const Bytef *) config, (uLongf) size, 
1201                             Z_BEST_SPEED));
1202   return xsize;
1203 }
1204                                 
1205
1206 /**
1207  * Create a link from slave controller to delegated controller. Whenever the
1208  * master controller is asked to start a peer at the delegated controller the
1209  * request will be routed towards slave controller (if a route exists). The
1210  * slave controller will then route it to the delegated controller. The
1211  * configuration of the slave controller is given and to be used to either
1212  * create the slave controller or to connect to an existing slave controller
1213  * process.  'is_subordinate' specifies if the given slave controller should be
1214  * started and managed by the master controller, or if the slave already has a
1215  * master and this is just a secondary master that is also allowed to use the
1216  * existing slave.
1217  *
1218  * @param master handle to the master controller who creates the association
1219  * @param delegated_host requests to which host should be delegated
1220  * @param slave_host which host is used to run the slave controller 
1221  * @param slave_cfg configuration to use for the slave controller
1222  * @param is_subordinate GNUNET_YES if the slave should be started (and stopped)
1223  *                       by the master controller; GNUNET_NO if we are just
1224  *                       allowed to use the slave via TCP/IP
1225  */
1226 void
1227 GNUNET_TESTBED_controller_link (struct GNUNET_TESTBED_Controller *master,
1228                                 struct GNUNET_TESTBED_Host *delegated_host,
1229                                 struct GNUNET_TESTBED_Host *slave_host,
1230                                 const struct GNUNET_CONFIGURATION_Handle *slave_cfg,
1231                                 int is_subordinate)
1232 {
1233   char *config;
1234   char *cconfig;
1235   size_t cc_size;
1236   size_t config_size;  
1237   
1238   GNUNET_assert (GNUNET_YES == 
1239                  GNUNET_TESTBED_is_host_registered_ (delegated_host, master));
1240   if ((NULL != slave_host) && (0 != GNUNET_TESTBED_host_get_id_ (slave_host)))
1241     GNUNET_assert (GNUNET_YES == 
1242                    GNUNET_TESTBED_is_host_registered_ (slave_host, master));
1243   config = GNUNET_CONFIGURATION_serialize (slave_cfg, &config_size);
1244   cc_size = GNUNET_TESTBED_compress_config_ (config, config_size, &cconfig);
1245   GNUNET_free (config);
1246   GNUNET_assert ((UINT16_MAX -
1247                   sizeof (struct GNUNET_TESTBED_ControllerLinkMessage))
1248                   >= cc_size); /* Configuration doesn't fit in 1 message */
1249   GNUNET_TESTBED_controller_link_2 (master, delegated_host, slave_host,
1250                                     (const char *) cconfig,
1251                                     cc_size, config_size, is_subordinate);
1252   GNUNET_free (cconfig);
1253 }
1254
1255
1256 /**
1257  * Ask the testbed controller to write the current overlay topology to
1258  * a file.  Naturally, the file will only contain a snapshot as the
1259  * topology may evolve all the time.
1260  *
1261  * @param controller overlay controller to inspect
1262  * @param filename name of the file the topology should
1263  *        be written to.
1264  */
1265 void
1266 GNUNET_TESTBED_overlay_write_topology_to_file (struct GNUNET_TESTBED_Controller *controller,
1267                                                const char *filename)
1268 {
1269   GNUNET_break (0);
1270 }
1271
1272
1273 /**
1274  * Creates a helper initialization message. Only for testing.
1275  *
1276  * @param cname the ip address of the controlling host
1277  * @param cfg the configuration that has to used to start the testbed service
1278  *          thru helper
1279  * @return the initialization message
1280  */
1281 struct GNUNET_TESTBED_HelperInit *
1282 GNUNET_TESTBED_create_helper_init_msg_ (const char *cname,
1283                                          const struct GNUNET_CONFIGURATION_Handle *cfg)
1284 {
1285   struct GNUNET_TESTBED_HelperInit *msg;
1286   char *config;
1287   char *xconfig;
1288   size_t config_size;
1289   size_t xconfig_size;
1290   uint16_t cname_len;
1291   uint16_t msg_size;
1292
1293   config = GNUNET_CONFIGURATION_serialize (cfg, &config_size);
1294   GNUNET_assert (NULL != config);
1295   xconfig_size =
1296     GNUNET_TESTBED_compress_config_ (config, config_size, &xconfig);
1297   GNUNET_free (config);
1298   cname_len = strlen (cname);
1299   msg_size = xconfig_size + cname_len + 1 + 
1300     sizeof (struct GNUNET_TESTBED_HelperInit);
1301   msg = GNUNET_realloc (xconfig, msg_size);
1302   (void) memmove ( ((void *) &msg[1]) + cname_len + 1, msg, xconfig_size);
1303   msg->header.size = htons (msg_size);
1304   msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_HELPER_INIT);
1305   msg->cname_size = htons (cname_len);
1306   msg->config_size = htons (config_size);
1307   (void) strcpy ((char *) &msg[1], cname);
1308   return msg;
1309 }
1310
1311
1312 /**
1313  * Cancel a pending operation.  Releases all resources
1314  * of the operation and will ensure that no event
1315  * is generated for the operation.  Does NOT guarantee
1316  * that the operation will be fully undone (or that
1317  * nothing ever happened).  
1318  * 
1319  * @param operation operation to cancel
1320  */
1321 void
1322 GNUNET_TESTBED_operation_cancel (struct GNUNET_TESTBED_Operation *operation)
1323 {
1324   GNUNET_CONTAINER_DLL_remove (operation->controller->op_head,
1325                                operation->controller->op_tail,
1326                                operation);
1327   GNUNET_TESTBED_operation_done (operation);
1328 }
1329
1330
1331 /**
1332  * Signal that the information from an operation has been fully
1333  * processed.  This function MUST be called for each event
1334  * of type 'operation_finished' to fully remove the operation
1335  * from the operation queue.  After calling this function, the
1336  * 'op_result' becomes invalid (!).
1337  * 
1338  * @param operation operation to signal completion for
1339  */
1340 void
1341 GNUNET_TESTBED_operation_done (struct GNUNET_TESTBED_Operation *operation)
1342 {
1343   switch (operation->type)
1344   {
1345   case OP_PEER_CREATE:
1346     GNUNET_TESTBED_operation_release_ (operation);
1347     return;
1348   case OP_PEER_DESTROY:
1349     GNUNET_TESTBED_operation_release_ (operation);
1350     return;
1351   case OP_PEER_START:
1352   case OP_PEER_STOP:
1353     break;
1354   case OP_PEER_INFO:
1355     {
1356       struct PeerInfoData2 *data;
1357       
1358       data = operation->data;
1359       switch (data->pit)
1360       {
1361       case GNUNET_TESTBED_PIT_IDENTITY:
1362         GNUNET_free (data->details.peer_identity);
1363         break;
1364       case GNUNET_TESTBED_PIT_CONFIGURATION:
1365         GNUNET_CONFIGURATION_destroy (data->details.cfg);
1366         break;
1367       case GNUNET_TESTBED_PIT_GENERIC:
1368         GNUNET_assert (0);              /* never reach here */
1369         break;
1370       }
1371     }
1372     GNUNET_free_non_null (operation->data);
1373     break;
1374   case OP_OVERLAY_CONNECT:
1375     GNUNET_free_non_null (operation->data);
1376     break;
1377   }
1378   GNUNET_free (operation);
1379 }
1380
1381
1382 /* end of testbed_api.c */