1use super::{decoder::*, encoder::*, *};
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9pub enum Protocol {
10 MQTT311,
15 MQIsdp,
18}
19impl Protocol {
20 pub(crate) fn new(name: &str, level: u8) -> Result<Protocol, Error> {
21 match (name, level) {
22 ("MQIsdp", 3) => Ok(Protocol::MQIsdp),
23 ("MQTT", 4) => Ok(Protocol::MQTT311),
24 _ => Err(Error::InvalidProtocol(name.into(), level)),
25 }
26 }
27 pub(crate) fn from_buffer(buf: &[u8], offset: &mut usize) -> Result<Self, Error> {
28 let protocol_name = read_str(buf, offset)?;
29 let protocol_level = buf[*offset];
30 *offset += 1;
31
32 Protocol::new(protocol_name, protocol_level)
33 }
34 pub(crate) fn to_buffer(&self, buf: &mut [u8], offset: &mut usize) -> Result<usize, Error> {
35 match self {
36 Protocol::MQTT311 => {
37 let slice = &[0u8, 4, b'M', b'Q', b'T', b'T', 4];
38 for &byte in slice {
39 write_u8(buf, offset, byte)?;
40 }
41 Ok(slice.len())
42 }
43 Protocol::MQIsdp => {
44 let slice = &[0u8, 4, b'M', b'Q', b'i', b's', b'd', b'p', 4];
45 for &byte in slice {
46 write_u8(buf, offset, byte)?;
47 }
48 Ok(slice.len())
49 }
50 }
51 }
52}
53
54#[derive(Debug, Clone, PartialEq)]
61pub struct LastWill<'a> {
62 pub topic: &'a str,
63 pub message: &'a [u8],
64 pub qos: QoS,
65 pub retain: bool,
66}
67
68#[derive(Debug, Clone, Copy, PartialEq)]
75#[cfg_attr(feature = "defmt-impl", derive(defmt::Format))]
76pub enum ConnectReturnCode {
77 Accepted,
78 RefusedProtocolVersion,
79 RefusedIdentifierRejected,
80 ServerUnavailable,
81 BadUsernamePassword,
82 NotAuthorized,
83}
84impl ConnectReturnCode {
85 fn as_u8(&self) -> u8 {
86 match *self {
87 ConnectReturnCode::Accepted => 0,
88 ConnectReturnCode::RefusedProtocolVersion => 1,
89 ConnectReturnCode::RefusedIdentifierRejected => 2,
90 ConnectReturnCode::ServerUnavailable => 3,
91 ConnectReturnCode::BadUsernamePassword => 4,
92 ConnectReturnCode::NotAuthorized => 5,
93 }
94 }
95 pub(crate) fn from_u8(byte: u8) -> Result<ConnectReturnCode, Error> {
96 match byte {
97 0 => Ok(ConnectReturnCode::Accepted),
98 1 => Ok(ConnectReturnCode::RefusedProtocolVersion),
99 2 => Ok(ConnectReturnCode::RefusedIdentifierRejected),
100 3 => Ok(ConnectReturnCode::ServerUnavailable),
101 4 => Ok(ConnectReturnCode::BadUsernamePassword),
102 5 => Ok(ConnectReturnCode::NotAuthorized),
103 n => Err(Error::InvalidConnectReturnCode(n)),
104 }
105 }
106}
107
108#[derive(Debug, Clone, PartialEq)]
112pub struct Connect<'a> {
113 pub protocol: Protocol,
114 pub keep_alive: u16,
115 pub client_id: &'a str,
116 pub clean_session: bool,
117 pub last_will: Option<LastWill<'a>>,
118 pub username: Option<&'a str>,
119 pub password: Option<&'a [u8]>,
120}
121
122#[derive(Debug, Clone, Copy, PartialEq)]
126pub struct Connack {
127 pub session_present: bool,
128 pub code: ConnectReturnCode,
129}
130
131impl<'a> Connect<'a> {
132 pub(crate) fn from_buffer(buf: &'a [u8], offset: &mut usize) -> Result<Self, Error> {
133 let protocol = Protocol::from_buffer(buf, offset)?;
134
135 let connect_flags = buf[*offset];
136 let keep_alive = ((buf[*offset + 1] as u16) << 8) | buf[*offset + 2] as u16;
137 *offset += 3;
138
139 let client_id = read_str(buf, offset)?;
140
141 let last_will = if connect_flags & 0b100 != 0 {
142 let will_topic = read_str(buf, offset)?;
143 let will_message = read_bytes(buf, offset)?;
144 let will_qod = QoS::from_u8((connect_flags & 0b11000) >> 3)?;
145 Some(LastWill {
146 topic: will_topic,
147 message: will_message,
148 qos: will_qod,
149 retain: (connect_flags & 0b00100000) != 0,
150 })
151 } else {
152 None
153 };
154
155 let username = if connect_flags & 0b10000000 != 0 {
156 Some(read_str(buf, offset)?)
157 } else {
158 None
159 };
160
161 let password = if connect_flags & 0b01000000 != 0 {
162 Some(read_bytes(buf, offset)?)
163 } else {
164 None
165 };
166
167 let clean_session = (connect_flags & 0b10) != 0;
168
169 Ok(Connect {
170 protocol,
171 keep_alive,
172 client_id,
173 clean_session,
174 last_will,
175 username,
176 password,
177 })
178 }
179
180 pub(crate) fn len(&self) -> usize {
181 let mut length: usize = 6 + 1 + 1; length += 2 + self.client_id.len();
183 length += 2; if let Some(username) = self.username {
185 length += username.len();
186 length += 2;
187 };
188 if let Some(password) = self.password {
189 length += password.len();
190 length += 2;
191 };
192 if let Some(last_will) = &self.last_will {
193 length += last_will.message.len();
194 length += last_will.topic.len();
195 length += 4;
196 };
197 length
198 }
199
200 pub(crate) fn to_buffer(&self, buf: &mut [u8], offset: &mut usize) -> Result<usize, Error> {
201 let header: u8 = 0b00010000;
202 let mut connect_flags: u8 = 0b00000000;
203 if self.clean_session {
204 connect_flags |= 0b10;
205 };
206 if self.username.is_some() {
207 connect_flags |= 0b10000000;
208 };
209 if self.password.is_some() {
210 connect_flags |= 0b01000000;
211 };
212 if let Some(last_will) = &self.last_will {
213 connect_flags |= 0b00000100;
214 connect_flags |= last_will.qos.as_u8() << 3;
215 if last_will.retain {
216 connect_flags |= 0b00100000;
217 };
218 };
219 let length = self.len();
220 check_remaining(buf, offset, length + 1)?;
221
222 write_u8(buf, offset, header)?;
224
225 let write_len = write_length(buf, offset, length)? + 1;
226 self.protocol.to_buffer(buf, offset)?;
227
228 write_u8(buf, offset, connect_flags)?;
229 write_u16(buf, offset, self.keep_alive)?;
230
231 write_string(buf, offset, self.client_id)?;
232
233 if let Some(last_will) = &self.last_will {
234 write_string(buf, offset, last_will.topic)?;
235 write_bytes(buf, offset, &last_will.message)?;
236 };
237
238 if let Some(username) = self.username {
239 write_string(buf, offset, username)?;
240 };
241 if let Some(password) = self.password {
242 write_bytes(buf, offset, password)?;
243 };
244 Ok(write_len)
246 }
247}
248
249impl Connack {
250 pub(crate) fn from_buffer(buf: &[u8], offset: &mut usize) -> Result<Self, Error> {
251 let flags = buf[*offset];
252 let return_code = buf[*offset + 1];
253 *offset += 2;
254 Ok(Connack {
255 session_present: (flags & 0b1 == 1),
256 code: ConnectReturnCode::from_u8(return_code)?,
257 })
258 }
259 pub(crate) fn to_buffer(&self, buf: &mut [u8], offset: &mut usize) -> Result<usize, Error> {
260 check_remaining(buf, offset, 4)?;
261 let header: u8 = 0b00100000;
262 let length: u8 = 2;
263 let mut flags: u8 = 0b00000000;
264 if self.session_present {
265 flags |= 0b1;
266 };
267 let rc = self.code.as_u8();
268 write_u8(buf, offset, header)?;
269 write_u8(buf, offset, length)?;
270 write_u8(buf, offset, flags)?;
271 write_u8(buf, offset, rc)?;
272 Ok(4)
273 }
274}