/* G:9 - Yield, disconnected, Auto-reconnect timed-out */
TEST_C(YieldTests, disconnectAutoReconnectTimeout) {
	IoT_Error_t rc = FAILURE;

	IOT_DEBUG("-->Running Yield Tests - G:9 - Yield, disconnected, Auto-reconnect timed-out \n");

	rc = aws_iot_mqtt_autoreconnect_set_status(&iotClient, true);
	CHECK_EQUAL_C_INT(SUCCESS, rc);

	CHECK_EQUAL_C_INT(true, aws_iot_mqtt_is_client_connected(&iotClient));
	CHECK_EQUAL_C_INT(true, aws_iot_is_autoreconnect_enabled(&iotClient));

	ResetTLSBuffer();

	/* Sleep for half keep alive interval to allow the first ping to be sent out */
	sleep(iotClient.clientData.keepAliveInterval / (uint32_t)2);
	rc = aws_iot_mqtt_yield(&iotClient, 100);
	CHECK_EQUAL_C_INT(SUCCESS, rc);
	CHECK_EQUAL_C_INT(true, isLastTLSTxMessagePingreq());

	/* Let ping request time out and call yield */
	sleep(iotClient.clientData.keepAliveInterval / (uint32_t)2 + 1);
	rc = aws_iot_mqtt_yield(&iotClient, 100);
	CHECK_EQUAL_C_INT(NETWORK_ATTEMPTING_RECONNECT, rc);
	CHECK_EQUAL_C_INT(0, aws_iot_mqtt_is_client_connected(&iotClient));
	CHECK_EQUAL_C_INT(true, dcHandlerInvoked);

	IOT_DEBUG("-->Success - G:9 - Yield, disconnected, Auto-reconnect timed-out \n");
}
/* G:6 - Yield, network disconnected, ping timeout, auto-reconnect disabled */
TEST_C(YieldTests, disconnectNoAutoReconnect) {
	IoT_Error_t rc = FAILURE;

	IOT_DEBUG("-->Running Yield Tests - G:6 - Yield, network disconnected, ping timeout, auto-reconnect disabled \n");

	rc = aws_iot_mqtt_autoreconnect_set_status(&iotClient, true);
	CHECK_EQUAL_C_INT(SUCCESS, rc);

	CHECK_EQUAL_C_INT(true, aws_iot_mqtt_is_client_connected(&iotClient));
	CHECK_EQUAL_C_INT(true, aws_iot_is_autoreconnect_enabled(&iotClient));

	/* Disable Autoreconnect, then let ping request time out and call yield */
	aws_iot_mqtt_autoreconnect_set_status(&iotClient, false);
	sleep((uint16_t)(iotClient.clientData.keepAliveInterval / 2));

	ResetTLSBuffer();

	/* Sleep for half keep alive interval to allow the first ping to be sent out */
	sleep(iotClient.clientData.keepAliveInterval / (uint32_t)2);
	rc = aws_iot_mqtt_yield(&iotClient, 100);
	CHECK_EQUAL_C_INT(SUCCESS, rc);
	CHECK_EQUAL_C_INT(true, isLastTLSTxMessagePingreq());

	/* Let ping request time out and call yield */
	sleep(iotClient.clientData.keepAliveInterval / (uint32_t)2 + 1);
	rc = aws_iot_mqtt_yield(&iotClient, 100);
	CHECK_EQUAL_C_INT(NETWORK_DISCONNECTED_ERROR, rc);
	CHECK_EQUAL_C_INT(1, isLastTLSTxMessageDisconnect());
	CHECK_EQUAL_C_INT(0, aws_iot_mqtt_is_client_connected(&iotClient));
	CHECK_EQUAL_C_INT(true, dcHandlerInvoked);

	IOT_DEBUG("-->Success - G:6 - Yield, network disconnected, ping timeout, auto-reconnect disabled \n");
}
/**
 * @brief MQTT Manual Re-Connection Function
 *
 * Called to establish an MQTT connection with the AWS IoT Service
 * using parameters from the last time a connection was attempted
 * Use after disconnect to start the reconnect process manually
 * Makes only one reconnect attempt. Sets the client state to
 * pending reconnect in case of failure
 *
 * @param pClient Reference to the IoT Client
 *
 * @return An IoT Error Type defining successful/failed connection
 */
