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}