1use 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;
21use tracing::instrument;
22use web_time_compat::Instant;
23
24#[async_trait]
25impl mgr::AbstractTunnel for tor_proto::ClientTunnel {
26 type Id = tor_proto::circuit::UniqId;
27
28 fn id(&self) -> Self::Id {
29 self.unique_id()
30 }
31
32 fn usable(&self) -> bool {
33 !self.is_closing()
34 }
35
36 #[allow(unstable_name_collisions)]
40 fn single_path(&self) -> tor_proto::Result<Arc<Path>> {
41 use itertools::Itertools as _;
42
43 self.all_paths().into_iter().exactly_one().map_err(|_| {
44 bad_api_usage!("requested the single path of a multi-path tunnel?!").into()
45 })
46 }
47
48 fn n_hops(&self) -> tor_proto::Result<usize> {
49 self.n_hops()
50 }
51
52 fn is_closing(&self) -> bool {
53 self.is_closed()
54 }
55
56 fn unique_id(&self) -> UniqId {
57 self.unique_id()
58 }
59
60 async fn extend<T: CircTarget + Sync>(
61 &self,
62 target: &T,
63 params: CircParameters,
64 ) -> tor_proto::Result<()> {
65 let circ = self.as_single_circ()?;
66 circ.extend(target, params).await
67 }
68
69 async fn last_known_to_be_used_at(&self) -> tor_proto::Result<Option<Instant>> {
70 self.disused_since().await
71 }
72}
73
74#[derive(Educe)]
77#[educe(Debug)]
78pub(crate) struct Plan {
79 final_spec: SupportedTunnelUsage,
81 path: OwnedPath,
84 params: CircParameters,
86 guard_status: Option<tor_guardmgr::GuardMonitor>,
89 #[educe(Debug(method = "skip_fmt"))]
93 guard_usable: Option<tor_guardmgr::GuardUsable>,
94}
95
96impl MockablePlan for Plan {}
97
98#[async_trait]
99impl<R: Runtime> crate::mgr::AbstractTunnelBuilder<R> for crate::build::TunnelBuilder<R> {
100 type Tunnel = ClientTunnel;
101 type Plan = Plan;
102
103 #[instrument(level = "trace", skip_all)]
104 fn plan_tunnel(
105 &self,
106 usage: &TargetTunnelUsage,
107 dir: DirInfo<'_>,
108 ) -> Result<(Plan, SupportedTunnelUsage)> {
109 let mut rng = rand::rng();
110 let (path, final_spec, guard_status, guard_usable) = usage.build_path(
111 &mut rng,
112 dir,
113 self.guardmgr(),
114 #[cfg(all(feature = "vanguards", feature = "hs-common"))]
115 self.vanguardmgr(),
116 self.path_config().as_ref(),
117 self.runtime().wallclock(),
118 )?;
119
120 let plan = Plan {
121 final_spec: final_spec.clone(),
122 path: (&path).try_into()?,
123 params: dir.circ_params(usage)?,
124 guard_status,
125 guard_usable,
126 };
127
128 Ok((plan, final_spec))
129 }
130
131 #[instrument(level = "trace", skip_all)]
132 async fn build_tunnel(&self, plan: Plan) -> Result<(SupportedTunnelUsage, Self::Tunnel)> {
133 use crate::build::GuardStatusHandle;
134 use tor_guardmgr::GuardStatus;
135 let Plan {
136 final_spec,
137 path,
138 params,
139 guard_status,
140 guard_usable,
141 } = plan;
142
143 let guard_usable: OptionFuture<_> = guard_usable.into();
144 let guard_status: Arc<GuardStatusHandle> = Arc::new(guard_status.into());
145
146 guard_status.pending(GuardStatus::AttemptAbandoned);
147
148 match self
155 .build_owned(
156 path,
157 ¶ms,
158 Arc::clone(&guard_status),
159 final_spec.channel_usage(),
160 )
161 .await
162 {
163 Ok(tunnel) => {
164 guard_status.report(GuardStatus::Success);
167
168 match guard_usable.await {
173 Some(Ok(true)) | None => (),
174 Some(Ok(false)) => return Err(Error::GuardNotUsable(tunnel.unique_id())),
175 Some(Err(_)) => {
176 return Err(internal!("Guard usability status cancelled").into());
177 }
178 }
179 Ok((final_spec, tunnel))
180 }
181 Err(e) => {
182 guard_status.commit();
186
187 Err(e)
188 }
189 }
190 }
191
192 fn launch_parallelism(&self, spec: &TargetTunnelUsage) -> usize {
193 match spec {
194 TargetTunnelUsage::Dir => 3,
195 _ => 1,
196 }
197 }
198
199 fn select_parallelism(&self, spec: &TargetTunnelUsage) -> usize {
200 self.launch_parallelism(spec)
201 }
202
203 fn learning_timeouts(&self) -> bool {
204 TunnelBuilder::learning_timeouts(self)
205 }
206
207 fn save_state(&self) -> Result<bool> {
208 TunnelBuilder::save_state(self)
209 }
210
211 fn path_config(&self) -> Arc<PathConfig> {
212 TunnelBuilder::path_config(self)
213 }
214
215 fn set_path_config(&self, new_config: PathConfig) {
216 TunnelBuilder::set_path_config(self, new_config);
217 }
218
219 fn estimator(&self) -> &timeouts::Estimator {
220 TunnelBuilder::estimator(self)
221 }
222
223 #[cfg(feature = "vanguards")]
224 fn vanguardmgr(&self) -> &Arc<VanguardMgr<R>> {
225 TunnelBuilder::vanguardmgr(self)
226 }
227
228 #[instrument(level = "trace", skip_all)]
229 fn upgrade_to_owned_state(&self) -> Result<()> {
230 TunnelBuilder::upgrade_to_owned_state(self)
231 }
232
233 #[instrument(level = "trace", skip_all)]
234 fn reload_state(&self) -> Result<()> {
235 TunnelBuilder::reload_state(self)
236 }
237
238 fn guardmgr(&self) -> &tor_guardmgr::GuardMgr<R> {
239 TunnelBuilder::guardmgr(self)
240 }
241
242 fn update_network_parameters(&self, p: &tor_netdir::params::NetParameters) {
243 TunnelBuilder::update_network_parameters(self, p);
244 }
245}