IoT_Error_t aws_iot_mqtt_attempt_reconnect(AWS_IoT_Client *pClient) {
	IoT_Error_t rc;

	FUNC_ENTRY;

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

	if(aws_iot_mqtt_is_client_connected(pClient)) {
		FUNC_EXIT_RC(NETWORK_ALREADY_CONNECTED_ERROR);
	}

	/* Ignoring return code. failures expected if network is disconnected */
	rc = aws_iot_mqtt_connect(pClient, NULL);

	/* If still disconnected handle disconnect */
	if(CLIENT_STATE_CONNECTED_IDLE != aws_iot_mqtt_get_client_state(pClient)) {
		aws_iot_mqtt_set_client_state(pClient, CLIENT_STATE_DISCONNECTED_ERROR, CLIENT_STATE_PENDING_RECONNECT);
		FUNC_EXIT_RC(NETWORK_ATTEMPTING_RECONNECT);
	}

	rc = aws_iot_mqtt_resubscribe(pClient);
	if(SUCCESS != rc) {
		FUNC_EXIT_RC(rc);
	}

	FUNC_EXIT_RC(NETWORK_RECONNECTED);
}
/**
 * @brief Disconnect an MQTT Connection
 *
 * Called to send a disconnect message to the broker.
 * This is the outer function which does the validations and calls the internal disconnect above
 * to perform the actual operation. It is also responsible for client state changes
 *
 * @param pClient Reference to the IoT Client
 *
 * @return An IoT Error Type defining successful/failed send of the disconnect control packet.
 */
IoT_Error_t aws_iot_mqtt_disconnect(AWS_IoT_Client *pClient) {
	ClientState clientState;
	IoT_Error_t rc;

	FUNC_ENTRY;

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

	clientState = aws_iot_mqtt_get_client_state(pClient);
	if(!aws_iot_mqtt_is_client_connected(pClient)) {
		/* Network is already disconnected. Do nothing */
		FUNC_EXIT_RC(NETWORK_DISCONNECTED_ERROR);
	}

	rc = aws_iot_mqtt_set_client_state(pClient, clientState, CLIENT_STATE_DISCONNECTING);
	if(SUCCESS != rc) {
		FUNC_EXIT_RC(rc);
	}

	rc = _aws_iot_mqtt_internal_disconnect(pClient);

	if(SUCCESS != rc) {
		pClient->clientStatus.clientState = clientState;
	} else {
		/* If called from Keepalive, this gets set to CLIENT_STATE_DISCONNECTED_ERROR */
		pClient->clientStatus.clientState = CLIENT_STATE_DISCONNECTED_MANUALLY;
	}

	FUNC_EXIT_RC(rc);
}
/**
 * @brief Subscribe to an MQTT topic.
 *
 * Called to send a subscribe message to the broker requesting a subscription
 * to an MQTT topic.
 * This is the outer function which does the validations and calls the internal resubscribe above
 * to perform the actual operation. It is also responsible for client state changes
 * @note Call is blocking.  The call returns after the receipt of the SUBACK control packet.
 *
 * @param pClient Reference to the IoT Client
 *
 * @return An IoT Error Type defining successful/failed subscription
 */
