diff --git a/Cargo.lock b/Cargo.lock index 8b652afba..b14a06f29 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -168,6 +168,7 @@ dependencies = [ "tor-error", "tor-guardmgr", "tor-llcrypto", + "tor-netdir", "tor-netdoc", "tor-persist", "tor-proto", @@ -3808,6 +3809,7 @@ dependencies = [ "tor-basic-utils", "tor-checkable", "tor-config", + "tor-error", "tor-linkspec", "tor-llcrypto", "tor-netdoc", diff --git a/crates/arti-client/Cargo.toml b/crates/arti-client/Cargo.toml index d02643090..f8b431b91 100644 --- a/crates/arti-client/Cargo.toml +++ b/crates/arti-client/Cargo.toml @@ -75,6 +75,7 @@ tor-dirmgr = { path = "../tor-dirmgr", version = "0.5.0" } tor-error = { path = "../tor-error", version = "0.3.2" } tor-guardmgr = { path = "../tor-guardmgr", version = "0.4.0" } tor-llcrypto = { path = "../tor-llcrypto", version = "0.3.2" } +tor-netdir = { path = "../tor-netdir", version = "0.4.0" } tor-netdoc = { path = "../tor-netdoc", version = "0.4.1" } tor-persist = { path = "../tor-persist", version = "0.4.1" } tor-proto = { path = "../tor-proto", version = "0.4.0" } diff --git a/crates/arti-client/src/client.rs b/crates/arti-client/src/client.rs index a4454aba0..a2eb99c5e 100644 --- a/crates/arti-client/src/client.rs +++ b/crates/arti-client/src/client.rs @@ -12,6 +12,7 @@ use tor_basic_utils::futures::{DropNotifyWatchSender, PostageWatchSenderExt}; use tor_circmgr::isolation::Isolation; use tor_circmgr::{isolation::StreamIsolationBuilder, IsolationToken, TargetPort}; use tor_config::MutCfg; +use tor_dirmgr::Timeliness; use tor_error::{internal, Bug}; use tor_persist::{FsStateMgr, StateMgr}; use tor_proto::circuit::ClientCirc; @@ -832,6 +833,24 @@ impl TorClient { &self.runtime } + /// Return a netdir that is timely according to the rules of `timeliness`. + /// + /// Use `action` to + fn netdir( + &self, + timeliness: Timeliness, + action: &'static str, + ) -> StdResult, ErrorDetail> { + use tor_netdir::Error as E; + match self.dirmgr.netdir(timeliness) { + Ok(netdir) => Ok(netdir), + Err(E::NoInfo) | Err(E::NotEnoughInfo) => { + Err(ErrorDetail::BootstrapRequired { action }) + } + Err(error) => Err(ErrorDetail::NoDir { error, action }), + } + } + /// Get or launch an exit-suitable circuit with a given set of /// exit ports. async fn get_or_launch_exit_circ( @@ -840,12 +859,7 @@ impl TorClient { prefs: &StreamPrefs, ) -> StdResult { self.wait_for_bootstrap().await?; - let dir = self - .dirmgr - .latest_netdir() - .ok_or(ErrorDetail::BootstrapRequired { - action: "launch a circuit", - })?; + let dir = self.netdir(Timeliness::Timely, "build a circuit")?; let isolation = { let mut b = StreamIsolationBuilder::new(); diff --git a/crates/arti-client/src/err.rs b/crates/arti-client/src/err.rs index fa93ef847..bf37d41e5 100644 --- a/crates/arti-client/src/err.rs +++ b/crates/arti-client/src/err.rs @@ -204,6 +204,17 @@ enum ErrorDetail { action: &'static str }, + /// Attempted to use a `TorClient` for something when it did not + /// have a valid directory. + #[error("Tried to {action} without a valid directory")] + NoDir { + /// The underlying error. + #[source] + error: tor_netdir::Error, + /// What we were trying to do that needed a directory. + action: &'static str, + }, + /// A programming problem, either in our code or the code calling it. #[error("Programming problem")] Bug(#[from] tor_error::Bug), @@ -283,6 +294,7 @@ impl tor_error::HasKind for ErrorDetail { E::Address(_) | E::InvalidHostname => EK::InvalidStreamTarget, E::LocalAddress => EK::ForbiddenStreamTarget, E::ChanMgrSetup(e) => e.kind(), + E::NoDir { error, .. } => error.kind(), E::Bug(e) => e.kind(), } }