1
//! Declarations for traits that we need our runtimes to implement.
2
use async_trait::async_trait;
3
use asynchronous_codec::Framed;
4
use futures::stream;
5
use futures::task::Spawn;
6
use futures::{AsyncRead, AsyncWrite, Future};
7
use std::fmt::Debug;
8
use std::io::{self, Result as IoResult};
9
use std::net;
10
use std::time::{Duration, Instant, SystemTime};
11
use tor_general_addr::unix;
12

            
13
/// A runtime for use by Tor client library code.
14
///
15
/// This trait comprises several other traits that we require all of our
16
/// runtimes to provide:
17
///
18
/// * [`futures::task::Spawn`] to launch new background tasks.
19
/// * [`SleepProvider`] to pause a task for a given amount of time.
20
/// * [`CoarseTimeProvider`] for a cheaper but less accurate notion of time.
21
/// * [`NetStreamProvider`] to launch and accept network connections.
22
/// * [`TlsProvider`] to launch TLS connections.
23
/// * [`Blocking`] to be able to run synchronous (cpubound or IO) code,
24
///   and *re*-enter the async context from synchronous thread
25
///   (This may become optional in the future, if/when we add WASM
26
///   support).
27
///
28
/// A value which is only `Runtime` cannot be used as an *entry point* to the runtime.
29
/// For that, it must also implement [`ToplevelBlockOn`],
30
/// making it a [`ToplevelRuntime`].
31
/// Since you can only [enter a runtime](ToplevelBlockOn::block_on) once,
32
/// typically you use a `ToplevelRuntime` to enter the runtime,
33
/// and use it as only a `Runtime` afterwards.
34
/// This means that library code should typically
35
/// deal with `Runtime` rather than `ToplevelRuntime`.
36
///
37
/// We require that every `Runtime` has an efficient [`Clone`] implementation
38
/// that gives a new opaque reference to the same underlying runtime.
39
///
40
/// Additionally, every `Runtime` is [`Send`] and [`Sync`], though these
41
/// requirements may be somewhat relaxed in the future.
42
///
43
/// At some future point,
44
/// Arti may require that the runtime `impl<S> TlsProvider<S>` (for suitable`S`),
45
/// rather than just for their own `TcpStream`s.
46
/// I.e., Arti may start to require that the runtime's TLS provider can wrap any streams,
47
/// not only the runtime's own TCP streams.
48
/// This might be expressed as an additional supertrait bound on `Runtime`,
49
/// eg when Rust supports GATs,
50
/// or as an additional bound on the Arti APIs that currently use `Runtime`.
51
/// For API future compatibility, if you `impl Runtime for MyRuntime`,
52
/// you should also ensure that you
53
/// ```ignore
54
/// impl<S> TlsProvider<S> for MyRuntime
55
/// where S: futures::AsyncRead + futures::AsyncWrite + Unpin + Send + 'static
56
/// ```
57
//
58
/// Perhaps we will need this if we make our own TLS connections *through* Tor,
59
/// rather than just channels to guards.
60
pub trait Runtime:
61
    Sync
62
    + Send
63
    + Spawn
64
    + Blocking
65
    + Clone
66
    + SleepProvider
67
    + CoarseTimeProvider
68
    + NetStreamProvider<net::SocketAddr>
69
    + NetStreamProvider<unix::SocketAddr>
70
    + TlsProvider<<Self as NetStreamProvider<net::SocketAddr>>::Stream>
71
    + UdpProvider
72
    + Debug
73
    + 'static
74
{
75
}
76

            
77
impl<T> Runtime for T where
78
    T: Sync
79
        + Send
80
        + Spawn
81
        + Blocking
82
        + Clone
83
        + SleepProvider
84
        + CoarseTimeProvider
85
        + NetStreamProvider<net::SocketAddr>
86
        + NetStreamProvider<unix::SocketAddr>
87
        + TlsProvider<<Self as NetStreamProvider<net::SocketAddr>>::Stream>
88
        + UdpProvider
89
        + Debug
90
        + 'static
