solana_sdk/
packet.rs

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