ndn_packet/lp/
fragment.rs1use super::decode_be_u64;
2
3pub struct FragmentHeader {
9 pub sequence: u64,
10 pub frag_index: u64,
11 pub frag_count: u64,
12 pub frag_start: usize,
14 pub frag_end: usize,
15}
16
17pub fn extract_fragment(raw: &[u8]) -> Option<FragmentHeader> {
26 if raw.first() != Some(&0x64) {
27 return None;
28 }
29 let (_, type_len) = ndn_tlv::read_varu64(raw).ok()?;
31 let (outer_len, len_len) = ndn_tlv::read_varu64(&raw[type_len..]).ok()?;
32 let header_len = type_len + len_len;
33 let inner = raw.get(header_len..header_len + outer_len as usize)?;
34
35 let mut pos = 0;
36 let mut sequence = None;
37 let mut frag_index = None;
38 let mut frag_count = None;
39 let mut frag_start = 0;
40 let mut frag_end = 0;
41
42 while pos < inner.len() {
43 let (t, tn) = ndn_tlv::read_varu64(&inner[pos..]).ok()?;
44 pos += tn;
45 let (l, ln) = ndn_tlv::read_varu64(&inner[pos..]).ok()?;
46 pos += ln;
47 let l = l as usize;
48 if pos + l > inner.len() {
49 return None;
50 }
51 match t {
52 0x51 => sequence = Some(decode_be_u64(&inner[pos..pos + l])),
53 0x52 => frag_index = Some(decode_be_u64(&inner[pos..pos + l])),
54 0x53 => {
55 let c = decode_be_u64(&inner[pos..pos + l]);
56 if c <= 1 {
57 return None;
58 } frag_count = Some(c);
60 }
61 0x50 => {
62 frag_start = header_len + pos;
64 frag_end = frag_start + l;
65 }
66 _ => {}
67 }
68 pos += l;
69 }
70
71 Some(FragmentHeader {
72 sequence: sequence?,
73 frag_index: frag_index?,
74 frag_count: frag_count?,
75 frag_start,
76 frag_end,
77 })
78}
79
80pub fn extract_acks(raw: &[u8]) -> (Option<u64>, smallvec::SmallVec<[u64; 8]>) {
85 let mut tx_seq = None;
86 let mut acks = smallvec::SmallVec::new();
87
88 if raw.first() != Some(&0x64) {
89 return (tx_seq, acks);
90 }
91 let Some((_, type_len)) = ndn_tlv::read_varu64(raw).ok() else {
92 return (tx_seq, acks);
93 };
94 let Some((outer_len, len_len)) = ndn_tlv::read_varu64(&raw[type_len..]).ok() else {
95 return (tx_seq, acks);
96 };
97 let header_len = type_len + len_len;
98 let Some(inner) = raw.get(header_len..header_len + outer_len as usize) else {
99 return (tx_seq, acks);
100 };
101
102 let mut pos = 0;
103 while pos < inner.len() {
104 let Some((t, tn)) = ndn_tlv::read_varu64(&inner[pos..]).ok() else {
105 break;
106 };
107 pos += tn;
108 let Some((l, ln)) = ndn_tlv::read_varu64(&inner[pos..]).ok() else {
109 break;
110 };
111 pos += ln;
112 let l = l as usize;
113 if pos + l > inner.len() {
114 break;
115 }
116 match t {
117 0x51 => tx_seq = Some(decode_be_u64(&inner[pos..pos + l])),
118 0x0344 => acks.push(decode_be_u64(&inner[pos..pos + l])),
119 _ => {}
120 }
121 pos += l;
122 }
123 (tx_seq, acks)
124}
125
126#[cfg(test)]
127mod tests {
128 use super::*;
129 use crate::encode::encode_interest;
130 use crate::lp::{LpPacket, encode_lp_acks, encode_lp_packet, encode_lp_reliable};
131 use crate::{Name, NameComponent};
132 use bytes::Bytes;
133 use ndn_tlv::TlvWriter;
134
135 fn name(comps: &[&[u8]]) -> Name {
136 Name::from_components(
137 comps
138 .iter()
139 .map(|c| NameComponent::generic(Bytes::copy_from_slice(c))),
140 )
141 }
142
143 #[test]
144 fn extract_fragment_returns_correct_fields() {
145 let n = name(&[b"test"]);
146 let interest_wire = encode_interest(&n, None);
147
148 let mut w = TlvWriter::new();
149 w.write_nested(crate::tlv_type::LP_PACKET, |w| {
150 w.write_tlv(crate::tlv_type::LP_SEQUENCE, &42u64.to_be_bytes());
151 w.write_tlv(crate::tlv_type::LP_FRAG_INDEX, &[1]);
152 w.write_tlv(crate::tlv_type::LP_FRAG_COUNT, &[3]);
153 w.write_tlv(crate::tlv_type::LP_FRAGMENT, &interest_wire);
154 });
155 let raw = w.finish();
156
157 let hdr = extract_fragment(&raw).unwrap();
158 assert_eq!(hdr.sequence, 42);
159 assert_eq!(hdr.frag_index, 1);
160 assert_eq!(hdr.frag_count, 3);
161 assert_eq!(&raw[hdr.frag_start..hdr.frag_end], &interest_wire[..]);
162 }
163
164 #[test]
165 fn extract_fragment_returns_none_for_unfragmented() {
166 let n = name(&[b"test"]);
167 let interest_wire = encode_interest(&n, None);
168 let lp_wire = encode_lp_packet(&interest_wire);
169 assert!(extract_fragment(&lp_wire).is_none());
170 }
171
172 #[test]
173 fn extract_fragment_returns_none_for_single_fragment() {
174 let mut w = TlvWriter::new();
175 w.write_nested(crate::tlv_type::LP_PACKET, |w| {
176 w.write_tlv(crate::tlv_type::LP_SEQUENCE, &[0]);
177 w.write_tlv(crate::tlv_type::LP_FRAG_INDEX, &[0]);
178 w.write_tlv(crate::tlv_type::LP_FRAG_COUNT, &[1]); w.write_tlv(crate::tlv_type::LP_FRAGMENT, &[0x05, 0x00]);
180 });
181 assert!(extract_fragment(&w.finish()).is_none());
182 }
183
184 #[test]
185 fn extract_fragment_matches_full_decode() {
186 use crate::fragment::fragment_packet;
188 let data: Vec<u8> = (0..3000).map(|i| (i % 256) as u8).collect();
189 let frags = fragment_packet(&data, 500, 99);
190 for frag_bytes in &frags {
191 let hdr = extract_fragment(frag_bytes).unwrap();
192 let lp = LpPacket::decode(Bytes::copy_from_slice(frag_bytes)).unwrap();
193 assert_eq!(hdr.sequence, lp.sequence.unwrap());
194 assert_eq!(hdr.frag_index, lp.frag_index.unwrap());
195 assert_eq!(hdr.frag_count, lp.frag_count.unwrap());
196 assert_eq!(
197 &frag_bytes[hdr.frag_start..hdr.frag_end],
198 &lp.fragment.unwrap()[..]
199 );
200 }
201 }
202
203 #[test]
204 fn extract_acks_from_reliable_packet() {
205 let wire = encode_lp_reliable(&[0x05, 0x00], 42, None, &[10, 20, 30]);
206 let (seq, acks) = extract_acks(&wire);
207 assert_eq!(seq, Some(42));
208 assert_eq!(&acks[..], &[10, 20, 30]);
209 }
210
211 #[test]
212 fn extract_acks_from_ack_only() {
213 let wire = encode_lp_acks(&[7, 8]);
214 let (seq, acks) = extract_acks(&wire);
215 assert_eq!(seq, None);
216 assert_eq!(&acks[..], &[7, 8]);
217 }
218
219 #[test]
220 fn extract_acks_from_plain_lp() {
221 let n = name(&[b"test"]);
222 let interest_wire = encode_interest(&n, None);
223 let wire = encode_lp_packet(&interest_wire);
224 let (seq, acks) = extract_acks(&wire);
225 assert_eq!(seq, None);
226 assert!(acks.is_empty());
227 }
228}