91
{
92
}
93

            
94
/// A runtime that we can use to run Tor as a client.
95
/// * [`ToplevelBlockOn`] to block on a top-level future and run it to completion
96
///   (This may become optional in the future, if/when we add WASM
97
///   support).
98
///
99
pub trait ToplevelRuntime: Runtime + ToplevelBlockOn {}
100
impl<T: Runtime + ToplevelBlockOn> ToplevelRuntime for T {}
101

            
102
/// Trait for a runtime that can wait until a timer has expired.
103
///
104
/// Every `SleepProvider` also implements
105
/// [`SleepProviderExt`](crate::SleepProviderExt); see that trait
106
/// for other useful functions.
107
pub trait SleepProvider: Clone + Send + Sync + 'static {
108
    /// A future returned by [`SleepProvider::sleep()`]
109
    type SleepFuture: Future<Output = ()> + Send + 'static;
110
    /// Return a future that will be ready after `duration` has
111
    /// elapsed.
112
    #[must_use = "sleep() returns a future, which does nothing unless used"]
113
    fn sleep(&self, duration: Duration) -> Self::SleepFuture;
114

            
115
    /// Return the SleepProvider's view of the current instant.
116
    ///
117
    /// (This is the same as `Instant::now`, if not running in test mode.)
118
36361
    fn now(&self) -> Instant {
119
36361
        Instant::now()
120
36361
    }
121

            
122
    /// Return the SleepProvider's view of the current wall-clock time.
123
    ///
124
    /// (This is the same as `SystemTime::now`, if not running in test mode.)
125
19518
    fn wallclock(&self) -> SystemTime {
126
19518
        SystemTime::now()
127
19518
    }
128

            
129
    /// Signify that a test running under mock time shouldn't advance time yet, with a given
130
    /// unique reason string. This is useful for making sure (mock) time doesn't advance while
131
    /// things that might require some (real-world) time to complete do so, such as spawning a task
132
    /// on another thread.
133
    ///
134
    /// Call `release_advance` with the same reason string in order to unblock.
135
    ///
136
    /// This method is only for testing: it should never have any
137
    /// effect when invoked on non-testing runtimes.
138
16
    fn block_advance<T: Into<String>>(&self, _reason: T) {}
139

            
140
    /// Signify that the reason to withhold time advancing provided in a call to `block_advance` no
141
    /// longer exists, and it's fine to move time forward if nothing else is blocking advances.
142
    ///
143
    /// This method is only for testing: it should never have any
144
    /// effect when invoked on non-testing runtimes.
145
    fn release_advance<T: Into<String>>(&self, _reason: T) {}
146

            
147
    /// Allow a test running under mock time to advance time by the provided duration, even if the
148
    /// above `block_advance` API has been used.
149
    ///
150
    /// This method is only for testing: it should never have any
151
    /// effect when invoked on non-testing runtimes.
152
1224
    fn allow_one_advance(&self, _dur: Duration) {}
153
}
154

            
155
/// A provider of reduced-precision timestamps
156
///
157
/// This doesn't provide any facility for sleeping.
158
/// If you want to sleep based on reduced-precision timestamps,
159
/// convert the desired sleep duration to `std::time::Duration`
160
/// and use [`SleepProvider`].
161
pub trait CoarseTimeProvider: Clone + Send + Sync + 'static {
162
    /// Return the `CoarseTimeProvider`'s view of the current instant.
163
    ///
164
    /// This is supposed to be cheaper than `std::time::Instant::now`.
165
    fn now_coarse(&self) -> crate::coarse_time::CoarseInstant;
166
}
167

            
168
/// Trait for a runtime that can be entered to block on a toplevel future.
169
///
170
/// This trait is *not* implied by `Runtime`, only by `ToplevelRuntime`.
171
/// `ToplevelRuntime` is available at the toplevel of each program,
172
/// typically, where a concrete async executor is selected.
173
pub trait ToplevelBlockOn: Clone + Send + Sync + 'static {
174
    /// Run `future` until it is ready, and return its output.
175
    ///
176
    /// # Not reentrant!
177
    ///
178
    /// There should be one call to `block_on` (for each fresh `Runtime`),
179
    /// at the toplevel of the program (or test case).
180
    /// (Sequential calls to `block_on` from the same thread are allowed.)
181
    ///
182
    /// `block_on` may not function correctly if is called
183
    /// from multiple threads simultaneously,
184
    /// or if calls involving different `Runtime`s are interleaved on the same thread.
185
    /// (Specific runtimes may offer better guarantees.)
186
    ///
