|
@@ -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
|
|
* <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
|
|
* guard as appropriate. Set <b>state_out</b> to the new guard-state
|
|
* of the circuit.
|
|
* 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);
|
|
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);
|
|
int num_entry_guards = get_n_primary_guards_to_use(usage);
|
|
smartlist_t *usable_primary_guards = smartlist_new();
|
|
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) {
|
|
SMARTLIST_FOREACH_BEGIN(gs->primary_entry_guards, entry_guard_t *, guard) {
|
|
entry_guard_consider_retry(guard);
|
|
entry_guard_consider_retry(guard);
|
|
if (! entry_guard_obeys_restriction(guard, rst))
|
|
if (! entry_guard_obeys_restriction(guard, rst))
|
|
@@ -2069,18 +2061,30 @@ select_entry_guard_for_circuit(guard_selection_t *gs,
|
|
} SMARTLIST_FOREACH_END(guard);
|
|
} SMARTLIST_FOREACH_END(guard);
|
|
|
|
|
|
if (smartlist_len(usable_primary_guards)) {
|
|
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);
|
|
smartlist_free(usable_primary_guards);
|
|
log_info(LD_GUARD, "Selected primary guard %s for circuit.",
|
|
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);
|
|
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) {
|
|
SMARTLIST_FOREACH_BEGIN(gs->confirmed_entry_guards, entry_guard_t *, guard) {
|
|
if (guard->is_primary)
|
|
if (guard->is_primary)
|
|
continue; /* we already considered this one. */
|
|
continue; /* we already considered this one. */
|
|
@@ -2101,34 +2105,93 @@ select_entry_guard_for_circuit(guard_selection_t *gs,
|
|
}
|
|
}
|
|
} SMARTLIST_FOREACH_END(guard);
|
|
} 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
|
|
/* "Otherwise, if there is no such entry, select a member at
|
|
random from {USABLE_FILTERED_GUARDS}." */
|
|
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;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|