Skip to main content

srt_runtime/packet/
data.rs

1//! SRT data packet — `draft-sharabayko-srt-01` §3.1, Figure 3.
2//!
3//! ```text
4//! word0  0|                Packet Sequence Number (31)                 |
5//! word1  PP|O|KK|R|                Message Number (26)                 |
6//! word2                          Timestamp (32)
7//! word3                    Destination Socket ID (32)
8//! rest                              Data
9//! ```
10
11use super::{Error, Result, SEQ_NUMBER_MASK, SRT_HEADER_LEN, be32, put_be32};
12
13/// Bit width of the Message Number field (§3.1).
14const MESSAGE_NUMBER_BITS: u32 = 26;
15/// Mask for the 26-bit Message Number field (§3.1).
16const MESSAGE_NUMBER_MASK: u32 = (1 << MESSAGE_NUMBER_BITS) - 1;
17
18/// `PP` (Packet Position Flag) wire values (§3.1).
19const PP_MIDDLE: u8 = 0b00;
20const PP_LAST: u8 = 0b01;
21const PP_FIRST: u8 = 0b10;
22const PP_SOLO: u8 = 0b11;
23
24/// `KK` (Key-based Encryption Flag) wire values (§3.1).
25const KK_NOT_ENCRYPTED: u8 = 0b00;
26const KK_EVEN: u8 = 0b01;
27const KK_ODD: u8 = 0b10;
28/// `11b` — reserved; only meaningful on control packets (Key Material `KK`).
29#[cfg(test)]
30const KK_CONTROL_ONLY: u8 = 0b11;
31
32/// `PP`: Packet Position Flag — position of the data packet in its message
33/// (`draft-sharabayko-srt-01` §3.1).
34#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
35#[cfg_attr(feature = "serde", derive(serde::Serialize))]
36#[non_exhaustive]
37pub enum PacketPosition {
38    /// `10b`: first packet of the message.
39    First,
40    /// `00b`: a packet in the middle of the message.
41    Middle,
42    /// `01b`: last packet of the message.
43    Last,
44    /// `11b`: the whole message fits in a single data packet.
45    Solo,
46}
47
48impl PacketPosition {
49    /// Decode the 2-bit `PP` field.
50    pub fn from_bits(v: u8) -> Self {
51        match v & 0b11 {
52            PP_FIRST => PacketPosition::First,
53            PP_LAST => PacketPosition::Last,
54            PP_SOLO => PacketPosition::Solo,
55            _ => PacketPosition::Middle, // PP_MIDDLE, and unreachable otherwise (v & 0b11 <= 3)
56        }
57    }
58
59    /// The 2-bit wire value.
60    pub fn to_bits(self) -> u8 {
61        match self {
62            PacketPosition::First => PP_FIRST,
63            PacketPosition::Middle => PP_MIDDLE,
64            PacketPosition::Last => PP_LAST,
65            PacketPosition::Solo => PP_SOLO,
66        }
67    }
68
69    /// Spec label.
70    pub fn name(&self) -> &'static str {
71        match self {
72            PacketPosition::First => "first",
73            PacketPosition::Middle => "middle",
74            PacketPosition::Last => "last",
75            PacketPosition::Solo => "solo",
76        }
77    }
78}
79
80broadcast_common::impl_spec_display!(PacketPosition);
81
82/// `KK`: Key-based Encryption Flag — whether/how the `Data` field is
83/// encrypted (`draft-sharabayko-srt-01` §3.1, §6). `11b` is reserved for
84/// control packets (Key Material's own `KK` field, §3.2.2) and should not
85/// appear on a data packet, but is decoded rather than rejected.
86#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
87#[cfg_attr(feature = "serde", derive(serde::Serialize))]
88#[non_exhaustive]
89pub enum EncryptionKeyField {
90    /// `00b`: the payload is not encrypted.
91    NotEncrypted,
92    /// `01b`: encrypted with the even key.
93    Even,
94    /// `10b`: encrypted with the odd key.
95    Odd,
96    /// `11b`: reserved — only meaningful on control packets.
97    Reserved(u8),
98}
99
100impl EncryptionKeyField {
101    /// Decode the 2-bit `KK` field.
102    pub fn from_bits(v: u8) -> Self {
103        match v & 0b11 {
104            KK_NOT_ENCRYPTED => EncryptionKeyField::NotEncrypted,
105            KK_EVEN => EncryptionKeyField::Even,
106            KK_ODD => EncryptionKeyField::Odd,
107            other => EncryptionKeyField::Reserved(other),
108        }
109    }
110
111    /// The 2-bit wire value.
112    pub fn to_bits(self) -> u8 {
113        match self {
114            EncryptionKeyField::NotEncrypted => KK_NOT_ENCRYPTED,
115            EncryptionKeyField::Even => KK_EVEN,
116            EncryptionKeyField::Odd => KK_ODD,
117            EncryptionKeyField::Reserved(v) => v & 0b11,
118        }
119    }
120
121    /// Spec label.
122    pub fn name(&self) -> &'static str {
123        match self {
124            EncryptionKeyField::NotEncrypted => "not encrypted",
125            EncryptionKeyField::Even => "even key",
126            EncryptionKeyField::Odd => "odd key",
127            EncryptionKeyField::Reserved(_) => "reserved",
128        }
129    }
130}
131
132broadcast_common::impl_spec_display!(EncryptionKeyField, Reserved);
133
134/// An SRT data packet (`draft-sharabayko-srt-01` §3.1, Figure 3).
135#[derive(Debug, Clone, PartialEq)]
136#[cfg_attr(feature = "serde", derive(serde::Serialize))]
137pub struct DataPacket<'a> {
138    /// Packet Sequence Number — 31 bits.
139    pub seq_number: u32,
140    /// `PP`: Packet Position Flag.
141    pub position: PacketPosition,
142    /// `O`: Order Flag — deliver in order (`true`) or not (`false`).
143    pub in_order: bool,
144    /// `KK`: Key-based Encryption Flag.
145    pub key_flag: EncryptionKeyField,
146    /// `R`: Retransmitted Packet Flag.
147    pub retransmitted: bool,
148    /// Message Number — 26 bits.
149    pub message_number: u32,
150    /// Timestamp, in microseconds relative to connection establishment (§3).
151    pub timestamp: u32,
152    /// Destination Socket ID (§3).
153    pub dest_socket_id: u32,
154    /// The payload. Length is whatever remains of the UDP datagram.
155    pub data: &'a [u8],
156}
157
158const KK_SHIFT: u32 = 27;
159const PP_SHIFT: u32 = 30;
160const O_SHIFT: u32 = 29;
161const R_SHIFT: u32 = 26;
162
163impl<'a> DataPacket<'a> {
164    /// Parse a data packet from `bytes` (the full SRT packet, header + data).
165    ///
166    /// # Errors
167    /// [`Error::BufferTooShort`] if shorter than the 16-byte header;
168    /// [`Error::WrongPacketKind`] if the `F` bit is set (this is a control
169    /// packet).
170    pub fn parse(bytes: &'a [u8]) -> Result<Self> {
171        if bytes.len() < SRT_HEADER_LEN {
172            return Err(Error::BufferTooShort {
173                need: SRT_HEADER_LEN,
174                have: bytes.len(),
175                what: "SRT data packet header",
176            });
177        }
178        let word0 = be32(bytes, 0);
179        if word0 & super::F_BIT != 0 {
180            return Err(Error::WrongPacketKind {
181                expected: "data packet (F=0)",
182            });
183        }
184        let word1 = be32(bytes, 4);
185        let seq_number = word0 & SEQ_NUMBER_MASK;
186        let position = PacketPosition::from_bits((word1 >> PP_SHIFT) as u8);
187        let in_order = (word1 >> O_SHIFT) & 1 != 0;
188        let key_flag = EncryptionKeyField::from_bits((word1 >> KK_SHIFT) as u8);
189        let retransmitted = (word1 >> R_SHIFT) & 1 != 0;
190        let message_number = word1 & MESSAGE_NUMBER_MASK;
191        let timestamp = be32(bytes, 8);
192        let dest_socket_id = be32(bytes, 12);
193        let data = &bytes[SRT_HEADER_LEN..];
194        Ok(DataPacket {
195            seq_number,
196            position,
197            in_order,
198            key_flag,
199            retransmitted,
200            message_number,
201            timestamp,
202            dest_socket_id,
203            data,
204        })
205    }
206
207    /// Number of bytes [`Self::serialize_into`] will write.
208    pub fn serialized_len(&self) -> usize {
209        SRT_HEADER_LEN + self.data.len()
210    }
211
212    /// Serialize this data packet into `buf`.
213    pub fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
214        let len = self.serialized_len();
215        if buf.len() < len {
216            return Err(Error::OutputBufferTooSmall {
217                need: len,
218                have: buf.len(),
219            });
220        }
221        if self.seq_number > SEQ_NUMBER_MASK {
222            return Err(Error::FieldTooWide {
223                what: "Packet Sequence Number",
224                value: u64::from(self.seq_number),
225                bits: 31,
226            });
227        }
228        if self.message_number > MESSAGE_NUMBER_MASK {
229            return Err(Error::FieldTooWide {
230                what: "Message Number",
231                value: u64::from(self.message_number),
232                bits: MESSAGE_NUMBER_BITS,
233            });
234        }
235        let word0 = self.seq_number; // F bit (bit 31) stays clear.
236        let word1 = (u32::from(self.position.to_bits()) << PP_SHIFT)
237            | (u32::from(self.in_order) << O_SHIFT)
238            | (u32::from(self.key_flag.to_bits()) << KK_SHIFT)
239            | (u32::from(self.retransmitted) << R_SHIFT)
240            | self.message_number;
241        put_be32(buf, 0, word0);
242        put_be32(buf, 4, word1);
243        put_be32(buf, 8, self.timestamp);
244        put_be32(buf, 12, self.dest_socket_id);
245        buf[SRT_HEADER_LEN..len].copy_from_slice(self.data);
246        Ok(len)
247    }
248}
249
250#[cfg(test)]
251mod tests {
252    use super::*;
253
254    fn sample() -> DataPacket<'static> {
255        DataPacket {
256            seq_number: 0x0123_4567,
257            position: PacketPosition::Solo,
258            in_order: true,
259            key_flag: EncryptionKeyField::Even,
260            retransmitted: false,
261            message_number: 0x0155_5555, // fits 26 bits
262            timestamp: 0xAABB_CCDD,
263            dest_socket_id: 0x1122_3344,
264            data: &[0x47, 0x00, 0x01, 0x02],
265        }
266    }
267
268    #[test]
269    fn round_trip_bytes_are_hand_computed() {
270        let pkt = sample();
271        let mut buf = [0u8; 20];
272        let n = pkt.serialize_into(&mut buf).unwrap();
273        assert_eq!(n, 20);
274
275        // word0: F=0, seq=0x01234567 -> top bit clear already.
276        assert_eq!(&buf[0..4], &0x0123_4567u32.to_be_bytes());
277        // word1: PP=11 (Solo), O=1, KK=01 (Even), R=0 (omitted: 0<<26 is a
278        // no-op), msg=0x01555555.
279        let expected_word1 = (0b11u32 << 30) | (1u32 << 29) | (0b01u32 << 27) | 0x0155_5555;
280        assert_eq!(&buf[4..8], &expected_word1.to_be_bytes());
281        assert_eq!(&buf[8..12], &0xAABB_CCDDu32.to_be_bytes());
282        assert_eq!(&buf[12..16], &0x1122_3344u32.to_be_bytes());
283        assert_eq!(&buf[16..20], &[0x47, 0x00, 0x01, 0x02]);
284
285        let parsed = DataPacket::parse(&buf).unwrap();
286        assert_eq!(parsed, pkt);
287    }
288
289    #[test]
290    fn mutate_field_changes_bytes() {
291        let mut pkt = sample();
292        let mut buf1 = [0u8; 20];
293        pkt.serialize_into(&mut buf1).unwrap();
294        pkt.retransmitted = true;
295        let mut buf2 = [0u8; 20];
296        pkt.serialize_into(&mut buf2).unwrap();
297        assert_ne!(buf1, buf2);
298    }
299
300    #[test]
301    fn rejects_control_packet_bytes() {
302        let mut buf = [0u8; 16];
303        buf[0] = 0x80; // F=1
304        assert_eq!(
305            DataPacket::parse(&buf).unwrap_err(),
306            Error::WrongPacketKind {
307                expected: "data packet (F=0)"
308            }
309        );
310    }
311
312    #[test]
313    fn all_packet_positions_round_trip() {
314        for p in [
315            PacketPosition::First,
316            PacketPosition::Middle,
317            PacketPosition::Last,
318            PacketPosition::Solo,
319        ] {
320            assert_eq!(PacketPosition::from_bits(p.to_bits()), p);
321        }
322    }
323
324    #[test]
325    fn all_key_flags_round_trip() {
326        for k in [
327            EncryptionKeyField::NotEncrypted,
328            EncryptionKeyField::Even,
329            EncryptionKeyField::Odd,
330        ] {
331            assert_eq!(EncryptionKeyField::from_bits(k.to_bits()), k);
332        }
333        assert_eq!(
334            EncryptionKeyField::from_bits(KK_CONTROL_ONLY),
335            EncryptionKeyField::Reserved(KK_CONTROL_ONLY)
336        );
337    }
338
339    #[test]
340    fn overwide_seq_number_errs() {
341        let mut pkt = sample();
342        pkt.seq_number = 0x8000_0000;
343        let mut buf = [0u8; 20];
344        assert!(matches!(
345            pkt.serialize_into(&mut buf),
346            Err(Error::FieldTooWide { .. })
347        ));
348    }
349}