IoT_Error_t aws_iot_mqtt_resubscribe(AWS_IoT_Client *pClient) {
	IoT_Error_t rc, resubRc;

	FUNC_ENTRY;

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

	if(false == aws_iot_mqtt_is_client_connected(pClient)) {
		FUNC_EXIT_RC(NETWORK_DISCONNECTED_ERROR);
	}

	if(CLIENT_STATE_CONNECTED_IDLE != aws_iot_mqtt_get_client_state(pClient)) {
		FUNC_EXIT_RC(MQTT_CLIENT_NOT_IDLE_ERROR);
	}

	rc = aws_iot_mqtt_set_client_state(pClient, CLIENT_STATE_CONNECTED_IDLE,
									   CLIENT_STATE_CONNECTED_RESUBSCRIBE_IN_PROGRESS);
	if(AWS_SUCCESS != rc) {
		FUNC_EXIT_RC(rc);
	}

	resubRc = _aws_iot_mqtt_internal_resubscribe(pClient);

	rc = aws_iot_mqtt_set_client_state(pClient, CLIENT_STATE_CONNECTED_RESUBSCRIBE_IN_PROGRESS,
									   CLIENT_STATE_CONNECTED_IDLE);
	if(AWS_SUCCESS == resubRc && AWS_SUCCESS != rc) {
		resubRc = rc;
	}

	FUNC_EXIT_RC(resubRc);
}
/**
 * @brief Subscribe to an MQTT topic.
 *
 * Called to send a subscribe message to the broker requesting a subscription
 * to an MQTT topic. This is the outer function which does the validations and
 * calls the internal subscribe above to perform the actual operation.
 * It is also responsible for client state changes
 * @note Call is blocking.  The call returns after the receipt of the SUBACK control packet.
 *
 * @param pClient Reference to the IoT Client
 * @param pTopicName Topic Name to publish to
 * @param topicNameLen Length of the topic name
 * @param pApplicationHandler_t Reference to the handler function for this subscription
 *
 * @return An IoT Error Type defining successful/failed subscription
 */
