ndn_discovery/
wire.rs

1//! Shared TLV encoding/decoding helpers for discovery packet builders.
2
3use bytes::Bytes;
4use ndn_packet::{Name, tlv_type};
5use ndn_tlv::{TlvReader, TlvWriter};
6
7// ─── Encoding ────────────────────────────────────────────────────────────────
8
9/// Encode a non-negative integer as the minimal-width big-endian representation.
10pub fn write_nni(w: &mut TlvWriter, typ: u64, val: u64) {
11    if val <= 0xFF {
12        w.write_tlv(typ, &[val as u8]);
13    } else if val <= 0xFFFF {
14        w.write_tlv(typ, &(val as u16).to_be_bytes());
15    } else if val <= 0xFFFF_FFFF {
16        w.write_tlv(typ, &(val as u32).to_be_bytes());
17    } else {
18        w.write_tlv(typ, &val.to_be_bytes());
19    }
20}
21
22/// Write a Name TLV (type 0x07) into a `TlvWriter`.
23pub fn write_name_tlv(w: &mut TlvWriter, name: &Name) {
24    w.write_nested(tlv_type::NAME, |w: &mut TlvWriter| {
25        for comp in name.components() {
26            w.write_tlv(comp.typ, &comp.value);
27        }
28    });
29}
30
31/// Encode a standalone Name TLV and return its wire bytes.
32pub fn encode_name_tlv(name: &Name) -> Vec<u8> {
33    let mut w = TlvWriter::new();
34    write_name_tlv(&mut w, name);
35    w.finish().to_vec()
36}
37
38// ─── Decoding ─────────────────────────────────────────────────────────────────
39
40/// Parse a `Name` from a slice that starts with a Name TLV (type 0x07).
41pub fn parse_name_from_tlv(wire: &Bytes) -> Option<Name> {
42    let mut r = TlvReader::new(wire.clone());
43    let (typ, val) = r.read_tlv().ok()?;
44    if typ != tlv_type::NAME {
45        return None;
46    }
47    Name::decode(val).ok()
48}
49
50/// Parsed fields from a raw Interest TLV without digest validation.
51///
52/// Used by discovery protocols for link-local hello Interests where the full
53/// NDN AppParams digest requirement (`ParametersSha256DigestComponent`) is not
54/// enforced — the receiver trusts the link rather than a cryptographic chain.
55pub struct RawInterest {
56    pub name: Name,
57    pub app_params: Option<Bytes>,
58}
59
60/// Parse Interest name and AppParams from raw wire bytes without validating
61/// the `ParametersSha256DigestComponent` that `Interest::decode` requires.
62pub fn parse_raw_interest(raw: &Bytes) -> Option<RawInterest> {
63    let mut r = TlvReader::new(raw.clone());
64    let (typ, value) = r.read_tlv().ok()?;
65    if typ != tlv_type::INTEREST {
66        return None;
67    }
68    let mut inner = TlvReader::new(value);
69    let mut name: Option<Name> = None;
70    let mut app_params: Option<Bytes> = None;
71    while !inner.is_empty() {
72        let (t, v) = inner.read_tlv().ok()?;
73        match t {
74            t if t == tlv_type::NAME => {
75                name = Some(Name::decode(v).ok()?);
76            }
77            t if t == tlv_type::APP_PARAMETERS => {
78                app_params = Some(v);
79            }
80            _ => {}
81        }
82    }
83    Some(RawInterest {
84        name: name?,
85        app_params,
86    })
87}
88
89/// Parse Data name and Content from raw wire bytes.
90pub struct RawData {
91    pub name: Name,
92    pub content: Option<Bytes>,
93}
94
95pub fn parse_raw_data(raw: &Bytes) -> Option<RawData> {
96    let mut r = TlvReader::new(raw.clone());
97    let (typ, value) = r.read_tlv().ok()?;
98    if typ != tlv_type::DATA {
99        return None;
100    }
101    let mut inner = TlvReader::new(value);
102    let mut name: Option<Name> = None;
103    let mut content: Option<Bytes> = None;
104    while !inner.is_empty() {
105        let (t, v) = inner.read_tlv().ok()?;
106        match t {
107            t if t == tlv_type::NAME => {
108                name = Some(Name::decode(v).ok()?);
109            }
110            t if t == tlv_type::CONTENT => {
111                content = Some(v);
112            }
113            _ => {}
114        }
115    }
116    Some(RawData {
117        name: name?,
118        content,
119    })
120}
121
122/// If `raw` is an LP-framed packet (`0x64`), extract and return the inner
123/// fragment bytes.  Otherwise return `raw` unchanged.
124///
125/// Returns `None` if the LP packet is malformed or carries no fragment (e.g.
126/// an ACK-only packet).
127pub fn unwrap_lp(raw: &Bytes) -> Option<Bytes> {
128    if !ndn_packet::lp::is_lp_packet(raw) {
129        return Some(raw.clone());
130    }
131    ndn_packet::lp::LpPacket::decode(raw.clone()).ok()?.fragment
132}