Skip to main content

net_wire/quic/packet/
parse.rs

1//! QUIC packet-view parsing errors.
2
3use core::fmt;
4
5use super::header::{QuicConnectionIdField, QuicLongPacketType, QuicVersion};
6
7/// Failure to parse a QUIC packet-header view.
8#[derive(Clone, Copy, Debug, Eq, PartialEq)]
9pub enum QuicPacketParseError {
10    /// A supplied UDP datagram contains no packet bytes.
11    EmptyDatagram,
12    /// A short-header packet cannot be delimited without caller-supplied destination ID context.
13    ShortHeaderContextRequired,
14    /// The first byte has the opposite QUIC header form from the requested view.
15    WrongHeaderForm {
16        /// Whether the requested view requires the long-header form bit to be set.
17        expected_long: bool,
18        /// The observed first byte.
19        first_byte: u8,
20    },
21    /// The input does not contain all bytes structurally required by the view.
22    Incomplete {
23        /// Absolute byte count required from the start of the supplied input.
24        required: usize,
25        /// Bytes available in the supplied input.
26        available: usize,
27    },
28    /// A caller-supplied length cannot be represented when locating a field.
29    LengthOverflow {
30        /// Offset before adding the supplied length.
31        offset: usize,
32        /// Length that could not be added to the offset.
33        length: usize,
34    },
35    /// A version-specific packet view does not define semantics for this QUIC version.
36    UnsupportedVersion {
37        /// The raw unsupported version.
38        version: QuicVersion,
39    },
40    /// A terminal packet was parsed by a view requiring a different exact version.
41    WrongVersion {
42        /// The observed raw version.
43        version: QuicVersion,
44    },
45    /// A Version Negotiation packet has no advertised versions after its invariant prefix.
46    EmptyVersionList,
47    /// A Version Negotiation version list does not contain a whole number of four-byte versions.
48    MisalignedVersionList {
49        /// The observed version-list byte length.
50        length: usize,
51    },
52    /// A supported-version terminal packet is not a Retry packet.
53    NotRetry {
54        /// The observed semantic packet type.
55        packet_type: QuicLongPacketType,
56    },
57    /// A Retry packet has an integrity tag but no Retry Token bytes.
58    EmptyRetryToken,
59    /// A supported-version long header has its required fixed bit cleared.
60    FixedBitNotSet {
61        /// The observed first byte.
62        first_byte: u8,
63    },
64    /// A supported-version connection ID exceeds its 20-byte limit.
65    ConnectionIdTooLong {
66        /// The overlong connection-ID field.
67        field: QuicConnectionIdField,
68        /// The observed byte length.
69        length: usize,
70    },
71    /// The packet type is terminal rather than length-delimited.
72    NotLengthDelimited {
73        /// The terminal semantic packet type.
74        packet_type: QuicLongPacketType,
75    },
76    /// A decoded length cannot be represented as `usize` on this target.
77    LengthNotRepresentable {
78        /// The decoded wire value.
79        value: u64,
80    },
81    /// A protected packet length is too short to contain a packet number and payload.
82    ProtectedRemainderTooShort {
83        /// Minimum protected remainder byte length.
84        minimum: u64,
85        /// Decoded protected remainder byte length.
86        actual: u64,
87    },
88}
89
90impl fmt::Display for QuicPacketParseError {
91    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
92        match self {
93            Self::EmptyDatagram => write!(f, "QUIC UDP datagram is empty"),
94            Self::ShortHeaderContextRequired => write!(
95                f,
96                "QUIC short-header packet requires destination connection-ID length context"
97            ),
98            Self::WrongHeaderForm {
99                expected_long,
100                first_byte,
101            } => {
102                let expected = if *expected_long { "long" } else { "short" };
103                write!(
104                    f,
105                    "QUIC {expected} header view received first byte {first_byte:#04x} with the wrong header form"
106                )
107            }
108            Self::Incomplete {
109                required,
110                available,
111            } => write!(
112                f,
113                "QUIC packet input is incomplete: need {required} bytes, have {available}"
114            ),
115            Self::LengthOverflow { offset, length } => write!(
116                f,
117                "QUIC packet field end cannot be represented: offset {offset} plus length {length} overflows usize"
118            ),
119            Self::UnsupportedVersion { version } => write!(
120                f,
121                "QUIC version-specific long-packet semantics are unsupported for version {:#010x}",
122                version.raw()
123            ),
124            Self::WrongVersion { version } => write!(
125                f,
126                "QUIC terminal packet view requires a different version than {:#010x}",
127                version.raw()
128            ),
129            Self::EmptyVersionList => write!(
130                f,
131                "QUIC Version Negotiation packet has an empty version list"
132            ),
133            Self::MisalignedVersionList { length } => write!(
134                f,
135                "QUIC Version Negotiation version list has invalid byte length {length}; expected a nonzero multiple of 4"
136            ),
137            Self::NotRetry { packet_type } => {
138                write!(f, "QUIC terminal packet is {packet_type:?}, not Retry")
139            }
140            Self::EmptyRetryToken => write!(f, "QUIC Retry packet has an empty Retry Token"),
141            Self::FixedBitNotSet { first_byte } => write!(
142                f,
143                "QUIC supported-version long packet has fixed bit clear in first byte {first_byte:#04x}"
144            ),
145            Self::ConnectionIdTooLong { field, length } => write!(
146                f,
147                "QUIC {field:?} connection ID has invalid length {length}; supported versions permit at most 20 bytes"
148            ),
149            Self::NotLengthDelimited { packet_type } => write!(
150                f,
151                "QUIC {packet_type:?} packet is terminal and not length-delimited"
152            ),
153            Self::LengthNotRepresentable { value } => write!(
154                f,
155                "QUIC wire length {value} cannot be represented as usize on this target"
156            ),
157            Self::ProtectedRemainderTooShort { minimum, actual } => write!(
158                f,
159                "QUIC protected packet length is too short: need at least {minimum} bytes, have {actual}"
160            ),
161        }
162    }
163}