diff --git a/src/encoding/variable_byte_integer.rs b/src/encoding/variable_byte_integer.rs index ecb2039..1c9be49 100644 --- a/src/encoding/variable_byte_integer.rs +++ b/src/encoding/variable_byte_integer.rs @@ -9,6 +9,8 @@ pub struct VariableByteIntegerEncoder; /// Variable byte integers error enumeration is used by both encoder and decoder for /// error notification. +#[derive(core::fmt::Debug)] +#[derive(Clone)] pub enum VariableByteIntegerError { EncodingError, DecodingError diff --git a/src/main.rs b/src/main.rs index 369b0cc..2002ec8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,8 +1,10 @@ -use rust_mqtt::packet::mqtt_packet::Packet; +use rust_mqtt::packet::mqtt_packet::*; use rust_mqtt::packet::packet_type::PacketType; use rust_mqtt::packet::packet_builder::PacketBuilder; use rust_mqtt::encoding::variable_byte_integer::VariableByteIntegerEncoder; use rust_mqtt::encoding::variable_byte_integer::VariableByteIntegerDecoder; +use rust_mqtt::packet::property::*; +use heapless::Vec; fn main() { env_logger::builder() @@ -15,9 +17,9 @@ fn main() { let z: u16 = 3; let p: u32 = 4; - let mut txt = *b"abcde"; + let mut txt = Vec::new(); let mut payld = *b"xxxxx"; - let packet = Packet::clean(&mut txt, &mut payld); + let packet = Packet::clean(txt, &mut payld); let mut packet_builder = PacketBuilder::new(packet); packet_builder.addPacketType(PacketType::Publish); @@ -34,11 +36,8 @@ fn main() { log::info!("{:02X?}", r); let d = VariableByteIntegerDecoder::decode(r); log::info!("Enum val: {}", o); - let x = Packet::new( l, 0, z, 0, &mut txt, &mut payld ); log::info!("Hello world"); - x.encode(); - x.get_reason_code(); } diff --git a/src/packet/mqtt_packet.rs b/src/packet/mqtt_packet.rs index 25f52b7..4b5ca0d 100644 --- a/src/packet/mqtt_packet.rs +++ b/src/packet/mqtt_packet.rs @@ -1,28 +1,48 @@ +use super::property::Property; +use super::packet_type::PacketType; +use heapless::Vec; + +pub const MAX_PROPERTIES: usize = 18; + pub struct Packet<'a> { // 7 - 4 mqtt control packet type, 3-0 flagy - pub header_control: u8, + pub fixed_header: u8, // 1 - 4 B lenght of variable header + len of payload pub remain_len: u32, // variable header //optional prida se pouze u packetu ve kterych ma co delat pub packet_identifier: u16, + + pub protocol_name_len: u16, + + pub protocol_name: u32, + + pub protocol_version: u8, + + pub connect_flags: u8, + + pub keep_alive: u16, // property len pub property_len: u32, + // properties - pub properties: &'a mut [u8], + pub properties: Vec, MAX_PROPERTIES>, + // Payload of message pub payload: &'a mut [u8] } impl<'a> Packet<'a> { - pub fn new(header_control: u8, remain_len: u32, packet_identifier: u16, property_len: u32, - properties: &'a mut [u8], payload: &'a mut [u8]) -> Self { - Self { header_control, remain_len, packet_identifier, property_len, properties, payload } + pub fn new(fixed_header: u8, remain_len: u32, packet_identifier: u16, protocol_name_len: u16, + protocol_name: u32, protocol_version: u8, + connect_flags: u8, keep_alive: u16, property_len: u32, + properties: Vec, MAX_PROPERTIES>, payload: &'a mut [u8]) -> Self { + Self { fixed_header, remain_len, packet_identifier, property_len, properties, payload, connect_flags, keep_alive, protocol_name_len, protocol_name, protocol_version } } - pub fn clean(properties: &'a mut [u8], payload: &'a mut [u8]) -> Self { - Self{ header_control: 0, remain_len: 0, packet_identifier: 0, property_len: 0, properties, payload } + pub fn clean(properties: Vec, MAX_PROPERTIES>, payload: &'a mut [u8]) -> Self { + Self{ fixed_header: 0x00, remain_len: 0, packet_identifier: 0, property_len: 0, properties, payload, connect_flags: 0, keep_alive: 0, protocol_name_len: 0, protocol_name: 0, protocol_version: 5} } pub fn encode(&self) { diff --git a/src/packet/packet_builder.rs b/src/packet/packet_builder.rs index 263b7f1..35e3113 100644 --- a/src/packet/packet_builder.rs +++ b/src/packet/packet_builder.rs @@ -1,13 +1,18 @@ use super::mqtt_packet::Packet; use super::packet_type::PacketType; +use super::property::Property; +use crate::utils::buffer_reader::*; // Je potreba vytvori +// metody packet buildery budou prijimat jako parametr buff reader, z ktereho bude postupne parsovat + pub struct PacketBuilder<'a> { currentPacket: Packet<'a>, } impl<'a> PacketBuilder<'a> { + pub fn new(packet: Packet<'a>) -> Self { Self{ currentPacket: packet } } @@ -20,13 +25,13 @@ impl<'a> PacketBuilder<'a> { return &self.currentPacket; } - pub fn addPacketType(& mut self, packet_type: PacketType) { - self.currentPacket.header_control = self.currentPacket.header_control & 0x0F; - self.currentPacket.header_control = self.currentPacket.header_control | >::into(packet_type); + pub fn addPacketType(& mut self, new_packet_type: PacketType) { + self.currentPacket.fixed_header = self.currentPacket.fixed_header & 0x0F; + self.currentPacket.fixed_header = self.currentPacket.fixed_header | >::into(new_packet_type); } pub fn addFlags(& mut self, dup: bool, qos: u8, retain: bool) { - let cur_type: u8 = self.currentPacket.header_control & 0xF0; + let cur_type: u8 = self.currentPacket.fixed_header & 0xF0; if cur_type != 0x30 { log::error!("Cannot add flags into packet with other than PUBLISH type"); return; @@ -44,10 +49,51 @@ impl<'a> PacketBuilder<'a> { if retain { flags = flags | 0x01; } - self.currentPacket.header_control = cur_type | flags; + self.currentPacket.fixed_header = cur_type | flags; } pub fn completePacket(& mut self) { // Tutaj se cely packet dokonci - spocita se remaining len co chybi v hlavicce atd... } + + pub fn decode_packet(& mut self, buff_reader: &'a mut BuffReader) { + self.decodeFixedHeader(buff_reader); + if self.currentPacket.fixed_header & 0xF0 == (PacketType::Connect).into() { + self.decodeControllPacket(buff_reader); + } + } + + pub fn decodeFixedHeader(& mut self, buff_reader: & mut BuffReader) -> PacketType { + let first_byte: u8 = buff_reader.readU8().unwrap(); + self.currentPacket.fixed_header = first_byte; + self.currentPacket.remain_len = buff_reader.readVariableByteInt().unwrap(); + return PacketType::from(self.currentPacket.fixed_header); + } + + pub fn decodeControllPacket(& mut self, buff_reader: &'a mut BuffReader) { + self.currentPacket.packet_identifier = 0; + self.currentPacket.protocol_name_len = buff_reader.readU16().unwrap(); + self.currentPacket.protocol_name = buff_reader.readU32().unwrap(); + self.currentPacket.protocol_version = buff_reader.readU8().unwrap(); + self.currentPacket.connect_flags = buff_reader.readU8().unwrap(); + self.currentPacket.keep_alive = buff_reader.readU16().unwrap(); + self.currentPacket.property_len = buff_reader.readVariableByteInt().unwrap(); + let mut x: u32 = 0; + let mut prop: Result; + let mut res; + loop { + prop = Property::decode(buff_reader); + if prop.is_ok() { + res = prop.unwrap(); + self.currentPacket.properties.push(res); + } else { + log::error!("Decoding property did not went well!"); + } + + x = x + res.len() as u32 + 1; + if x == self.currentPacket.property_len { + break; + } + } + } } \ No newline at end of file diff --git a/src/packet/packet_type.rs b/src/packet/packet_type.rs index f01275b..df9fb9d 100644 --- a/src/packet/packet_type.rs +++ b/src/packet/packet_type.rs @@ -1,6 +1,6 @@ // x x x x - - - - - +#[derive(PartialEq)] pub enum PacketType { Reserved, Connect, @@ -22,7 +22,8 @@ pub enum PacketType { impl From for PacketType { fn from(orig: u8) -> Self { - match orig { + let packet_type: u8 = orig & 0xF0; + match packet_type { 0x10 => return PacketType::Connect, 0x20 => return PacketType::Connack, 0x00 => return PacketType::Reserved, diff --git a/src/packet/property.rs b/src/packet/property.rs index cfce750..05b344b 100644 --- a/src/packet/property.rs +++ b/src/packet/property.rs @@ -3,15 +3,9 @@ use crate::utils::buffer_reader::StringPair; use crate::utils::buffer_reader::EncodedString; use crate::utils::buffer_reader::BinaryData; use crate::encoding::variable_byte_integer::VariableByteIntegerError; -/*use crate::encoding::variable_byte_integer::VariableByteIntegerDecoder; -use crate::encoding::variable_byte_integer::VariableByteIntegerError; -use core::str; +use crate::utils::buffer_reader::BuffReader; - -pub trait Decode<'a> { - fn decode(input: &'a [u8], offset: &'a mut usize) -> Result where Self: Sized; -} -*/ +#[derive(Clone)] pub enum Property<'a> { PayloadFormat(Result), MessageExpiryInterval(Result), @@ -42,40 +36,70 @@ pub enum Property<'a> { SharedSubscriptionAvailable(Result) } -/* -impl<'a> Decode<'a> for Property<'a> { - fn decode(input: &'a [u8], offset: &'a mut usize) -> Result { - let propertyIdentifier = parseU8(input, offset); +impl<'a> Property<'a> { + pub fn len(mut self) -> u16 { + match self { + Property::PayloadFormat(u) => return 1, + Property::MessageExpiryInterval(u) => return 4, + Property::ContentType(u) => return u.unwrap().len(), + Property::ResponseTopic(u) => return u.unwrap().len(), + Property::CorrelationData(u) => return u.unwrap().len(), + Property::SubscriptionIdentifier(u) => return 4, + Property::AssignedClientIdentifier(u) => return u.unwrap().len(), + Property::ServerKeepAlive(u) => return 2, + Property::AuthenticationMethod(u) => return u.unwrap().len(), + Property::AuthenticationData(u) => return u.unwrap().len(), + Property::RequestProblemInformation(u) => return 1, + Property::WillDelayInterval(u) => return 4, + Property::RequestResponseInformation(u) => return 1, + Property::ResponseInformation(u) => return u.unwrap().len(), + Property::ServerReference(u) => return u.unwrap().len(), + Property::ReasonString(u) => return u.unwrap().len(), + Property::ReceiveMaximum(u) => return 2, + Property::TopicAliasMaximum(u) => return 2, + Property::TopicAlias(u) => return 2, + Property::MaximumQoS(u) => return 1, + Property::RetainAvailable(u) => return 1, + Property::UserProperty(u) => return u.unwrap().len(), + Property::MaximumPacketSize(u) => return 4, + Property::WildcardSubscriptionAvailable(u) => return 1, + Property::SubscriptionIdentifierAvailable(u) => return 1, + Property::SharedSubscriptionAvailable(u) => return 1, + _ => return 0 + } + } + + pub fn decode(buff_reader: &'a mut BuffReader) -> Result, ProperyParseError> { + let propertyIdentifier = buff_reader.readU8(); match propertyIdentifier { - Ok(0x01) => return Ok(Property::PayloadFormat(parseU8(input, offset))), - Ok(0x02) => return Ok(Property::MessageExpiryInterval(parseU32(input, offset))), - Ok(0x03) => return Ok(Property::ContentType(parseString(input, offset))), - Ok(0x08) => return Ok(Property::ResponseTopic(parseString(input, offset))), - Ok(0x09) => return Ok(Property::CorrelationData(parseBinary(input, offset))), - Ok(0x0B) => return Ok(Property::SubscriptionIdentifier(parseVariableByteInt(input, offset))), - Ok(0x11) => return Ok(Property::SessionExpiryInterval(parseU32(input, offset))), - Ok(0x12) => return Ok(Property::AssignedClientIdentifier(parseString(input, offset))), - Ok(0x13) => return Ok(Property::ServerKeepAlive(parseU16(input, offset))), - Ok(0x15) => return Ok(Property::AuthenticationMethod(parseString(input, offset))), - Ok(0x16) => return Ok(Property::AuthenticationData(parseBinary(input, offset))), - Ok(0x17) => return Ok(Property::RequestProblemInformation(parseU8(input, offset))), - Ok(0x18) => return Ok(Property::WillDelayInterval(parseU32(input, offset))), - Ok(0x19) => return Ok(Property::RequestResponseInformation(parseU8(input, offset))), - Ok(0x1A) => return Ok(Property::ResponseInformation(parseString(input, offset))), - Ok(0x1C) => return Ok(Property::ServerReference(parseString(input, offset))), - Ok(0x1F) => return Ok(Property::ReasonString(parseString(input, offset))), - Ok(0x21) => return Ok(Property::ReceiveMaximum(parseU16(input, offset))), - Ok(0x22) => return Ok(Property::TopicAliasMaximum(parseU16(input, offset))), - Ok(0x23) => return Ok(Property::TopicAlias(parseU16(input, offset))), - Ok(0x24) => return Ok(Property::MaximumQoS(parseU8(input, offset))), - Ok(0x25) => return Ok(Property::RetainAvailable(parseU8(input, offset))), - Ok(0x26) => return Ok(Property::UserProperty(parseStringPair(input, offset))), - Ok(0x28) => return Ok(Property::WildcardSubscriptionAvailable(parseU8(input, offset))), - Ok(0x29) => return Ok(Property::SubscriptionIdentifierAvailable(parseU8(input, offset))), - Ok(0x2A) => return Ok(Property::SharedSubscriptionAvailable(parseU8(input, offset))), + Ok(0x01) => return Ok(Property::PayloadFormat(buff_reader.readU8())), + Ok(0x02) => return Ok(Property::MessageExpiryInterval(buff_reader.readU32())), + Ok(0x03) => return Ok(Property::ContentType(buff_reader.readString())), + Ok(0x08) => return Ok(Property::ResponseTopic(buff_reader.readString())), + Ok(0x09) => return Ok(Property::CorrelationData(buff_reader.readBinary())), + Ok(0x0B) => return Ok(Property::SubscriptionIdentifier(buff_reader.readVariableByteInt())), + Ok(0x11) => return Ok(Property::SessionExpiryInterval(buff_reader.readU32())), + Ok(0x12) => return Ok(Property::AssignedClientIdentifier(buff_reader.readString())), + Ok(0x13) => return Ok(Property::ServerKeepAlive(buff_reader.readU16())), + Ok(0x15) => return Ok(Property::AuthenticationMethod(buff_reader.readString())), + Ok(0x16) => return Ok(Property::AuthenticationData(buff_reader.readBinary())), + Ok(0x17) => return Ok(Property::RequestProblemInformation(buff_reader.readU8())), + Ok(0x18) => return Ok(Property::WillDelayInterval(buff_reader.readU32())), + Ok(0x19) => return Ok(Property::RequestResponseInformation(buff_reader.readU8())), + Ok(0x1A) => return Ok(Property::ResponseInformation(buff_reader.readString())), + Ok(0x1C) => return Ok(Property::ServerReference(buff_reader.readString())), + Ok(0x1F) => return Ok(Property::ReasonString(buff_reader.readString())), + Ok(0x21) => return Ok(Property::ReceiveMaximum(buff_reader.readU16())), + Ok(0x22) => return Ok(Property::TopicAliasMaximum(buff_reader.readU16())), + Ok(0x23) => return Ok(Property::TopicAlias(buff_reader.readU16())), + Ok(0x24) => return Ok(Property::MaximumQoS(buff_reader.readU8())), + Ok(0x25) => return Ok(Property::RetainAvailable(buff_reader.readU8())), + Ok(0x26) => return Ok(Property::UserProperty(buff_reader.readStringPair())), + Ok(0x28) => return Ok(Property::WildcardSubscriptionAvailable(buff_reader.readU8())), + Ok(0x29) => return Ok(Property::SubscriptionIdentifierAvailable(buff_reader.readU8())), + Ok(0x2A) => return Ok(Property::SharedSubscriptionAvailable(buff_reader.readU8())), Err(err) => return Err(err), _ => return Err(ProperyParseError::IdNotFound) } } -}*/ - +} \ No newline at end of file diff --git a/src/utils/buffer_reader.rs b/src/utils/buffer_reader.rs index 81d04d1..8a92c64 100644 --- a/src/utils/buffer_reader.rs +++ b/src/utils/buffer_reader.rs @@ -3,22 +3,45 @@ use crate::encoding::variable_byte_integer::VariableByteIntegerError; use core::str; use core::mem; +#[derive(Clone)] pub struct EncodedString<'a> { pub string: &'a str, pub len: u16 } +impl EncodedString<'_> { + pub fn len(&self) -> u16 { + return self.len + 2; + } +} + +#[derive(Clone)] pub struct BinaryData<'a> { pub bin: &'a [u8], pub len: u16 } +impl BinaryData<'_> { + pub fn len(&self) -> u16 { + return self.len + 2; + } +} + +#[derive(Clone)] pub struct StringPair<'a> { pub name: EncodedString<'a>, pub value: EncodedString<'a> } +impl StringPair<'_> { + pub fn len(&self) -> u16 { + let ln = self.name.len() + self.value.len(); + return ln; + } +} + #[derive(core::fmt::Debug)] +#[derive(Clone)] pub enum ProperyParseError { Utf8Error, IndexOutOfBounce,