1// Copyright 2018 Parity Technologies (UK) Ltd.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a
4// copy of this software and associated documentation files (the "Software"),
5// to deal in the Software without restriction, including without limitation
6// the rights to use, copy, modify, merge, publish, distribute, sublicense,
7// and/or sell copies of the Software, and to permit persons to whom the
8// Software is furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in
11// all copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
14// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19// DEALINGS IN THE SOFTWARE.
2021use crate::transport::TransportError;
22use crate::Multiaddr;
23use crate::{ConnectedPoint, PeerId};
24use std::{fmt, io};
2526/// Errors that can occur in the context of an established `Connection`.
27#[derive(Debug)]
28pub enum ConnectionError {
29/// An I/O error occurred on the connection.
30// TODO: Eventually this should also be a custom error?
31IO(io::Error),
3233/// The connection keep-alive timeout expired.
34KeepAliveTimeout,
35}
3637impl fmt::Display for ConnectionError {
38fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39match self {
40 ConnectionError::IO(err) => write!(f, "Connection error: I/O error: {err}"),
41 ConnectionError::KeepAliveTimeout => {
42write!(f, "Connection closed due to expired keep-alive timeout.")
43 }
44 }
45 }
46}
4748impl std::error::Error for ConnectionError {
49fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
50match self {
51 ConnectionError::IO(err) => Some(err),
52 ConnectionError::KeepAliveTimeout => None,
53 }
54 }
55}
5657impl From<io::Error> for ConnectionError {
58fn from(error: io::Error) -> Self {
59 ConnectionError::IO(error)
60 }
61}
6263/// Errors that can occur in the context of a pending outgoing `Connection`.
64///
65/// Note: Addresses for an outbound connection are dialed in parallel. Thus, compared to
66/// [`PendingInboundConnectionError`], one or more [`TransportError`]s can occur for a single
67/// connection.
68pub(crate) type PendingOutboundConnectionError =
69 PendingConnectionError<Vec<(Multiaddr, TransportError<io::Error>)>>;
7071/// Errors that can occur in the context of a pending incoming `Connection`.
72pub(crate) type PendingInboundConnectionError = PendingConnectionError<TransportError<io::Error>>;
7374/// Errors that can occur in the context of a pending `Connection`.
75#[derive(Debug)]
76pub enum PendingConnectionError<TTransErr> {
77/// An error occurred while negotiating the transport protocol(s) on a connection.
78Transport(TTransErr),
7980/// Pending connection attempt has been aborted.
81Aborted,
8283/// The peer identity obtained on the connection did not
84 /// match the one that was expected.
85WrongPeerId {
86 obtained: PeerId,
87 endpoint: ConnectedPoint,
88 },
8990/// The connection was dropped because it resolved to our own [`PeerId`].
91LocalPeerId { endpoint: ConnectedPoint },
92}
9394impl<T> PendingConnectionError<T> {
95pub fn map<U>(self, f: impl FnOnce(T) -> U) -> PendingConnectionError<U> {
96match self {
97 PendingConnectionError::Transport(t) => PendingConnectionError::Transport(f(t)),
98 PendingConnectionError::Aborted => PendingConnectionError::Aborted,
99 PendingConnectionError::WrongPeerId { obtained, endpoint } => {
100 PendingConnectionError::WrongPeerId { obtained, endpoint }
101 }
102 PendingConnectionError::LocalPeerId { endpoint } => {
103 PendingConnectionError::LocalPeerId { endpoint }
104 }
105 }
106 }
107}
108109impl<TTransErr> fmt::Display for PendingConnectionError<TTransErr>
110where
111TTransErr: fmt::Display + fmt::Debug,
112{
113fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
114match self {
115 PendingConnectionError::Aborted => write!(f, "Pending connection: Aborted."),
116 PendingConnectionError::Transport(err) => {
117write!(
118 f,
119"Pending connection: Transport error on connection: {err}"
120)
121 }
122 PendingConnectionError::WrongPeerId { obtained, endpoint } => {
123write!(
124 f,
125"Pending connection: Unexpected peer ID {obtained} at {endpoint:?}."
126)
127 }
128 PendingConnectionError::LocalPeerId { endpoint } => {
129write!(f, "Pending connection: Local peer ID at {endpoint:?}.")
130 }
131 }
132 }
133}
134135impl<TTransErr> std::error::Error for PendingConnectionError<TTransErr>
136where
137TTransErr: std::error::Error + 'static,
138{
139fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
140match self {
141 PendingConnectionError::Transport(_) => None,
142 PendingConnectionError::WrongPeerId { .. } => None,
143 PendingConnectionError::LocalPeerId { .. } => None,
144 PendingConnectionError::Aborted => None,
145 }
146 }
147}