Skip to main content

vane_core/
l4.rs

1use std::net::SocketAddr;
2use std::sync::Arc;
3
4use tokio::net::{TcpStream, UdpSocket};
5
6use crate::fetch::AsyncReadWrite;
7
8#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, serde::Serialize, serde::Deserialize)]
9pub struct QuicAssocId(pub u64);
10
11pub enum L4Conn {
12	Tcp(TcpStream),
13	/// Cleartext stream that the listener-side peek prelude has already
14	/// drained part of, with those bytes rewound into the read side via
15	/// `PeekedStream`. Type-erased so `vane-core` doesn't need to know
16	/// the concrete adapter; downstream consumers see the connection
17	/// from byte zero.
18	Peeked(Box<dyn AsyncReadWrite + Send>),
19	/// TLS-terminated stream after a server-side handshake completed.
20	/// The trait object erases the concrete `tokio_rustls::TlsStream`
21	/// type so that `vane-core` doesn't need to depend on rustls
22	/// (the parsing + termination live in `vane-engine`). `AsyncReadWrite`
23	/// is the same trait `L4ForwardFetch` uses for byte-tunnel I/O,
24	/// auto-impl'd on any `AsyncRead + AsyncWrite + Unpin`. See
25	/// `spec/architecture/08-tls.md` § _TLS termination (L4 → L7
26	/// upgrade)_.
27	Tls(Box<dyn AsyncReadWrite + Send>),
28	Udp(UdpAssoc),
29}
30
31pub struct UdpAssoc {
32	pub socket: Arc<UdpSocket>,
33	pub peer: SocketAddr,
34	pub quic: Option<QuicAssocId>,
35}
36
37#[cfg(test)]
38mod tests {
39	use super::*;
40
41	// Compile-gate: if L4Conn's variant shape changes, this signature fails
42	// to type-check. No runtime assertion is warranted.
43	fn _accepts_l4_conn(_: &L4Conn) {}
44
45	#[test]
46	fn quic_assoc_id_serde_round_trip() {
47		let id = QuicAssocId(0xdead_beef_cafe_babe);
48		let encoded = serde_json::to_string(&id).expect("serialize");
49		let decoded: QuicAssocId = serde_json::from_str(&encoded).expect("deserialize");
50		assert_eq!(decoded, id);
51	}
52
53	#[test]
54	fn quic_assoc_id_equality_is_structural() {
55		assert_eq!(QuicAssocId(42), QuicAssocId(42));
56		assert_ne!(QuicAssocId(42), QuicAssocId(43));
57	}
58}