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