libp2p_swarm/connection/
error.rs

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.
20
21use crate::transport::TransportError;
22use crate::Multiaddr;
23use crate::{ConnectedPoint, PeerId};
24use std::{fmt, io};
25
26/// 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?
31    IO(io::Error),
32
33    /// The connection keep-alive timeout expired.
34    KeepAliveTimeout,
35}
36
37impl fmt::Display for ConnectionError {
38    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39        match self {
40            ConnectionError::IO(err) => write!(f, "Connection error: I/O error: {err}"),
41            ConnectionError::KeepAliveTimeout => {
42                write!(f, "Connection closed due to expired keep-alive timeout.")
43            }
44        }
45    }
46}
47
48impl std::error::Error for ConnectionError {
49    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
50        match self {
51            ConnectionError::IO(err) => Some(err),
52            ConnectionError::KeepAliveTimeout => None,
53        }
54    }
55}
56
57impl From<io::Error> for ConnectionError {
58    fn from(error: io::Error) -> Self {
59        ConnectionError::IO(error)
60    }
61}
62
63/// 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>)>>;
70
71/// Errors that can occur in the context of a pending incoming `Connection`.
72pub(crate) type PendingInboundConnectionError = PendingConnectionError<TransportError<io::Error>>;
73
74/// 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.
78    Transport(TTransErr),
79
80    /// Pending connection attempt has been aborted.
81    Aborted,
82
83    /// The peer identity obtained on the connection did not
84    /// match the one that was expected.
85    WrongPeerId {
86        obtained: PeerId,
87        endpoint: ConnectedPoint,
88    },
89
90    /// The connection was dropped because it resolved to our own [`PeerId`].
91    LocalPeerId { endpoint: ConnectedPoint },
92}
93
94impl<T> PendingConnectionError<T> {
95    pub fn map<U>(self, f: impl FnOnce(T) -> U) -> PendingConnectionError<U> {
96        match 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}
108
109impl<TTransErr> fmt::Display for PendingConnectionError<TTransErr>
110where
111    TTransErr: fmt::Display + fmt::Debug,
112{
113    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
114        match self {
115            PendingConnectionError::Aborted => write!(f, "Pending connection: Aborted."),
116            PendingConnectionError::Transport(err) => {
117                write!(
118                    f,
119                    "Pending connection: Transport error on connection: {err}"
120                )
121            }
122            PendingConnectionError::WrongPeerId { obtained, endpoint } => {
123                write!(
124                    f,
125                    "Pending connection: Unexpected peer ID {obtained} at {endpoint:?}."
126                )
127            }
128            PendingConnectionError::LocalPeerId { endpoint } => {
129                write!(f, "Pending connection: Local peer ID at {endpoint:?}.")
130            }
131        }
132    }
133}
134
135impl<TTransErr> std::error::Error for PendingConnectionError<TTransErr>
136where
137    TTransErr: std::error::Error + 'static,
138{
139    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
140        match self {
141            PendingConnectionError::Transport(_) => None,
142            PendingConnectionError::WrongPeerId { .. } => None,
143            PendingConnectionError::LocalPeerId { .. } => None,
144            PendingConnectionError::Aborted => None,
145        }
146    }
147}