commit fa514fb207f23cb6f0ade95bbd830834ea14811f Author: George Kadianakis desnacked@gmail.com Date: Sun Sep 11 20:28:47 2011 +0200
Prepare circuitbuild.[ch] and config.[ch] for SIGHUPs.
* Create mark/sweep functions for transports. * Create a transport_resolve_conflicts() function that tries to resolve conflicts when registering transports. --- src/or/circuitbuild.c | 126 +++++++++++++++++++++++++++++++++++++++++++------ src/or/circuitbuild.h | 8 +++ src/or/config.c | 10 ++-- 3 files changed, 124 insertions(+), 20 deletions(-)
diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c index 382016e..bd06d31 100644 --- a/src/or/circuitbuild.c +++ b/src/or/circuitbuild.c @@ -124,7 +124,6 @@ static int onion_append_hop(crypt_path_t **head_ptr, extend_info_t *choice);
static void entry_guards_changed(void);
-static const transport_t *transport_get_by_name(const char *name); static void bridge_free(bridge_info_t *bridge);
/** @@ -4579,6 +4578,32 @@ bridge_free(bridge_info_t *bridge) /** A list of pluggable transports found in torrc. */ static smartlist_t *transport_list = NULL;
+/** Mark every entry of the transport list to be removed on our next call to + * sweep_transport_list unless it has first been un-marked. */ +void +mark_transport_list(void) +{ + if (!transport_list) + transport_list = smartlist_create(); + SMARTLIST_FOREACH(transport_list, transport_t *, t, + t->marked_for_removal = 1); +} + +/** Remove every entry of the transport list that was marked with + * mark_transport_list if it has not subsequently been un-marked. */ +void +sweep_transport_list(void) +{ + if (!transport_list) + transport_list = smartlist_create(); + SMARTLIST_FOREACH_BEGIN(transport_list, transport_t *, t) { + if (t->marked_for_removal) { + SMARTLIST_DEL_CURRENT(transport_list, t); + transport_free(t); + } + } SMARTLIST_FOREACH_END(t); +} + /** Initialize the pluggable transports list to empty, creating it if * needed. */ void @@ -4603,7 +4628,7 @@ transport_free(transport_t *transport)
/** Returns the transport in our transport list that has the name <b>name</b>. * Else returns NULL. */ -static const transport_t * +transport_t * transport_get_by_name(const char *name) { tor_assert(name); @@ -4611,7 +4636,7 @@ transport_get_by_name(const char *name) if (!transport_list) return NULL;
- SMARTLIST_FOREACH_BEGIN(transport_list, const transport_t *, transport) { + SMARTLIST_FOREACH_BEGIN(transport_list, transport_t *, transport) { if (!strcmp(transport->name, name)) return transport; } SMARTLIST_FOREACH_END(transport); @@ -4636,23 +4661,81 @@ transport_create(const tor_addr_t *addr, uint16_t port, return t; }
-/** Adds transport <b>t</b> to the internal list of pluggable transports. */ +/** Resolve any conflicts that the insertion of transport <b>t</b> + * might cause. + * Return 0 if <b>t</b> is OK and should be registered, 1 if there is + * a transport identical to <b>t</b> already registered and -1 if + * <b>t</b> cannot be added due to conflicts. */ +static int +transport_resolve_conflicts(transport_t *t) +{ + /* This is how we resolve transport conflicts: + + If there is already a transport with the same name and addrport, + we either have duplicate torrc lines OR we are here post-HUP and + this transport was here pre-HUP as well. In any case, mark the + old transport so that it doesn't get removed and ignore the new + one. + + If there is already a transport with the same name but different + addrport: + * if it's marked for removal, it means that it either has a lower + priority than 't' in torrc (otherwise the mark would have been + cleared by the paragraph above), or it doesn't exist at all in + the post-HUP torrc. We destroy the old transport and register 't'. + * if it's *not* marked for removal, it means that it was newly + added in the post-HUP torrc or that it's of higher priority, in + this case we ignore 't'. */ + transport_t *t_tmp = transport_get_by_name(t->name); + if (t_tmp) { /* same name */ + if (tor_addr_eq(&t->addr, &t_tmp->addr) && (t->port == t_tmp->port)) { + /* same name *and* addrport */ + t_tmp->marked_for_removal = 0; + return 1; + } else { /* same name but different addrport */ + if (t_tmp->marked_for_removal) { /* marked for removal */ + log_warn(LD_GENERAL, "You tried to add transport '%s' at '%s:%u' but " + "there was already a transport marked for deletion at '%s:%u'." + "We deleted the old transport and registered the new one.", + t->name, fmt_addr(&t->addr), t->port, + fmt_addr(&t_tmp->addr), t_tmp->port); + smartlist_remove(transport_list, t_tmp); + transport_free(t_tmp); + } else { /* *not* marked for removal */ + log_warn(LD_GENERAL, "You tried to add transport '%s' at '%s:%u' which " + "already exists at '%s:%u'. Skipping.", t->name, + fmt_addr(&t->addr), t->port, + fmt_addr(&t_tmp->addr), t_tmp->port); + return -1; + } + } + } + + return 0; +} + +/** Add transport <b>t</b> to the internal list of pluggable + * transports. + * Returns 0 if the transport was added correctly, 1 if the same + * transport was already registered (in this case the caller must + * free the transport) and -1 if there was an error. */ int transport_add(transport_t *t) { tor_assert(t);
- if (transport_get_by_name(t->name)) { /* check for duplicate names */ - log_notice(LD_CONFIG, "More than one transports have '%s' as " - "their name.", t->name); - return -1; - } + int r = transport_resolve_conflicts(t);
- if (!transport_list) - transport_list = smartlist_create(); + switch (r) { + case 0: /* should register transport */ + if (!transport_list) + transport_list = smartlist_create();
- smartlist_add(transport_list, t); - return 0; + smartlist_add(transport_list, t); + return 0; + default: /* should let the caller know the return code */ + return r; + } }
/** Remember a new pluggable transport proxy at <b>addr</b>:<b>port</b>. @@ -4664,10 +4747,23 @@ transport_add_from_config(const tor_addr_t *addr, uint16_t port, { transport_t *t = transport_create(addr, port, name, socks_ver);
- if (transport_add(t) < 0) { + int r = transport_add(t); + + switch (r) { + case -1: + default: + log_warn(LD_GENERAL, "Could not add transport %s at %s:%u. Skipping.", + t->name, fmt_addr(&t->addr), t->port); transport_free(t); return -1; - } else { + case 1: + log_warn(LD_GENERAL, "Succesfully registered transport %s at %s:%u.", + t->name, fmt_addr(&t->addr), t->port); + transport_free(t); /* falling */ + return 0; + case 0: + log_warn(LD_GENERAL, "Succesfully registered transport %s at %s:%u.", + t->name, fmt_addr(&t->addr), t->port); return 0; } } diff --git a/src/or/circuitbuild.h b/src/or/circuitbuild.h index 92449b4..10e7287 100644 --- a/src/or/circuitbuild.h +++ b/src/or/circuitbuild.h @@ -22,6 +22,9 @@ typedef struct { tor_addr_t addr; /** Port of proxy */ uint16_t port; + /** Boolean: We are re-parsing our transport list, and we are going to remove + * this one if we don't find it in the list of configured transports. */ + unsigned marked_for_removal : 1; } transport_t;
char *circuit_list_path(origin_circuit_t *circ, int verbose); @@ -77,6 +80,9 @@ int getinfo_helper_entry_guards(control_connection_t *conn,
void mark_bridge_list(void); void sweep_bridge_list(void); +void mark_transport_list(void); +void sweep_transport_list(void); + int routerinfo_is_a_configured_bridge(const routerinfo_t *ri); int node_is_a_configured_bridge(const node_t *node); void learned_router_identity(const tor_addr_t *addr, uint16_t port, @@ -149,6 +155,8 @@ transport_t *transport_create(const tor_addr_t *addr, uint16_t port,
int find_transport_by_bridge_addrport(const tor_addr_t *addr, uint16_t port, const transport_t **transport); +transport_t *transport_get_by_name(const char *name); + void validate_pluggable_transports_config(void);
#endif diff --git a/src/or/config.c b/src/or/config.c index 0b84f92..829d5ff 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -1251,7 +1251,8 @@ options_act(or_options_t *old_options) }
- clear_transport_list(); + mark_transport_list(); + pt_prepare_proxy_list_for_config_read(); if (options->ClientTransportPlugin) { for (cl = options->ClientTransportPlugin; cl; cl = cl->next) { if (parse_client_transport_line(cl->value, 0)<0) { @@ -1273,6 +1274,8 @@ options_act(or_options_t *old_options) } } } + sweep_transport_list(); + sweep_proxy_list();
/* Bail out at this point if we're not going to be a client or server: * we want to not fork, and to log stuff to stderr. */ @@ -4769,10 +4772,7 @@ parse_client_transport_line(const char *line, int validate_only) }
if (!validate_only) { - if (transport_add_from_config(&addr, port, name, - socks_ver) < 0) { - goto err; - } + transport_add_from_config(&addr, port, name, socks_ver);
log_debug(LD_DIR, "Transport '%s' found at %s:%d", name, fmt_addr(&addr), (int)port);
tor-commits@lists.torproject.org