- run on computers with gnunet_prefix != /usr/bin
[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 ". .bashrc; 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   static char *const binary_argv[] = {
1173     HELPER_TESTBED_BINARY, NULL
1174   };
1175   
1176   cp = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_ControllerProc));
1177   if ((NULL == host) || (0 == GNUNET_TESTBED_host_get_id_ (host)))
1178     cp->helper =
1179         GNUNET_HELPER_start (GNUNET_YES, HELPER_TESTBED_BINARY, binary_argv,
1180                              &helper_mst, &helper_exp_cb, cp);
1181   else
1182   {
1183     char *remote_args[8];
1184     unsigned int argp;
1185     const char *username;
1186     const char *hostname;
1187
1188     username = GNUNET_TESTBED_host_get_username_ (host);
1189     hostname = GNUNET_TESTBED_host_get_hostname_ (host);
1190     GNUNET_asprintf (&cp->port, "%u", GNUNET_TESTBED_host_get_ssh_port_ (host));
1191     if (NULL == username)
1192       GNUNET_asprintf (&cp->dst, "%s", hostname);
1193     else
1194       GNUNET_asprintf (&cp->dst, "%s@%s", username, hostname);
1195     LOG_DEBUG ("Starting SSH to destination %s\n", cp->dst);
1196     argp = 0;
1197     remote_args[argp++] = "ssh";
1198     remote_args[argp++] = "-p";
1199     remote_args[argp++] = cp->port;
1200     remote_args[argp++] = "-o";
1201     remote_args[argp++] = "BatchMode=yes";
1202     remote_args[argp++] = cp->dst;
1203     remote_args[argp++] = HELPER_TESTBED_BINARY;
1204     remote_args[argp++] = NULL;
1205     GNUNET_assert (argp == 8);
1206     cp->helper =
1207         GNUNET_HELPER_start (GNUNET_NO, "ssh", remote_args, &helper_mst,
1208                              &helper_exp_cb, cp);
1209   }
1210   if (NULL == cp->helper)
1211   {
1212     GNUNET_free_non_null (cp->port);
1213     GNUNET_free_non_null (cp->dst);
1214     GNUNET_free (cp);
1215     return NULL;
1216   }
1217   cp->host = host;
1218   cp->cb = cb;
1219   cp->cls = cls;
1220   msg = GNUNET_TESTBED_create_helper_init_msg_ (controller_ip, cfg);
1221   cp->msg = &msg->header;
1222   cp->shandle =
1223       GNUNET_HELPER_send (cp->helper, &msg->header, GNUNET_NO, &clear_msg, cp);
1224   if (NULL == cp->shandle)
1225   {
1226     GNUNET_free (msg);
1227     GNUNET_TESTBED_controller_stop (cp);
1228     return NULL;
1229   }
1230   return cp;
1231 }
1232
1233
1234 /**
1235  * Stop the controller process (also will terminate all peers and controllers
1236  * dependent on this controller).  This function blocks until the testbed has
1237  * been fully terminated (!).
1238  *
1239  * @param cproc the controller process handle
1240  */
1241 void
1242 GNUNET_TESTBED_controller_stop (struct GNUNET_TESTBED_ControllerProc *cproc)
1243 {
1244   if (NULL != cproc->shandle)
1245     GNUNET_HELPER_send_cancel (cproc->shandle);
1246   if (NULL != cproc->helper)
1247     GNUNET_HELPER_stop (cproc->helper);
1248   if (NULL != cproc->cfg)
1249     GNUNET_CONFIGURATION_destroy (cproc->cfg);
1250   GNUNET_free_non_null (cproc->port);
1251   GNUNET_free_non_null (cproc->dst);
1252   GNUNET_free (cproc);
1253 }
1254
1255
1256 /**
1257  * Start a controller process using the given configuration at the
1258  * given host.
1259  *
1260  * @param cfg configuration to use
1261  * @param host host to run the controller on; This should be the same host if
1262  *          the controller was previously started with
1263  *          GNUNET_TESTBED_controller_start; NULL for localhost
1264  * @param event_mask bit mask with set of events to call 'cc' for;
1265  *                   or-ed values of "1LL" shifted by the
1266  *                   respective 'enum GNUNET_TESTBED_EventType'
1267  *                   (i.e.  "(1LL << GNUNET_TESTBED_ET_CONNECT) | ...")
1268  * @param cc controller callback to invoke on events
1269  * @param cc_cls closure for cc
1270  * @return handle to the controller
1271  */
1272 struct GNUNET_TESTBED_Controller *
1273 GNUNET_TESTBED_controller_connect (const struct GNUNET_CONFIGURATION_Handle
1274                                    *cfg, struct GNUNET_TESTBED_Host *host,
1275                                    uint64_t event_mask,
1276                                    GNUNET_TESTBED_ControllerCallback cc,
1277                                    void *cc_cls)
1278 {
1279   struct GNUNET_TESTBED_Controller *controller;
1280   struct GNUNET_TESTBED_InitMessage *msg;
1281   const char *controller_hostname;
1282   unsigned long long max_parallel_operations;
1283   unsigned long long max_parallel_service_connections;
1284   unsigned long long max_parallel_topology_config_operations;
1285
1286   if (GNUNET_OK !=
1287       GNUNET_CONFIGURATION_get_value_number (cfg, "testbed",
1288                                              "MAX_PARALLEL_OPERATIONS",
1289                                              &max_parallel_operations))
1290   {
1291     GNUNET_break (0);
1292     return NULL;
1293   }
1294   if (GNUNET_OK !=
1295       GNUNET_CONFIGURATION_get_value_number (cfg, "testbed",
1296                                              "MAX_PARALLEL_SERVICE_CONNECTIONS",
1297                                              &max_parallel_service_connections))
1298   {
1299     GNUNET_break (0);
1300     return NULL;
1301   }
1302   if (GNUNET_OK !=
1303       GNUNET_CONFIGURATION_get_value_number (cfg, "testbed",
1304                                              "MAX_PARALLEL_TOPOLOGY_CONFIG_OPERATIONS",
1305                                              &max_parallel_topology_config_operations))
1306   {
1307     GNUNET_break (0);
1308     return NULL;
1309   }
1310   controller = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_Controller));
1311   controller->cc = cc;
1312   controller->cc_cls = cc_cls;
1313   controller->event_mask = event_mask;
1314   controller->cfg = GNUNET_CONFIGURATION_dup (cfg);
1315   controller->client = GNUNET_CLIENT_connect ("testbed", controller->cfg);
1316   if (NULL == controller->client)
1317   {
1318     GNUNET_TESTBED_controller_disconnect (controller);
1319     return NULL;
1320   }
1321   if (NULL == host)
1322   {
1323     host = GNUNET_TESTBED_host_create_by_id_ (0);
1324     if (NULL == host)           /* If the above host create fails */
1325     {
1326       LOG (GNUNET_ERROR_TYPE_WARNING,
1327            "Treating NULL host as localhost. Multiple references to localhost "
1328            "may break when localhost freed before calling disconnect \n");
1329       host = GNUNET_TESTBED_host_lookup_by_id_ (0);
1330     }
1331     else
1332     {
1333       controller->aux_host = GNUNET_YES;
1334     }
1335   }
1336   GNUNET_assert (NULL != host);
1337   GNUNET_TESTBED_mark_host_registered_at_ (host, controller);
1338   controller->host = host;
1339   controller->opq_parallel_operations =
1340       GNUNET_TESTBED_operation_queue_create_ ((unsigned int)
1341                                               max_parallel_operations);
1342   controller->opq_parallel_service_connections =
1343       GNUNET_TESTBED_operation_queue_create_ ((unsigned int)
1344                                               max_parallel_service_connections);
1345   controller->opq_parallel_topology_config_operations=
1346       GNUNET_TESTBED_operation_queue_create_ ((unsigned int)
1347                                               max_parallel_service_connections);
1348   controller_hostname = GNUNET_TESTBED_host_get_hostname_ (host);
1349   if (NULL == controller_hostname)
1350     controller_hostname = "127.0.0.1";
1351   msg =
1352       GNUNET_malloc (sizeof (struct GNUNET_TESTBED_InitMessage) +
1353                      strlen (controller_hostname) + 1);
1354   msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_INIT);
1355   msg->header.size =
1356       htons (sizeof (struct GNUNET_TESTBED_InitMessage) +
1357              strlen (controller_hostname) + 1);
1358   msg->host_id = htonl (GNUNET_TESTBED_host_get_id_ (host));
1359   msg->event_mask = GNUNET_htonll (controller->event_mask);
1360   strcpy ((char *) &msg[1], controller_hostname);
1361   GNUNET_TESTBED_queue_message_ (controller,
1362                                  (struct GNUNET_MessageHeader *) msg);
1363   return controller;
1364 }
1365
1366
1367 /**
1368  * Configure shared services at a controller.  Using this function,
1369  * you can specify that certain services (such as "resolver")
1370  * should not be run for each peer but instead be shared
1371  * across N peers on the specified host.  This function
1372  * must be called before any peers are created at the host.
1373  *
1374  * @param controller controller to configure
1375  * @param service_name name of the service to share
1376  * @param num_peers number of peers that should share one instance
1377  *        of the specified service (1 for no sharing is the default),
1378  *        use 0 to disable the service
1379  */
1380 void
1381 GNUNET_TESTBED_controller_configure_sharing (struct GNUNET_TESTBED_Controller
1382                                              *controller,
1383                                              const char *service_name,
1384                                              uint32_t num_peers)
1385 {
1386   struct GNUNET_TESTBED_ConfigureSharedServiceMessage *msg;
1387   uint16_t service_name_size;
1388   uint16_t msg_size;
1389
1390   service_name_size = strlen (service_name) + 1;
1391   msg_size =
1392       sizeof (struct GNUNET_TESTBED_ConfigureSharedServiceMessage) +
1393       service_name_size;
1394   msg = GNUNET_malloc (msg_size);
1395   msg->header.size = htons (msg_size);
1396   msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_SERVICESHARE);
1397   msg->host_id = htonl (GNUNET_TESTBED_host_get_id_ (controller->host));
1398   msg->num_peers = htonl (num_peers);
1399   memcpy (&msg[1], service_name, service_name_size);
1400   GNUNET_TESTBED_queue_message_ (controller,
1401                                  (struct GNUNET_MessageHeader *) msg);
1402 }
1403
1404
1405 /**
1406  * disconnects from the controller.
1407  *
1408  * @param controller handle to controller to stop
1409  */
1410 void
1411 GNUNET_TESTBED_controller_disconnect (struct GNUNET_TESTBED_Controller
1412                                       *controller)
1413 {
1414   struct MessageQueue *mq_entry;
1415
1416   if (NULL != controller->th)
1417     GNUNET_CLIENT_notify_transmit_ready_cancel (controller->th);
1418   /* Clear the message queue */
1419   while (NULL != (mq_entry = controller->mq_head))
1420   {
1421     GNUNET_CONTAINER_DLL_remove (controller->mq_head, controller->mq_tail,
1422                                  mq_entry);
1423     GNUNET_free (mq_entry->msg);
1424     GNUNET_free (mq_entry);
1425   }
1426   if (NULL != controller->client)
1427     GNUNET_CLIENT_disconnect (controller->client);
1428   GNUNET_CONFIGURATION_destroy (controller->cfg);
1429   if (GNUNET_YES == controller->aux_host)
1430     GNUNET_TESTBED_host_destroy (controller->host);
1431   GNUNET_TESTBED_operation_queue_destroy_ (controller->opq_parallel_operations);
1432   GNUNET_TESTBED_operation_queue_destroy_
1433       (controller->opq_parallel_service_connections);
1434   GNUNET_TESTBED_operation_queue_destroy_
1435       (controller->opq_parallel_topology_config_operations);
1436   GNUNET_free (controller);
1437 }
1438
1439
1440 /**
1441  * Register a host with the controller
1442  *
1443  * @param controller the controller handle
1444  * @param host the host to register
1445  * @param cc the completion callback to call to inform the status of
1446  *          registration. After calling this callback the registration handle
1447  *          will be invalid. Cannot be NULL.
1448  * @param cc_cls the closure for the cc
1449  * @return handle to the host registration which can be used to cancel the
1450  *           registration
1451  */
1452 struct GNUNET_TESTBED_HostRegistrationHandle *
1453 GNUNET_TESTBED_register_host (struct GNUNET_TESTBED_Controller *controller,
1454                               struct GNUNET_TESTBED_Host *host,
1455                               GNUNET_TESTBED_HostRegistrationCompletion cc,
1456                               void *cc_cls)
1457 {
1458   struct GNUNET_TESTBED_HostRegistrationHandle *rh;
1459   struct GNUNET_TESTBED_AddHostMessage *msg;
1460   const char *username;
1461   const char *hostname;
1462   uint16_t msg_size;
1463   uint16_t user_name_length;
1464
1465   if (NULL != controller->rh)
1466     return NULL;
1467   hostname = GNUNET_TESTBED_host_get_hostname_ (host);
1468   if (GNUNET_YES == GNUNET_TESTBED_is_host_registered_ (host, controller))
1469   {
1470     LOG (GNUNET_ERROR_TYPE_WARNING, "Host hostname: %s already registered\n",
1471          (NULL == hostname) ? "localhost" : hostname);
1472     return NULL;
1473   }
1474   rh = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_HostRegistrationHandle));
1475   rh->host = host;
1476   rh->c = controller;
1477   GNUNET_assert (NULL != cc);
1478   rh->cc = cc;
1479   rh->cc_cls = cc_cls;
1480   controller->rh = rh;
1481   username = GNUNET_TESTBED_host_get_username_ (host);
1482   msg_size = (sizeof (struct GNUNET_TESTBED_AddHostMessage));
1483   user_name_length = 0;
1484   if (NULL != username)
1485   {
1486     user_name_length = strlen (username) + 1;
1487     msg_size += user_name_length;
1488   }
1489   /* FIXME: what happens when hostname is NULL? localhost */
1490   GNUNET_assert (NULL != hostname);
1491   msg_size += strlen (hostname) + 1;
1492   msg = GNUNET_malloc (msg_size);
1493   msg->header.size = htons (msg_size);
1494   msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST);
1495   msg->host_id = htonl (GNUNET_TESTBED_host_get_id_ (host));
1496   msg->ssh_port = htons (GNUNET_TESTBED_host_get_ssh_port_ (host));
1497   msg->user_name_length = htons (user_name_length);
1498   if (NULL != username)
1499     memcpy (&msg[1], username, user_name_length);
1500   strcpy (((void *) &msg[1]) + user_name_length, hostname);
1501   GNUNET_TESTBED_queue_message_ (controller,
1502                                  (struct GNUNET_MessageHeader *) msg);
1503   return rh;
1504 }
1505
1506
1507 /**
1508  * Cancel the pending registration. Note that if the registration message is
1509  * already sent to the service the cancellation has only the effect that the
1510  * registration completion callback for the registration is never called.
1511  *
1512  * @param handle the registration handle to cancel
1513  */
1514 void
1515 GNUNET_TESTBED_cancel_registration (struct GNUNET_TESTBED_HostRegistrationHandle
1516                                     *handle)
1517 {
1518   if (handle != handle->c->rh)
1519   {
1520     GNUNET_break (0);
1521     return;
1522   }
1523   handle->c->rh = NULL;
1524   GNUNET_free (handle);
1525 }
1526
1527
1528 /**
1529  * Same as the GNUNET_TESTBED_controller_link, however expects configuration in
1530  * serialized and compressed
1531  *
1532  * @param master handle to the master controller who creates the association
1533  * @param delegated_host requests to which host should be delegated; cannot be NULL
1534  * @param slave_host which host is used to run the slave controller; use NULL to
1535  *          make the master controller connect to the delegated host
1536  * @param sxcfg serialized and compressed configuration
1537  * @param sxcfg_size the size scfg
1538  * @param scfg_size the size of uncompressed serialized configuration
1539  * @param is_subordinate GNUNET_YES if the controller at delegated_host should
1540  *          be started by the master controller; GNUNET_NO if we are just
1541  *          allowed to use the slave via TCP/IP
1542  */
1543 struct GNUNET_TESTBED_Operation *
1544 GNUNET_TESTBED_controller_link_2 (struct GNUNET_TESTBED_Controller *master,
1545                                   struct GNUNET_TESTBED_Host *delegated_host,
1546                                   struct GNUNET_TESTBED_Host *slave_host,
1547                                   const char *sxcfg, size_t sxcfg_size,
1548                                   size_t scfg_size, int is_subordinate)
1549 {
1550   struct OperationContext *opc;
1551   struct GNUNET_TESTBED_ControllerLinkMessage *msg;
1552   uint16_t msg_size;
1553
1554   GNUNET_assert (GNUNET_YES ==
1555                  GNUNET_TESTBED_is_host_registered_ (delegated_host, master));
1556   if ((NULL != slave_host) && (0 != GNUNET_TESTBED_host_get_id_ (slave_host)))
1557     GNUNET_assert (GNUNET_YES ==
1558                    GNUNET_TESTBED_is_host_registered_ (slave_host, master));
1559   msg_size = sxcfg_size + sizeof (struct GNUNET_TESTBED_ControllerLinkMessage);
1560   msg = GNUNET_malloc (msg_size);
1561   msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_LCONTROLLERS);
1562   msg->header.size = htons (msg_size);
1563   msg->delegated_host_id = htonl (GNUNET_TESTBED_host_get_id_ (delegated_host));
1564   msg->slave_host_id =
1565       htonl (GNUNET_TESTBED_host_get_id_
1566              ((NULL != slave_host) ? slave_host : master->host));
1567   msg->config_size = htons ((uint16_t) scfg_size);
1568   msg->is_subordinate = (GNUNET_YES == is_subordinate) ? 1 : 0;
1569   memcpy (&msg[1], sxcfg, sxcfg_size);
1570   opc = GNUNET_malloc (sizeof (struct OperationContext));
1571   opc->c = master;
1572   opc->data = msg;
1573   opc->type = OP_LINK_CONTROLLERS;
1574   opc->id = master->operation_counter++;
1575   opc->state = OPC_STATE_INIT;
1576   msg->operation_id = GNUNET_htonll (opc->id);
1577   opc->op =
1578       GNUNET_TESTBED_operation_create_ (opc, &opstart_link_controllers,
1579                                         &oprelease_link_controllers);
1580   GNUNET_TESTBED_operation_queue_insert_ (master->opq_parallel_operations,
1581                                           opc->op);
1582   return opc->op;
1583 }
1584
1585
1586 /**
1587  * Compresses given configuration using zlib compress
1588  *
1589  * @param config the serialized configuration
1590  * @param size the size of config
1591  * @param xconfig will be set to the compressed configuration (memory is fresly
1592  *          allocated)
1593  * @return the size of the xconfig
1594  */
1595 size_t
1596 GNUNET_TESTBED_compress_config_ (const char *config, size_t size,
1597                                  char **xconfig)
1598 {
1599   size_t xsize;
1600
1601   xsize = compressBound ((uLong) size);
1602   *xconfig = GNUNET_malloc (xsize);
1603   GNUNET_assert (Z_OK ==
1604                  compress2 ((Bytef *) * xconfig, (uLongf *) & xsize,
1605                             (const Bytef *) config, (uLongf) size,
1606                             Z_BEST_SPEED));
1607   return xsize;
1608 }
1609
1610
1611 /**
1612  * Create a link from slave controller to delegated controller. Whenever the
1613  * master controller is asked to start a peer at the delegated controller the
1614  * request will be routed towards slave controller (if a route exists). The
1615  * slave controller will then route it to the delegated controller. The
1616  * configuration of the slave controller is given and to be used to either
1617  * create the slave controller or to connect to an existing slave controller
1618  * process.  'is_subordinate' specifies if the given slave controller should be
1619  * started and managed by the master controller, or if the slave already has a
1620  * master and this is just a secondary master that is also allowed to use the
1621  * existing slave.
1622  *
1623  * @param master handle to the master controller who creates the association
1624  * @param delegated_host requests to which host should be delegated
1625  * @param slave_host which host is used to run the slave controller
1626  * @param slave_cfg configuration to use for the slave controller
1627  * @param is_subordinate GNUNET_YES if the slave should be started (and stopped)
1628  *                       by the master controller; GNUNET_NO if we are just
1629  *                       allowed to use the slave via TCP/IP
1630  * @return the operation handle
1631  */
1632 struct GNUNET_TESTBED_Operation *
1633 GNUNET_TESTBED_controller_link (struct GNUNET_TESTBED_Controller *master,
1634                                 struct GNUNET_TESTBED_Host *delegated_host,
1635                                 struct GNUNET_TESTBED_Host *slave_host,
1636                                 const struct GNUNET_CONFIGURATION_Handle
1637                                 *slave_cfg, int is_subordinate)
1638 {
1639   struct GNUNET_TESTBED_Operation *op;
1640   char *config;
1641   char *cconfig;
1642   size_t cc_size;
1643   size_t config_size;
1644
1645   GNUNET_assert (GNUNET_YES ==
1646                  GNUNET_TESTBED_is_host_registered_ (delegated_host, master));
1647   if ((NULL != slave_host) && (0 != GNUNET_TESTBED_host_get_id_ (slave_host)))
1648     GNUNET_assert (GNUNET_YES ==
1649                    GNUNET_TESTBED_is_host_registered_ (slave_host, master));
1650   config = GNUNET_CONFIGURATION_serialize (slave_cfg, &config_size);
1651   cc_size = GNUNET_TESTBED_compress_config_ (config, config_size, &cconfig);
1652   GNUNET_free (config);
1653   GNUNET_assert ((UINT16_MAX - sizeof (struct GNUNET_TESTBED_ControllerLinkMessage)) >= cc_size);       /* Configuration doesn't fit in 1 message */
1654   op = GNUNET_TESTBED_controller_link_2 (master, delegated_host, slave_host,
1655                                          (const char *) cconfig, cc_size,
1656                                          config_size, is_subordinate);
1657   GNUNET_free (cconfig);
1658   return op;
1659 }
1660
1661
1662 /**
1663  * Ask the testbed controller to write the current overlay topology to
1664  * a file.  Naturally, the file will only contain a snapshot as the
1665  * topology may evolve all the time.
1666  *
1667  * @param controller overlay controller to inspect
1668  * @param filename name of the file the topology should
1669  *        be written to.
1670  */
1671 void
1672 GNUNET_TESTBED_overlay_write_topology_to_file (struct GNUNET_TESTBED_Controller
1673                                                *controller,
1674                                                const char *filename)
1675 {
1676   GNUNET_break (0);
1677 }
1678
1679
1680 /**
1681  * Creates a helper initialization message. This function is here because we
1682  * want to use this in testing
1683  *
1684  * @param cname the ip address of the controlling host
1685  * @param cfg the configuration that has to used to start the testbed service
1686  *          thru helper
1687  * @return the initialization message
1688  */
1689 struct GNUNET_TESTBED_HelperInit *
1690 GNUNET_TESTBED_create_helper_init_msg_ (const char *cname,
1691                                         const struct GNUNET_CONFIGURATION_Handle
1692                                         *cfg)
1693 {
1694   struct GNUNET_TESTBED_HelperInit *msg;
1695   char *config;
1696   char *xconfig;
1697   size_t config_size;
1698   size_t xconfig_size;
1699   uint16_t cname_len;
1700   uint16_t msg_size;
1701
1702   config = GNUNET_CONFIGURATION_serialize (cfg, &config_size);
1703   GNUNET_assert (NULL != config);
1704   xconfig_size =
1705       GNUNET_TESTBED_compress_config_ (config, config_size, &xconfig);
1706   GNUNET_free (config);
1707   cname_len = strlen (cname);
1708   msg_size =
1709       xconfig_size + cname_len + 1 + sizeof (struct GNUNET_TESTBED_HelperInit);
1710   msg = GNUNET_realloc (xconfig, msg_size);
1711   (void) memmove (((void *) &msg[1]) + cname_len + 1, msg, xconfig_size);
1712   msg->header.size = htons (msg_size);
1713   msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_HELPER_INIT);
1714   msg->cname_size = htons (cname_len);
1715   msg->config_size = htons (config_size);
1716   (void) strcpy ((char *) &msg[1], cname);
1717   return msg;
1718 }
1719
1720
1721 /**
1722  * Cancel a pending operation.  Releases all resources
1723  * of the operation and will ensure that no event
1724  * is generated for the operation.  Does NOT guarantee
1725  * that the operation will be fully undone (or that
1726  * nothing ever happened).
1727  *
1728  * @param operation operation to cancel
1729  */
1730 void
1731 GNUNET_TESTBED_operation_cancel (struct GNUNET_TESTBED_Operation *operation)
1732 {
1733   GNUNET_TESTBED_operation_done (operation);
1734 }
1735
1736
1737 /**
1738  * Signal that the information from an operation has been fully
1739  * processed.  This function MUST be called for each event
1740  * of type 'operation_finished' to fully remove the operation
1741  * from the operation queue.  After calling this function, the
1742  * 'op_result' becomes invalid (!).
1743  *
1744  * @param operation operation to signal completion for
1745  */
1746 void
1747 GNUNET_TESTBED_operation_done (struct GNUNET_TESTBED_Operation *operation)
1748 {
1749   switch (operation->type)
1750   {
1751   case OP_PEER_CREATE:
1752   case OP_PEER_DESTROY:
1753   case OP_PEER_START:
1754   case OP_PEER_STOP:
1755   case OP_PEER_INFO:
1756   case OP_OVERLAY_CONNECT:
1757   case OP_LINK_CONTROLLERS:
1758     GNUNET_TESTBED_operation_release_ (operation);
1759     return;
1760   default:
1761     GNUNET_assert (0);
1762     break;
1763   }
1764 }
1765
1766
1767 /**
1768  * Generates configuration by parsing Peer configuration information reply message
1769  *
1770  * @param msg the peer configuration information message
1771  * @return handle to the parsed configuration
1772  */
1773 struct GNUNET_CONFIGURATION_Handle *
1774 GNUNET_TESTBED_get_config_from_peerinfo_msg_ (const struct
1775                                               GNUNET_TESTBED_PeerConfigurationInformationMessage
1776                                               *msg)
1777 {
1778   struct GNUNET_CONFIGURATION_Handle *cfg;
1779   char *config;
1780   uLong config_size;
1781   int ret;
1782   uint16_t msize;
1783
1784   config_size = (uLong) ntohs (msg->config_size);
1785   config = GNUNET_malloc (config_size);
1786   msize = ntohs (msg->header.size);
1787   msize -= sizeof (struct GNUNET_TESTBED_PeerConfigurationInformationMessage);
1788   if (Z_OK !=
1789       (ret =
1790        uncompress ((Bytef *) config, &config_size, (const Bytef *) &msg[1],
1791                    (uLong) msize)))
1792     GNUNET_assert (0);
1793   cfg = GNUNET_CONFIGURATION_create ();
1794   GNUNET_assert (GNUNET_OK ==
1795                  GNUNET_CONFIGURATION_deserialize (cfg, config,
1796                                                    (size_t) config_size,
1797                                                    GNUNET_NO));
1798   GNUNET_free (config);
1799   return cfg;
1800 }
1801
1802
1803 /**
1804  * Checks the integrity of the OperationFailureEventMessage and if good returns
1805  * the error message it contains.
1806  *
1807  * @param msg the OperationFailureEventMessage
1808  * @return the error message
1809  */
1810 const char *
1811 GNUNET_TESTBED_parse_error_string_ (const struct
1812                                     GNUNET_TESTBED_OperationFailureEventMessage
1813                                     *msg)
1814 {
1815   uint16_t msize;
1816   const char *emsg;
1817   
1818   msize = ntohs (msg->header.size);
1819   if (sizeof (struct GNUNET_TESTBED_OperationFailureEventMessage) >= msize)
1820     return NULL;
1821   msize -= sizeof (struct GNUNET_TESTBED_OperationFailureEventMessage);
1822   emsg = (const char *) &msg[1];
1823   if ('\0' != emsg[msize])
1824   {
1825     GNUNET_break (0);
1826     return NULL;
1827   }
1828   return emsg;
1829 }
1830
1831 /* end of testbed_api.c */