aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorge Kadianakis <desnacked@gmail.com>2011-09-11 20:29:12 +0200
committerGeorge Kadianakis <desnacked@gmail.com>2011-09-11 20:29:12 +0200
commit1e92b24889bd64ccdd568366aaf989714d130f31 (patch)
tree7528c43ff5fb77c43e4b32847df3dac09c36e0ec
parentfa514fb207f23cb6f0ade95bbd830834ea14811f (diff)
downloadtor-1e92b24889bd64ccdd568366aaf989714d130f31.tar
tor-1e92b24889bd64ccdd568366aaf989714d130f31.tar.gz
Update transports.[ch] to support SIGHUPs.
-rw-r--r--src/or/transports.c323
-rw-r--r--src/or/transports.h42
2 files changed, 292 insertions, 73 deletions
diff --git a/src/or/transports.c b/src/or/transports.c
index 6255a567b..c4391c5e2 100644
--- a/src/or/transports.c
+++ b/src/or/transports.c
@@ -17,10 +17,7 @@
static void set_managed_proxy_environment(char ***envp, const managed_proxy_t *mp);
static INLINE int proxy_configuration_finished(const managed_proxy_t *mp);
-static void managed_proxy_destroy_impl(managed_proxy_t *mp,
- int also_free_transports);
-#define managed_proxy_destroy(mp) managed_proxy_destroy_impl(mp, 0)
-#define managed_proxy_destroy_with_transports(mp) managed_proxy_destroy_impl(mp, 1)
+static void managed_proxy_destroy(managed_proxy_t *mp);
static void handle_finished_proxy(managed_proxy_t *mp);
static void configure_proxy(managed_proxy_t *mp);
@@ -55,14 +52,16 @@ static INLINE void free_execve_args(char **arg);
#define PROTO_VERSION_ONE 1
/** List of unconfigured managed proxies. */
-static smartlist_t *unconfigured_proxy_list = NULL;
+static smartlist_t *managed_proxy_list = NULL;
+/** Number of still unconfigured proxies. */
+static int unconfigured_proxies_n = 0;
/* The main idea here is:
A managed proxy is represented by a managed_proxy_t struct and can
spawn multiple transports.
- unconfigured_proxy_list is a list of all the unconfigured managed
+ managed_proxy_list is a list of all the unconfigured managed
proxies; everytime we find a managed proxy in torrc we add it in
that list.
In every run_scheduled_event() tick, we attempt to launch and then
@@ -79,8 +78,7 @@ static smartlist_t *unconfigured_proxy_list = NULL;
int
pt_proxies_configuration_pending(void)
{
- if (!unconfigured_proxy_list) return 0;
- return !!smartlist_len(unconfigured_proxy_list);
+ return !! unconfigured_proxies_n;
}
/** Return true if <b>mp</b> has the same argv as <b>proxy_argv</b> */
@@ -109,10 +107,10 @@ managed_proxy_has_argv(managed_proxy_t *mp, char **proxy_argv)
static managed_proxy_t *
get_managed_proxy_by_argv(char **proxy_argv)
{
- if (!unconfigured_proxy_list)
+ if (!managed_proxy_list)
return NULL;
- SMARTLIST_FOREACH_BEGIN(unconfigured_proxy_list, managed_proxy_t *, mp) {
+ SMARTLIST_FOREACH_BEGIN(managed_proxy_list, managed_proxy_t *, mp) {
if (managed_proxy_has_argv(mp, proxy_argv))
return mp;
} SMARTLIST_FOREACH_END(mp);
@@ -129,22 +127,88 @@ add_transport_to_proxy(const char *transport, managed_proxy_t *mp)
smartlist_add(mp->transports_to_launch, tor_strdup(transport));
}
+/** Called when a SIGHUP occurs.
+ * Returns true if managed proxy <b>mp</b> needs to be restarted
+ * after the SIGHUP based on the new torrc. */
+static int
+proxy_needs_restart(managed_proxy_t *mp)
+{
+ /* mp->transport_to_launch is populated with the names of the
+ transports that must be launched *after* the SIGHUP.
+
+ Since only PT_PROTO_COMPLETED proxies reach this function,
+ mp->transports is populated with strings of the *names of the
+ transports* that were launched *before* the SIGHUP.
+
+ If the two lists contain the same strings, we don't need to
+ restart the proxy, since it already does what we want. */
+
+ tor_assert(smartlist_len(mp->transports_to_launch) > 0);
+ tor_assert(mp->conf_state == PT_PROTO_COMPLETED);
+
+ if (smartlist_len(mp->transports_to_launch) != smartlist_len(mp->transports))
+ goto needs_restart;
+
+ SMARTLIST_FOREACH_BEGIN(mp->transports_to_launch, char *, t_t_l) {
+ if (!smartlist_string_isin(mp->transports, t_t_l))
+ goto needs_restart;
+
+ } SMARTLIST_FOREACH_END(t_t_l);
+
+ return 0;
+
+ needs_restart:
+ return 1;
+}
+
+/** Managed proxy <b>mp</b> must be restarted. Do all the necessary
+ * preparations and then flag its state so that it will be launched
+ * in the next tick. */
+static void
+proxy_prepare_for_restart(managed_proxy_t *mp)
+{
+ transport_t *t_tmp = NULL;
+
+ tor_assert(mp->conf_state == PT_PROTO_COMPLETED);
+ tor_assert(mp->pid);
+
+ /* kill the old obfsproxy process */
+ tor_terminate_process(mp->pid);
+ mp->pid = 0;
+ fclose(mp->stdout);
+
+ /* destroy all its old transports. we no longer use them. */
+ SMARTLIST_FOREACH_BEGIN(mp->transports, const char *, t_name) {
+ t_tmp = transport_get_by_name(t_name);
+ if (t_tmp)
+ t_tmp->marked_for_removal = 1;
+ } SMARTLIST_FOREACH_END(t_name);
+ sweep_transport_list();
+
+ /* free the transport names in mp->transports */
+ SMARTLIST_FOREACH(mp->transports, char *, t_name, tor_free(t_name));
+ smartlist_clear(mp->transports);
+
+ /* flag it as an infant proxy so that it gets launched on next tick */
+ mp->conf_state = PT_PROTO_INFANT;
+}
+
/** Launch managed proxy <b>mp</b>. */
static int
launch_managed_proxy(managed_proxy_t *mp)
{
char **envp=NULL;
- int retval;
+ int pid;
FILE *stdout_read = NULL;
int stdout_pipe=-1, stderr_pipe=-1;
/* prepare the environment variables for the managed proxy */
set_managed_proxy_environment(&envp, mp);
- retval = tor_spawn_background(mp->argv[0], &stdout_pipe,
- &stderr_pipe, (const char **)mp->argv,
- (const char **)envp);
- if (retval < 0) {
+ pid = tor_spawn_background(mp->argv[0], &stdout_pipe,
+ &stderr_pipe, (const char **)mp->argv,
+ (const char **)envp);
+ if (pid < 0) {
log_warn(LD_GENERAL, "Spawn failed");
return -1;
}
@@ -157,10 +221,11 @@ launch_managed_proxy(managed_proxy_t *mp)
/* Open the buffered IO streams */
stdout_read = fdopen(stdout_pipe, "r");
- log_warn(LD_CONFIG, "The spawn is alive (%d)!", retval);
+ log_warn(LD_CONFIG, "The spawn is alive (%d)!", pid);
mp->conf_state = PT_PROTO_LAUNCHED;
mp->stdout = stdout_read;
+ mp->pid = pid;
return 0;
}
@@ -171,12 +236,32 @@ launch_managed_proxy(managed_proxy_t *mp)
void
pt_configure_remaining_proxies(void)
{
- log_warn(LD_CONFIG, "We start configuring remaining managed proxies!");
- SMARTLIST_FOREACH_BEGIN(unconfigured_proxy_list, managed_proxy_t *, mp) {
- /* configured proxies shouldn't be in unconfigured_proxy_list. */
- tor_assert(!proxy_configuration_finished(mp));
+ log_warn(LD_CONFIG, "We start configuring remaining managed proxies (%d)!",
+ unconfigured_proxies_n);
+ SMARTLIST_FOREACH_BEGIN(managed_proxy_list, managed_proxy_t *, mp) {
+ tor_assert(mp->conf_state != PT_PROTO_BROKEN);
+
+ if (mp->got_hup) {
+ mp->got_hup = 0;
+
+ /* This proxy is marked by a SIGHUP. Check whether we need to
+ restart it. */
+ if (proxy_needs_restart(mp)) {
+ proxy_prepare_for_restart(mp);
+ continue;
+ } else { /* it doesn't need to be restarted. */
+ printf("No need for restart; status quo\n");
+ unconfigured_proxies_n--;
+ tor_assert(unconfigured_proxies_n >= 0);
+ }
+
+ continue;
+ }
- configure_proxy(mp);
+ /* If the proxy is not fully configured, try to configure it
+ futher. */
+ if (!proxy_configuration_finished(mp))
+ configure_proxy(mp);
} SMARTLIST_FOREACH_END(mp);
}
@@ -222,33 +307,55 @@ configure_proxy(managed_proxy_t *mp)
/** Register server managed proxy <b>mp</b> transports to state */
static void
-register_server_proxy(const managed_proxy_t *mp)
+register_server_proxy(managed_proxy_t *mp)
{
- if (mp->is_server) {
- SMARTLIST_FOREACH_BEGIN(mp->transports, transport_t *, t) {
- save_transport_to_state(t->name,&t->addr,t->port); /* pass tor_addr_t? */
- } SMARTLIST_FOREACH_END(t);
- }
+ smartlist_t *sm_tmp = smartlist_create();
+
+ tor_assert(mp->conf_state != PT_PROTO_COMPLETED);
+ SMARTLIST_FOREACH_BEGIN(mp->transports, transport_t *, t) {
+ save_transport_to_state(t->name,&t->addr,t->port); /* pass tor_addr_t? */
+ smartlist_add(sm_tmp, tor_strdup(t->name));
+ } SMARTLIST_FOREACH_END(t);
+
+ smartlist_free(mp->transports);
+ mp->transports = sm_tmp;
}
/** Register all the transports supported by client managed proxy
* <b>mp</b> to the bridge subsystem. */
static void
-register_client_proxy(const managed_proxy_t *mp)
+register_client_proxy(managed_proxy_t *mp)
{
+ int r;
+ smartlist_t *sm_tmp = smartlist_create();
+
+ tor_assert(mp->conf_state != PT_PROTO_COMPLETED);
SMARTLIST_FOREACH_BEGIN(mp->transports, transport_t *, t) {
- if (transport_add(t)<0) {
+ r = transport_add(t);
+ switch (r) {
+ case -1:
log_warn(LD_GENERAL, "Could not add transport %s. Skipping.", t->name);
transport_free(t);
- } else {
+ break;
+ case 0:
log_warn(LD_GENERAL, "Succesfully registered transport %s", t->name);
+ smartlist_add(sm_tmp, tor_strdup(t->name));
+ break;
+ case 1:
+ log_warn(LD_GENERAL, "Succesfully registered transport %s", t->name);
+ smartlist_add(sm_tmp, tor_strdup(t->name));
+ transport_free(t);
+ break;
}
} SMARTLIST_FOREACH_END(t);
+
+ smartlist_free(mp->transports);
+ mp->transports = sm_tmp;
}
/** Register the transports of managed proxy <b>mp</b>. */
static INLINE void
-register_proxy(const managed_proxy_t *mp)
+register_proxy(managed_proxy_t *mp)
{
if (mp->is_server)
register_server_proxy(mp);
@@ -256,18 +363,17 @@ register_proxy(const managed_proxy_t *mp)
register_client_proxy(mp);
}
-/** Free memory allocated by managed proxy <b>mp</b>.
- * If <b>also_free_transports</b> is set, also free the transports
- * associated with this managed proxy. */
+/** Free memory allocated by managed proxy <b>mp</b>. */
static void
-managed_proxy_destroy_impl(managed_proxy_t *mp, int also_free_transports)
+managed_proxy_destroy(managed_proxy_t *mp)
{
- /* transport_free() all its transports */
- if (also_free_transports)
+ printf("Destroying mp %p\n", mp);
+ if (mp->conf_state != PT_PROTO_COMPLETED)
SMARTLIST_FOREACH(mp->transports, transport_t *, t, transport_free(t));
+ else
+ SMARTLIST_FOREACH(mp->transports, char *, t_name, tor_free(t_name));
/* free the transports smartlist */
- smartlist_clear(mp->transports);
smartlist_free(mp->transports);
SMARTLIST_FOREACH(mp->transports_to_launch, char *, t, tor_free(t));
@@ -277,31 +383,32 @@ managed_proxy_destroy_impl(managed_proxy_t *mp, int also_free_transports)
smartlist_free(mp->transports_to_launch);
/* remove it from the list of managed proxies */
- smartlist_remove(unconfigured_proxy_list, mp);
+ smartlist_remove(managed_proxy_list, mp);
/* close its stdout stream */
- fclose(mp->stdout);
+ if (mp->stdout)
+ fclose(mp->stdout);
/* free the argv */
free_execve_args(mp->argv);
+ if (mp->pid)
+ tor_terminate_process(mp->pid);
+
tor_free(mp);
}
-
/** Handle a configured or broken managed proxy <b>mp</b>. */
static void
handle_finished_proxy(managed_proxy_t *mp)
{
switch (mp->conf_state) {
case PT_PROTO_BROKEN: /* if broken: */
- managed_proxy_destroy_with_transports(mp); /* destroy it and all its transports */
+ managed_proxy_destroy(mp); /* annihilate it. */
break;
case PT_PROTO_CONFIGURED: /* if configured correctly: */
register_proxy(mp); /* register transports */
- mp->conf_state = PT_PROTO_COMPLETED; /* mark it as completed, */
- managed_proxy_destroy(mp); /* destroy the managed proxy struct,
- keeping the transports intact */
+ mp->conf_state = PT_PROTO_COMPLETED; /* mark it as completed. */
break;
default:
log_warn(LD_CONFIG, "Unfinished managed proxy in "
@@ -309,7 +416,8 @@ handle_finished_proxy(managed_proxy_t *mp)
tor_assert(0);
}
- tor_assert(smartlist_len(unconfigured_proxy_list) >= 0);
+ unconfigured_proxies_n--;
+ tor_assert(unconfigured_proxies_n >= 0);
}
/** Return true if the configuration of the managed proxy <b>mp</b> is
@@ -322,8 +430,7 @@ proxy_configuration_finished(const managed_proxy_t *mp)
}
-/** This function is called when a proxy sends an {S,C}METHODS DONE message,
- */
+/** This function is called when a proxy sends an {S,C}METHODS DONE message. */
static void
handle_methods_done(const managed_proxy_t *mp)
{
@@ -694,6 +801,30 @@ set_managed_proxy_environment(char ***envp, const managed_proxy_t *mp)
tor_free(bindaddr);
}
+/** Create and return a new managed proxy for <b>transport</b> using
+ * <b>proxy_argv</b>. If <b>is_server</b> is true, it's a server
+ * managed proxy. */
+static managed_proxy_t *
+managed_proxy_create(const char *transport, char **proxy_argv, int is_server)
+{
+ managed_proxy_t *mp = tor_malloc_zero(sizeof(managed_proxy_t));
+ mp->conf_state = PT_PROTO_INFANT;
+ mp->is_server = is_server;
+ mp->argv = proxy_argv;
+ mp->transports = smartlist_create();
+
+ mp->transports_to_launch = smartlist_create();
+ add_transport_to_proxy(transport, mp);
+
+ /* register the managed proxy */
+ if (!managed_proxy_list)
+ managed_proxy_list = smartlist_create();
+ smartlist_add(managed_proxy_list, mp);
+ unconfigured_proxies_n++;
+
+ return mp;
+}
+
/** Register <b>transport</b> using proxy with <b>proxy_argv</b> to
* the managed proxy subsystem.
* If <b>is_server</b> is true, then the proxy is a server proxy. */
@@ -705,21 +836,28 @@ pt_kickstart_proxy(const char *transport, char **proxy_argv, int is_server)
mp = get_managed_proxy_by_argv(proxy_argv);
if (!mp) { /* we haven't seen this proxy before */
- /* create a managed proxy */
- managed_proxy_t *mp = tor_malloc_zero(sizeof(managed_proxy_t));
- mp->conf_state = PT_PROTO_INFANT;
- mp->is_server = is_server;
- mp->argv = proxy_argv;
- mp->transports = smartlist_create();
-
- mp->transports_to_launch = smartlist_create();
- add_transport_to_proxy(transport, mp);
+ managed_proxy_create(transport, proxy_argv, is_server);
+
+ } else { /* known proxy. add its transport to its transport list */
+ if (mp->got_hup) {
+ /* If the managed proxy we found is marked by a SIGHUP, it means
+ that it's not useless and should be kept. If it's marked for
+ removal, unmark it and increase the unconfigured proxies so
+ that we try to restart it if we need to. Afterwards, check if
+ a transport_t for 'transport' used to exist before the SIGHUP
+ and make sure it doesn't get deleted because we might reuse
+ it. */
+ if (mp->marked_for_removal) {
+ mp->marked_for_removal = 0;
+ unconfigured_proxies_n++;
+ }
+
+ transport_t *old_transport = NULL;
+ old_transport = transport_get_by_name(transport);
+ if (old_transport)
+ old_transport->marked_for_removal = 0;
+ }
- /* register the managed proxy */
- if (!unconfigured_proxy_list)
- unconfigured_proxy_list = smartlist_create();
- smartlist_add(unconfigured_proxy_list, mp);
- } else { /* known proxy. just add transport to its transport list */
add_transport_to_proxy(transport, mp);
free_execve_args(proxy_argv);
}
@@ -738,25 +876,66 @@ free_execve_args(char **arg)
tor_free(arg);
}
+
+/** Tor will read its config, prepare the managed proxy list so that
+ * proxies that are not used in the new config will shutdown, and
+ * proxies that need to spawn more transports will do so. */
+void
+pt_prepare_proxy_list_for_config_read(void)
+{
+ if (!managed_proxy_list)
+ return;
+
+ SMARTLIST_FOREACH_BEGIN(managed_proxy_list, managed_proxy_t *, mp) {
+ /* Destroy unconfigured proxies. */
+ if (mp->conf_state != PT_PROTO_COMPLETED) {
+ managed_proxy_destroy(mp);
+ unconfigured_proxies_n--;
+ continue;
+ }
+
+ tor_assert(mp->conf_state == PT_PROTO_COMPLETED);
+
+ mp->marked_for_removal = 1;
+ mp->got_hup = 1;
+ SMARTLIST_FOREACH(mp->transports_to_launch, char *, t, tor_free(t));
+ smartlist_clear(mp->transports_to_launch);
+ } SMARTLIST_FOREACH_END(mp);
+
+ tor_assert(unconfigured_proxies_n == 0);
+}
+
+/** The tor config was read, destroy all managed proxies that were
+ * marked by a previous call to prepare_proxy_list_for_config_read()
+ * and are not used by the new config. */
+void
+sweep_proxy_list(void)
+{
+ if (!managed_proxy_list)
+ return;
+
+ SMARTLIST_FOREACH_BEGIN(managed_proxy_list, managed_proxy_t *, mp) {
+ if (mp->marked_for_removal) {
+ SMARTLIST_DEL_CURRENT(managed_proxy_list, mp);
+ managed_proxy_destroy(mp);
+ }
+ } SMARTLIST_FOREACH_END(mp);
+}
+
/** Release all storage held by the pluggable transports subsystem. */
void
pt_free_all(void)
{
- if (unconfigured_proxy_list) {
+ if (managed_proxy_list) {
/* If the proxy is in PT_PROTO_COMPLETED, it has registered its
transports and it's the duty of the circuitbuild.c subsystem to
free them. Otherwise, it hasn't registered its transports yet
and we should free them here. */
- SMARTLIST_FOREACH_BEGIN(unconfigured_proxy_list, managed_proxy_t *, mp) {
- if (mp->conf_state == PT_PROTO_COMPLETED)
- managed_proxy_destroy(mp);
- else
- managed_proxy_destroy_with_transports(mp);
- } SMARTLIST_FOREACH_END(mp);
+ SMARTLIST_FOREACH(managed_proxy_list, managed_proxy_t *, mp,
+ managed_proxy_destroy(mp));
- smartlist_clear(unconfigured_proxy_list);
- smartlist_free(unconfigured_proxy_list);
- unconfigured_proxy_list=NULL;
+ smartlist_free(managed_proxy_list);
+ managed_proxy_list=NULL;
}
}
diff --git a/src/or/transports.h b/src/or/transports.h
index 6fec1dcf7..48b7839cf 100644
--- a/src/or/transports.h
+++ b/src/or/transports.h
@@ -25,6 +25,9 @@ int pt_proxies_configuration_pending(void);
void pt_free_all(void);
+void pt_prepare_proxy_list_for_config_read(void);
+void sweep_proxy_list(void);
+
#ifdef PT_PRIVATE
/** State of the managed proxy configuration protocol. */
enum pt_proto_state {
@@ -47,8 +50,45 @@ typedef struct {
FILE *stdout; /* a stream to its stdout
(closed in managed_proxy_destroy()) */
+ int pid; /* The Process ID this managed proxy is using. */
+
+ /** Boolean: We are re-parsing our config, and we are going to
+ * remove this managed proxy if we don't find it any transport
+ * plugins that use it. */
+ unsigned int marked_for_removal : 1;
+
+ /** Boolean: We got a SIGHUP while this proxy was running. We use
+ * this flag to signify that this proxy might need to be restarted
+ * so that it can listen for other transports according to the new
+ * torrc. */
+ unsigned int got_hup : 1;
+
smartlist_t *transports_to_launch; /* transports to-be-launched by this proxy */
- smartlist_t *transports; /* list of transport_t this proxy spawned */
+
+ /* The 'transports' list contains all the transports this proxy has
+ launched.
+
+ Before a managed_proxy_t reaches the PT_PROTO_COMPLETED phase,
+ this smartlist contains a 'transport_t' for every transport it
+ has launched.
+
+ When the managed_proxy_t reaches the PT_PROTO_COMPLETED phase, it
+ registers all its transports to the circuitbuild.c subsystem. At
+ that point the 'transport_t's are owned by the circuitbuild.c
+ subsystem.
+
+ To avoid carrying dangling 'transport_t's in this smartlist,
+ right before the managed_proxy_t reaches the PT_PROTO_COMPLETED
+ phase we replace all 'transport_t's with strings of their
+ transport names.
+
+ So, tl;dr:
+ When (conf_state != PT_PROTO_COMPLETED) this list carries
+ (transport_t *).
+ When (conf_state == PT_PROTO_COMPLETED) this list carries
+ (char *).
+ */
+ smartlist_t *transports;
} managed_proxy_t;
int parse_cmethod_line(const char *line, managed_proxy_t *mp);