commit 042d22c8d1c4e4224feadd4ff3995769eb8301b4 Author: rl1987 rl1987@sdf.lonestar.org Date: Fri Jun 22 16:43:50 2018 +0300
Split select_entry_guard_for_circuit() --- src/feature/client/entrynodes.c | 157 ++++++++++++++++++++++++++++------------ 1 file changed, 110 insertions(+), 47 deletions(-)
diff --git a/src/feature/client/entrynodes.c b/src/feature/client/entrynodes.c index af68de611..494ad3352 100644 --- a/src/feature/client/entrynodes.c +++ b/src/feature/client/entrynodes.c @@ -2027,31 +2027,23 @@ entry_guards_note_internet_connectivity(guard_selection_t *gs) }
/** - * Get a guard for use with a circuit. Prefer to pick a running primary - * guard; then a non-pending running filtered confirmed guard; then a - * non-pending runnable filtered guard. Update the + * Pick a primary guard for use with a circuit, if available. Update the * <b>last_tried_to_connect</b> time and the <b>is_pending</b> fields of the * guard as appropriate. Set <b>state_out</b> to the new guard-state * of the circuit. */ -STATIC entry_guard_t * -select_entry_guard_for_circuit(guard_selection_t *gs, - guard_usage_t usage, - const entry_guard_restriction_t *rst, - unsigned *state_out) +static entry_guard_t * +select_primary_guard_for_circuit(guard_selection_t *gs, + guard_usage_t usage, + const entry_guard_restriction_t *rst, + unsigned *state_out) { const int need_descriptor = (usage == GUARD_USAGE_TRAFFIC); - tor_assert(gs); - tor_assert(state_out); - - if (!gs->primary_guards_up_to_date) - entry_guards_update_primary(gs); + entry_guard_t *chosen_guard = NULL;
int num_entry_guards = get_n_primary_guards_to_use(usage); smartlist_t *usable_primary_guards = smartlist_new();
- /* "If any entry in PRIMARY_GUARDS has {is_reachable} status of - <maybe> or <yes>, return the first such guard." */ SMARTLIST_FOREACH_BEGIN(gs->primary_entry_guards, entry_guard_t *, guard) { entry_guard_consider_retry(guard); if (! entry_guard_obeys_restriction(guard, rst)) @@ -2069,18 +2061,30 @@ select_entry_guard_for_circuit(guard_selection_t *gs, } SMARTLIST_FOREACH_END(guard);
if (smartlist_len(usable_primary_guards)) { - entry_guard_t *guard = smartlist_choose(usable_primary_guards); + chosen_guard = smartlist_choose(usable_primary_guards); smartlist_free(usable_primary_guards); log_info(LD_GUARD, "Selected primary guard %s for circuit.", - entry_guard_describe(guard)); - return guard; + entry_guard_describe(chosen_guard)); } + smartlist_free(usable_primary_guards); + return chosen_guard; +} + +/** + * For use with a circuit, pick a non-pending running filtered confirmed guard, + * if one is available. Update the <b>last_tried_to_connect</b> time and the + * <b>is_pending</b> fields of the guard as appropriate. Set <b>state_out</b> + * to the new guard-state of the circuit. + */ +static entry_guard_t * +select_confirmed_guard_for_circuit(guard_selection_t *gs, + guard_usage_t usage, + const entry_guard_restriction_t *rst, + unsigned *state_out) +{ + const int need_descriptor = (usage == GUARD_USAGE_TRAFFIC);
- /* "Otherwise, if the ordered intersection of {CONFIRMED_GUARDS} - and {USABLE_FILTERED_GUARDS} is nonempty, return the first - entry in that intersection that has {is_pending} set to - false." */ SMARTLIST_FOREACH_BEGIN(gs->confirmed_entry_guards, entry_guard_t *, guard) { if (guard->is_primary) continue; /* we already considered this one. */ @@ -2101,34 +2105,93 @@ select_entry_guard_for_circuit(guard_selection_t *gs, } } SMARTLIST_FOREACH_END(guard);
+ return NULL; +} + +/** + * For use with a circuit, pick a confirmed usable filtered guard + * at random. Update the <b>last_tried_to_connect</b> time and the + * <b>is_pending</b> fields of the guard as appropriate. Set <b>state_out</b> + * to the new guard-state of the circuit. + */ +static entry_guard_t * +select_filtered_guard_for_circuit(guard_selection_t *gs, + guard_usage_t usage, + const entry_guard_restriction_t *rst, + unsigned *state_out) +{ + const int need_descriptor = (usage == GUARD_USAGE_TRAFFIC); + entry_guard_t *chosen_guard = NULL; + unsigned flags = 0; + if (need_descriptor) + flags |= SAMPLE_EXCLUDE_NO_DESCRIPTOR; + chosen_guard = sample_reachable_filtered_entry_guards(gs, + rst, + SAMPLE_EXCLUDE_CONFIRMED | + SAMPLE_EXCLUDE_PRIMARY | + SAMPLE_EXCLUDE_PENDING | + flags); + if (!chosen_guard) { + return NULL; + } + + chosen_guard->is_pending = 1; + chosen_guard->last_tried_to_connect = approx_time(); + *state_out = GUARD_CIRC_STATE_USABLE_IF_NO_BETTER_GUARD; + log_info(LD_GUARD, "No primary or confirmed guards available. Selected " + "random guard %s for circuit. Will try other guards before " + "using this circuit.", + entry_guard_describe(chosen_guard)); + return chosen_guard; +} + +/** + * Get a guard for use with a circuit. Prefer to pick a running primary + * guard; then a non-pending running filtered confirmed guard; then a + * non-pending runnable filtered guard. Update the + * <b>last_tried_to_connect</b> time and the <b>is_pending</b> fields of the + * guard as appropriate. Set <b>state_out</b> to the new guard-state + * of the circuit. + */ +STATIC entry_guard_t * +select_entry_guard_for_circuit(guard_selection_t *gs, + guard_usage_t usage, + const entry_guard_restriction_t *rst, + unsigned *state_out) +{ + entry_guard_t *chosen_guard = NULL; + tor_assert(gs); + tor_assert(state_out); + + if (!gs->primary_guards_up_to_date) + entry_guards_update_primary(gs); + + /* "If any entry in PRIMARY_GUARDS has {is_reachable} status of + <maybe> or <yes>, return the first such guard." */ + chosen_guard = select_primary_guard_for_circuit(gs, usage, rst, state_out); + if (chosen_guard) + return chosen_guard; + + /* "Otherwise, if the ordered intersection of {CONFIRMED_GUARDS} + and {USABLE_FILTERED_GUARDS} is nonempty, return the first + entry in that intersection that has {is_pending} set to + false." */ + chosen_guard = select_confirmed_guard_for_circuit(gs, usage, rst, state_out); + if (chosen_guard) + return chosen_guard; + /* "Otherwise, if there is no such entry, select a member at random from {USABLE_FILTERED_GUARDS}." */ - { - entry_guard_t *guard; - unsigned flags = 0; - if (need_descriptor) - flags |= SAMPLE_EXCLUDE_NO_DESCRIPTOR; - guard = sample_reachable_filtered_entry_guards(gs, - rst, - SAMPLE_EXCLUDE_CONFIRMED | - SAMPLE_EXCLUDE_PRIMARY | - SAMPLE_EXCLUDE_PENDING | - flags); - if (guard == NULL) { - log_info(LD_GUARD, "Absolutely no sampled guards were available. " - "Marking all guards for retry and starting from top again."); - mark_all_guards_maybe_reachable(gs); - return NULL; - } - guard->is_pending = 1; - guard->last_tried_to_connect = approx_time(); - *state_out = GUARD_CIRC_STATE_USABLE_IF_NO_BETTER_GUARD; - log_info(LD_GUARD, "No primary or confirmed guards available. Selected " - "random guard %s for circuit. Will try other guards before " - "using this circuit.", - entry_guard_describe(guard)); - return guard; + chosen_guard = select_filtered_guard_for_circuit(gs, usage, rst, state_out); + + if (chosen_guard == NULL) { + log_info(LD_GUARD, "Absolutely no sampled guards were available. " + "Marking all guards for retry and starting from top again."); + mark_all_guards_maybe_reachable(gs); + return NULL; } + + return chosen_guard; }
/**