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