protocol_v3.hpp 42 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397
  1. /*
  2. * Copyright (c) 2017-2023 zhllxt
  3. *
  4. * author : zhllxt
  5. * email : 37792738@qq.com
  6. *
  7. * chinese :
  8. * english : http://public.dhe.ibm.com/software/dw/webservices/ws-mqtt/mqtt-v3r1.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_V3_HPP__
  14. #define __ASIO2_MQTT_PROTOCOL_V3_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::v3
  20. {
  21. static constexpr std::uint8_t version_number = asio2::detail::to_underlying(mqtt::version::v3);
  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. * When a TCP/IP socket connection is established from a client to a server, a protocol level
  36. * session must be created using a CONNECT flow.
  37. *
  38. * http://public.dhe.ibm.com/software/dw/webservices/ws-mqtt/mqtt-v3r1.html#connect
  39. */
  40. class connect : public fixed_header<version_number>
  41. {
  42. public:
  43. connect() : fixed_header(control_packet_type::connect)
  44. {
  45. update_remain_length();
  46. }
  47. connect(utf8_string::value_type clientid) : fixed_header(control_packet_type::connect)
  48. {
  49. client_id(std::move(clientid));
  50. update_remain_length();
  51. }
  52. inline std::size_t required_size() const
  53. {
  54. return (fixed_header::required_size() + fixed_header::remain_length());
  55. }
  56. /*
  57. * The Container is usually a std::string, std::vector<char>, ...
  58. */
  59. template<class Container>
  60. inline connect& serialize(Container& buffer)
  61. {
  62. fixed_header::serialize(buffer);
  63. protocol_name_ .serialize(buffer);
  64. protocol_version_ .serialize(buffer);
  65. connect_flags_.byte .serialize(buffer);
  66. keep_alive_ .serialize(buffer);
  67. client_id_ .serialize(buffer);
  68. if (will_topic_ ) will_topic_ ->serialize(buffer);
  69. if (will_payload_) will_payload_->serialize(buffer);
  70. if (username_ ) username_ ->serialize(buffer);
  71. if (password_ ) password_ ->serialize(buffer);
  72. return (*this);
  73. }
  74. inline connect& deserialize(std::string_view& data)
  75. {
  76. fixed_header::deserialize(data);
  77. protocol_name_ .deserialize(data);
  78. protocol_version_ .deserialize(data);
  79. connect_flags_.byte .deserialize(data);
  80. keep_alive_ .deserialize(data);
  81. client_id_ .deserialize(data);
  82. if (has_will())
  83. {
  84. utf8_string will_topic{};
  85. will_topic.deserialize(data);
  86. will_topic_ = std::move(will_topic);
  87. binary_data will_payload{};
  88. will_payload.deserialize(data);
  89. will_payload_ = std::move(will_payload);
  90. }
  91. if (has_username())
  92. {
  93. utf8_string username{};
  94. username.deserialize(data);
  95. username_ = std::move(username);
  96. }
  97. if (has_password())
  98. {
  99. binary_data password{};
  100. password.deserialize(data);
  101. password_ = std::move(password);
  102. }
  103. update_remain_length();
  104. return (*this);
  105. }
  106. inline std::uint8_t protocol_version() const { return (protocol_version_ ); }
  107. inline bool clean_start () const { return (connect_flags_.bits.clean_session); }
  108. inline bool clean_session () const { return (connect_flags_.bits.clean_session); }
  109. inline bool has_will () const { return (connect_flags_.bits.will_flag ); }
  110. inline qos_type will_qos () const { return static_cast<qos_type>(connect_flags_.bits.will_qos ); }
  111. inline bool will_retain () const { return (connect_flags_.bits.will_retain ); }
  112. inline bool has_password () const { return (connect_flags_.bits.password_flag); }
  113. inline bool has_username () const { return (connect_flags_.bits.username_flag); }
  114. inline connect& clean_start (bool v) { connect_flags_.bits.clean_session = v; return (*this); }
  115. inline connect& clean_session (bool v) { connect_flags_.bits.clean_session = v; return (*this); }
  116. inline two_byte_integer::value_type keep_alive () const { return keep_alive_ ; }
  117. inline utf8_string::view_type client_id () const { return client_id_ .data_view(); }
  118. inline utf8_string::view_type will_topic () const { return will_topic_ ? will_topic_ ->data_view() : ""; }
  119. inline binary_data::view_type will_payload () const { return will_payload_ ? will_payload_->data_view() : ""; }
  120. inline utf8_string::view_type username () const { return username_ ? username_ ->data_view() : ""; }
  121. inline binary_data::view_type password () const { return password_ ? password_ ->data_view() : ""; }
  122. inline connect& keep_alive(two_byte_integer::value_type v)
  123. {
  124. keep_alive_ = std::move(v);
  125. return (*this);
  126. }
  127. template<class String>
  128. inline connect& client_id(String&& v)
  129. {
  130. client_id_ = std::forward<String>(v);
  131. update_remain_length();
  132. return (*this);
  133. }
  134. template<class String>
  135. inline connect& username(String&& v)
  136. {
  137. username_ = std::forward<String>(v);
  138. connect_flags_.bits.username_flag = true;
  139. update_remain_length();
  140. return (*this);
  141. }
  142. inline connect& password(binary_data::value_type v)
  143. {
  144. password_ = std::move(v);
  145. connect_flags_.bits.password_flag = true;
  146. update_remain_length();
  147. return (*this);
  148. }
  149. template<class String1, class String2, class QosOrInt>
  150. inline connect& will_attributes(String1&& topic, String2&& payload,
  151. QosOrInt qos = qos_type::at_most_once, bool retain = false)
  152. {
  153. will_topic_ = std::forward<String1>(topic);
  154. will_payload_ = std::forward<String2>(payload);
  155. connect_flags_.bits.will_flag = true;
  156. connect_flags_.bits.will_qos = static_cast<std::uint8_t>(qos);
  157. connect_flags_.bits.will_retain = retain;
  158. update_remain_length();
  159. return (*this);
  160. }
  161. inline bool will_topic_has_value() const noexcept { return will_topic_.has_value(); }
  162. inline bool username_has_value () const noexcept { return username_ .has_value(); }
  163. inline bool password_has_value () const noexcept { return password_ .has_value(); }
  164. inline connect& update_remain_length()
  165. {
  166. remain_length_ = static_cast<std::int32_t>(0
  167. + protocol_name_ .required_size()
  168. + protocol_version_ .required_size()
  169. + connect_flags_.byte .required_size()
  170. + keep_alive_ .required_size()
  171. + client_id_ .required_size()
  172. + (will_topic_ ? will_topic_ ->required_size() : 0)
  173. + (will_payload_ ? will_payload_->required_size() : 0)
  174. + (username_ ? username_ ->required_size() : 0)
  175. + (password_ ? password_ ->required_size() : 0)
  176. );
  177. return (*this);
  178. }
  179. protected:
  180. // The protocol name is present in the variable header of a MQTT CONNECT message.
  181. // This field is a UTF-encoded string that represents the protocol name MQIsdp, capitalized as shown.
  182. utf8_string protocol_name_{ "MQIsdp" };
  183. // The protocol version is present in the variable header of a CONNECT message.
  184. // The value of the Protocol version field for the current version of the protocol, 3 (0x03)
  185. one_byte_integer protocol_version_{ 0x03 };
  186. union
  187. {
  188. one_byte_integer byte{ 0 }; // all connect flags
  189. #if ASIO2_ENDIAN_BIG_BYTE
  190. struct
  191. {
  192. bool username_flag : 1; // User Name Flag
  193. bool password_flag : 1; // Password Flag
  194. bool will_retain : 1; // will retain setting
  195. std::uint8_t will_qos : 2; // will QoS value
  196. bool will_flag : 1; // will flag
  197. bool clean_session : 1; // Clean Session flag
  198. std::uint8_t reserved : 1; // unused
  199. } bits;
  200. #else
  201. struct
  202. {
  203. std::uint8_t reserved : 1; // unused
  204. bool clean_session : 1; // Clean Session flag
  205. bool will_flag : 1; // will flag
  206. std::uint8_t will_qos : 2; // will QoS value
  207. bool will_retain : 1; // will retain setting
  208. bool password_flag : 1; // Password Flag
  209. bool username_flag : 1; // User Name Flag
  210. } bits;
  211. #endif
  212. } connect_flags_{}; // connect flags byte
  213. // The Keep Alive is a time interval measured in seconds. Expressed as a 16-bit word
  214. // Default to 60 seconds
  215. two_byte_integer keep_alive_ { 60 };
  216. // The Client Identifier (ClientID) identifies the Client to the Server.
  217. // Each Client connecting to the Server has a unique ClientID.
  218. utf8_string client_id_ {};
  219. // If the Will Flag is set to 1, the Will Topic is the next field in the Payload.
  220. std::optional<utf8_string> will_topic_ {};
  221. // If the Will Flag is set to 1 the Will Payload is the next field in the Payload.
  222. std::optional<binary_data> will_payload_{};
  223. // If the User Name Flag is set to 1, the User Name is the next field in the Payload.
  224. std::optional<utf8_string> username_ {};
  225. // If the Password Flag is set to 1, the Password is the next field in the Payload.
  226. std::optional<binary_data> password_ {};
  227. };
  228. /**
  229. * CONNACK - Acknowledge connection request
  230. *
  231. * http://public.dhe.ibm.com/software/dw/webservices/ws-mqtt/mqtt-v3r1.html#connack
  232. */
  233. class connack : public fixed_header<version_number>
  234. {
  235. public:
  236. connack() : fixed_header(control_packet_type::connack)
  237. {
  238. update_remain_length();
  239. }
  240. explicit connack(std::uint8_t reason_code)
  241. : fixed_header(control_packet_type::connack)
  242. , reason_code_(reason_code)
  243. {
  244. update_remain_length();
  245. }
  246. explicit connack(connect_reason_code reason_code)
  247. : fixed_header(control_packet_type::connack)
  248. , reason_code_(asio2::detail::to_underlying(reason_code))
  249. {
  250. update_remain_length();
  251. }
  252. inline std::size_t required_size() const
  253. {
  254. return (fixed_header::required_size() + fixed_header::remain_length());
  255. }
  256. /*
  257. * The Container is usually a std::string, std::vector<char>, ...
  258. */
  259. template<class Container>
  260. inline connack& serialize(Container& buffer)
  261. {
  262. fixed_header::serialize(buffer);
  263. connack_flags_.byte.serialize(buffer);
  264. reason_code_ .serialize(buffer);
  265. return (*this);
  266. }
  267. inline connack& deserialize(std::string_view& data)
  268. {
  269. fixed_header::deserialize(data);
  270. connack_flags_.byte.deserialize(data);
  271. reason_code_ .deserialize(data);
  272. update_remain_length();
  273. return (*this);
  274. }
  275. inline bool session_present() const { return connack_flags_.bits.session_present; }
  276. inline connect_reason_code reason_code () const { return static_cast<connect_reason_code>(reason_code_.value()); }
  277. inline connack & session_present(bool v) { connack_flags_.bits.session_present = v; return (*this); }
  278. inline connack & reason_code (std::uint8_t v) { reason_code_ = v; return (*this); }
  279. inline connack & reason_code(connect_reason_code v)
  280. { reason_code_ = asio2::detail::to_underlying(v); return (*this); }
  281. inline connack& update_remain_length()
  282. {
  283. remain_length_ = static_cast<std::int32_t>(0
  284. + connack_flags_.byte.required_size()
  285. + reason_code_ .required_size()
  286. );
  287. return (*this);
  288. }
  289. protected:
  290. // Topic Name Compression Response
  291. // byte 1 Reserved values. Not used.
  292. //one_byte_integer reserved_ { 0 };
  293. // Here we use the connection flags to replace the "reserved_"
  294. union
  295. {
  296. one_byte_integer byte{ 0 }; // all connack flags
  297. #if ASIO2_ENDIAN_BIG_BYTE
  298. struct
  299. {
  300. std::uint8_t reserved : 7;
  301. bool session_present : 1; // session found on the server?
  302. } bits;
  303. #else
  304. struct
  305. {
  306. bool session_present : 1; // session found on the server?
  307. std::uint8_t reserved : 7;
  308. } bits;
  309. #endif
  310. } connack_flags_{}; // connack flags
  311. // Connect Return Code
  312. // byte 2 Return Code
  313. one_byte_integer reason_code_{ 0 };
  314. };
  315. /**
  316. * PUBLISH - Publish message
  317. *
  318. * A PUBLISH message is sent by a client to a server for distribution to interested subscribers.
  319. * Each PUBLISH message is associated with a topic name (also known as the Subject or Channel).
  320. * This is a hierarchical name space that defines a taxonomy of information sources for which
  321. * subscribers can register an interest. A message that is published to a specific topic name
  322. * is delivered to connected subscribers for that topic.
  323. * If a client subscribes to one or more topics, any message published to those topics are sent
  324. * by the server to the client as a PUBLISH message.
  325. *
  326. * http://public.dhe.ibm.com/software/dw/webservices/ws-mqtt/mqtt-v3r1.html#publish
  327. */
  328. class publish : public fixed_header<version_number>
  329. {
  330. public:
  331. publish() : fixed_header(control_packet_type::publish)
  332. {
  333. update_remain_length();
  334. }
  335. template<class String1, class String2, class QosOrInt, std::enable_if_t<
  336. asio2::detail::is_character_string_v<String1>, int> = 0>
  337. explicit publish(String1&& topic_name, String2&& payload, QosOrInt qos,
  338. bool dup = false, bool retain = false)
  339. : fixed_header(control_packet_type::publish)
  340. , topic_name_ (std::forward<String1>(topic_name))
  341. , payload_ (std::forward<String2>(payload ))
  342. {
  343. type_and_flags_.bits.dup = dup;
  344. type_and_flags_.bits.qos = static_cast<std::uint8_t>(qos);
  345. type_and_flags_.bits.retain = retain;
  346. update_remain_length();
  347. }
  348. template<class String1, class String2, class QosOrInt, std::enable_if_t<
  349. asio2::detail::is_character_string_v<String1>, int> = 0>
  350. explicit publish(std::uint16_t pid, String1&& topic_name, String2&& payload, QosOrInt qos,
  351. bool dup = false, bool retain = false)
  352. : fixed_header(control_packet_type::publish)
  353. , topic_name_ (std::forward<String1>(topic_name))
  354. , packet_id_ (pid)
  355. , payload_ (std::forward<String2>(payload ))
  356. {
  357. type_and_flags_.bits.dup = dup;
  358. type_and_flags_.bits.qos = static_cast<std::uint8_t>(qos);
  359. type_and_flags_.bits.retain = retain;
  360. ASIO2_ASSERT(type_and_flags_.bits.qos > std::uint8_t(0));
  361. update_remain_length();
  362. }
  363. inline std::size_t required_size() const
  364. {
  365. return (fixed_header::required_size() + fixed_header::remain_length());
  366. }
  367. /*
  368. * The Container is usually a std::string, std::vector<char>, ...
  369. */
  370. template<class Container>
  371. inline publish& serialize(Container& buffer)
  372. {
  373. fixed_header::serialize(buffer);
  374. // The Packet Identifier field is only present in PUBLISH packets where the QoS level is 1 or 2.
  375. // A PUBLISH packet MUST NOT contain a Packet Identifier if its QoS value is set to 0
  376. if ((type_and_flags_.bits.qos == std::uint8_t(0) && packet_id_.has_value()) ||
  377. (type_and_flags_.bits.qos > std::uint8_t(0) && !packet_id_.has_value()))
  378. {
  379. ASIO2_ASSERT(false);
  380. asio2::set_last_error(mqtt::make_error_code(mqtt::error::malformed_packet));
  381. }
  382. topic_name_.serialize(buffer);
  383. if (type_and_flags_.bits.qos > std::uint8_t(0) && packet_id_.has_value())
  384. {
  385. packet_id_->serialize(buffer);
  386. }
  387. payload_.serialize(buffer);
  388. return (*this);
  389. }
  390. inline publish& deserialize(std::string_view& data)
  391. {
  392. fixed_header::deserialize(data);
  393. topic_name_.deserialize(data);
  394. if (type_and_flags_.bits.qos == 1 || type_and_flags_.bits.qos == 2)
  395. {
  396. two_byte_integer packet_id{};
  397. packet_id.deserialize(data);
  398. packet_id_ = packet_id;
  399. }
  400. payload_ .deserialize(data);
  401. update_remain_length();
  402. return (*this);
  403. }
  404. inline bool dup () const { return (type_and_flags_.bits.dup ); }
  405. inline qos_type qos () const { return static_cast<qos_type>(type_and_flags_.bits.qos ); }
  406. inline bool retain() const { return (type_and_flags_.bits.retain); }
  407. inline publish & dup (bool v) { type_and_flags_.bits.dup = v; return (*this); }
  408. template<class QosOrInt>
  409. inline publish & qos (QosOrInt v) { type_and_flags_.bits.qos = static_cast<std::uint8_t>(v); return (*this); }
  410. inline publish & retain(bool v) { type_and_flags_.bits.retain = v; return (*this); }
  411. inline utf8_string::view_type topic_name() const { return topic_name_.data_view(); }
  412. inline two_byte_integer::value_type packet_id () const { return packet_id_ ? packet_id_->value() : 0; }
  413. inline application_message::view_type payload () const { return payload_ .data_view(); }
  414. inline publish & packet_id (std::uint16_t v) { packet_id_ = v ; update_remain_length(); return (*this); }
  415. template<class String>
  416. inline publish & topic_name(String&& v) { topic_name_ = std::forward<String>(v); update_remain_length(); return (*this); }
  417. template<class String>
  418. inline publish & payload (String&& v) { payload_ = std::forward<String>(v); update_remain_length(); return (*this); }
  419. inline bool has_packet_id() const noexcept { return packet_id_.has_value(); }
  420. inline publish& update_remain_length()
  421. {
  422. remain_length_ = static_cast<std::int32_t>(0
  423. + topic_name_.required_size()
  424. + (packet_id_ ? packet_id_->required_size() : 0)
  425. + payload_ .required_size()
  426. );
  427. return (*this);
  428. }
  429. protected:
  430. // The Topic Name identifies the information channel to which Payload data is published.
  431. utf8_string topic_name_{};
  432. // The Packet Identifier field is only present in PUBLISH packets where the QoS level is 1 or 2.
  433. // a Two Byte Integer Packet Identifier.
  434. std::optional<two_byte_integer> packet_id_ {};
  435. // The Payload contains the Application Message that is being published.
  436. // The content and format of the data is application specific.
  437. // The length of the Payload can be calculated by subtracting the length of the Variable Header
  438. // from the Remaining Length field that is in the Fixed Header.
  439. // It is valid for a PUBLISH packet to contain a zero length Payload.
  440. application_message payload_ {};
  441. };
  442. /**
  443. * PUBACK - Publish acknowledgement
  444. *
  445. * A PUBACK message is the response to a PUBLISH message with QoS level 1.
  446. * A PUBACK message is sent by a server in response to a PUBLISH message from a publishing client,
  447. * and by a subscriber in response to a PUBLISH message from the server.
  448. *
  449. * http://public.dhe.ibm.com/software/dw/webservices/ws-mqtt/mqtt-v3r1.html#puback
  450. */
  451. class puback : public fixed_header<version_number>
  452. {
  453. public:
  454. puback() : fixed_header(control_packet_type::puback)
  455. {
  456. update_remain_length();
  457. }
  458. explicit puback(std::uint16_t packet_id)
  459. : fixed_header(control_packet_type::puback)
  460. , packet_id_ (packet_id)
  461. {
  462. update_remain_length();
  463. }
  464. inline std::size_t required_size() const
  465. {
  466. return (fixed_header::required_size() + fixed_header::remain_length());
  467. }
  468. /*
  469. * The Container is usually a std::string, std::vector<char>, ...
  470. */
  471. template<class Container>
  472. inline puback& serialize(Container& buffer)
  473. {
  474. fixed_header::serialize(buffer);
  475. packet_id_ .serialize(buffer);
  476. return (*this);
  477. }
  478. inline puback& deserialize(std::string_view& data)
  479. {
  480. fixed_header::deserialize(data);
  481. packet_id_ .deserialize(data);
  482. update_remain_length();
  483. return (*this);
  484. }
  485. inline two_byte_integer::value_type packet_id () const { return packet_id_ .value() ; }
  486. inline puback & packet_id (std::uint16_t v) { packet_id_ = v; return (*this); }
  487. inline puback& update_remain_length()
  488. {
  489. remain_length_ = static_cast<std::int32_t>(0
  490. + packet_id_ .required_size()
  491. );
  492. return (*this);
  493. }
  494. protected:
  495. // Contains the Message Identifier (Message ID) for the PUBLISH message that is being acknowledged.
  496. two_byte_integer packet_id_ {};
  497. };
  498. /**
  499. * PUBREC - Assured publish received (part 1)
  500. *
  501. * A PUBREC message is the response to a PUBLISH message with QoS level 2.
  502. * It is the second message of the QoS level 2 protocol flow.
  503. * A PUBREC message is sent by the server in response to a PUBLISH message from a publishing client,
  504. * or by a subscriber in response to a PUBLISH message from the server.
  505. *
  506. * http://public.dhe.ibm.com/software/dw/webservices/ws-mqtt/mqtt-v3r1.html#pubrec
  507. */
  508. class pubrec : public fixed_header<version_number>
  509. {
  510. public:
  511. pubrec() : fixed_header(control_packet_type::pubrec)
  512. {
  513. update_remain_length();
  514. }
  515. explicit pubrec(std::uint16_t packet_id)
  516. : fixed_header(control_packet_type::pubrec)
  517. , packet_id_ (packet_id)
  518. {
  519. update_remain_length();
  520. }
  521. inline std::size_t required_size() const
  522. {
  523. return (fixed_header::required_size() + fixed_header::remain_length());
  524. }
  525. /*
  526. * The Container is usually a std::string, std::vector<char>, ...
  527. */
  528. template<class Container>
  529. inline pubrec& serialize(Container& buffer)
  530. {
  531. fixed_header::serialize(buffer);
  532. packet_id_ .serialize(buffer);
  533. return (*this);
  534. }
  535. inline pubrec& deserialize(std::string_view& data)
  536. {
  537. fixed_header::deserialize(data);
  538. packet_id_ .deserialize(data);
  539. update_remain_length();
  540. return (*this);
  541. }
  542. inline two_byte_integer::value_type packet_id () const { return packet_id_ .value() ; }
  543. inline pubrec & packet_id (std::uint16_t v) { packet_id_ = v; return (*this); }
  544. inline pubrec& update_remain_length()
  545. {
  546. remain_length_ = static_cast<std::int32_t>(0
  547. + packet_id_ .required_size()
  548. );
  549. return (*this);
  550. }
  551. protected:
  552. // The variable header contains the Message ID for the acknowledged PUBLISH.
  553. two_byte_integer packet_id_ {};
  554. };
  555. /**
  556. * PUBREL - Assured Publish Release (part 2)
  557. *
  558. * A PUBREL message is the response either from a publisher to a PUBREC message from the server,
  559. * or from the server to a PUBREC message from a subscriber.
  560. *
  561. * http://public.dhe.ibm.com/software/dw/webservices/ws-mqtt/mqtt-v3r1.html#pubrel
  562. */
  563. class pubrel : public fixed_header<version_number>
  564. {
  565. public:
  566. pubrel() : fixed_header(control_packet_type::pubrel)
  567. {
  568. // PUBREL messages use QoS level 1 as an acknowledgement is expected in the form of a PUBCOMP.
  569. // Retries are handled in the same way as PUBLISH messages.
  570. type_and_flags_.reserved.bit1 = 1;
  571. update_remain_length();
  572. }
  573. explicit pubrel(std::uint16_t packet_id)
  574. : fixed_header(control_packet_type::pubrel)
  575. , packet_id_ (packet_id)
  576. {
  577. type_and_flags_.reserved.bit1 = 1;
  578. update_remain_length();
  579. }
  580. inline std::size_t required_size() const
  581. {
  582. return (fixed_header::required_size() + fixed_header::remain_length());
  583. }
  584. /*
  585. * The Container is usually a std::string, std::vector<char>, ...
  586. */
  587. template<class Container>
  588. inline pubrel& serialize(Container& buffer)
  589. {
  590. fixed_header::serialize(buffer);
  591. packet_id_ .serialize(buffer);
  592. return (*this);
  593. }
  594. inline pubrel& deserialize(std::string_view& data)
  595. {
  596. fixed_header::deserialize(data);
  597. packet_id_ .deserialize(data);
  598. update_remain_length();
  599. return (*this);
  600. }
  601. inline two_byte_integer::value_type packet_id () const { return packet_id_ .value() ; }
  602. inline pubrel & packet_id (std::uint16_t v) { packet_id_ = v; return (*this); }
  603. inline pubrel& update_remain_length()
  604. {
  605. remain_length_ = static_cast<std::int32_t>(0
  606. + packet_id_ .required_size()
  607. );
  608. return (*this);
  609. }
  610. protected:
  611. // The variable header contains the same Message ID as the PUBREC message that is being acknowledged.
  612. two_byte_integer packet_id_ {};
  613. };
  614. /**
  615. * PUBCOMP - Assured publish complete (part 3)
  616. *
  617. * This message is either the response from the server to a PUBREL message from a publisher,
  618. * or the response from a subscriber to a PUBREL message from the server.
  619. * It is the fourth and last message in the QoS 2 protocol flow.
  620. *
  621. * http://public.dhe.ibm.com/software/dw/webservices/ws-mqtt/mqtt-v3r1.html#pubcomp
  622. */
  623. class pubcomp : public fixed_header<version_number>
  624. {
  625. public:
  626. pubcomp() : fixed_header(control_packet_type::pubcomp)
  627. {
  628. update_remain_length();
  629. }
  630. explicit pubcomp(std::uint16_t packet_id)
  631. : fixed_header(control_packet_type::pubcomp)
  632. , packet_id_ (packet_id)
  633. {
  634. update_remain_length();
  635. }
  636. inline std::size_t required_size() const
  637. {
  638. return (fixed_header::required_size() + fixed_header::remain_length());
  639. }
  640. /*
  641. * The Container is usually a std::string, std::vector<char>, ...
  642. */
  643. template<class Container>
  644. inline pubcomp& serialize(Container& buffer)
  645. {
  646. fixed_header::serialize(buffer);
  647. packet_id_ .serialize(buffer);
  648. return (*this);
  649. }
  650. inline pubcomp& deserialize(std::string_view& data)
  651. {
  652. fixed_header::deserialize(data);
  653. packet_id_ .deserialize(data);
  654. update_remain_length();
  655. return (*this);
  656. }
  657. inline two_byte_integer::value_type packet_id () const { return packet_id_ .value() ; }
  658. inline pubcomp & packet_id (std::uint16_t v) { packet_id_ = v; return (*this); }
  659. inline pubcomp& update_remain_length()
  660. {
  661. remain_length_ = static_cast<std::int32_t>(0
  662. + packet_id_ .required_size()
  663. );
  664. return (*this);
  665. }
  666. protected:
  667. // The variable header contains the same Message ID as the acknowledged PUBREL message.
  668. two_byte_integer packet_id_ {};
  669. };
  670. /**
  671. * SUBSCRIBE - Subscribe to named topics
  672. *
  673. * The SUBSCRIBE message allows a client to register an interest in one or more topic names with the server.
  674. * Messages published to these topics are delivered from the server to the client as PUBLISH messages.
  675. * The SUBSCRIBE message also specifies the QoS level at which the subscriber wants to receive published messages.
  676. *
  677. * http://public.dhe.ibm.com/software/dw/webservices/ws-mqtt/mqtt-v3r1.html#subscribe
  678. */
  679. class subscribe : public fixed_header<version_number>
  680. {
  681. public:
  682. subscribe() : fixed_header(control_packet_type::subscribe)
  683. {
  684. // SUBSCRIBE messages use QoS level 1 to acknowledge multiple subscription requests.
  685. // The corresponding SUBACK message is identified by matching the Message ID.
  686. // Retries are handled in the same way as PUBLISH messages.
  687. type_and_flags_.reserved.bit1 = 1;
  688. update_remain_length();
  689. }
  690. explicit subscribe(std::uint16_t packet_id)
  691. : fixed_header(control_packet_type::subscribe)
  692. , packet_id_ (packet_id)
  693. {
  694. type_and_flags_.reserved.bit1 = 1;
  695. update_remain_length();
  696. }
  697. inline std::size_t required_size() const
  698. {
  699. return (fixed_header::required_size() + fixed_header::remain_length());
  700. }
  701. /*
  702. * The Container is usually a std::string, std::vector<char>, ...
  703. */
  704. template<class Container>
  705. inline subscribe& serialize(Container& buffer)
  706. {
  707. update_remain_length();
  708. fixed_header::serialize(buffer);
  709. packet_id_ .serialize(buffer);
  710. subscriptions_.serialize(buffer);
  711. return (*this);
  712. }
  713. inline subscribe& deserialize(std::string_view& data)
  714. {
  715. fixed_header::deserialize(data);
  716. packet_id_ .deserialize(data);
  717. subscriptions_.deserialize(data);
  718. update_remain_length();
  719. return (*this);
  720. }
  721. inline two_byte_integer::value_type packet_id () const { return packet_id_ .value() ; }
  722. inline subscriptions_set& subscriptions() { return subscriptions_ ; }
  723. inline subscriptions_set const& subscriptions() const { return subscriptions_ ; }
  724. inline subscribe & packet_id (std::uint16_t v) { packet_id_ = v; return (*this); }
  725. template<class... Subscriptions>
  726. inline subscribe& add_subscriptions(Subscriptions&&... Subscripts)
  727. {
  728. subscriptions_.add(std::forward<Subscriptions>(Subscripts)...);
  729. update_remain_length();
  730. return (*this);
  731. }
  732. inline subscribe& erase_subscription(std::string_view topic_filter)
  733. {
  734. subscriptions_.erase(topic_filter);
  735. update_remain_length();
  736. return (*this);
  737. }
  738. inline subscribe& update_remain_length()
  739. {
  740. remain_length_ = static_cast<std::int32_t>(0
  741. + packet_id_ .required_size()
  742. + subscriptions_.required_size()
  743. );
  744. return (*this);
  745. }
  746. protected:
  747. // The variable header contains a Message ID because a SUBSCRIBE message has a QoS level of 1.
  748. two_byte_integer packet_id_ {};
  749. // The payload of a SUBSCRIBE message contains a list of topic names to which the client wants
  750. // to subscribe, and the QoS level at which the client wants to receive the messages. The strings
  751. // are UTF-encoded, and the QoS level occupies 2 bits of a single byte. The topic strings may
  752. // contain special Topic wildcard characters to represent a set of topics.
  753. subscriptions_set subscriptions_{};
  754. };
  755. /**
  756. * SUBACK - Subscription acknowledgement
  757. *
  758. * A SUBACK message is sent by the server to the client to confirm receipt of a SUBSCRIBE message.
  759. *
  760. * http://public.dhe.ibm.com/software/dw/webservices/ws-mqtt/mqtt-v3r1.html#suback
  761. */
  762. class suback : public fixed_header<version_number>
  763. {
  764. public:
  765. suback() : fixed_header(control_packet_type::suback)
  766. {
  767. update_remain_length();
  768. }
  769. explicit suback(std::uint16_t packet_id)
  770. : fixed_header(control_packet_type::suback)
  771. , packet_id_ (packet_id)
  772. {
  773. update_remain_length();
  774. }
  775. inline std::size_t required_size() const
  776. {
  777. return (fixed_header::required_size() + fixed_header::remain_length());
  778. }
  779. /*
  780. * The Container is usually a std::string, std::vector<char>, ...
  781. */
  782. template<class Container>
  783. inline suback& serialize(Container& buffer)
  784. {
  785. update_remain_length();
  786. fixed_header::serialize(buffer);
  787. packet_id_ .serialize(buffer);
  788. reason_codes_ .serialize(buffer);
  789. return (*this);
  790. }
  791. inline suback& deserialize(std::string_view& data)
  792. {
  793. fixed_header::deserialize(data);
  794. packet_id_ .deserialize(data);
  795. reason_codes_ .deserialize(data);
  796. update_remain_length();
  797. return (*this);
  798. }
  799. inline two_byte_integer::value_type packet_id () const { return packet_id_ .value(); }
  800. inline one_byte_integer_set & reason_codes () { return reason_codes_ ; }
  801. inline one_byte_integer_set const& reason_codes () const { return reason_codes_ ; }
  802. inline suback & packet_id (std::uint16_t v) { packet_id_ = v; return (*this); }
  803. template<class... Integers>
  804. inline suback& add_reason_codes(Integers... Ints)
  805. {
  806. reason_codes_.add(static_cast<one_byte_integer::value_type>(Ints)...);
  807. update_remain_length();
  808. return (*this);
  809. }
  810. inline suback& erase_reason_code(std::size_t index)
  811. {
  812. reason_codes_.erase(index);
  813. update_remain_length();
  814. return (*this);
  815. }
  816. inline suback& update_remain_length()
  817. {
  818. remain_length_ = static_cast<std::int32_t>(0
  819. + packet_id_ .required_size()
  820. + reason_codes_ .required_size()
  821. );
  822. return (*this);
  823. }
  824. protected:
  825. // The variable header contains the Message ID for the SUBSCRIBE message that is being acknowledged.
  826. two_byte_integer packet_id_ {};
  827. // The payload contains a vector of granted QoS levels. Each level corresponds to a topic name
  828. // in the corresponding SUBSCRIBE message. The order of QoS levels in the SUBACK message matches
  829. // the order of topic name and Requested QoS pairs in the SUBSCRIBE message. The Message ID in the
  830. // variable header enables you to match SUBACK messages with the corresponding SUBSCRIBE messages.
  831. one_byte_integer_set reason_codes_{};
  832. };
  833. /**
  834. * UNSUBSCRIBE - Unsubscribe from named topics
  835. *
  836. * An UNSUBSCRIBE message is sent by the client to the server to unsubscribe from named topics.
  837. *
  838. * http://public.dhe.ibm.com/software/dw/webservices/ws-mqtt/mqtt-v3r1.html#unsubscribe
  839. */
  840. class unsubscribe : public fixed_header<version_number>
  841. {
  842. public:
  843. unsubscribe() : fixed_header(control_packet_type::unsubscribe)
  844. {
  845. // UNSUBSCRIBE messages use QoS level 1 to acknowledge multiple unsubscribe requests.
  846. // The corresponding UNSUBACK message is identified by the Message ID. Retries are
  847. // handled in the same way as PUBLISH messages.
  848. type_and_flags_.reserved.bit1 = 1;
  849. update_remain_length();
  850. }
  851. template<class... Strings>
  852. explicit unsubscribe(std::uint16_t packet_id, Strings&&... topic_filters)
  853. : fixed_header (control_packet_type::unsubscribe)
  854. , packet_id_ (packet_id)
  855. , topic_filters_(std::forward<Strings>(topic_filters)...)
  856. {
  857. type_and_flags_.reserved.bit1 = 1;
  858. update_remain_length();
  859. }
  860. inline std::size_t required_size() const
  861. {
  862. return (fixed_header::required_size() + fixed_header::remain_length());
  863. }
  864. /*
  865. * The Container is usually a std::string, std::vector<char>, ...
  866. */
  867. template<class Container>
  868. inline unsubscribe& serialize(Container& buffer)
  869. {
  870. update_remain_length();
  871. fixed_header::serialize(buffer);
  872. packet_id_ .serialize(buffer);
  873. topic_filters_.serialize(buffer);
  874. return (*this);
  875. }
  876. inline unsubscribe& deserialize(std::string_view& data)
  877. {
  878. fixed_header::deserialize(data);
  879. packet_id_ .deserialize(data);
  880. topic_filters_.deserialize(data);
  881. update_remain_length();
  882. return (*this);
  883. }
  884. inline two_byte_integer::value_type packet_id () const { return packet_id_ .value() ; }
  885. inline utf8_string_set & topic_filters() { return topic_filters_ ; }
  886. inline utf8_string_set const& topic_filters() const { return topic_filters_ ; }
  887. inline unsubscribe & packet_id (std::uint16_t v) { packet_id_ = v; return (*this); }
  888. template<class... Strings>
  889. inline unsubscribe& add_topic_filters(Strings&&... Strs)
  890. {
  891. topic_filters_.add(std::forward<Strings>(Strs)...);
  892. update_remain_length();
  893. return (*this);
  894. }
  895. inline unsubscribe& erase_topic_filter(std::string_view topic_filter)
  896. {
  897. topic_filters_.erase(topic_filter);
  898. update_remain_length();
  899. return (*this);
  900. }
  901. inline unsubscribe& update_remain_length()
  902. {
  903. remain_length_ = static_cast<std::int32_t>(0
  904. + packet_id_ .required_size()
  905. + topic_filters_.required_size()
  906. );
  907. return (*this);
  908. }
  909. protected:
  910. // The variable header contains a Message ID because an UNSUBSCRIBE message has a QoS level of 1.
  911. two_byte_integer packet_id_ {};
  912. // The client unsubscribes from the list of topics named in the payload.
  913. // The strings are UTF-encoded and are packed contiguously.
  914. // Topic names in a UNSUBSCRIBE message are not compressed.
  915. utf8_string_set topic_filters_{};
  916. };
  917. /**
  918. * UNSUBACK - Unsubscribe acknowledgment
  919. *
  920. * The UNSUBACK message is sent by the server to the client to confirm receipt of an UNSUBSCRIBE message.
  921. *
  922. * http://public.dhe.ibm.com/software/dw/webservices/ws-mqtt/mqtt-v3r1.html#unsuback
  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 Message ID for the UNSUBSCRIBE message 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 message is an "are you alive?" message that is sent from a connected client to the server.
  976. *
  977. * http://public.dhe.ibm.com/software/dw/webservices/ws-mqtt/mqtt-v3r1.html#pingreq
  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 message is the response sent by a server to a PINGREQ message and means "yes I am alive".
  1019. *
  1020. * http://public.dhe.ibm.com/software/dw/webservices/ws-mqtt/mqtt-v3r1.html#pingresp
  1021. */
  1022. class pingresp : public fixed_header<version_number>
  1023. {
  1024. public:
  1025. pingresp() : fixed_header(control_packet_type::pingresp)
  1026. {
  1027. update_remain_length();
  1028. }
  1029. inline std::size_t required_size() const
  1030. {
  1031. return (fixed_header::required_size() + fixed_header::remain_length());
  1032. }
  1033. /*
  1034. * The Container is usually a std::string, std::vector<char>, ...
  1035. */
  1036. template<class Container>
  1037. inline pingresp& serialize(Container& buffer)
  1038. {
  1039. fixed_header::serialize(buffer);
  1040. return (*this);
  1041. }
  1042. inline pingresp& deserialize(std::string_view& data)
  1043. {
  1044. fixed_header::deserialize(data);
  1045. update_remain_length();
  1046. return (*this);
  1047. }
  1048. inline pingresp& update_remain_length()
  1049. {
  1050. remain_length_ = static_cast<std::int32_t>(0
  1051. );
  1052. return (*this);
  1053. }
  1054. protected:
  1055. // The PINGRESP packet has no Variable Header.
  1056. // The PINGRESP packet has no Payload.
  1057. };
  1058. /**
  1059. * DISCONNECT - Disconnect notification
  1060. *
  1061. * The DISCONNECT message is sent from the client to the server to indicate that it is about to close
  1062. * its TCP/IP connection. This allows for a clean disconnection, rather than just dropping the line.
  1063. * If the client had connected with the clean session flag set, then all previously maintained
  1064. * information about the client will be discarded.
  1065. * A server should not rely on the client to close the TCP/IP connection after receiving a DISCONNECT.
  1066. *
  1067. * http://public.dhe.ibm.com/software/dw/webservices/ws-mqtt/mqtt-v3r1.html#disconnect
  1068. */
  1069. class disconnect : public fixed_header<version_number>
  1070. {
  1071. public:
  1072. disconnect() : fixed_header(control_packet_type::disconnect)
  1073. {
  1074. update_remain_length();
  1075. }
  1076. inline std::size_t required_size() const
  1077. {
  1078. return (fixed_header::required_size() + fixed_header::remain_length());
  1079. }
  1080. /*
  1081. * The Container is usually a std::string, std::vector<char>, ...
  1082. */
  1083. template<class Container>
  1084. inline disconnect& serialize(Container& buffer)
  1085. {
  1086. fixed_header::serialize(buffer);
  1087. return (*this);
  1088. }
  1089. inline disconnect& deserialize(std::string_view& data)
  1090. {
  1091. fixed_header::deserialize(data);
  1092. update_remain_length();
  1093. return (*this);
  1094. }
  1095. inline disconnect& update_remain_length()
  1096. {
  1097. remain_length_ = static_cast<std::int32_t>(0
  1098. );
  1099. return (*this);
  1100. }
  1101. protected:
  1102. // There is no variable header.
  1103. // There is no payload.
  1104. };
  1105. }
  1106. namespace asio2::mqtt
  1107. {
  1108. template<typename = void>
  1109. inline constexpr std::string_view to_string(v3::connect_reason_code v)
  1110. {
  1111. using namespace std::string_view_literals;
  1112. switch(v)
  1113. {
  1114. case v3::connect_reason_code::success : return "Connection accepted"sv;
  1115. case v3::connect_reason_code::unacceptable_protocol_version : return "The Server does not support the level of the MQTT protocol requested by the Client"sv;
  1116. case v3::connect_reason_code::identifier_rejected : return "The Client identifier is correct UTF-8 but not allowed by the Server"sv;
  1117. case v3::connect_reason_code::server_unavailable : return "The Network Connection has been made but the MQTT service is unavailable"sv;
  1118. case v3::connect_reason_code::bad_user_name_or_password : return "The data in the user name or password is malformed"sv;
  1119. case v3::connect_reason_code::not_authorized : return "The Client is not authorized to connect"sv;
  1120. default:
  1121. ASIO2_ASSERT(false);
  1122. break;
  1123. }
  1124. return "unknown"sv;
  1125. }
  1126. template<typename message_type>
  1127. inline constexpr bool is_v3_message()
  1128. {
  1129. using type = asio2::detail::remove_cvref_t<message_type>;
  1130. if constexpr (
  1131. std::is_same_v<type, mqtt::v3::connect > ||
  1132. std::is_same_v<type, mqtt::v3::connack > ||
  1133. std::is_same_v<type, mqtt::v3::publish > ||
  1134. std::is_same_v<type, mqtt::v3::puback > ||
  1135. std::is_same_v<type, mqtt::v3::pubrec > ||
  1136. std::is_same_v<type, mqtt::v3::pubrel > ||
  1137. std::is_same_v<type, mqtt::v3::pubcomp > ||
  1138. std::is_same_v<type, mqtt::v3::subscribe > ||
  1139. std::is_same_v<type, mqtt::v3::suback > ||
  1140. std::is_same_v<type, mqtt::v3::unsubscribe > ||
  1141. std::is_same_v<type, mqtt::v3::unsuback > ||
  1142. std::is_same_v<type, mqtt::v3::pingreq > ||
  1143. std::is_same_v<type, mqtt::v3::pingresp > ||
  1144. std::is_same_v<type, mqtt::v3::disconnect > )
  1145. {
  1146. return true;
  1147. }
  1148. else
  1149. {
  1150. return false;
  1151. }
  1152. }
  1153. }
  1154. #endif // !__ASIO2_MQTT_PROTOCOL_V3_HPP__