#![allow(dead_code)]
use alloc::collections::VecDeque;
use alloc::vec::Vec;
use crate::quic::varint;
use crate::tls::Error;
pub(crate) struct DatagramQueues {
pub(crate) outbound: VecDeque<Vec<u8>>,
pub(crate) inbound: VecDeque<Vec<u8>>,
pub(crate) peer_max_frame_size: u64,
pub(crate) our_max_frame_size: u64,
}
impl DatagramQueues {
pub(crate) fn new(peer_param: Option<u64>, our_param: Option<u64>) -> Self {
Self {
outbound: VecDeque::new(),
inbound: VecDeque::new(),
peer_max_frame_size: peer_param.unwrap_or(0),
our_max_frame_size: our_param.unwrap_or(0),
}
}
pub(crate) fn peer_accepts(&self) -> bool {
self.peer_max_frame_size > 0
}
pub(crate) fn send(&mut self, data: &[u8]) -> Result<(), Error> {
if !self.peer_accepts() {
return Err(Error::InappropriateState);
}
let frame_len = 1 + varint::encoded_len(data.len() as u64) + data.len();
if (frame_len as u64) > self.peer_max_frame_size {
return Err(Error::IllegalParameter);
}
self.outbound.push_back(data.to_vec());
Ok(())
}
pub(crate) fn recv(&mut self) -> Option<Vec<u8>> {
self.inbound.pop_front()
}
pub(crate) fn pop_outbound(&mut self, budget: usize) -> Option<Vec<u8>> {
let head = self.outbound.front()?;
let frame_len = 1 + varint::encoded_len(head.len() as u64) + head.len();
if frame_len > budget {
return None;
}
self.outbound.pop_front()
}
pub(crate) fn enqueue_inbound(&mut self, data: Vec<u8>) {
self.inbound.push_back(data);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn send_refused_if_peer_didnt_advertise() {
let mut q = DatagramQueues::new(None, Some(1200));
let r = q.send(b"hi");
assert!(matches!(r, Err(Error::InappropriateState)));
let mut q2 = DatagramQueues::new(Some(0), Some(1200));
let r2 = q2.send(b"hi");
assert!(matches!(r2, Err(Error::InappropriateState)));
}
#[test]
fn send_rejects_payload_exceeding_peer_max() {
let mut q = DatagramQueues::new(Some(100), Some(1200));
let big = alloc::vec![0xABu8; 200];
let r = q.send(&big);
assert!(matches!(r, Err(Error::IllegalParameter)));
assert!(q.send(b"ok").is_ok());
}
#[test]
fn send_then_pop_round_trips() {
let mut q = DatagramQueues::new(Some(1200), Some(1200));
q.send(b"hello").expect("send");
q.send(b"world").expect("send");
let popped = q.pop_outbound(7).expect("pop");
assert_eq!(popped, b"hello".to_vec());
let no = q.pop_outbound(1);
assert!(no.is_none());
let popped2 = q.pop_outbound(1024).expect("pop second");
assert_eq!(popped2, b"world".to_vec());
assert!(q.pop_outbound(1024).is_none());
}
#[test]
fn recv_round_trips() {
let mut q = DatagramQueues::new(Some(1200), Some(1200));
q.enqueue_inbound(b"a".to_vec());
q.enqueue_inbound(b"b".to_vec());
assert_eq!(q.recv().unwrap(), b"a".to_vec());
assert_eq!(q.recv().unwrap(), b"b".to_vec());
assert!(q.recv().is_none());
}
#[test]
fn peer_accepts_reflects_advertised_value() {
assert!(!DatagramQueues::new(None, None).peer_accepts());
assert!(!DatagramQueues::new(Some(0), None).peer_accepts());
assert!(DatagramQueues::new(Some(1), None).peer_accepts());
assert!(DatagramQueues::new(Some(1200), None).peer_accepts());
}
}