coverity fixes
[oweals/gnunet.git] / src / testbed / testbed_api.c
1 /*
2       This file is part of GNUnet
3       (C) 2008--2012 Christian Grothoff (and other contributing authors)
4
5       GNUnet is free software; you can redistribute it and/or modify
6       it under the terms of the GNU General Public License as published
7       by the Free Software Foundation; either version 3, or (at your
8       option) any later version.
9
10       GNUnet is distributed in the hope that it will be useful, but
11       WITHOUT ANY WARRANTY; without even the implied warranty of
12       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13       General Public License for more details.
14
15       You should have received a copy of the GNU General Public License
16       along with GNUnet; see the file COPYING.  If not, write to the
17       Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18       Boston, MA 02111-1307, USA.
19  */
20
21 /**
22  * @file testbed/testbed_api.c
23  * @brief API for accessing the GNUnet testing service.
24  *        This library is supposed to make it easier to write
25  *        testcases and script large-scale benchmarks.
26  * @author Christian Grothoff
27  * @author Sree Harsha Totakura
28  */
29
30
31 #include "platform.h"
32 #include "gnunet_testbed_service.h"
33 #include "gnunet_core_service.h"
34 #include "gnunet_constants.h"
35 #include "gnunet_transport_service.h"
36 #include "gnunet_hello_lib.h"
37 #include <zlib.h>
38
39 #include "testbed.h"
40 #include "testbed_api.h"
41 #include "testbed_api_hosts.h"
42 #include "testbed_api_peers.h"
43 #include "testbed_api_operations.h"
44
45 /**
46  * Generic logging shorthand
47  */
48 #define LOG(kind, ...)                          \
49   GNUNET_log_from (kind, "testbed-api", __VA_ARGS__);
50
51 /**
52  * Debug logging
53  */
54 #define LOG_DEBUG(...)                          \
55   LOG (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__);
56
57 /**
58  * Relative time seconds shorthand
59  */
60 #define TIME_REL_SECS(sec) \
61   GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, sec)
62
63
64 /**
65  * Default server message sending retry timeout
66  */
67 #define TIMEOUT_REL TIME_REL_SECS(1)
68
69
70 /**
71  * Testbed Helper binary name
72  */
73 #define HELPER_TESTBED_BINARY "gnunet-helper-testbed"
74
75
76 /**
77  * The message queue for sending messages to the controller service
78  */
79 struct MessageQueue
80 {
81   /**
82    * The message to be sent
83    */
84   struct GNUNET_MessageHeader *msg;
85
86   /**
87    * next pointer for DLL
88    */
89   struct MessageQueue *next;
90
91   /**
92    * prev pointer for DLL
93    */
94   struct MessageQueue *prev;
95 };
96
97
98 /**
99  * Structure for a controller link
100  */
101 struct ControllerLink
102 {
103   /**
104    * The next ptr for DLL
105    */
106   struct ControllerLink *next;
107
108   /**
109    * The prev ptr for DLL
110    */
111   struct ControllerLink *prev;
112
113   /**
114    * The host which will be referred in the peer start request. This is the
115    * host where the peer should be started
116    */
117   struct GNUNET_TESTBED_Host *delegated_host;
118
119   /**
120    * The host which will contacted to delegate the peer start request
121    */
122   struct GNUNET_TESTBED_Host *slave_host;
123
124   /**
125    * The configuration to be used to connect to slave host
126    */
127   const struct GNUNET_CONFIGURATION_Handle *slave_cfg;
128
129   /**
130    * GNUNET_YES if the slave should be started (and stopped) by us; GNUNET_NO
131    * if we are just allowed to use the slave via TCP/IP
132    */
133   int is_subordinate;
134 };
135
136
137 /**
138  * handle for host registration
139  */
140 struct GNUNET_TESTBED_HostRegistrationHandle
141 {
142   /**
143    * The host being registered
144    */
145   struct GNUNET_TESTBED_Host *host;
146
147   /**
148    * The controller at which this host is being registered
149    */
150   struct GNUNET_TESTBED_Controller *c;
151
152   /**
153    * The Registartion completion callback
154    */
155   GNUNET_TESTBED_HostRegistrationCompletion cc;
156
157   /**
158    * The closure for above callback
159    */
160   void *cc_cls;
161 };
162
163
164 /**
165  * Context data for forwarded Operation
166  */
167 struct ForwardedOperationData
168 {
169
170   /**
171    * The callback to call when reply is available
172    */
173   GNUNET_CLIENT_MessageHandler cc;
174
175   /**
176    * The closure for the above callback
177    */
178   void *cc_cls;
179
180 };
181
182
183 /**
184  * Returns the operation context with the given id if found in the Operation
185  * context queues of the controller
186  *
187  * @param c the controller whose queues are searched
188  * @param id the id which has to be checked
189  * @return the matching operation context; NULL if no match found
190  */
191 static struct OperationContext *
192 find_opc (const struct GNUNET_TESTBED_Controller *c, const uint64_t id)
193 {
194   struct OperationContext *opc;
195
196   for (opc = c->ocq_head; NULL != opc; opc = opc->next)
197   {
198     if (id == opc->id)
199       return opc;
200   }
201   return NULL;
202 }
203
204
205 /**
206  * Handler for GNUNET_MESSAGE_TYPE_TESTBED_ADDHOSTCONFIRM message from
207  * controller (testbed service)
208  *
209  * @param c the controller handler
210  * @param msg message received
211  * @return GNUNET_YES if we can continue receiving from service; GNUNET_NO if
212  *           not
213  */
214 static int
215 handle_addhostconfirm (struct GNUNET_TESTBED_Controller *c,
216                        const struct GNUNET_TESTBED_HostConfirmedMessage *msg)
217 {
218   struct GNUNET_TESTBED_HostRegistrationHandle *rh;
219   char *emsg;
220   uint16_t msg_size;
221
222   rh = c->rh;
223   if (NULL == rh)
224   {
225     return GNUNET_OK;
226   }
227   if (GNUNET_TESTBED_host_get_id_ (rh->host) != ntohl (msg->host_id))
228   {
229     LOG_DEBUG ("Mismatch in host id's %u, %u of host confirm msg\n",
230                GNUNET_TESTBED_host_get_id_ (rh->host), ntohl (msg->host_id));
231     return GNUNET_OK;
232   }
233   c->rh = NULL;
234   msg_size = ntohs (msg->header.size);
235   if (sizeof (struct GNUNET_TESTBED_HostConfirmedMessage) == msg_size)
236   {
237     LOG_DEBUG ("Host %u successfully registered\n", ntohl (msg->host_id));
238     GNUNET_TESTBED_mark_host_registered_at_ (rh->host, c);
239     rh->cc (rh->cc_cls, NULL);
240     GNUNET_free (rh);
241     return GNUNET_OK;
242   }
243   /* We have an error message */
244   emsg = (char *) &msg[1];
245   if ('\0' !=
246       emsg[msg_size - sizeof (struct GNUNET_TESTBED_HostConfirmedMessage)])
247   {
248     GNUNET_break (0);
249     GNUNET_free (rh);
250     return GNUNET_NO;
251   }
252   LOG (GNUNET_ERROR_TYPE_ERROR, _("Adding host %u failed with error: %s\n"),
253        ntohl (msg->host_id), emsg);
254   rh->cc (rh->cc_cls, emsg);
255   GNUNET_free (rh);
256   return GNUNET_OK;
257 }
258
259
260 /**
261  * Handler for GNUNET_MESSAGE_TYPE_TESTBED_ADDHOSTCONFIRM message from
262  * controller (testbed service)
263  *
264  * @param c the controller handler
265  * @param msg message received
266  * @return GNUNET_YES if we can continue receiving from service; GNUNET_NO if
267  *           not
268  */
269 static int
270 handle_opsuccess (struct GNUNET_TESTBED_Controller *c,
271                   const struct
272                   GNUNET_TESTBED_GenericOperationSuccessEventMessage *msg)
273 {
274   struct OperationContext *opc;
275   struct GNUNET_TESTBED_EventInformation event;
276   uint64_t op_id;
277
278   op_id = GNUNET_ntohll (msg->operation_id);
279   LOG_DEBUG ("Operation %ul successful\n", op_id);
280   if (NULL == (opc = find_opc (c, op_id)))
281   {
282     LOG_DEBUG ("Operation not found\n");
283     return GNUNET_YES;
284   }
285   switch (opc->type)
286   {
287   case OP_FORWARDED:
288     {
289       struct ForwardedOperationData *fo_data;
290       
291       fo_data = opc->data;
292       if (NULL != fo_data->cc)
293         fo_data->cc (fo_data->cc_cls, (const struct GNUNET_MessageHeader *) msg);
294       GNUNET_CONTAINER_DLL_remove (c->ocq_head, c->ocq_tail, opc);
295       GNUNET_free (fo_data);
296       GNUNET_free (opc);
297       return GNUNET_YES;
298     }
299     break;
300   case OP_PEER_DESTROY:
301     {
302       struct GNUNET_TESTBED_Peer *peer;
303       
304       peer = opc->data;
305       GNUNET_free (peer);
306       opc->data = NULL;
307       //PEERDESTROYDATA
308     }
309     break;
310   case OP_LINK_CONTROLLERS:
311     break;
312   default:
313     GNUNET_assert (0);
314   }
315   event.type = GNUNET_TESTBED_ET_OPERATION_FINISHED;
316   event.details.operation_finished.operation = opc->op;
317   event.details.operation_finished.op_cls = NULL;
318   event.details.operation_finished.emsg = NULL;
319   event.details.operation_finished.generic = NULL;
320   GNUNET_CONTAINER_DLL_remove (opc->c->ocq_head, opc->c->ocq_tail, opc);
321   opc->state = OPC_STATE_FINISHED;
322   if (0 != (c->event_mask & (1L << GNUNET_TESTBED_ET_OPERATION_FINISHED)))
323   {
324     if (NULL != c->cc)
325       c->cc (c->cc_cls, &event);
326   }
327   return GNUNET_YES;
328 }
329
330
331 /**
332  * Handler for GNUNET_MESSAGE_TYPE_TESTBED_PEERCREATESUCCESS message from
333  * controller (testbed service)
334  *
335  * @param c the controller handler
336  * @param msg message received
337  * @return GNUNET_YES if we can continue receiving from service; GNUNET_NO if
338  *           not
339  */
340 static int
341 handle_peer_create_success (struct GNUNET_TESTBED_Controller *c,
342                             const struct
343                             GNUNET_TESTBED_PeerCreateSuccessEventMessage *msg)
344 {
345   struct OperationContext *opc;
346   struct PeerCreateData *data;
347   struct GNUNET_TESTBED_Peer *peer;
348   GNUNET_TESTBED_PeerCreateCallback cb;
349   void *cls;
350   uint64_t op_id;
351
352   GNUNET_assert (sizeof (struct GNUNET_TESTBED_PeerCreateSuccessEventMessage) ==
353                  ntohs (msg->header.size));
354   op_id = GNUNET_ntohll (msg->operation_id);
355   if (NULL == (opc = find_opc (c, op_id)))
356   {
357     LOG_DEBUG ("Operation context for PeerCreateSuccessEvent not found\n");
358     return GNUNET_YES;
359   }
360   if (OP_FORWARDED == opc->type)
361   {
362     struct ForwardedOperationData *fo_data;
363
364     fo_data = opc->data;
365     if (NULL != fo_data->cc)
366       fo_data->cc (fo_data->cc_cls, (const struct GNUNET_MessageHeader *) msg);
367     GNUNET_CONTAINER_DLL_remove (c->ocq_head, c->ocq_tail, opc);
368     GNUNET_free (fo_data);
369     GNUNET_free (opc);
370     return GNUNET_YES;
371   }
372   GNUNET_assert (OP_PEER_CREATE == opc->type);
373   GNUNET_assert (NULL != opc->data);
374   data = opc->data;
375   GNUNET_assert (NULL != data->peer);
376   peer = data->peer;
377   GNUNET_assert (peer->unique_id == ntohl (msg->peer_id));
378   peer->state = PS_CREATED;
379   cb = data->cb;
380   cls = data->cls;
381   GNUNET_free (opc->data);
382   GNUNET_CONTAINER_DLL_remove (opc->c->ocq_head, opc->c->ocq_tail, opc);
383   opc->state = OPC_STATE_FINISHED;
384   if (NULL != cb)
385     cb (cls, peer, NULL);
386   return GNUNET_YES;
387 }
388
389
390 /**
391  * Handler for GNUNET_MESSAGE_TYPE_TESTBED_PEEREVENT message from
392  * controller (testbed service)
393  *
394  * @param c the controller handler
395  * @param msg message received
396  * @return GNUNET_YES if we can continue receiving from service; GNUNET_NO if
397  *           not
398  */
399 static int
400 handle_peer_event (struct GNUNET_TESTBED_Controller *c,
401                    const struct GNUNET_TESTBED_PeerEventMessage *msg)
402 {
403   struct OperationContext *opc;
404   struct GNUNET_TESTBED_Peer *peer;
405   struct PeerEventData *data;
406   GNUNET_TESTBED_PeerChurnCallback pcc;
407   void *pcc_cls;
408   struct GNUNET_TESTBED_EventInformation event;
409   uint64_t op_id;
410
411   GNUNET_assert (sizeof (struct GNUNET_TESTBED_PeerEventMessage) ==
412                  ntohs (msg->header.size));
413   op_id = GNUNET_ntohll (msg->operation_id);
414   if (NULL == (opc = find_opc (c, op_id)))
415   {
416     LOG_DEBUG ("Operation not found\n");
417     return GNUNET_YES;
418   }
419   if (OP_FORWARDED == opc->type)
420   {
421     struct ForwardedOperationData *fo_data;
422
423     fo_data = opc->data;
424     if (NULL != fo_data->cc)
425       fo_data->cc (fo_data->cc_cls, (const struct GNUNET_MessageHeader *) msg);
426     GNUNET_CONTAINER_DLL_remove (c->ocq_head, c->ocq_tail, opc);
427     GNUNET_free (fo_data);
428     GNUNET_free (opc);
429     return GNUNET_YES;
430   }
431   GNUNET_assert ((OP_PEER_START == opc->type) || (OP_PEER_STOP == opc->type));
432   data = opc->data;
433   GNUNET_assert (NULL != data);
434   peer = data->peer;
435   GNUNET_assert (NULL != peer);
436   event.type = (enum GNUNET_TESTBED_EventType) ntohl (msg->event_type);
437   switch (event.type)
438   {
439   case GNUNET_TESTBED_ET_PEER_START:
440     peer->state = PS_STARTED;
441     event.details.peer_start.host = peer->host;
442     event.details.peer_start.peer = peer;
443     break;
444   case GNUNET_TESTBED_ET_PEER_STOP:
445     peer->state = PS_STOPPED;
446     event.details.peer_stop.peer = peer;
447     break;
448   default:
449     GNUNET_assert (0);          /* We should never reach this state */
450   }
451   pcc = data->pcc;
452   pcc_cls = data->pcc_cls;
453   GNUNET_free (data);
454   GNUNET_CONTAINER_DLL_remove (opc->c->ocq_head, opc->c->ocq_tail, opc);
455   opc->state = OPC_STATE_FINISHED;
456   if (0 !=
457       ((GNUNET_TESTBED_ET_PEER_START | GNUNET_TESTBED_ET_PEER_STOP) &
458        c->event_mask))
459   {
460     if (NULL != c->cc)
461       c->cc (c->cc_cls, &event);
462   }
463   if (NULL != pcc)
464     pcc (pcc_cls, NULL);
465   return GNUNET_YES;
466 }
467
468
469 /**
470  * Handler for GNUNET_MESSAGE_TYPE_TESTBED_PEERCONEVENT message from
471  * controller (testbed service)
472  *
473  * @param c the controller handler
474  * @param msg message received
475  * @return GNUNET_YES if we can continue receiving from service; GNUNET_NO if
476  *           not
477  */
478 static int
479 handle_peer_conevent (struct GNUNET_TESTBED_Controller *c,
480                       const struct GNUNET_TESTBED_ConnectionEventMessage *msg)
481 {
482   struct OperationContext *opc;
483   struct OverlayConnectData *data;
484   GNUNET_TESTBED_OperationCompletionCallback cb;
485   void *cb_cls;
486   struct GNUNET_TESTBED_EventInformation event;
487   uint64_t op_id;
488
489   op_id = GNUNET_ntohll (msg->operation_id);
490   if (NULL == (opc = find_opc (c, op_id)))
491   {
492     LOG_DEBUG ("Operation not found\n");
493     return GNUNET_YES;
494   }
495   data = opc->data;
496   GNUNET_assert (NULL != data);
497   GNUNET_assert ((ntohl (msg->peer1) == data->p1->unique_id) &&
498                  (ntohl (msg->peer2) == data->p2->unique_id));
499   event.type = (enum GNUNET_TESTBED_EventType) ntohl (msg->event_type);
500   switch (event.type)
501   {
502   case GNUNET_TESTBED_ET_CONNECT:
503     event.details.peer_connect.peer1 = data->p1;
504     event.details.peer_connect.peer2 = data->p2;
505     break;
506   case GNUNET_TESTBED_ET_DISCONNECT:
507     GNUNET_assert (0);          /* FIXME: implement */
508     break;
509   default:
510     GNUNET_assert (0);          /* Should never reach here */
511     break;
512   }
513   cb = data->cb;
514   cb_cls = data->cb_cls;
515   GNUNET_CONTAINER_DLL_remove (opc->c->ocq_head, opc->c->ocq_tail, opc);
516   opc->state = OPC_STATE_FINISHED;
517   GNUNET_free (data);
518   if (0 !=
519       ((GNUNET_TESTBED_ET_CONNECT | GNUNET_TESTBED_ET_DISCONNECT) &
520        c->event_mask))
521   {
522     if (NULL != c->cc)
523       c->cc (c->cc_cls, &event);
524   }
525   if (NULL != cb)
526     cb (cb_cls, opc->op, NULL);
527   return GNUNET_YES;
528 }
529
530
531 /**
532  * Handler for GNUNET_MESSAGE_TYPE_TESTBED_PEERCONFIG message from
533  * controller (testbed service)
534  *
535  * @param c the controller handler
536  * @param msg message received
537  * @return GNUNET_YES if we can continue receiving from service; GNUNET_NO if
538  *           not
539  */
540 static int
541 handle_peer_config (struct GNUNET_TESTBED_Controller *c,
542                     const struct
543                     GNUNET_TESTBED_PeerConfigurationInformationMessage *msg)
544 {
545   struct OperationContext *opc;
546   struct GNUNET_TESTBED_Peer *peer;
547   struct PeerInfoData *data;
548   struct GNUNET_TESTBED_PeerInformation *pinfo;
549   GNUNET_TESTBED_PeerInfoCallback cb;
550   void *cb_cls;
551   uint64_t op_id;
552
553   op_id = GNUNET_ntohll (msg->operation_id);
554   if (NULL == (opc = find_opc (c, op_id)))
555   {
556     LOG_DEBUG ("Operation not found\n");
557     return GNUNET_YES;
558   }
559   if (OP_FORWARDED == opc->type)
560   {
561     struct ForwardedOperationData *fo_data;
562
563     fo_data = opc->data;
564     if (NULL != fo_data->cc)
565       fo_data->cc (fo_data->cc_cls, (const struct GNUNET_MessageHeader *) msg);
566     GNUNET_CONTAINER_DLL_remove (c->ocq_head, c->ocq_tail, opc);
567     GNUNET_free (fo_data);
568     GNUNET_free (opc);
569     return GNUNET_YES;
570   }
571   data = opc->data;
572   GNUNET_assert (NULL != data);
573   peer = data->peer;
574   GNUNET_assert (NULL != peer);
575   GNUNET_assert (ntohl (msg->peer_id) == peer->unique_id);
576   pinfo = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_PeerInformation));
577   pinfo->pit = data->pit;
578   cb = data->cb;
579   cb_cls = data->cb_cls;
580   GNUNET_free (data);
581   opc->data = NULL;
582   switch (pinfo->pit)
583   {
584   case GNUNET_TESTBED_PIT_IDENTITY:
585     pinfo->result.id = GNUNET_malloc (sizeof (struct GNUNET_PeerIdentity));
586     (void) memcpy (pinfo->result.id, &msg->peer_identity,
587                    sizeof (struct GNUNET_PeerIdentity));
588     break;
589   case GNUNET_TESTBED_PIT_CONFIGURATION:
590     pinfo->result.cfg =        /* Freed in oprelease_peer_getinfo */
591         GNUNET_TESTBED_get_config_from_peerinfo_msg_ (msg);    
592     break;
593   case GNUNET_TESTBED_PIT_GENERIC:
594     GNUNET_assert (0);          /* never reach here */
595     break;
596   }
597   opc->data = pinfo;
598   GNUNET_CONTAINER_DLL_remove (opc->c->ocq_head, opc->c->ocq_tail, opc);
599   opc->state = OPC_STATE_FINISHED;
600   if (NULL != cb)
601     cb (cb_cls, opc->op, pinfo, NULL);
602   return GNUNET_YES;
603 }
604
605
606 /**
607  * Handler for GNUNET_MESSAGE_TYPE_TESTBED_OPERATIONFAILEVENT message from
608  * controller (testbed service)
609  *
610  * @param c the controller handler
611  * @param msg message received
612  * @return GNUNET_YES if we can continue receiving from service; GNUNET_NO if
613  *           not
614  */
615 static int
616 handle_op_fail_event (struct GNUNET_TESTBED_Controller *c,
617                       const struct GNUNET_TESTBED_OperationFailureEventMessage
618                       *msg)
619 {
620   struct OperationContext *opc;
621   const char *emsg;
622   uint64_t op_id;
623   struct GNUNET_TESTBED_EventInformation event;
624
625   op_id = GNUNET_ntohll (msg->operation_id);
626   if (NULL == (opc = find_opc (c, op_id)))
627   {
628     LOG_DEBUG ("Operation not found\n");
629     return GNUNET_YES;
630   }
631   GNUNET_CONTAINER_DLL_remove (opc->c->ocq_head, opc->c->ocq_tail, opc);
632   if (OP_FORWARDED == opc->type)
633   {
634     struct ForwardedOperationData *fo_data;
635
636     fo_data = opc->data;
637     if (NULL != fo_data->cc)
638       fo_data->cc (fo_data->cc_cls, (const struct GNUNET_MessageHeader *) msg);
639     GNUNET_free (fo_data);
640     GNUNET_free (opc);
641     return GNUNET_YES;
642   }
643   opc->state = OPC_STATE_FINISHED;
644   emsg = GNUNET_TESTBED_parse_error_string_ (msg);
645   if (NULL == emsg)
646     emsg = "Unknown error";
647   if (OP_PEER_INFO == opc->type)
648   {
649     struct PeerInfoData *data;
650     data = opc->data;
651     if (NULL != data->cb)
652       data->cb (data->cb_cls, opc->op, NULL, emsg);
653     GNUNET_free (data);
654     return GNUNET_YES;  /* We do not call controller callback for peer info */
655   }
656   if ((0 != (GNUNET_TESTBED_ET_OPERATION_FINISHED & c->event_mask)) &&
657       (NULL != c->cc))
658   {
659     event.type = GNUNET_TESTBED_ET_OPERATION_FINISHED;
660     event.details.operation_finished.operation = opc->op;
661     event.details.operation_finished.op_cls = NULL;
662     event.details.operation_finished.emsg = emsg;
663     event.details.operation_finished.generic = NULL;
664     c->cc (c->cc_cls, &event);
665   }
666   switch (opc->type)
667   {
668   case OP_PEER_CREATE:
669     {
670       struct PeerCreateData *data;      
671       data = opc->data;
672       GNUNET_free (data->peer);
673       if (NULL != data->cb)
674         data->cb (data->cls, NULL, emsg);
675       GNUNET_free (data);      
676     }
677     break;
678   case OP_PEER_START:
679   case OP_PEER_STOP:
680     {
681       struct PeerEventData *data;
682       data = opc->data;
683       if (NULL != data->pcc)
684         data->pcc (data->pcc_cls, emsg);
685       GNUNET_free (data);
686     }
687     break;
688   case OP_PEER_DESTROY:
689     break;
690   case OP_PEER_INFO:
691     GNUNET_assert (0);
692   case OP_OVERLAY_CONNECT:
693     {
694       struct OverlayConnectData *data;
695       data = opc->data;
696       if (NULL != data->cb)
697         data->cb (data->cb_cls, opc->op, emsg);
698       GNUNET_free (data);
699     }
700     break;
701   case OP_FORWARDED:
702     GNUNET_assert (0);
703   case OP_LINK_CONTROLLERS:     /* No secondary callback */
704     break;
705   default:
706     GNUNET_break (0);
707   }  
708   return GNUNET_YES;
709 }
710
711
712 /**
713  * Handler for messages from controller (testbed service)
714  *
715  * @param cls the controller handler
716  * @param msg message received, NULL on timeout or fatal error
717  */
718 static void
719 message_handler (void *cls, const struct GNUNET_MessageHeader *msg)
720 {
721   struct GNUNET_TESTBED_Controller *c = cls;
722   int status;
723   uint16_t msize;
724
725   c->in_receive = GNUNET_NO;
726   /* FIXME: Add checks for message integrity */
727   if (NULL == msg)
728   {
729     LOG_DEBUG ("Receive timed out or connection to service dropped\n");
730     return;
731   }
732   status = GNUNET_OK;
733   msize = ntohs (msg->size);
734   switch (ntohs (msg->type))
735   {
736   case GNUNET_MESSAGE_TYPE_TESTBED_ADDHOSTCONFIRM:
737     GNUNET_assert (msize >=
738                    sizeof (struct GNUNET_TESTBED_HostConfirmedMessage));
739     status =
740         handle_addhostconfirm (c,
741                                (const struct GNUNET_TESTBED_HostConfirmedMessage
742                                 *) msg);
743     break;
744   case GNUNET_MESSAGE_TYPE_TESTBED_GENERICOPSUCCESS:
745     GNUNET_assert (msize ==
746                    sizeof (struct
747                            GNUNET_TESTBED_GenericOperationSuccessEventMessage));
748     status =
749         handle_opsuccess (c,
750                           (const struct
751                            GNUNET_TESTBED_GenericOperationSuccessEventMessage *)
752                           msg);
753     break;
754   case GNUNET_MESSAGE_TYPE_TESTBED_PEERCREATESUCCESS:
755     GNUNET_assert (msize ==
756                    sizeof (struct
757                            GNUNET_TESTBED_PeerCreateSuccessEventMessage));
758     status =
759         handle_peer_create_success (c,
760                                     (const struct
761                                      GNUNET_TESTBED_PeerCreateSuccessEventMessage
762                                      *) msg);
763     break;
764   case GNUNET_MESSAGE_TYPE_TESTBED_PEEREVENT:
765     GNUNET_assert (msize == sizeof (struct GNUNET_TESTBED_PeerEventMessage));
766     status =
767         handle_peer_event (c,
768                            (const struct GNUNET_TESTBED_PeerEventMessage *)
769                            msg);
770
771     break;
772   case GNUNET_MESSAGE_TYPE_TESTBED_PEERCONFIG:
773     GNUNET_assert (msize >=
774                    sizeof (struct
775                            GNUNET_TESTBED_PeerConfigurationInformationMessage));
776     status =
777         handle_peer_config (c,
778                             (const struct
779                              GNUNET_TESTBED_PeerConfigurationInformationMessage
780                              *) msg);
781     break;
782   case GNUNET_MESSAGE_TYPE_TESTBED_PEERCONEVENT:
783     GNUNET_assert (msize ==
784                    sizeof (struct GNUNET_TESTBED_ConnectionEventMessage));
785     status =
786         handle_peer_conevent (c,
787                               (const struct
788                                GNUNET_TESTBED_ConnectionEventMessage *) msg);
789     break;
790   case GNUNET_MESSAGE_TYPE_TESTBED_OPERATIONFAILEVENT:
791     GNUNET_assert (msize >=
792                    sizeof (struct GNUNET_TESTBED_OperationFailureEventMessage));
793     status =
794         handle_op_fail_event (c,
795                               (const struct
796                                GNUNET_TESTBED_OperationFailureEventMessage *)
797                               msg);
798     break;
799   default:
800     GNUNET_assert (0);
801   }
802   if ((GNUNET_OK == status) && (GNUNET_NO == c->in_receive))
803   {
804     c->in_receive = GNUNET_YES;
805     GNUNET_CLIENT_receive (c->client, &message_handler, c,
806                            GNUNET_TIME_UNIT_FOREVER_REL);
807   }
808 }
809
810
811 /**
812  * Function called to notify a client about the connection begin ready to queue
813  * more data.  "buf" will be NULL and "size" zero if the connection was closed
814  * for writing in the meantime.
815  *
816  * @param cls closure
817  * @param size number of bytes available in buf
818  * @param buf where the callee should write the message
819  * @return number of bytes written to buf
820  */
821 static size_t
822 transmit_ready_notify (void *cls, size_t size, void *buf)
823 {
824   struct GNUNET_TESTBED_Controller *c = cls;
825   struct MessageQueue *mq_entry;
826
827   c->th = NULL;
828   mq_entry = c->mq_head;
829   GNUNET_assert (NULL != mq_entry);
830   if ((0 == size) && (NULL == buf))     /* Timeout */
831   {
832     LOG_DEBUG ("Message sending timed out -- retrying\n");
833     c->th =
834         GNUNET_CLIENT_notify_transmit_ready (c->client,
835                                              ntohs (mq_entry->msg->size),
836                                              TIMEOUT_REL, GNUNET_YES,
837                                              &transmit_ready_notify, c);
838     return 0;
839   }
840   GNUNET_assert (ntohs (mq_entry->msg->size) <= size);
841   size = ntohs (mq_entry->msg->size);
842   memcpy (buf, mq_entry->msg, size);
843   LOG_DEBUG ("Message of type: %u and size: %u sent\n",
844              ntohs (mq_entry->msg->type), size);
845   GNUNET_free (mq_entry->msg);
846   GNUNET_CONTAINER_DLL_remove (c->mq_head, c->mq_tail, mq_entry);
847   GNUNET_free (mq_entry);
848   mq_entry = c->mq_head;
849   if (NULL != mq_entry)
850     c->th =
851         GNUNET_CLIENT_notify_transmit_ready (c->client,
852                                              ntohs (mq_entry->msg->size),
853                                              TIMEOUT_REL, GNUNET_YES,
854                                              &transmit_ready_notify, c);
855   if (GNUNET_NO == c->in_receive)
856   {
857     c->in_receive = GNUNET_YES;
858     GNUNET_CLIENT_receive (c->client, &message_handler, c,
859                            GNUNET_TIME_UNIT_FOREVER_REL);
860   }
861   return size;
862 }
863
864
865 /**
866  * Queues a message in send queue for sending to the service
867  *
868  * @param controller the handle to the controller
869  * @param msg the message to queue
870  */
871 void
872 GNUNET_TESTBED_queue_message_ (struct GNUNET_TESTBED_Controller *controller,
873                                struct GNUNET_MessageHeader *msg)
874 {
875   struct MessageQueue *mq_entry;
876   uint16_t type;
877   uint16_t size;
878
879   type = ntohs (msg->type);
880   size = ntohs (msg->size);
881   GNUNET_assert ((GNUNET_MESSAGE_TYPE_TESTBED_INIT <= type) &&
882                  (GNUNET_MESSAGE_TYPE_TESTBED_MAX > type));
883   mq_entry = GNUNET_malloc (sizeof (struct MessageQueue));
884   mq_entry->msg = msg;
885   LOG (GNUNET_ERROR_TYPE_DEBUG,
886        "Queueing message of type %u, size %u for sending\n", type,
887        ntohs (msg->size));
888   GNUNET_CONTAINER_DLL_insert_tail (controller->mq_head, controller->mq_tail,
889                                     mq_entry);
890   if (NULL == controller->th)
891     controller->th =
892         GNUNET_CLIENT_notify_transmit_ready (controller->client, size,
893                                              TIMEOUT_REL, GNUNET_YES,
894                                              &transmit_ready_notify,
895                                              controller);
896 }
897
898
899 /**
900  * Sends the given message as an operation. The given callback is called when a
901  * reply for the operation is available.  Call
902  * GNUNET_TESTBED_forward_operation_msg_cancel_() to cleanup the returned
903  * operation context if the cc hasn't been called
904  *
905  * @param controller the controller to which the message has to be sent
906  * @param operation_id the operation id of the message
907  * @param msg the message to send
908  * @param cc the callback to call when reply is available
909  * @param cc_cls the closure for the above callback
910  * @return the operation context which can be used to cancel the forwarded
911  *           operation
912  */
913 struct OperationContext *
914 GNUNET_TESTBED_forward_operation_msg_ (struct GNUNET_TESTBED_Controller
915                                        *controller, uint64_t operation_id,
916                                        const struct GNUNET_MessageHeader *msg,
917                                        GNUNET_CLIENT_MessageHandler cc,
918                                        void *cc_cls)
919 {
920   struct OperationContext *opc;
921   struct ForwardedOperationData *data;
922   struct GNUNET_MessageHeader *dup_msg;
923   uint16_t msize;
924
925   data = GNUNET_malloc (sizeof (struct ForwardedOperationData));
926   data->cc = cc;
927   data->cc_cls = cc_cls;
928   opc = GNUNET_malloc (sizeof (struct OperationContext));
929   opc->c = controller;
930   opc->type = OP_FORWARDED;
931   opc->data = data;
932   opc->id = operation_id;
933   msize = ntohs (msg->size);
934   dup_msg = GNUNET_malloc (msize);
935   (void) memcpy (dup_msg, msg, msize);
936   GNUNET_TESTBED_queue_message_ (opc->c, dup_msg);
937   GNUNET_CONTAINER_DLL_insert_tail (controller->ocq_head, controller->ocq_tail,
938                                     opc);
939   return opc;
940 }
941
942
943 /**
944  * Function to cancel an operation created by simply forwarding an operation
945  * message.
946  *
947  * @param opc the operation context from GNUNET_TESTBED_forward_operation_msg_()
948  */
949 void
950 GNUNET_TESTBED_forward_operation_msg_cancel_ (struct OperationContext *opc)
951 {
952   GNUNET_CONTAINER_DLL_remove (opc->c->ocq_head, opc->c->ocq_tail, opc);
953   GNUNET_free (opc->data);
954   GNUNET_free (opc);
955 }
956
957
958 /**
959  * Handle for controller process
960  */
961 struct GNUNET_TESTBED_ControllerProc
962 {
963   /**
964    * The process handle
965    */
966   struct GNUNET_HELPER_Handle *helper;
967
968   /**
969    * The host where the helper is run
970    */
971   struct GNUNET_TESTBED_Host *host;
972
973   /**
974    * The controller error callback
975    */
976   GNUNET_TESTBED_ControllerStatusCallback cb;
977
978   /**
979    * The closure for the above callback
980    */
981   void *cls;
982
983   /**
984    * The send handle for the helper
985    */
986   struct GNUNET_HELPER_SendHandle *shandle;
987
988   /**
989    * The message corresponding to send handle
990    */
991   struct GNUNET_MessageHeader *msg;
992
993   /**
994    * The port number for ssh; used for helpers starting ssh
995    */
996   char *port;
997
998   /**
999    * The ssh destination string; used for helpers starting ssh
1000    */
1001   char *dst;
1002
1003   /**
1004    * The configuration of the running testbed service
1005    */
1006   struct GNUNET_CONFIGURATION_Handle *cfg;
1007
1008 };
1009
1010
1011 /**
1012  * Functions with this signature are called whenever a
1013  * complete message is received by the tokenizer.
1014  *
1015  * Do not call GNUNET_SERVER_mst_destroy in callback
1016  *
1017  * @param cls closure
1018  * @param client identification of the client
1019  * @param message the actual message
1020  *
1021  * @return GNUNET_OK on success, GNUNET_SYSERR to stop further processing
1022  */
1023 static int
1024 helper_mst (void *cls, void *client, const struct GNUNET_MessageHeader *message)
1025 {
1026   struct GNUNET_TESTBED_ControllerProc *cp = cls;
1027   const struct GNUNET_TESTBED_HelperReply *msg;
1028   const char *hostname;
1029   char *config;
1030   uLongf config_size;
1031   uLongf xconfig_size;
1032
1033   msg = (const struct GNUNET_TESTBED_HelperReply *) message;
1034   GNUNET_assert (sizeof (struct GNUNET_TESTBED_HelperReply) <
1035                  ntohs (msg->header.size));
1036   GNUNET_assert (GNUNET_MESSAGE_TYPE_TESTBED_HELPER_REPLY ==
1037                  ntohs (msg->header.type));
1038   config_size = (uLongf) ntohs (msg->config_size);
1039   xconfig_size =
1040       (uLongf) (ntohs (msg->header.size) -
1041                 sizeof (struct GNUNET_TESTBED_HelperReply));
1042   config = GNUNET_malloc (config_size);
1043   GNUNET_assert (Z_OK ==
1044                  uncompress ((Bytef *) config, &config_size,
1045                              (const Bytef *) &msg[1], xconfig_size));
1046   GNUNET_assert (NULL == cp->cfg);
1047   cp->cfg = GNUNET_CONFIGURATION_create ();
1048   GNUNET_assert (GNUNET_CONFIGURATION_deserialize
1049                  (cp->cfg, config, config_size, GNUNET_NO));
1050   GNUNET_free (config);
1051   if ((NULL == cp->host) ||
1052       (NULL == (hostname = GNUNET_TESTBED_host_get_hostname_ (cp->host))))
1053     hostname = "localhost";
1054   /* Change the hostname so that we can connect to it */
1055   GNUNET_CONFIGURATION_set_value_string (cp->cfg, "testbed", "hostname",
1056                                          hostname);
1057   cp->cb (cp->cls, cp->cfg, GNUNET_OK);
1058   return GNUNET_OK;
1059 }
1060
1061
1062 /**
1063  * Continuation function from GNUNET_HELPER_send()
1064  *
1065  * @param cls closure
1066  * @param result GNUNET_OK on success,
1067  *               GNUNET_NO if helper process died
1068  *               GNUNET_SYSERR during GNUNET_HELPER_stop
1069  */
1070 static void
1071 clear_msg (void *cls, int result)
1072 {
1073   struct GNUNET_TESTBED_ControllerProc *cp = cls;
1074
1075   GNUNET_assert (NULL != cp->shandle);
1076   cp->shandle = NULL;
1077   GNUNET_free (cp->msg);
1078 }
1079
1080
1081 /**
1082  * Callback that will be called when the helper process dies. This is not called
1083  * when the helper process is stoped using GNUNET_HELPER_stop()
1084  *
1085  * @param cls the closure from GNUNET_HELPER_start()
1086  */
1087 static void
1088 helper_exp_cb (void *cls)
1089 {
1090   struct GNUNET_TESTBED_ControllerProc *cp = cls;
1091   GNUNET_TESTBED_ControllerStatusCallback cb;
1092   void *cb_cls;
1093
1094   cb = cp->cb;
1095   cb_cls = cp->cls;
1096   cp->helper = NULL;
1097   GNUNET_TESTBED_controller_stop (cp);
1098   if (NULL != cb)
1099     cb (cb_cls, NULL, GNUNET_SYSERR);
1100 }
1101
1102
1103 /**
1104  * Function to call to start a link-controllers type operation once all queues
1105  * the operation is part of declare that the operation can be activated.
1106  *
1107  * @param cls the closure from GNUNET_TESTBED_operation_create_()
1108  */
1109 static void
1110 opstart_link_controllers (void *cls)
1111 {
1112   struct OperationContext *opc = cls;
1113   struct GNUNET_TESTBED_ControllerLinkMessage *msg;
1114
1115   GNUNET_assert (NULL != opc->data);
1116   msg = opc->data;
1117   opc->data = NULL;
1118   opc->state = OPC_STATE_STARTED;
1119   GNUNET_CONTAINER_DLL_insert_tail (opc->c->ocq_head, opc->c->ocq_tail, opc);
1120   GNUNET_TESTBED_queue_message_ (opc->c, &msg->header);
1121 }
1122
1123
1124 /**
1125  * Callback which will be called when link-controllers type operation is released
1126  *
1127  * @param cls the closure from GNUNET_TESTBED_operation_create_()
1128  */
1129 static void
1130 oprelease_link_controllers (void *cls)
1131 {
1132   struct OperationContext *opc = cls;
1133
1134   if (OPC_STATE_INIT == opc->state)
1135     GNUNET_free (opc->data);
1136   if (OPC_STATE_STARTED == opc->state)
1137     GNUNET_CONTAINER_DLL_remove (opc->c->ocq_head, opc->c->ocq_tail, opc);
1138   GNUNET_free (opc);
1139 }
1140
1141
1142 /**
1143  * Starts a controller process at the host. FIXME: add controller start callback
1144  * with the configuration with which the controller is started
1145  *
1146  * @param controller_ip the ip address of the controller. Will be set as TRUSTED
1147  *          host when starting testbed controller at host
1148  * @param host the host where the controller has to be started; NULL for
1149  *          localhost
1150  * @param cfg template configuration to use for the remote controller; the
1151  *          remote controller will be started with a slightly modified
1152  *          configuration (port numbers, unix domain sockets and service home
1153  *          values are changed as per TESTING library on the remote host)
1154  * @param cb function called when the controller is successfully started or
1155  *          dies unexpectedly; GNUNET_TESTBED_controller_stop shouldn't be
1156  *          called if cb is called with GNUNET_SYSERR as status. Will never be
1157  *          called in the same task as 'GNUNET_TESTBED_controller_start'
1158  *          (synchronous errors will be signalled by returning NULL). This
1159  *          parameter cannot be NULL.
1160  * @param cls closure for above callbacks
1161  * @return the controller process handle, NULL on errors
1162  */
1163 struct GNUNET_TESTBED_ControllerProc *
1164 GNUNET_TESTBED_controller_start (const char *controller_ip,
1165                                  struct GNUNET_TESTBED_Host *host,
1166                                  const struct GNUNET_CONFIGURATION_Handle *cfg,
1167                                  GNUNET_TESTBED_ControllerStatusCallback cb,
1168                                  void *cls)
1169 {
1170   struct GNUNET_TESTBED_ControllerProc *cp;
1171   struct GNUNET_TESTBED_HelperInit *msg;
1172
1173   cp = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_ControllerProc));
1174   if ((NULL == host) || (0 == GNUNET_TESTBED_host_get_id_ (host)))
1175   {
1176     char *const binary_argv[] = {
1177       HELPER_TESTBED_BINARY, NULL
1178     };
1179
1180     cp->helper =
1181         GNUNET_HELPER_start (GNUNET_YES, HELPER_TESTBED_BINARY, binary_argv,
1182                              &helper_mst, &helper_exp_cb, cp);
1183   }
1184   else
1185   {
1186     char *remote_args[8];
1187     unsigned int argp;
1188     const char *username;
1189     const char *hostname;
1190
1191     username = GNUNET_TESTBED_host_get_username_ (host);
1192     hostname = GNUNET_TESTBED_host_get_hostname_ (host);
1193     GNUNET_asprintf (&cp->port, "%u", GNUNET_TESTBED_host_get_ssh_port_ (host));
1194     if (NULL == username)
1195       GNUNET_asprintf (&cp->dst, "%s", hostname);
1196     else
1197       GNUNET_asprintf (&cp->dst, "%s@%s", username, hostname);
1198     LOG_DEBUG ("Starting SSH to destination %s\n", cp->dst);
1199     argp = 0;
1200     remote_args[argp++] = "ssh";
1201     remote_args[argp++] = "-p";
1202     remote_args[argp++] = cp->port;
1203     remote_args[argp++] = "-o";
1204     remote_args[argp++] = "BatchMode=yes";
1205     remote_args[argp++] = cp->dst;
1206     remote_args[argp++] = HELPER_TESTBED_BINARY;
1207     remote_args[argp++] = NULL;
1208     GNUNET_assert (argp == 8);
1209     cp->helper =
1210         GNUNET_HELPER_start (GNUNET_NO, "ssh", remote_args, &helper_mst,
1211                              &helper_exp_cb, cp);
1212   }
1213   if (NULL == cp->helper)
1214   {
1215     GNUNET_free_non_null (cp->port);
1216     GNUNET_free_non_null (cp->dst);
1217     GNUNET_free (cp);
1218     return NULL;
1219   }
1220   cp->host = host;
1221   cp->cb = cb;
1222   cp->cls = cls;
1223   msg = GNUNET_TESTBED_create_helper_init_msg_ (controller_ip, cfg);
1224   cp->msg = &msg->header;
1225   cp->shandle =
1226       GNUNET_HELPER_send (cp->helper, &msg->header, GNUNET_NO, &clear_msg, cp);
1227   if (NULL == cp->shandle)
1228   {
1229     GNUNET_free (msg);
1230     GNUNET_TESTBED_controller_stop (cp);
1231     return NULL;
1232   }
1233   return cp;
1234 }
1235
1236
1237 /**
1238  * Stop the controller process (also will terminate all peers and controllers
1239  * dependent on this controller).  This function blocks until the testbed has
1240  * been fully terminated (!).
1241  *
1242  * @param cproc the controller process handle
1243  */
1244 void
1245 GNUNET_TESTBED_controller_stop (struct GNUNET_TESTBED_ControllerProc *cproc)
1246 {
1247   if (NULL != cproc->shandle)
1248     GNUNET_HELPER_send_cancel (cproc->shandle);
1249   if (NULL != cproc->helper)
1250     GNUNET_HELPER_stop (cproc->helper);
1251   if (NULL != cproc->cfg)
1252     GNUNET_CONFIGURATION_destroy (cproc->cfg);
1253   GNUNET_free_non_null (cproc->port);
1254   GNUNET_free_non_null (cproc->dst);
1255   GNUNET_free (cproc);
1256 }
1257
1258
1259 /**
1260  * Start a controller process using the given configuration at the
1261  * given host.
1262  *
1263  * @param cfg configuration to use
1264  * @param host host to run the controller on; This should be the same host if
1265  *          the controller was previously started with
1266  *          GNUNET_TESTBED_controller_start; NULL for localhost
1267  * @param event_mask bit mask with set of events to call 'cc' for;
1268  *                   or-ed values of "1LL" shifted by the
1269  *                   respective 'enum GNUNET_TESTBED_EventType'
1270  *                   (i.e.  "(1LL << GNUNET_TESTBED_ET_CONNECT) | ...")
1271  * @param cc controller callback to invoke on events
1272  * @param cc_cls closure for cc
1273  * @return handle to the controller
1274  */
1275 struct GNUNET_TESTBED_Controller *
1276 GNUNET_TESTBED_controller_connect (const struct GNUNET_CONFIGURATION_Handle
1277                                    *cfg, struct GNUNET_TESTBED_Host *host,
1278                                    uint64_t event_mask,
1279                                    GNUNET_TESTBED_ControllerCallback cc,
1280                                    void *cc_cls)
1281 {
1282   struct GNUNET_TESTBED_Controller *controller;
1283   struct GNUNET_TESTBED_InitMessage *msg;
1284   const char *controller_hostname;
1285   unsigned long long max_parallel_operations;
1286   unsigned long long max_parallel_service_connections;
1287
1288   if (GNUNET_OK !=
1289       GNUNET_CONFIGURATION_get_value_number (cfg, "testbed",
1290                                              "MAX_PARALLEL_OPERATIONS",
1291                                              &max_parallel_operations))
1292   {
1293     GNUNET_break (0);
1294     return NULL;
1295   }
1296   if (GNUNET_OK !=
1297       GNUNET_CONFIGURATION_get_value_number (cfg, "testbed",
1298                                              "MAX_PARALLEL_SERVICE_CONNECTIONS",
1299                                              &max_parallel_service_connections))
1300   {
1301     GNUNET_break (0);
1302     return NULL;
1303   }
1304   controller = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_Controller));
1305   controller->cc = cc;
1306   controller->cc_cls = cc_cls;
1307   controller->event_mask = event_mask;
1308   controller->cfg = GNUNET_CONFIGURATION_dup (cfg);
1309   controller->client = GNUNET_CLIENT_connect ("testbed", controller->cfg);
1310   if (NULL == controller->client)
1311   {
1312     GNUNET_TESTBED_controller_disconnect (controller);
1313     return NULL;
1314   }
1315   if (NULL == host)
1316   {
1317     host = GNUNET_TESTBED_host_create_by_id_ (0);
1318     if (NULL == host)           /* If the above host create fails */
1319     {
1320       LOG (GNUNET_ERROR_TYPE_WARNING,
1321            "Treating NULL host as localhost. Multiple references to localhost "
1322            "may break when localhost freed before calling disconnect \n");
1323       host = GNUNET_TESTBED_host_lookup_by_id_ (0);
1324     }
1325     else
1326     {
1327       controller->aux_host = GNUNET_YES;
1328     }
1329   }
1330   GNUNET_assert (NULL != host);
1331   GNUNET_TESTBED_mark_host_registered_at_ (host, controller);
1332   controller->host = host;
1333   controller->opq_parallel_operations =
1334       GNUNET_TESTBED_operation_queue_create_ ((unsigned int)
1335                                               max_parallel_operations);
1336   controller->opq_parallel_service_connections =
1337       GNUNET_TESTBED_operation_queue_create_ ((unsigned int)
1338                                               max_parallel_service_connections);
1339   controller_hostname = GNUNET_TESTBED_host_get_hostname_ (host);
1340   if (NULL == controller_hostname)
1341     controller_hostname = "127.0.0.1";
1342   msg =
1343       GNUNET_malloc (sizeof (struct GNUNET_TESTBED_InitMessage) +
1344                      strlen (controller_hostname) + 1);
1345   msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_INIT);
1346   msg->header.size =
1347       htons (sizeof (struct GNUNET_TESTBED_InitMessage) +
1348              strlen (controller_hostname) + 1);
1349   msg->host_id = htonl (GNUNET_TESTBED_host_get_id_ (host));
1350   msg->event_mask = GNUNET_htonll (controller->event_mask);
1351   strcpy ((char *) &msg[1], controller_hostname);
1352   GNUNET_TESTBED_queue_message_ (controller,
1353                                  (struct GNUNET_MessageHeader *) msg);
1354   return controller;
1355 }
1356
1357
1358 /**
1359  * Configure shared services at a controller.  Using this function,
1360  * you can specify that certain services (such as "resolver")
1361  * should not be run for each peer but instead be shared
1362  * across N peers on the specified host.  This function
1363  * must be called before any peers are created at the host.
1364  *
1365  * @param controller controller to configure
1366  * @param service_name name of the service to share
1367  * @param num_peers number of peers that should share one instance
1368  *        of the specified service (1 for no sharing is the default),
1369  *        use 0 to disable the service
1370  */
1371 void
1372 GNUNET_TESTBED_controller_configure_sharing (struct GNUNET_TESTBED_Controller
1373                                              *controller,
1374                                              const char *service_name,
1375                                              uint32_t num_peers)
1376 {
1377   struct GNUNET_TESTBED_ConfigureSharedServiceMessage *msg;
1378   uint16_t service_name_size;
1379   uint16_t msg_size;
1380
1381   service_name_size = strlen (service_name) + 1;
1382   msg_size =
1383       sizeof (struct GNUNET_TESTBED_ConfigureSharedServiceMessage) +
1384       service_name_size;
1385   msg = GNUNET_malloc (msg_size);
1386   msg->header.size = htons (msg_size);
1387   msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_SERVICESHARE);
1388   msg->host_id = htonl (GNUNET_TESTBED_host_get_id_ (controller->host));
1389   msg->num_peers = htonl (num_peers);
1390   memcpy (&msg[1], service_name, service_name_size);
1391   GNUNET_TESTBED_queue_message_ (controller,
1392                                  (struct GNUNET_MessageHeader *) msg);
1393 }
1394
1395
1396 /**
1397  * disconnects from the controller.
1398  *
1399  * @param controller handle to controller to stop
1400  */
1401 void
1402 GNUNET_TESTBED_controller_disconnect (struct GNUNET_TESTBED_Controller
1403                                       *controller)
1404 {
1405   struct MessageQueue *mq_entry;
1406
1407   if (NULL != controller->th)
1408     GNUNET_CLIENT_notify_transmit_ready_cancel (controller->th);
1409   /* Clear the message queue */
1410   while (NULL != (mq_entry = controller->mq_head))
1411   {
1412     GNUNET_CONTAINER_DLL_remove (controller->mq_head, controller->mq_tail,
1413                                  mq_entry);
1414     GNUNET_free (mq_entry->msg);
1415     GNUNET_free (mq_entry);
1416   }
1417   if (NULL != controller->client)
1418     GNUNET_CLIENT_disconnect (controller->client);
1419   GNUNET_CONFIGURATION_destroy (controller->cfg);
1420   if (GNUNET_YES == controller->aux_host)
1421     GNUNET_TESTBED_host_destroy (controller->host);
1422   GNUNET_TESTBED_operation_queue_destroy_ (controller->opq_parallel_operations);
1423   GNUNET_TESTBED_operation_queue_destroy_
1424       (controller->opq_parallel_service_connections);
1425   GNUNET_free (controller);
1426 }
1427
1428
1429 /**
1430  * Register a host with the controller
1431  *
1432  * @param controller the controller handle
1433  * @param host the host to register
1434  * @param cc the completion callback to call to inform the status of
1435  *          registration. After calling this callback the registration handle
1436  *          will be invalid. Cannot be NULL.
1437  * @param cc_cls the closure for the cc
1438  * @return handle to the host registration which can be used to cancel the
1439  *           registration
1440  */
1441 struct GNUNET_TESTBED_HostRegistrationHandle *
1442 GNUNET_TESTBED_register_host (struct GNUNET_TESTBED_Controller *controller,
1443                               struct GNUNET_TESTBED_Host *host,
1444                               GNUNET_TESTBED_HostRegistrationCompletion cc,
1445                               void *cc_cls)
1446 {
1447   struct GNUNET_TESTBED_HostRegistrationHandle *rh;
1448   struct GNUNET_TESTBED_AddHostMessage *msg;
1449   const char *username;
1450   const char *hostname;
1451   uint16_t msg_size;
1452   uint16_t user_name_length;
1453
1454   if (NULL != controller->rh)
1455     return NULL;
1456   hostname = GNUNET_TESTBED_host_get_hostname_ (host);
1457   if (GNUNET_YES == GNUNET_TESTBED_is_host_registered_ (host, controller))
1458   {
1459     LOG (GNUNET_ERROR_TYPE_WARNING, "Host hostname: %s already registered\n",
1460          (NULL == hostname) ? "localhost" : hostname);
1461     return NULL;
1462   }
1463   rh = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_HostRegistrationHandle));
1464   rh->host = host;
1465   rh->c = controller;
1466   GNUNET_assert (NULL != cc);
1467   rh->cc = cc;
1468   rh->cc_cls = cc_cls;
1469   controller->rh = rh;
1470   username = GNUNET_TESTBED_host_get_username_ (host);
1471   msg_size = (sizeof (struct GNUNET_TESTBED_AddHostMessage));
1472   user_name_length = 0;
1473   if (NULL != username)
1474   {
1475     user_name_length = strlen (username) + 1;
1476     msg_size += user_name_length;
1477   }
1478   /* FIXME: what happens when hostname is NULL? localhost */
1479   GNUNET_assert (NULL != hostname);
1480   msg_size += strlen (hostname) + 1;
1481   msg = GNUNET_malloc (msg_size);
1482   msg->header.size = htons (msg_size);
1483   msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST);
1484   msg->host_id = htonl (GNUNET_TESTBED_host_get_id_ (host));
1485   msg->ssh_port = htons (GNUNET_TESTBED_host_get_ssh_port_ (host));
1486   msg->user_name_length = htons (user_name_length);
1487   if (NULL != username)
1488     memcpy (&msg[1], username, user_name_length);
1489   strcpy (((void *) &msg[1]) + user_name_length, hostname);
1490   GNUNET_TESTBED_queue_message_ (controller,
1491                                  (struct GNUNET_MessageHeader *) msg);
1492   return rh;
1493 }
1494
1495
1496 /**
1497  * Cancel the pending registration. Note that if the registration message is
1498  * already sent to the service the cancellation has only the effect that the
1499  * registration completion callback for the registration is never called.
1500  *
1501  * @param handle the registration handle to cancel
1502  */
1503 void
1504 GNUNET_TESTBED_cancel_registration (struct GNUNET_TESTBED_HostRegistrationHandle
1505                                     *handle)
1506 {
1507   if (handle != handle->c->rh)
1508   {
1509     GNUNET_break (0);
1510     return;
1511   }
1512   handle->c->rh = NULL;
1513   GNUNET_free (handle);
1514 }
1515
1516
1517 /**
1518  * Same as the GNUNET_TESTBED_controller_link, however expects configuration in
1519  * serialized and compressed
1520  *
1521  * @param master handle to the master controller who creates the association
1522  * @param delegated_host requests to which host should be delegated; cannot be NULL
1523  * @param slave_host which host is used to run the slave controller; use NULL to
1524  *          make the master controller connect to the delegated host
1525  * @param sxcfg serialized and compressed configuration
1526  * @param sxcfg_size the size scfg
1527  * @param scfg_size the size of uncompressed serialized configuration
1528  * @param is_subordinate GNUNET_YES if the controller at delegated_host should
1529  *          be started by the master controller; GNUNET_NO if we are just
1530  *          allowed to use the slave via TCP/IP
1531  */
1532 struct GNUNET_TESTBED_Operation *
1533 GNUNET_TESTBED_controller_link_2 (struct GNUNET_TESTBED_Controller *master,
1534                                   struct GNUNET_TESTBED_Host *delegated_host,
1535                                   struct GNUNET_TESTBED_Host *slave_host,
1536                                   const char *sxcfg, size_t sxcfg_size,
1537                                   size_t scfg_size, int is_subordinate)
1538 {
1539   struct OperationContext *opc;
1540   struct GNUNET_TESTBED_ControllerLinkMessage *msg;
1541   uint16_t msg_size;
1542
1543   GNUNET_assert (GNUNET_YES ==
1544                  GNUNET_TESTBED_is_host_registered_ (delegated_host, master));
1545   if ((NULL != slave_host) && (0 != GNUNET_TESTBED_host_get_id_ (slave_host)))
1546     GNUNET_assert (GNUNET_YES ==
1547                    GNUNET_TESTBED_is_host_registered_ (slave_host, master));
1548   msg_size = sxcfg_size + sizeof (struct GNUNET_TESTBED_ControllerLinkMessage);
1549   msg = GNUNET_malloc (msg_size);
1550   msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_LCONTROLLERS);
1551   msg->header.size = htons (msg_size);
1552   msg->delegated_host_id = htonl (GNUNET_TESTBED_host_get_id_ (delegated_host));
1553   msg->slave_host_id =
1554       htonl (GNUNET_TESTBED_host_get_id_
1555              ((NULL != slave_host) ? slave_host : master->host));
1556   msg->config_size = htons ((uint16_t) scfg_size);
1557   msg->is_subordinate = (GNUNET_YES == is_subordinate) ? 1 : 0;
1558   memcpy (&msg[1], sxcfg, sxcfg_size);
1559   opc = GNUNET_malloc (sizeof (struct OperationContext));
1560   opc->c = master;
1561   opc->data = msg;
1562   opc->type = OP_LINK_CONTROLLERS;
1563   opc->id = master->operation_counter++;
1564   opc->state = OPC_STATE_INIT;
1565   msg->operation_id = GNUNET_htonll (opc->id);
1566   opc->op =
1567       GNUNET_TESTBED_operation_create_ (opc, &opstart_link_controllers,
1568                                         &oprelease_link_controllers);
1569   GNUNET_TESTBED_operation_queue_insert_ (master->opq_parallel_operations,
1570                                           opc->op);
1571   return opc->op;
1572 }
1573
1574
1575 /**
1576  * Compresses given configuration using zlib compress
1577  *
1578  * @param config the serialized configuration
1579  * @param size the size of config
1580  * @param xconfig will be set to the compressed configuration (memory is fresly
1581  *          allocated)
1582  * @return the size of the xconfig
1583  */
1584 size_t
1585 GNUNET_TESTBED_compress_config_ (const char *config, size_t size,
1586                                  char **xconfig)
1587 {
1588   size_t xsize;
1589
1590   xsize = compressBound ((uLong) size);
1591   *xconfig = GNUNET_malloc (xsize);
1592   GNUNET_assert (Z_OK ==
1593                  compress2 ((Bytef *) * xconfig, (uLongf *) & xsize,
1594                             (const Bytef *) config, (uLongf) size,
1595                             Z_BEST_SPEED));
1596   return xsize;
1597 }
1598
1599
1600 /**
1601  * Create a link from slave controller to delegated controller. Whenever the
1602  * master controller is asked to start a peer at the delegated controller the
1603  * request will be routed towards slave controller (if a route exists). The
1604  * slave controller will then route it to the delegated controller. The
1605  * configuration of the slave controller is given and to be used to either
1606  * create the slave controller or to connect to an existing slave controller
1607  * process.  'is_subordinate' specifies if the given slave controller should be
1608  * started and managed by the master controller, or if the slave already has a
1609  * master and this is just a secondary master that is also allowed to use the
1610  * existing slave.
1611  *
1612  * @param master handle to the master controller who creates the association
1613  * @param delegated_host requests to which host should be delegated
1614  * @param slave_host which host is used to run the slave controller
1615  * @param slave_cfg configuration to use for the slave controller
1616  * @param is_subordinate GNUNET_YES if the slave should be started (and stopped)
1617  *                       by the master controller; GNUNET_NO if we are just
1618  *                       allowed to use the slave via TCP/IP
1619  * @return the operation handle
1620  */
1621 struct GNUNET_TESTBED_Operation *
1622 GNUNET_TESTBED_controller_link (struct GNUNET_TESTBED_Controller *master,
1623                                 struct GNUNET_TESTBED_Host *delegated_host,
1624                                 struct GNUNET_TESTBED_Host *slave_host,
1625                                 const struct GNUNET_CONFIGURATION_Handle
1626                                 *slave_cfg, int is_subordinate)
1627 {
1628   struct GNUNET_TESTBED_Operation *op;
1629   char *config;
1630   char *cconfig;
1631   size_t cc_size;
1632   size_t config_size;
1633
1634   GNUNET_assert (GNUNET_YES ==
1635                  GNUNET_TESTBED_is_host_registered_ (delegated_host, master));
1636   if ((NULL != slave_host) && (0 != GNUNET_TESTBED_host_get_id_ (slave_host)))
1637     GNUNET_assert (GNUNET_YES ==
1638                    GNUNET_TESTBED_is_host_registered_ (slave_host, master));
1639   config = GNUNET_CONFIGURATION_serialize (slave_cfg, &config_size);
1640   cc_size = GNUNET_TESTBED_compress_config_ (config, config_size, &cconfig);
1641   GNUNET_free (config);
1642   GNUNET_assert ((UINT16_MAX - sizeof (struct GNUNET_TESTBED_ControllerLinkMessage)) >= cc_size);       /* Configuration doesn't fit in 1 message */
1643   op = GNUNET_TESTBED_controller_link_2 (master, delegated_host, slave_host,
1644                                          (const char *) cconfig, cc_size,
1645                                          config_size, is_subordinate);
1646   GNUNET_free (cconfig);
1647   return op;
1648 }
1649
1650
1651 /**
1652  * Ask the testbed controller to write the current overlay topology to
1653  * a file.  Naturally, the file will only contain a snapshot as the
1654  * topology may evolve all the time.
1655  *
1656  * @param controller overlay controller to inspect
1657  * @param filename name of the file the topology should
1658  *        be written to.
1659  */
1660 void
1661 GNUNET_TESTBED_overlay_write_topology_to_file (struct GNUNET_TESTBED_Controller
1662                                                *controller,
1663                                                const char *filename)
1664 {
1665   GNUNET_break (0);
1666 }
1667
1668
1669 /**
1670  * Creates a helper initialization message. This function is here because we
1671  * want to use this in testing
1672  *
1673  * @param cname the ip address of the controlling host
1674  * @param cfg the configuration that has to used to start the testbed service
1675  *          thru helper
1676  * @return the initialization message
1677  */
1678 struct GNUNET_TESTBED_HelperInit *
1679 GNUNET_TESTBED_create_helper_init_msg_ (const char *cname,
1680                                         const struct GNUNET_CONFIGURATION_Handle
1681                                         *cfg)
1682 {
1683   struct GNUNET_TESTBED_HelperInit *msg;
1684   char *config;
1685   char *xconfig;
1686   size_t config_size;
1687   size_t xconfig_size;
1688   uint16_t cname_len;
1689   uint16_t msg_size;
1690
1691   config = GNUNET_CONFIGURATION_serialize (cfg, &config_size);
1692   GNUNET_assert (NULL != config);
1693   xconfig_size =
1694       GNUNET_TESTBED_compress_config_ (config, config_size, &xconfig);
1695   GNUNET_free (config);
1696   cname_len = strlen (cname);
1697   msg_size =
1698       xconfig_size + cname_len + 1 + sizeof (struct GNUNET_TESTBED_HelperInit);
1699   msg = GNUNET_realloc (xconfig, msg_size);
1700   (void) memmove (((void *) &msg[1]) + cname_len + 1, msg, xconfig_size);
1701   msg->header.size = htons (msg_size);
1702   msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_HELPER_INIT);
1703   msg->cname_size = htons (cname_len);
1704   msg->config_size = htons (config_size);
1705   (void) strcpy ((char *) &msg[1], cname);
1706   return msg;
1707 }
1708
1709
1710 /**
1711  * Cancel a pending operation.  Releases all resources
1712  * of the operation and will ensure that no event
1713  * is generated for the operation.  Does NOT guarantee
1714  * that the operation will be fully undone (or that
1715  * nothing ever happened).
1716  *
1717  * @param operation operation to cancel
1718  */
1719 void
1720 GNUNET_TESTBED_operation_cancel (struct GNUNET_TESTBED_Operation *operation)
1721 {
1722   GNUNET_TESTBED_operation_done (operation);
1723 }
1724
1725
1726 /**
1727  * Signal that the information from an operation has been fully
1728  * processed.  This function MUST be called for each event
1729  * of type 'operation_finished' to fully remove the operation
1730  * from the operation queue.  After calling this function, the
1731  * 'op_result' becomes invalid (!).
1732  *
1733  * @param operation operation to signal completion for
1734  */
1735 void
1736 GNUNET_TESTBED_operation_done (struct GNUNET_TESTBED_Operation *operation)
1737 {
1738   switch (operation->type)
1739   {
1740   case OP_PEER_CREATE:
1741   case OP_PEER_DESTROY:
1742   case OP_PEER_START:
1743   case OP_PEER_STOP:
1744   case OP_PEER_INFO:
1745   case OP_OVERLAY_CONNECT:
1746   case OP_LINK_CONTROLLERS:
1747     GNUNET_TESTBED_operation_release_ (operation);
1748     return;
1749   default:
1750     GNUNET_assert (0);
1751     break;
1752   }
1753 }
1754
1755
1756 /**
1757  * Generates configuration by parsing Peer configuration information reply message
1758  *
1759  * @param msg the peer configuration information message
1760  * @return handle to the parsed configuration
1761  */
1762 struct GNUNET_CONFIGURATION_Handle *
1763 GNUNET_TESTBED_get_config_from_peerinfo_msg_ (const struct
1764                                               GNUNET_TESTBED_PeerConfigurationInformationMessage
1765                                               *msg)
1766 {
1767   struct GNUNET_CONFIGURATION_Handle *cfg;
1768   char *config;
1769   uLong config_size;
1770   int ret;
1771   uint16_t msize;
1772
1773   config_size = (uLong) ntohs (msg->config_size);
1774   config = GNUNET_malloc (config_size);
1775   msize = ntohs (msg->header.size);
1776   msize -= sizeof (struct GNUNET_TESTBED_PeerConfigurationInformationMessage);
1777   if (Z_OK !=
1778       (ret =
1779        uncompress ((Bytef *) config, &config_size, (const Bytef *) &msg[1],
1780                    (uLong) msize)))
1781     GNUNET_assert (0);
1782   cfg = GNUNET_CONFIGURATION_create ();
1783   GNUNET_assert (GNUNET_OK ==
1784                  GNUNET_CONFIGURATION_deserialize (cfg, config,
1785                                                    (size_t) config_size,
1786                                                    GNUNET_NO));
1787   GNUNET_free (config);
1788   return cfg;
1789 }
1790
1791
1792 /**
1793  * Checks the integrity of the OperationFailureEventMessage and if good returns
1794  * the error message it contains.
1795  *
1796  * @param msg the OperationFailureEventMessage
1797  * @return the error message
1798  */
1799 const char *
1800 GNUNET_TESTBED_parse_error_string_ (const struct
1801                                     GNUNET_TESTBED_OperationFailureEventMessage
1802                                     *msg)
1803 {
1804   uint16_t msize;
1805   const char *emsg;
1806   
1807   msize = ntohs (msg->header.size);
1808   if (sizeof (struct GNUNET_TESTBED_OperationFailureEventMessage) >= msize)
1809     return NULL;
1810   msize -= sizeof (struct GNUNET_TESTBED_OperationFailureEventMessage);
1811   emsg = (const char *) &msg[1];
1812   if ('\0' != emsg[msize])
1813   {
1814     GNUNET_break (0);
1815     return NULL;
1816   }
1817   return emsg;
1818 }
1819
1820 /* end of testbed_api.c */