Skip to main content

fizyr_rpc/
error.rs

1//! Error types.
2
3/// Opaque error for all RPC operations.
4#[derive(Debug)]
5pub struct Error {
6	pub(crate) inner: private::InnerError,
7}
8
9impl std::error::Error for Error {}
10
11impl std::fmt::Display for Error {
12	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13		write!(f, "{}", self.inner)
14	}
15}
16
17impl From<private::InnerError> for Error {
18	fn from(error: private::InnerError) -> Error {
19		Self { inner: error }
20	}
21}
22
23/// The received update is unknown or invalid.
24///
25/// This error is used in generated interfaces only.
26pub enum ParseUpdateError<Body> {
27	/// The received update has an unknown service ID.
28	UnknownUpdate(crate::Message<Body>),
29
30	/// The received update has a known service ID, but an invalid body.
31	///
32	/// The body has been consumed in the parse attempt,
33	/// so only the message header and parse error are available.
34	InvalidUpdate(crate::MessageHeader, Box<dyn std::error::Error + Send>),
35}
36
37/// Error that can occur when receiving a message from a peer using a generated interface.
38///
39/// Apart from the [`struct@Error`] reported by [`PeerHandle::recv_message()`][crate::PeerHandle::recv_message],
40/// this error is used when the received message has an unknown service ID or an invalid body.
41pub enum RecvMessageError<Body> {
42	/// The underlying call to [`PeerHandle::recv_message()`][crate::PeerHandle::recv_message] returned an error.
43	Other(Error),
44
45	/// The received stream message has an unknown service ID.
46	UnknownStream(crate::Message<Body>),
47
48	/// The received request has an unknown service ID.
49	UnknownRequest(crate::ReceivedRequestHandle<Body>, Body),
50
51	/// The received stream message has a known service ID, but an invalid body.
52	///
53	/// The body has been consumed in the parse attempt,
54	/// so only the message header and parse error are available.
55	InvalidStream(crate::MessageHeader, Box<dyn std::error::Error + Send>),
56
57	/// The received request has a known service ID, but an invalid body.
58	///
59	/// The body has been consumed in the parse attempt,
60	/// so only the request handle and parse error are available.
61	InvalidRequest(crate::ReceivedRequestHandle<Body>, Box<dyn std::error::Error + Send>),
62}
63
64impl Error {
65	/// Create a new error from an I/O error.
66	pub fn io_error(error: std::io::Error) -> Self {
67		private::InnerError::from(error).into()
68	}
69
70	/// Create a new error for a message that is too short to be valid.
71	pub fn message_too_short(message_len: usize) -> Self {
72		private::InnerError::MessageTooShort { message_len }.into()
73	}
74
75	/// Create a new error for a message with an invalid message type in the header.
76	pub fn invalid_message_type(value: u32) -> Self {
77		private::InnerError::InvalidMessageType { value }.into()
78	}
79
80	/// Create a new error for a message with an body that exceeds the allowed size.
81	pub fn payload_too_large(body_len: usize, max_len: usize) -> Self {
82		private::InnerError::PayloadTooLarge { body_len, max_len }.into()
83	}
84
85	/// Create a new error for an incoming message with an unexpected service ID.
86	pub fn unexpected_service_id(service_id: i32) -> Self {
87		private::InnerError::UnexpectedServiceId { service_id }.into()
88	}
89
90	/// Create a new error for an outgoing message body that could not be encoded.
91	pub fn encode_failed(inner: Box<dyn std::error::Error + Send>) -> Self {
92		private::InnerError::EncodeFailed(inner).into()
93	}
94
95	/// Create a new error for an incoming message with a body that could not be decoded.
96	pub fn decode_failed(inner: Box<dyn std::error::Error + Send>) -> Self {
97		private::InnerError::DecodeFailed(inner).into()
98	}
99
100	/// Create a new error for an incoming message that represent an error response from the remote peer.
101	///
102	/// A remote error does not indicate a communication or protocol violation.
103	/// It is used when the remote peer correctly received and understood the request,
104	/// but is unable to succesfully complete it.
105	pub fn remote_error(message: String) -> Self {
106		private::InnerError::RemoteError(message).into()
107	}
108
109	/// Create a new error with a custom message.
110	pub fn custom(message: String) -> Self {
111		private::InnerError::Custom(message).into()
112	}
113
114	/// Check if this error is caused by the remote peer closing the connection cleanly.
115	pub fn is_connection_aborted(&self) -> bool {
116		if let private::InnerError::Io(e) = &self.inner {
117			e.kind() == std::io::ErrorKind::ConnectionAborted
118		} else {
119			false
120		}
121	}
122
123	/// Check if an unexpected message type was received.
124	///
125	/// This can happen when you call [`recv_response()`][crate::SentRequestHandle::recv_response] while an update message is still queued.
126	pub fn is_unexpected_message_type(&self) -> bool {
127		matches!(&self.inner, private::InnerError::UnexpectedMessageType(_))
128	}
129
130	/// Check if this error represent an error response from the remote peer.
131	///
132	/// See [`Self::remote_error()`] for more details on what a remote error is.
133	pub fn is_remote_error(&self) -> bool {
134		matches!(&self.inner, private::InnerError::RemoteError(_))
135	}
136
137	/// Get this error as remote error message.
138	///
139	/// See [`Self::remote_error()`] for more details on what a remote error is.
140	pub fn as_remote_error(&self) -> Option<&str> {
141		if let private::InnerError::RemoteError(msg) = &self.inner {
142			Some(msg)
143		} else {
144			None
145		}
146	}
147
148	/// Get this error as remote error message.
149	///
150	/// See [`Self::remote_error()`] for more details on what a remote error is.
151	pub fn into_remote_error(self) -> Option<String> {
152		if let private::InnerError::RemoteError(msg) = self.inner {
153			Some(msg)
154		} else {
155			None
156		}
157	}
158}
159
160impl<Body> RecvMessageError<Body> {
161	/// Check if this error is caused by the remote peer closing the connection cleanly.
162	pub fn is_connection_aborted(&self) -> bool {
163		if let Self::Other(e) = self {
164			e.is_connection_aborted()
165		} else {
166			false
167		}
168	}
169
170	/// Get the raw request handle associated with the received message.
171	///
172	/// The request handle can be used to send an error response to unknown or invalid requests.
173	///
174	/// For errors other than [`Self::UnknownRequest`] and [`Self::InvalidRequest`],
175	/// this function returns [`None`].
176	pub fn request_handle(&self) -> Option<&crate::ReceivedRequestHandle<Body>> {
177		match self {
178			Self::Other(_error) => None,
179			Self::UnknownStream(_message) => None,
180			Self::UnknownRequest(request, _body) => Some(request),
181			Self::InvalidStream(_message, _error) => None,
182			Self::InvalidRequest(request, _error) => Some(request),
183		}
184	}
185
186	/// Get the a mutable reference to the raw request handle associated with the received message.
187	///
188	/// The request handle can be used to send an error response to unknown or invalid requests.
189	///
190	/// For errors other than [`Self::UnknownRequest`] and [`Self::InvalidRequest`],
191	/// this function returns [`None`].
192	pub fn request_handle_mut(&mut self) -> Option<&mut crate::ReceivedRequestHandle<Body>> {
193		match self {
194			Self::Other(_error) => None,
195			Self::UnknownStream(_message) => None,
196			Self::UnknownRequest(request, _body) => Some(request),
197			Self::InvalidStream(_message, _error) => None,
198			Self::InvalidRequest(request, _error) => Some(request),
199		}
200	}
201}
202
203impl From<std::io::Error> for Error {
204	fn from(other: std::io::Error) -> Self {
205		Self::io_error(other)
206	}
207}
208
209impl<Body> From<Error> for RecvMessageError<Body> {
210	fn from(other: Error) -> Self {
211		Self::Other(other)
212	}
213}
214
215impl<Body> std::error::Error for ParseUpdateError<Body> {}
216impl<Body> std::error::Error for RecvMessageError<Body> {}
217
218impl<Body> std::fmt::Display for ParseUpdateError<Body> {
219	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
220		match self {
221			Self::UnknownUpdate(message) => write!(f, "received unknown update with service ID {}", message.header.service_id),
222			Self::InvalidUpdate(header, error) => write!(f, "received invalid update with service ID {}: {}", header.service_id, error),
223		}
224	}
225}
226
227impl<Body> std::fmt::Display for RecvMessageError<Body> {
228	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
229		match self {
230			Self::Other(e) => write!(f, "{}", e),
231			Self::UnknownStream(message) => write!(f, "received unknown stream message with service ID {}", message.header.service_id),
232			Self::InvalidStream(header, error) => write!(f, "received invalid stream message with service ID {}: {}", header.service_id, error),
233			Self::UnknownRequest(request, _body) => write!(f, "received unknown request message with service ID {}", request.service_id()),
234			Self::InvalidRequest(request, error) => write!(f, "received invalid request message with service ID {}: {}", request.service_id(), error),
235		}
236	}
237}
238
239impl<Body> std::fmt::Debug for ParseUpdateError<Body> {
240	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
241		match self {
242			Self::UnknownUpdate(message) => f.debug_tuple("UnknownUpdate").field(message).finish(),
243			Self::InvalidUpdate(header, error) => f.debug_tuple("InvalidUpdate").field(header).field(error).finish(),
244		}
245	}
246}
247
248impl<Body> std::fmt::Debug for RecvMessageError<Body> {
249	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
250		match self {
251			Self::Other(e) => f.debug_tuple("Other").field(e).finish(),
252			Self::UnknownStream(message) => f.debug_tuple("UnknownStream").field(message).finish(),
253			Self::UnknownRequest(request, _body) => f.debug_tuple("UnknownStream").field(request).finish(),
254			Self::InvalidStream(header, error) => f.debug_tuple("InvalidStread").field(header).field(error).finish(),
255			Self::InvalidRequest(request, error) => f.debug_tuple("InvalidRequest").field(request).field(error).finish(),
256		}
257	}
258}
259
260pub(crate) mod private {
261	use super::*;
262
263	pub(crate) fn connection_aborted() -> Error {
264		InnerError::from(std::io::Error::from(std::io::ErrorKind::ConnectionAborted)).into()
265	}
266
267	#[derive(Debug)]
268	#[doc(hidden)]
269	pub enum InnerError {
270		/// An I/O error occurred.
271		Io(std::io::Error),
272
273		/// The received message is too short to be valid.
274		MessageTooShort { message_len: usize },
275
276		/// The received message has an invalid type.
277		InvalidMessageType {
278			/// The received value.
279			value: u32,
280		},
281
282		/// The message body is too large.
283		PayloadTooLarge {
284			/// The actual length of the message body in bytes.
285			body_len: usize,
286
287			/// The maximum allowed length of a message body in bytes.
288			max_len: usize,
289		},
290
291		/// The request ID is already associated with an open request.
292		DuplicateRequestId {
293			/// The duplicate request ID.
294			request_id: u32,
295		},
296
297		/// The request ID is not associated with an open request.
298		UnknownRequestId {
299			/// The unknown request ID.
300			request_id: u32,
301		},
302
303		/// The received message has an unexpected message type.
304		UnexpectedMessageType(UnexpectedMessageType),
305
306		/// The received message has an unexpected service ID.
307		UnexpectedServiceId {
308			/// The unrecognized/unexpected service ID.
309			service_id: i32,
310		},
311
312		/// No free request ID was found.
313		NoFreeRequestIdFound,
314
315		/// The request has already been closed.
316		RequestClosed,
317
318		/// Failed to encode the message.
319		EncodeFailed(Box<dyn std::error::Error + Send>),
320
321		/// Failed to decode the message.
322		DecodeFailed(Box<dyn std::error::Error + Send>),
323
324		/// The remote peer replied with an error instead of the regular response.
325		RemoteError(String),
326
327		/// A custom error message.
328		Custom(String),
329	}
330
331	impl From<std::io::Error> for private::InnerError {
332		fn from(error: std::io::Error) -> Self {
333			private::InnerError::Io(error)
334		}
335	}
336
337	impl From<UnexpectedMessageType> for private::InnerError {
338		fn from(error: UnexpectedMessageType) -> Self {
339			private::InnerError::UnexpectedMessageType(error)
340		}
341	}
342
343	impl std::error::Error for InnerError {}
344
345	impl std::fmt::Display for InnerError {
346		fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
347			match self {
348				InnerError::Io(error) => write!(f, "{}", error),
349				InnerError::MessageTooShort { message_len } => write!(
350					f,
351					"the message is too short to be valid: need at least {} for the header, got only {message_len} bytes",
352					crate::HEADER_LEN
353				),
354				InnerError::InvalidMessageType { value } => write!(f, "invalid message type: expected a value in the range [0..4], got {value}"),
355				InnerError::PayloadTooLarge { body_len, max_len } => {
356					write!(f, "payload too large: maximum payload size is {max_len}, got {body_len}")
357				},
358				InnerError::DuplicateRequestId { request_id } => write!(
359					f,
360					"duplicate request ID: request ID {request_id} is already associated with an open request"
361				),
362				InnerError::UnknownRequestId { request_id } => {
363					write!(f, "unknown request ID: request ID {request_id} is not associated with an open request")
364				},
365				InnerError::UnexpectedMessageType(error) => write!(f, "{}", error),
366				InnerError::UnexpectedServiceId { service_id } => write!(f, "unexpected service ID: {service_id}"),
367				InnerError::NoFreeRequestIdFound => write!(f, "no free request ID was found"),
368				InnerError::RequestClosed => write!(f, "the request is already closed"),
369				InnerError::EncodeFailed(error) => write!(f, "{}", error),
370				InnerError::DecodeFailed(error) => write!(f, "{}", error),
371				InnerError::RemoteError(error) => write!(f, "{}", error),
372				InnerError::Custom(error) => write!(f, "{}", error),
373			}
374		}
375	}
376
377	/// Check if a message size is large enough to contain a valid message.
378	#[allow(dead_code)] // not used when all transports are disabled.
379	pub fn check_message_too_short(message_len: usize) -> Result<(), InnerError> {
380		if message_len >= crate::HEADER_LEN as usize {
381			Ok(())
382		} else {
383			Err(InnerError::MessageTooShort { message_len })
384		}
385	}
386
387	/// Check if a payload length is small enough to fit in a message body.
388	pub fn check_payload_too_large(body_len: usize, max_len: usize) -> Result<(), InnerError> {
389		if body_len <= max_len {
390			Ok(())
391		} else {
392			Err(InnerError::PayloadTooLarge { body_len, max_len })
393		}
394	}
395
396	/// The received message had an unexpected type.
397	#[derive(Debug, Clone)]
398	pub struct UnexpectedMessageType {
399		/// The actual type of the received message.
400		pub value: crate::MessageType,
401
402		/// The expected type of the received message.
403		pub expected: crate::MessageType,
404	}
405
406	impl std::error::Error for UnexpectedMessageType {}
407
408	impl std::fmt::Display for UnexpectedMessageType {
409		fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
410			// NOTE: we can use the same string for requester and responder updates,
411			// because they can never get mixed up.
412			// If that would happen, it means the message got routed wrong because it went in the wrong direction.
413			let to_str = |kind| match kind {
414				crate::MessageType::Request => "a request message",
415				crate::MessageType::Response => "a response message",
416				crate::MessageType::RequesterUpdate => "an update message",
417				crate::MessageType::ResponderUpdate => "an update message",
418				crate::MessageType::Stream => "a streaming message",
419			};
420			write!(
421				f,
422				"unexpected message type: expected {}, got {}",
423				to_str(self.expected),
424				to_str(self.value)
425			)
426		}
427	}
428}