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