1#[cfg(feature = "tls-native")]
2use native_tls::Error as TlsError;
3use sasl::client::MechanismError as SaslMechanismError;
4use std::borrow::Cow;
5use std::error::Error as StdError;
6use std::fmt;
7use std::io::Error as IoError;
8use std::str::Utf8Error;
9#[cfg(feature = "tls-rust")]
10use tokio_rustls::rustls::client::InvalidDnsNameError;
11#[cfg(feature = "tls-rust")]
12use tokio_rustls::rustls::Error as TlsError;
13use trust_dns_proto::error::ProtoError;
14use trust_dns_resolver::error::ResolveError;
15
16use xmpp_parsers::sasl::DefinedCondition as SaslDefinedCondition;
17use xmpp_parsers::{Error as ParsersError, JidParseError};
18
19/// Top-level error type
20#[derive(Debug)]
21pub enum Error {
22 /// I/O error
23 Io(IoError),
24 /// Error resolving DNS and establishing a connection
25 Connection(ConnecterError),
26 /// DNS label conversion error, no details available from module
27 /// `idna`
28 Idna,
29 /// Error parsing Jabber-Id
30 JidParse(JidParseError),
31 /// Protocol-level error
32 Protocol(ProtocolError),
33 /// Authentication error
34 Auth(AuthError),
35 /// TLS error
36 Tls(TlsError),
37 #[cfg(feature = "tls-rust")]
38 /// DNS name parsing error
39 DnsNameError(InvalidDnsNameError),
40 /// Connection closed
41 Disconnected,
42 /// Shoud never happen
43 InvalidState,
44}
45
46impl fmt::Display for Error {
47 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
48 match self {
49 Error::Io(e) => write!(fmt, "IO error: {}", e),
50 Error::Connection(e) => write!(fmt, "connection error: {}", e),
51 Error::Idna => write!(fmt, "IDNA error"),
52 Error::JidParse(e) => write!(fmt, "jid parse error: {}", e),
53 Error::Protocol(e) => write!(fmt, "protocol error: {}", e),
54 Error::Auth(e) => write!(fmt, "authentication error: {}", e),
55 Error::Tls(e) => write!(fmt, "TLS error: {}", e),
56 #[cfg(feature = "tls-rust")]
57 Error::DnsNameError(e) => write!(fmt, "DNS name error: {}", e),
58 Error::Disconnected => write!(fmt, "disconnected"),
59 Error::InvalidState => write!(fmt, "invalid state"),
60 }
61 }
62}
63
64impl From<IoError> for Error {
65 fn from(e: IoError) -> Self {
66 Error::Io(e)
67 }
68}
69
70impl From<ConnecterError> for Error {
71 fn from(e: ConnecterError) -> Self {
72 Error::Connection(e)
73 }
74}
75
76impl From<JidParseError> for Error {
77 fn from(e: JidParseError) -> Self {
78 Error::JidParse(e)
79 }
80}
81
82impl From<ProtocolError> for Error {
83 fn from(e: ProtocolError) -> Self {
84 Error::Protocol(e)
85 }
86}
87
88impl From<AuthError> for Error {
89 fn from(e: AuthError) -> Self {
90 Error::Auth(e)
91 }
92}
93
94impl From<TlsError> for Error {
95 fn from(e: TlsError) -> Self {
96 Error::Tls(e)
97 }
98}
99
100#[cfg(feature = "tls-rust")]
101impl From<InvalidDnsNameError> for Error {
102 fn from(e: InvalidDnsNameError) -> Self {
103 Error::DnsNameError(e)
104 }
105}
106
107/// Causes for stream parsing errors
108#[derive(Debug)]
109pub enum ParserError {
110 /// Encoding error
111 Utf8(Utf8Error),
112 /// XML parse error
113 Parse(ParseError),
114 /// Illegal `</>`
115 ShortTag,
116 /// Required by `impl Decoder`
117 Io(IoError),
118}
119
120impl fmt::Display for ParserError {
121 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
122 match self {
123 ParserError::Utf8(e) => write!(fmt, "UTF-8 error: {}", e),
124 ParserError::Parse(e) => write!(fmt, "parse error: {}", e),
125 ParserError::ShortTag => write!(fmt, "short tag"),
126 ParserError::Io(e) => write!(fmt, "IO error: {}", e),
127 }
128 }
129}
130
131impl From<IoError> for ParserError {
132 fn from(e: IoError) -> Self {
133 ParserError::Io(e)
134 }
135}
136
137impl From<ParserError> for Error {
138 fn from(e: ParserError) -> Self {
139 ProtocolError::Parser(e).into()
140 }
141}
142
143/// XML parse error wrapper type
144#[derive(Debug)]
145pub struct ParseError(pub Cow<'static, str>);
146
147impl StdError for ParseError {
148 fn description(&self) -> &str {
149 self.0.as_ref()
150 }
151 fn cause(&self) -> Option<&dyn StdError> {
152 None
153 }
154}
155
156impl fmt::Display for ParseError {
157 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
158 write!(f, "{}", self.0)
159 }
160}
161
162/// XMPP protocol-level error
163#[derive(Debug)]
164pub enum ProtocolError {
165 /// XML parser error
166 Parser(ParserError),
167 /// Error with expected stanza schema
168 Parsers(ParsersError),
169 /// No TLS available
170 NoTls,
171 /// Invalid response to resource binding
172 InvalidBindResponse,
173 /// No xmlns attribute in <stream:stream>
174 NoStreamNamespace,
175 /// No id attribute in <stream:stream>
176 NoStreamId,
177 /// Encountered an unexpected XML token
178 InvalidToken,
179 /// Unexpected <stream:stream> (shouldn't occur)
180 InvalidStreamStart,
181}
182
183impl fmt::Display for ProtocolError {
184 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
185 match self {
186 ProtocolError::Parser(e) => write!(fmt, "XML parser error: {}", e),
187 ProtocolError::Parsers(e) => write!(fmt, "error with expected stanza schema: {}", e),
188 ProtocolError::NoTls => write!(fmt, "no TLS available"),
189 ProtocolError::InvalidBindResponse => {
190 write!(fmt, "invalid response to resource binding")
191 }
192 ProtocolError::NoStreamNamespace => {
193 write!(fmt, "no xmlns attribute in <stream:stream>")
194 }
195 ProtocolError::NoStreamId => write!(fmt, "no id attribute in <stream:stream>"),
196 ProtocolError::InvalidToken => write!(fmt, "encountered an unexpected XML token"),
197 ProtocolError::InvalidStreamStart => write!(fmt, "unexpected <stream:stream>"),
198 }
199 }
200}
201
202impl From<ParserError> for ProtocolError {
203 fn from(e: ParserError) -> Self {
204 ProtocolError::Parser(e)
205 }
206}
207
208impl From<ParsersError> for ProtocolError {
209 fn from(e: ParsersError) -> Self {
210 ProtocolError::Parsers(e)
211 }
212}
213
214/// Authentication error
215#[derive(Debug)]
216pub enum AuthError {
217 /// No matching SASL mechanism available
218 NoMechanism,
219 /// Local SASL implementation error
220 Sasl(SaslMechanismError),
221 /// Failure from server
222 Fail(SaslDefinedCondition),
223 /// Component authentication failure
224 ComponentFail,
225}
226
227impl fmt::Display for AuthError {
228 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
229 match self {
230 AuthError::NoMechanism => write!(fmt, "no matching SASL mechanism available"),
231 AuthError::Sasl(s) => write!(fmt, "local SASL implementation error: {}", s),
232 AuthError::Fail(c) => write!(fmt, "failure from the server: {:?}", c),
233 AuthError::ComponentFail => write!(fmt, "component authentication failure"),
234 }
235 }
236}
237
238/// Error establishing connection
239#[derive(Debug)]
240pub enum ConnecterError {
241 /// All attempts failed, no error available
242 AllFailed,
243 /// DNS protocol error
244 Dns(ProtoError),
245 /// DNS resolution error
246 Resolve(ResolveError),
247}
248
249impl std::error::Error for ConnecterError {}
250
251impl std::fmt::Display for ConnecterError {
252 fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
253 write!(fmt, "{:?}", self)
254 }
255}