Rust MQTT

This commit is contained in:
Ondrej Babec
2022-03-12 15:56:37 +01:00
parent c8ee05821a
commit d993457add
77 changed files with 1010 additions and 1661 deletions

View File

@@ -0,0 +1,121 @@
/*
* MIT License
*
* Copyright (c) [2022] [Ondrej Babec <ond.babec@gmail.com>]
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
use heapless::Vec;
use crate::encoding::variable_byte_integer::VariableByteIntegerEncoder;
use crate::packet::v5::mqtt_packet::Packet;
use crate::utils::buffer_reader::BuffReader;
use crate::utils::buffer_writer::BuffWriter;
use crate::utils::types::BufferError;
use super::packet_type::PacketType;
use super::property::Property;
/// Auth packets serves MQTTv5 extended authentication. This packet is not currently supported
/// by rust-mqtt client but decoding and encoding of packet is prepared for future development.
pub struct AuthPacket<'a, const MAX_PROPERTIES: usize> {
pub fixed_header: u8,
pub remain_len: u32,
pub auth_reason: u8,
pub property_len: u32,
pub properties: Vec<Property<'a>, MAX_PROPERTIES>,
}
impl<'a, const MAX_PROPERTIES: usize> AuthPacket<'a, MAX_PROPERTIES> {
pub fn add_reason_code(&mut self, code: u8) {
if code != 0 && code != 24 && code != 25 {
log::error!("Provided reason code is not supported!");
return;
}
self.auth_reason = code;
}
pub fn add_property(&mut self, p: Property<'a>) {
if p.auth_property() {
self.push_to_properties(p);
} else {
log::error!("Provided property is not correct AUTH packet property!");
}
}
}
impl<'a, const MAX_PROPERTIES: usize> Packet<'a> for AuthPacket<'a, MAX_PROPERTIES> {
fn new() -> Self {
Self {
fixed_header: PacketType::Auth.into(),
remain_len: 0,
auth_reason: 0x00,
property_len: 0,
properties: Vec::<Property<'a>, MAX_PROPERTIES>::new(),
}
}
fn encode(&mut self, buffer: &mut [u8], buff_len: usize) -> Result<usize, BufferError> {
let mut buff_writer = BuffWriter::new(buffer, buff_len);
let mut rm_ln = self.property_len;
let property_len_enc: [u8; 4] = VariableByteIntegerEncoder::encode(self.property_len)?;
let property_len_len = VariableByteIntegerEncoder::len(property_len_enc);
rm_ln = rm_ln + property_len_len as u32;
rm_ln = rm_ln + 1;
buff_writer.write_u8(self.fixed_header)?;
buff_writer.write_variable_byte_int(rm_ln)?;
buff_writer.write_u8(self.auth_reason)?;
buff_writer.write_variable_byte_int(self.property_len)?;
buff_writer.write_properties::<MAX_PROPERTIES>(&self.properties)?;
Ok(buff_writer.position)
}
fn decode(&mut self, buff_reader: &mut BuffReader<'a>) -> Result<(), BufferError> {
self.decode_fixed_header(buff_reader)?;
self.auth_reason = buff_reader.read_u8()?;
return self.decode_properties(buff_reader);
}
fn set_property_len(&mut self, value: u32) {
self.property_len = value;
}
fn get_property_len(&mut self) -> u32 {
return self.property_len;
}
fn push_to_properties(&mut self, property: Property<'a>) {
self.properties.push(property);
}
fn property_allowed(&mut self, property: &Property<'a>) -> bool {
property.auth_property()
}
fn set_fixed_header(&mut self, header: u8) {
self.fixed_header = header;
}
fn set_remaining_len(&mut self, remaining_len: u32) {
self.remain_len = remaining_len;
}
}

View File

@@ -0,0 +1,107 @@
/*
* MIT License
*
* Copyright (c) [2022] [Ondrej Babec <ond.babec@gmail.com>]
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
use heapless::Vec;
use crate::encoding::variable_byte_integer::VariableByteIntegerEncoder;
use crate::packet::v5::mqtt_packet::Packet;
use crate::utils::buffer_reader::BuffReader;
use crate::utils::buffer_writer::BuffWriter;
use crate::utils::types::BufferError;
use super::packet_type::PacketType;
use super::property::Property;
pub struct ConnackPacket<'a, const MAX_PROPERTIES: usize> {
pub fixed_header: u8,
pub remain_len: u32,
pub ack_flags: u8,
pub connect_reason_code: u8,
pub property_len: u32,
pub properties: Vec<Property<'a>, MAX_PROPERTIES>,
}
impl<'a, const MAX_PROPERTIES: usize> ConnackPacket<'a, MAX_PROPERTIES> {}
impl<'a, const MAX_PROPERTIES: usize> Packet<'a> for ConnackPacket<'a, MAX_PROPERTIES> {
fn new() -> Self {
Self {
fixed_header: PacketType::Connack.into(),
remain_len: 0,
ack_flags: 0,
connect_reason_code: 0,
property_len: 0,
properties: Vec::<Property<'a>, MAX_PROPERTIES>::new(),
}
}
fn encode(&mut self, buffer: &mut [u8], buffer_len: usize) -> Result<usize, BufferError> {
let mut buff_writer = BuffWriter::new(buffer, buffer_len);
buff_writer.write_u8(self.fixed_header)?;
let property_len_enc = VariableByteIntegerEncoder::encode(self.property_len)?;
let property_len_len = VariableByteIntegerEncoder::len(property_len_enc);
let rm_len: u32 = 2 + self.property_len + property_len_len as u32;
buff_writer.write_variable_byte_int(rm_len)?;
buff_writer.write_u8(self.ack_flags)?;
buff_writer.write_u8(self.connect_reason_code)?;
buff_writer.write_variable_byte_int(self.property_len)?;
buff_writer.write_properties(&self.properties)?;
Ok(buff_writer.position)
}
fn decode(&mut self, buff_reader: &mut BuffReader<'a>) -> Result<(), BufferError> {
if self.decode_fixed_header(buff_reader)? != (PacketType::Connack).into() {
log::error!("Packet you are trying to decode is not CONNACK packet!");
return Err(BufferError::PacketTypeMismatch);
}
self.ack_flags = buff_reader.read_u8()?;
self.connect_reason_code = buff_reader.read_u8()?;
self.decode_properties(buff_reader)
}
fn set_property_len(&mut self, value: u32) {
self.property_len = value;
}
fn get_property_len(&mut self) -> u32 {
return self.property_len;
}
fn push_to_properties(&mut self, property: Property<'a>) {
self.properties.push(property);
}
fn property_allowed(&mut self, property: &Property<'a>) -> bool {
property.connack_property()
}
fn set_fixed_header(&mut self, header: u8) {
self.fixed_header = header;
}
fn set_remaining_len(&mut self, remaining_len: u32) {
self.remain_len = remaining_len;
}
}

View File

@@ -0,0 +1,217 @@
/*
* MIT License
*
* Copyright (c) [2022] [Ondrej Babec <ond.babec@gmail.com>]
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
use heapless::Vec;
use crate::encoding::variable_byte_integer::VariableByteIntegerEncoder;
use crate::packet::v5::mqtt_packet::Packet;
use crate::utils::buffer_reader::BuffReader;
use crate::utils::buffer_writer::BuffWriter;
use crate::utils::types::{BinaryData, BufferError, EncodedString};
use super::packet_type::PacketType;
use super::property::Property;
pub struct ConnectPacket<'a, const MAX_PROPERTIES: usize, const MAX_WILL_PROPERTIES: usize> {
pub fixed_header: u8,
pub remain_len: u32,
pub protocol_name_len: u16,
pub protocol_name: u32,
pub protocol_version: u8,
pub connect_flags: u8,
pub keep_alive: u16,
pub property_len: u32,
pub properties: Vec<Property<'a>, MAX_PROPERTIES>,
pub client_id: EncodedString<'a>,
pub will_property_len: u32,
pub will_properties: Vec<Property<'a>, MAX_WILL_PROPERTIES>,
pub will_topic: EncodedString<'a>,
pub will_payload: BinaryData<'a>,
pub username: EncodedString<'a>,
pub password: BinaryData<'a>,
}
impl<'a, const MAX_PROPERTIES: usize, const MAX_WILL_PROPERTIES: usize>
ConnectPacket<'a, MAX_PROPERTIES, MAX_WILL_PROPERTIES>
{
pub fn clean() -> Self {
let mut x = Self {
fixed_header: PacketType::Connect.into(),
remain_len: 0,
protocol_name_len: 4,
protocol_name: 0x4d515454,
protocol_version: 5,
connect_flags: 0x02,
keep_alive: 60,
property_len: 3,
properties: Vec::<Property<'a>, MAX_PROPERTIES>::new(),
client_id: EncodedString::new(),
/// Will is not supported as it is un-necessary load for embedded
will_property_len: 0,
will_properties: Vec::<Property<'a>, MAX_WILL_PROPERTIES>::new(),
will_topic: EncodedString::new(),
will_payload: BinaryData::new(),
username: EncodedString::new(),
password: BinaryData::new(),
};
let y = Property::ReceiveMaximum(20);
x.properties.push(y);
x.client_id.len = 0;
return x;
}
pub fn add_packet_type(&mut self, new_packet_type: PacketType) {
self.fixed_header = self.fixed_header & 0x0F;
self.fixed_header = self.fixed_header | <PacketType as Into<u8>>::into(new_packet_type);
}
pub fn add_username(&mut self, username: &EncodedString<'a>) {
self.username = (*username).clone();
self.connect_flags = self.connect_flags | 0x80;
}
pub fn add_password(&mut self, password: &BinaryData<'a>) {
self.password = (*password).clone();
self.connect_flags = self.connect_flags | 0x40;
}
pub fn add_client_id(&mut self, id: &EncodedString<'a>) {
self.client_id = (*id).clone();
}
}
impl<'a, const MAX_PROPERTIES: usize, const MAX_WILL_PROPERTIES: usize> Packet<'a>
for ConnectPacket<'a, MAX_PROPERTIES, MAX_WILL_PROPERTIES>
{
fn new() -> Self {
Self {
fixed_header: PacketType::Connect.into(),
remain_len: 0,
protocol_name_len: 4,
// MQTT
protocol_name: 0x4d515454,
protocol_version: 5,
// Clean start flag
connect_flags: 0x02,
keep_alive: 180,
property_len: 0,
properties: Vec::<Property<'a>, MAX_PROPERTIES>::new(),
client_id: EncodedString::new(),
will_property_len: 0,
will_properties: Vec::<Property<'a>, MAX_WILL_PROPERTIES>::new(),
will_topic: EncodedString::new(),
will_payload: BinaryData::new(),
username: EncodedString::new(),
password: BinaryData::new(),
}
}
fn encode(&mut self, buffer: &mut [u8], buffer_len: usize) -> Result<usize, BufferError> {
let mut buff_writer = BuffWriter::new(buffer, buffer_len);
let mut rm_ln = self.property_len;
let property_len_enc: [u8; 4] = VariableByteIntegerEncoder::encode(self.property_len)?;
let property_len_len = VariableByteIntegerEncoder::len(property_len_enc);
// Number 12 => protocol_name_len + protocol_name (6) + protocol_version (1)+ connect_flags (1) + keep_alive (2) + client_id_len (2)
rm_ln = rm_ln + property_len_len as u32 + 10 + self.client_id.len as u32 + 2;
if self.connect_flags & 0x04 != 0 {
let wil_prop_len_enc = VariableByteIntegerEncoder::encode(self.will_property_len)?;
let wil_prop_len_len = VariableByteIntegerEncoder::len(wil_prop_len_enc);
rm_ln = rm_ln
+ wil_prop_len_len as u32
+ self.will_property_len as u32
+ self.will_topic.len as u32
+ self.will_payload.len as u32;
}
if (self.connect_flags & 0x80) != 0 {
rm_ln = rm_ln + self.username.len as u32 + 2;
}
if self.connect_flags & 0x40 != 0 {
rm_ln = rm_ln + self.password.len as u32 + 2;
}
buff_writer.write_u8(self.fixed_header)?;
buff_writer.write_variable_byte_int(rm_ln)?;
buff_writer.write_u16(self.protocol_name_len)?;
buff_writer.write_u32(self.protocol_name)?;
buff_writer.write_u8(self.protocol_version)?;
buff_writer.write_u8(self.connect_flags)?;
buff_writer.write_u16(self.keep_alive)?;
buff_writer.write_variable_byte_int(self.property_len)?;
buff_writer.write_properties::<MAX_PROPERTIES>(&self.properties)?;
buff_writer.write_string_ref(&self.client_id)?;
if self.connect_flags & 0x04 != 0 {
buff_writer.write_variable_byte_int(self.will_property_len)?;
buff_writer.write_properties(&self.will_properties)?;
buff_writer.write_string_ref(&self.will_topic)?;
buff_writer.write_binary_ref(&self.will_payload)?;
}
if self.connect_flags & 0x80 != 0 {
buff_writer.write_string_ref(&self.username)?;
}
if self.connect_flags & 0x40 != 0 {
buff_writer.write_binary_ref(&self.password)?;
}
Ok(buff_writer.position)
}
fn decode(&mut self, _buff_reader: &mut BuffReader<'a>) -> Result<(), BufferError> {
log::error!("Decode function is not available for control packet!");
Err(BufferError::WrongPacketToDecode)
}
fn set_property_len(&mut self, value: u32) {
self.property_len = value;
}
fn get_property_len(&mut self) -> u32 {
return self.property_len;
}
fn push_to_properties(&mut self, property: Property<'a>) {
self.properties.push(property);
}
fn property_allowed(&mut self, property: &Property<'a>) -> bool {
property.connect_property()
}
fn set_fixed_header(&mut self, header: u8) {
self.fixed_header = header;
}
fn set_remaining_len(&mut self, remaining_len: u32) {
self.remain_len = remaining_len;
}
}

View File

@@ -0,0 +1,112 @@
/*
* MIT License
*
* Copyright (c) [2022] [Ondrej Babec <ond.babec@gmail.com>]
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
use heapless::Vec;
use crate::encoding::variable_byte_integer::VariableByteIntegerEncoder;
use crate::packet::v5::mqtt_packet::Packet;
use crate::utils::buffer_reader::BuffReader;
use crate::utils::buffer_writer::BuffWriter;
use crate::utils::types::BufferError;
use super::packet_type::PacketType;
use super::property::Property;
pub struct DisconnectPacket<'a, const MAX_PROPERTIES: usize> {
// 7 - 4 mqtt control packet type, 3-0 flagy
pub fixed_header: u8,
// 1 - 4 B lenght of variable header + len of payload
pub remain_len: u32,
pub disconnect_reason: u8,
pub property_len: u32,
pub properties: Vec<Property<'a>, MAX_PROPERTIES>,
}
impl<'a, const MAX_PROPERTIES: usize> DisconnectPacket<'a, MAX_PROPERTIES> {
fn add_reason(&mut self, reason: u8) {
self.disconnect_reason = reason;
}
}
impl<'a, const MAX_PROPERTIES: usize> Packet<'a> for DisconnectPacket<'a, MAX_PROPERTIES> {
fn new() -> Self {
Self {
fixed_header: PacketType::Disconnect.into(),
remain_len: 5,
disconnect_reason: 0x00,
property_len: 0,
properties: Vec::<Property<'a>, MAX_PROPERTIES>::new(),
}
}
fn encode(&mut self, buffer: &mut [u8], buffer_len: usize) -> Result<usize, BufferError> {
let mut buff_writer = BuffWriter::new(buffer, buffer_len);
buff_writer.write_u8(self.fixed_header)?;
let property_len_enc = VariableByteIntegerEncoder::encode(self.property_len)?;
let property_len_len = VariableByteIntegerEncoder::len(property_len_enc);
let rm_len: u32 = 1 + self.property_len + property_len_len as u32;
buff_writer.write_variable_byte_int(rm_len)?;
buff_writer.write_u8(self.disconnect_reason)?;
buff_writer.write_variable_byte_int(self.property_len)?;
buff_writer.write_properties(&self.properties)?;
Ok(buff_writer.position)
}
fn decode(&mut self, buff_reader: &mut BuffReader<'a>) -> Result<(), BufferError> {
if self.decode_fixed_header(buff_reader)? != (PacketType::Disconnect).into() {
log::error!("Packet you are trying to decode is not DISCONNECT packet!");
return Err(BufferError::WrongPacketToDecode);
}
self.disconnect_reason = buff_reader.read_u8()?;
return self.decode_properties(buff_reader);
}
fn set_property_len(&mut self, value: u32) {
self.property_len = value;
}
fn get_property_len(&mut self) -> u32 {
return self.property_len;
}
fn push_to_properties(&mut self, property: Property<'a>) {
self.properties.push(property);
}
fn property_allowed(&mut self, property: &Property<'a>) -> bool {
property.disconnect_property()
}
fn set_fixed_header(&mut self, header: u8) {
self.fixed_header = header;
}
fn set_remaining_len(&mut self, remaining_len: u32) {
self.remain_len = remaining_len;
}
}

44
mqtt/src/packet/v5/mod.rs Normal file
View File

@@ -0,0 +1,44 @@
/*
* MIT License
*
* Copyright (c) [2022] [Ondrej Babec <ond.babec@gmail.com>]
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
pub mod auth_packet;
pub mod connack_packet;
pub mod mqtt_packet;
pub mod packet_type;
pub mod property;
pub mod puback_packet;
pub mod pubcomp_packet;
pub mod publish_packet;
pub mod pubrec_packet;
pub mod pubrel_packet;
pub mod subscription_packet;
pub mod unsubscription_packet;
pub mod connect_packet;
pub mod disconnect_packet;
pub mod pingreq_packet;
pub mod pingresp_packet;
pub mod reason_codes;
pub mod suback_packet;
pub mod unsuback_packet;

View File

@@ -0,0 +1,107 @@
/*
* MIT License
*
* Copyright (c) [2022] [Ondrej Babec <ond.babec@gmail.com>]
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
use crate::packet::v5::packet_type::PacketType;
use crate::utils::buffer_reader::BuffReader;
use crate::utils::types::BufferError;
use heapless::Vec;
use super::property::Property;
/// This trait provide interface for mapping MQTTv5 packets to human readable structures
/// which can be later modified and used for communication purposes.
pub trait Packet<'a> {
fn new() -> Self;
/// Method encode provide way how to transfer Packet struct into Byte array (buffer)
fn encode(&mut self, buffer: &mut [u8], buff_len: usize) -> Result<usize, BufferError>;
/// Decode method is opposite of encode - decoding Byte array and mapping it into corresponding Packet struct
fn decode(&mut self, buff_reader: &mut BuffReader<'a>) -> Result<(), BufferError>;
/// Setter method for packet properties len - not all Packet types support this
fn set_property_len(&mut self, value: u32);
/// Setter method for packet properties len - not all Packet types support this
fn get_property_len(&mut self) -> u32;
/// Method enables pushing new property into packet properties
fn push_to_properties(&mut self, property: Property<'a>);
/// Returns if property is allowed for packet
fn property_allowed(&mut self, property: &Property<'a>) -> bool;
/// Method enables adding properties from client config - each packet decides if property can be used with that or not
fn add_properties<const MAX_PROPERTIES: usize>(
&mut self,
properties: &Vec<Property<'a>, MAX_PROPERTIES>,
) -> u32 {
let mut i = 0;
let max = properties.len();
let mut res: u32 = 0;
loop {
let prop = properties.get(i).unwrap();
if self.property_allowed(prop) {
self.push_to_properties((*prop).clone());
res = res + prop.len() as u32 + 1;
}
i = i + 1;
if i == max {
break;
}
}
return res;
}
/// Setter for packet fixed header
fn set_fixed_header(&mut self, header: u8);
/// Setter for remaining len
fn set_remaining_len(&mut self, remaining_len: u32);
/// Method is decoding Byte array pointing to properties into heapless Vec
/// in packet. If decoding goes wrong method is returning Error
fn decode_properties(&mut self, buff_reader: &mut BuffReader<'a>) -> Result<(), BufferError> {
self.set_property_len(buff_reader.read_variable_byte_int().unwrap());
let mut x: u32 = 0;
let mut prop: Property;
if self.get_property_len() != 0 {
loop {
prop = Property::decode(buff_reader)?;
log::debug!("Parsed property {:?}", prop);
x = x + prop.len() as u32 + 1;
self.push_to_properties(prop);
if x == self.get_property_len() {
break;
}
}
}
Ok(())
}
/// Method is decoding packet header into fixed header part and remaining length
fn decode_fixed_header(
&mut self,
buff_reader: &mut BuffReader,
) -> Result<PacketType, BufferError> {
let first_byte: u8 = buff_reader.read_u8()?;
self.set_fixed_header(first_byte);
self.set_remaining_len(buff_reader.read_variable_byte_int()?);
return Ok(PacketType::from(first_byte));
}
}

View File

@@ -0,0 +1,93 @@
/*
* MIT License
*
* Copyright (c) [2022] [Ondrej Babec <ond.babec@gmail.com>]
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
// x x x x - - - -
#[derive(PartialEq)]
pub enum PacketType {
Reserved,
Connect,
Connack,
Publish,
Puback,
Pubrec,
Pubrel,
Pubcomp,
Subscribe,
Suback,
Unsubscribe,
Unsuback,
Pingreq,
Pingresp,
Disconnect,
Auth,
}
impl From<u8> for PacketType {
fn from(orig: u8) -> Self {
let packet_type: u8 = orig & 0xF0;
return match packet_type {
0x10 => PacketType::Connect,
0x20 => PacketType::Connack,
0x00 => PacketType::Reserved,
0x30 => PacketType::Publish,
0x40 => PacketType::Puback,
0x50 => PacketType::Pubrec,
0x60 => PacketType::Pubrel,
0x70 => PacketType::Pubcomp,
0x80 => PacketType::Subscribe,
0x90 => PacketType::Suback,
0xA0 => PacketType::Unsubscribe,
0xB0 => PacketType::Unsuback,
0xC0 => PacketType::Pingreq,
0xD0 => PacketType::Pingresp,
0xE0 => PacketType::Disconnect,
0xF0 => PacketType::Auth,
_ => PacketType::Reserved,
};
}
}
impl Into<u8> for PacketType {
fn into(self) -> u8 {
return match self {
PacketType::Connect => 0x10,
PacketType::Connack => 0x20,
PacketType::Publish => 0x30,
PacketType::Puback => 0x40,
PacketType::Pubrec => 0x50,
PacketType::Pubrel => 0x60,
PacketType::Pubcomp => 0x70,
PacketType::Subscribe => 0x82,
PacketType::Suback => 0x90,
PacketType::Unsubscribe => 0xA0,
PacketType::Unsuback => 0xB0,
PacketType::Pingreq => 0xC0,
PacketType::Pingresp => 0xD0,
PacketType::Disconnect => 0xE0,
PacketType::Auth => 0xF0,
PacketType::Reserved => 0x00,
};
}
}

View File

@@ -0,0 +1,84 @@
/*
* MIT License
*
* Copyright (c) [2022] [Ondrej Babec <ond.babec@gmail.com>]
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
use crate::packet::v5::mqtt_packet::Packet;
use crate::utils::buffer_reader::BuffReader;
use crate::utils::buffer_writer::BuffWriter;
use crate::utils::types::BufferError;
use super::packet_type::PacketType;
use super::property::Property;
pub struct PingreqPacket {
pub fixed_header: u8,
pub remain_len: u32,
}
impl PingreqPacket {}
impl<'a> Packet<'a> for PingreqPacket {
fn new() -> Self {
Self {
fixed_header: PacketType::Pingreq.into(),
remain_len: 0,
}
}
fn encode(&mut self, buffer: &mut [u8], buffer_len: usize) -> Result<usize, BufferError> {
let mut buff_writer = BuffWriter::new(buffer, buffer_len);
buff_writer.write_u8(self.fixed_header)?;
buff_writer.write_variable_byte_int(0 as u32)?;
Ok(buff_writer.position)
}
fn decode(&mut self, _buff_reader: &mut BuffReader<'a>) -> Result<(), BufferError> {
log::error!("Pingreq Packet packet does not support decode funtion on client!");
Err(BufferError::WrongPacketToDecode)
}
fn set_property_len(&mut self, _value: u32) {
log::error!("PINGREQ packet does not contain any properties!");
}
fn get_property_len(&mut self) -> u32 {
log::error!("PINGREQ packet does not contain any properties!");
return 0;
}
fn push_to_properties(&mut self, _property: Property<'a>) {
log::error!("PINGREQ packet does not contain any properties!");
}
fn property_allowed(&mut self, property: &Property<'a>) -> bool {
property.pingreq_property()
}
fn set_fixed_header(&mut self, header: u8) {
self.fixed_header = header;
}
fn set_remaining_len(&mut self, remaining_len: u32) {
self.remain_len = remaining_len;
}
}

View File

@@ -0,0 +1,92 @@
/*
* MIT License
*
* Copyright (c) [2022] [Ondrej Babec <ond.babec@gmail.com>]
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
use crate::packet::v5::mqtt_packet::Packet;
use crate::utils::buffer_reader::BuffReader;
use crate::utils::buffer_writer::BuffWriter;
use crate::utils::types::BufferError;
use super::packet_type::PacketType;
use super::property::Property;
pub struct PingrespPacket {
pub fixed_header: u8,
pub remain_len: u32,
}
impl<'a> PingrespPacket {}
impl<'a> Packet<'a> for PingrespPacket {
fn new() -> Self {
Self {
fixed_header: PacketType::Pingresp.into(),
remain_len: 0,
}
}
fn encode(&mut self, buffer: &mut [u8], buffer_len: usize) -> Result<usize, BufferError> {
let mut buff_writer = BuffWriter::new(buffer, buffer_len);
buff_writer.write_u8(self.fixed_header)?;
buff_writer.write_variable_byte_int(self.remain_len)?;
Ok(buff_writer.position)
}
fn decode(&mut self, buff_reader: &mut BuffReader<'a>) -> Result<(), BufferError> {
let x = self.decode_fixed_header(buff_reader)?;
if x != (PacketType::Pingresp).into() {
log::error!("Packet you are trying to decode is not PINGRESP packet!");
return Err(BufferError::PacketTypeMismatch);
}
if self.remain_len != 0 {
log::error!("PINGRESP packet does not have 0 lenght!");
return Err(BufferError::PacketTypeMismatch);
}
Ok(())
}
fn set_property_len(&mut self, _value: u32) {
log::error!("PINGRESP packet does not contain any properties!");
}
fn get_property_len(&mut self) -> u32 {
log::error!("PINGRESP packet does not contain any properties!");
return 0;
}
fn push_to_properties(&mut self, _property: Property<'a>) {
log::error!("PINGRESP packet does not contain any properties!");
}
fn property_allowed(&mut self, property: &Property<'a>) -> bool {
property.pingresp_property()
}
fn set_fixed_header(&mut self, header: u8) {
self.fixed_header = header;
}
fn set_remaining_len(&mut self, remaining_len: u32) {
self.remain_len = remaining_len;
}
}

View File

@@ -0,0 +1,364 @@
/*
* MIT License
*
* Copyright (c) [2022] [Ondrej Babec <ond.babec@gmail.com>]
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
use crate::encoding::variable_byte_integer::VariableByteIntegerEncoder;
use crate::utils::buffer_reader::BuffReader;
use crate::utils::buffer_writer::BuffWriter;
use crate::utils::types::{BinaryData, BufferError, EncodedString, StringPair};
#[derive(Debug, Clone)]
pub enum Property<'a> {
PayloadFormat(u8),
MessageExpiryInterval(u32),
ContentType(EncodedString<'a>),
ResponseTopic(EncodedString<'a>),
CorrelationData(BinaryData<'a>),
SubscriptionIdentifier(u32),
SessionExpiryInterval(u32),
AssignedClientIdentifier(EncodedString<'a>),
ServerKeepAlive(u16),
AuthenticationMethod(EncodedString<'a>),
AuthenticationData(BinaryData<'a>),
RequestProblemInformation(u8),
WillDelayInterval(u32),
RequestResponseInformation(u8),
ResponseInformation(EncodedString<'a>),
ServerReference(EncodedString<'a>),
ReasonString(EncodedString<'a>),
ReceiveMaximum(u16),
TopicAliasMaximum(u16),
TopicAlias(u16),
MaximumQoS(u8),
RetainAvailable(u8),
UserProperty(StringPair<'a>),
MaximumPacketSize(u32),
WildcardSubscriptionAvailable(u8),
SubscriptionIdentifierAvailable(u8),
SharedSubscriptionAvailable(u8),
Reserved(),
}
impl<'a> Property<'a> {
pub fn connect_property(&self) -> bool {
return match self {
Property::SessionExpiryInterval(_u) => true,
Property::ReceiveMaximum(_u) => true,
Property::MaximumPacketSize(_u) => true,
Property::TopicAliasMaximum(_u) => true,
Property::RequestResponseInformation(_u) => true,
Property::RequestProblemInformation(_u) => true,
Property::UserProperty(_u) => true,
Property::AuthenticationMethod(_u) => true,
Property::AuthenticationData(_u) => true,
_ => false,
};
}
pub fn connack_property(&self) -> bool {
return match self {
Property::SessionExpiryInterval(_u) => true,
Property::ReceiveMaximum(_u) => true,
Property::MaximumQoS(_u) => true,
Property::MaximumPacketSize(_u) => true,
Property::AssignedClientIdentifier(_u) => true,
Property::TopicAliasMaximum(_u) => true,
Property::ReasonString(_u) => true,
Property::UserProperty(_u) => true,
Property::WildcardSubscriptionAvailable(_u) => true,
Property::SubscriptionIdentifierAvailable(_u) => true,
Property::SharedSubscriptionAvailable(_u) => true,
Property::ServerKeepAlive(_u) => true,
Property::ResponseInformation(_u) => true,
Property::ServerReference(_u) => true,
Property::AuthenticationMethod(_u) => true,
Property::AuthenticationData(_u) => true,
_ => false,
};
}
pub fn publish_property(&self) -> bool {
return match self {
Property::PayloadFormat(_u) => true,
Property::MessageExpiryInterval(_u) => true,
Property::TopicAlias(_u) => true,
Property::ResponseTopic(_u) => true,
Property::CorrelationData(_u) => true,
Property::UserProperty(_u) => true,
Property::SubscriptionIdentifier(_u) => true,
Property::ContentType(_u) => true,
_ => false,
};
}
pub fn puback_property(&self) -> bool {
return match self {
Property::ReasonString(_u) => true,
Property::UserProperty(_u) => true,
_ => false,
};
}
pub fn pubrec_property(&self) -> bool {
return match self {
Property::ReasonString(_u) => true,
Property::UserProperty(_u) => true,
_ => false,
};
}
pub fn pubrel_property(&self) -> bool {
return match self {
Property::ReasonString(_u) => true,
Property::UserProperty(_u) => true,
_ => false,
};
}
pub fn pubcomp_property(&self) -> bool {
return match self {
Property::ReasonString(_u) => true,
Property::UserProperty(_u) => true,
_ => false,
};
}
pub fn subscribe_property(&self) -> bool {
return match self {
Property::SubscriptionIdentifier(_u) => true,
Property::UserProperty(_u) => true,
_ => false,
};
}
pub fn suback_property(&self) -> bool {
return match self {
Property::ReasonString(_u) => true,
Property::UserProperty(_u) => true,
_ => false,
};
}
pub fn unsubscribe_property(&self) -> bool {
return match self {
Property::UserProperty(_u) => true,
_ => false,
};
}
pub fn unsuback_property(&self) -> bool {
return match self {
Property::ReasonString(_u) => true,
Property::UserProperty(_u) => true,
_ => false,
};
}
pub fn pingreq_property(&self) -> bool {
return match self {
_ => false,
};
}
pub fn pingresp_property(&self) -> bool {
return match self {
_ => false,
};
}
pub fn disconnect_property(&self) -> bool {
return match self {
Property::SessionExpiryInterval(_u) => true,
Property::ReasonString(_u) => true,
Property::UserProperty(_u) => true,
Property::ServerReference(_u) => true,
_ => false,
};
}
pub fn auth_property(&self) -> bool {
return match self {
Property::AuthenticationMethod(_u) => true,
Property::AuthenticationData(_u) => true,
Property::ReasonString(_u) => true,
Property::UserProperty(_u) => true,
_ => false,
};
}
pub fn len(&self) -> u16 {
return match self {
Property::PayloadFormat(_u) => 1,
Property::MessageExpiryInterval(_u) => 4,
Property::ContentType(u) => u.len(),
Property::ResponseTopic(u) => u.len(),
Property::CorrelationData(u) => u.len(),
Property::SubscriptionIdentifier(u) => {
VariableByteIntegerEncoder::len(VariableByteIntegerEncoder::encode(*u).unwrap())
as u16
}
Property::SessionExpiryInterval(_u) => 4,
Property::AssignedClientIdentifier(u) => u.len(),
Property::ServerKeepAlive(_u) => 2,
Property::AuthenticationMethod(u) => u.len(),
Property::AuthenticationData(u) => u.len(),
Property::RequestProblemInformation(_u) => 1,
Property::WillDelayInterval(_u) => 4,
Property::RequestResponseInformation(_u) => 1,
Property::ResponseInformation(u) => u.len(),
Property::ServerReference(u) => u.len(),
Property::ReasonString(u) => u.len(),
Property::ReceiveMaximum(_u) => 2,
Property::TopicAliasMaximum(_u) => 2,
Property::TopicAlias(_u) => 2,
Property::MaximumQoS(_u) => 1,
Property::RetainAvailable(_u) => 1,
Property::UserProperty(u) => u.len(),
Property::MaximumPacketSize(_u) => 4,
Property::WildcardSubscriptionAvailable(_u) => 1,
Property::SubscriptionIdentifierAvailable(_u) => 1,
Property::SharedSubscriptionAvailable(_u) => 1,
_ => 0,
};
}
pub fn encode(&self, buff_writer: &mut BuffWriter<'a>) -> Result<(), BufferError> {
return match self {
Property::PayloadFormat(u) => buff_writer.write_u8(*u),
Property::MessageExpiryInterval(u) => buff_writer.write_u32(*u),
Property::ContentType(u) => buff_writer.write_string_ref(u),
Property::ResponseTopic(u) => buff_writer.write_string_ref(u),
Property::CorrelationData(u) => buff_writer.write_binary_ref(u),
Property::SubscriptionIdentifier(u) => buff_writer.write_variable_byte_int(*u),
Property::SessionExpiryInterval(u) => buff_writer.write_u32(*u),
Property::AssignedClientIdentifier(u) => buff_writer.write_string_ref(u),
Property::ServerKeepAlive(u) => buff_writer.write_u16(*u),
Property::AuthenticationMethod(u) => buff_writer.write_string_ref(u),
Property::AuthenticationData(u) => buff_writer.write_binary_ref(u),
Property::RequestProblemInformation(u) => buff_writer.write_u8(*u),
Property::WillDelayInterval(u) => buff_writer.write_u32(*u),
Property::RequestResponseInformation(u) => buff_writer.write_u8(*u),
Property::ResponseInformation(u) => buff_writer.write_string_ref(u),
Property::ServerReference(u) => buff_writer.write_string_ref(u),
Property::ReasonString(u) => buff_writer.write_string_ref(u),
Property::ReceiveMaximum(u) => buff_writer.write_u16(*u),
Property::TopicAliasMaximum(u) => buff_writer.write_u16(*u),
Property::TopicAlias(u) => buff_writer.write_u16(*u),
Property::MaximumQoS(u) => buff_writer.write_u8(*u),
Property::RetainAvailable(u) => buff_writer.write_u8(*u),
Property::UserProperty(u) => buff_writer.write_string_pair_ref(u),
Property::MaximumPacketSize(u) => buff_writer.write_u32(*u),
Property::WildcardSubscriptionAvailable(u) => buff_writer.write_u8(*u),
Property::SubscriptionIdentifierAvailable(u) => buff_writer.write_u8(*u),
Property::SharedSubscriptionAvailable(u) => buff_writer.write_u8(*u),
_ => Err(BufferError::PropertyNotFound),
};
}
pub fn decode(buff_reader: &mut BuffReader<'a>) -> Result<Property<'a>, BufferError> {
let property_identifier = buff_reader.read_u8();
return match property_identifier {
Ok(0x01) => Ok(Property::PayloadFormat(buff_reader.read_u8()?)),
Ok(0x02) => Ok(Property::MessageExpiryInterval(buff_reader.read_u32()?)),
Ok(0x03) => Ok(Property::ContentType(buff_reader.read_string()?)),
Ok(0x08) => Ok(Property::ResponseTopic(buff_reader.read_string()?)),
Ok(0x09) => Ok(Property::CorrelationData(buff_reader.read_binary()?)),
Ok(0x0B) => Ok(Property::SubscriptionIdentifier(
buff_reader.read_variable_byte_int()?,
)),
Ok(0x11) => Ok(Property::SessionExpiryInterval(buff_reader.read_u32()?)),
Ok(0x12) => Ok(Property::AssignedClientIdentifier(
buff_reader.read_string()?,
)),
Ok(0x13) => Ok(Property::ServerKeepAlive(buff_reader.read_u16()?)),
Ok(0x15) => Ok(Property::AuthenticationMethod(buff_reader.read_string()?)),
Ok(0x16) => Ok(Property::AuthenticationData(buff_reader.read_binary()?)),
Ok(0x17) => Ok(Property::RequestProblemInformation(buff_reader.read_u8()?)),
Ok(0x18) => Ok(Property::WillDelayInterval(buff_reader.read_u32()?)),
Ok(0x19) => Ok(Property::RequestResponseInformation(buff_reader.read_u8()?)),
Ok(0x1A) => Ok(Property::ResponseInformation(buff_reader.read_string()?)),
Ok(0x1C) => Ok(Property::ServerReference(buff_reader.read_string()?)),
Ok(0x1F) => Ok(Property::ReasonString(buff_reader.read_string()?)),
Ok(0x21) => Ok(Property::ReceiveMaximum(buff_reader.read_u16()?)),
Ok(0x22) => Ok(Property::TopicAliasMaximum(buff_reader.read_u16()?)),
Ok(0x23) => Ok(Property::TopicAlias(buff_reader.read_u16()?)),
Ok(0x24) => Ok(Property::MaximumQoS(buff_reader.read_u8()?)),
Ok(0x25) => Ok(Property::RetainAvailable(buff_reader.read_u8()?)),
Ok(0x26) => Ok(Property::UserProperty(buff_reader.read_string_pair()?)),
Ok(0x28) => Ok(Property::WildcardSubscriptionAvailable(
buff_reader.read_u8()?,
)),
Ok(0x29) => Ok(Property::SubscriptionIdentifierAvailable(
buff_reader.read_u8()?,
)),
Ok(0x2A) => Ok(Property::SharedSubscriptionAvailable(
buff_reader.read_u8()?,
)),
Err(err) => Err(err),
_ => Err(BufferError::IdNotFound),
};
}
}
impl Into<u8> for &Property<'a> {
fn into(self) -> u8 {
return match &*self {
Property::PayloadFormat(_u) => 0x01,
Property::MessageExpiryInterval(_u) => 0x02,
Property::ContentType(_u) => 0x03,
Property::ResponseTopic(_u) => 0x08,
Property::CorrelationData(_u) => 0x09,
Property::SubscriptionIdentifier(_u) => 0x0B,
Property::SessionExpiryInterval(_u) => 0x11,
Property::AssignedClientIdentifier(_u) => 0x12,
Property::ServerKeepAlive(_u) => 0x13,
Property::AuthenticationMethod(_u) => 0x15,
Property::AuthenticationData(_u) => 0x16,
Property::RequestProblemInformation(_u) => 0x17,
Property::WillDelayInterval(_u) => 0x18,
Property::RequestResponseInformation(_u) => 0x19,
Property::ResponseInformation(_u) => 0x1A,
Property::ServerReference(_u) => 0x1C,
Property::ReasonString(_u) => 0x1F,
Property::ReceiveMaximum(_u) => 0x21,
Property::TopicAliasMaximum(_u) => 0x22,
Property::TopicAlias(_u) => 0x23,
Property::MaximumQoS(_u) => 0x24,
Property::RetainAvailable(_u) => 0x25,
Property::UserProperty(_u) => 0x26,
Property::MaximumPacketSize(_u) => 0x27,
Property::WildcardSubscriptionAvailable(_u) => 0x28,
Property::SubscriptionIdentifierAvailable(_u) => 0x29,
Property::SharedSubscriptionAvailable(_u) => 0x2A,
_ => 0x00,
};
}
}
impl From<u8> for Property<'a> {
fn from(_orig: u8) -> Self {
return match _orig {
_ => Property::Reserved(),
};
}
}

View File

@@ -0,0 +1,116 @@
/*
* MIT License
*
* Copyright (c) [2022] [Ondrej Babec <ond.babec@gmail.com>]
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
use heapless::Vec;
use crate::encoding::variable_byte_integer::VariableByteIntegerEncoder;
use crate::packet::v5::mqtt_packet::Packet;
use crate::utils::buffer_reader::BuffReader;
use crate::utils::buffer_writer::BuffWriter;
use crate::utils::types::BufferError;
use super::packet_type::PacketType;
use super::property::Property;
pub struct PubackPacket<'a, const MAX_PROPERTIES: usize> {
pub fixed_header: u8,
pub remain_len: u32,
pub packet_identifier: u16,
pub reason_code: u8,
pub property_len: u32,
pub properties: Vec<Property<'a>, MAX_PROPERTIES>,
}
impl<'a, const MAX_PROPERTIES: usize> PubackPacket<'a, MAX_PROPERTIES> {}
impl<'a, const MAX_PROPERTIES: usize> Packet<'a> for PubackPacket<'a, MAX_PROPERTIES> {
fn new() -> Self {
Self {
fixed_header: PacketType::Puback.into(),
remain_len: 0,
packet_identifier: 0,
reason_code: 0,
property_len: 0,
properties: Vec::<Property<'a>, MAX_PROPERTIES>::new(),
}
}
fn encode(&mut self, buffer: &mut [u8], buffer_len: usize) -> Result<usize, BufferError> {
let mut buff_writer = BuffWriter::new(buffer, buffer_len);
let mut rm_ln = self.property_len;
let property_len_enc: [u8; 4] = VariableByteIntegerEncoder::encode(self.property_len)?;
let property_len_len = VariableByteIntegerEncoder::len(property_len_enc);
rm_ln = rm_ln + property_len_len as u32 + 3;
buff_writer.write_u8(self.fixed_header)?;
buff_writer.write_variable_byte_int(rm_ln)?;
buff_writer.write_u16(self.packet_identifier)?;
buff_writer.write_u8(self.reason_code)?;
buff_writer.write_variable_byte_int(self.property_len)?;
buff_writer.write_properties::<MAX_PROPERTIES>(&self.properties)?;
Ok(buff_writer.position)
}
fn decode(&mut self, buff_reader: &mut BuffReader<'a>) -> Result<(), BufferError> {
if self.decode_fixed_header(buff_reader)? != (PacketType::Puback).into() {
log::error!("Packet you are trying to decode is not PUBACK packet!");
return Err(BufferError::PacketTypeMismatch);
}
self.packet_identifier = buff_reader.read_u16()?;
if self.remain_len != 2 {
self.reason_code = buff_reader.read_u8()?;
}
if self.remain_len < 4 {
self.property_len = 0;
} else {
self.decode_properties(buff_reader)?;
}
Ok(())
}
fn set_property_len(&mut self, value: u32) {
self.property_len = value;
}
fn get_property_len(&mut self) -> u32 {
return self.property_len;
}
fn push_to_properties(&mut self, property: Property<'a>) {
self.properties.push(property);
}
fn property_allowed(&mut self, property: &Property<'a>) -> bool {
property.puback_property()
}
fn set_fixed_header(&mut self, header: u8) {
self.fixed_header = header;
}
fn set_remaining_len(&mut self, remaining_len: u32) {
self.remain_len = remaining_len;
}
}

View File

@@ -0,0 +1,110 @@
/*
* MIT License
*
* Copyright (c) [2022] [Ondrej Babec <ond.babec@gmail.com>]
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
use heapless::Vec;
use crate::encoding::variable_byte_integer::VariableByteIntegerEncoder;
use crate::packet::v5::mqtt_packet::Packet;
use crate::utils::buffer_reader::BuffReader;
use crate::utils::buffer_writer::BuffWriter;
use crate::utils::types::BufferError;
use super::packet_type::PacketType;
use super::property::Property;
pub struct PubcompPacket<'a, const MAX_PROPERTIES: usize> {
pub fixed_header: u8,
pub remain_len: u32,
pub packet_identifier: u16,
pub reason_code: u8,
pub property_len: u32,
pub properties: Vec<Property<'a>, MAX_PROPERTIES>,
}
impl<'a, const MAX_PROPERTIES: usize> PubcompPacket<'a, MAX_PROPERTIES> {}
impl<'a, const MAX_PROPERTIES: usize> Packet<'a> for PubcompPacket<'a, MAX_PROPERTIES> {
fn new() -> Self {
Self {
fixed_header: PacketType::Pubcomp.into(),
remain_len: 0,
packet_identifier: 0,
reason_code: 0,
property_len: 0,
properties: Vec::<Property<'a>, MAX_PROPERTIES>::new(),
}
}
fn encode(&mut self, buffer: &mut [u8], buffer_len: usize) -> Result<usize, BufferError> {
let mut buff_writer = BuffWriter::new(buffer, buffer_len);
let mut rm_ln = self.property_len;
let property_len_enc: [u8; 4] = VariableByteIntegerEncoder::encode(self.property_len)?;
let property_len_len = VariableByteIntegerEncoder::len(property_len_enc);
rm_ln = rm_ln + property_len_len as u32 + 3;
buff_writer.write_u8(self.fixed_header)?;
buff_writer.write_variable_byte_int(rm_ln)?;
buff_writer.write_u16(self.packet_identifier)?;
buff_writer.write_u8(self.reason_code)?;
buff_writer.write_variable_byte_int(self.property_len)?;
buff_writer.write_properties::<MAX_PROPERTIES>(&self.properties)?;
Ok(buff_writer.position)
}
fn decode(&mut self, buff_reader: &mut BuffReader<'a>) -> Result<(), BufferError> {
if self.decode_fixed_header(buff_reader)? != (PacketType::Pubcomp).into() {
log::error!("Packet you are trying to decode is not PUBCOMP packet!");
return Err(BufferError::PacketTypeMismatch);
}
self.packet_identifier = buff_reader.read_u16()?;
self.reason_code = buff_reader.read_u8()?;
self.decode_properties(buff_reader)?;
Ok(())
}
fn set_property_len(&mut self, value: u32) {
self.property_len = value;
}
fn get_property_len(&mut self) -> u32 {
return self.property_len;
}
fn push_to_properties(&mut self, property: Property<'a>) {
self.properties.push(property);
}
fn property_allowed(&mut self, property: &Property<'a>) -> bool {
property.pubcomp_property()
}
fn set_fixed_header(&mut self, header: u8) {
self.fixed_header = header;
}
fn set_remaining_len(&mut self, remaining_len: u32) {
self.remain_len = remaining_len;
}
}

View File

@@ -0,0 +1,179 @@
/*
* MIT License
*
* Copyright (c) [2022] [Ondrej Babec <ond.babec@gmail.com>]
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
use heapless::Vec;
use crate::encoding::variable_byte_integer::VariableByteIntegerEncoder;
use crate::packet::v5::mqtt_packet::Packet;
use crate::packet::v5::publish_packet::QualityOfService::{QoS0, QoS1, QoS2, INVALID};
use crate::utils::buffer_reader::BuffReader;
use crate::utils::buffer_writer::BuffWriter;
use crate::utils::types::{BufferError, EncodedString};
use super::packet_type::PacketType;
use super::property::Property;
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum QualityOfService {
QoS0,
QoS1,
QoS2,
INVALID,
}
impl From<u8> for QualityOfService {
fn from(orig: u8) -> Self {
return match orig {
0 => QoS0,
2 => QoS1,
4 => QoS2,
_ => INVALID,
};
}
}
impl Into<u8> for QualityOfService {
fn into(self) -> u8 {
return match self {
QoS0 => 0,
QoS1 => 2,
QoS2 => 4,
INVALID => 3,
};
}
}
pub struct PublishPacket<'a, const MAX_PROPERTIES: usize> {
pub fixed_header: u8,
pub remain_len: u32,
pub topic_name: EncodedString<'a>,
pub packet_identifier: u16,
pub property_len: u32,
pub properties: Vec<Property<'a>, MAX_PROPERTIES>,
pub message: Option<&'a [u8]>,
}
impl<'a, const MAX_PROPERTIES: usize> PublishPacket<'a, MAX_PROPERTIES> {
pub fn add_topic_name(&mut self, topic_name: &'a str) {
self.topic_name.string = topic_name;
self.topic_name.len = topic_name.len() as u16;
}
pub fn add_message(&mut self, message: &'a [u8]) {
self.message = Some(message);
}
pub fn add_qos(&mut self, qos: QualityOfService) {
self.fixed_header = self.fixed_header | <QualityOfService as Into<u8>>::into(qos);
}
pub fn add_identifier(&mut self, identifier: u16) {
self.packet_identifier = identifier;
}
}
impl<'a, const MAX_PROPERTIES: usize> Packet<'a> for PublishPacket<'a, MAX_PROPERTIES> {
fn new() -> Self {
Self {
fixed_header: PacketType::Publish.into(),
remain_len: 0,
topic_name: EncodedString::new(),
packet_identifier: 1,
property_len: 0,
properties: Vec::<Property<'a>, MAX_PROPERTIES>::new(),
message: None,
}
}
fn encode(&mut self, buffer: &mut [u8], buffer_len: usize) -> Result<usize, BufferError> {
let mut buff_writer = BuffWriter::new(buffer, buffer_len);
let mut rm_ln = self.property_len;
let property_len_enc: [u8; 4] = VariableByteIntegerEncoder::encode(self.property_len)?;
let property_len_len = VariableByteIntegerEncoder::len(property_len_enc);
let msg_len = self.message.unwrap().len() as u32;
rm_ln = rm_ln + property_len_len as u32 + msg_len + self.topic_name.len as u32 + 2;
buff_writer.write_u8(self.fixed_header)?;
let qos = self.fixed_header & 0x03;
if qos != 0 {
rm_ln = rm_ln + 2;
}
buff_writer.write_variable_byte_int(rm_ln)?;
buff_writer.write_string_ref(&self.topic_name)?;
if qos != 0 {
buff_writer.write_u16(self.packet_identifier)?;
}
buff_writer.write_variable_byte_int(self.property_len)?;
buff_writer.write_properties::<MAX_PROPERTIES>(&self.properties)?;
buff_writer.insert_ref(msg_len as usize, self.message.unwrap())?;
Ok(buff_writer.position)
}
fn decode(&mut self, buff_reader: &mut BuffReader<'a>) -> Result<(), BufferError> {
if self.decode_fixed_header(buff_reader)? != (PacketType::Publish).into() {
log::error!("Packet you are trying to decode is not PUBLISH packet!");
return Err(BufferError::PacketTypeMismatch);
}
self.topic_name = buff_reader.read_string()?;
let qos = self.fixed_header & 0x03;
if qos != 0 {
// Decode only for QoS 1 / 2
self.packet_identifier = buff_reader.read_u16()?;
}
self.decode_properties(buff_reader)?;
let mut total_len =
VariableByteIntegerEncoder::len(VariableByteIntegerEncoder::encode(self.remain_len)?);
total_len = total_len + 1 + self.remain_len as usize;
self.message = Some(buff_reader.read_message(total_len));
Ok(())
}
fn set_property_len(&mut self, value: u32) {
self.property_len = value;
}
fn get_property_len(&mut self) -> u32 {
return self.property_len;
}
fn push_to_properties(&mut self, property: Property<'a>) {
self.properties.push(property);
}
fn property_allowed(&mut self, property: &Property<'a>) -> bool {
property.publish_property()
}
fn set_fixed_header(&mut self, header: u8) {
self.fixed_header = header;
}
fn set_remaining_len(&mut self, remaining_len: u32) {
self.remain_len = remaining_len;
}
}

View File

@@ -0,0 +1,109 @@
/*
* MIT License
*
* Copyright (c) [2022] [Ondrej Babec <ond.babec@gmail.com>]
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
use heapless::Vec;
use crate::encoding::variable_byte_integer::VariableByteIntegerEncoder;
use crate::packet::v5::mqtt_packet::Packet;
use crate::utils::buffer_reader::BuffReader;
use crate::utils::buffer_writer::BuffWriter;
use crate::utils::types::BufferError;
use super::packet_type::PacketType;
use super::property::Property;
pub struct PubrecPacket<'a, const MAX_PROPERTIES: usize> {
pub fixed_header: u8,
pub remain_len: u32,
pub packet_identifier: u16,
pub reason_code: u8,
pub property_len: u32,
pub properties: Vec<Property<'a>, MAX_PROPERTIES>,
}
impl<'a, const MAX_PROPERTIES: usize> PubrecPacket<'a, MAX_PROPERTIES> {}
impl<'a, const MAX_PROPERTIES: usize> Packet<'a> for PubrecPacket<'a, MAX_PROPERTIES> {
fn new() -> Self {
Self {
fixed_header: PacketType::Pubrec.into(),
remain_len: 0,
packet_identifier: 0,
reason_code: 0,
property_len: 0,
properties: Vec::<Property<'a>, MAX_PROPERTIES>::new(),
}
}
fn encode(&mut self, buffer: &mut [u8], buffer_len: usize) -> Result<usize, BufferError> {
let mut buff_writer = BuffWriter::new(buffer, buffer_len);
let mut rm_ln = self.property_len;
let property_len_enc: [u8; 4] = VariableByteIntegerEncoder::encode(self.property_len)?;
let property_len_len = VariableByteIntegerEncoder::len(property_len_enc);
rm_ln = rm_ln + property_len_len as u32 + 3;
buff_writer.write_u8(self.fixed_header)?;
buff_writer.write_variable_byte_int(rm_ln)?;
buff_writer.write_u16(self.packet_identifier)?;
buff_writer.write_u8(self.reason_code)?;
buff_writer.write_variable_byte_int(self.property_len)?;
buff_writer.write_properties::<MAX_PROPERTIES>(&self.properties)?;
Ok(buff_writer.position)
}
fn decode(&mut self, buff_reader: &mut BuffReader<'a>) -> Result<(), BufferError> {
if self.decode_fixed_header(buff_reader)? != (PacketType::Pubrec).into() {
log::error!("Packet you are trying to decode is not PUBREC packet!");
return Err(BufferError::PacketTypeMismatch);
}
self.packet_identifier = buff_reader.read_u16()?;
self.reason_code = buff_reader.read_u8()?;
return self.decode_properties(buff_reader);
}
fn set_property_len(&mut self, value: u32) {
self.property_len = value;
}
fn get_property_len(&mut self) -> u32 {
return self.property_len;
}
fn push_to_properties(&mut self, property: Property<'a>) {
self.properties.push(property);
}
fn property_allowed(&mut self, property: &Property<'a>) -> bool {
property.pubrec_property()
}
fn set_fixed_header(&mut self, header: u8) {
self.fixed_header = header;
}
fn set_remaining_len(&mut self, remaining_len: u32) {
self.remain_len = remaining_len;
}
}

View File

@@ -0,0 +1,109 @@
/*
* MIT License
*
* Copyright (c) [2022] [Ondrej Babec <ond.babec@gmail.com>]
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
use heapless::Vec;
use crate::encoding::variable_byte_integer::VariableByteIntegerEncoder;
use crate::packet::v5::mqtt_packet::Packet;
use crate::utils::buffer_reader::BuffReader;
use crate::utils::buffer_writer::BuffWriter;
use crate::utils::types::BufferError;
use super::packet_type::PacketType;
use super::property::Property;
pub struct PubrelPacket<'a, const MAX_PROPERTIES: usize> {
pub fixed_header: u8,
pub remain_len: u32,
pub packet_identifier: u16,
pub reason_code: u8,
pub property_len: u32,
pub properties: Vec<Property<'a>, MAX_PROPERTIES>,
}
impl<'a, const MAX_PROPERTIES: usize> PubrelPacket<'a, MAX_PROPERTIES> {}
impl<'a, const MAX_PROPERTIES: usize> Packet<'a> for PubrelPacket<'a, MAX_PROPERTIES> {
fn new() -> Self {
Self {
fixed_header: 0,
remain_len: 0,
packet_identifier: 0,
reason_code: 0,
property_len: 0,
properties: Vec::<Property<'a>, MAX_PROPERTIES>::new(),
}
}
fn encode(&mut self, buffer: &mut [u8], buffer_len: usize) -> Result<usize, BufferError> {
let mut buff_writer = BuffWriter::new(buffer, buffer_len);
let mut rm_ln = self.property_len;
let property_len_enc: [u8; 4] = VariableByteIntegerEncoder::encode(self.property_len)?;
let property_len_len = VariableByteIntegerEncoder::len(property_len_enc);
rm_ln = rm_ln + property_len_len as u32 + 3;
buff_writer.write_u8(self.fixed_header)?;
buff_writer.write_variable_byte_int(rm_ln)?;
buff_writer.write_u16(self.packet_identifier)?;
buff_writer.write_u8(self.reason_code)?;
buff_writer.write_variable_byte_int(self.property_len)?;
buff_writer.write_properties::<MAX_PROPERTIES>(&self.properties)?;
Ok(buff_writer.position)
}
fn decode(&mut self, buff_reader: &mut BuffReader<'a>) -> Result<(), BufferError> {
if self.decode_fixed_header(buff_reader)? != (PacketType::Pubrel).into() {
log::error!("Packet you are trying to decode is not PUBREL packet!");
return Err(BufferError::PacketTypeMismatch);
}
self.packet_identifier = buff_reader.read_u16()?;
self.reason_code = buff_reader.read_u8()?;
return self.decode_properties(buff_reader);
}
fn set_property_len(&mut self, value: u32) {
self.property_len = value;
}
fn get_property_len(&mut self) -> u32 {
return self.property_len;
}
fn push_to_properties(&mut self, property: Property<'a>) {
self.properties.push(property);
}
fn property_allowed(&mut self, property: &Property<'a>) -> bool {
property.pubrel_property()
}
fn set_fixed_header(&mut self, header: u8) {
self.fixed_header = header;
}
fn set_remaining_len(&mut self, remaining_len: u32) {
self.remain_len = remaining_len;
}
}

View File

@@ -0,0 +1,241 @@
/*
* MIT License
*
* Copyright (c) [2022] [Ondrej Babec <ond.babec@gmail.com>]
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
use core::fmt::{Display, Formatter};
#[derive(Debug, PartialEq)]
pub enum ReasonCode {
Success,
GrantedQoS1,
GrantedQoS2,
DisconnectWithWillMessage,
NoMatchingSubscribers,
NoSubscriptionExisted,
ContinueAuth,
ReAuthenticate,
UnspecifiedError,
MalformedPacket,
ProtocolError,
ImplementationSpecificError,
UnsupportedProtocolVersion,
ClientIdNotValid,
BadUserNameOrPassword,
NotAuthorized,
ServerUnavailable,
ServerBusy,
Banned,
ServerShuttingDown,
BadAuthMethod,
KeepAliveTimeout,
SessionTakeOver,
TopicFilterInvalid,
TopicNameInvalid,
PacketIdentifierInUse,
PacketIdentifierNotFound,
ReceiveMaximumExceeded,
TopicAliasInvalid,
PacketTooLarge,
MessageRateTooHigh,
QuotaExceeded,
AdministrativeAction,
PayloadFormatInvalid,
RetainNotSupported,
QoSNotSupported,
UseAnotherServer,
ServerMoved,
SharedSubscriptionNotSupported,
ConnectionRateExceeded,
MaximumConnectTime,
SubscriptionIdentifiersNotSupported,
WildcardSubscriptionNotSupported,
TimerNotSupported,
BuffError,
NetworkError,
}
impl Into<u8> for ReasonCode {
fn into(self) -> u8 {
return match self {
ReasonCode::Success => 0x00,
ReasonCode::GrantedQoS1 => 0x01,
ReasonCode::GrantedQoS2 => 0x02,
ReasonCode::DisconnectWithWillMessage => 0x04,
ReasonCode::NoMatchingSubscribers => 0x10,
ReasonCode::NoSubscriptionExisted => 0x11,
ReasonCode::ContinueAuth => 0x18,
ReasonCode::ReAuthenticate => 0x19,
ReasonCode::UnspecifiedError => 0x80,
ReasonCode::MalformedPacket => 0x81,
ReasonCode::ProtocolError => 0x82,
ReasonCode::ImplementationSpecificError => 0x83,
ReasonCode::UnsupportedProtocolVersion => 0x84,
ReasonCode::ClientIdNotValid => 0x85,
ReasonCode::BadUserNameOrPassword => 0x86,
ReasonCode::NotAuthorized => 0x87,
ReasonCode::ServerUnavailable => 0x88,
ReasonCode::ServerBusy => 0x89,
ReasonCode::Banned => 0x8A,
ReasonCode::ServerShuttingDown => 0x8B,
ReasonCode::BadAuthMethod => 0x8C,
ReasonCode::KeepAliveTimeout => 0x8D,
ReasonCode::SessionTakeOver => 0x8E,
ReasonCode::TopicFilterInvalid => 0x8F,
ReasonCode::TopicNameInvalid => 0x90,
ReasonCode::PacketIdentifierInUse => 0x91,
ReasonCode::PacketIdentifierNotFound => 0x92,
ReasonCode::ReceiveMaximumExceeded => 0x93,
ReasonCode::TopicAliasInvalid => 0x94,
ReasonCode::PacketTooLarge => 0x95,
ReasonCode::MessageRateTooHigh => 0x96,
ReasonCode::QuotaExceeded => 0x97,
ReasonCode::AdministrativeAction => 0x98,
ReasonCode::PayloadFormatInvalid => 0x99,
ReasonCode::RetainNotSupported => 0x9A,
ReasonCode::QoSNotSupported => 0x9B,
ReasonCode::UseAnotherServer => 0x9C,
ReasonCode::ServerMoved => 0x9D,
ReasonCode::SharedSubscriptionNotSupported => 0x9E,
ReasonCode::ConnectionRateExceeded => 0x9F,
ReasonCode::MaximumConnectTime => 0xA0,
ReasonCode::SubscriptionIdentifiersNotSupported => 0xA1,
ReasonCode::WildcardSubscriptionNotSupported => 0xA2,
ReasonCode::TimerNotSupported => 0xFD,
ReasonCode::BuffError => 0xFE,
ReasonCode::NetworkError => 0xFF,
};
}
}
impl From<u8> for ReasonCode {
fn from(orig: u8) -> Self {
return match orig {
0x00 => ReasonCode::Success,
0x01 => ReasonCode::GrantedQoS1,
0x02 => ReasonCode::GrantedQoS2,
0x04 => ReasonCode::DisconnectWithWillMessage,
0x10 => ReasonCode::NoMatchingSubscribers,
0x11 => ReasonCode::NoSubscriptionExisted,
0x18 => ReasonCode::ContinueAuth,
0x19 => ReasonCode::ReAuthenticate,
0x80 => ReasonCode::UnspecifiedError,
0x81 => ReasonCode::MalformedPacket,
0x82 => ReasonCode::ProtocolError,
0x83 => ReasonCode::ImplementationSpecificError,
0x84 => ReasonCode::UnsupportedProtocolVersion,
0x85 => ReasonCode::ClientIdNotValid,
0x86 => ReasonCode::BadUserNameOrPassword,
0x87 => ReasonCode::NotAuthorized,
0x88 => ReasonCode::ServerUnavailable,
0x89 => ReasonCode::ServerBusy,
0x8A => ReasonCode::Banned,
0x8B => ReasonCode::ServerShuttingDown,
0x8C => ReasonCode::BadAuthMethod,
0x8D => ReasonCode::KeepAliveTimeout,
0x8E => ReasonCode::SessionTakeOver,
0x8F => ReasonCode::TopicFilterInvalid,
0x90 => ReasonCode::TopicNameInvalid,
0x91 => ReasonCode::PacketIdentifierInUse,
0x92 => ReasonCode::PacketIdentifierNotFound,
0x93 => ReasonCode::ReceiveMaximumExceeded,
0x94 => ReasonCode::TopicAliasInvalid,
0x95 => ReasonCode::PacketTooLarge,
0x96 => ReasonCode::MessageRateTooHigh,
0x97 => ReasonCode::QuotaExceeded,
0x98 => ReasonCode::AdministrativeAction,
0x99 => ReasonCode::PayloadFormatInvalid,
0x9A => ReasonCode::RetainNotSupported,
0x9B => ReasonCode::QoSNotSupported,
0x9C => ReasonCode::UseAnotherServer,
0x9D => ReasonCode::ServerMoved,
0x9E => ReasonCode::SharedSubscriptionNotSupported,
0xA0 => ReasonCode::MaximumConnectTime,
0xA1 => ReasonCode::SubscriptionIdentifiersNotSupported,
0xA2 => ReasonCode::WildcardSubscriptionNotSupported,
0xFD => ReasonCode::TimerNotSupported,
0xFE => ReasonCode::BuffError,
_ => ReasonCode::NetworkError,
};
}
}
impl Display for ReasonCode {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
match *self {
ReasonCode::Success => write!(f, "Operation was successful!"),
ReasonCode::GrantedQoS1 => write!(f, "Granted QoS level 1!"),
ReasonCode::GrantedQoS2 => write!(f, "Granted QoS level 2!"),
ReasonCode::DisconnectWithWillMessage => write!(f, "Disconnected with Will message!"),
ReasonCode::NoMatchingSubscribers => write!(f, "No matching subscribers on broker!"),
ReasonCode::NoSubscriptionExisted => write!(f, "Subscription not exist!"),
ReasonCode::ContinueAuth => write!(f, "Broker asks for more AUTH packets!"),
ReasonCode::ReAuthenticate => write!(f, "Broker requires re-authentication!"),
ReasonCode::UnspecifiedError => write!(f, "Unspecified error!"),
ReasonCode::MalformedPacket => write!(f, "Malformed packet sent!"),
ReasonCode::ProtocolError => write!(f, "Protocol specific error!"),
ReasonCode::ImplementationSpecificError => write!(f, "Implementation specific error!"),
ReasonCode::UnsupportedProtocolVersion => write!(f, "Unsupported protocol version!"),
ReasonCode::ClientIdNotValid => write!(f, "Client sent not valid identification"),
ReasonCode::BadUserNameOrPassword => {
write!(f, "Authentication error, username of password not valid!")
}
ReasonCode::NotAuthorized => write!(f, "Client not authorized!"),
ReasonCode::ServerUnavailable => write!(f, "Server unavailable!"),
ReasonCode::ServerBusy => write!(f, "Server is busy!"),
ReasonCode::Banned => write!(f, "Client is banned on broker!"),
ReasonCode::ServerShuttingDown => write!(f, "Server is shutting down!"),
ReasonCode::BadAuthMethod => write!(f, "Provided bad authentication method!"),
ReasonCode::KeepAliveTimeout => write!(f, "Client reached timeout"),
ReasonCode::SessionTakeOver => write!(f, "Took over session!"),
ReasonCode::TopicFilterInvalid => write!(f, "Topic filter is not valid!"),
ReasonCode::TopicNameInvalid => write!(f, "Topic name is not valid!"),
ReasonCode::PacketIdentifierInUse => write!(f, "Packet identifier is already in use!"),
ReasonCode::PacketIdentifierNotFound => write!(f, "Packet identifier not found!"),
ReasonCode::ReceiveMaximumExceeded => write!(f, "Maximum receive amount exceeded!"),
ReasonCode::TopicAliasInvalid => write!(f, "Invalid topic alias!"),
ReasonCode::PacketTooLarge => write!(f, "Sent packet was too large!"),
ReasonCode::MessageRateTooHigh => write!(f, "Message rate is too high!"),
ReasonCode::QuotaExceeded => write!(f, "Quota exceeded!"),
ReasonCode::AdministrativeAction => write!(f, "Administrative action!"),
ReasonCode::PayloadFormatInvalid => write!(f, "Invalid payload format!"),
ReasonCode::RetainNotSupported => write!(f, "Message retain not supported!"),
ReasonCode::QoSNotSupported => write!(f, "Used QoS is not supported!"),
ReasonCode::UseAnotherServer => write!(f, "Use another server!"),
ReasonCode::ServerMoved => write!(f, "Server moved!"),
ReasonCode::SharedSubscriptionNotSupported => {
write!(f, "Shared subscription is not supported")
}
ReasonCode::ConnectionRateExceeded => write!(f, "Connection rate exceeded!"),
ReasonCode::MaximumConnectTime => write!(f, "Maximum connect time exceeded!"),
ReasonCode::SubscriptionIdentifiersNotSupported => {
write!(f, "Subscription identifier not supported!")
}
ReasonCode::WildcardSubscriptionNotSupported => {
write!(f, "Wildcard subscription not supported!")
}
ReasonCode::TimerNotSupported => write!(f, "Timer implementation is not provided"),
ReasonCode::BuffError => write!(f, "Error encountered during write / read from packet"),
ReasonCode::NetworkError => write!(f, "Unknown error!"),
}
}
}

View File

@@ -0,0 +1,120 @@
/*
* MIT License
*
* Copyright (c) [2022] [Ondrej Babec <ond.babec@gmail.com>]
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
use crate::encoding::variable_byte_integer::VariableByteIntegerEncoder;
use heapless::Vec;
use crate::packet::v5::mqtt_packet::Packet;
use crate::utils::buffer_reader::BuffReader;
use crate::utils::types::BufferError;
use super::packet_type::PacketType;
use super::property::Property;
pub struct SubackPacket<'a, const MAX_REASONS: usize, const MAX_PROPERTIES: usize> {
pub fixed_header: u8,
pub remain_len: u32,
pub packet_identifier: u16,
pub property_len: u32,
pub properties: Vec<Property<'a>, MAX_PROPERTIES>,
pub reason_codes: Vec<u8, MAX_REASONS>,
}
impl<'a, const MAX_REASONS: usize, const MAX_PROPERTIES: usize>
SubackPacket<'a, MAX_REASONS, MAX_PROPERTIES>
{
pub fn read_reason_codes(
&mut self,
buff_reader: &mut BuffReader<'a>,
) -> Result<(), BufferError> {
let rm_ln_ln = VariableByteIntegerEncoder::len(
VariableByteIntegerEncoder::encode(self.remain_len).unwrap(),
);
let max = self.remain_len as usize + rm_ln_ln + 1;
if buff_reader.position >= max {
return Ok(());
}
loop {
self.reason_codes.push(buff_reader.read_u8()?);
if buff_reader.position == max {
break;
}
}
return Ok(());
}
}
impl<'a, const MAX_REASONS: usize, const MAX_PROPERTIES: usize> Packet<'a>
for SubackPacket<'a, MAX_REASONS, MAX_PROPERTIES>
{
fn new() -> Self {
Self {
fixed_header: PacketType::Suback.into(),
remain_len: 0,
packet_identifier: 0,
property_len: 0,
properties: Vec::<Property<'a>, MAX_PROPERTIES>::new(),
reason_codes: Vec::<u8, MAX_REASONS>::new(),
}
}
fn encode(&mut self, _buffer: &mut [u8], _buffer_len: usize) -> Result<usize, BufferError> {
log::error!("SUBACK packet does not support encoding!");
return Err(BufferError::WrongPacketToEncode);
}
fn decode(&mut self, buff_reader: &mut BuffReader<'a>) -> Result<(), BufferError> {
if self.decode_fixed_header(buff_reader)? != (PacketType::Suback).into() {
log::error!("Packet you are trying to decode is not SUBACK packet!");
return Err(BufferError::PacketTypeMismatch);
}
self.packet_identifier = buff_reader.read_u16()?;
self.decode_properties(buff_reader)?;
return self.read_reason_codes(buff_reader);
}
fn set_property_len(&mut self, value: u32) {
self.property_len = value;
}
fn get_property_len(&mut self) -> u32 {
return self.property_len;
}
fn push_to_properties(&mut self, property: Property<'a>) {
self.properties.push(property);
}
fn property_allowed(&mut self, property: &Property<'a>) -> bool {
property.suback_property()
}
fn set_fixed_header(&mut self, header: u8) {
self.fixed_header = header;
}
fn set_remaining_len(&mut self, remaining_len: u32) {
self.remain_len = remaining_len;
}
}

View File

@@ -0,0 +1,135 @@
/*
* MIT License
*
* Copyright (c) [2022] [Ondrej Babec <ond.babec@gmail.com>]
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
use heapless::Vec;
use super::packet_type::PacketType;
use super::property::Property;
use crate::encoding::variable_byte_integer::VariableByteIntegerEncoder;
use crate::packet::v5::mqtt_packet::Packet;
use crate::packet::v5::publish_packet::QualityOfService;
use crate::utils::buffer_reader::BuffReader;
use crate::utils::buffer_writer::BuffWriter;
use crate::utils::types::{BufferError, TopicFilter};
pub struct SubscriptionPacket<'a, const MAX_FILTERS: usize, const MAX_PROPERTIES: usize> {
pub fixed_header: u8,
pub remain_len: u32,
pub packet_identifier: u16,
pub property_len: u32,
pub properties: Vec<Property<'a>, MAX_PROPERTIES>,
pub topic_filter_len: u16,
pub topic_filters: Vec<TopicFilter<'a>, MAX_FILTERS>,
}
impl<'a, const MAX_FILTERS: usize, const MAX_PROPERTIES: usize>
SubscriptionPacket<'a, MAX_FILTERS, MAX_PROPERTIES>
{
pub fn add_new_filter(&mut self, topic_name: &'a str, qos: QualityOfService) {
let len = topic_name.len();
let mut new_filter = TopicFilter::new();
new_filter.filter.string = topic_name;
new_filter.filter.len = len as u16;
new_filter.sub_options =
new_filter.sub_options | (<QualityOfService as Into<u8>>::into(qos) >> 1);
self.topic_filters.push(new_filter);
self.topic_filter_len = self.topic_filter_len + 1;
}
}
impl<'a, const MAX_FILTERS: usize, const MAX_PROPERTIES: usize> Packet<'a>
for SubscriptionPacket<'a, MAX_FILTERS, MAX_PROPERTIES>
{
fn new() -> Self {
let x = Self {
fixed_header: PacketType::Subscribe.into(),
remain_len: 0,
packet_identifier: 1,
property_len: 0,
properties: Vec::<Property<'a>, MAX_PROPERTIES>::new(),
topic_filter_len: 0,
topic_filters: Vec::<TopicFilter<'a>, MAX_FILTERS>::new(),
};
return x;
}
fn encode(&mut self, buffer: &mut [u8], buffer_len: usize) -> Result<usize, BufferError> {
let mut buff_writer = BuffWriter::new(buffer, buffer_len);
let mut rm_ln = self.property_len;
let property_len_enc: [u8; 4] = VariableByteIntegerEncoder::encode(self.property_len)?;
let property_len_len = VariableByteIntegerEncoder::len(property_len_enc);
let mut lt = 0;
let mut filters_len = 0;
loop {
filters_len = filters_len + self.topic_filters.get(lt).unwrap().filter.len + 3;
lt = lt + 1;
if lt == self.topic_filter_len as usize {
break;
}
}
rm_ln = rm_ln + property_len_len as u32 + 2 + filters_len as u32;
buff_writer.write_u8(self.fixed_header)?;
buff_writer.write_variable_byte_int(rm_ln)?;
buff_writer.write_u16(self.packet_identifier)?;
buff_writer.write_variable_byte_int(self.property_len)?;
buff_writer.write_properties::<MAX_PROPERTIES>(&self.properties)?;
buff_writer.write_topic_filters_ref(
true,
self.topic_filter_len as usize,
&self.topic_filters,
)?;
Ok(buff_writer.position)
}
fn decode(&mut self, _buff_reader: &mut BuffReader<'a>) -> Result<(), BufferError> {
log::error!("Subscribe packet does not support decode funtion on client!");
Err(BufferError::WrongPacketToDecode)
}
fn set_property_len(&mut self, value: u32) {
self.property_len = value;
}
fn get_property_len(&mut self) -> u32 {
return self.property_len;
}
fn push_to_properties(&mut self, property: Property<'a>) {
self.properties.push(property);
}
fn property_allowed(&mut self, property: &Property<'a>) -> bool {
property.subscribe_property()
}
fn set_fixed_header(&mut self, header: u8) {
self.fixed_header = header;
}
fn set_remaining_len(&mut self, remaining_len: u32) {
self.remain_len = remaining_len;
}
}

View File

@@ -0,0 +1,114 @@
/*
* MIT License
*
* Copyright (c) [2022] [Ondrej Babec <ond.babec@gmail.com>]
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
use heapless::Vec;
use crate::packet::v5::mqtt_packet::Packet;
use crate::utils::buffer_reader::BuffReader;
use crate::utils::types::BufferError;
use super::packet_type::PacketType;
use super::property::Property;
pub struct UnsubackPacket<'a, const MAX_REASONS: usize, const MAX_PROPERTIES: usize> {
pub fixed_header: u8,
pub remain_len: u32,
pub packet_identifier: u16,
pub property_len: u32,
pub properties: Vec<Property<'a>, MAX_PROPERTIES>,
pub reason_codes: Vec<u8, MAX_REASONS>,
}
impl<'a, const MAX_REASONS: usize, const MAX_PROPERTIES: usize>
UnsubackPacket<'a, MAX_REASONS, MAX_PROPERTIES>
{
pub fn read_reason_codes(
&mut self,
buff_reader: &mut BuffReader<'a>,
) -> Result<(), BufferError> {
let mut i = 0;
loop {
self.reason_codes.push(buff_reader.read_u8()?);
i = i + 1;
if i == MAX_REASONS {
break;
}
}
Ok(())
}
}
impl<'a, const MAX_REASONS: usize, const MAX_PROPERTIES: usize> Packet<'a>
for UnsubackPacket<'a, MAX_REASONS, MAX_PROPERTIES>
{
fn new() -> Self {
Self {
fixed_header: PacketType::Unsuback.into(),
remain_len: 0,
packet_identifier: 0,
property_len: 0,
properties: Vec::<Property<'a>, MAX_PROPERTIES>::new(),
reason_codes: Vec::<u8, MAX_REASONS>::new(),
}
}
fn encode(&mut self, _buffer: &mut [u8], _buffer_len: usize) -> Result<usize, BufferError> {
log::error!("UNSUBACK packet does not support encoding!");
Err(BufferError::WrongPacketToEncode)
}
fn decode(&mut self, buff_reader: &mut BuffReader<'a>) -> Result<(), BufferError> {
if self.decode_fixed_header(buff_reader)? != (PacketType::Unsuback).into() {
log::error!("Packet you are trying to decode is not UNSUBACK packet!");
return Err(BufferError::PacketTypeMismatch);
}
self.packet_identifier = buff_reader.read_u16()?;
self.decode_properties(buff_reader)?;
return self.read_reason_codes(buff_reader);
}
fn set_property_len(&mut self, value: u32) {
self.property_len = value;
}
fn get_property_len(&mut self) -> u32 {
return self.property_len;
}
fn push_to_properties(&mut self, property: Property<'a>) {
self.properties.push(property);
}
fn property_allowed(&mut self, property: &Property<'a>) -> bool {
property.unsuback_property()
}
fn set_fixed_header(&mut self, header: u8) {
self.fixed_header = header;
}
fn set_remaining_len(&mut self, remaining_len: u32) {
self.remain_len = remaining_len;
}
}

View File

@@ -0,0 +1,135 @@
/*
* MIT License
*
* Copyright (c) [2022] [Ondrej Babec <ond.babec@gmail.com>]
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
use heapless::Vec;
use crate::encoding::variable_byte_integer::VariableByteIntegerEncoder;
use crate::packet::v5::mqtt_packet::Packet;
use crate::packet::v5::publish_packet::QualityOfService;
use crate::utils::buffer_reader::BuffReader;
use crate::utils::buffer_writer::BuffWriter;
use crate::utils::types::{BufferError, TopicFilter};
use super::property::Property;
pub struct UnsubscriptionPacket<'a, const MAX_FILTERS: usize, const MAX_PROPERTIES: usize> {
pub fixed_header: u8,
pub remain_len: u32,
pub packet_identifier: u16,
pub property_len: u32,
pub properties: Vec<Property<'a>, MAX_PROPERTIES>,
pub topic_filter_len: u16,
pub topic_filters: Vec<TopicFilter<'a>, MAX_FILTERS>,
}
impl<'a, const MAX_FILTERS: usize, const MAX_PROPERTIES: usize>
UnsubscriptionPacket<'a, MAX_FILTERS, MAX_PROPERTIES>
{
pub fn add_new_filter(&mut self, topic_name: &'a str, qos: QualityOfService) {
let len = topic_name.len();
let mut new_filter = TopicFilter::new();
new_filter.filter.string = topic_name;
new_filter.filter.len = len as u16;
new_filter.sub_options =
new_filter.sub_options | (<QualityOfService as Into<u8>>::into(qos) >> 1);
self.topic_filters.push(new_filter);
self.topic_filter_len = self.topic_filter_len + 1;
}
}
impl<'a, const MAX_FILTERS: usize, const MAX_PROPERTIES: usize> Packet<'a>
for UnsubscriptionPacket<'a, MAX_FILTERS, MAX_PROPERTIES>
{
fn new() -> Self {
Self {
fixed_header: 0,
remain_len: 0,
packet_identifier: 0,
property_len: 0,
properties: Vec::<Property<'a>, MAX_PROPERTIES>::new(),
topic_filter_len: 0,
topic_filters: Vec::<TopicFilter<'a>, MAX_FILTERS>::new(),
}
}
fn encode(&mut self, buffer: &mut [u8], buffer_len: usize) -> Result<usize, BufferError> {
let mut buff_writer = BuffWriter::new(buffer, buffer_len);
let mut rm_ln = self.property_len;
let property_len_enc: [u8; 4] = VariableByteIntegerEncoder::encode(self.property_len)?;
let property_len_len = VariableByteIntegerEncoder::len(property_len_enc);
let mut lt = 0;
let mut filters_len = 0;
loop {
filters_len = filters_len + self.topic_filters.get(lt).unwrap().filter.len + 2;
lt = lt + 1;
if lt == self.topic_filter_len as usize {
break;
}
}
rm_ln = rm_ln + property_len_len as u32 + 2 + filters_len as u32;
buff_writer.write_u8(self.fixed_header)?;
buff_writer.write_variable_byte_int(rm_ln)?;
buff_writer.write_u16(self.packet_identifier)?;
buff_writer.write_variable_byte_int(self.property_len)?;
buff_writer.write_properties::<MAX_PROPERTIES>(&self.properties)?;
buff_writer.write_topic_filters_ref(
false,
self.topic_filter_len as usize,
&self.topic_filters,
)?;
Ok(buff_writer.position)
}
fn decode(&mut self, _buff_reader: &mut BuffReader<'a>) -> Result<(), BufferError> {
log::error!("Unsubscribe packet does not support decode funtion on client!");
Err(BufferError::WrongPacketToDecode)
}
fn set_property_len(&mut self, value: u32) {
self.property_len = value;
}
fn get_property_len(&mut self) -> u32 {
return self.property_len;
}
fn push_to_properties(&mut self, property: Property<'a>) {
self.properties.push(property);
}
fn property_allowed(&mut self, property: &Property<'a>) -> bool {
property.unsubscribe_property()
}
fn set_fixed_header(&mut self, header: u8) {
self.fixed_header = header;
}
fn set_remaining_len(&mut self, remaining_len: u32) {
self.remain_len = remaining_len;
}
}