srt_runtime/packet/
nak.rs1use alloc::vec::Vec;
16
17use super::{Error, F_BIT, Result, SEQ_NUMBER_MASK, be32};
18
19#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
23#[cfg_attr(feature = "serde", derive(serde::Serialize))]
24#[non_exhaustive]
25pub enum LossListEntry {
26 Single(u32),
28 Range(u32, u32),
31}
32
33#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
35#[cfg_attr(feature = "serde", derive(serde::Serialize))]
36pub struct NakPacket<'a> {
37 pub timestamp: u32,
39 pub dest_socket_id: u32,
41 pub raw_loss_list: &'a [u8],
43}
44
45impl<'a> NakPacket<'a> {
46 pub(crate) fn parse_cif(timestamp: u32, dest_socket_id: u32, cif: &'a [u8]) -> Self {
47 NakPacket {
48 timestamp,
49 dest_socket_id,
50 raw_loss_list: cif,
51 }
52 }
53
54 pub(crate) fn cif_len(&self) -> usize {
55 self.raw_loss_list.len()
56 }
57
58 pub(crate) fn write_cif(&self, buf: &mut [u8]) {
59 buf.copy_from_slice(self.raw_loss_list);
60 }
61
62 pub fn entries(&self) -> LossListIter<'a> {
65 LossListIter {
66 rest: self.raw_loss_list,
67 }
68 }
69}
70
71#[derive(Debug, Clone)]
73pub struct LossListIter<'a> {
74 rest: &'a [u8],
75}
76
77impl Iterator for LossListIter<'_> {
78 type Item = Result<LossListEntry>;
79
80 fn next(&mut self) -> Option<Self::Item> {
81 if self.rest.is_empty() {
82 return None;
83 }
84 if self.rest.len() < 4 {
85 self.rest = &[];
86 return Some(Err(Error::InvalidLossList {
87 reason: "trailing bytes are not a whole 4-byte entry",
88 }));
89 }
90 let w0 = be32(self.rest, 0);
91 self.rest = &self.rest[4..];
92 if w0 & F_BIT != 0 {
93 let first = w0 & SEQ_NUMBER_MASK;
94 if self.rest.len() < 4 {
95 self.rest = &[];
96 return Some(Err(Error::InvalidLossList {
97 reason: "range entry missing its end sequence number",
98 }));
99 }
100 let w1 = be32(self.rest, 0);
101 self.rest = &self.rest[4..];
102 if w1 & F_BIT != 0 {
103 return Some(Err(Error::InvalidLossList {
104 reason: "range end entry had its top bit set",
105 }));
106 }
107 Some(Ok(LossListEntry::Range(first, w1 & SEQ_NUMBER_MASK)))
108 } else {
109 Some(Ok(LossListEntry::Single(w0 & SEQ_NUMBER_MASK)))
110 }
111 }
112}
113
114pub fn build_loss_list(entries: &[LossListEntry]) -> Result<Vec<u8>> {
120 let mut out = Vec::with_capacity(entries.len() * 4);
121 let check = |seq: u32| -> Result<()> {
122 if seq > SEQ_NUMBER_MASK {
123 return Err(Error::FieldTooWide {
124 what: "loss list sequence number",
125 value: u64::from(seq),
126 bits: 31,
127 });
128 }
129 Ok(())
130 };
131 for entry in entries {
132 match *entry {
133 LossListEntry::Single(seq) => {
134 check(seq)?;
135 out.extend_from_slice(&seq.to_be_bytes());
136 }
137 LossListEntry::Range(first, last) => {
138 check(first)?;
139 check(last)?;
140 out.extend_from_slice(&(first | F_BIT).to_be_bytes());
141 out.extend_from_slice(&last.to_be_bytes());
142 }
143 }
144 }
145 Ok(out)
146}
147
148#[cfg(test)]
149mod tests {
150 use super::super::control::ControlPacket;
151 use super::*;
152
153 #[test]
154 fn single_and_range_entries_round_trip_hand_computed_bytes() {
155 let entries = [
156 LossListEntry::Single(5),
157 LossListEntry::Range(10, 20),
158 LossListEntry::Single(30),
159 ];
160 let raw = build_loss_list(&entries).unwrap();
161 assert_eq!(raw.len(), 16);
162 assert_eq!(&raw[0..4], &5u32.to_be_bytes());
163 assert_eq!(&raw[4..8], &(10u32 | 0x8000_0000).to_be_bytes());
164 assert_eq!(&raw[8..12], &20u32.to_be_bytes());
165 assert_eq!(&raw[12..16], &30u32.to_be_bytes());
166
167 let pkt = ControlPacket::Nak(NakPacket {
168 timestamp: 1,
169 dest_socket_id: 2,
170 raw_loss_list: &raw,
171 });
172 let mut buf = alloc::vec![0u8; pkt.serialized_len()];
173 pkt.serialize_into(&mut buf).unwrap();
174 let parsed = ControlPacket::parse(&buf).unwrap();
175 assert_eq!(parsed, pkt);
176
177 if let ControlPacket::Nak(n) = parsed {
178 let decoded: Vec<LossListEntry> = n.entries().map(|e| e.unwrap()).collect();
179 assert_eq!(&decoded, &entries);
180 } else {
181 panic!("expected NAK");
182 }
183 }
184
185 #[test]
186 fn malformed_range_end_top_bit_errs_without_panic() {
187 let mut raw = Vec::new();
190 raw.extend_from_slice(&(1u32 | 0x8000_0000).to_be_bytes());
191 raw.extend_from_slice(&(2u32 | 0x8000_0000).to_be_bytes());
192 let n = NakPacket {
193 timestamp: 0,
194 dest_socket_id: 0,
195 raw_loss_list: &raw,
196 };
197 let mut it = n.entries();
198 assert!(matches!(
199 it.next(),
200 Some(Err(Error::InvalidLossList { .. }))
201 ));
202 assert!(it.next().is_none());
203 }
204
205 #[test]
206 fn overwide_sequence_number_errs() {
207 assert!(matches!(
208 build_loss_list(&[LossListEntry::Single(0x8000_0000)]),
209 Err(Error::FieldTooWide { .. })
210 ));
211 }
212}