187
    /// (`tor_rtmock::MockExecutor`'s implementation will often detect violations.)
188
    fn block_on<F: Future>(&self, future: F) -> F::Output;
189
}
190

            
191
/// Support for interacting with blocking (non-async) code
192
///
193
/// This supports two use cases: blocking IO and CPU-intensive activities.
194
/// (In both of these cases, simply calling the functions within an `async` task
195
/// is a bad idea, because that can block the whole async runtime.)
196
///
197
/// ### Blocking IO
198
///
199
/// `Blocking` can be used to interact with libraries or OS primitives
200
/// that only offer a synchronous, blocking, interface.
201
///
202
/// Use [`spawn_blocking`](Blocking::spawn_blocking)
203
/// when it is convenient to have a long-running thread,
204
/// for these operations.
205
///
206
/// Use [`blocking_io`](Blocking::blocking_io)
207
/// when the blocking code is usually expected to complete quickly,
208
/// and/or you will be switching back and forth a lot
209
/// between sync and async contexts.
210
/// Note that you cannot call back to async code from within `blocking_io`.
211
///
212
/// ### CPU-intensive activities
213
///
214
/// Perform CPU-intensive work, that ought not to block the program's main loop,
215
/// via [`Blocking::spawn_blocking`].
216
///
217
/// `spawn_blocking` does not apply any limiting or prioritisation;
218
/// its threads simply compete for CPU with other threads in the program.
219
/// That must be done by the caller; therefore:
220
///
221
/// **Limit the number of cpu threads** spawned
222
/// in order to limit the total amount of CPU time consumed by any part of the program.
223
/// For example, consider using one CPU thread per Tor Hidden Service.
224
///
225
/// It is most performant to spawn a long-running thread,
226
/// rather than to repeatedly spawn short-lived threads for individual work items.
227
/// This also makes it easier to limit the number of concurrente cpu threads.
228
/// For the same reason, [`Blocking::blocking_io`] should be avoided
229
/// for the CPU-intensive use case.
230
///
231
/// ### Mapping to concrete functions from underlying libraries
232
///
233
/// The semantics of `Blocking` are heavily influenced by Tokio
234
/// and by the desire to be able to use tor-rtmock's `MockExecutor` to test Arti code.
235
///
236
/// | `tor-rtcompat`               | Tokio                 | `MockExecutor`                 |
237
/// |------------------------------|-----------------------|--------------------------------|
238
/// | `ToplevelBlockOn::block_on`  | `Runtime::block_on`   | `ToplevelBlockOn::block_on`    |
239
/// | `Blocking::spawn_blocking`   | `task::spawn_blocking`  | `subthread_spawn`            |
240
/// | `Blocking::reenter_block_on` | `Handle::block_on`    | `subthread_block_on_future`    |
241
/// | `Blocking::blocking_io`      | `block_in_place`      | `subthread_spawn`              |
242
/// | (not available)              | (not implemented)     | `progress_until_stalled` etc.  |
243
///
244
/// Re `block_on`, see also the docs for the underlying implementations in
245
/// [tokio][tokio-threadpool] and
246
/// [async-std][async-std-threadpool].
247
///
248
/// [tokio-threadpool]: https://docs.rs/tokio/latest/tokio/task/fn.spawn_blocking.html
249
/// [async-std-threadpool]: https://docs.rs/async-std/latest/async_std/task/fn.spawn_blocking.html
250
pub trait Blocking: Clone + Send + Sync + 'static {
251
    /// Spawn a thread for blocking IO or CPU-bound work.
252
    ///
253
    /// This is used in two situations:
254
    ///
255
    ///  * To perform blocking IO
256
    ///  * For cpu-intensive work
257
    ///
258
    /// See [`Blocking`]'s trait level docs for advice on choosing
259
    /// between `spawn_blocking` and [`Blocking::blocking_io`].
260
    ///
261
    /// `Blocking::spawn_blocking` is similar to `std::thread::spawn`
262
    /// but also makes any necessary arrangements so that `reenter_block_on`,
263
    /// can be called on the spawned thread.
264
    ///
265
    /// However, `Blocking::spawn_blocking` *does not guarantee*
266
    /// to use a completely fresh thread.
267
    /// The implementation may have a thread pool, allowing it reuse an existing thread.
