ergot_base/
wire_frames.rs

1use log::warn;
2use postcard::{Serializer, ser_flavors};
3use serde::{Deserialize, Serialize};
4
5use crate::{Address, AnyAllAppendix, FrameKind, HeaderSeq, Key, ProtocolError, nash::NameHash};
6
7#[derive(Serialize, Deserialize, Debug)]
8pub struct CommonHeader {
9    pub src: Address,
10    pub dst: Address,
11    pub seq_no: u16,
12    pub kind: FrameKind,
13    pub ttl: u8,
14}
15
16pub enum PartialDecodeTail<'a> {
17    Specific(&'a [u8]),
18    AnyAll {
19        apdx: AnyAllAppendix,
20        body: &'a [u8],
21    },
22    Err(ProtocolError),
23}
24
25pub struct PartialDecode<'a> {
26    pub hdr: CommonHeader,
27    pub tail: PartialDecodeTail<'a>,
28    /// hdr_raw MUST contain the full serialized header, inclusive of the
29    /// "AnyAllAppendix" if present.
30    pub hdr_raw: &'a [u8],
31}
32
33pub(crate) fn decode_frame_partial(data: &[u8]) -> Option<PartialDecode<'_>> {
34    let (common, remain) = postcard::take_from_bytes::<CommonHeader>(data).ok()?;
35    let is_err = common.kind == FrameKind::PROTOCOL_ERROR;
36    let any_all = [0, 255].contains(&common.dst.port_id);
37
38    match (is_err, any_all) {
39        // Not allowed: any/all AND is err
40        (true, true) => {
41            warn!("Rejecting any/all protocol error message");
42            None
43        }
44        (true, false) => {
45            let hdr_raw_len = data.len() - remain.len();
46            let hdr_raw = &data[..hdr_raw_len];
47            // err
48            let (err, remain) = postcard::take_from_bytes::<ProtocolError>(remain).ok()?;
49            if !remain.is_empty() {
50                warn!("Excess data, rejecting");
51                return None;
52            }
53            Some(PartialDecode {
54                hdr: common,
55                tail: PartialDecodeTail::Err(err),
56                hdr_raw,
57            })
58        }
59        (false, true) => {
60            let (key, remain) = postcard::take_from_bytes::<Key>(remain).ok()?;
61            let (nash, remain) = postcard::take_from_bytes::<u32>(remain).ok()?;
62            let hdr_raw_len = data.len() - remain.len();
63            let hdr_raw = &data[..hdr_raw_len];
64
65            Some(PartialDecode {
66                hdr: common,
67                tail: PartialDecodeTail::AnyAll {
68                    apdx: AnyAllAppendix {
69                        key,
70                        nash: NameHash::from_u32(nash),
71                    },
72                    body: remain,
73                },
74                hdr_raw,
75            })
76        }
77        (false, false) => {
78            let hdr_raw_len = data.len() - remain.len();
79            let hdr_raw = &data[..hdr_raw_len];
80
81            Some(PartialDecode {
82                hdr: common,
83                tail: PartialDecodeTail::Specific(remain),
84                hdr_raw,
85            })
86        }
87    }
88}
89
90// must not be error
91// doesn't check if dest is actually any/all
92pub fn encode_frame_ty<F, T>(
93    flav: F,
94    hdr: &CommonHeader,
95    apdx: Option<&AnyAllAppendix>,
96    body: &T,
97) -> Result<F::Output, ()>
98where
99    F: ser_flavors::Flavor,
100    T: Serialize,
101{
102    let mut serializer = Serializer { output: flav };
103    hdr.serialize(&mut serializer).map_err(drop)?;
104
105    if let Some(app) = apdx {
106        serializer.output.try_extend(&app.key.0).map_err(drop)?;
107        let val: u32 = app.nash.as_ref().map(NameHash::to_u32).unwrap_or(0);
108        val.serialize(&mut serializer).map_err(drop)?;
109    }
110
111    body.serialize(&mut serializer).map_err(drop)?;
112    serializer.output.finalize().map_err(drop)
113}
114
115pub fn encode_frame_err<F>(flav: F, hdr: &CommonHeader, err: ProtocolError) -> Result<F::Output, ()>
116where
117    F: ser_flavors::Flavor,
118{
119    let mut serializer = Serializer { output: flav };
120    hdr.serialize(&mut serializer).map_err(drop)?;
121    err.serialize(&mut serializer).map_err(drop)?;
122    serializer.output.finalize().map_err(drop)
123}
124
125pub fn de_frame(remain: &[u8]) -> Option<BorrowedFrame<'_>> {
126    let res = decode_frame_partial(remain)?;
127
128    let app;
129    let body = match res.tail {
130        PartialDecodeTail::Specific(body) => {
131            app = None;
132            Ok(body)
133        }
134        PartialDecodeTail::AnyAll { apdx, body } => {
135            app = Some(apdx);
136            Ok(body)
137        }
138        PartialDecodeTail::Err(protocol_error) => {
139            app = None;
140            Err(protocol_error)
141        }
142    };
143
144    let CommonHeader {
145        src,
146        dst,
147        seq_no,
148        kind,
149        ttl,
150    } = res.hdr;
151
152    Some(BorrowedFrame {
153        hdr: HeaderSeq {
154            src,
155            dst,
156            seq_no,
157            any_all: app,
158            kind,
159            ttl,
160        },
161        body,
162        hdr_raw: res.hdr_raw,
163    })
164}
165
166pub struct BorrowedFrame<'a> {
167    pub hdr: HeaderSeq,
168    pub hdr_raw: &'a [u8],
169    pub body: Result<&'a [u8], ProtocolError>,
170}