message_decoders.hpp 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. //
  2. // Copyright (c) 2023-2025 Ivica Siladic, Bruno Iljazovic, Korina Simicevic
  3. //
  4. // Distributed under the Boost Software License, Version 1.0.
  5. // (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. //
  7. #ifndef BOOST_MQTT5_MESSAGE_DECODERS_HPP
  8. #define BOOST_MQTT5_MESSAGE_DECODERS_HPP
  9. #include <boost/mqtt5/types.hpp>
  10. #include <boost/mqtt5/detail/internal_types.hpp>
  11. #include <boost/mqtt5/impl/codecs/base_decoders.hpp>
  12. #include <cstdint>
  13. #include <optional>
  14. #include <string>
  15. #include <utility>
  16. #include <vector>
  17. namespace boost::mqtt5::decoders {
  18. using byte_citer = detail::byte_citer;
  19. using fixed_header = std::tuple<
  20. uint8_t, // control byte
  21. uint32_t // remaining_length
  22. >;
  23. inline std::optional<fixed_header> decode_fixed_header(
  24. byte_citer& it, const byte_citer last
  25. ) {
  26. constexpr auto fixed_header_ = basic::byte_ >> basic::varint_;
  27. return type_parse(it, last, fixed_header_);
  28. }
  29. using packet_id = uint16_t;
  30. inline std::optional<packet_id> decode_packet_id(
  31. byte_citer& it
  32. ) {
  33. constexpr auto packet_id_ = basic::word_;
  34. return type_parse(it, it + sizeof(uint16_t), packet_id_);
  35. }
  36. using connect_message = std::tuple<
  37. std::string, // client_id,
  38. std::optional<std::string>, // user_name,
  39. std::optional<std::string>, // password,
  40. uint16_t, // keep_alive,
  41. bool, // clean_start,
  42. connect_props, // props,
  43. std::optional<will> // will
  44. >;
  45. inline std::optional<connect_message> decode_connect(
  46. uint32_t remain_length, byte_citer& it
  47. ) {
  48. constexpr auto var_header_ =
  49. basic::utf8_ >> // MQTT
  50. basic::byte_ >> // (num 5)
  51. basic::byte_ >> // conn_flags_
  52. basic::word_ >> // keep_alive
  53. prop::props_<connect_props>;
  54. const byte_citer end = it + remain_length;
  55. auto vh = type_parse(it, end, var_header_);
  56. if (!vh)
  57. return std::optional<connect_message>{};
  58. auto& [mqtt_str, version, flags, keep_alive, cprops] = *vh;
  59. if (mqtt_str != "MQTT" || version != 5)
  60. return std::optional<connect_message>{};
  61. bool has_will = (flags & 0b00000100);
  62. bool has_uname = (flags & 0b10000000);
  63. bool has_pwd = (flags & 0b01000000);
  64. auto payload_ =
  65. basic::utf8_ >> // client_id
  66. basic::if_(has_will)[prop::props_<will_props>] >>
  67. basic::if_(has_will)[basic::utf8_] >> // will topic
  68. basic::if_(has_will)[basic::binary_] >> // will message
  69. basic::if_(has_uname)[basic::utf8_] >> // username
  70. basic::if_(has_pwd)[basic::utf8_]; // password
  71. auto pload = type_parse(it, end, payload_);
  72. if (!pload)
  73. return std::optional<connect_message>{};
  74. std::optional<will> w;
  75. if (has_will)
  76. w.emplace(
  77. std::move(*std::get<2>(*pload)), // will_topic
  78. std::move(*std::get<3>(*pload)), // will_message
  79. qos_e((flags & 0b00011000) >> 3),
  80. retain_e((flags & 0b00100000) >> 5),
  81. std::move(*std::get<1>(*pload)) // will props
  82. );
  83. connect_message retval = {
  84. std::move(std::get<0>(*pload)), // client_id
  85. std::move(std::get<4>(*pload)), // user_name
  86. std::move(std::get<5>(*pload)), // password
  87. keep_alive,
  88. flags & 0b00000010, // clean_start
  89. std::move(cprops), // connect_props
  90. std::move(w) // will
  91. };
  92. return std::optional<connect_message> { std::move(retval) };
  93. }
  94. using connack_message = std::tuple<
  95. uint8_t, // session_present
  96. uint8_t, // connect reason code
  97. connack_props // props
  98. >;
  99. inline std::optional<connack_message> decode_connack(
  100. uint32_t remain_length, byte_citer& it
  101. ) {
  102. constexpr auto connack_ = basic::byte_ >> basic::byte_ >> prop::props_<connack_props>;
  103. return type_parse(it, it + remain_length, connack_);
  104. }
  105. using publish_message = std::tuple<
  106. std::string, // topic
  107. std::optional<uint16_t>, // packet_id
  108. uint8_t, // dup_e, qos_e, retain_e
  109. publish_props, // publish props
  110. std::string // payload
  111. >;
  112. inline std::optional<publish_message> decode_publish(
  113. uint8_t control_byte, uint32_t remain_length, byte_citer& it
  114. ) {
  115. uint8_t flags = control_byte & 0b1111;
  116. auto qos = qos_e((flags >> 1) & 0b11);
  117. auto publish_ =
  118. basic::utf8_ >> basic::if_(qos != qos_e::at_most_once)[basic::word_] >>
  119. basic::attr(flags) >> prop::props_<publish_props> >>
  120. basic::verbatim_;
  121. return type_parse(it, it + remain_length, publish_);
  122. }
  123. using puback_message = std::tuple<
  124. uint8_t, // puback reason code
  125. puback_props // props
  126. >;
  127. inline std::optional<puback_message> decode_puback(
  128. uint32_t remain_length, byte_citer& it
  129. ) {
  130. if (remain_length == 0)
  131. return puback_message {};
  132. constexpr auto puback_ = basic::byte_ >> prop::props_<puback_props>;
  133. return type_parse(it, it + remain_length, puback_);
  134. }
  135. using pubrec_message = std::tuple<
  136. uint8_t, // puback reason code
  137. pubrec_props // props
  138. >;
  139. inline std::optional<pubrec_message> decode_pubrec(
  140. uint32_t remain_length, byte_citer& it
  141. ) {
  142. if (remain_length == 0)
  143. return pubrec_message {};
  144. constexpr auto pubrec_ = basic::byte_ >> prop::props_<pubrec_props>;
  145. return type_parse(it, it + remain_length, pubrec_);
  146. }
  147. using pubrel_message = std::tuple<
  148. uint8_t, // puback reason code
  149. pubrel_props // props
  150. >;
  151. inline std::optional<pubrel_message> decode_pubrel(
  152. uint32_t remain_length, byte_citer& it
  153. ) {
  154. if (remain_length == 0)
  155. return pubrel_message {};
  156. constexpr auto pubrel_ = basic::byte_ >> prop::props_<pubrel_props>;
  157. return type_parse(it, it + remain_length, pubrel_);
  158. }
  159. using pubcomp_message = std::tuple<
  160. uint8_t, // puback reason code
  161. pubcomp_props // props
  162. >;
  163. inline std::optional<pubcomp_message> decode_pubcomp(
  164. uint32_t remain_length, byte_citer& it
  165. ) {
  166. if (remain_length == 0)
  167. return pubcomp_message {};
  168. constexpr auto pubcomp_ = basic::byte_ >> prop::props_<pubcomp_props>;
  169. return type_parse(it, it + remain_length, pubcomp_);
  170. }
  171. using subscribe_message = std::tuple<
  172. subscribe_props,
  173. std::vector<std::tuple<std::string, uint8_t>> // topic filter with opts
  174. >;
  175. inline std::optional<subscribe_message> decode_subscribe(
  176. uint32_t remain_length, byte_citer& it
  177. ) {
  178. constexpr auto subscribe_ = prop::props_<subscribe_props> >> +(basic::utf8_ >> basic::byte_);
  179. return type_parse(it, it + remain_length, subscribe_);
  180. }
  181. using suback_message = std::tuple<
  182. suback_props,
  183. std::vector<uint8_t> // reason_codes
  184. >;
  185. inline std::optional<suback_message> decode_suback(
  186. uint32_t remain_length, byte_citer& it
  187. ) {
  188. constexpr auto suback_ = prop::props_<suback_props> >> +basic::byte_;
  189. return type_parse(it, it + remain_length, suback_);
  190. }
  191. using unsubscribe_message = std::tuple<
  192. unsubscribe_props,
  193. std::vector<std::string> // topics
  194. >;
  195. inline std::optional<unsubscribe_message> decode_unsubscribe(
  196. uint32_t remain_length, byte_citer& it
  197. ) {
  198. constexpr auto unsubscribe_ = prop::props_<unsubscribe_props> >> +basic::utf8_;
  199. return type_parse(it, it + remain_length, unsubscribe_);
  200. }
  201. using unsuback_message = std::tuple<
  202. unsuback_props,
  203. std::vector<uint8_t> // reason_codes
  204. >;
  205. inline std::optional<unsuback_message> decode_unsuback(
  206. uint32_t remain_length, byte_citer& it
  207. ) {
  208. constexpr auto unsuback_ = prop::props_<unsuback_props> >> +basic::byte_;
  209. return type_parse(it, it + remain_length, unsuback_);
  210. }
  211. using disconnect_message = std::tuple<
  212. uint8_t, // reason_code
  213. disconnect_props
  214. >;
  215. inline std::optional<disconnect_message> decode_disconnect(
  216. uint32_t remain_length, byte_citer& it
  217. ) {
  218. if (remain_length == 0)
  219. return disconnect_message {};
  220. constexpr auto disconnect_ = basic::byte_ >> prop::props_<disconnect_props>;
  221. return type_parse(it, it + remain_length, disconnect_);
  222. }
  223. using auth_message = std::tuple<
  224. uint8_t, // reason_code
  225. auth_props
  226. >;
  227. inline std::optional<auth_message> decode_auth(
  228. uint32_t remain_length, byte_citer& it
  229. ) {
  230. if (remain_length == 0)
  231. return auth_message {};
  232. constexpr auto auth_ = basic::byte_ >> prop::props_<auth_props>;
  233. return type_parse(it, it + remain_length, auth_);
  234. }
  235. } // end namespace boost::mqtt5::decoders
  236. #endif // !BOOST_MQTT5_MESSAGE_DECODERS_HPP