mqtt/
packet.rs

1use proto::{Protocol, QoS};
2
3bitflags! {
4    pub struct ConnectFlags: u8 {
5        const USERNAME      = 0b10000000;
6        const PASSWORD      = 0b01000000;
7        const WILL_RETAIN   = 0b00100000;
8        const WILL_QOS      = 0b00011000;
9        const WILL          = 0b00000100;
10        const CLEAN_SESSION = 0b00000010;
11    }
12}
13
14pub const WILL_QOS_SHIFT: u8 = 3;
15
16bitflags! {
17    pub struct ConnectAckFlags: u8 {
18        const SESSION_PRESENT = 0b00000001;
19    }
20}
21
22#[repr(u8)]
23#[derive(Debug, Eq, PartialEq, Copy, Clone)]
24/// Connect Return Code
25pub enum ConnectReturnCode {
26    /// Connection accepted
27    ConnectionAccepted = 0,
28    /// Connection Refused, unacceptable protocol version
29    UnacceptableProtocolVersion = 1,
30    /// Connection Refused, identifier rejected
31    IdentifierRejected = 2,
32    /// Connection Refused, Server unavailable
33    ServiceUnavailable = 3,
34    /// Connection Refused, bad user name or password
35    BadUserNameOrPassword = 4,
36    /// Connection Refused, not authorized
37    NotAuthorized = 5,
38    /// Reserved
39    Reserved = 6,
40}
41
42const_enum!(ConnectReturnCode: u8);
43
44impl ConnectReturnCode {
45    pub fn reason(&self) -> &'static str {
46        match *self {
47            ConnectReturnCode::ConnectionAccepted => "Connection Accepted",
48            ConnectReturnCode::UnacceptableProtocolVersion => {
49                "Connection Refused, unacceptable protocol version"
50            }
51            ConnectReturnCode::IdentifierRejected => "Connection Refused, identifier rejected",
52            ConnectReturnCode::ServiceUnavailable => "Connection Refused, Server unavailable",
53            ConnectReturnCode::BadUserNameOrPassword => {
54                "Connection Refused, bad user name or password"
55            }
56            ConnectReturnCode::NotAuthorized => "Connection Refused, not authorized",
57            _ => "Connection Refused",
58        }
59    }
60}
61
62#[derive(Debug, PartialEq, Clone)]
63pub struct FixedHeader {
64    /// MQTT Control Packet type
65    pub packet_type: u8,
66    /// Flags specific to each MQTT Control Packet type
67    pub packet_flags: u8,
68    /// the number of bytes remaining within the current packet,
69    /// including data in the variable header and the payload.
70    pub remaining_length: usize,
71}
72
73#[derive(Debug, PartialEq, Clone)]
74/// Connection Will
75pub struct LastWill<'a> {
76    /// the QoS level to be used when publishing the Will Message.
77    pub qos: QoS,
78    /// the Will Message is to be Retained when it is published.
79    pub retain: bool,
80    /// the Will Topic
81    pub topic: &'a str,
82    /// defines the Application Message that is to be published to the Will Topic
83    pub message: &'a [u8],
84}
85
86#[derive(Debug, PartialEq, Copy, Clone)]
87/// Subscribe Return Code
88pub enum SubscribeReturnCode {
89    Success(QoS),
90    Failure,
91}
92
93#[derive(Debug, PartialEq, Clone)]
94/// MQTT Control Packets
95pub enum Packet<'a> {
96    /// Client request to connect to Server
97    Connect {
98        protocol: Protocol,
99        /// the handling of the Session state.
100        clean_session: bool,
101        /// a time interval measured in seconds.
102        keep_alive: u16,
103        /// Will Message be stored on the Server and associated with the Network Connection.
104        last_will: Option<LastWill<'a>>,
105        /// identifies the Client to the Server.
106        client_id: &'a str,
107        /// username can be used by the Server for authentication and authorization.
108        username: Option<&'a str>,
109        /// password can be used by the Server for authentication and authorization.
110        password: Option<&'a [u8]>,
111    },
112    /// Connect acknowledgment
113    ConnectAck {
114        /// enables a Client to establish whether the Client and Server have a consistent view
115        /// about whether there is already stored Session state.
116        session_present: bool,
117        return_code: ConnectReturnCode,
118    },
119    /// Publish message
120    Publish {
121        /// this might be re-delivery of an earlier attempt to send the Packet.
122        dup: bool,
123        retain: bool,
124        /// the level of assurance for delivery of an Application Message.
125        qos: QoS,
126        /// the information channel to which payload data is published.
127        topic: &'a str,
128        /// only present in PUBLISH Packets where the QoS level is 1 or 2.
129        packet_id: Option<u16>,
130        /// the Application Message that is being published.
131        payload: &'a [u8],
132    },
133    /// Publish acknowledgment
134    PublishAck {
135        /// Packet Identifier
136        packet_id: u16,
137    },
138    /// Publish received (assured delivery part 1)
139    PublishReceived {
140        /// Packet Identifier
141        packet_id: u16,
142    },
143    /// Publish release (assured delivery part 2)
144    PublishRelease {
145        /// Packet Identifier
146        packet_id: u16,
147    },
148    /// Publish complete (assured delivery part 3)
149    PublishComplete {
150        /// Packet Identifier
151        packet_id: u16,
152    },
153    /// Client subscribe request
154    Subscribe {
155        /// Packet Identifier
156        packet_id: u16,
157        /// the list of Topic Filters and QoS to which the Client wants to subscribe.
158        topic_filters: Vec<(&'a str, QoS)>,
159    },
160    /// Subscribe acknowledgment
161    SubscribeAck {
162        packet_id: u16,
163        /// corresponds to a Topic Filter in the SUBSCRIBE Packet being acknowledged.
164        status: Vec<SubscribeReturnCode>,
165    },
166    /// Unsubscribe request
167    Unsubscribe {
168        /// Packet Identifier
169        packet_id: u16,
170        /// the list of Topic Filters that the Client wishes to unsubscribe from.
171        topic_filters: Vec<&'a str>,
172    },
173    /// Unsubscribe acknowledgment
174    UnsubscribeAck {
175        /// Packet Identifier
176        packet_id: u16,
177    },
178    /// PING request
179    PingRequest,
180    /// PING response
181    PingResponse,
182    /// Client is disconnecting
183    Disconnect,
184}
185
186impl<'a> Packet<'a> {
187    #[inline]
188    /// MQTT Control Packet type
189    pub fn packet_type(&self) -> u8 {
190        match *self {
191            Packet::Connect { .. } => CONNECT,
192            Packet::ConnectAck { .. } => CONNACK,
193            Packet::Publish { .. } => PUBLISH,
194            Packet::PublishAck { .. } => PUBACK,
195            Packet::PublishReceived { .. } => PUBREC,
196            Packet::PublishRelease { .. } => PUBREL,
197            Packet::PublishComplete { .. } => PUBCOMP,
198            Packet::Subscribe { .. } => SUBSCRIBE,
199            Packet::SubscribeAck { .. } => SUBACK,
200            Packet::Unsubscribe { .. } => UNSUBSCRIBE,
201            Packet::UnsubscribeAck { .. } => UNSUBACK,
202            Packet::PingRequest => PINGREQ,
203            Packet::PingResponse => PINGRESP,
204            Packet::Disconnect => DISCONNECT,
205        }
206    }
207
208    /// Flags specific to each MQTT Control Packet type
209    pub fn packet_flags(&self) -> u8 {
210        match *self {
211            Packet::Publish { dup, qos, retain, .. } => {
212                let mut b = qos.into();
213
214                b <<= 1;
215
216                if dup {
217                    b |= 0b1000;
218                }
219
220                if retain {
221                    b |= 0b0001;
222                }
223
224                b
225            }
226            Packet::PublishRelease { .. } |
227            Packet::Subscribe { .. } |
228            Packet::Unsubscribe { .. } => 0b0010,
229            _ => 0,
230        }
231    }
232}
233
234pub const CONNECT: u8 = 1;
235pub const CONNACK: u8 = 2;
236pub const PUBLISH: u8 = 3;
237pub const PUBACK: u8 = 4;
238pub const PUBREC: u8 = 5;
239pub const PUBREL: u8 = 6;
240pub const PUBCOMP: u8 = 7;
241pub const SUBSCRIBE: u8 = 8;
242pub const SUBACK: u8 = 9;
243pub const UNSUBSCRIBE: u8 = 10;
244pub const UNSUBACK: u8 = 11;
245pub const PINGREQ: u8 = 12;
246pub const PINGRESP: u8 = 13;
247pub const DISCONNECT: u8 = 14;