From 19189307613654a3967159f364cb7eb90b45b4ac Mon Sep 17 00:00:00 2001 From: Ondrej Babec Date: Fri, 25 Feb 2022 09:31:16 +0100 Subject: [PATCH 01/10] Client first --- Cargo.lock | 185 +++++++++++++++++++++++++++++++++++ Cargo.toml | 1 + LICENSE | 16 +-- src/client/client_v5.rs | 20 ++++ src/client/mod.rs | 1 + src/lib.rs | 2 + src/main.rs | 25 ----- src/network/mod.rs | 1 + src/network/network_trait.rs | 5 + src/packet/publish_packet.rs | 14 ++- 10 files changed, 232 insertions(+), 38 deletions(-) create mode 100644 src/client/client_v5.rs create mode 100644 src/client/mod.rs create mode 100644 src/network/mod.rs create mode 100644 src/network/network_trait.rs diff --git a/Cargo.lock b/Cargo.lock index 6e711ae..77f9b8b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -89,6 +89,12 @@ version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +[[package]] +name = "bytes" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" + [[package]] name = "cfg-if" version = "1.0.0" @@ -484,6 +490,28 @@ version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" +[[package]] +name = "mio" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba272f85fa0b41fc91872be579b3bbe0f56b792aa361a380eb669469f68dafb2" +dependencies = [ + "libc", + "log", + "miow", + "ntapi", + "winapi", +] + +[[package]] +name = "miow" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" +dependencies = [ + "winapi", +] + [[package]] name = "nb" version = "0.1.3" @@ -510,6 +538,15 @@ dependencies = [ "version_check", ] +[[package]] +name = "ntapi" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28774a7fd2fbb4f0babd8237ce554b73af68021b5f695a3cebd6c59bac0980f" +dependencies = [ + "winapi", +] + [[package]] name = "num-traits" version = "0.1.43" @@ -528,6 +565,45 @@ dependencies = [ "autocfg", ] +[[package]] +name = "num_cpus" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "once_cell" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5" + +[[package]] +name = "parking_lot" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f5ec2493a61ac0506c0f4199f99070cbe83857b0337006a30f3e6719b8ef58" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28141e0cc4143da2443301914478dc976a61ffdb3f043058310c70df2fed8954" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-sys", +] + [[package]] name = "pin-project" version = "1.0.10" @@ -608,6 +684,15 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +[[package]] +name = "redox_syscall" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" +dependencies = [ + "bitflags", +] + [[package]] name = "regex" version = "1.5.4" @@ -661,6 +746,7 @@ dependencies = [ "env_logger", "heapless", "log", + "tokio", ] [[package]] @@ -734,12 +820,37 @@ dependencies = [ "serde 1.0.136", ] +[[package]] +name = "signal-hook-registry" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" +dependencies = [ + "libc", +] + [[package]] name = "slab" version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5" +[[package]] +name = "smallvec" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" + +[[package]] +name = "socket2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "spin" version = "0.9.2" @@ -787,6 +898,37 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "tokio" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2af73ac49756f3f7c01172e34a23e5d0216f6c32333757c2c61feb2bbff5a5ee" +dependencies = [ + "bytes", + "libc", + "memchr", + "mio", + "num_cpus", + "once_cell", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "winapi", +] + +[[package]] +name = "tokio-macros" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "toml" version = "0.5.8" @@ -860,6 +1002,49 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-sys" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3df6e476185f92a12c072be4a189a0210dcdcf512a1891d6dff9edb874deadc6" +dependencies = [ + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_msvc" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8e92753b1c443191654ec532f14c199742964a061be25d77d7a96f09db20bf5" + +[[package]] +name = "windows_i686_gnu" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a711c68811799e017b6038e0922cb27a5e2f43a2ddb609fe0b6f3eeda9de615" + +[[package]] +name = "windows_i686_msvc" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "146c11bb1a02615db74680b32a68e2d61f553cc24c4eb5b4ca10311740e44172" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c912b12f7454c6620635bbff3450962753834be2a594819bd5e945af18ec64bc" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "504a2476202769977a040c6364301a3f65d0cc9e3fb08600b2bda150a0488316" + [[package]] name = "yaml-rust" version = "0.4.5" diff --git a/Cargo.toml b/Cargo.toml index bfc5885..7bba01c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,7 @@ drogue-device = { version = "0.1.0", default-features = false, features = ["log" env_logger = "0.9.0" log = "0.4.14" heapless = "0.7.10" +tokio = { version = "1", features = ["full"] } [patch.crates-io] embassy = { git = "https://github.com/embassy-rs/embassy.git", rev = "d76cd5ceaf5140c48ef97180beae156c0c0e07c8" } diff --git a/LICENSE b/LICENSE index f288702..a824681 100644 --- a/LICENSE +++ b/LICENSE @@ -98,7 +98,7 @@ public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. +a computer Network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible @@ -264,7 +264,7 @@ in one of these ways: medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. + Corresponding Source from a Network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This @@ -277,7 +277,7 @@ in one of these ways: Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source + copy the object code is a Network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the @@ -330,9 +330,9 @@ been installed in ROM). requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. +Network may be denied when the modification itself materially and +adversely affects the operation of the Network or violates the rules and +protocols for communication across the Network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly @@ -499,7 +499,7 @@ patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, +publicly available Network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner @@ -557,7 +557,7 @@ under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the +section 13, concerning interaction through a Network will apply to the combination as such. 14. Revised Versions of this License. diff --git a/src/client/client_v5.rs b/src/client/client_v5.rs new file mode 100644 index 0000000..6f0e3c3 --- /dev/null +++ b/src/client/client_v5.rs @@ -0,0 +1,20 @@ +use crate::packet::publish_packet::PublishPacket; +use crate::network::network_trait::Network; + +struct MqttClientV5 { + network_driver: T, +} + +impl MqttClientV5 +where + T: Network, +{ + fn send_message(& mut self, topic_name: & str, message: & str, buffer: & mut [u8]) { + let packet = PublishPacket::new(topic_name, message); + self.network_driver.send() + } + + fn receive_message(& mut self) { + + } +} diff --git a/src/client/mod.rs b/src/client/mod.rs new file mode 100644 index 0000000..ab4c08b --- /dev/null +++ b/src/client/mod.rs @@ -0,0 +1 @@ +pub mod client_v5; \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 9ce0124..4b69db3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,6 +6,8 @@ pub mod encoding; pub mod packet; pub mod utils; +pub mod client; +mod network; #[allow(unused_variables)] pub fn print_stack(file: &'static str, line: u32) { diff --git a/src/main.rs b/src/main.rs index d8ac3a5..8764f37 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,9 +1,3 @@ -/*use rust_mqtt::packet::mqtt_packet::*; -use rust_mqtt::packet::property::*;*/ -/*use heapless::Vec; -use std::fs::File; -use std::io::Read;*/ - use rust_mqtt::packet::connect_packet::ConnectPacket; use rust_mqtt::packet::mqtt_packet::Packet; use rust_mqtt::packet::publish_packet::PublishPacket; @@ -31,23 +25,4 @@ fn main() { let lncntrl = cntrl.encode(&mut res3); println!("{:02X?}", &res3[0..lncntrl]); log::info!("xxx"); - - /*let fl = File::open("/Users/obabec/development/school/rust-mqtt/mqtt_control_example.bin"); - - let mut f = File::open("/Users/obabec/development/school/rust-mqtt/mqtt_control_example.bin").expect("no file found"); - let mut buffer: [u8; 500] = [0; 500]; - f.read(&mut buffer).expect("buffer overflow"); - - - // - let mut payld = *b"xxxxx";*/ - //let packet = Packet::clean(txt, &mut payld); - /*let mut buffer_reader = BuffReader::new(&buffer); - packet_builder.decode_packet(& mut buffer_reader); - - - let bytes: [u8; 4] = packet_builder.currentPacket.protocol_name.to_be_bytes(); - - let prot = std::str::from_utf8(&bytes).unwrap(); - log::info!("Protocol name: {}", prot)*/ } diff --git a/src/network/mod.rs b/src/network/mod.rs new file mode 100644 index 0000000..294a433 --- /dev/null +++ b/src/network/mod.rs @@ -0,0 +1 @@ +pub mod network_trait; \ No newline at end of file diff --git a/src/network/network_trait.rs b/src/network/network_trait.rs new file mode 100644 index 0000000..2564695 --- /dev/null +++ b/src/network/network_trait.rs @@ -0,0 +1,5 @@ + +pub trait Network { + fn send(buffer: & mut [u8]); + fn receive(buffer: & mut [u8]); +} \ No newline at end of file diff --git a/src/packet/publish_packet.rs b/src/packet/publish_packet.rs index cb7d05e..3bbaaff 100644 --- a/src/packet/publish_packet.rs +++ b/src/packet/publish_packet.rs @@ -27,21 +27,25 @@ pub struct PublishPacket<'a, const MAX_PROPERTIES: usize> { } impl<'a, const MAX_PROPERTIES: usize> PublishPacket<'a, MAX_PROPERTIES> { - pub fn new(message: &'a [u8]) -> Self { + pub fn new(topic_name: & str, message: &'a str) -> Self { let mut x = Self { fixed_header: PacketType::Publish.into(), remain_len: 0, topic_name: EncodedString::new(), - packet_identifier: 0, + packet_identifier: 1, property_len: 0, properties: Vec::, MAX_PROPERTIES>::new(), - message, + message: message.as_bytes(), }; - x.topic_name.string = "test/topic"; - x.topic_name.len = 10; + x.add_topic_name(topic_name); return x; } + pub fn add_topic_name(&mut self, topic_name: & str) { + self.topic_name.string = topic_name; + self.topic_name.len = topic_name.len() as u16; + } + pub fn decode_publish_packet(&mut self, buff_reader: &mut BuffReader<'a>) { if self.decode_fixed_header(buff_reader) != (PacketType::Publish).into() { log::error!("Packet you are trying to decode is not PUBLISH packet!"); From e660f8ead2a930ad4f8286018a3dd6d0350ebb80 Mon Sep 17 00:00:00 2001 From: Ondrej Babec Date: Fri, 25 Feb 2022 14:17:58 +0100 Subject: [PATCH 02/10] Async --- src/client/client_v5.rs | 62 ++++++++++++++++++++---- src/lib.rs | 8 +++- src/main.rs | 15 ++++-- src/network/network_trait.rs | 34 ++++++++++++-- src/packet/auth_packet.rs | 3 ++ src/packet/connack_packet.rs | 4 ++ src/packet/connect_packet.rs | 4 ++ src/packet/disconnect_packet.rs | 14 ++++++ src/packet/mqtt_packet.rs | 3 +- src/packet/pingreq_packet.rs | 4 ++ src/packet/pingresp_packet.rs | 4 ++ src/packet/puback_packet.rs | 4 ++ src/packet/pubcomp_packet.rs | 4 ++ src/packet/publish_packet.rs | 38 ++++++++++++++- src/packet/pubrec_packet.rs | 4 ++ src/packet/pubrel_packet.rs | 4 ++ src/packet/suback_packet.rs | 4 ++ src/packet/subscription_packet.rs | 4 ++ src/packet/unsuback_packet.rs | 4 ++ src/packet/unsubscription_packet.rs | 6 ++- src/tokio_network.rs | 73 +++++++++++++++++++++++++++++ 21 files changed, 279 insertions(+), 21 deletions(-) create mode 100644 src/tokio_network.rs diff --git a/src/client/client_v5.rs b/src/client/client_v5.rs index 6f0e3c3..5834dfa 100644 --- a/src/client/client_v5.rs +++ b/src/client/client_v5.rs @@ -1,20 +1,64 @@ -use crate::packet::publish_packet::PublishPacket; -use crate::network::network_trait::Network; +use crate::packet::publish_packet::{PublishPacket, QualityOfService}; +use crate::network::network_trait::{Network, NetworkError}; +use crate::packet::connack_packet::ConnackPacket; +use crate::packet::connect_packet::ConnectPacket; +use crate::packet::disconnect_packet::DisconnectPacket; +use crate::packet::mqtt_packet::Packet; +use crate::packet::publish_packet::QualityOfService::QoS1; +use crate::utils::buffer_reader::BuffReader; -struct MqttClientV5 { +pub struct MqttClientV5 { network_driver: T, } -impl MqttClientV5 +impl MqttClientV5 where - T: Network, + T: Network { - fn send_message(& mut self, topic_name: & str, message: & str, buffer: & mut [u8]) { - let packet = PublishPacket::new(topic_name, message); - self.network_driver.send() + pub fn new(network_driver: T) -> Self { + Self { + network_driver, + } + } + // connect -> connack -> publish -> QoS ? -> disconn + pub async fn send_message(& mut self, topic_name: & str, message: & str, buffer: & mut [u8], qos: QualityOfService) -> Result<(), NetworkError> { + //connect + self.network_driver.create_connection() ?; + + let mut connect = ConnectPacket::clean(); + let mut len = connect.encode(buffer); + self.network_driver.send(buffer, len).await ?; + //connack + let connack: ConnackPacket = self.receive::>(buffer).await ?; + if connack.connect_reason_code != 0x00 { + todo!(); + } + + // publish + let mut packet = PublishPacket::new(topic_name, message); + len = packet.encode(buffer); + let result = self.network_driver.send(buffer, len).await ?; + + //QoS1 + if qos.into() == QoS1.into() { + todo!(); + } + + //Disconnect + let mut disconnect = DisconnectPacket::new(); + len = disconnect.encode(buffer); + self.network_driver.send(buffer, len); + return result; } - fn receive_message(& mut self) { + pub async fn receive>(& mut self, buffer: & mut [u8]) -> Result { + self.network_driver.receive(buffer).await ?; + let mut packet = P::new(); + packet.decode(&mut BuffReader::new(buffer)); + return Ok(packet); + } + + pub async fn receive_message(& mut self, buffer: & mut [u8]) -> Result<(), NetworkError> { } } diff --git a/src/lib.rs b/src/lib.rs index 4b69db3..12a7066 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,12 +2,18 @@ #![macro_use] #![cfg_attr(not(feature = "std"), no_std)] #![allow(dead_code)] +#![feature(type_alias_impl_trait)] +#![feature(generic_associated_types)] +#![feature(async)] + +extern crate alloc; pub mod encoding; pub mod packet; pub mod utils; pub mod client; -mod network; +pub mod network; +pub mod tokio_network; #[allow(unused_variables)] pub fn print_stack(file: &'static str, line: u32) { diff --git a/src/main.rs b/src/main.rs index 8764f37..90c7757 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,10 @@ +use rust_mqtt::client::client_v5::MqttClientV5; +use rust_mqtt::network::network_trait::Network; use rust_mqtt::packet::connect_packet::ConnectPacket; use rust_mqtt::packet::mqtt_packet::Packet; use rust_mqtt::packet::publish_packet::PublishPacket; use rust_mqtt::packet::subscription_packet::SubscriptionPacket; +use rust_mqtt::tokio_network::TokioNetwork; fn main() { env_logger::builder() @@ -9,12 +12,12 @@ fn main() { .format_timestamp_nanos() .init(); - let mut pckt: SubscriptionPacket<1, 0> = SubscriptionPacket::new(); + /*let mut pckt: SubscriptionPacket<1, 0> = SubscriptionPacket::new(); let mut res = vec![0; 140]; let lnsub = pckt.encode(&mut res); println!("{:02X?}", &res[0..lnsub]); let mut res2 = vec![0; 260]; - let mut x = b"hello world"; + let mut pblsh = PublishPacket::<0>::new(x); let lnpblsh = pblsh.encode(&mut res2); println!("{:02X?}", &res2[0..lnpblsh]); @@ -24,5 +27,11 @@ fn main() { let mut cntrl = ConnectPacket::<3, 0>::clean(); let lncntrl = cntrl.encode(&mut res3); println!("{:02X?}", &res3[0..lncntrl]); - log::info!("xxx"); + log::info!("xxx");*/ + let mut ip: [u8; 4] = [37, 205, 11, 180]; + let mut port: u16 = 1883; + let mut tokio_network: TokioNetwork = TokioNetwork::new(ip, port); + let client = MqttClientV5::new::(tokio_network); + let mut x = b"hello world"; + let mut res2 = vec![0; 260]; } diff --git a/src/network/network_trait.rs b/src/network/network_trait.rs index 2564695..d45a2b0 100644 --- a/src/network/network_trait.rs +++ b/src/network/network_trait.rs @@ -1,5 +1,33 @@ +use core::fmt::Error; + +use core::future::Future; +use crate::packet::mqtt_packet::Packet; + +pub enum NetworkError { + Connection, + Unknown, +} + + pub trait Network { - fn send(buffer: & mut [u8]); - fn receive(buffer: & mut [u8]); -} \ No newline at end of file + type ConnectionFuture<'m>: Future> + where + Self: 'm; + + type WriteFuture<'m>: Future> + where + Self: 'm; + + type ReadFuture<'m>: Future> + where + Self: 'm; + + fn new(ip: [u8; 4], port: u16) -> Self; + + fn create_connection(& mut self) -> Self::ConnectionFuture<'m>; + + fn send(& mut self, buffer: & mut [u8], len: usize) -> Self::WriteFuture<'m>; + + fn receive(& mut self, buffer: & mut [u8]) -> Self::ReadFuture<'m>; +} diff --git a/src/packet/auth_packet.rs b/src/packet/auth_packet.rs index 4e62253..4e7314a 100644 --- a/src/packet/auth_packet.rs +++ b/src/packet/auth_packet.rs @@ -46,6 +46,9 @@ impl<'a, const MAX_PROPERTIES: usize> AuthPacket<'a, MAX_PROPERTIES> { } impl<'a, const MAX_PROPERTIES: usize> Packet<'a> for AuthPacket<'a, MAX_PROPERTIES> { + fn new() -> Self { + todo!() + } /*fn new() -> Packet<'a, MAX_PROPERTIES> { return AuthPacket { fixed_header: PacketType::Auth.into(), remain_len: 0, auth_reason: 0, property_len: 0, properties: Vec::, MAX_PROPERTIES>::new() } }*/ diff --git a/src/packet/connack_packet.rs b/src/packet/connack_packet.rs index 83cd1cb..76601c1 100644 --- a/src/packet/connack_packet.rs +++ b/src/packet/connack_packet.rs @@ -32,6 +32,10 @@ impl<'a, const MAX_PROPERTIES: usize> ConnackPacket<'a, MAX_PROPERTIES> { } impl<'a, const MAX_PROPERTIES: usize> Packet<'a> for ConnackPacket<'a, MAX_PROPERTIES> { + fn new() -> Self { + todo!() + } + fn encode(&mut self, buffer: &mut [u8]) -> usize { let mut buff_writer = BuffWriter::new(buffer); buff_writer.write_u8(self.fixed_header); diff --git a/src/packet/connect_packet.rs b/src/packet/connect_packet.rs index 9e55674..aaf5a6c 100644 --- a/src/packet/connect_packet.rs +++ b/src/packet/connect_packet.rs @@ -101,6 +101,10 @@ impl<'a, const MAX_PROPERTIES: usize, const MAX_WILL_PROPERTIES: usize> impl<'a, const MAX_PROPERTIES: usize, const MAX_WILL_PROPERTIES: usize> Packet<'a> for ConnectPacket<'a, MAX_PROPERTIES, MAX_WILL_PROPERTIES> { + fn new() -> Self { + todo!() + } + fn encode(&mut self, buffer: &mut [u8]) -> usize { let mut buff_writer = BuffWriter::new(buffer); diff --git a/src/packet/disconnect_packet.rs b/src/packet/disconnect_packet.rs index f182e50..2a85962 100644 --- a/src/packet/disconnect_packet.rs +++ b/src/packet/disconnect_packet.rs @@ -30,9 +30,23 @@ impl<'a, const MAX_PROPERTIES: usize> DisconnectPacket<'a, MAX_PROPERTIES> { self.disconnect_reason = buff_reader.read_u8().unwrap(); self.decode_properties(buff_reader); } + + fn add_reason(& mut self, reason: u8) { + self.disconnect_reason = reason; + } } impl<'a, const MAX_PROPERTIES: usize> Packet<'a> for DisconnectPacket<'a, MAX_PROPERTIES> { + fn new() -> Self { + Self { + fixed_header: PacketType::Disconnect.into(), + remain_len: 5, + disconnect_reason: 0x00, + property_len: 0, + properties: Vec::, MAX_PROPERTIES>::new() + } + } + fn encode(&mut self, buffer: &mut [u8]) -> usize { let mut buff_writer = BuffWriter::new(buffer); buff_writer.write_u8(self.fixed_header); diff --git a/src/packet/mqtt_packet.rs b/src/packet/mqtt_packet.rs index b090d63..5100cc0 100644 --- a/src/packet/mqtt_packet.rs +++ b/src/packet/mqtt_packet.rs @@ -5,9 +5,10 @@ use crate::utils::buffer_reader::ParseError; use super::property::Property; pub trait Packet<'a> { - //fn new() -> dyn Packet<'a> where Self: Sized; + fn new() -> Self; fn encode(&mut self, buffer: &mut [u8]) -> usize; + // -> Result fn decode(&mut self, buff_reader: &mut BuffReader<'a>); // properties diff --git a/src/packet/pingreq_packet.rs b/src/packet/pingreq_packet.rs index 40234f2..dad2941 100644 --- a/src/packet/pingreq_packet.rs +++ b/src/packet/pingreq_packet.rs @@ -15,6 +15,10 @@ pub struct PingreqPacket { impl PingreqPacket {} impl<'a> Packet<'a> for PingreqPacket { + fn new() -> Self { + todo!() + } + fn encode(&mut self, buffer: &mut [u8]) -> usize { let mut buff_writer = BuffWriter::new(buffer); buff_writer.write_u8(self.fixed_header); diff --git a/src/packet/pingresp_packet.rs b/src/packet/pingresp_packet.rs index b6c32ae..645edc0 100644 --- a/src/packet/pingresp_packet.rs +++ b/src/packet/pingresp_packet.rs @@ -22,6 +22,10 @@ impl<'a> PingrespPacket { } impl<'a> Packet<'a> for PingrespPacket { + fn new() -> Self { + todo!() + } + fn encode(&mut self, buffer: &mut [u8]) -> usize { let mut buff_writer = BuffWriter::new(buffer); buff_writer.write_u8(self.fixed_header); diff --git a/src/packet/puback_packet.rs b/src/packet/puback_packet.rs index 42e8278..384212e 100644 --- a/src/packet/puback_packet.rs +++ b/src/packet/puback_packet.rs @@ -36,6 +36,10 @@ impl<'a, const MAX_PROPERTIES: usize> PubackPacket<'a, MAX_PROPERTIES> { } impl<'a, const MAX_PROPERTIES: usize> Packet<'a> for PubackPacket<'a, MAX_PROPERTIES> { + fn new() -> Self { + todo!() + } + fn encode(&mut self, buffer: &mut [u8]) -> usize { let mut buff_writer = BuffWriter::new(buffer); diff --git a/src/packet/pubcomp_packet.rs b/src/packet/pubcomp_packet.rs index 58811a9..2b497d3 100644 --- a/src/packet/pubcomp_packet.rs +++ b/src/packet/pubcomp_packet.rs @@ -36,6 +36,10 @@ impl<'a, const MAX_PROPERTIES: usize> PubcompPacket<'a, MAX_PROPERTIES> { } impl<'a, const MAX_PROPERTIES: usize> Packet<'a> for PubcompPacket<'a, MAX_PROPERTIES> { + fn new() -> Self { + todo!() + } + fn encode(&mut self, buffer: &mut [u8]) -> usize { let mut buff_writer = BuffWriter::new(buffer); diff --git a/src/packet/publish_packet.rs b/src/packet/publish_packet.rs index 3bbaaff..10b46ba 100644 --- a/src/packet/publish_packet.rs +++ b/src/packet/publish_packet.rs @@ -2,6 +2,7 @@ use crate::encoding::variable_byte_integer::VariableByteIntegerEncoder; use heapless::Vec; use crate::packet::mqtt_packet::Packet; +use crate::packet::publish_packet::QualityOfService::{INVALID, QoS0, QoS1, QoS2}; use crate::utils::buffer_reader::BuffReader; use crate::utils::buffer_reader::EncodedString; use crate::utils::buffer_writer::BuffWriter; @@ -9,6 +10,35 @@ use crate::utils::buffer_writer::BuffWriter; use super::packet_type::PacketType; use super::property::Property; +pub enum QualityOfService { + QoS0, + QoS1, + QoS2, + INVALID +} + +impl From for QualityOfService { + fn from(orig: u8) -> Self { + return match orig { + 0 => QoS0, + 1 => QoS1, + 2 => QoS2, + _ => INVALID + } + } +} + +impl Into for QualityOfService { + fn into(self) -> u8 { + return match self { + QoS0 => 0, + QoS1 => 1, + QoS2 => 2, + INVALID => 3, + } + } +} + pub struct PublishPacket<'a, const MAX_PROPERTIES: usize> { // 7 - 4 mqtt control packet type, 3-0 flagy pub fixed_header: u8, @@ -27,7 +57,7 @@ pub struct PublishPacket<'a, const MAX_PROPERTIES: usize> { } impl<'a, const MAX_PROPERTIES: usize> PublishPacket<'a, MAX_PROPERTIES> { - pub fn new(topic_name: & str, message: &'a str) -> Self { + pub fn new(topic_name: &'a str, message: &'a str) -> Self { let mut x = Self { fixed_header: PacketType::Publish.into(), remain_len: 0, @@ -41,7 +71,7 @@ impl<'a, const MAX_PROPERTIES: usize> PublishPacket<'a, MAX_PROPERTIES> { return x; } - pub fn add_topic_name(&mut self, topic_name: & str) { + pub fn add_topic_name(&mut self, topic_name: &'a str) { self.topic_name.string = topic_name; self.topic_name.len = topic_name.len() as u16; } @@ -63,6 +93,10 @@ impl<'a, const MAX_PROPERTIES: usize> PublishPacket<'a, MAX_PROPERTIES> { } impl<'a, const MAX_PROPERTIES: usize> Packet<'a> for PublishPacket<'a, MAX_PROPERTIES> { + fn new() -> Self { + todo!() + } + fn encode(&mut self, buffer: &mut [u8]) -> usize { let mut buff_writer = BuffWriter::new(buffer); diff --git a/src/packet/pubrec_packet.rs b/src/packet/pubrec_packet.rs index 996016e..c256189 100644 --- a/src/packet/pubrec_packet.rs +++ b/src/packet/pubrec_packet.rs @@ -36,6 +36,10 @@ impl<'a, const MAX_PROPERTIES: usize> PubrecPacket<'a, MAX_PROPERTIES> { } impl<'a, const MAX_PROPERTIES: usize> Packet<'a> for PubrecPacket<'a, MAX_PROPERTIES> { + fn new() -> Self { + todo!() + } + fn encode(&mut self, buffer: &mut [u8]) -> usize { let mut buff_writer = BuffWriter::new(buffer); diff --git a/src/packet/pubrel_packet.rs b/src/packet/pubrel_packet.rs index 3ac8da3..e5c5035 100644 --- a/src/packet/pubrel_packet.rs +++ b/src/packet/pubrel_packet.rs @@ -36,6 +36,10 @@ impl<'a, const MAX_PROPERTIES: usize> PubrelPacket<'a, MAX_PROPERTIES> { } impl<'a, const MAX_PROPERTIES: usize> Packet<'a> for PubrelPacket<'a, MAX_PROPERTIES> { + fn new() -> Self { + todo!() + } + fn encode(&mut self, buffer: &mut [u8]) -> usize { let mut buff_writer = BuffWriter::new(buffer); diff --git a/src/packet/suback_packet.rs b/src/packet/suback_packet.rs index c90bc28..6b073ca 100644 --- a/src/packet/suback_packet.rs +++ b/src/packet/suback_packet.rs @@ -52,6 +52,10 @@ impl<'a, const MAX_REASONS: usize, const MAX_PROPERTIES: usize> impl<'a, const MAX_REASONS: usize, const MAX_PROPERTIES: usize> Packet<'a> for SubackPacket<'a, MAX_REASONS, MAX_PROPERTIES> { + fn new() -> Self { + todo!() + } + fn encode(&mut self, buffer: &mut [u8]) -> usize { log::error!("SUBACK packet does not support encoding!"); return 0; diff --git a/src/packet/subscription_packet.rs b/src/packet/subscription_packet.rs index 096f8ac..9170b2a 100644 --- a/src/packet/subscription_packet.rs +++ b/src/packet/subscription_packet.rs @@ -53,6 +53,10 @@ impl<'a, const MAX_FILTERS: usize, const MAX_PROPERTIES: usize> impl<'a, const MAX_FILTERS: usize, const MAX_PROPERTIES: usize> Packet<'a> for SubscriptionPacket<'a, MAX_FILTERS, MAX_PROPERTIES> { + fn new() -> Self { + todo!() + } + fn encode(&mut self, buffer: &mut [u8]) -> usize { let mut buff_writer = BuffWriter::new(buffer); diff --git a/src/packet/unsuback_packet.rs b/src/packet/unsuback_packet.rs index b1c857a..f0f8a1b 100644 --- a/src/packet/unsuback_packet.rs +++ b/src/packet/unsuback_packet.rs @@ -50,6 +50,10 @@ impl<'a, const MAX_REASONS: usize, const MAX_PROPERTIES: usize> impl<'a, const MAX_REASONS: usize, const MAX_PROPERTIES: usize> Packet<'a> for UnsubackPacket<'a, MAX_REASONS, MAX_PROPERTIES> { + fn new() -> Self { + todo!() + } + fn encode(&mut self, buffer: &mut [u8]) -> usize { log::error!("UNSUBACK packet does not support encoding!"); return 0; diff --git a/src/packet/unsubscription_packet.rs b/src/packet/unsubscription_packet.rs index 1464eec..e29d901 100644 --- a/src/packet/unsubscription_packet.rs +++ b/src/packet/unsubscription_packet.rs @@ -32,14 +32,16 @@ pub struct UnsubscriptionPacket<'a, const MAX_FILTERS: usize, const MAX_PROPERTI impl<'a, const MAX_FILTERS: usize, const MAX_PROPERTIES: usize> UnsubscriptionPacket<'a, MAX_FILTERS, MAX_PROPERTIES> { - /*pub fn new() -> Self { - }*/ } impl<'a, const MAX_FILTERS: usize, const MAX_PROPERTIES: usize> Packet<'a> for UnsubscriptionPacket<'a, MAX_FILTERS, MAX_PROPERTIES> { + fn new() -> Self { + todo!() + } + fn encode(&mut self, buffer: &mut [u8]) -> usize { let mut buff_writer = BuffWriter::new(buffer); diff --git a/src/tokio_network.rs b/src/tokio_network.rs new file mode 100644 index 0000000..1db4d07 --- /dev/null +++ b/src/tokio_network.rs @@ -0,0 +1,73 @@ +use alloc::format; +use alloc::string::String; +use core::borrow::BorrowMut; +use core::fmt::Error; +use core::future::Future; +use core::ptr::null; +use embassy::io::WriteAll; +use tokio::io::{AsyncReadExt, AsyncWriteExt}; +use tokio::net::{TcpListener, TcpStream}; +use crate::network::network_trait::{Network, NetworkError}; +use crate::packet::mqtt_packet::Packet; + +pub struct TokioNetwork<'a> { + ip: [u8; 4], + port: u16, + socket: &'a mut TcpStream, +} + +impl<'a> TokioNetwork<'a> { + fn convert_ip(& mut self) -> String { + String::from(format!("{}.{}.{}.{}:{}", self.ip[0], self.ip[1], self.ip[2], self.ip[3], self.port)) + } +} + +impl Network for TokioNetwork { + type ConnectionFuture<'m> where Self: 'm = impl Future> + 'm; + type WriteFuture<'m> where Self: 'm = impl Future> + 'm; + type ReadFuture<'m> where Self: 'm = impl Future> + 'm; + + fn new(ip: [u8; 4], port: u16) -> Self { + return Self { + ip, + port, + socket: &mut (TcpStream), + } + } + + fn create_connection(&mut self) -> Self::ConnectionFuture<'m> { + async move { + TcpStream::connect(self.convert_ip()) + .await + .map_err(|_| NetworkError::Connection); + } + + } + + fn send<'m>(&mut self, buffer: &mut [u8], len: usize) -> Self::WriteFuture<'m> { + async move { + self.socket.write_all(&buffer[0..len]) + .await + .map_err(|_| NetworkError::Unknown); + } + + } + + fn receive<'m>(&mut self, buffer: &mut [u8]) -> Self::ReadFuture<'m> { + async move { + self.socket.read(buffer) + .await + .map_err(|_| NetworkError::Connection); + } + } + + /*fn send(&mut self, buffer: &mut [u8], len: usize) -> Result<(), NetworkError> { + self.socket.write_all(&buffer[0..len]); + Ok(()) + } + + fn receive(&mut self, buffer: &mut [u8]) -> Result { + let len = self.socket.read(buffer).await ?; + Ok(len) + }*/ +} \ No newline at end of file From 1e3f8e8302849d4e661ad2f41fa153b8231d6b09 Mon Sep 17 00:00:00 2001 From: Ondrej Babec Date: Fri, 25 Feb 2022 15:19:28 +0100 Subject: [PATCH 03/10] Futures --- src/client/client_v5.rs | 22 ++++++++++---------- src/lib.rs | 1 - src/network/network_trait.rs | 6 +++--- src/tokio_network.rs | 39 +++++++++++++++++++++++------------- 4 files changed, 39 insertions(+), 29 deletions(-) diff --git a/src/client/client_v5.rs b/src/client/client_v5.rs index 5834dfa..6bd32a5 100644 --- a/src/client/client_v5.rs +++ b/src/client/client_v5.rs @@ -11,7 +11,7 @@ pub struct MqttClientV5 { network_driver: T, } -impl MqttClientV5 +impl<'a, T, const MAX_PROPERTIES: usize> MqttClientV5 where T: Network { @@ -21,11 +21,11 @@ where } } // connect -> connack -> publish -> QoS ? -> disconn - pub async fn send_message(& mut self, topic_name: & str, message: & str, buffer: & mut [u8], qos: QualityOfService) -> Result<(), NetworkError> { + pub async fn send_message(& mut self, topic_name: & str, message: & str, buffer: &'a mut [u8], qos: QualityOfService) -> Result<(), NetworkError> { //connect - self.network_driver.create_connection() ?; + self.network_driver.create_connection().await ?; - let mut connect = ConnectPacket::clean(); + let mut connect = ConnectPacket::<3, 0>::clean(); let mut len = connect.encode(buffer); self.network_driver.send(buffer, len).await ?; //connack @@ -35,23 +35,23 @@ where } // publish - let mut packet = PublishPacket::new(topic_name, message); + let mut packet = PublishPacket::<5>::new(topic_name, message); len = packet.encode(buffer); - let result = self.network_driver.send(buffer, len).await ?; + self.network_driver.send(buffer, len).await ?; //QoS1 - if qos.into() == QoS1.into() { + if >::into(qos) == >::into(QoS1) { todo!(); } //Disconnect - let mut disconnect = DisconnectPacket::new(); + let mut disconnect = DisconnectPacket::<5>::new(); len = disconnect.encode(buffer); self.network_driver.send(buffer, len); - return result; + Ok(()) } - pub async fn receive>(& mut self, buffer: & mut [u8]) -> Result { + pub async fn receive>(& mut self, buffer: &'a mut [u8]) -> Result { self.network_driver.receive(buffer).await ?; let mut packet = P::new(); packet.decode(&mut BuffReader::new(buffer)); @@ -59,6 +59,6 @@ where } pub async fn receive_message(& mut self, buffer: & mut [u8]) -> Result<(), NetworkError> { - + return Ok(()); } } diff --git a/src/lib.rs b/src/lib.rs index 12a7066..5298429 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,7 +4,6 @@ #![allow(dead_code)] #![feature(type_alias_impl_trait)] #![feature(generic_associated_types)] -#![feature(async)] extern crate alloc; diff --git a/src/network/network_trait.rs b/src/network/network_trait.rs index d45a2b0..0065fa7 100644 --- a/src/network/network_trait.rs +++ b/src/network/network_trait.rs @@ -25,9 +25,9 @@ pub trait Network { fn new(ip: [u8; 4], port: u16) -> Self; - fn create_connection(& mut self) -> Self::ConnectionFuture<'m>; + fn create_connection(&'m mut self) -> Self::ConnectionFuture<'m>; - fn send(& mut self, buffer: & mut [u8], len: usize) -> Self::WriteFuture<'m>; + fn send(&'m mut self, buffer: &'m mut [u8], len: usize) -> Self::WriteFuture<'m>; - fn receive(& mut self, buffer: & mut [u8]) -> Self::ReadFuture<'m>; + fn receive(&'m mut self, buffer: &'m mut [u8]) -> Self::ReadFuture<'m>; } diff --git a/src/tokio_network.rs b/src/tokio_network.rs index 1db4d07..2e8ba69 100644 --- a/src/tokio_network.rs +++ b/src/tokio_network.rs @@ -10,13 +10,13 @@ use tokio::net::{TcpListener, TcpStream}; use crate::network::network_trait::{Network, NetworkError}; use crate::packet::mqtt_packet::Packet; -pub struct TokioNetwork<'a> { +pub struct TokioNetwork { ip: [u8; 4], port: u16, - socket: &'a mut TcpStream, + socket: Option, } -impl<'a> TokioNetwork<'a> { +impl TokioNetwork { fn convert_ip(& mut self) -> String { String::from(format!("{}.{}.{}.{}:{}", self.ip[0], self.ip[1], self.ip[2], self.ip[3], self.port)) } @@ -31,33 +31,44 @@ impl Network for TokioNetwork { return Self { ip, port, - socket: &mut (TcpStream), + socket: Option::None, } } - fn create_connection(&mut self) -> Self::ConnectionFuture<'m> { + fn create_connection<'m>(&'m mut self) -> Self::ConnectionFuture<'m> { async move { TcpStream::connect(self.convert_ip()) .await - .map_err(|_| NetworkError::Connection); + .map(|socket| self.socket = Some(socket)) + .map(|_| ()) + .map_err(|_| NetworkError::Connection) } } - fn send<'m>(&mut self, buffer: &mut [u8], len: usize) -> Self::WriteFuture<'m> { + fn send<'m>(&'m mut self, buffer: &'m mut [u8], len: usize) -> Self::WriteFuture<'m> { async move { - self.socket.write_all(&buffer[0..len]) - .await - .map_err(|_| NetworkError::Unknown); + return if let Some(ref mut stream) = self.socket { + stream.write_all(&buffer[0..len]) + .await + .map_err(|_| NetworkError::Unknown) + } else { + Err(NetworkError::Unknown) + } + } } - fn receive<'m>(&mut self, buffer: &mut [u8]) -> Self::ReadFuture<'m> { + fn receive<'m>(&'m mut self, buffer: &'m mut [u8]) -> Self::ReadFuture<'m> { async move { - self.socket.read(buffer) - .await - .map_err(|_| NetworkError::Connection); + return if let Some(ref mut stream) = self.socket { + stream.read(buffer) + .await + .map_err(|_| NetworkError::Connection) + } else { + Err(NetworkError::Unknown) + } } } From 7b7c8aa2aa2976977ddd33fe3016d8ea0412a40e Mon Sep 17 00:00:00 2001 From: Ondrej Babec Date: Fri, 25 Feb 2022 15:41:04 +0100 Subject: [PATCH 04/10] Optimize --- src/client/client_v5.rs | 37 ++++++++++++++++------------- src/network/network_trait.rs | 2 +- src/packet/auth_packet.rs | 2 +- src/packet/connack_packet.rs | 2 +- src/packet/connect_packet.rs | 2 +- src/packet/disconnect_packet.rs | 2 +- src/packet/puback_packet.rs | 2 +- src/packet/pubcomp_packet.rs | 2 +- src/packet/publish_packet.rs | 2 +- src/packet/pubrec_packet.rs | 2 +- src/packet/pubrel_packet.rs | 2 +- src/packet/suback_packet.rs | 2 +- src/packet/subscription_packet.rs | 2 +- src/packet/unsubscription_packet.rs | 2 +- src/tokio_network.rs | 2 ++ src/utils/buffer_writer.rs | 6 +++-- 16 files changed, 39 insertions(+), 32 deletions(-) diff --git a/src/client/client_v5.rs b/src/client/client_v5.rs index 6bd32a5..404d813 100644 --- a/src/client/client_v5.rs +++ b/src/client/client_v5.rs @@ -1,43 +1,46 @@ -use crate::packet::publish_packet::{PublishPacket, QualityOfService}; use crate::network::network_trait::{Network, NetworkError}; use crate::packet::connack_packet::ConnackPacket; use crate::packet::connect_packet::ConnectPacket; use crate::packet::disconnect_packet::DisconnectPacket; use crate::packet::mqtt_packet::Packet; +use crate::packet::publish_packet::{PublishPacket, QualityOfService}; use crate::packet::publish_packet::QualityOfService::QoS1; use crate::utils::buffer_reader::BuffReader; -pub struct MqttClientV5 { - network_driver: T, +pub struct MqttClientV5<'a, T, const MAX_PROPERTIES: usize> { + network_driver: &'a mut T, + buffer: &'a mut [u8] } -impl<'a, T, const MAX_PROPERTIES: usize> MqttClientV5 +impl<'a, T, const MAX_PROPERTIES: usize> MqttClientV5<'a, T, MAX_PROPERTIES> where T: Network { - pub fn new(network_driver: T) -> Self { + pub fn new(network_driver: &'a mut T, buffer: &'a mut [u8]) -> Self { Self { network_driver, + buffer } } // connect -> connack -> publish -> QoS ? -> disconn - pub async fn send_message(& mut self, topic_name: & str, message: & str, buffer: &'a mut [u8], qos: QualityOfService) -> Result<(), NetworkError> { + pub async fn send_message(&'a mut self, topic_name: & str, message: & str, qos: QualityOfService) -> Result<(), NetworkError> { //connect self.network_driver.create_connection().await ?; let mut connect = ConnectPacket::<3, 0>::clean(); - let mut len = connect.encode(buffer); - self.network_driver.send(buffer, len).await ?; + let mut len = connect.encode(self.buffer); + + self.network_driver.send(self.buffer, len).await ?; //connack - let connack: ConnackPacket = self.receive::>(buffer).await ?; + let connack: ConnackPacket = self.receive::>().await ?; if connack.connect_reason_code != 0x00 { todo!(); } // publish let mut packet = PublishPacket::<5>::new(topic_name, message); - len = packet.encode(buffer); - self.network_driver.send(buffer, len).await ?; + len = packet.encode(self.buffer); + self.network_driver.send(self.buffer, len).await ?; //QoS1 if >::into(qos) == >::into(QoS1) { @@ -46,19 +49,19 @@ where //Disconnect let mut disconnect = DisconnectPacket::<5>::new(); - len = disconnect.encode(buffer); - self.network_driver.send(buffer, len); + len = disconnect.encode(self.buffer); + self.network_driver.send(self.buffer, len); Ok(()) } - pub async fn receive>(& mut self, buffer: &'a mut [u8]) -> Result { - self.network_driver.receive(buffer).await ?; + pub async fn receive>(&'a mut self) -> Result { + self.network_driver.receive(self.buffer).await ?; let mut packet = P::new(); - packet.decode(&mut BuffReader::new(buffer)); + packet.decode(&mut BuffReader::new(self.buffer)); return Ok(packet); } - pub async fn receive_message(& mut self, buffer: & mut [u8]) -> Result<(), NetworkError> { + pub async fn receive_message(&'a mut self) -> Result<(), NetworkError> { return Ok(()); } } diff --git a/src/network/network_trait.rs b/src/network/network_trait.rs index 0065fa7..4d38b56 100644 --- a/src/network/network_trait.rs +++ b/src/network/network_trait.rs @@ -1,6 +1,6 @@ use core::fmt::Error; - use core::future::Future; + use crate::packet::mqtt_packet::Packet; pub enum NetworkError { diff --git a/src/packet/auth_packet.rs b/src/packet/auth_packet.rs index 4e7314a..d2fb850 100644 --- a/src/packet/auth_packet.rs +++ b/src/packet/auth_packet.rs @@ -1,6 +1,6 @@ -use crate::encoding::variable_byte_integer::VariableByteIntegerEncoder; use heapless::Vec; +use crate::encoding::variable_byte_integer::VariableByteIntegerEncoder; use crate::packet::mqtt_packet::Packet; use crate::utils::buffer_reader::BuffReader; use crate::utils::buffer_writer::BuffWriter; diff --git a/src/packet/connack_packet.rs b/src/packet/connack_packet.rs index 76601c1..3f0449e 100644 --- a/src/packet/connack_packet.rs +++ b/src/packet/connack_packet.rs @@ -1,6 +1,6 @@ -use crate::encoding::variable_byte_integer::VariableByteIntegerEncoder; use heapless::Vec; +use crate::encoding::variable_byte_integer::VariableByteIntegerEncoder; use crate::packet::mqtt_packet::Packet; use crate::utils::buffer_reader::BuffReader; use crate::utils::buffer_writer::BuffWriter; diff --git a/src/packet/connect_packet.rs b/src/packet/connect_packet.rs index aaf5a6c..77eaa72 100644 --- a/src/packet/connect_packet.rs +++ b/src/packet/connect_packet.rs @@ -1,6 +1,6 @@ -use crate::encoding::variable_byte_integer::VariableByteIntegerEncoder; use heapless::Vec; +use crate::encoding::variable_byte_integer::VariableByteIntegerEncoder; use crate::packet::mqtt_packet::Packet; use crate::utils::buffer_reader::BinaryData; use crate::utils::buffer_reader::BuffReader; diff --git a/src/packet/disconnect_packet.rs b/src/packet/disconnect_packet.rs index 2a85962..ca8cc5e 100644 --- a/src/packet/disconnect_packet.rs +++ b/src/packet/disconnect_packet.rs @@ -1,6 +1,6 @@ -use crate::encoding::variable_byte_integer::VariableByteIntegerEncoder; use heapless::Vec; +use crate::encoding::variable_byte_integer::VariableByteIntegerEncoder; use crate::packet::mqtt_packet::Packet; use crate::utils::buffer_reader::BuffReader; use crate::utils::buffer_writer::BuffWriter; diff --git a/src/packet/puback_packet.rs b/src/packet/puback_packet.rs index 384212e..9a51b85 100644 --- a/src/packet/puback_packet.rs +++ b/src/packet/puback_packet.rs @@ -1,6 +1,6 @@ -use crate::encoding::variable_byte_integer::VariableByteIntegerEncoder; use heapless::Vec; +use crate::encoding::variable_byte_integer::VariableByteIntegerEncoder; use crate::packet::mqtt_packet::Packet; use crate::utils::buffer_reader::BuffReader; use crate::utils::buffer_writer::BuffWriter; diff --git a/src/packet/pubcomp_packet.rs b/src/packet/pubcomp_packet.rs index 2b497d3..b067ca6 100644 --- a/src/packet/pubcomp_packet.rs +++ b/src/packet/pubcomp_packet.rs @@ -1,6 +1,6 @@ -use crate::encoding::variable_byte_integer::VariableByteIntegerEncoder; use heapless::Vec; +use crate::encoding::variable_byte_integer::VariableByteIntegerEncoder; use crate::packet::mqtt_packet::Packet; use crate::utils::buffer_reader::BuffReader; use crate::utils::buffer_writer::BuffWriter; diff --git a/src/packet/publish_packet.rs b/src/packet/publish_packet.rs index 10b46ba..1c94662 100644 --- a/src/packet/publish_packet.rs +++ b/src/packet/publish_packet.rs @@ -1,6 +1,6 @@ -use crate::encoding::variable_byte_integer::VariableByteIntegerEncoder; use heapless::Vec; +use crate::encoding::variable_byte_integer::VariableByteIntegerEncoder; use crate::packet::mqtt_packet::Packet; use crate::packet::publish_packet::QualityOfService::{INVALID, QoS0, QoS1, QoS2}; use crate::utils::buffer_reader::BuffReader; diff --git a/src/packet/pubrec_packet.rs b/src/packet/pubrec_packet.rs index c256189..00a8428 100644 --- a/src/packet/pubrec_packet.rs +++ b/src/packet/pubrec_packet.rs @@ -1,6 +1,6 @@ -use crate::encoding::variable_byte_integer::VariableByteIntegerEncoder; use heapless::Vec; +use crate::encoding::variable_byte_integer::VariableByteIntegerEncoder; use crate::packet::mqtt_packet::Packet; use crate::utils::buffer_reader::BuffReader; use crate::utils::buffer_writer::BuffWriter; diff --git a/src/packet/pubrel_packet.rs b/src/packet/pubrel_packet.rs index e5c5035..2a25bd8 100644 --- a/src/packet/pubrel_packet.rs +++ b/src/packet/pubrel_packet.rs @@ -1,6 +1,6 @@ -use crate::encoding::variable_byte_integer::VariableByteIntegerEncoder; use heapless::Vec; +use crate::encoding::variable_byte_integer::VariableByteIntegerEncoder; use crate::packet::mqtt_packet::Packet; use crate::utils::buffer_reader::BuffReader; use crate::utils::buffer_writer::BuffWriter; diff --git a/src/packet/suback_packet.rs b/src/packet/suback_packet.rs index 6b073ca..b6e5adc 100644 --- a/src/packet/suback_packet.rs +++ b/src/packet/suback_packet.rs @@ -1,6 +1,6 @@ -use crate::encoding::variable_byte_integer::VariableByteIntegerEncoder; use heapless::Vec; +use crate::encoding::variable_byte_integer::VariableByteIntegerEncoder; use crate::packet::mqtt_packet::Packet; use crate::utils::buffer_reader::BuffReader; use crate::utils::buffer_writer::BuffWriter; diff --git a/src/packet/subscription_packet.rs b/src/packet/subscription_packet.rs index 9170b2a..5abfe78 100644 --- a/src/packet/subscription_packet.rs +++ b/src/packet/subscription_packet.rs @@ -1,6 +1,6 @@ -use crate::encoding::variable_byte_integer::VariableByteIntegerEncoder; use heapless::Vec; +use crate::encoding::variable_byte_integer::VariableByteIntegerEncoder; use crate::packet::mqtt_packet::Packet; use crate::utils::buffer_reader::BuffReader; use crate::utils::buffer_reader::TopicFilter; diff --git a/src/packet/unsubscription_packet.rs b/src/packet/unsubscription_packet.rs index e29d901..ae7ba7f 100644 --- a/src/packet/unsubscription_packet.rs +++ b/src/packet/unsubscription_packet.rs @@ -1,6 +1,6 @@ -use crate::encoding::variable_byte_integer::VariableByteIntegerEncoder; use heapless::Vec; +use crate::encoding::variable_byte_integer::VariableByteIntegerEncoder; use crate::packet::mqtt_packet::Packet; use crate::utils::buffer_reader::BuffReader; use crate::utils::buffer_reader::TopicFilter; diff --git a/src/tokio_network.rs b/src/tokio_network.rs index 2e8ba69..47582cd 100644 --- a/src/tokio_network.rs +++ b/src/tokio_network.rs @@ -4,9 +4,11 @@ use core::borrow::BorrowMut; use core::fmt::Error; use core::future::Future; use core::ptr::null; + use embassy::io::WriteAll; use tokio::io::{AsyncReadExt, AsyncWriteExt}; use tokio::net::{TcpListener, TcpStream}; + use crate::network::network_trait::{Network, NetworkError}; use crate::packet::mqtt_packet::Packet; diff --git a/src/utils/buffer_writer.rs b/src/utils/buffer_writer.rs index bb6f974..162821e 100644 --- a/src/utils/buffer_writer.rs +++ b/src/utils/buffer_writer.rs @@ -1,8 +1,10 @@ +use core::str; + +use heapless::Vec; + use crate::encoding::variable_byte_integer::{VariableByteInteger, VariableByteIntegerEncoder}; use crate::packet::property::Property; use crate::utils::buffer_reader::{BinaryData, EncodedString, StringPair, TopicFilter}; -use core::str; -use heapless::Vec; pub struct BuffWriter<'a> { buffer: &'a mut [u8], From cc6498a76f6a8728cb0bfda96aefd7054b08fd5e Mon Sep 17 00:00:00 2001 From: Ondrej Babec Date: Fri, 25 Feb 2022 16:20:55 +0100 Subject: [PATCH 05/10] Fix async --- src/client/client_v5.rs | 72 ++++++++++++++++++++++++----------------- src/main.rs | 5 +-- src/tokio_network.rs | 4 +++ 3 files changed, 49 insertions(+), 32 deletions(-) diff --git a/src/client/client_v5.rs b/src/client/client_v5.rs index 404d813..22bcfbe 100644 --- a/src/client/client_v5.rs +++ b/src/client/client_v5.rs @@ -1,3 +1,4 @@ +use core::future::Future; use crate::network::network_trait::{Network, NetworkError}; use crate::packet::connack_packet::ConnackPacket; use crate::packet::connect_packet::ConnectPacket; @@ -23,42 +24,53 @@ where } } // connect -> connack -> publish -> QoS ? -> disconn - pub async fn send_message(&'a mut self, topic_name: & str, message: & str, qos: QualityOfService) -> Result<(), NetworkError> { - //connect - self.network_driver.create_connection().await ?; + pub async fn send_message(&'a mut self, topic_name: & str, message: & str, qos: QualityOfService) -> impl Future> { + async move { + let mut len = { + let mut connect = ConnectPacket::<3, 0>::clean(); + connect.encode(self.buffer) + }; - let mut connect = ConnectPacket::<3, 0>::clean(); - let mut len = connect.encode(self.buffer); + self.network_driver.send(self.buffer, len).await?; - self.network_driver.send(self.buffer, len).await ?; - //connack - let connack: ConnackPacket = self.receive::>().await ?; - if connack.connect_reason_code != 0x00 { - todo!(); + //connack + let connack = { + let connack = self.receive().await?; + let mut packet = ConnackPacket::new(); + packet.decode(&mut BuffReader::new(self.buffer)); + packet + }; + + if connack.connect_reason_code != 0x00 { + todo!(); + } + + // publish + + len = { + let mut packet = PublishPacket::<5>::new(topic_name, message); + packet.encode(self.buffer) + }; + + self.network_driver.send(self.buffer, len).await?; + + + //QoS1 + if >::into(qos) == >::into(QoS1) { + todo!(); + } + + //Disconnect + let mut disconnect = DisconnectPacket::<5>::new(); + len = disconnect.encode(self.buffer); + self.network_driver.send(self.buffer, len); + Ok(()) } - - // publish - let mut packet = PublishPacket::<5>::new(topic_name, message); - len = packet.encode(self.buffer); - self.network_driver.send(self.buffer, len).await ?; - - //QoS1 - if >::into(qos) == >::into(QoS1) { - todo!(); - } - - //Disconnect - let mut disconnect = DisconnectPacket::<5>::new(); - len = disconnect.encode(self.buffer); - self.network_driver.send(self.buffer, len); - Ok(()) } - pub async fn receive>(&'a mut self) -> Result { + pub async fn receive(&'a mut self) -> Result<(), NetworkError> { self.network_driver.receive(self.buffer).await ?; - let mut packet = P::new(); - packet.decode(&mut BuffReader::new(self.buffer)); - return Ok(packet); + Ok(()) } pub async fn receive_message(&'a mut self) -> Result<(), NetworkError> { diff --git a/src/main.rs b/src/main.rs index 90c7757..47a58af 100644 --- a/src/main.rs +++ b/src/main.rs @@ -31,7 +31,8 @@ fn main() { let mut ip: [u8; 4] = [37, 205, 11, 180]; let mut port: u16 = 1883; let mut tokio_network: TokioNetwork = TokioNetwork::new(ip, port); - let client = MqttClientV5::new::(tokio_network); - let mut x = b"hello world"; + tokio_network.create_connection().await; let mut res2 = vec![0; 260]; + let client = MqttClientV5::new(&mut tokio_network, &mut res2); + let mut x = b"hello world"; } diff --git a/src/tokio_network.rs b/src/tokio_network.rs index 47582cd..4db8861 100644 --- a/src/tokio_network.rs +++ b/src/tokio_network.rs @@ -24,6 +24,10 @@ impl TokioNetwork { } } +impl TokioNetwork { + +} + impl Network for TokioNetwork { type ConnectionFuture<'m> where Self: 'm = impl Future> + 'm; type WriteFuture<'m> where Self: 'm = impl Future> + 'm; From 5729feef15fedb93d75faa4f58828121b1b6504b Mon Sep 17 00:00:00 2001 From: Ondrej Babec Date: Fri, 25 Feb 2022 16:35:46 +0100 Subject: [PATCH 06/10] Type issue --- src/client/client_v5.rs | 73 ++++++++++++++++++++--------------------- src/main.rs | 1 + src/tokio_network.rs | 1 - 3 files changed, 37 insertions(+), 38 deletions(-) diff --git a/src/client/client_v5.rs b/src/client/client_v5.rs index 22bcfbe..34198c2 100644 --- a/src/client/client_v5.rs +++ b/src/client/client_v5.rs @@ -24,48 +24,47 @@ where } } // connect -> connack -> publish -> QoS ? -> disconn - pub async fn send_message(&'a mut self, topic_name: & str, message: & str, qos: QualityOfService) -> impl Future> { - async move { - let mut len = { - let mut connect = ConnectPacket::<3, 0>::clean(); - connect.encode(self.buffer) - }; + pub async fn send_message(&'a mut self, topic_name: & str, message: & str, qos: QualityOfService) -> Result<(), NetworkError> { - self.network_driver.send(self.buffer, len).await?; + let mut len = { + let mut connect = ConnectPacket::<3, 0>::clean(); + connect.encode(self.buffer) + }; - //connack - let connack = { - let connack = self.receive().await?; - let mut packet = ConnackPacket::new(); - packet.decode(&mut BuffReader::new(self.buffer)); - packet - }; + self.network_driver.send(self.buffer, len).await ?; - if connack.connect_reason_code != 0x00 { - todo!(); - } + //connack + let connack = { + self.receive().await ?; + let mut packet = ConnackPacket::new(); + packet.decode(&mut BuffReader::new(self.buffer)); + packet + }; - // publish - - len = { - let mut packet = PublishPacket::<5>::new(topic_name, message); - packet.encode(self.buffer) - }; - - self.network_driver.send(self.buffer, len).await?; - - - //QoS1 - if >::into(qos) == >::into(QoS1) { - todo!(); - } - - //Disconnect - let mut disconnect = DisconnectPacket::<5>::new(); - len = disconnect.encode(self.buffer); - self.network_driver.send(self.buffer, len); - Ok(()) + if connack.connect_reason_code != 0x00 { + todo!(); } + + // publish + + len = { + let mut packet = PublishPacket::<5>::new(topic_name, message); + packet.encode(self.buffer) + }; + + self.network_driver.send(self.buffer, len).await ?; + + + //QoS1 + if >::into(qos) == >::into(QoS1) { + todo!(); + } + + //Disconnect + let mut disconnect = DisconnectPacket::<5>::new(); + len = disconnect.encode(self.buffer); + self.network_driver.send(self.buffer, len); + Ok(()) } pub async fn receive(&'a mut self) -> Result<(), NetworkError> { diff --git a/src/main.rs b/src/main.rs index 47a58af..dea981a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,6 +6,7 @@ use rust_mqtt::packet::publish_packet::PublishPacket; use rust_mqtt::packet::subscription_packet::SubscriptionPacket; use rust_mqtt::tokio_network::TokioNetwork; +#[tokio::main] fn main() { env_logger::builder() .filter_level(log::LevelFilter::Info) diff --git a/src/tokio_network.rs b/src/tokio_network.rs index 4db8861..9d9fe1d 100644 --- a/src/tokio_network.rs +++ b/src/tokio_network.rs @@ -5,7 +5,6 @@ use core::fmt::Error; use core::future::Future; use core::ptr::null; -use embassy::io::WriteAll; use tokio::io::{AsyncReadExt, AsyncWriteExt}; use tokio::net::{TcpListener, TcpStream}; From a862637a7744e73c0fef8ebc18e457d026b5af31 Mon Sep 17 00:00:00 2001 From: Ondrej Babec Date: Fri, 25 Feb 2022 16:49:48 +0100 Subject: [PATCH 07/10] Custom scope --- src/client/client_v5.rs | 14 ++++++++------ src/main.rs | 2 +- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/client/client_v5.rs b/src/client/client_v5.rs index 34198c2..d1ddf79 100644 --- a/src/client/client_v5.rs +++ b/src/client/client_v5.rs @@ -34,16 +34,18 @@ where self.network_driver.send(self.buffer, len).await ?; //connack - let connack = { + { self.receive().await ?; - let mut packet = ConnackPacket::new(); + let mut packet = ConnackPacket::<5>::new(); packet.decode(&mut BuffReader::new(self.buffer)); - packet + + + if packet.connect_reason_code != 0x00 { + todo!(); + } }; - if connack.connect_reason_code != 0x00 { - todo!(); - } + // publish diff --git a/src/main.rs b/src/main.rs index dea981a..0e09864 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,7 +7,7 @@ use rust_mqtt::packet::subscription_packet::SubscriptionPacket; use rust_mqtt::tokio_network::TokioNetwork; #[tokio::main] -fn main() { +async fn main() { env_logger::builder() .filter_level(log::LevelFilter::Info) .format_timestamp_nanos() From 3cb9de03711a41d4d2504b84d5d724d5ca6c00d2 Mon Sep 17 00:00:00 2001 From: Ondrej Babec Date: Sat, 26 Feb 2022 15:12:19 +0100 Subject: [PATCH 08/10] Working example of client --- src/client/client_v5.rs | 99 ++++++++++++++++++++--------- src/client/mod.rs | 2 +- src/lib.rs | 6 +- src/main.rs | 83 +++++++++++++++++------- src/network/mod.rs | 2 +- src/network/network_trait.rs | 6 +- src/packet/connack_packet.rs | 9 ++- src/packet/connect_packet.rs | 1 + src/packet/disconnect_packet.rs | 4 +- src/packet/mqtt_packet.rs | 28 ++++---- src/packet/publish_packet.rs | 50 ++++++++------- src/packet/suback_packet.rs | 9 ++- src/packet/subscription_packet.rs | 27 ++++---- src/packet/unsubscription_packet.rs | 1 - src/tokio_network.rs | 43 ++++++++----- src/utils/buffer_reader.rs | 5 +- src/utils/buffer_writer.rs | 2 +- 17 files changed, 242 insertions(+), 135 deletions(-) diff --git a/src/client/client_v5.rs b/src/client/client_v5.rs index d1ddf79..eae67f9 100644 --- a/src/client/client_v5.rs +++ b/src/client/client_v5.rs @@ -1,80 +1,117 @@ use core::future::Future; + use crate::network::network_trait::{Network, NetworkError}; use crate::packet::connack_packet::ConnackPacket; use crate::packet::connect_packet::ConnectPacket; use crate::packet::disconnect_packet::DisconnectPacket; use crate::packet::mqtt_packet::Packet; -use crate::packet::publish_packet::{PublishPacket, QualityOfService}; use crate::packet::publish_packet::QualityOfService::QoS1; +use crate::packet::publish_packet::{PublishPacket, QualityOfService}; +use crate::packet::suback_packet::SubackPacket; +use crate::packet::subscription_packet::SubscriptionPacket; use crate::utils::buffer_reader::BuffReader; pub struct MqttClientV5<'a, T, const MAX_PROPERTIES: usize> { network_driver: &'a mut T, - buffer: &'a mut [u8] + buffer: &'a mut [u8], } impl<'a, T, const MAX_PROPERTIES: usize> MqttClientV5<'a, T, MAX_PROPERTIES> where - T: Network + T: Network, { pub fn new(network_driver: &'a mut T, buffer: &'a mut [u8]) -> Self { Self { network_driver, - buffer + buffer, } } - // connect -> connack -> publish -> QoS ? -> disconn - pub async fn send_message(&'a mut self, topic_name: & str, message: & str, qos: QualityOfService) -> Result<(), NetworkError> { + pub async fn connect_to_broker<'b>(&'b mut self) -> Result<(), NetworkError> { let mut len = { - let mut connect = ConnectPacket::<3, 0>::clean(); + let mut connect = ConnectPacket::<'b, 3, 0>::clean(); connect.encode(self.buffer) }; - self.network_driver.send(self.buffer, len).await ?; + self.network_driver.send(self.buffer, len).await?; //connack - { - self.receive().await ?; - let mut packet = ConnackPacket::<5>::new(); + let reason: u8 = { + self.network_driver.receive(self.buffer).await?; + let mut packet = ConnackPacket::<'b, 5>::new(); packet.decode(&mut BuffReader::new(self.buffer)); - - - if packet.connect_reason_code != 0x00 { - todo!(); - } + packet.connect_reason_code }; + if reason != 0x00 { + Err(NetworkError::Connection) + } else { + Ok(()) + } + + } + + pub async fn disconnect<'b>(&'b mut self) -> Result<(), NetworkError> { + let mut disconnect = DisconnectPacket::<'b, 5>::new(); + let mut len = disconnect.encode(self.buffer); + self.network_driver.send(self.buffer, len).await?; + Ok(()) + } + // connect -> connack -> publish -> QoS ? -> disconn + pub async fn send_message<'b>( + &'b mut self, + topic_name: &'b str, + message: &'b str, + qos: QualityOfService, + ) -> Result<(), NetworkError> { // publish - - len = { - let mut packet = PublishPacket::<5>::new(topic_name, message); + let len = { + let mut packet = PublishPacket::<'b, 5>::new(); + packet.add_topic_name(topic_name); + packet.add_message(message.as_bytes()); packet.encode(self.buffer) }; - self.network_driver.send(self.buffer, len).await ?; - + self.network_driver.send(self.buffer, len).await?; //QoS1 if >::into(qos) == >::into(QoS1) { todo!(); } - - //Disconnect - let mut disconnect = DisconnectPacket::<5>::new(); - len = disconnect.encode(self.buffer); - self.network_driver.send(self.buffer, len); Ok(()) } - pub async fn receive(&'a mut self) -> Result<(), NetworkError> { - self.network_driver.receive(self.buffer).await ?; - Ok(()) + pub async fn subscribe_to_topic<'b>(&'b mut self, topic_name: &'b str) -> Result<(), NetworkError> { + let len = { + let mut subs = SubscriptionPacket::<'b, 1, 1>::new(); + subs.add_new_filter(topic_name); + subs.encode(self.buffer) + }; + let xx: [u8; 14] = (self.buffer[0..14]).try_into().unwrap(); + log::info!("{:x?}", xx); + self.network_driver.send(self.buffer, len).await?; + + let reason = { + self.network_driver.receive(self.buffer).await?; + let mut packet = SubackPacket::<'b, 5, 5>::new(); + packet.decode(&mut BuffReader::new(self.buffer)); + *packet.reason_codes.get(0).unwrap() + }; + + if reason > 1 { + Err(NetworkError::Unknown) + } else { + Ok(()) + } + } - pub async fn receive_message(&'a mut self) -> Result<(), NetworkError> { - return Ok(()); + pub async fn receive_message<'b>(&'b mut self) -> Result<&'b [u8], NetworkError> { + self.network_driver.receive(self.buffer).await?; + let mut packet = PublishPacket::<'b, 5>::new(); + packet.decode(&mut BuffReader::new(self.buffer)); + return Ok(packet.message.unwrap()); } } diff --git a/src/client/mod.rs b/src/client/mod.rs index ab4c08b..3f271f3 100644 --- a/src/client/mod.rs +++ b/src/client/mod.rs @@ -1 +1 @@ -pub mod client_v5; \ No newline at end of file +pub mod client_v5; diff --git a/src/lib.rs b/src/lib.rs index 5298429..6c19f62 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,12 +7,12 @@ extern crate alloc; -pub mod encoding; -pub mod packet; -pub mod utils; pub mod client; +pub mod encoding; pub mod network; +pub mod packet; pub mod tokio_network; +pub mod utils; #[allow(unused_variables)] pub fn print_stack(file: &'static str, line: u32) { diff --git a/src/main.rs b/src/main.rs index 0e09864..9c18a55 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,10 +1,60 @@ use rust_mqtt::client::client_v5::MqttClientV5; -use rust_mqtt::network::network_trait::Network; +use rust_mqtt::network::network_trait::{Network, NetworkError}; use rust_mqtt::packet::connect_packet::ConnectPacket; use rust_mqtt::packet::mqtt_packet::Packet; -use rust_mqtt::packet::publish_packet::PublishPacket; +use rust_mqtt::packet::publish_packet::{PublishPacket, QualityOfService}; use rust_mqtt::packet::subscription_packet::SubscriptionPacket; use rust_mqtt::tokio_network::TokioNetwork; +use std::time::Duration; +use tokio::time::sleep; +use tokio::{join, task}; + +async fn receive() { + let mut ip: [u8; 4] = [37, 205, 11, 180]; + let mut port: u16 = 1883; + let mut tokio_network: TokioNetwork = TokioNetwork::new(ip, port); + tokio_network.create_connection().await; + let mut res2 = vec![0; 260]; + let mut client = MqttClientV5::::new(&mut tokio_network, &mut res2); + + let mut result = { client.connect_to_broker().await }; + + { + client.subscribe_to_topic("test/topic").await; + } + { + log::info!("Waiting for new message!"); + let mes = client.receive_message().await.unwrap(); + let x = String::from_utf8_lossy(mes); + log::info!("Got new message: {}", x); + } + { + client.disconnect().await; + } +} + +async fn publish(message: &str) { + let mut ip: [u8; 4] = [37, 205, 11, 180]; + let mut port: u16 = 1883; + let mut tokio_network: TokioNetwork = TokioNetwork::new(ip, port); + tokio_network.create_connection().await; + let mut res2 = vec![0; 260]; + let mut client = MqttClientV5::::new(&mut tokio_network, &mut res2); + + let mut result = { client.connect_to_broker().await }; + log::info!("Waiting until send!"); + sleep(Duration::from_secs(15)); + let mut result: Result<(), NetworkError> = { + log::info!("Sending new message!"); + client + .send_message("test/topic", message, QualityOfService::QoS0) + .await + }; + + { + client.disconnect().await; + } +} #[tokio::main] async fn main() { @@ -13,27 +63,14 @@ async fn main() { .format_timestamp_nanos() .init(); - /*let mut pckt: SubscriptionPacket<1, 0> = SubscriptionPacket::new(); - let mut res = vec![0; 140]; - let lnsub = pckt.encode(&mut res); - println!("{:02X?}", &res[0..lnsub]); - let mut res2 = vec![0; 260]; + let recv = task::spawn(async move { + receive().await; + }); - let mut pblsh = PublishPacket::<0>::new(x); - let lnpblsh = pblsh.encode(&mut res2); - println!("{:02X?}", &res2[0..lnpblsh]); - log::info!("xxx"); + let publ = task::spawn(async move { + publish("hello world 123 !").await; + }); - let mut res3 = vec![0; 260]; - let mut cntrl = ConnectPacket::<3, 0>::clean(); - let lncntrl = cntrl.encode(&mut res3); - println!("{:02X?}", &res3[0..lncntrl]); - log::info!("xxx");*/ - let mut ip: [u8; 4] = [37, 205, 11, 180]; - let mut port: u16 = 1883; - let mut tokio_network: TokioNetwork = TokioNetwork::new(ip, port); - tokio_network.create_connection().await; - let mut res2 = vec![0; 260]; - let client = MqttClientV5::new(&mut tokio_network, &mut res2); - let mut x = b"hello world"; + join!(recv, publ); + log::info!("Done"); } diff --git a/src/network/mod.rs b/src/network/mod.rs index 294a433..e083076 100644 --- a/src/network/mod.rs +++ b/src/network/mod.rs @@ -1 +1 @@ -pub mod network_trait; \ No newline at end of file +pub mod network_trait; diff --git a/src/network/network_trait.rs b/src/network/network_trait.rs index 4d38b56..b446bc3 100644 --- a/src/network/network_trait.rs +++ b/src/network/network_trait.rs @@ -3,17 +3,17 @@ use core::future::Future; use crate::packet::mqtt_packet::Packet; + +#[derive(Debug)] pub enum NetworkError { Connection, Unknown, } - - pub trait Network { type ConnectionFuture<'m>: Future> where - Self: 'm; + Self: 'm; type WriteFuture<'m>: Future> where diff --git a/src/packet/connack_packet.rs b/src/packet/connack_packet.rs index 3f0449e..f6c97c3 100644 --- a/src/packet/connack_packet.rs +++ b/src/packet/connack_packet.rs @@ -33,7 +33,14 @@ impl<'a, const MAX_PROPERTIES: usize> ConnackPacket<'a, MAX_PROPERTIES> { impl<'a, const MAX_PROPERTIES: usize> Packet<'a> for ConnackPacket<'a, MAX_PROPERTIES> { fn new() -> Self { - todo!() + Self { + fixed_header: PacketType::Connack.into(), + remain_len: 0, + ack_flags: 0, + connect_reason_code: 0, + property_len: 0, + properties: Vec::, MAX_PROPERTIES>::new(), + } } fn encode(&mut self, buffer: &mut [u8]) -> usize { diff --git a/src/packet/connect_packet.rs b/src/packet/connect_packet.rs index 77eaa72..7a38449 100644 --- a/src/packet/connect_packet.rs +++ b/src/packet/connect_packet.rs @@ -98,6 +98,7 @@ impl<'a, const MAX_PROPERTIES: usize, const MAX_WILL_PROPERTIES: usize> self.fixed_header = cur_type | flags; } } + impl<'a, const MAX_PROPERTIES: usize, const MAX_WILL_PROPERTIES: usize> Packet<'a> for ConnectPacket<'a, MAX_PROPERTIES, MAX_WILL_PROPERTIES> { diff --git a/src/packet/disconnect_packet.rs b/src/packet/disconnect_packet.rs index ca8cc5e..4338307 100644 --- a/src/packet/disconnect_packet.rs +++ b/src/packet/disconnect_packet.rs @@ -31,7 +31,7 @@ impl<'a, const MAX_PROPERTIES: usize> DisconnectPacket<'a, MAX_PROPERTIES> { self.decode_properties(buff_reader); } - fn add_reason(& mut self, reason: u8) { + fn add_reason(&mut self, reason: u8) { self.disconnect_reason = reason; } } @@ -43,7 +43,7 @@ impl<'a, const MAX_PROPERTIES: usize> Packet<'a> for DisconnectPacket<'a, MAX_PR remain_len: 5, disconnect_reason: 0x00, property_len: 0, - properties: Vec::, MAX_PROPERTIES>::new() + properties: Vec::, MAX_PROPERTIES>::new(), } } diff --git a/src/packet/mqtt_packet.rs b/src/packet/mqtt_packet.rs index 5100cc0..9a65305 100644 --- a/src/packet/mqtt_packet.rs +++ b/src/packet/mqtt_packet.rs @@ -24,20 +24,22 @@ pub trait Packet<'a> { self.set_property_len(buff_reader.read_variable_byte_int().unwrap()); let mut x: u32 = 0; let mut prop: Result; - loop { - let mut res: Property; - prop = Property::decode(buff_reader); - if let Ok(res) = prop { - log::info!("Parsed property {:?}", res); - x = x + res.len() as u32 + 1; - self.push_to_properties(res); - } else { - // error handler - log::error!("Problem during property decoding"); - } + if self.get_property_len() != 0 { + loop { + let mut res: Property; + prop = Property::decode(buff_reader); + if let Ok(res) = prop { + log::info!("Parsed property {:?}", res); + x = x + res.len() as u32 + 1; + self.push_to_properties(res); + } else { + // error handler + log::error!("Problem during property decoding"); + } - if x == self.get_property_len() { - break; + if x == self.get_property_len() { + break; + } } } } diff --git a/src/packet/publish_packet.rs b/src/packet/publish_packet.rs index 1c94662..3f4ed21 100644 --- a/src/packet/publish_packet.rs +++ b/src/packet/publish_packet.rs @@ -1,8 +1,9 @@ +use core::ptr::null; use heapless::Vec; use crate::encoding::variable_byte_integer::VariableByteIntegerEncoder; use crate::packet::mqtt_packet::Packet; -use crate::packet::publish_packet::QualityOfService::{INVALID, QoS0, QoS1, QoS2}; +use crate::packet::publish_packet::QualityOfService::{QoS0, QoS1, QoS2, INVALID}; use crate::utils::buffer_reader::BuffReader; use crate::utils::buffer_reader::EncodedString; use crate::utils::buffer_writer::BuffWriter; @@ -14,7 +15,7 @@ pub enum QualityOfService { QoS0, QoS1, QoS2, - INVALID + INVALID, } impl From for QualityOfService { @@ -23,8 +24,8 @@ impl From for QualityOfService { 0 => QoS0, 1 => QoS1, 2 => QoS2, - _ => INVALID - } + _ => INVALID, + }; } } @@ -35,7 +36,7 @@ impl Into for QualityOfService { QoS1 => 1, QoS2 => 2, INVALID => 3, - } + }; } } @@ -53,29 +54,19 @@ pub struct PublishPacket<'a, const MAX_PROPERTIES: usize> { // properties pub properties: Vec, MAX_PROPERTIES>, - pub message: &'a [u8], + pub message: Option<&'a [u8]>, } impl<'a, const MAX_PROPERTIES: usize> PublishPacket<'a, MAX_PROPERTIES> { - pub fn new(topic_name: &'a str, message: &'a str) -> Self { - let mut x = Self { - fixed_header: PacketType::Publish.into(), - remain_len: 0, - topic_name: EncodedString::new(), - packet_identifier: 1, - property_len: 0, - properties: Vec::, MAX_PROPERTIES>::new(), - message: message.as_bytes(), - }; - x.add_topic_name(topic_name); - return x; - } - pub fn add_topic_name(&mut self, topic_name: &'a str) { self.topic_name.string = topic_name; self.topic_name.len = topic_name.len() as u16; } + pub fn add_message(& mut self, message: &'a [u8]) { + self.message = Some(message); + } + pub fn decode_publish_packet(&mut self, buff_reader: &mut BuffReader<'a>) { if self.decode_fixed_header(buff_reader) != (PacketType::Publish).into() { log::error!("Packet you are trying to decode is not PUBLISH packet!"); @@ -88,13 +79,24 @@ impl<'a, const MAX_PROPERTIES: usize> PublishPacket<'a, MAX_PROPERTIES> { self.packet_identifier = buff_reader.read_u16().unwrap(); } self.decode_properties(buff_reader); - self.message = buff_reader.read_message(); + let mut total_len = VariableByteIntegerEncoder::len( + VariableByteIntegerEncoder::encode(self.remain_len).unwrap()); + total_len = total_len + 1 + self.remain_len as usize; + self.message = Some(buff_reader.read_message(total_len)); } } impl<'a, const MAX_PROPERTIES: usize> Packet<'a> for PublishPacket<'a, MAX_PROPERTIES> { fn new() -> Self { - todo!() + Self { + fixed_header: PacketType::Publish.into(), + remain_len: 0, + topic_name: EncodedString::new(), + packet_identifier: 1, + property_len: 0, + properties: Vec::, MAX_PROPERTIES>::new(), + message: None + } } fn encode(&mut self, buffer: &mut [u8]) -> usize { @@ -104,7 +106,7 @@ impl<'a, const MAX_PROPERTIES: usize> Packet<'a> for PublishPacket<'a, MAX_PROPE let property_len_enc: [u8; 4] = VariableByteIntegerEncoder::encode(self.property_len).unwrap(); let property_len_len = VariableByteIntegerEncoder::len(property_len_enc); - let mut msg_len = self.message.len() as u32; + let mut msg_len = self.message.unwrap().len() as u32; rm_ln = rm_ln + property_len_len as u32 + msg_len + self.topic_name.len as u32 + 2; buff_writer.write_u8(self.fixed_header); @@ -122,7 +124,7 @@ impl<'a, const MAX_PROPERTIES: usize> Packet<'a> for PublishPacket<'a, MAX_PROPE buff_writer.write_variable_byte_int(self.property_len); buff_writer.encode_properties::(&self.properties); - buff_writer.insert_ref(msg_len as usize, self.message); + buff_writer.insert_ref(msg_len as usize, self.message.unwrap()); return buff_writer.position; } diff --git a/src/packet/suback_packet.rs b/src/packet/suback_packet.rs index b6e5adc..064c303 100644 --- a/src/packet/suback_packet.rs +++ b/src/packet/suback_packet.rs @@ -53,7 +53,14 @@ impl<'a, const MAX_REASONS: usize, const MAX_PROPERTIES: usize> Packet<'a> for SubackPacket<'a, MAX_REASONS, MAX_PROPERTIES> { fn new() -> Self { - todo!() + Self { + fixed_header: PacketType::Suback.into(), + remain_len: 0, + packet_identifier: 0, + property_len: 0, + properties: Vec::, MAX_PROPERTIES>::new(), + reason_codes: Vec::::new() + } } fn encode(&mut self, buffer: &mut [u8]) -> usize { diff --git a/src/packet/subscription_packet.rs b/src/packet/subscription_packet.rs index 5abfe78..8a63aab 100644 --- a/src/packet/subscription_packet.rs +++ b/src/packet/subscription_packet.rs @@ -32,14 +32,27 @@ pub struct SubscriptionPacket<'a, const MAX_FILTERS: usize, const MAX_PROPERTIES impl<'a, const MAX_FILTERS: usize, const MAX_PROPERTIES: usize> SubscriptionPacket<'a, MAX_FILTERS, MAX_PROPERTIES> { - pub fn new() -> Self { + pub fn add_new_filter(& mut self, topic_name: &'a str) { + let len = topic_name.len(); + let mut new_filter = TopicFilter::new(); + new_filter.filter.string = topic_name; + new_filter.filter.len = len as u16; + self.topic_filters.push(new_filter); + self.topic_filter_len = self.topic_filter_len + 1; + } +} + +impl<'a, const MAX_FILTERS: usize, const MAX_PROPERTIES: usize> Packet<'a> + for SubscriptionPacket<'a, MAX_FILTERS, MAX_PROPERTIES> +{ + fn new() -> Self { let mut x = Self { fixed_header: PacketType::Subscribe.into(), remain_len: 0, packet_identifier: 1, property_len: 0, properties: Vec::, MAX_PROPERTIES>::new(), - topic_filter_len: 1, + topic_filter_len: 0, topic_filters: Vec::, MAX_FILTERS>::new(), }; let mut p = TopicFilter::new(); @@ -48,14 +61,6 @@ impl<'a, const MAX_FILTERS: usize, const MAX_PROPERTIES: usize> x.topic_filters.push(p); return x; } -} - -impl<'a, const MAX_FILTERS: usize, const MAX_PROPERTIES: usize> Packet<'a> - for SubscriptionPacket<'a, MAX_FILTERS, MAX_PROPERTIES> -{ - fn new() -> Self { - todo!() - } fn encode(&mut self, buffer: &mut [u8]) -> usize { let mut buff_writer = BuffWriter::new(buffer); @@ -82,7 +87,7 @@ impl<'a, const MAX_FILTERS: usize, const MAX_PROPERTIES: usize> Packet<'a> buff_writer.write_variable_byte_int(self.property_len); buff_writer.encode_properties::(&self.properties); buff_writer.encode_topic_filters_ref( - false, + true, self.topic_filter_len as usize, &self.topic_filters, ); diff --git a/src/packet/unsubscription_packet.rs b/src/packet/unsubscription_packet.rs index ae7ba7f..8b7e7f0 100644 --- a/src/packet/unsubscription_packet.rs +++ b/src/packet/unsubscription_packet.rs @@ -32,7 +32,6 @@ pub struct UnsubscriptionPacket<'a, const MAX_FILTERS: usize, const MAX_PROPERTI impl<'a, const MAX_FILTERS: usize, const MAX_PROPERTIES: usize> UnsubscriptionPacket<'a, MAX_FILTERS, MAX_PROPERTIES> { - } impl<'a, const MAX_FILTERS: usize, const MAX_PROPERTIES: usize> Packet<'a> diff --git a/src/tokio_network.rs b/src/tokio_network.rs index 9d9fe1d..601d0a5 100644 --- a/src/tokio_network.rs +++ b/src/tokio_network.rs @@ -18,26 +18,36 @@ pub struct TokioNetwork { } impl TokioNetwork { - fn convert_ip(& mut self) -> String { - String::from(format!("{}.{}.{}.{}:{}", self.ip[0], self.ip[1], self.ip[2], self.ip[3], self.port)) + fn convert_ip(&mut self) -> String { + String::from(format!( + "{}.{}.{}.{}:{}", + self.ip[0], self.ip[1], self.ip[2], self.ip[3], self.port + )) } } -impl TokioNetwork { - -} +impl TokioNetwork {} impl Network for TokioNetwork { - type ConnectionFuture<'m> where Self: 'm = impl Future> + 'm; - type WriteFuture<'m> where Self: 'm = impl Future> + 'm; - type ReadFuture<'m> where Self: 'm = impl Future> + 'm; + type ConnectionFuture<'m> + where + Self: 'm, + = impl Future> + 'm; + type WriteFuture<'m> + where + Self: 'm, + = impl Future> + 'm; + type ReadFuture<'m> + where + Self: 'm, + = impl Future> + 'm; fn new(ip: [u8; 4], port: u16) -> Self { return Self { ip, port, socket: Option::None, - } + }; } fn create_connection<'m>(&'m mut self) -> Self::ConnectionFuture<'m> { @@ -48,32 +58,31 @@ impl Network for TokioNetwork { .map(|_| ()) .map_err(|_| NetworkError::Connection) } - } fn send<'m>(&'m mut self, buffer: &'m mut [u8], len: usize) -> Self::WriteFuture<'m> { async move { return if let Some(ref mut stream) = self.socket { - stream.write_all(&buffer[0..len]) + stream + .write_all(&buffer[0..len]) .await .map_err(|_| NetworkError::Unknown) } else { Err(NetworkError::Unknown) - } - + }; } - } fn receive<'m>(&'m mut self, buffer: &'m mut [u8]) -> Self::ReadFuture<'m> { async move { return if let Some(ref mut stream) = self.socket { - stream.read(buffer) + stream + .read(buffer) .await .map_err(|_| NetworkError::Connection) } else { Err(NetworkError::Unknown) - } + }; } } @@ -86,4 +95,4 @@ impl Network for TokioNetwork { let len = self.socket.read(buffer).await ?; Ok(len) }*/ -} \ No newline at end of file +} diff --git a/src/utils/buffer_reader.rs b/src/utils/buffer_reader.rs index 0b8c272..d1a8276 100644 --- a/src/utils/buffer_reader.rs +++ b/src/utils/buffer_reader.rs @@ -150,6 +150,7 @@ impl<'a> BuffReader<'a> { log::error!("Could not parse utf-8 string"); return Err(ParseError::Utf8Error); } + self.increment_position(len_res as usize); return Ok(EncodedString { string: res_str.unwrap(), len: len_res, @@ -188,7 +189,7 @@ impl<'a> BuffReader<'a> { }); } - pub fn read_message(&mut self) -> &'a [u8] { - return &self.buffer[self.position..]; + pub fn read_message(&mut self, total_len: usize) -> &'a [u8] { + return &self.buffer[self.position..total_len]; } } diff --git a/src/utils/buffer_writer.rs b/src/utils/buffer_writer.rs index 162821e..3d0bc8c 100644 --- a/src/utils/buffer_writer.rs +++ b/src/utils/buffer_writer.rs @@ -49,7 +49,7 @@ impl<'a> BuffWriter<'a> { pub fn write_u32(&mut self, four_bytes: u32) { let bytes: [u8; 4] = four_bytes.to_be_bytes(); - self.insert_ref(4,&bytes); + self.insert_ref(4, &bytes); } pub fn write_string_ref(&mut self, str: &EncodedString<'a>) { From 4eaa83bf1cf16a3ac4f0d4adc47df34670f31df4 Mon Sep 17 00:00:00 2001 From: Ondrej Babec Date: Sun, 27 Feb 2022 15:48:09 +0100 Subject: [PATCH 09/10] Error handling --- src/client/client_config.rs | 42 +++++++ src/client/client_v5.rs | 72 +++++++++-- src/client/mod.rs | 1 + src/main.rs | 38 ++++-- src/network/network_trait.rs | 3 + src/packet/connect_packet.rs | 28 +++-- src/packet/mod.rs | 1 + src/packet/puback_packet.rs | 20 ++- src/packet/publish_packet.rs | 19 ++- src/packet/reason_codes.rs | 202 ++++++++++++++++++++++++++++++ src/packet/subscription_packet.rs | 8 +- src/utils/buffer_reader.rs | 2 + src/utils/mod.rs | 1 + src/utils/rng_generator.rs | 25 ++++ 14 files changed, 421 insertions(+), 41 deletions(-) create mode 100644 src/client/client_config.rs create mode 100644 src/packet/reason_codes.rs create mode 100644 src/utils/rng_generator.rs diff --git a/src/client/client_config.rs b/src/client/client_config.rs new file mode 100644 index 0000000..21b21dc --- /dev/null +++ b/src/client/client_config.rs @@ -0,0 +1,42 @@ +use crate::packet::publish_packet::QualityOfService; +use crate::utils::buffer_reader::{BinaryData, EncodedString}; + +pub struct ClientConfig<'a> { + pub qos: QualityOfService, + pub username_flag: bool, + pub username: EncodedString<'a>, + pub password_flag: bool, + pub password: BinaryData<'a> +} + +impl ClientConfig<'a> { + pub fn new() -> Self { + Self { + qos: QualityOfService::QoS0, + username_flag: false, + username: EncodedString::new(), + password_flag: false, + password: BinaryData::new(), + } + } + + pub fn add_qos(& mut self, qos: QualityOfService) { + self.qos = qos; + } + + pub fn add_username(& mut self, username: &'a str) { + let mut username_s: EncodedString = EncodedString::new(); + username_s.string = username; + username_s.len = username.len() as u16; + self.username_flag = true; + self.username = username_s; + } + + pub fn add_password(& mut self, password: &'a str) { + let mut password_s: BinaryData = BinaryData::new(); + password_s.bin = password.as_bytes(); + password_s.len = password_s.bin.len() as u16; + self.password = password_s; + self.password_flag = true; + } +} \ No newline at end of file diff --git a/src/client/client_v5.rs b/src/client/client_v5.rs index eae67f9..937492c 100644 --- a/src/client/client_v5.rs +++ b/src/client/client_v5.rs @@ -1,35 +1,52 @@ use core::future::Future; +use embassy::traits::rng; +use rand_core::RngCore; +use crate::client::client_config::ClientConfig; use crate::network::network_trait::{Network, NetworkError}; use crate::packet::connack_packet::ConnackPacket; use crate::packet::connect_packet::ConnectPacket; use crate::packet::disconnect_packet::DisconnectPacket; use crate::packet::mqtt_packet::Packet; +use crate::packet::puback_packet::PubackPacket; use crate::packet::publish_packet::QualityOfService::QoS1; use crate::packet::publish_packet::{PublishPacket, QualityOfService}; use crate::packet::suback_packet::SubackPacket; use crate::packet::subscription_packet::SubscriptionPacket; use crate::utils::buffer_reader::BuffReader; +use crate::utils::rng_generator::CountingRng; pub struct MqttClientV5<'a, T, const MAX_PROPERTIES: usize> { network_driver: &'a mut T, buffer: &'a mut [u8], + recv_buffer: &'a mut [u8], + rng: CountingRng, + config: ClientConfig<'a>, } impl<'a, T, const MAX_PROPERTIES: usize> MqttClientV5<'a, T, MAX_PROPERTIES> where T: Network, { - pub fn new(network_driver: &'a mut T, buffer: &'a mut [u8]) -> Self { + pub fn new(network_driver: &'a mut T, buffer: &'a mut [u8], recv_buffer: &'a mut [u8], config: ClientConfig<'a>) -> Self { Self { network_driver, buffer, + recv_buffer, + rng: CountingRng(50), + config } } pub async fn connect_to_broker<'b>(&'b mut self) -> Result<(), NetworkError> { let mut len = { let mut connect = ConnectPacket::<'b, 3, 0>::clean(); + if self.config.username_flag { + connect.add_username(& self.config.username); + } + if self.config.password_flag { + connect.add_password(& self.config.password) + } connect.encode(self.buffer) }; @@ -58,35 +75,55 @@ where Ok(()) } - - // connect -> connack -> publish -> QoS ? -> disconn pub async fn send_message<'b>( &'b mut self, topic_name: &'b str, message: &'b str, - qos: QualityOfService, ) -> Result<(), NetworkError> { - // publish + + let identifier: u16 = self.rng.next_u32() as u16; let len = { let mut packet = PublishPacket::<'b, 5>::new(); packet.add_topic_name(topic_name); + packet.add_qos(self.config.qos); + packet.add_identifier(identifier); packet.add_message(message.as_bytes()); packet.encode(self.buffer) }; - self.network_driver.send(self.buffer, len).await?; + let x = self.network_driver.send(self.buffer, len).await; + + if let Err(e) = x { + log::error!("Chyba pri prenosu!"); + return Err(e); + } //QoS1 - if >::into(qos) == >::into(QoS1) { - todo!(); + if >::into(self.config.qos ) == >::into(QoS1) { + let reason = { + self.network_driver.receive(self.buffer).await?; + let mut packet = PubackPacket::<'b, 5>::new(); + packet.decode(&mut BuffReader::new(self.buffer)); + [packet.packet_identifier, packet.reason_code as u16] + }; + + if identifier != reason[0] { + return Err(NetworkError::IDNotMatchedOnAck); + } + + if reason[1] != 0 { + return Err(NetworkError::QoSAck); + } } Ok(()) } + // TODO - multiple topic subscribe func + pub async fn subscribe_to_topic<'b>(&'b mut self, topic_name: &'b str) -> Result<(), NetworkError> { let len = { let mut subs = SubscriptionPacket::<'b, 1, 1>::new(); - subs.add_new_filter(topic_name); + subs.add_new_filter(topic_name, self.config.qos); subs.encode(self.buffer) }; let xx: [u8; 14] = (self.buffer[0..14]).try_into().unwrap(); @@ -100,7 +137,7 @@ where *packet.reason_codes.get(0).unwrap() }; - if reason > 1 { + if reason == (>::into(self.config.qos) >> 1) { Err(NetworkError::Unknown) } else { Ok(()) @@ -109,9 +146,20 @@ where } pub async fn receive_message<'b>(&'b mut self) -> Result<&'b [u8], NetworkError> { - self.network_driver.receive(self.buffer).await?; + self.network_driver.receive(self.recv_buffer).await?; let mut packet = PublishPacket::<'b, 5>::new(); - packet.decode(&mut BuffReader::new(self.buffer)); + packet.decode(&mut BuffReader::new(self.recv_buffer)); + + if (packet.fixed_header & 0x06) == >::into(QualityOfService::QoS1) { + let mut puback = PubackPacket::<'b, 5>::new(); + puback.packet_identifier = packet.packet_identifier; + puback.reason_code = 0x00; + { + let len = puback.encode(self.buffer); + self.network_driver.send(self.buffer, len).await ?; + } + } + return Ok(packet.message.unwrap()); } } diff --git a/src/client/mod.rs b/src/client/mod.rs index 3f271f3..c047371 100644 --- a/src/client/mod.rs +++ b/src/client/mod.rs @@ -1 +1,2 @@ pub mod client_v5; +pub mod client_config; diff --git a/src/main.rs b/src/main.rs index 9c18a55..824dc28 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,20 +8,27 @@ use rust_mqtt::tokio_network::TokioNetwork; use std::time::Duration; use tokio::time::sleep; use tokio::{join, task}; +use rust_mqtt::client::client_config::ClientConfig; +use rust_mqtt::packet::publish_packet::QualityOfService::QoS1; async fn receive() { let mut ip: [u8; 4] = [37, 205, 11, 180]; let mut port: u16 = 1883; let mut tokio_network: TokioNetwork = TokioNetwork::new(ip, port); tokio_network.create_connection().await; + let mut config = ClientConfig::new(); + config.add_qos(QualityOfService::QoS1); + config.add_username("test"); + config.add_password("testPass"); let mut res2 = vec![0; 260]; - let mut client = MqttClientV5::::new(&mut tokio_network, &mut res2); + let mut res3 = vec![0; 260]; + let mut client = MqttClientV5::::new(&mut tokio_network, &mut res2, & mut res3, config); let mut result = { client.connect_to_broker().await }; { client.subscribe_to_topic("test/topic").await; - } + }; { log::info!("Waiting for new message!"); let mes = client.receive_message().await.unwrap(); @@ -38,18 +45,33 @@ async fn publish(message: &str) { let mut port: u16 = 1883; let mut tokio_network: TokioNetwork = TokioNetwork::new(ip, port); tokio_network.create_connection().await; + let config = ClientConfig::new(); let mut res2 = vec![0; 260]; - let mut client = MqttClientV5::::new(&mut tokio_network, &mut res2); + let mut res3 = vec![0; 260]; + let mut client = MqttClientV5::::new(&mut tokio_network, &mut res2, & mut res3, config); let mut result = { client.connect_to_broker().await }; log::info!("Waiting until send!"); sleep(Duration::from_secs(15)); - let mut result: Result<(), NetworkError> = { + result= { log::info!("Sending new message!"); client - .send_message("test/topic", message, QualityOfService::QoS0) + .send_message("test/topic", message) .await }; + if let Err(e) = result { + log::error!("Chyba!"); + } + + result = { + log::info!("Sending new message!"); + client + .send_message("test/topic", "Dalsi zprava :)") + .await + }; + if let Err(err) = result { + log::error!("Chyba!"); + } { client.disconnect().await; @@ -63,7 +85,7 @@ async fn main() { .format_timestamp_nanos() .init(); - let recv = task::spawn(async move { + /*let recv = task::spawn(async move { receive().await; }); @@ -71,6 +93,8 @@ async fn main() { publish("hello world 123 !").await; }); - join!(recv, publ); + join!(recv, publ);*/ + receive().await; + //publish("Ahoj 123").await; log::info!("Done"); } diff --git a/src/network/network_trait.rs b/src/network/network_trait.rs index b446bc3..3466a3f 100644 --- a/src/network/network_trait.rs +++ b/src/network/network_trait.rs @@ -8,6 +8,9 @@ use crate::packet::mqtt_packet::Packet; pub enum NetworkError { Connection, Unknown, + QoSAck, + IDNotMatchedOnAck, + NoMatchingSubs, } pub trait Network { diff --git a/src/packet/connect_packet.rs b/src/packet/connect_packet.rs index 7a38449..1845d3b 100644 --- a/src/packet/connect_packet.rs +++ b/src/packet/connect_packet.rs @@ -97,6 +97,16 @@ impl<'a, const MAX_PROPERTIES: usize, const MAX_WILL_PROPERTIES: usize> } self.fixed_header = cur_type | flags; } + + pub fn add_username(&mut self, username: &EncodedString<'a>) { + self.username = (*username).clone(); + self.connect_flags = self.connect_flags | 0x80; + } + + pub fn add_password(&mut self, password: &BinaryData<'a>) { + self.password = (*password).clone(); + self.connect_flags = self.connect_flags | 0x40; + } } impl<'a, const MAX_PROPERTIES: usize, const MAX_WILL_PROPERTIES: usize> Packet<'a> @@ -116,7 +126,7 @@ impl<'a, const MAX_PROPERTIES: usize, const MAX_WILL_PROPERTIES: usize> Packet<' // 12 = protocol_name_len + protocol_name + protocol_version + connect_flags + keep_alive + client_id_len rm_ln = rm_ln + property_len_len as u32 + 12; - if self.connect_flags & 0x04 == 1 { + if self.connect_flags & 0x04 != 0 { let wil_prop_len_enc = VariableByteIntegerEncoder::encode(self.will_property_len).unwrap(); let wil_prop_len_len = VariableByteIntegerEncoder::len(wil_prop_len_enc); @@ -126,13 +136,13 @@ impl<'a, const MAX_PROPERTIES: usize, const MAX_WILL_PROPERTIES: usize> Packet<' + self.will_topic.len as u32 + self.will_payload.len as u32; } - - if self.connect_flags & 0x80 == 1 { - rm_ln = rm_ln + self.username.len as u32; + let x = self.connect_flags & 0x80; + if (self.connect_flags & 0x80) != 0 { + rm_ln = rm_ln + self.username.len as u32 + 2; } - if self.connect_flags & 0x40 == 1 { - rm_ln = rm_ln + self.password.len as u32; + if self.connect_flags & 0x40 != 0 { + rm_ln = rm_ln + self.password.len as u32 + 2; } buff_writer.write_u8(self.fixed_header); @@ -147,18 +157,18 @@ impl<'a, const MAX_PROPERTIES: usize, const MAX_WILL_PROPERTIES: usize> Packet<' buff_writer.encode_properties::(&self.properties); buff_writer.write_string_ref(&self.client_id); - if self.connect_flags & 0x04 == 1 { + if self.connect_flags & 0x04 != 0 { buff_writer.write_variable_byte_int(self.will_property_len); buff_writer.encode_properties(&self.will_properties); buff_writer.write_string_ref(&self.will_topic); buff_writer.write_binary_ref(&self.will_payload); } - if self.connect_flags & 0x80 == 1 { + if self.connect_flags & 0x80 != 0 { buff_writer.write_string_ref(&self.username); } - if self.connect_flags & 0x40 == 1 { + if self.connect_flags & 0x40 != 0 { buff_writer.write_binary_ref(&self.password); } diff --git a/src/packet/mod.rs b/src/packet/mod.rs index f76a034..2b75c1d 100644 --- a/src/packet/mod.rs +++ b/src/packet/mod.rs @@ -18,3 +18,4 @@ pub mod pingreq_packet; pub mod pingresp_packet; pub mod suback_packet; pub mod unsuback_packet; +pub mod reason_codes; diff --git a/src/packet/puback_packet.rs b/src/packet/puback_packet.rs index 9a51b85..d3a2705 100644 --- a/src/packet/puback_packet.rs +++ b/src/packet/puback_packet.rs @@ -30,14 +30,28 @@ impl<'a, const MAX_PROPERTIES: usize> PubackPacket<'a, MAX_PROPERTIES> { return; } self.packet_identifier = buff_reader.read_u16().unwrap(); - self.reason_code = buff_reader.read_u8().unwrap(); - self.decode_properties(buff_reader); + if self.remain_len != 2 { + self.reason_code = buff_reader.read_u8().unwrap(); + } + if self.remain_len < 4 { + self.property_len = 0; + } else { + self.decode_properties(buff_reader); + } + } } impl<'a, const MAX_PROPERTIES: usize> Packet<'a> for PubackPacket<'a, MAX_PROPERTIES> { fn new() -> Self { - todo!() + Self { + fixed_header: PacketType::Puback.into(), + remain_len: 0, + packet_identifier: 0, + reason_code: 0, + property_len: 0, + properties: Vec::, MAX_PROPERTIES>::new() + } } fn encode(&mut self, buffer: &mut [u8]) -> usize { diff --git a/src/packet/publish_packet.rs b/src/packet/publish_packet.rs index 3f4ed21..99ec544 100644 --- a/src/packet/publish_packet.rs +++ b/src/packet/publish_packet.rs @@ -11,6 +11,7 @@ use crate::utils::buffer_writer::BuffWriter; use super::packet_type::PacketType; use super::property::Property; +#[derive(Clone, Copy)] pub enum QualityOfService { QoS0, QoS1, @@ -22,8 +23,8 @@ impl From for QualityOfService { fn from(orig: u8) -> Self { return match orig { 0 => QoS0, - 1 => QoS1, - 2 => QoS2, + 2 => QoS1, + 4 => QoS2, _ => INVALID, }; } @@ -33,8 +34,8 @@ impl Into for QualityOfService { fn into(self) -> u8 { return match self { QoS0 => 0, - QoS1 => 1, - QoS2 => 2, + QoS1 => 2, + QoS2 => 4, INVALID => 3, }; } @@ -67,6 +68,14 @@ impl<'a, const MAX_PROPERTIES: usize> PublishPacket<'a, MAX_PROPERTIES> { self.message = Some(message); } + pub fn add_qos(& mut self, qos: QualityOfService) { + self.fixed_header = self.fixed_header | >::into(qos); + } + + pub fn add_identifier(& mut self, identifier: u16) { + self.packet_identifier = identifier; + } + pub fn decode_publish_packet(&mut self, buff_reader: &mut BuffReader<'a>) { if self.decode_fixed_header(buff_reader) != (PacketType::Publish).into() { log::error!("Packet you are trying to decode is not PUBLISH packet!"); @@ -112,7 +121,7 @@ impl<'a, const MAX_PROPERTIES: usize> Packet<'a> for PublishPacket<'a, MAX_PROPE buff_writer.write_u8(self.fixed_header); let qos = self.fixed_header & 0x03; if qos != 0 { - rm_ln + 2; + rm_ln = rm_ln + 2; } buff_writer.write_variable_byte_int(rm_ln); diff --git a/src/packet/reason_codes.rs b/src/packet/reason_codes.rs new file mode 100644 index 0000000..22a54f1 --- /dev/null +++ b/src/packet/reason_codes.rs @@ -0,0 +1,202 @@ +use core::fmt::{Display, Formatter, write}; +use crate::packet::reason_codes::ReasonCode::ServerMoved; + +pub enum ReasonCode { + Success, + GrantedQoS1, + GrantedQoS2, + DisconnectWithWillMessage, + NoMatchingSubscribers, + NoSubscriptionExisted, + ContinueAuth, + ReAuthenticate, + UnspecifiedError, + MalformedPacket, + ProtocolError, + ImplementationSpecificError, + UnsupportedProtocolVersion, + ClientIdNotValid, + BadUserNameOrPassword, + NotAuthorized, + ServerUnavailable, + ServerBusy, + Banned, + ServerShuttingDown, + BadAuthMethod, + KeepAliveTimeout, + SessionTakeOver, + TopicFilterInvalid, + TopicNameInvalid, + PacketIdentifierInUse, + PacketIdentifierNotFound, + ReceiveMaximumExceeded, + TopicAliasInvalid, + PacketTooLarge, + MessageRateTooHigh, + QuotaExceeded, + AdministrativeAction, + PayloadFormatInvalid, + RetainNotSupported, + QoSNotSupported, + UseAnotherServer, + ServerMoved, + SharedSubscriptionNotSupported, + ConnectionRateExceeded, + MaximumConnectTime, + SubscriptionIdentifiersNotSupported, + WildcardSubscriptionNotSupported, + Unknown +} + +impl Into for ReasonCode { + fn into(self) -> u8 { + return match self { + ReasonCode::Success => 0x00, + ReasonCode::GrantedQoS1 => 0x01, + ReasonCode::GrantedQoS2 => 0x02, + ReasonCode::DisconnectWithWillMessage => 0x04, + ReasonCode::NoMatchingSubscribers => 0x10, + ReasonCode::NoSubscriptionExisted => 0x11, + ReasonCode::ContinueAuth => 0x18, + ReasonCode::ReAuthenticate => 0x19, + ReasonCode::UnspecifiedError => 0x80, + ReasonCode::MalformedPacket => 0x81, + ReasonCode::ProtocolError => 0x82, + ReasonCode::ImplementationSpecificError => 0x83, + ReasonCode::UnsupportedProtocolVersion => 0x84, + ReasonCode::ClientIdNotValid => 0x85, + ReasonCode::BadUserNameOrPassword => 0x86, + ReasonCode::NotAuthorized => 0x87, + ReasonCode::ServerUnavailable => 0x88, + ReasonCode::ServerBusy => 0x89, + ReasonCode::Banned => 0x8A, + ReasonCode::ServerShuttingDown => 0x8B, + ReasonCode::BadAuthMethod => 0x8C, + ReasonCode::KeepAliveTimeout => 0x8D, + ReasonCode::SessionTakeOver => 0x8E, + ReasonCode::TopicFilterInvalid => 0x8F, + ReasonCode::TopicNameInvalid => 0x90, + ReasonCode::PacketIdentifierInUse => 0x91, + ReasonCode::PacketIdentifierNotFound => 0x92, + ReasonCode::ReceiveMaximumExceeded => 0x93, + ReasonCode::TopicAliasInvalid => 0x94, + ReasonCode::PacketTooLarge => 0x95, + ReasonCode::MessageRateTooHigh => 0x96, + ReasonCode::QuotaExceeded => 0x97, + ReasonCode::AdministrativeAction => 0x98, + ReasonCode::PayloadFormatInvalid => 0x99, + ReasonCode::RetainNotSupported => 0x9A, + ReasonCode::QoSNotSupported => 0x9B, + ReasonCode::UseAnotherServer => 0x9C, + ReasonCode::ServerMoved => 0x9D, + ReasonCode::SharedSubscriptionNotSupported => 0x9E, + ReasonCode::ConnectionRateExceeded => 0x9F, + ReasonCode::MaximumConnectTime => 0xA0, + ReasonCode::SubscriptionIdentifiersNotSupported => 0xA1, + ReasonCode::WildcardSubscriptionNotSupported => 0xA2, + ReasonCode::Unknown => 0xFF + } + + } +} + +impl From for ReasonCode { + fn from(orig: u8) -> Self { + return match orig { + 0x00 => ReasonCode::Success, + 0x01 => ReasonCode::GrantedQoS1, + 0x02 => ReasonCode::GrantedQoS2, + 0x04 => ReasonCode::DisconnectWithWillMessage, + 0x10 => ReasonCode::NoMatchingSubscribers, + 0x11 => ReasonCode::NoSubscriptionExisted, + 0x18 => ReasonCode::ContinueAuth, + 0x19 => ReasonCode::ReAuthenticate, + 0x80 => ReasonCode::UnspecifiedError, + 0x81 => ReasonCode::MalformedPacket, + 0x82 => ReasonCode::ProtocolError, + 0x83 => ReasonCode::ImplementationSpecificError, + 0x84 => ReasonCode::UnsupportedProtocolVersion, + 0x85 => ReasonCode::ClientIdNotValid, + 0x86 => ReasonCode::BadUserNameOrPassword, + 0x87 => ReasonCode::NotAuthorized, + 0x88 => ReasonCode::ServerUnavailable, + 0x89 => ReasonCode::ServerBusy, + 0x8A => ReasonCode::Banned, + 0x8B => ReasonCode::ServerShuttingDown, + 0x8C => ReasonCode::BadAuthMethod, + 0x8D => ReasonCode::KeepAliveTimeout, + 0x8E => ReasonCode::SessionTakeOver, + 0x8F => ReasonCode::TopicFilterInvalid, + 0x90 => ReasonCode::TopicNameInvalid, + 0x91 => ReasonCode::PacketIdentifierInUse, + 0x92 => ReasonCode::PacketIdentifierNotFound, + 0x93 => ReasonCode::ReceiveMaximumExceeded, + 0x94 => ReasonCode::TopicAliasInvalid, + 0x95 => ReasonCode::PacketTooLarge, + 0x96 => ReasonCode::MessageRateTooHigh, + 0x97 => ReasonCode::QuotaExceeded, + 0x98 => ReasonCode::AdministrativeAction, + 0x99 => ReasonCode::PayloadFormatInvalid, + 0x9A => ReasonCode::RetainNotSupported, + 0x9B => ReasonCode::QoSNotSupported, + 0x9C => ReasonCode::UseAnotherServer, + 0x9D => ReasonCode::ServerMoved, + 0x9E => ReasonCode::SharedSubscriptionNotSupported, + 0xA0 => ReasonCode::MaximumConnectTime, + 0xA1 => ReasonCode::SubscriptionIdentifiersNotSupported, + 0xA2 => ReasonCode::WildcardSubscriptionNotSupported, + _ => ReasonCode::Unknown + } + } +} + +impl Display for ReasonCode { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + match *self { + ReasonCode::Success => write!(f, "Operation was successful!"), + ReasonCode::GrantedQoS1 => write!(f, "Granted QoS level 1!"), + ReasonCode::GrantedQoS2 => write!(f, "Granted QoS level 2!"), + ReasonCode::DisconnectWithWillMessage => {} + ReasonCode::NoMatchingSubscribers => write!(f, "No matching subscribers on broker!"), + ReasonCode::NoSubscriptionExisted => write!(f, "Subscription not exist!"), + ReasonCode::ContinueAuth => write!(f, "Broker asks for more AUTH packets!"), + ReasonCode::ReAuthenticate => write!(f, "Broker requires re-authentication!"), + ReasonCode::UnspecifiedError => write!(f, "Unspecified error!"), + ReasonCode::MalformedPacket => write!(f, "Malformed packet sent!"), + ReasonCode::ProtocolError => write!(f, "Protocol specific error!"), + ReasonCode::ImplementationSpecificError => write!(f, "Implementation specific error!"), + ReasonCode::UnsupportedProtocolVersion => write!(f, "Unsupported protocol version!"), + ReasonCode::ClientIdNotValid => write!(f, "Client sent not valid identification"), + ReasonCode::BadUserNameOrPassword => write!(f, "Authentication error, username of password not valid!"), + ReasonCode::NotAuthorized => write!(f, "Client not authorized!"), + ReasonCode::ServerUnavailable => write!(f, "Server unavailable!"), + ReasonCode::ServerBusy => write!(f, "Server is busy!"), + ReasonCode::Banned => write!(f, "Client is banned on broker!"), + ReasonCode::ServerShuttingDown => write!(f, "Server is shutting down!"), + ReasonCode::BadAuthMethod => write!(f, "Provided bad authentication method!"), + ReasonCode::KeepAliveTimeout => write!(f, "Client reached timeout"), + ReasonCode::SessionTakeOver => write!(f, "Took over session!"), + ReasonCode::TopicFilterInvalid => write!(f, "Topic filter is not valid!"), + ReasonCode::TopicNameInvalid => write!(f, "Topic name is not valid!"), + ReasonCode::PacketIdentifierInUse => write!(f, "Packet identifier is already in use!"), + ReasonCode::PacketIdentifierNotFound => write!(f, "Packet identifier not found!"), + ReasonCode::ReceiveMaximumExceeded => write!(f, "Maximum receive amount exceeded!"), + ReasonCode::TopicAliasInvalid => write!(f, "Invalid topic alias!"), + ReasonCode::PacketTooLarge => write!(f, "Sent packet was too large!"), + ReasonCode::MessageRateTooHigh => write!(f, "Message rate is too high!"), + ReasonCode::QuotaExceeded => write!(f, "Quota exceeded!"), + ReasonCode::AdministrativeAction => write!(f, "Administrative action!"), + ReasonCode::PayloadFormatInvalid => write!(f, "Invalid payload format!"), + ReasonCode::RetainNotSupported => write!(f, "Message retain not supported!"), + ReasonCode::QoSNotSupported => write!(f, "Used QoS is not supported!"), + ReasonCode::UseAnotherServer => write!(f, "Use another server!"), + ReasonCode::ServerMoved => write!(f, "Server moved!"), + ReasonCode::SharedSubscriptionNotSupported => write!(f, "Shared subscription is not supported"), + ReasonCode::ConnectionRateExceeded => write!(f, "Connection rate exceeded!"), + ReasonCode::MaximumConnectTime => write!(f, "Maximum connect time exceeded!"), + ReasonCode::SubscriptionIdentifiersNotSupported => write!(f, "Subscription identifier not supported!"), + ReasonCode::WildcardSubscriptionNotSupported => write!(f, "Wildcard subscription not supported!"), + ReasonCode::Unknown => write!(f, "Unknown error!"), + } + } +} \ No newline at end of file diff --git a/src/packet/subscription_packet.rs b/src/packet/subscription_packet.rs index 8a63aab..d396035 100644 --- a/src/packet/subscription_packet.rs +++ b/src/packet/subscription_packet.rs @@ -2,6 +2,7 @@ use heapless::Vec; use crate::encoding::variable_byte_integer::VariableByteIntegerEncoder; use crate::packet::mqtt_packet::Packet; +use crate::packet::publish_packet::QualityOfService; use crate::utils::buffer_reader::BuffReader; use crate::utils::buffer_reader::TopicFilter; use crate::utils::buffer_writer::BuffWriter; @@ -32,11 +33,12 @@ pub struct SubscriptionPacket<'a, const MAX_FILTERS: usize, const MAX_PROPERTIES impl<'a, const MAX_FILTERS: usize, const MAX_PROPERTIES: usize> SubscriptionPacket<'a, MAX_FILTERS, MAX_PROPERTIES> { - pub fn add_new_filter(& mut self, topic_name: &'a str) { + pub fn add_new_filter(& mut self, topic_name: &'a str, qos: QualityOfService) { let len = topic_name.len(); let mut new_filter = TopicFilter::new(); new_filter.filter.string = topic_name; new_filter.filter.len = len as u16; + new_filter.sub_options = new_filter.sub_options | (>::into(qos) >> 1); self.topic_filters.push(new_filter); self.topic_filter_len = self.topic_filter_len + 1; } @@ -55,10 +57,6 @@ impl<'a, const MAX_FILTERS: usize, const MAX_PROPERTIES: usize> Packet<'a> topic_filter_len: 0, topic_filters: Vec::, MAX_FILTERS>::new(), }; - let mut p = TopicFilter::new(); - p.filter.len = 6; - p.filter.string = "test/#"; - x.topic_filters.push(p); return x; } diff --git a/src/utils/buffer_reader.rs b/src/utils/buffer_reader.rs index d1a8276..6dc2c46 100644 --- a/src/utils/buffer_reader.rs +++ b/src/utils/buffer_reader.rs @@ -4,6 +4,7 @@ use core::str; use crate::encoding::variable_byte_integer::VariableByteIntegerDecoder; #[derive(Debug)] +#[derive(Clone)] pub struct EncodedString<'a> { pub string: &'a str, pub len: u16, @@ -20,6 +21,7 @@ impl EncodedString<'_> { } #[derive(Debug)] +#[derive(Clone)] pub struct BinaryData<'a> { pub bin: &'a [u8], pub len: u16, diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 7f6b1dc..3e38d69 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -1,2 +1,3 @@ pub mod buffer_reader; pub mod buffer_writer; +pub mod rng_generator; diff --git a/src/utils/rng_generator.rs b/src/utils/rng_generator.rs new file mode 100644 index 0000000..9d98c42 --- /dev/null +++ b/src/utils/rng_generator.rs @@ -0,0 +1,25 @@ +use rand_core::{RngCore, Error, impls}; + +pub struct CountingRng(pub u64); + +impl RngCore for CountingRng { + fn next_u32(&mut self) -> u32 { + self.next_u64() as u32 + } + + fn next_u64(&mut self) -> u64 { + self.0 += 1; + if self.0 > u16::MAX as u64 { + self.0 = 1; + } + self.0 + } + + fn fill_bytes(&mut self, dest: &mut [u8]) { + impls::fill_bytes_via_next(self, dest) + } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + Ok(self.fill_bytes(dest)) + } +} \ No newline at end of file From 80c0e25eda01f7987a0a4025fbde64133b6d519e Mon Sep 17 00:00:00 2001 From: Ondrej Babec Date: Sun, 27 Feb 2022 19:40:00 +0100 Subject: [PATCH 10/10] Add licences --- LICENSE | 695 +------------------------- src/client/client_config.rs | 25 + src/client/client_v5.rs | 43 +- src/client/mod.rs | 25 + src/encoding/mod.rs | 25 + src/encoding/variable_byte_integer.rs | 24 + src/lib.rs | 52 +- src/main.rs | 10 +- src/network/mod.rs | 25 + src/network/network_trait.rs | 8 +- src/packet/auth_packet.rs | 44 +- src/packet/connack_packet.rs | 24 + src/packet/connect_packet.rs | 24 + src/packet/disconnect_packet.rs | 24 + src/packet/mod.rs | 25 +- src/packet/mqtt_packet.rs | 44 +- src/packet/packet_type.rs | 24 + src/packet/pingreq_packet.rs | 24 + src/packet/pingresp_packet.rs | 24 + src/packet/property.rs | 24 + src/packet/puback_packet.rs | 24 + src/packet/pubcomp_packet.rs | 24 + src/packet/publish_packet.rs | 24 + src/packet/pubrec_packet.rs | 24 + src/packet/pubrel_packet.rs | 24 + src/packet/reason_codes.rs | 11 +- src/packet/suback_packet.rs | 24 + src/packet/subscription_packet.rs | 24 + src/packet/unsuback_packet.rs | 24 + src/packet/unsubscription_packet.rs | 24 + src/tokio_network.rs | 29 +- src/utils/buffer_reader.rs | 49 +- src/utils/buffer_writer.rs | 24 + src/utils/mod.rs | 24 + src/utils/rng_generator.rs | 3 + 35 files changed, 792 insertions(+), 777 deletions(-) diff --git a/LICENSE b/LICENSE index a824681..dc695c4 100644 --- a/LICENSE +++ b/LICENSE @@ -1,674 +1,21 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer Network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a Network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a Network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -Network may be denied when the modification itself materially and -adversely affects the operation of the Network or violates the rules and -protocols for communication across the Network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available Network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a Network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. +MIT License + +Copyright (c) [2022] [Ondrej Babec ] + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/src/client/client_config.rs b/src/client/client_config.rs index 21b21dc..8430e6e 100644 --- a/src/client/client_config.rs +++ b/src/client/client_config.rs @@ -1,3 +1,28 @@ +/* + * MIT License + * + * Copyright (c) [2022] [Ondrej Babec ] + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + + use crate::packet::publish_packet::QualityOfService; use crate::utils::buffer_reader::{BinaryData, EncodedString}; diff --git a/src/client/client_v5.rs b/src/client/client_v5.rs index 937492c..23638d9 100644 --- a/src/client/client_v5.rs +++ b/src/client/client_v5.rs @@ -11,6 +11,7 @@ use crate::packet::mqtt_packet::Packet; use crate::packet::puback_packet::PubackPacket; use crate::packet::publish_packet::QualityOfService::QoS1; use crate::packet::publish_packet::{PublishPacket, QualityOfService}; +use crate::packet::reason_codes::ReasonCode; use crate::packet::suback_packet::SubackPacket; use crate::packet::subscription_packet::SubscriptionPacket; use crate::utils::buffer_reader::BuffReader; @@ -38,7 +39,7 @@ where } } - pub async fn connect_to_broker<'b>(&'b mut self) -> Result<(), NetworkError> { + pub async fn connect_to_broker<'b>(&'b mut self) -> Result<(), ReasonCode> { let mut len = { let mut connect = ConnectPacket::<'b, 3, 0>::clean(); if self.config.username_flag { @@ -50,7 +51,7 @@ where connect.encode(self.buffer) }; - self.network_driver.send(self.buffer, len).await?; + self.network_driver.send(self.buffer, len).await ?; //connack let reason: u8 = { @@ -61,14 +62,14 @@ where }; if reason != 0x00 { - Err(NetworkError::Connection) + return Err(ReasonCode::from(reason)); } else { Ok(()) } } - pub async fn disconnect<'b>(&'b mut self) -> Result<(), NetworkError> { + pub async fn disconnect<'b>(&'b mut self) -> Result<(), ReasonCode> { let mut disconnect = DisconnectPacket::<'b, 5>::new(); let mut len = disconnect.encode(self.buffer); self.network_driver.send(self.buffer, len).await?; @@ -79,7 +80,7 @@ where &'b mut self, topic_name: &'b str, message: &'b str, - ) -> Result<(), NetworkError> { + ) -> Result<(), ReasonCode> { let identifier: u16 = self.rng.next_u32() as u16; let len = { @@ -91,62 +92,58 @@ where packet.encode(self.buffer) }; - let x = self.network_driver.send(self.buffer, len).await; + self.network_driver.send(self.buffer, len).await ?; - if let Err(e) = x { - log::error!("Chyba pri prenosu!"); - return Err(e); - } //QoS1 if >::into(self.config.qos ) == >::into(QoS1) { let reason = { - self.network_driver.receive(self.buffer).await?; + self.network_driver.receive(self.buffer).await ?; let mut packet = PubackPacket::<'b, 5>::new(); packet.decode(&mut BuffReader::new(self.buffer)); [packet.packet_identifier, packet.reason_code as u16] }; if identifier != reason[0] { - return Err(NetworkError::IDNotMatchedOnAck); + return Err(ReasonCode::PacketIdentifierNotFound); } if reason[1] != 0 { - return Err(NetworkError::QoSAck); + return Err(ReasonCode::from(reason[1] as u8)); } } Ok(()) } // TODO - multiple topic subscribe func - - pub async fn subscribe_to_topic<'b>(&'b mut self, topic_name: &'b str) -> Result<(), NetworkError> { + + pub async fn subscribe_to_topic<'b>(&'b mut self, topic_name: &'b str) -> Result<(), ReasonCode> { let len = { let mut subs = SubscriptionPacket::<'b, 1, 1>::new(); subs.add_new_filter(topic_name, self.config.qos); subs.encode(self.buffer) }; - let xx: [u8; 14] = (self.buffer[0..14]).try_into().unwrap(); - log::info!("{:x?}", xx); - self.network_driver.send(self.buffer, len).await?; + + self.network_driver.send(self.buffer, len).await ?; let reason = { - self.network_driver.receive(self.buffer).await?; + self.network_driver.receive(self.buffer).await ?; + let mut packet = SubackPacket::<'b, 5, 5>::new(); packet.decode(&mut BuffReader::new(self.buffer)); *packet.reason_codes.get(0).unwrap() }; - if reason == (>::into(self.config.qos) >> 1) { - Err(NetworkError::Unknown) + if reason != (>::into(self.config.qos) >> 1) { + Err(ReasonCode::from(reason)) } else { Ok(()) } } - pub async fn receive_message<'b>(&'b mut self) -> Result<&'b [u8], NetworkError> { - self.network_driver.receive(self.recv_buffer).await?; + pub async fn receive_message<'b>(&'b mut self) -> Result<&'b [u8], ReasonCode> { + self.network_driver.receive(self.recv_buffer).await ?; let mut packet = PublishPacket::<'b, 5>::new(); packet.decode(&mut BuffReader::new(self.recv_buffer)); diff --git a/src/client/mod.rs b/src/client/mod.rs index c047371..8574d8d 100644 --- a/src/client/mod.rs +++ b/src/client/mod.rs @@ -1,2 +1,27 @@ +/* + * MIT License + * + * Copyright (c) [2022] [Ondrej Babec ] + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + + pub mod client_v5; pub mod client_config; diff --git a/src/encoding/mod.rs b/src/encoding/mod.rs index 563194c..0324c19 100644 --- a/src/encoding/mod.rs +++ b/src/encoding/mod.rs @@ -1 +1,26 @@ +/* + * MIT License + * + * Copyright (c) [2022] [Ondrej Babec ] + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + + pub mod variable_byte_integer; diff --git a/src/encoding/variable_byte_integer.rs b/src/encoding/variable_byte_integer.rs index a338f90..afb561f 100644 --- a/src/encoding/variable_byte_integer.rs +++ b/src/encoding/variable_byte_integer.rs @@ -1,3 +1,27 @@ +/* +MIT License + +Copyright (c) [2022] [Ondrej Babec ] + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ + #![crate_name = "doc"] use crate::utils::buffer_reader::ParseError; diff --git a/src/lib.rs b/src/lib.rs index 6c19f62..e18bc7e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,27 @@ +/* + * MIT License + * + * Copyright (c) [2022] [Ondrej Babec ] + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + #![feature(in_band_lifetimes)] #![macro_use] #![cfg_attr(not(feature = "std"), no_std)] @@ -13,31 +37,3 @@ pub mod network; pub mod packet; pub mod tokio_network; pub mod utils; - -#[allow(unused_variables)] -pub fn print_stack(file: &'static str, line: u32) { - let _u: u32 = 1; - let _uptr: *const u32 = &_u; - // log::trace!("[{}:{}] SP: 0x{:p}", file, line, &_uptr); -} - -#[allow(unused_variables)] -pub fn log_stack(file: &'static str) { - let _u: u32 = 1; - let _uptr: *const u32 = &_u; - //trace!("[{}] SP: 0x{:?}", file, &_uptr); -} - -#[allow(unused_variables)] -pub fn print_size(name: &'static str) { - //log::info!("[{}] size: {}", name, core::mem::size_of::()); -} - -#[allow(unused_variables)] -pub fn print_value_size(name: &'static str, val: &T) { - /* log::info!( - "[{}] value size: {}", - name, - core::mem::size_of_val::(val) - );*/ -} diff --git a/src/main.rs b/src/main.rs index 824dc28..c6c200d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -19,12 +19,18 @@ async fn receive() { let mut config = ClientConfig::new(); config.add_qos(QualityOfService::QoS1); config.add_username("test"); - config.add_password("testPass"); + config.add_password("testPass1"); let mut res2 = vec![0; 260]; let mut res3 = vec![0; 260]; let mut client = MqttClientV5::::new(&mut tokio_network, &mut res2, & mut res3, config); - let mut result = { client.connect_to_broker().await }; + let mut result = { + client.connect_to_broker().await + }; + if let Err(r) = result { + log::error!("[ERROR]: {}", r); + return; + } { client.subscribe_to_topic("test/topic").await; diff --git a/src/network/mod.rs b/src/network/mod.rs index e083076..fb22dd6 100644 --- a/src/network/mod.rs +++ b/src/network/mod.rs @@ -1 +1,26 @@ +/* + * MIT License + * + * Copyright (c) [2022] [Ondrej Babec ] + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + + pub mod network_trait; diff --git a/src/network/network_trait.rs b/src/network/network_trait.rs index 3466a3f..bfe623f 100644 --- a/src/network/network_trait.rs +++ b/src/network/network_trait.rs @@ -1,6 +1,6 @@ use core::fmt::Error; use core::future::Future; - +use crate::packet::reason_codes::ReasonCode; use crate::packet::mqtt_packet::Packet; @@ -14,15 +14,15 @@ pub enum NetworkError { } pub trait Network { - type ConnectionFuture<'m>: Future> + type ConnectionFuture<'m>: Future> where Self: 'm; - type WriteFuture<'m>: Future> + type WriteFuture<'m>: Future> where Self: 'm; - type ReadFuture<'m>: Future> + type ReadFuture<'m>: Future> where Self: 'm; diff --git a/src/packet/auth_packet.rs b/src/packet/auth_packet.rs index d2fb850..032d5a0 100644 --- a/src/packet/auth_packet.rs +++ b/src/packet/auth_packet.rs @@ -1,3 +1,28 @@ +/* + * MIT License + * + * Copyright (c) [2022] [Ondrej Babec ] + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + + use heapless::Vec; use crate::encoding::variable_byte_integer::VariableByteIntegerEncoder; @@ -8,20 +33,18 @@ use crate::utils::buffer_writer::BuffWriter; use super::packet_type::PacketType; use super::property::Property; +/// Auth packets serves MQTTv5 extended authentication. This packet is not currently supported +/// by rust-mqtt client but decoding and encoding of packet is prepared for future development. pub struct AuthPacket<'a, const MAX_PROPERTIES: usize> { - // 7 - 4 mqtt control packet type, 3-0 flagy pub fixed_header: u8, - // 1 - 4 B lenght of variable header + len of payload pub remain_len: u32, - pub auth_reason: u8, - pub property_len: u32, - pub properties: Vec, MAX_PROPERTIES>, } impl<'a, const MAX_PROPERTIES: usize> AuthPacket<'a, MAX_PROPERTIES> { + /// Function is decoding auth packet from Byte array (buffer). pub fn decode_auth_packet(&mut self, buff_reader: &mut BuffReader<'a>) { self.decode_fixed_header(buff_reader); self.auth_reason = buff_reader.read_u8().unwrap(); @@ -47,11 +70,14 @@ impl<'a, const MAX_PROPERTIES: usize> AuthPacket<'a, MAX_PROPERTIES> { impl<'a, const MAX_PROPERTIES: usize> Packet<'a> for AuthPacket<'a, MAX_PROPERTIES> { fn new() -> Self { - todo!() + Self { + fixed_header: PacketType::Auth.into(), + remain_len: 0, + auth_reason: 0x00, + property_len: 0, + properties: Vec::, MAX_PROPERTIES>::new() + } } - /*fn new() -> Packet<'a, MAX_PROPERTIES> { - return AuthPacket { fixed_header: PacketType::Auth.into(), remain_len: 0, auth_reason: 0, property_len: 0, properties: Vec::, MAX_PROPERTIES>::new() } - }*/ fn encode(&mut self, buffer: &mut [u8]) -> usize { let mut buff_writer = BuffWriter::new(buffer); diff --git a/src/packet/connack_packet.rs b/src/packet/connack_packet.rs index f6c97c3..98d005e 100644 --- a/src/packet/connack_packet.rs +++ b/src/packet/connack_packet.rs @@ -1,3 +1,27 @@ +/* + * MIT License + * + * Copyright (c) [2022] [Ondrej Babec ] + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + use heapless::Vec; use crate::encoding::variable_byte_integer::VariableByteIntegerEncoder; diff --git a/src/packet/connect_packet.rs b/src/packet/connect_packet.rs index 1845d3b..d3d2893 100644 --- a/src/packet/connect_packet.rs +++ b/src/packet/connect_packet.rs @@ -1,3 +1,27 @@ +/* + * MIT License + * + * Copyright (c) [2022] [Ondrej Babec ] + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + use heapless::Vec; use crate::encoding::variable_byte_integer::VariableByteIntegerEncoder; diff --git a/src/packet/disconnect_packet.rs b/src/packet/disconnect_packet.rs index 4338307..6507240 100644 --- a/src/packet/disconnect_packet.rs +++ b/src/packet/disconnect_packet.rs @@ -1,3 +1,27 @@ +/* + * MIT License + * + * Copyright (c) [2022] [Ondrej Babec ] + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + use heapless::Vec; use crate::encoding::variable_byte_integer::VariableByteIntegerEncoder; diff --git a/src/packet/mod.rs b/src/packet/mod.rs index 2b75c1d..5ec0c97 100644 --- a/src/packet/mod.rs +++ b/src/packet/mod.rs @@ -1,4 +1,27 @@ -//pub mod control_packet; +/* + * MIT License + * + * Copyright (c) [2022] [Ondrej Babec ] + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + pub mod auth_packet; pub mod connack_packet; pub mod mqtt_packet; diff --git a/src/packet/mqtt_packet.rs b/src/packet/mqtt_packet.rs index 9a65305..e7ea635 100644 --- a/src/packet/mqtt_packet.rs +++ b/src/packet/mqtt_packet.rs @@ -1,25 +1,55 @@ +/* + * MIT License + * + * Copyright (c) [2022] [Ondrej Babec ] + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + use crate::packet::packet_type::PacketType; use crate::utils::buffer_reader::BuffReader; use crate::utils::buffer_reader::ParseError; use super::property::Property; - +/// This trait provide interface for mapping MQTTv5 packets to human readable structures +/// which can be later modified and used for communication purposes. pub trait Packet<'a> { fn new() -> Self; - + /// Method encode provide way how to transfer Packet struct into Byte array (buffer) fn encode(&mut self, buffer: &mut [u8]) -> usize; - // -> Result + /// Decode method is opposite of encode - decoding Byte array and mapping it into corresponding Packet struct fn decode(&mut self, buff_reader: &mut BuffReader<'a>); - // properties + /// Setter method for packet properties len - not all Packet types support this fn set_property_len(&mut self, value: u32); + /// Setter method for packet properties len - not all Packet types support this fn get_property_len(&mut self) -> u32; + /// Method enables pushing new property into packet properties fn push_to_properties(&mut self, property: Property<'a>); - // header + /// Setter for packet fixed header fn set_fixed_header(&mut self, header: u8); + /// Setter for remaining len fn set_remaining_len(&mut self, remaining_len: u32); + /// Method is decoding Byte array pointing to properties into heapless Vec + /// in packet. If decoding goes wrong method is returning Error fn decode_properties(&mut self, buff_reader: &mut BuffReader<'a>) { self.set_property_len(buff_reader.read_variable_byte_int().unwrap()); let mut x: u32 = 0; @@ -29,11 +59,10 @@ pub trait Packet<'a> { let mut res: Property; prop = Property::decode(buff_reader); if let Ok(res) = prop { - log::info!("Parsed property {:?}", res); + log::debug!("Parsed property {:?}", res); x = x + res.len() as u32 + 1; self.push_to_properties(res); } else { - // error handler log::error!("Problem during property decoding"); } @@ -44,6 +73,7 @@ pub trait Packet<'a> { } } + /// Method is decoding packet header into fixed header part and remaining length fn decode_fixed_header(&mut self, buff_reader: &mut BuffReader) -> PacketType { let first_byte: u8 = buff_reader.read_u8().unwrap(); self.set_fixed_header(first_byte); diff --git a/src/packet/packet_type.rs b/src/packet/packet_type.rs index 82fc069..97ac1a7 100644 --- a/src/packet/packet_type.rs +++ b/src/packet/packet_type.rs @@ -1,3 +1,27 @@ +/* + * MIT License + * + * Copyright (c) [2022] [Ondrej Babec ] + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + // x x x x - - - - #[derive(PartialEq)] diff --git a/src/packet/pingreq_packet.rs b/src/packet/pingreq_packet.rs index dad2941..f7f3d6f 100644 --- a/src/packet/pingreq_packet.rs +++ b/src/packet/pingreq_packet.rs @@ -1,3 +1,27 @@ +/* + * MIT License + * + * Copyright (c) [2022] [Ondrej Babec ] + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + use crate::packet::mqtt_packet::Packet; use crate::utils::buffer_reader::BuffReader; use crate::utils::buffer_writer::BuffWriter; diff --git a/src/packet/pingresp_packet.rs b/src/packet/pingresp_packet.rs index 645edc0..ef140e1 100644 --- a/src/packet/pingresp_packet.rs +++ b/src/packet/pingresp_packet.rs @@ -1,3 +1,27 @@ +/* + * MIT License + * + * Copyright (c) [2022] [Ondrej Babec ] + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + use crate::packet::mqtt_packet::Packet; use crate::utils::buffer_reader::BuffReader; use crate::utils::buffer_writer::BuffWriter; diff --git a/src/packet/property.rs b/src/packet/property.rs index fe16104..03aca0b 100644 --- a/src/packet/property.rs +++ b/src/packet/property.rs @@ -1,3 +1,27 @@ +/* + * MIT License + * + * Copyright (c) [2022] [Ondrej Babec ] + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + use crate::encoding::variable_byte_integer::{VariableByteInteger, VariableByteIntegerEncoder}; use crate::utils::buffer_reader::BinaryData; use crate::utils::buffer_reader::BuffReader; diff --git a/src/packet/puback_packet.rs b/src/packet/puback_packet.rs index d3a2705..630e2fb 100644 --- a/src/packet/puback_packet.rs +++ b/src/packet/puback_packet.rs @@ -1,3 +1,27 @@ +/* + * MIT License + * + * Copyright (c) [2022] [Ondrej Babec ] + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + use heapless::Vec; use crate::encoding::variable_byte_integer::VariableByteIntegerEncoder; diff --git a/src/packet/pubcomp_packet.rs b/src/packet/pubcomp_packet.rs index b067ca6..7510a9b 100644 --- a/src/packet/pubcomp_packet.rs +++ b/src/packet/pubcomp_packet.rs @@ -1,3 +1,27 @@ +/* + * MIT License + * + * Copyright (c) [2022] [Ondrej Babec ] + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + use heapless::Vec; use crate::encoding::variable_byte_integer::VariableByteIntegerEncoder; diff --git a/src/packet/publish_packet.rs b/src/packet/publish_packet.rs index 99ec544..d22fce4 100644 --- a/src/packet/publish_packet.rs +++ b/src/packet/publish_packet.rs @@ -1,3 +1,27 @@ +/* + * MIT License + * + * Copyright (c) [2022] [Ondrej Babec ] + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + use core::ptr::null; use heapless::Vec; diff --git a/src/packet/pubrec_packet.rs b/src/packet/pubrec_packet.rs index 00a8428..08c7e5c 100644 --- a/src/packet/pubrec_packet.rs +++ b/src/packet/pubrec_packet.rs @@ -1,3 +1,27 @@ +/* + * MIT License + * + * Copyright (c) [2022] [Ondrej Babec ] + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + use heapless::Vec; use crate::encoding::variable_byte_integer::VariableByteIntegerEncoder; diff --git a/src/packet/pubrel_packet.rs b/src/packet/pubrel_packet.rs index 2a25bd8..0d25638 100644 --- a/src/packet/pubrel_packet.rs +++ b/src/packet/pubrel_packet.rs @@ -1,3 +1,27 @@ +/* + * MIT License + * + * Copyright (c) [2022] [Ondrej Babec ] + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + use heapless::Vec; use crate::encoding::variable_byte_integer::VariableByteIntegerEncoder; diff --git a/src/packet/reason_codes.rs b/src/packet/reason_codes.rs index 22a54f1..de5fb8f 100644 --- a/src/packet/reason_codes.rs +++ b/src/packet/reason_codes.rs @@ -1,6 +1,7 @@ use core::fmt::{Display, Formatter, write}; use crate::packet::reason_codes::ReasonCode::ServerMoved; +#[derive(Debug)] pub enum ReasonCode { Success, GrantedQoS1, @@ -45,7 +46,7 @@ pub enum ReasonCode { MaximumConnectTime, SubscriptionIdentifiersNotSupported, WildcardSubscriptionNotSupported, - Unknown + NetworkError, } impl Into for ReasonCode { @@ -94,7 +95,7 @@ impl Into for ReasonCode { ReasonCode::MaximumConnectTime => 0xA0, ReasonCode::SubscriptionIdentifiersNotSupported => 0xA1, ReasonCode::WildcardSubscriptionNotSupported => 0xA2, - ReasonCode::Unknown => 0xFF + ReasonCode::NetworkError => 0xFF } } @@ -145,7 +146,7 @@ impl From for ReasonCode { 0xA0 => ReasonCode::MaximumConnectTime, 0xA1 => ReasonCode::SubscriptionIdentifiersNotSupported, 0xA2 => ReasonCode::WildcardSubscriptionNotSupported, - _ => ReasonCode::Unknown + _ => ReasonCode::NetworkError } } } @@ -156,7 +157,7 @@ impl Display for ReasonCode { ReasonCode::Success => write!(f, "Operation was successful!"), ReasonCode::GrantedQoS1 => write!(f, "Granted QoS level 1!"), ReasonCode::GrantedQoS2 => write!(f, "Granted QoS level 2!"), - ReasonCode::DisconnectWithWillMessage => {} + ReasonCode::DisconnectWithWillMessage => write!(f, "Disconnected with Will message!"), ReasonCode::NoMatchingSubscribers => write!(f, "No matching subscribers on broker!"), ReasonCode::NoSubscriptionExisted => write!(f, "Subscription not exist!"), ReasonCode::ContinueAuth => write!(f, "Broker asks for more AUTH packets!"), @@ -196,7 +197,7 @@ impl Display for ReasonCode { ReasonCode::MaximumConnectTime => write!(f, "Maximum connect time exceeded!"), ReasonCode::SubscriptionIdentifiersNotSupported => write!(f, "Subscription identifier not supported!"), ReasonCode::WildcardSubscriptionNotSupported => write!(f, "Wildcard subscription not supported!"), - ReasonCode::Unknown => write!(f, "Unknown error!"), + ReasonCode::NetworkError => write!(f, "Unknown error!"), } } } \ No newline at end of file diff --git a/src/packet/suback_packet.rs b/src/packet/suback_packet.rs index 064c303..bcd7878 100644 --- a/src/packet/suback_packet.rs +++ b/src/packet/suback_packet.rs @@ -1,3 +1,27 @@ +/* + * MIT License + * + * Copyright (c) [2022] [Ondrej Babec ] + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + use heapless::Vec; use crate::encoding::variable_byte_integer::VariableByteIntegerEncoder; diff --git a/src/packet/subscription_packet.rs b/src/packet/subscription_packet.rs index d396035..e32ea8d 100644 --- a/src/packet/subscription_packet.rs +++ b/src/packet/subscription_packet.rs @@ -1,3 +1,27 @@ +/* + * MIT License + * + * Copyright (c) [2022] [Ondrej Babec ] + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + use heapless::Vec; use crate::encoding::variable_byte_integer::VariableByteIntegerEncoder; diff --git a/src/packet/unsuback_packet.rs b/src/packet/unsuback_packet.rs index f0f8a1b..b834a33 100644 --- a/src/packet/unsuback_packet.rs +++ b/src/packet/unsuback_packet.rs @@ -1,3 +1,27 @@ +/* + * MIT License + * + * Copyright (c) [2022] [Ondrej Babec ] + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + use heapless::Vec; use crate::packet::mqtt_packet::Packet; diff --git a/src/packet/unsubscription_packet.rs b/src/packet/unsubscription_packet.rs index 8b7e7f0..1d374d7 100644 --- a/src/packet/unsubscription_packet.rs +++ b/src/packet/unsubscription_packet.rs @@ -1,3 +1,27 @@ +/* + * MIT License + * + * Copyright (c) [2022] [Ondrej Babec ] + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + use heapless::Vec; use crate::encoding::variable_byte_integer::VariableByteIntegerEncoder; diff --git a/src/tokio_network.rs b/src/tokio_network.rs index 601d0a5..5471f44 100644 --- a/src/tokio_network.rs +++ b/src/tokio_network.rs @@ -8,8 +8,9 @@ use core::ptr::null; use tokio::io::{AsyncReadExt, AsyncWriteExt}; use tokio::net::{TcpListener, TcpStream}; -use crate::network::network_trait::{Network, NetworkError}; +use crate::network::network_trait::{Network}; use crate::packet::mqtt_packet::Packet; +use crate::packet::reason_codes::ReasonCode; pub struct TokioNetwork { ip: [u8; 4], @@ -32,15 +33,15 @@ impl Network for TokioNetwork { type ConnectionFuture<'m> where Self: 'm, - = impl Future> + 'm; + = impl Future> + 'm; type WriteFuture<'m> where Self: 'm, - = impl Future> + 'm; + = impl Future> + 'm; type ReadFuture<'m> where Self: 'm, - = impl Future> + 'm; + = impl Future> + 'm; fn new(ip: [u8; 4], port: u16) -> Self { return Self { @@ -56,7 +57,7 @@ impl Network for TokioNetwork { .await .map(|socket| self.socket = Some(socket)) .map(|_| ()) - .map_err(|_| NetworkError::Connection) + .map_err(|_| ReasonCode::NetworkError) } } @@ -66,9 +67,9 @@ impl Network for TokioNetwork { stream .write_all(&buffer[0..len]) .await - .map_err(|_| NetworkError::Unknown) + .map_err(|_| ReasonCode::NetworkError) } else { - Err(NetworkError::Unknown) + Err(ReasonCode::NetworkError) }; } } @@ -79,20 +80,10 @@ impl Network for TokioNetwork { stream .read(buffer) .await - .map_err(|_| NetworkError::Connection) + .map_err(|_| ReasonCode::NetworkError) } else { - Err(NetworkError::Unknown) + Err(ReasonCode::NetworkError) }; } } - - /*fn send(&mut self, buffer: &mut [u8], len: usize) -> Result<(), NetworkError> { - self.socket.write_all(&buffer[0..len]); - Ok(()) - } - - fn receive(&mut self, buffer: &mut [u8]) -> Result { - let len = self.socket.read(buffer).await ?; - Ok(len) - }*/ } diff --git a/src/utils/buffer_reader.rs b/src/utils/buffer_reader.rs index 6dc2c46..9ecf40e 100644 --- a/src/utils/buffer_reader.rs +++ b/src/utils/buffer_reader.rs @@ -1,8 +1,33 @@ +/* + * MIT License + * + * Copyright (c) [2022] [Ondrej Babec ] + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + use core::mem; use core::str; use crate::encoding::variable_byte_integer::VariableByteIntegerDecoder; +/// Encoded string provides structure representing UTF-8 encoded string in MQTTv5 packets #[derive(Debug)] #[derive(Clone)] pub struct EncodedString<'a> { @@ -14,12 +39,13 @@ impl EncodedString<'_> { pub fn new() -> Self { Self { string: "", len: 0 } } - + /// Return length of string pub fn len(&self) -> u16 { return self.len + 2; } } +/// Binary data represents `Binary data` in MQTTv5 protocol #[derive(Debug)] #[derive(Clone)] pub struct BinaryData<'a> { @@ -31,12 +57,13 @@ impl BinaryData<'_> { pub fn new() -> Self { Self { bin: &[0], len: 0 } } - + /// Returns length of Byte array pub fn len(&self) -> u16 { return self.len + 2; } } +/// String pair struct represents `String pair` in MQTTv5 (2 UTF-8 encoded strings name-value) #[derive(Debug)] pub struct StringPair<'a> { pub name: EncodedString<'a>, @@ -44,12 +71,14 @@ pub struct StringPair<'a> { } impl StringPair<'_> { + /// Returns length which is equal to sum of the lenghts of UTF-8 encoded strings in pair pub fn len(&self) -> u16 { let ln = self.name.len() + self.value.len(); return ln; } } +/// Topic filter serves as bound for topic selection and subscription options for `SUBSCRIPTION` packet #[derive(Debug)] pub struct TopicFilter<'a> { pub filter: EncodedString<'a>, @@ -79,6 +108,8 @@ pub enum ParseError { DecodingError, } +/// Buff reader is reading corresponding types from buffer (Byte array) and stores current position +/// (later as cursor) pub struct BuffReader<'a> { buffer: &'a [u8], pub position: usize, @@ -96,6 +127,8 @@ impl<'a> BuffReader<'a> { }; } + /// Variable byte integer can be 1-4 Bytes long. Buffer reader takes all 4 Bytes at first and + /// than check what is true length of varbyteint and increment cursor by that pub fn read_variable_byte_int(&mut self) -> Result { let variable_byte_integer: [u8; 4] = [ self.buffer[self.position], @@ -104,6 +137,7 @@ impl<'a> BuffReader<'a> { self.buffer[self.position + 3], ]; let mut len: usize = 1; + /// Everytime checking first bit of Byte which determines whenever there is continous Byte if variable_byte_integer[0] & 0x80 == 1 { len = len + 1; if variable_byte_integer[1] & 0x80 == 1 { @@ -117,33 +151,35 @@ impl<'a> BuffReader<'a> { return VariableByteIntegerDecoder::decode(variable_byte_integer); } + /// Reading u32 from buffer as `Big endian` pub fn read_u32(&mut self) -> Result { let (int_bytes, rest) = self.buffer[self.position..].split_at(mem::size_of::()); let ret: u32 = u32::from_be_bytes(int_bytes.try_into().unwrap()); - //let ret: u32 = (((self.buffer[self.position] as u32) << 24) | ((self.buffer[self.position + 1] as u32) << 16) | ((self.buffer[self.position + 2] as u32) << 8) | (self.buffer[self.position + 3] as u32)) as u32; self.increment_position(4); return Ok(ret); } + /// Reading u16 from buffer as `Big endinan` pub fn read_u16(&mut self) -> Result { let (int_bytes, rest) = self.buffer[self.position..].split_at(mem::size_of::()); let ret: u16 = u16::from_be_bytes(int_bytes.try_into().unwrap()); - //(((self.buffer[self.position] as u16) << 8) | (self.buffer[self.position + 1] as u16)) as u16; self.increment_position(2); return Ok(ret); } + /// Reading one byte from buffer as `Big endian` pub fn read_u8(&mut self) -> Result { let ret: u8 = self.buffer[self.position]; self.increment_position(1); return Ok(ret); } + /// Reading UTF-8 encoded string from buffer pub fn read_string(&mut self) -> Result, ParseError> { let len = self.read_u16(); match len { Err(err) => return Err(err), - _ => log::debug!("[parseString] let not parsed"), + _ => {}, } let len_res = len.unwrap(); let res_str = @@ -160,6 +196,7 @@ impl<'a> BuffReader<'a> { } //TODO: Index out of bounce err !!!!! + /// Read Binary data from buffer pub fn read_binary(&mut self) -> Result, ParseError> { let len = self.read_u16(); match len { @@ -174,6 +211,7 @@ impl<'a> BuffReader<'a> { }); } + /// Read string pair from buffer pub fn read_string_pair(&mut self) -> Result, ParseError> { let name = self.read_string(); match name { @@ -191,6 +229,7 @@ impl<'a> BuffReader<'a> { }); } + /// Read payload message from buffer pub fn read_message(&mut self, total_len: usize) -> &'a [u8] { return &self.buffer[self.position..total_len]; } diff --git a/src/utils/buffer_writer.rs b/src/utils/buffer_writer.rs index 3d0bc8c..2f2f8af 100644 --- a/src/utils/buffer_writer.rs +++ b/src/utils/buffer_writer.rs @@ -1,3 +1,27 @@ +/* + * MIT License + * + * Copyright (c) [2022] [Ondrej Babec ] + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + use core::str; use heapless::Vec; diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 3e38d69..de04e4c 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -1,3 +1,27 @@ +/* + * MIT License + * + * Copyright (c) [2022] [Ondrej Babec ] + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + pub mod buffer_reader; pub mod buffer_writer; pub mod rng_generator; diff --git a/src/utils/rng_generator.rs b/src/utils/rng_generator.rs index 9d98c42..2e96e02 100644 --- a/src/utils/rng_generator.rs +++ b/src/utils/rng_generator.rs @@ -1,3 +1,6 @@ +// This code is handed from Embedded Rust documentation and +// is accessible from https://docs.rust-embedded.org/cortex-m-rt/0.6.0/rand/trait.RngCore.html + use rand_core::{RngCore, Error, impls}; pub struct CountingRng(pub u64);