// Licensed under the Apache License, Version 2.0 or the MIT license // , 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 { fn frame_type_bit(self) -> u64 { match self { Self::Transport(_) => 0, Self::Application(_) => 1, } } fn from_type_bit(bit: u64, code: u64) -> Self { if (bit & 0x01) == 0 { Self::Transport(code) } else { Self::Application(code) } } #[must_use] pub fn code(&self) -> u64 { match self { Self::Transport(c) | Self::Application(c) => *c, } } } impl From for CloseError { fn from(err: CloseReason) -> Self { match err { CloseReason::Transport(c) => Self::Transport(c.code()), CloseReason::Application(c) => Self::Application(c), } } } impl From 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, ecn_count: Option, }, 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> { fn get_stream_type_bit(stream_type: StreamType) -> u64 { match stream_type { StreamType::BiDi => 0, StreamType::UniDi => 1, } } fn stream_type_from_bit(bit: u64) -> StreamType { if (bit & 0x01) == 0 { StreamType::BiDi } else { StreamType::UniDi } } #[must_use] pub 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 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 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 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 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>> { 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 { /// 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(v: Option) -> Res { v.ok_or(Error::NoMoreData) } fn dv(dec: &mut Decoder) -> Res { d(dec.decode_varint()) } fn decode_ack<'a>(dec: &mut Decoder<'a>, ecn: bool) -> Res> { 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 = 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 test_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"); } }