nodedb_cluster/rpc_codec/
header.rs1use crate::error::{ClusterError, Result};
13use crate::wire::WIRE_VERSION;
14
15pub const HEADER_SIZE: usize = 10;
17
18pub const MAX_RPC_PAYLOAD_SIZE: u32 = 64 * 1024 * 1024;
22
23pub fn write_frame(rpc_type: u8, payload: &[u8], out: &mut Vec<u8>) -> Result<()> {
27 let payload_len: u32 = payload.len().try_into().map_err(|_| ClusterError::Codec {
28 detail: format!("payload too large: {} bytes", payload.len()),
29 })?;
30 let crc = crc32c::crc32c(payload);
31 out.push(WIRE_VERSION as u8);
33 out.push(rpc_type);
34 out.extend_from_slice(&payload_len.to_le_bytes());
35 out.extend_from_slice(&crc.to_le_bytes());
36 out.extend_from_slice(payload);
37 Ok(())
38}
39
40pub fn parse_frame(data: &[u8]) -> Result<(u8, &[u8])> {
44 if data.len() < HEADER_SIZE {
45 return Err(ClusterError::Codec {
46 detail: format!("frame too short: {} bytes, need {HEADER_SIZE}", data.len()),
47 });
48 }
49
50 let version = data[0];
51 if version != WIRE_VERSION as u8 {
52 return Err(ClusterError::Codec {
53 detail: format!("unsupported wire version: {version}, expected {WIRE_VERSION}"),
54 });
55 }
56
57 let rpc_type = data[1];
58 let payload_len = u32::from_le_bytes([data[2], data[3], data[4], data[5]]);
59 let expected_crc = u32::from_le_bytes([data[6], data[7], data[8], data[9]]);
60
61 if payload_len > MAX_RPC_PAYLOAD_SIZE {
62 return Err(ClusterError::Codec {
63 detail: format!("payload length {payload_len} exceeds maximum {MAX_RPC_PAYLOAD_SIZE}"),
64 });
65 }
66
67 let expected_total = HEADER_SIZE + payload_len as usize;
68 if data.len() < expected_total {
69 return Err(ClusterError::Codec {
70 detail: format!(
71 "frame truncated: got {} bytes, expected {expected_total}",
72 data.len()
73 ),
74 });
75 }
76
77 let payload = &data[HEADER_SIZE..expected_total];
78 let actual_crc = crc32c::crc32c(payload);
79 if actual_crc != expected_crc {
80 return Err(ClusterError::Codec {
81 detail: format!(
82 "CRC32C mismatch: expected {expected_crc:#010x}, got {actual_crc:#010x}"
83 ),
84 });
85 }
86
87 Ok((rpc_type, payload))
88}
89
90pub fn frame_size(header: &[u8; HEADER_SIZE]) -> Result<usize> {
92 let payload_len = u32::from_le_bytes([header[2], header[3], header[4], header[5]]);
93 if payload_len > MAX_RPC_PAYLOAD_SIZE {
94 return Err(ClusterError::Codec {
95 detail: format!("payload length {payload_len} exceeds maximum {MAX_RPC_PAYLOAD_SIZE}"),
96 });
97 }
98 Ok(HEADER_SIZE + payload_len as usize)
99}
100
101