const char* IoTHubAccount_GetEventhubAccessKey(void)
{
    char *iothub_connection_string;
    static char access_key[128];

    if ((iothub_connection_string = IoTHubAccount_GetIoTHubConnString()) != NULL)
    {
        STRING_HANDLE iothub_connection_string_str;

        if((iothub_connection_string_str = STRING_construct(iothub_connection_string)) != NULL)
        {
            STRING_TOKENIZER_HANDLE tokenizer;

            if ((tokenizer = STRING_TOKENIZER_create(iothub_connection_string_str)) != NULL)
            {
                STRING_HANDLE tokenString;

                if ((tokenString = STRING_new()) != NULL)
                {
                    STRING_HANDLE valueString;

                    if ((valueString = STRING_new()) != NULL)
                    {
                        while ((STRING_TOKENIZER_get_next_token(tokenizer, tokenString, "=") == 0))
                        {
                            char tokenValue[128];
                            strcpy(tokenValue, STRING_c_str(tokenString));

                            if (STRING_TOKENIZER_get_next_token(tokenizer, tokenString, ";") != 0)
                            {
                                break;
                            }

                            if (strcmp(tokenValue, "SharedAccessKey") == 0)
                            {
                                strcpy(access_key, STRING_c_str(tokenString));
                                break;
                            }
                        }

                        STRING_delete(valueString);
                    }

                    STRING_delete(tokenString);
                }

                STRING_TOKENIZER_destroy(tokenizer);
            }

            STRING_delete(iothub_connection_string_str);
        }
    }

    return access_key;
}
const char* IoTHubAccount_GetIoTHubSuffix(void)
{
    static char iothub_suffix[256];
    char *iothub_connection_string;

    iothub_connection_string = IoTHubAccount_GetIoTHubConnString();

    if (iothub_connection_string != NULL)
    {
        sscanf(iothub_connection_string, "HostName=%*[^.].%[^;/]", iothub_suffix);
    }

    return iothub_suffix;
}
const char* IoTHubAccount_GetIoTHubName(void)
{
    static char iothub_name[128];

    char *iothub_connection_string;

    iothub_connection_string = IoTHubAccount_GetIoTHubConnString();

    if (iothub_connection_string != NULL)
    {
        sscanf(iothub_connection_string, "HostName=%[^.]", iothub_name);
    }

    return iothub_name;
}
static void RecvMessage(IOTHUB_PROVISIONED_DEVICE* deviceToUse)
{
    // arrange
    IOTHUB_CLIENT_HANDLE iotHubClientHandle;

    IOTHUB_SERVICE_CLIENT_AUTH_HANDLE iotHubServiceClientHandle;
    IOTHUB_MESSAGING_CLIENT_HANDLE iotHubMessagingHandle;
    IOTHUB_MESSAGING_RESULT iotHubMessagingResult;
    IOTHUB_MESSAGE_RESULT iotHubMessageResult;

    EXPECTED_RECEIVE_DATA* receiveUserContext;
    IOTHUB_MESSAGE_HANDLE messageHandle;

    // act
    IoTHub_Init();

    // Create Service Client
    iotHubServiceClientHandle = IoTHubServiceClientAuth_CreateFromConnectionString(IoTHubAccount_GetIoTHubConnString(g_iothubAcctInfo1));
    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(iotHubMessagingHandle, openCompleteCallback, (void*)"Context string for open");
    ASSERT_ARE_EQUAL(int, IOTHUB_MESSAGING_OK, iotHubMessagingResult);

    // Create user context and message
    receiveUserContext = ReceiveUserContext_Create();
    ASSERT_IS_NOT_NULL(receiveUserContext, "Could not create receive user context");

    messageHandle = IoTHubMessage_CreateFromString(MSG_CONTENT1);

    ASSERT_IS_NOT_NULL(messageHandle, "Could not create IoTHubMessage to send C2D messages to the device");

    iotHubMessageResult = IoTHubMessage_SetMessageId(messageHandle, MSG_ID1);
    ASSERT_ARE_EQUAL(int, IOTHUB_MESSAGING_OK, iotHubMessageResult);

    iotHubMessageResult = IoTHubMessage_SetCorrelationId(messageHandle, MSG_CORRELATION_ID1);
    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 (Map_AddOrUpdate(mapHandle, MSG_PROP_KEYS[i], MSG_PROP_VALS[i]) != MAP_OK)
        {
            (void)printf("ERROR: Map_AddOrUpdate failed for property %zu!\r\n", i);
        }
    }

    iotHubMessagingResult = IoTHubMessaging_SendAsync(iotHubMessagingHandle, deviceToUse->deviceId, messageHandle, sendCompleteCallback, receiveUserContext);
    ASSERT_ARE_EQUAL(int, IOTHUB_MESSAGING_OK, iotHubMessagingResult, "IoTHubMessaging_SendAsync failed, could not send C2D message to the device");
    iotHubClientHandle = IoTHubClient_CreateFromConnectionString(deviceToUse->connectionString, HTTP_Protocol);
    ASSERT_IS_NOT_NULL(iotHubClientHandle, "Failure creating Iothub Client");

    if (deviceToUse->howToCreate == IOTHUB_ACCOUNT_AUTH_X509) {
        IOTHUB_CLIENT_RESULT result;
        result = IoTHubClient_SetOption(iotHubClientHandle, OPTION_X509_CERT, deviceToUse->certificate);
        ASSERT_ARE_EQUAL(IOTHUB_CLIENT_RESULT, IOTHUB_CLIENT_OK, result, "Could not set the device x509 certificate");
        result = IoTHubClient_SetOption(iotHubClientHandle, OPTION_X509_PRIVATE_KEY, deviceToUse->primaryAuthentication);
        ASSERT_ARE_EQUAL(IOTHUB_CLIENT_RESULT, IOTHUB_CLIENT_OK, result, "Could not set the device x509 privateKey");
    }

    IOTHUB_CLIENT_RESULT result = IoTHubClient_SetMessageCallback(iotHubClientHandle, ReceiveMessageCallback, receiveUserContext);
    ASSERT_ARE_EQUAL(IOTHUB_CLIENT_RESULT, IOTHUB_CLIENT_OK, result, "Failure setting message callback");

    unsigned int minimumPollingTime = 1; /*because it should not wait*/
    if (IoTHubClient_SetOption(iotHubClientHandle, OPTION_MIN_POLLING_TIME, &minimumPollingTime) != IOTHUB_CLIENT_OK)
    {
        printf("failure to set option \"MinimumPollingTime\"\r\n");
    }

    time_t beginOperation, nowTime;
    beginOperation = time(NULL);
    while (
        (
        (nowTime = time(NULL)),
            (difftime(nowTime, beginOperation) < MAX_CLOUD_TRAVEL_TIME) //time box
            )
        )
    {
        if (Lock(receiveUserContext->lock) != LOCK_OK)
        {
            ASSERT_FAIL("unable ot lock");
        }
        else
        {
            if (receiveUserContext->wasFound)
            {
                (void)Unlock(receiveUserContext->lock);
                break;
            }
            (void)Unlock(receiveUserContext->lock);
        }
        ThreadAPI_Sleep(100);
    }

    // assert
    ASSERT_IS_TRUE(receiveUserContext->wasFound, "Failure retrieving message that was sent to IotHub."); // was found is written by the callback...

    // cleanup
    IoTHubMessage_Destroy(messageHandle);
    IoTHubMessaging_Close(iotHubMessagingHandle);
    IoTHubMessaging_Destroy(iotHubMessagingHandle);
    IoTHubServiceClientAuth_Destroy(iotHubServiceClientHandle);

    IoTHubClient_Destroy(iotHubClientHandle);
    ReceiveUserContext_Destroy(receiveUserContext);
}
static void SendEvent(IOTHUB_PROVISIONED_DEVICE* deviceToUse)
{
    // arrange
    IOTHUB_CLIENT_HANDLE iotHubClientHandle;
    IOTHUB_MESSAGE_HANDLE msgHandle;

    EXPECTED_SEND_DATA* sendData = EventData_Create();
    ASSERT_IS_NOT_NULL(sendData, "Failure creating data to be sent");

    // Send the Event
    {
        IOTHUB_CLIENT_RESULT result;
        // Create the IoT Hub Data
        iotHubClientHandle = IoTHubClient_CreateFromConnectionString(deviceToUse->connectionString, HTTP_Protocol);
        ASSERT_IS_NOT_NULL(iotHubClientHandle, "Failure creating IothubClient handle");

        msgHandle = IoTHubMessage_CreateFromByteArray((const unsigned char*)sendData->expectedString, strlen(sendData->expectedString));
        ASSERT_IS_NOT_NULL(msgHandle, "Failure to create message handle");

        if (deviceToUse->howToCreate == IOTHUB_ACCOUNT_AUTH_X509) {
            result = IoTHubClient_SetOption(iotHubClientHandle, OPTION_X509_CERT, deviceToUse->certificate);
            ASSERT_ARE_EQUAL(IOTHUB_CLIENT_RESULT, IOTHUB_CLIENT_OK, result, "Could not set the device x509 certificate");
            result = IoTHubClient_SetOption(iotHubClientHandle, OPTION_X509_PRIVATE_KEY, deviceToUse->primaryAuthentication);
            ASSERT_ARE_EQUAL(IOTHUB_CLIENT_RESULT, IOTHUB_CLIENT_OK, result, "Could not set the device x509 privateKey");
        }

        // act
        result = IoTHubClient_SendEventAsync(iotHubClientHandle, msgHandle, ReceiveConfirmationCallback, sendData);
        ASSERT_ARE_EQUAL(IOTHUB_CLIENT_RESULT, IOTHUB_CLIENT_OK, result, "Failure calling IoTHubClient_SendEventAsync");
    }

    time_t beginOperation, nowTime;
    beginOperation = time(NULL);
    while (
        (nowTime = time(NULL)),
        (difftime(nowTime, beginOperation) < MAX_CLOUD_TRAVEL_TIME) // time box
        )
    {
        if (Lock(sendData->lock) != LOCK_OK)
        {
            ASSERT_FAIL("unable to lock");
        }
        else
        {
            if (sendData->dataWasRecv)
            {
                Unlock(sendData->lock);
                break;
            }
            Unlock(sendData->lock);
        }
        ThreadAPI_Sleep(100);
    }

    if (Lock(sendData->lock) != LOCK_OK)
    {
        ASSERT_FAIL("unable to lock");
    }
    else
    {
        ASSERT_IS_TRUE(sendData->dataWasRecv, "Failure sending data to IotHub"); // was found is written by the callback...
        (void)Unlock(sendData->lock);
    }

    {
        IOTHUB_TEST_HANDLE iotHubTestHandle = IoTHubTest_Initialize(IoTHubAccount_GetEventHubConnectionString(g_iothubAcctInfo1), IoTHubAccount_GetIoTHubConnString(g_iothubAcctInfo1), deviceToUse->deviceId, IoTHubAccount_GetEventhubListenName(g_iothubAcctInfo1), IoTHubAccount_GetEventhubAccessKey(g_iothubAcctInfo1), IoTHubAccount_GetSharedAccessSignature(g_iothubAcctInfo1), IoTHubAccount_GetEventhubConsumerGroup(g_iothubAcctInfo1));
        ASSERT_IS_NOT_NULL(iotHubTestHandle);

        IOTHUB_TEST_CLIENT_RESULT result = IoTHubTest_ListenForEventForMaxDrainTime(iotHubTestHandle, IoTHubCallback, IoTHubAccount_GetIoTHubPartitionCount(g_iothubAcctInfo1), sendData);
        ASSERT_ARE_EQUAL(IOTHUB_TEST_CLIENT_RESULT, IOTHUB_TEST_CLIENT_OK, result);

        IoTHubTest_Deinit(iotHubTestHandle);
    }

    // assert
    ASSERT_IS_TRUE(sendData->wasFound, "Failure receiving data from eventhub"); // was found is written by the callback...*/

                                                                                         // cleanup
    IoTHubMessage_Destroy(msgHandle);

    IoTHubClient_Destroy(iotHubClientHandle);
    EventData_Destroy(sendData);
}
static int sendEventLoop(IOTHUB_CLIENT_HANDLE iotHubClientHandle, LONGHAUL_SEND_TEST_STATE* test_state)
{
	int result = 0;

#ifndef MBED_BUILD_TIMESTAMP
	IOTHUB_TEST_HANDLE iotHubTestHandle;

	if ((iotHubTestHandle = IoTHubTest_Initialize(IoTHubAccount_GetEventHubConnectionString(g_iothubAcctInfo), IoTHubAccount_GetIoTHubConnString(g_iothubAcctInfo), IoTHubAccount_GetDeviceId(g_iothubAcctInfo), IoTHubAccount_GetDeviceKey(g_iothubAcctInfo), IoTHubAccount_GetEventhubListenName(g_iothubAcctInfo), IoTHubAccount_GetEventhubAccessKey(g_iothubAcctInfo), IoTHubAccount_GetSharedAccessSignature(g_iothubAcctInfo), IoTHubAccount_GetEventhubConsumerGroup(g_iothubAcctInfo))) == NULL)
	{
		LogError("Failed initializing the Event Hub test client.");
		result = __LINE__;
	}
	else
	{
		initializeSendStatistics(&test_state->statistics);
#endif
		time_t testInitialTime;

		if ((testInitialTime = time(NULL)) == INDEFINITE_TIME)
		{
			LogError("Failed setting the initial time of the test (time(NULL) failed).");
			result = __LINE__;
		}
		else
		{
			time_t loopIterationStartTimeInSeconds, loopIterationEndTimeInSeconds;
			double loopIterationTotalTime;
			time_t testCurrentTime;

			while (result == 0)
			{
				if ((testCurrentTime = time(NULL)) == INDEFINITE_TIME)
				{
					LogError("Failed setting the current time of the test (time(NULL) failed)");
					result = __LINE__;
					break;
				}
				else if (difftime(testCurrentTime, testInitialTime) > test_state->profile->totalRunTimeInSeconds)
				{
					LogInfo("Test run for the expected duration (%d seconds)", test_state->profile->totalRunTimeInSeconds);
					break;
				}

				if ((loopIterationStartTimeInSeconds = time(NULL)) == INDEFINITE_TIME)
				{
					LogError("Failed setting the initial time of the send/receive loop (time(NULL) failed)");
					result = __LINE__;
					break;
				}

				if (test_state->timeUntilNextSendEventInSeconds <= 0.0)
				{
					EXPECTED_SEND_DATA* sendData;
					IOTHUB_MESSAGE_HANDLE msgHandle;

					if ((sendData = EventData_Create()) == NULL)
					{
						LogError("Failed creating EXPECTED_SEND_DATA.");
						result = __LINE__;
					}
					else
					{
						if ((msgHandle = IoTHubMessage_CreateFromByteArray((const unsigned char*)sendData->expectedString, strlen(sendData->expectedString))) == NULL)
						{
							LogError("Failed creating IOTHUB_MESSAGE_HANDLE.");
							result = __LINE__;
						}
						else
						{
							if (IoTHubClient_SendEventAsync(iotHubClientHandle, msgHandle, SendConfirmationCallback, sendData) != IOTHUB_CLIENT_OK)
							{
								LogError("Call to IoTHubClient_SendEventAsync failed.");
								result = __LINE__;
							}
							else
							{
								bool dataWasSent = false;
								time_t beginOperation, nowTime;

								if ((beginOperation = time(NULL)) == INDEFINITE_TIME)
								{
									LogError("Failed setting beginOperation (time(NULL) failed).");
									result = __LINE__;
								}
								else
								{
									do
									{
										if (Lock(sendData->lock) != LOCK_OK)
										{
											LogError("Unable to lock to flag event sent.");
											break;
										}
										else
										{
											if (sendData->dataWasSent)
											{
												dataWasSent = true;
												Unlock(sendData->lock);
												break;
											}
											Unlock(sendData->lock);
										}
										ThreadAPI_Sleep(100);

										if ((nowTime = time(NULL)) == INDEFINITE_TIME)
										{
											LogError("Failed setting nowTime (time(NULL) failed).");
											result = __LINE__;
											break;
										}
									} while (difftime(nowTime, beginOperation) < MAX_CLOUD_TRAVEL_TIME);

									if (!dataWasSent)
									{
										LogError("Failure sending data to IotHub");
										result = __LINE__;
									}
									else
									{
#ifdef MBED_BUILD_TIMESTAMP
										if (verifyEventReceivedByHub(sendData) != 0)
										{
											result = __LINE__;
										}
										else
										{
#else
										if (verifyEventReceivedByHub(sendData, iotHubTestHandle) != 0)
										{
											result = __LINE__;
										}
										else
										{
											computeSendStatistics(&test_state->statistics, sendData);
#endif
											test_state->timeUntilNextSendEventInSeconds = test_state->profile->eventFrequencyInSecs[test_state->sendFrequencyIndex];

											if ((test_state->sendFrequencyIndex + 1) < test_state->profile->numberOfEventFrequencyVariations) test_state->sendFrequencyIndex++;
										}
									}
								}
							}

							IoTHubMessage_Destroy(msgHandle);
						}

						EventData_Destroy(sendData);
					}
				}

				ThreadAPI_Sleep(500);

				if ((loopIterationEndTimeInSeconds = time(NULL)) == INDEFINITE_TIME)
				{
					LogError("Failed setting the end time of the send loop iteration (time(NULL) failed)");
					result = __LINE__;
				}
				else
				{
					loopIterationTotalTime = difftime(loopIterationEndTimeInSeconds, loopIterationStartTimeInSeconds);
					test_state->timeUntilNextSendEventInSeconds -= loopIterationTotalTime;
				}
			} // While loop
		}
			
#ifndef MBED_BUILD_TIMESTAMP
		printSendStatistics(&test_state->statistics);

		IoTHubTest_Deinit(iotHubTestHandle);
	}
#endif

	return result;
}

static int receiveMessageLoop(IOTHUB_CLIENT_HANDLE iotHubClientHandle, LONGHAUL_RECEIVE_TEST_STATE* test_state)
{
	int result = 0;

#ifndef MBED_BUILD_TIMESTAMP
	IOTHUB_TEST_HANDLE iotHubTestHandle;

	if ((iotHubTestHandle = IoTHubTest_Initialize(IoTHubAccount_GetEventHubConnectionString(g_iothubAcctInfo), IoTHubAccount_GetIoTHubConnString(g_iothubAcctInfo), IoTHubAccount_GetDeviceId(g_iothubAcctInfo), IoTHubAccount_GetDeviceKey(g_iothubAcctInfo), IoTHubAccount_GetEventhubListenName(g_iothubAcctInfo), IoTHubAccount_GetEventhubAccessKey(g_iothubAcctInfo), IoTHubAccount_GetSharedAccessSignature(g_iothubAcctInfo), IoTHubAccount_GetEventhubConsumerGroup(g_iothubAcctInfo))) == NULL)
	{
		LogError("Failed initializing the Event Hub test client.");
		result = __LINE__;
	}
	else
	{
		initializeReceiveStatistics(&test_state->statistics);
#endif
		time_t testInitialTime;

		if ((testInitialTime = time(NULL)) == INDEFINITE_TIME)
		{
			LogError("Failed setting the initial time of the test (time(NULL) failed).");
			result = __LINE__;
		}
		else
		{
			time_t loopIterationStartTimeInSeconds, loopIterationEndTimeInSeconds;
			double loopIterationTotalTime;
			time_t testCurrentTime;

			while (result == 0)
			{
				if ((testCurrentTime = time(NULL)) == INDEFINITE_TIME)
				{
					LogError("Failed setting the current time of the test (time(NULL) failed)");
					result = __LINE__;
					break;
				}
				else if (difftime(testCurrentTime, testInitialTime) > test_state->profile->totalRunTimeInSeconds)
				{
					LogInfo("Test run for the expected duration (%d seconds)", test_state->profile->totalRunTimeInSeconds);
					break;
				}

				if ((loopIterationStartTimeInSeconds = time(NULL)) == INDEFINITE_TIME)
				{
					LogError("Failed setting the initial time of the receive loop iteration (time(NULL) failed)");
					result = __LINE__;
					break;
				}

				if (test_state->timeUntilNextReceiveMessageInSeconds <= 0.0)
				{
					EXPECTED_RECEIVE_DATA* receiveData;

					if ((receiveData = MessageData_Create()) == NULL)
					{
						LogError("Failed creating EXPECTED_RECEIVE_DATA.");
						result = __LINE__;
					}
					else
					{
						IOTHUB_TEST_CLIENT_RESULT sendResult;

						if (IoTHubClient_SetMessageCallback(iotHubClientHandle, ReceiveMessageCallback, receiveData) != IOTHUB_CLIENT_OK)
						{
							LogError("Call to IoTHubClient_SetMessageCallback failed.");
							result = __LINE__;
						}
						else if ((sendResult = IoTHubTest_SendMessage(iotHubTestHandle, (const unsigned char*)receiveData->data, receiveData->dataSize)) != IOTHUB_TEST_CLIENT_OK)
						{
							LogError("Call to IoTHubTest_SendMessage failed (%i).", sendResult);
							result = __LINE__;
						}
						else
						{
							if ((receiveData->timeSent = time(NULL)) == INDEFINITE_TIME)
							{
								LogError("Failed setting receiveData->timeSent (time(NULL) failed)");
							}

							time_t beginOperation, nowTime;
							
							if ((beginOperation = time(NULL)) == INDEFINITE_TIME)
							{
								LogError("Failed setting beginOperation (time(NULL) failed).");
								result = __LINE__;
							}
							else
							{
								do
								{
									if (Lock(receiveData->lock) != LOCK_OK)
									{
										LogError("Unable to lock to verify if C2D message has been received.");
										result = __LINE__;
										break;
									}
									else
									{
										if (receiveData->receivedByClient)
										{
											(void)Unlock(receiveData->lock);
											break;
										}
										(void)Unlock(receiveData->lock);
									}
									ThreadAPI_Sleep(100);

									if ((nowTime = time(NULL)) == INDEFINITE_TIME)
									{
										LogError("Failed setting nowTime (time(NULL) failed).");
										result = __LINE__;
										break;
									}
								} while (difftime(nowTime, beginOperation) < MAX_CLOUD_TRAVEL_TIME);

								if (result == 0)
								{
									if (!receiveData->receivedByClient)
									{
										LogError("Failure retrieving data from C2D");
										result = __LINE__;
									}
									else
									{
#ifndef MBED_BUILD_TIMESTAMP
										computeReceiveStatistics(&test_state->statistics, receiveData);
#endif
										test_state->timeUntilNextReceiveMessageInSeconds = test_state->profile->messageFrequencyInSecs[test_state->receiveFrequencyIndex];

										if ((test_state->receiveFrequencyIndex + 1) < test_state->profile->numberOfMessageFrequencyVariations) test_state->receiveFrequencyIndex++;
									}
								}
							}
						}

						MessageData_Destroy(receiveData);
					}
				}

				ThreadAPI_Sleep(500);

				if ((loopIterationEndTimeInSeconds = time(NULL)) == INDEFINITE_TIME)
				{
					LogError("Failed setting the end time of the receive loop iteration (time(NULL) failed)");
					result = __LINE__;
				}
				else
				{
					loopIterationTotalTime = difftime(loopIterationEndTimeInSeconds, loopIterationStartTimeInSeconds);
					test_state->timeUntilNextReceiveMessageInSeconds -= loopIterationTotalTime;
				}
			} // While loop
		}

#ifndef MBED_BUILD_TIMESTAMP
		printReceiveStatistics(&test_state->statistics);

		IoTHubTest_Deinit(iotHubTestHandle);
		}
#endif

	return result;
}