phantom_protocol/transport/
framing.rs1use crate::crypto::adaptive_crypto::{CryptoSession, AEAD_OVERHEAD};
16
17use tokio::io::{AsyncReadExt, AsyncWriteExt};
18use tokio::net::TcpStream;
19
20pub const FRAME_HEADER_SIZE: usize = 4;
22
23pub const MAX_FRAME_PAYLOAD: usize = 64 * 1024; pub struct FrameWriter;
28
29impl Default for FrameWriter {
30 fn default() -> Self {
31 Self::new()
32 }
33}
34
35impl FrameWriter {
36 pub fn new() -> Self {
38 Self
39 }
40
41 pub const SPAWN_BLOCKING_THRESHOLD: usize = 256 * 1024; #[inline]
49 pub async fn write_frame(
50 &self,
51 stream: &mut TcpStream,
52 session: &CryptoSession,
53 data: &[u8],
54 ) -> Result<usize, FrameError> {
55 if data.is_empty() {
56 return Ok(0);
57 }
58
59 let total_len = data.len();
60 let num_chunks = total_len.div_ceil(MAX_FRAME_PAYLOAD);
61
62 let total_cap = num_chunks * (FRAME_HEADER_SIZE + AEAD_OVERHEAD) + total_len;
64 let mut batch_buf = Vec::with_capacity(total_cap);
65
66 if total_len > Self::SPAWN_BLOCKING_THRESHOLD {
67 let session = session.clone();
69 let data = data.to_vec();
70
71 batch_buf = tokio::task::spawn_blocking(move || {
72 let mut buf = Vec::with_capacity(total_cap);
73 for chunk in data.chunks(MAX_FRAME_PAYLOAD) {
74 let frame_start = buf.len();
75 let ct_len = chunk.len() + AEAD_OVERHEAD;
76 let len_bytes = (ct_len as u32).to_be_bytes();
77 buf.extend_from_slice(&len_bytes);
79 buf.extend_from_slice(chunk);
81 session
83 .encrypt_in_place_offset(
84 &len_bytes,
85 &mut buf,
86 frame_start + FRAME_HEADER_SIZE,
87 )
88 .map_err(|_| FrameError::EncryptFailed)?;
89 }
90 Ok::<Vec<u8>, FrameError>(buf)
91 })
92 .await
93 .map_err(|_| FrameError::EncryptFailed)??;
94 } else {
95 for chunk in data.chunks(MAX_FRAME_PAYLOAD) {
97 let frame_start = batch_buf.len();
98 let ct_len = chunk.len() + AEAD_OVERHEAD;
99 let len_bytes = (ct_len as u32).to_be_bytes();
100 batch_buf.extend_from_slice(&len_bytes);
102 batch_buf.extend_from_slice(chunk);
104 session
106 .encrypt_in_place_offset(
107 &len_bytes,
108 &mut batch_buf,
109 frame_start + FRAME_HEADER_SIZE,
110 )
111 .map_err(|_| FrameError::EncryptFailed)?;
112 }
113 }
114
115 stream.write_all(&batch_buf).await.map_err(FrameError::Io)?;
117
118 Ok(total_len)
119 }
120
121 #[inline]
124 pub async fn write_frames_batch(
125 &self,
126 stream: &mut TcpStream,
127 session: &CryptoSession,
128 payloads: &[&[u8]],
129 ) -> Result<usize, FrameError> {
130 if payloads.is_empty() {
131 return Ok(0);
132 }
133
134 let total_size: usize = payloads
136 .iter()
137 .map(|p| FRAME_HEADER_SIZE + p.len() + AEAD_OVERHEAD)
138 .sum();
139
140 let mut batch_buf = Vec::with_capacity(total_size);
141 let mut total_payload = 0usize;
142
143 for payload in payloads {
144 let frame_start = batch_buf.len();
145 let ct_len = payload.len() + AEAD_OVERHEAD;
146 let len_bytes = (ct_len as u32).to_be_bytes();
147
148 batch_buf.extend_from_slice(&len_bytes);
150 batch_buf.extend_from_slice(payload);
152
153 let encrypt_start = frame_start + FRAME_HEADER_SIZE;
155 session
156 .encrypt_in_place_offset(&len_bytes, &mut batch_buf, encrypt_start)
157 .map_err(|_| FrameError::EncryptFailed)?;
158
159 total_payload += payload.len();
160 }
161
162 stream.write_all(&batch_buf).await.map_err(FrameError::Io)?;
164
165 Ok(total_payload)
166 }
167}
168
169pub struct FrameReader {
171 header_buf: [u8; FRAME_HEADER_SIZE],
173}
174
175impl Default for FrameReader {
176 fn default() -> Self {
177 Self::new()
178 }
179}
180
181impl FrameReader {
182 pub fn new() -> Self {
183 Self {
184 header_buf: [0u8; FRAME_HEADER_SIZE],
185 }
186 }
187
188 #[inline]
191 pub async fn read_frame(
192 &mut self,
193 stream: &mut TcpStream,
194 session: &CryptoSession,
195 ) -> Result<Vec<u8>, FrameError> {
196 stream
198 .read_exact(&mut self.header_buf)
199 .await
200 .map_err(FrameError::Io)?;
201
202 let ct_len = u32::from_be_bytes(self.header_buf) as usize;
203
204 if ct_len > MAX_FRAME_PAYLOAD + AEAD_OVERHEAD {
205 return Err(FrameError::FrameTooLarge(ct_len));
206 }
207
208 let mut ct = vec![0u8; ct_len];
210 stream.read_exact(&mut ct).await.map_err(FrameError::Io)?;
211
212 if ct_len > FrameWriter::SPAWN_BLOCKING_THRESHOLD {
215 let session = session.clone();
216 let header_buf = self.header_buf; ct = tokio::task::spawn_blocking(move || {
218 let pt = session
219 .decrypt_in_place(&header_buf, &mut ct)
220 .map_err(|_| FrameError::DecryptFailed)?;
221 let pt_len = pt.len();
222 ct.truncate(pt_len);
223 Ok::<Vec<u8>, FrameError>(ct)
224 })
225 .await
226 .map_err(|_| FrameError::DecryptFailed)??;
227 } else {
228 let pt = session
229 .decrypt_in_place(&self.header_buf, &mut ct)
230 .map_err(|_| FrameError::DecryptFailed)?;
231 let pt_len = pt.len();
232 ct.truncate(pt_len);
233 }
234
235 Ok(ct)
236 }
237}
238
239#[derive(Debug)]
241pub enum FrameError {
242 Io(std::io::Error),
243 EncryptFailed,
244 DecryptFailed,
245 FrameTooLarge(usize),
246}
247
248impl std::fmt::Display for FrameError {
249 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
250 match self {
251 Self::Io(e) => write!(f, "Frame I/O error: {}", e),
252 Self::EncryptFailed => write!(f, "Frame encryption failed"),
253 Self::DecryptFailed => write!(f, "Frame decryption / auth failed"),
254 Self::FrameTooLarge(n) => write!(f, "Frame too large: {} bytes", n),
255 }
256 }
257}
258
259impl std::error::Error for FrameError {}
260
261impl From<std::io::Error> for FrameError {
262 fn from(e: std::io::Error) -> Self {
263 Self::Io(e)
264 }
265}
266
267#[cfg(test)]
274mod tests {
275 use super::*;
276 use std::sync::Arc;
277 use tokio::net::TcpListener;
278
279 #[tokio::test]
280 async fn frame_round_trip() {
281 let secret = [0xABu8; 32];
282 let cs = Arc::new(CryptoSession::from_shared_secret(&secret).unwrap());
283 let ss = Arc::new(CryptoSession::from_shared_secret_peer(&secret).unwrap());
284
285 let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
286 let addr = listener.local_addr().unwrap();
287
288 let ss2 = ss.clone();
289 let handle = tokio::spawn(async move {
290 let (mut tcp, _) = listener.accept().await.unwrap();
291 let mut reader = FrameReader::new();
292 let data = reader.read_frame(&mut tcp, &ss2).await.unwrap();
293 assert_eq!(&data, b"Hello, zero-copy framing!");
294 });
295
296 let mut tcp = TcpStream::connect(addr).await.unwrap();
297 let writer = FrameWriter::new();
298 writer
299 .write_frame(&mut tcp, &cs, b"Hello, zero-copy framing!")
300 .await
301 .unwrap();
302
303 handle.await.unwrap();
304 }
305
306 #[tokio::test]
307 async fn large_message_round_trip() {
308 let secret = [0x12u8; 32];
309 let cs = Arc::new(CryptoSession::from_shared_secret(&secret).unwrap());
310 let ss = Arc::new(CryptoSession::from_shared_secret_peer(&secret).unwrap());
311
312 let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
313 let addr = listener.local_addr().unwrap();
314
315 let original_data = vec![0x42u8; 1024 * 1024]; let data_clone = original_data.clone();
317
318 let ss2 = ss.clone();
319 let handle = tokio::spawn(async move {
320 let (mut tcp, _) = listener.accept().await.unwrap();
321 let mut reader = FrameReader::new();
322 let mut received_data = Vec::new();
323
324 let num_chunks = (data_clone.len() + MAX_FRAME_PAYLOAD - 1) / MAX_FRAME_PAYLOAD;
325 for _ in 0..num_chunks {
326 let chunk = reader.read_frame(&mut tcp, &ss2).await.unwrap();
327 received_data.extend_from_slice(&chunk);
328 }
329 assert_eq!(received_data, data_clone);
330 });
331
332 let mut tcp = TcpStream::connect(addr).await.unwrap();
333 let writer = FrameWriter::new();
334 writer
335 .write_frame(&mut tcp, &cs, &original_data)
336 .await
337 .unwrap();
338
339 handle.await.unwrap();
340 }
341
342 #[tokio::test]
343 async fn frame_batch_round_trip() {
344 let secret = [0xCDu8; 32];
345 let cs = Arc::new(CryptoSession::from_shared_secret(&secret).unwrap());
346 let ss = Arc::new(CryptoSession::from_shared_secret_peer(&secret).unwrap());
347
348 let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
349 let addr = listener.local_addr().unwrap();
350
351 let ss2 = ss.clone();
352 let handle = tokio::spawn(async move {
353 let (mut tcp, _) = listener.accept().await.unwrap();
354 let mut reader = FrameReader::new();
355 let d1 = reader.read_frame(&mut tcp, &ss2).await.unwrap();
356 let d2 = reader.read_frame(&mut tcp, &ss2).await.unwrap();
357 let d3 = reader.read_frame(&mut tcp, &ss2).await.unwrap();
358 assert_eq!(&d1, b"Frame 1");
359 assert_eq!(&d2, b"Frame 2");
360 assert_eq!(&d3, b"Frame 3");
361 });
362
363 let mut tcp = TcpStream::connect(addr).await.unwrap();
364 let writer = FrameWriter::new();
365 let payloads: Vec<&[u8]> = vec![b"Frame 1", b"Frame 2", b"Frame 3"];
366 writer
367 .write_frames_batch(&mut tcp, &cs, &payloads)
368 .await
369 .unwrap();
370
371 handle.await.unwrap();
372 }
373}