Make the guard selection function return a more useful type.

This commit is contained in:
Nick Mathewson 2021-10-11 15:23:12 -04:00
parent 19038ae39a
commit 73669fa05e
3 changed files with 56 additions and 4 deletions

View File

@ -449,6 +449,14 @@ impl Guard {
pub(crate) fn get_weight(&self, dir: &NetDir) -> Option<RelayWeight> {
dir.weight_by_rsa_id(&self.id.rsa, tor_netdir::WeightRole::Guard)
}
/// Return a [`crate::Guard`] object to represent this guard.
pub(crate) fn get_external_rep(&self) -> crate::Guard {
crate::Guard {
id: self.id.clone(),
orports: self.orports.clone(),
}
}
}
impl tor_linkspec::ChanTarget for Guard {

View File

@ -133,6 +133,7 @@ use futures::task::{SpawnError, SpawnExt};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::convert::{TryFrom, TryInto};
use std::net::SocketAddr;
use std::sync::{Arc, Mutex};
use std::time::{Duration, Instant, SystemTime};
use tracing::{debug, info, trace, warn};
@ -388,7 +389,7 @@ impl<R: Runtime> GuardMgr<R> {
&self,
usage: GuardUsage,
netdir: Option<&NetDir>,
) -> Result<(GuardId, GuardMonitor, GuardUsable), PickGuardError> {
) -> Result<(Guard, GuardMonitor, GuardUsable), PickGuardError> {
let now = self.runtime.now();
let wallclock = self.runtime.wallclock();
@ -399,6 +400,11 @@ impl<R: Runtime> GuardMgr<R> {
inner.active_guards.consider_all_retries(now);
let (origin, guard_id) = inner.select_guard_with_retries(&usage, netdir, wallclock)?;
let guard = inner
.active_guards
.get(&guard_id)
.expect("Selected guard that wasn't in our sample!?")
.get_external_rep();
trace!(?guard_id, ?usage, "Guard selected");
@ -422,7 +428,7 @@ impl<R: Runtime> GuardMgr<R> {
.unbounded_send(Ok(daemon::Msg::Observe(rcv)))
.expect("Guard observer task exited prematurely");
Ok((guard_id, monitor, usable))
Ok((guard, monitor, usable))
}
/// Ensure that the message queue is flushed before proceding to
@ -774,6 +780,39 @@ impl GuardId {
}
}
/// Representation of a guard, as returned by [`GuardMgr::select_guard()`].
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Guard {
/// The guard's identities
id: GuardId,
/// The addresses at which the guard can be contacted.
orports: Vec<SocketAddr>,
}
impl Guard {
/// Return the identities of this guard.
pub fn id(&self) -> &GuardId {
&self.id
}
/// Look up this guard in `netdir`.
pub fn get_relay<'a>(&self, netdir: &'a NetDir) -> Option<Relay<'a>> {
self.id().get_relay(netdir)
}
}
// This is somewhat redundant with the implementation in crate::guard::Guard.
impl tor_linkspec::ChanTarget for Guard {
fn addrs(&self) -> &[SocketAddr] {
&self.orports[..]
}
fn ed_identity(&self) -> &pk::ed25519::Ed25519Identity {
&self.id.ed25519
}
fn rsa_identity(&self) -> &pk::rsa::RsaIdentity {
&self.id.rsa
}
}
/// The purpose for which we plan to use a guard.
///
/// This can affect the guard selection algorithm.
@ -968,9 +1007,9 @@ mod test {
guardmgr.update_network(&netdir);
guardmgr.set_filter(GuardFilter::TestingLimitKeys, &netdir);
let (id1, _mon, _usable) = guardmgr.select_guard(u, Some(&netdir)).unwrap();
let (guard, _mon, _usable) = guardmgr.select_guard(u, Some(&netdir)).unwrap();
// Make sure that the filter worked.
assert_eq!(id1.rsa.as_bytes()[0] % 4, 0);
assert_eq!(guard.id().rsa.as_bytes()[0] % 4, 0);
})
}
}

View File

@ -139,6 +139,11 @@ impl GuardSet {
assert_eq!(len_pre, len_post);
}
/// Return the guard whose id is `id`, if any.
pub(crate) fn get(&self, id: &GuardId) -> Option<&Guard> {
self.guards.get(id)
}
/// Replace the filter used by this `GuardSet` with `filter`.
///
/// Removes all primary guards that the filter doesn't permit.