4b9f94f6aeea292488ddf0513f2fe2a4c7206265
[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  * Handle for controller process
72  */
73 struct GNUNET_TESTBED_ControllerProc
74 {
75   /**
76    * The process handle
77    */
78   struct GNUNET_HELPER_Handle *helper;
79
80   /**
81    * The arguments used to start the helper
82    */
83   char **helper_argv;
84
85   /**
86    * The host where the helper is run
87    */
88   struct GNUNET_TESTBED_Host *host;
89
90   /**
91    * The controller error callback
92    */
93   GNUNET_TESTBED_ControllerStatusCallback cb;
94
95   /**
96    * The closure for the above callback
97    */
98   void *cls;
99
100   /**
101    * The send handle for the helper
102    */
103   struct GNUNET_HELPER_SendHandle *shandle;
104
105   /**
106    * The message corresponding to send handle
107    */
108   struct GNUNET_MessageHeader *msg;
109
110   /**
111    * The configuration of the running testbed service
112    */
113   struct GNUNET_CONFIGURATION_Handle *cfg;
114
115 };
116
117
118 /**
119  * The message queue for sending messages to the controller service
120  */
121 struct MessageQueue
122 {
123   /**
124    * The message to be sent
125    */
126   struct GNUNET_MessageHeader *msg;
127
128   /**
129    * next pointer for DLL
130    */
131   struct MessageQueue *next;
132
133   /**
134    * prev pointer for DLL
135    */
136   struct MessageQueue *prev;
137 };
138
139
140 /**
141  * Structure for a controller link
142  */
143 struct ControllerLink
144 {
145   /**
146    * The next ptr for DLL
147    */
148   struct ControllerLink *next;
149
150   /**
151    * The prev ptr for DLL
152    */
153   struct ControllerLink *prev;
154
155   /**
156    * The host which will be referred in the peer start request. This is the
157    * host where the peer should be started
158    */
159   struct GNUNET_TESTBED_Host *delegated_host;
160
161   /**
162    * The host which will contacted to delegate the peer start request
163    */
164   struct GNUNET_TESTBED_Host *slave_host;
165
166   /**
167    * The configuration to be used to connect to slave host
168    */
169   const struct GNUNET_CONFIGURATION_Handle *slave_cfg;
170
171   /**
172    * GNUNET_YES if the slave should be started (and stopped) by us; GNUNET_NO
173    * if we are just allowed to use the slave via TCP/IP
174    */
175   int is_subordinate;
176 };
177
178
179 /**
180  * handle for host registration
181  */
182 struct GNUNET_TESTBED_HostRegistrationHandle
183 {
184   /**
185    * The host being registered
186    */
187   struct GNUNET_TESTBED_Host *host;
188
189   /**
190    * The controller at which this host is being registered
191    */
192   struct GNUNET_TESTBED_Controller *c;
193
194   /**
195    * The Registartion completion callback
196    */
197   GNUNET_TESTBED_HostRegistrationCompletion cc;
198
199   /**
200    * The closure for above callback
201    */
202   void *cc_cls;
203 };
204
205
206 /**
207  * Context data for forwarded Operation
208  */
209 struct ForwardedOperationData
210 {
211
212   /**
213    * The callback to call when reply is available
214    */
215   GNUNET_CLIENT_MessageHandler cc;
216
217   /**
218    * The closure for the above callback
219    */
220   void *cc_cls;
221
222 };
223
224
225 /**
226  * Context data for get slave config operations
227  */
228 struct GetSlaveConfigData
229 {
230   /**
231    * The id of the slave controller
232    */
233   uint32_t slave_id;
234
235 };
236
237
238 /**
239  * Context data for controller link operations
240  */
241 struct ControllerLinkData
242 {
243   /**
244    * The controller link message
245    */
246   struct GNUNET_TESTBED_ControllerLinkMessage *msg;
247
248 };
249
250
251 struct SDEntry
252 {
253   /**
254    * DLL next pointer
255    */
256   struct SDEntry *next;
257
258   /**
259    * DLL prev pointer
260    */
261   struct SDEntry *prev;
262   
263   /**
264    * The value to store
265    */
266   unsigned int amount;
267 };
268
269
270 struct SDHandle
271 {
272   /**
273    * DLL head for storing entries
274    */
275   struct SDEntry *head;
276   
277   /**
278    * DLL tail for storing entries
279    */
280   struct SDEntry *tail;
281   
282   /**
283    * Squared sum of data values
284    */
285   unsigned long long sqsum;
286
287   /**
288    * Sum of the data values
289    */
290   unsigned long sum;
291
292   /**
293    * The average of data amounts
294    */
295   float avg;
296
297   /**
298    * The variance
299    */
300   double vr;
301
302   /**
303    * Number of data values; also the length of DLL containing SDEntries
304    */
305   unsigned int cnt;
306   
307   /**
308    * max number of entries we can have in the DLL
309    */
310   unsigned int max_cnt;
311 };
312
313
314 /**
315  * Initialize standard deviation calculation handle
316  *
317  * @param max_cnt the maximum number of readings to keep
318  * @return the initialized handle
319  */
320 static struct SDHandle *
321 SD_init (unsigned int max_cnt)
322 {
323   struct SDHandle *h;
324   
325   GNUNET_assert (1 < max_cnt);
326   h = GNUNET_malloc (sizeof (struct SDHandle));
327   h->max_cnt = max_cnt;
328   return h;
329 }
330
331
332 /**
333  * Frees the memory allocated to the SD handle
334  *
335  * @param h the SD handle
336  */
337 static void
338 SD_destroy (struct SDHandle *h)
339 {
340   struct SDEntry *entry;
341   
342   while (NULL != (entry = h->head))
343   {
344     GNUNET_CONTAINER_DLL_remove (h->head, h->tail, entry);
345     GNUNET_free (entry);
346   }
347   GNUNET_free (h);
348 }
349
350
351 /**
352  * Add a reading to SD
353  *
354  * @param h the SD handle
355  * @param amount the reading value
356  */
357 static void
358 SD_add_data (struct SDHandle *h, unsigned int amount)
359 {
360   struct SDEntry *entry;
361   double sqavg;
362   double sqsum_avg;
363
364   entry = NULL;
365   if (h->cnt == h->max_cnt)
366   {
367     entry = h->head;
368     GNUNET_CONTAINER_DLL_remove (h->head, h->tail, entry);
369     h->sum -= entry->amount;
370     h->sqsum -= ((unsigned long) entry->amount) * 
371         ((unsigned long) entry->amount);
372     h->cnt--;
373   }
374   GNUNET_assert (h->cnt < h->max_cnt);
375   if (NULL == entry)
376     entry = GNUNET_malloc (sizeof (struct SDEntry));
377   entry->amount = amount;
378   GNUNET_CONTAINER_DLL_insert_tail (h->head, h->tail, entry);
379   h->sum += amount;
380   h->cnt++;
381   h->avg = ((float) h->sum) / ((float) h->cnt);
382   h->sqsum += ((unsigned long) amount) * ((unsigned long) amount);
383   sqsum_avg = ((double) h->sqsum) / ((double) h->cnt);
384   sqavg = ((double) h->avg) * ((double) h->avg);
385   h->vr = sqsum_avg - sqavg;
386 }
387
388
389 /**
390  * Returns the factor by which the given amount differs from the standard deviation
391  *
392  * @param h the SDhandle
393  * @param amount the value for which the deviation is returned
394
395  * @return the deviation from the average; GNUNET_SYSERR if the deviation cannot
396  *           be calculated OR 0 if the deviation is less than the average; a
397  *           maximum of 4 is returned for deviations equal to or larger than 4
398  */
399 static int
400 SD_deviation_factor (struct SDHandle *h, unsigned int amount)
401 {
402   double diff;
403   unsigned int n;
404
405   if (h->cnt < 2)
406     return GNUNET_SYSERR;
407   if (((float) amount) > h->avg)
408     diff = ((float) amount) - h->avg;
409   else
410     return 0; //diff = h->avg - ((float) amount);
411   diff *= diff;
412   for (n = 1; n < 4; n++)
413     if (diff < (((double) (n * n)) * h->vr))
414       break;
415   return n;
416 }
417
418
419 /**
420  * Returns the operation context with the given id if found in the Operation
421  * context queues of the controller
422  *
423  * @param c the controller whose queues are searched
424  * @param id the id which has to be checked
425  * @return the matching operation context; NULL if no match found
426  */
427 static struct OperationContext *
428 find_opc (const struct GNUNET_TESTBED_Controller *c, const uint64_t id)
429 {
430   struct OperationContext *opc;
431
432   for (opc = c->ocq_head; NULL != opc; opc = opc->next)
433   {
434     if (id == opc->id)
435       return opc;
436   }
437   return NULL;
438 }
439
440
441 /**
442  * Handler for GNUNET_MESSAGE_TYPE_TESTBED_ADDHOSTCONFIRM message from
443  * controller (testbed service)
444  *
445  * @param c the controller handler
446  * @param msg message received
447  * @return GNUNET_YES if we can continue receiving from service; GNUNET_NO if
448  *           not
449  */
450 static int
451 handle_addhostconfirm (struct GNUNET_TESTBED_Controller *c,
452                        const struct GNUNET_TESTBED_HostConfirmedMessage *msg)
453 {
454   struct GNUNET_TESTBED_HostRegistrationHandle *rh;
455   char *emsg;
456   uint16_t msg_size;
457
458   rh = c->rh;
459   if (NULL == rh)
460   {
461     return GNUNET_OK;
462   }
463   if (GNUNET_TESTBED_host_get_id_ (rh->host) != ntohl (msg->host_id))
464   {
465     LOG_DEBUG ("Mismatch in host id's %u, %u of host confirm msg\n",
466                GNUNET_TESTBED_host_get_id_ (rh->host), ntohl (msg->host_id));
467     return GNUNET_OK;
468   }
469   c->rh = NULL;
470   msg_size = ntohs (msg->header.size);
471   if (sizeof (struct GNUNET_TESTBED_HostConfirmedMessage) == msg_size)
472   {
473     LOG_DEBUG ("Host %u successfully registered\n", ntohl (msg->host_id));
474     GNUNET_TESTBED_mark_host_registered_at_ (rh->host, c);
475     rh->cc (rh->cc_cls, NULL);
476     GNUNET_free (rh);
477     return GNUNET_OK;
478   }
479   /* We have an error message */
480   emsg = (char *) &msg[1];
481   if ('\0' !=
482       emsg[msg_size - sizeof (struct GNUNET_TESTBED_HostConfirmedMessage)])
483   {
484     GNUNET_break (0);
485     GNUNET_free (rh);
486     return GNUNET_NO;
487   }
488   LOG (GNUNET_ERROR_TYPE_ERROR, _("Adding host %u failed with error: %s\n"),
489        ntohl (msg->host_id), emsg);
490   rh->cc (rh->cc_cls, emsg);
491   GNUNET_free (rh);
492   return GNUNET_OK;
493 }
494
495
496 /**
497  * Handler for forwarded operations
498  *
499  * @param c the controller handle
500  * @param opc the opearation context
501  * @param msg the message
502  */
503 static void
504 handle_forwarded_operation_msg (struct GNUNET_TESTBED_Controller *c,
505                                 struct OperationContext *opc,
506                                 const struct GNUNET_MessageHeader *msg)
507 {
508   struct ForwardedOperationData *fo_data;
509
510   fo_data = opc->data;
511   if (NULL != fo_data->cc)
512     fo_data->cc (fo_data->cc_cls, msg);
513   GNUNET_CONTAINER_DLL_remove (c->ocq_head, c->ocq_tail, opc);
514   GNUNET_free (fo_data);
515   GNUNET_free (opc);
516 }
517
518
519 /**
520  * Handler for GNUNET_MESSAGE_TYPE_TESTBED_ADDHOSTCONFIRM message from
521  * controller (testbed service)
522  *
523  * @param c the controller handler
524  * @param msg message received
525  * @return GNUNET_YES if we can continue receiving from service; GNUNET_NO if
526  *           not
527  */
528 static int
529 handle_opsuccess (struct GNUNET_TESTBED_Controller *c,
530                   const struct
531                   GNUNET_TESTBED_GenericOperationSuccessEventMessage *msg)
532 {
533   struct OperationContext *opc;
534   struct GNUNET_TESTBED_EventInformation event;
535   uint64_t op_id;
536
537   op_id = GNUNET_ntohll (msg->operation_id);
538   LOG_DEBUG ("Operation %lu successful\n", op_id);
539   if (NULL == (opc = find_opc (c, op_id)))
540   {
541     LOG_DEBUG ("Operation not found\n");
542     return GNUNET_YES;
543   }
544   event.type = GNUNET_TESTBED_ET_OPERATION_FINISHED;
545   event.details.operation_finished.operation = opc->op;
546   event.details.operation_finished.op_cls = opc->op_cls;
547   event.details.operation_finished.emsg = NULL;
548   event.details.operation_finished.generic = NULL;
549   switch (opc->type)
550   {
551   case OP_FORWARDED:
552     {
553       handle_forwarded_operation_msg
554           (c, opc, (const struct GNUNET_MessageHeader *) msg);
555       return GNUNET_YES;
556     }
557     break;
558   case OP_PEER_DESTROY:
559     {
560       struct GNUNET_TESTBED_Peer *peer;
561       
562       peer = opc->data;
563       GNUNET_free (peer);
564       opc->data = NULL;
565       //PEERDESTROYDATA
566     }
567     break;
568   case OP_LINK_CONTROLLERS:
569     {
570       struct ControllerLinkData *data;
571       
572       data = opc->data;
573       GNUNET_assert (NULL != data);      
574       GNUNET_free (data);
575       opc->data = NULL;
576     }
577     break;
578   default:
579     GNUNET_assert (0);
580   }  
581   GNUNET_CONTAINER_DLL_remove (opc->c->ocq_head, opc->c->ocq_tail, opc);
582   opc->state = OPC_STATE_FINISHED;
583   if (0 != (c->event_mask & (1L << GNUNET_TESTBED_ET_OPERATION_FINISHED)))
584   {
585     if (NULL != c->cc)
586       c->cc (c->cc_cls, &event);
587   }
588   else
589     LOG_DEBUG ("Not calling callback\n");
590   return GNUNET_YES;
591 }
592
593
594 /**
595  * Handler for GNUNET_MESSAGE_TYPE_TESTBED_PEERCREATESUCCESS message from
596  * controller (testbed service)
597  *
598  * @param c the controller handle
599  * @param msg message received
600  * @return GNUNET_YES if we can continue receiving from service; GNUNET_NO if
601  *           not
602  */
603 static int
604 handle_peer_create_success (struct GNUNET_TESTBED_Controller *c,
605                             const struct
606                             GNUNET_TESTBED_PeerCreateSuccessEventMessage *msg)
607 {
608   struct OperationContext *opc;
609   struct PeerCreateData *data;
610   struct GNUNET_TESTBED_Peer *peer;
611   GNUNET_TESTBED_PeerCreateCallback cb;
612   void *cls;
613   uint64_t op_id;
614
615   GNUNET_assert (sizeof (struct GNUNET_TESTBED_PeerCreateSuccessEventMessage) ==
616                  ntohs (msg->header.size));
617   op_id = GNUNET_ntohll (msg->operation_id);
618   if (NULL == (opc = find_opc (c, op_id)))
619   {
620     LOG_DEBUG ("Operation context for PeerCreateSuccessEvent not found\n");
621     return GNUNET_YES;
622   }
623   if (OP_FORWARDED == opc->type)
624   {
625     handle_forwarded_operation_msg (c, opc,
626                                     (const struct GNUNET_MessageHeader *) msg);
627     return GNUNET_YES;
628   }
629   GNUNET_assert (OP_PEER_CREATE == opc->type);
630   GNUNET_assert (NULL != opc->data);
631   data = opc->data;
632   GNUNET_assert (NULL != data->peer);
633   peer = data->peer;
634   GNUNET_assert (peer->unique_id == ntohl (msg->peer_id));
635   peer->state = PS_CREATED;
636   cb = data->cb;
637   cls = data->cls;
638   GNUNET_free (opc->data);
639   GNUNET_CONTAINER_DLL_remove (opc->c->ocq_head, opc->c->ocq_tail, opc);
640   opc->state = OPC_STATE_FINISHED;
641   if (NULL != cb)
642     cb (cls, peer, NULL);
643   return GNUNET_YES;
644 }
645
646
647 /**
648  * Handler for GNUNET_MESSAGE_TYPE_TESTBED_PEEREVENT message from
649  * controller (testbed service)
650  *
651  * @param c the controller handler
652  * @param msg message received
653  * @return GNUNET_YES if we can continue receiving from service; GNUNET_NO if
654  *           not
655  */
656 static int
657 handle_peer_event (struct GNUNET_TESTBED_Controller *c,
658                    const struct GNUNET_TESTBED_PeerEventMessage *msg)
659 {
660   struct OperationContext *opc;
661   struct GNUNET_TESTBED_Peer *peer;
662   struct PeerEventData *data;
663   GNUNET_TESTBED_PeerChurnCallback pcc;
664   void *pcc_cls;
665   struct GNUNET_TESTBED_EventInformation event;
666   uint64_t op_id;
667
668   GNUNET_assert (sizeof (struct GNUNET_TESTBED_PeerEventMessage) ==
669                  ntohs (msg->header.size));
670   op_id = GNUNET_ntohll (msg->operation_id);
671   if (NULL == (opc = find_opc (c, op_id)))
672   {
673     LOG_DEBUG ("Operation not found\n");
674     return GNUNET_YES;
675   }
676   if (OP_FORWARDED == opc->type)
677   {
678     handle_forwarded_operation_msg (c, opc,
679                                     (const struct GNUNET_MessageHeader *) msg);
680     return GNUNET_YES;
681   }
682   GNUNET_assert ((OP_PEER_START == opc->type) || (OP_PEER_STOP == opc->type));
683   data = opc->data;
684   GNUNET_assert (NULL != data);
685   peer = data->peer;
686   GNUNET_assert (NULL != peer);
687   event.type = (enum GNUNET_TESTBED_EventType) ntohl (msg->event_type);
688   switch (event.type)
689   {
690   case GNUNET_TESTBED_ET_PEER_START:
691     peer->state = PS_STARTED;
692     event.details.peer_start.host = peer->host;
693     event.details.peer_start.peer = peer;
694     break;
695   case GNUNET_TESTBED_ET_PEER_STOP:
696     peer->state = PS_STOPPED;
697     event.details.peer_stop.peer = peer;
698     break;
699   default:
700     GNUNET_assert (0);          /* We should never reach this state */
701   }
702   pcc = data->pcc;
703   pcc_cls = data->pcc_cls;
704   GNUNET_free (data);
705   GNUNET_CONTAINER_DLL_remove (opc->c->ocq_head, opc->c->ocq_tail, opc);
706   opc->state = OPC_STATE_FINISHED;
707   if (0 !=
708       ((GNUNET_TESTBED_ET_PEER_START | GNUNET_TESTBED_ET_PEER_STOP) &
709        c->event_mask))
710   {
711     if (NULL != c->cc)
712       c->cc (c->cc_cls, &event);
713   }
714   if (NULL != pcc)
715     pcc (pcc_cls, NULL);
716   return GNUNET_YES;
717 }
718
719
720 /**
721  * Handler for GNUNET_MESSAGE_TYPE_TESTBED_PEERCONEVENT message from
722  * controller (testbed service)
723  *
724  * @param c the controller handler
725  * @param msg message received
726  * @return GNUNET_YES if we can continue receiving from service; GNUNET_NO if
727  *           not
728  */
729 static int
730 handle_peer_conevent (struct GNUNET_TESTBED_Controller *c,
731                       const struct GNUNET_TESTBED_ConnectionEventMessage *msg)
732 {
733   struct OperationContext *opc;
734   struct OverlayConnectData *data;
735   GNUNET_TESTBED_OperationCompletionCallback cb;
736   void *cb_cls;
737   struct GNUNET_TESTBED_EventInformation event;
738   uint64_t op_id;
739
740   op_id = GNUNET_ntohll (msg->operation_id);
741   if (NULL == (opc = find_opc (c, op_id)))
742   {
743     LOG_DEBUG ("Operation not found\n");
744     return GNUNET_YES;
745   }
746   if (OP_FORWARDED == opc->type)
747   {
748     handle_forwarded_operation_msg (c, opc,
749                                     (const struct GNUNET_MessageHeader *) msg);
750     return GNUNET_YES;
751   }
752   GNUNET_assert (OP_OVERLAY_CONNECT == opc->type);
753   data = opc->data;
754   GNUNET_assert (NULL != data);
755   GNUNET_assert ((ntohl (msg->peer1) == data->p1->unique_id) &&
756                  (ntohl (msg->peer2) == data->p2->unique_id));
757   event.type = (enum GNUNET_TESTBED_EventType) ntohl (msg->event_type);
758   switch (event.type)
759   {
760   case GNUNET_TESTBED_ET_CONNECT:
761     event.details.peer_connect.peer1 = data->p1;
762     event.details.peer_connect.peer2 = data->p2;
763     break;
764   case GNUNET_TESTBED_ET_DISCONNECT:
765     GNUNET_assert (0);          /* FIXME: implement */
766     break;
767   default:
768     GNUNET_assert (0);          /* Should never reach here */
769     break;
770   }
771   cb = data->cb;
772   cb_cls = data->cb_cls;
773   GNUNET_CONTAINER_DLL_remove (opc->c->ocq_head, opc->c->ocq_tail, opc);
774   opc->state = OPC_STATE_FINISHED;
775   if (0 !=
776       ((GNUNET_TESTBED_ET_CONNECT | GNUNET_TESTBED_ET_DISCONNECT) &
777        c->event_mask))
778   {
779     if (NULL != c->cc)
780       c->cc (c->cc_cls, &event);
781   }
782   if (NULL != cb)
783     cb (cb_cls, opc->op, NULL);
784   return GNUNET_YES;
785 }
786
787
788 /**
789  * Handler for GNUNET_MESSAGE_TYPE_TESTBED_PEERCONFIG message from
790  * controller (testbed service)
791  *
792  * @param c the controller handler
793  * @param msg message received
794  * @return GNUNET_YES if we can continue receiving from service; GNUNET_NO if
795  *           not
796  */
797 static int
798 handle_peer_config (struct GNUNET_TESTBED_Controller *c,
799                     const struct
800                     GNUNET_TESTBED_PeerConfigurationInformationMessage *msg)
801 {
802   struct OperationContext *opc;
803   struct GNUNET_TESTBED_Peer *peer;
804   struct PeerInfoData *data;
805   struct GNUNET_TESTBED_PeerInformation *pinfo;
806   GNUNET_TESTBED_PeerInfoCallback cb;
807   void *cb_cls;
808   uint64_t op_id;
809
810   op_id = GNUNET_ntohll (msg->operation_id);
811   if (NULL == (opc = find_opc (c, op_id)))
812   {
813     LOG_DEBUG ("Operation not found\n");
814     return GNUNET_YES;
815   }
816   if (OP_FORWARDED == opc->type)
817   {
818     handle_forwarded_operation_msg (c, opc,
819                                     (const struct GNUNET_MessageHeader *) msg);
820     return GNUNET_YES;
821   }
822   data = opc->data;
823   GNUNET_assert (NULL != data);
824   peer = data->peer;
825   GNUNET_assert (NULL != peer);
826   GNUNET_assert (ntohl (msg->peer_id) == peer->unique_id);
827   pinfo = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_PeerInformation));
828   pinfo->pit = data->pit;
829   cb = data->cb;
830   cb_cls = data->cb_cls;
831   GNUNET_free (data);
832   opc->data = NULL;
833   switch (pinfo->pit)
834   {
835   case GNUNET_TESTBED_PIT_IDENTITY:
836     pinfo->result.id = GNUNET_malloc (sizeof (struct GNUNET_PeerIdentity));
837     (void) memcpy (pinfo->result.id, &msg->peer_identity,
838                    sizeof (struct GNUNET_PeerIdentity));
839     break;
840   case GNUNET_TESTBED_PIT_CONFIGURATION:
841     pinfo->result.cfg =        /* Freed in oprelease_peer_getinfo */
842         GNUNET_TESTBED_extract_config_ (&msg->header);
843     break;
844   case GNUNET_TESTBED_PIT_GENERIC:
845     GNUNET_assert (0);          /* never reach here */
846     break;
847   }
848   opc->data = pinfo;
849   GNUNET_CONTAINER_DLL_remove (opc->c->ocq_head, opc->c->ocq_tail, opc);
850   opc->state = OPC_STATE_FINISHED;
851   if (NULL != cb)
852     cb (cb_cls, opc->op, pinfo, NULL);
853   return GNUNET_YES;
854 }
855
856
857 /**
858  * Handler for GNUNET_MESSAGE_TYPE_TESTBED_OPERATIONFAILEVENT message from
859  * controller (testbed service)
860  *
861  * @param c the controller handler
862  * @param msg message received
863  * @return GNUNET_YES if we can continue receiving from service; GNUNET_NO if
864  *           not
865  */
866 static int
867 handle_op_fail_event (struct GNUNET_TESTBED_Controller *c,
868                       const struct GNUNET_TESTBED_OperationFailureEventMessage
869                       *msg)
870 {
871   struct OperationContext *opc;
872   const char *emsg;
873   uint64_t op_id;
874   struct GNUNET_TESTBED_EventInformation event;
875
876   op_id = GNUNET_ntohll (msg->operation_id);
877   if (NULL == (opc = find_opc (c, op_id)))
878   {
879     LOG_DEBUG ("Operation not found\n");
880     return GNUNET_YES;
881   }
882   if (OP_FORWARDED == opc->type)
883   {
884     handle_forwarded_operation_msg (c, opc,
885                                     (const struct GNUNET_MessageHeader *) msg);
886     return GNUNET_YES;
887   }
888   GNUNET_CONTAINER_DLL_remove (opc->c->ocq_head, opc->c->ocq_tail, opc);
889   opc->state = OPC_STATE_FINISHED;
890   emsg = GNUNET_TESTBED_parse_error_string_ (msg);
891   if (NULL == emsg)
892     emsg = "Unknown error";
893   if (OP_PEER_INFO == opc->type)
894   {
895     struct PeerInfoData *data;
896     data = opc->data;
897     if (NULL != data->cb)
898       data->cb (data->cb_cls, opc->op, NULL, emsg);
899     GNUNET_free (data);
900     return GNUNET_YES;  /* We do not call controller callback for peer info */
901   }
902   if ((0 != (GNUNET_TESTBED_ET_OPERATION_FINISHED & c->event_mask)) &&
903       (NULL != c->cc))
904   {
905     event.type = GNUNET_TESTBED_ET_OPERATION_FINISHED;
906     event.details.operation_finished.operation = opc->op;
907     event.details.operation_finished.op_cls = opc->op_cls;
908     event.details.operation_finished.emsg = emsg;
909     event.details.operation_finished.generic = NULL;
910     c->cc (c->cc_cls, &event);
911   }
912   switch (opc->type)
913   {
914   case OP_PEER_CREATE:
915     {
916       struct PeerCreateData *data;      
917       data = opc->data;
918       GNUNET_free (data->peer);
919       if (NULL != data->cb)
920         data->cb (data->cls, NULL, emsg);
921       GNUNET_free (data);      
922     }
923     break;
924   case OP_PEER_START:
925   case OP_PEER_STOP:
926     {
927       struct PeerEventData *data;
928       data = opc->data;
929       if (NULL != data->pcc)
930         data->pcc (data->pcc_cls, emsg);
931       GNUNET_free (data);
932     }
933     break;
934   case OP_PEER_DESTROY:
935     break;
936   case OP_PEER_INFO:
937     GNUNET_assert (0);
938   case OP_OVERLAY_CONNECT:
939     {
940       struct OverlayConnectData *data;
941       data = opc->data;
942       if (NULL != data->cb)
943         data->cb (data->cb_cls, opc->op, emsg);
944     }
945     break;
946   case OP_FORWARDED:
947     GNUNET_assert (0);
948   case OP_LINK_CONTROLLERS:     /* No secondary callback */
949     break;
950   default:
951     GNUNET_break (0);
952   }  
953   return GNUNET_YES;
954 }
955
956
957 /**
958  * Function to build GET_SLAVE_CONFIG message
959  *
960  * @param op_id the id this message should contain in its operation id field
961  * @param slave_id the id this message should contain in its slave id field
962  * @return newly allocated SlaveGetConfigurationMessage
963  */
964 static struct GNUNET_TESTBED_SlaveGetConfigurationMessage *
965 GNUNET_TESTBED_generate_slavegetconfig_msg_ (uint64_t op_id, uint32_t slave_id)
966 {
967   struct GNUNET_TESTBED_SlaveGetConfigurationMessage *msg;
968   uint16_t msize;
969   
970   msize = sizeof (struct GNUNET_TESTBED_SlaveGetConfigurationMessage);
971   msg = GNUNET_malloc (msize);
972   msg->header.size = htons (msize);
973   msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_GETSLAVECONFIG);
974   msg->operation_id = GNUNET_htonll (op_id);
975   msg->slave_id = htonl (slave_id);
976   return msg;
977 }
978
979
980 /**
981  * Handler for GNUNET_MESSAGE_TYPE_TESTBED_SLAVECONFIG message from controller
982  * (testbed service)
983  *
984  * @param c the controller handler
985  * @param msg message received
986  * @return GNUNET_YES if we can continue receiving from service; GNUNET_NO if
987  *           not
988  */
989 static int
990 handle_slave_config (struct GNUNET_TESTBED_Controller *c,
991                      const struct GNUNET_TESTBED_SlaveConfiguration * msg)
992 {
993   struct OperationContext *opc;
994   uint64_t op_id;
995   struct GNUNET_TESTBED_EventInformation event;  
996
997   op_id = GNUNET_ntohll (msg->operation_id);
998   if (NULL == (opc = find_opc (c, op_id)))
999   {
1000     LOG_DEBUG ("Operation not found\n");
1001     return GNUNET_YES;
1002   }
1003   if (OP_GET_SLAVE_CONFIG != opc->type)
1004   {
1005     GNUNET_break (0);
1006     return GNUNET_YES;
1007   }
1008   GNUNET_free (opc->data);
1009   opc->data = NULL;
1010   opc->state = OPC_STATE_FINISHED;
1011   GNUNET_CONTAINER_DLL_remove (opc->c->ocq_head, opc->c->ocq_tail, opc);
1012   if ((0 != (GNUNET_TESTBED_ET_OPERATION_FINISHED & c->event_mask)) &&
1013       (NULL != c->cc))
1014   {
1015     opc->data = GNUNET_TESTBED_extract_config_ (&msg->header);
1016     event.type = GNUNET_TESTBED_ET_OPERATION_FINISHED;   
1017     event.details.operation_finished.generic = opc->data;
1018     event.details.operation_finished.operation = opc->op;
1019     event.details.operation_finished.op_cls = opc->op_cls;
1020     event.details.operation_finished.emsg = NULL;
1021     c->cc (c->cc_cls, &event);
1022   }
1023   return GNUNET_YES;
1024 }
1025
1026
1027 /**
1028  * Handler for messages from controller (testbed service)
1029  *
1030  * @param cls the controller handler
1031  * @param msg message received, NULL on timeout or fatal error
1032  */
1033 static void
1034 message_handler (void *cls, const struct GNUNET_MessageHeader *msg)
1035 {
1036   struct GNUNET_TESTBED_Controller *c = cls;
1037   int status;
1038   uint16_t msize;
1039
1040   c->in_receive = GNUNET_NO;
1041   /* FIXME: Add checks for message integrity */
1042   if (NULL == msg)
1043   {
1044     LOG_DEBUG ("Receive timed out or connection to service dropped\n");
1045     return;
1046   }
1047   status = GNUNET_OK;
1048   msize = ntohs (msg->size);
1049   switch (ntohs (msg->type))
1050   {
1051   case GNUNET_MESSAGE_TYPE_TESTBED_ADDHOSTCONFIRM:
1052     GNUNET_assert (msize >=
1053                    sizeof (struct GNUNET_TESTBED_HostConfirmedMessage));
1054     status =
1055         handle_addhostconfirm (c,
1056                                (const struct GNUNET_TESTBED_HostConfirmedMessage
1057                                 *) msg);
1058     break;
1059   case GNUNET_MESSAGE_TYPE_TESTBED_GENERICOPSUCCESS:
1060     GNUNET_assert (msize ==
1061                    sizeof (struct
1062                            GNUNET_TESTBED_GenericOperationSuccessEventMessage));
1063     status =
1064         handle_opsuccess (c,
1065                           (const struct
1066                            GNUNET_TESTBED_GenericOperationSuccessEventMessage *)
1067                           msg);
1068     break;
1069   case GNUNET_MESSAGE_TYPE_TESTBED_PEERCREATESUCCESS:
1070     GNUNET_assert (msize ==
1071                    sizeof (struct
1072                            GNUNET_TESTBED_PeerCreateSuccessEventMessage));
1073     status =
1074         handle_peer_create_success (c,
1075                                     (const struct
1076                                      GNUNET_TESTBED_PeerCreateSuccessEventMessage
1077                                      *) msg);
1078     break;
1079   case GNUNET_MESSAGE_TYPE_TESTBED_PEEREVENT:
1080     GNUNET_assert (msize == sizeof (struct GNUNET_TESTBED_PeerEventMessage));
1081     status =
1082         handle_peer_event (c,
1083                            (const struct GNUNET_TESTBED_PeerEventMessage *)
1084                            msg);
1085
1086     break;
1087   case GNUNET_MESSAGE_TYPE_TESTBED_PEERCONFIG:
1088     GNUNET_assert (msize >=
1089                    sizeof (struct
1090                            GNUNET_TESTBED_PeerConfigurationInformationMessage));
1091     status =
1092         handle_peer_config (c,
1093                             (const struct
1094                              GNUNET_TESTBED_PeerConfigurationInformationMessage
1095                              *) msg);
1096     break;
1097   case GNUNET_MESSAGE_TYPE_TESTBED_PEERCONEVENT:
1098     GNUNET_assert (msize ==
1099                    sizeof (struct GNUNET_TESTBED_ConnectionEventMessage));
1100     status =
1101         handle_peer_conevent (c,
1102                               (const struct
1103                                GNUNET_TESTBED_ConnectionEventMessage *) msg);
1104     break;
1105   case GNUNET_MESSAGE_TYPE_TESTBED_OPERATIONFAILEVENT:
1106     GNUNET_assert (msize >=
1107                    sizeof (struct GNUNET_TESTBED_OperationFailureEventMessage));
1108     status =
1109         handle_op_fail_event (c,
1110                               (const struct
1111                                GNUNET_TESTBED_OperationFailureEventMessage *)
1112                               msg);
1113     break;
1114   case GNUNET_MESSAGE_TYPE_TESTBED_SLAVECONFIG:
1115     GNUNET_assert (msize >
1116                    sizeof (struct GNUNET_TESTBED_SlaveConfiguration));
1117     status = 
1118         handle_slave_config (c, (const struct 
1119                                  GNUNET_TESTBED_SlaveConfiguration *) msg);
1120     break;
1121   default:
1122     GNUNET_assert (0);
1123   }
1124   if ((GNUNET_OK == status) && (GNUNET_NO == c->in_receive))
1125   {
1126     c->in_receive = GNUNET_YES;
1127     GNUNET_CLIENT_receive (c->client, &message_handler, c,
1128                            GNUNET_TIME_UNIT_FOREVER_REL);
1129   }
1130 }
1131
1132
1133 /**
1134  * Function called to notify a client about the connection begin ready to queue
1135  * more data.  "buf" will be NULL and "size" zero if the connection was closed
1136  * for writing in the meantime.
1137  *
1138  * @param cls closure
1139  * @param size number of bytes available in buf
1140  * @param buf where the callee should write the message
1141  * @return number of bytes written to buf
1142  */
1143 static size_t
1144 transmit_ready_notify (void *cls, size_t size, void *buf)
1145 {
1146   struct GNUNET_TESTBED_Controller *c = cls;
1147   struct MessageQueue *mq_entry;
1148
1149   c->th = NULL;
1150   mq_entry = c->mq_head;
1151   GNUNET_assert (NULL != mq_entry);
1152   if ((0 == size) && (NULL == buf))     /* Timeout */
1153   {
1154     LOG_DEBUG ("Message sending timed out -- retrying\n");
1155     c->th =
1156         GNUNET_CLIENT_notify_transmit_ready (c->client,
1157                                              ntohs (mq_entry->msg->size),
1158                                              TIMEOUT_REL, GNUNET_YES,
1159                                              &transmit_ready_notify, c);
1160     return 0;
1161   }
1162   GNUNET_assert (ntohs (mq_entry->msg->size) <= size);
1163   size = ntohs (mq_entry->msg->size);
1164   memcpy (buf, mq_entry->msg, size);
1165   LOG_DEBUG ("Message of type: %u and size: %u sent\n",
1166              ntohs (mq_entry->msg->type), size);
1167   GNUNET_free (mq_entry->msg);
1168   GNUNET_CONTAINER_DLL_remove (c->mq_head, c->mq_tail, mq_entry);
1169   GNUNET_free (mq_entry);
1170   mq_entry = c->mq_head;
1171   if (NULL != mq_entry)
1172     c->th =
1173         GNUNET_CLIENT_notify_transmit_ready (c->client,
1174                                              ntohs (mq_entry->msg->size),
1175                                              TIMEOUT_REL, GNUNET_YES,
1176                                              &transmit_ready_notify, c);
1177   if (GNUNET_NO == c->in_receive)
1178   {
1179     c->in_receive = GNUNET_YES;
1180     GNUNET_CLIENT_receive (c->client, &message_handler, c,
1181                            GNUNET_TIME_UNIT_FOREVER_REL);
1182   }
1183   return size;
1184 }
1185
1186
1187 /**
1188  * Queues a message in send queue for sending to the service
1189  *
1190  * @param controller the handle to the controller
1191  * @param msg the message to queue
1192  */
1193 void
1194 GNUNET_TESTBED_queue_message_ (struct GNUNET_TESTBED_Controller *controller,
1195                                struct GNUNET_MessageHeader *msg)
1196 {
1197   struct MessageQueue *mq_entry;
1198   uint16_t type;
1199   uint16_t size;
1200
1201   type = ntohs (msg->type);
1202   size = ntohs (msg->size);
1203   GNUNET_assert ((GNUNET_MESSAGE_TYPE_TESTBED_INIT <= type) &&
1204                  (GNUNET_MESSAGE_TYPE_TESTBED_MAX > type));
1205   mq_entry = GNUNET_malloc (sizeof (struct MessageQueue));
1206   mq_entry->msg = msg;
1207   LOG (GNUNET_ERROR_TYPE_DEBUG,
1208        "Queueing message of type %u, size %u for sending\n", type,
1209        ntohs (msg->size));
1210   GNUNET_CONTAINER_DLL_insert_tail (controller->mq_head, controller->mq_tail,
1211                                     mq_entry);
1212   if (NULL == controller->th)
1213     controller->th =
1214         GNUNET_CLIENT_notify_transmit_ready (controller->client, size,
1215                                              TIMEOUT_REL, GNUNET_YES,
1216                                              &transmit_ready_notify,
1217                                              controller);
1218 }
1219
1220
1221 /**
1222  * Sends the given message as an operation. The given callback is called when a
1223  * reply for the operation is available.  Call
1224  * GNUNET_TESTBED_forward_operation_msg_cancel_() to cleanup the returned
1225  * operation context if the cc hasn't been called
1226  *
1227  * @param controller the controller to which the message has to be sent
1228  * @param operation_id the operation id of the message
1229  * @param msg the message to send
1230  * @param cc the callback to call when reply is available
1231  * @param cc_cls the closure for the above callback
1232  * @return the operation context which can be used to cancel the forwarded
1233  *           operation
1234  */
1235 struct OperationContext *
1236 GNUNET_TESTBED_forward_operation_msg_ (struct GNUNET_TESTBED_Controller
1237                                        *controller, uint64_t operation_id,
1238                                        const struct GNUNET_MessageHeader *msg,
1239                                        GNUNET_CLIENT_MessageHandler cc,
1240                                        void *cc_cls)
1241 {
1242   struct OperationContext *opc;
1243   struct ForwardedOperationData *data;
1244   struct GNUNET_MessageHeader *dup_msg;
1245   uint16_t msize;
1246
1247   data = GNUNET_malloc (sizeof (struct ForwardedOperationData));
1248   data->cc = cc;
1249   data->cc_cls = cc_cls;
1250   opc = GNUNET_malloc (sizeof (struct OperationContext));
1251   opc->c = controller;
1252   opc->type = OP_FORWARDED;
1253   opc->data = data;
1254   opc->id = operation_id;
1255   msize = ntohs (msg->size);
1256   dup_msg = GNUNET_malloc (msize);
1257   (void) memcpy (dup_msg, msg, msize);
1258   GNUNET_TESTBED_queue_message_ (opc->c, dup_msg);
1259   GNUNET_CONTAINER_DLL_insert_tail (controller->ocq_head, controller->ocq_tail,
1260                                     opc);
1261   return opc;
1262 }
1263
1264
1265 /**
1266  * Function to cancel an operation created by simply forwarding an operation
1267  * message.
1268  *
1269  * @param opc the operation context from GNUNET_TESTBED_forward_operation_msg_()
1270  */
1271 void
1272 GNUNET_TESTBED_forward_operation_msg_cancel_ (struct OperationContext *opc)
1273 {
1274   GNUNET_CONTAINER_DLL_remove (opc->c->ocq_head, opc->c->ocq_tail, opc);
1275   GNUNET_free (opc->data);
1276   GNUNET_free (opc);
1277 }
1278
1279
1280 /**
1281  * Functions with this signature are called whenever a
1282  * complete message is received by the tokenizer.
1283  *
1284  * Do not call GNUNET_SERVER_mst_destroy in callback
1285  *
1286  * @param cls closure
1287  * @param client identification of the client
1288  * @param message the actual message
1289  *
1290  * @return GNUNET_OK on success, GNUNET_SYSERR to stop further processing
1291  */
1292 static int
1293 helper_mst (void *cls, void *client, const struct GNUNET_MessageHeader *message)
1294 {
1295   struct GNUNET_TESTBED_ControllerProc *cp = cls;
1296   const struct GNUNET_TESTBED_HelperReply *msg;
1297   const char *hostname;
1298   char *config;
1299   uLongf config_size;
1300   uLongf xconfig_size;
1301
1302   msg = (const struct GNUNET_TESTBED_HelperReply *) message;
1303   GNUNET_assert (sizeof (struct GNUNET_TESTBED_HelperReply) <
1304                  ntohs (msg->header.size));
1305   GNUNET_assert (GNUNET_MESSAGE_TYPE_TESTBED_HELPER_REPLY ==
1306                  ntohs (msg->header.type));
1307   config_size = (uLongf) ntohs (msg->config_size);
1308   xconfig_size =
1309       (uLongf) (ntohs (msg->header.size) -
1310                 sizeof (struct GNUNET_TESTBED_HelperReply));
1311   config = GNUNET_malloc (config_size);
1312   GNUNET_assert (Z_OK ==
1313                  uncompress ((Bytef *) config, &config_size,
1314                              (const Bytef *) &msg[1], xconfig_size));
1315   GNUNET_assert (NULL == cp->cfg);
1316   cp->cfg = GNUNET_CONFIGURATION_create ();
1317   GNUNET_assert (GNUNET_CONFIGURATION_deserialize
1318                  (cp->cfg, config, config_size, GNUNET_NO));
1319   GNUNET_free (config);
1320   if ((NULL == cp->host) ||
1321       (NULL == (hostname = GNUNET_TESTBED_host_get_hostname (cp->host))))
1322     hostname = "localhost";
1323   /* Change the hostname so that we can connect to it */
1324   GNUNET_CONFIGURATION_set_value_string (cp->cfg, "testbed", "hostname",
1325                                          hostname);
1326   cp->cb (cp->cls, cp->cfg, GNUNET_OK);
1327   return GNUNET_OK;
1328 }
1329
1330
1331 /**
1332  * Continuation function from GNUNET_HELPER_send()
1333  *
1334  * @param cls closure
1335  * @param result GNUNET_OK on success,
1336  *               GNUNET_NO if helper process died
1337  *               GNUNET_SYSERR during GNUNET_HELPER_stop
1338  */
1339 static void
1340 clear_msg (void *cls, int result)
1341 {
1342   struct GNUNET_TESTBED_ControllerProc *cp = cls;
1343
1344   GNUNET_assert (NULL != cp->shandle);
1345   cp->shandle = NULL;
1346   GNUNET_free (cp->msg);
1347 }
1348
1349
1350 /**
1351  * Callback that will be called when the helper process dies. This is not called
1352  * when the helper process is stoped using GNUNET_HELPER_stop()
1353  *
1354  * @param cls the closure from GNUNET_HELPER_start()
1355  */
1356 static void
1357 helper_exp_cb (void *cls)
1358 {
1359   struct GNUNET_TESTBED_ControllerProc *cp = cls;
1360   GNUNET_TESTBED_ControllerStatusCallback cb;
1361   void *cb_cls;
1362
1363   cb = cp->cb;
1364   cb_cls = cp->cls;
1365   cp->helper = NULL;
1366   GNUNET_TESTBED_controller_stop (cp);
1367   if (NULL != cb)
1368     cb (cb_cls, NULL, GNUNET_SYSERR);
1369 }
1370
1371
1372 /**
1373  * Function to call to start a link-controllers type operation once all queues
1374  * the operation is part of declare that the operation can be activated.
1375  *
1376  * @param cls the closure from GNUNET_TESTBED_operation_create_()
1377  */
1378 static void
1379 opstart_link_controllers (void *cls)
1380 {
1381   struct OperationContext *opc = cls;
1382   struct ControllerLinkData *data;
1383   struct GNUNET_TESTBED_ControllerLinkMessage *msg;
1384
1385   GNUNET_assert (NULL != opc->data);
1386   data = opc->data;
1387   msg = data->msg;
1388   data->msg = NULL;
1389   opc->state = OPC_STATE_STARTED;
1390   GNUNET_CONTAINER_DLL_insert_tail (opc->c->ocq_head, opc->c->ocq_tail, opc);
1391   GNUNET_TESTBED_queue_message_ (opc->c, &msg->header);
1392 }
1393
1394
1395 /**
1396  * Callback which will be called when link-controllers type operation is released
1397  *
1398  * @param cls the closure from GNUNET_TESTBED_operation_create_()
1399  */
1400 static void
1401 oprelease_link_controllers (void *cls)
1402 {
1403   struct OperationContext *opc = cls;
1404   struct ControllerLinkData *data;
1405
1406   data = opc->data;
1407   switch (opc->state)
1408   {
1409   case OPC_STATE_INIT:
1410     GNUNET_free (data->msg);
1411     break;
1412   case OPC_STATE_STARTED:
1413     GNUNET_CONTAINER_DLL_remove (opc->c->ocq_head, opc->c->ocq_tail, opc);
1414     break;
1415   case OPC_STATE_FINISHED:
1416     break;
1417   }
1418   GNUNET_free_non_null (data);
1419   GNUNET_free (opc);
1420 }
1421
1422
1423 /**
1424  * Function to be called when get slave config operation is ready
1425  *
1426  * @param cls the OperationContext of type OP_GET_SLAVE_CONFIG
1427  */
1428 static void
1429 opstart_get_slave_config (void *cls)
1430 {
1431   struct OperationContext *opc = cls;
1432   struct GetSlaveConfigData *data;
1433   struct GNUNET_TESTBED_SlaveGetConfigurationMessage *msg;
1434
1435   data = opc->data;
1436   msg = GNUNET_TESTBED_generate_slavegetconfig_msg_ (opc->id, data->slave_id);
1437   GNUNET_CONTAINER_DLL_insert_tail (opc->c->ocq_head, opc->c->ocq_tail, opc);
1438   GNUNET_TESTBED_queue_message_ (opc->c, &msg->header);
1439   opc->state = OPC_STATE_STARTED;
1440 }
1441
1442
1443 /**
1444  * Function to be called when get slave config operation is cancelled or finished
1445  *
1446  * @param cls the OperationContext of type OP_GET_SLAVE_CONFIG
1447  */
1448 static void
1449 oprelease_get_slave_config (void *cls)
1450 {
1451   struct OperationContext *opc = cls;
1452
1453   switch (opc->state)
1454   {
1455   case OPC_STATE_INIT:
1456     GNUNET_free (opc->data);
1457     break;
1458   case OPC_STATE_STARTED:
1459     GNUNET_free (opc->data);
1460     GNUNET_CONTAINER_DLL_remove (opc->c->ocq_head, opc->c->ocq_tail, opc);
1461     break;
1462   case OPC_STATE_FINISHED:
1463     if (NULL != opc->data)
1464       GNUNET_CONFIGURATION_destroy (opc->data);
1465     break;
1466   }
1467   GNUNET_free (opc);
1468 }
1469
1470
1471 /**
1472  * Initializes the operation queue for parallel overlay connects
1473  *
1474  * @param c the controller handle
1475  * @param npoc the number of parallel overlay connects - the queue size
1476  */
1477 static void
1478 GNUNET_TESTBED_set_num_parallel_overlay_connects_ (struct
1479                                                    GNUNET_TESTBED_Controller *c,
1480                                                    unsigned int npoc)
1481 {
1482   fprintf (stderr, "%d", npoc);
1483   GNUNET_free_non_null (c->tslots);
1484   c->tslots_filled = 0;  
1485   c->num_parallel_connects = npoc;
1486   c->tslots = GNUNET_malloc (npoc * sizeof (struct TimeSlot));
1487   GNUNET_TESTBED_operation_queue_reset_max_active_ 
1488       (c->opq_parallel_overlay_connect_operations, npoc);
1489 }
1490
1491
1492 /**
1493  * Function to copy NULL terminated list of arguments
1494  *
1495  * @param argv the NULL terminated list of arguments. Cannot be NULL.
1496  * @return the copied NULL terminated arguments
1497  */
1498 static char **
1499 copy_argv (const char *const *argv)
1500 {
1501   char **argv_dup;
1502   unsigned int argp;
1503
1504   GNUNET_assert (NULL != argv);
1505   for (argp = 0; NULL != argv[argp]; argp++);
1506   argv_dup = GNUNET_malloc (sizeof (char *) * (argp + 1));
1507   for (argp = 0; NULL != argv[argp]; argp++)
1508     argv_dup[argp] = strdup (argv[argp]);
1509   return argv_dup;
1510 }
1511
1512
1513 /**
1514  * Frees the given NULL terminated arguments
1515  *
1516  * @param argv the NULL terminated list of arguments
1517  */
1518 static void
1519 free_argv (char **argv)
1520 {
1521   unsigned int argp;
1522   
1523   for (argp = 0; NULL != argv[argp]; argp++)
1524     GNUNET_free (argv[argp]);
1525   GNUNET_free (argv);
1526 }
1527
1528
1529 /**
1530  * Starts a controller process at the given host
1531  *
1532  * @param trusted_ip the ip address of the controller which will be set as TRUSTED
1533  *          HOST(all connections form this ip are permitted by the testbed) when
1534  *          starting testbed controller at host. This can either be a single ip
1535  *          address or a network address in CIDR notation.
1536  * @param host the host where the controller has to be started; NULL for
1537  *          localhost
1538  * @param cfg template configuration to use for the remote controller; the
1539  *          remote controller will be started with a slightly modified
1540  *          configuration (port numbers, unix domain sockets and service home
1541  *          values are changed as per TESTING library on the remote host)
1542  * @param cb function called when the controller is successfully started or
1543  *          dies unexpectedly; GNUNET_TESTBED_controller_stop shouldn't be
1544  *          called if cb is called with GNUNET_SYSERR as status. Will never be
1545  *          called in the same task as 'GNUNET_TESTBED_controller_start'
1546  *          (synchronous errors will be signalled by returning NULL). This
1547  *          parameter cannot be NULL.
1548  * @param cls closure for above callbacks
1549  * @return the controller process handle, NULL on errors
1550  */
1551 struct GNUNET_TESTBED_ControllerProc *
1552 GNUNET_TESTBED_controller_start (const char *trusted_ip,
1553                                  struct GNUNET_TESTBED_Host *host,
1554                                  const struct GNUNET_CONFIGURATION_Handle *cfg,
1555                                  GNUNET_TESTBED_ControllerStatusCallback cb,
1556                                  void *cls)
1557 {
1558   struct GNUNET_TESTBED_ControllerProc *cp;
1559   struct GNUNET_TESTBED_HelperInit *msg;
1560   const char *hostname;
1561   static char *const binary_argv[] = {
1562     HELPER_TESTBED_BINARY, NULL
1563   };  
1564
1565   hostname = NULL;
1566   cp = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_ControllerProc));
1567   if ((NULL == host) || (0 == GNUNET_TESTBED_host_get_id_ (host)))
1568   {
1569     cp->helper =
1570         GNUNET_HELPER_start (GNUNET_YES, HELPER_TESTBED_BINARY, binary_argv,
1571                              &helper_mst, &helper_exp_cb, cp);
1572   }
1573   else
1574   {
1575     char *helper_binary_path;
1576 #define NUM_REMOTE_ARGS 12
1577     const char *remote_args[NUM_REMOTE_ARGS];
1578     const char *username;
1579     char *port;
1580     char *dst;
1581     unsigned int argp;
1582
1583     username = GNUNET_TESTBED_host_get_username_ (host);
1584     hostname = GNUNET_TESTBED_host_get_hostname (host);
1585     GNUNET_asprintf (&port, "%u", GNUNET_TESTBED_host_get_ssh_port_ (host));
1586     if (NULL == username)
1587       GNUNET_asprintf (&dst, "%s", hostname);
1588     else
1589       GNUNET_asprintf (&dst, "%s@%s", username, hostname);
1590     LOG_DEBUG ("Starting SSH to destination %s\n", dst);
1591     argp = 0;
1592     remote_args[argp++] = "ssh";
1593     remote_args[argp++] = "-p";
1594     remote_args[argp++] = port;
1595     remote_args[argp++] = "-o";
1596     remote_args[argp++] = "BatchMode=yes";
1597     remote_args[argp++] = "-o";
1598     remote_args[argp++] = "NoHostAuthenticationForLocalhost=yes";
1599     remote_args[argp++] = dst;
1600     if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, "testbed",
1601                                                             "HELPER_BINARY_PATH",
1602                                                             &helper_binary_path))
1603       helper_binary_path = GNUNET_OS_get_libexec_binary_path (HELPER_TESTBED_BINARY);
1604     remote_args[argp++] = "sh";
1605     remote_args[argp++] = "-lc";
1606     remote_args[argp++] = helper_binary_path;
1607     remote_args[argp++] = NULL;
1608     GNUNET_assert (NUM_REMOTE_ARGS == argp);
1609     cp->helper_argv = copy_argv (remote_args);
1610     GNUNET_free (port);
1611     GNUNET_free (dst);
1612     cp->helper =
1613         GNUNET_HELPER_start (GNUNET_NO, "ssh", cp->helper_argv, &helper_mst,
1614                              &helper_exp_cb, cp);
1615     GNUNET_free (helper_binary_path);
1616   }
1617   if (NULL == cp->helper)
1618   {
1619     if (NULL != cp->helper_argv)
1620       free_argv (cp->helper_argv);
1621     GNUNET_free (cp);
1622     return NULL;
1623   }
1624   cp->host = host;
1625   cp->cb = cb;
1626   cp->cls = cls;
1627   msg = GNUNET_TESTBED_create_helper_init_msg_ (trusted_ip, hostname, cfg);
1628   cp->msg = &msg->header;
1629   cp->shandle =
1630       GNUNET_HELPER_send (cp->helper, &msg->header, GNUNET_NO, &clear_msg, cp);
1631   if (NULL == cp->shandle)
1632   {
1633     GNUNET_free (msg);
1634     GNUNET_TESTBED_controller_stop (cp);
1635     return NULL;
1636   }
1637   return cp;
1638 }
1639
1640
1641 /**
1642  * Stop the controller process (also will terminate all peers and controllers
1643  * dependent on this controller).  This function blocks until the testbed has
1644  * been fully terminated (!). The controller status cb from
1645  * GNUNET_TESTBED_controller_start() will not be called.
1646  *
1647  * @param cproc the controller process handle
1648  */
1649 void
1650 GNUNET_TESTBED_controller_stop (struct GNUNET_TESTBED_ControllerProc *cproc)
1651 {
1652   if (NULL != cproc->shandle)
1653     GNUNET_HELPER_send_cancel (cproc->shandle);
1654   if (NULL != cproc->helper)
1655     GNUNET_HELPER_stop (cproc->helper);
1656   if (NULL != cproc->cfg)
1657     GNUNET_CONFIGURATION_destroy (cproc->cfg);
1658   if (NULL != cproc->helper_argv)
1659     free_argv (cproc->helper_argv);
1660   GNUNET_free (cproc);
1661 }
1662
1663
1664 /**
1665  * Start a controller process using the given configuration at the
1666  * given host.
1667  *
1668  * @param cfg configuration to use
1669  * @param host host to run the controller on; This should be the same host if
1670  *          the controller was previously started with
1671  *          GNUNET_TESTBED_controller_start; NULL for localhost
1672  * @param event_mask bit mask with set of events to call 'cc' for;
1673  *                   or-ed values of "1LL" shifted by the
1674  *                   respective 'enum GNUNET_TESTBED_EventType'
1675  *                   (i.e.  "(1LL << GNUNET_TESTBED_ET_CONNECT) | ...")
1676  * @param cc controller callback to invoke on events
1677  * @param cc_cls closure for cc
1678  * @return handle to the controller
1679  */
1680 struct GNUNET_TESTBED_Controller *
1681 GNUNET_TESTBED_controller_connect (const struct GNUNET_CONFIGURATION_Handle
1682                                    *cfg, struct GNUNET_TESTBED_Host *host,
1683                                    uint64_t event_mask,
1684                                    GNUNET_TESTBED_ControllerCallback cc,
1685                                    void *cc_cls)
1686 {
1687   struct GNUNET_TESTBED_Controller *controller;
1688   struct GNUNET_TESTBED_InitMessage *msg;
1689   const char *controller_hostname;
1690   unsigned long long max_parallel_operations;
1691   unsigned long long max_parallel_service_connections;
1692   unsigned long long max_parallel_topology_config_operations;
1693
1694   if (GNUNET_OK !=
1695       GNUNET_CONFIGURATION_get_value_number (cfg, "testbed",
1696                                              "MAX_PARALLEL_OPERATIONS",
1697                                              &max_parallel_operations))
1698   {
1699     GNUNET_break (0);
1700     return NULL;
1701   }
1702   if (GNUNET_OK !=
1703       GNUNET_CONFIGURATION_get_value_number (cfg, "testbed",
1704                                              "MAX_PARALLEL_SERVICE_CONNECTIONS",
1705                                              &max_parallel_service_connections))
1706   {
1707     GNUNET_break (0);
1708     return NULL;
1709   }
1710   if (GNUNET_OK !=
1711       GNUNET_CONFIGURATION_get_value_number (cfg, "testbed",
1712                                              "MAX_PARALLEL_TOPOLOGY_CONFIG_OPERATIONS",
1713                                              &max_parallel_topology_config_operations))
1714   {
1715     GNUNET_break (0);
1716     return NULL;
1717   }
1718   controller = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_Controller));
1719   controller->cc = cc;
1720   controller->cc_cls = cc_cls;
1721   controller->event_mask = event_mask;
1722   controller->cfg = GNUNET_CONFIGURATION_dup (cfg);
1723   controller->client = GNUNET_CLIENT_connect ("testbed", controller->cfg);
1724   if (NULL == controller->client)
1725   {
1726     GNUNET_TESTBED_controller_disconnect (controller);
1727     return NULL;
1728   }
1729   if (NULL == host)
1730   {
1731     host = GNUNET_TESTBED_host_create_by_id_ (0);
1732     if (NULL == host)           /* If the above host create fails */
1733     {
1734       LOG (GNUNET_ERROR_TYPE_WARNING,
1735            "Treating NULL host as localhost. Multiple references to localhost "
1736            "may break when localhost freed before calling disconnect \n");
1737       host = GNUNET_TESTBED_host_lookup_by_id_ (0);
1738     }
1739     else
1740     {
1741       controller->aux_host = GNUNET_YES;
1742     }
1743   }
1744   GNUNET_assert (NULL != host);
1745   GNUNET_TESTBED_mark_host_registered_at_ (host, controller);
1746   controller->host = host;
1747   controller->opq_parallel_operations =
1748       GNUNET_TESTBED_operation_queue_create_ ((unsigned int)
1749                                               max_parallel_operations);
1750   controller->opq_parallel_service_connections =
1751       GNUNET_TESTBED_operation_queue_create_ ((unsigned int)
1752                                               max_parallel_service_connections);
1753   controller->opq_parallel_topology_config_operations=
1754       GNUNET_TESTBED_operation_queue_create_ ((unsigned int)
1755                                               max_parallel_topology_config_operations);
1756   controller->opq_parallel_overlay_connect_operations=
1757       GNUNET_TESTBED_operation_queue_create_ (0);
1758   GNUNET_TESTBED_set_num_parallel_overlay_connects_ (controller, 1);
1759   controller->poc_sd = SD_init (10);
1760   controller_hostname = GNUNET_TESTBED_host_get_hostname (host);
1761   if (NULL == controller_hostname)
1762     controller_hostname = "127.0.0.1";
1763   msg =
1764       GNUNET_malloc (sizeof (struct GNUNET_TESTBED_InitMessage) +
1765                      strlen (controller_hostname) + 1);
1766   msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_INIT);
1767   msg->header.size =
1768       htons (sizeof (struct GNUNET_TESTBED_InitMessage) +
1769              strlen (controller_hostname) + 1);
1770   msg->host_id = htonl (GNUNET_TESTBED_host_get_id_ (host));
1771   msg->event_mask = GNUNET_htonll (controller->event_mask);
1772   strcpy ((char *) &msg[1], controller_hostname);
1773   GNUNET_TESTBED_queue_message_ (controller,
1774                                  (struct GNUNET_MessageHeader *) msg);
1775   return controller;
1776 }
1777
1778
1779 /**
1780  * Configure shared services at a controller.  Using this function,
1781  * you can specify that certain services (such as "resolver")
1782  * should not be run for each peer but instead be shared
1783  * across N peers on the specified host.  This function
1784  * must be called before any peers are created at the host.
1785  *
1786  * @param controller controller to configure
1787  * @param service_name name of the service to share
1788  * @param num_peers number of peers that should share one instance
1789  *        of the specified service (1 for no sharing is the default),
1790  *        use 0 to disable the service
1791  */
1792 void
1793 GNUNET_TESTBED_controller_configure_sharing (struct GNUNET_TESTBED_Controller
1794                                              *controller,
1795                                              const char *service_name,
1796                                              uint32_t num_peers)
1797 {
1798   struct GNUNET_TESTBED_ConfigureSharedServiceMessage *msg;
1799   uint16_t service_name_size;
1800   uint16_t msg_size;
1801
1802   service_name_size = strlen (service_name) + 1;
1803   msg_size =
1804       sizeof (struct GNUNET_TESTBED_ConfigureSharedServiceMessage) +
1805       service_name_size;
1806   msg = GNUNET_malloc (msg_size);
1807   msg->header.size = htons (msg_size);
1808   msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_SERVICESHARE);
1809   msg->host_id = htonl (GNUNET_TESTBED_host_get_id_ (controller->host));
1810   msg->num_peers = htonl (num_peers);
1811   memcpy (&msg[1], service_name, service_name_size);
1812   GNUNET_TESTBED_queue_message_ (controller,
1813                                  (struct GNUNET_MessageHeader *) msg);
1814   GNUNET_break (0);             /* This function is not yet implemented on the
1815                                    testbed service */
1816 }
1817
1818
1819 /**
1820  * disconnects from the controller.
1821  *
1822  * @param controller handle to controller to stop
1823  */
1824 void
1825 GNUNET_TESTBED_controller_disconnect (struct GNUNET_TESTBED_Controller
1826                                       *controller)
1827 {
1828   struct MessageQueue *mq_entry;
1829
1830   if (NULL != controller->th)
1831     GNUNET_CLIENT_notify_transmit_ready_cancel (controller->th);
1832   /* Clear the message queue */
1833   while (NULL != (mq_entry = controller->mq_head))
1834   {
1835     GNUNET_CONTAINER_DLL_remove (controller->mq_head, controller->mq_tail,
1836                                  mq_entry);
1837     GNUNET_free (mq_entry->msg);
1838     GNUNET_free (mq_entry);
1839   }
1840   if (NULL != controller->client)
1841     GNUNET_CLIENT_disconnect (controller->client);
1842   GNUNET_CONFIGURATION_destroy (controller->cfg);
1843   if (GNUNET_YES == controller->aux_host)
1844     GNUNET_TESTBED_host_destroy (controller->host);
1845   GNUNET_TESTBED_operation_queue_destroy_ (controller->opq_parallel_operations);
1846   GNUNET_TESTBED_operation_queue_destroy_
1847       (controller->opq_parallel_service_connections);
1848   GNUNET_TESTBED_operation_queue_destroy_
1849       (controller->opq_parallel_topology_config_operations);
1850   GNUNET_TESTBED_operation_queue_destroy_
1851       (controller->opq_parallel_overlay_connect_operations);
1852   SD_destroy (controller->poc_sd);
1853   GNUNET_free_non_null (controller->tslots);
1854   GNUNET_free (controller);
1855 }
1856
1857
1858 /**
1859  * Register a host with the controller
1860  *
1861  * @param controller the controller handle
1862  * @param host the host to register
1863  * @param cc the completion callback to call to inform the status of
1864  *          registration. After calling this callback the registration handle
1865  *          will be invalid. Cannot be NULL.
1866  * @param cc_cls the closure for the cc
1867  * @return handle to the host registration which can be used to cancel the
1868  *           registration
1869  */
1870 struct GNUNET_TESTBED_HostRegistrationHandle *
1871 GNUNET_TESTBED_register_host (struct GNUNET_TESTBED_Controller *controller,
1872                               struct GNUNET_TESTBED_Host *host,
1873                               GNUNET_TESTBED_HostRegistrationCompletion cc,
1874                               void *cc_cls)
1875 {
1876   struct GNUNET_TESTBED_HostRegistrationHandle *rh;
1877   struct GNUNET_TESTBED_AddHostMessage *msg;
1878   const char *username;
1879   const char *hostname;
1880   uint16_t msg_size;
1881   uint16_t user_name_length;
1882
1883   if (NULL != controller->rh)
1884     return NULL;
1885   hostname = GNUNET_TESTBED_host_get_hostname (host);
1886   if (GNUNET_YES == GNUNET_TESTBED_is_host_registered_ (host, controller))
1887   {
1888     LOG (GNUNET_ERROR_TYPE_WARNING, "Host hostname: %s already registered\n",
1889          (NULL == hostname) ? "localhost" : hostname);
1890     return NULL;
1891   }
1892   rh = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_HostRegistrationHandle));
1893   rh->host = host;
1894   rh->c = controller;
1895   GNUNET_assert (NULL != cc);
1896   rh->cc = cc;
1897   rh->cc_cls = cc_cls;
1898   controller->rh = rh;
1899   username = GNUNET_TESTBED_host_get_username_ (host);
1900   msg_size = (sizeof (struct GNUNET_TESTBED_AddHostMessage));
1901   user_name_length = 0;
1902   if (NULL != username)
1903   {
1904     user_name_length = strlen (username) + 1;
1905     msg_size += user_name_length;
1906   }
1907   /* FIXME: what happens when hostname is NULL? localhost */
1908   GNUNET_assert (NULL != hostname);
1909   msg_size += strlen (hostname) + 1;
1910   msg = GNUNET_malloc (msg_size);
1911   msg->header.size = htons (msg_size);
1912   msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST);
1913   msg->host_id = htonl (GNUNET_TESTBED_host_get_id_ (host));
1914   msg->ssh_port = htons (GNUNET_TESTBED_host_get_ssh_port_ (host));
1915   if (NULL != username)
1916   {
1917     msg->user_name_length = htons (user_name_length - 1);
1918     memcpy (&msg[1], username, user_name_length);
1919   }
1920   else
1921     msg->user_name_length = htons (user_name_length);
1922   strcpy (((void *) &msg[1]) + user_name_length, hostname);
1923   GNUNET_TESTBED_queue_message_ (controller,
1924                                  (struct GNUNET_MessageHeader *) msg);
1925   return rh;
1926 }
1927
1928
1929 /**
1930  * Cancel the pending registration. Note that if the registration message is
1931  * already sent to the service the cancellation has only the effect that the
1932  * registration completion callback for the registration is never called.
1933  *
1934  * @param handle the registration handle to cancel
1935  */
1936 void
1937 GNUNET_TESTBED_cancel_registration (struct GNUNET_TESTBED_HostRegistrationHandle
1938                                     *handle)
1939 {
1940   if (handle != handle->c->rh)
1941   {
1942     GNUNET_break (0);
1943     return;
1944   }
1945   handle->c->rh = NULL;
1946   GNUNET_free (handle);
1947 }
1948
1949
1950 /**
1951  * Same as the GNUNET_TESTBED_controller_link_2, but with ids for delegated host
1952  * and slave host
1953  *
1954  * @param op_cls the operation closure for the event which is generated to
1955  *          signal success or failure of this operation
1956  * @param master handle to the master controller who creates the association
1957  * @param delegated_host_id id of the host to which requests should be delegated
1958  * @param slave_host_id id of the host which is used to run the slave controller
1959  * @param sxcfg serialized and compressed configuration
1960  * @param sxcfg_size the size sxcfg
1961  * @param scfg_size the size of uncompressed serialized configuration
1962  * @param is_subordinate GNUNET_YES if the controller at delegated_host should
1963  *          be started by the slave controller; GNUNET_NO if the slave
1964  *          controller has to connect to the already started delegated
1965  *          controller via TCP/IP
1966  * @return the operation handle
1967  */
1968 struct GNUNET_TESTBED_Operation *
1969 GNUNET_TESTBED_controller_link_2_ (void *op_cls,
1970                                    struct GNUNET_TESTBED_Controller *master,
1971                                    uint32_t delegated_host_id,
1972                                    uint32_t slave_host_id,
1973                                    const char *sxcfg, size_t sxcfg_size,
1974                                    size_t scfg_size, int is_subordinate)
1975 {
1976   struct OperationContext *opc;
1977   struct GNUNET_TESTBED_ControllerLinkMessage *msg;
1978   struct ControllerLinkData *data;
1979   uint16_t msg_size;
1980
1981   msg_size = sxcfg_size + sizeof (struct GNUNET_TESTBED_ControllerLinkMessage);
1982   msg = GNUNET_malloc (msg_size);
1983   msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_LCONTROLLERS);
1984   msg->header.size = htons (msg_size);
1985   msg->delegated_host_id = htonl (delegated_host_id);
1986   msg->slave_host_id = htonl (slave_host_id);
1987   msg->config_size = htons ((uint16_t) scfg_size);
1988   msg->is_subordinate = (GNUNET_YES == is_subordinate) ? 1 : 0;
1989   memcpy (&msg[1], sxcfg, sxcfg_size);
1990   data = GNUNET_malloc (sizeof (struct ControllerLinkData));
1991   data->msg = msg;
1992   opc = GNUNET_malloc (sizeof (struct OperationContext));
1993   opc->c = master;
1994   opc->data = data;
1995   opc->type = OP_LINK_CONTROLLERS;
1996   opc->id = GNUNET_TESTBED_get_next_op_id (opc->c);
1997   opc->state = OPC_STATE_INIT;
1998   opc->op_cls = op_cls;
1999   msg->operation_id = GNUNET_htonll (opc->id);
2000   opc->op =
2001       GNUNET_TESTBED_operation_create_ (opc, &opstart_link_controllers,
2002                                         &oprelease_link_controllers);
2003   GNUNET_TESTBED_operation_queue_insert_ (master->opq_parallel_operations,
2004                                           opc->op);
2005   GNUNET_TESTBED_operation_begin_wait_ (opc->op);
2006   return opc->op;
2007 }
2008
2009
2010 /**
2011  * Same as the GNUNET_TESTBED_controller_link, however expects configuration in
2012  * serialized and compressed
2013  *
2014  * @param op_cls the operation closure for the event which is generated to
2015  *          signal success or failure of this operation
2016  * @param master handle to the master controller who creates the association
2017  * @param delegated_host requests to which host should be delegated; cannot be NULL
2018  * @param slave_host which host is used to run the slave controller; use NULL to
2019  *          make the master controller connect to the delegated host
2020  * @param sxcfg serialized and compressed configuration
2021  * @param sxcfg_size the size sxcfg
2022  * @param scfg_size the size of uncompressed serialized configuration
2023  * @param is_subordinate GNUNET_YES if the controller at delegated_host should
2024  *          be started by the slave controller; GNUNET_NO if the slave
2025  *          controller has to connect to the already started delegated
2026  *          controller via TCP/IP
2027  * @return the operation handle
2028  */
2029 struct GNUNET_TESTBED_Operation *
2030 GNUNET_TESTBED_controller_link_2 (void *op_cls,
2031                                   struct GNUNET_TESTBED_Controller *master,
2032                                   struct GNUNET_TESTBED_Host *delegated_host,
2033                                   struct GNUNET_TESTBED_Host *slave_host,
2034                                   const char *sxcfg, size_t sxcfg_size,
2035                                   size_t scfg_size, int is_subordinate)
2036
2037   uint32_t delegated_host_id;
2038   uint32_t slave_host_id;
2039
2040   GNUNET_assert (GNUNET_YES ==
2041                  GNUNET_TESTBED_is_host_registered_ (delegated_host, master));
2042   delegated_host_id = GNUNET_TESTBED_host_get_id_ (delegated_host);
2043   slave_host_id = 
2044       GNUNET_TESTBED_host_get_id_ ((NULL != slave_host)
2045                                    ? slave_host : master->host);
2046   if ((NULL != slave_host) && (0 != GNUNET_TESTBED_host_get_id_ (slave_host)))
2047     GNUNET_assert (GNUNET_YES ==
2048                    GNUNET_TESTBED_is_host_registered_ (slave_host, master));
2049   
2050   return GNUNET_TESTBED_controller_link_2_ (op_cls,
2051                                             master,
2052                                             delegated_host_id,
2053                                             slave_host_id,
2054                                             sxcfg, sxcfg_size,
2055                                             scfg_size, is_subordinate);
2056 }
2057
2058
2059 /**
2060  * Compresses given configuration using zlib compress
2061  *
2062  * @param config the serialized configuration
2063  * @param size the size of config
2064  * @param xconfig will be set to the compressed configuration (memory is fresly
2065  *          allocated)
2066  * @return the size of the xconfig
2067  */
2068 size_t
2069 GNUNET_TESTBED_compress_config_ (const char *config, size_t size,
2070                                  char **xconfig)
2071 {
2072   size_t xsize;
2073
2074   xsize = compressBound ((uLong) size);
2075   *xconfig = GNUNET_malloc (xsize);
2076   GNUNET_assert (Z_OK ==
2077                  compress2 ((Bytef *) * xconfig, (uLongf *) & xsize,
2078                             (const Bytef *) config, (uLongf) size,
2079                             Z_BEST_SPEED));
2080   return xsize;
2081 }
2082
2083
2084 /**
2085  * Same as the GNUNET_TESTBED_controller_link, but with ids for delegated host
2086  * and slave host
2087  *
2088  * @param op_cls the operation closure for the event which is generated to
2089  *          signal success or failure of this operation
2090  * @param master handle to the master controller who creates the association
2091  * @param delegated_host_id id of the host to which requests should be
2092  *          delegated; cannot be NULL
2093  * @param slave_host_id id of the host which should connect to controller
2094  *          running on delegated host ; use NULL to make the master controller
2095  *          connect to the delegated host
2096  * @param slave_cfg configuration to use for the slave controller
2097  * @param is_subordinate GNUNET_YES if the controller at delegated_host should
2098  *          be started by the slave controller; GNUNET_NO if the slave
2099  *          controller has to connect to the already started delegated
2100  *          controller via TCP/IP
2101  * @return the operation handle
2102  */
2103 struct GNUNET_TESTBED_Operation *
2104 GNUNET_TESTBED_controller_link_ (void *op_cls,
2105                                 struct GNUNET_TESTBED_Controller *master,
2106                                 uint32_t delegated_host_id,
2107                                 uint32_t slave_host_id,
2108                                 const struct GNUNET_CONFIGURATION_Handle
2109                                 *slave_cfg,
2110                                 int is_subordinate)
2111 {
2112   struct GNUNET_TESTBED_Operation *op;
2113   char *config;
2114   char *cconfig;
2115   size_t cc_size;
2116   size_t config_size;
2117
2118   config = GNUNET_CONFIGURATION_serialize (slave_cfg, &config_size);
2119   cc_size = GNUNET_TESTBED_compress_config_ (config, config_size, &cconfig);
2120   GNUNET_free (config);
2121   /* Configuration doesn't fit in 1 message */
2122   GNUNET_assert ((UINT16_MAX - 
2123                   sizeof (struct GNUNET_TESTBED_ControllerLinkMessage)) >=
2124                  cc_size);
2125   op = GNUNET_TESTBED_controller_link_2_ (op_cls, master, delegated_host_id,
2126                                           slave_host_id, (const char *) cconfig,
2127                                           cc_size, config_size, is_subordinate);
2128   GNUNET_free (cconfig);
2129   return op;
2130 }
2131
2132
2133 /**
2134  * Create a link from slave controller to delegated controller. Whenever the
2135  * master controller is asked to start a peer at the delegated controller the
2136  * request will be routed towards slave controller (if a route exists). The
2137  * slave controller will then route it to the delegated controller. The
2138  * configuration of the delegated controller is given and is used to either
2139  * create the delegated controller or to connect to an existing controller. Note
2140  * that while starting the delegated controller the configuration will be
2141  * modified to accommodate available free ports.  the 'is_subordinate' specifies
2142  * if the given delegated controller should be started and managed by the slave
2143  * controller, or if the delegated controller already has a master and the slave
2144  * controller connects to it as a non master controller. The success or failure
2145  * of this operation will be signalled through the
2146  * GNUNET_TESTBED_ControllerCallback() with an event of type
2147  * GNUNET_TESTBED_ET_OPERATION_FINISHED
2148  *
2149  * @param op_cls the operation closure for the event which is generated to
2150  *          signal success or failure of this operation
2151  * @param master handle to the master controller who creates the association
2152  * @param delegated_host requests to which host should be delegated; cannot be NULL
2153  * @param slave_host which host is used to run the slave controller; use NULL to
2154  *          make the master controller connect to the delegated host
2155  * @param slave_cfg configuration to use for the slave controller
2156  * @param is_subordinate GNUNET_YES if the controller at delegated_host should
2157  *          be started by the slave controller; GNUNET_NO if the slave
2158  *          controller has to connect to the already started delegated
2159  *          controller via TCP/IP
2160  * @return the operation handle
2161  */
2162 struct GNUNET_TESTBED_Operation *
2163 GNUNET_TESTBED_controller_link (void *op_cls,
2164                                 struct GNUNET_TESTBED_Controller *master,
2165                                 struct GNUNET_TESTBED_Host *delegated_host,
2166                                 struct GNUNET_TESTBED_Host *slave_host,
2167                                 const struct GNUNET_CONFIGURATION_Handle
2168                                 *slave_cfg, int is_subordinate)
2169 {
2170   uint32_t slave_host_id;
2171   uint32_t delegated_host_id;
2172
2173   GNUNET_assert (GNUNET_YES ==
2174                  GNUNET_TESTBED_is_host_registered_ (delegated_host, master));
2175   slave_host_id = 
2176       GNUNET_TESTBED_host_get_id_ ((NULL != slave_host)
2177                                    ? slave_host : master->host);
2178   delegated_host_id = GNUNET_TESTBED_host_get_id_ (delegated_host);
2179   if ((NULL != slave_host) && (0 != slave_host_id))
2180     GNUNET_assert (GNUNET_YES ==
2181                    GNUNET_TESTBED_is_host_registered_ (slave_host, master));
2182   return GNUNET_TESTBED_controller_link_ (op_cls, master,
2183                                           delegated_host_id,
2184                                           slave_host_id,
2185                                           slave_cfg,
2186                                           is_subordinate);
2187                                           
2188 }
2189
2190
2191 /**
2192  * Like GNUNET_TESTBED_get_slave_config(), however without the host registration
2193  * check. Another difference is that this function takes the id of the slave
2194  * host.
2195  *
2196  * @param op_cls the closure for the operation
2197  * @param master the handle to master controller
2198  * @param slave_host_id id of the host where the slave controller is running to
2199  *          the slave_host should remain valid until this operation is cancelled
2200  *          or marked as finished
2201  * @return the operation handle;
2202  */
2203 struct GNUNET_TESTBED_Operation *
2204 GNUNET_TESTBED_get_slave_config_ (void *op_cls,
2205                                   struct GNUNET_TESTBED_Controller *master,
2206                                   uint32_t slave_host_id)
2207 {  
2208   struct OperationContext *opc;
2209   struct GetSlaveConfigData *data;
2210
2211   data = GNUNET_malloc (sizeof (struct GetSlaveConfigData));
2212   data->slave_id = slave_host_id;
2213   opc = GNUNET_malloc (sizeof (struct OperationContext));
2214   opc->state = OPC_STATE_INIT;
2215   opc->c = master;
2216   opc->id = GNUNET_TESTBED_get_next_op_id (master);
2217   opc->type = OP_GET_SLAVE_CONFIG;
2218   opc->data = data;
2219   opc->op_cls = op_cls;
2220   opc->op =
2221       GNUNET_TESTBED_operation_create_ (opc, &opstart_get_slave_config,
2222                                         &oprelease_get_slave_config);
2223   GNUNET_TESTBED_operation_queue_insert_ (master->opq_parallel_operations,
2224                                           opc->op); 
2225   GNUNET_TESTBED_operation_begin_wait_ (opc->op);
2226   return opc->op;
2227 }
2228
2229
2230 /**
2231  * Function to acquire the configuration of a running slave controller. The
2232  * completion of the operation is signalled through the controller_cb from
2233  * GNUNET_TESTBED_controller_connect(). If the operation is successful the
2234  * handle to the configuration is available in the generic pointer of
2235  * operation_finished field of struct GNUNET_TESTBED_EventInformation.
2236  *
2237  * @param op_cls the closure for the operation
2238  * @param master the handle to master controller
2239  * @param slave_host the host where the slave controller is running; the handle
2240  *          to the slave_host should remain valid until this operation is
2241  *          cancelled or marked as finished
2242  * @return the operation handle; NULL if the slave_host is not registered at
2243  *           master
2244  */
2245 struct GNUNET_TESTBED_Operation *
2246 GNUNET_TESTBED_get_slave_config (void *op_cls,
2247                                  struct GNUNET_TESTBED_Controller *master,
2248                                  struct GNUNET_TESTBED_Host *slave_host)
2249 {
2250   if (GNUNET_NO == GNUNET_TESTBED_is_host_registered_ (slave_host, master))
2251     return NULL;
2252   return GNUNET_TESTBED_get_slave_config_ (op_cls, master,
2253                                            GNUNET_TESTBED_host_get_id_ (slave_host));
2254 }
2255
2256
2257 /**
2258  * Ask the testbed controller to write the current overlay topology to
2259  * a file.  Naturally, the file will only contain a snapshot as the
2260  * topology may evolve all the time.
2261  *
2262  * @param controller overlay controller to inspect
2263  * @param filename name of the file the topology should
2264  *        be written to.
2265  */
2266 void
2267 GNUNET_TESTBED_overlay_write_topology_to_file (struct GNUNET_TESTBED_Controller
2268                                                *controller,
2269                                                const char *filename)
2270 {
2271   GNUNET_break (0);
2272 }
2273
2274
2275 /**
2276  * Creates a helper initialization message. This function is here because we
2277  * want to use this in testing
2278  *
2279  * @param trusted_ip the ip address of the controller which will be set as TRUSTED
2280  *          HOST(all connections form this ip are permitted by the testbed) when
2281  *          starting testbed controller at host. This can either be a single ip
2282  *          address or a network address in CIDR notation.
2283  * @param hostname the hostname of the destination this message is intended for
2284  * @param cfg the configuration that has to used to start the testbed service
2285  *          thru helper
2286  * @return the initialization message
2287  */
2288 struct GNUNET_TESTBED_HelperInit *
2289 GNUNET_TESTBED_create_helper_init_msg_ (const char *trusted_ip,
2290                                         const char *hostname,
2291                                         const struct GNUNET_CONFIGURATION_Handle
2292                                         *cfg)
2293 {
2294   struct GNUNET_TESTBED_HelperInit *msg;
2295   char *config;
2296   char *xconfig;
2297   size_t config_size;
2298   size_t xconfig_size;
2299   uint16_t trusted_ip_len;
2300   uint16_t hostname_len;
2301   uint16_t msg_size;
2302
2303   config = GNUNET_CONFIGURATION_serialize (cfg, &config_size);
2304   GNUNET_assert (NULL != config);
2305   xconfig_size =
2306       GNUNET_TESTBED_compress_config_ (config, config_size, &xconfig);
2307   GNUNET_free (config);
2308   trusted_ip_len = strlen (trusted_ip);
2309   hostname_len = (NULL == hostname) ? 0 : strlen (hostname);
2310   msg_size =
2311       xconfig_size + trusted_ip_len + 1 + sizeof (struct GNUNET_TESTBED_HelperInit);
2312   msg_size += hostname_len;
2313   msg = GNUNET_realloc (xconfig, msg_size);
2314   (void) memmove (((void *) &msg[1]) + trusted_ip_len + 1 + hostname_len,
2315                   msg,
2316                   xconfig_size);
2317   msg->header.size = htons (msg_size);
2318   msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_HELPER_INIT);
2319   msg->trusted_ip_size = htons (trusted_ip_len);
2320   msg->hostname_size = htons (hostname_len);
2321   msg->config_size = htons (config_size);
2322   (void) strcpy ((char *) &msg[1], trusted_ip);
2323   if (0 != hostname_len)
2324     (void) strncpy (((char *) &msg[1]) + trusted_ip_len + 1, hostname, hostname_len);
2325   return msg;
2326 }
2327
2328
2329 /**
2330  * Cancel a pending operation.  Releases all resources
2331  * of the operation and will ensure that no event
2332  * is generated for the operation.  Does NOT guarantee
2333  * that the operation will be fully undone (or that
2334  * nothing ever happened).
2335  *
2336  * @param operation operation to cancel
2337  */
2338 void
2339 GNUNET_TESTBED_operation_cancel (struct GNUNET_TESTBED_Operation *operation)
2340 {
2341   GNUNET_TESTBED_operation_done (operation);
2342 }
2343
2344
2345 /**
2346  * Signal that the information from an operation has been fully
2347  * processed.  This function MUST be called for each event
2348  * of type 'operation_finished' to fully remove the operation
2349  * from the operation queue.  After calling this function, the
2350  * 'op_result' becomes invalid (!).
2351  *
2352  * @param operation operation to signal completion for
2353  */
2354 void
2355 GNUNET_TESTBED_operation_done (struct GNUNET_TESTBED_Operation *operation)
2356 {
2357     GNUNET_TESTBED_operation_release_ (operation);
2358 }
2359
2360
2361 /**
2362  * Generates configuration by uncompressing configuration in given message. The
2363  * given message should be of the following types:
2364  * GNUNET_MESSAGE_TYPE_TESTBED_PEERCONFIG,
2365  * GNUNET_MESSAGE_TYPE_TESTBED_SLAVECONFIG
2366  *
2367  * @param msg the message containing compressed configuration
2368  * @return handle to the parsed configuration
2369  */
2370 struct GNUNET_CONFIGURATION_Handle *
2371 GNUNET_TESTBED_extract_config_ (const struct GNUNET_MessageHeader *msg)
2372 {  
2373   struct GNUNET_CONFIGURATION_Handle *cfg;
2374   Bytef *data;
2375   const Bytef *xdata;
2376   uLong data_len;
2377   uLong xdata_len;
2378   int ret;
2379
2380   switch (ntohs (msg->type))
2381   {
2382   case GNUNET_MESSAGE_TYPE_TESTBED_PEERCONFIG:
2383     {
2384       const struct GNUNET_TESTBED_PeerConfigurationInformationMessage *imsg;
2385
2386       imsg = (const struct GNUNET_TESTBED_PeerConfigurationInformationMessage *)
2387           msg;
2388       data_len = (uLong) ntohs (imsg->config_size);
2389       xdata_len = ntohs (imsg->header.size)
2390           - sizeof (struct GNUNET_TESTBED_PeerConfigurationInformationMessage);
2391       xdata = (const Bytef *) &imsg[1];
2392     }
2393     break;
2394   case GNUNET_MESSAGE_TYPE_TESTBED_SLAVECONFIG:
2395     {
2396       const struct GNUNET_TESTBED_SlaveConfiguration *imsg;
2397
2398       imsg = (const struct GNUNET_TESTBED_SlaveConfiguration *) msg;
2399       data_len = (uLong) ntohs (imsg->config_size);
2400       xdata_len =  ntohs (imsg->header.size) 
2401           - sizeof (struct GNUNET_TESTBED_SlaveConfiguration);
2402       xdata = (const Bytef *) &imsg[1];
2403     }
2404     break;
2405   default:
2406     GNUNET_assert (0);
2407   }  
2408   data = GNUNET_malloc (data_len);
2409   if (Z_OK !=
2410       (ret =
2411        uncompress (data, &data_len, xdata, xdata_len)))
2412     GNUNET_assert (0);
2413   cfg = GNUNET_CONFIGURATION_create ();
2414   GNUNET_assert (GNUNET_OK ==
2415                  GNUNET_CONFIGURATION_deserialize (cfg, (const char *) data,
2416                                                    (size_t) data_len,
2417                                                    GNUNET_NO));
2418   GNUNET_free (data);
2419   return cfg;
2420 }
2421
2422
2423 /**
2424  * Checks the integrity of the OperationFailureEventMessage and if good returns
2425  * the error message it contains.
2426  *
2427  * @param msg the OperationFailureEventMessage
2428  * @return the error message
2429  */
2430 const char *
2431 GNUNET_TESTBED_parse_error_string_ (const struct
2432                                     GNUNET_TESTBED_OperationFailureEventMessage
2433                                     *msg)
2434 {
2435   uint16_t msize;
2436   const char *emsg;
2437   
2438   msize = ntohs (msg->header.size);
2439   if (sizeof (struct GNUNET_TESTBED_OperationFailureEventMessage) >= msize)
2440     return NULL;
2441   msize -= sizeof (struct GNUNET_TESTBED_OperationFailureEventMessage);
2442   emsg = (const char *) &msg[1];
2443   if ('\0' != emsg[msize - 1])
2444   {
2445     GNUNET_break (0);
2446     return NULL;
2447   }
2448   return emsg;
2449 }
2450
2451
2452 /**
2453  * Function to return the operation id for a controller. The operation id is
2454  * created from the controllers host id and its internal operation counter.
2455  *
2456  * @param controller the handle to the controller whose operation id has to be incremented
2457  * @return the incremented operation id.
2458  */
2459 uint64_t
2460 GNUNET_TESTBED_get_next_op_id (struct GNUNET_TESTBED_Controller *controller)
2461 {
2462   uint64_t op_id;  
2463
2464   op_id = (uint64_t) GNUNET_TESTBED_host_get_id_ (controller->host);
2465   op_id = op_id <<  32;
2466   op_id |= (uint64_t) controller->operation_counter++;
2467   return op_id;
2468 }
2469
2470
2471 /**
2472  * Returns a timing slot which will be exclusively locked
2473  *
2474  * @param c the controller handle
2475  * @param key a pointer which is associated to the returned slot; should not be
2476  *          NULL. It serves as a key to determine the correct owner of the slot
2477  * @return the time slot index in the array of time slots in the controller
2478  *           handle
2479  */
2480 unsigned int
2481 GNUNET_TESTBED_get_tslot_ (struct GNUNET_TESTBED_Controller *c, void *key)
2482 {
2483   unsigned int slot;
2484
2485   GNUNET_assert (NULL != c->tslots);
2486   GNUNET_assert (NULL != key);
2487   for (slot = 0; slot < c->num_parallel_connects; slot++)
2488     if (NULL == c->tslots[slot].key)
2489     {
2490       c->tslots[slot].key = key;
2491       return slot;
2492     }
2493   GNUNET_assert (0);            /* We should always find a free tslot */
2494 }
2495
2496
2497 /**
2498  * Decides whether any change in the number of parallel overlay connects is
2499  * necessary to adapt to the load on the system
2500  *
2501  * @param c the controller handle
2502  */
2503 static void
2504 decide_npoc (struct GNUNET_TESTBED_Controller *c)
2505 {
2506   struct GNUNET_TIME_Relative avg;
2507   int sd;
2508   unsigned int slot;
2509
2510   if (c->tslots_filled != c->num_parallel_connects)
2511     return;
2512   avg = GNUNET_TIME_UNIT_ZERO;
2513   for (slot = 0; slot < c->num_parallel_connects; slot++)
2514     avg = GNUNET_TIME_relative_add (avg, c->tslots[slot].time);
2515   avg = GNUNET_TIME_relative_divide (avg, c->num_parallel_connects);
2516   GNUNET_assert (GNUNET_TIME_UNIT_FOREVER_REL.rel_value != avg.rel_value);
2517   sd = SD_deviation_factor (c->poc_sd, (unsigned int) avg.rel_value);
2518   if (GNUNET_SYSERR == sd)
2519   {
2520     SD_add_data (c->poc_sd, (unsigned int) avg.rel_value);
2521     GNUNET_TESTBED_set_num_parallel_overlay_connects_ (c, c->num_parallel_connects);
2522     return;
2523   }
2524   GNUNET_assert (0 <= sd);
2525   if (sd <= 1)
2526   {
2527     SD_add_data (c->poc_sd, (unsigned int) avg.rel_value);
2528     GNUNET_TESTBED_set_num_parallel_overlay_connects_
2529         (c, c->num_parallel_connects * 2);
2530     return;
2531   }
2532   if (1 == c->num_parallel_connects)
2533   {
2534     GNUNET_TESTBED_set_num_parallel_overlay_connects_ (c, 1);
2535     return;
2536   }
2537   GNUNET_TESTBED_set_num_parallel_overlay_connects_ 
2538       (c, c->num_parallel_connects / 2);
2539 }
2540
2541
2542 /**
2543  * Releases a time slot thus making it available for be used again
2544  *
2545  * @param c the controller handle
2546  * @param index the index of the the time slot
2547  * @param key the key to prove ownership of the timeslot
2548  * @return GNUNET_YES if the time slot is successfully removed; GNUNET_NO if the
2549  *           time slot cannot be removed - this could be because of the index
2550  *           greater than existing number of time slots or `key' being different
2551  */
2552 int
2553 GNUNET_TESTBED_release_time_slot_ (struct GNUNET_TESTBED_Controller *c,
2554                                   unsigned int index,
2555                                    void *key)
2556 {
2557   struct TimeSlot *slot;
2558
2559   GNUNET_assert (NULL != key);
2560   if (index >= c->num_parallel_connects)
2561     return GNUNET_NO;
2562   slot = &c->tslots[index];
2563   if (key != slot->key)
2564     return GNUNET_NO;
2565   slot->key = NULL;
2566   return GNUNET_YES;
2567 }
2568
2569
2570 /**
2571  * Function to update a time slot
2572  *
2573  * @param c the controller handle
2574  * @param index the index of the time slot to update
2575  * @param key the key to identify ownership of the slot
2576  * @param time the new time
2577  */
2578 void
2579 GNUNET_TESTBED_update_time_slot_ (struct GNUNET_TESTBED_Controller *c,
2580                                   unsigned int index,
2581                                   void *key,
2582                                   struct GNUNET_TIME_Relative time)
2583 {
2584   struct GNUNET_TIME_Relative avg;
2585   struct TimeSlot *slot;
2586
2587   if (GNUNET_NO == GNUNET_TESTBED_release_time_slot_ (c, index, key))
2588     return;
2589   slot = &c->tslots[index];
2590   if (GNUNET_TIME_UNIT_ZERO.rel_value == slot->time.rel_value)
2591   {
2592     slot->time = time;
2593     c->tslots_filled++;
2594     decide_npoc (c);
2595     return;
2596   }
2597   avg = GNUNET_TIME_relative_add (slot->time, time);
2598   avg = GNUNET_TIME_relative_divide (avg, 2);
2599   slot->time = avg;
2600 }
2601
2602
2603 /* end of testbed_api.c */