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

            
22
#[async_trait]
23
impl 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)]
68
pub(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

            
86
impl MockablePlan for Plan {}
87

            
88
#[async_trait]
89
impl<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
32
    fn save_state(&self) -> Result<bool> {
196
32
        TunnelBuilder::save_state(self)
197
32
    }
198

            
199
8
    fn path_config(&self) -> Arc<PathConfig> {
200
8
        TunnelBuilder::path_config(self)
201
8
    }
202

            
203
4
    fn set_path_config(&self, new_config: PathConfig) {
204
4
        TunnelBuilder::set_path_config(self, new_config);
205
4
    }
206

            
207
    fn estimator(&self) -> &timeouts::Estimator {
208
        TunnelBuilder::estimator(self)
209
    }
210

            
211
    #[cfg(feature = "vanguards")]
212
30
    fn vanguardmgr(&self) -> &Arc<VanguardMgr<R>> {
213
30
        TunnelBuilder::vanguardmgr(self)
214
30
    }
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
32
    fn guardmgr(&self) -> &tor_guardmgr::GuardMgr<R> {
225
32
        TunnelBuilder::guardmgr(self)
226
32
    }
227

            
228
    fn update_network_parameters(&self, p: &tor_netdir::params::NetParameters) {
229
        TunnelBuilder::update_network_parameters(self, p);
230
    }
231
}