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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
|
//! Traits and code to define different mechanisms for building Channels to
//! different kinds of targets.
use std::sync::{Arc, Mutex};
use crate::event::ChanMgrEventSender;
use async_trait::async_trait;
use tor_error::{internal, HasKind, HasRetryTime};
use tor_linkspec::{HasChanMethod, OwnedChanTarget, PtTransportName};
use tor_proto::channel::Channel;
use tracing::debug;
/// An opaque type that lets a `ChannelFactory` update the `ChanMgr` about bootstrap progress.
///
/// A future release of this crate might make this type less opaque.
// FIXME(eta): Do that.
#[derive(Clone)]
pub struct BootstrapReporter(pub(crate) Arc<Mutex<ChanMgrEventSender>>);
impl BootstrapReporter {
#[cfg(test)]
/// Create a useless version of this type to satisfy some test.
pub(crate) fn fake() -> Self {
let (snd, _rcv) = crate::event::channel();
Self(Arc::new(Mutex::new(snd)))
}
}
/// An object that knows how to build `Channels` to `ChanTarget`s.
///
/// This trait must be object-safe.
///
/// Every [`ChanMgr`](crate::ChanMgr) has a `ChannelFactory` that it uses to
/// construct all of its channels.
///
/// A `ChannelFactory` can be implemented in terms of a
/// [`TransportImplHelper`](crate::transport::TransportImplHelper), by wrapping it in a
/// `ChanBuilder`.
///
// FIXME(eta): Rectify the below situation.
/// (In fact, as of the time of writing, this is the *only* way to implement this trait
/// outside of this crate while keeping bootstrap status reporting, since `BootstrapReporter`
/// is an opaque type.)
#[async_trait]
pub trait ChannelFactory: Send + Sync {
/// Open an authenticated channel to `target`.
///
/// This method does does not necessarily handle retries or timeouts,
/// although some of its implementations may.
///
/// This method does not necessarily handle every kind of transport. If the
/// caller provides a target with an unsupported
/// [`TransportId`](tor_linkspec::TransportId), this method should return
/// [`Error::NoSuchTransport`](crate::Error::NoSuchTransport).
async fn connect_via_transport(
&self,
target: &OwnedChanTarget,
reporter: BootstrapReporter,
) -> crate::Result<Arc<Channel>>;
}
#[async_trait]
impl<'a> ChannelFactory for Arc<(dyn ChannelFactory + Send + Sync + 'a)> {
async fn connect_via_transport(
&self,
target: &OwnedChanTarget,
reporter: BootstrapReporter,
) -> crate::Result<Arc<Channel>> {
self.as_ref().connect_via_transport(target, reporter).await
}
}
#[async_trait]
impl<'a> ChannelFactory for Box<(dyn ChannelFactory + Send + Sync + 'a)> {
async fn connect_via_transport(
&self,
target: &OwnedChanTarget,
reporter: BootstrapReporter,
) -> crate::Result<Arc<Channel>> {
self.as_ref().connect_via_transport(target, reporter).await
}
}
#[async_trait]
impl<CF> crate::mgr::AbstractChannelFactory for CF
where
CF: ChannelFactory + Sync,
{
type Channel = tor_proto::channel::Channel;
type BuildSpec = OwnedChanTarget;
async fn build_channel(
&self,
target: &Self::BuildSpec,
reporter: BootstrapReporter,
) -> crate::Result<Arc<Self::Channel>> {
debug!("Attempting to open a new channel to {target}");
self.connect_via_transport(target, reporter).await
}
}
/// The error type returned by a pluggable transport manager.
pub trait AbstractPtError:
std::error::Error + HasKind + HasRetryTime + Send + Sync + std::fmt::Debug
{
}
/// A pluggable transport manager.
///
/// We can't directly reference the `PtMgr` type from `tor-ptmgr`, because of dependency resolution
/// constraints, so this defines the interface for what one should look like.
#[async_trait]
pub trait AbstractPtMgr: Send + Sync {
/// Get a `ChannelFactory` for the provided `PtTransportName`.
async fn factory_for_transport(
&self,
transport: &PtTransportName,
) -> Result<Option<Arc<dyn ChannelFactory + Send + Sync>>, Arc<dyn AbstractPtError>>;
}
#[async_trait]
impl<P> AbstractPtMgr for Option<P>
where
P: AbstractPtMgr,
{
async fn factory_for_transport(
&self,
transport: &PtTransportName,
) -> Result<Option<Arc<dyn ChannelFactory + Send + Sync>>, Arc<dyn AbstractPtError>> {
match self {
Some(mgr) => mgr.factory_for_transport(transport).await,
None => Ok(None),
}
}
}
/// A ChannelFactory built from an optional PtMgr to use for pluggable transports, and a
/// ChannelFactory to use for everything else.
#[derive(Clone)]
pub(crate) struct CompoundFactory {
#[cfg(feature = "pt-client")]
/// The PtMgr to use for pluggable transports
ptmgr: Option<Arc<dyn AbstractPtMgr + 'static>>,
/// The factory to use for everything else
default_factory: Arc<dyn ChannelFactory + 'static>,
}
#[async_trait]
impl ChannelFactory for CompoundFactory {
async fn connect_via_transport(
&self,
target: &OwnedChanTarget,
reporter: BootstrapReporter,
) -> crate::Result<Arc<Channel>> {
use tor_linkspec::ChannelMethod::*;
let factory = match target.chan_method() {
Direct(_) => self.default_factory.clone(),
#[cfg(feature = "pt-client")]
Pluggable(a) => match self.ptmgr.as_ref() {
Some(mgr) => mgr
.factory_for_transport(a.transport())
.await
.map_err(crate::Error::Pt)?
.ok_or_else(|| crate::Error::NoSuchTransport(a.transport().clone().into()))?,
None => return Err(crate::Error::NoSuchTransport(a.transport().clone().into())),
},
#[allow(unreachable_patterns)]
_ => {
return Err(crate::Error::Internal(internal!(
"No support for channel method"
)))
}
};
factory.connect_via_transport(target, reporter).await
}
}
impl CompoundFactory {
/// Create a new `Factory` that will try to use `ptmgr` to handle pluggable
/// transports requests, and `default_factory` to handle everything else.
pub(crate) fn new(
default_factory: Arc<dyn ChannelFactory + 'static>,
#[cfg(feature = "pt-client")] ptmgr: Option<Arc<dyn AbstractPtMgr + 'static>>,
) -> Self {
Self {
default_factory,
#[cfg(feature = "pt-client")]
ptmgr,
}
}
#[cfg(feature = "pt-client")]
/// Replace the PtMgr in this object.
pub(crate) fn replace_ptmgr(&mut self, ptmgr: Arc<dyn AbstractPtMgr + 'static>) {
self.ptmgr = Some(ptmgr);
}
}
|