fix
[oweals/gnunet.git] / src / testbed / testbed_api.c
1 /*
2       This file is part of GNUnet
3       Copyright (C) 2008--2013 GNUnet e.V.
4
5       GNUnet is free software: you can redistribute it and/or modify it
6       under the terms of the GNU Affero General Public License as published
7       by the Free Software Foundation, either version 3 of the License,
8       or (at your 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       Affero General Public License for more details.
14      
15       You should have received a copy of the GNU Affero General Public License
16       along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18
19 /**
20  * @file testbed/testbed_api.c
21  * @brief API for accessing the GNUnet testing service.
22  *        This library is supposed to make it easier to write
23  *        testcases and script large-scale benchmarks.
24  * @author Christian Grothoff
25  * @author Sree Harsha Totakura
26  */
27 #include "platform.h"
28 #include "gnunet_testbed_service.h"
29 #include "gnunet_core_service.h"
30 #include "gnunet_constants.h"
31 #include "gnunet_transport_service.h"
32 #include "gnunet_hello_lib.h"
33 #include <zlib.h>
34
35 #include "testbed.h"
36 #include "testbed_api.h"
37 #include "testbed_api_hosts.h"
38 #include "testbed_api_peers.h"
39 #include "testbed_api_operations.h"
40 #include "testbed_api_sd.h"
41
42 /**
43  * Generic logging shorthand
44  */
45 #define LOG(kind, ...)                          \
46   GNUNET_log_from (kind, "testbed-api", __VA_ARGS__)
47
48 /**
49  * Debug logging
50  */
51 #define LOG_DEBUG(...)                          \
52   LOG (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
53
54 /**
55  * Relative time seconds shorthand
56  */
57 #define TIME_REL_SECS(sec) \
58   GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, sec)
59
60
61 /**
62  * Default server message sending retry timeout
63  */
64 #define TIMEOUT_REL TIME_REL_SECS(1)
65
66
67 /**
68  * Context data for forwarded Operation
69  */
70 struct ForwardedOperationData
71 {
72
73   /**
74    * The callback to call when reply is available
75    */
76   GNUNET_MQ_MessageCallback cc;
77
78   /**
79    * The closure for the above callback
80    */
81   void *cc_cls;
82
83 };
84
85
86 /**
87  * Context data for get slave config operations
88  */
89 struct GetSlaveConfigData
90 {
91   /**
92    * The id of the slave controller
93    */
94   uint32_t slave_id;
95
96 };
97
98
99 /**
100  * Context data for controller link operations
101  */
102 struct ControllerLinkData
103 {
104   /**
105    * The controller link message
106    */
107   struct GNUNET_TESTBED_ControllerLinkRequest *msg;
108
109   /**
110    * The id of the host which is hosting the controller to be linked
111    */
112   uint32_t host_id;
113
114 };
115
116
117 /**
118  * Date context for OP_SHUTDOWN_PEERS operations
119  */
120 struct ShutdownPeersData
121 {
122   /**
123    * The operation completion callback to call
124    */
125   GNUNET_TESTBED_OperationCompletionCallback cb;
126
127   /**
128    * The closure for the above callback
129    */
130   void *cb_cls;
131 };
132
133
134 /**
135  * An entry in the stack for keeping operations which are about to expire
136  */
137 struct ExpireOperationEntry
138 {
139   /**
140    * DLL head; new entries are to be inserted here
141    */
142   struct ExpireOperationEntry *next;
143
144   /**
145    * DLL tail; entries are deleted from here
146    */
147   struct ExpireOperationEntry *prev;
148
149   /**
150    * The operation.  This will be a dangling pointer when the operation is freed
151    */
152   const struct GNUNET_TESTBED_Operation *op;
153 };
154
155
156 /**
157  * DLL head for list of operations marked for expiry
158  */
159 static struct ExpireOperationEntry *exop_head;
160
161 /**
162  * DLL tail for list of operation marked for expiry
163  */
164 static struct ExpireOperationEntry *exop_tail;
165
166
167 /**
168  * Inserts an operation into the list of operations marked for expiry
169  *
170  * @param op the operation to insert
171  */
172 static void
173 exop_insert (struct GNUNET_TESTBED_Operation *op)
174 {
175   struct ExpireOperationEntry *entry;
176
177   entry = GNUNET_new (struct ExpireOperationEntry);
178   entry->op = op;
179   GNUNET_CONTAINER_DLL_insert_tail (exop_head, exop_tail, entry);
180 }
181
182
183 /**
184  * Checks if an operation is present in the list of operations marked for
185  * expiry.  If the operation is found, it and the tail of operations after it
186  * are removed from the list.
187  *
188  * @param op the operation to check
189  * @return GNUNET_NO if the operation is not present in the list; GNUNET_YES if
190  *           the operation is found in the list (the operation is then removed
191  *           from the list -- calling this function again with the same
192  *           paramenter will return GNUNET_NO)
193  */
194 static int
195 exop_check (const struct GNUNET_TESTBED_Operation *const op)
196 {
197   struct ExpireOperationEntry *entry;
198   struct ExpireOperationEntry *entry2;
199   int found;
200
201   found = GNUNET_NO;
202   entry = exop_head;
203   while (NULL != entry)
204   {
205     if (op == entry->op)
206     {
207       found = GNUNET_YES;
208       break;
209     }
210     entry = entry->next;
211   }
212   if (GNUNET_NO == found)
213     return GNUNET_NO;
214   /* Truncate the tail */
215   while (NULL != entry)
216   {
217     entry2 = entry->next;
218     GNUNET_CONTAINER_DLL_remove (exop_head,
219                                  exop_tail,
220                                  entry);
221     GNUNET_free (entry);
222     entry = entry2;
223   }
224   return GNUNET_YES;
225 }
226
227
228 /**
229  * Context information to be used while searching for operation contexts
230  */
231 struct SearchContext
232 {
233   /**
234    * The result of the search
235    */
236   struct OperationContext *opc;
237
238   /**
239    * The id of the operation context we are searching for
240    */
241   uint64_t id;
242 };
243
244
245 /**
246  * Search iterator for searching an operation context
247  *
248  * @param cls the serach context
249  * @param key current key code
250  * @param value value in the hash map
251  * @return #GNUNET_YES if we should continue to iterate,
252  *         #GNUNET_NO if not.
253  */
254 static int
255 opc_search_iterator (void *cls,
256                      uint32_t key,
257                      void *value)
258 {
259   struct SearchContext *sc = cls;
260   struct OperationContext *opc = value;
261
262   GNUNET_assert (NULL != opc);
263   GNUNET_assert (NULL == sc->opc);
264   if (opc->id != sc->id)
265     return GNUNET_YES;
266   sc->opc = opc;
267   return GNUNET_NO;
268 }
269
270
271 /**
272  * Returns the operation context with the given id if found in the Operation
273  * context queues of the controller
274  *
275  * @param c the controller whose operation context map is searched
276  * @param id the id which has to be checked
277  * @return the matching operation context; NULL if no match found
278  */
279 static struct OperationContext *
280 find_opc (const struct GNUNET_TESTBED_Controller *c, const uint64_t id)
281 {
282   struct SearchContext sc;
283
284   sc.id = id;
285   sc.opc = NULL;
286   GNUNET_assert (NULL != c->opc_map);
287   if (GNUNET_SYSERR !=
288       GNUNET_CONTAINER_multihashmap32_get_multiple (c->opc_map, (uint32_t) id,
289                                                     &opc_search_iterator, &sc))
290     return NULL;
291   return sc.opc;
292 }
293
294
295 /**
296  * Inserts the given operation context into the operation context map of the
297  * given controller.  Creates the operation context map if one does not exist
298  * for the controller
299  *
300  * @param c the controller
301  * @param opc the operation context to be inserted
302  */
303 void
304 GNUNET_TESTBED_insert_opc_ (struct GNUNET_TESTBED_Controller *c,
305                             struct OperationContext *opc)
306 {
307   if (NULL == c->opc_map)
308     c->opc_map = GNUNET_CONTAINER_multihashmap32_create (256);
309   GNUNET_assert (GNUNET_OK ==
310                  GNUNET_CONTAINER_multihashmap32_put (c->opc_map,
311                                                       (uint32_t) opc->id, opc,
312                                                       GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
313 }
314
315
316 /**
317  * Removes the given operation context from the operation context map of the
318  * given controller
319  *
320  * @param c the controller
321  * @param opc the operation context to remove
322  */
323 void
324 GNUNET_TESTBED_remove_opc_ (const struct GNUNET_TESTBED_Controller *c,
325                             struct OperationContext *opc)
326 {
327   GNUNET_assert (NULL != c->opc_map);
328   GNUNET_assert (GNUNET_YES ==
329                  GNUNET_CONTAINER_multihashmap32_remove (c->opc_map,
330                                                          (uint32_t) opc->id,
331                                                          opc));
332   if ( (0 == GNUNET_CONTAINER_multihashmap32_size (c->opc_map))
333        && (NULL != c->opcq_empty_cb) )
334     c->opcq_empty_cb (c->opcq_empty_cls);
335 }
336
337
338
339 /**
340  * Check #GNUNET_MESSAGE_TYPE_TESTBED_ADDHOSTCONFIRM message is well-formed.
341  *
342  * @param cls the controller handler
343  * @param msg message received
344  * @return #GNUNET_OK if message is well-formed
345  */
346 static int
347 check_add_host_confirm (void *cls,
348                         const struct GNUNET_TESTBED_HostConfirmedMessage *msg)
349 {
350   const char *emsg;
351   uint16_t msg_size;
352
353   msg_size = ntohs (msg->header.size) - sizeof (*msg);
354   if (0 == msg_size)
355     return GNUNET_OK;
356   /* We have an error message */
357   emsg = (const char *) &msg[1];
358   if ('\0' != emsg[msg_size - 1])
359   {
360     GNUNET_break (0);
361     return GNUNET_SYSERR;
362   }
363   return GNUNET_OK;
364 }
365
366
367 /**
368  * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_ADDHOSTCONFIRM message from
369  * controller (testbed service)
370  *
371  * @param cls the controller handler
372  * @param msg message received
373  */
374 static void
375 handle_add_host_confirm (void *cls,
376                          const struct GNUNET_TESTBED_HostConfirmedMessage *msg)
377 {
378   struct GNUNET_TESTBED_Controller *c = cls;
379   struct GNUNET_TESTBED_HostRegistrationHandle *rh = c->rh;
380   const char *emsg;
381   uint16_t msg_size;
382
383   if (NULL == rh)
384     return;
385   if (GNUNET_TESTBED_host_get_id_ (rh->host) != ntohl (msg->host_id))
386   {
387     LOG_DEBUG ("Mismatch in host id's %u, %u of host confirm msg\n",
388                GNUNET_TESTBED_host_get_id_ (rh->host),
389                ntohl (msg->host_id));
390     return;
391   }
392   c->rh = NULL;
393   msg_size = ntohs (msg->header.size) - sizeof (*msg);
394   if (0 == msg_size)
395   {
396     LOG_DEBUG ("Host %u successfully registered\n",
397                ntohl (msg->host_id));
398     GNUNET_TESTBED_mark_host_registered_at_ (rh->host,
399                                              c);
400     rh->cc (rh->cc_cls,
401             NULL);
402     GNUNET_free (rh);
403     return;
404   }
405   /* We have an error message */
406   emsg = (const char *) &msg[1];
407   LOG (GNUNET_ERROR_TYPE_ERROR,
408        _("Adding host %u failed with error: %s\n"),
409        ntohl (msg->host_id),
410        emsg);
411   rh->cc (rh->cc_cls,
412           emsg);
413   GNUNET_free (rh);
414 }
415
416
417 /**
418  * Handler for forwarded operations
419  *
420  * @param c the controller handle
421  * @param opc the opearation context
422  * @param msg the message
423  */
424 static void
425 handle_forwarded_operation_msg (void *cls,
426                                 struct OperationContext *opc,
427                                 const struct GNUNET_MessageHeader *msg)
428 {
429   struct GNUNET_TESTBED_Controller *c = cls;
430   struct ForwardedOperationData *fo_data;
431
432   fo_data = opc->data;
433   if (NULL != fo_data->cc)
434     fo_data->cc (fo_data->cc_cls, msg);
435   GNUNET_TESTBED_remove_opc_ (c, opc);
436   GNUNET_free (fo_data);
437   GNUNET_free (opc);
438 }
439
440
441 /**
442  * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_ADD_HOST_SUCCESS message from
443  * controller (testbed service)
444  *
445  * @param c the controller handler
446  * @param msg message received
447  */
448 static void
449 handle_opsuccess (void *cls,
450                   const struct GNUNET_TESTBED_GenericOperationSuccessEventMessage *msg)
451 {
452   struct GNUNET_TESTBED_Controller *c = cls;
453   struct OperationContext *opc;
454   GNUNET_TESTBED_OperationCompletionCallback op_comp_cb;
455   void *op_comp_cb_cls;
456   struct GNUNET_TESTBED_EventInformation event;
457   uint64_t op_id;
458
459   op_id = GNUNET_ntohll (msg->operation_id);
460   LOG_DEBUG ("Operation %lu successful\n", op_id);
461   if (NULL == (opc = find_opc (c, op_id)))
462   {
463     LOG_DEBUG ("Operation not found\n");
464     return;
465   }
466   event.type = GNUNET_TESTBED_ET_OPERATION_FINISHED;
467   event.op = opc->op;
468   event.op_cls = opc->op_cls;
469   event.details.operation_finished.emsg = NULL;
470   event.details.operation_finished.generic = NULL;
471   op_comp_cb = NULL;
472   op_comp_cb_cls = NULL;
473   switch (opc->type)
474   {
475   case OP_FORWARDED:
476     {
477       handle_forwarded_operation_msg (c, opc,
478                                       (const struct GNUNET_MessageHeader *) msg);
479       return;
480     }
481     break;
482   case OP_PEER_DESTROY:
483   {
484     struct GNUNET_TESTBED_Peer *peer;
485
486     peer = opc->data;
487     GNUNET_TESTBED_peer_deregister_ (peer);
488     GNUNET_free (peer);
489     opc->data = NULL;
490     //PEERDESTROYDATA
491   }
492     break;
493   case OP_SHUTDOWN_PEERS:
494   {
495     struct ShutdownPeersData *data;
496
497     data = opc->data;
498     op_comp_cb = data->cb;
499     op_comp_cb_cls = data->cb_cls;
500     GNUNET_free (data);
501     opc->data = NULL;
502     GNUNET_TESTBED_cleanup_peers_ ();
503   }
504     break;
505   case OP_MANAGE_SERVICE:
506   {
507     struct ManageServiceData *data;
508
509     GNUNET_assert (NULL != (data = opc->data));
510     op_comp_cb = data->cb;
511     op_comp_cb_cls = data->cb_cls;
512     GNUNET_free (data);
513     opc->data = NULL;
514   }
515     break;
516   case OP_PEER_RECONFIGURE:
517     break;
518   default:
519     GNUNET_assert (0);
520   }
521   GNUNET_TESTBED_remove_opc_ (opc->c, opc);
522   opc->state = OPC_STATE_FINISHED;
523   exop_insert (event.op);
524   if (0 != (c->event_mask & (1L << GNUNET_TESTBED_ET_OPERATION_FINISHED)))
525   {
526     if (NULL != c->cc)
527       c->cc (c->cc_cls, &event);
528     if (GNUNET_NO == exop_check (event.op))
529       return;
530   }
531   else
532     LOG_DEBUG ("Not calling callback\n");
533   if (NULL != op_comp_cb)
534     op_comp_cb (op_comp_cb_cls, event.op, NULL);
535    /* You could have marked the operation as done by now */
536   GNUNET_break (GNUNET_NO == exop_check (event.op));
537 }
538
539
540 /**
541  * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER_SUCCESS message from
542  * controller (testbed service)
543  *
544  * @param c the controller handle
545  * @param msg message received
546  */
547 static void
548 handle_peer_create_success (void *cls,
549                             const struct GNUNET_TESTBED_PeerCreateSuccessEventMessage *msg)
550 {
551   struct GNUNET_TESTBED_Controller *c = cls;
552   struct OperationContext *opc;
553   struct PeerCreateData *data;
554   struct GNUNET_TESTBED_Peer *peer;
555   struct GNUNET_TESTBED_Operation *op;
556   GNUNET_TESTBED_PeerCreateCallback cb;
557   void *cb_cls;
558   uint64_t op_id;
559
560   GNUNET_assert (sizeof (struct GNUNET_TESTBED_PeerCreateSuccessEventMessage) ==
561                  ntohs (msg->header.size));
562   op_id = GNUNET_ntohll (msg->operation_id);
563   if (NULL == (opc = find_opc (c, op_id)))
564   {
565     LOG_DEBUG ("Operation context for PeerCreateSuccessEvent not found\n");
566     return;
567   }
568   if (OP_FORWARDED == opc->type)
569   {
570     handle_forwarded_operation_msg (c, opc,
571                                     (const struct GNUNET_MessageHeader *) msg);
572     return;
573   }
574   GNUNET_assert (OP_PEER_CREATE == opc->type);
575   GNUNET_assert (NULL != opc->data);
576   data = opc->data;
577   GNUNET_assert (NULL != data->peer);
578   peer = data->peer;
579   GNUNET_assert (peer->unique_id == ntohl (msg->peer_id));
580   peer->state = TESTBED_PS_CREATED;
581   GNUNET_TESTBED_peer_register_ (peer);
582   cb = data->cb;
583   cb_cls = data->cls;
584   op = opc->op;
585   GNUNET_free (opc->data);
586   GNUNET_TESTBED_remove_opc_ (opc->c, opc);
587   opc->state = OPC_STATE_FINISHED;
588   exop_insert (op);
589   if (NULL != cb)
590     cb (cb_cls, peer, NULL);
591    /* You could have marked the operation as done by now */
592   GNUNET_break (GNUNET_NO == exop_check (op));
593 }
594
595
596 /**
597  * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_PEER_EVENT message from
598  * controller (testbed service)
599  *
600  * @param c the controller handler
601  * @param msg message received
602  */
603 static void
604 handle_peer_event (void *cls,
605                    const struct GNUNET_TESTBED_PeerEventMessage *msg)
606 {
607   struct GNUNET_TESTBED_Controller *c = cls;
608   struct OperationContext *opc;
609   struct GNUNET_TESTBED_Peer *peer;
610   struct PeerEventData *data;
611   GNUNET_TESTBED_PeerChurnCallback pcc;
612   void *pcc_cls;
613   struct GNUNET_TESTBED_EventInformation event;
614   uint64_t op_id;
615   uint64_t mask;
616
617   GNUNET_assert (sizeof (struct GNUNET_TESTBED_PeerEventMessage) ==
618                  ntohs (msg->header.size));
619   op_id = GNUNET_ntohll (msg->operation_id);
620   if (NULL == (opc = find_opc (c, op_id)))
621   {
622     LOG_DEBUG ("Operation not found\n");
623     return;
624   }
625   if (OP_FORWARDED == opc->type)
626   {
627     handle_forwarded_operation_msg (c, opc,
628                                     (const struct GNUNET_MessageHeader *) msg);
629     return;
630   }
631   GNUNET_assert ((OP_PEER_START == opc->type) || (OP_PEER_STOP == opc->type));
632   data = opc->data;
633   GNUNET_assert (NULL != data);
634   peer = data->peer;
635   GNUNET_assert (NULL != peer);
636   event.type = (enum GNUNET_TESTBED_EventType) ntohl (msg->event_type);
637   event.op = opc->op;
638   event.op_cls = opc->op_cls;
639   switch (event.type)
640   {
641   case GNUNET_TESTBED_ET_PEER_START:
642     peer->state = TESTBED_PS_STARTED;
643     event.details.peer_start.host = peer->host;
644     event.details.peer_start.peer = peer;
645     break;
646   case GNUNET_TESTBED_ET_PEER_STOP:
647     peer->state = TESTBED_PS_STOPPED;
648     event.details.peer_stop.peer = peer;
649     break;
650   default:
651     GNUNET_assert (0);          /* We should never reach this state */
652   }
653   pcc = data->pcc;
654   pcc_cls = data->pcc_cls;
655   GNUNET_free (data);
656   GNUNET_TESTBED_remove_opc_ (opc->c, opc);
657   opc->state = OPC_STATE_FINISHED;
658   exop_insert (event.op);
659   mask = 1LL << GNUNET_TESTBED_ET_PEER_START;
660   mask |= 1LL << GNUNET_TESTBED_ET_PEER_STOP;
661   if (0 != (mask & c->event_mask))
662   {
663     if (NULL != c->cc)
664       c->cc (c->cc_cls, &event);
665     if (GNUNET_NO == exop_check (event.op))
666       return;
667   }
668   if (NULL != pcc)
669     pcc (pcc_cls, NULL);
670    /* You could have marked the operation as done by now */
671   GNUNET_break (GNUNET_NO == exop_check (event.op));
672 }
673
674
675 /**
676  * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_PEER_CONNECT_EVENT message from
677  * controller (testbed service)
678  *
679  * @param c the controller handler
680  * @param msg message received
681  */
682 static void
683 handle_peer_conevent (void *cls,
684                       const struct GNUNET_TESTBED_ConnectionEventMessage *msg)
685 {
686   struct GNUNET_TESTBED_Controller *c = cls;
687   struct OperationContext *opc;
688   struct OverlayConnectData *data;
689   GNUNET_TESTBED_OperationCompletionCallback cb;
690   void *cb_cls;
691   struct GNUNET_TESTBED_EventInformation event;
692   uint64_t op_id;
693   uint64_t mask;
694
695   op_id = GNUNET_ntohll (msg->operation_id);
696   if (NULL == (opc = find_opc (c, op_id)))
697   {
698     LOG_DEBUG ("Operation not found\n");
699     return;
700   }
701   if (OP_FORWARDED == opc->type)
702   {
703     handle_forwarded_operation_msg (c, opc,
704                                     (const struct GNUNET_MessageHeader *) msg);
705     return;
706   }
707   GNUNET_assert (OP_OVERLAY_CONNECT == opc->type);
708   GNUNET_assert (NULL != (data = opc->data));
709   GNUNET_assert ((ntohl (msg->peer1) == data->p1->unique_id) &&
710                  (ntohl (msg->peer2) == data->p2->unique_id));
711   event.type = (enum GNUNET_TESTBED_EventType) ntohl (msg->event_type);
712   event.op = opc->op;
713   event.op_cls = opc->op_cls;
714   switch (event.type)
715   {
716   case GNUNET_TESTBED_ET_CONNECT:
717     event.details.peer_connect.peer1 = data->p1;
718     event.details.peer_connect.peer2 = data->p2;
719     break;
720   case GNUNET_TESTBED_ET_DISCONNECT:
721     GNUNET_assert (0);          /* FIXME: implement */
722     break;
723   default:
724     GNUNET_assert (0);          /* Should never reach here */
725     break;
726   }
727   cb = data->cb;
728   cb_cls = data->cb_cls;
729   GNUNET_TESTBED_remove_opc_ (opc->c, opc);
730   opc->state = OPC_STATE_FINISHED;
731   exop_insert (event.op);
732   mask = 1LL << GNUNET_TESTBED_ET_CONNECT;
733   mask |= 1LL << GNUNET_TESTBED_ET_DISCONNECT;
734   if (0 != (mask & c->event_mask))
735   {
736     if (NULL != c->cc)
737       c->cc (c->cc_cls, &event);
738     if (GNUNET_NO == exop_check (event.op))
739       return;
740   }
741   if (NULL != cb)
742     cb (cb_cls, opc->op, NULL);
743    /* You could have marked the operation as done by now */
744   GNUNET_break (GNUNET_NO == exop_check (event.op));
745 }
746
747
748 /**
749  * Validate #GNUNET_MESSAGE_TYPE_TESTBED_PEER_INFORMATION message from
750  * controller (testbed service)
751  *
752  * @param c the controller handler
753  * @param msg message received
754  */
755 static int
756 check_peer_config (void *cls,
757                    const struct GNUNET_TESTBED_PeerConfigurationInformationMessage *msg)
758 {
759   /* anything goes? */
760   return GNUNET_OK;
761 }
762
763
764 /**
765  * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_PEER_INFORMATION message from
766  * controller (testbed service)
767  *
768  * @param c the controller handler
769  * @param msg message received
770  */
771 static void
772 handle_peer_config (void *cls,
773                     const struct GNUNET_TESTBED_PeerConfigurationInformationMessage *msg)
774 {
775   struct GNUNET_TESTBED_Controller *c = cls;
776   struct OperationContext *opc;
777   struct GNUNET_TESTBED_Peer *peer;
778   struct PeerInfoData *data;
779   struct GNUNET_TESTBED_PeerInformation *pinfo;
780   GNUNET_TESTBED_PeerInfoCallback cb;
781   void *cb_cls;
782   uint64_t op_id;
783
784   op_id = GNUNET_ntohll (msg->operation_id);
785   if (NULL == (opc = find_opc (c, op_id)))
786   {
787     LOG_DEBUG ("Operation not found\n");
788     return;
789   }
790   if (OP_FORWARDED == opc->type)
791   {
792     handle_forwarded_operation_msg (c,
793                                     opc,
794                                     &msg->header);
795     return;
796   }
797   data = opc->data;
798   GNUNET_assert (NULL != data);
799   peer = data->peer;
800   GNUNET_assert (NULL != peer);
801   GNUNET_assert (ntohl (msg->peer_id) == peer->unique_id);
802   pinfo = GNUNET_new (struct GNUNET_TESTBED_PeerInformation);
803   pinfo->pit = data->pit;
804   cb = data->cb;
805   cb_cls = data->cb_cls;
806   GNUNET_assert (NULL != cb);
807   GNUNET_free (data);
808   opc->data = NULL;
809   switch (pinfo->pit)
810   {
811   case GNUNET_TESTBED_PIT_IDENTITY:
812     pinfo->result.id = GNUNET_new (struct GNUNET_PeerIdentity);
813     GNUNET_memcpy (pinfo->result.id,
814                    &msg->peer_identity,
815                    sizeof (struct GNUNET_PeerIdentity));
816     break;
817   case GNUNET_TESTBED_PIT_CONFIGURATION:
818     pinfo->result.cfg =         /* Freed in oprelease_peer_getinfo */
819         GNUNET_TESTBED_extract_config_ (&msg->header);
820     break;
821   case GNUNET_TESTBED_PIT_GENERIC:
822     GNUNET_assert (0);          /* never reach here */
823     break;
824   }
825   opc->data = pinfo;
826   GNUNET_TESTBED_remove_opc_ (opc->c, opc);
827   opc->state = OPC_STATE_FINISHED;
828   cb (cb_cls, opc->op, pinfo, NULL);
829   /* We dont check whether the operation is marked as done here as the
830      operation contains data (cfg/identify) which will be freed at a later point
831   */
832 }
833
834
835 /**
836  * Validate #GNUNET_MESSAGE_TYPE_TESTBED_OPERATION_FAIL_EVENT message from
837  * controller (testbed service)
838  *
839  * @param c the controller handler
840  * @param msg message received
841  * @return #GNUNET_OK if message is well-formed
842  */
843 static int
844 check_op_fail_event (void *cls,
845                      const struct GNUNET_TESTBED_OperationFailureEventMessage *msg)
846 {
847   /* we accept anything as a valid error message */
848   return GNUNET_OK;
849 }
850
851
852 /**
853  * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_OPERATION_FAIL_EVENT message from
854  * controller (testbed service)
855  *
856  * @param c the controller handler
857  * @param msg message received
858  */
859 static void
860 handle_op_fail_event (void *cls,
861                       const struct GNUNET_TESTBED_OperationFailureEventMessage *msg)
862 {
863   struct GNUNET_TESTBED_Controller *c = cls;
864   struct OperationContext *opc;
865   const char *emsg;
866   uint64_t op_id;
867   uint64_t mask;
868   struct GNUNET_TESTBED_EventInformation event;
869
870   op_id = GNUNET_ntohll (msg->operation_id);
871   if (NULL == (opc = find_opc (c, op_id)))
872   {
873     LOG_DEBUG ("Operation not found\n");
874     return;
875   }
876   if (OP_FORWARDED == opc->type)
877   {
878     handle_forwarded_operation_msg (c, opc,
879                                     (const struct GNUNET_MessageHeader *) msg);
880     return;
881   }
882   GNUNET_TESTBED_remove_opc_ (opc->c, opc);
883   opc->state = OPC_STATE_FINISHED;
884   emsg = GNUNET_TESTBED_parse_error_string_ (msg);
885   if (NULL == emsg)
886     emsg = "Unknown error";
887   if (OP_PEER_INFO == opc->type)
888   {
889     struct PeerInfoData *data;
890
891     data = opc->data;
892     if (NULL != data->cb)
893       data->cb (data->cb_cls, opc->op, NULL, emsg);
894     GNUNET_free (data);
895     return;          /* We do not call controller callback for peer info */
896   }
897   event.type = GNUNET_TESTBED_ET_OPERATION_FINISHED;
898   event.op = opc->op;
899   event.op_cls = opc->op_cls;
900   event.details.operation_finished.emsg = emsg;
901   event.details.operation_finished.generic = NULL;
902   mask = (1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED);
903   if ((0 != (mask & c->event_mask)) && (NULL != c->cc))
904   {
905     exop_insert (event.op);
906     c->cc (c->cc_cls, &event);
907     if (GNUNET_NO == exop_check (event.op))
908       return;
909   }
910   switch (opc->type)
911   {
912   case OP_PEER_CREATE:
913     {
914       struct PeerCreateData *data;
915
916       data = opc->data;
917       GNUNET_free (data->peer);
918       if (NULL != data->cb)
919         data->cb (data->cls, NULL, emsg);
920       GNUNET_free (data);
921     }
922     break;
923   case OP_PEER_START:
924   case OP_PEER_STOP:
925     {
926       struct PeerEventData *data;
927
928       data = opc->data;
929       if (NULL != data->pcc)
930         data->pcc (data->pcc_cls, emsg);
931       GNUNET_free (data);
932     }
933     break;
934   case OP_PEER_DESTROY:
935     break;
936   case OP_PEER_INFO:
937     GNUNET_assert (0);
938   case OP_OVERLAY_CONNECT:
939     {
940       struct OverlayConnectData *data;
941
942       data = opc->data;
943       GNUNET_TESTBED_operation_mark_failed (opc->op);
944       if (NULL != data->cb)
945         data->cb (data->cb_cls, opc->op, emsg);
946     }
947     break;
948   case OP_FORWARDED:
949     GNUNET_assert (0);
950   case OP_LINK_CONTROLLERS:    /* No secondary callback */
951     break;
952   case OP_SHUTDOWN_PEERS:
953     {
954       struct ShutdownPeersData *data;
955
956       data = opc->data;
957       GNUNET_free (data);         /* FIXME: Decide whether we call data->op_cb */
958       opc->data = NULL;
959     }
960     break;
961   case OP_MANAGE_SERVICE:
962     {
963       struct ManageServiceData *data = opc->data;
964       GNUNET_TESTBED_OperationCompletionCallback cb;
965       void *cb_cls;
966
967       GNUNET_assert (NULL != data);
968       cb = data->cb;
969       cb_cls = data->cb_cls;
970       GNUNET_free (data);
971       opc->data = NULL;
972       exop_insert (event.op);
973       if (NULL != cb)
974         cb (cb_cls, opc->op, emsg);
975       /* You could have marked the operation as done by now */
976       GNUNET_break (GNUNET_NO == exop_check (event.op));
977     }
978     break;
979   default:
980     GNUNET_break (0);
981   }
982 }
983
984
985 /**
986  * Function to build GET_SLAVE_CONFIG message
987  *
988  * @param op_id the id this message should contain in its operation id field
989  * @param slave_id the id this message should contain in its slave id field
990  * @return newly allocated SlaveGetConfigurationMessage
991  */
992 static struct GNUNET_TESTBED_SlaveGetConfigurationMessage *
993 GNUNET_TESTBED_generate_slavegetconfig_msg_ (uint64_t op_id, uint32_t slave_id)
994 {
995   struct GNUNET_TESTBED_SlaveGetConfigurationMessage *msg;
996   uint16_t msize;
997
998   msize = sizeof (struct GNUNET_TESTBED_SlaveGetConfigurationMessage);
999   msg = GNUNET_malloc (msize);
1000   msg->header.size = htons (msize);
1001   msg->header.type =
1002       htons (GNUNET_MESSAGE_TYPE_TESTBED_GET_SLAVE_CONFIGURATION);
1003   msg->operation_id = GNUNET_htonll (op_id);
1004   msg->slave_id = htonl (slave_id);
1005   return msg;
1006 }
1007
1008
1009
1010 /**
1011  * Validate #GNUNET_MESSAGE_TYPE_TESTBED_SLAVE_INFORMATION message from
1012  * controller (testbed service)
1013  *
1014  * @param c the controller handler
1015  * @param msg message received
1016  */
1017 static int
1018 check_slave_config (void *cls,
1019                     const struct GNUNET_TESTBED_SlaveConfiguration *msg)
1020 {
1021   /* anything goes? */
1022   return GNUNET_OK;
1023 }
1024
1025
1026 /**
1027  * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_SLAVE_CONFIGURATION message from controller
1028  * (testbed service)
1029  *
1030  * @param c the controller handler
1031  * @param msg message received
1032  */
1033 static void
1034 handle_slave_config (void *cls,
1035                      const struct GNUNET_TESTBED_SlaveConfiguration *msg)
1036 {
1037   struct GNUNET_TESTBED_Controller *c = cls;
1038   struct OperationContext *opc;
1039   uint64_t op_id;
1040   uint64_t mask;
1041   struct GNUNET_TESTBED_EventInformation event;
1042
1043   op_id = GNUNET_ntohll (msg->operation_id);
1044   if (NULL == (opc = find_opc (c, op_id)))
1045   {
1046     LOG_DEBUG ("Operation not found\n");
1047     return;
1048   }
1049   if (OP_GET_SLAVE_CONFIG != opc->type)
1050   {
1051     GNUNET_break (0);
1052     return;
1053   }
1054   opc->state = OPC_STATE_FINISHED;
1055   GNUNET_TESTBED_remove_opc_ (opc->c, opc);
1056   mask = 1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED;
1057   if ((0 != (mask & c->event_mask)) &&
1058       (NULL != c->cc))
1059   {
1060     opc->data = GNUNET_TESTBED_extract_config_ (&msg->header);
1061     event.type = GNUNET_TESTBED_ET_OPERATION_FINISHED;
1062     event.op = opc->op;
1063     event.op_cls = opc->op_cls;
1064     event.details.operation_finished.generic = opc->data;
1065     event.details.operation_finished.emsg = NULL;
1066     c->cc (c->cc_cls, &event);
1067   }
1068 }
1069
1070
1071 /**
1072  * Check #GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS_RESULT message from controller
1073  * (testbed service)
1074  *
1075  * @param c the controller handler
1076  * @param msg message received
1077  * @return #GNUNET_OK if @a msg is well-formed
1078  */
1079 static int
1080 check_link_controllers_result (void *cls,
1081                                 const struct GNUNET_TESTBED_ControllerLinkResponse *msg)
1082 {
1083   /* actual check to be implemented */
1084   return GNUNET_OK;
1085 }
1086
1087
1088 /**
1089  * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS_RESULT message from controller
1090  * (testbed service)
1091  *
1092  * @param c the controller handler
1093  * @param msg message received
1094  */
1095 static void
1096 handle_link_controllers_result (void *cls,
1097                                 const struct GNUNET_TESTBED_ControllerLinkResponse *msg)
1098 {
1099   struct GNUNET_TESTBED_Controller *c = cls;
1100   struct OperationContext *opc;
1101   struct ControllerLinkData *data;
1102   struct GNUNET_CONFIGURATION_Handle *cfg;
1103   struct GNUNET_TESTBED_Host *host;
1104   char *emsg;
1105   uint64_t op_id;
1106   struct GNUNET_TESTBED_EventInformation event;
1107
1108   op_id = GNUNET_ntohll (msg->operation_id);
1109   if (NULL == (opc = find_opc (c, op_id)))
1110   {
1111     LOG_DEBUG ("Operation not found\n");
1112     return;
1113   }
1114   if (OP_FORWARDED == opc->type)
1115   {
1116     handle_forwarded_operation_msg (c, opc,
1117                                     (const struct GNUNET_MessageHeader *) msg);
1118     return;
1119   }
1120   if (OP_LINK_CONTROLLERS != opc->type)
1121   {
1122     GNUNET_break (0);
1123     return;
1124   }
1125   GNUNET_assert (NULL != (data = opc->data));
1126   host = GNUNET_TESTBED_host_lookup_by_id_ (data->host_id);
1127   GNUNET_assert (NULL != host);
1128   GNUNET_free (data);
1129   opc->data = NULL;
1130   opc->state = OPC_STATE_FINISHED;
1131   GNUNET_TESTBED_remove_opc_ (opc->c, opc);
1132   event.type = GNUNET_TESTBED_ET_OPERATION_FINISHED;
1133   event.op = opc->op;
1134   event.op_cls = opc->op_cls;
1135   event.details.operation_finished.emsg = NULL;
1136   event.details.operation_finished.generic = NULL;
1137   emsg = NULL;
1138   cfg = NULL;
1139   if (GNUNET_NO == ntohs (msg->success))
1140   {
1141     emsg = GNUNET_malloc (ntohs (msg->header.size)
1142                           - sizeof (struct
1143                                     GNUNET_TESTBED_ControllerLinkResponse) + 1);
1144     GNUNET_memcpy (emsg,
1145                    &msg[1],
1146                    ntohs (msg->header.size)- sizeof (struct GNUNET_TESTBED_ControllerLinkResponse));
1147     event.details.operation_finished.emsg = emsg;
1148   }
1149   else
1150   {
1151     if (0 != ntohs (msg->config_size))
1152     {
1153       cfg = GNUNET_TESTBED_extract_config_ ((const struct GNUNET_MessageHeader *) msg);
1154       GNUNET_assert (NULL != cfg);
1155       GNUNET_TESTBED_host_replace_cfg_ (host, cfg);
1156     }
1157   }
1158   if (0 != (c->event_mask & (1L << GNUNET_TESTBED_ET_OPERATION_FINISHED)))
1159   {
1160     if (NULL != c->cc)
1161       c->cc (c->cc_cls, &event);
1162   }
1163   else
1164     LOG_DEBUG ("Not calling callback\n");
1165   if (NULL != cfg)
1166     GNUNET_CONFIGURATION_destroy (cfg);
1167   GNUNET_free_non_null (emsg);
1168 }
1169
1170
1171 /**
1172  * Validate #GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_STATUS message.
1173  *
1174  * @param cls the controller handle to determine the connection this message
1175  *   belongs to
1176  * @param msg the barrier status message
1177  * @return #GNUNET_OK if the message is valid; #GNUNET_SYSERR to tear it
1178  *   down signalling an error (message malformed)
1179  */
1180 static int
1181 check_barrier_status (void *cls,
1182                       const struct GNUNET_TESTBED_BarrierStatusMsg *msg)
1183 {
1184   uint16_t msize;
1185   uint16_t name_len;
1186   int status;
1187   const char *name;
1188   size_t emsg_len;
1189
1190   msize = ntohs (msg->header.size);
1191   name = msg->data;
1192   name_len = ntohs (msg->name_len);
1193
1194   if (sizeof (struct GNUNET_TESTBED_BarrierStatusMsg) + name_len + 1 > msize)
1195   {
1196     GNUNET_break_op (0);
1197     return GNUNET_SYSERR;
1198   }
1199   if ('\0' != name[name_len])
1200   {
1201     GNUNET_break_op (0);
1202     return GNUNET_SYSERR;
1203   }
1204   status = ntohs (msg->status);
1205   if (GNUNET_TESTBED_BARRIERSTATUS_ERROR == status)
1206   {
1207     emsg_len = msize - (sizeof (struct GNUNET_TESTBED_BarrierStatusMsg) + name_len
1208                         + 1); /* +1!? */
1209     if (0 == emsg_len)
1210     {
1211       GNUNET_break_op (0);
1212       return GNUNET_SYSERR;
1213     }
1214   }
1215   return GNUNET_OK;
1216 }
1217
1218
1219 /**
1220  * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_STATUS messages
1221  *
1222  * @param cls the controller handle to determine the connection this message
1223  *   belongs to
1224  * @param msg the barrier status message
1225  */
1226 static void
1227 handle_barrier_status (void *cls,
1228                        const struct GNUNET_TESTBED_BarrierStatusMsg *msg)
1229 {
1230   struct GNUNET_TESTBED_Controller *c = cls;
1231   struct GNUNET_TESTBED_Barrier *barrier;
1232   char *emsg;
1233   const char *name;
1234   struct GNUNET_HashCode key;
1235   size_t emsg_len;
1236   int status;
1237   uint16_t msize;
1238   uint16_t name_len;
1239
1240   emsg = NULL;
1241   barrier = NULL;
1242   msize = ntohs (msg->header.size);
1243   if (msize <= sizeof (struct GNUNET_TESTBED_BarrierStatusMsg))
1244   {
1245     GNUNET_break_op (0);
1246     goto cleanup;
1247   }
1248   name = msg->data;
1249   name_len = ntohs (msg->name_len);
1250   if (name_len >=  //name_len is strlen(barrier_name)
1251       (msize - ((sizeof msg->header) + sizeof (msg->status)) )   )
1252   {
1253     GNUNET_break_op (0);
1254     goto cleanup;
1255   }
1256   if ('\0' != name[name_len])
1257   {
1258     GNUNET_break_op (0);
1259     goto cleanup;
1260   }
1261   LOG_DEBUG ("Received BARRIER_STATUS msg\n");
1262   status = ntohs (msg->status);
1263   if (GNUNET_TESTBED_BARRIERSTATUS_ERROR == status)
1264   {
1265     status = -1;
1266     //unlike name_len, emsg_len includes the trailing zero
1267     emsg_len = msize - (sizeof (struct GNUNET_TESTBED_BarrierStatusMsg)
1268                         + (name_len + 1));
1269     if (0 == emsg_len)
1270     {
1271       GNUNET_break_op (0);
1272       goto cleanup;
1273     }
1274     if ('\0' != (msg->data[(name_len + 1) + (emsg_len - 1)]))
1275     {
1276       GNUNET_break_op (0);
1277       goto cleanup;
1278     }
1279     emsg = GNUNET_malloc (emsg_len);
1280     GNUNET_memcpy (emsg,
1281                    msg->data + name_len + 1,
1282                    emsg_len);
1283   }
1284   if (NULL == c->barrier_map)
1285   {
1286     GNUNET_break_op (0);
1287     goto cleanup;
1288   }
1289   GNUNET_CRYPTO_hash (name, name_len, &key);
1290   barrier = GNUNET_CONTAINER_multihashmap_get (c->barrier_map, &key);
1291   if (NULL == barrier)
1292   {
1293     GNUNET_break_op (0);
1294     goto cleanup;
1295   }
1296   GNUNET_assert (NULL != barrier->cb);
1297   if ((GNUNET_YES == barrier->echo) &&
1298       (GNUNET_TESTBED_BARRIERSTATUS_CROSSED == status))
1299     GNUNET_TESTBED_queue_message_ (c,
1300                                    GNUNET_copy_message (&msg->header));
1301   barrier->cb (barrier->cls,
1302                name,
1303                barrier,
1304                status,
1305                emsg);
1306   if (GNUNET_TESTBED_BARRIERSTATUS_INITIALISED == status)
1307     return;           /* just initialised; skip cleanup */
1308
1309  cleanup:
1310   GNUNET_free_non_null (emsg);
1311   /**
1312    * Do not remove the barrier if we did not echo the status back; this is
1313    * required at the chained testbed controller setup to ensure the only the
1314    * test-driver echos the status and the controller hierarchy properly
1315    * propagates the status.
1316    */
1317   if ((NULL != barrier) && (GNUNET_YES == barrier->echo))
1318     GNUNET_TESTBED_barrier_remove_ (barrier);
1319 }
1320
1321
1322 /**
1323  * Queues a message in send queue for sending to the service
1324  *
1325  * @param controller the handle to the controller
1326  * @param msg the message to queue
1327  */
1328 void
1329 GNUNET_TESTBED_queue_message_ (struct GNUNET_TESTBED_Controller *controller,
1330                                struct GNUNET_MessageHeader *msg)
1331 {
1332   struct GNUNET_MQ_Envelope *env;
1333   struct GNUNET_MessageHeader *m2;
1334   uint16_t type;
1335   uint16_t size;
1336
1337   type = ntohs (msg->type);
1338   size = ntohs (msg->size);
1339   GNUNET_assert ((GNUNET_MESSAGE_TYPE_TESTBED_INIT <= type) &&
1340                  (GNUNET_MESSAGE_TYPE_TESTBED_MAX > type));
1341   env = GNUNET_MQ_msg_extra (m2,
1342                              size - sizeof (*m2),
1343                              type);
1344   GNUNET_memcpy (m2, msg, size);
1345   GNUNET_free (msg);
1346   GNUNET_MQ_send (controller->mq,
1347                   env);
1348 }
1349
1350
1351 /**
1352  * Sends the given message as an operation. The given callback is called when a
1353  * reply for the operation is available.  Call
1354  * GNUNET_TESTBED_forward_operation_msg_cancel_() to cleanup the returned
1355  * operation context if the cc hasn't been called
1356  *
1357  * @param controller the controller to which the message has to be sent
1358  * @param operation_id the operation id of the message
1359  * @param msg the message to send
1360  * @param cc the callback to call when reply is available
1361  * @param cc_cls the closure for the above callback
1362  * @return the operation context which can be used to cancel the forwarded
1363  *           operation
1364  */
1365 struct OperationContext *
1366 GNUNET_TESTBED_forward_operation_msg_ (struct GNUNET_TESTBED_Controller *controller,
1367                                        uint64_t operation_id,
1368                                        const struct GNUNET_MessageHeader *msg,
1369                                        GNUNET_MQ_MessageCallback cc,
1370                                        void *cc_cls)
1371 {
1372   struct OperationContext *opc;
1373   struct ForwardedOperationData *data;
1374   struct GNUNET_MQ_Envelope *env;
1375   struct GNUNET_MessageHeader *m2;
1376   uint16_t type = ntohs (msg->type);
1377   uint16_t size = ntohs (msg->size);
1378
1379   env = GNUNET_MQ_msg_extra (m2,
1380                              size - sizeof (*m2),
1381                              type);
1382   GNUNET_memcpy (m2,
1383                  msg,
1384                  size);
1385   GNUNET_MQ_send (controller->mq,
1386                   env);
1387   data = GNUNET_new (struct ForwardedOperationData);
1388   data->cc = cc;
1389   data->cc_cls = cc_cls;
1390   opc = GNUNET_new (struct OperationContext);
1391   opc->c = controller;
1392   opc->type = OP_FORWARDED;
1393   opc->data = data;
1394   opc->id = operation_id;
1395   GNUNET_TESTBED_insert_opc_ (controller,
1396                               opc);
1397   return opc;
1398 }
1399
1400
1401 /**
1402  * Function to cancel an operation created by simply forwarding an operation
1403  * message.
1404  *
1405  * @param opc the operation context from GNUNET_TESTBED_forward_operation_msg_()
1406  */
1407 void
1408 GNUNET_TESTBED_forward_operation_msg_cancel_ (struct OperationContext *opc)
1409 {
1410   GNUNET_TESTBED_remove_opc_ (opc->c,
1411                               opc);
1412   GNUNET_free (opc->data);
1413   GNUNET_free (opc);
1414 }
1415
1416
1417 /**
1418  * Function to call to start a link-controllers type operation once all queues
1419  * the operation is part of declare that the operation can be activated.
1420  *
1421  * @param cls the closure from GNUNET_TESTBED_operation_create_()
1422  */
1423 static void
1424 opstart_link_controllers (void *cls)
1425 {
1426   struct OperationContext *opc = cls;
1427   struct ControllerLinkData *data;
1428   struct GNUNET_TESTBED_ControllerLinkRequest *msg;
1429
1430   GNUNET_assert (NULL != opc->data);
1431   data = opc->data;
1432   msg = data->msg;
1433   data->msg = NULL;
1434   opc->state = OPC_STATE_STARTED;
1435   GNUNET_TESTBED_insert_opc_ (opc->c, opc);
1436   GNUNET_TESTBED_queue_message_ (opc->c, &msg->header);
1437 }
1438
1439
1440 /**
1441  * Callback which will be called when link-controllers type operation is released
1442  *
1443  * @param cls the closure from GNUNET_TESTBED_operation_create_()
1444  */
1445 static void
1446 oprelease_link_controllers (void *cls)
1447 {
1448   struct OperationContext *opc = cls;
1449   struct ControllerLinkData *data;
1450
1451   data = opc->data;
1452   switch (opc->state)
1453   {
1454   case OPC_STATE_INIT:
1455     GNUNET_free (data->msg);
1456     break;
1457   case OPC_STATE_STARTED:
1458     GNUNET_TESTBED_remove_opc_ (opc->c, opc);
1459     break;
1460   case OPC_STATE_FINISHED:
1461     break;
1462   }
1463   GNUNET_free_non_null (data);
1464   GNUNET_free (opc);
1465 }
1466
1467
1468 /**
1469  * Function to be called when get slave config operation is ready
1470  *
1471  * @param cls the OperationContext of type OP_GET_SLAVE_CONFIG
1472  */
1473 static void
1474 opstart_get_slave_config (void *cls)
1475 {
1476   struct OperationContext *opc = cls;
1477   struct GetSlaveConfigData *data = opc->data;
1478   struct GNUNET_TESTBED_SlaveGetConfigurationMessage *msg;
1479
1480   GNUNET_assert (NULL != data);
1481   msg = GNUNET_TESTBED_generate_slavegetconfig_msg_ (opc->id, data->slave_id);
1482   GNUNET_free (opc->data);
1483   data = NULL;
1484   opc->data = NULL;
1485   GNUNET_TESTBED_insert_opc_ (opc->c, opc);
1486   GNUNET_TESTBED_queue_message_ (opc->c, &msg->header);
1487   opc->state = OPC_STATE_STARTED;
1488 }
1489
1490
1491 /**
1492  * Function to be called when get slave config operation is cancelled or finished
1493  *
1494  * @param cls the OperationContext of type OP_GET_SLAVE_CONFIG
1495  */
1496 static void
1497 oprelease_get_slave_config (void *cls)
1498 {
1499   struct OperationContext *opc = cls;
1500
1501   switch (opc->state)
1502   {
1503   case OPC_STATE_INIT:
1504     GNUNET_free (opc->data);
1505     break;
1506   case OPC_STATE_STARTED:
1507     GNUNET_TESTBED_remove_opc_ (opc->c, opc);
1508     break;
1509   case OPC_STATE_FINISHED:
1510     if (NULL != opc->data)
1511       GNUNET_CONFIGURATION_destroy (opc->data);
1512     break;
1513   }
1514   GNUNET_free (opc);
1515 }
1516
1517
1518 /**
1519  * Generic error handler, called with the appropriate error code and
1520  * the same closure specified at the creation of the message queue.
1521  * Not every message queue implementation supports an error handler.
1522  *
1523  * @param cls closure, a `struct GNUNET_TESTBED_Controller *`
1524  * @param error error code
1525  */
1526 static void
1527 mq_error_handler (void *cls,
1528                   enum GNUNET_MQ_Error error)
1529 {
1530   /* struct GNUNET_TESTBED_Controller *c = cls; */
1531
1532   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1533               "Encountered MQ error: %d\n",
1534               error);
1535   /* now what? */
1536   GNUNET_SCHEDULER_shutdown (); /* seems most reasonable */
1537 }
1538
1539
1540 /**
1541  * Start a controller process using the given configuration at the
1542  * given host.
1543  *
1544  * @param host host to run the controller on; This should be the same host if
1545  *          the controller was previously started with
1546  *          GNUNET_TESTBED_controller_start()
1547  * @param event_mask bit mask with set of events to call 'cc' for;
1548  *                   or-ed values of "1LL" shifted by the
1549  *                   respective 'enum GNUNET_TESTBED_EventType'
1550  *                   (i.e.  "(1LL << GNUNET_TESTBED_ET_CONNECT) | ...")
1551  * @param cc controller callback to invoke on events
1552  * @param cc_cls closure for cc
1553  * @return handle to the controller
1554  */
1555 struct GNUNET_TESTBED_Controller *
1556 GNUNET_TESTBED_controller_connect (struct GNUNET_TESTBED_Host *host,
1557                                    uint64_t event_mask,
1558                                    GNUNET_TESTBED_ControllerCallback cc,
1559                                    void *cc_cls)
1560 {
1561   struct GNUNET_TESTBED_Controller *controller
1562     = GNUNET_new (struct GNUNET_TESTBED_Controller);
1563   struct GNUNET_MQ_MessageHandler handlers[] = {
1564     GNUNET_MQ_hd_var_size (add_host_confirm,
1565                            GNUNET_MESSAGE_TYPE_TESTBED_ADD_HOST_SUCCESS,
1566                            struct GNUNET_TESTBED_HostConfirmedMessage,
1567                            controller),
1568     GNUNET_MQ_hd_fixed_size (peer_conevent,
1569                              GNUNET_MESSAGE_TYPE_TESTBED_PEER_CONNECT_EVENT,
1570                              struct GNUNET_TESTBED_ConnectionEventMessage,
1571                              controller),
1572     GNUNET_MQ_hd_fixed_size (opsuccess,
1573                              GNUNET_MESSAGE_TYPE_TESTBED_GENERIC_OPERATION_SUCCESS,
1574                              struct GNUNET_TESTBED_GenericOperationSuccessEventMessage,
1575                              controller),
1576     GNUNET_MQ_hd_var_size (op_fail_event,
1577                            GNUNET_MESSAGE_TYPE_TESTBED_OPERATION_FAIL_EVENT,
1578                            struct GNUNET_TESTBED_OperationFailureEventMessage,
1579                            controller),
1580     GNUNET_MQ_hd_fixed_size (peer_create_success,
1581                              GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER_SUCCESS,
1582                              struct GNUNET_TESTBED_PeerCreateSuccessEventMessage,
1583                              controller),
1584     GNUNET_MQ_hd_fixed_size (peer_event,
1585                              GNUNET_MESSAGE_TYPE_TESTBED_PEER_EVENT,
1586                              struct GNUNET_TESTBED_PeerEventMessage,
1587                              controller),
1588     GNUNET_MQ_hd_var_size (peer_config,
1589                            GNUNET_MESSAGE_TYPE_TESTBED_PEER_INFORMATION,
1590                            struct GNUNET_TESTBED_PeerConfigurationInformationMessage,
1591                            controller),
1592     GNUNET_MQ_hd_var_size (slave_config,
1593                            GNUNET_MESSAGE_TYPE_TESTBED_SLAVE_CONFIGURATION,
1594                            struct GNUNET_TESTBED_SlaveConfiguration,
1595                            controller),
1596     GNUNET_MQ_hd_var_size (link_controllers_result,
1597                            GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS_RESULT,
1598                            struct GNUNET_TESTBED_ControllerLinkResponse,
1599                            controller),
1600     GNUNET_MQ_hd_var_size (barrier_status,
1601                            GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_STATUS,
1602                            struct GNUNET_TESTBED_BarrierStatusMsg,
1603                            controller),
1604     GNUNET_MQ_handler_end ()
1605   };
1606   struct GNUNET_TESTBED_InitMessage *msg;
1607   struct GNUNET_MQ_Envelope *env;
1608   const struct GNUNET_CONFIGURATION_Handle *cfg;
1609   const char *controller_hostname;
1610   unsigned long long max_parallel_operations;
1611   unsigned long long max_parallel_service_connections;
1612   unsigned long long max_parallel_topology_config_operations;
1613   size_t slen;
1614
1615   GNUNET_assert (NULL != (cfg = GNUNET_TESTBED_host_get_cfg_ (host)));
1616   if (GNUNET_OK !=
1617       GNUNET_CONFIGURATION_get_value_number (cfg, "testbed",
1618                                              "MAX_PARALLEL_OPERATIONS",
1619                                              &max_parallel_operations))
1620   {
1621     GNUNET_break (0);
1622     GNUNET_free (controller);
1623     return NULL;
1624   }
1625   if (GNUNET_OK !=
1626       GNUNET_CONFIGURATION_get_value_number (cfg, "testbed",
1627                                              "MAX_PARALLEL_SERVICE_CONNECTIONS",
1628                                              &max_parallel_service_connections))
1629   {
1630     GNUNET_break (0);
1631     GNUNET_free (controller);
1632     return NULL;
1633   }
1634   if (GNUNET_OK !=
1635       GNUNET_CONFIGURATION_get_value_number (cfg, "testbed",
1636                                              "MAX_PARALLEL_TOPOLOGY_CONFIG_OPERATIONS",
1637                                              &max_parallel_topology_config_operations))
1638   {
1639     GNUNET_break (0);
1640     GNUNET_free (controller);
1641     return NULL;
1642   }
1643   controller->cc = cc;
1644   controller->cc_cls = cc_cls;
1645   controller->event_mask = event_mask;
1646   controller->cfg = GNUNET_CONFIGURATION_dup (cfg);
1647   controller->mq = GNUNET_CLIENT_connect (controller->cfg,
1648                                           "testbed",
1649                                           handlers,
1650                                           &mq_error_handler,
1651                                           controller);
1652   if (NULL == controller->mq)
1653   {
1654     GNUNET_break (0);
1655     GNUNET_TESTBED_controller_disconnect (controller);
1656     return NULL;
1657   }
1658   GNUNET_TESTBED_mark_host_registered_at_ (host, controller);
1659   controller->host = host;
1660   controller->opq_parallel_operations =
1661       GNUNET_TESTBED_operation_queue_create_ (OPERATION_QUEUE_TYPE_FIXED,
1662                                               (unsigned int) max_parallel_operations);
1663   controller->opq_parallel_service_connections =
1664       GNUNET_TESTBED_operation_queue_create_ (OPERATION_QUEUE_TYPE_FIXED,
1665                                               (unsigned int)
1666                                               max_parallel_service_connections);
1667   controller->opq_parallel_topology_config_operations =
1668       GNUNET_TESTBED_operation_queue_create_ (OPERATION_QUEUE_TYPE_FIXED,
1669                                               (unsigned int)
1670                                               max_parallel_topology_config_operations);
1671   controller_hostname = GNUNET_TESTBED_host_get_hostname (host);
1672   if (NULL == controller_hostname)
1673     controller_hostname = "127.0.0.1";
1674   slen = strlen (controller_hostname) + 1;
1675   env = GNUNET_MQ_msg_extra (msg,
1676                              slen,
1677                              GNUNET_MESSAGE_TYPE_TESTBED_INIT);
1678   msg->host_id = htonl (GNUNET_TESTBED_host_get_id_ (host));
1679   msg->event_mask = GNUNET_htonll (controller->event_mask);
1680   GNUNET_memcpy (&msg[1],
1681                  controller_hostname,
1682                  slen);
1683   GNUNET_MQ_send (controller->mq,
1684                   env);
1685   return controller;
1686 }
1687
1688
1689 /**
1690  * Iterator to free opc map entries
1691  *
1692  * @param cls closure
1693  * @param key current key code
1694  * @param value value in the hash map
1695  * @return #GNUNET_YES if we should continue to iterate,
1696  *         #GNUNET_NO if not.
1697  */
1698 static int
1699 opc_free_iterator (void *cls, uint32_t key, void *value)
1700 {
1701   struct GNUNET_CONTAINER_MultiHashMap32 *map = cls;
1702   struct OperationContext *opc = value;
1703
1704   GNUNET_assert (NULL != opc);
1705   GNUNET_break (0);
1706   GNUNET_assert (GNUNET_YES ==
1707                  GNUNET_CONTAINER_multihashmap32_remove (map, key, value));
1708   GNUNET_free (opc);
1709   return GNUNET_YES;
1710 }
1711
1712
1713 /**
1714  * Stop the given controller (also will terminate all peers and
1715  * controllers dependent on this controller).  This function
1716  * blocks until the testbed has been fully terminated (!).
1717  *
1718  * @param c handle to controller to stop
1719  */
1720 void
1721 GNUNET_TESTBED_controller_disconnect (struct GNUNET_TESTBED_Controller *c)
1722 {
1723   if (NULL != c->mq)
1724   {
1725     GNUNET_MQ_destroy (c->mq);
1726     c->mq = NULL;
1727   }
1728   if (NULL != c->host)
1729     GNUNET_TESTBED_deregister_host_at_ (c->host, c);
1730   GNUNET_CONFIGURATION_destroy (c->cfg);
1731   GNUNET_TESTBED_operation_queue_destroy_ (c->opq_parallel_operations);
1732   GNUNET_TESTBED_operation_queue_destroy_
1733       (c->opq_parallel_service_connections);
1734   GNUNET_TESTBED_operation_queue_destroy_
1735       (c->opq_parallel_topology_config_operations);
1736   if (NULL != c->opc_map)
1737   {
1738     GNUNET_assert (GNUNET_SYSERR !=
1739                    GNUNET_CONTAINER_multihashmap32_iterate (c->opc_map,
1740                                                             &opc_free_iterator,
1741                                                             c->opc_map));
1742     GNUNET_assert (0 == GNUNET_CONTAINER_multihashmap32_size (c->opc_map));
1743     GNUNET_CONTAINER_multihashmap32_destroy (c->opc_map);
1744   }
1745   GNUNET_free (c);
1746 }
1747
1748
1749 /**
1750  * Compresses given configuration using zlib compress
1751  *
1752  * @param config the serialized configuration
1753  * @param size the size of config
1754  * @param xconfig will be set to the compressed configuration (memory is fresly
1755  *          allocated)
1756  * @return the size of the xconfig
1757  */
1758 size_t
1759 GNUNET_TESTBED_compress_config_ (const char *config,
1760                                  size_t size,
1761                                  char **xconfig)
1762 {
1763   size_t xsize;
1764
1765   xsize = compressBound ((uLong) size);
1766   *xconfig = GNUNET_malloc (xsize);
1767   GNUNET_assert (Z_OK ==
1768                  compress2 ((Bytef *) * xconfig, (uLongf *) & xsize,
1769                             (const Bytef *) config, (uLongf) size,
1770                             Z_BEST_SPEED));
1771   return xsize;
1772 }
1773
1774
1775 /**
1776  * Function to serialize and compress using zlib a configuration through a
1777  * configuration handle
1778  *
1779  * @param cfg the configuration
1780  * @param size the size of configuration when serialize.  Will be set on success.
1781  * @param xsize the sizeo of the compressed configuration.  Will be set on success.
1782  * @return the serialized and compressed configuration
1783  */
1784 char *
1785 GNUNET_TESTBED_compress_cfg_ (const struct GNUNET_CONFIGURATION_Handle *cfg,
1786                               size_t *size, size_t *xsize)
1787 {
1788   char *config;
1789   char *xconfig;
1790   size_t size_;
1791   size_t xsize_;
1792
1793   config = GNUNET_CONFIGURATION_serialize (cfg, &size_);
1794   xsize_ = GNUNET_TESTBED_compress_config_ (config, size_, &xconfig);
1795   GNUNET_free (config);
1796   *size = size_;
1797   *xsize = xsize_;
1798   return xconfig;
1799 }
1800
1801
1802 /**
1803  * Create a link from slave controller to delegated controller. Whenever the
1804  * master controller is asked to start a peer at the delegated controller the
1805  * request will be routed towards slave controller (if a route exists). The
1806  * slave controller will then route it to the delegated controller. The
1807  * configuration of the delegated controller is given and is used to either
1808  * create the delegated controller or to connect to an existing controller. Note
1809  * that while starting the delegated controller the configuration will be
1810  * modified to accommodate available free ports.  the 'is_subordinate' specifies
1811  * if the given delegated controller should be started and managed by the slave
1812  * controller, or if the delegated controller already has a master and the slave
1813  * controller connects to it as a non master controller. The success or failure
1814  * of this operation will be signalled through the
1815  * GNUNET_TESTBED_ControllerCallback() with an event of type
1816  * GNUNET_TESTBED_ET_OPERATION_FINISHED
1817  *
1818  * @param op_cls the operation closure for the event which is generated to
1819  *          signal success or failure of this operation
1820  * @param master handle to the master controller who creates the association
1821  * @param delegated_host requests to which host should be delegated; cannot be NULL
1822  * @param slave_host which host is used to run the slave controller; use NULL to
1823  *          make the master controller connect to the delegated host
1824  * @param is_subordinate GNUNET_YES if the controller at delegated_host should
1825  *          be started by the slave controller; GNUNET_NO if the slave
1826  *          controller has to connect to the already started delegated
1827  *          controller via TCP/IP
1828  * @return the operation handle
1829  */
1830 struct GNUNET_TESTBED_Operation *
1831 GNUNET_TESTBED_controller_link (void *op_cls,
1832                                 struct GNUNET_TESTBED_Controller *master,
1833                                 struct GNUNET_TESTBED_Host *delegated_host,
1834                                 struct GNUNET_TESTBED_Host *slave_host,
1835                                 int is_subordinate)
1836 {
1837   struct OperationContext *opc;
1838   struct GNUNET_TESTBED_ControllerLinkRequest *msg;
1839   struct ControllerLinkData *data;
1840   uint32_t slave_host_id;
1841   uint32_t delegated_host_id;
1842   uint16_t msg_size;
1843
1844   GNUNET_assert (GNUNET_YES ==
1845                  GNUNET_TESTBED_is_host_registered_ (delegated_host, master));
1846   slave_host_id =
1847       GNUNET_TESTBED_host_get_id_ ((NULL !=
1848                                     slave_host) ? slave_host : master->host);
1849   delegated_host_id = GNUNET_TESTBED_host_get_id_ (delegated_host);
1850   if ((NULL != slave_host) && (0 != slave_host_id))
1851     GNUNET_assert (GNUNET_YES ==
1852                    GNUNET_TESTBED_is_host_registered_ (slave_host, master));
1853   msg_size = sizeof (struct GNUNET_TESTBED_ControllerLinkRequest);
1854   msg = GNUNET_malloc (msg_size);
1855   msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS);
1856   msg->header.size = htons (msg_size);
1857   msg->delegated_host_id = htonl (delegated_host_id);
1858   msg->slave_host_id = htonl (slave_host_id);
1859   msg->is_subordinate = (GNUNET_YES == is_subordinate) ? 1 : 0;
1860   data = GNUNET_new (struct ControllerLinkData);
1861   data->msg = msg;
1862   data->host_id = delegated_host_id;
1863   opc = GNUNET_new (struct OperationContext);
1864   opc->c = master;
1865   opc->data = data;
1866   opc->type = OP_LINK_CONTROLLERS;
1867   opc->id = GNUNET_TESTBED_get_next_op_id (opc->c);
1868   opc->state = OPC_STATE_INIT;
1869   opc->op_cls = op_cls;
1870   msg->operation_id = GNUNET_htonll (opc->id);
1871   opc->op =
1872       GNUNET_TESTBED_operation_create_ (opc, &opstart_link_controllers,
1873                                         &oprelease_link_controllers);
1874   GNUNET_TESTBED_operation_queue_insert_ (master->opq_parallel_operations,
1875                                           opc->op);
1876   GNUNET_TESTBED_operation_begin_wait_ (opc->op);
1877   return opc->op;
1878 }
1879
1880
1881 /**
1882  * Like GNUNET_TESTBED_get_slave_config(), however without the host registration
1883  * check. Another difference is that this function takes the id of the slave
1884  * host.
1885  *
1886  * @param op_cls the closure for the operation
1887  * @param master the handle to master controller
1888  * @param slave_host_id id of the host where the slave controller is running to
1889  *          the slave_host should remain valid until this operation is cancelled
1890  *          or marked as finished
1891  * @return the operation handle;
1892  */
1893 struct GNUNET_TESTBED_Operation *
1894 GNUNET_TESTBED_get_slave_config_ (void *op_cls,
1895                                   struct GNUNET_TESTBED_Controller *master,
1896                                   uint32_t slave_host_id)
1897 {
1898   struct OperationContext *opc;
1899   struct GetSlaveConfigData *data;
1900
1901   data = GNUNET_new (struct GetSlaveConfigData);
1902   data->slave_id = slave_host_id;
1903   opc = GNUNET_new (struct OperationContext);
1904   opc->state = OPC_STATE_INIT;
1905   opc->c = master;
1906   opc->id = GNUNET_TESTBED_get_next_op_id (master);
1907   opc->type = OP_GET_SLAVE_CONFIG;
1908   opc->data = data;
1909   opc->op_cls = op_cls;
1910   opc->op =
1911       GNUNET_TESTBED_operation_create_ (opc, &opstart_get_slave_config,
1912                                         &oprelease_get_slave_config);
1913   GNUNET_TESTBED_operation_queue_insert_ (master->opq_parallel_operations,
1914                                           opc->op);
1915   GNUNET_TESTBED_operation_begin_wait_ (opc->op);
1916   return opc->op;
1917 }
1918
1919
1920 /**
1921  * Function to acquire the configuration of a running slave controller. The
1922  * completion of the operation is signalled through the controller_cb from
1923  * GNUNET_TESTBED_controller_connect(). If the operation is successful the
1924  * handle to the configuration is available in the generic pointer of
1925  * operation_finished field of struct GNUNET_TESTBED_EventInformation.
1926  *
1927  * @param op_cls the closure for the operation
1928  * @param master the handle to master controller
1929  * @param slave_host the host where the slave controller is running; the handle
1930  *          to the slave_host should remain valid until this operation is
1931  *          cancelled or marked as finished
1932  * @return the operation handle; NULL if the slave_host is not registered at
1933  *           master
1934  */
1935 struct GNUNET_TESTBED_Operation *
1936 GNUNET_TESTBED_get_slave_config (void *op_cls,
1937                                  struct GNUNET_TESTBED_Controller *master,
1938                                  struct GNUNET_TESTBED_Host *slave_host)
1939 {
1940   if (GNUNET_NO == GNUNET_TESTBED_is_host_registered_ (slave_host, master))
1941     return NULL;
1942   return GNUNET_TESTBED_get_slave_config_ (op_cls, master,
1943                                            GNUNET_TESTBED_host_get_id_
1944                                            (slave_host));
1945 }
1946
1947
1948 /**
1949  * Ask the testbed controller to write the current overlay topology to
1950  * a file.  Naturally, the file will only contain a snapshot as the
1951  * topology may evolve all the time.
1952  *
1953  * @param controller overlay controller to inspect
1954  * @param filename name of the file the topology should
1955  *        be written to.
1956  */
1957 void
1958 GNUNET_TESTBED_overlay_write_topology_to_file (struct GNUNET_TESTBED_Controller
1959                                                *controller,
1960                                                const char *filename)
1961 {
1962   GNUNET_break (0);
1963 }
1964
1965
1966 /**
1967  * Creates a helper initialization message. This function is here because we
1968  * want to use this in testing
1969  *
1970  * @param trusted_ip the ip address of the controller which will be set as TRUSTED
1971  *          HOST(all connections form this ip are permitted by the testbed) when
1972  *          starting testbed controller at host. This can either be a single ip
1973  *          address or a network address in CIDR notation.
1974  * @param hostname the hostname of the destination this message is intended for
1975  * @param cfg the configuration that has to used to start the testbed service
1976  *          thru helper
1977  * @return the initialization message
1978  */
1979 struct GNUNET_TESTBED_HelperInit *
1980 GNUNET_TESTBED_create_helper_init_msg_ (const char *trusted_ip,
1981                                         const char *hostname,
1982                                         const struct GNUNET_CONFIGURATION_Handle
1983                                         *cfg)
1984 {
1985   struct GNUNET_TESTBED_HelperInit *msg;
1986   char *config;
1987   char *xconfig;
1988   size_t config_size;
1989   size_t xconfig_size;
1990   uint16_t trusted_ip_len;
1991   uint16_t hostname_len;
1992   uint16_t msg_size;
1993
1994   config = GNUNET_CONFIGURATION_serialize (cfg, &config_size);
1995   GNUNET_assert (NULL != config);
1996   xconfig_size =
1997       GNUNET_TESTBED_compress_config_ (config, config_size, &xconfig);
1998   GNUNET_free (config);
1999   trusted_ip_len = strlen (trusted_ip);
2000   hostname_len = (NULL == hostname) ? 0 : strlen (hostname);
2001   msg_size =
2002       xconfig_size + trusted_ip_len + 1 +
2003       sizeof (struct GNUNET_TESTBED_HelperInit);
2004   msg_size += hostname_len;
2005   msg = GNUNET_realloc (xconfig, msg_size);
2006   (void) memmove (((void *) &msg[1]) + trusted_ip_len + 1 + hostname_len, msg,
2007                   xconfig_size);
2008   msg->header.size = htons (msg_size);
2009   msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_HELPER_INIT);
2010   msg->trusted_ip_size = htons (trusted_ip_len);
2011   msg->hostname_size = htons (hostname_len);
2012   msg->config_size = htons (config_size);
2013   (void) strcpy ((char *) &msg[1], trusted_ip);
2014   if (0 != hostname_len)
2015     (void) strncpy (((char *) &msg[1]) + trusted_ip_len + 1, hostname,
2016                     hostname_len);
2017   return msg;
2018 }
2019
2020
2021 /**
2022  * This function is used to signal that the event information (struct
2023  * GNUNET_TESTBED_EventInformation) from an operation has been fully processed
2024  * i.e. if the event callback is ever called for this operation. If the event
2025  * callback for this operation has not yet been called, calling this function
2026  * cancels the operation, frees its resources and ensures the no event is
2027  * generated with respect to this operation. Note that however cancelling an
2028  * operation does NOT guarantee that the operation will be fully undone (or that
2029  * nothing ever happened).
2030  *
2031  * This function MUST be called for every operation to fully remove the
2032  * operation from the operation queue.  After calling this function, if
2033  * operation is completed and its event information is of type
2034  * GNUNET_TESTBED_ET_OPERATION_FINISHED, the 'op_result' becomes invalid (!).
2035
2036  * If the operation is generated from GNUNET_TESTBED_service_connect() then
2037  * calling this function on such as operation calls the disconnect adapter if
2038  * the connect adapter was ever called.
2039  *
2040  * @param operation operation to signal completion or cancellation
2041  */
2042 void
2043 GNUNET_TESTBED_operation_done (struct GNUNET_TESTBED_Operation *operation)
2044 {
2045   (void) exop_check (operation);
2046   GNUNET_TESTBED_operation_release_ (operation);
2047 }
2048
2049
2050 /**
2051  * Generates configuration by uncompressing configuration in given message. The
2052  * given message should be of the following types:
2053  * #GNUNET_MESSAGE_TYPE_TESTBED_PEER_INFORMATION,
2054  * #GNUNET_MESSAGE_TYPE_TESTBED_SLAVE_CONFIGURATION,
2055  * #GNUNET_MESSAGE_TYPE_TESTBED_ADD_HOST,
2056  * #GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS,
2057  * #GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS_RESULT,
2058  *
2059  * FIXME: This API is incredibly ugly.
2060  *
2061  * @param msg the message containing compressed configuration
2062  * @return handle to the parsed configuration; NULL upon error while parsing the message
2063  */
2064 struct GNUNET_CONFIGURATION_Handle *
2065 GNUNET_TESTBED_extract_config_ (const struct GNUNET_MessageHeader *msg)
2066 {
2067   struct GNUNET_CONFIGURATION_Handle *cfg;
2068   Bytef *data;
2069   const Bytef *xdata;
2070   uLong data_len;
2071   uLong xdata_len;
2072   int ret;
2073
2074   switch (ntohs (msg->type))
2075   {
2076   case GNUNET_MESSAGE_TYPE_TESTBED_PEER_INFORMATION:
2077   {
2078     const struct GNUNET_TESTBED_PeerConfigurationInformationMessage *imsg;
2079
2080     imsg =
2081         (const struct GNUNET_TESTBED_PeerConfigurationInformationMessage *) msg;
2082     data_len = (uLong) ntohs (imsg->config_size);
2083     xdata_len =
2084         ntohs (imsg->header.size) -
2085         sizeof (struct GNUNET_TESTBED_PeerConfigurationInformationMessage);
2086     xdata = (const Bytef *) &imsg[1];
2087   }
2088     break;
2089   case GNUNET_MESSAGE_TYPE_TESTBED_SLAVE_CONFIGURATION:
2090   {
2091     const struct GNUNET_TESTBED_SlaveConfiguration *imsg;
2092
2093     imsg = (const struct GNUNET_TESTBED_SlaveConfiguration *) msg;
2094     data_len = (uLong) ntohs (imsg->config_size);
2095     xdata_len =
2096         ntohs (imsg->header.size) -
2097         sizeof (struct GNUNET_TESTBED_SlaveConfiguration);
2098     xdata = (const Bytef *) &imsg[1];
2099   }
2100   break;
2101   case GNUNET_MESSAGE_TYPE_TESTBED_ADD_HOST:
2102     {
2103       const struct GNUNET_TESTBED_AddHostMessage *imsg;
2104       uint16_t osize;
2105
2106       imsg = (const struct GNUNET_TESTBED_AddHostMessage *) msg;
2107       data_len = (uLong) ntohs (imsg->config_size);
2108       osize = sizeof (struct GNUNET_TESTBED_AddHostMessage) +
2109           ntohs (imsg->username_length) + ntohs (imsg->hostname_length);
2110       xdata_len = ntohs (imsg->header.size) - osize;
2111       xdata = (const Bytef *) ((const void *) imsg + osize);
2112     }
2113     break;
2114   case GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS_RESULT:
2115     {
2116       const struct GNUNET_TESTBED_ControllerLinkResponse *imsg;
2117
2118       imsg = (const struct GNUNET_TESTBED_ControllerLinkResponse *) msg;
2119       data_len = ntohs (imsg->config_size);
2120       xdata_len = ntohs (imsg->header.size) -
2121           sizeof (const struct GNUNET_TESTBED_ControllerLinkResponse);
2122       xdata = (const Bytef *) &imsg[1];
2123     }
2124     break;
2125   case GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER:
2126     {
2127       const struct GNUNET_TESTBED_PeerCreateMessage *imsg;
2128
2129       imsg = (const struct GNUNET_TESTBED_PeerCreateMessage *) msg;
2130       data_len = ntohs (imsg->config_size);
2131       xdata_len = ntohs (imsg->header.size) -
2132           sizeof (struct GNUNET_TESTBED_PeerCreateMessage);
2133       xdata = (const Bytef *) &imsg[1];
2134     }
2135     break;
2136   case GNUNET_MESSAGE_TYPE_TESTBED_RECONFIGURE_PEER:
2137     {
2138       const struct GNUNET_TESTBED_PeerReconfigureMessage *imsg;
2139
2140       imsg = (const struct GNUNET_TESTBED_PeerReconfigureMessage *) msg;
2141       data_len =  ntohs (imsg->config_size);
2142       xdata_len = ntohs (imsg->header.size) -
2143           sizeof (struct GNUNET_TESTBED_PeerReconfigureMessage);
2144       xdata = (const Bytef *) &imsg[1];
2145     }
2146     break;
2147   default:
2148     GNUNET_assert (0);
2149   }
2150   data = GNUNET_malloc (data_len);
2151   if (Z_OK != (ret = uncompress (data, &data_len, xdata, xdata_len)))
2152   {
2153     GNUNET_free (data);
2154     GNUNET_break_op (0);        /* Un-compression failure */
2155     return NULL;
2156   }
2157   cfg = GNUNET_CONFIGURATION_create ();
2158   if (GNUNET_OK !=
2159       GNUNET_CONFIGURATION_deserialize (cfg,
2160                                         (const char *) data,
2161                                         (size_t) data_len,
2162                                         NULL))
2163   {
2164     GNUNET_free (data);
2165     GNUNET_break_op (0);        /* De-serialization failure */
2166     return NULL;
2167   }
2168   GNUNET_free (data);
2169   return cfg;
2170 }
2171
2172
2173 /**
2174  * Checks the integrity of the OperationFailureEventMessage and if good returns
2175  * the error message it contains.
2176  *
2177  * @param msg the OperationFailureEventMessage
2178  * @return the error message
2179  */
2180 const char *
2181 GNUNET_TESTBED_parse_error_string_ (const struct
2182                                     GNUNET_TESTBED_OperationFailureEventMessage
2183                                     *msg)
2184 {
2185   uint16_t msize;
2186   const char *emsg;
2187
2188   msize = ntohs (msg->header.size);
2189   if (sizeof (struct GNUNET_TESTBED_OperationFailureEventMessage) >= msize)
2190     return NULL;
2191   msize -= sizeof (struct GNUNET_TESTBED_OperationFailureEventMessage);
2192   emsg = (const char *) &msg[1];
2193   if ('\0' != emsg[msize - 1])
2194   {
2195     GNUNET_break (0);
2196     return NULL;
2197   }
2198   return emsg;
2199 }
2200
2201
2202 /**
2203  * Function to return the operation id for a controller. The operation id is
2204  * created from the controllers host id and its internal operation counter.
2205  *
2206  * @param controller the handle to the controller whose operation id has to be incremented
2207  * @return the incremented operation id.
2208  */
2209 uint64_t
2210 GNUNET_TESTBED_get_next_op_id (struct GNUNET_TESTBED_Controller * controller)
2211 {
2212   uint64_t op_id;
2213
2214   op_id = (uint64_t) GNUNET_TESTBED_host_get_id_ (controller->host);
2215   op_id = op_id << 32;
2216   op_id |= (uint64_t) controller->operation_counter++;
2217   return op_id;
2218 }
2219
2220
2221 /**
2222  * Function called when a shutdown peers operation is ready
2223  *
2224  * @param cls the closure from GNUNET_TESTBED_operation_create_()
2225  */
2226 static void
2227 opstart_shutdown_peers (void *cls)
2228 {
2229   struct OperationContext *opc = cls;
2230   struct GNUNET_MQ_Envelope *env;
2231   struct GNUNET_TESTBED_ShutdownPeersMessage *msg;
2232
2233   opc->state = OPC_STATE_STARTED;
2234   env = GNUNET_MQ_msg (msg,
2235                        GNUNET_MESSAGE_TYPE_TESTBED_SHUTDOWN_PEERS);
2236   msg->operation_id = GNUNET_htonll (opc->id);
2237   GNUNET_TESTBED_insert_opc_ (opc->c,
2238                               opc);
2239   GNUNET_MQ_send (opc->c->mq,
2240                   env);
2241 }
2242
2243
2244 /**
2245  * Callback which will be called when shutdown peers operation is released
2246  *
2247  * @param cls the closure from GNUNET_TESTBED_operation_create_()
2248  */
2249 static void
2250 oprelease_shutdown_peers (void *cls)
2251 {
2252   struct OperationContext *opc = cls;
2253
2254   switch (opc->state)
2255   {
2256   case OPC_STATE_STARTED:
2257     GNUNET_TESTBED_remove_opc_ (opc->c, opc);
2258     /* no break; continue */
2259   case OPC_STATE_INIT:
2260     GNUNET_free (opc->data);
2261     break;
2262   case OPC_STATE_FINISHED:
2263     break;
2264   }
2265   GNUNET_free (opc);
2266 }
2267
2268
2269 /**
2270  * Stops and destroys all peers.  Is equivalent of calling
2271  * GNUNET_TESTBED_peer_stop() and GNUNET_TESTBED_peer_destroy() on all peers,
2272  * except that the peer stop event and operation finished event corresponding to
2273  * the respective functions are not generated.  This function should be called
2274  * when there are no other pending operations.  If there are pending operations,
2275  * it will return NULL
2276  *
2277  * @param c the controller to send this message to
2278  * @param op_cls closure for the operation
2279  * @param cb the callback to call when all peers are stopped and destroyed
2280  * @param cb_cls the closure for the callback
2281  * @return operation handle on success; NULL if any pending operations are
2282  *           present
2283  */
2284 struct GNUNET_TESTBED_Operation *
2285 GNUNET_TESTBED_shutdown_peers (struct GNUNET_TESTBED_Controller *c,
2286                                void *op_cls,
2287                                GNUNET_TESTBED_OperationCompletionCallback cb,
2288                                void *cb_cls)
2289 {
2290   struct OperationContext *opc;
2291   struct ShutdownPeersData *data;
2292
2293   if (0 != GNUNET_CONTAINER_multihashmap32_size (c->opc_map))
2294     return NULL;
2295   data = GNUNET_new (struct ShutdownPeersData);
2296   data->cb = cb;
2297   data->cb_cls = cb_cls;
2298   opc = GNUNET_new (struct OperationContext);
2299   opc->c = c;
2300   opc->op_cls = op_cls;
2301   opc->data = data;
2302   opc->id =  GNUNET_TESTBED_get_next_op_id (c);
2303   opc->type = OP_SHUTDOWN_PEERS;
2304   opc->state = OPC_STATE_INIT;
2305   opc->op = GNUNET_TESTBED_operation_create_ (opc, &opstart_shutdown_peers,
2306                                               &oprelease_shutdown_peers);
2307   GNUNET_TESTBED_operation_queue_insert_ (opc->c->opq_parallel_operations,
2308                                         opc->op);
2309   GNUNET_TESTBED_operation_begin_wait_ (opc->op);
2310   return opc->op;
2311 }
2312
2313
2314 /**
2315  * Return the index of the peer inside of the total peer array,
2316  * aka. the peer's "unique ID".
2317  *
2318  * @param peer Peer handle.
2319  *
2320  * @return The peer's unique ID.
2321  */
2322 uint32_t
2323 GNUNET_TESTBED_get_index (const struct GNUNET_TESTBED_Peer *peer)
2324 {
2325   return peer->unique_id;
2326 }
2327
2328
2329 /**
2330  * Remove a barrier and it was the last one in the barrier hash map, destroy the
2331  * hash map
2332  *
2333  * @param barrier the barrier to remove
2334  */
2335 void
2336 GNUNET_TESTBED_barrier_remove_ (struct GNUNET_TESTBED_Barrier *barrier)
2337 {
2338   struct GNUNET_TESTBED_Controller *c = barrier->c;
2339
2340   GNUNET_assert (NULL != c->barrier_map); /* No barriers present */
2341   GNUNET_assert (GNUNET_OK ==
2342                  GNUNET_CONTAINER_multihashmap_remove (c->barrier_map,
2343                                                        &barrier->key,
2344                                                        barrier));
2345   GNUNET_free (barrier->name);
2346   GNUNET_free (barrier);
2347   if (0 == GNUNET_CONTAINER_multihashmap_size (c->barrier_map))
2348   {
2349     GNUNET_CONTAINER_multihashmap_destroy (c->barrier_map);
2350     c->barrier_map = NULL;
2351   }
2352 }
2353
2354
2355 /**
2356  * Initialise a barrier and call the given callback when the required percentage
2357  * of peers (quorum) reach the barrier OR upon error.
2358  *
2359  * @param controller the handle to the controller
2360  * @param name identification name of the barrier
2361  * @param quorum the percentage of peers that is required to reach the barrier.
2362  *   Peers signal reaching a barrier by calling
2363  *   GNUNET_TESTBED_barrier_reached().
2364  * @param cb the callback to call when the barrier is reached or upon error.
2365  *   Cannot be NULL.
2366  * @param cls closure for the above callback
2367  * @param echo GNUNET_YES to echo the barrier crossed status message back to the
2368  *   controller
2369  * @return barrier handle; NULL upon error
2370  */
2371 struct GNUNET_TESTBED_Barrier *
2372 GNUNET_TESTBED_barrier_init_ (struct GNUNET_TESTBED_Controller *controller,
2373                               const char *name,
2374                               unsigned int quorum,
2375                               GNUNET_TESTBED_barrier_status_cb cb, void *cls,
2376                               int echo)
2377 {
2378   struct GNUNET_TESTBED_BarrierInit *msg;
2379   struct GNUNET_MQ_Envelope *env;
2380   struct GNUNET_TESTBED_Barrier *barrier;
2381   struct GNUNET_HashCode key;
2382   size_t name_len;
2383
2384   GNUNET_assert (quorum <= 100);
2385   GNUNET_assert (NULL != cb);
2386   name_len = strlen (name);
2387   GNUNET_assert (0 < name_len);
2388   GNUNET_CRYPTO_hash (name, name_len, &key);
2389   if (NULL == controller->barrier_map)
2390     controller->barrier_map = GNUNET_CONTAINER_multihashmap_create (3, GNUNET_YES);
2391   if (GNUNET_YES ==
2392       GNUNET_CONTAINER_multihashmap_contains (controller->barrier_map,
2393                                               &key))
2394   {
2395     GNUNET_break (0);
2396     return NULL;
2397   }
2398   LOG_DEBUG ("Initialising barrier `%s'\n", name);
2399   barrier = GNUNET_new (struct GNUNET_TESTBED_Barrier);
2400   barrier->c = controller;
2401   barrier->name = GNUNET_strdup (name);
2402   barrier->cb = cb;
2403   barrier->cls = cls;
2404   barrier->echo = echo;
2405   GNUNET_memcpy (&barrier->key, &key, sizeof (struct GNUNET_HashCode));
2406   GNUNET_assert (GNUNET_OK ==
2407                  GNUNET_CONTAINER_multihashmap_put (controller->barrier_map,
2408                                                     &barrier->key,
2409                                                     barrier,
2410                                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
2411
2412   env = GNUNET_MQ_msg_extra (msg,
2413                              name_len,
2414                              GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_INIT);
2415   msg->quorum = (uint8_t) quorum;
2416   GNUNET_memcpy (msg->name,
2417                  barrier->name,
2418                  name_len);
2419   GNUNET_MQ_send (barrier->c->mq,
2420                   env);
2421   return barrier;
2422 }
2423
2424
2425 /**
2426  * Initialise a barrier and call the given callback when the required percentage
2427  * of peers (quorum) reach the barrier OR upon error.
2428  *
2429  * @param controller the handle to the controller
2430  * @param name identification name of the barrier
2431  * @param quorum the percentage of peers that is required to reach the barrier.
2432  *   Peers signal reaching a barrier by calling
2433  *   GNUNET_TESTBED_barrier_reached().
2434  * @param cb the callback to call when the barrier is reached or upon error.
2435  *   Cannot be NULL.
2436  * @param cls closure for the above callback
2437  * @return barrier handle; NULL upon error
2438  */
2439 struct GNUNET_TESTBED_Barrier *
2440 GNUNET_TESTBED_barrier_init (struct GNUNET_TESTBED_Controller *controller,
2441                              const char *name,
2442                              unsigned int quorum,
2443                              GNUNET_TESTBED_barrier_status_cb cb, void *cls)
2444 {
2445   return GNUNET_TESTBED_barrier_init_ (controller,
2446                                        name, quorum, cb, cls, GNUNET_YES);
2447 }
2448
2449
2450 /**
2451  * Cancel a barrier.
2452  *
2453  * @param barrier the barrier handle
2454  */
2455 void
2456 GNUNET_TESTBED_barrier_cancel (struct GNUNET_TESTBED_Barrier *barrier)
2457 {
2458   struct GNUNET_MQ_Envelope *env;
2459   struct GNUNET_TESTBED_BarrierCancel *msg;
2460   size_t slen;
2461
2462   slen = strlen (barrier->name);
2463   env = GNUNET_MQ_msg_extra (msg,
2464                              slen,
2465                              GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_CANCEL);
2466   GNUNET_memcpy (msg->name,
2467                  barrier->name,
2468                  slen);
2469   GNUNET_MQ_send (barrier->c->mq,
2470                   env);
2471   GNUNET_TESTBED_barrier_remove_ (barrier);
2472 }
2473
2474
2475 /* end of testbed_api.c */