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

Revision:
80:db5f5237bc95
Parent:
78:74a8d3068204
Child:
82:f94e6bed4495
--- a/iothub_client.c	Fri Nov 17 13:57:39 2017 -0800
+++ b/iothub_client.c	Fri Dec 15 14:09:20 2017 -0800
@@ -62,6 +62,15 @@
     LOCK_HANDLE lockGarbage;
     int canBeGarbageCollected; /*flag indicating that the UPLOADTOBLOB_SAVED_DATA structure can be freed because the thread deadling with it finished*/
 }UPLOADTOBLOB_SAVED_DATA;
+
+typedef struct UPLOADTOBLOB_MULTIBLOCK_SAVED_DATA_TAG
+{
+    char* destinationFileName;
+    IOTHUB_CLIENT_FILE_UPLOAD_GET_DATA_CALLBACK getDataCallback;
+    void* context;
+    THREAD_HANDLE uploadingThreadHandle;
+    IOTHUB_CLIENT_HANDLE iotHubClientHandle;
+}UPLOADTOBLOB_MULTIBLOCK_SAVED_DATA;
 #endif
 
 #define USER_CALLBACK_TYPE_VALUES       \
@@ -405,6 +414,44 @@
 {
     size_t callbacks_length = VECTOR_size(call_backs);
     size_t index;
+
+    IOTHUB_CLIENT_DEVICE_TWIN_CALLBACK desired_state_callback = NULL;
+    IOTHUB_CLIENT_EVENT_CONFIRMATION_CALLBACK event_confirm_callback = NULL;
+    IOTHUB_CLIENT_REPORTED_STATE_CALLBACK reported_state_callback = NULL;
+    IOTHUB_CLIENT_CONNECTION_STATUS_CALLBACK connection_status_callback = NULL;
+    IOTHUB_CLIENT_DEVICE_METHOD_CALLBACK_ASYNC device_method_callback = NULL;
+    IOTHUB_CLIENT_INBOUND_DEVICE_METHOD_CALLBACK inbound_device_method_callback = NULL;
+    IOTHUB_CLIENT_MESSAGE_CALLBACK_ASYNC message_callback = NULL;
+    IOTHUB_CLIENT_HANDLE message_user_context_handle = NULL;
+    IOTHUB_CLIENT_HANDLE method_user_context_handle = NULL;
+
+    // Make a local copy of these callbacks, as we don't run with a lock held and iotHubClientInstance may change mid-run.
+    if (Lock(iotHubClientInstance->LockHandle) != LOCK_OK)
+    {
+        LogError("failed locking for dispatch_user_callbacks");
+    }
+    else
+    {
+        desired_state_callback = iotHubClientInstance->desired_state_callback;
+        event_confirm_callback = iotHubClientInstance->event_confirm_callback;
+        reported_state_callback = iotHubClientInstance->reported_state_callback;
+        connection_status_callback = iotHubClientInstance->connection_status_callback;
+        device_method_callback = iotHubClientInstance->device_method_callback;
+        inbound_device_method_callback = iotHubClientInstance->inbound_device_method_callback;
+        message_callback = iotHubClientInstance->message_callback;
+        if (iotHubClientInstance->method_user_context)
+        {
+            method_user_context_handle = iotHubClientInstance->method_user_context->iotHubClientHandle;
+        }
+        if (iotHubClientInstance->message_user_context)
+        {
+            message_user_context_handle = iotHubClientInstance->message_user_context->iotHubClientHandle;
+        }
+        
+        (void)Unlock(iotHubClientInstance->LockHandle);
+    }
+
+    
     for (index = 0; index < callbacks_length; index++)
     {
         USER_CALLBACK_INFO* queued_cb = (USER_CALLBACK_INFO*)VECTOR_element(call_backs, index);
@@ -418,19 +465,6 @@
             {
                 case CALLBACK_TYPE_DEVICE_TWIN:
                 {
-                    IOTHUB_CLIENT_DEVICE_TWIN_CALLBACK desired_state_callback;
-
-                    if (Lock(iotHubClientInstance->LockHandle) != LOCK_OK)
-                    {
-                        LogError("failed locking for dispatch_user_callbacks");
-                        desired_state_callback = NULL;
-                    }
-                    else
-                    {
-                        desired_state_callback = iotHubClientInstance->desired_state_callback;
-                        (void)Unlock(iotHubClientInstance->LockHandle);
-                    }
-
                     if (desired_state_callback)
                     {
                         desired_state_callback(queued_cb->iothub_callback.dev_twin_cb_info.update_state, queued_cb->iothub_callback.dev_twin_cb_info.payLoad, queued_cb->iothub_callback.dev_twin_cb_info.size, queued_cb->userContextCallback);
@@ -443,25 +477,25 @@
                     break;
                 }
                 case CALLBACK_TYPE_EVENT_CONFIRM:
-                    if (iotHubClientInstance->event_confirm_callback)
+                    if (event_confirm_callback)
                     {
-                        iotHubClientInstance->event_confirm_callback(queued_cb->iothub_callback.event_confirm_cb_info.confirm_result, queued_cb->userContextCallback);
+                        event_confirm_callback(queued_cb->iothub_callback.event_confirm_cb_info.confirm_result, queued_cb->userContextCallback);
                     }
                     break;
                 case CALLBACK_TYPE_REPORTED_STATE:
-                    if (iotHubClientInstance->reported_state_callback)
+                    if (reported_state_callback)
                     {
-                        iotHubClientInstance->reported_state_callback(queued_cb->iothub_callback.reported_state_cb_info.status_code, queued_cb->userContextCallback);
+                        reported_state_callback(queued_cb->iothub_callback.reported_state_cb_info.status_code, queued_cb->userContextCallback);
                     }
                     break;
                 case CALLBACK_TYPE_CONNECTION_STATUS:
-                    if (iotHubClientInstance->connection_status_callback)
+                    if (connection_status_callback)
                     {
-                        iotHubClientInstance->connection_status_callback(queued_cb->iothub_callback.connection_status_cb_info.connection_status, queued_cb->iothub_callback.connection_status_cb_info.status_reason, queued_cb->userContextCallback);
+                        connection_status_callback(queued_cb->iothub_callback.connection_status_cb_info.connection_status, queued_cb->iothub_callback.connection_status_cb_info.status_reason, queued_cb->userContextCallback);
                     }
                     break;
                 case CALLBACK_TYPE_DEVICE_METHOD:
-                    if (iotHubClientInstance->device_method_callback)
+                    if (device_method_callback)
                     {
                         const char* method_name = STRING_c_str(queued_cb->iothub_callback.method_cb_info.method_name);
                         const unsigned char* payload = BUFFER_u_char(queued_cb->iothub_callback.method_cb_info.payload);
@@ -469,12 +503,11 @@
 
                         unsigned char* payload_resp = NULL;
                         size_t response_size = 0;
-                        int status = iotHubClientInstance->device_method_callback(method_name, payload, payload_len, &payload_resp, &response_size, queued_cb->userContextCallback);
+                        int status = device_method_callback(method_name, payload, payload_len, &payload_resp, &response_size, queued_cb->userContextCallback);
 
                         if (payload_resp && (response_size > 0))
                         {
-                            IOTHUB_CLIENT_HANDLE handle = iotHubClientInstance->method_user_context->iotHubClientHandle;
-                            IOTHUB_CLIENT_RESULT result = IoTHubClient_DeviceMethodResponse(handle, queued_cb->iothub_callback.method_cb_info.method_id, (const unsigned char*)payload_resp, response_size, status);
+                            IOTHUB_CLIENT_RESULT result = IoTHubClient_DeviceMethodResponse(method_user_context_handle, queued_cb->iothub_callback.method_cb_info.method_id, (const unsigned char*)payload_resp, response_size, status);
                             if (result != IOTHUB_CLIENT_OK)
                             {
                                 LogError("IoTHubClient_LL_DeviceMethodResponse failed");
@@ -491,28 +524,27 @@
                     }
                     break;
                 case CALLBACK_TYPE_INBOUD_DEVICE_METHOD:
-                    if (iotHubClientInstance->inbound_device_method_callback)
+                    if (inbound_device_method_callback)
                     {
                         const char* method_name = STRING_c_str(queued_cb->iothub_callback.method_cb_info.method_name);
                         const unsigned char* payload = BUFFER_u_char(queued_cb->iothub_callback.method_cb_info.payload);
                         size_t payload_len = BUFFER_length(queued_cb->iothub_callback.method_cb_info.payload);
 
-                        iotHubClientInstance->inbound_device_method_callback(method_name, payload, payload_len, queued_cb->iothub_callback.method_cb_info.method_id, queued_cb->userContextCallback);
+                        inbound_device_method_callback(method_name, payload, payload_len, queued_cb->iothub_callback.method_cb_info.method_id, queued_cb->userContextCallback);
 
                         BUFFER_delete(queued_cb->iothub_callback.method_cb_info.payload);
                         STRING_delete(queued_cb->iothub_callback.method_cb_info.method_name);
                     }
                     break;
                 case CALLBACK_TYPE_MESSAGE:
-                    if (iotHubClientInstance->message_callback)
+                    if (message_callback)
                     {
-                        IOTHUBMESSAGE_DISPOSITION_RESULT disposition = iotHubClientInstance->message_callback(queued_cb->iothub_callback.message_cb_info->messageHandle, queued_cb->userContextCallback);
-                        IOTHUB_CLIENT_HANDLE handle = iotHubClientInstance->message_user_context->iotHubClientHandle;
+                        IOTHUBMESSAGE_DISPOSITION_RESULT disposition = message_callback(queued_cb->iothub_callback.message_cb_info->messageHandle, queued_cb->userContextCallback);
 
-                        if (Lock(handle->LockHandle) == LOCK_OK)
+                        if (Lock(message_user_context_handle->LockHandle) == LOCK_OK)
                         {
-                            IOTHUB_CLIENT_RESULT result = IoTHubClient_LL_SendMessageDisposition(handle->IoTHubClientLLHandle, queued_cb->iothub_callback.message_cb_info, disposition);
-                            (void)Unlock(handle->LockHandle);
+                            IOTHUB_CLIENT_RESULT result = IoTHubClient_LL_SendMessageDisposition(message_user_context_handle->IoTHubClientLLHandle, queued_cb->iothub_callback.message_cb_info, disposition);
+                            (void)Unlock(message_user_context_handle->LockHandle);
                             if (result != IOTHUB_CLIENT_OK)
                             {
                                 LogError("IoTHubClient_LL_SendMessageDisposition failed");
@@ -1065,11 +1097,6 @@
         }
         else
         {
-            if (iotHubClientInstance->created_with_transport_handle == 0)
-            {
-                iotHubClientInstance->event_confirm_callback = eventConfirmationCallback;
-            }
-
             /* Codes_SRS_IOTHUBCLIENT_01_025: [IoTHubClient_SendEventAsync shall be made thread-safe by using the lock created in IoTHubClient_Create.] */
             if (Lock(iotHubClientInstance->LockHandle) != LOCK_OK)
             {
@@ -1079,6 +1106,11 @@
             }
             else
             {
+                if (iotHubClientInstance->created_with_transport_handle == 0)
+                {
+                    iotHubClientInstance->event_confirm_callback = eventConfirmationCallback;
+                }
+
                 if (iotHubClientInstance->created_with_transport_handle != 0 || eventConfirmationCallback == NULL)
                 {
                     result = IoTHubClient_LL_SendEventAsync(iotHubClientInstance->IoTHubClientLLHandle, eventMessageHandle, eventConfirmationCallback, userContextCallback);
@@ -1174,11 +1206,6 @@
         }
         else
         {
-            if (iotHubClientInstance->created_with_transport_handle == 0)
-            {
-                iotHubClientInstance->message_callback = messageCallback;
-            }
-
             /* Codes_SRS_IOTHUBCLIENT_01_027: [IoTHubClient_SetMessageCallback shall be made thread-safe by using the lock created in IoTHubClient_Create.] */
             if (Lock(iotHubClientInstance->LockHandle) != LOCK_OK)
             {
@@ -1188,6 +1215,10 @@
             }
             else
             {
+                if (iotHubClientInstance->created_with_transport_handle == 0)
+                {
+                    iotHubClientInstance->message_callback = messageCallback;
+                }
                 if (iotHubClientInstance->message_user_context != NULL)
                 {
                     free(iotHubClientInstance->message_user_context);
@@ -1573,11 +1604,6 @@
         }
         else
         {
-            if (iotHubClientInstance->created_with_transport_handle == 0)
-            {
-                iotHubClientInstance->reported_state_callback = reportedStateCallback;
-            }
-
             /*Codes_SRS_IOTHUBCLIENT_10_021: [** `IoTHubClient_SendReportedState` shall be made thread-safe by using the lock created in IoTHubClient_Create. ]*/
             if (Lock(iotHubClientInstance->LockHandle) != LOCK_OK)
             {
@@ -1587,6 +1613,11 @@
             }
             else
             {
+                if (iotHubClientInstance->created_with_transport_handle == 0)
+                {
+                    iotHubClientInstance->reported_state_callback = reportedStateCallback;
+                }
+
                 if (iotHubClientInstance->created_with_transport_handle != 0 || reportedStateCallback == NULL)
                 {
                     /*Codes_SRS_IOTHUBCLIENT_10_017: [** `IoTHubClient_SendReportedState` shall call `IoTHubClient_LL_SendReportedState`, while passing the `IoTHubClient_LL handle` created by `IoTHubClient_LL_Create` along with the parameters `reportedState`, `size`, `reportedStateCallback`, and `userContextCallback`. ]*/
@@ -1647,11 +1678,6 @@
         }
         else
         {
-            if (iotHubClientInstance->created_with_transport_handle == 0)
-            {
-                iotHubClientInstance->device_method_callback = deviceMethodCallback;
-            }
-
             /*Codes_SRS_IOTHUBCLIENT_12_018: [ IoTHubClient_SetDeviceMethodCallback shall be made thread-safe by using the lock created in IoTHubClient_Create. ]*/
             if (Lock(iotHubClientInstance->LockHandle) != LOCK_OK)
             {
@@ -1661,6 +1687,11 @@
             }
             else
             {
+                if (iotHubClientInstance->created_with_transport_handle == 0)
+                {
+                    iotHubClientInstance->device_method_callback = deviceMethodCallback;
+                }
+
                 if (iotHubClientInstance->method_user_context)
                 {
                     free(iotHubClientInstance->method_user_context);
@@ -1730,11 +1761,6 @@
         }
         else
         {
-            if (iotHubClientInstance->created_with_transport_handle == 0)
-            {
-                iotHubClientInstance->inbound_device_method_callback = inboundDeviceMethodCallback;
-            }
-
             /*Codes_SRS_IOTHUBCLIENT_07_007: [ IoTHubClient_SetDeviceMethodCallback_Ex shall be made thread-safe by using the lock created in IoTHubClient_Create. ]*/
             if (Lock(iotHubClientInstance->LockHandle) != LOCK_OK)
             {
@@ -1744,6 +1770,11 @@
             }
             else
             {
+                if (iotHubClientInstance->created_with_transport_handle == 0)
+                {
+                    iotHubClientInstance->inbound_device_method_callback = inboundDeviceMethodCallback;
+                }
+
                 if (iotHubClientInstance->method_user_context)
                 {
                     free(iotHubClientInstance->method_user_context);
@@ -2031,4 +2062,86 @@
     }
     return result;
 }
+
+static int uploadMultipleBlock_thread(void* data)
+{
+    UPLOADTOBLOB_MULTIBLOCK_SAVED_DATA *blocksData = (UPLOADTOBLOB_MULTIBLOCK_SAVED_DATA *)data;
+    IOTHUB_CLIENT_LL_HANDLE llHandle = blocksData->iotHubClientHandle->IoTHubClientLLHandle;
+
+    /*Codes_SRS_IOTHUBCLIENT_99_078: [ The thread shall call `IoTHubClient_LL_UploadMultipleBlocksToBlob` passing the information packed in the structure. ]*/
+    IOTHUB_CLIENT_RESULT result = IoTHubClient_LL_UploadMultipleBlocksToBlob(llHandle, blocksData->destinationFileName, blocksData->getDataCallback, blocksData->context);
+
+    // Clean resources
+    free(blocksData->destinationFileName);
+    free(blocksData);
+    ThreadAPI_Exit(result);
+    return 0;
+}
+
+IOTHUB_CLIENT_RESULT IoTHubClient_UploadMultipleBlocksToBlobAsync(IOTHUB_CLIENT_HANDLE iotHubClientHandle, const char* destinationFileName, IOTHUB_CLIENT_FILE_UPLOAD_GET_DATA_CALLBACK getDataCallback, void* context)
+{
+    IOTHUB_CLIENT_RESULT result;
+
+    /*Codes_SRS_IOTHUBCLIENT_99_072: [ If `iotHubClientHandle` is `NULL` then `IoTHubClient_UploadMultipleBlocksToBlobAsync` shall fail and return `IOTHUB_CLIENT_INVALID_ARG`. ]*/
+    /*Codes_SRS_IOTHUBCLIENT_99_073: [ If `destinationFileName` is `NULL` then `IoTHubClient_UploadMultipleBlocksToBlobAsync` shall fail and return `IOTHUB_CLIENT_INVALID_ARG`. ]*/
+    /*Codes_SRS_IOTHUBCLIENT_99_074: [ If `getDataCallback` is `NULL` then `IoTHubClient_UploadMultipleBlocksToBlobAsync` shall fail and return `IOTHUB_CLIENT_INVALID_ARG`. ]*/
+    if (
+        (iotHubClientHandle == NULL) ||
+        (destinationFileName == NULL) ||
+        (getDataCallback == NULL)
+        )
+    {
+        LogError("invalid parameters iotHubClientHandle = %p , destinationFileName = %p, getDataCallback = %p",
+            iotHubClientHandle,
+            destinationFileName,
+            getDataCallback
+        );
+        result = IOTHUB_CLIENT_INVALID_ARG;
+    }
+    else
+    {
+        /*Codes_SRS_IOTHUBCLIENT_99_075: [ `IoTHubClient_UploadMultipleBlocksToBlobAsync` shall copy the `destinationFileName`, `getDataCallback`, `context`  and `iotHubClientHandle` into a structure. ]*/
+        UPLOADTOBLOB_MULTIBLOCK_SAVED_DATA *blocksData = (UPLOADTOBLOB_MULTIBLOCK_SAVED_DATA *)malloc(sizeof(UPLOADTOBLOB_MULTIBLOCK_SAVED_DATA));
+        if (blocksData == NULL)
+        {
+            /*Codes_SRS_IOTHUBCLIENT_99_077: [ If copying to the structure or spawning the thread fails, then `IoTHubClient_UploadMultipleBlocksToBlobAsync` shall fail and return `IOTHUB_CLIENT_ERROR`. ]*/
+            LogError("unable to malloc");
+            result = IOTHUB_CLIENT_ERROR;
+        }
+        else
+        {
+            /*Codes_SRS_IOTHUBCLIENT_99_075: [ `IoTHubClient_UploadMultipleBlocksToBlobAsync` shall copy the `destinationFileName`, `getDataCallback`, `context`  and `iotHubClientHandle` into a structure. ]*/
+            if (mallocAndStrcpy_s((char**)&blocksData->destinationFileName, destinationFileName) != 0)
+            {
+                /*Codes_SRS_IOTHUBCLIENT_99_077: [ If copying to the structure or spawning the thread fails, then `IoTHubClient_UploadMultipleBlocksToBlobAsync` shall fail and return `IOTHUB_CLIENT_ERROR`. ]*/
+                LogError("unable to mallocAndStrcpy_s");
+                free(blocksData);
+                result = IOTHUB_CLIENT_ERROR;
+            }
+            else
+            {
+                /*Codes_SRS_IOTHUBCLIENT_99_075: [ `IoTHubClient_UploadMultipleBlocksToBlobAsync` shall copy the `destinationFileName`, `getDataCallback`, `context`  and `iotHubClientHandle` into a structure. ]*/
+                blocksData->getDataCallback = getDataCallback;
+                blocksData->context = context;
+                blocksData->iotHubClientHandle = iotHubClientHandle;
+                if (ThreadAPI_Create(&blocksData->uploadingThreadHandle, uploadMultipleBlock_thread, blocksData) != THREADAPI_OK)
+                {
+                    /*Codes_SRS_IOTHUBCLIENT_99_077: [ If copying to the structure or spawning the thread fails, then `IoTHubClient_UploadMultipleBlocksToBlobAsync` shall fail and return `IOTHUB_CLIENT_ERROR`. ]*/
+                    LogError("unable to ThreadAPI_Create");
+                    free(blocksData->destinationFileName);
+                    free(blocksData);
+                    result = IOTHUB_CLIENT_ERROR;
+                }
+                else
+                {
+                    /*Codes_SRS_IOTHUBCLIENT_99_077: [ If copying to the structure and spawning the thread succeeds, then `IoTHubClient_UploadMultipleBlocksToBlobAsync` shall return `IOTHUB_CLIENT_OK`. ]*/
+                    result = IOTHUB_CLIENT_OK;
+                }
+            }
+        }
+    }
+
+    return result;
+}
+
 #endif /*DONT_USE_UPLOADTOBLOB*/