ant_quic/
transport_error.rs

1// Copyright 2024 Saorsa Labs Ltd.
2//
3// This Saorsa Network Software is licensed under the General Public License (GPL), version 3.
4// Please see the file LICENSE-GPL, or visit <http://www.gnu.org/licenses/> for the full text.
5//
6// Full details available at https://saorsalabs.com/licenses
7
8use std::fmt;
9
10use bytes::{Buf, BufMut};
11
12use crate::{
13    coding::{self, BufExt, BufMutExt},
14    frame,
15};
16
17/// Transport-level errors occur when a peer violates the protocol specification
18#[derive(Debug, Clone, Eq, PartialEq)]
19pub struct Error {
20    /// Type of error
21    pub code: Code,
22    /// Frame type that triggered the error
23    pub frame: Option<frame::FrameType>,
24    /// Human-readable explanation of the reason
25    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/// Transport-level error code
54#[derive(Copy, Clone, Eq, PartialEq)]
55pub struct Code(u64);
56
57impl Code {
58    /// Create QUIC error code from TLS alert code
59    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        buf.write_var(self.0)
70    }
71}
72
73impl From<Code> for u64 {
74    fn from(x: Code) -> Self {
75        x.0
76    }
77}
78
79macro_rules! errors {
80    {$($name:ident($val:expr_2021) $desc:expr_2021;)*} => {
81        #[allow(non_snake_case, unused)]
82        impl Error {
83            $(
84            pub(crate) fn $name<T>(reason: T) -> Self where T: Into<String> {
85                Self {
86                    code: Code::$name,
87                    frame: None,
88                    reason: reason.into(),
89                }
90            }
91            )*
92        }
93
94        impl Code {
95            $(#[doc = $desc] pub const $name: Self = Code($val);)*
96        }
97
98        impl fmt::Debug for Code {
99            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
100                match self.0 {
101                    $($val => f.write_str(stringify!($name)),)*
102                    x if (0x100..0x200).contains(&x) => write!(f, "Code::crypto({:02x})", self.0 as u8),
103                    _ => write!(f, "Code({:x})", self.0),
104                }
105            }
106        }
107
108        impl fmt::Display for Code {
109            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
110                match self.0 {
111                    $($val => f.write_str($desc),)*
112                    // We're trying to be abstract over the crypto protocol, so human-readable descriptions here is tricky.
113                    _ if self.0 >= 0x100 && self.0 < 0x200 => write!(f, "the cryptographic handshake failed: error {}", self.0 & 0xFF),
114                    _ => f.write_str("unknown error"),
115                }
116            }
117        }
118    }
119}
120
121errors! {
122    NO_ERROR(0x0) "the connection is being closed abruptly in the absence of any error";
123    INTERNAL_ERROR(0x1) "the endpoint encountered an internal error and cannot continue with the connection";
124    CONNECTION_REFUSED(0x2) "the server refused to accept a new connection";
125    FLOW_CONTROL_ERROR(0x3) "received more data than permitted in advertised data limits";
126    STREAM_LIMIT_ERROR(0x4) "received a frame for a stream identifier that exceeded advertised the stream limit for the corresponding stream type";
127    STREAM_STATE_ERROR(0x5) "received a frame for a stream that was not in a state that permitted that frame";
128    FINAL_SIZE_ERROR(0x6) "received a STREAM frame or a RESET_STREAM frame containing a different final size to the one already established";
129    FRAME_ENCODING_ERROR(0x7) "received a frame that was badly formatted";
130    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";
131    CONNECTION_ID_LIMIT_ERROR(0x9) "the number of connection IDs provided by the peer exceeds the advertised active_connection_id_limit";
132    PROTOCOL_VIOLATION(0xA) "detected an error with protocol compliance that was not covered by more specific error codes";
133    INVALID_TOKEN(0xB) "received an invalid Retry Token in a client Initial";
134    APPLICATION_ERROR(0xC) "the application or application protocol caused the connection to be closed during the handshake";
135    CRYPTO_BUFFER_EXCEEDED(0xD) "received more data in CRYPTO frames than can be buffered";
136    KEY_UPDATE_ERROR(0xE) "key update error";
137    AEAD_LIMIT_REACHED(0xF) "the endpoint has reached the confidentiality or integrity limit for the AEAD algorithm";
138    NO_VIABLE_PATH(0x10) "no viable network path exists";
139}