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::future::{FutureExt, RemoteHandle};
5
use futures::stream;
6
use futures::task::{Spawn, SpawnError};
7
use futures::{AsyncRead, AsyncWrite, Future};
8
use std::borrow::Cow;
9
use std::fmt::Debug;
10
use std::io::{self, Result as IoResult};
11
use std::net;
12
use tor_general_addr::unix;
13
use web_time_compat::{Duration, Instant, InstantExt, SystemTime, SystemTimeExt};
14

            
15
#[cfg(feature = "tls-server")]
16
use tor_cert_x509::TlsKeyAndCert;
17

            
18
use crate::network::{TcpListenOptions, UnixListenOptions};
19

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

            
84
impl<T> Runtime for T where
85
    T: Sync
86
        + Send
87
        + Spawn
88
        + Blocking
89
        + Clone
90
        + SleepProvider
91
        + CoarseTimeProvider
92
        + NetStreamProvider<net::SocketAddr, ListenOptions = TcpListenOptions>
93
        + NetStreamProvider<unix::SocketAddr, ListenOptions = UnixListenOptions>
94
        + TlsProvider<<Self as NetStreamProvider<net::SocketAddr>>::Stream>
95
        + UdpProvider
96
        + Debug
97
        + 'static
98
{
99
}
100

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

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

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

            
129
    /// Return the SleepProvider's view of the current wall-clock time.
130
    ///
131
    /// (This is the same as `SystemTime::now`, if not running in test mode.)
132
27211
    fn wallclock(&self) -> SystemTime {
133
27211
        SystemTime::get()
134
27211
    }
135

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

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

            
154
    /// Allow a test running under mock time to advance time by the provided duration, even if the
155
    /// above `block_advance` API has been used.
156
    ///
157
    /// This method is only for testing: it should never have any
158
    /// effect when invoked on non-testing runtimes.
159
1344
    fn allow_one_advance(&self, _dur: Duration) {}
160
}
161

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

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

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

            
312
    /// Future from [`spawn_blocking`](Self::spawn_blocking)
313
    ///
314
    /// The function callback (`f: F` in [`spawn_blocking`](Self::spawn_blocking)
315
    /// will start to run regardless of whether this future is awaited.
316
    ///
317
    /// Dropping this future doesn't stop the callback; it detaches it:
318
    /// the function will continue to run, but its output can no longer be collected.
319
    type ThreadHandle<T: Send + 'static>: Future<Output = T>;
