]> git.sur5r.net Git - freertos/blob - FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/mqtt/src/iot_mqtt_serialize.c
Add the Labs projects provided in the V10.2.1_191129 zip file.
[freertos] / FreeRTOS-Labs / Source / FreeRTOS-IoT-Libraries / c_sdk / standard / mqtt / src / iot_mqtt_serialize.c
1 /*\r
2  * IoT MQTT V2.1.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 \r
23 /**\r
24  * @file iot_mqtt_serialize.c\r
25  * @brief Implements functions that generate and decode MQTT network packets.\r
26  */\r
27 \r
28 /* The config header is always included first. */\r
29 #include "iot_config.h"\r
30 \r
31 /* Standard includes. */\r
32 #include <string.h>\r
33 \r
34 /* Error handling include. */\r
35 #include "iot_error.h"\r
36 \r
37 /* MQTT internal includes. */\r
38 #include "private/iot_mqtt_internal.h"\r
39 \r
40 /* Platform layer includes. */\r
41 #include "platform/iot_threads.h"\r
42 \r
43 /* Atomic operations. */\r
44 #include "iot_atomic.h"\r
45 \r
46 /*-----------------------------------------------------------*/\r
47 \r
48 /*\r
49  * Macros for reading the high and low byte of a 2-byte unsigned int.\r
50  */\r
51 #define UINT16_HIGH_BYTE( x )    ( ( uint8_t ) ( x >> 8 ) )            /**< @brief Get high byte. */\r
52 #define UINT16_LOW_BYTE( x )     ( ( uint8_t ) ( x & 0x00ff ) )        /**< @brief Get low byte. */\r
53 \r
54 /**\r
55  * @brief Macro for decoding a 2-byte unsigned int from a sequence of bytes.\r
56  *\r
57  * @param[in] ptr A uint8_t* that points to the high byte.\r
58  */\r
59 #define UINT16_DECODE( ptr )                                \\r
60     ( uint16_t ) ( ( ( ( uint16_t ) ( *( ptr ) ) ) << 8 ) | \\r
61                    ( ( uint16_t ) ( *( ptr + 1 ) ) ) )\r
62 \r
63 /**\r
64  * @brief Macro for setting a bit in a 1-byte unsigned int.\r
65  *\r
66  * @param[in] x The unsigned int to set.\r
67  * @param[in] position Which bit to set.\r
68  */\r
69 #define UINT8_SET_BIT( x, position )      ( x = ( uint8_t ) ( x | ( 0x01 << position ) ) )\r
70 \r
71 /**\r
72  * @brief Macro for checking if a bit is set in a 1-byte unsigned int.\r
73  *\r
74  * @param[in] x The unsigned int to check.\r
75  * @param[in] position Which bit to check.\r
76  */\r
77 #define UINT8_CHECK_BIT( x, position )    ( ( x & ( 0x01 << position ) ) == ( 0x01 << position ) )\r
78 \r
79 /*\r
80  * Positions of each flag in the "Connect Flag" field of an MQTT CONNECT\r
81  * packet.\r
82  */\r
83 #define MQTT_CONNECT_FLAG_CLEAN                     ( 1 )  /**< @brief Clean session. */\r
84 #define MQTT_CONNECT_FLAG_WILL                      ( 2 )  /**< @brief Will present. */\r
85 #define MQTT_CONNECT_FLAG_WILL_QOS1                 ( 3 )  /**< @brief Will QoS1. */\r
86 #define MQTT_CONNECT_FLAG_WILL_QOS2                 ( 4 )  /**< @brief Will QoS2. */\r
87 #define MQTT_CONNECT_FLAG_WILL_RETAIN               ( 5 )  /**< @brief Will retain. */\r
88 #define MQTT_CONNECT_FLAG_PASSWORD                  ( 6 )  /**< @brief Password present. */\r
89 #define MQTT_CONNECT_FLAG_USERNAME                  ( 7 )  /**< @brief Username present. */\r
90 \r
91 /*\r
92  * Positions of each flag in the first byte of an MQTT PUBLISH packet's\r
93  * fixed header.\r
94  */\r
95 #define MQTT_PUBLISH_FLAG_RETAIN                    ( 0 )  /**< @brief Message retain flag. */\r
96 #define MQTT_PUBLISH_FLAG_QOS1                      ( 1 )  /**< @brief Publish QoS 1. */\r
97 #define MQTT_PUBLISH_FLAG_QOS2                      ( 2 )  /**< @brief Publish QoS 2. */\r
98 #define MQTT_PUBLISH_FLAG_DUP                       ( 3 )  /**< @brief Duplicate message. */\r
99 \r
100 /**\r
101  * @brief The constant specifying MQTT version 3.1.1. Placed in the CONNECT packet.\r
102  */\r
103 #define MQTT_VERSION_3_1_1                          ( ( uint8_t ) 4U )\r
104 \r
105 /**\r
106  * @brief Per the MQTT 3.1.1 spec, the largest "Remaining Length" of an MQTT\r
107  * packet is this value.\r
108  */\r
109 #define MQTT_MAX_REMAINING_LENGTH                   ( 268435455UL )\r
110 \r
111 /**\r
112  * @brief The maximum possible size of a CONNECT packet.\r
113  *\r
114  * All strings in a CONNECT packet are constrained to 2-byte lengths, giving a\r
115  * maximum length smaller than the max "Remaining Length" constant above.\r
116  */\r
117 #define MQTT_PACKET_CONNECT_MAX_SIZE                ( 327700UL )\r
118 \r
119 /*\r
120  * Constants relating to CONNACK packets, defined by MQTT 3.1.1 spec.\r
121  */\r
122 #define MQTT_PACKET_CONNACK_REMAINING_LENGTH        ( ( uint8_t ) 2 )    /**< @brief A CONNACK packet always has a "Remaining length" of 2. */\r
123 #define MQTT_PACKET_CONNACK_SESSION_PRESENT_MASK    ( ( uint8_t ) 0x01 ) /**< @brief The "Session Present" bit is always the lowest bit. */\r
124 \r
125 /*\r
126  * Constants relating to PUBLISH and PUBACK packets, defined by MQTT\r
127  * 3.1.1 spec.\r
128  */\r
129 #define MQTT_PACKET_PUBACK_SIZE                     ( 4 )               /**< @brief A PUBACK packet is always 4 bytes in size. */\r
130 #define MQTT_PACKET_PUBACK_REMAINING_LENGTH         ( ( uint8_t ) 2 )   /**< @brief A PUBACK packet always has a "Remaining length" of 2. */\r
131 \r
132 /*\r
133  * Constants relating to SUBACK and UNSUBACK packets, defined by MQTT\r
134  * 3.1.1 spec.\r
135  */\r
136 #define MQTT_PACKET_SUBACK_MINIMUM_SIZE             ( 5 )               /**< @brief The size of the smallest valid SUBACK packet. */\r
137 #define MQTT_PACKET_UNSUBACK_REMAINING_LENGTH       ( ( uint8_t ) 2 )   /**< @brief An UNSUBACK packet always has a "Remaining length" of 2. */\r
138 \r
139 /*\r
140  * Constants relating to PINGREQ and PINGRESP packets, defined by MQTT 3.1.1 spec.\r
141  */\r
142 #define MQTT_PACKET_PINGREQ_SIZE                    ( 2 ) /**< @brief A PINGREQ packet is always 2 bytes in size. */\r
143 #define MQTT_PACKET_PINGRESP_REMAINING_LENGTH       ( 0 ) /**< @brief A PINGRESP packet always has a "Remaining length" of 0. */\r
144 \r
145 /*\r
146  * Constants relating to DISCONNECT packets, defined by MQTT 3.1.1 spec.\r
147  */\r
148 #define MQTT_PACKET_DISCONNECT_SIZE                 ( 2 ) /**< @brief A DISCONNECT packet is always 2 bytes in size. */\r
149 \r
150 /* Username for metrics with AWS IoT. */\r
151 #if AWS_IOT_MQTT_ENABLE_METRICS == 1 || DOXYGEN == 1\r
152     #ifndef AWS_IOT_METRICS_USERNAME\r
153 \r
154 /**\r
155  * @brief Specify C SDK and version.\r
156  */\r
157         #define AWS_IOT_METRICS_USERNAME           "?SDK=C&Version=4.0.0"\r
158 \r
159 /**\r
160  * @brief The length of #AWS_IOT_METRICS_USERNAME.\r
161  */\r
162         #define AWS_IOT_METRICS_USERNAME_LENGTH    ( ( uint16_t ) sizeof( AWS_IOT_METRICS_USERNAME ) - 1 )\r
163     #endif /* ifndef AWS_IOT_METRICS_USERNAME */\r
164 #endif /* if AWS_IOT_MQTT_ENABLE_METRICS == 1 || DOXYGEN == 1 */\r
165 \r
166 /*-----------------------------------------------------------*/\r
167 \r
168 /**\r
169  * @brief Generate and return a 2-byte packet identifier.\r
170  *\r
171  * This packet identifier will be nonzero.\r
172  *\r
173  * @return The packet identifier.\r
174  */\r
175 static uint16_t _nextPacketIdentifier( void );\r
176 \r
177 /**\r
178  * @brief Calculate the number of bytes required to encode an MQTT\r
179  * "Remaining length" field.\r
180  *\r
181  * @param[in] length The value of the "Remaining length" to encode.\r
182  *\r
183  * @return The size of the encoding of length. This is always `1`, `2`, `3`, or `4`.\r
184  */\r
185 static size_t _remainingLengthEncodedSize( size_t length );\r
186 \r
187 /**\r
188  * @brief Encode the "Remaining length" field per MQTT spec.\r
189  *\r
190  * @param[out] pDestination Where to write the encoded "Remaining length".\r
191  * @param[in] length The "Remaining length" to encode.\r
192  *\r
193  * @return Pointer to the end of the encoded "Remaining length", which is 1-4\r
194  * bytes greater than `pDestination`.\r
195  *\r
196  * @warning This function does not check the size of `pDestination`! Ensure that\r
197  * `pDestination` is large enough to hold the encoded "Remaining length" using\r
198  * the function #_remainingLengthEncodedSize to avoid buffer overflows.\r
199  */\r
200 static uint8_t * _encodeRemainingLength( uint8_t * pDestination,\r
201                                          size_t length );\r
202 \r
203 /**\r
204  * @brief Encode a C string as a UTF-8 string, per MQTT 3.1.1 spec.\r
205  *\r
206  * @param[out] pDestination Where to write the encoded string.\r
207  * @param[in] source The string to encode.\r
208  * @param[in] sourceLength The length of source.\r
209  *\r
210  * @return Pointer to the end of the encoded string, which is `sourceLength+2`\r
211  * bytes greater than `pDestination`.\r
212  *\r
213  * @warning This function does not check the size of `pDestination`! Ensure that\r
214  * `pDestination` is large enough to hold `sourceLength+2` bytes to avoid a buffer\r
215  * overflow.\r
216  */\r
217 static uint8_t * _encodeString( uint8_t * pDestination,\r
218                                 const char * source,\r
219                                 uint16_t sourceLength );\r
220 \r
221 /**\r
222  * @brief Calculate the size and "Remaining length" of a CONNECT packet generated\r
223  * from the given parameters.\r
224  *\r
225  * @param[in] pConnectInfo User-provided CONNECT information struct.\r
226  * @param[out] pRemainingLength Output for calculated "Remaining length" field.\r
227  * @param[out] pPacketSize Output for calculated total packet size.\r
228  *\r
229  * @return `true` if the packet is within the length allowed by MQTT 3.1.1 spec; `false`\r
230  * otherwise. If this function returns `false`, the output parameters should be ignored.\r
231  */\r
232 static bool _connectPacketSize( const IotMqttConnectInfo_t * pConnectInfo,\r
233                                 size_t * pRemainingLength,\r
234                                 size_t * pPacketSize );\r
235 \r
236 /**\r
237  * @brief Calculate the size and "Remaining length" of a PUBLISH packet generated\r
238  * from the given parameters.\r
239  *\r
240  * @param[in] pPublishInfo User-provided PUBLISH information struct.\r
241  * @param[out] pRemainingLength Output for calculated "Remaining length" field.\r
242  * @param[out] pPacketSize Output for calculated total packet size.\r
243  *\r
244  * @return `true` if the packet is within the length allowed by MQTT 3.1.1 spec; `false`\r
245  * otherwise. If this function returns `false`, the output parameters should be ignored.\r
246  */\r
247 static bool _publishPacketSize( const IotMqttPublishInfo_t * pPublishInfo,\r
248                                 size_t * pRemainingLength,\r
249                                 size_t * pPacketSize );\r
250 \r
251 /**\r
252  * @brief Calculate the size and "Remaining length" of a SUBSCRIBE or UNSUBSCRIBE\r
253  * packet generated from the given parameters.\r
254  *\r
255  * @param[in] type Either IOT_MQTT_SUBSCRIBE or IOT_MQTT_UNSUBSCRIBE.\r
256  * @param[in] pSubscriptionList User-provided array of subscriptions.\r
257  * @param[in] subscriptionCount Size of `pSubscriptionList`.\r
258  * @param[out] pRemainingLength Output for calculated "Remaining length" field.\r
259  * @param[out] pPacketSize Output for calculated total packet size.\r
260  *\r
261  * @return `true` if the packet is within the length allowed by MQTT 3.1.1 spec; `false`\r
262  * otherwise. If this function returns `false`, the output parameters should be ignored.\r
263  */\r
264 static bool _subscriptionPacketSize( IotMqttOperationType_t type,\r
265                                      const IotMqttSubscription_t * pSubscriptionList,\r
266                                      size_t subscriptionCount,\r
267                                      size_t * pRemainingLength,\r
268                                      size_t * pPacketSize );\r
269 \r
270 /**\r
271  * @brief Generate a CONNECT packet from the given parameters.\r
272  *\r
273  * @param[in] pConnectInfo User-provided CONNECT information.\r
274  * @param[in] remainingLength User provided remaining length.\r
275  * @param[in, out] pBuffer User provided buffer where the CONNECT packet is written.\r
276  * @param[in] connectPacketSize Size of the buffer pointed to by `pBuffer`.\r
277  *\r
278  */\r
279 void _serializeConnect( const IotMqttConnectInfo_t * pConnectInfo,\r
280                         size_t remainingLength,\r
281                         uint8_t * pBuffer,\r
282                         size_t connectPacketSize );\r
283 \r
284 /**\r
285  * @brief Generate a PUBLISH packet from the given parameters.\r
286  *\r
287  * @param[in] pPublishInfo User-provided PUBLISH information.\r
288  * @param[in] remainingLength User provided remaining length.\r
289  * @param[out] pPacketIdentifier The packet identifier generated for this PUBLISH.\r
290  * @param[out] pPacketIdentifierHigh Where the high byte of the packet identifier\r
291  * is written.\r
292  * @param[in, out] pBuffer User provided buffer where the PUBLISH packet is written.\r
293  * @param[in] publishPacketSize Size of buffer pointed to by `pBuffer`.\r
294  *\r
295  */\r
296 void _serializePublish( const IotMqttPublishInfo_t * pPublishInfo,\r
297                         size_t remainingLength,\r
298                         uint16_t * pPacketIdentifier,\r
299                         uint8_t ** pPacketIdentifierHigh,\r
300                         uint8_t * pBuffer,\r
301                         size_t publishPacketSize );\r
302 \r
303 /**\r
304  * @brief Generate a SUBSCRIBE packet from the given parameters.\r
305  *\r
306  * @param[in] pSubscriptionList User-provided array of subscriptions.\r
307  * @param[in] subscriptionCount Size of `pSubscriptionList`.\r
308  * @param[in] remainingLength User provided remaining length.\r
309  * @param[out] pPacketIdentifier The packet identifier generated for this SUBSCRIBE.\r
310  * @param[in, out] pBuffer User provided buffer where the SUBSCRIBE packet is written.\r
311  * @param[in] subscribePacketSize Size of the buffer pointed to by  `pBuffer`.\r
312  *\r
313  */\r
314 void _serializeSubscribe( const IotMqttSubscription_t * pSubscriptionList,\r
315                           size_t subscriptionCount,\r
316                           size_t remainingLength,\r
317                           uint16_t * pPacketIdentifier,\r
318                           uint8_t * pBuffer,\r
319                           size_t subscribePacketSize );\r
320 \r
321 /**\r
322  * @brief Generate an UNSUBSCRIBE packet from the given parameters.\r
323  *\r
324  * @param[in] pSubscriptionList User-provided array of subscriptions to remove.\r
325  * @param[in] subscriptionCount Size of `pSubscriptionList`.\r
326  * @param[in] remainingLength User provided remaining length.\r
327  * @param[out] pPacketIdentifier The packet identifier generated for this UNSUBSCRIBE.\r
328  * @param[in, out] pBuffer User provided buffer where the UNSUBSCRIBE packet is written.\r
329  * @param[in] unsubscribePacketSize size of the buffer pointed to by  `pBuffer`.\r
330  *\r
331  */\r
332 void _serializeUnsubscribe( const IotMqttSubscription_t * pSubscriptionList,\r
333                             size_t subscriptionCount,\r
334                             size_t remainingLength,\r
335                             uint16_t * pPacketIdentifier,\r
336                             uint8_t * pBuffer,\r
337                             size_t unsubscribePacketSize );\r
338 \r
339 /*-----------------------------------------------------------*/\r
340 \r
341 #if LIBRARY_LOG_LEVEL > IOT_LOG_NONE\r
342 \r
343 /**\r
344  * @brief If logging is enabled, define a log configuration that only prints the log\r
345  * string. This is used when printing out details of deserialized MQTT packets.\r
346  */\r
347     static const IotLogConfig_t _logHideAll =\r
348     {\r
349         .hideLibraryName = true,\r
350         .hideLogLevel    = true,\r
351         .hideTimestring  = true\r
352     };\r
353 #endif\r
354 \r
355 /*-----------------------------------------------------------*/\r
356 \r
357 static uint16_t _nextPacketIdentifier( void )\r
358 {\r
359     /* MQTT specifies 2 bytes for the packet identifier; however, operating on\r
360      * 32-bit integers is generally faster. */\r
361     static uint32_t nextPacketIdentifier = 1;\r
362 \r
363     /* The next packet identifier will be greater by 2. This prevents packet\r
364      * identifiers from ever being 0, which is not allowed by MQTT 3.1.1. Packet\r
365      * identifiers will follow the sequence 1,3,5...65535,1,3,5... */\r
366     return ( uint16_t ) Atomic_Add_u32( &nextPacketIdentifier, 2 );\r
367 }\r
368 \r
369 /*-----------------------------------------------------------*/\r
370 \r
371 static size_t _remainingLengthEncodedSize( size_t length )\r
372 {\r
373     size_t encodedSize = 0;\r
374 \r
375     /* length should have already been checked before calling this function. */\r
376     IotMqtt_Assert( length <= MQTT_MAX_REMAINING_LENGTH );\r
377 \r
378     /* Determine how many bytes are needed to encode length.\r
379      * The values below are taken from the MQTT 3.1.1 spec. */\r
380 \r
381     /* 1 byte is needed to encode lengths between 0 and 127. */\r
382     if( length < 128 )\r
383     {\r
384         encodedSize = 1;\r
385     }\r
386     /* 2 bytes are needed to encode lengths between 128 and 16,383. */\r
387     else if( length < 16384 )\r
388     {\r
389         encodedSize = 2;\r
390     }\r
391     /* 3 bytes are needed to encode lengths between 16,384 and 2,097,151. */\r
392     else if( length < 2097152 )\r
393     {\r
394         encodedSize = 3;\r
395     }\r
396     /* 4 bytes are needed to encode lengths between 2,097,152 and 268,435,455. */\r
397     else\r
398     {\r
399         encodedSize = 4;\r
400     }\r
401 \r
402     return encodedSize;\r
403 }\r
404 \r
405 /*-----------------------------------------------------------*/\r
406 \r
407 static uint8_t * _encodeRemainingLength( uint8_t * pDestination,\r
408                                          size_t length )\r
409 {\r
410     uint8_t lengthByte = 0, * pLengthEnd = pDestination;\r
411 \r
412     /* This algorithm is copied from the MQTT v3.1.1 spec. */\r
413     do\r
414     {\r
415         lengthByte = length % 128;\r
416         length = length / 128;\r
417 \r
418         /* Set the high bit of this byte, indicating that there's more data. */\r
419         if( length > 0 )\r
420         {\r
421             UINT8_SET_BIT( lengthByte, 7 );\r
422         }\r
423         else\r
424         {\r
425             EMPTY_ELSE_MARKER;\r
426         }\r
427 \r
428         /* Output a single encoded byte. */\r
429         *pLengthEnd = lengthByte;\r
430         pLengthEnd++;\r
431     } while( length > 0 );\r
432 \r
433     return pLengthEnd;\r
434 }\r
435 \r
436 /*-----------------------------------------------------------*/\r
437 \r
438 static uint8_t * _encodeString( uint8_t * pDestination,\r
439                                 const char * source,\r
440                                 uint16_t sourceLength )\r
441 {\r
442     /* The first byte of a UTF-8 string is the high byte of the string length. */\r
443     *pDestination = UINT16_HIGH_BYTE( sourceLength );\r
444     pDestination++;\r
445 \r
446     /* The second byte of a UTF-8 string is the low byte of the string length. */\r
447     *pDestination = UINT16_LOW_BYTE( sourceLength );\r
448     pDestination++;\r
449 \r
450     /* Copy the string into pDestination. */\r
451     ( void ) memcpy( pDestination, source, sourceLength );\r
452 \r
453     /* Return the pointer to the end of the encoded string. */\r
454     pDestination += sourceLength;\r
455 \r
456     return pDestination;\r
457 }\r
458 \r
459 /*-----------------------------------------------------------*/\r
460 \r
461 static bool _connectPacketSize( const IotMqttConnectInfo_t * pConnectInfo,\r
462                                 size_t * pRemainingLength,\r
463                                 size_t * pPacketSize )\r
464 {\r
465     bool status = true;\r
466     size_t connectPacketSize = 0, remainingLength = 0;\r
467 \r
468     /* The CONNECT packet will always include a 10-byte variable header. */\r
469     connectPacketSize += 10U;\r
470 \r
471     /* Add the length of the client identifier if provided. */\r
472     connectPacketSize += pConnectInfo->clientIdentifierLength + sizeof( uint16_t );\r
473 \r
474     /* Add the lengths of the will message and topic name if provided. */\r
475     if( pConnectInfo->pWillInfo != NULL )\r
476     {\r
477         connectPacketSize += pConnectInfo->pWillInfo->topicNameLength + sizeof( uint16_t ) +\r
478                              pConnectInfo->pWillInfo->payloadLength + sizeof( uint16_t );\r
479     }\r
480     else\r
481     {\r
482         EMPTY_ELSE_MARKER;\r
483     }\r
484 \r
485     /* Depending on the status of metrics, add the length of the metrics username\r
486      * or the user-provided username. */\r
487     if( pConnectInfo->awsIotMqttMode == true )\r
488     {\r
489         #if AWS_IOT_MQTT_ENABLE_METRICS == 1\r
490             connectPacketSize += AWS_IOT_METRICS_USERNAME_LENGTH + sizeof( uint16_t );\r
491         #endif\r
492     }\r
493     else\r
494     {\r
495         /* Add the lengths of the username and password if provided and not\r
496          * connecting to an AWS IoT MQTT server. */\r
497         if( pConnectInfo->pUserName != NULL )\r
498         {\r
499             connectPacketSize += pConnectInfo->userNameLength + sizeof( uint16_t );\r
500         }\r
501         else\r
502         {\r
503             EMPTY_ELSE_MARKER;\r
504         }\r
505 \r
506         if( pConnectInfo->pPassword != NULL )\r
507         {\r
508             connectPacketSize += pConnectInfo->passwordLength + sizeof( uint16_t );\r
509         }\r
510         else\r
511         {\r
512             EMPTY_ELSE_MARKER;\r
513         }\r
514     }\r
515 \r
516     /* At this point, the "Remaining Length" field of the MQTT CONNECT packet has\r
517      * been calculated. */\r
518     remainingLength = connectPacketSize;\r
519 \r
520     /* Calculate the full size of the MQTT CONNECT packet by adding the size of\r
521      * the "Remaining Length" field plus 1 byte for the "Packet Type" field. */\r
522     connectPacketSize += 1 + _remainingLengthEncodedSize( connectPacketSize );\r
523 \r
524     /* Check that the CONNECT packet is within the bounds of the MQTT spec. */\r
525     if( connectPacketSize > MQTT_PACKET_CONNECT_MAX_SIZE )\r
526     {\r
527         status = false;\r
528     }\r
529     else\r
530     {\r
531         *pRemainingLength = remainingLength;\r
532         *pPacketSize = connectPacketSize;\r
533     }\r
534 \r
535     return status;\r
536 }\r
537 \r
538 /*-----------------------------------------------------------*/\r
539 \r
540 static bool _publishPacketSize( const IotMqttPublishInfo_t * pPublishInfo,\r
541                                 size_t * pRemainingLength,\r
542                                 size_t * pPacketSize )\r
543 {\r
544     bool status = true;\r
545     size_t publishPacketSize = 0, payloadLimit = 0;\r
546 \r
547     /* The variable header of a PUBLISH packet always contains the topic name. */\r
548     publishPacketSize += pPublishInfo->topicNameLength + sizeof( uint16_t );\r
549 \r
550     /* The variable header of a QoS 1 or 2 PUBLISH packet contains a 2-byte\r
551      * packet identifier. */\r
552     if( pPublishInfo->qos > IOT_MQTT_QOS_0 )\r
553     {\r
554         publishPacketSize += sizeof( uint16_t );\r
555     }\r
556     else\r
557     {\r
558         EMPTY_ELSE_MARKER;\r
559     }\r
560 \r
561     /* Calculate the maximum allowed size of the payload for the given parameters.\r
562      * This calculation excludes the "Remaining length" encoding, whose size is not\r
563      * yet known. */\r
564     payloadLimit = MQTT_MAX_REMAINING_LENGTH - publishPacketSize - 1;\r
565 \r
566     /* Ensure that the given payload fits within the calculated limit. */\r
567     if( pPublishInfo->payloadLength > payloadLimit )\r
568     {\r
569         status = false;\r
570     }\r
571     else\r
572     {\r
573         /* Add the length of the PUBLISH payload. At this point, the "Remaining length"\r
574          * has been calculated. */\r
575         publishPacketSize += pPublishInfo->payloadLength;\r
576 \r
577         /* Now that the "Remaining length" is known, recalculate the payload limit\r
578          * based on the size of its encoding. */\r
579         payloadLimit -= _remainingLengthEncodedSize( publishPacketSize );\r
580 \r
581         /* Check that the given payload fits within the size allowed by MQTT spec. */\r
582         if( pPublishInfo->payloadLength > payloadLimit )\r
583         {\r
584             status = false;\r
585         }\r
586         else\r
587         {\r
588             /* Set the "Remaining length" output parameter and calculate the full\r
589              * size of the PUBLISH packet. */\r
590             *pRemainingLength = publishPacketSize;\r
591 \r
592             publishPacketSize += 1 + _remainingLengthEncodedSize( publishPacketSize );\r
593             *pPacketSize = publishPacketSize;\r
594         }\r
595     }\r
596 \r
597     return status;\r
598 }\r
599 \r
600 /*-----------------------------------------------------------*/\r
601 \r
602 static bool _subscriptionPacketSize( IotMqttOperationType_t type,\r
603                                      const IotMqttSubscription_t * pSubscriptionList,\r
604                                      size_t subscriptionCount,\r
605                                      size_t * pRemainingLength,\r
606                                      size_t * pPacketSize )\r
607 {\r
608     bool status = true;\r
609     size_t i = 0, subscriptionPacketSize = 0;\r
610 \r
611     /* Only SUBSCRIBE and UNSUBSCRIBE operations should call this function. */\r
612     IotMqtt_Assert( ( type == IOT_MQTT_SUBSCRIBE ) || ( type == IOT_MQTT_UNSUBSCRIBE ) );\r
613 \r
614     /* The variable header of a subscription packet consists of a 2-byte packet\r
615      * identifier. */\r
616     subscriptionPacketSize += sizeof( uint16_t );\r
617 \r
618     /* Sum the lengths of all subscription topic filters; add 1 byte for each\r
619      * subscription's QoS if type is IOT_MQTT_SUBSCRIBE. */\r
620     for( i = 0; i < subscriptionCount; i++ )\r
621     {\r
622         /* Add the length of the topic filter. */\r
623         subscriptionPacketSize += pSubscriptionList[ i ].topicFilterLength + sizeof( uint16_t );\r
624 \r
625         /* Only SUBSCRIBE packets include the QoS. */\r
626         if( type == IOT_MQTT_SUBSCRIBE )\r
627         {\r
628             subscriptionPacketSize += 1;\r
629         }\r
630         else\r
631         {\r
632             EMPTY_ELSE_MARKER;\r
633         }\r
634     }\r
635 \r
636     /* At this point, the "Remaining length" has been calculated. Return error\r
637      * if the "Remaining length" exceeds what is allowed by MQTT 3.1.1. Otherwise,\r
638      * set the output parameter.*/\r
639     if( subscriptionPacketSize > MQTT_MAX_REMAINING_LENGTH )\r
640     {\r
641         status = false;\r
642     }\r
643     else\r
644     {\r
645         *pRemainingLength = subscriptionPacketSize;\r
646 \r
647         /* Calculate the full size of the subscription packet by adding the size of the\r
648          * "Remaining length" field plus 1 byte for the "Packet type" field. Set the\r
649          * pPacketSize output parameter. */\r
650         subscriptionPacketSize += 1 + _remainingLengthEncodedSize( subscriptionPacketSize );\r
651         *pPacketSize = subscriptionPacketSize;\r
652     }\r
653 \r
654     return status;\r
655 }\r
656 \r
657 /*-----------------------------------------------------------*/\r
658 \r
659 void _serializeConnect( const IotMqttConnectInfo_t * pConnectInfo,\r
660                         size_t remainingLength,\r
661                         uint8_t * pBuffer,\r
662                         size_t connectPacketSize )\r
663 {\r
664     uint8_t connectFlags = 0;\r
665     uint8_t * pConnectPacket = pBuffer;\r
666 \r
667     /* The first byte in the CONNECT packet is the control packet type. */\r
668     *pBuffer = MQTT_PACKET_TYPE_CONNECT;\r
669     pBuffer++;\r
670 \r
671     /* The remaining length of the CONNECT packet is encoded starting from the\r
672      * second byte. The remaining length does not include the length of the fixed\r
673      * header or the encoding of the remaining length. */\r
674     pBuffer = _encodeRemainingLength( pBuffer, remainingLength );\r
675 \r
676     /* The string "MQTT" is placed at the beginning of the CONNECT packet's variable\r
677      * header. This string is 4 bytes long. */\r
678     pBuffer = _encodeString( pBuffer, "MQTT", 4 );\r
679 \r
680     /* The MQTT protocol version is the second byte of the variable header. */\r
681     *pBuffer = MQTT_VERSION_3_1_1;\r
682     pBuffer++;\r
683 \r
684     /* Set the CONNECT flags based on the given parameters. */\r
685     if( pConnectInfo->cleanSession == true )\r
686     {\r
687         UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_CLEAN );\r
688     }\r
689     else\r
690     {\r
691         EMPTY_ELSE_MARKER;\r
692     }\r
693 \r
694     /* Username and password depend on MQTT mode. */\r
695     if( pConnectInfo->awsIotMqttMode == true )\r
696     {\r
697         /* Set the username flag for AWS IoT metrics. The AWS IoT MQTT server\r
698          * never uses a password. */\r
699         #if AWS_IOT_MQTT_ENABLE_METRICS == 1\r
700             UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_USERNAME );\r
701         #endif\r
702     }\r
703     else\r
704     {\r
705         /* Set the flags for username and password if provided. */\r
706         if( pConnectInfo->pUserName != NULL )\r
707         {\r
708             UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_USERNAME );\r
709         }\r
710         else\r
711         {\r
712             EMPTY_ELSE_MARKER;\r
713         }\r
714 \r
715         if( pConnectInfo->pPassword != NULL )\r
716         {\r
717             UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_PASSWORD );\r
718         }\r
719         else\r
720         {\r
721             EMPTY_ELSE_MARKER;\r
722         }\r
723     }\r
724 \r
725     /* Set will flag if an LWT is provided. */\r
726     if( pConnectInfo->pWillInfo != NULL )\r
727     {\r
728         UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_WILL );\r
729 \r
730         /* Flags only need to be changed for will QoS 1 and 2. */\r
731         switch( pConnectInfo->pWillInfo->qos )\r
732         {\r
733             case IOT_MQTT_QOS_1:\r
734                 UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_WILL_QOS1 );\r
735                 break;\r
736 \r
737             case IOT_MQTT_QOS_2:\r
738                 UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_WILL_QOS2 );\r
739                 break;\r
740 \r
741             default:\r
742                 break;\r
743         }\r
744 \r
745         if( pConnectInfo->pWillInfo->retain == true )\r
746         {\r
747             UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_WILL_RETAIN );\r
748         }\r
749         else\r
750         {\r
751             EMPTY_ELSE_MARKER;\r
752         }\r
753     }\r
754     else\r
755     {\r
756         EMPTY_ELSE_MARKER;\r
757     }\r
758 \r
759     *pBuffer = connectFlags;\r
760     pBuffer++;\r
761 \r
762     /* Write the 2 bytes of the keep alive interval into the CONNECT packet. */\r
763     *pBuffer = UINT16_HIGH_BYTE( pConnectInfo->keepAliveSeconds );\r
764     *( pBuffer + 1 ) = UINT16_LOW_BYTE( pConnectInfo->keepAliveSeconds );\r
765     pBuffer += 2;\r
766 \r
767     /* Write the client identifier into the CONNECT packet. */\r
768     pBuffer = _encodeString( pBuffer,\r
769                              pConnectInfo->pClientIdentifier,\r
770                              pConnectInfo->clientIdentifierLength );\r
771 \r
772     /* Write the will topic name and message into the CONNECT packet if provided. */\r
773     if( pConnectInfo->pWillInfo != NULL )\r
774     {\r
775         pBuffer = _encodeString( pBuffer,\r
776                                  pConnectInfo->pWillInfo->pTopicName,\r
777                                  pConnectInfo->pWillInfo->topicNameLength );\r
778 \r
779         pBuffer = _encodeString( pBuffer,\r
780                                  pConnectInfo->pWillInfo->pPayload,\r
781                                  ( uint16_t ) pConnectInfo->pWillInfo->payloadLength );\r
782     }\r
783     else\r
784     {\r
785         EMPTY_ELSE_MARKER;\r
786     }\r
787 \r
788     /* If metrics are enabled, write the metrics username into the CONNECT packet.\r
789      * Otherwise, write the username and password only when not connecting to an\r
790      * AWS IoT MQTT server. */\r
791     if( pConnectInfo->awsIotMqttMode == true )\r
792     {\r
793         #if AWS_IOT_MQTT_ENABLE_METRICS == 1\r
794             IotLogInfo( "Anonymous metrics (SDK language, SDK version) will be provided to AWS IoT. "\r
795                         "Recompile with AWS_IOT_MQTT_ENABLE_METRICS set to 0 to disable." );\r
796 \r
797             pBuffer = _encodeString( pBuffer,\r
798                                      AWS_IOT_METRICS_USERNAME,\r
799                                      AWS_IOT_METRICS_USERNAME_LENGTH );\r
800         #endif\r
801     }\r
802     else\r
803     {\r
804         if( pConnectInfo->pUserName != NULL )\r
805         {\r
806             pBuffer = _encodeString( pBuffer,\r
807                                      pConnectInfo->pUserName,\r
808                                      pConnectInfo->userNameLength );\r
809         }\r
810         else\r
811         {\r
812             EMPTY_ELSE_MARKER;\r
813         }\r
814 \r
815         if( pConnectInfo->pPassword != NULL )\r
816         {\r
817             pBuffer = _encodeString( pBuffer,\r
818                                      pConnectInfo->pPassword,\r
819                                      pConnectInfo->passwordLength );\r
820         }\r
821         else\r
822         {\r
823             EMPTY_ELSE_MARKER;\r
824         }\r
825     }\r
826 \r
827     /* Ensure that the difference between the end and beginning of the buffer\r
828      * is equal to connectPacketSize, i.e. pBuffer did not overflow. */\r
829     IotMqtt_Assert( ( size_t ) ( pBuffer - pConnectPacket ) == connectPacketSize );\r
830 \r
831     /* Print out the serialized CONNECT packet for debugging purposes. */\r
832     IotLog_PrintBuffer( "MQTT CONNECT packet:", pConnectPacket, connectPacketSize );\r
833 }\r
834 \r
835 /*-----------------------------------------------------------*/\r
836 \r
837 void _serializePublish( const IotMqttPublishInfo_t * pPublishInfo,\r
838                         size_t remainingLength,\r
839                         uint16_t * pPacketIdentifier,\r
840                         uint8_t ** pPacketIdentifierHigh,\r
841                         uint8_t * pBuffer,\r
842                         size_t publishPacketSize )\r
843 {\r
844     uint8_t publishFlags = 0;\r
845     uint16_t packetIdentifier = 0;\r
846     uint8_t * pPublishPacket = pBuffer;\r
847 \r
848     /* The first byte of a PUBLISH packet contains the packet type and flags. */\r
849     publishFlags = MQTT_PACKET_TYPE_PUBLISH;\r
850 \r
851     if( pPublishInfo->qos == IOT_MQTT_QOS_1 )\r
852     {\r
853         UINT8_SET_BIT( publishFlags, MQTT_PUBLISH_FLAG_QOS1 );\r
854     }\r
855     else if( pPublishInfo->qos == IOT_MQTT_QOS_2 )\r
856     {\r
857         UINT8_SET_BIT( publishFlags, MQTT_PUBLISH_FLAG_QOS2 );\r
858     }\r
859     else\r
860     {\r
861         EMPTY_ELSE_MARKER;\r
862     }\r
863 \r
864     if( pPublishInfo->retain == true )\r
865     {\r
866         UINT8_SET_BIT( publishFlags, MQTT_PUBLISH_FLAG_RETAIN );\r
867     }\r
868     else\r
869     {\r
870         EMPTY_ELSE_MARKER;\r
871     }\r
872 \r
873     *pBuffer = publishFlags;\r
874     pBuffer++;\r
875 \r
876     /* The "Remaining length" is encoded from the second byte. */\r
877     pBuffer = _encodeRemainingLength( pBuffer, remainingLength );\r
878 \r
879     /* The topic name is placed after the "Remaining length". */\r
880     pBuffer = _encodeString( pBuffer,\r
881                              pPublishInfo->pTopicName,\r
882                              pPublishInfo->topicNameLength );\r
883 \r
884     /* A packet identifier is required for QoS 1 and 2 messages. */\r
885     if( pPublishInfo->qos > IOT_MQTT_QOS_0 )\r
886     {\r
887         /* Get the next packet identifier. It should always be nonzero. */\r
888         packetIdentifier = _nextPacketIdentifier();\r
889         IotMqtt_Assert( packetIdentifier != 0 );\r
890 \r
891         /* Set the packet identifier output parameters. */\r
892         *pPacketIdentifier = packetIdentifier;\r
893 \r
894         if( pPacketIdentifierHigh != NULL )\r
895         {\r
896             *pPacketIdentifierHigh = pBuffer;\r
897         }\r
898         else\r
899         {\r
900             EMPTY_ELSE_MARKER;\r
901         }\r
902 \r
903         /* Place the packet identifier into the PUBLISH packet. */\r
904         *pBuffer = UINT16_HIGH_BYTE( packetIdentifier );\r
905         *( pBuffer + 1 ) = UINT16_LOW_BYTE( packetIdentifier );\r
906         pBuffer += 2;\r
907     }\r
908     else\r
909     {\r
910         EMPTY_ELSE_MARKER;\r
911     }\r
912 \r
913     /* The payload is placed after the packet identifier. */\r
914     if( pPublishInfo->payloadLength > 0 )\r
915     {\r
916         ( void ) memcpy( pBuffer, pPublishInfo->pPayload, pPublishInfo->payloadLength );\r
917         pBuffer += pPublishInfo->payloadLength;\r
918     }\r
919     else\r
920     {\r
921         EMPTY_ELSE_MARKER;\r
922     }\r
923 \r
924     /* Ensure that the difference between the end and beginning of the buffer\r
925      * is equal to publishPacketSize, i.e. pBuffer did not overflow. */\r
926     IotMqtt_Assert( ( size_t ) ( pBuffer - pPublishPacket ) == publishPacketSize );\r
927 \r
928     /* Print out the serialized PUBLISH packet for debugging purposes. */\r
929     IotLog_PrintBuffer( "MQTT PUBLISH packet:", pPublishPacket, publishPacketSize );\r
930 }\r
931 \r
932 /*-----------------------------------------------------------*/\r
933 \r
934 void _serializeSubscribe( const IotMqttSubscription_t * pSubscriptionList,\r
935                           size_t subscriptionCount,\r
936                           size_t remainingLength,\r
937                           uint16_t * pPacketIdentifier,\r
938                           uint8_t * pBuffer,\r
939                           size_t subscribePacketSize )\r
940 {\r
941     uint16_t packetIdentifier = 0;\r
942     size_t i = 0;\r
943     uint8_t * pSubscribePacket = pBuffer;\r
944 \r
945     /* The first byte in SUBSCRIBE is the packet type. */\r
946     *pBuffer = MQTT_PACKET_TYPE_SUBSCRIBE;\r
947     pBuffer++;\r
948 \r
949     /* Encode the "Remaining length" starting from the second byte. */\r
950     pBuffer = _encodeRemainingLength( pBuffer, remainingLength );\r
951 \r
952     /* Get the next packet identifier. It should always be nonzero. */\r
953     packetIdentifier = _nextPacketIdentifier();\r
954     *pPacketIdentifier = packetIdentifier;\r
955     IotMqtt_Assert( packetIdentifier != 0 );\r
956 \r
957     /* Place the packet identifier into the SUBSCRIBE packet. */\r
958     *pBuffer = UINT16_HIGH_BYTE( packetIdentifier );\r
959     *( pBuffer + 1 ) = UINT16_LOW_BYTE( packetIdentifier );\r
960     pBuffer += 2;\r
961 \r
962     /* Serialize each subscription topic filter and QoS. */\r
963     for( i = 0; i < subscriptionCount; i++ )\r
964     {\r
965         pBuffer = _encodeString( pBuffer,\r
966                                  pSubscriptionList[ i ].pTopicFilter,\r
967                                  pSubscriptionList[ i ].topicFilterLength );\r
968 \r
969         /* Place the QoS in the SUBSCRIBE packet. */\r
970         *pBuffer = ( uint8_t ) ( pSubscriptionList[ i ].qos );\r
971         pBuffer++;\r
972     }\r
973 \r
974     /* Ensure that the difference between the end and beginning of the buffer\r
975      * is equal to subscribePacketSize, i.e. pBuffer did not overflow. */\r
976     IotMqtt_Assert( ( size_t ) ( pBuffer - pSubscribePacket ) == subscribePacketSize );\r
977 \r
978     /* Print out the serialized SUBSCRIBE packet for debugging purposes. */\r
979     IotLog_PrintBuffer( "MQTT SUBSCRIBE packet:", pSubscribePacket, subscribePacketSize );\r
980 }\r
981 \r
982 /*-----------------------------------------------------------*/\r
983 \r
984 void _serializeUnsubscribe( const IotMqttSubscription_t * pSubscriptionList,\r
985                             size_t subscriptionCount,\r
986                             size_t remainingLength,\r
987                             uint16_t * pPacketIdentifier,\r
988                             uint8_t * pBuffer,\r
989                             size_t unsubscribePacketSize )\r
990 {\r
991     uint16_t packetIdentifier = 0;\r
992     size_t i = 0;\r
993     uint8_t * pUnsubscribePacket = pBuffer;\r
994 \r
995     /* The first byte in UNSUBSCRIBE is the packet type. */\r
996     *pBuffer = MQTT_PACKET_TYPE_UNSUBSCRIBE;\r
997     pBuffer++;\r
998 \r
999     /* Encode the "Remaining length" starting from the second byte. */\r
1000     pBuffer = _encodeRemainingLength( pBuffer, remainingLength );\r
1001 \r
1002     /* Get the next packet identifier. It should always be nonzero. */\r
1003     packetIdentifier = _nextPacketIdentifier();\r
1004     *pPacketIdentifier = packetIdentifier;\r
1005     IotMqtt_Assert( packetIdentifier != 0 );\r
1006 \r
1007     /* Place the packet identifier into the UNSUBSCRIBE packet. */\r
1008     *pBuffer = UINT16_HIGH_BYTE( packetIdentifier );\r
1009     *( pBuffer + 1 ) = UINT16_LOW_BYTE( packetIdentifier );\r
1010     pBuffer += 2;\r
1011 \r
1012     /* Serialize each subscription topic filter. */\r
1013     for( i = 0; i < subscriptionCount; i++ )\r
1014     {\r
1015         pBuffer = _encodeString( pBuffer,\r
1016                                  pSubscriptionList[ i ].pTopicFilter,\r
1017                                  pSubscriptionList[ i ].topicFilterLength );\r
1018     }\r
1019 \r
1020     /* Ensure that the difference between the end and beginning of the buffer\r
1021      * is equal to unsubscribePacketSize, i.e. pBuffer did not overflow. */\r
1022     IotMqtt_Assert( ( size_t ) ( pBuffer - pUnsubscribePacket ) == unsubscribePacketSize );\r
1023 \r
1024     /* Print out the serialized UNSUBSCRIBE packet for debugging purposes. */\r
1025     IotLog_PrintBuffer( "MQTT UNSUBSCRIBE packet:", pUnsubscribePacket, unsubscribePacketSize );\r
1026 }\r
1027 \r
1028 /*-----------------------------------------------------------*/\r
1029 \r
1030 uint8_t _IotMqtt_GetPacketType( void * pNetworkConnection,\r
1031                                 const IotNetworkInterface_t * pNetworkInterface )\r
1032 {\r
1033     uint8_t packetType = 0xff;\r
1034 \r
1035     /* The MQTT packet type is in the first byte of the packet. */\r
1036     ( void ) _IotMqtt_GetNextByte( pNetworkConnection,\r
1037                                    pNetworkInterface,\r
1038                                    &packetType );\r
1039 \r
1040     return packetType;\r
1041 }\r
1042 \r
1043 /*-----------------------------------------------------------*/\r
1044 \r
1045 size_t _IotMqtt_GetRemainingLength( void * pNetworkConnection,\r
1046                                     const IotNetworkInterface_t * pNetworkInterface )\r
1047 {\r
1048     uint8_t encodedByte = 0;\r
1049     size_t remainingLength = 0, multiplier = 1, bytesDecoded = 0, expectedSize = 0;\r
1050 \r
1051     /* This algorithm is copied from the MQTT v3.1.1 spec. */\r
1052     do\r
1053     {\r
1054         if( multiplier > 2097152 ) /* 128 ^ 3 */\r
1055         {\r
1056             remainingLength = MQTT_REMAINING_LENGTH_INVALID;\r
1057             break;\r
1058         }\r
1059         else\r
1060         {\r
1061             if( _IotMqtt_GetNextByte( pNetworkConnection,\r
1062                                       pNetworkInterface,\r
1063                                       &encodedByte ) == true )\r
1064             {\r
1065                 remainingLength += ( encodedByte & 0x7F ) * multiplier;\r
1066                 multiplier *= 128;\r
1067                 bytesDecoded++;\r
1068             }\r
1069             else\r
1070             {\r
1071                 remainingLength = MQTT_REMAINING_LENGTH_INVALID;\r
1072                 break;\r
1073             }\r
1074         }\r
1075     } while( ( encodedByte & 0x80 ) != 0 );\r
1076 \r
1077     /* Check that the decoded remaining length conforms to the MQTT specification. */\r
1078     if( remainingLength != MQTT_REMAINING_LENGTH_INVALID )\r
1079     {\r
1080         expectedSize = _remainingLengthEncodedSize( remainingLength );\r
1081 \r
1082         if( bytesDecoded != expectedSize )\r
1083         {\r
1084             remainingLength = MQTT_REMAINING_LENGTH_INVALID;\r
1085         }\r
1086         else\r
1087         {\r
1088             /* Valid remaining length should be at most 4 bytes. */\r
1089             IotMqtt_Assert( bytesDecoded <= 4 );\r
1090         }\r
1091     }\r
1092     else\r
1093     {\r
1094         EMPTY_ELSE_MARKER;\r
1095     }\r
1096 \r
1097     return remainingLength;\r
1098 }\r
1099 \r
1100 /*-----------------------------------------------------------*/\r
1101 \r
1102 size_t _IotMqtt_GetRemainingLength_Generic( void * pNetworkConnection,\r
1103                                             IotMqttGetNextByte_t getNextByte )\r
1104 {\r
1105     uint8_t encodedByte = 0;\r
1106     size_t remainingLength = 0, multiplier = 1, bytesDecoded = 0, expectedSize = 0;\r
1107 \r
1108     /* This algorithm is copied from the MQTT v3.1.1 spec. */\r
1109     do\r
1110     {\r
1111         if( multiplier > 2097152 ) /* 128 ^ 3 */\r
1112         {\r
1113             remainingLength = MQTT_REMAINING_LENGTH_INVALID;\r
1114             break;\r
1115         }\r
1116         else\r
1117         {\r
1118             if( getNextByte( pNetworkConnection, &encodedByte ) == IOT_MQTT_SUCCESS )\r
1119             {\r
1120                 remainingLength += ( encodedByte & 0x7F ) * multiplier;\r
1121                 multiplier *= 128;\r
1122                 bytesDecoded++;\r
1123             }\r
1124             else\r
1125             {\r
1126                 remainingLength = MQTT_REMAINING_LENGTH_INVALID;\r
1127                 break;\r
1128             }\r
1129         }\r
1130     } while( ( encodedByte & 0x80 ) != 0 );\r
1131 \r
1132     /* Check that the decoded remaining length conforms to the MQTT specification. */\r
1133     if( remainingLength != MQTT_REMAINING_LENGTH_INVALID )\r
1134     {\r
1135         expectedSize = _remainingLengthEncodedSize( remainingLength );\r
1136 \r
1137         if( bytesDecoded != expectedSize )\r
1138         {\r
1139             remainingLength = MQTT_REMAINING_LENGTH_INVALID;\r
1140         }\r
1141         else\r
1142         {\r
1143             /* Valid remaining length should be at most 4 bytes. */\r
1144             IotMqtt_Assert( bytesDecoded <= 4 );\r
1145         }\r
1146     }\r
1147     else\r
1148     {\r
1149         EMPTY_ELSE_MARKER;\r
1150     }\r
1151 \r
1152     return remainingLength;\r
1153 }\r
1154 \r
1155 /*-----------------------------------------------------------*/\r
1156 \r
1157 IotMqttError_t _IotMqtt_SerializeConnect( const IotMqttConnectInfo_t * pConnectInfo,\r
1158                                           uint8_t ** pConnectPacket,\r
1159                                           size_t * pPacketSize )\r
1160 {\r
1161     IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS );\r
1162     size_t remainingLength = 0, connectPacketSize = 0;\r
1163     uint8_t * pBuffer = NULL;\r
1164 \r
1165     /* Calculate the "Remaining length" field and total packet size. If it exceeds\r
1166      * what is allowed in the MQTT standard, return an error. */\r
1167     if( _connectPacketSize( pConnectInfo, &remainingLength, &connectPacketSize ) == false )\r
1168     {\r
1169         IotLogError( "Connect packet length exceeds %lu, which is the maximum"\r
1170                      " size allowed by MQTT 3.1.1.",\r
1171                      MQTT_PACKET_CONNECT_MAX_SIZE );\r
1172 \r
1173         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER );\r
1174     }\r
1175     else\r
1176     {\r
1177         EMPTY_ELSE_MARKER;\r
1178     }\r
1179 \r
1180     /* Total size of the connect packet should be larger than the "Remaining length"\r
1181      * field. */\r
1182     IotMqtt_Assert( connectPacketSize > remainingLength );\r
1183 \r
1184     /* Allocate memory to hold the CONNECT packet. */\r
1185     pBuffer = IotMqtt_MallocMessage( connectPacketSize );\r
1186 \r
1187     /* Check that sufficient memory was allocated. */\r
1188     if( pBuffer == NULL )\r
1189     {\r
1190         IotLogError( "Failed to allocate memory for CONNECT packet." );\r
1191 \r
1192         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_NO_MEMORY );\r
1193     }\r
1194     else\r
1195     {\r
1196         EMPTY_ELSE_MARKER;\r
1197     }\r
1198 \r
1199     /* Set the output parameters. The remainder of this function always succeeds. */\r
1200     *pConnectPacket = pBuffer;\r
1201     *pPacketSize = connectPacketSize;\r
1202 \r
1203     _serializeConnect( pConnectInfo, remainingLength, pBuffer, connectPacketSize );\r
1204 \r
1205     IOT_FUNCTION_EXIT_NO_CLEANUP();\r
1206 }\r
1207 \r
1208 /*-----------------------------------------------------------*/\r
1209 \r
1210 IotMqttError_t _IotMqtt_DeserializeConnack( _mqttPacket_t * pConnack )\r
1211 {\r
1212     IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS );\r
1213     const uint8_t * pRemainingData = pConnack->pRemainingData;\r
1214 \r
1215     /* If logging is enabled, declare the CONNACK response code strings. The\r
1216      * fourth byte of CONNACK indexes into this array for the corresponding response. */\r
1217     #if LIBRARY_LOG_LEVEL > IOT_LOG_NONE\r
1218         static const char * pConnackResponses[ 6 ] =\r
1219         {\r
1220             "Connection accepted.",                               /* 0 */\r
1221             "Connection refused: unacceptable protocol version.", /* 1 */\r
1222             "Connection refused: identifier rejected.",           /* 2 */\r
1223             "Connection refused: server unavailable",             /* 3 */\r
1224             "Connection refused: bad user name or password.",     /* 4 */\r
1225             "Connection refused: not authorized."                 /* 5 */\r
1226         };\r
1227     #endif\r
1228 \r
1229     /* Check that the control packet type is 0x20. */\r
1230     if( pConnack->type != MQTT_PACKET_TYPE_CONNACK )\r
1231     {\r
1232         IotLog( IOT_LOG_ERROR,\r
1233                 &_logHideAll,\r
1234                 "Bad control packet type 0x%02x.",\r
1235                 pConnack->type );\r
1236 \r
1237         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
1238     }\r
1239     else\r
1240     {\r
1241         EMPTY_ELSE_MARKER;\r
1242     }\r
1243 \r
1244     /* According to MQTT 3.1.1, the second byte of CONNACK must specify a\r
1245      * "Remaining length" of 2. */\r
1246     if( pConnack->remainingLength != MQTT_PACKET_CONNACK_REMAINING_LENGTH )\r
1247     {\r
1248         IotLog( IOT_LOG_ERROR,\r
1249                 &_logHideAll,\r
1250                 "CONNACK does not have remaining length of %d.",\r
1251                 MQTT_PACKET_CONNACK_REMAINING_LENGTH );\r
1252 \r
1253         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
1254     }\r
1255     else\r
1256     {\r
1257         EMPTY_ELSE_MARKER;\r
1258     }\r
1259 \r
1260     /* Check the reserved bits in CONNACK. The high 7 bits of the second byte\r
1261      * in CONNACK must be 0. */\r
1262     if( ( pRemainingData[ 0 ] | 0x01 ) != 0x01 )\r
1263     {\r
1264         IotLog( IOT_LOG_ERROR,\r
1265                 &_logHideAll,\r
1266                 "Reserved bits in CONNACK incorrect." );\r
1267 \r
1268         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
1269     }\r
1270     else\r
1271     {\r
1272         EMPTY_ELSE_MARKER;\r
1273     }\r
1274 \r
1275     /* Determine if the "Session Present" bit it set. This is the lowest bit of\r
1276      * the second byte in CONNACK. */\r
1277     if( ( pRemainingData[ 0 ] & MQTT_PACKET_CONNACK_SESSION_PRESENT_MASK )\r
1278         == MQTT_PACKET_CONNACK_SESSION_PRESENT_MASK )\r
1279     {\r
1280         IotLog( IOT_LOG_DEBUG,\r
1281                 &_logHideAll,\r
1282                 "CONNACK session present bit set." );\r
1283 \r
1284         /* MQTT 3.1.1 specifies that the fourth byte in CONNACK must be 0 if the\r
1285          * "Session Present" bit is set. */\r
1286         if( pRemainingData[ 1 ] != 0 )\r
1287         {\r
1288             IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
1289         }\r
1290         else\r
1291         {\r
1292             EMPTY_ELSE_MARKER;\r
1293         }\r
1294     }\r
1295     else\r
1296     {\r
1297         IotLog( IOT_LOG_DEBUG,\r
1298                 &_logHideAll,\r
1299                 "CONNACK session present bit not set." );\r
1300     }\r
1301 \r
1302     /* In MQTT 3.1.1, only values 0 through 5 are valid CONNACK response codes. */\r
1303     if( pRemainingData[ 1 ] > 5 )\r
1304     {\r
1305         IotLog( IOT_LOG_DEBUG,\r
1306                 &_logHideAll,\r
1307                 "CONNACK response %hhu is not valid.",\r
1308                 pRemainingData[ 1 ] );\r
1309 \r
1310         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
1311     }\r
1312     else\r
1313     {\r
1314         EMPTY_ELSE_MARKER;\r
1315     }\r
1316 \r
1317     /* Print the appropriate message for the CONNACK response code if logs are\r
1318      * enabled. */\r
1319     #if LIBRARY_LOG_LEVEL > IOT_LOG_NONE\r
1320         IotLog( IOT_LOG_DEBUG,\r
1321                 &_logHideAll,\r
1322                 "%s",\r
1323                 pConnackResponses[ pRemainingData[ 1 ] ] );\r
1324     #endif\r
1325 \r
1326     /* A nonzero CONNACK response code means the connection was refused. */\r
1327     if( pRemainingData[ 1 ] > 0 )\r
1328     {\r
1329         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_SERVER_REFUSED );\r
1330     }\r
1331     else\r
1332     {\r
1333         EMPTY_ELSE_MARKER;\r
1334     }\r
1335 \r
1336     IOT_FUNCTION_EXIT_NO_CLEANUP();\r
1337 }\r
1338 \r
1339 /*-----------------------------------------------------------*/\r
1340 \r
1341 IotMqttError_t _IotMqtt_SerializePublish( const IotMqttPublishInfo_t * pPublishInfo,\r
1342                                           uint8_t ** pPublishPacket,\r
1343                                           size_t * pPacketSize,\r
1344                                           uint16_t * pPacketIdentifier,\r
1345                                           uint8_t ** pPacketIdentifierHigh )\r
1346 {\r
1347     IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS );\r
1348     size_t remainingLength = 0, publishPacketSize = 0;\r
1349     uint8_t * pBuffer = NULL;\r
1350 \r
1351     /* Calculate the "Remaining length" field and total packet size. If it exceeds\r
1352      * what is allowed in the MQTT standard, return an error. */\r
1353     if( _publishPacketSize( pPublishInfo, &remainingLength, &publishPacketSize ) == false )\r
1354     {\r
1355         IotLogError( "Publish packet remaining length exceeds %lu, which is the "\r
1356                      "maximum size allowed by MQTT 3.1.1.",\r
1357                      MQTT_MAX_REMAINING_LENGTH );\r
1358 \r
1359         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER );\r
1360     }\r
1361     else\r
1362     {\r
1363         EMPTY_ELSE_MARKER;\r
1364     }\r
1365 \r
1366     /* Total size of the publish packet should be larger than the "Remaining length"\r
1367      * field. */\r
1368     IotMqtt_Assert( publishPacketSize > remainingLength );\r
1369 \r
1370     /* Allocate memory to hold the PUBLISH packet. */\r
1371     pBuffer = IotMqtt_MallocMessage( publishPacketSize );\r
1372 \r
1373     /* Check that sufficient memory was allocated. */\r
1374     if( pBuffer == NULL )\r
1375     {\r
1376         IotLogError( "Failed to allocate memory for PUBLISH packet." );\r
1377 \r
1378         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_NO_MEMORY );\r
1379     }\r
1380     else\r
1381     {\r
1382         EMPTY_ELSE_MARKER;\r
1383     }\r
1384 \r
1385     /* Set the output parameters. The remainder of this function always succeeds. */\r
1386     *pPublishPacket = pBuffer;\r
1387     *pPacketSize = publishPacketSize;\r
1388 \r
1389     /* Serialize publish into buffer pointed to by pBuffer */\r
1390     _serializePublish( pPublishInfo,\r
1391                        remainingLength,\r
1392                        pPacketIdentifier,\r
1393                        pPacketIdentifierHigh,\r
1394                        pBuffer,\r
1395                        publishPacketSize );\r
1396 \r
1397     IOT_FUNCTION_EXIT_NO_CLEANUP();\r
1398 }\r
1399 \r
1400 /*-----------------------------------------------------------*/\r
1401 \r
1402 void _IotMqtt_PublishSetDup( uint8_t * pPublishPacket,\r
1403                              uint8_t * pPacketIdentifierHigh,\r
1404                              uint16_t * pNewPacketIdentifier )\r
1405 {\r
1406     uint16_t newPacketIdentifier = 0;\r
1407 \r
1408     /* For an AWS IoT MQTT server, change the packet identifier. */\r
1409     if( pPacketIdentifierHigh != NULL )\r
1410     {\r
1411         /* Output parameter for new packet identifier must be provided. */\r
1412         IotMqtt_Assert( pNewPacketIdentifier != NULL );\r
1413 \r
1414         /* Generate a new packet identifier. */\r
1415         newPacketIdentifier = _nextPacketIdentifier();\r
1416 \r
1417         IotLogDebug( "Changing PUBLISH packet identifier %hu to %hu.",\r
1418                      UINT16_DECODE( pPacketIdentifierHigh ),\r
1419                      newPacketIdentifier );\r
1420 \r
1421         /* Replace the packet identifier. */\r
1422         *pPacketIdentifierHigh = UINT16_HIGH_BYTE( newPacketIdentifier );\r
1423         *( pPacketIdentifierHigh + 1 ) = UINT16_LOW_BYTE( newPacketIdentifier );\r
1424         *pNewPacketIdentifier = newPacketIdentifier;\r
1425     }\r
1426     else\r
1427     {\r
1428         /* For a compliant MQTT 3.1.1 server, set the DUP flag. */\r
1429         UINT8_SET_BIT( *pPublishPacket, MQTT_PUBLISH_FLAG_DUP );\r
1430 \r
1431         IotLogDebug( "PUBLISH DUP flag set." );\r
1432     }\r
1433 }\r
1434 \r
1435 /*-----------------------------------------------------------*/\r
1436 \r
1437 IotMqttError_t _IotMqtt_DeserializePublish( _mqttPacket_t * pPublish )\r
1438 {\r
1439     IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS );\r
1440     IotMqttPublishInfo_t * pOutput = &( pPublish->u.pIncomingPublish->u.publish.publishInfo );\r
1441     uint8_t publishFlags = 0;\r
1442     const uint8_t * pVariableHeader = pPublish->pRemainingData, * pPacketIdentifierHigh = NULL;\r
1443 \r
1444     /* The flags are the lower 4 bits of the first byte in PUBLISH. */\r
1445     publishFlags = pPublish->type;\r
1446 \r
1447     /* Parse the Retain bit. */\r
1448     pOutput->retain = UINT8_CHECK_BIT( publishFlags, MQTT_PUBLISH_FLAG_RETAIN );\r
1449 \r
1450     IotLog( IOT_LOG_DEBUG,\r
1451             &_logHideAll,\r
1452             "Retain bit is %d.", pOutput->retain );\r
1453 \r
1454     /* Check for QoS 2. */\r
1455     if( UINT8_CHECK_BIT( publishFlags, MQTT_PUBLISH_FLAG_QOS2 ) == true )\r
1456     {\r
1457         /* PUBLISH packet is invalid if both QoS 1 and QoS 2 bits are set. */\r
1458         if( UINT8_CHECK_BIT( publishFlags, MQTT_PUBLISH_FLAG_QOS1 ) == true )\r
1459         {\r
1460             IotLog( IOT_LOG_DEBUG,\r
1461                     &_logHideAll,\r
1462                     "Bad QoS: 3." );\r
1463 \r
1464             IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
1465         }\r
1466         else\r
1467         {\r
1468             EMPTY_ELSE_MARKER;\r
1469         }\r
1470 \r
1471         pOutput->qos = IOT_MQTT_QOS_2;\r
1472     }\r
1473     /* Check for QoS 1. */\r
1474     else if( UINT8_CHECK_BIT( publishFlags, MQTT_PUBLISH_FLAG_QOS1 ) == true )\r
1475     {\r
1476         pOutput->qos = IOT_MQTT_QOS_1;\r
1477     }\r
1478     /* If the PUBLISH isn't QoS 1 or 2, then it's QoS 0. */\r
1479     else\r
1480     {\r
1481         pOutput->qos = IOT_MQTT_QOS_0;\r
1482     }\r
1483 \r
1484     IotLog( IOT_LOG_DEBUG,\r
1485             &_logHideAll,\r
1486             "QoS is %d.", pOutput->qos );\r
1487 \r
1488     /* Parse the DUP bit. */\r
1489     if( UINT8_CHECK_BIT( publishFlags, MQTT_PUBLISH_FLAG_DUP ) == true )\r
1490     {\r
1491         IotLog( IOT_LOG_DEBUG,\r
1492                 &_logHideAll,\r
1493                 "DUP is 1." );\r
1494     }\r
1495     else\r
1496     {\r
1497         IotLog( IOT_LOG_DEBUG,\r
1498                 &_logHideAll,\r
1499                 "DUP is 0." );\r
1500     }\r
1501 \r
1502     /* Sanity checks for "Remaining length". */\r
1503     if( pOutput->qos == IOT_MQTT_QOS_0 )\r
1504     {\r
1505         /* A QoS 0 PUBLISH must have a remaining length of at least 3 to accommodate\r
1506          * topic name length (2 bytes) and topic name (at least 1 byte). */\r
1507         if( pPublish->remainingLength < 3 )\r
1508         {\r
1509             IotLog( IOT_LOG_DEBUG,\r
1510                     &_logHideAll,\r
1511                     "QoS 0 PUBLISH cannot have a remaining length less than 3." );\r
1512 \r
1513             IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
1514         }\r
1515         else\r
1516         {\r
1517             EMPTY_ELSE_MARKER;\r
1518         }\r
1519     }\r
1520     else\r
1521     {\r
1522         /* A QoS 1 or 2 PUBLISH must have a remaining length of at least 5 to\r
1523          * accommodate a packet identifier as well as the topic name length and\r
1524          * topic name. */\r
1525         if( pPublish->remainingLength < 5 )\r
1526         {\r
1527             IotLog( IOT_LOG_DEBUG,\r
1528                     &_logHideAll,\r
1529                     "QoS 1 or 2 PUBLISH cannot have a remaining length less than 5." );\r
1530 \r
1531             IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
1532         }\r
1533         else\r
1534         {\r
1535             EMPTY_ELSE_MARKER;\r
1536         }\r
1537     }\r
1538 \r
1539     /* Extract the topic name starting from the first byte of the variable header.\r
1540      * The topic name string starts at byte 3 in the variable header. */\r
1541     pOutput->topicNameLength = UINT16_DECODE( pVariableHeader );\r
1542 \r
1543     /* Sanity checks for topic name length and "Remaining length". */\r
1544     if( pOutput->qos == IOT_MQTT_QOS_0 )\r
1545     {\r
1546         /* Check that the "Remaining length" is at least as large as the variable\r
1547          * header. */\r
1548         if( pPublish->remainingLength < pOutput->topicNameLength + sizeof( uint16_t ) )\r
1549         {\r
1550             IotLog( IOT_LOG_DEBUG,\r
1551                     &_logHideAll,\r
1552                     "Remaining length cannot be less than variable header length." );\r
1553 \r
1554             IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
1555         }\r
1556         else\r
1557         {\r
1558             EMPTY_ELSE_MARKER;\r
1559         }\r
1560     }\r
1561     else\r
1562     {\r
1563         /* Check that the "Remaining length" is at least as large as the variable\r
1564          * header. */\r
1565         if( pPublish->remainingLength < pOutput->topicNameLength + 2 * sizeof( uint16_t ) )\r
1566         {\r
1567             IotLog( IOT_LOG_DEBUG,\r
1568                     &_logHideAll,\r
1569                     "Remaining length cannot be less than variable header length." );\r
1570 \r
1571             IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
1572         }\r
1573         else\r
1574         {\r
1575             EMPTY_ELSE_MARKER;\r
1576         }\r
1577     }\r
1578 \r
1579     /* Parse the topic. */\r
1580     pOutput->pTopicName = ( const char * ) ( pVariableHeader + sizeof( uint16_t ) );\r
1581 \r
1582     IotLog( IOT_LOG_DEBUG,\r
1583             &_logHideAll,\r
1584             "Topic name length %hu: %.*s",\r
1585             pOutput->topicNameLength,\r
1586             pOutput->topicNameLength,\r
1587             pOutput->pTopicName );\r
1588 \r
1589     /* Extract the packet identifier for QoS 1 or 2 PUBLISH packets. Packet\r
1590      * identifier starts immediately after the topic name. */\r
1591     pPacketIdentifierHigh = ( const uint8_t * ) ( pOutput->pTopicName + pOutput->topicNameLength );\r
1592 \r
1593     if( pOutput->qos > IOT_MQTT_QOS_0 )\r
1594     {\r
1595         pPublish->packetIdentifier = UINT16_DECODE( pPacketIdentifierHigh );\r
1596 \r
1597         IotLog( IOT_LOG_DEBUG,\r
1598                 &_logHideAll,\r
1599                 "Packet identifier %hu.", pPublish->packetIdentifier );\r
1600 \r
1601         /* Packet identifier cannot be 0. */\r
1602         if( pPublish->packetIdentifier == 0 )\r
1603         {\r
1604             IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
1605         }\r
1606         else\r
1607         {\r
1608             EMPTY_ELSE_MARKER;\r
1609         }\r
1610     }\r
1611     else\r
1612     {\r
1613         EMPTY_ELSE_MARKER;\r
1614     }\r
1615 \r
1616     /* Calculate the length of the payload. QoS 1 or 2 PUBLISH packets contain\r
1617      * a packet identifier, but QoS 0 PUBLISH packets do not. */\r
1618     if( pOutput->qos == IOT_MQTT_QOS_0 )\r
1619     {\r
1620         pOutput->payloadLength = ( pPublish->remainingLength - pOutput->topicNameLength - sizeof( uint16_t ) );\r
1621         pOutput->pPayload = pPacketIdentifierHigh;\r
1622     }\r
1623     else\r
1624     {\r
1625         pOutput->payloadLength = ( pPublish->remainingLength - pOutput->topicNameLength - 2 * sizeof( uint16_t ) );\r
1626         pOutput->pPayload = pPacketIdentifierHigh + sizeof( uint16_t );\r
1627     }\r
1628 \r
1629     IotLog( IOT_LOG_DEBUG,\r
1630             &_logHideAll,\r
1631             "Payload length %hu.", pOutput->payloadLength );\r
1632 \r
1633     IOT_FUNCTION_EXIT_NO_CLEANUP();\r
1634 }\r
1635 \r
1636 /*-----------------------------------------------------------*/\r
1637 \r
1638 IotMqttError_t _IotMqtt_SerializePuback( uint16_t packetIdentifier,\r
1639                                          uint8_t ** pPubackPacket,\r
1640                                          size_t * pPacketSize )\r
1641 {\r
1642     IotMqttError_t status = IOT_MQTT_SUCCESS;\r
1643 \r
1644     /* Allocate memory for PUBACK. */\r
1645     uint8_t * pBuffer = IotMqtt_MallocMessage( MQTT_PACKET_PUBACK_SIZE );\r
1646 \r
1647     if( pBuffer == NULL )\r
1648     {\r
1649         IotLogError( "Failed to allocate memory for PUBACK packet" );\r
1650 \r
1651         status = IOT_MQTT_NO_MEMORY;\r
1652     }\r
1653     else\r
1654     {\r
1655         /* Set the output parameters. The remainder of this function always succeeds. */\r
1656         *pPubackPacket = pBuffer;\r
1657         *pPacketSize = MQTT_PACKET_PUBACK_SIZE;\r
1658 \r
1659         /* Set the 4 bytes in PUBACK. */\r
1660         pBuffer[ 0 ] = MQTT_PACKET_TYPE_PUBACK;\r
1661         pBuffer[ 1 ] = MQTT_PACKET_PUBACK_REMAINING_LENGTH;\r
1662         pBuffer[ 2 ] = UINT16_HIGH_BYTE( packetIdentifier );\r
1663         pBuffer[ 3 ] = UINT16_LOW_BYTE( packetIdentifier );\r
1664 \r
1665         /* Print out the serialized PUBACK packet for debugging purposes. */\r
1666         IotLog_PrintBuffer( "MQTT PUBACK packet:", *pPubackPacket, MQTT_PACKET_PUBACK_SIZE );\r
1667     }\r
1668 \r
1669     return status;\r
1670 }\r
1671 \r
1672 /*-----------------------------------------------------------*/\r
1673 \r
1674 IotMqttError_t _IotMqtt_DeserializePuback( _mqttPacket_t * pPuback )\r
1675 {\r
1676     IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS );\r
1677 \r
1678     /* Check the "Remaining length" of the received PUBACK. */\r
1679     if( pPuback->remainingLength != MQTT_PACKET_PUBACK_REMAINING_LENGTH )\r
1680     {\r
1681         IotLog( IOT_LOG_ERROR,\r
1682                 &_logHideAll,\r
1683                 "PUBACK does not have remaining length of %d.",\r
1684                 MQTT_PACKET_PUBACK_REMAINING_LENGTH );\r
1685 \r
1686         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
1687     }\r
1688     else\r
1689     {\r
1690         EMPTY_ELSE_MARKER;\r
1691     }\r
1692 \r
1693     /* Extract the packet identifier (third and fourth bytes) from PUBACK. */\r
1694     pPuback->packetIdentifier = UINT16_DECODE( pPuback->pRemainingData );\r
1695 \r
1696     IotLog( IOT_LOG_DEBUG,\r
1697             &_logHideAll,\r
1698             "Packet identifier %hu.", pPuback->packetIdentifier );\r
1699 \r
1700     /* Packet identifier cannot be 0. */\r
1701     if( pPuback->packetIdentifier == 0 )\r
1702     {\r
1703         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
1704     }\r
1705     else\r
1706     {\r
1707         EMPTY_ELSE_MARKER;\r
1708     }\r
1709 \r
1710     /* Check that the control packet type is 0x40 (this must be done after the\r
1711      * packet identifier is parsed). */\r
1712     if( pPuback->type != MQTT_PACKET_TYPE_PUBACK )\r
1713     {\r
1714         IotLog( IOT_LOG_ERROR,\r
1715                 &_logHideAll,\r
1716                 "Bad control packet type 0x%02x.",\r
1717                 pPuback->type );\r
1718 \r
1719         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
1720     }\r
1721     else\r
1722     {\r
1723         EMPTY_ELSE_MARKER;\r
1724     }\r
1725 \r
1726     IOT_FUNCTION_EXIT_NO_CLEANUP();\r
1727 }\r
1728 \r
1729 /*-----------------------------------------------------------*/\r
1730 \r
1731 IotMqttError_t _IotMqtt_SerializeSubscribe( const IotMqttSubscription_t * pSubscriptionList,\r
1732                                             size_t subscriptionCount,\r
1733                                             uint8_t ** pSubscribePacket,\r
1734                                             size_t * pPacketSize,\r
1735                                             uint16_t * pPacketIdentifier )\r
1736 {\r
1737     IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS );\r
1738     size_t subscribePacketSize = 0, remainingLength = 0;\r
1739     uint8_t * pBuffer = NULL;\r
1740 \r
1741     /* Calculate the "Remaining length" field and total packet size. If it exceeds\r
1742      * what is allowed in the MQTT standard, return an error. */\r
1743     if( _subscriptionPacketSize( IOT_MQTT_SUBSCRIBE,\r
1744                                  pSubscriptionList,\r
1745                                  subscriptionCount,\r
1746                                  &remainingLength,\r
1747                                  &subscribePacketSize ) == false )\r
1748     {\r
1749         IotLogError( "Subscribe packet remaining length exceeds %lu, which is the "\r
1750                      "maximum size allowed by MQTT 3.1.1.",\r
1751                      MQTT_MAX_REMAINING_LENGTH );\r
1752 \r
1753         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER );\r
1754     }\r
1755     else\r
1756     {\r
1757         EMPTY_ELSE_MARKER;\r
1758     }\r
1759 \r
1760     /* Total size of the subscribe packet should be larger than the "Remaining length"\r
1761      * field. */\r
1762     IotMqtt_Assert( subscribePacketSize > remainingLength );\r
1763 \r
1764     /* Allocate memory to hold the SUBSCRIBE packet. */\r
1765     pBuffer = IotMqtt_MallocMessage( subscribePacketSize );\r
1766 \r
1767     /* Check that sufficient memory was allocated. */\r
1768     if( pBuffer == NULL )\r
1769     {\r
1770         IotLogError( "Failed to allocate memory for SUBSCRIBE packet." );\r
1771 \r
1772         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_NO_MEMORY );\r
1773     }\r
1774     else\r
1775     {\r
1776         EMPTY_ELSE_MARKER;\r
1777     }\r
1778 \r
1779     /* Set the output parameters. The remainder of this function always succeeds. */\r
1780     *pSubscribePacket = pBuffer;\r
1781     *pPacketSize = subscribePacketSize;\r
1782 \r
1783     /* Serialize subscribe into buffer pointed to by pBuffer */\r
1784     _serializeSubscribe( pSubscriptionList,\r
1785                          subscriptionCount,\r
1786                          remainingLength,\r
1787                          pPacketIdentifier,\r
1788                          pBuffer,\r
1789                          subscribePacketSize );\r
1790 \r
1791 \r
1792     IOT_FUNCTION_EXIT_NO_CLEANUP();\r
1793 }\r
1794 \r
1795 /*-----------------------------------------------------------*/\r
1796 \r
1797 IotMqttError_t _IotMqtt_DeserializeSuback( _mqttPacket_t * pSuback )\r
1798 {\r
1799     IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS );\r
1800     size_t i = 0, remainingLength = pSuback->remainingLength;\r
1801     uint8_t subscriptionStatus = 0;\r
1802     const uint8_t * pVariableHeader = pSuback->pRemainingData;\r
1803 \r
1804     /* A SUBACK must have a remaining length of at least 3 to accommodate the\r
1805      * packet identifier and at least one return code. */\r
1806     if( remainingLength < 3 )\r
1807     {\r
1808         IotLog( IOT_LOG_DEBUG,\r
1809                 &_logHideAll,\r
1810                 "SUBACK cannot have a remaining length less than 3." );\r
1811 \r
1812         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
1813     }\r
1814     else\r
1815     {\r
1816         EMPTY_ELSE_MARKER;\r
1817     }\r
1818 \r
1819     /* Extract the packet identifier (first 2 bytes of variable header) from SUBACK. */\r
1820     pSuback->packetIdentifier = UINT16_DECODE( pVariableHeader );\r
1821 \r
1822     IotLog( IOT_LOG_DEBUG,\r
1823             &_logHideAll,\r
1824             "Packet identifier %hu.", pSuback->packetIdentifier );\r
1825 \r
1826     /* Check that the control packet type is 0x90 (this must be done after the\r
1827      * packet identifier is parsed). */\r
1828     if( pSuback->type != MQTT_PACKET_TYPE_SUBACK )\r
1829     {\r
1830         IotLog( IOT_LOG_ERROR,\r
1831                 &_logHideAll,\r
1832                 "Bad control packet type 0x%02x.",\r
1833                 pSuback->type );\r
1834 \r
1835         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
1836     }\r
1837     else\r
1838     {\r
1839         EMPTY_ELSE_MARKER;\r
1840     }\r
1841 \r
1842     /* Iterate through each status byte in the SUBACK packet. */\r
1843     for( i = 0; i < remainingLength - sizeof( uint16_t ); i++ )\r
1844     {\r
1845         /* Read a single status byte in SUBACK. */\r
1846         subscriptionStatus = *( pVariableHeader + sizeof( uint16_t ) + i );\r
1847 \r
1848         /* MQTT 3.1.1 defines the following values as status codes. */\r
1849         switch( subscriptionStatus )\r
1850         {\r
1851             case 0x00:\r
1852             case 0x01:\r
1853             case 0x02:\r
1854                 IotLog( IOT_LOG_DEBUG,\r
1855                         &_logHideAll,\r
1856                         "Topic filter %lu accepted, max QoS %hhu.",\r
1857                         ( unsigned long ) i, subscriptionStatus );\r
1858                 break;\r
1859 \r
1860             case 0x80:\r
1861                 IotLog( IOT_LOG_DEBUG,\r
1862                         &_logHideAll,\r
1863                         "Topic filter %lu refused.", ( unsigned long ) i );\r
1864 \r
1865                 /* Remove a rejected subscription from the subscription manager. */\r
1866                 _IotMqtt_RemoveSubscriptionByPacket( pSuback->u.pMqttConnection,\r
1867                                                      pSuback->packetIdentifier,\r
1868                                                      ( int32_t ) i );\r
1869 \r
1870                 status = IOT_MQTT_SERVER_REFUSED;\r
1871 \r
1872                 break;\r
1873 \r
1874             default:\r
1875                 IotLog( IOT_LOG_DEBUG,\r
1876                         &_logHideAll,\r
1877                         "Bad SUBSCRIBE status %hhu.", subscriptionStatus );\r
1878 \r
1879                 status = IOT_MQTT_BAD_RESPONSE;\r
1880 \r
1881                 break;\r
1882         }\r
1883 \r
1884         /* Stop parsing the subscription statuses if a bad response was received. */\r
1885         if( status == IOT_MQTT_BAD_RESPONSE )\r
1886         {\r
1887             break;\r
1888         }\r
1889         else\r
1890         {\r
1891             EMPTY_ELSE_MARKER;\r
1892         }\r
1893     }\r
1894 \r
1895     IOT_FUNCTION_EXIT_NO_CLEANUP();\r
1896 }\r
1897 \r
1898 /*-----------------------------------------------------------*/\r
1899 \r
1900 IotMqttError_t _IotMqtt_SerializeUnsubscribe( const IotMqttSubscription_t * pSubscriptionList,\r
1901                                               size_t subscriptionCount,\r
1902                                               uint8_t ** pUnsubscribePacket,\r
1903                                               size_t * pPacketSize,\r
1904                                               uint16_t * pPacketIdentifier )\r
1905 {\r
1906     IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS );\r
1907     size_t unsubscribePacketSize = 0, remainingLength = 0;\r
1908     uint8_t * pBuffer = NULL;\r
1909 \r
1910     /* Calculate the "Remaining length" field and total packet size. If it exceeds\r
1911      * what is allowed in the MQTT standard, return an error. */\r
1912     if( _subscriptionPacketSize( IOT_MQTT_UNSUBSCRIBE,\r
1913                                  pSubscriptionList,\r
1914                                  subscriptionCount,\r
1915                                  &remainingLength,\r
1916                                  &unsubscribePacketSize ) == false )\r
1917     {\r
1918         IotLogError( "Unsubscribe packet remaining length exceeds %lu, which is the "\r
1919                      "maximum size allowed by MQTT 3.1.1.",\r
1920                      MQTT_MAX_REMAINING_LENGTH );\r
1921 \r
1922         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER );\r
1923     }\r
1924     else\r
1925     {\r
1926         EMPTY_ELSE_MARKER;\r
1927     }\r
1928 \r
1929     /* Total size of the unsubscribe packet should be larger than the "Remaining length"\r
1930      * field. */\r
1931     IotMqtt_Assert( unsubscribePacketSize > remainingLength );\r
1932 \r
1933     /* Allocate memory to hold the UNSUBSCRIBE packet. */\r
1934     pBuffer = IotMqtt_MallocMessage( unsubscribePacketSize );\r
1935 \r
1936     /* Check that sufficient memory was allocated. */\r
1937     if( pBuffer == NULL )\r
1938     {\r
1939         IotLogError( "Failed to allocate memory for UNSUBSCRIBE packet." );\r
1940 \r
1941         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_NO_MEMORY );\r
1942     }\r
1943     else\r
1944     {\r
1945         EMPTY_ELSE_MARKER;\r
1946     }\r
1947 \r
1948     /* Set the output parameters. The remainder of this function always succeeds. */\r
1949     *pUnsubscribePacket = pBuffer;\r
1950     *pPacketSize = unsubscribePacketSize;\r
1951 \r
1952     /* Serialize unsubscribe into buffer pointed to by pBuffer */\r
1953     _serializeUnsubscribe( pSubscriptionList,\r
1954                            subscriptionCount,\r
1955                            remainingLength,\r
1956                            pPacketIdentifier,\r
1957                            pBuffer,\r
1958                            unsubscribePacketSize );\r
1959 \r
1960     IOT_FUNCTION_EXIT_NO_CLEANUP();\r
1961 }\r
1962 \r
1963 /*-----------------------------------------------------------*/\r
1964 \r
1965 IotMqttError_t _IotMqtt_DeserializeUnsuback( _mqttPacket_t * pUnsuback )\r
1966 {\r
1967     IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS );\r
1968 \r
1969     /* Check the "Remaining length" (second byte) of the received UNSUBACK. */\r
1970     if( pUnsuback->remainingLength != MQTT_PACKET_UNSUBACK_REMAINING_LENGTH )\r
1971     {\r
1972         IotLog( IOT_LOG_ERROR,\r
1973                 &_logHideAll,\r
1974                 "UNSUBACK does not have remaining length of %d.",\r
1975                 MQTT_PACKET_UNSUBACK_REMAINING_LENGTH );\r
1976 \r
1977         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
1978     }\r
1979     else\r
1980     {\r
1981         EMPTY_ELSE_MARKER;\r
1982     }\r
1983 \r
1984     /* Extract the packet identifier (third and fourth bytes) from UNSUBACK. */\r
1985     pUnsuback->packetIdentifier = UINT16_DECODE( pUnsuback->pRemainingData );\r
1986 \r
1987     /* Packet identifier cannot be 0. */\r
1988     if( pUnsuback->packetIdentifier == 0 )\r
1989     {\r
1990         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
1991     }\r
1992     else\r
1993     {\r
1994         EMPTY_ELSE_MARKER;\r
1995     }\r
1996 \r
1997     IotLog( IOT_LOG_DEBUG,\r
1998             &_logHideAll,\r
1999             "Packet identifier %hu.", pUnsuback->packetIdentifier );\r
2000 \r
2001     /* Check that the control packet type is 0xb0 (this must be done after the\r
2002      * packet identifier is parsed). */\r
2003     if( pUnsuback->type != MQTT_PACKET_TYPE_UNSUBACK )\r
2004     {\r
2005         IotLog( IOT_LOG_ERROR,\r
2006                 &_logHideAll,\r
2007                 "Bad control packet type 0x%02x.",\r
2008                 pUnsuback->type );\r
2009 \r
2010         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
2011     }\r
2012     else\r
2013     {\r
2014         EMPTY_ELSE_MARKER;\r
2015     }\r
2016 \r
2017     IOT_FUNCTION_EXIT_NO_CLEANUP();\r
2018 }\r
2019 \r
2020 /*-----------------------------------------------------------*/\r
2021 \r
2022 IotMqttError_t _IotMqtt_SerializePingreq( uint8_t ** pPingreqPacket,\r
2023                                           size_t * pPacketSize )\r
2024 {\r
2025     /* PINGREQ packets are always the same. */\r
2026     static const uint8_t pPingreq[ MQTT_PACKET_PINGREQ_SIZE ] =\r
2027     {\r
2028         MQTT_PACKET_TYPE_PINGREQ,\r
2029         0x00\r
2030     };\r
2031 \r
2032     /* Set the output parameters. */\r
2033     *pPingreqPacket = ( uint8_t * ) pPingreq;\r
2034     *pPacketSize = MQTT_PACKET_PINGREQ_SIZE;\r
2035 \r
2036     /* Print out the PINGREQ packet for debugging purposes. */\r
2037     IotLog_PrintBuffer( "MQTT PINGREQ packet:", pPingreq, MQTT_PACKET_PINGREQ_SIZE );\r
2038 \r
2039     return IOT_MQTT_SUCCESS;\r
2040 }\r
2041 \r
2042 /*-----------------------------------------------------------*/\r
2043 \r
2044 IotMqttError_t _IotMqtt_DeserializePingresp( _mqttPacket_t * pPingresp )\r
2045 {\r
2046     IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS );\r
2047 \r
2048     /* Check that the control packet type is 0xd0. */\r
2049     if( pPingresp->type != MQTT_PACKET_TYPE_PINGRESP )\r
2050     {\r
2051         IotLog( IOT_LOG_ERROR,\r
2052                 &_logHideAll,\r
2053                 "Bad control packet type 0x%02x.",\r
2054                 pPingresp->type );\r
2055 \r
2056         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
2057     }\r
2058     else\r
2059     {\r
2060         EMPTY_ELSE_MARKER;\r
2061     }\r
2062 \r
2063     /* Check the "Remaining length" (second byte) of the received PINGRESP. */\r
2064     if( pPingresp->remainingLength != MQTT_PACKET_PINGRESP_REMAINING_LENGTH )\r
2065     {\r
2066         IotLog( IOT_LOG_ERROR,\r
2067                 &_logHideAll,\r
2068                 "PINGRESP does not have remaining length of %d.",\r
2069                 MQTT_PACKET_PINGRESP_REMAINING_LENGTH );\r
2070 \r
2071         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
2072     }\r
2073     else\r
2074     {\r
2075         EMPTY_ELSE_MARKER;\r
2076     }\r
2077 \r
2078     IOT_FUNCTION_EXIT_NO_CLEANUP();\r
2079 }\r
2080 \r
2081 /*-----------------------------------------------------------*/\r
2082 \r
2083 IotMqttError_t _IotMqtt_SerializeDisconnect( uint8_t ** pDisconnectPacket,\r
2084                                              size_t * pPacketSize )\r
2085 {\r
2086     /* DISCONNECT packets are always the same. */\r
2087     static const uint8_t pDisconnect[ MQTT_PACKET_DISCONNECT_SIZE ] =\r
2088     {\r
2089         MQTT_PACKET_TYPE_DISCONNECT,\r
2090         0x00\r
2091     };\r
2092 \r
2093     /* Set the output parameters. */\r
2094     *pDisconnectPacket = ( uint8_t * ) pDisconnect;\r
2095     *pPacketSize = MQTT_PACKET_DISCONNECT_SIZE;\r
2096 \r
2097     /* Print out the DISCONNECT packet for debugging purposes. */\r
2098     IotLog_PrintBuffer( "MQTT DISCONNECT packet:", pDisconnect, MQTT_PACKET_DISCONNECT_SIZE );\r
2099 \r
2100     return IOT_MQTT_SUCCESS;\r
2101 }\r
2102 \r
2103 /*-----------------------------------------------------------*/\r
2104 \r
2105 void _IotMqtt_FreePacket( uint8_t * pPacket )\r
2106 {\r
2107     uint8_t packetType = *pPacket;\r
2108 \r
2109     /* Don't call free on DISCONNECT and PINGREQ; those are allocated from static\r
2110      * memory. */\r
2111     if( packetType != MQTT_PACKET_TYPE_DISCONNECT )\r
2112     {\r
2113         if( packetType != MQTT_PACKET_TYPE_PINGREQ )\r
2114         {\r
2115             IotMqtt_FreeMessage( pPacket );\r
2116         }\r
2117         else\r
2118         {\r
2119             EMPTY_ELSE_MARKER;\r
2120         }\r
2121     }\r
2122     else\r
2123     {\r
2124         EMPTY_ELSE_MARKER;\r
2125     }\r
2126 }\r
2127 \r
2128 /*-----------------------------------------------------------*/\r
2129 \r
2130 /* Public interface functions for serialization */\r
2131 \r
2132 /*-----------------------------------------------------------*/\r
2133 \r
2134 IotMqttError_t IotMqtt_GetConnectPacketSize( const IotMqttConnectInfo_t * pConnectInfo,\r
2135                                              size_t * pRemainingLength,\r
2136                                              size_t * pPacketSize )\r
2137 {\r
2138     IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS );\r
2139 \r
2140     if( ( pConnectInfo == NULL ) || ( pRemainingLength == NULL ) || ( pPacketSize == NULL ) )\r
2141     {\r
2142         IotLogError( "IotMqtt_GetConnectPacketSize() called with required parameter(s) set to NULL." );\r
2143         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER );\r
2144     }\r
2145 \r
2146     if( ( pConnectInfo->clientIdentifierLength == 0 ) || ( pConnectInfo->pClientIdentifier == NULL ) )\r
2147     {\r
2148         IotLogError( "IotMqtt_GetConnectPacketSize() client identifier must be set." );\r
2149         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER );\r
2150     }\r
2151 \r
2152     /* Calculate the "Remaining length" field and total packet size. If it exceeds\r
2153      * what is allowed in the MQTT standard, return an error. */\r
2154     if( _connectPacketSize( pConnectInfo, pRemainingLength, pPacketSize ) == false )\r
2155     {\r
2156         IotLogError( "Connect packet length exceeds %lu, which is the maximum"\r
2157                      " size allowed by MQTT 3.1.1.",\r
2158                      MQTT_PACKET_CONNECT_MAX_SIZE );\r
2159 \r
2160         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER );\r
2161     }\r
2162     else\r
2163     {\r
2164         EMPTY_ELSE_MARKER;\r
2165     }\r
2166 \r
2167     /* Total size of the subscribe packet should be larger than the "Remaining length"\r
2168      * field. */\r
2169     if( ( *pPacketSize ) < ( *pRemainingLength ) )\r
2170     {\r
2171         IotLogError( "Connection packet remaining length (%lu) exceeds packet size (%lu)",\r
2172                      ( *pRemainingLength ), ( *pPacketSize ) );\r
2173         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER );\r
2174     }\r
2175 \r
2176     IOT_FUNCTION_EXIT_NO_CLEANUP();\r
2177 }\r
2178 \r
2179 /*-----------------------------------------------------------*/\r
2180 \r
2181 IotMqttError_t IotMqtt_SerializeConnect( const IotMqttConnectInfo_t * pConnectInfo,\r
2182                                          size_t remainingLength,\r
2183                                          uint8_t * pBuffer,\r
2184                                          size_t bufferSize )\r
2185 {\r
2186     IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS );\r
2187 \r
2188     if( ( pBuffer == NULL ) || ( pConnectInfo == NULL ) )\r
2189     {\r
2190         IotLogError( "IotMqtt_SerializeConnect() called with required parameter(s) set to NULL." );\r
2191         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER );\r
2192     }\r
2193 \r
2194     if( ( pConnectInfo->clientIdentifierLength == 0 ) || ( pConnectInfo->pClientIdentifier == NULL ) )\r
2195     {\r
2196         IotLogError( "IotMqtt_SerializeConnect() client identifier must be set." );\r
2197         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER );\r
2198     }\r
2199 \r
2200     if( remainingLength > bufferSize )\r
2201     {\r
2202         IotLogError( " Serialize Connect packet remaining length (%lu) exceeds buffer size (%lu)",\r
2203                      remainingLength, bufferSize );\r
2204         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER );\r
2205     }\r
2206 \r
2207     _serializeConnect( pConnectInfo,\r
2208                        remainingLength,\r
2209                        pBuffer,\r
2210                        bufferSize );\r
2211 \r
2212     IOT_FUNCTION_EXIT_NO_CLEANUP();\r
2213 }\r
2214 \r
2215 /*-----------------------------------------------------------*/\r
2216 \r
2217 IotMqttError_t IotMqtt_GetSubscriptionPacketSize( IotMqttOperationType_t type,\r
2218                                                   const IotMqttSubscription_t * pSubscriptionList,\r
2219                                                   size_t subscriptionCount,\r
2220                                                   size_t * pRemainingLength,\r
2221                                                   size_t * pPacketSize )\r
2222 {\r
2223     IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS );\r
2224 \r
2225     if( ( pSubscriptionList == NULL ) || ( pRemainingLength == NULL ) || ( pPacketSize == NULL ) )\r
2226     {\r
2227         IotLogError( "IotMqtt_GetSubscriptionPacketSize() called with required parameter(s) set to NULL." );\r
2228         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER );\r
2229     }\r
2230 \r
2231     if( ( type != IOT_MQTT_SUBSCRIBE ) && ( type != IOT_MQTT_UNSUBSCRIBE ) )\r
2232     {\r
2233         IotLogError( "IotMqtt_GetSubscriptionPacketSize() called with unknown type." );\r
2234         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER );\r
2235     }\r
2236 \r
2237     if( subscriptionCount == 0 )\r
2238     {\r
2239         IotLogError( "IotMqtt_GetSubscriptionPacketSize() called with zero subscription count." );\r
2240         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER );\r
2241     }\r
2242 \r
2243     if( _subscriptionPacketSize( type,\r
2244                                  pSubscriptionList,\r
2245                                  subscriptionCount,\r
2246                                  pRemainingLength,\r
2247                                  pPacketSize ) == false )\r
2248     {\r
2249         IotLogError( "Unsubscribe packet remaining length exceeds %lu, which is the "\r
2250                      "maximum size allowed by MQTT 3.1.1.",\r
2251                      MQTT_MAX_REMAINING_LENGTH );\r
2252         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER );\r
2253     }\r
2254     else\r
2255     {\r
2256         EMPTY_ELSE_MARKER;\r
2257     }\r
2258 \r
2259     /* Total size of the subscribe packet should be larger than the "Remaining length"\r
2260      * field. */\r
2261     if( ( *pPacketSize ) < ( *pRemainingLength ) )\r
2262     {\r
2263         IotLogError( "Subscription packet remaining length (%lu) exceeds packet size (%lu)",\r
2264                      ( *pRemainingLength ), ( *pPacketSize ) );\r
2265         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER );\r
2266     }\r
2267 \r
2268     IOT_FUNCTION_EXIT_NO_CLEANUP();\r
2269 }\r
2270 \r
2271 /*-----------------------------------------------------------*/\r
2272 \r
2273 IotMqttError_t IotMqtt_SerializeSubscribe( const IotMqttSubscription_t * pSubscriptionList,\r
2274                                            size_t subscriptionCount,\r
2275                                            size_t remainingLength,\r
2276                                            uint16_t * pPacketIdentifier,\r
2277                                            uint8_t * pBuffer,\r
2278                                            size_t bufferSize )\r
2279 {\r
2280     IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS );\r
2281 \r
2282     if( ( pBuffer == NULL ) || ( pSubscriptionList == NULL ) || ( pPacketIdentifier == NULL ) )\r
2283     {\r
2284         IotLogError( "IotMqtt_SerializeSubscribe() called with required parameter(s) set to NULL." );\r
2285         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER );\r
2286     }\r
2287 \r
2288     if( subscriptionCount == 0 )\r
2289     {\r
2290         IotLogError( "IotMqtt_SerializeSubscribe() called with zero subscription count." );\r
2291         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER );\r
2292     }\r
2293 \r
2294     if( remainingLength > bufferSize )\r
2295     {\r
2296         IotLogError( " Subscribe packet remaining length (%lu) exceeds buffer size (%lu).",\r
2297                      remainingLength, bufferSize );\r
2298         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER );\r
2299     }\r
2300 \r
2301     _serializeSubscribe( pSubscriptionList,\r
2302                          subscriptionCount,\r
2303                          remainingLength,\r
2304                          pPacketIdentifier,\r
2305                          pBuffer,\r
2306                          bufferSize );\r
2307 \r
2308     IOT_FUNCTION_EXIT_NO_CLEANUP();\r
2309 }\r
2310 \r
2311 /*-----------------------------------------------------------*/\r
2312 \r
2313 IotMqttError_t IotMqtt_GetPublishPacketSize( IotMqttPublishInfo_t * pPublishInfo,\r
2314                                              size_t * pRemainingLength,\r
2315                                              size_t * pPacketSize )\r
2316 {\r
2317     IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS );\r
2318 \r
2319     if( ( pPublishInfo == NULL ) || ( pRemainingLength == NULL ) || ( pPacketSize == NULL ) )\r
2320     {\r
2321         IotLogError( "IotMqtt_GetPublishPacketSize() called with required parameter(s) set to NULL." );\r
2322         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER );\r
2323     }\r
2324 \r
2325     if( ( pPublishInfo->pTopicName == NULL ) || ( pPublishInfo->topicNameLength == 0 ) )\r
2326     {\r
2327         IotLogError( "IotMqtt_GetPublishPacketSize() called with no topic." );\r
2328         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER );\r
2329     }\r
2330 \r
2331     /* Calculate the "Remaining length" field and total packet size. If it exceeds\r
2332      * what is allowed in the MQTT standard, return an error. */\r
2333     if( _publishPacketSize( pPublishInfo, pRemainingLength, pPacketSize ) == false )\r
2334     {\r
2335         IotLogError( "Publish packet remaining length exceeds %lu, which is the "\r
2336                      "maximum size allowed by MQTT 3.1.1.",\r
2337                      MQTT_MAX_REMAINING_LENGTH );\r
2338 \r
2339         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER );\r
2340     }\r
2341     else\r
2342     {\r
2343         EMPTY_ELSE_MARKER;\r
2344     }\r
2345 \r
2346     /* Total size of the publish packet should be larger than the "Remaining length"\r
2347      * field. */\r
2348     if( ( *pPacketSize ) < ( *pRemainingLength ) )\r
2349     {\r
2350         IotLogError( "Publish packet remaining length (%lu) exceeds packet size (%lu).",\r
2351                      ( *pRemainingLength ), ( *pPacketSize ) );\r
2352         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER );\r
2353     }\r
2354 \r
2355     IOT_FUNCTION_EXIT_NO_CLEANUP();\r
2356 }\r
2357 \r
2358 /*-----------------------------------------------------------*/\r
2359 \r
2360 IotMqttError_t IotMqtt_SerializePublish( IotMqttPublishInfo_t * pPublishInfo,\r
2361                                          size_t remainingLength,\r
2362                                          uint16_t * pPacketIdentifier,\r
2363                                          uint8_t ** pPacketIdentifierHigh,\r
2364                                          uint8_t * pBuffer,\r
2365                                          size_t bufferSize )\r
2366 \r
2367 {\r
2368     IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS );\r
2369 \r
2370     if( ( pBuffer == NULL ) || ( pPublishInfo == NULL ) || ( pPacketIdentifier == NULL ) )\r
2371     {\r
2372         IotLogError( "IotMqtt_SerializePublish() called with required parameter(s) set to NULL." );\r
2373         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER );\r
2374     }\r
2375 \r
2376     if( ( pPublishInfo->pTopicName == NULL ) || ( pPublishInfo->topicNameLength == 0 ) )\r
2377     {\r
2378         IotLogError( "IotMqtt_SerializePublish() called with no topic." );\r
2379         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER );\r
2380     }\r
2381 \r
2382     if( remainingLength > bufferSize )\r
2383     {\r
2384         IotLogError( "Publish packet remaining length (%lu) exceeds buffer size (%lu).",\r
2385                      remainingLength, bufferSize );\r
2386         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER );\r
2387     }\r
2388 \r
2389     _serializePublish( pPublishInfo,\r
2390                        remainingLength,\r
2391                        pPacketIdentifier,\r
2392                        pPacketIdentifierHigh,\r
2393                        pBuffer,\r
2394                        bufferSize );\r
2395     IOT_FUNCTION_EXIT_NO_CLEANUP();\r
2396 }\r
2397 \r
2398 /*-----------------------------------------------------------*/\r
2399 \r
2400 IotMqttError_t IotMqtt_SerializeUnsubscribe( const IotMqttSubscription_t * pSubscriptionList,\r
2401                                              size_t subscriptionCount,\r
2402                                              size_t remainingLength,\r
2403                                              uint16_t * pPacketIdentifier,\r
2404                                              uint8_t * pBuffer,\r
2405                                              size_t bufferSize )\r
2406 {\r
2407     IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS );\r
2408 \r
2409     if( ( pBuffer == NULL ) || ( pPacketIdentifier == NULL ) || ( pSubscriptionList == NULL ) )\r
2410     {\r
2411         IotLogError( "IotMqtt_SerializeUnsubscribe() called with required parameter(s) set to NULL." );\r
2412         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER );\r
2413     }\r
2414 \r
2415     if( subscriptionCount == 0 )\r
2416     {\r
2417         IotLogError( "IotMqtt_SerializeUnsubscribe() called with zero subscription count." );\r
2418         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER );\r
2419     }\r
2420 \r
2421     if( remainingLength > bufferSize )\r
2422     {\r
2423         IotLogError( "Unsubscribe packet remaining length (%lu) exceeds buffer size (%lu).",\r
2424                      remainingLength, bufferSize );\r
2425         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER );\r
2426     }\r
2427 \r
2428     _serializeUnsubscribe( pSubscriptionList,\r
2429                            subscriptionCount,\r
2430                            remainingLength,\r
2431                            pPacketIdentifier,\r
2432                            pBuffer,\r
2433                            bufferSize );\r
2434     IOT_FUNCTION_EXIT_NO_CLEANUP();\r
2435 }\r
2436 \r
2437 /*-----------------------------------------------------------*/\r
2438 \r
2439 IotMqttError_t IotMqtt_SerializeDisconnect( uint8_t * pBuffer,\r
2440                                             size_t bufferSize )\r
2441 {\r
2442     IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS );\r
2443     uint8_t * pDisconnectPacket = NULL;\r
2444     size_t remainingLength = 0;\r
2445 \r
2446     if( pBuffer == NULL )\r
2447     {\r
2448         IotLogError( "IotMqtt_SerializeDisconnect() called with NULL buffer pointer." );\r
2449         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER );\r
2450     }\r
2451 \r
2452     if( bufferSize < MQTT_PACKET_DISCONNECT_SIZE )\r
2453     {\r
2454         IotLogError( "Disconnect packet length (%lu) exceeds buffer size (%lu).",\r
2455                      MQTT_PACKET_DISCONNECT_SIZE, bufferSize );\r
2456         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER );\r
2457     }\r
2458 \r
2459     /* Call internal function with local variables, as disconnect  uses\r
2460      * static memory, there is no need to pass the buffer\r
2461      * Note: _IotMqtt_SerializeDisconnect always succeeds */\r
2462     _IotMqtt_SerializeDisconnect( &pDisconnectPacket, &remainingLength );\r
2463 \r
2464     memcpy( pBuffer, pDisconnectPacket, MQTT_PACKET_DISCONNECT_SIZE );\r
2465     IOT_FUNCTION_EXIT_NO_CLEANUP();\r
2466 }\r
2467 \r
2468 /*-----------------------------------------------------------*/\r
2469 \r
2470 IotMqttError_t IotMqtt_SerializePingreq( uint8_t * pBuffer,\r
2471                                          size_t bufferSize )\r
2472 {\r
2473     IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS );\r
2474     uint8_t * pPingreqPacket = NULL;\r
2475     size_t packetSize = 0;\r
2476 \r
2477     if( pBuffer == NULL )\r
2478     {\r
2479         IotLogError( "IotMqtt_SerializePingreq() called with NULL buffer pointer." );\r
2480         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER );\r
2481     }\r
2482 \r
2483     if( bufferSize < MQTT_PACKET_PINGREQ_SIZE )\r
2484     {\r
2485         IotLogError( "Pingreq length (%lu) exceeds buffer size (%lu).",\r
2486                      MQTT_PACKET_DISCONNECT_SIZE, bufferSize );\r
2487         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER );\r
2488     }\r
2489 \r
2490     /* Call internal function with local variables, as ping request uses\r
2491      * static memory, there is no need to pass the buffer\r
2492      * Note: _IotMqtt_SerializePingReq always succeeds */\r
2493     _IotMqtt_SerializePingreq( &pPingreqPacket, &packetSize );\r
2494     memcpy( pBuffer, pPingreqPacket, MQTT_PACKET_PINGREQ_SIZE );\r
2495     IOT_FUNCTION_EXIT_NO_CLEANUP();\r
2496 }\r
2497 \r
2498 /*-----------------------------------------------------------*/\r
2499 \r
2500 IotMqttError_t IotMqtt_DeserializePublish( IotMqttPacketInfo_t * pMqttPacket )\r
2501 {\r
2502     IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS );\r
2503     /* Internal MQTT packet structure */\r
2504     _mqttPacket_t mqttPacket;\r
2505     /* Internal MQTT operation structure needed for deserializing publish */\r
2506     _mqttOperation_t mqttOperation;\r
2507 \r
2508     if( pMqttPacket == NULL )\r
2509     {\r
2510         IotLogError( "IotMqtt_DeserializePublish()called with NULL pMqttPacket pointer." );\r
2511         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER );\r
2512     }\r
2513 \r
2514     if( ( pMqttPacket->type & 0xf0 ) != MQTT_PACKET_TYPE_PUBLISH )\r
2515     {\r
2516         IotLogError( "IotMqtt_DeserializePublish() called with incorrect packet type:(%lu).", pMqttPacket->type );\r
2517         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER );\r
2518     }\r
2519 \r
2520     /* Set internal mqtt packet parameters. */\r
2521     memset( ( void * ) &mqttPacket, 0x00, sizeof( _mqttPacket_t ) );\r
2522     mqttPacket.pRemainingData = pMqttPacket->pRemainingData;\r
2523     mqttPacket.remainingLength = pMqttPacket->remainingLength;\r
2524     mqttPacket.type = pMqttPacket->type;\r
2525 \r
2526     /* Set Publish specific parameters */\r
2527     memset( ( void * ) &mqttOperation, 0x00, sizeof( _mqttOperation_t ) );\r
2528     mqttOperation.incomingPublish = true;\r
2529     mqttPacket.u.pIncomingPublish = &mqttOperation;\r
2530     status = _IotMqtt_DeserializePublish( &mqttPacket );\r
2531 \r
2532     if( status == IOT_MQTT_SUCCESS )\r
2533     {\r
2534         pMqttPacket->pubInfo = mqttOperation.u.publish.publishInfo;\r
2535         pMqttPacket->packetIdentifier = mqttPacket.packetIdentifier;\r
2536     }\r
2537 \r
2538     IOT_FUNCTION_EXIT_NO_CLEANUP();\r
2539 }\r
2540 \r
2541 /*-----------------------------------------------------------*/\r
2542 \r
2543 IotMqttError_t IotMqtt_DeserializeResponse( IotMqttPacketInfo_t * pMqttPacket )\r
2544 {\r
2545     IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS );\r
2546     /* Internal MQTT packet structure */\r
2547     _mqttPacket_t mqttPacket;\r
2548 \r
2549     if( ( pMqttPacket == NULL ) || ( pMqttPacket->pRemainingData == NULL ) )\r
2550     {\r
2551         IotLogError( "IotMqtt_DeserializeResponse() called with NULL pMqttPacket pointer or NULL pRemainingLength." );\r
2552         IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER );\r
2553     }\r
2554 \r
2555     /* Set internal mqtt packet parameters. */\r
2556     memset( ( void * ) &mqttPacket, 0x00, sizeof( _mqttPacket_t ) );\r
2557 \r
2558     mqttPacket.pRemainingData = pMqttPacket->pRemainingData;\r
2559     mqttPacket.remainingLength = pMqttPacket->remainingLength;\r
2560     mqttPacket.type = pMqttPacket->type;\r
2561 \r
2562     /* Call internal deserialize */\r
2563     switch( pMqttPacket->type & 0xf0 )\r
2564     {\r
2565         case MQTT_PACKET_TYPE_CONNACK:\r
2566             status = _IotMqtt_DeserializeConnack( &mqttPacket );\r
2567             break;\r
2568 \r
2569         case MQTT_PACKET_TYPE_PUBACK:\r
2570             status = _IotMqtt_DeserializePuback( &mqttPacket );\r
2571             break;\r
2572 \r
2573         case MQTT_PACKET_TYPE_SUBACK:\r
2574             status = _IotMqtt_DeserializeSuback( &mqttPacket );\r
2575             break;\r
2576 \r
2577         case MQTT_PACKET_TYPE_UNSUBACK:\r
2578             status = _IotMqtt_DeserializeUnsuback( &mqttPacket );\r
2579             break;\r
2580 \r
2581         case MQTT_PACKET_TYPE_PINGRESP:\r
2582             status = _IotMqtt_DeserializePingresp( &mqttPacket );\r
2583             break;\r
2584 \r
2585         /* Any other packet type is invalid. */\r
2586         default:\r
2587             IotLogError( "IotMqtt_DeserializeResponse() called with unknown packet type:(%lu).", pMqttPacket->type );\r
2588             IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER );\r
2589     }\r
2590 \r
2591     if( status != IOT_MQTT_SUCCESS )\r
2592     {\r
2593         IOT_SET_AND_GOTO_CLEANUP( status );\r
2594     }\r
2595     else\r
2596     {\r
2597         /* Set packetIdentifier only if success is returned. */\r
2598         pMqttPacket->packetIdentifier = mqttPacket.packetIdentifier;\r
2599     }\r
2600 \r
2601     IOT_FUNCTION_EXIT_NO_CLEANUP();\r
2602 }\r
2603 \r
2604 /*-----------------------------------------------------------*/\r