diff options
| -rw-r--r-- | crates/tor-circmgr/src/build.rs | 1 | ||||
| -rw-r--r-- | crates/tor-circmgr/src/hspool.rs | 38 | ||||
| -rw-r--r-- | crates/tor-circmgr/src/hspool/pool.rs | 39 |
3 files changed, 63 insertions, 15 deletions
diff --git a/crates/tor-circmgr/src/build.rs b/crates/tor-circmgr/src/build.rs index c5169989b..4236a8976 100644 --- a/crates/tor-circmgr/src/build.rs +++ b/crates/tor-circmgr/src/build.rs @@ -385,7 +385,6 @@ pub struct CircuitBuilder<R: Runtime> { guardmgr: tor_guardmgr::GuardMgr<R>, /// The vanguard manager object used for HS circuits. #[cfg(all(feature = "vanguards", feature = "hs-common"))] - #[allow(dead_code)] // TODO HS-VANGUARDS vanguardmgr: Arc<VanguardMgr<R>>, } diff --git a/crates/tor-circmgr/src/hspool.rs b/crates/tor-circmgr/src/hspool.rs index da69805c9..5c6076d2a 100644 --- a/crates/tor-circmgr/src/hspool.rs +++ b/crates/tor-circmgr/src/hspool.rs @@ -29,6 +29,8 @@ use std::result::Result as StdResult; pub use config::HsCircPoolConfig; +use self::pool::HsCircPrefs; + /// The (onion-service-related) purpose for which a given circuit is going to be /// used. /// @@ -80,6 +82,20 @@ pub(crate) struct HsCircStub { pub(crate) kind: HsCircStubKind, } +impl HsCircStub { + /// Whether this circuit satisfies _all_ the [`HsCircPrefs`]. + /// + /// Returns `false` if any of the `prefs` are not satisfied. + fn satisfies_prefs(&self, prefs: &HsCircPrefs) -> bool { + let HsCircPrefs { kind_prefs } = prefs; + + match kind_prefs { + Some(kind) => *kind == self.kind, + None => true, + } + } +} + impl Deref for HsCircStub { type Target = Arc<ClientCirc>; @@ -265,7 +281,7 @@ impl<R: Runtime> HsCircPool<R> { if kind == HsCircKind::ClientRend { return Err(bad_api_usage!("get_or_launch_specific with ClientRend circuit!?").into()); } - // TODO HS-VANGUARDS: the kind makes no difference yet, but it will at some point in the future. + let wanted_kind = kind.stub_kind(); // For most* of these circuit types, we want to build our circuit with @@ -380,20 +396,22 @@ impl<R: Runtime> HsCircPool<R> { // restrictions, and we allow the guard to appear as either of the last // two hope of the circuit. if vanguards_enabled { - // TODO HS-VANGUARDS: check if the circuit is still usable using - // circuit_still_useable - // - // TODO HS-VANGUARDS: this is suboptimal. If we need a STUB+ - // circuit, we need to prefer STUB+ circuits over STUB - circ.can_become(kind) + circ.can_become(kind) && circuit_still_useable(netdir, circ, |_relay| true) } else { circuit_compatible_with_target(netdir, circ, &target_exclusion) } }; - let found_usable_circ = inner - .pool - .take_one_where(&mut rand::thread_rng(), restrictions); + let mut prefs = HsCircPrefs::default(); + + if vanguards_enabled { + prefs.preferred_stub_kind(kind); + } + + let found_usable_circ = + inner + .pool + .take_one_where(&mut rand::thread_rng(), restrictions, &prefs); // Tell the background task to fire immediately if we have very few circuits // circuits left, or if we found nothing. diff --git a/crates/tor-circmgr/src/hspool/pool.rs b/crates/tor-circmgr/src/hspool/pool.rs index 5209ce9fb..b33538e1d 100644 --- a/crates/tor-circmgr/src/hspool/pool.rs +++ b/crates/tor-circmgr/src/hspool/pool.rs @@ -192,14 +192,30 @@ impl Pool { self.stub_target + self.ext_stub_target } - /// If there is any circuit in this pool for which `f` returns true, return one such circuit at random, and remove it from the pool. - pub(super) fn take_one_where<R, F>(&mut self, rng: &mut R, f: F) -> Option<HsCircStub> + /// If there is any circuit in this pool for which `f` returns true and that satisfies + /// all of the specified [`HsCircPrefs`], return one such circuit at random, and remove + /// it from the pool. + /// + /// If none of the circuits satisfy `prefs`, return a randomly selected circuit for which `f` + /// returns true, and remove it from the pool. + pub(super) fn take_one_where<R, F>( + &mut self, + rng: &mut R, + f: F, + prefs: &HsCircPrefs, + ) -> Option<HsCircStub> where R: Rng, F: Fn(&HsCircStub) -> bool, { - // Select a circuit satisfying `f` at random. - let rv = match random_idx_where(rng, &mut self.circuits[..], f) { + let rv = match random_idx_where(rng, &mut self.circuits[..], |circ_stub| { + // First, check if any circuit matches _all_ the prefs + circ_stub.satisfies_prefs(prefs) && f(circ_stub) + }) + .or_else(|| { + // Select a circuit satisfying `f` at random. + random_idx_where(rng, &mut self.circuits[..], f) + }) { Some(idx) => Some(self.circuits.swap_remove(idx)), None => None, }; @@ -292,6 +308,21 @@ impl Pool { } } +/// Preferences for what kind of circuit to select from the pool. +#[derive(Default, Debug, Clone)] +pub(super) struct HsCircPrefs { + /// If `Some`, specifies the [`HsCircStubKind`] we would like. + pub(super) kind_prefs: Option<HsCircStubKind>, +} + +impl HsCircPrefs { + /// Set the preferred [`HsCircStubKind`]. + pub(super) fn preferred_stub_kind(&mut self, kind: HsCircStubKind) -> &mut Self { + self.kind_prefs = Some(kind); + self + } +} + /// Helper: find a random item `elt` in `slice` such that `predicate(elt)` is /// true. Return the index of that item. /// |
