aboutsummaryrefslogtreecommitdiff
path: root/src/or
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2011-05-23 01:23:53 -0400
committerNick Mathewson <nickm@torproject.org>2011-05-23 01:23:53 -0400
commit2527acb2dc8b71515ac0c882e3af4fc034ab1b48 (patch)
tree48bdb4a6919a11fdb337969bb46353701895ad54 /src/or
parentcb7fff193e2749f241e646b155de3ee33623606e (diff)
parentb80a8bba199b9adfb9c893641ba770566fa548e1 (diff)
downloadtor-2527acb2dc8b71515ac0c882e3af4fc034ab1b48.tar
tor-2527acb2dc8b71515ac0c882e3af4fc034ab1b48.tar.gz
Merge remote-tracking branch 'origin/maint-0.2.2'
Conflicts: src/common/Makefile.am src/or/control.c
Diffstat (limited to 'src/or')
-rw-r--r--src/or/config.c15
-rw-r--r--src/or/connection.c3
-rw-r--r--src/or/control.c138
-rw-r--r--src/or/control.h4
-rw-r--r--src/or/or.h10
-rw-r--r--src/or/router.c7
6 files changed, 169 insertions, 8 deletions
diff --git a/src/or/config.c b/src/or/config.c
index 3493abf71..f3c634569 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. */
@@ -411,6 +413,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"),
@@ -1263,6 +1266,8 @@ options_act(or_options_t *old_options)
return -1;
}
+ monitor_owning_controller_process(options->OwningControllerProcess);
+
/* reload keys as needed for rendezvous services. */
if (rend_service_load_keys()<0) {
log_warn(LD_GENERAL,"Error loading rendezvous service keys");
@@ -3563,6 +3568,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/connection.c b/src/or/connection.c
index 0a5bb8ccd..7faeeb079 100644
--- a/src/or/connection.c
+++ b/src/or/connection.c
@@ -523,8 +523,7 @@ connection_free(connection_t *conn)
}
}
if (conn->type == CONN_TYPE_CONTROL) {
- TO_CONTROL_CONN(conn)->event_mask = 0;
- control_update_global_event_mask();
+ connection_control_closed(TO_CONTROL_CONN(conn));
}
connection_unregister_events(conn);
_connection_free(conn);
diff --git a/src/or/control.c b/src/or/control.c
index e0e8f7eee..98560733d 100644
--- a/src/or/control.c
+++ b/src/or/control.c
@@ -38,6 +38,8 @@
#include <sys/resource.h>
#endif
+#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)
@@ -1284,6 +1286,26 @@ handle_control_signal(control_connection_t *conn, uint32_t len,
return 0;
}
+/** Called when we get a TAKEOWNERSHIP command. Mark this connection
+ * as an owning connection, so that we will exit if the connection
+ * closes. */
+static int
+handle_control_takeownership(control_connection_t *conn, uint32_t len,
+ const char *body)
+{
+ (void)len;
+ (void)body;
+
+ conn->is_owning_control_connection = 1;
+
+ log_info(LD_CONTROL, "Control connection %d has taken ownership of this "
+ "Tor instance.",
+ (int)(conn->_base.s));
+
+ send_control_done(conn);
+ return 0;
+}
+
/** Called when we get a MAPADDRESS command; try to bind all listed addresses,
* and report success or failure. */
static int
@@ -2084,8 +2106,8 @@ static const getinfo_item_t getinfo_items[] = {
"v2 networkstatus docs as retrieved from a DirPort."),
ITEM("dir/status-vote/current/consensus", dir,
"v3 Networkstatus consensus as retrieved from a DirPort."),
- PREFIX("exit-policy/default", policies,
- "The default value appended to the configured exit policy."),
+ ITEM("exit-policy/default", policies,
+ "The default value appended to the configured exit policy."),
PREFIX("ip-to-country/", geoip, "Perform a GEOIP lookup"),
{ NULL, NULL, NULL, 0 }
};
@@ -2919,6 +2941,43 @@ connection_control_reached_eof(control_connection_t *conn)
return 0;
}
+/** Shut down this Tor instance in the same way that SIGINT would, but
+ * with a log message appropriate for the loss of an owning controller. */
+static void
+lost_owning_controller(const char *owner_type, const char *loss_manner)
+{
+ int shutdown_slowly = server_mode(get_options());
+
+ log_notice(LD_CONTROL, "Owning controller %s has %s -- %s.",
+ owner_type, loss_manner,
+ shutdown_slowly ? "shutting down" : "exiting now");
+
+ /* XXXX Perhaps 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();
+}
+
+/** Called when <b>conn</b> is being freed. */
+void
+connection_control_closed(control_connection_t *conn)
+{
+ tor_assert(conn);
+
+ conn->event_mask = 0;
+ control_update_global_event_mask();
+
+ if (conn->is_owning_control_connection) {
+ lost_owning_controller("connection", "closed");
+ }
+}
+
/** Return true iff <b>cmd</b> is allowable (or at least forgivable) at this
* stage of the protocol. */
static int
@@ -3083,6 +3142,9 @@ connection_control_process_inbuf(control_connection_t *conn)
return 0;
}
+ /* XXXX Why is this not implemented as a table like the GETINFO
+ * items are? Even handling the plus signs at the beginnings of
+ * commands wouldn't be very hard with proper macros. */
cmd_data_len = (uint32_t)data_len;
if (!strcasecmp(conn->incoming_cmd, "SETCONF")) {
if (handle_control_setconf(conn, cmd_data_len, args))
@@ -3108,6 +3170,9 @@ connection_control_process_inbuf(control_connection_t *conn)
} else if (!strcasecmp(conn->incoming_cmd, "SIGNAL")) {
if (handle_control_signal(conn, cmd_data_len, args))
return -1;
+ } else if (!strcasecmp(conn->incoming_cmd, "TAKEOWNERSHIP")) {
+ if (handle_control_takeownership(conn, cmd_data_len, args))
+ return -1;
} else if (!strcasecmp(conn->incoming_cmd, "MAPADDRESS")) {
if (handle_control_mapaddress(conn, cmd_data_len, args))
return -1;
@@ -4006,6 +4071,75 @@ 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)
+{
+ (void)unused;
+
+ lost_owning_controller("process", "vanished");
+}
+
+/** Set <b>process_spec</b> as Tor's owning controller process.
+ * Exit on failure. */
+void
+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;
+ }
+
+ /* 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;
+
+ 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_err(LD_BUG, "Couldn't create process-termination monitor for "
+ "owning controller: %s. Exiting.",
+ msg);
+ owning_controller_process_spec = NULL;
+ tor_cleanup();
+ exit(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 f8b8a990a..147a5af0b 100644
--- a/src/or/control.h
+++ b/src/or/control.h
@@ -27,6 +27,8 @@ void control_ports_write_to_file(void);
int connection_control_finished_flushing(control_connection_t *conn);
int connection_control_reached_eof(control_connection_t *conn);
+void connection_control_closed(control_connection_t *conn);
+
int connection_control_process_inbuf(control_connection_t *conn);
#define EVENT_AUTHDIR_NEWDESCS 0x000D
@@ -73,6 +75,8 @@ smartlist_t *decode_hashed_passwords(config_line_t *passwords);
void disable_control_logging(void);
void enable_control_logging(void);
+void 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 6c7430a4e..4b20b57d1 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -1027,7 +1027,7 @@ typedef struct connection_t {
/* XXXX023 move this field, and all the listener-only fields (just
socket_family, I think), into a new listener_connection_t subtype. */
/** If the connection is a CONN_TYPE_AP_DNS_LISTENER, this field points
- * to the evdns_server_port is uses to listen to and answer connections. */
+ * to the evdns_server_port it uses to listen to and answer connections. */
struct evdns_server_port *dns_server_port;
/** Unique ID for measuring tunneled network status requests. */
@@ -1271,6 +1271,9 @@ typedef struct control_connection_t {
/** True if we have sent a protocolinfo reply on this connection. */
unsigned int have_sent_protocolinfo:1;
+ /** True if we have received a takeownership command on this
+ * connection. */
+ unsigned int is_owning_control_connection:1;
/** Amount of space allocated in incoming_cmd. */
uint32_t incoming_cmd_len;
@@ -2842,6 +2845,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). */
diff --git a/src/or/router.c b/src/or/router.c
index 63ed4cf40..2b11a5202 100644
--- a/src/or/router.c
+++ b/src/or/router.c
@@ -492,8 +492,8 @@ init_keys(void)
char fingerprint_line[MAX_NICKNAME_LEN+FINGERPRINT_LEN+3];
const char *mydesc;
crypto_pk_env_t *prkey;
- char digest[20];
- char v3_digest[20];
+ char digest[DIGEST_LEN];
+ char v3_digest[DIGEST_LEN];
char *cp;
or_options_t *options = get_options();
dirinfo_type_t type;
@@ -505,7 +505,8 @@ init_keys(void)
if (!key_lock)
key_lock = tor_mutex_new();
- /* There are a couple of paths that put us here before */
+ /* There are a couple of paths that put us here before we've asked
+ * openssl to initialize itself. */
if (crypto_global_init(get_options()->HardwareAccel,
get_options()->AccelName,
get_options()->AccelDir)) {