Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 3 additions & 8 deletions nvx-rs/src/protocol/nvxs/record.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

use std::fmt;

use crate::protocol::outer::encode_header;
use crate::protocol::{
CAPABILITY_LEN, OUTER_ACK, OUTER_CREDIT, OUTER_DATA, OUTER_ERROR, OUTER_GUEST_ATTACH,
OUTER_HEADER_LEN, OUTER_HOST_ATTACH, OUTER_MAGIC, OUTER_MAX_PAYLOAD, OUTER_MAX_RECEIVE_WINDOW,
Expand Down Expand Up @@ -315,15 +316,9 @@ pub fn encode_record(
check_payload(record_type, payload)?;
// The length check bounds the payload by `OUTER_MAX_PAYLOAD`, so it fits the header's field.
let length = payload.len() as u32;
let header = encode_header(record_type.code(), instance_id, epoch, sequence, length);
output.reserve(OUTER_HEADER_LEN + payload.len());
output.extend_from_slice(&OUTER_MAGIC);
output.extend_from_slice(&OUTER_VERSION.to_le_bytes());
output.push(record_type.code());
output.push(0);
output.extend_from_slice(instance_id);
output.extend_from_slice(&epoch.to_le_bytes());
output.extend_from_slice(&sequence.to_le_bytes());
output.extend_from_slice(&length.to_le_bytes());
output.extend_from_slice(&header);
output.extend_from_slice(payload);
Ok(())
}
Expand Down
33 changes: 25 additions & 8 deletions nvx-rs/src/protocol/outer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,19 +82,36 @@ pub fn encode_outer(
.ok()
.filter(|&length| length as usize <= OUTER_MAX_PAYLOAD)
.ok_or_else(|| violation("control payload exceeds the outer protocol limit"))?;
let header = encode_header(record_type, instance_id, epoch, sequence, length);
let mut record = Vec::with_capacity(OUTER_HEADER_LEN + payload.len());
record.extend_from_slice(&OUTER_MAGIC);
record.extend_from_slice(&OUTER_VERSION.to_le_bytes());
record.push(record_type);
record.push(0);
record.extend_from_slice(instance_id);
record.extend_from_slice(&epoch.to_le_bytes());
record.extend_from_slice(&sequence.to_le_bytes());
record.extend_from_slice(&length.to_le_bytes());
record.extend_from_slice(&header);
record.extend_from_slice(payload);
Ok(record)
}

/// Returns the header of a record: [`OUTER_MAGIC`], [`OUTER_VERSION`], `record_type`, a zero
/// flags byte, `instance_id`, `epoch`, `sequence`, and the payload's `length`, with the integers
/// little-endian. It checks nothing: [`encode_outer`] and
/// [`encode_record`](super::nvxs::encode_record) each validate their record first.
pub(super) fn encode_header(
record_type: u8,
instance_id: &[u8; 16],
epoch: u64,
sequence: u64,
length: u32,
) -> [u8; OUTER_HEADER_LEN] {
let mut header = [0; OUTER_HEADER_LEN];
header[..4].copy_from_slice(&OUTER_MAGIC);
header[4..6].copy_from_slice(&OUTER_VERSION.to_le_bytes());
header[6] = record_type;
// The flags byte, header[7], stays zero.
header[8..24].copy_from_slice(instance_id);
header[24..32].copy_from_slice(&epoch.to_le_bytes());
header[32..40].copy_from_slice(&sequence.to_le_bytes());
header[40..].copy_from_slice(&length.to_le_bytes());
header
}

/// Decodes and validates an outer record header.
pub fn decode_outer_header(header: &[u8; OUTER_HEADER_LEN]) -> Result<OuterHeader, ProtocolError> {
let version = u16::from_le_bytes([header[4], header[5]]);
Expand Down
Loading