X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Ftestbed%2Ftestbed_api_hosts.c;h=42b8e38649c72044ba27b08777b51a8a736b1f83;hb=f4d040c0f0dd2fef3d73b1f4532c76219f760f75;hp=4d9fb2e618b3f4b50ee972ccf0a092a40ad81f98;hpb=a93954693fef730d7a41c168b4961d19e5dff90c;p=oweals%2Fgnunet.git diff --git a/src/testbed/testbed_api_hosts.c b/src/testbed/testbed_api_hosts.c index 4d9fb2e61..42b8e3864 100644 --- a/src/testbed/testbed_api_hosts.c +++ b/src/testbed/testbed_api_hosts.c @@ -26,12 +26,13 @@ * @author Christian Grothoff */ #include "platform.h" +#include "gnunet_util_lib.h" #include "gnunet_testbed_service.h" #include "gnunet_core_service.h" -#include "gnunet_constants.h" #include "gnunet_transport_service.h" -#include "gnunet_hello_lib.h" -#include "gnunet_container_lib.h" + +#include "testbed_api.h" +#include "testbed_api_hosts.h" /** * Generic logging shorthand @@ -54,7 +55,7 @@ struct RegisteredController * The controller at which this host is registered */ const struct GNUNET_TESTBED_Controller *controller; - + /** * The next ptr for DLL */ @@ -131,7 +132,7 @@ static uint32_t host_list_size; /** * Lookup a host by ID. - * + * * @param id global host ID assigned to the host; 0 is * reserved to always mean 'localhost' * @return handle to the host, NULL if host not found @@ -149,7 +150,7 @@ GNUNET_TESTBED_host_lookup_by_id_ (uint32_t id) * Create a host by ID; given this host handle, we could not * run peers at the host, but we can talk about the host * internally. - * + * * @param id global host ID assigned to the host; 0 is * reserved to always mean 'localhost' * @return handle to the host, NULL on error @@ -163,13 +164,13 @@ GNUNET_TESTBED_host_create_by_id_ (uint32_t id) /** * Obtain the host's unique global ID. - * + * * @param host handle to the host, NULL means 'localhost' * @return id global host ID assigned to the host (0 is * 'localhost', but then obviously not globally unique) */ uint32_t -GNUNET_TESTBED_host_get_id_ (const struct GNUNET_TESTBED_Host *host) +GNUNET_TESTBED_host_get_id_ (const struct GNUNET_TESTBED_Host * host) { return host->id; } @@ -177,7 +178,7 @@ GNUNET_TESTBED_host_get_id_ (const struct GNUNET_TESTBED_Host *host) /** * Obtain the host's hostname. - * + * * @param host handle to the host, NULL means 'localhost' * @return hostname of the host */ @@ -188,9 +189,22 @@ GNUNET_TESTBED_host_get_hostname_ (const struct GNUNET_TESTBED_Host *host) } +/** + * Obtain the host's hostname. + * + * @param host handle to the host, NULL means 'localhost' + * @return hostname of the host + */ +const char * +GNUNET_TESTBED_host_get_hostname (const struct GNUNET_TESTBED_Host *host) +{ + return GNUNET_TESTBED_host_get_hostname_ (host); +} + + /** * Obtain the host's username - * + * * @param host handle to the host, NULL means 'localhost' * @return username to login to the host */ @@ -203,12 +217,12 @@ GNUNET_TESTBED_host_get_username_ (const struct GNUNET_TESTBED_Host *host) /** * Obtain the host's ssh port - * + * * @param host handle to the host, NULL means 'localhost' * @return username to login to the host */ uint16_t -GNUNET_TESTBED_host_get_ssh_port_ (const struct GNUNET_TESTBED_Host *host) +GNUNET_TESTBED_host_get_ssh_port_ (const struct GNUNET_TESTBED_Host * host) { return host->port; } @@ -216,7 +230,7 @@ GNUNET_TESTBED_host_get_ssh_port_ (const struct GNUNET_TESTBED_Host *host) /** * Create a host to run peers and controllers on. - * + * * @param id global host ID assigned to the host; 0 is * reserved to always mean 'localhost' * @param hostname name of the host, use "NULL" for localhost @@ -225,29 +239,36 @@ GNUNET_TESTBED_host_get_ssh_port_ (const struct GNUNET_TESTBED_Host *host) * @return handle to the host, NULL on error */ struct GNUNET_TESTBED_Host * -GNUNET_TESTBED_host_create_with_id (uint32_t id, - const char *hostname, - const char *username, - uint16_t port) +GNUNET_TESTBED_host_create_with_id (uint32_t id, const char *hostname, + const char *username, uint16_t port) { struct GNUNET_TESTBED_Host *host; + uint32_t new_size; - if ((id < host_list_size) && (NULL != host_list[host_list_size])) + if ((id < host_list_size) && (NULL != host_list[id])) { - LOG (GNUNET_ERROR_TYPE_WARNING, "Host with id: %u already created\n"); + LOG (GNUNET_ERROR_TYPE_WARNING, "Host with id: %u already created\n", id); return NULL; } host = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_Host)); - host->hostname = hostname; - host->username = username; + host->hostname = (NULL != hostname) ? GNUNET_strdup (hostname) : NULL; + host->username = (NULL != username) ? GNUNET_strdup (username) : NULL; host->id = id; host->port = (0 == port) ? 22 : port; - if (id < host_list_size) + new_size = host_list_size; + while (id >= new_size) + new_size += HOST_LIST_GROW_STEP; + if (new_size != host_list_size) { - host_list_size += HOST_LIST_GROW_STEP; - host_list = GNUNET_realloc (host_list, sizeof (struct GNUNET_TESTBED_Host) - * host_list_size); + host_list = + GNUNET_realloc (host_list, + sizeof (struct GNUNET_TESTBED_Host *) * new_size); + (void) memset (&host_list[host_list_size], 0, + sizeof (struct GNUNET_TESTBED_Host *) * (new_size - + host_list_size)); + host_list_size = new_size; } + LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding host with id: %u\n", host->id); host_list[id] = host; return host; } @@ -255,24 +276,22 @@ GNUNET_TESTBED_host_create_with_id (uint32_t id, /** * Create a host to run peers and controllers on. - * + * * @param hostname name of the host, use "NULL" for localhost * @param username username to use for the login; may be NULL * @param port port number to use for ssh; use 0 to let ssh decide * @return handle to the host, NULL on error */ struct GNUNET_TESTBED_Host * -GNUNET_TESTBED_host_create (const char *hostname, - const char *username, - uint16_t port) +GNUNET_TESTBED_host_create (const char *hostname, const char *username, + uint16_t port) { static uint32_t uid_generator; if (NULL == hostname) return GNUNET_TESTBED_host_create_with_id (0, hostname, username, port); - return GNUNET_TESTBED_host_create_with_id (++uid_generator, - hostname, username, - port); + return GNUNET_TESTBED_host_create_with_id (++uid_generator, hostname, + username, port); } @@ -280,16 +299,91 @@ GNUNET_TESTBED_host_create (const char *hostname, * Load a set of hosts from a configuration file. * * @param filename file with the host specification - * @param hosts set to the hosts found in the file + * @param hosts set to the hosts found in the file; caller must free this if + * number of hosts returned is greater than 0 * @return number of hosts returned in 'hosts', 0 on error */ unsigned int GNUNET_TESTBED_hosts_load_from_file (const char *filename, - struct GNUNET_TESTBED_Host **hosts) + struct GNUNET_TESTBED_Host ***hosts) { - // see testing_group.c, GNUNET_TESTING_hosts_load - GNUNET_break (0); - return 0; + //struct GNUNET_TESTBED_Host **host_array; + struct GNUNET_TESTBED_Host *starting_host; + char *data; + char *buf; + char username[256]; + char hostname[256]; + uint64_t fs; + short int port; + int ret; + unsigned int offset; + unsigned int count; + + + GNUNET_assert (NULL != filename); + if (GNUNET_YES != GNUNET_DISK_file_test (filename)) + { + LOG (GNUNET_ERROR_TYPE_WARNING, _("Hosts file %s not found\n"), filename); + return 0; + } + if (GNUNET_OK != + GNUNET_DISK_file_size (filename, &fs, GNUNET_YES, GNUNET_YES)) + fs = 0; + if (0 == fs) + { + LOG (GNUNET_ERROR_TYPE_WARNING, _("Hosts file %s has no data\n"), filename); + return 0; + } + data = GNUNET_malloc (fs); + if (fs != GNUNET_DISK_fn_read (filename, data, fs)) + { + GNUNET_free (data); + LOG (GNUNET_ERROR_TYPE_WARNING, _("Hosts file %s cannot be read\n"), + filename); + return 0; + } + buf = data; + offset = 0; + starting_host = NULL; + count = 0; + while (offset < (fs - 1)) + { + offset++; + if (((data[offset] == '\n')) && (buf != &data[offset])) + { + data[offset] = '\0'; + ret = SSCANF (buf, "%255[a-zA-Z0-9_]@%255[a-zA-Z0-9.]:%5hd", + username, hostname, &port); + if (3 == ret) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Successfully read host %s, port %d and user %s from file\n", + hostname, port, username); + /* We store hosts in a static list; hence we only require the starting + host pointer in that list to access the newly created list of hosts */ + if (NULL == starting_host) + starting_host = GNUNET_TESTBED_host_create (hostname, username, + port); + else + (void) GNUNET_TESTBED_host_create (hostname, username, port); + count++; + } + else + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Error reading line `%s' in hostfile\n", buf); + buf = &data[offset + 1]; + } + else if ((data[offset] == '\n') || (data[offset] == '\0')) + buf = &data[offset + 1]; + } + GNUNET_free (data); + if (NULL == starting_host) + return 0; + *hosts = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_Host *) * count); + memcpy (*hosts, + &host_list[GNUNET_TESTBED_host_get_id_ (starting_host)], + sizeof (struct GNUNET_TESTBED_Host *) * count); + return count; } @@ -301,7 +395,7 @@ GNUNET_TESTBED_hosts_load_from_file (const char *filename, */ void GNUNET_TESTBED_host_destroy (struct GNUNET_TESTBED_Host *host) -{ +{ struct RegisteredController *rc; uint32_t id; @@ -309,138 +403,29 @@ GNUNET_TESTBED_host_destroy (struct GNUNET_TESTBED_Host *host) GNUNET_assert (host_list[host->id] == host); host_list[host->id] = NULL; /* clear registered controllers list */ - for (rc=host->rc_head; NULL != rc; rc=host->rc_head) + for (rc = host->rc_head; NULL != rc; rc = host->rc_head) { GNUNET_CONTAINER_DLL_remove (host->rc_head, host->rc_tail, rc); GNUNET_free (rc); } - for (id = 0; id < HOST_LIST_GROW_STEP; id++) + GNUNET_free_non_null ((char *) host->username); + GNUNET_free_non_null ((char *) host->hostname); + GNUNET_free (host); + while (host_list_size >= HOST_LIST_GROW_STEP) { - if ((host->id + id >= host_list_size) || (NULL != host_list[host->id + id])) + for (id = host_list_size - 1; id > host_list_size - HOST_LIST_GROW_STEP; + id--) + if (NULL != host_list[id]) + break; + if (id != host_list_size - HOST_LIST_GROW_STEP) + break; + if (NULL != host_list[id]) break; - } - if (HOST_LIST_GROW_STEP == id) - { host_list_size -= HOST_LIST_GROW_STEP; - host_list = GNUNET_realloc (host_list, host_list_size); - } - GNUNET_free (host); -} - - -/** - * Wrapper around GNUNET_HELPER_Handle - */ -struct GNUNET_TESTBED_HelperHandle -{ - /** - * The process handle - */ - struct GNUNET_OS_Process *process; - - /** - * Pipe connecting to stdin of the process. - */ - struct GNUNET_DISK_PipeHandle *cpipe; - - /** - * The port number for ssh; used for helpers starting ssh - */ - char *port; - - /** - * The ssh destination string; used for helpers starting ssh - */ - char *dst; -}; - - -/** - * 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 host host to use, use "NULL" for localhost - * @param binary_argv binary name and command-line arguments to give to the binary - * @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[]) -{ - struct GNUNET_TESTBED_HelperHandle *h; - unsigned int argc; - - argc = 0; - while (NULL != binary_argv[argc]) - argc++; - h = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_HelperHandle)); - h->cpipe = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_YES, GNUNET_NO); - if ((NULL == host) || (0 == host->id)) - { - h->process = GNUNET_OS_start_process_vap (GNUNET_YES, - h->cpipe, NULL, - "gnunet-service-testbed", - binary_argv); } - else - { - char *remote_args[argc + 6 + 1]; - unsigned int argp; - - GNUNET_asprintf (&h->port, "%d", host->port); - if (NULL == host->username) - GNUNET_asprintf (&h->dst, "%s", host->hostname); - else - GNUNET_asprintf (&h->dst, "%s@%s", host->hostname, host->username); - argp = 0; - remote_args[argp++] = "ssh"; - remote_args[argp++] = "-p"; - 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++] = NULL; - GNUNET_assert (argp == argc + 6 + 1); - h->process = GNUNET_OS_start_process_vap (GNUNET_YES, - h->cpipe, NULL, - "ssh", - remote_args); - } - if (NULL == h->process) - { - GNUNET_break (GNUNET_OK == GNUNET_DISK_pipe_close (h->cpipe)); - 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, GNUNET_DISK_PIPE_END_READ)); - return h; -} - - -/** - * Stops a helper in the HelperHandle using GNUNET_HELPER_stop - * - * @param handle the handle returned from GNUNET_TESTBED_host_start_ - */ -void -GNUNET_TESTBED_host_stop_ (struct GNUNET_TESTBED_HelperHandle *handle) -{ - GNUNET_break (GNUNET_OK == GNUNET_DISK_pipe_close (handle->cpipe)); - 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); - GNUNET_free_non_null (handle->port); - GNUNET_free_non_null (handle->dst); - GNUNET_free (handle); + host_list = + GNUNET_realloc (host_list, + sizeof (struct GNUNET_TESTBED_Host *) * host_list_size); } @@ -452,14 +437,14 @@ GNUNET_TESTBED_host_stop_ (struct GNUNET_TESTBED_HelperHandle *handle) */ void GNUNET_TESTBED_mark_host_registered_at_ (struct GNUNET_TESTBED_Host *host, - const struct GNUNET_TESTBED_Controller - * const controller) + const struct GNUNET_TESTBED_Controller + *const controller) { struct RegisteredController *rc; - - for (rc=host->rc_head; NULL != rc; rc=rc->next) + + for (rc = host->rc_head; NULL != rc; rc = rc->next) { - if (controller == rc->controller) /* already registered at controller */ + if (controller == rc->controller) /* already registered at controller */ { GNUNET_break (0); return; @@ -467,7 +452,6 @@ GNUNET_TESTBED_mark_host_registered_at_ (struct GNUNET_TESTBED_Host *host, } rc = GNUNET_malloc (sizeof (struct RegisteredController)); rc->controller = controller; - //host->controller = controller; GNUNET_CONTAINER_DLL_insert_tail (host->rc_head, host->rc_tail, rc); } @@ -481,14 +465,14 @@ GNUNET_TESTBED_mark_host_registered_at_ (struct GNUNET_TESTBED_Host *host, */ int GNUNET_TESTBED_is_host_registered_ (const struct GNUNET_TESTBED_Host *host, - const struct GNUNET_TESTBED_Controller - *const controller) + const struct GNUNET_TESTBED_Controller + *const controller) { struct RegisteredController *rc; - - for (rc=host->rc_head; NULL != rc; rc=rc->next) + + for (rc = host->rc_head; NULL != rc; rc = rc->next) { - if (controller == rc->controller) /* already registered at controller */ + if (controller == rc->controller) /* already registered at controller */ { return GNUNET_YES; } @@ -497,4 +481,75 @@ GNUNET_TESTBED_is_host_registered_ (const struct GNUNET_TESTBED_Host *host, } +/** + * 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 + * @return GNUNET_YES if testbed service can be started on the given host + * remotely; GNUNET_NO if not + */ +int +GNUNET_TESTBED_is_host_habitable (const struct GNUNET_TESTBED_Host *host, + const struct GNUNET_CONFIGURATION_Handle *config) +{ + char *remote_args[11]; + char *helper_binary_path; + char *portstr; + char *ssh_addr; + const char *hostname; + struct GNUNET_OS_Process *auxp; + unsigned long code; + enum GNUNET_OS_ProcessStatusType type; + int ret; + unsigned int argp; + + portstr = NULL; + ssh_addr = NULL; + hostname = (NULL == host->hostname) ? "127.0.0.1" : host->hostname; + if (NULL == host->username) + ssh_addr = GNUNET_strdup (hostname); + else + GNUNET_asprintf (&ssh_addr, "%s@%s", host->username, hostname); + if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (config, "testbed", + "HELPER_BINARY_PATH", + &helper_binary_path)) + helper_binary_path = GNUNET_OS_get_libexec_binary_path (HELPER_TESTBED_BINARY); + argp = 0; + remote_args[argp++] = "ssh"; + GNUNET_asprintf (&portstr, "%u", host->port); + remote_args[argp++] = "-p"; + remote_args[argp++] = portstr; + remote_args[argp++] = "-o"; + remote_args[argp++] = "BatchMode=yes"; + remote_args[argp++] = "-o"; + remote_args[argp++] = "NoHostAuthenticationForLocalhost=yes"; + remote_args[argp++] = ssh_addr; + remote_args[argp++] = "stat"; + remote_args[argp++] = helper_binary_path; + remote_args[argp++] = NULL; + GNUNET_assert (argp == 11); + auxp = + GNUNET_OS_start_process_vap (GNUNET_NO, GNUNET_OS_INHERIT_STD_ERR, NULL, + NULL, "ssh", remote_args); + if (NULL == auxp) + { + GNUNET_free (ssh_addr); + GNUNET_free (portstr); + return GNUNET_NO; + } + do + { + ret = GNUNET_OS_process_status (auxp, &type, &code); + GNUNET_assert (GNUNET_SYSERR != ret); + (void) usleep (300); + } + while (GNUNET_NO == ret); + GNUNET_OS_process_destroy (auxp); + GNUNET_free (ssh_addr); + GNUNET_free (portstr); + GNUNET_free (helper_binary_path); + return (0 != code) ? GNUNET_NO : GNUNET_YES; +} + /* end of testbed_api_hosts.c */