- remove dead code as controller linking operation does not require host
[oweals/gnunet.git] / src / testbed / testbed_api.c
1 /*
2       This file is part of GNUnet
3       (C) 2008--2013 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 #include "testbed_api_sd.h"
45
46 /**
47  * Generic logging shorthand
48  */
49 #define LOG(kind, ...)                          \
50   GNUNET_log_from (kind, "testbed-api", __VA_ARGS__)
51
52 /**
53  * Debug logging
54  */
55 #define LOG_DEBUG(...)                          \
56   LOG (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
57
58 /**
59  * Relative time seconds shorthand
60  */
61 #define TIME_REL_SECS(sec) \
62   GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, sec)
63
64
65 /**
66  * Default server message sending retry timeout
67  */
68 #define TIMEOUT_REL TIME_REL_SECS(1)
69
70
71 /**
72  * The message queue for sending messages to the controller service
73  */
74 struct MessageQueue
75 {
76   /**
77    * The message to be sent
78    */
79   struct GNUNET_MessageHeader *msg;
80
81   /**
82    * next pointer for DLL
83    */
84   struct MessageQueue *next;
85
86   /**
87    * prev pointer for DLL
88    */
89   struct MessageQueue *prev;
90 };
91
92
93 /**
94  * Context data for forwarded Operation
95  */
96 struct ForwardedOperationData
97 {
98
99   /**
100    * The callback to call when reply is available
101    */
102   GNUNET_CLIENT_MessageHandler cc;
103
104   /**
105    * The closure for the above callback
106    */
107   void *cc_cls;
108
109 };
110
111
112 /**
113  * Context data for get slave config operations
114  */
115 struct GetSlaveConfigData
116 {
117   /**
118    * The id of the slave controller
119    */
120   uint32_t slave_id;
121
122 };
123
124
125 /**
126  * Context data for controller link operations
127  */
128 struct ControllerLinkData
129 {
130   /**
131    * The controller link message
132    */
133   struct GNUNET_TESTBED_ControllerLinkRequest *msg;
134
135   /**
136    * The id of the host which is hosting the controller to be linked
137    */
138   uint32_t host_id;
139
140 };
141
142
143 /**
144  * Date context for OP_SHUTDOWN_PEERS operations
145  */
146 struct ShutdownPeersData
147 {
148   /**
149    * The operation completion callback to call
150    */
151   GNUNET_TESTBED_OperationCompletionCallback cb;
152
153   /**
154    * The closure for the above callback
155    */
156   void *cb_cls;
157 };
158
159
160 /**
161  * An entry in the stack for keeping operations which are about to expire
162  */
163 struct ExpireOperationEntry
164 {
165   /**
166    * DLL head; new entries are to be inserted here
167    */
168   struct ExpireOperationEntry *next;
169
170   /**
171    * DLL tail; entries are deleted from here
172    */
173   struct ExpireOperationEntry *prev;
174
175   /**
176    * The operation.  This will be a dangling pointer when the operation is freed
177    */
178   const struct GNUNET_TESTBED_Operation *op;
179 };
180
181
182 /**
183  * DLL head for list of operations marked for expiry
184  */
185 static struct ExpireOperationEntry *exop_head;
186
187 /**
188  * DLL tail for list of operation marked for expiry
189  */
190 static struct ExpireOperationEntry *exop_tail;
191
192
193 /**
194  * Inserts an operation into the list of operations marked for expiry
195  *
196  * @param op the operation to insert
197  */
198 static void
199 exop_insert (struct GNUNET_TESTBED_Operation *op)
200 {
201   struct ExpireOperationEntry *entry;
202
203   entry = GNUNET_malloc (sizeof (struct ExpireOperationEntry));
204   entry->op = op;
205   GNUNET_CONTAINER_DLL_insert_tail (exop_head, exop_tail, entry);  
206 }
207
208
209 /**
210  * Checks if an operation is present in the list of operations marked for
211  * expiry.  If the operation is found, it and the tail of operations after it
212  * are removed from the list.
213  *
214  * @param op the operation to check
215  * @return GNUNET_NO if the operation is not present in the list; GNUNET_YES if
216  *           the operation is found in the list (the operation is then removed
217  *           from the list -- calling this function again with the same
218  *           paramenter will return GNUNET_NO)
219  */
220 static int
221 exop_check (const struct GNUNET_TESTBED_Operation *const op)
222 {
223   struct ExpireOperationEntry *entry;
224   struct ExpireOperationEntry *entry2;
225   int found;
226
227   found = GNUNET_NO;
228   entry = exop_head;
229   while (NULL != entry)
230   {
231     if (op == entry->op)
232     {
233       found = GNUNET_YES;
234       break;
235     }
236     entry = entry->next;
237   }
238   if (GNUNET_NO == found)
239     return GNUNET_NO;
240   /* Truncate the tail */
241   while (NULL != entry)
242   {
243     entry2 = entry->next;
244     GNUNET_CONTAINER_DLL_remove (exop_head, exop_tail, entry);
245     GNUNET_free (entry);
246     entry = entry2;
247   }
248   return GNUNET_YES;
249 }
250
251
252 /**
253  * Returns the operation context with the given id if found in the Operation
254  * context queues of the controller
255  *
256  * @param c the controller whose queues are searched
257  * @param id the id which has to be checked
258  * @return the matching operation context; NULL if no match found
259  */
260 static struct OperationContext *
261 find_opc (const struct GNUNET_TESTBED_Controller *c, const uint64_t id)
262 {
263   struct OperationContext *opc;
264
265   for (opc = c->ocq_head; NULL != opc; opc = opc->next)
266   {
267     if (id == opc->id)
268       return opc;
269   }
270   return NULL;
271 }
272
273
274 /**
275  * Handler for forwarded operations
276  *
277  * @param c the controller handle
278  * @param opc the opearation context
279  * @param msg the message
280  */
281 static void
282 handle_forwarded_operation_msg (struct GNUNET_TESTBED_Controller *c,
283                                 struct OperationContext *opc,
284                                 const struct GNUNET_MessageHeader *msg)
285 {
286   struct ForwardedOperationData *fo_data;
287
288   fo_data = opc->data;
289   if (NULL != fo_data->cc)
290     fo_data->cc (fo_data->cc_cls, msg);
291   GNUNET_CONTAINER_DLL_remove (c->ocq_head, c->ocq_tail, opc);
292   GNUNET_free (fo_data);
293   GNUNET_free (opc);
294 }
295
296
297 /**
298  * Handler for GNUNET_MESSAGE_TYPE_TESTBED_ADDHOSTCONFIRM message from
299  * controller (testbed service)
300  *
301  * @param c the controller handler
302  * @param msg message received
303  * @return GNUNET_YES if we can continue receiving from service; GNUNET_NO if
304  *           not
305  */
306 static int
307 handle_opsuccess (struct GNUNET_TESTBED_Controller *c,
308                   const struct
309                   GNUNET_TESTBED_GenericOperationSuccessEventMessage *msg)
310 {
311   struct OperationContext *opc;
312   GNUNET_TESTBED_OperationCompletionCallback op_comp_cb;
313   void *op_comp_cb_cls;
314   struct GNUNET_TESTBED_EventInformation event;
315   uint64_t op_id;
316
317   op_id = GNUNET_ntohll (msg->operation_id);
318   LOG_DEBUG ("Operation %lu successful\n", op_id);
319   if (NULL == (opc = find_opc (c, op_id)))
320   {
321     LOG_DEBUG ("Operation not found\n");
322     return GNUNET_YES;
323   }
324   event.type = GNUNET_TESTBED_ET_OPERATION_FINISHED;
325   event.op = opc->op;
326   event.op_cls = opc->op_cls;
327   event.details.operation_finished.emsg = NULL;
328   event.details.operation_finished.generic = NULL;
329   op_comp_cb = NULL;
330   op_comp_cb_cls = NULL;
331   switch (opc->type)
332   {
333   case OP_FORWARDED:
334   {
335     handle_forwarded_operation_msg (c, opc,
336                                     (const struct GNUNET_MessageHeader *) msg);
337     return GNUNET_YES;
338   }
339     break;
340   case OP_PEER_DESTROY:
341   {
342     struct GNUNET_TESTBED_Peer *peer;
343
344     peer = opc->data;
345     GNUNET_TESTBED_peer_deregister_ (peer);
346     GNUNET_free (peer);
347     opc->data = NULL;
348     //PEERDESTROYDATA
349   }
350     break;
351   case OP_SHUTDOWN_PEERS:
352   {
353     struct ShutdownPeersData *data;
354
355     data = opc->data;
356     op_comp_cb = data->cb;
357     op_comp_cb_cls = data->cb_cls;
358     GNUNET_free (data);
359     opc->data = NULL;
360     GNUNET_TESTBED_cleanup_peers_ ();
361   }
362     break;
363   case OP_MANAGE_SERVICE:
364   {
365     struct ManageServiceData *data;
366
367     GNUNET_assert (NULL != (data = opc->data));
368     op_comp_cb = data->cb;
369     op_comp_cb_cls = data->cb_cls;
370     GNUNET_free (data);
371     opc->data = NULL;
372   }
373     break;
374   default:
375     GNUNET_assert (0);
376   }
377   GNUNET_CONTAINER_DLL_remove (opc->c->ocq_head, opc->c->ocq_tail, opc);
378   opc->state = OPC_STATE_FINISHED;
379   exop_insert (event.op);  
380   if (0 != (c->event_mask & (1L << GNUNET_TESTBED_ET_OPERATION_FINISHED)))
381   {
382     if (NULL != c->cc)
383       c->cc (c->cc_cls, &event);
384     if (GNUNET_NO == exop_check (event.op))
385       return GNUNET_YES;
386   }
387   else
388     LOG_DEBUG ("Not calling callback\n");
389   if (NULL != op_comp_cb)
390     op_comp_cb (op_comp_cb_cls, event.op, NULL);
391    /* You could have marked the operation as done by now */
392   GNUNET_break (GNUNET_NO == exop_check (event.op));
393   return GNUNET_YES;
394 }
395
396
397 /**
398  * Handler for GNUNET_MESSAGE_TYPE_TESTBED_PEERCREATESUCCESS message from
399  * controller (testbed service)
400  *
401  * @param c the controller handle
402  * @param msg message received
403  * @return GNUNET_YES if we can continue receiving from service; GNUNET_NO if
404  *           not
405  */
406 static int
407 handle_peer_create_success (struct GNUNET_TESTBED_Controller *c,
408                             const struct
409                             GNUNET_TESTBED_PeerCreateSuccessEventMessage *msg)
410 {
411   struct OperationContext *opc;
412   struct PeerCreateData *data;
413   struct GNUNET_TESTBED_Peer *peer;
414   struct GNUNET_TESTBED_Operation *op;
415   GNUNET_TESTBED_PeerCreateCallback cb;
416   void *cls;
417   uint64_t op_id;
418
419   GNUNET_assert (sizeof (struct GNUNET_TESTBED_PeerCreateSuccessEventMessage) ==
420                  ntohs (msg->header.size));
421   op_id = GNUNET_ntohll (msg->operation_id);
422   if (NULL == (opc = find_opc (c, op_id)))
423   {
424     LOG_DEBUG ("Operation context for PeerCreateSuccessEvent not found\n");
425     return GNUNET_YES;
426   }
427   if (OP_FORWARDED == opc->type)
428   {
429     handle_forwarded_operation_msg (c, opc,
430                                     (const struct GNUNET_MessageHeader *) msg);
431     return GNUNET_YES;
432   }
433   GNUNET_assert (OP_PEER_CREATE == opc->type);
434   GNUNET_assert (NULL != opc->data);
435   data = opc->data;
436   GNUNET_assert (NULL != data->peer);
437   peer = data->peer;
438   GNUNET_assert (peer->unique_id == ntohl (msg->peer_id));
439   peer->state = PS_CREATED;
440   GNUNET_TESTBED_peer_register_ (peer);
441   cb = data->cb;
442   cls = data->cls;
443   op = opc->op;
444   GNUNET_free (opc->data);
445   GNUNET_CONTAINER_DLL_remove (opc->c->ocq_head, opc->c->ocq_tail, opc);
446   opc->state = OPC_STATE_FINISHED;
447   exop_insert (op);
448   if (NULL != cb)
449     cb (cls, peer, NULL);
450    /* You could have marked the operation as done by now */
451   GNUNET_break (GNUNET_NO == exop_check (op));
452   return GNUNET_YES;
453 }
454
455
456 /**
457  * Handler for GNUNET_MESSAGE_TYPE_TESTBED_PEEREVENT message from
458  * controller (testbed service)
459  *
460  * @param c the controller handler
461  * @param msg message received
462  * @return GNUNET_YES if we can continue receiving from service; GNUNET_NO if
463  *           not
464  */
465 static int
466 handle_peer_event (struct GNUNET_TESTBED_Controller *c,
467                    const struct GNUNET_TESTBED_PeerEventMessage *msg)
468 {
469   struct OperationContext *opc;
470   struct GNUNET_TESTBED_Peer *peer;
471   struct PeerEventData *data;
472   GNUNET_TESTBED_PeerChurnCallback pcc;
473   void *pcc_cls;
474   struct GNUNET_TESTBED_EventInformation event;
475   uint64_t op_id;
476
477   GNUNET_assert (sizeof (struct GNUNET_TESTBED_PeerEventMessage) ==
478                  ntohs (msg->header.size));
479   op_id = GNUNET_ntohll (msg->operation_id);
480   if (NULL == (opc = find_opc (c, op_id)))
481   {
482     LOG_DEBUG ("Operation not found\n");
483     return GNUNET_YES;
484   }
485   if (OP_FORWARDED == opc->type)
486   {
487     handle_forwarded_operation_msg (c, opc,
488                                     (const struct GNUNET_MessageHeader *) msg);
489     return GNUNET_YES;
490   }
491   GNUNET_assert ((OP_PEER_START == opc->type) || (OP_PEER_STOP == opc->type));
492   data = opc->data;
493   GNUNET_assert (NULL != data);
494   peer = data->peer;
495   GNUNET_assert (NULL != peer);
496   event.type = (enum GNUNET_TESTBED_EventType) ntohl (msg->event_type);
497   event.op = opc->op;
498   event.op_cls = opc->op_cls;
499   switch (event.type)
500   {
501   case GNUNET_TESTBED_ET_PEER_START:
502     peer->state = PS_STARTED;
503     event.details.peer_start.host = peer->host;
504     event.details.peer_start.peer = peer;
505     break;
506   case GNUNET_TESTBED_ET_PEER_STOP:
507     peer->state = PS_STOPPED;
508     event.details.peer_stop.peer = peer;
509     break;
510   default:
511     GNUNET_assert (0);          /* We should never reach this state */
512   }
513   pcc = data->pcc;
514   pcc_cls = data->pcc_cls;
515   GNUNET_free (data);
516   GNUNET_CONTAINER_DLL_remove (opc->c->ocq_head, opc->c->ocq_tail, opc);
517   opc->state = OPC_STATE_FINISHED;
518   exop_insert (event.op);
519   if (0 !=
520       ((GNUNET_TESTBED_ET_PEER_START | GNUNET_TESTBED_ET_PEER_STOP) &
521        c->event_mask))
522   {
523     if (NULL != c->cc)
524       c->cc (c->cc_cls, &event);    
525     if (GNUNET_NO == exop_check (event.op))
526       return GNUNET_YES;
527   }
528   if (NULL != pcc)
529     pcc (pcc_cls, NULL);
530    /* You could have marked the operation as done by now */
531   GNUNET_break (GNUNET_NO == exop_check (event.op));
532   return GNUNET_YES;
533 }
534
535
536 /**
537  * Handler for GNUNET_MESSAGE_TYPE_TESTBED_PEERCONEVENT message from
538  * controller (testbed service)
539  *
540  * @param c the controller handler
541  * @param msg message received
542  * @return GNUNET_YES if we can continue receiving from service; GNUNET_NO if
543  *           not
544  */
545 static int
546 handle_peer_conevent (struct GNUNET_TESTBED_Controller *c,
547                       const struct GNUNET_TESTBED_ConnectionEventMessage *msg)
548 {
549   struct OperationContext *opc;
550   struct OverlayConnectData *data;
551   GNUNET_TESTBED_OperationCompletionCallback cb;
552   void *cb_cls;
553   struct GNUNET_TESTBED_EventInformation event;
554   uint64_t op_id;
555
556   op_id = GNUNET_ntohll (msg->operation_id);
557   if (NULL == (opc = find_opc (c, op_id)))
558   {
559     LOG_DEBUG ("Operation not found\n");
560     return GNUNET_YES;
561   }
562   if (OP_FORWARDED == opc->type)
563   {
564     handle_forwarded_operation_msg (c, opc,
565                                     (const struct GNUNET_MessageHeader *) msg);
566     return GNUNET_YES;
567   }
568   GNUNET_assert (OP_OVERLAY_CONNECT == opc->type);
569   GNUNET_assert (NULL != (data = opc->data));
570   GNUNET_assert ((ntohl (msg->peer1) == data->p1->unique_id) &&
571                  (ntohl (msg->peer2) == data->p2->unique_id));
572   event.type = (enum GNUNET_TESTBED_EventType) ntohl (msg->event_type);
573   event.op = opc->op;
574   event.op_cls = opc->op_cls;
575   switch (event.type)
576   {
577   case GNUNET_TESTBED_ET_CONNECT:
578     event.details.peer_connect.peer1 = data->p1;
579     event.details.peer_connect.peer2 = data->p2;
580     break;
581   case GNUNET_TESTBED_ET_DISCONNECT:
582     GNUNET_assert (0);          /* FIXME: implement */
583     break;
584   default:
585     GNUNET_assert (0);          /* Should never reach here */
586     break;
587   }
588   cb = data->cb;
589   cb_cls = data->cb_cls;
590   GNUNET_CONTAINER_DLL_remove (opc->c->ocq_head, opc->c->ocq_tail, opc);
591   opc->state = OPC_STATE_FINISHED;
592   exop_insert (event.op);
593   if (0 !=
594       ((GNUNET_TESTBED_ET_CONNECT | GNUNET_TESTBED_ET_DISCONNECT) &
595        c->event_mask))
596   {
597     if (NULL != c->cc)
598       c->cc (c->cc_cls, &event);
599     if (GNUNET_NO == exop_check (event.op))
600       return GNUNET_YES;
601   }  
602   if (NULL != cb)
603     cb (cb_cls, opc->op, NULL);
604    /* You could have marked the operation as done by now */
605   GNUNET_break (GNUNET_NO == exop_check (event.op));
606   return GNUNET_YES;
607 }
608
609
610 /**
611  * Handler for GNUNET_MESSAGE_TYPE_TESTBED_PEERCONFIG message from
612  * controller (testbed service)
613  *
614  * @param c the controller handler
615  * @param msg message received
616  * @return GNUNET_YES if we can continue receiving from service; GNUNET_NO if
617  *           not
618  */
619 static int
620 handle_peer_config (struct GNUNET_TESTBED_Controller *c,
621                     const struct
622                     GNUNET_TESTBED_PeerConfigurationInformationMessage *msg)
623 {
624   struct OperationContext *opc;
625   struct GNUNET_TESTBED_Peer *peer;
626   struct PeerInfoData *data;
627   struct GNUNET_TESTBED_PeerInformation *pinfo;
628   GNUNET_TESTBED_PeerInfoCallback cb;
629   void *cb_cls;
630   uint64_t op_id;
631
632   op_id = GNUNET_ntohll (msg->operation_id);
633   if (NULL == (opc = find_opc (c, op_id)))
634   {
635     LOG_DEBUG ("Operation not found\n");
636     return GNUNET_YES;
637   }
638   if (OP_FORWARDED == opc->type)
639   {
640     handle_forwarded_operation_msg (c, opc,
641                                     (const struct GNUNET_MessageHeader *) msg);
642     return GNUNET_YES;
643   }
644   data = opc->data;
645   GNUNET_assert (NULL != data);
646   peer = data->peer;
647   GNUNET_assert (NULL != peer);
648   GNUNET_assert (ntohl (msg->peer_id) == peer->unique_id);
649   pinfo = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_PeerInformation));
650   pinfo->pit = data->pit;  
651   cb = data->cb;
652   cb_cls = data->cb_cls;
653   GNUNET_assert (NULL != cb);
654   GNUNET_free (data);
655   opc->data = NULL;  
656   switch (pinfo->pit)
657   {
658   case GNUNET_TESTBED_PIT_IDENTITY:
659     pinfo->result.id = GNUNET_malloc (sizeof (struct GNUNET_PeerIdentity));
660     (void) memcpy (pinfo->result.id, &msg->peer_identity,
661                    sizeof (struct GNUNET_PeerIdentity));
662     break;
663   case GNUNET_TESTBED_PIT_CONFIGURATION:
664     pinfo->result.cfg =         /* Freed in oprelease_peer_getinfo */
665         GNUNET_TESTBED_extract_config_ (&msg->header);
666     break;
667   case GNUNET_TESTBED_PIT_GENERIC:
668     GNUNET_assert (0);          /* never reach here */
669     break;
670   }
671   opc->data = pinfo;
672   GNUNET_CONTAINER_DLL_remove (opc->c->ocq_head, opc->c->ocq_tail, opc);
673   opc->state = OPC_STATE_FINISHED;
674   cb (cb_cls, opc->op, pinfo, NULL);
675   /* We dont check whether the operation is marked as done here as the
676      operation contains data (cfg/identify) which will be freed at a later point
677   */
678   return GNUNET_YES;
679 }
680
681
682 /**
683  * Handler for GNUNET_MESSAGE_TYPE_TESTBED_OPERATIONFAILEVENT message from
684  * controller (testbed service)
685  *
686  * @param c the controller handler
687  * @param msg message received
688  * @return GNUNET_YES if we can continue receiving from service; GNUNET_NO if
689  *           not
690  */
691 static int
692 handle_op_fail_event (struct GNUNET_TESTBED_Controller *c,
693                       const struct GNUNET_TESTBED_OperationFailureEventMessage
694                       *msg)
695 {
696   struct OperationContext *opc;
697   const char *emsg;
698   uint64_t op_id;
699   struct GNUNET_TESTBED_EventInformation event;
700
701   op_id = GNUNET_ntohll (msg->operation_id);
702   if (NULL == (opc = find_opc (c, op_id)))
703   {
704     LOG_DEBUG ("Operation not found\n");
705     return GNUNET_YES;
706   }
707   if (OP_FORWARDED == opc->type)
708   {
709     handle_forwarded_operation_msg (c, opc,
710                                     (const struct GNUNET_MessageHeader *) msg);
711     return GNUNET_YES;
712   }
713   GNUNET_CONTAINER_DLL_remove (opc->c->ocq_head, opc->c->ocq_tail, opc);
714   opc->state = OPC_STATE_FINISHED;
715   emsg = GNUNET_TESTBED_parse_error_string_ (msg);
716   if (NULL == emsg)
717     emsg = "Unknown error";
718   if (OP_PEER_INFO == opc->type)
719   {
720     struct PeerInfoData *data;
721
722     data = opc->data;
723     if (NULL != data->cb)
724       data->cb (data->cb_cls, opc->op, NULL, emsg);
725     GNUNET_free (data);
726     return GNUNET_YES;          /* We do not call controller callback for peer info */
727   }
728   event.type = GNUNET_TESTBED_ET_OPERATION_FINISHED;
729   event.op = opc->op;
730   event.op_cls = opc->op_cls;
731   event.details.operation_finished.emsg = emsg;
732   event.details.operation_finished.generic = NULL;
733   if ((0 != (GNUNET_TESTBED_ET_OPERATION_FINISHED & c->event_mask)) &&
734       (NULL != c->cc))
735   {
736     exop_insert (event.op);
737     c->cc (c->cc_cls, &event);
738     if (GNUNET_NO == exop_check (event.op))
739       return GNUNET_YES;
740   }
741   switch (opc->type)
742   {
743   case OP_PEER_CREATE:
744   {
745     struct PeerCreateData *data;
746
747     data = opc->data;
748     GNUNET_free (data->peer);
749     if (NULL != data->cb)
750       data->cb (data->cls, NULL, emsg);
751     GNUNET_free (data);
752   }
753     break;
754   case OP_PEER_START:
755   case OP_PEER_STOP:
756   {
757     struct PeerEventData *data;
758
759     data = opc->data;
760     if (NULL != data->pcc)
761       data->pcc (data->pcc_cls, emsg);
762     GNUNET_free (data);
763   }
764     break;
765   case OP_PEER_DESTROY:
766     break;
767   case OP_PEER_INFO:
768     GNUNET_assert (0);
769   case OP_OVERLAY_CONNECT:
770   {
771     struct OverlayConnectData *data;
772
773     data = opc->data;
774     data->failed = GNUNET_YES;
775     if (NULL != data->cb)
776       data->cb (data->cb_cls, opc->op, emsg);
777   }
778     break;
779   case OP_FORWARDED:
780     GNUNET_assert (0);
781   case OP_LINK_CONTROLLERS:    /* No secondary callback */
782     break;    
783   case OP_SHUTDOWN_PEERS:
784   {
785     struct ShutdownPeersData *data;
786
787     data = opc->data;
788     GNUNET_free (data);         /* FIXME: Decide whether we call data->op_cb */
789     opc->data = NULL;
790   }
791     break;
792   case OP_MANAGE_SERVICE:
793   {
794     struct ManageServiceData *data = opc->data;
795       GNUNET_TESTBED_OperationCompletionCallback cb;
796     void *cb_cls;
797
798     GNUNET_assert (NULL != data);
799     cb = data->cb;
800     cb_cls = data->cb_cls;
801     GNUNET_free (data);
802     opc->data = NULL;
803     exop_insert (event.op);
804     if (NULL != cb)
805       cb (cb_cls, opc->op, emsg);
806     /* You could have marked the operation as done by now */
807     GNUNET_break (GNUNET_NO == exop_check (event.op));
808   }
809     break;
810   default:
811     GNUNET_break (0);
812   }
813   return GNUNET_YES;
814 }
815
816
817 /**
818  * Function to build GET_SLAVE_CONFIG message
819  *
820  * @param op_id the id this message should contain in its operation id field
821  * @param slave_id the id this message should contain in its slave id field
822  * @return newly allocated SlaveGetConfigurationMessage
823  */
824 static struct GNUNET_TESTBED_SlaveGetConfigurationMessage *
825 GNUNET_TESTBED_generate_slavegetconfig_msg_ (uint64_t op_id, uint32_t slave_id)
826 {
827   struct GNUNET_TESTBED_SlaveGetConfigurationMessage *msg;
828   uint16_t msize;
829
830   msize = sizeof (struct GNUNET_TESTBED_SlaveGetConfigurationMessage);
831   msg = GNUNET_malloc (msize);
832   msg->header.size = htons (msize);
833   msg->header.type =
834       htons (GNUNET_MESSAGE_TYPE_TESTBED_GET_SLAVE_CONFIGURATION);
835   msg->operation_id = GNUNET_htonll (op_id);
836   msg->slave_id = htonl (slave_id);
837   return msg;
838 }
839
840
841 /**
842  * Handler for GNUNET_MESSAGE_TYPE_TESTBED_SLAVECONFIG message from controller
843  * (testbed service)
844  *
845  * @param c the controller handler
846  * @param msg message received
847  * @return GNUNET_YES if we can continue receiving from service; GNUNET_NO if
848  *           not
849  */
850 static int
851 handle_slave_config (struct GNUNET_TESTBED_Controller *c,
852                      const struct GNUNET_TESTBED_SlaveConfiguration *msg)
853 {
854   struct OperationContext *opc;
855   uint64_t op_id;
856   struct GNUNET_TESTBED_EventInformation event;
857
858   op_id = GNUNET_ntohll (msg->operation_id);
859   if (NULL == (opc = find_opc (c, op_id)))
860   {
861     LOG_DEBUG ("Operation not found\n");
862     return GNUNET_YES;
863   }
864   if (OP_GET_SLAVE_CONFIG != opc->type)
865   {
866     GNUNET_break (0);
867     return GNUNET_YES;
868   }
869   opc->state = OPC_STATE_FINISHED;
870   GNUNET_CONTAINER_DLL_remove (opc->c->ocq_head, opc->c->ocq_tail, opc);
871   if ((0 != (GNUNET_TESTBED_ET_OPERATION_FINISHED & c->event_mask)) &&
872       (NULL != c->cc))
873   {
874     opc->data = GNUNET_TESTBED_extract_config_ (&msg->header);
875     event.type = GNUNET_TESTBED_ET_OPERATION_FINISHED;
876     event.op = opc->op;
877     event.op_cls = opc->op_cls;
878     event.details.operation_finished.generic = opc->data;
879     event.details.operation_finished.emsg = NULL;
880     c->cc (c->cc_cls, &event);
881   }
882   return GNUNET_YES;
883 }
884
885
886 /**
887  * Handler for GNUNET_MESSAGE_TYPE_TESTBED_SLAVECONFIG message from controller
888  * (testbed service)
889  *
890  * @param c the controller handler
891  * @param msg message received
892  * @return GNUNET_YES if we can continue receiving from service; GNUNET_NO if
893  *           not
894  */
895 static int
896 handle_link_controllers_result (struct GNUNET_TESTBED_Controller *c,
897                                 const struct
898                                 GNUNET_TESTBED_ControllerLinkResponse *msg)
899 {
900   struct OperationContext *opc;
901   struct ControllerLinkData *data;
902   struct GNUNET_CONFIGURATION_Handle *cfg;
903   struct GNUNET_TESTBED_Host *host;
904   char *emsg;
905   uint64_t op_id;
906   struct GNUNET_TESTBED_EventInformation event;
907
908   op_id = GNUNET_ntohll (msg->operation_id);
909   if (NULL == (opc = find_opc (c, op_id)))
910   {
911     LOG_DEBUG ("Operation not found\n");
912     return GNUNET_YES;
913   }
914   if (OP_FORWARDED == opc->type)
915   {
916     handle_forwarded_operation_msg (c, opc,
917                                     (const struct GNUNET_MessageHeader *) msg);
918     return GNUNET_YES;
919   }
920   if (OP_LINK_CONTROLLERS != opc->type)
921   {
922     GNUNET_break (0);
923     return GNUNET_YES;
924   }
925   GNUNET_assert (NULL != (data = opc->data));
926   host = GNUNET_TESTBED_host_lookup_by_id_ (data->host_id);
927   GNUNET_assert (NULL != host);
928   GNUNET_free (data);
929   opc->data = NULL;
930   opc->state = OPC_STATE_FINISHED;
931   GNUNET_CONTAINER_DLL_remove (opc->c->ocq_head, opc->c->ocq_tail, opc);
932   event.type = GNUNET_TESTBED_ET_OPERATION_FINISHED;
933   event.op = opc->op;
934   event.op_cls = opc->op_cls;
935   event.details.operation_finished.emsg = NULL;
936   event.details.operation_finished.generic = NULL;
937   emsg = NULL;
938   cfg = NULL;
939   if (GNUNET_NO == ntohs (msg->success))
940   {
941     emsg = GNUNET_malloc (ntohs (msg->header.size)
942                           - sizeof (struct
943                                     GNUNET_TESTBED_ControllerLinkResponse) + 1);
944     memcpy (emsg, &msg[1], ntohs (msg->header.size)
945                           - sizeof (struct
946                                     GNUNET_TESTBED_ControllerLinkResponse));
947     event.details.operation_finished.emsg = emsg;
948   }
949   else
950   {
951     if (0 != ntohs (msg->config_size))
952     {
953       cfg = GNUNET_TESTBED_extract_config_ ((const struct GNUNET_MessageHeader *) msg);
954       GNUNET_assert (NULL != cfg);
955       GNUNET_TESTBED_host_replace_cfg_ (host, cfg);
956     }
957   }
958   if (0 != (c->event_mask & (1L << GNUNET_TESTBED_ET_OPERATION_FINISHED)))
959   {
960     if (NULL != c->cc)
961       c->cc (c->cc_cls, &event);
962   }
963   else
964     LOG_DEBUG ("Not calling callback\n");
965   if (NULL != cfg)
966     GNUNET_CONFIGURATION_destroy (cfg);
967   GNUNET_free_non_null (emsg);
968   return GNUNET_YES;
969 }
970
971
972 /**
973  * Handler for messages from controller (testbed service)
974  *
975  * @param cls the controller handler
976  * @param msg message received, NULL on timeout or fatal error
977  */
978 static void
979 message_handler (void *cls, const struct GNUNET_MessageHeader *msg)
980 {
981   struct GNUNET_TESTBED_Controller *c = cls;
982   int status;
983   uint16_t msize;
984
985   c->in_receive = GNUNET_NO;
986   /* FIXME: Add checks for message integrity */
987   if (NULL == msg)
988   {
989     LOG_DEBUG ("Receive timed out or connection to service dropped\n");
990     return;
991   }
992   status = GNUNET_OK;
993   msize = ntohs (msg->size);
994   switch (ntohs (msg->type))
995   {
996   case GNUNET_MESSAGE_TYPE_TESTBED_ADD_HOST_SUCCESS:
997     GNUNET_assert (msize >=
998                    sizeof (struct GNUNET_TESTBED_HostConfirmedMessage));
999     status =
1000         GNUNET_TESTBED_host_handle_addhostconfirm_
1001         (c, (const struct GNUNET_TESTBED_HostConfirmedMessage*) msg);
1002     break;
1003   case GNUNET_MESSAGE_TYPE_TESTBED_GENERIC_OPERATION_SUCCESS:
1004     GNUNET_assert (msize ==
1005                    sizeof (struct
1006                            GNUNET_TESTBED_GenericOperationSuccessEventMessage));
1007     status =
1008         handle_opsuccess (c,
1009                           (const struct
1010                            GNUNET_TESTBED_GenericOperationSuccessEventMessage *)
1011                           msg);
1012     break;
1013   case GNUNET_MESSAGE_TYPE_TESTBED_OPERATION_FAIL_EVENT:
1014     GNUNET_assert (msize >=
1015                    sizeof (struct GNUNET_TESTBED_OperationFailureEventMessage));
1016     status =
1017         handle_op_fail_event (c,
1018                               (const struct
1019                                GNUNET_TESTBED_OperationFailureEventMessage *)
1020                               msg);
1021     break;
1022   case GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER_SUCCESS:
1023     GNUNET_assert (msize ==
1024                    sizeof (struct
1025                            GNUNET_TESTBED_PeerCreateSuccessEventMessage));
1026     status =
1027         handle_peer_create_success (c,
1028                                     (const struct
1029                                      GNUNET_TESTBED_PeerCreateSuccessEventMessage
1030                                      *) msg);
1031     break;
1032   case GNUNET_MESSAGE_TYPE_TESTBED_PEER_EVENT:
1033     GNUNET_assert (msize == sizeof (struct GNUNET_TESTBED_PeerEventMessage));
1034     status =
1035         handle_peer_event (c,
1036                            (const struct GNUNET_TESTBED_PeerEventMessage *)
1037                            msg);
1038
1039     break;
1040   case GNUNET_MESSAGE_TYPE_TESTBED_PEER_CONFIGURATION:
1041     GNUNET_assert (msize >=
1042                    sizeof (struct
1043                            GNUNET_TESTBED_PeerConfigurationInformationMessage));
1044     status =
1045         handle_peer_config (c,
1046                             (const struct
1047                              GNUNET_TESTBED_PeerConfigurationInformationMessage
1048                              *) msg);
1049     break;
1050   case GNUNET_MESSAGE_TYPE_TESTBED_PEER_CONNECT_EVENT:
1051     GNUNET_assert (msize ==
1052                    sizeof (struct GNUNET_TESTBED_ConnectionEventMessage));
1053     status =
1054         handle_peer_conevent (c,
1055                               (const struct
1056                                GNUNET_TESTBED_ConnectionEventMessage *) msg);
1057     break;
1058   case GNUNET_MESSAGE_TYPE_TESTBED_SLAVE_CONFIGURATION:
1059     GNUNET_assert (msize > sizeof (struct GNUNET_TESTBED_SlaveConfiguration));
1060     status =
1061         handle_slave_config (c,
1062                              (const struct GNUNET_TESTBED_SlaveConfiguration *)
1063                              msg);
1064     break;
1065   case GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS_RESULT:
1066     status = 
1067         handle_link_controllers_result (c,
1068                                         (const struct
1069                                          GNUNET_TESTBED_ControllerLinkResponse
1070                                          *) msg);
1071     break;
1072   default:
1073     GNUNET_assert (0);
1074   }
1075   if ((GNUNET_OK == status) && (GNUNET_NO == c->in_receive))
1076   {
1077     c->in_receive = GNUNET_YES;
1078     GNUNET_CLIENT_receive (c->client, &message_handler, c,
1079                            GNUNET_TIME_UNIT_FOREVER_REL);
1080   }
1081 }
1082
1083
1084 /**
1085  * Function called to notify a client about the connection begin ready to queue
1086  * more data.  "buf" will be NULL and "size" zero if the connection was closed
1087  * for writing in the meantime.
1088  *
1089  * @param cls closure
1090  * @param size number of bytes available in buf
1091  * @param buf where the callee should write the message
1092  * @return number of bytes written to buf
1093  */
1094 static size_t
1095 transmit_ready_notify (void *cls, size_t size, void *buf)
1096 {
1097   struct GNUNET_TESTBED_Controller *c = cls;
1098   struct MessageQueue *mq_entry;
1099
1100   c->th = NULL;
1101   mq_entry = c->mq_head;
1102   GNUNET_assert (NULL != mq_entry);
1103   if ((0 == size) && (NULL == buf))     /* Timeout */
1104   {
1105     LOG_DEBUG ("Message sending timed out -- retrying\n");
1106     c->th =
1107         GNUNET_CLIENT_notify_transmit_ready (c->client,
1108                                              ntohs (mq_entry->msg->size),
1109                                              TIMEOUT_REL, GNUNET_YES,
1110                                              &transmit_ready_notify, c);
1111     return 0;
1112   }
1113   GNUNET_assert (ntohs (mq_entry->msg->size) <= size);
1114   size = ntohs (mq_entry->msg->size);
1115   memcpy (buf, mq_entry->msg, size);
1116   LOG_DEBUG ("Message of type: %u and size: %u sent\n",
1117              ntohs (mq_entry->msg->type), size);
1118   GNUNET_free (mq_entry->msg);
1119   GNUNET_CONTAINER_DLL_remove (c->mq_head, c->mq_tail, mq_entry);
1120   GNUNET_free (mq_entry);
1121   mq_entry = c->mq_head;
1122   if (NULL != mq_entry)
1123     c->th =
1124         GNUNET_CLIENT_notify_transmit_ready (c->client,
1125                                              ntohs (mq_entry->msg->size),
1126                                              TIMEOUT_REL, GNUNET_YES,
1127                                              &transmit_ready_notify, c);
1128   if (GNUNET_NO == c->in_receive)
1129   {
1130     c->in_receive = GNUNET_YES;
1131     GNUNET_CLIENT_receive (c->client, &message_handler, c,
1132                            GNUNET_TIME_UNIT_FOREVER_REL);
1133   }
1134   return size;
1135 }
1136
1137
1138 /**
1139  * Queues a message in send queue for sending to the service
1140  *
1141  * @param controller the handle to the controller
1142  * @param msg the message to queue
1143  */
1144 void
1145 GNUNET_TESTBED_queue_message_ (struct GNUNET_TESTBED_Controller *controller,
1146                                struct GNUNET_MessageHeader *msg)
1147 {
1148   struct MessageQueue *mq_entry;
1149   uint16_t type;
1150   uint16_t size;
1151
1152   type = ntohs (msg->type);
1153   size = ntohs (msg->size);
1154   GNUNET_assert ((GNUNET_MESSAGE_TYPE_TESTBED_INIT <= type) &&
1155                  (GNUNET_MESSAGE_TYPE_TESTBED_MAX > type));
1156   mq_entry = GNUNET_malloc (sizeof (struct MessageQueue));
1157   mq_entry->msg = msg;
1158   LOG (GNUNET_ERROR_TYPE_DEBUG,
1159        "Queueing message of type %u, size %u for sending\n", type,
1160        ntohs (msg->size));
1161   GNUNET_CONTAINER_DLL_insert_tail (controller->mq_head, controller->mq_tail,
1162                                     mq_entry);
1163   if (NULL == controller->th)
1164     controller->th =
1165         GNUNET_CLIENT_notify_transmit_ready (controller->client, size,
1166                                              TIMEOUT_REL, GNUNET_YES,
1167                                              &transmit_ready_notify,
1168                                              controller);
1169 }
1170
1171
1172 /**
1173  * Sends the given message as an operation. The given callback is called when a
1174  * reply for the operation is available.  Call
1175  * GNUNET_TESTBED_forward_operation_msg_cancel_() to cleanup the returned
1176  * operation context if the cc hasn't been called
1177  *
1178  * @param controller the controller to which the message has to be sent
1179  * @param operation_id the operation id of the message
1180  * @param msg the message to send
1181  * @param cc the callback to call when reply is available
1182  * @param cc_cls the closure for the above callback
1183  * @return the operation context which can be used to cancel the forwarded
1184  *           operation
1185  */
1186 struct OperationContext *
1187 GNUNET_TESTBED_forward_operation_msg_ (struct GNUNET_TESTBED_Controller
1188                                        *controller, uint64_t operation_id,
1189                                        const struct GNUNET_MessageHeader *msg,
1190                                        GNUNET_CLIENT_MessageHandler cc,
1191                                        void *cc_cls)
1192 {
1193   struct OperationContext *opc;
1194   struct ForwardedOperationData *data;
1195   struct GNUNET_MessageHeader *dup_msg;
1196   uint16_t msize;
1197
1198   data = GNUNET_malloc (sizeof (struct ForwardedOperationData));
1199   data->cc = cc;
1200   data->cc_cls = cc_cls;
1201   opc = GNUNET_malloc (sizeof (struct OperationContext));
1202   opc->c = controller;
1203   opc->type = OP_FORWARDED;
1204   opc->data = data;
1205   opc->id = operation_id;
1206   msize = ntohs (msg->size);
1207   dup_msg = GNUNET_malloc (msize);
1208   (void) memcpy (dup_msg, msg, msize);
1209   GNUNET_TESTBED_queue_message_ (opc->c, dup_msg);
1210   GNUNET_CONTAINER_DLL_insert_tail (controller->ocq_head, controller->ocq_tail,
1211                                     opc);
1212   return opc;
1213 }
1214
1215
1216 /**
1217  * Function to cancel an operation created by simply forwarding an operation
1218  * message.
1219  *
1220  * @param opc the operation context from GNUNET_TESTBED_forward_operation_msg_()
1221  */
1222 void
1223 GNUNET_TESTBED_forward_operation_msg_cancel_ (struct OperationContext *opc)
1224 {
1225   GNUNET_CONTAINER_DLL_remove (opc->c->ocq_head, opc->c->ocq_tail, opc);
1226   GNUNET_free (opc->data);
1227   GNUNET_free (opc);
1228 }
1229
1230
1231 /**
1232  * Function to call to start a link-controllers type operation once all queues
1233  * the operation is part of declare that the operation can be activated.
1234  *
1235  * @param cls the closure from GNUNET_TESTBED_operation_create_()
1236  */
1237 static void
1238 opstart_link_controllers (void *cls)
1239 {
1240   struct OperationContext *opc = cls;
1241   struct ControllerLinkData *data;
1242   struct GNUNET_TESTBED_ControllerLinkRequest *msg;
1243
1244   GNUNET_assert (NULL != opc->data);
1245   data = opc->data;
1246   msg = data->msg;
1247   data->msg = NULL;
1248   opc->state = OPC_STATE_STARTED;
1249   GNUNET_CONTAINER_DLL_insert_tail (opc->c->ocq_head, opc->c->ocq_tail, opc);
1250   GNUNET_TESTBED_queue_message_ (opc->c, &msg->header);
1251 }
1252
1253
1254 /**
1255  * Callback which will be called when link-controllers type operation is released
1256  *
1257  * @param cls the closure from GNUNET_TESTBED_operation_create_()
1258  */
1259 static void
1260 oprelease_link_controllers (void *cls)
1261 {
1262   struct OperationContext *opc = cls;
1263   struct ControllerLinkData *data;
1264
1265   data = opc->data;
1266   switch (opc->state)
1267   {
1268   case OPC_STATE_INIT:
1269     GNUNET_free (data->msg);    
1270     break;
1271   case OPC_STATE_STARTED:
1272     GNUNET_CONTAINER_DLL_remove (opc->c->ocq_head, opc->c->ocq_tail, opc);
1273     break;
1274   case OPC_STATE_FINISHED:
1275     break;
1276   }
1277   GNUNET_free_non_null (data);
1278   GNUNET_free (opc);
1279 }
1280
1281
1282 /**
1283  * Function to be called when get slave config operation is ready
1284  *
1285  * @param cls the OperationContext of type OP_GET_SLAVE_CONFIG
1286  */
1287 static void
1288 opstart_get_slave_config (void *cls)
1289 {
1290   struct OperationContext *opc = cls;
1291   struct GetSlaveConfigData *data = opc->data;
1292   struct GNUNET_TESTBED_SlaveGetConfigurationMessage *msg;
1293
1294   GNUNET_assert (NULL != data);
1295   msg = GNUNET_TESTBED_generate_slavegetconfig_msg_ (opc->id, data->slave_id);
1296   GNUNET_free (opc->data);
1297   data = NULL;
1298   opc->data = NULL;
1299   GNUNET_CONTAINER_DLL_insert_tail (opc->c->ocq_head, opc->c->ocq_tail, opc);
1300   GNUNET_TESTBED_queue_message_ (opc->c, &msg->header);
1301   opc->state = OPC_STATE_STARTED;
1302 }
1303
1304
1305 /**
1306  * Function to be called when get slave config operation is cancelled or finished
1307  *
1308  * @param cls the OperationContext of type OP_GET_SLAVE_CONFIG
1309  */
1310 static void
1311 oprelease_get_slave_config (void *cls)
1312 {
1313   struct OperationContext *opc = cls;
1314
1315   switch (opc->state)
1316   {
1317   case OPC_STATE_INIT:
1318     GNUNET_free (opc->data);
1319     break;
1320   case OPC_STATE_STARTED:
1321     GNUNET_CONTAINER_DLL_remove (opc->c->ocq_head, opc->c->ocq_tail, opc);
1322     break;
1323   case OPC_STATE_FINISHED:
1324     if (NULL != opc->data)
1325       GNUNET_CONFIGURATION_destroy (opc->data);
1326     break;
1327   }
1328   GNUNET_free (opc);
1329 }
1330
1331
1332 /**
1333  * Start a controller process using the given configuration at the
1334  * given host.
1335  *
1336  * @param host host to run the controller on; This should be the same host if
1337  *          the controller was previously started with
1338  *          GNUNET_TESTBED_controller_start; NULL for localhost
1339  * @param event_mask bit mask with set of events to call 'cc' for;
1340  *                   or-ed values of "1LL" shifted by the
1341  *                   respective 'enum GNUNET_TESTBED_EventType'
1342  *                   (i.e.  "(1LL << GNUNET_TESTBED_ET_CONNECT) | ...")
1343  * @param cc controller callback to invoke on events
1344  * @param cc_cls closure for cc
1345  * @return handle to the controller
1346  */
1347 struct GNUNET_TESTBED_Controller *
1348 GNUNET_TESTBED_controller_connect (struct GNUNET_TESTBED_Host *host,
1349                                    uint64_t event_mask,
1350                                    GNUNET_TESTBED_ControllerCallback cc,
1351                                    void *cc_cls)
1352 {
1353   struct GNUNET_TESTBED_Controller *controller;
1354   struct GNUNET_TESTBED_InitMessage *msg;
1355   const struct GNUNET_CONFIGURATION_Handle *cfg;
1356   const char *controller_hostname;
1357   unsigned long long max_parallel_operations;
1358   unsigned long long max_parallel_service_connections;
1359   unsigned long long max_parallel_topology_config_operations;
1360
1361   GNUNET_assert (NULL != (cfg = GNUNET_TESTBED_host_get_cfg_ (host)));
1362   if (GNUNET_OK !=
1363       GNUNET_CONFIGURATION_get_value_number (cfg, "testbed",
1364                                              "MAX_PARALLEL_OPERATIONS",
1365                                              &max_parallel_operations))
1366   {
1367     GNUNET_break (0);
1368     return NULL;
1369   }
1370   if (GNUNET_OK !=
1371       GNUNET_CONFIGURATION_get_value_number (cfg, "testbed",
1372                                              "MAX_PARALLEL_SERVICE_CONNECTIONS",
1373                                              &max_parallel_service_connections))
1374   {
1375     GNUNET_break (0);
1376     return NULL;
1377   }
1378   if (GNUNET_OK !=
1379       GNUNET_CONFIGURATION_get_value_number (cfg, "testbed",
1380                                              "MAX_PARALLEL_TOPOLOGY_CONFIG_OPERATIONS",
1381                                              &max_parallel_topology_config_operations))
1382   {
1383     GNUNET_break (0);
1384     return NULL;
1385   }
1386   controller = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_Controller));
1387   controller->cc = cc;
1388   controller->cc_cls = cc_cls;
1389   controller->event_mask = event_mask;
1390   controller->cfg = GNUNET_CONFIGURATION_dup (cfg);
1391   controller->client = GNUNET_CLIENT_connect ("testbed", controller->cfg);
1392   if (NULL == controller->client)
1393   {
1394     GNUNET_TESTBED_controller_disconnect (controller);
1395     return NULL;
1396   }
1397   if (NULL == host)
1398   {
1399     host = GNUNET_TESTBED_host_create_by_id_ (0, controller->cfg);
1400     if (NULL == host)           /* If the above host create fails */
1401     {
1402       LOG (GNUNET_ERROR_TYPE_WARNING,
1403            "Treating NULL host as localhost. Multiple references to localhost "
1404            "may break when localhost freed before calling disconnect \n");
1405       host = GNUNET_TESTBED_host_lookup_by_id_ (0);
1406     }
1407     else
1408     {
1409       controller->aux_host = GNUNET_YES;
1410     }
1411   }
1412   GNUNET_assert (NULL != host);
1413   GNUNET_TESTBED_mark_host_registered_at_ (host, controller);
1414   controller->host = host;
1415   controller->opq_parallel_operations =
1416       GNUNET_TESTBED_operation_queue_create_ ((unsigned int)
1417                                               max_parallel_operations);
1418   controller->opq_parallel_service_connections =
1419       GNUNET_TESTBED_operation_queue_create_ ((unsigned int)
1420                                               max_parallel_service_connections);
1421   controller->opq_parallel_topology_config_operations =
1422       GNUNET_TESTBED_operation_queue_create_ ((unsigned int)
1423                                               max_parallel_topology_config_operations);
1424   controller_hostname = GNUNET_TESTBED_host_get_hostname (host);
1425   if (NULL == controller_hostname)
1426     controller_hostname = "127.0.0.1";
1427   msg =
1428       GNUNET_malloc (sizeof (struct GNUNET_TESTBED_InitMessage) +
1429                      strlen (controller_hostname) + 1);
1430   msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_INIT);
1431   msg->header.size =
1432       htons (sizeof (struct GNUNET_TESTBED_InitMessage) +
1433              strlen (controller_hostname) + 1);
1434   msg->host_id = htonl (GNUNET_TESTBED_host_get_id_ (host));
1435   msg->event_mask = GNUNET_htonll (controller->event_mask);
1436   strcpy ((char *) &msg[1], controller_hostname);
1437   GNUNET_TESTBED_queue_message_ (controller,
1438                                  (struct GNUNET_MessageHeader *) msg);
1439   return controller;
1440 }
1441
1442
1443 /**
1444  * Configure shared services at a controller.  Using this function,
1445  * you can specify that certain services (such as "resolver")
1446  * should not be run for each peer but instead be shared
1447  * across N peers on the specified host.  This function
1448  * must be called before any peers are created at the host.
1449  *
1450  * @param controller controller to configure
1451  * @param service_name name of the service to share
1452  * @param num_peers number of peers that should share one instance
1453  *        of the specified service (1 for no sharing is the default),
1454  *        use 0 to disable the service
1455  */
1456 void
1457 GNUNET_TESTBED_controller_configure_sharing (struct GNUNET_TESTBED_Controller
1458                                              *controller,
1459                                              const char *service_name,
1460                                              uint32_t num_peers)
1461 {
1462   struct GNUNET_TESTBED_ConfigureSharedServiceMessage *msg;
1463   uint16_t service_name_size;
1464   uint16_t msg_size;
1465
1466   service_name_size = strlen (service_name) + 1;
1467   msg_size =
1468       sizeof (struct GNUNET_TESTBED_ConfigureSharedServiceMessage) +
1469       service_name_size;
1470   msg = GNUNET_malloc (msg_size);
1471   msg->header.size = htons (msg_size);
1472   msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_SHARE_SERVICE);
1473   msg->host_id = htonl (GNUNET_TESTBED_host_get_id_ (controller->host));
1474   msg->num_peers = htonl (num_peers);
1475   memcpy (&msg[1], service_name, service_name_size);
1476   GNUNET_TESTBED_queue_message_ (controller,
1477                                  (struct GNUNET_MessageHeader *) msg);
1478   GNUNET_break (0);             /* This function is not yet implemented on the
1479                                  * testbed service */
1480 }
1481
1482
1483 /**
1484  * disconnects from the controller.
1485  *
1486  * @param controller handle to controller to stop
1487  */
1488 void
1489 GNUNET_TESTBED_controller_disconnect (struct GNUNET_TESTBED_Controller
1490                                       *controller)
1491 {
1492   struct MessageQueue *mq_entry;
1493
1494   if (NULL != controller->th)
1495     GNUNET_CLIENT_notify_transmit_ready_cancel (controller->th);
1496   /* Clear the message queue */
1497   while (NULL != (mq_entry = controller->mq_head))
1498   {
1499     GNUNET_CONTAINER_DLL_remove (controller->mq_head, controller->mq_tail,
1500                                  mq_entry);
1501     GNUNET_free (mq_entry->msg);
1502     GNUNET_free (mq_entry);
1503   }
1504   if (NULL != controller->client)
1505     GNUNET_CLIENT_disconnect (controller->client);
1506   GNUNET_CONFIGURATION_destroy (controller->cfg);
1507   if (GNUNET_YES == controller->aux_host)
1508     GNUNET_TESTBED_host_destroy (controller->host);
1509   GNUNET_TESTBED_operation_queue_destroy_ (controller->opq_parallel_operations);
1510   GNUNET_TESTBED_operation_queue_destroy_
1511       (controller->opq_parallel_service_connections);
1512   GNUNET_TESTBED_operation_queue_destroy_
1513       (controller->opq_parallel_topology_config_operations);
1514   GNUNET_free (controller);
1515 }
1516
1517
1518 /**
1519  * Compresses given configuration using zlib compress
1520  *
1521  * @param config the serialized configuration
1522  * @param size the size of config
1523  * @param xconfig will be set to the compressed configuration (memory is fresly
1524  *          allocated)
1525  * @return the size of the xconfig
1526  */
1527 size_t
1528 GNUNET_TESTBED_compress_config_ (const char *config, size_t size,
1529                                  char **xconfig)
1530 {
1531   size_t xsize;
1532
1533   xsize = compressBound ((uLong) size);
1534   *xconfig = GNUNET_malloc (xsize);
1535   GNUNET_assert (Z_OK ==
1536                  compress2 ((Bytef *) * xconfig, (uLongf *) & xsize,
1537                             (const Bytef *) config, (uLongf) size,
1538                             Z_BEST_SPEED));
1539   return xsize;
1540 }
1541
1542
1543 /**
1544  * Function to serialize and compress using zlib a configuration through a
1545  * configuration handle
1546  *
1547  * @param cfg the configuration
1548  * @param size the size of configuration when serialize.  Will be set on success.
1549  * @param xsize the sizeo of the compressed configuration.  Will be set on success.
1550  * @return the serialized and compressed configuration
1551  */
1552 char *
1553 GNUNET_TESTBED_compress_cfg_ (const struct GNUNET_CONFIGURATION_Handle *cfg,
1554                               size_t *size, size_t *xsize)
1555 {
1556   char *config;
1557   char *xconfig;
1558   size_t size_;
1559   size_t xsize_;
1560   
1561   config = GNUNET_CONFIGURATION_serialize (cfg, &size_);
1562   xsize_ = GNUNET_TESTBED_compress_config_ (config, size_, &xconfig);
1563   GNUNET_free (config);
1564   *size = size_;
1565   *xsize = xsize_;
1566   return xconfig;
1567 }
1568
1569
1570 /**
1571  * Create a link from slave controller to delegated controller. Whenever the
1572  * master controller is asked to start a peer at the delegated controller the
1573  * request will be routed towards slave controller (if a route exists). The
1574  * slave controller will then route it to the delegated controller. The
1575  * configuration of the delegated controller is given and is used to either
1576  * create the delegated controller or to connect to an existing controller. Note
1577  * that while starting the delegated controller the configuration will be
1578  * modified to accommodate available free ports.  the 'is_subordinate' specifies
1579  * if the given delegated controller should be started and managed by the slave
1580  * controller, or if the delegated controller already has a master and the slave
1581  * controller connects to it as a non master controller. The success or failure
1582  * of this operation will be signalled through the
1583  * GNUNET_TESTBED_ControllerCallback() with an event of type
1584  * GNUNET_TESTBED_ET_OPERATION_FINISHED
1585  *
1586  * @param op_cls the operation closure for the event which is generated to
1587  *          signal success or failure of this operation
1588  * @param master handle to the master controller who creates the association
1589  * @param delegated_host requests to which host should be delegated; cannot be NULL
1590  * @param slave_host which host is used to run the slave controller; use NULL to
1591  *          make the master controller connect to the delegated host
1592  * @param slave_cfg configuration to use for the slave controller
1593  * @param is_subordinate GNUNET_YES if the controller at delegated_host should
1594  *          be started by the slave controller; GNUNET_NO if the slave
1595  *          controller has to connect to the already started delegated
1596  *          controller via TCP/IP
1597  * @return the operation handle
1598  */
1599 struct GNUNET_TESTBED_Operation *
1600 GNUNET_TESTBED_controller_link (void *op_cls,
1601                                 struct GNUNET_TESTBED_Controller *master,
1602                                 struct GNUNET_TESTBED_Host *delegated_host,
1603                                 struct GNUNET_TESTBED_Host *slave_host,
1604                                 const struct GNUNET_CONFIGURATION_Handle
1605                                 *slave_cfg, int is_subordinate)
1606 {
1607   struct OperationContext *opc;
1608   struct GNUNET_TESTBED_ControllerLinkRequest *msg;
1609   struct ControllerLinkData *data;
1610   uint32_t slave_host_id;
1611   uint32_t delegated_host_id;
1612   uint16_t msg_size;
1613   
1614   GNUNET_assert (GNUNET_YES ==
1615                  GNUNET_TESTBED_is_host_registered_ (delegated_host, master));
1616   slave_host_id =
1617       GNUNET_TESTBED_host_get_id_ ((NULL !=
1618                                     slave_host) ? slave_host : master->host);
1619   delegated_host_id = GNUNET_TESTBED_host_get_id_ (delegated_host);
1620   if ((NULL != slave_host) && (0 != slave_host_id))
1621     GNUNET_assert (GNUNET_YES ==
1622                    GNUNET_TESTBED_is_host_registered_ (slave_host, master));
1623   msg_size = sizeof (struct GNUNET_TESTBED_ControllerLinkRequest);
1624   msg = GNUNET_malloc (msg_size);
1625   msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS);
1626   msg->header.size = htons (msg_size);
1627   msg->delegated_host_id = htonl (delegated_host_id);
1628   msg->slave_host_id = htonl (slave_host_id);
1629   msg->is_subordinate = (GNUNET_YES == is_subordinate) ? 1 : 0;data = GNUNET_malloc (sizeof (struct ControllerLinkData));
1630   data->msg = msg;
1631   data->host_id = delegated_host_id;
1632   opc = GNUNET_malloc (sizeof (struct OperationContext));
1633   opc->c = master;
1634   opc->data = data;
1635   opc->type = OP_LINK_CONTROLLERS;
1636   opc->id = GNUNET_TESTBED_get_next_op_id (opc->c);
1637   opc->state = OPC_STATE_INIT;
1638   opc->op_cls = op_cls;
1639   msg->operation_id = GNUNET_htonll (opc->id);
1640   opc->op =
1641       GNUNET_TESTBED_operation_create_ (opc, &opstart_link_controllers,
1642                                         &oprelease_link_controllers);
1643   GNUNET_TESTBED_operation_queue_insert_ (master->opq_parallel_operations,
1644                                           opc->op);
1645   GNUNET_TESTBED_operation_begin_wait_ (opc->op);
1646   return opc->op;
1647 }
1648
1649
1650 /**
1651  * Like GNUNET_TESTBED_get_slave_config(), however without the host registration
1652  * check. Another difference is that this function takes the id of the slave
1653  * host.
1654  *
1655  * @param op_cls the closure for the operation
1656  * @param master the handle to master controller
1657  * @param slave_host_id id of the host where the slave controller is running to
1658  *          the slave_host should remain valid until this operation is cancelled
1659  *          or marked as finished
1660  * @return the operation handle;
1661  */
1662 struct GNUNET_TESTBED_Operation *
1663 GNUNET_TESTBED_get_slave_config_ (void *op_cls,
1664                                   struct GNUNET_TESTBED_Controller *master,
1665                                   uint32_t slave_host_id)
1666 {
1667   struct OperationContext *opc;
1668   struct GetSlaveConfigData *data;
1669
1670   data = GNUNET_malloc (sizeof (struct GetSlaveConfigData));
1671   data->slave_id = slave_host_id;
1672   opc = GNUNET_malloc (sizeof (struct OperationContext));
1673   opc->state = OPC_STATE_INIT;
1674   opc->c = master;
1675   opc->id = GNUNET_TESTBED_get_next_op_id (master);
1676   opc->type = OP_GET_SLAVE_CONFIG;
1677   opc->data = data;
1678   opc->op_cls = op_cls;
1679   opc->op =
1680       GNUNET_TESTBED_operation_create_ (opc, &opstart_get_slave_config,
1681                                         &oprelease_get_slave_config);
1682   GNUNET_TESTBED_operation_queue_insert_ (master->opq_parallel_operations,
1683                                           opc->op);
1684   GNUNET_TESTBED_operation_begin_wait_ (opc->op);
1685   return opc->op;
1686 }
1687
1688
1689 /**
1690  * Function to acquire the configuration of a running slave controller. The
1691  * completion of the operation is signalled through the controller_cb from
1692  * GNUNET_TESTBED_controller_connect(). If the operation is successful the
1693  * handle to the configuration is available in the generic pointer of
1694  * operation_finished field of struct GNUNET_TESTBED_EventInformation.
1695  *
1696  * @param op_cls the closure for the operation
1697  * @param master the handle to master controller
1698  * @param slave_host the host where the slave controller is running; the handle
1699  *          to the slave_host should remain valid until this operation is
1700  *          cancelled or marked as finished
1701  * @return the operation handle; NULL if the slave_host is not registered at
1702  *           master
1703  */
1704 struct GNUNET_TESTBED_Operation *
1705 GNUNET_TESTBED_get_slave_config (void *op_cls,
1706                                  struct GNUNET_TESTBED_Controller *master,
1707                                  struct GNUNET_TESTBED_Host *slave_host)
1708 {
1709   if (GNUNET_NO == GNUNET_TESTBED_is_host_registered_ (slave_host, master))
1710     return NULL;
1711   return GNUNET_TESTBED_get_slave_config_ (op_cls, master,
1712                                            GNUNET_TESTBED_host_get_id_
1713                                            (slave_host));
1714 }
1715
1716
1717 /**
1718  * Ask the testbed controller to write the current overlay topology to
1719  * a file.  Naturally, the file will only contain a snapshot as the
1720  * topology may evolve all the time.
1721  *
1722  * @param controller overlay controller to inspect
1723  * @param filename name of the file the topology should
1724  *        be written to.
1725  */
1726 void
1727 GNUNET_TESTBED_overlay_write_topology_to_file (struct GNUNET_TESTBED_Controller
1728                                                *controller,
1729                                                const char *filename)
1730 {
1731   GNUNET_break (0);
1732 }
1733
1734
1735 /**
1736  * Creates a helper initialization message. This function is here because we
1737  * want to use this in testing
1738  *
1739  * @param trusted_ip the ip address of the controller which will be set as TRUSTED
1740  *          HOST(all connections form this ip are permitted by the testbed) when
1741  *          starting testbed controller at host. This can either be a single ip
1742  *          address or a network address in CIDR notation.
1743  * @param hostname the hostname of the destination this message is intended for
1744  * @param cfg the configuration that has to used to start the testbed service
1745  *          thru helper
1746  * @return the initialization message
1747  */
1748 struct GNUNET_TESTBED_HelperInit *
1749 GNUNET_TESTBED_create_helper_init_msg_ (const char *trusted_ip,
1750                                         const char *hostname,
1751                                         const struct GNUNET_CONFIGURATION_Handle
1752                                         *cfg)
1753 {
1754   struct GNUNET_TESTBED_HelperInit *msg;
1755   char *config;
1756   char *xconfig;
1757   size_t config_size;
1758   size_t xconfig_size;
1759   uint16_t trusted_ip_len;
1760   uint16_t hostname_len;
1761   uint16_t msg_size;
1762
1763   config = GNUNET_CONFIGURATION_serialize (cfg, &config_size);
1764   GNUNET_assert (NULL != config);
1765   xconfig_size =
1766       GNUNET_TESTBED_compress_config_ (config, config_size, &xconfig);
1767   GNUNET_free (config);
1768   trusted_ip_len = strlen (trusted_ip);
1769   hostname_len = (NULL == hostname) ? 0 : strlen (hostname);
1770   msg_size =
1771       xconfig_size + trusted_ip_len + 1 +
1772       sizeof (struct GNUNET_TESTBED_HelperInit);
1773   msg_size += hostname_len;
1774   msg = GNUNET_realloc (xconfig, msg_size);
1775   (void) memmove (((void *) &msg[1]) + trusted_ip_len + 1 + hostname_len, msg,
1776                   xconfig_size);
1777   msg->header.size = htons (msg_size);
1778   msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_HELPER_INIT);
1779   msg->trusted_ip_size = htons (trusted_ip_len);
1780   msg->hostname_size = htons (hostname_len);
1781   msg->config_size = htons (config_size);
1782   (void) strcpy ((char *) &msg[1], trusted_ip);
1783   if (0 != hostname_len)
1784     (void) strncpy (((char *) &msg[1]) + trusted_ip_len + 1, hostname,
1785                     hostname_len);
1786   return msg;
1787 }
1788
1789
1790 /**
1791  * Signal that the information from an operation has been fully
1792  * processed.  This function MUST be called for each event
1793  * of type 'operation_finished' to fully remove the operation
1794  * from the operation queue.  After calling this function, the
1795  * 'op_result' becomes invalid (!).
1796  *
1797  * @param operation operation to signal completion for
1798  */
1799 void
1800 GNUNET_TESTBED_operation_done (struct GNUNET_TESTBED_Operation *operation)
1801 {
1802   (void) exop_check (operation);
1803   GNUNET_TESTBED_operation_release_ (operation);
1804 }
1805
1806
1807 /**
1808  * Generates configuration by uncompressing configuration in given message. The
1809  * given message should be of the following types:
1810  * GNUNET_MESSAGE_TYPE_TESTBED_PEER_CONFIGURATION,
1811  * GNUNET_MESSAGE_TYPE_TESTBED_SLAVE_CONFIGURATION,
1812  * GNUNET_MESSAGE_TYPE_TESTBED_ADD_HOST,
1813  * GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS,
1814  * GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS_RESULT,
1815  *
1816  * @param msg the message containing compressed configuration
1817  * @return handle to the parsed configuration; NULL upon error while parsing the message
1818  */
1819 struct GNUNET_CONFIGURATION_Handle *
1820 GNUNET_TESTBED_extract_config_ (const struct GNUNET_MessageHeader *msg)
1821 {
1822   struct GNUNET_CONFIGURATION_Handle *cfg;
1823   Bytef *data;
1824   const Bytef *xdata;
1825   uLong data_len;
1826   uLong xdata_len;
1827   int ret;
1828
1829   switch (ntohs (msg->type))
1830   {
1831   case GNUNET_MESSAGE_TYPE_TESTBED_PEER_CONFIGURATION:
1832   {
1833     const struct GNUNET_TESTBED_PeerConfigurationInformationMessage *imsg;
1834
1835     imsg =
1836         (const struct GNUNET_TESTBED_PeerConfigurationInformationMessage *) msg;
1837     data_len = (uLong) ntohs (imsg->config_size);
1838     xdata_len =
1839         ntohs (imsg->header.size) -
1840         sizeof (struct GNUNET_TESTBED_PeerConfigurationInformationMessage);
1841     xdata = (const Bytef *) &imsg[1];
1842   }
1843     break;
1844   case GNUNET_MESSAGE_TYPE_TESTBED_SLAVE_CONFIGURATION:
1845   {
1846     const struct GNUNET_TESTBED_SlaveConfiguration *imsg;
1847
1848     imsg = (const struct GNUNET_TESTBED_SlaveConfiguration *) msg;
1849     data_len = (uLong) ntohs (imsg->config_size);
1850     xdata_len =
1851         ntohs (imsg->header.size) -
1852         sizeof (struct GNUNET_TESTBED_SlaveConfiguration);
1853     xdata = (const Bytef *) &imsg[1];
1854   }
1855   break;
1856   case GNUNET_MESSAGE_TYPE_TESTBED_ADD_HOST:
1857     {
1858       const struct GNUNET_TESTBED_AddHostMessage *imsg;
1859       uint16_t osize;
1860       
1861       imsg = (const struct GNUNET_TESTBED_AddHostMessage *) msg;
1862       data_len = (uLong) ntohs (imsg->config_size);
1863       osize = sizeof (struct GNUNET_TESTBED_AddHostMessage) +
1864           ntohs (imsg->username_length) + ntohs (imsg->hostname_length); 
1865       xdata_len = ntohs (imsg->header.size) - osize;
1866       xdata = (const Bytef *) ((const void *) imsg + osize);
1867     }
1868     break;
1869   case GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS_RESULT:
1870     {
1871       const struct GNUNET_TESTBED_ControllerLinkResponse *imsg;
1872       
1873       imsg = (const struct GNUNET_TESTBED_ControllerLinkResponse *) msg;
1874       data_len = ntohs (imsg->config_size);
1875       xdata_len = ntohs (imsg->header.size) - 
1876           sizeof (const struct GNUNET_TESTBED_ControllerLinkResponse);
1877       xdata = (const Bytef *) &imsg[1];
1878     }
1879     break;
1880   default:
1881     GNUNET_assert (0);
1882   }
1883   data = GNUNET_malloc (data_len);
1884   if (Z_OK != (ret = uncompress (data, &data_len, xdata, xdata_len)))
1885   {
1886     GNUNET_free (data);
1887     GNUNET_break_op (0);
1888     return NULL;
1889   }
1890   cfg = GNUNET_CONFIGURATION_create ();
1891   if (GNUNET_OK !=
1892       GNUNET_CONFIGURATION_deserialize (cfg, (const char *) data,
1893                                         (size_t) data_len,
1894                                         GNUNET_NO))
1895   {
1896     GNUNET_free (data);
1897     GNUNET_break_op (0);
1898     return NULL;
1899   }
1900   GNUNET_free (data);
1901   return cfg;
1902 }
1903
1904
1905 /**
1906  * Checks the integrity of the OperationFailureEventMessage and if good returns
1907  * the error message it contains.
1908  *
1909  * @param msg the OperationFailureEventMessage
1910  * @return the error message
1911  */
1912 const char *
1913 GNUNET_TESTBED_parse_error_string_ (const struct
1914                                     GNUNET_TESTBED_OperationFailureEventMessage
1915                                     *msg)
1916 {
1917   uint16_t msize;
1918   const char *emsg;
1919
1920   msize = ntohs (msg->header.size);
1921   if (sizeof (struct GNUNET_TESTBED_OperationFailureEventMessage) >= msize)
1922     return NULL;
1923   msize -= sizeof (struct GNUNET_TESTBED_OperationFailureEventMessage);
1924   emsg = (const char *) &msg[1];
1925   if ('\0' != emsg[msize - 1])
1926   {
1927     GNUNET_break (0);
1928     return NULL;
1929   }
1930   return emsg;
1931 }
1932
1933
1934 /**
1935  * Function to return the operation id for a controller. The operation id is
1936  * created from the controllers host id and its internal operation counter.
1937  *
1938  * @param controller the handle to the controller whose operation id has to be incremented
1939  * @return the incremented operation id.
1940  */
1941 uint64_t
1942 GNUNET_TESTBED_get_next_op_id (struct GNUNET_TESTBED_Controller * controller)
1943 {
1944   uint64_t op_id;
1945
1946   op_id = (uint64_t) GNUNET_TESTBED_host_get_id_ (controller->host);
1947   op_id = op_id << 32;
1948   op_id |= (uint64_t) controller->operation_counter++;
1949   return op_id;
1950 }
1951
1952
1953 /**
1954  * Function called when a shutdown peers operation is ready
1955  *
1956  * @param cls the closure from GNUNET_TESTBED_operation_create_()
1957  */
1958 static void
1959 opstart_shutdown_peers (void *cls)
1960 {
1961   struct OperationContext *opc = cls;
1962   struct GNUNET_TESTBED_ShutdownPeersMessage *msg;
1963
1964   opc->state = OPC_STATE_STARTED;
1965   msg = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_ShutdownPeersMessage));
1966   msg->header.size = 
1967       htons (sizeof (struct GNUNET_TESTBED_ShutdownPeersMessage));
1968   msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_SHUTDOWN_PEERS);
1969   msg->operation_id = GNUNET_htonll (opc->id);
1970   GNUNET_CONTAINER_DLL_insert_tail (opc->c->ocq_head, opc->c->ocq_tail, opc);
1971   GNUNET_TESTBED_queue_message_ (opc->c, &msg->header);
1972 }
1973
1974
1975 /**
1976  * Callback which will be called when shutdown peers operation is released
1977  *
1978  * @param cls the closure from GNUNET_TESTBED_operation_create_()
1979  */
1980 static void
1981 oprelease_shutdown_peers (void *cls)
1982 {
1983   struct OperationContext *opc = cls;
1984
1985   switch (opc->state)
1986   {
1987   case OPC_STATE_STARTED:
1988     GNUNET_CONTAINER_DLL_remove (opc->c->ocq_head, opc->c->ocq_tail, opc);
1989     /* no break; continue */
1990   case OPC_STATE_INIT:
1991     GNUNET_free (opc->data);
1992     break;
1993   case OPC_STATE_FINISHED:
1994     break;
1995   }
1996   GNUNET_free (opc);
1997 }
1998
1999
2000 /**
2001  * Stops and destroys all peers.  Is equivalent of calling
2002  * GNUNET_TESTBED_peer_stop() and GNUNET_TESTBED_peer_destroy() on all peers,
2003  * except that the peer stop event and operation finished event corresponding to
2004  * the respective functions are not generated.  This function should be called
2005  * when there are no other pending operations.  If there are pending operations,
2006  * it will return NULL
2007  *
2008  * @param controller the controller to send this message to
2009  * @param op_cls closure for the operation
2010  * @param cb the callback to call when all peers are stopped and destroyed
2011  * @param cb_cls the closure for the callback
2012  * @return operation handle on success; NULL if any pending operations are
2013  *           present
2014  */
2015 struct GNUNET_TESTBED_Operation *
2016 GNUNET_TESTBED_shutdown_peers (struct GNUNET_TESTBED_Controller *controller,
2017                                void *op_cls,
2018                                GNUNET_TESTBED_OperationCompletionCallback cb,
2019                                void *cb_cls)
2020 {
2021   struct OperationContext *opc;
2022   struct ShutdownPeersData *data;
2023
2024   if (NULL != controller->ocq_head)
2025     return NULL;
2026   data = GNUNET_malloc (sizeof (struct ShutdownPeersData));
2027   data->cb = cb;
2028   data->cb_cls = cb_cls;
2029   opc = GNUNET_malloc (sizeof (struct OperationContext));
2030   opc->c = controller;
2031   opc->op_cls = op_cls;
2032   opc->data = data;
2033   opc->id =  GNUNET_TESTBED_get_next_op_id (controller);
2034   opc->type = OP_SHUTDOWN_PEERS;
2035   opc->state = OPC_STATE_INIT;  
2036   opc->op = GNUNET_TESTBED_operation_create_ (opc, &opstart_shutdown_peers,
2037                                               &oprelease_shutdown_peers);
2038   GNUNET_TESTBED_operation_queue_insert_ (opc->c->opq_parallel_operations,
2039                                         opc->op);
2040   GNUNET_TESTBED_operation_begin_wait_ (opc->op);
2041   return opc->op;
2042 }
2043
2044
2045 /* end of testbed_api.c */