+ aux = argstr;
+ GNUNET_assert (0 < GNUNET_asprintf (&argstr, "%s %s", aux, cp->helper_argv[cnt]));
+ GNUNET_free (aux);
+ }
+ LOG_DEBUG ("Helper cmd str: %s\n", argstr);
+ GNUNET_free (argstr);
+ cp->helper =
+ GNUNET_HELPER_start (GNUNET_NO, cp->helper_argv[0], cp->helper_argv, &helper_mst,
+ &helper_exp_cb, cp);
+ GNUNET_free (helper_binary_path_args[0]);
+ }
+ if (NULL == cp->helper)
+ {
+ if (NULL != cp->helper_argv)
+ free_argv (cp->helper_argv);
+ GNUNET_free (cp);
+ return NULL;
+ }
+ cp->host = host;
+ cp->cb = cb;
+ cp->cls = cls;
+ msg = GNUNET_TESTBED_create_helper_init_msg_ (trusted_ip, hostname, cfg);
+ cp->msg = &msg->header;
+ cp->shandle =
+ GNUNET_HELPER_send (cp->helper, &msg->header, GNUNET_NO, &clear_msg, cp);
+ if (NULL == cp->shandle)
+ {
+ GNUNET_free (msg);
+ GNUNET_TESTBED_controller_stop (cp);
+ return NULL;
+ }
+ return cp;
+}
+
+
+/**
+ * Sends termination signal to the controller's helper process
+ *
+ * @param cproc the handle to the controller's helper process
+ */
+void
+GNUNET_TESTBED_controller_kill_ (struct GNUNET_TESTBED_ControllerProc *cproc)
+{
+ if (NULL != cproc->shandle)
+ GNUNET_HELPER_send_cancel (cproc->shandle);
+ if (NULL != cproc->helper)
+ GNUNET_HELPER_kill (cproc->helper, GNUNET_YES);
+}
+
+
+/**
+ * Cleans-up the controller's helper process handle
+ *
+ * @param cproc the handle to the controller's helper process
+ */
+void
+GNUNET_TESTBED_controller_destroy_ (struct GNUNET_TESTBED_ControllerProc *cproc)
+{
+ if (NULL != cproc->helper)
+ {
+ GNUNET_break (GNUNET_OK == GNUNET_HELPER_wait (cproc->helper));
+ GNUNET_HELPER_destroy (cproc->helper);
+ }
+ if (NULL != cproc->helper_argv)
+ free_argv (cproc->helper_argv);
+ cproc->host->controller_started = GNUNET_NO;
+ cproc->host->locked = GNUNET_NO;
+ GNUNET_free_non_null (cproc->msg);
+ GNUNET_free (cproc);
+}
+
+
+/**
+ * Stop the controller process (also will terminate all peers and controllers
+ * dependent on this controller). This function blocks until the testbed has
+ * been fully terminated (!). The controller status cb from
+ * GNUNET_TESTBED_controller_start() will not be called.
+ *
+ * @param cproc the controller process handle
+ */
+void
+GNUNET_TESTBED_controller_stop (struct GNUNET_TESTBED_ControllerProc *cproc)
+{
+ GNUNET_TESTBED_controller_kill_ (cproc);
+ GNUNET_TESTBED_controller_destroy_ (cproc);
+}
+
+
+/**
+ * The handle for whether a host is habitable or not
+ */
+struct GNUNET_TESTBED_HostHabitableCheckHandle
+{
+ /**
+ * The host to check
+ */
+ const struct GNUNET_TESTBED_Host *host;
+
+ /**
+ * The callback to call once we have the status
+ */
+ GNUNET_TESTBED_HostHabitableCallback cb;
+
+ /**
+ * The callback closure
+ */
+ void *cb_cls;
+
+ /**
+ * The process handle for the SSH process
+ */
+ struct GNUNET_OS_Process *auxp;
+
+ /**
+ * The arguments used to start the helper
+ */
+ char **helper_argv;
+
+ /**
+ * Task id for the habitability check task
+ */
+ GNUNET_SCHEDULER_TaskIdentifier habitability_check_task;
+
+ /**
+ * How long we wait before checking the process status. Should grow
+ * exponentially
+ */
+ struct GNUNET_TIME_Relative wait_time;
+
+};
+
+
+/**
+ * Task for checking whether a host is habitable or not
+ *
+ * @param cls GNUNET_TESTBED_HostHabitableCheckHandle
+ * @param tc the scheduler task context
+ */
+static void
+habitability_check (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct GNUNET_TESTBED_HostHabitableCheckHandle *h = cls;
+ void *cb_cls;
+ GNUNET_TESTBED_HostHabitableCallback cb;
+ const struct GNUNET_TESTBED_Host *host;
+ unsigned long code;
+ enum GNUNET_OS_ProcessStatusType type;
+ int ret;
+
+ h->habitability_check_task = GNUNET_SCHEDULER_NO_TASK;
+ ret = GNUNET_OS_process_status (h->auxp, &type, &code);
+ if (GNUNET_SYSERR == ret)
+ {
+ GNUNET_break (0);
+ ret = GNUNET_NO;
+ goto call_cb;
+ }
+ if (GNUNET_NO == ret)
+ {
+ h->wait_time = GNUNET_TIME_STD_BACKOFF (h->wait_time);
+ h->habitability_check_task =
+ GNUNET_SCHEDULER_add_delayed (h->wait_time, &habitability_check, h);
+ return;
+ }
+ GNUNET_OS_process_destroy (h->auxp);
+ h->auxp = NULL;
+ ret = (0 != code) ? GNUNET_NO : GNUNET_YES;
+
+call_cb:
+ if (NULL != h->auxp)
+ GNUNET_OS_process_destroy (h->auxp);
+ cb = h->cb;
+ cb_cls = h->cb_cls;
+ host = h->host;
+ free_argv (h->helper_argv);
+ GNUNET_free (h);
+ if (NULL != cb)
+ cb (cb_cls, host, ret);
+}
+
+
+/**
+ * Checks whether a host can be used to start testbed service
+ *
+ * @param host the host to check
+ * @param config the configuration handle to lookup the path of the testbed
+ * helper
+ * @param cb the callback to call to inform about habitability of the given host
+ * @param cb_cls the closure for the callback
+ * @return NULL upon any error or a handle which can be passed to
+ * GNUNET_TESTBED_is_host_habitable_cancel()
+ */
+struct GNUNET_TESTBED_HostHabitableCheckHandle *
+GNUNET_TESTBED_is_host_habitable (const struct GNUNET_TESTBED_Host *host,
+ const struct GNUNET_CONFIGURATION_Handle
+ *config,
+ GNUNET_TESTBED_HostHabitableCallback cb,
+ void *cb_cls)
+{
+ struct GNUNET_TESTBED_HostHabitableCheckHandle *h;
+ char **rsh_args;
+ char **rsh_suffix_args;
+ char *stat_args[3];
+ const char *hostname;
+ char *port;
+
+ h = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_HostHabitableCheckHandle));
+ h->cb = cb;
+ h->cb_cls = cb_cls;
+ h->host = host;
+ hostname = (NULL == host->hostname) ? "127.0.0.1" : host->hostname;
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_filename (config, "testbed",
+ "HELPER_BINARY_PATH",
+ &stat_args[1]))
+ stat_args[1] =
+ GNUNET_OS_get_libexec_binary_path (HELPER_TESTBED_BINARY);
+ GNUNET_asprintf (&port, "%u", host->port);
+ rsh_args = gen_rsh_args (port, hostname, host->username);
+ GNUNET_free (port);
+ port = NULL;
+ stat_args[0] = "stat";
+ stat_args[2] = NULL;
+ rsh_suffix_args = gen_rsh_suffix_args ((const char **) stat_args);
+ GNUNET_free (stat_args[1]);
+ h->helper_argv = join_argv ((const char **) rsh_args,
+ (const char **) rsh_suffix_args);
+ free_argv (rsh_suffix_args);
+ free_argv (rsh_args);
+ h->auxp =
+ GNUNET_OS_start_process_vap (GNUNET_NO, GNUNET_OS_INHERIT_STD_ERR, NULL,
+ NULL, h->helper_argv[0], h->helper_argv);
+ if (NULL == h->auxp)
+ {
+ GNUNET_break (0); /* Cannot exec SSH? */