3 * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
\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
12 * The above copyright notice and this permission notice shall be included in all
\r
13 * copies or substantial portions of the Software.
\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
24 * @file iot_mqtt_serialize.c
\r
25 * @brief Implements functions that generate and decode MQTT network packets.
\r
28 /* The config header is always included first. */
\r
29 #include "iot_config.h"
\r
31 /* Standard includes. */
\r
34 /* Error handling include. */
\r
35 #include "iot_error.h"
\r
37 /* MQTT internal includes. */
\r
38 #include "private/iot_mqtt_internal.h"
\r
40 /* Platform layer includes. */
\r
41 #include "platform/iot_threads.h"
\r
43 /* Atomic operations. */
\r
44 #include "iot_atomic.h"
\r
46 /*-----------------------------------------------------------*/
\r
49 * Macros for reading the high and low byte of a 2-byte unsigned int.
\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
55 * @brief Macro for decoding a 2-byte unsigned int from a sequence of bytes.
\r
57 * @param[in] ptr A uint8_t* that points to the high byte.
\r
59 #define UINT16_DECODE( ptr ) \
\r
60 ( uint16_t ) ( ( ( ( uint16_t ) ( *( ptr ) ) ) << 8 ) | \
\r
61 ( ( uint16_t ) ( *( ptr + 1 ) ) ) )
\r
64 * @brief Macro for setting a bit in a 1-byte unsigned int.
\r
66 * @param[in] x The unsigned int to set.
\r
67 * @param[in] position Which bit to set.
\r
69 #define UINT8_SET_BIT( x, position ) ( x = ( uint8_t ) ( x | ( 0x01 << position ) ) )
\r
72 * @brief Macro for checking if a bit is set in a 1-byte unsigned int.
\r
74 * @param[in] x The unsigned int to check.
\r
75 * @param[in] position Which bit to check.
\r
77 #define UINT8_CHECK_BIT( x, position ) ( ( x & ( 0x01 << position ) ) == ( 0x01 << position ) )
\r
80 * Positions of each flag in the "Connect Flag" field of an MQTT CONNECT
\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
92 * Positions of each flag in the first byte of an MQTT PUBLISH packet's
\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
101 * @brief The constant specifying MQTT version 3.1.1. Placed in the CONNECT packet.
\r
103 #define MQTT_VERSION_3_1_1 ( ( uint8_t ) 4U )
\r
106 * @brief Per the MQTT 3.1.1 spec, the largest "Remaining Length" of an MQTT
\r
107 * packet is this value.
\r
109 #define MQTT_MAX_REMAINING_LENGTH ( 268435455UL )
\r
112 * @brief The maximum possible size of a CONNECT packet.
\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
117 #define MQTT_PACKET_CONNECT_MAX_SIZE ( 327700UL )
\r
120 * Constants relating to CONNACK packets, defined by MQTT 3.1.1 spec.
\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
126 * Constants relating to PUBLISH and PUBACK packets, defined by MQTT
\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
133 * Constants relating to SUBACK and UNSUBACK packets, defined by MQTT
\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
140 * Constants relating to PINGREQ and PINGRESP packets, defined by MQTT 3.1.1 spec.
\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
146 * Constants relating to DISCONNECT packets, defined by MQTT 3.1.1 spec.
\r
148 #define MQTT_PACKET_DISCONNECT_SIZE ( 2 ) /**< @brief A DISCONNECT packet is always 2 bytes in size. */
\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
155 * @brief Specify C SDK and version.
\r
157 #define AWS_IOT_METRICS_USERNAME "?SDK=C&Version=4.0.0"
\r
160 * @brief The length of #AWS_IOT_METRICS_USERNAME.
\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
166 /*-----------------------------------------------------------*/
\r
169 * @brief Generate and return a 2-byte packet identifier.
\r
171 * This packet identifier will be nonzero.
\r
173 * @return The packet identifier.
\r
175 static uint16_t _nextPacketIdentifier( void );
\r
178 * @brief Calculate the number of bytes required to encode an MQTT
\r
179 * "Remaining length" field.
\r
181 * @param[in] length The value of the "Remaining length" to encode.
\r
183 * @return The size of the encoding of length. This is always `1`, `2`, `3`, or `4`.
\r
185 static size_t _remainingLengthEncodedSize( size_t length );
\r
188 * @brief Encode the "Remaining length" field per MQTT spec.
\r
190 * @param[out] pDestination Where to write the encoded "Remaining length".
\r
191 * @param[in] length The "Remaining length" to encode.
\r
193 * @return Pointer to the end of the encoded "Remaining length", which is 1-4
\r
194 * bytes greater than `pDestination`.
\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
200 static uint8_t * _encodeRemainingLength( uint8_t * pDestination,
\r
204 * @brief Encode a C string as a UTF-8 string, per MQTT 3.1.1 spec.
\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
210 * @return Pointer to the end of the encoded string, which is `sourceLength+2`
\r
211 * bytes greater than `pDestination`.
\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
217 static uint8_t * _encodeString( uint8_t * pDestination,
\r
218 const char * source,
\r
219 uint16_t sourceLength );
\r
222 * @brief Calculate the size and "Remaining length" of a CONNECT packet generated
\r
223 * from the given parameters.
\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
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
232 static bool _connectPacketSize( const IotMqttConnectInfo_t * pConnectInfo,
\r
233 size_t * pRemainingLength,
\r
234 size_t * pPacketSize );
\r
237 * @brief Calculate the size and "Remaining length" of a PUBLISH packet generated
\r
238 * from the given parameters.
\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
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
247 static bool _publishPacketSize( const IotMqttPublishInfo_t * pPublishInfo,
\r
248 size_t * pRemainingLength,
\r
249 size_t * pPacketSize );
\r
252 * @brief Calculate the size and "Remaining length" of a SUBSCRIBE or UNSUBSCRIBE
\r
253 * packet generated from the given parameters.
\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
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
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
271 * @brief Generate a CONNECT packet from the given parameters.
\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
279 void _serializeConnect( const IotMqttConnectInfo_t * pConnectInfo,
\r
280 size_t remainingLength,
\r
282 size_t connectPacketSize );
\r
285 * @brief Generate a PUBLISH packet from the given parameters.
\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
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
296 void _serializePublish( const IotMqttPublishInfo_t * pPublishInfo,
\r
297 size_t remainingLength,
\r
298 uint16_t * pPacketIdentifier,
\r
299 uint8_t ** pPacketIdentifierHigh,
\r
301 size_t publishPacketSize );
\r
304 * @brief Generate a SUBSCRIBE packet from the given parameters.
\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
314 void _serializeSubscribe( const IotMqttSubscription_t * pSubscriptionList,
\r
315 size_t subscriptionCount,
\r
316 size_t remainingLength,
\r
317 uint16_t * pPacketIdentifier,
\r
319 size_t subscribePacketSize );
\r
322 * @brief Generate an UNSUBSCRIBE packet from the given parameters.
\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
332 void _serializeUnsubscribe( const IotMqttSubscription_t * pSubscriptionList,
\r
333 size_t subscriptionCount,
\r
334 size_t remainingLength,
\r
335 uint16_t * pPacketIdentifier,
\r
337 size_t unsubscribePacketSize );
\r
339 /*-----------------------------------------------------------*/
\r
341 #if LIBRARY_LOG_LEVEL > IOT_LOG_NONE
\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
347 static const IotLogConfig_t _logHideAll =
\r
349 .hideLibraryName = true,
\r
350 .hideLogLevel = true,
\r
351 .hideTimestring = true
\r
355 /*-----------------------------------------------------------*/
\r
357 static uint16_t _nextPacketIdentifier( void )
\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
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
369 /*-----------------------------------------------------------*/
\r
371 static size_t _remainingLengthEncodedSize( size_t length )
\r
373 size_t encodedSize = 0;
\r
375 /* length should have already been checked before calling this function. */
\r
376 IotMqtt_Assert( length <= MQTT_MAX_REMAINING_LENGTH );
\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
381 /* 1 byte is needed to encode lengths between 0 and 127. */
\r
386 /* 2 bytes are needed to encode lengths between 128 and 16,383. */
\r
387 else if( length < 16384 )
\r
391 /* 3 bytes are needed to encode lengths between 16,384 and 2,097,151. */
\r
392 else if( length < 2097152 )
\r
396 /* 4 bytes are needed to encode lengths between 2,097,152 and 268,435,455. */
\r
402 return encodedSize;
\r
405 /*-----------------------------------------------------------*/
\r
407 static uint8_t * _encodeRemainingLength( uint8_t * pDestination,
\r
410 uint8_t lengthByte = 0, * pLengthEnd = pDestination;
\r
412 /* This algorithm is copied from the MQTT v3.1.1 spec. */
\r
415 lengthByte = length % 128;
\r
416 length = length / 128;
\r
418 /* Set the high bit of this byte, indicating that there's more data. */
\r
421 UINT8_SET_BIT( lengthByte, 7 );
\r
428 /* Output a single encoded byte. */
\r
429 *pLengthEnd = lengthByte;
\r
431 } while( length > 0 );
\r
436 /*-----------------------------------------------------------*/
\r
438 static uint8_t * _encodeString( uint8_t * pDestination,
\r
439 const char * source,
\r
440 uint16_t sourceLength )
\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
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
450 /* Copy the string into pDestination. */
\r
451 ( void ) memcpy( pDestination, source, sourceLength );
\r
453 /* Return the pointer to the end of the encoded string. */
\r
454 pDestination += sourceLength;
\r
456 return pDestination;
\r
459 /*-----------------------------------------------------------*/
\r
461 static bool _connectPacketSize( const IotMqttConnectInfo_t * pConnectInfo,
\r
462 size_t * pRemainingLength,
\r
463 size_t * pPacketSize )
\r
465 bool status = true;
\r
466 size_t connectPacketSize = 0, remainingLength = 0;
\r
468 /* The CONNECT packet will always include a 10-byte variable header. */
\r
469 connectPacketSize += 10U;
\r
471 /* Add the length of the client identifier if provided. */
\r
472 connectPacketSize += pConnectInfo->clientIdentifierLength + sizeof( uint16_t );
\r
474 /* Add the lengths of the will message and topic name if provided. */
\r
475 if( pConnectInfo->pWillInfo != NULL )
\r
477 connectPacketSize += pConnectInfo->pWillInfo->topicNameLength + sizeof( uint16_t ) +
\r
478 pConnectInfo->pWillInfo->payloadLength + sizeof( uint16_t );
\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
489 #if AWS_IOT_MQTT_ENABLE_METRICS == 1
\r
490 connectPacketSize += AWS_IOT_METRICS_USERNAME_LENGTH + sizeof( uint16_t );
\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
499 connectPacketSize += pConnectInfo->userNameLength + sizeof( uint16_t );
\r
506 if( pConnectInfo->pPassword != NULL )
\r
508 connectPacketSize += pConnectInfo->passwordLength + sizeof( uint16_t );
\r
516 /* At this point, the "Remaining Length" field of the MQTT CONNECT packet has
\r
517 * been calculated. */
\r
518 remainingLength = connectPacketSize;
\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
524 /* Check that the CONNECT packet is within the bounds of the MQTT spec. */
\r
525 if( connectPacketSize > MQTT_PACKET_CONNECT_MAX_SIZE )
\r
531 *pRemainingLength = remainingLength;
\r
532 *pPacketSize = connectPacketSize;
\r
538 /*-----------------------------------------------------------*/
\r
540 static bool _publishPacketSize( const IotMqttPublishInfo_t * pPublishInfo,
\r
541 size_t * pRemainingLength,
\r
542 size_t * pPacketSize )
\r
544 bool status = true;
\r
545 size_t publishPacketSize = 0, payloadLimit = 0;
\r
547 /* The variable header of a PUBLISH packet always contains the topic name. */
\r
548 publishPacketSize += pPublishInfo->topicNameLength + sizeof( uint16_t );
\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
554 publishPacketSize += sizeof( uint16_t );
\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
564 payloadLimit = MQTT_MAX_REMAINING_LENGTH - publishPacketSize - 1;
\r
566 /* Ensure that the given payload fits within the calculated limit. */
\r
567 if( pPublishInfo->payloadLength > payloadLimit )
\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
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
581 /* Check that the given payload fits within the size allowed by MQTT spec. */
\r
582 if( pPublishInfo->payloadLength > payloadLimit )
\r
588 /* Set the "Remaining length" output parameter and calculate the full
\r
589 * size of the PUBLISH packet. */
\r
590 *pRemainingLength = publishPacketSize;
\r
592 publishPacketSize += 1 + _remainingLengthEncodedSize( publishPacketSize );
\r
593 *pPacketSize = publishPacketSize;
\r
600 /*-----------------------------------------------------------*/
\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
608 bool status = true;
\r
609 size_t i = 0, subscriptionPacketSize = 0;
\r
611 /* Only SUBSCRIBE and UNSUBSCRIBE operations should call this function. */
\r
612 IotMqtt_Assert( ( type == IOT_MQTT_SUBSCRIBE ) || ( type == IOT_MQTT_UNSUBSCRIBE ) );
\r
614 /* The variable header of a subscription packet consists of a 2-byte packet
\r
616 subscriptionPacketSize += sizeof( uint16_t );
\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
622 /* Add the length of the topic filter. */
\r
623 subscriptionPacketSize += pSubscriptionList[ i ].topicFilterLength + sizeof( uint16_t );
\r
625 /* Only SUBSCRIBE packets include the QoS. */
\r
626 if( type == IOT_MQTT_SUBSCRIBE )
\r
628 subscriptionPacketSize += 1;
\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
645 *pRemainingLength = subscriptionPacketSize;
\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
657 /*-----------------------------------------------------------*/
\r
659 void _serializeConnect( const IotMqttConnectInfo_t * pConnectInfo,
\r
660 size_t remainingLength,
\r
662 size_t connectPacketSize )
\r
664 uint8_t connectFlags = 0;
\r
665 uint8_t * pConnectPacket = pBuffer;
\r
667 /* The first byte in the CONNECT packet is the control packet type. */
\r
668 *pBuffer = MQTT_PACKET_TYPE_CONNECT;
\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
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
680 /* The MQTT protocol version is the second byte of the variable header. */
\r
681 *pBuffer = MQTT_VERSION_3_1_1;
\r
684 /* Set the CONNECT flags based on the given parameters. */
\r
685 if( pConnectInfo->cleanSession == true )
\r
687 UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_CLEAN );
\r
694 /* Username and password depend on MQTT mode. */
\r
695 if( pConnectInfo->awsIotMqttMode == true )
\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
705 /* Set the flags for username and password if provided. */
\r
706 if( pConnectInfo->pUserName != NULL )
\r
708 UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_USERNAME );
\r
715 if( pConnectInfo->pPassword != NULL )
\r
717 UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_PASSWORD );
\r
725 /* Set will flag if an LWT is provided. */
\r
726 if( pConnectInfo->pWillInfo != NULL )
\r
728 UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_WILL );
\r
730 /* Flags only need to be changed for will QoS 1 and 2. */
\r
731 switch( pConnectInfo->pWillInfo->qos )
\r
733 case IOT_MQTT_QOS_1:
\r
734 UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_WILL_QOS1 );
\r
737 case IOT_MQTT_QOS_2:
\r
738 UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_WILL_QOS2 );
\r
745 if( pConnectInfo->pWillInfo->retain == true )
\r
747 UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_WILL_RETAIN );
\r
759 *pBuffer = connectFlags;
\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
767 /* Write the client identifier into the CONNECT packet. */
\r
768 pBuffer = _encodeString( pBuffer,
\r
769 pConnectInfo->pClientIdentifier,
\r
770 pConnectInfo->clientIdentifierLength );
\r
772 /* Write the will topic name and message into the CONNECT packet if provided. */
\r
773 if( pConnectInfo->pWillInfo != NULL )
\r
775 pBuffer = _encodeString( pBuffer,
\r
776 pConnectInfo->pWillInfo->pTopicName,
\r
777 pConnectInfo->pWillInfo->topicNameLength );
\r
779 pBuffer = _encodeString( pBuffer,
\r
780 pConnectInfo->pWillInfo->pPayload,
\r
781 ( uint16_t ) pConnectInfo->pWillInfo->payloadLength );
\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
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
797 pBuffer = _encodeString( pBuffer,
\r
798 AWS_IOT_METRICS_USERNAME,
\r
799 AWS_IOT_METRICS_USERNAME_LENGTH );
\r
804 if( pConnectInfo->pUserName != NULL )
\r
806 pBuffer = _encodeString( pBuffer,
\r
807 pConnectInfo->pUserName,
\r
808 pConnectInfo->userNameLength );
\r
815 if( pConnectInfo->pPassword != NULL )
\r
817 pBuffer = _encodeString( pBuffer,
\r
818 pConnectInfo->pPassword,
\r
819 pConnectInfo->passwordLength );
\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
831 /* Print out the serialized CONNECT packet for debugging purposes. */
\r
832 IotLog_PrintBuffer( "MQTT CONNECT packet:", pConnectPacket, connectPacketSize );
\r
835 /*-----------------------------------------------------------*/
\r
837 void _serializePublish( const IotMqttPublishInfo_t * pPublishInfo,
\r
838 size_t remainingLength,
\r
839 uint16_t * pPacketIdentifier,
\r
840 uint8_t ** pPacketIdentifierHigh,
\r
842 size_t publishPacketSize )
\r
844 uint8_t publishFlags = 0;
\r
845 uint16_t packetIdentifier = 0;
\r
846 uint8_t * pPublishPacket = pBuffer;
\r
848 /* The first byte of a PUBLISH packet contains the packet type and flags. */
\r
849 publishFlags = MQTT_PACKET_TYPE_PUBLISH;
\r
851 if( pPublishInfo->qos == IOT_MQTT_QOS_1 )
\r
853 UINT8_SET_BIT( publishFlags, MQTT_PUBLISH_FLAG_QOS1 );
\r
855 else if( pPublishInfo->qos == IOT_MQTT_QOS_2 )
\r
857 UINT8_SET_BIT( publishFlags, MQTT_PUBLISH_FLAG_QOS2 );
\r
864 if( pPublishInfo->retain == true )
\r
866 UINT8_SET_BIT( publishFlags, MQTT_PUBLISH_FLAG_RETAIN );
\r
873 *pBuffer = publishFlags;
\r
876 /* The "Remaining length" is encoded from the second byte. */
\r
877 pBuffer = _encodeRemainingLength( pBuffer, remainingLength );
\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
884 /* A packet identifier is required for QoS 1 and 2 messages. */
\r
885 if( pPublishInfo->qos > IOT_MQTT_QOS_0 )
\r
887 /* Get the next packet identifier. It should always be nonzero. */
\r
888 packetIdentifier = _nextPacketIdentifier();
\r
889 IotMqtt_Assert( packetIdentifier != 0 );
\r
891 /* Set the packet identifier output parameters. */
\r
892 *pPacketIdentifier = packetIdentifier;
\r
894 if( pPacketIdentifierHigh != NULL )
\r
896 *pPacketIdentifierHigh = pBuffer;
\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
913 /* The payload is placed after the packet identifier. */
\r
914 if( pPublishInfo->payloadLength > 0 )
\r
916 ( void ) memcpy( pBuffer, pPublishInfo->pPayload, pPublishInfo->payloadLength );
\r
917 pBuffer += pPublishInfo->payloadLength;
\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
928 /* Print out the serialized PUBLISH packet for debugging purposes. */
\r
929 IotLog_PrintBuffer( "MQTT PUBLISH packet:", pPublishPacket, publishPacketSize );
\r
932 /*-----------------------------------------------------------*/
\r
934 void _serializeSubscribe( const IotMqttSubscription_t * pSubscriptionList,
\r
935 size_t subscriptionCount,
\r
936 size_t remainingLength,
\r
937 uint16_t * pPacketIdentifier,
\r
939 size_t subscribePacketSize )
\r
941 uint16_t packetIdentifier = 0;
\r
943 uint8_t * pSubscribePacket = pBuffer;
\r
945 /* The first byte in SUBSCRIBE is the packet type. */
\r
946 *pBuffer = MQTT_PACKET_TYPE_SUBSCRIBE;
\r
949 /* Encode the "Remaining length" starting from the second byte. */
\r
950 pBuffer = _encodeRemainingLength( pBuffer, remainingLength );
\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
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
962 /* Serialize each subscription topic filter and QoS. */
\r
963 for( i = 0; i < subscriptionCount; i++ )
\r
965 pBuffer = _encodeString( pBuffer,
\r
966 pSubscriptionList[ i ].pTopicFilter,
\r
967 pSubscriptionList[ i ].topicFilterLength );
\r
969 /* Place the QoS in the SUBSCRIBE packet. */
\r
970 *pBuffer = ( uint8_t ) ( pSubscriptionList[ i ].qos );
\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
978 /* Print out the serialized SUBSCRIBE packet for debugging purposes. */
\r
979 IotLog_PrintBuffer( "MQTT SUBSCRIBE packet:", pSubscribePacket, subscribePacketSize );
\r
982 /*-----------------------------------------------------------*/
\r
984 void _serializeUnsubscribe( const IotMqttSubscription_t * pSubscriptionList,
\r
985 size_t subscriptionCount,
\r
986 size_t remainingLength,
\r
987 uint16_t * pPacketIdentifier,
\r
989 size_t unsubscribePacketSize )
\r
991 uint16_t packetIdentifier = 0;
\r
993 uint8_t * pUnsubscribePacket = pBuffer;
\r
995 /* The first byte in UNSUBSCRIBE is the packet type. */
\r
996 *pBuffer = MQTT_PACKET_TYPE_UNSUBSCRIBE;
\r
999 /* Encode the "Remaining length" starting from the second byte. */
\r
1000 pBuffer = _encodeRemainingLength( pBuffer, remainingLength );
\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
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
1012 /* Serialize each subscription topic filter. */
\r
1013 for( i = 0; i < subscriptionCount; i++ )
\r
1015 pBuffer = _encodeString( pBuffer,
\r
1016 pSubscriptionList[ i ].pTopicFilter,
\r
1017 pSubscriptionList[ i ].topicFilterLength );
\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
1024 /* Print out the serialized UNSUBSCRIBE packet for debugging purposes. */
\r
1025 IotLog_PrintBuffer( "MQTT UNSUBSCRIBE packet:", pUnsubscribePacket, unsubscribePacketSize );
\r
1028 /*-----------------------------------------------------------*/
\r
1030 uint8_t _IotMqtt_GetPacketType( void * pNetworkConnection,
\r
1031 const IotNetworkInterface_t * pNetworkInterface )
\r
1033 uint8_t packetType = 0xff;
\r
1035 /* The MQTT packet type is in the first byte of the packet. */
\r
1036 ( void ) _IotMqtt_GetNextByte( pNetworkConnection,
\r
1037 pNetworkInterface,
\r
1040 return packetType;
\r
1043 /*-----------------------------------------------------------*/
\r
1045 size_t _IotMqtt_GetRemainingLength( void * pNetworkConnection,
\r
1046 const IotNetworkInterface_t * pNetworkInterface )
\r
1048 uint8_t encodedByte = 0;
\r
1049 size_t remainingLength = 0, multiplier = 1, bytesDecoded = 0, expectedSize = 0;
\r
1051 /* This algorithm is copied from the MQTT v3.1.1 spec. */
\r
1054 if( multiplier > 2097152 ) /* 128 ^ 3 */
\r
1056 remainingLength = MQTT_REMAINING_LENGTH_INVALID;
\r
1061 if( _IotMqtt_GetNextByte( pNetworkConnection,
\r
1062 pNetworkInterface,
\r
1063 &encodedByte ) == true )
\r
1065 remainingLength += ( encodedByte & 0x7F ) * multiplier;
\r
1066 multiplier *= 128;
\r
1071 remainingLength = MQTT_REMAINING_LENGTH_INVALID;
\r
1075 } while( ( encodedByte & 0x80 ) != 0 );
\r
1077 /* Check that the decoded remaining length conforms to the MQTT specification. */
\r
1078 if( remainingLength != MQTT_REMAINING_LENGTH_INVALID )
\r
1080 expectedSize = _remainingLengthEncodedSize( remainingLength );
\r
1082 if( bytesDecoded != expectedSize )
\r
1084 remainingLength = MQTT_REMAINING_LENGTH_INVALID;
\r
1088 /* Valid remaining length should be at most 4 bytes. */
\r
1089 IotMqtt_Assert( bytesDecoded <= 4 );
\r
1094 EMPTY_ELSE_MARKER;
\r
1097 return remainingLength;
\r
1100 /*-----------------------------------------------------------*/
\r
1102 size_t _IotMqtt_GetRemainingLength_Generic( void * pNetworkConnection,
\r
1103 IotMqttGetNextByte_t getNextByte )
\r
1105 uint8_t encodedByte = 0;
\r
1106 size_t remainingLength = 0, multiplier = 1, bytesDecoded = 0, expectedSize = 0;
\r
1108 /* This algorithm is copied from the MQTT v3.1.1 spec. */
\r
1111 if( multiplier > 2097152 ) /* 128 ^ 3 */
\r
1113 remainingLength = MQTT_REMAINING_LENGTH_INVALID;
\r
1118 if( getNextByte( pNetworkConnection, &encodedByte ) == IOT_MQTT_SUCCESS )
\r
1120 remainingLength += ( encodedByte & 0x7F ) * multiplier;
\r
1121 multiplier *= 128;
\r
1126 remainingLength = MQTT_REMAINING_LENGTH_INVALID;
\r
1130 } while( ( encodedByte & 0x80 ) != 0 );
\r
1132 /* Check that the decoded remaining length conforms to the MQTT specification. */
\r
1133 if( remainingLength != MQTT_REMAINING_LENGTH_INVALID )
\r
1135 expectedSize = _remainingLengthEncodedSize( remainingLength );
\r
1137 if( bytesDecoded != expectedSize )
\r
1139 remainingLength = MQTT_REMAINING_LENGTH_INVALID;
\r
1143 /* Valid remaining length should be at most 4 bytes. */
\r
1144 IotMqtt_Assert( bytesDecoded <= 4 );
\r
1149 EMPTY_ELSE_MARKER;
\r
1152 return remainingLength;
\r
1155 /*-----------------------------------------------------------*/
\r
1157 IotMqttError_t _IotMqtt_SerializeConnect( const IotMqttConnectInfo_t * pConnectInfo,
\r
1158 uint8_t ** pConnectPacket,
\r
1159 size_t * pPacketSize )
\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
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
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
1173 IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER );
\r
1177 EMPTY_ELSE_MARKER;
\r
1180 /* Total size of the connect packet should be larger than the "Remaining length"
\r
1182 IotMqtt_Assert( connectPacketSize > remainingLength );
\r
1184 /* Allocate memory to hold the CONNECT packet. */
\r
1185 pBuffer = IotMqtt_MallocMessage( connectPacketSize );
\r
1187 /* Check that sufficient memory was allocated. */
\r
1188 if( pBuffer == NULL )
\r
1190 IotLogError( "Failed to allocate memory for CONNECT packet." );
\r
1192 IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_NO_MEMORY );
\r
1196 EMPTY_ELSE_MARKER;
\r
1199 /* Set the output parameters. The remainder of this function always succeeds. */
\r
1200 *pConnectPacket = pBuffer;
\r
1201 *pPacketSize = connectPacketSize;
\r
1203 _serializeConnect( pConnectInfo, remainingLength, pBuffer, connectPacketSize );
\r
1205 IOT_FUNCTION_EXIT_NO_CLEANUP();
\r
1208 /*-----------------------------------------------------------*/
\r
1210 IotMqttError_t _IotMqtt_DeserializeConnack( _mqttPacket_t * pConnack )
\r
1212 IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS );
\r
1213 const uint8_t * pRemainingData = pConnack->pRemainingData;
\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
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
1229 /* Check that the control packet type is 0x20. */
\r
1230 if( pConnack->type != MQTT_PACKET_TYPE_CONNACK )
\r
1232 IotLog( IOT_LOG_ERROR,
\r
1234 "Bad control packet type 0x%02x.",
\r
1237 IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );
\r
1241 EMPTY_ELSE_MARKER;
\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
1248 IotLog( IOT_LOG_ERROR,
\r
1250 "CONNACK does not have remaining length of %d.",
\r
1251 MQTT_PACKET_CONNACK_REMAINING_LENGTH );
\r
1253 IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );
\r
1257 EMPTY_ELSE_MARKER;
\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
1264 IotLog( IOT_LOG_ERROR,
\r
1266 "Reserved bits in CONNACK incorrect." );
\r
1268 IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );
\r
1272 EMPTY_ELSE_MARKER;
\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
1280 IotLog( IOT_LOG_DEBUG,
\r
1282 "CONNACK session present bit set." );
\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
1288 IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );
\r
1292 EMPTY_ELSE_MARKER;
\r
1297 IotLog( IOT_LOG_DEBUG,
\r
1299 "CONNACK session present bit not set." );
\r
1302 /* In MQTT 3.1.1, only values 0 through 5 are valid CONNACK response codes. */
\r
1303 if( pRemainingData[ 1 ] > 5 )
\r
1305 IotLog( IOT_LOG_DEBUG,
\r
1307 "CONNACK response %hhu is not valid.",
\r
1308 pRemainingData[ 1 ] );
\r
1310 IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );
\r
1314 EMPTY_ELSE_MARKER;
\r
1317 /* Print the appropriate message for the CONNACK response code if logs are
\r
1319 #if LIBRARY_LOG_LEVEL > IOT_LOG_NONE
\r
1320 IotLog( IOT_LOG_DEBUG,
\r
1323 pConnackResponses[ pRemainingData[ 1 ] ] );
\r
1326 /* A nonzero CONNACK response code means the connection was refused. */
\r
1327 if( pRemainingData[ 1 ] > 0 )
\r
1329 IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_SERVER_REFUSED );
\r
1333 EMPTY_ELSE_MARKER;
\r
1336 IOT_FUNCTION_EXIT_NO_CLEANUP();
\r
1339 /*-----------------------------------------------------------*/
\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
1347 IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS );
\r
1348 size_t remainingLength = 0, publishPacketSize = 0;
\r
1349 uint8_t * pBuffer = NULL;
\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
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
1359 IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER );
\r
1363 EMPTY_ELSE_MARKER;
\r
1366 /* Total size of the publish packet should be larger than the "Remaining length"
\r
1368 IotMqtt_Assert( publishPacketSize > remainingLength );
\r
1370 /* Allocate memory to hold the PUBLISH packet. */
\r
1371 pBuffer = IotMqtt_MallocMessage( publishPacketSize );
\r
1373 /* Check that sufficient memory was allocated. */
\r
1374 if( pBuffer == NULL )
\r
1376 IotLogError( "Failed to allocate memory for PUBLISH packet." );
\r
1378 IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_NO_MEMORY );
\r
1382 EMPTY_ELSE_MARKER;
\r
1385 /* Set the output parameters. The remainder of this function always succeeds. */
\r
1386 *pPublishPacket = pBuffer;
\r
1387 *pPacketSize = publishPacketSize;
\r
1389 /* Serialize publish into buffer pointed to by pBuffer */
\r
1390 _serializePublish( pPublishInfo,
\r
1392 pPacketIdentifier,
\r
1393 pPacketIdentifierHigh,
\r
1395 publishPacketSize );
\r
1397 IOT_FUNCTION_EXIT_NO_CLEANUP();
\r
1400 /*-----------------------------------------------------------*/
\r
1402 void _IotMqtt_PublishSetDup( uint8_t * pPublishPacket,
\r
1403 uint8_t * pPacketIdentifierHigh,
\r
1404 uint16_t * pNewPacketIdentifier )
\r
1406 uint16_t newPacketIdentifier = 0;
\r
1408 /* For an AWS IoT MQTT server, change the packet identifier. */
\r
1409 if( pPacketIdentifierHigh != NULL )
\r
1411 /* Output parameter for new packet identifier must be provided. */
\r
1412 IotMqtt_Assert( pNewPacketIdentifier != NULL );
\r
1414 /* Generate a new packet identifier. */
\r
1415 newPacketIdentifier = _nextPacketIdentifier();
\r
1417 IotLogDebug( "Changing PUBLISH packet identifier %hu to %hu.",
\r
1418 UINT16_DECODE( pPacketIdentifierHigh ),
\r
1419 newPacketIdentifier );
\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
1428 /* For a compliant MQTT 3.1.1 server, set the DUP flag. */
\r
1429 UINT8_SET_BIT( *pPublishPacket, MQTT_PUBLISH_FLAG_DUP );
\r
1431 IotLogDebug( "PUBLISH DUP flag set." );
\r
1435 /*-----------------------------------------------------------*/
\r
1437 IotMqttError_t _IotMqtt_DeserializePublish( _mqttPacket_t * pPublish )
\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
1444 /* The flags are the lower 4 bits of the first byte in PUBLISH. */
\r
1445 publishFlags = pPublish->type;
\r
1447 /* Parse the Retain bit. */
\r
1448 pOutput->retain = UINT8_CHECK_BIT( publishFlags, MQTT_PUBLISH_FLAG_RETAIN );
\r
1450 IotLog( IOT_LOG_DEBUG,
\r
1452 "Retain bit is %d.", pOutput->retain );
\r
1454 /* Check for QoS 2. */
\r
1455 if( UINT8_CHECK_BIT( publishFlags, MQTT_PUBLISH_FLAG_QOS2 ) == true )
\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
1460 IotLog( IOT_LOG_DEBUG,
\r
1464 IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );
\r
1468 EMPTY_ELSE_MARKER;
\r
1471 pOutput->qos = IOT_MQTT_QOS_2;
\r
1473 /* Check for QoS 1. */
\r
1474 else if( UINT8_CHECK_BIT( publishFlags, MQTT_PUBLISH_FLAG_QOS1 ) == true )
\r
1476 pOutput->qos = IOT_MQTT_QOS_1;
\r
1478 /* If the PUBLISH isn't QoS 1 or 2, then it's QoS 0. */
\r
1481 pOutput->qos = IOT_MQTT_QOS_0;
\r
1484 IotLog( IOT_LOG_DEBUG,
\r
1486 "QoS is %d.", pOutput->qos );
\r
1488 /* Parse the DUP bit. */
\r
1489 if( UINT8_CHECK_BIT( publishFlags, MQTT_PUBLISH_FLAG_DUP ) == true )
\r
1491 IotLog( IOT_LOG_DEBUG,
\r
1497 IotLog( IOT_LOG_DEBUG,
\r
1502 /* Sanity checks for "Remaining length". */
\r
1503 if( pOutput->qos == IOT_MQTT_QOS_0 )
\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
1509 IotLog( IOT_LOG_DEBUG,
\r
1511 "QoS 0 PUBLISH cannot have a remaining length less than 3." );
\r
1513 IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );
\r
1517 EMPTY_ELSE_MARKER;
\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
1525 if( pPublish->remainingLength < 5 )
\r
1527 IotLog( IOT_LOG_DEBUG,
\r
1529 "QoS 1 or 2 PUBLISH cannot have a remaining length less than 5." );
\r
1531 IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );
\r
1535 EMPTY_ELSE_MARKER;
\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
1543 /* Sanity checks for topic name length and "Remaining length". */
\r
1544 if( pOutput->qos == IOT_MQTT_QOS_0 )
\r
1546 /* Check that the "Remaining length" is at least as large as the variable
\r
1548 if( pPublish->remainingLength < pOutput->topicNameLength + sizeof( uint16_t ) )
\r
1550 IotLog( IOT_LOG_DEBUG,
\r
1552 "Remaining length cannot be less than variable header length." );
\r
1554 IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );
\r
1558 EMPTY_ELSE_MARKER;
\r
1563 /* Check that the "Remaining length" is at least as large as the variable
\r
1565 if( pPublish->remainingLength < pOutput->topicNameLength + 2 * sizeof( uint16_t ) )
\r
1567 IotLog( IOT_LOG_DEBUG,
\r
1569 "Remaining length cannot be less than variable header length." );
\r
1571 IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );
\r
1575 EMPTY_ELSE_MARKER;
\r
1579 /* Parse the topic. */
\r
1580 pOutput->pTopicName = ( const char * ) ( pVariableHeader + sizeof( uint16_t ) );
\r
1582 IotLog( IOT_LOG_DEBUG,
\r
1584 "Topic name length %hu: %.*s",
\r
1585 pOutput->topicNameLength,
\r
1586 pOutput->topicNameLength,
\r
1587 pOutput->pTopicName );
\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
1593 if( pOutput->qos > IOT_MQTT_QOS_0 )
\r
1595 pPublish->packetIdentifier = UINT16_DECODE( pPacketIdentifierHigh );
\r
1597 IotLog( IOT_LOG_DEBUG,
\r
1599 "Packet identifier %hu.", pPublish->packetIdentifier );
\r
1601 /* Packet identifier cannot be 0. */
\r
1602 if( pPublish->packetIdentifier == 0 )
\r
1604 IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );
\r
1608 EMPTY_ELSE_MARKER;
\r
1613 EMPTY_ELSE_MARKER;
\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
1620 pOutput->payloadLength = ( pPublish->remainingLength - pOutput->topicNameLength - sizeof( uint16_t ) );
\r
1621 pOutput->pPayload = pPacketIdentifierHigh;
\r
1625 pOutput->payloadLength = ( pPublish->remainingLength - pOutput->topicNameLength - 2 * sizeof( uint16_t ) );
\r
1626 pOutput->pPayload = pPacketIdentifierHigh + sizeof( uint16_t );
\r
1629 IotLog( IOT_LOG_DEBUG,
\r
1631 "Payload length %hu.", pOutput->payloadLength );
\r
1633 IOT_FUNCTION_EXIT_NO_CLEANUP();
\r
1636 /*-----------------------------------------------------------*/
\r
1638 IotMqttError_t _IotMqtt_SerializePuback( uint16_t packetIdentifier,
\r
1639 uint8_t ** pPubackPacket,
\r
1640 size_t * pPacketSize )
\r
1642 IotMqttError_t status = IOT_MQTT_SUCCESS;
\r
1644 /* Allocate memory for PUBACK. */
\r
1645 uint8_t * pBuffer = IotMqtt_MallocMessage( MQTT_PACKET_PUBACK_SIZE );
\r
1647 if( pBuffer == NULL )
\r
1649 IotLogError( "Failed to allocate memory for PUBACK packet" );
\r
1651 status = IOT_MQTT_NO_MEMORY;
\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
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
1665 /* Print out the serialized PUBACK packet for debugging purposes. */
\r
1666 IotLog_PrintBuffer( "MQTT PUBACK packet:", *pPubackPacket, MQTT_PACKET_PUBACK_SIZE );
\r
1672 /*-----------------------------------------------------------*/
\r
1674 IotMqttError_t _IotMqtt_DeserializePuback( _mqttPacket_t * pPuback )
\r
1676 IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS );
\r
1678 /* Check the "Remaining length" of the received PUBACK. */
\r
1679 if( pPuback->remainingLength != MQTT_PACKET_PUBACK_REMAINING_LENGTH )
\r
1681 IotLog( IOT_LOG_ERROR,
\r
1683 "PUBACK does not have remaining length of %d.",
\r
1684 MQTT_PACKET_PUBACK_REMAINING_LENGTH );
\r
1686 IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );
\r
1690 EMPTY_ELSE_MARKER;
\r
1693 /* Extract the packet identifier (third and fourth bytes) from PUBACK. */
\r
1694 pPuback->packetIdentifier = UINT16_DECODE( pPuback->pRemainingData );
\r
1696 IotLog( IOT_LOG_DEBUG,
\r
1698 "Packet identifier %hu.", pPuback->packetIdentifier );
\r
1700 /* Packet identifier cannot be 0. */
\r
1701 if( pPuback->packetIdentifier == 0 )
\r
1703 IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );
\r
1707 EMPTY_ELSE_MARKER;
\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
1714 IotLog( IOT_LOG_ERROR,
\r
1716 "Bad control packet type 0x%02x.",
\r
1719 IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );
\r
1723 EMPTY_ELSE_MARKER;
\r
1726 IOT_FUNCTION_EXIT_NO_CLEANUP();
\r
1729 /*-----------------------------------------------------------*/
\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
1737 IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS );
\r
1738 size_t subscribePacketSize = 0, remainingLength = 0;
\r
1739 uint8_t * pBuffer = NULL;
\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
1747 &subscribePacketSize ) == false )
\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
1753 IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER );
\r
1757 EMPTY_ELSE_MARKER;
\r
1760 /* Total size of the subscribe packet should be larger than the "Remaining length"
\r
1762 IotMqtt_Assert( subscribePacketSize > remainingLength );
\r
1764 /* Allocate memory to hold the SUBSCRIBE packet. */
\r
1765 pBuffer = IotMqtt_MallocMessage( subscribePacketSize );
\r
1767 /* Check that sufficient memory was allocated. */
\r
1768 if( pBuffer == NULL )
\r
1770 IotLogError( "Failed to allocate memory for SUBSCRIBE packet." );
\r
1772 IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_NO_MEMORY );
\r
1776 EMPTY_ELSE_MARKER;
\r
1779 /* Set the output parameters. The remainder of this function always succeeds. */
\r
1780 *pSubscribePacket = pBuffer;
\r
1781 *pPacketSize = subscribePacketSize;
\r
1783 /* Serialize subscribe into buffer pointed to by pBuffer */
\r
1784 _serializeSubscribe( pSubscriptionList,
\r
1785 subscriptionCount,
\r
1787 pPacketIdentifier,
\r
1789 subscribePacketSize );
\r
1792 IOT_FUNCTION_EXIT_NO_CLEANUP();
\r
1795 /*-----------------------------------------------------------*/
\r
1797 IotMqttError_t _IotMqtt_DeserializeSuback( _mqttPacket_t * pSuback )
\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
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
1808 IotLog( IOT_LOG_DEBUG,
\r
1810 "SUBACK cannot have a remaining length less than 3." );
\r
1812 IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );
\r
1816 EMPTY_ELSE_MARKER;
\r
1819 /* Extract the packet identifier (first 2 bytes of variable header) from SUBACK. */
\r
1820 pSuback->packetIdentifier = UINT16_DECODE( pVariableHeader );
\r
1822 IotLog( IOT_LOG_DEBUG,
\r
1824 "Packet identifier %hu.", pSuback->packetIdentifier );
\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
1830 IotLog( IOT_LOG_ERROR,
\r
1832 "Bad control packet type 0x%02x.",
\r
1835 IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );
\r
1839 EMPTY_ELSE_MARKER;
\r
1842 /* Iterate through each status byte in the SUBACK packet. */
\r
1843 for( i = 0; i < remainingLength - sizeof( uint16_t ); i++ )
\r
1845 /* Read a single status byte in SUBACK. */
\r
1846 subscriptionStatus = *( pVariableHeader + sizeof( uint16_t ) + i );
\r
1848 /* MQTT 3.1.1 defines the following values as status codes. */
\r
1849 switch( subscriptionStatus )
\r
1854 IotLog( IOT_LOG_DEBUG,
\r
1856 "Topic filter %lu accepted, max QoS %hhu.",
\r
1857 ( unsigned long ) i, subscriptionStatus );
\r
1861 IotLog( IOT_LOG_DEBUG,
\r
1863 "Topic filter %lu refused.", ( unsigned long ) i );
\r
1865 /* Remove a rejected subscription from the subscription manager. */
\r
1866 _IotMqtt_RemoveSubscriptionByPacket( pSuback->u.pMqttConnection,
\r
1867 pSuback->packetIdentifier,
\r
1870 status = IOT_MQTT_SERVER_REFUSED;
\r
1875 IotLog( IOT_LOG_DEBUG,
\r
1877 "Bad SUBSCRIBE status %hhu.", subscriptionStatus );
\r
1879 status = IOT_MQTT_BAD_RESPONSE;
\r
1884 /* Stop parsing the subscription statuses if a bad response was received. */
\r
1885 if( status == IOT_MQTT_BAD_RESPONSE )
\r
1891 EMPTY_ELSE_MARKER;
\r
1895 IOT_FUNCTION_EXIT_NO_CLEANUP();
\r
1898 /*-----------------------------------------------------------*/
\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
1906 IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS );
\r
1907 size_t unsubscribePacketSize = 0, remainingLength = 0;
\r
1908 uint8_t * pBuffer = NULL;
\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
1916 &unsubscribePacketSize ) == false )
\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
1922 IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER );
\r
1926 EMPTY_ELSE_MARKER;
\r
1929 /* Total size of the unsubscribe packet should be larger than the "Remaining length"
\r
1931 IotMqtt_Assert( unsubscribePacketSize > remainingLength );
\r
1933 /* Allocate memory to hold the UNSUBSCRIBE packet. */
\r
1934 pBuffer = IotMqtt_MallocMessage( unsubscribePacketSize );
\r
1936 /* Check that sufficient memory was allocated. */
\r
1937 if( pBuffer == NULL )
\r
1939 IotLogError( "Failed to allocate memory for UNSUBSCRIBE packet." );
\r
1941 IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_NO_MEMORY );
\r
1945 EMPTY_ELSE_MARKER;
\r
1948 /* Set the output parameters. The remainder of this function always succeeds. */
\r
1949 *pUnsubscribePacket = pBuffer;
\r
1950 *pPacketSize = unsubscribePacketSize;
\r
1952 /* Serialize unsubscribe into buffer pointed to by pBuffer */
\r
1953 _serializeUnsubscribe( pSubscriptionList,
\r
1954 subscriptionCount,
\r
1956 pPacketIdentifier,
\r
1958 unsubscribePacketSize );
\r
1960 IOT_FUNCTION_EXIT_NO_CLEANUP();
\r
1963 /*-----------------------------------------------------------*/
\r
1965 IotMqttError_t _IotMqtt_DeserializeUnsuback( _mqttPacket_t * pUnsuback )
\r
1967 IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS );
\r
1969 /* Check the "Remaining length" (second byte) of the received UNSUBACK. */
\r
1970 if( pUnsuback->remainingLength != MQTT_PACKET_UNSUBACK_REMAINING_LENGTH )
\r
1972 IotLog( IOT_LOG_ERROR,
\r
1974 "UNSUBACK does not have remaining length of %d.",
\r
1975 MQTT_PACKET_UNSUBACK_REMAINING_LENGTH );
\r
1977 IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );
\r
1981 EMPTY_ELSE_MARKER;
\r
1984 /* Extract the packet identifier (third and fourth bytes) from UNSUBACK. */
\r
1985 pUnsuback->packetIdentifier = UINT16_DECODE( pUnsuback->pRemainingData );
\r
1987 /* Packet identifier cannot be 0. */
\r
1988 if( pUnsuback->packetIdentifier == 0 )
\r
1990 IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );
\r
1994 EMPTY_ELSE_MARKER;
\r
1997 IotLog( IOT_LOG_DEBUG,
\r
1999 "Packet identifier %hu.", pUnsuback->packetIdentifier );
\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
2005 IotLog( IOT_LOG_ERROR,
\r
2007 "Bad control packet type 0x%02x.",
\r
2008 pUnsuback->type );
\r
2010 IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );
\r
2014 EMPTY_ELSE_MARKER;
\r
2017 IOT_FUNCTION_EXIT_NO_CLEANUP();
\r
2020 /*-----------------------------------------------------------*/
\r
2022 IotMqttError_t _IotMqtt_SerializePingreq( uint8_t ** pPingreqPacket,
\r
2023 size_t * pPacketSize )
\r
2025 /* PINGREQ packets are always the same. */
\r
2026 static const uint8_t pPingreq[ MQTT_PACKET_PINGREQ_SIZE ] =
\r
2028 MQTT_PACKET_TYPE_PINGREQ,
\r
2032 /* Set the output parameters. */
\r
2033 *pPingreqPacket = ( uint8_t * ) pPingreq;
\r
2034 *pPacketSize = MQTT_PACKET_PINGREQ_SIZE;
\r
2036 /* Print out the PINGREQ packet for debugging purposes. */
\r
2037 IotLog_PrintBuffer( "MQTT PINGREQ packet:", pPingreq, MQTT_PACKET_PINGREQ_SIZE );
\r
2039 return IOT_MQTT_SUCCESS;
\r
2042 /*-----------------------------------------------------------*/
\r
2044 IotMqttError_t _IotMqtt_DeserializePingresp( _mqttPacket_t * pPingresp )
\r
2046 IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS );
\r
2048 /* Check that the control packet type is 0xd0. */
\r
2049 if( pPingresp->type != MQTT_PACKET_TYPE_PINGRESP )
\r
2051 IotLog( IOT_LOG_ERROR,
\r
2053 "Bad control packet type 0x%02x.",
\r
2054 pPingresp->type );
\r
2056 IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );
\r
2060 EMPTY_ELSE_MARKER;
\r
2063 /* Check the "Remaining length" (second byte) of the received PINGRESP. */
\r
2064 if( pPingresp->remainingLength != MQTT_PACKET_PINGRESP_REMAINING_LENGTH )
\r
2066 IotLog( IOT_LOG_ERROR,
\r
2068 "PINGRESP does not have remaining length of %d.",
\r
2069 MQTT_PACKET_PINGRESP_REMAINING_LENGTH );
\r
2071 IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );
\r
2075 EMPTY_ELSE_MARKER;
\r
2078 IOT_FUNCTION_EXIT_NO_CLEANUP();
\r
2081 /*-----------------------------------------------------------*/
\r
2083 IotMqttError_t _IotMqtt_SerializeDisconnect( uint8_t ** pDisconnectPacket,
\r
2084 size_t * pPacketSize )
\r
2086 /* DISCONNECT packets are always the same. */
\r
2087 static const uint8_t pDisconnect[ MQTT_PACKET_DISCONNECT_SIZE ] =
\r
2089 MQTT_PACKET_TYPE_DISCONNECT,
\r
2093 /* Set the output parameters. */
\r
2094 *pDisconnectPacket = ( uint8_t * ) pDisconnect;
\r
2095 *pPacketSize = MQTT_PACKET_DISCONNECT_SIZE;
\r
2097 /* Print out the DISCONNECT packet for debugging purposes. */
\r
2098 IotLog_PrintBuffer( "MQTT DISCONNECT packet:", pDisconnect, MQTT_PACKET_DISCONNECT_SIZE );
\r
2100 return IOT_MQTT_SUCCESS;
\r
2103 /*-----------------------------------------------------------*/
\r
2105 void _IotMqtt_FreePacket( uint8_t * pPacket )
\r
2107 uint8_t packetType = *pPacket;
\r
2109 /* Don't call free on DISCONNECT and PINGREQ; those are allocated from static
\r
2111 if( packetType != MQTT_PACKET_TYPE_DISCONNECT )
\r
2113 if( packetType != MQTT_PACKET_TYPE_PINGREQ )
\r
2115 IotMqtt_FreeMessage( pPacket );
\r
2119 EMPTY_ELSE_MARKER;
\r
2124 EMPTY_ELSE_MARKER;
\r
2128 /*-----------------------------------------------------------*/
\r
2130 /* Public interface functions for serialization */
\r
2132 /*-----------------------------------------------------------*/
\r
2134 IotMqttError_t IotMqtt_GetConnectPacketSize( const IotMqttConnectInfo_t * pConnectInfo,
\r
2135 size_t * pRemainingLength,
\r
2136 size_t * pPacketSize )
\r
2138 IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS );
\r
2140 if( ( pConnectInfo == NULL ) || ( pRemainingLength == NULL ) || ( pPacketSize == NULL ) )
\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
2146 if( ( pConnectInfo->clientIdentifierLength == 0 ) || ( pConnectInfo->pClientIdentifier == NULL ) )
\r
2148 IotLogError( "IotMqtt_GetConnectPacketSize() client identifier must be set." );
\r
2149 IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER );
\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
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
2160 IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER );
\r
2164 EMPTY_ELSE_MARKER;
\r
2167 /* Total size of the subscribe packet should be larger than the "Remaining length"
\r
2169 if( ( *pPacketSize ) < ( *pRemainingLength ) )
\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
2176 IOT_FUNCTION_EXIT_NO_CLEANUP();
\r
2179 /*-----------------------------------------------------------*/
\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
2186 IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS );
\r
2188 if( ( pBuffer == NULL ) || ( pConnectInfo == NULL ) )
\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
2194 if( ( pConnectInfo->clientIdentifierLength == 0 ) || ( pConnectInfo->pClientIdentifier == NULL ) )
\r
2196 IotLogError( "IotMqtt_SerializeConnect() client identifier must be set." );
\r
2197 IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER );
\r
2200 if( remainingLength > bufferSize )
\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
2207 _serializeConnect( pConnectInfo,
\r
2212 IOT_FUNCTION_EXIT_NO_CLEANUP();
\r
2215 /*-----------------------------------------------------------*/
\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
2223 IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS );
\r
2225 if( ( pSubscriptionList == NULL ) || ( pRemainingLength == NULL ) || ( pPacketSize == NULL ) )
\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
2231 if( ( type != IOT_MQTT_SUBSCRIBE ) && ( type != IOT_MQTT_UNSUBSCRIBE ) )
\r
2233 IotLogError( "IotMqtt_GetSubscriptionPacketSize() called with unknown type." );
\r
2234 IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER );
\r
2237 if( subscriptionCount == 0 )
\r
2239 IotLogError( "IotMqtt_GetSubscriptionPacketSize() called with zero subscription count." );
\r
2240 IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER );
\r
2243 if( _subscriptionPacketSize( type,
\r
2244 pSubscriptionList,
\r
2245 subscriptionCount,
\r
2247 pPacketSize ) == false )
\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
2256 EMPTY_ELSE_MARKER;
\r
2259 /* Total size of the subscribe packet should be larger than the "Remaining length"
\r
2261 if( ( *pPacketSize ) < ( *pRemainingLength ) )
\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
2268 IOT_FUNCTION_EXIT_NO_CLEANUP();
\r
2271 /*-----------------------------------------------------------*/
\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
2280 IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS );
\r
2282 if( ( pBuffer == NULL ) || ( pSubscriptionList == NULL ) || ( pPacketIdentifier == NULL ) )
\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
2288 if( subscriptionCount == 0 )
\r
2290 IotLogError( "IotMqtt_SerializeSubscribe() called with zero subscription count." );
\r
2291 IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER );
\r
2294 if( remainingLength > bufferSize )
\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
2301 _serializeSubscribe( pSubscriptionList,
\r
2302 subscriptionCount,
\r
2304 pPacketIdentifier,
\r
2308 IOT_FUNCTION_EXIT_NO_CLEANUP();
\r
2311 /*-----------------------------------------------------------*/
\r
2313 IotMqttError_t IotMqtt_GetPublishPacketSize( IotMqttPublishInfo_t * pPublishInfo,
\r
2314 size_t * pRemainingLength,
\r
2315 size_t * pPacketSize )
\r
2317 IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS );
\r
2319 if( ( pPublishInfo == NULL ) || ( pRemainingLength == NULL ) || ( pPacketSize == NULL ) )
\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
2325 if( ( pPublishInfo->pTopicName == NULL ) || ( pPublishInfo->topicNameLength == 0 ) )
\r
2327 IotLogError( "IotMqtt_GetPublishPacketSize() called with no topic." );
\r
2328 IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER );
\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
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
2339 IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER );
\r
2343 EMPTY_ELSE_MARKER;
\r
2346 /* Total size of the publish packet should be larger than the "Remaining length"
\r
2348 if( ( *pPacketSize ) < ( *pRemainingLength ) )
\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
2355 IOT_FUNCTION_EXIT_NO_CLEANUP();
\r
2358 /*-----------------------------------------------------------*/
\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
2368 IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS );
\r
2370 if( ( pBuffer == NULL ) || ( pPublishInfo == NULL ) || ( pPacketIdentifier == NULL ) )
\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
2376 if( ( pPublishInfo->pTopicName == NULL ) || ( pPublishInfo->topicNameLength == 0 ) )
\r
2378 IotLogError( "IotMqtt_SerializePublish() called with no topic." );
\r
2379 IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER );
\r
2382 if( remainingLength > bufferSize )
\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
2389 _serializePublish( pPublishInfo,
\r
2391 pPacketIdentifier,
\r
2392 pPacketIdentifierHigh,
\r
2395 IOT_FUNCTION_EXIT_NO_CLEANUP();
\r
2398 /*-----------------------------------------------------------*/
\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
2407 IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS );
\r
2409 if( ( pBuffer == NULL ) || ( pPacketIdentifier == NULL ) || ( pSubscriptionList == NULL ) )
\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
2415 if( subscriptionCount == 0 )
\r
2417 IotLogError( "IotMqtt_SerializeUnsubscribe() called with zero subscription count." );
\r
2418 IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER );
\r
2421 if( remainingLength > bufferSize )
\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
2428 _serializeUnsubscribe( pSubscriptionList,
\r
2429 subscriptionCount,
\r
2431 pPacketIdentifier,
\r
2434 IOT_FUNCTION_EXIT_NO_CLEANUP();
\r
2437 /*-----------------------------------------------------------*/
\r
2439 IotMqttError_t IotMqtt_SerializeDisconnect( uint8_t * pBuffer,
\r
2440 size_t bufferSize )
\r
2442 IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS );
\r
2443 uint8_t * pDisconnectPacket = NULL;
\r
2444 size_t remainingLength = 0;
\r
2446 if( pBuffer == NULL )
\r
2448 IotLogError( "IotMqtt_SerializeDisconnect() called with NULL buffer pointer." );
\r
2449 IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER );
\r
2452 if( bufferSize < MQTT_PACKET_DISCONNECT_SIZE )
\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
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
2464 memcpy( pBuffer, pDisconnectPacket, MQTT_PACKET_DISCONNECT_SIZE );
\r
2465 IOT_FUNCTION_EXIT_NO_CLEANUP();
\r
2468 /*-----------------------------------------------------------*/
\r
2470 IotMqttError_t IotMqtt_SerializePingreq( uint8_t * pBuffer,
\r
2471 size_t bufferSize )
\r
2473 IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS );
\r
2474 uint8_t * pPingreqPacket = NULL;
\r
2475 size_t packetSize = 0;
\r
2477 if( pBuffer == NULL )
\r
2479 IotLogError( "IotMqtt_SerializePingreq() called with NULL buffer pointer." );
\r
2480 IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER );
\r
2483 if( bufferSize < MQTT_PACKET_PINGREQ_SIZE )
\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
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
2498 /*-----------------------------------------------------------*/
\r
2500 IotMqttError_t IotMqtt_DeserializePublish( IotMqttPacketInfo_t * pMqttPacket )
\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
2508 if( pMqttPacket == NULL )
\r
2510 IotLogError( "IotMqtt_DeserializePublish()called with NULL pMqttPacket pointer." );
\r
2511 IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER );
\r
2514 if( ( pMqttPacket->type & 0xf0 ) != MQTT_PACKET_TYPE_PUBLISH )
\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
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
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
2532 if( status == IOT_MQTT_SUCCESS )
\r
2534 pMqttPacket->pubInfo = mqttOperation.u.publish.publishInfo;
\r
2535 pMqttPacket->packetIdentifier = mqttPacket.packetIdentifier;
\r
2538 IOT_FUNCTION_EXIT_NO_CLEANUP();
\r
2541 /*-----------------------------------------------------------*/
\r
2543 IotMqttError_t IotMqtt_DeserializeResponse( IotMqttPacketInfo_t * pMqttPacket )
\r
2545 IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS );
\r
2546 /* Internal MQTT packet structure */
\r
2547 _mqttPacket_t mqttPacket;
\r
2549 if( ( pMqttPacket == NULL ) || ( pMqttPacket->pRemainingData == NULL ) )
\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
2555 /* Set internal mqtt packet parameters. */
\r
2556 memset( ( void * ) &mqttPacket, 0x00, sizeof( _mqttPacket_t ) );
\r
2558 mqttPacket.pRemainingData = pMqttPacket->pRemainingData;
\r
2559 mqttPacket.remainingLength = pMqttPacket->remainingLength;
\r
2560 mqttPacket.type = pMqttPacket->type;
\r
2562 /* Call internal deserialize */
\r
2563 switch( pMqttPacket->type & 0xf0 )
\r
2565 case MQTT_PACKET_TYPE_CONNACK:
\r
2566 status = _IotMqtt_DeserializeConnack( &mqttPacket );
\r
2569 case MQTT_PACKET_TYPE_PUBACK:
\r
2570 status = _IotMqtt_DeserializePuback( &mqttPacket );
\r
2573 case MQTT_PACKET_TYPE_SUBACK:
\r
2574 status = _IotMqtt_DeserializeSuback( &mqttPacket );
\r
2577 case MQTT_PACKET_TYPE_UNSUBACK:
\r
2578 status = _IotMqtt_DeserializeUnsuback( &mqttPacket );
\r
2581 case MQTT_PACKET_TYPE_PINGRESP:
\r
2582 status = _IotMqtt_DeserializePingresp( &mqttPacket );
\r
2585 /* Any other packet type is invalid. */
\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
2591 if( status != IOT_MQTT_SUCCESS )
\r
2593 IOT_SET_AND_GOTO_CLEANUP( status );
\r
2597 /* Set packetIdentifier only if success is returned. */
\r
2598 pMqttPacket->packetIdentifier = mqttPacket.packetIdentifier;
\r
2601 IOT_FUNCTION_EXIT_NO_CLEANUP();
\r
2604 /*-----------------------------------------------------------*/
\r