error.rs - source

quiche/

error.rs

1// Copyright (C) 2018-2019, Cloudflare, Inc.
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are
6// met:
7//
8//     * Redistributions of source code must retain the above copyright notice,
9//       this list of conditions and the following disclaimer.
10//
11//     * Redistributions in binary form must reproduce the above copyright
12//       notice, this list of conditions and the following disclaimer in the
13//       documentation and/or other materials provided with the distribution.
14//
15// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
16// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
17// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
19// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
27/// A specialized [`Result`] type for quiche operations.
28///
29/// This type is used throughout quiche's public API for any operation that
30/// can produce an error.
31///
32/// [`Result`]: https://doc.rust-lang.org/std/result/enum.Result.html
33pub type Result<T> = std::result::Result<T, Error>;
34
35/// A QUIC error.
36#[derive(Clone, Copy, Debug, PartialEq, Eq)]
37pub enum Error {
38    /// There is no more work to do.
39    Done,
40
41    /// The provided buffer is too short.
42    BufferTooShort,
43
44    /// The provided packet cannot be parsed because its version is unknown.
45    UnknownVersion,
46
47    /// The provided packet cannot be parsed because it contains an invalid
48    /// frame.
49    InvalidFrame,
50
51    /// The provided packet cannot be parsed.
52    InvalidPacket,
53
54    /// The operation cannot be completed because the connection is in an
55    /// invalid state.
56    InvalidState,
57
58    /// The operation cannot be completed because the stream is in an
59    /// invalid state.
60    ///
61    /// The stream ID is provided as associated data.
62    InvalidStreamState(u64),
63
64    /// The peer's transport params cannot be parsed.
65    InvalidTransportParam,
66
67    /// A cryptographic operation failed.
68    CryptoFail,
69
70    /// The TLS handshake failed.
71    TlsFail,
72
73    /// The peer violated the local flow control limits.
74    FlowControl,
75
76    /// The peer violated the local stream limits.
77    StreamLimit,
78
79    /// The specified stream was stopped by the peer.
80    ///
81    /// The error code sent as part of the `STOP_SENDING` frame is provided as
82    /// associated data.
83    StreamStopped(u64),
84
85    /// The specified stream was reset by the peer.
86    ///
87    /// The error code sent as part of the `RESET_STREAM` frame is provided as
88    /// associated data.
89    StreamReset(u64),
90
91    /// The received data exceeds the stream's final size.
92    FinalSize,
93
94    /// Error in congestion control.
95    CongestionControl,
96
97    /// Too many identifiers were provided.
98    IdLimit,
99
100    /// Not enough available identifiers.
101    OutOfIdentifiers,
102
103    /// Error in key update.
104    KeyUpdate,
105
106    /// The peer sent more data in CRYPTO frames than we can buffer.
107    CryptoBufferExceeded,
108
109    /// The peer sent an ACK frame with an invalid range.
110    InvalidAckRange,
111
112    /// The peer send an ACK frame for a skipped packet used for Optimistic ACK
113    /// mitigation.
114    OptimisticAckDetected,
115
116    /// An invalid DCID was used when connecting to a remote peer.
117    InvalidDcidInitialization,
118}
119
120/// QUIC error codes sent on the wire.
121///
122/// As defined in [RFC9000](https://www.rfc-editor.org/rfc/rfc9000.html#name-error-codes).
123#[derive(Copy, Clone, Debug, Eq, PartialEq)]
124pub enum WireErrorCode {
125    /// An endpoint uses this with CONNECTION_CLOSE to signal that the
126    /// connection is being closed abruptly in the absence of any error.
127    NoError              = 0x0,
128    /// The endpoint encountered an internal error and cannot continue with the
129    /// connection.
130    InternalError        = 0x1,
131    /// The server refused to accept a new connection.
132    ConnectionRefused    = 0x2,
133    /// An endpoint received more data than it permitted in its advertised data
134    /// limits; see Section 4.
135    FlowControlError     = 0x3,
136    /// An endpoint received a frame for a stream identifier that exceeded its
137    /// advertised stream limit for the corresponding stream type.
138    StreamLimitError     = 0x4,
139    /// An endpoint received a frame for a stream that was not in a state that
140    /// permitted that frame.
141    StreamStateError     = 0x5,
142    /// (1) An endpoint received a STREAM frame containing data that exceeded
143    /// the previously established final size, (2) an endpoint received a
144    /// STREAM frame or a RESET_STREAM frame containing a final size that
145    /// was lower than the size of stream data that was already received, or
146    /// (3) an endpoint received a STREAM frame or a RESET_STREAM frame
147    /// containing a different final size to the one already established.
148    FinalSizeError       = 0x6,
149    /// An endpoint received a frame that was badly formatted -- for instance, a
150    /// frame of an unknown type or an ACK frame that has more
151    /// acknowledgment ranges than the remainder of the packet could carry.
152    FrameEncodingError   = 0x7,
153    /// An endpoint received transport parameters that were badly formatted,
154    /// included an invalid value, omitted a mandatory transport parameter,
155    /// included a forbidden transport parameter, or were otherwise in
156    /// error.
157    TransportParameterError = 0x8,
158    /// The number of connection IDs provided by the peer exceeds the advertised
159    /// active_connection_id_limit.
160    ConnectionIdLimitError = 0x9,
161    /// An endpoint detected an error with protocol compliance that was not
162    /// covered by more specific error codes.
163    ProtocolViolation    = 0xa,
164    /// A server received a client Initial that contained an invalid Token
165    /// field.
166    InvalidToken         = 0xb,
167    /// The application or application protocol caused the connection to be
168    /// closed.
169    ApplicationError     = 0xc,
170    /// An endpoint has received more data in CRYPTO frames than it can buffer.
171    CryptoBufferExceeded = 0xd,
172    /// An endpoint detected errors in performing key updates.
173    KeyUpdateError       = 0xe,
174    /// An endpoint has reached the confidentiality or integrity limit for the
175    /// AEAD algorithm used by the given connection.
176    AeadLimitReached     = 0xf,
177    /// An endpoint has determined that the network path is incapable of
178    /// supporting QUIC. An endpoint is unlikely to receive a
179    /// CONNECTION_CLOSE frame carrying this code except when the path does
180    /// not support a large enough MTU.
181    NoViablePath         = 0x10,
182}
183
184impl Error {
185    pub(crate) fn to_wire(self) -> u64 {
186        match self {
187            Error::Done => WireErrorCode::NoError as u64,
188            Error::InvalidFrame => WireErrorCode::FrameEncodingError as u64,
189            Error::InvalidStreamState(..) =>
190                WireErrorCode::StreamStateError as u64,
191            Error::InvalidTransportParam =>
192                WireErrorCode::TransportParameterError as u64,
193            Error::FlowControl => WireErrorCode::FlowControlError as u64,
194            Error::StreamLimit => WireErrorCode::StreamLimitError as u64,
195            Error::IdLimit => WireErrorCode::ConnectionIdLimitError as u64,
196            Error::FinalSize => WireErrorCode::FinalSizeError as u64,
197            Error::CryptoBufferExceeded =>
198                WireErrorCode::CryptoBufferExceeded as u64,
199            Error::KeyUpdate => WireErrorCode::KeyUpdateError as u64,
200            _ => WireErrorCode::ProtocolViolation as u64,
201        }
202    }
203
204    #[cfg(feature = "ffi")]
205    pub(crate) fn to_c(self) -> libc::ssize_t {
206        match self {
207            Error::Done => -1,
208            Error::BufferTooShort => -2,
209            Error::UnknownVersion => -3,
210            Error::InvalidFrame => -4,
211            Error::InvalidPacket => -5,
212            Error::InvalidState => -6,
213            Error::InvalidStreamState(_) => -7,
214            Error::InvalidTransportParam => -8,
215            Error::CryptoFail => -9,
216            Error::TlsFail => -10,
217            Error::FlowControl => -11,
218            Error::StreamLimit => -12,
219            Error::FinalSize => -13,
220            Error::CongestionControl => -14,
221            Error::StreamStopped { .. } => -15,
222            Error::StreamReset { .. } => -16,
223            Error::IdLimit => -17,
224            Error::OutOfIdentifiers => -18,
225            Error::KeyUpdate => -19,
226            Error::CryptoBufferExceeded => -20,
227            Error::InvalidAckRange => -21,
228            Error::OptimisticAckDetected => -22,
229            Error::InvalidDcidInitialization => -23,
230        }
231    }
232}
233
234impl std::fmt::Display for Error {
235    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
236        write!(f, "{self:?}")
237    }
238}
239
240impl std::error::Error for Error {
241    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
242        None
243    }
244}
245
246impl From<octets::BufferTooShortError> for Error {
247    fn from(_err: octets::BufferTooShortError) -> Self {
248        Error::BufferTooShort
249    }
250}
251
252/// Represents information carried by `CONNECTION_CLOSE` frames.
253#[derive(Clone, Debug, PartialEq, Eq)]
254pub struct ConnectionError {
255    /// Whether the error came from the application or the transport layer.
256    pub is_app: bool,
257
258    /// The error code carried by the `CONNECTION_CLOSE` frame.
259    pub error_code: u64,
260
261    /// The reason carried by the `CONNECTION_CLOSE` frame.
262    pub reason: Vec<u8>,
263}