mqtt_encoder.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  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_encoder.c
  41. *
  42. * @brief Encoding functions needed to create packet to be sent to the broker.
  43. */
  44. #include "mqtt_internal.h"
  45. #if MQTT_CONFIG_LOG_ENABLED
  46. #define NRF_LOG_MODULE_NAME mqtt_enc
  47. #define NRF_LOG_LEVEL MQTT_CONFIG_LOG_LEVEL
  48. #define NRF_LOG_INFO_COLOR MQTT_CONFIG_INFO_COLOR
  49. #define NRF_LOG_DEBUG_COLOR MQTT_CONFIG_DEBUG_COLOR
  50. #include "nrf_log.h"
  51. NRF_LOG_MODULE_REGISTER();
  52. #define MQTT_TRC NRF_LOG_DEBUG /**< Used for getting trace of execution in the module. */
  53. #define MQTT_ERR NRF_LOG_ERROR /**< Used for logging errors in the module. */
  54. #define MQTT_DUMP NRF_LOG_HEXDUMP_DEBUG /**< Used for dumping octet information to get details of bond information etc. */
  55. #define MQTT_ENTRY() MQTT_TRC(">> %s", __func__)
  56. #define MQTT_EXIT() MQTT_TRC("<< %s", __func__)
  57. #else // MQTT_CONFIG_LOG_ENABLED
  58. #define MQTT_TRC(...) /**< Disables traces. */
  59. #define MQTT_DUMP(...) /**< Disables dumping of octet streams. */
  60. #define MQTT_ERR(...) /**< Disables error logs. */
  61. #define MQTT_ENTRY(...)
  62. #define MQTT_EXIT(...)
  63. #endif // MQTT_CONFIG_LOG_ENABLED
  64. #define MQTT_3_1_0_PROTO_DESC_LEN 6
  65. #define MQTT_3_1_1_PROTO_DESC_LEN 4
  66. const uint8_t mqtt_3_1_0_proto_desc_str[MQTT_3_1_0_PROTO_DESC_LEN] = {'M', 'Q', 'I', 's', 'd', 'p'};
  67. const uint8_t mqtt_3_1_1_proto_desc_str[MQTT_3_1_1_PROTO_DESC_LEN] = {'M', 'Q', 'T', 'T'};
  68. const mqtt_utf8_t mqtt_3_1_0_proto_desc =
  69. {
  70. .p_utf_str = (uint8_t *)&mqtt_3_1_0_proto_desc_str[0],
  71. .utf_strlen = MQTT_3_1_0_PROTO_DESC_LEN
  72. };
  73. const mqtt_utf8_t mqtt_3_1_1_proto_desc =
  74. {
  75. .p_utf_str = (uint8_t *)&mqtt_3_1_1_proto_desc_str[0],
  76. .utf_strlen = MQTT_3_1_1_PROTO_DESC_LEN
  77. };
  78. uint32_t pack_uint8(uint8_t val,
  79. uint32_t buffer_len,
  80. uint8_t * const buffer,
  81. uint32_t * const p_offset)
  82. {
  83. uint32_t err_code = NRF_ERROR_DATA_SIZE;
  84. if (buffer_len > (*p_offset))
  85. {
  86. MQTT_TRC(">> %s V:%02x BL:%08x, B:%p, O:%08x", __func__,
  87. val, buffer_len, buffer, (*p_offset));
  88. // Pack value.
  89. buffer[(*p_offset)] = val;
  90. // Increment offset.
  91. (*p_offset) += SIZE_OF_UINT8;
  92. // Indicate success.
  93. err_code = NRF_SUCCESS;
  94. }
  95. return err_code;
  96. }
  97. uint32_t pack_uint16(uint16_t val,
  98. uint32_t buffer_len,
  99. uint8_t * const buffer,
  100. uint32_t * const p_offset)
  101. {
  102. uint32_t err_code = NRF_ERROR_DATA_SIZE;
  103. if (buffer_len > (*p_offset))
  104. {
  105. const uint32_t available_len = buffer_len - (*p_offset);
  106. MQTT_TRC(">> %s V:%04x BL:%08x, B:%p, O:%08x A:%08x", __func__,
  107. val, buffer_len, buffer, (*p_offset), available_len);
  108. if (available_len >= SIZE_OF_UINT16)
  109. {
  110. // Pack value.
  111. buffer[(*p_offset)] = MSB_16(val);
  112. buffer[(*p_offset)+1] = LSB_16(val);
  113. // Increment offset.
  114. (*p_offset) += SIZE_OF_UINT16;
  115. // Indicate success.
  116. err_code = NRF_SUCCESS;
  117. }
  118. }
  119. return err_code;
  120. }
  121. uint32_t pack_utf8_str(mqtt_utf8_t const * const p_str,
  122. uint32_t buffer_len,
  123. uint8_t * const buffer,
  124. uint32_t * const p_offset)
  125. {
  126. uint32_t err_code = NRF_ERROR_DATA_SIZE;
  127. if (buffer_len > (*p_offset))
  128. {
  129. const uint32_t available_len = buffer_len - (*p_offset);
  130. err_code = NRF_ERROR_NO_MEM;
  131. MQTT_TRC(">> %s USL:%08x BL:%08x, B:%p, O:%08x A:%08x", __func__,
  132. GET_UT8STR_BUFFER_SIZE(p_str), buffer_len, buffer, (*p_offset), available_len);
  133. if (available_len >= GET_UT8STR_BUFFER_SIZE(p_str))
  134. {
  135. // Length followed by string.
  136. err_code = pack_uint16(p_str->utf_strlen, buffer_len, buffer, p_offset);
  137. if (err_code == NRF_SUCCESS)
  138. {
  139. memcpy(&buffer[(*p_offset)], p_str->p_utf_str, p_str->utf_strlen);
  140. (*p_offset) += p_str->utf_strlen;
  141. err_code = NRF_SUCCESS;
  142. }
  143. }
  144. }
  145. return err_code;
  146. }
  147. uint32_t pack_bin_str(mqtt_binstr_t const * const p_str,
  148. uint32_t buffer_len,
  149. uint8_t * const buffer,
  150. uint32_t * const p_offset)
  151. {
  152. uint32_t err_code = NRF_ERROR_DATA_SIZE;
  153. if (buffer_len > (*p_offset))
  154. {
  155. const uint32_t available_len = buffer_len - (*p_offset);
  156. err_code = NRF_ERROR_NO_MEM;
  157. MQTT_TRC(">> %s BSL:%08x BL:%08x, B:%p, O:%08x A:%08x", __func__,
  158. GET_BINSTR_BUFFER_SIZE(p_str), buffer_len, buffer, (*p_offset), available_len);
  159. if (available_len >= GET_BINSTR_BUFFER_SIZE(p_str))
  160. {
  161. memcpy(&buffer[(*p_offset)], p_str->p_bin_str, p_str->bin_strlen);
  162. (*p_offset) += p_str->bin_strlen;
  163. err_code = NRF_SUCCESS;
  164. }
  165. }
  166. return err_code;
  167. }
  168. void packet_length_encode(uint32_t remaining_length, uint8_t * p_buff, uint32_t * p_size)
  169. {
  170. uint16_t index = 0;
  171. const uint32_t offset = (*p_size);
  172. MQTT_TRC(">> RL:0x%08x O:%08x P:%p", remaining_length, offset, p_buff);
  173. do
  174. {
  175. if (p_buff != NULL)
  176. {
  177. p_buff[offset+index] = remaining_length % 0x80;
  178. }
  179. remaining_length /= 0x80;
  180. if (remaining_length > 0)
  181. {
  182. if (p_buff != NULL)
  183. {
  184. p_buff[offset+index] |= 0x80;
  185. }
  186. }
  187. index++;
  188. } while (remaining_length > 0);
  189. MQTT_TRC("<< RLS:0x%08x", index);
  190. *p_size += index;
  191. }
  192. uint32_t mqtt_encode_fixed_header(uint8_t message_type, uint32_t length, uint8_t ** pp_packet)
  193. {
  194. uint32_t packet_length = 0xFFFFFFFF;
  195. if (MQTT_MAX_PAYLOAD_SIZE >= length)
  196. {
  197. uint32_t offset = 1;
  198. MQTT_TRC("<< %s MT:0x%02x L:0x%08x", __func__, message_type, length);
  199. packet_length_encode(length, NULL, &offset);
  200. MQTT_TRC("Remaining length size = %02x", offset);
  201. uint8_t * p_mqtt_header = ((*pp_packet) - offset);
  202. // Reset offset.
  203. offset = 0;
  204. UNUSED_VARIABLE(pack_uint8(message_type, MQTT_MAX_PACKET_LENGTH, p_mqtt_header, &offset));
  205. packet_length_encode(length, p_mqtt_header, &offset);
  206. (* pp_packet) = p_mqtt_header;
  207. packet_length = (length + offset);
  208. }
  209. return packet_length;
  210. }
  211. uint32_t zero_len_str_encode(uint32_t buffer_len,
  212. uint8_t * const buffer,
  213. uint32_t * const offset)
  214. {
  215. return pack_uint16(0x0000, buffer_len, buffer, offset);
  216. }
  217. void connect_request_encode(const mqtt_client_t * p_client,
  218. uint8_t ** pp_packet,
  219. uint32_t * p_packet_length)
  220. {
  221. uint32_t err_code;
  222. uint32_t offset = 0;
  223. uint8_t * p_payload = &p_client->p_packet[MQTT_FIXED_HEADER_EXTENDED_SIZE];
  224. uint8_t connect_flags = p_client->clean_session << 1; // Clean session always.
  225. const mqtt_utf8_t * p_mqtt_proto_desc;
  226. if (p_client->protocol_version == MQTT_VERSION_3_1_1)
  227. {
  228. p_mqtt_proto_desc = &mqtt_3_1_1_proto_desc;
  229. }
  230. else
  231. {
  232. p_mqtt_proto_desc = &mqtt_3_1_0_proto_desc;
  233. }
  234. memset(p_payload, 0, MQTT_MAX_PACKET_LENGTH);
  235. // Pack protocol description.
  236. MQTT_TRC("Encoding Protocol Description. Str:%s Size:%08x.",
  237. p_mqtt_proto_desc->p_utf_str,
  238. p_mqtt_proto_desc->utf_strlen);
  239. err_code = pack_utf8_str(p_mqtt_proto_desc,
  240. MQTT_MAX_VARIABLE_HEADER_N_PAYLOAD,
  241. p_payload,
  242. &offset);
  243. if (err_code == NRF_SUCCESS)
  244. {
  245. MQTT_TRC("Encoding Protocol Version %02x.", p_client->protocol_version);
  246. // Pack protocol version.
  247. err_code = pack_uint8(p_client->protocol_version,
  248. MQTT_MAX_VARIABLE_HEADER_N_PAYLOAD,
  249. p_payload,
  250. &offset);
  251. }
  252. // Remember position of connect flag and
  253. // leave one byte for it to be packed once we determine its value.
  254. const uint32_t connect_flag_offset = MQTT_FIXED_HEADER_EXTENDED_SIZE + offset;
  255. offset++;
  256. if (err_code == NRF_SUCCESS)
  257. {
  258. MQTT_TRC("Encoding Keep Alive Time %04x.", MQTT_KEEPALIVE);
  259. // Pack keep alive time.
  260. err_code = pack_uint16(MQTT_KEEPALIVE,
  261. MQTT_MAX_VARIABLE_HEADER_N_PAYLOAD,
  262. p_payload,
  263. &offset);
  264. }
  265. if (err_code == NRF_SUCCESS)
  266. {
  267. MQTT_TRC("Encoding Client Id. Str:%s Size:%08x.",
  268. p_client->client_id.p_utf_str,
  269. p_client->client_id.utf_strlen);
  270. // Pack client id
  271. err_code = pack_utf8_str(&p_client->client_id,
  272. MQTT_MAX_VARIABLE_HEADER_N_PAYLOAD,
  273. p_payload,
  274. &offset);
  275. }
  276. if (err_code == NRF_SUCCESS)
  277. {
  278. // Pack will topic and QoS
  279. if (p_client->p_will_topic != NULL)
  280. {
  281. MQTT_TRC("Encoding Will Topic. Str:%s Size:%08x.",
  282. p_client->p_will_topic->topic.p_utf_str,
  283. p_client->p_will_topic->topic.utf_strlen);
  284. // Set Will topic in connect flags.
  285. connect_flags |= MQTT_CONNECT_FLAG_WILL_TOPIC;
  286. err_code = pack_utf8_str(&p_client->p_will_topic->topic,
  287. MQTT_MAX_VARIABLE_HEADER_N_PAYLOAD,
  288. p_payload,
  289. &offset);
  290. if (err_code == NRF_SUCCESS)
  291. {
  292. // QoS is always 1 as of now.
  293. connect_flags |= ((p_client->p_will_topic->qos & 0x03) << 3);
  294. connect_flags |= p_client->will_retain << 5;
  295. if (p_client->p_will_message != NULL)
  296. {
  297. MQTT_TRC("Encoding Will Message. Str:%s Size:%08x.",
  298. p_client->p_will_message->p_utf_str,
  299. p_client->p_will_message->utf_strlen);
  300. err_code = pack_utf8_str(p_client->p_will_message,
  301. MQTT_MAX_VARIABLE_HEADER_N_PAYLOAD,
  302. p_payload,
  303. &offset);
  304. }
  305. else
  306. {
  307. MQTT_TRC("Encoding Zero Length Will Message.");
  308. err_code = zero_len_str_encode(MQTT_MAX_VARIABLE_HEADER_N_PAYLOAD,
  309. p_payload,
  310. &offset);
  311. }
  312. }
  313. }
  314. }
  315. if (err_code == NRF_SUCCESS)
  316. {
  317. // Pack Username if any.
  318. if (p_client->p_user_name != NULL)
  319. {
  320. connect_flags |= MQTT_CONNECT_FLAG_USERNAME;
  321. MQTT_TRC("Encoding Username. Str:%s, Size:%08x.",
  322. p_client->p_user_name->p_utf_str,
  323. p_client->p_user_name->utf_strlen);
  324. err_code = pack_utf8_str(p_client->p_user_name,
  325. MQTT_MAX_VARIABLE_HEADER_N_PAYLOAD,
  326. p_payload,
  327. &offset);
  328. if (err_code == NRF_SUCCESS)
  329. {
  330. // Pack Password if any.
  331. if (p_client->p_password != NULL)
  332. {
  333. MQTT_TRC("Encoding Password. Str:%s Size:%08x.",
  334. p_client->p_password->p_utf_str,
  335. p_client->p_password->utf_strlen);
  336. connect_flags |= MQTT_CONNECT_FLAG_PASSWORD;
  337. err_code = pack_utf8_str(p_client->p_password,
  338. MQTT_MAX_VARIABLE_HEADER_N_PAYLOAD,
  339. p_payload,
  340. &offset);
  341. }
  342. }
  343. }
  344. }
  345. if (err_code == NRF_SUCCESS)
  346. {
  347. // Pack the connect flags.
  348. p_client->p_packet[connect_flag_offset] = connect_flags;
  349. const uint8_t message_type = MQTT_MESSAGES_OPTIONS(MQTT_PKT_TYPE_CONNECT,
  350. 0, // Duplicate flag not set.
  351. 0, // QoS not set.
  352. 0); // Retain not set.
  353. offset = mqtt_encode_fixed_header(message_type,
  354. offset,
  355. &p_payload);
  356. (*p_packet_length) = offset;
  357. (*pp_packet) = p_payload;
  358. }
  359. else
  360. {
  361. (*p_packet_length) = 0;
  362. (*pp_packet) = NULL;
  363. }
  364. }