IoT_Error_t aws_iot_mqtt_subscribe(AWS_IoT_Client *pClient, const char *pTopicName, uint16_t topicNameLen,
								   QoS qos, pApplicationHandler_t pApplicationHandler, void *pApplicationHandlerData) {
	ClientState clientState;
	IoT_Error_t rc, subRc;

	FUNC_ENTRY;

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

	if(!aws_iot_mqtt_is_client_connected(pClient)) {
		FUNC_EXIT_RC(NETWORK_DISCONNECTED_ERROR);
	}

	clientState = aws_iot_mqtt_get_client_state(pClient);
	if(CLIENT_STATE_CONNECTED_IDLE != clientState && CLIENT_STATE_CONNECTED_WAIT_FOR_CB_RETURN != clientState) {
		FUNC_EXIT_RC(MQTT_CLIENT_NOT_IDLE_ERROR);
	}

	rc = aws_iot_mqtt_set_client_state(pClient, clientState, CLIENT_STATE_CONNECTED_SUBSCRIBE_IN_PROGRESS);
	if(AWS_SUCCESS != rc) {
		FUNC_EXIT_RC(rc);
	}

	subRc = _aws_iot_mqtt_internal_subscribe(pClient, pTopicName, topicNameLen, qos,
											 pApplicationHandler, pApplicationHandlerData);

	rc = aws_iot_mqtt_set_client_state(pClient, CLIENT_STATE_CONNECTED_SUBSCRIBE_IN_PROGRESS, clientState);
	if(AWS_SUCCESS == subRc && AWS_SUCCESS != rc) {
		subRc = rc;
	}

	FUNC_EXIT_RC(subRc);
}
/* G:11 - Yield, disconnected, Manual reconnect */
TEST_C(YieldTests, disconnectManualAutoReconnect) {
	IoT_Error_t rc = FAILURE;
	unsigned char *currPayload = NULL;

	IOT_DEBUG("-->Running Yield Tests - G:11 - Yield, disconnected, Manual reconnect \n");

	CHECK_C(aws_iot_mqtt_is_client_connected(&iotClient));

	/* Disable Autoreconnect, then let ping request time out and call yield */
	aws_iot_mqtt_autoreconnect_set_status(&iotClient, false);
	CHECK_C(!aws_iot_is_autoreconnect_enabled(&iotClient));

	/* Sleep for half keep alive interval to allow the first ping to be sent out */
	sleep(iotClient.clientData.keepAliveInterval / (uint32_t)2);
	rc = aws_iot_mqtt_yield(&iotClient, 100);
	CHECK_EQUAL_C_INT(SUCCESS, rc);
	CHECK_EQUAL_C_INT(true, isLastTLSTxMessagePingreq());

	/* Let ping request time out and call yield */
	sleep(iotClient.clientData.keepAliveInterval / (uint32_t)2 + 1);
	rc = aws_iot_mqtt_yield(&iotClient, 100);
	CHECK_EQUAL_C_INT(NETWORK_DISCONNECTED_ERROR, rc);
	CHECK_EQUAL_C_INT(1, isLastTLSTxMessageDisconnect());
	CHECK_C(!aws_iot_mqtt_is_client_connected(&iotClient));
	CHECK_EQUAL_C_INT(true, dcHandlerInvoked);

	dcHandlerInvoked = false;
	setTLSRxBufferForConnack(&connectParams, 0, 0);
	rc = aws_iot_mqtt_attempt_reconnect(&iotClient);
	CHECK_EQUAL_C_INT(NETWORK_RECONNECTED, rc);

	currPayload = connectTxBufferHeaderParser(&prfrdParams, TxBuffer.pBuffer);
	CHECK_C(true == isConnectTxBufFlagCorrect(&connectParams, &prfrdParams));
	CHECK_C(true == isConnectTxBufPayloadCorrect(&connectParams, currPayload));
	CHECK_C(aws_iot_mqtt_is_client_connected(&iotClient));
	CHECK_EQUAL_C_INT(false, dcHandlerInvoked);

	IOT_DEBUG("-->Success - G:11 - Yield, disconnected, Manual reconnect \n");
}
/* G:10 - Yield, disconnected, Auto-reconnect successful */
TEST_C(YieldTests, disconnectAutoReconnectSuccess) {
	IoT_Error_t rc = FAILURE;
	unsigned char *currPayload = NULL;

	IOT_DEBUG("-->Running Yield Tests - G:10 - Yield, disconnected, Auto-reconnect successful \n");

	rc = aws_iot_mqtt_autoreconnect_set_status(&iotClient, true);
	CHECK_EQUAL_C_INT(SUCCESS, rc);

	CHECK_EQUAL_C_INT(true, aws_iot_mqtt_is_client_connected(&iotClient));
	CHECK_EQUAL_C_INT(true, aws_iot_is_autoreconnect_enabled(&iotClient));

	/* Sleep for half keep alive interval to allow the first ping to be sent out */
	sleep(iotClient.clientData.keepAliveInterval / (uint32_t)2);
	rc = aws_iot_mqtt_yield(&iotClient, 100);
	CHECK_EQUAL_C_INT(SUCCESS, rc);
	CHECK_EQUAL_C_INT(true, isLastTLSTxMessagePingreq());

	/* Let ping request time out and call yield */
	sleep(iotClient.clientData.keepAliveInterval / (uint32_t)2 + 1);
	rc = aws_iot_mqtt_yield(&iotClient, 100);
	CHECK_EQUAL_C_INT(NETWORK_ATTEMPTING_RECONNECT, rc);

	sleep(2); /* Default min reconnect delay is 1 sec */
	printf("\nWakeup");
	setTLSRxBufferForConnack(&connectParams, 0, 0);
	rc = aws_iot_mqtt_yield(&iotClient, 100);
	CHECK_EQUAL_C_INT(SUCCESS, rc);

	currPayload = connectTxBufferHeaderParser(&prfrdParams, TxBuffer.pBuffer);
	CHECK_C(true == isConnectTxBufFlagCorrect(&connectParams, &prfrdParams));
	CHECK_C(true == isConnectTxBufPayloadCorrect(&connectParams, currPayload));
	CHECK_EQUAL_C_INT(true, aws_iot_mqtt_is_client_connected(&iotClient));
	CHECK_EQUAL_C_INT(true, dcHandlerInvoked);

	IOT_DEBUG("-->Success - G:10 - Yield, disconnected, Auto-reconnect successful \n");
}
Exemple #9
0
/* F:4 - Disconnect attempt, not connected */
TEST_C(DisconnectTests, disconnectNotConnected) {
	IoT_Error_t rc = SUCCESS;

	IOT_DEBUG("-->Running Disconnect Tests - F:4 - Disconnect attempt, not connected \n");

	/* First make sure client is disconnected */
	rc = aws_iot_mqtt_disconnect(&iotClient);

	/* Check client is disconnected */
	CHECK_EQUAL_C_INT(false, aws_iot_mqtt_is_client_connected(&iotClient));

	/* Now call disconnect again */
	rc = aws_iot_mqtt_disconnect(&iotClient);
	CHECK_EQUAL_C_INT(NETWORK_DISCONNECTED_ERROR, rc);

	IOT_DEBUG("-->Success - F:4 - Disconnect attempt, not connected \n");
}
Exemple #10
0
/* F:7 - Disconnect, with set handler and invoked on disconnect */
TEST_C(DisconnectTests, SetHandlerAndInvokedOnDisconnect) {
	bool connected = false;
	bool currentAutoReconnectStatus = false;
	int i;
	int j;
	int attempt = 3;
	uint32_t dcCount = 0;
	IoT_Error_t rc = SUCCESS;
	IOT_DEBUG("-->Running Disconnect Tests - F:7 - Disconnect, with set handler and invoked on disconnect \n");

	handlerInvoked = false;
	InitMQTTParamsSetup(&initParams, "localhost", AWS_IOT_MQTT_PORT, false, NULL);
	rc = aws_iot_mqtt_init(&iotClient, &initParams);
	CHECK_EQUAL_C_INT(SUCCESS, rc);

	ConnectMQTTParamsSetup(&connectParams, AWS_IOT_MQTT_CLIENT_ID, (uint16_t) strlen(AWS_IOT_MQTT_CLIENT_ID));
	connectParams.keepAliveIntervalInSec = 5;
	setTLSRxBufferForConnack(&connectParams, 0, 0);
	rc = aws_iot_mqtt_connect(&iotClient, &connectParams);
	CHECK_EQUAL_C_INT(SUCCESS, rc);

	aws_iot_mqtt_set_disconnect_handler(&iotClient, disconnectTestHandler, NULL);
	aws_iot_mqtt_autoreconnect_set_status(&iotClient, true);

	IOT_DEBUG("Current Keep Alive Interval is set to %d sec.\n", connectParams.keepAliveIntervalInSec);
	currentAutoReconnectStatus = aws_iot_is_autoreconnect_enabled(&iotClient);

	connected = aws_iot_mqtt_is_client_connected(&iotClient);
	CHECK_EQUAL_C_INT(1, connected);

	aws_iot_mqtt_autoreconnect_set_status(&iotClient, false);

	// 3 cycles of keep alive time expiring
	// verify a ping request is sent and give a ping response
	for(i = 0; i < attempt; i++) {
		/* Set TLS buffer for ping response */
		ResetTLSBuffer();
		setTLSRxBufferForPingresp();
		for(j = 0; j <= connectParams.keepAliveIntervalInSec; j++) {
			sleep(1);
			rc = aws_iot_mqtt_yield(&iotClient, 100);
			CHECK_EQUAL_C_INT(SUCCESS, rc);
		}
		CHECK_EQUAL_C_INT(1, isLastTLSTxMessagePingreq());
	}
	ResetTLSBuffer();

	// keepalive() waits for 1/2 of keepalive time after sending ping request
	// to receive a pingresponse before determining the connection is not alive
	// wait for keepalive time and then yield()
	sleep(connectParams.keepAliveIntervalInSec);
	rc = aws_iot_mqtt_yield(&iotClient, 100);
	CHECK_EQUAL_C_INT(NETWORK_DISCONNECTED_ERROR, rc);
	CHECK_EQUAL_C_INT(1, isLastTLSTxMessageDisconnect());

	connected = aws_iot_mqtt_is_client_connected(&iotClient);
	CHECK_EQUAL_C_INT(0, connected);

	CHECK_EQUAL_C_INT(true, handlerInvoked);

	dcCount = aws_iot_mqtt_get_network_disconnected_count(&iotClient);
	CHECK_C(1 == dcCount);

	aws_iot_mqtt_reset_network_disconnected_count(&iotClient);

	dcCount = aws_iot_mqtt_get_network_disconnected_count(&iotClient);
	CHECK_C(0 == dcCount);

	ResetTLSBuffer();
	aws_iot_mqtt_autoreconnect_set_status(&iotClient, currentAutoReconnectStatus);

	IOT_DEBUG("-->Success - F:7 - Disconnect, with set handler and invoked on disconnect \n");
}
/* G:12 - Yield, resubscribe to all topics on reconnect */
TEST_C(YieldTests, resubscribeSuccessfulReconnect) {
	IoT_Error_t rc = FAILURE;
	char cPayload[100];
	bool connected = false;
	bool autoReconnectEnabled = false;
	char expectedCallbackString[100];

	IOT_DEBUG("-->Running Yield Tests - G:12 - Yield, resubscribe to all topics on reconnect \n");

	rc = aws_iot_mqtt_autoreconnect_set_status(&iotClient, true);
	CHECK_EQUAL_C_INT(SUCCESS, rc);

	snprintf(CallbackMsgString, 100, "NOT_VISITED");

	testPubMsgParams.qos = QOS1;
	testPubMsgParams.isRetained = 0;
	snprintf(cPayload, 100, "%s : %d ", "hello from SDK", 0);
	testPubMsgParams.payload = (void *) cPayload;
	testPubMsgParams.payloadLen = strlen(cPayload);

	connected = aws_iot_mqtt_is_client_connected(&iotClient);
	CHECK_EQUAL_C_INT(1, connected);

	ResetTLSBuffer();

	/* Subscribe to a topic */
	setTLSRxBufferForSuback(subTopic, subTopicLen, QOS1, testPubMsgParams);
	rc = aws_iot_mqtt_subscribe(&iotClient, subTopic, subTopicLen, QOS0, iot_tests_unit_acr_subscribe_callback_handler,
								NULL);
	CHECK_EQUAL_C_INT(SUCCESS, rc);

	ResetTLSBuffer();

	/* Check subscribe */
	snprintf(expectedCallbackString, 100, "Message for %s", subTopic);
	setTLSRxBufferWithMsgOnSubscribedTopic(subTopic, subTopicLen, QOS1, testPubMsgParams, expectedCallbackString);
	rc = aws_iot_mqtt_yield(&iotClient, 100);
	CHECK_EQUAL_C_INT(SUCCESS, rc);
	CHECK_EQUAL_C_STRING(expectedCallbackString, CallbackMsgString);

	ResetTLSBuffer();

	autoReconnectEnabled = aws_iot_is_autoreconnect_enabled(&iotClient);
	CHECK_EQUAL_C_INT(1, autoReconnectEnabled);

	/* Sleep for half keep alive interval to allow the first ping to be sent out */
	sleep(iotClient.clientData.keepAliveInterval / (uint32_t)2);
	rc = aws_iot_mqtt_yield(&iotClient, 100);
	CHECK_EQUAL_C_INT(SUCCESS, rc);
	CHECK_EQUAL_C_INT(true, isLastTLSTxMessagePingreq());

	/* Let ping request time out and call yield */
	sleep(iotClient.clientData.keepAliveInterval / (uint32_t)2 + 1);
	rc = aws_iot_mqtt_yield(&iotClient, 100);
	CHECK_EQUAL_C_INT(NETWORK_ATTEMPTING_RECONNECT, rc);

	sleep(2); /* Default min reconnect delay is 1 sec */

	ResetTLSBuffer();
	setTLSRxBufferForConnackAndSuback(&connectParams, 0, subTopic, subTopicLen, QOS1);

	rc = aws_iot_mqtt_yield(&iotClient, 100);
	CHECK_EQUAL_C_INT(SUCCESS, rc);

	/* Test if reconnect worked */
	connected = aws_iot_mqtt_is_client_connected(&iotClient);
	CHECK_EQUAL_C_INT(true, connected);

	ResetTLSBuffer();

	/* Check subscribe */
	snprintf(expectedCallbackString, 100, "Message for %s after resub", subTopic);
	setTLSRxBufferWithMsgOnSubscribedTopic(subTopic, subTopicLen, QOS1, testPubMsgParams, expectedCallbackString);
	rc = aws_iot_mqtt_yield(&iotClient, 100);
	CHECK_EQUAL_C_INT(SUCCESS, rc);
	CHECK_EQUAL_C_STRING(expectedCallbackString, CallbackMsgString);
	CHECK_EQUAL_C_INT(true, dcHandlerInvoked);

	IOT_DEBUG("-->Success - G:12 - Yield, resubscribe to all topics on reconnect \n");
}