quinn_proto/
transport_error.rs

1use std::fmt;
2
3use bytes::{Buf, BufMut};
4
5use crate::{
6    coding::{self, BufExt, BufMutExt},
7    frame,
8};
9
10/// Transport-level errors occur when a peer violates the protocol specification
11#[derive(Debug, Clone, Eq, PartialEq)]
12pub struct Error {
13    /// Type of error
14    pub code: Code,
15    /// Frame type that triggered the error
16    pub frame: Option<frame::FrameType>,
17    /// Human-readable explanation of the reason
18    pub reason: String,
19}
20
21impl fmt::Display for Error {
22    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
23        self.code.fmt(f)?;
24        if let Some(frame) = self.frame {
25            write!(f, " in {frame}")?;
26        }
27        if !self.reason.is_empty() {
28            write!(f, ": {}", self.reason)?;
29        }
30        Ok(())
31    }
32}
33
34impl std::error::Error for Error {}
35
36impl From<Code> for Error {
37    fn from(x: Code) -> Self {
38        Self {
39            code: x,
40            frame: None,
41            reason: "".to_string(),
42        }
43    }
44}
45
46/// Transport-level error code
47#[derive(Copy, Clone, Eq, PartialEq)]
48pub struct Code(u64);
49
50impl Code {
51    /// Create QUIC error code from TLS alert code
52    pub fn crypto(code: u8) -> Self {
53        Self(0x100 | u64::from(code))
54    }
55}
56
57impl coding::Codec for Code {
58    fn decode<B: Buf>(buf: &mut B) -> coding::Result<Self> {
59        Ok(Self(buf.get_var()?))
60    }
61    fn encode<B: BufMut>(&self, buf: &mut B) {
62        buf.write_var(self.0)
63    }
64}
65
66impl From<Code> for u64 {
67    fn from(x: Code) -> Self {
68        x.0
69    }
70}
71
72macro_rules! errors {
73    {$($name:ident($val:expr) $desc:expr;)*} => {
74        #[allow(non_snake_case, unused)]
75        impl Error {
76            $(
77            pub(crate) fn $name<T>(reason: T) -> Self where T: Into<String> {
78                Self {
79                    code: Code::$name,
80                    frame: None,
81                    reason: reason.into(),
82                }
83            }
84            )*
85        }
86
87        impl Code {
88            $(#[doc = $desc] pub const $name: Self = Code($val);)*
89        }
90
91        impl fmt::Debug for Code {
92            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
93                match self.0 {
94                    $($val => f.write_str(stringify!($name)),)*
95                    x if (0x100..0x200).contains(&x) => write!(f, "Code::crypto({:02x})", self.0 as u8),
96                    _ => write!(f, "Code({:x})", self.0),
97                }
98            }
99        }
100
101        impl fmt::Display for Code {
102            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
103                match self.0 {
104                    $($val => f.write_str($desc),)*
105                    // We're trying to be abstract over the crypto protocol, so human-readable descriptions here is tricky.
106                    _ if self.0 >= 0x100 && self.0 < 0x200 => write!(f, "the cryptographic handshake failed: error {}", self.0 & 0xFF),
107                    _ => f.write_str("unknown error"),
108                }
109            }
110        }
111    }
112}
113
114errors! {
115    NO_ERROR(0x0) "the connection is being closed abruptly in the absence of any error";
116    INTERNAL_ERROR(0x1) "the endpoint encountered an internal error and cannot continue with the connection";
117    CONNECTION_REFUSED(0x2) "the server refused to accept a new connection";
118    FLOW_CONTROL_ERROR(0x3) "received more data than permitted in advertised data limits";
119    STREAM_LIMIT_ERROR(0x4) "received a frame for a stream identifier that exceeded advertised the stream limit for the corresponding stream type";
120    STREAM_STATE_ERROR(0x5) "received a frame for a stream that was not in a state that permitted that frame";
121    FINAL_SIZE_ERROR(0x6) "received a STREAM frame or a RESET_STREAM frame containing a different final size to the one already established";
122    FRAME_ENCODING_ERROR(0x7) "received a frame that was badly formatted";
123    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";
124    CONNECTION_ID_LIMIT_ERROR(0x9) "the number of connection IDs provided by the peer exceeds the advertised active_connection_id_limit";
125    PROTOCOL_VIOLATION(0xA) "detected an error with protocol compliance that was not covered by more specific error codes";
126    INVALID_TOKEN(0xB) "received an invalid Retry Token in a client Initial";
127    APPLICATION_ERROR(0xC) "the application or application protocol caused the connection to be closed during the handshake";
128    CRYPTO_BUFFER_EXCEEDED(0xD) "received more data in CRYPTO frames than can be buffered";
129    KEY_UPDATE_ERROR(0xE) "key update error";
130    AEAD_LIMIT_REACHED(0xF) "the endpoint has reached the confidentiality or integrity limit for the AEAD algorithm";
131    NO_VIABLE_PATH(0x10) "no viable network path exists";
132}