// Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. #ifdef __cplusplus #include #include #include #else #include #include #include #include #include "umock_c/umock_c.h" #endif #ifdef AZIOT_LINUX #include #include #include #include #include #include #endif #include "testrunnerswitcher.h" #include "iothub.h" #include "iothub_device_client.h" #include "iothub_module_client.h" #include "iothub_device_client_ll.h" #include "iothub_module_client_ll.h" #include "iothub_client_options.h" #include "iothub_message.h" #include "iothub_messaging.h" #include "iothub_account.h" #include "iothubtest.h" #include "azure_c_shared_utility/buffer_.h" #include "azure_c_shared_utility/threadapi.h" #include "azure_c_shared_utility/shared_util_options.h" #include "azure_c_shared_utility/xlogging.h" #include "azure_c_shared_utility/lock.h" #include "azure_c_shared_utility/random.h" #ifdef SET_TRUSTED_CERT_IN_SAMPLES #include "certs.h" #endif // SET_TRUSTED_CERT_IN_SAMPLES #include "iothubclient_common_e2e.h" static bool g_callbackRecv = false; static TEST_PROTOCOL_TYPE test_protocol_type; const char* TEST_EVENT_DATA_FMT = "{\"data\":\"%.24s\",\"id\":\"%d\"}"; const char* TEST_EVENT_DATA_FMT_SPECIAL_CHAR = "{\"#data\":\"$%.24s\",\";id\":\"*%d\"}"; const char* TEST_EVENT_DATA_FMT_LONG = "{\"data\":\"*.s\",\"id\":\"%d\"}"; #define MSG_UNIQUE_ID_STAMP_LEN 5 const char MSG_ID[] = "MessageIdForE2E"; const char MSG_ID_SPECIAL[] = "MessageIdForE2E*"; const char MSG_CORRELATION_ID[] = "MessageCorrelationIdForE2E"; const char MSG_CORRELATION_ID_SPECIAL[] = "MessageCorrelationIdFor#E2E"; const char MSG_CONTENT[] = "Message content for E2E"; const char MSG_CONTENT_SPECIAL[] = "!*'();:@&=+$,/?#[]"; #define MSG_PROP_COUNT 3 const char* MSG_PROP_KEYS[MSG_PROP_COUNT] = { "Key1", "Key2", "Key3" }; const char* MSG_PROP_VALS[MSG_PROP_COUNT] = { "Val1", "Val2", "Val3" }; const char* MSG_PROP_KEYS_SPECIAL[MSG_PROP_COUNT] = { "&ey1", "K/y2", "Ke?3"}; const char* MSG_PROP_VALS_SPECIAL[MSG_PROP_COUNT] = { "=al1", "V@l2", "Va%3" }; // Due to the way some test messages are composed, please do not set the initial // value of g_iotHubTestId to zero (due to potential issues with strlen). static size_t g_iotHubTestId = 1; IOTHUB_ACCOUNT_INFO_HANDLE g_iothubAcctInfo = NULL; E2E_TEST_OPTIONS g_e2e_test_options; static IOTHUB_DEVICE_CLIENT_HANDLE iothub_deviceclient_handle = NULL; static IOTHUB_MODULE_CLIENT_HANDLE iothub_moduleclient_handle = NULL; static IOTHUB_DEVICE_CLIENT_LL_HANDLE iothub_deviceclient_ll_handle = NULL; static IOTHUB_MODULE_CLIENT_LL_HANDLE iothub_moduleclient_ll_handle = NULL; #define RETRY_COUNT 4 #define RETRY_DELAY_SECONDS 60 #define IOTHUB_COUNTER_MAX 10 #define MAX_CLOUD_TRAVEL_TIME 120.0 // Wait for 5 mins (arbitrary value since 2 mins didn't work for fault injection tests) #define MAX_CLOUD_TRAVEL_TIME_FAULT_INJECTION 300.0 // Wait for 60 seconds for the service to tell us that an event was received. #define MAX_SERVICE_EVENT_WAIT_TIME_SECONDS 60 // When waiting for events, start listening for events that happened up to 60 seconds in the past. #define SERVICE_EVENT_WAIT_TIME_DELTA_SECONDS 60 #define MAX_SECURITY_DEVICE_WAIT_TIME 30 // A default message size of 0 causes client_create_and_send_d2c_messages to use // `test_message_creation` for creating the telemetry message. #define DEFAULT_MESSAGE_SIZE 0 #define LARGE_MESSAGE_SIZE 64536 #define LARGE_MESSAGE_COUNT 5 TEST_DEFINE_ENUM_TYPE(IOTHUB_TEST_CLIENT_RESULT, IOTHUB_TEST_CLIENT_RESULT_VALUES); TEST_DEFINE_ENUM_TYPE(IOTHUB_CLIENT_RESULT, IOTHUB_CLIENT_RESULT_VALUES); TEST_DEFINE_ENUM_TYPE(IOTHUB_MESSAGE_RESULT, IOTHUB_MESSAGE_RESULT_VALUES); TEST_DEFINE_ENUM_TYPE(MAP_RESULT, MAP_RESULT_VALUES); TEST_DEFINE_ENUM_TYPE(LOCK_RESULT, LOCK_RESULT_VALUES); typedef struct EXPECTED_SEND_DATA_TAG { const char* expectedString; bool wasFound; bool dataWasRecv; IOTHUB_CLIENT_CONFIRMATION_RESULT result; LOCK_HANDLE lock; IOTHUB_MESSAGE_HANDLE msgHandle; } EXPECTED_SEND_DATA; #define MAX_SEND_DATA_BUNDLE_ITEM_COUNT 5 typedef struct SEND_DATA_BUNDLE_TAG { int count; EXPECTED_SEND_DATA* items[MAX_SEND_DATA_BUNDLE_ITEM_COUNT]; } SEND_DATA_BUNDLE; typedef struct EXPECTED_RECEIVE_DATA_TAG { bool wasFound; LOCK_HANDLE lock; /*needed to protect this structure*/ IOTHUB_MESSAGE_HANDLE msgHandle; char correlation_id[sizeof(MSG_CORRELATION_ID_SPECIAL) + MSG_UNIQUE_ID_STAMP_LEN]; char message_id[sizeof(MSG_ID_SPECIAL) + MSG_UNIQUE_ID_STAMP_LEN]; } EXPECTED_RECEIVE_DATA; typedef struct CONNECTION_STATUS_DATA_TAG { bool connFaultHappened; bool connRestored; LOCK_HANDLE lock; IOTHUB_CLIENT_CONNECTION_STATUS currentStatus; IOTHUB_CLIENT_CONNECTION_STATUS_REASON currentStatusReason; } CONNECTION_STATUS_INFO; static CONNECTION_STATUS_INFO g_connection_status_info; static void openCompleteCallback(void* context) { LogInfo("Open completed, context: %s", (char*)context); } static void sendCompleteCallback(void* context, IOTHUB_MESSAGING_RESULT messagingResult) { time_t t = get_time(NULL); char* timeString = get_ctime(&t); (void) context; if (messagingResult == IOTHUB_MESSAGING_OK) { LogInfo("%.24s C2D Message has been sent successfully", timeString); } else { LogError("%.24s C2D send failed! messagingResult=%s", timeString, MU_ENUM_TO_STRING(IOTHUB_MESSAGING_RESULT, messagingResult)); } } static int IoTHubCallback(void* context, const char* data, size_t size) { int messagesReceived = 0; SEND_DATA_BUNDLE* d2cMessages = (SEND_DATA_BUNDLE*)context; for (int i = 0; i < d2cMessages->count; i++) { EXPECTED_SEND_DATA* expectedData = d2cMessages->items[i]; if (expectedData != NULL) { if (Lock(expectedData->lock) != LOCK_OK) { ASSERT_FAIL("unable to lock"); } else { if ( (strlen(expectedData->expectedString) == size) && (memcmp(expectedData->expectedString, data, size) == 0) ) { expectedData->wasFound = true; } messagesReceived += (expectedData->wasFound ? 1 : 0); (void)Unlock(expectedData->lock); } } } // Returning 0 means "keep processing" return (messagesReceived == d2cMessages->count ? 1 : 0); } // Invoked when a connection status changes. Tests poll the status in the connection_status_info to make sure expected transitions occur. static void connection_status_callback(IOTHUB_CLIENT_CONNECTION_STATUS status, IOTHUB_CLIENT_CONNECTION_STATUS_REASON reason, void* userContextCallback) { LogInfo("connection_status_callback: status=<%s>, reason=<%s>", MU_ENUM_TO_STRING(IOTHUB_CLIENT_CONNECTION_STATUS, status), MU_ENUM_TO_STRING(IOTHUB_CLIENT_CONNECTION_STATUS_REASON, reason)); CONNECTION_STATUS_INFO* connection_status_info = (CONNECTION_STATUS_INFO*)userContextCallback; ASSERT_ARE_EQUAL(LOCK_RESULT, LOCK_OK, Lock(connection_status_info->lock)); if ((connection_status_info->currentStatus == IOTHUB_CLIENT_CONNECTION_AUTHENTICATED) && (status == IOTHUB_CLIENT_CONNECTION_UNAUTHENTICATED)) { connection_status_info->connFaultHappened = true; } if ((connection_status_info->currentStatus == IOTHUB_CLIENT_CONNECTION_UNAUTHENTICATED) && (status == IOTHUB_CLIENT_CONNECTION_AUTHENTICATED)) { connection_status_info->connRestored = true; } connection_status_info->currentStatus = status; connection_status_info->currentStatusReason = reason; (void)Unlock(connection_status_info->lock); } static void ReceiveConfirmationCallback(IOTHUB_CLIENT_CONFIRMATION_RESULT result, void* userContextCallback) { LogInfo("ReceiveConfirmationCallback invoked, result=<%s>, userContextCallback=<%p>", MU_ENUM_TO_STRING(IOTHUB_CLIENT_CONFIRMATION_RESULT, result), userContextCallback); EXPECTED_SEND_DATA* expectedData = (EXPECTED_SEND_DATA*)userContextCallback; if (expectedData != NULL) { ASSERT_ARE_EQUAL(LOCK_RESULT, LOCK_OK, Lock(expectedData->lock)); expectedData->dataWasRecv = true; expectedData->result = result; (void)Unlock(expectedData->lock); } } static IOTHUBMESSAGE_DISPOSITION_RESULT ReceiveMessageCallback(IOTHUB_MESSAGE_HANDLE messageHandle, void* userContextCallback) { EXPECTED_RECEIVE_DATA* receiveUserContext = (EXPECTED_RECEIVE_DATA*)userContextCallback; if (receiveUserContext == NULL) { ASSERT_FAIL("User context is NULL"); } else { ASSERT_ARE_EQUAL(LOCK_RESULT, LOCK_OK, Lock(receiveUserContext->lock)); const char* messageId; const char* correlationId; const unsigned char* content; size_t contentSize; messageId = IoTHubMessage_GetMessageId(messageHandle); ASSERT_IS_NOT_NULL(messageId, "messageId not received"); if (g_e2e_test_options.use_special_chars && strncmp(messageId, MSG_ID_SPECIAL, sizeof(MSG_ID_SPECIAL) - 1) != 0) { ASSERT_FAIL("Message ID mismatch."); } else if (!g_e2e_test_options.use_special_chars && strncmp(messageId, MSG_ID, sizeof(MSG_ID) - 1) != 0) { ASSERT_FAIL("Message ID mismatch."); } correlationId = IoTHubMessage_GetCorrelationId(messageHandle); ASSERT_IS_NOT_NULL(correlationId, "correlationId not received"); if (g_e2e_test_options.use_special_chars && strncmp(correlationId, MSG_CORRELATION_ID_SPECIAL, sizeof(MSG_CORRELATION_ID_SPECIAL) - 1) != 0) { ASSERT_FAIL("Message correlation ID mismatch."); } else if (!g_e2e_test_options.use_special_chars && strncmp(correlationId, MSG_CORRELATION_ID, sizeof(MSG_CORRELATION_ID) - 1) != 0) { ASSERT_FAIL("Message correlation ID mismatch."); } IOTHUBMESSAGE_CONTENT_TYPE contentType = IoTHubMessage_GetContentType(messageHandle); ASSERT_ARE_EQUAL(int, (int)IOTHUBMESSAGE_BYTEARRAY, (int)contentType, "Content types don't match"); ASSERT_ARE_EQUAL(IOTHUB_MESSAGE_RESULT, IOTHUB_MESSAGE_OK, IoTHubMessage_GetByteArray(messageHandle, &content, &contentSize)); LogInfo("Received new message from IoT Hub :\nMessage-id: %s\nCorrelation-id: %s", messageId, correlationId); receiveUserContext->wasFound = true; MAP_HANDLE mapHandle = IoTHubMessage_Properties(messageHandle); ASSERT_IS_NOT_NULL(mapHandle, "No message properties available"); const char*const* keys; const char*const* values; size_t propertyCount = 0; ASSERT_ARE_EQUAL(MAP_RESULT, MAP_OK, Map_GetInternals(mapHandle, &keys, &values, &propertyCount)); ASSERT_ARE_EQUAL(int, MSG_PROP_COUNT, propertyCount); LogInfo("Message Properties:"); const char** msg_prop_keys; const char** msg_prop_vals; if (g_e2e_test_options.use_special_chars) { msg_prop_keys = MSG_PROP_KEYS_SPECIAL; msg_prop_vals = MSG_PROP_VALS_SPECIAL; } else { msg_prop_keys = MSG_PROP_KEYS; msg_prop_vals = MSG_PROP_VALS; } for (size_t index = 0; index < propertyCount; index++) { LogInfo("\tKey: %s Value: %s", keys[index], values[index]); ASSERT_ARE_EQUAL(char_ptr, keys[index], msg_prop_keys[index], "Expected keys mismatch at index %lu", (unsigned long)index); ASSERT_ARE_EQUAL(char_ptr, values[index], msg_prop_vals[index], "Expected values mismatch at index %lu", (unsigned long)index); } receiveUserContext->wasFound = true; Unlock(receiveUserContext->lock); } return IOTHUBMESSAGE_ACCEPTED; } static void GenerateUniqueId(const char* prefix, size_t prefix_len, char* buffer, size_t buffer_len) { if (prefix_len <= buffer_len) { memcpy(buffer, prefix, prefix_len); buffer_len -= prefix_len; if ((MSG_UNIQUE_ID_STAMP_LEN) <= buffer_len) { buffer[prefix_len - 1] = '.'; for (int i = 0; i < (MSG_UNIQUE_ID_STAMP_LEN - 1); i++) { buffer[prefix_len + i] = (unsigned char)((RANDOM_generate() % 10) + '0'); } buffer[prefix_len + MSG_UNIQUE_ID_STAMP_LEN - 1] = '\0'; } } else { buffer[0] = '\0'; } } static EXPECTED_RECEIVE_DATA* ReceiveUserContext_Create(void) { EXPECTED_RECEIVE_DATA* result = (EXPECTED_RECEIVE_DATA*)calloc(sizeof(EXPECTED_RECEIVE_DATA), 1); if (result != NULL) { if ((result->lock = Lock_Init()) == NULL) { free(result); result = NULL; } } return result; } static void ReceiveUserContext_Destroy(EXPECTED_RECEIVE_DATA* data) { if (data != NULL) { (void)Lock_Deinit(data->lock); if (data->msgHandle != NULL) { IoTHubMessage_Destroy(data->msgHandle); } free(data); } } static EXPECTED_SEND_DATA* EventData_Create_With_String(char* string) { EXPECTED_SEND_DATA* result = (EXPECTED_SEND_DATA*)malloc(sizeof(EXPECTED_SEND_DATA)); if (result == NULL) { LogError("Failed allocating EXPECTED_SEND_DATA"); } else { memset(result, 0, sizeof(*result)); if ((result->lock = Lock_Init()) == NULL) { ASSERT_FAIL("unable to Lock_Init"); free(result); result = NULL; } else { result->expectedString = string; result->wasFound = false; result->dataWasRecv = false; result->result = IOTHUB_CLIENT_CONFIRMATION_ERROR; } } return result; } static EXPECTED_SEND_DATA* EventData_Create(void) { EXPECTED_SEND_DATA* result; char temp[1000]; char* tempString; time_t t = time(NULL); size_t string_length; const char* data_fmt; if (g_e2e_test_options.use_special_chars) { data_fmt = TEST_EVENT_DATA_FMT_SPECIAL_CHAR; } else { data_fmt = TEST_EVENT_DATA_FMT; } string_length = sprintf(temp, data_fmt, ctime(&t), g_iotHubTestId++); if ((tempString = (char*)malloc(string_length + 1)) == NULL) { result = NULL; } else { (void)strcpy(tempString, temp); result = EventData_Create_With_String(tempString); if (result == NULL) { free(tempString); } } return result; } static EXPECTED_SEND_DATA* EventData_Create_With_Custom_Size(size_t messageSize) { EXPECTED_SEND_DATA* result; char* message = calloc(messageSize, sizeof(char)); ASSERT_IS_NOT_NULL(message, "Failed to allocate EventData message"); size_t idStringLength = sprintf(message, "%d", (int)g_iotHubTestId++); (void)memset(message + idStringLength, 'a', messageSize - idStringLength - 1); result = EventData_Create_With_String(message); ASSERT_IS_NOT_NULL(result, "Failed allocating EventData"); return result; } static void EventData_Destroy(EXPECTED_SEND_DATA* data) { if (data != NULL) { (void)Lock_Deinit(data->lock); if (data->expectedString != NULL) { free((void*)data->expectedString); } if (data->msgHandle != NULL) { IoTHubMessage_Destroy(data->msgHandle); } free(data); } } #ifdef AZIOT_LINUX static char* get_target_mac_address() { char* result; int s; if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) { LogError("Failure: socket create failure %d.", s); result = NULL; } else { struct ifreq ifr; struct ifconf ifc; char buf[1024]; ifc.ifc_len = sizeof(buf); ifc.ifc_buf = buf; if (ioctl(s, SIOCGIFCONF, &ifc) == -1) { LogError("ioctl failed querying socket (SIOCGIFCONF)"); result = NULL; } else { struct ifreq* it = ifc.ifc_req; const struct ifreq* const end = it + (ifc.ifc_len / sizeof(struct ifreq)); const char* networkInterface = IoTHubTest_GetTargetNetworkInterface(); result = NULL; for (; it != end; ++it) { strcpy(ifr.ifr_name, it->ifr_name); if (ioctl(s, SIOCGIFFLAGS, &ifr) != 0) { LogError("ioctl failed querying socket (SIOCGIFFLAGS)"); break; } else if (ioctl(s, SIOCGIFHWADDR, &ifr) != 0) { LogError("ioctl failed querying socket (SIOCGIFHWADDR)"); break; } else if (ioctl(s, SIOCGIFADDR, &ifr) != 0) { LogError("ioctl failed querying socket (SIOCGIFADDR)"); break; } else if (strcmp(ifr.ifr_name, networkInterface) == 0) { unsigned char* mac = (unsigned char*)ifr.ifr_hwaddr.sa_data; if ((result = (char*)malloc(sizeof(char) * 18)) == NULL) { LogError("failed formatting mac address (malloc failed)"); } else if (sprintf(result, "%02X:%02X:%02X:%02X:%02X:%02X", mac[0],mac[1],mac[2],mac[3],mac[4],mac[5]) <= 0) { LogError("failed formatting mac address (sprintf failed)"); free(result); result = NULL; } break; } } } close(s); } return result; } #endif //AZIOT_LINUX void e2e_init(TEST_PROTOCOL_TYPE protocol_type, bool testing_modules) { int result = IoTHub_Init(); ASSERT_ARE_EQUAL(int, 0, result, "Iothub init failed"); g_iothubAcctInfo = IoTHubAccount_Init(testing_modules); ASSERT_IS_NOT_NULL(g_iothubAcctInfo, "Could not initialize IoTHubAccount"); (void)IoTHub_Init(); memset(&g_e2e_test_options, 0, sizeof(E2E_TEST_OPTIONS)); g_e2e_test_options.set_mac_address = false; g_e2e_test_options.use_special_chars = false; g_connection_status_info.lock = Lock_Init(); test_protocol_type = protocol_type; } void e2e_deinit(void) { IoTHubAccount_deinit(g_iothubAcctInfo); // Need a double deinit IoTHub_Deinit(); IoTHub_Deinit(); Lock_Deinit(g_connection_status_info.lock); } static void setoption_on_device_or_module(const char * optionName, const void * optionData, const char * errorMessage) { IOTHUB_CLIENT_RESULT result; if (iothub_moduleclient_handle != NULL) { result = IoTHubModuleClient_SetOption(iothub_moduleclient_handle, optionName, optionData); } else if (iothub_deviceclient_handle != NULL) { result = IoTHubDeviceClient_SetOption(iothub_deviceclient_handle, optionName, optionData); } else if (iothub_moduleclient_ll_handle != NULL) { result = IoTHubModuleClient_LL_SetOption(iothub_moduleclient_ll_handle, optionName, optionData); } else { result = IoTHubDeviceClient_LL_SetOption(iothub_deviceclient_ll_handle, optionName, optionData); } ASSERT_ARE_EQUAL(IOTHUB_CLIENT_RESULT, IOTHUB_CLIENT_OK, result, errorMessage); } static void setconnectionstatuscallback_on_device_or_module() { IOTHUB_CLIENT_RESULT result; if (iothub_moduleclient_handle != NULL) { result = IoTHubModuleClient_SetConnectionStatusCallback(iothub_moduleclient_handle, connection_status_callback, &g_connection_status_info); } else if (iothub_deviceclient_handle != NULL) { result = IoTHubDeviceClient_SetConnectionStatusCallback(iothub_deviceclient_handle, connection_status_callback, &g_connection_status_info); } else if(iothub_moduleclient_ll_handle != NULL) { result = IoTHubModuleClient_LL_SetConnectionStatusCallback(iothub_moduleclient_ll_handle, connection_status_callback, &g_connection_status_info); } else { result = IoTHubDeviceClient_LL_SetConnectionStatusCallback(iothub_deviceclient_ll_handle, connection_status_callback, &g_connection_status_info); } ASSERT_ARE_EQUAL(IOTHUB_CLIENT_RESULT, IOTHUB_CLIENT_OK, result, "Could not set connection Status Callback"); } static void sendeventasync_on_device_or_module(IOTHUB_MESSAGE_HANDLE msgHandle, EXPECTED_SEND_DATA* sendData) { IOTHUB_CLIENT_RESULT result; if (iothub_moduleclient_handle != NULL) { result = IoTHubModuleClient_SendEventAsync(iothub_moduleclient_handle, msgHandle, ReceiveConfirmationCallback, sendData); } else if (iothub_deviceclient_handle != NULL) { result = IoTHubDeviceClient_SendEventAsync(iothub_deviceclient_handle, msgHandle, ReceiveConfirmationCallback, sendData); } else if (iothub_moduleclient_ll_handle != NULL) { result = IoTHubModuleClient_LL_SendEventAsync(iothub_moduleclient_ll_handle, msgHandle, ReceiveConfirmationCallback, sendData); } else { result = IoTHubDeviceClient_LL_SendEventAsync(iothub_deviceclient_ll_handle, msgHandle, ReceiveConfirmationCallback, sendData); } ASSERT_ARE_EQUAL(IOTHUB_CLIENT_RESULT, IOTHUB_CLIENT_OK, result, "SendEventAsync failed"); } static void setmessagecallback_on_device_or_module(EXPECTED_RECEIVE_DATA* receiveUserContext) { IOTHUB_CLIENT_RESULT result; if (iothub_moduleclient_handle != NULL) { result = IoTHubModuleClient_SetMessageCallback(iothub_moduleclient_handle, ReceiveMessageCallback, receiveUserContext); } else if (iothub_deviceclient_handle != NULL) { result = IoTHubDeviceClient_SetMessageCallback(iothub_deviceclient_handle, ReceiveMessageCallback, receiveUserContext); } else if (iothub_moduleclient_ll_handle != NULL) { result = IoTHubModuleClient_LL_SetMessageCallback(iothub_moduleclient_ll_handle, ReceiveMessageCallback, receiveUserContext); } else { result = IoTHubDeviceClient_LL_SetMessageCallback(iothub_deviceclient_ll_handle, ReceiveMessageCallback, receiveUserContext); } ASSERT_ARE_EQUAL(IOTHUB_CLIENT_RESULT, IOTHUB_CLIENT_OK, result, "IoTHubDeviceClient_SetMessageCallback failed"); } static void destroy_on_device_or_module() { if (iothub_deviceclient_handle != NULL) { IoTHubDeviceClient_Destroy(iothub_deviceclient_handle); iothub_deviceclient_handle = NULL; } if (iothub_moduleclient_handle != NULL) { IoTHubModuleClient_Destroy(iothub_moduleclient_handle); iothub_moduleclient_handle = NULL; } if (iothub_deviceclient_ll_handle != NULL) { IoTHubDeviceClient_LL_Destroy(iothub_deviceclient_ll_handle); iothub_deviceclient_ll_handle = NULL; } if (iothub_moduleclient_ll_handle != NULL) { IoTHubModuleClient_LL_Destroy(iothub_moduleclient_ll_handle); iothub_moduleclient_ll_handle = NULL; } } static void run_client_do_work() { if (iothub_deviceclient_ll_handle != NULL) { IoTHubDeviceClient_LL_DoWork(iothub_deviceclient_ll_handle); } else if (iothub_moduleclient_ll_handle != NULL) { IoTHubModuleClient_LL_DoWork(iothub_moduleclient_ll_handle); } } static void setup_iothub_client(IOTHUB_PROVISIONED_DEVICE* deviceToUse) { #ifdef SET_TRUSTED_CERT_IN_SAMPLES setoption_on_device_or_module(OPTION_TRUSTED_CERT, certificates, "Cannot enable trusted cert"); #endif // SET_TRUSTED_CERT_IN_SAMPLES // Set connection status change callback setconnectionstatuscallback_on_device_or_module(); if (deviceToUse->howToCreate == IOTHUB_ACCOUNT_AUTH_X509) { setoption_on_device_or_module(OPTION_X509_CERT, deviceToUse->certificate, "Could not set the device x509 certificate"); setoption_on_device_or_module(OPTION_X509_PRIVATE_KEY, deviceToUse->primaryAuthentication, "Could not set the device x509 privateKey"); } bool trace = true; setoption_on_device_or_module(OPTION_LOG_TRACE, &trace, "Cannot enable tracing"); setoption_on_device_or_module(OPTION_PRODUCT_INFO, "MQTT_E2E/1.1.12", "Cannot set product info"); //Turn on URL encoding/decoding (MQTT) if (g_e2e_test_options.use_special_chars) { bool encodeDecode = true; setoption_on_device_or_module(OPTION_AUTO_URL_ENCODE_DECODE, &encodeDecode, "Cannot set auto_url_encode/decode"); } if (test_protocol_type == TEST_AMQP || test_protocol_type == TEST_AMQP_WEBSOCKETS) { size_t svc2cl_keep_alive_timeout_secs = 120; // service will send pings at 120 x 7/8 = 105 seconds. Higher the value, lesser the frequency of service side pings. setoption_on_device_or_module(OPTION_SERVICE_SIDE_KEEP_ALIVE_FREQ_SECS, &svc2cl_keep_alive_timeout_secs, "Cannot set OPTION_SERVICE_SIDE_KEEP_ALIVE_FREQ_SECS"); // Set keep alive for remote idle is optional. If it is not set the default ratio of 1/2 will be used. For default value of 4 minutes, it will be 2 minutes (120 seconds) double cl2svc_keep_alive_send_ratio = 1.0 / 2.0; // Set it to 120 seconds (240 x 1/2 = 120 seconds) for 4 minutes remote idle. // client will send pings to service at 210 second interval for 4 minutes remote idle. For 25 minutes remote idle, it will be set to 21 minutes. setoption_on_device_or_module(OPTION_REMOTE_IDLE_TIMEOUT_RATIO, &cl2svc_keep_alive_send_ratio, "Cannot set OPTION_REMOTE_IDLE_TIMEOUT_RATIO"); } #ifdef AZIOT_LINUX if (g_e2e_test_options.set_mac_address) { char* mac_address = get_target_mac_address(); ASSERT_IS_NOT_NULL(mac_address, "failed getting the target MAC ADDRESS"); setoption_on_device_or_module(OPTION_NET_INT_MAC_ADDRESS, mac_address, "Cannot setoption MAC ADDRESS"); LogInfo("Target MAC ADDRESS: %s", mac_address); free(mac_address); } #endif //AZIOT_LINUX } static void client_connect_to_hub(IOTHUB_PROVISIONED_DEVICE* deviceToUse, IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol) { ASSERT_IS_NULL(iothub_deviceclient_handle, "iothub_deviceclient_handle is non-NULL on test initialization"); ASSERT_IS_NULL(iothub_moduleclient_handle, "iothub_moduleclient_handle is non-NULL on test initialization"); if (deviceToUse->moduleConnectionString != NULL) { iothub_moduleclient_handle = IoTHubModuleClient_CreateFromConnectionString(deviceToUse->moduleConnectionString, protocol); ASSERT_IS_NOT_NULL(iothub_moduleclient_handle, "Could not invoke IoTHubModuleClient_CreateFromConnectionString"); } else { iothub_deviceclient_handle = IoTHubDeviceClient_CreateFromConnectionString(deviceToUse->connectionString, protocol); ASSERT_IS_NOT_NULL(iothub_deviceclient_handle, "Could not invoke IoTHubDeviceClient_CreateFromConnectionString"); } setup_iothub_client(deviceToUse); } static void client_ll_connect_to_hub(IOTHUB_PROVISIONED_DEVICE* deviceToUse, IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol) { size_t client_conn_wait_time = 4000; ASSERT_IS_NULL(iothub_deviceclient_ll_handle, "iothub_deviceclient_ll_handle is non-NULL on test initialization"); ASSERT_IS_NULL(iothub_moduleclient_ll_handle, "iothub_moduleclient_ll_handle is non-NULL on test initialization"); if (deviceToUse->moduleConnectionString != NULL) { iothub_moduleclient_ll_handle = IoTHubModuleClient_LL_CreateFromConnectionString(deviceToUse->moduleConnectionString, protocol); ASSERT_IS_NOT_NULL(iothub_moduleclient_ll_handle, "Could not invoke IoTHubModuleClient_LL_CreateFromConnectionString"); } else { iothub_deviceclient_ll_handle = IoTHubDeviceClient_LL_CreateFromConnectionString(deviceToUse->connectionString, protocol); ASSERT_IS_NOT_NULL(iothub_deviceclient_ll_handle, "Could not invoke IoTHubDeviceClient_LL_CreateFromConnectionString"); } setup_iothub_client(deviceToUse); // LL clients require _DoWork to be explicitly called to do network I/O. // Calling the function below guarantees DoWork is called and the client gets authenticated. ASSERT_IS_TRUE(wait_for_client_authenticated(client_conn_wait_time)); } void client_create_and_send_d2c_messages(TEST_MESSAGE_CREATION_MECHANISM test_message_creation, int count, size_t messageSize, SEND_DATA_BUNDLE* d2cMessages) { for (int i = 0; i < count; i++) { IOTHUB_MESSAGE_HANDLE msgHandle; EXPECTED_SEND_DATA* sendData = (messageSize == 0 ? EventData_Create() : EventData_Create_With_Custom_Size(messageSize)); ASSERT_IS_NOT_NULL(sendData, "Could not create the EventData associated with the event to be sent"); if (test_message_creation == TEST_MESSAGE_CREATE_BYTE_ARRAY) { msgHandle = IoTHubMessage_CreateFromByteArray((const unsigned char*)sendData->expectedString, strlen(sendData->expectedString)); } else if (test_message_creation == TEST_MESSAGE_CREATE_STRING) { msgHandle = IoTHubMessage_CreateFromString(sendData->expectedString); } else { msgHandle = NULL; ASSERT_FAIL("Unknown test message creation mechanism specified"); } ASSERT_IS_NOT_NULL(msgHandle, "Could not create the D2C message to be sent"); for (size_t j = 0; j < MSG_PROP_COUNT; j++) { if (g_e2e_test_options.use_special_chars) { ASSERT_ARE_EQUAL(IOTHUB_MESSAGE_RESULT, IOTHUB_MESSAGE_OK, IoTHubMessage_SetProperty(msgHandle, MSG_PROP_KEYS_SPECIAL[j], MSG_PROP_VALS_SPECIAL[j]), "Map_AddOrUpdate failed for property %zu!", j); } else { ASSERT_ARE_EQUAL(IOTHUB_MESSAGE_RESULT, IOTHUB_MESSAGE_OK, IoTHubMessage_SetProperty(msgHandle, MSG_PROP_KEYS[j], MSG_PROP_VALS[j]), "Map_AddOrUpdate failed for property %zu!", j); } } sendData->msgHandle = msgHandle; d2cMessages->items[i] = sendData; d2cMessages->count++; // act sendeventasync_on_device_or_module(msgHandle, sendData); } } D2C_MESSAGE_HANDLE client_create_and_send_d2c(TEST_MESSAGE_CREATION_MECHANISM test_message_creation) { SEND_DATA_BUNDLE d2cMessages; client_create_and_send_d2c_messages(test_message_creation, 1, DEFAULT_MESSAGE_SIZE, &d2cMessages); return d2cMessages.items[0]; } bool client_wait_for_d2c_confirmations(SEND_DATA_BUNDLE* d2cMessages, IOTHUB_CLIENT_CONFIRMATION_RESULT expectedClientResult) { time_t beginOperation, nowTime; bool allMessagesDelivered = false; for (int i = 0; i < d2cMessages->count; i++) { LogInfo("Begin wait for d2c confirmation. d2cMessage=<%p>", d2cMessages->items[i]); } beginOperation = time(NULL); while ( (nowTime = time(NULL)), !allMessagesDelivered && (difftime(nowTime, beginOperation) < MAX_CLOUD_TRAVEL_TIME) // time box ) { allMessagesDelivered = true; for (int i = 0; i < d2cMessages->count; i++) { if (!client_received_confirmation(d2cMessages->items[i], expectedClientResult)) { allMessagesDelivered = false; break; } } run_client_do_work(); ThreadAPI_Sleep(100); } for (int i = 0; i < d2cMessages->count; i++) { bool messageSent = client_received_confirmation(d2cMessages->items[i], expectedClientResult); LogInfo("Completed wait for d2c confirmation. d2cMessage=<%p>, ret=<%d>", d2cMessages->items[i], messageSent); } return allMessagesDelivered; } bool client_wait_for_d2c_confirmation(D2C_MESSAGE_HANDLE d2cMessage, IOTHUB_CLIENT_CONFIRMATION_RESULT expectedClientResult) { SEND_DATA_BUNDLE d2cMessages; d2cMessages.count = 1; d2cMessages.items[0] = (EXPECTED_SEND_DATA*)d2cMessage; return client_wait_for_d2c_confirmations(&d2cMessages, expectedClientResult); } bool client_received_confirmation(D2C_MESSAGE_HANDLE d2cMessage, IOTHUB_CLIENT_CONFIRMATION_RESULT expectedClientResult) { bool result = false; EXPECTED_SEND_DATA* sendData = (EXPECTED_SEND_DATA*)d2cMessage; ASSERT_ARE_EQUAL(LOCK_RESULT, LOCK_OK, Lock(sendData->lock)); result = sendData->dataWasRecv; if (sendData->dataWasRecv == true) { ASSERT_ARE_EQUAL(int, expectedClientResult, sendData->result, "Result from callback does not match expected"); } (void)Unlock(sendData->lock); return result; } // White-listed IoT Hub's (ONLY!) have special logic that looks at message properties such as 'AzIoTHub_FaultOperationType' and if so, will // cause the specified error to occur. This allows end-to-end testing to simulate across a wide range of errors. D2C_MESSAGE_HANDLE send_error_injection_message(const char* faultOperationType, const char* faultOperationCloseReason, const char* faultOperationDelayInSecs) { IOTHUB_MESSAGE_HANDLE msgHandle; EXPECTED_SEND_DATA* sendData = EventData_Create(); ASSERT_IS_NOT_NULL(sendData, "Could not create the EventData associated with the event to be sent"); if (sendData != NULL) { msgHandle = IoTHubMessage_CreateFromByteArray((const unsigned char*)sendData->expectedString, strlen(sendData->expectedString)); ASSERT_IS_NOT_NULL(msgHandle, "Could not create the D2C message to be sent"); ASSERT_ARE_EQUAL(IOTHUB_MESSAGE_RESULT, IOTHUB_MESSAGE_OK, IoTHubMessage_SetProperty(msgHandle, "AzIoTHub_FaultOperationType", faultOperationType)); ASSERT_ARE_EQUAL(IOTHUB_MESSAGE_RESULT, IOTHUB_MESSAGE_OK, IoTHubMessage_SetProperty(msgHandle, "AzIoTHub_FaultOperationCloseReason", faultOperationCloseReason)); ASSERT_ARE_EQUAL(IOTHUB_MESSAGE_RESULT, IOTHUB_MESSAGE_OK, IoTHubMessage_SetProperty(msgHandle, "AzIoTHub_FaultOperationDelayInSecs", faultOperationDelayInSecs)); ASSERT_ARE_EQUAL(IOTHUB_MESSAGE_RESULT, IOTHUB_MESSAGE_OK, IoTHubMessage_SetProperty(msgHandle, "AzIoTHub_FaultOperationDurationInSecs", "20")); sendData->msgHandle = msgHandle; // act sendeventasync_on_device_or_module(msgHandle, sendData); } return (D2C_MESSAGE_HANDLE)sendData; } bool client_wait_for_connection_fault() { time_t beginOperation, nowTime; beginOperation = time(NULL); while ( (nowTime = time(NULL)), (difftime(nowTime, beginOperation) < MAX_CLOUD_TRAVEL_TIME_FAULT_INJECTION) // time box ) { if (client_status_fault_happened()) { break; } ThreadAPI_Sleep(100); } return (client_status_fault_happened()); } bool client_status_fault_happened() { bool result = false; ASSERT_ARE_EQUAL(LOCK_RESULT, LOCK_OK, Lock(g_connection_status_info.lock)); result = g_connection_status_info.connFaultHappened; (void)Unlock(g_connection_status_info.lock); return result; } bool wait_for_client_authenticated(size_t wait_time) { bool result = false; time_t beginOperation, nowTime; beginOperation = time(NULL); while ( (nowTime = time(NULL)), (difftime(nowTime, beginOperation) < wait_time) // time box ) { ASSERT_ARE_EQUAL(LOCK_RESULT, LOCK_OK, Lock(g_connection_status_info.lock)); result = (g_connection_status_info.currentStatus == IOTHUB_CLIENT_CONNECTION_AUTHENTICATED); (void)Unlock(g_connection_status_info.lock); if (result) { break; } run_client_do_work(); ThreadAPI_Sleep(100); } return result; } bool client_wait_for_connection_restored() { time_t beginOperation, nowTime; beginOperation = time(NULL); while ( (nowTime = time(NULL)), (difftime(nowTime, beginOperation) < MAX_CLOUD_TRAVEL_TIME) // time box ) { if (client_status_restored()) { break; } ThreadAPI_Sleep(100); } return (client_status_restored()); } bool client_status_restored() { bool result = false; ASSERT_ARE_EQUAL(LOCK_RESULT, LOCK_OK, Lock(g_connection_status_info.lock)); result = g_connection_status_info.connRestored; (void)Unlock(g_connection_status_info.lock); return result; } // Resets global connection status at beginning of tests. void clear_connection_status_info_flags() { ASSERT_ARE_EQUAL(LOCK_RESULT, LOCK_OK, Lock(g_connection_status_info.lock)); g_connection_status_info.connFaultHappened = false; g_connection_status_info.connRestored = false; g_connection_status_info.currentStatus = IOTHUB_CLIENT_CONNECTION_UNAUTHENTICATED; g_connection_status_info.currentStatusReason = IOTHUB_CLIENT_CONNECTION_NO_NETWORK; (void)Unlock(g_connection_status_info.lock); } static void service_wait_for_security_d2c_event_arrival(IOTHUB_PROVISIONED_DEVICE* deviceToUse, D2C_MESSAGE_HANDLE d2cMessage, double max_wait_time) { EXPECTED_SEND_DATA* sendData = (EXPECTED_SEND_DATA*)d2cMessage; SEND_DATA_BUNDLE d2cMessages; d2cMessages.count = 1; d2cMessages.items[0] = sendData; IOTHUB_TEST_HANDLE iotHubTestHandle = IoTHubTest_Initialize(IoTHubAccount_GetEventHubConnectionString(g_iothubAcctInfo), IoTHubAccount_GetIoTHubConnString(g_iothubAcctInfo), deviceToUse->deviceId, IoTHubAccount_GetEventhubListenName(g_iothubAcctInfo), IoTHubAccount_GetEventhubAccessKey(g_iothubAcctInfo), IoTHubAccount_GetSharedAccessSignature(g_iothubAcctInfo), IoTHubAccount_GetEventhubConsumerGroup(g_iothubAcctInfo)); ASSERT_IS_NOT_NULL(iotHubTestHandle, "Could not initialize IoTHubTest in order to listen for events"); LogInfo("Beginning to listen for d2c event arrival. Waiting up to %f seconds...", max_wait_time); IOTHUB_TEST_CLIENT_RESULT result = IoTHubTest_ListenForEvent(iotHubTestHandle, IoTHubCallback, IoTHubAccount_GetIoTHubPartitionCount(g_iothubAcctInfo), &d2cMessages, time(NULL)-SERVICE_EVENT_WAIT_TIME_DELTA_SECONDS, max_wait_time); ASSERT_ARE_EQUAL(IOTHUB_TEST_CLIENT_RESULT, IOTHUB_TEST_CLIENT_ERROR, result, "Listening for the event failed"); ASSERT_IS_FALSE(sendData->wasFound, "Failure event was not routed correctly when sending security event"); // was found is written by the callback... IoTHubTest_Deinit(iotHubTestHandle); LogInfo("Completed listening for security event arrival."); } void service_wait_for_d2c_events_arrival(IOTHUB_PROVISIONED_DEVICE* deviceToUse, SEND_DATA_BUNDLE* d2cMessages, double max_wait_time) { bool allMessagesArrived = true; IOTHUB_TEST_HANDLE iotHubTestHandle = IoTHubTest_Initialize(IoTHubAccount_GetEventHubConnectionString(g_iothubAcctInfo), IoTHubAccount_GetIoTHubConnString(g_iothubAcctInfo), deviceToUse->deviceId, IoTHubAccount_GetEventhubListenName(g_iothubAcctInfo), IoTHubAccount_GetEventhubAccessKey(g_iothubAcctInfo), IoTHubAccount_GetSharedAccessSignature(g_iothubAcctInfo), IoTHubAccount_GetEventhubConsumerGroup(g_iothubAcctInfo)); ASSERT_IS_NOT_NULL(iotHubTestHandle, "Could not initialize IoTHubTest in order to listen for events"); LogInfo("Beginning to listen for d2c event arrival. Waiting up to %f seconds...", max_wait_time); IOTHUB_TEST_CLIENT_RESULT result = IoTHubTest_ListenForEvent(iotHubTestHandle, IoTHubCallback, IoTHubAccount_GetIoTHubPartitionCount(g_iothubAcctInfo), d2cMessages, time(NULL) - SERVICE_EVENT_WAIT_TIME_DELTA_SECONDS, max_wait_time); ASSERT_ARE_EQUAL(IOTHUB_TEST_CLIENT_RESULT, IOTHUB_TEST_CLIENT_OK, result, "Listening for the event failed"); for (int i = 0; i < d2cMessages->count; i++) { allMessagesArrived &= d2cMessages->items[i]->wasFound; LogInfo("d2c message %p received by eventhub: %d", d2cMessages->items[i], d2cMessages->items[i]->wasFound); } ASSERT_IS_TRUE(allMessagesArrived, "Failure retrieving all data that was sent to eventhub"); // was found is written by the callback... IoTHubTest_Deinit(iotHubTestHandle); LogInfo("Completed listening for d2c event arrival."); } void service_wait_for_d2c_event_arrival(IOTHUB_PROVISIONED_DEVICE* deviceToUse, D2C_MESSAGE_HANDLE d2cMessage, double max_wait_time) { SEND_DATA_BUNDLE d2cMessages; d2cMessages.count = 1; d2cMessages.items[0] = (EXPECTED_SEND_DATA*)d2cMessage; service_wait_for_d2c_events_arrival(deviceToUse, &d2cMessages, max_wait_time); } bool service_received_the_message(D2C_MESSAGE_HANDLE d2cMessage) { return ((EXPECTED_SEND_DATA*)d2cMessage)->wasFound; } void destroy_d2c_message_handle(D2C_MESSAGE_HANDLE d2cMessage) { LogInfo("Destroying message %p", d2cMessage); EventData_Destroy((EXPECTED_SEND_DATA*)d2cMessage); } void destroy_d2c_messages(SEND_DATA_BUNDLE* d2cMessages) { for (int i = 0; i < d2cMessages->count; i++) { destroy_d2c_message_handle(d2cMessages->items[i]); } } static void send_event_test(IOTHUB_PROVISIONED_DEVICE* deviceToUse, IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol) { TEST_MESSAGE_CREATION_MECHANISM test_message_creation[] = { TEST_MESSAGE_CREATE_BYTE_ARRAY, TEST_MESSAGE_CREATE_STRING }; int i; for (i = 0; i < sizeof(test_message_creation) / sizeof(test_message_creation[0]); i++) { // arrange D2C_MESSAGE_HANDLE d2cMessage; // Create the IoT Hub Data client_connect_to_hub(deviceToUse, protocol); // Send the Event from the client d2cMessage = client_create_and_send_d2c(test_message_creation[i]); // Wait for confirmation that the event was recevied bool dataWasRecv = client_wait_for_d2c_confirmation(d2cMessage, IOTHUB_CLIENT_CONFIRMATION_OK); ASSERT_IS_TRUE(dataWasRecv, "Failure sending data to IotHub"); // was received by the callback... // close the client connection destroy_on_device_or_module(); // Wait for the message to arrive service_wait_for_d2c_event_arrival(deviceToUse, d2cMessage, MAX_SERVICE_EVENT_WAIT_TIME_SECONDS); // cleanup destroy_d2c_message_handle(d2cMessage); } } /** * This is a test function that can send several telemetry messages in one shot, * aiming to trigger the telemetry batching capability of the Azure IoT C SDK (AMQP). * We need to use the Azure IoT C SDK LL API to force the batching to occur, since we lose * control on convenience layer (which has a dedicated thread running *DoWork, and could consume * messages on the `waitingToSend` list too fast and prevent telemetry batching to kick in). */ static void send_batch_event_test(IOTHUB_PROVISIONED_DEVICE* deviceToUse, IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol) { TEST_MESSAGE_CREATION_MECHANISM test_message_creation[] = { TEST_MESSAGE_CREATE_BYTE_ARRAY, TEST_MESSAGE_CREATE_STRING }; int i; for (i = 0; i < sizeof(test_message_creation) / sizeof(test_message_creation[0]); i++) { // arrange SEND_DATA_BUNDLE d2cMessages = { 0 }; clear_connection_status_info_flags(); // Create the IoT Hub Data client_ll_connect_to_hub(deviceToUse, protocol); // Send the Events from the client client_create_and_send_d2c_messages(test_message_creation[i], LARGE_MESSAGE_COUNT, LARGE_MESSAGE_SIZE, &d2cMessages); // Wait for confirmation that the event was recevied bool dataWasRecv = client_wait_for_d2c_confirmations(&d2cMessages, IOTHUB_CLIENT_CONFIRMATION_OK); ASSERT_IS_TRUE(dataWasRecv, "Failure sending data to IotHub"); // was received by the callback... // close the client connection destroy_on_device_or_module(); // Wait for the message to arrive service_wait_for_d2c_events_arrival(deviceToUse, &d2cMessages, MAX_SERVICE_EVENT_WAIT_TIME_SECONDS); // cleanup destroy_d2c_messages(&d2cMessages); } } void e2e_send_event_test_sas(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol) { send_event_test(IoTHubAccount_GetSASDevice(g_iothubAcctInfo), protocol); } void e2e_send_batch_event_test_sas(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol) { send_batch_event_test(IoTHubAccount_GetSASDevice(g_iothubAcctInfo), protocol); } void e2e_send_event_test_x509(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol) { send_event_test(IoTHubAccount_GetX509Device(g_iothubAcctInfo), protocol); } void e2e_send_security_event_test_sas(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol) { //IOTHUB_MESSAGE_HANDLE msgHandle; //char* test_telemetry_message; const char* TEST_ASC_SECURITY_MESSAGE = "{ \ \"AgentVersion\": \"0.0.1\", \ \"AgentId\" : \"{A3B5D80C-06AA-4D84-BA2D-5470ADAE33A3}\", \ \"MessageSchemaVersion\" : \"1.0\", \ \"Events\" : \ { \ \"EventType\": \"Security\", \ \"Category\" : \"Periodic\", \ \"Name\" : \"ListeningPorts\", \ \"IsEmpty\" : true, \ \"PayloadSchemaVersion\" : \"1.0\", \ \"Id\" : \"12432\", \ \"TimestampLocal\" : \"2012-04-23T18:25:43.511Z\", \ \"TimestampUTC\" : \"2012-04-23T18:25:43.511Z\" }, \ \"Payload\": { \"data\": \"test\" } \ } \ }"; // Create the IoT Hub Data IOTHUB_PROVISIONED_DEVICE* deviceToUse; deviceToUse = IoTHubAccount_GetSASDevice(g_iothubAcctInfo); client_connect_to_hub(deviceToUse, protocol); EXPECTED_SEND_DATA* send_data = (EXPECTED_SEND_DATA*)client_create_and_send_d2c(TEST_MESSAGE_CREATE_STRING); bool dataWasRecv = client_wait_for_d2c_confirmation((D2C_MESSAGE_HANDLE)send_data, IOTHUB_CLIENT_CONFIRMATION_OK); ASSERT_IS_TRUE(dataWasRecv, "Failure sending data to IotHub"); // was received by the callback... // Free the message IoTHubMessage_Destroy(send_data->msgHandle); // Send the messages to the ASC Event hub // Create an ASC Security Message LogInfo("Sending ASC message to endpoint"); const char* temp_string_val = send_data->expectedString; send_data->msgHandle = IoTHubMessage_CreateFromString(TEST_ASC_SECURITY_MESSAGE); ASSERT_IS_NOT_NULL(send_data->msgHandle, "Could not create the ASC Security message to be sent"); send_data->wasFound = false; send_data->dataWasRecv = false; send_data->result = IOTHUB_CLIENT_CONFIRMATION_ERROR; send_data->expectedString = TEST_ASC_SECURITY_MESSAGE; // Send the messages to the ASC Event hub ASSERT_ARE_EQUAL(IOTHUB_MESSAGE_RESULT, IOTHUB_MESSAGE_OK, IoTHubMessage_SetAsSecurityMessage(send_data->msgHandle), "Failure setting message as a security message"); // Send ASC message, it should not arrive in the IoTHub EventHub sendeventasync_on_device_or_module(send_data->msgHandle, send_data); // close the client connection destroy_on_device_or_module(); // Wait for the message to not arrive since it's going to an ASC eventhub service_wait_for_security_d2c_event_arrival(deviceToUse, send_data, MAX_SECURITY_DEVICE_WAIT_TIME); // Done with ASC test, restore string send_data->expectedString = temp_string_val; // cleanup EventData_Destroy(send_data); } // Simulates a fault occurring in end-to-end testing (with special opcodes forcing service failure on certain white-listed Hubs) and // ability to recover after error. void e2e_d2c_with_svc_fault_ctrl(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol, const char* faultOperationType, const char* faultOperationCloseReason, const char* faultOperationDelayInSecs) { // arrange D2C_MESSAGE_HANDLE d2cMessageInitial = NULL; D2C_MESSAGE_HANDLE d2cMessageFaultInjection = NULL; D2C_MESSAGE_HANDLE d2cMessageDuringRetry = NULL; IOTHUB_PROVISIONED_DEVICE* deviceToUse = IoTHubAccount_GetSASDevice(g_iothubAcctInfo); clear_connection_status_info_flags(); // Create the IoT Hub Data client_connect_to_hub(deviceToUse, protocol); // Send the Event from the client LogInfo("Creating and sending message..."); d2cMessageInitial = client_create_and_send_d2c(TEST_MESSAGE_CREATE_STRING); // Wait for confirmation that the event was recevied LogInfo("Waiting for initial message %p", d2cMessageInitial); bool dataWasRecv = client_wait_for_d2c_confirmation(d2cMessageInitial, IOTHUB_CLIENT_CONFIRMATION_OK); ASSERT_IS_TRUE(dataWasRecv, "Failure sending data to IotHub"); // was received by the callback... LogInfo("Send server fault control message..."); d2cMessageFaultInjection = send_error_injection_message(faultOperationType, faultOperationCloseReason, faultOperationDelayInSecs); LogInfo("FaultInject message handle is %p", d2cMessageFaultInjection); LogInfo("Sleeping after sending fault injection..."); ThreadAPI_Sleep(5000); // Wait for the server fault message to be timed out LogInfo("Waiting for server fault message to timeout"); dataWasRecv = client_wait_for_d2c_confirmation(d2cMessageFaultInjection, IOTHUB_CLIENT_CONFIRMATION_MESSAGE_TIMEOUT); ASSERT_IS_TRUE(dataWasRecv, "Failure recieving server fault message timeout"); // was received by the callback... // Send the Event fromsend_data. the client LogInfo("Send message after the server fault and then sleeping..."); d2cMessageDuringRetry = client_create_and_send_d2c(TEST_MESSAGE_CREATE_STRING); ThreadAPI_Sleep(8000); // Wait for confirmation that the event was recevied LogInfo("Waiting for message after server fault %p", d2cMessageDuringRetry); dataWasRecv = client_wait_for_d2c_confirmation(d2cMessageDuringRetry, IOTHUB_CLIENT_CONFIRMATION_OK); ASSERT_IS_TRUE(dataWasRecv, "Don't recover after the fault..."); // close the client connection destroy_on_device_or_module(); // Wait for the message to arrive LogInfo("waiting for d2c arrive..."); service_wait_for_d2c_event_arrival(deviceToUse, d2cMessageDuringRetry, MAX_SERVICE_EVENT_WAIT_TIME_SECONDS); // cleanup destroy_d2c_message_handle(d2cMessageDuringRetry); destroy_d2c_message_handle(d2cMessageFaultInjection); destroy_d2c_message_handle(d2cMessageInitial); } // Simulates a fault occurring in end-to-end testing (with special opcodes forcing service failure on certain white-listed Hubs) and // ability to recover after error. Further simulates connection status events being fired as expected. // Note that not all classes of failures result in connection status being reflected. void e2e_d2c_with_svc_fault_ctrl_with_transport_status(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol, const char* faultOperationType, const char* faultOperationCloseReason, const char* faultOperationDelayInSecs) { IOTHUB_PROVISIONED_DEVICE* deviceToUse = IoTHubAccount_GetSASDevice(g_iothubAcctInfo); // arrange D2C_MESSAGE_HANDLE d2cMessageInitial = NULL; D2C_MESSAGE_HANDLE d2cMessageFaultInjection = NULL; D2C_MESSAGE_HANDLE d2cMessageDuringRetry = NULL; EXPECTED_RECEIVE_DATA* receiveUserContext = NULL; clear_connection_status_info_flags(); // Create the IoT Hub Data client_connect_to_hub(deviceToUse, protocol); if ((0 == strcmp(faultOperationType, "KillAmqpCBSLinkReq")) || (0 == strcmp(faultOperationType, "KillAmqpCBSLinkResp"))) { // We will only detect errors in CBS link when we attempt to refresh the token, which usually is quite long (see OPTION_SAS_TOKEN_LIFETIME). // We make the refresh time only 10 seconds so that the error is detected more quickly. size_t refresh_time = 10; setoption_on_device_or_module(OPTION_SAS_TOKEN_LIFETIME, (const void*)&refresh_time, "Failed setting OPTION_SAS_TOKEN_LIFETIME"); } LogInfo("Sleeping 3 seconds to let SetMessageCallback() register with server."); ThreadAPI_Sleep(3000); LogInfo("Continue with service client message."); // Send the Event from the client LogInfo("Send message and wait for confirmation..."); d2cMessageInitial = client_create_and_send_d2c(TEST_MESSAGE_CREATE_BYTE_ARRAY); // Wait for confirmation that the event was recevied bool dataWasRecv = client_wait_for_d2c_confirmation(d2cMessageInitial, IOTHUB_CLIENT_CONFIRMATION_OK); ASSERT_IS_TRUE(dataWasRecv, "Failure sending data to IotHub"); // was received by the callback... // Set callback. This is required to create the D2C link (it's not created otherwise) that we'll get DETATCH message on. receiveUserContext = ReceiveUserContext_Create(); setmessagecallback_on_device_or_module(receiveUserContext); // Send the Fault Control Event from the client LogInfo("Send server fault control message..."); d2cMessageFaultInjection = send_error_injection_message(faultOperationType, faultOperationCloseReason, faultOperationDelayInSecs); LogInfo("Sleeping after sending fault injection..."); ThreadAPI_Sleep(3000); LogInfo("Woke up after sending fault injection..."); // Wait for connection status change (restored) LogInfo("wait for restore..."); bool connStatus = client_wait_for_connection_restored(); ASSERT_IS_TRUE(connStatus, "Fault injection failed - connection has not been restored"); // Wait for connection status change (fault) LogInfo("wait for fault..."); connStatus = client_wait_for_connection_fault(); ASSERT_IS_TRUE(connStatus, "Fault injection failed - no fault happened"); // Wait for connection status change (restored) LogInfo("wait for restore..."); connStatus = client_wait_for_connection_restored(); ASSERT_IS_TRUE(connStatus, "Fault injection failed - connection has not been restored"); // Send the Event from the client LogInfo("Send message after the server fault and wait for confirmation..."); d2cMessageDuringRetry = client_create_and_send_d2c(TEST_MESSAGE_CREATE_BYTE_ARRAY); // Wait for confirmation that the event was recevied LogInfo("wait for d2c confirm..."); dataWasRecv = client_wait_for_d2c_confirmation(d2cMessageDuringRetry, IOTHUB_CLIENT_CONFIRMATION_OK); ASSERT_IS_TRUE(dataWasRecv, "Failure sending data to IotHub"); // was received by the callback... // close the client connection destroy_on_device_or_module(); // Wait for the message to arrive LogInfo("waiting for d2c arrive..."); service_wait_for_d2c_event_arrival(deviceToUse, d2cMessageDuringRetry, MAX_SERVICE_EVENT_WAIT_TIME_SECONDS); // cleanup destroy_d2c_message_handle(d2cMessageInitial); destroy_d2c_message_handle(d2cMessageFaultInjection); destroy_d2c_message_handle(d2cMessageDuringRetry); ReceiveUserContext_Destroy(receiveUserContext); } // Simulates a fault occurring in end-to-end testing (with special opcodes forcing service failure on certain white-listed Hubs) and // ability to recover after error. void e2e_d2c_with_svc_fault_ctrl_error_message_callback(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol, const char* faultOperationType, const char* faultOperationCloseReason, const char* faultOperationDelayInSecs, bool setTimeoutOption, bool isMqtt) { // Note we pass 'isMqtt' instead of (protocol==MQTT_Transport) because this takes an explicit dependency on MQTT libraries, which will not be present // for someone building AMQP only. IOTHUB_PROVISIONED_DEVICE* deviceToUse = IoTHubAccount_GetSASDevice(g_iothubAcctInfo); // arrange D2C_MESSAGE_HANDLE d2cMessageInitial = NULL; D2C_MESSAGE_HANDLE d2cMessageFaultInjection = NULL; D2C_MESSAGE_HANDLE d2cMessageDuringRetry = NULL; bool connStatus; clear_connection_status_info_flags(); // Create the IoT Hub Data client_connect_to_hub(deviceToUse, protocol); if (setTimeoutOption) { setoption_on_device_or_module("event_send_timeout_secs", "30", "Failure setting transport timeout"); } // Send the Event from the client LogInfo("Send message and wait for confirmation..."); d2cMessageInitial = client_create_and_send_d2c(TEST_MESSAGE_CREATE_STRING); // Wait for confirmation that the event was recevied bool dataWasRecv = client_wait_for_d2c_confirmation(d2cMessageInitial, IOTHUB_CLIENT_CONFIRMATION_OK); ASSERT_IS_TRUE(dataWasRecv, "Failure sending data to IotHub"); // was received by the callback... // Send the Fault Control Event from the client LogInfo("Send server fault control message..."); d2cMessageFaultInjection = send_error_injection_message(faultOperationType, faultOperationCloseReason, faultOperationDelayInSecs); LogInfo("Sleeping after sending fault injection..."); ThreadAPI_Sleep(3000); LogInfo("Sending message and expect no confirmation..."); d2cMessageDuringRetry = client_create_and_send_d2c(TEST_MESSAGE_CREATE_STRING); if (isMqtt) { // MQTT gets disconnects (not error messages), though it'll auto-reconnect. Make sure that happens. LogInfo("wait for fault..."); connStatus = client_wait_for_connection_fault(); ASSERT_IS_TRUE(connStatus, "Fault injection failed - no fault happened"); // Wait for connection status change (restored) LogInfo("wait for restore..."); connStatus = client_wait_for_connection_restored(); ASSERT_IS_TRUE(connStatus, "Fault injection failed - connection has not been restored"); } // AMQP fault injection tests persist the fact an error occurred on server and mean the test gets this back. MQTT fault injection on server is more stateless; we'll // reconnect automatically after error but server will have us succeed. dataWasRecv = client_wait_for_d2c_confirmation(d2cMessageDuringRetry, isMqtt ? IOTHUB_CLIENT_CONFIRMATION_OK : IOTHUB_CLIENT_CONFIRMATION_ERROR); ASSERT_IS_TRUE(dataWasRecv, "Failure getting response from IoT Hub..."); // was received by the callback... // close the client connection destroy_on_device_or_module(); // cleanup destroy_d2c_message_handle(d2cMessageInitial); destroy_d2c_message_handle(d2cMessageFaultInjection); destroy_d2c_message_handle(d2cMessageDuringRetry); } EXPECTED_RECEIVE_DATA *service_create_c2d(const char *content) { IOTHUB_MESSAGE_RESULT iotHubMessageResult; IOTHUB_MESSAGE_HANDLE messageHandle; EXPECTED_RECEIVE_DATA *receiveUserContext = ReceiveUserContext_Create(); ASSERT_IS_NOT_NULL(receiveUserContext, "Could not create receive user context"); if (receiveUserContext != NULL) { messageHandle = IoTHubMessage_CreateFromString(content); ASSERT_IS_NOT_NULL(messageHandle, "Could not create IoTHubMessage to send C2D messages to the device"); if (g_e2e_test_options.use_special_chars) { GenerateUniqueId(MSG_ID_SPECIAL, sizeof(MSG_ID_SPECIAL), receiveUserContext->message_id, sizeof(receiveUserContext->message_id)); iotHubMessageResult = IoTHubMessage_SetMessageId(messageHandle, receiveUserContext->message_id); } else { GenerateUniqueId(MSG_ID, sizeof(MSG_ID), receiveUserContext->message_id, sizeof(receiveUserContext->message_id)); iotHubMessageResult = IoTHubMessage_SetMessageId(messageHandle, receiveUserContext->message_id); } ASSERT_ARE_EQUAL(int, IOTHUB_MESSAGING_OK, iotHubMessageResult); if (g_e2e_test_options.use_special_chars) { GenerateUniqueId(MSG_CORRELATION_ID_SPECIAL, sizeof(MSG_CORRELATION_ID_SPECIAL), receiveUserContext->correlation_id, sizeof(receiveUserContext->correlation_id)); iotHubMessageResult = IoTHubMessage_SetCorrelationId(messageHandle, receiveUserContext->correlation_id); } else { GenerateUniqueId(MSG_CORRELATION_ID, sizeof(MSG_CORRELATION_ID), receiveUserContext->correlation_id, sizeof(receiveUserContext->correlation_id)); iotHubMessageResult = IoTHubMessage_SetCorrelationId(messageHandle, receiveUserContext->correlation_id); } ASSERT_ARE_EQUAL(int, IOTHUB_MESSAGING_OK, iotHubMessageResult); MAP_HANDLE mapHandle = IoTHubMessage_Properties(messageHandle); for (size_t i = 0; i < MSG_PROP_COUNT; i++) { if (g_e2e_test_options.use_special_chars) { ASSERT_ARE_EQUAL(MAP_RESULT, MAP_OK, Map_AddOrUpdate(mapHandle, MSG_PROP_KEYS_SPECIAL[i], MSG_PROP_VALS_SPECIAL[i])); } else { ASSERT_ARE_EQUAL(MAP_RESULT, MAP_OK, Map_AddOrUpdate(mapHandle, MSG_PROP_KEYS[i], MSG_PROP_VALS[i])); } } receiveUserContext->msgHandle = messageHandle; } return receiveUserContext; } static void service_send_c2d(IOTHUB_MESSAGING_CLIENT_HANDLE iotHubMessagingHandle, EXPECTED_RECEIVE_DATA* receiveUserContext, IOTHUB_PROVISIONED_DEVICE* deviceToUse) { IOTHUB_MESSAGING_RESULT iotHubMessagingResult; if (deviceToUse->moduleId) { iotHubMessagingResult = IOTHUB_MESSAGING_ERROR; ASSERT_FAIL("modules are not supported for sending messages"); } else { iotHubMessagingResult = IoTHubMessaging_SendAsync(iotHubMessagingHandle, deviceToUse->deviceId, receiveUserContext->msgHandle, sendCompleteCallback, receiveUserContext); } ASSERT_ARE_EQUAL(int, IOTHUB_MESSAGING_OK, iotHubMessagingResult, "IoTHubMessaging_SendAsync failed, could not send C2D message to the device"); } void client_wait_for_c2d_event_arrival(EXPECTED_RECEIVE_DATA* receiveUserContext) { time_t beginOperation, nowTime; beginOperation = time(NULL); while ( (nowTime = time(NULL)), (difftime(nowTime, beginOperation) < MAX_CLOUD_TRAVEL_TIME) //time box ) { ASSERT_ARE_EQUAL(LOCK_RESULT, LOCK_OK, Lock(receiveUserContext->lock)); if (receiveUserContext->wasFound) { (void)Unlock(receiveUserContext->lock); break; } (void)Unlock(receiveUserContext->lock); ThreadAPI_Sleep(100); } } static IOTHUB_MESSAGING_RESULT IoTHubMessaging_Open_with_retry(IOTHUB_MESSAGING_CLIENT_HANDLE messagingClientHandle, IOTHUB_OPEN_COMPLETE_CALLBACK openCompleteCallback, void* userContextCallback) { IOTHUB_MESSAGING_RESULT result = IOTHUB_MESSAGING_ERROR; for (int i = 0; i < RETRY_COUNT; i++) { result = IoTHubMessaging_Open(messagingClientHandle, openCompleteCallback, userContextCallback); if (result == IOTHUB_MESSAGING_OK) { break; } ThreadAPI_Sleep(1000 * RETRY_DELAY_SECONDS); } return result; } static void recv_message_test(IOTHUB_PROVISIONED_DEVICE* deviceToUse, IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol) { // arrange IOTHUB_SERVICE_CLIENT_AUTH_HANDLE iotHubServiceClientHandle; IOTHUB_MESSAGING_CLIENT_HANDLE iotHubMessagingHandle; IOTHUB_MESSAGING_RESULT iotHubMessagingResult; size_t client_conn_wait_time = 4000; EXPECTED_RECEIVE_DATA* receiveUserContext; clear_connection_status_info_flags(); // Create device client client_connect_to_hub(deviceToUse, protocol); // Make sure we have a connection ASSERT_IS_TRUE(wait_for_client_authenticated(client_conn_wait_time), "Connection Callback has not been called"); // Create receive context const char* msg_content; if (g_e2e_test_options.use_special_chars) { msg_content = MSG_CONTENT; } else { msg_content = MSG_CONTENT_SPECIAL; } receiveUserContext = service_create_c2d(msg_content); // Set callback setmessagecallback_on_device_or_module(receiveUserContext); if (test_protocol_type == TEST_HTTP) { // Http protocol does not have a connection callback, so we just need to wait here ThreadAPI_Sleep(2000); } else { // Let the iothub client establish the connection if (!wait_for_client_authenticated(client_conn_wait_time)) { // In some situations this will pass due to the device already being connected // Or being amqp. Make sure we flag this as a possible situation and continue LogInfo("Did not recieve the client connection callback within the alloted time <%lu> seconds", (unsigned long)client_conn_wait_time); } // Make sure we subscribe to all the events ThreadAPI_Sleep(3000); } // Create Service Client iotHubServiceClientHandle = IoTHubServiceClientAuth_CreateFromConnectionString(IoTHubAccount_GetIoTHubConnString(g_iothubAcctInfo)); ASSERT_IS_NOT_NULL(iotHubServiceClientHandle, "Could not initialize IoTHubServiceClient to send C2D messages to the device"); iotHubMessagingHandle = IoTHubMessaging_Create(iotHubServiceClientHandle); ASSERT_IS_NOT_NULL(iotHubMessagingHandle, "Could not initialize IoTHubMessaging to send C2D messages to the device"); #ifdef SET_TRUSTED_CERT_IN_SAMPLES ASSERT_ARE_EQUAL(int, IOTHUB_MESSAGING_OK, IoTHubMessaging_SetTrustedCert(iotHubMessagingHandle, certificates)); #endif // SET_TRUSTED_CERT_IN_SAMPLES iotHubMessagingResult = IoTHubMessaging_Open_with_retry(iotHubMessagingHandle, openCompleteCallback, (void*)"Context string for open"); ASSERT_ARE_EQUAL(int, IOTHUB_MESSAGING_OK, iotHubMessagingResult); // Send message service_send_c2d(iotHubMessagingHandle, receiveUserContext, deviceToUse); // wait for message to arrive on client client_wait_for_c2d_event_arrival(receiveUserContext); if (receiveUserContext->wasFound == false) { LogError("C2D message not received. message_id: %s, correlation_id: %s", receiveUserContext->message_id, receiveUserContext->correlation_id); } // assert ASSERT_IS_TRUE(receiveUserContext->wasFound, "Failure retrieving data from C2D"); // was found is written by the callback... // cleanup IoTHubMessaging_Close(iotHubMessagingHandle); IoTHubMessaging_Destroy(iotHubMessagingHandle); IoTHubServiceClientAuth_Destroy(iotHubServiceClientHandle); destroy_on_device_or_module(); ReceiveUserContext_Destroy(receiveUserContext); } void e2e_recv_message_test_sas(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol) { recv_message_test(IoTHubAccount_GetSASDevice(g_iothubAcctInfo), protocol); } void e2e_recv_message_test_x509(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol) { recv_message_test(IoTHubAccount_GetX509Device(g_iothubAcctInfo), protocol); } void e2e_c2d_with_svc_fault_ctrl(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol, const char* faultOperationType, const char* faultOperationCloseReason, const char* faultOperationDelayInSecs) { // arrange IOTHUB_SERVICE_CLIENT_AUTH_HANDLE iotHubServiceClientHandle; IOTHUB_MESSAGING_CLIENT_HANDLE iotHubMessagingHandle; IOTHUB_MESSAGING_RESULT iotHubMessagingResult; EXPECTED_RECEIVE_DATA* receiveUserContext; D2C_MESSAGE_HANDLE d2cMessage; IOTHUB_PROVISIONED_DEVICE* deviceToUse = IoTHubAccount_GetSASDevice(g_iothubAcctInfo); clear_connection_status_info_flags(); // Create device client client_connect_to_hub(deviceToUse, protocol); // Make sure we have a connection ASSERT_IS_TRUE(client_wait_for_connection_restored(), "Connection Callback has not been called"); // Create receive context receiveUserContext = service_create_c2d(MSG_CONTENT); // Set callback setmessagecallback_on_device_or_module(receiveUserContext); LogInfo("Sleeping 3 seconds to let SetMessageCallback() register with server."); ThreadAPI_Sleep(3000); LogInfo("Continue with service client message."); // Create Service Client iotHubServiceClientHandle = IoTHubServiceClientAuth_CreateFromConnectionString(IoTHubAccount_GetIoTHubConnString(g_iothubAcctInfo)); ASSERT_IS_NOT_NULL(iotHubServiceClientHandle, "Could not initialize IoTHubServiceClient to send C2D messages to the device"); iotHubMessagingHandle = IoTHubMessaging_Create(iotHubServiceClientHandle); ASSERT_IS_NOT_NULL(iotHubMessagingHandle, "Could not initialize IoTHubMessaging to send C2D messages to the device"); iotHubMessagingResult = IoTHubMessaging_Open_with_retry(iotHubMessagingHandle, openCompleteCallback, (void*)"Context string for open"); ASSERT_ARE_EQUAL(int, IOTHUB_MESSAGING_OK, iotHubMessagingResult); // Send message service_send_c2d(iotHubMessagingHandle, receiveUserContext, deviceToUse); // wait for message to arrive on client client_wait_for_c2d_event_arrival(receiveUserContext); // assert ASSERT_ARE_EQUAL(LOCK_RESULT, LOCK_OK, Lock(receiveUserContext->lock)); ASSERT_IS_TRUE(receiveUserContext->wasFound, "Failure retrieving data from C2D"); // was found is written by the callback... Unlock(receiveUserContext->lock); LogInfo("Send server fault control message..."); d2cMessage = send_error_injection_message(faultOperationType, faultOperationCloseReason, faultOperationDelayInSecs); LogInfo("Sleeping after sending fault injection..."); ThreadAPI_Sleep(3000); // Send message ASSERT_ARE_EQUAL(LOCK_RESULT, LOCK_OK, Lock(receiveUserContext->lock)); receiveUserContext->wasFound = false; Unlock(receiveUserContext->lock); service_send_c2d(iotHubMessagingHandle, receiveUserContext, deviceToUse); // wait for message to arrive on client client_wait_for_c2d_event_arrival(receiveUserContext); // assert ASSERT_ARE_EQUAL(LOCK_RESULT, LOCK_OK, Lock(receiveUserContext->lock)); ASSERT_IS_TRUE(receiveUserContext->wasFound, "Failure retrieving data from C2D"); // was found is written by the callback... Unlock(receiveUserContext->lock); // cleanup IoTHubMessaging_Close(iotHubMessagingHandle); IoTHubMessaging_Destroy(iotHubMessagingHandle); IoTHubServiceClientAuth_Destroy(iotHubServiceClientHandle); destroy_on_device_or_module(); ReceiveUserContext_Destroy(receiveUserContext); destroy_d2c_message_handle(d2cMessage); } //*********************************************************** // D2C //*********************************************************** void e2e_d2c_svc_fault_ctrl_kill_TCP_connection(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol) { e2e_d2c_with_svc_fault_ctrl(protocol, "KillTcp", "boom", "1"); } void e2e_d2c_svc_fault_ctrl_kill_TCP_connection_with_transport_status_check(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol) { e2e_d2c_with_svc_fault_ctrl_with_transport_status(protocol, "KillTcp", "boom", "1"); } void e2e_d2c_svc_fault_ctrl_AMQP_kill_connection(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol) { e2e_d2c_with_svc_fault_ctrl_with_transport_status(protocol, "KillAmqpConnection", "Connection fault", "1"); } void e2e_d2c_svc_fault_ctrl_AMQP_kill_session(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol) { e2e_d2c_with_svc_fault_ctrl_with_transport_status(protocol, "KillAmqpSession", "Session fault", "1"); } void e2e_d2c_svc_fault_ctrl_AMQP_kill_CBS_request_link(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol) { e2e_d2c_with_svc_fault_ctrl_with_transport_status(protocol, "KillAmqpCBSLinkReq", "CBS request link fault", "1"); } void e2e_d2c_svc_fault_ctrl_AMQP_kill_CBS_response_link(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol) { e2e_d2c_with_svc_fault_ctrl_with_transport_status(protocol, "KillAmqpCBSLinkResp", "CBS response link fault", "1"); } void e2e_d2c_svc_fault_ctrl_AMQP_kill_D2C_link(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol) { e2e_d2c_with_svc_fault_ctrl_with_transport_status(protocol, "KillAmqpD2CLink", "D2C link fault", "1"); } void e2e_d2c_svc_fault_ctrl_AMQP_kill_C2D_link(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol) { e2e_d2c_with_svc_fault_ctrl_with_transport_status(protocol, "KillAmqpC2DLink", "C2D link fault", "1"); } void e2e_d2c_svc_fault_ctrl_AMQP_throttling_reconnect(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol) { e2e_d2c_with_svc_fault_ctrl_error_message_callback(protocol, "InvokeThrottling", "20", "1", true, false); } void e2e_d2c_svc_fault_ctrl_AMQP_message_quota_exceeded(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol) { e2e_d2c_with_svc_fault_ctrl_error_message_callback(protocol, "InvokeMaxMessageQuota", "20", "1", true, false); } void e2e_d2c_svc_fault_ctrl_AMQP_auth_error(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol) { e2e_d2c_with_svc_fault_ctrl_error_message_callback(protocol, "InvokeAuthError", "20", "1", true, false); } void e2e_d2c_svc_fault_ctrl_AMQP_shut_down(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol) { e2e_d2c_with_svc_fault_ctrl_with_transport_status(protocol, "ShutDownAmqp", "byebye", "1"); } void e2e_d2c_svc_fault_ctrl_MQTT_throttling_reconnect(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol) { e2e_d2c_with_svc_fault_ctrl_error_message_callback(protocol, "InvokeThrottling", "20", "1", false, true); } void e2e_d2c_svc_fault_ctrl_MQTT_message_quota_exceeded(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol) { e2e_d2c_with_svc_fault_ctrl_error_message_callback(protocol, "InvokeMaxMessageQuota", "20", "1", false, true); } void e2e_d2c_svc_fault_ctrl_MQTT_auth_error(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol) { e2e_d2c_with_svc_fault_ctrl_error_message_callback(protocol, "InvokeAuthError", "20", "1", false, true); } void e2e_d2c_svc_fault_ctrl_MQTT_shut_down(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol) { e2e_d2c_with_svc_fault_ctrl_with_transport_status(protocol, "ShutDownMqtt", "byebye", "1"); } //*********************************************************** // C2D //*********************************************************** void e2e_c2d_svc_fault_ctrl_kill_TCP_connection(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol) { e2e_c2d_with_svc_fault_ctrl(protocol, "KillTcp", "boom", "1"); } void e2e_c2d_svc_fault_ctrl_AMQP_kill_connection(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol) { e2e_c2d_with_svc_fault_ctrl(protocol, "KillAmqpConnection", "Connection fault", "1"); } void e2e_c2d_svc_fault_ctrl_AMQP_kill_session(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol) { e2e_c2d_with_svc_fault_ctrl(protocol, "KillAmqpSession", "Session fault", "1"); } void e2e_c2d_svc_fault_ctrl_AMQP_kill_CBS_request_link(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol) { e2e_c2d_with_svc_fault_ctrl(protocol, "KillAmqpCBSLinkReq", "CBS request link fault", "1"); } void e2e_c2d_svc_fault_ctrl_AMQP_kill_CBS_response_link(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol) { e2e_c2d_with_svc_fault_ctrl(protocol, "KillAmqpCBSLinkResp", "CBS response link fault", "1"); } void e2e_c2d_svc_fault_ctrl_AMQP_kill_D2C_link(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol) { e2e_c2d_with_svc_fault_ctrl(protocol, "KillAmqpc2dLink", "c2d link fault", "1"); } void e2e_c2d_svc_fault_ctrl_AMQP_kill_C2D_link(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol) { e2e_c2d_with_svc_fault_ctrl(protocol, "KillAmqpC2DLink", "C2D link fault", "1"); } void e2e_c2d_svc_fault_ctrl_AMQP_shut_down(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol) { e2e_c2d_with_svc_fault_ctrl(protocol, "ShutDownAmqp", "byebye", "1"); } void e2e_c2d_svc_fault_ctrl_throttling_reconnect(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol) { e2e_c2d_with_svc_fault_ctrl(protocol, "InvokeThrottling", "20", "1"); } void e2e_c2d_svc_fault_ctrl_message_quota_exceeded(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol) { e2e_c2d_with_svc_fault_ctrl(protocol, "InvokeMaxMessageQuota", "20", "1"); } void e2e_c2d_svc_fault_ctrl_auth_error(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol) { e2e_c2d_with_svc_fault_ctrl(protocol, "InvokeAuthError", "20", "1"); } void e2e_c2d_svc_fault_ctrl_MQTT_shut_down(IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol) { e2e_c2d_with_svc_fault_ctrl(protocol, "ShutDownMqtt", "byebye", "1"); }