1use 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}