diff --git a/src/encoding/variable_byte_integer.rs b/src/encoding/variable_byte_integer.rs index 025a602..ecb2039 100644 --- a/src/encoding/variable_byte_integer.rs +++ b/src/encoding/variable_byte_integer.rs @@ -14,14 +14,14 @@ pub enum VariableByteIntegerError { DecodingError } - +pub type VariableByteInteger = [u8; 4]; impl VariableByteIntegerEncoder { /// Encode function takes as parameter integer as u32 type and encodes /// this integer into maximal 4 Bytes. MSb of each Byte is controll bit. /// This bit is saying if there is continuing Byte in stream or not, this way /// we can effectively use 1 to 4 Bytes based in integer len. - pub fn encode(mut target: u32) -> Result<[u8; 4], VariableByteIntegerError> { + pub fn encode(mut target: u32) -> Result { // General known informations from OASIS const MAX_ENCODABLE: u32 = 268435455; const MOD: u32 = 128; @@ -59,7 +59,7 @@ impl VariableByteIntegerDecoder { /// Decode function takes as paramater encoded integer represented /// as array of 4 unsigned numbers of exactly 1 Byte each -> 4 Bytes maximal /// same as maximal amount of bytes for variable byte encoding in MQTT. - pub fn decode(encoded: [u8; 4]) -> Result { + pub fn decode(encoded: VariableByteInteger) -> Result { let mut multiplier: u32 = 1; let mut ret: u32 = 0; diff --git a/src/main.rs b/src/main.rs index 14916f2..369b0cc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,6 @@ use rust_mqtt::packet::mqtt_packet::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; @@ -16,7 +17,12 @@ fn main() { let mut txt = *b"abcde"; let mut payld = *b"xxxxx"; + let packet = Packet::clean(&mut txt, &mut payld); + let mut packet_builder = PacketBuilder::new(packet); + packet_builder.addPacketType(PacketType::Publish); + /*let s: str = "AAAAAA"; + test(&s);*/ let f = PacketType::from(0xA0); let o: u8 = f.into(); @@ -28,10 +34,15 @@ fn main() { log::info!("{:02X?}", r); let d = VariableByteIntegerDecoder::decode(r); log::info!("Enum val: {}", o); - let x = Packet::new( l, y, z, p, &mut txt, &mut payld ); + let x = Packet::new( l, 0, z, 0, &mut txt, &mut payld ); log::info!("Hello world"); x.encode(); x.get_reason_code(); -} \ No newline at end of file +} + +/*fn test(tst: &str) { + log::info!("xx"); + log::info!("Prvni: {}", ) +}*/ \ No newline at end of file diff --git a/src/packet/mod.rs b/src/packet/mod.rs index 198b2a0..1ede481 100644 --- a/src/packet/mod.rs +++ b/src/packet/mod.rs @@ -1,3 +1,4 @@ pub mod mqtt_packet; pub mod packet_type; -pub mod packet_builder; \ No newline at end of file +pub mod packet_builder; +pub mod property; \ No newline at end of file diff --git a/src/packet/mqtt_packet.rs b/src/packet/mqtt_packet.rs index fc0ccc1..25f52b7 100644 --- a/src/packet/mqtt_packet.rs +++ b/src/packet/mqtt_packet.rs @@ -1,24 +1,28 @@ pub struct Packet<'a> { // 7 - 4 mqtt control packet type, 3-0 flagy - header_control: u8, - // 1 - 4 B - remain_len: u32, + pub header_control: u8, + // 1 - 4 B lenght of variable header + len of payload + pub remain_len: u32, // variable header - //optional - packet_identifier: u16, + //optional prida se pouze u packetu ve kterych ma co delat + pub packet_identifier: u16, // property len - property_len: u32, + pub property_len: u32, // properties - properties: &'a mut [u8], + pub properties: &'a mut [u8], // Payload of message - payload: &'a mut [u8] + 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} + Self { header_control, remain_len, packet_identifier, property_len, properties, payload } + } + + 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 encode(&self) { diff --git a/src/packet/packet_builder.rs b/src/packet/packet_builder.rs index 839cbe0..263b7f1 100644 --- a/src/packet/packet_builder.rs +++ b/src/packet/packet_builder.rs @@ -1,11 +1,17 @@ use super::mqtt_packet::Packet; use super::packet_type::PacketType; +// Je potreba vytvori + pub struct PacketBuilder<'a> { currentPacket: Packet<'a>, } impl<'a> PacketBuilder<'a> { + pub fn new(packet: Packet<'a>) -> Self { + Self{ currentPacket: packet } + } + pub fn build(&self) -> &Packet<'a> { return &self.currentPacket; } @@ -14,7 +20,34 @@ impl<'a> PacketBuilder<'a> { return &self.currentPacket; } - pub fn addPacketType(packet_type: PacketType) { + 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 addFlags(& mut self, dup: bool, qos: u8, retain: bool) { + let cur_type: u8 = self.currentPacket.header_control & 0xF0; + if cur_type != 0x30 { + log::error!("Cannot add flags into packet with other than PUBLISH type"); + return; + } + let mut flags: u8 = 0x00; + if dup { + flags = flags | 0x08; + } + if qos == 1 { + flags = flags | 0x02; + } + if qos == 2 { + flags = flags | 0x04; + } + if retain { + flags = flags | 0x01; + } + self.currentPacket.header_control = cur_type | flags; + } + + pub fn completePacket(& mut self) { + // Tutaj se cely packet dokonci - spocita se remaining len co chybi v hlavicce atd... } } \ No newline at end of file diff --git a/src/packet/property.rs b/src/packet/property.rs new file mode 100644 index 0000000..c081f66 --- /dev/null +++ b/src/packet/property.rs @@ -0,0 +1,182 @@ +use crate::encoding::variable_byte_integer::VariableByteIntegerDecoder; +use crate::encoding::variable_byte_integer::VariableByteIntegerError; +use core::str; + + +pub trait Decode<'a> { + fn decode(input: &'a [u8], offset: &'a mut usize) -> Result where Self: Sized; +} + +pub struct EncodedString<'a> { + pub string: &'a str, + pub len: u16 +} + +pub struct BinaryData<'a> { + pub bin: &'a [u8], + pub len: u16 +} + +pub struct StringPair<'a> { + pub name: EncodedString<'a>, + pub value: EncodedString<'a> +} + +#[derive(core::fmt::Debug)] +pub enum ProperyParseError { + Utf8Error, + IndexOutOfBounce, + VariableByteIntegerError, + IdNotFound +} + +pub enum Property<'a> { + PayloadFormat(Result), + MessageExpiryInterval(Result), + ContentType(Result, ProperyParseError>), + ResponseTopic(Result, ProperyParseError>), + CorrelationData(Result, ProperyParseError>), + SubscriptionIdentifier(Result), + SessionExpiryInterval(Result), + AssignedClientIdentifier(Result, ProperyParseError>), + ServerKeepAlive(Result), + AuthenticationMethod(Result, ProperyParseError>), + AuthenticationData(Result, ProperyParseError>), + RequestProblemInformation(Result), + WillDelayInterval(Result), + RequestResponseInformation(Result), + ResponseInformation(Result, ProperyParseError>), + ServerReference(Result, ProperyParseError>), + ReasonString(Result, ProperyParseError>), + ReceiveMaximum(Result), + TopicAliasMaximum(Result), + TopicAlias(Result), + MaximumQoS(Result), + RetainAvailable(Result), + UserProperty(Result, ProperyParseError>), + MaximumPacketSize(Result), + WildcardSubscriptionAvailable(Result), + SubscriptionIdentifierAvailable(Result), + SharedSubscriptionAvailable(Result) +} + + +impl<'a> Decode<'a> for Property<'a> { + fn decode(input: &'a [u8], offset: &'a mut usize) -> Result { + let propertyIdentifier = parseU8(input, offset); + 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))), + Err(err) => return Err(err), + _ => return Err(ProperyParseError::IdNotFound) + } + } +} + +fn parseVariableByteInt<'a>(input: &'a [u8], offset: & mut usize) -> Result { + let variable_byte_integer: [u8; 4] = [input[*offset], input[*offset + 1], input[*offset + 2], input[*offset + 3]]; + *offset = *offset + 4; + return VariableByteIntegerDecoder::decode(variable_byte_integer); +} + +fn parseU32<'a>(input: &'a [u8], offset: & mut usize) -> Result { + let ret: u32 = (((input[*offset] as u32) << 24) | ((input[*offset + 1] as u32) << 16) | ((input[*offset + 2] as u32) << 8) | (input[*offset + 3] as u32)) as u32; + *offset = *offset + 4; + return Ok(ret); +} + +fn parseU16<'a>(input: &'a [u8], offset: & mut usize) -> Result { + let ret: u16 = (((input[*offset] as u16) << 8) | (input[*offset + 1] as u16)) as u16; + *offset = *offset + 2; + return Ok(ret); +} + +fn parseU8<'a>(input: &'a [u8], offset: & mut usize) -> Result { + let ret: u8 = input[*offset]; + *offset = *offset + 1; + return Ok(ret); +} + +fn parseString<'a>(input: &'a [u8], offset: & mut usize) -> Result, ProperyParseError> { + let len = parseU16(input, offset); + match len { + Err(err) => return Err(err), + _ => log::debug!("[parseString] let not parsed") + } + let len_res = len.unwrap(); + let res_str = str::from_utf8(&(input[*offset..(*offset + len_res as usize)])); + if res_str.is_err() { + log::error!("Could not parse utf-8 string"); + return Err(ProperyParseError::Utf8Error); + } + return Ok(EncodedString { string: res_str.unwrap(), len: len_res }); +} + +//TODO: Index out of bounce err !!!!! +fn parseBinary<'a>(input: &'a [u8], offset: & mut usize) -> Result, ProperyParseError> { + let len = parseU16(input, offset); + match len { + Err(err) => return Err(err), + _ => log::debug!("[parseBinary] let not parsed") + } + let len_res = len.unwrap(); + let res_bin = &(input[*offset..(*offset + len_res as usize)]); + return Ok(BinaryData { bin: res_bin, len: len_res }); +} + +fn parseStringPair<'a>(input: &'a [u8], offset: & mut usize) -> Result, ProperyParseError> { + let name = parseString(input, offset); + match name { + Err(err) => return Err(err), + _ => log::debug!("[String pair] name not parsed") + } + let value = parseString(input, offset); + match value { + Err(err) => return Err(err), + _ => log::debug!("[String pair] value not parsed") + } + return Ok(StringPair { name: name.unwrap(), value: value.unwrap() }); +} + +/*impl<'a> From for Property<'a> { + fn from(orig: u8) -> Self { + match orig { + 0x01 => return Property::PayloadFormat, + 0x02 => return Property::MessageExpiryInterval, + 0x03 => return Property::ContentType, + 0x08 => return Property::ResponseTopic, + 0x09 => return Property::CorrelationData, + 0x0B => return Property::SubscriptionIdentifier, + 0x11 => return Property::SessionExpiryInterval, + 0x12 => return Property::AssignedClientIdentifier, + 0x13 => return Property::ServerKeepAlive, + 0x15 => return Property::AuthenticationMethod, + 0x16 => return Property::AuthenticationMethod + _ => return Property::TopicAlias + } + } +}*/ \ No newline at end of file