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