X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Ftestbed%2Fgnunet-helper-testbed.c;h=f3c56eb9db7806a904bb636b7c47f62a3f261848;hb=5742938289524f4c5fba7883742e4dd69cccf11d;hp=4c78e325212e1a5217ca80cac28c875fbd1bb270;hpb=b9d47fab2e69e34326ec67bcf1144db45aef5b58;p=oweals%2Fgnunet.git diff --git a/src/testbed/gnunet-helper-testbed.c b/src/testbed/gnunet-helper-testbed.c index 4c78e3252..f3c56eb9d 100644 --- a/src/testbed/gnunet-helper-testbed.c +++ b/src/testbed/gnunet-helper-testbed.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet - (C) 2012 Christian Grothoff (and other contributing authors) + Copyright (C) 2008--2013 GNUnet e.V. GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published @@ -14,8 +14,8 @@ You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ /** @@ -24,12 +24,15 @@ * gnunet-service-testbed. This binary also receives configuration * from the remove controller which is put in a temporary location * with ports and paths fixed so that gnunet-service-testbed runs - * without any hurdles. - * + * without any hurdles. + * * This helper monitors for three termination events. They are: (1)The * stdin of the helper is closed for reading; (2)the helper received * SIGTERM/SIGINT; (3)the testbed crashed. In case of events 1 and 2 - * the helper kills the testbed service. + * the helper kills the testbed service. When testbed crashed (event + * 3), the helper should send a SIGTERM to its own process group; this + * behaviour will help terminate any child processes (peers) testbed + * has started and prevents them from leaking and running forever. * * @author Sree Harsha Totakura */ @@ -121,22 +124,17 @@ static struct GNUNET_DISK_PipeHandle *sigpipe; /** * Task identifier for the read task */ -static GNUNET_SCHEDULER_TaskIdentifier read_task_id; +static struct GNUNET_SCHEDULER_Task *read_task_id; /** * Task identifier for the write task */ -static GNUNET_SCHEDULER_TaskIdentifier write_task_id; +static struct GNUNET_SCHEDULER_Task *write_task_id; /** * Task to kill the child */ -static GNUNET_SCHEDULER_TaskIdentifier child_death_task_id; - -/** - * shutdown task id - */ -static GNUNET_SCHEDULER_TaskIdentifier shutdown_task_id; +static struct GNUNET_SCHEDULER_Task * child_death_task_id; /** * Are we done reading messages from stdin? @@ -153,32 +151,34 @@ static int status; * Task to shut down cleanly * * @param cls NULL - * @param tc the task context */ static void -shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +shutdown_task (void *cls) { - LOG_DEBUG ("Shutting down\n"); - shutdown_task_id = GNUNET_SCHEDULER_NO_TASK; + LOG_DEBUG ("Shutting down\n"); if (NULL != testbed) { LOG_DEBUG ("Killing testbed\n"); - GNUNET_break (0 == GNUNET_OS_process_kill (testbed, SIGTERM)); - } - if (GNUNET_SCHEDULER_NO_TASK != read_task_id) + GNUNET_break (0 == GNUNET_OS_process_kill (testbed, GNUNET_TERM_SIG)); + } + if (NULL != read_task_id) { GNUNET_SCHEDULER_cancel (read_task_id); - read_task_id = GNUNET_SCHEDULER_NO_TASK; + read_task_id = NULL; } - if (GNUNET_SCHEDULER_NO_TASK != write_task_id) + if (NULL != write_task_id) { - GNUNET_SCHEDULER_cancel (write_task_id); - write_task_id = GNUNET_SCHEDULER_NO_TASK; + struct WriteContext *wc; + + wc = GNUNET_SCHEDULER_cancel (write_task_id); + write_task_id = NULL; + GNUNET_free (wc->data); + GNUNET_free (wc); } - if (GNUNET_SCHEDULER_NO_TASK != child_death_task_id) + if (NULL != child_death_task_id) { GNUNET_SCHEDULER_cancel (child_death_task_id); - child_death_task_id = GNUNET_SCHEDULER_NO_TASK; + child_death_task_id = NULL; } if (NULL != stdin_fd) (void) GNUNET_DISK_file_close (stdin_fd); @@ -191,7 +191,7 @@ shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (testbed)); GNUNET_OS_process_destroy (testbed); testbed = NULL; - } + } if (NULL != test_system) { GNUNET_TESTING_system_destroy (test_system, GNUNET_YES); @@ -200,44 +200,26 @@ shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) } -/** - * Scheduler shutdown task to be run now. - */ -static void -shutdown_now (void) -{ - if (GNUNET_SCHEDULER_NO_TASK != shutdown_task_id) - GNUNET_SCHEDULER_cancel (shutdown_task_id); - shutdown_task_id = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL); -} - - /** * Task to write to the standard out * * @param cls the WriteContext - * @param tc the TaskContext */ static void -write_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +write_task (void *cls) { struct WriteContext *wc = cls; ssize_t bytes_wrote; GNUNET_assert (NULL != wc); - write_task_id = GNUNET_SCHEDULER_NO_TASK; - if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason)) - { - GNUNET_free (wc->data); - GNUNET_free (wc); - return; - } + write_task_id = NULL; bytes_wrote = GNUNET_DISK_file_write (stdout_fd, wc->data + wc->pos, wc->length - wc->pos); if (GNUNET_SYSERR == bytes_wrote) { - LOG (GNUNET_ERROR_TYPE_WARNING, "Cannot reply back configuration\n"); + LOG (GNUNET_ERROR_TYPE_WARNING, + "Cannot reply back configuration\n"); GNUNET_free (wc->data); GNUNET_free (wc); return; @@ -250,7 +232,8 @@ write_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) return; } write_task_id = - GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL, stdout_fd, + GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL, + stdout_fd, &write_task, wc); } @@ -260,10 +243,9 @@ write_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) * process died). * * @param cls closure, NULL if we need to self-restart - * @param tc context */ static void -child_death_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +child_death_task (void *cls) { const struct GNUNET_DISK_FileHandle *pr; char c[16]; @@ -272,14 +254,7 @@ child_death_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) int ret; pr = GNUNET_DISK_pipe_handle (sigpipe, GNUNET_DISK_PIPE_END_READ); - child_death_task_id = GNUNET_SCHEDULER_NO_TASK; - if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY)) - { - child_death_task_id = - GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, - pr, &child_death_task, NULL); - return; - } + child_death_task_id = NULL; /* consume the signal */ GNUNET_break (0 < GNUNET_DISK_file_read (pr, &c, sizeof (c))); LOG_DEBUG ("Got SIGCHLD\n"); @@ -288,13 +263,18 @@ child_death_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) GNUNET_break (0); return; } - GNUNET_break (GNUNET_SYSERR != + GNUNET_break (GNUNET_SYSERR != (ret = GNUNET_OS_process_status (testbed, &type, &code))); if (GNUNET_NO != ret) { GNUNET_OS_process_destroy (testbed); testbed = NULL; - shutdown_now (); + /* Send SIGTERM to our process group */ + if (0 != PLIBC_KILL (0, GNUNET_TERM_SIG)) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "signal"); + GNUNET_SCHEDULER_shutdown (); /* Couldn't send the signal, we shutdown frowning */ + } return; } LOG_DEBUG ("Child hasn't died. Resuming to monitor its status\n"); @@ -308,13 +288,13 @@ child_death_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) * Functions with this signature are called whenever a * complete message is received by the tokenizer. * - * Do not call GNUNET_SERVER_mst_destroy in callback + * Do not call #GNUNET_SERVER_mst_destroy() in this 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 + * @return #GNUNET_OK on success, #GNUNET_SYSERR to stop further processing */ static int tokenizer_cb (void *cls, void *client, @@ -329,6 +309,8 @@ tokenizer_cb (void *cls, void *client, char *hostname; char *config; char *xconfig; + char *evstr; + //char *str; size_t config_size; uLongf ul_config_size; size_t xconfig_size; @@ -392,15 +374,45 @@ tokenizer_cb (void *cls, void *client, hostname_size); hostname[hostname_size] = '\0'; } + /* unset GNUNET_TESTING_PREFIX if present as it is more relevant for testbed */ + evstr = getenv (GNUNET_TESTING_PREFIX); + if (NULL != evstr) + { + /* unsetting the variable will invalidate the pointer! */ + evstr = GNUNET_strdup (evstr); +#ifdef WINDOWS + GNUNET_break (0 != SetEnvironmentVariable (GNUNET_TESTING_PREFIX, NULL)); +#else + GNUNET_break (0 == unsetenv (GNUNET_TESTING_PREFIX)); +#endif + } test_system = - GNUNET_TESTING_system_create ("testbed-helper", trusted_ip, hostname); + GNUNET_TESTING_system_create ("testbed-helper", trusted_ip, hostname, + NULL); + if (NULL != evstr) + { +#ifdef WINDOWS + GNUNET_assert (0 != SetEnvironmentVariable (GNUNET_TESTING_PREFIX, + evstr)); +#else + char *evar; + + GNUNET_asprintf (&evar, + GNUNET_TESTING_PREFIX "=%s", + evstr); + GNUNET_assert (0 == putenv (evar)); /* consumes 'evar', + see putenv(): becomes part of envrionment! */ +#endif + GNUNET_free (evstr); + evstr = NULL; + } GNUNET_free_non_null (hostname); hostname = NULL; GNUNET_assert (NULL != test_system); GNUNET_assert (GNUNET_OK == GNUNET_TESTING_configuration_create (test_system, cfg)); GNUNET_assert (GNUNET_OK == - GNUNET_CONFIGURATION_get_value_string (cfg, "PATHS", + GNUNET_CONFIGURATION_get_value_filename (cfg, "PATHS", "DEFAULTCONFIG", &config)); if (GNUNET_OK != GNUNET_CONFIGURATION_write (cfg, config)) @@ -413,11 +425,26 @@ tokenizer_cb (void *cls, void *client, } LOG_DEBUG ("Staring testbed with config: %s\n", config); binary = GNUNET_OS_get_libexec_binary_path ("gnunet-service-testbed"); + { + char *evar; + + /* expose testbed configuration through env variable */ + GNUNET_asprintf (&evar, + "%s=%s", + ENV_TESTBED_CONFIG, + config); + GNUNET_assert (0 == putenv (evar)); /* consumes 'evar', + see putenv(): becomes part of envrionment! */ + evstr = NULL; + } testbed = GNUNET_OS_start_process (PIPE_CONTROL, - GNUNET_OS_INHERIT_STD_ERR /*verbose? */ , NULL, - NULL, binary, "gnunet-service-testbed", "-c", - config, NULL); + GNUNET_OS_INHERIT_STD_ERR /*verbose? */ , + NULL, NULL, NULL, + binary, + "gnunet-service-testbed", + "-c", config, + NULL); GNUNET_free (binary); GNUNET_free (config); if (NULL == testbed) @@ -434,7 +461,7 @@ tokenizer_cb (void *cls, void *client, xconfig_size = GNUNET_TESTBED_compress_config_ (config, config_size, &xconfig); GNUNET_free (config); - wc = GNUNET_malloc (sizeof (struct WriteContext)); + wc = GNUNET_new (struct WriteContext); wc->length = xconfig_size + sizeof (struct GNUNET_TESTBED_HelperReply); reply = GNUNET_realloc (xconfig, wc->length); memmove (&reply[1], reply, xconfig_size); @@ -443,8 +470,9 @@ tokenizer_cb (void *cls, void *client, reply->config_size = htons ((uint16_t) config_size); wc->data = reply; write_task_id = - GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL, stdout_fd, - &write_task, wc); + GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL, + stdout_fd, + &write_task, wc); child_death_task_id = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_DISK_pipe_handle (sigpipe, @@ -454,7 +482,7 @@ tokenizer_cb (void *cls, void *client, error: status = GNUNET_SYSERR; - shutdown_now (); + GNUNET_SCHEDULER_shutdown (); return GNUNET_SYSERR; } @@ -463,42 +491,41 @@ error: * Task to read from stdin * * @param cls NULL - * @param tc the task context */ static void -read_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +read_task (void *cls) { char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE]; ssize_t sread; - read_task_id = GNUNET_SCHEDULER_NO_TASK; - if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason)) - return; + read_task_id = NULL; sread = GNUNET_DISK_file_read (stdin_fd, buf, sizeof (buf)); if ((GNUNET_SYSERR == sread) || (0 == sread)) { LOG_DEBUG ("STDIN closed\n"); - shutdown_now (); + GNUNET_SCHEDULER_shutdown (); return; } if (GNUNET_YES == done_reading) { /* didn't expect any more data! */ GNUNET_break_op (0); - shutdown_now (); + GNUNET_SCHEDULER_shutdown (); return; } - LOG_DEBUG ("Read %u bytes\n", sread); + LOG_DEBUG ("Read %u bytes\n", + (unsigned int) sread); if (GNUNET_OK != GNUNET_SERVER_mst_receive (tokenizer, NULL, buf, sread, GNUNET_NO, GNUNET_NO)) { GNUNET_break (0); - shutdown_now (); + GNUNET_SCHEDULER_shutdown (); return; } read_task_id = /* No timeout while reading */ - GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, stdin_fd, + GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, + stdin_fd, &read_task, NULL); } @@ -512,7 +539,9 @@ read_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) * @param cfg configuration */ static void -run (void *cls, char *const *args, const char *cfgfile, +run (void *cls, + char *const *args, + const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { LOG_DEBUG ("Starting testbed helper...\n"); @@ -520,11 +549,11 @@ run (void *cls, char *const *args, const char *cfgfile, stdin_fd = GNUNET_DISK_get_handle_from_native (stdin); stdout_fd = GNUNET_DISK_get_handle_from_native (stdout); read_task_id = - GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, stdin_fd, + GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, + stdin_fd, &read_task, NULL); - shutdown_task_id = - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, - NULL); + GNUNET_SCHEDULER_add_shutdown (&shutdown_task, + NULL); } @@ -564,11 +593,10 @@ main (int argc, char **argv) int ret; status = GNUNET_OK; - if (NULL == (sigpipe = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, + if (NULL == (sigpipe = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_NO, GNUNET_NO))) { GNUNET_break (0); - ret = GNUNET_SYSERR; return 1; } shc_chld =