tor_circmgr/
impls.rs

1//! Implement traits from [`crate::mgr`] for the circuit types we use.
2
3use crate::build::TunnelBuilder;
4use crate::mgr::{self, MockablePlan};
5use crate::path::OwnedPath;
6use crate::usage::{SupportedTunnelUsage, TargetTunnelUsage};
7use crate::{DirInfo, Error, PathConfig, Result, timeouts};
8use async_trait::async_trait;
9use educe::Educe;
10use futures::future::OptionFuture;
11use std::sync::Arc;
12use tor_basic_utils::skip_fmt;
13use tor_error::{bad_api_usage, internal};
14#[cfg(feature = "vanguards")]
15use tor_guardmgr::vanguards::VanguardMgr;
16use tor_linkspec::CircTarget;
17use tor_proto::ClientTunnel;
18use tor_proto::circuit::UniqId;
19use tor_proto::client::circuit::{CircParameters, Path};
20use tor_rtcompat::Runtime;
21
22#[async_trait]
23impl mgr::AbstractTunnel for tor_proto::ClientTunnel {
24    type Id = tor_proto::circuit::UniqId;
25
26    fn id(&self) -> Self::Id {
27        self.unique_id()
28    }
29
30    fn usable(&self) -> bool {
31        !self.is_closing()
32    }
33
34    fn single_path(&self) -> tor_proto::Result<Arc<Path>> {
35        use itertools::Itertools as _;
36
37        self.all_paths().into_iter().exactly_one().map_err(|_| {
38            bad_api_usage!("requested the single path of a multi-path tunnel?!").into()
39        })
40    }
41
42    fn n_hops(&self) -> tor_proto::Result<usize> {
43        self.n_hops()
44    }
45
46    fn is_closing(&self) -> bool {
47        self.is_closed()
48    }
49
50    fn unique_id(&self) -> UniqId {
51        self.unique_id()
52    }
53
54    async fn extend<T: CircTarget + Sync>(
55        &self,
56        target: &T,
57        params: CircParameters,
58    ) -> tor_proto::Result<()> {
59        let circ = self.as_single_circ()?;
60        circ.extend(target, params).await
61    }
62}
63
64/// The information generated by circuit planning, and used to build a
65/// circuit.
66#[derive(Educe)]
67#[educe(Debug)]
68pub(crate) struct Plan {
69    /// The supported usage that the circuit will have when complete
70    final_spec: SupportedTunnelUsage,
71    /// An owned copy of the path to build.
72    // TODO: it would be nice if this weren't owned.
73    path: OwnedPath,
74    /// The protocol parameters to use when constructing the circuit.
75    params: CircParameters,
76    /// If this path is using a guard, we'll use this object to report
77    /// whether the circuit succeeded or failed.
78    guard_status: Option<tor_guardmgr::GuardMonitor>,
79    /// If this path is using a guard, we'll use this object to learn
80    /// whether we're allowed to use the circuit or whether we have to
81    /// wait a while.
82    #[educe(Debug(method = "skip_fmt"))]
83    guard_usable: Option<tor_guardmgr::GuardUsable>,
84}
85
86impl MockablePlan for Plan {}
87
88#[async_trait]
89impl<R: Runtime> crate::mgr::AbstractTunnelBuilder<R> for crate::build::TunnelBuilder<R> {
90    type Tunnel = ClientTunnel;
91    type Plan = Plan;
92
93    fn plan_tunnel(
94        &self,
95        usage: &TargetTunnelUsage,
96        dir: DirInfo<'_>,
97    ) -> Result<(Plan, SupportedTunnelUsage)> {
98        let mut rng = rand::rng();
99        let (path, final_spec, guard_status, guard_usable) = usage.build_path(
100            &mut rng,
101            dir,
102            self.guardmgr(),
103            #[cfg(all(feature = "vanguards", feature = "hs-common"))]
104            self.vanguardmgr(),
105            self.path_config().as_ref(),
106            self.runtime().wallclock(),
107        )?;
108
109        let plan = Plan {
110            final_spec: final_spec.clone(),
111            path: (&path).try_into()?,
112            params: dir.circ_params(usage)?,
113            guard_status,
114            guard_usable,
115        };
116
117        Ok((plan, final_spec))
118    }
119
120    async fn build_tunnel(&self, plan: Plan) -> Result<(SupportedTunnelUsage, Self::Tunnel)> {
121        use crate::build::GuardStatusHandle;
122        use tor_guardmgr::GuardStatus;
123        let Plan {
124            final_spec,
125            path,
126            params,
127            guard_status,
128            guard_usable,
129        } = plan;
130
131        let guard_usable: OptionFuture<_> = guard_usable.into();
132        let guard_status: Arc<GuardStatusHandle> = Arc::new(guard_status.into());
133
134        guard_status.pending(GuardStatus::AttemptAbandoned);
135
136        // TODO: We may want to lower the logic for handling
137        // guard_status and guard_usable into build.rs, so that they
138        // can be handled correctly on user-selected paths as well.
139        //
140        // This will probably require a different API for circuit
141        // construction.
142        match self
143            .build_owned(
144                path,
145                &params,
146                Arc::clone(&guard_status),
147                final_spec.channel_usage(),
148            )
149            .await
150        {
151            Ok(tunnel) => {
152                // Report success to the guard manager, so it knows that
153                // this guard is reachable.
154                guard_status.report(GuardStatus::Success);
155
156                // We have to wait for the guard manager to tell us whether
157                // this guard is actually _usable_ or not.  Possibly,
158                // it is a speculative guard that we're only trying out
159                // in case some preferable guard won't meet our needs.
160                match guard_usable.await {
161                    Some(Ok(true)) | None => (),
162                    Some(Ok(false)) => return Err(Error::GuardNotUsable(tunnel.unique_id())),
163                    Some(Err(_)) => {
164                        return Err(internal!("Guard usability status cancelled").into());
165                    }
166                }
167                Ok((final_spec, tunnel))
168            }
169            Err(e) => {
170                // The attempt failed; the builder should have set the
171                // pending status on the guard to some value which will
172                // tell the guard manager whether to blame the guard or not.
173                guard_status.commit();
174
175                Err(e)
176            }
177        }
178    }
179
180    fn launch_parallelism(&self, spec: &TargetTunnelUsage) -> usize {
181        match spec {
182            TargetTunnelUsage::Dir => 3,
183            _ => 1,
184        }
185    }
186
187    fn select_parallelism(&self, spec: &TargetTunnelUsage) -> usize {
188        self.launch_parallelism(spec)
189    }
190
191    fn learning_timeouts(&self) -> bool {
192        TunnelBuilder::learning_timeouts(self)
193    }
194
195    fn save_state(&self) -> Result<bool> {
196        TunnelBuilder::save_state(self)
197    }
198
199    fn path_config(&self) -> Arc<PathConfig> {
200        TunnelBuilder::path_config(self)
201    }
202
203    fn set_path_config(&self, new_config: PathConfig) {
204        TunnelBuilder::set_path_config(self, new_config);
205    }
206
207    fn estimator(&self) -> &timeouts::Estimator {
208        TunnelBuilder::estimator(self)
209    }
210
211    #[cfg(feature = "vanguards")]
212    fn vanguardmgr(&self) -> &Arc<VanguardMgr<R>> {
213        TunnelBuilder::vanguardmgr(self)
214    }
215
216    fn upgrade_to_owned_state(&self) -> Result<()> {
217        TunnelBuilder::upgrade_to_owned_state(self)
218    }
219
220    fn reload_state(&self) -> Result<()> {
221        TunnelBuilder::reload_state(self)
222    }
223
224    fn guardmgr(&self) -> &tor_guardmgr::GuardMgr<R> {
225        TunnelBuilder::guardmgr(self)
226    }
227
228    fn update_network_parameters(&self, p: &tor_netdir::params::NetParameters) {
229        TunnelBuilder::update_network_parameters(self, p);
230    }
231}