diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c
index 86406cbea9..b8a82e886e 100644
--- a/src/or/circuitbuild.c
+++ b/src/or/circuitbuild.c
@@ -2685,13 +2685,29 @@ choose_good_exit_server_general(routerlist_t *dir, int need_uptime,
n_supported[i] = -1;
continue; /* skip routers that are known to be down or bad exits */
}
+
+ if (options->_ExcludeExitNodesUnion &&
+ routerset_contains_router(options->_ExcludeExitNodesUnion, router)) {
+ n_supported[i] = -1;
+ continue; /* user asked us not to use it, no matter what */
+ }
+ if (options->ExitNodes &&
+ !routerset_contains_router(options->ExitNodes, router)) {
+ n_supported[i] = -1;
+ continue; /* not one of our chosen exit nodes */
+ }
+
if (router_is_unreliable(router, need_uptime, need_capacity, 0) &&
- (!options->ExitNodes ||
- !routerset_contains_router(options->ExitNodes, router))) {
+ !options->ExitNodes) {
/* FFFF Someday, differentiate between a routerset that names
* routers, and a routerset that names countries, and only do this
* check if they've asked for specific exit relays. Or if the country
* they ask for is rare. Or something. */
+ /* XXX022-1090 We need to pick a tradeoff here: if we throw it out because
+ * it's unreliable, users might end up with no exit options even
+ * though some options are up. If we don't throw it out, users who
+ * set ExitNodes will have partitioning problems because they'll be
+ * the only folks willing to use this node. */
n_supported[i] = -1;
continue; /* skip routers that are not suitable, unless we have
* ExitNodes set, in which case we asked for it */
@@ -2753,21 +2769,13 @@ choose_good_exit_server_general(routerlist_t *dir, int need_uptime,
/* If any routers definitely support any pending connections, choose one
* at random. */
if (best_support > 0) {
- smartlist_t *supporting = smartlist_create(), *use = smartlist_create();
+ smartlist_t *supporting = smartlist_create();
for (i = 0; i < smartlist_len(dir->routers); i++)
if (n_supported[i] == best_support)
smartlist_add(supporting, smartlist_get(dir->routers, i));
- routersets_get_disjunction(use, supporting, options->ExitNodes,
- options->_ExcludeExitNodesUnion, 1);
- if (smartlist_len(use) == 0 && options->ExitNodes &&
- !options->StrictNodes) { /* give up on exitnodes and try again */
- routersets_get_disjunction(use, supporting, NULL,
- options->_ExcludeExitNodesUnion, 1);
- }
- router = routerlist_sl_choose_by_bandwidth(use, WEIGHT_FOR_EXIT);
- smartlist_free(use);
+ router = routerlist_sl_choose_by_bandwidth(supporting, WEIGHT_FOR_EXIT);
smartlist_free(supporting);
} else {
/* Either there are no pending connections, or no routers even seem to
@@ -2775,7 +2783,7 @@ choose_good_exit_server_general(routerlist_t *dir, int need_uptime,
* at least one predicted exit port. */
int attempt;
- smartlist_t *needed_ports, *supporting, *use;
+ smartlist_t *needed_ports, *supporting;
if (best_support == -1) {
if (need_uptime || need_capacity) {
@@ -2792,7 +2800,6 @@ choose_good_exit_server_general(routerlist_t *dir, int need_uptime,
options->_ExcludeExitNodesUnion ? " or are Excluded" : "");
}
supporting = smartlist_create();
- use = smartlist_create();
needed_ports = circuit_get_unhandled_ports(time(NULL));
for (attempt = 0; attempt < 2; attempt++) {
/* try once to pick only from routers that satisfy a needed port,
@@ -2807,25 +2814,13 @@ choose_good_exit_server_general(routerlist_t *dir, int need_uptime,
}
}
- routersets_get_disjunction(use, supporting, options->ExitNodes,
- options->_ExcludeExitNodesUnion, 1);
- if (smartlist_len(use) == 0 && options->ExitNodes &&
- !options->StrictNodes) { /* give up on exitnodes and try again */
- routersets_get_disjunction(use, supporting, NULL,
- options->_ExcludeExitNodesUnion, 1);
- }
- /* FFF sometimes the above results in null, when the requested
- * exit node is considered down by the consensus. we should pick
- * it anyway, since the user asked for it. */
- router = routerlist_sl_choose_by_bandwidth(use, WEIGHT_FOR_EXIT);
+ router = routerlist_sl_choose_by_bandwidth(supporting, WEIGHT_FOR_EXIT);
if (router)
break;
smartlist_clear(supporting);
- smartlist_clear(use);
}
SMARTLIST_FOREACH(needed_ports, uint16_t *, cp, tor_free(cp));
smartlist_free(needed_ports);
- smartlist_free(use);
smartlist_free(supporting);
}
@@ -2834,10 +2829,11 @@ choose_good_exit_server_general(routerlist_t *dir, int need_uptime,
log_info(LD_CIRC, "Chose exit server '%s'", router->nickname);
return router;
}
- if (options->ExitNodes && options->StrictNodes) {
+ if (options->ExitNodes) {
log_warn(LD_CIRC,
- "No specified exit routers seem to be running, and "
- "StrictNodes is set: can't choose an exit.");
+ "No specified %sexit routers seem to be running: "
+ "can't choose an exit.",
+ options->_ExcludeExitNodesUnion ? "non-excluded " : "");
}
return NULL;
}
diff --git a/src/or/routerlist.c b/src/or/routerlist.c
index 523596ddda..a9a216b2a1 100644
--- a/src/or/routerlist.c
+++ b/src/or/routerlist.c
@@ -5473,12 +5473,14 @@ routerset_needs_geoip(const routerset_t *set)
return set && smartlist_len(set->country_names);
}
+#if 0
/** Return true iff there are no entries in set. */
static int
routerset_is_empty(const routerset_t *set)
{
return !set || smartlist_len(set->list) == 0;
}
+#endif
/** Helper. Return true iff set contains a router based on the other
* provided fields. Return higher values for more specific subentries: a
@@ -5594,6 +5596,7 @@ routerset_get_all_routers(smartlist_t *out, const routerset_t *routerset,
}
}
+#if 0
/** Add to target every routerinfo_t from source except:
*
* 1) Don't add it if include is non-empty and the relay isn't in
@@ -5624,6 +5627,7 @@ routersets_get_disjunction(smartlist_t *target,
}
});
}
+#endif
/** Remove every routerinfo_t from lst that is in routerset. */
void
diff --git a/src/or/routerlist.h b/src/or/routerlist.h
index cd0eb956b5..3bbdc42eb0 100644
--- a/src/or/routerlist.h
+++ b/src/or/routerlist.h
@@ -175,9 +175,11 @@ int routerset_contains_extendinfo(const routerset_t *set,
void routerset_get_all_routers(smartlist_t *out, const routerset_t *routerset,
const routerset_t *excludeset,
int running_only);
+#if 0
void routersets_get_disjunction(smartlist_t *target, const smartlist_t *source,
const routerset_t *include,
const routerset_t *exclude, int running_only);
+#endif
void routerset_subtract_routers(smartlist_t *out,
const routerset_t *routerset);
char *routerset_to_string(const routerset_t *routerset);