320

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

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

            
402
/// Extension trait for [`Spawn`].
403
///
404
/// This is very similar to, and preferred over, [`futures::task::SpawnExt`].
405
/// Unlike `futures::task::SpawnExt`, it is compatible with tokio-console,
406
/// and preserves span information for `tracing`.
407
// If https://github.com/rust-lang/futures-rs/issues/2977 is ever addressed,
408
// we can consider transitioning back to `futures::task::SpawnExt`.
409
pub trait SpawnExt: Spawn {
410
    /// Spawns a task that polls the given future with output `()` to completion.
411
    ///
412
    /// See [`futures::task::SpawnExt::spawn`].
413
    #[track_caller]
414
4042
    fn spawn<Fut>(&self, future: Fut) -> Result<(), SpawnError>
415
4042
    where
416
4042
        Fut: Future<Output = ()> + Send + 'static,
417
    {
418
        use tracing::Instrument as _;
419
4042
        self.spawn_obj(Box::new(future.in_current_span()).into())
420
4042
    }
421

            
422
    /// Spawns a task that polls the given future to completion and returns a future that resolves
423
    /// to the spawned future’s output.
424
    ///
425
    /// See [`futures::task::SpawnExt::spawn_with_handle`].
426
    #[track_caller]
427
580
    fn spawn_with_handle<Fut>(
428
580
        &self,
429
580
        future: Fut,
430
580
    ) -> Result<RemoteHandle<<Fut as Future>::Output>, SpawnError>
431
580
    where
432
580
        Fut: Future + Send + 'static,
433
580
        <Fut as Future>::Output: Send,
434
    {
435
580
        let (future, handle) = future.remote_handle();
436
580
        self.spawn(future)?;
437
580
        Ok(handle)
438
580
    }
439
}
440

            
441
impl<T: Spawn> SpawnExt for T {}
442

            
443
/// Additional operations that can be performed on connected stream sockets.
444
///
445
/// Some operations provided by this trait set socket options (`setsockopt()`).
446
/// Some socket options cannot be set after a stream socket is connected,
447
/// so these options are not provided by this trait.
448
/// Instead, they should be set through options given to
449
/// [`NetStreamProvider::connect()`] or [`NetStreamProvider::listen()`].
450
/// For example, see the options provided by [`TcpListenOptions`].
451
pub trait StreamOps {
452
    /// Set the [`TCP_NOTSENT_LOWAT`] socket option, if this `Stream` is a TCP stream.
453
    ///
454
    /// Implementations should return an [`UnsupportedStreamOp`] IO error
455
    /// if the stream is not a TCP stream,
456
    /// and on platforms where the operation is not supported.
457
    ///
458
    /// [`TCP_NOTSENT_LOWAT`]: https://lwn.net/Articles/560082/
459
    fn set_tcp_notsent_lowat(&self, _notsent_lowat: u32) -> IoResult<()> {
460
        Err(UnsupportedStreamOp {
461
            op: "set_tcp_notsent_lowat",
462
            reason: "unsupported object type",
463
        }
464
        .into())
465
    }
466

            
467
    /// Return a new handle that implements [`StreamOps`],
468
    /// and that can be used independently of `self`.
469
2
    fn new_handle(&self) -> Box<dyn StreamOps + Send + Unpin> {
470
2
        Box::new(NoOpStreamOpsHandle)
471
2
    }
472
}
473

            
474
/// A [`StreamOps`] handle that always returns an error.
475
///
476
/// Returned from [`StreamOps::new_handle`] for types and platforms
477
/// that do not support `StreamOps`.
478
#[derive(Copy, Clone, Debug, Default)]
479
#[non_exhaustive]
480
pub struct NoOpStreamOpsHandle;
481

            
482
impl StreamOps for NoOpStreamOpsHandle {
483
    fn new_handle(&self) -> Box<dyn StreamOps + Send + Unpin> {
484
        Box::new(*self)
485
    }
486
}
487

            
488
impl<T: StreamOps, C> StreamOps for Framed<T, C> {
489
    fn set_tcp_notsent_lowat(&self, notsent_lowat: u32) -> IoResult<()> {
490
        let inner: &T = self;
491
        inner.set_tcp_notsent_lowat(notsent_lowat)
492
    }
493

            
494
4
    fn new_handle(&self) -> Box<dyn StreamOps + Send + Unpin> {
495
4
        let inner: &T = self;
496
4
        inner.new_handle()
497
4
    }
498
}
499

            
500
/// Error: Tried to perform a [`StreamOps`] operation on an unsupported stream type
501
/// or on an unsupported platform.
502
///
503
/// (For example, you can't call [`StreamOps::set_tcp_notsent_lowat`] on Windows
504
/// or on a stream type that is not backed by a TCP socket.)
505
#[derive(Clone, Debug, thiserror::Error)]
506
#[error("Operation {op} not supported: {reason}")]
507
pub struct UnsupportedStreamOp {
508
    /// The unsupported operation.
509
    op: &'static str,
510
    /// The reason the operation is unsupported.
511
    reason: &'static str,
512
}
513

            
514
impl UnsupportedStreamOp {
515
    /// Construct a new `UnsupportedStreamOp` error with the provided operation and reason.
516
    pub fn new(op: &'static str, reason: &'static str) -> Self {
517
        Self { op, reason }
518
    }
519
}
520

            
521
impl From<UnsupportedStreamOp> for io::Error {
522
    fn from(value: UnsupportedStreamOp) -> Self {
523
        io::Error::new(io::ErrorKind::Unsupported, value)
524
    }
525
}
526

            
527
/// Trait for a runtime that can create and accept connections
528
/// over network sockets.
529
///
530
/// (In Arti we use the [`AsyncRead`] and [`AsyncWrite`] traits from
531
/// [`futures::io`] as more standard, even though the ones from Tokio
532
/// can be a bit more efficient.  Let's hope that they converge in the
533
/// future.)
534
// TODO: Use of async_trait is not ideal, since we have to box with every
535
// call.  Still, async_io basically makes that necessary :/
536
#[async_trait]
537
pub trait NetStreamProvider<ADDR = net::SocketAddr>: Clone + Send + Sync + 'static {
538
    /// The type for the connections returned by [`Self::connect()`].
