use std::cmp::min;
use std::{convert::TryFrom, fmt};
use bitflags::bitflags;
use bytes::{Buf, BufMut, Bytes};
use super::{MsgNumber, PacketParseError, SeqNumber, SocketId, TimeStamp};
#[derive(Clone, PartialEq, Eq)]
pub struct DataPacket {
pub seq_number: SeqNumber,
pub message_loc: PacketLocation,
pub in_order_delivery: bool,
pub encryption: DataEncryption,
pub retransmitted: bool,
pub message_number: MsgNumber,
pub timestamp: TimeStamp,
pub dest_sockid: SocketId,
pub payload: Bytes,
}
impl DataPacket {
pub const HEADER_SIZE: usize = super::Packet::HEADER_SIZE.0 as usize;
}
bitflags! {
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct PacketLocation: u8 {
const MIDDLE = 0b0000_0000;
const FIRST = 0b1000_0000;
const LAST = 0b0100_0000;
const ONLY = Self::FIRST.bits() | Self::LAST.bits();
}
}
#[derive(Copy, Debug, Clone, PartialEq, Eq)]
pub enum DataEncryption {
None = 0b0000_0000,
Even = 0b0000_1000,
Odd = 0b0001_0000,
}
impl DataPacket {
pub fn parse(buf: &mut impl Buf) -> Result<DataPacket, PacketParseError> {
let seq_number = SeqNumber::new_truncate(buf.get_u32());
let second_word_first_byte = buf.get_u32();
let [swb1, _, _, _] = second_word_first_byte.to_be_bytes();
let message_loc = PacketLocation::from_bits_truncate(swb1);
let encryption = DataEncryption::try_from(swb1)?;
let retransmitted = (swb1 >> 2) & 1 == 1;
let in_order_delivery = (swb1 & 0b0010_0000) != 0;
let message_number = MsgNumber::new_truncate(second_word_first_byte);
let timestamp = TimeStamp::from_micros(buf.get_u32());
let dest_sockid = SocketId(buf.get_u32());
Ok(DataPacket {
seq_number,
message_loc,
in_order_delivery,
encryption,
retransmitted,
message_number,
timestamp,
dest_sockid,
payload: Buf::copy_to_bytes(buf, buf.remaining()),
})
}
pub fn serialize(&self, into: &mut impl BufMut) {
assert!(self.seq_number.as_raw() & (1 << 31) == 0);
into.put_u32(self.seq_number.as_raw());
into.put_u32(
self.message_number.as_raw()
| ((u32::from(
self.message_loc.bits() | (self.in_order_delivery as u8) << 5 | self.encryption as u8 | (self.retransmitted as u8) << 2, )) << 24),
);
into.put_u32(self.timestamp.as_micros());
into.put_u32(self.dest_sockid.0);
into.put(&self.payload[..]);
}
pub fn wire_size(&self) -> usize {
Self::HEADER_SIZE + self.payload.len()
}
}
impl TryFrom<u8> for DataEncryption {
type Error = PacketParseError;
fn try_from(value: u8) -> Result<Self, Self::Error> {
Ok(match value & 0b0001_1000 {
0b0000_0000 => DataEncryption::None,
0b0000_1000 => DataEncryption::Even,
0b0001_0000 => DataEncryption::Odd,
e => return Err(PacketParseError::BadDataEncryption(e)),
})
}
}
impl fmt::Debug for DataPacket {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(
f,
"{{DATA sn={} loc={:?} enc={:?} re={:?} msgno={} ts={:?} dst={:?} payload=[len={}, start={:?}]}}",
self.seq_number.0,
self.message_loc,
self.encryption,
self.retransmitted,
self.message_number.0,
self.timestamp,
self.dest_sockid,
self.payload.len(),
self.payload.slice(..min(8, self.payload.len())),
)
}
}
#[cfg(test)]
mod tests {
use super::*;
use proptest::prelude::*;
use std::io::Cursor;
proptest! {
#[test]
fn data_enc(i: u8) {
match DataEncryption::try_from(i) {
Err(PacketParseError::BadDataEncryption(e)) => {
assert_eq!(i & 0b0001_1000, e);
assert_eq!(e, 0b0001_1000);
}
Err(e) => panic!("{}", e),
Ok(de) => {
assert_eq!(de as u8, i & 0b0001_1000);
}
}
}
#[test]
fn test_datapacket(message_loc: u8, enc in 0u8..3u8, retransmitted: bool, in_order_delivery: bool) {
let message_loc = PacketLocation::from_bits_truncate(message_loc);
let encryption = DataEncryption::try_from(enc << 3).unwrap();
let dp = DataPacket {
seq_number: SeqNumber::new_truncate(123),
message_loc,
in_order_delivery,
encryption,
retransmitted,
message_number: MsgNumber::new_truncate(123),
timestamp: TimeStamp::from_micros(0),
dest_sockid: SocketId(0),
payload: Bytes::new(),
};
let mut v = vec![];
dp.serialize(&mut v);
let dp2 = DataPacket::parse(&mut Cursor::new(&v)).unwrap();
assert_eq!(dp, dp2);
let mut v2 = vec![];
dp2.serialize(&mut v2);
assert_eq!(v, v2);
}
}
}