Skip to main content

rust_mqtt/client/
err.rs

1use crate::{
2    client::raw::RawError,
3    eio::ErrorKind,
4    header::Reserved,
5    types::{MqttString, ReasonCode, TooLargeToEncode},
6};
7
8/// The main error returned by [`crate::client::Client`].
9///
10/// Distincts between unrecoverable and recoverable errors.
11/// Recoverability in this context refers to whether the current network connection can
12/// be used for further communication after the error has occured.
13///
14/// # Recovery
15/// - For unrecoverable errors, [`crate::client::Client::abort`] can be called to send an optional DISCONNECT
16///   packet if allowed by specification. You can then try to recover the session by calling
17///   [`crate::client::Client::connect`] again without clean start.
18/// - For recoverable errors, follow the error-specific behaviour.
19#[derive(Debug, Clone, PartialEq, Eq)]
20#[cfg_attr(feature = "defmt", derive(defmt::Format))]
21pub enum Error<'e> {
22    /// An underlying Read/Write method returned an error.
23    ///
24    /// Unrecoverable error. [`crate::client::Client::abort`] should be called.
25    Network(ErrorKind),
26
27    /// The remote server did something the client does not understand / does not match the specification.
28    ///
29    /// Unrecoverable error. [`crate::client::Client::abort`] should be called.
30    Server,
31
32    /// A buffer provision by the [`crate::buffer::BufferProvider`] failed. Therefore a packet
33    /// could not be received correctly.
34    ///
35    /// Unrecoverable error. [`crate::client::Client::abort`] should be called.
36    Alloc,
37
38    /// An AUTH packet header has been received by the client. AUTH packets are not supported by the client.
39    /// The client has scheduled a DISCONNECT packet with [`ReasonCode::ImplementationSpecificError`].
40    /// The packet body has not been decoded.
41    ///
42    /// Unrecoverable error. [`crate::client::Client::abort`] should be called.
43    AuthPacketReceived,
44
45    /// The client could not connect to the broker or the broker has sent a DISCONNECT packet.
46    ///
47    /// Unrecoverable error. [`crate::client::Client::abort`] should be called.
48    Disconnect {
49        /// The [`ReasonCode`] of the causing CONNACK or DISCONNECT packet. If the disconnection is caused
50        /// by a CONNACK packet, the reason code ss always erroneous.
51        reason: ReasonCode,
52
53        /// The reason string property of the causing CONNACK or DISCONNECT packet if the server included
54        /// a reason string.
55        reason_string: Option<MqttString<'e>>,
56
57        /// The server reference property of the causing CONNACK or DISCONNCET packet if the server included
58        /// a server reference. Identifies another server which can be used.
59        server_reference: Option<MqttString<'e>>,
60    },
61
62    /// Another unrecoverable error has been returned earlier. The underlying connection is in a state,
63    /// in which it refuses/is not able to perform regular communication.
64    ///
65    /// Unrecoverable error. [`crate::client::Client::abort`] should be called.
66    RecoveryRequired,
67
68    /// A republish of a packet without an in flight entry was attempted.
69    ///
70    /// Recoverable error. No action has been taken by the client.
71    PacketIdentifierNotInFlight,
72
73    /// A republish of a packet with a quality of service that does not match the quality of
74    /// service of the original publication was attempted.
75    ///
76    /// Recoverable error. No action has been taken by the client.
77    RepublishQoSNotMatching,
78
79    /// A republish of a packet whose corresponding PUBREL packet has already been sent was attempted.
80    /// Sending the PUBLISH packet in this case would result in a protocol violation.
81    ///
82    /// Recoverable error. No action has been taken by the client.
83    PacketIdentifierAwaitingPubcomp,
84
85    /// A packet was too long to encode its length with the variable byte integer.
86    ///
87    /// This can currently only be returned from [`crate::client::Client::publish`] or
88    /// [`crate::client::Client::republish`].
89    ///
90    /// Recoverable error. No action has been taken by the client.
91    PacketMaximumLengthExceeded,
92
93    /// A packet is too long and would exceed the servers maximum packet size.
94    ///
95    /// Recoverable error. No action has been taken by the client.
96    ServerMaximumPacketSizeExceeded,
97
98    /// The value of a topic alias in an outgoing PUBLISH packet was 0 or greater than the server's maximum allowed
99    /// value. Sending this PUBLISH packet would raise a protocol error.
100    ///
101    /// Recoverable error. No action has been taken by the client.
102    InvalidTopicAlias,
103
104    /// An action was rejected because an internal buffer used for tracking session state is full.
105    ///
106    /// Recoverable error. Try again after a [`crate::client::event::Event`] has been emitted that indicates
107    /// that buffer might be free again.
108    ///
109    /// Example:
110    ///     [`crate::client::Client::subscribe`] returns this error. Wait until a
111    ///     [`crate::client::event::Event::Suback`] is received.
112    ///     This clears a spot in the subscribe packet identifiers.
113    SessionBuffer,
114
115    /// A publish now would exceed the server's receive maximum and ultimately cause a protocol error.
116    ///
117    /// Recoverable error. Try again after either [`crate::client::event::Event::PublishAcknowledged`] or
118    /// [`crate::client::event::Event::PublishComplete`] has been emitted that indicates that buffer might be
119    /// free again.
120    /// been emitted that indicates that buffer might be free again.
121    SendQuotaExceeded,
122
123    /// A disconnect now with the given session expiry interval would cause a protocol error.
124    ///
125    /// A disconnection was attempted with a session expiry interval change where the session expiry interval in the
126    /// CONNECT packet was zero ([`crate::config::SessionExpiryInterval::EndOnDisconnect`]) and was
127    /// greater than zero ([`crate::config::SessionExpiryInterval::NeverEnd`] or
128    /// [`crate::config::SessionExpiryInterval::Seconds`]) in the DISCONNECT packet.
129    ///
130    /// Recoverable error. Try disconnecting again without an session expiry interval or with a
131    /// session expiry interval of zero ([`crate::config::SessionExpiryInterval::EndOnDisconnect`]).
132    IllegalDisconnectSessionExpiryInterval,
133}
134
135impl Error<'_> {
136    /// Returns whether the client can recover from this error without closing the network connection.
137    #[must_use]
138    pub fn is_recoverable(&self) -> bool {
139        matches!(
140            self,
141            Self::PacketIdentifierNotInFlight
142                | Self::RepublishQoSNotMatching
143                | Self::PacketIdentifierAwaitingPubcomp
144                | Self::PacketMaximumLengthExceeded
145                | Self::ServerMaximumPacketSizeExceeded
146                | Self::InvalidTopicAlias
147                | Self::SessionBuffer
148                | Self::SendQuotaExceeded
149                | Self::IllegalDisconnectSessionExpiryInterval
150        )
151    }
152}
153
154impl From<Reserved> for Error<'_> {
155    fn from(_: Reserved) -> Self {
156        Self::Server
157    }
158}
159
160impl<B> From<RawError<B>> for Error<'_> {
161    fn from(e: RawError<B>) -> Self {
162        match e {
163            RawError::Disconnected => Self::RecoveryRequired,
164            RawError::Network(e) => Self::Network(e),
165            RawError::Alloc(_) => Self::Alloc,
166            RawError::Server => Self::Server,
167        }
168    }
169}
170
171impl From<TooLargeToEncode> for Error<'_> {
172    fn from(_: TooLargeToEncode) -> Self {
173        Self::PacketMaximumLengthExceeded
174    }
175}