summaryrefslogtreecommitdiff
path: root/tor-circmgr/src/impls.rs
blob: 79f6c91ef4bd451637cbdf8a275c2716a4bf9e82 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
//! Implement traits from [`crate::mgr`] for the circuit types we use.

use crate::mgr::{self};
use crate::usage::{SupportedCircUsage, TargetCircUsage};
use crate::{DirInfo, Result};
use async_trait::async_trait;
use rand::{rngs::StdRng, SeedableRng};
use std::convert::TryInto;
use std::sync::Arc;
use std::time::Duration;
use tor_chanmgr::ChanMgr;
use tor_proto::circuit::ClientCirc;
use tor_rtcompat::{Runtime, SleepProviderExt};

impl mgr::AbstractCirc for tor_proto::circuit::ClientCirc {
    type Id = tor_proto::circuit::UniqId;
    fn id(&self) -> Self::Id {
        self.unique_id()
    }
    fn usable(&self) -> bool {
        !self.is_closing()
    }
}

/// The information generated by circuit planning, and used to build a
/// circuit.
pub(crate) struct Plan {
    /// The supported usage that the circuit will have when complete
    final_spec: SupportedCircUsage,
    /// An owned copy of the path to build.
    // TODO: it would be nice if this weren't owned.
    path: crate::path::OwnedPath,
    /// The protocol parameters to use when constructing the circuit.
    params: tor_proto::circuit::CircParameters,
}

/// An object that knows how to build circuits.
pub(crate) struct Builder<R: Runtime> {
    /// The runtime used by this circuit builder.
    runtime: R,
    /// A channel manager that this circuit builder uses to make chanels.
    chanmgr: Arc<ChanMgr<R>>,
}

impl<R: Runtime> Builder<R> {
    /// Construct a new Builder
    pub(crate) fn new(runtime: R, chanmgr: Arc<ChanMgr<R>>) -> Self {
        Builder { runtime, chanmgr }
    }
}

#[async_trait]
impl<R: Runtime> crate::mgr::AbstractCircBuilder for Builder<R> {
    type Circ = ClientCirc;
    type Spec = SupportedCircUsage;
    type Plan = Plan;

    fn plan_circuit(
        &self,
        usage: &TargetCircUsage,
        dir: DirInfo<'_>,
    ) -> Result<(Plan, SupportedCircUsage)> {
        let mut rng = rand::thread_rng();
        let (path, final_spec) = usage.build_path(&mut rng, dir)?;

        let plan = Plan {
            final_spec: final_spec.clone(),
            path: (&path).try_into()?,
            params: dir.circ_params(),
        };

        Ok((plan, final_spec))
    }

    async fn build_circuit(&self, plan: Plan) -> Result<(SupportedCircUsage, Arc<ClientCirc>)> {
        let delay = Duration::from_secs(5); // TODO: make this configurable and inferred.

        let Plan {
            final_spec,
            path,
            params,
        } = plan;
        let mut rng =
            StdRng::from_rng(rand::thread_rng()).expect("couldn't construct temporary rng");

        let build_future = path.build_circuit(&mut rng, &self.runtime, &self.chanmgr, &params);
        let circuit = self.runtime.timeout(delay, build_future).await??;

        Ok((final_spec, circuit))
    }

    fn launch_parallelism(&self, spec: &TargetCircUsage) -> usize {
        match spec {
            TargetCircUsage::Dir => 3,
            _ => 1,
        }
    }

    fn select_parallelism(&self, spec: &TargetCircUsage) -> usize {
        self.launch_parallelism(spec)
    }
}