add payload_len field to wire protocol header
Ethernet pads frames to 60 bytes minimum; without an explicit length field the receiver cannot distinguish real payload from zero padding (e.g. a 6-byte DISCOVER becomes 46 bytes after padding, failing the 'payload must be empty' check). Header is now 8 bytes: [ver:1][type:1][session_id:4][payload_len:2] (both multi-byte fields big-endian). The receiver slices exactly payload_len bytes and ignores trailing padding. Updated PROTOCOL.md, Rust frame.rs, and C# Frame.cs.
This commit is contained in:
+34
-28
@@ -3,6 +3,7 @@
|
||||
pub const ETHERTYPE: u16 = 0x6969;
|
||||
pub const ETH_HEADER_LEN: usize = 14;
|
||||
pub const VERSION: u8 = 1;
|
||||
pub const HEADER_LEN: usize = 8;
|
||||
pub const MAX_PAYLOAD: usize = 1480;
|
||||
|
||||
pub const TYPE_DISCOVER: u8 = 0x01;
|
||||
@@ -76,50 +77,50 @@ fn encode_entry(buf: &mut Vec<u8>, e: &UpstreamEntry) {
|
||||
buf.extend_from_slice(&label_bytes[..label_len as usize]);
|
||||
}
|
||||
|
||||
/// Build the 8-byte header + payload. The payload_len field records the
|
||||
/// exact payload length so the receiver can ignore Ethernet padding.
|
||||
fn build(type_byte: u8, session_id: u32, payload: Vec<u8>) -> Vec<u8> {
|
||||
let len = payload.len() as u16;
|
||||
let mut buf = Vec::with_capacity(HEADER_LEN + payload.len());
|
||||
buf.push(VERSION);
|
||||
buf.push(type_byte);
|
||||
buf.extend_from_slice(&session_id.to_be_bytes());
|
||||
buf.extend_from_slice(&len.to_be_bytes());
|
||||
buf.extend_from_slice(&payload);
|
||||
buf
|
||||
}
|
||||
|
||||
impl Frame {
|
||||
pub fn encode(&self) -> Vec<u8> {
|
||||
let mut buf = Vec::new();
|
||||
match self {
|
||||
Frame::Discover => {
|
||||
buf.extend_from_slice(&[VERSION, TYPE_DISCOVER, 0, 0, 0, 0]);
|
||||
}
|
||||
Frame::Discover => build(TYPE_DISCOVER, 0, Vec::new()),
|
||||
Frame::Manifest(entries) => {
|
||||
buf.extend_from_slice(&[VERSION, TYPE_MANIFEST, 0, 0, 0, 0]);
|
||||
let mut payload = Vec::new();
|
||||
for e in entries {
|
||||
encode_entry(&mut buf, e);
|
||||
encode_entry(&mut payload, e);
|
||||
}
|
||||
build(TYPE_MANIFEST, 0, payload)
|
||||
}
|
||||
Frame::Open { upstream_id } => {
|
||||
buf.extend_from_slice(&[VERSION, TYPE_OPEN, 0, 0, 0, 0, *upstream_id]);
|
||||
}
|
||||
Frame::Open { upstream_id } => build(TYPE_OPEN, 0, vec![*upstream_id]),
|
||||
Frame::OpenAck { session_id, upstream_id } => {
|
||||
buf.extend_from_slice(&[VERSION, TYPE_OPEN_ACK]);
|
||||
buf.extend_from_slice(&session_id.to_be_bytes());
|
||||
buf.push(*upstream_id);
|
||||
build(TYPE_OPEN_ACK, *session_id, vec![*upstream_id])
|
||||
}
|
||||
Frame::OpenNak { upstream_id, reason } => {
|
||||
buf.extend_from_slice(&[VERSION, TYPE_OPEN_NAK, 0, 0, 0, 0]);
|
||||
buf.push(*upstream_id);
|
||||
buf.push(*reason);
|
||||
}
|
||||
Frame::Data { session_id, payload } => {
|
||||
buf.extend_from_slice(&[VERSION, TYPE_DATA]);
|
||||
buf.extend_from_slice(&session_id.to_be_bytes());
|
||||
buf.extend_from_slice(payload);
|
||||
build(TYPE_OPEN_NAK, 0, vec![*upstream_id, *reason])
|
||||
}
|
||||
Frame::Data { session_id, payload } => build(TYPE_DATA, *session_id, payload.clone()),
|
||||
Frame::Close { session_id, reason } => {
|
||||
buf.extend_from_slice(&[VERSION, TYPE_CLOSE]);
|
||||
buf.extend_from_slice(&session_id.to_be_bytes());
|
||||
if let Some(r) = reason {
|
||||
buf.push(*r);
|
||||
}
|
||||
let p = match reason {
|
||||
Some(r) => vec![*r],
|
||||
None => Vec::new(),
|
||||
};
|
||||
build(TYPE_CLOSE, *session_id, p)
|
||||
}
|
||||
}
|
||||
buf
|
||||
}
|
||||
|
||||
pub fn parse(buf: &[u8]) -> Result<Frame, DecodeError> {
|
||||
if buf.len() < 6 {
|
||||
if buf.len() < HEADER_LEN {
|
||||
return Err(DecodeError::Short);
|
||||
}
|
||||
let version = buf[0];
|
||||
@@ -128,7 +129,12 @@ impl Frame {
|
||||
}
|
||||
let typ = buf[1];
|
||||
let session_id = u32::from_be_bytes([buf[2], buf[3], buf[4], buf[5]]);
|
||||
let payload = &buf[6..];
|
||||
let payload_len = u16::from_be_bytes([buf[6], buf[7]]) as usize;
|
||||
if buf.len() < HEADER_LEN + payload_len {
|
||||
return Err(DecodeError::BadPayload("payload_len exceeds available data"));
|
||||
}
|
||||
// Slice exactly payload_len bytes, ignoring any trailing Ethernet padding.
|
||||
let payload = &buf[HEADER_LEN..HEADER_LEN + payload_len];
|
||||
match typ {
|
||||
TYPE_DISCOVER => {
|
||||
if !payload.is_empty() {
|
||||
|
||||
Reference in New Issue
Block a user