diff --git a/tor-netdir/src/lib.rs b/tor-netdir/src/lib.rs index 89f9b8446..40b86522b 100644 --- a/tor-netdir/src/lib.rs +++ b/tor-netdir/src/lib.rs @@ -1,3 +1,5 @@ +#![allow(unused)] + mod err; use tor_checkable::{ExternallySigned, SelfSigned, Timebound}; @@ -8,6 +10,7 @@ use tor_netdoc::AllowAnnotations; use ll::pk::rsa::RSAIdentity; use log::{info, warn}; +use std::cell::Cell; use std::collections::HashMap; use std::fs; use std::path::{Path, PathBuf}; @@ -28,10 +31,18 @@ pub struct NetDirConfig { cache_path: Option, } +#[derive(Copy, Clone)] +enum WeightFn { + NoBandwidths, + NoMeasuredBandwidths, + MeasuredBandwidths, +} + #[allow(unused)] pub struct NetDir { consensus: MDConsensus, mds: HashMap, + weight_fn: Cell>, } // TODO: This should probably be a more specific struct, with a trait @@ -195,7 +206,11 @@ impl NetDirConfig { } info!("Loaded {} microdescriptors", mds.len()); - Ok(NetDir { consensus, mds }) + Ok(NetDir { + consensus, + mds, + weight_fn: Cell::new(None), + }) } } @@ -219,6 +234,23 @@ impl NetDir { pub fn relays(&self) -> impl Iterator> { self.all_relays().filter(Relay::is_usable) } + fn pick_weight_fn(&self) { + let has_measured = self.relays().any(|r| r.rs.get_weight().is_measured()); + let has_nonzero = self.relays().any(|r| r.rs.get_weight().is_nonzero()); + if !has_nonzero { + self.weight_fn.set(Some(WeightFn::NoBandwidths)); + } else if !has_measured { + self.weight_fn.set(Some(WeightFn::NoMeasuredBandwidths)); + } else { + self.weight_fn.set(Some(WeightFn::MeasuredBandwidths)); + } + } + fn get_weight_fn(&self) -> WeightFn { + if self.weight_fn.get().is_none() { + self.pick_weight_fn(); + } + self.weight_fn.get().unwrap() + } } impl<'a> Relay<'a> { @@ -231,4 +263,16 @@ impl<'a> Relay<'a> { pub fn get_rsa_id(&self) -> &RSAIdentity { self.rs.get_rsa_identity() } + + fn get_weight(&self, wf: WeightFn) -> u32 { + use netstatus::RouterWeight::*; + use WeightFn::*; + match (wf, self.rs.get_weight()) { + (NoBandwidths, _) => 1, + (NoMeasuredBandwidths, Unmeasured(u)) => *u, + (NoMeasuredBandwidths, Measured(u)) => *u, + (MeasuredBandwidths, Unmeasured(_)) => 0, + (MeasuredBandwidths, Measured(u)) => *u, + } + } } diff --git a/tor-netdoc/src/netstatus.rs b/tor-netdoc/src/netstatus.rs index 8a4c6a3b8..c98210031 100644 --- a/tor-netdoc/src/netstatus.rs +++ b/tor-netdoc/src/netstatus.rs @@ -170,12 +170,32 @@ struct RouterFlags { /// Recognized weight fields on a single relay in a consensus #[allow(dead_code)] -enum RouterWeight { +pub enum RouterWeight { // TODO SPEC: Document that these are u32 in dir-spec.txt + /// An unmeasured weight for a router. Unmeasured(u32), + /// An measured weight for a router. Measured(u32), } +impl RouterWeight { + /// Return true if this weight is the result of a successful measurement + pub fn is_measured(&self) -> bool { + match self { + RouterWeight::Measured(x) if x > &0 => true, + _ => false, + } + } + /// Return true if this weight is nonzero + pub fn is_nonzero(&self) -> bool { + match self { + RouterWeight::Unmeasured(0) => false, + RouterWeight::Measured(0) => false, + _ => true, + } + } +} + /// A single relay's status as represented in a microdesc consensus. #[allow(dead_code)] pub struct MDConsensusRouterStatus { @@ -207,6 +227,10 @@ impl MDConsensusRouterStatus { pub fn orport_addrs(&self) -> impl Iterator { self.addrs.iter() } + /// Return the declared weight of this routerstatus in the directory. + pub fn get_weight(&self) -> &RouterWeight { + &self.weight + } } /// All information about a single authority, as represented in a consensus