Skip to main content

rmqtt_codec/
error.rs

1//! Error types for MQTT protocol encoding and decoding operations
2//!
3//! This module defines the error hierarchy used throughout the codec crate:
4//! - `HandshakeError`: Errors during the initial MQTT connection handshake
5//! - `ProtocolError`: Higher-level protocol errors (decode, encode, timeout)
6//! - `DecodeError`: Specific errors that occur when parsing MQTT packets from bytes
7//! - `EncodeError`: Specific errors that occur when serializing MQTT packets to bytes
8//! - `SendPacketError`: Errors that occur when preparing a packet for transmission
9
10use std::io;
11
12use bytestring::ByteString;
13use serde::{Deserialize, Serialize};
14
15use crate::v5::{DisconnectReasonCode, ToReasonCode};
16
17/// Errors which can occur during mqtt connection handshake.
18#[derive(Deserialize, Serialize, Debug, Clone, thiserror::Error)]
19pub enum HandshakeError {
20    /// Protocol error
21    #[error("Mqtt protocol error: {}", _0)]
22    Protocol(#[from] ProtocolError),
23    /// Handshake timeout
24    #[error("Handshake timeout")]
25    Timeout,
26}
27
28impl ToReasonCode for HandshakeError {
29    fn to_reason_code(&self) -> DisconnectReasonCode {
30        match self {
31            HandshakeError::Protocol(err) => err.to_reason_code(),
32            HandshakeError::Timeout => DisconnectReasonCode::MaximumConnectTime,
33            // HandshakeError::Disconnected(_) => DisconnectReasonCode::ServerBusy,
34        }
35    }
36}
37
38/// Protocol level errors
39#[derive(Deserialize, Serialize, Debug, Clone, thiserror::Error)]
40pub enum ProtocolError {
41    /// MQTT decoding error
42    #[error("Decoding error: {0:?}")]
43    Decode(#[from] DecodeError),
44    /// MQTT encoding error
45    #[error("Encoding error: {0:?}")]
46    Encode(#[from] EncodeError),
47    /// Keep alive timeout
48    #[error("Keep Alive timeout")]
49    KeepAliveTimeout,
50}
51
52impl ToReasonCode for ProtocolError {
53    fn to_reason_code(&self) -> DisconnectReasonCode {
54        match self {
55            ProtocolError::Decode(err) => err.to_reason_code(),
56            ProtocolError::Encode(err) => err.to_reason_code(),
57            ProtocolError::KeepAliveTimeout => DisconnectReasonCode::KeepAliveTimeout,
58        }
59    }
60}
61
62/// Errors that occur when decoding/parsing MQTT packets from a byte stream
63#[derive(Debug, Clone, thiserror::Error, Deserialize, Serialize)]
64pub enum DecodeError {
65    #[error("Invalid protocol")]
66    InvalidProtocol,
67    #[error("Invalid length")]
68    InvalidLength,
69    #[error("Malformed packet")]
70    MalformedPacket,
71    #[error("Unsupported protocol level")]
72    UnsupportedProtocolLevel,
73    #[error("Connect frame's reserved flag is set")]
74    ConnectReservedFlagSet,
75    #[error("ConnectAck frame's reserved flag is set")]
76    ConnAckReservedFlagSet,
77    #[error("Invalid client id")]
78    InvalidClientId,
79    #[error("Unsupported packet type")]
80    UnsupportedPacketType,
81    // MQTT v3 only
82    #[error("Packet id is required")]
83    PacketIdRequired,
84    #[error("Max size exceeded: size={size}, max={max}")]
85    MaxSizeExceeded { size: u32, max: u32 },
86    #[error("utf8 error")]
87    Utf8Error,
88    #[error("io error, {:?}", _0)]
89    Io(ByteString),
90}
91
92impl From<io::Error> for DecodeError {
93    fn from(e: io::Error) -> DecodeError {
94        DecodeError::Io(e.to_string().into())
95    }
96}
97
98impl ToReasonCode for DecodeError {
99    fn to_reason_code(&self) -> DisconnectReasonCode {
100        match self {
101            DecodeError::InvalidProtocol => DisconnectReasonCode::ProtocolError,
102            DecodeError::InvalidLength => DisconnectReasonCode::MalformedPacket,
103            DecodeError::MalformedPacket => DisconnectReasonCode::MalformedPacket,
104            DecodeError::UnsupportedProtocolLevel => DisconnectReasonCode::ImplementationSpecificError,
105            DecodeError::ConnectReservedFlagSet => DisconnectReasonCode::ProtocolError,
106            DecodeError::ConnAckReservedFlagSet => DisconnectReasonCode::ProtocolError,
107            DecodeError::InvalidClientId => DisconnectReasonCode::NotAuthorized,
108            DecodeError::UnsupportedPacketType => DisconnectReasonCode::ImplementationSpecificError,
109            DecodeError::PacketIdRequired => DisconnectReasonCode::ProtocolError,
110            DecodeError::MaxSizeExceeded { .. } => DisconnectReasonCode::PacketTooLarge,
111            DecodeError::Utf8Error => DisconnectReasonCode::PayloadFormatInvalid,
112            DecodeError::Io(_) => DisconnectReasonCode::UnspecifiedError,
113        }
114    }
115}
116
117/// Errors that occur when encoding/serializing MQTT packets to a byte stream
118#[derive(Deserialize, Serialize, Debug, Clone, thiserror::Error)]
119pub enum EncodeError {
120    #[error("Packet is bigger than peer's Maximum Packet Size: size={size}, max={max}")]
121    OverMaxPacketSize { size: u32, max: u32 },
122    #[error("Invalid length")]
123    InvalidLength,
124    #[error("Malformed packet")]
125    MalformedPacket,
126    #[error("Packet id is required")]
127    PacketIdRequired,
128    #[error("Unsupported version")]
129    UnsupportedVersion,
130    #[error("io error, {:?}", _0)]
131    Io(ByteString),
132}
133
134impl From<io::Error> for EncodeError {
135    fn from(e: io::Error) -> EncodeError {
136        EncodeError::Io(e.to_string().into())
137    }
138}
139
140impl ToReasonCode for EncodeError {
141    fn to_reason_code(&self) -> DisconnectReasonCode {
142        match self {
143            EncodeError::OverMaxPacketSize { .. } => DisconnectReasonCode::PacketTooLarge,
144            EncodeError::InvalidLength => DisconnectReasonCode::MalformedPacket,
145            EncodeError::MalformedPacket => DisconnectReasonCode::MalformedPacket,
146            EncodeError::PacketIdRequired => DisconnectReasonCode::ProtocolError,
147            EncodeError::UnsupportedVersion => DisconnectReasonCode::ImplementationSpecificError,
148            EncodeError::Io(_) => DisconnectReasonCode::UnspecifiedError,
149        }
150    }
151}
152
153/// Errors that occur when sending MQTT packets
154///
155/// Wraps encoding errors that happen during packet transmission
156#[derive(Deserialize, Serialize, Debug, Clone, thiserror::Error)]
157pub enum SendPacketError {
158    /// Encoder error
159    #[error("Encoding error {:?}", _0)]
160    Encode(#[from] EncodeError),
161    // /// Provided packet id is in use
162    // #[error("Provided packet id is in use")]
163    // PacketIdInUse(NonZeroU16),
164
165    // /// Peer disconnected
166    // #[error("Peer is disconnected")]
167    // Disconnected,
168}
169
170impl ToReasonCode for SendPacketError {
171    fn to_reason_code(&self) -> DisconnectReasonCode {
172        match self {
173            SendPacketError::Encode(e) => e.to_reason_code(),
174        }
175    }
176}