diff --git a/crates/tor-guardmgr/src/bridge.rs b/crates/tor-guardmgr/src/bridge.rs index 2e0c8e703..db4b01007 100644 --- a/crates/tor-guardmgr/src/bridge.rs +++ b/crates/tor-guardmgr/src/bridge.rs @@ -17,3 +17,5 @@ mod relay; pub use config::{BridgeConfig, BridgeParseError}; pub use descs::{BridgeDesc, BridgeDescError, BridgeDescEvent, BridgeDescList, BridgeDescProvider}; pub use relay::BridgeRelay; + +pub(crate) use descs::BridgeSet; diff --git a/crates/tor-guardmgr/src/lib.rs b/crates/tor-guardmgr/src/lib.rs index 3b6f887cc..02f441bd3 100644 --- a/crates/tor-guardmgr/src/lib.rs +++ b/crates/tor-guardmgr/src/lib.rs @@ -110,7 +110,7 @@ pub use pending::{GuardMonitor, GuardStatus, GuardUsable}; pub use skew::SkewEstimate; use pending::{PendingRequest, RequestId}; -use sample::{GuardSet, Universe}; +use sample::{GuardSet, Universe, UniverseRef}; use crate::ids::{FirstHopIdInner, GuardId}; @@ -720,7 +720,6 @@ impl GuardMgrInner { /// is one) from our [`BridgeDescProvider`](bridge::BridgeDescProvider) (if /// we have one). #[cfg(feature = "bridge-client")] - #[allow(dead_code)] fn latest_bridge_desc_list(&self) -> Option> { self.bridge_desc_provider .as_ref() @@ -730,8 +729,10 @@ impl GuardMgrInner { /// Run a function that takes `&mut self` and an optional NetDir. /// - /// We try to use the netdir - /// from our [`NetDirProvider`] (if we have one). + /// We try to use the netdir from our [`NetDirProvider`] (if we have one). + /// Therefore, although its _parameters_ are suitable for every + /// [`GuardSet`], its _contents_ might not be. For those, call + /// [`with_opt_universe`](Self::with_opt_universe) instead. // // This function exists to handle the lifetime mess where sometimes the // resulting NetDir will borrow from `netdir`, and sometimes it will borrow @@ -747,6 +748,37 @@ impl GuardMgrInner { } } + /// Run a function that takes `&mut self` and an optional [`UniverseRef`]. + /// + /// We try to get a universe from the appropriate source for the current + /// active guard set. + fn with_opt_universe(&mut self, func: F) -> T + where + F: for<'a> FnOnce(&mut Self, Option>) -> T, + { + // TODO pt-client: soon, make the function take an GuardSet and a set + // of parameters, so we can't get the active set wrong. + match self.guards.active_set { + GuardSetSelector::Default | GuardSetSelector::Restricted => { + if let Some(nd) = self.timely_netdir() { + func(self, Some(UniverseRef::NetDir(nd.as_ref()))) + } else { + func(self, None) + } + } + #[cfg(feature = "bridge-client")] + GuardSetSelector::Bridges => { + let bridge_descs = self.latest_bridge_desc_list(); + let bridge_config = self.configured_bridges.clone(); + let bridge_set = bridge::BridgeSet::new( + bridge_config.as_ref(), + bridge_descs.as_ref().map(|b| b.as_ref()), + ); + func(self, Some(UniverseRef::BridgeSet(bridge_set))) + } + } + } + /// Update the status of all guards in the active set, based on the passage /// of time and (optionally) a network directory. If no directory is /// provided, we try to find one from the installed provider. @@ -756,13 +788,14 @@ impl GuardMgrInner { fn update(&mut self, now: SystemTime) { self.with_opt_netdir(|this, netdir| { this.update_active_set_and_filter(netdir); + }); + self.with_opt_universe(|this, univ| { Self::update_guardset_internal( &this.params, now, this.guards.active_guards_mut(), - netdir, + univ.as_ref(), ); - //XXXX use real universe }); } @@ -1226,20 +1259,20 @@ impl GuardMgrInner { }; // That didn't work. If we have a netdir, expand the sample and try again. - let res = self.with_opt_netdir(|this, dir| { - let dir = dir?; + let res = self.with_opt_universe(|this, univ| { + let univ = univ?; trace!("No guards available, trying to extend the sample."); Self::update_guardset_internal( &this.params, wallclock, this.guards.active_guards_mut(), - Some(dir), + Some(&univ), ); - if this - .guards - .active_guards_mut() - .extend_sample_as_needed(wallclock, &this.params, dir) - { + if this.guards.active_guards_mut().extend_sample_as_needed( + wallclock, + &this.params, + &univ, + ) { this.guards .active_guards_mut() .select_primary_guards(&this.params); diff --git a/crates/tor-guardmgr/src/sample.rs b/crates/tor-guardmgr/src/sample.rs index 6da0a90e4..fd06c3aad 100644 --- a/crates/tor-guardmgr/src/sample.rs +++ b/crates/tor-guardmgr/src/sample.rs @@ -25,7 +25,7 @@ use std::collections::{HashMap, HashSet}; use std::time::{Instant, SystemTime}; use tracing::{debug, info}; -pub(crate) use candidate::{Candidate, CandidateStatus, Universe, WeightThreshold}; +pub(crate) use candidate::{Candidate, CandidateStatus, Universe, UniverseRef, WeightThreshold}; /// A set of sampled guards, along with various orderings on subsets /// of the sample. diff --git a/crates/tor-guardmgr/src/sample/candidate.rs b/crates/tor-guardmgr/src/sample/candidate.rs index 7237efdb7..b9d164c5e 100644 --- a/crates/tor-guardmgr/src/sample/candidate.rs +++ b/crates/tor-guardmgr/src/sample/candidate.rs @@ -184,3 +184,68 @@ impl Universe for NetDir { .collect() } } + +/// Reference to a [`Universe`] of one of the types supported by this crate. +/// +/// This enum exists because `Universe` is not dyn-compatible. +#[derive(Clone, Debug)] +pub(crate) enum UniverseRef<'a> { + /// A reference to a netdir. + NetDir(&'a NetDir), + /// A BridgeSet (which is always references internally) + #[cfg(feature = "bridge-client")] + BridgeSet(crate::bridge::BridgeSet<'a>), +} + +impl<'a> Universe for UniverseRef<'a> { + fn contains(&self, guard: &T) -> Option { + match self { + UniverseRef::NetDir(r) => r.contains(guard), + #[cfg(feature = "bridge-client")] + UniverseRef::BridgeSet(r) => r.contains(guard), + } + } + + fn status(&self, guard: &T) -> CandidateStatus { + match self { + UniverseRef::NetDir(r) => r.status(guard), + #[cfg(feature = "bridge-client")] + UniverseRef::BridgeSet(r) => r.status(guard), + } + } + + fn timestamp(&self) -> SystemTime { + match self { + UniverseRef::NetDir(r) => r.timestamp(), + #[cfg(feature = "bridge-client")] + UniverseRef::BridgeSet(r) => r.timestamp(), + } + } + + fn weight_threshold(&self, sample: &ByRelayIds, params: &GuardParams) -> WeightThreshold + where + T: HasRelayIds, + { + match self { + UniverseRef::NetDir(r) => r.weight_threshold(sample, params), + #[cfg(feature = "bridge-client")] + UniverseRef::BridgeSet(r) => r.weight_threshold(sample, params), + } + } + + fn sample( + &self, + pre_existing: &ByRelayIds, + filter: &GuardFilter, + n: usize, + ) -> Vec<(Candidate, RelayWeight)> + where + T: HasRelayIds, + { + match self { + UniverseRef::NetDir(r) => r.sample(pre_existing, filter, n), + #[cfg(feature = "bridge-client")] + UniverseRef::BridgeSet(r) => r.sample(pre_existing, filter, n), + } + } +}