Skip to main content

tor_circmgr/path/
dirpath.rs

1//! Code to construct paths to a directory for non-anonymous downloads
2use super::TorPath;
3use crate::Result;
4use tor_guardmgr::{GuardMgr, GuardMonitor, GuardUsable};
5use tor_rtcompat::Runtime;
6use tracing::instrument;
7
8/// A PathBuilder that can connect to a directory.
9#[non_exhaustive]
10pub(crate) struct DirPathBuilder {}
11
12impl Default for DirPathBuilder {
13    fn default() -> Self {
14        Self::new()
15    }
16}
17
18impl DirPathBuilder {
19    /// Create a new DirPathBuilder.
20    pub(crate) fn new() -> Self {
21        DirPathBuilder {}
22    }
23
24    /// Try to create and return a path corresponding to the requirements of
25    /// this builder.
26    #[instrument(skip_all, level = "trace")]
27    pub(crate) fn pick_path<'a, RT: Runtime>(
28        &self,
29        guards: &GuardMgr<RT>,
30    ) -> Result<(TorPath<'a>, GuardMonitor, GuardUsable)> {
31        let guard_usage = tor_guardmgr::GuardUsageBuilder::default()
32            .kind(tor_guardmgr::GuardUsageKind::OneHopDirectory)
33            .build()
34            .expect("Unable to build directory guard usage");
35        let (guard, mon, usable) = guards.select_guard(guard_usage)?;
36        Ok((TorPath::new_one_hop_owned(&guard), mon, usable))
37    }
38}
39
40#[cfg(test)]
41mod test {
42    // @@ begin test lint list maintained by maint/add_warning @@
43    #![allow(clippy::bool_assert_comparison)]
44    #![allow(clippy::clone_on_copy)]
45    #![allow(clippy::dbg_macro)]
46    #![allow(clippy::mixed_attributes_style)]
47    #![allow(clippy::print_stderr)]
48    #![allow(clippy::print_stdout)]
49    #![allow(clippy::single_char_pattern)]
50    #![allow(clippy::unwrap_used)]
51    #![allow(clippy::unchecked_time_subtraction)]
52    #![allow(clippy::useless_vec)]
53    #![allow(clippy::needless_pass_by_value)]
54    //! <!-- @@ end test lint list maintained by maint/add_warning @@ -->
55
56    use super::*;
57    use std::collections::HashSet;
58    use tor_guardmgr::TestConfig;
59    use tor_linkspec::RelayIds;
60    use tor_netdir::testnet;
61    use tor_persist::TestingStateMgr;
62
63    #[test]
64    fn dirpath() {
65        tor_rtcompat::test_with_all_runtimes!(|rt| async move {
66            let netdir = testnet::construct_netdir().unwrap_if_sufficient().unwrap();
67            let statemgr = TestingStateMgr::new();
68            let guards =
69                tor_guardmgr::GuardMgr::new(rt.clone(), statemgr, &TestConfig::default()).unwrap();
70            guards.install_test_netdir(&netdir);
71
72            let mut distinct_guards = HashSet::new();
73
74            // This is a nice easy case, since we tested the harder cases
75            // in guard-spec.  We'll just have every path succeed.
76            for _ in 0..40 {
77                let (path, mon, usable) = DirPathBuilder::new().pick_path(&guards).unwrap();
78                if let crate::path::TorPathInner::OwnedOneHop(relay) = path.inner {
79                    distinct_guards.insert(RelayIds::from_relay_ids(&relay));
80                    mon.succeeded();
81                    assert!(usable.await.unwrap());
82                } else {
83                    panic!("Generated the wrong kind of path.");
84                }
85            }
86            assert_eq!(
87                distinct_guards.len(),
88                netdir.params().guard_dir_use_parallelism.get() as usize
89            );
90        });
91    }
92}