123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392 |
- /*
- * Copyright (c) 2017-2023 zhllxt
- *
- * author : zhllxt
- * email : 37792738@qq.com
- *
- * chinese : http://blog.mcxiaoke.com/mqtt/protocol/MQTT-3.1.1-CN.html
- * english : http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html
- *
- * Distributed under the Boost Software License, Version 1.0. (See accompanying
- * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
- */
- #ifndef __ASIO2_MQTT_PROTOCOL_V4_HPP__
- #define __ASIO2_MQTT_PROTOCOL_V4_HPP__
- #if defined(_MSC_VER) && (_MSC_VER >= 1200)
- #pragma once
- #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
- #include <asio2/mqtt/core.hpp>
- namespace asio2::mqtt::v4
- {
- static constexpr std::uint8_t version_number = asio2::detail::to_underlying(mqtt::version::v4);
- enum class connect_reason_code : std::uint8_t
- {
- /* 0 0x00 Connection Accepted : */ success = 0,
- /* 1 0x01 Connection Refused : */ unacceptable_protocol_version = 1,
- /* 2 0x02 Connection Refused : */ identifier_rejected = 2,
- /* 3 0x03 Connection Refused : */ server_unavailable = 3,
- /* 4 0x04 Connection Refused : */ bad_user_name_or_password = 4,
- /* 5 0x05 Connection Refused : */ not_authorized = 5,
- /* 6 - 255 Reserved for future use */
- };
- /**
- * CONNECT - Client requests a connection to a Server
- *
- * After a Network Connection is established by a Client to a Server, the first packet sent from the
- * Client to the Server MUST be a CONNECT packet [MQTT-3.1.0-1].
- *
- * A Client can only send the CONNECT Packet once over a Network Connection. The Server MUST process
- * a second CONNECT Packet sent from a Client as a protocol violation and disconnect the Client
- *
- * http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718028
- */
- class connect : public fixed_header<version_number>
- {
- public:
- connect() : fixed_header(control_packet_type::connect)
- {
- update_remain_length();
- }
- connect(utf8_string::value_type clientid) : fixed_header(control_packet_type::connect)
- {
- client_id(std::move(clientid));
- update_remain_length();
- }
- inline std::size_t required_size() const
- {
- return (fixed_header::required_size() + fixed_header::remain_length());
- }
- /*
- * The Container is usually a std::string, std::vector<char>, ...
- */
- template<class Container>
- inline connect& serialize(Container& buffer)
- {
- fixed_header::serialize(buffer);
- protocol_name_ .serialize(buffer);
- protocol_version_ .serialize(buffer);
- connect_flags_.byte .serialize(buffer);
- keep_alive_ .serialize(buffer);
- client_id_ .serialize(buffer);
- if (will_topic_ ) will_topic_ ->serialize(buffer);
- if (will_payload_) will_payload_->serialize(buffer);
- if (username_ ) username_ ->serialize(buffer);
- if (password_ ) password_ ->serialize(buffer);
- return (*this);
- }
- inline connect& deserialize(std::string_view& data)
- {
- fixed_header::deserialize(data);
- protocol_name_ .deserialize(data);
- protocol_version_ .deserialize(data);
- connect_flags_.byte .deserialize(data);
- keep_alive_ .deserialize(data);
- client_id_ .deserialize(data);
- if (has_will())
- {
- utf8_string will_topic{};
- will_topic.deserialize(data);
- will_topic_ = std::move(will_topic);
- binary_data will_payload{};
- will_payload.deserialize(data);
- will_payload_ = std::move(will_payload);
- }
- if (has_username())
- {
- utf8_string username{};
- username.deserialize(data);
- username_ = std::move(username);
- }
- if (has_password())
- {
- binary_data password{};
- password.deserialize(data);
- password_ = std::move(password);
- }
- update_remain_length();
- return (*this);
- }
- inline std::uint8_t protocol_version() const { return (protocol_version_ ); }
- inline bool clean_start () const { return (connect_flags_.bits.clean_session); }
- inline bool clean_session () const { return (connect_flags_.bits.clean_session); }
- inline bool has_will () const { return (connect_flags_.bits.will_flag ); }
- inline qos_type will_qos () const { return static_cast<qos_type>(connect_flags_.bits.will_qos ); }
- inline bool will_retain () const { return (connect_flags_.bits.will_retain ); }
- inline bool has_password () const { return (connect_flags_.bits.password_flag); }
- inline bool has_username () const { return (connect_flags_.bits.username_flag); }
- inline connect& clean_start (bool v) { connect_flags_.bits.clean_session = v; return (*this); }
- inline connect& clean_session (bool v) { connect_flags_.bits.clean_session = v; return (*this); }
- inline two_byte_integer::value_type keep_alive () const { return keep_alive_ ; }
- inline utf8_string::view_type client_id () const { return client_id_ .data_view(); }
- inline utf8_string::view_type will_topic () const { return will_topic_ ? will_topic_ ->data_view() : ""; }
- inline binary_data::view_type will_payload () const { return will_payload_ ? will_payload_->data_view() : ""; }
- inline utf8_string::view_type username () const { return username_ ? username_ ->data_view() : ""; }
- inline binary_data::view_type password () const { return password_ ? password_ ->data_view() : ""; }
- inline connect& keep_alive(two_byte_integer::value_type v)
- {
- keep_alive_ = std::move(v);
- return (*this);
- }
- template<class String>
- inline connect& client_id(String&& v)
- {
- client_id_ = std::forward<String>(v);
- update_remain_length();
- return (*this);
- }
- template<class String>
- inline connect& username(String&& v)
- {
- username_ = std::forward<String>(v);
- connect_flags_.bits.username_flag = true;
- update_remain_length();
- return (*this);
- }
- inline connect& password(binary_data::value_type v)
- {
- password_ = std::move(v);
- connect_flags_.bits.password_flag = true;
- update_remain_length();
- return (*this);
- }
- template<class String1, class String2, class QosOrInt>
- inline connect& will_attributes(String1&& topic, String2&& payload,
- QosOrInt qos = qos_type::at_most_once, bool retain = false)
- {
- will_topic_ = std::forward<String1>(topic);
- will_payload_ = std::forward<String2>(payload);
- connect_flags_.bits.will_flag = true;
- connect_flags_.bits.will_qos = static_cast<std::uint8_t>(qos);
- connect_flags_.bits.will_retain = retain;
- update_remain_length();
- return (*this);
- }
- inline bool will_topic_has_value() const noexcept { return will_topic_.has_value(); }
- inline bool username_has_value () const noexcept { return username_ .has_value(); }
- inline bool password_has_value () const noexcept { return password_ .has_value(); }
- inline connect& update_remain_length()
- {
- remain_length_ = static_cast<std::int32_t>(0
- + protocol_name_ .required_size()
- + protocol_version_ .required_size()
- + connect_flags_.byte .required_size()
- + keep_alive_ .required_size()
- + client_id_ .required_size()
- + (will_topic_ ? will_topic_ ->required_size() : 0)
- + (will_payload_ ? will_payload_->required_size() : 0)
- + (username_ ? username_ ->required_size() : 0)
- + (password_ ? password_ ->required_size() : 0)
- );
- return (*this);
- }
- protected:
- // The Protocol Name is a UTF-8 Encoded String that represents the protocol name "MQTT".
- // The string, its offset and length will not be changed by future versions of the MQTT specification.
- utf8_string protocol_name_{ "MQTT" };
- // The 8 bit unsigned value that represents the revision level of the protocol used by the Client.
- // The value of the Protocol Level field for the version 3.1.1 of the protocol is 4 (0x04).
- one_byte_integer protocol_version_{ 0x04 };
- union
- {
- one_byte_integer byte{ 0 }; // all connect flags
- #if ASIO2_ENDIAN_BIG_BYTE
- struct
- {
- bool username_flag : 1; // User Name Flag
- bool password_flag : 1; // Password Flag
- bool will_retain : 1; // will retain setting
- std::uint8_t will_qos : 2; // will QoS value
- bool will_flag : 1; // will flag
- bool clean_session : 1; // Clean Session flag
- std::uint8_t reserved : 1; // unused
- } bits;
- #else
- struct
- {
- std::uint8_t reserved : 1; // unused
- bool clean_session : 1; // Clean Session flag
- bool will_flag : 1; // will flag
- std::uint8_t will_qos : 2; // will QoS value
- bool will_retain : 1; // will retain setting
- bool password_flag : 1; // Password Flag
- bool username_flag : 1; // User Name Flag
- } bits;
- #endif
- } connect_flags_{}; // connect flags byte
- // The Keep Alive is a time interval measured in seconds. Expressed as a 16-bit word
- // Default to 60 seconds
- two_byte_integer keep_alive_ { 60 };
- // The Client Identifier (ClientID) identifies the Client to the Server.
- // Each Client connecting to the Server has a unique ClientID.
- utf8_string client_id_ {};
- // If the Will Flag is set to 1, the Will Topic is the next field in the Payload.
- std::optional<utf8_string> will_topic_ {};
- // If the Will Flag is set to 1 the Will Payload is the next field in the Payload.
- std::optional<binary_data> will_payload_{};
- // If the User Name Flag is set to 1, the User Name is the next field in the Payload.
- std::optional<utf8_string> username_ {};
- // If the Password Flag is set to 1, the Password is the next field in the Payload.
- std::optional<binary_data> password_ {};
- };
- /**
- * CONNACK - Acknowledge connection request
- *
- * http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718033
- */
- class connack : public fixed_header<version_number>
- {
- public:
- connack() : fixed_header(control_packet_type::connack)
- {
- update_remain_length();
- }
- explicit connack(bool session_present, std::uint8_t reason_code)
- : fixed_header(control_packet_type::connack)
- , reason_code_(reason_code)
- {
- connack_flags_.bits.session_present = session_present;
- update_remain_length();
- }
- explicit connack(bool session_present, connect_reason_code reason_code)
- : fixed_header(control_packet_type::connack)
- , reason_code_(asio2::detail::to_underlying(reason_code))
- {
- connack_flags_.bits.session_present = session_present;
- update_remain_length();
- }
- inline std::size_t required_size() const
- {
- return (fixed_header::required_size() + fixed_header::remain_length());
- }
- /*
- * The Container is usually a std::string, std::vector<char>, ...
- */
- template<class Container>
- inline connack& serialize(Container& buffer)
- {
- fixed_header::serialize(buffer);
- connack_flags_.byte .serialize(buffer);
- reason_code_ .serialize(buffer);
- return (*this);
- }
- inline connack& deserialize(std::string_view& data)
- {
- fixed_header::deserialize(data);
- connack_flags_.byte .deserialize(data);
- reason_code_ .deserialize(data);
- update_remain_length();
- return (*this);
- }
- inline bool session_present() const { return connack_flags_.bits.session_present; }
- inline connect_reason_code reason_code () const { return static_cast<connect_reason_code>(reason_code_.value()); }
- inline connack & session_present(bool v) { connack_flags_.bits.session_present = v; return (*this); }
- inline connack & reason_code (std::uint8_t v) { reason_code_ = v; return (*this); }
- inline connack & reason_code (connect_reason_code v)
- { reason_code_ = asio2::detail::to_underlying(v); return (*this); }
- inline connack& update_remain_length()
- {
- remain_length_ = static_cast<std::int32_t>(0
- + connack_flags_.byte .required_size()
- + reason_code_ .required_size()
- );
- return (*this);
- }
- protected:
- union
- {
- one_byte_integer byte{ 0 }; // all connack flags
- #if ASIO2_ENDIAN_BIG_BYTE
- struct
- {
- std::uint8_t reserved : 7;
- bool session_present : 1; // session found on the server?
- } bits;
- #else
- struct
- {
- bool session_present : 1; // session found on the server?
- std::uint8_t reserved : 7;
- } bits;
- #endif
- } connack_flags_{}; // connack flags
- // Byte 2 in the Variable Header is the Connect Reason Code.
- one_byte_integer reason_code_{ 0 };
- };
- /**
- * PUBLISH - Publish message
- *
- * A PUBLISH packet is sent from a Client to a Server or from a Server to a Client to transport an Application Message.
- *
- * http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718037
- */
- class publish : public fixed_header<version_number>
- {
- public:
- publish() : fixed_header(control_packet_type::publish)
- {
- update_remain_length();
- }
- template<class String1, class String2, class QosOrInt, std::enable_if_t<
- asio2::detail::is_character_string_v<String1>, int> = 0>
- explicit publish(String1&& topic_name, String2&& payload, QosOrInt qos,
- bool dup = false, bool retain = false)
- : fixed_header(control_packet_type::publish)
- , topic_name_ (std::forward<String1>(topic_name))
- , payload_ (std::forward<String2>(payload ))
- {
- type_and_flags_.bits.dup = dup;
- type_and_flags_.bits.qos = static_cast<std::uint8_t>(qos);
- type_and_flags_.bits.retain = retain;
- update_remain_length();
- }
- template<class String1, class String2, class QosOrInt, std::enable_if_t<
- asio2::detail::is_character_string_v<String1>, int> = 0>
- explicit publish(std::uint16_t pid, String1&& topic_name, String2&& payload, QosOrInt qos,
- bool dup = false, bool retain = false)
- : fixed_header(control_packet_type::publish)
- , topic_name_ (std::forward<String1>(topic_name))
- , packet_id_ (pid)
- , payload_ (std::forward<String2>(payload ))
- {
- type_and_flags_.bits.dup = dup;
- type_and_flags_.bits.qos = static_cast<std::uint8_t>(qos);
- type_and_flags_.bits.retain = retain;
- ASIO2_ASSERT(type_and_flags_.bits.qos > std::uint8_t(0));
- update_remain_length();
- }
- inline std::size_t required_size() const
- {
- return (fixed_header::required_size() + fixed_header::remain_length());
- }
- /*
- * The Container is usually a std::string, std::vector<char>, ...
- */
- template<class Container>
- inline publish& serialize(Container& buffer)
- {
- fixed_header::serialize(buffer);
- // The Packet Identifier field is only present in PUBLISH packets where the QoS level is 1 or 2.
- // A PUBLISH packet MUST NOT contain a Packet Identifier if its QoS value is set to 0
- if ((type_and_flags_.bits.qos == std::uint8_t(0) && packet_id_.has_value()) ||
- (type_and_flags_.bits.qos > std::uint8_t(0) && !packet_id_.has_value()))
- {
- ASIO2_ASSERT(false);
- asio2::set_last_error(mqtt::make_error_code(mqtt::error::malformed_packet));
- }
- topic_name_.serialize(buffer);
- if (type_and_flags_.bits.qos > std::uint8_t(0) && packet_id_.has_value())
- {
- packet_id_->serialize(buffer);
- }
- payload_.serialize(buffer);
- return (*this);
- }
- inline publish& deserialize(std::string_view& data)
- {
- fixed_header::deserialize(data);
- topic_name_.deserialize(data);
- // A PUBLISH Packet MUST NOT contain a Packet Identifier if its QoS value is set to 0 [MQTT-2.3.1-5].
- if (type_and_flags_.bits.qos == 1 || type_and_flags_.bits.qos == 2)
- {
- two_byte_integer packet_id{};
- packet_id.deserialize(data);
- packet_id_ = packet_id;
- }
- payload_ .deserialize(data);
- update_remain_length();
- return (*this);
- }
- inline bool dup () const { return (type_and_flags_.bits.dup ); }
- inline qos_type qos () const { return static_cast<qos_type>(type_and_flags_.bits.qos ); }
- inline bool retain() const { return (type_and_flags_.bits.retain); }
- inline publish & dup (bool v) { type_and_flags_.bits.dup = v; return (*this); }
- template<class QosOrInt>
- inline publish & qos (QosOrInt v) { type_and_flags_.bits.qos = static_cast<std::uint8_t>(v); return (*this); }
- inline publish & retain(bool v) { type_and_flags_.bits.retain = v; return (*this); }
- inline utf8_string::view_type topic_name() const { return topic_name_.data_view(); }
- inline two_byte_integer::value_type packet_id () const { return packet_id_ ? packet_id_->value() : 0; }
- inline application_message::view_type payload () const { return payload_.data_view() ; }
- inline publish & packet_id (std::uint16_t v) { packet_id_ = v ; update_remain_length(); return (*this); }
- template<class String>
- inline publish & topic_name(String&& v) { topic_name_ = std::forward<String>(v); update_remain_length(); return (*this); }
- template<class String>
- inline publish & payload (String&& v) { payload_ = std::forward<String>(v); update_remain_length(); return (*this); }
- inline bool has_packet_id() const noexcept { return packet_id_.has_value(); }
- inline publish& update_remain_length()
- {
- remain_length_ = static_cast<std::int32_t>(0
- + topic_name_.required_size()
- + (packet_id_ ? packet_id_->required_size() : 0)
- + payload_ .required_size()
- );
- return (*this);
- }
- protected:
- // The Topic Name identifies the information channel to which Payload data is published.
- utf8_string topic_name_{};
- // The Packet Identifier field is only present in PUBLISH packets where the QoS level is 1 or 2.
- // a Two Byte Integer Packet Identifier.
- std::optional<two_byte_integer> packet_id_ {};
- // The Payload contains the Application Message that is being published.
- // The content and format of the data is application specific.
- // The length of the Payload can be calculated by subtracting the length of the Variable Header
- // from the Remaining Length field that is in the Fixed Header.
- // It is valid for a PUBLISH packet to contain a zero length Payload.
- application_message payload_ {};
- };
- /**
- * PUBACK - Publish acknowledgement
- *
- * A PUBACK Packet is the response to a PUBLISH Packet with QoS level 1.
- *
- * http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718043
- */
- class puback : public fixed_header<version_number>
- {
- public:
- puback() : fixed_header(control_packet_type::puback)
- {
- update_remain_length();
- }
- explicit puback(std::uint16_t packet_id)
- : fixed_header(control_packet_type::puback)
- , packet_id_ (packet_id)
- {
- update_remain_length();
- }
- inline std::size_t required_size() const
- {
- return (fixed_header::required_size() + fixed_header::remain_length());
- }
- /*
- * The Container is usually a std::string, std::vector<char>, ...
- */
- template<class Container>
- inline puback& serialize(Container& buffer)
- {
- fixed_header::serialize(buffer);
- packet_id_ .serialize(buffer);
- return (*this);
- }
- inline puback& deserialize(std::string_view& data)
- {
- fixed_header::deserialize(data);
- packet_id_ .deserialize(data);
- update_remain_length();
- return (*this);
- }
- inline two_byte_integer::value_type packet_id () const { return packet_id_ .value() ; }
- inline puback & packet_id (std::uint16_t v) { packet_id_ = v; return (*this); }
- inline puback& update_remain_length()
- {
- remain_length_ = static_cast<std::int32_t>(0
- + packet_id_ .required_size()
- );
- return (*this);
- }
- protected:
- // This contains the Packet Identifier from the PUBLISH Packet that is being acknowledged.
- two_byte_integer packet_id_ {};
- };
- /**
- * PUBREC - Publish received (QoS 2 publish received, part 1)
- *
- * A PUBREC Packet is the response to a PUBLISH Packet with QoS 2.
- * It is the second packet of the QoS 2 protocol exchange.
- *
- * http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718048
- */
- class pubrec : public fixed_header<version_number>
- {
- public:
- pubrec() : fixed_header(control_packet_type::pubrec)
- {
- update_remain_length();
- }
- explicit pubrec(std::uint16_t packet_id)
- : fixed_header(control_packet_type::pubrec)
- , packet_id_ (packet_id)
- {
- update_remain_length();
- }
- inline std::size_t required_size() const
- {
- return (fixed_header::required_size() + fixed_header::remain_length());
- }
- /*
- * The Container is usually a std::string, std::vector<char>, ...
- */
- template<class Container>
- inline pubrec& serialize(Container& buffer)
- {
- fixed_header::serialize(buffer);
- packet_id_ .serialize(buffer);
- return (*this);
- }
- inline pubrec& deserialize(std::string_view& data)
- {
- fixed_header::deserialize(data);
- packet_id_ .deserialize(data);
- update_remain_length();
- return (*this);
- }
- inline two_byte_integer::value_type packet_id () const { return packet_id_ .value() ; }
- inline pubrec & packet_id (std::uint16_t v) { packet_id_ = v; return (*this); }
- inline pubrec& update_remain_length()
- {
- remain_length_ = static_cast<std::int32_t>(0
- + packet_id_ .required_size()
- );
- return (*this);
- }
- protected:
- // The variable header contains the Packet Identifier from the PUBLISH Packet that is being acknowledged.
- two_byte_integer packet_id_ {};
- };
- /**
- * PUBREL - Publish release (QoS 2 publish received, part 2)
- *
- * A PUBREL Packet is the response to a PUBREC Packet.
- * It is the third packet of the QoS 2 protocol exchange.
- *
- * http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718053
- */
- class pubrel : public fixed_header<version_number>
- {
- public:
- pubrel() : fixed_header(control_packet_type::pubrel)
- {
- // Bits 3,2,1 and 0 of the Fixed Header in the PUBREL packet are reserved and MUST be
- // set to 0,0,1 and 0 respectively.
- // The Server MUST treat any other value as malformed and close the Network Connection [MQTT-3.6.1-1].
- type_and_flags_.reserved.bit1 = 1;
- update_remain_length();
- }
- explicit pubrel(std::uint16_t packet_id)
- : fixed_header(control_packet_type::pubrel)
- , packet_id_ (packet_id)
- {
- type_and_flags_.reserved.bit1 = 1;
- update_remain_length();
- }
- inline std::size_t required_size() const
- {
- return (fixed_header::required_size() + fixed_header::remain_length());
- }
- /*
- * The Container is usually a std::string, std::vector<char>, ...
- */
- template<class Container>
- inline pubrel& serialize(Container& buffer)
- {
- fixed_header::serialize(buffer);
- packet_id_ .serialize(buffer);
- return (*this);
- }
- inline pubrel& deserialize(std::string_view& data)
- {
- fixed_header::deserialize(data);
- packet_id_ .deserialize(data);
- update_remain_length();
- return (*this);
- }
- inline two_byte_integer::value_type packet_id () const { return packet_id_ .value() ; }
- inline pubrel & packet_id (std::uint16_t v) { packet_id_ = v; return (*this); }
- inline pubrel& update_remain_length()
- {
- remain_length_ = static_cast<std::int32_t>(0
- + packet_id_ .required_size()
- );
- return (*this);
- }
- protected:
- // The variable header contains the same Packet Identifier as the PUBREC Packet that is being acknowledged.
- two_byte_integer packet_id_ {};
- };
- /**
- * PUBCOMP - Publish complete (QoS 2 publish received, part 3)
- *
- * The PUBCOMP Packet is the response to a PUBREL Packet.
- * It is the fourth and final packet of the QoS 2 protocol exchange.
- *
- * http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718058
- */
- class pubcomp : public fixed_header<version_number>
- {
- public:
- pubcomp() : fixed_header(control_packet_type::pubcomp)
- {
- update_remain_length();
- }
- explicit pubcomp(std::uint16_t packet_id)
- : fixed_header(control_packet_type::pubcomp)
- , packet_id_ (packet_id)
- {
- update_remain_length();
- }
- inline std::size_t required_size() const
- {
- return (fixed_header::required_size() + fixed_header::remain_length());
- }
- /*
- * The Container is usually a std::string, std::vector<char>, ...
- */
- template<class Container>
- inline pubcomp& serialize(Container& buffer)
- {
- fixed_header::serialize(buffer);
- packet_id_ .serialize(buffer);
- return (*this);
- }
- inline pubcomp& deserialize(std::string_view& data)
- {
- fixed_header::deserialize(data);
- packet_id_ .deserialize(data);
- update_remain_length();
- return (*this);
- }
- inline two_byte_integer::value_type packet_id () const { return packet_id_ .value() ; }
- inline pubcomp & packet_id (std::uint16_t v) { packet_id_ = v; return (*this); }
- inline pubcomp& update_remain_length()
- {
- remain_length_ = static_cast<std::int32_t>(0
- + packet_id_ .required_size()
- );
- return (*this);
- }
- protected:
- // The variable header contains the same Packet Identifier as the PUBREL Packet that is being acknowledged.
- two_byte_integer packet_id_ {};
- };
- /**
- * SUBSCRIBE - Subscribe to topics
- *
- * The SUBSCRIBE Packet is sent from the Client to the Server to create one or more Subscriptions.
- * Each Subscription registers a Client's interest in one or more Topics.
- * The Server sends PUBLISH Packets to the Client in order to forward Application Messages that were
- * published to Topics that match these Subscriptions.
- * The SUBSCRIBE Packet also specifies (for each Subscription) the maximum QoS with which the Server
- * can send Application Messages to the Client.
- *
- * http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718063
- */
- class subscribe : public fixed_header<version_number>
- {
- public:
- subscribe() : fixed_header(control_packet_type::subscribe)
- {
- // Bits 3,2,1 and 0 of the fixed header of the SUBSCRIBE Control Packet are reserved and MUST be
- // set to 0,0,1 and 0 respectively. The Server MUST treat any other value as malformed and close
- // the Network Connection [MQTT-3.8.1-1].
- type_and_flags_.reserved.bit1 = 1;
- update_remain_length();
- }
- explicit subscribe(std::uint16_t packet_id)
- : fixed_header(control_packet_type::subscribe)
- , packet_id_ (packet_id)
- {
- type_and_flags_.reserved.bit1 = 1;
- update_remain_length();
- }
- inline std::size_t required_size() const
- {
- return (fixed_header::required_size() + fixed_header::remain_length());
- }
- /*
- * The Container is usually a std::string, std::vector<char>, ...
- */
- template<class Container>
- inline subscribe& serialize(Container& buffer)
- {
- update_remain_length();
- fixed_header::serialize(buffer);
- packet_id_ .serialize(buffer);
- subscriptions_.serialize(buffer);
- return (*this);
- }
- inline subscribe& deserialize(std::string_view& data)
- {
- fixed_header::deserialize(data);
- packet_id_ .deserialize(data);
- subscriptions_.deserialize(data);
- update_remain_length();
- return (*this);
- }
- inline two_byte_integer::value_type packet_id () const { return packet_id_ .value() ; }
- inline subscriptions_set& subscriptions() { return subscriptions_ ; }
- inline subscriptions_set const& subscriptions() const { return subscriptions_ ; }
- inline subscribe & packet_id (std::uint16_t v) { packet_id_ = v; return (*this); }
- template<class... Subscriptions>
- inline subscribe& add_subscriptions(Subscriptions&&... Subscripts)
- {
- subscriptions_.add(std::forward<Subscriptions>(Subscripts)...);
- update_remain_length();
- return (*this);
- }
- inline subscribe& erase_subscription(std::string_view topic_filter)
- {
- subscriptions_.erase(topic_filter);
- update_remain_length();
- return (*this);
- }
- inline subscribe& update_remain_length()
- {
- remain_length_ = static_cast<std::int32_t>(0
- + packet_id_ .required_size()
- + subscriptions_.required_size()
- );
- return (*this);
- }
- protected:
- // The variable header contains a Packet Identifier.
- two_byte_integer packet_id_ {};
- // The payload of a SUBSCRIBE Packet contains a list of Topic Filters indicating the Topics
- // to which the Client wants to subscribe. The Topic Filters in a SUBSCRIBE packet payload
- // MUST be UTF-8 encoded strings as defined in Section 1.5.3 [MQTT-3.8.3-1]. A Server SHOULD
- // support Topic filters that contain the wildcard characters defined in Section 4.7.1. If
- // it chooses not to support topic filters that contain wildcard characters it MUST reject
- // any Subscription request whose filter contains them [MQTT-3.8.3-2]. Each filter is
- // followed by a byte called the Requested QoS. This gives the maximum QoS level at which
- // the Server can send Application Messages to the Client.
- subscriptions_set subscriptions_{};
- };
- /**
- * SUBACK - Subscribe acknowledgement
- *
- * A SUBACK Packet is sent by the Server to the Client to confirm receipt and processing of a SUBSCRIBE Packet.
- *
- * http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718068
- */
- class suback : public fixed_header<version_number>
- {
- public:
- suback() : fixed_header(control_packet_type::suback)
- {
- update_remain_length();
- }
- explicit suback(std::uint16_t packet_id)
- : fixed_header(control_packet_type::suback)
- , packet_id_ (packet_id)
- {
- update_remain_length();
- }
- inline std::size_t required_size() const
- {
- return (fixed_header::required_size() + fixed_header::remain_length());
- }
- /*
- * The Container is usually a std::string, std::vector<char>, ...
- */
- template<class Container>
- inline suback& serialize(Container& buffer)
- {
- update_remain_length();
- fixed_header::serialize(buffer);
- packet_id_ .serialize(buffer);
- reason_codes_ .serialize(buffer);
- return (*this);
- }
- inline suback& deserialize(std::string_view& data)
- {
- fixed_header::deserialize(data);
- packet_id_ .deserialize(data);
- reason_codes_ .deserialize(data);
- update_remain_length();
- return (*this);
- }
- inline two_byte_integer::value_type packet_id () const { return packet_id_ .value() ; }
- inline one_byte_integer_set & reason_codes () { return reason_codes_ ; }
- inline one_byte_integer_set const& reason_codes () const { return reason_codes_ ; }
- inline suback & packet_id (std::uint16_t v) { packet_id_ = v; return (*this); }
- template<class... Integers>
- inline suback& add_reason_codes(Integers... Ints)
- {
- reason_codes_.add(static_cast<one_byte_integer::value_type>(Ints)...);
- update_remain_length();
- return (*this);
- }
- inline suback& erase_reason_code(std::size_t index)
- {
- reason_codes_.erase(index);
- update_remain_length();
- return (*this);
- }
- inline suback& update_remain_length()
- {
- remain_length_ = static_cast<std::int32_t>(0
- + packet_id_ .required_size()
- + reason_codes_ .required_size()
- );
- return (*this);
- }
- protected:
- // The variable header contains the Packet Identifier from the SUBSCRIBE Packet that is being acknowledged.
- two_byte_integer packet_id_ {};
- // The payload contains a list of return codes. Each return code corresponds to a Topic Filter
- // in the SUBSCRIBE Packet being acknowledged. The order of return codes in the SUBACK Packet
- // MUST match the order of Topic Filters in the SUBSCRIBE Packet [MQTT-3.9.3-1].
- one_byte_integer_set reason_codes_{};
- };
- /**
- * UNSUBSCRIBE - Unsubscribe from topics
- *
- * An UNSUBSCRIBE Packet is sent by the Client to the Server, to unsubscribe from topics.
- *
- * http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718072
- */
- class unsubscribe : public fixed_header<version_number>
- {
- public:
- unsubscribe() : fixed_header(control_packet_type::unsubscribe)
- {
- // Bits 3,2,1 and 0 of the Fixed Header of the UNSUBSCRIBE packet are reserved and MUST
- // be set to 0,0,1 and 0 respectively. The Server MUST treat any other value as malformed
- // and close the Network Connection [MQTT-3.10.1-1].
- type_and_flags_.reserved.bit1 = 1;
- update_remain_length();
- }
- template<class... Strings>
- explicit unsubscribe(std::uint16_t packet_id, Strings&&... topic_filters)
- : fixed_header (control_packet_type::unsubscribe)
- , packet_id_ (packet_id)
- , topic_filters_(std::forward<Strings>(topic_filters)...)
- {
- type_and_flags_.reserved.bit1 = 1;
- update_remain_length();
- }
- inline std::size_t required_size() const
- {
- return (fixed_header::required_size() + fixed_header::remain_length());
- }
- /*
- * The Container is usually a std::string, std::vector<char>, ...
- */
- template<class Container>
- inline unsubscribe& serialize(Container& buffer)
- {
- update_remain_length();
- fixed_header::serialize(buffer);
- packet_id_ .serialize(buffer);
- topic_filters_.serialize(buffer);
- return (*this);
- }
- inline unsubscribe& deserialize(std::string_view& data)
- {
- fixed_header::deserialize(data);
- packet_id_ .deserialize(data);
- topic_filters_.deserialize(data);
- update_remain_length();
- return (*this);
- }
- inline two_byte_integer::value_type packet_id () const { return packet_id_ .value() ; }
- inline utf8_string_set & topic_filters() { return topic_filters_ ; }
- inline utf8_string_set const& topic_filters() const { return topic_filters_ ; }
- inline unsubscribe & packet_id (std::uint16_t v) { packet_id_ = v; return (*this); }
- template<class... Strings>
- inline unsubscribe& add_topic_filters(Strings&&... Strs)
- {
- topic_filters_.add(std::forward<Strings>(Strs)...);
- update_remain_length();
- return (*this);
- }
- inline unsubscribe& erase_topic_filter(std::string_view topic_filter)
- {
- topic_filters_.erase(topic_filter);
- update_remain_length();
- return (*this);
- }
- inline unsubscribe& update_remain_length()
- {
- remain_length_ = static_cast<std::int32_t>(0
- + packet_id_ .required_size()
- + topic_filters_.required_size()
- );
- return (*this);
- }
- protected:
- // The variable header contains a Packet Identifier.
- two_byte_integer packet_id_ {};
- // The payload for the UNSUBSCRIBE Packet contains the list of Topic Filters that the Client
- // wishes to unsubscribe from. The Topic Filters in an UNSUBSCRIBE packet MUST be UTF-8
- // encoded strings as defined in Section 1.5.3, packed contiguously [MQTT-3.10.3-1].
- // The Payload of an UNSUBSCRIBE packet MUST contain at least one Topic Filter.An UNSUBSCRIBE
- // packet with no payload is a protocol violation[MQTT - 3.10.3 - 2].See section 4.8 for
- // information about handling errors.
- utf8_string_set topic_filters_{};
- };
- /**
- * UNSUBACK - Unsubscribe acknowledgement
- *
- * The UNSUBACK packet is sent by the Server to the Client to confirm receipt of an UNSUBSCRIBE packet.
- *
- * http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718077
- */
- class unsuback : public fixed_header<version_number>
- {
- public:
- unsuback() : fixed_header(control_packet_type::unsuback)
- {
- update_remain_length();
- }
- explicit unsuback(std::uint16_t packet_id)
- : fixed_header(control_packet_type::unsuback)
- , packet_id_ (packet_id)
- {
- update_remain_length();
- }
- inline std::size_t required_size() const
- {
- return (fixed_header::required_size() + fixed_header::remain_length());
- }
- /*
- * The Container is usually a std::string, std::vector<char>, ...
- */
- template<class Container>
- inline unsuback& serialize(Container& buffer)
- {
- fixed_header::serialize(buffer);
- packet_id_ .serialize(buffer);
- return (*this);
- }
- inline unsuback& deserialize(std::string_view& data)
- {
- fixed_header::deserialize(data);
- packet_id_ .deserialize(data);
- update_remain_length();
- return (*this);
- }
- inline two_byte_integer::value_type packet_id () const { return packet_id_ .value() ; }
- inline unsuback & packet_id (std::uint16_t v) { packet_id_ = v; return (*this); }
- inline unsuback& update_remain_length()
- {
- remain_length_ = static_cast<std::int32_t>(0
- + packet_id_ .required_size()
- );
- return (*this);
- }
- protected:
- // The variable header contains the Packet Identifier of the UNSUBSCRIBE Packet that is being acknowledged.
- two_byte_integer packet_id_ {};
- // The UNSUBACK Packet has no payload.
- };
- /**
- * PINGREQ - PING request
- *
- * The PINGREQ packet is sent from a Client to the Server.
- *
- * http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718081
- */
- class pingreq : public fixed_header<version_number>
- {
- public:
- pingreq() : fixed_header(control_packet_type::pingreq)
- {
- update_remain_length();
- }
- inline std::size_t required_size() const
- {
- return (fixed_header::required_size() + fixed_header::remain_length());
- }
- /*
- * The Container is usually a std::string, std::vector<char>, ...
- */
- template<class Container>
- inline pingreq& serialize(Container& buffer)
- {
- fixed_header::serialize(buffer);
- return (*this);
- }
- inline pingreq& deserialize(std::string_view& data)
- {
- fixed_header::deserialize(data);
- update_remain_length();
- return (*this);
- }
- inline pingreq& update_remain_length()
- {
- remain_length_ = static_cast<std::int32_t>(0
- );
- return (*this);
- }
- protected:
- // The PINGREQ packet has no Variable Header.
- // The PINGREQ packet has no Payload.
- };
- /**
- * PINGRESP - PING response
- *
- * A PINGRESP Packet is sent by the Server to the Client in response to a PINGREQ packet.
- * It indicates that the Server is alive.
- *
- * http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718086
- */
- class pingresp : public fixed_header<version_number>
- {
- public:
- pingresp() : fixed_header(control_packet_type::pingresp)
- {
- update_remain_length();
- }
- inline std::size_t required_size() const
- {
- return (fixed_header::required_size() + fixed_header::remain_length());
- }
- /*
- * The Container is usually a std::string, std::vector<char>, ...
- */
- template<class Container>
- inline pingresp& serialize(Container& buffer)
- {
- fixed_header::serialize(buffer);
- return (*this);
- }
- inline pingresp& deserialize(std::string_view& data)
- {
- fixed_header::deserialize(data);
- update_remain_length();
- return (*this);
- }
- inline pingresp& update_remain_length()
- {
- remain_length_ = static_cast<std::int32_t>(0
- );
- return (*this);
- }
- protected:
- // The PINGRESP packet has no Variable Header.
- // The PINGRESP packet has no Payload.
- };
- /**
- * DISCONNECT - Disconnect notification
- *
- * The DISCONNECT Packet is the final Control Packet sent from the Client to the Server.
- * It indicates that the Client is disconnecting cleanly.
- *
- * http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718090
- */
- class disconnect : public fixed_header<version_number>
- {
- public:
- disconnect() : fixed_header(control_packet_type::disconnect)
- {
- update_remain_length();
- }
- inline std::size_t required_size() const
- {
- return (fixed_header::required_size() + fixed_header::remain_length());
- }
- /*
- * The Container is usually a std::string, std::vector<char>, ...
- */
- template<class Container>
- inline disconnect& serialize(Container& buffer)
- {
- fixed_header::serialize(buffer);
- return (*this);
- }
- inline disconnect& deserialize(std::string_view& data)
- {
- fixed_header::deserialize(data);
- update_remain_length();
- return (*this);
- }
- inline disconnect& update_remain_length()
- {
- remain_length_ = static_cast<std::int32_t>(0
- );
- return (*this);
- }
- protected:
- // The DISCONNECT Packet has no variable header.
- // The DISCONNECT Packet has no payload.
- };
- }
- namespace asio2::mqtt
- {
- template<typename = void>
- inline constexpr std::string_view to_string(v4::connect_reason_code v)
- {
- using namespace std::string_view_literals;
- switch(v)
- {
- case v4::connect_reason_code::success : return "Connection accepted"sv;
- case v4::connect_reason_code::unacceptable_protocol_version : return "The Server does not support the level of the MQTT protocol requested by the Client"sv;
- case v4::connect_reason_code::identifier_rejected : return "The Client identifier is correct UTF-8 but not allowed by the Server"sv;
- case v4::connect_reason_code::server_unavailable : return "The Network Connection has been made but the MQTT service is unavailable"sv;
- case v4::connect_reason_code::bad_user_name_or_password : return "The data in the user name or password is malformed"sv;
- case v4::connect_reason_code::not_authorized : return "The Client is not authorized to connect"sv;
- default:
- ASIO2_ASSERT(false);
- break;
- }
- return "unknown"sv;
- }
- template<typename message_type>
- inline constexpr bool is_v4_message()
- {
- using type = asio2::detail::remove_cvref_t<message_type>;
- if constexpr (
- std::is_same_v<type, mqtt::v4::connect > ||
- std::is_same_v<type, mqtt::v4::connack > ||
- std::is_same_v<type, mqtt::v4::publish > ||
- std::is_same_v<type, mqtt::v4::puback > ||
- std::is_same_v<type, mqtt::v4::pubrec > ||
- std::is_same_v<type, mqtt::v4::pubrel > ||
- std::is_same_v<type, mqtt::v4::pubcomp > ||
- std::is_same_v<type, mqtt::v4::subscribe > ||
- std::is_same_v<type, mqtt::v4::suback > ||
- std::is_same_v<type, mqtt::v4::unsubscribe > ||
- std::is_same_v<type, mqtt::v4::unsuback > ||
- std::is_same_v<type, mqtt::v4::pingreq > ||
- std::is_same_v<type, mqtt::v4::pingresp > ||
- std::is_same_v<type, mqtt::v4::disconnect > )
- {
- return true;
- }
- else
- {
- return false;
- }
- }
- }
- #endif // !__ASIO2_MQTT_PROTOCOL_V4_HPP__
|