network/
error.rs

1// Copyright 2019 Conflux Foundation. All rights reserved.
2// Conflux is free software and distributed under GNU General Public License.
3// See http://www.gnu.org/licenses/
4
5use crate::{iolib::IoError, service::ProtocolVersion, ProtocolId};
6use rlp::{self, Decodable, DecoderError, Encodable, Rlp, RlpStream};
7use std::{fmt, io, net};
8use thiserror::Error;
9
10#[derive(Clone, Debug, PartialEq, Eq)]
11pub enum DisconnectReason {
12    DisconnectRequested,
13    UselessPeer,
14    WrongEndpointInfo,
15    IpLimited,
16    UpdateNodeIdFailed,
17    Blacklisted,
18    Custom(String),
19    Unknown,
20}
21
22impl DisconnectReason {
23    fn code(&self) -> u8 {
24        match self {
25            DisconnectReason::DisconnectRequested => 0,
26            DisconnectReason::UselessPeer => 1,
27            DisconnectReason::WrongEndpointInfo => 2,
28            DisconnectReason::IpLimited => 3,
29            DisconnectReason::UpdateNodeIdFailed => 4,
30            DisconnectReason::Blacklisted => 5,
31            DisconnectReason::Custom(_) => 100,
32            DisconnectReason::Unknown => 0xff,
33        }
34    }
35}
36
37impl Encodable for DisconnectReason {
38    fn rlp_append(&self, s: &mut RlpStream) {
39        let mut raw = vec![self.code()];
40
41        if let DisconnectReason::Custom(msg) = self {
42            raw.extend(msg.bytes());
43        }
44
45        s.append_raw(&raw[..], raw.len());
46    }
47}
48
49impl Decodable for DisconnectReason {
50    fn decode(rlp: &Rlp) -> std::result::Result<Self, DecoderError> {
51        let raw = rlp.as_raw().to_vec();
52
53        if raw.is_empty() {
54            return Err(DecoderError::RlpIsTooShort);
55        }
56
57        match raw[0] {
58            0 => Ok(DisconnectReason::DisconnectRequested),
59            1 => Ok(DisconnectReason::UselessPeer),
60            2 => Ok(DisconnectReason::WrongEndpointInfo),
61            3 => Ok(DisconnectReason::IpLimited),
62            4 => Ok(DisconnectReason::UpdateNodeIdFailed),
63            5 => Ok(DisconnectReason::Blacklisted),
64            100 => match std::str::from_utf8(&raw[1..]) {
65                Err(_) => {
66                    Err(DecoderError::Custom("Unable to decode message part"))
67                }
68                Ok(msg) => Ok(DisconnectReason::Custom(msg.to_owned())),
69            },
70            _ => Ok(DisconnectReason::Unknown),
71        }
72    }
73}
74
75impl fmt::Display for DisconnectReason {
76    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
77        let msg = match *self {
78            DisconnectReason::DisconnectRequested => "disconnect requested",
79            DisconnectReason::UselessPeer => "useless peer",
80            DisconnectReason::WrongEndpointInfo => "wrong node id",
81            DisconnectReason::IpLimited => "IP limited",
82            DisconnectReason::UpdateNodeIdFailed => "Update node id failed",
83            DisconnectReason::Blacklisted => "blacklisted",
84            DisconnectReason::Custom(ref msg) => &msg[..],
85            DisconnectReason::Unknown => "unknown",
86        };
87
88        f.write_str(msg)
89    }
90}
91
92#[derive(Debug, Copy, Clone, PartialEq, Eq)]
93pub enum ThrottlingReason {
94    QueueFull,
95    Throttled,
96    PacketThrottled(&'static str),
97}
98
99impl fmt::Display for ThrottlingReason {
100    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
101        match *self {
102            ThrottlingReason::QueueFull => {
103                f.write_str("egress queue capacity reached")
104            }
105            ThrottlingReason::Throttled => f.write_str("egress throttled"),
106            ThrottlingReason::PacketThrottled(name) => {
107                let msg = format!("packet {} throttled", name);
108                f.write_str(msg.as_str())
109            }
110        }
111    }
112}
113
114#[derive(Debug, Error)]
115pub enum Error {
116    #[error(transparent)]
117    SocketIo(#[from] IoError),
118
119    #[error("Failed to parse network address")]
120    AddressParse,
121
122    #[error("Failed to resolve network address {}", .0.as_ref().map_or("".to_string(), |e| e.to_string()))]
123    AddressResolve(Option<io::Error>),
124
125    #[error("Authentication failure")]
126    Auth,
127
128    #[error("Bad protocol")]
129    BadProtocol,
130
131    #[error("Bad socket address")]
132    BadAddr,
133
134    #[error("Decoder error: reason={0}")]
135    Decoder(String),
136
137    #[error("Expired message")]
138    Expired,
139
140    #[error("Peer disconnected: {0}")]
141    Disconnect(DisconnectReason),
142
143    #[error("Invalid node id")]
144    InvalidNodeId,
145
146    #[error("Packet is too large")]
147    OversizedPacket,
148
149    #[error("Unexpected IO error: {0}")]
150    Io(io::Error),
151
152    #[error("Received message is deprecated. Protocol {protocol:?}, message id {msg_id}, \
153                min_supported_version {min_supported_version}")]
154    MessageDeprecated {
155        protocol: ProtocolId,
156        msg_id: u16,
157        min_supported_version: ProtocolVersion,
158    },
159
160    #[error("We are trying to send unsupported message to peer. Protocol {protocol:?},\
161                message id {msg_id}, peer_protocol_version {peer_protocol_version:?}, min_supported_version {min_supported_version:?}")]
162    SendUnsupportedMessage {
163        protocol: ProtocolId,
164        msg_id: u16,
165        peer_protocol_version: Option<ProtocolVersion>,
166        min_supported_version: Option<ProtocolVersion>,
167    },
168
169    #[error("throttling failure: {0}")]
170    Throttling(ThrottlingReason),
171
172    #[error("{0}")]
173    Msg(String),
174}
175
176impl From<io::Error> for Error {
177    fn from(err: io::Error) -> Self { Error::Io(err) }
178}
179
180impl From<rlp::DecoderError> for Error {
181    fn from(err: rlp::DecoderError) -> Self {
182        Error::Decoder(format!("{}", err)).into()
183    }
184}
185
186impl From<crate::keylib::Error> for Error {
187    fn from(_err: crate::keylib::Error) -> Self { Error::Auth.into() }
188}
189
190impl From<cfx_crypto::crypto::Error> for Error {
191    fn from(_err: cfx_crypto::crypto::Error) -> Self { Error::Auth.into() }
192}
193
194impl From<net::AddrParseError> for Error {
195    fn from(_err: net::AddrParseError) -> Self { Error::BadAddr.into() }
196}
197
198impl From<&str> for Error {
199    fn from(error: &str) -> Self { Error::Msg(error.to_string()) }
200}
201
202#[cfg(test)]
203mod tests {
204    use super::DisconnectReason::{self, *};
205    use rlp::{decode, encode};
206
207    fn check_rlp(r: DisconnectReason) {
208        assert_eq!(decode::<DisconnectReason>(&encode(&r)).unwrap(), r);
209    }
210
211    #[test]
212    fn test_disconnect_reason_rlp() {
213        check_rlp(DisconnectRequested);
214        check_rlp(UselessPeer);
215        check_rlp(WrongEndpointInfo);
216        check_rlp(IpLimited);
217        check_rlp(UpdateNodeIdFailed);
218        check_rlp(Unknown);
219
220        check_rlp(Custom("".to_owned()));
221        check_rlp(Custom("test test test".to_owned()));
222    }
223}