use crate::error::{EnigmaPacketError, Result};
pub const MAGIC: [u8; 4] = *b"ENP1";
pub const VERSION: u8 = 1;
pub const HEADER_LEN: usize = 12;
pub const MIN_PACKET_SIZE: usize = HEADER_LEN;
pub const MAX_PACKET_SIZE: usize = 16 * 1024 * 1024;
pub const MAX_BODY_SIZE: usize = MAX_PACKET_SIZE - HEADER_LEN;
#[derive(Debug, Clone, Copy)]
pub struct PacketView<'a> {
pub version: u8,
pub flags: u8,
pub reserved: u16,
pub body_len: u32,
pub body: &'a [u8],
}
pub fn peek_packet(packet: &[u8]) -> Result<PacketView<'_>> {
parse_frame(packet)
}
pub(crate) fn encode_frame(body: &[u8], flags: u8) -> Result<Vec<u8>> {
if body.len() > MAX_BODY_SIZE || body.len() > u32::MAX as usize {
return Err(EnigmaPacketError::SizeLimitExceeded);
}
let total = HEADER_LEN
.checked_add(body.len())
.ok_or(EnigmaPacketError::SizeLimitExceeded)?;
if total > MAX_PACKET_SIZE {
return Err(EnigmaPacketError::SizeLimitExceeded);
}
let mut buf = Vec::with_capacity(total);
buf.extend_from_slice(&MAGIC);
buf.push(VERSION);
buf.push(flags);
buf.extend_from_slice(&0u16.to_be_bytes());
buf.extend_from_slice(&(body.len() as u32).to_be_bytes());
buf.extend_from_slice(body);
Ok(buf)
}
pub(crate) fn parse_frame(packet: &[u8]) -> Result<PacketView<'_>> {
if packet.len() < HEADER_LEN {
return Err(EnigmaPacketError::InvalidPacket("packet too small".into()));
}
if packet.len() > MAX_PACKET_SIZE {
return Err(EnigmaPacketError::SizeLimitExceeded);
}
if packet[..4] != MAGIC {
return Err(EnigmaPacketError::InvalidPacket("invalid magic".into()));
}
let version = packet[4];
if version != VERSION {
return Err(EnigmaPacketError::UnsupportedVersion(version));
}
let flags = packet[5];
let reserved = u16::from_be_bytes([packet[6], packet[7]]);
let body_len = u32::from_be_bytes([packet[8], packet[9], packet[10], packet[11]]) as usize;
let total = HEADER_LEN
.checked_add(body_len)
.ok_or(EnigmaPacketError::SizeLimitExceeded)?;
if total > MAX_PACKET_SIZE {
return Err(EnigmaPacketError::SizeLimitExceeded);
}
if packet.len() != total {
return Err(EnigmaPacketError::InvalidPacket(
"body length mismatch".into(),
));
}
let body = &packet[HEADER_LEN..];
Ok(PacketView {
version,
flags,
reserved,
body_len: body_len as u32,
body,
})
}