error.rs

  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}