1#![cfg_attr(feature = "frozen-abi", feature(min_specialization))]
3#![cfg_attr(docsrs, feature(doc_auto_cfg))]
4
5#[cfg(feature = "frozen-abi")]
6use solana_frozen_abi_macro::AbiExample;
7#[cfg(feature = "bincode")]
8use {
9 bincode::{Options, Result},
10 std::io::Write,
11};
12use {
13 bitflags::bitflags,
14 std::{
15 fmt,
16 net::{IpAddr, Ipv4Addr, SocketAddr},
17 slice::SliceIndex,
18 },
19};
20#[cfg(feature = "serde")]
21use {
22 serde_derive::{Deserialize, Serialize},
23 serde_with::{serde_as, Bytes},
24};
25
26#[cfg(test)]
27static_assertions::const_assert_eq!(PACKET_DATA_SIZE, 1232);
28pub const PACKET_DATA_SIZE: usize = 1280 - 40 - 8;
33
34#[cfg(feature = "bincode")]
35pub trait Encode {
36 fn encode<W: Write>(&self, writer: W) -> Result<()>;
37}
38
39#[cfg(feature = "bincode")]
40impl<T: ?Sized + serde::Serialize> Encode for T {
41 fn encode<W: Write>(&self, writer: W) -> Result<()> {
42 bincode::serialize_into::<W, T>(writer, self)
43 }
44}
45
46bitflags! {
47 #[repr(C)]
48 #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
49 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
50 pub struct PacketFlags: u8 {
51 const DISCARD = 0b0000_0001;
52 const FORWARDED = 0b0000_0010;
53 const REPAIR = 0b0000_0100;
54 const SIMPLE_VOTE_TX = 0b0000_1000;
55 const UNUSED_0 = 0b0001_0000;
57 const UNUSED_1 = 0b0010_0000;
59 const PERF_TRACK_PACKET = 0b0100_0000;
61 const FROM_STAKED_NODE = 0b1000_0000;
63 }
64}
65
66#[cfg_attr(feature = "frozen-abi", derive(AbiExample))]
67#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
68#[derive(Clone, Debug, PartialEq, Eq)]
69#[repr(C)]
70pub struct Meta {
71 pub size: usize,
72 pub addr: IpAddr,
73 pub port: u16,
74 pub flags: PacketFlags,
75}
76
77#[cfg(feature = "frozen-abi")]
78impl ::solana_frozen_abi::abi_example::AbiExample for PacketFlags {
79 fn example() -> Self {
80 Self::empty()
81 }
82}
83
84#[cfg(feature = "frozen-abi")]
85impl ::solana_frozen_abi::abi_example::TransparentAsHelper for PacketFlags {}
86
87#[cfg(feature = "frozen-abi")]
88impl ::solana_frozen_abi::abi_example::EvenAsOpaque for PacketFlags {
89 const TYPE_NAME_MATCHER: &'static str = "::_::InternalBitFlags";
90}
91
92#[cfg_attr(feature = "serde", cfg_eval::cfg_eval, serde_as)]
121#[cfg_attr(feature = "frozen-abi", derive(AbiExample))]
122#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
123#[derive(Clone, Eq)]
124#[repr(C)]
125pub struct Packet {
126 #[cfg_attr(feature = "serde", serde_as(as = "Bytes"))]
129 buffer: [u8; PACKET_DATA_SIZE],
130 meta: Meta,
131}
132
133impl Packet {
134 pub fn new(buffer: [u8; PACKET_DATA_SIZE], meta: Meta) -> Self {
135 Self { buffer, meta }
136 }
137
138 #[inline]
144 pub fn data<I>(&self, index: I) -> Option<&<I as SliceIndex<[u8]>>::Output>
145 where
146 I: SliceIndex<[u8]>,
147 {
148 if self.meta.discard() {
152 None
153 } else {
154 self.buffer.get(..self.meta.size)?.get(index)
155 }
156 }
157
158 #[inline]
162 pub fn buffer_mut(&mut self) -> &mut [u8] {
163 debug_assert!(!self.meta.discard());
164 &mut self.buffer[..]
165 }
166
167 #[inline]
168 pub fn meta(&self) -> &Meta {
169 &self.meta
170 }
171
172 #[inline]
173 pub fn meta_mut(&mut self) -> &mut Meta {
174 &mut self.meta
175 }
176
177 #[cfg(feature = "bincode")]
178 pub fn from_data<T: Encode>(dest: Option<&SocketAddr>, data: T) -> Result<Self> {
179 let mut packet = Self::default();
180 Self::populate_packet(&mut packet, dest, &data)?;
181 Ok(packet)
182 }
183
184 #[cfg(feature = "bincode")]
185 pub fn populate_packet<T: Encode>(
186 &mut self,
187 dest: Option<&SocketAddr>,
188 data: &T,
189 ) -> Result<()> {
190 debug_assert!(!self.meta.discard());
191 let mut wr = std::io::Cursor::new(self.buffer_mut());
192 <T as Encode>::encode(data, &mut wr)?;
193 self.meta.size = wr.position() as usize;
194 if let Some(dest) = dest {
195 self.meta.set_socket_addr(dest);
196 }
197 Ok(())
198 }
199
200 #[cfg(feature = "bincode")]
201 pub fn deserialize_slice<T, I>(&self, index: I) -> Result<T>
202 where
203 T: serde::de::DeserializeOwned,
204 I: SliceIndex<[u8], Output = [u8]>,
205 {
206 let bytes = self.data(index).ok_or(bincode::ErrorKind::SizeLimit)?;
207 bincode::options()
208 .with_limit(PACKET_DATA_SIZE as u64)
209 .with_fixint_encoding()
210 .reject_trailing_bytes()
211 .deserialize(bytes)
212 }
213}
214
215impl fmt::Debug for Packet {
216 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
217 write!(
218 f,
219 "Packet {{ size: {:?}, addr: {:?} }}",
220 self.meta.size,
221 self.meta.socket_addr()
222 )
223 }
224}
225
226#[allow(clippy::uninit_assumed_init)]
227impl Default for Packet {
228 fn default() -> Self {
229 let buffer = std::mem::MaybeUninit::<[u8; PACKET_DATA_SIZE]>::uninit();
230 Self {
231 buffer: unsafe { buffer.assume_init() },
232 meta: Meta::default(),
233 }
234 }
235}
236
237impl PartialEq for Packet {
238 fn eq(&self, other: &Self) -> bool {
239 self.meta() == other.meta() && self.data(..) == other.data(..)
240 }
241}
242
243impl Meta {
244 pub fn socket_addr(&self) -> SocketAddr {
245 SocketAddr::new(self.addr, self.port)
246 }
247
248 pub fn set_socket_addr(&mut self, socket_addr: &SocketAddr) {
249 self.addr = socket_addr.ip();
250 self.port = socket_addr.port();
251 }
252
253 pub fn set_from_staked_node(&mut self, from_staked_node: bool) {
254 self.flags
255 .set(PacketFlags::FROM_STAKED_NODE, from_staked_node);
256 }
257
258 #[inline]
259 pub fn discard(&self) -> bool {
260 self.flags.contains(PacketFlags::DISCARD)
261 }
262
263 #[inline]
264 pub fn set_discard(&mut self, discard: bool) {
265 self.flags.set(PacketFlags::DISCARD, discard);
266 }
267
268 #[inline]
269 pub fn set_track_performance(&mut self, is_performance_track: bool) {
270 self.flags
271 .set(PacketFlags::PERF_TRACK_PACKET, is_performance_track);
272 }
273
274 #[inline]
275 pub fn set_simple_vote(&mut self, is_simple_vote: bool) {
276 self.flags.set(PacketFlags::SIMPLE_VOTE_TX, is_simple_vote);
277 }
278
279 #[inline]
280 pub fn forwarded(&self) -> bool {
281 self.flags.contains(PacketFlags::FORWARDED)
282 }
283
284 #[inline]
285 pub fn repair(&self) -> bool {
286 self.flags.contains(PacketFlags::REPAIR)
287 }
288
289 #[inline]
290 pub fn is_simple_vote_tx(&self) -> bool {
291 self.flags.contains(PacketFlags::SIMPLE_VOTE_TX)
292 }
293
294 #[inline]
295 pub fn is_perf_track_packet(&self) -> bool {
296 self.flags.contains(PacketFlags::PERF_TRACK_PACKET)
297 }
298
299 #[inline]
300 pub fn is_from_staked_node(&self) -> bool {
301 self.flags.contains(PacketFlags::FROM_STAKED_NODE)
302 }
303}
304
305impl Default for Meta {
306 fn default() -> Self {
307 Self {
308 size: 0,
309 addr: IpAddr::V4(Ipv4Addr::UNSPECIFIED),
310 port: 0,
311 flags: PacketFlags::empty(),
312 }
313 }
314}
315
316#[cfg(test)]
317mod tests {
318 use super::*;
319
320 #[test]
321 fn test_deserialize_slice() {
322 let p = Packet::from_data(None, u32::MAX).unwrap();
323 assert_eq!(p.deserialize_slice(..).ok(), Some(u32::MAX));
324 assert_eq!(p.deserialize_slice(0..4).ok(), Some(u32::MAX));
325 assert_eq!(
326 p.deserialize_slice::<u16, _>(0..4)
327 .map_err(|e| e.to_string()),
328 Err("Slice had bytes remaining after deserialization".to_string()),
329 );
330 assert_eq!(
331 p.deserialize_slice::<u32, _>(0..0)
332 .map_err(|e| e.to_string()),
333 Err("io error: unexpected end of file".to_string()),
334 );
335 assert_eq!(
336 p.deserialize_slice::<u32, _>(0..1)
337 .map_err(|e| e.to_string()),
338 Err("io error: unexpected end of file".to_string()),
339 );
340 assert_eq!(
341 p.deserialize_slice::<u32, _>(0..5)
342 .map_err(|e| e.to_string()),
343 Err("the size limit has been reached".to_string()),
344 );
345 #[allow(clippy::reversed_empty_ranges)]
346 let reversed_empty_range = 4..0;
347 assert_eq!(
348 p.deserialize_slice::<u32, _>(reversed_empty_range)
349 .map_err(|e| e.to_string()),
350 Err("the size limit has been reached".to_string()),
351 );
352 assert_eq!(
353 p.deserialize_slice::<u32, _>(4..5)
354 .map_err(|e| e.to_string()),
355 Err("the size limit has been reached".to_string()),
356 );
357 }
358}