use crate::{
Buf,
BufError::{self},
BufMut, BufResult, Codec, Cursor,
ietf::quicv1::{ConnectionId, RetryToken, VarInt, VariableLengthInteger},
};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(u64)]
pub enum FrameType {
Padding = 0x00,
Ping = 0x01,
Ack = 0x02,
ResetStream = 0x04,
StopSending = 0x05,
Crypto = 0x06,
NewToken = 0x07,
Stream = 0x08,
MaxData = 0x10,
MaxStreamData = 0x11,
MaxStreams = 0x12,
DataBlocked = 0x14,
StreamDataBlocked = 0x15,
StreamsBlocked = 0x16,
NewConnectionId = 0x18,
RetireConnectionId = 0x19,
PathChallenge = 0x1a,
PathResponse = 0x1b,
ConnectionClose = 0x1c,
HandshakeDone = 0x1e,
}
impl Codec for FrameType {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
(*self as u8).encode(writer, ())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
match u8::decode(reader, ())? {
x if x == (Self::Padding as u8) => Ok(Self::Padding),
_ => Err(BufError::UnexpectedValue),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct PaddingFrame;
impl PaddingFrame {
pub const TYPE: VarInt = VariableLengthInteger(FrameType::Padding as u64);
}
impl Codec for PaddingFrame {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
Self::TYPE.encode(writer, ())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
if VarInt::decode(reader, ())? != Self::TYPE {
return Err(BufError::UnexpectedValue);
}
Ok(Self {})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct PingFrame;
impl PingFrame {
pub const TYPE: VarInt = VariableLengthInteger(FrameType::Ping as u64);
}
impl Codec for PingFrame {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
Self::TYPE.encode(writer, ())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
if VarInt::decode(reader, ())? != Self::TYPE {
return Err(BufError::UnexpectedValue);
}
Ok(Self {})
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct AckFrame {
pub largest_acknowledged: VarInt,
pub ack_delay: VarInt,
pub first_ack_range: VarInt,
pub ack_ranges: Vec<AckRange>,
pub ecn_counts: Option<EcnCounts>,
}
impl AckFrame {
pub fn calculate_type(&self) -> VarInt {
match self.ecn_counts {
Some(_) => VariableLengthInteger(0x03),
None => VariableLengthInteger(0x02),
}
}
}
impl Codec for AckFrame {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
self.calculate_type().encode(writer, ())?;
self.largest_acknowledged.encode(writer, ())?;
self.ack_delay.encode(writer, ())?;
(VariableLengthInteger::new(self.ack_ranges.len() as u64)?).encode(writer, ())?;
self.first_ack_range.encode(writer, ())?;
self.ack_ranges.encode(writer, ())?;
match self.ecn_counts {
Some(ecn_counts) => ecn_counts.encode(writer, ()),
None => Ok(()),
}
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
let r#type = (VarInt::decode(reader, ())?).into_inner();
let largest_acknowledged = VarInt::decode(reader, ())?;
let ack_delay = VarInt::decode(reader, ())?;
let ack_range_count = VarInt::decode(reader, ())?;
let first_ack_range = VarInt::decode(reader, ())?;
let ack_ranges = Vec::decode(reader, ack_range_count.0 as usize)?;
let ecn_counts = match r#type {
0x02 => None,
0x03 => Some(EcnCounts::decode(reader, ())?),
_ => return Err(BufError::UnexpectedValue),
};
Ok(Self {
largest_acknowledged,
ack_delay,
first_ack_range,
ack_ranges,
ecn_counts,
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct AckRange {
pub gap: VarInt,
pub ack_range_length: VarInt,
}
impl Codec for AckRange {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
self.gap.encode(writer, ())?;
self.ack_range_length.encode(writer, ())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
Ok(Self {
gap: VarInt::decode(reader, ())?,
ack_range_length: VarInt::decode(reader, ())?,
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct EcnCounts {
pub ect0_count: VarInt,
pub ect1_count: VarInt,
pub ecn_ce_count: VarInt,
}
impl Codec for EcnCounts {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
self.ect0_count.encode(writer, ())?;
self.ect1_count.encode(writer, ())?;
self.ecn_ce_count.encode(writer, ())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
Ok(Self {
ect0_count: VarInt::decode(reader, ())?,
ect1_count: VarInt::decode(reader, ())?,
ecn_ce_count: VarInt::decode(reader, ())?,
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ResetStreamFrame {
pub stream_id: StreamId,
pub application_protocol_error_code: VarInt,
pub final_size: VarInt,
}
impl ResetStreamFrame {
pub const TYPE: VarInt = VariableLengthInteger(FrameType::ResetStream as u64);
}
impl Codec for ResetStreamFrame {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
Self::TYPE.encode(writer, ())?;
self.stream_id.encode(writer, ())?;
self.application_protocol_error_code.encode(writer, ())?;
self.final_size.encode(writer, ())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
if VarInt::decode(reader, ())? != Self::TYPE {
return Err(BufError::UnexpectedValue);
}
let stream_id = StreamId::decode(reader, ())?;
let application_protocol_error_code = VarInt::decode(reader, ())?;
let final_size = VarInt::decode(reader, ())?;
Ok(Self {
stream_id,
application_protocol_error_code,
final_size,
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct StopSendingFrame {
pub stream_id: StreamId,
pub application_protocol_error_code: VarInt,
}
impl StopSendingFrame {
pub const TYPE: VarInt = VariableLengthInteger(FrameType::StopSending as u64);
}
impl Codec for StopSendingFrame {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
Self::TYPE.encode(writer, ())?;
self.stream_id.encode(writer, ())?;
self.application_protocol_error_code.encode(writer, ())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
if VarInt::decode(reader, ())? != Self::TYPE {
return Err(BufError::UnexpectedValue);
}
let stream_id = StreamId::decode(reader, ())?;
let application_protocol_error_code = VarInt::decode(reader, ())?;
Ok(Self {
stream_id,
application_protocol_error_code,
})
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct CryptoFrame {
pub offset: VarInt,
pub crypto_data: Vec<u8>,
}
impl CryptoFrame {
pub const TYPE: VarInt = VariableLengthInteger(FrameType::Crypto as u64);
pub fn calculate_length(&self) -> VarInt {
VariableLengthInteger(self.crypto_data.len() as u64)
}
}
impl Codec for CryptoFrame {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
Self::TYPE.encode(writer, ())?;
self.offset.encode(writer, ())?;
self.calculate_length().encode(writer, ())?;
self.crypto_data.encode(writer, ())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
if VarInt::decode(reader, ())? != Self::TYPE {
return Err(BufError::UnexpectedValue);
}
let offset = VarInt::decode(reader, ())?;
let length = (VarInt::decode(reader, ())?).into_inner();
let mut crypto_data = [0u8; 1400];
let mut crypto_data = &mut crypto_data[..length as usize];
reader.read_into(&mut crypto_data)?;
let crypto_data = crypto_data.to_vec();
Ok(Self {
offset,
crypto_data,
})
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct NewTokenFrame {
pub token: RetryToken,
}
impl NewTokenFrame {
pub const TYPE: VarInt = VariableLengthInteger(FrameType::NewToken as u64);
pub fn calculate_token_length(&self) -> VarInt {
VariableLengthInteger(self.token.0.len() as u64)
}
}
impl Codec for NewTokenFrame {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
Self::TYPE.encode(writer, ())?;
self.calculate_token_length().encode(writer, ())?;
self.token.0.encode(writer, ())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
if VarInt::decode(reader, ())? != Self::TYPE {
return Err(BufError::UnexpectedValue);
}
let length = (VarInt::decode(reader, ())?).into_inner();
let mut token = [0u8; 1400];
let mut token = &mut token[..length as usize];
reader.read_into(&mut token)?;
let token = RetryToken(token.to_vec());
Ok(Self { token })
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct StreamFrame {
pub stream_id: StreamId,
pub offset: Option<VarInt>,
pub length: Option<VarInt>,
pub fin: bool,
pub stream_data: Vec<u8>,
}
impl StreamFrame {
pub const TYPE: VarInt = VarInt::new_const(0x08);
pub const TYPE_OFF: VarInt = VarInt::new_const(0x0c);
pub const TYPE_LEN: VarInt = VarInt::new_const(0x0a);
pub const TYPE_FIN: VarInt = VarInt::new_const(0x09);
pub const TYPE_LEN_FIN: VarInt = VarInt::new_const(0x0b);
pub const TYPE_OFF_LEN: VarInt = VarInt::new_const(0x0e);
pub const TYPE_OFF_FIN: VarInt = VarInt::new_const(0x0d);
pub const TYPE_OFF_LEN_FIN: VarInt = VarInt::new_const(0x0f);
pub fn calculate_type(&self) -> VarInt {
match self.offset {
Some(_) => match self.length {
Some(_) => match self.fin {
true => Self::TYPE_OFF_LEN_FIN,
false => Self::TYPE_OFF_LEN,
},
None => match self.fin {
true => Self::TYPE_OFF_FIN,
false => Self::TYPE_OFF,
},
},
None => match self.length {
Some(_) => match self.fin {
true => Self::TYPE_LEN_FIN,
false => Self::TYPE_LEN,
},
None => match self.fin {
true => Self::TYPE_FIN,
false => Self::TYPE,
},
},
}
}
pub fn calculate_length(&self) -> VarInt {
VariableLengthInteger(self.stream_data.len() as u64)
}
}
impl Codec for StreamFrame {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
self.calculate_type().encode(writer, ())?;
self.stream_id.encode(writer, ())?;
match self.offset {
Some(offset) => offset.encode(writer, ()),
None => Ok(()),
}?;
match self.length {
Some(_) => self.calculate_length().encode(writer, ()),
None => Ok(()),
}?;
self.stream_data.encode(writer, ())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
let typ = VariableLengthInteger::decode(reader, ())?;
let stream_id = StreamId::decode(reader, ())?;
let (offset, length, fin) = match typ {
Self::TYPE => (None, None, false),
Self::TYPE_FIN => (None, None, true),
Self::TYPE_LEN => (None, Some(VarInt::decode(reader, ())?), false),
Self::TYPE_LEN_FIN => (None, Some(VarInt::decode(reader, ())?), true),
Self::TYPE_OFF => (
Some(VariableLengthInteger::decode(reader, ())?),
None,
false,
),
Self::TYPE_OFF_FIN => (Some(VarInt::decode(reader, ())?), None, true),
Self::TYPE_OFF_LEN => (
Some(VarInt::decode(reader, ())?),
Some(VarInt::decode(reader, ())?),
false,
),
Self::TYPE_OFF_LEN_FIN => (
Some(VarInt::decode(reader, ())?),
Some(VarInt::decode(reader, ())?),
true,
),
_ => return Err(BufError::UnexpectedValue),
};
let stream_data = match length {
Some(x) => Vec::decode(reader, x.0 as usize)?,
None => Vec::decode(reader, ())?,
};
Ok(Self {
stream_id,
offset,
length,
fin,
stream_data,
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct StreamId(pub VarInt);
impl Codec for StreamId {
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(VarInt::decode(reader, ())?))
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(u8)]
pub enum StreamType {
ClientInitiatedBidirectional = 0x00,
ServerInitiatedBidirectional = 0x01,
ClientInitiatedUnidirectional = 0x02,
ServerInitiatedUnidirectional = 0x03,
}
impl Codec for StreamType {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
(*self as u8).encode(writer, ())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
match u8::decode(reader, ())? {
x if x == (Self::ClientInitiatedBidirectional as u8) => {
Ok(Self::ClientInitiatedBidirectional)
}
x if x == (Self::ServerInitiatedBidirectional as u8) => {
Ok(Self::ServerInitiatedBidirectional)
}
x if x == (Self::ClientInitiatedUnidirectional as u8) => {
Ok(Self::ClientInitiatedUnidirectional)
}
x if x == (Self::ServerInitiatedUnidirectional as u8) => {
Ok(Self::ServerInitiatedUnidirectional)
}
_ => Err(BufError::UnexpectedValue),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct MaxDataFrame {
pub maximum_data: VarInt,
}
impl MaxDataFrame {
pub const TYPE: VarInt = VariableLengthInteger(FrameType::MaxData as u64);
}
impl Codec for MaxDataFrame {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
Self::TYPE.encode(writer, ())?;
self.maximum_data.encode(writer, ())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
if VarInt::decode(reader, ())? != Self::TYPE {
return Err(BufError::UnexpectedValue);
}
Ok(Self {
maximum_data: VarInt::decode(reader, ())?,
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct MaxStreamDataFrame {
pub stream_id: StreamId,
pub maximum_stream_data: VarInt,
}
impl MaxStreamDataFrame {
pub const TYPE: VarInt = VariableLengthInteger(FrameType::MaxStreamData as u64);
}
impl Codec for MaxStreamDataFrame {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
Self::TYPE.encode(writer, ())?;
self.stream_id.encode(writer, ())?;
self.maximum_stream_data.encode(writer, ())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
if VarInt::decode(reader, ())? != Self::TYPE {
return Err(BufError::UnexpectedValue);
}
Ok(Self {
stream_id: StreamId::decode(reader, ())?,
maximum_stream_data: VariableLengthInteger::decode(reader, ())?,
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct MaxStreamsFrame {
pub maximum_streams: VarInt,
pub bidirectional: bool,
}
impl MaxStreamsFrame {
pub const TYPE_BIDIRECTRIONAL: VarInt = VarInt::new_const(0x12);
pub const TYPE_UNIDIRECTRIONAL: VarInt = VarInt::new_const(0x13);
pub fn calculate_type(&self) -> VarInt {
match self.bidirectional {
true => Self::TYPE_BIDIRECTRIONAL,
false => Self::TYPE_UNIDIRECTRIONAL,
}
}
}
impl Codec for MaxStreamsFrame {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
self.calculate_type().encode(writer, ())?;
self.maximum_streams.encode(writer, ())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
let bidirectional = match VarInt::decode(reader, ())? {
Self::TYPE_BIDIRECTRIONAL => true,
Self::TYPE_UNIDIRECTRIONAL => false,
_ => return Err(BufError::UnexpectedValue),
};
let maximum_streams = VariableLengthInteger::decode(reader, ())?;
Ok(Self {
maximum_streams,
bidirectional,
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct DataBlockedFrame {
pub maximum_data: VarInt,
}
impl DataBlockedFrame {
pub const TYPE: VarInt = VariableLengthInteger(FrameType::DataBlocked as u64);
}
impl Codec for DataBlockedFrame {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
Self::TYPE.encode(writer, ())?;
self.maximum_data.encode(writer, ())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
if VarInt::decode(reader, ())? != Self::TYPE {
return Err(BufError::UnexpectedValue);
}
Ok(Self {
maximum_data: VarInt::decode(reader, ())?,
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct StreamDataBlockedFrame {
pub stream_id: StreamId,
pub maximum_stream_data: VarInt,
}
impl StreamDataBlockedFrame {
pub const TYPE: VarInt = VariableLengthInteger(FrameType::StreamDataBlocked as u64);
}
impl Codec for StreamDataBlockedFrame {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
Self::TYPE.encode(writer, ())?;
self.stream_id.encode(writer, ())?;
self.maximum_stream_data.encode(writer, ())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
if VarInt::decode(reader, ())? != Self::TYPE {
return Err(BufError::UnexpectedValue);
}
Ok(Self {
stream_id: StreamId::decode(reader, ())?,
maximum_stream_data: VarInt::decode(reader, ())?,
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct StreamsBlockedFrame {
pub maximum_streams: VarInt,
pub bidirectional: bool,
}
impl StreamsBlockedFrame {
pub const TYPE_BIDIRECTRIONAL: VarInt = VarInt::new_const(0x16);
pub const TYPE_UNIDIRECTRIONAL: VarInt = VarInt::new_const(0x17);
pub fn calculate_type(&self) -> VarInt {
match self.bidirectional {
true => Self::TYPE_BIDIRECTRIONAL,
false => Self::TYPE_UNIDIRECTRIONAL,
}
}
}
impl Codec for StreamsBlockedFrame {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
self.calculate_type().encode(writer, ())?;
self.maximum_streams.encode(writer, ())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
let bidirectional = match VarInt::decode(reader, ())? {
Self::TYPE_BIDIRECTRIONAL => true,
Self::TYPE_UNIDIRECTRIONAL => false,
_ => return Err(BufError::UnexpectedValue),
};
let maximum_streams = VariableLengthInteger::decode(reader, ())?;
Ok(Self {
maximum_streams,
bidirectional,
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct NewConnectionIdFrame {
pub sequence_number: VarInt,
pub retire_prior_to: VarInt,
pub connection_id: ConnectionId,
pub stateless_reset_token: [u8; 16],
}
impl NewConnectionIdFrame {
pub const TYPE: VarInt = VariableLengthInteger(FrameType::NewConnectionId as u64);
}
impl Codec for NewConnectionIdFrame {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
Self::TYPE.encode(writer, ())?;
self.sequence_number.encode(writer, ())?;
self.retire_prior_to.encode(writer, ())?;
self.connection_id.encode(writer, ())?;
self.stateless_reset_token.encode(writer, ())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
if VarInt::decode(reader, ())? != Self::TYPE {
return Err(BufError::UnexpectedValue);
}
Ok(Self {
sequence_number: VarInt::decode(reader, ())?,
retire_prior_to: VarInt::decode(reader, ())?,
connection_id: ConnectionId::decode(reader, ())?,
stateless_reset_token: reader.read_array::<16>()?,
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct RetireConnectionIdFrame {
pub sequence_number: VarInt,
}
impl RetireConnectionIdFrame {
pub const TYPE: VarInt = VariableLengthInteger(FrameType::RetireConnectionId as u64);
}
impl Codec for RetireConnectionIdFrame {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
Self::TYPE.encode(writer, ())?;
self.sequence_number.encode(writer, ())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
if VarInt::decode(reader, ())? != Self::TYPE {
return Err(BufError::UnexpectedValue);
}
Ok(Self {
sequence_number: VarInt::decode(reader, ())?,
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct PathChallengeFrame {
pub data: [u8; 8],
}
impl PathChallengeFrame {
pub const TYPE: VarInt = VariableLengthInteger(FrameType::PathChallenge as u64);
}
impl Codec for PathChallengeFrame {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
Self::TYPE.encode(writer, ())?;
self.data.encode(writer, ())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
if VarInt::decode(reader, ())? != Self::TYPE {
return Err(BufError::UnexpectedValue);
}
Ok(Self {
data: reader.read_array::<8>()?,
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct PathResponseFrame {
pub data: [u8; 8],
}
impl PathResponseFrame {
pub const TYPE: VarInt = VariableLengthInteger(FrameType::PathResponse as u64);
}
impl Codec for PathResponseFrame {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
Self::TYPE.encode(writer, ())?;
self.data.encode(writer, ())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
if VarInt::decode(reader, ())? != Self::TYPE {
return Err(BufError::UnexpectedValue);
}
Ok(Self {
data: reader.read_array::<8>()?,
})
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ConnectionCloseFrame {
pub error_code: VarInt,
pub frame_type: Option<VarInt>,
pub reason_phrase: Vec<u8>,
}
impl ConnectionCloseFrame {
pub const TYPE_QUIC: VarInt = VarInt::new_const(0x1c);
pub const TYPE_APPLICATION: VarInt = VarInt::new_const(0x1d);
pub fn calculate_type(&self) -> VarInt {
match self.frame_type {
Some(_) => Self::TYPE_QUIC,
None => Self::TYPE_APPLICATION,
}
}
}
impl Codec for ConnectionCloseFrame {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
self.calculate_type().encode(writer, ())?;
self.error_code.encode(writer, ())?;
match self.frame_type {
Some(frame_type) => frame_type.encode(writer, ()),
None => Ok(()),
}?;
(VarInt::new(self.reason_phrase.len() as u64)?).encode(writer, ())?;
self.reason_phrase.encode(writer, ())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
let r#type = (VarInt::decode(reader, ())?).0;
let error_code = VarInt::decode(reader, ())?;
let frame_type = match r#type {
0x1d => None,
0x1c => Some(VarInt::decode(reader, ())?),
_ => return Err(BufError::UnexpectedValue),
};
let reason_phrase_length = (VarInt::decode(reader, ())?).0;
let mut reason_phrase = [0u8; 1400];
let mut reason_phrase = &mut reason_phrase[..reason_phrase_length as usize];
reader.read_into(&mut reason_phrase)?;
let reason_phrase = reason_phrase.to_vec();
Ok(Self {
error_code,
frame_type,
reason_phrase,
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(u64)]
pub enum TransportErrorCode {
NoError = 0x00,
InternalError = 0x01,
ConnectionRefused = 0x02,
FlowControlError = 0x03,
StreamLimitError = 0x04,
StreamStateError = 0x05,
FinalSizeError = 0x06,
FrameEncodingError = 0x07,
TransportParameterError = 0x08,
ConnectionIdLimitError = 0x09,
ProtocolViolation = 0x0a,
InvalidToken = 0x0b,
ApplicationError = 0x0c,
CryptoBufferExceeded = 0x0d,
KeyUpdateError = 0x0e,
AeadLimitReached = 0x0f,
NoViablePath = 0x10,
CryptoError = 0x0100,
}
impl From<TransportErrorCode> for VarInt {
fn from(value: TransportErrorCode) -> Self {
Self(value as u64)
}
}
impl TryFrom<VarInt> for TransportErrorCode {
type Error = BufError;
fn try_from(value: VarInt) -> Result<Self, Self::Error> {
Self::try_from(value.into_inner())
}
}
impl From<TransportErrorCode> for u64 {
fn from(value: TransportErrorCode) -> Self {
value as u64
}
}
impl TryFrom<u64> for TransportErrorCode {
type Error = BufError;
fn try_from(value: u64) -> Result<Self, Self::Error> {
match value {
x if x == Self::NoError as u64 => Ok(Self::NoError),
x if x == Self::InternalError as u64 => Ok(Self::InternalError),
x if x == Self::ConnectionRefused as u64 => Ok(Self::ConnectionRefused),
x if x == Self::FlowControlError as u64 => Ok(Self::FlowControlError),
x if x == Self::StreamLimitError as u64 => Ok(Self::StreamLimitError),
x if x == Self::StreamStateError as u64 => Ok(Self::StreamStateError),
x if x == Self::FinalSizeError as u64 => Ok(Self::FinalSizeError),
x if x == Self::FrameEncodingError as u64 => Ok(Self::FrameEncodingError),
x if x == Self::TransportParameterError as u64 => Ok(Self::TransportParameterError),
x if x == Self::ConnectionIdLimitError as u64 => Ok(Self::ConnectionIdLimitError),
x if x == Self::ProtocolViolation as u64 => Ok(Self::ProtocolViolation),
x if x == Self::InvalidToken as u64 => Ok(Self::InvalidToken),
x if x == Self::ApplicationError as u64 => Ok(Self::ApplicationError),
x if x == Self::CryptoBufferExceeded as u64 => Ok(Self::CryptoBufferExceeded),
x if x == Self::KeyUpdateError as u64 => Ok(Self::KeyUpdateError),
x if x == Self::AeadLimitReached as u64 => Ok(Self::AeadLimitReached),
x if x == Self::NoViablePath as u64 => Ok(Self::NoViablePath),
x if x >= Self::CryptoError as u64 && x <= 0x01ff => Ok(Self::CryptoError),
_ => Err(BufError::UnexpectedValue),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct HandshakeDoneFrame;
impl HandshakeDoneFrame {
pub const TYPE: VarInt = VariableLengthInteger(FrameType::HandshakeDone as u64);
}
impl Codec for HandshakeDoneFrame {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
Self::TYPE.encode(writer, ())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
if VarInt::decode(reader, ())? != Self::TYPE {
return Err(BufError::UnexpectedValue);
}
Ok(Self {})
}
}
#[cfg(test)]
mod tests {
use core::fmt::Debug;
use crate::{
Codec, Cursor,
ietf::quicv1::{
AckFrame, AckRange, ConnectionCloseFrame, ConnectionId, CryptoFrame, DataBlockedFrame,
EcnCounts, HandshakeDoneFrame, MaxDataFrame, MaxStreamDataFrame, MaxStreamsFrame,
NewConnectionIdFrame, NewTokenFrame, PaddingFrame, PathChallengeFrame,
PathResponseFrame, PingFrame, ResetStreamFrame, RetireConnectionIdFrame, RetryToken,
StopSendingFrame, StreamDataBlockedFrame, StreamFrame, StreamId, StreamsBlockedFrame,
VariableLengthInteger,
},
};
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 padding() {
let etalon_bytes = &[0x00];
let etalon_struct = PaddingFrame {};
codec_roundtrip(etalon_struct, etalon_bytes, ());
}
#[test]
fn ping() {
let etalon_bytes = &[0x01];
let etalon_struct = PingFrame {};
codec_roundtrip(etalon_struct, etalon_bytes, ());
}
#[test]
fn ack() {
let etalon_bytes = &[0x02, 0x05, 0x00, 0x01, 0x01, 0x00, 0x00];
let etalon_struct = AckFrame {
largest_acknowledged: VariableLengthInteger(5),
ack_delay: VariableLengthInteger(0),
first_ack_range: VariableLengthInteger(1),
ack_ranges: vec![AckRange {
gap: VariableLengthInteger(0),
ack_range_length: VariableLengthInteger(0),
}],
ecn_counts: None,
};
codec_roundtrip(etalon_struct, etalon_bytes, ());
let etalon_bytes = &[0x03, 0x05, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00];
let etalon_struct = AckFrame {
largest_acknowledged: VariableLengthInteger(5),
ack_delay: VariableLengthInteger(0),
first_ack_range: VariableLengthInteger(1),
ack_ranges: vec![AckRange {
gap: VariableLengthInteger(0),
ack_range_length: VariableLengthInteger(0),
}],
ecn_counts: Some(EcnCounts {
ect0_count: VariableLengthInteger(0),
ect1_count: VariableLengthInteger(0),
ecn_ce_count: VariableLengthInteger(0),
}),
};
codec_roundtrip(etalon_struct, etalon_bytes, ());
}
#[test]
fn reset_stream() {
let etalon_bytes = &[0x04, 0x00, 0x00, 0x00];
let etalon_struct = ResetStreamFrame {
stream_id: StreamId(VariableLengthInteger::new_const(0)),
application_protocol_error_code: VariableLengthInteger::new_const(0),
final_size: VariableLengthInteger::new_const(0),
};
codec_roundtrip(etalon_struct, etalon_bytes, ());
}
#[test]
fn stop_sending() {
let etalon_bytes = &[0x05, 0x00, 0x00];
let etalon_struct = StopSendingFrame {
stream_id: StreamId(VariableLengthInteger::new_const(0)),
application_protocol_error_code: VariableLengthInteger::new_const(0),
};
codec_roundtrip(etalon_struct, etalon_bytes, ());
}
#[test]
fn crypto() {
let etalon_bytes = &[0x06, 0x00, 0x03, 0x40, 0x40, 0x40];
let etalon_struct = CryptoFrame {
offset: VariableLengthInteger(0),
crypto_data: vec![0x40, 0x40, 0x40],
};
codec_roundtrip(etalon_struct, etalon_bytes, ());
}
#[test]
fn new_token() {
let etalon_bytes = &[0x07, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05];
let etalon_struct = NewTokenFrame {
token: RetryToken(vec![0x05, 0x05, 0x05, 0x05, 0x05]),
};
codec_roundtrip(etalon_struct, etalon_bytes, ());
}
#[test]
fn stream() {
let etalon_bytes = &[0x08, 0x00, 0x00];
let etalon_struct = StreamFrame {
stream_id: StreamId(VariableLengthInteger(0)),
offset: None,
length: None,
fin: false,
stream_data: vec![0x00],
};
codec_roundtrip(etalon_struct, etalon_bytes, ());
let etalon_bytes = &[0x0c, 0x00, 0x00, 0x00];
let etalon_struct = StreamFrame {
stream_id: StreamId(VariableLengthInteger(0)),
offset: Some(VariableLengthInteger::new_const(0)),
length: None,
fin: false,
stream_data: vec![0x00],
};
codec_roundtrip(etalon_struct, etalon_bytes, ());
let etalon_bytes = &[0x0a, 0x00, 0x01, 0x00];
let etalon_struct = StreamFrame {
stream_id: StreamId(VariableLengthInteger(0)),
offset: None,
length: Some(VariableLengthInteger::new_const(1)),
fin: false,
stream_data: vec![0x00],
};
codec_roundtrip(etalon_struct, etalon_bytes, ());
let etalon_bytes = &[0x09, 0x00, 0x00];
let etalon_struct = StreamFrame {
stream_id: StreamId(VariableLengthInteger(0)),
offset: None,
length: None,
fin: true,
stream_data: vec![0x00],
};
codec_roundtrip(etalon_struct, etalon_bytes, ());
let etalon_bytes = &[0x0e, 0x00, 0x00, 0x01, 0x00];
let etalon_struct = StreamFrame {
stream_id: StreamId(VariableLengthInteger(0)),
offset: Some(VariableLengthInteger::new_const(0)),
length: Some(VariableLengthInteger::new_const(1)),
fin: false,
stream_data: vec![0x00],
};
codec_roundtrip(etalon_struct, etalon_bytes, ());
let etalon_bytes = &[0x0d, 0x00, 0x00, 0x00];
let etalon_struct = StreamFrame {
stream_id: StreamId(VariableLengthInteger(0)),
offset: Some(VariableLengthInteger::new_const(0)),
length: None,
fin: true,
stream_data: vec![0x00],
};
codec_roundtrip(etalon_struct, etalon_bytes, ());
let etalon_bytes = &[0x0f, 0x00, 0x00, 0x01, 0x00];
let etalon_struct = StreamFrame {
stream_id: StreamId(VariableLengthInteger(0)),
offset: Some(VariableLengthInteger::new_const(0)),
length: Some(VariableLengthInteger::new_const(1)),
fin: true,
stream_data: vec![0x00],
};
codec_roundtrip(etalon_struct, etalon_bytes, ());
}
#[test]
fn max_data() {
let etalon_bytes = &[0x10, 0x00];
let etalon_struct = MaxDataFrame {
maximum_data: VariableLengthInteger::new_const(0),
};
codec_roundtrip(etalon_struct, etalon_bytes, ());
}
#[test]
fn max_stream_data() {
let etalon_bytes = &[0x11, 0x00, 0x00];
let etalon_struct = MaxStreamDataFrame {
stream_id: StreamId(VariableLengthInteger::new_const(0)),
maximum_stream_data: VariableLengthInteger::new_const(0),
};
codec_roundtrip(etalon_struct, etalon_bytes, ());
}
#[test]
fn max_streams() {
let etalon_bytes = &[0x12, 0x00];
let etalon_struct = MaxStreamsFrame {
maximum_streams: VariableLengthInteger::new_const(0),
bidirectional: true,
};
codec_roundtrip(etalon_struct, etalon_bytes, ());
let etalon_bytes = &[0x13, 0x00];
let etalon_struct = MaxStreamsFrame {
maximum_streams: VariableLengthInteger::new_const(0),
bidirectional: false,
};
codec_roundtrip(etalon_struct, etalon_bytes, ());
}
#[test]
fn data_blocked() {
let etalon_bytes = &[0x14, 0x00];
let etalon_struct = DataBlockedFrame {
maximum_data: VariableLengthInteger::new_const(0),
};
codec_roundtrip(etalon_struct, etalon_bytes, ());
}
#[test]
fn stream_data_blocked() {
let etalon_bytes = &[0x15, 0x00, 0x00];
let etalon_struct = StreamDataBlockedFrame {
stream_id: StreamId(VariableLengthInteger::new_const(0)),
maximum_stream_data: VariableLengthInteger::new_const(0),
};
codec_roundtrip(etalon_struct, etalon_bytes, ());
}
#[test]
fn streams_blocked() {
let etalon_bytes = &[0x16, 0x00];
let etalon_struct = StreamsBlockedFrame {
maximum_streams: VariableLengthInteger(0),
bidirectional: true,
};
codec_roundtrip(etalon_struct, etalon_bytes, ());
let etalon_bytes = &[0x17, 0x00];
let etalon_struct = StreamsBlockedFrame {
maximum_streams: VariableLengthInteger(0),
bidirectional: false,
};
codec_roundtrip(etalon_struct, etalon_bytes, ());
}
#[test]
fn new_connection_id() {
let etalon_bytes = &[
0x018, 0x01, 0x02, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x10, 0x10,
0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
];
let etalon_struct = NewConnectionIdFrame {
sequence_number: VariableLengthInteger(1),
retire_prior_to: VariableLengthInteger(2),
connection_id: ConnectionId::new(&[0x08; 8]).unwrap(),
stateless_reset_token: [16u8; 16],
};
codec_roundtrip(etalon_struct, etalon_bytes, ());
}
#[test]
fn retire_connection_id() {
let etalon_bytes = &[0x19, 0x00];
let etalon_struct = RetireConnectionIdFrame {
sequence_number: VariableLengthInteger(0),
};
codec_roundtrip(etalon_struct, etalon_bytes, ());
}
#[test]
fn path_challenge() {
let etalon_bytes = &[0x1A, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11];
let etalon_struct = PathChallengeFrame { data: [0x11u8; 8] };
codec_roundtrip(etalon_struct, etalon_bytes, ());
}
#[test]
fn path_response() {
let etalon_bytes = &[0x1B, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13];
let etalon_struct = PathResponseFrame { data: [0x13u8; 8] };
codec_roundtrip(etalon_struct, etalon_bytes, ());
}
#[test]
fn connection_close() {
let etalon_bytes = &[
0x1c, 0x14, 0x06, 0x14, 50, 49, 55, 58, 72, 97, 110, 100, 115, 104, 97, 107, 101, 32,
102, 97, 105, 108, 101, 100,
];
let etalon_struct = ConnectionCloseFrame {
error_code: VariableLengthInteger(0x14),
frame_type: Some(VariableLengthInteger(0x06)),
reason_phrase: b"217:Handshake failed".to_vec(),
};
codec_roundtrip(etalon_struct, etalon_bytes, ());
let etalon_bytes = &[
0x1d, 0x14, 0x14, 50, 49, 55, 58, 72, 97, 110, 100, 115, 104, 97, 107, 101, 32, 102,
97, 105, 108, 101, 100,
];
let etalon_struct = ConnectionCloseFrame {
error_code: VariableLengthInteger(0x14),
frame_type: None,
reason_phrase: b"217:Handshake failed".to_vec(),
};
codec_roundtrip(etalon_struct, etalon_bytes, ());
}
#[test]
fn handshake_done() {
let etalon_bytes = &[0x1E];
let etalon_struct = HandshakeDoneFrame {};
codec_roundtrip(etalon_struct, etalon_bytes, ());
}
}