1use std::fmt;
9
10use bytes::{Buf, BufMut};
11
12use crate::{
13 coding::{self, BufExt, BufMutExt},
14 frame,
15};
16
17#[derive(Debug, Clone, Eq, PartialEq)]
19pub struct Error {
20 pub code: Code,
22 pub frame: Option<frame::FrameType>,
24 pub reason: String,
26}
27
28impl fmt::Display for Error {
29 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
30 self.code.fmt(f)?;
31 if let Some(frame) = self.frame {
32 write!(f, " in {frame}")?;
33 }
34 if !self.reason.is_empty() {
35 write!(f, ": {}", self.reason)?;
36 }
37 Ok(())
38 }
39}
40
41impl std::error::Error for Error {}
42
43impl From<Code> for Error {
44 fn from(x: Code) -> Self {
45 Self {
46 code: x,
47 frame: None,
48 reason: "".to_string(),
49 }
50 }
51}
52
53#[derive(Copy, Clone, Eq, PartialEq)]
55pub struct Code(u64);
56
57impl Code {
58 pub fn crypto(code: u8) -> Self {
60 Self(0x100 | u64::from(code))
61 }
62}
63
64impl coding::Codec for Code {
65 fn decode<B: Buf>(buf: &mut B) -> coding::Result<Self> {
66 Ok(Self(buf.get_var()?))
67 }
68 fn encode<B: BufMut>(&self, buf: &mut B) {
69 if buf.write_var(self.0).is_err() {
70 tracing::error!("VarInt overflow while encoding TransportErrorCode");
71 debug_assert!(false, "VarInt overflow while encoding TransportErrorCode");
72 }
73 }
74}
75
76impl From<Code> for u64 {
77 fn from(x: Code) -> Self {
78 x.0
79 }
80}
81
82macro_rules! errors {
83 {$($name:ident($val:expr_2021) $desc:expr_2021;)*} => {
84 #[allow(non_snake_case, unused)]
85 impl Error {
86 $(
87 pub(crate) fn $name<T>(reason: T) -> Self where T: Into<String> {
88 Self {
89 code: Code::$name,
90 frame: None,
91 reason: reason.into(),
92 }
93 }
94 )*
95 }
96
97 impl Code {
98 $(#[doc = $desc] pub const $name: Self = Code($val);)*
99 }
100
101 impl fmt::Debug for Code {
102 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
103 match self.0 {
104 $($val => f.write_str(stringify!($name)),)*
105 x if (0x100..0x200).contains(&x) => write!(f, "Code::crypto({:02x})", self.0 as u8),
106 _ => write!(f, "Code({:x})", self.0),
107 }
108 }
109 }
110
111 impl fmt::Display for Code {
112 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
113 match self.0 {
114 $($val => f.write_str($desc),)*
115 _ if self.0 >= 0x100 && self.0 < 0x200 => write!(f, "the cryptographic handshake failed: error {}", self.0 & 0xFF),
117 _ => f.write_str("unknown error"),
118 }
119 }
120 }
121 }
122}
123
124errors! {
125 NO_ERROR(0x0) "the connection is being closed abruptly in the absence of any error";
126 INTERNAL_ERROR(0x1) "the endpoint encountered an internal error and cannot continue with the connection";
127 CONNECTION_REFUSED(0x2) "the server refused to accept a new connection";
128 FLOW_CONTROL_ERROR(0x3) "received more data than permitted in advertised data limits";
129 STREAM_LIMIT_ERROR(0x4) "received a frame for a stream identifier that exceeded advertised the stream limit for the corresponding stream type";
130 STREAM_STATE_ERROR(0x5) "received a frame for a stream that was not in a state that permitted that frame";
131 FINAL_SIZE_ERROR(0x6) "received a STREAM frame or a RESET_STREAM frame containing a different final size to the one already established";
132 FRAME_ENCODING_ERROR(0x7) "received a frame that was badly formatted";
133 TRANSPORT_PARAMETER_ERROR(0x8) "received transport parameters that were badly formatted, included an invalid value, was absent even though it is mandatory, was present though it is forbidden, or is otherwise in error";
134 CONNECTION_ID_LIMIT_ERROR(0x9) "the number of connection IDs provided by the peer exceeds the advertised active_connection_id_limit";
135 PROTOCOL_VIOLATION(0xA) "detected an error with protocol compliance that was not covered by more specific error codes";
136 INVALID_TOKEN(0xB) "received an invalid Retry Token in a client Initial";
137 APPLICATION_ERROR(0xC) "the application or application protocol caused the connection to be closed during the handshake";
138 CRYPTO_BUFFER_EXCEEDED(0xD) "received more data in CRYPTO frames than can be buffered";
139 KEY_UPDATE_ERROR(0xE) "key update error";
140 AEAD_LIMIT_REACHED(0xF) "the endpoint has reached the confidentiality or integrity limit for the AEAD algorithm";
141 NO_VIABLE_PATH(0x10) "no viable network path exists";
142}
143
144#[cfg(test)]
145mod tests {
146 use super::*;
147 use crate::coding::Codec;
148 use bytes::BytesMut;
149
150 #[test]
151 fn transport_error_display() {
152 let err = Error::from(Code::PROTOCOL_VIOLATION);
153 let display = format!("{err}");
154 assert!(!display.is_empty());
155 }
156
157 #[test]
158 fn transport_error_display_with_frame() {
159 let err = Error {
161 code: Code::INTERNAL_ERROR,
162 frame: Some(frame::FrameType(0x00)), reason: "test reason".into(),
164 };
165 let display = format!("{err}");
166 assert!(display.contains("test reason"));
167 }
168
169 #[test]
170 fn transport_error_from_code() {
171 let err: Error = Code::NO_ERROR.into();
172 assert_eq!(err.code, Code::NO_ERROR);
173 assert_eq!(err.frame, None);
174 assert!(err.reason.is_empty());
175 }
176
177 #[test]
178 fn transport_error_is_error() {
179 let err = Error::from(Code::FLOW_CONTROL_ERROR);
180 let err_ref: &dyn std::error::Error = &err;
181 assert!(!format!("{err_ref}").is_empty());
182 }
183
184 #[test]
185 fn transport_error_convenience_constructors() {
186 let e = Error::NO_ERROR(String::new());
188 assert_eq!(e.code, Code::NO_ERROR);
189
190 let e = Error::INTERNAL_ERROR("oops");
191 assert_eq!(e.code, Code::INTERNAL_ERROR);
192 assert_eq!(e.reason, "oops");
193
194 let e = Error::CONNECTION_REFUSED("refused");
195 assert_eq!(e.code, Code::CONNECTION_REFUSED);
196
197 let e = Error::FLOW_CONTROL_ERROR("too much data");
198 assert_eq!(e.code, Code::FLOW_CONTROL_ERROR);
199
200 let e = Error::STREAM_LIMIT_ERROR("too many streams");
201 assert_eq!(e.code, Code::STREAM_LIMIT_ERROR);
202
203 let e = Error::STREAM_STATE_ERROR("bad state");
204 assert_eq!(e.code, Code::STREAM_STATE_ERROR);
205
206 let e = Error::FINAL_SIZE_ERROR("size mismatch");
207 assert_eq!(e.code, Code::FINAL_SIZE_ERROR);
208
209 let e = Error::FRAME_ENCODING_ERROR("bad frame");
210 assert_eq!(e.code, Code::FRAME_ENCODING_ERROR);
211
212 let e = Error::TRANSPORT_PARAMETER_ERROR("bad params");
213 assert_eq!(e.code, Code::TRANSPORT_PARAMETER_ERROR);
214
215 let e = Error::CONNECTION_ID_LIMIT_ERROR("too many CIDs");
216 assert_eq!(e.code, Code::CONNECTION_ID_LIMIT_ERROR);
217
218 let e = Error::PROTOCOL_VIOLATION("violation");
219 assert_eq!(e.code, Code::PROTOCOL_VIOLATION);
220
221 let e = Error::INVALID_TOKEN("bad token");
222 assert_eq!(e.code, Code::INVALID_TOKEN);
223
224 let e = Error::APPLICATION_ERROR("app error");
225 assert_eq!(e.code, Code::APPLICATION_ERROR);
226
227 let e = Error::CRYPTO_BUFFER_EXCEEDED("buffer full");
228 assert_eq!(e.code, Code::CRYPTO_BUFFER_EXCEEDED);
229
230 let e = Error::KEY_UPDATE_ERROR("key update");
231 assert_eq!(e.code, Code::KEY_UPDATE_ERROR);
232
233 let e = Error::AEAD_LIMIT_REACHED("aead limit");
234 assert_eq!(e.code, Code::AEAD_LIMIT_REACHED);
235
236 let e = Error::NO_VIABLE_PATH("no path");
237 assert_eq!(e.code, Code::NO_VIABLE_PATH);
238 }
239
240 #[test]
241 fn code_crypto_constructor() {
242 let code = Code::crypto(0x2C);
243 let val: u64 = code.into();
244 assert_eq!(val, 0x12C); }
246
247 #[test]
248 fn code_from_u64_and_back() {
249 let code = Code::NO_ERROR;
250 let val: u64 = code.into();
251 assert_eq!(val, 0x0);
252
253 let code = Code::NO_VIABLE_PATH;
254 let val: u64 = code.into();
255 assert_eq!(val, 0x10);
256 }
257
258 #[test]
259 fn code_debug_no_error() {
260 assert_eq!(format!("{:?}", Code::NO_ERROR), "NO_ERROR");
261 }
262
263 #[test]
264 fn code_debug_crypto() {
265 assert_eq!(format!("{:?}", Code::crypto(0x2C)), "Code::crypto(2c)");
266 }
267
268 #[test]
269 fn code_debug_unknown() {
270 assert_eq!(format!("{:?}", Code(0x1234)), "Code(1234)");
271 }
272
273 #[test]
274 fn code_display_no_error() {
275 assert_eq!(
276 format!("{}", Code::NO_ERROR),
277 "the connection is being closed abruptly in the absence of any error"
278 );
279 }
280
281 #[test]
282 fn code_display_crypto() {
283 let display = format!("{}", Code::crypto(0x2C));
284 assert!(display.contains("cryptographic handshake"));
285 }
286
287 #[test]
288 fn code_display_unknown() {
289 assert_eq!(format!("{}", Code(0x1234)), "unknown error");
290 }
291
292 #[test]
293 fn transport_error_code_encoding_roundtrip() {
294 let codes = [
295 Code::NO_ERROR,
296 Code::PROTOCOL_VIOLATION,
297 Code::INTERNAL_ERROR,
298 Code::crypto(0x2C),
299 Code(0x1234),
300 ];
301
302 for code in &codes {
303 let mut buf = BytesMut::new();
304 code.encode(&mut buf);
305 let mut read = buf.freeze();
306 let decoded = Code::decode(&mut read).unwrap();
307 assert_eq!(&decoded, code);
308 }
309 }
310
311 #[test]
312 fn transport_error_code_equality() {
313 assert_eq!(Code::NO_ERROR, Code::NO_ERROR);
314 assert_ne!(Code::NO_ERROR, Code::INTERNAL_ERROR);
315 assert_eq!(Code::crypto(0x2C), Code::crypto(0x2C));
316 assert_ne!(Code::crypto(0x2C), Code::crypto(0x2D));
317 }
318
319 #[test]
320 fn transport_error_equality() {
321 let e1 = Error::INTERNAL_ERROR("test");
322 let e2 = Error::INTERNAL_ERROR("test");
323 assert_eq!(e1, e2);
324
325 let e3 = Error::INTERNAL_ERROR("different");
326 assert_ne!(e1, e3);
327 }
328
329 #[test]
330 fn transport_error_clone() {
331 let e = Error::PROTOCOL_VIOLATION("clone test");
332 let cloned = e.clone();
333 assert_eq!(e, cloned);
334 }
335
336 #[test]
337 fn transport_error_debug_format() {
338 let e = Error::from(Code::INTERNAL_ERROR);
339 let debug = format!("{e:?}");
340 assert!(debug.contains("INTERNAL_ERROR"));
341 }
342
343 #[test]
344 fn transport_error_debug_with_frame_and_reason() {
345 let e = Error {
346 code: Code::PROTOCOL_VIOLATION,
347 frame: Some(frame::FrameType(0x01)),
348 reason: "bad thing".into(),
349 };
350 let debug = format!("{e:?}");
351 assert!(debug.contains("PROTOCOL_VIOLATION"));
352 assert!(debug.contains("bad thing"));
353 }
354
355 #[test]
356 fn code_debug_all_variants() {
357 assert_eq!(format!("{:?}", Code::NO_ERROR), "NO_ERROR");
359 assert_eq!(format!("{:?}", Code::INTERNAL_ERROR), "INTERNAL_ERROR");
360 assert_eq!(
361 format!("{:?}", Code::CONNECTION_REFUSED),
362 "CONNECTION_REFUSED"
363 );
364 assert_eq!(
365 format!("{:?}", Code::FLOW_CONTROL_ERROR),
366 "FLOW_CONTROL_ERROR"
367 );
368 assert_eq!(
369 format!("{:?}", Code::STREAM_LIMIT_ERROR),
370 "STREAM_LIMIT_ERROR"
371 );
372 assert_eq!(
373 format!("{:?}", Code::STREAM_STATE_ERROR),
374 "STREAM_STATE_ERROR"
375 );
376 assert_eq!(format!("{:?}", Code::FINAL_SIZE_ERROR), "FINAL_SIZE_ERROR");
377 assert_eq!(
378 format!("{:?}", Code::FRAME_ENCODING_ERROR),
379 "FRAME_ENCODING_ERROR"
380 );
381 assert_eq!(
382 format!("{:?}", Code::TRANSPORT_PARAMETER_ERROR),
383 "TRANSPORT_PARAMETER_ERROR"
384 );
385 assert_eq!(
386 format!("{:?}", Code::CONNECTION_ID_LIMIT_ERROR),
387 "CONNECTION_ID_LIMIT_ERROR"
388 );
389 assert_eq!(
390 format!("{:?}", Code::PROTOCOL_VIOLATION),
391 "PROTOCOL_VIOLATION"
392 );
393 assert_eq!(format!("{:?}", Code::INVALID_TOKEN), "INVALID_TOKEN");
394 assert_eq!(
395 format!("{:?}", Code::APPLICATION_ERROR),
396 "APPLICATION_ERROR"
397 );
398 assert_eq!(
399 format!("{:?}", Code::CRYPTO_BUFFER_EXCEEDED),
400 "CRYPTO_BUFFER_EXCEEDED"
401 );
402 assert_eq!(format!("{:?}", Code::KEY_UPDATE_ERROR), "KEY_UPDATE_ERROR");
403 assert_eq!(
404 format!("{:?}", Code::AEAD_LIMIT_REACHED),
405 "AEAD_LIMIT_REACHED"
406 );
407 assert_eq!(format!("{:?}", Code::NO_VIABLE_PATH), "NO_VIABLE_PATH");
408 }
409
410 #[test]
411 fn code_display_all_variants() {
412 let displays = [
414 (Code::NO_ERROR, "connection"),
415 (Code::INTERNAL_ERROR, "internal error"),
416 (Code::CONNECTION_REFUSED, "refused"),
417 (Code::FLOW_CONTROL_ERROR, "data limits"),
418 (Code::STREAM_LIMIT_ERROR, "stream limit"),
419 (Code::STREAM_STATE_ERROR, "stream"),
420 (Code::FINAL_SIZE_ERROR, "final size"),
421 (Code::FRAME_ENCODING_ERROR, "badly formatted"),
422 (Code::TRANSPORT_PARAMETER_ERROR, "transport parameters"),
423 (Code::CONNECTION_ID_LIMIT_ERROR, "connection IDs"),
424 (Code::PROTOCOL_VIOLATION, "protocol compliance"),
425 (Code::INVALID_TOKEN, "invalid Retry Token"),
426 (Code::APPLICATION_ERROR, "application"),
427 (Code::CRYPTO_BUFFER_EXCEEDED, "CRYPTO frames"),
428 (Code::KEY_UPDATE_ERROR, "key update"),
429 (Code::AEAD_LIMIT_REACHED, "AEAD"),
430 (Code::NO_VIABLE_PATH, "no viable network path"),
431 ];
432
433 for (code, expected_fragment) in &displays {
434 let display = format!("{code}");
435 assert!(
436 display.contains(expected_fragment),
437 "Code {code:?} display '{display}' should contain '{expected_fragment}'"
438 );
439 }
440 }
441}