From: Christian Grothoff Date: Thu, 14 Jun 2012 09:25:54 +0000 (+0000) Subject: -testbed hackery X-Git-Tag: initial-import-from-subversion-38251~13073 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=da1f2411d623d100d9df6a72c6081ccaccc23d13;p=oweals%2Fgnunet.git -testbed hackery --- diff --git a/src/include/gnunet_testbed_service.h b/src/include/gnunet_testbed_service.h index 6b50efe97..a3f092172 100644 --- a/src/include/gnunet_testbed_service.h +++ b/src/include/gnunet_testbed_service.h @@ -88,6 +88,26 @@ GNUNET_TESTBED_host_create (const char *hostname, uint16_t port); + +/** + * Create a host to run peers and controllers on. This function is used + * if a peer learns about a host via IPC between controllers (and thus + * some higher-level controller has already determined the unique IDs). + * + * @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 + * @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_with_id (uint32_t id, + const char *hostname, + const char *username, + uint16_t port); + + /** * Load a set of hosts from a configuration file. * @@ -785,7 +805,6 @@ GNUNET_TESTBED_overlay_configure_topology (void *op_cls, ...); - /** * Ask the testbed controller to write the current overlay topology to * a file. Naturally, the file will only contain a snapshot as the diff --git a/src/testbed/gnunet-service-testbed.c b/src/testbed/gnunet-service-testbed.c index 665af9d3a..327daf584 100644 --- a/src/testbed/gnunet-service-testbed.c +++ b/src/testbed/gnunet-service-testbed.c @@ -54,6 +54,11 @@ struct Context }; +/** + * Wrapped stdin. + */ +static struct GNUNET_DISK_FileHandle *fh; + /** * The master context; generated with the first INIT message */ @@ -139,8 +144,13 @@ handle_addhost (void *cls, host = GNUNET_TESTBED_host_create (hostname, username, ntohs (msg->ssh_port)); /* Store host in a hashmap? But the host_id will be different */ + /* hashmap? maybe array? 4-8 bytes/host and O(1) lookup vs. + > 80 bytes for hash map with slightly worse lookup; only + if we really get a tiny fraction of the hosts, the hash + map would result in any savings... (GNUNET_array_grow) */ } + /** * Task to clean up and shutdown nicely * @@ -151,8 +161,16 @@ static void shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { + shutdown_task_id = GNUNET_SCHEDULER_NO_TASK; + GNUNET_SCHEDULER_shutdown (); LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down testbed service\n"); + if (NULL != fh) + { + GNUNET_DISK_file_close (fh); + fh = NULL; + } GNUNET_free_non_null (master_context); + master_context = NULL; } @@ -171,9 +189,12 @@ client_disconnect_cb (void *cls, struct GNUNET_SERVER_Client *client) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Master client disconnected\n"); GNUNET_SERVER_client_drop (client); - GNUNET_SCHEDULER_cancel (shutdown_task_id); - shutdown_task_id = - GNUNET_SCHEDULER_add_now (&shutdown_task, NULL); + /* should not be needed as we're terminated by failure to read + from stdin, but if stdin fails for some reason, this shouldn't + hurt for now --- might need to revise this later if we ever + decide that master connections might be temporarily down + for some reason */ + GNUNET_SCHEDULER_shutdown (); } } @@ -202,11 +223,19 @@ testbed_run (void *cls, message_handlers); GNUNET_SERVER_disconnect_notify (server, &client_disconnect_cb, - NULL); - shutdown_task_id = - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, - &shutdown_task, - NULL); + NULL); + fh = GNUNET_DISK_get_handle_from_native (stdin); + if (NULL == fh) + shutdown_task_id = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, + &shutdown_task, + NULL); + else + shutdown_task_id = + GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, + fh, + &shutdown_task, + NULL); } diff --git a/src/testbed/testbed_api.c b/src/testbed/testbed_api.c index 5d34640fa..3f49890c4 100644 --- a/src/testbed/testbed_api.c +++ b/src/testbed/testbed_api.c @@ -123,9 +123,37 @@ struct GNUNET_TESTBED_Controller * The controller event mask */ uint64_t event_mask; + + /** + * Did we start the receive loop yet? + */ + int in_receive; }; + +/** + * Handler for messages from controller (testbed service) + * + * @param cls the controller handler + * @param msg message received, NULL on timeout or fatal error + */ +static void +message_handler (void *cls, const struct GNUNET_MessageHeader *msg) +{ + struct GNUNET_TESTBED_Controller *c = cls; + + /* FIXME: Add checks for message integrity */ + switch (ntohs (msg->type)) + { + default: + GNUNET_break (0); + } + GNUNET_CLIENT_receive (c->client, &message_handler, c, + GNUNET_TIME_UNIT_FOREVER_REL); +} + + /** * Function called to notify a client about the connection begin ready to queue * more data. "buf" will be NULL and "size" zero if the connection was closed @@ -159,6 +187,13 @@ transmit_ready_notify (void *cls, size_t size, void *buf) GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_NO, &transmit_ready_notify, c); + if ( (GNUNET_NO == c->in_receive) && + (size > 0) ) + { + c->in_receive = GNUNET_YES; + GNUNET_CLIENT_receive (c->client, &message_handler, c, + GNUNET_TIME_UNIT_FOREVER_REL); + } return size; } @@ -197,61 +232,6 @@ queue_message (struct GNUNET_TESTBED_Controller *controller, } -/** - * Handler for messages from controller (testbed service) - * - * @param cls the controller handler - * @param msg message received, NULL on timeout or fatal error - */ -static void -message_handler (void *cls, const struct GNUNET_MessageHeader *msg) -{ - struct GNUNET_TESTBED_Controller *c = cls; - - /* FIXME: Add checks for message integrity */ - switch (ntohs (msg->type)) - { - default: - GNUNET_break (0); - } - GNUNET_CLIENT_receive (c->client, &message_handler, c, - GNUNET_TIME_UNIT_FOREVER_REL); -} - - -/** - * ?Callback for messages recevied from server? - * - * Do not call GNUNET_SERVER_mst_destroy in callback - * - * @param cls closure - * @param client identification of the client - * @param message the actual message - * - * @return GNUNET_OK on success, GNUNET_SYSERR to stop further processing - */ -static int -server_mst_cb (void *cls, void *client, - const struct GNUNET_MessageHeader *message) -{ - struct GNUNET_TESTBED_Controller *c = cls; - struct GNUNET_TESTBED_InitMessage *msg; - - c->client = GNUNET_CLIENT_connect ("testbed", c->cfg); - if (NULL == c->client) - return GNUNET_SYSERR; /* FIXME: Call controller startup_cb ? */ - GNUNET_CLIENT_receive (c->client, &message_handler, c, - GNUNET_TIME_UNIT_FOREVER_REL); - msg = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_InitMessage)); - msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_INIT); - msg->header.size = htons (sizeof (struct GNUNET_TESTBED_InitMessage)); - msg->host_id = htonl (GNUNET_TESTBED_host_get_id_ (c->host)); - msg->event_mask = GNUNET_htonll (c->event_mask); - queue_message (c, (struct GNUNET_MessageHeader *) msg); - return GNUNET_OK; -} - - /** * Start a controller process using the given configuration at the * given host. @@ -279,9 +259,10 @@ GNUNET_TESTBED_controller_start (const struct GNUNET_CONFIGURATION_Handle *cfg, "gnunet-service-testbed", NULL }; + struct GNUNET_TESTBED_InitMessage *msg; + controller = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_Controller)); - controller->helper = GNUNET_TESTBED_host_run_ (host, binary_argv, - &server_mst_cb, controller); + controller->helper = GNUNET_TESTBED_host_run_ (host, binary_argv); if (NULL == controller->helper) { GNUNET_free (controller); @@ -292,6 +273,18 @@ GNUNET_TESTBED_controller_start (const struct GNUNET_CONFIGURATION_Handle *cfg, controller->cc_cls = cc_cls; controller->event_mask = event_mask; controller->cfg = GNUNET_CONFIGURATION_dup (cfg); + controller->client = GNUNET_CLIENT_connect ("testbed", controller->cfg); + if (NULL == controller->client) + { + GNUNET_TESTBED_controller_stop (controller); + return NULL; + } + msg = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_InitMessage)); + msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_INIT); + msg->header.size = htons (sizeof (struct GNUNET_TESTBED_InitMessage)); + msg->host_id = htonl (GNUNET_TESTBED_host_get_id_ (controller->host)); + msg->event_mask = GNUNET_htonll (controller->event_mask); + queue_message (controller, (struct GNUNET_MessageHeader *) msg); return controller; } @@ -338,7 +331,8 @@ GNUNET_TESTBED_controller_stop (struct GNUNET_TESTBED_Controller *controller) GNUNET_free (mq_entry->msg); GNUNET_free (mq_entry); } - GNUNET_CLIENT_disconnect (controller->client); + if (NULL != controller->client) + GNUNET_CLIENT_disconnect (controller->client); GNUNET_TESTBED_host_stop_ (controller->helper); GNUNET_CONFIGURATION_destroy (controller->cfg); GNUNET_free (controller); @@ -391,6 +385,7 @@ void GNUNET_TESTBED_overlay_write_topology_to_file (struct GNUNET_TESTBED_Controller *controller, const char *filename) { + GNUNET_break (0); } diff --git a/src/testbed/testbed_api_hosts.c b/src/testbed/testbed_api_hosts.c index a12d6ce11..c4dfcf3c9 100644 --- a/src/testbed/testbed_api_hosts.c +++ b/src/testbed/testbed_api_hosts.c @@ -132,7 +132,7 @@ GNUNET_TESTBED_host_create_by_id_ (uint32_t id) uint32_t GNUNET_TESTBED_host_get_id_ (const struct GNUNET_TESTBED_Host *host) { - return host->unique_id; + return host->unique_id; } @@ -147,10 +147,10 @@ GNUNET_TESTBED_host_get_id_ (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; @@ -180,10 +180,10 @@ GNUNET_TESTBED_host_create (const char *hostname, 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 (0, hostname, username, port); + return GNUNET_TESTBED_host_create_with_id (++uid_generator, + hostname, username, + port); } @@ -198,6 +198,7 @@ unsigned int GNUNET_TESTBED_hosts_load_from_file (const char *filename, struct GNUNET_TESTBED_Host **hosts) { + // see testing_group.c, GNUNET_TESTING_hosts_load GNUNET_break (0); return 0; } @@ -223,9 +224,14 @@ GNUNET_TESTBED_host_destroy (struct GNUNET_TESTBED_Host *host) struct GNUNET_TESTBED_HelperHandle { /** - * The helper handle + * The process handle */ - struct GNUNET_HELPER_Handle *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 @@ -247,39 +253,62 @@ struct GNUNET_TESTBED_HelperHandle * * @param host host to use, use "NULL" for localhost * @param binary_argv binary name and command-line arguments to give to the binary - * @param cb function to call for messages received from the binary - * @param cb_cls closure for cb * @return handle to terminate the command, NULL on error */ struct GNUNET_TESTBED_HelperHandle * -GNUNET_TESTBED_host_run_ (struct GNUNET_TESTBED_Host *host, - char *const binary_argv[], - GNUNET_SERVER_MessageTokenizerCallback cb, void *cb_cls) +GNUNET_TESTBED_host_run_ (const struct GNUNET_TESTBED_Host *host, + char *const binary_argv[]) { - /* FIXME: decide on the SSH command line, prepend it and - run GNUNET_HELPER_start with the modified binary_name and binary_argv! */ struct GNUNET_TESTBED_HelperHandle *h; - char *const local_args[] = {NULL}; + 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 (0 == host->unique_id) { - h->handle = GNUNET_HELPER_start ("gnunet-service-testbed", local_args, - cb, cb_cls); + 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); GNUNET_asprintf (&h->dst, "%s@%s", host->hostname, host->username); - char *remote_args[] = {"ssh", "-p", h->port, "-q", h->dst, - "gnunet-service-testbed", NULL}; - h->handle = GNUNET_HELPER_start ("ssh", remote_args, cb, cb_cls); + 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->handle) + 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; } @@ -292,7 +321,10 @@ GNUNET_TESTBED_host_run_ (struct GNUNET_TESTBED_Host *host, void GNUNET_TESTBED_host_stop_ (struct GNUNET_TESTBED_HelperHandle *handle) { - GNUNET_HELPER_stop (handle->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); diff --git a/src/testbed/testbed_api_hosts.h b/src/testbed/testbed_api_hosts.h index 0c36da0ee..eaf2a4d11 100644 --- a/src/testbed/testbed_api_hosts.h +++ b/src/testbed/testbed_api_hosts.h @@ -54,25 +54,6 @@ struct GNUNET_TESTBED_Host * GNUNET_TESTBED_host_create_by_id_ (uint32_t id); -/** - * Create a host to run peers and controllers on. This function is used - * if a peer learns about a host via IPC between controllers (and thus - * some higher-level controller has already determined the unique IDs). - * - * @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 - * @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_with_id_ (uint32_t id, - const char *hostname, - const char *username, - uint16_t port); - - /** * Obtain a host's unique global ID. * @@ -98,14 +79,11 @@ struct GNUNET_TESTBED_HelperHandle; * * @param host host to use, use "NULL" for localhost * @param binary_argv binary name and command-line arguments to give to the binary - * @param cb function to call for messages received from the binary - * @param cb_cls closure for cb * @return handle to terminate the command, NULL on error */ struct GNUNET_TESTBED_HelperHandle * -GNUNET_TESTBED_host_run_ (struct GNUNET_TESTBED_Host *host, - char *const binary_argv[], - GNUNET_SERVER_MessageTokenizerCallback cb, void *cb_cls); +GNUNET_TESTBED_host_run_ (const struct GNUNET_TESTBED_Host *host, + char *const binary_argv[]); /**