properties.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431
  1. /////////////////////////////////////////////////////////////////////////////
  2. /// @file properties.h
  3. /// Declaration of MQTT properties class
  4. /// @date July 7, 2019
  5. /// @author Frank Pagliughi
  6. /////////////////////////////////////////////////////////////////////////////
  7. /*******************************************************************************
  8. * Copyright (c) 2019-2024 Frank Pagliughi <fpagliughi@mindspring.com>
  9. *
  10. * All rights reserved. This program and the accompanying materials
  11. * are made available under the terms of the Eclipse Public License v2.0
  12. * and Eclipse Distribution License v1.0 which accompany this distribution.
  13. *
  14. * The Eclipse Public License is available at
  15. * http://www.eclipse.org/legal/epl-v20.html
  16. * and the Eclipse Distribution License is available at
  17. * http://www.eclipse.org/org/documents/edl-v10.php.
  18. *
  19. * Contributors:
  20. * Frank Pagliughi - initial implementation and documentation
  21. *******************************************************************************/
  22. #ifndef __mqtt_properties_h
  23. #define __mqtt_properties_h
  24. extern "C" {
  25. #include "MQTTProperties.h"
  26. }
  27. #include "mqtt/types.h"
  28. #include "mqtt/buffer_ref.h"
  29. #include "mqtt/exception.h"
  30. #include "mqtt/platform.h"
  31. #include <tuple>
  32. #include <initializer_list>
  33. #include <iostream>
  34. namespace mqtt {
  35. /** A pair of strings as a tuple. */
  36. using string_pair = std::tuple<string, string>;
  37. /////////////////////////////////////////////////////////////////////////////
  38. /**
  39. * A single MQTT v5 property.
  40. */
  41. class property
  42. {
  43. /** The underlying Paho C property struct. */
  44. MQTTProperty prop_;
  45. // Make a deep copy of the property struct into this one.
  46. // For string properties, this allocates memory and copied the string(s)
  47. void copy(const MQTTProperty& other);
  48. public:
  49. /**
  50. * The integer codes for the different v5 properties.
  51. */
  52. enum code {
  53. PAYLOAD_FORMAT_INDICATOR = 1,
  54. MESSAGE_EXPIRY_INTERVAL = 2,
  55. CONTENT_TYPE = 3,
  56. RESPONSE_TOPIC = 8,
  57. CORRELATION_DATA = 9,
  58. SUBSCRIPTION_IDENTIFIER = 11,
  59. SESSION_EXPIRY_INTERVAL = 17,
  60. ASSIGNED_CLIENT_IDENTIFIER = 18,
  61. SERVER_KEEP_ALIVE = 19,
  62. AUTHENTICATION_METHOD = 21,
  63. AUTHENTICATION_DATA = 22,
  64. REQUEST_PROBLEM_INFORMATION = 23,
  65. WILL_DELAY_INTERVAL = 24,
  66. REQUEST_RESPONSE_INFORMATION = 25,
  67. RESPONSE_INFORMATION = 26,
  68. SERVER_REFERENCE = 28,
  69. REASON_STRING = 31,
  70. RECEIVE_MAXIMUM = 33,
  71. TOPIC_ALIAS_MAXIMUM = 34,
  72. TOPIC_ALIAS = 35,
  73. MAXIMUM_QOS = 36,
  74. RETAIN_AVAILABLE = 37,
  75. USER_PROPERTY = 38,
  76. MAXIMUM_PACKET_SIZE = 39,
  77. WILDCARD_SUBSCRIPTION_AVAILABLE = 40,
  78. SUBSCRIPTION_IDENTIFIERS_AVAILABLE = 41,
  79. SHARED_SUBSCRIPTION_AVAILABLE = 42
  80. };
  81. /**
  82. * Create a numeric property.
  83. * This can be a byte, or 2-byte, 4-byte, or variable byte integer.
  84. * @param c The property code
  85. * @param val The integer value for the property
  86. */
  87. property(code c, int32_t val);
  88. /**
  89. * Create a numeric property.
  90. * This can be a byte, or 2-byte, 4-byte, or variable byte integer.
  91. * @param c The property code
  92. * @param val The integer value for the property
  93. */
  94. property(code c, uint32_t val) : property(c, int32_t(val)) {}
  95. /**
  96. * Create a string or binary property.
  97. * @param c The property code
  98. * @param val The value for the property
  99. */
  100. property(code c, string_ref val);
  101. /**
  102. * Create a string pair property.
  103. * @param c The property code
  104. * @param name The string name for the property
  105. * @param val The string value for the property
  106. */
  107. property(code c, string_ref name, string_ref val);
  108. /**
  109. * Creates a property list from an C struct.
  110. * @param cprop A C struct for a property list.
  111. */
  112. explicit property(const MQTTProperty& cprop);
  113. /**
  114. * Moves a C struct into this property list.
  115. * This takes ownership of any memory that the C struct is holding.
  116. * @param cprop A C struct for a property list.
  117. */
  118. explicit property(MQTTProperty&& cprop);
  119. /**
  120. * Copy constructor
  121. * @param other The other property to copy into this one.
  122. */
  123. property(const property& other);
  124. /**
  125. * Move constructor.
  126. * @param other The other property that is moved into this one.
  127. */
  128. property(property&& other);
  129. /**
  130. * Destructor
  131. */
  132. ~property();
  133. /**
  134. * Copy assignment.
  135. * @param rhs Another property list to copy into this one.
  136. * @return A reference to this object.
  137. */
  138. property& operator=(const property& rhs);
  139. /**
  140. * Move assignment.
  141. * @param rhs Another property list to move into this one.
  142. * @return A reference to this object.
  143. */
  144. property& operator=(property&& rhs);
  145. /**
  146. * Gets the underlying C property struct.
  147. * @return A const reference to the underlying C property
  148. * struct.
  149. */
  150. const MQTTProperty& c_struct() const { return prop_; }
  151. /**
  152. * Gets the property type (identifier).
  153. * @return The code for the property type.
  154. */
  155. code type() const { return code(prop_.identifier); }
  156. /**
  157. * Gets a printable name for the property type.
  158. * @return A printable name for the property type.
  159. */
  160. const char* type_name() const {
  161. return ::MQTTPropertyName(prop_.identifier);
  162. }
  163. };
  164. /**
  165. * Extracts the value from the property as the specified type.
  166. * @return The value from the property as the specified type.
  167. */
  168. template <typename T>
  169. inline T get(const property&) { throw bad_cast(); }
  170. /**
  171. * Extracts the value from the property as an unsigned 8-bit integer.
  172. * @return The value from the property as an unsigned 8-bit integer.
  173. */
  174. template <>
  175. inline uint8_t get<uint8_t>(const property& prop) {
  176. return (uint8_t) prop.c_struct().value.byte;
  177. }
  178. /**
  179. * Extracts the value from the property as an unsigned 16-bit integer.
  180. * @return The value from the property as an unsigned 16-bit integer.
  181. */
  182. template <>
  183. inline uint16_t get<uint16_t>(const property& prop) {
  184. return (uint16_t) prop.c_struct().value.integer2;
  185. }
  186. /**
  187. * Extracts the value from the property as a signed 16-bit integer.
  188. * @return The value from the property as a signed 16-bit integer.
  189. * @deprecated All integer properties are unsigned. Use
  190. * `get<uint16_t>()`
  191. */
  192. template <>
  193. inline int16_t get<int16_t>(const property& prop) {
  194. return (int16_t) prop.c_struct().value.integer2;
  195. }
  196. /**
  197. * Extracts the value from the property as an unsigned 32-bit integer.
  198. * @return The value from the property as an unsigned 32-bit integer.
  199. */
  200. template <>
  201. inline uint32_t get<uint32_t>(const property& prop) {
  202. return (uint32_t) prop.c_struct().value.integer4;
  203. }
  204. /**
  205. * Extracts the value from the property as a signed 32-bit integer.
  206. * @return The value from the property as a signed 32-bit integer.
  207. * @deprecated All integer properties are unsigned. Use
  208. * `get<uint32_t>()`
  209. */
  210. template <>
  211. inline int32_t get<int32_t>(const property& prop) {
  212. return (int32_t) prop.c_struct().value.integer4;
  213. }
  214. /**
  215. * Extracts the value from the property as a string.
  216. * @return The value from the property as a string.
  217. */
  218. template <>
  219. inline string get<string>(const property& prop) {
  220. return (!prop.c_struct().value.data.data) ? string()
  221. : string(prop.c_struct().value.data.data, prop.c_struct().value.data.len);
  222. }
  223. /**
  224. * Extracts the value from the property as a pair of strings.
  225. * @return The value from the property as a pair of strings.
  226. */
  227. template <>
  228. inline string_pair get<string_pair>(const property& prop) {
  229. string name = (!prop.c_struct().value.data.data) ? string()
  230. : string(prop.c_struct().value.data.data, prop.c_struct().value.data.len);
  231. string value = (!prop.c_struct().value.value.data) ? string()
  232. : string(prop.c_struct().value.value.data, prop.c_struct().value.value.len);
  233. return std::make_tuple(std::move(name), std::move(value));
  234. }
  235. /////////////////////////////////////////////////////////////////////////////
  236. /**
  237. * MQTT v5 property list.
  238. *
  239. * A collection of properties that can be added to outgoing packets or
  240. * retrieved from incoming packets.
  241. */
  242. class properties
  243. {
  244. /** The default C struct */
  245. PAHO_MQTTPP_EXPORT static const MQTTProperties DFLT_C_STRUCT;
  246. /** The underlying C properties struct */
  247. MQTTProperties props_;
  248. template<typename T>
  249. friend T get(const properties& props, property::code propid, size_t idx);
  250. template<typename T>
  251. friend T get(const properties& props, property::code propid);
  252. public:
  253. /**
  254. * Default constructor.
  255. * Creates an empty properties list.
  256. */
  257. properties();
  258. /**
  259. * Copy constructor.
  260. * @param other The property list to copy.
  261. */
  262. properties(const properties& other)
  263. : props_(::MQTTProperties_copy(&other.props_)) {}
  264. /**
  265. * Move constructor.
  266. * @param other The property list to move to this one.
  267. */
  268. properties(properties&& other) : props_(other.props_) {
  269. std::memset(&other.props_, 0, sizeof(MQTTProperties));
  270. }
  271. /**
  272. * Creates a list of properties from a C struct.
  273. * @param cprops The c struct of properties
  274. */
  275. properties(const MQTTProperties& cprops) {
  276. props_ = ::MQTTProperties_copy(&cprops);
  277. }
  278. /**
  279. * Constructs from a list of property objects.
  280. * @param props An initializer list of property objects.
  281. */
  282. properties(std::initializer_list<property> props);
  283. /**
  284. * Destructor.
  285. */
  286. ~properties() { ::MQTTProperties_free(&props_); }
  287. /**
  288. * Gets a reference to the underlying C properties structure.
  289. * @return A const reference to the underlying C properties structure.
  290. */
  291. const MQTTProperties& c_struct() const { return props_; }
  292. /**
  293. * Copy assignment.
  294. * @param rhs The other property list to copy into this one
  295. * @return A reference to this object.
  296. */
  297. properties& operator=(const properties& rhs);
  298. /**
  299. * Move assignment.
  300. * @param rhs The property list to move to this one.
  301. * @return A reference to this object.
  302. */
  303. properties& operator=(properties&& rhs);
  304. /**
  305. * Determines if the property list is empty.
  306. * @return @em true if there are no properties in the list, @em false if
  307. * the list contains any items.
  308. */
  309. bool empty() const { return props_.count == 0; }
  310. /**
  311. * Gets the numbers of property items in the list.
  312. * @return The number of property items in the list.
  313. */
  314. size_t size() const { return size_t(props_.count); }
  315. /**
  316. * Adds a property to the list.
  317. * @param prop The property to add to the list.
  318. */
  319. void add(const property& prop) {
  320. ::MQTTProperties_add(&props_, &prop.c_struct());
  321. }
  322. /**
  323. * Removes all the items from the property list.
  324. */
  325. void clear() {
  326. ::MQTTProperties_free(&props_);
  327. }
  328. /**
  329. * Determines if the list contains a specific property.
  330. * @param propid The property ID (code).
  331. * @return @em true if the list contains the property, @em false if not.
  332. */
  333. bool contains(property::code propid) const {
  334. return ::MQTTProperties_hasProperty(const_cast<MQTTProperties*>(&props_),
  335. MQTTPropertyCodes(propid)) != 0;
  336. }
  337. /**
  338. * Get the number of properties in the list with the specified property
  339. * ID.
  340. *
  341. * Most properties can exist only once. User properties and subscription
  342. * ID's can exist more than once.
  343. *
  344. * @param propid The property ID (code).
  345. * @return The number of properties in the list with the specified ID.
  346. */
  347. size_t count(property::code propid) const {
  348. return size_t(::MQTTProperties_propertyCount(
  349. const_cast<MQTTProperties*>(&props_), MQTTPropertyCodes(propid)));
  350. }
  351. /**
  352. * Gets the property with the specified ID.
  353. *
  354. * @param propid The property ID (code).
  355. * @param idx Which instance of the property to retrieve, if there are
  356. * more than one.
  357. * @return The requested property
  358. */
  359. property get(property::code propid, size_t idx=0);
  360. };
  361. // --------------------------------------------------------------------------
  362. /**
  363. * Retrieves a single value from a property list for when there may be
  364. * multiple identical property ID's.
  365. * @tparam T The type of the value to retrieve
  366. * @param props The property list
  367. * @param propid The property ID code for the desired value.
  368. * @param idx Index of the desired property ID
  369. * @return The requested value of type T
  370. */
  371. template<typename T>
  372. inline T get(const properties& props, property::code propid, size_t idx)
  373. {
  374. MQTTProperty* prop = MQTTProperties_getPropertyAt(
  375. const_cast<MQTTProperties*>(&props.c_struct()),
  376. MQTTPropertyCodes(propid), int(idx));
  377. if (!prop)
  378. throw bad_cast();
  379. return get<T>(property(*prop));
  380. }
  381. /**
  382. * Retrieves a single value from a property list.
  383. * @tparam T The type of the value to retrieve
  384. * @param props The property list
  385. * @param propid The property ID code for the desired value.
  386. * @return The requested value of type T
  387. */
  388. template<typename T>
  389. inline T get(const properties& props, property::code propid)
  390. {
  391. return get<T>(props, propid, 0);
  392. }
  393. /////////////////////////////////////////////////////////////////////////////
  394. // end namespace mqtt
  395. }
  396. #endif // __mqtt_properties_h