]> git.sur5r.net Git - freertos/blob - FreeRTOS-Plus/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/mqtt/src/iot_mqtt_serialize.c
Correct an err in queue.c introduced when previously updating behaviour when queue...
[freertos] / FreeRTOS-Plus / Source / FreeRTOS-IoT-Libraries / c_sdk / standard / mqtt / src / iot_mqtt_serialize.c
1 /*\r
2  * Amazon FreeRTOS MQTT V2.0.0\r
3  * Copyright (C) 2018 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\r
4  *\r
5  * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
6  * this software and associated documentation files (the "Software"), to deal in\r
7  * the Software without restriction, including without limitation the rights to\r
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
9  * the Software, and to permit persons to whom the Software is furnished to do so,\r
10  * subject to the following conditions:\r
11  *\r
12  * The above copyright notice and this permission notice shall be included in all\r
13  * copies or substantial portions of the Software.\r
14  *\r
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
17  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
18  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
19  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
20  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
21  *\r
22  * http://aws.amazon.com/freertos\r
23  * http://www.FreeRTOS.org\r
24  */\r
25 \r
26 /**\r
27  * @file iot_mqtt_serialize.c\r
28  * @brief Implements functions that generate and decode MQTT network packets.\r
29  */\r
30 \r
31 /* The config header is always included first. */\r
32 #include "iot_config.h"\r
33 \r
34 /* Standard includes. */\r
35 #include <string.h>\r
36 \r
37 /* Error handling include. */\r
38 #include "private/iot_error.h"\r
39 \r
40 /* MQTT internal includes. */\r
41 #include "private/iot_mqtt_internal.h"\r
42 \r
43 /* Platform layer includes. */\r
44 #include "platform/iot_threads.h"\r
45 \r
46 /* Atomic operations. */\r
47 #include "iot_atomic.h"\r
48 \r
49 /*-----------------------------------------------------------*/\r
50 \r
51 /*\r
52  * Macros for reading the high and low byte of a 2-byte unsigned int.\r
53  */\r
54 #define UINT16_HIGH_BYTE( x )    ( ( uint8_t ) ( x >> 8 ) )            /**< @brief Get high byte. */\r
55 #define UINT16_LOW_BYTE( x )     ( ( uint8_t ) ( x & 0x00ff ) )        /**< @brief Get low byte. */\r
56 \r
57 /**\r
58  * @brief Macro for decoding a 2-byte unsigned int from a sequence of bytes.\r
59  *\r
60  * @param[in] ptr A uint8_t* that points to the high byte.\r
61  */\r
62 #define UINT16_DECODE( ptr )                                \\r
63     ( uint16_t ) ( ( ( ( uint16_t ) ( *( ptr ) ) ) << 8 ) | \\r
64                    ( ( uint16_t ) ( *( ptr + 1 ) ) ) )\r
65 \r
66 /**\r
67  * @brief Macro for setting a bit in a 1-byte unsigned int.\r
68  *\r
69  * @param[in] x The unsigned int to set.\r
70  * @param[in] position Which bit to set.\r
71  */\r
72 #define UINT8_SET_BIT( x, position )      ( x = ( uint8_t ) ( x | ( 0x01 << position ) ) )\r
73 \r
74 /**\r
75  * @brief Macro for checking if a bit is set in a 1-byte unsigned int.\r
76  *\r
77  * @param[in] x The unsigned int to check.\r
78  * @param[in] position Which bit to check.\r
79  */\r
80 #define UINT8_CHECK_BIT( x, position )    ( ( x & ( 0x01 << position ) ) == ( 0x01 << position ) )\r
81 \r
82 /*\r
83  * Positions of each flag in the "Connect Flag" field of an MQTT CONNECT\r
84  * packet.\r
85  */\r
86 #define MQTT_CONNECT_FLAG_CLEAN                     ( 1 )  /**< @brief Clean session. */\r
87 #define MQTT_CONNECT_FLAG_WILL                      ( 2 )  /**< @brief Will present. */\r
88 #define MQTT_CONNECT_FLAG_WILL_QOS1                 ( 3 )  /**< @brief Will QoS1. */\r
89 #define MQTT_CONNECT_FLAG_WILL_QOS2                 ( 4 )  /**< @brief Will QoS2. */\r
90 #define MQTT_CONNECT_FLAG_WILL_RETAIN               ( 5 )  /**< @brief Will retain. */\r
91 #define MQTT_CONNECT_FLAG_PASSWORD                  ( 6 )  /**< @brief Password present. */\r
92 #define MQTT_CONNECT_FLAG_USERNAME                  ( 7 )  /**< @brief Username present. */\r
93 \r
94 /*\r
95  * Positions of each flag in the first byte of an MQTT PUBLISH packet's\r
96  * fixed header.\r
97  */\r
98 #define MQTT_PUBLISH_FLAG_RETAIN                    ( 0 )  /**< @brief Message retain flag. */\r
99 #define MQTT_PUBLISH_FLAG_QOS1                      ( 1 )  /**< @brief Publish QoS 1. */\r
100 #define MQTT_PUBLISH_FLAG_QOS2                      ( 2 )  /**< @brief Publish QoS 2. */\r
101 #define MQTT_PUBLISH_FLAG_DUP                       ( 3 )  /**< @brief Duplicate message. */\r
102 \r
103 /**\r
104  * @brief The constant specifying MQTT version 3.1.1. Placed in the CONNECT packet.\r
105  */\r
106 #define MQTT_VERSION_3_1_1                          ( ( uint8_t ) 4U )\r
107 \r
108 /**\r
109  * @brief Per the MQTT 3.1.1 spec, the largest "Remaining Length" of an MQTT\r
110  * packet is this value.\r
111  */\r
112 #define MQTT_MAX_REMAINING_LENGTH                   ( 268435455UL )\r
113 \r
114 /**\r
115  * @brief The maximum possible size of a CONNECT packet.\r
116  *\r
117  * All strings in a CONNECT packet are constrained to 2-byte lengths, giving a\r
118  * maximum length smaller than the max "Remaining Length" constant above.\r
119  */\r
120 #define MQTT_PACKET_CONNECT_MAX_SIZE                ( 327700UL )\r
121 \r
122 /*\r
123  * Constants relating to CONNACK packets, defined by MQTT 3.1.1 spec.\r
124  */\r
125 #define MQTT_PACKET_CONNACK_REMAINING_LENGTH        ( ( uint8_t ) 2 )    /**< @brief A CONNACK packet always has a "Remaining length" of 2. */\r
126 #define MQTT_PACKET_CONNACK_SESSION_PRESENT_MASK    ( ( uint8_t ) 0x01 ) /**< @brief The "Session Present" bit is always the lowest bit. */\r
127 \r
128 /*\r
129  * Constants relating to PUBLISH and PUBACK packets, defined by MQTT\r
130  * 3.1.1 spec.\r
131  */\r
132 #define MQTT_PACKET_PUBACK_SIZE                     ( 4 )               /**< @brief A PUBACK packet is always 4 bytes in size. */\r
133 #define MQTT_PACKET_PUBACK_REMAINING_LENGTH         ( ( uint8_t ) 2 )   /**< @brief A PUBACK packet always has a "Remaining length" of 2. */\r
134 \r
135 /*\r
136  * Constants relating to SUBACK and UNSUBACK packets, defined by MQTT\r
137  * 3.1.1 spec.\r
138  */\r
139 #define MQTT_PACKET_SUBACK_MINIMUM_SIZE             ( 5 )               /**< @brief The size of the smallest valid SUBACK packet. */\r
140 #define MQTT_PACKET_UNSUBACK_REMAINING_LENGTH       ( ( uint8_t ) 2 )   /**< @brief An UNSUBACK packet always has a "Remaining length" of 2. */\r
141 \r
142 /*\r
143  * Constants relating to PINGREQ and PINGRESP packets, defined by MQTT 3.1.1 spec.\r
144  */\r
145 #define MQTT_PACKET_PINGREQ_SIZE                    ( 2 ) /**< @brief A PINGREQ packet is always 2 bytes in size. */\r
146 #define MQTT_PACKET_PINGRESP_REMAINING_LENGTH       ( 0 ) /**< @brief A PINGRESP packet always has a "Remaining length" of 0. */\r
147 \r
148 /*\r
149  * Constants relating to DISCONNECT packets, defined by MQTT 3.1.1 spec.\r
150  */\r
151 #define MQTT_PACKET_DISCONNECT_SIZE                 ( 2 ) /**< @brief A DISCONNECT packet is always 2 bytes in size. */\r
152 \r
153 /* Username for metrics with AWS IoT. */\r
154 #if AWS_IOT_MQTT_ENABLE_METRICS == 1 || DOXYGEN == 1\r
155     #ifndef AWS_IOT_METRICS_USERNAME\r
156 \r
157 /**\r
158  * @brief Specify C SDK and version.\r
159  */\r
160         #define AWS_IOT_METRICS_USERNAME           "?SDK=C&Version=4.0.0"\r
161 \r
162 /**\r
163  * @brief The length of #AWS_IOT_METRICS_USERNAME.\r
164  */\r
165         #define AWS_IOT_METRICS_USERNAME_LENGTH    ( ( uint16_t ) sizeof( AWS_IOT_METRICS_USERNAME ) - 1 )\r
166     #endif /* ifndef AWS_IOT_METRICS_USERNAME */\r
167 #endif /* if AWS_IOT_MQTT_ENABLE_METRICS == 1 || DOXYGEN == 1 */\r
168 \r
169 /*-----------------------------------------------------------*/\r
170 \r
171 /**\r
172  * @brief Generate and return a 2-byte packet identifier.\r
173  *\r
174  * This packet identifier will be nonzero.\r
175  *\r
176  * @return The packet identifier.\r
177  */\r
178 static uint16_t _nextPacketIdentifier( void );\r
179 \r
180 /**\r
181  * @brief Calculate the number of bytes required to encode an MQTT\r
182  * "Remaining length" field.\r
183  *\r
184  * @param[in] length The value of the "Remaining length" to encode.\r
185  *\r
186  * @return The size of the encoding of length. This is always `1`, `2`, `3`, or `4`.\r
187  */\r
188 static size_t _remainingLengthEncodedSize( size_t length );\r
189 \r
190 /**\r
191  * @brief Encode the "Remaining length" field per MQTT spec.\r
192  *\r
193  * @param[out] pDestination Where to write the encoded "Remaining length".\r
194  * @param[in] length The "Remaining length" to encode.\r
195  *\r
196  * @return Pointer to the end of the encoded "Remaining length", which is 1-4\r
197  * bytes greater than `pDestination`.\r
198  *\r
199  * @warning This function does not check the size of `pDestination`! Ensure that\r
200  * `pDestination` is large enough to hold the encoded "Remaining length" using\r
201  * the function #_remainingLengthEncodedSize to avoid buffer overflows.\r
202  */\r
203 static uint8_t * _encodeRemainingLength( uint8_t * pDestination,\r
204                                          size_t length );\r
205 \r
206 /**\r
207  * @brief Encode a C string as a UTF-8 string, per MQTT 3.1.1 spec.\r
208  *\r
209  * @param[out] pDestination Where to write the encoded string.\r
210  * @param[in] source The string to encode.\r
211  * @param[in] sourceLength The length of source.\r
212  *\r
213  * @return Pointer to the end of the encoded string, which is `sourceLength+2`\r
214  * bytes greater than `pDestination`.\r
215  *\r
216  * @warning This function does not check the size of `pDestination`! Ensure that\r
217  * `pDestination` is large enough to hold `sourceLength+2` bytes to avoid a buffer\r
218  * overflow.\r
219  */\r
220 static uint8_t * _encodeString( uint8_t * pDestination,\r
221                                 const char * source,\r
222                                 uint16_t sourceLength );\r
223 \r
224 /**\r
225  * @brief Calculate the size and "Remaining length" of a CONNECT packet generated\r
226  * from the given parameters.\r
227  *\r
228  * @param[in] pConnectInfo User-provided CONNECT information struct.\r
229  * @param[out] pRemainingLength Output for calculated "Remaining length" field.\r
230  * @param[out] pPacketSize Output for calculated total packet size.\r
231  *\r
232  * @return `true` if the packet is within the length allowed by MQTT 3.1.1 spec; `false`\r
233  * otherwise. If this function returns `false`, the output parameters should be ignored.\r
234  */\r
235 static bool _connectPacketSize( const IotMqttConnectInfo_t * pConnectInfo,\r
236                                 size_t * pRemainingLength,\r
237                                 size_t * pPacketSize );\r
238 \r
239 /**\r
240  * @brief Calculate the size and "Remaining length" of a PUBLISH packet generated\r
241  * from the given parameters.\r
242  *\r
243  * @param[in] pPublishInfo User-provided PUBLISH information struct.\r
244  * @param[out] pRemainingLength Output for calculated "Remaining length" field.\r
245  * @param[out] pPacketSize Output for calculated total packet size.\r
246  *\r
247  * @return `true` if the packet is within the length allowed by MQTT 3.1.1 spec; `false`\r
248  * otherwise. If this function returns `false`, the output parameters should be ignored.\r
249  */\r
250 static bool _publishPacketSize( const IotMqttPublishInfo_t * pPublishInfo,\r
251                                 size_t * pRemainingLength,\r
252                                 size_t * pPacketSize );\r
253 \r
254 /**\r
255  * @brief Calculate the size and "Remaining length" of a SUBSCRIBE or UNSUBSCRIBE\r
256  * packet generated from the given parameters.\r
257  *\r
258  * @param[in] type Either IOT_MQTT_SUBSCRIBE or IOT_MQTT_UNSUBSCRIBE.\r
259  * @param[in] pSubscriptionList User-provided array of subscriptions.\r
260  * @param[in] subscriptionCount Size of `pSubscriptionList`.\r
261  * @param[out] pRemainingLength Output for calculated "Remaining length" field.\r
262  * @param[out] pPacketSize Output for calculated total packet size.\r
263  *\r
264  * @return `true` if the packet is within the length allowed by MQTT 3.1.1 spec; `false`\r
265  * otherwise. If this function returns `false`, the output parameters should be ignored.\r
266  */\r
267 static bool _subscriptionPacketSize( IotMqttOperationType_t type,\r
268                                      const IotMqttSubscription_t * pSubscriptionList,\r
269                                      size_t subscriptionCount,\r
270                                      size_t * pRemainingLength,\r
271                                      size_t * pPacketSize );\r
272 \r
273 /*-----------------------------------------------------------*/\r
274 \r
275 #if LIBRARY_LOG_LEVEL > IOT_LOG_NONE\r
276 \r
277 /**\r
278  * @brief If logging is enabled, define a log configuration that only prints the log\r
279  * string. This is used when printing out details of deserialized MQTT packets.\r
280  */\r
281     static const IotLogConfig_t _logHideAll =\r
282     {\r
283         .hideLibraryName = true,\r
284         .hideLogLevel    = true,\r
285         .hideTimestring  = true\r
286     };\r
287 #endif\r
288 \r
289 /*-----------------------------------------------------------*/\r
290 \r
291 static uint16_t _nextPacketIdentifier( void )\r
292 {\r
293     /* MQTT specifies 2 bytes for the packet identifier; however, operating on\r
294      * 32-bit integers is generally faster. */\r
295     static uint32_t nextPacketIdentifier = 1;\r
296 \r
297     /* The next packet identifier will be greater by 2. This prevents packet\r
298      * identifiers from ever being 0, which is not allowed by MQTT 3.1.1. Packet\r
299      * identifiers will follow the sequence 1,3,5...65535,1,3,5... */\r
300     return ( uint16_t ) Atomic_Add_u32( &nextPacketIdentifier, 2 );\r
301 }\r
302 \r
303 /*-----------------------------------------------------------*/\r
304 \r
305 static size_t _remainingLengthEncodedSize( size_t length )\r
306 {\r
307     size_t encodedSize = 0;\r
308 \r
309     /* length should have already been checked before calling this function. */\r
310     IotMqtt_Assert( length <= MQTT_MAX_REMAINING_LENGTH );\r
311 \r
312     /* Determine how many bytes are needed to encode length.\r
313      * The values below are taken from the MQTT 3.1.1 spec. */\r
314 \r
315     /* 1 byte is needed to encode lengths between 0 and 127. */\r
316     if( length < 128 )\r
317     {\r
318         encodedSize = 1;\r
319     }\r
320     /* 2 bytes are needed to encode lengths between 128 and 16,383. */\r
321     else if( length < 16384 )\r
322     {\r
323         encodedSize = 2;\r
324     }\r
325     /* 3 bytes are needed to encode lengths between 16,384 and 2,097,151. */\r
326     else if( length < 2097152 )\r
327     {\r
328         encodedSize = 3;\r
329     }\r
330     /* 4 bytes are needed to encode lengths between 2,097,152 and 268,435,455. */\r
331     else\r
332     {\r
333         encodedSize = 4;\r
334     }\r
335 \r
336     return encodedSize;\r
337 }\r
338 \r
339 /*-----------------------------------------------------------*/\r
340 \r
341 static uint8_t * _encodeRemainingLength( uint8_t * pDestination,\r
342                                          size_t length )\r
343 {\r
344     uint8_t lengthByte = 0, * pLengthEnd = pDestination;\r
345 \r
346     /* This algorithm is copied from the MQTT v3.1.1 spec. */\r
347     do\r
348     {\r
349         lengthByte = length % 128;\r
350         length = length / 128;\r
351 \r
352         /* Set the high bit of this byte, indicating that there's more data. */\r
353         if( length > 0 )\r
354         {\r
355             UINT8_SET_BIT( lengthByte, 7 );\r
356         }\r
357         else\r
358         {\r
359             EMPTY_ELSE_MARKER;\r
360         }\r
361 \r
362         /* Output a single encoded byte. */\r
363         *pLengthEnd = lengthByte;\r
364         pLengthEnd++;\r
365     } while( length > 0 );\r
366 \r
367     return pLengthEnd;\r
368 }\r
369 \r
370 /*-----------------------------------------------------------*/\r
371 \r
372 static uint8_t * _encodeString( uint8_t * pDestination,\r
373                                 const char * source,\r
374                                 uint16_t sourceLength )\r
375 {\r
376     /* The first byte of a UTF-8 string is the high byte of the string length. */\r
377     *pDestination = UINT16_HIGH_BYTE( sourceLength );\r
378     pDestination++;\r
379 \r
380     /* The second byte of a UTF-8 string is the low byte of the string length. */\r
381     *pDestination = UINT16_LOW_BYTE( sourceLength );\r
382     pDestination++;\r
383 \r
384     /* Copy the string into pDestination. */\r
385     ( void ) memcpy( pDestination, source, sourceLength );\r
386 \r
387     /* Return the pointer to the end of the encoded string. */\r
388     pDestination += sourceLength;\r
389 \r
390     return pDestination;\r
391 }\r
392 \r
393 /*-----------------------------------------------------------*/\r
394 \r
395 static bool _connectPacketSize( const IotMqttConnectInfo_t * pConnectInfo,\r
396                                 size_t * pRemainingLength,\r
397                                 size_t * pPacketSize )\r
398 {\r
399     bool status = true;\r
400     size_t connectPacketSize = 0, remainingLength = 0;\r
401 \r
402     /* The CONNECT packet will always include a 10-byte variable header. */\r
403     connectPacketSize += 10U;\r
404 \r
405     /* Add the length of the client identifier if provided. */\r
406     if( pConnectInfo->clientIdentifierLength > 0 )\r
407     {\r
408         connectPacketSize += pConnectInfo->clientIdentifierLength + sizeof( uint16_t );\r
409     }\r
410     else\r
411     {\r
412         EMPTY_ELSE_MARKER;\r
413     }\r
414 \r
415     /* Add the lengths of the will message and topic name if provided. */\r
416     if( pConnectInfo->pWillInfo != NULL )\r
417     {\r
418         connectPacketSize += pConnectInfo->pWillInfo->topicNameLength + sizeof( uint16_t ) +\r
419                              pConnectInfo->pWillInfo->payloadLength + sizeof( uint16_t );\r
420     }\r
421     else\r
422     {\r
423         EMPTY_ELSE_MARKER;\r
424     }\r
425 \r
426     /* Depending on the status of metrics, add the length of the metrics username\r
427      * or the user-provided username. */\r
428     if( pConnectInfo->awsIotMqttMode == true )\r
429     {\r
430         #if AWS_IOT_MQTT_ENABLE_METRICS == 1\r
431             connectPacketSize += AWS_IOT_METRICS_USERNAME_LENGTH + sizeof( uint16_t );\r
432         #endif\r
433     }\r
434     else\r
435     {\r
436         /* Add the lengths of the username and password if provided and not\r
437          * connecting to an AWS IoT MQTT server. */\r
438         if( pConnectInfo->pUserName != NULL )\r
439         {\r
440             connectPacketSize += pConnectInfo->userNameLength + sizeof( uint16_t );\r
441         }\r
442         else\r
443         {\r
444             EMPTY_ELSE_MARKER;\r
445         }\r
446 \r
447         if( pConnectInfo->pPassword != NULL )\r
448         {\r
449             connectPacketSize += pConnectInfo->passwordLength + sizeof( uint16_t );\r
450         }\r
451         else\r
452         {\r
453             EMPTY_ELSE_MARKER;\r
454         }\r
455     }\r
456 \r
457     /* At this point, the "Remaining Length" field of the MQTT CONNECT packet has\r
458      * been calculated. */\r
459     remainingLength = connectPacketSize;\r
460 \r
461     /* Calculate the full size of the MQTT CONNECT packet by adding the size of\r
462      * the "Remaining Length" field plus 1 byte for the "Packet Type" field. */\r
463     connectPacketSize += 1 + _remainingLengthEncodedSize( connectPacketSize );\r
464 \r
465     /* Check that the CONNECT packet is within the bounds of the MQTT spec. */\r
466     if( connectPacketSize > MQTT_PACKET_CONNECT_MAX_SIZE )\r
467     {\r
468         status = false;\r
469     }\r
470     else\r
471     {\r
472         *pRemainingLength = remainingLength;\r
473         *pPacketSize = connectPacketSize;\r
474     }\r
475 \r
476     return status;\r
477 }\r
478 \r
479 /*-----------------------------------------------------------*/\r
480 \r
481 static bool _publishPacketSize( const IotMqttPublishInfo_t * pPublishInfo,\r
482                                 size_t * pRemainingLength,\r
483                                 size_t * pPacketSize )\r
484 {\r
485     bool status = true;\r
486     size_t publishPacketSize = 0, payloadLimit = 0;\r
487 \r
488     /* The variable header of a PUBLISH packet always contains the topic name. */\r
489     publishPacketSize += pPublishInfo->topicNameLength + sizeof( uint16_t );\r
490 \r
491     /* The variable header of a QoS 1 or 2 PUBLISH packet contains a 2-byte\r
492      * packet identifier. */\r
493     if( pPublishInfo->qos > IOT_MQTT_QOS_0 )\r
494     {\r
495         publishPacketSize += sizeof( uint16_t );\r
496     }\r
497     else\r
498     {\r
499         EMPTY_ELSE_MARKER;\r
500     }\r
501 \r
502     /* Calculate the maximum allowed size of the payload for the given parameters.\r
503      * This calculation excludes the "Remaining length" encoding, whose size is not\r
504      * yet known. */\r
505     payloadLimit = MQTT_MAX_REMAINING_LENGTH - publishPacketSize - 1;\r
506 \r
507     /* Ensure that the given payload fits within the calculated limit. */\r
508     if( pPublishInfo->payloadLength > payloadLimit )\r
509     {\r
510         status = false;\r
511     }\r
512     else\r
513     {\r
514         /* Add the length of the PUBLISH payload. At this point, the "Remaining length"\r
515          * has been calculated. */\r
516         publishPacketSize += pPublishInfo->payloadLength;\r
517 \r
518         /* Now that the "Remaining length" is known, recalculate the payload limit\r
519          * based on the size of its encoding. */\r
520         payloadLimit -= _remainingLengthEncodedSize( publishPacketSize );\r
521 \r
522         /* Check that the given payload fits within the size allowed by MQTT spec. */\r
523         if( pPublishInfo->payloadLength > payloadLimit )\r
524         {\r
525             status = false;\r
526         }\r
527         else\r
528         {\r
529             /* Set the "Remaining length" output parameter and calculate the full\r
530              * size of the PUBLISH packet. */\r
531             *pRemainingLength = publishPacketSize;\r
532 \r
533             publishPacketSize += 1 + _remainingLengthEncodedSize( publishPacketSize );\r
534             *pPacketSize = publishPacketSize;\r
535         }\r
536     }\r
537 \r
538     return status;\r
539 }\r
540 \r
541 /*-----------------------------------------------------------*/\r
542 \r
543 static bool _subscriptionPacketSize( IotMqttOperationType_t type,\r
544                                      const IotMqttSubscription_t * pSubscriptionList,\r
545                                      size_t subscriptionCount,\r
546                                      size_t * pRemainingLength,\r
547                                      size_t * pPacketSize )\r
548 {\r
549     bool status = true;\r
550     size_t i = 0, subscriptionPacketSize = 0;\r
551 \r
552     /* Only SUBSCRIBE and UNSUBSCRIBE operations should call this function. */\r
553     IotMqtt_Assert( ( type == IOT_MQTT_SUBSCRIBE ) || ( type == IOT_MQTT_UNSUBSCRIBE ) );\r
554 \r
555     /* The variable header of a subscription packet consists of a 2-byte packet\r
556      * identifier. */\r
557     subscriptionPacketSize += sizeof( uint16_t );\r
558 \r
559     /* Sum the lengths of all subscription topic filters; add 1 byte for each\r
560      * subscription's QoS if type is IOT_MQTT_SUBSCRIBE. */\r
561     for( i = 0; i < subscriptionCount; i++ )\r
562     {\r
563         /* Add the length of the topic filter. */\r
564         subscriptionPacketSize += pSubscriptionList[ i ].topicFilterLength + sizeof( uint16_t );\r
565 \r
566         /* Only SUBSCRIBE packets include the QoS. */\r
567         if( type == IOT_MQTT_SUBSCRIBE )\r
568         {\r
569             subscriptionPacketSize += 1;\r
570         }\r
571         else\r
572         {\r
573             EMPTY_ELSE_MARKER;\r
574         }\r
575     }\r
576 \r
577     /* At this point, the "Remaining length" has been calculated. Return error\r
578      * if the "Remaining length" exceeds what is allowed by MQTT 3.1.1. Otherwise,\r
579      * set the output parameter.*/\r
580     if( subscriptionPacketSize > MQTT_MAX_REMAINING_LENGTH )\r
581     {\r
582         status = false;\r
583     }\r
584     else\r
585     {\r
586         *pRemainingLength = subscriptionPacketSize;\r
587 \r
588         /* Calculate the full size of the subscription packet by adding the size of the\r
589          * "Remaining length" field plus 1 byte for the "Packet type" field. Set the\r
590          * pPacketSize output parameter. */\r
591         subscriptionPacketSize += 1 + _remainingLengthEncodedSize( subscriptionPacketSize );\r
592         *pPacketSize = subscriptionPacketSize;\r
593     }\r
594 \r
595     return status;\r
596 }\r
597 \r
598 /*-----------------------------------------------------------*/\r
599 \r
600 uint8_t _IotMqtt_GetPacketType( void * pNetworkConnection,\r
601                                 const IotNetworkInterface_t * pNetworkInterface )\r
602 {\r
603     uint8_t packetType = 0xff;\r
604 \r
605     /* The MQTT packet type is in the first byte of the packet. */\r
606     ( void ) _IotMqtt_GetNextByte( pNetworkConnection,\r
607                                    pNetworkInterface,\r
608                                    &packetType );\r
609 \r
610     return packetType;\r
611 }\r
612 \r
613 /*-----------------------------------------------------------*/\r
614 \r
615 size_t _IotMqtt_GetRemainingLength( void * pNetworkConnection,\r
616                                     const IotNetworkInterface_t * pNetworkInterface )\r
617 {\r
618     uint8_t encodedByte = 0;\r
619     size_t remainingLength = 0, multiplier = 1, bytesDecoded = 0, expectedSize = 0;\r
620 \r
621     /* This algorithm is copied from the MQTT v3.1.1 spec. */\r
622     do\r
623     {\r
624         if( multiplier > 2097152 ) /* 128 ^ 3 */\r
625         {\r
626             remainingLength = MQTT_REMAINING_LENGTH_INVALID;\r
627             break;\r
628         }\r
629         else\r
630         {\r
631             if( _IotMqtt_GetNextByte( pNetworkConnection,\r
632                                       pNetworkInterface,\r
633                                       &encodedByte ) == true )\r
634             {\r
635                 remainingLength += ( encodedByte & 0x7F ) * multiplier;\r
636                 multiplier *= 128;\r
637                 bytesDecoded++;\r
638             }\r
639             else\r
640             {\r
641                 remainingLength = MQTT_REMAINING_LENGTH_INVALID;\r
642                 break;\r
643             }\r
644         }\r
645     } while( ( encodedByte & 0x80 ) != 0 );\r
646 \r
647     /* Check that the decoded remaining length conforms to the MQTT specification. */\r
648     if( remainingLength != MQTT_REMAINING_LENGTH_INVALID )\r
649     {\r
650         expectedSize = _remainingLengthEncodedSize( remainingLength );\r
651 \r
652         if( bytesDecoded != expectedSize )\r
653         {\r
654             remainingLength = MQTT_REMAINING_LENGTH_INVALID;\r
655         }\r
656         else\r
657         {\r
658             /* Valid remaining length should be at most 4 bytes. */\r
659             IotMqtt_Assert( bytesDecoded <= 4 );\r
660         }\r
661     }\r
662     else\r
663     {\r
664         EMPTY_ELSE_MARKER;\r
665     }\r
666 \r
667     return remainingLength;\r
668 }\r
669 \r
670 /*-----------------------------------------------------------*/\r
671 \r
672 IotMqttError_t _IotMqtt_SerializeConnect( const IotMqttConnectInfo_t * pConnectInfo,\r
673                                           uint8_t ** pConnectPacket,\r
674                                           size_t * pPacketSize )\r
675 {\r
676     IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS );\r
677     uint8_t connectFlags = 0;\r
678     size_t remainingLength = 0, connectPacketSize = 0;\r
679     uint8_t * pBuffer = NULL;\r
680 \r
681     /* Calculate the "Remaining length" field and total packet size. If it exceeds\r
682      * what is allowed in the MQTT standard, return an error. */\r
683     if( _connectPacketSize( pConnectInfo, &remainingLength, &connectPacketSize ) == false )\r
684     {\r
685         IotLogError( "Connect packet length exceeds %lu, which is the maximum"\r
686                      " size allowed by MQTT 3.1.1.",\r
687                      MQTT_PACKET_CONNECT_MAX_SIZE );\r
688 \r
689         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER );\r
690     }\r
691     else\r
692     {\r
693         EMPTY_ELSE_MARKER;\r
694     }\r
695 \r
696     /* Total size of the connect packet should be larger than the "Remaining length"\r
697      * field. */\r
698     IotMqtt_Assert( connectPacketSize > remainingLength );\r
699 \r
700     /* Allocate memory to hold the CONNECT packet. */\r
701     pBuffer = IotMqtt_MallocMessage( connectPacketSize );\r
702 \r
703     /* Check that sufficient memory was allocated. */\r
704     if( pBuffer == NULL )\r
705     {\r
706         IotLogError( "Failed to allocate memory for CONNECT packet." );\r
707 \r
708         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_NO_MEMORY );\r
709     }\r
710     else\r
711     {\r
712         EMPTY_ELSE_MARKER;\r
713     }\r
714 \r
715     /* Set the output parameters. The remainder of this function always succeeds. */\r
716     *pConnectPacket = pBuffer;\r
717     *pPacketSize = connectPacketSize;\r
718 \r
719     /* The first byte in the CONNECT packet is the control packet type. */\r
720     *pBuffer = MQTT_PACKET_TYPE_CONNECT;\r
721     pBuffer++;\r
722 \r
723     /* The remaining length of the CONNECT packet is encoded starting from the\r
724      * second byte. The remaining length does not include the length of the fixed\r
725      * header or the encoding of the remaining length. */\r
726     pBuffer = _encodeRemainingLength( pBuffer, remainingLength );\r
727 \r
728     /* The string "MQTT" is placed at the beginning of the CONNECT packet's variable\r
729      * header. This string is 4 bytes long. */\r
730     pBuffer = _encodeString( pBuffer, "MQTT", 4 );\r
731 \r
732     /* The MQTT protocol version is the second byte of the variable header. */\r
733     *pBuffer = MQTT_VERSION_3_1_1;\r
734     pBuffer++;\r
735 \r
736     /* Set the CONNECT flags based on the given parameters. */\r
737     if( pConnectInfo->cleanSession == true )\r
738     {\r
739         UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_CLEAN );\r
740     }\r
741     else\r
742     {\r
743         EMPTY_ELSE_MARKER;\r
744     }\r
745 \r
746     /* Username and password depend on MQTT mode. */\r
747     if( pConnectInfo->awsIotMqttMode == true )\r
748     {\r
749         /* Set the username flag for AWS IoT metrics. The AWS IoT MQTT server\r
750          * never uses a password. */\r
751         #if AWS_IOT_MQTT_ENABLE_METRICS == 1\r
752             UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_USERNAME );\r
753         #endif\r
754     }\r
755     else\r
756     {\r
757         /* Set the flags for username and password if provided. */\r
758         if( pConnectInfo->pUserName != NULL )\r
759         {\r
760             UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_USERNAME );\r
761         }\r
762         else\r
763         {\r
764             EMPTY_ELSE_MARKER;\r
765         }\r
766 \r
767         if( pConnectInfo->pPassword != NULL )\r
768         {\r
769             UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_PASSWORD );\r
770         }\r
771         else\r
772         {\r
773             EMPTY_ELSE_MARKER;\r
774         }\r
775     }\r
776 \r
777     /* Set will flag if an LWT is provided. */\r
778     if( pConnectInfo->pWillInfo != NULL )\r
779     {\r
780         UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_WILL );\r
781 \r
782         /* Flags only need to be changed for will QoS 1 and 2. */\r
783         switch( pConnectInfo->pWillInfo->qos )\r
784         {\r
785             case IOT_MQTT_QOS_1:\r
786                 UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_WILL_QOS1 );\r
787                 break;\r
788 \r
789             case IOT_MQTT_QOS_2:\r
790                 UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_WILL_QOS2 );\r
791                 break;\r
792 \r
793             default:\r
794                 break;\r
795         }\r
796 \r
797         if( pConnectInfo->pWillInfo->retain == true )\r
798         {\r
799             UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_WILL_RETAIN );\r
800         }\r
801         else\r
802         {\r
803             EMPTY_ELSE_MARKER;\r
804         }\r
805     }\r
806     else\r
807     {\r
808         EMPTY_ELSE_MARKER;\r
809     }\r
810 \r
811     *pBuffer = connectFlags;\r
812     pBuffer++;\r
813 \r
814     /* Write the 2 bytes of the keep alive interval into the CONNECT packet. */\r
815     *pBuffer = UINT16_HIGH_BYTE( pConnectInfo->keepAliveSeconds );\r
816     *( pBuffer + 1 ) = UINT16_LOW_BYTE( pConnectInfo->keepAliveSeconds );\r
817     pBuffer += 2;\r
818 \r
819     /* Write the client identifier into the CONNECT packet. */\r
820     pBuffer = _encodeString( pBuffer,\r
821                              pConnectInfo->pClientIdentifier,\r
822                              pConnectInfo->clientIdentifierLength );\r
823 \r
824     /* Write the will topic name and message into the CONNECT packet if provided. */\r
825     if( pConnectInfo->pWillInfo != NULL )\r
826     {\r
827         pBuffer = _encodeString( pBuffer,\r
828                                  pConnectInfo->pWillInfo->pTopicName,\r
829                                  pConnectInfo->pWillInfo->topicNameLength );\r
830 \r
831         pBuffer = _encodeString( pBuffer,\r
832                                  pConnectInfo->pWillInfo->pPayload,\r
833                                  ( uint16_t ) pConnectInfo->pWillInfo->payloadLength );\r
834     }\r
835     else\r
836     {\r
837         EMPTY_ELSE_MARKER;\r
838     }\r
839 \r
840     /* If metrics are enabled, write the metrics username into the CONNECT packet.\r
841      * Otherwise, write the username and password only when not connecting to an\r
842      * AWS IoT MQTT server. */\r
843     if( pConnectInfo->awsIotMqttMode == true )\r
844     {\r
845         #if AWS_IOT_MQTT_ENABLE_METRICS == 1\r
846             IotLogInfo( "Anonymous metrics (SDK language, SDK version) will be provided to AWS IoT. "\r
847                         "Recompile with AWS_IOT_MQTT_ENABLE_METRICS set to 0 to disable." );\r
848 \r
849             pBuffer = _encodeString( pBuffer,\r
850                                      AWS_IOT_METRICS_USERNAME,\r
851                                      AWS_IOT_METRICS_USERNAME_LENGTH );\r
852         #endif\r
853     }\r
854     else\r
855     {\r
856         if( pConnectInfo->pUserName != NULL )\r
857         {\r
858             pBuffer = _encodeString( pBuffer,\r
859                                      pConnectInfo->pUserName,\r
860                                      pConnectInfo->userNameLength );\r
861         }\r
862         else\r
863         {\r
864             EMPTY_ELSE_MARKER;\r
865         }\r
866 \r
867         if( pConnectInfo->pPassword != NULL )\r
868         {\r
869             pBuffer = _encodeString( pBuffer,\r
870                                      pConnectInfo->pPassword,\r
871                                      pConnectInfo->passwordLength );\r
872         }\r
873         else\r
874         {\r
875             EMPTY_ELSE_MARKER;\r
876         }\r
877     }\r
878 \r
879     /* Ensure that the difference between the end and beginning of the buffer\r
880      * is equal to connectPacketSize, i.e. pBuffer did not overflow. */\r
881     IotMqtt_Assert( ( size_t ) ( pBuffer - *pConnectPacket ) == connectPacketSize );\r
882 \r
883     /* Print out the serialized CONNECT packet for debugging purposes. */\r
884     IotLog_PrintBuffer( "MQTT CONNECT packet:", *pConnectPacket, connectPacketSize );\r
885 \r
886     IOT_FUNCTION_EXIT_NO_CLEANUP();\r
887 }\r
888 \r
889 /*-----------------------------------------------------------*/\r
890 \r
891 IotMqttError_t _IotMqtt_DeserializeConnack( _mqttPacket_t * pConnack )\r
892 {\r
893     IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS );\r
894     const uint8_t * pRemainingData = pConnack->pRemainingData;\r
895 \r
896     /* If logging is enabled, declare the CONNACK response code strings. The\r
897      * fourth byte of CONNACK indexes into this array for the corresponding response. */\r
898     #if LIBRARY_LOG_LEVEL > IOT_LOG_NONE\r
899         static const char * pConnackResponses[ 6 ] =\r
900         {\r
901             "Connection accepted.",                               /* 0 */\r
902             "Connection refused: unacceptable protocol version.", /* 1 */\r
903             "Connection refused: identifier rejected.",           /* 2 */\r
904             "Connection refused: server unavailable",             /* 3 */\r
905             "Connection refused: bad user name or password.",     /* 4 */\r
906             "Connection refused: not authorized."                 /* 5 */\r
907         };\r
908     #endif\r
909 \r
910     /* Check that the control packet type is 0x20. */\r
911     if( pConnack->type != MQTT_PACKET_TYPE_CONNACK )\r
912     {\r
913         IotLog( IOT_LOG_ERROR,\r
914                 &_logHideAll,\r
915                 "Bad control packet type 0x%02x.",\r
916                 pConnack->type );\r
917 \r
918         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
919     }\r
920     else\r
921     {\r
922         EMPTY_ELSE_MARKER;\r
923     }\r
924 \r
925     /* According to MQTT 3.1.1, the second byte of CONNACK must specify a\r
926      * "Remaining length" of 2. */\r
927     if( pConnack->remainingLength != MQTT_PACKET_CONNACK_REMAINING_LENGTH )\r
928     {\r
929         IotLog( IOT_LOG_ERROR,\r
930                 &_logHideAll,\r
931                 "CONNACK does not have remaining length of %d.",\r
932                 MQTT_PACKET_CONNACK_REMAINING_LENGTH );\r
933 \r
934         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
935     }\r
936     else\r
937     {\r
938         EMPTY_ELSE_MARKER;\r
939     }\r
940 \r
941     /* Check the reserved bits in CONNACK. The high 7 bits of the second byte\r
942      * in CONNACK must be 0. */\r
943     if( ( pRemainingData[ 0 ] | 0x01 ) != 0x01 )\r
944     {\r
945         IotLog( IOT_LOG_ERROR,\r
946                 &_logHideAll,\r
947                 "Reserved bits in CONNACK incorrect." );\r
948 \r
949         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
950     }\r
951     else\r
952     {\r
953         EMPTY_ELSE_MARKER;\r
954     }\r
955 \r
956     /* Determine if the "Session Present" bit it set. This is the lowest bit of\r
957      * the second byte in CONNACK. */\r
958     if( ( pRemainingData[ 0 ] & MQTT_PACKET_CONNACK_SESSION_PRESENT_MASK )\r
959         == MQTT_PACKET_CONNACK_SESSION_PRESENT_MASK )\r
960     {\r
961         IotLog( IOT_LOG_DEBUG,\r
962                 &_logHideAll,\r
963                 "CONNACK session present bit set." );\r
964 \r
965         /* MQTT 3.1.1 specifies that the fourth byte in CONNACK must be 0 if the\r
966          * "Session Present" bit is set. */\r
967         if( pRemainingData[ 1 ] != 0 )\r
968         {\r
969             IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
970         }\r
971         else\r
972         {\r
973             EMPTY_ELSE_MARKER;\r
974         }\r
975     }\r
976     else\r
977     {\r
978         IotLog( IOT_LOG_DEBUG,\r
979                 &_logHideAll,\r
980                 "CONNACK session present bit not set." );\r
981     }\r
982 \r
983     /* In MQTT 3.1.1, only values 0 through 5 are valid CONNACK response codes. */\r
984     if( pRemainingData[ 1 ] > 5 )\r
985     {\r
986         IotLog( IOT_LOG_DEBUG,\r
987                 &_logHideAll,\r
988                 "CONNACK response %hhu is not valid.",\r
989                 pRemainingData[ 1 ] );\r
990 \r
991         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
992     }\r
993     else\r
994     {\r
995         EMPTY_ELSE_MARKER;\r
996     }\r
997 \r
998     /* Print the appropriate message for the CONNACK response code if logs are\r
999      * enabled. */\r
1000     #if LIBRARY_LOG_LEVEL > IOT_LOG_NONE\r
1001         IotLog( IOT_LOG_DEBUG,\r
1002                 &_logHideAll,\r
1003                 "%s",\r
1004                 pConnackResponses[ pRemainingData[ 1 ] ] );\r
1005     #endif\r
1006 \r
1007     /* A nonzero CONNACK response code means the connection was refused. */\r
1008     if( pRemainingData[ 1 ] > 0 )\r
1009     {\r
1010         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_SERVER_REFUSED );\r
1011     }\r
1012     else\r
1013     {\r
1014         EMPTY_ELSE_MARKER;\r
1015     }\r
1016 \r
1017     IOT_FUNCTION_EXIT_NO_CLEANUP();\r
1018 }\r
1019 \r
1020 /*-----------------------------------------------------------*/\r
1021 \r
1022 IotMqttError_t _IotMqtt_SerializePublish( const IotMqttPublishInfo_t * pPublishInfo,\r
1023                                           uint8_t ** pPublishPacket,\r
1024                                           size_t * pPacketSize,\r
1025                                           uint16_t * pPacketIdentifier,\r
1026                                           uint8_t ** pPacketIdentifierHigh )\r
1027 {\r
1028     IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS );\r
1029     uint8_t publishFlags = 0;\r
1030     uint16_t packetIdentifier = 0;\r
1031     size_t remainingLength = 0, publishPacketSize = 0;\r
1032     uint8_t * pBuffer = NULL;\r
1033 \r
1034     /* Calculate the "Remaining length" field and total packet size. If it exceeds\r
1035      * what is allowed in the MQTT standard, return an error. */\r
1036     if( _publishPacketSize( pPublishInfo, &remainingLength, &publishPacketSize ) == false )\r
1037     {\r
1038         IotLogError( "Publish packet remaining length exceeds %lu, which is the "\r
1039                      "maximum size allowed by MQTT 3.1.1.",\r
1040                      MQTT_MAX_REMAINING_LENGTH );\r
1041 \r
1042         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER );\r
1043     }\r
1044     else\r
1045     {\r
1046         EMPTY_ELSE_MARKER;\r
1047     }\r
1048 \r
1049     /* Total size of the publish packet should be larger than the "Remaining length"\r
1050      * field. */\r
1051     IotMqtt_Assert( publishPacketSize > remainingLength );\r
1052 \r
1053     /* Allocate memory to hold the PUBLISH packet. */\r
1054     pBuffer = IotMqtt_MallocMessage( publishPacketSize );\r
1055 \r
1056     /* Check that sufficient memory was allocated. */\r
1057     if( pBuffer == NULL )\r
1058     {\r
1059         IotLogError( "Failed to allocate memory for PUBLISH packet." );\r
1060 \r
1061         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_NO_MEMORY );\r
1062     }\r
1063     else\r
1064     {\r
1065         EMPTY_ELSE_MARKER;\r
1066     }\r
1067 \r
1068     /* Set the output parameters. The remainder of this function always succeeds. */\r
1069     *pPublishPacket = pBuffer;\r
1070     *pPacketSize = publishPacketSize;\r
1071 \r
1072     /* The first byte of a PUBLISH packet contains the packet type and flags. */\r
1073     publishFlags = MQTT_PACKET_TYPE_PUBLISH;\r
1074 \r
1075     if( pPublishInfo->qos == IOT_MQTT_QOS_1 )\r
1076     {\r
1077         UINT8_SET_BIT( publishFlags, MQTT_PUBLISH_FLAG_QOS1 );\r
1078     }\r
1079     else if( pPublishInfo->qos == IOT_MQTT_QOS_2 )\r
1080     {\r
1081         UINT8_SET_BIT( publishFlags, MQTT_PUBLISH_FLAG_QOS2 );\r
1082     }\r
1083     else\r
1084     {\r
1085         EMPTY_ELSE_MARKER;\r
1086     }\r
1087 \r
1088     if( pPublishInfo->retain == true )\r
1089     {\r
1090         UINT8_SET_BIT( publishFlags, MQTT_PUBLISH_FLAG_RETAIN );\r
1091     }\r
1092     else\r
1093     {\r
1094         EMPTY_ELSE_MARKER;\r
1095     }\r
1096 \r
1097     *pBuffer = publishFlags;\r
1098     pBuffer++;\r
1099 \r
1100     /* The "Remaining length" is encoded from the second byte. */\r
1101     pBuffer = _encodeRemainingLength( pBuffer, remainingLength );\r
1102 \r
1103     /* The topic name is placed after the "Remaining length". */\r
1104     pBuffer = _encodeString( pBuffer,\r
1105                              pPublishInfo->pTopicName,\r
1106                              pPublishInfo->topicNameLength );\r
1107 \r
1108     /* A packet identifier is required for QoS 1 and 2 messages. */\r
1109     if( pPublishInfo->qos > IOT_MQTT_QOS_0 )\r
1110     {\r
1111         /* Get the next packet identifier. It should always be nonzero. */\r
1112         packetIdentifier = _nextPacketIdentifier();\r
1113         IotMqtt_Assert( packetIdentifier != 0 );\r
1114 \r
1115         /* Set the packet identifier output parameters. */\r
1116         *pPacketIdentifier = packetIdentifier;\r
1117 \r
1118         if( pPacketIdentifierHigh != NULL )\r
1119         {\r
1120             *pPacketIdentifierHigh = pBuffer;\r
1121         }\r
1122         else\r
1123         {\r
1124             EMPTY_ELSE_MARKER;\r
1125         }\r
1126 \r
1127         /* Place the packet identifier into the PUBLISH packet. */\r
1128         *pBuffer = UINT16_HIGH_BYTE( packetIdentifier );\r
1129         *( pBuffer + 1 ) = UINT16_LOW_BYTE( packetIdentifier );\r
1130         pBuffer += 2;\r
1131     }\r
1132     else\r
1133     {\r
1134         EMPTY_ELSE_MARKER;\r
1135     }\r
1136 \r
1137     /* The payload is placed after the packet identifier. */\r
1138     if( pPublishInfo->payloadLength > 0 )\r
1139     {\r
1140         ( void ) memcpy( pBuffer, pPublishInfo->pPayload, pPublishInfo->payloadLength );\r
1141         pBuffer += pPublishInfo->payloadLength;\r
1142     }\r
1143     else\r
1144     {\r
1145         EMPTY_ELSE_MARKER;\r
1146     }\r
1147 \r
1148     /* Ensure that the difference between the end and beginning of the buffer\r
1149      * is equal to publishPacketSize, i.e. pBuffer did not overflow. */\r
1150     IotMqtt_Assert( ( size_t ) ( pBuffer - *pPublishPacket ) == publishPacketSize );\r
1151 \r
1152     /* Print out the serialized PUBLISH packet for debugging purposes. */\r
1153     IotLog_PrintBuffer( "MQTT PUBLISH packet:", *pPublishPacket, publishPacketSize );\r
1154 \r
1155     IOT_FUNCTION_EXIT_NO_CLEANUP();\r
1156 }\r
1157 \r
1158 /*-----------------------------------------------------------*/\r
1159 \r
1160 void _IotMqtt_PublishSetDup( uint8_t * pPublishPacket,\r
1161                              uint8_t * pPacketIdentifierHigh,\r
1162                              uint16_t * pNewPacketIdentifier )\r
1163 {\r
1164     uint16_t newPacketIdentifier = 0;\r
1165 \r
1166     /* For an AWS IoT MQTT server, change the packet identifier. */\r
1167     if( pPacketIdentifierHigh != NULL )\r
1168     {\r
1169         /* Output parameter for new packet identifier must be provided. */\r
1170         IotMqtt_Assert( pNewPacketIdentifier != NULL );\r
1171 \r
1172         /* Generate a new packet identifier. */\r
1173         newPacketIdentifier = _nextPacketIdentifier();\r
1174 \r
1175         IotLogDebug( "Changing PUBLISH packet identifier %hu to %hu.",\r
1176                      UINT16_DECODE( pPacketIdentifierHigh ),\r
1177                      newPacketIdentifier );\r
1178 \r
1179         /* Replace the packet identifier. */\r
1180         *pPacketIdentifierHigh = UINT16_HIGH_BYTE( newPacketIdentifier );\r
1181         *( pPacketIdentifierHigh + 1 ) = UINT16_LOW_BYTE( newPacketIdentifier );\r
1182         *pNewPacketIdentifier = newPacketIdentifier;\r
1183     }\r
1184     else\r
1185     {\r
1186         /* For a compliant MQTT 3.1.1 server, set the DUP flag. */\r
1187         UINT8_SET_BIT( *pPublishPacket, MQTT_PUBLISH_FLAG_DUP );\r
1188 \r
1189         IotLogDebug( "PUBLISH DUP flag set." );\r
1190     }\r
1191 }\r
1192 \r
1193 /*-----------------------------------------------------------*/\r
1194 \r
1195 IotMqttError_t _IotMqtt_DeserializePublish( _mqttPacket_t * pPublish )\r
1196 {\r
1197     IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS );\r
1198     IotMqttPublishInfo_t * pOutput = &( pPublish->u.pIncomingPublish->u.publish.publishInfo );\r
1199     uint8_t publishFlags = 0;\r
1200     const uint8_t * pVariableHeader = pPublish->pRemainingData, * pPacketIdentifierHigh = NULL;\r
1201 \r
1202     /* The flags are the lower 4 bits of the first byte in PUBLISH. */\r
1203     publishFlags = pPublish->type;\r
1204 \r
1205     /* Parse the Retain bit. */\r
1206     pOutput->retain = UINT8_CHECK_BIT( publishFlags, MQTT_PUBLISH_FLAG_RETAIN );\r
1207 \r
1208     IotLog( IOT_LOG_DEBUG,\r
1209             &_logHideAll,\r
1210             "Retain bit is %d.", pOutput->retain );\r
1211 \r
1212     /* Check for QoS 2. */\r
1213     if( UINT8_CHECK_BIT( publishFlags, MQTT_PUBLISH_FLAG_QOS2 ) == true )\r
1214     {\r
1215         /* PUBLISH packet is invalid if both QoS 1 and QoS 2 bits are set. */\r
1216         if( UINT8_CHECK_BIT( publishFlags, MQTT_PUBLISH_FLAG_QOS1 ) == true )\r
1217         {\r
1218             IotLog( IOT_LOG_DEBUG,\r
1219                     &_logHideAll,\r
1220                     "Bad QoS: 3." );\r
1221 \r
1222             IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
1223         }\r
1224         else\r
1225         {\r
1226             EMPTY_ELSE_MARKER;\r
1227         }\r
1228 \r
1229         pOutput->qos = IOT_MQTT_QOS_2;\r
1230     }\r
1231     /* Check for QoS 1. */\r
1232     else if( UINT8_CHECK_BIT( publishFlags, MQTT_PUBLISH_FLAG_QOS1 ) == true )\r
1233     {\r
1234         pOutput->qos = IOT_MQTT_QOS_1;\r
1235     }\r
1236     /* If the PUBLISH isn't QoS 1 or 2, then it's QoS 0. */\r
1237     else\r
1238     {\r
1239         pOutput->qos = IOT_MQTT_QOS_0;\r
1240     }\r
1241 \r
1242     IotLog( IOT_LOG_DEBUG,\r
1243             &_logHideAll,\r
1244             "QoS is %d.", pOutput->qos );\r
1245 \r
1246     /* Parse the DUP bit. */\r
1247     if( UINT8_CHECK_BIT( publishFlags, MQTT_PUBLISH_FLAG_DUP ) == true )\r
1248     {\r
1249         IotLog( IOT_LOG_DEBUG,\r
1250                 &_logHideAll,\r
1251                 "DUP is 1." );\r
1252     }\r
1253     else\r
1254     {\r
1255         IotLog( IOT_LOG_DEBUG,\r
1256                 &_logHideAll,\r
1257                 "DUP is 0." );\r
1258     }\r
1259 \r
1260     /* Sanity checks for "Remaining length". */\r
1261     if( pOutput->qos == IOT_MQTT_QOS_0 )\r
1262     {\r
1263         /* A QoS 0 PUBLISH must have a remaining length of at least 3 to accommodate\r
1264          * topic name length (2 bytes) and topic name (at least 1 byte). */\r
1265         if( pPublish->remainingLength < 3 )\r
1266         {\r
1267             IotLog( IOT_LOG_DEBUG,\r
1268                     &_logHideAll,\r
1269                     "QoS 0 PUBLISH cannot have a remaining length less than 3." );\r
1270 \r
1271             IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
1272         }\r
1273         else\r
1274         {\r
1275             EMPTY_ELSE_MARKER;\r
1276         }\r
1277     }\r
1278     else\r
1279     {\r
1280         /* A QoS 1 or 2 PUBLISH must have a remaining length of at least 5 to\r
1281          * accommodate a packet identifier as well as the topic name length and\r
1282          * topic name. */\r
1283         if( pPublish->remainingLength < 5 )\r
1284         {\r
1285             IotLog( IOT_LOG_DEBUG,\r
1286                     &_logHideAll,\r
1287                     "QoS 1 or 2 PUBLISH cannot have a remaining length less than 5." );\r
1288 \r
1289             IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
1290         }\r
1291         else\r
1292         {\r
1293             EMPTY_ELSE_MARKER;\r
1294         }\r
1295     }\r
1296 \r
1297     /* Extract the topic name starting from the first byte of the variable header.\r
1298      * The topic name string starts at byte 3 in the variable header. */\r
1299     pOutput->topicNameLength = UINT16_DECODE( pVariableHeader );\r
1300 \r
1301     /* Sanity checks for topic name length and "Remaining length". */\r
1302     if( pOutput->qos == IOT_MQTT_QOS_0 )\r
1303     {\r
1304         /* Check that the "Remaining length" is at least as large as the variable\r
1305          * header. */\r
1306         if( pPublish->remainingLength < pOutput->topicNameLength + sizeof( uint16_t ) )\r
1307         {\r
1308             IotLog( IOT_LOG_DEBUG,\r
1309                     &_logHideAll,\r
1310                     "Remaining length cannot be less than variable header length." );\r
1311 \r
1312             IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
1313         }\r
1314         else\r
1315         {\r
1316             EMPTY_ELSE_MARKER;\r
1317         }\r
1318     }\r
1319     else\r
1320     {\r
1321         /* Check that the "Remaining length" is at least as large as the variable\r
1322          * header. */\r
1323         if( pPublish->remainingLength < pOutput->topicNameLength + 2 * sizeof( uint16_t ) )\r
1324         {\r
1325             IotLog( IOT_LOG_DEBUG,\r
1326                     &_logHideAll,\r
1327                     "Remaining length cannot be less than variable header length." );\r
1328 \r
1329             IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
1330         }\r
1331         else\r
1332         {\r
1333             EMPTY_ELSE_MARKER;\r
1334         }\r
1335     }\r
1336 \r
1337     /* Parse the topic. */\r
1338     pOutput->pTopicName = ( const char * ) ( pVariableHeader + sizeof( uint16_t ) );\r
1339 \r
1340     IotLog( IOT_LOG_DEBUG,\r
1341             &_logHideAll,\r
1342             "Topic name length %hu: %.*s",\r
1343             pOutput->topicNameLength,\r
1344             pOutput->topicNameLength,\r
1345             pOutput->pTopicName );\r
1346 \r
1347     /* Extract the packet identifier for QoS 1 or 2 PUBLISH packets. Packet\r
1348      * identifier starts immediately after the topic name. */\r
1349     pPacketIdentifierHigh = ( const uint8_t * ) ( pOutput->pTopicName + pOutput->topicNameLength );\r
1350 \r
1351     if( pOutput->qos > IOT_MQTT_QOS_0 )\r
1352     {\r
1353         pPublish->packetIdentifier = UINT16_DECODE( pPacketIdentifierHigh );\r
1354 \r
1355         IotLog( IOT_LOG_DEBUG,\r
1356                 &_logHideAll,\r
1357                 "Packet identifier %hu.", pPublish->packetIdentifier );\r
1358 \r
1359         /* Packet identifier cannot be 0. */\r
1360         if( pPublish->packetIdentifier == 0 )\r
1361         {\r
1362             IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
1363         }\r
1364         else\r
1365         {\r
1366             EMPTY_ELSE_MARKER;\r
1367         }\r
1368     }\r
1369     else\r
1370     {\r
1371         EMPTY_ELSE_MARKER;\r
1372     }\r
1373 \r
1374     /* Calculate the length of the payload. QoS 1 or 2 PUBLISH packets contain\r
1375      * a packet identifer, but QoS 0 PUBLISH packets do not. */\r
1376     if( pOutput->qos == IOT_MQTT_QOS_0 )\r
1377     {\r
1378         pOutput->payloadLength = ( pPublish->remainingLength - pOutput->topicNameLength - sizeof( uint16_t ) );\r
1379         pOutput->pPayload = pPacketIdentifierHigh;\r
1380     }\r
1381     else\r
1382     {\r
1383         pOutput->payloadLength = ( pPublish->remainingLength - pOutput->topicNameLength - 2 * sizeof( uint16_t ) );\r
1384         pOutput->pPayload = pPacketIdentifierHigh + sizeof( uint16_t );\r
1385     }\r
1386 \r
1387     IotLog( IOT_LOG_DEBUG,\r
1388             &_logHideAll,\r
1389             "Payload length %hu.", pOutput->payloadLength );\r
1390 \r
1391     IOT_FUNCTION_EXIT_NO_CLEANUP();\r
1392 }\r
1393 \r
1394 /*-----------------------------------------------------------*/\r
1395 \r
1396 IotMqttError_t _IotMqtt_SerializePuback( uint16_t packetIdentifier,\r
1397                                          uint8_t ** pPubackPacket,\r
1398                                          size_t * pPacketSize )\r
1399 {\r
1400     IotMqttError_t status = IOT_MQTT_SUCCESS;\r
1401 \r
1402     /* Allocate memory for PUBACK. */\r
1403     uint8_t * pBuffer = IotMqtt_MallocMessage( MQTT_PACKET_PUBACK_SIZE );\r
1404 \r
1405     if( pBuffer == NULL )\r
1406     {\r
1407         IotLogError( "Failed to allocate memory for PUBACK packet" );\r
1408 \r
1409         status = IOT_MQTT_NO_MEMORY;\r
1410     }\r
1411     else\r
1412     {\r
1413         /* Set the output parameters. The remainder of this function always succeeds. */\r
1414         *pPubackPacket = pBuffer;\r
1415         *pPacketSize = MQTT_PACKET_PUBACK_SIZE;\r
1416 \r
1417         /* Set the 4 bytes in PUBACK. */\r
1418         pBuffer[ 0 ] = MQTT_PACKET_TYPE_PUBACK;\r
1419         pBuffer[ 1 ] = MQTT_PACKET_PUBACK_REMAINING_LENGTH;\r
1420         pBuffer[ 2 ] = UINT16_HIGH_BYTE( packetIdentifier );\r
1421         pBuffer[ 3 ] = UINT16_LOW_BYTE( packetIdentifier );\r
1422 \r
1423         /* Print out the serialized PUBACK packet for debugging purposes. */\r
1424         IotLog_PrintBuffer( "MQTT PUBACK packet:", *pPubackPacket, MQTT_PACKET_PUBACK_SIZE );\r
1425     }\r
1426 \r
1427     return status;\r
1428 }\r
1429 \r
1430 /*-----------------------------------------------------------*/\r
1431 \r
1432 IotMqttError_t _IotMqtt_DeserializePuback( _mqttPacket_t * pPuback )\r
1433 {\r
1434     IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS );\r
1435 \r
1436     /* Check the "Remaining length" of the received PUBACK. */\r
1437     if( pPuback->remainingLength != MQTT_PACKET_PUBACK_REMAINING_LENGTH )\r
1438     {\r
1439         IotLog( IOT_LOG_ERROR,\r
1440                 &_logHideAll,\r
1441                 "PUBACK does not have remaining length of %d.",\r
1442                 MQTT_PACKET_PUBACK_REMAINING_LENGTH );\r
1443 \r
1444         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
1445     }\r
1446     else\r
1447     {\r
1448         EMPTY_ELSE_MARKER;\r
1449     }\r
1450 \r
1451     /* Extract the packet identifier (third and fourth bytes) from PUBACK. */\r
1452     pPuback->packetIdentifier = UINT16_DECODE( pPuback->pRemainingData );\r
1453 \r
1454     IotLog( IOT_LOG_DEBUG,\r
1455             &_logHideAll,\r
1456             "Packet identifier %hu.", pPuback->packetIdentifier );\r
1457 \r
1458     /* Packet identifier cannot be 0. */\r
1459     if( pPuback->packetIdentifier == 0 )\r
1460     {\r
1461         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
1462     }\r
1463     else\r
1464     {\r
1465         EMPTY_ELSE_MARKER;\r
1466     }\r
1467 \r
1468     /* Check that the control packet type is 0x40 (this must be done after the\r
1469      * packet identifier is parsed). */\r
1470     if( pPuback->type != MQTT_PACKET_TYPE_PUBACK )\r
1471     {\r
1472         IotLog( IOT_LOG_ERROR,\r
1473                 &_logHideAll,\r
1474                 "Bad control packet type 0x%02x.",\r
1475                 pPuback->type );\r
1476 \r
1477         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
1478     }\r
1479     else\r
1480     {\r
1481         EMPTY_ELSE_MARKER;\r
1482     }\r
1483 \r
1484     IOT_FUNCTION_EXIT_NO_CLEANUP();\r
1485 }\r
1486 \r
1487 /*-----------------------------------------------------------*/\r
1488 \r
1489 IotMqttError_t _IotMqtt_SerializeSubscribe( const IotMqttSubscription_t * pSubscriptionList,\r
1490                                             size_t subscriptionCount,\r
1491                                             uint8_t ** pSubscribePacket,\r
1492                                             size_t * pPacketSize,\r
1493                                             uint16_t * pPacketIdentifier )\r
1494 {\r
1495     IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS );\r
1496     size_t i = 0, subscribePacketSize = 0, remainingLength = 0;\r
1497     uint16_t packetIdentifier = 0;\r
1498     uint8_t * pBuffer = NULL;\r
1499 \r
1500     /* Calculate the "Remaining length" field and total packet size. If it exceeds\r
1501      * what is allowed in the MQTT standard, return an error. */\r
1502     if( _subscriptionPacketSize( IOT_MQTT_SUBSCRIBE,\r
1503                                  pSubscriptionList,\r
1504                                  subscriptionCount,\r
1505                                  &remainingLength,\r
1506                                  &subscribePacketSize ) == false )\r
1507     {\r
1508         IotLogError( "Subscribe packet remaining length exceeds %lu, which is the "\r
1509                      "maximum size allowed by MQTT 3.1.1.",\r
1510                      MQTT_MAX_REMAINING_LENGTH );\r
1511 \r
1512         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER );\r
1513     }\r
1514     else\r
1515     {\r
1516         EMPTY_ELSE_MARKER;\r
1517     }\r
1518 \r
1519     /* Total size of the subscribe packet should be larger than the "Remaining length"\r
1520      * field. */\r
1521     IotMqtt_Assert( subscribePacketSize > remainingLength );\r
1522 \r
1523     /* Allocate memory to hold the SUBSCRIBE packet. */\r
1524     pBuffer = IotMqtt_MallocMessage( subscribePacketSize );\r
1525 \r
1526     /* Check that sufficient memory was allocated. */\r
1527     if( pBuffer == NULL )\r
1528     {\r
1529         IotLogError( "Failed to allocate memory for SUBSCRIBE packet." );\r
1530 \r
1531         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_NO_MEMORY );\r
1532     }\r
1533     else\r
1534     {\r
1535         EMPTY_ELSE_MARKER;\r
1536     }\r
1537 \r
1538     /* Set the output parameters. The remainder of this function always succeeds. */\r
1539     *pSubscribePacket = pBuffer;\r
1540     *pPacketSize = subscribePacketSize;\r
1541 \r
1542     /* The first byte in SUBSCRIBE is the packet type. */\r
1543     *pBuffer = MQTT_PACKET_TYPE_SUBSCRIBE;\r
1544     pBuffer++;\r
1545 \r
1546     /* Encode the "Remaining length" starting from the second byte. */\r
1547     pBuffer = _encodeRemainingLength( pBuffer, remainingLength );\r
1548 \r
1549     /* Get the next packet identifier. It should always be nonzero. */\r
1550     packetIdentifier = _nextPacketIdentifier();\r
1551     *pPacketIdentifier = packetIdentifier;\r
1552     IotMqtt_Assert( packetIdentifier != 0 );\r
1553 \r
1554     /* Place the packet identifier into the SUBSCRIBE packet. */\r
1555     *pBuffer = UINT16_HIGH_BYTE( packetIdentifier );\r
1556     *( pBuffer + 1 ) = UINT16_LOW_BYTE( packetIdentifier );\r
1557     pBuffer += 2;\r
1558 \r
1559     /* Serialize each subscription topic filter and QoS. */\r
1560     for( i = 0; i < subscriptionCount; i++ )\r
1561     {\r
1562         pBuffer = _encodeString( pBuffer,\r
1563                                  pSubscriptionList[ i ].pTopicFilter,\r
1564                                  pSubscriptionList[ i ].topicFilterLength );\r
1565 \r
1566         /* Place the QoS in the SUBSCRIBE packet. */\r
1567         *pBuffer = ( uint8_t ) ( pSubscriptionList[ i ].qos );\r
1568         pBuffer++;\r
1569     }\r
1570 \r
1571     /* Ensure that the difference between the end and beginning of the buffer\r
1572      * is equal to subscribePacketSize, i.e. pBuffer did not overflow. */\r
1573     IotMqtt_Assert( ( size_t ) ( pBuffer - *pSubscribePacket ) == subscribePacketSize );\r
1574 \r
1575     /* Print out the serialized SUBSCRIBE packet for debugging purposes. */\r
1576     IotLog_PrintBuffer( "MQTT SUBSCRIBE packet:", *pSubscribePacket, subscribePacketSize );\r
1577 \r
1578     IOT_FUNCTION_EXIT_NO_CLEANUP();\r
1579 }\r
1580 \r
1581 /*-----------------------------------------------------------*/\r
1582 \r
1583 IotMqttError_t _IotMqtt_DeserializeSuback( _mqttPacket_t * pSuback )\r
1584 {\r
1585     IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS );\r
1586     size_t i = 0, remainingLength = pSuback->remainingLength;\r
1587     uint8_t subscriptionStatus = 0;\r
1588     const uint8_t * pVariableHeader = pSuback->pRemainingData;\r
1589 \r
1590     /* A SUBACK must have a remaining length of at least 3 to accommodate the\r
1591      * packet identifer and at least 1 return code. */\r
1592     if( remainingLength < 3 )\r
1593     {\r
1594         IotLog( IOT_LOG_DEBUG,\r
1595                 &_logHideAll,\r
1596                 "SUBACK cannot have a remaining length less than 3." );\r
1597 \r
1598         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
1599     }\r
1600     else\r
1601     {\r
1602         EMPTY_ELSE_MARKER;\r
1603     }\r
1604 \r
1605     /* Extract the packet identifier (first 2 bytes of variable header) from SUBACK. */\r
1606     pSuback->packetIdentifier = UINT16_DECODE( pVariableHeader );\r
1607 \r
1608     IotLog( IOT_LOG_DEBUG,\r
1609             &_logHideAll,\r
1610             "Packet identifier %hu.", pSuback->packetIdentifier );\r
1611 \r
1612     /* Check that the control packet type is 0x90 (this must be done after the\r
1613      * packet identifier is parsed). */\r
1614     if( pSuback->type != MQTT_PACKET_TYPE_SUBACK )\r
1615     {\r
1616         IotLog( IOT_LOG_ERROR,\r
1617                 &_logHideAll,\r
1618                 "Bad control packet type 0x%02x.",\r
1619                 pSuback->type );\r
1620 \r
1621         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
1622     }\r
1623     else\r
1624     {\r
1625         EMPTY_ELSE_MARKER;\r
1626     }\r
1627 \r
1628     /* Iterate through each status byte in the SUBACK packet. */\r
1629     for( i = 0; i < remainingLength - sizeof( uint16_t ); i++ )\r
1630     {\r
1631         /* Read a single status byte in SUBACK. */\r
1632         subscriptionStatus = *( pVariableHeader + sizeof( uint16_t ) + i );\r
1633 \r
1634         /* MQTT 3.1.1 defines the following values as status codes. */\r
1635         switch( subscriptionStatus )\r
1636         {\r
1637             case 0x00:\r
1638             case 0x01:\r
1639             case 0x02:\r
1640                 IotLog( IOT_LOG_DEBUG,\r
1641                         &_logHideAll,\r
1642                         "Topic filter %lu accepted, max QoS %hhu.",\r
1643                         ( unsigned long ) i, subscriptionStatus );\r
1644                 break;\r
1645 \r
1646             case 0x80:\r
1647                 IotLog( IOT_LOG_DEBUG,\r
1648                         &_logHideAll,\r
1649                         "Topic filter %lu refused.", ( unsigned long ) i );\r
1650 \r
1651                 /* Remove a rejected subscription from the subscription manager. */\r
1652                 _IotMqtt_RemoveSubscriptionByPacket( pSuback->u.pMqttConnection,\r
1653                                                      pSuback->packetIdentifier,\r
1654                                                      ( int32_t ) i );\r
1655 \r
1656                 status = IOT_MQTT_SERVER_REFUSED;\r
1657 \r
1658                 break;\r
1659 \r
1660             default:\r
1661                 IotLog( IOT_LOG_DEBUG,\r
1662                         &_logHideAll,\r
1663                         "Bad SUBSCRIBE status %hhu.", subscriptionStatus );\r
1664 \r
1665                 status = IOT_MQTT_BAD_RESPONSE;\r
1666 \r
1667                 break;\r
1668         }\r
1669 \r
1670         /* Stop parsing the subscription statuses if a bad response was received. */\r
1671         if( status == IOT_MQTT_BAD_RESPONSE )\r
1672         {\r
1673             break;\r
1674         }\r
1675         else\r
1676         {\r
1677             EMPTY_ELSE_MARKER;\r
1678         }\r
1679     }\r
1680 \r
1681     IOT_FUNCTION_EXIT_NO_CLEANUP();\r
1682 }\r
1683 \r
1684 /*-----------------------------------------------------------*/\r
1685 \r
1686 IotMqttError_t _IotMqtt_SerializeUnsubscribe( const IotMqttSubscription_t * pSubscriptionList,\r
1687                                               size_t subscriptionCount,\r
1688                                               uint8_t ** pUnsubscribePacket,\r
1689                                               size_t * pPacketSize,\r
1690                                               uint16_t * pPacketIdentifier )\r
1691 {\r
1692     IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS );\r
1693     size_t i = 0, unsubscribePacketSize = 0, remainingLength = 0;\r
1694     uint16_t packetIdentifier = 0;\r
1695     uint8_t * pBuffer = NULL;\r
1696 \r
1697     /* Calculate the "Remaining length" field and total packet size. If it exceeds\r
1698      * what is allowed in the MQTT standard, return an error. */\r
1699     if( _subscriptionPacketSize( IOT_MQTT_UNSUBSCRIBE,\r
1700                                  pSubscriptionList,\r
1701                                  subscriptionCount,\r
1702                                  &remainingLength,\r
1703                                  &unsubscribePacketSize ) == false )\r
1704     {\r
1705         IotLogError( "Unsubscribe packet remaining length exceeds %lu, which is the "\r
1706                      "maximum size allowed by MQTT 3.1.1.",\r
1707                      MQTT_MAX_REMAINING_LENGTH );\r
1708 \r
1709         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER );\r
1710     }\r
1711     else\r
1712     {\r
1713         EMPTY_ELSE_MARKER;\r
1714     }\r
1715 \r
1716     /* Total size of the unsubscribe packet should be larger than the "Remaining length"\r
1717      * field. */\r
1718     IotMqtt_Assert( unsubscribePacketSize > remainingLength );\r
1719 \r
1720     /* Allocate memory to hold the UNSUBSCRIBE packet. */\r
1721     pBuffer = IotMqtt_MallocMessage( unsubscribePacketSize );\r
1722 \r
1723     /* Check that sufficient memory was allocated. */\r
1724     if( pBuffer == NULL )\r
1725     {\r
1726         IotLogError( "Failed to allocate memory for UNSUBSCRIBE packet." );\r
1727 \r
1728         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_NO_MEMORY );\r
1729     }\r
1730     else\r
1731     {\r
1732         EMPTY_ELSE_MARKER;\r
1733     }\r
1734 \r
1735     /* Set the output parameters. The remainder of this function always succeeds. */\r
1736     *pUnsubscribePacket = pBuffer;\r
1737     *pPacketSize = unsubscribePacketSize;\r
1738 \r
1739     /* The first byte in UNSUBSCRIBE is the packet type. */\r
1740     *pBuffer = MQTT_PACKET_TYPE_UNSUBSCRIBE;\r
1741     pBuffer++;\r
1742 \r
1743     /* Encode the "Remaining length" starting from the second byte. */\r
1744     pBuffer = _encodeRemainingLength( pBuffer, remainingLength );\r
1745 \r
1746     /* Get the next packet identifier. It should always be nonzero. */\r
1747     packetIdentifier = _nextPacketIdentifier();\r
1748     *pPacketIdentifier = packetIdentifier;\r
1749     IotMqtt_Assert( packetIdentifier != 0 );\r
1750 \r
1751     /* Place the packet identifier into the UNSUBSCRIBE packet. */\r
1752     *pBuffer = UINT16_HIGH_BYTE( packetIdentifier );\r
1753     *( pBuffer + 1 ) = UINT16_LOW_BYTE( packetIdentifier );\r
1754     pBuffer += 2;\r
1755 \r
1756     /* Serialize each subscription topic filter. */\r
1757     for( i = 0; i < subscriptionCount; i++ )\r
1758     {\r
1759         pBuffer = _encodeString( pBuffer,\r
1760                                  pSubscriptionList[ i ].pTopicFilter,\r
1761                                  pSubscriptionList[ i ].topicFilterLength );\r
1762     }\r
1763 \r
1764     /* Ensure that the difference between the end and beginning of the buffer\r
1765      * is equal to unsubscribePacketSize, i.e. pBuffer did not overflow. */\r
1766     IotMqtt_Assert( ( size_t ) ( pBuffer - *pUnsubscribePacket ) == unsubscribePacketSize );\r
1767 \r
1768     /* Print out the serialized UNSUBSCRIBE packet for debugging purposes. */\r
1769     IotLog_PrintBuffer( "MQTT UNSUBSCRIBE packet:", *pUnsubscribePacket, unsubscribePacketSize );\r
1770 \r
1771     IOT_FUNCTION_EXIT_NO_CLEANUP();\r
1772 }\r
1773 \r
1774 /*-----------------------------------------------------------*/\r
1775 \r
1776 IotMqttError_t _IotMqtt_DeserializeUnsuback( _mqttPacket_t * pUnsuback )\r
1777 {\r
1778     IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS );\r
1779 \r
1780     /* Check the "Remaining length" (second byte) of the received UNSUBACK. */\r
1781     if( pUnsuback->remainingLength != MQTT_PACKET_UNSUBACK_REMAINING_LENGTH )\r
1782     {\r
1783         IotLog( IOT_LOG_ERROR,\r
1784                 &_logHideAll,\r
1785                 "UNSUBACK does not have remaining length of %d.",\r
1786                 MQTT_PACKET_UNSUBACK_REMAINING_LENGTH );\r
1787 \r
1788         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
1789     }\r
1790     else\r
1791     {\r
1792         EMPTY_ELSE_MARKER;\r
1793     }\r
1794 \r
1795     /* Extract the packet identifier (third and fourth bytes) from UNSUBACK. */\r
1796     pUnsuback->packetIdentifier = UINT16_DECODE( pUnsuback->pRemainingData );\r
1797 \r
1798     /* Packet identifier cannot be 0. */\r
1799     if( pUnsuback->packetIdentifier == 0 )\r
1800     {\r
1801         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
1802     }\r
1803     else\r
1804     {\r
1805         EMPTY_ELSE_MARKER;\r
1806     }\r
1807 \r
1808     IotLog( IOT_LOG_DEBUG,\r
1809             &_logHideAll,\r
1810             "Packet identifier %hu.", pUnsuback->packetIdentifier );\r
1811 \r
1812     /* Check that the control packet type is 0xb0 (this must be done after the\r
1813      * packet identifier is parsed). */\r
1814     if( pUnsuback->type != MQTT_PACKET_TYPE_UNSUBACK )\r
1815     {\r
1816         IotLog( IOT_LOG_ERROR,\r
1817                 &_logHideAll,\r
1818                 "Bad control packet type 0x%02x.",\r
1819                 pUnsuback->type );\r
1820 \r
1821         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
1822     }\r
1823     else\r
1824     {\r
1825         EMPTY_ELSE_MARKER;\r
1826     }\r
1827 \r
1828     IOT_FUNCTION_EXIT_NO_CLEANUP();\r
1829 }\r
1830 \r
1831 /*-----------------------------------------------------------*/\r
1832 \r
1833 IotMqttError_t _IotMqtt_SerializePingreq( uint8_t ** pPingreqPacket,\r
1834                                           size_t * pPacketSize )\r
1835 {\r
1836     /* PINGREQ packets are always the same. */\r
1837     static const uint8_t pPingreq[ MQTT_PACKET_PINGREQ_SIZE ] =\r
1838     {\r
1839         MQTT_PACKET_TYPE_PINGREQ,\r
1840         0x00\r
1841     };\r
1842 \r
1843     /* Set the output parameters. */\r
1844     *pPingreqPacket = ( uint8_t * ) pPingreq;\r
1845     *pPacketSize = MQTT_PACKET_PINGREQ_SIZE;\r
1846 \r
1847     /* Print out the PINGREQ packet for debugging purposes. */\r
1848     IotLog_PrintBuffer( "MQTT PINGREQ packet:", pPingreq, MQTT_PACKET_PINGREQ_SIZE );\r
1849 \r
1850     return IOT_MQTT_SUCCESS;\r
1851 }\r
1852 \r
1853 /*-----------------------------------------------------------*/\r
1854 \r
1855 IotMqttError_t _IotMqtt_DeserializePingresp( _mqttPacket_t * pPingresp )\r
1856 {\r
1857     IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS );\r
1858 \r
1859     /* Check that the control packet type is 0xd0. */\r
1860     if( pPingresp->type != MQTT_PACKET_TYPE_PINGRESP )\r
1861     {\r
1862         IotLog( IOT_LOG_ERROR,\r
1863                 &_logHideAll,\r
1864                 "Bad control packet type 0x%02x.",\r
1865                 pPingresp->type );\r
1866 \r
1867         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
1868     }\r
1869     else\r
1870     {\r
1871         EMPTY_ELSE_MARKER;\r
1872     }\r
1873 \r
1874     /* Check the "Remaining length" (second byte) of the received PINGRESP. */\r
1875     if( pPingresp->remainingLength != MQTT_PACKET_PINGRESP_REMAINING_LENGTH )\r
1876     {\r
1877         IotLog( IOT_LOG_ERROR,\r
1878                 &_logHideAll,\r
1879                 "PINGRESP does not have remaining length of %d.",\r
1880                 MQTT_PACKET_PINGRESP_REMAINING_LENGTH );\r
1881 \r
1882         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
1883     }\r
1884     else\r
1885     {\r
1886         EMPTY_ELSE_MARKER;\r
1887     }\r
1888 \r
1889     IOT_FUNCTION_EXIT_NO_CLEANUP();\r
1890 }\r
1891 \r
1892 /*-----------------------------------------------------------*/\r
1893 \r
1894 IotMqttError_t _IotMqtt_SerializeDisconnect( uint8_t ** pDisconnectPacket,\r
1895                                              size_t * pPacketSize )\r
1896 {\r
1897     /* DISCONNECT packets are always the same. */\r
1898     static const uint8_t pDisconnect[ MQTT_PACKET_DISCONNECT_SIZE ] =\r
1899     {\r
1900         MQTT_PACKET_TYPE_DISCONNECT,\r
1901         0x00\r
1902     };\r
1903 \r
1904     /* Set the output parameters. */\r
1905     *pDisconnectPacket = ( uint8_t * ) pDisconnect;\r
1906     *pPacketSize = MQTT_PACKET_DISCONNECT_SIZE;\r
1907 \r
1908     /* Print out the DISCONNECT packet for debugging purposes. */\r
1909     IotLog_PrintBuffer( "MQTT DISCONNECT packet:", pDisconnect, MQTT_PACKET_DISCONNECT_SIZE );\r
1910 \r
1911     return IOT_MQTT_SUCCESS;\r
1912 }\r
1913 \r
1914 /*-----------------------------------------------------------*/\r
1915 \r
1916 void _IotMqtt_FreePacket( uint8_t * pPacket )\r
1917 {\r
1918     uint8_t packetType = *pPacket;\r
1919 \r
1920     /* Don't call free on DISCONNECT and PINGREQ; those are allocated from static\r
1921      * memory. */\r
1922     if( packetType != MQTT_PACKET_TYPE_DISCONNECT )\r
1923     {\r
1924         if( packetType != MQTT_PACKET_TYPE_PINGREQ )\r
1925         {\r
1926             IotMqtt_FreeMessage( pPacket );\r
1927         }\r
1928         else\r
1929         {\r
1930             EMPTY_ELSE_MARKER;\r
1931         }\r
1932     }\r
1933     else\r
1934     {\r
1935         EMPTY_ELSE_MARKER;\r
1936     }\r
1937 }\r
1938 \r
1939 /*-----------------------------------------------------------*/\r