fix: fixing Property mapping

Fixed UserProperty
Fixed Payload Properties
This commit is contained in:
brenodetomini
2024-02-02 13:46:45 -03:00
parent 216b7e27d3
commit 5454051dfb
29 changed files with 857 additions and 520 deletions

236
.clang-format Normal file
View File

@@ -0,0 +1,236 @@
---
Language: Cpp
# BasedOnStyle: LLVM
AccessModifierOffset: -2
AlignAfterOpenBracket: Align
AlignArrayOfStructures: None
AlignConsecutiveAssignments:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
PadOperators: true
AlignConsecutiveBitFields:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
PadOperators: false
AlignConsecutiveDeclarations:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
PadOperators: false
AlignConsecutiveMacros:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
PadOperators: false
AlignConsecutiveShortCaseStatements:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCaseColons: false
AlignEscapedNewlines: Right
AlignOperands: Align
AlignTrailingComments:
Kind: Always
OverEmptyLines: 0
AllowAllArgumentsOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: Never
AllowShortCaseLabelsOnASingleLine: false
AllowShortEnumsOnASingleLine: true
AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: Never
AllowShortLambdasOnASingleLine: All
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: MultiLine
AttributeMacros:
- __capability
BinPackArguments: true
BinPackParameters: true
BitFieldColonSpacing: Both
BraceWrapping:
AfterCaseLabel: false
AfterClass: false
AfterControlStatement: Never
AfterEnum: false
AfterExternBlock: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
BeforeCatch: false
BeforeElse: false
BeforeLambdaBody: false
BeforeWhile: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakAfterAttributes: Never
BreakAfterJavaFieldAnnotations: false
BreakArrays: true
BreakBeforeBinaryOperators: None
BreakBeforeConceptDeclarations: Always
BreakBeforeBraces: Attach
BreakBeforeInlineASMColon: OnlyMultiline
BreakBeforeTernaryOperators: true
BreakConstructorInitializers: BeforeColon
BreakInheritanceList: BeforeColon
BreakStringLiterals: true
ColumnLimit: 256
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
EmptyLineAfterAccessModifier: Never
EmptyLineBeforeAccessModifier: LogicalBlock
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IfMacros:
- KJ_IF_MAYBE
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
Priority: 2
SortPriority: 0
CaseSensitive: false
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
Priority: 3
SortPriority: 0
CaseSensitive: false
- Regex: '.*'
Priority: 1
SortPriority: 0
CaseSensitive: false
IncludeIsMainRegex: '(Test)?$'
IncludeIsMainSourceRegex: ''
IndentAccessModifiers: false
IndentCaseBlocks: false
IndentCaseLabels: false
IndentExternBlock: AfterExternBlock
IndentGotoLabels: true
IndentPPDirectives: None
IndentRequiresClause: true
IndentWidth: 2
IndentWrappedFunctionNames: false
InsertBraces: false
InsertNewlineAtEOF: false
InsertTrailingCommas: None
IntegerLiteralSeparator:
Binary: 0
BinaryMinDigits: 0
Decimal: 0
DecimalMinDigits: 0
Hex: 0
HexMinDigits: 0
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: true
KeepEmptyLinesAtEOF: false
LambdaBodyIndentation: Signature
LineEnding: DeriveLF
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 2
ObjCBreakBeforeNestedBlockParam: true
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PackConstructorInitializers: BinPack
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakOpenParenthesis: 0
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyIndentedWhitespace: 0
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Right
PPIndentWidth: -1
QualifierAlignment: Leave
ReferenceAlignment: Pointer
ReflowComments: true
RemoveBracesLLVM: false
RemoveParentheses: Leave
RemoveSemicolon: false
RequiresClausePosition: OwnLine
RequiresExpressionIndentation: OuterScope
SeparateDefinitionBlocks: Leave
ShortNamespaceLines: 1
SortIncludes: CaseSensitive
SortJavaStaticImport: Before
SortUsingDeclarations: LexicographicNumeric
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: true
SpaceAroundPointerQualifiers: Default
SpaceBeforeAssignmentOperators: true
SpaceBeforeCaseColon: false
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeJsonColon: false
SpaceBeforeParens: ControlStatements
SpaceBeforeParensOptions:
AfterControlStatements: true
AfterForeachMacros: true
AfterFunctionDefinitionName: false
AfterFunctionDeclarationName: false
AfterIfMacros: true
AfterOverloadedOperator: false
AfterRequiresInClause: false
AfterRequiresInExpression: false
BeforeNonEmptyParentheses: false
SpaceBeforeRangeBasedForLoopColon: true
SpaceBeforeSquareBrackets: false
SpaceInEmptyBlock: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: Never
SpacesInContainerLiterals: true
SpacesInLineCommentPrefix:
Minimum: 1
Maximum: -1
SpacesInParens: Never
SpacesInParensOptions:
InCStyleCasts: false
InConditionalStatements: false
InEmptyParentheses: false
Other: false
SpacesInSquareBrackets: false
Standard: Latest
StatementAttributeLikeMacros:
- Q_EMIT
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
TabWidth: 8
UseTab: Never
VerilogBreakBetweenInstancePorts: true
WhitespaceSensitiveMacros:
- BOOST_PP_STRINGIZE
- CF_SWIFT_NAME
- NS_SWIFT_NAME
- PP_STRINGIZE
- STRINGIZE
...

View File

@@ -6,7 +6,7 @@ target_sources(libmqttd
PUBLIC ${HPP_FILES_LOCAL}
)
add_subdirectory(packet_interface)
add_subdirectory(control_packet)
add_subdirectory(connection)
target_include_directories(libmqttd PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})

View File