539
    type Stream: AsyncRead + AsyncWrite + StreamOps + Send + Sync + Unpin + 'static;
540
    /// The type for the listeners returned by [`Self::listen()`].
541
    type Listener: NetStreamListener<ADDR, Stream = Self::Stream> + Send + Sync + Unpin + 'static;
542
    /// The options that can be passed to [`Self::connect()`].
543
    ///
544
    /// It can include options set with `setsockopt`,
545
    /// as well as options that influence higher layers (eg, the runtime).
546
    ///
547
    /// For connected streams,
548
    /// you can use [`StreamOps`] to perform additional operations
549
    /// or to configure additional options.
550
    type ConnectOptions: Clone + Default + Send + Sync + Unpin + 'static;
551
    /// The options that can be passed to [`Self::listen()`].
552
    ///
553
    /// This includes both options that affect the listening,
554
    /// and options that will apply to any individual accepted connection streams.
555
    ///
556
    /// It can include options set with `setsockopt`,
557
    /// as well as options that influence higher layers (eg, the runtime).
558
    ///
559
    /// For established streams that are accepted from a listener,
560
    /// you can use [`StreamOps`] to perform additional operations
561
    /// or to configure additional options.
562
    type ListenOptions: Clone + Default + Send + Sync + Unpin + 'static;
563

            
564
    /// Launch a connection connection to a given socket address.
565
    ///
566
    /// Note that unlike `std::net:TcpStream::connect`, we do not accept
567
    /// any types other than a single `ADDR`.  We do this because
568
    /// we must be absolutely sure not to perform
569
    /// unnecessary DNS lookups.
570
    async fn connect(&self, addr: &ADDR, options: &Self::ConnectOptions) -> IoResult<Self::Stream>;
571

            
572
    /// Open a listener on a given socket address.
573
    async fn listen(&self, addr: &ADDR, options: &Self::ListenOptions) -> IoResult<Self::Listener>;
574
}
575

            
576
/// Trait for a local socket that accepts incoming streams.
577
///
578
/// These objects are returned by instances of [`NetStreamProvider`].  To use
579
/// one,
580
/// use `incoming` to convert this object into a [`stream::Stream`].
581
pub trait NetStreamListener<ADDR = net::SocketAddr> {
582
    /// The type of connections returned by [`Self::incoming()`].
583
    type Stream: AsyncRead + AsyncWrite + StreamOps + Send + Sync + Unpin + 'static;
584

            
585
    /// The type of [`stream::Stream`] returned by [`Self::incoming()`].
586
    type Incoming: stream::Stream<Item = IoResult<(Self::Stream, ADDR)>>
587
        + Send
588
        + Sync
589
        + Unpin
590
        + 'static;
591

            
592
    /// Wrap this listener into a new [`stream::Stream`] that yields
593
    /// streams and addresses.
594
    fn incoming(self) -> Self::Incoming;
595

            
596
    /// Return the local address that this listener is bound to.
597
    fn local_addr(&self) -> IoResult<ADDR>;
598
}
599

            
600
/// Trait for a runtime that can send and receive UDP datagrams.
601
#[async_trait]
602
pub trait UdpProvider: Clone + Send + Sync + 'static {
603
    /// The type of Udp Socket returned by [`Self::bind()`]
604
    type UdpSocket: UdpSocket + Send + Sync + Unpin + 'static;
605

            
606
    /// Bind a local port to send and receive packets from
607
    async fn bind(&self, addr: &net::SocketAddr) -> IoResult<Self::UdpSocket>;
