mqtt.h 56 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543
  1. /*
  2. MIT License
  3. Copyright (c) 2018 Liam Bindle
  4. Copyright (c) 2019 Kalycito Infotech Private Limited
  5. Permission is hereby granted, free of charge, to any person obtaining a copy
  6. of this software and associated documentation files (the "Software"), to deal
  7. in the Software without restriction, including without limitation the rights
  8. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. copies of the Software, and to permit persons to whom the Software is
  10. furnished to do so, subject to the following conditions:
  11. The above copyright notice and this permission notice shall be included in all
  12. copies or substantial portions of the Software.
  13. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  16. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  18. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  19. SOFTWARE.
  20. */
  21. #ifndef __MQTT_H__
  22. #define __MQTT_H__
  23. #include "mqtt_pal.h"
  24. #ifdef __MINGW32__
  25. #include <pthread.h>
  26. #endif
  27. /**
  28. * @file
  29. * @brief Declares all the MQTT-C functions and datastructures.
  30. *
  31. * @note You should <code>\#include <mqtt.h></code>.
  32. *
  33. * @example simple_publisher.c
  34. * A simple program to that publishes the current time whenever ENTER is pressed.
  35. *
  36. * Usage:
  37. * \code{.sh}
  38. * ./bin/simple_publisher [address [port [topic]]]
  39. * \endcode
  40. *
  41. * Where \c address is the address of the MQTT broker, \c port is the port number the
  42. * MQTT broker is running on, and \c topic is the name of the topic to publish with. Note
  43. * that all these arguments are optional and the defaults are \c address = \c "test.mosquitto.org",
  44. * \c port = \c "1883", and \c topic = "datetime".
  45. *
  46. * @example simple_subscriber.c
  47. * A simple program that subscribes to a single topic and prints all updates that are received.
  48. *
  49. * Usage:
  50. * \code{.sh}
  51. * ./bin/simple_subscriber [address [port [topic]]]
  52. * \endcode
  53. *
  54. * Where \c address is the address of the MQTT broker, \c port is the port number the
  55. * MQTT broker is running on, and \c topic is the name of the topic subscribe to. Note
  56. * that all these arguments are optional and the defaults are \c address = \c "test.mosquitto.org",
  57. * \c port = \c "1883", and \c topic = "datetime".
  58. *
  59. * @example reconnect_subscriber.c
  60. * Same program as \ref simple_subscriber.c, but using the automatic reconnect functionality.
  61. *
  62. * @example bio_publisher.c
  63. * Same program as \ref simple_publisher.c, but uses a unencrypted BIO socket.
  64. *
  65. * @example openssl_publisher.c
  66. * Same program as \ref simple_publisher.c, but over an encrypted connection using OpenSSL.
  67. *
  68. * Usage:
  69. * \code{.sh}
  70. * ./bin/openssl_publisher ca_file [address [port [topic]]]
  71. * \endcode
  72. *
  73. *
  74. * @defgroup api API
  75. * @brief Documentation of everything you need to know to use the MQTT-C client.
  76. *
  77. * This module contains everything you need to know to use MQTT-C in your application.
  78. * For usage examples see:
  79. * - @ref simple_publisher.c
  80. * - @ref simple_subscriber.c
  81. * - @ref reconnect_subscriber.c
  82. * - @ref bio_publisher.c
  83. * - @ref openssl_publisher.c
  84. *
  85. * @note MQTT-C can be used in both single-threaded and multi-threaded applications. All
  86. * the functions in \ref api are thread-safe.
  87. *
  88. * @defgroup packers Control Packet Serialization
  89. * @brief Developer documentation of the functions and datastructures used for serializing MQTT
  90. * control packets.
  91. *
  92. * @defgroup unpackers Control Packet Deserialization
  93. * @brief Developer documentation of the functions and datastructures used for deserializing MQTT
  94. * control packets.
  95. *
  96. * @defgroup details Utilities
  97. * @brief Developer documentation for the utilities used to implement the MQTT-C client.
  98. *
  99. * @note To deserialize a packet from a buffer use \ref mqtt_unpack_response (it's the only
  100. * function you need).
  101. */
  102. /**
  103. * @brief An enumeration of the MQTT control packet types.
  104. * @ingroup unpackers
  105. *
  106. * @see <a href="http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718021">
  107. * MQTT v3.1.1: MQTT Control Packet Types
  108. * </a>
  109. */
  110. enum MQTTControlPacketType {
  111. MQTT_CONTROL_CONNECT=1u,
  112. MQTT_CONTROL_CONNACK=2u,
  113. MQTT_CONTROL_PUBLISH=3u,
  114. MQTT_CONTROL_PUBACK=4u,
  115. MQTT_CONTROL_PUBREC=5u,
  116. MQTT_CONTROL_PUBREL=6u,
  117. MQTT_CONTROL_PUBCOMP=7u,
  118. MQTT_CONTROL_SUBSCRIBE=8u,
  119. MQTT_CONTROL_SUBACK=9u,
  120. MQTT_CONTROL_UNSUBSCRIBE=10u,
  121. MQTT_CONTROL_UNSUBACK=11u,
  122. MQTT_CONTROL_PINGREQ=12u,
  123. MQTT_CONTROL_PINGRESP=13u,
  124. MQTT_CONTROL_DISCONNECT=14u
  125. };
  126. /**
  127. * @brief The fixed header of an MQTT control packet.
  128. * @ingroup unpackers
  129. *
  130. * @see <a href="http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718020">
  131. * MQTT v3.1.1: Fixed Header
  132. * </a>
  133. */
  134. struct mqtt_fixed_header {
  135. /** The type of packet. */
  136. enum MQTTControlPacketType control_type;
  137. /** The packets control flags.*/
  138. //uint8_t control_flags: 4; error: type of bit-field ‘control_flags’ is a GCC extension
  139. unsigned int control_flags: 4;
  140. /** The remaining size of the packet in bytes (i.e. the size of variable header and payload).*/
  141. uint32_t remaining_length;
  142. };
  143. /**
  144. * @brief The protocol identifier for MQTT v3.1.1.
  145. * @ingroup packers
  146. *
  147. * @see <a href="http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718030">
  148. * MQTT v3.1.1: CONNECT Variable Header.
  149. * </a>
  150. */
  151. #define MQTT_PROTOCOL_LEVEL 0x04
  152. /**
  153. * @brief A macro used to declare the enum MQTTErrors and associated
  154. * error messages (the members of the num) at the same time.
  155. */
  156. #define __ALL_MQTT_ERRORS(MQTT_ERROR) \
  157. MQTT_ERROR(MQTT_ERROR_NULLPTR) \
  158. MQTT_ERROR(MQTT_ERROR_CONTROL_FORBIDDEN_TYPE) \
  159. MQTT_ERROR(MQTT_ERROR_CONTROL_INVALID_FLAGS) \
  160. MQTT_ERROR(MQTT_ERROR_CONTROL_WRONG_TYPE) \
  161. MQTT_ERROR(MQTT_ERROR_CONNECT_NULL_CLIENT_ID) \
  162. MQTT_ERROR(MQTT_ERROR_CONNECT_NULL_WILL_MESSAGE) \
  163. MQTT_ERROR(MQTT_ERROR_CONNECT_FORBIDDEN_WILL_QOS) \
  164. MQTT_ERROR(MQTT_ERROR_CONNACK_FORBIDDEN_FLAGS) \
  165. MQTT_ERROR(MQTT_ERROR_CONNACK_FORBIDDEN_CODE) \
  166. MQTT_ERROR(MQTT_ERROR_PUBLISH_FORBIDDEN_QOS) \
  167. MQTT_ERROR(MQTT_ERROR_SUBSCRIBE_TOO_MANY_TOPICS) \
  168. MQTT_ERROR(MQTT_ERROR_MALFORMED_RESPONSE) \
  169. MQTT_ERROR(MQTT_ERROR_UNSUBSCRIBE_TOO_MANY_TOPICS) \
  170. MQTT_ERROR(MQTT_ERROR_RESPONSE_INVALID_CONTROL_TYPE) \
  171. MQTT_ERROR(MQTT_ERROR_CONNECT_NOT_CALLED) \
  172. MQTT_ERROR(MQTT_ERROR_SEND_BUFFER_IS_FULL) \
  173. MQTT_ERROR(MQTT_ERROR_SOCKET_ERROR) \
  174. MQTT_ERROR(MQTT_ERROR_MALFORMED_REQUEST) \
  175. MQTT_ERROR(MQTT_ERROR_RECV_BUFFER_TOO_SMALL) \
  176. MQTT_ERROR(MQTT_ERROR_ACK_OF_UNKNOWN) \
  177. MQTT_ERROR(MQTT_ERROR_NOT_IMPLEMENTED) \
  178. MQTT_ERROR(MQTT_ERROR_CONNECTION_REFUSED) \
  179. MQTT_ERROR(MQTT_ERROR_SUBSCRIBE_FAILED) \
  180. MQTT_ERROR(MQTT_ERROR_CONNECTION_CLOSED) \
  181. MQTT_ERROR(MQTT_ERROR_INITIAL_RECONNECT) \
  182. MQTT_ERROR(MQTT_ERROR_INVALID_REMAINING_LENGTH)
  183. /* todo: add more connection refused errors */
  184. /**
  185. * @brief A macro used to generate the enum MQTTErrors from
  186. * \ref __ALL_MQTT_ERRORS
  187. * @see __ALL_MQTT_ERRORS
  188. */
  189. #define GENERATE_ENUM(ENUM) ENUM,
  190. /**
  191. * @brief A macro used to generate the error messages associated with
  192. * MQTTErrors from \ref __ALL_MQTT_ERRORS
  193. * @see __ALL_MQTT_ERRORS
  194. */
  195. #define GENERATE_STRING(STRING) #STRING,
  196. /**
  197. * @brief An enumeration of error codes. Error messages can be retrieved by calling \ref mqtt_error_str.
  198. * @ingroup api
  199. *
  200. * @see mqtt_error_str
  201. */
  202. enum MQTTErrors {
  203. MQTT_ERROR_UNKNOWN=INT_MIN,
  204. __ALL_MQTT_ERRORS(GENERATE_ENUM)
  205. MQTT_OK = 1
  206. };
  207. /**
  208. * @brief Returns an error message for error code, \p error.
  209. * @ingroup api
  210. *
  211. * @param[in] error the error code.
  212. *
  213. * @returns The associated error message.
  214. */
  215. const char* mqtt_error_str(enum MQTTErrors error);
  216. /**
  217. * @brief Pack a MQTT string, given a c-string \p str.
  218. *
  219. * @param[out] buf the buffer that the MQTT string will be written to.
  220. * @param[in] str the c-string to be written to \p buf.
  221. *
  222. * @warning This function provides no error checking.
  223. *
  224. * @returns strlen(str) + 2
  225. */
  226. ssize_t __mqtt_pack_str(uint8_t *buf, const char* str);
  227. /** @brief A macro to get the MQTT string length from a c-string. */
  228. #define __mqtt_packed_cstrlen(x) (2 + strlen(x))
  229. /* RESPONSES */
  230. /**
  231. * @brief An enumeration of the return codes returned in a CONNACK packet.
  232. * @ingroup unpackers
  233. *
  234. * @see <a href="http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Table_3.1_-">
  235. * MQTT v3.1.1: CONNACK return codes.
  236. * </a>
  237. */
  238. enum MQTTConnackReturnCode {
  239. MQTT_CONNACK_ACCEPTED = 0u,
  240. MQTT_CONNACK_REFUSED_PROTOCOL_VERSION = 1u,
  241. MQTT_CONNACK_REFUSED_IDENTIFIER_REJECTED = 2u,
  242. MQTT_CONNACK_REFUSED_SERVER_UNAVAILABLE = 3u,
  243. MQTT_CONNACK_REFUSED_BAD_USER_NAME_OR_PASSWORD = 4u,
  244. MQTT_CONNACK_REFUSED_NOT_AUTHORIZED = 5u
  245. };
  246. /**
  247. * @brief A connection response datastructure.
  248. * @ingroup unpackers
  249. *
  250. * @see <a href="http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718033">
  251. * MQTT v3.1.1: CONNACK - Acknowledgement connection response.
  252. * </a>
  253. */
  254. struct mqtt_response_connack {
  255. /**
  256. * @brief Allows client and broker to check if they have a consistent view about whether there is
  257. * already a stored session state.
  258. */
  259. uint8_t session_present_flag;
  260. /**
  261. * @brief The return code of the connection request.
  262. *
  263. * @see MQTTConnackReturnCode
  264. */
  265. enum MQTTConnackReturnCode return_code;
  266. };
  267. /**
  268. * @brief A publish packet received from the broker.
  269. * @ingroup unpackers
  270. *
  271. * A publish packet is received from the broker when a client publishes to a topic that the
  272. * \em {local client} is subscribed to.
  273. *
  274. * @see <a href="http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718037">
  275. * MQTT v3.1.1: PUBLISH - Publish Message.
  276. * </a>
  277. */
  278. struct mqtt_response_publish {
  279. /**
  280. * @brief The DUP flag. DUP flag is 0 if its the first attempt to send this publish packet. A DUP flag
  281. * of 1 means that this might be a re-delivery of the packet.
  282. */
  283. uint8_t dup_flag;
  284. /**
  285. * @brief The quality of service level.
  286. *
  287. * @see <a href="http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Table_3.11_-">
  288. * MQTT v3.1.1: QoS Definitions
  289. * </a>
  290. */
  291. uint8_t qos_level;
  292. /** @brief The retain flag of this publish message. */
  293. uint8_t retain_flag;
  294. /** @brief Size of the topic name (number of characters). */
  295. uint16_t topic_name_size;
  296. /**
  297. * @brief The topic name.
  298. * @note topic_name is not null terminated. Therefore topic_name_size must be used to get the
  299. * string length.
  300. */
  301. const void* topic_name;
  302. /** @brief The publish message's packet ID. */
  303. uint16_t packet_id;
  304. /** @brief The publish message's application message.*/
  305. const void* application_message;
  306. /** @brief The size of the application message in bytes. */
  307. size_t application_message_size;
  308. };
  309. /**
  310. * @brief A publish acknowledgement for messages that were published with QoS level 1.
  311. * @ingroup unpackers
  312. *
  313. * @see <a href="http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718043">
  314. * MQTT v3.1.1: PUBACK - Publish Acknowledgement.
  315. * </a>
  316. *
  317. */
  318. struct mqtt_response_puback {
  319. /** @brief The published messages packet ID. */
  320. uint16_t packet_id;
  321. };
  322. /**
  323. * @brief The response packet to a PUBLISH packet with QoS level 2.
  324. * @ingroup unpackers
  325. *
  326. * @see <a href="http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718048">
  327. * MQTT v3.1.1: PUBREC - Publish Received.
  328. * </a>
  329. *
  330. */
  331. struct mqtt_response_pubrec {
  332. /** @brief The published messages packet ID. */
  333. uint16_t packet_id;
  334. };
  335. /**
  336. * @brief The response to a PUBREC packet.
  337. * @ingroup unpackers
  338. *
  339. * @see <a href="http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718053">
  340. * MQTT v3.1.1: PUBREL - Publish Release.
  341. * </a>
  342. *
  343. */
  344. struct mqtt_response_pubrel {
  345. /** @brief The published messages packet ID. */
  346. uint16_t packet_id;
  347. };
  348. /**
  349. * @brief The response to a PUBREL packet.
  350. * @ingroup unpackers
  351. *
  352. * @see <a href="http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718058">
  353. * MQTT v3.1.1: PUBCOMP - Publish Complete.
  354. * </a>
  355. *
  356. */
  357. struct mqtt_response_pubcomp {
  358. /** T@brief he published messages packet ID. */
  359. uint16_t packet_id;
  360. };
  361. /**
  362. * @brief An enumeration of subscription acknowledgement return codes.
  363. * @ingroup unpackers
  364. *
  365. * @see <a href="http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Figure_3.26_-">
  366. * MQTT v3.1.1: SUBACK Return Codes.
  367. * </a>
  368. */
  369. enum MQTTSubackReturnCodes {
  370. MQTT_SUBACK_SUCCESS_MAX_QOS_0 = 0u,
  371. MQTT_SUBACK_SUCCESS_MAX_QOS_1 = 1u,
  372. MQTT_SUBACK_SUCCESS_MAX_QOS_2 = 2u,
  373. MQTT_SUBACK_FAILURE = 128u
  374. };
  375. /**
  376. * @brief The response to a subscription request.
  377. * @ingroup unpackers
  378. *
  379. * @see <a href="http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718068">
  380. * MQTT v3.1.1: SUBACK - Subscription Acknowledgement.
  381. * </a>
  382. */
  383. struct mqtt_response_suback {
  384. /** @brief The published messages packet ID. */
  385. uint16_t packet_id;
  386. /**
  387. * Array of return codes corresponding to the requested subscribe topics.
  388. *
  389. * @see MQTTSubackReturnCodes
  390. */
  391. const uint8_t *return_codes;
  392. /** The number of return codes. */
  393. size_t num_return_codes;
  394. };
  395. /**
  396. * @brief The brokers response to a UNSUBSCRIBE request.
  397. * @ingroup unpackers
  398. *
  399. * @see <a href="http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718077">
  400. * MQTT v3.1.1: UNSUBACK - Unsubscribe Acknowledgement.
  401. * </a>
  402. */
  403. struct mqtt_response_unsuback {
  404. /** @brief The published messages packet ID. */
  405. uint16_t packet_id;
  406. };
  407. /**
  408. * @brief The response to a ping request.
  409. * @ingroup unpackers
  410. *
  411. * @note This response contains no members.
  412. *
  413. * @see <a href="http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718086">
  414. * MQTT v3.1.1: PINGRESP - Ping Response.
  415. * </a>
  416. */
  417. //TODO: error: struct has no members [-Werror=pedantic]
  418. //struct mqtt_response_pingresp {};
  419. struct mqtt_response_pingresp {int dummy;};
  420. /**
  421. * @brief A struct used to deserialize/interpret an incoming packet from the broker.
  422. * @ingroup unpackers
  423. */
  424. struct mqtt_response {
  425. /** @brief The mqtt_fixed_header of the deserialized packet. */
  426. struct mqtt_fixed_header fixed_header;
  427. /**
  428. * @brief A union of the possible responses from the broker.
  429. *
  430. * @note The fixed_header contains the control type. This control type corresponds to the
  431. * member of this union that should be accessed. For example if
  432. * fixed_header#control_type == \c MQTT_CONTROL_PUBLISH then
  433. * decoded#publish should be accessed.
  434. */
  435. union {
  436. struct mqtt_response_connack connack;
  437. struct mqtt_response_publish publish;
  438. struct mqtt_response_puback puback;
  439. struct mqtt_response_pubrec pubrec;
  440. struct mqtt_response_pubrel pubrel;
  441. struct mqtt_response_pubcomp pubcomp;
  442. struct mqtt_response_suback suback;
  443. struct mqtt_response_unsuback unsuback;
  444. struct mqtt_response_pingresp pingresp;
  445. } decoded;
  446. };
  447. /**
  448. * @brief Deserialize the contents of \p buf into an mqtt_fixed_header object.
  449. * @ingroup unpackers
  450. *
  451. * @note This function performs complete error checking and a positive return value
  452. * means the entire mqtt_response can be deserialized from \p buf.
  453. *
  454. * @param[out] response the response who's \ref mqtt_response.fixed_header will be initialized.
  455. * @param[in] buf the buffer.
  456. * @param[in] bufsz the total number of bytes in the buffer.
  457. *
  458. * @returns The number of bytes that were consumed, or 0 if the buffer does not contain enough
  459. * bytes to parse the packet, or a negative value if there was a protocol violation.
  460. */
  461. ssize_t mqtt_unpack_fixed_header(struct mqtt_response *response, const uint8_t *buf, size_t bufsz);
  462. /**
  463. * @brief Deserialize a CONNACK response from \p buf.
  464. * @ingroup unpackers
  465. *
  466. * @pre \ref mqtt_unpack_fixed_header must have returned a positive value and the control packet type
  467. * must be \c MQTT_CONTROL_CONNACK.
  468. *
  469. * @param[out] mqtt_response the mqtt_response that will be initialized.
  470. * @param[in] buf the buffer that contains the variable header and payload of the packet. The
  471. * first byte of \p buf should be the first byte of the variable header.
  472. *
  473. * @relates mqtt_response_connack
  474. *
  475. * @returns The number of bytes that were consumed, or 0 if the buffer does not contain enough
  476. * bytes to parse the packet, or a negative value if there was a protocol violation.
  477. */
  478. ssize_t mqtt_unpack_connack_response (struct mqtt_response *mqtt_response, const uint8_t *buf);
  479. /**
  480. * @brief Deserialize a publish response from \p buf.
  481. * @ingroup unpackers
  482. *
  483. * @pre \ref mqtt_unpack_fixed_header must have returned a positive value and the mqtt_response must
  484. * have a control type of \c MQTT_CONTROL_PUBLISH.
  485. *
  486. * @param[out] mqtt_response the response that is initialized from the contents of \p buf.
  487. * @param[in] buf the buffer with the incoming data.
  488. *
  489. * @relates mqtt_response_publish
  490. *
  491. * @returns The number of bytes that were consumed, or 0 if the buffer does not contain enough
  492. * bytes to parse the packet, or a negative value if there was a protocol violation.
  493. */
  494. ssize_t mqtt_unpack_publish_response (struct mqtt_response *mqtt_response, const uint8_t *buf);
  495. /**
  496. * @brief Deserialize a PUBACK/PUBREC/PUBREL/PUBCOMP packet from \p buf.
  497. * @ingroup unpackers
  498. *
  499. * @pre \ref mqtt_unpack_fixed_header must have returned a positive value and the mqtt_response must
  500. * have a control type of \c MQTT_CONTROL_PUBACK, \c MQTT_CONTROL_PUBREC, \c MQTT_CONTROL_PUBREL
  501. * or \c MQTT_CONTROL_PUBCOMP.
  502. *
  503. * @param[out] mqtt_response the response that is initialized from the contents of \p buf.
  504. * @param[in] buf the buffer with the incoming data.
  505. *
  506. * @relates mqtt_response_puback mqtt_response_pubrec mqtt_response_pubrel mqtt_response_pubcomp
  507. *
  508. * @returns The number of bytes that were consumed, or 0 if the buffer does not contain enough
  509. * bytes to parse the packet, or a negative value if there was a protocol violation.
  510. */
  511. ssize_t mqtt_unpack_pubxxx_response(struct mqtt_response *mqtt_response, const uint8_t *buf);
  512. /**
  513. * @brief Deserialize a SUBACK packet from \p buf.
  514. * @ingroup unpacker
  515. *
  516. * @pre \ref mqtt_unpack_fixed_header must have returned a positive value and the mqtt_response must
  517. * have a control type of \c MQTT_CONTROL_SUBACK.
  518. *
  519. * @param[out] mqtt_response the response that is initialized from the contents of \p buf.
  520. * @param[in] buf the buffer with the incoming data.
  521. *
  522. * @relates mqtt_response_suback
  523. *
  524. * @returns The number of bytes that were consumed, or 0 if the buffer does not contain enough
  525. * bytes to parse the packet, or a negative value if there was a protocol violation.
  526. */
  527. ssize_t mqtt_unpack_suback_response(struct mqtt_response *mqtt_response, const uint8_t *buf);
  528. /**
  529. * @brief Deserialize an UNSUBACK packet from \p buf.
  530. * @ingroup unpacker
  531. *
  532. * @pre \ref mqtt_unpack_fixed_header must have returned a positive value and the mqtt_response must
  533. * have a control type of \c MQTT_CONTROL_UNSUBACK.
  534. *
  535. * @param[out] mqtt_response the response that is initialized from the contents of \p buf.
  536. * @param[in] buf the buffer with the incoming data.
  537. *
  538. * @relates mqtt_response_unsuback
  539. *
  540. * @returns The number of bytes that were consumed, or 0 if the buffer does not contain enough
  541. * bytes to parse the packet, or a negative value if there was a protocol violation.
  542. */
  543. ssize_t mqtt_unpack_unsuback_response(struct mqtt_response *mqtt_response, const uint8_t *buf);
  544. /**
  545. * @brief Deserialize a packet from the broker.
  546. * @ingroup unpackers
  547. *
  548. * @param[out] response the mqtt_response that will be initialize from \p buf.
  549. * @param[in] buf the incoming data buffer.
  550. * @param[in] bufsz the number of bytes available in the buffer.
  551. *
  552. * @relates mqtt_response
  553. *
  554. * @returns The number of bytes consumed on success, zero \p buf does not contain enough bytes
  555. * to deserialize the packet, a negative value if a protocol violation was encountered.
  556. */
  557. ssize_t mqtt_unpack_response(struct mqtt_response* response, const uint8_t *buf, size_t bufsz);
  558. /* REQUESTS */
  559. /**
  560. * @brief Serialize an mqtt_fixed_header and write it to \p buf.
  561. * @ingroup packers
  562. *
  563. * @note This function performs complete error checking and a positive return value
  564. * guarantees the entire packet will fit into the given buffer.
  565. *
  566. * @param[out] buf the buffer to write to.
  567. * @param[in] bufsz the maximum number of bytes that can be put in to \p buf.
  568. * @param[in] fixed_header the fixed header that will be serialized.
  569. *
  570. * @returns The number of bytes written to \p buf, or 0 if \p buf is too small, or a
  571. * negative value if there was a protocol violation.
  572. */
  573. ssize_t mqtt_pack_fixed_header(uint8_t *buf, size_t bufsz, const struct mqtt_fixed_header *fixed_header);
  574. /**
  575. * @brief An enumeration of CONNECT packet flags.
  576. * @ingroup packers
  577. *
  578. * @see <a href="http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718030">
  579. * MQTT v3.1.1: CONNECT Variable Header.
  580. * </a>
  581. */
  582. enum MQTTConnectFlags {
  583. MQTT_CONNECT_RESERVED = 1u,
  584. MQTT_CONNECT_CLEAN_SESSION = 2u,
  585. MQTT_CONNECT_WILL_FLAG = 4u,
  586. MQTT_CONNECT_WILL_QOS_0 = (0u & 0x03) << 3,
  587. MQTT_CONNECT_WILL_QOS_1 = (1u & 0x03) << 3,
  588. MQTT_CONNECT_WILL_QOS_2 = (2u & 0x03) << 3,
  589. MQTT_CONNECT_WILL_RETAIN = 32u,
  590. MQTT_CONNECT_PASSWORD = 64u,
  591. MQTT_CONNECT_USER_NAME = 128u,
  592. };
  593. /**
  594. * @brief Serialize a connection request into a buffer.
  595. * @ingroup packers
  596. *
  597. * @param[out] buf the buffer to pack the connection request packet into.
  598. * @param[in] bufsz the number of bytes left in \p buf.
  599. * @param[in] client_id the ID that identifies the local client. \p client_id is a required
  600. * parameter.
  601. * @param[in] will_topic the topic under which the local client's will message will be published.
  602. * Set to \c NULL for no will message. If \p will_topic is not \c NULL a
  603. * \p will_message must also be provided.
  604. * @param[in] will_message the will message to be published upon a unsuccessful disconnection of
  605. * the local client. Set to \c NULL if \p will_topic is \c NULL.
  606. * \p will_message must \em not be \c NULL if \p will_topic is not
  607. * \c NULL.
  608. * @param[in] will_message_size The size of \p will_message in bytes.
  609. * @param[in] user_name the username to be used to connect to the broker with. Set to \c NULL if
  610. * no username is required.
  611. * @param[in] password the password to be used to connect to the broker with. Set to \c NULL if
  612. * no password is required.
  613. * @param[in] connect_flags additional MQTTConnectFlags to be set. The only flags that need to be
  614. * set manually are \c MQTT_CONNECT_CLEAN_SESSION,
  615. * \c MQTT_CONNECT_WILL_QOS_X (for \c X &isin; {0, 1, 2}), and
  616. * \c MQTT_CONNECT_WILL_RETAIN. Set to 0 if no additional flags are
  617. * required.
  618. * @param[in] keep_alive the keep alive time in seconds. It is the responsibility of the clinet
  619. * to ensure packets are sent to the server \em {at least} this frequently.
  620. *
  621. * @note If there is a \p will_topic and no additional \p connect_flags are given, then by
  622. * default \p will_message will be published at QoS level 0.
  623. *
  624. * @see <a href="http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718028">
  625. * MQTT v3.1.1: CONNECT - Client Requests a Connection to a Server.
  626. * </a>
  627. *
  628. * @returns The number of bytes put into \p buf, 0 if \p buf is too small to fit the CONNECT
  629. * packet, a negative value if there was a protocol violation.
  630. */
  631. ssize_t mqtt_pack_connection_request(uint8_t* buf, size_t bufsz,
  632. const char* client_id,
  633. const char* will_topic,
  634. const void* will_message,
  635. size_t will_message_size,
  636. const char* user_name,
  637. const char* password,
  638. uint8_t connect_flags,
  639. uint16_t keep_alive);
  640. /**
  641. * @brief An enumeration of the PUBLISH flags.
  642. * @ingroup packers
  643. *
  644. * @see <a href="http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718037">
  645. * MQTT v3.1.1: PUBLISH - Publish Message.
  646. * </a>
  647. */
  648. enum MQTTPublishFlags {
  649. MQTT_PUBLISH_DUP = 8u,
  650. MQTT_PUBLISH_QOS_0 = ((0u << 1) & 0x06),
  651. MQTT_PUBLISH_QOS_1 = ((1u << 1) & 0x06),
  652. MQTT_PUBLISH_QOS_2 = ((2u << 1) & 0x06),
  653. MQTT_PUBLISH_QOS_MASK = ((3u << 1) & 0x06),
  654. MQTT_PUBLISH_RETAIN = 0x01
  655. };
  656. /**
  657. * @brief Serialize a PUBLISH request and put it in \p buf.
  658. * @ingroup packers
  659. *
  660. * @param[out] buf the buffer to put the PUBLISH packet in.
  661. * @param[in] bufsz the maximum number of bytes that can be put into \p buf.
  662. * @param[in] topic_name the topic to publish \p application_message under.
  663. * @param[in] packet_id this packets packet ID.
  664. * @param[in] application_message the application message to be published.
  665. * @param[in] application_message_size the size of \p application_message in bytes.
  666. * @param[in] publish_flags The flags to publish \p application_message with. These include
  667. * the \c MQTT_PUBLISH_DUP flag, \c MQTT_PUBLISH_QOS_X (\c X &isin;
  668. * {0, 1, 2}), and \c MQTT_PUBLISH_RETAIN flag.
  669. *
  670. * @note The default QoS is level 0.
  671. *
  672. * @see <a href="http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718037">
  673. * MQTT v3.1.1: PUBLISH - Publish Message.
  674. * </a>
  675. *
  676. * @returns The number of bytes put into \p buf, 0 if \p buf is too small to fit the PUBLISH
  677. * packet, a negative value if there was a protocol violation.
  678. */
  679. ssize_t mqtt_pack_publish_request(uint8_t *buf, size_t bufsz,
  680. const char* topic_name,
  681. uint16_t packet_id,
  682. void* application_message,
  683. size_t application_message_size,
  684. uint8_t publish_flags);
  685. /**
  686. * @brief Serialize a PUBACK, PUBREC, PUBREL, or PUBCOMP packet and put it in \p buf.
  687. * @ingroup packers
  688. *
  689. * @param[out] buf the buffer to put the PUBXXX packet in.
  690. * @param[in] bufsz the maximum number of bytes that can be put into \p buf.
  691. * @param[in] control_type the type of packet. Must be one of: \c MQTT_CONTROL_PUBACK,
  692. * \c MQTT_CONTROL_PUBREC, \c MQTT_CONTROL_PUBREL,
  693. * or \c MQTT_CONTROL_PUBCOMP.
  694. * @param[in] packet_id the packet ID of the packet being acknowledged.
  695. *
  696. *
  697. * @see <a href="http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718043">
  698. * MQTT v3.1.1: PUBACK - Publish Acknowledgement.
  699. * </a>
  700. * @see <a href="http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718048">
  701. * MQTT v3.1.1: PUBREC - Publish Received.
  702. * </a>
  703. * @see <a href="http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718053">
  704. * MQTT v3.1.1: PUBREL - Publish Released.
  705. * </a>
  706. * @see <a href="http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718058">
  707. * MQTT v3.1.1: PUBCOMP - Publish Complete.
  708. * </a>
  709. *
  710. * @returns The number of bytes put into \p buf, 0 if \p buf is too small to fit the PUBXXX
  711. * packet, a negative value if there was a protocol violation.
  712. */
  713. ssize_t mqtt_pack_pubxxx_request(uint8_t *buf, size_t bufsz,
  714. enum MQTTControlPacketType control_type,
  715. uint16_t packet_id);
  716. /**
  717. * @brief The maximum number topics that can be subscribed to in a single call to
  718. * mqtt_pack_subscribe_request.
  719. * @ingroup packers
  720. *
  721. * @see mqtt_pack_subscribe_request
  722. */
  723. #define MQTT_SUBSCRIBE_REQUEST_MAX_NUM_TOPICS 8
  724. /**
  725. * @brief Serialize a SUBSCRIBE packet and put it in \p buf.
  726. * @ingroup packers
  727. *
  728. * @param[out] buf the buffer to put the SUBSCRIBE packet in.
  729. * @param[in] bufsz the maximum number of bytes that can be put into \p buf.
  730. * @param[in] packet_id the packet ID to be used.
  731. * @param[in] ... \c NULL terminated list of (\c {const char *topic_name}, \c {int max_qos_level})
  732. * pairs.
  733. *
  734. * @note The variadic arguments, \p ..., \em must be followed by a \c NULL. For example:
  735. * @code
  736. * ssize_t n = mqtt_pack_subscribe_request(buf, bufsz, 1234, "topic_1", 0, "topic_2", 2, NULL);
  737. * @endcode
  738. *
  739. * @see <a href="http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718063">
  740. * MQTT v3.1.1: SUBSCRIBE - Subscribe to Topics.
  741. * </a>
  742. *
  743. * @returns The number of bytes put into \p buf, 0 if \p buf is too small to fit the SUBSCRIBE
  744. * packet, a negative value if there was a protocol violation.
  745. */
  746. ssize_t mqtt_pack_subscribe_request(uint8_t *buf, size_t bufsz,
  747. uint16_t packet_id,
  748. ...); /* null terminated */
  749. /**
  750. * @brief The maximum number topics that can be subscribed to in a single call to
  751. * mqtt_pack_unsubscribe_request.
  752. * @ingroup packers
  753. *
  754. * @see mqtt_pack_unsubscribe_request
  755. */
  756. #define MQTT_UNSUBSCRIBE_REQUEST_MAX_NUM_TOPICS 8
  757. /**
  758. * @brief Serialize a UNSUBSCRIBE packet and put it in \p buf.
  759. * @ingroup packers
  760. *
  761. * @param[out] buf the buffer to put the UNSUBSCRIBE packet in.
  762. * @param[in] bufsz the maximum number of bytes that can be put into \p buf.
  763. * @param[in] packet_id the packet ID to be used.
  764. * @param[in] ... \c NULL terminated list of \c {const char *topic_name}'s to unsubscribe from.
  765. *
  766. * @note The variadic arguments, \p ..., \em must be followed by a \c NULL. For example:
  767. * @code
  768. * ssize_t n = mqtt_pack_unsubscribe_request(buf, bufsz, 4321, "topic_1", "topic_2", NULL);
  769. * @endcode
  770. *
  771. * @see <a href="http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718072">
  772. * MQTT v3.1.1: UNSUBSCRIBE - Unsubscribe from Topics.
  773. * </a>
  774. *
  775. * @returns The number of bytes put into \p buf, 0 if \p buf is too small to fit the UNSUBSCRIBE
  776. * packet, a negative value if there was a protocol violation.
  777. */
  778. ssize_t mqtt_pack_unsubscribe_request(uint8_t *buf, size_t bufsz,
  779. uint16_t packet_id,
  780. ...); /* null terminated */
  781. /**
  782. * @brief Serialize a PINGREQ and put it into \p buf.
  783. * @ingroup packers
  784. *
  785. * @param[out] buf the buffer to put the PINGREQ packet in.
  786. * @param[in] bufsz the maximum number of bytes that can be put into \p buf.
  787. *
  788. * @see <a href="http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718081">
  789. * MQTT v3.1.1: PINGREQ - Ping Request.
  790. * </a>
  791. *
  792. * @returns The number of bytes put into \p buf, 0 if \p buf is too small to fit the PINGREQ
  793. * packet, a negative value if there was a protocol violation.
  794. */
  795. ssize_t mqtt_pack_ping_request(uint8_t *buf, size_t bufsz);
  796. /**
  797. * @brief Serialize a DISCONNECT and put it into \p buf.
  798. * @ingroup packers
  799. *
  800. * @param[out] buf the buffer to put the DISCONNECT packet in.
  801. * @param[in] bufsz the maximum number of bytes that can be put into \p buf.
  802. *
  803. * @see <a href="http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718090">
  804. * MQTT v3.1.1: DISCONNECT - Disconnect Notification.
  805. * </a>
  806. *
  807. * @returns The number of bytes put into \p buf, 0 if \p buf is too small to fit the DISCONNECT
  808. * packet, a negative value if there was a protocol violation.
  809. */
  810. ssize_t mqtt_pack_disconnect(uint8_t *buf, size_t bufsz);
  811. /**
  812. * @brief An enumeration of queued message states.
  813. * @ingroup details
  814. */
  815. enum MQTTQueuedMessageState {
  816. MQTT_QUEUED_UNSENT,
  817. MQTT_QUEUED_AWAITING_ACK,
  818. MQTT_QUEUED_COMPLETE
  819. };
  820. /**
  821. * @brief A message in a mqtt_message_queue.
  822. * @ingroup details
  823. */
  824. struct mqtt_queued_message {
  825. /** @brief A pointer to the start of the message. */
  826. uint8_t *start;
  827. /** @brief The number of bytes in the message. */
  828. size_t size;
  829. /** @brief The state of the message. */
  830. enum MQTTQueuedMessageState state;
  831. /**
  832. * @brief The time at which the message was sent..
  833. *
  834. * @note A timeout will only occur if the message is in
  835. * the MQTT_QUEUED_AWAITING_ACK \c state.
  836. */
  837. mqtt_pal_time_t time_sent;
  838. /**
  839. * @brief The control type of the message.
  840. */
  841. enum MQTTControlPacketType control_type;
  842. /**
  843. * @brief The packet id of the message.
  844. *
  845. * @note This field is only used if the associate \c control_type has a
  846. * \c packet_id field.
  847. */
  848. uint16_t packet_id;
  849. };
  850. /**
  851. * @brief A message queue.
  852. * @ingroup details
  853. *
  854. * @note This struct is used internally to manage sending messages.
  855. * @note The only members the user should use are \c curr and \c curr_sz.
  856. */
  857. struct mqtt_message_queue {
  858. /**
  859. * @brief The start of the message queue's memory block.
  860. *
  861. * @warning This member should \em not be manually changed.
  862. */
  863. void *mem_start;
  864. /** @brief The end of the message queue's memory block. */
  865. void *mem_end;
  866. /**
  867. * @brief A pointer to the position in the buffer you can pack bytes at.
  868. *
  869. * @note Immediately after packing bytes at \c curr you \em must call
  870. * mqtt_mq_register.
  871. */
  872. uint8_t *curr;
  873. /**
  874. * @brief The number of bytes that can be written to \c curr.
  875. *
  876. * @note curr_sz will decrease by more than the number of bytes you write to
  877. * \c curr. This is because the mqtt_queued_message structs share the
  878. * same memory (and thus, a mqtt_queued_message must be allocated in
  879. * the message queue's memory whenever a new message is registered).
  880. */
  881. size_t curr_sz;
  882. /**
  883. * @brief The tail of the array of mqtt_queued_messages's.
  884. *
  885. * @note This member should not be used manually.
  886. */
  887. struct mqtt_queued_message *queue_tail;
  888. };
  889. /**
  890. * @brief Initialize a message queue.
  891. * @ingroup details
  892. *
  893. * @param[out] mq The message queue to initialize.
  894. * @param[in] buf The buffer for this message queue.
  895. * @param[in] bufsz The number of bytes in the buffer.
  896. *
  897. * @relates mqtt_message_queue
  898. */
  899. void mqtt_mq_init(struct mqtt_message_queue *mq, void *buf, size_t bufsz);
  900. /**
  901. * @brief Clear as many messages from the front of the queue as possible.
  902. * @ingroup details
  903. *
  904. * @note Calls to this function are the \em only way to remove messages from the queue.
  905. *
  906. * @param mq The message queue.
  907. *
  908. * @relates mqtt_message_queue
  909. */
  910. void mqtt_mq_clean(struct mqtt_message_queue *mq);
  911. /**
  912. * @brief Register a message that was just added to the buffer.
  913. * @ingroup details
  914. *
  915. * @note This function should be called immediately following a call to a packer function
  916. * that returned a positive value. The positive value (number of bytes packed) should
  917. * be passed to this function.
  918. *
  919. * @param mq The message queue.
  920. * @param[in] nbytes The number of bytes that were just packed.
  921. *
  922. * @note This function will step mqtt_message_queue::curr and update mqtt_message_queue::curr_sz.
  923. * @relates mqtt_message_queue
  924. *
  925. * @returns The newly added struct mqtt_queued_message.
  926. */
  927. struct mqtt_queued_message* mqtt_mq_register(struct mqtt_message_queue *mq, size_t nbytes);
  928. /**
  929. * @brief Find a message in the message queue.
  930. * @ingroup details
  931. *
  932. * @param mq The message queue.
  933. * @param[in] control_type The control type of the message you want to find.
  934. * @param[in] packet_id The packet ID of the message you want to find. Set to \c NULL if you
  935. * don't want to specify a packet ID.
  936. *
  937. * @relates mqtt_message_queue
  938. * @returns The found message. \c NULL if the message was not found.
  939. */
  940. struct mqtt_queued_message* mqtt_mq_find(struct mqtt_message_queue *mq, enum MQTTControlPacketType control_type, uint16_t *packet_id);
  941. /**
  942. * @brief Returns the mqtt_queued_message at \p index.
  943. * @ingroup details
  944. *
  945. * @param mq_ptr A pointer to the message queue.
  946. * @param index The index of the message.
  947. *
  948. * @returns The mqtt_queued_message at \p index.
  949. */
  950. #define mqtt_mq_get(mq_ptr, index) (((struct mqtt_queued_message*) ((mq_ptr)->mem_end)) - 1 - index)
  951. /**
  952. * @brief Returns the number of messages in the message queue, \p mq_ptr.
  953. * @ingroup details
  954. */
  955. #define mqtt_mq_length(mq_ptr) (((struct mqtt_queued_message*) ((mq_ptr)->mem_end)) - (mq_ptr)->queue_tail)
  956. /**
  957. * @brief Used internally to recalculate the \c curr_sz.
  958. * @ingroup details
  959. */
  960. #define mqtt_mq_currsz(mq_ptr) (mq_ptr->curr >= (uint8_t*) ((mq_ptr)->queue_tail - 1)) ? 0 : ((uint8_t*) ((mq_ptr)->queue_tail - 1)) - (mq_ptr)->curr
  961. /* CLIENT */
  962. /**
  963. * @brief An MQTT client.
  964. * @ingroup details
  965. *
  966. * @note All members can be manipulated via the related functions.
  967. */
  968. struct mqtt_client {
  969. /** @brief The socket connecting to the MQTT broker. */
  970. mqtt_pal_socket_handle socketfd;
  971. /** @brief The LFSR state used to generate packet ID's. */
  972. uint16_t pid_lfsr;
  973. /** @brief The keep-alive time in seconds. */
  974. uint16_t keep_alive;
  975. /**
  976. * @brief A counter counting pings that have been sent to keep the connection alive.
  977. * @see keep_alive
  978. */
  979. int number_of_keep_alives;
  980. /**
  981. * @brief The timestamp of the last message sent to the buffer.
  982. *
  983. * This is used to detect the need for keep-alive pings.
  984. *
  985. * @see keep_alive
  986. */
  987. mqtt_pal_time_t time_of_last_send;
  988. /**
  989. * @brief The error state of the client.
  990. *
  991. * error should be MQTT_OK for the entirety of the connection.
  992. *
  993. * @note The error state will be MQTT_ERROR_CONNECT_NOT_CALLED until
  994. * you call mqtt_connect.
  995. */
  996. enum MQTTErrors error;
  997. /**
  998. * @brief The timeout period in seconds.
  999. *
  1000. * If the broker doesn't return an ACK within response_timeout seconds a timeout
  1001. * will occur and the message will be retransmitted.
  1002. *
  1003. * @note The default value is 30 [seconds] but you can change it at any time.
  1004. */
  1005. int response_timeout;
  1006. /** @brief A counter counting the number of timeouts that have occurred. */
  1007. int number_of_timeouts;
  1008. /**
  1009. * @brief Approximately much time it has typically taken to receive responses from the
  1010. * broker.
  1011. *
  1012. * @note This is tracked using a exponential-averaging.
  1013. */
  1014. double typical_response_time;
  1015. /**
  1016. * @brief The callback that is called whenever a publish is received from the broker.
  1017. *
  1018. * Any topics that you have subscribed to will be returned from the broker as
  1019. * mqtt_response_publish messages. All the publishes received from the broker will
  1020. * be passed to this function.
  1021. *
  1022. * @note A pointer to publish_response_callback_state is always passed to the callback.
  1023. * Use publish_response_callback_state to keep track of any state information you
  1024. * need.
  1025. */
  1026. void (*publish_response_callback)(void** state, struct mqtt_response_publish *publish);
  1027. /**
  1028. * @brief A pointer to any publish_response_callback state information you need.
  1029. *
  1030. * @note A pointer to this pointer will always be publish_response_callback upon
  1031. * receiving a publish message from the broker.
  1032. */
  1033. void* publish_response_callback_state;
  1034. /**
  1035. * @brief A user-specified callback, triggered on each \ref mqtt_sync, allowing
  1036. * the user to perform state inspections (and custom socket error detection)
  1037. * on the client.
  1038. *
  1039. * This callback is triggered on each call to \ref mqtt_sync. If it returns MQTT_OK
  1040. * then \ref mqtt_sync will continue normally (performing reads and writes). If it
  1041. * returns an error then \ref mqtt_sync will not call reads and writes.
  1042. *
  1043. * This callback can be used to perform custom error detection, namely platform
  1044. * specific socket error detection, and force the client into an error state.
  1045. *
  1046. * This member is always initialized to NULL but it can be manually set at any
  1047. * time.
  1048. */
  1049. enum MQTTErrors (*inspector_callback)(struct mqtt_client*);
  1050. /**
  1051. * @brief A callback that is called whenever the client is in an error state.
  1052. *
  1053. * This callback is responsible for: application level error handling, closing
  1054. * previous sockets, and reestabilishing the connection to the broker and
  1055. * session configurations (i.e. subscriptions).
  1056. */
  1057. void (*reconnect_callback)(struct mqtt_client*, void**);
  1058. /**
  1059. * @brief A pointer to some state. A pointer to this member is passed to
  1060. * \ref mqtt_client.reconnect_callback.
  1061. */
  1062. void* reconnect_state;
  1063. /**
  1064. * @brief The buffer where ingress data is temporarily stored.
  1065. */
  1066. struct {
  1067. /** @brief The start of the receive buffer's memory. */
  1068. uint8_t *mem_start;
  1069. /** @brief The size of the receive buffer's memory. */
  1070. size_t mem_size;
  1071. /** @brief A pointer to the next writtable location in the receive buffer. */
  1072. uint8_t *curr;
  1073. /** @brief The number of bytes that are still writable at curr. */
  1074. size_t curr_sz;
  1075. } recv_buffer;
  1076. /**
  1077. * @brief A variable passed to support thread-safety.
  1078. *
  1079. * A pointer to this variable is passed to \c MQTT_PAL_MUTEX_LOCK, and
  1080. * \c MQTT_PAL_MUTEX_UNLOCK.
  1081. */
  1082. mqtt_pal_mutex_t mutex;
  1083. /** @brief The sending message queue. */
  1084. struct mqtt_message_queue mq;
  1085. };
  1086. /**
  1087. * @brief Generate a new next packet ID.
  1088. * @ingroup details
  1089. *
  1090. * Packet ID's are generated using a max-length LFSR.
  1091. *
  1092. * @param client The MQTT client.
  1093. *
  1094. * @returns The new packet ID that should be used.
  1095. */
  1096. uint16_t __mqtt_next_pid(struct mqtt_client *client);
  1097. /**
  1098. * @brief Handles egress client traffic.
  1099. * @ingroup details
  1100. *
  1101. * @param client The MQTT client.
  1102. *
  1103. * @returns MQTT_OK upon success, an \ref MQTTErrors otherwise.
  1104. */
  1105. ssize_t __mqtt_send(struct mqtt_client *client);
  1106. /**
  1107. * @brief Handles ingress client traffic.
  1108. * @ingroup details
  1109. *
  1110. * @param client The MQTT client.
  1111. *
  1112. * @returns MQTT_OK upon success, an \ref MQTTErrors otherwise.
  1113. */
  1114. ssize_t __mqtt_recv(struct mqtt_client *client);
  1115. /**
  1116. * @brief Function that does the actual sending and receiving of
  1117. * traffic from the network.
  1118. * @ingroup api
  1119. *
  1120. * All the other functions in the @ref api simply stage messages for
  1121. * being sent to the broker. This function does the actual sending of
  1122. * those messages. Additionally this function receives traffic (responses and
  1123. * acknowledgements) from the broker and responds to that traffic accordingly.
  1124. * Lastly this function also calls the \c publish_response_callback when
  1125. * any \c MQTT_CONTROL_PUBLISH messages are received.
  1126. *
  1127. * @pre mqtt_init must have been called.
  1128. *
  1129. * @param[in,out] client The MQTT client.
  1130. *
  1131. * @attention It is the responsibility of the application programmer to
  1132. * call this function periodically. All functions in the @ref api are
  1133. * thread-safe so it is perfectly reasonable to have a thread dedicated
  1134. * to calling this function every 200 ms or so. MQTT-C can be used in single
  1135. * threaded application though by simply calling this functino periodically
  1136. * inside your main thread. See @ref simple_publisher.c and @ref simple_subscriber.c
  1137. * for examples (specifically the \c client_refresher functions).
  1138. *
  1139. * @returns MQTT_OK upon success, an \ref MQTTErrors otherwise.
  1140. */
  1141. enum MQTTErrors mqtt_sync(struct mqtt_client *client);
  1142. /**
  1143. * @brief Initializes an MQTT client.
  1144. * @ingroup api
  1145. *
  1146. * This function \em must be called before any other API function calls.
  1147. *
  1148. * @pre None.
  1149. *
  1150. * @param[out] client The MQTT client.
  1151. * @param[in] sockfd The socket file descriptor (or equivalent socket handle, e.g. BIO pointer
  1152. * for OpenSSL sockets) connected to the MQTT broker.
  1153. * @param[in] sendbuf A buffer that will be used for sending messages to the broker.
  1154. * @param[in] sendbufsz The size of \p sendbuf in bytes.
  1155. * @param[in] recvbuf A buffer that will be used for receiving messages from the broker.
  1156. * @param[in] recvbufsz The size of \p recvbuf in bytes.
  1157. * @param[in] publish_response_callback The callback to call whenever application messages
  1158. * are received from the broker.
  1159. *
  1160. * @post mqtt_connect must be called.
  1161. *
  1162. * @note \p sockfd is a non-blocking TCP connection.
  1163. * @note If \p sendbuf fills up completely during runtime a \c MQTT_ERROR_SEND_BUFFER_IS_FULL
  1164. * error will be set. Similarly if \p recvbuf is ever to small to receive a message from
  1165. * the broker an MQTT_ERROR_RECV_BUFFER_TOO_SMALL error will be set.
  1166. * @note A pointer to \ref mqtt_client.publish_response_callback_state is always passed as the
  1167. * \c state argument to \p publish_response_callback. Note that the second argument is
  1168. * the mqtt_response_publish that was received from the broker.
  1169. *
  1170. * @attention Only initialize an MQTT client once (i.e. don't call \ref mqtt_init or
  1171. * \ref mqtt_init_reconnect more than once per client).
  1172. *
  1173. * @returns \c MQTT_OK upon success, an \ref MQTTErrors otherwise.
  1174. */
  1175. enum MQTTErrors mqtt_init(struct mqtt_client *client,
  1176. mqtt_pal_socket_handle sockfd,
  1177. uint8_t *sendbuf, size_t sendbufsz,
  1178. uint8_t *recvbuf, size_t recvbufsz,
  1179. void (*publish_response_callback)(void** state, struct mqtt_response_publish *publish));
  1180. /**
  1181. * @brief Initializes an MQTT client and enables automatic reconnections.
  1182. * @ingroup api
  1183. *
  1184. * An alternative to \ref mqtt_init that allows the client to automatically reconnect to the
  1185. * broker after an error occurs (e.g. socket error or internal buffer overflows).
  1186. *
  1187. * This is accomplished by calling the \p reconnect_callback whenever the client enters an error
  1188. * state. The job of the \p reconnect_callback is to: (1) perform error handling/logging,
  1189. * (2) clean up the old connection (i.e. close client->socketfd), (3) \ref mqtt_reinit the
  1190. * client, and (4) reconfigure the MQTT session by calling \ref mqtt_connect followed by other
  1191. * API calls such as \ref mqtt_subscribe.
  1192. *
  1193. * The first argument to the \p reconnect_callback is the client (which will be in an error
  1194. * state) and the second argument is a pointer to a void pointer where you can store some state
  1195. * information. Internally, MQTT-C calls the reconnect callback like so:
  1196. *
  1197. * \code
  1198. * client->reconnect_callback(client, &client->reconnect_state)
  1199. * \endcode
  1200. *
  1201. * Note that the \p reconnect_callback is also called to setup the initial session. After
  1202. * calling \ref mqtt_init_reconnect the client will be in the error state
  1203. * \c MQTT_ERROR_INITIAL_RECONNECT.
  1204. *
  1205. * @pre None.
  1206. *
  1207. * @param[in,out] client The MQTT client that will be initialized.
  1208. * @param[in] reconnect_callback The callback that will be called to connect/reconnect the
  1209. * client to the broker and perform application level error handling.
  1210. * @param[in] reconnect_state A pointer to some state data for your \p reconnect_callback.
  1211. * If your \p reconnect_callback does not require any state information set this
  1212. * to NULL. A pointer to the memory address where the client stores a copy of this
  1213. * pointer is passed as the second argumnet to \p reconnect_callback.
  1214. * @param[in] publish_response_callback The callback to call whenever application messages
  1215. * are received from the broker.
  1216. *
  1217. * @post Call \p reconnect_callback yourself, or call \ref mqtt_sync
  1218. * (which will trigger the call to \p reconnect_callback).
  1219. *
  1220. * @attention Only initialize an MQTT client once (i.e. don't call \ref mqtt_init or
  1221. * \ref mqtt_init_reconnect more than once per client).
  1222. *
  1223. */
  1224. void mqtt_init_reconnect(struct mqtt_client *client,
  1225. void (*reconnect_callback)(struct mqtt_client *client, void** state),
  1226. void *reconnect_state,
  1227. void (*publish_response_callback)(void** state, struct mqtt_response_publish *publish));
  1228. /**
  1229. * @brief Safely assign/reassign a socket and buffers to an new/existing client.
  1230. * @ingroup api
  1231. *
  1232. * This function also clears the \p client error state. Upon exiting this function
  1233. * \c client->error will be \c MQTT_ERROR_CONNECT_NOT_CALLED (which will be cleared)
  1234. * as soon as \ref mqtt_connect is called.
  1235. *
  1236. * @pre This function must be called BEFORE \ref mqtt_connect.
  1237. *
  1238. * @param[in,out] client The MQTT client.
  1239. * @param[in] socketfd The new socket connected to the broker.
  1240. * @param[in] sendbuf The buffer that will be used to buffer egress traffic to the broker.
  1241. * @param[in] sendbufsz The size of \p sendbuf in bytes.
  1242. * @param[in] recvbuf The buffer that will be used to buffer ingress traffic from the broker.
  1243. * @param[in] recvbufsz The size of \p recvbuf in bytes.
  1244. *
  1245. * @post Call \ref mqtt_connect.
  1246. *
  1247. * @attention This function should be used in conjunction with clients that have been
  1248. * initialzed with \ref mqtt_init_reconnect.
  1249. */
  1250. void mqtt_reinit(struct mqtt_client* client,
  1251. mqtt_pal_socket_handle socketfd,
  1252. uint8_t *sendbuf, size_t sendbufsz,
  1253. uint8_t *recvbuf, size_t recvbufsz);
  1254. /**
  1255. * @brief Establishes a session with the MQTT broker.
  1256. * @ingroup api
  1257. *
  1258. * @pre mqtt_init must have been called.
  1259. *
  1260. * @param[in,out] client The MQTT client.
  1261. * @param[in] client_id The unique name identifying the client.
  1262. * @param[in] will_topic The topic name of client's \p will_message. If no will message is
  1263. * desired set to \c NULL.
  1264. * @param[in] will_message The application message (data) to be published in the event the
  1265. * client ungracefully disconnects. Set to \c NULL if \p will_topic is \c NULL.
  1266. * @param[in] will_message_size The size of \p will_message in bytes.
  1267. * @param[in] user_name The username to use when establishing the session with the MQTT broker.
  1268. * Set to \c NULL if a username is not required.
  1269. * @param[in] password The password to use when establishing the session with the MQTT broker.
  1270. * Set to \c NULL if a password is not required.
  1271. * @param[in] connect_flags Additional \ref MQTTConnectFlags to use when establishing the connection.
  1272. * These flags are for forcing the session to start clean,
  1273. * \c MQTT_CONNECT_CLEAN_SESSION, the QOS level to publish the \p will_message with
  1274. * (provided \c will_message != \c NULL), MQTT_CONNECT_WILL_QOS_[0,1,2], and whether
  1275. * or not the broker should retain the \c will_message, MQTT_CONNECT_WILL_RETAIN.
  1276. * @param[in] keep_alive The keep-alive time in seconds. A reasonable value for this is 400 [seconds].
  1277. *
  1278. * @returns \c MQTT_OK upon success, an \ref MQTTErrors otherwise.
  1279. */
  1280. enum MQTTErrors mqtt_connect(struct mqtt_client *client,
  1281. const char* client_id,
  1282. const char* will_topic,
  1283. const void* will_message,
  1284. size_t will_message_size,
  1285. const char* user_name,
  1286. const char* password,
  1287. uint8_t connect_flags,
  1288. uint16_t keep_alive);
  1289. /*
  1290. todo: will_message should be a void*
  1291. */
  1292. /**
  1293. * @brief Publish an application message.
  1294. * @ingroup api
  1295. *
  1296. * Publishes an application message to the MQTT broker.
  1297. *
  1298. * @pre mqtt_connect must have been called.
  1299. *
  1300. * @param[in,out] client The MQTT client.
  1301. * @param[in] topic_name The name of the topic.
  1302. * @param[in] application_message The data to be published.
  1303. * @param[in] application_message_size The size of \p application_message in bytes.
  1304. * @param[in] publish_flags \ref MQTTPublishFlags to be used, namely the QOS level to
  1305. * publish at (MQTT_PUBLISH_QOS_[0,1,2]) or whether or not the broker should
  1306. * retain the publish (MQTT_PUBLISH_RETAIN).
  1307. *
  1308. * @returns \c MQTT_OK upon success, an \ref MQTTErrors otherwise.
  1309. */
  1310. enum MQTTErrors mqtt_publish(struct mqtt_client *client,
  1311. const char* topic_name,
  1312. void* application_message,
  1313. size_t application_message_size,
  1314. uint8_t publish_flags);
  1315. /**
  1316. * @brief Acknowledge an ingree publish with QOS==1.
  1317. * @ingroup details
  1318. *
  1319. * @param[in,out] client The MQTT client.
  1320. * @param[in] packet_id The packet ID of the ingress publish being acknowledged.
  1321. *
  1322. * @returns \c MQTT_OK upon success, an \ref MQTTErrors otherwise.
  1323. */
  1324. ssize_t __mqtt_puback(struct mqtt_client *client, uint16_t packet_id);
  1325. /**
  1326. * @brief Acknowledge an ingree publish with QOS==2.
  1327. * @ingroup details
  1328. *
  1329. * @param[in,out] client The MQTT client.
  1330. * @param[in] packet_id The packet ID of the ingress publish being acknowledged.
  1331. *
  1332. * @returns \c MQTT_OK upon success, an \ref MQTTErrors otherwise.
  1333. */
  1334. ssize_t __mqtt_pubrec(struct mqtt_client *client, uint16_t packet_id);
  1335. /**
  1336. * @brief Acknowledge an ingree PUBREC packet.
  1337. * @ingroup details
  1338. *
  1339. * @param[in,out] client The MQTT client.
  1340. * @param[in] packet_id The packet ID of the ingress PUBREC being acknowledged.
  1341. *
  1342. * @returns \c MQTT_OK upon success, an \ref MQTTErrors otherwise.
  1343. */
  1344. ssize_t __mqtt_pubrel(struct mqtt_client *client, uint16_t packet_id);
  1345. /**
  1346. * @brief Acknowledge an ingree PUBREL packet.
  1347. * @ingroup details
  1348. *
  1349. * @param[in,out] client The MQTT client.
  1350. * @param[in] packet_id The packet ID of the ingress PUBREL being acknowledged.
  1351. *
  1352. * @returns \c MQTT_OK upon success, an \ref MQTTErrors otherwise.
  1353. */
  1354. ssize_t __mqtt_pubcomp(struct mqtt_client *client, uint16_t packet_id);
  1355. /**
  1356. * @brief Subscribe to a topic.
  1357. * @ingroup api
  1358. *
  1359. * @pre mqtt_connect must have been called.
  1360. *
  1361. * @param[in,out] client The MQTT client.
  1362. * @param[in] topic_name The name of the topic to subscribe to.
  1363. * @param[in] max_qos_level The maximum QOS level with which the broker can send application
  1364. * messages for this topic.
  1365. *
  1366. * @returns \c MQTT_OK upon success, an \ref MQTTErrors otherwise.
  1367. */
  1368. enum MQTTErrors mqtt_subscribe(struct mqtt_client *client,
  1369. const char* topic_name,
  1370. int max_qos_level);
  1371. /**
  1372. * @brief Unsubscribe from a topic.
  1373. * @ingroup api
  1374. *
  1375. * @pre mqtt_connect must have been called.
  1376. *
  1377. * @param[in,out] client The MQTT client.
  1378. * @param[in] topic_name The name of the topic to unsubscribe from.
  1379. *
  1380. * @returns \c MQTT_OK upon success, an \ref MQTTErrors otherwise.
  1381. */
  1382. enum MQTTErrors mqtt_unsubscribe(struct mqtt_client *client,
  1383. const char* topic_name);
  1384. /**
  1385. * @brief Ping the broker.
  1386. * @ingroup api
  1387. *
  1388. * @pre mqtt_connect must have been called.
  1389. *
  1390. * @param[in,out] client The MQTT client.
  1391. *
  1392. * @returns \c MQTT_OK upon success, an \ref MQTTErrors otherwise.
  1393. */
  1394. enum MQTTErrors mqtt_ping(struct mqtt_client *client);
  1395. /**
  1396. * @brief Ping the broker without locking/unlocking the mutex.
  1397. * @see mqtt_ping
  1398. */
  1399. enum MQTTErrors __mqtt_ping(struct mqtt_client *client);
  1400. /**
  1401. * @brief Terminate the session with the MQTT broker.
  1402. * @ingroup api
  1403. *
  1404. * @pre mqtt_connect must have been called.
  1405. *
  1406. * @param[in,out] client The MQTT client.
  1407. *
  1408. * @note To re-establish the session, mqtt_connect must be called.
  1409. *
  1410. * @returns \c MQTT_OK upon success, an \ref MQTTErrors otherwise.
  1411. */
  1412. enum MQTTErrors mqtt_disconnect(struct mqtt_client *client);
  1413. #endif /* __MQTT_H__ */