1mod data;
7mod interest;
8
9pub use data::DataBuilder;
10pub use interest::{InterestBuilder, encode_interest, ensure_nonce};
11
12use std::sync::atomic::{AtomicU32, Ordering};
13
14use bytes::Bytes;
15use ndn_tlv::TlvWriter;
16
17use crate::{Name, tlv_type};
18
19#[cfg(feature = "std")]
30pub fn encode_data_unsigned(name: &Name, content: &[u8]) -> Bytes {
31 DataBuilder::new(name.clone(), content)
32 .freshness(std::time::Duration::ZERO)
33 .sign_digest_sha256()
34}
35
36pub fn encode_nack(reason: crate::NackReason, interest_wire: &[u8]) -> Bytes {
44 crate::lp::encode_lp_nack(reason, interest_wire)
45}
46
47pub(crate) fn nni(val: u64) -> ([u8; 8], usize) {
56 let be = val.to_be_bytes();
57 if val <= 0xFF {
58 ([be[7], 0, 0, 0, 0, 0, 0, 0], 1)
59 } else if val <= 0xFFFF {
60 ([be[6], be[7], 0, 0, 0, 0, 0, 0], 2)
61 } else if val <= 0xFFFF_FFFF {
62 ([be[4], be[5], be[6], be[7], 0, 0, 0, 0], 4)
63 } else {
64 (be, 8)
65 }
66}
67
68pub(super) fn write_nni(w: &mut TlvWriter, typ: u64, val: u64) {
70 let (buf, len) = nni(val);
71 w.write_tlv(typ, &buf[..len]);
72}
73
74pub(super) fn write_name(w: &mut TlvWriter, name: &Name) {
77 w.write_nested(tlv_type::NAME, |w| {
78 for comp in name.components() {
79 w.write_tlv(comp.typ, &comp.value);
80 }
81 });
82}
83
84pub(super) fn next_nonce() -> u32 {
90 static COUNTER: AtomicU32 = AtomicU32::new(0);
91 let seq = COUNTER.fetch_add(1, Ordering::Relaxed);
92 (std::process::id() << 16).wrapping_add(seq)
93}
94
95pub(super) fn rand_nonce_bytes() -> [u8; 8] {
99 let mut buf = [0u8; 8];
100 ring::rand::SecureRandom::fill(&ring::rand::SystemRandom::new(), &mut buf)
101 .expect("system RNG failed");
102 buf
103}
104
105#[cfg(test)]
108mod tests {
109 use super::*;
110 use crate::{Data, NameComponent};
111 use bytes::Bytes;
112 use std::time::Duration;
113
114 pub(super) fn name(components: &[&[u8]]) -> Name {
115 Name::from_components(
116 components
117 .iter()
118 .map(|c| NameComponent::generic(Bytes::copy_from_slice(c))),
119 )
120 }
121
122 #[test]
123 fn data_roundtrip_name_and_content() {
124 let n = name(&[b"localhost", b"ndn-ctl", b"get-stats"]);
125 let content = br#"{"status":"ok","pit_size":42}"#;
126 let bytes = encode_data_unsigned(&n, content);
127 let data = Data::decode(bytes).unwrap();
128 assert_eq!(*data.name, n);
129 assert_eq!(data.content().map(|b| b.as_ref()), Some(content.as_ref()));
130 }
131
132 #[test]
133 fn data_freshness_is_zero() {
134 let n = name(&[b"test"]);
135 let bytes = encode_data_unsigned(&n, b"hello");
136 let data = Data::decode(bytes).unwrap();
137 let mi = data.meta_info().expect("meta_info present");
138 assert_eq!(mi.freshness_period, Some(Duration::from_millis(0)));
139 }
140
141 #[test]
142 fn nack_roundtrip() {
143 use crate::{Nack, NackReason};
144 let n = name(&[b"test", b"nack"]);
145 let interest_wire = encode_interest(&n, None);
146 let nack_wire = encode_nack(NackReason::NoRoute, &interest_wire);
147 let nack = Nack::decode(nack_wire).unwrap();
148 assert_eq!(nack.reason, NackReason::NoRoute);
149 assert_eq!(*nack.interest.name, n);
150 }
151
152 #[test]
153 fn nack_congestion_roundtrip() {
154 use crate::{Nack, NackReason};
155 let n = name(&[b"hello"]);
156 let interest_wire = encode_interest(&n, None);
157 let nack_wire = encode_nack(NackReason::Congestion, &interest_wire);
158 let nack = Nack::decode(nack_wire).unwrap();
159 assert_eq!(nack.reason, NackReason::Congestion);
160 }
161
162 #[test]
165 fn nni_minimal_encoding() {
166 assert_eq!(nni(0), ([0, 0, 0, 0, 0, 0, 0, 0], 1));
168 assert_eq!(nni(255), ([0xFF, 0, 0, 0, 0, 0, 0, 0], 1));
169
170 assert_eq!(nni(256), ([0x01, 0x00, 0, 0, 0, 0, 0, 0], 2));
172 assert_eq!(nni(4000), ([0x0F, 0xA0, 0, 0, 0, 0, 0, 0], 2));
173 assert_eq!(nni(65535), ([0xFF, 0xFF, 0, 0, 0, 0, 0, 0], 2));
174
175 assert_eq!(nni(65536), ([0x00, 0x01, 0x00, 0x00, 0, 0, 0, 0], 4));
177 assert_eq!(nni(1_000_000), ([0x00, 0x0F, 0x42, 0x40, 0, 0, 0, 0], 4));
178
179 let big: u64 = 0x1_0000_0000;
181 let (buf, len) = nni(big);
182 assert_eq!(len, 8);
183 assert_eq!(buf, big.to_be_bytes());
184 }
185
186 pub(super) fn assert_bytes_eq(actual: &[u8], expected: &[u8], msg: &str) {
190 if actual != expected {
191 panic!(
192 "{msg}\n actual: {}\n expected: {}",
193 hex(actual),
194 hex(expected),
195 );
196 }
197 }
198
199 pub(super) fn hex(bytes: &[u8]) -> String {
200 bytes
201 .iter()
202 .map(|b| format!("{b:02X}"))
203 .collect::<Vec<_>>()
204 .join(" ")
205 }
206
207 #[test]
208 fn wire_data_unsigned_structure() {
209 let wire = encode_data_unsigned(&name(&[b"A"]), b"X");
211
212 assert_eq!(wire[0], 0x06);
214
215 assert_bytes_eq(&wire[2..7], &[0x07, 0x03, 0x08, 0x01, 0x41], "Name /A");
217
218 assert_bytes_eq(&wire[7..12], &[0x14, 0x03, 0x19, 0x01, 0x00], "MetaInfo");
220
221 assert_bytes_eq(&wire[12..15], &[0x15, 0x01, 0x58], "Content");
223
224 assert_bytes_eq(&wire[15..20], &[0x16, 0x03, 0x1B, 0x01, 0x00], "SigInfo");
226
227 assert_eq!(wire[20], 0x17);
229 assert_eq!(wire[21], 0x20, "SigValue length should be 32");
230 assert!(
231 !wire[22..54].iter().all(|&b| b == 0),
232 "SigValue should be a real SHA-256, not zeros"
233 );
234
235 assert_eq!(wire.len(), 54, "total Data length");
236 }
237
238 #[test]
239 fn wire_nack_reason_nni() {
240 use crate::{Nack, NackReason};
241 let n = name(&[b"A"]);
242 let interest_wire = encode_interest(&n, None);
243 let nack_wire = encode_nack(NackReason::NoRoute, &interest_wire);
244
245 let nack = Nack::decode(nack_wire.clone()).unwrap();
246 assert_eq!(nack.reason, NackReason::NoRoute);
247
248 let needle = [0xFD, 0x03, 0x21, 0x01, 0x96];
251 assert!(
252 nack_wire.windows(5).any(|w| w == needle),
253 "NackReason TLV should be FD 03 21 01 96, got: {}",
254 hex(&nack_wire),
255 );
256 }
257
258 #[test]
259 fn wire_ndnd_data_decode() {
260 let ndnd_wire: &[u8] = &[
261 0x06, 0x1D, 0x07, 0x06, 0x08, 0x04, 0x74, 0x65, 0x73, 0x74, 0x14, 0x04, 0x19, 0x02, 0x27, 0x10, 0x15, 0x02, 0x68, 0x69, 0x16, 0x03, 0x1B, 0x01, 0x00, 0x17, 0x04, 0xAA, 0xBB, 0xCC, 0xDD, ];
271 let data = Data::decode(Bytes::from_static(ndnd_wire)).unwrap();
272 assert_eq!(data.name.to_string(), "/test");
273 assert_eq!(data.content().map(|b| b.as_ref()), Some(b"hi".as_ref()));
274 let mi = data.meta_info().expect("meta_info");
275 assert_eq!(mi.freshness_period, Some(Duration::from_secs(10)));
276 }
277
278 #[test]
279 fn wire_ndnd_data_no_metainfo_decode() {
280 let ndnd_wire: &[u8] = &[
281 0x06, 0x15, 0x07, 0x06, 0x08, 0x04, 0x74, 0x65, 0x73, 0x74, 0x15, 0x02, 0x68, 0x69, 0x16, 0x03, 0x1B, 0x01, 0x00, 0x17, 0x04, 0x00, 0x00, 0x00, 0x00, ];
289 let data = Data::decode(Bytes::from_static(ndnd_wire)).unwrap();
290 assert_eq!(data.name.to_string(), "/test");
291 assert!(data.meta_info().is_none());
292 }
293}