mqtt_internal.h 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446
  1. /**
  2. * Copyright (c) 2015 - 2019, Nordic Semiconductor ASA
  3. *
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without modification,
  7. * are permitted provided that the following conditions are met:
  8. *
  9. * 1. Redistributions of source code must retain the above copyright notice, this
  10. * list of conditions and the following disclaimer.
  11. *
  12. * 2. Redistributions in binary form, except as embedded into a Nordic
  13. * Semiconductor ASA integrated circuit in a product or a software update for
  14. * such product, must reproduce the above copyright notice, this list of
  15. * conditions and the following disclaimer in the documentation and/or other
  16. * materials provided with the distribution.
  17. *
  18. * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
  19. * contributors may be used to endorse or promote products derived from this
  20. * software without specific prior written permission.
  21. *
  22. * 4. This software, with or without modification, must only be used with a
  23. * Nordic Semiconductor ASA integrated circuit.
  24. *
  25. * 5. Any software provided in binary form under this license must not be reverse
  26. * engineered, decompiled, modified and/or disassembled.
  27. *
  28. * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
  29. * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  30. * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
  31. * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
  32. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  33. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
  34. * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  35. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  36. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  37. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  38. *
  39. */
  40. /** @file mqtt_internal.h
  41. *
  42. * @brief Function and data structures internal to MQTT module.
  43. */
  44. #ifndef MQTT_INTERNAL_H_
  45. #define MQTT_INTERNAL_H_
  46. #include "nordic_common.h"
  47. #include "sdk_common.h"
  48. #include "sdk_config.h"
  49. #include "mqtt.h"
  50. #include "iot_errors.h"
  51. #include "nrf_tls.h"
  52. #include <stdint.h>
  53. #include <string.h>
  54. #include "nrf_error.h"
  55. #include "nrf_tls.h"
  56. #ifdef __cplusplus
  57. extern "C" {
  58. #endif
  59. #ifndef MQTT_MAX_CLIENTS
  60. #define MQTT_MAX_CLIENTS 1 /**< Maximum number of clients that can be managed by the module. */
  61. #endif //MQTT_MAX_CLIENTS
  62. #ifndef MQTT_KEEPALIVE
  63. #define MQTT_KEEPALIVE 60 /**< Keep alive time for MQTT (in seconds). Sending of Ping Requests to be keep the connection alive are governed by this value. */
  64. #endif //MQTT_KEEPALIVE
  65. #ifndef MQTT_MAX_PACKET_LENGTH
  66. #define MQTT_MAX_PACKET_LENGTH 128 /**< Maximum MQTT packet size that can be sent (including the fixed and variable header). */
  67. #endif // MQTT_MAX_PACKET_LENGTH
  68. #define MQTT_FIXED_HEADER_SIZE 2 /**< Fixed header minimum size. Remaining length size is 1 in this case. */
  69. #define MQTT_FIXED_HEADER_EXTENDED_SIZE 5 /**< Maximum size of the fixed header. Remaining length size is 4 in this case. */
  70. /**@brief MQTT Control Packet Types. */
  71. #define MQTT_PKT_TYPE_CONNECT 0x10
  72. #define MQTT_PKT_TYPE_CONNACK 0x20
  73. #define MQTT_PKT_TYPE_PUBLISH 0x30
  74. #define MQTT_PKT_TYPE_PUBACK 0x40
  75. #define MQTT_PKT_TYPE_PUBREC 0x50
  76. #define MQTT_PKT_TYPE_PUBREL 0x60
  77. #define MQTT_PKT_TYPE_PUBCOMP 0x70
  78. #define MQTT_PKT_TYPE_SUBSCRIBE 0x82 // QoS 1 for subscribe
  79. #define MQTT_PKT_TYPE_SUBACK 0x90
  80. #define MQTT_PKT_TYPE_UNSUBSCRIBE 0xA2
  81. #define MQTT_PKT_TYPE_UNSUBACK 0xB0
  82. #define MQTT_PKT_TYPE_PINGREQ 0xC0
  83. #define MQTT_PKT_TYPE_PINGRSP 0xD0
  84. #define MQTT_PKT_TYPE_DISCONNECT 0xE0
  85. /**@brief Masks for MQTT header flags. */
  86. #define MQTT_HEADER_DUP_MASK 0x08
  87. #define MQTT_HEADER_QOS_MASK 0x06
  88. #define MQTT_HEADER_RETAIN_MASK 0x01
  89. #define MQTT_HEADER_CONNACK_MASK 0x0F
  90. /**@brief Masks for MQTT header flags. */
  91. #define MQTT_CONNECT_FLAG_CLEAN_SESSION 0x02
  92. #define MQTT_CONNECT_FLAG_WILL_TOPIC 0x04
  93. #define MQTT_CONNECT_FLAG_WILL_RETAIN 0x20
  94. #define MQTT_CONNECT_FLAG_PASSWORD 0x40
  95. #define MQTT_CONNECT_FLAG_USERNAME 0x80
  96. /**@brief Size of mandatory header of MQTT Packet. */
  97. #define MQTT_PKT_HEADER_SIZE 2
  98. /**@brief */
  99. #define MQTT_MAX_PAYLOAD_SIZE 0x0FFFFFFF
  100. /**@brief Maximum size of variable and payload in the packet. */
  101. #define MQTT_MAX_VARIABLE_HEADER_N_PAYLOAD (MQTT_MAX_PACKET_LENGTH - MQTT_FIXED_HEADER_EXTENDED_SIZE)
  102. /**@brief Defines size of uint8 in bytes. */
  103. #define SIZE_OF_UINT8 1
  104. /**@brief Defines size of uint8 in bytes. */
  105. #define SIZE_OF_UINT16 2
  106. /**@brief Computes total size needed to pack a UTF8 string. */
  107. #define GET_UT8STR_BUFFER_SIZE(STR) (SIZE_OF_UINT16 + (STR)->utf_strlen)
  108. /**@brief Computes total size needed to pack a binary stream. */
  109. #define GET_BINSTR_BUFFER_SIZE(STR) ((STR)->bin_strlen)
  110. /**@brief Unsubscribe packet size. */
  111. #define MQTT_UNSUBSCRIBE_PKT_SIZE 4
  112. /**@brief Sets MQTT Client's state with one indicated in 'STATE'. */
  113. #define MQTT_SET_STATE(CLIENT, STATE) ((CLIENT)->state |= (STATE))
  114. /**@brief Sets MQTT Client's state exclusive to 'STATE'. */
  115. #define MQTT_SET_STATE_EXCLUSIVE(CLIENT, STATE) ((CLIENT)->state = (STATE))
  116. /**@brief Verifies if MQTT Client's state is set with one indicated in 'STATE'. */
  117. #define MQTT_VERIFY_STATE(CLIENT, STATE) ((CLIENT)->state & (STATE))
  118. /**@brief Reset 'STATE' in MQTT Client's state. */
  119. #define MQTT_RESET_STATE(CLIENT, STATE) ((CLIENT)->state &= ~(STATE))
  120. /**@brief Initialize MQTT Client's state. */
  121. #define MQTT_STATE_INIT(CLIENT) (CLIENT)->state = MQTT_STATE_IDLE
  122. /**@brief Computes the first byte of MQTT message header based on message type, duplication flag,
  123. * QoS and the retain flag.
  124. */
  125. #define MQTT_MESSAGES_OPTIONS(TYPE, DUP, QOS, RETAIN) \
  126. (((TYPE) & 0xF0) | \
  127. (((DUP) << 3) & 0x08) | \
  128. (((QOS) << 1) & 0x06) | \
  129. ((RETAIN) & 0x01))
  130. #define MQTT_EVT_FLAG_NONE 0x00000000
  131. #define MQTT_EVT_FLAG_INSTANCE_RESET 0x00000001
  132. /**
  133. * @defgroup iot_mqtt_mutex_lock_unlock Module's Mutex Lock/Unlock Macros.
  134. *
  135. * @details Macros used to lock and unlock modules. Currently, SDK does not use mutexes but
  136. * framework is provided in case the need to use an alternative architecture arises.
  137. * @{
  138. */
  139. #define MQTT_MUTEX_LOCK() SDK_MUTEX_LOCK(m_mqtt_mutex) /**< Lock module using mutex */
  140. #define MQTT_MUTEX_UNLOCK() SDK_MUTEX_UNLOCK(m_mqtt_mutex) /**< Unlock module using mutex */
  141. /** @} */
  142. /**@brief Check if the input pointer is NULL, if so it returns NRF_ERROR_NULL.
  143. */
  144. #define NULL_PARAM_CHECK(PARAM) \
  145. if ((PARAM) == NULL) \
  146. { \
  147. return (NRF_ERROR_NULL | IOT_MQTT_ERR_BASE); \
  148. }
  149. #define NULL_PARAM_CHECK_VOID(PARAM) \
  150. if ((PARAM) == NULL) \
  151. { \
  152. return; \
  153. }
  154. /**@brief MQTT States. */
  155. typedef enum
  156. {
  157. MQTT_STATE_IDLE = 0x00000000, /**< Idle state, implying the client entry in the table is unused/free. */
  158. MQTT_STATE_TCP_CONNECTING = 0x00000001, /**< TCP Connection has been requested, awaiting result of the request. */
  159. MQTT_STATE_TCP_CONNECTED = 0x00000002, /**< TCP Connection successfully established. */
  160. MQTT_STATE_CONNECTED = 0x00000004, /**< MQTT Connection successful. */
  161. MQTT_STATE_PENDING_WRITE = 0x00000008, /**< State that indicates write callback is awaited for an issued request. */
  162. MQTT_STATE_DISCONNECTING = 0x00000010 /**< TCP Disconnect has been requested, awaiting result of the request. */
  163. } mqtt_state_t;
  164. /**@brief Packs unsigned 8 bit value to the buffer at the offset requested.
  165. *
  166. * @param[in] val Value to be packed.
  167. * @param[in] buffer_len Total size of the buffer on which value is to be packed.
  168. * This shall not be zero.
  169. * @param[out] p_buffer Buffer where the value is to be packed.
  170. * @param[inout] p_offset Offset on the buffer where the value is to be packed. If the procedure
  171. * is successful, the offset is incremented to point to the next write/pack
  172. * location on the buffer.
  173. *
  174. * @retval NRF_SUCCESS if procedure is successful.
  175. * @retval NRF_ERROR_DATA_SIZE if the offset is greater than or equal to the buffer length.
  176. */
  177. uint32_t pack_uint8(uint8_t val,
  178. uint32_t buffer_len,
  179. uint8_t * const p_buffer,
  180. uint32_t * const p_offset);
  181. /**@brief Packs unsigned 16 bit value to the buffer at the offset requested.
  182. *
  183. * @param[in] val Value to be packed.
  184. * @param[in] buffer_len Total size of the buffer on which value is to be packed.
  185. * This shall not be zero.
  186. * @param[out] p_buffer Buffer where the value is to be packed.
  187. * @param[inout] p_offset Offset on the buffer where the value is to be packed. If the procedure
  188. * is successful, the offset is incremented to point to the next write/pack
  189. * location on the buffer.
  190. *
  191. * @retval NRF_SUCCESS if the procedure is successful.
  192. * @retval NRF_ERROR_DATA_SIZE if the offset is greater than or equal to the buffer length minus
  193. * the size of unsigned 16 bit integer.
  194. */
  195. uint32_t pack_uint16(uint16_t val,
  196. uint32_t buffer_len,
  197. uint8_t * const p_buffer,
  198. uint32_t * const p_offset);
  199. /**@brief Packs utf8 string to the buffer at the offset requested.
  200. *
  201. * @param[in] p_str UTF-8 string and its length to be packed.
  202. * @param[in] buffer_len Total size of the buffer on which string is to be packed.
  203. * This shall not be zero.
  204. * @param[out] p_buffer Buffer where the string is to be packed.
  205. * @param[inout] p_offset Offset on the buffer where the string is to be packed. If the procedure
  206. * is successful, the offset is incremented to point to the next write/pack
  207. * location on the buffer.
  208. *
  209. * @retval NRF_SUCCESS if the procedure is successful.
  210. * @retval NRF_ERROR_DATA_SIZE if the offset is greater than or equal to the buffer length minus
  211. * the size of unsigned 16 bit integer.
  212. * @retval NRF_ERROR_NO_MEM if there is no room on the buffer to pack the string.
  213. */
  214. uint32_t pack_utf8_str(mqtt_utf8_t const * const p_str,
  215. uint32_t buffer_len,
  216. uint8_t * const p_buffer,
  217. uint32_t * const p_offset);
  218. /**@brief Packs binary string to the buffer at the offset requested.
  219. *
  220. * @param[in] p_str Binary string and its length to be packed.
  221. * @param[in] buffer_len Total size of the buffer on which string is to be packed.
  222. * @param[in] p_buffer Buffer where the string is to be packed.
  223. * @param[inout] p_offset Offset on the buffer where the string is to be packed. If the procedure
  224. * is successful, the offset is incremented to point to the next write/pack
  225. * location on the buffer.
  226. *
  227. * @retval NRF_SUCCESS if the procedure is successful.
  228. * @retval NRF_ERROR_DATA_SIZE if the offset is greater than or equal to the buffer length.
  229. * @retval NRF_ERROR_NO_MEM if there is no room on the buffer to pack the string.
  230. */
  231. uint32_t pack_bin_str(mqtt_binstr_t const * const p_str,
  232. uint32_t buffer_len,
  233. uint8_t * const p_buffer,
  234. uint32_t * const p_offset);
  235. /**@brief Unpacks unsigned 8 bit value from the buffer from the offset requested.
  236. *
  237. * @param[out] p_val Memory where the value is to be unpacked.
  238. * @param[in] buffer_len Total size of the buffer. This shall not be zero.
  239. * @param[in] p_buffer Buffer from which the value is to be unpacked.
  240. * @param[inout] p_offset Offset on the buffer from where the value is to be unpacked. If the
  241. * procedure is successful, the offset is incremented to point to the next
  242. * read/unpack location on the buffer.
  243. *
  244. * @retval NRF_SUCCESS if the procedure is successful.
  245. * @retval NRF_ERROR_DATA_SIZE if the offset is greater than or equal to the buffer length.
  246. */
  247. uint32_t unpack_uint8(uint8_t * p_val,
  248. uint32_t buffer_len,
  249. uint8_t * const p_buffer,
  250. uint32_t * const p_offset);
  251. /**@brief Unpacks unsigned 16 bit value from the buffer from the offset requested.
  252. *
  253. * @param[out] p_val Memory where the value is to be unpacked.
  254. * @param[in] buffer_len Total size of the buffer. This shall not be zero.
  255. * @param[in] p_buffer Buffer from which the value is to be unpacked.
  256. * @param[inout] p_offset Offset on the buffer from where the value is to be unpacked. If the
  257. * procedure is successful, the offset is incremented to point to the next
  258. * read/unpack location on the buffer.
  259. *
  260. * @retval NRF_SUCCESS if the procedure is successful.
  261. * @retval NRF_ERROR_DATA_SIZE if the offset is greater than or equal to the buffer length.
  262. */
  263. uint32_t unpack_uint16(uint16_t * p_val,
  264. uint32_t buffer_len,
  265. uint8_t * const p_buffer,
  266. uint32_t * const p_offset);
  267. /**@brief Unpacks unsigned 16 bit value from the buffer from the offset requested.
  268. *
  269. * @param[out] p_str Memory where the utf8 string and its value are to be unpacked.
  270. * No copy of data is performed for the string.
  271. * @param[in] buffer_len Total size of the buffer. This shall not be zero.
  272. * @param[in] p_buffer Buffer from which the string is to be unpacked.
  273. * @param[inout] p_offset Offset on the buffer from where the value is to be unpacked. If the
  274. * procedure is successful, the offset is incremented to point to the next
  275. * read/unpack location on the buffer.
  276. *
  277. * @retval NRF_SUCCESS if the procedure is successful.
  278. * @retval NRF_ERROR_DATA_SIZE if the offset is greater than or equal to the buffer length.
  279. */
  280. uint32_t unpack_utf8_str(mqtt_utf8_t * const p_str,
  281. uint32_t buffer_len,
  282. uint8_t * const p_buffer,
  283. uint32_t * const p_offset);
  284. /**@brief Unpacks binary string from the buffer from the offset requested.
  285. *
  286. * @param[out] p_str Memory where the binary string and its length are to be unpacked.
  287. * No copy of data is performed for the string.
  288. * @param[in] buffer_len Total size of the buffer. This shall not be zero.
  289. * @param[in] p_buffer Buffer where the value is to be unpacked.
  290. * @param[inout] p_offset Offset on the buffer from where the value is to be unpacked. If the
  291. * procedure is successful, the offset is incremented to point to the next
  292. * read/unpack location on the buffer.
  293. *
  294. * @retval NRF_SUCCESS if the procedure is successful.
  295. * @retval NRF_ERROR_DATA_SIZE if the offset is greater than or equal to the buffer length.
  296. */
  297. uint32_t unpack_bin_str(mqtt_binstr_t * const p_str,
  298. uint32_t buffer_len,
  299. uint8_t * const p_buffer,
  300. uint32_t * const p_offset);
  301. /**@brief Unpacks utf8 string from the buffer from the offset requested.
  302. *
  303. * @param[out] p_str Memory where the utf8 string and its length are to be unpacked.
  304. * @param[in] buffer_len Total size of the buffer. This shall not be zero.
  305. * @param[in] p_buffer Buffer where the value is to be unpacked.
  306. * @param[inout] p_offset Offset on the buffer from where the value is to be unpacked. If the
  307. * procedure is successful, the offset is incremented to point to the next
  308. * read/unpack location on the buffer.
  309. *
  310. * @retval NRF_SUCCESS if the procedure is successful.
  311. * @retval NRF_ERROR_DATA_SIZE if the offset is greater than or equal to the buffer length.
  312. */
  313. uint32_t zero_len_str_encode(uint32_t buffer_len,
  314. uint8_t * const p_buffer,
  315. uint32_t * const p_offset);
  316. /**@brief Computes and encodes length for the MQTT fixed header.
  317. *
  318. * @note The remaining length is not packed as a fixed unsigned 32 bit integer. Instead it is packed
  319. * on algorithm below:
  320. *
  321. * @code
  322. * do
  323. * encodedByte = X MOD 128
  324. * X = X DIV 128
  325. * // if there are more data to encode, set the top bit of this byte
  326. * if ( X > 0 )
  327. * encodedByte = encodedByte OR 128
  328. * endif
  329. * 'output' encodedByte
  330. * while ( X > 0 )
  331. * @endcode
  332. *
  333. * @param[in] remaining_length Length of variable header and payload in the MQTT message.
  334. * @param[out] p_buffer Buffer where the length is to be packed.
  335. * @param[inout] p_offset Offset on the buffer where the length is to be packed.
  336. */
  337. void packet_length_encode(uint32_t remaining_length, uint8_t * p_buffer, uint32_t * p_offset);
  338. /**@brief Decode MQTT Packet Length in the MQTT fixed header.
  339. *
  340. * @param[in] p_buffer Buffer where the length is to be decoded.
  341. * @param[in] buffer_len Length of p_buffer
  342. * @param[out] p_remaining_length Length of variable header and payload in the MQTT message.
  343. * @param[inout] p_offset Offset on the buffer from where the length is to be unpacked.
  344. *
  345. * @retval NRF_SUCCESS if the procedure is successful.
  346. * @retval NRF_ERROR_DATA_SIZE if the offset is greater than or equal to the buffer length.
  347. */
  348. uint32_t packet_length_decode(uint8_t * p_buffer,
  349. uint32_t buffer_len,
  350. uint32_t * p_remaining_length,
  351. uint32_t * p_offset);
  352. /**@brief Encodes fixed header for the MQTT message and provides pointer to start of the header.
  353. *
  354. * @param[in] message_type Message type containing packet type and the flags.
  355. * Use @ref MQTT_MESSAGES_OPTIONS to construct the message_type.
  356. * @param[in] length Buffer where the message payload along with variable header.
  357. * @param[inout] pp_packet Pointer to the MQTT message variable header and payload.
  358. * The 5 bytes before the start of the message are assumed by the
  359. * routine to be available to pack the fixed header. However, since
  360. * the fixed header length is variable length, the pointer to the
  361. * start of the MQTT message along with encoded fixed header is
  362. * supplied as output parameter if the procedure was successful.
  363. *
  364. * @retval 0xFFFFFFFF if the procedure failed, else length of total MQTT message along with the
  365. * fixed header.
  366. */
  367. uint32_t mqtt_encode_fixed_header(uint8_t message_type, uint32_t length, uint8_t ** pp_packet);
  368. /**@brief Constructs/encodes connect packet.
  369. *
  370. * @param[in] p_client Identifies the client for which the procedure is requested.
  371. * All information required for creating the packet like client id,
  372. * clean session flag, retain session flag etc are assumed to be
  373. * populated for the client instance when this procedure is requested.
  374. * @param[out] pp_packet Pointer to the MQTT connect message.
  375. * @param[out] p_packet_length Length of the connect request.
  376. *
  377. * @retval 0xFFFFFFFF if the procedure failed, else length of total MQTT message along with the
  378. * fixed header.
  379. */
  380. void connect_request_encode(const mqtt_client_t * p_client,
  381. uint8_t ** pp_packet,
  382. uint32_t * p_packet_length);
  383. #ifdef __cplusplus
  384. }
  385. #endif
  386. #endif // MQTT_INTERNAL_H_