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