268
    /// Correspondingly, if a very large number of `Blocking::spawn_blocking` calls,
269
    /// are in progress at once, some of them may block.
270
    /// (For example, the implementation for Tokio uses `tokio::task::spawn_blocking`,
271
    /// which has both of these properties.)
272
    ///
273
    /// ### Typical use of `spawn_blocking`
274
    ///
275
    ///  * Spawn the thread with `SpawnThread::spawn_blocking`.
276
    ///  * On that thread, receive work items from from the async environment
277
    ///    using async inter-task facilities (eg `futures::channel::mpsc::channel`),
278
    ///    called via [`reenter_block_on`](Blocking::reenter_block_on).
279
    ///  * Return answers with async inter-task facilities, calling either
280
    ///    a non-blocking immediate send (eg `[try_send`])
281
    ///    or an async send call via `reneter_block_on`.
282
    ///
283
    /// ### CPU-intensive work
284
    ///
285
    /// Limit the number of CPU-intensive concurrent threads spawned with `spawn_blocking`.
286
    /// See the [trait-level docs](Blocking) for more details.
287
    ///
288
    /// ### Panics
289
    ///
290
    /// `Blocking::spawn_blocking` may only be called from within either:
291
    ///
292
    ///  * A task or future being polled by this `Runtime`; or
293
    ///  * A thread itself spawned with `Blocking::spawn_blocking` on the this runtime.
294
    ///
295
    /// Otherwise it may malfunction or panic.
296
    /// (`tor_rtmock::MockExecutor`'s implementation will usually detect violations.)
297
    ///
298
    /// If `f` panics, `ThreadHandle` will also panic when polled
299
    /// (perhaps using `resume_unwind`).
300
    fn spawn_blocking<F, T>(&self, f: F) -> Self::ThreadHandle<T>
301
    where
302
        F: FnOnce() -> T + Send + 'static,
303
        T: Send + 'static;
304

            
305
    /// Future from [`spawn_blocking`](Self::spawn_blocking)
306
    type ThreadHandle<T: Send + 'static>: Future<Output = T>;
307

            
308
    /// Block on a future, from within `Blocking::spawn_blocking`
309
    ///
310
    /// Reenters the executor, blocking this thread until `future` is `Ready`.
311
    ///
312
    /// See [`spawn_blocking`](Blocking::spawn_blocking) and
313
    /// [`Blocking`]'s trait-level docs for more details.
314
    ///
315
    /// It is not guaranteed what thread the future will be polled on.
316
    /// In production `Runtime`s, it will usually be the thread calling `reenter_block_on`.
317
    // All existing runtimes other than MockExecutor accept a non-Send future, but
318
    // MockExecutor::subthread_block_on_future does not.
319
    // If this restriction turns out to be awkward, MockExecutor could be changed, with some work.
320
    ///
321
    /// ### Panics
322
    ///
323
    /// Must only be called on a thread made with `Blocking::spawn_blocking`.
324
    /// **Not** allowed within [`blocking_io`](Blocking::blocking_io).
325
    ///
326
    /// Otherwise it may malfunction or panic.
327
    /// (`tor_rtmock::MockExecutor`'s implemnetation will usually detect violations.)
328
    fn reenter_block_on<F>(&self, future: F) -> F::Output
329
    where
330
        F: Future,
331
        F::Output: Send + 'static;
332

            
333
    /// Perform some blocking IO from an async future
334
    ///
335
    /// Call the blocking function `f`, informing the async executor
336
    /// that we are going to perform blocking IO.
337
    ///
338
    /// This is a usually-faster, but simpler, alternative to [`Blocking::spawn_blocking`].
339
    ///
340
    /// Its API can be more convenient than `spawn_blocking`.
341
    /// `blocking_io` is intended to be more performant than `spawn_blocking`
342
    /// when called repeatedly (ie, when switching quickly between sync and async).
343
    ///
344
    /// See [`Blocking`]'s trait-level docs for more information about
345
    /// the performance properties, and on choosing between `blocking_io`
346
    /// and `spawn_blocking`.
347
    /// (Avoid using `blocking_io` for CPU-intensive work.)
348
    ///
349
    /// ### Limitations
350
    ///
351
    ///  * `f` may **not** call [`Blocking::reenter_block_on`], so:
352
    ///  * `f` cannot execute any futures.
