/**
- * Starts a controller process at the host
+ * Starts a controller process at the host. FIXME: add controller start callback
+ * with the configuration with which the controller is started
*
- * @param system used for reserving ports if host is NULL and to determine
- * which 'host' to set as TRUSTED ('controller') when starting testbed remotely
+ * @param controller_ip the ip address of the controller. Will be set as TRUSTED
+ * host when starting testbed controller at host
* @param host the host where the controller has to be started; NULL for localhost
- * @param cfg template configuration to use for the remote controller; will
- * be modified to contain the actual host/port/unixpath used for
- * the testbed service
+ * @param cfg template configuration to use for the remote controller; the
+ * remote controller will be started with a slightly modified
+ * configuration (port numbers, unix domain sockets and service home
+ * values are changed as per TESTING library on the remote host)
* @param cec function called if the contoller dies unexpectedly; will not be
* invoked after GNUNET_TESTBED_controller_stop, if 'cec' was called,
* GNUNET_TESTBED_controller_stop must no longer be called; will
* @return the controller process handle, NULL on errors
*/
struct GNUNET_TESTBED_ControllerProc *
-GNUNET_TESTBED_controller_start (struct GNUNET_TESTING_System *system,
+GNUNET_TESTBED_controller_start (const char *controller_ip,
struct GNUNET_TESTBED_Host *host,
- struct GNUNET_CONFIGURATION_Handle *cfg,
+ const struct GNUNET_CONFIGURATION_Handle *cfg,
GNUNET_TESTBED_ControllerErrorCallback cec,
void *cec_cls);
if ENABLE_TEST_RUN
TESTS = \
- test_testbed_api_hosts \
- test_testbed_api \
- test_gnunet_testbed_helper
+ test_testbed_api_hosts \
+ test_gnunet_testbed_helper
endif
test_testbed_api_hosts_SOURCES = \
* The client handle associated with this context
*/
struct GNUNET_SERVER_Client *client;
+
+ /**
+ * The network address of the master controller
+ */
+ char *master_ip;
+
+ /**
+ * The TESTING system handle for starting peers locally
+ */
+ struct GNUNET_TESTING_System *system;
/**
* Event mask of event to be responded in this context
/* Testing System */
/******************/
-/**
- * Handle to the local testing system - for starting peers locally
- */
-static struct GNUNET_TESTING_System *test_system;
-
/**
* Our configuration; we also use this as template for starting other controllers
*/
{
const struct GNUNET_TESTBED_InitMessage *msg;
struct GNUNET_TESTBED_Host *host;
+ void *addr;
+ size_t addrlen;
if (NULL != master_context)
{
master_context = GNUNET_malloc (sizeof (struct Context));
master_context->client = client;
master_context->host_id = ntohl (msg->host_id);
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_SERVER_client_get_address (client, &addr, &addrlen));
+ master_context->master_ip = GNUNET_malloc (NI_MAXHOST);
+ if (0 != getnameinfo (addr, addrlen, master_context->master_ip, NI_MAXHOST,
+ NULL, 0, NI_NUMERICHOST))
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ "Cannot determine the ip of master controller: %s\n", STRERROR (errno));
+ GNUNET_assert (0);
+ }
+ master_context->system =
+ GNUNET_TESTING_system_create ("testbed", master_context->master_ip);
host = GNUNET_TESTBED_host_create_with_id (master_context->host_id,
NULL, NULL, 0);
host_list_add (host);
if (1 == msg->is_subordinate)
{
slave->controller_proc =
- GNUNET_TESTBED_controller_start (test_system,
+ GNUNET_TESTBED_controller_start (master_context->master_ip,
host_list[delegated_host_id],
cfg, &slave_shutdown_handler,
slave);
peer->cfg = cfg;
peer->id = ntohl (msg->peer_id);
LOG_DEBUG ("Creating peer with id: %u\n", peer->id);
- peer->peer = GNUNET_TESTING_peer_configure (test_system, peer->cfg,
+ peer->peer = GNUNET_TESTING_peer_configure (master_context->system, peer->cfg,
peer->id,
NULL /* Peer id */,
&emsg);
LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down testbed service\n");
(void) GNUNET_CONTAINER_multihashmap_iterate (ss_map, &ss_map_free_iterator,
NULL);
- GNUNET_CONTAINER_multihashmap_destroy (ss_map);
- GNUNET_TESTING_system_destroy (test_system, GNUNET_YES);
+ GNUNET_CONTAINER_multihashmap_destroy (ss_map);
if (NULL != fh)
{
GNUNET_DISK_file_close (fh);
if (NULL != slave_list[id]->controller_proc)
GNUNET_TESTBED_controller_stop (slave_list[id]->controller_proc);
}
+ GNUNET_free_non_null (master_context->master_ip);
+ if (NULL != master_context->system)
+ GNUNET_TESTING_system_destroy (master_context->system, GNUNET_YES);
GNUNET_free_non_null (master_context);
}
&client_disconnect_cb,
NULL);
ss_map = GNUNET_CONTAINER_multihashmap_create (5);
- test_system = GNUNET_TESTING_system_create ("testbed", NULL);
-
fh = GNUNET_DISK_get_handle_from_native (stdin);
if (NULL == fh)
shutdown_task_id =
- GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
&shutdown_task,
NULL);
else
#define TIME_REL_SECS(sec) \
GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, sec)
-/**
- * The testing system we work with
- */
-struct GNUNET_TESTING_System *test_system;
-
/**
* Our localhost
*/
GNUNET_TESTBED_controller_stop (cp);
GNUNET_TESTBED_host_destroy (neighbour);
GNUNET_TESTBED_host_destroy (host);
- GNUNET_TESTING_system_destroy (test_system, GNUNET_YES);
}
{
uint64_t event_mask;
- test_system = GNUNET_TESTING_system_create ("test_testbed",
- "127.0.0.1");
host = GNUNET_TESTBED_host_create (NULL, NULL, 0);
GNUNET_assert (NULL != host);
cfg = GNUNET_CONFIGURATION_dup (config);
- cp = GNUNET_TESTBED_controller_start (test_system, host, cfg, NULL, NULL);
+ cp = GNUNET_TESTBED_controller_start ("127.0.0.1", host, cfg, NULL, NULL);
event_mask = 0;
event_mask |= (1L << GNUNET_TESTBED_ET_PEER_START);
event_mask |= (1L << GNUNET_TESTBED_ET_PEER_STOP);
*/
static struct GNUNET_TESTBED_HelperHandle *helper_handle;
+/**
+ * Global test status
+ */
+static int status;
+
+/**
+ * Shutdown task identifier
+ */
+GNUNET_SCHEDULER_TaskIdentifier shutdown_id;
/**
* The shutdown task
}
+/**
+ * Callback that will be called when the helper process dies. This is not called
+ * when the helper process is stoped using GNUNET_HELPER_stop()
+ *
+ * @param cls the closure from GNUNET_HELPER_start()
+ * @param h the handle representing the helper process. This handle is invalid
+ * in this callback. It is only presented for reference. No operations
+ * can be performed using it.
+ */
+static void
+exp_cb (void *cls, const struct GNUNET_HELPER_Handle *h)
+{
+ status = GNUNET_SYSERR;
+ GNUNET_SCHEDULER_cancel (shutdown_id);
+ GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
+}
+
+
/**
* Main run function.
*
run (void *cls, char *const *args, const char *cfgfile,
const struct GNUNET_CONFIGURATION_Handle *cfg)
{
- char *const binary_args[] = {"gnunet-service-testbed",
- NULL};
-
host = GNUNET_TESTBED_host_create ("localhost", NULL, 0);
GNUNET_assert (NULL != host);
GNUNET_assert (0 != GNUNET_TESTBED_host_get_id_ (host));
GNUNET_assert (NULL != host);
GNUNET_assert (0 == GNUNET_TESTBED_host_get_id_ (host));
GNUNET_assert (host == GNUNET_TESTBED_host_lookup_by_id_ (0));
- helper_handle = GNUNET_TESTBED_host_run_ (host, binary_args);
+ helper_handle = GNUNET_TESTBED_host_run_ ("127.0.0.1", host, cfg, &exp_cb, NULL);
GNUNET_assert (NULL != helper_handle);
- GNUNET_SCHEDULER_add_delayed (TIME_REL_SECS (1), &do_shutdown, NULL);
+ shutdown_id =
+ GNUNET_SCHEDULER_add_delayed (TIME_REL_SECS (2), &do_shutdown, NULL);
}
int main (int argc, char **argv)
{
- int ret;
-
char *const argv2[] = { "test_testbed_api_hosts",
"-c", "test_testbed_api.conf",
NULL
GNUNET_GETOPT_OPTION_END
};
- ret = GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, argv2,
- "test_testbed_api_hosts", "nohelp", options, &run, NULL);
-
- return GNUNET_OK == ret ? 0 : 1;
+ status = GNUNET_YES;
+ if (GNUNET_OK !=
+ GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, argv2,
+ "test_testbed_api_hosts", "nohelp",
+ options, &run, NULL))
+ return 1;
+ return (GNUNET_OK == status) ? 0 : 1;
}
* The closure for the above callback
*/
void *cec_cls;
-
- /**
- * The task id of the task that will be called when controller dies
- */
- GNUNET_SCHEDULER_TaskIdentifier controller_dead_task_id;
};
/**
- * The task which is run when a controller dies (its stdout is closed)
+ * Callback that will be called when the helper process dies. This is not called
+ * when the helper process is stoped using GNUNET_HELPER_stop()
*
- * @param cls the ControllerProc struct
- * @param tc the context
+ * @param cls the closure from GNUNET_HELPER_start()
+ * @param h the handle representing the helper process. This handle is invalid
+ * in this callback. It is only presented for reference. No operations
+ * can be performed using it.
*/
-static void
-controller_dead_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+static void
+controller_exp_cb (void *cls, const struct GNUNET_HELPER_Handle *h)
{
struct GNUNET_TESTBED_ControllerProc *cproc = cls;
- cproc->controller_dead_task_id = GNUNET_SCHEDULER_NO_TASK;
if (NULL != cproc->cec)
cproc->cec (cproc->cec_cls, NULL); /* FIXME: How to get the error message? */
}
/**
* Starts a controller process at the host
*
- * @param system used for reserving ports if host is NULL and to determine
- * which 'host' to set as TRUSTED ('controller') when starting testbed remotely
+ * @param controller_ip the ip address of the controller. Will be set as TRUSTED
+ * host when starting testbed controller at host
* @param host the host where the controller has to be started; NULL for localhost
- * @param cfg template configuration to use for the remote controller; will
- * be modified to contain the actual host/port/unixpath used for
- * the testbed service
+ * @param cfg template configuration to use for the remote controller; the
+ * remote controller will be started with a slightly modified
+ * configuration (port numbers, unix domain sockets and service home
+ * values are changed as per TESTING library on the remote host)
* @param cec function called if the contoller dies unexpectedly; will not be
* invoked after GNUNET_TESTBED_controller_stop, if 'cec' was called,
* GNUNET_TESTBED_controller_stop must no longer be called; will
* @return the controller process handle, NULL on errors
*/
struct GNUNET_TESTBED_ControllerProc *
-GNUNET_TESTBED_controller_start (struct GNUNET_TESTING_System *system,
+GNUNET_TESTBED_controller_start (const char *controller_ip,
struct GNUNET_TESTBED_Host *host,
- struct GNUNET_CONFIGURATION_Handle *cfg,
+ const struct GNUNET_CONFIGURATION_Handle *cfg,
GNUNET_TESTBED_ControllerErrorCallback cec,
void *cec_cls)
{
struct GNUNET_TESTBED_ControllerProc *cproc;
- const struct GNUNET_DISK_FileHandle *read_fh;
- char *cfg_filename;
-
- if ((NULL == host) || (0 == GNUNET_TESTBED_host_get_id_ (host)))
- {
- if (GNUNET_OK != GNUNET_TESTING_configuration_create (system, cfg))
- return NULL;
- GNUNET_assert
- (GNUNET_OK ==
- GNUNET_CONFIGURATION_get_value_string (cfg, "PATHS", "DEFAULTCONFIG",
- &cfg_filename));
- if (GNUNET_OK != GNUNET_CONFIGURATION_write (cfg, cfg_filename))
- {
- GNUNET_break (0);
- return NULL;
- }
- char * const binary_argv[] = {
- "gnunet-service-testbed",
- "-c", cfg_filename,
- NULL
- };
- cproc = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_ControllerProc));
- cproc->helper = GNUNET_TESTBED_host_run_ (host, binary_argv);
- GNUNET_free (cfg_filename);
- if (NULL == cproc->helper)
- {
- GNUNET_free (cproc);
- return NULL;
- }
- }
- else
+
+ cproc = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_ControllerProc));
+ cproc->helper = GNUNET_TESTBED_host_run_ (controller_ip, host, cfg,
+ &controller_exp_cb, cproc);
+ if (NULL == cproc->helper)
{
- GNUNET_break (0); /* FIXME: start controller remotely */
+ GNUNET_free (cproc);
return NULL;
}
- read_fh = GNUNET_DISK_pipe_handle (cproc->helper->cpipe_out,
- GNUNET_DISK_PIPE_END_READ);
- if (NULL == read_fh)
- {
- GNUNET_break (0); // we can't catch the process
- }
cproc->cec = cec;
cproc->cec_cls = cec_cls;
- cproc->controller_dead_task_id =
- GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, read_fh,
- &controller_dead_task, cproc);
return cproc;
}
void
GNUNET_TESTBED_controller_stop (struct GNUNET_TESTBED_ControllerProc *cproc)
{
- if (GNUNET_SCHEDULER_NO_TASK != cproc->controller_dead_task_id)
- {
- GNUNET_SCHEDULER_cancel (cproc->controller_dead_task_id);
- cproc->controller_dead_task_id = GNUNET_SCHEDULER_NO_TASK;
- }
GNUNET_TESTBED_host_stop_ (cproc->helper);
GNUNET_free (cproc);
}
#include "testbed_api.h"
#include "testbed_api_hosts.h"
+#include "testbed_helper.h"
/**
* Generic logging shorthand
}
+/**
+ * Continuation function from GNUNET_HELPER_send()
+ *
+ * @param cls closure
+ * @param result GNUNET_OK on success,
+ * GNUNET_NO if helper process died
+ * GNUNET_SYSERR during GNUNET_HELPER_stop
+ */
+static void
+clear_msg (void *cls, int result)
+{
+ GNUNET_free (cls);
+}
+
+
+/**
+ * Callback that will be called when the helper process dies. This is not called
+ * when the helper process is stoped using GNUNET_HELPER_stop()
+ *
+ * @param cls the closure from GNUNET_HELPER_start()
+ * @param h the handle representing the helper process. This handle is invalid
+ * in this callback. It is only presented for reference. No operations
+ * can be performed using it.
+ */
+static void
+helper_exp_cb (void *cls, const struct GNUNET_HELPER_Handle *h)
+{
+ struct GNUNET_TESTBED_HelperHandle *handle = cls;
+
+ handle->is_stopped = GNUNET_YES;
+ GNUNET_TESTBED_host_stop_ (handle);
+ handle->exp_cb (handle->exp_cb_cls, h);
+}
+
+
/**
* Run a given helper process at the given host. Communication
* with the helper will be via GNUnet messages on stdin/stdout.
* Runs the process via 'ssh' at the specified host, or locally.
* Essentially an SSH-wrapper around the 'gnunet_helper_lib.h' API.
*
+ * @param controller_ip the ip address of the controller. Will be set as TRUSTED
+ * host when starting testbed controller at host
* @param host host to use, use "NULL" for localhost
- * @param binary_argv binary name and command-line arguments to give to the binary
+ * @param binary_argv binary name and command-line arguments to give to the
+ * binary
+ * @param cfg template configuration to use for the remote controller; the
+ * remote controller will be started with a slightly modified
+ * configuration (port numbers, unix domain sockets and service home
+ * values are changed as per TESTING library on the remote host)
+ * @param cb the callback to run when helper process dies; cannot be NULL
+ * @param cb_cls the closure for the above callback
* @return handle to terminate the command, NULL on error
*/
struct GNUNET_TESTBED_HelperHandle *
-GNUNET_TESTBED_host_run_ (const struct GNUNET_TESTBED_Host *host,
- char *const binary_argv[])
+GNUNET_TESTBED_host_run_ (const char *controller_ip,
+ const struct GNUNET_TESTBED_Host *host,
+ const struct GNUNET_CONFIGURATION_Handle *cfg,
+ GNUNET_HELPER_ExceptionCallback cb,
+ void *cb_cls)
{
- struct GNUNET_TESTBED_HelperHandle *h;
- unsigned int argc;
+ struct GNUNET_TESTBED_HelperHandle *h;
+ struct GNUNET_TESTBED_HelperInit *msg;
- argc = 0;
- while (NULL != binary_argv[argc])
- argc++;
+ GNUNET_assert (NULL != cb);
h = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_HelperHandle));
- h->cpipe_in = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_YES, GNUNET_NO);
- h->cpipe_out = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_NO, GNUNET_YES);
- if ((NULL == h->cpipe_in) || (NULL == h->cpipe_out))
- {
- GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
- "pipe");
- GNUNET_free (h);
- return NULL;
- }
+ h->exp_cb = cb;
+ h->exp_cb_cls = cb_cls;
+ h->is_stopped = GNUNET_NO;
if ((NULL == host) || (0 == host->id))
{
- h->process = GNUNET_OS_start_process_vap (GNUNET_YES,
- GNUNET_OS_INHERIT_STD_ALL,
- h->cpipe_in, h->cpipe_out,
- "gnunet-service-testbed",
- binary_argv);
+ char * const binary_argv[] = {
+ "gnunet-testbed-helper", NULL
+ };
+
+ h->helper =
+ GNUNET_HELPER_start ("gnunet-testbed-helper", binary_argv, NULL, &helper_exp_cb, h);
}
else
{
- char *remote_args[argc + 6 + 1];
+ char *remote_args[6 + 1];
unsigned int argp;
GNUNET_asprintf (&h->port, "%d", host->port);
remote_args[argp++] = h->port;
remote_args[argp++] = "-q";
remote_args[argp++] = h->dst;
- remote_args[argp++] = "gnunet-service-testbed";
- while (NULL != binary_argv[argp-6])
- {
- remote_args[argp] = binary_argv[argp - 6];
- argp++;
- }
+ remote_args[argp++] = "gnunet-testbed-helper";
remote_args[argp++] = NULL;
- GNUNET_assert (argp == argc + 6 + 1);
- h->process = GNUNET_OS_start_process_vap (GNUNET_YES,
- GNUNET_OS_INHERIT_STD_ALL,
- h->cpipe_in, NULL,
- "ssh",
- remote_args);
+ GNUNET_assert (argp == 6 + 1);
+ h->helper = GNUNET_HELPER_start ("ssh", remote_args, NULL, &helper_exp_cb, h);
}
- if (NULL == h->process)
+ msg = GNUNET_TESTBED_create_helper_init_msg_ (controller_ip, cfg);
+ if ((NULL == h->helper) ||
+ (NULL == (h->helper_shandle = GNUNET_HELPER_send (h->helper, &msg->header, GNUNET_NO,
+ &clear_msg, msg))))
{
- GNUNET_break (GNUNET_OK == GNUNET_DISK_pipe_close (h->cpipe_in));
+ GNUNET_free (msg);
GNUNET_free_non_null (h->port);
GNUNET_free_non_null (h->dst);
GNUNET_free (h);
return NULL;
}
- GNUNET_break (GNUNET_OK == GNUNET_DISK_pipe_close_end (h->cpipe_in, GNUNET_DISK_PIPE_END_READ));
return h;
}
void
GNUNET_TESTBED_host_stop_ (struct GNUNET_TESTBED_HelperHandle *handle)
{
- GNUNET_break (GNUNET_OK == GNUNET_DISK_pipe_close (handle->cpipe_in));
- GNUNET_break (GNUNET_OK == GNUNET_DISK_pipe_close (handle->cpipe_out));
- GNUNET_break (0 == GNUNET_OS_process_kill (handle->process, SIGTERM));
- GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (handle->process));
- GNUNET_OS_process_destroy (handle->process);
+ if (GNUNET_YES != handle->is_stopped)
+ GNUNET_HELPER_stop (handle->helper);
GNUNET_free_non_null (handle->port);
GNUNET_free_non_null (handle->dst);
GNUNET_free (handle);
/**
* The process handle
*/
- struct GNUNET_OS_Process *process;
+ struct GNUNET_HELPER_Handle *helper;
/**
- * Pipe connecting to stdin of the process.
+ * The send handle for the helper
*/
- struct GNUNET_DISK_PipeHandle *cpipe_in;
-
- /**
- * Pipe from the stdout of the process.
- */
- struct GNUNET_DISK_PipeHandle *cpipe_out;
+ struct GNUNET_HELPER_SendHandle *helper_shandle;
/**
* The port number for ssh; used for helpers starting ssh
/**
* The ssh destination string; used for helpers starting ssh
*/
- char *dst;
+ char *dst;
+
+ /**
+ * The helper exception callback
+ */
+ GNUNET_HELPER_ExceptionCallback exp_cb;
+
+ /**
+ * The closure for exp_cb
+ */
+ void *exp_cb_cls;
+
+ /**
+ * Is the helper stopped?
+ */
+ int is_stopped;
};
* Runs the process via 'ssh' at the specified host, or locally.
* Essentially an SSH-wrapper around the 'gnunet_helper_lib.h' API.
*
+ * @param controller_ip the ip address of the controller. Will be set as TRUSTED
+ * host when starting testbed controller at host
* @param host host to use, use "NULL" for localhost
- * @param binary_argv binary name and command-line arguments to give to the binary
+ * @param binary_argv binary name and command-line arguments to give to the
+ * binary
+ * @param cfg template configuration to use for the remote controller; the
+ * remote controller will be started with a slightly modified
+ * configuration (port numbers, unix domain sockets and service home
+ * values are changed as per TESTING library on the remote host)
+ * @param cb the callback to run when helper process dies; cannot be NULL
+ * @param cb_cls the closure for the above callback
* @return handle to terminate the command, NULL on error
*/
struct GNUNET_TESTBED_HelperHandle *
-GNUNET_TESTBED_host_run_ (const struct GNUNET_TESTBED_Host *host,
- char *const binary_argv[]);
+GNUNET_TESTBED_host_run_ (const char *controller_ip,
+ const struct GNUNET_TESTBED_Host *host,
+ const struct GNUNET_CONFIGURATION_Handle *cfg,
+ GNUNET_HELPER_ExceptionCallback cb,
+ void *cb_cls);
/**
*/
struct GNUNET_TESTBED_HelperInit *
GNUNET_TESTBED_create_helper_init_msg_ (const char *cname,
- const struct GNUNET_CONFIGURATION_Handle *cfg);
+ const struct GNUNET_CONFIGURATION_Handle *cfg);