mountain_mqtt/
error.rs

1use core::{
2    fmt::{Display, Formatter},
3    str::Utf8Error,
4};
5
6/// An error occurring while attempting to read/receive/decode an MQTT packet
7/// Can occur at multiple levels:
8/// 1. Reading data from a [Connection] - e.g. an IO error occurs in underlying data stream
9/// 2. Reading data from a buffer - e.g. running out of data
10/// 3. Decoding byte data as expected types, e.g. encountering an invalid boolean encoding (value not 0 or 1)
11/// 4. Building a packet structure, e.g. there are too many properties or subscription request to fit in a fixed-length [heapless::Vec]
12/// 5. Validating that packet matches MQTT specification, e.g. "reserved" bits of first header byte are not set to correct values
13///
14/// This does NOT include any errors found to be encoded in the packet itself - as long as these
15/// errors are correctly decoded this doesn't represent a read error. Errors in the packet will
16/// be handled at higher layers.
17///
18/// Note that these errors mostly map to [ReasonCode::MalformedPacket] when they result in an error
19/// encoded in an MQTT packet, they are intended to provide a more granular description of the error
20/// to assist in debugging and error handling. Other errors would not ever be represented in a packet,
21/// since they represent errors like a failure to read from the network, etc.
22///
23/// Note that some errors map to a [ReasonCode] other than [ReasonCode::MalformedPacket], for example
24/// [PacketReadError::UnexpectedPropertyIdentifier] may map to [ReasonCode::ProtocolError] in the case
25/// where a reason string property is sent in a packet type that should not have such a property, see
26/// [MQTT-3.1.2-29] in the specification.
27#[derive(Copy, Clone, Debug, PartialEq)]
28pub enum PacketReadError {
29    /// No more data was available at a point where the MQTT specification states more data
30    /// must be present in the packet
31    InsufficientData,
32
33    /// Data contained bytes that could not be converted to a valid utf8 string
34    InvalidUtf8,
35
36    /// Data contained bytes that resulted in a utf8 string containing one or more null
37    /// characters, which are not permitted in MQTT strings
38    NullCharacterInString,
39
40    /// While decoding a variable byte integer, the data did not match possible encodings
41    /// (e.g. it contained more than 3 bytes with continuation bit set, indicating a total encoded
42    /// length greater than 4 bytes)
43    InvalidVariableByteIntegerEncoding,
44
45    /// Data was expected to be of a known packet type, but the first header byte did not match this
46    IncorrectPacketType,
47
48    /// Data contained an unknown reason code
49    UnknownReasonCode,
50
51    /// Data contained a u8 value that was expected to be 0 (false) or 1 (true), but was some other value
52    InvalidBooleanValue,
53
54    /// Data contained a list of properties longer than the `P` parameter of a packet,
55    /// and so overflowed a [heapless::Vec]
56    TooManyProperties,
57
58    /// Data contained an encoded [QualityOfService] value which was not a recognised value
59    /// (Malformed Packet)
60    InvalidQosValue,
61
62    /// A Connect packet was decoded which did not contain the expected protocol name (MQTT) and version (5)
63    /// This can be returned to clients, but it is also acceptable to simply close the network connection,
64    /// see spec 3.1.2.1 and 3.1.2.2
65    UnsupportedProtocolVersion,
66
67    /// Data contained a list of subscription requests (or suback reason codes) longer than the `S`
68    /// parameter of a packet, and so overflowed a [heapless::Vec]
69    TooManyRequests,
70
71    /// Data meant to encode a packet type had an invalid value. E.g. first header byte could not be
72    /// decoded to a [PacketType], or contained invalid values for the "reserved" bits.
73    InvalidPacketType,
74
75    /// Failure to receive via connection
76    ConnectionReceive,
77
78    /// Packet was too large to place in provided buffer
79    PacketTooLargeForBuffer,
80
81    /// When decoding a property for a packet, encountered a value of the property identifier byte
82    /// that was not expected in the given context. This may be an id that is completely unknown, or
83    /// just one that is not expected for the type of packet being decoded.
84    UnexpectedPropertyIdentifier,
85
86    /// When decoding the "retain handling" subscription option, an invalid value not matching the
87    /// specification was encountered
88    InvalidRetainHandlingValue,
89
90    /// When decoding connect flags of Connect packet, an invalid value was encountered (Malformed Packet)
91    InvalidConnectFlags,
92
93    /// When decoding a packet, the "remaining length" in the packet header was incorrect -
94    /// the actual packet format indicates the packet is longer or shorter than header indicates
95    IncorrectPacketLength,
96
97    /// All Subscribe packets must have at least one subscription request [MQTT-3.8.3-2]
98    SubscribeWithoutValidSubscriptionRequest,
99
100    /// All Suback packets must have at least one reason code, since they are responding
101    /// to a [Subscription] with at least one subscription request [MQTT-3.8.3-2]
102    SubackWithoutValidReasonCode,
103
104    /// All Unsubscribe packets must have at least one subscription request [MQTT-3.10.3-2]
105    UnsubscribeWithoutValidSubscriptionRequest,
106
107    /// All Unsuback packets must have at least one reason code, since they are responding
108    /// to a [Unsubscribe] with at least one subscription request [MQTT-3.10.3-2]
109    UnsubackWithoutValidReasonCode,
110
111    // If a connect packet has no will specified, it must also have the will quality of service bits as 0 [MQTT-3.1.2-11]
112    WillQosSpecifiedWithoutWill,
113
114    // If a connect packet has no will specified, it must also have the will Retain bit as 0 [MQTT-3.1.2-13]
115    WillRetainSpecifiedWithoutWill,
116
117    // Subscription options u8 values must not have reserved bits set to non-zero [MQTT-3.8.3-5]
118    SubscriptionOptionsReservedBitsNonZero,
119}
120
121#[cfg(feature = "defmt")]
122impl defmt::Format for PacketReadError {
123    fn format(&self, f: defmt::Formatter) {
124        match self {
125            Self::InsufficientData => defmt::write!(f, "InsufficientData"),
126            Self::InvalidUtf8 => defmt::write!(f, "InvalidUtf8"),
127            Self::NullCharacterInString => defmt::write!(f, "NullCharacterInString"),
128            Self::InvalidVariableByteIntegerEncoding => {
129                defmt::write!(f, "InvalidVariableByteIntegerEncoding")
130            }
131            Self::IncorrectPacketType => defmt::write!(f, "IncorrectPacketType"),
132            Self::UnknownReasonCode => defmt::write!(f, "UnknownReasonCode"),
133            Self::InvalidBooleanValue => defmt::write!(f, "InvalidBooleanValue"),
134            Self::TooManyProperties => defmt::write!(f, "TooManyProperties"),
135            Self::InvalidQosValue => defmt::write!(f, "InvalidQosValue"),
136            Self::UnsupportedProtocolVersion => defmt::write!(f, "UnsupportedProtocolVersion"),
137            Self::TooManyRequests => defmt::write!(f, "TooManyRequests"),
138            Self::InvalidPacketType => defmt::write!(f, "InvalidPacketType"),
139            Self::ConnectionReceive => defmt::write!(f, "ConnectionReceive"),
140            Self::PacketTooLargeForBuffer => defmt::write!(f, "PacketTooLargeForBuffer"),
141            Self::UnexpectedPropertyIdentifier => defmt::write!(f, "UnexpectedPropertyIdentifier"),
142            Self::InvalidRetainHandlingValue => defmt::write!(f, "InvalidRetainHandlingValue"),
143            Self::InvalidConnectFlags => defmt::write!(f, "InvalidConnectFlags"),
144            Self::IncorrectPacketLength => defmt::write!(f, "IncorrectPacketLength"),
145            Self::SubscribeWithoutValidSubscriptionRequest => {
146                defmt::write!(f, "SubscribeWithoutValidSubscriptionRequest")
147            }
148            Self::SubackWithoutValidReasonCode => defmt::write!(f, "SubackWithoutValidReasonCode"),
149            Self::UnsubscribeWithoutValidSubscriptionRequest => {
150                defmt::write!(f, "UnsubscribeWithoutValidSubscriptionRequest")
151            }
152            Self::UnsubackWithoutValidReasonCode => {
153                defmt::write!(f, "UnsubackWithoutValidReasonCode")
154            }
155            Self::WillQosSpecifiedWithoutWill => defmt::write!(f, "WillQosSpecifiedWithoutWill"),
156            Self::WillRetainSpecifiedWithoutWill => {
157                defmt::write!(f, "WillRetainSpecifiedWithoutWill")
158            }
159            Self::SubscriptionOptionsReservedBitsNonZero => {
160                defmt::write!(f, "SubscriptionOptionsReservedBitsNonZero")
161            }
162        }
163    }
164}
165
166impl From<Utf8Error> for PacketReadError {
167    fn from(_e: Utf8Error) -> Self {
168        Self::InvalidUtf8
169    }
170}
171
172impl Display for PacketReadError {
173    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
174        match self {
175            Self::InsufficientData => write!(f, "InsufficientData"),
176            Self::InvalidUtf8 => write!(f, "InvalidUtf8"),
177            Self::NullCharacterInString => write!(f, "NullCharacterInString"),
178            Self::InvalidVariableByteIntegerEncoding => {
179                write!(f, "InvalidVariableByteIntegerEncoding")
180            }
181            Self::IncorrectPacketType => write!(f, "IncorrectPacketType"),
182            Self::UnknownReasonCode => write!(f, "UnknownReasonCode"),
183            Self::InvalidBooleanValue => write!(f, "InvalidBooleanValue"),
184            Self::TooManyProperties => write!(f, "TooManyProperties"),
185            Self::InvalidQosValue => write!(f, "InvalidQosValue"),
186            Self::UnsupportedProtocolVersion => write!(f, "UnsupportedProtocolVersion"),
187            Self::TooManyRequests => write!(f, "TooManyRequests"),
188            Self::InvalidPacketType => write!(f, "InvalidPacketType"),
189            Self::ConnectionReceive => write!(f, "ConnectionReceive"),
190            Self::PacketTooLargeForBuffer => write!(f, "PacketTooLargeForBuffer"),
191            Self::UnexpectedPropertyIdentifier => write!(f, "UnexpectedPropertyIdentifier"),
192            Self::InvalidRetainHandlingValue => write!(f, "InvalidRetainHandlingValue"),
193            Self::InvalidConnectFlags => write!(f, "InvalidConnectFlags"),
194            Self::IncorrectPacketLength => write!(f, "IncorrectPacketLength"),
195            Self::SubscribeWithoutValidSubscriptionRequest => {
196                write!(f, "SubscribeWithoutValidSubscriptionRequest")
197            }
198            Self::SubackWithoutValidReasonCode => write!(f, "SubackWithoutValidReasonCode"),
199            Self::UnsubscribeWithoutValidSubscriptionRequest => {
200                write!(f, "UnsubscribeWithoutValidSubscriptionRequest")
201            }
202            Self::UnsubackWithoutValidReasonCode => write!(f, "UnsubackWithoutValidReasonCode"),
203            Self::WillQosSpecifiedWithoutWill => write!(f, "WillQosSpecifiedWithoutWill"),
204            Self::WillRetainSpecifiedWithoutWill => write!(f, "WillRetainSpecifiedWithoutWill"),
205            Self::SubscriptionOptionsReservedBitsNonZero => {
206                write!(f, "ReservedBitsSetInSubscriptionOptions")
207            }
208        }
209    }
210}
211
212#[derive(Copy, Clone, Debug, PartialEq)]
213pub enum PacketWriteError {
214    /// On attempt to put data that will not fit in buffer
215    Overflow,
216
217    /// On attempt to put a string containing a null character (which is not valid in an MQTT message)
218    NullCharacterInString,
219
220    /// On attempt to put a u32 value as a variable byte integer, where the value is too large to encode
221    VariableByteIntegerTooLarge,
222
223    /// On attempt to put binary data with too many bytes to encode
224    DataTooLarge,
225
226    /// On attempt to put a string where the encoded form is too many bytes to encode
227    StringTooLarge,
228
229    /// Failure to send via connection
230    ConnectionSend,
231}
232
233#[cfg(feature = "defmt")]
234impl defmt::Format for PacketWriteError {
235    fn format(&self, f: defmt::Formatter) {
236        match self {
237            Self::Overflow => defmt::write!(f, "Overflow"),
238            Self::NullCharacterInString => defmt::write!(f, "NullCharacterInString"),
239            Self::VariableByteIntegerTooLarge => defmt::write!(f, "VariableByteIntegerTooLarge"),
240            Self::DataTooLarge => defmt::write!(f, "DataTooLarge"),
241            Self::StringTooLarge => defmt::write!(f, "StringTooLarge"),
242            Self::ConnectionSend => defmt::write!(f, "ConnectionSend"),
243        }
244    }
245}
246
247impl Display for PacketWriteError {
248    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
249        match self {
250            Self::Overflow => write!(f, "Overflow"),
251            Self::NullCharacterInString => write!(f, "NullCharacterInString"),
252            Self::VariableByteIntegerTooLarge => write!(f, "VariableByteIntegerTooLarge"),
253            Self::DataTooLarge => write!(f, "DataTooLarge"),
254            Self::StringTooLarge => write!(f, "StringTooLarge"),
255            Self::ConnectionSend => write!(f, "ConnectionSend"),
256        }
257    }
258}