// Copyright (C) 2018-2019, Cloudflare, Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // // * Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. use crate::Error; use crate::Result; use crate::octets; use crate::packet; use crate::ranges; use crate::stream; pub const MAX_CRYPTO_OVERHEAD: usize = 8; pub const MAX_DGRAM_OVERHEAD: usize = 2; pub const MAX_STREAM_OVERHEAD: usize = 12; pub const MAX_STREAM_SIZE: u64 = 1 << 62; #[derive(Clone, PartialEq)] pub enum Frame { Padding { len: usize, }, Ping, ACK { ack_delay: u64, ranges: ranges::RangeSet, }, ResetStream { stream_id: u64, error_code: u64, final_size: u64, }, StopSending { stream_id: u64, error_code: u64, }, Crypto { data: stream::RangeBuf, }, NewToken { token: Vec, }, Stream { stream_id: u64, data: stream::RangeBuf, }, MaxData { max: u64, }, MaxStreamData { stream_id: u64, max: u64, }, MaxStreamsBidi { max: u64, }, MaxStreamsUni { max: u64, }, DataBlocked { limit: u64, }, StreamDataBlocked { stream_id: u64, limit: u64, }, StreamsBlockedBidi { limit: u64, }, StreamsBlockedUni { limit: u64, }, NewConnectionId { seq_num: u64, retire_prior_to: u64, conn_id: Vec, reset_token: Vec, }, RetireConnectionId { seq_num: u64, }, PathChallenge { data: Vec, }, PathResponse { data: Vec, }, ConnectionClose { error_code: u64, frame_type: u64, reason: Vec, }, ApplicationClose { error_code: u64, reason: Vec, }, HandshakeDone, Datagram { data: Vec, }, } impl Frame { pub fn from_bytes( b: &mut octets::Octets, pkt: packet::Type, ) -> Result { let frame_type = b.get_varint()?; // println!("GOT FRAME {:x}", frame_type); let frame = match frame_type { 0x00 => { let mut len = 1; while b.peek_u8() == Ok(0x00) { b.get_u8()?; len += 1; } Frame::Padding { len } }, 0x01 => Frame::Ping, 0x02 => parse_ack_frame(frame_type, b)?, 0x04 => Frame::ResetStream { stream_id: b.get_varint()?, error_code: b.get_varint()?, final_size: b.get_varint()?, }, 0x05 => Frame::StopSending { stream_id: b.get_varint()?, error_code: b.get_varint()?, }, 0x06 => { let offset = b.get_varint()?; let data = b.get_bytes_with_varint_length()?; let data = stream::RangeBuf::from(data.as_ref(), offset, false); Frame::Crypto { data } }, 0x07 => Frame::NewToken { token: b.get_bytes_with_varint_length()?.to_vec(), }, 0x08..=0x0f => parse_stream_frame(frame_type, b)?, 0x10 => Frame::MaxData { max: b.get_varint()?, }, 0x11 => Frame::MaxStreamData { stream_id: b.get_varint()?, max: b.get_varint()?, }, 0x12 => Frame::MaxStreamsBidi { max: b.get_varint()?, }, 0x13 => Frame::MaxStreamsUni { max: b.get_varint()?, }, 0x14 => Frame::DataBlocked { limit: b.get_varint()?, }, 0x15 => Frame::StreamDataBlocked { stream_id: b.get_varint()?, limit: b.get_varint()?, }, 0x16 => Frame::StreamsBlockedBidi { limit: b.get_varint()?, }, 0x17 => Frame::StreamsBlockedUni { limit: b.get_varint()?, }, 0x18 => Frame::NewConnectionId { seq_num: b.get_varint()?, retire_prior_to: b.get_varint()?, conn_id: b.get_bytes_with_u8_length()?.to_vec(), reset_token: b.get_bytes(16)?.to_vec(), }, 0x19 => Frame::RetireConnectionId { seq_num: b.get_varint()?, }, 0x1a => Frame::PathChallenge { data: b.get_bytes(8)?.to_vec(), }, 0x1b => Frame::PathResponse { data: b.get_bytes(8)?.to_vec(), }, 0x1c => Frame::ConnectionClose { error_code: b.get_varint()?, frame_type: b.get_varint()?, reason: b.get_bytes_with_varint_length()?.to_vec(), }, 0x1d => Frame::ApplicationClose { error_code: b.get_varint()?, reason: b.get_bytes_with_varint_length()?.to_vec(), }, 0x1e => Frame::HandshakeDone, 0x30 | 0x31 => parse_datagram_frame(frame_type, b)?, _ => return Err(Error::InvalidFrame), }; let allowed = match (pkt, &frame) { // PADDING and PING are allowed on all packet types. (_, Frame::Padding { .. }) | (_, Frame::Ping { .. }) => true, // ACK, CRYPTO, HANDSHAKE_DONE, NEW_TOKEN, PATH_RESPONSE, and // RETIRE_CONNECTION_ID can't be sent on 0-RTT packets. (packet::Type::ZeroRTT, Frame::ACK { .. }) => false, (packet::Type::ZeroRTT, Frame::Crypto { .. }) => false, (packet::Type::ZeroRTT, Frame::HandshakeDone) => false, (packet::Type::ZeroRTT, Frame::NewToken { .. }) => false, (packet::Type::ZeroRTT, Frame::PathResponse { .. }) => false, (packet::Type::ZeroRTT, Frame::RetireConnectionId { .. }) => false, (packet::Type::ZeroRTT, Frame::ConnectionClose { .. }) => false, // ACK, CRYPTO and CONNECTION_CLOSE can be sent on all other packet // types. (_, Frame::ACK { .. }) => true, (_, Frame::Crypto { .. }) => true, (_, Frame::ConnectionClose { .. }) => true, // All frames are allowed on 0-RTT and 1-RTT packets. (packet::Type::Short, _) => true, (packet::Type::ZeroRTT, _) => true, // All other cases are forbidden. (..) => false, }; if !allowed { return Err(Error::InvalidPacket); } Ok(frame) } pub fn to_bytes(&self, b: &mut octets::OctetsMut) -> Result { let before = b.cap(); match self { Frame::Padding { len } => { let mut left = *len; while left > 0 { b.put_varint(0x00)?; left -= 1; } }, Frame::Ping => { b.put_varint(0x01)?; }, Frame::ACK { ack_delay, ranges } => { b.put_varint(0x02)?; let mut it = ranges.iter().rev(); let first = it.next().unwrap(); let ack_block = (first.end - 1) - first.start; b.put_varint(first.end - 1)?; b.put_varint(*ack_delay)?; b.put_varint(it.len() as u64)?; b.put_varint(ack_block)?; let mut smallest_ack = first.start; for block in it { let gap = smallest_ack - block.end - 1; let ack_block = (block.end - 1) - block.start; b.put_varint(gap)?; b.put_varint(ack_block)?; smallest_ack = block.start; } }, Frame::ResetStream { stream_id, error_code, final_size, } => { b.put_varint(0x04)?; b.put_varint(*stream_id)?; b.put_varint(*error_code)?; b.put_varint(*final_size)?; }, Frame::StopSending { stream_id, error_code, } => { b.put_varint(0x05)?; b.put_varint(*stream_id)?; b.put_varint(*error_code)?; }, Frame::Crypto { data } => { b.put_varint(0x06)?; b.put_varint(data.off() as u64)?; b.put_varint(data.len() as u64)?; b.put_bytes(&data)?; }, Frame::NewToken { token } => { b.put_varint(0x07)?; b.put_varint(token.len() as u64)?; b.put_bytes(&token)?; }, Frame::Stream { stream_id, data } => { let mut ty: u8 = 0x08; // Always encode offset ty |= 0x04; // Always encode length ty |= 0x02; if data.fin() { ty |= 0x01; } b.put_varint(u64::from(ty))?; b.put_varint(*stream_id)?; b.put_varint(data.off() as u64)?; b.put_varint(data.len() as u64)?; b.put_bytes(data.as_ref())?; }, Frame::MaxData { max } => { b.put_varint(0x10)?; b.put_varint(*max)?; }, Frame::MaxStreamData { stream_id, max } => { b.put_varint(0x11)?; b.put_varint(*stream_id)?; b.put_varint(*max)?; }, Frame::MaxStreamsBidi { max } => { b.put_varint(0x12)?; b.put_varint(*max)?; }, Frame::MaxStreamsUni { max } => { b.put_varint(0x13)?; b.put_varint(*max)?; }, Frame::DataBlocked { limit } => { b.put_varint(0x14)?; b.put_varint(*limit)?; }, Frame::StreamDataBlocked { stream_id, limit } => { b.put_varint(0x15)?; b.put_varint(*stream_id)?; b.put_varint(*limit)?; }, Frame::StreamsBlockedBidi { limit } => { b.put_varint(0x16)?; b.put_varint(*limit)?; }, Frame::StreamsBlockedUni { limit } => { b.put_varint(0x17)?; b.put_varint(*limit)?; }, Frame::NewConnectionId { seq_num, retire_prior_to, conn_id, reset_token, } => { b.put_varint(0x18)?; b.put_varint(*seq_num)?; b.put_varint(*retire_prior_to)?; b.put_u8(conn_id.len() as u8)?; b.put_bytes(conn_id.as_ref())?; b.put_bytes(reset_token.as_ref())?; }, Frame::RetireConnectionId { seq_num } => { b.put_varint(0x19)?; b.put_varint(*seq_num)?; }, Frame::PathChallenge { data } => { b.put_varint(0x1a)?; b.put_bytes(data.as_ref())?; }, Frame::PathResponse { data } => { b.put_varint(0x1b)?; b.put_bytes(data.as_ref())?; }, Frame::ConnectionClose { error_code, frame_type, reason, } => { b.put_varint(0x1c)?; b.put_varint(*error_code)?; b.put_varint(*frame_type)?; b.put_varint(reason.len() as u64)?; b.put_bytes(reason.as_ref())?; }, Frame::ApplicationClose { error_code, reason } => { b.put_varint(0x1d)?; b.put_varint(*error_code)?; b.put_varint(reason.len() as u64)?; b.put_bytes(reason.as_ref())?; }, Frame::HandshakeDone => { b.put_varint(0x1e)?; }, Frame::Datagram { data } => { let mut ty: u8 = 0x30; // Always encode length ty |= 0x01; b.put_varint(u64::from(ty))?; b.put_varint(data.len() as u64)?; b.put_bytes(data.as_ref())?; }, } Ok(before - b.cap()) } pub fn wire_len(&self) -> usize { match self { Frame::Padding { len } => *len, Frame::Ping => 1, Frame::ACK { ack_delay, ranges } => { let mut it = ranges.iter().rev(); let first = it.next().unwrap(); let ack_block = (first.end - 1) - first.start; let mut len = 1 + // frame type octets::varint_len(first.end - 1) + // largest_ack octets::varint_len(*ack_delay) + // ack_delay octets::varint_len(it.len() as u64) + // block_count octets::varint_len(ack_block); // first_block let mut smallest_ack = first.start; for block in it { let gap = smallest_ack - block.end - 1; let ack_block = (block.end - 1) - block.start; len += octets::varint_len(gap) + // gap octets::varint_len(ack_block); // ack_block smallest_ack = block.start; } len }, Frame::ResetStream { stream_id, error_code, final_size, } => { 1 + // frame type octets::varint_len(*stream_id) + // stream_id octets::varint_len(*error_code) + // error_code octets::varint_len(*final_size) // final_size }, Frame::StopSending { stream_id, error_code, } => { 1 + // frame type octets::varint_len(*stream_id) + // stream_id octets::varint_len(*error_code) // error_code }, Frame::Crypto { data } => { 1 + // frame type octets::varint_len(data.off() as u64) + // offset octets::varint_len(data.len() as u64) + // length data.len() // data }, Frame::NewToken { token } => { 1 + // frame type octets::varint_len(token.len() as u64) + // token length token.len() // token }, Frame::Stream { stream_id, data } => { 1 + // frame type octets::varint_len(*stream_id) + // stream_id octets::varint_len(data.off() as u64) + // offset octets::varint_len(data.len() as u64) + // length data.len() // data }, Frame::MaxData { max } => { 1 + // frame type octets::varint_len(*max) // max }, Frame::MaxStreamData { stream_id, max } => { 1 + // frame type octets::varint_len(*stream_id) + // stream_id octets::varint_len(*max) // max }, Frame::MaxStreamsBidi { max } => { 1 + // frame type octets::varint_len(*max) // max }, Frame::MaxStreamsUni { max } => { 1 + // frame type octets::varint_len(*max) // max }, Frame::DataBlocked { limit } => { 1 + // frame type octets::varint_len(*limit) // limit }, Frame::StreamDataBlocked { stream_id, limit } => { 1 + // frame type octets::varint_len(*stream_id) + // stream_id octets::varint_len(*limit) // limit }, Frame::StreamsBlockedBidi { limit } => { 1 + // frame type octets::varint_len(*limit) // limit }, Frame::StreamsBlockedUni { limit } => { 1 + // frame type octets::varint_len(*limit) // limit }, Frame::NewConnectionId { seq_num, retire_prior_to, conn_id, reset_token, } => { 1 + // frame type octets::varint_len(*seq_num) + // seq_num octets::varint_len(*retire_prior_to) + // retire_prior_to 1 + // conn_id length conn_id.len() + // conn_id reset_token.len() // reset_token }, Frame::RetireConnectionId { seq_num } => { 1 + // frame type octets::varint_len(*seq_num) // seq_num }, Frame::PathChallenge { .. } => { 1 + // frame type 8 // data }, Frame::PathResponse { .. } => { 1 + // frame type 8 // data }, Frame::ConnectionClose { frame_type, error_code, reason, .. } => { 1 + // frame type octets::varint_len(*error_code) + // error_code octets::varint_len(*frame_type) + // frame_type octets::varint_len(reason.len() as u64) + // reason_len reason.len() // reason }, Frame::ApplicationClose { reason, error_code } => { 1 + // frame type octets::varint_len(*error_code) + // error_code octets::varint_len(reason.len() as u64) + // reason_len reason.len() // reason }, Frame::HandshakeDone => { 1 // frame type }, Frame::Datagram { data } => { 1 + // frame type octets::varint_len(data.len() as u64) + // length data.len() // data }, } } pub fn ack_eliciting(&self) -> bool { // Any other frame is ack-eliciting (note the `!`). !matches!(self, Frame::Padding { .. } | Frame::ACK { .. } | Frame::ApplicationClose { .. } | Frame::ConnectionClose { .. }) } pub fn shrink_for_retransmission(&mut self) { if let Frame::Datagram { data } = self { *data = Vec::new(); } } #[cfg(feature = "qlog")] pub fn to_qlog(&self) -> qlog::QuicFrame { match self { Frame::Padding { .. } => qlog::QuicFrame::padding(), Frame::Ping { .. } => qlog::QuicFrame::ping(), Frame::ACK { ack_delay, ranges } => { let ack_ranges = ranges.iter().map(|r| (r.start, r.end - 1)).collect(); qlog::QuicFrame::ack( Some(ack_delay.to_string()), Some(ack_ranges), None, None, None, ) }, Frame::ResetStream { stream_id, error_code, final_size, } => qlog::QuicFrame::reset_stream( stream_id.to_string(), *error_code, final_size.to_string(), ), Frame::StopSending { stream_id, error_code, } => qlog::QuicFrame::stop_sending(stream_id.to_string(), *error_code), Frame::Crypto { data } => qlog::QuicFrame::crypto( data.off().to_string(), data.len().to_string(), ), Frame::NewToken { token } => qlog::QuicFrame::new_token( token.len().to_string(), "TODO: https://github.com/quiclog/internet-drafts/issues/36" .to_string(), ), Frame::Stream { stream_id, data } => qlog::QuicFrame::stream( stream_id.to_string(), data.off().to_string(), data.len().to_string(), data.fin(), None, ), Frame::MaxData { max } => qlog::QuicFrame::max_data(max.to_string()), Frame::MaxStreamData { stream_id, max } => qlog::QuicFrame::max_stream_data( stream_id.to_string(), max.to_string(), ), Frame::MaxStreamsBidi { max } => qlog::QuicFrame::max_streams( qlog::StreamType::Bidirectional, max.to_string(), ), Frame::MaxStreamsUni { max } => qlog::QuicFrame::max_streams( qlog::StreamType::Unidirectional, max.to_string(), ), Frame::DataBlocked { limit } => qlog::QuicFrame::data_blocked(limit.to_string()), Frame::StreamDataBlocked { stream_id, limit } => qlog::QuicFrame::stream_data_blocked( stream_id.to_string(), limit.to_string(), ), Frame::StreamsBlockedBidi { limit } => qlog::QuicFrame::streams_blocked( qlog::StreamType::Bidirectional, limit.to_string(), ), Frame::StreamsBlockedUni { limit } => qlog::QuicFrame::streams_blocked( qlog::StreamType::Unidirectional, limit.to_string(), ), Frame::NewConnectionId { seq_num, retire_prior_to, conn_id, .. } => qlog::QuicFrame::new_connection_id( seq_num.to_string(), retire_prior_to.to_string(), conn_id.len() as u64, "TODO: https://github.com/quiclog/internet-drafts/issues/36" .to_string(), "TODO: https://github.com/quiclog/internet-drafts/issues/36" .to_string(), ), Frame::RetireConnectionId { seq_num } => qlog::QuicFrame::retire_connection_id(seq_num.to_string()), Frame::PathChallenge { .. } => qlog::QuicFrame::path_challenge(Some( "TODO: https://github.com/quiclog/internet-drafts/issues/36" .to_string(), )), Frame::PathResponse { .. } => qlog::QuicFrame::path_response(Some( "TODO: https://github.com/quiclog/internet-drafts/issues/36" .to_string(), )), Frame::ConnectionClose { error_code, reason, .. } => qlog::QuicFrame::connection_close( qlog::ErrorSpace::TransportError, *error_code, *error_code, String::from_utf8(reason.clone()).unwrap(), Some( "TODO: https://github.com/quiclog/internet-drafts/issues/36" .to_string(), ), ), Frame::ApplicationClose { error_code, reason } => qlog::QuicFrame::connection_close( qlog::ErrorSpace::ApplicationError, *error_code, *error_code, String::from_utf8(reason.clone()).unwrap(), None, /* Application variant of the frame has no trigger * frame type */ ), Frame::HandshakeDone => qlog::QuicFrame::handshake_done(), Frame::Datagram { .. } => qlog::QuicFrame::unknown(0x30), } } } impl std::fmt::Debug for Frame { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self { Frame::Padding { len } => { write!(f, "PADDING len={}", len)?; }, Frame::Ping => { write!(f, "PING")?; }, Frame::ACK { ack_delay, ranges } => { write!(f, "ACK delay={} blocks={:?}", ack_delay, ranges)?; }, Frame::ResetStream { stream_id, error_code, final_size, } => { write!( f, "RESET_STREAM stream={} err={:x} size={}", stream_id, error_code, final_size )?; }, Frame::StopSending { stream_id, error_code, } => { write!( f, "STOP_SENDING stream={} err={:x}", stream_id, error_code )?; }, Frame::Crypto { data } => { write!(f, "CRYPTO off={} len={}", data.off(), data.len())?; }, Frame::NewToken { .. } => { write!(f, "NEW_TOKEN (TODO)")?; }, Frame::Stream { stream_id, data } => { write!( f, "STREAM id={} off={} len={} fin={}", stream_id, data.off(), data.len(), data.fin() )?; }, Frame::MaxData { max } => { write!(f, "MAX_DATA max={}", max)?; }, Frame::MaxStreamData { stream_id, max } => { write!(f, "MAX_STREAM_DATA stream={} max={}", stream_id, max)?; }, Frame::MaxStreamsBidi { max } => { write!(f, "MAX_STREAMS type=bidi max={}", max)?; }, Frame::MaxStreamsUni { max } => { write!(f, "MAX_STREAMS type=uni max={}", max)?; }, Frame::DataBlocked { limit } => { write!(f, "DATA_BLOCKED limit={}", limit)?; }, Frame::StreamDataBlocked { stream_id, limit } => { write!( f, "STREAM_DATA_BLOCKED stream={} limit={}", stream_id, limit )?; }, Frame::StreamsBlockedBidi { limit } => { write!(f, "STREAMS_BLOCKED type=bidi limit={}", limit)?; }, Frame::StreamsBlockedUni { limit } => { write!(f, "STREAMS_BLOCKED type=uni limit={}", limit)?; }, Frame::NewConnectionId { .. } => { write!(f, "NEW_CONNECTION_ID (TODO)")?; }, Frame::RetireConnectionId { .. } => { write!(f, "RETIRE_CONNECTION_ID (TODO)")?; }, Frame::PathChallenge { data } => { write!(f, "PATH_CHALLENGE data={:02x?}", data)?; }, Frame::PathResponse { data } => { write!(f, "PATH_RESPONSE data={:02x?}", data)?; }, Frame::ConnectionClose { error_code, frame_type, reason, } => { write!( f, "CONNECTION_CLOSE err={:x} frame={:x} reason={:x?}", error_code, frame_type, reason )?; }, Frame::ApplicationClose { error_code, reason } => { write!( f, "APPLICATION_CLOSE err={:x} reason={:x?}", error_code, reason )?; }, Frame::HandshakeDone => { write!(f, "HANDSHAKE_DONE")?; }, Frame::Datagram { data } => { write!(f, "DATAGRAM len={}", data.len(),)?; }, } Ok(()) } } fn parse_ack_frame(_ty: u64, b: &mut octets::Octets) -> Result { let largest_ack = b.get_varint()?; let ack_delay = b.get_varint()?; let block_count = b.get_varint()?; let ack_block = b.get_varint()?; if largest_ack < ack_block { return Err(Error::InvalidFrame); } let mut smallest_ack = largest_ack - ack_block; let mut ranges = ranges::RangeSet::default(); #[allow(clippy::range_plus_one)] ranges.insert(smallest_ack..largest_ack + 1); for _i in 0..block_count { let gap = b.get_varint()?; if smallest_ack < 2 + gap { return Err(Error::InvalidFrame); } let largest_ack = (smallest_ack - gap) - 2; let ack_block = b.get_varint()?; if largest_ack < ack_block { return Err(Error::InvalidFrame); } smallest_ack = largest_ack - ack_block; #[allow(clippy::range_plus_one)] ranges.insert(smallest_ack..largest_ack + 1); } Ok(Frame::ACK { ack_delay, ranges }) } fn parse_stream_frame(ty: u64, b: &mut octets::Octets) -> Result { let first = ty as u8; let stream_id = b.get_varint()?; let offset = if first & 0x04 != 0 { b.get_varint()? } else { 0 }; let len = if first & 0x02 != 0 { b.get_varint()? as usize } else { b.cap() }; if offset + len as u64 >= MAX_STREAM_SIZE { return Err(Error::InvalidFrame); } let fin = first & 0x01 != 0; let data = b.get_bytes(len)?; let data = stream::RangeBuf::from(data.as_ref(), offset, fin); Ok(Frame::Stream { stream_id, data }) } fn parse_datagram_frame(ty: u64, b: &mut octets::Octets) -> Result { let first = ty as u8; let len = if first & 0x01 != 0 { b.get_varint()? as usize } else { b.cap() }; let data = b.get_bytes(len)?; Ok(Frame::Datagram { data: Vec::from(data.buf()), }) } #[cfg(test)] mod tests { use super::*; #[test] fn padding() { let mut d = [42; 128]; let frame = Frame::Padding { len: 128 }; let wire_len = { let mut b = octets::OctetsMut::with_slice(&mut d); frame.to_bytes(&mut b).unwrap() }; assert_eq!(wire_len, 128); let mut b = octets::Octets::with_slice(&d); assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame)); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_ok()); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT).is_ok()); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::Handshake).is_ok()); } #[test] fn ping() { let mut d = [42; 128]; let frame = Frame::Ping; let wire_len = { let mut b = octets::OctetsMut::with_slice(&mut d); frame.to_bytes(&mut b).unwrap() }; assert_eq!(wire_len, 1); assert_eq!(&d[..wire_len], [0x01 as u8]); let mut b = octets::Octets::with_slice(&d); assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame)); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT).is_ok()); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_ok()); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::Handshake).is_ok()); } #[test] fn ack() { let mut d = [42; 128]; let mut ranges = ranges::RangeSet::default(); ranges.insert(4..7); ranges.insert(9..12); ranges.insert(15..19); ranges.insert(3000..5000); let frame = Frame::ACK { ack_delay: 874_656_534, ranges, }; let wire_len = { let mut b = octets::OctetsMut::with_slice(&mut d); frame.to_bytes(&mut b).unwrap() }; assert_eq!(wire_len, 17); let mut b = octets::Octets::with_slice(&d); assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame)); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_ok()); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT).is_err()); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::Handshake).is_ok()); } #[test] fn reset_stream() { let mut d = [42; 128]; let frame = Frame::ResetStream { stream_id: 123_213, error_code: 21_123_767, final_size: 21_123_767, }; let wire_len = { let mut b = octets::OctetsMut::with_slice(&mut d); frame.to_bytes(&mut b).unwrap() }; assert_eq!(wire_len, 13); let mut b = octets::Octets::with_slice(&d); assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame)); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT).is_ok()); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_err()); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::Handshake).is_err()); } #[test] fn stop_sending() { let mut d = [42; 128]; let frame = Frame::StopSending { stream_id: 123_213, error_code: 15_352, }; let wire_len = { let mut b = octets::OctetsMut::with_slice(&mut d); frame.to_bytes(&mut b).unwrap() }; assert_eq!(wire_len, 7); let mut b = octets::Octets::with_slice(&d); assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame)); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT).is_ok()); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_err()); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::Handshake).is_err()); } #[test] fn crypto() { let mut d = [42; 128]; let data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; let frame = Frame::Crypto { data: stream::RangeBuf::from(&data, 1230976, false), }; let wire_len = { let mut b = octets::OctetsMut::with_slice(&mut d); frame.to_bytes(&mut b).unwrap() }; assert_eq!(wire_len, 18); let mut b = octets::Octets::with_slice(&d); assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame)); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_ok()); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT).is_err()); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::Handshake).is_ok()); } #[test] fn new_token() { let mut d = [42; 128]; let frame = Frame::NewToken { token: Vec::from("this is a token"), }; let wire_len = { let mut b = octets::OctetsMut::with_slice(&mut d); frame.to_bytes(&mut b).unwrap() }; assert_eq!(wire_len, 17); let mut b = octets::Octets::with_slice(&d); assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame)); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_err()); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT).is_err()); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::Handshake).is_err()); } #[test] fn stream() { let mut d = [42; 128]; let data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; let frame = Frame::Stream { stream_id: 32, data: stream::RangeBuf::from(&data, 1230976, true), }; let wire_len = { let mut b = octets::OctetsMut::with_slice(&mut d); frame.to_bytes(&mut b).unwrap() }; assert_eq!(wire_len, 19); let mut b = octets::Octets::with_slice(&d); assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame)); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT).is_ok()); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_err()); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::Handshake).is_err()); } #[test] fn stream_too_big() { let mut d = [42; 128]; let data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; let frame = Frame::Stream { stream_id: 32, data: stream::RangeBuf::from(&data, MAX_STREAM_SIZE - 11, true), }; let wire_len = { let mut b = octets::OctetsMut::with_slice(&mut d); frame.to_bytes(&mut b).unwrap() }; assert_eq!(wire_len, 23); let mut b = octets::Octets::with_slice(&d); assert_eq!( Frame::from_bytes(&mut b, packet::Type::Short), Err(Error::InvalidFrame) ); } #[test] fn max_data() { let mut d = [42; 128]; let frame = Frame::MaxData { max: 128_318_273 }; let wire_len = { let mut b = octets::OctetsMut::with_slice(&mut d); frame.to_bytes(&mut b).unwrap() }; assert_eq!(wire_len, 5); let mut b = octets::Octets::with_slice(&d); assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame)); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT).is_ok()); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_err()); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::Handshake).is_err()); } #[test] fn max_stream_data() { let mut d = [42; 128]; let frame = Frame::MaxStreamData { stream_id: 12_321, max: 128_318_273, }; let wire_len = { let mut b = octets::OctetsMut::with_slice(&mut d); frame.to_bytes(&mut b).unwrap() }; assert_eq!(wire_len, 7); let mut b = octets::Octets::with_slice(&d); assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame)); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT).is_ok()); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_err()); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::Handshake).is_err()); } #[test] fn max_streams_bidi() { let mut d = [42; 128]; let frame = Frame::MaxStreamsBidi { max: 128_318_273 }; let wire_len = { let mut b = octets::OctetsMut::with_slice(&mut d); frame.to_bytes(&mut b).unwrap() }; assert_eq!(wire_len, 5); let mut b = octets::Octets::with_slice(&d); assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame)); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT).is_ok()); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_err()); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::Handshake).is_err()); } #[test] fn max_streams_uni() { let mut d = [42; 128]; let frame = Frame::MaxStreamsUni { max: 128_318_273 }; let wire_len = { let mut b = octets::OctetsMut::with_slice(&mut d); frame.to_bytes(&mut b).unwrap() }; assert_eq!(wire_len, 5); let mut b = octets::Octets::with_slice(&d); assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame)); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT).is_ok()); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_err()); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::Handshake).is_err()); } #[test] fn data_blocked() { let mut d = [42; 128]; let frame = Frame::DataBlocked { limit: 128_318_273 }; let wire_len = { let mut b = octets::OctetsMut::with_slice(&mut d); frame.to_bytes(&mut b).unwrap() }; assert_eq!(wire_len, 5); let mut b = octets::Octets::with_slice(&d); assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame)); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT).is_ok()); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_err()); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::Handshake).is_err()); } #[test] fn stream_data_blocked() { let mut d = [42; 128]; let frame = Frame::StreamDataBlocked { stream_id: 12_321, limit: 128_318_273, }; let wire_len = { let mut b = octets::OctetsMut::with_slice(&mut d); frame.to_bytes(&mut b).unwrap() }; assert_eq!(wire_len, 7); let mut b = octets::Octets::with_slice(&d); assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame)); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT).is_ok()); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_err()); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::Handshake).is_err()); } #[test] fn streams_blocked_bidi() { let mut d = [42; 128]; let frame = Frame::StreamsBlockedBidi { limit: 128_318_273 }; let wire_len = { let mut b = octets::OctetsMut::with_slice(&mut d); frame.to_bytes(&mut b).unwrap() }; assert_eq!(wire_len, 5); let mut b = octets::Octets::with_slice(&d); assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame)); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT).is_ok()); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_err()); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::Handshake).is_err()); } #[test] fn streams_blocked_uni() { let mut d = [42; 128]; let frame = Frame::StreamsBlockedUni { limit: 128_318_273 }; let wire_len = { let mut b = octets::OctetsMut::with_slice(&mut d); frame.to_bytes(&mut b).unwrap() }; assert_eq!(wire_len, 5); let mut b = octets::Octets::with_slice(&d); assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame)); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT).is_ok()); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_err()); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::Handshake).is_err()); } #[test] fn new_connection_id() { let mut d = [42; 128]; let frame = Frame::NewConnectionId { seq_num: 123_213, retire_prior_to: 122_211, conn_id: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], reset_token: vec![0x42; 16], }; let wire_len = { let mut b = octets::OctetsMut::with_slice(&mut d); frame.to_bytes(&mut b).unwrap() }; assert_eq!(wire_len, 41); let mut b = octets::Octets::with_slice(&d); assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame)); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT).is_ok()); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_err()); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::Handshake).is_err()); } #[test] fn retire_connection_id() { let mut d = [42; 128]; let frame = Frame::RetireConnectionId { seq_num: 123_213 }; let wire_len = { let mut b = octets::OctetsMut::with_slice(&mut d); frame.to_bytes(&mut b).unwrap() }; assert_eq!(wire_len, 5); let mut b = octets::Octets::with_slice(&d); assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame)); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_err()); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT).is_err()); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::Handshake).is_err()); } #[test] fn path_challenge() { let mut d = [42; 128]; let frame = Frame::PathChallenge { data: vec![1, 2, 3, 4, 5, 6, 7, 8], }; let wire_len = { let mut b = octets::OctetsMut::with_slice(&mut d); frame.to_bytes(&mut b).unwrap() }; assert_eq!(wire_len, 9); let mut b = octets::Octets::with_slice(&d); assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame)); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT).is_ok()); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_err()); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::Handshake).is_err()); } #[test] fn path_response() { let mut d = [42; 128]; let frame = Frame::PathResponse { data: vec![1, 2, 3, 4, 5, 6, 7, 8], }; let wire_len = { let mut b = octets::OctetsMut::with_slice(&mut d); frame.to_bytes(&mut b).unwrap() }; assert_eq!(wire_len, 9); let mut b = octets::Octets::with_slice(&d); assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame)); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_err()); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT).is_err()); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::Handshake).is_err()); } #[test] fn connection_close() { let mut d = [42; 128]; let frame = Frame::ConnectionClose { error_code: 0xbeef, frame_type: 523_423, reason: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], }; let wire_len = { let mut b = octets::OctetsMut::with_slice(&mut d); frame.to_bytes(&mut b).unwrap() }; assert_eq!(wire_len, 22); let mut b = octets::Octets::with_slice(&d); assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame)); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_ok()); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT).is_err()); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::Handshake).is_ok()); } #[test] fn application_close() { let mut d = [42; 128]; let frame = Frame::ApplicationClose { error_code: 0xbeef, reason: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], }; let wire_len = { let mut b = octets::OctetsMut::with_slice(&mut d); frame.to_bytes(&mut b).unwrap() }; assert_eq!(wire_len, 18); let mut b = octets::Octets::with_slice(&d); assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame)); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT).is_ok()); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_err()); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::Handshake).is_err()); } #[test] fn handshake_done() { let mut d = [42; 128]; let frame = Frame::HandshakeDone; let wire_len = { let mut b = octets::OctetsMut::with_slice(&mut d); frame.to_bytes(&mut b).unwrap() }; assert_eq!(wire_len, 1); let mut b = octets::Octets::with_slice(&d); assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame)); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_err()); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT).is_err()); let mut b = octets::Octets::with_slice(&d); assert!(Frame::from_bytes(&mut b, packet::Type::Handshake).is_err()); } #[test] fn datagram() { let mut d = [42; 128]; let data = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; let mut frame = Frame::Datagram { data: data.clone() }; let wire_len = { let mut b = octets::OctetsMut::with_slice(&mut d); frame.to_bytes(&mut b).unwrap() }; assert_eq!(wire_len, 14); let mut b = octets::Octets::with_slice(&mut d); assert_eq!( Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame.clone()) ); let mut b = octets::Octets::with_slice(&mut d); assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_err()); let mut b = octets::Octets::with_slice(&mut d); assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT).is_ok()); let mut b = octets::Octets::with_slice(&mut d); assert!(Frame::from_bytes(&mut b, packet::Type::Handshake).is_err()); let frame_data = match &frame { Frame::Datagram { data } => data.clone(), _ => unreachable!(), }; assert_eq!(frame_data, data); frame.shrink_for_retransmission(); let frame_data = match &frame { Frame::Datagram { data } => data.clone(), _ => unreachable!(), }; assert_eq!(frame_data.len(), 0); } }