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);
14pub 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 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 #[inline]
61 pub fn data<I>(&self, index: I) -> Option<&<I as SliceIndex<[u8]>>::Output>
62 where
63 I: SliceIndex<[u8]>,
64 {
65 if self.meta.discard() {
69 None
70 } else {
71 self.buffer.get(..self.meta.size)?.get(index)
72 }
73 }
74
75 #[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}