tokio_xmpp/
error.rs

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