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