use alloc::boxed::Box;
use alloc::vec::Vec;
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub(crate) enum Level {
Initial = 0,
EarlyData = 1,
Handshake = 2,
OneRtt = 3,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub(crate) enum Direction {
Tx,
Rx,
}
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
pub(crate) enum EngineMode {
#[default]
Tls,
#[allow(dead_code)]
Dtls,
Quic,
}
pub(crate) trait QuicHooks: Send {
fn on_handshake_data(&mut self, level: Level, data: &[u8]);
fn on_traffic_secret(&mut self, level: Level, dir: Direction, secret: &[u8]);
fn our_transport_params(&self) -> Vec<u8>;
fn on_peer_transport_params(&mut self, raw: &[u8]);
}
#[allow(dead_code)]
pub(crate) struct NoHooks;
impl QuicHooks for NoHooks {
fn on_handshake_data(&mut self, _level: Level, _data: &[u8]) {}
fn on_traffic_secret(&mut self, _level: Level, _dir: Direction, _secret: &[u8]) {}
fn our_transport_params(&self) -> alloc::vec::Vec<u8> {
alloc::vec::Vec::new()
}
fn on_peer_transport_params(&mut self, _raw: &[u8]) {}
}
pub(crate) type BoxedHooks = Box<dyn QuicHooks>;
#[cfg(test)]
pub(crate) mod tests {
use super::*;
use alloc::vec::Vec;
pub(crate) struct CapturingHooks {
pub our_params: Vec<u8>,
pub peer_params: Vec<u8>,
pub peer_params_seen: bool,
pub tx_handshake: Vec<(Level, Vec<u8>)>,
pub secrets: Vec<(Level, Direction, Vec<u8>)>,
}
impl CapturingHooks {
pub(crate) fn new(our_params: Vec<u8>) -> Self {
Self {
our_params,
peer_params: Vec::new(),
peer_params_seen: false,
tx_handshake: Vec::new(),
secrets: Vec::new(),
}
}
}
impl QuicHooks for CapturingHooks {
fn on_handshake_data(&mut self, level: Level, data: &[u8]) {
self.tx_handshake.push((level, data.to_vec()));
}
fn on_traffic_secret(&mut self, level: Level, dir: Direction, secret: &[u8]) {
self.secrets.push((level, dir, secret.to_vec()));
}
fn our_transport_params(&self) -> Vec<u8> {
self.our_params.clone()
}
fn on_peer_transport_params(&mut self, raw: &[u8]) {
self.peer_params = raw.to_vec();
self.peer_params_seen = true;
}
}
#[test]
fn no_hooks_is_inert() {
let mut h = NoHooks;
h.on_handshake_data(Level::Initial, &[1, 2, 3]);
h.on_traffic_secret(Level::Handshake, Direction::Tx, &[4, 5]);
h.on_peer_transport_params(&[6, 7]);
assert!(h.our_transport_params().is_empty());
}
#[test]
fn capturing_hooks_records_calls() {
let mut h = CapturingHooks::new(alloc::vec![1, 2, 3]);
h.on_handshake_data(Level::Initial, b"hello");
h.on_handshake_data(Level::Handshake, b"finished");
h.on_traffic_secret(Level::Handshake, Direction::Tx, b"shts");
h.on_traffic_secret(Level::Handshake, Direction::Rx, b"chts");
h.on_peer_transport_params(b"peer");
assert_eq!(h.our_transport_params(), &[1, 2, 3]);
assert_eq!(h.tx_handshake.len(), 2);
assert_eq!(h.tx_handshake[0].0, Level::Initial);
assert_eq!(h.tx_handshake[1].0, Level::Handshake);
assert_eq!(h.secrets.len(), 2);
assert_eq!(h.peer_params, b"peer");
assert!(h.peer_params_seen);
}
#[test]
fn engine_mode_default_is_tls() {
assert_eq!(EngineMode::default(), EngineMode::Tls);
}
}