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
use crate::{
misc::Either,
sync::{Arc, AtomicCell, AtomicWaker},
tls::{Alert, protocol::key_update::KeyUpdate},
};
use core::{future::poll_fn, task::Poll};
/// The RFC requires all parties (Client or Server) to send back some types of TLS records.
///
/// `WTX` automatically enforces such behavior in sequential code but how is the reader part
/// going to access the writer part in concurrent scenarios? In fact, there are numerous ways
/// to approach this and the choice is yours to make.
///
/// You can see this structure as a bridge between the reader and the writer. Examples about
/// possible utilizations are available in the `wtx-examples` directory.
#[derive(Clone, Debug)]
pub struct TlsStreamBridge<const IS_CLIENT: bool> {
inner: Arc<(AtomicCell<Option<TlsStreamBridgeData>>, AtomicWaker)>,
}
impl<const IS_CLIENT: bool> TlsStreamBridge<IS_CLIENT> {
pub(crate) fn new() -> Self {
Self { inner: Arc::new((AtomicCell::new(None), AtomicWaker::new())) }
}
/// Awaits special records sent by the concurrent reader part. It should probably be called
/// within a loop.
///
/// The future returned by this method is cancel-safe in the sense that it does not owns
/// temporary internal data.
#[inline]
pub async fn listen(&self) -> TlsStreamBridgeData {
poll_fn(|cx| {
self.inner.1.register(cx.waker());
if let Some(elem) = self.inner.0.update(|_curr| None) {
Poll::Ready(elem)
} else {
Poll::Pending
}
})
.await
}
pub(crate) fn update(&self, data: TlsStreamBridgeData) {
let _ = self.inner.0.update(|_curr| Some(data));
self.inner.1.wake();
}
}
/// Data returned by the [`TlsStreamBridge::listen`] method. Should be handed to the writer part.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct TlsStreamBridgeData {
frame: Either<Alert, KeyUpdate>,
}
impl TlsStreamBridgeData {
#[inline]
pub(crate) const fn new(frame: Either<Alert, KeyUpdate>) -> Self {
Self { frame }
}
#[inline]
pub(crate) const fn frame(self) -> Either<Alert, KeyUpdate> {
self.frame
}
}