9e671087aa1105a885a0e460b745fc45bdc683d7
[oweals/gnunet.git] / src / testbed / testbed_api_hosts.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_hosts.c
23  * @brief API for manipulating 'hosts' controlled by the GNUnet testing service;
24  *        allows parsing hosts files, starting, stopping and communicating (via
25  *        SSH/stdin/stdout) with the remote (or local) processes
26  * @author Christian Grothoff
27  */
28 #include "platform.h"
29 #include "gnunet_util_lib.h"
30 #include "gnunet_testbed_service.h"
31 #include "gnunet_core_service.h"
32 #include "gnunet_transport_service.h"
33
34 #include "testbed_api.h"
35 #include "testbed_api_hosts.h"
36 #include "testbed_helper.h"
37 #include "testbed_api_operations.h"
38 #include "testbed_api_sd.h"
39
40 #include <zlib.h>
41
42 /**
43  * Generic logging shorthand
44  */
45 #define LOG(kind, ...)                          \
46   GNUNET_log_from (kind, "testbed-api-hosts", __VA_ARGS__);
47
48 /**
49  * Debug logging shorthand
50  */
51 #define LOG_DEBUG(...)                          \
52   LOG (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__);
53
54 /**
55  * Number of extra elements we create space for when we grow host list
56  */
57 #define HOST_LIST_GROW_STEP 10
58
59
60 /**
61  * A list entry for registered controllers list
62  */
63 struct RegisteredController
64 {
65   /**
66    * The controller at which this host is registered
67    */
68   const struct GNUNET_TESTBED_Controller *controller;
69
70   /**
71    * The next ptr for DLL
72    */
73   struct RegisteredController *next;
74
75   /**
76    * The prev ptr for DLL
77    */
78   struct RegisteredController *prev;
79 };
80
81
82 /**
83  * A slot to record time taken by an overlay connect operation
84  */
85 struct TimeSlot
86 {
87   /**
88    * A key to identify this timeslot
89    */
90   void *key;
91
92   /**
93    * Time
94    */
95   struct GNUNET_TIME_Relative time;
96
97   /**
98    * Number of timing values accumulated
99    */
100   unsigned int nvals;
101 };
102
103
104 /**
105  * Opaque handle to a host running experiments managed by the testing framework.
106  * The master process must be able to SSH to this host without password (via
107  * ssh-agent).
108  */
109 struct GNUNET_TESTBED_Host
110 {
111
112   /**
113    * The next pointer for DLL
114    */
115   struct GNUNET_TESTBED_Host *next;
116
117   /**
118    * The prev pointer for DLL
119    */
120   struct GNUNET_TESTBED_Host *prev;
121
122   /**
123    * The hostname of the host; NULL for localhost
124    */
125   const char *hostname;
126
127   /**
128    * The username to be used for SSH login
129    */
130   const char *username;
131
132   /**
133    * the configuration to use as a template while starting a controller on this
134    * host.  Operation queue size specific to a host are also read from this
135    * configuration handle
136    */
137   struct GNUNET_CONFIGURATION_Handle *cfg;
138
139   /**
140    * The head for the list of controllers where this host is registered
141    */
142   struct RegisteredController *rc_head;
143
144   /**
145    * The tail for the list of controllers where this host is registered
146    */
147   struct RegisteredController *rc_tail;
148
149   /**
150    * Operation queue for simultaneous overlay connect operations target at this
151    * host
152    */
153   struct OperationQueue *opq_parallel_overlay_connect_operations;
154
155   /**
156    * An array of timing slots; size should be equal to the current number of parallel
157    * overlay connects
158    */
159   struct TimeSlot *tslots;
160
161   /**
162    * Handle for SD calculations amount parallel overlay connect operation finish
163    * times
164    */
165   struct SDHandle *poc_sd;  
166
167   /**
168    * The number of parallel overlay connects we do currently
169    */
170   unsigned int num_parallel_connects;
171
172   /**
173    * Counter to indicate when all the available time slots are filled
174    */
175   unsigned int tslots_filled;
176
177   /**
178    * Is a controller started on this host?
179    */
180   int controller_started;
181
182   /**
183    * Global ID we use to refer to a host on the network
184    */
185   uint32_t id;
186
187   /**
188    * The port which is to be used for SSH
189    */
190   uint16_t port;
191
192 };
193
194
195 /**
196  * Array of available hosts
197  */
198 static struct GNUNET_TESTBED_Host **host_list;
199
200 /**
201  * The size of the available hosts list
202  */
203 static unsigned int host_list_size;
204
205
206 /**
207  * Lookup a host by ID.
208  *
209  * @param id global host ID assigned to the host; 0 is
210  *        reserved to always mean 'localhost'
211  * @return handle to the host, NULL if host not found
212  */
213 struct GNUNET_TESTBED_Host *
214 GNUNET_TESTBED_host_lookup_by_id_ (uint32_t id)
215 {
216   if (host_list_size <= id)
217     return NULL;
218   return host_list[id];
219 }
220
221
222 /**
223  * Create a host by ID; given this host handle, we could not
224  * run peers at the host, but we can talk about the host
225  * internally.
226  *
227  * @param id global host ID assigned to the host; 0 is
228  *        reserved to always mean 'localhost'
229  * @param cfg the configuration to use as a template while starting a controller
230  *          on this host.  Operation queue sizes specific to a host are also
231  *          read from this configuration handle
232  * @return handle to the host, NULL on error
233  */
234 struct GNUNET_TESTBED_Host *
235 GNUNET_TESTBED_host_create_by_id_ (uint32_t id,
236                                    const struct GNUNET_CONFIGURATION_Handle
237                                    *cfg)
238 {
239   return GNUNET_TESTBED_host_create_with_id (id, NULL, NULL, cfg, 0);
240 }
241
242
243 /**
244  * Obtain the host's unique global ID.
245  *
246  * @param host handle to the host, NULL means 'localhost'
247  * @return id global host ID assigned to the host (0 is
248  *         'localhost', but then obviously not globally unique)
249  */
250 uint32_t
251 GNUNET_TESTBED_host_get_id_ (const struct GNUNET_TESTBED_Host * host)
252 {
253   return host->id;
254 }
255
256
257 /**
258  * Obtain the host's hostname.
259  *
260  * @param host handle to the host, NULL means 'localhost'
261  * @return hostname of the host
262  */
263 const char *
264 GNUNET_TESTBED_host_get_hostname (const struct GNUNET_TESTBED_Host *host)
265 {
266   return host->hostname;
267 }
268
269
270 /**
271  * Obtain the host's username
272  *
273  * @param host handle to the host, NULL means 'localhost'
274  * @return username to login to the host
275  */
276 const char *
277 GNUNET_TESTBED_host_get_username_ (const struct GNUNET_TESTBED_Host *host)
278 {
279   return host->username;
280 }
281
282
283 /**
284  * Obtain the host's ssh port
285  *
286  * @param host handle to the host, NULL means 'localhost'
287  * @return username to login to the host
288  */
289 uint16_t
290 GNUNET_TESTBED_host_get_ssh_port_ (const struct GNUNET_TESTBED_Host * host)
291 {
292   return host->port;
293 }
294
295
296 /**
297  * Check whether a controller is already started on the given host
298  *
299  * @param host the handle to the host
300  * @return GNUNET_YES if the controller is already started; GNUNET_NO if not
301  */
302 int
303 GNUNET_TESTBED_host_controller_started (const struct GNUNET_TESTBED_Host *host)
304 {
305   return host->controller_started;
306 }
307
308
309 /**
310  * Obtain the host's configuration template
311  *
312  * @param host handle to the host
313  * @return the host's configuration template
314  */
315 const struct GNUNET_CONFIGURATION_Handle *
316 GNUNET_TESTBED_host_get_cfg_ (const struct GNUNET_TESTBED_Host *host)
317 {
318   return host->cfg;
319 }
320
321
322 /**
323  * Create a host to run peers and controllers on.
324  *
325  * @param id global host ID assigned to the host; 0 is
326  *        reserved to always mean 'localhost'
327  * @param hostname name of the host, use "NULL" for localhost
328  * @param username username to use for the login; may be NULL
329  * @param cfg the configuration to use as a template while starting a controller
330  *          on this host.  Operation queue sizes specific to a host are also
331  *          read from this configuration handle
332  * @param port port number to use for ssh; use 0 to let ssh decide
333  * @return handle to the host, NULL on error
334  */
335 struct GNUNET_TESTBED_Host *
336 GNUNET_TESTBED_host_create_with_id (uint32_t id, const char *hostname,
337                                     const char *username, 
338                                     const struct GNUNET_CONFIGURATION_Handle
339                                     *cfg,
340                                     uint16_t port)
341 {
342   struct GNUNET_TESTBED_Host *host;
343   unsigned int new_size;
344
345   if ((id < host_list_size) && (NULL != host_list[id]))
346   {
347     LOG (GNUNET_ERROR_TYPE_WARNING, "Host with id: %u already created\n", id);
348     return NULL;
349   }
350   host = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_Host));
351   host->hostname = (NULL != hostname) ? GNUNET_strdup (hostname) : NULL;
352   host->username = (NULL != username) ? GNUNET_strdup (username) : NULL;
353   host->id = id;
354   host->port = (0 == port) ? 22 : port;
355   host->cfg = GNUNET_CONFIGURATION_dup (cfg);
356   host->opq_parallel_overlay_connect_operations =
357       GNUNET_TESTBED_operation_queue_create_ (0);
358   GNUNET_TESTBED_set_num_parallel_overlay_connects_ (host, 1);
359   host->poc_sd = GNUNET_TESTBED_SD_init_ (10);
360   new_size = host_list_size;
361   while (id >= new_size)
362     new_size += HOST_LIST_GROW_STEP;
363   if (new_size != host_list_size)
364     GNUNET_array_grow (host_list, host_list_size, new_size);
365   GNUNET_assert (id < host_list_size);
366   LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding host with id: %u\n", host->id);
367   host_list[id] = host;
368   return host;
369 }
370
371
372 /**
373  * Create a host to run peers and controllers on.
374  *
375  * @param hostname name of the host, use "NULL" for localhost
376  * @param username username to use for the login; may be NULL
377  * @param cfg the configuration to use as a template while starting a controller
378  *          on this host.  Operation queue sizes specific to a host are also
379  *          read from this configuration handle
380  * @param port port number to use for ssh; use 0 to let ssh decide
381  * @return handle to the host, NULL on error
382  */
383 struct GNUNET_TESTBED_Host *
384 GNUNET_TESTBED_host_create (const char *hostname, const char *username,
385                             const struct GNUNET_CONFIGURATION_Handle *cfg,
386                             uint16_t port)
387 {
388   static uint32_t uid_generator;
389
390   if (NULL == hostname)
391     return GNUNET_TESTBED_host_create_with_id (0, hostname, username, 
392                                                cfg, port);
393   return GNUNET_TESTBED_host_create_with_id (++uid_generator, hostname,
394                                              username, cfg, port);
395 }
396
397
398 /**
399  * Load a set of hosts from a configuration file.
400  *
401  * @param filename file with the host specification
402  * @param cfg the configuration to use as a template while starting a controller
403  *          on any of the loaded hosts.  Operation queue sizes specific to a host
404  *          are also read from this configuration handle
405  * @param hosts set to the hosts found in the file; caller must free this if
406  *          number of hosts returned is greater than 0
407  * @return number of hosts returned in 'hosts', 0 on error
408  */
409 unsigned int
410 GNUNET_TESTBED_hosts_load_from_file (const char *filename,
411                                      const struct GNUNET_CONFIGURATION_Handle
412                                      *cfg,
413                                      struct GNUNET_TESTBED_Host ***hosts)
414 {
415   //struct GNUNET_TESTBED_Host **host_array;
416   struct GNUNET_TESTBED_Host *starting_host;
417   char *data;
418   char *buf;
419   char username[256];
420   char hostname[256];
421   uint64_t fs;
422   short int port;
423   int ret;
424   unsigned int offset;
425   unsigned int count;
426
427
428   GNUNET_assert (NULL != filename);
429   if (GNUNET_YES != GNUNET_DISK_file_test (filename))
430   {
431     LOG (GNUNET_ERROR_TYPE_WARNING, _("Hosts file %s not found\n"), filename);
432     return 0;
433   }
434   if (GNUNET_OK !=
435       GNUNET_DISK_file_size (filename, &fs, GNUNET_YES, GNUNET_YES))
436     fs = 0;
437   if (0 == fs)
438   {
439     LOG (GNUNET_ERROR_TYPE_WARNING, _("Hosts file %s has no data\n"), filename);
440     return 0;
441   }
442   data = GNUNET_malloc (fs);
443   if (fs != GNUNET_DISK_fn_read (filename, data, fs))
444   {
445     GNUNET_free (data);
446     LOG (GNUNET_ERROR_TYPE_WARNING, _("Hosts file %s cannot be read\n"),
447          filename);
448     return 0;
449   }
450   buf = data;
451   offset = 0;
452   starting_host = NULL;
453   count = 0;
454   while (offset < (fs - 1))
455   {
456     offset++;
457     if (((data[offset] == '\n')) && (buf != &data[offset]))
458     {
459       data[offset] = '\0';
460       ret =
461           SSCANF (buf, "%255[a-zA-Z0-9_]@%255[a-zA-Z0-9.]:%5hd", username,
462                   hostname, &port);
463       if (3 == ret)
464       {
465         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
466                     "Successfully read host %s, port %d and user %s from file\n",
467                     hostname, port, username);
468         /* We store hosts in a static list; hence we only require the starting
469          * host pointer in that list to access the newly created list of hosts */
470         if (NULL == starting_host)
471           starting_host = GNUNET_TESTBED_host_create (hostname, username, cfg,
472                                                       port);
473         else
474           (void) GNUNET_TESTBED_host_create (hostname, username, cfg, port);
475         count++;
476       }
477       else
478         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
479                     "Error reading line `%s' in hostfile\n", buf);
480       buf = &data[offset + 1];
481     }
482     else if ((data[offset] == '\n') || (data[offset] == '\0'))
483       buf = &data[offset + 1];
484   }
485   GNUNET_free (data);
486   if (NULL == starting_host)
487     return 0;
488   *hosts = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_Host *) * count);
489   memcpy (*hosts, &host_list[GNUNET_TESTBED_host_get_id_ (starting_host)],
490           sizeof (struct GNUNET_TESTBED_Host *) * count);
491   return count;
492 }
493
494
495 /**
496  * Destroy a host handle.  Must only be called once everything
497  * running on that host has been stopped.
498  *
499  * @param host handle to destroy
500  */
501 void
502 GNUNET_TESTBED_host_destroy (struct GNUNET_TESTBED_Host *host)
503 {
504   struct RegisteredController *rc;
505   uint32_t id;
506
507   GNUNET_assert (host->id < host_list_size);
508   GNUNET_assert (host_list[host->id] == host);
509   host_list[host->id] = NULL;
510   /* clear registered controllers list */
511   for (rc = host->rc_head; NULL != rc; rc = host->rc_head)
512   {
513     GNUNET_CONTAINER_DLL_remove (host->rc_head, host->rc_tail, rc);
514     GNUNET_free (rc);
515   }
516   GNUNET_free_non_null ((char *) host->username);
517   GNUNET_free_non_null ((char *) host->hostname);
518   GNUNET_TESTBED_operation_queue_destroy_
519       (host->opq_parallel_overlay_connect_operations);
520   GNUNET_TESTBED_SD_destroy_ (host->poc_sd);
521   GNUNET_free_non_null (host->tslots);
522   GNUNET_CONFIGURATION_destroy (host->cfg);
523   GNUNET_free (host);
524   while (host_list_size >= HOST_LIST_GROW_STEP)
525   {
526     for (id = host_list_size - 1; id > host_list_size - HOST_LIST_GROW_STEP;
527          id--)
528       if (NULL != host_list[id])
529         break;
530     if (id != host_list_size - HOST_LIST_GROW_STEP)
531       break;
532     if (NULL != host_list[id])
533       break;
534     host_list_size -= HOST_LIST_GROW_STEP;
535   }
536   host_list =
537       GNUNET_realloc (host_list,
538                       sizeof (struct GNUNET_TESTBED_Host *) * host_list_size);
539 }
540
541
542 /**
543  * Marks a host as registered with a controller
544  *
545  * @param host the host to mark
546  * @param controller the controller at which this host is registered
547  */
548 void
549 GNUNET_TESTBED_mark_host_registered_at_ (struct GNUNET_TESTBED_Host *host,
550                                          const struct GNUNET_TESTBED_Controller
551                                          *const controller)
552 {
553   struct RegisteredController *rc;
554
555   for (rc = host->rc_head; NULL != rc; rc = rc->next)
556   {
557     if (controller == rc->controller)   /* already registered at controller */
558     {
559       GNUNET_break (0);
560       return;
561     }
562   }
563   rc = GNUNET_malloc (sizeof (struct RegisteredController));
564   rc->controller = controller;
565   GNUNET_CONTAINER_DLL_insert_tail (host->rc_head, host->rc_tail, rc);
566 }
567
568
569 /**
570  * Checks whether a host has been registered
571  *
572  * @param host the host to check
573  * @param controller the controller at which host's registration is checked
574  * @return GNUNET_YES if registered; GNUNET_NO if not
575  */
576 int
577 GNUNET_TESTBED_is_host_registered_ (const struct GNUNET_TESTBED_Host *host,
578                                     const struct GNUNET_TESTBED_Controller
579                                     *const controller)
580 {
581   struct RegisteredController *rc;
582
583   for (rc = host->rc_head; NULL != rc; rc = rc->next)
584   {
585     if (controller == rc->controller)   /* already registered at controller */
586     {
587       return GNUNET_YES;
588     }
589   }
590   return GNUNET_NO;
591 }
592
593
594 /**
595  * Handle for controller process
596  */
597 struct GNUNET_TESTBED_ControllerProc
598 {
599   /**
600    * The process handle
601    */
602   struct GNUNET_HELPER_Handle *helper;
603
604   /**
605    * The arguments used to start the helper
606    */
607   char **helper_argv;
608
609   /**
610    * The host where the helper is run
611    */
612   struct GNUNET_TESTBED_Host *host;
613
614   /**
615    * The controller error callback
616    */
617   GNUNET_TESTBED_ControllerStatusCallback cb;
618
619   /**
620    * The closure for the above callback
621    */
622   void *cls;
623
624   /**
625    * The send handle for the helper
626    */
627   struct GNUNET_HELPER_SendHandle *shandle;
628
629   /**
630    * The message corresponding to send handle
631    */
632   struct GNUNET_MessageHeader *msg;
633
634   /**
635    * The configuration of the running testbed service
636    */
637   struct GNUNET_CONFIGURATION_Handle *cfg;
638
639 };
640
641
642 /**
643  * Function to copy NULL terminated list of arguments
644  *
645  * @param argv the NULL terminated list of arguments. Cannot be NULL.
646  * @return the copied NULL terminated arguments
647  */
648 static char **
649 copy_argv (const char *const *argv)
650 {
651   char **argv_dup;
652   unsigned int argp;
653
654   GNUNET_assert (NULL != argv);
655   for (argp = 0; NULL != argv[argp]; argp++) ;
656   argv_dup = GNUNET_malloc (sizeof (char *) * (argp + 1));
657   for (argp = 0; NULL != argv[argp]; argp++)
658     argv_dup[argp] = strdup (argv[argp]);
659   return argv_dup;
660 }
661
662
663 /**
664  * Function to join NULL terminated list of arguments
665  *
666  * @param argv1 the NULL terminated list of arguments. Cannot be NULL.
667  * @param argv2 the NULL terminated list of arguments. Cannot be NULL.
668  * @return the joined NULL terminated arguments
669  */
670 static char **
671 join_argv (const char *const *argv1, const char *const *argv2)
672 {
673   char **argvj;
674   char *argv;
675   unsigned int carg;
676   unsigned int cnt;
677
678   carg = 0;
679   argvj = NULL;
680   for (cnt = 0; NULL != argv1[cnt]; cnt++)
681   {
682     argv = GNUNET_strdup (argv1[cnt]);
683     GNUNET_array_append (argvj, carg, argv);
684   }
685   for (cnt = 0; NULL != argv2[cnt]; cnt++)
686   {
687     argv = GNUNET_strdup (argv2[cnt]);
688     GNUNET_array_append (argvj, carg, argv);
689   }
690   GNUNET_array_append (argvj, carg, NULL);
691   return argvj;
692 }
693
694
695 /**
696  * Frees the given NULL terminated arguments
697  *
698  * @param argv the NULL terminated list of arguments
699  */
700 static void
701 free_argv (char **argv)
702 {
703   unsigned int argp;
704
705   for (argp = 0; NULL != argv[argp]; argp++)
706     GNUNET_free (argv[argp]);
707   GNUNET_free (argv);
708 }
709
710
711 /**
712  * Generates arguments for opening a remote shell. Builds up the arguments
713  * from the environment variable GNUNET_TESTBED_RSH_CMD. The variable
714  * should not mention `-p' (port) option and destination address as these will
715  * be set locally in the function from its parameteres. If the environmental
716  * variable is not found then it defaults to `ssh -o BatchMode=yes -o
717  * NoHostAuthenticationForLocalhost=yes'
718  *
719  * @param port the destination port number
720  * @param dst the destination address
721  * @return NULL terminated list of arguments
722  */
723 static char **
724 gen_rsh_args (const char *port, const char *dst)
725 {
726   static const char *default_ssh_args[] = {
727     "ssh",
728     "-o",
729     "BatchMode=yes",
730     "-o",
731     "NoHostAuthenticationForLocalhost=yes",
732     NULL
733   };
734   char **ssh_args;
735   char *ssh_cmd;
736   char *ssh_cmd_cp;
737   char *arg;
738   unsigned int cnt;
739
740   ssh_args = NULL;
741   if (NULL != (ssh_cmd = getenv ("GNUNET_TESTBED_RSH_CMD")))
742   {
743     ssh_cmd = GNUNET_strdup (ssh_cmd);
744     ssh_cmd_cp = ssh_cmd;
745     for (cnt = 0; NULL != (arg = strtok (ssh_cmd, " ")); ssh_cmd = NULL)
746       GNUNET_array_append (ssh_args, cnt, GNUNET_strdup (arg));
747     GNUNET_free (ssh_cmd_cp);
748   }
749   else
750   {
751     ssh_args = copy_argv (default_ssh_args);
752     cnt = (sizeof (default_ssh_args)) / (sizeof (const char *));
753     GNUNET_array_grow (ssh_args, cnt, cnt - 1);
754   }
755   GNUNET_array_append (ssh_args, cnt, GNUNET_strdup ("-p"));
756   GNUNET_array_append (ssh_args, cnt, GNUNET_strdup (port));
757   GNUNET_array_append (ssh_args, cnt, GNUNET_strdup (dst));
758   GNUNET_array_append (ssh_args, cnt, NULL);
759   return ssh_args;
760 }
761
762
763 /**
764  * Generates the arguments needed for executing the given binary in a remote
765  * shell. Builds the arguments from the environmental variable
766  * GNUNET_TETSBED_RSH_CMD_SUFFIX. If the environmental variable is not found,
767  * only the given binary name will be present in the returned arguments
768  *
769  * @param append_args the arguments to append after generating the suffix
770  *          arguments. Can be NULL; if not must be NULL terminated 'char *' array
771  * @return NULL-terminated args
772  */
773 static char **
774 gen_rsh_suffix_args (const char * const *append_args)
775 {
776   char **rshell_args;
777   char *rshell_cmd;
778   char *rshell_cmd_cp;
779   char *arg;
780   unsigned int cnt;
781   unsigned int append_cnt;
782
783   rshell_args = NULL;
784   cnt = 0;
785   if (NULL != (rshell_cmd = getenv ("GNUNET_TESTBED_RSH_CMD_SUFFIX")))
786   {
787     rshell_cmd = GNUNET_strdup (rshell_cmd);
788     rshell_cmd_cp = rshell_cmd;
789     for (; NULL != (arg = strtok (rshell_cmd, " ")); rshell_cmd = NULL)
790       GNUNET_array_append (rshell_args, cnt, GNUNET_strdup (arg));
791     GNUNET_free (rshell_cmd_cp);
792   }
793   if (NULL != append_args)
794   {
795     for (append_cnt = 0; NULL != append_args[append_cnt]; append_cnt++)      
796       GNUNET_array_append (rshell_args, cnt, GNUNET_strdup (append_args[append_cnt]));
797   }
798   GNUNET_array_append (rshell_args, cnt, NULL);
799   return rshell_args;
800 }
801
802
803 /**
804  * Functions with this signature are called whenever a
805  * complete message is received by the tokenizer.
806  *
807  * Do not call GNUNET_SERVER_mst_destroy in callback
808  *
809  * @param cls closure
810  * @param client identification of the client
811  * @param message the actual message
812  *
813  * @return GNUNET_OK on success, GNUNET_SYSERR to stop further processing
814  */
815 static int
816 helper_mst (void *cls, void *client, const struct GNUNET_MessageHeader *message)
817 {
818   struct GNUNET_TESTBED_ControllerProc *cp = cls;
819   const struct GNUNET_TESTBED_HelperReply *msg;
820   const char *hostname;
821   char *config;
822   uLongf config_size;
823   uLongf xconfig_size;
824
825   msg = (const struct GNUNET_TESTBED_HelperReply *) message;
826   GNUNET_assert (sizeof (struct GNUNET_TESTBED_HelperReply) <
827                  ntohs (msg->header.size));
828   GNUNET_assert (GNUNET_MESSAGE_TYPE_TESTBED_HELPER_REPLY ==
829                  ntohs (msg->header.type));
830   config_size = (uLongf) ntohs (msg->config_size);
831   xconfig_size =
832       (uLongf) (ntohs (msg->header.size) -
833                 sizeof (struct GNUNET_TESTBED_HelperReply));
834   config = GNUNET_malloc (config_size);
835   GNUNET_assert (Z_OK ==
836                  uncompress ((Bytef *) config, &config_size,
837                              (const Bytef *) &msg[1], xconfig_size));
838   GNUNET_assert (NULL == cp->cfg);
839   cp->cfg = GNUNET_CONFIGURATION_create ();
840   GNUNET_assert (GNUNET_CONFIGURATION_deserialize
841                  (cp->cfg, config, config_size, GNUNET_NO));
842   GNUNET_free (config);
843   if ((NULL == cp->host) ||
844       (NULL == (hostname = GNUNET_TESTBED_host_get_hostname (cp->host))))
845     hostname = "localhost";
846   /* Change the hostname so that we can connect to it */
847   GNUNET_CONFIGURATION_set_value_string (cp->cfg, "testbed", "hostname",
848                                          hostname);
849   cp->cb (cp->cls, cp->cfg, GNUNET_OK);
850   return GNUNET_OK;
851 }
852
853
854 /**
855  * Continuation function from GNUNET_HELPER_send()
856  *
857  * @param cls closure
858  * @param result GNUNET_OK on success,
859  *               GNUNET_NO if helper process died
860  *               GNUNET_SYSERR during GNUNET_HELPER_stop
861  */
862 static void
863 clear_msg (void *cls, int result)
864 {
865   struct GNUNET_TESTBED_ControllerProc *cp = cls;
866
867   GNUNET_assert (NULL != cp->shandle);
868   cp->shandle = NULL;
869   GNUNET_free (cp->msg);
870 }
871
872
873 /**
874  * Callback that will be called when the helper process dies. This is not called
875  * when the helper process is stoped using GNUNET_HELPER_stop()
876  *
877  * @param cls the closure from GNUNET_HELPER_start()
878  */
879 static void
880 helper_exp_cb (void *cls)
881 {
882   struct GNUNET_TESTBED_ControllerProc *cp = cls;
883   GNUNET_TESTBED_ControllerStatusCallback cb;
884   void *cb_cls;
885
886   cb = cp->cb;
887   cb_cls = cp->cls;
888   cp->helper = NULL;
889   GNUNET_TESTBED_controller_stop (cp);
890   if (NULL != cb)
891     cb (cb_cls, NULL, GNUNET_SYSERR);
892 }
893
894
895 /**
896  * Starts a controller process at the given host
897  *
898  * @param trusted_ip the ip address of the controller which will be set as TRUSTED
899  *          HOST(all connections form this ip are permitted by the testbed) when
900  *          starting testbed controller at host. This can either be a single ip
901  *          address or a network address in CIDR notation.
902  * @param host the host where the controller has to be started; NULL for
903  *          localhost
904  * @param cfg template configuration to use for the remote controller; the
905  *          remote controller will be started with a slightly modified
906  *          configuration (port numbers, unix domain sockets and service home
907  *          values are changed as per TESTING library on the remote host)
908  * @param cb function called when the controller is successfully started or
909  *          dies unexpectedly; GNUNET_TESTBED_controller_stop shouldn't be
910  *          called if cb is called with GNUNET_SYSERR as status. Will never be
911  *          called in the same task as 'GNUNET_TESTBED_controller_start'
912  *          (synchronous errors will be signalled by returning NULL). This
913  *          parameter cannot be NULL.
914  * @param cls closure for above callbacks
915  * @return the controller process handle, NULL on errors
916  */
917 struct GNUNET_TESTBED_ControllerProc *
918 GNUNET_TESTBED_controller_start (const char *trusted_ip,
919                                  struct GNUNET_TESTBED_Host *host,
920                                  const struct GNUNET_CONFIGURATION_Handle *cfg,
921                                  GNUNET_TESTBED_ControllerStatusCallback cb,
922                                  void *cls)
923 {
924   struct GNUNET_TESTBED_ControllerProc *cp;
925   struct GNUNET_TESTBED_HelperInit *msg;
926   const char *hostname;
927
928   static char *const binary_argv[] = {
929     HELPER_TESTBED_BINARY, NULL
930   };
931
932   hostname = NULL;  
933   cp = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_ControllerProc));
934   if ((NULL == host) || (0 == GNUNET_TESTBED_host_get_id_ (host)))
935   {
936     cp->helper =
937         GNUNET_HELPER_start (GNUNET_YES, HELPER_TESTBED_BINARY, binary_argv,
938                              &helper_mst, &helper_exp_cb, cp);
939   }
940   else
941   {
942     char *helper_binary_path_args[2];
943     char **rsh_args;
944     char **rsh_suffix_args;
945     const char *username;
946     char *port;
947     char *dst;
948
949     username = GNUNET_TESTBED_host_get_username_ (host);
950     hostname = GNUNET_TESTBED_host_get_hostname (host);
951     GNUNET_asprintf (&port, "%u", GNUNET_TESTBED_host_get_ssh_port_ (host));
952     if (NULL == username)
953       GNUNET_asprintf (&dst, "%s", hostname);
954     else
955       GNUNET_asprintf (&dst, "%s@%s", username, hostname);
956     LOG_DEBUG ("Starting SSH to destination %s\n", dst);
957
958     if (GNUNET_OK !=
959         GNUNET_CONFIGURATION_get_value_string (cfg, "testbed",
960                                                "HELPER_BINARY_PATH",
961                                                &helper_binary_path_args[0]))
962       helper_binary_path_args[0] =
963           GNUNET_OS_get_libexec_binary_path (HELPER_TESTBED_BINARY);
964     helper_binary_path_args[1] = NULL;
965     rsh_args = gen_rsh_args (port, dst);
966     rsh_suffix_args = gen_rsh_suffix_args ((const char **) helper_binary_path_args);
967     cp->helper_argv =
968         join_argv ((const char **) rsh_args, (const char **) rsh_suffix_args);
969     free_argv (rsh_args);
970     free_argv (rsh_suffix_args);
971     GNUNET_free (port);
972     GNUNET_free (dst);
973     cp->helper =
974         GNUNET_HELPER_start (GNUNET_NO, cp->helper_argv[0], cp->helper_argv, &helper_mst,
975                              &helper_exp_cb, cp);
976     GNUNET_free (helper_binary_path_args[0]);
977   }
978   if (NULL == cp->helper)
979   {
980     if (NULL != cp->helper_argv)
981       free_argv (cp->helper_argv);
982     GNUNET_free (cp);
983     return NULL;
984   }
985   cp->host = host;
986   cp->cb = cb;
987   cp->cls = cls;
988   msg = GNUNET_TESTBED_create_helper_init_msg_ (trusted_ip, hostname, cfg);
989   cp->msg = &msg->header;
990   cp->shandle =
991       GNUNET_HELPER_send (cp->helper, &msg->header, GNUNET_NO, &clear_msg, cp);
992   if (NULL == cp->shandle)
993   {
994     GNUNET_free (msg);
995     GNUNET_TESTBED_controller_stop (cp);
996     return NULL;
997   }
998   return cp;
999 }
1000
1001
1002 /**
1003  * Stop the controller process (also will terminate all peers and controllers
1004  * dependent on this controller).  This function blocks until the testbed has
1005  * been fully terminated (!). The controller status cb from
1006  * GNUNET_TESTBED_controller_start() will not be called.
1007  *
1008  * @param cproc the controller process handle
1009  */
1010 void
1011 GNUNET_TESTBED_controller_stop (struct GNUNET_TESTBED_ControllerProc *cproc)
1012 {
1013   if (NULL != cproc->shandle)
1014     GNUNET_HELPER_send_cancel (cproc->shandle);
1015   if (NULL != cproc->helper)
1016     GNUNET_HELPER_soft_stop (cproc->helper);
1017   if (NULL != cproc->cfg)
1018     GNUNET_CONFIGURATION_destroy (cproc->cfg);
1019   if (NULL != cproc->helper_argv)
1020     free_argv (cproc->helper_argv);
1021   GNUNET_free (cproc);
1022 }
1023
1024
1025 /**
1026  * The handle for whether a host is habitable or not
1027  */
1028 struct GNUNET_TESTBED_HostHabitableCheckHandle
1029 {
1030   /**
1031    * The host to check
1032    */
1033   const struct GNUNET_TESTBED_Host *host;
1034
1035   /* /\** */
1036   /*  * the configuration handle to lookup the path of the testbed helper */
1037   /*  *\/ */
1038   /* const struct GNUNET_CONFIGURATION_Handle *cfg; */
1039
1040   /**
1041    * The callback to call once we have the status
1042    */
1043   GNUNET_TESTBED_HostHabitableCallback cb;
1044
1045   /**
1046    * The callback closure
1047    */
1048   void *cb_cls;
1049
1050   /**
1051    * The process handle for the SSH process
1052    */
1053   struct GNUNET_OS_Process *auxp;
1054
1055   /**
1056    * The arguments used to start the helper
1057    */
1058   char **helper_argv;
1059
1060   /**
1061    * Task id for the habitability check task
1062    */
1063   GNUNET_SCHEDULER_TaskIdentifier habitability_check_task;
1064
1065   /**
1066    * How long we wait before checking the process status. Should grow
1067    * exponentially
1068    */
1069   struct GNUNET_TIME_Relative wait_time;
1070
1071 };
1072
1073
1074 /**
1075  * Task for checking whether a host is habitable or not
1076  *
1077  * @param cls GNUNET_TESTBED_HostHabitableCheckHandle
1078  * @param tc the scheduler task context
1079  */
1080 static void
1081 habitability_check (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1082 {
1083   struct GNUNET_TESTBED_HostHabitableCheckHandle *h = cls;
1084   void *cb_cls;
1085   GNUNET_TESTBED_HostHabitableCallback cb;
1086   const struct GNUNET_TESTBED_Host *host;
1087   unsigned long code;
1088   enum GNUNET_OS_ProcessStatusType type;
1089   int ret;
1090
1091   h->habitability_check_task = GNUNET_SCHEDULER_NO_TASK;
1092   ret = GNUNET_OS_process_status (h->auxp, &type, &code);
1093   if (GNUNET_SYSERR == ret)
1094   {
1095     GNUNET_break (0);
1096     ret = GNUNET_NO;
1097     goto call_cb;
1098   }
1099   if (GNUNET_NO == ret)
1100   {
1101     h->wait_time = GNUNET_TIME_STD_BACKOFF (h->wait_time);
1102     h->habitability_check_task =
1103         GNUNET_SCHEDULER_add_delayed (h->wait_time, &habitability_check, h);
1104     return;
1105   }
1106   GNUNET_OS_process_destroy (h->auxp);
1107   h->auxp = NULL;
1108   ret = (0 != code) ? GNUNET_NO : GNUNET_YES;
1109
1110 call_cb:
1111   if (NULL != h->auxp)
1112     GNUNET_OS_process_destroy (h->auxp);
1113   cb = h->cb;
1114   cb_cls = h->cb_cls;
1115   host = h->host;
1116   GNUNET_free (h);
1117   if (NULL != cb)
1118     cb (cb_cls, host, ret);
1119 }
1120
1121
1122 /**
1123  * Checks whether a host can be used to start testbed service
1124  *
1125  * @param host the host to check
1126  * @param config the configuration handle to lookup the path of the testbed
1127  *          helper
1128  * @param cb the callback to call to inform about habitability of the given host
1129  * @param cb_cls the closure for the callback
1130  * @return NULL upon any error or a handle which can be passed to
1131  *           GNUNET_TESTBED_is_host_habitable_cancel()
1132  */
1133 struct GNUNET_TESTBED_HostHabitableCheckHandle *
1134 GNUNET_TESTBED_is_host_habitable (const struct GNUNET_TESTBED_Host *host,
1135                                   const struct GNUNET_CONFIGURATION_Handle
1136                                   *config,
1137                                   GNUNET_TESTBED_HostHabitableCallback cb,
1138                                   void *cb_cls)
1139 {
1140   struct GNUNET_TESTBED_HostHabitableCheckHandle *h;
1141   char **rsh_args;
1142   char **rsh_suffix_args;
1143   char *stat_args[3];
1144   const char *hostname;
1145   char *port;
1146   char *dst;
1147
1148   h = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_HostHabitableCheckHandle));
1149   h->cb = cb;
1150   h->cb_cls = cb_cls;
1151   h->host = host;
1152   hostname = (NULL == host->hostname) ? "127.0.0.1" : host->hostname;
1153   if (NULL == host->username)
1154     dst = GNUNET_strdup (hostname);
1155   else
1156     GNUNET_asprintf (&dst, "%s@%s", host->username, hostname);
1157   if (GNUNET_OK !=
1158       GNUNET_CONFIGURATION_get_value_string (config, "testbed",
1159                                              "HELPER_BINARY_PATH",
1160                                              &stat_args[1]))
1161     stat_args[1] =
1162         GNUNET_OS_get_libexec_binary_path (HELPER_TESTBED_BINARY);  
1163   GNUNET_asprintf (&port, "%u", host->port);
1164   rsh_args = gen_rsh_args (port, dst);
1165   GNUNET_free (port);
1166   GNUNET_free (dst);
1167   port = NULL;
1168   dst = NULL;
1169   stat_args[0] = "stat";
1170   stat_args[2] = NULL;
1171   rsh_suffix_args = gen_rsh_suffix_args ((const char **) stat_args);
1172   h->helper_argv = join_argv ((const char **) rsh_args,
1173                               (const char **) rsh_suffix_args);
1174   GNUNET_free (rsh_suffix_args);
1175   GNUNET_free (rsh_args);
1176   h->auxp =
1177       GNUNET_OS_start_process_vap (GNUNET_NO, GNUNET_OS_INHERIT_STD_ERR, NULL,
1178                                    NULL, h->helper_argv[0], h->helper_argv);
1179   if (NULL == h->auxp)
1180   {
1181     GNUNET_break (0);           /* Cannot exec SSH? */
1182     GNUNET_free (h);
1183     return NULL;
1184   }
1185   h->wait_time = GNUNET_TIME_STD_BACKOFF (h->wait_time);
1186   h->habitability_check_task =
1187       GNUNET_SCHEDULER_add_delayed (h->wait_time, &habitability_check, h);
1188   return h;
1189 }
1190
1191
1192 /**
1193  * Function to cancel a request started using GNUNET_TESTBED_is_host_habitable()
1194  *
1195  * @param handle the habitability check handle
1196  */
1197 void
1198 GNUNET_TESTBED_is_host_habitable_cancel (struct
1199                                          GNUNET_TESTBED_HostHabitableCheckHandle
1200                                          *handle)
1201 {
1202   GNUNET_SCHEDULER_cancel (handle->habitability_check_task);
1203   (void) GNUNET_OS_process_kill (handle->auxp, SIGTERM);
1204   (void) GNUNET_OS_process_wait (handle->auxp);
1205   GNUNET_OS_process_destroy (handle->auxp);
1206   free_argv (handle->helper_argv);
1207   GNUNET_free (handle);
1208 }
1209
1210
1211 /**
1212  * handle for host registration
1213  */
1214 struct GNUNET_TESTBED_HostRegistrationHandle
1215 {
1216   /**
1217    * The host being registered
1218    */
1219   struct GNUNET_TESTBED_Host *host;
1220
1221   /**
1222    * The controller at which this host is being registered
1223    */
1224   struct GNUNET_TESTBED_Controller *c;
1225
1226   /**
1227    * The Registartion completion callback
1228    */
1229   GNUNET_TESTBED_HostRegistrationCompletion cc;
1230
1231   /**
1232    * The closure for above callback
1233    */
1234   void *cc_cls;
1235 };
1236
1237
1238 /**
1239  * Register a host with the controller
1240  *
1241  * @param controller the controller handle
1242  * @param host the host to register
1243  * @param cc the completion callback to call to inform the status of
1244  *          registration. After calling this callback the registration handle
1245  *          will be invalid. Cannot be NULL.
1246  * @param cc_cls the closure for the cc
1247  * @return handle to the host registration which can be used to cancel the
1248  *           registration
1249  */
1250 struct GNUNET_TESTBED_HostRegistrationHandle *
1251 GNUNET_TESTBED_register_host (struct GNUNET_TESTBED_Controller *controller,
1252                               struct GNUNET_TESTBED_Host *host,
1253                               GNUNET_TESTBED_HostRegistrationCompletion cc,
1254                               void *cc_cls)
1255 {
1256   struct GNUNET_TESTBED_HostRegistrationHandle *rh;
1257   struct GNUNET_TESTBED_AddHostMessage *msg;
1258   const char *username;
1259   const char *hostname;
1260   char *config;
1261   char *cconfig;
1262   void *ptr;
1263   size_t cc_size;
1264   size_t config_size;
1265   uint16_t msg_size;
1266   uint16_t username_length;
1267   uint16_t hostname_length;
1268
1269   if (NULL != controller->rh)
1270     return NULL;
1271   hostname = GNUNET_TESTBED_host_get_hostname (host);
1272   if (GNUNET_YES == GNUNET_TESTBED_is_host_registered_ (host, controller))
1273   {
1274     LOG (GNUNET_ERROR_TYPE_WARNING, "Host hostname: %s already registered\n",
1275          (NULL == hostname) ? "localhost" : hostname);
1276     return NULL;
1277   }
1278   rh = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_HostRegistrationHandle));
1279   rh->host = host;
1280   rh->c = controller;
1281   GNUNET_assert (NULL != cc);
1282   rh->cc = cc;
1283   rh->cc_cls = cc_cls;
1284   controller->rh = rh;
1285   username = GNUNET_TESTBED_host_get_username_ (host);
1286   username_length = 0;
1287   if (NULL != username)
1288     username_length = strlen (username);
1289   GNUNET_assert (NULL != hostname); /* Hostname must be present */
1290   hostname_length = strlen (hostname);
1291   GNUNET_assert (NULL != host->cfg);
1292   config = GNUNET_CONFIGURATION_serialize (host->cfg, &config_size);
1293   cc_size = GNUNET_TESTBED_compress_config_ (config, config_size, &cconfig);
1294   GNUNET_free (config);
1295   msg_size = (sizeof (struct GNUNET_TESTBED_AddHostMessage));
1296   msg_size += username_length;
1297   msg_size += hostname_length;
1298   msg_size += cc_size;
1299   msg = GNUNET_malloc (msg_size);
1300   msg->header.size = htons (msg_size);
1301   msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_ADD_HOST);
1302   msg->host_id = htonl (GNUNET_TESTBED_host_get_id_ (host));
1303   msg->ssh_port = htons (GNUNET_TESTBED_host_get_ssh_port_ (host));
1304   ptr = &msg[1];
1305   if (NULL != username)
1306   {
1307     msg->username_length = htons (username_length);
1308     ptr = mempcpy (ptr, username, username_length);
1309   }
1310   msg->hostname_length = htons (hostname_length);
1311   ptr = mempcpy (ptr, hostname, hostname_length);
1312   msg->config_size = htons (config_size);
1313   ptr = mempcpy (ptr, cconfig, cc_size);
1314   GNUNET_assert ((ptr - (void *) msg) == msg_size);
1315   GNUNET_free (cconfig);
1316   GNUNET_TESTBED_queue_message_ (controller,
1317                                  (struct GNUNET_MessageHeader *) msg);
1318   return rh;
1319 }
1320
1321
1322 /**
1323  * Cancel the pending registration. Note that if the registration message is
1324  * already sent to the service the cancellation has only the effect that the
1325  * registration completion callback for the registration is never called.
1326  *
1327  * @param handle the registration handle to cancel
1328  */
1329 void
1330 GNUNET_TESTBED_cancel_registration (struct GNUNET_TESTBED_HostRegistrationHandle
1331                                     *handle)
1332 {
1333   if (handle != handle->c->rh)
1334   {
1335     GNUNET_break (0);
1336     return;
1337   }
1338   handle->c->rh = NULL;
1339   GNUNET_free (handle);
1340 }
1341
1342
1343 /**
1344  * Initializes the operation queue for parallel overlay connects
1345  *
1346  * @param h the host handle
1347  * @param npoc the number of parallel overlay connects - the queue size
1348  */
1349 void
1350 GNUNET_TESTBED_set_num_parallel_overlay_connects_ (struct
1351                                                    GNUNET_TESTBED_Host *h,
1352                                                    unsigned int npoc)
1353 {
1354   //fprintf (stderr, "%d", npoc);
1355   GNUNET_free_non_null (h->tslots);
1356   h->tslots_filled = 0;
1357   h->num_parallel_connects = npoc;
1358   h->tslots = GNUNET_malloc (npoc * sizeof (struct TimeSlot));
1359   GNUNET_TESTBED_operation_queue_reset_max_active_
1360       (h->opq_parallel_overlay_connect_operations, npoc);
1361 }
1362
1363
1364 /**
1365  * Returns a timing slot which will be exclusively locked
1366  *
1367  * @param h the host handle
1368  * @param key a pointer which is associated to the returned slot; should not be
1369  *          NULL. It serves as a key to determine the correct owner of the slot
1370  * @return the time slot index in the array of time slots in the controller
1371  *           handle
1372  */
1373 unsigned int
1374 GNUNET_TESTBED_get_tslot_ (struct GNUNET_TESTBED_Host *h, void *key)
1375 {
1376   unsigned int slot;
1377
1378   GNUNET_assert (NULL != h->tslots);
1379   GNUNET_assert (NULL != key);
1380   for (slot = 0; slot < h->num_parallel_connects; slot++)
1381     if (NULL == h->tslots[slot].key)
1382     {
1383       h->tslots[slot].key = key;
1384       return slot;
1385     }
1386   GNUNET_assert (0);            /* We should always find a free tslot */
1387 }
1388
1389
1390 /**
1391  * Decides whether any change in the number of parallel overlay connects is
1392  * necessary to adapt to the load on the system
1393  *
1394  * @param h the host handle
1395  */
1396 static void
1397 decide_npoc (struct GNUNET_TESTBED_Host *h)
1398 {
1399   struct GNUNET_TIME_Relative avg;
1400   int sd;
1401   unsigned int slot;
1402   unsigned int nvals;
1403
1404   if (h->tslots_filled != h->num_parallel_connects)
1405     return;
1406   avg = GNUNET_TIME_UNIT_ZERO;
1407   nvals = 0;
1408   for (slot = 0; slot < h->num_parallel_connects; slot++)
1409   {
1410     avg = GNUNET_TIME_relative_add (avg, h->tslots[slot].time);
1411     nvals += h->tslots[slot].nvals;
1412   }
1413   GNUNET_assert (nvals >= h->num_parallel_connects);
1414   avg = GNUNET_TIME_relative_divide (avg, nvals);
1415   GNUNET_assert (GNUNET_TIME_UNIT_FOREVER_REL.rel_value != avg.rel_value);
1416   sd = GNUNET_TESTBED_SD_deviation_factor_ (h->poc_sd, (unsigned int) avg.rel_value);
1417   if ( (sd <= 5) ||
1418        (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
1419                                        h->num_parallel_connects)) )
1420     GNUNET_TESTBED_SD_add_data_ (h->poc_sd, (unsigned int) avg.rel_value);
1421   if (GNUNET_SYSERR == sd)
1422   {
1423     GNUNET_TESTBED_set_num_parallel_overlay_connects_ (h,
1424                                                        h->num_parallel_connects);
1425     return;
1426   }
1427   GNUNET_assert (0 <= sd);
1428   if (0 == sd)
1429   {
1430     GNUNET_TESTBED_set_num_parallel_overlay_connects_ (h,
1431                                                        h->num_parallel_connects
1432                                                        * 2);
1433     return;
1434   }
1435   if (1 == sd)
1436   {
1437     GNUNET_TESTBED_set_num_parallel_overlay_connects_ (h,
1438                                                        h->num_parallel_connects
1439                                                        + 1);
1440     return;
1441   }
1442   if (1 == h->num_parallel_connects)
1443   {
1444     GNUNET_TESTBED_set_num_parallel_overlay_connects_ (h, 1);
1445     return;
1446   }
1447   if (2 == sd)
1448   {
1449     GNUNET_TESTBED_set_num_parallel_overlay_connects_ (h,
1450                                                        h->num_parallel_connects
1451                                                        - 1);
1452     return;
1453   }
1454   GNUNET_TESTBED_set_num_parallel_overlay_connects_ (h,
1455                                                      h->num_parallel_connects /
1456                                                      2);
1457 }
1458
1459
1460 /**
1461  * Releases a time slot thus making it available for be used again
1462  *
1463  * @param h the host handle
1464  * @param index the index of the the time slot
1465  * @param key the key to prove ownership of the timeslot
1466  * @return GNUNET_YES if the time slot is successfully removed; GNUNET_NO if the
1467  *           time slot cannot be removed - this could be because of the index
1468  *           greater than existing number of time slots or `key' being different
1469  */
1470 int
1471 GNUNET_TESTBED_release_time_slot_ (struct GNUNET_TESTBED_Host *h,
1472                                    unsigned int index, void *key)
1473 {
1474   struct TimeSlot *slot;
1475
1476   GNUNET_assert (NULL != key);
1477   if (index >= h->num_parallel_connects)
1478     return GNUNET_NO;
1479   slot = &h->tslots[index];
1480   if (key != slot->key)
1481     return GNUNET_NO;
1482   slot->key = NULL;
1483   return GNUNET_YES;
1484 }
1485
1486
1487 /**
1488  * Function to update a time slot
1489  *
1490  * @param h the host handle
1491  * @param index the index of the time slot to update
1492  * @param key the key to identify ownership of the slot
1493  * @param time the new time
1494  * @param failed should this reading be treated as coming from a fail event
1495  */
1496 void
1497 GNUNET_TESTBED_update_time_slot_ (struct GNUNET_TESTBED_Host *h,
1498                                   unsigned int index, void *key,
1499                                   struct GNUNET_TIME_Relative time, int failed)
1500 {
1501   struct TimeSlot *slot;
1502
1503   if (GNUNET_YES == failed)
1504   {
1505     if (1 == h->num_parallel_connects)
1506     {
1507       GNUNET_TESTBED_set_num_parallel_overlay_connects_ (h, 1);
1508       return;
1509     }
1510     GNUNET_TESTBED_set_num_parallel_overlay_connects_ (h,
1511                                                        h->num_parallel_connects
1512                                                        - 1);
1513   }
1514   if (GNUNET_NO == GNUNET_TESTBED_release_time_slot_ (h, index, key))
1515     return;
1516   slot = &h->tslots[index];
1517   slot->nvals++;
1518   if (GNUNET_TIME_UNIT_ZERO.rel_value == slot->time.rel_value)
1519   {
1520     slot->time = time;
1521     h->tslots_filled++;
1522     decide_npoc (h);
1523     return;
1524   }
1525   slot->time = GNUNET_TIME_relative_add (slot->time, time);
1526 }
1527
1528
1529 /**
1530  * Queues the given operation in the queue for parallel overlay connects of the
1531  * given host
1532  *
1533  * @param h the host handle
1534  * @param op the operation to queue in the given host's parally overlay connect
1535  *          queue 
1536  */
1537 void
1538 GNUNET_TESTBED_host_queue_oc_ (struct GNUNET_TESTBED_Host *h, 
1539                                struct GNUNET_TESTBED_Operation *op)
1540 {  
1541   GNUNET_TESTBED_operation_queue_insert_
1542       (h->opq_parallel_overlay_connect_operations, op);
1543 }
1544
1545
1546 /**
1547  * Handler for GNUNET_MESSAGE_TYPE_TESTBED_ADDHOSTCONFIRM message from
1548  * controller (testbed service)
1549  *
1550  * @param c the controller handler
1551  * @param msg message received
1552  * @return GNUNET_YES if we can continue receiving from service; GNUNET_NO if
1553  *           not
1554  */
1555 int
1556 GNUNET_TESTBED_host_handle_addhostconfirm_ (struct GNUNET_TESTBED_Controller *c,
1557                                             const struct
1558                                             GNUNET_TESTBED_HostConfirmedMessage
1559                                             *msg)
1560 {
1561   struct GNUNET_TESTBED_HostRegistrationHandle *rh;
1562   char *emsg;
1563   uint16_t msg_size;
1564
1565   rh = c->rh;
1566   if (NULL == rh)
1567   {
1568     return GNUNET_OK;
1569   }
1570   if (GNUNET_TESTBED_host_get_id_ (rh->host) != ntohl (msg->host_id))
1571   {
1572     LOG_DEBUG ("Mismatch in host id's %u, %u of host confirm msg\n",
1573                GNUNET_TESTBED_host_get_id_ (rh->host), ntohl (msg->host_id));
1574     return GNUNET_OK;
1575   }
1576   c->rh = NULL;
1577   msg_size = ntohs (msg->header.size);
1578   if (sizeof (struct GNUNET_TESTBED_HostConfirmedMessage) == msg_size)
1579   {
1580     LOG_DEBUG ("Host %u successfully registered\n", ntohl (msg->host_id));
1581     GNUNET_TESTBED_mark_host_registered_at_ (rh->host, c);
1582     rh->cc (rh->cc_cls, NULL);
1583     GNUNET_free (rh);
1584     return GNUNET_OK;
1585   }
1586   /* We have an error message */
1587   emsg = (char *) &msg[1];
1588   if ('\0' !=
1589       emsg[msg_size - sizeof (struct GNUNET_TESTBED_HostConfirmedMessage)])
1590   {
1591     GNUNET_break (0);
1592     GNUNET_free (rh);
1593     return GNUNET_NO;
1594   }
1595   LOG (GNUNET_ERROR_TYPE_ERROR, _("Adding host %u failed with error: %s\n"),
1596        ntohl (msg->host_id), emsg);
1597   rh->cc (rh->cc_cls, emsg);
1598   GNUNET_free (rh);
1599   return GNUNET_OK;
1600 }
1601
1602 /* end of testbed_api_hosts.c */