Make QOS and retain part of the publish API, add raw client, fix clippy warnings, update e-io version (#25)
This commit is contained in:
parent
d224254d51
commit
482b7895e1
|
@ -15,11 +15,11 @@ heapless = "0.7.10"
|
||||||
rand_core = "0.6.0"
|
rand_core = "0.6.0"
|
||||||
defmt = { version = "0.3", optional = true }
|
defmt = { version = "0.3", optional = true }
|
||||||
log = { version = "0.4.14", optional = true }
|
log = { version = "0.4.14", optional = true }
|
||||||
embedded-io = { version = "0.3.0", features = ["async"]}
|
embedded-io = { version = "0.4.0", features = ["async"]}
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tokio = { version = "1", features = ["full"] }
|
tokio = { version = "1", features = ["full"] }
|
||||||
embedded-io = { version = "0.3.0", features = ["tokio"]}
|
embedded-io = { version = "0.4.0", features = ["tokio"]}
|
||||||
tokio-test = { version = "0.4.2"}
|
tokio-test = { version = "0.4.2"}
|
||||||
env_logger = "0.9.0"
|
env_logger = "0.9.0"
|
||||||
futures = { version = "0.3.21" }
|
futures = { version = "0.3.21" }
|
||||||
|
|
60
examples/pubsub.rs
Normal file
60
examples/pubsub.rs
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
use std::{
|
||||||
|
net::{Ipv4Addr, SocketAddr},
|
||||||
|
time::Duration,
|
||||||
|
};
|
||||||
|
|
||||||
|
use embedded_io::adapters::FromTokio;
|
||||||
|
use rust_mqtt::{
|
||||||
|
client::{client::MqttClient, client_config::ClientConfig},
|
||||||
|
packet::v5::reason_codes::ReasonCode,
|
||||||
|
utils::rng_generator::CountingRng,
|
||||||
|
};
|
||||||
|
use tokio::net::TcpStream;
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() {
|
||||||
|
env_logger::init();
|
||||||
|
|
||||||
|
let addr = SocketAddr::new(Ipv4Addr::new(127, 0, 0, 1).into(), 1883);
|
||||||
|
|
||||||
|
let connection = TcpStream::connect(addr)
|
||||||
|
.await
|
||||||
|
.map_err(|_| ReasonCode::NetworkError)
|
||||||
|
.unwrap();
|
||||||
|
let connection = FromTokio::<TcpStream>::new(connection);
|
||||||
|
let mut config = ClientConfig::new(
|
||||||
|
rust_mqtt::client::client_config::MqttVersion::MQTTv5,
|
||||||
|
CountingRng(20000),
|
||||||
|
);
|
||||||
|
config.add_max_subscribe_qos(rust_mqtt::packet::v5::publish_packet::QualityOfService::QoS1);
|
||||||
|
config.add_client_id("client");
|
||||||
|
// 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 = MqttClient::<_, 5, _>::new(
|
||||||
|
connection,
|
||||||
|
&mut write_buffer,
|
||||||
|
80,
|
||||||
|
&mut recv_buffer,
|
||||||
|
80,
|
||||||
|
config,
|
||||||
|
);
|
||||||
|
|
||||||
|
client.connect_to_broker().await.unwrap();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
client
|
||||||
|
.send_message(
|
||||||
|
"hello",
|
||||||
|
b"hello2",
|
||||||
|
rust_mqtt::packet::v5::publish_packet::QualityOfService::QoS0,
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
tokio::time::sleep(Duration::from_millis(500)).await;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
[toolchain]
|
[toolchain]
|
||||||
channel = "nightly-2022-03-10"
|
channel = "nightly-2022-11-22"
|
||||||
components = [ "rust-src", "rustfmt" ]
|
components = [ "rust-src", "rustfmt" ]
|
||||||
targets = [ "thumbv7em-none-eabi", "thumbv7m-none-eabi", "thumbv6m-none-eabi", "thumbv7em-none-eabihf", "thumbv8m.main-none-eabihf", "wasm32-unknown-unknown" ]
|
targets = [ "thumbv7em-none-eabi", "thumbv7m-none-eabi", "thumbv6m-none-eabi", "thumbv7em-none-eabihf", "thumbv8m.main-none-eabihf", "wasm32-unknown-unknown" ]
|
|
@ -26,38 +26,17 @@ use embedded_io::asynch::{Read, Write};
|
||||||
use heapless::Vec;
|
use heapless::Vec;
|
||||||
use rand_core::RngCore;
|
use rand_core::RngCore;
|
||||||
|
|
||||||
use crate::client::client_config::{ClientConfig, MqttVersion};
|
use crate::client::client_config::ClientConfig;
|
||||||
use crate::encoding::variable_byte_integer::{VariableByteInteger, VariableByteIntegerDecoder};
|
use crate::packet::v5::publish_packet::QualityOfService::{self, QoS1};
|
||||||
use crate::network::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::reason_codes::ReasonCode;
|
||||||
use crate::packet::v5::reason_codes::ReasonCode::{BuffError, NetworkError};
|
|
||||||
use crate::packet::v5::suback_packet::SubackPacket;
|
use super::raw_client::{Event, RawMqttClient};
|
||||||
use crate::packet::v5::subscription_packet::SubscriptionPacket;
|
|
||||||
use crate::packet::v5::unsuback_packet::UnsubackPacket;
|
|
||||||
use crate::packet::v5::unsubscription_packet::UnsubscriptionPacket;
|
|
||||||
use crate::utils::buffer_reader::BuffReader;
|
|
||||||
use crate::utils::buffer_writer::BuffWriter;
|
|
||||||
use crate::utils::types::BufferError;
|
|
||||||
|
|
||||||
pub struct MqttClient<'a, T, const MAX_PROPERTIES: usize, R: RngCore>
|
pub struct MqttClient<'a, T, const MAX_PROPERTIES: usize, R: RngCore>
|
||||||
where
|
where
|
||||||
T: Read + Write,
|
T: Read + Write,
|
||||||
{
|
{
|
||||||
connection: Option<NetworkConnection<T>>,
|
raw: RawMqttClient<'a, T, MAX_PROPERTIES, R>,
|
||||||
buffer: &'a mut [u8],
|
|
||||||
buffer_len: usize,
|
|
||||||
recv_buffer: &'a mut [u8],
|
|
||||||
recv_buffer_len: usize,
|
|
||||||
config: ClientConfig<'a, MAX_PROPERTIES, R>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T, const MAX_PROPERTIES: usize, R> MqttClient<'a, T, MAX_PROPERTIES, R>
|
impl<'a, T, const MAX_PROPERTIES: usize, R> MqttClient<'a, T, MAX_PROPERTIES, R>
|
||||||
|
@ -74,80 +53,14 @@ where
|
||||||
config: ClientConfig<'a, MAX_PROPERTIES, R>,
|
config: ClientConfig<'a, MAX_PROPERTIES, R>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
connection: Some(NetworkConnection::new(network_driver)),
|
raw: RawMqttClient::new(
|
||||||
buffer,
|
network_driver,
|
||||||
buffer_len,
|
buffer,
|
||||||
recv_buffer,
|
buffer_len,
|
||||||
recv_buffer_len,
|
recv_buffer,
|
||||||
config,
|
recv_buffer_len,
|
||||||
}
|
config,
|
||||||
}
|
),
|
||||||
|
|
||||||
async fn connect_to_broker_v5<'b>(&'b mut self) -> Result<(), ReasonCode> {
|
|
||||||
if self.connection.is_none() {
|
|
||||||
return Err(ReasonCode::NetworkError);
|
|
||||||
}
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
if self.config.will_flag {
|
|
||||||
connect.add_will(
|
|
||||||
&self.config.will_topic,
|
|
||||||
&self.config.will_payload,
|
|
||||||
self.config.will_retain,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
connect.add_client_id(&self.config.client_id);
|
|
||||||
connect.encode(self.buffer, self.buffer_len)
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Err(err) = len {
|
|
||||||
error!("[DECODE ERR]: {}", err);
|
|
||||||
return Err(ReasonCode::BuffError);
|
|
||||||
}
|
|
||||||
let conn = self.connection.as_mut().unwrap();
|
|
||||||
trace!("Sending connect");
|
|
||||||
conn.send(&self.buffer[0..len.unwrap()]).await?;
|
|
||||||
|
|
||||||
//connack
|
|
||||||
let reason: Result<u8, BufferError> = {
|
|
||||||
trace!("Waiting for connack");
|
|
||||||
|
|
||||||
let read =
|
|
||||||
{ receive_packet(self.buffer, self.buffer_len, self.recv_buffer, conn).await? };
|
|
||||||
|
|
||||||
let mut packet = ConnackPacket::<'b, MAX_PROPERTIES>::new();
|
|
||||||
if let Err(err) = packet.decode(&mut BuffReader::new(self.buffer, read)) {
|
|
||||||
if err == BufferError::PacketTypeMismatch {
|
|
||||||
let mut disc = DisconnectPacket::<'b, MAX_PROPERTIES>::new();
|
|
||||||
if disc.decode(&mut BuffReader::new(self.buffer, read)).is_ok() {
|
|
||||||
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 {
|
|
||||||
error!("[DECODE ERR]: {}", err);
|
|
||||||
return Err(ReasonCode::BuffError);
|
|
||||||
}
|
|
||||||
let res = reason.unwrap();
|
|
||||||
if res != 0x00 {
|
|
||||||
return Err(ReasonCode::from(res));
|
|
||||||
} else {
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,33 +69,14 @@ where
|
||||||
/// If the connection to the broker fails, method returns Err variable that contains
|
/// If the connection to the broker fails, method returns Err variable that contains
|
||||||
/// Reason codes returned from the broker.
|
/// Reason codes returned from the broker.
|
||||||
pub async fn connect_to_broker<'b>(&'b mut self) -> Result<(), ReasonCode> {
|
pub async fn connect_to_broker<'b>(&'b mut self) -> Result<(), ReasonCode> {
|
||||||
match self.config.mqtt_version {
|
self.raw.connect_to_broker().await?;
|
||||||
MqttVersion::MQTTv3 => Err(ReasonCode::UnsupportedProtocolVersion),
|
|
||||||
MqttVersion::MQTTv5 => self.connect_to_broker_v5().await,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn disconnect_v5<'b>(&'b mut self) -> Result<(), ReasonCode> {
|
match self.raw.poll::<0>().await? {
|
||||||
if self.connection.is_none() {
|
Event::Connack => Ok(()),
|
||||||
return Err(ReasonCode::NetworkError);
|
Event::Disconnect(reason) => Err(reason),
|
||||||
|
// If an application message comes at this moment, it is lost.
|
||||||
|
_ => Err(ReasonCode::ImplementationSpecificError),
|
||||||
}
|
}
|
||||||
let conn = self.connection.as_mut().unwrap();
|
|
||||||
trace!("Creating disconnect packet!");
|
|
||||||
let mut disconnect = DisconnectPacket::<'b, MAX_PROPERTIES>::new();
|
|
||||||
let len = disconnect.encode(self.buffer, self.buffer_len);
|
|
||||||
if let Err(err) = len {
|
|
||||||
warn!("[DECODE ERR]: {}", err);
|
|
||||||
let _ = self.connection.take();
|
|
||||||
return Err(ReasonCode::BuffError);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Err(_e) = conn.send(&self.buffer[0..len.unwrap()]).await {
|
|
||||||
warn!("Could not send DISCONNECT packet");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Drop connection
|
|
||||||
let _ = self.connection.take();
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Method allows client disconnect from the server. Client disconnects from the specified broker
|
/// Method allows client disconnect from the server. Client disconnects from the specified broker
|
||||||
|
@ -190,72 +84,10 @@ where
|
||||||
/// If the disconnect from the broker fails, method returns Err variable that contains
|
/// If the disconnect from the broker fails, method returns Err variable that contains
|
||||||
/// Reason codes returned from the broker.
|
/// Reason codes returned from the broker.
|
||||||
pub async fn disconnect<'b>(&'b mut self) -> Result<(), ReasonCode> {
|
pub async fn disconnect<'b>(&'b mut self) -> Result<(), ReasonCode> {
|
||||||
match self.config.mqtt_version {
|
self.raw.disconnect().await?;
|
||||||
MqttVersion::MQTTv3 => Err(ReasonCode::UnsupportedProtocolVersion),
|
|
||||||
MqttVersion::MQTTv5 => self.disconnect_v5().await,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn send_message_v5<'b>(
|
|
||||||
&'b mut self,
|
|
||||||
topic_name: &'b str,
|
|
||||||
message: &'b [u8],
|
|
||||||
) -> Result<(), ReasonCode> {
|
|
||||||
if self.connection.is_none() {
|
|
||||||
return Err(ReasonCode::NetworkError);
|
|
||||||
}
|
|
||||||
let conn = self.connection.as_mut().unwrap();
|
|
||||||
let identifier: u16 = self.config.rng.next_u32() as u16;
|
|
||||||
//self.rng.next_u32() as u16;
|
|
||||||
let len = {
|
|
||||||
let mut packet = PublishPacket::<'b, MAX_PROPERTIES>::new();
|
|
||||||
packet.add_topic_name(topic_name);
|
|
||||||
packet.add_qos(self.config.qos);
|
|
||||||
packet.add_identifier(identifier);
|
|
||||||
packet.add_message(message);
|
|
||||||
packet.encode(self.buffer, self.buffer_len)
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Err(err) = len {
|
|
||||||
error!("[DECODE ERR]: {}", err);
|
|
||||||
return Err(ReasonCode::BuffError);
|
|
||||||
}
|
|
||||||
trace!("Sending message");
|
|
||||||
conn.send(&self.buffer[0..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> = {
|
|
||||||
trace!("Waiting for ack");
|
|
||||||
let read =
|
|
||||||
receive_packet(self.buffer, self.buffer_len, self.recv_buffer, conn).await?;
|
|
||||||
trace!("[PUBACK] Received packet with len");
|
|
||||||
let mut packet = PubackPacket::<'b, MAX_PROPERTIES>::new();
|
|
||||||
if let Err(err) = packet.decode(&mut BuffReader::new(self.buffer, read)) {
|
|
||||||
Err(err)
|
|
||||||
} else {
|
|
||||||
Ok([packet.packet_identifier, packet.reason_code as u16])
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Err(err) = reason {
|
|
||||||
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Method allows sending message to broker specified from the ClientConfig. Client sends the
|
/// Method allows sending message to broker specified from the ClientConfig. Client sends the
|
||||||
/// message from the parameter `message` to the topic `topic_name` on the broker
|
/// message from the parameter `message` to the topic `topic_name` on the broker
|
||||||
/// specified in the ClientConfig. If the send fails method returns Err with reason code
|
/// specified in the ClientConfig. If the send fails method returns Err with reason code
|
||||||
|
@ -264,71 +96,31 @@ where
|
||||||
&'b mut self,
|
&'b mut self,
|
||||||
topic_name: &'b str,
|
topic_name: &'b str,
|
||||||
message: &'b [u8],
|
message: &'b [u8],
|
||||||
|
qos: QualityOfService,
|
||||||
|
retain: bool,
|
||||||
) -> Result<(), ReasonCode> {
|
) -> Result<(), ReasonCode> {
|
||||||
match self.config.mqtt_version {
|
let identifier = self
|
||||||
MqttVersion::MQTTv3 => Err(ReasonCode::UnsupportedProtocolVersion),
|
.raw
|
||||||
MqttVersion::MQTTv5 => self.send_message_v5(topic_name, message).await,
|
.send_message(topic_name, message, qos, retain)
|
||||||
}
|
.await?;
|
||||||
}
|
|
||||||
|
|
||||||
async fn subscribe_to_topics_v5<'b, const TOPICS: usize>(
|
// QoS1
|
||||||
&'b mut self,
|
if qos == QoS1 {
|
||||||
topic_names: &'b Vec<&'b str, TOPICS>,
|
match self.raw.poll::<0>().await? {
|
||||||
) -> Result<(), ReasonCode> {
|
Event::Puback(ack_identifier) => {
|
||||||
if self.connection.is_none() {
|
if identifier == ack_identifier {
|
||||||
return Err(ReasonCode::NetworkError);
|
Ok(())
|
||||||
}
|
} else {
|
||||||
let conn = self.connection.as_mut().unwrap();
|
Err(ReasonCode::PacketIdentifierNotFound)
|
||||||
let len = {
|
}
|
||||||
let mut subs = SubscriptionPacket::<'b, TOPICS, MAX_PROPERTIES>::new();
|
|
||||||
let mut i = 0;
|
|
||||||
loop {
|
|
||||||
if i == TOPICS {
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
subs.add_new_filter(topic_names.get(i).unwrap(), self.config.qos);
|
Event::Disconnect(reason) => Err(reason),
|
||||||
i = i + 1;
|
// If an application message comes at this moment, it is lost.
|
||||||
|
_ => Err(ReasonCode::ImplementationSpecificError),
|
||||||
}
|
}
|
||||||
subs.encode(self.buffer, self.buffer_len)
|
} else {
|
||||||
};
|
Ok(())
|
||||||
|
|
||||||
if let Err(err) = len {
|
|
||||||
error!("[DECODE ERR]: {}", err);
|
|
||||||
return Err(ReasonCode::BuffError);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
conn.send(&self.buffer[0..len.unwrap()]).await?;
|
|
||||||
|
|
||||||
let reason: Result<Vec<u8, TOPICS>, BufferError> = {
|
|
||||||
let read =
|
|
||||||
{ receive_packet(self.buffer, self.buffer_len, self.recv_buffer, conn).await? };
|
|
||||||
|
|
||||||
let mut packet = SubackPacket::<'b, TOPICS, MAX_PROPERTIES>::new();
|
|
||||||
if let Err(err) = packet.decode(&mut BuffReader::new(self.buffer, read)) {
|
|
||||||
Err(err)
|
|
||||||
} else {
|
|
||||||
Ok(packet.reason_codes)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Err(err) = reason {
|
|
||||||
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 as Into<u8>>::into(self.config.qos) >> 1)
|
|
||||||
{
|
|
||||||
return Err(ReasonCode::from(*reasons.get(i).unwrap()));
|
|
||||||
}
|
|
||||||
i = i + 1;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Method allows client subscribe to multiple topics specified in the parameter
|
/// Method allows client subscribe to multiple topics specified in the parameter
|
||||||
|
@ -339,9 +131,19 @@ where
|
||||||
&'b mut self,
|
&'b mut self,
|
||||||
topic_names: &'b Vec<&'b str, TOPICS>,
|
topic_names: &'b Vec<&'b str, TOPICS>,
|
||||||
) -> Result<(), ReasonCode> {
|
) -> Result<(), ReasonCode> {
|
||||||
match self.config.mqtt_version {
|
let identifier = self.raw.subscribe_to_topics(topic_names).await?;
|
||||||
MqttVersion::MQTTv3 => Err(ReasonCode::UnsupportedProtocolVersion),
|
|
||||||
MqttVersion::MQTTv5 => self.subscribe_to_topics_v5(topic_names).await,
|
match self.raw.poll::<TOPICS>().await? {
|
||||||
|
Event::Suback(ack_identifier) => {
|
||||||
|
if identifier == ack_identifier {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(ReasonCode::PacketIdentifierNotFound)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Event::Disconnect(reason) => Err(reason),
|
||||||
|
// If an application message comes at this moment, it is lost.
|
||||||
|
_ => Err(ReasonCode::ImplementationSpecificError),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -352,97 +154,19 @@ where
|
||||||
&'b mut self,
|
&'b mut self,
|
||||||
topic_name: &'b str,
|
topic_name: &'b str,
|
||||||
) -> Result<(), ReasonCode> {
|
) -> Result<(), ReasonCode> {
|
||||||
match self.config.mqtt_version {
|
let identifier = self.raw.unsubscribe_from_topic(topic_name).await?;
|
||||||
MqttVersion::MQTTv3 => Err(ReasonCode::UnsupportedProtocolVersion),
|
|
||||||
MqttVersion::MQTTv5 => self.unsubscribe_from_topic_v5(topic_name).await,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn unsubscribe_from_topic_v5<'b>(
|
match self.raw.poll::<0>().await? {
|
||||||
&'b mut self,
|
Event::Unsuback(ack_identifier) => {
|
||||||
topic_name: &'b str,
|
if identifier == ack_identifier {
|
||||||
) -> Result<(), ReasonCode> {
|
Ok(())
|
||||||
if self.connection.is_none() {
|
} else {
|
||||||
return Err(ReasonCode::NetworkError);
|
Err(ReasonCode::PacketIdentifierNotFound)
|
||||||
}
|
}
|
||||||
let conn = self.connection.as_mut().unwrap();
|
|
||||||
|
|
||||||
let len = {
|
|
||||||
let mut unsub = UnsubscriptionPacket::<'b, 1, MAX_PROPERTIES>::new();
|
|
||||||
unsub.packet_identifier = self.config.rng.next_u32() as u16;
|
|
||||||
unsub.add_new_filter(topic_name);
|
|
||||||
unsub.encode(self.buffer, self.buffer_len)
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Err(err) = len {
|
|
||||||
error!("[DECODE ERR]: {}", err);
|
|
||||||
return Err(ReasonCode::BuffError);
|
|
||||||
}
|
|
||||||
conn.send(&self.buffer[0..len.unwrap()]).await?;
|
|
||||||
|
|
||||||
let reason: Result<u8, BufferError> = {
|
|
||||||
let read =
|
|
||||||
{ receive_packet(self.buffer, self.buffer_len, self.recv_buffer, conn).await? };
|
|
||||||
let mut packet = UnsubackPacket::<'b, 1, MAX_PROPERTIES>::new();
|
|
||||||
|
|
||||||
if let Err(err) = packet.decode(&mut BuffReader::new(self.buffer, read)) {
|
|
||||||
Err(err)
|
|
||||||
} else {
|
|
||||||
Ok(*packet.reason_codes.get(0).unwrap())
|
|
||||||
}
|
}
|
||||||
};
|
Event::Disconnect(reason) => Err(reason),
|
||||||
|
// If an application message comes at this moment, it is lost.
|
||||||
if let Err(err) = reason {
|
_ => Err(ReasonCode::ImplementationSpecificError),
|
||||||
error!("[DECODE ERR]: {}", err);
|
|
||||||
return Err(ReasonCode::BuffError);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn subscribe_to_topic_v5<'b>(
|
|
||||||
&'b mut self,
|
|
||||||
topic_name: &'b str,
|
|
||||||
) -> Result<(), ReasonCode> {
|
|
||||||
if self.connection.is_none() {
|
|
||||||
return Err(ReasonCode::NetworkError);
|
|
||||||
}
|
|
||||||
let conn = self.connection.as_mut().unwrap();
|
|
||||||
let len = {
|
|
||||||
let mut subs = SubscriptionPacket::<'b, 1, MAX_PROPERTIES>::new();
|
|
||||||
subs.add_new_filter(topic_name, self.config.qos);
|
|
||||||
subs.encode(self.buffer, self.buffer_len)
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Err(err) = len {
|
|
||||||
error!("[DECODE ERR]: {}", err);
|
|
||||||
return Err(ReasonCode::BuffError);
|
|
||||||
}
|
|
||||||
|
|
||||||
conn.send(&self.buffer[0..len.unwrap()]).await?;
|
|
||||||
|
|
||||||
let reason: Result<u8, BufferError> = {
|
|
||||||
let read =
|
|
||||||
{ receive_packet(self.buffer, self.buffer_len, self.recv_buffer, conn).await? };
|
|
||||||
|
|
||||||
let mut packet = SubackPacket::<'b, 1, MAX_PROPERTIES>::new();
|
|
||||||
if let Err(err) = packet.decode(&mut BuffReader::new(self.buffer, read)) {
|
|
||||||
Err(err)
|
|
||||||
} else {
|
|
||||||
Ok(*packet.reason_codes.get(0).unwrap())
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Err(err) = reason {
|
|
||||||
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(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -453,85 +177,34 @@ where
|
||||||
&'b mut self,
|
&'b mut self,
|
||||||
topic_name: &'b str,
|
topic_name: &'b str,
|
||||||
) -> Result<(), ReasonCode> {
|
) -> Result<(), ReasonCode> {
|
||||||
match self.config.mqtt_version {
|
let mut topic_names = Vec::<&'b str, 1>::new();
|
||||||
MqttVersion::MQTTv3 => Err(ReasonCode::UnsupportedProtocolVersion),
|
topic_names.push(topic_name).unwrap();
|
||||||
MqttVersion::MQTTv5 => self.subscribe_to_topic_v5(topic_name).await,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn receive_message_v5<'b>(&'b mut self) -> Result<(&'b str, &'b [u8]), ReasonCode> {
|
let identifier = self.raw.subscribe_to_topics(&topic_names).await?;
|
||||||
if self.connection.is_none() {
|
|
||||||
return Err(ReasonCode::NetworkError);
|
|
||||||
}
|
|
||||||
let conn = self.connection.as_mut().unwrap();
|
|
||||||
let read = { receive_packet(self.buffer, self.buffer_len, self.recv_buffer, conn).await? };
|
|
||||||
|
|
||||||
let mut packet = PublishPacket::<'b, 5>::new();
|
match self.raw.poll::<1>().await? {
|
||||||
if let Err(err) = { packet.decode(&mut BuffReader::new(self.buffer, read)) } {
|
Event::Suback(ack_identifier) => {
|
||||||
if err == BufferError::PacketTypeMismatch {
|
if identifier == ack_identifier {
|
||||||
let mut disc = DisconnectPacket::<'b, 5>::new();
|
Ok(())
|
||||||
if disc.decode(&mut BuffReader::new(self.buffer, read)).is_ok() {
|
} else {
|
||||||
error!("Client was disconnected with reason: ");
|
Err(ReasonCode::PacketIdentifierNotFound)
|
||||||
return Err(ReasonCode::from(disc.disconnect_reason));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
error!("[DECODE ERR]: {}", err);
|
Event::Disconnect(reason) => Err(reason),
|
||||||
return Err(ReasonCode::BuffError);
|
// If an application message comes at this moment, it is lost.
|
||||||
|
_ => Err(ReasonCode::ImplementationSpecificError),
|
||||||
}
|
}
|
||||||
|
|
||||||
if (packet.fixed_header & 0x06)
|
|
||||||
== <QualityOfService as Into<u8>>::into(QualityOfService::QoS1)
|
|
||||||
{
|
|
||||||
let mut puback = PubackPacket::<'b, MAX_PROPERTIES>::new();
|
|
||||||
puback.packet_identifier = packet.packet_identifier;
|
|
||||||
puback.reason_code = 0x00;
|
|
||||||
{
|
|
||||||
let len = { puback.encode(self.recv_buffer, self.recv_buffer_len) };
|
|
||||||
if let Err(err) = len {
|
|
||||||
error!("[DECODE ERR]: {}", err);
|
|
||||||
return Err(ReasonCode::BuffError);
|
|
||||||
}
|
|
||||||
conn.send(&self.recv_buffer[0..len.unwrap()]).await?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Ok((packet.topic_name.string, packet.message.unwrap()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Method allows client receive a message. The work of this method strictly depends on the
|
/// Method allows client receive a message. The work of this method strictly depends on the
|
||||||
/// network implementation passed in the `ClientConfig`. It expects the PUBLISH packet
|
/// network implementation passed in the `ClientConfig`. It expects the PUBLISH packet
|
||||||
/// from the broker.
|
/// from the broker.
|
||||||
pub async fn receive_message<'b>(&'b mut self) -> Result<(&'b str, &'b [u8]), ReasonCode> {
|
pub async fn receive_message<'b>(&'b mut self) -> Result<(&'b str, &'b [u8]), ReasonCode> {
|
||||||
match self.config.mqtt_version {
|
match self.raw.poll::<0>().await? {
|
||||||
MqttVersion::MQTTv3 => Err(ReasonCode::UnsupportedProtocolVersion),
|
Event::Message(topic, payload) => Ok((topic, payload)),
|
||||||
MqttVersion::MQTTv5 => self.receive_message_v5().await,
|
Event::Disconnect(reason) => Err(reason),
|
||||||
}
|
// If an application message comes at this moment, it is lost.
|
||||||
}
|
_ => Err(ReasonCode::ImplementationSpecificError),
|
||||||
|
|
||||||
async fn send_ping_v5<'b>(&'b mut self) -> Result<(), ReasonCode> {
|
|
||||||
if self.connection.is_none() {
|
|
||||||
return Err(ReasonCode::NetworkError);
|
|
||||||
}
|
|
||||||
let conn = self.connection.as_mut().unwrap();
|
|
||||||
let len = {
|
|
||||||
let mut packet = PingreqPacket::new();
|
|
||||||
packet.encode(self.buffer, self.buffer_len)
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Err(err) = len {
|
|
||||||
error!("[DECODE ERR]: {}", err);
|
|
||||||
return Err(ReasonCode::BuffError);
|
|
||||||
}
|
|
||||||
|
|
||||||
conn.send(&self.buffer[0..len.unwrap()]).await?;
|
|
||||||
|
|
||||||
let read = { receive_packet(self.buffer, self.buffer_len, self.recv_buffer, conn).await? };
|
|
||||||
let mut packet = PingrespPacket::new();
|
|
||||||
if let Err(err) = packet.decode(&mut BuffReader::new(self.buffer, read)) {
|
|
||||||
error!("[DECODE ERR]: {}", err);
|
|
||||||
return Err(ReasonCode::BuffError);
|
|
||||||
} else {
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -539,96 +212,13 @@ where
|
||||||
/// If there is expectation for long running connection. Method should be executed
|
/// If there is expectation for long running connection. Method should be executed
|
||||||
/// regularly by the timer that counts down the session expiry interval.
|
/// regularly by the timer that counts down the session expiry interval.
|
||||||
pub async fn send_ping<'b>(&'b mut self) -> Result<(), ReasonCode> {
|
pub async fn send_ping<'b>(&'b mut self) -> Result<(), ReasonCode> {
|
||||||
match self.config.mqtt_version {
|
self.raw.send_ping().await?;
|
||||||
MqttVersion::MQTTv3 => Err(ReasonCode::UnsupportedProtocolVersion),
|
|
||||||
MqttVersion::MQTTv5 => self.send_ping_v5().await,
|
match self.raw.poll::<0>().await? {
|
||||||
|
Event::Pingresp => Ok(()),
|
||||||
|
Event::Disconnect(reason) => Err(reason),
|
||||||
|
// If an application message comes at this moment, it is lost.
|
||||||
|
_ => Err(ReasonCode::ImplementationSpecificError),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "tls"))]
|
|
||||||
async fn receive_packet<'c, T: Read + Write>(
|
|
||||||
buffer: &mut [u8],
|
|
||||||
buffer_len: usize,
|
|
||||||
recv_buffer: &mut [u8],
|
|
||||||
conn: &'c mut NetworkConnection<T>,
|
|
||||||
) -> Result<usize, ReasonCode> {
|
|
||||||
let target_len: usize;
|
|
||||||
let mut rem_len: Result<VariableByteInteger, ()>;
|
|
||||||
let mut writer = BuffWriter::new(buffer, buffer_len);
|
|
||||||
let mut i = 0;
|
|
||||||
|
|
||||||
// Get len of packet
|
|
||||||
trace!("Reading lenght of packet");
|
|
||||||
loop {
|
|
||||||
trace!(" Reading in loop!");
|
|
||||||
let len: usize = conn
|
|
||||||
.receive(&mut recv_buffer[writer.position..(writer.position + 1)])
|
|
||||||
.await?;
|
|
||||||
trace!(" Received data!");
|
|
||||||
if len == 0 {
|
|
||||||
trace!("Zero byte len packet received, dropping connection.");
|
|
||||||
return Err(NetworkError);
|
|
||||||
}
|
|
||||||
i = i + len;
|
|
||||||
if let Err(_e) = writer.insert_ref(len, &recv_buffer[writer.position..i]) {
|
|
||||||
error!("Error occurred during write to buffer!");
|
|
||||||
return Err(ReasonCode::BuffError);
|
|
||||||
}
|
|
||||||
if i > 1 {
|
|
||||||
rem_len = writer.get_rem_len();
|
|
||||||
if rem_len.is_ok() {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if i >= 5 {
|
|
||||||
error!("Could not read len of packet!");
|
|
||||||
return Err(NetworkError);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
trace!("Lenght done!");
|
|
||||||
let rem_len_len = i;
|
|
||||||
i = 0;
|
|
||||||
if let Ok(l) = VariableByteIntegerDecoder::decode(rem_len.unwrap()) {
|
|
||||||
trace!("Reading packet with target len {}", l);
|
|
||||||
target_len = l as usize;
|
|
||||||
} else {
|
|
||||||
error!("Could not decode len of packet!");
|
|
||||||
return Err(BuffError);
|
|
||||||
}
|
|
||||||
|
|
||||||
loop {
|
|
||||||
if writer.position == target_len + rem_len_len {
|
|
||||||
trace!("Received packet with len: {}", (target_len + rem_len_len));
|
|
||||||
return Ok(target_len + rem_len_len);
|
|
||||||
}
|
|
||||||
let len: usize = conn
|
|
||||||
.receive(&mut recv_buffer[writer.position..writer.position + (target_len - i)])
|
|
||||||
.await?;
|
|
||||||
i = i + len;
|
|
||||||
if let Err(_e) =
|
|
||||||
writer.insert_ref(len, &recv_buffer[writer.position..(writer.position + i)])
|
|
||||||
{
|
|
||||||
error!("Error occurred during write to buffer!");
|
|
||||||
return Err(BuffError);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "tls")]
|
|
||||||
async fn receive_packet<'c, T: Read + Write>(
|
|
||||||
buffer: &mut [u8],
|
|
||||||
buffer_len: usize,
|
|
||||||
recv_buffer: &mut [u8],
|
|
||||||
conn: &'c mut NetworkConnection<T>,
|
|
||||||
) -> Result<usize, ReasonCode> {
|
|
||||||
trace!("Reading packet");
|
|
||||||
let mut writer = BuffWriter::new(buffer, buffer_len);
|
|
||||||
let len = conn.receive(recv_buffer).await?;
|
|
||||||
if let Err(_e) = writer.insert_ref(len, &recv_buffer[writer.position..(writer.position + len)])
|
|
||||||
{
|
|
||||||
error!("Error occurred during write to buffer!");
|
|
||||||
return Err(BuffError);
|
|
||||||
}
|
|
||||||
Ok(len)
|
|
||||||
}
|
|
||||||
|
|
|
@ -46,7 +46,7 @@ pub enum MqttVersion {
|
||||||
/// Examples of the configurations can be found in the integration tests.
|
/// Examples of the configurations can be found in the integration tests.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct ClientConfig<'a, const MAX_PROPERTIES: usize, T: RngCore> {
|
pub struct ClientConfig<'a, const MAX_PROPERTIES: usize, T: RngCore> {
|
||||||
pub qos: QualityOfService,
|
pub max_subscribe_qos: QualityOfService,
|
||||||
pub keep_alive: u16,
|
pub keep_alive: u16,
|
||||||
pub username_flag: bool,
|
pub username_flag: bool,
|
||||||
pub username: EncodedString<'a>,
|
pub username: EncodedString<'a>,
|
||||||
|
@ -66,7 +66,7 @@ pub struct ClientConfig<'a, const MAX_PROPERTIES: usize, T: RngCore> {
|
||||||
impl<'a, const MAX_PROPERTIES: usize, T: RngCore> ClientConfig<'a, MAX_PROPERTIES, T> {
|
impl<'a, const MAX_PROPERTIES: usize, T: RngCore> ClientConfig<'a, MAX_PROPERTIES, T> {
|
||||||
pub fn new(version: MqttVersion, rng: T) -> Self {
|
pub fn new(version: MqttVersion, rng: T) -> Self {
|
||||||
Self {
|
Self {
|
||||||
qos: QualityOfService::QoS0,
|
max_subscribe_qos: QualityOfService::QoS0,
|
||||||
keep_alive: 60,
|
keep_alive: 60,
|
||||||
username_flag: false,
|
username_flag: false,
|
||||||
username: EncodedString::new(),
|
username: EncodedString::new(),
|
||||||
|
@ -84,8 +84,8 @@ impl<'a, const MAX_PROPERTIES: usize, T: RngCore> ClientConfig<'a, MAX_PROPERTIE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_qos(&mut self, qos: QualityOfService) {
|
pub fn add_max_subscribe_qos(&mut self, qos: QualityOfService) {
|
||||||
self.qos = qos;
|
self.max_subscribe_qos = qos;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_will(&mut self, topic: &'a str, payload: &'a [u8], retain: bool) {
|
pub fn add_will(&mut self, topic: &'a str, payload: &'a [u8], retain: bool) {
|
||||||
|
@ -136,7 +136,7 @@ impl<'a, const MAX_PROPERTIES: usize, T: RngCore> ClientConfig<'a, MAX_PROPERTIE
|
||||||
self.properties.push(prop);
|
self.properties.push(prop);
|
||||||
return 5;
|
return 5;
|
||||||
}
|
}
|
||||||
return 0;
|
0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_client_id(&mut self, client_id: &'a str) {
|
pub fn add_client_id(&mut self, client_id: &'a str) {
|
||||||
|
|
|
@ -22,6 +22,8 @@
|
||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#[allow(clippy::module_inception)]
|
||||||
pub mod client;
|
pub mod client;
|
||||||
#[allow(unused_must_use)]
|
#[allow(unused_must_use)]
|
||||||
pub mod client_config;
|
pub mod client_config;
|
||||||
|
pub mod raw_client;
|
||||||
|
|
572
src/client/raw_client.rs
Normal file
572
src/client/raw_client.rs
Normal file
|
@ -0,0 +1,572 @@
|
||||||
|
use embedded_io::asynch::{Read, Write};
|
||||||
|
use heapless::Vec;
|
||||||
|
use rand_core::RngCore;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
encoding::variable_byte_integer::{VariableByteInteger, VariableByteIntegerDecoder},
|
||||||
|
network::NetworkConnection,
|
||||||
|
packet::v5::{
|
||||||
|
connack_packet::ConnackPacket,
|
||||||
|
connect_packet::ConnectPacket,
|
||||||
|
disconnect_packet::DisconnectPacket,
|
||||||
|
mqtt_packet::Packet,
|
||||||
|
packet_type::PacketType,
|
||||||
|
pingreq_packet::PingreqPacket,
|
||||||
|
pingresp_packet::PingrespPacket,
|
||||||
|
puback_packet::PubackPacket,
|
||||||
|
publish_packet::{PublishPacket, QualityOfService},
|
||||||
|
reason_codes::ReasonCode,
|
||||||
|
suback_packet::SubackPacket,
|
||||||
|
subscription_packet::SubscriptionPacket,
|
||||||
|
unsuback_packet::UnsubackPacket,
|
||||||
|
unsubscription_packet::UnsubscriptionPacket,
|
||||||
|
},
|
||||||
|
utils::{buffer_reader::BuffReader, buffer_writer::BuffWriter, types::BufferError},
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::client_config::{ClientConfig, MqttVersion};
|
||||||
|
|
||||||
|
pub enum Event<'a> {
|
||||||
|
Connack,
|
||||||
|
Puback(u16),
|
||||||
|
Suback(u16),
|
||||||
|
Unsuback(u16),
|
||||||
|
Pingresp,
|
||||||
|
Message(&'a str, &'a [u8]),
|
||||||
|
Disconnect(ReasonCode),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct RawMqttClient<'a, T, const MAX_PROPERTIES: usize, R: RngCore>
|
||||||
|
where
|
||||||
|
T: Read + Write,
|
||||||
|
{
|
||||||
|
connection: Option<NetworkConnection<T>>,
|
||||||
|
buffer: &'a mut [u8],
|
||||||
|
buffer_len: usize,
|
||||||
|
recv_buffer: &'a mut [u8],
|
||||||
|
recv_buffer_len: usize,
|
||||||
|
config: ClientConfig<'a, MAX_PROPERTIES, R>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T, const MAX_PROPERTIES: usize, R> RawMqttClient<'a, T, MAX_PROPERTIES, R>
|
||||||
|
where
|
||||||
|
T: Read + Write,
|
||||||
|
R: RngCore,
|
||||||
|
{
|
||||||
|
pub fn new(
|
||||||
|
network_driver: T,
|
||||||
|
buffer: &'a mut [u8],
|
||||||
|
buffer_len: usize,
|
||||||
|
recv_buffer: &'a mut [u8],
|
||||||
|
recv_buffer_len: usize,
|
||||||
|
config: ClientConfig<'a, MAX_PROPERTIES, R>,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
connection: Some(NetworkConnection::new(network_driver)),
|
||||||
|
buffer,
|
||||||
|
buffer_len,
|
||||||
|
recv_buffer,
|
||||||
|
recv_buffer_len,
|
||||||
|
config,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn connect_to_broker_v5<'b>(&'b mut self) -> Result<(), ReasonCode> {
|
||||||
|
if self.connection.is_none() {
|
||||||
|
return Err(ReasonCode::NetworkError);
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
if self.config.will_flag {
|
||||||
|
connect.add_will(
|
||||||
|
&self.config.will_topic,
|
||||||
|
&self.config.will_payload,
|
||||||
|
self.config.will_retain,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
connect.add_client_id(&self.config.client_id);
|
||||||
|
connect.encode(self.buffer, self.buffer_len)
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Err(err) = len {
|
||||||
|
error!("[DECODE ERR]: {}", err);
|
||||||
|
return Err(ReasonCode::BuffError);
|
||||||
|
}
|
||||||
|
let conn = self.connection.as_mut().unwrap();
|
||||||
|
trace!("Sending connect");
|
||||||
|
conn.send(&self.buffer[0..len.unwrap()]).await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Method allows client connect to server. Client is connecting to the specified broker
|
||||||
|
/// in the `ClientConfig`. Method selects proper implementation of the MQTT version based on the config.
|
||||||
|
/// If the connection to the broker fails, method returns Err variable that contains
|
||||||
|
/// Reason codes returned from the broker.
|
||||||
|
pub async fn connect_to_broker<'b>(&'b mut self) -> Result<(), ReasonCode> {
|
||||||
|
match self.config.mqtt_version {
|
||||||
|
MqttVersion::MQTTv3 => Err(ReasonCode::UnsupportedProtocolVersion),
|
||||||
|
MqttVersion::MQTTv5 => self.connect_to_broker_v5().await,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn disconnect_v5<'b>(&'b mut self) -> Result<(), ReasonCode> {
|
||||||
|
if self.connection.is_none() {
|
||||||
|
return Err(ReasonCode::NetworkError);
|
||||||
|
}
|
||||||
|
let conn = self.connection.as_mut().unwrap();
|
||||||
|
trace!("Creating disconnect packet!");
|
||||||
|
let mut disconnect = DisconnectPacket::<'b, MAX_PROPERTIES>::new();
|
||||||
|
let len = disconnect.encode(self.buffer, self.buffer_len);
|
||||||
|
if let Err(err) = len {
|
||||||
|
warn!("[DECODE ERR]: {}", err);
|
||||||
|
let _ = self.connection.take();
|
||||||
|
return Err(ReasonCode::BuffError);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Err(_e) = conn.send(&self.buffer[0..len.unwrap()]).await {
|
||||||
|
warn!("Could not send DISCONNECT packet");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Drop connection
|
||||||
|
let _ = self.connection.take();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Method allows client disconnect from the server. Client disconnects from the specified broker
|
||||||
|
/// in the `ClientConfig`. Method selects proper implementation of the MQTT version based on the config.
|
||||||
|
/// If the disconnect from the broker fails, method returns Err variable that contains
|
||||||
|
/// Reason codes returned from the broker.
|
||||||
|
pub async fn disconnect<'b>(&'b mut self) -> Result<(), ReasonCode> {
|
||||||
|
match self.config.mqtt_version {
|
||||||
|
MqttVersion::MQTTv3 => Err(ReasonCode::UnsupportedProtocolVersion),
|
||||||
|
MqttVersion::MQTTv5 => self.disconnect_v5().await,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn send_message_v5<'b>(
|
||||||
|
&'b mut self,
|
||||||
|
topic_name: &'b str,
|
||||||
|
message: &'b [u8],
|
||||||
|
qos: QualityOfService,
|
||||||
|
retain: bool,
|
||||||
|
) -> Result<u16, ReasonCode> {
|
||||||
|
if self.connection.is_none() {
|
||||||
|
return Err(ReasonCode::NetworkError);
|
||||||
|
}
|
||||||
|
let conn = self.connection.as_mut().unwrap();
|
||||||
|
let identifier: u16 = self.config.rng.next_u32() as u16;
|
||||||
|
//self.rng.next_u32() as u16;
|
||||||
|
let len = {
|
||||||
|
let mut packet = PublishPacket::<'b, MAX_PROPERTIES>::new();
|
||||||
|
packet.add_topic_name(topic_name);
|
||||||
|
packet.add_qos(qos);
|
||||||
|
packet.add_identifier(identifier);
|
||||||
|
packet.add_message(message);
|
||||||
|
packet.add_retain(retain);
|
||||||
|
packet.encode(self.buffer, self.buffer_len)
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Err(err) = len {
|
||||||
|
error!("[DECODE ERR]: {}", err);
|
||||||
|
return Err(ReasonCode::BuffError);
|
||||||
|
}
|
||||||
|
trace!("Sending message");
|
||||||
|
conn.send(&self.buffer[0..len.unwrap()]).await?;
|
||||||
|
|
||||||
|
Ok(identifier)
|
||||||
|
}
|
||||||
|
/// Method allows sending message to broker specified from the ClientConfig. Client sends the
|
||||||
|
/// message from the parameter `message` to the topic `topic_name` on the broker
|
||||||
|
/// specified in the ClientConfig. If the send fails method returns Err with reason code
|
||||||
|
/// received by broker.
|
||||||
|
pub async fn send_message<'b>(
|
||||||
|
&'b mut self,
|
||||||
|
topic_name: &'b str,
|
||||||
|
message: &'b [u8],
|
||||||
|
qos: QualityOfService,
|
||||||
|
retain: bool,
|
||||||
|
) -> Result<u16, ReasonCode> {
|
||||||
|
match self.config.mqtt_version {
|
||||||
|
MqttVersion::MQTTv3 => Err(ReasonCode::UnsupportedProtocolVersion),
|
||||||
|
MqttVersion::MQTTv5 => self.send_message_v5(topic_name, message, qos, retain).await,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn subscribe_to_topics_v5<'b, const TOPICS: usize>(
|
||||||
|
&'b mut self,
|
||||||
|
topic_names: &'b Vec<&'b str, TOPICS>,
|
||||||
|
) -> Result<u16, ReasonCode> {
|
||||||
|
if self.connection.is_none() {
|
||||||
|
return Err(ReasonCode::NetworkError);
|
||||||
|
}
|
||||||
|
let conn = self.connection.as_mut().unwrap();
|
||||||
|
let identifier: u16 = self.config.rng.next_u32() as u16;
|
||||||
|
let len = {
|
||||||
|
let mut subs = SubscriptionPacket::<'b, TOPICS, MAX_PROPERTIES>::new();
|
||||||
|
subs.packet_identifier = identifier;
|
||||||
|
let mut i = 0;
|
||||||
|
loop {
|
||||||
|
if i == TOPICS {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
subs.add_new_filter(topic_names.get(i).unwrap(), self.config.max_subscribe_qos);
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
subs.encode(self.buffer, self.buffer_len)
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Err(err) = len {
|
||||||
|
error!("[DECODE ERR]: {}", err);
|
||||||
|
return Err(ReasonCode::BuffError);
|
||||||
|
}
|
||||||
|
|
||||||
|
conn.send(&self.buffer[0..len.unwrap()]).await?;
|
||||||
|
|
||||||
|
Ok(identifier)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Method allows client subscribe to multiple topics specified in the parameter
|
||||||
|
/// `topic_names` on the broker specified in the `ClientConfig`. Generics `TOPICS`
|
||||||
|
/// sets the value of the `topics_names` vector. MQTT protocol implementation
|
||||||
|
/// is selected automatically.
|
||||||
|
pub async fn subscribe_to_topics<'b, const TOPICS: usize>(
|
||||||
|
&'b mut self,
|
||||||
|
topic_names: &'b Vec<&'b str, TOPICS>,
|
||||||
|
) -> Result<u16, ReasonCode> {
|
||||||
|
match self.config.mqtt_version {
|
||||||
|
MqttVersion::MQTTv3 => Err(ReasonCode::UnsupportedProtocolVersion),
|
||||||
|
MqttVersion::MQTTv5 => self.subscribe_to_topics_v5(topic_names).await,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Method allows client unsubscribe from the topic specified in the parameter
|
||||||
|
/// `topic_name` on the broker from the `ClientConfig`. MQTT protocol implementation
|
||||||
|
/// is selected automatically.
|
||||||
|
pub async fn unsubscribe_from_topic<'b>(
|
||||||
|
&'b mut self,
|
||||||
|
topic_name: &'b str,
|
||||||
|
) -> Result<u16, ReasonCode> {
|
||||||
|
match self.config.mqtt_version {
|
||||||
|
MqttVersion::MQTTv3 => Err(ReasonCode::UnsupportedProtocolVersion),
|
||||||
|
MqttVersion::MQTTv5 => self.unsubscribe_from_topic_v5(topic_name).await,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn unsubscribe_from_topic_v5<'b>(
|
||||||
|
&'b mut self,
|
||||||
|
topic_name: &'b str,
|
||||||
|
) -> Result<u16, ReasonCode> {
|
||||||
|
if self.connection.is_none() {
|
||||||
|
return Err(ReasonCode::NetworkError);
|
||||||
|
}
|
||||||
|
let conn = self.connection.as_mut().unwrap();
|
||||||
|
let identifier = self.config.rng.next_u32() as u16;
|
||||||
|
|
||||||
|
let len = {
|
||||||
|
let mut unsub = UnsubscriptionPacket::<'b, 1, MAX_PROPERTIES>::new();
|
||||||
|
unsub.packet_identifier = identifier;
|
||||||
|
unsub.add_new_filter(topic_name);
|
||||||
|
unsub.encode(self.buffer, self.buffer_len)
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Err(err) = len {
|
||||||
|
error!("[DECODE ERR]: {}", err);
|
||||||
|
return Err(ReasonCode::BuffError);
|
||||||
|
}
|
||||||
|
conn.send(&self.buffer[0..len.unwrap()]).await?;
|
||||||
|
|
||||||
|
Ok(identifier)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn send_ping_v5<'b>(&'b mut self) -> Result<(), ReasonCode> {
|
||||||
|
if self.connection.is_none() {
|
||||||
|
return Err(ReasonCode::NetworkError);
|
||||||
|
}
|
||||||
|
let conn = self.connection.as_mut().unwrap();
|
||||||
|
let len = {
|
||||||
|
let mut packet = PingreqPacket::new();
|
||||||
|
packet.encode(self.buffer, self.buffer_len)
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Err(err) = len {
|
||||||
|
error!("[DECODE ERR]: {}", err);
|
||||||
|
return Err(ReasonCode::BuffError);
|
||||||
|
}
|
||||||
|
|
||||||
|
conn.send(&self.buffer[0..len.unwrap()]).await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Method allows client send PING message to the broker specified in the `ClientConfig`.
|
||||||
|
/// If there is expectation for long running connection. Method should be executed
|
||||||
|
/// regularly by the timer that counts down the session expiry interval.
|
||||||
|
pub async fn send_ping<'b>(&'b mut self) -> Result<(), ReasonCode> {
|
||||||
|
match self.config.mqtt_version {
|
||||||
|
MqttVersion::MQTTv3 => Err(ReasonCode::UnsupportedProtocolVersion),
|
||||||
|
MqttVersion::MQTTv5 => self.send_ping_v5().await,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn poll<'b, const MAX_TOPICS: usize>(&'b mut self) -> Result<Event<'b>, ReasonCode> {
|
||||||
|
if self.connection.is_none() {
|
||||||
|
return Err(ReasonCode::NetworkError);
|
||||||
|
}
|
||||||
|
|
||||||
|
let conn = self.connection.as_mut().unwrap();
|
||||||
|
|
||||||
|
trace!("Waiting for a packet");
|
||||||
|
|
||||||
|
let read = { receive_packet(self.buffer, self.buffer_len, self.recv_buffer, conn).await? };
|
||||||
|
|
||||||
|
let buf_reader = BuffReader::new(self.buffer, read);
|
||||||
|
|
||||||
|
match PacketType::from(buf_reader.peek_u8().map_err(|_| ReasonCode::BuffError)?) {
|
||||||
|
PacketType::Reserved
|
||||||
|
| PacketType::Connect
|
||||||
|
| PacketType::Subscribe
|
||||||
|
| PacketType::Unsubscribe
|
||||||
|
| PacketType::Pingreq => Err(ReasonCode::ProtocolError),
|
||||||
|
PacketType::Pubrec | PacketType::Pubrel | PacketType::Pubcomp | PacketType::Auth => {
|
||||||
|
Err(ReasonCode::ImplementationSpecificError)
|
||||||
|
}
|
||||||
|
PacketType::Connack => {
|
||||||
|
let mut packet = ConnackPacket::<'b, MAX_PROPERTIES>::new();
|
||||||
|
if let Err(err) = packet.decode(&mut BuffReader::new(self.buffer, read)) {
|
||||||
|
// if err == BufferError::PacketTypeMismatch {
|
||||||
|
// let mut disc = DisconnectPacket::<'b, MAX_PROPERTIES>::new();
|
||||||
|
// if disc.decode(&mut BuffReader::new(self.buffer, read)).is_ok() {
|
||||||
|
// error!("Client was disconnected with reason: ");
|
||||||
|
// return Err(ReasonCode::from(disc.disconnect_reason));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
error!("[DECODE ERR]: {}", err);
|
||||||
|
Err(ReasonCode::BuffError)
|
||||||
|
} else if packet.connect_reason_code != 0x00 {
|
||||||
|
Err(ReasonCode::from(packet.connect_reason_code))
|
||||||
|
} else {
|
||||||
|
Ok(Event::Connack)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PacketType::Puback => {
|
||||||
|
let reason: Result<[u16; 2], BufferError> = {
|
||||||
|
let mut packet = PubackPacket::<'b, MAX_PROPERTIES>::new();
|
||||||
|
packet
|
||||||
|
.decode(&mut BuffReader::new(self.buffer, read))
|
||||||
|
.map(|_| [packet.packet_identifier, packet.reason_code as u16])
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Err(err) = reason {
|
||||||
|
error!("[DECODE ERR]: {}", err);
|
||||||
|
return Err(ReasonCode::BuffError);
|
||||||
|
}
|
||||||
|
|
||||||
|
let res = reason.unwrap();
|
||||||
|
|
||||||
|
if res[1] != 0 {
|
||||||
|
return Err(ReasonCode::from(res[1] as u8));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Event::Puback(res[0]))
|
||||||
|
}
|
||||||
|
PacketType::Suback => {
|
||||||
|
let reason: Result<(u16, Vec<u8, MAX_TOPICS>), BufferError> = {
|
||||||
|
let mut packet = SubackPacket::<'b, MAX_TOPICS, MAX_PROPERTIES>::new();
|
||||||
|
packet
|
||||||
|
.decode(&mut BuffReader::new(self.buffer, read))
|
||||||
|
.map(|_| (packet.packet_identifier, packet.reason_codes))
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Err(err) = reason {
|
||||||
|
error!("[DECODE ERR]: {}", err);
|
||||||
|
return Err(ReasonCode::BuffError);
|
||||||
|
}
|
||||||
|
let (packet_identifier, reasons) = reason.unwrap();
|
||||||
|
let mut i = 0;
|
||||||
|
loop {
|
||||||
|
if i == reasons.len() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if *reasons.get(i).unwrap()
|
||||||
|
!= (<QualityOfService as Into<u8>>::into(self.config.max_subscribe_qos)
|
||||||
|
>> 1)
|
||||||
|
{
|
||||||
|
return Err(ReasonCode::from(*reasons.get(i).unwrap()));
|
||||||
|
}
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
Ok(Event::Suback(packet_identifier))
|
||||||
|
}
|
||||||
|
PacketType::Unsuback => {
|
||||||
|
let res: Result<u16, BufferError> = {
|
||||||
|
let mut packet = UnsubackPacket::<'b, 1, MAX_PROPERTIES>::new();
|
||||||
|
packet
|
||||||
|
.decode(&mut BuffReader::new(self.buffer, read))
|
||||||
|
.map(|_| packet.packet_identifier)
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Err(err) = res {
|
||||||
|
error!("[DECODE ERR]: {}", err);
|
||||||
|
Err(ReasonCode::BuffError)
|
||||||
|
} else {
|
||||||
|
Ok(Event::Unsuback(res.unwrap()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PacketType::Pingresp => {
|
||||||
|
let mut packet = PingrespPacket::new();
|
||||||
|
if let Err(err) = packet.decode(&mut BuffReader::new(self.buffer, read)) {
|
||||||
|
error!("[DECODE ERR]: {}", err);
|
||||||
|
Err(ReasonCode::BuffError)
|
||||||
|
} else {
|
||||||
|
Ok(Event::Pingresp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PacketType::Publish => {
|
||||||
|
let mut packet = PublishPacket::<'b, 5>::new();
|
||||||
|
if let Err(err) = { packet.decode(&mut BuffReader::new(self.buffer, read)) } {
|
||||||
|
// if err == BufferError::PacketTypeMismatch {
|
||||||
|
// let mut disc = DisconnectPacket::<'b, 5>::new();
|
||||||
|
// if disc.decode(&mut BuffReader::new(self.buffer, read)).is_ok() {
|
||||||
|
// error!("Client was disconnected with reason: ");
|
||||||
|
// return Err(ReasonCode::from(disc.disconnect_reason));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
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, MAX_PROPERTIES>::new();
|
||||||
|
puback.packet_identifier = packet.packet_identifier;
|
||||||
|
puback.reason_code = 0x00;
|
||||||
|
{
|
||||||
|
let len = { puback.encode(self.recv_buffer, self.recv_buffer_len) };
|
||||||
|
if let Err(err) = len {
|
||||||
|
error!("[DECODE ERR]: {}", err);
|
||||||
|
return Err(ReasonCode::BuffError);
|
||||||
|
}
|
||||||
|
conn.send(&self.recv_buffer[0..len.unwrap()]).await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Event::Message(
|
||||||
|
packet.topic_name.string,
|
||||||
|
packet.message.unwrap(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
PacketType::Disconnect => {
|
||||||
|
let mut disc = DisconnectPacket::<'b, 5>::new();
|
||||||
|
let res = disc.decode(&mut BuffReader::new(self.buffer, read));
|
||||||
|
|
||||||
|
match res {
|
||||||
|
Ok(_) => Ok(Event::Disconnect(ReasonCode::from(disc.disconnect_reason))),
|
||||||
|
Err(err) => {
|
||||||
|
error!("[DECODE ERR]: {}", err);
|
||||||
|
Err(ReasonCode::BuffError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "tls"))]
|
||||||
|
async fn receive_packet<'c, T: Read + Write>(
|
||||||
|
buffer: &mut [u8],
|
||||||
|
buffer_len: usize,
|
||||||
|
recv_buffer: &mut [u8],
|
||||||
|
conn: &'c mut NetworkConnection<T>,
|
||||||
|
) -> Result<usize, ReasonCode> {
|
||||||
|
use crate::utils::buffer_writer::RemLenError;
|
||||||
|
|
||||||
|
let target_len: usize;
|
||||||
|
let mut rem_len: Result<VariableByteInteger, RemLenError>;
|
||||||
|
let mut writer = BuffWriter::new(buffer, buffer_len);
|
||||||
|
let mut i = 0;
|
||||||
|
|
||||||
|
// Get len of packet
|
||||||
|
trace!("Reading lenght of packet");
|
||||||
|
loop {
|
||||||
|
trace!(" Reading in loop!");
|
||||||
|
let len: usize = conn
|
||||||
|
.receive(&mut recv_buffer[writer.position..(writer.position + 1)])
|
||||||
|
.await?;
|
||||||
|
trace!(" Received data!");
|
||||||
|
if len == 0 {
|
||||||
|
trace!("Zero byte len packet received, dropping connection.");
|
||||||
|
return Err(ReasonCode::NetworkError);
|
||||||
|
}
|
||||||
|
i += len;
|
||||||
|
if let Err(_e) = writer.insert_ref(len, &recv_buffer[writer.position..i]) {
|
||||||
|
error!("Error occurred during write to buffer!");
|
||||||
|
return Err(ReasonCode::BuffError);
|
||||||
|
}
|
||||||
|
if i > 1 {
|
||||||
|
rem_len = writer.get_rem_len();
|
||||||
|
if rem_len.is_ok() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if i >= 5 {
|
||||||
|
error!("Could not read len of packet!");
|
||||||
|
return Err(ReasonCode::NetworkError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
trace!("Lenght done!");
|
||||||
|
let rem_len_len = i;
|
||||||
|
i = 0;
|
||||||
|
if let Ok(l) = VariableByteIntegerDecoder::decode(rem_len.unwrap()) {
|
||||||
|
trace!("Reading packet with target len {}", l);
|
||||||
|
target_len = l as usize;
|
||||||
|
} else {
|
||||||
|
error!("Could not decode len of packet!");
|
||||||
|
return Err(ReasonCode::BuffError);
|
||||||
|
}
|
||||||
|
|
||||||
|
loop {
|
||||||
|
if writer.position == target_len + rem_len_len {
|
||||||
|
trace!("Received packet with len: {}", (target_len + rem_len_len));
|
||||||
|
return Ok(target_len + rem_len_len);
|
||||||
|
}
|
||||||
|
let len: usize = conn
|
||||||
|
.receive(&mut recv_buffer[writer.position..writer.position + (target_len - i)])
|
||||||
|
.await?;
|
||||||
|
i += len;
|
||||||
|
if let Err(_e) =
|
||||||
|
writer.insert_ref(len, &recv_buffer[writer.position..(writer.position + i)])
|
||||||
|
{
|
||||||
|
error!("Error occurred during write to buffer!");
|
||||||
|
return Err(ReasonCode::BuffError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "tls")]
|
||||||
|
async fn receive_packet<'c, T: Read + Write>(
|
||||||
|
buffer: &mut [u8],
|
||||||
|
buffer_len: usize,
|
||||||
|
recv_buffer: &mut [u8],
|
||||||
|
conn: &'c mut NetworkConnection<T>,
|
||||||
|
) -> Result<usize, ReasonCode> {
|
||||||
|
trace!("Reading packet");
|
||||||
|
let mut writer = BuffWriter::new(buffer, buffer_len);
|
||||||
|
let len = conn.receive(recv_buffer).await?;
|
||||||
|
if let Err(_e) = writer.insert_ref(len, &recv_buffer[writer.position..(writer.position + len)])
|
||||||
|
{
|
||||||
|
error!("Error occurred during write to buffer!");
|
||||||
|
return Err(ReasonCode::BuffError);
|
||||||
|
}
|
||||||
|
Ok(len)
|
||||||
|
}
|
|
@ -58,30 +58,29 @@ impl VariableByteIntegerEncoder {
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
encoded_byte = (target % MOD) as u8;
|
encoded_byte = (target % MOD) as u8;
|
||||||
target = target / 128;
|
target /= 128;
|
||||||
if target > 0 {
|
if target > 0 {
|
||||||
encoded_byte = encoded_byte | 128;
|
encoded_byte |= 128;
|
||||||
}
|
}
|
||||||
res[i] = encoded_byte;
|
res[i] = encoded_byte;
|
||||||
i = i + 1;
|
i += 1;
|
||||||
if target <= 0 {
|
if target == 0 {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Ok(res);
|
Ok(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn len(var_int: VariableByteInteger) -> usize {
|
pub fn len(var_int: VariableByteInteger) -> usize {
|
||||||
let mut i: usize = 0;
|
let mut i: usize = 0;
|
||||||
loop {
|
loop {
|
||||||
let encoded_byte: u8;
|
let encoded_byte = var_int[i];
|
||||||
encoded_byte = var_int[i];
|
i += 1;
|
||||||
i = i + 1;
|
|
||||||
if (encoded_byte & 128) == 0 {
|
if (encoded_byte & 128) == 0 {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return i;
|
i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,17 +101,17 @@ impl VariableByteIntegerDecoder {
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
encoded_byte = encoded[i];
|
encoded_byte = encoded[i];
|
||||||
i = i + 1;
|
i += 1;
|
||||||
ret = ret + ((encoded_byte & 127) as u32 * multiplier) as u32;
|
ret += (encoded_byte & 127) as u32 * multiplier;
|
||||||
if multiplier > 128 * 128 * 128 {
|
if multiplier > 128 * 128 * 128 {
|
||||||
return Err(BufferError::DecodingError);
|
return Err(BufferError::DecodingError);
|
||||||
}
|
}
|
||||||
multiplier = multiplier * 128;
|
multiplier *= 128;
|
||||||
if (encoded_byte & 128) == 0 {
|
if (encoded_byte & 128) == 0 {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ok(ret);
|
Ok(ret)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,6 @@
|
||||||
#![cfg_attr(not(feature = "std"), no_std)]
|
#![cfg_attr(not(feature = "std"), no_std)]
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
#![feature(type_alias_impl_trait)]
|
#![feature(type_alias_impl_trait)]
|
||||||
#![feature(generic_associated_types)]
|
|
||||||
pub(crate) mod fmt;
|
pub(crate) mod fmt;
|
||||||
|
|
||||||
pub mod client;
|
pub mod client;
|
||||||
|
|
|
@ -78,8 +78,8 @@ impl<'a, const MAX_PROPERTIES: usize> Packet<'a> for AuthPacket<'a, MAX_PROPERTI
|
||||||
let mut rm_ln = self.property_len;
|
let mut rm_ln = self.property_len;
|
||||||
let property_len_enc: [u8; 4] = VariableByteIntegerEncoder::encode(self.property_len)?;
|
let property_len_enc: [u8; 4] = VariableByteIntegerEncoder::encode(self.property_len)?;
|
||||||
let property_len_len = VariableByteIntegerEncoder::len(property_len_enc);
|
let property_len_len = VariableByteIntegerEncoder::len(property_len_enc);
|
||||||
rm_ln = rm_ln + property_len_len as u32;
|
rm_ln += property_len_len as u32;
|
||||||
rm_ln = rm_ln + 1;
|
rm_ln += 1;
|
||||||
|
|
||||||
buff_writer.write_u8(self.fixed_header)?;
|
buff_writer.write_u8(self.fixed_header)?;
|
||||||
buff_writer.write_variable_byte_int(rm_ln)?;
|
buff_writer.write_variable_byte_int(rm_ln)?;
|
||||||
|
@ -92,7 +92,7 @@ impl<'a, const MAX_PROPERTIES: usize> Packet<'a> for AuthPacket<'a, MAX_PROPERTI
|
||||||
fn decode(&mut self, buff_reader: &mut BuffReader<'a>) -> Result<(), BufferError> {
|
fn decode(&mut self, buff_reader: &mut BuffReader<'a>) -> Result<(), BufferError> {
|
||||||
self.decode_fixed_header(buff_reader)?;
|
self.decode_fixed_header(buff_reader)?;
|
||||||
self.auth_reason = buff_reader.read_u8()?;
|
self.auth_reason = buff_reader.read_u8()?;
|
||||||
return self.decode_properties(buff_reader);
|
self.decode_properties(buff_reader)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_property_len(&mut self, value: u32) {
|
fn set_property_len(&mut self, value: u32) {
|
||||||
|
@ -100,7 +100,7 @@ impl<'a, const MAX_PROPERTIES: usize> Packet<'a> for AuthPacket<'a, MAX_PROPERTI
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_property_len(&mut self) -> u32 {
|
fn get_property_len(&mut self) -> u32 {
|
||||||
return self.property_len;
|
self.property_len
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_to_properties(&mut self, property: Property<'a>) {
|
fn push_to_properties(&mut self, property: Property<'a>) {
|
||||||
|
|
|
@ -72,7 +72,7 @@ impl<'a, const MAX_PROPERTIES: usize> Packet<'a> for ConnackPacket<'a, MAX_PROPE
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decode(&mut self, buff_reader: &mut BuffReader<'a>) -> Result<(), BufferError> {
|
fn decode(&mut self, buff_reader: &mut BuffReader<'a>) -> Result<(), BufferError> {
|
||||||
if self.decode_fixed_header(buff_reader)? != (PacketType::Connack).into() {
|
if self.decode_fixed_header(buff_reader)? != PacketType::Connack {
|
||||||
error!("Packet you are trying to decode is not CONNACK packet!");
|
error!("Packet you are trying to decode is not CONNACK packet!");
|
||||||
return Err(BufferError::PacketTypeMismatch);
|
return Err(BufferError::PacketTypeMismatch);
|
||||||
}
|
}
|
||||||
|
@ -86,7 +86,7 @@ impl<'a, const MAX_PROPERTIES: usize> Packet<'a> for ConnackPacket<'a, MAX_PROPE
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_property_len(&mut self) -> u32 {
|
fn get_property_len(&mut self) -> u32 {
|
||||||
return self.property_len;
|
self.property_len
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_to_properties(&mut self, property: Property<'a>) {
|
fn push_to_properties(&mut self, property: Property<'a>) {
|
||||||
|
|
|
@ -80,22 +80,22 @@ impl<'a, const MAX_PROPERTIES: usize, const MAX_WILL_PROPERTIES: usize>
|
||||||
let y = Property::ReceiveMaximum(20);
|
let y = Property::ReceiveMaximum(20);
|
||||||
x.properties.push(y);
|
x.properties.push(y);
|
||||||
x.client_id.len = 0;
|
x.client_id.len = 0;
|
||||||
return x;
|
x
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_packet_type(&mut self, new_packet_type: PacketType) {
|
pub fn add_packet_type(&mut self, new_packet_type: PacketType) {
|
||||||
self.fixed_header = self.fixed_header & 0x0F;
|
self.fixed_header &= 0x0F;
|
||||||
self.fixed_header = self.fixed_header | <PacketType as Into<u8>>::into(new_packet_type);
|
self.fixed_header |= u8::from(new_packet_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_username(&mut self, username: &EncodedString<'a>) {
|
pub fn add_username(&mut self, username: &EncodedString<'a>) {
|
||||||
self.username = (*username).clone();
|
self.username = (*username).clone();
|
||||||
self.connect_flags = self.connect_flags | 0x80;
|
self.connect_flags |= 0x80;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_password(&mut self, password: &BinaryData<'a>) {
|
pub fn add_password(&mut self, password: &BinaryData<'a>) {
|
||||||
self.password = (*password).clone();
|
self.password = (*password).clone();
|
||||||
self.connect_flags = self.connect_flags | 0x40;
|
self.connect_flags |= 0x40;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_will(&mut self, topic: &EncodedString<'a>, payload: &BinaryData<'a>, retain: bool) {
|
pub fn add_will(&mut self, topic: &EncodedString<'a>, payload: &BinaryData<'a>, retain: bool) {
|
||||||
|
@ -152,7 +152,7 @@ impl<'a, const MAX_PROPERTIES: usize, const MAX_WILL_PROPERTIES: usize> Packet<'
|
||||||
let wil_prop_len_len = VariableByteIntegerEncoder::len(wil_prop_len_enc);
|
let wil_prop_len_len = VariableByteIntegerEncoder::len(wil_prop_len_enc);
|
||||||
rm_ln = rm_ln
|
rm_ln = rm_ln
|
||||||
+ wil_prop_len_len as u32
|
+ wil_prop_len_len as u32
|
||||||
+ self.will_property_len as u32
|
+ self.will_property_len
|
||||||
+ self.will_topic.len as u32
|
+ self.will_topic.len as u32
|
||||||
+ 2
|
+ 2
|
||||||
+ self.will_payload.len as u32
|
+ self.will_payload.len as u32
|
||||||
|
@ -206,7 +206,7 @@ impl<'a, const MAX_PROPERTIES: usize, const MAX_WILL_PROPERTIES: usize> Packet<'
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_property_len(&mut self) -> u32 {
|
fn get_property_len(&mut self) -> u32 {
|
||||||
return self.property_len;
|
self.property_len
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_to_properties(&mut self, property: Property<'a>) {
|
fn push_to_properties(&mut self, property: Property<'a>) {
|
||||||
|
|
|
@ -78,7 +78,7 @@ impl<'a, const MAX_PROPERTIES: usize> Packet<'a> for DisconnectPacket<'a, MAX_PR
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decode(&mut self, buff_reader: &mut BuffReader<'a>) -> Result<(), BufferError> {
|
fn decode(&mut self, buff_reader: &mut BuffReader<'a>) -> Result<(), BufferError> {
|
||||||
if self.decode_fixed_header(buff_reader)? != (PacketType::Disconnect).into() {
|
if self.decode_fixed_header(buff_reader)? != PacketType::Disconnect {
|
||||||
error!("Packet you are trying to decode is not DISCONNECT packet!");
|
error!("Packet you are trying to decode is not DISCONNECT packet!");
|
||||||
return Err(BufferError::WrongPacketToDecode);
|
return Err(BufferError::WrongPacketToDecode);
|
||||||
}
|
}
|
||||||
|
@ -87,7 +87,7 @@ impl<'a, const MAX_PROPERTIES: usize> Packet<'a> for DisconnectPacket<'a, MAX_PR
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
self.disconnect_reason = buff_reader.read_u8()?;
|
self.disconnect_reason = buff_reader.read_u8()?;
|
||||||
return self.decode_properties(buff_reader);
|
self.decode_properties(buff_reader)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_property_len(&mut self, value: u32) {
|
fn set_property_len(&mut self, value: u32) {
|
||||||
|
@ -95,7 +95,7 @@ impl<'a, const MAX_PROPERTIES: usize> Packet<'a> for DisconnectPacket<'a, MAX_PR
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_property_len(&mut self) -> u32 {
|
fn get_property_len(&mut self) -> u32 {
|
||||||
return self.property_len;
|
self.property_len
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_to_properties(&mut self, property: Property<'a>) {
|
fn push_to_properties(&mut self, property: Property<'a>) {
|
||||||
|
|
|
@ -59,14 +59,14 @@ pub trait Packet<'a> {
|
||||||
let prop = properties.get(i).unwrap();
|
let prop = properties.get(i).unwrap();
|
||||||
if self.property_allowed(prop) {
|
if self.property_allowed(prop) {
|
||||||
self.push_to_properties((*prop).clone());
|
self.push_to_properties((*prop).clone());
|
||||||
res = res + prop.len() as u32 + 1;
|
res = res + prop.encoded_len() as u32 + 1;
|
||||||
}
|
}
|
||||||
i = i + 1;
|
i += 1;
|
||||||
if i == max {
|
if i == max {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return res;
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Setter for packet fixed header
|
/// Setter for packet fixed header
|
||||||
|
@ -84,7 +84,7 @@ pub trait Packet<'a> {
|
||||||
loop {
|
loop {
|
||||||
prop = Property::decode(buff_reader)?;
|
prop = Property::decode(buff_reader)?;
|
||||||
//debug!("Parsed property {:?}", prop);
|
//debug!("Parsed property {:?}", prop);
|
||||||
x = x + prop.len() as u32 + 1;
|
x = x + prop.encoded_len() as u32 + 1;
|
||||||
self.push_to_properties(prop);
|
self.push_to_properties(prop);
|
||||||
|
|
||||||
if x == self.get_property_len() {
|
if x == self.get_property_len() {
|
||||||
|
@ -104,6 +104,6 @@ pub trait Packet<'a> {
|
||||||
trace!("First byte of accepted packet: {:02X}", first_byte);
|
trace!("First byte of accepted packet: {:02X}", first_byte);
|
||||||
self.set_fixed_header(first_byte);
|
self.set_fixed_header(first_byte);
|
||||||
self.set_remaining_len(buff_reader.read_variable_byte_int()?);
|
self.set_remaining_len(buff_reader.read_variable_byte_int()?);
|
||||||
return Ok(PacketType::from(first_byte));
|
Ok(PacketType::from(first_byte))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,7 @@ pub enum PacketType {
|
||||||
impl From<u8> for PacketType {
|
impl From<u8> for PacketType {
|
||||||
fn from(orig: u8) -> Self {
|
fn from(orig: u8) -> Self {
|
||||||
let packet_type: u8 = orig & 0xF0;
|
let packet_type: u8 = orig & 0xF0;
|
||||||
return match packet_type {
|
match packet_type {
|
||||||
0x10 => PacketType::Connect,
|
0x10 => PacketType::Connect,
|
||||||
0x20 => PacketType::Connack,
|
0x20 => PacketType::Connack,
|
||||||
0x00 => PacketType::Reserved,
|
0x00 => PacketType::Reserved,
|
||||||
|
@ -65,13 +65,13 @@ impl From<u8> for PacketType {
|
||||||
0xE0 => PacketType::Disconnect,
|
0xE0 => PacketType::Disconnect,
|
||||||
0xF0 => PacketType::Auth,
|
0xF0 => PacketType::Auth,
|
||||||
_ => PacketType::Reserved,
|
_ => PacketType::Reserved,
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Into<u8> for PacketType {
|
impl From<PacketType> for u8 {
|
||||||
fn into(self) -> u8 {
|
fn from(value: PacketType) -> Self {
|
||||||
return match self {
|
match value {
|
||||||
PacketType::Connect => 0x10,
|
PacketType::Connect => 0x10,
|
||||||
PacketType::Connack => 0x20,
|
PacketType::Connack => 0x20,
|
||||||
PacketType::Publish => 0x30,
|
PacketType::Publish => 0x30,
|
||||||
|
@ -88,6 +88,6 @@ impl Into<u8> for PacketType {
|
||||||
PacketType::Disconnect => 0xE0,
|
PacketType::Disconnect => 0xE0,
|
||||||
PacketType::Auth => 0xF0,
|
PacketType::Auth => 0xF0,
|
||||||
PacketType::Reserved => 0x00,
|
PacketType::Reserved => 0x00,
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,7 +48,7 @@ impl<'a> Packet<'a> for PingreqPacket {
|
||||||
fn encode(&mut self, buffer: &mut [u8], buffer_len: usize) -> Result<usize, BufferError> {
|
fn encode(&mut self, buffer: &mut [u8], buffer_len: usize) -> Result<usize, BufferError> {
|
||||||
let mut buff_writer = BuffWriter::new(buffer, buffer_len);
|
let mut buff_writer = BuffWriter::new(buffer, buffer_len);
|
||||||
buff_writer.write_u8(self.fixed_header)?;
|
buff_writer.write_u8(self.fixed_header)?;
|
||||||
buff_writer.write_variable_byte_int(0 as u32)?;
|
buff_writer.write_variable_byte_int(0)?;
|
||||||
Ok(buff_writer.position)
|
Ok(buff_writer.position)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ impl<'a> Packet<'a> for PingreqPacket {
|
||||||
|
|
||||||
fn get_property_len(&mut self) -> u32 {
|
fn get_property_len(&mut self) -> u32 {
|
||||||
error!("PINGREQ packet does not contain any properties!");
|
error!("PINGREQ packet does not contain any properties!");
|
||||||
return 0;
|
0
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_to_properties(&mut self, _property: Property<'a>) {
|
fn push_to_properties(&mut self, _property: Property<'a>) {
|
||||||
|
|
|
@ -35,7 +35,7 @@ pub struct PingrespPacket {
|
||||||
pub remain_len: u32,
|
pub remain_len: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> PingrespPacket {}
|
impl PingrespPacket {}
|
||||||
|
|
||||||
impl<'a> Packet<'a> for PingrespPacket {
|
impl<'a> Packet<'a> for PingrespPacket {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
|
@ -54,7 +54,7 @@ impl<'a> Packet<'a> for PingrespPacket {
|
||||||
|
|
||||||
fn decode(&mut self, buff_reader: &mut BuffReader<'a>) -> Result<(), BufferError> {
|
fn decode(&mut self, buff_reader: &mut BuffReader<'a>) -> Result<(), BufferError> {
|
||||||
let x = self.decode_fixed_header(buff_reader)?;
|
let x = self.decode_fixed_header(buff_reader)?;
|
||||||
if x != (PacketType::Pingresp).into() {
|
if x != PacketType::Pingresp {
|
||||||
error!("Packet you are trying to decode is not PINGRESP packet!");
|
error!("Packet you are trying to decode is not PINGRESP packet!");
|
||||||
return Err(BufferError::PacketTypeMismatch);
|
return Err(BufferError::PacketTypeMismatch);
|
||||||
}
|
}
|
||||||
|
@ -71,7 +71,7 @@ impl<'a> Packet<'a> for PingrespPacket {
|
||||||
|
|
||||||
fn get_property_len(&mut self) -> u32 {
|
fn get_property_len(&mut self) -> u32 {
|
||||||
error!("PINGRESP packet does not contain any properties!");
|
error!("PINGRESP packet does not contain any properties!");
|
||||||
return 0;
|
0
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_to_properties(&mut self, _property: Property<'a>) {
|
fn push_to_properties(&mut self, _property: Property<'a>) {
|
||||||
|
|
|
@ -61,7 +61,9 @@ pub enum Property<'a> {
|
||||||
|
|
||||||
impl<'a> Property<'a> {
|
impl<'a> Property<'a> {
|
||||||
pub fn connect_property(&self) -> bool {
|
pub fn connect_property(&self) -> bool {
|
||||||
return match self {
|
// not possible to use with associated values with different types
|
||||||
|
#[allow(clippy::match_like_matches_macro)]
|
||||||
|
match self {
|
||||||
Property::SessionExpiryInterval(_u) => true,
|
Property::SessionExpiryInterval(_u) => true,
|
||||||
Property::ReceiveMaximum(_u) => true,
|
Property::ReceiveMaximum(_u) => true,
|
||||||
Property::MaximumPacketSize(_u) => true,
|
Property::MaximumPacketSize(_u) => true,
|
||||||
|
@ -72,11 +74,13 @@ impl<'a> Property<'a> {
|
||||||
Property::AuthenticationMethod(_u) => true,
|
Property::AuthenticationMethod(_u) => true,
|
||||||
Property::AuthenticationData(_u) => true,
|
Property::AuthenticationData(_u) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn connack_property(&self) -> bool {
|
pub fn connack_property(&self) -> bool {
|
||||||
return match self {
|
// not possible to use with associated values with different types
|
||||||
|
#[allow(clippy::match_like_matches_macro)]
|
||||||
|
match self {
|
||||||
Property::SessionExpiryInterval(_u) => true,
|
Property::SessionExpiryInterval(_u) => true,
|
||||||
Property::ReceiveMaximum(_u) => true,
|
Property::ReceiveMaximum(_u) => true,
|
||||||
Property::MaximumQoS(_u) => true,
|
Property::MaximumQoS(_u) => true,
|
||||||
|
@ -94,11 +98,13 @@ impl<'a> Property<'a> {
|
||||||
Property::AuthenticationMethod(_u) => true,
|
Property::AuthenticationMethod(_u) => true,
|
||||||
Property::AuthenticationData(_u) => true,
|
Property::AuthenticationData(_u) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn publish_property(&self) -> bool {
|
pub fn publish_property(&self) -> bool {
|
||||||
return match self {
|
// not possible to use with associated values with different types
|
||||||
|
#[allow(clippy::match_like_matches_macro)]
|
||||||
|
match self {
|
||||||
Property::PayloadFormat(_u) => true,
|
Property::PayloadFormat(_u) => true,
|
||||||
Property::MessageExpiryInterval(_u) => true,
|
Property::MessageExpiryInterval(_u) => true,
|
||||||
Property::TopicAlias(_u) => true,
|
Property::TopicAlias(_u) => true,
|
||||||
|
@ -108,142 +114,155 @@ impl<'a> Property<'a> {
|
||||||
Property::SubscriptionIdentifier(_u) => true,
|
Property::SubscriptionIdentifier(_u) => true,
|
||||||
Property::ContentType(_u) => true,
|
Property::ContentType(_u) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn puback_property(&self) -> bool {
|
pub fn puback_property(&self) -> bool {
|
||||||
return match self {
|
// not possible to use with associated values with different types
|
||||||
|
#[allow(clippy::match_like_matches_macro)]
|
||||||
|
match self {
|
||||||
Property::ReasonString(_u) => true,
|
Property::ReasonString(_u) => true,
|
||||||
Property::UserProperty(_u) => true,
|
Property::UserProperty(_u) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pubrec_property(&self) -> bool {
|
pub fn pubrec_property(&self) -> bool {
|
||||||
return match self {
|
// not possible to use with associated values with different types
|
||||||
|
#[allow(clippy::match_like_matches_macro)]
|
||||||
|
match self {
|
||||||
Property::ReasonString(_u) => true,
|
Property::ReasonString(_u) => true,
|
||||||
Property::UserProperty(_u) => true,
|
Property::UserProperty(_u) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pubrel_property(&self) -> bool {
|
pub fn pubrel_property(&self) -> bool {
|
||||||
return match self {
|
// not possible to use with associated values with different types
|
||||||
|
#[allow(clippy::match_like_matches_macro)]
|
||||||
|
match self {
|
||||||
Property::ReasonString(_u) => true,
|
Property::ReasonString(_u) => true,
|
||||||
Property::UserProperty(_u) => true,
|
Property::UserProperty(_u) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pubcomp_property(&self) -> bool {
|
pub fn pubcomp_property(&self) -> bool {
|
||||||
return match self {
|
// not possible to use with associated values with different types
|
||||||
|
#[allow(clippy::match_like_matches_macro)]
|
||||||
|
match self {
|
||||||
Property::ReasonString(_u) => true,
|
Property::ReasonString(_u) => true,
|
||||||
Property::UserProperty(_u) => true,
|
Property::UserProperty(_u) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn subscribe_property(&self) -> bool {
|
pub fn subscribe_property(&self) -> bool {
|
||||||
return match self {
|
// not possible to use with associated values with different types
|
||||||
|
#[allow(clippy::match_like_matches_macro)]
|
||||||
|
match self {
|
||||||
Property::SubscriptionIdentifier(_u) => true,
|
Property::SubscriptionIdentifier(_u) => true,
|
||||||
Property::UserProperty(_u) => true,
|
Property::UserProperty(_u) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn suback_property(&self) -> bool {
|
pub fn suback_property(&self) -> bool {
|
||||||
return match self {
|
// not possible to use with associated values with different types
|
||||||
|
#[allow(clippy::match_like_matches_macro)]
|
||||||
|
match self {
|
||||||
Property::ReasonString(_u) => true,
|
Property::ReasonString(_u) => true,
|
||||||
Property::UserProperty(_u) => true,
|
Property::UserProperty(_u) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unsubscribe_property(&self) -> bool {
|
pub fn unsubscribe_property(&self) -> bool {
|
||||||
return match self {
|
matches!(self, Property::UserProperty(_u))
|
||||||
Property::UserProperty(_u) => true,
|
|
||||||
_ => false,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unsuback_property(&self) -> bool {
|
pub fn unsuback_property(&self) -> bool {
|
||||||
return match self {
|
// not possible to use with associated values with different types
|
||||||
|
#[allow(clippy::match_like_matches_macro)]
|
||||||
|
match self {
|
||||||
Property::ReasonString(_u) => true,
|
Property::ReasonString(_u) => true,
|
||||||
Property::UserProperty(_u) => true,
|
Property::UserProperty(_u) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pingreq_property(&self) -> bool {
|
pub fn pingreq_property(&self) -> bool {
|
||||||
return match self {
|
warn!("pingreq property list is incomplete");
|
||||||
_ => false,
|
false
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pingresp_property(&self) -> bool {
|
pub fn pingresp_property(&self) -> bool {
|
||||||
return match self {
|
warn!("pingresp property list is incomplete");
|
||||||
_ => false,
|
false
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn disconnect_property(&self) -> bool {
|
pub fn disconnect_property(&self) -> bool {
|
||||||
return match self {
|
// not possible to use with associated values with different types
|
||||||
|
#[allow(clippy::match_like_matches_macro)]
|
||||||
|
match self {
|
||||||
Property::SessionExpiryInterval(_u) => true,
|
Property::SessionExpiryInterval(_u) => true,
|
||||||
Property::ReasonString(_u) => true,
|
Property::ReasonString(_u) => true,
|
||||||
Property::UserProperty(_u) => true,
|
Property::UserProperty(_u) => true,
|
||||||
Property::ServerReference(_u) => true,
|
Property::ServerReference(_u) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn auth_property(&self) -> bool {
|
pub fn auth_property(&self) -> bool {
|
||||||
return match self {
|
// not possible to use with associated values with different types
|
||||||
|
#[allow(clippy::match_like_matches_macro)]
|
||||||
|
match self {
|
||||||
Property::AuthenticationMethod(_u) => true,
|
Property::AuthenticationMethod(_u) => true,
|
||||||
Property::AuthenticationData(_u) => true,
|
Property::AuthenticationData(_u) => true,
|
||||||
Property::ReasonString(_u) => true,
|
Property::ReasonString(_u) => true,
|
||||||
Property::UserProperty(_u) => true,
|
Property::UserProperty(_u) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn len(&self) -> u16 {
|
pub fn encoded_len(&self) -> u16 {
|
||||||
return match self {
|
match self {
|
||||||
Property::PayloadFormat(_u) => 1,
|
Property::PayloadFormat(_u) => 1,
|
||||||
Property::MessageExpiryInterval(_u) => 4,
|
Property::MessageExpiryInterval(_u) => 4,
|
||||||
Property::ContentType(u) => u.len(),
|
Property::ContentType(u) => u.encoded_len(),
|
||||||
Property::ResponseTopic(u) => u.len(),
|
Property::ResponseTopic(u) => u.encoded_len(),
|
||||||
Property::CorrelationData(u) => u.len(),
|
Property::CorrelationData(u) => u.encoded_len(),
|
||||||
Property::SubscriptionIdentifier(u) => {
|
Property::SubscriptionIdentifier(u) => {
|
||||||
VariableByteIntegerEncoder::len(VariableByteIntegerEncoder::encode(*u).unwrap())
|
VariableByteIntegerEncoder::len(VariableByteIntegerEncoder::encode(*u).unwrap())
|
||||||
as u16
|
as u16
|
||||||
}
|
}
|
||||||
Property::SessionExpiryInterval(_u) => 4,
|
Property::SessionExpiryInterval(_u) => 4,
|
||||||
Property::AssignedClientIdentifier(u) => u.len(),
|
Property::AssignedClientIdentifier(u) => u.encoded_len(),
|
||||||
Property::ServerKeepAlive(_u) => 2,
|
Property::ServerKeepAlive(_u) => 2,
|
||||||
Property::AuthenticationMethod(u) => u.len(),
|
Property::AuthenticationMethod(u) => u.encoded_len(),
|
||||||
Property::AuthenticationData(u) => u.len(),
|
Property::AuthenticationData(u) => u.encoded_len(),
|
||||||
Property::RequestProblemInformation(_u) => 1,
|
Property::RequestProblemInformation(_u) => 1,
|
||||||
Property::WillDelayInterval(_u) => 4,
|
Property::WillDelayInterval(_u) => 4,
|
||||||
Property::RequestResponseInformation(_u) => 1,
|
Property::RequestResponseInformation(_u) => 1,
|
||||||
Property::ResponseInformation(u) => u.len(),
|
Property::ResponseInformation(u) => u.encoded_len(),
|
||||||
Property::ServerReference(u) => u.len(),
|
Property::ServerReference(u) => u.encoded_len(),
|
||||||
Property::ReasonString(u) => u.len(),
|
Property::ReasonString(u) => u.encoded_len(),
|
||||||
Property::ReceiveMaximum(_u) => 2,
|
Property::ReceiveMaximum(_u) => 2,
|
||||||
Property::TopicAliasMaximum(_u) => 2,
|
Property::TopicAliasMaximum(_u) => 2,
|
||||||
Property::TopicAlias(_u) => 2,
|
Property::TopicAlias(_u) => 2,
|
||||||
Property::MaximumQoS(_u) => 1,
|
Property::MaximumQoS(_u) => 1,
|
||||||
Property::RetainAvailable(_u) => 1,
|
Property::RetainAvailable(_u) => 1,
|
||||||
Property::UserProperty(u) => u.len(),
|
Property::UserProperty(u) => u.encoded_len(),
|
||||||
Property::MaximumPacketSize(_u) => 4,
|
Property::MaximumPacketSize(_u) => 4,
|
||||||
Property::WildcardSubscriptionAvailable(_u) => 1,
|
Property::WildcardSubscriptionAvailable(_u) => 1,
|
||||||
Property::SubscriptionIdentifierAvailable(_u) => 1,
|
Property::SubscriptionIdentifierAvailable(_u) => 1,
|
||||||
Property::SharedSubscriptionAvailable(_u) => 1,
|
Property::SharedSubscriptionAvailable(_u) => 1,
|
||||||
_ => 0,
|
_ => 0,
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn encode(&self, buff_writer: &mut BuffWriter<'a>) -> Result<(), BufferError> {
|
pub fn encode(&self, buff_writer: &mut BuffWriter<'a>) -> Result<(), BufferError> {
|
||||||
return match self {
|
match self {
|
||||||
Property::PayloadFormat(u) => buff_writer.write_u8(*u),
|
Property::PayloadFormat(u) => buff_writer.write_u8(*u),
|
||||||
Property::MessageExpiryInterval(u) => buff_writer.write_u32(*u),
|
Property::MessageExpiryInterval(u) => buff_writer.write_u32(*u),
|
||||||
Property::ContentType(u) => buff_writer.write_string_ref(u),
|
Property::ContentType(u) => buff_writer.write_string_ref(u),
|
||||||
|
@ -272,7 +291,7 @@ impl<'a> Property<'a> {
|
||||||
Property::SubscriptionIdentifierAvailable(u) => buff_writer.write_u8(*u),
|
Property::SubscriptionIdentifierAvailable(u) => buff_writer.write_u8(*u),
|
||||||
Property::SharedSubscriptionAvailable(u) => buff_writer.write_u8(*u),
|
Property::SharedSubscriptionAvailable(u) => buff_writer.write_u8(*u),
|
||||||
_ => Err(BufferError::PropertyNotFound),
|
_ => Err(BufferError::PropertyNotFound),
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn decode(buff_reader: &mut BuffReader<'a>) -> Result<Property<'a>, BufferError> {
|
pub fn decode(buff_reader: &mut BuffReader<'a>) -> Result<Property<'a>, BufferError> {
|
||||||
|
@ -321,9 +340,9 @@ impl<'a> Property<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Into<u8> for &Property<'a> {
|
impl<'a> From<&Property<'a>> for u8 {
|
||||||
fn into(self) -> u8 {
|
fn from(value: &Property<'a>) -> Self {
|
||||||
return match &*self {
|
match value {
|
||||||
Property::PayloadFormat(_u) => 0x01,
|
Property::PayloadFormat(_u) => 0x01,
|
||||||
Property::MessageExpiryInterval(_u) => 0x02,
|
Property::MessageExpiryInterval(_u) => 0x02,
|
||||||
Property::ContentType(_u) => 0x03,
|
Property::ContentType(_u) => 0x03,
|
||||||
|
@ -352,14 +371,13 @@ impl<'a> Into<u8> for &Property<'a> {
|
||||||
Property::SubscriptionIdentifierAvailable(_u) => 0x29,
|
Property::SubscriptionIdentifierAvailable(_u) => 0x29,
|
||||||
Property::SharedSubscriptionAvailable(_u) => 0x2A,
|
Property::SharedSubscriptionAvailable(_u) => 0x2A,
|
||||||
_ => 0x00,
|
_ => 0x00,
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> From<u8> for Property<'a> {
|
impl<'a> From<u8> for Property<'a> {
|
||||||
fn from(_orig: u8) -> Self {
|
fn from(_orig: u8) -> Self {
|
||||||
return match _orig {
|
warn!("Deserialization of Properties from u8 is not implemented");
|
||||||
_ => Property::Reserved(),
|
Property::Reserved()
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,7 +74,7 @@ impl<'a, const MAX_PROPERTIES: usize> Packet<'a> for PubackPacket<'a, MAX_PROPER
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decode(&mut self, buff_reader: &mut BuffReader<'a>) -> Result<(), BufferError> {
|
fn decode(&mut self, buff_reader: &mut BuffReader<'a>) -> Result<(), BufferError> {
|
||||||
if self.decode_fixed_header(buff_reader)? != (PacketType::Puback).into() {
|
if self.decode_fixed_header(buff_reader)? != PacketType::Puback {
|
||||||
error!("Packet you are trying to decode is not PUBACK packet!");
|
error!("Packet you are trying to decode is not PUBACK packet!");
|
||||||
return Err(BufferError::PacketTypeMismatch);
|
return Err(BufferError::PacketTypeMismatch);
|
||||||
}
|
}
|
||||||
|
@ -95,7 +95,7 @@ impl<'a, const MAX_PROPERTIES: usize> Packet<'a> for PubackPacket<'a, MAX_PROPER
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_property_len(&mut self) -> u32 {
|
fn get_property_len(&mut self) -> u32 {
|
||||||
return self.property_len;
|
self.property_len
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_to_properties(&mut self, property: Property<'a>) {
|
fn push_to_properties(&mut self, property: Property<'a>) {
|
||||||
|
|
|
@ -74,7 +74,7 @@ impl<'a, const MAX_PROPERTIES: usize> Packet<'a> for PubcompPacket<'a, MAX_PROPE
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decode(&mut self, buff_reader: &mut BuffReader<'a>) -> Result<(), BufferError> {
|
fn decode(&mut self, buff_reader: &mut BuffReader<'a>) -> Result<(), BufferError> {
|
||||||
if self.decode_fixed_header(buff_reader)? != (PacketType::Pubcomp).into() {
|
if self.decode_fixed_header(buff_reader)? != PacketType::Pubcomp {
|
||||||
error!("Packet you are trying to decode is not PUBCOMP packet!");
|
error!("Packet you are trying to decode is not PUBCOMP packet!");
|
||||||
return Err(BufferError::PacketTypeMismatch);
|
return Err(BufferError::PacketTypeMismatch);
|
||||||
}
|
}
|
||||||
|
@ -89,7 +89,7 @@ impl<'a, const MAX_PROPERTIES: usize> Packet<'a> for PubcompPacket<'a, MAX_PROPE
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_property_len(&mut self) -> u32 {
|
fn get_property_len(&mut self) -> u32 {
|
||||||
return self.property_len;
|
self.property_len
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_to_properties(&mut self, property: Property<'a>) {
|
fn push_to_properties(&mut self, property: Property<'a>) {
|
||||||
|
|
|
@ -44,23 +44,23 @@ pub enum QualityOfService {
|
||||||
|
|
||||||
impl From<u8> for QualityOfService {
|
impl From<u8> for QualityOfService {
|
||||||
fn from(orig: u8) -> Self {
|
fn from(orig: u8) -> Self {
|
||||||
return match orig {
|
match orig {
|
||||||
0 => QoS0,
|
0 => QoS0,
|
||||||
2 => QoS1,
|
2 => QoS1,
|
||||||
4 => QoS2,
|
4 => QoS2,
|
||||||
_ => INVALID,
|
_ => INVALID,
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Into<u8> for QualityOfService {
|
impl From<QualityOfService> for u8 {
|
||||||
fn into(self) -> u8 {
|
fn from(value: QualityOfService) -> Self {
|
||||||
return match self {
|
match value {
|
||||||
QoS0 => 0,
|
QoS0 => 0,
|
||||||
QoS1 => 2,
|
QoS1 => 2,
|
||||||
QoS2 => 4,
|
QoS2 => 4,
|
||||||
INVALID => 3,
|
INVALID => 3,
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,7 +85,11 @@ impl<'a, const MAX_PROPERTIES: usize> PublishPacket<'a, MAX_PROPERTIES> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_qos(&mut self, qos: QualityOfService) {
|
pub fn add_qos(&mut self, qos: QualityOfService) {
|
||||||
self.fixed_header = self.fixed_header | <QualityOfService as Into<u8>>::into(qos);
|
self.fixed_header |= <QualityOfService as Into<u8>>::into(qos);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_retain(&mut self, retain: bool) {
|
||||||
|
self.fixed_header |= retain as u8
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_identifier(&mut self, identifier: u16) {
|
pub fn add_identifier(&mut self, identifier: u16) {
|
||||||
|
@ -118,7 +122,7 @@ impl<'a, const MAX_PROPERTIES: usize> Packet<'a> for PublishPacket<'a, MAX_PROPE
|
||||||
buff_writer.write_u8(self.fixed_header)?;
|
buff_writer.write_u8(self.fixed_header)?;
|
||||||
let qos = self.fixed_header & 0x06;
|
let qos = self.fixed_header & 0x06;
|
||||||
if qos != 0 {
|
if qos != 0 {
|
||||||
rm_ln = rm_ln + 2;
|
rm_ln += 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
buff_writer.write_variable_byte_int(rm_ln)?;
|
buff_writer.write_variable_byte_int(rm_ln)?;
|
||||||
|
@ -135,7 +139,7 @@ impl<'a, const MAX_PROPERTIES: usize> Packet<'a> for PublishPacket<'a, MAX_PROPE
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decode(&mut self, buff_reader: &mut BuffReader<'a>) -> Result<(), BufferError> {
|
fn decode(&mut self, buff_reader: &mut BuffReader<'a>) -> Result<(), BufferError> {
|
||||||
if self.decode_fixed_header(buff_reader)? != (PacketType::Publish).into() {
|
if self.decode_fixed_header(buff_reader)? != PacketType::Publish {
|
||||||
error!("Packet you are trying to decode is not PUBLISH packet!");
|
error!("Packet you are trying to decode is not PUBLISH packet!");
|
||||||
return Err(BufferError::PacketTypeMismatch);
|
return Err(BufferError::PacketTypeMismatch);
|
||||||
}
|
}
|
||||||
|
@ -158,7 +162,7 @@ impl<'a, const MAX_PROPERTIES: usize> Packet<'a> for PublishPacket<'a, MAX_PROPE
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_property_len(&mut self) -> u32 {
|
fn get_property_len(&mut self) -> u32 {
|
||||||
return self.property_len;
|
self.property_len
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_to_properties(&mut self, property: Property<'a>) {
|
fn push_to_properties(&mut self, property: Property<'a>) {
|
||||||
|
|
|
@ -74,13 +74,13 @@ impl<'a, const MAX_PROPERTIES: usize> Packet<'a> for PubrecPacket<'a, MAX_PROPER
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decode(&mut self, buff_reader: &mut BuffReader<'a>) -> Result<(), BufferError> {
|
fn decode(&mut self, buff_reader: &mut BuffReader<'a>) -> Result<(), BufferError> {
|
||||||
if self.decode_fixed_header(buff_reader)? != (PacketType::Pubrec).into() {
|
if self.decode_fixed_header(buff_reader)? != PacketType::Pubrec {
|
||||||
error!("Packet you are trying to decode is not PUBREC packet!");
|
error!("Packet you are trying to decode is not PUBREC packet!");
|
||||||
return Err(BufferError::PacketTypeMismatch);
|
return Err(BufferError::PacketTypeMismatch);
|
||||||
}
|
}
|
||||||
self.packet_identifier = buff_reader.read_u16()?;
|
self.packet_identifier = buff_reader.read_u16()?;
|
||||||
self.reason_code = buff_reader.read_u8()?;
|
self.reason_code = buff_reader.read_u8()?;
|
||||||
return self.decode_properties(buff_reader);
|
self.decode_properties(buff_reader)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_property_len(&mut self, value: u32) {
|
fn set_property_len(&mut self, value: u32) {
|
||||||
|
@ -88,7 +88,7 @@ impl<'a, const MAX_PROPERTIES: usize> Packet<'a> for PubrecPacket<'a, MAX_PROPER
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_property_len(&mut self) -> u32 {
|
fn get_property_len(&mut self) -> u32 {
|
||||||
return self.property_len;
|
self.property_len
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_to_properties(&mut self, property: Property<'a>) {
|
fn push_to_properties(&mut self, property: Property<'a>) {
|
||||||
|
|
|
@ -74,13 +74,13 @@ impl<'a, const MAX_PROPERTIES: usize> Packet<'a> for PubrelPacket<'a, MAX_PROPER
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decode(&mut self, buff_reader: &mut BuffReader<'a>) -> Result<(), BufferError> {
|
fn decode(&mut self, buff_reader: &mut BuffReader<'a>) -> Result<(), BufferError> {
|
||||||
if self.decode_fixed_header(buff_reader)? != (PacketType::Pubrel).into() {
|
if self.decode_fixed_header(buff_reader)? != PacketType::Pubrel {
|
||||||
error!("Packet you are trying to decode is not PUBREL packet!");
|
error!("Packet you are trying to decode is not PUBREL packet!");
|
||||||
return Err(BufferError::PacketTypeMismatch);
|
return Err(BufferError::PacketTypeMismatch);
|
||||||
}
|
}
|
||||||
self.packet_identifier = buff_reader.read_u16()?;
|
self.packet_identifier = buff_reader.read_u16()?;
|
||||||
self.reason_code = buff_reader.read_u8()?;
|
self.reason_code = buff_reader.read_u8()?;
|
||||||
return self.decode_properties(buff_reader);
|
self.decode_properties(buff_reader)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_property_len(&mut self, value: u32) {
|
fn set_property_len(&mut self, value: u32) {
|
||||||
|
@ -88,7 +88,7 @@ impl<'a, const MAX_PROPERTIES: usize> Packet<'a> for PubrelPacket<'a, MAX_PROPER
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_property_len(&mut self) -> u32 {
|
fn get_property_len(&mut self) -> u32 {
|
||||||
return self.property_len;
|
self.property_len
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_to_properties(&mut self, property: Property<'a>) {
|
fn push_to_properties(&mut self, property: Property<'a>) {
|
||||||
|
|
|
@ -75,9 +75,9 @@ pub enum ReasonCode {
|
||||||
NetworkError,
|
NetworkError,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Into<u8> for ReasonCode {
|
impl From<ReasonCode> for u8 {
|
||||||
fn into(self) -> u8 {
|
fn from(value: ReasonCode) -> Self {
|
||||||
return match self {
|
match value {
|
||||||
ReasonCode::Success => 0x00,
|
ReasonCode::Success => 0x00,
|
||||||
ReasonCode::GrantedQoS1 => 0x01,
|
ReasonCode::GrantedQoS1 => 0x01,
|
||||||
ReasonCode::GrantedQoS2 => 0x02,
|
ReasonCode::GrantedQoS2 => 0x02,
|
||||||
|
@ -124,13 +124,13 @@ impl Into<u8> for ReasonCode {
|
||||||
ReasonCode::TimerNotSupported => 0xFD,
|
ReasonCode::TimerNotSupported => 0xFD,
|
||||||
ReasonCode::BuffError => 0xFE,
|
ReasonCode::BuffError => 0xFE,
|
||||||
ReasonCode::NetworkError => 0xFF,
|
ReasonCode::NetworkError => 0xFF,
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<u8> for ReasonCode {
|
impl From<u8> for ReasonCode {
|
||||||
fn from(orig: u8) -> Self {
|
fn from(orig: u8) -> Self {
|
||||||
return match orig {
|
match orig {
|
||||||
0x00 => ReasonCode::Success,
|
0x00 => ReasonCode::Success,
|
||||||
0x01 => ReasonCode::GrantedQoS1,
|
0x01 => ReasonCode::GrantedQoS1,
|
||||||
0x02 => ReasonCode::GrantedQoS2,
|
0x02 => ReasonCode::GrantedQoS2,
|
||||||
|
@ -176,7 +176,7 @@ impl From<u8> for ReasonCode {
|
||||||
0xFD => ReasonCode::TimerNotSupported,
|
0xFD => ReasonCode::TimerNotSupported,
|
||||||
0xFE => ReasonCode::BuffError,
|
0xFE => ReasonCode::BuffError,
|
||||||
_ => ReasonCode::NetworkError,
|
_ => ReasonCode::NetworkError,
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -61,7 +61,7 @@ impl<'a, const MAX_REASONS: usize, const MAX_PROPERTIES: usize>
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Ok(());
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,17 +81,17 @@ impl<'a, const MAX_REASONS: usize, const MAX_PROPERTIES: usize> Packet<'a>
|
||||||
|
|
||||||
fn encode(&mut self, _buffer: &mut [u8], _buffer_len: usize) -> Result<usize, BufferError> {
|
fn encode(&mut self, _buffer: &mut [u8], _buffer_len: usize) -> Result<usize, BufferError> {
|
||||||
error!("SUBACK packet does not support encoding!");
|
error!("SUBACK packet does not support encoding!");
|
||||||
return Err(BufferError::WrongPacketToEncode);
|
Err(BufferError::WrongPacketToEncode)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decode(&mut self, buff_reader: &mut BuffReader<'a>) -> Result<(), BufferError> {
|
fn decode(&mut self, buff_reader: &mut BuffReader<'a>) -> Result<(), BufferError> {
|
||||||
if self.decode_fixed_header(buff_reader)? != (PacketType::Suback).into() {
|
if self.decode_fixed_header(buff_reader)? != PacketType::Suback {
|
||||||
error!("Packet you are trying to decode is not SUBACK packet!");
|
error!("Packet you are trying to decode is not SUBACK packet!");
|
||||||
return Err(BufferError::PacketTypeMismatch);
|
return Err(BufferError::PacketTypeMismatch);
|
||||||
}
|
}
|
||||||
self.packet_identifier = buff_reader.read_u16()?;
|
self.packet_identifier = buff_reader.read_u16()?;
|
||||||
self.decode_properties(buff_reader)?;
|
self.decode_properties(buff_reader)?;
|
||||||
return self.read_reason_codes(buff_reader);
|
self.read_reason_codes(buff_reader)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_property_len(&mut self, value: u32) {
|
fn set_property_len(&mut self, value: u32) {
|
||||||
|
@ -99,7 +99,7 @@ impl<'a, const MAX_REASONS: usize, const MAX_PROPERTIES: usize> Packet<'a>
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_property_len(&mut self) -> u32 {
|
fn get_property_len(&mut self) -> u32 {
|
||||||
return self.property_len;
|
self.property_len
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_to_properties(&mut self, property: Property<'a>) {
|
fn push_to_properties(&mut self, property: Property<'a>) {
|
||||||
|
|
|
@ -52,10 +52,9 @@ impl<'a, const MAX_FILTERS: usize, const MAX_PROPERTIES: usize>
|
||||||
let mut new_filter = TopicFilter::new();
|
let mut new_filter = TopicFilter::new();
|
||||||
new_filter.filter.string = topic_name;
|
new_filter.filter.string = topic_name;
|
||||||
new_filter.filter.len = len as u16;
|
new_filter.filter.len = len as u16;
|
||||||
new_filter.sub_options =
|
new_filter.sub_options |= <QualityOfService as Into<u8>>::into(qos) >> 1;
|
||||||
new_filter.sub_options | (<QualityOfService as Into<u8>>::into(qos) >> 1);
|
|
||||||
self.topic_filters.push(new_filter);
|
self.topic_filters.push(new_filter);
|
||||||
self.topic_filter_len = self.topic_filter_len + 1;
|
self.topic_filter_len += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,7 +62,7 @@ impl<'a, const MAX_FILTERS: usize, const MAX_PROPERTIES: usize> Packet<'a>
|
||||||
for SubscriptionPacket<'a, MAX_FILTERS, MAX_PROPERTIES>
|
for SubscriptionPacket<'a, MAX_FILTERS, MAX_PROPERTIES>
|
||||||
{
|
{
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
let x = Self {
|
Self {
|
||||||
fixed_header: PacketType::Subscribe.into(),
|
fixed_header: PacketType::Subscribe.into(),
|
||||||
remain_len: 0,
|
remain_len: 0,
|
||||||
packet_identifier: 1,
|
packet_identifier: 1,
|
||||||
|
@ -71,8 +70,7 @@ impl<'a, const MAX_FILTERS: usize, const MAX_PROPERTIES: usize> Packet<'a>
|
||||||
properties: Vec::<Property<'a>, MAX_PROPERTIES>::new(),
|
properties: Vec::<Property<'a>, MAX_PROPERTIES>::new(),
|
||||||
topic_filter_len: 0,
|
topic_filter_len: 0,
|
||||||
topic_filters: Vec::<TopicFilter<'a>, MAX_FILTERS>::new(),
|
topic_filters: Vec::<TopicFilter<'a>, MAX_FILTERS>::new(),
|
||||||
};
|
}
|
||||||
return x;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn encode(&mut self, buffer: &mut [u8], buffer_len: usize) -> Result<usize, BufferError> {
|
fn encode(&mut self, buffer: &mut [u8], buffer_len: usize) -> Result<usize, BufferError> {
|
||||||
|
@ -86,7 +84,7 @@ impl<'a, const MAX_FILTERS: usize, const MAX_PROPERTIES: usize> Packet<'a>
|
||||||
let mut filters_len = 0;
|
let mut filters_len = 0;
|
||||||
loop {
|
loop {
|
||||||
filters_len = filters_len + self.topic_filters.get(lt).unwrap().filter.len + 3;
|
filters_len = filters_len + self.topic_filters.get(lt).unwrap().filter.len + 3;
|
||||||
lt = lt + 1;
|
lt += 1;
|
||||||
if lt == self.topic_filter_len as usize {
|
if lt == self.topic_filter_len as usize {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -115,7 +113,7 @@ impl<'a, const MAX_FILTERS: usize, const MAX_PROPERTIES: usize> Packet<'a>
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_property_len(&mut self) -> u32 {
|
fn get_property_len(&mut self) -> u32 {
|
||||||
return self.property_len;
|
self.property_len
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_to_properties(&mut self, property: Property<'a>) {
|
fn push_to_properties(&mut self, property: Property<'a>) {
|
||||||
|
|
|
@ -50,7 +50,7 @@ impl<'a, const MAX_REASONS: usize, const MAX_PROPERTIES: usize>
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
loop {
|
loop {
|
||||||
self.reason_codes.push(buff_reader.read_u8()?);
|
self.reason_codes.push(buff_reader.read_u8()?);
|
||||||
i = i + 1;
|
i += 1;
|
||||||
if i == MAX_REASONS {
|
if i == MAX_REASONS {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -79,13 +79,13 @@ impl<'a, const MAX_REASONS: usize, const MAX_PROPERTIES: usize> Packet<'a>
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decode(&mut self, buff_reader: &mut BuffReader<'a>) -> Result<(), BufferError> {
|
fn decode(&mut self, buff_reader: &mut BuffReader<'a>) -> Result<(), BufferError> {
|
||||||
if self.decode_fixed_header(buff_reader)? != (PacketType::Unsuback).into() {
|
if self.decode_fixed_header(buff_reader)? != PacketType::Unsuback {
|
||||||
error!("Packet you are trying to decode is not UNSUBACK packet!");
|
error!("Packet you are trying to decode is not UNSUBACK packet!");
|
||||||
return Err(BufferError::PacketTypeMismatch);
|
return Err(BufferError::PacketTypeMismatch);
|
||||||
}
|
}
|
||||||
self.packet_identifier = buff_reader.read_u16()?;
|
self.packet_identifier = buff_reader.read_u16()?;
|
||||||
self.decode_properties(buff_reader)?;
|
self.decode_properties(buff_reader)?;
|
||||||
return self.read_reason_codes(buff_reader);
|
self.read_reason_codes(buff_reader)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_property_len(&mut self, value: u32) {
|
fn set_property_len(&mut self, value: u32) {
|
||||||
|
@ -93,7 +93,7 @@ impl<'a, const MAX_REASONS: usize, const MAX_PROPERTIES: usize> Packet<'a>
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_property_len(&mut self) -> u32 {
|
fn get_property_len(&mut self) -> u32 {
|
||||||
return self.property_len;
|
self.property_len
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_to_properties(&mut self, property: Property<'a>) {
|
fn push_to_properties(&mut self, property: Property<'a>) {
|
||||||
|
|
|
@ -51,9 +51,9 @@ impl<'a, const MAX_FILTERS: usize, const MAX_PROPERTIES: usize>
|
||||||
let mut new_filter = TopicFilter::new();
|
let mut new_filter = TopicFilter::new();
|
||||||
new_filter.filter.string = topic_name;
|
new_filter.filter.string = topic_name;
|
||||||
new_filter.filter.len = len as u16;
|
new_filter.filter.len = len as u16;
|
||||||
new_filter.sub_options = new_filter.sub_options | 0x01;
|
new_filter.sub_options |= 0x01;
|
||||||
self.topic_filters.push(new_filter);
|
self.topic_filters.push(new_filter);
|
||||||
self.topic_filter_len = self.topic_filter_len + 1;
|
self.topic_filter_len += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,7 +83,7 @@ impl<'a, const MAX_FILTERS: usize, const MAX_PROPERTIES: usize> Packet<'a>
|
||||||
let mut filters_len = 0;
|
let mut filters_len = 0;
|
||||||
loop {
|
loop {
|
||||||
filters_len = filters_len + self.topic_filters.get(lt).unwrap().filter.len + 2;
|
filters_len = filters_len + self.topic_filters.get(lt).unwrap().filter.len + 2;
|
||||||
lt = lt + 1;
|
lt += 1;
|
||||||
if lt == self.topic_filter_len as usize {
|
if lt == self.topic_filter_len as usize {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -113,7 +113,7 @@ impl<'a, const MAX_FILTERS: usize, const MAX_PROPERTIES: usize> Packet<'a>
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_property_len(&mut self) -> u32 {
|
fn get_property_len(&mut self) -> u32 {
|
||||||
return self.property_len;
|
self.property_len
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_to_properties(&mut self, property: Property<'a>) {
|
fn push_to_properties(&mut self, property: Property<'a>) {
|
||||||
|
|
|
@ -38,15 +38,15 @@ pub struct BuffReader<'a> {
|
||||||
|
|
||||||
impl<'a> BuffReader<'a> {
|
impl<'a> BuffReader<'a> {
|
||||||
pub fn increment_position(&mut self, increment: usize) {
|
pub fn increment_position(&mut self, increment: usize) {
|
||||||
self.position = self.position + increment;
|
self.position += increment;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(buffer: &'a [u8], buff_len: usize) -> Self {
|
pub fn new(buffer: &'a [u8], buff_len: usize) -> Self {
|
||||||
return BuffReader {
|
Self {
|
||||||
buffer,
|
buffer,
|
||||||
position: 0,
|
position: 0,
|
||||||
len: buff_len,
|
len: buff_len,
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Variable byte integer can be 1-4 Bytes long. Buffer reader takes all 4 Bytes at first and
|
/// Variable byte integer can be 1-4 Bytes long. Buffer reader takes all 4 Bytes at first and
|
||||||
|
@ -66,14 +66,14 @@ impl<'a> BuffReader<'a> {
|
||||||
}
|
}
|
||||||
if self.buffer[self.position + x] & 0x80 != 0 {
|
if self.buffer[self.position + x] & 0x80 != 0 {
|
||||||
variable_byte_integer[x] = self.buffer[self.position + x];
|
variable_byte_integer[x] = self.buffer[self.position + x];
|
||||||
len = len + 1
|
len += 1
|
||||||
} else {
|
} else {
|
||||||
variable_byte_integer[x] = self.buffer[self.position + x];
|
variable_byte_integer[x] = self.buffer[self.position + x];
|
||||||
x = x + 1;
|
x += 1;
|
||||||
if x != 4 {
|
if x != 4 {
|
||||||
loop {
|
loop {
|
||||||
variable_byte_integer[x] = 0;
|
variable_byte_integer[x] = 0;
|
||||||
x = x + 1;
|
x += 1;
|
||||||
if x == 4 {
|
if x == 4 {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -81,10 +81,10 @@ impl<'a> BuffReader<'a> {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
x = x + 1;
|
x += 1;
|
||||||
}
|
}
|
||||||
self.increment_position(len);
|
self.increment_position(len);
|
||||||
return VariableByteIntegerDecoder::decode(variable_byte_integer);
|
VariableByteIntegerDecoder::decode(variable_byte_integer)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reading u32 from buffer as `Big endian`
|
/// Reading u32 from buffer as `Big endian`
|
||||||
|
@ -95,7 +95,7 @@ impl<'a> BuffReader<'a> {
|
||||||
let (int_bytes, _rest) = self.buffer[self.position..].split_at(mem::size_of::<u32>());
|
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());
|
let ret: u32 = u32::from_be_bytes(int_bytes.try_into().unwrap());
|
||||||
self.increment_position(4);
|
self.increment_position(4);
|
||||||
return Ok(ret);
|
Ok(ret)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reading u16 from buffer as `Big endinan`
|
/// Reading u16 from buffer as `Big endinan`
|
||||||
|
@ -106,7 +106,7 @@ impl<'a> BuffReader<'a> {
|
||||||
let (int_bytes, _rest) = self.buffer[self.position..].split_at(mem::size_of::<u16>());
|
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());
|
let ret: u16 = u16::from_be_bytes(int_bytes.try_into().unwrap());
|
||||||
self.increment_position(2);
|
self.increment_position(2);
|
||||||
return Ok(ret);
|
Ok(ret)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reading one byte from buffer as `Big endian`
|
/// Reading one byte from buffer as `Big endian`
|
||||||
|
@ -116,14 +116,14 @@ impl<'a> BuffReader<'a> {
|
||||||
}
|
}
|
||||||
let ret: u8 = self.buffer[self.position];
|
let ret: u8 = self.buffer[self.position];
|
||||||
self.increment_position(1);
|
self.increment_position(1);
|
||||||
return Ok(ret);
|
Ok(ret)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reading UTF-8 encoded string from buffer
|
/// Reading UTF-8 encoded string from buffer
|
||||||
pub fn read_string(&mut self) -> Result<EncodedString<'a>, BufferError> {
|
pub fn read_string(&mut self) -> Result<EncodedString<'a>, BufferError> {
|
||||||
let len = self.read_u16()? as usize;
|
let len = self.read_u16()? as usize;
|
||||||
|
|
||||||
if self.position + len - 1 >= self.len {
|
if self.position + len > self.len {
|
||||||
return Err(BufferError::InsufficientBufferSize);
|
return Err(BufferError::InsufficientBufferSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,29 +133,29 @@ impl<'a> BuffReader<'a> {
|
||||||
return Err(BufferError::Utf8Error);
|
return Err(BufferError::Utf8Error);
|
||||||
}
|
}
|
||||||
self.increment_position(len);
|
self.increment_position(len);
|
||||||
return Ok(EncodedString {
|
Ok(EncodedString {
|
||||||
string: res_str.unwrap(),
|
string: res_str.unwrap(),
|
||||||
len: len as u16,
|
len: len as u16,
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read Binary data from buffer
|
/// Read Binary data from buffer
|
||||||
pub fn read_binary(&mut self) -> Result<BinaryData<'a>, BufferError> {
|
pub fn read_binary(&mut self) -> Result<BinaryData<'a>, BufferError> {
|
||||||
let len = self.read_u16()?;
|
let len = self.read_u16()?;
|
||||||
|
|
||||||
if self.position + len as usize - 1 >= self.len {
|
if self.position + len as usize > self.len {
|
||||||
return Err(BufferError::InsufficientBufferSize);
|
return Err(BufferError::InsufficientBufferSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
let res_bin = &(self.buffer[self.position..(self.position + len as usize)]);
|
let res_bin = &(self.buffer[self.position..(self.position + len as usize)]);
|
||||||
return Ok(BinaryData { bin: res_bin, len });
|
Ok(BinaryData { bin: res_bin, len })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read string pair from buffer
|
/// Read string pair from buffer
|
||||||
pub fn read_string_pair(&mut self) -> Result<StringPair<'a>, BufferError> {
|
pub fn read_string_pair(&mut self) -> Result<StringPair<'a>, BufferError> {
|
||||||
let name = self.read_string()?;
|
let name = self.read_string()?;
|
||||||
let value = self.read_string()?;
|
let value = self.read_string()?;
|
||||||
return Ok(StringPair { name, value });
|
Ok(StringPair { name, value })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read payload message from buffer
|
/// Read payload message from buffer
|
||||||
|
@ -163,6 +163,14 @@ impl<'a> BuffReader<'a> {
|
||||||
if total_len > self.len {
|
if total_len > self.len {
|
||||||
return &self.buffer[self.position..self.len];
|
return &self.buffer[self.position..self.len];
|
||||||
}
|
}
|
||||||
return &self.buffer[self.position..total_len];
|
&self.buffer[self.position..total_len]
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Peeking (without incremental internal pointer) one byte from buffer as `Big endian`
|
||||||
|
pub fn peek_u8(&self) -> Result<u8, BufferError> {
|
||||||
|
if self.position >= self.len {
|
||||||
|
return Err(BufferError::InsufficientBufferSize);
|
||||||
|
}
|
||||||
|
Ok(self.buffer[self.position])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,9 @@ use crate::encoding::variable_byte_integer::{VariableByteInteger, VariableByteIn
|
||||||
use crate::packet::v5::property::Property;
|
use crate::packet::v5::property::Property;
|
||||||
use crate::utils::types::{BinaryData, BufferError, EncodedString, StringPair, TopicFilter};
|
use crate::utils::types::{BinaryData, BufferError, EncodedString, StringPair, TopicFilter};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct RemLenError;
|
||||||
|
|
||||||
/// Buff writer is writing corresponding types to buffer (Byte array) and stores current position
|
/// Buff writer is writing corresponding types to buffer (Byte array) and stores current position
|
||||||
/// (later as cursor)
|
/// (later as cursor)
|
||||||
pub struct BuffWriter<'a> {
|
pub struct BuffWriter<'a> {
|
||||||
|
@ -38,27 +41,28 @@ pub struct BuffWriter<'a> {
|
||||||
|
|
||||||
impl<'a> BuffWriter<'a> {
|
impl<'a> BuffWriter<'a> {
|
||||||
pub fn new(buffer: &'a mut [u8], buff_len: usize) -> Self {
|
pub fn new(buffer: &'a mut [u8], buff_len: usize) -> Self {
|
||||||
return BuffWriter {
|
Self {
|
||||||
buffer,
|
buffer,
|
||||||
position: 0,
|
position: 0,
|
||||||
len: buff_len,
|
len: buff_len,
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn increment_position(&mut self, increment: usize) {
|
fn increment_position(&mut self, increment: usize) {
|
||||||
self.position = self.position + increment;
|
self.position += increment;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns n-th Byte from the buffer to which is currently written.
|
/// Returns n-th Byte from the buffer to which is currently written.
|
||||||
pub fn get_n_byte(&mut self, n: usize) -> u8 {
|
pub fn get_n_byte(&mut self, n: usize) -> u8 {
|
||||||
if self.position >= n {
|
if self.position >= n {
|
||||||
return self.buffer[n];
|
self.buffer[n]
|
||||||
|
} else {
|
||||||
|
0
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the remaining lenght of the packet from the buffer to which is packet written.
|
/// Return the remaining lenght of the packet from the buffer to which is packet written.
|
||||||
pub fn get_rem_len(&mut self) -> Result<VariableByteInteger, ()> {
|
pub fn get_rem_len(&mut self) -> Result<VariableByteInteger, RemLenError> {
|
||||||
let max = if self.position >= 5 {
|
let max = if self.position >= 5 {
|
||||||
4
|
4
|
||||||
} else {
|
} else {
|
||||||
|
@ -72,12 +76,12 @@ impl<'a> BuffWriter<'a> {
|
||||||
return Ok(len);
|
return Ok(len);
|
||||||
}
|
}
|
||||||
if len[i - 1] & 0x80 != 0 && i == max && i != 4 {
|
if len[i - 1] & 0x80 != 0 && i == max && i != 4 {
|
||||||
return Err(());
|
return Err(RemLenError);
|
||||||
}
|
}
|
||||||
if i == max {
|
if i == max {
|
||||||
return Ok(len);
|
return Ok(len);
|
||||||
}
|
}
|
||||||
i = i + 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,36 +95,36 @@ impl<'a> BuffWriter<'a> {
|
||||||
loop {
|
loop {
|
||||||
self.buffer[self.position] = array[x];
|
self.buffer[self.position] = array[x];
|
||||||
self.increment_position(1);
|
self.increment_position(1);
|
||||||
x = x + 1;
|
x += 1;
|
||||||
if x == len {
|
if x == len {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Ok(());
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Writes a single Byte to the buffer.
|
/// Writes a single Byte to the buffer.
|
||||||
pub fn write_u8(&mut self, byte: u8) -> Result<(), BufferError> {
|
pub fn write_u8(&mut self, byte: u8) -> Result<(), BufferError> {
|
||||||
return if self.position >= self.len {
|
if self.position >= self.len {
|
||||||
Err(BufferError::InsufficientBufferSize)
|
Err(BufferError::InsufficientBufferSize)
|
||||||
} else {
|
} else {
|
||||||
self.buffer[self.position] = byte;
|
self.buffer[self.position] = byte;
|
||||||
self.increment_position(1);
|
self.increment_position(1);
|
||||||
Ok(())
|
Ok(())
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Writes the two Byte value to the buffer.
|
/// Writes the two Byte value to the buffer.
|
||||||
pub fn write_u16(&mut self, two_bytes: u16) -> Result<(), BufferError> {
|
pub fn write_u16(&mut self, two_bytes: u16) -> Result<(), BufferError> {
|
||||||
let bytes: [u8; 2] = two_bytes.to_be_bytes();
|
let bytes: [u8; 2] = two_bytes.to_be_bytes();
|
||||||
return self.insert_ref(2, &bytes);
|
self.insert_ref(2, &bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Writes the four Byte value to the buffer.
|
/// Writes the four Byte value to the buffer.
|
||||||
pub fn write_u32(&mut self, four_bytes: u32) -> Result<(), BufferError> {
|
pub fn write_u32(&mut self, four_bytes: u32) -> Result<(), BufferError> {
|
||||||
let bytes: [u8; 4] = four_bytes.to_be_bytes();
|
let bytes: [u8; 4] = four_bytes.to_be_bytes();
|
||||||
return self.insert_ref(4, &bytes);
|
self.insert_ref(4, &bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Writes the UTF-8 string type to the buffer.
|
/// Writes the UTF-8 string type to the buffer.
|
||||||
|
@ -130,32 +134,32 @@ impl<'a> BuffWriter<'a> {
|
||||||
let bytes = str.string.as_bytes();
|
let bytes = str.string.as_bytes();
|
||||||
return self.insert_ref(str.len as usize, bytes);
|
return self.insert_ref(str.len as usize, bytes);
|
||||||
}
|
}
|
||||||
return Ok(());
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Writes BinaryData to the buffer.
|
/// Writes BinaryData to the buffer.
|
||||||
pub fn write_binary_ref(&mut self, bin: &BinaryData<'a>) -> Result<(), BufferError> {
|
pub fn write_binary_ref(&mut self, bin: &BinaryData<'a>) -> Result<(), BufferError> {
|
||||||
self.write_u16(bin.len)?;
|
self.write_u16(bin.len)?;
|
||||||
return self.insert_ref(bin.len as usize, bin.bin);
|
self.insert_ref(bin.len as usize, bin.bin)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Writes the string pair to the buffer.
|
/// Writes the string pair to the buffer.
|
||||||
pub fn write_string_pair_ref(&mut self, str_pair: &StringPair<'a>) -> Result<(), BufferError> {
|
pub fn write_string_pair_ref(&mut self, str_pair: &StringPair<'a>) -> Result<(), BufferError> {
|
||||||
self.write_string_ref(&str_pair.name)?;
|
self.write_string_ref(&str_pair.name)?;
|
||||||
return self.write_string_ref(&str_pair.value);
|
self.write_string_ref(&str_pair.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Encodes the u32 value into the VariableByteInteger and this value writes to the buffer.
|
/// Encodes the u32 value into the VariableByteInteger and this value writes to the buffer.
|
||||||
pub fn write_variable_byte_int(&mut self, int: u32) -> Result<(), BufferError> {
|
pub fn write_variable_byte_int(&mut self, int: u32) -> Result<(), BufferError> {
|
||||||
let x: VariableByteInteger = VariableByteIntegerEncoder::encode(int)?;
|
let x: VariableByteInteger = VariableByteIntegerEncoder::encode(int)?;
|
||||||
let len = VariableByteIntegerEncoder::len(x);
|
let len = VariableByteIntegerEncoder::len(x);
|
||||||
return self.insert_ref(len, &x);
|
self.insert_ref(len, &x)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_property(&mut self, property: &Property<'a>) -> Result<(), BufferError> {
|
fn write_property(&mut self, property: &Property<'a>) -> Result<(), BufferError> {
|
||||||
let x: u8 = property.into();
|
let x: u8 = property.into();
|
||||||
self.write_u8(x)?;
|
self.write_u8(x)?;
|
||||||
return property.encode(self);
|
property.encode(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Writes all properties from the `properties` Vec into the buffer.
|
/// Writes all properties from the `properties` Vec into the buffer.
|
||||||
|
@ -169,7 +173,7 @@ impl<'a> BuffWriter<'a> {
|
||||||
loop {
|
loop {
|
||||||
let prop: &Property = properties.get(i).unwrap_or(&Property::Reserved());
|
let prop: &Property = properties.get(i).unwrap_or(&Property::Reserved());
|
||||||
self.write_property(prop)?;
|
self.write_property(prop)?;
|
||||||
i = i + 1;
|
i += 1;
|
||||||
if i == len {
|
if i == len {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -189,7 +193,7 @@ impl<'a> BuffWriter<'a> {
|
||||||
if sub {
|
if sub {
|
||||||
self.write_u8(topic_filter.sub_options)?;
|
self.write_u8(topic_filter.sub_options)?;
|
||||||
}
|
}
|
||||||
return Ok(());
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Writes the topic filter Vec to the buffer. If the `sub` option is set to `false`, it will not
|
/// Writes the topic filter Vec to the buffer. If the `sub` option is set to `false`, it will not
|
||||||
|
@ -204,7 +208,7 @@ impl<'a> BuffWriter<'a> {
|
||||||
loop {
|
loop {
|
||||||
let topic_filter: &TopicFilter<'a> = filters.get(i).unwrap();
|
let topic_filter: &TopicFilter<'a> = filters.get(i).unwrap();
|
||||||
self.write_topic_filter_ref(sub, topic_filter)?;
|
self.write_topic_filter_ref(sub, topic_filter)?;
|
||||||
i = i + 1;
|
i += 1;
|
||||||
if i == len {
|
if i == len {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ impl RngCore for CountingRng {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
|
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
|
||||||
Ok(self.fill_bytes(dest))
|
self.fill_bytes(dest);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,7 +56,7 @@ impl Display for BufferError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Encoded string provides structure representing UTF-8 encoded string in MQTTv5 packets
|
/// Encoded string provides structure representing UTF-8 encoded string in MQTTv5 packets
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, Default)]
|
||||||
pub struct EncodedString<'a> {
|
pub struct EncodedString<'a> {
|
||||||
pub string: &'a str,
|
pub string: &'a str,
|
||||||
pub len: u16,
|
pub len: u16,
|
||||||
|
@ -68,13 +68,13 @@ impl EncodedString<'_> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return length of string
|
/// Return length of string
|
||||||
pub fn len(&self) -> u16 {
|
pub fn encoded_len(&self) -> u16 {
|
||||||
return self.len + 2;
|
self.len + 2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Binary data represents `Binary data` in MQTTv5 protocol
|
/// Binary data represents `Binary data` in MQTTv5 protocol
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, Default)]
|
||||||
pub struct BinaryData<'a> {
|
pub struct BinaryData<'a> {
|
||||||
pub bin: &'a [u8],
|
pub bin: &'a [u8],
|
||||||
pub len: u16,
|
pub len: u16,
|
||||||
|
@ -85,13 +85,13 @@ impl BinaryData<'_> {
|
||||||
Self { bin: &[0], len: 0 }
|
Self { bin: &[0], len: 0 }
|
||||||
}
|
}
|
||||||
/// Returns length of Byte array
|
/// Returns length of Byte array
|
||||||
pub fn len(&self) -> u16 {
|
pub fn encoded_len(&self) -> u16 {
|
||||||
return self.len + 2;
|
self.len + 2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// String pair struct represents `String pair` in MQTTv5 (2 UTF-8 encoded strings name-value)
|
/// String pair struct represents `String pair` in MQTTv5 (2 UTF-8 encoded strings name-value)
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, Default)]
|
||||||
pub struct StringPair<'a> {
|
pub struct StringPair<'a> {
|
||||||
pub name: EncodedString<'a>,
|
pub name: EncodedString<'a>,
|
||||||
pub value: EncodedString<'a>,
|
pub value: EncodedString<'a>,
|
||||||
|
@ -105,14 +105,13 @@ impl StringPair<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Returns length which is equal to sum of the lenghts of UTF-8 encoded strings in pair
|
/// Returns length which is equal to sum of the lenghts of UTF-8 encoded strings in pair
|
||||||
pub fn len(&self) -> u16 {
|
pub fn encoded_len(&self) -> u16 {
|
||||||
let ln = self.name.len() + self.value.len();
|
self.name.encoded_len() + self.value.encoded_len()
|
||||||
return ln;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Topic filter serves as bound for topic selection and subscription options for `SUBSCRIPTION` packet
|
/// Topic filter serves as bound for topic selection and subscription options for `SUBSCRIPTION` packet
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Default)]
|
||||||
pub struct TopicFilter<'a> {
|
pub struct TopicFilter<'a> {
|
||||||
pub filter: EncodedString<'a>,
|
pub filter: EncodedString<'a>,
|
||||||
pub sub_options: u8,
|
pub sub_options: u8,
|
||||||
|
@ -126,7 +125,7 @@ impl TopicFilter<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn len(&self) -> u16 {
|
pub fn encoded_len(&self) -> u16 {
|
||||||
return self.filter.len + 3;
|
self.filter.len + 3
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,6 +63,7 @@ fn setup() {
|
||||||
async fn publish_core<'b>(
|
async fn publish_core<'b>(
|
||||||
client: &mut MqttClient<'b, TokioNetwork, 5, CountingRng>,
|
client: &mut MqttClient<'b, TokioNetwork, 5, CountingRng>,
|
||||||
wait: u64,
|
wait: u64,
|
||||||
|
qos: QualityOfService,
|
||||||
topic: &str,
|
topic: &str,
|
||||||
message: &str,
|
message: &str,
|
||||||
err: bool,
|
err: bool,
|
||||||
|
@ -80,7 +81,9 @@ async fn publish_core<'b>(
|
||||||
"[Publisher] Sending new message {} to topic {}",
|
"[Publisher] Sending new message {} to topic {}",
|
||||||
message, topic
|
message, topic
|
||||||
);
|
);
|
||||||
result = client.send_message(topic, message.as_bytes()).await;
|
result = client
|
||||||
|
.send_message(topic, message.as_bytes(), qos, false)
|
||||||
|
.await;
|
||||||
info!("[PUBLISHER] sent");
|
info!("[PUBLISHER] sent");
|
||||||
if err == true {
|
if err == true {
|
||||||
assert_err!(result);
|
assert_err!(result);
|
||||||
|
@ -107,7 +110,7 @@ async fn publish(
|
||||||
.map_err(|_| ReasonCode::NetworkError)?;
|
.map_err(|_| ReasonCode::NetworkError)?;
|
||||||
let connection = TokioNetwork::new(connection);
|
let connection = TokioNetwork::new(connection);
|
||||||
let mut config = ClientConfig::new(MQTTv5, CountingRng(20000));
|
let mut config = ClientConfig::new(MQTTv5, CountingRng(20000));
|
||||||
config.add_qos(qos);
|
config.add_max_subscribe_qos(qos);
|
||||||
config.add_username(USERNAME);
|
config.add_username(USERNAME);
|
||||||
config.add_password(PASSWORD);
|
config.add_password(PASSWORD);
|
||||||
config.max_packet_size = 100;
|
config.max_packet_size = 100;
|
||||||
|
@ -122,7 +125,7 @@ async fn publish(
|
||||||
80,
|
80,
|
||||||
config,
|
config,
|
||||||
);
|
);
|
||||||
publish_core(&mut client, wait, topic, MSG, false).await
|
publish_core(&mut client, wait, qos, topic, MSG, false).await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn publish_spec(
|
async fn publish_spec(
|
||||||
|
@ -139,7 +142,7 @@ async fn publish_spec(
|
||||||
.map_err(|_| ReasonCode::NetworkError)?;
|
.map_err(|_| ReasonCode::NetworkError)?;
|
||||||
let connection = TokioNetwork::new(connection);
|
let connection = TokioNetwork::new(connection);
|
||||||
let mut config = ClientConfig::new(MQTTv5, CountingRng(20000));
|
let mut config = ClientConfig::new(MQTTv5, CountingRng(20000));
|
||||||
config.add_qos(qos);
|
config.add_max_subscribe_qos(qos);
|
||||||
config.add_username(USERNAME);
|
config.add_username(USERNAME);
|
||||||
config.add_password(PASSWORD);
|
config.add_password(PASSWORD);
|
||||||
config.max_packet_size = 100;
|
config.max_packet_size = 100;
|
||||||
|
@ -154,7 +157,7 @@ async fn publish_spec(
|
||||||
80,
|
80,
|
||||||
config,
|
config,
|
||||||
);
|
);
|
||||||
publish_core(&mut client, wait, topic, message, err).await
|
publish_core(&mut client, wait, qos, topic, message, err).await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn receive_core<'b>(
|
async fn receive_core<'b>(
|
||||||
|
@ -236,7 +239,7 @@ async fn receive_multiple<const TOPICS: usize>(
|
||||||
.map_err(|_| ReasonCode::NetworkError)?;
|
.map_err(|_| ReasonCode::NetworkError)?;
|
||||||
let connection = TokioNetwork::new(connection);
|
let connection = TokioNetwork::new(connection);
|
||||||
let mut config = ClientConfig::new(MQTTv5, CountingRng(20000));
|
let mut config = ClientConfig::new(MQTTv5, CountingRng(20000));
|
||||||
config.add_qos(qos);
|
config.add_max_subscribe_qos(qos);
|
||||||
config.add_username(USERNAME);
|
config.add_username(USERNAME);
|
||||||
config.add_password(PASSWORD);
|
config.add_password(PASSWORD);
|
||||||
config.max_packet_size = 60;
|
config.max_packet_size = 60;
|
||||||
|
@ -263,7 +266,7 @@ async fn receive(ip: Ipv4Addr, qos: QualityOfService, topic: &str) -> Result<(),
|
||||||
.map_err(|_| ReasonCode::NetworkError)?;
|
.map_err(|_| ReasonCode::NetworkError)?;
|
||||||
let connection = TokioNetwork::new(connection);
|
let connection = TokioNetwork::new(connection);
|
||||||
let mut config = ClientConfig::new(MQTTv5, CountingRng(20000));
|
let mut config = ClientConfig::new(MQTTv5, CountingRng(20000));
|
||||||
config.add_qos(qos);
|
config.add_max_subscribe_qos(qos);
|
||||||
config.add_username(USERNAME);
|
config.add_username(USERNAME);
|
||||||
config.add_password(PASSWORD);
|
config.add_password(PASSWORD);
|
||||||
config.max_packet_size = 6000;
|
config.max_packet_size = 6000;
|
||||||
|
@ -290,7 +293,7 @@ async fn receive_with_wrong_cred(qos: QualityOfService) -> Result<(), ReasonCode
|
||||||
.map_err(|_| ReasonCode::NetworkError)?;
|
.map_err(|_| ReasonCode::NetworkError)?;
|
||||||
let connection = TokioNetwork::new(connection);
|
let connection = TokioNetwork::new(connection);
|
||||||
let mut config = ClientConfig::new(MQTTv5, CountingRng(20000));
|
let mut config = ClientConfig::new(MQTTv5, CountingRng(20000));
|
||||||
config.add_qos(qos);
|
config.add_max_subscribe_qos(qos);
|
||||||
config.add_username("xyz");
|
config.add_username("xyz");
|
||||||
config.add_password(PASSWORD);
|
config.add_password(PASSWORD);
|
||||||
config.max_packet_size = 60;
|
config.max_packet_size = 60;
|
||||||
|
@ -329,7 +332,7 @@ async fn receive_multiple_second_unsub<const TOPICS: usize>(
|
||||||
.map_err(|_| ReasonCode::NetworkError)?;
|
.map_err(|_| ReasonCode::NetworkError)?;
|
||||||
let connection = TokioNetwork::new(connection);
|
let connection = TokioNetwork::new(connection);
|
||||||
let mut config = ClientConfig::new(MQTTv5, CountingRng(20000));
|
let mut config = ClientConfig::new(MQTTv5, CountingRng(20000));
|
||||||
config.add_qos(qos);
|
config.add_max_subscribe_qos(qos);
|
||||||
config.add_username(USERNAME);
|
config.add_username(USERNAME);
|
||||||
config.add_password(PASSWORD);
|
config.add_password(PASSWORD);
|
||||||
config.max_packet_size = 60;
|
config.max_packet_size = 60;
|
||||||
|
|
|
@ -78,7 +78,9 @@ async fn publish_core<'b>(
|
||||||
info!("[Publisher] Sending new message {} to topic {}", MSG, topic);
|
info!("[Publisher] Sending new message {} to topic {}", MSG, topic);
|
||||||
let mut count = 0;
|
let mut count = 0;
|
||||||
loop {
|
loop {
|
||||||
result = client.send_message(topic, MSG.as_bytes()).await;
|
result = client
|
||||||
|
.send_message(topic, MSG.as_bytes(), QualityOfService::QoS0, false)
|
||||||
|
.await;
|
||||||
info!("[PUBLISHER] sent {}", count);
|
info!("[PUBLISHER] sent {}", count);
|
||||||
assert_ok!(result);
|
assert_ok!(result);
|
||||||
count = count + 1;
|
count = count + 1;
|
||||||
|
@ -107,7 +109,7 @@ async fn publish(
|
||||||
.map_err(|_| ReasonCode::NetworkError)?;
|
.map_err(|_| ReasonCode::NetworkError)?;
|
||||||
let connection = TokioNetwork::new(connection);
|
let connection = TokioNetwork::new(connection);
|
||||||
let mut config = ClientConfig::new(MQTTv5, CountingRng(50000));
|
let mut config = ClientConfig::new(MQTTv5, CountingRng(50000));
|
||||||
config.add_qos(qos);
|
config.add_max_subscribe_qos(qos);
|
||||||
config.add_username(USERNAME);
|
config.add_username(USERNAME);
|
||||||
config.add_password(PASSWORD);
|
config.add_password(PASSWORD);
|
||||||
config.max_packet_size = 100;
|
config.max_packet_size = 100;
|
||||||
|
@ -171,7 +173,7 @@ async fn receive(
|
||||||
.map_err(|_| ReasonCode::NetworkError)?;
|
.map_err(|_| ReasonCode::NetworkError)?;
|
||||||
let connection = TokioNetwork::new(connection);
|
let connection = TokioNetwork::new(connection);
|
||||||
let mut config = ClientConfig::new(MQTTv5, CountingRng(50000));
|
let mut config = ClientConfig::new(MQTTv5, CountingRng(50000));
|
||||||
config.add_qos(qos);
|
config.add_max_subscribe_qos(qos);
|
||||||
config.add_username(USERNAME);
|
config.add_username(USERNAME);
|
||||||
config.add_password(PASSWORD);
|
config.add_password(PASSWORD);
|
||||||
config.max_packet_size = 6000;
|
config.max_packet_size = 6000;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user