corrected version (with typedef struct IOTHUB_CLIENT_LL_UPLOADTOBLOB_HANDLE_DATA* IOTHUB_CLIENT_LL_UPLOADTOBLOB_HANDLE;) included in the sources

Dependents:   STM32F746_iothub_client_sample_mqtt

Fork of iothub_client by Azure IoT

Revision:
37:18310e4d888d
Parent:
35:ceed20da4ba6
Child:
38:a05929a75111
--- 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;