1 //! Implement traits from [`crate::mgr`] for the circuit types we use.
2 
3 use crate::mgr::{self, MockablePlan};
4 use crate::path::OwnedPath;
5 use crate::usage::{SupportedCircUsage, TargetCircUsage};
6 use crate::{DirInfo, Error, Result};
7 use async_trait::async_trait;
8 use futures::future::OptionFuture;
9 use rand::{rngs::StdRng, SeedableRng};
10 use std::convert::TryInto;
11 use std::sync::Arc;
12 use tor_proto::circuit::{CircParameters, ClientCirc};
13 use tor_rtcompat::Runtime;
14 
15 impl mgr::AbstractCirc for tor_proto::circuit::ClientCirc {
16     type Id = tor_proto::circuit::UniqId;
id(&self) -> Self::Id17     fn id(&self) -> Self::Id {
18         self.unique_id()
19     }
usable(&self) -> bool20     fn usable(&self) -> bool {
21         !self.is_closing()
22     }
23 }
24 
25 /// The information generated by circuit planning, and used to build a
26 /// circuit.
27 pub(crate) struct Plan {
28     /// The supported usage that the circuit will have when complete
29     final_spec: SupportedCircUsage,
30     /// An owned copy of the path to build.
31     // TODO: it would be nice if this weren't owned.
32     path: OwnedPath,
33     /// The protocol parameters to use when constructing the circuit.
34     params: CircParameters,
35     /// If this path is using a guard, we'll use this object to report
36     /// whether the circuit succeeded or failed.
37     guard_status: Option<tor_guardmgr::GuardMonitor>,
38     /// If this path is using a guard, we'll use this object to learn
39     /// whether we're allowed to use the circuit or whether we have to
40     /// wait a while.
41     guard_usable: Option<tor_guardmgr::GuardUsable>,
42 }
43 
44 impl MockablePlan for Plan {}
45 
46 #[async_trait]
47 impl<R: Runtime> crate::mgr::AbstractCircBuilder for crate::build::CircuitBuilder<R> {
48     type Circ = ClientCirc;
49     type Spec = SupportedCircUsage;
50     type Plan = Plan;
51 
plan_circuit( &self, usage: &TargetCircUsage, dir: DirInfo<'_>, ) -> Result<(Plan, SupportedCircUsage)>52     fn plan_circuit(
53         &self,
54         usage: &TargetCircUsage,
55         dir: DirInfo<'_>,
56     ) -> Result<(Plan, SupportedCircUsage)> {
57         let mut rng = rand::thread_rng();
58         let (path, final_spec, guard_status, guard_usable) =
59             usage.build_path(&mut rng, dir, Some(self.guardmgr()), self.path_config())?;
60 
61         let plan = Plan {
62             final_spec: final_spec.clone(),
63             path: (&path).try_into()?,
64             params: dir.circ_params(),
65             guard_status,
66             guard_usable,
67         };
68 
69         Ok((plan, final_spec))
70     }
71 
build_circuit(&self, plan: Plan) -> Result<(SupportedCircUsage, Arc<ClientCirc>)>72     async fn build_circuit(&self, plan: Plan) -> Result<(SupportedCircUsage, Arc<ClientCirc>)> {
73         use crate::build::GuardStatusHandle;
74         use tor_guardmgr::GuardStatus;
75         let Plan {
76             final_spec,
77             path,
78             params,
79             guard_status,
80             guard_usable,
81         } = plan;
82         let rng = StdRng::from_rng(rand::thread_rng()).expect("couldn't construct temporary rng");
83 
84         let guard_usable: OptionFuture<_> = guard_usable.into();
85         let guard_status: Arc<GuardStatusHandle> = Arc::new(guard_status.into());
86 
87         guard_status.pending(GuardStatus::AttemptAbandoned);
88 
89         // TODO: We may want to lower the logic for handling
90         // guard_status and guard_usable into build.rs, so that they
91         // can be handled correctly on user-selected paths as well.
92         //
93         // This will probably require a different API for circuit
94         // construction.
95         match self
96             .build_owned(path, &params, rng, Arc::clone(&guard_status))
97             .await
98         {
99             Ok(circuit) => {
100                 // Report success to the guard manager, so it knows that
101                 // this guard is reachable.
102                 guard_status.report(GuardStatus::Success);
103 
104                 // We have to wait for the guard manager to tell us whether
105                 // this guard is actually _usable_ or not.  Possibly,
106                 // it is a speculative guard that we're only trying out
107                 // in case some preferable guard won't meet our needs.
108                 match guard_usable.await {
109                     Some(Ok(true)) | None => (),
110                     Some(Ok(false)) => return Err(Error::GuardNotUsable),
111                     Some(Err(_)) => {
112                         return Err(Error::Internal("Guard usability status cancelled".into()))
113                     }
114                 }
115                 Ok((final_spec, circuit))
116             }
117             Err(e) => {
118                 // The attempt failed; the builder should have set the
119                 // pending status on the guard to some value which will
120                 // tell the guard manager whether to blame the guard or not.
121                 guard_status.commit();
122 
123                 Err(e)
124             }
125         }
126     }
127 
launch_parallelism(&self, spec: &TargetCircUsage) -> usize128     fn launch_parallelism(&self, spec: &TargetCircUsage) -> usize {
129         match spec {
130             TargetCircUsage::Dir => 3,
131             _ => 1,
132         }
133     }
134 
select_parallelism(&self, spec: &TargetCircUsage) -> usize135     fn select_parallelism(&self, spec: &TargetCircUsage) -> usize {
136         self.launch_parallelism(spec)
137     }
138 
learning_timeouts(&self) -> bool139     fn learning_timeouts(&self) -> bool {
140         crate::build::CircuitBuilder::learning_timeouts(self)
141     }
142 }
143