protocol_v4.hpp 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392
  1. /*
  2. * Copyright (c) 2017-2023 zhllxt
  3. *
  4. * author : zhllxt
  5. * email : 37792738@qq.com
  6. *
  7. * chinese : http://blog.mcxiaoke.com/mqtt/protocol/MQTT-3.1.1-CN.html
  8. * english : http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html
  9. *
  10. * Distributed under the Boost Software License, Version 1.0. (See accompanying
  11. * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  12. */
  13. #ifndef __ASIO2_MQTT_PROTOCOL_V4_HPP__
  14. #define __ASIO2_MQTT_PROTOCOL_V4_HPP__
  15. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  16. #pragma once
  17. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  18. #include <asio2/mqtt/core.hpp>
  19. namespace asio2::mqtt::v4
  20. {
  21. static constexpr std::uint8_t version_number = asio2::detail::to_underlying(mqtt::version::v4);
  22. enum class connect_reason_code : std::uint8_t
  23. {
  24. /* 0 0x00 Connection Accepted : */ success = 0,
  25. /* 1 0x01 Connection Refused : */ unacceptable_protocol_version = 1,
  26. /* 2 0x02 Connection Refused : */ identifier_rejected = 2,
  27. /* 3 0x03 Connection Refused : */ server_unavailable = 3,
  28. /* 4 0x04 Connection Refused : */ bad_user_name_or_password = 4,
  29. /* 5 0x05 Connection Refused : */ not_authorized = 5,
  30. /* 6 - 255 Reserved for future use */
  31. };
  32. /**
  33. * CONNECT - Client requests a connection to a Server
  34. *
  35. * After a Network Connection is established by a Client to a Server, the first packet sent from the
  36. * Client to the Server MUST be a CONNECT packet [MQTT-3.1.0-1].
  37. *
  38. * A Client can only send the CONNECT Packet once over a Network Connection. The Server MUST process
  39. * a second CONNECT Packet sent from a Client as a protocol violation and disconnect the Client
  40. *
  41. * http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718028
  42. */
  43. class connect : public fixed_header<version_number>
  44. {
  45. public:
  46. connect() : fixed_header(control_packet_type::connect)
  47. {
  48. update_remain_length();
  49. }
  50. connect(utf8_string::value_type clientid) : fixed_header(control_packet_type::connect)
  51. {
  52. client_id(std::move(clientid));
  53. update_remain_length();
  54. }
  55. inline std::size_t required_size() const
  56. {
  57. return (fixed_header::required_size() + fixed_header::remain_length());
  58. }
  59. /*
  60. * The Container is usually a std::string, std::vector<char>, ...
  61. */
  62. template<class Container>
  63. inline connect& serialize(Container& buffer)
  64. {
  65. fixed_header::serialize(buffer);
  66. protocol_name_ .serialize(buffer);
  67. protocol_version_ .serialize(buffer);
  68. connect_flags_.byte .serialize(buffer);
  69. keep_alive_ .serialize(buffer);
  70. client_id_ .serialize(buffer);
  71. if (will_topic_ ) will_topic_ ->serialize(buffer);
  72. if (will_payload_) will_payload_->serialize(buffer);
  73. if (username_ ) username_ ->serialize(buffer);
  74. if (password_ ) password_ ->serialize(buffer);
  75. return (*this);
  76. }
  77. inline connect& deserialize(std::string_view& data)
  78. {
  79. fixed_header::deserialize(data);
  80. protocol_name_ .deserialize(data);
  81. protocol_version_ .deserialize(data);
  82. connect_flags_.byte .deserialize(data);
  83. keep_alive_ .deserialize(data);
  84. client_id_ .deserialize(data);
  85. if (has_will())
  86. {
  87. utf8_string will_topic{};
  88. will_topic.deserialize(data);
  89. will_topic_ = std::move(will_topic);
  90. binary_data will_payload{};
  91. will_payload.deserialize(data);
  92. will_payload_ = std::move(will_payload);
  93. }
  94. if (has_username())
  95. {
  96. utf8_string username{};
  97. username.deserialize(data);
  98. username_ = std::move(username);
  99. }
  100. if (has_password())
  101. {
  102. binary_data password{};
  103. password.deserialize(data);
  104. password_ = std::move(password);
  105. }
  106. update_remain_length();
  107. return (*this);
  108. }
  109. inline std::uint8_t protocol_version() const { return (protocol_version_ ); }
  110. inline bool clean_start () const { return (connect_flags_.bits.clean_session); }
  111. inline bool clean_session () const { return (connect_flags_.bits.clean_session); }
  112. inline bool has_will () const { return (connect_flags_.bits.will_flag ); }
  113. inline qos_type will_qos () const { return static_cast<qos_type>(connect_flags_.bits.will_qos ); }
  114. inline bool will_retain () const { return (connect_flags_.bits.will_retain ); }
  115. inline bool has_password () const { return (connect_flags_.bits.password_flag); }
  116. inline bool has_username () const { return (connect_flags_.bits.username_flag); }
  117. inline connect& clean_start (bool v) { connect_flags_.bits.clean_session = v; return (*this); }
  118. inline connect& clean_session (bool v) { connect_flags_.bits.clean_session = v; return (*this); }
  119. inline two_byte_integer::value_type keep_alive () const { return keep_alive_ ; }
  120. inline utf8_string::view_type client_id () const { return client_id_ .data_view(); }
  121. inline utf8_string::view_type will_topic () const { return will_topic_ ? will_topic_ ->data_view() : ""; }
  122. inline binary_data::view_type will_payload () const { return will_payload_ ? will_payload_->data_view() : ""; }
  123. inline utf8_string::view_type username () const { return username_ ? username_ ->data_view() : ""; }
  124. inline binary_data::view_type password () const { return password_ ? password_ ->data_view() : ""; }
  125. inline connect& keep_alive(two_byte_integer::value_type v)
  126. {
  127. keep_alive_ = std::move(v);
  128. return (*this);
  129. }
  130. template<class String>
  131. inline connect& client_id(String&& v)
  132. {
  133. client_id_ = std::forward<String>(v);
  134. update_remain_length();
  135. return (*this);
  136. }
  137. template<class String>
  138. inline connect& username(String&& v)
  139. {
  140. username_ = std::forward<String>(v);
  141. connect_flags_.bits.username_flag = true;
  142. update_remain_length();
  143. return (*this);
  144. }
  145. inline connect& password(binary_data::value_type v)
  146. {
  147. password_ = std::move(v);
  148. connect_flags_.bits.password_flag = true;
  149. update_remain_length();
  150. return (*this);
  151. }
  152. template<class String1, class String2, class QosOrInt>
  153. inline connect& will_attributes(String1&& topic, String2&& payload,
  154. QosOrInt qos = qos_type::at_most_once, bool retain = false)
  155. {
  156. will_topic_ = std::forward<String1>(topic);
  157. will_payload_ = std::forward<String2>(payload);
  158. connect_flags_.bits.will_flag = true;
  159. connect_flags_.bits.will_qos = static_cast<std::uint8_t>(qos);
  160. connect_flags_.bits.will_retain = retain;
  161. update_remain_length();
  162. return (*this);
  163. }
  164. inline bool will_topic_has_value() const noexcept { return will_topic_.has_value(); }
  165. inline bool username_has_value () const noexcept { return username_ .has_value(); }
  166. inline bool password_has_value () const noexcept { return password_ .has_value(); }
  167. inline connect& update_remain_length()
  168. {
  169. remain_length_ = static_cast<std::int32_t>(0
  170. + protocol_name_ .required_size()
  171. + protocol_version_ .required_size()
  172. + connect_flags_.byte .required_size()
  173. + keep_alive_ .required_size()
  174. + client_id_ .required_size()
  175. + (will_topic_ ? will_topic_ ->required_size() : 0)
  176. + (will_payload_ ? will_payload_->required_size() : 0)
  177. + (username_ ? username_ ->required_size() : 0)
  178. + (password_ ? password_ ->required_size() : 0)
  179. );
  180. return (*this);
  181. }
  182. protected:
  183. // The Protocol Name is a UTF-8 Encoded String that represents the protocol name "MQTT".
  184. // The string, its offset and length will not be changed by future versions of the MQTT specification.
  185. utf8_string protocol_name_{ "MQTT" };
  186. // The 8 bit unsigned value that represents the revision level of the protocol used by the Client.
  187. // The value of the Protocol Level field for the version 3.1.1 of the protocol is 4 (0x04).
  188. one_byte_integer protocol_version_{ 0x04 };
  189. union
  190. {
  191. one_byte_integer byte{ 0 }; // all connect flags
  192. #if ASIO2_ENDIAN_BIG_BYTE
  193. struct
  194. {
  195. bool username_flag : 1; // User Name Flag
  196. bool password_flag : 1; // Password Flag
  197. bool will_retain : 1; // will retain setting
  198. std::uint8_t will_qos : 2; // will QoS value
  199. bool will_flag : 1; // will flag
  200. bool clean_session : 1; // Clean Session flag
  201. std::uint8_t reserved : 1; // unused
  202. } bits;
  203. #else
  204. struct
  205. {
  206. std::uint8_t reserved : 1; // unused
  207. bool clean_session : 1; // Clean Session flag
  208. bool will_flag : 1; // will flag
  209. std::uint8_t will_qos : 2; // will QoS value
  210. bool will_retain : 1; // will retain setting
  211. bool password_flag : 1; // Password Flag
  212. bool username_flag : 1; // User Name Flag
  213. } bits;
  214. #endif
  215. } connect_flags_{}; // connect flags byte
  216. // The Keep Alive is a time interval measured in seconds. Expressed as a 16-bit word
  217. // Default to 60 seconds
  218. two_byte_integer keep_alive_ { 60 };
  219. // The Client Identifier (ClientID) identifies the Client to the Server.
  220. // Each Client connecting to the Server has a unique ClientID.
  221. utf8_string client_id_ {};
  222. // If the Will Flag is set to 1, the Will Topic is the next field in the Payload.
  223. std::optional<utf8_string> will_topic_ {};
  224. // If the Will Flag is set to 1 the Will Payload is the next field in the Payload.
  225. std::optional<binary_data> will_payload_{};
  226. // If the User Name Flag is set to 1, the User Name is the next field in the Payload.
  227. std::optional<utf8_string> username_ {};
  228. // If the Password Flag is set to 1, the Password is the next field in the Payload.
  229. std::optional<binary_data> password_ {};
  230. };
  231. /**
  232. * CONNACK - Acknowledge connection request
  233. *
  234. * http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718033
  235. */
  236. class connack : public fixed_header<version_number>
  237. {
  238. public:
  239. connack() : fixed_header(control_packet_type::connack)
  240. {
  241. update_remain_length();
  242. }
  243. explicit connack(bool session_present, std::uint8_t reason_code)
  244. : fixed_header(control_packet_type::connack)
  245. , reason_code_(reason_code)
  246. {
  247. connack_flags_.bits.session_present = session_present;
  248. update_remain_length();
  249. }
  250. explicit connack(bool session_present, connect_reason_code reason_code)
  251. : fixed_header(control_packet_type::connack)
  252. , reason_code_(asio2::detail::to_underlying(reason_code))
  253. {
  254. connack_flags_.bits.session_present = session_present;
  255. update_remain_length();
  256. }
  257. inline std::size_t required_size() const
  258. {
  259. return (fixed_header::required_size() + fixed_header::remain_length());
  260. }
  261. /*
  262. * The Container is usually a std::string, std::vector<char>, ...
  263. */
  264. template<class Container>
  265. inline connack& serialize(Container& buffer)
  266. {
  267. fixed_header::serialize(buffer);
  268. connack_flags_.byte .serialize(buffer);
  269. reason_code_ .serialize(buffer);
  270. return (*this);
  271. }
  272. inline connack& deserialize(std::string_view& data)
  273. {
  274. fixed_header::deserialize(data);
  275. connack_flags_.byte .deserialize(data);
  276. reason_code_ .deserialize(data);
  277. update_remain_length();
  278. return (*this);
  279. }
  280. inline bool session_present() const { return connack_flags_.bits.session_present; }
  281. inline connect_reason_code reason_code () const { return static_cast<connect_reason_code>(reason_code_.value()); }
  282. inline connack & session_present(bool v) { connack_flags_.bits.session_present = v; return (*this); }
  283. inline connack & reason_code (std::uint8_t v) { reason_code_ = v; return (*this); }
  284. inline connack & reason_code (connect_reason_code v)
  285. { reason_code_ = asio2::detail::to_underlying(v); return (*this); }
  286. inline connack& update_remain_length()
  287. {
  288. remain_length_ = static_cast<std::int32_t>(0
  289. + connack_flags_.byte .required_size()
  290. + reason_code_ .required_size()
  291. );
  292. return (*this);
  293. }
  294. protected:
  295. union
  296. {
  297. one_byte_integer byte{ 0 }; // all connack flags
  298. #if ASIO2_ENDIAN_BIG_BYTE
  299. struct
  300. {
  301. std::uint8_t reserved : 7;
  302. bool session_present : 1; // session found on the server?
  303. } bits;
  304. #else
  305. struct
  306. {
  307. bool session_present : 1; // session found on the server?
  308. std::uint8_t reserved : 7;
  309. } bits;
  310. #endif
  311. } connack_flags_{}; // connack flags
  312. // Byte 2 in the Variable Header is the Connect Reason Code.
  313. one_byte_integer reason_code_{ 0 };
  314. };
  315. /**
  316. * PUBLISH - Publish message
  317. *
  318. * A PUBLISH packet is sent from a Client to a Server or from a Server to a Client to transport an Application Message.
  319. *
  320. * http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718037
  321. */
  322. class publish : public fixed_header<version_number>
  323. {
  324. public:
  325. publish() : fixed_header(control_packet_type::publish)
  326. {
  327. update_remain_length();
  328. }
  329. template<class String1, class String2, class QosOrInt, std::enable_if_t<
  330. asio2::detail::is_character_string_v<String1>, int> = 0>
  331. explicit publish(String1&& topic_name, String2&& payload, QosOrInt qos,
  332. bool dup = false, bool retain = false)
  333. : fixed_header(control_packet_type::publish)
  334. , topic_name_ (std::forward<String1>(topic_name))
  335. , payload_ (std::forward<String2>(payload ))
  336. {
  337. type_and_flags_.bits.dup = dup;
  338. type_and_flags_.bits.qos = static_cast<std::uint8_t>(qos);
  339. type_and_flags_.bits.retain = retain;
  340. update_remain_length();
  341. }
  342. template<class String1, class String2, class QosOrInt, std::enable_if_t<
  343. asio2::detail::is_character_string_v<String1>, int> = 0>
  344. explicit publish(std::uint16_t pid, String1&& topic_name, String2&& payload, QosOrInt qos,
  345. bool dup = false, bool retain = false)
  346. : fixed_header(control_packet_type::publish)
  347. , topic_name_ (std::forward<String1>(topic_name))
  348. , packet_id_ (pid)
  349. , payload_ (std::forward<String2>(payload ))
  350. {
  351. type_and_flags_.bits.dup = dup;
  352. type_and_flags_.bits.qos = static_cast<std::uint8_t>(qos);
  353. type_and_flags_.bits.retain = retain;
  354. ASIO2_ASSERT(type_and_flags_.bits.qos > std::uint8_t(0));
  355. update_remain_length();
  356. }
  357. inline std::size_t required_size() const
  358. {
  359. return (fixed_header::required_size() + fixed_header::remain_length());
  360. }
  361. /*
  362. * The Container is usually a std::string, std::vector<char>, ...
  363. */
  364. template<class Container>
  365. inline publish& serialize(Container& buffer)
  366. {
  367. fixed_header::serialize(buffer);
  368. // The Packet Identifier field is only present in PUBLISH packets where the QoS level is 1 or 2.
  369. // A PUBLISH packet MUST NOT contain a Packet Identifier if its QoS value is set to 0
  370. if ((type_and_flags_.bits.qos == std::uint8_t(0) && packet_id_.has_value()) ||
  371. (type_and_flags_.bits.qos > std::uint8_t(0) && !packet_id_.has_value()))
  372. {
  373. ASIO2_ASSERT(false);
  374. asio2::set_last_error(mqtt::make_error_code(mqtt::error::malformed_packet));
  375. }
  376. topic_name_.serialize(buffer);
  377. if (type_and_flags_.bits.qos > std::uint8_t(0) && packet_id_.has_value())
  378. {
  379. packet_id_->serialize(buffer);
  380. }
  381. payload_.serialize(buffer);
  382. return (*this);
  383. }
  384. inline publish& deserialize(std::string_view& data)
  385. {
  386. fixed_header::deserialize(data);
  387. topic_name_.deserialize(data);
  388. // A PUBLISH Packet MUST NOT contain a Packet Identifier if its QoS value is set to 0 [MQTT-2.3.1-5].
  389. if (type_and_flags_.bits.qos == 1 || type_and_flags_.bits.qos == 2)
  390. {
  391. two_byte_integer packet_id{};
  392. packet_id.deserialize(data);
  393. packet_id_ = packet_id;
  394. }
  395. payload_ .deserialize(data);
  396. update_remain_length();
  397. return (*this);
  398. }
  399. inline bool dup () const { return (type_and_flags_.bits.dup ); }
  400. inline qos_type qos () const { return static_cast<qos_type>(type_and_flags_.bits.qos ); }
  401. inline bool retain() const { return (type_and_flags_.bits.retain); }
  402. inline publish & dup (bool v) { type_and_flags_.bits.dup = v; return (*this); }
  403. template<class QosOrInt>
  404. inline publish & qos (QosOrInt v) { type_and_flags_.bits.qos = static_cast<std::uint8_t>(v); return (*this); }
  405. inline publish & retain(bool v) { type_and_flags_.bits.retain = v; return (*this); }
  406. inline utf8_string::view_type topic_name() const { return topic_name_.data_view(); }
  407. inline two_byte_integer::value_type packet_id () const { return packet_id_ ? packet_id_->value() : 0; }
  408. inline application_message::view_type payload () const { return payload_.data_view() ; }
  409. inline publish & packet_id (std::uint16_t v) { packet_id_ = v ; update_remain_length(); return (*this); }
  410. template<class String>
  411. inline publish & topic_name(String&& v) { topic_name_ = std::forward<String>(v); update_remain_length(); return (*this); }
  412. template<class String>
  413. inline publish & payload (String&& v) { payload_ = std::forward<String>(v); update_remain_length(); return (*this); }
  414. inline bool has_packet_id() const noexcept { return packet_id_.has_value(); }
  415. inline publish& update_remain_length()
  416. {
  417. remain_length_ = static_cast<std::int32_t>(0
  418. + topic_name_.required_size()
  419. + (packet_id_ ? packet_id_->required_size() : 0)
  420. + payload_ .required_size()
  421. );
  422. return (*this);
  423. }
  424. protected:
  425. // The Topic Name identifies the information channel to which Payload data is published.
  426. utf8_string topic_name_{};
  427. // The Packet Identifier field is only present in PUBLISH packets where the QoS level is 1 or 2.
  428. // a Two Byte Integer Packet Identifier.
  429. std::optional<two_byte_integer> packet_id_ {};
  430. // The Payload contains the Application Message that is being published.
  431. // The content and format of the data is application specific.
  432. // The length of the Payload can be calculated by subtracting the length of the Variable Header
  433. // from the Remaining Length field that is in the Fixed Header.
  434. // It is valid for a PUBLISH packet to contain a zero length Payload.
  435. application_message payload_ {};
  436. };
  437. /**
  438. * PUBACK - Publish acknowledgement
  439. *
  440. * A PUBACK Packet is the response to a PUBLISH Packet with QoS level 1.
  441. *
  442. * http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718043
  443. */
  444. class puback : public fixed_header<version_number>
  445. {
  446. public:
  447. puback() : fixed_header(control_packet_type::puback)
  448. {
  449. update_remain_length();
  450. }
  451. explicit puback(std::uint16_t packet_id)
  452. : fixed_header(control_packet_type::puback)
  453. , packet_id_ (packet_id)
  454. {
  455. update_remain_length();
  456. }
  457. inline std::size_t required_size() const
  458. {
  459. return (fixed_header::required_size() + fixed_header::remain_length());
  460. }
  461. /*
  462. * The Container is usually a std::string, std::vector<char>, ...
  463. */
  464. template<class Container>
  465. inline puback& serialize(Container& buffer)
  466. {
  467. fixed_header::serialize(buffer);
  468. packet_id_ .serialize(buffer);
  469. return (*this);
  470. }
  471. inline puback& deserialize(std::string_view& data)
  472. {
  473. fixed_header::deserialize(data);
  474. packet_id_ .deserialize(data);
  475. update_remain_length();
  476. return (*this);
  477. }
  478. inline two_byte_integer::value_type packet_id () const { return packet_id_ .value() ; }
  479. inline puback & packet_id (std::uint16_t v) { packet_id_ = v; return (*this); }
  480. inline puback& update_remain_length()
  481. {
  482. remain_length_ = static_cast<std::int32_t>(0
  483. + packet_id_ .required_size()
  484. );
  485. return (*this);
  486. }
  487. protected:
  488. // This contains the Packet Identifier from the PUBLISH Packet that is being acknowledged.
  489. two_byte_integer packet_id_ {};
  490. };
  491. /**
  492. * PUBREC - Publish received (QoS 2 publish received, part 1)
  493. *
  494. * A PUBREC Packet is the response to a PUBLISH Packet with QoS 2.
  495. * It is the second packet of the QoS 2 protocol exchange.
  496. *
  497. * http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718048
  498. */
  499. class pubrec : public fixed_header<version_number>
  500. {
  501. public:
  502. pubrec() : fixed_header(control_packet_type::pubrec)
  503. {
  504. update_remain_length();
  505. }
  506. explicit pubrec(std::uint16_t packet_id)
  507. : fixed_header(control_packet_type::pubrec)
  508. , packet_id_ (packet_id)
  509. {
  510. update_remain_length();
  511. }
  512. inline std::size_t required_size() const
  513. {
  514. return (fixed_header::required_size() + fixed_header::remain_length());
  515. }
  516. /*
  517. * The Container is usually a std::string, std::vector<char>, ...
  518. */
  519. template<class Container>
  520. inline pubrec& serialize(Container& buffer)
  521. {
  522. fixed_header::serialize(buffer);
  523. packet_id_ .serialize(buffer);
  524. return (*this);
  525. }
  526. inline pubrec& deserialize(std::string_view& data)
  527. {
  528. fixed_header::deserialize(data);
  529. packet_id_ .deserialize(data);
  530. update_remain_length();
  531. return (*this);
  532. }
  533. inline two_byte_integer::value_type packet_id () const { return packet_id_ .value() ; }
  534. inline pubrec & packet_id (std::uint16_t v) { packet_id_ = v; return (*this); }
  535. inline pubrec& update_remain_length()
  536. {
  537. remain_length_ = static_cast<std::int32_t>(0
  538. + packet_id_ .required_size()
  539. );
  540. return (*this);
  541. }
  542. protected:
  543. // The variable header contains the Packet Identifier from the PUBLISH Packet that is being acknowledged.
  544. two_byte_integer packet_id_ {};
  545. };
  546. /**
  547. * PUBREL - Publish release (QoS 2 publish received, part 2)
  548. *
  549. * A PUBREL Packet is the response to a PUBREC Packet.
  550. * It is the third packet of the QoS 2 protocol exchange.
  551. *
  552. * http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718053
  553. */
  554. class pubrel : public fixed_header<version_number>
  555. {
  556. public:
  557. pubrel() : fixed_header(control_packet_type::pubrel)
  558. {
  559. // Bits 3,2,1 and 0 of the Fixed Header in the PUBREL packet are reserved and MUST be
  560. // set to 0,0,1 and 0 respectively.
  561. // The Server MUST treat any other value as malformed and close the Network Connection [MQTT-3.6.1-1].
  562. type_and_flags_.reserved.bit1 = 1;
  563. update_remain_length();
  564. }
  565. explicit pubrel(std::uint16_t packet_id)
  566. : fixed_header(control_packet_type::pubrel)
  567. , packet_id_ (packet_id)
  568. {
  569. type_and_flags_.reserved.bit1 = 1;
  570. update_remain_length();
  571. }
  572. inline std::size_t required_size() const
  573. {
  574. return (fixed_header::required_size() + fixed_header::remain_length());
  575. }
  576. /*
  577. * The Container is usually a std::string, std::vector<char>, ...
  578. */
  579. template<class Container>
  580. inline pubrel& serialize(Container& buffer)
  581. {
  582. fixed_header::serialize(buffer);
  583. packet_id_ .serialize(buffer);
  584. return (*this);
  585. }
  586. inline pubrel& deserialize(std::string_view& data)
  587. {
  588. fixed_header::deserialize(data);
  589. packet_id_ .deserialize(data);
  590. update_remain_length();
  591. return (*this);
  592. }
  593. inline two_byte_integer::value_type packet_id () const { return packet_id_ .value() ; }
  594. inline pubrel & packet_id (std::uint16_t v) { packet_id_ = v; return (*this); }
  595. inline pubrel& update_remain_length()
  596. {
  597. remain_length_ = static_cast<std::int32_t>(0
  598. + packet_id_ .required_size()
  599. );
  600. return (*this);
  601. }
  602. protected:
  603. // The variable header contains the same Packet Identifier as the PUBREC Packet that is being acknowledged.
  604. two_byte_integer packet_id_ {};
  605. };
  606. /**
  607. * PUBCOMP - Publish complete (QoS 2 publish received, part 3)
  608. *
  609. * The PUBCOMP Packet is the response to a PUBREL Packet.
  610. * It is the fourth and final packet of the QoS 2 protocol exchange.
  611. *
  612. * http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718058
  613. */
  614. class pubcomp : public fixed_header<version_number>
  615. {
  616. public:
  617. pubcomp() : fixed_header(control_packet_type::pubcomp)
  618. {
  619. update_remain_length();
  620. }
  621. explicit pubcomp(std::uint16_t packet_id)
  622. : fixed_header(control_packet_type::pubcomp)
  623. , packet_id_ (packet_id)
  624. {
  625. update_remain_length();
  626. }
  627. inline std::size_t required_size() const
  628. {
  629. return (fixed_header::required_size() + fixed_header::remain_length());
  630. }
  631. /*
  632. * The Container is usually a std::string, std::vector<char>, ...
  633. */
  634. template<class Container>
  635. inline pubcomp& serialize(Container& buffer)
  636. {
  637. fixed_header::serialize(buffer);
  638. packet_id_ .serialize(buffer);
  639. return (*this);
  640. }
  641. inline pubcomp& deserialize(std::string_view& data)
  642. {
  643. fixed_header::deserialize(data);
  644. packet_id_ .deserialize(data);
  645. update_remain_length();
  646. return (*this);
  647. }
  648. inline two_byte_integer::value_type packet_id () const { return packet_id_ .value() ; }
  649. inline pubcomp & packet_id (std::uint16_t v) { packet_id_ = v; return (*this); }
  650. inline pubcomp& update_remain_length()
  651. {
  652. remain_length_ = static_cast<std::int32_t>(0
  653. + packet_id_ .required_size()
  654. );
  655. return (*this);
  656. }
  657. protected:
  658. // The variable header contains the same Packet Identifier as the PUBREL Packet that is being acknowledged.
  659. two_byte_integer packet_id_ {};
  660. };
  661. /**
  662. * SUBSCRIBE - Subscribe to topics
  663. *
  664. * The SUBSCRIBE Packet is sent from the Client to the Server to create one or more Subscriptions.
  665. * Each Subscription registers a Client's interest in one or more Topics.
  666. * The Server sends PUBLISH Packets to the Client in order to forward Application Messages that were
  667. * published to Topics that match these Subscriptions.
  668. * The SUBSCRIBE Packet also specifies (for each Subscription) the maximum QoS with which the Server
  669. * can send Application Messages to the Client.
  670. *
  671. * http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718063
  672. */
  673. class subscribe : public fixed_header<version_number>
  674. {
  675. public:
  676. subscribe() : fixed_header(control_packet_type::subscribe)
  677. {
  678. // Bits 3,2,1 and 0 of the fixed header of the SUBSCRIBE Control Packet are reserved and MUST be
  679. // set to 0,0,1 and 0 respectively. The Server MUST treat any other value as malformed and close
  680. // the Network Connection [MQTT-3.8.1-1].
  681. type_and_flags_.reserved.bit1 = 1;
  682. update_remain_length();
  683. }
  684. explicit subscribe(std::uint16_t packet_id)
  685. : fixed_header(control_packet_type::subscribe)
  686. , packet_id_ (packet_id)
  687. {
  688. type_and_flags_.reserved.bit1 = 1;
  689. update_remain_length();
  690. }
  691. inline std::size_t required_size() const
  692. {
  693. return (fixed_header::required_size() + fixed_header::remain_length());
  694. }
  695. /*
  696. * The Container is usually a std::string, std::vector<char>, ...
  697. */
  698. template<class Container>
  699. inline subscribe& serialize(Container& buffer)
  700. {
  701. update_remain_length();
  702. fixed_header::serialize(buffer);
  703. packet_id_ .serialize(buffer);
  704. subscriptions_.serialize(buffer);
  705. return (*this);
  706. }
  707. inline subscribe& deserialize(std::string_view& data)
  708. {
  709. fixed_header::deserialize(data);
  710. packet_id_ .deserialize(data);
  711. subscriptions_.deserialize(data);
  712. update_remain_length();
  713. return (*this);
  714. }
  715. inline two_byte_integer::value_type packet_id () const { return packet_id_ .value() ; }
  716. inline subscriptions_set& subscriptions() { return subscriptions_ ; }
  717. inline subscriptions_set const& subscriptions() const { return subscriptions_ ; }
  718. inline subscribe & packet_id (std::uint16_t v) { packet_id_ = v; return (*this); }
  719. template<class... Subscriptions>
  720. inline subscribe& add_subscriptions(Subscriptions&&... Subscripts)
  721. {
  722. subscriptions_.add(std::forward<Subscriptions>(Subscripts)...);
  723. update_remain_length();
  724. return (*this);
  725. }
  726. inline subscribe& erase_subscription(std::string_view topic_filter)
  727. {
  728. subscriptions_.erase(topic_filter);
  729. update_remain_length();
  730. return (*this);
  731. }
  732. inline subscribe& update_remain_length()
  733. {
  734. remain_length_ = static_cast<std::int32_t>(0
  735. + packet_id_ .required_size()
  736. + subscriptions_.required_size()
  737. );
  738. return (*this);
  739. }
  740. protected:
  741. // The variable header contains a Packet Identifier.
  742. two_byte_integer packet_id_ {};
  743. // The payload of a SUBSCRIBE Packet contains a list of Topic Filters indicating the Topics
  744. // to which the Client wants to subscribe. The Topic Filters in a SUBSCRIBE packet payload
  745. // MUST be UTF-8 encoded strings as defined in Section 1.5.3 [MQTT-3.8.3-1]. A Server SHOULD
  746. // support Topic filters that contain the wildcard characters defined in Section 4.7.1. If
  747. // it chooses not to support topic filters that contain wildcard characters it MUST reject
  748. // any Subscription request whose filter contains them [MQTT-3.8.3-2]. Each filter is
  749. // followed by a byte called the Requested QoS. This gives the maximum QoS level at which
  750. // the Server can send Application Messages to the Client.
  751. subscriptions_set subscriptions_{};
  752. };
  753. /**
  754. * SUBACK - Subscribe acknowledgement
  755. *
  756. * A SUBACK Packet is sent by the Server to the Client to confirm receipt and processing of a SUBSCRIBE Packet.
  757. *
  758. * http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718068
  759. */
  760. class suback : public fixed_header<version_number>
  761. {
  762. public:
  763. suback() : fixed_header(control_packet_type::suback)
  764. {
  765. update_remain_length();
  766. }
  767. explicit suback(std::uint16_t packet_id)
  768. : fixed_header(control_packet_type::suback)
  769. , packet_id_ (packet_id)
  770. {
  771. update_remain_length();
  772. }
  773. inline std::size_t required_size() const
  774. {
  775. return (fixed_header::required_size() + fixed_header::remain_length());
  776. }
  777. /*
  778. * The Container is usually a std::string, std::vector<char>, ...
  779. */
  780. template<class Container>
  781. inline suback& serialize(Container& buffer)
  782. {
  783. update_remain_length();
  784. fixed_header::serialize(buffer);
  785. packet_id_ .serialize(buffer);
  786. reason_codes_ .serialize(buffer);
  787. return (*this);
  788. }
  789. inline suback& deserialize(std::string_view& data)
  790. {
  791. fixed_header::deserialize(data);
  792. packet_id_ .deserialize(data);
  793. reason_codes_ .deserialize(data);
  794. update_remain_length();
  795. return (*this);
  796. }
  797. inline two_byte_integer::value_type packet_id () const { return packet_id_ .value() ; }
  798. inline one_byte_integer_set & reason_codes () { return reason_codes_ ; }
  799. inline one_byte_integer_set const& reason_codes () const { return reason_codes_ ; }
  800. inline suback & packet_id (std::uint16_t v) { packet_id_ = v; return (*this); }
  801. template<class... Integers>
  802. inline suback& add_reason_codes(Integers... Ints)
  803. {
  804. reason_codes_.add(static_cast<one_byte_integer::value_type>(Ints)...);
  805. update_remain_length();
  806. return (*this);
  807. }
  808. inline suback& erase_reason_code(std::size_t index)
  809. {
  810. reason_codes_.erase(index);
  811. update_remain_length();
  812. return (*this);
  813. }
  814. inline suback& update_remain_length()
  815. {
  816. remain_length_ = static_cast<std::int32_t>(0
  817. + packet_id_ .required_size()
  818. + reason_codes_ .required_size()
  819. );
  820. return (*this);
  821. }
  822. protected:
  823. // The variable header contains the Packet Identifier from the SUBSCRIBE Packet that is being acknowledged.
  824. two_byte_integer packet_id_ {};
  825. // The payload contains a list of return codes. Each return code corresponds to a Topic Filter
  826. // in the SUBSCRIBE Packet being acknowledged. The order of return codes in the SUBACK Packet
  827. // MUST match the order of Topic Filters in the SUBSCRIBE Packet [MQTT-3.9.3-1].
  828. one_byte_integer_set reason_codes_{};
  829. };
  830. /**
  831. * UNSUBSCRIBE - Unsubscribe from topics
  832. *
  833. * An UNSUBSCRIBE Packet is sent by the Client to the Server, to unsubscribe from topics.
  834. *
  835. * http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718072
  836. */
  837. class unsubscribe : public fixed_header<version_number>
  838. {
  839. public:
  840. unsubscribe() : fixed_header(control_packet_type::unsubscribe)
  841. {
  842. // Bits 3,2,1 and 0 of the Fixed Header of the UNSUBSCRIBE packet are reserved and MUST
  843. // be set to 0,0,1 and 0 respectively. The Server MUST treat any other value as malformed
  844. // and close the Network Connection [MQTT-3.10.1-1].
  845. type_and_flags_.reserved.bit1 = 1;
  846. update_remain_length();
  847. }
  848. template<class... Strings>
  849. explicit unsubscribe(std::uint16_t packet_id, Strings&&... topic_filters)
  850. : fixed_header (control_packet_type::unsubscribe)
  851. , packet_id_ (packet_id)
  852. , topic_filters_(std::forward<Strings>(topic_filters)...)
  853. {
  854. type_and_flags_.reserved.bit1 = 1;
  855. update_remain_length();
  856. }
  857. inline std::size_t required_size() const
  858. {
  859. return (fixed_header::required_size() + fixed_header::remain_length());
  860. }
  861. /*
  862. * The Container is usually a std::string, std::vector<char>, ...
  863. */
  864. template<class Container>
  865. inline unsubscribe& serialize(Container& buffer)
  866. {
  867. update_remain_length();
  868. fixed_header::serialize(buffer);
  869. packet_id_ .serialize(buffer);
  870. topic_filters_.serialize(buffer);
  871. return (*this);
  872. }
  873. inline unsubscribe& deserialize(std::string_view& data)
  874. {
  875. fixed_header::deserialize(data);
  876. packet_id_ .deserialize(data);
  877. topic_filters_.deserialize(data);
  878. update_remain_length();
  879. return (*this);
  880. }
  881. inline two_byte_integer::value_type packet_id () const { return packet_id_ .value() ; }
  882. inline utf8_string_set & topic_filters() { return topic_filters_ ; }
  883. inline utf8_string_set const& topic_filters() const { return topic_filters_ ; }
  884. inline unsubscribe & packet_id (std::uint16_t v) { packet_id_ = v; return (*this); }
  885. template<class... Strings>
  886. inline unsubscribe& add_topic_filters(Strings&&... Strs)
  887. {
  888. topic_filters_.add(std::forward<Strings>(Strs)...);
  889. update_remain_length();
  890. return (*this);
  891. }
  892. inline unsubscribe& erase_topic_filter(std::string_view topic_filter)
  893. {
  894. topic_filters_.erase(topic_filter);
  895. update_remain_length();
  896. return (*this);
  897. }
  898. inline unsubscribe& update_remain_length()
  899. {
  900. remain_length_ = static_cast<std::int32_t>(0
  901. + packet_id_ .required_size()
  902. + topic_filters_.required_size()
  903. );
  904. return (*this);
  905. }
  906. protected:
  907. // The variable header contains a Packet Identifier.
  908. two_byte_integer packet_id_ {};
  909. // The payload for the UNSUBSCRIBE Packet contains the list of Topic Filters that the Client
  910. // wishes to unsubscribe from. The Topic Filters in an UNSUBSCRIBE packet MUST be UTF-8
  911. // encoded strings as defined in Section 1.5.3, packed contiguously [MQTT-3.10.3-1].
  912. // The Payload of an UNSUBSCRIBE packet MUST contain at least one Topic Filter.An UNSUBSCRIBE
  913. // packet with no payload is a protocol violation[MQTT - 3.10.3 - 2].See section 4.8 for
  914. // information about handling errors.
  915. utf8_string_set topic_filters_{};
  916. };
  917. /**
  918. * UNSUBACK - Unsubscribe acknowledgement
  919. *
  920. * The UNSUBACK packet is sent by the Server to the Client to confirm receipt of an UNSUBSCRIBE packet.
  921. *
  922. * http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718077
  923. */
  924. class unsuback : public fixed_header<version_number>
  925. {
  926. public:
  927. unsuback() : fixed_header(control_packet_type::unsuback)
  928. {
  929. update_remain_length();
  930. }
  931. explicit unsuback(std::uint16_t packet_id)
  932. : fixed_header(control_packet_type::unsuback)
  933. , packet_id_ (packet_id)
  934. {
  935. update_remain_length();
  936. }
  937. inline std::size_t required_size() const
  938. {
  939. return (fixed_header::required_size() + fixed_header::remain_length());
  940. }
  941. /*
  942. * The Container is usually a std::string, std::vector<char>, ...
  943. */
  944. template<class Container>
  945. inline unsuback& serialize(Container& buffer)
  946. {
  947. fixed_header::serialize(buffer);
  948. packet_id_ .serialize(buffer);
  949. return (*this);
  950. }
  951. inline unsuback& deserialize(std::string_view& data)
  952. {
  953. fixed_header::deserialize(data);
  954. packet_id_ .deserialize(data);
  955. update_remain_length();
  956. return (*this);
  957. }
  958. inline two_byte_integer::value_type packet_id () const { return packet_id_ .value() ; }
  959. inline unsuback & packet_id (std::uint16_t v) { packet_id_ = v; return (*this); }
  960. inline unsuback& update_remain_length()
  961. {
  962. remain_length_ = static_cast<std::int32_t>(0
  963. + packet_id_ .required_size()
  964. );
  965. return (*this);
  966. }
  967. protected:
  968. // The variable header contains the Packet Identifier of the UNSUBSCRIBE Packet that is being acknowledged.
  969. two_byte_integer packet_id_ {};
  970. // The UNSUBACK Packet has no payload.
  971. };
  972. /**
  973. * PINGREQ - PING request
  974. *
  975. * The PINGREQ packet is sent from a Client to the Server.
  976. *
  977. * http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718081
  978. */
  979. class pingreq : public fixed_header<version_number>
  980. {
  981. public:
  982. pingreq() : fixed_header(control_packet_type::pingreq)
  983. {
  984. update_remain_length();
  985. }
  986. inline std::size_t required_size() const
  987. {
  988. return (fixed_header::required_size() + fixed_header::remain_length());
  989. }
  990. /*
  991. * The Container is usually a std::string, std::vector<char>, ...
  992. */
  993. template<class Container>
  994. inline pingreq& serialize(Container& buffer)
  995. {
  996. fixed_header::serialize(buffer);
  997. return (*this);
  998. }
  999. inline pingreq& deserialize(std::string_view& data)
  1000. {
  1001. fixed_header::deserialize(data);
  1002. update_remain_length();
  1003. return (*this);
  1004. }
  1005. inline pingreq& update_remain_length()
  1006. {
  1007. remain_length_ = static_cast<std::int32_t>(0
  1008. );
  1009. return (*this);
  1010. }
  1011. protected:
  1012. // The PINGREQ packet has no Variable Header.
  1013. // The PINGREQ packet has no Payload.
  1014. };
  1015. /**
  1016. * PINGRESP - PING response
  1017. *
  1018. * A PINGRESP Packet is sent by the Server to the Client in response to a PINGREQ packet.
  1019. * It indicates that the Server is alive.
  1020. *
  1021. * http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718086
  1022. */
  1023. class pingresp : public fixed_header<version_number>
  1024. {
  1025. public:
  1026. pingresp() : fixed_header(control_packet_type::pingresp)
  1027. {
  1028. update_remain_length();
  1029. }
  1030. inline std::size_t required_size() const
  1031. {
  1032. return (fixed_header::required_size() + fixed_header::remain_length());
  1033. }
  1034. /*
  1035. * The Container is usually a std::string, std::vector<char>, ...
  1036. */
  1037. template<class Container>
  1038. inline pingresp& serialize(Container& buffer)
  1039. {
  1040. fixed_header::serialize(buffer);
  1041. return (*this);
  1042. }
  1043. inline pingresp& deserialize(std::string_view& data)
  1044. {
  1045. fixed_header::deserialize(data);
  1046. update_remain_length();
  1047. return (*this);
  1048. }
  1049. inline pingresp& update_remain_length()
  1050. {
  1051. remain_length_ = static_cast<std::int32_t>(0
  1052. );
  1053. return (*this);
  1054. }
  1055. protected:
  1056. // The PINGRESP packet has no Variable Header.
  1057. // The PINGRESP packet has no Payload.
  1058. };
  1059. /**
  1060. * DISCONNECT - Disconnect notification
  1061. *
  1062. * The DISCONNECT Packet is the final Control Packet sent from the Client to the Server.
  1063. * It indicates that the Client is disconnecting cleanly.
  1064. *
  1065. * http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718090
  1066. */
  1067. class disconnect : public fixed_header<version_number>
  1068. {
  1069. public:
  1070. disconnect() : fixed_header(control_packet_type::disconnect)
  1071. {
  1072. update_remain_length();
  1073. }
  1074. inline std::size_t required_size() const
  1075. {
  1076. return (fixed_header::required_size() + fixed_header::remain_length());
  1077. }
  1078. /*
  1079. * The Container is usually a std::string, std::vector<char>, ...
  1080. */
  1081. template<class Container>
  1082. inline disconnect& serialize(Container& buffer)
  1083. {
  1084. fixed_header::serialize(buffer);
  1085. return (*this);
  1086. }
  1087. inline disconnect& deserialize(std::string_view& data)
  1088. {
  1089. fixed_header::deserialize(data);
  1090. update_remain_length();
  1091. return (*this);
  1092. }
  1093. inline disconnect& update_remain_length()
  1094. {
  1095. remain_length_ = static_cast<std::int32_t>(0
  1096. );
  1097. return (*this);
  1098. }
  1099. protected:
  1100. // The DISCONNECT Packet has no variable header.
  1101. // The DISCONNECT Packet has no payload.
  1102. };
  1103. }
  1104. namespace asio2::mqtt
  1105. {
  1106. template<typename = void>
  1107. inline constexpr std::string_view to_string(v4::connect_reason_code v)
  1108. {
  1109. using namespace std::string_view_literals;
  1110. switch(v)
  1111. {
  1112. case v4::connect_reason_code::success : return "Connection accepted"sv;
  1113. 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;
  1114. case v4::connect_reason_code::identifier_rejected : return "The Client identifier is correct UTF-8 but not allowed by the Server"sv;
  1115. case v4::connect_reason_code::server_unavailable : return "The Network Connection has been made but the MQTT service is unavailable"sv;
  1116. case v4::connect_reason_code::bad_user_name_or_password : return "The data in the user name or password is malformed"sv;
  1117. case v4::connect_reason_code::not_authorized : return "The Client is not authorized to connect"sv;
  1118. default:
  1119. ASIO2_ASSERT(false);
  1120. break;
  1121. }
  1122. return "unknown"sv;
  1123. }
  1124. template<typename message_type>
  1125. inline constexpr bool is_v4_message()
  1126. {
  1127. using type = asio2::detail::remove_cvref_t<message_type>;
  1128. if constexpr (
  1129. std::is_same_v<type, mqtt::v4::connect > ||
  1130. std::is_same_v<type, mqtt::v4::connack > ||
  1131. std::is_same_v<type, mqtt::v4::publish > ||
  1132. std::is_same_v<type, mqtt::v4::puback > ||
  1133. std::is_same_v<type, mqtt::v4::pubrec > ||
  1134. std::is_same_v<type, mqtt::v4::pubrel > ||
  1135. std::is_same_v<type, mqtt::v4::pubcomp > ||
  1136. std::is_same_v<type, mqtt::v4::subscribe > ||
  1137. std::is_same_v<type, mqtt::v4::suback > ||
  1138. std::is_same_v<type, mqtt::v4::unsubscribe > ||
  1139. std::is_same_v<type, mqtt::v4::unsuback > ||
  1140. std::is_same_v<type, mqtt::v4::pingreq > ||
  1141. std::is_same_v<type, mqtt::v4::pingresp > ||
  1142. std::is_same_v<type, mqtt::v4::disconnect > )
  1143. {
  1144. return true;
  1145. }
  1146. else
  1147. {
  1148. return false;
  1149. }
  1150. }
  1151. }
  1152. #endif // !__ASIO2_MQTT_PROTOCOL_V4_HPP__