pim_protocol/
data_frame.rs1use bitflags::bitflags;
4use bytes::{Buf, BufMut, BytesMut};
5
6use pim_core::{FrameCodec, NodeId, PimError};
7
8bitflags! {
9 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
11 pub struct DataFlags: u8 {
12 const IS_FRAGMENT = 0b0000_0001;
14 const IS_LAST_FRAGMENT = 0b0000_0010;
16 const REQUIRES_ACK = 0b0000_0100;
18 const IS_ACK = 0b0000_1000;
20 const IS_INTERNET = 0b0001_0000;
22 const IS_E2E = 0b0010_0000;
25 const IS_CONTROL = 0b0100_0000;
27 }
28}
29
30#[derive(Debug, Clone, PartialEq, Eq)]
34pub struct MeshDataFrame {
35 pub src_id: NodeId,
37 pub dst_id: NodeId,
39 pub session_id: u32,
41 pub ttl: u8,
43 pub flags: DataFlags,
45 pub payload: bytes::Bytes,
47}
48
49const HEADER_SIZE: usize = 40;
50
51impl FrameCodec for MeshDataFrame {
52 fn encode(&self, buf: &mut BytesMut) {
53 buf.put_slice(self.src_id.as_bytes());
54 buf.put_slice(self.dst_id.as_bytes());
55 buf.put_u32(self.session_id);
56 buf.put_u8(self.ttl);
57 buf.put_u8(self.flags.bits());
58 buf.put_u16(self.payload.len() as u16);
59 buf.put_slice(&self.payload);
60 }
61
62 fn decode(buf: &mut BytesMut) -> Result<Self, PimError> {
63 if buf.len() < HEADER_SIZE {
64 return Err(PimError::Protocol(format!(
65 "data frame too short: need {HEADER_SIZE} bytes, have {}",
66 buf.len()
67 )));
68 }
69
70 let mut src_bytes = [0u8; 16];
71 src_bytes.copy_from_slice(&buf[0..16]);
72 let src_id = NodeId::from_bytes(src_bytes);
73
74 let mut dst_bytes = [0u8; 16];
75 dst_bytes.copy_from_slice(&buf[16..32]);
76 let dst_id = NodeId::from_bytes(dst_bytes);
77
78 let session_id = (&buf[32..36]).get_u32();
79 let ttl = buf[36];
80 let flags = DataFlags::from_bits_truncate(buf[37]);
81 let payload_len = (&buf[38..40]).get_u16() as usize;
82
83 let total = HEADER_SIZE + payload_len;
84 if buf.len() < total {
85 return Err(PimError::Protocol(format!(
86 "data frame truncated: need {total} bytes, have {}",
87 buf.len()
88 )));
89 }
90
91 buf.advance(HEADER_SIZE);
92 let payload = buf.split_to(payload_len).freeze();
93
94 Ok(MeshDataFrame {
95 src_id,
96 dst_id,
97 session_id,
98 ttl,
99 flags,
100 payload,
101 })
102 }
103}
104
105#[cfg(test)]
106mod tests;