Revision control

Copy as Markdown

Other Tools

// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Directly relating to QUIC frames.
use std::ops::RangeInclusive;
use neqo_common::{qtrace, Decoder, Encoder};
use crate::{
cid::MAX_CONNECTION_ID_LEN,
ecn::EcnCount,
packet::PacketType,
stream_id::{StreamId, StreamType},
AppError, CloseReason, Error, Res, TransportError,
};
#[allow(clippy::module_name_repetitions)]
pub type FrameType = u64;
pub const FRAME_TYPE_PADDING: FrameType = 0x0;
pub const FRAME_TYPE_PING: FrameType = 0x1;
pub const FRAME_TYPE_ACK: FrameType = 0x2;
pub const FRAME_TYPE_ACK_ECN: FrameType = 0x3;
pub const FRAME_TYPE_RESET_STREAM: FrameType = 0x4;
pub const FRAME_TYPE_STOP_SENDING: FrameType = 0x5;
pub const FRAME_TYPE_CRYPTO: FrameType = 0x6;
pub const FRAME_TYPE_NEW_TOKEN: FrameType = 0x7;
const FRAME_TYPE_STREAM: FrameType = 0x8;
const FRAME_TYPE_STREAM_MAX: FrameType = 0xf;
pub const FRAME_TYPE_MAX_DATA: FrameType = 0x10;
pub const FRAME_TYPE_MAX_STREAM_DATA: FrameType = 0x11;
pub const FRAME_TYPE_MAX_STREAMS_BIDI: FrameType = 0x12;
pub const FRAME_TYPE_MAX_STREAMS_UNIDI: FrameType = 0x13;
pub const FRAME_TYPE_DATA_BLOCKED: FrameType = 0x14;
pub const FRAME_TYPE_STREAM_DATA_BLOCKED: FrameType = 0x15;
pub const FRAME_TYPE_STREAMS_BLOCKED_BIDI: FrameType = 0x16;
pub const FRAME_TYPE_STREAMS_BLOCKED_UNIDI: FrameType = 0x17;
pub const FRAME_TYPE_NEW_CONNECTION_ID: FrameType = 0x18;
pub const FRAME_TYPE_RETIRE_CONNECTION_ID: FrameType = 0x19;
pub const FRAME_TYPE_PATH_CHALLENGE: FrameType = 0x1a;
pub const FRAME_TYPE_PATH_RESPONSE: FrameType = 0x1b;
pub const FRAME_TYPE_CONNECTION_CLOSE_TRANSPORT: FrameType = 0x1c;
pub const FRAME_TYPE_CONNECTION_CLOSE_APPLICATION: FrameType = 0x1d;
pub const FRAME_TYPE_HANDSHAKE_DONE: FrameType = 0x1e;
// draft-ietf-quic-ack-delay
pub const FRAME_TYPE_ACK_FREQUENCY: FrameType = 0xaf;
// draft-ietf-quic-datagram
pub const FRAME_TYPE_DATAGRAM: FrameType = 0x30;
pub const FRAME_TYPE_DATAGRAM_WITH_LEN: FrameType = 0x31;
const DATAGRAM_FRAME_BIT_LEN: u64 = 0x01;
const STREAM_FRAME_BIT_FIN: u64 = 0x01;
const STREAM_FRAME_BIT_LEN: u64 = 0x02;
const STREAM_FRAME_BIT_OFF: u64 = 0x04;
#[derive(PartialEq, Eq, Debug, PartialOrd, Ord, Clone, Copy)]
pub enum CloseError {
Transport(TransportError),
Application(AppError),
}
impl CloseError {
const fn frame_type_bit(self) -> u64 {
match self {
Self::Transport(_) => 0,
Self::Application(_) => 1,
}
}
const fn from_type_bit(bit: u64, code: u64) -> Self {
if (bit & 0x01) == 0 {
Self::Transport(code)
} else {
Self::Application(code)
}
}
#[must_use]
pub const fn code(&self) -> u64 {
match self {
Self::Transport(c) | Self::Application(c) => *c,
}
}
}
impl From<CloseReason> for CloseError {
fn from(err: CloseReason) -> Self {
match err {
CloseReason::Transport(c) => Self::Transport(c.code()),
CloseReason::Application(c) => Self::Application(c),
}
}
}
impl From<std::array::TryFromSliceError> for Error {
fn from(_err: std::array::TryFromSliceError) -> Self {
Self::FrameEncodingError
}
}
#[derive(PartialEq, Eq, Debug, Default, Clone)]
pub struct AckRange {
pub(crate) gap: u64,
pub(crate) range: u64,
}
#[derive(PartialEq, Eq, Debug, Clone)]
pub enum Frame<'a> {
Padding(u16),
Ping,
Ack {
largest_acknowledged: u64,
ack_delay: u64,
first_ack_range: u64,
ack_ranges: Vec<AckRange>,
ecn_count: Option<EcnCount>,
},
ResetStream {
stream_id: StreamId,
application_error_code: AppError,
final_size: u64,
},
StopSending {
stream_id: StreamId,
application_error_code: AppError,
},
Crypto {
offset: u64,
data: &'a [u8],
},
NewToken {
token: &'a [u8],
},
Stream {
stream_id: StreamId,
offset: u64,
data: &'a [u8],
fin: bool,
fill: bool,
},
MaxData {
maximum_data: u64,
},
MaxStreamData {
stream_id: StreamId,
maximum_stream_data: u64,
},
MaxStreams {
stream_type: StreamType,
maximum_streams: u64,
},
DataBlocked {
data_limit: u64,
},
StreamDataBlocked {
stream_id: StreamId,
stream_data_limit: u64,
},
StreamsBlocked {
stream_type: StreamType,
stream_limit: u64,
},
NewConnectionId {
sequence_number: u64,
retire_prior: u64,
connection_id: &'a [u8],
stateless_reset_token: &'a [u8; 16],
},
RetireConnectionId {
sequence_number: u64,
},
PathChallenge {
data: [u8; 8],
},
PathResponse {
data: [u8; 8],
},
ConnectionClose {
error_code: CloseError,
frame_type: u64,
// Not a reference as we use this to hold the value.
// This is not used in optimized builds anyway.
reason_phrase: String,
},
HandshakeDone,
AckFrequency {
/// The current ACK frequency sequence number.
seqno: u64,
/// The number of contiguous packets that can be received without
/// acknowledging immediately.
tolerance: u64,
/// The time to delay after receiving the first packet that is
/// not immediately acknowledged.
delay: u64,
/// Ignore reordering when deciding to immediately acknowledge.
ignore_order: bool,
},
Datagram {
data: &'a [u8],
fill: bool,
},
}
impl<'a> Frame<'a> {
const fn get_stream_type_bit(stream_type: StreamType) -> u64 {
match stream_type {
StreamType::BiDi => 0,
StreamType::UniDi => 1,
}
}
const fn stream_type_from_bit(bit: u64) -> StreamType {
if (bit & 0x01) == 0 {
StreamType::BiDi
} else {
StreamType::UniDi
}
}
#[must_use]
pub const fn get_type(&self) -> FrameType {
match self {
Self::Padding { .. } => FRAME_TYPE_PADDING,
Self::Ping => FRAME_TYPE_PING,
Self::Ack { .. } => FRAME_TYPE_ACK,
Self::ResetStream { .. } => FRAME_TYPE_RESET_STREAM,
Self::StopSending { .. } => FRAME_TYPE_STOP_SENDING,
Self::Crypto { .. } => FRAME_TYPE_CRYPTO,
Self::NewToken { .. } => FRAME_TYPE_NEW_TOKEN,
Self::Stream {
fin, offset, fill, ..
} => Self::stream_type(*fin, *offset > 0, *fill),
Self::MaxData { .. } => FRAME_TYPE_MAX_DATA,
Self::MaxStreamData { .. } => FRAME_TYPE_MAX_STREAM_DATA,
Self::MaxStreams { stream_type, .. } => {
FRAME_TYPE_MAX_STREAMS_BIDI + Self::get_stream_type_bit(*stream_type)
}
Self::DataBlocked { .. } => FRAME_TYPE_DATA_BLOCKED,
Self::StreamDataBlocked { .. } => FRAME_TYPE_STREAM_DATA_BLOCKED,
Self::StreamsBlocked { stream_type, .. } => {
FRAME_TYPE_STREAMS_BLOCKED_BIDI + Self::get_stream_type_bit(*stream_type)
}
Self::NewConnectionId { .. } => FRAME_TYPE_NEW_CONNECTION_ID,
Self::RetireConnectionId { .. } => FRAME_TYPE_RETIRE_CONNECTION_ID,
Self::PathChallenge { .. } => FRAME_TYPE_PATH_CHALLENGE,
Self::PathResponse { .. } => FRAME_TYPE_PATH_RESPONSE,
Self::ConnectionClose { error_code, .. } => {
FRAME_TYPE_CONNECTION_CLOSE_TRANSPORT + error_code.frame_type_bit()
}
Self::HandshakeDone => FRAME_TYPE_HANDSHAKE_DONE,
Self::AckFrequency { .. } => FRAME_TYPE_ACK_FREQUENCY,
Self::Datagram { fill, .. } => {
if *fill {
FRAME_TYPE_DATAGRAM
} else {
FRAME_TYPE_DATAGRAM_WITH_LEN
}
}
}
}
#[must_use]
pub const fn is_stream(&self) -> bool {
matches!(
self,
Self::ResetStream { .. }
| Self::StopSending { .. }
| Self::Stream { .. }
| Self::MaxData { .. }
| Self::MaxStreamData { .. }
| Self::MaxStreams { .. }
| Self::DataBlocked { .. }
| Self::StreamDataBlocked { .. }
| Self::StreamsBlocked { .. }
)
}
#[must_use]
pub const fn stream_type(fin: bool, nonzero_offset: bool, fill: bool) -> u64 {
let mut t = FRAME_TYPE_STREAM;
if fin {
t |= STREAM_FRAME_BIT_FIN;
}
if nonzero_offset {
t |= STREAM_FRAME_BIT_OFF;
}
if !fill {
t |= STREAM_FRAME_BIT_LEN;
}
t
}
/// If the frame causes a recipient to generate an ACK within its
/// advertised maximum acknowledgement delay.
#[must_use]
pub const fn ack_eliciting(&self) -> bool {
!matches!(
self,
Self::Ack { .. } | Self::Padding { .. } | Self::ConnectionClose { .. }
)
}
/// If the frame can be sent in a path probe
/// without initiating migration to that path.
#[must_use]
pub const fn path_probing(&self) -> bool {
matches!(
self,
Self::Padding { .. }
| Self::NewConnectionId { .. }
| Self::PathChallenge { .. }
| Self::PathResponse { .. }
)
}
/// Converts `AckRanges` as encoded in a ACK frame (see -transport
/// 19.3.1) into ranges of acked packets (end, start), inclusive of
/// start and end values.
///
/// # Errors
///
/// Returns an error if the ranges are invalid.
pub fn decode_ack_frame(
largest_acked: u64,
first_ack_range: u64,
ack_ranges: &[AckRange],
) -> Res<Vec<RangeInclusive<u64>>> {
let mut acked_ranges = Vec::with_capacity(ack_ranges.len() + 1);
if largest_acked < first_ack_range {
return Err(Error::FrameEncodingError);
}
acked_ranges.push((largest_acked - first_ack_range)..=largest_acked);
if !ack_ranges.is_empty() && largest_acked < first_ack_range + 1 {
return Err(Error::FrameEncodingError);
}
let mut cur = if ack_ranges.is_empty() {
0
} else {
largest_acked - first_ack_range - 1
};
for r in ack_ranges {
if cur < r.gap + 1 {
return Err(Error::FrameEncodingError);
}
cur = cur - r.gap - 1;
if cur < r.range {
return Err(Error::FrameEncodingError);
}
acked_ranges.push((cur - r.range)..=cur);
if cur > r.range + 1 {
cur -= r.range + 1;
} else {
cur -= r.range;
}
}
Ok(acked_ranges)
}
#[must_use]
pub fn dump(&self) -> String {
match self {
Self::Crypto { offset, data } => {
format!("Crypto {{ offset: {}, len: {} }}", offset, data.len())
}
Self::Stream {
stream_id,
offset,
fill,
data,
fin,
} => format!(
"Stream {{ stream_id: {}, offset: {}, len: {}{}, fin: {} }}",
stream_id.as_u64(),
offset,
if *fill { ">>" } else { "" },
data.len(),
fin,
),
Self::Padding(length) => format!("Padding {{ len: {length} }}"),
Self::Datagram { data, .. } => format!("Datagram {{ len: {} }}", data.len()),
_ => format!("{self:?}"),
}
}
#[must_use]
pub fn is_allowed(&self, pt: PacketType) -> bool {
match self {
Self::Padding { .. } | Self::Ping => true,
Self::Crypto { .. }
| Self::Ack { .. }
| Self::ConnectionClose {
error_code: CloseError::Transport(_),
..
} => pt != PacketType::ZeroRtt,
Self::NewToken { .. } | Self::ConnectionClose { .. } => pt == PacketType::Short,
_ => pt == PacketType::ZeroRtt || pt == PacketType::Short,
}
}
/// # Errors
///
/// Returns an error if the frame cannot be decoded.
#[allow(clippy::too_many_lines)] // Yeah, but it's a nice match statement.
pub fn decode(dec: &mut Decoder<'a>) -> Res<Self> {
/// Maximum ACK Range Count in ACK Frame
///
/// Given a max UDP datagram size of 64k bytes and a minimum ACK Range size of 2
/// bytes (2 QUIC varints), a single datagram can at most contain 32k ACK
/// Ranges.
///
/// Note that the maximum (jumbogram) Ethernet MTU of 9216 or on the
/// Internet the regular Ethernet MTU of 1518 are more realistically to
/// be the limiting factor. Though for simplicity the higher limit is chosen.
const MAX_ACK_RANGE_COUNT: u64 = 32 * 1024;
fn d<T>(v: Option<T>) -> Res<T> {
v.ok_or(Error::NoMoreData)
}
fn dv(dec: &mut Decoder) -> Res<u64> {
d(dec.decode_varint())
}
fn decode_ack<'a>(dec: &mut Decoder<'a>, ecn: bool) -> Res<Frame<'a>> {
let la = dv(dec)?;
let ad = dv(dec)?;
let nr = dv(dec).and_then(|nr| {
if nr < MAX_ACK_RANGE_COUNT {
Ok(nr)
} else {
Err(Error::TooMuchData)
}
})?;
let fa = dv(dec)?;
let mut arr: Vec<AckRange> = Vec::with_capacity(usize::try_from(nr)?);
for _ in 0..nr {
let ar = AckRange {
gap: dv(dec)?,
range: dv(dec)?,
};
arr.push(ar);
}
// Now check for the values for ACK_ECN.
let ecn_count = if ecn {
Some(EcnCount::new(0, dv(dec)?, dv(dec)?, dv(dec)?))
} else {
None
};
Ok(Frame::Ack {
largest_acknowledged: la,
ack_delay: ad,
first_ack_range: fa,
ack_ranges: arr,
ecn_count,
})
}
// Check for minimal encoding of frame type.
let pos = dec.offset();
let t = dv(dec)?;
// RFC 9000, Section 12.4:
//
// The Frame Type field uses a variable-length integer encoding [...],
// with one exception. To ensure simple and efficient implementations of
// frame parsing, a frame type MUST use the shortest possible encoding.
if Encoder::varint_len(t) != dec.offset() - pos {
return Err(Error::ProtocolViolation);
}
match t {
FRAME_TYPE_PADDING => {
let mut length: u16 = 1;
while let Some(b) = dec.peek_byte() {
if u64::from(b) != FRAME_TYPE_PADDING {
break;
}
length += 1;
dec.skip(1);
}
Ok(Self::Padding(length))
}
FRAME_TYPE_PING => Ok(Self::Ping),
FRAME_TYPE_RESET_STREAM => Ok(Self::ResetStream {
stream_id: StreamId::from(dv(dec)?),
application_error_code: dv(dec)?,
final_size: match dec.decode_varint() {
Some(v) => v,
_ => return Err(Error::NoMoreData),
},
}),
FRAME_TYPE_ACK => decode_ack(dec, false),
FRAME_TYPE_ACK_ECN => decode_ack(dec, true),
FRAME_TYPE_STOP_SENDING => Ok(Self::StopSending {
stream_id: StreamId::from(dv(dec)?),
application_error_code: dv(dec)?,
}),
FRAME_TYPE_CRYPTO => {
let offset = dv(dec)?;
let data = d(dec.decode_vvec())?;
if offset + u64::try_from(data.len())? > ((1 << 62) - 1) {
return Err(Error::FrameEncodingError);
}
Ok(Self::Crypto { offset, data })
}
FRAME_TYPE_NEW_TOKEN => {
let token = d(dec.decode_vvec())?;
if token.is_empty() {
return Err(Error::FrameEncodingError);
}
Ok(Self::NewToken { token })
}
FRAME_TYPE_STREAM..=FRAME_TYPE_STREAM_MAX => {
let s = dv(dec)?;
let o = if t & STREAM_FRAME_BIT_OFF == 0 {
0
} else {
dv(dec)?
};
let fill = (t & STREAM_FRAME_BIT_LEN) == 0;
let data = if fill {
qtrace!("STREAM frame, extends to the end of the packet");
dec.decode_remainder()
} else {
qtrace!("STREAM frame, with length");
d(dec.decode_vvec())?
};
if o + u64::try_from(data.len())? > ((1 << 62) - 1) {
return Err(Error::FrameEncodingError);
}
Ok(Self::Stream {
fin: (t & STREAM_FRAME_BIT_FIN) != 0,
stream_id: StreamId::from(s),
offset: o,
data,
fill,
})
}
FRAME_TYPE_MAX_DATA => Ok(Self::MaxData {
maximum_data: dv(dec)?,
}),
FRAME_TYPE_MAX_STREAM_DATA => Ok(Self::MaxStreamData {
stream_id: StreamId::from(dv(dec)?),
maximum_stream_data: dv(dec)?,
}),
FRAME_TYPE_MAX_STREAMS_BIDI | FRAME_TYPE_MAX_STREAMS_UNIDI => {
let m = dv(dec)?;
if m > (1 << 60) {
return Err(Error::StreamLimitError);
}
Ok(Self::MaxStreams {
stream_type: Self::stream_type_from_bit(t),
maximum_streams: m,
})
}
FRAME_TYPE_DATA_BLOCKED => Ok(Self::DataBlocked {
data_limit: dv(dec)?,
}),
FRAME_TYPE_STREAM_DATA_BLOCKED => Ok(Self::StreamDataBlocked {
stream_id: dv(dec)?.into(),
stream_data_limit: dv(dec)?,
}),
FRAME_TYPE_STREAMS_BLOCKED_BIDI | FRAME_TYPE_STREAMS_BLOCKED_UNIDI => {
Ok(Self::StreamsBlocked {
stream_type: Self::stream_type_from_bit(t),
stream_limit: dv(dec)?,
})
}
FRAME_TYPE_NEW_CONNECTION_ID => {
let sequence_number = dv(dec)?;
let retire_prior = dv(dec)?;
let connection_id = d(dec.decode_vec(1))?;
if connection_id.len() > MAX_CONNECTION_ID_LEN {
return Err(Error::DecodingFrame);
}
let srt = d(dec.decode(16))?;
let stateless_reset_token = <&[_; 16]>::try_from(srt)?;
Ok(Self::NewConnectionId {
sequence_number,
retire_prior,
connection_id,
stateless_reset_token,
})
}
FRAME_TYPE_RETIRE_CONNECTION_ID => Ok(Self::RetireConnectionId {
sequence_number: dv(dec)?,
}),
FRAME_TYPE_PATH_CHALLENGE => {
let data = d(dec.decode(8))?;
let mut datav: [u8; 8] = [0; 8];
datav.copy_from_slice(data);
Ok(Self::PathChallenge { data: datav })
}
FRAME_TYPE_PATH_RESPONSE => {
let data = d(dec.decode(8))?;
let mut datav: [u8; 8] = [0; 8];
datav.copy_from_slice(data);
Ok(Self::PathResponse { data: datav })
}
FRAME_TYPE_CONNECTION_CLOSE_TRANSPORT | FRAME_TYPE_CONNECTION_CLOSE_APPLICATION => {
let error_code = CloseError::from_type_bit(t, dv(dec)?);
let frame_type = if t == FRAME_TYPE_CONNECTION_CLOSE_TRANSPORT {
dv(dec)?
} else {
0
};
// We can tolerate this copy for now.
let reason_phrase = String::from_utf8_lossy(d(dec.decode_vvec())?).to_string();
Ok(Self::ConnectionClose {
error_code,
frame_type,
reason_phrase,
})
}
FRAME_TYPE_HANDSHAKE_DONE => Ok(Self::HandshakeDone),
FRAME_TYPE_ACK_FREQUENCY => {
let seqno = dv(dec)?;
let tolerance = dv(dec)?;
if tolerance == 0 {
return Err(Error::FrameEncodingError);
}
let delay = dv(dec)?;
let ignore_order = match d(dec.decode_uint(1))? {
0 => false,
1 => true,
_ => return Err(Error::FrameEncodingError),
};
Ok(Self::AckFrequency {
seqno,
tolerance,
delay,
ignore_order,
})
}
FRAME_TYPE_DATAGRAM | FRAME_TYPE_DATAGRAM_WITH_LEN => {
let fill = (t & DATAGRAM_FRAME_BIT_LEN) == 0;
let data = if fill {
qtrace!("DATAGRAM frame, extends to the end of the packet");
dec.decode_remainder()
} else {
qtrace!("DATAGRAM frame, with length");
d(dec.decode_vvec())?
};
Ok(Self::Datagram { data, fill })
}
_ => Err(Error::UnknownFrameType),
}
}
}
#[cfg(test)]
mod tests {
use neqo_common::{Decoder, Encoder};
use crate::{
cid::MAX_CONNECTION_ID_LEN,
ecn::EcnCount,
frame::{AckRange, Frame, FRAME_TYPE_ACK},
CloseError, Error, StreamId, StreamType,
};
fn just_dec(f: &Frame, s: &str) {
let encoded = Encoder::from_hex(s);
let decoded = Frame::decode(&mut encoded.as_decoder()).expect("Failed to decode frame");
assert_eq!(*f, decoded);
}
#[test]
fn padding() {
let f = Frame::Padding(1);
just_dec(&f, "00");
let f = Frame::Padding(2);
just_dec(&f, "0000");
}
#[test]
fn ping() {
let f = Frame::Ping;
just_dec(&f, "01");
}
#[test]
fn ack() {
let ar = vec![AckRange { gap: 1, range: 2 }, AckRange { gap: 3, range: 4 }];
let f = Frame::Ack {
largest_acknowledged: 0x1234,
ack_delay: 0x1235,
first_ack_range: 0x1236,
ack_ranges: ar.clone(),
ecn_count: None,
};
just_dec(&f, "025234523502523601020304");
// Try to parse ACK_ECN without ECN values
let enc = Encoder::from_hex("035234523502523601020304");
let mut dec = enc.as_decoder();
assert_eq!(Frame::decode(&mut dec).unwrap_err(), Error::NoMoreData);
// Try to parse ACK_ECN with ECN values
let ecn_count = Some(EcnCount::new(0, 1, 2, 3));
let fe = Frame::Ack {
largest_acknowledged: 0x1234,
ack_delay: 0x1235,
first_ack_range: 0x1236,
ack_ranges: ar,
ecn_count,
};
let enc = Encoder::from_hex("035234523502523601020304010203");
let mut dec = enc.as_decoder();
assert_eq!(Frame::decode(&mut dec).unwrap(), fe);
}
#[test]
fn reset_stream() {
let f = Frame::ResetStream {
stream_id: StreamId::from(0x1234),
application_error_code: 0x77,
final_size: 0x3456,
};
just_dec(&f, "04523440777456");
}
#[test]
fn stop_sending() {
let f = Frame::StopSending {
stream_id: StreamId::from(63),
application_error_code: 0x77,
};
just_dec(&f, "053F4077");
}
#[test]
fn crypto() {
let f = Frame::Crypto {
offset: 1,
data: &[1, 2, 3],
};
just_dec(&f, "060103010203");
}
#[test]
fn new_token() {
let f = Frame::NewToken {
token: &[0x12, 0x34, 0x56],
};
just_dec(&f, "0703123456");
}
#[test]
fn empty_new_token() {
let mut dec = Decoder::from(&[0x07, 0x00][..]);
assert_eq!(
Frame::decode(&mut dec).unwrap_err(),
Error::FrameEncodingError
);
}
#[test]
fn stream() {
// First, just set the length bit.
let f = Frame::Stream {
fin: false,
stream_id: StreamId::from(5),
offset: 0,
data: &[1, 2, 3],
fill: false,
};
just_dec(&f, "0a0503010203");
// Now with offset != 0 and FIN
let f = Frame::Stream {
fin: true,
stream_id: StreamId::from(5),
offset: 1,
data: &[1, 2, 3],
fill: false,
};
just_dec(&f, "0f050103010203");
// Now to fill the packet.
let f = Frame::Stream {
fin: true,
stream_id: StreamId::from(5),
offset: 0,
data: &[1, 2, 3],
fill: true,
};
just_dec(&f, "0905010203");
}
#[test]
fn max_data() {
let f = Frame::MaxData {
maximum_data: 0x1234,
};
just_dec(&f, "105234");
}
#[test]
fn max_stream_data() {
let f = Frame::MaxStreamData {
stream_id: StreamId::from(5),
maximum_stream_data: 0x1234,
};
just_dec(&f, "11055234");
}
#[test]
fn max_streams() {
let mut f = Frame::MaxStreams {
stream_type: StreamType::BiDi,
maximum_streams: 0x1234,
};
just_dec(&f, "125234");
f = Frame::MaxStreams {
stream_type: StreamType::UniDi,
maximum_streams: 0x1234,
};
just_dec(&f, "135234");
}
#[test]
fn data_blocked() {
let f = Frame::DataBlocked { data_limit: 0x1234 };
just_dec(&f, "145234");
}
#[test]
fn stream_data_blocked() {
let f = Frame::StreamDataBlocked {
stream_id: StreamId::from(5),
stream_data_limit: 0x1234,
};
just_dec(&f, "15055234");
}
#[test]
fn streams_blocked() {
let mut f = Frame::StreamsBlocked {
stream_type: StreamType::BiDi,
stream_limit: 0x1234,
};
just_dec(&f, "165234");
f = Frame::StreamsBlocked {
stream_type: StreamType::UniDi,
stream_limit: 0x1234,
};
just_dec(&f, "175234");
}
#[test]
fn new_connection_id() {
let f = Frame::NewConnectionId {
sequence_number: 0x1234,
retire_prior: 0,
connection_id: &[0x01, 0x02],
stateless_reset_token: &[9; 16],
};
just_dec(&f, "1852340002010209090909090909090909090909090909");
}
#[test]
fn too_large_new_connection_id() {
let mut enc = Encoder::from_hex("18523400"); // up to the CID
enc.encode_vvec(&[0x0c; MAX_CONNECTION_ID_LEN + 10]);
enc.encode(&[0x11; 16][..]);
assert_eq!(
Frame::decode(&mut enc.as_decoder()).unwrap_err(),
Error::DecodingFrame
);
}
#[test]
fn retire_connection_id() {
let f = Frame::RetireConnectionId {
sequence_number: 0x1234,
};
just_dec(&f, "195234");
}
#[test]
fn path_challenge() {
let f = Frame::PathChallenge { data: [9; 8] };
just_dec(&f, "1a0909090909090909");
}
#[test]
fn path_response() {
let f = Frame::PathResponse { data: [9; 8] };
just_dec(&f, "1b0909090909090909");
}
#[test]
fn connection_close_transport() {
let f = Frame::ConnectionClose {
error_code: CloseError::Transport(0x5678),
frame_type: 0x1234,
reason_phrase: String::from("\x01\x02\x03"),
};
just_dec(&f, "1c80005678523403010203");
}
#[test]
fn connection_close_application() {
let f = Frame::ConnectionClose {
error_code: CloseError::Application(0x5678),
frame_type: 0,
reason_phrase: String::from("\x01\x02\x03"),
};
just_dec(&f, "1d8000567803010203");
}
#[test]
fn compare() {
let f1 = Frame::Padding(1);
let f2 = Frame::Padding(1);
let f3 = Frame::Crypto {
offset: 0,
data: &[1, 2, 3],
};
let f4 = Frame::Crypto {
offset: 0,
data: &[1, 2, 3],
};
let f5 = Frame::Crypto {
offset: 1,
data: &[1, 2, 3],
};
let f6 = Frame::Crypto {
offset: 0,
data: &[1, 2, 4],
};
assert_eq!(f1, f2);
assert_ne!(f1, f3);
assert_eq!(f3, f4);
assert_ne!(f3, f5);
assert_ne!(f3, f6);
}
#[test]
fn decode_ack_frame() {
let res = Frame::decode_ack_frame(7, 2, &[AckRange { gap: 0, range: 3 }]);
assert!(res.is_ok());
assert_eq!(res.unwrap(), vec![5..=7, 0..=3]);
}
#[test]
fn ack_frequency() {
let f = Frame::AckFrequency {
seqno: 10,
tolerance: 5,
delay: 2000,
ignore_order: true,
};
just_dec(&f, "40af0a0547d001");
}
#[test]
fn ack_frequency_ignore_error_error() {
let enc = Encoder::from_hex("40af0a0547d003"); // ignore_order of 3
assert_eq!(
Frame::decode(&mut enc.as_decoder()).unwrap_err(),
Error::FrameEncodingError
);
}
/// Hopefully this test is eventually redundant.
#[test]
fn ack_frequency_zero_packets() {
let enc = Encoder::from_hex("40af0a000101"); // packets of 0
assert_eq!(
Frame::decode(&mut enc.as_decoder()).unwrap_err(),
Error::FrameEncodingError
);
}
#[test]
fn datagram() {
// Without the length bit.
let f = Frame::Datagram {
data: &[1, 2, 3],
fill: true,
};
just_dec(&f, "30010203");
// With the length bit.
let f = Frame::Datagram {
data: &[1, 2, 3],
fill: false,
};
just_dec(&f, "3103010203");
}
#[test]
fn frame_decode_enforces_bound_on_ack_range() {
let mut e = Encoder::new();
e.encode_varint(FRAME_TYPE_ACK);
e.encode_varint(0u64); // largest acknowledged
e.encode_varint(0u64); // ACK delay
e.encode_varint(u32::MAX); // ACK range count = huge, but maybe available for allocation
assert_eq!(Err(Error::TooMuchData), Frame::decode(&mut e.as_decoder()));
}
#[test]
#[should_panic(expected = "Failed to decode frame")]
fn invalid_frame_type_len() {
let f = Frame::Datagram {
data: &[1, 2, 3],
fill: true,
};
just_dec(&f, "4030010203");
}
}