/* 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"); }
/* 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"); }
/* 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"); }