608
}
609

            
610
/// Trait for a locally bound Udp socket that can send and receive datagrams.
611
///
612
/// These objects are returned by instances of [`UdpProvider`].
613
//
614
// NOTE that UdpSocket objects are _necessarily_ un-connected.  If you need to
615
// implement a connected Udp socket in the future, please make a new trait (and
616
// a new type.)
617
#[async_trait]
618
pub trait UdpSocket {
619
    /// Wait for an incoming datagram; return it along its address.
620
    async fn recv(&self, buf: &mut [u8]) -> IoResult<(usize, net::SocketAddr)>;
621
    /// Send a datagram to the provided address.
622
    async fn send(&self, buf: &[u8], target: &net::SocketAddr) -> IoResult<usize>;
623
    /// Return the local address that this socket is bound to.
624
    fn local_addr(&self) -> IoResult<net::SocketAddr>;
625
}
626

            
627
/// An object with a peer certificate: typically a TLS connection.
628
pub trait CertifiedConn {
629
    /// Return the keying material (RFC 5705) given a label and an optional context.
630
    fn export_keying_material(
631
        &self,
632
        len: usize,
633
        label: &[u8],
634
        context: Option<&[u8]>,
635
    ) -> IoResult<Vec<u8>>;
636
    /// Try to return the (DER-encoded) peer certificate for this
637
    /// connection, if any.
638
    fn peer_certificate(&self) -> IoResult<Option<Cow<'_, [u8]>>>;
639

            
640
    /// Try to return the (DER-encoded) link certificate (if any) containing
641
    /// the key we used to authenticate this connection.
642
    ///
643
    /// Ordinarily, this will return a certificate for server connections,
644
    /// and None for client connections.
645
    //
646
    // NOTE: (The correct return value in the _absence_ of a certificate is None.
647
    // Later, if we support optional certificates for clients,
648
    // the place to return an Unsupported error would be
649
    // from whatever function tries to set such a certificate.)
650
    fn own_certificate(&self) -> IoResult<Option<Cow<'_, [u8]>>>;
651
}
652

            
653
/// An object that knows how to wrap a TCP connection (where the type of said TCP
654
/// connection is `S`) with TLS.
655
///
656
/// # Usage notes
657
///
658
/// Note that because of Tor's peculiarities, this is not a
659
/// general-purpose TLS type.  Unlike typical users, Tor does not want
660
/// its TLS library to check whether the certificates used in TLS are signed
661
/// within the web PKI hierarchy, or what their hostnames are, or even whether
662
/// they are valid.  It *does*, however, check that the subject public key in the
663
/// certificate is indeed correctly used to authenticate the TLS handshake.
664
///
665
/// If you are implementing something other than Tor, this is **not** the
666
/// functionality you want.
667
///
668
/// How can this behavior be remotely safe, even in Tor?  It only works for Tor
669
/// because the certificate that a Tor relay uses in TLS is not actually being
670
/// used to certify that relay's public key.  Instead, the certificate only used
671
/// as a container for the relay's public key.  The real certification happens
672
/// later, inside the TLS session, when the relay presents a CERTS cell.
673
///
674
/// Such sneakiness was especially necessary before TLS 1.3, which encrypts more
675
/// of the handshake, and before pluggable transports, which make
676
/// "innocuous-looking TLS handshakes" less important than they once were.  Once
677
/// TLS 1.3 is completely ubiquitous, we might be able to specify a simpler link
678
/// handshake than Tor uses now.
679
#[async_trait]
680
pub trait TlsConnector<S> {
681
    /// The type of connection returned by this connector
682
    type Conn: AsyncRead + AsyncWrite + CertifiedConn + Unpin + Send + 'static;
683

            
684
    /// Start a TLS session over the provided TCP stream `stream`.
685
    ///
686
    /// For a client connection,
687
    /// declare `sni_hostname` as the desired hostname, but don't actually check
688
    /// whether the hostname in the certificate matches it.  The connector may
689
    /// send `sni_hostname` as part of its handshake, if it supports
690
    /// [SNI](https://en.wikipedia.org/wiki/Server_Name_Indication) or one of
691
    /// the TLS 1.3 equivalents.
692
    ///
693
    /// (For a server connection, `sni_hostname` is ignored.)
694
    async fn negotiate_unvalidated(&self, stream: S, sni_hostname: &str) -> IoResult<Self::Conn>;
695
}
696

            
697
/// Trait for a runtime that knows how to create TLS connections over
698
/// TCP streams of type `S`.
699
///
700
/// This is separate from [`TlsConnector`] because eventually we may
701
/// eventually want to support multiple `TlsConnector` implementations
702
/// that use a single [`Runtime`].
703
///
704
/// See the [`TlsConnector`] documentation for a discussion of the Tor-specific
705
/// limitations of this trait: If you are implementing something other than Tor,
706
/// this is **not** the functionality you want.
707
pub trait TlsProvider<S: StreamOps>: Clone + Send + Sync + 'static {
708
    /// The Connector object that this provider can return.
