properties.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  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 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 v1.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-v10.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 <tuple>
  31. #include <initializer_list>
  32. #include <iostream>
  33. namespace mqtt {
  34. using string_pair = std::tuple<string, string>;
  35. /////////////////////////////////////////////////////////////////////////////
  36. /**
  37. * A single MQTT v5 property.
  38. */
  39. class property
  40. {
  41. /** The underlying Paho C property struct. */
  42. MQTTProperty prop_;
  43. // Make a deep copy of the property struct into this one.
  44. // For string properties, this allocates memory and copied the string(s)
  45. void copy(const MQTTProperty& other);
  46. public:
  47. enum code {
  48. PAYLOAD_FORMAT_INDICATOR = 1,
  49. MESSAGE_EXPIRY_INTERVAL = 2,
  50. CONTENT_TYPE = 3,
  51. RESPONSE_TOPIC = 8,
  52. CORRELATION_DATA = 9,
  53. SUBSCRIPTION_IDENTIFIER = 11,
  54. SESSION_EXPIRY_INTERVAL = 17,
  55. ASSIGNED_CLIENT_IDENTIFER = 18,
  56. SERVER_KEEP_ALIVE = 19,
  57. AUTHENTICATION_METHOD = 21,
  58. AUTHENTICATION_DATA = 22,
  59. REQUEST_PROBLEM_INFORMATION = 23,
  60. WILL_DELAY_INTERVAL = 24,
  61. REQUEST_RESPONSE_INFORMATION = 25,
  62. RESPONSE_INFORMATION = 26,
  63. SERVER_REFERENCE = 28,
  64. REASON_STRING = 31,
  65. RECEIVE_MAXIMUM = 33,
  66. TOPIC_ALIAS_MAXIMUM = 34,
  67. TOPIC_ALIAS = 35,
  68. MAXIMUM_QOS = 36,
  69. RETAIN_AVAILABLE = 37,
  70. USER_PROPERTY = 38,
  71. MAXIMUM_PACKET_SIZE = 39,
  72. WILDCARD_SUBSCRIPTION_AVAILABLE = 40,
  73. SUBSCRIPTION_IDENTIFIERS_AVAILABLE = 41,
  74. SHARED_SUBSCRIPTION_AVAILABLE = 42
  75. };
  76. /**
  77. * Create a numeric property.
  78. * This can be a byte, or 2-byte, 4-byte, or variable byte integer.
  79. * @param c The property code
  80. * @param val The integer value for the property
  81. */
  82. property(code c, int32_t val);
  83. /**
  84. * Create a string or binary property.
  85. * @param c The property code
  86. * @param val The value for the property
  87. */
  88. property(code c, string_ref val);
  89. /**
  90. * Create a string pair property.
  91. * @param c The property code
  92. * @param name The string name for the property
  93. * @param val The string value for the property
  94. */
  95. property(code c, string_ref name, string_ref val);
  96. /**
  97. * Creates a property list from an C struct.
  98. * @param cprop A C struct for a property list.
  99. */
  100. explicit property(const MQTTProperty& cprop);
  101. /**
  102. * Moves a C struct into this property list.
  103. * This takes ownership of any memory that the C struct is holding.
  104. * @param cprop A C struct for a property list.
  105. */
  106. explicit property(MQTTProperty&& cprop);
  107. /**
  108. * Copy constructor
  109. * @param other The other property to copy into this one.
  110. */
  111. property(const property& other);
  112. /**
  113. * Move constructor.
  114. * @param other The other property that is moved into this one.
  115. */
  116. property(property&& other);
  117. /**
  118. * Destructor
  119. */
  120. ~property();
  121. /**
  122. * Copy assignment.
  123. * @param rhs Another property list to copy into this one.
  124. * @return A reference to this object.
  125. */
  126. property& operator=(const property& rhs);
  127. /**
  128. * Move assignment.
  129. * @param rhs Another property list to move into this one.
  130. * @return A reference to this object.
  131. */
  132. property& operator=(property&& rhs);
  133. /**
  134. * Gets the underlying C property struct.
  135. * @return A const reference to the underlying C property
  136. * struct.
  137. */
  138. const MQTTProperty& c_struct() const { return prop_; }
  139. /**
  140. * Gets the property type (identifier).
  141. * @return The code for the property type.
  142. */
  143. code type() const { return code(prop_.identifier); }
  144. /**
  145. * Gets a printable name for the property type.
  146. * @return A printable name for the property type.
  147. */
  148. const char* type_name() const {
  149. return ::MQTTPropertyName(prop_.identifier);
  150. }
  151. };
  152. /**
  153. * Extracts the value from the property as the specitied type.
  154. * @return The value from the property as the specitied type.
  155. */
  156. template <typename T>
  157. inline T get(const property&) { throw bad_cast(); }
  158. template <>
  159. inline uint8_t get<uint8_t>(const property& prop) {
  160. return (uint8_t) prop.c_struct().value.byte;
  161. }
  162. template <>
  163. inline uint16_t get<uint16_t>(const property& prop) {
  164. return (uint16_t) prop.c_struct().value.integer2;
  165. }
  166. template <>
  167. inline int16_t get<int16_t>(const property& prop) {
  168. return (int16_t) prop.c_struct().value.integer2;
  169. }
  170. template <>
  171. inline uint32_t get<uint32_t>(const property& prop) {
  172. return (uint32_t) prop.c_struct().value.integer4;
  173. }
  174. template <>
  175. inline int32_t get<int32_t>(const property& prop) {
  176. return (int32_t) prop.c_struct().value.integer4;
  177. }
  178. template <>
  179. inline string get<string>(const property& prop) {
  180. return (!prop.c_struct().value.data.data) ? string()
  181. : string(prop.c_struct().value.data.data, prop.c_struct().value.data.len);
  182. }
  183. template <>
  184. inline string_pair get<string_pair>(const property& prop) {
  185. string name = (!prop.c_struct().value.data.data) ? string()
  186. : string(prop.c_struct().value.data.data, prop.c_struct().value.data.len);
  187. string value = (!prop.c_struct().value.value.data) ? string()
  188. : string(prop.c_struct().value.value.data, prop.c_struct().value.value.len);
  189. return std::make_tuple(std::move(name), std::move(value));
  190. }
  191. /////////////////////////////////////////////////////////////////////////////
  192. /**
  193. * MQTT v5 property list.
  194. *
  195. * A collection of properties that can be added to outgoing packets or
  196. * retrieved from incoming packets.
  197. */
  198. class properties
  199. {
  200. /** The underlying C properties struct */
  201. MQTTProperties props_;
  202. template<typename T>
  203. friend T get(const properties& props, property::code propid, size_t idx);
  204. template<typename T>
  205. friend T get(const properties& props, property::code propid);
  206. public:
  207. /**
  208. * Default constructor.
  209. * Creates an empty properties list.
  210. */
  211. properties() {
  212. std::memset(&props_, 0, sizeof(MQTTProperties));
  213. }
  214. /**
  215. * Copy constructor.
  216. * @param other The property list to copy.
  217. */
  218. properties(const properties& other)
  219. : props_(::MQTTProperties_copy(&other.props_)) {}
  220. /**
  221. * Move constructor.
  222. * @param other The property list to move to this one.
  223. */
  224. properties(properties&& other) : props_(other.props_) {
  225. std::memset(&other.props_, 0, sizeof(MQTTProperties));
  226. }
  227. /**
  228. * Creates a list of properties from a C struct.
  229. * @param cprops The c struct of properties
  230. */
  231. properties(const MQTTProperties& cprops) {
  232. props_ = ::MQTTProperties_copy(&cprops);
  233. }
  234. /**
  235. * Constructs from a list of property objects.
  236. * @param An initializer list of property objects.
  237. */
  238. properties(std::initializer_list<property> props);
  239. /**
  240. * Destructor.
  241. */
  242. ~properties() { ::MQTTProperties_free(&props_); }
  243. /**
  244. * Gets a reference to the underlying C properties structure.
  245. * @return A const reference to the underlying C properties structure.
  246. */
  247. const MQTTProperties& c_struct() const { return props_; }
  248. /**
  249. * Copy assignment.
  250. * @param rhs The other property list to copy into this one
  251. * @return A reference to this object.
  252. */
  253. properties& operator=(const properties& rhs) {
  254. if (&rhs != this) {
  255. ::MQTTProperties_free(&props_);
  256. props_ = ::MQTTProperties_copy(&rhs.props_);
  257. }
  258. return *this;
  259. }
  260. /**
  261. * Move assignment
  262. * @param rht The property list to move to this one.
  263. * @return A reference to this object.
  264. */
  265. properties& operator=(properties&& rhs) {
  266. if (&rhs != this) {
  267. ::MQTTProperties_free(&props_);
  268. props_ = rhs.props_;
  269. std::memset(&rhs.props_, 0, sizeof(MQTTProperties));
  270. }
  271. return *this;
  272. }
  273. /**
  274. * Determines if the property list is empty.
  275. * @return @em true if there are no properties in the list, @em false if
  276. * the list contains any items.
  277. */
  278. bool empty() const { return props_.count == 0; }
  279. /**
  280. * Gets the numbers of property items in the list.
  281. * @return The number of property items in the list.
  282. */
  283. size_t size() const { return size_t(props_.count); }
  284. /**
  285. * Gets the number of bytes required for the serialized
  286. * structure on the wire.
  287. * @return The number of bytes required for the serialized
  288. * struct.
  289. */
  290. size_t byte_length() const {
  291. return (size_t) ::MQTTProperties_len(const_cast<MQTTProperties*>(&props_));
  292. }
  293. /**
  294. * Adds a property to the list.
  295. * @param prop The property to add to the list.
  296. */
  297. void add(const property& prop) {
  298. ::MQTTProperties_add(&props_, &prop.c_struct());
  299. }
  300. /**
  301. * Removes all the items from the property list.
  302. */
  303. void clear();
  304. /**
  305. * Determines if the list contains a specific property.
  306. * @param propid The property ID (code).
  307. * @return @em true if the list contains the property, @em false if not.
  308. */
  309. bool contains(property::code propid) const {
  310. return ::MQTTProperties_hasProperty(const_cast<MQTTProperties*>(&props_),
  311. MQTTPropertyCodes(propid)) != 0;
  312. }
  313. /**
  314. * Get the number of properties in the list with the specified property
  315. * ID.
  316. *
  317. * Most properties can exist only once. User properties and subscription
  318. * ID's can exist more than once.
  319. *
  320. * @param propid The property ID (code).
  321. * @return The number of properties in the list with the specified ID.
  322. */
  323. size_t count(property::code propid) {
  324. return size_t(::MQTTProperties_propertyCount(&props_, MQTTPropertyCodes(propid)));
  325. }
  326. /**
  327. * Gets the property with the specified ID.
  328. *
  329. * @param propid The property ID (code).
  330. * @param idx Which instance of the property to retrieve, if there are
  331. * more than one.
  332. * @return The requested property
  333. */
  334. property get(property::code propid, size_t idx=0);
  335. };
  336. // --------------------------------------------------------------------------
  337. template<typename T>
  338. inline T get(const properties& props, property::code propid, size_t idx)
  339. {
  340. MQTTProperty* prop = MQTTProperties_getPropertyAt(
  341. const_cast<MQTTProperties*>(&props.c_struct()),
  342. MQTTPropertyCodes(propid), int(idx));
  343. if (!prop)
  344. throw bad_cast();
  345. return get<T>(property(*prop));
  346. }
  347. template<typename T>
  348. inline T get(const properties& props, property::code propid)
  349. {
  350. return get<T>(props, propid, 0);
  351. }
  352. /////////////////////////////////////////////////////////////////////////////
  353. // end namespace mqtt
  354. }
  355. #endif // __mqtt_properties_h