reason_codes.hpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496
  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_REASON_CODES_HPP
  8. #define BOOST_MQTT5_REASON_CODES_HPP
  9. #include <algorithm>
  10. #include <cstdint>
  11. #include <optional>
  12. #include <ostream>
  13. #include <type_traits>
  14. #include <utility>
  15. namespace boost::mqtt5 {
  16. /// \cond internal
  17. namespace reason_codes {
  18. enum class category : uint8_t {
  19. none,
  20. connack, puback, pubrec,
  21. pubrel, pubcomp, suback,
  22. unsuback, auth, disconnect
  23. };
  24. } // end namespace reason_codes
  25. /// \endcond
  26. /**
  27. * \brief A class holding Reason Code values originating from Control Packets.
  28. *
  29. * \details A Reason Code is a one byte unsigned value that indicates the result of an operation.
  30. * Reason Codes less than 0x80 indicate successful completion of an operation.
  31. * The normal Reason Code for success is 0.
  32. * Reason Code values of 0x80 or greater indicate failure.
  33. * The \__CONNACK\__, \__PUBACK\__, \__PUBREC\__, \__PUBREL\__, \__PUBCOMP\__, \__DISCONNECT\__
  34. * and \__AUTH\__ Control Packets have a single Reason Code as part of the Variable Header.
  35. * The \__SUBACK\__ and \__UNSUBACK\__ packets contain a list of one or more Reason Codes in the Payload.
  36. *
  37. * \see See \__REASON_CODES\__ for a complete list of all possible instances of this class.
  38. */
  39. class reason_code {
  40. uint8_t _code;
  41. reason_codes::category _category { reason_codes::category::none };
  42. public:
  43. /// \cond internal
  44. constexpr reason_code() : _code(0xff) {}
  45. constexpr reason_code(uint8_t code, reason_codes::category cat) :
  46. _code(code), _category(cat)
  47. {}
  48. constexpr explicit reason_code(uint8_t code) : _code(code) {}
  49. /// \endcond
  50. /**
  51. * \brief Indication if the object holds a Reason Code indicating an error.
  52. *
  53. * \details Any Reason Code holding a value equal to or greater than 0x80.
  54. */
  55. explicit operator bool() const noexcept {
  56. return _code >= 0x80;
  57. }
  58. /**
  59. * \brief Returns the byte value of the Reason Code.
  60. */
  61. constexpr uint8_t value() const noexcept {
  62. return _code;
  63. }
  64. /// Insertion operator.
  65. friend std::ostream& operator<<(std::ostream& os, const reason_code& rc) {
  66. os << rc.message();
  67. return os;
  68. }
  69. /// Operator less than.
  70. friend bool operator<(const reason_code& lhs, const reason_code& rhs) {
  71. return lhs._code < rhs._code;
  72. }
  73. /// Equality operator.
  74. friend bool operator==(const reason_code& lhs, const reason_code& rhs) {
  75. return lhs._code == rhs._code && lhs._category == rhs._category;
  76. }
  77. /**
  78. * \brief Returns a message describing the meaning behind the Reason Code.
  79. */
  80. std::string message() const {
  81. switch (_code) {
  82. case 0x00:
  83. if (_category == reason_codes::category::suback)
  84. return "The subscription is accepted with maximum QoS sent at 0";
  85. if (_category == reason_codes::category::disconnect)
  86. return "Close the connection normally. Do not send the Will Message";
  87. return "The operation completed successfully";
  88. case 0x01:
  89. return "The subscription is accepted with maximum QoS sent at 1";
  90. case 0x02:
  91. return "The subscription is accepted with maximum QoS sent at 2";
  92. case 0x04:
  93. return "The Client wishes to disconnect but requires"
  94. "that the Server also publishes its Will Message";
  95. case 0x10:
  96. return "The message is accepted but there are no subscribers";
  97. case 0x11:
  98. return "No matching Topic Filter is being used by the Client.";
  99. case 0x18:
  100. return "Continue the authentication with another step";
  101. case 0x19:
  102. return "Initiate a re-authentication";
  103. case 0x80:
  104. return "The Server does not wish to reveal the reason for the"
  105. "failure or none of the other Reason Codes apply";
  106. case 0x81:
  107. return "Data within the packet could not be correctly parsed";
  108. case 0x82:
  109. return "Data in the packet does not conform to this specification";
  110. case 0x83:
  111. return "The packet is valid but not accepted by this Server";
  112. case 0x84:
  113. return "The Server does not support the requested "
  114. "version of the MQTT protocol";
  115. case 0x85:
  116. return "The Client ID is valid but not allowed by this Server";
  117. case 0x86:
  118. return "The Server does not accept the User Name or Password provided";
  119. case 0x87:
  120. return "The request is not authorized";
  121. case 0x88:
  122. return "The MQTT Server is not available";
  123. case 0x89:
  124. return "The MQTT Server is busy, try again later";
  125. case 0x8a:
  126. return "The Client has been banned by administrative action";
  127. case 0x8b:
  128. return "The Server is shutting down";
  129. case 0x8c:
  130. return "The authentication method is not supported or "
  131. "does not match the method currently in use";
  132. case 0x8d:
  133. return "No packet has been received for 1.5 times the Keepalive time";
  134. case 0x8e:
  135. return "Another Connection using the same ClientID has connected "
  136. "causing this Connection to be closed";
  137. case 0x8f:
  138. return "The Topic Filer is not malformed, but it is not accepted";
  139. case 0x90:
  140. return "The Topic Name is not malformed, but it is not accepted";
  141. case 0x91:
  142. return "The Packet Identifier is already in use";
  143. case 0x92:
  144. return "The Packet Identifier is not known";
  145. case 0x93:
  146. return "The Client or Server has received more than the Receive "
  147. "Maximum publication for which it has not sent PUBACK or PUBCOMP";
  148. case 0x94:
  149. return "The Client or Server received a PUBLISH packet containing "
  150. "a Topic Alias greater than the Maximum Topic Alias";
  151. case 0x95:
  152. return "The packet exceeded the maximum permissible size";
  153. case 0x96:
  154. return "The received data rate is too high";
  155. case 0x97:
  156. return "An implementation or administrative imposed limit has been exceeded";
  157. case 0x98:
  158. return "The Connection is closed due to an administrative action";
  159. case 0x99:
  160. return "The Payload does not match the specified Payload Format Indicator";
  161. case 0x9a:
  162. return "The Server does not support retained messages";
  163. case 0x9b:
  164. return "The Server does not support the QoS the Client specified or "
  165. "it is greater than the Maximum QoS specified";
  166. case 0x9c:
  167. return "The Client should temporarily use another server";
  168. case 0x9d:
  169. return "The Client should permanently use another server";
  170. case 0x9e:
  171. return "The Server does not support Shared Subscriptions for this Client";
  172. case 0x9f:
  173. return "The connection rate limit has been exceeded";
  174. case 0xa0:
  175. return "The maximum connection time authorized for this "
  176. "connection has been exceeded";
  177. case 0xa1:
  178. return "The Server does not support Subscription Identifiers";
  179. case 0xa2:
  180. return "The Server does not support Wildcard Subscriptions";
  181. case 0xff:
  182. return "No reason code";
  183. default:
  184. return "Invalid reason code";
  185. }
  186. }
  187. };
  188. namespace reason_codes {
  189. /** \brief No Reason Code. A \ref client::error occurred.*/
  190. constexpr reason_code empty {};
  191. /** \brief The operation completed successfully. */
  192. constexpr reason_code success { 0x00 };
  193. /** \brief Close the connection normally. Do not send the Will Message. */
  194. constexpr reason_code normal_disconnection { 0x00, category::disconnect };
  195. /** \brief The subscription is accepted with maximum QoS sent at 0. */
  196. constexpr reason_code granted_qos_0 { 0x00, category::suback };
  197. /** \brief The subscription is accepted with maximum QoS sent at 1. */
  198. constexpr reason_code granted_qos_1 { 0x01 };
  199. /** \brief The subscription is accepted with maximum QoS sent at 2 */
  200. constexpr reason_code granted_qos_2 { 0x02 };
  201. /** \brief The Client wishes to disconnect but requires that
  202. the Server also publishes its Will Message. */
  203. constexpr reason_code disconnect_with_will_message { 0x04 };
  204. /** \brief The message is accepted but there are no subscribers. */
  205. constexpr reason_code no_matching_subscribers { 0x10 };
  206. /** \brief No matching Topic Filter is being used by the Client. */
  207. constexpr reason_code no_subscription_existed { 0x11 };
  208. /** \brief Continue the authentication with another step. */
  209. constexpr reason_code continue_authentication { 0x18 };
  210. /** \brief Initiate a re-authentication. */
  211. constexpr reason_code reauthenticate { 0x19 };
  212. /** \brief The Server does not wish to reveal the reason for the
  213. failure or none of the other Reason Codes apply. */
  214. constexpr reason_code unspecified_error { 0x80 };
  215. /** \brief Data within the packet could not be correctly parsed. */
  216. constexpr reason_code malformed_packet { 0x81 };
  217. /** \brief Data in the packet does not conform to this specification. */
  218. constexpr reason_code protocol_error { 0x82 };
  219. /** \brief The packet is valid but not accepted by this Server. */
  220. constexpr reason_code implementation_specific_error { 0x83 };
  221. /** \brief The Server does not support the requested version of the MQTT protocol. */
  222. constexpr reason_code unsupported_protocol_version { 0x84 };
  223. /** \brief The Client ID is valid but not allowed by this Server. */
  224. constexpr reason_code client_identifier_not_valid { 0x85 };
  225. /** \brief The Server does not accept the User Name or Password provided. */
  226. constexpr reason_code bad_username_or_password { 0x86 };
  227. /** \brief The request is not authorized. */
  228. constexpr reason_code not_authorized { 0x87 };
  229. /** \brief The MQTT Server is not available. */
  230. constexpr reason_code server_unavailable { 0x88 };
  231. /** \brief The MQTT Server is busy, try again later. */
  232. constexpr reason_code server_busy { 0x89 };
  233. /** \brief The Client has been banned by administrative action. */
  234. constexpr reason_code banned { 0x8a };
  235. /** \brief The Server is shutting down. */
  236. constexpr reason_code server_shutting_down { 0x8b };
  237. /** \brief The authentication method is not supported or
  238. does not match the method currently in use. */
  239. constexpr reason_code bad_authentication_method { 0x8c };
  240. /** \brief No packet has been received for 1.5 times the Keepalive time. */
  241. constexpr reason_code keep_alive_timeout { 0x8d };
  242. /** \brief Another Connection using the same ClientID has connected
  243. causing this Connection to be closed. */
  244. constexpr reason_code session_taken_over { 0x8e };
  245. /** \brief The Topic Filter is not malformed, but it is not accepted. */
  246. constexpr reason_code topic_filter_invalid { 0x8f };
  247. /** \brief The Topic Name is not malformed, but it is not accepted. */
  248. constexpr reason_code topic_name_invalid { 0x90 };
  249. /** \brief The Packet Identifier is already in use. */
  250. constexpr reason_code packet_identifier_in_use { 0x91 };
  251. /** \brief The Packet Identifier is not known. */
  252. constexpr reason_code packet_identifier_not_found { 0x92 };
  253. /** \brief The Client or Server has received more than the Receive
  254. Maximum publication for which it has not sent PUBACK or PUBCOMP. */
  255. constexpr reason_code receive_maximum_exceeded { 0x93 };
  256. /** \brief The Client or Server received a PUBLISH packet containing
  257. a Topic Alias greater than the Maximum Topic Alias. */
  258. constexpr reason_code topic_alias_invalid { 0x94 };
  259. /** \brief The packet exceeded the maximum permissible size. */
  260. constexpr reason_code packet_too_large { 0x95 };
  261. /** \brief The received data rate is too high. */
  262. constexpr reason_code message_rate_too_high { 0x96 };
  263. /** \brief An implementation or administrative imposed limit has been exceeded. */
  264. constexpr reason_code quota_exceeded { 0x97 };
  265. /** \brief The Connection is closed due to an administrative action. */
  266. constexpr reason_code administrative_action { 0x98 };
  267. /** \brief The Payload does not match the specified Payload Format Indicator. */
  268. constexpr reason_code payload_format_invalid { 0x99 };
  269. /** \brief The Server does not support retained messages. */
  270. constexpr reason_code retain_not_supported { 0x9a };
  271. /** \brief The Server does not support the QoS the Client specified or
  272. it is greater than the Maximum QoS specified. */
  273. constexpr reason_code qos_not_supported { 0x9b };
  274. /** \brief The Client should temporarily use another server. */
  275. constexpr reason_code use_another_server { 0x9c };
  276. /** \brief The Client should permanently use another server. */
  277. constexpr reason_code server_moved { 0x9d };
  278. /** \brief The Server does not support Shared Subscriptions for this Client. */
  279. constexpr reason_code shared_subscriptions_not_supported { 0x9e };
  280. /** \brief The connection rate limit has been exceeded. */
  281. constexpr reason_code connection_rate_exceeded { 0x9f };
  282. /** \brief The maximum connection time authorized for this
  283. connection has been exceeded. */
  284. constexpr reason_code maximum_connect_time { 0xa0 };
  285. /** \brief The Server does not support Subscription Identifiers. */
  286. constexpr reason_code subscription_ids_not_supported { 0xa1 };
  287. /** \brief The Server does not support Wildcard Subscriptions. */
  288. constexpr reason_code wildcard_subscriptions_not_supported { 0xa2 };
  289. namespace detail {
  290. template <
  291. category cat,
  292. std::enable_if_t<cat == category::connack, bool> = true
  293. >
  294. std::pair<reason_code*, size_t> valid_codes() {
  295. static reason_code valid_codes[] = {
  296. success, unspecified_error, malformed_packet,
  297. protocol_error, implementation_specific_error,
  298. unsupported_protocol_version, client_identifier_not_valid,
  299. bad_username_or_password, not_authorized,
  300. server_unavailable, server_busy, banned,
  301. bad_authentication_method, topic_name_invalid,
  302. packet_too_large, quota_exceeded,
  303. payload_format_invalid, retain_not_supported,
  304. qos_not_supported, use_another_server,
  305. server_moved, connection_rate_exceeded
  306. };
  307. static size_t len = sizeof(valid_codes) / sizeof(reason_code);
  308. return std::make_pair(valid_codes, len);
  309. }
  310. template <
  311. category cat,
  312. std::enable_if_t<cat == category::auth, bool> = true
  313. >
  314. std::pair<reason_code*, size_t> valid_codes() {
  315. static reason_code valid_codes[] = {
  316. success, continue_authentication, reauthenticate
  317. };
  318. static size_t len = sizeof(valid_codes) / sizeof(reason_code);
  319. return std::make_pair(valid_codes, len);
  320. }
  321. template <
  322. category cat,
  323. std::enable_if_t<
  324. cat == category::puback || cat == category::pubrec, bool
  325. > = true
  326. >
  327. std::pair<reason_code*, size_t> valid_codes() {
  328. static reason_code valid_codes[] = {
  329. success, no_matching_subscribers, unspecified_error,
  330. implementation_specific_error, not_authorized,
  331. topic_name_invalid, packet_identifier_in_use,
  332. quota_exceeded, payload_format_invalid
  333. };
  334. static size_t len = sizeof(valid_codes) / sizeof(reason_code);
  335. return std::make_pair(valid_codes, len);
  336. }
  337. template <
  338. category cat,
  339. std::enable_if_t<
  340. cat == category::pubrel || cat == category::pubcomp, bool
  341. > = true
  342. >
  343. std::pair<reason_code*, size_t> valid_codes() {
  344. static reason_code valid_codes[] = {
  345. success, packet_identifier_not_found
  346. };
  347. static size_t len = sizeof(valid_codes) / sizeof(reason_code);
  348. return std::make_pair(valid_codes, len);
  349. }
  350. template <
  351. category cat,
  352. std::enable_if_t<cat == category::suback, bool> = true
  353. >
  354. std::pair<reason_code*, size_t> valid_codes() {
  355. static reason_code valid_codes[] = {
  356. granted_qos_0, granted_qos_1, granted_qos_2,
  357. unspecified_error, implementation_specific_error,
  358. not_authorized, topic_filter_invalid,
  359. packet_identifier_in_use, quota_exceeded,
  360. shared_subscriptions_not_supported,
  361. subscription_ids_not_supported,
  362. wildcard_subscriptions_not_supported
  363. };
  364. static size_t len = sizeof(valid_codes) / sizeof(reason_code);
  365. return std::make_pair(valid_codes, len);
  366. }
  367. template <
  368. category cat,
  369. std::enable_if_t<cat == category::unsuback, bool> = true
  370. >
  371. std::pair<reason_code*, size_t> valid_codes() {
  372. static reason_code valid_codes[] = {
  373. success, no_subscription_existed,
  374. unspecified_error, implementation_specific_error,
  375. not_authorized, topic_filter_invalid,
  376. packet_identifier_in_use
  377. };
  378. static size_t len = sizeof(valid_codes) / sizeof(reason_code);
  379. return std::make_pair(valid_codes, len);
  380. }
  381. template <
  382. category cat,
  383. std::enable_if_t<cat == category::disconnect, bool> = true
  384. >
  385. std::pair<reason_code*, size_t> valid_codes() {
  386. static reason_code valid_codes[] = {
  387. normal_disconnection, unspecified_error,
  388. malformed_packet, protocol_error,
  389. implementation_specific_error, not_authorized,
  390. server_busy, server_shutting_down,
  391. keep_alive_timeout, session_taken_over,
  392. topic_filter_invalid, topic_name_invalid,
  393. receive_maximum_exceeded, topic_alias_invalid,
  394. packet_too_large, message_rate_too_high,
  395. quota_exceeded, administrative_action,
  396. payload_format_invalid, retain_not_supported,
  397. qos_not_supported, use_another_server,
  398. server_moved, shared_subscriptions_not_supported,
  399. connection_rate_exceeded, maximum_connect_time,
  400. subscription_ids_not_supported,
  401. wildcard_subscriptions_not_supported
  402. };
  403. static size_t len = sizeof(valid_codes) / sizeof(reason_code);
  404. return std::make_pair(valid_codes, len);
  405. }
  406. } // end namespace detail
  407. } // end namespace reason_codes
  408. template <reason_codes::category cat>
  409. std::optional<reason_code> to_reason_code(uint8_t code) {
  410. auto [ptr, len] = reason_codes::detail::valid_codes<cat>();
  411. auto it = std::lower_bound(ptr, ptr + len, reason_code(code));
  412. if (it->value() == code)
  413. return *it;
  414. return std::nullopt;
  415. }
  416. } // end namespace boost::mqtt5
  417. #endif // !BOOST_MQTT5_REASON_CODES_HPP