summaryrefslogtreecommitdiff
path: root/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/mqtt/src/private/iot_mqtt_internal.h
diff options
context:
space:
mode:
Diffstat (limited to 'FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/mqtt/src/private/iot_mqtt_internal.h')
-rw-r--r--FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/mqtt/src/private/iot_mqtt_internal.h1038
1 files changed, 1038 insertions, 0 deletions
diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/mqtt/src/private/iot_mqtt_internal.h b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/mqtt/src/private/iot_mqtt_internal.h
new file mode 100644
index 000000000..4c1099129
--- /dev/null
+++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/mqtt/src/private/iot_mqtt_internal.h
@@ -0,0 +1,1038 @@
+/*
+ * IoT MQTT V2.1.0
+ * Copyright (C) 2018 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.
+ */
+
+/**
+ * @file iot_mqtt_internal.h
+ * @brief Internal header of MQTT library. This header should not be included in
+ * typical application code.
+ */
+
+#ifndef IOT_MQTT_INTERNAL_H_
+#define IOT_MQTT_INTERNAL_H_
+
+/* The config header is always included first. */
+#include "iot_config.h"
+
+/* Linear containers (lists and queues) include. */
+#include "iot_linear_containers.h"
+
+/* MQTT include. */
+#include "iot_mqtt.h"
+
+/* Task pool include. */
+#include "iot_taskpool_freertos.h"
+
+/**
+ * @def IotMqtt_Assert( expression )
+ * @brief Assertion macro for the MQTT library.
+ *
+ * Set @ref IOT_MQTT_ENABLE_ASSERTS to `1` to enable assertions in the MQTT
+ * library.
+ *
+ * @param[in] expression Expression to be evaluated.
+ */
+#if IOT_MQTT_ENABLE_ASSERTS == 1
+ #ifndef IotMqtt_Assert
+ #ifdef Iot_DefaultAssert
+ #define IotMqtt_Assert( expression ) Iot_DefaultAssert( expression )
+ #else
+ #error "Asserts are enabled for MQTT, but IotMqtt_Assert is not defined"
+ #endif
+ #endif
+#else
+ #define IotMqtt_Assert( expression )
+#endif
+
+/* Configure logs for MQTT functions. */
+#ifdef IOT_LOG_LEVEL_MQTT
+ #define LIBRARY_LOG_LEVEL IOT_LOG_LEVEL_MQTT
+#else
+ #ifdef IOT_LOG_LEVEL_GLOBAL
+ #define LIBRARY_LOG_LEVEL IOT_LOG_LEVEL_GLOBAL
+ #else
+ #define LIBRARY_LOG_LEVEL IOT_LOG_NONE
+ #endif
+#endif
+
+#define LIBRARY_LOG_NAME ( "MQTT" )
+#include "iot_logging_setup.h"
+
+/*
+ * Provide default values for undefined memory allocation functions based on
+ * the usage of dynamic memory allocation.
+ */
+#if IOT_STATIC_MEMORY_ONLY == 1
+ #include "iot_static_memory.h"
+
+/**
+ * @brief Allocate an #_mqttConnection_t. This function should have the same
+ * signature as [malloc]
+ * (http://pubs.opengroup.org/onlinepubs/9699919799/functions/malloc.html).
+ */
+ void * IotMqtt_MallocConnection( size_t size );
+
+/**
+ * @brief Free an #_mqttConnection_t. This function should have the same
+ * signature as [free]
+ * (http://pubs.opengroup.org/onlinepubs/9699919799/functions/free.html).
+ */
+ void IotMqtt_FreeConnection( void * ptr );
+
+/**
+ * @brief Allocate memory for an MQTT packet. This function should have the
+ * same signature as [malloc]
+ * (http://pubs.opengroup.org/onlinepubs/9699919799/functions/malloc.html).
+ */
+ #define IotMqtt_MallocMessage Iot_MallocMessageBuffer
+
+/**
+ * @brief Free an MQTT packet. This function should have the same signature
+ * as [free]
+ * (http://pubs.opengroup.org/onlinepubs/9699919799/functions/free.html).
+ */
+ #define IotMqtt_FreeMessage Iot_FreeMessageBuffer
+
+/**
+ * @brief Allocate an #_mqttOperation_t. This function should have the same
+ * signature as [malloc]
+ * (http://pubs.opengroup.org/onlinepubs/9699919799/functions/malloc.html).
+ */
+ void * IotMqtt_MallocOperation( size_t size );
+
+/**
+ * @brief Free an #_mqttOperation_t. This function should have the same
+ * signature as [free]
+ * (http://pubs.opengroup.org/onlinepubs/9699919799/functions/free.html).
+ */
+ void IotMqtt_FreeOperation( void * ptr );
+
+/**
+ * @brief Allocate an #_mqttSubscription_t. This function should have the
+ * same signature as [malloc]
+ * (http://pubs.opengroup.org/onlinepubs/9699919799/functions/malloc.html).
+ */
+ void * IotMqtt_MallocSubscription( size_t size );
+
+/**
+ * @brief Free an #_mqttSubscription_t. This function should have the same
+ * signature as [free]
+ * (http://pubs.opengroup.org/onlinepubs/9699919799/functions/free.html).
+ */
+ void IotMqtt_FreeSubscription( void * ptr );
+#else /* if IOT_STATIC_MEMORY_ONLY == 1 */
+ #ifndef IotMqtt_MallocConnection
+ #ifdef Iot_DefaultMalloc
+ #define IotMqtt_MallocConnection Iot_DefaultMalloc
+ #else
+ #error "No malloc function defined for IotMqtt_MallocConnection"
+ #endif
+ #endif
+
+ #ifndef IotMqtt_FreeConnection
+ #ifdef Iot_DefaultFree
+ #define IotMqtt_FreeConnection Iot_DefaultFree
+ #else
+ #error "No free function defined for IotMqtt_FreeConnection"
+ #endif
+ #endif
+
+ #ifndef IotMqtt_MallocMessage
+ #ifdef Iot_DefaultMalloc
+ #define IotMqtt_MallocMessage Iot_DefaultMalloc
+ #else
+ #error "No malloc function defined for IotMqtt_MallocMessage"
+ #endif
+ #endif
+
+ #ifndef IotMqtt_FreeMessage
+ #ifdef Iot_DefaultFree
+ #define IotMqtt_FreeMessage Iot_DefaultFree
+ #else
+ #error "No free function defined for IotMqtt_FreeMessage"
+ #endif
+ #endif
+
+ #ifndef IotMqtt_MallocOperation
+ #ifdef Iot_DefaultMalloc
+ #define IotMqtt_MallocOperation Iot_DefaultMalloc
+ #else
+ #error "No malloc function defined for IotMqtt_MallocOperation"
+ #endif
+ #endif
+
+ #ifndef IotMqtt_FreeOperation
+ #ifdef Iot_DefaultFree
+ #define IotMqtt_FreeOperation Iot_DefaultFree
+ #else
+ #error "No free function defined for IotMqtt_FreeOperation"
+ #endif
+ #endif
+
+ #ifndef IotMqtt_MallocSubscription
+ #ifdef Iot_DefaultMalloc
+ #define IotMqtt_MallocSubscription Iot_DefaultMalloc
+ #else
+ #error "No malloc function defined for IotMqtt_MallocSubscription"
+ #endif
+ #endif
+
+ #ifndef IotMqtt_FreeSubscription
+ #ifdef Iot_DefaultFree
+ #define IotMqtt_FreeSubscription Iot_DefaultFree
+ #else
+ #error "No free function defined for IotMqtt_FreeSubscription"
+ #endif
+ #endif
+#endif /* if IOT_STATIC_MEMORY_ONLY == 1 */
+
+/**
+ * @cond DOXYGEN_IGNORE
+ * Doxygen should ignore this section.
+ *
+ * Provide default values for undefined configuration constants.
+ */
+#ifndef AWS_IOT_MQTT_ENABLE_METRICS
+ #define AWS_IOT_MQTT_ENABLE_METRICS ( 1 )
+#endif
+#ifndef IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES
+ #define IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES ( 0 )
+#endif
+#ifndef IOT_MQTT_RESPONSE_WAIT_MS
+ #define IOT_MQTT_RESPONSE_WAIT_MS ( 1000 )
+#endif
+#ifndef IOT_MQTT_RETRY_MS_CEILING
+ #define IOT_MQTT_RETRY_MS_CEILING ( 60000 )
+#endif
+/** @endcond */
+
+/**
+ * @brief Marks the empty statement of an `else` branch.
+ *
+ * Does nothing, but allows test coverage to detect branches not taken. By default,
+ * this is defined to nothing. When running code coverage testing, this is defined
+ * to an assembly NOP.
+ */
+#ifndef EMPTY_ELSE_MARKER
+ #define EMPTY_ELSE_MARKER
+#endif
+
+#define MQTT_SERVER_MAX_CLIENTID_LENGTH ( ( uint16_t ) 23 ) /**< @brief Optional maximum length of client identifier specified by MQTT 3.1.1. */
+#define MQTT_SERVER_MAX_PUBLISH_PAYLOAD_LENGTH ( ( size_t ) ( 268435456 ) ) /**< @brief Maximum publish payload length supported by MQTT 3.1.1. */
+#define MQTT_SERVER_MAX_LWT_PAYLOAD_LENGTH ( ( size_t ) UINT16_MAX ) /**< @brief Maximum LWT payload length supported by MQTT 3.1.1. */
+
+/*
+ * Constants related to limits defined in AWS Service Limits.
+ *
+ * For details, see
+ * https://docs.aws.amazon.com/general/latest/gr/aws_service_limits.html
+ *
+ * Used to validate parameters if when connecting to an AWS IoT MQTT server.
+ */
+#define AWS_IOT_MQTT_SERVER_MAX_CLIENTID_LENGTH ( ( uint16_t ) 128 ) /**< @brief Maximum length of client identifier accepted by AWS IoT. */
+#define AWS_IOT_MQTT_SERVER_MAX_TOPIC_LENGTH ( ( uint16_t ) 256 ) /**< @brief Maximum length of topic names or filters accepted by AWS IoT. */
+#define AWS_IOT_MQTT_SERVER_MAX_TOPIC_FILTERS_PER_SUBSCRIBE ( ( size_t ) 8 ) /**< @brief Maximum number of topic filters in a single SUBSCRIBE packet. */
+#define AWS_IOT_MQTT_SERVER_MAX_PUBLISH_PAYLOAD_LENGTH ( ( size_t ) ( 131072 ) ) /**< @brief Maximum publish payload length accepted by AWS IoT. */
+
+/*
+ * MQTT control packet type and flags. Always the first byte of an MQTT
+ * packet.
+ *
+ * For details, see
+ * http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/csprd02/mqtt-v3.1.1-csprd02.html#_Toc385349757
+ */
+#define MQTT_PACKET_TYPE_CONNECT ( ( uint8_t ) 0x10U ) /**< @brief CONNECT (client-to-server). */
+#define MQTT_PACKET_TYPE_CONNACK ( ( uint8_t ) 0x20U ) /**< @brief CONNACK (server-to-client). */
+#define MQTT_PACKET_TYPE_PUBLISH ( ( uint8_t ) 0x30U ) /**< @brief PUBLISH (bi-directional). */
+#define MQTT_PACKET_TYPE_PUBACK ( ( uint8_t ) 0x40U ) /**< @brief PUBACK (server-to-client). */
+#define MQTT_PACKET_TYPE_SUBSCRIBE ( ( uint8_t ) 0x82U ) /**< @brief SUBSCRIBE (client-to-server). */
+#define MQTT_PACKET_TYPE_SUBACK ( ( uint8_t ) 0x90U ) /**< @brief SUBACK (server-to-client). */
+#define MQTT_PACKET_TYPE_UNSUBSCRIBE ( ( uint8_t ) 0xa2U ) /**< @brief UNSUBSCRIBE (client-to-server). */
+#define MQTT_PACKET_TYPE_UNSUBACK ( ( uint8_t ) 0xb0U ) /**< @brief UNSUBACK (server-to-client). */
+#define MQTT_PACKET_TYPE_PINGREQ ( ( uint8_t ) 0xc0U ) /**< @brief PINGREQ (client-to-server). */
+#define MQTT_PACKET_TYPE_PINGRESP ( ( uint8_t ) 0xd0U ) /**< @brief PINGRESP (server-to-client). */
+#define MQTT_PACKET_TYPE_DISCONNECT ( ( uint8_t ) 0xe0U ) /**< @brief DISCONNECT (client-to-server). */
+
+/**
+ * @brief A value that represents an invalid remaining length.
+ *
+ * This value is greater than what is allowed by the MQTT specification.
+ */
+#define MQTT_REMAINING_LENGTH_INVALID ( ( size_t ) 268435456 )
+
+/**
+ * @brief When this flag is passed, MQTT functions will execute jobs on the calling
+ * thread, bypassing the task pool.
+ *
+ * This flag is used along with @ref mqtt_constants_flags, but is intended for internal
+ * use only. Nevertheless, its value must be bitwise exclusive of all conflicting
+ * @ref mqtt_constants_flags.
+ */
+#define MQTT_INTERNAL_FLAG_BLOCK_ON_SEND ( 0x80000000 )
+
+/**
+ * @brief When calling #_IotMqtt_RemoveSubscriptionByPacket, use this value
+ * for `order` to delete all subscriptions for the packet.
+ *
+ * This flag is used along with @ref mqtt_constants_flags, but is intended for internal
+ * use only.
+ *
+ * @ref mqtt_constants_flags.
+ */
+#define MQTT_REMOVE_ALL_SUBSCRIPTIONS ( -1 )
+
+/*---------------------- MQTT internal data structures ----------------------*/
+
+/**
+ * @cond DOXYGEN_IGNORE
+ * Doxygen should ignore this section.
+ *
+ * Forward declaration of MQTT connection type.
+ */
+struct _mqttConnection;
+/** @endcond */
+
+/**
+ * @brief Internal structure representing a single MQTT operation, such as
+ * CONNECT, SUBSCRIBE, PUBLISH, etc.
+ *
+ * Queues of these structures keeps track of all in-progress MQTT operations.
+ */
+typedef struct _mqttOperation
+{
+ /* Pointers to neighboring queue elements. */
+ IotLink_t link; /**< @brief List link member. */
+
+ bool incomingPublish; /**< @brief Set to true if this operation is an incoming PUBLISH. */
+ struct _mqttConnection * pMqttConnection; /**< @brief MQTT connection associated with this operation. */
+
+ IotTaskPoolJobStorage_t jobStorage; /**< @brief Task pool job storage associated with this operation. */
+ IotTaskPoolJob_t job; /**< @brief Task pool job associated with this operation. */
+
+ union
+ {
+ /* If incomingPublish is false, this struct is valid. */
+ struct
+ {
+ /* Basic operation information. */
+ int32_t jobReference; /**< @brief Tracks if a job is using this operation. Must always be 0, 1, or 2. */
+ IotMqttOperationType_t type; /**< @brief What operation this structure represents. */
+ uint32_t flags; /**< @brief Flags passed to the function that created this operation. */
+ uint16_t packetIdentifier; /**< @brief The packet identifier used with this operation. */
+
+ /* Serialized packet and size. */
+ uint8_t * pMqttPacket; /**< @brief The MQTT packet to send over the network. */
+ uint8_t * pPacketIdentifierHigh; /**< @brief The location of the high byte of the packet identifier in the MQTT packet. */
+ size_t packetSize; /**< @brief Size of `pMqttPacket`. */
+
+ /* How to notify of an operation's completion. */
+ union
+ {
+ IotSemaphore_t waitSemaphore; /**< @brief Semaphore to be used with @ref mqtt_function_wait. */
+ IotMqttCallbackInfo_t callback; /**< @brief User-provided callback function and parameter. */
+ } notify; /**< @brief How to notify of this operation's completion. */
+ IotMqttError_t status; /**< @brief Result of this operation. This is reported once a response is received. */
+
+ union
+ {
+ struct
+ {
+ uint32_t count; /**< @brief Current number of retries. */
+ uint32_t limit; /**< @brief Maximum number of retries allowed. */
+ uint32_t nextPeriodMs; /**< @brief Next retry period. */
+ } retry; /**< @brief Additional information for PUBLISH retry. */
+
+ struct
+ {
+ uint32_t failure; /**< @brief Flag tracking keep-alive status. */
+ uint32_t keepAliveMs; /**< @brief Keep-alive interval in milliseconds. Its max value (per spec) is 65,535,000. */
+ uint32_t nextPeriodMs; /**< @brief Relative delay for next keep-alive job. */
+ } ping; /**< @brief Additional information for keep-alive pings. */
+ } periodic; /**< @brief Additional information for periodic operations. */
+ } operation;
+
+ /* If incomingPublish is true, this struct is valid. */
+ struct
+ {
+ IotMqttPublishInfo_t publishInfo; /**< @brief Deserialized PUBLISH. */
+ const void * pReceivedData; /**< @brief Any buffer associated with this PUBLISH that should be freed. */
+ } publish;
+ } u; /**< @brief Valid member depends on _mqttOperation_t.incomingPublish. */
+} _mqttOperation_t;
+
+/**
+ * @brief Represents an MQTT connection.
+ */
+typedef struct _mqttConnection
+{
+ bool awsIotMqttMode; /**< @brief Specifies if this connection is to an AWS IoT MQTT server. */
+ bool ownNetworkConnection; /**< @brief Whether this MQTT connection owns its network connection. */
+ void * pNetworkConnection; /**< @brief References the transport-layer network connection. */
+ const IotNetworkInterface_t * pNetworkInterface; /**< @brief Network interface provided to @ref mqtt_function_connect. */
+ IotMqttCallbackInfo_t disconnectCallback; /**< @brief A function to invoke when this connection is disconnected. */
+
+ const IotMqttSerializer_t * pSerializer; /**< @brief MQTT packet serializer overrides. */
+
+ bool disconnected; /**< @brief Tracks if this connection has been disconnected. */
+ IotMutex_t referencesMutex; /**< @brief Recursive mutex. Grants access to connection state and operation lists. */
+ int32_t references; /**< @brief Counts callbacks and operations using this connection. */
+ IotListDouble_t pendingProcessing; /**< @brief List of operations waiting to be processed by a task pool routine. */
+ IotListDouble_t pendingResponse; /**< @brief List of processed operations awaiting a server response. */
+
+ IotListDouble_t subscriptionList; /**< @brief Holds subscriptions associated with this connection. */
+ IotMutex_t subscriptionMutex; /**< @brief Grants exclusive access to the subscription list. */
+
+ _mqttOperation_t pingreq; /**< @brief Operation used for MQTT keep-alive. */
+} _mqttConnection_t;
+
+/**
+ * @brief Represents a subscription stored in an MQTT connection.
+ */
+typedef struct _mqttSubscription
+{
+ IotLink_t link; /**< @brief List link member. */
+
+ int32_t references; /**< @brief How many subscription callbacks are using this subscription. */
+
+ /**
+ * @brief Tracks whether an unsubscribe function has been called for
+ * this subscription.
+ *
+ * If there are active subscription callbacks, this subscription cannot be removed.
+ * Instead, this flag will be set, which schedules the removal of this subscription
+ * once all subscription callbacks terminate.
+ */
+ bool unsubscribed;
+
+ struct
+ {
+ uint16_t identifier; /**< @brief Packet identifier. */
+ size_t order; /**< @brief Order in the packet's list of subscriptions. */
+ } packetInfo; /**< @brief Information about the SUBSCRIBE packet that registered this subscription. */
+
+ IotMqttCallbackInfo_t callback; /**< @brief Callback information for this subscription. */
+
+ uint16_t topicFilterLength; /**< @brief Length of #_mqttSubscription_t.pTopicFilter. */
+ char pTopicFilter[]; /**< @brief The subscription topic filter. */
+} _mqttSubscription_t;
+
+/**
+ * @brief Represents an MQTT packet received from the network.
+ *
+ * This struct is used to hold parameters for the deserializers so that all
+ * deserializers have the same function signature.
+ */
+typedef struct _mqttPacket
+{
+ union
+ {
+ /**
+ * @brief (Input) MQTT connection associated with this packet. Only used
+ * when deserializing SUBACKs.
+ */
+ _mqttConnection_t * pMqttConnection;
+
+ /**
+ * @brief (Output) Operation representing an incoming PUBLISH. Only used
+ * when deserializing PUBLISHes.
+ */
+ _mqttOperation_t * pIncomingPublish;
+ } u; /**< @brief Valid member depends on packet being decoded. */
+
+ uint8_t * pRemainingData; /**< @brief (Input) The remaining data in MQTT packet. */
+ size_t remainingLength; /**< @brief (Input) Length of the remaining data in the MQTT packet. */
+ uint16_t packetIdentifier; /**< @brief (Output) MQTT packet identifier. */
+ uint8_t type; /**< @brief (Input) A value identifying the packet type. */
+} _mqttPacket_t;
+
+/*-------------------- MQTT struct validation functions ---------------------*/
+
+/**
+ * @brief Check that an #IotMqttConnectInfo_t is valid.
+ *
+ * @param[in] pConnectInfo The #IotMqttConnectInfo_t to validate.
+ *
+ * @return `true` if `pConnectInfo` is valid; `false` otherwise.
+ */
+bool _IotMqtt_ValidateConnect( const IotMqttConnectInfo_t * pConnectInfo );
+
+/**
+ * @brief Check that an #IotMqttPublishInfo_t is valid.
+ *
+ * @param[in] awsIotMqttMode Specifies if this PUBLISH packet is being sent to
+ * an AWS IoT MQTT server.
+ * @param[in] pPublishInfo The #IotMqttPublishInfo_t to validate.
+ *
+ * @return `true` if `pPublishInfo` is valid; `false` otherwise.
+ */
+bool _IotMqtt_ValidatePublish( bool awsIotMqttMode,
+ const IotMqttPublishInfo_t * pPublishInfo );
+
+/**
+ * @brief Check that an #IotMqttPublishInfo_t is valid for an LWT publish
+ *
+ * @param[in] awsIotMqttMode Specifies if this PUBLISH packet is being sent to
+ * an AWS IoT MQTT server.
+ * @param[in] pLwtPublishInfo The #IotMqttPublishInfo_t to validate.
+ *
+ * @return `true` if `pLwtPublishInfo` is valid; `false` otherwise.
+ */
+bool _IotMqtt_ValidateLwtPublish( bool awsIotMqttMode,
+ const IotMqttPublishInfo_t * pLwtPublishInfo );
+
+/**
+ * @brief Check that an #IotMqttOperation_t is valid and waitable.
+ *
+ * @param[in] operation The #IotMqttOperation_t to validate.
+ *
+ * @return `true` if `operation` is valid; `false` otherwise.
+ */
+bool _IotMqtt_ValidateOperation( IotMqttOperation_t operation );
+
+/**
+ * @brief Check that a list of #IotMqttSubscription_t is valid.
+ *
+ * @param[in] operation Either #IOT_MQTT_SUBSCRIBE or #IOT_MQTT_UNSUBSCRIBE.
+ * Some parameters are not validated for #IOT_MQTT_UNSUBSCRIBE.
+ * @param[in] awsIotMqttMode Specifies if this SUBSCRIBE packet is being sent to
+ * an AWS IoT MQTT server.
+ * @param[in] pListStart First element of the list to validate.
+ * @param[in] listSize Number of elements in the subscription list.
+ *
+ * @return `true` if every element in the list is valid; `false` otherwise.
+ */
+bool _IotMqtt_ValidateSubscriptionList( IotMqttOperationType_t operation,
+ bool awsIotMqttMode,
+ const IotMqttSubscription_t * pListStart,
+ size_t listSize );
+
+/*-------------------- MQTT packet serializer functions ---------------------*/
+
+/**
+ * @brief Get the MQTT packet type from a stream of bytes off the network.
+ *
+ * @param[in] pNetworkConnection Reference to the network connection.
+ * @param[in] pNetworkInterface Function pointers used to interact with the
+ * network.
+ *
+ * @return One of the server-to-client MQTT packet types.
+ *
+ * @note This function is only used for incoming packets, and may not work
+ * correctly for outgoing packets.
+ */
+uint8_t _IotMqtt_GetPacketType( void * pNetworkConnection,
+ const IotNetworkInterface_t * pNetworkInterface );
+
+/**
+ * @brief Get the remaining length from a stream of bytes off the network.
+ *
+ * @param[in] pNetworkConnection Reference to the network connection.
+ * @param[in] pNetworkInterface Function pointers used to interact with the
+ * network.
+ *
+ * @return The remaining length; #MQTT_REMAINING_LENGTH_INVALID on error.
+ */
+size_t _IotMqtt_GetRemainingLength( void * pNetworkConnection,
+ const IotNetworkInterface_t * pNetworkInterface );
+
+/**
+ * @brief Get the remaining length from a stream of bytes off the network.
+ *
+ * @param[in] pNetworkConnection Reference to the network connection.
+ * @param[in] getNextByte Function pointer used to interact with the
+ * network to get next byte.
+ *
+ * @return The remaining length; #MQTT_REMAINING_LENGTH_INVALID on error.
+ *
+ * @note This function is similar to _IotMqtt_GetRemainingLength() but it uses
+ * user provided getNextByte function to parse the stream instead of using
+ * _IotMqtt_GetNextByte(). pNetworkConnection is implementation dependent and
+ * user provided function makes use of it.
+ *
+ */
+size_t _IotMqtt_GetRemainingLength_Generic( void * pNetworkConnection,
+ IotMqttGetNextByte_t getNextByte );
+
+/**
+ * @brief Generate a CONNECT packet from the given parameters.
+ *
+ * @param[in] pConnectInfo User-provided CONNECT information.
+ * @param[out] pConnectPacket Where the CONNECT packet is written.
+ * @param[out] pPacketSize Size of the packet written to `pConnectPacket`.
+ *
+ * @return #IOT_MQTT_SUCCESS or #IOT_MQTT_NO_MEMORY.
+ */
+IotMqttError_t _IotMqtt_SerializeConnect( const IotMqttConnectInfo_t * pConnectInfo,
+ uint8_t ** pConnectPacket,
+ size_t * pPacketSize );
+
+/**
+ * @brief Deserialize a CONNACK packet.
+ *
+ * Converts the packet from a stream of bytes to an #IotMqttError_t. Also
+ * prints out debug log messages about the packet.
+ *
+ * @param[in,out] pConnack Pointer to an MQTT packet struct representing a CONNACK.
+ *
+ * @return #IOT_MQTT_SUCCESS if CONNACK specifies that CONNECT was accepted;
+ * #IOT_MQTT_SERVER_REFUSED if CONNACK specifies that CONNECT was rejected;
+ * #IOT_MQTT_BAD_RESPONSE if the CONNACK packet doesn't follow MQTT spec.
+ */
+IotMqttError_t _IotMqtt_DeserializeConnack( _mqttPacket_t * pConnack );
+
+/**
+ * @brief Generate a PUBLISH packet from the given parameters.
+ *
+ * @param[in] pPublishInfo User-provided PUBLISH information.
+ * @param[out] pPublishPacket Where the PUBLISH packet is written.
+ * @param[out] pPacketSize Size of the packet written to `pPublishPacket`.
+ * @param[out] pPacketIdentifier The packet identifier generated for this PUBLISH.
+ * @param[out] pPacketIdentifierHigh Where the high byte of the packet identifier
+ * is written.
+ *
+ * @return #IOT_MQTT_SUCCESS or #IOT_MQTT_NO_MEMORY.
+ */
+IotMqttError_t _IotMqtt_SerializePublish( const IotMqttPublishInfo_t * pPublishInfo,
+ uint8_t ** pPublishPacket,
+ size_t * pPacketSize,
+ uint16_t * pPacketIdentifier,
+ uint8_t ** pPacketIdentifierHigh );
+
+/**
+ * @brief Set the DUP bit in a QoS 1 PUBLISH packet.
+ *
+ * @param[in] pPublishPacket Pointer to the PUBLISH packet to modify.
+ * @param[in] pPacketIdentifierHigh The high byte of any packet identifier to modify.
+ * @param[out] pNewPacketIdentifier Since AWS IoT does not support the DUP flag,
+ * a new packet identifier is generated and should be written here. This parameter
+ * is only used when connected to an AWS IoT MQTT server.
+ *
+ * @note See #IotMqttPublishInfo_t for caveats with retransmission to the
+ * AWS IoT MQTT server.
+ */
+void _IotMqtt_PublishSetDup( uint8_t * pPublishPacket,
+ uint8_t * pPacketIdentifierHigh,
+ uint16_t * pNewPacketIdentifier );
+
+/**
+ * @brief Deserialize a PUBLISH packet received from the server.
+ *
+ * Converts the packet from a stream of bytes to an #IotMqttPublishInfo_t and
+ * extracts the packet identifier. Also prints out debug log messages about the
+ * packet.
+ *
+ * @param[in,out] pPublish Pointer to an MQTT packet struct representing a PUBLISH.
+ *
+ * @return #IOT_MQTT_SUCCESS if PUBLISH is valid; #IOT_MQTT_BAD_RESPONSE
+ * if the PUBLISH packet doesn't follow MQTT spec.
+ */
+IotMqttError_t _IotMqtt_DeserializePublish( _mqttPacket_t * pPublish );
+
+/**
+ * @brief Generate a PUBACK packet for the given packet identifier.
+ *
+ * @param[in] packetIdentifier The packet identifier to place in PUBACK.
+ * @param[out] pPubackPacket Where the PUBACK packet is written.
+ * @param[out] pPacketSize Size of the packet written to `pPubackPacket`.
+ *
+ * @return #IOT_MQTT_SUCCESS or #IOT_MQTT_NO_MEMORY.
+ */
+IotMqttError_t _IotMqtt_SerializePuback( uint16_t packetIdentifier,
+ uint8_t ** pPubackPacket,
+ size_t * pPacketSize );
+
+/**
+ * @brief Deserialize a PUBACK packet.
+ *
+ * Converts the packet from a stream of bytes to an #IotMqttError_t and extracts
+ * the packet identifier. Also prints out debug log messages about the packet.
+ *
+ * @param[in,out] pPuback Pointer to an MQTT packet struct representing a PUBACK.
+ *
+ * @return #IOT_MQTT_SUCCESS if PUBACK is valid; #IOT_MQTT_BAD_RESPONSE
+ * if the PUBACK packet doesn't follow MQTT spec.
+ */
+IotMqttError_t _IotMqtt_DeserializePuback( _mqttPacket_t * pPuback );
+
+/**
+ * @brief Generate a SUBSCRIBE packet from the given parameters.
+ *
+ * @param[in] pSubscriptionList User-provided array of subscriptions.
+ * @param[in] subscriptionCount Size of `pSubscriptionList`.
+ * @param[out] pSubscribePacket Where the SUBSCRIBE packet is written.
+ * @param[out] pPacketSize Size of the packet written to `pSubscribePacket`.
+ * @param[out] pPacketIdentifier The packet identifier generated for this SUBSCRIBE.
+ *
+ * @return #IOT_MQTT_SUCCESS or #IOT_MQTT_NO_MEMORY.
+ */
+IotMqttError_t _IotMqtt_SerializeSubscribe( const IotMqttSubscription_t * pSubscriptionList,
+ size_t subscriptionCount,
+ uint8_t ** pSubscribePacket,
+ size_t * pPacketSize,
+ uint16_t * pPacketIdentifier );
+
+/**
+ * @brief Deserialize a SUBACK packet.
+ *
+ * Converts the packet from a stream of bytes to an #IotMqttError_t and extracts
+ * the packet identifier. Also prints out debug log messages about the packet.
+ *
+ * @param[in,out] pSuback Pointer to an MQTT packet struct representing a SUBACK.
+ *
+ * @return #IOT_MQTT_SUCCESS if SUBACK is valid; #IOT_MQTT_BAD_RESPONSE
+ * if the SUBACK packet doesn't follow MQTT spec.
+ */
+IotMqttError_t _IotMqtt_DeserializeSuback( _mqttPacket_t * pSuback );
+
+/**
+ * @brief Generate an UNSUBSCRIBE packet from the given parameters.
+ *
+ * @param[in] pSubscriptionList User-provided array of subscriptions to remove.
+ * @param[in] subscriptionCount Size of `pSubscriptionList`.
+ * @param[out] pUnsubscribePacket Where the UNSUBSCRIBE packet is written.
+ * @param[out] pPacketSize Size of the packet written to `pUnsubscribePacket`.
+ * @param[out] pPacketIdentifier The packet identifier generated for this UNSUBSCRIBE.
+ *
+ * @return #IOT_MQTT_SUCCESS or #IOT_MQTT_NO_MEMORY.
+ */
+IotMqttError_t _IotMqtt_SerializeUnsubscribe( const IotMqttSubscription_t * pSubscriptionList,
+ size_t subscriptionCount,
+ uint8_t ** pUnsubscribePacket,
+ size_t * pPacketSize,
+ uint16_t * pPacketIdentifier );
+
+/**
+ * @brief Deserialize a UNSUBACK packet.
+ *
+ * Converts the packet from a stream of bytes to an #IotMqttError_t and extracts
+ * the packet identifier. Also prints out debug log messages about the packet.
+ *
+ * @param[in,out] pUnsuback Pointer to an MQTT packet struct representing an UNSUBACK.
+ *
+ * @return #IOT_MQTT_SUCCESS if UNSUBACK is valid; #IOT_MQTT_BAD_RESPONSE
+ * if the UNSUBACK packet doesn't follow MQTT spec.
+ */
+IotMqttError_t _IotMqtt_DeserializeUnsuback( _mqttPacket_t * pUnsuback );
+
+/**
+ * @brief Generate a PINGREQ packet.
+ *
+ * @param[out] pPingreqPacket Where the PINGREQ packet is written.
+ * @param[out] pPacketSize Size of the packet written to `pPingreqPacket`.
+ *
+ * @return Always returns #IOT_MQTT_SUCCESS.
+ */
+IotMqttError_t _IotMqtt_SerializePingreq( uint8_t ** pPingreqPacket,
+ size_t * pPacketSize );
+
+/**
+ * @brief Deserialize a PINGRESP packet.
+ *
+ * Converts the packet from a stream of bytes to an #IotMqttError_t. Also
+ * prints out debug log messages about the packet.
+ *
+ * @param[in,out] pPingresp Pointer to an MQTT packet struct representing a PINGRESP.
+ *
+ * @return #IOT_MQTT_SUCCESS if PINGRESP is valid; #IOT_MQTT_BAD_RESPONSE
+ * if the PINGRESP packet doesn't follow MQTT spec.
+ */
+IotMqttError_t _IotMqtt_DeserializePingresp( _mqttPacket_t * pPingresp );
+
+/**
+ * @brief Generate a DISCONNECT packet.
+ *
+ * @param[out] pDisconnectPacket Where the DISCONNECT packet is written.
+ * @param[out] pPacketSize Size of the packet written to `pDisconnectPacket`.
+ *
+ * @return Always returns #IOT_MQTT_SUCCESS.
+ */
+IotMqttError_t _IotMqtt_SerializeDisconnect( uint8_t ** pDisconnectPacket,
+ size_t * pPacketSize );
+
+/**
+ * @brief Free a packet generated by the serializer.
+ *
+ * @param[in] pPacket The packet to free.
+ */
+void _IotMqtt_FreePacket( uint8_t * pPacket );
+
+/*-------------------- MQTT operation record functions ----------------------*/
+
+/**
+ * @brief Create a record for a new in-progress MQTT operation.
+ *
+ * @param[in] pMqttConnection The MQTT connection to associate with the operation.
+ * @param[in] flags Flags variable passed to a user-facing MQTT function.
+ * @param[in] pCallbackInfo User-provided callback function and parameter.
+ * @param[out] pNewOperation Set to point to the new operation on success.
+ *
+ * @return #IOT_MQTT_SUCCESS, #IOT_MQTT_BAD_PARAMETER, or #IOT_MQTT_NO_MEMORY.
+ */
+IotMqttError_t _IotMqtt_CreateOperation( _mqttConnection_t * pMqttConnection,
+ uint32_t flags,
+ const IotMqttCallbackInfo_t * pCallbackInfo,
+ _mqttOperation_t ** pNewOperation );
+
+/**
+ * @brief Decrement the job reference count of an MQTT operation and optionally
+ * cancel its job.
+ *
+ * Checks if the operation may be destroyed afterwards.
+ *
+ * @param[in] pOperation The MQTT operation with the job to cancel.
+ * @param[in] cancelJob Whether to attempt cancellation of the operation's job.
+ *
+ * @return `true` if the the operation may be safely destroyed; `false` otherwise.
+ */
+bool _IotMqtt_DecrementOperationReferences( _mqttOperation_t * pOperation,
+ bool cancelJob );
+
+/**
+ * @brief Free resources used to record an MQTT operation. This is called when
+ * the operation completes.
+ *
+ * @param[in] pOperation The operation which completed.
+ */
+void _IotMqtt_DestroyOperation( _mqttOperation_t * pOperation );
+
+/**
+ * @brief Task pool routine for processing an MQTT connection's keep-alive.
+ *
+ * @param[in] pTaskPool Pointer to the system task pool.
+ * @param[in] pKeepAliveJob Pointer the an MQTT connection's keep-alive job.
+ * @param[in] pContext Pointer to an MQTT connection, passed as an opaque context.
+ */
+void _IotMqtt_ProcessKeepAlive( IotTaskPool_t pTaskPool,
+ IotTaskPoolJob_t pKeepAliveJob,
+ void * pContext );
+
+/**
+ * @brief Task pool routine for processing an incoming PUBLISH message.
+ *
+ * @param[in] pTaskPool Pointer to the system task pool.
+ * @param[in] pPublishJob Pointer to the incoming PUBLISH operation's job.
+ * @param[in] pContext Pointer to the incoming PUBLISH operation, passed as an
+ * opaque context.
+ */
+void _IotMqtt_ProcessIncomingPublish( IotTaskPool_t pTaskPool,
+ IotTaskPoolJob_t pPublishJob,
+ void * pContext );
+
+/**
+ * @brief Task pool routine for processing an MQTT operation to send.
+ *
+ * @param[in] pTaskPool Pointer to the system task pool.
+ * @param[in] pSendJob Pointer to an operation's job.
+ * @param[in] pContext Pointer to the operation to send, passed as an opaque
+ * context.
+ */
+void _IotMqtt_ProcessSend( IotTaskPool_t pTaskPool,
+ IotTaskPoolJob_t pSendJob,
+ void * pContext );
+
+/**
+ * @brief Task pool routine for processing a completed MQTT operation.
+ *
+ * @param[in] pTaskPool Pointer to the system task pool.
+ * @param[in] pOperationJob Pointer to the completed operation's job.
+ * @param[in] pContext Pointer to the completed operation, passed as an opaque
+ * context.
+ */
+void _IotMqtt_ProcessCompletedOperation( IotTaskPool_t pTaskPool,
+ IotTaskPoolJob_t pOperationJob,
+ void * pContext );
+
+/**
+ * @brief Schedule an operation for immediate processing.
+ *
+ * @param[in] pOperation The operation to schedule.
+ * @param[in] jobRoutine The routine to run for the job. Must be either
+ * #_IotMqtt_ProcessSend, #_IotMqtt_ProcessCompletedOperation, or
+ * #_IotMqtt_ProcessIncomingPublish.
+ * @param[in] delay A delay before the operation job should be executed. Pass
+ * `0` to execute ASAP.
+ *
+ * @return #IOT_MQTT_SUCCESS or #IOT_MQTT_SCHEDULING_ERROR.
+ */
+IotMqttError_t _IotMqtt_ScheduleOperation( _mqttOperation_t * pOperation,
+ IotTaskPoolRoutine_t jobRoutine,
+ uint32_t delay );
+
+/**
+ * @brief Search a list of MQTT operations pending responses using an operation
+ * name and packet identifier. Removes a matching operation from the list if found.
+ *
+ * @param[in] pMqttConnection The connection associated with the operation.
+ * @param[in] type The operation type to look for.
+ * @param[in] pPacketIdentifier A packet identifier to match. Pass `NULL` to ignore.
+ *
+ * @return Pointer to any matching operation; `NULL` if no match was found.
+ */
+_mqttOperation_t * _IotMqtt_FindOperation( _mqttConnection_t * pMqttConnection,
+ IotMqttOperationType_t type,
+ const uint16_t * pPacketIdentifier );
+
+/**
+ * @brief Notify of a completed MQTT operation.
+ *
+ * @param[in] pOperation The MQTT operation which completed.
+ *
+ * Depending on the parameters passed to a user-facing MQTT function, the
+ * notification will cause @ref mqtt_function_wait to return or invoke a
+ * user-provided callback.
+ */
+void _IotMqtt_Notify( _mqttOperation_t * pOperation );
+
+/*----------------- MQTT subscription management functions ------------------*/
+
+/**
+ * @brief Add an array of subscriptions to the subscription manager.
+ *
+ * @param[in] pMqttConnection The MQTT connection associated with the subscriptions.
+ * @param[in] subscribePacketIdentifier Packet identifier for the subscriptions'
+ * SUBSCRIBE packet.
+ * @param[in] pSubscriptionList The first element in the array.
+ * @param[in] subscriptionCount Number of elements in `pSubscriptionList`.
+ *
+ * @return #IOT_MQTT_SUCCESS or #IOT_MQTT_NO_MEMORY.
+ */
+IotMqttError_t _IotMqtt_AddSubscriptions( _mqttConnection_t * pMqttConnection,
+ uint16_t subscribePacketIdentifier,
+ const IotMqttSubscription_t * pSubscriptionList,
+ size_t subscriptionCount );
+
+/**
+ * @brief Process a received PUBLISH from the server, invoking any subscription
+ * callbacks that have a matching topic filter.
+ *
+ * @param[in] pMqttConnection The MQTT connection associated with the received
+ * PUBLISH.
+ * @param[in] pCallbackParam The parameter to pass to a PUBLISH callback.
+ */
+void _IotMqtt_InvokeSubscriptionCallback( _mqttConnection_t * pMqttConnection,
+ IotMqttCallbackParam_t * pCallbackParam );
+
+/**
+ * @brief Remove a single subscription from the subscription manager by
+ * packetIdentifier and order.
+ *
+ * @param[in] pMqttConnection The MQTT connection associated with the subscriptions.
+ * @param[in] packetIdentifier The packet identifier associated with the subscription's
+ * SUBSCRIBE packet.
+ * @param[in] order The order of the subscription in the SUBSCRIBE packet.
+ * Pass #MQTT_REMOVE_ALL_SUBSCRIPTIONS to ignore order and remove all subscriptions for `packetIdentifier`.
+ */
+void _IotMqtt_RemoveSubscriptionByPacket( _mqttConnection_t * pMqttConnection,
+ uint16_t packetIdentifier,
+ int32_t order );
+
+/**
+ * @brief Remove an array of subscriptions from the subscription manager by
+ * topic filter.
+ *
+ * @param[in] pMqttConnection The MQTT connection associated with the subscriptions.
+ * @param[in] pSubscriptionList The first element in the array.
+ * @param[in] subscriptionCount Number of elements in `pSubscriptionList`.
+ */
+void _IotMqtt_RemoveSubscriptionByTopicFilter( _mqttConnection_t * pMqttConnection,
+ const IotMqttSubscription_t * pSubscriptionList,
+ size_t subscriptionCount );
+
+/*------------------ MQTT connection management functions -------------------*/
+
+/**
+ * @brief Attempt to increment the reference count of an MQTT connection.
+ *
+ * @param[in] pMqttConnection The referenced MQTT connection.
+ *
+ * @return `true` if the reference count was incremented; `false` otherwise. The
+ * reference count will not be incremented for a disconnected connection.
+ */
+bool _IotMqtt_IncrementConnectionReferences( _mqttConnection_t * pMqttConnection );
+
+/**
+ * @brief Decrement the reference count of an MQTT connection.
+ *
+ * Also destroys an unreferenced MQTT connection.
+ *
+ * @param[in] pMqttConnection The referenced MQTT connection.
+ */
+void _IotMqtt_DecrementConnectionReferences( _mqttConnection_t * pMqttConnection );
+
+/**
+ * @brief Read the next available byte on a network connection.
+ *
+ * @param[in] pNetworkConnection Reference to the network connection.
+ * @param[in] pNetworkInterface Function pointers used to interact with the
+ * network.
+ * @param[out] pIncomingByte The byte read from the network.
+ *
+ * @return `true` if a byte was successfully received from the network; `false`
+ * otherwise.
+ */
+bool _IotMqtt_GetNextByte( void * pNetworkConnection,
+ const IotNetworkInterface_t * pNetworkInterface,
+ uint8_t * pIncomingByte );
+
+/**
+ * @brief Closes the network connection associated with an MQTT connection.
+ *
+ * A network disconnect function must be set in the network interface for the
+ * network connection to be closed.
+ *
+ * @param[in] disconnectReason A reason to pass to the connection's disconnect
+ * callback.
+ * @param[in] pMqttConnection The MQTT connection with the network connection
+ * to close.
+ */
+void _IotMqtt_CloseNetworkConnection( IotMqttDisconnectReason_t disconnectReason,
+ _mqttConnection_t * pMqttConnection );
+
+#if IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES == 1
+
+/**
+ * @brief Utility macro for creating serializer override selector functions
+ */
+ #define _SERIALIZER_OVERRIDE_SELECTOR( _funcType_t, _funcName, _defaultFunc, _serializerMember ) \
+ static _funcType_t _funcName( const IotMqttSerializer_t * pSerializer ); \
+ static _funcType_t _funcName( const IotMqttSerializer_t * pSerializer ) \
+ { \
+ _funcType_t _returnValue = _defaultFunc; \
+ if( pSerializer != NULL ) \
+ { \
+ if( pSerializer->_serializerMember != NULL ) \
+ { \
+ _returnValue = pSerializer->_serializerMember; \
+ } \
+ else \
+ { \
+ EMPTY_ELSE_MARKER; \
+ } \
+ } \
+ else \
+ { \
+ EMPTY_ELSE_MARKER; \
+ } \
+ return _returnValue; \
+ }
+#endif /* if IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES == 1 */
+
+#endif /* ifndef IOT_MQTT_INTERNAL_H_ */