diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..1e584ca --- /dev/null +++ b/.clang-format @@ -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 +... + diff --git a/src/libmqttd/network/CMakeLists.txt b/src/libmqttd/network/CMakeLists.txt index eb27b58..a730b61 100644 --- a/src/libmqttd/network/CMakeLists.txt +++ b/src/libmqttd/network/CMakeLists.txt @@ -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}) diff --git a/src/libmqttd/network/connection/connect_ack.cpp b/src/libmqttd/network/connection/connect_ack.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/libmqttd/network/connection/connect_ack.hpp b/src/libmqttd/network/connection/connect_ack.hpp new file mode 100644 index 0000000..e69de29 diff --git a/src/libmqttd/network/connection/connect_packet.cpp b/src/libmqttd/network/connection/connect_packet.cpp index 2ca27e0..f6e36c7 100644 --- a/src/libmqttd/network/connection/connect_packet.cpp +++ b/src/libmqttd/network/connection/connect_packet.cpp @@ -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 +#include +#include -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 data) - : PacketInterface(data) { - set_variable_header(); -} +ConnectPacket::ConnectPacket(std::vector 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(protocol_version_start_byte); - uint16_t protocol_name_length = utilities::types::get_fixed_size_integer(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(&(*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(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(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(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( - utilities::bit::get(connection_flags_value, flag_pos)); + return static_cast(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(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(get_connection_flag(ConnectFlags::USERNAME_FLAG))) { + packet_str << "\t\t" + << "\u21B3" + << "Username = " << this->payload.username << std::endl; + } + if (std::get(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(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(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(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()); + } +} diff --git a/src/libmqttd/network/connection/connect_packet.hpp b/src/libmqttd/network/connection/connect_packet.hpp index b2e96ad..ce0c97b 100644 --- a/src/libmqttd/network/connection/connect_packet.hpp +++ b/src/libmqttd/network/connection/connect_packet.hpp @@ -1,10 +1,13 @@ #ifndef INCLUDE_CONNECTION_CONNECT_PACKET_HPP_ #define INCLUDE_CONNECTION_CONNECT_PACKET_HPP_ -#include -#include -#include +#include "utf8_string.hpp" +#include +#include +#include #include +#include +#include enum ConnectFlags : uint16_t { RESERVERD = 0, @@ -18,9 +21,9 @@ enum ConnectFlags : uint16_t { using ConnectionFlagValue = std::variant; -class ConnectPacket : public PacketInterface { +class ConnectPacket : public ControlPacket { public: - ConnectPacket(PacketInterface &); + ConnectPacket(ControlPacket &); ConnectPacket(std::vector); ~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::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_ diff --git a/src/libmqttd/network/connection/last_will.hpp b/src/libmqttd/network/connection/last_will.hpp new file mode 100644 index 0000000..9ae77c3 --- /dev/null +++ b/src/libmqttd/network/connection/last_will.hpp @@ -0,0 +1,17 @@ +#ifndef INCLUDE_CONNECTION_LAST_WILL_HPP_ +#define INCLUDE_CONNECTION_LAST_WILL_HPP_ + +#include +#include +#include +#include + +struct LastWill { + MQTTProperties properties; + utf8_str will_topic; + binary_data will_payload; +}; + +using last_will = LastWill; + +#endif // INCLUDE_CONNECTION_LAST_WILL_HPP_ diff --git a/src/libmqttd/network/packet_interface/CMakeLists.txt b/src/libmqttd/network/control_packet/CMakeLists.txt similarity index 100% rename from src/libmqttd/network/packet_interface/CMakeLists.txt rename to src/libmqttd/network/control_packet/CMakeLists.txt diff --git a/src/libmqttd/network/control_packet/control_packet.cpp b/src/libmqttd/network/control_packet/control_packet.cpp new file mode 100644 index 0000000..31a8c1b --- /dev/null +++ b/src/libmqttd/network/control_packet/control_packet.cpp @@ -0,0 +1,43 @@ +#include "control_packet.hpp" +#include "variable_header.hpp" +#include +#include +#include + +ControlPacket::ControlPacket(const std::vector &data) { + this->raw_data = data; + unsigned char fixed_header_packet_type = (static_cast(raw_data[0]) >> 4) & 0x0F; + this->fixed_header.packet_type = PacketType(fixed_header_packet_type); + + unsigned char fixed_header_packet_flags = (static_cast(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(); +} + diff --git a/src/libmqttd/network/packet_interface/packet_interface.hpp b/src/libmqttd/network/control_packet/control_packet.hpp similarity index 50% rename from src/libmqttd/network/packet_interface/packet_interface.hpp rename to src/libmqttd/network/control_packet/control_packet.hpp index 2e3287a..e94ad5b 100644 --- a/src/libmqttd/network/packet_interface/packet_interface.hpp +++ b/src/libmqttd/network/control_packet/control_packet.hpp @@ -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 -class PacketInterface { +class ControlPacket { public: - PacketInterface(const std::vector &); - PacketInterface(PacketInterface &); - ~PacketInterface() = default; + ControlPacket(const std::vector &); + 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 raw_data; - fixed_header_t fixed_header; - std::unique_ptr variable_header; - uint variable_header_start; + FixedHeader fixed_header; + std::unique_ptr 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::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_ diff --git a/src/libmqttd/network/packet_interface/fixed_header.cpp b/src/libmqttd/network/control_packet/fixed_header.cpp similarity index 100% rename from src/libmqttd/network/packet_interface/fixed_header.cpp rename to src/libmqttd/network/control_packet/fixed_header.cpp diff --git a/src/libmqttd/network/packet_interface/fixed_header.hpp b/src/libmqttd/network/control_packet/fixed_header.hpp similarity index 91% rename from src/libmqttd/network/packet_interface/fixed_header.hpp rename to src/libmqttd/network/control_packet/fixed_header.hpp index 8bb9a7b..1ca546c 100644 --- a/src/libmqttd/network/packet_interface/fixed_header.hpp +++ b/src/libmqttd/network/control_packet/fixed_header.hpp @@ -5,7 +5,6 @@ #include #include -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); diff --git a/src/libmqttd/network/control_packet/property.cpp b/src/libmqttd/network/control_packet/property.cpp new file mode 100644 index 0000000..77b83a3 --- /dev/null +++ b/src/libmqttd/network/control_packet/property.cpp @@ -0,0 +1,323 @@ +#include "utf8_string_pair.hpp" +#include +#include +#include +#include + +struct VariantPrinter { + std::ostream &os; + template 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(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::const_iterator> parse_mqtt_properties(const std::vector::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(*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(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(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(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(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(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(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(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(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(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(*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); +} diff --git a/src/libmqttd/network/packet_interface/variable_header.hpp b/src/libmqttd/network/control_packet/property.hpp similarity index 57% rename from src/libmqttd/network/packet_interface/variable_header.hpp rename to src/libmqttd/network/control_packet/property.hpp index 7a73a25..824ea9f 100644 --- a/src/libmqttd/network/packet_interface/variable_header.hpp +++ b/src/libmqttd/network/control_packet/property.hpp @@ -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 +#include #include +#include #include - +#include +#include #include #include @@ -38,21 +41,21 @@ enum class PropertyIdentifier : uint32_t { SHARED_SUBSCRIPTION_AVAILABLE = 42 }; -using PropertyValue = - std::variant; - +using UserProperty = std::queue; +using PropertyValue = std::variant; using PropertyMap = std::map; -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::const_iterator> parse_mqtt_properties(const std::vector::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_ diff --git a/src/libmqttd/network/control_packet/variable_header.cpp b/src/libmqttd/network/control_packet/variable_header.cpp new file mode 100644 index 0000000..3c20ac1 --- /dev/null +++ b/src/libmqttd/network/control_packet/variable_header.cpp @@ -0,0 +1,11 @@ +#include + +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; +} diff --git a/src/libmqttd/network/control_packet/variable_header.hpp b/src/libmqttd/network/control_packet/variable_header.hpp new file mode 100644 index 0000000..c2de09e --- /dev/null +++ b/src/libmqttd/network/control_packet/variable_header.hpp @@ -0,0 +1,17 @@ +#ifndef INCLUDE_PACKET_INTERFACE_VARIABLE_HEADER_HPP_ +#define INCLUDE_PACKET_INTERFACE_VARIABLE_HEADER_HPP_ + +#include +#include +#include +#include + +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_ diff --git a/src/libmqttd/network/packet_interface/packet_interface.cpp b/src/libmqttd/network/packet_interface/packet_interface.cpp deleted file mode 100644 index ffeff8e..0000000 --- a/src/libmqttd/network/packet_interface/packet_interface.cpp +++ /dev/null @@ -1,280 +0,0 @@ -#include "packet_interface.hpp" -#include "spdlog/spdlog.h" - -PacketInterface::PacketInterface(const std::vector &data) { - this->raw_data = data; - unsigned char fixed_header_packet_type = - (static_cast(raw_data[0]) >> 4) & 0x0F; - this->fixed_header.packet_type = PacketType(fixed_header_packet_type); - - unsigned char fixed_header_packet_flags = - (static_cast(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::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(*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( - 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( - 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( - 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( - 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( - 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( - 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( - 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( - 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(*current_byte); - throw std::runtime_error("Invalid property received (" + - std::to_string(byte_value) + ")"); - } - } - current_byte = std::next(current_byte, next_property_offset); - } -} diff --git a/src/libmqttd/network/packet_interface/variable_header.cpp b/src/libmqttd/network/packet_interface/variable_header.cpp deleted file mode 100644 index 922615f..0000000 --- a/src/libmqttd/network/packet_interface/variable_header.cpp +++ /dev/null @@ -1,121 +0,0 @@ -#include "spdlog/spdlog.h" -#include - -struct VariantPrinter { - std::ostream &os; - - template 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(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; -} diff --git a/src/libmqttd/protocol/session.cpp b/src/libmqttd/protocol/session.cpp index 20f7fe3..7cdff40 100644 --- a/src/libmqttd/protocol/session.cpp +++ b/src/libmqttd/protocol/session.cpp @@ -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: { diff --git a/src/libmqttd/protocol/session.hpp b/src/libmqttd/protocol/session.hpp index e1898eb..69d6020 100644 --- a/src/libmqttd/protocol/session.hpp +++ b/src/libmqttd/protocol/session.hpp @@ -1,7 +1,7 @@ #ifndef INCLUDE_PROTOCOL_SESSION_HPP_ #define INCLUDE_PROTOCOL_SESSION_HPP_ -#include +#include #include #include #include diff --git a/src/libmqttd/types/binary_data.cpp b/src/libmqttd/types/binary_data.cpp index fc5d1fd..6980cdd 100644 --- a/src/libmqttd/types/binary_data.cpp +++ b/src/libmqttd/types/binary_data.cpp @@ -2,6 +2,11 @@ #include "spdlog/spdlog.h" #include +BinaryData::BinaryData() { + this->data_size = 0; + this->data = {}; +} + BinaryData::BinaryData(const std::vector::const_iterator &data_begin) { this->data_size = std::to_integer((*data_begin << 8) | *(std::next(data_begin, 1))); this->data.resize(this->data_size); diff --git a/src/libmqttd/types/binary_data.hpp b/src/libmqttd/types/binary_data.hpp index 81d9324..dafe89a 100644 --- a/src/libmqttd/types/binary_data.hpp +++ b/src/libmqttd/types/binary_data.hpp @@ -8,6 +8,7 @@ class BinaryData { public: // Create a BinaryData from the start of byte vector + BinaryData(); BinaryData(const std::vector::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_ diff --git a/src/libmqttd/types/utf8_string.cpp b/src/libmqttd/types/utf8_string.cpp index 11dd8ef..3296425 100644 --- a/src/libmqttd/types/utf8_string.cpp +++ b/src/libmqttd/types/utf8_string.cpp @@ -1,14 +1,17 @@ +//TODO: Implement UTF8 string verifications such as Page 17, line 274 #include "spdlog/spdlog.h" -#include #include +UTF8String::UTF8String() { this->utf8_string = ""; } UTF8String::UTF8String( const std::vector::const_iterator &data_begin) { uint16_t data_size = std::to_integer((*data_begin << 8) | *(std::next(data_begin, 1))); - auto utf8_string_begin = reinterpret_cast(&(*std::next(data_begin, 2))); - auto utf8_string_end = reinterpret_cast(&(*std::next(data_begin, 2+data_size))); + auto utf8_string_begin = + reinterpret_cast(&(*std::next(data_begin, 2))); + auto utf8_string_end = + reinterpret_cast(&(*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; } - diff --git a/src/libmqttd/types/utf8_string.hpp b/src/libmqttd/types/utf8_string.hpp index 40ef4a3..c52d7a9 100644 --- a/src/libmqttd/types/utf8_string.hpp +++ b/src/libmqttd/types/utf8_string.hpp @@ -6,16 +6,18 @@ class UTF8String { public: + UTF8String(); UTF8String(const std::vector::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_ diff --git a/src/libmqttd/types/utf8_string_pair.cpp b/src/libmqttd/types/utf8_string_pair.cpp new file mode 100644 index 0000000..7c32550 --- /dev/null +++ b/src/libmqttd/types/utf8_string_pair.cpp @@ -0,0 +1,16 @@ +#include "spdlog/spdlog.h" +#include "utf8_string.hpp" +#include + +UTF8StringPair::UTF8StringPair(const std::vector::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; +} diff --git a/src/libmqttd/types/utf8_string_pair.hpp b/src/libmqttd/types/utf8_string_pair.hpp new file mode 100644 index 0000000..46f665f --- /dev/null +++ b/src/libmqttd/types/utf8_string_pair.hpp @@ -0,0 +1,21 @@ +#ifndef INCLUDE_TYPES_UTF8_STRING_PAIR_HPP_ +#define INCLUDE_TYPES_UTF8_STRING_PAIR_HPP_ + +#include + +class UTF8StringPair { +public: + UTF8StringPair(); + UTF8StringPair(const std::vector::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_ diff --git a/src/libmqttd/types/variable_byte_int.cpp b/src/libmqttd/types/variable_byte_int.cpp index 6271ec6..fe566e6 100644 --- a/src/libmqttd/types/variable_byte_int.cpp +++ b/src/libmqttd/types/variable_byte_int.cpp @@ -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())); diff --git a/src/libmqttd/types/variable_byte_int.hpp b/src/libmqttd/types/variable_byte_int.hpp index 2a9e98f..e7cdaef 100644 --- a/src/libmqttd/types/variable_byte_int.hpp +++ b/src/libmqttd/types/variable_byte_int.hpp @@ -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 */ diff --git a/src/version.hpp b/src/version.hpp index 2928bc7..8636378 100644 --- a/src/version.hpp +++ b/src/version.hpp @@ -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