Add property decoding
This commit is contained in:
parent
7446fcba04
commit
2f1c317e11
|
@ -14,14 +14,14 @@ pub enum VariableByteIntegerError {
|
||||||
DecodingError
|
DecodingError
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type VariableByteInteger = [u8; 4];
|
||||||
|
|
||||||
impl VariableByteIntegerEncoder {
|
impl VariableByteIntegerEncoder {
|
||||||
/// Encode function takes as parameter integer as u32 type and encodes
|
/// 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 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
|
/// 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.
|
/// 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<VariableByteInteger, VariableByteIntegerError> {
|
||||||
// General known informations from OASIS
|
// General known informations from OASIS
|
||||||
const MAX_ENCODABLE: u32 = 268435455;
|
const MAX_ENCODABLE: u32 = 268435455;
|
||||||
const MOD: u32 = 128;
|
const MOD: u32 = 128;
|
||||||
|
@ -59,7 +59,7 @@ impl VariableByteIntegerDecoder {
|
||||||
/// Decode function takes as paramater encoded integer represented
|
/// Decode function takes as paramater encoded integer represented
|
||||||
/// as array of 4 unsigned numbers of exactly 1 Byte each -> 4 Bytes maximal
|
/// 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.
|
/// same as maximal amount of bytes for variable byte encoding in MQTT.
|
||||||
pub fn decode(encoded: [u8; 4]) -> Result<u32, VariableByteIntegerError> {
|
pub fn decode(encoded: VariableByteInteger) -> Result<u32, VariableByteIntegerError> {
|
||||||
let mut multiplier: u32 = 1;
|
let mut multiplier: u32 = 1;
|
||||||
let mut ret: u32 = 0;
|
let mut ret: u32 = 0;
|
||||||
|
|
||||||
|
|
15
src/main.rs
15
src/main.rs
|
@ -1,5 +1,6 @@
|
||||||
use rust_mqtt::packet::mqtt_packet::Packet;
|
use rust_mqtt::packet::mqtt_packet::Packet;
|
||||||
use rust_mqtt::packet::packet_type::PacketType;
|
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::VariableByteIntegerEncoder;
|
||||||
use rust_mqtt::encoding::variable_byte_integer::VariableByteIntegerDecoder;
|
use rust_mqtt::encoding::variable_byte_integer::VariableByteIntegerDecoder;
|
||||||
|
|
||||||
|
@ -16,7 +17,12 @@ fn main() {
|
||||||
|
|
||||||
let mut txt = *b"abcde";
|
let mut txt = *b"abcde";
|
||||||
let mut payld = *b"xxxxx";
|
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 f = PacketType::from(0xA0);
|
||||||
let o: u8 = f.into();
|
let o: u8 = f.into();
|
||||||
|
@ -28,10 +34,15 @@ fn main() {
|
||||||
log::info!("{:02X?}", r);
|
log::info!("{:02X?}", r);
|
||||||
let d = VariableByteIntegerDecoder::decode(r);
|
let d = VariableByteIntegerDecoder::decode(r);
|
||||||
log::info!("Enum val: {}", o);
|
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");
|
log::info!("Hello world");
|
||||||
x.encode();
|
x.encode();
|
||||||
x.get_reason_code();
|
x.get_reason_code();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*fn test(tst: &str) {
|
||||||
|
log::info!("xx");
|
||||||
|
log::info!("Prvni: {}", )
|
||||||
|
}*/
|
|
@ -1,3 +1,4 @@
|
||||||
pub mod mqtt_packet;
|
pub mod mqtt_packet;
|
||||||
pub mod packet_type;
|
pub mod packet_type;
|
||||||
pub mod packet_builder;
|
pub mod packet_builder;
|
||||||
|
pub mod property;
|
|
@ -1,24 +1,28 @@
|
||||||
pub struct Packet<'a> {
|
pub struct Packet<'a> {
|
||||||
// 7 - 4 mqtt control packet type, 3-0 flagy
|
// 7 - 4 mqtt control packet type, 3-0 flagy
|
||||||
header_control: u8,
|
pub header_control: u8,
|
||||||
// 1 - 4 B
|
// 1 - 4 B lenght of variable header + len of payload
|
||||||
remain_len: u32,
|
pub remain_len: u32,
|
||||||
|
|
||||||
// variable header
|
// variable header
|
||||||
//optional
|
//optional prida se pouze u packetu ve kterych ma co delat
|
||||||
packet_identifier: u16,
|
pub packet_identifier: u16,
|
||||||
// property len
|
// property len
|
||||||
property_len: u32,
|
pub property_len: u32,
|
||||||
// properties
|
// properties
|
||||||
properties: &'a mut [u8],
|
pub properties: &'a mut [u8],
|
||||||
// Payload of message
|
// Payload of message
|
||||||
payload: &'a mut [u8]
|
pub payload: &'a mut [u8]
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Packet<'a> {
|
impl<'a> Packet<'a> {
|
||||||
pub fn new(header_control: u8, remain_len: u32, packet_identifier: u16, property_len: u32,
|
pub fn new(header_control: u8, remain_len: u32, packet_identifier: u16, property_len: u32,
|
||||||
properties: &'a mut [u8], payload: &'a mut [u8]) -> Self {
|
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) {
|
pub fn encode(&self) {
|
||||||
|
|
|
@ -1,11 +1,17 @@
|
||||||
use super::mqtt_packet::Packet;
|
use super::mqtt_packet::Packet;
|
||||||
use super::packet_type::PacketType;
|
use super::packet_type::PacketType;
|
||||||
|
|
||||||
|
// Je potreba vytvori
|
||||||
|
|
||||||
pub struct PacketBuilder<'a> {
|
pub struct PacketBuilder<'a> {
|
||||||
currentPacket: Packet<'a>,
|
currentPacket: Packet<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> PacketBuilder<'a> {
|
impl<'a> PacketBuilder<'a> {
|
||||||
|
pub fn new(packet: Packet<'a>) -> Self {
|
||||||
|
Self{ currentPacket: packet }
|
||||||
|
}
|
||||||
|
|
||||||
pub fn build(&self) -> &Packet<'a> {
|
pub fn build(&self) -> &Packet<'a> {
|
||||||
return &self.currentPacket;
|
return &self.currentPacket;
|
||||||
}
|
}
|
||||||
|
@ -14,7 +20,34 @@ impl<'a> PacketBuilder<'a> {
|
||||||
return &self.currentPacket;
|
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 | <PacketType as Into<u8>>::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...
|
||||||
}
|
}
|
||||||
}
|
}
|
182
src/packet/property.rs
Normal file
182
src/packet/property.rs
Normal file
|
@ -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<Self, ProperyParseError> 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<u8, ProperyParseError>),
|
||||||
|
MessageExpiryInterval(Result<u32, ProperyParseError>),
|
||||||
|
ContentType(Result<EncodedString<'a>, ProperyParseError>),
|
||||||
|
ResponseTopic(Result<EncodedString<'a>, ProperyParseError>),
|
||||||
|
CorrelationData(Result<BinaryData<'a>, ProperyParseError>),
|
||||||
|
SubscriptionIdentifier(Result<u32, VariableByteIntegerError>),
|
||||||
|
SessionExpiryInterval(Result<u32, ProperyParseError>),
|
||||||
|
AssignedClientIdentifier(Result<EncodedString<'a>, ProperyParseError>),
|
||||||
|
ServerKeepAlive(Result<u16, ProperyParseError>),
|
||||||
|
AuthenticationMethod(Result<EncodedString<'a>, ProperyParseError>),
|
||||||
|
AuthenticationData(Result<BinaryData<'a>, ProperyParseError>),
|
||||||
|
RequestProblemInformation(Result<u8, ProperyParseError>),
|
||||||
|
WillDelayInterval(Result<u32, ProperyParseError>),
|
||||||
|
RequestResponseInformation(Result<u8, ProperyParseError>),
|
||||||
|
ResponseInformation(Result<EncodedString<'a>, ProperyParseError>),
|
||||||
|
ServerReference(Result<EncodedString<'a>, ProperyParseError>),
|
||||||
|
ReasonString(Result<EncodedString<'a>, ProperyParseError>),
|
||||||
|
ReceiveMaximum(Result<u16, ProperyParseError>),
|
||||||
|
TopicAliasMaximum(Result<u16, ProperyParseError>),
|
||||||
|
TopicAlias(Result<u16, ProperyParseError>),
|
||||||
|
MaximumQoS(Result<u8, ProperyParseError>),
|
||||||
|
RetainAvailable(Result<u8, ProperyParseError>),
|
||||||
|
UserProperty(Result<StringPair<'a>, ProperyParseError>),
|
||||||
|
MaximumPacketSize(Result<u32, ProperyParseError>),
|
||||||
|
WildcardSubscriptionAvailable(Result<u8, ProperyParseError>),
|
||||||
|
SubscriptionIdentifierAvailable(Result<u8, ProperyParseError>),
|
||||||
|
SharedSubscriptionAvailable(Result<u8, ProperyParseError>)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl<'a> Decode<'a> for Property<'a> {
|
||||||
|
fn decode(input: &'a [u8], offset: &'a mut usize) -> Result<Self, ProperyParseError> {
|
||||||
|
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<u32, VariableByteIntegerError> {
|
||||||
|
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<u32, ProperyParseError> {
|
||||||
|
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<u16, ProperyParseError> {
|
||||||
|
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<u8, ProperyParseError> {
|
||||||
|
let ret: u8 = input[*offset];
|
||||||
|
*offset = *offset + 1;
|
||||||
|
return Ok(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parseString<'a>(input: &'a [u8], offset: & mut usize) -> Result<EncodedString<'a>, 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<BinaryData<'a>, 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<StringPair<'a>, 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<u8> 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}*/
|
Loading…
Reference in New Issue
Block a user