-/*\r
- * Amazon FreeRTOS MQTT V2.0.0\r
- * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.\r
- *\r
- * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
- * this software and associated documentation files (the "Software"), to deal in\r
- * the Software without restriction, including without limitation the rights to\r
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
- * the Software, and to permit persons to whom the Software is furnished to do so,\r
- * subject to the following conditions:\r
- *\r
- * The above copyright notice and this permission notice shall be included in all\r
- * copies or substantial portions of the Software.\r
- *\r
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
- *\r
- * http://aws.amazon.com/freertos\r
- * http://www.FreeRTOS.org\r
- */\r
-\r
-/**\r
- * @file iot_mqtt_serialize.c\r
- * @brief Implements functions that generate and decode MQTT network packets.\r
- */\r
-\r
-/* The config header is always included first. */\r
-#include "iot_config.h"\r
-\r
-/* Standard includes. */\r
-#include <string.h>\r
-\r
-/* Error handling include. */\r
-#include "private/iot_error.h"\r
-\r
-/* MQTT internal includes. */\r
-#include "private/iot_mqtt_internal.h"\r
-\r
-/* Platform layer includes. */\r
-#include "platform/iot_threads.h"\r
-\r
-/* Atomic operations. */\r
-#include "iot_atomic.h"\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-/*\r
- * Macros for reading the high and low byte of a 2-byte unsigned int.\r
- */\r
-#define UINT16_HIGH_BYTE( x ) ( ( uint8_t ) ( x >> 8 ) ) /**< @brief Get high byte. */\r
-#define UINT16_LOW_BYTE( x ) ( ( uint8_t ) ( x & 0x00ff ) ) /**< @brief Get low byte. */\r
-\r
-/**\r
- * @brief Macro for decoding a 2-byte unsigned int from a sequence of bytes.\r
- *\r
- * @param[in] ptr A uint8_t* that points to the high byte.\r
- */\r
-#define UINT16_DECODE( ptr ) \\r
- ( uint16_t ) ( ( ( ( uint16_t ) ( *( ptr ) ) ) << 8 ) | \\r
- ( ( uint16_t ) ( *( ptr + 1 ) ) ) )\r
-\r
-/**\r
- * @brief Macro for setting a bit in a 1-byte unsigned int.\r
- *\r
- * @param[in] x The unsigned int to set.\r
- * @param[in] position Which bit to set.\r
- */\r
-#define UINT8_SET_BIT( x, position ) ( x = ( uint8_t ) ( x | ( 0x01 << position ) ) )\r
-\r
-/**\r
- * @brief Macro for checking if a bit is set in a 1-byte unsigned int.\r
- *\r
- * @param[in] x The unsigned int to check.\r
- * @param[in] position Which bit to check.\r
- */\r
-#define UINT8_CHECK_BIT( x, position ) ( ( x & ( 0x01 << position ) ) == ( 0x01 << position ) )\r
-\r
-/*\r
- * Positions of each flag in the "Connect Flag" field of an MQTT CONNECT\r
- * packet.\r
- */\r
-#define MQTT_CONNECT_FLAG_CLEAN ( 1 ) /**< @brief Clean session. */\r
-#define MQTT_CONNECT_FLAG_WILL ( 2 ) /**< @brief Will present. */\r
-#define MQTT_CONNECT_FLAG_WILL_QOS1 ( 3 ) /**< @brief Will QoS1. */\r
-#define MQTT_CONNECT_FLAG_WILL_QOS2 ( 4 ) /**< @brief Will QoS2. */\r
-#define MQTT_CONNECT_FLAG_WILL_RETAIN ( 5 ) /**< @brief Will retain. */\r
-#define MQTT_CONNECT_FLAG_PASSWORD ( 6 ) /**< @brief Password present. */\r
-#define MQTT_CONNECT_FLAG_USERNAME ( 7 ) /**< @brief Username present. */\r
-\r
-/*\r
- * Positions of each flag in the first byte of an MQTT PUBLISH packet's\r
- * fixed header.\r
- */\r
-#define MQTT_PUBLISH_FLAG_RETAIN ( 0 ) /**< @brief Message retain flag. */\r
-#define MQTT_PUBLISH_FLAG_QOS1 ( 1 ) /**< @brief Publish QoS 1. */\r
-#define MQTT_PUBLISH_FLAG_QOS2 ( 2 ) /**< @brief Publish QoS 2. */\r
-#define MQTT_PUBLISH_FLAG_DUP ( 3 ) /**< @brief Duplicate message. */\r
-\r
-/**\r
- * @brief The constant specifying MQTT version 3.1.1. Placed in the CONNECT packet.\r
- */\r
-#define MQTT_VERSION_3_1_1 ( ( uint8_t ) 4U )\r
-\r
-/**\r
- * @brief Per the MQTT 3.1.1 spec, the largest "Remaining Length" of an MQTT\r
- * packet is this value.\r
- */\r
-#define MQTT_MAX_REMAINING_LENGTH ( 268435455UL )\r
-\r
-/**\r
- * @brief The maximum possible size of a CONNECT packet.\r
- *\r
- * All strings in a CONNECT packet are constrained to 2-byte lengths, giving a\r
- * maximum length smaller than the max "Remaining Length" constant above.\r
- */\r
-#define MQTT_PACKET_CONNECT_MAX_SIZE ( 327700UL )\r
-\r
-/*\r
- * Constants relating to CONNACK packets, defined by MQTT 3.1.1 spec.\r
- */\r
-#define MQTT_PACKET_CONNACK_REMAINING_LENGTH ( ( uint8_t ) 2 ) /**< @brief A CONNACK packet always has a "Remaining length" of 2. */\r
-#define MQTT_PACKET_CONNACK_SESSION_PRESENT_MASK ( ( uint8_t ) 0x01 ) /**< @brief The "Session Present" bit is always the lowest bit. */\r
-\r
-/*\r
- * Constants relating to PUBLISH and PUBACK packets, defined by MQTT\r
- * 3.1.1 spec.\r
- */\r
-#define MQTT_PACKET_PUBACK_SIZE ( 4 ) /**< @brief A PUBACK packet is always 4 bytes in size. */\r
-#define MQTT_PACKET_PUBACK_REMAINING_LENGTH ( ( uint8_t ) 2 ) /**< @brief A PUBACK packet always has a "Remaining length" of 2. */\r
-\r
-/*\r
- * Constants relating to SUBACK and UNSUBACK packets, defined by MQTT\r
- * 3.1.1 spec.\r
- */\r
-#define MQTT_PACKET_SUBACK_MINIMUM_SIZE ( 5 ) /**< @brief The size of the smallest valid SUBACK packet. */\r
-#define MQTT_PACKET_UNSUBACK_REMAINING_LENGTH ( ( uint8_t ) 2 ) /**< @brief An UNSUBACK packet always has a "Remaining length" of 2. */\r
-\r
-/*\r
- * Constants relating to PINGREQ and PINGRESP packets, defined by MQTT 3.1.1 spec.\r
- */\r
-#define MQTT_PACKET_PINGREQ_SIZE ( 2 ) /**< @brief A PINGREQ packet is always 2 bytes in size. */\r
-#define MQTT_PACKET_PINGRESP_REMAINING_LENGTH ( 0 ) /**< @brief A PINGRESP packet always has a "Remaining length" of 0. */\r
-\r
-/*\r
- * Constants relating to DISCONNECT packets, defined by MQTT 3.1.1 spec.\r
- */\r
-#define MQTT_PACKET_DISCONNECT_SIZE ( 2 ) /**< @brief A DISCONNECT packet is always 2 bytes in size. */\r
-\r
-/* Username for metrics with AWS IoT. */\r
-#if AWS_IOT_MQTT_ENABLE_METRICS == 1 || DOXYGEN == 1\r
- #ifndef AWS_IOT_METRICS_USERNAME\r
-\r
-/**\r
- * @brief Specify C SDK and version.\r
- */\r
- #define AWS_IOT_METRICS_USERNAME "?SDK=C&Version=4.0.0"\r
-\r
-/**\r
- * @brief The length of #AWS_IOT_METRICS_USERNAME.\r
- */\r
- #define AWS_IOT_METRICS_USERNAME_LENGTH ( ( uint16_t ) sizeof( AWS_IOT_METRICS_USERNAME ) - 1 )\r
- #endif /* ifndef AWS_IOT_METRICS_USERNAME */\r
-#endif /* if AWS_IOT_MQTT_ENABLE_METRICS == 1 || DOXYGEN == 1 */\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-/**\r
- * @brief Generate and return a 2-byte packet identifier.\r
- *\r
- * This packet identifier will be nonzero.\r
- *\r
- * @return The packet identifier.\r
- */\r
-static uint16_t _nextPacketIdentifier( void );\r
-\r
-/**\r
- * @brief Calculate the number of bytes required to encode an MQTT\r
- * "Remaining length" field.\r
- *\r
- * @param[in] length The value of the "Remaining length" to encode.\r
- *\r
- * @return The size of the encoding of length. This is always `1`, `2`, `3`, or `4`.\r
- */\r
-static size_t _remainingLengthEncodedSize( size_t length );\r
-\r
-/**\r
- * @brief Encode the "Remaining length" field per MQTT spec.\r
- *\r
- * @param[out] pDestination Where to write the encoded "Remaining length".\r
- * @param[in] length The "Remaining length" to encode.\r
- *\r
- * @return Pointer to the end of the encoded "Remaining length", which is 1-4\r
- * bytes greater than `pDestination`.\r
- *\r
- * @warning This function does not check the size of `pDestination`! Ensure that\r
- * `pDestination` is large enough to hold the encoded "Remaining length" using\r
- * the function #_remainingLengthEncodedSize to avoid buffer overflows.\r
- */\r
-static uint8_t * _encodeRemainingLength( uint8_t * pDestination,\r
- size_t length );\r
-\r
-/**\r
- * @brief Encode a C string as a UTF-8 string, per MQTT 3.1.1 spec.\r
- *\r
- * @param[out] pDestination Where to write the encoded string.\r
- * @param[in] source The string to encode.\r
- * @param[in] sourceLength The length of source.\r
- *\r
- * @return Pointer to the end of the encoded string, which is `sourceLength+2`\r
- * bytes greater than `pDestination`.\r
- *\r
- * @warning This function does not check the size of `pDestination`! Ensure that\r
- * `pDestination` is large enough to hold `sourceLength+2` bytes to avoid a buffer\r
- * overflow.\r
- */\r
-static uint8_t * _encodeString( uint8_t * pDestination,\r
- const char * source,\r
- uint16_t sourceLength );\r
-\r
-/**\r
- * @brief Calculate the size and "Remaining length" of a CONNECT packet generated\r
- * from the given parameters.\r
- *\r
- * @param[in] pConnectInfo User-provided CONNECT information struct.\r
- * @param[out] pRemainingLength Output for calculated "Remaining length" field.\r
- * @param[out] pPacketSize Output for calculated total packet size.\r
- *\r
- * @return `true` if the packet is within the length allowed by MQTT 3.1.1 spec; `false`\r
- * otherwise. If this function returns `false`, the output parameters should be ignored.\r
- */\r
-static bool _connectPacketSize( const IotMqttConnectInfo_t * pConnectInfo,\r
- size_t * pRemainingLength,\r
- size_t * pPacketSize );\r
-\r
-/**\r
- * @brief Calculate the size and "Remaining length" of a PUBLISH packet generated\r
- * from the given parameters.\r
- *\r
- * @param[in] pPublishInfo User-provided PUBLISH information struct.\r
- * @param[out] pRemainingLength Output for calculated "Remaining length" field.\r
- * @param[out] pPacketSize Output for calculated total packet size.\r
- *\r
- * @return `true` if the packet is within the length allowed by MQTT 3.1.1 spec; `false`\r
- * otherwise. If this function returns `false`, the output parameters should be ignored.\r
- */\r
-static bool _publishPacketSize( const IotMqttPublishInfo_t * pPublishInfo,\r
- size_t * pRemainingLength,\r
- size_t * pPacketSize );\r
-\r
-/**\r
- * @brief Calculate the size and "Remaining length" of a SUBSCRIBE or UNSUBSCRIBE\r
- * packet generated from the given parameters.\r
- *\r
- * @param[in] type Either IOT_MQTT_SUBSCRIBE or IOT_MQTT_UNSUBSCRIBE.\r
- * @param[in] pSubscriptionList User-provided array of subscriptions.\r
- * @param[in] subscriptionCount Size of `pSubscriptionList`.\r
- * @param[out] pRemainingLength Output for calculated "Remaining length" field.\r
- * @param[out] pPacketSize Output for calculated total packet size.\r
- *\r
- * @return `true` if the packet is within the length allowed by MQTT 3.1.1 spec; `false`\r
- * otherwise. If this function returns `false`, the output parameters should be ignored.\r
- */\r
-static bool _subscriptionPacketSize( IotMqttOperationType_t type,\r
- const IotMqttSubscription_t * pSubscriptionList,\r
- size_t subscriptionCount,\r
- size_t * pRemainingLength,\r
- size_t * pPacketSize );\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-#if LIBRARY_LOG_LEVEL > IOT_LOG_NONE\r
-\r
-/**\r
- * @brief If logging is enabled, define a log configuration that only prints the log\r
- * string. This is used when printing out details of deserialized MQTT packets.\r
- */\r
- static const IotLogConfig_t _logHideAll =\r
- {\r
- .hideLibraryName = true,\r
- .hideLogLevel = true,\r
- .hideTimestring = true\r
- };\r
-#endif\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-static uint16_t _nextPacketIdentifier( void )\r
-{\r
- /* MQTT specifies 2 bytes for the packet identifier; however, operating on\r
- * 32-bit integers is generally faster. */\r
- static uint32_t nextPacketIdentifier = 1;\r
-\r
- /* The next packet identifier will be greater by 2. This prevents packet\r
- * identifiers from ever being 0, which is not allowed by MQTT 3.1.1. Packet\r
- * identifiers will follow the sequence 1,3,5...65535,1,3,5... */\r
- return ( uint16_t ) Atomic_Add_u32( &nextPacketIdentifier, 2 );\r
-}\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-static size_t _remainingLengthEncodedSize( size_t length )\r
-{\r
- size_t encodedSize = 0;\r
-\r
- /* length should have already been checked before calling this function. */\r
- IotMqtt_Assert( length <= MQTT_MAX_REMAINING_LENGTH );\r
-\r
- /* Determine how many bytes are needed to encode length.\r
- * The values below are taken from the MQTT 3.1.1 spec. */\r
-\r
- /* 1 byte is needed to encode lengths between 0 and 127. */\r
- if( length < 128 )\r
- {\r
- encodedSize = 1;\r
- }\r
- /* 2 bytes are needed to encode lengths between 128 and 16,383. */\r
- else if( length < 16384 )\r
- {\r
- encodedSize = 2;\r
- }\r
- /* 3 bytes are needed to encode lengths between 16,384 and 2,097,151. */\r
- else if( length < 2097152 )\r
- {\r
- encodedSize = 3;\r
- }\r
- /* 4 bytes are needed to encode lengths between 2,097,152 and 268,435,455. */\r
- else\r
- {\r
- encodedSize = 4;\r
- }\r
-\r
- return encodedSize;\r
-}\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-static uint8_t * _encodeRemainingLength( uint8_t * pDestination,\r
- size_t length )\r
-{\r
- uint8_t lengthByte = 0, * pLengthEnd = pDestination;\r
-\r
- /* This algorithm is copied from the MQTT v3.1.1 spec. */\r
- do\r
- {\r
- lengthByte = length % 128;\r
- length = length / 128;\r
-\r
- /* Set the high bit of this byte, indicating that there's more data. */\r
- if( length > 0 )\r
- {\r
- UINT8_SET_BIT( lengthByte, 7 );\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
-\r
- /* Output a single encoded byte. */\r
- *pLengthEnd = lengthByte;\r
- pLengthEnd++;\r
- } while( length > 0 );\r
-\r
- return pLengthEnd;\r
-}\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-static uint8_t * _encodeString( uint8_t * pDestination,\r
- const char * source,\r
- uint16_t sourceLength )\r
-{\r
- /* The first byte of a UTF-8 string is the high byte of the string length. */\r
- *pDestination = UINT16_HIGH_BYTE( sourceLength );\r
- pDestination++;\r
-\r
- /* The second byte of a UTF-8 string is the low byte of the string length. */\r
- *pDestination = UINT16_LOW_BYTE( sourceLength );\r
- pDestination++;\r
-\r
- /* Copy the string into pDestination. */\r
- ( void ) memcpy( pDestination, source, sourceLength );\r
-\r
- /* Return the pointer to the end of the encoded string. */\r
- pDestination += sourceLength;\r
-\r
- return pDestination;\r
-}\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-static bool _connectPacketSize( const IotMqttConnectInfo_t * pConnectInfo,\r
- size_t * pRemainingLength,\r
- size_t * pPacketSize )\r
-{\r
- bool status = true;\r
- size_t connectPacketSize = 0, remainingLength = 0;\r
-\r
- /* The CONNECT packet will always include a 10-byte variable header. */\r
- connectPacketSize += 10U;\r
-\r
- /* Add the length of the client identifier if provided. */\r
- if( pConnectInfo->clientIdentifierLength > 0 )\r
- {\r
- connectPacketSize += pConnectInfo->clientIdentifierLength + sizeof( uint16_t );\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
-\r
- /* Add the lengths of the will message and topic name if provided. */\r
- if( pConnectInfo->pWillInfo != NULL )\r
- {\r
- connectPacketSize += pConnectInfo->pWillInfo->topicNameLength + sizeof( uint16_t ) +\r
- pConnectInfo->pWillInfo->payloadLength + sizeof( uint16_t );\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
-\r
- /* Depending on the status of metrics, add the length of the metrics username\r
- * or the user-provided username. */\r
- if( pConnectInfo->awsIotMqttMode == true )\r
- {\r
- #if AWS_IOT_MQTT_ENABLE_METRICS == 1\r
- connectPacketSize += AWS_IOT_METRICS_USERNAME_LENGTH + sizeof( uint16_t );\r
- #endif\r
- }\r
- else\r
- {\r
- /* Add the lengths of the username and password if provided and not\r
- * connecting to an AWS IoT MQTT server. */\r
- if( pConnectInfo->pUserName != NULL )\r
- {\r
- connectPacketSize += pConnectInfo->userNameLength + sizeof( uint16_t );\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
-\r
- if( pConnectInfo->pPassword != NULL )\r
- {\r
- connectPacketSize += pConnectInfo->passwordLength + sizeof( uint16_t );\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
- }\r
-\r
- /* At this point, the "Remaining Length" field of the MQTT CONNECT packet has\r
- * been calculated. */\r
- remainingLength = connectPacketSize;\r
-\r
- /* Calculate the full size of the MQTT CONNECT packet by adding the size of\r
- * the "Remaining Length" field plus 1 byte for the "Packet Type" field. */\r
- connectPacketSize += 1 + _remainingLengthEncodedSize( connectPacketSize );\r
-\r
- /* Check that the CONNECT packet is within the bounds of the MQTT spec. */\r
- if( connectPacketSize > MQTT_PACKET_CONNECT_MAX_SIZE )\r
- {\r
- status = false;\r
- }\r
- else\r
- {\r
- *pRemainingLength = remainingLength;\r
- *pPacketSize = connectPacketSize;\r
- }\r
-\r
- return status;\r
-}\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-static bool _publishPacketSize( const IotMqttPublishInfo_t * pPublishInfo,\r
- size_t * pRemainingLength,\r
- size_t * pPacketSize )\r
-{\r
- bool status = true;\r
- size_t publishPacketSize = 0, payloadLimit = 0;\r
-\r
- /* The variable header of a PUBLISH packet always contains the topic name. */\r
- publishPacketSize += pPublishInfo->topicNameLength + sizeof( uint16_t );\r
-\r
- /* The variable header of a QoS 1 or 2 PUBLISH packet contains a 2-byte\r
- * packet identifier. */\r
- if( pPublishInfo->qos > IOT_MQTT_QOS_0 )\r
- {\r
- publishPacketSize += sizeof( uint16_t );\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
-\r
- /* Calculate the maximum allowed size of the payload for the given parameters.\r
- * This calculation excludes the "Remaining length" encoding, whose size is not\r
- * yet known. */\r
- payloadLimit = MQTT_MAX_REMAINING_LENGTH - publishPacketSize - 1;\r
-\r
- /* Ensure that the given payload fits within the calculated limit. */\r
- if( pPublishInfo->payloadLength > payloadLimit )\r
- {\r
- status = false;\r
- }\r
- else\r
- {\r
- /* Add the length of the PUBLISH payload. At this point, the "Remaining length"\r
- * has been calculated. */\r
- publishPacketSize += pPublishInfo->payloadLength;\r
-\r
- /* Now that the "Remaining length" is known, recalculate the payload limit\r
- * based on the size of its encoding. */\r
- payloadLimit -= _remainingLengthEncodedSize( publishPacketSize );\r
-\r
- /* Check that the given payload fits within the size allowed by MQTT spec. */\r
- if( pPublishInfo->payloadLength > payloadLimit )\r
- {\r
- status = false;\r
- }\r
- else\r
- {\r
- /* Set the "Remaining length" output parameter and calculate the full\r
- * size of the PUBLISH packet. */\r
- *pRemainingLength = publishPacketSize;\r
-\r
- publishPacketSize += 1 + _remainingLengthEncodedSize( publishPacketSize );\r
- *pPacketSize = publishPacketSize;\r
- }\r
- }\r
-\r
- return status;\r
-}\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-static bool _subscriptionPacketSize( IotMqttOperationType_t type,\r
- const IotMqttSubscription_t * pSubscriptionList,\r
- size_t subscriptionCount,\r
- size_t * pRemainingLength,\r
- size_t * pPacketSize )\r
-{\r
- bool status = true;\r
- size_t i = 0, subscriptionPacketSize = 0;\r
-\r
- /* Only SUBSCRIBE and UNSUBSCRIBE operations should call this function. */\r
- IotMqtt_Assert( ( type == IOT_MQTT_SUBSCRIBE ) || ( type == IOT_MQTT_UNSUBSCRIBE ) );\r
-\r
- /* The variable header of a subscription packet consists of a 2-byte packet\r
- * identifier. */\r
- subscriptionPacketSize += sizeof( uint16_t );\r
-\r
- /* Sum the lengths of all subscription topic filters; add 1 byte for each\r
- * subscription's QoS if type is IOT_MQTT_SUBSCRIBE. */\r
- for( i = 0; i < subscriptionCount; i++ )\r
- {\r
- /* Add the length of the topic filter. */\r
- subscriptionPacketSize += pSubscriptionList[ i ].topicFilterLength + sizeof( uint16_t );\r
-\r
- /* Only SUBSCRIBE packets include the QoS. */\r
- if( type == IOT_MQTT_SUBSCRIBE )\r
- {\r
- subscriptionPacketSize += 1;\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
- }\r
-\r
- /* At this point, the "Remaining length" has been calculated. Return error\r
- * if the "Remaining length" exceeds what is allowed by MQTT 3.1.1. Otherwise,\r
- * set the output parameter.*/\r
- if( subscriptionPacketSize > MQTT_MAX_REMAINING_LENGTH )\r
- {\r
- status = false;\r
- }\r
- else\r
- {\r
- *pRemainingLength = subscriptionPacketSize;\r
-\r
- /* Calculate the full size of the subscription packet by adding the size of the\r
- * "Remaining length" field plus 1 byte for the "Packet type" field. Set the\r
- * pPacketSize output parameter. */\r
- subscriptionPacketSize += 1 + _remainingLengthEncodedSize( subscriptionPacketSize );\r
- *pPacketSize = subscriptionPacketSize;\r
- }\r
-\r
- return status;\r
-}\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-uint8_t _IotMqtt_GetPacketType( void * pNetworkConnection,\r
- const IotNetworkInterface_t * pNetworkInterface )\r
-{\r
- uint8_t packetType = 0xff;\r
-\r
- /* The MQTT packet type is in the first byte of the packet. */\r
- ( void ) _IotMqtt_GetNextByte( pNetworkConnection,\r
- pNetworkInterface,\r
- &packetType );\r
-\r
- return packetType;\r
-}\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-size_t _IotMqtt_GetRemainingLength( void * pNetworkConnection,\r
- const IotNetworkInterface_t * pNetworkInterface )\r
-{\r
- uint8_t encodedByte = 0;\r
- size_t remainingLength = 0, multiplier = 1, bytesDecoded = 0, expectedSize = 0;\r
-\r
- /* This algorithm is copied from the MQTT v3.1.1 spec. */\r
- do\r
- {\r
- if( multiplier > 2097152 ) /* 128 ^ 3 */\r
- {\r
- remainingLength = MQTT_REMAINING_LENGTH_INVALID;\r
- break;\r
- }\r
- else\r
- {\r
- if( _IotMqtt_GetNextByte( pNetworkConnection,\r
- pNetworkInterface,\r
- &encodedByte ) == true )\r
- {\r
- remainingLength += ( encodedByte & 0x7F ) * multiplier;\r
- multiplier *= 128;\r
- bytesDecoded++;\r
- }\r
- else\r
- {\r
- remainingLength = MQTT_REMAINING_LENGTH_INVALID;\r
- break;\r
- }\r
- }\r
- } while( ( encodedByte & 0x80 ) != 0 );\r
-\r
- /* Check that the decoded remaining length conforms to the MQTT specification. */\r
- if( remainingLength != MQTT_REMAINING_LENGTH_INVALID )\r
- {\r
- expectedSize = _remainingLengthEncodedSize( remainingLength );\r
-\r
- if( bytesDecoded != expectedSize )\r
- {\r
- remainingLength = MQTT_REMAINING_LENGTH_INVALID;\r
- }\r
- else\r
- {\r
- /* Valid remaining length should be at most 4 bytes. */\r
- IotMqtt_Assert( bytesDecoded <= 4 );\r
- }\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
-\r
- return remainingLength;\r
-}\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-IotMqttError_t _IotMqtt_SerializeConnect( const IotMqttConnectInfo_t * pConnectInfo,\r
- uint8_t ** pConnectPacket,\r
- size_t * pPacketSize )\r
-{\r
- IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS );\r
- uint8_t connectFlags = 0;\r
- size_t remainingLength = 0, connectPacketSize = 0;\r
- uint8_t * pBuffer = NULL;\r
-\r
- /* Calculate the "Remaining length" field and total packet size. If it exceeds\r
- * what is allowed in the MQTT standard, return an error. */\r
- if( _connectPacketSize( pConnectInfo, &remainingLength, &connectPacketSize ) == false )\r
- {\r
- IotLogError( "Connect packet length exceeds %lu, which is the maximum"\r
- " size allowed by MQTT 3.1.1.",\r
- MQTT_PACKET_CONNECT_MAX_SIZE );\r
-\r
- IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER );\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
-\r
- /* Total size of the connect packet should be larger than the "Remaining length"\r
- * field. */\r
- IotMqtt_Assert( connectPacketSize > remainingLength );\r
-\r
- /* Allocate memory to hold the CONNECT packet. */\r
- pBuffer = IotMqtt_MallocMessage( connectPacketSize );\r
-\r
- /* Check that sufficient memory was allocated. */\r
- if( pBuffer == NULL )\r
- {\r
- IotLogError( "Failed to allocate memory for CONNECT packet." );\r
-\r
- IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_NO_MEMORY );\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
-\r
- /* Set the output parameters. The remainder of this function always succeeds. */\r
- *pConnectPacket = pBuffer;\r
- *pPacketSize = connectPacketSize;\r
-\r
- /* The first byte in the CONNECT packet is the control packet type. */\r
- *pBuffer = MQTT_PACKET_TYPE_CONNECT;\r
- pBuffer++;\r
-\r
- /* The remaining length of the CONNECT packet is encoded starting from the\r
- * second byte. The remaining length does not include the length of the fixed\r
- * header or the encoding of the remaining length. */\r
- pBuffer = _encodeRemainingLength( pBuffer, remainingLength );\r
-\r
- /* The string "MQTT" is placed at the beginning of the CONNECT packet's variable\r
- * header. This string is 4 bytes long. */\r
- pBuffer = _encodeString( pBuffer, "MQTT", 4 );\r
-\r
- /* The MQTT protocol version is the second byte of the variable header. */\r
- *pBuffer = MQTT_VERSION_3_1_1;\r
- pBuffer++;\r
-\r
- /* Set the CONNECT flags based on the given parameters. */\r
- if( pConnectInfo->cleanSession == true )\r
- {\r
- UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_CLEAN );\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
-\r
- /* Username and password depend on MQTT mode. */\r
- if( pConnectInfo->awsIotMqttMode == true )\r
- {\r
- /* Set the username flag for AWS IoT metrics. The AWS IoT MQTT server\r
- * never uses a password. */\r
- #if AWS_IOT_MQTT_ENABLE_METRICS == 1\r
- UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_USERNAME );\r
- #endif\r
- }\r
- else\r
- {\r
- /* Set the flags for username and password if provided. */\r
- if( pConnectInfo->pUserName != NULL )\r
- {\r
- UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_USERNAME );\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
-\r
- if( pConnectInfo->pPassword != NULL )\r
- {\r
- UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_PASSWORD );\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
- }\r
-\r
- /* Set will flag if an LWT is provided. */\r
- if( pConnectInfo->pWillInfo != NULL )\r
- {\r
- UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_WILL );\r
-\r
- /* Flags only need to be changed for will QoS 1 and 2. */\r
- switch( pConnectInfo->pWillInfo->qos )\r
- {\r
- case IOT_MQTT_QOS_1:\r
- UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_WILL_QOS1 );\r
- break;\r
-\r
- case IOT_MQTT_QOS_2:\r
- UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_WILL_QOS2 );\r
- break;\r
-\r
- default:\r
- break;\r
- }\r
-\r
- if( pConnectInfo->pWillInfo->retain == true )\r
- {\r
- UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_WILL_RETAIN );\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
-\r
- *pBuffer = connectFlags;\r
- pBuffer++;\r
-\r
- /* Write the 2 bytes of the keep alive interval into the CONNECT packet. */\r
- *pBuffer = UINT16_HIGH_BYTE( pConnectInfo->keepAliveSeconds );\r
- *( pBuffer + 1 ) = UINT16_LOW_BYTE( pConnectInfo->keepAliveSeconds );\r
- pBuffer += 2;\r
-\r
- /* Write the client identifier into the CONNECT packet. */\r
- pBuffer = _encodeString( pBuffer,\r
- pConnectInfo->pClientIdentifier,\r
- pConnectInfo->clientIdentifierLength );\r
-\r
- /* Write the will topic name and message into the CONNECT packet if provided. */\r
- if( pConnectInfo->pWillInfo != NULL )\r
- {\r
- pBuffer = _encodeString( pBuffer,\r
- pConnectInfo->pWillInfo->pTopicName,\r
- pConnectInfo->pWillInfo->topicNameLength );\r
-\r
- pBuffer = _encodeString( pBuffer,\r
- pConnectInfo->pWillInfo->pPayload,\r
- ( uint16_t ) pConnectInfo->pWillInfo->payloadLength );\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
-\r
- /* If metrics are enabled, write the metrics username into the CONNECT packet.\r
- * Otherwise, write the username and password only when not connecting to an\r
- * AWS IoT MQTT server. */\r
- if( pConnectInfo->awsIotMqttMode == true )\r
- {\r
- #if AWS_IOT_MQTT_ENABLE_METRICS == 1\r
- IotLogInfo( "Anonymous metrics (SDK language, SDK version) will be provided to AWS IoT. "\r
- "Recompile with AWS_IOT_MQTT_ENABLE_METRICS set to 0 to disable." );\r
-\r
- pBuffer = _encodeString( pBuffer,\r
- AWS_IOT_METRICS_USERNAME,\r
- AWS_IOT_METRICS_USERNAME_LENGTH );\r
- #endif\r
- }\r
- else\r
- {\r
- if( pConnectInfo->pUserName != NULL )\r
- {\r
- pBuffer = _encodeString( pBuffer,\r
- pConnectInfo->pUserName,\r
- pConnectInfo->userNameLength );\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
-\r
- if( pConnectInfo->pPassword != NULL )\r
- {\r
- pBuffer = _encodeString( pBuffer,\r
- pConnectInfo->pPassword,\r
- pConnectInfo->passwordLength );\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
- }\r
-\r
- /* Ensure that the difference between the end and beginning of the buffer\r
- * is equal to connectPacketSize, i.e. pBuffer did not overflow. */\r
- IotMqtt_Assert( ( size_t ) ( pBuffer - *pConnectPacket ) == connectPacketSize );\r
-\r
- /* Print out the serialized CONNECT packet for debugging purposes. */\r
- IotLog_PrintBuffer( "MQTT CONNECT packet:", *pConnectPacket, connectPacketSize );\r
-\r
- IOT_FUNCTION_EXIT_NO_CLEANUP();\r
-}\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-IotMqttError_t _IotMqtt_DeserializeConnack( _mqttPacket_t * pConnack )\r
-{\r
- IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS );\r
- const uint8_t * pRemainingData = pConnack->pRemainingData;\r
-\r
- /* If logging is enabled, declare the CONNACK response code strings. The\r
- * fourth byte of CONNACK indexes into this array for the corresponding response. */\r
- #if LIBRARY_LOG_LEVEL > IOT_LOG_NONE\r
- static const char * pConnackResponses[ 6 ] =\r
- {\r
- "Connection accepted.", /* 0 */\r
- "Connection refused: unacceptable protocol version.", /* 1 */\r
- "Connection refused: identifier rejected.", /* 2 */\r
- "Connection refused: server unavailable", /* 3 */\r
- "Connection refused: bad user name or password.", /* 4 */\r
- "Connection refused: not authorized." /* 5 */\r
- };\r
- #endif\r
-\r
- /* Check that the control packet type is 0x20. */\r
- if( pConnack->type != MQTT_PACKET_TYPE_CONNACK )\r
- {\r
- IotLog( IOT_LOG_ERROR,\r
- &_logHideAll,\r
- "Bad control packet type 0x%02x.",\r
- pConnack->type );\r
-\r
- IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
-\r
- /* According to MQTT 3.1.1, the second byte of CONNACK must specify a\r
- * "Remaining length" of 2. */\r
- if( pConnack->remainingLength != MQTT_PACKET_CONNACK_REMAINING_LENGTH )\r
- {\r
- IotLog( IOT_LOG_ERROR,\r
- &_logHideAll,\r
- "CONNACK does not have remaining length of %d.",\r
- MQTT_PACKET_CONNACK_REMAINING_LENGTH );\r
-\r
- IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
-\r
- /* Check the reserved bits in CONNACK. The high 7 bits of the second byte\r
- * in CONNACK must be 0. */\r
- if( ( pRemainingData[ 0 ] | 0x01 ) != 0x01 )\r
- {\r
- IotLog( IOT_LOG_ERROR,\r
- &_logHideAll,\r
- "Reserved bits in CONNACK incorrect." );\r
-\r
- IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
-\r
- /* Determine if the "Session Present" bit it set. This is the lowest bit of\r
- * the second byte in CONNACK. */\r
- if( ( pRemainingData[ 0 ] & MQTT_PACKET_CONNACK_SESSION_PRESENT_MASK )\r
- == MQTT_PACKET_CONNACK_SESSION_PRESENT_MASK )\r
- {\r
- IotLog( IOT_LOG_DEBUG,\r
- &_logHideAll,\r
- "CONNACK session present bit set." );\r
-\r
- /* MQTT 3.1.1 specifies that the fourth byte in CONNACK must be 0 if the\r
- * "Session Present" bit is set. */\r
- if( pRemainingData[ 1 ] != 0 )\r
- {\r
- IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
- }\r
- else\r
- {\r
- IotLog( IOT_LOG_DEBUG,\r
- &_logHideAll,\r
- "CONNACK session present bit not set." );\r
- }\r
-\r
- /* In MQTT 3.1.1, only values 0 through 5 are valid CONNACK response codes. */\r
- if( pRemainingData[ 1 ] > 5 )\r
- {\r
- IotLog( IOT_LOG_DEBUG,\r
- &_logHideAll,\r
- "CONNACK response %hhu is not valid.",\r
- pRemainingData[ 1 ] );\r
-\r
- IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
-\r
- /* Print the appropriate message for the CONNACK response code if logs are\r
- * enabled. */\r
- #if LIBRARY_LOG_LEVEL > IOT_LOG_NONE\r
- IotLog( IOT_LOG_DEBUG,\r
- &_logHideAll,\r
- "%s",\r
- pConnackResponses[ pRemainingData[ 1 ] ] );\r
- #endif\r
-\r
- /* A nonzero CONNACK response code means the connection was refused. */\r
- if( pRemainingData[ 1 ] > 0 )\r
- {\r
- IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_SERVER_REFUSED );\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
-\r
- IOT_FUNCTION_EXIT_NO_CLEANUP();\r
-}\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-IotMqttError_t _IotMqtt_SerializePublish( const IotMqttPublishInfo_t * pPublishInfo,\r
- uint8_t ** pPublishPacket,\r
- size_t * pPacketSize,\r
- uint16_t * pPacketIdentifier,\r
- uint8_t ** pPacketIdentifierHigh )\r
-{\r
- IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS );\r
- uint8_t publishFlags = 0;\r
- uint16_t packetIdentifier = 0;\r
- size_t remainingLength = 0, publishPacketSize = 0;\r
- uint8_t * pBuffer = NULL;\r
-\r
- /* Calculate the "Remaining length" field and total packet size. If it exceeds\r
- * what is allowed in the MQTT standard, return an error. */\r
- if( _publishPacketSize( pPublishInfo, &remainingLength, &publishPacketSize ) == false )\r
- {\r
- IotLogError( "Publish packet remaining length exceeds %lu, which is the "\r
- "maximum size allowed by MQTT 3.1.1.",\r
- MQTT_MAX_REMAINING_LENGTH );\r
-\r
- IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER );\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
-\r
- /* Total size of the publish packet should be larger than the "Remaining length"\r
- * field. */\r
- IotMqtt_Assert( publishPacketSize > remainingLength );\r
-\r
- /* Allocate memory to hold the PUBLISH packet. */\r
- pBuffer = IotMqtt_MallocMessage( publishPacketSize );\r
-\r
- /* Check that sufficient memory was allocated. */\r
- if( pBuffer == NULL )\r
- {\r
- IotLogError( "Failed to allocate memory for PUBLISH packet." );\r
-\r
- IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_NO_MEMORY );\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
-\r
- /* Set the output parameters. The remainder of this function always succeeds. */\r
- *pPublishPacket = pBuffer;\r
- *pPacketSize = publishPacketSize;\r
-\r
- /* The first byte of a PUBLISH packet contains the packet type and flags. */\r
- publishFlags = MQTT_PACKET_TYPE_PUBLISH;\r
-\r
- if( pPublishInfo->qos == IOT_MQTT_QOS_1 )\r
- {\r
- UINT8_SET_BIT( publishFlags, MQTT_PUBLISH_FLAG_QOS1 );\r
- }\r
- else if( pPublishInfo->qos == IOT_MQTT_QOS_2 )\r
- {\r
- UINT8_SET_BIT( publishFlags, MQTT_PUBLISH_FLAG_QOS2 );\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
-\r
- if( pPublishInfo->retain == true )\r
- {\r
- UINT8_SET_BIT( publishFlags, MQTT_PUBLISH_FLAG_RETAIN );\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
-\r
- *pBuffer = publishFlags;\r
- pBuffer++;\r
-\r
- /* The "Remaining length" is encoded from the second byte. */\r
- pBuffer = _encodeRemainingLength( pBuffer, remainingLength );\r
-\r
- /* The topic name is placed after the "Remaining length". */\r
- pBuffer = _encodeString( pBuffer,\r
- pPublishInfo->pTopicName,\r
- pPublishInfo->topicNameLength );\r
-\r
- /* A packet identifier is required for QoS 1 and 2 messages. */\r
- if( pPublishInfo->qos > IOT_MQTT_QOS_0 )\r
- {\r
- /* Get the next packet identifier. It should always be nonzero. */\r
- packetIdentifier = _nextPacketIdentifier();\r
- IotMqtt_Assert( packetIdentifier != 0 );\r
-\r
- /* Set the packet identifier output parameters. */\r
- *pPacketIdentifier = packetIdentifier;\r
-\r
- if( pPacketIdentifierHigh != NULL )\r
- {\r
- *pPacketIdentifierHigh = pBuffer;\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
-\r
- /* Place the packet identifier into the PUBLISH packet. */\r
- *pBuffer = UINT16_HIGH_BYTE( packetIdentifier );\r
- *( pBuffer + 1 ) = UINT16_LOW_BYTE( packetIdentifier );\r
- pBuffer += 2;\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
-\r
- /* The payload is placed after the packet identifier. */\r
- if( pPublishInfo->payloadLength > 0 )\r
- {\r
- ( void ) memcpy( pBuffer, pPublishInfo->pPayload, pPublishInfo->payloadLength );\r
- pBuffer += pPublishInfo->payloadLength;\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
-\r
- /* Ensure that the difference between the end and beginning of the buffer\r
- * is equal to publishPacketSize, i.e. pBuffer did not overflow. */\r
- IotMqtt_Assert( ( size_t ) ( pBuffer - *pPublishPacket ) == publishPacketSize );\r
-\r
- /* Print out the serialized PUBLISH packet for debugging purposes. */\r
- IotLog_PrintBuffer( "MQTT PUBLISH packet:", *pPublishPacket, publishPacketSize );\r
-\r
- IOT_FUNCTION_EXIT_NO_CLEANUP();\r
-}\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-void _IotMqtt_PublishSetDup( uint8_t * pPublishPacket,\r
- uint8_t * pPacketIdentifierHigh,\r
- uint16_t * pNewPacketIdentifier )\r
-{\r
- uint16_t newPacketIdentifier = 0;\r
-\r
- /* For an AWS IoT MQTT server, change the packet identifier. */\r
- if( pPacketIdentifierHigh != NULL )\r
- {\r
- /* Output parameter for new packet identifier must be provided. */\r
- IotMqtt_Assert( pNewPacketIdentifier != NULL );\r
-\r
- /* Generate a new packet identifier. */\r
- newPacketIdentifier = _nextPacketIdentifier();\r
-\r
- IotLogDebug( "Changing PUBLISH packet identifier %hu to %hu.",\r
- UINT16_DECODE( pPacketIdentifierHigh ),\r
- newPacketIdentifier );\r
-\r
- /* Replace the packet identifier. */\r
- *pPacketIdentifierHigh = UINT16_HIGH_BYTE( newPacketIdentifier );\r
- *( pPacketIdentifierHigh + 1 ) = UINT16_LOW_BYTE( newPacketIdentifier );\r
- *pNewPacketIdentifier = newPacketIdentifier;\r
- }\r
- else\r
- {\r
- /* For a compliant MQTT 3.1.1 server, set the DUP flag. */\r
- UINT8_SET_BIT( *pPublishPacket, MQTT_PUBLISH_FLAG_DUP );\r
-\r
- IotLogDebug( "PUBLISH DUP flag set." );\r
- }\r
-}\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-IotMqttError_t _IotMqtt_DeserializePublish( _mqttPacket_t * pPublish )\r
-{\r
- IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS );\r
- IotMqttPublishInfo_t * pOutput = &( pPublish->u.pIncomingPublish->u.publish.publishInfo );\r
- uint8_t publishFlags = 0;\r
- const uint8_t * pVariableHeader = pPublish->pRemainingData, * pPacketIdentifierHigh = NULL;\r
-\r
- /* The flags are the lower 4 bits of the first byte in PUBLISH. */\r
- publishFlags = pPublish->type;\r
-\r
- /* Parse the Retain bit. */\r
- pOutput->retain = UINT8_CHECK_BIT( publishFlags, MQTT_PUBLISH_FLAG_RETAIN );\r
-\r
- IotLog( IOT_LOG_DEBUG,\r
- &_logHideAll,\r
- "Retain bit is %d.", pOutput->retain );\r
-\r
- /* Check for QoS 2. */\r
- if( UINT8_CHECK_BIT( publishFlags, MQTT_PUBLISH_FLAG_QOS2 ) == true )\r
- {\r
- /* PUBLISH packet is invalid if both QoS 1 and QoS 2 bits are set. */\r
- if( UINT8_CHECK_BIT( publishFlags, MQTT_PUBLISH_FLAG_QOS1 ) == true )\r
- {\r
- IotLog( IOT_LOG_DEBUG,\r
- &_logHideAll,\r
- "Bad QoS: 3." );\r
-\r
- IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
-\r
- pOutput->qos = IOT_MQTT_QOS_2;\r
- }\r
- /* Check for QoS 1. */\r
- else if( UINT8_CHECK_BIT( publishFlags, MQTT_PUBLISH_FLAG_QOS1 ) == true )\r
- {\r
- pOutput->qos = IOT_MQTT_QOS_1;\r
- }\r
- /* If the PUBLISH isn't QoS 1 or 2, then it's QoS 0. */\r
- else\r
- {\r
- pOutput->qos = IOT_MQTT_QOS_0;\r
- }\r
-\r
- IotLog( IOT_LOG_DEBUG,\r
- &_logHideAll,\r
- "QoS is %d.", pOutput->qos );\r
-\r
- /* Parse the DUP bit. */\r
- if( UINT8_CHECK_BIT( publishFlags, MQTT_PUBLISH_FLAG_DUP ) == true )\r
- {\r
- IotLog( IOT_LOG_DEBUG,\r
- &_logHideAll,\r
- "DUP is 1." );\r
- }\r
- else\r
- {\r
- IotLog( IOT_LOG_DEBUG,\r
- &_logHideAll,\r
- "DUP is 0." );\r
- }\r
-\r
- /* Sanity checks for "Remaining length". */\r
- if( pOutput->qos == IOT_MQTT_QOS_0 )\r
- {\r
- /* A QoS 0 PUBLISH must have a remaining length of at least 3 to accommodate\r
- * topic name length (2 bytes) and topic name (at least 1 byte). */\r
- if( pPublish->remainingLength < 3 )\r
- {\r
- IotLog( IOT_LOG_DEBUG,\r
- &_logHideAll,\r
- "QoS 0 PUBLISH cannot have a remaining length less than 3." );\r
-\r
- IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
- }\r
- else\r
- {\r
- /* A QoS 1 or 2 PUBLISH must have a remaining length of at least 5 to\r
- * accommodate a packet identifier as well as the topic name length and\r
- * topic name. */\r
- if( pPublish->remainingLength < 5 )\r
- {\r
- IotLog( IOT_LOG_DEBUG,\r
- &_logHideAll,\r
- "QoS 1 or 2 PUBLISH cannot have a remaining length less than 5." );\r
-\r
- IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
- }\r
-\r
- /* Extract the topic name starting from the first byte of the variable header.\r
- * The topic name string starts at byte 3 in the variable header. */\r
- pOutput->topicNameLength = UINT16_DECODE( pVariableHeader );\r
-\r
- /* Sanity checks for topic name length and "Remaining length". */\r
- if( pOutput->qos == IOT_MQTT_QOS_0 )\r
- {\r
- /* Check that the "Remaining length" is at least as large as the variable\r
- * header. */\r
- if( pPublish->remainingLength < pOutput->topicNameLength + sizeof( uint16_t ) )\r
- {\r
- IotLog( IOT_LOG_DEBUG,\r
- &_logHideAll,\r
- "Remaining length cannot be less than variable header length." );\r
-\r
- IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
- }\r
- else\r
- {\r
- /* Check that the "Remaining length" is at least as large as the variable\r
- * header. */\r
- if( pPublish->remainingLength < pOutput->topicNameLength + 2 * sizeof( uint16_t ) )\r
- {\r
- IotLog( IOT_LOG_DEBUG,\r
- &_logHideAll,\r
- "Remaining length cannot be less than variable header length." );\r
-\r
- IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
- }\r
-\r
- /* Parse the topic. */\r
- pOutput->pTopicName = ( const char * ) ( pVariableHeader + sizeof( uint16_t ) );\r
-\r
- IotLog( IOT_LOG_DEBUG,\r
- &_logHideAll,\r
- "Topic name length %hu: %.*s",\r
- pOutput->topicNameLength,\r
- pOutput->topicNameLength,\r
- pOutput->pTopicName );\r
-\r
- /* Extract the packet identifier for QoS 1 or 2 PUBLISH packets. Packet\r
- * identifier starts immediately after the topic name. */\r
- pPacketIdentifierHigh = ( const uint8_t * ) ( pOutput->pTopicName + pOutput->topicNameLength );\r
-\r
- if( pOutput->qos > IOT_MQTT_QOS_0 )\r
- {\r
- pPublish->packetIdentifier = UINT16_DECODE( pPacketIdentifierHigh );\r
-\r
- IotLog( IOT_LOG_DEBUG,\r
- &_logHideAll,\r
- "Packet identifier %hu.", pPublish->packetIdentifier );\r
-\r
- /* Packet identifier cannot be 0. */\r
- if( pPublish->packetIdentifier == 0 )\r
- {\r
- IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
-\r
- /* Calculate the length of the payload. QoS 1 or 2 PUBLISH packets contain\r
- * a packet identifer, but QoS 0 PUBLISH packets do not. */\r
- if( pOutput->qos == IOT_MQTT_QOS_0 )\r
- {\r
- pOutput->payloadLength = ( pPublish->remainingLength - pOutput->topicNameLength - sizeof( uint16_t ) );\r
- pOutput->pPayload = pPacketIdentifierHigh;\r
- }\r
- else\r
- {\r
- pOutput->payloadLength = ( pPublish->remainingLength - pOutput->topicNameLength - 2 * sizeof( uint16_t ) );\r
- pOutput->pPayload = pPacketIdentifierHigh + sizeof( uint16_t );\r
- }\r
-\r
- IotLog( IOT_LOG_DEBUG,\r
- &_logHideAll,\r
- "Payload length %hu.", pOutput->payloadLength );\r
-\r
- IOT_FUNCTION_EXIT_NO_CLEANUP();\r
-}\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-IotMqttError_t _IotMqtt_SerializePuback( uint16_t packetIdentifier,\r
- uint8_t ** pPubackPacket,\r
- size_t * pPacketSize )\r
-{\r
- IotMqttError_t status = IOT_MQTT_SUCCESS;\r
-\r
- /* Allocate memory for PUBACK. */\r
- uint8_t * pBuffer = IotMqtt_MallocMessage( MQTT_PACKET_PUBACK_SIZE );\r
-\r
- if( pBuffer == NULL )\r
- {\r
- IotLogError( "Failed to allocate memory for PUBACK packet" );\r
-\r
- status = IOT_MQTT_NO_MEMORY;\r
- }\r
- else\r
- {\r
- /* Set the output parameters. The remainder of this function always succeeds. */\r
- *pPubackPacket = pBuffer;\r
- *pPacketSize = MQTT_PACKET_PUBACK_SIZE;\r
-\r
- /* Set the 4 bytes in PUBACK. */\r
- pBuffer[ 0 ] = MQTT_PACKET_TYPE_PUBACK;\r
- pBuffer[ 1 ] = MQTT_PACKET_PUBACK_REMAINING_LENGTH;\r
- pBuffer[ 2 ] = UINT16_HIGH_BYTE( packetIdentifier );\r
- pBuffer[ 3 ] = UINT16_LOW_BYTE( packetIdentifier );\r
-\r
- /* Print out the serialized PUBACK packet for debugging purposes. */\r
- IotLog_PrintBuffer( "MQTT PUBACK packet:", *pPubackPacket, MQTT_PACKET_PUBACK_SIZE );\r
- }\r
-\r
- return status;\r
-}\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-IotMqttError_t _IotMqtt_DeserializePuback( _mqttPacket_t * pPuback )\r
-{\r
- IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS );\r
-\r
- /* Check the "Remaining length" of the received PUBACK. */\r
- if( pPuback->remainingLength != MQTT_PACKET_PUBACK_REMAINING_LENGTH )\r
- {\r
- IotLog( IOT_LOG_ERROR,\r
- &_logHideAll,\r
- "PUBACK does not have remaining length of %d.",\r
- MQTT_PACKET_PUBACK_REMAINING_LENGTH );\r
-\r
- IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
-\r
- /* Extract the packet identifier (third and fourth bytes) from PUBACK. */\r
- pPuback->packetIdentifier = UINT16_DECODE( pPuback->pRemainingData );\r
-\r
- IotLog( IOT_LOG_DEBUG,\r
- &_logHideAll,\r
- "Packet identifier %hu.", pPuback->packetIdentifier );\r
-\r
- /* Packet identifier cannot be 0. */\r
- if( pPuback->packetIdentifier == 0 )\r
- {\r
- IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
-\r
- /* Check that the control packet type is 0x40 (this must be done after the\r
- * packet identifier is parsed). */\r
- if( pPuback->type != MQTT_PACKET_TYPE_PUBACK )\r
- {\r
- IotLog( IOT_LOG_ERROR,\r
- &_logHideAll,\r
- "Bad control packet type 0x%02x.",\r
- pPuback->type );\r
-\r
- IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
-\r
- IOT_FUNCTION_EXIT_NO_CLEANUP();\r
-}\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-IotMqttError_t _IotMqtt_SerializeSubscribe( const IotMqttSubscription_t * pSubscriptionList,\r
- size_t subscriptionCount,\r
- uint8_t ** pSubscribePacket,\r
- size_t * pPacketSize,\r
- uint16_t * pPacketIdentifier )\r
-{\r
- IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS );\r
- size_t i = 0, subscribePacketSize = 0, remainingLength = 0;\r
- uint16_t packetIdentifier = 0;\r
- uint8_t * pBuffer = NULL;\r
-\r
- /* Calculate the "Remaining length" field and total packet size. If it exceeds\r
- * what is allowed in the MQTT standard, return an error. */\r
- if( _subscriptionPacketSize( IOT_MQTT_SUBSCRIBE,\r
- pSubscriptionList,\r
- subscriptionCount,\r
- &remainingLength,\r
- &subscribePacketSize ) == false )\r
- {\r
- IotLogError( "Subscribe packet remaining length exceeds %lu, which is the "\r
- "maximum size allowed by MQTT 3.1.1.",\r
- MQTT_MAX_REMAINING_LENGTH );\r
-\r
- IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER );\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
-\r
- /* Total size of the subscribe packet should be larger than the "Remaining length"\r
- * field. */\r
- IotMqtt_Assert( subscribePacketSize > remainingLength );\r
-\r
- /* Allocate memory to hold the SUBSCRIBE packet. */\r
- pBuffer = IotMqtt_MallocMessage( subscribePacketSize );\r
-\r
- /* Check that sufficient memory was allocated. */\r
- if( pBuffer == NULL )\r
- {\r
- IotLogError( "Failed to allocate memory for SUBSCRIBE packet." );\r
-\r
- IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_NO_MEMORY );\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
-\r
- /* Set the output parameters. The remainder of this function always succeeds. */\r
- *pSubscribePacket = pBuffer;\r
- *pPacketSize = subscribePacketSize;\r
-\r
- /* The first byte in SUBSCRIBE is the packet type. */\r
- *pBuffer = MQTT_PACKET_TYPE_SUBSCRIBE;\r
- pBuffer++;\r
-\r
- /* Encode the "Remaining length" starting from the second byte. */\r
- pBuffer = _encodeRemainingLength( pBuffer, remainingLength );\r
-\r
- /* Get the next packet identifier. It should always be nonzero. */\r
- packetIdentifier = _nextPacketIdentifier();\r
- *pPacketIdentifier = packetIdentifier;\r
- IotMqtt_Assert( packetIdentifier != 0 );\r
-\r
- /* Place the packet identifier into the SUBSCRIBE packet. */\r
- *pBuffer = UINT16_HIGH_BYTE( packetIdentifier );\r
- *( pBuffer + 1 ) = UINT16_LOW_BYTE( packetIdentifier );\r
- pBuffer += 2;\r
-\r
- /* Serialize each subscription topic filter and QoS. */\r
- for( i = 0; i < subscriptionCount; i++ )\r
- {\r
- pBuffer = _encodeString( pBuffer,\r
- pSubscriptionList[ i ].pTopicFilter,\r
- pSubscriptionList[ i ].topicFilterLength );\r
-\r
- /* Place the QoS in the SUBSCRIBE packet. */\r
- *pBuffer = ( uint8_t ) ( pSubscriptionList[ i ].qos );\r
- pBuffer++;\r
- }\r
-\r
- /* Ensure that the difference between the end and beginning of the buffer\r
- * is equal to subscribePacketSize, i.e. pBuffer did not overflow. */\r
- IotMqtt_Assert( ( size_t ) ( pBuffer - *pSubscribePacket ) == subscribePacketSize );\r
-\r
- /* Print out the serialized SUBSCRIBE packet for debugging purposes. */\r
- IotLog_PrintBuffer( "MQTT SUBSCRIBE packet:", *pSubscribePacket, subscribePacketSize );\r
-\r
- IOT_FUNCTION_EXIT_NO_CLEANUP();\r
-}\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-IotMqttError_t _IotMqtt_DeserializeSuback( _mqttPacket_t * pSuback )\r
-{\r
- IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS );\r
- size_t i = 0, remainingLength = pSuback->remainingLength;\r
- uint8_t subscriptionStatus = 0;\r
- const uint8_t * pVariableHeader = pSuback->pRemainingData;\r
-\r
- /* A SUBACK must have a remaining length of at least 3 to accommodate the\r
- * packet identifer and at least 1 return code. */\r
- if( remainingLength < 3 )\r
- {\r
- IotLog( IOT_LOG_DEBUG,\r
- &_logHideAll,\r
- "SUBACK cannot have a remaining length less than 3." );\r
-\r
- IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
-\r
- /* Extract the packet identifier (first 2 bytes of variable header) from SUBACK. */\r
- pSuback->packetIdentifier = UINT16_DECODE( pVariableHeader );\r
-\r
- IotLog( IOT_LOG_DEBUG,\r
- &_logHideAll,\r
- "Packet identifier %hu.", pSuback->packetIdentifier );\r
-\r
- /* Check that the control packet type is 0x90 (this must be done after the\r
- * packet identifier is parsed). */\r
- if( pSuback->type != MQTT_PACKET_TYPE_SUBACK )\r
- {\r
- IotLog( IOT_LOG_ERROR,\r
- &_logHideAll,\r
- "Bad control packet type 0x%02x.",\r
- pSuback->type );\r
-\r
- IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
-\r
- /* Iterate through each status byte in the SUBACK packet. */\r
- for( i = 0; i < remainingLength - sizeof( uint16_t ); i++ )\r
- {\r
- /* Read a single status byte in SUBACK. */\r
- subscriptionStatus = *( pVariableHeader + sizeof( uint16_t ) + i );\r
-\r
- /* MQTT 3.1.1 defines the following values as status codes. */\r
- switch( subscriptionStatus )\r
- {\r
- case 0x00:\r
- case 0x01:\r
- case 0x02:\r
- IotLog( IOT_LOG_DEBUG,\r
- &_logHideAll,\r
- "Topic filter %lu accepted, max QoS %hhu.",\r
- ( unsigned long ) i, subscriptionStatus );\r
- break;\r
-\r
- case 0x80:\r
- IotLog( IOT_LOG_DEBUG,\r
- &_logHideAll,\r
- "Topic filter %lu refused.", ( unsigned long ) i );\r
-\r
- /* Remove a rejected subscription from the subscription manager. */\r
- _IotMqtt_RemoveSubscriptionByPacket( pSuback->u.pMqttConnection,\r
- pSuback->packetIdentifier,\r
- ( int32_t ) i );\r
-\r
- status = IOT_MQTT_SERVER_REFUSED;\r
-\r
- break;\r
-\r
- default:\r
- IotLog( IOT_LOG_DEBUG,\r
- &_logHideAll,\r
- "Bad SUBSCRIBE status %hhu.", subscriptionStatus );\r
-\r
- status = IOT_MQTT_BAD_RESPONSE;\r
-\r
- break;\r
- }\r
-\r
- /* Stop parsing the subscription statuses if a bad response was received. */\r
- if( status == IOT_MQTT_BAD_RESPONSE )\r
- {\r
- break;\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
- }\r
-\r
- IOT_FUNCTION_EXIT_NO_CLEANUP();\r
-}\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-IotMqttError_t _IotMqtt_SerializeUnsubscribe( const IotMqttSubscription_t * pSubscriptionList,\r
- size_t subscriptionCount,\r
- uint8_t ** pUnsubscribePacket,\r
- size_t * pPacketSize,\r
- uint16_t * pPacketIdentifier )\r
-{\r
- IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS );\r
- size_t i = 0, unsubscribePacketSize = 0, remainingLength = 0;\r
- uint16_t packetIdentifier = 0;\r
- uint8_t * pBuffer = NULL;\r
-\r
- /* Calculate the "Remaining length" field and total packet size. If it exceeds\r
- * what is allowed in the MQTT standard, return an error. */\r
- if( _subscriptionPacketSize( IOT_MQTT_UNSUBSCRIBE,\r
- pSubscriptionList,\r
- subscriptionCount,\r
- &remainingLength,\r
- &unsubscribePacketSize ) == false )\r
- {\r
- IotLogError( "Unsubscribe packet remaining length exceeds %lu, which is the "\r
- "maximum size allowed by MQTT 3.1.1.",\r
- MQTT_MAX_REMAINING_LENGTH );\r
-\r
- IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER );\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
-\r
- /* Total size of the unsubscribe packet should be larger than the "Remaining length"\r
- * field. */\r
- IotMqtt_Assert( unsubscribePacketSize > remainingLength );\r
-\r
- /* Allocate memory to hold the UNSUBSCRIBE packet. */\r
- pBuffer = IotMqtt_MallocMessage( unsubscribePacketSize );\r
-\r
- /* Check that sufficient memory was allocated. */\r
- if( pBuffer == NULL )\r
- {\r
- IotLogError( "Failed to allocate memory for UNSUBSCRIBE packet." );\r
-\r
- IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_NO_MEMORY );\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
-\r
- /* Set the output parameters. The remainder of this function always succeeds. */\r
- *pUnsubscribePacket = pBuffer;\r
- *pPacketSize = unsubscribePacketSize;\r
-\r
- /* The first byte in UNSUBSCRIBE is the packet type. */\r
- *pBuffer = MQTT_PACKET_TYPE_UNSUBSCRIBE;\r
- pBuffer++;\r
-\r
- /* Encode the "Remaining length" starting from the second byte. */\r
- pBuffer = _encodeRemainingLength( pBuffer, remainingLength );\r
-\r
- /* Get the next packet identifier. It should always be nonzero. */\r
- packetIdentifier = _nextPacketIdentifier();\r
- *pPacketIdentifier = packetIdentifier;\r
- IotMqtt_Assert( packetIdentifier != 0 );\r
-\r
- /* Place the packet identifier into the UNSUBSCRIBE packet. */\r
- *pBuffer = UINT16_HIGH_BYTE( packetIdentifier );\r
- *( pBuffer + 1 ) = UINT16_LOW_BYTE( packetIdentifier );\r
- pBuffer += 2;\r
-\r
- /* Serialize each subscription topic filter. */\r
- for( i = 0; i < subscriptionCount; i++ )\r
- {\r
- pBuffer = _encodeString( pBuffer,\r
- pSubscriptionList[ i ].pTopicFilter,\r
- pSubscriptionList[ i ].topicFilterLength );\r
- }\r
-\r
- /* Ensure that the difference between the end and beginning of the buffer\r
- * is equal to unsubscribePacketSize, i.e. pBuffer did not overflow. */\r
- IotMqtt_Assert( ( size_t ) ( pBuffer - *pUnsubscribePacket ) == unsubscribePacketSize );\r
-\r
- /* Print out the serialized UNSUBSCRIBE packet for debugging purposes. */\r
- IotLog_PrintBuffer( "MQTT UNSUBSCRIBE packet:", *pUnsubscribePacket, unsubscribePacketSize );\r
-\r
- IOT_FUNCTION_EXIT_NO_CLEANUP();\r
-}\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-IotMqttError_t _IotMqtt_DeserializeUnsuback( _mqttPacket_t * pUnsuback )\r
-{\r
- IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS );\r
-\r
- /* Check the "Remaining length" (second byte) of the received UNSUBACK. */\r
- if( pUnsuback->remainingLength != MQTT_PACKET_UNSUBACK_REMAINING_LENGTH )\r
- {\r
- IotLog( IOT_LOG_ERROR,\r
- &_logHideAll,\r
- "UNSUBACK does not have remaining length of %d.",\r
- MQTT_PACKET_UNSUBACK_REMAINING_LENGTH );\r
-\r
- IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
-\r
- /* Extract the packet identifier (third and fourth bytes) from UNSUBACK. */\r
- pUnsuback->packetIdentifier = UINT16_DECODE( pUnsuback->pRemainingData );\r
-\r
- /* Packet identifier cannot be 0. */\r
- if( pUnsuback->packetIdentifier == 0 )\r
- {\r
- IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
-\r
- IotLog( IOT_LOG_DEBUG,\r
- &_logHideAll,\r
- "Packet identifier %hu.", pUnsuback->packetIdentifier );\r
-\r
- /* Check that the control packet type is 0xb0 (this must be done after the\r
- * packet identifier is parsed). */\r
- if( pUnsuback->type != MQTT_PACKET_TYPE_UNSUBACK )\r
- {\r
- IotLog( IOT_LOG_ERROR,\r
- &_logHideAll,\r
- "Bad control packet type 0x%02x.",\r
- pUnsuback->type );\r
-\r
- IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
-\r
- IOT_FUNCTION_EXIT_NO_CLEANUP();\r
-}\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-IotMqttError_t _IotMqtt_SerializePingreq( uint8_t ** pPingreqPacket,\r
- size_t * pPacketSize )\r
-{\r
- /* PINGREQ packets are always the same. */\r
- static const uint8_t pPingreq[ MQTT_PACKET_PINGREQ_SIZE ] =\r
- {\r
- MQTT_PACKET_TYPE_PINGREQ,\r
- 0x00\r
- };\r
-\r
- /* Set the output parameters. */\r
- *pPingreqPacket = ( uint8_t * ) pPingreq;\r
- *pPacketSize = MQTT_PACKET_PINGREQ_SIZE;\r
-\r
- /* Print out the PINGREQ packet for debugging purposes. */\r
- IotLog_PrintBuffer( "MQTT PINGREQ packet:", pPingreq, MQTT_PACKET_PINGREQ_SIZE );\r
-\r
- return IOT_MQTT_SUCCESS;\r
-}\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-IotMqttError_t _IotMqtt_DeserializePingresp( _mqttPacket_t * pPingresp )\r
-{\r
- IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS );\r
-\r
- /* Check that the control packet type is 0xd0. */\r
- if( pPingresp->type != MQTT_PACKET_TYPE_PINGRESP )\r
- {\r
- IotLog( IOT_LOG_ERROR,\r
- &_logHideAll,\r
- "Bad control packet type 0x%02x.",\r
- pPingresp->type );\r
-\r
- IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
-\r
- /* Check the "Remaining length" (second byte) of the received PINGRESP. */\r
- if( pPingresp->remainingLength != MQTT_PACKET_PINGRESP_REMAINING_LENGTH )\r
- {\r
- IotLog( IOT_LOG_ERROR,\r
- &_logHideAll,\r
- "PINGRESP does not have remaining length of %d.",\r
- MQTT_PACKET_PINGRESP_REMAINING_LENGTH );\r
-\r
- IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
-\r
- IOT_FUNCTION_EXIT_NO_CLEANUP();\r
-}\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-IotMqttError_t _IotMqtt_SerializeDisconnect( uint8_t ** pDisconnectPacket,\r
- size_t * pPacketSize )\r
-{\r
- /* DISCONNECT packets are always the same. */\r
- static const uint8_t pDisconnect[ MQTT_PACKET_DISCONNECT_SIZE ] =\r
- {\r
- MQTT_PACKET_TYPE_DISCONNECT,\r
- 0x00\r
- };\r
-\r
- /* Set the output parameters. */\r
- *pDisconnectPacket = ( uint8_t * ) pDisconnect;\r
- *pPacketSize = MQTT_PACKET_DISCONNECT_SIZE;\r
-\r
- /* Print out the DISCONNECT packet for debugging purposes. */\r
- IotLog_PrintBuffer( "MQTT DISCONNECT packet:", pDisconnect, MQTT_PACKET_DISCONNECT_SIZE );\r
-\r
- return IOT_MQTT_SUCCESS;\r
-}\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-void _IotMqtt_FreePacket( uint8_t * pPacket )\r
-{\r
- uint8_t packetType = *pPacket;\r
-\r
- /* Don't call free on DISCONNECT and PINGREQ; those are allocated from static\r
- * memory. */\r
- if( packetType != MQTT_PACKET_TYPE_DISCONNECT )\r
- {\r
- if( packetType != MQTT_PACKET_TYPE_PINGREQ )\r
- {\r
- IotMqtt_FreeMessage( pPacket );\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
-}\r
-\r
-/*-----------------------------------------------------------*/\r