IoT_Error_t aws_iot_mqtt_set_client_state(AWS_IoT_Client *pClient, ClientState expectedCurrentState,
										  ClientState newState) {
	IoT_Error_t rc;
#ifdef _ENABLE_THREAD_SUPPORT_
	IoT_Error_t threadRc = AWS_FAILURE;
#endif

	FUNC_ENTRY;
	if(NULL == pClient) {
		FUNC_EXIT_RC(NULL_VALUE_ERROR);
	}

#ifdef _ENABLE_THREAD_SUPPORT_
	rc = aws_iot_mqtt_client_lock_mutex(pClient, &(pClient->clientData.state_change_mutex));
	if(AWS_SUCCESS != rc) {
		return rc;
	}
#endif
	if(expectedCurrentState == aws_iot_mqtt_get_client_state(pClient)) {
		pClient->clientStatus.clientState = newState;
		rc = AWS_SUCCESS;
	} else {
		rc = MQTT_UNEXPECTED_CLIENT_STATE_ERROR;
	}

#ifdef _ENABLE_THREAD_SUPPORT_
	threadRc = aws_iot_mqtt_client_unlock_mutex(pClient, &(pClient->clientData.state_change_mutex));
	if(AWS_SUCCESS == rc && AWS_SUCCESS != threadRc) {
		rc = threadRc;
	}
#endif

	FUNC_EXIT_RC(rc);
}
IoT_Error_t aws_iot_mqtt_internal_send_packet(AWS_IoT_Client *pClient, size_t length, Timer *pTimer) {

	size_t sentLen, sent;
	IoT_Error_t rc;

	FUNC_ENTRY;

	if(NULL == pClient || NULL == pTimer) {
		FUNC_EXIT_RC(NULL_VALUE_ERROR);
	}

	if(length >= pClient->clientData.writeBufSize) {
		FUNC_EXIT_RC(MQTT_TX_BUFFER_TOO_SHORT_ERROR);
	}

#ifdef _ENABLE_THREAD_SUPPORT_
	rc = aws_iot_mqtt_client_lock_mutex(pClient, &(pClient->clientData.tls_write_mutex));
	if(SUCCESS != rc) {
		FUNC_EXIT_RC(rc);
	}
#endif

	sentLen = 0;
	sent = 0;

	while(sent < length && !has_timer_expired(pTimer)) {
		rc = pClient->networkStack.write(&(pClient->networkStack), &pClient->clientData.writeBuf[sent], length, pTimer,
										 &sentLen);
		if(SUCCESS != rc) {
			/* there was an error writing the data */
			break;
		}
		sent += sentLen;
	}

#ifdef _ENABLE_THREAD_SUPPORT_
	rc = aws_iot_mqtt_client_unlock_mutex(pClient, &(pClient->clientData.tls_write_mutex));
	if(SUCCESS != rc) {
		FUNC_EXIT_RC(rc);
	}
#endif

	if(sent == length) {
		/* record the fact that we have successfully sent the packet */
		//countdown_sec(&c->pingTimer, c->clientData.keepAliveInterval);
		FUNC_EXIT_RC(SUCCESS);
	}

	FUNC_EXIT_RC(FAILURE);
}
IoT_Error_t aws_iot_mqtt_internal_cycle_read(AWS_IoT_Client *pClient, Timer *pTimer, uint8_t *pPacketType) {
	IoT_Error_t rc;

#ifdef _ENABLE_THREAD_SUPPORT_
	IoT_Error_t threadRc;
#endif

	if(NULL == pClient || NULL == pTimer) {
		return NULL_VALUE_ERROR;
	}

#ifdef _ENABLE_THREAD_SUPPORT_
	threadRc = aws_iot_mqtt_client_lock_mutex(pClient, &(pClient->clientData.tls_read_mutex));
	if(SUCCESS != threadRc) {
		FUNC_EXIT_RC(threadRc);
	}
#endif

	/* read the socket, see what work is due */
	rc = _aws_iot_mqtt_internal_read_packet(pClient, pTimer, pPacketType);

#ifdef _ENABLE_THREAD_SUPPORT_
	threadRc = aws_iot_mqtt_client_unlock_mutex(pClient, &(pClient->clientData.tls_read_mutex));
	if(SUCCESS != threadRc && (MQTT_NOTHING_TO_READ == rc || SUCCESS == rc)) {
		return threadRc;
	}
#endif

	if(MQTT_NOTHING_TO_READ == rc) {
		/* Nothing to read, not a cycle failure */
		return SUCCESS;
	} else if(SUCCESS != rc) {
		return rc;
	}

	switch(*pPacketType) {
		case CONNACK:
		case PUBACK:
		case SUBACK:
		case UNSUBACK:
			/* SDK is blocking, these responses will be forwarded to calling function to process */
			break;
		case PUBLISH: {
			rc = _aws_iot_mqtt_internal_handle_publish(pClient, pTimer);
			break;
		}
		case PUBREC:
		case PUBCOMP:
			/* QoS2 not supported at this time */
			break;
		case PINGRESP: {
			pClient->clientStatus.isPingOutstanding = 0;
			countdown_sec(&pClient->pingTimer, pClient->clientData.keepAliveInterval);
			break;
		}
		default: {
			/* Either unknown packet type or Failure occurred
             * Should not happen */
			rc = MQTT_RX_MESSAGE_PACKET_TYPE_INVALID_ERROR;
			break;
		}
	}

	return rc;
}