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
117/// QUIC error codes sent on the wire.
118///
119/// As defined in [RFC9000](https://www.rfc-editor.org/rfc/rfc9000.html#name-error-codes).
120#[derive(Copy, Clone, Debug, Eq, PartialEq)]
121pub enum WireErrorCode {
122    /// An endpoint uses this with CONNECTION_CLOSE to signal that the
123    /// connection is being closed abruptly in the absence of any error.
124    NoError              = 0x0,
125    /// The endpoint encountered an internal error and cannot continue with the
126    /// connection.
127    InternalError        = 0x1,
128    /// The server refused to accept a new connection.
129    ConnectionRefused    = 0x2,
130    /// An endpoint received more data than it permitted in its advertised data
131    /// limits; see Section 4.
132    FlowControlError     = 0x3,
133    /// An endpoint received a frame for a stream identifier that exceeded its
134    /// advertised stream limit for the corresponding stream type.
135    StreamLimitError     = 0x4,
136    /// An endpoint received a frame for a stream that was not in a state that
137    /// permitted that frame.
138    StreamStateError     = 0x5,
139    /// (1) An endpoint received a STREAM frame containing data that exceeded
140    /// the previously established final size, (2) an endpoint received a
141    /// STREAM frame or a RESET_STREAM frame containing a final size that
142    /// was lower than the size of stream data that was already received, or
143    /// (3) an endpoint received a STREAM frame or a RESET_STREAM frame
144    /// containing a different final size to the one already established.
145    FinalSizeError       = 0x6,
146    /// An endpoint received a frame that was badly formatted -- for instance, a
147    /// frame of an unknown type or an ACK frame that has more
148    /// acknowledgment ranges than the remainder of the packet could carry.
149    FrameEncodingError   = 0x7,
150    /// An endpoint received transport parameters that were badly formatted,
151    /// included an invalid value, omitted a mandatory transport parameter,
152    /// included a forbidden transport parameter, or were otherwise in
153    /// error.
154    TransportParameterError = 0x8,
155    /// The number of connection IDs provided by the peer exceeds the advertised
156    /// active_connection_id_limit.
157    ConnectionIdLimitError = 0x9,
158    /// An endpoint detected an error with protocol compliance that was not
159    /// covered by more specific error codes.
160    ProtocolViolation    = 0xa,
161    /// A server received a client Initial that contained an invalid Token
162    /// field.
163    InvalidToken         = 0xb,
164    /// The application or application protocol caused the connection to be
165    /// closed.
166    ApplicationError     = 0xc,
167    /// An endpoint has received more data in CRYPTO frames than it can buffer.
168    CryptoBufferExceeded = 0xd,
169    /// An endpoint detected errors in performing key updates.
170    KeyUpdateError       = 0xe,
171    /// An endpoint has reached the confidentiality or integrity limit for the
172    /// AEAD algorithm used by the given connection.
173    AeadLimitReached     = 0xf,
174    /// An endpoint has determined that the network path is incapable of
175    /// supporting QUIC. An endpoint is unlikely to receive a
176    /// CONNECTION_CLOSE frame carrying this code except when the path does
177    /// not support a large enough MTU.
178    NoViablePath         = 0x10,
179}
180
181impl Error {
182    pub(crate) fn to_wire(self) -> u64 {
183        match self {
184            Error::Done => WireErrorCode::NoError as u64,
185            Error::InvalidFrame => WireErrorCode::FrameEncodingError as u64,
186            Error::InvalidStreamState(..) =>
187                WireErrorCode::StreamStateError as u64,
188            Error::InvalidTransportParam =>
189                WireErrorCode::TransportParameterError as u64,
190            Error::FlowControl => WireErrorCode::FlowControlError as u64,
191            Error::StreamLimit => WireErrorCode::StreamLimitError as u64,
192            Error::IdLimit => WireErrorCode::ConnectionIdLimitError as u64,
193            Error::FinalSize => WireErrorCode::FinalSizeError as u64,
194            Error::CryptoBufferExceeded =>
195                WireErrorCode::CryptoBufferExceeded as u64,
196            Error::KeyUpdate => WireErrorCode::KeyUpdateError as u64,
197            _ => WireErrorCode::ProtocolViolation as u64,
198        }
199    }
200
201    #[cfg(feature = "ffi")]
202    pub(crate) fn to_c(self) -> libc::ssize_t {
203        match self {
204            Error::Done => -1,
205            Error::BufferTooShort => -2,
206            Error::UnknownVersion => -3,
207            Error::InvalidFrame => -4,
208            Error::InvalidPacket => -5,
209            Error::InvalidState => -6,
210            Error::InvalidStreamState(_) => -7,
211            Error::InvalidTransportParam => -8,
212            Error::CryptoFail => -9,
213            Error::TlsFail => -10,
214            Error::FlowControl => -11,
215            Error::StreamLimit => -12,
216            Error::FinalSize => -13,
217            Error::CongestionControl => -14,
218            Error::StreamStopped { .. } => -15,
219            Error::StreamReset { .. } => -16,
220            Error::IdLimit => -17,
221            Error::OutOfIdentifiers => -18,
222            Error::KeyUpdate => -19,
223            Error::CryptoBufferExceeded => -20,
224            Error::InvalidAckRange => -21,
225            Error::OptimisticAckDetected => -22,
226        }
227    }
228}
229
230impl std::fmt::Display for Error {
231    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
232        write!(f, "{self:?}")
233    }
234}
235
236impl std::error::Error for Error {
237    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
238        None
239    }
240}
241
242impl From<octets::BufferTooShortError> for Error {
243    fn from(_err: octets::BufferTooShortError) -> Self {
244        Error::BufferTooShort
245    }
246}
247
248/// Represents information carried by `CONNECTION_CLOSE` frames.
249#[derive(Clone, Debug, PartialEq, Eq)]
250pub struct ConnectionError {
251    /// Whether the error came from the application or the transport layer.
252    pub is_app: bool,
253
254    /// The error code carried by the `CONNECTION_CLOSE` frame.
255    pub error_code: u64,
256
257    /// The reason carried by the `CONNECTION_CLOSE` frame.
258    pub reason: Vec<u8>,
259}