pub const FRAMING_HEADER_LEN: usize = 2;
pub const MAX_FRAMED_PACKET_SIZE: usize = u16::MAX as usize;
pub fn frame_packet(buf: &[u8]) -> Vec<u8> {
assert!(
buf.len() <= MAX_FRAMED_PACKET_SIZE,
"packet length {} exceeds maximum {}",
buf.len(),
MAX_FRAMED_PACKET_SIZE
);
let mut framed = Vec::with_capacity(FRAMING_HEADER_LEN + buf.len());
let header = (buf.len() as u16).to_be_bytes();
framed.extend_from_slice(&header);
framed.extend_from_slice(buf);
framed
}
pub fn frame_packet_to(buf: &[u8], out: &mut [u8]) -> Option<usize> {
if buf.len() > MAX_FRAMED_PACKET_SIZE {
return None;
}
let total_len = FRAMING_HEADER_LEN + buf.len();
if out.len() < total_len {
return None;
}
let header = (buf.len() as u16).to_be_bytes();
out[..FRAMING_HEADER_LEN].copy_from_slice(&header);
out[FRAMING_HEADER_LEN..total_len].copy_from_slice(buf);
Some(total_len)
}
#[derive(Debug, Default)]
pub struct TcpFrameDecoder {
buffer: Vec<u8>,
}
impl TcpFrameDecoder {
pub fn new() -> Self {
Self { buffer: Vec::new() }
}
pub fn with_capacity(capacity: usize) -> Self {
Self {
buffer: Vec::with_capacity(capacity),
}
}
pub fn extend_from_slice(&mut self, data: &[u8]) {
self.buffer.extend_from_slice(data);
}
pub fn next_packet(&mut self) -> Option<Vec<u8>> {
if self.buffer.len() < FRAMING_HEADER_LEN {
return None;
}
let length = u16::from_be_bytes([self.buffer[0], self.buffer[1]]) as usize;
let total_len = FRAMING_HEADER_LEN + length;
if self.buffer.len() < total_len {
return None;
}
let packet = self.buffer[FRAMING_HEADER_LEN..total_len].to_vec();
self.buffer.drain(..total_len);
Some(packet)
}
pub fn buffered_len(&self) -> usize {
self.buffer.len()
}
pub fn is_empty(&self) -> bool {
self.buffer.is_empty()
}
pub fn clear(&mut self) {
self.buffer.clear();
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_frame_packet() {
let packet = b"Hello, WebRTC!";
let framed = frame_packet(packet);
assert_eq!(framed.len(), FRAMING_HEADER_LEN + packet.len());
let length = u16::from_be_bytes([framed[0], framed[1]]) as usize;
assert_eq!(length, packet.len());
assert_eq!(&framed[FRAMING_HEADER_LEN..], packet);
}
#[test]
fn test_frame_packet_to() {
let packet = b"Hello";
let mut out = [0u8; 100];
let n = frame_packet_to(packet, &mut out).unwrap();
assert_eq!(n, 7);
assert_eq!(&out[..n], &frame_packet(packet)[..]);
}
#[test]
fn test_frame_packet_to_buffer_too_small() {
let packet = b"Hello";
let mut out = [0u8; 3];
assert!(frame_packet_to(packet, &mut out).is_none());
}
#[test]
fn test_decoder_complete_packet() {
let mut decoder = TcpFrameDecoder::new();
let framed = frame_packet(b"Test");
decoder.extend_from_slice(&framed);
let packet = decoder.next_packet().unwrap();
assert_eq!(packet, b"Test");
assert!(decoder.is_empty());
}
#[test]
fn test_decoder_partial_header() {
let mut decoder = TcpFrameDecoder::new();
decoder.extend_from_slice(&[0]);
assert!(decoder.next_packet().is_none());
decoder.extend_from_slice(&[5, b'H', b'e', b'l', b'l', b'o']);
assert_eq!(decoder.next_packet(), Some(b"Hello".to_vec()));
}
#[test]
fn test_decoder_partial_payload() {
let mut decoder = TcpFrameDecoder::new();
decoder.extend_from_slice(&[0, 5, b'H', b'e']);
assert!(decoder.next_packet().is_none());
assert_eq!(decoder.buffered_len(), 4);
decoder.extend_from_slice(&[b'l', b'l', b'o']);
assert_eq!(decoder.next_packet(), Some(b"Hello".to_vec()));
}
#[test]
fn test_decoder_multiple_packets() {
let mut decoder = TcpFrameDecoder::new();
let framed1 = frame_packet(b"First");
let framed2 = frame_packet(b"Second");
let framed3 = frame_packet(b"Third");
decoder.extend_from_slice(&framed1);
decoder.extend_from_slice(&framed2);
decoder.extend_from_slice(&framed3);
assert_eq!(decoder.next_packet(), Some(b"First".to_vec()));
assert_eq!(decoder.next_packet(), Some(b"Second".to_vec()));
assert_eq!(decoder.next_packet(), Some(b"Third".to_vec()));
assert!(decoder.next_packet().is_none());
}
#[test]
fn test_decoder_multiple_packets_interleaved() {
let mut decoder = TcpFrameDecoder::new();
let mut combined = frame_packet(b"First");
combined.extend_from_slice(&frame_packet(b"Second"));
decoder.extend_from_slice(&combined[..5]);
assert!(decoder.next_packet().is_none());
decoder.extend_from_slice(&combined[5..]);
assert_eq!(decoder.next_packet(), Some(b"First".to_vec()));
assert_eq!(decoder.next_packet(), Some(b"Second".to_vec()));
}
#[test]
fn test_empty_packet() {
let framed = frame_packet(b"");
assert_eq!(framed.len(), FRAMING_HEADER_LEN);
assert_eq!(framed, vec![0, 0]);
let mut decoder = TcpFrameDecoder::new();
decoder.extend_from_slice(&framed);
assert_eq!(decoder.next_packet(), Some(vec![]));
}
#[test]
#[should_panic(expected = "packet length")]
fn test_frame_packet_too_large() {
let huge = vec![0u8; MAX_FRAMED_PACKET_SIZE + 1];
frame_packet(&huge);
}
#[test]
fn test_decoder_clear() {
let mut decoder = TcpFrameDecoder::new();
decoder.extend_from_slice(&[0, 5, b'H']);
assert_eq!(decoder.buffered_len(), 3);
decoder.clear();
assert!(decoder.is_empty());
}
}