353
    ///    If this is needed, break up `f` into smaller pieces so that the
354
    ///    futures can be awaited outside the call to `blocking_io`,
355
    ///    or use `spawn_blocking` for the whole activity.
356
    ///  * `f` *may* be called on the calling thread when `blocking_io` is called,
357
    ///    on an executor thread when the returned future is polled,
358
    ///    or a different thread.
359
    ///  * Not suitable for CPU-intensive work
360
    ///    (mostly because there is no practical way to ration or limit
361
    ///    the amount of cpu time used).
362
    ///    Use `spawn_blocking` for that.
363
    ///  * Performance better than using `spawn_blocking` each time is not guaranteed.
364
    ///
365
    /// ### Panics
366
    ///
367
    /// `Blocking::block_in_place` may only be called from within
368
    /// a task or future being polled by this `Runtime`.
369
    ///
370
    /// Otherwise it may malfunction or panic.
371
    /// (`tor_rtmock::MockExecutor`'s implemnetation will usually detect violations.)
372
    ///
373
    /// ### Fallback (provided) implementation
374
    ///
375
    /// The fallback implementation is currently used with `async_std`.
376
    /// It spawns a thread with `spawn_blocking`, once for each `blocking_io` call.
377
    fn blocking_io<F, T>(&self, f: F) -> impl Future<Output = T>
378
    where
379
        F: FnOnce() -> T + Send + 'static,
380
        T: Send + 'static,
381
    {
382
        self.spawn_blocking(f)
383
    }
384
}
385

            
386
/// Trait providing additional operations on network sockets.
387
pub trait StreamOps {
388
    /// Set the [`TCP_NOTSENT_LOWAT`] socket option, if this `Stream` is a TCP stream.
389
    ///
390
    /// Implementations should return an [`UnsupportedStreamOp`] IO error
391
    /// if the stream is not a TCP stream,
392
    /// and on platforms where the operation is not supported.
393
    ///
394
    /// [`TCP_NOTSENT_LOWAT`]: https://lwn.net/Articles/560082/
395
    fn set_tcp_notsent_lowat(&self, _notsent_lowat: u32) -> IoResult<()> {
396
        Err(UnsupportedStreamOp {
397
            op: "set_tcp_notsent_lowat",
398
            reason: "unsupported object type",
399
        }
400
        .into())
401
    }
402

            
403
    /// Return a new handle that implements [`StreamOps`],
404
    /// and that can be used independently of `self`.
405
2
    fn new_handle(&self) -> Box<dyn StreamOps + Send + Unpin> {
406
2
        Box::new(NoOpStreamOpsHandle)
407
2
    }
408
}
409

            
410
/// A [`StreamOps`] handle that always returns an error.
411
///
412
/// Returned from [`StreamOps::new_handle`] for types and platforms
413
/// that do not support `StreamOps`.
414
#[derive(Copy, Clone, Debug, Default)]
415
#[non_exhaustive]
416
pub struct NoOpStreamOpsHandle;
417

            
418
impl StreamOps for NoOpStreamOpsHandle {
419
    fn new_handle(&self) -> Box<dyn StreamOps + Send + Unpin> {
420
        Box::new(*self)
421
    }
422
}
423

            
424
impl<T: StreamOps, C> StreamOps for Framed<T, C> {
425
    fn set_tcp_notsent_lowat(&self, notsent_lowat: u32) -> IoResult<()> {
426
        let inner: &T = self;
427
        inner.set_tcp_notsent_lowat(notsent_lowat)
428
    }
429

            
430
4
    fn new_handle(&self) -> Box<dyn StreamOps + Send + Unpin> {
431
4
        let inner: &T = self;
432
4
        inner.new_handle()
433
4
    }
434
}
435

            
436
/// Error: Tried to perform a [`StreamOps`] operation on an unsupported stream type
437
/// or on an unsupported platform.
438
///
439
/// (For example, you can't call [`StreamOps::set_tcp_notsent_lowat`] on Windows
440
/// or on a stream type that is not backed by a TCP socket.)
441
#[derive(Clone, Debug, thiserror::Error)]
442
#[error("Operation {op} not supported: {reason}")]
443
pub struct UnsupportedStreamOp {
444
    /// The unsupported operation.
445
    op: &'static str,
446
    /// The reason the operation is unsupported.
447
    reason: &'static str,
448
}
449

            
450
impl UnsupportedStreamOp {
451
    /// Construct a new `UnsupportedStreamOp` error with the provided operation and reason.
452
    pub fn new(op: &'static str, reason: &'static str) -> Self {
453
        Self { op, reason }
454
    }
455
}
456

            
457
impl From<UnsupportedStreamOp> for io::Error {
458
    fn from(value: UnsupportedStreamOp) -> Self {
459
        io::Error::new(io::ErrorKind::Unsupported, value)
460
    }
461
}
462

            
463
/// Trait for a runtime that can create and accept connections
464
/// over network sockets.
465
///
466
/// (In Arti we use the [`AsyncRead`] and [`AsyncWrite`] traits from
467
/// [`futures::io`] as more standard, even though the ones from Tokio
468
/// can be a bit more efficient.  Let's hope that they converge in the
469
/// future.)
470
// TODO: Use of async_trait is not ideal, since we have to box with every
471
// call.  Still, async_io basically makes that necessary :/
472
#[async_trait]
473
pub trait NetStreamProvider<ADDR = net::SocketAddr>: Clone + Send + Sync + 'static {
474
    /// The type for the connections returned by [`Self::connect()`].
