diff options
Diffstat (limited to 'src/or')
-rw-r--r-- | src/or/config.c | 18 | ||||
-rw-r--r-- | src/or/control.c | 86 | ||||
-rw-r--r-- | src/or/control.h | 2 | ||||
-rw-r--r-- | src/or/or.h | 5 |
4 files changed, 111 insertions, 0 deletions
diff --git a/src/or/config.c b/src/or/config.c index 34208e85bf..b2bc9f3e9a 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -38,6 +38,8 @@ #include <shlobj.h> #endif +#include "procmon.h" + /** Enumeration of types which option values can take */ typedef enum config_type_t { CONFIG_TYPE_STRING = 0, /**< An arbitrary string. */ @@ -393,6 +395,7 @@ static config_var_t _option_vars[] = { VAR("__LeaveStreamsUnattached",BOOL, LeaveStreamsUnattached, "0"), VAR("__HashedControlSessionPassword", LINELIST, HashedControlSessionPassword, NULL), + VAR("__OwningControllerProcess",STRING,OwningControllerProcess, NULL), V(MinUptimeHidServDirectoryV2, INTERVAL, "24 hours"), V(_UsingTestNetworkDefaults, BOOL, "0"), @@ -1229,6 +1232,11 @@ options_act(or_options_t *old_options) return -1; } + if (monitor_owning_controller_process(options->OwningControllerProcess)) { + log_warn(LD_CONFIG, "Error monitoring owning controller process"); + return -1; + } + /* reload keys as needed for rendezvous services. */ if (rend_service_load_keys()<0) { log_warn(LD_GENERAL,"Error loading rendezvous service keys"); @@ -3446,6 +3454,16 @@ options_validate(or_options_t *old_options, or_options_t *options, } } + if (options->OwningControllerProcess) { + const char *validate_pspec_msg = NULL; + if (tor_validate_process_specifier(options->OwningControllerProcess, + &validate_pspec_msg)) { + tor_asprintf(msg, "Bad OwningControllerProcess: %s", + validate_pspec_msg); + return -1; + } + } + if (options->ControlListenAddress) { int all_are_local = 1; config_line_t *ln; diff --git a/src/or/control.c b/src/or/control.c index 926a465203..3a96904438 100644 --- a/src/or/control.c +++ b/src/or/control.c @@ -32,6 +32,8 @@ #include "routerlist.h" #include "routerparse.h" +#include "procmon.h" + /** Yield true iff <b>s</b> is the state of a control_connection_t that has * finished authentication and is accepting commands. */ #define STATE_IS_OPEN(s) ((s) == CONTROL_CONN_STATE_OPEN) @@ -3779,6 +3781,90 @@ init_cookie_authentication(int enabled) return 0; } +/** A copy of the process specifier of Tor's owning controller, or + * NULL if this Tor instance is not currently owned by a process. */ +static char *owning_controller_process_spec = NULL; + +/** A process-termination monitor for Tor's owning controller, or NULL + * if this Tor instance is not currently owned by a process. */ +static tor_process_monitor_t *owning_controller_process_monitor = NULL; + +/** Process-termination monitor callback for Tor's owning controller + * process. */ +static void +owning_controller_procmon_cb(void *unused) +{ + int shutdown_slowly = server_mode(get_options()); + + (void)unused; + + log_notice(LD_CONTROL, "Owning controller process has vanished -- " + "%s.", + shutdown_slowly ? "shutting down" : "exiting now"); + + /* XXXX This chunk of code should be a separate function, called + * here and by process_signal(SIGINT). */ + + if (!shutdown_slowly) { + tor_cleanup(); + exit(0); + } + /* XXXX This will close all listening sockets except control-port + * listeners. Perhaps we should close those too. */ + hibernate_begin_shutdown(); +} + +/** Set <b>process_spec</b> as Tor's owning controller process. + * Return 0 on success, -1 on failure. */ +int +monitor_owning_controller_process(const char *process_spec) +{ + const char *msg; + + tor_assert((owning_controller_process_spec == NULL) == + (owning_controller_process_monitor == NULL)); + + if (owning_controller_process_spec != NULL) { + if ((process_spec != NULL) && !strcmp(process_spec, + owning_controller_process_spec)) { + /* Same process -- return now, instead of disposing of and + * recreating the process-termination monitor. */ + return 0; + } + + /* We are currently owned by a process, and we should no longer be + * owned by it. Free the process-termination monitor. */ + tor_process_monitor_free(owning_controller_process_monitor); + owning_controller_process_monitor = NULL; + + tor_free(owning_controller_process_spec); + owning_controller_process_spec = NULL; + } + + tor_assert((owning_controller_process_spec == NULL) && + (owning_controller_process_monitor == NULL)); + + if (process_spec == NULL) + return 0; + + owning_controller_process_spec = tor_strdup(process_spec); + owning_controller_process_monitor = + tor_process_monitor_new(tor_libevent_get_base(), + owning_controller_process_spec, + LD_CONTROL, + owning_controller_procmon_cb, NULL, + &msg); + + if (owning_controller_process_monitor == NULL) { + log_warn(LD_CONTROL, "Couldn't create process-termination monitor for " + "owning controller: %s", + msg); + return -1; + } + + return 0; +} + /** Convert the name of a bootstrapping phase <b>s</b> into strings * <b>tag</b> and <b>summary</b> suitable for display by the controller. */ static int diff --git a/src/or/control.h b/src/or/control.h index 2ae96b4b8a..81c23010d2 100644 --- a/src/or/control.h +++ b/src/or/control.h @@ -70,6 +70,8 @@ smartlist_t *decode_hashed_passwords(config_line_t *passwords); void disable_control_logging(void); void enable_control_logging(void); +int monitor_owning_controller_process(const char *process_spec); + void control_event_bootstrap(bootstrap_status_t status, int progress); void control_event_bootstrap_problem(const char *warn, int reason); diff --git a/src/or/or.h b/src/or/or.h index d667358eb0..546c38a9a8 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -2669,6 +2669,11 @@ typedef struct { int DisablePredictedCircuits; /**< Boolean: does Tor preemptively * make circuits in the background (0), * or not (1)? */ + + /** Process specifier for a controller that ‘owns’ this Tor + * instance. Tor will terminate if its owning controller does. */ + char *OwningControllerProcess; + int ShutdownWaitLength; /**< When we get a SIGINT and we're a server, how * long do we wait before exiting? */ char *SafeLogging; /**< Contains "relay", "1", "0" (meaning no scrubbing). */ |