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, ¶ms, 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