From 97d9ba2380e0c894a1b611bdb4f35d0fe98a837a Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Mon, 11 Dec 2017 10:57:00 -0500 Subject: [PATCH] Add a mostly disabled feature to debug restarting in-process For 23847, we want Tor to be able to shut down and then restart in the same process. Here's a patch to make the Tor binary do that. To test it, you need to build with --enable-restart-debugging, and then you need to set the environment variable TOR_DEBUG_RESTART. With this option, Tor will then run for 5 seconds, then restart itself in-process without exiting. This only happens once. You can change the 5-second interval using TOR_DEBUG_RESTART_AFTER_SECONDS. Implements ticket 24583. --- changes/feature24583 | 9 +++++++++ configure.ac | 6 ++++++ src/or/main.c | 39 +++++++++++++++++++++++++++++++++++++++ src/or/tor_main.c | 16 +++++++++++++++- 4 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 changes/feature24583 diff --git a/changes/feature24583 b/changes/feature24583 new file mode 100644 index 0000000000..19feaec5bb --- /dev/null +++ b/changes/feature24583 @@ -0,0 +1,9 @@ + o Minor features (testing, debugging): + - For development purposes, Tor now has a mode in which it runs + for a few seconds, then stops, and starts again without exiting + the process. This mode is meant to help us debug various issues + with ticket 23847. To use this feature, compile with + --enable-restart-degbugging, and set the TOR_DEBUG_RESTART + environment variable. This is expected to crash a lot, and is + really meant for developers only. It will likely be removed in a future + release. Implements ticket 24583. diff --git a/configure.ac b/configure.ac index ee75d3a29e..36a27b54bd 100644 --- a/configure.ac +++ b/configure.ac @@ -59,6 +59,8 @@ AC_ARG_ENABLE(rust, AS_HELP_STRING(--enable-rust, [enable rust integration])) AC_ARG_ENABLE(cargo-online-mode, AS_HELP_STRING(--enable-cargo-online-mode, [Allow cargo to make network requests to fetch crates. For builds with rust only.])) +AC_ARG_ENABLE(restart-debugging, + AS_HELP_STRING(--enable-restart-debugging, [Build Tor with support for debugging in-process restart. Developers only.])) if test "x$enable_coverage" != "xyes" -a "x$enable_asserts_in_tests" = "xno" ; then AC_MSG_ERROR([Can't disable assertions outside of coverage build]) @@ -107,6 +109,10 @@ AC_ARG_ENABLE(systemd, * ) AC_MSG_ERROR(bad value for --enable-systemd) ;; esac], [systemd=auto]) +if test "$enable_restart_debugging" = "yes"; then + AC_DEFINE(ENABLE_RESTART_DEBUGGING, 1, + [Defined if we're building with support for in-process restart debugging.]) +fi # systemd support diff --git a/src/or/main.c b/src/or/main.c index aae98dd8ab..dc954bc15d 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -682,6 +682,20 @@ shutdown_did_not_work_callback(evutil_socket_t fd, short event, void *arg) // LCOV_EXCL_STOP } +#ifdef ENABLE_RESTART_DEBUGGING +static struct event *tor_shutdown_event_loop_for_restart_event = NULL; +static void +tor_shutdown_event_loop_for_restart_cb( + evutil_socket_t fd, short event, void *arg) +{ + (void)fd; + (void)event; + (void)arg; + tor_event_free(tor_shutdown_event_loop_for_restart_event); + tor_shutdown_event_loop_and_exit(0); +} +#endif + /** * After finishing the current callback (if any), shut down the main loop, * clean up the process, and exit with exitcode. @@ -2675,6 +2689,31 @@ do_main_loop(void) main_loop_should_exit = 0; main_loop_exit_value = 0; +#ifdef ENABLE_RESTART_DEBUGGING + { + static int first_time = 1; + + if (first_time && getenv("TOR_DEBUG_RESTART")) { + first_time = 0; + const char *sec_str = getenv("TOR_DEBUG_RESTART_AFTER_SECONDS"); + long sec; + int sec_ok=0; + if (sec_str && + (sec = tor_parse_long(sec_str, 10, 0, INT_MAX, &sec_ok, NULL)) && + sec_ok) { + /* Okay, we parsed the seconds. */ + } else { + sec = 5; + } + struct timeval restart_after = { (time_t) sec, 0 }; + tor_shutdown_event_loop_for_restart_event = + tor_evtimer_new(tor_libevent_get_base(), + tor_shutdown_event_loop_for_restart_cb, NULL); + event_add(tor_shutdown_event_loop_for_restart_event, &restart_after); + } + } +#endif + return run_main_loop_until_done(); } diff --git a/src/or/tor_main.c b/src/or/tor_main.c index c203d8248f..703669ac99 100644 --- a/src/or/tor_main.c +++ b/src/or/tor_main.c @@ -3,6 +3,11 @@ * Copyright (c) 2007-2017, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +#include "orconfig.h" +#ifdef ENABLE_RESTART_DEBUGGING +#include +#endif + /** * \file tor_main.c * \brief Stub module containing a main() function. @@ -19,9 +24,18 @@ int tor_main(int argc, char *argv[]); int main(int argc, char *argv[]) { - int r = tor_main(argc, argv); + int r; +#ifdef ENABLE_RESTART_DEBUGGING + int restart_count = getenv("TOR_DEBUG_RESTART") ? 1 : 0; + again: +#endif + r = tor_main(argc, argv); if (r < 0 || r > 255) return 1; +#ifdef ENABLE_RESTART_DEBUGGING + else if (r == 0 && restart_count--) + goto again; +#endif else return r; }