srt_runtime/lib.rs
1//! `srt-runtime` — SRT (Secure Reliable Transport) packet codecs.
2//!
3//! Spec grounding: [`draft-sharabayko-srt-01`](https://datatracker.ietf.org/doc/html/draft-sharabayko-srt-01)
4//! (free, redistributable IETF Internet-Draft), vendored at
5//! `specs/ietf_draft_sharabayko_srt_01.txt`; the curated field tables this
6//! crate implements against live in `specs/rules/srt-rules.md`.
7//!
8//! # Scope of this release
9//!
10//! This release adds a sans-IO **ARQ (Automatic Repeat reQuest) reliability
11//! engine** (§4.8/§4.8.1/§4.8.2/§4.10), a **TSBPD delivery scheduler**
12//! (§4.5/§4.6/§4.7, curated at `specs/rules/srt-tsbpd.md`), a **LiveCC packet
13//! pacing controller** (§5.1, curated at `specs/rules/srt-livecc.md`), a
14//! **Rendezvous handshake state machine** (§4.3.2, curated at
15//! `specs/rules/srt-rendezvous.md`), and the **HSv5 Caller-Listener handshake
16//! state machine** (§4.3.1) on top of the packet codecs (§3, Packet Structure
17//! — the 16-byte SRT header, the data packet §3.1, and every control packet
18//! type in §3.2, including Handshake with its extension messages: Handshake
19//! Extension §3.2.1.1, Key Material §3.2.1.2/§3.2.2, Stream ID §3.2.1.3, Group
20//! Membership §3.2.1.4).
21//!
22//! - [`arq::Sender`] / [`arq::Receiver`] drive the loss-detection, ACK/NAK/
23//! ACKACK exchange, and RTT/RTTVar estimation (§4.8, §4.10) over the
24//! existing [`packet`] codecs — see the `arq` module doc for the full rule
25//! mapping and its explicit non-goals (TLPKTDROP, RTO/congestion control,
26//! send-queue overflow sizing).
27//! - [`tsbpd::TsbpdScheduler`] drives receiver-side delivery timing (§4.5,
28//! rule 9's `PktTsbpdTime` formula) and too-late packet drop (§4.6,
29//! `TLPKTDROP_THRESHOLD`) — see the `tsbpd` module doc for the full rule
30//! mapping and its explicit non-goals (drift estimation, sender-side
31//! TLPKTDROP, wrapping-period `TsbpdTimeBase` adjustment).
32//! - [`livecc::LiveCC`] drives sender-side packet pacing (§5.1): the
33//! `PKT_SND_PERIOD` inter-packet send interval computed from a running EWMA
34//! of `AvgPayloadSize` and the configured `MAX_BW` (§5.1.1's `MAXBW_SET` /
35//! `INPUTBW_SET` / `INPUTBW_ESTIMATED` modes) — see the `livecc` module doc
36//! for the full formula mapping.
37//! - [`filecc::FileCc`] drives sender-side **file/bulk-transfer** congestion
38//! control (§5.2): the two-phase Slow Start / Congestion Avoidance
39//! AIMD algorithm that grows/shrinks both `CWND_SIZE` and `PKT_SND_PERIOD`
40//! — the window-based sibling of [`livecc::LiveCC`]'s pacing-only model —
41//! see the `filecc` module doc for the full formula mapping and its two
42//! flagged spec gaps.
43//! - [`caller::CallerHandshake`] / [`listener::ListenerHandshake`] drive the
44//! induction → conclusion exchange (§4.3.1.1/§4.3.1.2): building the wire
45//! packets via the existing [`packet`] codecs, validating the peer's
46//! replies, and exposing [`handshake_sm::NegotiatedParams`] on success.
47//! - [`rendezvous::RendezvousHandshake`] drives the symmetric peer-to-peer
48//! exchange (§4.3.2): both sides run the same engine; the cookie contest
49//! (greater cookie wins) resolves which one plays
50//! [`rendezvous::RendezvousRole::Initiator`] vs
51//! [`rendezvous::RendezvousRole::Responder`] at runtime, through the
52//! `Waving -> Attention -> Initiated -> Connected` states.
53//!
54//! The optional `crypto` feature (off by default) adds the §6 payload
55//! **encryption** path on top of that: AES-CTR encrypt/decrypt, RFC 3394 AES
56//! key wrap/unwrap of the SEK, and PBKDF2 (HMAC-SHA1) KEK derivation — see
57//! [`crypto`]. [`packet::KeyMaterial`] still only carries the wrapped-key
58//! *bytes*; [`crypto`] is what actually wraps/unwraps and encrypts/decrypts
59//! them. The same feature also wires that primitive into the handshake
60//! exchange — [`handshake_sm::CryptoConfig`] (§6.1.5 Key Material Exchange,
61//! piggybacked on [`caller::CallerHandshake`]/[`listener::ListenerHandshake`]'s
62//! existing CONCLUSION extension flow, reusing [`packet::KeyMaterial`]
63//! rather than inventing a new wire message) — and adds a sans-IO
64//! SEK-rotation driver for §6.1.6 KM Refresh, [`km_refresh::KmRefreshDriver`].
65//!
66//! **Explicit follow-ups, not attempted here:**
67//! - CUBIC/BBR or any other alternative file-transfer congestion-control
68//! algorithm (§5.2 names them as applicable alternatives to
69//! [`filecc::FileCc`]'s default algorithm but does not describe them).
70//! - Wiring [`filecc::FileCc`] / [`livecc::LiveCC`] into a real send-queue
71//! scheduler ([`arq::Sender`] has no congestion-control hook today).
72//! - Wiring the negotiated SEK from [`handshake_sm::NegotiatedParams`] (or
73//! [`km_refresh::KmRefreshDriver`]'s events) into [`io`]'s tokio adapter to
74//! actually encrypt/decrypt data-packet payloads end-to-end over a real
75//! socket — the handshake negotiation and the rotation state machine are
76//! both sans-IO and fully wired/tested; driving real payload
77//! encryption from them through `io.rs` (additive, `crypto`-feature-gated,
78//! without touching the existing ARQ/TSBPD paths) is a follow-up.
79//!
80//! **Permanently out of scope:** the Version-4 legacy Rendezvous path (§4.3.2).
81//! Only the current HSv5 Rendezvous flow ([`rendezvous`]) is implemented; V4 is
82//! a legacy interop path for pre-HSv5 peers and is not planned.
83//!
84//! # The sans-IO contract
85//!
86//! No sockets: [`packet::SrtPacket::parse`] takes the bytes of one UDP
87//! datagram and returns a typed packet; the packet's `serialize_into` writes
88//! it back out. [`caller::CallerHandshake`] / [`listener::ListenerHandshake`]
89//! / [`rendezvous::RendezvousHandshake`] extend the same contract to the
90//! handshake *exchange* — `start`/`feed` consume typed packets and return
91//! bytes to send plus typed [`handshake_sm::HandshakeOutput`] events;
92//! timeouts/retransmits are driven by caller-supplied `tick()` calls, never a
93//! wall-clock read from inside the crate.
94//!
95//! # Reserved-bit policy
96//!
97//! Fields the spec documents as fixed-value or reserved-for-future-use
98//! (`Subtype` on every Control Type except User-Defined; the header
99//! `Type-specific Information` word where a packet type does not use it; the
100//! Key Material message's `S`/`V`/`PT`/`Sign`/`Resv1`/`Resv2`/`Resv3` fields)
101//! are validated against their spec-mandated value on parse and are not
102//! stored in the typed structs — they are reconstructed on serialize. A
103//! non-compliant value is a structured [`error::Error`], never a panic.
104//!
105//! # Module map
106//! - [`packet`] — [`packet::SrtPacket`], the data/control packet types, and
107//! their sub-structures (handshake extensions, Key Material, ACK variants,
108//! NAK loss-list coding).
109//! - [`arq`] — [`arq::Sender`] / [`arq::Receiver`] (§4.8 ARQ, §4.10 RTT),
110//! [`arq::seq`] (wrap-safe sequence arithmetic), [`arq::rtt::RttEstimator`].
111//! - [`tsbpd`] — [`tsbpd::TsbpdScheduler`]: sans-IO TSBPD delivery timing and
112//! too-late packet drop (§4.5/§4.6).
113//! - [`livecc`] — [`livecc::LiveCC`] / [`livecc::MaxBwConfig`]: sans-IO LiveCC
114//! packet pacing (§5.1).
115//! - [`filecc`] — [`filecc::FileCc`] / [`filecc::Phase`]: sans-IO FileCC
116//! window + pacing congestion control (§5.2).
117//! - [`handshake_sm`] — shared handshake types: [`handshake_sm::HandshakeConfig`],
118//! [`handshake_sm::NegotiatedParams`], [`handshake_sm::HandshakeOutput`],
119//! [`handshake_sm::RejectionReason`] (§4.3, Table 7).
120//! - [`caller`] — [`caller::CallerHandshake`] (§4.3.1, Caller role).
121//! - [`listener`] — [`listener::ListenerHandshake`] (§4.3.1, Listener role).
122//! - [`rendezvous`] — [`rendezvous::RendezvousHandshake`] (§4.3.2).
123//! - [`error`] — the [`Error`] enum and [`Result`] alias.
124//! - [`crypto`] (feature `crypto`) — §6 payload encryption primitives.
125//! - [`km_refresh`] (feature `crypto`) — [`km_refresh::KmRefreshDriver`]: the
126//! sans-IO §6.1.6 KM Refresh (SEK-rotation) state machine.
127//! - [`io`] (feature `tokio`) — [`io::SrtSocket`] / [`io::SrtListener`]: an
128//! async UDP socket adapter driving the sans-IO handshake + ARQ + TSBPD
129//! engines end-to-end over real sockets.
130
131#![cfg_attr(not(feature = "std"), no_std)]
132#![forbid(unsafe_code)]
133#![warn(missing_docs)]
134#![cfg_attr(docsrs, feature(doc_cfg))]
135
136extern crate alloc;
137
138pub mod arq;
139pub mod caller;
140#[cfg(feature = "crypto")]
141#[cfg_attr(docsrs, doc(cfg(feature = "crypto")))]
142pub mod crypto;
143pub mod error;
144pub mod filecc;
145pub mod handshake_sm;
146#[cfg(feature = "crypto")]
147#[cfg_attr(docsrs, doc(cfg(feature = "crypto")))]
148pub mod km_refresh;
149pub mod listener;
150pub mod livecc;
151pub mod packet;
152pub mod rendezvous;
153pub mod tsbpd;
154
155#[cfg(feature = "tokio")]
156#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
157pub mod io;
158
159pub use caller::{CallerHandshake, CallerHandshakeState};
160pub use error::{Error, Result};
161pub use handshake_sm::{HandshakeConfig, HandshakeOutput, NegotiatedParams, RejectionReason};
162pub use listener::{ListenerHandshake, ListenerHandshakeState};
163pub use packet::SrtPacket;
164pub use rendezvous::{RendezvousHandshake, RendezvousHandshakeState, RendezvousRole};
165
166/// The Internet-Draft this crate implements packet structure from.
167pub const SPEC: &str = "draft-sharabayko-srt-01";