Rust MQTT
This commit is contained in:
91
mqtt/src/client/client_config.rs
Normal file
91
mqtt/src/client/client_config.rs
Normal file
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* 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::property::Property;
|
||||
use crate::packet::v5::publish_packet::QualityOfService;
|
||||
use crate::utils::types::{BinaryData, EncodedString};
|
||||
use heapless::Vec;
|
||||
|
||||
pub struct ClientConfig<'a, const MAX_PROPERTIES: usize> {
|
||||
pub qos: QualityOfService,
|
||||
pub keep_alive: u16,
|
||||
pub client_id: EncodedString<'a>,
|
||||
pub username_flag: bool,
|
||||
pub username: EncodedString<'a>,
|
||||
pub password_flag: bool,
|
||||
pub password: BinaryData<'a>,
|
||||
pub properties: Vec<Property<'a>, MAX_PROPERTIES>,
|
||||
pub max_packet_size: u32,
|
||||
}
|
||||
|
||||
impl<'a, const MAX_PROPERTIES: usize> ClientConfig<'a, MAX_PROPERTIES> {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
qos: QualityOfService::QoS0,
|
||||
keep_alive: 60,
|
||||
client_id: EncodedString::new(),
|
||||
username_flag: false,
|
||||
username: EncodedString::new(),
|
||||
password_flag: false,
|
||||
password: BinaryData::new(),
|
||||
properties: Vec::<Property<'a>, MAX_PROPERTIES>::new(),
|
||||
max_packet_size: 265_000,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_qos(&mut self, qos: QualityOfService) {
|
||||
self.qos = qos;
|
||||
}
|
||||
|
||||
pub fn add_username(&mut self, username: &'a str) {
|
||||
let mut username_s: EncodedString = EncodedString::new();
|
||||
username_s.string = username;
|
||||
username_s.len = username.len() as u16;
|
||||
self.username_flag = true;
|
||||
self.username = username_s;
|
||||
}
|
||||
|
||||
pub fn add_password(&mut self, password: &'a str) {
|
||||
let mut password_s: BinaryData = BinaryData::new();
|
||||
password_s.bin = password.as_bytes();
|
||||
password_s.len = password_s.bin.len() as u16;
|
||||
self.password = password_s;
|
||||
self.password_flag = true;
|
||||
}
|
||||
|
||||
pub fn add_property(&mut self, prop: Property<'a>) {
|
||||
if self.properties.len() < MAX_PROPERTIES {
|
||||
self.properties.push(prop);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_max_packet_size_as_prop(&mut self) -> u32 {
|
||||
if self.properties.len() < MAX_PROPERTIES {
|
||||
let prop = Property::MaximumPacketSize(self.max_packet_size);
|
||||
self.properties.push(prop);
|
||||
return 5;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
353
mqtt/src/client/client_v5.rs
Normal file
353
mqtt/src/client/client_v5.rs
Normal file
@@ -0,0 +1,353 @@
|
||||
/*
|
||||
* 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::client::client_config::ClientConfig;
|
||||
use crate::network::network_trait::NetworkConnection;
|
||||
use crate::packet::v5::connack_packet::ConnackPacket;
|
||||
use crate::packet::v5::connect_packet::ConnectPacket;
|
||||
use crate::packet::v5::disconnect_packet::DisconnectPacket;
|
||||
use crate::packet::v5::mqtt_packet::Packet;
|
||||
use crate::packet::v5::pingreq_packet::PingreqPacket;
|
||||
use crate::packet::v5::pingresp_packet::PingrespPacket;
|
||||
use crate::packet::v5::puback_packet::PubackPacket;
|
||||
use crate::packet::v5::publish_packet::QualityOfService::QoS1;
|
||||
use crate::packet::v5::publish_packet::{PublishPacket, QualityOfService};
|
||||
use crate::packet::v5::reason_codes::ReasonCode;
|
||||
use crate::packet::v5::suback_packet::SubackPacket;
|
||||
use crate::packet::v5::subscription_packet::SubscriptionPacket;
|
||||
use crate::utils::buffer_reader::BuffReader;
|
||||
use crate::utils::rng_generator::CountingRng;
|
||||
use crate::utils::types::BufferError;
|
||||
use heapless::Vec;
|
||||
use rand_core::RngCore;
|
||||
|
||||
pub struct MqttClientV5<'a, T, const MAX_PROPERTIES: usize> {
|
||||
network_driver: &'a mut T,
|
||||
buffer: &'a mut [u8],
|
||||
buffer_len: usize,
|
||||
recv_buffer: &'a mut [u8],
|
||||
recv_buffer_len: usize,
|
||||
rng: CountingRng,
|
||||
config: ClientConfig<'a, MAX_PROPERTIES>,
|
||||
}
|
||||
|
||||
impl<'a, T, const MAX_PROPERTIES: usize> MqttClientV5<'a, T, MAX_PROPERTIES>
|
||||
where
|
||||
T: NetworkConnection,
|
||||
{
|
||||
pub fn new(
|
||||
network_driver: &'a mut T,
|
||||
buffer: &'a mut [u8],
|
||||
buffer_len: usize,
|
||||
recv_buffer: &'a mut [u8],
|
||||
recv_buffer_len: usize,
|
||||
config: ClientConfig<'a, MAX_PROPERTIES>,
|
||||
) -> Self {
|
||||
Self {
|
||||
network_driver,
|
||||
buffer,
|
||||
buffer_len,
|
||||
recv_buffer,
|
||||
recv_buffer_len,
|
||||
rng: CountingRng(50),
|
||||
config,
|
||||
}
|
||||
}
|
||||
|
||||
// Muze prijit disconnect kvuli male velikosti packetu
|
||||
pub async fn connect_to_broker<'b>(&'b mut self) -> Result<(), ReasonCode> {
|
||||
let len = {
|
||||
let mut connect = ConnectPacket::<'b, MAX_PROPERTIES, 0>::new();
|
||||
connect.keep_alive = self.config.keep_alive;
|
||||
self.config.add_max_packet_size_as_prop();
|
||||
connect.property_len = connect.add_properties(&self.config.properties);
|
||||
if self.config.username_flag {
|
||||
connect.add_username(&self.config.username);
|
||||
}
|
||||
if self.config.password_flag {
|
||||
connect.add_password(&self.config.password)
|
||||
}
|
||||
connect.encode(self.buffer, self.buffer_len)
|
||||
};
|
||||
|
||||
if let Err(err) = len {
|
||||
log::error!("[DECODE ERR]: {}", err);
|
||||
return Err(ReasonCode::BuffError);
|
||||
}
|
||||
self.network_driver.send(self.buffer, len.unwrap()).await?;
|
||||
|
||||
//connack
|
||||
let reason: Result<u8, BufferError> = {
|
||||
self.network_driver.receive(self.buffer).await?;
|
||||
let mut packet = ConnackPacket::<'b, 5>::new();
|
||||
if let Err(err) = packet.decode(&mut BuffReader::new(self.buffer, self.buffer_len)) {
|
||||
if err == BufferError::PacketTypeMismatch {
|
||||
let mut disc = DisconnectPacket::<'b, 5>::new();
|
||||
if disc
|
||||
.decode(&mut BuffReader::new(self.buffer, self.buffer_len))
|
||||
.is_ok()
|
||||
{
|
||||
log::error!("Client was disconnected with reason: ");
|
||||
return Err(ReasonCode::from(disc.disconnect_reason));
|
||||
}
|
||||
}
|
||||
Err(err)
|
||||
} else {
|
||||
Ok(packet.connect_reason_code)
|
||||
}
|
||||
};
|
||||
|
||||
if let Err(err) = reason {
|
||||
log::error!("[DECODE ERR]: {}", err);
|
||||
return Err(ReasonCode::BuffError);
|
||||
}
|
||||
let res = reason.unwrap();
|
||||
if res != 0x00 {
|
||||
return Err(ReasonCode::from(res));
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn disconnect<'b>(&'b mut self) -> Result<(), ReasonCode> {
|
||||
let mut disconnect = DisconnectPacket::<'b, 5>::new();
|
||||
let len = disconnect.encode(self.buffer, self.buffer_len);
|
||||
if let Err(err) = len {
|
||||
log::error!("[DECODE ERR]: {}", err);
|
||||
return Err(ReasonCode::BuffError);
|
||||
}
|
||||
self.network_driver.send(self.buffer, len.unwrap()).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn send_message<'b>(
|
||||
&'b mut self,
|
||||
topic_name: &'b str,
|
||||
message: &'b str,
|
||||
) -> Result<(), ReasonCode> {
|
||||
let identifier: u16 = self.rng.next_u32() as u16;
|
||||
let len = {
|
||||
let mut packet = PublishPacket::<'b, 5>::new();
|
||||
packet.add_topic_name(topic_name);
|
||||
packet.add_qos(self.config.qos);
|
||||
packet.add_identifier(identifier);
|
||||
packet.add_message(message.as_bytes());
|
||||
packet.encode(self.buffer, self.buffer_len)
|
||||
};
|
||||
|
||||
if let Err(err) = len {
|
||||
log::error!("[DECODE ERR]: {}", err);
|
||||
return Err(ReasonCode::BuffError);
|
||||
}
|
||||
|
||||
self.network_driver.send(self.buffer, len.unwrap()).await?;
|
||||
|
||||
//QoS1
|
||||
if <QualityOfService as Into<u8>>::into(self.config.qos)
|
||||
== <QualityOfService as Into<u8>>::into(QoS1)
|
||||
{
|
||||
let reason: Result<[u16; 2], BufferError> = {
|
||||
self.network_driver.receive(self.buffer).await?;
|
||||
let mut packet = PubackPacket::<'b, 5>::new();
|
||||
if let Err(err) = packet.decode(&mut BuffReader::new(self.buffer, self.buffer_len))
|
||||
{
|
||||
Err(err)
|
||||
} else {
|
||||
Ok([packet.packet_identifier, packet.reason_code as u16])
|
||||
}
|
||||
};
|
||||
|
||||
if let Err(err) = reason {
|
||||
log::error!("[DECODE ERR]: {}", err);
|
||||
return Err(ReasonCode::BuffError);
|
||||
}
|
||||
|
||||
let res = reason.unwrap();
|
||||
if identifier != res[0] {
|
||||
return Err(ReasonCode::PacketIdentifierNotFound);
|
||||
}
|
||||
|
||||
if res[1] != 0 {
|
||||
return Err(ReasonCode::from(res[1] as u8));
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn subscribe_to_topics<'b, const TOPICS: usize>(
|
||||
&'b mut self,
|
||||
topic_names: &'b Vec<&'b str, TOPICS>,
|
||||
) -> Result<(), ReasonCode> {
|
||||
let len = {
|
||||
let mut subs = SubscriptionPacket::<'b, TOPICS, 1>::new();
|
||||
let mut i = 0;
|
||||
loop {
|
||||
if i == TOPICS {
|
||||
break;
|
||||
}
|
||||
subs.add_new_filter(topic_names.get(i).unwrap(), self.config.qos);
|
||||
i = i + 1;
|
||||
}
|
||||
subs.encode(self.buffer, self.buffer_len)
|
||||
};
|
||||
|
||||
if let Err(err) = len {
|
||||
log::error!("[DECODE ERR]: {}", err);
|
||||
return Err(ReasonCode::BuffError);
|
||||
}
|
||||
|
||||
self.network_driver.send(self.buffer, len.unwrap()).await?;
|
||||
|
||||
let reason: Result<Vec<u8, TOPICS>, BufferError> = {
|
||||
self.network_driver.receive(self.buffer).await?;
|
||||
|
||||
let mut packet = SubackPacket::<'b, TOPICS, 5>::new();
|
||||
if let Err(err) = packet.decode(&mut BuffReader::new(self.buffer, self.buffer_len)) {
|
||||
Err(err)
|
||||
} else {
|
||||
Ok(packet.reason_codes)
|
||||
}
|
||||
};
|
||||
|
||||
if let Err(err) = reason {
|
||||
log::error!("[DECODE ERR]: {}", err);
|
||||
return Err(ReasonCode::BuffError);
|
||||
}
|
||||
let reasons = reason.unwrap();
|
||||
let mut i = 0;
|
||||
loop {
|
||||
if i == TOPICS {
|
||||
break;
|
||||
}
|
||||
if *reasons.get(i).unwrap() != QualityOfService::into(self.config.qos) {
|
||||
return Err(ReasonCode::from(*reasons.get(i).unwrap()));
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn subscribe_to_topic<'b>(
|
||||
&'b mut self,
|
||||
topic_name: &'b str,
|
||||
) -> Result<(), ReasonCode> {
|
||||
let len = {
|
||||
let mut subs = SubscriptionPacket::<'b, 1, 1>::new();
|
||||
subs.add_new_filter(topic_name, self.config.qos);
|
||||
subs.encode(self.buffer, self.buffer_len)
|
||||
};
|
||||
|
||||
if let Err(err) = len {
|
||||
log::error!("[DECODE ERR]: {}", err);
|
||||
return Err(ReasonCode::BuffError);
|
||||
}
|
||||
|
||||
self.network_driver.send(self.buffer, len.unwrap()).await?;
|
||||
|
||||
let reason: Result<u8, BufferError> = {
|
||||
self.network_driver.receive(self.buffer).await?;
|
||||
|
||||
let mut packet = SubackPacket::<'b, 5, 5>::new();
|
||||
if let Err(err) = packet.decode(&mut BuffReader::new(self.buffer, self.buffer_len)) {
|
||||
Err(err)
|
||||
} else {
|
||||
Ok(*packet.reason_codes.get(0).unwrap())
|
||||
}
|
||||
};
|
||||
|
||||
if let Err(err) = reason {
|
||||
log::error!("[DECODE ERR]: {}", err);
|
||||
return Err(ReasonCode::BuffError);
|
||||
}
|
||||
|
||||
let res = reason.unwrap();
|
||||
if res != (<QualityOfService as Into<u8>>::into(self.config.qos) >> 1) {
|
||||
Err(ReasonCode::from(res))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn receive_message<'b>(&'b mut self) -> Result<&'b [u8], ReasonCode> {
|
||||
self.network_driver.receive(self.recv_buffer).await?;
|
||||
let mut packet = PublishPacket::<'b, 5>::new();
|
||||
if let Err(err) =
|
||||
packet.decode(&mut BuffReader::new(self.recv_buffer, self.recv_buffer_len))
|
||||
{
|
||||
if err == BufferError::PacketTypeMismatch {
|
||||
let mut disc = DisconnectPacket::<'b, 5>::new();
|
||||
if disc
|
||||
.decode(&mut BuffReader::new(self.buffer, self.buffer_len))
|
||||
.is_ok()
|
||||
{
|
||||
log::error!("Client was disconnected with reason: ");
|
||||
return Err(ReasonCode::from(disc.disconnect_reason));
|
||||
}
|
||||
}
|
||||
log::error!("[DECODE ERR]: {}", err);
|
||||
return Err(ReasonCode::BuffError);
|
||||
}
|
||||
|
||||
if (packet.fixed_header & 0x06)
|
||||
== <QualityOfService as Into<u8>>::into(QualityOfService::QoS1)
|
||||
{
|
||||
let mut puback = PubackPacket::<'b, 5>::new();
|
||||
puback.packet_identifier = packet.packet_identifier;
|
||||
puback.reason_code = 0x00;
|
||||
{
|
||||
let len = puback.encode(self.buffer, self.buffer_len);
|
||||
if let Err(err) = len {
|
||||
log::error!("[DECODE ERR]: {}", err);
|
||||
return Err(ReasonCode::BuffError);
|
||||
}
|
||||
self.network_driver.send(self.buffer, len.unwrap()).await?;
|
||||
}
|
||||
}
|
||||
|
||||
return Ok(packet.message.unwrap());
|
||||
}
|
||||
|
||||
pub async fn send_ping<'b>(&'b mut self) -> Result<(), ReasonCode> {
|
||||
let len = {
|
||||
let mut packet = PingreqPacket::new();
|
||||
packet.encode(self.buffer, self.buffer_len)
|
||||
};
|
||||
|
||||
if let Err(err) = len {
|
||||
log::error!("[DECODE ERR]: {}", err);
|
||||
return Err(ReasonCode::BuffError);
|
||||
}
|
||||
|
||||
self.network_driver.send(self.buffer, len.unwrap()).await?;
|
||||
|
||||
self.network_driver.receive(self.buffer).await?;
|
||||
let mut packet = PingrespPacket::new();
|
||||
if let Err(err) = packet.decode(&mut BuffReader::new(self.buffer, self.buffer_len)) {
|
||||
log::error!("[DECODE ERR]: {}", err);
|
||||
return Err(ReasonCode::BuffError);
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
27
mqtt/src/client/mod.rs
Normal file
27
mqtt/src/client/mod.rs
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#[allow(unused_must_use)]
|
||||
pub mod client_config;
|
||||
pub mod client_v5;
|
||||
25
mqtt/src/encoding/mod.rs
Normal file
25
mqtt/src/encoding/mod.rs
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* 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 variable_byte_integer;
|
||||
118
mqtt/src/encoding/variable_byte_integer.rs
Normal file
118
mqtt/src/encoding/variable_byte_integer.rs
Normal file
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) [2022] [Ondrej Babec <ond.babec@gmailc.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::utils::types::BufferError;
|
||||
|
||||
/// VariableByteIntegerEncoder and VariableByteIntegerDecoder are implemented based on
|
||||
/// pseudo code which is introduced in MQTT version 5.0 OASIS standard accesible from
|
||||
/// https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901107
|
||||
|
||||
/// Variable byte integer encoder structure is help structure which implements function used to
|
||||
/// encode integer into MQTT variable byte integer format. This format is mainly used to encode
|
||||
/// lenghts stored in a packet.
|
||||
pub struct VariableByteIntegerEncoder;
|
||||
|
||||
/// Variable byte integers error enumeration is used by both encoder and decoder for
|
||||
/// error notification.
|
||||
|
||||
pub type VariableByteInteger = [u8; 4];
|
||||
|
||||
impl VariableByteIntegerEncoder {
|
||||
/// Encode function takes as parameter integer as u32 type and encodes
|
||||
/// this integer into maximal 4 Bytes. MSb of each Byte is controll bit.
|
||||
/// This bit is saying if there is continuing Byte in stream or not, this way
|
||||
/// we can effectively use 1 to 4 Bytes based in integer len.
|
||||
pub fn encode(mut target: u32) -> Result<VariableByteInteger, BufferError> {
|
||||
// General known informations from OASIS
|
||||
const MAX_ENCODABLE: u32 = 268435455;
|
||||
const MOD: u32 = 128;
|
||||
if target > MAX_ENCODABLE {
|
||||
log::error!("Maximal value of integer for encoding was exceeded");
|
||||
return Err(BufferError::EncodingError);
|
||||
}
|
||||
|
||||
let mut res: [u8; 4] = [0; 4];
|
||||
let mut encoded_byte: u8;
|
||||
let mut i: usize = 0;
|
||||
|
||||
loop {
|
||||
encoded_byte = (target % MOD) as u8;
|
||||
target = target / 128;
|
||||
if target > 0 {
|
||||
encoded_byte = encoded_byte | 128;
|
||||
}
|
||||
res[i] = encoded_byte;
|
||||
i = i + 1;
|
||||
if target <= 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return Ok(res);
|
||||
}
|
||||
|
||||
pub fn len(var_int: VariableByteInteger) -> usize {
|
||||
let mut i: usize = 0;
|
||||
loop {
|
||||
let encoded_byte: u8;
|
||||
encoded_byte = var_int[i];
|
||||
i = i + 1;
|
||||
if (encoded_byte & 128) == 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
/// Variable byte integer decoder structure is help structure which implements function used to
|
||||
/// decode message lenghts in MQTT packet and other parts encoded into variable byte integer.
|
||||
pub struct VariableByteIntegerDecoder;
|
||||
|
||||
impl VariableByteIntegerDecoder {
|
||||
/// Decode function takes as paramater encoded integer represented
|
||||
/// as array of 4 unsigned numbers of exactly 1 Byte each -> 4 Bytes maximal
|
||||
/// same as maximal amount of bytes for variable byte encoding in MQTT.
|
||||
pub fn decode(encoded: VariableByteInteger) -> Result<u32, BufferError> {
|
||||
let mut multiplier: u32 = 1;
|
||||
let mut ret: u32 = 0;
|
||||
|
||||
let mut encoded_byte: u8;
|
||||
let mut i: usize = 0;
|
||||
|
||||
loop {
|
||||
encoded_byte = encoded[i];
|
||||
i = i + 1;
|
||||
ret = ret + ((encoded_byte & 127) as u32 * multiplier) as u32;
|
||||
if multiplier > 128 * 128 * 128 {
|
||||
return Err(BufferError::DecodingError);
|
||||
}
|
||||
multiplier = multiplier * 128;
|
||||
if (encoded_byte & 128) == 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return Ok(ret);
|
||||
}
|
||||
}
|
||||
38
mqtt/src/lib.rs
Normal file
38
mqtt/src/lib.rs
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#![feature(in_band_lifetimes)]
|
||||
#![macro_use]
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
#![allow(dead_code)]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
#![feature(generic_associated_types)]
|
||||
|
||||
pub mod client;
|
||||
pub mod encoding;
|
||||
pub mod network;
|
||||
pub mod packet;
|
||||
pub mod tests;
|
||||
pub mod tokio_net;
|
||||
pub mod utils;
|
||||
25
mqtt/src/network/mod.rs
Normal file
25
mqtt/src/network/mod.rs
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* 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 network_trait;
|
||||
66
mqtt/src/network/network_trait.rs
Normal file
66
mqtt/src/network/network_trait.rs
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* 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::future::Future;
|
||||
|
||||
use crate::packet::v5::reason_codes::ReasonCode;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum NetworkError {
|
||||
Connection,
|
||||
Unknown,
|
||||
QoSAck,
|
||||
IDNotMatchedOnAck,
|
||||
NoMatchingSubs,
|
||||
}
|
||||
|
||||
pub trait NetworkConnectionFactory: Sized {
|
||||
type Connection: NetworkConnection;
|
||||
|
||||
type ConnectionFuture<'m>: Future<Output = Result<Self::Connection, ReasonCode>>
|
||||
where
|
||||
Self: 'm;
|
||||
|
||||
fn connect<'m>(&'m mut self, ip: [u8; 4], port: u16) -> Self::ConnectionFuture<'m>;
|
||||
}
|
||||
|
||||
pub trait NetworkConnection {
|
||||
type WriteFuture<'m>: Future<Output = Result<(), ReasonCode>>
|
||||
where
|
||||
Self: 'm;
|
||||
|
||||
type ReadFuture<'m>: Future<Output = Result<usize, ReasonCode>>
|
||||
where
|
||||
Self: 'm;
|
||||
|
||||
type CloseFuture<'m>: Future<Output = Result<(), ReasonCode>>
|
||||
where
|
||||
Self: 'm;
|
||||
|
||||
fn send(&'m mut self, buffer: &'m mut [u8], len: usize) -> Self::WriteFuture<'m>;
|
||||
|
||||
fn receive(&'m mut self, buffer: &'m mut [u8]) -> Self::ReadFuture<'m>;
|
||||
|
||||
fn close(self) -> Self::CloseFuture<'m>;
|
||||
}
|
||||
26
mqtt/src/packet/mod.rs
Normal file
26
mqtt/src/packet/mod.rs
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#[allow(unused_must_use)]
|
||||
pub mod v5;
|
||||
121
mqtt/src/packet/v5/auth_packet.rs
Normal file
121
mqtt/src/packet/v5/auth_packet.rs
Normal 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;
|
||||
}
|
||||
}
|
||||
107
mqtt/src/packet/v5/connack_packet.rs
Normal file
107
mqtt/src/packet/v5/connack_packet.rs
Normal 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;
|
||||
}
|
||||
}
|
||||
217
mqtt/src/packet/v5/connect_packet.rs
Normal file
217
mqtt/src/packet/v5/connect_packet.rs
Normal 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;
|
||||
}
|
||||
}
|
||||
112
mqtt/src/packet/v5/disconnect_packet.rs
Normal file
112
mqtt/src/packet/v5/disconnect_packet.rs
Normal 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
44
mqtt/src/packet/v5/mod.rs
Normal 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;
|
||||
107
mqtt/src/packet/v5/mqtt_packet.rs
Normal file
107
mqtt/src/packet/v5/mqtt_packet.rs
Normal 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));
|
||||
}
|
||||
}
|
||||
93
mqtt/src/packet/v5/packet_type.rs
Normal file
93
mqtt/src/packet/v5/packet_type.rs
Normal 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,
|
||||
};
|
||||
}
|
||||
}
|
||||
84
mqtt/src/packet/v5/pingreq_packet.rs
Normal file
84
mqtt/src/packet/v5/pingreq_packet.rs
Normal 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;
|
||||
}
|
||||
}
|
||||
92
mqtt/src/packet/v5/pingresp_packet.rs
Normal file
92
mqtt/src/packet/v5/pingresp_packet.rs
Normal 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;
|
||||
}
|
||||
}
|
||||
364
mqtt/src/packet/v5/property.rs
Normal file
364
mqtt/src/packet/v5/property.rs
Normal 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(),
|
||||
};
|
||||
}
|
||||
}
|
||||
116
mqtt/src/packet/v5/puback_packet.rs
Normal file
116
mqtt/src/packet/v5/puback_packet.rs
Normal 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;
|
||||
}
|
||||
}
|
||||
110
mqtt/src/packet/v5/pubcomp_packet.rs
Normal file
110
mqtt/src/packet/v5/pubcomp_packet.rs
Normal 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;
|
||||
}
|
||||
}
|
||||
179
mqtt/src/packet/v5/publish_packet.rs
Normal file
179
mqtt/src/packet/v5/publish_packet.rs
Normal 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;
|
||||
}
|
||||
}
|
||||
109
mqtt/src/packet/v5/pubrec_packet.rs
Normal file
109
mqtt/src/packet/v5/pubrec_packet.rs
Normal 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;
|
||||
}
|
||||
}
|
||||
109
mqtt/src/packet/v5/pubrel_packet.rs
Normal file
109
mqtt/src/packet/v5/pubrel_packet.rs
Normal 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;
|
||||
}
|
||||
}
|
||||
241
mqtt/src/packet/v5/reason_codes.rs
Normal file
241
mqtt/src/packet/v5/reason_codes.rs
Normal 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!"),
|
||||
}
|
||||
}
|
||||
}
|
||||
120
mqtt/src/packet/v5/suback_packet.rs
Normal file
120
mqtt/src/packet/v5/suback_packet.rs
Normal 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;
|
||||
}
|
||||
}
|
||||
135
mqtt/src/packet/v5/subscription_packet.rs
Normal file
135
mqtt/src/packet/v5/subscription_packet.rs
Normal 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;
|
||||
}
|
||||
}
|
||||
114
mqtt/src/packet/v5/unsuback_packet.rs
Normal file
114
mqtt/src/packet/v5/unsuback_packet.rs
Normal 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;
|
||||
}
|
||||
}
|
||||
135
mqtt/src/packet/v5/unsubscription_packet.rs
Normal file
135
mqtt/src/packet/v5/unsubscription_packet.rs
Normal 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;
|
||||
}
|
||||
}
|
||||
228
mqtt/src/tests/integration/integration_test_single.rs
Normal file
228
mqtt/src/tests/integration/integration_test_single.rs
Normal file
@@ -0,0 +1,228 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
extern crate alloc;
|
||||
use alloc::string::String;
|
||||
use core::time::Duration;
|
||||
use std::future::Future;
|
||||
use tokio::time::sleep;
|
||||
use tokio::{join, task};
|
||||
use tokio_test::assert_ok;
|
||||
|
||||
use crate::client::client_config::ClientConfig;
|
||||
use crate::client::client_v5::MqttClientV5;
|
||||
use crate::network::network_trait::{NetworkConnection, NetworkConnectionFactory};
|
||||
use crate::packet::v5::property::Property;
|
||||
use crate::packet::v5::publish_packet::QualityOfService;
|
||||
use crate::packet::v5::reason_codes::ReasonCode;
|
||||
use crate::packet::v5::reason_codes::ReasonCode::NotAuthorized;
|
||||
use crate::tokio_net::tokio_network::{TokioNetwork, TokioNetworkFactory};
|
||||
use crate::utils::types::BufferError;
|
||||
|
||||
static IP: [u8; 4] = [127, 0, 0, 1];
|
||||
static PORT: u16 = 1883;
|
||||
static USERNAME: &str = "test";
|
||||
static PASSWORD: &str = "testPass";
|
||||
static MSG: &str = "testMessage";
|
||||
|
||||
fn init() {
|
||||
let _ = env_logger::builder()
|
||||
.filter_level(log::LevelFilter::Info)
|
||||
.format_timestamp_nanos()
|
||||
.try_init();
|
||||
}
|
||||
|
||||
async fn publish_core<'b>(
|
||||
client: &mut MqttClientV5<'b, TokioNetwork, 5>,
|
||||
topic: &str,
|
||||
) -> Result<(), ReasonCode> {
|
||||
log::info!(
|
||||
"[Publisher] Connection to broker with username {} and password {}",
|
||||
USERNAME,
|
||||
PASSWORD
|
||||
);
|
||||
let mut result = { client.connect_to_broker().await };
|
||||
assert_ok!(result);
|
||||
log::info!("[Publisher] Waiting {} seconds before sending", 5);
|
||||
sleep(Duration::from_secs(5)).await;
|
||||
|
||||
log::info!("[Publisher] Sending new message {} to topic {}", MSG, topic);
|
||||
result = { client.send_message(topic, MSG).await };
|
||||
assert_ok!(result);
|
||||
|
||||
log::info!("[Publisher] Disconnecting!");
|
||||
result = { client.disconnect().await };
|
||||
assert_ok!(result);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn publish(qos: QualityOfService, topic: &str) -> Result<(), ReasonCode> {
|
||||
let mut tokio_factory: TokioNetworkFactory = TokioNetworkFactory::new();
|
||||
let mut tokio_network: TokioNetwork = tokio_factory.connect(IP, PORT).await?;
|
||||
let mut config = ClientConfig::new();
|
||||
config.add_qos(qos);
|
||||
config.add_username(USERNAME);
|
||||
config.add_password(PASSWORD);
|
||||
config.max_packet_size = 100;
|
||||
let mut recv_buffer = [0; 80];
|
||||
let mut write_buffer = [0; 80];
|
||||
|
||||
let mut client = MqttClientV5::<TokioNetwork, 5>::new(
|
||||
&mut tokio_network,
|
||||
&mut write_buffer,
|
||||
80,
|
||||
&mut recv_buffer,
|
||||
80,
|
||||
config,
|
||||
);
|
||||
publish_core(&mut client, topic).await
|
||||
}
|
||||
|
||||
async fn receive_core<'b>(
|
||||
client: &mut MqttClientV5<'b, TokioNetwork, 5>,
|
||||
topic: &str,
|
||||
) -> Result<(), ReasonCode> {
|
||||
log::info!(
|
||||
"[Receiver] Connection to broker with username {} and password {}",
|
||||
USERNAME,
|
||||
PASSWORD
|
||||
);
|
||||
let mut result = { client.connect_to_broker().await };
|
||||
assert_ok!(result);
|
||||
|
||||
log::info!("[Receiver] Subscribing to topic {}", topic);
|
||||
result = { client.subscribe_to_topic(topic).await };
|
||||
assert_ok!(result);
|
||||
log::info!("[Receiver] Waiting for new message!");
|
||||
let msg = { client.receive_message().await };
|
||||
assert_ok!(msg);
|
||||
let act_message = String::from_utf8_lossy(msg?);
|
||||
log::info!("[Receiver] Got new message: {}", act_message);
|
||||
assert_eq!(act_message, MSG);
|
||||
|
||||
log::info!("[Receiver] Disconnecting");
|
||||
result = { client.disconnect().await };
|
||||
assert_ok!(result);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn receive(qos: QualityOfService, topic: &str) -> Result<(), ReasonCode> {
|
||||
let mut tokio_factory: TokioNetworkFactory = TokioNetworkFactory::new();
|
||||
let mut tokio_network: TokioNetwork = tokio_factory.connect(IP, PORT).await?;
|
||||
let mut config = ClientConfig::new();
|
||||
config.add_qos(qos);
|
||||
config.add_username(USERNAME);
|
||||
config.add_password(PASSWORD);
|
||||
config.max_packet_size = 60;
|
||||
config.properties.push(Property::ReceiveMaximum(20));
|
||||
let mut recv_buffer = [0; 100];
|
||||
let mut write_buffer = [0; 100];
|
||||
|
||||
let mut client = MqttClientV5::<TokioNetwork, 5>::new(
|
||||
&mut tokio_network,
|
||||
&mut write_buffer,
|
||||
100,
|
||||
&mut recv_buffer,
|
||||
100,
|
||||
config,
|
||||
);
|
||||
|
||||
receive_core(&mut client, topic).await
|
||||
}
|
||||
|
||||
async fn receive_with_wrong_cred(qos: QualityOfService) -> Result<(), ReasonCode> {
|
||||
let mut tokio_factory: TokioNetworkFactory = TokioNetworkFactory::new();
|
||||
let mut tokio_network: TokioNetwork = tokio_factory.connect(IP, PORT).await?;
|
||||
let mut config = ClientConfig::new();
|
||||
config.add_qos(qos);
|
||||
config.add_username("xyz");
|
||||
config.add_password(PASSWORD);
|
||||
config.max_packet_size = 60;
|
||||
config.properties.push(Property::ReceiveMaximum(20));
|
||||
let mut recv_buffer = [0; 100];
|
||||
let mut write_buffer = [0; 100];
|
||||
|
||||
let mut client = MqttClientV5::<TokioNetwork, 5>::new(
|
||||
&mut tokio_network,
|
||||
&mut write_buffer,
|
||||
100,
|
||||
&mut recv_buffer,
|
||||
100,
|
||||
config,
|
||||
);
|
||||
|
||||
log::info!(
|
||||
"[Receiver] Connection to broker with username {} and password {}",
|
||||
"xyz",
|
||||
PASSWORD
|
||||
);
|
||||
let result = { client.connect_to_broker().await };
|
||||
assert!(result.is_err());
|
||||
assert_eq!(result.unwrap_err(), NotAuthorized);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn simple_publish_recv() {
|
||||
init();
|
||||
log::info!("Running simple integration test");
|
||||
|
||||
let recv =
|
||||
task::spawn(async move { receive(QualityOfService::QoS0, "test/recv/simple").await });
|
||||
|
||||
let publ =
|
||||
task::spawn(async move { publish(QualityOfService::QoS0, "test/recv/simple").await });
|
||||
|
||||
let (r, p) = join!(recv, publ);
|
||||
assert_ok!(r.unwrap());
|
||||
assert_ok!(p.unwrap());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn simple_publish_recv_qos() {
|
||||
init();
|
||||
log::info!("Running simple integration test with Quality of Service 1");
|
||||
|
||||
let recv = task::spawn(async move { receive(QualityOfService::QoS1, "test/recv/qos").await });
|
||||
|
||||
let publ = task::spawn(async move { publish(QualityOfService::QoS1, "test/recv/qos").await });
|
||||
let (r, p) = join!(recv, publ);
|
||||
assert_ok!(r.unwrap());
|
||||
assert_ok!(p.unwrap());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn simple_publish_recv_wrong_cred() {
|
||||
init();
|
||||
log::info!("Running simple integration test wrong credentials");
|
||||
|
||||
let recv = task::spawn(async move { receive_with_wrong_cred(QualityOfService::QoS1).await });
|
||||
|
||||
let recv_right =
|
||||
task::spawn(async move { receive(QualityOfService::QoS0, "test/recv/wrong").await });
|
||||
|
||||
let publ = task::spawn(async move { publish(QualityOfService::QoS1, "test/recv/wrong").await });
|
||||
let (r, rv, p) = join!(recv, recv_right, publ);
|
||||
assert_ok!(rv.unwrap());
|
||||
assert_ok!(p.unwrap());
|
||||
}
|
||||
24
mqtt/src/tests/integration/mod.rs
Normal file
24
mqtt/src/tests/integration/mod.rs
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* 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 integration_test_single;
|
||||
33
mqtt/src/tests/mod.rs
Normal file
33
mqtt/src/tests/mod.rs
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(unused_must_use)]
|
||||
pub mod unit;
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[allow(unused_must_use)]
|
||||
#[allow(unused_imports)]
|
||||
#[cfg(feature = "tokio")]
|
||||
pub mod integration;
|
||||
25
mqtt/src/tests/unit/encoding/mod.rs
Normal file
25
mqtt/src/tests/unit/encoding/mod.rs
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* 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 variable_byte_integer_unit;
|
||||
80
mqtt/src/tests/unit/encoding/variable_byte_integer_unit.rs
Normal file
80
mqtt/src/tests/unit/encoding/variable_byte_integer_unit.rs
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* 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::{
|
||||
VariableByteInteger, VariableByteIntegerDecoder, VariableByteIntegerEncoder,
|
||||
};
|
||||
use crate::utils::types::BufferError;
|
||||
|
||||
#[test]
|
||||
fn test_decode() {
|
||||
static BUFFER: VariableByteInteger = [0x81, 0x81, 0x81, 0x01];
|
||||
|
||||
let decoded = VariableByteIntegerDecoder::decode(BUFFER);
|
||||
assert!(decoded.is_ok());
|
||||
assert_eq!(decoded.unwrap(), 2113665);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_decode_small() {
|
||||
static BUFFER: VariableByteInteger = [0x81, 0x81, 0x01, 0x85];
|
||||
|
||||
let decoded = VariableByteIntegerDecoder::decode(BUFFER);
|
||||
assert!(decoded.is_ok());
|
||||
assert_eq!(decoded.unwrap(), 16_513);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_encode() {
|
||||
let encoded = VariableByteIntegerEncoder::encode(211_366_5);
|
||||
assert!(encoded.is_ok());
|
||||
let res = encoded.unwrap();
|
||||
assert_eq!(res, [0x81, 0x81, 0x81, 0x01]);
|
||||
assert_eq!(VariableByteIntegerEncoder::len(res), 4);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_encode_small() {
|
||||
let encoded = VariableByteIntegerEncoder::encode(16_513);
|
||||
assert!(encoded.is_ok());
|
||||
let res = encoded.unwrap();
|
||||
assert_eq!(res, [0x81, 0x81, 0x01, 0x00]);
|
||||
assert_eq!(VariableByteIntegerEncoder::len(res), 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_encode_extra_small() {
|
||||
let encoded = VariableByteIntegerEncoder::encode(5);
|
||||
assert!(encoded.is_ok());
|
||||
let res = encoded.unwrap();
|
||||
assert_eq!(res, [0x05, 0x00, 0x00, 0x00]);
|
||||
assert_eq!(VariableByteIntegerEncoder::len(res), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_encode_max() {
|
||||
let encoded = VariableByteIntegerEncoder::encode(288_435_455);
|
||||
assert!(encoded.is_err());
|
||||
assert_eq!(encoded.unwrap_err(), BufferError::EncodingError);
|
||||
}
|
||||
27
mqtt/src/tests/unit/mod.rs
Normal file
27
mqtt/src/tests/unit/mod.rs
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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 encoding;
|
||||
pub mod packet;
|
||||
pub mod utils;
|
||||
25
mqtt/src/tests/unit/packet/mod.rs
Normal file
25
mqtt/src/tests/unit/packet/mod.rs
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* 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 v5;
|
||||
86
mqtt/src/tests/unit/packet/v5/connack_packet_unit.rs
Normal file
86
mqtt/src/tests/unit/packet/v5/connack_packet_unit.rs
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* 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::connack_packet::ConnackPacket;
|
||||
use crate::packet::v5::mqtt_packet::Packet;
|
||||
use crate::packet::v5::property::Property;
|
||||
use crate::packet::v5::reason_codes::ReasonCode;
|
||||
use crate::utils::buffer_reader::BuffReader;
|
||||
|
||||
#[test]
|
||||
fn test_encode() {
|
||||
let mut buffer: [u8; 100] = [0; 100];
|
||||
let mut connack = ConnackPacket::<2>::new();
|
||||
connack.property_len = 3;
|
||||
let prop = Property::ReceiveMaximum(21);
|
||||
connack.properties.push(prop);
|
||||
connack.connect_reason_code = ReasonCode::ServerMoved.into();
|
||||
connack.ack_flags = 0x45;
|
||||
|
||||
let res = connack.encode(&mut buffer, 100);
|
||||
assert!(res.is_ok());
|
||||
assert_eq!(
|
||||
buffer[0..res.unwrap()],
|
||||
[
|
||||
0x20,
|
||||
0x06,
|
||||
0x45,
|
||||
ReasonCode::ServerMoved.into(),
|
||||
0x03,
|
||||
0x21,
|
||||
0x00,
|
||||
0x15
|
||||
]
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_decode() {
|
||||
let mut buffer: [u8; 8] = [
|
||||
0x20,
|
||||
0x06,
|
||||
0x45,
|
||||
ReasonCode::ServerMoved.into(),
|
||||
0x03,
|
||||
0x21,
|
||||
0x00,
|
||||
0x15,
|
||||
];
|
||||
let mut connack_res = ConnackPacket::<2>::new();
|
||||
let res = connack_res.decode(&mut BuffReader::new(&mut buffer, 8));
|
||||
|
||||
assert!(res.is_ok());
|
||||
assert_eq!(connack_res.property_len, 3);
|
||||
assert_eq!(connack_res.ack_flags, 0x45);
|
||||
assert_eq!(
|
||||
connack_res.connect_reason_code,
|
||||
ReasonCode::ServerMoved.into()
|
||||
);
|
||||
assert_eq!(connack_res.property_len, 3);
|
||||
let prop = connack_res.properties.get(0).unwrap();
|
||||
assert_eq!(<&Property as Into<u8>>::into(prop), 0x21);
|
||||
if let Property::ReceiveMaximum(u) = *prop {
|
||||
assert_eq!(u, 21);
|
||||
}
|
||||
}
|
||||
42
mqtt/src/tests/unit/packet/v5/connect_packet_unit.rs
Normal file
42
mqtt/src/tests/unit/packet/v5/connect_packet_unit.rs
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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::connect_packet::ConnectPacket;
|
||||
use crate::packet::v5::mqtt_packet::Packet;
|
||||
|
||||
#[test]
|
||||
fn test_encode() {
|
||||
let mut buffer: [u8; 100] = [0; 100];
|
||||
let mut connect = ConnectPacket::<1, 0>::clean();
|
||||
let res = connect.encode(&mut buffer, 100);
|
||||
|
||||
assert!(res.is_ok());
|
||||
assert_eq!(
|
||||
buffer[0..res.unwrap()],
|
||||
[
|
||||
0x10, 0x10, 0x00, 0x04, 0x4d, 0x51, 0x54, 0x54, 0x05, 0x02, 0x00, 0x3c, 0x03, 0x21,
|
||||
0x00, 0x14, 0x00, 0x00
|
||||
]
|
||||
)
|
||||
}
|
||||
64
mqtt/src/tests/unit/packet/v5/disconnect_packet_unit.rs
Normal file
64
mqtt/src/tests/unit/packet/v5/disconnect_packet_unit.rs
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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::disconnect_packet::DisconnectPacket;
|
||||
use crate::packet::v5::mqtt_packet::Packet;
|
||||
use crate::packet::v5::packet_type::PacketType;
|
||||
use crate::packet::v5::property::Property;
|
||||
use crate::utils::buffer_reader::BuffReader;
|
||||
use heapless::Vec;
|
||||
|
||||
#[test]
|
||||
fn test_encode() {
|
||||
let mut buffer: [u8; 10] = [0; 10];
|
||||
let mut packet = DisconnectPacket::<1>::new();
|
||||
let prop: Property = Property::SessionExpiryInterval(512);
|
||||
let mut props = Vec::<Property, 1>::new();
|
||||
props.push(prop);
|
||||
packet.property_len = packet.add_properties(&props);
|
||||
let res = packet.encode(&mut buffer, 100);
|
||||
assert!(res.is_ok());
|
||||
assert_eq!(
|
||||
buffer[0..res.unwrap()],
|
||||
[0xE0, 0x07, 0x00, 0x05, 0x11, 0x00, 0x00, 0x02, 0x00]
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_decode() {
|
||||
let buffer: [u8; 10] = [0xE0, 0x07, 0x00, 0x05, 0x11, 0x00, 0x00, 0x04, 0x00, 0x00];
|
||||
let mut packet = DisconnectPacket::<1>::new();
|
||||
let res = packet.decode(&mut BuffReader::new(&buffer, 10));
|
||||
assert!(res.is_ok());
|
||||
assert_eq!(packet.fixed_header, PacketType::Disconnect.into());
|
||||
assert_eq!(packet.remain_len, 7);
|
||||
assert_eq!(packet.disconnect_reason, 0x00);
|
||||
assert_eq!(packet.property_len, 5);
|
||||
let prop = packet.properties.get(0);
|
||||
assert!(prop.is_some());
|
||||
assert_eq!(<&Property as Into<u8>>::into(prop.unwrap()), 0x11);
|
||||
if let Property::SessionExpiryInterval(u) = *prop.unwrap() {
|
||||
assert_eq!(u, 1024);
|
||||
}
|
||||
}
|
||||
38
mqtt/src/tests/unit/packet/v5/mod.rs
Normal file
38
mqtt/src/tests/unit/packet/v5/mod.rs
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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 connack_packet_unit;
|
||||
pub mod connect_packet_unit;
|
||||
pub mod disconnect_packet_unit;
|
||||
pub mod pingreq_packet_unit;
|
||||
pub mod pingresp_packet_unit;
|
||||
pub mod puback_packet_unit;
|
||||
pub mod pubcomp_packet_unit;
|
||||
pub mod publish_packet_unit;
|
||||
pub mod pubrec_packet_unit;
|
||||
pub mod pubrel_packet_unit;
|
||||
pub mod suback_packet_unit;
|
||||
pub mod subscription_packet_unit;
|
||||
pub mod unsuback_packet_unit;
|
||||
pub mod unsubscription_packet_unit;
|
||||
38
mqtt/src/tests/unit/packet/v5/pingreq_packet_unit.rs
Normal file
38
mqtt/src/tests/unit/packet/v5/pingreq_packet_unit.rs
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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::packet::v5::packet_type::PacketType;
|
||||
use crate::packet::v5::pingreq_packet::PingreqPacket;
|
||||
|
||||
#[test]
|
||||
fn test_encode() {
|
||||
let mut buffer: [u8; 3] = [0x00, 0x98, 0x45];
|
||||
let mut packet = PingreqPacket::new();
|
||||
packet.fixed_header = PacketType::Pingreq.into();
|
||||
packet.remain_len = 0;
|
||||
let res = packet.encode(&mut buffer, 3);
|
||||
assert!(res.is_ok());
|
||||
assert_eq!(buffer, [0xC0, 0x00, 0x45])
|
||||
}
|
||||
49
mqtt/src/tests/unit/packet/v5/pingresp_packet_unit.rs
Normal file
49
mqtt/src/tests/unit/packet/v5/pingresp_packet_unit.rs
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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::packet::v5::packet_type::PacketType;
|
||||
use crate::packet::v5::pingresp_packet::PingrespPacket;
|
||||
use crate::utils::buffer_reader::BuffReader;
|
||||
|
||||
#[test]
|
||||
fn test_encode() {
|
||||
let mut buffer: [u8; 3] = [0x00, 0x98, 0x45];
|
||||
let mut packet = PingrespPacket::new();
|
||||
packet.fixed_header = PacketType::Pingresp.into();
|
||||
packet.remain_len = 0;
|
||||
let res = packet.encode(&mut buffer, 3);
|
||||
assert!(res.is_ok());
|
||||
assert_eq!(buffer, [0xD0, 0x00, 0x45])
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_decode() {
|
||||
let buffer: [u8; 3] = [0xD0, 0x00, 0x51];
|
||||
let mut packet = PingrespPacket::new();
|
||||
let res = packet.decode(&mut BuffReader::new(&buffer, 3));
|
||||
assert!(res.is_ok());
|
||||
assert_eq!(packet.fixed_header, PacketType::Pingresp.into());
|
||||
assert_eq!(packet.remain_len, 0);
|
||||
}
|
||||
73
mqtt/src/tests/unit/packet/v5/puback_packet_unit.rs
Normal file
73
mqtt/src/tests/unit/packet/v5/puback_packet_unit.rs
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* 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::packet::v5::packet_type::PacketType;
|
||||
use crate::packet::v5::property::Property;
|
||||
use crate::packet::v5::puback_packet::PubackPacket;
|
||||
use crate::utils::buffer_reader::BuffReader;
|
||||
use crate::utils::types::EncodedString;
|
||||
use heapless::Vec;
|
||||
|
||||
#[test]
|
||||
fn test_encode() {
|
||||
let mut buffer: [u8; 14] = [0; 14];
|
||||
let mut packet = PubackPacket::<1>::new();
|
||||
packet.packet_identifier = 35420;
|
||||
packet.reason_code = 0x00;
|
||||
let mut str = EncodedString::new();
|
||||
str.string = "Hello";
|
||||
str.len = 5;
|
||||
let mut props = Vec::<Property, 1>::new();
|
||||
props.push(Property::ReasonString(str));
|
||||
packet.property_len = packet.add_properties(&props);
|
||||
let res = packet.encode(&mut buffer, 14);
|
||||
assert!(res.is_ok());
|
||||
assert_eq!(res.unwrap(), 14);
|
||||
assert_eq!(
|
||||
buffer,
|
||||
[0x40, 0x0C, 0x8A, 0x5C, 0x00, 0x08, 0x1F, 0x00, 0x05, 0x48, 0x65, 0x6c, 0x6c, 0x6f]
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_decode() {
|
||||
let buffer: [u8; 14] = [
|
||||
0x40, 0x0C, 0x8A, 0x5E, 0x15, 0x08, 0x1F, 0x00, 0x05, 0x48, 0x65, 0x6c, 0x6c, 0x6f,
|
||||
];
|
||||
let mut packet = PubackPacket::<1>::new();
|
||||
let res = packet.decode(&mut BuffReader::new(&buffer, 14));
|
||||
assert!(res.is_ok());
|
||||
assert_eq!(packet.fixed_header, PacketType::Puback.into());
|
||||
assert_eq!(packet.remain_len, 12);
|
||||
assert_eq!(packet.packet_identifier, 35422);
|
||||
assert_eq!(packet.reason_code, 0x15);
|
||||
assert_eq!(packet.property_len, 8);
|
||||
let prop = packet.properties.get(0);
|
||||
assert!(prop.is_some());
|
||||
assert_eq!(<&Property as Into<u8>>::into(prop.unwrap()), 0x1F);
|
||||
if let Property::ReasonString(u) = (*prop.unwrap()).clone() {
|
||||
assert_eq!(u.string, "Hello");
|
||||
}
|
||||
}
|
||||
73
mqtt/src/tests/unit/packet/v5/pubcomp_packet_unit.rs
Normal file
73
mqtt/src/tests/unit/packet/v5/pubcomp_packet_unit.rs
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* 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::packet::v5::packet_type::PacketType;
|
||||
use crate::packet::v5::property::Property;
|
||||
use crate::packet::v5::pubcomp_packet::PubcompPacket;
|
||||
use crate::utils::buffer_reader::BuffReader;
|
||||
use crate::utils::types::EncodedString;
|
||||
use heapless::Vec;
|
||||
|
||||
#[test]
|
||||
fn test_encode() {
|
||||
let mut buffer: [u8; 14] = [0; 14];
|
||||
let mut packet = PubcompPacket::<1>::new();
|
||||
packet.fixed_header = PacketType::Pubcomp.into();
|
||||
packet.packet_identifier = 35420;
|
||||
packet.reason_code = 0x00;
|
||||
let mut str = EncodedString::new();
|
||||
str.string = "Wheel";
|
||||
str.len = 5;
|
||||
let mut props = Vec::<Property, 1>::new();
|
||||
props.push(Property::ReasonString(str));
|
||||
packet.property_len = packet.add_properties(&props);
|
||||
let res = packet.encode(&mut buffer, 14);
|
||||
assert!(res.is_ok());
|
||||
assert_eq!(res.unwrap(), 14);
|
||||
assert_eq!(
|
||||
buffer,
|
||||
[0x70, 0x0C, 0x8A, 0x5C, 0x00, 0x08, 0x1F, 0x00, 0x05, 0x57, 0x68, 0x65, 0x65, 0x6c]
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_decode() {
|
||||
let buffer: [u8; 14] = [
|
||||
0x70, 0x0C, 0x8A, 0x5C, 0x00, 0x08, 0x1F, 0x00, 0x05, 0x57, 0x68, 0x65, 0x65, 0x6c,
|
||||
];
|
||||
let mut packet = PubcompPacket::<1>::new();
|
||||
let res = packet.decode(&mut BuffReader::new(&buffer, 14));
|
||||
assert!(res.is_ok());
|
||||
assert_eq!(packet.fixed_header, PacketType::Pubcomp.into());
|
||||
assert_eq!(packet.packet_identifier, 35420);
|
||||
assert_eq!(packet.reason_code, 0x00);
|
||||
assert_eq!(packet.property_len, 8);
|
||||
let prop = packet.properties.get(0);
|
||||
assert!(prop.is_some());
|
||||
assert_eq!(<&Property as Into<u8>>::into(prop.unwrap()), 0x1F);
|
||||
if let Property::ReasonString(u) = (*prop.unwrap()).clone() {
|
||||
assert_eq!(u.string, "Wheel");
|
||||
}
|
||||
}
|
||||
97
mqtt/src/tests/unit/packet/v5/publish_packet_unit.rs
Normal file
97
mqtt/src/tests/unit/packet/v5/publish_packet_unit.rs
Normal file
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* 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::packet::v5::packet_type::PacketType;
|
||||
use crate::packet::v5::property::Property;
|
||||
use crate::packet::v5::publish_packet::{PublishPacket, QualityOfService};
|
||||
use crate::utils::buffer_reader::BuffReader;
|
||||
use crate::utils::types::EncodedString;
|
||||
use heapless::Vec;
|
||||
|
||||
#[test]
|
||||
fn test_encode() {
|
||||
let mut buffer: [u8; 29] = [0; 29];
|
||||
let mut packet = PublishPacket::<2>::new();
|
||||
packet.fixed_header = PacketType::Publish.into();
|
||||
packet.add_qos(QualityOfService::QoS1);
|
||||
let mut topic = EncodedString::new();
|
||||
topic.string = "test";
|
||||
topic.len = 4;
|
||||
packet.topic_name = topic;
|
||||
packet.packet_identifier = 23432;
|
||||
let mut props = Vec::<Property, 2>::new();
|
||||
props.push(Property::PayloadFormat(0x01));
|
||||
props.push(Property::MessageExpiryInterval(45678));
|
||||
packet.property_len = packet.add_properties(&props);
|
||||
static MESSAGE: [u8; 11] = [
|
||||
0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64,
|
||||
];
|
||||
packet.add_message(&MESSAGE);
|
||||
let res = packet.encode(&mut buffer, 100);
|
||||
assert!(res.is_ok());
|
||||
assert_eq!(res.unwrap(), 29);
|
||||
assert_eq!(
|
||||
buffer,
|
||||
[
|
||||
0x32, 0x1B, 0x00, 0x04, 0x74, 0x65, 0x73, 0x74, 0x5B, 0x88, 0x07, 0x01, 0x01, 0x02,
|
||||
0x00, 0x00, 0xB2, 0x6E, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c,
|
||||
0x64
|
||||
]
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_decode() {
|
||||
let buffer: [u8; 29] = [
|
||||
0x32, 0x1B, 0x00, 0x04, 0x74, 0x65, 0x73, 0x74, 0x5B, 0x88, 0x07, 0x01, 0x01, 0x02, 0x00,
|
||||
0x00, 0xB2, 0x6E, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64,
|
||||
];
|
||||
let mut packet = PublishPacket::<2>::new();
|
||||
let res = packet.decode(&mut BuffReader::new(&buffer, 29));
|
||||
assert!(res.is_ok());
|
||||
assert_eq!(packet.fixed_header, 0x32);
|
||||
assert_eq!(packet.topic_name.len, 4);
|
||||
assert_eq!(packet.topic_name.string, "test");
|
||||
assert_eq!(packet.packet_identifier, 23432);
|
||||
assert_eq!(packet.property_len, 7);
|
||||
let prop = packet.properties.get(0);
|
||||
assert!(prop.is_some());
|
||||
assert_eq!(<&Property as Into<u8>>::into(prop.unwrap()), 0x01);
|
||||
if let Property::PayloadFormat(u) = (*prop.unwrap()).clone() {
|
||||
assert_eq!(u, 0x01);
|
||||
}
|
||||
let prop2 = packet.properties.get(1);
|
||||
assert!(prop2.is_some());
|
||||
assert_eq!(<&Property as Into<u8>>::into(prop2.unwrap()), 0x02);
|
||||
if let Property::MessageExpiryInterval(u) = (*prop2.unwrap()).clone() {
|
||||
assert_eq!(u, 45678);
|
||||
}
|
||||
if let Some(message) = packet.message {
|
||||
assert_eq!(
|
||||
*message,
|
||||
[0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64]
|
||||
);
|
||||
}
|
||||
}
|
||||
86
mqtt/src/tests/unit/packet/v5/pubrec_packet_unit.rs
Normal file
86
mqtt/src/tests/unit/packet/v5/pubrec_packet_unit.rs
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* 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::packet::v5::packet_type::PacketType;
|
||||
use crate::packet::v5::property::Property;
|
||||
use crate::packet::v5::pubrec_packet::PubrecPacket;
|
||||
use crate::utils::buffer_reader::BuffReader;
|
||||
use crate::utils::types::{EncodedString, StringPair};
|
||||
use heapless::Vec;
|
||||
|
||||
#[test]
|
||||
fn test_encode() {
|
||||
let mut buffer: [u8; 20] = [0; 20];
|
||||
let mut packet = PubrecPacket::<2>::new();
|
||||
packet.packet_identifier = 35420;
|
||||
packet.reason_code = 0x12;
|
||||
let mut name = EncodedString::new();
|
||||
name.string = "name1";
|
||||
name.len = 5;
|
||||
let mut val = EncodedString::new();
|
||||
val.string = "val1";
|
||||
val.len = 4;
|
||||
let mut pair = StringPair::new();
|
||||
pair.name = name;
|
||||
pair.value = val;
|
||||
let mut props = Vec::<Property, 1>::new();
|
||||
props.push(Property::UserProperty(pair));
|
||||
packet.property_len = packet.add_properties(&props);
|
||||
let res = packet.encode(&mut buffer, 20);
|
||||
assert!(res.is_ok());
|
||||
assert_eq!(res.unwrap(), 20);
|
||||
assert_eq!(
|
||||
buffer,
|
||||
[
|
||||
0x50, 0x12, 0x8A, 0x5C, 0x12, 0x0E, 0x26, 0x00, 0x05, 0x6e, 0x61, 0x6d, 0x65, 0x31,
|
||||
0x00, 0x04, 0x76, 0x61, 0x6c, 0x31
|
||||
]
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_decode() {
|
||||
let buffer: [u8; 20] = [
|
||||
0x50, 0x12, 0x8A, 0x5C, 0x12, 0x0E, 0x26, 0x00, 0x05, 0x6e, 0x61, 0x6d, 0x65, 0x31, 0x00,
|
||||
0x04, 0x76, 0x61, 0x6c, 0x31,
|
||||
];
|
||||
let mut packet = PubrecPacket::<1>::new();
|
||||
let res = packet.decode(&mut BuffReader::new(&buffer, 20));
|
||||
assert!(res.is_ok());
|
||||
assert_eq!(packet.fixed_header, PacketType::Pubrec.into());
|
||||
assert_eq!(packet.remain_len, 18);
|
||||
assert_eq!(packet.packet_identifier, 35420);
|
||||
assert_eq!(packet.reason_code, 0x12);
|
||||
assert_eq!(packet.property_len, 14);
|
||||
let prop = packet.properties.get(0);
|
||||
assert!(prop.is_some());
|
||||
assert_eq!(<&Property as Into<u8>>::into(prop.unwrap()), 0x26);
|
||||
if let Property::UserProperty(u) = (*prop.unwrap()).clone() {
|
||||
assert_eq!(u.name.len, 5);
|
||||
assert_eq!(u.name.string, "name1");
|
||||
assert_eq!(u.value.len, 4);
|
||||
assert_eq!(u.value.string, "val1");
|
||||
}
|
||||
}
|
||||
87
mqtt/src/tests/unit/packet/v5/pubrel_packet_unit.rs
Normal file
87
mqtt/src/tests/unit/packet/v5/pubrel_packet_unit.rs
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* 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::packet::v5::packet_type::PacketType;
|
||||
use crate::packet::v5::property::Property;
|
||||
use crate::packet::v5::pubrel_packet::PubrelPacket;
|
||||
use crate::utils::buffer_reader::BuffReader;
|
||||
use crate::utils::types::{EncodedString, StringPair};
|
||||
use heapless::Vec;
|
||||
|
||||
#[test]
|
||||
fn test_encode() {
|
||||
let mut buffer: [u8; 21] = [0; 21];
|
||||
let mut packet = PubrelPacket::<1>::new();
|
||||
packet.fixed_header = PacketType::Pubrel.into();
|
||||
packet.packet_identifier = 12345;
|
||||
packet.reason_code = 0x86;
|
||||
let mut name = EncodedString::new();
|
||||
name.string = "haha";
|
||||
name.len = 4;
|
||||
let mut val = EncodedString::new();
|
||||
val.string = "hehe89";
|
||||
val.len = 6;
|
||||
let mut pair = StringPair::new();
|
||||
pair.name = name;
|
||||
pair.value = val;
|
||||
let mut props = Vec::<Property, 1>::new();
|
||||
props.push(Property::UserProperty(pair));
|
||||
packet.property_len = packet.add_properties(&props);
|
||||
let res = packet.encode(&mut buffer, 21);
|
||||
assert!(res.is_ok());
|
||||
assert_eq!(res.unwrap(), 21);
|
||||
assert_eq!(
|
||||
buffer,
|
||||
[
|
||||
0x60, 0x13, 0x30, 0x39, 0x86, 0x0F, 0x26, 0x00, 0x04, 0x68, 0x61, 0x68, 0x61, 0x00,
|
||||
0x06, 0x68, 0x65, 0x68, 0x65, 0x38, 0x39
|
||||
]
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_decode() {
|
||||
let buffer: [u8; 21] = [
|
||||
0x60, 0x13, 0x30, 0x39, 0x86, 0x0F, 0x26, 0x00, 0x04, 0x68, 0x61, 0x68, 0x61, 0x00, 0x06,
|
||||
0x68, 0x65, 0x68, 0x65, 0x38, 0x39,
|
||||
];
|
||||
let mut packet = PubrelPacket::<1>::new();
|
||||
let res = packet.decode(&mut BuffReader::new(&buffer, 21));
|
||||
assert!(res.is_ok());
|
||||
assert_eq!(packet.fixed_header, PacketType::Pubrel.into());
|
||||
assert_eq!(packet.remain_len, 19);
|
||||
assert_eq!(packet.packet_identifier, 12345);
|
||||
assert_eq!(packet.reason_code, 0x86);
|
||||
assert_eq!(packet.property_len, 15);
|
||||
let prop = packet.properties.get(0);
|
||||
assert!(prop.is_some());
|
||||
assert_eq!(<&Property as Into<u8>>::into(prop.unwrap()), 0x26);
|
||||
if let Property::UserProperty(u) = (*prop.unwrap()).clone() {
|
||||
assert_eq!(u.name.len, 4);
|
||||
assert_eq!(u.name.string, "haha");
|
||||
assert_eq!(u.value.len, 6);
|
||||
assert_eq!(u.value.string, "hehe89");
|
||||
}
|
||||
}
|
||||
67
mqtt/src/tests/unit/packet/v5/suback_packet_unit.rs
Normal file
67
mqtt/src/tests/unit/packet/v5/suback_packet_unit.rs
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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::packet::v5::packet_type::PacketType;
|
||||
use crate::packet::v5::property::Property;
|
||||
use crate::packet::v5::suback_packet::SubackPacket;
|
||||
use crate::utils::buffer_reader::BuffReader;
|
||||
|
||||
#[test]
|
||||
fn test_decode() {
|
||||
let buffer: [u8; 23] = [
|
||||
0x90, 0x15, 0xCC, 0x08, 0x0F, 0x1F, 0x00, 0x0C, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x53,
|
||||
0x74, 0x72, 0x69, 0x6e, 0x67, 0x12, 0x34, 0x56,
|
||||
];
|
||||
let mut packet = SubackPacket::<3, 1>::new();
|
||||
let res = packet.decode(&mut BuffReader::new(&buffer, 23));
|
||||
assert!(res.is_ok());
|
||||
assert_eq!(packet.fixed_header, PacketType::Suback.into());
|
||||
assert_eq!(packet.remain_len, 21);
|
||||
assert_eq!(packet.packet_identifier, 52232);
|
||||
assert_eq!(packet.property_len, 15);
|
||||
let prop = packet.properties.get(0);
|
||||
assert!(prop.is_some());
|
||||
assert_eq!(<&Property as Into<u8>>::into(prop.unwrap()), 0x1F);
|
||||
if let Property::ReasonString(u) = (*prop.unwrap()).clone() {
|
||||
assert_eq!(u.len, 12);
|
||||
assert_eq!(u.string, "reasonString");
|
||||
}
|
||||
assert_eq!(packet.reason_codes.len(), 3);
|
||||
let res1 = packet.reason_codes.get(0);
|
||||
assert!(res1.is_some());
|
||||
if let Some(r) = res1 {
|
||||
assert_eq!(*r, 0x12);
|
||||
}
|
||||
let res2 = packet.reason_codes.get(1);
|
||||
assert!(res2.is_some());
|
||||
if let Some(r) = res2 {
|
||||
assert_eq!(*r, 0x34);
|
||||
}
|
||||
let res3 = packet.reason_codes.get(2);
|
||||
assert!(res3.is_some());
|
||||
if let Some(r) = res3 {
|
||||
assert_eq!(*r, 0x56);
|
||||
}
|
||||
}
|
||||
54
mqtt/src/tests/unit/packet/v5/subscription_packet_unit.rs
Normal file
54
mqtt/src/tests/unit/packet/v5/subscription_packet_unit.rs
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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::packet::v5::packet_type::PacketType;
|
||||
use crate::packet::v5::property::Property;
|
||||
use crate::packet::v5::publish_packet::QualityOfService::{QoS0, QoS1};
|
||||
use crate::packet::v5::subscription_packet::SubscriptionPacket;
|
||||
use heapless::Vec;
|
||||
|
||||
#[test]
|
||||
fn test_encode() {
|
||||
let mut buffer: [u8; 30] = [0; 30];
|
||||
let mut packet = SubscriptionPacket::<2, 1>::new();
|
||||
packet.fixed_header = PacketType::Subscribe.into();
|
||||
packet.packet_identifier = 5432;
|
||||
let mut props = Vec::<Property, 2>::new();
|
||||
props.push(Property::SubscriptionIdentifier(2432));
|
||||
packet.property_len = packet.add_properties(&props);
|
||||
packet.add_new_filter("test/topic", QoS0);
|
||||
packet.add_new_filter("hehe/#", QoS1);
|
||||
let res = packet.encode(&mut buffer, 30);
|
||||
assert!(res.is_ok());
|
||||
assert_eq!(res.unwrap(), 30);
|
||||
assert_eq!(
|
||||
buffer,
|
||||
[
|
||||
0x82, 0x1C, 0x15, 0x38, 0x03, 0x0B, 0x80, 0x13, 0x00, 0x0A, 0x74, 0x65, 0x73, 0x74,
|
||||
0x2f, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x00, 0x00, 0x06, 0x68, 0x65, 0x68, 0x65, 0x2F,
|
||||
0x23, 0x01
|
||||
]
|
||||
);
|
||||
}
|
||||
62
mqtt/src/tests/unit/packet/v5/unsuback_packet_unit.rs
Normal file
62
mqtt/src/tests/unit/packet/v5/unsuback_packet_unit.rs
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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::packet::v5::packet_type::PacketType;
|
||||
use crate::packet::v5::property::Property;
|
||||
use crate::packet::v5::unsuback_packet::UnsubackPacket;
|
||||
use crate::utils::buffer_reader::BuffReader;
|
||||
|
||||
#[test]
|
||||
fn test_decode() {
|
||||
let buffer: [u8; 22] = [
|
||||
0xB0, 0x14, 0xCC, 0x08, 0x0F, 0x1F, 0x00, 0x0C, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x53,
|
||||
0x74, 0x72, 0x69, 0x6e, 0x67, 0x77, 0x55,
|
||||
];
|
||||
let mut packet = UnsubackPacket::<2, 1>::new();
|
||||
let res = packet.decode(&mut BuffReader::new(&buffer, 22));
|
||||
assert!(res.is_ok());
|
||||
assert_eq!(packet.fixed_header, PacketType::Unsuback.into());
|
||||
assert_eq!(packet.remain_len, 20);
|
||||
assert_eq!(packet.packet_identifier, 52232);
|
||||
assert_eq!(packet.property_len, 15);
|
||||
let prop = packet.properties.get(0);
|
||||
assert!(prop.is_some());
|
||||
assert_eq!(<&Property as Into<u8>>::into(prop.unwrap()), 0x1F);
|
||||
if let Property::ReasonString(u) = (*prop.unwrap()).clone() {
|
||||
assert_eq!(u.len, 12);
|
||||
assert_eq!(u.string, "reasonString");
|
||||
}
|
||||
assert_eq!(packet.reason_codes.len(), 2);
|
||||
let res1 = packet.reason_codes.get(0);
|
||||
assert!(res1.is_some());
|
||||
if let Some(r) = res1 {
|
||||
assert_eq!(*r, 0x77);
|
||||
}
|
||||
let res2 = packet.reason_codes.get(1);
|
||||
assert!(res2.is_some());
|
||||
if let Some(r) = res2 {
|
||||
assert_eq!(*r, 0x55);
|
||||
}
|
||||
}
|
||||
64
mqtt/src/tests/unit/packet/v5/unsubscription_packet_unit.rs
Normal file
64
mqtt/src/tests/unit/packet/v5/unsubscription_packet_unit.rs
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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::packet::v5::packet_type::PacketType;
|
||||
use crate::packet::v5::property::Property;
|
||||
use crate::packet::v5::publish_packet::QualityOfService::{QoS0, QoS1};
|
||||
use crate::packet::v5::unsubscription_packet::UnsubscriptionPacket;
|
||||
use crate::utils::types::{EncodedString, StringPair};
|
||||
use heapless::Vec;
|
||||
|
||||
#[test]
|
||||
fn test_encode() {
|
||||
let mut buffer: [u8; 40] = [0; 40];
|
||||
let mut packet = UnsubscriptionPacket::<2, 1>::new();
|
||||
packet.fixed_header = PacketType::Unsubscribe.into();
|
||||
packet.packet_identifier = 5432;
|
||||
let mut name = EncodedString::new();
|
||||
name.string = "haha";
|
||||
name.len = 4;
|
||||
let mut val = EncodedString::new();
|
||||
val.string = "hehe89";
|
||||
val.len = 6;
|
||||
let mut pair = StringPair::new();
|
||||
pair.name = name;
|
||||
pair.value = val;
|
||||
let mut props = Vec::<Property, 1>::new();
|
||||
props.push(Property::UserProperty(pair));
|
||||
packet.property_len = packet.add_properties(&props);
|
||||
packet.add_new_filter("test/topic", QoS0);
|
||||
packet.add_new_filter("hehe/#", QoS1);
|
||||
let res = packet.encode(&mut buffer, 40);
|
||||
assert!(res.is_ok());
|
||||
assert_eq!(res.unwrap(), 40);
|
||||
assert_eq!(
|
||||
buffer,
|
||||
[
|
||||
0xA0, 0x26, 0x15, 0x38, 0x0F, 0x26, 0x00, 0x04, 0x68, 0x61, 0x68, 0x61, 0x00, 0x06,
|
||||
0x68, 0x65, 0x68, 0x65, 0x38, 0x39, 0x00, 0x0A, 0x74, 0x65, 0x73, 0x74, 0x2F, 0x74,
|
||||
0x6F, 0x70, 0x69, 0x63, 0x00, 0x06, 0x68, 0x65, 0x68, 0x65, 0x2F, 0x23
|
||||
]
|
||||
);
|
||||
}
|
||||
235
mqtt/src/tests/unit/utils/buffer_reader_unit.rs
Normal file
235
mqtt/src/tests/unit/utils/buffer_reader_unit.rs
Normal file
@@ -0,0 +1,235 @@
|
||||
/*
|
||||
* 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::utils::buffer_reader::BuffReader;
|
||||
use crate::utils::types::BufferError;
|
||||
|
||||
#[test]
|
||||
fn buffer_read_variable_byte() {
|
||||
static BUFFER: [u8; 5] = [0x82, 0x82, 0x03, 0x85, 0x84];
|
||||
let mut reader: BuffReader = BuffReader::new(&BUFFER, 5);
|
||||
let test_number = reader.read_variable_byte_int();
|
||||
assert!(test_number.is_ok());
|
||||
assert_eq!(reader.position, 3);
|
||||
assert_eq!(test_number.unwrap(), 49410);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn buffer_read_invalid_size() {
|
||||
static BUFFER: [u8; 2] = [0x82, 0x82];
|
||||
let mut reader: BuffReader = BuffReader::new(&BUFFER, 2);
|
||||
let test_number = reader.read_variable_byte_int();
|
||||
assert!(test_number.is_err());
|
||||
assert_eq!(
|
||||
test_number.unwrap_err(),
|
||||
BufferError::InsufficientBufferSize
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_smaller_var_int() {
|
||||
static BUFFER: [u8; 2] = [0x82, 0x02];
|
||||
let mut reader: BuffReader = BuffReader::new(&BUFFER, 2);
|
||||
let test_number = reader.read_variable_byte_int();
|
||||
assert!(test_number.is_ok());
|
||||
assert_eq!(reader.position, 2);
|
||||
assert_eq!(test_number.unwrap(), 258);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_complete_var_int() {
|
||||
static BUFFER: [u8; 4] = [0x81, 0x81, 0x81, 0x01];
|
||||
let mut reader: BuffReader = BuffReader::new(&BUFFER, 4);
|
||||
let test_number = reader.read_variable_byte_int();
|
||||
assert!(test_number.is_ok());
|
||||
assert_eq!(reader.position, 4);
|
||||
assert_eq!(test_number.unwrap(), 2113665);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_var_empty_buffer() {
|
||||
static BUFFER: [u8; 0] = [];
|
||||
let mut reader: BuffReader = BuffReader::new(&BUFFER, 0);
|
||||
let test_number = reader.read_variable_byte_int();
|
||||
assert!(test_number.is_err());
|
||||
assert_eq!(
|
||||
test_number.unwrap_err(),
|
||||
BufferError::InsufficientBufferSize
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_read_u32() {
|
||||
static BUFFER: [u8; 4] = [0x00, 0x02, 0x5E, 0xC1];
|
||||
let mut reader: BuffReader = BuffReader::new(&BUFFER, 4);
|
||||
let test_number = reader.read_u32();
|
||||
assert!(test_number.is_ok());
|
||||
assert_eq!(test_number.unwrap(), 155329);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_read_u32_oob() {
|
||||
static BUFFER: [u8; 3] = [0x00, 0x02, 0x5E];
|
||||
let mut reader: BuffReader = BuffReader::new(&BUFFER, 3);
|
||||
let test_number = reader.read_u32();
|
||||
assert!(test_number.is_err());
|
||||
assert_eq!(
|
||||
test_number.unwrap_err(),
|
||||
BufferError::InsufficientBufferSize
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_read_u16() {
|
||||
static BUFFER: [u8; 2] = [0x48, 0x5F];
|
||||
let mut reader: BuffReader = BuffReader::new(&BUFFER, 2);
|
||||
let test_number = reader.read_u16();
|
||||
assert!(test_number.is_ok());
|
||||
assert_eq!(test_number.unwrap(), 18527);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_read_u16_oob() {
|
||||
static BUFFER: [u8; 1] = [0x5E];
|
||||
let mut reader: BuffReader = BuffReader::new(&BUFFER, 1);
|
||||
let test_number = reader.read_u16();
|
||||
assert!(test_number.is_err());
|
||||
assert_eq!(
|
||||
test_number.unwrap_err(),
|
||||
BufferError::InsufficientBufferSize
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_read_u8() {
|
||||
static BUFFER: [u8; 1] = [0xFD];
|
||||
let mut reader: BuffReader = BuffReader::new(&BUFFER, 1);
|
||||
let test_number = reader.read_u8();
|
||||
assert!(test_number.is_ok());
|
||||
assert_eq!(test_number.unwrap(), 253);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_read_u8_oob() {
|
||||
static BUFFER: [u8; 0] = [];
|
||||
let mut reader: BuffReader = BuffReader::new(&BUFFER, 0);
|
||||
let test_number = reader.read_u8();
|
||||
assert!(test_number.is_err());
|
||||
assert_eq!(
|
||||
test_number.unwrap_err(),
|
||||
BufferError::InsufficientBufferSize
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_read_string() {
|
||||
static BUFFER: [u8; 6] = [0x00, 0x04, 0xF0, 0x9F, 0x92, 0x96];
|
||||
let mut reader: BuffReader = BuffReader::new(&BUFFER, 6);
|
||||
let test_string = reader.read_string();
|
||||
assert!(test_string.is_ok());
|
||||
let unw = test_string.unwrap();
|
||||
assert_eq!(unw.string, "💖");
|
||||
assert_eq!(unw.len, 4);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_read_string_utf8_wrong() {
|
||||
static BUFFER: [u8; 5] = [0x00, 0x03, 0xF0, 0x9F, 0x92];
|
||||
let mut reader: BuffReader = BuffReader::new(&BUFFER, 5);
|
||||
let test_string = reader.read_string();
|
||||
assert!(test_string.is_err());
|
||||
assert_eq!(test_string.unwrap_err(), BufferError::Utf8Error);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_read_string_oob() {
|
||||
static BUFFER: [u8; 5] = [0x00, 0x04, 0xF0, 0x9F, 0x92];
|
||||
let mut reader: BuffReader = BuffReader::new(&BUFFER, 5);
|
||||
let test_string = reader.read_string();
|
||||
assert!(test_string.is_err());
|
||||
assert_eq!(
|
||||
test_string.unwrap_err(),
|
||||
BufferError::InsufficientBufferSize
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_read_binary() {
|
||||
static BUFFER: [u8; 6] = [0x00, 0x04, 0xFF, 0xEE, 0xDD, 0xCC];
|
||||
let mut reader: BuffReader = BuffReader::new(&BUFFER, 6);
|
||||
let test_bin = reader.read_binary();
|
||||
assert!(test_bin.is_ok());
|
||||
let unw = test_bin.unwrap();
|
||||
assert_eq!(unw.bin, [0xFF, 0xEE, 0xDD, 0xCC]);
|
||||
assert_eq!(unw.len, 4);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_read_binary_oob() {
|
||||
static BUFFER: [u8; 5] = [0x00, 0x04, 0xFF, 0xEE, 0xDD];
|
||||
let mut reader: BuffReader = BuffReader::new(&BUFFER, 5);
|
||||
let test_bin = reader.read_binary();
|
||||
assert!(test_bin.is_err());
|
||||
assert_eq!(test_bin.unwrap_err(), BufferError::InsufficientBufferSize);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_read_string_pair() {
|
||||
static BUFFER: [u8; 11] = [
|
||||
0x00, 0x04, 0xF0, 0x9F, 0x98, 0x8E, 0x00, 0x03, 0xE2, 0x93, 0x87,
|
||||
];
|
||||
let mut reader: BuffReader = BuffReader::new(&BUFFER, 11);
|
||||
let string_pair = reader.read_string_pair();
|
||||
assert!(string_pair.is_ok());
|
||||
let unw = string_pair.unwrap();
|
||||
assert_eq!(unw.name.string, "😎");
|
||||
assert_eq!(unw.name.len, 4);
|
||||
assert_eq!(unw.value.string, "Ⓡ");
|
||||
assert_eq!(unw.value.len, 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_read_string_pair_wrong_utf8() {
|
||||
static BUFFER: [u8; 11] = [
|
||||
0x00, 0x03, 0xF0, 0x9F, 0x92, 0x00, 0x04, 0xF0, 0x9F, 0x98, 0x8E,
|
||||
];
|
||||
let mut reader: BuffReader = BuffReader::new(&BUFFER, 11);
|
||||
let string_pair = reader.read_string_pair();
|
||||
assert!(string_pair.is_err());
|
||||
assert_eq!(string_pair.unwrap_err(), BufferError::Utf8Error)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_read_string_pair_oob() {
|
||||
static BUFFER: [u8; 11] = [
|
||||
0x00, 0x04, 0xF0, 0x9F, 0x98, 0x8E, 0x00, 0x04, 0xE2, 0x93, 0x87,
|
||||
];
|
||||
let mut reader: BuffReader = BuffReader::new(&BUFFER, 11);
|
||||
let string_pair = reader.read_string_pair();
|
||||
assert!(string_pair.is_err());
|
||||
assert_eq!(
|
||||
string_pair.unwrap_err(),
|
||||
BufferError::InsufficientBufferSize
|
||||
);
|
||||
}
|
||||
381
mqtt/src/tests/unit/utils/buffer_writer_unit.rs
Normal file
381
mqtt/src/tests/unit/utils/buffer_writer_unit.rs
Normal file
@@ -0,0 +1,381 @@
|
||||
/*
|
||||
* 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::property::Property;
|
||||
use crate::utils::buffer_writer::BuffWriter;
|
||||
use crate::utils::types::{BinaryData, BufferError, EncodedString, StringPair, TopicFilter};
|
||||
use heapless::Vec;
|
||||
|
||||
#[test]
|
||||
fn buffer_write_ref() {
|
||||
static BUFFER: [u8; 5] = [0x82, 0x82, 0x03, 0x85, 0x84];
|
||||
let mut res_buffer: [u8; 5] = [0; 5];
|
||||
|
||||
let mut writer: BuffWriter = BuffWriter::new(&mut res_buffer, 5);
|
||||
let test_write = writer.insert_ref(5, &BUFFER);
|
||||
assert!(test_write.is_ok());
|
||||
assert_eq!(writer.position, 5);
|
||||
assert_eq!(BUFFER, res_buffer);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn buffer_write_ref_oob() {
|
||||
static BUFFER: [u8; 5] = [0x82, 0x82, 0x03, 0x85, 0x84];
|
||||
let mut res_buffer: [u8; 4] = [0; 4];
|
||||
|
||||
let mut writer: BuffWriter = BuffWriter::new(&mut res_buffer, 4);
|
||||
let test_number = writer.insert_ref(5, &BUFFER);
|
||||
assert!(test_number.is_err());
|
||||
assert_eq!(
|
||||
test_number.unwrap_err(),
|
||||
BufferError::InsufficientBufferSize
|
||||
);
|
||||
assert_eq!(res_buffer, [0; 4])
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn buffer_write_u8() {
|
||||
let mut res_buffer: [u8; 1] = [0; 1];
|
||||
|
||||
let mut writer: BuffWriter = BuffWriter::new(&mut res_buffer, 1);
|
||||
let test_write = writer.write_u8(0xFA);
|
||||
assert!(test_write.is_ok());
|
||||
assert_eq!(writer.position, 1);
|
||||
assert_eq!(res_buffer, [0xFA]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn buffer_write_u8_oob() {
|
||||
let mut res_buffer: [u8; 0] = [];
|
||||
|
||||
let mut writer: BuffWriter = BuffWriter::new(&mut res_buffer, 0);
|
||||
let test_number = writer.write_u8(0xFA);
|
||||
assert!(test_number.is_err());
|
||||
assert_eq!(
|
||||
test_number.unwrap_err(),
|
||||
BufferError::InsufficientBufferSize
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn buffer_write_u16() {
|
||||
let mut res_buffer: [u8; 2] = [0; 2];
|
||||
|
||||
let mut writer: BuffWriter = BuffWriter::new(&mut res_buffer, 2);
|
||||
let test_write = writer.write_u16(0xFAED);
|
||||
assert!(test_write.is_ok());
|
||||
assert_eq!(writer.position, 2);
|
||||
assert_eq!(res_buffer, [0xFA, 0xED]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn buffer_write_u16_oob() {
|
||||
let mut res_buffer: [u8; 1] = [0; 1];
|
||||
|
||||
let mut writer: BuffWriter = BuffWriter::new(&mut res_buffer, 1);
|
||||
let test_number = writer.write_u16(0xFAED);
|
||||
assert!(test_number.is_err());
|
||||
assert_eq!(
|
||||
test_number.unwrap_err(),
|
||||
BufferError::InsufficientBufferSize
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn buffer_write_u32() {
|
||||
let mut res_buffer: [u8; 4] = [0; 4];
|
||||
|
||||
let mut writer: BuffWriter = BuffWriter::new(&mut res_buffer, 4);
|
||||
let test_write = writer.write_u32(0xFAEDCC09);
|
||||
assert!(test_write.is_ok());
|
||||
assert_eq!(writer.position, 4);
|
||||
assert_eq!(res_buffer, [0xFA, 0xED, 0xCC, 0x09]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn buffer_write_u32_oob() {
|
||||
let mut res_buffer: [u8; 3] = [0; 3];
|
||||
|
||||
let mut writer: BuffWriter = BuffWriter::new(&mut res_buffer, 3);
|
||||
let test_number = writer.write_u32(0xFAEDCC08);
|
||||
assert!(test_number.is_err());
|
||||
assert_eq!(
|
||||
test_number.unwrap_err(),
|
||||
BufferError::InsufficientBufferSize
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn buffer_write_string() {
|
||||
let mut res_buffer: [u8; 6] = [0; 6];
|
||||
let mut string = EncodedString::new();
|
||||
string.string = "😎";
|
||||
string.len = 4;
|
||||
let mut writer: BuffWriter = BuffWriter::new(&mut res_buffer, 6);
|
||||
let test_write = writer.write_string_ref(&string);
|
||||
assert!(test_write.is_ok());
|
||||
assert_eq!(writer.position, 6);
|
||||
assert_eq!(res_buffer, [0x00, 0x04, 0xF0, 0x9F, 0x98, 0x8E]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn buffer_write_string_oob() {
|
||||
let mut res_buffer: [u8; 5] = [0; 5];
|
||||
let mut string = EncodedString::new();
|
||||
string.string = "😎";
|
||||
string.len = 4;
|
||||
let mut writer: BuffWriter = BuffWriter::new(&mut res_buffer, 5);
|
||||
let test_write = writer.write_string_ref(&string);
|
||||
assert!(test_write.is_err());
|
||||
assert_eq!(test_write.unwrap_err(), BufferError::InsufficientBufferSize);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn buffer_write_bin() {
|
||||
let mut res_buffer: [u8; 6] = [0; 6];
|
||||
let mut bin = BinaryData::new();
|
||||
bin.bin = &[0xAB, 0xEF, 0x88, 0x43];
|
||||
bin.len = 4;
|
||||
let mut writer: BuffWriter = BuffWriter::new(&mut res_buffer, 6);
|
||||
let test_write = writer.write_binary_ref(&bin);
|
||||
assert!(test_write.is_ok());
|
||||
assert_eq!(writer.position, 6);
|
||||
assert_eq!(res_buffer, [0x00, 0x04, 0xAB, 0xEF, 0x88, 0x43]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn buffer_write_bin_oob() {
|
||||
let mut res_buffer: [u8; 6] = [0; 6];
|
||||
let mut bin = BinaryData::new();
|
||||
bin.bin = &[0xAB, 0xEF, 0x88, 0x43];
|
||||
bin.len = 4;
|
||||
let mut writer: BuffWriter = BuffWriter::new(&mut res_buffer, 5);
|
||||
let test_write = writer.write_binary_ref(&bin);
|
||||
assert!(test_write.is_err());
|
||||
assert_eq!(test_write.unwrap_err(), BufferError::InsufficientBufferSize);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn buffer_write_string_pair() {
|
||||
let mut res_buffer: [u8; 12] = [0; 12];
|
||||
let mut name = EncodedString::new();
|
||||
name.string = "Name";
|
||||
name.len = 4;
|
||||
|
||||
let mut value = EncodedString::new();
|
||||
value.string = "😎";
|
||||
value.len = 4;
|
||||
let mut pair = StringPair::new();
|
||||
pair.name = name;
|
||||
pair.value = value;
|
||||
let mut writer: BuffWriter = BuffWriter::new(&mut res_buffer, 12);
|
||||
let test_write = writer.write_string_pair_ref(&pair);
|
||||
assert!(test_write.is_ok());
|
||||
assert_eq!(writer.position, 12);
|
||||
assert_eq!(
|
||||
res_buffer,
|
||||
[0x00, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x00, 0x04, 0xF0, 0x9F, 0x98, 0x8E]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn buffer_write_string_pair_oob() {
|
||||
let mut res_buffer: [u8; 12] = [0; 12];
|
||||
let mut name = EncodedString::new();
|
||||
name.string = "Name";
|
||||
name.len = 4;
|
||||
|
||||
let mut value = EncodedString::new();
|
||||
value.string = "😎";
|
||||
value.len = 4;
|
||||
let mut pair = StringPair::new();
|
||||
pair.name = name;
|
||||
pair.value = value;
|
||||
let mut writer: BuffWriter = BuffWriter::new(&mut res_buffer, 10);
|
||||
let test_write = writer.write_string_pair_ref(&pair);
|
||||
assert!(test_write.is_err());
|
||||
assert_eq!(test_write.unwrap_err(), BufferError::InsufficientBufferSize)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn buffer_write_var_byte() {
|
||||
let mut res_buffer: [u8; 2] = [0; 2];
|
||||
|
||||
let mut writer: BuffWriter = BuffWriter::new(&mut res_buffer, 2);
|
||||
let test_write = writer.write_variable_byte_int(512);
|
||||
assert!(test_write.is_ok());
|
||||
assert_eq!(writer.position, 2);
|
||||
assert_eq!(res_buffer, [0x80, 0x04]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn buffer_write_var_byte_oob() {
|
||||
let mut res_buffer: [u8; 2] = [0; 2];
|
||||
|
||||
let mut writer: BuffWriter = BuffWriter::new(&mut res_buffer, 2);
|
||||
let test_number = writer.write_variable_byte_int(453123);
|
||||
assert!(test_number.is_err());
|
||||
assert_eq!(
|
||||
test_number.unwrap_err(),
|
||||
BufferError::InsufficientBufferSize
|
||||
);
|
||||
}
|
||||
|
||||
/*#[test]
|
||||
fn buffer_write_property() {
|
||||
let mut res_buffer: [u8; 7] = [0; 7];
|
||||
let mut topic = EncodedString::new();
|
||||
topic.string = "Name";
|
||||
topic.len = 4;
|
||||
let prop = Property::ResponseTopic(topic);
|
||||
let mut writer: BuffWriter = BuffWriter::new(& mut res_buffer, 7);
|
||||
let test_write = writer.write_property(&prop);
|
||||
assert!(test_write.is_ok());
|
||||
assert_eq!(writer.position, 7);
|
||||
assert_eq!(res_buffer, [0x08, 0x00, 0x04, 0x4e, 0x61, 0x6d, 0x65]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn buffer_write_property_oob() {
|
||||
let mut res_buffer: [u8; 7] = [0; 7];
|
||||
let mut topic = EncodedString::new();
|
||||
topic.string = "Name";
|
||||
topic.len = 4;
|
||||
let prop = Property::ResponseTopic(topic);
|
||||
let mut writer: BuffWriter = BuffWriter::new(& mut res_buffer, 4);
|
||||
let test_write = writer.write_property(&prop);
|
||||
assert!(test_write.is_err());
|
||||
assert_eq!(test_write.unwrap_err(), BufferError::InsufficientBufferSize);
|
||||
}*/
|
||||
|
||||
#[test]
|
||||
fn buffer_write_properties() {
|
||||
let mut res_buffer: [u8; 13] = [0; 13];
|
||||
let mut topic = EncodedString::new();
|
||||
topic.string = "Name";
|
||||
topic.len = 4;
|
||||
let prop = Property::ResponseTopic(topic);
|
||||
let mut corr = BinaryData::new();
|
||||
corr.bin = &[0x12, 0x34, 0x56];
|
||||
corr.len = 3;
|
||||
let prop2 = Property::CorrelationData(corr);
|
||||
let mut properties = Vec::<Property, 2>::new();
|
||||
properties.push(prop);
|
||||
properties.push(prop2);
|
||||
let mut writer: BuffWriter = BuffWriter::new(&mut res_buffer, 13);
|
||||
let test_write = writer.write_properties(&properties);
|
||||
assert!(test_write.is_ok());
|
||||
assert_eq!(writer.position, 13);
|
||||
assert_eq!(
|
||||
res_buffer,
|
||||
[0x08, 0x00, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x09, 0x00, 0x03, 0x12, 0x34, 0x56]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn buffer_write_properties_oob() {
|
||||
let mut res_buffer: [u8; 10] = [0; 10];
|
||||
let mut topic = EncodedString::new();
|
||||
topic.string = "Name";
|
||||
topic.len = 4;
|
||||
let prop = Property::ResponseTopic(topic);
|
||||
let mut corr = BinaryData::new();
|
||||
corr.bin = &[0x12, 0x34, 0x56];
|
||||
corr.len = 3;
|
||||
let prop2 = Property::CorrelationData(corr);
|
||||
let mut properties = Vec::<Property, 2>::new();
|
||||
properties.push(prop);
|
||||
properties.push(prop2);
|
||||
let mut writer: BuffWriter = BuffWriter::new(&mut res_buffer, 10);
|
||||
let test_write = writer.write_properties(&properties);
|
||||
assert!(test_write.is_err());
|
||||
assert_eq!(test_write.unwrap_err(), BufferError::InsufficientBufferSize);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn buffer_write_filters() {
|
||||
let mut res_buffer: [u8; 15] = [0; 15];
|
||||
static STR1: &str = "test";
|
||||
static STR2: &str = "topic";
|
||||
let mut topic = EncodedString::new();
|
||||
topic.string = STR1;
|
||||
topic.len = 4;
|
||||
|
||||
let mut topic2 = EncodedString::new();
|
||||
topic2.string = STR2;
|
||||
topic2.len = 5;
|
||||
|
||||
let mut filter1 = TopicFilter::new();
|
||||
filter1.filter = topic;
|
||||
filter1.sub_options = 0xAE;
|
||||
|
||||
let mut filter2 = TopicFilter::new();
|
||||
filter2.filter = topic2;
|
||||
filter2.sub_options = 0x22;
|
||||
|
||||
let mut filters = Vec::<TopicFilter, 2>::new();
|
||||
filters.push(filter1);
|
||||
filters.push(filter2);
|
||||
let mut writer: BuffWriter = BuffWriter::new(&mut res_buffer, 15);
|
||||
let test_write = writer.write_topic_filters_ref(true, 2, &filters);
|
||||
assert!(test_write.is_ok());
|
||||
assert_eq!(writer.position, 15);
|
||||
assert_eq!(
|
||||
res_buffer,
|
||||
[
|
||||
0x00, 0x04, 0x74, 0x65, 0x73, 0x74, 0xAE, 0x00, 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63,
|
||||
0x22
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn buffer_write_filters_oob() {
|
||||
let mut res_buffer: [u8; 15] = [0; 15];
|
||||
static STR1: &str = "test";
|
||||
static STR2: &str = "topic";
|
||||
let mut topic = EncodedString::new();
|
||||
topic.string = STR1;
|
||||
topic.len = 4;
|
||||
|
||||
let mut topic2 = EncodedString::new();
|
||||
topic2.string = STR2;
|
||||
topic2.len = 5;
|
||||
|
||||
let mut filter1 = TopicFilter::new();
|
||||
filter1.filter = topic;
|
||||
filter1.sub_options = 0xAE;
|
||||
|
||||
let mut filter2 = TopicFilter::new();
|
||||
filter2.filter = topic2;
|
||||
filter2.sub_options = 0x22;
|
||||
|
||||
let mut filters = Vec::<TopicFilter, 2>::new();
|
||||
filters.push(filter1);
|
||||
filters.push(filter2);
|
||||
let mut writer: BuffWriter = BuffWriter::new(&mut res_buffer, 5);
|
||||
let test_write = writer.write_topic_filters_ref(true, 2, &filters);
|
||||
assert!(test_write.is_err());
|
||||
assert_eq!(test_write.unwrap_err(), BufferError::InsufficientBufferSize)
|
||||
}
|
||||
26
mqtt/src/tests/unit/utils/mod.rs
Normal file
26
mqtt/src/tests/unit/utils/mod.rs
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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 buffer_reader_unit;
|
||||
pub mod buffer_writer_unit;
|
||||
31
mqtt/src/tokio_net/mod.rs
Normal file
31
mqtt/src/tokio_net/mod.rs
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#![feature(in_band_lifetimes)]
|
||||
#![macro_use]
|
||||
#![allow(dead_code)]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
#![feature(generic_associated_types)]
|
||||
#[cfg(feature = "tokio")]
|
||||
pub mod tokio_network;
|
||||
145
mqtt/src/tokio_net/tokio_network.rs
Normal file
145
mqtt/src/tokio_net/tokio_network.rs
Normal file
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
extern crate alloc;
|
||||
use alloc::format;
|
||||
use alloc::string::String;
|
||||
use core::future::Future;
|
||||
use core::time::Duration;
|
||||
|
||||
use crate::network::network_trait::{NetworkConnection, NetworkConnectionFactory};
|
||||
use crate::packet::v5::reason_codes::ReasonCode;
|
||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||
use tokio::net::TcpStream;
|
||||
use tokio::time::sleep;
|
||||
|
||||
pub struct TokioNetwork {
|
||||
stream: Option<TcpStream>,
|
||||
}
|
||||
|
||||
impl TokioNetwork {
|
||||
pub fn new(stream: TcpStream) -> Self {
|
||||
Self {
|
||||
stream: Some(stream),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn convert_ip(ip: [u8; 4], port: u16) -> String {
|
||||
String::from(format!("{}.{}.{}.{}:{}", ip[0], ip[1], ip[2], ip[3], port))
|
||||
}
|
||||
}
|
||||
|
||||
impl NetworkConnection for TokioNetwork {
|
||||
type WriteFuture<'m>
|
||||
where
|
||||
Self: 'm,
|
||||
= impl Future<Output = Result<(), ReasonCode>> + 'm;
|
||||
|
||||
type ReadFuture<'m>
|
||||
where
|
||||
Self: 'm,
|
||||
= impl Future<Output = Result<usize, ReasonCode>> + 'm;
|
||||
|
||||
type CloseFuture<'m>
|
||||
where
|
||||
Self: 'm,
|
||||
= impl Future<Output = Result<(), ReasonCode>> + 'm;
|
||||
|
||||
/*type TimerFuture<'m>
|
||||
where
|
||||
Self: 'm,
|
||||
= impl Future<Output = ()>;*/
|
||||
|
||||
fn send<'m>(&'m mut self, buffer: &'m mut [u8], len: usize) -> Self::WriteFuture<'m> {
|
||||
async move {
|
||||
return if let Some(ref mut stream) = self.stream {
|
||||
stream
|
||||
.write_all(&buffer[0..len])
|
||||
.await
|
||||
.map_err(|_| ReasonCode::NetworkError)
|
||||
} else {
|
||||
Err(ReasonCode::NetworkError)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn receive<'m>(&'m mut self, buffer: &'m mut [u8]) -> Self::ReadFuture<'m> {
|
||||
async move {
|
||||
return if let Some(ref mut stream) = self.stream {
|
||||
stream
|
||||
.read(buffer)
|
||||
.await
|
||||
.map_err(|_| ReasonCode::NetworkError)
|
||||
} else {
|
||||
Err(ReasonCode::NetworkError)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn close<'m>(mut self) -> Self::CloseFuture<'m> {
|
||||
async move {
|
||||
return if let Some(ref mut stream) = self.stream {
|
||||
stream
|
||||
.shutdown()
|
||||
.await
|
||||
.map_err(|_| ReasonCode::NetworkError)
|
||||
} else {
|
||||
Err(ReasonCode::NetworkError)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/*fn count_down(&'m mut self, time_in_secs: u64) -> Self::TimerFuture<'m> {
|
||||
async move {
|
||||
return sleep(Duration::from_secs(time_in_secs))
|
||||
.await
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
pub struct TokioNetworkFactory {}
|
||||
|
||||
impl TokioNetworkFactory {
|
||||
pub fn new() -> Self {
|
||||
Self {}
|
||||
}
|
||||
}
|
||||
|
||||
impl NetworkConnectionFactory for TokioNetworkFactory {
|
||||
type Connection = TokioNetwork;
|
||||
|
||||
type ConnectionFuture<'m>
|
||||
where
|
||||
Self: 'm,
|
||||
= impl Future<Output = Result<TokioNetwork, ReasonCode>> + 'm;
|
||||
|
||||
fn connect<'m>(&'m mut self, ip: [u8; 4], port: u16) -> Self::ConnectionFuture<'m> {
|
||||
async move {
|
||||
let stream = TcpStream::connect(TokioNetwork::convert_ip(ip, port))
|
||||
.await
|
||||
.map_err(|_| ReasonCode::NetworkError)?;
|
||||
Ok(TokioNetwork::new(stream))
|
||||
}
|
||||
}
|
||||
}
|
||||
168
mqtt/src/utils/buffer_reader.rs
Normal file
168
mqtt/src/utils/buffer_reader.rs
Normal file
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* 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::mem;
|
||||
use core::str;
|
||||
|
||||
use crate::encoding::variable_byte_integer::VariableByteIntegerDecoder;
|
||||
use crate::utils::types::{BinaryData, BufferError, EncodedString, StringPair};
|
||||
|
||||
/// Buff reader is reading corresponding types from buffer (Byte array) and stores current position
|
||||
/// (later as cursor)
|
||||
pub struct BuffReader<'a> {
|
||||
buffer: &'a [u8],
|
||||
pub position: usize,
|
||||
len: usize,
|
||||
}
|
||||
|
||||
impl<'a> BuffReader<'a> {
|
||||
pub fn increment_position(&mut self, increment: usize) {
|
||||
self.position = self.position + increment;
|
||||
}
|
||||
|
||||
pub fn new(buffer: &'a [u8], buff_len: usize) -> Self {
|
||||
return BuffReader {
|
||||
buffer,
|
||||
position: 0,
|
||||
len: buff_len,
|
||||
};
|
||||
}
|
||||
|
||||
/// Variable byte integer can be 1-4 Bytes long. Buffer reader takes all 4 Bytes at first and
|
||||
/// than check what is true length of varbyteint and increment cursor by that
|
||||
pub fn read_variable_byte_int(&mut self) -> Result<u32, BufferError> {
|
||||
let mut variable_byte_integer: [u8; 4] = [0; 4];
|
||||
let mut len: usize = 1;
|
||||
|
||||
// Everytime checking first bit of Byte which determines whenever there is continuous Byte
|
||||
let mut x = 0;
|
||||
loop {
|
||||
if x >= 4 {
|
||||
break;
|
||||
}
|
||||
if self.position + x >= self.len {
|
||||
return Err(BufferError::InsufficientBufferSize);
|
||||
}
|
||||
if self.buffer[self.position + x] & 0x80 != 0 {
|
||||
variable_byte_integer[x] = self.buffer[self.position + x];
|
||||
len = len + 1
|
||||
} else {
|
||||
variable_byte_integer[x] = self.buffer[self.position + x];
|
||||
x = x + 1;
|
||||
if x != 4 {
|
||||
loop {
|
||||
variable_byte_integer[x] = 0;
|
||||
x = x + 1;
|
||||
if x == 4 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
x = x + 1;
|
||||
}
|
||||
self.increment_position(len);
|
||||
return VariableByteIntegerDecoder::decode(variable_byte_integer);
|
||||
}
|
||||
|
||||
/// Reading u32 from buffer as `Big endian`
|
||||
pub fn read_u32(&mut self) -> Result<u32, BufferError> {
|
||||
if self.position + 4 > self.len {
|
||||
return Err(BufferError::InsufficientBufferSize);
|
||||
}
|
||||
let (int_bytes, _rest) = self.buffer[self.position..].split_at(mem::size_of::<u32>());
|
||||
let ret: u32 = u32::from_be_bytes(int_bytes.try_into().unwrap());
|
||||
self.increment_position(4);
|
||||
return Ok(ret);
|
||||
}
|
||||
|
||||
/// Reading u16 from buffer as `Big endinan`
|
||||
pub fn read_u16(&mut self) -> Result<u16, BufferError> {
|
||||
if self.position + 2 > self.len {
|
||||
return Err(BufferError::InsufficientBufferSize);
|
||||
}
|
||||
let (int_bytes, _rest) = self.buffer[self.position..].split_at(mem::size_of::<u16>());
|
||||
let ret: u16 = u16::from_be_bytes(int_bytes.try_into().unwrap());
|
||||
self.increment_position(2);
|
||||
return Ok(ret);
|
||||
}
|
||||
|
||||
/// Reading one byte from buffer as `Big endian`
|
||||
pub fn read_u8(&mut self) -> Result<u8, BufferError> {
|
||||
if self.position >= self.len {
|
||||
return Err(BufferError::InsufficientBufferSize);
|
||||
}
|
||||
let ret: u8 = self.buffer[self.position];
|
||||
self.increment_position(1);
|
||||
return Ok(ret);
|
||||
}
|
||||
|
||||
/// Reading UTF-8 encoded string from buffer
|
||||
pub fn read_string(&mut self) -> Result<EncodedString<'a>, BufferError> {
|
||||
let len = self.read_u16()? as usize;
|
||||
|
||||
if self.position + len - 1 >= self.len {
|
||||
return Err(BufferError::InsufficientBufferSize);
|
||||
}
|
||||
|
||||
let res_str = str::from_utf8(&(self.buffer[self.position..(self.position + len)]));
|
||||
if res_str.is_err() {
|
||||
log::error!("Could not parse utf-8 string");
|
||||
return Err(BufferError::Utf8Error);
|
||||
}
|
||||
self.increment_position(len);
|
||||
return Ok(EncodedString {
|
||||
string: res_str.unwrap(),
|
||||
len: len as u16,
|
||||
});
|
||||
}
|
||||
|
||||
/// Read Binary data from buffer
|
||||
pub fn read_binary(&mut self) -> Result<BinaryData<'a>, BufferError> {
|
||||
let len = self.read_u16()?;
|
||||
|
||||
if self.position + len as usize - 1 >= self.len {
|
||||
return Err(BufferError::InsufficientBufferSize);
|
||||
}
|
||||
|
||||
let res_bin = &(self.buffer[self.position..(self.position + len as usize)]);
|
||||
return Ok(BinaryData { bin: res_bin, len });
|
||||
}
|
||||
|
||||
/// Read string pair from buffer
|
||||
pub fn read_string_pair(&mut self) -> Result<StringPair<'a>, BufferError> {
|
||||
let name = self.read_string()?;
|
||||
let value = self.read_string()?;
|
||||
return Ok(StringPair { name, value });
|
||||
}
|
||||
|
||||
/// Read payload message from buffer
|
||||
pub fn read_message(&mut self, total_len: usize) -> &'a [u8] {
|
||||
if total_len > self.len {
|
||||
return &self.buffer[self.position..self.len];
|
||||
}
|
||||
return &self.buffer[self.position..total_len];
|
||||
}
|
||||
}
|
||||
167
mqtt/src/utils/buffer_writer.rs
Normal file
167
mqtt/src/utils/buffer_writer.rs
Normal file
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* 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::{VariableByteInteger, VariableByteIntegerEncoder};
|
||||
use crate::packet::v5::property::Property;
|
||||
use crate::utils::types::{BinaryData, BufferError, EncodedString, StringPair, TopicFilter};
|
||||
|
||||
pub struct BuffWriter<'a> {
|
||||
buffer: &'a mut [u8],
|
||||
pub position: usize,
|
||||
len: usize,
|
||||
}
|
||||
|
||||
impl<'a> BuffWriter<'a> {
|
||||
pub fn new(buffer: &'a mut [u8], buff_len: usize) -> Self {
|
||||
return BuffWriter {
|
||||
buffer,
|
||||
position: 0,
|
||||
len: buff_len,
|
||||
};
|
||||
}
|
||||
|
||||
fn increment_position(&mut self, increment: usize) {
|
||||
self.position = self.position + increment;
|
||||
}
|
||||
|
||||
pub fn insert_ref(&mut self, len: usize, array: &[u8]) -> Result<(), BufferError> {
|
||||
let mut x: usize = 0;
|
||||
if self.position + len > self.len {
|
||||
return Err(BufferError::InsufficientBufferSize);
|
||||
}
|
||||
if len != 0 {
|
||||
loop {
|
||||
self.buffer[self.position] = array[x];
|
||||
self.increment_position(1);
|
||||
x = x + 1;
|
||||
if x == len {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
pub fn write_u8(&mut self, byte: u8) -> Result<(), BufferError> {
|
||||
return if self.position >= self.len {
|
||||
Err(BufferError::InsufficientBufferSize)
|
||||
} else {
|
||||
self.buffer[self.position] = byte;
|
||||
self.increment_position(1);
|
||||
Ok(())
|
||||
};
|
||||
}
|
||||
|
||||
pub fn write_u16(&mut self, two_bytes: u16) -> Result<(), BufferError> {
|
||||
let bytes: [u8; 2] = two_bytes.to_be_bytes();
|
||||
return self.insert_ref(2, &bytes);
|
||||
}
|
||||
|
||||
pub fn write_u32(&mut self, four_bytes: u32) -> Result<(), BufferError> {
|
||||
let bytes: [u8; 4] = four_bytes.to_be_bytes();
|
||||
return self.insert_ref(4, &bytes);
|
||||
}
|
||||
|
||||
pub fn write_string_ref(&mut self, str: &EncodedString<'a>) -> Result<(), BufferError> {
|
||||
self.write_u16(str.len)?;
|
||||
if str.len != 0 {
|
||||
let bytes = str.string.as_bytes();
|
||||
return self.insert_ref(str.len as usize, bytes);
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
pub fn write_binary_ref(&mut self, bin: &BinaryData<'a>) -> Result<(), BufferError> {
|
||||
self.write_u16(bin.len)?;
|
||||
return self.insert_ref(bin.len as usize, bin.bin);
|
||||
}
|
||||
|
||||
pub fn write_string_pair_ref(&mut self, str_pair: &StringPair<'a>) -> Result<(), BufferError> {
|
||||
self.write_string_ref(&str_pair.name)?;
|
||||
return self.write_string_ref(&str_pair.value);
|
||||
}
|
||||
|
||||
pub fn write_variable_byte_int(&mut self, int: u32) -> Result<(), BufferError> {
|
||||
let x: VariableByteInteger = VariableByteIntegerEncoder::encode(int)?;
|
||||
let len = VariableByteIntegerEncoder::len(x);
|
||||
return self.insert_ref(len, &x);
|
||||
}
|
||||
|
||||
fn write_property(&mut self, property: &Property<'a>) -> Result<(), BufferError> {
|
||||
let x: u8 = property.into();
|
||||
self.write_u8(x)?;
|
||||
return property.encode(self);
|
||||
}
|
||||
|
||||
pub fn write_properties<const LEN: usize>(
|
||||
&mut self,
|
||||
properties: &Vec<Property<'a>, LEN>,
|
||||
) -> Result<(), BufferError> {
|
||||
let mut i = 0;
|
||||
let len = properties.len();
|
||||
if len != 0 {
|
||||
loop {
|
||||
let prop: &Property = properties.get(i).unwrap_or(&Property::Reserved());
|
||||
self.write_property(prop)?;
|
||||
i = i + 1;
|
||||
if i == len {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_topic_filter_ref(
|
||||
&mut self,
|
||||
sub: bool,
|
||||
topic_filter: &TopicFilter<'a>,
|
||||
) -> Result<(), BufferError> {
|
||||
self.write_string_ref(&topic_filter.filter)?;
|
||||
if sub {
|
||||
self.write_u8(topic_filter.sub_options)?;
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
pub fn write_topic_filters_ref<const MAX: usize>(
|
||||
&mut self,
|
||||
sub: bool,
|
||||
len: usize,
|
||||
filters: &Vec<TopicFilter<'a>, MAX>,
|
||||
) -> Result<(), BufferError> {
|
||||
let mut i = 0;
|
||||
loop {
|
||||
let topic_filter: &TopicFilter<'a> = filters.get(i).unwrap();
|
||||
self.write_topic_filter_ref(sub, topic_filter)?;
|
||||
i = i + 1;
|
||||
if i == len {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
28
mqtt/src/utils/mod.rs
Normal file
28
mqtt/src/utils/mod.rs
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* 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 buffer_reader;
|
||||
pub mod buffer_writer;
|
||||
pub mod rng_generator;
|
||||
pub mod types;
|
||||
28
mqtt/src/utils/rng_generator.rs
Normal file
28
mqtt/src/utils/rng_generator.rs
Normal file
@@ -0,0 +1,28 @@
|
||||
// This code is handed from Embedded Rust documentation and
|
||||
// is accessible from https://docs.rust-embedded.org/cortex-m-rt/0.6.0/rand/trait.RngCore.html
|
||||
|
||||
use rand_core::{impls, Error, RngCore};
|
||||
|
||||
pub struct CountingRng(pub u64);
|
||||
|
||||
impl RngCore for CountingRng {
|
||||
fn next_u32(&mut self) -> u32 {
|
||||
self.next_u64() as u32
|
||||
}
|
||||
|
||||
fn next_u64(&mut self) -> u64 {
|
||||
self.0 += 1;
|
||||
if self.0 > u16::MAX as u64 {
|
||||
self.0 = 1;
|
||||
}
|
||||
self.0
|
||||
}
|
||||
|
||||
fn fill_bytes(&mut self, dest: &mut [u8]) {
|
||||
impls::fill_bytes_via_next(self, dest)
|
||||
}
|
||||
|
||||
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
|
||||
Ok(self.fill_bytes(dest))
|
||||
}
|
||||
}
|
||||
131
mqtt/src/utils/types.rs
Normal file
131
mqtt/src/utils/types.rs
Normal file
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* 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(core::fmt::Debug, Clone, PartialEq)]
|
||||
pub enum BufferError {
|
||||
Utf8Error,
|
||||
InsufficientBufferSize,
|
||||
VariableByteIntegerError,
|
||||
IdNotFound,
|
||||
EncodingError,
|
||||
DecodingError,
|
||||
PacketTypeMismatch,
|
||||
WrongPacketToDecode,
|
||||
WrongPacketToEncode,
|
||||
PropertyNotFound,
|
||||
}
|
||||
|
||||
impl Display for BufferError {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
|
||||
match *self {
|
||||
BufferError::Utf8Error => write!(f, "Error encountered during UTF8 decoding!"),
|
||||
BufferError::InsufficientBufferSize => write!(f, "Buffer size is not sufficient for packet!"),
|
||||
BufferError::VariableByteIntegerError => write!(f, "Error encountered during variable byte integer decoding / encoding!"),
|
||||
BufferError::IdNotFound => write!(f, "Packet identifier not found!"),
|
||||
BufferError::EncodingError => write!(f, "Error encountered during packet encoding!"),
|
||||
BufferError::DecodingError => write!(f, "Error encountered during packet decoding!"),
|
||||
BufferError::PacketTypeMismatch => write!(f, "Packet type not matched during decoding (Received different packet type than encode type)!"),
|
||||
BufferError::WrongPacketToDecode => write!(f, "Not able to decode packet, this packet is used just for sending to broker, not receiving by client!"),
|
||||
BufferError::WrongPacketToEncode => write!(f, "Not able to encode packet, this packet is used only from server to client not the opposite way!"),
|
||||
BufferError::PropertyNotFound => write!(f, "Property with ID not found!")
|
||||
}
|
||||
}
|
||||
}
|
||||
/// Encoded string provides structure representing UTF-8 encoded string in MQTTv5 packets
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct EncodedString<'a> {
|
||||
pub string: &'a str,
|
||||
pub len: u16,
|
||||
}
|
||||
|
||||
impl EncodedString<'_> {
|
||||
pub fn new() -> Self {
|
||||
Self { string: "", len: 0 }
|
||||
}
|
||||
|
||||
/// Return length of string
|
||||
pub fn len(&self) -> u16 {
|
||||
return self.len + 2;
|
||||
}
|
||||
}
|
||||
|
||||
/// Binary data represents `Binary data` in MQTTv5 protocol
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct BinaryData<'a> {
|
||||
pub bin: &'a [u8],
|
||||
pub len: u16,
|
||||
}
|
||||
|
||||
impl BinaryData<'_> {
|
||||
pub fn new() -> Self {
|
||||
Self { bin: &[0], len: 0 }
|
||||
}
|
||||
/// Returns length of Byte array
|
||||
pub fn len(&self) -> u16 {
|
||||
return self.len + 2;
|
||||
}
|
||||
}
|
||||
|
||||
/// String pair struct represents `String pair` in MQTTv5 (2 UTF-8 encoded strings name-value)
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct StringPair<'a> {
|
||||
pub name: EncodedString<'a>,
|
||||
pub value: EncodedString<'a>,
|
||||
}
|
||||
|
||||
impl StringPair<'_> {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
name: EncodedString::new(),
|
||||
value: EncodedString::new(),
|
||||
}
|
||||
}
|
||||
/// Returns length which is equal to sum of the lenghts of UTF-8 encoded strings in pair
|
||||
pub fn len(&self) -> u16 {
|
||||
let ln = self.name.len() + self.value.len();
|
||||
return ln;
|
||||
}
|
||||
}
|
||||
|
||||
/// Topic filter serves as bound for topic selection and subscription options for `SUBSCRIPTION` packet
|
||||
#[derive(Debug)]
|
||||
pub struct TopicFilter<'a> {
|
||||
pub filter: EncodedString<'a>,
|
||||
pub sub_options: u8,
|
||||
}
|
||||
|
||||
impl TopicFilter<'_> {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
filter: EncodedString::new(),
|
||||
sub_options: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn len(&self) -> u16 {
|
||||
return self.filter.len + 3;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user