1
//! Implement traits from [`crate::mgr`] for the circuit types we use.
2

            
3
use crate::build::TunnelBuilder;
4
use crate::mgr::{self, MockablePlan};
5
use crate::path::OwnedPath;
6
use crate::usage::{SupportedTunnelUsage, TargetTunnelUsage};
7
use crate::{DirInfo, Error, PathConfig, Result, timeouts};
8
use async_trait::async_trait;
9
use educe::Educe;
10
use futures::future::OptionFuture;
11
use std::sync::Arc;
12
use tor_basic_utils::skip_fmt;
13
use tor_error::{bad_api_usage, internal};
14
#[cfg(feature = "vanguards")]
15
use tor_guardmgr::vanguards::VanguardMgr;
16
use tor_linkspec::CircTarget;
17
use tor_proto::ClientTunnel;
18
use tor_proto::circuit::UniqId;
19
use tor_proto::client::circuit::{CircParameters, Path};
20
use tor_rtcompat::Runtime;
21
use tracing::instrument;
22
use web_time_compat::Instant;
23

            
24
#[async_trait]
25
impl 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
    // TODO: replace Itertools::exactly_one() with a stdlib equivalent when there is one.
37
    //
38
    // See issue #48919 <https://github.com/rust-lang/rust/issues/48919>
39
    #[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
/// The information generated by circuit planning, and used to build a
75
/// circuit.
76
#[derive(Educe)]
77
#[educe(Debug)]
78
pub(crate) struct Plan {
79
    /// The supported usage that the circuit will have when complete
80
    final_spec: SupportedTunnelUsage,
81
    /// An owned copy of the path to build.
82
    // TODO: it would be nice if this weren't owned.
83
    path: OwnedPath,
84
    /// The protocol parameters to use when constructing the circuit.
85
    params: CircParameters,
86
    /// If this path is using a guard, we'll use this object to report
87
    /// whether the circuit succeeded or failed.
88
    guard_status: Option<tor_guardmgr::GuardMonitor>,
89
    /// If this path is using a guard, we'll use this object to learn
90
    /// whether we're allowed to use the circuit or whether we have to
91
    /// wait a while.
92
    #[educe(Debug(method = "skip_fmt"))]
93
    guard_usable: Option<tor_guardmgr::GuardUsable>,
94
}
95

            
96
impl MockablePlan for Plan {}
97

            
98
#[async_trait]
99
impl<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
        // TODO: We may want to lower the logic for handling
149
        // guard_status and guard_usable into build.rs, so that they
150
        // can be handled correctly on user-selected paths as well.
151
        //
152
        // This will probably require a different API for circuit
153
        // construction.
154
        match self
155
            .build_owned(
156
                path,
157
                &params,
158
                Arc::clone(&guard_status),
159
                final_spec.channel_usage(),
160
            )
161
            .await
162
        {
163
            Ok(tunnel) => {
164
                // Report success to the guard manager, so it knows that
165
                // this guard is reachable.
166
                guard_status.report(GuardStatus::Success);
167

            
168
                // We have to wait for the guard manager to tell us whether
169
                // this guard is actually _usable_ or not.  Possibly,
170
                // it is a speculative guard that we're only trying out
171
                // in case some preferable guard won't meet our needs.
172
                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
                // The attempt failed; the builder should have set the
183
                // pending status on the guard to some value which will
184
                // tell the guard manager whether to blame the guard or not.
185
                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
44
    fn save_state(&self) -> Result<bool> {
208
44
        TunnelBuilder::save_state(self)
209
44
    }
210

            
211
8
    fn path_config(&self) -> Arc<PathConfig> {
212
8
        TunnelBuilder::path_config(self)
213
8
    }
214

            
215
4
    fn set_path_config(&self, new_config: PathConfig) {
216
4
        TunnelBuilder::set_path_config(self, new_config);
217
4
    }
218

            
219
    fn estimator(&self) -> &timeouts::Estimator {
220
        TunnelBuilder::estimator(self)
221
    }
222

            
223
    #[cfg(feature = "vanguards")]
224
38
    fn vanguardmgr(&self) -> &Arc<VanguardMgr<R>> {
225
38
        TunnelBuilder::vanguardmgr(self)
226
38
    }
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
48
    fn guardmgr(&self) -> &tor_guardmgr::GuardMgr<R> {
239
48
        TunnelBuilder::guardmgr(self)
240
48
    }
241

            
242
    fn update_network_parameters(&self, p: &tor_netdir::params::NetParameters) {
243
        TunnelBuilder::update_network_parameters(self, p);
244
    }
245
}