@@ -1,63 +1,39 @@
#include "connect_packet.hpp"
#include "binary_data.hpp"
#include "property.hpp"
#include "utf8_string.hpp"
#include "utilities.hpp"
#include "variable_header.hpp"
#include <iostream>
#include <iterator>
#include <stdexcept>
ConnectPacket::ConnectPacket(PacketInterface &packet)
: PacketInterface(packet) {
set_variable_header();
ConnectPacket::ConnectPacket(ControlPacket &packet) : ControlPacket(packet) {
parse_variable_header();
parse_payload();
}
ConnectPacket::~ConnectPacket() {}
ConnectPacket::ConnectPacket(std::vector<std::byte> data)
: PacketInterface(data) {
set_variable_header();
}
ConnectPacket::ConnectPacket(std::vector<std::byte> data) : ControlPacket(data) { parse_variable_header(); }
void ConnectPacket::set_protocol_name() {
if (raw_data.size() < 8)
throw std::range_error("Received data is too small for a connect package");
void ConnectPacket::parse_variable_header() {
auto protocol_name_start_byte = this->get_variable_header_start_byte();
this->protocol_name = utf8_str(protocol_name_start_byte);
if (this->protocol_name.data() != "MQTT")
throw std::invalid_argument("Wrong protocol name. Expected MQTT and received " + this->protocol_name.data());
auto protocol_version_start_byte = std::next(protocol_name_start_byte, 2 + protocol_name.size());
this->protocol_version = utilities::types::get_fixed_size_integer<uint8_t>(protocol_version_start_byte);
uint16_t protocol_name_length = utilities::types::get_fixed_size_integer<uint16_t>(std::next(raw_data.begin(), variable_header_start));
auto connection_flags_start_byte = std::next(protocol_version_start_byte);
this->connection_flags = *connection_flags_start_byte;
// 2 Bytes are the MSB and LSB of protocol_name_length
protocol_name_start_byte = variable_header_start + 2;
auto start_iter = std::next(raw_data.begin(), protocol_name_start_byte);
auto end_iter = std::next(start_iter, protocol_name_length);
std::string result(reinterpret_cast<const char *>(&(*start_iter)),
std::distance(start_iter, end_iter));
this->protocol_name = result;
auto keepalive_start_byte = std::next(connection_flags_start_byte);
this->keepalive = utilities::types::get_fixed_size_integer<uint16_t>(keepalive_start_byte);
if (this->protocol_name != "MQTT")
throw std::invalid_argument(
"Wrong protocol name. Expected MQTT and received " +
this->protocol_name);
}
void ConnectPacket::set_protocol_version() {
protocol_version_start_byte = protocol_name_start_byte + protocol_name.size();
this->protocol_version =
std::to_integer<uint8_t>(raw_data[protocol_version_start_byte]);
}
void ConnectPacket::set_connection_flags() {
connection_flags_start_byte = protocol_version_start_byte + 1;
this->connection_flags = raw_data[connection_flags_start_byte];
}
void ConnectPacket::set_keepalive() {
keepalive_start_byte = connection_flags_start_byte + 1;
this->keepalive = utilities::types::get_fixed_size_integer<uint16_t>(std::next(raw_data.begin(), keepalive_start_byte));
}
void ConnectPacket::set_variable_header() {
set_protocol_name();
set_protocol_version();
set_connection_flags();
set_keepalive();
auto header_properties_start = std::next(raw_data.begin(), keepalive_start_byte+2);
PacketInterface::set_variable_header_properties(header_properties_start);
auto header_properties_start_byte = std::next(keepalive_start_byte, sizeof(this->keepalive));
std::tie(this->variable_header->properties, payload_start_byte) = parse_mqtt_properties(header_properties_start_byte);
}
ConnectionFlagValue ConnectPacket::get_connection_flag(ConnectFlags flag) {
@@ -71,18 +47,76 @@ ConnectionFlagValue ConnectPacket::get_connection_flag(ConnectFlags flag) {
return qos;
}
return static_cast<bool>(
utilities::bit::get(connection_flags_value, flag_pos));
return static_cast<bool>(utilities::bit::get(connection_flags_value, flag_pos));
}
std::string ConnectPacket::to_string() {
std::ostringstream packet_str;
packet_str << PacketInterface::to_string();
packet_str << "Protocol is " << this->protocol_name << std::endl;
packet_str << "Protocol Version is " << std::to_string(this->protocol_version)
<< std::endl;
packet_str << "KeepAlive is " << this->keepalive << std::endl;
packet_str << *(this->variable_header) << std::endl;
packet_str << ControlPacket::to_string();
packet_str << "\t"
<< "\u21B3"
<< "Variable Hedaer" << std::endl;
packet_str << "\t\t"
<< "\u21B3"
<< "Protocol = " << this->protocol_name << std::endl;
packet_str << "\t\t"
<< "\u21B3"
<< "Protocol Version = " << std::to_string(this->protocol_version) << std::endl;
packet_str << "\t\t"
<< "\u21B3"
<< "Protocol Flags = " << this->connection_flags << std::endl;
packet_str << "\t\t"
<< "\u21B3"
<< "KeepAlive = " << this->keepalive << std::endl;
packet_str << *(this->variable_header);
// Payload
packet_str << "\t"
<< "\u21B3"
<< "Payload" << std::endl;
packet_str << "\t\t"
<< "\u21B3"
<< "Client ID = " << this->payload.client_id << std::endl;
if (std::get<bool>(get_connection_flag(ConnectFlags::WILL_FLAG))) {
packet_str << this->payload.lastwill.properties;
packet_str << "\t\t"
<< "\u21B3"
<< "Last Will Topic = " << this->payload.lastwill.will_topic << std::endl;
}
if (std::get<bool>(get_connection_flag(ConnectFlags::USERNAME_FLAG))) {
packet_str << "\t\t"
<< "\u21B3"
<< "Username = " << this->payload.username << std::endl;
}
if (std::get<bool>(get_connection_flag(ConnectFlags::PASSWORD_FLAG))) {
packet_str << "\t\t"
<< "\u21B3"
<< "Password = " << this->payload.password << std::endl;
}
return packet_str.str();
}
void ConnectPacket::parse_payload() {
this->payload.client_id = utf8_str(payload_start_byte);
auto next_field_start_byte = std::next(payload_start_byte, 2 + this->payload.client_id.size());
if (std::get<bool>(get_connection_flag(ConnectFlags::WILL_FLAG))) {
std::tie(this->payload.lastwill.properties, next_field_start_byte) = parse_mqtt_properties(next_field_start_byte);
this->payload.lastwill.will_topic = utf8_str(next_field_start_byte);
next_field_start_byte = std::next(next_field_start_byte, 2 + this->payload.lastwill.will_topic.size());
this->payload.lastwill.will_payload = binary_data(next_field_start_byte);
next_field_start_byte = std::next(next_field_start_byte, 2 + this->payload.lastwill.will_payload.size());
}
if (std::get<bool>(get_connection_flag(ConnectFlags::USERNAME_FLAG))) {
this->payload.username = utf8_str(next_field_start_byte);
next_field_start_byte = std::next(next_field_start_byte, 2 + this->payload.username.size());
}
if (std::get<bool>(get_connection_flag(ConnectFlags::PASSWORD_FLAG))) {
this->payload.password = binary_data(next_field_start_byte);
next_field_start_byte = std::next(next_field_start_byte, 2 + this->payload.password.size());
}
}

View File

@@ -1,10 +1,13 @@
#ifndef INCLUDE_CONNECTION_CONNECT_PACKET_HPP_
#define INCLUDE_CONNECTION_CONNECT_PACKET_HPP_
#include <utilities.hpp>
#include <packet_interface.hpp>
#include <vector>
#include "utf8_string.hpp"
#include <control_packet.hpp>
#include <cstddef>
#include <last_will.hpp>
#include <stdexcept>
#include <utilities.hpp>
#include <vector>
enum ConnectFlags : uint16_t {
RESERVERD = 0,
@@ -18,9 +21,9 @@ enum ConnectFlags : uint16_t {
using ConnectionFlagValue = std::variant<bool, uint8_t>;
class ConnectPacket : public PacketInterface {
class ConnectPacket : public ControlPacket {
public:
ConnectPacket(PacketInterface &);
ConnectPacket(ControlPacket &);
ConnectPacket(std::vector<std::byte>);
~ConnectPacket();
ConnectionFlagValue get_connection_flag(ConnectFlags flag);
@@ -28,24 +31,20 @@ public:
std::string to_string() final;
private:
void set_protocol_name();
uint8_t protocol_name_start_byte;
std::string protocol_name;
void set_protocol_version();
uint8_t protocol_version_start_byte;
utf8_str protocol_name;
std::uint8_t protocol_version;
void set_connection_flags();
uint8_t connection_flags_start_byte;
std::byte connection_flags;
void set_keepalive();
uint8_t keepalive_start_byte;
std::uint16_t keepalive;
void set_variable_header() final;
void populate_payload() final {};
std::vector<std::byte>::const_iterator payload_start_byte;
void parse_variable_header() final;
void parse_payload() final;
struct {
utf8_str client_id;
LastWill lastwill;
utf8_str username;
binary_data password;
} payload;
};
#endif // INCLUDE_CONNECTION_CONNECT_PACKET_HPP_

View File

@@ -0,0 +1,17 @@
#ifndef INCLUDE_CONNECTION_LAST_WILL_HPP_
#define INCLUDE_CONNECTION_LAST_WILL_HPP_
#include <property.hpp>
#include <variable_byte_int.hpp>
#include <binary_data.hpp>
#include <utf8_string.hpp>
struct LastWill {
MQTTProperties properties;
utf8_str will_topic;
binary_data will_payload;
};
using last_will = LastWill;
#endif // INCLUDE_CONNECTION_LAST_WILL_HPP_

View File

@@ -0,0 +1,43 @@
#include "control_packet.hpp"
#include "variable_header.hpp"
#include <cstddef>
#include <vector>
#include <sstream>
ControlPacket::ControlPacket(const std::vector<std::byte> &data) {
this->raw_data = data;
unsigned char fixed_header_packet_type = (static_cast<unsigned char>(raw_data[0]) >> 4) & 0x0F;
this->fixed_header.packet_type = PacketType(fixed_header_packet_type);
unsigned char fixed_header_packet_flags = (static_cast<unsigned char>(raw_data[0]) & 0x0F);
this->fixed_header.packet_flags = fixed_header_packet_flags;
auto it = data.begin() + 1;
this->fixed_header.remaining_length = int_vb(it);
this->variable_header.reset(new VariableHeader);
}
ControlPacket::ControlPacket(ControlPacket &packet) {
this->fixed_header.packet_type = packet.fixed_header.packet_type;
this->fixed_header.packet_flags = packet.fixed_header.packet_flags;
this->fixed_header.remaining_length = packet.fixed_header.remaining_length;
this->variable_header = std::move(packet.variable_header);
this->raw_data = packet.raw_data;
}
std::string ControlPacket::to_string() {
std::ostringstream packet_str;
packet_str << std::endl;
packet_str << "Packet Type = " << this->get_packet_type() << std::endl;
packet_str << "\t"
<< "\u21B3"
<< "Packet flags = " << this->get_packet_flags() << std::endl;
packet_str << "\t"
<< "\u21B3"
<< "Remaining length = " << this->fixed_header.remaining_length << std::endl;
return packet_str.str();
}

View File

@@ -1,5 +1,5 @@
#ifndef INCLUDE_NETWORK_PACKET_INTERFACE_HPP_
#define INCLUDE_NETWORK_PACKET_INTERFACE_HPP_
#ifndef INCLUDE_NETWORK_CONTROL_PACKET_HPP_
#define INCLUDE_NETWORK_CONTROL_PACKET_HPP_
#include "fixed_header.hpp"
#include "variable_header.hpp"
@@ -10,11 +10,11 @@
#include <sstream>
class PacketInterface {
class ControlPacket {
public:
PacketInterface(const std::vector<std::byte> &);
PacketInterface(PacketInterface &);
~PacketInterface() = default;
ControlPacket(const std::vector<std::byte> &);
ControlPacket(ControlPacket &);
~ControlPacket() = default;
inline uint length() const {
return sizeof(this->fixed_header) + this->fixed_header.remaining_length;
@@ -31,13 +31,13 @@ public:
protected:
std::vector<std::byte> raw_data;
fixed_header_t fixed_header;
std::unique_ptr<variable_header_t> variable_header;
uint variable_header_start;
FixedHeader fixed_header;
std::unique_ptr<VariableHeader> variable_header;
virtual void parse_variable_header(){};
virtual void parse_payload(){};
virtual void set_variable_header(){};
virtual void set_variable_header_properties(const std::vector<std::byte>::const_iterator &it);
virtual void populate_payload(){};
inline auto get_variable_header_start_byte() const { return std::next(raw_data.begin(), 1 + fixed_header.remaining_length.size()); };
};
#endif // INCLUDE_NETWORK_PACKET_INTERFACE_HPP_
#endif // INCLUDE_NETWORK_CONTROL_PACKET_HPP_

View File

@@ -5,7 +5,6 @@
#include <bitset>
#include <ostream>
typedef struct fixed_header fixed_header_t;
enum class PacketType : uint32_t {
RESERVED = 0,
@@ -28,7 +27,7 @@ enum class PacketType : uint32_t {
std::ostream& operator<<(std::ostream& lhs, PacketType p);
struct fixed_header {
struct FixedHeader {
PacketType packet_type = PacketType(0);
std::bitset<4> packet_flags = {0};
int_vb remaining_length = int_vb(0);

View File

@@ -0,0 +1,323 @@
#include "utf8_string_pair.hpp"
#include <cstddef>
#include <property.hpp>
#include <tuple>
#include <vector>
struct VariantPrinter {
std::ostream &os;
template <typename T> void operator()(const T &value) const { os << value; }
};
std::ostream &operator<<(std::ostream &os, const PropertyIdentifier &value) {
switch (value) {
case PropertyIdentifier::PAYLOAD_FORMAT_INDICATOR:
os << "PAYLOAD_FORMAT_INDICATOR";
break;
case PropertyIdentifier::MESSAGE_EXPIRY_INTERVAL:
os << "MESSAGE_EXPIRY_INTERVAL";
break;
case PropertyIdentifier::CONTENT_TYPE:
os << "CONTENT_TYPE";
break;
case PropertyIdentifier::RESPONSE_TOPIC:
os << "RESPONSE_TOPIC";
break;
case PropertyIdentifier::CORRELATION_DATA:
os << "CORRELATION_DATA";
break;
case PropertyIdentifier::SUBSCRIPTION_IDENTIFIER:
os << "SUBSCRIPTION_IDENTIFIER";
break;
case PropertyIdentifier::SESSION_EXPIRY_INTERVAL:
os << "SESSION_EXPIRY_INTERVAL";
break;
case PropertyIdentifier::ASSIGNED_CLIENT_IDENTIFIER:
os << "ASSIGNED_CLIENT_IDENTIFIER";
break;
case PropertyIdentifier::SERVER_KEEP_ALIVE:
os << "SERVER_KEEP_ALIVE";
break;
case PropertyIdentifier::AUTHENTICATION_METHOD:
os << "AUTHENTICATION_METHOD";
break;
case PropertyIdentifier::AUTHENTICATION_DATA:
os << "AUTHENTICATION_DATA";
break;
case PropertyIdentifier::REQUEST_PROBLEM_INFORMATION:
os << "REQUEST_PROBLEM_INFORMATION";
break;
case PropertyIdentifier::WILL_DELAY_INTERVAL:
os << "WILL_DELAY_INTERVAL";
break;
case PropertyIdentifier::REQUEST_RESPONSE_INFORMATION:
os << "REQUEST_RESPONSE_INFORMATION";
break;
case PropertyIdentifier::RESPONSE_INFORMATION:
os << "RESPONSE_INFORMATION";
break;
case PropertyIdentifier::SERVER_REFERENCE:
os << "SERVER_REFERENCE";
break;
case PropertyIdentifier::REASON_STRING:
os << "REASON_STRING";
break;
case PropertyIdentifier::RECEIVE_MAXIMUM:
os << "RECEIVE_MAXIMUM";
break;
case PropertyIdentifier::TOPIC_ALIAS_MAXIMUM:
os << "TOPIC_ALIAS_MAXIMUM";
break;
case PropertyIdentifier::TOPIC_ALIAS:
os << "TOPIC_ALIAS";
break;
case PropertyIdentifier::MAXIMUM_QOS:
os << "MAXIMUM_QOS";
break;
case PropertyIdentifier::RETAIN_AVAILABLE:
os << "RETAIN_AVAILABLE";
break;
case PropertyIdentifier::USER_PROPERTY:
os << "USER_PROPERTY";
break;
case PropertyIdentifier::MAXIMUM_PACKET_SIZE:
os << "MAXIMUM_PACKET_SIZE";
break;
case PropertyIdentifier::WILDCARD_SUBSCRIPTION_AVAILABLE:
os << "WILDCARD_SUBSCRIPTION_AVAILABLE";
break;
case PropertyIdentifier::SUBSCRIPTION_IDENTIFIER_AVAILABLE:
os << "SUBSCRIPTION_IDENTIFIER_AVAILABLE";
break;
case PropertyIdentifier::SHARED_SUBSCRIPTION_AVAILABLE:
os << "SHARED_SUBSCRIPTION_AVAILABLE";
break;
default:
os << "Unknown PropertyIdentifier";
break;
}
return os;
}
std::ostream &operator<<(std::ostream &os, const std::byte &value) {
os << std::to_string(std::to_integer<uint8_t>(value));
return os;
}
std::ostream &operator<<(std::ostream &os, const PropertyValue &value) {
std::visit(VariantPrinter{os}, value);
return os;
}
std::ostream &operator<<(std::ostream &os, const UserProperty &value) {
UserProperty queue = value;
os << std::endl;
while(!queue.empty()) {
UTF8StringPair queue_value = queue.front();
os << "\t\t\t\t\u21B3(" << queue_value.get_key() << ", " << queue_value.get_value() << ")" << std::endl;
queue.pop();
}
return os;
}
std::ostream &operator<<(std::ostream &os, const PropertyMap &value) {
for (const auto &[property_key, property_value] : value) {
os << "\t\t\t\u21B3" << property_key << ": " << property_value << std::endl;
}
return os;
}
std::ostream &operator<<(std::ostream &os, const MQTTProperties &value) {
os << "\t\t\u21B3"
<< "Property Length = " << value.length << std::endl;
os << "\t\t\u21B3"
<< "Property Values" << std::endl;
os << value.properties;
return os;
}
std::tuple<MQTTProperties, std::vector<std::byte>::const_iterator> parse_mqtt_properties(const std::vector<std::byte>::const_iterator &property_start) {
MQTTProperties parsed_properties;
parsed_properties.properties[PropertyIdentifier::USER_PROPERTY] = UserProperty();
parsed_properties.length = int_vb(property_start);
spdlog::trace("Parsing Properties with length " + std::to_string(parsed_properties.length));
auto current_byte = std::next(property_start, parsed_properties.length.size());
while (std::distance(property_start, current_byte) < parsed_properties.length) {
uint next_property_offset = 0;
PropertyIdentifier current_property = PropertyIdentifier(std::to_integer<uint8_t>(*current_byte));
spdlog::trace("Parsing Variable Header Property with identifier " + std::to_string(int(current_property)));
switch (current_property) {
case PropertyIdentifier::PAYLOAD_FORMAT_INDICATOR: {
next_property_offset = 2;
std::byte property_value = *(std::next(current_byte, 1));
parsed_properties.properties[PropertyIdentifier::PAYLOAD_FORMAT_INDICATOR] = PropertyValue{property_value};
break;
}
case PropertyIdentifier::MESSAGE_EXPIRY_INTERVAL: {
uint32_t property_value = utilities::types::get_fixed_size_integer<uint32_t>(std::next(current_byte));
;
next_property_offset = 1 + sizeof(property_value);
parsed_properties.properties[PropertyIdentifier::MESSAGE_EXPIRY_INTERVAL] = PropertyValue{property_value};
break;
}
case PropertyIdentifier::CONTENT_TYPE: {
utf8_str property_value(std::next(current_byte));
parsed_properties.properties[PropertyIdentifier::CONTENT_TYPE] = PropertyValue{property_value};
next_property_offset = 1 + 2 + property_value.size();
break;
}
case PropertyIdentifier::RESPONSE_TOPIC: {
utf8_str property_value(std::next(current_byte));
parsed_properties.properties[PropertyIdentifier::RESPONSE_TOPIC] = PropertyValue{property_value};
next_property_offset = 1 + 2 + property_value.size();
break;
}
case PropertyIdentifier::CORRELATION_DATA: {
binary_data property_value(std::next(current_byte));
parsed_properties.properties[PropertyIdentifier::CORRELATION_DATA] = PropertyValue{property_value};
next_property_offset = 1 + 2 + property_value.size();
}
case PropertyIdentifier::SUBSCRIPTION_IDENTIFIER: {
int_vb property_value(current_byte);
parsed_properties.properties[PropertyIdentifier::CORRELATION_DATA] = PropertyValue{property_value};
next_property_offset = 1 + 2 + property_value.size();
}
case PropertyIdentifier::SESSION_EXPIRY_INTERVAL: {
uint32_t property_value = utilities::types::get_fixed_size_integer<uint32_t>(std::next(current_byte));
next_property_offset = 1 + sizeof(property_value);
parsed_properties.properties[PropertyIdentifier::SESSION_EXPIRY_INTERVAL] = PropertyValue{property_value};
break;
}
case PropertyIdentifier::ASSIGNED_CLIENT_IDENTIFIER: {
utf8_str property_value(std::next(current_byte));
parsed_properties.properties[PropertyIdentifier::ASSIGNED_CLIENT_IDENTIFIER] = PropertyValue{property_value};
next_property_offset = 1 + 2 + property_value.size();
break;
}
case PropertyIdentifier::SERVER_KEEP_ALIVE: {
uint16_t property_value = utilities::types::get_fixed_size_integer<uint16_t>(std::next(current_byte));
next_property_offset = 1 + sizeof(property_value);
parsed_properties.properties[PropertyIdentifier::SERVER_KEEP_ALIVE] = PropertyValue{property_value};
break;
}
case PropertyIdentifier::AUTHENTICATION_METHOD: {
utf8_str property_value(std::next(current_byte));
parsed_properties.properties[PropertyIdentifier::AUTHENTICATION_METHOD] = PropertyValue{property_value};
next_property_offset = 1 + 2 + property_value.size();
break;
}
case PropertyIdentifier::AUTHENTICATION_DATA: {
binary_data property_value(std::next(current_byte));
parsed_properties.properties[PropertyIdentifier::AUTHENTICATION_DATA] = PropertyValue{property_value};
next_property_offset = 1 + 2 + property_value.size();
}
case PropertyIdentifier::REQUEST_PROBLEM_INFORMATION: {
next_property_offset = 2;
std::byte property_value = *(std::next(current_byte, 1));
parsed_properties.properties[PropertyIdentifier::REQUEST_PROBLEM_INFORMATION] = PropertyValue{property_value};
break;
}
case PropertyIdentifier::WILL_DELAY_INTERVAL: {
uint32_t property_value = utilities::types::get_fixed_size_integer<uint32_t>(std::next(current_byte));
next_property_offset = 1 + sizeof(property_value);
parsed_properties.properties[PropertyIdentifier::WILL_DELAY_INTERVAL] = PropertyValue{property_value};
break;
}
case PropertyIdentifier::REQUEST_RESPONSE_INFORMATION: {
next_property_offset = 2;
std::byte property_value = *(std::next(current_byte, 1));
parsed_properties.properties[PropertyIdentifier::REQUEST_RESPONSE_INFORMATION] = PropertyValue{property_value};
break;
}
case PropertyIdentifier::RESPONSE_INFORMATION: {
utf8_str property_value(std::next(current_byte));
parsed_properties.properties[PropertyIdentifier::RESPONSE_INFORMATION] = PropertyValue{property_value};
next_property_offset = 1 + 2 + property_value.size();
break;
}
case PropertyIdentifier::SERVER_REFERENCE: {
utf8_str property_value(std::next(current_byte));
parsed_properties.properties[PropertyIdentifier::SERVER_REFERENCE] = PropertyValue{property_value};
next_property_offset = 1 + 2 + property_value.size();
break;
}
case PropertyIdentifier::REASON_STRING: {
utf8_str property_value(std::next(current_byte));
parsed_properties.properties[PropertyIdentifier::REASON_STRING] = PropertyValue{property_value};
next_property_offset = 1 + 2 + property_value.size();
break;
}
case PropertyIdentifier::RECEIVE_MAXIMUM: {
uint16_t property_value = utilities::types::get_fixed_size_integer<uint16_t>(std::next(current_byte));
next_property_offset = 1 + sizeof(property_value);
parsed_properties.properties[PropertyIdentifier::RECEIVE_MAXIMUM] = PropertyValue{property_value};
break;
}
case PropertyIdentifier::TOPIC_ALIAS_MAXIMUM: {
uint16_t property_value = utilities::types::get_fixed_size_integer<uint16_t>(std::next(current_byte));
next_property_offset = 1 + sizeof(property_value);
parsed_properties.properties[PropertyIdentifier::RECEIVE_MAXIMUM] = PropertyValue{property_value};
break;
}
case PropertyIdentifier::TOPIC_ALIAS: {
uint16_t property_value = utilities::types::get_fixed_size_integer<uint16_t>(std::next(current_byte));
next_property_offset = 1 + sizeof(property_value);
parsed_properties.properties[PropertyIdentifier::RECEIVE_MAXIMUM] = PropertyValue{property_value};
break;
}
case PropertyIdentifier::MAXIMUM_QOS: {
std::byte property_value = *(std::next(current_byte, 1));
next_property_offset = 1 + sizeof(property_value);
parsed_properties.properties[PropertyIdentifier::MAXIMUM_QOS] = PropertyValue{property_value};
break;
}
case PropertyIdentifier::RETAIN_AVAILABLE: {
std::byte property_value = *(std::next(current_byte, 1));
next_property_offset = 1 + sizeof(property_value);
parsed_properties.properties[PropertyIdentifier::RETAIN_AVAILABLE] = PropertyValue{property_value};
break;
}
case PropertyIdentifier::USER_PROPERTY: {
UTF8StringPair property_value(std::next(current_byte));
auto& user_property_list = std::get<UserProperty>(parsed_properties.properties[PropertyIdentifier::USER_PROPERTY]);
user_property_list.push(property_value);
next_property_offset = 1 + 4 + property_value.size();
break;
}
case PropertyIdentifier::MAXIMUM_PACKET_SIZE: {
uint32_t property_value = utilities::types::get_fixed_size_integer<uint32_t>(std::next(current_byte));
next_property_offset = 1 + sizeof(property_value);
parsed_properties.properties[PropertyIdentifier::RECEIVE_MAXIMUM] = PropertyValue{property_value};
break;
}
case PropertyIdentifier::WILDCARD_SUBSCRIPTION_AVAILABLE: {
std::byte property_value = *(std::next(current_byte, 1));
next_property_offset = 1 + sizeof(property_value);
parsed_properties.properties[PropertyIdentifier::WILDCARD_SUBSCRIPTION_AVAILABLE] = PropertyValue{property_value};
break;
}
case PropertyIdentifier::SUBSCRIPTION_IDENTIFIER_AVAILABLE: {
std::byte property_value = *(std::next(current_byte, 1));
next_property_offset = 1 + sizeof(property_value);
parsed_properties.properties[PropertyIdentifier::SUBSCRIPTION_IDENTIFIER_AVAILABLE] = PropertyValue{property_value};
break;
}
case PropertyIdentifier::SHARED_SUBSCRIPTION_AVAILABLE: {
std::byte property_value = *(std::next(current_byte, 1));
next_property_offset = 1 + sizeof(property_value);
parsed_properties.properties[PropertyIdentifier::SHARED_SUBSCRIPTION_AVAILABLE] = PropertyValue{property_value};
break;
}
default: {
uint8_t byte_value = std::to_integer<uint8_t>(*current_byte);
throw std::runtime_error("Invalid property received (" + std::to_string(byte_value) + ")");
}
}
current_byte = std::next(current_byte, next_property_offset);
}
return std::make_tuple(parsed_properties, current_byte);
}

View File

@@ -1,10 +1,13 @@
#ifndef INCLUDE_PACKET_INTERFACE_VARIABLE_HEADER_HPP_
#define INCLUDE_PACKET_INTERFACE_VARIABLE_HEADER_HPP_
#ifndef INCLUDE_CONTROL_PACKET_PROPERTY_HPP_
#define INCLUDE_CONTROL_PACKET_PROPERTY_HPP_
#include <binary_data.hpp>
#include <queue>
#include <utf8_string.hpp>
#include <utf8_string_pair.hpp>
#include <variable_byte_int.hpp>
#include <spdlog/spdlog.h>
#include <cstdint>
#include <map>
#include <variant>
@@ -38,21 +41,21 @@ enum class PropertyIdentifier : uint32_t {
SHARED_SUBSCRIPTION_AVAILABLE = 42
};
using PropertyValue =
std::variant<std::byte, uint32_t, uint16_t, int_vb, binary_data, utf8_str>;
using UserProperty = std::queue<UTF8StringPair>;
using PropertyValue = std::variant<std::byte, uint32_t, uint16_t, int_vb, binary_data, utf8_str, UserProperty>;
using PropertyMap = std::map<PropertyIdentifier, PropertyValue>;
struct variable_header {
uint16_t packet_identifier = 0;
int_vb property_length = int_vb(0);
struct MQTTProperties {
int_vb length;
PropertyMap properties;
};
typedef struct variable_header variable_header_t;
std::tuple<MQTTProperties, std::vector<std::byte>::const_iterator> parse_mqtt_properties(const std::vector<std::byte>::const_iterator &property_start);
std::ostream &operator<<(std::ostream &os, const std::byte &value);
std::ostream &operator<<(std::ostream &os, const UserProperty &value);
std::ostream &operator<<(std::ostream &os, const PropertyIdentifier &value);
std::ostream &operator<<(std::ostream &os, const PropertyValue &value);
std::ostream &operator<<(std::ostream &os, const variable_header_t &value);
std::ostream &operator<<(std::ostream &os, const PropertyMap &value);
std::ostream &operator<<(std::ostream &os, const MQTTProperties &value);
#endif // INCLUDE_PACKET_INTERFACE_VARIABLE_HEADER_HPP_
#endif // INCLUDE_CONTROL_PACKET_PROPERTY_HPP_

View File

@@ -0,0 +1,11 @@
#include <variable_header.hpp>
std::ostream &operator<<(std::ostream &os, const VariableHeader &value) {
os << "\t\t"
<< "\u21B3"
<< "Packet identifier = " << value.packet_identifier << std::endl;
if (value.properties.length > 0) {
os << value.properties;
}
return os;
}

View File

@@ -0,0 +1,17 @@
#ifndef INCLUDE_PACKET_INTERFACE_VARIABLE_HEADER_HPP_
#define INCLUDE_PACKET_INTERFACE_VARIABLE_HEADER_HPP_
#include <binary_data.hpp>
#include <property.hpp>
#include <utf8_string.hpp>
#include <variable_byte_int.hpp>
struct VariableHeader {
uint16_t packet_identifier = 0;
MQTTProperties properties;
uint byte_size = 0;
};
std::ostream &operator<<(std::ostream &os, const VariableHeader &value);
#endif // INCLUDE_PACKET_INTERFACE_VARIABLE_HEADER_HPP_

View File

@@ -1,280 +0,0 @@
#include "packet_interface.hpp"
#include "spdlog/spdlog.h"
PacketInterface::PacketInterface(const std::vector<std::byte> &data) {
this->raw_data = data;
unsigned char fixed_header_packet_type =
(static_cast<unsigned char>(raw_data[0]) >> 4) & 0x0F;
this->fixed_header.packet_type = PacketType(fixed_header_packet_type);
unsigned char fixed_header_packet_flags =
(static_cast<unsigned char>(raw_data[0]) & 0x0F);
this->fixed_header.packet_flags = fixed_header_packet_flags;
auto it = data.begin() + 1;
this->fixed_header.remaining_length = int_vb(it);
// 1 Byte is for MQTT Control packet Type and reserved value
this->variable_header_start = 1 + this->fixed_header.remaining_length.size();
this->variable_header.reset(new variable_header_t);
}
PacketInterface::PacketInterface(PacketInterface &packet) {
this->fixed_header.packet_type = packet.fixed_header.packet_type;
this->fixed_header.packet_flags = packet.fixed_header.packet_flags;
this->fixed_header.remaining_length = packet.fixed_header.remaining_length;
this->variable_header = std::move(packet.variable_header);
// 1 Byte is for MQTT Control packet Type and reserved value
this->variable_header_start = 1 + this->fixed_header.remaining_length.size();
this->raw_data = packet.raw_data;
}
std::string PacketInterface::to_string() {
std::ostringstream packet_str;
packet_str << std::endl;
packet_str << "Packet type is " << this->get_packet_type() << std::endl;
packet_str << "Packet flags are " << this->get_packet_flags() << std::endl;
packet_str << "Remaining length is " << this->fixed_header.remaining_length
<< std::endl;
return packet_str.str();
}
void PacketInterface::set_variable_header_properties(
const std::vector<std::byte>::const_iterator &it) {
// Length of the properties in bytes
this->variable_header->property_length = int_vb(it);
auto current_byte =
std::next(it, this->variable_header->property_length.size());
while (std::distance(it, current_byte) <
this->variable_header->property_length) {
uint next_property_offset = 0;
PropertyIdentifier current_property =
PropertyIdentifier(std::to_integer<uint8_t>(*current_byte));
spdlog::trace("Parsing Variable Header Property with identifier " +
std::to_string(int(current_property)));
switch (current_property) {
case PropertyIdentifier::PAYLOAD_FORMAT_INDICATOR: {
next_property_offset = 2;
std::byte property_value = *(std::next(current_byte, 1));
variable_header
->properties[PropertyIdentifier::PAYLOAD_FORMAT_INDICATOR] =
PropertyValue{property_value};
break;
}
case PropertyIdentifier::MESSAGE_EXPIRY_INTERVAL: {
uint32_t property_value =
utilities::types::get_fixed_size_integer<uint32_t>(
std::next(current_byte));
;
next_property_offset = 1 + sizeof(property_value);
variable_header->properties[PropertyIdentifier::MESSAGE_EXPIRY_INTERVAL] =
PropertyValue{property_value};
break;
}
case PropertyIdentifier::CONTENT_TYPE: {
utf8_str property_value(current_byte);
variable_header->properties[PropertyIdentifier::CONTENT_TYPE] =
PropertyValue{property_value};
next_property_offset = 1 + 2 + property_value.size();
break;
}
case PropertyIdentifier::RESPONSE_TOPIC: {
utf8_str property_value(current_byte);
variable_header->properties[PropertyIdentifier::RESPONSE_TOPIC] =
PropertyValue{property_value};
next_property_offset = 1 + 2 + property_value.size();
break;
}
case PropertyIdentifier::CORRELATION_DATA: {
binary_data property_value(current_byte);
variable_header->properties[PropertyIdentifier::CORRELATION_DATA] =
PropertyValue{property_value};
next_property_offset = 1 + 2 + property_value.size();
}
case PropertyIdentifier::SUBSCRIPTION_IDENTIFIER: {
int_vb property_value(current_byte);
variable_header->properties[PropertyIdentifier::CORRELATION_DATA] =
PropertyValue{property_value};
next_property_offset = 1 + 2 + property_value.size();
}
case PropertyIdentifier::SESSION_EXPIRY_INTERVAL: {
uint32_t property_value =
utilities::types::get_fixed_size_integer<uint32_t>(
std::next(current_byte));
next_property_offset = 1 + sizeof(property_value);
variable_header->properties[PropertyIdentifier::SESSION_EXPIRY_INTERVAL] =
PropertyValue{property_value};
break;
}
case PropertyIdentifier::ASSIGNED_CLIENT_IDENTIFIER: {
utf8_str property_value(current_byte);
variable_header
->properties[PropertyIdentifier::ASSIGNED_CLIENT_IDENTIFIER] =
PropertyValue{property_value};
next_property_offset = 1 + 2 + property_value.size();
break;
}
case PropertyIdentifier::SERVER_KEEP_ALIVE: {
uint16_t property_value =
utilities::types::get_fixed_size_integer<uint16_t>(
std::next(current_byte));
next_property_offset = 1 + sizeof(property_value);
variable_header->properties[PropertyIdentifier::SERVER_KEEP_ALIVE] =
PropertyValue{property_value};
break;
}
case PropertyIdentifier::AUTHENTICATION_METHOD: {
utf8_str property_value(current_byte);
variable_header->properties[PropertyIdentifier::AUTHENTICATION_METHOD] =
PropertyValue{property_value};
next_property_offset = 1 + 2 + property_value.size();
break;
}
case PropertyIdentifier::AUTHENTICATION_DATA: {
binary_data property_value(current_byte);
variable_header->properties[PropertyIdentifier::AUTHENTICATION_DATA] =
PropertyValue{property_value};
next_property_offset = 1 + 2 + property_value.size();
}
case PropertyIdentifier::REQUEST_PROBLEM_INFORMATION: {
next_property_offset = 2;
std::byte property_value = *(std::next(current_byte, 1));
variable_header
->properties[PropertyIdentifier::REQUEST_PROBLEM_INFORMATION] =
PropertyValue{property_value};
break;
}
case PropertyIdentifier::WILL_DELAY_INTERVAL: {
uint32_t property_value =
utilities::types::get_fixed_size_integer<uint32_t>(
std::next(current_byte));
next_property_offset = 1 + sizeof(property_value);
variable_header->properties[PropertyIdentifier::WILL_DELAY_INTERVAL] =
PropertyValue{property_value};
break;
}
case PropertyIdentifier::REQUEST_RESPONSE_INFORMATION: {
next_property_offset = 2;
std::byte property_value = *(std::next(current_byte, 1));
variable_header
->properties[PropertyIdentifier::REQUEST_RESPONSE_INFORMATION] =
PropertyValue{property_value};
break;
}
case PropertyIdentifier::RESPONSE_INFORMATION: {
utf8_str property_value(current_byte);
variable_header->properties[PropertyIdentifier::RESPONSE_INFORMATION] =
PropertyValue{property_value};
next_property_offset = 1 + 2 + property_value.size();
break;
}
case PropertyIdentifier::SERVER_REFERENCE: {
utf8_str property_value(current_byte);
variable_header->properties[PropertyIdentifier::SERVER_REFERENCE] =
PropertyValue{property_value};
next_property_offset = 1 + 2 + property_value.size();
break;
}
case PropertyIdentifier::REASON_STRING: {
utf8_str property_value(current_byte);
variable_header->properties[PropertyIdentifier::REASON_STRING] =
PropertyValue{property_value};
next_property_offset = 1 + 2 + property_value.size();
break;
}
case PropertyIdentifier::RECEIVE_MAXIMUM: {
uint16_t property_value =
utilities::types::get_fixed_size_integer<uint16_t>(
std::next(current_byte));
next_property_offset = 1 + sizeof(property_value);
variable_header->properties[PropertyIdentifier::RECEIVE_MAXIMUM] =
PropertyValue{property_value};
break;
}
case PropertyIdentifier::TOPIC_ALIAS_MAXIMUM: {
uint16_t property_value =
utilities::types::get_fixed_size_integer<uint16_t>(
std::next(current_byte));
next_property_offset = 1 + sizeof(property_value);
variable_header->properties[PropertyIdentifier::RECEIVE_MAXIMUM] =
PropertyValue{property_value};
break;
}
case PropertyIdentifier::TOPIC_ALIAS: {
uint16_t property_value =
utilities::types::get_fixed_size_integer<uint16_t>(
std::next(current_byte));
next_property_offset = 1 + sizeof(property_value);
variable_header->properties[PropertyIdentifier::RECEIVE_MAXIMUM] =
PropertyValue{property_value};
break;
}
case PropertyIdentifier::MAXIMUM_QOS: {
std::byte property_value = *(std::next(current_byte, 1));
next_property_offset = 1 + sizeof(property_value);
variable_header->properties[PropertyIdentifier::MAXIMUM_QOS] =
PropertyValue{property_value};
break;
}
case PropertyIdentifier::RETAIN_AVAILABLE: {
std::byte property_value = *(std::next(current_byte, 1));
next_property_offset = 1 + sizeof(property_value);
variable_header->properties[PropertyIdentifier::RETAIN_AVAILABLE] =
PropertyValue{property_value};
break;
}
case PropertyIdentifier::USER_PROPERTY: {
utf8_str property_value(current_byte);
variable_header->properties[PropertyIdentifier::USER_PROPERTY] =
PropertyValue{property_value};
next_property_offset = 1 + 2 + property_value.size();
break;
}
case PropertyIdentifier::MAXIMUM_PACKET_SIZE: {
uint32_t property_value =
utilities::types::get_fixed_size_integer<uint32_t>(
std::next(current_byte));
next_property_offset = 1 + sizeof(property_value);
variable_header->properties[PropertyIdentifier::RECEIVE_MAXIMUM] =
PropertyValue{property_value};
break;
}
case PropertyIdentifier::WILDCARD_SUBSCRIPTION_AVAILABLE: {
std::byte property_value = *(std::next(current_byte, 1));
next_property_offset = 1 + sizeof(property_value);
variable_header
->properties[PropertyIdentifier::WILDCARD_SUBSCRIPTION_AVAILABLE] =
PropertyValue{property_value};
break;
}
case PropertyIdentifier::SUBSCRIPTION_IDENTIFIER_AVAILABLE: {
std::byte property_value = *(std::next(current_byte, 1));
next_property_offset = 1 + sizeof(property_value);
variable_header
->properties[PropertyIdentifier::SUBSCRIPTION_IDENTIFIER_AVAILABLE] =
PropertyValue{property_value};
break;
}
case PropertyIdentifier::SHARED_SUBSCRIPTION_AVAILABLE: {
std::byte property_value = *(std::next(current_byte, 1));
next_property_offset = 1 + sizeof(property_value);
variable_header
->properties[PropertyIdentifier::SHARED_SUBSCRIPTION_AVAILABLE] =
PropertyValue{property_value};
break;
}
default: {
uint8_t byte_value = std::to_integer<uint8_t>(*current_byte);
throw std::runtime_error("Invalid property received (" +
std::to_string(byte_value) + ")");
}
}
current_byte = std::next(current_byte, next_property_offset);
}
}

View File

@@ -1,121 +0,0 @@
#include "spdlog/spdlog.h"
#include <variable_header.hpp>
struct VariantPrinter {
std::ostream &os;
template <typename T> void operator()(const T &value) const { os << value; }
};
// Função global para converter a enumeração para string
std::ostream &operator<<(std::ostream &os, const PropertyIdentifier &value) {
switch (value) {
case PropertyIdentifier::PAYLOAD_FORMAT_INDICATOR:
os << "PAYLOAD_FORMAT_INDICATOR";
break;
case PropertyIdentifier::MESSAGE_EXPIRY_INTERVAL:
os << "MESSAGE_EXPIRY_INTERVAL";
break;
case PropertyIdentifier::CONTENT_TYPE:
os << "CONTENT_TYPE";
break;
case PropertyIdentifier::RESPONSE_TOPIC:
os << "RESPONSE_TOPIC";
break;
case PropertyIdentifier::CORRELATION_DATA:
os << "CORRELATION_DATA";
break;
case PropertyIdentifier::SUBSCRIPTION_IDENTIFIER:
os << "SUBSCRIPTION_IDENTIFIER";
break;
case PropertyIdentifier::SESSION_EXPIRY_INTERVAL:
os << "SESSION_EXPIRY_INTERVAL";
break;
case PropertyIdentifier::ASSIGNED_CLIENT_IDENTIFIER:
os << "ASSIGNED_CLIENT_IDENTIFIER";
break;
case PropertyIdentifier::SERVER_KEEP_ALIVE:
os << "SERVER_KEEP_ALIVE";
break;
case PropertyIdentifier::AUTHENTICATION_METHOD:
os << "AUTHENTICATION_METHOD";
break;
case PropertyIdentifier::AUTHENTICATION_DATA:
os << "AUTHENTICATION_DATA";
break;
case PropertyIdentifier::REQUEST_PROBLEM_INFORMATION:
os << "REQUEST_PROBLEM_INFORMATION";
break;
case PropertyIdentifier::WILL_DELAY_INTERVAL:
os << "WILL_DELAY_INTERVAL";
break;
case PropertyIdentifier::REQUEST_RESPONSE_INFORMATION:
os << "REQUEST_RESPONSE_INFORMATION";
break;
case PropertyIdentifier::RESPONSE_INFORMATION:
os << "RESPONSE_INFORMATION";
break;
case PropertyIdentifier::SERVER_REFERENCE:
os << "SERVER_REFERENCE";
break;
case PropertyIdentifier::REASON_STRING:
os << "REASON_STRING";
break;
case PropertyIdentifier::RECEIVE_MAXIMUM:
os << "RECEIVE_MAXIMUM";
break;
case PropertyIdentifier::TOPIC_ALIAS_MAXIMUM:
os << "TOPIC_ALIAS_MAXIMUM";
break;
case PropertyIdentifier::TOPIC_ALIAS:
os << "TOPIC_ALIAS";
break;
case PropertyIdentifier::MAXIMUM_QOS:
os << "MAXIMUM_QOS";
break;
case PropertyIdentifier::RETAIN_AVAILABLE:
os << "RETAIN_AVAILABLE";
break;
case PropertyIdentifier::USER_PROPERTY:
os << "USER_PROPERTY";
break;
case PropertyIdentifier::MAXIMUM_PACKET_SIZE:
os << "MAXIMUM_PACKET_SIZE";
break;
case PropertyIdentifier::WILDCARD_SUBSCRIPTION_AVAILABLE:
os << "WILDCARD_SUBSCRIPTION_AVAILABLE";
break;
case PropertyIdentifier::SUBSCRIPTION_IDENTIFIER_AVAILABLE:
os << "SUBSCRIPTION_IDENTIFIER_AVAILABLE";
break;
case PropertyIdentifier::SHARED_SUBSCRIPTION_AVAILABLE:
os << "SHARED_SUBSCRIPTION_AVAILABLE";
break;
default:
os << "Unknown PropertyIdentifier";
break;
}
return os;
}
std::ostream &operator<<(std::ostream &os, const std::byte &value) {
os << std::to_string(std::to_integer<uint8_t>(value));
return os;
}
std::ostream &operator<<(std::ostream &os, const PropertyValue &value) {
std::visit(VariantPrinter{os}, value);
return os;
}
std::ostream &operator<<(std::ostream &os, const variable_header_t &value) {
os << "Packet identifier is " << value.packet_identifier << std::endl;
os << "Property length is " << value.property_length << std::endl;
os << "Property map" << std::endl;
if (value.property_length > 0) {
for (const auto &[key, value] : value.properties) {
os << "\t" << "\u21B3" << key << ": " << value << std::endl;
}
}
return os;
}

View File

@@ -44,11 +44,12 @@ void Session::listen() {
return;
}
PacketInterface packet(buffer);
ControlPacket packet(buffer);
switch (packet.get_packet_type()) {
case PacketType::CONNECT: {
ConnectPacket conn_packet(packet);
spdlog::trace(conn_packet.to_string());
break;
}
default: {

View File

@@ -1,7 +1,7 @@
#ifndef INCLUDE_PROTOCOL_SESSION_HPP_
#define INCLUDE_PROTOCOL_SESSION_HPP_
#include <packet_interface.hpp>
#include <control_packet.hpp>
#include <spdlog/spdlog.h>
#include <string>
#include <sys/socket.h>

View File

@@ -2,6 +2,11 @@
#include "spdlog/spdlog.h"
#include <iomanip>
BinaryData::BinaryData() {
this->data_size = 0;
this->data = {};
}
BinaryData::BinaryData(const std::vector<std::byte>::const_iterator &data_begin) {
this->data_size = std::to_integer<uint16_t>((*data_begin << 8) | *(std::next(data_begin, 1)));
this->data.resize(this->data_size);

View File

@@ -8,6 +8,7 @@
class BinaryData {
public:
// Create a BinaryData from the start of byte vector
BinaryData();
BinaryData(const std::vector<std::byte>::const_iterator &data_begin);
~BinaryData() = default;
@@ -22,6 +23,6 @@ protected:
uint16_t data_size;
};
typedef BinaryData binary_data;
using binary_data = BinaryData;
#endif // INCLUDE_TYPES_BINARY_DATA_HPP_

View File

@@ -1,14 +1,17 @@
//TODO: Implement UTF8 string verifications such as Page 17, line 274
#include "spdlog/spdlog.h"
#include <stdexcept>
#include <utf8_string.hpp>
UTF8String::UTF8String() { this->utf8_string = ""; }
UTF8String::UTF8String(
const std::vector<std::byte>::const_iterator &data_begin) {
uint16_t data_size = std::to_integer<uint16_t>((*data_begin << 8) |
*(std::next(data_begin, 1)));
auto utf8_string_begin = reinterpret_cast<const char*>(&(*std::next(data_begin, 2)));
auto utf8_string_end = reinterpret_cast<const char*>(&(*std::next(data_begin, 2+data_size)));
auto utf8_string_begin =
reinterpret_cast<const char *>(&(*std::next(data_begin, 2)));
auto utf8_string_end =
reinterpret_cast<const char *>(&(*std::next(data_begin, 2 + data_size)));
this->utf8_string.resize(data_size);
this->utf8_string.assign(utf8_string_begin, utf8_string_end);
@@ -19,4 +22,3 @@ std::ostream &operator<<(std::ostream &os, const UTF8String &value) {
os << value.utf8_string;
return os;
}

View File

@@ -6,16 +6,18 @@
class UTF8String {
public:
UTF8String();
UTF8String(const std::vector<std::byte>::const_iterator &data_begin);
~UTF8String() = default;
inline const uint16_t size() const { return utf8_string.size(); };
friend std::ostream &operator<<(std::ostream &, const UTF8String &);
inline const std::string data() const { return this->utf8_string; };
private:
friend std::ostream &operator<<(std::ostream &os, const UTF8String &value);
protected:
std::string utf8_string;
};
typedef UTF8String utf8_str;
using utf8_str = UTF8String;
#endif // INCLUDE_TYPES_UTF8_STRING_HPP_

View File

@@ -0,0 +1,16 @@
#include "spdlog/spdlog.h"
#include "utf8_string.hpp"
#include <utf8_string_pair.hpp>
UTF8StringPair::UTF8StringPair(const std::vector<std::byte>::const_iterator &data_begin) {
this->key = UTF8String(data_begin);
spdlog::trace(this->get_key().data());
auto value_start_byte = std::next(data_begin, 2 + this->key.size());
this->value = UTF8String(value_start_byte);
spdlog::trace(this->get_value().data());
}
std::ostream &operator<<(std::ostream &os, const UTF8StringPair &value) {
os << "(" << value.key << ", " << value.value << ")";
return os;
}

View File

@@ -0,0 +1,21 @@
#ifndef INCLUDE_TYPES_UTF8_STRING_PAIR_HPP_
#define INCLUDE_TYPES_UTF8_STRING_PAIR_HPP_
#include <utf8_string.hpp>
class UTF8StringPair {
public:
UTF8StringPair();
UTF8StringPair(const std::vector<std::byte>::const_iterator &data_begin);
~UTF8StringPair() = default;
friend std::ostream &operator<<(std::ostream &os, const UTF8StringPair &value);
inline const uint32_t size() const { return key.size() + value.size(); };
inline const UTF8String get_key() const { return this->key; };
inline const UTF8String get_value() const { return this->value; };
private:
utf8_str key, value;
};
#endif // INCLUDE_TYPES_UTF8_STRING_PAIR_HPP_

View File

@@ -1,6 +1,12 @@
//TODO: This implemetation assumes 4 bytes from variable int always, according to specification it should occupy as many bytes as length()
#include "variable_byte_int.hpp"
#include "spdlog/spdlog.h"
VariableByteInteger::VariableByteInteger() {
this->encoded_value.fill(std::byte(0));
this->decoded_value = 0;
}
VariableByteInteger::VariableByteInteger(const uint32_t &value) {
if(value > this->max())
throw std::runtime_error("Maximum value of Variable Byte Integer is " + std::to_string(this->max()));

View File

@@ -11,6 +11,8 @@
class VariableByteInteger {
public:
VariableByteInteger();
// Create a VariableByte Integer from a pure integer value
VariableByteInteger(const uint32_t &decoded_value);
@@ -48,6 +50,6 @@ private:
uint8_t bytes_count;
};
typedef VariableByteInteger int_vb;
using int_vb = VariableByteInteger;
#endif /* end of include guard: VARIABLE_BYTE_INT_H */

View File

@@ -1,5 +1,5 @@
#define MQTTD_VERSION_MAJOR 0
#define MQTTD_VERSION_MINOR 0
#define MQTTD_VERSION_PATCH 1
#define MQTTD_COMMIT_HASH 067d7111a44464271cd666b2e197434c9eed7eef
#define MQTTD_BUILD_TIMESTAMP 1706468278
#define MQTTD_COMMIT_HASH 216b7e27d3c8d6bd7735ed385e568b1ee8d0aa17
#define MQTTD_BUILD_TIMESTAMP 1706889192