475
    type Stream: AsyncRead + AsyncWrite + StreamOps + Send + Sync + Unpin + 'static;
476
    /// The type for the listeners returned by [`Self::listen()`].
477
    type Listener: NetStreamListener<ADDR, Stream = Self::Stream> + Send + Sync + Unpin + 'static;
478

            
479
    /// Launch a connection connection to a given socket address.
480
    ///
481
    /// Note that unlike `std::net:TcpStream::connect`, we do not accept
482
    /// any types other than a single `ADDR`.  We do this because
483
    /// we must be absolutely sure not to perform
484
    /// unnecessary DNS lookups.
485
    async fn connect(&self, addr: &ADDR) -> IoResult<Self::Stream>;
486

            
487
    /// Open a listener on a given socket address.
488
    async fn listen(&self, addr: &ADDR) -> IoResult<Self::Listener>;
489
}
490

            
491
/// Trait for a local socket that accepts incoming streams.
492
///
493
/// These objects are returned by instances of [`NetStreamProvider`].  To use
494
/// one,
495
/// use `incoming` to convert this object into a [`stream::Stream`].
496
pub trait NetStreamListener<ADDR = net::SocketAddr> {
497
    /// The type of connections returned by [`Self::incoming()`].
498
    type Stream: AsyncRead + AsyncWrite + StreamOps + Send + Sync + Unpin + 'static;
499

            
500
    /// The type of [`stream::Stream`] returned by [`Self::incoming()`].
501
    type Incoming: stream::Stream<Item = IoResult<(Self::Stream, ADDR)>>
502
        + Send
503
        + Sync
504
        + Unpin
505
        + 'static;
506

            
507
    /// Wrap this listener into a new [`stream::Stream`] that yields
508
    /// streams and addresses.
509
    fn incoming(self) -> Self::Incoming;
510

            
511
    /// Return the local address that this listener is bound to.
512
    fn local_addr(&self) -> IoResult<ADDR>;
513
}
514

            
515
/// Trait for a runtime that can send and receive UDP datagrams.
516
#[async_trait]
517
pub trait UdpProvider: Clone + Send + Sync + 'static {
518
    /// The type of Udp Socket returned by [`Self::bind()`]
519
    type UdpSocket: UdpSocket + Send + Sync + Unpin + 'static;
520

            
521
    /// Bind a local port to send and receive packets from
522
    async fn bind(&self, addr: &net::SocketAddr) -> IoResult<Self::UdpSocket>;
