1use bytes::Bytes;
11use std::{fmt, io, net::SocketAddr};
12use thiserror::Error;
13
14#[derive(Error, Debug)]
16pub enum EndpointError {
17    #[error("Certificate could not be generated for config")]
19    Certificate(CertificateError),
20    #[error(transparent)]
22    IoError(#[from] io::Error),
23}
24
25#[derive(Error, Debug)]
27pub enum CertificateError {
28    #[error("Rcgen internal error generating certificate")]
30    Rcgen(#[from] rcgen::RcgenError),
31    #[error("Certificate or name validation error")]
33    WebPki(#[from] webpki::Error),
34    #[error("Rustls internal error")]
36    Rustls(#[from] rustls::Error),
37}
38
39#[derive(Clone, Debug, Error, PartialEq, Eq)]
43pub enum ConnectionError {
44    #[error("The endpoint has been stopped")]
46    Stopped,
47
48    #[error("The number of active connections on the local endpoint is at the limit")]
55    TooManyConnections,
56
57    #[error("Invalid remote address: {0}")]
61    InvalidAddress(SocketAddr),
62
63    #[error("BUG: internal configuration error")]
68    InternalConfigError(#[source] InternalConfigError),
69
70    #[error("{}", quinn::ConnectionError::VersionMismatch)]
72    VersionMismatch,
73
74    #[error("{0}")]
76    TransportError(#[source] quinn_proto::TransportError),
77
78    #[error("{}", quinn::ConnectionError::Reset)]
80    Reset,
81
82    #[error("{}", quinn::ConnectionError::TimedOut)]
84    TimedOut,
85
86    #[error("The connection was closed, {0}")]
88    Closed(Close),
89}
90
91impl From<quinn::ConnectError> for ConnectionError {
92    fn from(error: quinn::ConnectError) -> Self {
93        match error {
94            quinn::ConnectError::EndpointStopping => Self::Stopped,
95            quinn::ConnectError::TooManyConnections => Self::TooManyConnections,
96            quinn::ConnectError::InvalidRemoteAddress(addr) => Self::InvalidAddress(addr),
97            quinn::ConnectError::InvalidDnsName(_)
98            | quinn::ConnectError::NoDefaultClientConfig
99            | quinn::ConnectError::UnsupportedVersion => {
100                Self::InternalConfigError(InternalConfigError(error))
104            }
105        }
106    }
107}
108
109impl From<quinn::ConnectionError> for ConnectionError {
110    fn from(error: quinn::ConnectionError) -> Self {
111        match error {
112            quinn::ConnectionError::LocallyClosed => Self::Closed(Close::Local),
113            quinn::ConnectionError::ApplicationClosed(close) => Self::Closed(Close::Application {
114                error_code: close.error_code.into_inner(),
115                reason: close.reason,
116            }),
117            quinn::ConnectionError::ConnectionClosed(close) => Self::Closed(Close::Transport {
118                error_code: TransportErrorCode(close.error_code),
119                reason: close.reason,
120            }),
121            quinn::ConnectionError::VersionMismatch => Self::VersionMismatch,
122            quinn::ConnectionError::TransportError(error) => Self::TransportError(error),
123            quinn::ConnectionError::Reset => Self::Reset,
124            quinn::ConnectionError::TimedOut => Self::TimedOut,
125        }
126    }
127}
128
129#[derive(Clone, Debug, Error, PartialEq, Eq)]
131#[error(transparent)]
132pub struct InternalConfigError(quinn::ConnectError);
133
134#[derive(Clone, Debug, PartialEq, Eq)]
136pub enum Close {
137    Local,
139
140    Application {
142        error_code: u64,
144
145        reason: Bytes,
147    },
148
149    Transport {
153        error_code: TransportErrorCode,
155
156        reason: Bytes,
158    },
159}
160
161impl fmt::Display for Close {
162    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
163        let (closed_by, error_code, reason): (_, &dyn fmt::Display, _) = match self {
164            Self::Local => return write!(f, "we closed the connection"),
165            Self::Application { error_code, reason } => ("remote application", error_code, reason),
166            Self::Transport { error_code, reason } => ("transport layer", error_code, reason),
167        };
168        write!(
169            f,
170            "{} closed the connection (error code: {}, reason: {})",
171            closed_by,
172            error_code,
173            String::from_utf8_lossy(reason)
174        )
175    }
176}
177
178impl From<quinn::ApplicationClose> for Close {
179    fn from(close: quinn::ApplicationClose) -> Self {
180        Self::Application {
181            error_code: close.error_code.into_inner(),
182            reason: close.reason,
183        }
184    }
185}
186
187impl From<quinn::ConnectionClose> for Close {
188    fn from(close: quinn::ConnectionClose) -> Self {
189        Self::Transport {
190            error_code: TransportErrorCode(close.error_code),
191            reason: close.reason,
192        }
193    }
194}
195
196#[derive(Clone, PartialEq, Eq)]
200pub struct TransportErrorCode(quinn_proto::TransportErrorCode);
201
202impl fmt::Debug for TransportErrorCode {
203    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
204        write!(f, "{:?}", self.0)
205    }
206}
207
208impl fmt::Display for TransportErrorCode {
209    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
210        write!(f, "{}", self.0)
211    }
212}
213
214#[derive(Debug, Error)]
220pub enum RpcError {
221    #[error("We did not receive a response within the expected time")]
223    TimedOut,
224
225    #[error("Failed to send the request")]
227    Send(#[from] SendError),
228
229    #[error("Failed to receive the response")]
231    Recv(#[from] RecvError),
232}
233
234impl From<ConnectionError> for RpcError {
238    fn from(error: ConnectionError) -> Self {
239        Self::Send(error.into())
240    }
241}
242
243impl From<quinn::ConnectionError> for RpcError {
244    fn from(error: quinn::ConnectionError) -> Self {
245        Self::Send(error.into())
246    }
247}
248
249impl From<tokio::time::error::Elapsed> for RpcError {
250    fn from(_: tokio::time::error::Elapsed) -> Self {
251        Self::TimedOut
252    }
253}
254
255#[derive(Debug, Error)]
257pub enum SendError {
258    #[error("The serialized message is too long ({0} bytes, max: 4 GiB)")]
260    MessageTooLong(usize),
261
262    #[error("Failed to serialize message")]
268    Serialization(#[from] bincode::Error),
269
270    #[error("Connection was lost when trying to send a message")]
272    ConnectionLost(#[from] ConnectionError),
273
274    #[error("Stream was lost when trying to send a message")]
276    StreamLost(#[source] StreamError),
277}
278
279impl From<quinn::ConnectionError> for SendError {
280    fn from(error: quinn::ConnectionError) -> Self {
281        Self::ConnectionLost(error.into())
282    }
283}
284
285impl From<quinn::WriteError> for SendError {
286    fn from(error: quinn::WriteError) -> Self {
287        match error {
288            quinn::WriteError::Stopped(code) => Self::StreamLost(StreamError::Stopped(code.into())),
289            quinn::WriteError::ConnectionLost(error) => Self::ConnectionLost(error.into()),
290            quinn::WriteError::UnknownStream => Self::StreamLost(StreamError::Gone),
291            quinn::WriteError::ZeroRttRejected => Self::StreamLost(StreamError::Unsupported(
292                UnsupportedStreamOperation(error.into()),
293            )),
294        }
295    }
296}
297
298#[derive(Debug, Error)]
300pub enum RecvError {
301    #[error("Message received from peer has an empty payload")]
303    EmptyMsgPayload,
304
305    #[error("Received too few bytes for message")]
307    NotEnoughBytes,
308
309    #[error("Failed to deserialize message")]
311    Serialization(#[from] bincode::Error),
312
313    #[error("Invalid message type flag found in message header: {0}")]
315    InvalidMsgTypeFlag(u8),
316
317    #[error("Type of message received is unexpected: {0}")]
319    UnexpectedMsgReceived(String),
320
321    #[error("Connection was lost when trying to receive a message")]
323    ConnectionLost(#[from] ConnectionError),
324
325    #[error("Error reading to end of stream")]
327    ReadToEndError(#[from] quinn::ReadToEndError),
328
329    #[error("Stream was lost when trying to receive a message")]
331    StreamLost(#[source] StreamError),
332}
333
334impl From<quinn::ConnectionError> for RecvError {
335    fn from(error: quinn::ConnectionError) -> Self {
336        Self::ConnectionLost(error.into())
337    }
338}
339
340impl From<quinn::ReadError> for RecvError {
341    fn from(error: quinn::ReadError) -> Self {
342        use quinn::ReadError;
343
344        match error {
345            ReadError::Reset(code) => Self::StreamLost(StreamError::Stopped(code.into())),
346            ReadError::ConnectionLost(error) => Self::ConnectionLost(error.into()),
347            ReadError::UnknownStream => Self::StreamLost(StreamError::Gone),
348            ReadError::IllegalOrderedRead | ReadError::ZeroRttRejected => Self::StreamLost(
349                StreamError::Unsupported(UnsupportedStreamOperation(error.into())),
350            ),
351        }
352    }
353}
354
355impl From<quinn::ReadExactError> for RecvError {
356    fn from(error: quinn::ReadExactError) -> Self {
357        match error {
358            quinn::ReadExactError::FinishedEarly => Self::NotEnoughBytes,
359            quinn::ReadExactError::ReadError(error) => error.into(),
360        }
361    }
362}
363
364#[derive(Debug, Error)]
366pub enum StreamError {
367    #[error("The peer abandoned the stream (error code: {0})")]
369    Stopped(u64),
370
371    #[error("The stream was already stopped, finished, or reset")]
373    Gone,
374
375    #[error("An error was caused by an unsupported operation")]
380    Unsupported(#[source] UnsupportedStreamOperation),
381}
382
383#[derive(Debug, Error)]
385#[error(transparent)]
386pub struct UnsupportedStreamOperation(Box<dyn std::error::Error + Send + Sync>);