s2n_quic_dc/stream/send/
error.rs1use crate::{
5 event::IntoEvent,
6 stream::{packet_number, recv, shared::ShutdownKind},
7};
8use core::{fmt, panic::Location};
9use s2n_quic_core::{buffer, varint::VarInt};
10
11#[derive(Clone, Copy)]
12pub struct Error {
13 pub(crate) kind: Kind,
14 pub(crate) location: &'static Location<'static>,
15}
16
17impl fmt::Debug for Error {
18 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
19 f.debug_struct("Error")
20 .field("kind", &self.kind)
21 .field("crate", &"s2n-quic-dc")
22 .field("file", &self.file())
23 .field("line", &self.location.line())
24 .finish()
25 }
26}
27
28impl fmt::Display for Error {
29 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
30 let Self { kind, location } = self;
31 let file = self.file();
32 let line = location.line();
33 write!(f, "[s2n-quic-dc::{file}:{line}]: {kind}")
34 }
35}
36
37impl core::error::Error for Error {}
38
39impl IntoEvent<Error> for Error {
40 fn into_event(self) -> Error {
41 self
42 }
43}
44
45impl Error {
46 #[track_caller]
47 #[inline]
48 pub fn new(kind: Kind) -> Self {
49 Self {
50 kind,
51 location: Location::caller(),
52 }
53 }
54
55 #[inline]
56 pub fn kind(&self) -> &Kind {
57 &self.kind
58 }
59
60 #[inline]
61 fn file(&self) -> &'static str {
62 self.location
63 .file()
64 .trim_start_matches(concat!(env!("CARGO_MANIFEST_DIR"), "/src/"))
65 }
66
67 pub(crate) fn for_recv(self) -> Option<recv::Error> {
68 let kind = self.kind.for_recv()?;
69 Some(recv::Error {
70 kind,
71 location: self.location,
72 })
73 }
74}
75
76impl From<Kind> for Error {
77 #[track_caller]
78 #[inline]
79 fn from(kind: Kind) -> Self {
80 Self::new(kind)
81 }
82}
83
84#[derive(Clone, Copy, Debug, thiserror::Error)]
85pub enum Kind {
86 #[error("payload provided is too large and exceeded the maximum offset")]
87 PayloadTooLarge,
88 #[error("the provided packet buffer is too small for the minimum packet size")]
89 PacketBufferTooSmall,
90 #[error("the number of packets able to be sent on the sender has been exceeded")]
91 PacketNumberExhaustion,
92 #[error("retransmission not possible")]
93 RetransmissionFailure,
94 #[error("stream has been finished")]
95 StreamFinished,
96 #[error("the final size of the stream has changed")]
97 FinalSizeChanged,
98 #[error("the sender idle timer expired")]
99 IdleTimeout,
100 #[error("the crypto key has been replayed and is invalid")]
101 KeyReplayPrevented,
102 #[error("the crypto key has been potentially replayed (gap: {gap:?}) and is invalid")]
103 KeyReplayMaybePrevented { gap: Option<u64> },
104 #[error("the stream is using an unknown path secret")]
105 UnknownPathSecret,
106 #[error("the stream was reset by the peer with code {code}")]
107 TransportError { code: VarInt },
108 #[error("the stream was closed with application code {error}")]
109 ApplicationError {
110 error: s2n_quic_core::application::Error,
111 },
112 #[error("an invalid frame was received: {decoder}")]
113 FrameError { decoder: s2n_codec::DecoderError },
114 #[error("the stream experienced an unrecoverable error")]
115 FatalError,
116}
117
118impl Kind {
119 #[inline]
120 #[track_caller]
121 pub(crate) fn err(self) -> Error {
122 Error::new(self)
123 }
124
125 pub(crate) fn for_recv(self) -> Option<recv::ErrorKind> {
126 use recv::ErrorKind as RecvKind;
127
128 match self {
129 Kind::PayloadTooLarge => None,
130 Kind::PacketBufferTooSmall => None,
131 Kind::PacketNumberExhaustion => None,
132 Kind::RetransmissionFailure => None,
133 Kind::StreamFinished => None,
134 Kind::FinalSizeChanged => None,
135 Kind::IdleTimeout => Some(RecvKind::IdleTimeout),
136 Kind::KeyReplayPrevented => Some(RecvKind::KeyReplayPrevented),
137 Kind::KeyReplayMaybePrevented { gap } => {
138 Some(RecvKind::KeyReplayMaybePrevented { gap })
139 }
140 Kind::UnknownPathSecret => Some(RecvKind::UnknownPathSecret),
141 Kind::TransportError { code } => Some(RecvKind::TransportError { code }),
142 Kind::ApplicationError { error } if *error == 0 => None,
144 Kind::ApplicationError { error } => Some(RecvKind::ApplicationError { error }),
145 Kind::FrameError { .. } => None,
146 Kind::FatalError => Some(RecvKind::TruncatedTransport),
147 }
148 }
149}
150
151impl From<Error> for std::io::Error {
152 #[inline]
153 #[track_caller]
154 fn from(error: Error) -> Self {
155 Self::new(error.kind.into(), error)
156 }
157}
158
159impl From<Kind> for std::io::ErrorKind {
160 #[inline]
161 fn from(kind: Kind) -> Self {
162 use std::io::ErrorKind;
163 match kind {
164 Kind::PayloadTooLarge => ErrorKind::BrokenPipe,
165 Kind::PacketBufferTooSmall => ErrorKind::InvalidInput,
166 Kind::PacketNumberExhaustion => ErrorKind::BrokenPipe,
167 Kind::RetransmissionFailure => ErrorKind::BrokenPipe,
168 Kind::StreamFinished => ErrorKind::UnexpectedEof,
169 Kind::FinalSizeChanged => ErrorKind::InvalidInput,
170 Kind::IdleTimeout => ErrorKind::TimedOut,
171 Kind::KeyReplayPrevented => ErrorKind::PermissionDenied,
172 Kind::KeyReplayMaybePrevented { .. } => ErrorKind::PermissionDenied,
173 Kind::UnknownPathSecret => ErrorKind::PermissionDenied,
174 Kind::ApplicationError { error } if *error == ShutdownKind::PRUNED_CODE as u64 => {
175 ErrorKind::ConnectionRefused
176 }
177 Kind::ApplicationError { .. } => ErrorKind::ConnectionReset,
178 Kind::TransportError { .. } => ErrorKind::ConnectionAborted,
179 Kind::FrameError { .. } => ErrorKind::InvalidData,
180 Kind::FatalError => ErrorKind::BrokenPipe,
181 }
182 }
183}
184
185impl From<packet_number::ExhaustionError> for Error {
186 #[inline]
187 #[track_caller]
188 fn from(_error: packet_number::ExhaustionError) -> Self {
189 Kind::PacketNumberExhaustion.err()
190 }
191}
192
193impl From<buffer::Error<core::convert::Infallible>> for Error {
194 #[inline]
195 #[track_caller]
196 fn from(error: buffer::Error<core::convert::Infallible>) -> Self {
197 match error {
198 buffer::Error::OutOfRange => Kind::PayloadTooLarge.err(),
199 buffer::Error::InvalidFin => Kind::FinalSizeChanged.err(),
200 buffer::Error::ReaderError(_) => unreachable!(),
201 }
202 }
203}