523
}
524

            
525
/// Trait for a locally bound Udp socket that can send and receive datagrams.
526
///
527
/// These objects are returned by instances of [`UdpProvider`].
528
//
529
// NOTE that UdpSocket objects are _necessarily_ un-connected.  If you need to
530
// implement a connected Udp socket in the future, please make a new trait (and
531
// a new type.)
532
#[async_trait]
533
pub trait UdpSocket {
534
    /// Wait for an incoming datagram; return it along its address.
535
    async fn recv(&self, buf: &mut [u8]) -> IoResult<(usize, net::SocketAddr)>;
536
    /// Send a datagram to the provided address.
537
    async fn send(&self, buf: &[u8], target: &net::SocketAddr) -> IoResult<usize>;
538
    /// Return the local address that this socket is bound to.
539
    fn local_addr(&self) -> IoResult<net::SocketAddr>;
540
}
541

            
542
/// An object with a peer certificate: typically a TLS connection.
543
pub trait CertifiedConn {
544
    /// Return the keying material (RFC 5705) given a label and an optional context.
545
    fn export_keying_material(
546
        &self,
547
        len: usize,
548
        label: &[u8],
549
        context: Option<&[u8]>,
550
    ) -> IoResult<Vec<u8>>;
551
    /// Try to return the (DER-encoded) peer certificate for this
552
    /// connection, if any.
553
    fn peer_certificate(&self) -> IoResult<Option<Vec<u8>>>;
554
}
555

            
556
/// An object that knows how to wrap a TCP connection (where the type of said TCP
557
/// connection is `S`) with TLS.
558
///
559
/// # Usage notes
560
///
561
/// Note that because of Tor's peculiarities, this is not a
562
/// general-purpose TLS type.  Unlike typical users, Tor does not want
563
/// its TLS library to check whether the certificates used in TLS are signed
564
/// within the web PKI hierarchy, or what their hostnames are, or even whether
565
/// they are valid.  It *does*, however, check that the subject public key in the
566
/// certificate is indeed correctly used to authenticate the TLS handshake.
567
///
568
/// If you are implementing something other than Tor, this is **not** the
569
/// functionality you want.
570
///
571
/// How can this behavior be remotely safe, even in Tor?  It only works for Tor
572
/// because the certificate that a Tor relay uses in TLS is not actually being
573
/// used to certify that relay's public key.  Instead, the certificate only used
574
/// as a container for the relay's public key.  The real certification happens
575
/// later, inside the TLS session, when the relay presents a CERTS cell.
576
///
577
/// Such sneakiness was especially necessary before TLS 1.3, which encrypts more
578
/// of the handshake, and before pluggable transports, which make
579
/// "innocuous-looking TLS handshakes" less important than they once were.  Once
580
/// TLS 1.3 is completely ubiquitous, we might be able to specify a simpler link
581
/// handshake than Tor uses now.
582
#[async_trait]
583
pub trait TlsConnector<S> {
584
    /// The type of connection returned by this connector
585
    type Conn: AsyncRead + AsyncWrite + CertifiedConn + Unpin + Send + 'static;
586

            
587
    /// Start a TLS session over the provided TCP stream `stream`.
588
    ///
589
    /// Declare `sni_hostname` as the desired hostname, but don't actually check
590
    /// whether the hostname in the certificate matches it.  The connector may
591
    /// send `sni_hostname` as part of its handshake, if it supports
592
    /// [SNI](https://en.wikipedia.org/wiki/Server_Name_Indication) or one of
593
    /// the TLS 1.3 equivalents.
594
    async fn negotiate_unvalidated(&self, stream: S, sni_hostname: &str) -> IoResult<Self::Conn>;
595
}
596

            
597
/// Trait for a runtime that knows how to create TLS connections over
598
/// TCP streams of type `S`.
599
///
600
/// This is separate from [`TlsConnector`] because eventually we may
601
/// eventually want to support multiple `TlsConnector` implementations
602
/// that use a single [`Runtime`].
603
///
604
/// See the [`TlsConnector`] documentation for a discussion of the Tor-specific
605
/// limitations of this trait: If you are implementing something other than Tor,
606
/// this is **not** the functionality you want.
607
pub trait TlsProvider<S: StreamOps>: Clone + Send + Sync + 'static {
608
    /// The Connector object that this provider can return.
609
    type Connector: TlsConnector<S, Conn = Self::TlsStream> + Send + Sync + Unpin;
610

            
611
    /// The type of the stream returned by that connector.
612
    type TlsStream: AsyncRead + AsyncWrite + StreamOps + CertifiedConn + Unpin + Send + 'static;
613

            
614
    /// Return a TLS connector for use with this runtime.
615
    fn tls_connector(&self) -> Self::Connector;
616

            
617
    /// Return true iff the keying material exporters (RFC 5705) is supported.
618
    fn supports_keying_material_export(&self) -> bool;
619
}