Microsoft Azure IoTHub client libraries
Dependents: sht15_remote_monitoring RobotArmDemo iothub_client_sample_amqp f767zi_mqtt ... more
This library implements the Microsoft Azure IoTHub client library. The code is replicated from https://github.com/Azure/azure-iot-sdks
Diff: iothub_client.c
- Revision:
- 37:18310e4d888d
- Parent:
- 35:ceed20da4ba6
- Child:
- 38:a05929a75111
diff -r 67300d5a4c1f -r 18310e4d888d iothub_client.c --- a/iothub_client.c Fri Mar 11 17:00:59 2016 -0800 +++ b/iothub_client.c Fri Mar 25 16:00:25 2016 -0700 @@ -13,6 +13,7 @@ #include "crt_abstractions.h" #include "iothub_client.h" #include "iothub_client_ll.h" +#include "iothubtransport.h" #include "threadapi.h" #include "lock.h" #include "iot_logging.h" @@ -20,6 +21,7 @@ typedef struct IOTHUB_CLIENT_INSTANCE_TAG { IOTHUB_CLIENT_LL_HANDLE IoTHubClientLLHandle; + TRANSPORT_HANDLE TransportHandle; THREAD_HANDLE ThreadHandle; LOCK_HANDLE LockHandle; sig_atomic_t StopThread; @@ -32,35 +34,66 @@ { IOTHUB_CLIENT_INSTANCE* iotHubClientInstance = (IOTHUB_CLIENT_INSTANCE*)threadArgument; - /* Codes_SRS_IOTHUBCLIENT_01_038: [The thread shall exit when IoTHubClient_Destroy is called.] */ - while (!iotHubClientInstance->StopThread) + while (1) { - /* Codes_SRS_IOTHUBCLIENT_01_039: [All calls to IoTHubClient_LL_DoWork shall be protected by the lock created in IotHubClient_Create.] */ - /* Codes_SRS_IOTHUBCLIENT_01_040: [If acquiring the lock fails, IoTHubClient_LL_DoWork shall not be called.] */ if (Lock(iotHubClientInstance->LockHandle) == LOCK_OK) { - /* Codes_SRS_IOTHUBCLIENT_01_037: [The thread created by IoTHubClient_SendEvent or IoTHubClient_SetMessageCallback shall call IoTHubClient_LL_DoWork every 1 ms.] */ - IoTHubClient_LL_DoWork(iotHubClientInstance->IoTHubClientLLHandle); - /* Codes_SRS_IOTHUBCLIENT_01_039: [All calls to IoTHubClient_LL_DoWork shall be protected by the lock created in IotHubClient_Create.] */ - Unlock(iotHubClientInstance->LockHandle); + /*Codes_SRS_IOTHUBCLIENT_01_038: [ The thread shall exit when IoTHubClient_Destroy is called. ]*/ + if (iotHubClientInstance->StopThread) + { + (void)Unlock(iotHubClientInstance->LockHandle); + break; /*gets out of the thread*/ + } + else + { + /* Codes_SRS_IOTHUBCLIENT_01_037: [The thread created by IoTHubClient_SendEvent or IoTHubClient_SetMessageCallback shall call IoTHubClient_LL_DoWork every 1 ms.] */ + /* Codes_SRS_IOTHUBCLIENT_01_039: [All calls to IoTHubClient_LL_DoWork shall be protected by the lock created in IotHubClient_Create.] */ + IoTHubClient_LL_DoWork(iotHubClientInstance->IoTHubClientLLHandle); + (void)Unlock(iotHubClientInstance->LockHandle); + } } - - ThreadAPI_Sleep(1); + else + { + /*Codes_SRS_IOTHUBCLIENT_01_040: [If acquiring the lock fails, IoTHubClient_LL_DoWork shall not be called.]*/ + /*no code, shall retry*/ + } + (void)ThreadAPI_Sleep(1); } - + return 0; } -static void StartWorkerThreadIfNeeded(IOTHUB_CLIENT_INSTANCE* iotHubClientInstance) +static IOTHUB_CLIENT_RESULT StartWorkerThreadIfNeeded(IOTHUB_CLIENT_INSTANCE* iotHubClientInstance) { - if (iotHubClientInstance->ThreadHandle == NULL) - { - iotHubClientInstance->StopThread = 0; - if (ThreadAPI_Create(&iotHubClientInstance->ThreadHandle, ScheduleWork_Thread, iotHubClientInstance) != THREADAPI_OK) - { - iotHubClientInstance->ThreadHandle = NULL; - } - } + IOTHUB_CLIENT_RESULT result; + if (iotHubClientInstance->TransportHandle == NULL) + { + if (iotHubClientInstance->ThreadHandle == NULL) + { + iotHubClientInstance->StopThread = 0; + if (ThreadAPI_Create(&iotHubClientInstance->ThreadHandle, ScheduleWork_Thread, iotHubClientInstance) != THREADAPI_OK) + { + iotHubClientInstance->ThreadHandle = NULL; + result = IOTHUB_CLIENT_ERROR; + } + else + { + result = IOTHUB_CLIENT_OK; + } + } + else + { + result = IOTHUB_CLIENT_OK; + } + } + else + { + /*Codes_SRS_IOTHUBCLIENT_17_012: [ If the transport connection is shared, the thread shall be started by calling IoTHubTransport_StartWorkerThread. ]*/ + /*Codes_SRS_IOTHUBCLIENT_17_011: [ If the transport connection is shared, the thread shall be started by calling IoTHubTransport_StartWorkerThread*/ + + result = IoTHubTransport_StartWorkerThread(iotHubClientInstance->TransportHandle, iotHubClientInstance); + } + return result; } IOTHUB_CLIENT_HANDLE IoTHubClient_CreateFromConnectionString(const char* connectionString, IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol) @@ -88,32 +121,34 @@ } else { - /* Codes_SRS_IOTHUBCLIENT_12_005: [IoTHubClient_CreateFromConnectionString shall create a lock object to be used later for serializing IoTHubClient calls] */ - result->LockHandle = Lock_Init(); - if (result->LockHandle == NULL) - { - /* Codes_SRS_IOTHUBCLIENT_12_009: [If lock creation failed, IoTHubClient_CreateFromConnectionString shall do clean up and return NULL] */ - free(result); - result = NULL; - LogError("Lock_Init failed\r\n"); - } - else - { - /* Codes_SRS_IOTHUBCLIENT_12_006: [IoTHubClient_CreateFromConnectionString shall instantiate a new IoTHubClient_LL instance by calling IoTHubClient_LL_CreateFromConnectionString and passing the connectionString] */ - result->IoTHubClientLLHandle = IoTHubClient_LL_CreateFromConnectionString(connectionString, protocol); - if (result->IoTHubClientLLHandle == NULL) + /* Codes_SRS_IOTHUBCLIENT_12_005: [IoTHubClient_CreateFromConnectionString shall create a lock object to be used later for serializing IoTHubClient calls] */ + result->LockHandle = Lock_Init(); + if (result->LockHandle == NULL) { - /* Codes_SRS_IOTHUBCLIENT_12_010: [If IoTHubClient_LL_CreateFromConnectionString fails then IoTHubClient_CreateFromConnectionString shall do clean - up and return NULL] */ - Lock_Deinit(result->LockHandle); + /* Codes_SRS_IOTHUBCLIENT_12_009: [If lock creation failed, IoTHubClient_CreateFromConnectionString shall do clean up and return NULL] */ free(result); result = NULL; - LogError("IoTHubClient_LL_CreateFromConnectionString failed\r\n"); + LogError("Lock_Init failed\r\n"); } else - { - result->ThreadHandle = NULL; + { + /* Codes_SRS_IOTHUBCLIENT_12_006: [IoTHubClient_CreateFromConnectionString shall instantiate a new IoTHubClient_LL instance by calling IoTHubClient_LL_CreateFromConnectionString and passing the connectionString] */ + result->IoTHubClientLLHandle = IoTHubClient_LL_CreateFromConnectionString(connectionString, protocol); + if (result->IoTHubClientLLHandle == NULL) + { + /* Codes_SRS_IOTHUBCLIENT_12_010: [If IoTHubClient_LL_CreateFromConnectionString fails then IoTHubClient_CreateFromConnectionString shall do clean - up and return NULL] */ + Lock_Deinit(result->LockHandle); + free(result); + result = NULL; + LogError("IoTHubClient_LL_CreateFromConnectionString failed\r\n"); + } + else + { + result->ThreadHandle = NULL; + result->TransportHandle = NULL; + } } - } + } } return result; @@ -128,8 +163,6 @@ /* Codes_SRS_IOTHUBCLIENT_01_004: [If allocating memory for the new IoTHubClient instance fails, then IoTHubClient_Create shall return NULL.] */ if (result != NULL) { - result->ThreadHandle = NULL; - /* Codes_SRS_IOTHUBCLIENT_01_029: [IoTHubClient_Create shall create a lock object to be used later for serializing IoTHubClient calls.] */ result->LockHandle = Lock_Init(); if (result->LockHandle == NULL) @@ -151,36 +184,158 @@ free(result); result = NULL; } + else + { + result->TransportHandle = NULL; + result->ThreadHandle = NULL; + } } } return result; } +IOTHUB_CLIENT_HANDLE IoTHubClient_CreateWithTransport(TRANSPORT_HANDLE transportHandle, const IOTHUB_CLIENT_CONFIG* config) +{ + IOTHUB_CLIENT_INSTANCE* result; + /*Codes_SRS_IOTHUBCLIENT_17_013: [ IoTHubClient_CreateWithTransport shall return NULL if transportHandle is NULL. ]*/ + /*Codes_SRS_IOTHUBCLIENT_17_014: [ IoTHubClient_CreateWithTransport shall return NULL if config is NULL. ]*/ + if (transportHandle == NULL || config == NULL) + { + result = NULL; + } + else + { + /*Codes_SRS_IOTHUBCLIENT_17_001: [ IoTHubClient_CreateWithTransport shall allocate a new IoTHubClient instance and return a non-NULL handle to it. ]*/ + result = (IOTHUB_CLIENT_INSTANCE*)malloc(sizeof(IOTHUB_CLIENT_INSTANCE)); + /*Codes_SRS_IOTHUBCLIENT_17_002: [ If allocating memory for the new IoTHubClient instance fails, then IoTHubClient_CreateWithTransport shall return NULL. ]*/ + if (result != NULL) + { + result->ThreadHandle = NULL; + result->TransportHandle = transportHandle; + /*Codes_SRS_IOTHUBCLIENT_17_005: [ IoTHubClient_CreateWithTransport shall call IoTHubTransport_GetLock to get the transport lock to be used later for serializing IoTHubClient calls. ]*/ + LOCK_HANDLE transportLock = IoTHubTransport_GetLock(transportHandle); + result->LockHandle = transportLock; + if (result->LockHandle == NULL) + { + /*Codes_SRS_IOTHUBCLIENT_17_006: [ If IoTHubTransport_GetLock fails, then IoTHubClient_CreateWithTransport shall return NULL. ]*/ + free(result); + result = NULL; + } + else + { + IOTHUB_CLIENT_DEVICE_CONFIG deviceConfig; + deviceConfig.deviceId = config->deviceId; + deviceConfig.deviceKey = config->deviceKey; + deviceConfig.protocol = config->protocol; + + /*Codes_SRS_IOTHUBCLIENT_17_003: [ IoTHubClient_CreateWithTransport shall call IoTHubTransport_GetLLTransport on transportHandle to get lower layer transport. ]*/ + deviceConfig.transportHandle = IoTHubTransport_GetLLTransport(transportHandle); + + if (deviceConfig.transportHandle == NULL) + { + /*Codes_SRS_IOTHUBCLIENT_17_004: [ If IoTHubTransport_GetLLTransport fails, then IoTHubClient_CreateWithTransport shall return NULL. ]*/ + free(result); + result = NULL; + } + else + { + if (Lock(transportLock) != LOCK_OK) + { + free(result); + result = NULL; + } + else + { + /*Codes_SRS_IOTHUBCLIENT_17_007: [ IoTHubClient_CreateWithTransport shall instantiate a new IoTHubClient_LL instance by calling IoTHubClient_LL_CreateWithTransport and passing the lower layer transport and config argument. ]*/ + result->IoTHubClientLLHandle = IoTHubClient_LL_CreateWithTransport(&deviceConfig); + if (result->IoTHubClientLLHandle == NULL) + { + /*Codes_SRS_IOTHUBCLIENT_17_008: [ If IoTHubClient_LL_CreateWithTransport fails, then IoTHubClient_Create shall return NULL. ]*/ + /*Codes_SRS_IOTHUBCLIENT_17_009: [ If IoTHubClient_LL_CreateWithTransport fails, all resources allocated by it shall be freed. ]*/ + free(result); + result = NULL; + } + + if (Unlock(transportLock) != LOCK_OK) + { + LogError("unable to Unlock"); + } + } + + } + } + } + } + + return result; +} + /* Codes_SRS_IOTHUBCLIENT_01_005: [IoTHubClient_Destroy shall free all resources associated with the iotHubClientHandle instance.] */ void IoTHubClient_Destroy(IOTHUB_CLIENT_HANDLE iotHubClientHandle) { /* Codes_SRS_IOTHUBCLIENT_01_008: [IoTHubClient_Destroy shall do nothing if parameter iotHubClientHandle is NULL.] */ if (iotHubClientHandle != NULL) { + bool okToJoin; + IOTHUB_CLIENT_INSTANCE* iotHubClientInstance = (IOTHUB_CLIENT_INSTANCE*)iotHubClientHandle; - /* Codes_SRS_IOTHUBCLIENT_01_007: [The thread created as part of executing IoTHubClient_SendEventAsync or IoTHubClient_SetMessageCallback shall be joined.] */ + /*Codes_SRS_IOTHUBCLIENT_02_043: [ IoTHubClient_Destroy shall lock the serializing lock and signal the worker thread (if any) to end ]*/ + if (Lock(iotHubClientInstance->LockHandle) != LOCK_OK) + { + LogError("unable to Lock - - will still proceed to try to end the thread without locking"); + } + if (iotHubClientInstance->ThreadHandle != NULL) { - int res; - iotHubClientInstance->StopThread = 1; - if (ThreadAPI_Join(iotHubClientInstance->ThreadHandle, &res) != THREADAPI_OK) - { - LogError("ThreadAPI_Join failed\r\n"); - } + iotHubClientInstance->StopThread = 1; + okToJoin = true; } + else + { + okToJoin = false; + } + + if (iotHubClientInstance->TransportHandle != NULL) + { + /*Codes_SRS_IOTHUBCLIENT_01_007: [ The thread created as part of executing IoTHubClient_SendEventAsync or IoTHubClient_SetNotificationMessageCallback shall be joined. ]*/ + okToJoin = IoTHubTransport_SignalEndWorkerThread(iotHubClientInstance->TransportHandle, iotHubClientHandle); + } /* Codes_SRS_IOTHUBCLIENT_01_006: [That includes destroying the IoTHubClient_LL instance by calling IoTHubClient_LL_Destroy.] */ IoTHubClient_LL_Destroy(iotHubClientInstance->IoTHubClientLLHandle); - /* Codes_SRS_IOTHUBCLIENT_01_032: [The lock allocated in IoTHubClient_Create shall be also freed.] */ - Lock_Deinit(iotHubClientInstance->LockHandle); + /*Codes_SRS_IOTHUBCLIENT_02_045: [ IoTHubClient_Destroy shall unlock the serializing lock. ]*/ + if (Unlock(iotHubClientInstance->LockHandle) != LOCK_OK) + { + LogError("unable to Unlock"); + } + + if (okToJoin == true) + { + if (iotHubClientInstance->ThreadHandle != NULL) + { + int res; + /*Codes_SRS_IOTHUBCLIENT_01_007: [ The thread created as part of executing IoTHubClient_SendEventAsync or IoTHubClient_SetNotificationMessageCallback shall be joined. ]*/ + if (ThreadAPI_Join(iotHubClientInstance->ThreadHandle, &res) != THREADAPI_OK) + { + LogError("ThreadAPI_Join failed\r\n"); + } + } + if (iotHubClientInstance->TransportHandle != NULL) + { + /*Codes_SRS_IOTHUBCLIENT_01_007: [ The thread created as part of executing IoTHubClient_SendEventAsync or IoTHubClient_SetNotificationMessageCallback shall be joined. ]*/ + IoTHubTransport_JoinWorkerThread(iotHubClientInstance->TransportHandle, iotHubClientHandle); + } + } + + if (iotHubClientInstance->TransportHandle == NULL) + { + /* Codes_SRS_IOTHUBCLIENT_01_032: [If the lock was allocated in IoTHubClient_Create, it shall be also freed..] */ + Lock_Deinit(iotHubClientInstance->LockHandle); + } + free(iotHubClientInstance); } } @@ -209,9 +364,7 @@ else { /* Codes_SRS_IOTHUBCLIENT_01_009: [IoTHubClient_SendEventAsync shall start the worker thread if it was not previously started.] */ - StartWorkerThreadIfNeeded(iotHubClientInstance); - - if (iotHubClientInstance->ThreadHandle == NULL) + if ((result = StartWorkerThreadIfNeeded(iotHubClientInstance)) != IOTHUB_CLIENT_OK) { /* Codes_SRS_IOTHUBCLIENT_01_010: [If starting the thread fails, IoTHubClient_SendEventAsync shall return IOTHUB_CLIENT_ERROR.] */ result = IOTHUB_CLIENT_ERROR; @@ -291,9 +444,7 @@ else { /* Codes_SRS_IOTHUBCLIENT_01_014: [IoTHubClient_SetMessageCallback shall start the worker thread if it was not previously started.] */ - StartWorkerThreadIfNeeded(iotHubClientInstance); - - if (iotHubClientInstance->ThreadHandle == NULL) + if ((result = StartWorkerThreadIfNeeded(iotHubClientInstance)) != IOTHUB_CLIENT_OK) { /* Codes_SRS_IOTHUBCLIENT_01_015: [If starting the thread fails, IoTHubClient_SetMessageCallback shall return IOTHUB_CLIENT_ERROR.] */ result = IOTHUB_CLIENT_ERROR;