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