1use crate::asn1::Frame;
2use crate::policy::TransitStatus;
3#[cfg(feature = "derive")]
4use crate::Errorizable;
5
6pub type Result<T> = core::result::Result<T, TransportError>;
7
8#[derive(Debug, Copy, Clone, PartialEq, Eq)]
10pub enum TransportFailure {
11 EncodingFailed,
13 EncryptionFailed,
15 SizeExceeded,
17 EncryptorUnavailable,
19 NonceGenerationFailed,
21 Busy,
23 Forbidden,
25 Unauthorized,
27 Timeout,
29 PolicyRejection,
31}
32
33#[cfg_attr(feature = "derive", derive(Errorizable))]
35#[derive(Debug)]
36pub enum TransportError {
37 #[cfg_attr(feature = "derive", error("Connection closed gracefully"))]
38 ConnectionClosed,
39 #[cfg_attr(feature = "derive", error("Connection failed"))]
40 ConnectionFailed,
41 #[cfg_attr(feature = "derive", error("Send failed"))]
42 SendFailed,
43 #[cfg_attr(feature = "derive", error("Encryption required but not provided"))]
44 MissingEncryption,
45 #[cfg_attr(feature = "derive", error("Invalid message"))]
46 InvalidMessage,
47 #[cfg_attr(feature = "derive", error("Invalid reply"))]
48 InvalidReply,
49 #[cfg_attr(feature = "derive", error("Missing request"))]
50 MissingRequest,
51 #[cfg_attr(feature = "derive", error("Max retries exceeded"))]
52 MaxRetriesExceeded,
53 #[cfg_attr(feature = "derive", error("Invalid address"))]
54 InvalidAddress,
55 #[cfg_attr(feature = "derive", error("Invalid state"))]
56 InvalidState,
57 #[cfg(feature = "x509")]
58 #[cfg_attr(feature = "derive", error("Invalid certificate: {0}"))]
59 #[cfg_attr(feature = "derive", from)]
60 InvalidCertificate(crate::crypto::x509::error::CertificateValidationError),
61 #[cfg_attr(feature = "derive", error("Message not sent: {1:?} - {0:?}"))]
62 MessageNotSent(Box<Frame>, TransportFailure),
63 #[cfg_attr(feature = "derive", error("Operation failed: {0:?}"))]
64 OperationFailed(TransportFailure),
65 #[cfg(feature = "x509")]
66 #[cfg_attr(feature = "derive", error("Handshake error: {0}"))]
67 #[cfg_attr(feature = "derive", from)]
68 HandshakeError(crate::transport::handshake::HandshakeError),
69 #[cfg_attr(feature = "derive", error("DER error: {0}"))]
70 #[cfg_attr(feature = "derive", from)]
71 DerError(der::Error),
72 #[cfg(feature = "std")]
73 #[cfg_attr(feature = "derive", error("I/O error: {0}"))]
74 #[cfg_attr(feature = "derive", from)]
75 IoError(std::io::Error),
76}
77
78#[cfg(not(feature = "derive"))]
79impl core::fmt::Display for TransportError {
80 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
81 write!(f, "{self:?}")
82 }
83}
84
85impl From<TransitStatus> for TransportError {
86 fn from(status: TransitStatus) -> Self {
87 match status {
88 TransitStatus::Request => TransportError::InvalidMessage,
89 TransitStatus::Accepted => TransportError::InvalidMessage,
90 TransitStatus::Busy => TransportError::OperationFailed(TransportFailure::Busy),
91 TransitStatus::Unauthorized => TransportError::OperationFailed(TransportFailure::Unauthorized),
92 TransitStatus::Forbidden => TransportError::OperationFailed(TransportFailure::Forbidden),
93 TransitStatus::Timeout => TransportError::OperationFailed(TransportFailure::Timeout),
94 }
95 }
96}
97
98#[cfg(not(feature = "derive"))]
99impl core::error::Error for TransportError {}
100
101#[cfg(all(feature = "std", not(feature = "derive")))]
102crate::impl_from!(std::io::Error => TransportError::IoError);
103#[cfg(not(feature = "derive"))]
104crate::impl_from!(der::Error => TransportError::DerError);
105#[cfg(all(feature = "x509", not(feature = "derive")))]
106crate::impl_from!(crate::transport::handshake::HandshakeError => TransportError::HandshakeError);
107
108crate::impl_from!(
109 spki::Error => TransportError::DerError extract spki::Error::Asn1(der_err) =>
110 der_err else der::Error::from(der::ErrorKind::Failed)
111);
112#[cfg(feature = "x509")]
113crate::impl_from!(
114 x509_cert::builder::Error => TransportError::DerError extract x509_cert::builder::Error::Asn1(der_err) =>
115 der_err else der::Error::from(der::ErrorKind::Failed)
116);
117
118#[cfg(all(feature = "std", feature = "tcp"))]
120impl From<std::net::AddrParseError> for TransportError {
121 fn from(err: std::net::AddrParseError) -> Self {
122 TransportError::IoError(std::io::Error::new(std::io::ErrorKind::InvalidInput, err))
123 }
124}
125
126#[cfg(feature = "tokio")]
128impl From<tokio::task::JoinError> for TransportError {
129 fn from(err: tokio::task::JoinError) -> Self {
130 TransportError::IoError(std::io::Error::other(err))
131 }
132}
133
134#[cfg(feature = "tokio")]
136impl From<tokio::time::error::Elapsed> for TransportError {
137 fn from(_: tokio::time::error::Elapsed) -> Self {
138 TransportError::OperationFailed(TransportFailure::Timeout)
139 }
140}
141
142#[cfg(all(feature = "x509", feature = "secp256k1"))]
144impl From<k256::ecdsa::Error> for TransportError {
145 fn from(err: k256::ecdsa::Error) -> Self {
146 TransportError::HandshakeError(crate::transport::handshake::HandshakeError::from(err))
147 }
148}
149
150impl TransportError {
151 pub fn from_failure(frame: Frame, failure: TransportFailure) -> Self {
152 TransportError::MessageNotSent(Box::new(frame), failure)
153 }
154
155 pub fn take_frame(self) -> Option<crate::asn1::Frame> {
157 match self {
158 TransportError::MessageNotSent(frame, _) => Some(*frame),
159 _ => None,
160 }
161 }
162
163 pub fn frame(&self) -> Option<&crate::asn1::Frame> {
165 match self {
166 TransportError::MessageNotSent(frame, _) => Some(frame),
167 _ => None,
168 }
169 }
170
171 pub fn failure_reason(&self) -> Option<&TransportFailure> {
173 match self {
174 TransportError::MessageNotSent(_, reason) => Some(reason),
175 _ => None,
176 }
177 }
178
179 pub fn is_connection_error(&self) -> bool {
184 matches!(
185 self,
186 TransportError::ConnectionClosed
187 | TransportError::ConnectionFailed
188 | TransportError::OperationFailed(TransportFailure::Timeout)
189 ) || {
190 #[cfg(feature = "std")]
191 {
192 matches!(self, TransportError::IoError(_))
193 }
194 #[cfg(not(feature = "std"))]
195 {
196 false
197 }
198 }
199 }
200}
201
202impl From<TransportFailure> for TransportError {
203 fn from(failure: TransportFailure) -> Self {
204 match failure {
205 TransportFailure::EncodingFailed => TransportError::InvalidMessage,
206 TransportFailure::SizeExceeded => TransportError::InvalidMessage,
207 TransportFailure::PolicyRejection => TransportError::InvalidReply,
208 TransportFailure::NonceGenerationFailed => TransportError::SendFailed,
209 other => TransportError::OperationFailed(other),
211 }
212 }
213}
214
215impl TransportFailure {
216 pub fn with_frame(self, frame: Frame) -> TransportError {
217 TransportError::from_failure(frame, self)
218 }
219
220 pub fn with_optional_frame(self, frame: Option<Frame>) -> TransportError {
221 if let Some(frame) = frame {
222 self.with_frame(frame)
223 } else {
224 self.into()
225 }
226 }
227}