enigma_packet/
framing.rs

1use crate::error::{EnigmaPacketError, Result};
2
3pub const MAGIC: [u8; 4] = *b"ENP1";
4pub const VERSION: u8 = 1;
5pub const HEADER_LEN: usize = 12;
6pub const MIN_PACKET_SIZE: usize = HEADER_LEN;
7pub const MAX_PACKET_SIZE: usize = 16 * 1024 * 1024;
8pub const MAX_BODY_SIZE: usize = MAX_PACKET_SIZE - HEADER_LEN;
9
10#[derive(Debug, Clone, Copy)]
11pub struct PacketView<'a> {
12    pub version: u8,
13    pub flags: u8,
14    pub reserved: u16,
15    pub body_len: u32,
16    pub body: &'a [u8],
17}
18
19pub fn peek_packet(packet: &[u8]) -> Result<PacketView<'_>> {
20    parse_frame(packet)
21}
22
23pub(crate) fn encode_frame(body: &[u8], flags: u8) -> Result<Vec<u8>> {
24    if body.len() > MAX_BODY_SIZE || body.len() > u32::MAX as usize {
25        return Err(EnigmaPacketError::SizeLimitExceeded);
26    }
27    let total = HEADER_LEN
28        .checked_add(body.len())
29        .ok_or(EnigmaPacketError::SizeLimitExceeded)?;
30    if total > MAX_PACKET_SIZE {
31        return Err(EnigmaPacketError::SizeLimitExceeded);
32    }
33    let mut buf = Vec::with_capacity(total);
34    buf.extend_from_slice(&MAGIC);
35    buf.push(VERSION);
36    buf.push(flags);
37    buf.extend_from_slice(&0u16.to_be_bytes());
38    buf.extend_from_slice(&(body.len() as u32).to_be_bytes());
39    buf.extend_from_slice(body);
40    Ok(buf)
41}
42
43pub(crate) fn parse_frame(packet: &[u8]) -> Result<PacketView<'_>> {
44    if packet.len() < HEADER_LEN {
45        return Err(EnigmaPacketError::InvalidPacket("packet too small".into()));
46    }
47    if packet.len() > MAX_PACKET_SIZE {
48        return Err(EnigmaPacketError::SizeLimitExceeded);
49    }
50    if packet[..4] != MAGIC {
51        return Err(EnigmaPacketError::InvalidPacket("invalid magic".into()));
52    }
53    let version = packet[4];
54    if version != VERSION {
55        return Err(EnigmaPacketError::UnsupportedVersion(version));
56    }
57    let flags = packet[5];
58    let reserved = u16::from_be_bytes([packet[6], packet[7]]);
59    let body_len = u32::from_be_bytes([packet[8], packet[9], packet[10], packet[11]]) as usize;
60    let total = HEADER_LEN
61        .checked_add(body_len)
62        .ok_or(EnigmaPacketError::SizeLimitExceeded)?;
63    if total > MAX_PACKET_SIZE {
64        return Err(EnigmaPacketError::SizeLimitExceeded);
65    }
66    if packet.len() != total {
67        return Err(EnigmaPacketError::InvalidPacket(
68            "body length mismatch".into(),
69        ));
70    }
71    let body = &packet[HEADER_LEN..];
72    Ok(PacketView {
73        version,
74        flags,
75        reserved,
76        body_len: body_len as u32,
77        body,
78    })
79}