709
    type Connector: TlsConnector<S, Conn = Self::TlsStream> + Send + Sync + Unpin;
710

            
711
    /// The type of the stream returned by that connector.
712
    type TlsStream: AsyncRead + AsyncWrite + StreamOps + CertifiedConn + Unpin + Send + 'static;
713

            
714
    /// The Acceptor object that this provider can return, for handling incoming connections.
715
    type Acceptor: TlsConnector<S, Conn = Self::TlsServerStream> + Send + Sync + Unpin;
716

            
717
    /// The type of stream returned by that Acceptor.
718
    type TlsServerStream: AsyncRead
719
        + AsyncWrite
720
        + StreamOps
721
        + CertifiedConn
722
        + Unpin
723
        + Send
724
        + 'static;
725

            
726
    /// Return a TLS connector for use with this runtime.
727
    fn tls_connector(&self) -> Self::Connector;
728

            
729
    /// Return a TLS acceptor for use with this runtime.
730
    ///
731
    /// Not every [`TlsProvider`] supports this method.
732
    /// For those that do, this method is only supported
733
    /// when `tor-rtcompat` is built with the `tls-server` feature.
734
    /// When this method is unsupported, it returns an error.
735
    fn tls_acceptor(&self, settings: TlsAcceptorSettings) -> IoResult<Self::Acceptor>;
736

            
737
    /// Return true iff the keying material exporters (RFC 5705) is supported.
738
    fn supports_keying_material_export(&self) -> bool;
739
}
740

            
741
/// Settings used for constructing a TlsAcceptor.
742
#[derive(Debug, Clone)]
743
#[non_exhaustive]
744
pub struct TlsAcceptorSettings {
745
    /// The certificates and keys for this acceptor.
746
    #[cfg(feature = "tls-server")]
747
    pub(crate) identity: TlsKeyAndCert,
748

            
749
    /// Indicates that this type can not be constructed.
750
    #[cfg(not(feature = "tls-server"))]
751
    unconstructable: void::Void,
752
    //
753
    // TODO: Add support for additional certificates in a chain.
754
    // TODO: Possibly, add support for PEM.
755
}
756

            
757
impl TlsAcceptorSettings {
758
    /// Create a new TlsAcceptorSettings from a certificate and its associated private key,
759
    /// both in DER format.
760
    ///
761
    /// Does not perform full (or even, necessarily, any) validation.
762
    //
763
    // TODO: It would be great to take a tor_cert::x509::TlsKeyAndCert instead,
764
    // but that would (apparently) introduce a dependency cycle.  It would be cool to figure out how
765
    // to invert that.
766
    #[allow(clippy::unnecessary_wraps)]
767
    #[cfg(feature = "tls-server")]
768
14
    pub fn new(identity: TlsKeyAndCert) -> std::io::Result<Self> {
769
14
        Ok(Self { identity })
770
14
    }
771

            
772
    /// Return the primary certificate for this [`TlsAcceptorSettings`], in DER format.
773
6
    pub fn cert_der(&self) -> &[u8] {
774
        #[cfg(not(feature = "tls-server"))]
775
        {
776
            void::unreachable(self.unconstructable);
777
        }
778
        #[cfg(feature = "tls-server")]
779
6
        self.identity.certificates_der()[0]
780
6
    }
781
}
782

            
783
/// An error returned by TlsProvider::tls_acceptor when the TlsProvider does not have TLS server support.
784
#[derive(Clone, Debug, thiserror::Error)]
785
#[non_exhaustive]
786
#[error("This TlsProvider does not support running as a server")]
787
pub struct TlsServerUnsupported {}
788

            
789
impl From<TlsServerUnsupported> for io::Error {
790
8
    fn from(value: TlsServerUnsupported) -> Self {
791
8
        io::Error::new(io::ErrorKind::Unsupported, value)
792
8
    }
793
}