message_encoders.hpp 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433
  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_ENCODERS_HPP
  8. #define BOOST_MQTT5_MESSAGE_ENCODERS_HPP
  9. #include <boost/mqtt5/types.hpp>
  10. #include <boost/mqtt5/impl/codecs/base_encoders.hpp>
  11. #include <cstdint>
  12. #include <optional>
  13. #include <string>
  14. #include <string_view>
  15. #include <vector>
  16. namespace boost::mqtt5::encoders {
  17. template <typename encoder>
  18. std::string encode(const encoder& e) {
  19. std::string s;
  20. s.reserve(e.byte_size());
  21. s << e;
  22. return s;
  23. }
  24. inline std::string encode_connect(
  25. std::string_view client_id,
  26. std::optional<std::string_view> user_name,
  27. std::optional<std::string_view> password,
  28. uint16_t keep_alive, bool clean_start,
  29. const connect_props& props,
  30. const std::optional<will>& w
  31. ) {
  32. auto packet_type_ =
  33. basic::flag<4>(0b0001) |
  34. basic::flag<4>(0);
  35. auto conn_flags_ =
  36. basic::flag<1>(user_name) |
  37. basic::flag<1>(password) |
  38. basic::flag<1>(w, &will::retain) |
  39. basic::flag<2>(w, &will::qos) |
  40. basic::flag<1>(w) |
  41. basic::flag<1>(clean_start) |
  42. basic::flag<1>(0);
  43. auto var_header_ =
  44. basic::utf8_("MQTT") &
  45. basic::byte_(uint8_t(5)) &
  46. conn_flags_ &
  47. basic::int16_(keep_alive) &
  48. prop::props_(props);
  49. auto payload_ =
  50. basic::utf8_(client_id) &
  51. prop::props_(w) &
  52. basic::utf8_(w, &will::topic) &
  53. basic::binary_(w, &will::message) &
  54. basic::utf8_(user_name) &
  55. basic::utf8_(password);
  56. auto message_body_ = var_header_ & payload_;
  57. auto fixed_header_ =
  58. packet_type_ &
  59. basic::varlen_(message_body_.byte_size());
  60. auto connect_message_ = fixed_header_ & message_body_;
  61. return encode(connect_message_);
  62. }
  63. inline std::string encode_connack(
  64. bool session_present,
  65. uint8_t reason_code,
  66. const connack_props& props
  67. ) {
  68. auto packet_type_ =
  69. basic::flag<4>(0b0010) |
  70. basic::flag<4>(0);
  71. auto var_header_ =
  72. basic::flag<1>(session_present) &
  73. basic::byte_(reason_code) &
  74. prop::props_(props);
  75. auto fixed_header_ =
  76. packet_type_ &
  77. basic::varlen_(var_header_.byte_size());
  78. auto connack_message_ = fixed_header_ & var_header_;
  79. return encode(connack_message_);
  80. }
  81. inline std::string encode_publish(
  82. uint16_t packet_id,
  83. std::string_view topic_name,
  84. std::string_view payload,
  85. qos_e qos, retain_e retain, dup_e dup,
  86. const publish_props& props
  87. ) {
  88. std::optional<uint16_t> used_packet_id;
  89. if (qos != qos_e::at_most_once) used_packet_id.emplace(packet_id);
  90. auto packet_type_ =
  91. basic::flag<4>(0b0011) |
  92. basic::flag<1>(dup) |
  93. basic::flag<2>(qos) |
  94. basic::flag<1>(retain);
  95. auto var_header_ =
  96. basic::utf8_(topic_name) &
  97. basic::int16_(used_packet_id) &
  98. prop::props_(props);
  99. auto message_body_ = var_header_ & basic::verbatim_(payload);
  100. auto fixed_header_ =
  101. packet_type_ &
  102. basic::varlen_(message_body_.byte_size());
  103. auto publish_message_ = fixed_header_ & message_body_;
  104. return encode(publish_message_);
  105. }
  106. inline std::string encode_puback(
  107. uint16_t packet_id,
  108. uint8_t reason_code,
  109. const puback_props& props
  110. ) {
  111. auto packet_type_ =
  112. basic::flag<4>(0b0100) |
  113. basic::flag<4>(0);
  114. auto var_header_ =
  115. basic::int16_(packet_id) &
  116. basic::byte_(reason_code) &
  117. prop::props_may_omit_(props);
  118. auto fixed_header_ =
  119. packet_type_ &
  120. basic::varlen_(var_header_.byte_size());
  121. auto puback_message_ = fixed_header_ & var_header_;
  122. return encode(puback_message_);
  123. }
  124. inline std::string encode_pubrec(
  125. uint16_t packet_id,
  126. uint8_t reason_code,
  127. const pubrec_props& props
  128. ) {
  129. auto packet_type_ =
  130. basic::flag<4>(0b0101) |
  131. basic::flag<4>(0b0000);
  132. auto var_header_ =
  133. basic::int16_(packet_id) &
  134. basic::byte_(reason_code) &
  135. prop::props_may_omit_(props);
  136. auto fixed_header_ =
  137. packet_type_ &
  138. basic::varlen_(var_header_.byte_size());
  139. auto pubrec_message_ = fixed_header_ & var_header_;
  140. return encode(pubrec_message_);
  141. }
  142. inline std::string encode_pubrel(
  143. uint16_t packet_id,
  144. uint8_t reason_code,
  145. const pubrel_props& props
  146. ) {
  147. auto packet_type_ =
  148. basic::flag<4>(0b0110) |
  149. basic::flag<4>(0b0010);
  150. auto var_header_ =
  151. basic::int16_(packet_id) &
  152. basic::byte_(reason_code) &
  153. prop::props_may_omit_(props);
  154. auto fixed_header_ =
  155. packet_type_ &
  156. basic::varlen_(var_header_.byte_size());
  157. auto pubrel_message_ = fixed_header_ & var_header_;
  158. return encode(pubrel_message_);
  159. }
  160. inline std::string encode_pubcomp(
  161. uint16_t packet_id,
  162. uint8_t reason_code,
  163. const pubcomp_props& props
  164. ) {
  165. auto packet_type_ =
  166. basic::flag<4>(0b0111) |
  167. basic::flag<4>(0b0000);
  168. auto var_header_ =
  169. basic::int16_(packet_id) &
  170. basic::byte_(reason_code) &
  171. prop::props_may_omit_(props);
  172. auto fixed_header_ =
  173. packet_type_ &
  174. basic::varlen_(var_header_.byte_size());
  175. auto pubcomp_message_ = fixed_header_ & var_header_;
  176. return encode(pubcomp_message_);
  177. }
  178. inline std::string encode_subscribe(
  179. uint16_t packet_id,
  180. const std::vector<subscribe_topic>& topics,
  181. const subscribe_props& props
  182. ) {
  183. auto packet_type_ =
  184. basic::flag<4>(0b1000) |
  185. basic::flag<4>(0b0010);
  186. size_t payload_size = 0;
  187. for (const auto& [topic_filter, _]: topics)
  188. payload_size += basic::utf8_(topic_filter).byte_size() + 1;
  189. auto var_header_ =
  190. basic::int16_(packet_id) &
  191. prop::props_(props);
  192. auto message_ =
  193. packet_type_ &
  194. basic::varlen_(var_header_.byte_size() + payload_size) &
  195. var_header_;
  196. auto s = encode(message_);
  197. s.reserve(s.size() + payload_size);
  198. for (const auto& [topic_filter, sub_opts]: topics) {
  199. auto opts_ =
  200. basic::flag<2>(sub_opts.retain_handling) |
  201. basic::flag<1>(sub_opts.retain_as_published) |
  202. basic::flag<1>(sub_opts.no_local) |
  203. basic::flag<2>(sub_opts.max_qos);
  204. auto filter_ = basic::utf8_(topic_filter) & opts_;
  205. s << filter_;
  206. }
  207. return s;
  208. }
  209. inline std::string encode_suback(
  210. uint16_t packet_id,
  211. const std::vector<uint8_t>& reason_codes,
  212. const suback_props& props
  213. ) {
  214. auto packet_type_ =
  215. basic::flag<4>(0b1001) |
  216. basic::flag<4>(0b0000);
  217. auto var_header_ =
  218. basic::int16_(packet_id) &
  219. prop::props_(props);
  220. auto message_ =
  221. packet_type_ &
  222. basic::varlen_(var_header_.byte_size() + reason_codes.size()) &
  223. var_header_;
  224. auto s = encode(message_);
  225. s.reserve(s.size() + reason_codes.size());
  226. for (auto reason_code: reason_codes)
  227. s << basic::byte_(reason_code);
  228. return s;
  229. }
  230. inline std::string encode_unsubscribe(
  231. uint16_t packet_id,
  232. const std::vector<std::string>& topics,
  233. const unsubscribe_props& props
  234. ) {
  235. auto packet_type_ =
  236. basic::flag<4>(0b1010) |
  237. basic::flag<4>(0b0010);
  238. size_t payload_size = 0;
  239. for (const auto& topic: topics)
  240. payload_size += basic::utf8_(topic).byte_size();
  241. auto var_header_ =
  242. basic::int16_(packet_id) &
  243. prop::props_(props);
  244. auto message_ =
  245. packet_type_ &
  246. basic::varlen_(var_header_.byte_size() + payload_size) &
  247. var_header_;
  248. auto s = encode(message_);
  249. s.reserve(s.size() + payload_size);
  250. for (const auto& topic: topics)
  251. s << basic::utf8_(topic);
  252. return s;
  253. }
  254. inline std::string encode_unsuback(
  255. uint16_t packet_id,
  256. const std::vector<uint8_t>& reason_codes,
  257. const unsuback_props& props
  258. ) {
  259. auto packet_type_ =
  260. basic::flag<4>(0b1011) |
  261. basic::flag<4>(0b0000);
  262. auto var_header_ =
  263. basic::int16_(packet_id) &
  264. prop::props_(props);
  265. auto message_ =
  266. packet_type_ &
  267. basic::varlen_(var_header_.byte_size() + reason_codes.size()) &
  268. var_header_;
  269. auto s = encode(message_);
  270. s.reserve(s.size() + reason_codes.size());
  271. for (auto reason_code: reason_codes)
  272. s << basic::byte_(reason_code);
  273. return s;
  274. }
  275. inline std::string encode_pingreq() {
  276. auto packet_type_ =
  277. basic::flag<4>(0b1100) |
  278. basic::flag<4>(0);
  279. auto remaining_len_ =
  280. basic::byte_(uint8_t(0));
  281. auto ping_req_ = packet_type_ & remaining_len_;
  282. return encode(ping_req_);
  283. }
  284. inline std::string encode_pingresp() {
  285. auto packet_type_ =
  286. basic::flag<4>(0b1101) |
  287. basic::flag<4>(0);
  288. auto remaining_len_ =
  289. basic::byte_(uint8_t(0));
  290. auto ping_resp_ = packet_type_ & remaining_len_;
  291. return encode(ping_resp_);
  292. }
  293. inline std::string encode_disconnect(
  294. uint8_t reason_code,
  295. const disconnect_props& props
  296. ) {
  297. auto packet_type_ =
  298. basic::flag<4>(0b1110) |
  299. basic::flag<4>(0b0000);
  300. auto var_header_ =
  301. basic::byte_(reason_code) &
  302. prop::props_(props);
  303. auto fixed_header_ =
  304. packet_type_ &
  305. basic::varlen_(var_header_.byte_size());
  306. auto disconnect_message_ = fixed_header_ & var_header_;
  307. return encode(disconnect_message_);
  308. }
  309. inline std::string encode_auth(
  310. uint8_t reason_code,
  311. const auth_props& props
  312. ) {
  313. auto packet_type_ =
  314. basic::flag<4>(0b1111) |
  315. basic::flag<4>(0b0000);
  316. auto var_header_ =
  317. basic::byte_(reason_code) &
  318. prop::props_(props);
  319. auto fixed_header_ =
  320. packet_type_ &
  321. basic::varlen_(var_header_.byte_size());
  322. auto auth_message_ = fixed_header_ & var_header_;
  323. return encode(auth_message_);
  324. }
  325. } // end namespace boost::mqtt5::encoders
  326. #endif // !BOOST_MQTT5_MESSAGE_ENCODERS_HPP