use crate::error::{Error, Result};
#[derive(Debug, Default)]
pub struct TurnStreamDecoder {
buffer: Vec<u8>,
}
impl TurnStreamDecoder {
pub fn new() -> Self {
Self::default()
}
pub fn extend_from_slice(&mut self, data: &[u8]) {
self.buffer.extend_from_slice(data);
}
pub fn next_message(&mut self) -> Result<Option<Vec<u8>>> {
if self.buffer.len() < CHANNEL_DATA_HEADER_LEN {
return Ok(None);
}
let length = u16::from_be_bytes([self.buffer[2], self.buffer[3]]) as usize;
let total = match self.buffer[0] >> 6 {
0b00 => STUN_HEADER_LEN + length,
0b01 => CHANNEL_DATA_HEADER_LEN + length.next_multiple_of(4),
_ => {
return Err(Error::OtherTurnErr(format!(
"stream byte {:#04x} starts neither a STUN nor a ChannelData message",
self.buffer[0]
)));
}
};
if self.buffer.len() < total {
return Ok(None);
}
let message = self.buffer[..total].to_vec();
self.buffer.drain(..total);
Ok(Some(message))
}
pub fn buffered_len(&self) -> usize {
self.buffer.len()
}
}
const STUN_HEADER_LEN: usize = 20;
const CHANNEL_DATA_HEADER_LEN: usize = 4;
#[cfg(test)]
mod tests {
use super::*;
fn stun(length: u16) -> Vec<u8> {
let mut msg = vec![0x00, 0x01];
msg.extend_from_slice(&length.to_be_bytes());
msg.extend_from_slice(&[0x21, 0x12, 0xa4, 0x42]);
msg.extend_from_slice(&[7; 12]);
msg.extend(std::iter::repeat_n(0u8, length as usize));
msg
}
fn channel_data(data: &[u8]) -> Vec<u8> {
let mut msg = vec![0x40, 0x00];
msg.extend_from_slice(&(data.len() as u16).to_be_bytes());
msg.extend_from_slice(data);
while msg.len() % 4 != 0 {
msg.push(0);
}
msg
}
fn drain(decoder: &mut TurnStreamDecoder) -> Vec<Vec<u8>> {
let mut out = Vec::new();
while let Some(msg) = decoder.next_message().unwrap() {
out.push(msg);
}
out
}
#[test]
fn a_stun_message_is_twenty_bytes_plus_its_length() {
let msg = stun(8);
let mut decoder = TurnStreamDecoder::new();
decoder.extend_from_slice(&msg);
assert_eq!(drain(&mut decoder), vec![msg]);
assert_eq!(decoder.buffered_len(), 0);
}
#[test]
fn channel_data_comes_out_with_its_padding() {
for data in [&b""[..], b"a", b"ab", b"abc", b"abcd", b"abcde"] {
let msg = channel_data(data);
let mut decoder = TurnStreamDecoder::new();
decoder.extend_from_slice(&msg);
assert_eq!(drain(&mut decoder), vec![msg], "{} data bytes", data.len());
assert_eq!(decoder.buffered_len(), 0);
}
}
#[test]
fn messages_arriving_together_come_out_one_by_one() {
let (a, b, c) = (stun(4), channel_data(b"xyz"), stun(0));
let mut decoder = TurnStreamDecoder::new();
decoder.extend_from_slice(&[a.clone(), b.clone(), c.clone()].concat());
assert_eq!(drain(&mut decoder), vec![a, b, c]);
}
#[test]
fn a_message_split_across_reads_waits_until_it_is_whole() {
let msg = channel_data(b"hello");
let mut decoder = TurnStreamDecoder::new();
for (i, byte) in msg.iter().enumerate() {
decoder.extend_from_slice(&[*byte]);
if i + 1 < msg.len() {
assert_eq!(decoder.next_message().unwrap(), None, "early at byte {i}");
}
}
assert_eq!(drain(&mut decoder), vec![msg]);
}
#[test]
fn a_partial_message_after_a_whole_one_stays_buffered() {
let whole = stun(0);
let next = channel_data(b"later");
let mut decoder = TurnStreamDecoder::new();
decoder.extend_from_slice(&[whole.clone(), next[..3].to_vec()].concat());
assert_eq!(drain(&mut decoder), vec![whole]);
assert_eq!(decoder.buffered_len(), 3);
decoder.extend_from_slice(&next[3..]);
assert_eq!(drain(&mut decoder), vec![next]);
}
#[test]
fn bytes_that_are_not_turn_end_the_stream() {
for first in [0x80u8, 0xbf, 0xc0, 0xff] {
let mut decoder = TurnStreamDecoder::new();
decoder.extend_from_slice(&[first, 0, 0, 4, 1, 2, 3, 4]);
assert!(
matches!(decoder.next_message(), Err(Error::OtherTurnErr(_))),
"first byte {first:#04x} was accepted"
);
}
}
}