use crate::{Buf, BufError, BufMut, BufResult, Codec, Cursor};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(u8)]
pub enum HeaderForm {
ShortHeader = 0x00,
LongHeader = 0x01,
}
impl Codec for HeaderForm {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
let current_byte = writer.peek_u8().unwrap_or(0x00);
let header_bit = (*self as u8) << 7;
let byte = (current_byte & !0x80) | header_bit;
writer.poke_u8(byte)
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
let value = reader.peek_u8()? & 0x80;
match value {
0 => Ok(Self::ShortHeader),
_ => Ok(Self::LongHeader),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Version(pub u32);
impl Version {
pub const VERSION_NEGOTIATION: Self = Self(0x00000000);
pub const QUIC_V1: Self = Self(0x00000001);
pub const QUIC_V2: Self = Self(0x6b3343cf);
pub fn is_grease(&self) -> bool {
(self.0 & 0x0f0f0f0f) == 0x0a0a0a0a
}
}
impl Codec for Version {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
self.0.encode(writer, ())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
Ok(Self(u32::decode(reader, ())?))
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ConnectionId(Vec<u8>);
impl ConnectionId {
pub const MAXIMAL_LENGTH: u8 = u8::MAX;
pub fn from_slice(connection_id: &[u8]) -> BufResult<Self> {
if connection_id.length() > Self::MAXIMAL_LENGTH as usize {
return Err(BufError::InvalidLength);
}
Ok(Self(connection_id.to_vec()))
}
pub fn from_vec(connection_id: Vec<u8>) -> BufResult<Self> {
if connection_id.len() > Self::MAXIMAL_LENGTH as usize {
return Err(BufError::InvalidLength);
}
Ok(Self(connection_id))
}
pub fn length(&self) -> u8 {
self.0.len() as u8
}
pub fn bytes(&self) -> Vec<u8> {
self.0.clone()
}
}
impl Codec for ConnectionId {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
(self.0.len() as u8).encode(writer, ())?;
self.0.encode(writer, self.0.len())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
let bytes = &mut [0u8; Self::MAXIMAL_LENGTH as usize];
let length = u8::decode(reader, ())?;
reader.read_into(&mut bytes[..length as usize])?;
Ok(Self::from_slice(&bytes[..length as usize])?)
}
}
impl Codec<u8> for ConnectionId {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: u8) -> BufResult<()> {
writer.write_slice(&self.0[..self.length() as usize])
}
fn decode<R: Buf>(reader: &mut Cursor<R>, cil: u8) -> BufResult<Self> {
let bytes = &mut [0u8; Self::MAXIMAL_LENGTH as usize];
reader.read_into(&mut bytes[..cil as usize])?;
Ok(Self::from_slice(&bytes[..cil as usize])?)
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct VersionNegotiationPacket {
pub destination_connection_id: ConnectionId,
pub source_connection_id: ConnectionId,
pub supported_version: Vec<Version>,
}
impl VersionNegotiationPacket {
pub const HEADER_FORM: HeaderForm = HeaderForm::LongHeader;
pub const VERSION: Version = Version::VERSION_NEGOTIATION;
}
impl Codec for VersionNegotiationPacket {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
Self::HEADER_FORM.encode(writer, ())?;
writer.advance(1)?;
Self::VERSION.encode(writer, ())?;
self.destination_connection_id.encode(writer, ())?;
self.source_connection_id.encode(writer, ())?;
self.supported_version.encode(writer, ())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
if HeaderForm::decode(reader, ())? != Self::HEADER_FORM {
return Err(BufError::UnexpectedValue);
}
reader.advance(1)?;
if Version::decode(reader, ())? != Self::VERSION {
return Err(BufError::UnexpectedValue);
}
let destination_connection_id = ConnectionId::decode(reader, ())?;
let source_connection_id = ConnectionId::decode(reader, ())?;
let supported_version = Vec::decode(reader, ())?;
Ok(Self {
destination_connection_id,
source_connection_id,
supported_version,
})
}
}
#[cfg(test)]
mod tests {
use core::fmt::Debug;
use crate::{
BufError, Codec, Cursor,
quic::{ConnectionId, HeaderForm, Version, VersionNegotiationPacket},
};
fn codec_roundtrip<T: Codec<C> + Debug + Eq, C: Copy>(
etalon_struct: T,
etalon_bytes: &[u8],
context: C,
) {
let mut encoded_bytes = vec![];
{
let writer = &mut Cursor::new(&mut encoded_bytes);
etalon_struct.encode(writer, context).unwrap();
}
assert_eq!(etalon_bytes, &encoded_bytes);
let decoded_struct = {
let reader = &mut Cursor::new(&mut encoded_bytes);
T::decode(reader, context).unwrap()
};
assert_eq!(etalon_struct, decoded_struct);
encoded_bytes.fill(0x00);
{
let writer = &mut Cursor::new(&mut encoded_bytes);
decoded_struct.encode(writer, context).unwrap();
}
assert_eq!(etalon_bytes, &encoded_bytes);
}
#[test]
fn header_form() {
let etalon_bytes = &[0b10000000];
let etalon_struct = HeaderForm::LongHeader;
codec_roundtrip(etalon_struct, etalon_bytes, ());
let etalon_bytes = &[0b00000000];
let etalon_struct = HeaderForm::ShortHeader;
codec_roundtrip(etalon_struct, etalon_bytes, ());
}
#[test]
fn version() {
let etalon_bytes = &[0x00, 0x00, 0x00, 0x01];
let etalon_struct = Version(1);
codec_roundtrip(etalon_struct, etalon_bytes, ());
assert_eq!(etalon_struct.is_grease(), false);
let etalon_bytes = &[0x1a, 0x1a, 0x1a, 0x1a];
let etalon_struct = Version(0x1a1a1a1a);
codec_roundtrip(etalon_struct, etalon_bytes, ());
assert_eq!(etalon_struct.is_grease(), true);
}
#[test]
fn connection_id() {
assert_eq!(
ConnectionId::from_slice(&[0x08; 256]),
Err(BufError::InvalidLength)
);
let etalon_bytes = &[0x08; 9];
let etalon_struct = ConnectionId::from_slice(&[0x08; 8]).unwrap();
codec_roundtrip(etalon_struct, etalon_bytes, ());
let etalon_bytes = &[0x014; 21];
let etalon_struct = ConnectionId::from_slice(&[0x014; 20]).unwrap();
codec_roundtrip(etalon_struct, etalon_bytes, ());
}
#[test]
fn version_negotiation_packet() {
let etalon_struct = VersionNegotiationPacket {
destination_connection_id: ConnectionId::from_slice(&[0x82; 8]).unwrap(),
source_connection_id: ConnectionId::from_slice(&[0x41; 8]).unwrap(),
supported_version: vec![Version(0)],
};
let etalon_bytes: &[u8] = &[
0b10000000, 0x00, 0x00, 0x00, 0x00, 0x08, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x08, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x00, 0x00, 0x00, 0x00,
];
codec_roundtrip(etalon_struct, etalon_bytes, ());
}
}