iroh_quinn_proto/
transport_error.rs1use std::{fmt, sync::Arc};
2
3use bytes::{Buf, BufMut};
4
5use crate::{
6 VarInt,
7 coding::{self, BufExt, BufMutExt, Decodable, Encodable},
8 frame::MaybeFrame,
9};
10
11#[derive(Debug, Clone)]
17#[non_exhaustive]
18pub struct Error {
19 pub code: Code,
21 pub frame: MaybeFrame,
23 pub reason: String,
25 pub crypto: Option<Arc<dyn std::error::Error + Send + Sync>>,
27}
28
29impl Error {
30 pub fn new(code: Code, reason: String) -> Self {
32 Self {
33 code,
34 frame: MaybeFrame::None,
35 reason,
36 crypto: None,
37 }
38 }
39}
40
41impl PartialEq for Error {
42 fn eq(&self, other: &Self) -> bool {
43 self.code == other.code
44 }
45}
46
47impl Eq for Error {}
48
49impl fmt::Display for Error {
50 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
51 self.code.fmt(f)?;
52 if self.frame != MaybeFrame::None {
53 write!(f, " in {}", self.frame)?;
54 }
55 if !self.reason.is_empty() {
56 write!(f, ": {}", self.reason)?;
57 }
58 Ok(())
59 }
60}
61
62impl std::error::Error for Error {}
63
64#[derive(Copy, Clone, Eq, PartialEq)]
66pub struct Code(u64);
67
68impl Code {
69 pub fn crypto(code: u8) -> Self {
71 Self(0x100 | u64::from(code))
72 }
73}
74
75impl Decodable for Code {
76 fn decode<B: Buf>(buf: &mut B) -> coding::Result<Self> {
77 Ok(Self(buf.get_var()?))
78 }
79}
80
81impl Encodable for Code {
82 fn encode<B: BufMut>(&self, buf: &mut B) {
83 buf.write_var(self.0)
84 }
85}
86
87impl From<Code> for u64 {
88 fn from(x: Code) -> Self {
89 x.0
90 }
91}
92
93impl From<VarInt> for Code {
94 fn from(value: VarInt) -> Self {
95 Self(value.0)
96 }
97}
98
99impl From<Code> for VarInt {
100 fn from(value: Code) -> Self {
101 Self(value.0)
102 }
103}
104
105macro_rules! errors {
106 {$($name:ident($val:expr) $desc:expr;)*} => {
107 #[allow(non_snake_case, unused)]
108 impl Error {
109 $(
110 pub(crate) fn $name<T>(reason: T) -> Self where T: Into<String> {
111 Self::new(Code::$name, reason.into())
112 }
113 )*
114 }
115
116 impl Code {
117 $(#[doc = $desc] pub const $name: Self = Code($val);)*
118 }
119
120 impl fmt::Debug for Code {
121 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
122 match self.0 {
123 $($val => f.write_str(stringify!($name)),)*
124 x if (0x100..0x200).contains(&x) => write!(f, "Code::crypto({:02x})", self.0 as u8),
125 _ => write!(f, "Code({:x})", self.0),
126 }
127 }
128 }
129
130 impl fmt::Display for Code {
131 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
132 match self.0 {
133 $($val => f.write_str($desc),)*
134 _ if self.0 >= 0x100 && self.0 < 0x200 => write!(f, "the cryptographic handshake failed: error {}", self.0 & 0xFF),
136 _ => f.write_str("unknown error"),
137 }
138 }
139 }
140 }
141}
142
143errors! {
144 NO_ERROR(0x0) "the connection is being closed abruptly in the absence of any error";
145 INTERNAL_ERROR(0x1) "the endpoint encountered an internal error and cannot continue with the connection";
146 CONNECTION_REFUSED(0x2) "the server refused to accept a new connection";
147 FLOW_CONTROL_ERROR(0x3) "received more data than permitted in advertised data limits";
148 STREAM_LIMIT_ERROR(0x4) "received a frame for a stream identifier that exceeded advertised the stream limit for the corresponding stream type";
149 STREAM_STATE_ERROR(0x5) "received a frame for a stream that was not in a state that permitted that frame";
150 FINAL_SIZE_ERROR(0x6) "received a STREAM frame or a RESET_STREAM frame containing a different final size to the one already established";
151 FRAME_ENCODING_ERROR(0x7) "received a frame that was badly formatted";
152 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";
153 CONNECTION_ID_LIMIT_ERROR(0x9) "the number of connection IDs provided by the peer exceeds the advertised active_connection_id_limit";
154 PROTOCOL_VIOLATION(0xA) "detected an error with protocol compliance that was not covered by more specific error codes";
155 INVALID_TOKEN(0xB) "received an invalid Retry Token in a client Initial";
156 APPLICATION_ERROR(0xC) "the application or application protocol caused the connection to be closed during the handshake";
157 CRYPTO_BUFFER_EXCEEDED(0xD) "received more data in CRYPTO frames than can be buffered";
158 KEY_UPDATE_ERROR(0xE) "key update error";
159 AEAD_LIMIT_REACHED(0xF) "the endpoint has reached the confidentiality or integrity limit for the AEAD algorithm";
160 NO_VIABLE_PATH(0x10) "no viable network path exists";
161 APPLICATION_ABANDON_PATH(0x004150504142414e) "Path abandoned at the application's request";
162 PATH_RESOURCE_LIMIT_REACHED(0x0052534c494d4954) "Path abandoned due to resource limitations in the transport";
163 PATH_UNSTABLE_OR_POOR(0x00554e5f494e5446) "Path abandoned due to unstable interfaces";
164 NO_CID_AVAILABLE_FOR_PATH(0x004e4f5f4349445f) "Path abandoned due to no available connection IDs for the path";
165}