in source/core_mqtt_state.c [73:288]
static bool validateTransitionPublish( MQTTPublishState_t currentState,
MQTTPublishState_t newState,
MQTTStateOperation_t opType,
MQTTQoS_t qos );
/**
* @brief Test if a transition to a new state is possible, when dealing with acks.
*
* @param[in] currentState The current state.
* @param[in] newState State to transition to.
*
* @return `true` if transition is possible, else `false`.
*/
static bool validateTransitionAck( MQTTPublishState_t currentState,
MQTTPublishState_t newState );
/**
* @brief Test if the publish corresponding to an ack is outgoing or incoming.
*
* @param[in] packetType PUBACK, PUBREC, PUBREL, or PUBCOMP.
* @param[in] opType Send, or Receive.
*
* @return `true` if corresponds to outgoing publish, else `false`.
*/
static bool isPublishOutgoing( MQTTPubAckType_t packetType,
MQTTStateOperation_t opType );
/**
* @brief Find a packet ID in the state record.
*
* @param[in] records State record array.
* @param[in] recordCount Length of record array.
* @param[in] packetId packet ID to search for.
* @param[out] pQos QoS retrieved from record.
* @param[out] pCurrentState state retrieved from record.
*
* @return index of the packet id in the record if it exists, else the record length.
*/
static size_t findInRecord( const MQTTPubAckInfo_t * records,
size_t recordCount,
uint16_t packetId,
MQTTQoS_t * pQos,
MQTTPublishState_t * pCurrentState );
/**
* @brief Compact records.
*
* Records are arranged in the relative order to maintain message ordering.
* This will lead to fragmentation and this function will help in defragmenting
* the records array.
*
* @param[in] records State record array.
* @param[in] recordCount Length of record array.
*/
static void compactRecords( MQTTPubAckInfo_t * records,
size_t recordCount );
/**
* @brief Store a new entry in the state record.
*
* @param[in] records State record array.
* @param[in] recordCount Length of record array.
* @param[in] packetId Packet ID of new entry.
* @param[in] qos QoS of new entry.
* @param[in] publishState State of new entry.
*
* @return #MQTTSuccess, #MQTTNoMemory, or #MQTTStateCollision.
*/
static MQTTStatus_t addRecord( MQTTPubAckInfo_t * records,
size_t recordCount,
uint16_t packetId,
MQTTQoS_t qos,
MQTTPublishState_t publishState );
/**
* @brief Update and possibly delete an entry in the state record.
*
* @param[in] records State record array.
* @param[in] recordIndex index of record to update.
* @param[in] newState New state to update.
* @param[in] shouldDelete Whether an existing entry should be deleted.
*/
static void updateRecord( MQTTPubAckInfo_t * records,
size_t recordIndex,
MQTTPublishState_t newState,
bool shouldDelete );
/**
* @brief Get the packet ID and index of an outgoing publish in specified
* states.
*
* @param[in] pMqttContext Initialized MQTT context.
* @param[in] searchStates The states to search for in 2-byte bit map.
* @param[in,out] pCursor Index at which to start searching.
*
* @return Packet ID of the outgoing publish.
*/
static uint16_t stateSelect( const MQTTContext_t * pMqttContext,
uint16_t searchStates,
MQTTStateCursor_t * pCursor );
/**
* @brief Update the state records for an ACK after state transition
* validations.
*
* @param[in] records State records pointer.
* @param[in] recordIndex Index at which the record is stored.
* @param[in] packetId Packet id of the packet.
* @param[in] currentState Current state of the publish record.
* @param[in] newState New state of the publish.
*
* @return #MQTTIllegalState, or #MQTTSuccess.
*/
static MQTTStatus_t updateStateAck( MQTTPubAckInfo_t * records,
size_t recordIndex,
uint16_t packetId,
MQTTPublishState_t currentState,
MQTTPublishState_t newState );
/**
* @brief Update the state record for a PUBLISH packet after validating
* the state transitions.
*
* @param[in] pMqttContext Initialized MQTT context.
* @param[in] recordIndex Index in state records at which publish record exists.
* @param[in] packetId ID of the PUBLISH packet.
* @param[in] opType Send or Receive.
* @param[in] qos 0, 1, or 2.
* @param[in] currentState Current state of the publish record.
* @param[in] newState New state of the publish record.
*
* @return #MQTTIllegalState, #MQTTStateCollision or #MQTTSuccess.
*/
static MQTTStatus_t updateStatePublish( MQTTContext_t * pMqttContext,
size_t recordIndex,
uint16_t packetId,
MQTTStateOperation_t opType,
MQTTQoS_t qos,
MQTTPublishState_t currentState,
MQTTPublishState_t newState );
/*-----------------------------------------------------------*/
static bool validateTransitionPublish( MQTTPublishState_t currentState,
MQTTPublishState_t newState,
MQTTStateOperation_t opType,
MQTTQoS_t qos )
{
bool isValid = false;
switch( currentState )
{
case MQTTStateNull:
/* Transitions from null occur when storing a new entry into the record. */
if( opType == MQTT_RECEIVE )
{
isValid = ( ( newState == MQTTPubAckSend ) || ( newState == MQTTPubRecSend ) ) ? true : false;
}
break;
case MQTTPublishSend:
/* Outgoing publish. All such publishes start in this state due to
* the reserve operation. */
switch( qos )
{
case MQTTQoS1:
isValid = ( newState == MQTTPubAckPending ) ? true : false;
break;
case MQTTQoS2:
isValid = ( newState == MQTTPubRecPending ) ? true : false;
break;
case MQTTQoS0:
default:
/* QoS 0 is checked before calling this function. */
break;
}
break;
/* Below cases are for validating the resends of publish when a session is
* reestablished. */
case MQTTPubAckPending:
/* When a session is reestablished, outgoing QoS1 publishes in state
* #MQTTPubAckPending can be resent. The state remains the same. */
isValid = ( newState == MQTTPubAckPending ) ? true : false;
break;
case MQTTPubRecPending:
/* When a session is reestablished, outgoing QoS2 publishes in state
* #MQTTPubRecPending can be resent. The state remains the same. */
isValid = ( newState == MQTTPubRecPending ) ? true : false;
break;
case MQTTPubAckSend:
case MQTTPubCompPending:
case MQTTPubCompSend:
case MQTTPubRecSend:
case MQTTPubRelPending:
case MQTTPubRelSend:
case MQTTPublishDone:
default:
/* For a PUBLISH, we should not start from any other state. */
break;
}
return isValid;
}