fix: fixing Property mapping
Fixed UserProperty Fixed Payload Properties
This commit is contained in:
236
.clang-format
Normal file
236
.clang-format
Normal 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
|
||||
...
|
||||
|
||||
@@ -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})
|
||||
|
||||
0
src/libmqttd/network/connection/connect_ack.cpp
Normal file
0
src/libmqttd/network/connection/connect_ack.cpp
Normal file
0
src/libmqttd/network/connection/connect_ack.hpp
Normal file
0
src/libmqttd/network/connection/connect_ack.hpp
Normal 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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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_
|
||||
|
||||
17
src/libmqttd/network/connection/last_will.hpp
Normal file
17
src/libmqttd/network/connection/last_will.hpp
Normal 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_
|
||||
43
src/libmqttd/network/control_packet/control_packet.cpp
Normal file
43
src/libmqttd/network/control_packet/control_packet.cpp
Normal 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();
|
||||
}
|
||||
|
||||
@@ -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_
|
||||
@@ -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);
|
||||
323
src/libmqttd/network/control_packet/property.cpp
Normal file
323
src/libmqttd/network/control_packet/property.cpp
Normal 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);
|
||||
}
|
||||
@@ -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_
|
||||
11
src/libmqttd/network/control_packet/variable_header.cpp
Normal file
11
src/libmqttd/network/control_packet/variable_header.cpp
Normal 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;
|
||||
}
|
||||
17
src/libmqttd/network/control_packet/variable_header.hpp
Normal file
17
src/libmqttd/network/control_packet/variable_header.hpp
Normal 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_
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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: {
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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_
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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_
|
||||
|
||||
16
src/libmqttd/types/utf8_string_pair.cpp
Normal file
16
src/libmqttd/types/utf8_string_pair.cpp
Normal 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;
|
||||
}
|
||||
21
src/libmqttd/types/utf8_string_pair.hpp
Normal file
21
src/libmqttd/types/utf8_string_pair.hpp
Normal 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_
|
||||
@@ -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()));
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user