+++ /dev/null
-/*\r
- * Amazon FreeRTOS MQTT V2.0.0\r
- * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.\r
- *\r
- * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
- * this software and associated documentation files (the "Software"), to deal in\r
- * the Software without restriction, including without limitation the rights to\r
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
- * the Software, and to permit persons to whom the Software is furnished to do so,\r
- * subject to the following conditions:\r
- *\r
- * The above copyright notice and this permission notice shall be included in all\r
- * copies or substantial portions of the Software.\r
- *\r
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
- *\r
- * http://aws.amazon.com/freertos\r
- * http://www.FreeRTOS.org\r
- */\r
-\r
-/**\r
- * @file iot_mqtt_network.c\r
- * @brief Implements functions involving transport layer connections.\r
- */\r
-\r
-/* The config header is always included first. */\r
-#include "iot_config.h"\r
-\r
-/* Standard includes. */\r
-#include <string.h>\r
-\r
-/* Error handling include. */\r
-#include "private/iot_error.h"\r
-\r
-/* MQTT internal include. */\r
-#include "private/iot_mqtt_internal.h"\r
-\r
-/* Platform layer includes. */\r
-#include "platform/iot_threads.h"\r
-\r
-/* Atomics include. */\r
-#include "iot_atomic.h"\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-/**\r
- * @brief Check if an incoming packet type is valid.\r
- *\r
- * @param[in] packetType The packet type to check.\r
- *\r
- * @return `true` if the packet type is valid; `false` otherwise.\r
- */\r
-static bool _incomingPacketValid( uint8_t packetType );\r
-\r
-/**\r
- * @brief Get an incoming MQTT packet from the network.\r
- *\r
- * @param[in] pNetworkConnection Network connection to use for receive, which\r
- * may be different from the network connection associated with the MQTT connection.\r
- * @param[in] pMqttConnection The associated MQTT connection.\r
- * @param[out] pIncomingPacket Output parameter for the incoming packet.\r
- *\r
- * @return #IOT_MQTT_SUCCESS, #IOT_MQTT_NO_MEMORY or #IOT_MQTT_BAD_RESPONSE.\r
- */\r
-static IotMqttError_t _getIncomingPacket( void * pNetworkConnection,\r
- const _mqttConnection_t * pMqttConnection,\r
- _mqttPacket_t * pIncomingPacket );\r
-\r
-/**\r
- * @brief Deserialize a packet received from the network.\r
- *\r
- * @param[in] pMqttConnection The associated MQTT connection.\r
- * @param[in] pIncomingPacket The packet received from the network.\r
- *\r
- * @return #IOT_MQTT_SUCCESS, #IOT_MQTT_NO_MEMORY, #IOT_MQTT_NETWORK_ERROR,\r
- * #IOT_MQTT_SCHEDULING_ERROR, #IOT_MQTT_BAD_RESPONSE, or #IOT_MQTT_SERVER_REFUSED.\r
- */\r
-static IotMqttError_t _deserializeIncomingPacket( _mqttConnection_t * pMqttConnection,\r
- _mqttPacket_t * pIncomingPacket );\r
-\r
-/**\r
- * @brief Send a PUBACK for a received QoS 1 PUBLISH packet.\r
- *\r
- * @param[in] pMqttConnection Which connection the PUBACK should be sent over.\r
- * @param[in] packetIdentifier Which packet identifier to include in PUBACK.\r
- */\r
-static void _sendPuback( _mqttConnection_t * pMqttConnection,\r
- uint16_t packetIdentifier );\r
-\r
-/**\r
- * @brief Flush a packet from the stream of incoming data.\r
- *\r
- * This function is called when memory for a packet cannot be allocated. The\r
- * packet is flushed from the stream of incoming data so that the next packet\r
- * may be read.\r
- *\r
- * @param[in] pNetworkConnection Network connection to use for receive, which\r
- * may be different from the network connection associated with the MQTT connection.\r
- * @param[in] pMqttConnection The associated MQTT connection.\r
- * @param[in] length The length of the packet to flush.\r
- */\r
-static void _flushPacket( void * pNetworkConnection,\r
- const _mqttConnection_t * pMqttConnection,\r
- size_t length );\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-static bool _incomingPacketValid( uint8_t packetType )\r
-{\r
- bool status = true;\r
-\r
- /* Check packet type. Mask out lower bits to ignore flags. */\r
- switch( packetType & 0xf0 )\r
- {\r
- /* Valid incoming packet types. */\r
- case MQTT_PACKET_TYPE_CONNACK:\r
- case MQTT_PACKET_TYPE_PUBLISH:\r
- case MQTT_PACKET_TYPE_PUBACK:\r
- case MQTT_PACKET_TYPE_SUBACK:\r
- case MQTT_PACKET_TYPE_UNSUBACK:\r
- case MQTT_PACKET_TYPE_PINGRESP:\r
- break;\r
-\r
- /* Any other packet type is invalid. */\r
- default:\r
- status = false;\r
- break;\r
- }\r
-\r
- return status;\r
-}\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-static IotMqttError_t _getIncomingPacket( void * pNetworkConnection,\r
- const _mqttConnection_t * pMqttConnection,\r
- _mqttPacket_t * pIncomingPacket )\r
-{\r
- IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS );\r
- size_t dataBytesRead = 0;\r
-\r
- /* Default functions for retrieving packet type and length. */\r
- uint8_t ( * getPacketType )( void *,\r
- const IotNetworkInterface_t * ) = _IotMqtt_GetPacketType;\r
- size_t ( * getRemainingLength )( void *,\r
- const IotNetworkInterface_t * ) = _IotMqtt_GetRemainingLength;\r
-\r
- /* No buffer for remaining data should be allocated. */\r
- IotMqtt_Assert( pIncomingPacket->pRemainingData == NULL );\r
- IotMqtt_Assert( pIncomingPacket->remainingLength == 0 );\r
-\r
- /* Choose packet type and length functions. */\r
- #if IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES == 1\r
- if( pMqttConnection->pSerializer != NULL )\r
- {\r
- if( pMqttConnection->pSerializer->getPacketType != NULL )\r
- {\r
- getPacketType = pMqttConnection->pSerializer->getPacketType;\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
-\r
- if( pMqttConnection->pSerializer->getRemainingLength != NULL )\r
- {\r
- getRemainingLength = pMqttConnection->pSerializer->getRemainingLength;\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
- #endif /* if IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES == 1 */\r
-\r
- /* Read the packet type, which is the first byte available. */\r
- pIncomingPacket->type = getPacketType( pNetworkConnection,\r
- pMqttConnection->pNetworkInterface );\r
-\r
- /* Check that the incoming packet type is valid. */\r
- if( _incomingPacketValid( pIncomingPacket->type ) == false )\r
- {\r
- IotLogError( "(MQTT connection %p) Unknown packet type %02x received.",\r
- pMqttConnection,\r
- pIncomingPacket->type );\r
-\r
- IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
-\r
- /* Read the remaining length. */\r
- pIncomingPacket->remainingLength = getRemainingLength( pNetworkConnection,\r
- pMqttConnection->pNetworkInterface );\r
-\r
- if( pIncomingPacket->remainingLength == MQTT_REMAINING_LENGTH_INVALID )\r
- {\r
- IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
-\r
- /* Allocate a buffer for the remaining data and read the data. */\r
- if( pIncomingPacket->remainingLength > 0 )\r
- {\r
- pIncomingPacket->pRemainingData = IotMqtt_MallocMessage( pIncomingPacket->remainingLength );\r
-\r
- if( pIncomingPacket->pRemainingData == NULL )\r
- {\r
- IotLogError( "(MQTT connection %p) Failed to allocate buffer of length "\r
- "%lu for incoming packet type %lu.",\r
- pMqttConnection,\r
- ( unsigned long ) pIncomingPacket->remainingLength,\r
- ( unsigned long ) pIncomingPacket->type );\r
-\r
- _flushPacket( pNetworkConnection, pMqttConnection, pIncomingPacket->remainingLength );\r
-\r
- IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_NO_MEMORY );\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
-\r
- dataBytesRead = pMqttConnection->pNetworkInterface->receive( pNetworkConnection,\r
- pIncomingPacket->pRemainingData,\r
- pIncomingPacket->remainingLength );\r
-\r
- if( dataBytesRead != pIncomingPacket->remainingLength )\r
- {\r
- IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE );\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
-\r
- /* Clean up on error. */\r
- IOT_FUNCTION_CLEANUP_BEGIN();\r
-\r
- if( status != IOT_MQTT_SUCCESS )\r
- {\r
- if( pIncomingPacket->pRemainingData != NULL )\r
- {\r
- IotMqtt_FreeMessage( pIncomingPacket->pRemainingData );\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
-\r
- IOT_FUNCTION_CLEANUP_END();\r
-}\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-static IotMqttError_t _deserializeIncomingPacket( _mqttConnection_t * pMqttConnection,\r
- _mqttPacket_t * pIncomingPacket )\r
-{\r
- IotMqttError_t status = IOT_MQTT_STATUS_PENDING;\r
- _mqttOperation_t * pOperation = NULL;\r
-\r
- /* Deserializer function. */\r
- IotMqttError_t ( * deserialize )( _mqttPacket_t * ) = NULL;\r
-\r
- /* A buffer for remaining data must be allocated if remaining length is not 0. */\r
- IotMqtt_Assert( ( pIncomingPacket->remainingLength > 0 ) ==\r
- ( pIncomingPacket->pRemainingData != NULL ) );\r
-\r
- /* Only valid packets should be given to this function. */\r
- IotMqtt_Assert( _incomingPacketValid( pIncomingPacket->type ) == true );\r
-\r
- /* Mask out the low bits of packet type to ignore flags. */\r
- switch( ( pIncomingPacket->type & 0xf0 ) )\r
- {\r
- case MQTT_PACKET_TYPE_CONNACK:\r
- IotLogDebug( "(MQTT connection %p) CONNACK in data stream.", pMqttConnection );\r
-\r
- /* Choose CONNACK deserializer. */\r
- deserialize = _IotMqtt_DeserializeConnack;\r
-\r
- #if IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES == 1\r
- if( pMqttConnection->pSerializer != NULL )\r
- {\r
- if( pMqttConnection->pSerializer->deserialize.connack != NULL )\r
- {\r
- deserialize = pMqttConnection->pSerializer->deserialize.connack;\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
- #endif /* if IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES == 1 */\r
-\r
- /* Deserialize CONNACK and notify of result. */\r
- status = deserialize( pIncomingPacket );\r
- pOperation = _IotMqtt_FindOperation( pMqttConnection,\r
- IOT_MQTT_CONNECT,\r
- NULL );\r
-\r
- if( pOperation != NULL )\r
- {\r
- pOperation->u.operation.status = status;\r
- _IotMqtt_Notify( pOperation );\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
-\r
- break;\r
-\r
- case MQTT_PACKET_TYPE_PUBLISH:\r
- IotLogDebug( "(MQTT connection %p) PUBLISH in data stream.", pMqttConnection );\r
-\r
- /* Allocate memory to handle the incoming PUBLISH. */\r
- pOperation = IotMqtt_MallocOperation( sizeof( _mqttOperation_t ) );\r
-\r
- if( pOperation == NULL )\r
- {\r
- IotLogWarn( "Failed to allocate memory for incoming PUBLISH." );\r
- status = IOT_MQTT_NO_MEMORY;\r
-\r
- break;\r
- }\r
- else\r
- {\r
- /* Set the members of the incoming PUBLISH operation. */\r
- ( void ) memset( pOperation, 0x00, sizeof( _mqttOperation_t ) );\r
- pOperation->incomingPublish = true;\r
- pOperation->pMqttConnection = pMqttConnection;\r
- pIncomingPacket->u.pIncomingPublish = pOperation;\r
- }\r
-\r
- /* Choose a PUBLISH deserializer. */\r
- deserialize = _IotMqtt_DeserializePublish;\r
-\r
- #if IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES == 1\r
- if( pMqttConnection->pSerializer != NULL )\r
- {\r
- if( pMqttConnection->pSerializer->deserialize.publish != NULL )\r
- {\r
- deserialize = pMqttConnection->pSerializer->deserialize.publish;\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
- #endif /* if IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES == 1 */\r
-\r
- /* Deserialize incoming PUBLISH. */\r
- status = deserialize( pIncomingPacket );\r
-\r
- if( status == IOT_MQTT_SUCCESS )\r
- {\r
- /* Send a PUBACK for QoS 1 PUBLISH. */\r
- if( pOperation->u.publish.publishInfo.qos == IOT_MQTT_QOS_1 )\r
- {\r
- _sendPuback( pMqttConnection, pIncomingPacket->packetIdentifier );\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
-\r
- /* Transfer ownership of the received MQTT packet to the PUBLISH operation. */\r
- pOperation->u.publish.pReceivedData = pIncomingPacket->pRemainingData;\r
- pIncomingPacket->pRemainingData = NULL;\r
-\r
- /* Add the PUBLISH to the list of operations pending processing. */\r
- IotMutex_Lock( &( pMqttConnection->referencesMutex ) );\r
- IotListDouble_InsertHead( &( pMqttConnection->pendingProcessing ),\r
- &( pOperation->link ) );\r
- IotMutex_Unlock( &( pMqttConnection->referencesMutex ) );\r
-\r
- /* Increment the MQTT connection reference count before scheduling an\r
- * incoming PUBLISH. */\r
- if( _IotMqtt_IncrementConnectionReferences( pMqttConnection ) == true )\r
- {\r
- /* Schedule PUBLISH for callback invocation. */\r
- status = _IotMqtt_ScheduleOperation( pOperation, _IotMqtt_ProcessIncomingPublish, 0 );\r
- }\r
- else\r
- {\r
- status = IOT_MQTT_NETWORK_ERROR;\r
- }\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
-\r
- /* Free PUBLISH operation on error. */\r
- if( status != IOT_MQTT_SUCCESS )\r
- {\r
- /* Check ownership of the received MQTT packet. */\r
- if( pOperation->u.publish.pReceivedData != NULL )\r
- {\r
- /* Retrieve the pointer MQTT packet pointer so it may be freed later. */\r
- IotMqtt_Assert( pIncomingPacket->pRemainingData == NULL );\r
- pIncomingPacket->pRemainingData = ( uint8_t * ) pOperation->u.publish.pReceivedData;\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
-\r
- /* Remove operation from pending processing list. */\r
- IotMutex_Lock( &( pMqttConnection->referencesMutex ) );\r
-\r
- if( IotLink_IsLinked( &( pOperation->link ) ) == true )\r
- {\r
- IotListDouble_Remove( &( pOperation->link ) );\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
-\r
- IotMutex_Unlock( &( pMqttConnection->referencesMutex ) );\r
-\r
- IotMqtt_Assert( pOperation != NULL );\r
- IotMqtt_FreeOperation( pOperation );\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
-\r
- break;\r
-\r
- case MQTT_PACKET_TYPE_PUBACK:\r
- IotLogDebug( "(MQTT connection %p) PUBACK in data stream.", pMqttConnection );\r
-\r
- /* Choose PUBACK deserializer. */\r
- deserialize = _IotMqtt_DeserializePuback;\r
-\r
- #if IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES == 1\r
- if( pMqttConnection->pSerializer != NULL )\r
- {\r
- if( pMqttConnection->pSerializer->deserialize.puback != NULL )\r
- {\r
- deserialize = pMqttConnection->pSerializer->deserialize.puback;\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
- #endif /* if IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES == 1 */\r
-\r
- /* Deserialize PUBACK and notify of result. */\r
- status = deserialize( pIncomingPacket );\r
- pOperation = _IotMqtt_FindOperation( pMqttConnection,\r
- IOT_MQTT_PUBLISH_TO_SERVER,\r
- &( pIncomingPacket->packetIdentifier ) );\r
-\r
- if( pOperation != NULL )\r
- {\r
- pOperation->u.operation.status = status;\r
- _IotMqtt_Notify( pOperation );\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
-\r
- break;\r
-\r
- case MQTT_PACKET_TYPE_SUBACK:\r
- IotLogDebug( "(MQTT connection %p) SUBACK in data stream.", pMqttConnection );\r
-\r
- /* Choose SUBACK deserializer. */\r
- deserialize = _IotMqtt_DeserializeSuback;\r
-\r
- #if IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES == 1\r
- if( pMqttConnection->pSerializer != NULL )\r
- {\r
- if( pMqttConnection->pSerializer->deserialize.suback != NULL )\r
- {\r
- deserialize = pMqttConnection->pSerializer->deserialize.suback;\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
- #endif /* if IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES == 1 */\r
-\r
- /* Deserialize SUBACK and notify of result. */\r
- pIncomingPacket->u.pMqttConnection = pMqttConnection;\r
- status = deserialize( pIncomingPacket );\r
- pOperation = _IotMqtt_FindOperation( pMqttConnection,\r
- IOT_MQTT_SUBSCRIBE,\r
- &( pIncomingPacket->packetIdentifier ) );\r
-\r
- if( pOperation != NULL )\r
- {\r
- pOperation->u.operation.status = status;\r
- _IotMqtt_Notify( pOperation );\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
-\r
- break;\r
-\r
- case MQTT_PACKET_TYPE_UNSUBACK:\r
- IotLogDebug( "(MQTT connection %p) UNSUBACK in data stream.", pMqttConnection );\r
-\r
- /* Choose UNSUBACK deserializer. */\r
- deserialize = _IotMqtt_DeserializeUnsuback;\r
-\r
- #if IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES == 1\r
- if( pMqttConnection->pSerializer != NULL )\r
- {\r
- if( pMqttConnection->pSerializer->deserialize.unsuback != NULL )\r
- {\r
- deserialize = pMqttConnection->pSerializer->deserialize.unsuback;\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
- #endif /* if IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES == 1 */\r
-\r
- /* Deserialize UNSUBACK and notify of result. */\r
- status = deserialize( pIncomingPacket );\r
- pOperation = _IotMqtt_FindOperation( pMqttConnection,\r
- IOT_MQTT_UNSUBSCRIBE,\r
- &( pIncomingPacket->packetIdentifier ) );\r
-\r
- if( pOperation != NULL )\r
- {\r
- pOperation->u.operation.status = status;\r
- _IotMqtt_Notify( pOperation );\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
-\r
- break;\r
-\r
- default:\r
- /* The only remaining valid type is PINGRESP. */\r
- IotMqtt_Assert( ( pIncomingPacket->type & 0xf0 ) == MQTT_PACKET_TYPE_PINGRESP );\r
- IotLogDebug( "(MQTT connection %p) PINGRESP in data stream.", pMqttConnection );\r
-\r
- /* Choose PINGRESP deserializer. */\r
- deserialize = _IotMqtt_DeserializePingresp;\r
-\r
- #if IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES == 1\r
- if( pMqttConnection->pSerializer != NULL )\r
- {\r
- if( pMqttConnection->pSerializer->deserialize.pingresp != NULL )\r
- {\r
- deserialize = pMqttConnection->pSerializer->deserialize.pingresp;\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
- #endif /* if IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES == 1 */\r
-\r
- /* Deserialize PINGRESP. */\r
- status = deserialize( pIncomingPacket );\r
-\r
- if( status == IOT_MQTT_SUCCESS )\r
- {\r
- if( Atomic_CompareAndSwap_u32( &( pMqttConnection->pingreq.u.operation.periodic.ping.failure ),\r
- 0,\r
- 1 ) == 1 )\r
- {\r
- IotLogDebug( "(MQTT connection %p) PINGRESP successfully parsed.",\r
- pMqttConnection );\r
- }\r
- else\r
- {\r
- IotLogWarn( "(MQTT connection %p) Unexpected PINGRESP received.",\r
- pMqttConnection );\r
- }\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
-\r
- break;\r
- }\r
-\r
- if( status != IOT_MQTT_SUCCESS )\r
- {\r
- IotLogError( "(MQTT connection %p) Packet parser status %s.",\r
- pMqttConnection,\r
- IotMqtt_strerror( status ) );\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
-\r
- return status;\r
-}\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-static void _sendPuback( _mqttConnection_t * pMqttConnection,\r
- uint16_t packetIdentifier )\r
-{\r
- IotMqttError_t status = IOT_MQTT_STATUS_PENDING;\r
- _mqttOperation_t * pPubackOperation = NULL;\r
-\r
- /* Default PUBACK serializer function. */\r
- IotMqttError_t ( * serializePuback )( uint16_t,\r
- uint8_t **,\r
- size_t * ) = _IotMqtt_SerializePuback;\r
-\r
- IotLogDebug( "(MQTT connection %p) Sending PUBACK for received PUBLISH %hu.",\r
- pMqttConnection,\r
- packetIdentifier );\r
-\r
- /* Choose PUBACK serializer and free packet functions. */\r
- #if IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES == 1\r
- if( pMqttConnection->pSerializer != NULL )\r
- {\r
- if( pMqttConnection->pSerializer->serialize.puback != NULL )\r
- {\r
- serializePuback = pMqttConnection->pSerializer->serialize.puback;\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
- #endif /* if IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES == 1 */\r
-\r
- /* Create a PUBACK operation. */\r
- status = _IotMqtt_CreateOperation( pMqttConnection,\r
- 0,\r
- NULL,\r
- &pPubackOperation );\r
-\r
- if( status != IOT_MQTT_SUCCESS )\r
- {\r
- IOT_GOTO_CLEANUP();\r
- }\r
-\r
- /* Set the operation type. */\r
- pPubackOperation->u.operation.type = IOT_MQTT_PUBACK;\r
-\r
- /* Generate a PUBACK packet from the packet identifier. */\r
- status = serializePuback( packetIdentifier,\r
- &( pPubackOperation->u.operation.pMqttPacket ),\r
- &( pPubackOperation->u.operation.packetSize ) );\r
-\r
- if( status != IOT_MQTT_SUCCESS )\r
- {\r
- IOT_GOTO_CLEANUP();\r
- }\r
-\r
- /* Add the PUBACK operation to the send queue for network transmission. */\r
- status = _IotMqtt_ScheduleOperation( pPubackOperation,\r
- _IotMqtt_ProcessSend,\r
- 0 );\r
-\r
- if( status != IOT_MQTT_SUCCESS )\r
- {\r
- IotLogError( "(MQTT connection %p) Failed to enqueue PUBACK for sending.",\r
- pMqttConnection );\r
-\r
- IOT_GOTO_CLEANUP();\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
-\r
- /* Clean up on error. */\r
- IOT_FUNCTION_CLEANUP_BEGIN();\r
-\r
- if( status != IOT_MQTT_SUCCESS )\r
- {\r
- if( pPubackOperation != NULL )\r
- {\r
- _IotMqtt_DestroyOperation( pPubackOperation );\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
-}\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-static void _flushPacket( void * pNetworkConnection,\r
- const _mqttConnection_t * pMqttConnection,\r
- size_t length )\r
-{\r
- size_t bytesFlushed = 0;\r
- uint8_t receivedByte = 0;\r
-\r
- for( bytesFlushed = 0; bytesFlushed < length; bytesFlushed++ )\r
- {\r
- ( void ) _IotMqtt_GetNextByte( pNetworkConnection,\r
- pMqttConnection->pNetworkInterface,\r
- &receivedByte );\r
- }\r
-}\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-bool _IotMqtt_GetNextByte( void * pNetworkConnection,\r
- const IotNetworkInterface_t * pNetworkInterface,\r
- uint8_t * pIncomingByte )\r
-{\r
- bool status = false;\r
- uint8_t incomingByte = 0;\r
- size_t bytesReceived = 0;\r
-\r
- /* Attempt to read 1 byte. */\r
- bytesReceived = pNetworkInterface->receive( pNetworkConnection,\r
- &incomingByte,\r
- 1 );\r
-\r
- /* Set the output parameter and return success if 1 byte was read. */\r
- if( bytesReceived == 1 )\r
- {\r
- *pIncomingByte = incomingByte;\r
- status = true;\r
- }\r
- else\r
- {\r
- /* Network receive must return 0 on failure. */\r
- IotMqtt_Assert( bytesReceived == 0 );\r
- }\r
-\r
- return status;\r
-}\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-void _IotMqtt_CloseNetworkConnection( IotMqttDisconnectReason_t disconnectReason,\r
- _mqttConnection_t * pMqttConnection )\r
-{\r
- IotTaskPoolError_t taskPoolStatus = IOT_TASKPOOL_SUCCESS;\r
- IotNetworkError_t closeStatus = IOT_NETWORK_SUCCESS;\r
- IotMqttCallbackParam_t callbackParam = { .u.message = { 0 } };\r
- void * pNetworkConnection = NULL, * pDisconnectCallbackContext = NULL;\r
-\r
- /* Disconnect callback function. */\r
- void ( * disconnectCallback )( void *,\r
- IotMqttCallbackParam_t * ) = NULL;\r
-\r
- /* Network close function. */\r
- IotNetworkError_t ( * closeConnection) ( void * ) = NULL;\r
-\r
- /* Default free packet function. */\r
- void ( * freePacket )( uint8_t * ) = _IotMqtt_FreePacket;\r
-\r
- /* Mark the MQTT connection as disconnected and the keep-alive as failed. */\r
- IotMutex_Lock( &( pMqttConnection->referencesMutex ) );\r
- pMqttConnection->disconnected = true;\r
-\r
- if( pMqttConnection->pingreq.u.operation.periodic.ping.keepAliveMs != 0 )\r
- {\r
- /* Keep-alive must have a PINGREQ allocated. */\r
- IotMqtt_Assert( pMqttConnection->pingreq.u.operation.pMqttPacket != NULL );\r
- IotMqtt_Assert( pMqttConnection->pingreq.u.operation.packetSize != 0 );\r
-\r
- /* PINGREQ provides a reference to the connection, so reference count must\r
- * be nonzero. */\r
- IotMqtt_Assert( pMqttConnection->references > 0 );\r
-\r
- /* Attempt to cancel the keep-alive job. */\r
- taskPoolStatus = IotTaskPool_TryCancel( IOT_SYSTEM_TASKPOOL,\r
- pMqttConnection->pingreq.job,\r
- NULL );\r
-\r
- /* If the keep-alive job was not canceled, it must be already executing.\r
- * Any other return value is invalid. */\r
- IotMqtt_Assert( ( taskPoolStatus == IOT_TASKPOOL_SUCCESS ) ||\r
- ( taskPoolStatus == IOT_TASKPOOL_CANCEL_FAILED ) );\r
-\r
- /* Clean up keep-alive if its job was successfully canceled. Otherwise,\r
- * the executing keep-alive job will clean up itself. */\r
- if( taskPoolStatus == IOT_TASKPOOL_SUCCESS )\r
- {\r
- /* Choose a function to free the packet. */\r
- #if IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES == 1\r
- if( pMqttConnection->pSerializer != NULL )\r
- {\r
- if( pMqttConnection->pSerializer->freePacket != NULL )\r
- {\r
- freePacket = pMqttConnection->pSerializer->freePacket;\r
- }\r
- }\r
- #endif\r
-\r
- freePacket( pMqttConnection->pingreq.u.operation.pMqttPacket );\r
-\r
- /* Clear data about the keep-alive. */\r
- pMqttConnection->pingreq.u.operation.periodic.ping.keepAliveMs = 0;\r
- pMqttConnection->pingreq.u.operation.pMqttPacket = NULL;\r
- pMqttConnection->pingreq.u.operation.packetSize = 0;\r
-\r
- /* Keep-alive is cleaned up; decrement reference count. Since this\r
- * function must be followed with a call to DISCONNECT, a check to\r
- * destroy the connection is not done here. */\r
- pMqttConnection->references--;\r
-\r
- IotLogDebug( "(MQTT connection %p) Keep-alive job canceled and cleaned up.",\r
- pMqttConnection );\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
-\r
- /* Copy the function pointers and contexts, as the MQTT connection may be\r
- * modified after the mutex is released. */\r
- disconnectCallback = pMqttConnection->disconnectCallback.function;\r
- pDisconnectCallbackContext = pMqttConnection->disconnectCallback.pCallbackContext;\r
-\r
- closeConnection = pMqttConnection->pNetworkInterface->close;\r
- pNetworkConnection = pMqttConnection->pNetworkConnection;\r
-\r
- IotMutex_Unlock( &( pMqttConnection->referencesMutex ) );\r
-\r
- /* Close the network connection. */\r
- if( closeConnection != NULL )\r
- {\r
- closeStatus = closeConnection( pNetworkConnection );\r
-\r
- if( closeStatus == IOT_NETWORK_SUCCESS )\r
- {\r
- IotLogInfo( "(MQTT connection %p) Network connection closed.", pMqttConnection );\r
- }\r
- else\r
- {\r
- IotLogWarn( "(MQTT connection %p) Failed to close network connection, error %d.",\r
- pMqttConnection,\r
- closeStatus );\r
- }\r
- }\r
- else\r
- {\r
- IotLogWarn( "(MQTT connection %p) No network close function was set. Network connection"\r
- " not closed.", pMqttConnection );\r
- }\r
-\r
- /* Invoke the disconnect callback. */\r
- if( disconnectCallback != NULL )\r
- {\r
- /* Set the members of the callback parameter. */\r
- callbackParam.mqttConnection = pMqttConnection;\r
- callbackParam.u.disconnectReason = disconnectReason;\r
-\r
- disconnectCallback( pDisconnectCallbackContext,\r
- &callbackParam );\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
-}\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-void IotMqtt_ReceiveCallback( void * pNetworkConnection,\r
- void * pReceiveContext )\r
-{\r
- IotMqttError_t status = IOT_MQTT_SUCCESS;\r
- _mqttPacket_t incomingPacket = { .u.pMqttConnection = NULL };\r
-\r
- /* Cast context to correct type. */\r
- _mqttConnection_t * pMqttConnection = ( _mqttConnection_t * ) pReceiveContext;\r
-\r
- /* Read an MQTT packet from the network. */\r
- status = _getIncomingPacket( pNetworkConnection,\r
- pMqttConnection,\r
- &incomingPacket );\r
-\r
- if( status == IOT_MQTT_SUCCESS )\r
- {\r
- /* Deserialize the received packet. */\r
- status = _deserializeIncomingPacket( pMqttConnection,\r
- &incomingPacket );\r
-\r
- /* Free any buffers allocated for the MQTT packet. */\r
- if( incomingPacket.pRemainingData != NULL )\r
- {\r
- IotMqtt_FreeMessage( incomingPacket.pRemainingData );\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
-\r
- /* Close the network connection on a bad response. */\r
- if( status == IOT_MQTT_BAD_RESPONSE )\r
- {\r
- IotLogError( "(MQTT connection %p) Error processing incoming data. Closing connection.",\r
- pMqttConnection );\r
-\r
- _IotMqtt_CloseNetworkConnection( IOT_MQTT_BAD_PACKET_RECEIVED,\r
- pMqttConnection );\r
- }\r
- else\r
- {\r
- EMPTY_ELSE_MARKER;\r
- }\r
-}\r
-\r
-/*-----------------------------------------------------------*/\r