Skip to main content

cbe_sdk/
packet.rs

1//! The definition of a Cartallum CBE network packet.
2
3use {
4    bincode::{Options, Result},
5    bitflags::bitflags,
6    serde::Serialize,
7    std::{
8        fmt, io,
9        net::{IpAddr, Ipv4Addr, SocketAddr},
10        slice::SliceIndex,
11    },
12};
13
14#[cfg(test)]
15static_assertions::const_assert_eq!(PACKET_DATA_SIZE, 1232);
16/// Maximum over-the-wire size of a Transaction
17///   1280 is IPv6 minimum MTU
18///   40 bytes is the size of the IPv6 header
19///   8 bytes is the size of the fragment header
20pub const PACKET_DATA_SIZE: usize = 1280 - 40 - 8;
21
22bitflags! {
23    #[repr(C)]
24    pub struct PacketFlags: u8 {
25        const DISCARD        = 0b0000_0001;
26        const FORWARDED      = 0b0000_0010;
27        const REPAIR         = 0b0000_0100;
28        const SIMPLE_VOTE_TX = 0b0000_1000;
29        const TRACER_PACKET  = 0b0001_0000;
30    }
31}
32
33#[derive(Clone, Debug, PartialEq, Eq)]
34#[repr(C)]
35pub struct Meta {
36    pub size: usize,
37    pub addr: IpAddr,
38    pub port: u16,
39    pub flags: PacketFlags,
40    pub sender_stake: u64,
41}
42
43#[derive(Clone, Eq)]
44#[repr(C)]
45pub struct Packet {
46    // Bytes past Packet.meta.size are not valid to read from.
47    // Use Packet.data(index) to read from the buffer.
48    buffer: [u8; PACKET_DATA_SIZE],
49    meta: Meta,
50}
51
52impl Packet {
53    pub fn new(buffer: [u8; PACKET_DATA_SIZE], meta: Meta) -> Self {
54        Self { buffer, meta }
55    }
56
57    /// Returns an immutable reference to the underlying buffer up to
58    /// packet.meta.size. The rest of the buffer is not valid to read from.
59    /// packet.data(..) returns packet.buffer.get(..packet.meta.size).
60    /// Returns None if the index is invalid or if the packet is already marked
61    /// as discard.
62    #[inline]
63    pub fn data<I>(&self, index: I) -> Option<&<I as SliceIndex<[u8]>>::Output>
64    where
65        I: SliceIndex<[u8]>,
66    {
67        // If the packet is marked as discard, it is either invalid or
68        // otherwise should be ignored, and so the payload should not be read
69        // from.
70        if self.meta.discard() {
71            None
72        } else {
73            self.buffer.get(..self.meta.size)?.get(index)
74        }
75    }
76
77    /// Returns a mutable reference to the entirety of the underlying buffer to
78    /// write into. The caller is responsible for updating Packet.meta.size
79    /// after writing to the buffer.
80    #[inline]
81    pub fn buffer_mut(&mut self) -> &mut [u8] {
82        debug_assert!(!self.meta.discard());
83        &mut self.buffer[..]
84    }
85
86    #[inline]
87    pub fn meta(&self) -> &Meta {
88        &self.meta
89    }
90
91    #[inline]
92    pub fn meta_mut(&mut self) -> &mut Meta {
93        &mut self.meta
94    }
95
96    pub fn from_data<T: Serialize>(dest: Option<&SocketAddr>, data: T) -> Result<Self> {
97        let mut packet = Packet::default();
98        Self::populate_packet(&mut packet, dest, &data)?;
99        Ok(packet)
100    }
101
102    pub fn populate_packet<T: Serialize>(
103        &mut self,
104        dest: Option<&SocketAddr>,
105        data: &T,
106    ) -> Result<()> {
107        debug_assert!(!self.meta.discard());
108        let mut wr = io::Cursor::new(self.buffer_mut());
109        bincode::serialize_into(&mut wr, data)?;
110        self.meta.size = wr.position() as usize;
111        if let Some(dest) = dest {
112            self.meta.set_socket_addr(dest);
113        }
114        Ok(())
115    }
116
117    pub fn deserialize_slice<T, I>(&self, index: I) -> Result<T>
118    where
119        T: serde::de::DeserializeOwned,
120        I: SliceIndex<[u8], Output = [u8]>,
121    {
122        let bytes = self.data(index).ok_or(bincode::ErrorKind::SizeLimit)?;
123        bincode::options()
124            .with_limit(PACKET_DATA_SIZE as u64)
125            .with_fixint_encoding()
126            .reject_trailing_bytes()
127            .deserialize(bytes)
128    }
129}
130
131impl fmt::Debug for Packet {
132    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
133        write!(
134            f,
135            "Packet {{ size: {:?}, addr: {:?} }}",
136            self.meta.size,
137            self.meta.socket_addr()
138        )
139    }
140}
141
142#[allow(clippy::uninit_assumed_init)]
143impl Default for Packet {
144    fn default() -> Packet {
145        let buffer = std::mem::MaybeUninit::<[u8; PACKET_DATA_SIZE]>::uninit();
146        Packet {
147            buffer: unsafe { buffer.assume_init() },
148            meta: Meta::default(),
149        }
150    }
151}
152
153impl PartialEq for Packet {
154    fn eq(&self, other: &Packet) -> bool {
155        self.meta() == other.meta() && self.data(..) == other.data(..)
156    }
157}
158
159impl Meta {
160    pub fn socket_addr(&self) -> SocketAddr {
161        SocketAddr::new(self.addr, self.port)
162    }
163
164    pub fn set_socket_addr(&mut self, socket_addr: &SocketAddr) {
165        self.addr = socket_addr.ip();
166        self.port = socket_addr.port();
167    }
168
169    #[inline]
170    pub fn discard(&self) -> bool {
171        self.flags.contains(PacketFlags::DISCARD)
172    }
173
174    #[inline]
175    pub fn set_discard(&mut self, discard: bool) {
176        self.flags.set(PacketFlags::DISCARD, discard);
177    }
178
179    #[inline]
180    pub fn set_tracer(&mut self, is_tracer: bool) {
181        self.flags.set(PacketFlags::TRACER_PACKET, is_tracer);
182    }
183
184    #[inline]
185    pub fn set_simple_vote(&mut self, is_simple_vote: bool) {
186        self.flags.set(PacketFlags::SIMPLE_VOTE_TX, is_simple_vote);
187    }
188
189    #[inline]
190    pub fn forwarded(&self) -> bool {
191        self.flags.contains(PacketFlags::FORWARDED)
192    }
193
194    #[inline]
195    pub fn repair(&self) -> bool {
196        self.flags.contains(PacketFlags::REPAIR)
197    }
198
199    #[inline]
200    pub fn is_simple_vote_tx(&self) -> bool {
201        self.flags.contains(PacketFlags::SIMPLE_VOTE_TX)
202    }
203
204    #[inline]
205    pub fn is_tracer_packet(&self) -> bool {
206        self.flags.contains(PacketFlags::TRACER_PACKET)
207    }
208}
209
210impl Default for Meta {
211    fn default() -> Self {
212        Self {
213            size: 0,
214            addr: IpAddr::V4(Ipv4Addr::UNSPECIFIED),
215            port: 0,
216            flags: PacketFlags::empty(),
217            sender_stake: 0,
218        }
219    }
220}
221
222#[cfg(test)]
223mod tests {
224    use super::*;
225
226    #[test]
227    fn test_deserialize_slice() {
228        let p = Packet::from_data(None, u32::MAX).unwrap();
229        assert_eq!(p.deserialize_slice(..).ok(), Some(u32::MAX));
230        assert_eq!(p.deserialize_slice(0..4).ok(), Some(u32::MAX));
231        assert_eq!(
232            p.deserialize_slice::<u16, _>(0..4)
233                .map_err(|e| e.to_string()),
234            Err("Slice had bytes remaining after deserialization".to_string()),
235        );
236        assert_eq!(
237            p.deserialize_slice::<u32, _>(0..0)
238                .map_err(|e| e.to_string()),
239            Err("io error: unexpected end of file".to_string()),
240        );
241        assert_eq!(
242            p.deserialize_slice::<u32, _>(0..1)
243                .map_err(|e| e.to_string()),
244            Err("io error: unexpected end of file".to_string()),
245        );
246        assert_eq!(
247            p.deserialize_slice::<u32, _>(0..5)
248                .map_err(|e| e.to_string()),
249            Err("the size limit has been reached".to_string()),
250        );
251        #[allow(clippy::reversed_empty_ranges)]
252        let reversed_empty_range = 4..0;
253        assert_eq!(
254            p.deserialize_slice::<u32, _>(reversed_empty_range)
255                .map_err(|e| e.to_string()),
256            Err("the size limit has been reached".to_string()),
257        );
258        assert_eq!(
259            p.deserialize_slice::<u32, _>(4..5)
260                .map_err(|e| e.to_string()),
261            Err("the size limit has been reached".to_string()),
262        );
263    }
264}