// A QUIC connection's numbering and handshake-input core (RFC 9000 §12.3, RFC 9001
// §4.1.3). A connection keeps three independent packet-number spaces — Initial,
// Handshake, and Application (1-RTT) — and a CRYPTO byte stream per encryption level,
// each ordered on its own. This skeleton routes a received packet's number to its space
// (for acknowledgement) and a received CRYPTO frame to its level's reassembler (yielding
// the contiguous TLS handshake bytes to feed the handshake), and hands out send-side
// packet numbers per space. It holds no keys or socket — the key schedule and the async
// UDP transport wrap this pure core.
///|
/// A QUIC encryption level / packet-number space (RFC 9001 §4.1.1). 0-RTT shares the
/// Application space, so the three long-lived spaces are Initial, Handshake, and
/// Application.
pub(all) enum QuicLevel {
Initial
Handshake
Application
} derive(Eq, Debug)
///|
/// A QUIC connection's per-space numbering/ACK state and per-level CRYPTO streams.
pub struct QuicConnection {
is_server : Bool
initial_space : PacketNumberSpace
handshake_space : PacketNumberSpace
application_space : PacketNumberSpace
initial_crypto : StreamReassembler
handshake_crypto : StreamReassembler
application_crypto : StreamReassembler
}
///|
/// A fresh connection (client or server) with empty spaces and CRYPTO streams.
pub fn QuicConnection::new(is_server : Bool) -> QuicConnection {
{
is_server,
initial_space: PacketNumberSpace::new(),
handshake_space: PacketNumberSpace::new(),
application_space: PacketNumberSpace::new(),
initial_crypto: StreamReassembler::new(),
handshake_crypto: StreamReassembler::new(),
application_crypto: StreamReassembler::new(),
}
}
///|
/// Whether this endpoint is the server.
pub fn QuicConnection::is_server(self : QuicConnection) -> Bool {
self.is_server
}
///|
/// The packet-number space for `level`.
pub fn QuicConnection::space(
self : QuicConnection,
level : QuicLevel,
) -> PacketNumberSpace {
match level {
Initial => self.initial_space
Handshake => self.handshake_space
Application => self.application_space
}
}
///|
/// The CRYPTO reassembler for `level`.
pub fn QuicConnection::crypto_stream(
self : QuicConnection,
level : QuicLevel,
) -> StreamReassembler {
match level {
Initial => self.initial_crypto
Handshake => self.handshake_crypto
Application => self.application_crypto
}
}
///|
/// Allocate the next packet number to send at `level`.
pub fn QuicConnection::next_packet_number(
self : QuicConnection,
level : QuicLevel,
) -> Int64 {
self.space(level).next_packet_number()
}
///|
/// Record that a packet numbered `pn` arrived at `level`; `ack_eliciting` marks one that
/// must be acknowledged.
pub fn QuicConnection::on_packet_received(
self : QuicConnection,
level : QuicLevel,
pn : Int64,
ack_eliciting : Bool,
) -> Unit {
self.space(level).on_packet_received(pn, ack_eliciting)
}
///|
/// Record the peer's acknowledgement of up to `largest` at `level`.
pub fn QuicConnection::on_ack_received(
self : QuicConnection,
level : QuicLevel,
largest : Int64,
) -> Unit {
self.space(level).on_ack_received(largest)
}
///|
/// Build the ACK frame owed at `level`, or `None` if nothing has been received there.
pub fn QuicConnection::build_ack(
self : QuicConnection,
level : QuicLevel,
ack_delay : UInt64,
) -> QuicFrame? {
self.space(level).build_ack(ack_delay)
}
///|
/// Feed a CRYPTO frame's `data` at `offset` and `level` into that level's handshake
/// stream, returning the newly contiguous TLS handshake bytes now readable (empty while
/// an earlier gap is still outstanding). CRYPTO streams carry no fin.
pub fn QuicConnection::on_crypto_frame(
self : QuicConnection,
level : QuicLevel,
offset : UInt64,
data : Bytes,
) -> Bytes raise ReassemblyError {
let stream = self.crypto_stream(level)
stream.insert(offset, data, false)
stream.read()
}