use { bincode::Result, serde::Serialize, std::{ fmt, io, net::{IpAddr, Ipv4Addr, SocketAddr}, }, }; /// Maximum over-the-wire size of a Transaction /// 1280 is IPv6 minimum MTU /// 40 bytes is the size of the IPv6 header /// 8 bytes is the size of the fragment header pub const PACKET_DATA_SIZE: usize = 1280 - 40 - 8; #[derive(Clone, Debug, PartialEq)] #[repr(C)] pub struct Meta { pub size: usize, pub forwarded: bool, pub repair: bool, pub discard: bool, pub addr: IpAddr, pub port: u16, pub is_tracer_tx: bool, pub is_simple_vote_tx: bool, } #[derive(Clone)] #[repr(C)] pub struct Packet { pub data: [u8; PACKET_DATA_SIZE], pub meta: Meta, } impl Packet { pub fn new(data: [u8; PACKET_DATA_SIZE], meta: Meta) -> Self { Self { data, meta } } pub fn from_data(dest: Option<&SocketAddr>, data: T) -> Result { let mut packet = Packet::default(); Self::populate_packet(&mut packet, dest, &data)?; Ok(packet) } pub fn populate_packet( packet: &mut Packet, dest: Option<&SocketAddr>, data: &T, ) -> Result<()> { let mut wr = io::Cursor::new(&mut packet.data[..]); bincode::serialize_into(&mut wr, data)?; let len = wr.position() as usize; packet.meta.size = len; if let Some(dest) = dest { packet.meta.set_addr(dest); } Ok(()) } } impl fmt::Debug for Packet { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, "Packet {{ size: {:?}, addr: {:?} }}", self.meta.size, self.meta.addr() ) } } #[allow(clippy::uninit_assumed_init)] impl Default for Packet { fn default() -> Packet { Packet { data: unsafe { std::mem::MaybeUninit::uninit().assume_init() }, meta: Meta::default(), } } } impl PartialEq for Packet { fn eq(&self, other: &Packet) -> bool { let self_data: &[u8] = self.data.as_ref(); let other_data: &[u8] = other.data.as_ref(); self.meta == other.meta && self_data[..self.meta.size] == other_data[..self.meta.size] } } impl Meta { pub fn addr(&self) -> SocketAddr { SocketAddr::new(self.addr, self.port) } pub fn set_addr(&mut self, socket_addr: &SocketAddr) { self.addr = socket_addr.ip(); self.port = socket_addr.port(); } } impl Default for Meta { fn default() -> Self { Self { size: 0, forwarded: false, repair: false, discard: false, addr: IpAddr::V4(Ipv4Addr::UNSPECIFIED), port: 0, is_tracer_tx: false, is_simple_vote_tx: false, } } }