in source/core_mqtt.c [1461:1581]
static MQTTStatus_t receiveConnack( const MQTTContext_t * pContext,
uint32_t timeoutMs,
bool cleanSession,
MQTTPacketInfo_t * pIncomingPacket,
bool * pSessionPresent )
{
MQTTStatus_t status = MQTTSuccess;
MQTTGetCurrentTimeFunc_t getTimeStamp = NULL;
uint32_t entryTimeMs = 0U, remainingTimeMs = 0U, timeTakenMs = 0U;
bool breakFromLoop = false;
uint16_t loopCount = 0U;
assert( pContext != NULL );
assert( pIncomingPacket != NULL );
assert( pContext->getTime != NULL );
getTimeStamp = pContext->getTime;
/* Get the entry time for the function. */
entryTimeMs = getTimeStamp();
do
{
/* Transport read for incoming CONNACK packet type and length.
* MQTT_GetIncomingPacketTypeAndLength is a blocking call and it is
* returned after a transport receive timeout, an error, or a successful
* receive of packet type and length. */
status = MQTT_GetIncomingPacketTypeAndLength( pContext->transportInterface.recv,
pContext->transportInterface.pNetworkContext,
pIncomingPacket );
/* The loop times out based on 2 conditions.
* 1. If timeoutMs is greater than 0:
* Loop times out based on the timeout calculated by getTime()
* function.
* 2. If timeoutMs is 0:
* Loop times out based on the maximum number of retries config
* MQTT_MAX_CONNACK_RECEIVE_RETRY_COUNT. This config will control
* maximum the number of retry attempts to read the CONNACK packet.
* A value of 0 for the config will try once to read CONNACK. */
if( timeoutMs > 0U )
{
breakFromLoop = ( calculateElapsedTime( getTimeStamp(), entryTimeMs ) >= timeoutMs ) ? true : false;
}
else
{
breakFromLoop = ( loopCount >= MQTT_MAX_CONNACK_RECEIVE_RETRY_COUNT ) ? true : false;
loopCount++;
}
/* Loop until there is data to read or if we have exceeded the timeout/retries. */
} while( ( status == MQTTNoDataAvailable ) && ( breakFromLoop == false ) );
if( status == MQTTSuccess )
{
/* Time taken in this function so far. */
timeTakenMs = calculateElapsedTime( getTimeStamp(), entryTimeMs );
if( timeTakenMs < timeoutMs )
{
/* Calculate remaining time for receiving the remainder of
* the packet. */
remainingTimeMs = timeoutMs - timeTakenMs;
}
/* Reading the remainder of the packet by transport recv.
* Attempt to read once even if the timeout has expired.
* Invoking receivePacket with remainingTime as 0 would attempt to
* recv from network once. If using retries, the remainder of the
* CONNACK packet is tried to be read only once. Reading once would be
* good as the packet type and remaining length was already read. Hence,
* the probability of the remaining 2 bytes available to read is very high. */
if( pIncomingPacket->type == MQTT_PACKET_TYPE_CONNACK )
{
status = receivePacket( pContext,
*pIncomingPacket,
remainingTimeMs );
}
else
{
LogError( ( "Incorrect packet type %X received while expecting"
" CONNACK(%X).",
( unsigned int ) pIncomingPacket->type,
MQTT_PACKET_TYPE_CONNACK ) );
status = MQTTBadResponse;
}
}
if( status == MQTTSuccess )
{
/* Update the packet info pointer to the buffer read. */
pIncomingPacket->pRemainingData = pContext->networkBuffer.pBuffer;
/* Deserialize CONNACK. */
status = MQTT_DeserializeAck( pIncomingPacket, NULL, pSessionPresent );
}
/* If a clean session is requested, a session present should not be set by
* broker. */
if( status == MQTTSuccess )
{
if( ( cleanSession == true ) && ( *pSessionPresent == true ) )
{
LogError( ( "Unexpected session present flag in CONNACK response from broker."
" CONNECT request with clean session was made with broker." ) );
status = MQTTBadResponse;
}
}
if( status == MQTTSuccess )
{
LogDebug( ( "Received MQTT CONNACK successfully from broker." ) );
}
else
{
LogError( ( "CONNACK recv failed with status = %s.",
MQTT_Status_strerror( status ) ) );
}
return status;
}