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