Browse Source

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.
Nick Mathewson 6 years ago
parent
commit
97d9ba2380
4 changed files with 69 additions and 1 deletions
  1. 9 0
      changes/feature24583
  2. 6 0
      configure.ac
  3. 39 0
      src/or/main.c
  4. 15 1
      src/or/tor_main.c

+ 9 - 0
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.

+ 6 - 0
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

+ 39 - 0
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 <b>exitcode</b>.
@@ -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();
 }
 

+ 15 - 1
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 <stdlib.h>
+#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;
 }