1
1
//! `tor-chanmgr`: Manage a set of channels on the Tor network.
2
//!
3
//! # Overview
4
//!
5
//! This crate is part of
6
//! [Arti](https://gitlab.torproject.org/tpo/core/arti/), a project to
7
//! implement [Tor](https://www.torproject.org/) in Rust.
8
//!
9
//! In Tor, a channel is a connection to a Tor relay.  It can be
10
//! direct via TLS, or indirect via TLS over a pluggable transport.
11
//! (For now, only direct channels are supported.)
12
//!
13
//! Since a channel can be used for more than one circuit, it's
14
//! important to reuse channels when possible.  This crate implements
15
//! a [`ChanMgr`] type that can be used to create channels on demand,
16
//! and return existing channels when they already exist.
17

            
18
#![deny(missing_docs)]
19
#![warn(noop_method_call)]
20
#![deny(unreachable_pub)]
21
#![warn(clippy::all)]
22
#![deny(clippy::await_holding_lock)]
23
#![deny(clippy::cargo_common_metadata)]
24
#![deny(clippy::cast_lossless)]
25
#![deny(clippy::checked_conversions)]
26
#![warn(clippy::cognitive_complexity)]
27
#![deny(clippy::debug_assert_with_mut_call)]
28
#![deny(clippy::exhaustive_enums)]
29
#![deny(clippy::exhaustive_structs)]
30
#![deny(clippy::expl_impl_clone_on_copy)]
31
#![deny(clippy::fallible_impl_from)]
32
#![deny(clippy::implicit_clone)]
33
#![deny(clippy::large_stack_arrays)]
34
#![warn(clippy::manual_ok_or)]
35
#![deny(clippy::missing_docs_in_private_items)]
36
#![deny(clippy::missing_panics_doc)]
37
#![warn(clippy::needless_borrow)]
38
#![warn(clippy::needless_pass_by_value)]
39
#![warn(clippy::option_option)]
40
#![warn(clippy::rc_buffer)]
41
#![deny(clippy::ref_option_ref)]
42
#![warn(clippy::semicolon_if_nothing_returned)]
43
#![warn(clippy::trait_duplication_in_bounds)]
44
#![deny(clippy::unnecessary_wraps)]
45
#![warn(clippy::unseparated_literal_suffix)]
46
#![deny(clippy::unwrap_used)]
47

            
48
mod builder;
49
mod err;
50
mod event;
51
mod mgr;
52
#[cfg(test)]
53
mod testing;
54

            
55
use std::time::Duration;
56
use tor_linkspec::{ChanTarget, OwnedChanTarget};
57
use tor_proto::channel::Channel;
58

            
59
pub use err::Error;
60

            
61
use tor_rtcompat::Runtime;
62

            
63
/// A Result as returned by this crate.
64
pub type Result<T> = std::result::Result<T, Error>;
65

            
66
pub use event::{ConnBlockage, ConnStatus, ConnStatusEvents};
67

            
68
/// A Type that remembers a set of live channels, and launches new
69
/// ones on request.
70
///
71
/// Use the [ChanMgr::get_or_launch] function to create a new channel, or
72
/// get one if it exists.
73
pub struct ChanMgr<R: Runtime> {
74
    /// Internal channel manager object that does the actual work.
75
    mgr: mgr::AbstractChanMgr<builder::ChanBuilder<R>>,
76

            
77
    /// Stream of [`ConnStatus`] events.
78
    bootstrap_status: event::ConnStatusEvents,
79
}
80

            
81
impl<R: Runtime> ChanMgr<R> {
82
    /// Construct a new channel manager.
83
18
    pub fn new(runtime: R) -> Self {
84
18
        let (sender, receiver) = event::channel();
85
18
        let builder = builder::ChanBuilder::new(runtime, sender);
86
18
        let mgr = mgr::AbstractChanMgr::new(builder);
87
18
        ChanMgr {
88
18
            mgr,
89
18
            bootstrap_status: receiver,
90
18
        }
91
18
    }
92

            
93
    /// Try to get a suitable channel to the provided `target`,
94
    /// launching one if one does not exist.
95
    ///
96
    /// If there is already a channel launch attempt in progress, this
97
    /// function will wait until that launch is complete, and succeed
98
    /// or fail depending on its outcome.
99
    pub async fn get_or_launch<T: ChanTarget + ?Sized>(&self, target: &T) -> Result<Channel> {
100
        let ed_identity = target.ed_identity();
101
        let targetinfo = OwnedChanTarget::from_chan_target(target);
102

            
103
        let chan = self.mgr.get_or_launch(*ed_identity, targetinfo).await?;
104
        // Double-check the match to make sure that the RSA identity is
105
        // what we wanted too.
106
        chan.check_match(target)?;
107
        Ok(chan)
108
    }
109

            
110
    /// Return a stream of [`ConnStatus`] events to tell us about changes
111
    /// in our ability to connect to the internet.
112
    ///
113
    /// Note that this stream can be lossy: the caller will not necessarily
114
    /// observe every event on the stream
115
2
    pub fn bootstrap_events(&self) -> ConnStatusEvents {
116
2
        self.bootstrap_status.clone()
117
2
    }
118

            
119
    /// Expire all channels that have been unused for too long.
120
    ///
121
    /// Return the duration from now until next channel expires.
122
2
    pub fn expire_channels(&self) -> Duration {
123
2
        self.mgr.expire_channels()
124
2
    }
125
}