iroh_quinn_proto/
frame.rs

1use std::{
2    fmt::{self, Write},
3    mem,
4    net::{IpAddr, SocketAddr},
5    ops::{Range, RangeInclusive},
6};
7
8use bytes::{Buf, BufMut, Bytes};
9use tinyvec::TinyVec;
10
11use crate::{
12    Dir, MAX_CID_SIZE, RESET_TOKEN_SIZE, ResetToken, StreamId, TransportError, TransportErrorCode,
13    VarInt,
14    coding::{self, BufExt, BufMutExt, Decodable, Encodable, UnexpectedEnd},
15    connection::PathId,
16    range_set::ArrayRangeSet,
17    shared::{ConnectionId, EcnCodepoint},
18};
19
20#[cfg(feature = "arbitrary")]
21use arbitrary::Arbitrary;
22
23/// Generates the [`FrameType`] enum, and its associated conversions from and to u64
24macro_rules! frame_types {
25    // Process the unit variants.
26    (enum_defs: [$($enum_defs: tt)*] try_from_arms: [$($try_from_arms: tt)*] to_u64_arms:[$($to_u64_arms: tt)*] // accumulators
27     $variant: ident = $value: literal, // VariantName = value,
28     $($token: tt)*) => {
29        frame_types!{
30            enum_defs: [$($enum_defs)* $variant,]
31            try_from_arms: [$($try_from_arms)* $value => Self::$variant,]
32            to_u64_arms: [$($to_u64_arms)* FrameType::$variant => $value,]
33            $($token)*
34        }
35    };
36
37    // Process the tuple variants.
38    (enum_defs: [$($enum_defs: tt)*] try_from_arms: [$($try_from_arms: tt)*] to_u64_arms:[$($to_u64_arms: tt)*] // accumulators
39     $variant: ident($inner: ident), // VariantName(InnerType),
40     $($token: tt)*) => {
41        frame_types!{
42            enum_defs: [$($enum_defs)* $variant($inner),]
43            try_from_arms: [$($try_from_arms)* value if <$inner>::VALUES.contains(&value) => Self::$variant($inner(value as u8)),]
44            to_u64_arms: [$($to_u64_arms)* FrameType::$variant($inner(value)) => value as u64,]
45            $($token)*
46        }
47    };
48
49    // Final generation step.
50    (enum_defs: [$($enum_defs: tt)+] try_from_arms: [$($try_from_arms: tt)+] to_u64_arms: [$($to_u64_arms: tt)+]) => {
51        /// A QUIC frame type
52        #[derive(Copy, Clone, Eq, PartialEq, derive_more::Debug, derive_more::Display)]
53        #[display(rename_all = "SCREAMING_SNAKE_CASE")]
54        #[allow(missing_docs)]
55        pub enum FrameType {
56            $($enum_defs)*
57        }
58
59        pub struct InvalidFrameId(u64);
60
61        impl TryFrom<u64> for FrameType {
62            type Error = InvalidFrameId;
63            fn try_from(value: u64) -> Result<Self, Self::Error> {
64                Ok(match value {
65                    $($try_from_arms)*
66                    other => return Err(InvalidFrameId(other))
67                })
68            }
69        }
70
71        impl FrameType {
72            pub(crate) const fn to_u64(self) -> u64 {
73                match self {
74                    $($to_u64_arms)*
75                }
76            }
77        }
78    };
79}
80
81frame_types! {
82    enum_defs: []
83    try_from_arms: []
84    to_u64_arms: []
85    Padding = 0x00,
86    Ping = 0x01,
87    Ack = 0x02,
88    AckEcn = 0x03,
89    ResetStream = 0x04,
90    StopSending = 0x05,
91    Crypto = 0x06,
92    NewToken = 0x07,
93    // STREAM
94    Stream(StreamInfo),
95    MaxData = 0x10,
96    MaxStreamData = 0x11,
97    MaxStreamsBidi = 0x12,
98    MaxStreamsUni = 0x13,
99    DataBlocked = 0x14,
100    StreamDataBlocked = 0x15,
101    StreamsBlockedBidi = 0x16,
102    StreamsBlockedUni = 0x17,
103    NewConnectionId = 0x18,
104    RetireConnectionId = 0x19,
105    PathChallenge = 0x1a,
106    PathResponse = 0x1b,
107    ConnectionClose = 0x1c,
108    ApplicationClose = 0x1d,
109    HandshakeDone = 0x1e,
110    // ACK Frequency
111    AckFrequency = 0xaf,
112    ImmediateAck = 0x1f,
113    // DATAGRAM
114    Datagram(DatagramInfo),
115    // ADDRESS DISCOVERY REPORT
116    ObservedIpv4Addr = 0x9f81a6,
117    ObservedIpv6Addr = 0x9f81a7,
118    // Multipath
119    PathAck = 0x15228c00,
120    PathAckEcn = 0x15228c01,
121    PathAbandon = 0x15228c05,
122    PathStatusBackup = 0x15228c07,
123    PathStatusAvailable = 0x15228c08,
124    PathNewConnectionId = 0x15228c09,
125    PathRetireConnectionId = 0x15228c0a,
126    MaxPathId = 0x15228c0c,
127    PathsBlocked = 0x15228c0d,
128    PathCidsBlocked = 0x15228c0e,
129    // IROH'S NAT TRAVERSAL
130    AddIpv4Address = 0x3d7f90,
131    AddIpv6Address = 0x3d7f91,
132    ReachOutAtIpv4 = 0x3d7f92,
133    ReachOutAtIpv6 = 0x3d7f93,
134    RemoveAddress = 0x3d7f94,
135}
136
137impl FrameType {
138    /// The encoded size of this [`FrameType`].
139    const fn size(&self) -> usize {
140        VarInt(self.to_u64()).size()
141    }
142}
143
144impl Decodable for FrameType {
145    fn decode<B: Buf>(buf: &mut B) -> coding::Result<Self> {
146        Self::try_from(buf.get_var()?).map_err(|_| coding::UnexpectedEnd)
147    }
148}
149
150impl Encodable for FrameType {
151    fn encode<B: BufMut>(&self, buf: &mut B) {
152        buf.write_var(self.to_u64());
153    }
154}
155
156pub(crate) trait FrameStruct {
157    /// Smallest number of bytes this type of frame is guaranteed to fit within.
158    const SIZE_BOUND: usize;
159}
160
161/// The type used to refer to [`FrameType`]s in closing and transport errors.
162#[derive(Copy, Clone, Eq, PartialEq, derive_more::Debug, derive_more::Display)]
163pub enum MaybeFrame {
164    /// Not attributed to any particular [`FrameType`].
165    None,
166    /// Attributed to some frame type this implementation does not recognize.
167    #[display("UNKNOWN{:02x}", _0)]
168    #[debug("Unknown{:02x}", _0)]
169    Unknown(u64),
170    /// Attributed to a specific [`FrameType`], never [`FrameType::Padding`].
171    Known(FrameType),
172}
173
174impl MaybeFrame {
175    /// Encoded size of this [`MaybeFrame`].
176    const fn size(&self) -> usize {
177        match self {
178            Self::None => VarInt(0).size(),
179            Self::Unknown(other) => VarInt(*other).size(),
180            Self::Known(frame_type) => frame_type.size(),
181        }
182    }
183}
184
185impl Decodable for MaybeFrame {
186    fn decode<B: Buf>(buf: &mut B) -> coding::Result<Self> {
187        match FrameType::try_from(buf.get_var()?) {
188            Ok(FrameType::Padding) => Ok(Self::None),
189            Ok(other_frame) => Ok(Self::Known(other_frame)),
190            Err(InvalidFrameId(other)) => Ok(Self::Unknown(other)),
191        }
192    }
193}
194
195impl Encodable for MaybeFrame {
196    fn encode<B: BufMut>(&self, buf: &mut B) {
197        match self {
198            Self::None => buf.write(0u64),
199            Self::Unknown(frame_id) => buf.write(*frame_id),
200            Self::Known(frame_type) => buf.write(*frame_type),
201        }
202    }
203}
204
205#[derive(Debug, Copy, Clone, Eq, PartialEq, derive_more::Display)]
206#[display("STREAM")]
207pub struct StreamInfo(u8);
208
209impl StreamInfo {
210    const VALUES: RangeInclusive<u64> = RangeInclusive::new(0x08, 0x0f);
211    fn fin(self) -> bool {
212        self.0 & 0x01 != 0
213    }
214    fn len(self) -> bool {
215        self.0 & 0x02 != 0
216    }
217    fn off(self) -> bool {
218        self.0 & 0x04 != 0
219    }
220}
221
222#[derive(Debug, Copy, Clone, Eq, PartialEq, derive_more::Display)]
223#[display("DATAGRAM")]
224pub struct DatagramInfo(u8);
225
226impl DatagramInfo {
227    const VALUES: RangeInclusive<u64> = RangeInclusive::new(0x30, 0x31);
228
229    fn len(self) -> bool {
230        self.0 & 0x01 != 0
231    }
232}
233
234#[derive(Debug)]
235pub(crate) enum Frame {
236    Padding,
237    Ping,
238    Ack(Ack),
239    PathAck(PathAck),
240    ResetStream(ResetStream),
241    StopSending(StopSending),
242    Crypto(Crypto),
243    NewToken(NewToken),
244    Stream(Stream),
245    MaxData(VarInt),
246    MaxStreamData { id: StreamId, offset: u64 },
247    MaxStreams { dir: Dir, count: u64 },
248    DataBlocked { offset: u64 },
249    StreamDataBlocked { id: StreamId, offset: u64 },
250    StreamsBlocked { dir: Dir, limit: u64 },
251    NewConnectionId(NewConnectionId),
252    RetireConnectionId(RetireConnectionId),
253    PathChallenge(PathChallenge),
254    PathResponse(PathResponse),
255    Close(Close),
256    Datagram(Datagram),
257    AckFrequency(AckFrequency),
258    ImmediateAck,
259    HandshakeDone,
260    ObservedAddr(ObservedAddr),
261    PathAbandon(PathAbandon),
262    PathStatusAvailable(PathStatusAvailable),
263    PathStatusBackup(PathStatusBackup),
264    MaxPathId(MaxPathId),
265    PathsBlocked(PathsBlocked),
266    PathCidsBlocked(PathCidsBlocked),
267    AddAddress(AddAddress),
268    ReachOut(ReachOut),
269    RemoveAddress(RemoveAddress),
270}
271
272impl fmt::Display for Frame {
273    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
274        // Eventually all our frames will support fmt::Display and be able to be used to log
275        // consistently. For now we fall back to fmt::Debug.
276        match self {
277            Self::Padding => write!(f, "PADDING"),
278            Self::Ping => write!(f, "PING"),
279            Self::PathChallenge(frame) => write!(f, "{frame}"),
280            Self::PathResponse(frame) => write!(f, "{frame}"),
281            Self::ImmediateAck => write!(f, "IMMEDIATE_ACK"),
282            Self::HandshakeDone => write!(f, "HANDSHAKE_DONE"),
283            _ => write!(f, "{self:?}"),
284        }
285    }
286}
287
288impl Frame {
289    pub(crate) fn ty(&self) -> FrameType {
290        use Frame::*;
291        match *self {
292            Padding => FrameType::Padding,
293            ResetStream(_) => FrameType::ResetStream,
294            Close(self::Close::Connection(_)) => FrameType::ConnectionClose,
295            Close(self::Close::Application(_)) => FrameType::ConnectionClose,
296            MaxData(_) => FrameType::MaxData,
297            MaxStreamData { .. } => FrameType::MaxStreamData,
298            MaxStreams { dir: Dir::Bi, .. } => FrameType::MaxStreamsBidi,
299            MaxStreams { dir: Dir::Uni, .. } => FrameType::MaxStreamsUni,
300            Ping => FrameType::Ping,
301            DataBlocked { .. } => FrameType::DataBlocked,
302            StreamDataBlocked { .. } => FrameType::StreamDataBlocked,
303            StreamsBlocked { dir: Dir::Bi, .. } => FrameType::StreamsBlockedBidi,
304            StreamsBlocked { dir: Dir::Uni, .. } => FrameType::StreamsBlockedUni,
305            StopSending { .. } => FrameType::StopSending,
306            RetireConnectionId { .. } => FrameType::RetireConnectionId,
307            Ack(_) => FrameType::Ack,
308            PathAck(_) => FrameType::PathAck,
309            Stream(ref x) => {
310                let mut ty = *StreamInfo::VALUES.start() as u8;
311                if x.fin {
312                    ty |= 0x01;
313                }
314                if x.offset != 0 {
315                    ty |= 0x04;
316                }
317                // TODO(@divma): move all this to getframetype for Stream
318                FrameType::Stream(StreamInfo(ty))
319            }
320            PathChallenge(_) => FrameType::PathChallenge,
321            PathResponse(_) => FrameType::PathResponse,
322            NewConnectionId(cid) => cid.get_type(),
323            Crypto(_) => FrameType::Crypto,
324            NewToken(_) => FrameType::NewToken,
325            Datagram(_) => FrameType::Datagram(DatagramInfo(*DatagramInfo::VALUES.start() as u8)),
326            AckFrequency(_) => FrameType::AckFrequency,
327            ImmediateAck => FrameType::ImmediateAck,
328            HandshakeDone => FrameType::HandshakeDone,
329            ObservedAddr(ref observed) => observed.get_type(),
330            PathAbandon(_) => FrameType::PathAbandon,
331            PathStatusAvailable(_) => FrameType::PathStatusAvailable,
332            PathStatusBackup(_) => FrameType::PathStatusBackup,
333            MaxPathId(_) => FrameType::MaxPathId,
334            PathsBlocked(_) => FrameType::PathsBlocked,
335            PathCidsBlocked(_) => FrameType::PathCidsBlocked,
336            AddAddress(ref frame) => frame.get_type(),
337            ReachOut(ref frame) => frame.get_type(),
338            RemoveAddress(_) => self::RemoveAddress::TYPE,
339        }
340    }
341
342    pub(crate) fn is_ack_eliciting(&self) -> bool {
343        !matches!(
344            *self,
345            Self::Ack(_) | Self::PathAck(_) | Self::Padding | Self::Close(_)
346        )
347    }
348
349    /// Returns `true` if this frame MUST be sent in 1-RTT space
350    pub(crate) fn is_1rtt(&self) -> bool {
351        // See also https://www.ietf.org/archive/id/draft-ietf-quic-multipath-17.html#section-4-1:
352        // > All frames defined in this document MUST only be sent in 1-RTT packets.
353        // > If an endpoint receives a multipath-specific frame in a different packet type, it MUST close the
354        // > connection with an error of type PROTOCOL_VIOLATION.
355
356        self.is_multipath_frame() || self.is_qad_frame()
357    }
358
359    fn is_qad_frame(&self) -> bool {
360        matches!(*self, Self::ObservedAddr(_))
361    }
362
363    fn is_multipath_frame(&self) -> bool {
364        matches!(
365            *self,
366            Self::PathAck(_)
367                | Self::PathAbandon(_)
368                | Self::PathStatusBackup(_)
369                | Self::PathStatusAvailable(_)
370                | Self::MaxPathId(_)
371                | Self::PathsBlocked(_)
372                | Self::PathCidsBlocked(_)
373                | Self::NewConnectionId(NewConnectionId {
374                    path_id: Some(_),
375                    ..
376                })
377                | Self::RetireConnectionId(RetireConnectionId {
378                    path_id: Some(_),
379                    ..
380                })
381        )
382    }
383}
384
385#[derive(Debug, Clone, Copy, PartialEq, Eq, derive_more::Display)]
386#[display("PATH_CHALLENGE({_0:08x})")]
387pub(crate) struct PathChallenge(pub(crate) u64);
388
389impl PathChallenge {
390    pub(crate) const SIZE_BOUND: usize = 9;
391}
392impl Decodable for PathChallenge {
393    fn decode<B: Buf>(buf: &mut B) -> coding::Result<Self> {
394        Ok(Self(buf.get()?))
395    }
396}
397impl Encodable for PathChallenge {
398    fn encode<B: BufMut>(&self, buf: &mut B) {
399        buf.write(FrameType::PathChallenge);
400        buf.write(self.0);
401    }
402}
403
404#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, derive_more::Display)]
405#[display("PATH_RESPONSE({_0:08x})")]
406pub(crate) struct PathResponse(pub(crate) u64);
407
408impl PathResponse {
409    pub(crate) const SIZE_BOUND: usize = 9;
410}
411
412impl Decodable for PathResponse {
413    fn decode<B: Buf>(buf: &mut B) -> coding::Result<Self> {
414        Ok(Self(buf.get()?))
415    }
416}
417impl Encodable for PathResponse {
418    fn encode<B: BufMut>(&self, buf: &mut B) {
419        buf.write(FrameType::PathResponse);
420        buf.write(self.0);
421    }
422}
423
424#[derive(Debug, PartialEq, Eq)]
425pub(crate) struct RetireConnectionId {
426    pub(crate) path_id: Option<PathId>,
427    pub(crate) sequence: u64,
428}
429
430impl RetireConnectionId {
431    /// Maximum size of this frame when the frame type is [`FrameType::RetireConnectionId`]
432    pub(crate) const SIZE_BOUND: usize = {
433        let type_len = FrameType::RetireConnectionId.size();
434        let seq_max_len = 8usize;
435        type_len + seq_max_len
436    };
437
438    /// Maximum size of this frame when the frame type is [`FrameType::PathRetireConnectionId`]
439    pub(crate) const SIZE_BOUND_MULTIPATH: usize = {
440        let type_len = FrameType::PathRetireConnectionId.size();
441        let path_id_len = VarInt::from_u32(u32::MAX).size();
442        let seq_max_len = 8usize;
443        type_len + path_id_len + seq_max_len
444    };
445
446    /// Decode [`Self`] from the buffer, provided that the frame type has been verified (either
447    /// [`FrameType::PathRetireConnectionId`], or [`FrameType::RetireConnectionId`])
448    pub(crate) fn decode<R: Buf>(bytes: &mut R, read_path: bool) -> coding::Result<Self> {
449        Ok(Self {
450            path_id: if read_path { Some(bytes.get()?) } else { None },
451            sequence: bytes.get_var()?,
452        })
453    }
454
455    /// Get the [`FrameType`] for this [`RetireConnectionId`]
456    pub(crate) fn get_type(&self) -> FrameType {
457        if self.path_id.is_some() {
458            FrameType::PathRetireConnectionId
459        } else {
460            FrameType::RetireConnectionId
461        }
462    }
463
464    /// Returns the maximum encoded size on the wire
465    ///
466    /// `path_retire_cid` determines whether this frame is a multipath frame. This is a rough upper
467    /// estimate, does not squeeze every last byte out.
468    pub(crate) const fn size_bound(path_retire_cid: bool) -> usize {
469        match path_retire_cid {
470            true => Self::SIZE_BOUND_MULTIPATH,
471            false => Self::SIZE_BOUND,
472        }
473    }
474}
475
476impl Encodable for RetireConnectionId {
477    fn encode<W: BufMut>(&self, buf: &mut W) {
478        buf.write(self.get_type());
479        if let Some(id) = self.path_id {
480            buf.write(id);
481        }
482        buf.write_var(self.sequence);
483    }
484}
485
486#[derive(Clone, Debug)]
487pub enum Close {
488    Connection(ConnectionClose),
489    Application(ApplicationClose),
490}
491
492impl Close {
493    pub(crate) fn encode<W: BufMut>(&self, out: &mut W, max_len: usize) {
494        match *self {
495            Self::Connection(ref x) => x.encode(out, max_len),
496            Self::Application(ref x) => x.encode(out, max_len),
497        }
498    }
499
500    pub(crate) fn is_transport_layer(&self) -> bool {
501        matches!(*self, Self::Connection(_))
502    }
503}
504
505impl From<TransportError> for Close {
506    fn from(x: TransportError) -> Self {
507        Self::Connection(x.into())
508    }
509}
510impl From<ConnectionClose> for Close {
511    fn from(x: ConnectionClose) -> Self {
512        Self::Connection(x)
513    }
514}
515impl From<ApplicationClose> for Close {
516    fn from(x: ApplicationClose) -> Self {
517        Self::Application(x)
518    }
519}
520
521/// Reason given by the transport for closing the connection
522#[derive(Debug, Clone, PartialEq, Eq)]
523pub struct ConnectionClose {
524    /// Class of error as encoded in the specification
525    pub error_code: TransportErrorCode,
526    /// Type of frame that caused the close
527    pub frame_type: MaybeFrame,
528    /// Human-readable reason for the close
529    pub reason: Bytes,
530}
531
532impl fmt::Display for ConnectionClose {
533    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
534        self.error_code.fmt(f)?;
535        if !self.reason.as_ref().is_empty() {
536            f.write_str(": ")?;
537            f.write_str(&String::from_utf8_lossy(&self.reason))?;
538        }
539        Ok(())
540    }
541}
542
543impl From<TransportError> for ConnectionClose {
544    fn from(x: TransportError) -> Self {
545        Self {
546            error_code: x.code,
547            frame_type: x.frame,
548            reason: x.reason.into(),
549        }
550    }
551}
552
553impl FrameStruct for ConnectionClose {
554    const SIZE_BOUND: usize = 1 + 8 + 8 + 8;
555}
556
557impl ConnectionClose {
558    pub(crate) fn encode<W: BufMut>(&self, out: &mut W, max_len: usize) {
559        out.write(FrameType::ConnectionClose); // 1 byte
560        out.write(self.error_code); // <= 8 bytes
561        out.write(self.frame_type); // <= 8 bytes
562        let max_len = max_len
563            - 3
564            - self.frame_type.size()
565            - VarInt::from_u64(self.reason.len() as u64).unwrap().size();
566        let actual_len = self.reason.len().min(max_len);
567        out.write_var(actual_len as u64); // <= 8 bytes
568        out.put_slice(&self.reason[0..actual_len]); // whatever's left
569    }
570}
571
572/// Reason given by an application for closing the connection
573#[derive(Debug, Clone, PartialEq, Eq)]
574pub struct ApplicationClose {
575    /// Application-specific reason code
576    pub error_code: VarInt,
577    /// Human-readable reason for the close
578    pub reason: Bytes,
579}
580
581impl fmt::Display for ApplicationClose {
582    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
583        if !self.reason.as_ref().is_empty() {
584            f.write_str(&String::from_utf8_lossy(&self.reason))?;
585            f.write_str(" (code ")?;
586            self.error_code.fmt(f)?;
587            f.write_str(")")?;
588        } else {
589            self.error_code.fmt(f)?;
590        }
591        Ok(())
592    }
593}
594
595impl FrameStruct for ApplicationClose {
596    const SIZE_BOUND: usize = 1 + 8 + 8;
597}
598
599impl ApplicationClose {
600    pub(crate) fn encode<W: BufMut>(&self, out: &mut W, max_len: usize) {
601        out.write(FrameType::ApplicationClose); // 1 byte
602        out.write(self.error_code); // <= 8 bytes
603        let max_len = max_len - 3 - VarInt::from_u64(self.reason.len() as u64).unwrap().size();
604        let actual_len = self.reason.len().min(max_len);
605        out.write_var(actual_len as u64); // <= 8 bytes
606        out.put_slice(&self.reason[0..actual_len]); // whatever's left
607    }
608}
609
610#[derive(Clone, Eq, PartialEq)]
611pub struct PathAck {
612    pub path_id: PathId,
613    pub largest: u64,
614    pub delay: u64,
615    pub additional: Bytes,
616    pub ecn: Option<EcnCounts>,
617}
618
619impl fmt::Debug for PathAck {
620    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
621        let mut ranges = "[".to_string();
622        let mut first = true;
623        for range in self.into_iter() {
624            if !first {
625                ranges.push(',');
626            }
627            write!(ranges, "{range:?}")?;
628            first = false;
629        }
630        ranges.push(']');
631
632        f.debug_struct("PathAck")
633            .field("path_id", &self.path_id)
634            .field("largest", &self.largest)
635            .field("delay", &self.delay)
636            .field("ecn", &self.ecn)
637            .field("ranges", &ranges)
638            .finish()
639    }
640}
641
642impl<'a> IntoIterator for &'a PathAck {
643    type Item = RangeInclusive<u64>;
644    type IntoIter = AckIter<'a>;
645
646    fn into_iter(self) -> AckIter<'a> {
647        AckIter::new(self.largest, &self.additional[..])
648    }
649}
650
651impl PathAck {
652    /// Encode [`Self`] into the given buffer
653    ///
654    /// The [`FrameType`] will be either [`FrameType::PathAckEcn`] or [`FrameType::PathAck`]
655    /// depending on whether [`EcnCounts`] are provided.
656    ///
657    /// PANICS: if `ranges` is empty.
658    pub fn encode<W: BufMut>(
659        path_id: PathId,
660        delay: u64,
661        ranges: &ArrayRangeSet,
662        ecn: Option<&EcnCounts>,
663        buf: &mut W,
664    ) {
665        let mut rest = ranges.iter().rev();
666        let first = rest
667            .next()
668            .expect("Caller has verified ranges is non empty");
669        let largest = first.end - 1;
670        let first_size = first.end - first.start;
671        let kind = match ecn.is_some() {
672            true => FrameType::PathAckEcn,
673            false => FrameType::PathAck,
674        };
675        buf.write(kind);
676        buf.write(path_id);
677        buf.write_var(largest);
678        buf.write_var(delay);
679        buf.write_var(ranges.len() as u64 - 1);
680        buf.write_var(first_size - 1);
681        let mut prev = first.start;
682        for block in rest {
683            let size = block.end - block.start;
684            buf.write_var(prev - block.end - 1);
685            buf.write_var(size - 1);
686            prev = block.start;
687        }
688        if let Some(x) = ecn {
689            x.encode(buf)
690        }
691    }
692
693    pub fn into_ack(self) -> (Ack, PathId) {
694        let ack = Ack {
695            largest: self.largest,
696            delay: self.delay,
697            additional: self.additional,
698            ecn: self.ecn,
699        };
700
701        (ack, self.path_id)
702    }
703}
704
705#[derive(Clone, Eq, PartialEq)]
706pub struct Ack {
707    pub largest: u64,
708    pub delay: u64,
709    pub additional: Bytes,
710    pub ecn: Option<EcnCounts>,
711}
712
713impl fmt::Debug for Ack {
714    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
715        let mut ranges = "[".to_string();
716        let mut first = true;
717        for range in self.iter() {
718            if !first {
719                ranges.push(',');
720            }
721            write!(ranges, "{range:?}").unwrap();
722            first = false;
723        }
724        ranges.push(']');
725
726        f.debug_struct("Ack")
727            .field("largest", &self.largest)
728            .field("delay", &self.delay)
729            .field("ecn", &self.ecn)
730            .field("ranges", &ranges)
731            .finish()
732    }
733}
734
735impl<'a> IntoIterator for &'a Ack {
736    type Item = RangeInclusive<u64>;
737    type IntoIter = AckIter<'a>;
738
739    fn into_iter(self) -> AckIter<'a> {
740        AckIter::new(self.largest, &self.additional[..])
741    }
742}
743
744impl Ack {
745    pub fn encode<W: BufMut>(
746        delay: u64,
747        ranges: &ArrayRangeSet,
748        ecn: Option<&EcnCounts>,
749        buf: &mut W,
750    ) {
751        let mut rest = ranges.iter().rev();
752        let first = rest.next().unwrap();
753        let largest = first.end - 1;
754        let first_size = first.end - first.start;
755        let kind = match ecn.is_some() {
756            true => FrameType::AckEcn,
757            false => FrameType::Ack,
758        };
759        buf.write(kind);
760        buf.write_var(largest);
761        buf.write_var(delay);
762        buf.write_var(ranges.len() as u64 - 1);
763        buf.write_var(first_size - 1);
764        let mut prev = first.start;
765        for block in rest {
766            let size = block.end - block.start;
767            buf.write_var(prev - block.end - 1);
768            buf.write_var(size - 1);
769            prev = block.start;
770        }
771        if let Some(x) = ecn {
772            x.encode(buf)
773        }
774    }
775
776    pub fn iter(&self) -> AckIter<'_> {
777        self.into_iter()
778    }
779}
780
781#[derive(Debug, Copy, Clone, Eq, PartialEq)]
782pub struct EcnCounts {
783    pub ect0: u64,
784    pub ect1: u64,
785    pub ce: u64,
786}
787
788impl std::ops::AddAssign<EcnCodepoint> for EcnCounts {
789    fn add_assign(&mut self, rhs: EcnCodepoint) {
790        match rhs {
791            EcnCodepoint::Ect0 => {
792                self.ect0 += 1;
793            }
794            EcnCodepoint::Ect1 => {
795                self.ect1 += 1;
796            }
797            EcnCodepoint::Ce => {
798                self.ce += 1;
799            }
800        }
801    }
802}
803
804impl EcnCounts {
805    pub const ZERO: Self = Self {
806        ect0: 0,
807        ect1: 0,
808        ce: 0,
809    };
810}
811
812impl Encodable for EcnCounts {
813    fn encode<W: BufMut>(&self, out: &mut W) {
814        out.write_var(self.ect0);
815        out.write_var(self.ect1);
816        out.write_var(self.ce);
817    }
818}
819
820#[derive(Debug, Clone)]
821pub(crate) struct Stream {
822    pub(crate) id: StreamId,
823    pub(crate) offset: u64,
824    pub(crate) fin: bool,
825    pub(crate) data: Bytes,
826}
827
828impl FrameStruct for Stream {
829    const SIZE_BOUND: usize = 1 + 8 + 8 + 8;
830}
831
832/// Metadata from a stream frame
833#[derive(Debug, Clone)]
834pub(crate) struct StreamMeta {
835    pub(crate) id: StreamId,
836    pub(crate) offsets: Range<u64>,
837    pub(crate) fin: bool,
838}
839
840// This manual implementation exists because `Default` is not implemented for `StreamId`
841impl Default for StreamMeta {
842    fn default() -> Self {
843        Self {
844            id: StreamId(0),
845            offsets: 0..0,
846            fin: false,
847        }
848    }
849}
850
851impl StreamMeta {
852    pub(crate) fn encode<W: BufMut>(&self, length: bool, out: &mut W) {
853        let mut ty = *StreamInfo::VALUES.start();
854        if self.offsets.start != 0 {
855            ty |= 0x04;
856        }
857        if length {
858            ty |= 0x02;
859        }
860        if self.fin {
861            ty |= 0x01;
862        }
863        out.write_var(ty); // 1 byte
864        out.write(self.id); // <=8 bytes
865        if self.offsets.start != 0 {
866            out.write_var(self.offsets.start); // <=8 bytes
867        }
868        if length {
869            out.write_var(self.offsets.end - self.offsets.start); // <=8 bytes
870        }
871    }
872}
873
874/// A vector of [`StreamMeta`] with optimization for the single element case
875pub(crate) type StreamMetaVec = TinyVec<[StreamMeta; 1]>;
876
877#[derive(Debug, Clone)]
878pub(crate) struct Crypto {
879    pub(crate) offset: u64,
880    pub(crate) data: Bytes,
881}
882
883impl Crypto {
884    pub(crate) const SIZE_BOUND: usize = 17;
885}
886
887impl Encodable for Crypto {
888    fn encode<W: BufMut>(&self, out: &mut W) {
889        out.write(FrameType::Crypto);
890        out.write_var(self.offset);
891        out.write_var(self.data.len() as u64);
892        out.put_slice(&self.data);
893    }
894}
895
896#[derive(Debug, Clone)]
897pub(crate) struct NewToken {
898    pub(crate) token: Bytes,
899}
900
901impl Encodable for NewToken {
902    fn encode<W: BufMut>(&self, out: &mut W) {
903        out.write(FrameType::NewToken);
904        out.write_var(self.token.len() as u64);
905        out.put_slice(&self.token);
906    }
907}
908
909impl NewToken {
910    pub(crate) fn size(&self) -> usize {
911        1 + VarInt::from_u64(self.token.len() as u64).unwrap().size() + self.token.len()
912    }
913}
914
915#[derive(Debug, Clone)]
916pub(crate) struct MaxPathId(pub(crate) PathId);
917
918impl MaxPathId {
919    pub(crate) const SIZE_BOUND: usize =
920        FrameType::MaxPathId.size() + VarInt(u32::MAX as u64).size();
921}
922
923impl Decodable for MaxPathId {
924    fn decode<B: Buf>(buf: &mut B) -> coding::Result<Self> {
925        Ok(Self(buf.get()?))
926    }
927}
928
929impl Encodable for MaxPathId {
930    fn encode<B: BufMut>(&self, buf: &mut B) {
931        buf.write(FrameType::MaxPathId);
932        buf.write(self.0);
933    }
934}
935
936#[derive(Debug, Clone, PartialEq, Eq)]
937pub(crate) struct PathsBlocked(pub(crate) PathId);
938
939impl PathsBlocked {
940    pub(crate) const SIZE_BOUND: usize =
941        FrameType::PathsBlocked.size() + VarInt(u32::MAX as u64).size();
942}
943
944impl Encodable for PathsBlocked {
945    fn encode<B: BufMut>(&self, buf: &mut B) {
946        buf.write(FrameType::PathsBlocked);
947        buf.write(self.0);
948    }
949}
950
951impl Decodable for PathsBlocked {
952    /// Decode [`Self`] from the buffer, provided that the frame type has been verified
953    fn decode<B: Buf>(buf: &mut B) -> coding::Result<Self> {
954        Ok(Self(buf.get()?))
955    }
956}
957
958#[derive(Debug, Clone, PartialEq, Eq)]
959pub(crate) struct PathCidsBlocked {
960    pub(crate) path_id: PathId,
961    pub(crate) next_seq: VarInt,
962}
963
964impl PathCidsBlocked {
965    pub(crate) const SIZE_BOUND: usize =
966        FrameType::PathCidsBlocked.size() + VarInt(u32::MAX as u64).size() + VarInt::MAX.size();
967}
968
969impl Decodable for PathCidsBlocked {
970    fn decode<R: Buf>(buf: &mut R) -> coding::Result<Self> {
971        Ok(Self {
972            path_id: buf.get()?,
973            next_seq: buf.get()?,
974        })
975    }
976}
977
978impl Encodable for PathCidsBlocked {
979    fn encode<W: BufMut>(&self, buf: &mut W) {
980        buf.write(FrameType::PathCidsBlocked);
981        buf.write(self.path_id);
982        buf.write(self.next_seq);
983    }
984}
985
986pub(crate) struct Iter {
987    bytes: Bytes,
988    last_ty: MaybeFrame,
989}
990
991impl Iter {
992    pub(crate) fn new(payload: Bytes) -> Result<Self, TransportError> {
993        if payload.is_empty() {
994            // "An endpoint MUST treat receipt of a packet containing no frames as a
995            // connection error of type PROTOCOL_VIOLATION."
996            // https://www.rfc-editor.org/rfc/rfc9000.html#name-frames-and-frame-types
997            return Err(TransportError::PROTOCOL_VIOLATION(
998                "packet payload is empty",
999            ));
1000        }
1001
1002        Ok(Self {
1003            bytes: payload,
1004            last_ty: MaybeFrame::None,
1005        })
1006    }
1007
1008    fn take_len(&mut self) -> Result<Bytes, UnexpectedEnd> {
1009        let len = self.bytes.get_var()?;
1010        if len > self.bytes.remaining() as u64 {
1011            return Err(UnexpectedEnd);
1012        }
1013        Ok(self.bytes.split_to(len as usize))
1014    }
1015
1016    #[track_caller]
1017    fn try_next(&mut self) -> Result<Frame, IterErr> {
1018        self.last_ty = self.bytes.get()?;
1019
1020        let ty = match self.last_ty {
1021            MaybeFrame::None => FrameType::Padding,
1022            MaybeFrame::Unknown(_other) => return Err(IterErr::InvalidFrameId),
1023            MaybeFrame::Known(frame_type) => frame_type,
1024        };
1025        Ok(match ty {
1026            FrameType::Padding => Frame::Padding,
1027            FrameType::ResetStream => Frame::ResetStream(ResetStream {
1028                id: self.bytes.get()?,
1029                error_code: self.bytes.get()?,
1030                final_offset: self.bytes.get()?,
1031            }),
1032            FrameType::ConnectionClose => Frame::Close(Close::Connection(ConnectionClose {
1033                error_code: self.bytes.get()?,
1034                frame_type: self.bytes.get()?,
1035                reason: self.take_len()?,
1036            })),
1037            FrameType::ApplicationClose => Frame::Close(Close::Application(ApplicationClose {
1038                error_code: self.bytes.get()?,
1039                reason: self.take_len()?,
1040            })),
1041            FrameType::MaxData => Frame::MaxData(self.bytes.get()?),
1042            FrameType::MaxStreamData => Frame::MaxStreamData {
1043                id: self.bytes.get()?,
1044                offset: self.bytes.get_var()?,
1045            },
1046            FrameType::MaxStreamsBidi => Frame::MaxStreams {
1047                dir: Dir::Bi,
1048                count: self.bytes.get_var()?,
1049            },
1050            FrameType::MaxStreamsUni => Frame::MaxStreams {
1051                dir: Dir::Uni,
1052                count: self.bytes.get_var()?,
1053            },
1054            FrameType::Ping => Frame::Ping,
1055            FrameType::DataBlocked => Frame::DataBlocked {
1056                offset: self.bytes.get_var()?,
1057            },
1058            FrameType::StreamDataBlocked => Frame::StreamDataBlocked {
1059                id: self.bytes.get()?,
1060                offset: self.bytes.get_var()?,
1061            },
1062            FrameType::StreamsBlockedBidi => Frame::StreamsBlocked {
1063                dir: Dir::Bi,
1064                limit: self.bytes.get_var()?,
1065            },
1066            FrameType::StreamsBlockedUni => Frame::StreamsBlocked {
1067                dir: Dir::Uni,
1068                limit: self.bytes.get_var()?,
1069            },
1070            FrameType::StopSending => Frame::StopSending(StopSending {
1071                id: self.bytes.get()?,
1072                error_code: self.bytes.get()?,
1073            }),
1074            FrameType::RetireConnectionId | FrameType::PathRetireConnectionId => {
1075                Frame::RetireConnectionId(RetireConnectionId::decode(
1076                    &mut self.bytes,
1077                    ty == FrameType::PathRetireConnectionId,
1078                )?)
1079            }
1080            FrameType::Ack | FrameType::AckEcn => {
1081                let largest = self.bytes.get_var()?;
1082                let delay = self.bytes.get_var()?;
1083                let extra_blocks = self.bytes.get_var()? as usize;
1084                let n = scan_ack_blocks(&self.bytes, largest, extra_blocks)?;
1085                Frame::Ack(Ack {
1086                    delay,
1087                    largest,
1088                    additional: self.bytes.split_to(n),
1089                    ecn: if ty != FrameType::AckEcn && ty != FrameType::PathAckEcn {
1090                        None
1091                    } else {
1092                        Some(EcnCounts {
1093                            ect0: self.bytes.get_var()?,
1094                            ect1: self.bytes.get_var()?,
1095                            ce: self.bytes.get_var()?,
1096                        })
1097                    },
1098                })
1099            }
1100            FrameType::PathAck | FrameType::PathAckEcn => {
1101                let path_id = self.bytes.get()?;
1102                let largest = self.bytes.get_var()?;
1103                let delay = self.bytes.get_var()?;
1104                let extra_blocks = self.bytes.get_var()? as usize;
1105                let n = scan_ack_blocks(&self.bytes, largest, extra_blocks)?;
1106                Frame::PathAck(PathAck {
1107                    path_id,
1108                    delay,
1109                    largest,
1110                    additional: self.bytes.split_to(n),
1111                    ecn: if ty != FrameType::AckEcn && ty != FrameType::PathAckEcn {
1112                        None
1113                    } else {
1114                        Some(EcnCounts {
1115                            ect0: self.bytes.get_var()?,
1116                            ect1: self.bytes.get_var()?,
1117                            ce: self.bytes.get_var()?,
1118                        })
1119                    },
1120                })
1121            }
1122            FrameType::PathChallenge => Frame::PathChallenge(self.bytes.get()?),
1123            FrameType::PathResponse => Frame::PathResponse(self.bytes.get()?),
1124            FrameType::NewConnectionId | FrameType::PathNewConnectionId => {
1125                let read_path = ty == FrameType::PathNewConnectionId;
1126                Frame::NewConnectionId(NewConnectionId::read(&mut self.bytes, read_path)?)
1127            }
1128            FrameType::Crypto => Frame::Crypto(Crypto {
1129                offset: self.bytes.get_var()?,
1130                data: self.take_len()?,
1131            }),
1132            FrameType::NewToken => Frame::NewToken(NewToken {
1133                token: self.take_len()?,
1134            }),
1135            FrameType::HandshakeDone => Frame::HandshakeDone,
1136            FrameType::AckFrequency => Frame::AckFrequency(AckFrequency {
1137                sequence: self.bytes.get()?,
1138                ack_eliciting_threshold: self.bytes.get()?,
1139                request_max_ack_delay: self.bytes.get()?,
1140                reordering_threshold: self.bytes.get()?,
1141            }),
1142            FrameType::ImmediateAck => Frame::ImmediateAck,
1143            FrameType::ObservedIpv4Addr | FrameType::ObservedIpv6Addr => {
1144                let is_ipv6 = ty == FrameType::ObservedIpv6Addr;
1145                let observed = ObservedAddr::read(&mut self.bytes, is_ipv6)?;
1146                Frame::ObservedAddr(observed)
1147            }
1148            FrameType::PathAbandon => Frame::PathAbandon(PathAbandon::decode(&mut self.bytes)?),
1149            FrameType::PathStatusAvailable => {
1150                Frame::PathStatusAvailable(PathStatusAvailable::decode(&mut self.bytes)?)
1151            }
1152            FrameType::PathStatusBackup => {
1153                Frame::PathStatusBackup(PathStatusBackup::decode(&mut self.bytes)?)
1154            }
1155            FrameType::MaxPathId => Frame::MaxPathId(MaxPathId::decode(&mut self.bytes)?),
1156            FrameType::PathsBlocked => Frame::PathsBlocked(PathsBlocked::decode(&mut self.bytes)?),
1157            FrameType::PathCidsBlocked => {
1158                Frame::PathCidsBlocked(PathCidsBlocked::decode(&mut self.bytes)?)
1159            }
1160            FrameType::AddIpv4Address | FrameType::AddIpv6Address => {
1161                let is_ipv6 = ty == FrameType::AddIpv6Address;
1162                let add_address = AddAddress::read(&mut self.bytes, is_ipv6)?;
1163                Frame::AddAddress(add_address)
1164            }
1165            FrameType::ReachOutAtIpv4 | FrameType::ReachOutAtIpv6 => {
1166                let is_ipv6 = ty == FrameType::ReachOutAtIpv6;
1167                let reach_out = ReachOut::read(&mut self.bytes, is_ipv6)?;
1168                Frame::ReachOut(reach_out)
1169            }
1170            FrameType::RemoveAddress => Frame::RemoveAddress(RemoveAddress::read(&mut self.bytes)?),
1171            FrameType::Stream(s) => Frame::Stream(Stream {
1172                id: self.bytes.get()?,
1173                offset: if s.off() { self.bytes.get_var()? } else { 0 },
1174                fin: s.fin(),
1175                data: if s.len() {
1176                    self.take_len()?
1177                } else {
1178                    self.take_remaining()
1179                },
1180            }),
1181            FrameType::Datagram(d) => Frame::Datagram(Datagram {
1182                data: if d.len() {
1183                    self.take_len()?
1184                } else {
1185                    self.take_remaining()
1186                },
1187            }),
1188        })
1189    }
1190
1191    fn take_remaining(&mut self) -> Bytes {
1192        mem::take(&mut self.bytes)
1193    }
1194}
1195
1196impl Iterator for Iter {
1197    type Item = Result<Frame, InvalidFrame>;
1198    fn next(&mut self) -> Option<Self::Item> {
1199        if !self.bytes.has_remaining() {
1200            return None;
1201        }
1202        match self.try_next() {
1203            Ok(x) => Some(Ok(x)),
1204            Err(e) => {
1205                // Corrupt frame, skip it and everything that follows
1206                self.bytes.clear();
1207                Some(Err(InvalidFrame {
1208                    ty: self.last_ty,
1209                    reason: e.reason(),
1210                }))
1211            }
1212        }
1213    }
1214}
1215
1216#[derive(Debug)]
1217pub(crate) struct InvalidFrame {
1218    pub(crate) ty: MaybeFrame,
1219    pub(crate) reason: &'static str,
1220}
1221
1222impl From<InvalidFrame> for TransportError {
1223    fn from(err: InvalidFrame) -> Self {
1224        let mut te = Self::FRAME_ENCODING_ERROR(err.reason);
1225        te.frame = err.ty;
1226        te
1227    }
1228}
1229
1230/// Validate exactly `n` ACK ranges in `buf` and return the number of bytes they cover
1231fn scan_ack_blocks(mut buf: &[u8], largest: u64, n: usize) -> Result<usize, IterErr> {
1232    let total_len = buf.remaining();
1233    let first_block = buf.get_var()?;
1234    let mut smallest = largest.checked_sub(first_block).ok_or(IterErr::Malformed)?;
1235    for _ in 0..n {
1236        let gap = buf.get_var()?;
1237        smallest = smallest.checked_sub(gap + 2).ok_or(IterErr::Malformed)?;
1238        let block = buf.get_var()?;
1239        smallest = smallest.checked_sub(block).ok_or(IterErr::Malformed)?;
1240    }
1241    Ok(total_len - buf.remaining())
1242}
1243
1244#[derive(Debug)]
1245enum IterErr {
1246    UnexpectedEnd,
1247    InvalidFrameId,
1248    Malformed,
1249}
1250
1251impl IterErr {
1252    fn reason(&self) -> &'static str {
1253        use IterErr::*;
1254        match *self {
1255            UnexpectedEnd => "unexpected end",
1256            InvalidFrameId => "invalid frame ID",
1257            Malformed => "malformed",
1258        }
1259    }
1260}
1261
1262impl From<UnexpectedEnd> for IterErr {
1263    fn from(_: UnexpectedEnd) -> Self {
1264        Self::UnexpectedEnd
1265    }
1266}
1267
1268#[derive(Debug, Clone)]
1269pub struct AckIter<'a> {
1270    largest: u64,
1271    data: &'a [u8],
1272}
1273
1274impl<'a> AckIter<'a> {
1275    fn new(largest: u64, data: &'a [u8]) -> Self {
1276        Self { largest, data }
1277    }
1278}
1279
1280impl Iterator for AckIter<'_> {
1281    type Item = RangeInclusive<u64>;
1282    fn next(&mut self) -> Option<RangeInclusive<u64>> {
1283        if !self.data.has_remaining() {
1284            return None;
1285        }
1286        let block = self.data.get_var().unwrap();
1287        let largest = self.largest;
1288        if let Ok(gap) = self.data.get_var() {
1289            self.largest -= block + gap + 2;
1290        }
1291        Some(largest - block..=largest)
1292    }
1293}
1294
1295#[allow(unreachable_pub)] // fuzzing only
1296#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
1297#[derive(Debug, Copy, Clone)]
1298pub struct ResetStream {
1299    pub(crate) id: StreamId,
1300    pub(crate) error_code: VarInt,
1301    pub(crate) final_offset: VarInt,
1302}
1303
1304impl FrameStruct for ResetStream {
1305    const SIZE_BOUND: usize = 1 + 8 + 8 + 8;
1306}
1307
1308impl Encodable for ResetStream {
1309    fn encode<W: BufMut>(&self, out: &mut W) {
1310        out.write(FrameType::ResetStream); // 1 byte
1311        out.write(self.id); // <= 8 bytes
1312        out.write(self.error_code); // <= 8 bytes
1313        out.write(self.final_offset); // <= 8 bytes
1314    }
1315}
1316
1317#[derive(Debug, Copy, Clone)]
1318pub(crate) struct StopSending {
1319    pub(crate) id: StreamId,
1320    pub(crate) error_code: VarInt,
1321}
1322
1323impl FrameStruct for StopSending {
1324    const SIZE_BOUND: usize = 1 + 8 + 8;
1325}
1326
1327impl Encodable for StopSending {
1328    fn encode<W: BufMut>(&self, out: &mut W) {
1329        out.write(FrameType::StopSending); // 1 byte
1330        out.write(self.id); // <= 8 bytes
1331        out.write(self.error_code) // <= 8 bytes
1332    }
1333}
1334
1335#[derive(Debug, Copy, Clone, PartialEq, Eq)]
1336pub(crate) struct NewConnectionId {
1337    pub(crate) path_id: Option<PathId>,
1338    pub(crate) sequence: u64,
1339    pub(crate) retire_prior_to: u64,
1340    pub(crate) id: ConnectionId,
1341    pub(crate) reset_token: ResetToken,
1342}
1343
1344impl NewConnectionId {
1345    /// Maximum size of this frame when the frame type is [`FrameType::NewConnectionId`],
1346    pub(crate) const SIZE_BOUND: usize = {
1347        let type_len = FrameType::NewConnectionId.size();
1348        let seq_max_len = 8usize;
1349        let retire_prior_to_max_len = 8usize;
1350        let cid_len_len = 1;
1351        let cid_len = 160;
1352        let reset_token_len = 16;
1353        type_len + seq_max_len + retire_prior_to_max_len + cid_len_len + cid_len + reset_token_len
1354    };
1355
1356    /// Maximum size of this frame when the frame type is [`FrameType::PathNewConnectionId`],
1357    pub(crate) const SIZE_BOUND_MULTIPATH: usize = {
1358        let type_len = FrameType::PathNewConnectionId.size();
1359        let path_id_len = VarInt::from_u32(u32::MAX).size();
1360        let seq_max_len = 8usize;
1361        let retire_prior_to_max_len = 8usize;
1362        let cid_len_len = 1;
1363        let cid_len = 160;
1364        let reset_token_len = 16;
1365        type_len
1366            + path_id_len
1367            + seq_max_len
1368            + retire_prior_to_max_len
1369            + cid_len_len
1370            + cid_len
1371            + reset_token_len
1372    };
1373
1374    pub(crate) fn get_type(&self) -> FrameType {
1375        if self.path_id.is_some() {
1376            FrameType::PathNewConnectionId
1377        } else {
1378            FrameType::NewConnectionId
1379        }
1380    }
1381
1382    /// Returns the maximum encoded size on the wire.
1383    ///
1384    /// This is a rough upper estimate, does not squeeze every last byte out.
1385    pub(crate) const fn size_bound(path_new_cid: bool, cid_len: usize) -> usize {
1386        let upper_bound = match path_new_cid {
1387            true => Self::SIZE_BOUND_MULTIPATH,
1388            false => Self::SIZE_BOUND,
1389        };
1390        // instead of using the maximum cid len, use the provided one
1391        upper_bound - 160 + cid_len
1392    }
1393
1394    fn read<R: Buf>(bytes: &mut R, read_path: bool) -> Result<Self, IterErr> {
1395        let path_id = if read_path { Some(bytes.get()?) } else { None };
1396        let sequence = bytes.get_var()?;
1397        let retire_prior_to = bytes.get_var()?;
1398        if retire_prior_to > sequence {
1399            return Err(IterErr::Malformed);
1400        }
1401        let length = bytes.get::<u8>()? as usize;
1402        if length > MAX_CID_SIZE || length == 0 {
1403            return Err(IterErr::Malformed);
1404        }
1405        if length > bytes.remaining() {
1406            return Err(IterErr::UnexpectedEnd);
1407        }
1408        let mut stage = [0; MAX_CID_SIZE];
1409        bytes.copy_to_slice(&mut stage[0..length]);
1410        let id = ConnectionId::new(&stage[..length]);
1411        if bytes.remaining() < 16 {
1412            return Err(IterErr::UnexpectedEnd);
1413        }
1414        let mut reset_token = [0; RESET_TOKEN_SIZE];
1415        bytes.copy_to_slice(&mut reset_token);
1416        Ok(Self {
1417            path_id,
1418            sequence,
1419            retire_prior_to,
1420            id,
1421            reset_token: reset_token.into(),
1422        })
1423    }
1424}
1425
1426impl Encodable for NewConnectionId {
1427    fn encode<W: BufMut>(&self, out: &mut W) {
1428        out.write(self.get_type());
1429        if let Some(id) = self.path_id {
1430            out.write(id);
1431        }
1432        out.write_var(self.sequence);
1433        out.write_var(self.retire_prior_to);
1434        out.write(self.id.len() as u8);
1435        out.put_slice(&self.id);
1436        out.put_slice(&self.reset_token);
1437    }
1438}
1439
1440impl FrameStruct for NewConnectionId {
1441    const SIZE_BOUND: usize = 1 + 8 + 8 + 1 + MAX_CID_SIZE + RESET_TOKEN_SIZE;
1442}
1443
1444/// An unreliable datagram
1445#[derive(Debug, Clone)]
1446pub struct Datagram {
1447    /// Payload
1448    pub data: Bytes,
1449}
1450
1451impl FrameStruct for Datagram {
1452    const SIZE_BOUND: usize = 1 + 8;
1453}
1454
1455impl Datagram {
1456    pub(crate) fn encode(&self, length: bool, out: &mut impl BufMut) {
1457        out.write(FrameType::Datagram(DatagramInfo(
1458            *DatagramInfo::VALUES.start() as u8 | u8::from(length),
1459        ))); // 1 byte
1460        if length {
1461            // Safe to unwrap because we check length sanity before queueing datagrams
1462            out.write(VarInt::from_u64(self.data.len() as u64).unwrap()); // <= 8 bytes
1463        }
1464        out.put_slice(&self.data);
1465    }
1466
1467    pub(crate) fn size(&self, length: bool) -> usize {
1468        1 + if length {
1469            VarInt::from_u64(self.data.len() as u64).unwrap().size()
1470        } else {
1471            0
1472        } + self.data.len()
1473    }
1474}
1475
1476#[derive(Debug, Copy, Clone, PartialEq, Eq)]
1477pub(crate) struct AckFrequency {
1478    pub(crate) sequence: VarInt,
1479    pub(crate) ack_eliciting_threshold: VarInt,
1480    pub(crate) request_max_ack_delay: VarInt,
1481    pub(crate) reordering_threshold: VarInt,
1482}
1483
1484impl Encodable for AckFrequency {
1485    fn encode<W: BufMut>(&self, buf: &mut W) {
1486        buf.write(FrameType::AckFrequency);
1487        buf.write(self.sequence);
1488        buf.write(self.ack_eliciting_threshold);
1489        buf.write(self.request_max_ack_delay);
1490        buf.write(self.reordering_threshold);
1491    }
1492}
1493
1494/* Address Discovery https://datatracker.ietf.org/doc/draft-seemann-quic-address-discovery/ */
1495
1496/// Conjunction of the information contained in the address discovery frames
1497/// ([`FrameType::ObservedIpv4Addr`], [`FrameType::ObservedIpv6Addr`]).
1498#[derive(Debug, PartialEq, Eq, Clone)]
1499pub(crate) struct ObservedAddr {
1500    /// Monotonically increasing integer within the same connection.
1501    pub(crate) seq_no: VarInt,
1502    /// Reported observed address.
1503    pub(crate) ip: IpAddr,
1504    /// Reported observed port.
1505    pub(crate) port: u16,
1506}
1507
1508impl ObservedAddr {
1509    pub(crate) fn new<N: Into<VarInt>>(remote: std::net::SocketAddr, seq_no: N) -> Self {
1510        Self {
1511            ip: remote.ip(),
1512            port: remote.port(),
1513            seq_no: seq_no.into(),
1514        }
1515    }
1516
1517    /// Get the [`FrameType`] for this frame.
1518    pub(crate) fn get_type(&self) -> FrameType {
1519        if self.ip.is_ipv6() {
1520            FrameType::ObservedIpv6Addr
1521        } else {
1522            FrameType::ObservedIpv4Addr
1523        }
1524    }
1525
1526    /// Compute the number of bytes needed to encode the frame.
1527    pub(crate) fn size(&self) -> usize {
1528        let type_size = self.get_type().size();
1529        let req_id_bytes = self.seq_no.size();
1530        let ip_bytes = if self.ip.is_ipv6() { 16 } else { 4 };
1531        let port_bytes = 2;
1532        type_size + req_id_bytes + ip_bytes + port_bytes
1533    }
1534
1535    /// Reads the frame contents from the buffer.
1536    ///
1537    /// Should only be called when the frame type has been identified as
1538    /// [`FrameType::ObservedIpv4Addr`] or [`FrameType::ObservedIpv6Addr`].
1539    pub(crate) fn read<R: Buf>(bytes: &mut R, is_ipv6: bool) -> coding::Result<Self> {
1540        let seq_no = bytes.get()?;
1541        let ip = if is_ipv6 {
1542            IpAddr::V6(bytes.get()?)
1543        } else {
1544            IpAddr::V4(bytes.get()?)
1545        };
1546        let port = bytes.get()?;
1547        Ok(Self { seq_no, ip, port })
1548    }
1549
1550    /// Gives the [`SocketAddr`] reported in the frame.
1551    pub(crate) fn socket_addr(&self) -> SocketAddr {
1552        (self.ip, self.port).into()
1553    }
1554}
1555
1556impl Encodable for ObservedAddr {
1557    fn encode<W: BufMut>(&self, buf: &mut W) {
1558        buf.write(self.get_type());
1559        buf.write(self.seq_no);
1560        match self.ip {
1561            IpAddr::V4(ipv4_addr) => {
1562                buf.write(ipv4_addr);
1563            }
1564            IpAddr::V6(ipv6_addr) => {
1565                buf.write(ipv6_addr);
1566            }
1567        }
1568        buf.write::<u16>(self.port);
1569    }
1570}
1571
1572/* Multipath <https://datatracker.ietf.org/doc/draft-ietf-quic-multipath/> */
1573
1574#[derive(Debug, PartialEq, Eq)]
1575pub(crate) struct PathAbandon {
1576    pub(crate) path_id: PathId,
1577    pub(crate) error_code: TransportErrorCode,
1578}
1579
1580impl PathAbandon {
1581    pub(crate) const SIZE_BOUND: usize = FrameType::PathAbandon.size() + 8 + 8;
1582}
1583
1584impl Encodable for PathAbandon {
1585    fn encode<W: BufMut>(&self, buf: &mut W) {
1586        buf.write(FrameType::PathAbandon);
1587        buf.write(self.path_id);
1588        buf.write(self.error_code);
1589    }
1590}
1591
1592impl Decodable for PathAbandon {
1593    fn decode<R: Buf>(bytes: &mut R) -> coding::Result<Self> {
1594        Ok(Self {
1595            path_id: bytes.get()?,
1596            error_code: bytes.get()?,
1597        })
1598    }
1599}
1600
1601#[derive(Debug, PartialEq, Eq)]
1602pub(crate) struct PathStatusAvailable {
1603    pub(crate) path_id: PathId,
1604    pub(crate) status_seq_no: VarInt,
1605}
1606
1607impl PathStatusAvailable {
1608    const TYPE: FrameType = FrameType::PathStatusAvailable;
1609    pub(crate) const SIZE_BOUND: usize = FrameType::PathStatusAvailable.size() + 8 + 8;
1610}
1611
1612impl Encodable for PathStatusAvailable {
1613    fn encode<W: BufMut>(&self, buf: &mut W) {
1614        buf.write(Self::TYPE);
1615        buf.write(self.path_id);
1616        buf.write(self.status_seq_no);
1617    }
1618}
1619
1620impl Decodable for PathStatusAvailable {
1621    fn decode<R: Buf>(bytes: &mut R) -> coding::Result<Self> {
1622        Ok(Self {
1623            path_id: bytes.get()?,
1624            status_seq_no: bytes.get()?,
1625        })
1626    }
1627}
1628
1629#[derive(Debug, PartialEq, Eq)]
1630pub(crate) struct PathStatusBackup {
1631    pub(crate) path_id: PathId,
1632    pub(crate) status_seq_no: VarInt,
1633}
1634
1635impl PathStatusBackup {
1636    const TYPE: FrameType = FrameType::PathStatusBackup;
1637}
1638
1639impl Encodable for PathStatusBackup {
1640    fn encode<W: BufMut>(&self, buf: &mut W) {
1641        buf.write(Self::TYPE);
1642        buf.write(self.path_id);
1643        buf.write(self.status_seq_no);
1644    }
1645}
1646
1647impl Decodable for PathStatusBackup {
1648    fn decode<R: Buf>(bytes: &mut R) -> coding::Result<Self> {
1649        Ok(Self {
1650            path_id: bytes.get()?,
1651            status_seq_no: bytes.get()?,
1652        })
1653    }
1654}
1655
1656/* Nat traversal frames */
1657
1658/// Conjunction of the information contained in the add address frames
1659/// ([`FrameType::AddIpv4Address`], [`FrameType::AddIpv6Address`]).
1660#[derive(Debug, PartialEq, Eq, Copy, Clone, PartialOrd, Ord)]
1661// TODO(@divma): remove
1662#[allow(dead_code)]
1663pub(crate) struct AddAddress {
1664    /// Monotonically increasing integer within the same connection
1665    // TODO(@divma): both assumed, the draft has no mention of this but it's standard
1666    pub(crate) seq_no: VarInt,
1667    /// Address to include in the known set
1668    pub(crate) ip: IpAddr,
1669    /// Port to use with this address
1670    pub(crate) port: u16,
1671}
1672
1673// TODO(@divma): remove
1674#[allow(dead_code)]
1675impl AddAddress {
1676    /// Smallest number of bytes this type of frame is guaranteed to fit within.
1677    pub(crate) const SIZE_BOUND: usize = Self {
1678        ip: IpAddr::V6(std::net::Ipv6Addr::LOCALHOST),
1679        port: u16::MAX,
1680        seq_no: VarInt::MAX,
1681    }
1682    .size();
1683
1684    pub(crate) const fn new((ip, port): (IpAddr, u16), seq_no: VarInt) -> Self {
1685        Self { ip, port, seq_no }
1686    }
1687
1688    /// Get the [`FrameType`] for this frame.
1689    pub(crate) const fn get_type(&self) -> FrameType {
1690        if self.ip.is_ipv6() {
1691            FrameType::AddIpv6Address
1692        } else {
1693            FrameType::AddIpv4Address
1694        }
1695    }
1696
1697    /// Compute the number of bytes needed to encode the frame
1698    pub(crate) const fn size(&self) -> usize {
1699        let type_size = self.get_type().size();
1700        let seq_no_bytes = self.seq_no.size();
1701        let ip_bytes = if self.ip.is_ipv6() { 16 } else { 4 };
1702        let port_bytes = 2;
1703        type_size + seq_no_bytes + ip_bytes + port_bytes
1704    }
1705
1706    /// Read the frame contents from the buffer
1707    ///
1708    /// Should only be called when the frame type has been identified as
1709    /// [`FrameType::AddIpv4Address`] or [`FrameType::AddIpv6Address`].
1710    pub(crate) fn read<R: Buf>(bytes: &mut R, is_ipv6: bool) -> coding::Result<Self> {
1711        let seq_no = bytes.get()?;
1712        let ip = if is_ipv6 {
1713            IpAddr::V6(bytes.get()?)
1714        } else {
1715            IpAddr::V4(bytes.get()?)
1716        };
1717        let port = bytes.get()?;
1718        Ok(Self { seq_no, ip, port })
1719    }
1720
1721    /// Give the [`SocketAddr`] encoded in the frame
1722    pub(crate) fn socket_addr(&self) -> SocketAddr {
1723        self.ip_port().into()
1724    }
1725
1726    pub(crate) fn ip_port(&self) -> (IpAddr, u16) {
1727        (self.ip, self.port)
1728    }
1729}
1730
1731impl Encodable for AddAddress {
1732    fn encode<W: BufMut>(&self, buf: &mut W) {
1733        buf.write(self.get_type());
1734        buf.write(self.seq_no);
1735        match self.ip {
1736            IpAddr::V4(ipv4_addr) => {
1737                buf.write(ipv4_addr);
1738            }
1739            IpAddr::V6(ipv6_addr) => {
1740                buf.write(ipv6_addr);
1741            }
1742        }
1743        buf.write::<u16>(self.port);
1744    }
1745}
1746
1747/// Conjunction of the information contained in the reach out frames
1748/// ([`FrameType::ReachOutAtIpv4`], [`FrameType::ReachOutAtIpv6`])
1749#[derive(Debug, PartialEq, Eq, Clone)]
1750// TODO(@divma): remove
1751#[allow(dead_code)]
1752pub(crate) struct ReachOut {
1753    /// The sequence number of the NAT Traversal attempts
1754    pub(crate) round: VarInt,
1755    /// Address to use
1756    pub(crate) ip: IpAddr,
1757    /// Port to use with this address
1758    pub(crate) port: u16,
1759}
1760
1761// TODO(@divma): remove
1762#[allow(dead_code)]
1763impl ReachOut {
1764    /// Smallest number of bytes this type of frame is guaranteed to fit within
1765    pub(crate) const SIZE_BOUND: usize = Self {
1766        round: VarInt::MAX,
1767        ip: IpAddr::V6(std::net::Ipv6Addr::LOCALHOST),
1768        port: u16::MAX,
1769    }
1770    .size();
1771
1772    pub(crate) const fn new(round: VarInt, (ip, port): (IpAddr, u16)) -> Self {
1773        Self { round, ip, port }
1774    }
1775
1776    /// Get the [`FrameType`] for this frame
1777    pub(crate) const fn get_type(&self) -> FrameType {
1778        if self.ip.is_ipv6() {
1779            FrameType::ReachOutAtIpv6
1780        } else {
1781            FrameType::ReachOutAtIpv4
1782        }
1783    }
1784
1785    /// Compute the number of bytes needed to encode the frame
1786    pub(crate) const fn size(&self) -> usize {
1787        let type_size = self.get_type().size();
1788        let round_bytes = self.round.size();
1789        let ip_bytes = if self.ip.is_ipv6() { 16 } else { 4 };
1790        let port_bytes = 2;
1791        type_size + round_bytes + ip_bytes + port_bytes
1792    }
1793
1794    /// Read the frame contents from the buffer
1795    ///
1796    /// Should only be called when the frame type has been identified as
1797    /// [`FrameType::ReachOutAtIpv4`] or [`FrameType::ReachOutAtIpv6`].
1798    pub(crate) fn read<R: Buf>(bytes: &mut R, is_ipv6: bool) -> coding::Result<Self> {
1799        let round = bytes.get()?;
1800        let ip = if is_ipv6 {
1801            IpAddr::V6(bytes.get()?)
1802        } else {
1803            IpAddr::V4(bytes.get()?)
1804        };
1805        let port = bytes.get()?;
1806        Ok(Self { round, ip, port })
1807    }
1808
1809    /// Give the [`SocketAddr`] encoded in the frame
1810    pub(crate) fn socket_addr(&self) -> SocketAddr {
1811        (self.ip, self.port).into()
1812    }
1813}
1814
1815impl Encodable for ReachOut {
1816    fn encode<W: BufMut>(&self, buf: &mut W) {
1817        buf.write(self.get_type());
1818        buf.write(self.round);
1819        match self.ip {
1820            IpAddr::V4(ipv4_addr) => {
1821                buf.write(ipv4_addr);
1822            }
1823            IpAddr::V6(ipv6_addr) => {
1824                buf.write(ipv6_addr);
1825            }
1826        }
1827        buf.write::<u16>(self.port);
1828    }
1829}
1830
1831/// Frame signaling an address is no longer being advertised
1832#[derive(Debug, PartialEq, Eq, Copy, Clone, PartialOrd, Ord)]
1833// TODO(@divma): remove
1834#[allow(dead_code)]
1835pub(crate) struct RemoveAddress {
1836    /// The sequence number of the address advertisement to be removed
1837    pub(crate) seq_no: VarInt,
1838}
1839
1840// TODO(@divma): remove
1841#[allow(dead_code)]
1842impl RemoveAddress {
1843    /// [`FrameType`] of this frame
1844    pub(crate) const TYPE: FrameType = FrameType::RemoveAddress;
1845
1846    /// Smallest number of bytes this type of frame is guaranteed to fit within
1847    pub(crate) const SIZE_BOUND: usize = Self::new(VarInt::MAX).size();
1848
1849    pub(crate) const fn new(seq_no: VarInt) -> Self {
1850        Self { seq_no }
1851    }
1852
1853    /// Compute the number of bytes needed to encode the frame
1854    pub(crate) const fn size(&self) -> usize {
1855        let type_size = Self::TYPE.size();
1856        let seq_no_bytes = self.seq_no.size();
1857        type_size + seq_no_bytes
1858    }
1859
1860    /// Read the frame contents from the buffer
1861    ///
1862    /// Should only be called when the frame type has been identified as
1863    /// [`FrameType::RemoveAddress`].
1864    pub(crate) fn read<R: Buf>(bytes: &mut R) -> coding::Result<Self> {
1865        Ok(Self {
1866            seq_no: bytes.get()?,
1867        })
1868    }
1869}
1870
1871impl Encodable for RemoveAddress {
1872    fn encode<W: BufMut>(&self, buf: &mut W) {
1873        buf.write(Self::TYPE);
1874        buf.write(self.seq_no);
1875    }
1876}
1877
1878#[cfg(test)]
1879mod test {
1880    use super::*;
1881    use crate::coding::Encodable;
1882    use assert_matches::assert_matches;
1883
1884    #[track_caller]
1885    fn frames(buf: Vec<u8>) -> Vec<Frame> {
1886        Iter::new(Bytes::from(buf))
1887            .unwrap()
1888            .collect::<Result<Vec<_>, _>>()
1889            .unwrap()
1890    }
1891
1892    #[test]
1893    fn ack_coding() {
1894        const PACKETS: &[u64] = &[1, 2, 3, 5, 10, 11, 14];
1895        let mut ranges = ArrayRangeSet::new();
1896        for &packet in PACKETS {
1897            ranges.insert(packet..packet + 1);
1898        }
1899        let mut buf = Vec::new();
1900        const ECN: EcnCounts = EcnCounts {
1901            ect0: 42,
1902            ect1: 24,
1903            ce: 12,
1904        };
1905        Ack::encode(42, &ranges, Some(&ECN), &mut buf);
1906        let frames = frames(buf);
1907        assert_eq!(frames.len(), 1);
1908        match frames[0] {
1909            Frame::Ack(ref ack) => {
1910                let mut packets = ack.iter().flatten().collect::<Vec<_>>();
1911                packets.sort_unstable();
1912                assert_eq!(&packets[..], PACKETS);
1913                assert_eq!(ack.ecn, Some(ECN));
1914            }
1915            ref x => panic!("incorrect frame {x:?}"),
1916        }
1917    }
1918
1919    #[test]
1920    #[allow(clippy::range_plus_one)]
1921    fn path_ack_coding() {
1922        const PACKETS: &[u64] = &[1, 2, 3, 5, 10, 11, 14];
1923        let mut ranges = ArrayRangeSet::new();
1924        for &packet in PACKETS {
1925            ranges.insert(packet..packet + 1);
1926        }
1927        let mut buf = Vec::new();
1928        const ECN: EcnCounts = EcnCounts {
1929            ect0: 42,
1930            ect1: 24,
1931            ce: 12,
1932        };
1933        const PATH_ID: PathId = PathId::MAX;
1934        PathAck::encode(PATH_ID, 42, &ranges, Some(&ECN), &mut buf);
1935        let frames = frames(buf);
1936        assert_eq!(frames.len(), 1);
1937        match frames[0] {
1938            Frame::PathAck(ref ack) => {
1939                assert_eq!(ack.path_id, PATH_ID);
1940                let mut packets = ack.into_iter().flatten().collect::<Vec<_>>();
1941                packets.sort_unstable();
1942                assert_eq!(&packets[..], PACKETS);
1943                assert_eq!(ack.ecn, Some(ECN));
1944            }
1945            ref x => panic!("incorrect frame {x:?}"),
1946        }
1947    }
1948
1949    #[test]
1950    fn ack_frequency_coding() {
1951        let mut buf = Vec::new();
1952        let original = AckFrequency {
1953            sequence: VarInt(42),
1954            ack_eliciting_threshold: VarInt(20),
1955            request_max_ack_delay: VarInt(50_000),
1956            reordering_threshold: VarInt(1),
1957        };
1958        original.encode(&mut buf);
1959        let frames = frames(buf);
1960        assert_eq!(frames.len(), 1);
1961        match &frames[0] {
1962            Frame::AckFrequency(decoded) => assert_eq!(decoded, &original),
1963            x => panic!("incorrect frame {x:?}"),
1964        }
1965    }
1966
1967    #[test]
1968    fn immediate_ack_coding() {
1969        let mut buf = Vec::new();
1970        FrameType::ImmediateAck.encode(&mut buf);
1971        let frames = frames(buf);
1972        assert_eq!(frames.len(), 1);
1973        assert_matches!(&frames[0], Frame::ImmediateAck);
1974    }
1975
1976    /// Test that encoding and decoding [`ObservedAddr`] produces the same result.
1977    #[test]
1978    fn test_observed_addr_roundrip() {
1979        let observed_addr = ObservedAddr {
1980            seq_no: VarInt(42),
1981            ip: std::net::Ipv4Addr::LOCALHOST.into(),
1982            port: 4242,
1983        };
1984        let mut buf = Vec::with_capacity(observed_addr.size());
1985        observed_addr.encode(&mut buf);
1986
1987        assert_eq!(
1988            observed_addr.size(),
1989            buf.len(),
1990            "expected written bytes and actual size differ"
1991        );
1992
1993        let mut decoded = frames(buf);
1994        assert_eq!(decoded.len(), 1);
1995        match decoded.pop().expect("non empty") {
1996            Frame::ObservedAddr(decoded) => assert_eq!(decoded, observed_addr),
1997            x => panic!("incorrect frame {x:?}"),
1998        }
1999    }
2000
2001    #[test]
2002    fn test_path_abandon_roundtrip() {
2003        let abandon = PathAbandon {
2004            path_id: PathId(42),
2005            error_code: TransportErrorCode::NO_ERROR,
2006        };
2007        let mut buf = Vec::new();
2008        abandon.encode(&mut buf);
2009
2010        let mut decoded = frames(buf);
2011        assert_eq!(decoded.len(), 1);
2012        match decoded.pop().expect("non empty") {
2013            Frame::PathAbandon(decoded) => assert_eq!(decoded, abandon),
2014            x => panic!("incorrect frame {x:?}"),
2015        }
2016    }
2017
2018    #[test]
2019    fn test_path_status_available_roundtrip() {
2020        let path_status_available = PathStatusAvailable {
2021            path_id: PathId(42),
2022            status_seq_no: VarInt(73),
2023        };
2024        let mut buf = Vec::new();
2025        path_status_available.encode(&mut buf);
2026
2027        let mut decoded = frames(buf);
2028        assert_eq!(decoded.len(), 1);
2029        match decoded.pop().expect("non empty") {
2030            Frame::PathStatusAvailable(decoded) => assert_eq!(decoded, path_status_available),
2031            x => panic!("incorrect frame {x:?}"),
2032        }
2033    }
2034
2035    #[test]
2036    fn test_path_status_backup_roundtrip() {
2037        let path_status_backup = PathStatusBackup {
2038            path_id: PathId(42),
2039            status_seq_no: VarInt(73),
2040        };
2041        let mut buf = Vec::new();
2042        path_status_backup.encode(&mut buf);
2043
2044        let mut decoded = frames(buf);
2045        assert_eq!(decoded.len(), 1);
2046        match decoded.pop().expect("non empty") {
2047            Frame::PathStatusBackup(decoded) => assert_eq!(decoded, path_status_backup),
2048            x => panic!("incorrect frame {x:?}"),
2049        }
2050    }
2051
2052    #[test]
2053    fn test_path_new_connection_id_roundtrip() {
2054        let cid = NewConnectionId {
2055            path_id: Some(PathId(22)),
2056            sequence: 31,
2057            retire_prior_to: 13,
2058            id: ConnectionId::new(&[0xAB; 8]),
2059            reset_token: ResetToken::from([0xCD; crate::RESET_TOKEN_SIZE]),
2060        };
2061        let mut buf = Vec::new();
2062        cid.encode(&mut buf);
2063
2064        let mut decoded = frames(buf);
2065        assert_eq!(decoded.len(), 1);
2066        match decoded.pop().expect("non empty") {
2067            Frame::NewConnectionId(decoded) => assert_eq!(decoded, cid),
2068            x => panic!("incorrect frame {x:?}"),
2069        }
2070    }
2071
2072    #[test]
2073    fn test_path_retire_connection_id_roundtrip() {
2074        let retire_cid = RetireConnectionId {
2075            path_id: Some(PathId(22)),
2076            sequence: 31,
2077        };
2078        let mut buf = Vec::new();
2079        retire_cid.encode(&mut buf);
2080
2081        let mut decoded = frames(buf);
2082        assert_eq!(decoded.len(), 1);
2083        match decoded.pop().expect("non empty") {
2084            Frame::RetireConnectionId(decoded) => assert_eq!(decoded, retire_cid),
2085            x => panic!("incorrect frame {x:?}"),
2086        }
2087    }
2088
2089    #[test]
2090    fn test_paths_blocked_path_cids_blocked_roundtrip() {
2091        let mut buf = Vec::new();
2092
2093        let frame0 = PathsBlocked(PathId(22));
2094        frame0.encode(&mut buf);
2095        let frame1 = PathCidsBlocked {
2096            path_id: PathId(23),
2097            next_seq: VarInt(32),
2098        };
2099        frame1.encode(&mut buf);
2100
2101        let mut decoded = frames(buf);
2102        assert_eq!(decoded.len(), 2);
2103        match decoded.pop().expect("non empty") {
2104            Frame::PathCidsBlocked(decoded) => assert_eq!(decoded, frame1),
2105            x => panic!("incorrect frame {x:?}"),
2106        }
2107        match decoded.pop().expect("non empty") {
2108            Frame::PathsBlocked(decoded) => assert_eq!(decoded, frame0),
2109            x => panic!("incorrect frame {x:?}"),
2110        }
2111    }
2112
2113    /// Test that encoding and decoding [`AddAddress`] produces the same result
2114    #[test]
2115    fn test_add_address_roundrip() {
2116        let add_address = AddAddress {
2117            seq_no: VarInt(42),
2118            ip: std::net::Ipv4Addr::LOCALHOST.into(),
2119            port: 4242,
2120        };
2121        let mut buf = Vec::with_capacity(add_address.size());
2122        add_address.encode(&mut buf);
2123
2124        assert_eq!(
2125            add_address.size(),
2126            buf.len(),
2127            "expected written bytes and actual size differ"
2128        );
2129
2130        let mut decoded = frames(buf);
2131        assert_eq!(decoded.len(), 1);
2132        match decoded.pop().expect("non empty") {
2133            Frame::AddAddress(decoded) => assert_eq!(decoded, add_address),
2134            x => panic!("incorrect frame {x:?}"),
2135        }
2136    }
2137
2138    /// Test that encoding and decoding [`AddAddress`] produces the same result
2139    #[test]
2140    fn test_reach_out_roundrip() {
2141        let reach_out = ReachOut {
2142            round: VarInt(42),
2143            ip: std::net::Ipv6Addr::LOCALHOST.into(),
2144            port: 4242,
2145        };
2146        let mut buf = Vec::with_capacity(reach_out.size());
2147        reach_out.encode(&mut buf);
2148
2149        assert_eq!(
2150            reach_out.size(),
2151            buf.len(),
2152            "expected written bytes and actual size differ"
2153        );
2154
2155        let mut decoded = frames(buf);
2156        assert_eq!(decoded.len(), 1);
2157        match decoded.pop().expect("non empty") {
2158            Frame::ReachOut(decoded) => assert_eq!(decoded, reach_out),
2159            x => panic!("incorrect frame {x:?}"),
2160        }
2161    }
2162
2163    /// Test that encoding and decoding [`RemoveAddress`] produces the same result
2164    #[test]
2165    fn test_remove_address_roundrip() {
2166        let remove_addr = RemoveAddress::new(VarInt(10));
2167        let mut buf = Vec::with_capacity(remove_addr.size());
2168        remove_addr.encode(&mut buf);
2169
2170        assert_eq!(
2171            remove_addr.size(),
2172            buf.len(),
2173            "expected written bytes and actual size differ"
2174        );
2175
2176        let mut decoded = frames(buf);
2177        assert_eq!(decoded.len(), 1);
2178        match decoded.pop().expect("non empty") {
2179            Frame::RemoveAddress(decoded) => assert_eq!(decoded, remove_addr),
2180            x => panic!("incorrect frame {x:?}"),
2181        }
2182    }
2183}