rmqtt_codec/
error.rs

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