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;
}