tokio_xmpp/
error.rs

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