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:
62:5a4cdacf5090
Parent:
61:8b85a4e797cf
Child:
66:a419827cb051
--- a/iothub_client.c	Fri Mar 10 11:47:36 2017 -0800
+++ b/iothub_client.c	Fri Mar 24 16:35:32 2017 -0700
@@ -37,11 +37,13 @@
     IOTHUB_CLIENT_EVENT_CONFIRMATION_CALLBACK event_confirm_callback;
     IOTHUB_CLIENT_REPORTED_STATE_CALLBACK reported_state_callback;
     IOTHUB_CLIENT_CONNECTION_STATUS_CALLBACK connection_status_callback;
-    IOTHUB_CLIENT_INBOUND_DEVICE_METHOD_CALLBACK device_method_callback;
+    IOTHUB_CLIENT_DEVICE_METHOD_CALLBACK_ASYNC device_method_callback;
+    IOTHUB_CLIENT_INBOUND_DEVICE_METHOD_CALLBACK inbound_device_method_callback;
     IOTHUB_CLIENT_MESSAGE_CALLBACK_ASYNC message_callback;
     struct IOTHUB_QUEUE_CONTEXT_TAG* devicetwin_user_context;
     struct IOTHUB_QUEUE_CONTEXT_TAG* connection_status_user_context;
     struct IOTHUB_QUEUE_CONTEXT_TAG* message_user_context;
+    struct IOTHUB_QUEUE_CONTEXT_TAG* method_user_context;
 } IOTHUB_CLIENT_INSTANCE;
 
 #ifndef DONT_USE_UPLOADTOBLOB
@@ -59,12 +61,13 @@
 }UPLOADTOBLOB_SAVED_DATA;
 #endif
 
-#define USER_CALLBACK_TYPE_VALUES   \
-    CALLBACK_TYPE_DEVICE_TWIN,      \
-    CALLBACK_TYPE_EVENT_CONFIRM,    \
-    CALLBACK_TYPE_REPORTED_STATE,   \
-    CALLBACK_TYPE_CONNECTION_STATUS, \
-    CALLBACK_TYPE_DEVICE_METHOD,     \
+#define USER_CALLBACK_TYPE_VALUES       \
+    CALLBACK_TYPE_DEVICE_TWIN,          \
+    CALLBACK_TYPE_EVENT_CONFIRM,        \
+    CALLBACK_TYPE_REPORTED_STATE,       \
+    CALLBACK_TYPE_CONNECTION_STATUS,    \
+    CALLBACK_TYPE_DEVICE_METHOD,        \
+    CALLBACK_TYPE_INBOUD_DEVICE_METHOD, \
     CALLBACK_TYPE_MESSAGE
 
 DEFINE_ENUM(USER_CALLBACK_TYPE, USER_CALLBACK_TYPE_VALUES)
@@ -201,52 +204,95 @@
     return result;
 }
 
-static int iothub_ll_inbound_device_method_callback(const char* method_name, const unsigned char* payload, size_t size, METHOD_HANDLE method_id, void* userContextCallback)
+static int make_method_calback_queue_context(USER_CALLBACK_INFO* queue_cb_info, const char* method_name, const unsigned char* payload, size_t size, METHOD_HANDLE method_id, IOTHUB_QUEUE_CONTEXT* queue_context)
 {
     int result;
-    IOTHUB_QUEUE_CONTEXT* queue_context = (IOTHUB_QUEUE_CONTEXT*)userContextCallback;
-    /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_001: [ if userContextCallback is NULL, IOTHUB_CLIENT_INBOUND_DEVICE_METHOD_CALLBACK shall return a nonNULL value. ] */
-    if (queue_context != NULL)
+    /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_002: [ IOTHUB_CLIENT_INBOUND_DEVICE_METHOD_CALLBACK shall copy the method_name and payload. ] */
+    queue_cb_info->userContextCallback = queue_context->userContextCallback;
+    queue_cb_info->iothub_callback.method_cb_info.method_id = method_id;
+    if ((queue_cb_info->iothub_callback.method_cb_info.method_name = STRING_construct(method_name)) == NULL)
     {
-        /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_002: [ IOTHUB_CLIENT_INBOUND_DEVICE_METHOD_CALLBACK shall copy the method_name and payload. ] */
-        USER_CALLBACK_INFO queue_cb_info;
-        queue_cb_info.type = CALLBACK_TYPE_DEVICE_METHOD;
-        queue_cb_info.userContextCallback = queue_context->userContextCallback;
-        queue_cb_info.iothub_callback.method_cb_info.method_id = method_id;
-        if ( (queue_cb_info.iothub_callback.method_cb_info.method_name = STRING_construct(method_name)) == NULL)
+        /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_003: [ If a failure is encountered IOTHUB_CLIENT_INBOUND_DEVICE_METHOD_CALLBACK shall return a non-NULL value. ]*/
+        LogError("STRING_construct failed");
+        result = __FAILURE__;
+    }
+    else
+    {
+        if ((queue_cb_info->iothub_callback.method_cb_info.payload = BUFFER_create(payload, size)) == NULL)
         {
+            STRING_delete(queue_cb_info->iothub_callback.method_cb_info.method_name);
             /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_003: [ If a failure is encountered IOTHUB_CLIENT_INBOUND_DEVICE_METHOD_CALLBACK shall return a non-NULL value. ]*/
-            LogError("Failure: STRING_construct");
-            result = __FAILURE__;
-        }
-        else if ((queue_cb_info.iothub_callback.method_cb_info.payload = BUFFER_create(payload, size)) == NULL)
-        {
-            STRING_delete(queue_cb_info.iothub_callback.method_cb_info.method_name);
-            /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_003: [ If a failure is encountered IOTHUB_CLIENT_INBOUND_DEVICE_METHOD_CALLBACK shall return a non-NULL value. ]*/
-            LogError("Failure: BUFFER_create");
-            result = __FAILURE__;
-        }
-        else if (VECTOR_push_back(queue_context->iotHubClientHandle->saved_user_callback_list, &queue_cb_info, 1) != 0)
-        {
-            STRING_delete(queue_cb_info.iothub_callback.method_cb_info.method_name);
-            BUFFER_delete(queue_cb_info.iothub_callback.method_cb_info.payload);
-            /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_003: [ If a failure is encountered IOTHUB_CLIENT_INBOUND_DEVICE_METHOD_CALLBACK shall return a non-NULL value. ]*/
-            LogError("connection status callback vector push failed.");
+            LogError("BUFFER_create failed");
             result = __FAILURE__;
         }
         else
         {
-            /*Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_004: [ On success IOTHUB_CLIENT_INBOUND_DEVICE_METHOD_CALLBACK shall return a 0 value. ]*/
-            result = 0;
+            if (VECTOR_push_back(queue_context->iotHubClientHandle->saved_user_callback_list, queue_cb_info, 1) == 0)
+            {
+                result = 0;
+            }
+            else
+            {
+                STRING_delete(queue_cb_info->iothub_callback.method_cb_info.method_name);
+                BUFFER_delete(queue_cb_info->iothub_callback.method_cb_info.payload);
+                /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_003: [ If a failure is encountered IOTHUB_CLIENT_INBOUND_DEVICE_METHOD_CALLBACK shall return a non-NULL value. ]*/
+                LogError("VECTOR_push_back failed");
+                result = __FAILURE__;
+            }
         }
-        free(queue_context);
+    }
+    return result;
+}
+
+static int iothub_ll_device_method_callback(const char* method_name, const unsigned char* payload, size_t size, METHOD_HANDLE method_id, void* userContextCallback)
+{
+    int result;
+    /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_001: [ if userContextCallback is NULL, IOTHUB_CLIENT_INBOUND_DEVICE_METHOD_CALLBACK shall return a nonNULL value. ] */
+    if (userContextCallback == NULL)
+    {
+        LogError("invalid parameter userContextCallback(NULL)");
+        result = __FAILURE__;
     }
     else
     {
-        /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_003: [ If a failure is encountered IOTHUB_CLIENT_INBOUND_DEVICE_METHOD_CALLBACK shall return a non-NULL value. ]*/
-        LogError("Invalid parameter: userContextCallback NULL");
+        IOTHUB_QUEUE_CONTEXT* queue_context = (IOTHUB_QUEUE_CONTEXT*)userContextCallback;
+
+        USER_CALLBACK_INFO queue_cb_info;
+        queue_cb_info.type = CALLBACK_TYPE_DEVICE_METHOD;
+
+        result = make_method_calback_queue_context(&queue_cb_info, method_name, payload, size, method_id, queue_context);
+        if (result != 0)
+        {
+            LogError("construction of method calback queue context failed");
+            result = __FAILURE__;
+        }
+    }
+    return result;
+}
+
+static int iothub_ll_inbound_device_method_callback(const char* method_name, const unsigned char* payload, size_t size, METHOD_HANDLE method_id, void* userContextCallback)
+{
+    int result;
+    /* Codes_SRS_IOTHUB_MQTT_TRANSPORT_07_001: [ if userContextCallback is NULL, IOTHUB_CLIENT_INBOUND_DEVICE_METHOD_CALLBACK shall return a nonNULL value. ] */
+    if (userContextCallback == NULL)
+    {
+        LogError("invalid parameter userContextCallback(NULL)");
         result = __FAILURE__;
     }
+    else
+    {
+        IOTHUB_QUEUE_CONTEXT* queue_context = (IOTHUB_QUEUE_CONTEXT*)userContextCallback;
+
+        USER_CALLBACK_INFO queue_cb_info;
+        queue_cb_info.type = CALLBACK_TYPE_INBOUD_DEVICE_METHOD;
+
+        result = make_method_calback_queue_context(&queue_cb_info, method_name, payload, size, method_id, queue_context);
+        if (result != 0)
+        {
+            LogError("construction of method calback queue context failed");
+            result = __FAILURE__;
+        }
+    }
     return result;
 }
 
@@ -401,7 +447,38 @@
                         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->device_method_callback(method_name, payload, payload_len, queued_cb->iothub_callback.method_cb_info.method_id, queued_cb->userContextCallback);
+
+                        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);
+
+                        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);
+                            if (result != IOTHUB_CLIENT_OK)
+                            {
+                                LogError("IoTHubClient_LL_DeviceMethodResponse failed");
+                            }
+                        }
+
+                        BUFFER_delete(queued_cb->iothub_callback.method_cb_info.payload);
+                        STRING_delete(queued_cb->iothub_callback.method_cb_info.method_name);
+						
+						if (payload_resp)
+						{
+                            free(payload_resp);
+						}
+                    }
+                    break;
+                case CALLBACK_TYPE_INBOUD_DEVICE_METHOD:
+                    if (iotHubClientInstance->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);
 
                         BUFFER_delete(queued_cb->iothub_callback.method_cb_info.payload);
                         STRING_delete(queued_cb->iothub_callback.method_cb_info.method_name);
@@ -416,11 +493,11 @@
                         if (Lock(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);
                             if (result != IOTHUB_CLIENT_OK)
                             {
-                                LogError("IoTHubClient_LL_Send_Message_Disposition failed");
+                                LogError("IoTHubClient_LL_SendMessageDisposition failed");
                             }
-                            (void)Unlock(handle->LockHandle);
                         }
                         else
                         {
@@ -656,6 +733,7 @@
                     result->connection_status_user_context = NULL;
                     result->message_callback = NULL;
                     result->message_user_context = NULL;
+                    result->method_user_context = NULL;
                 }
             }
         }
@@ -724,7 +802,7 @@
     if (iotHubClientHandle != NULL)
     {
         bool okToJoin;
-        size_t vector_size;       
+        size_t vector_size;
 
         IOTHUB_CLIENT_INSTANCE* iotHubClientInstance = (IOTHUB_CLIENT_INSTANCE*)iotHubClientHandle;
 
@@ -800,7 +878,7 @@
             USER_CALLBACK_INFO* queue_cb_info = (USER_CALLBACK_INFO*)VECTOR_element(iotHubClientInstance->saved_user_callback_list, index);
             if (queue_cb_info != NULL)
             {
-                if (queue_cb_info->type == CALLBACK_TYPE_DEVICE_METHOD)
+                if ((queue_cb_info->type == CALLBACK_TYPE_DEVICE_METHOD) || (queue_cb_info->type == CALLBACK_TYPE_INBOUD_DEVICE_METHOD))
                 {
                     STRING_delete(queue_cb_info->iothub_callback.method_cb_info.method_name);
                     BUFFER_delete(queue_cb_info->iothub_callback.method_cb_info.payload);
@@ -840,6 +918,10 @@
         {
             free(iotHubClientInstance->message_user_context);
         }
+        if (iotHubClientInstance->method_user_context != NULL)
+        {
+            free(iotHubClientInstance->method_user_context);
+        }
         free(iotHubClientInstance);
     }
 }
@@ -992,10 +1074,11 @@
                 if (iotHubClientInstance->message_user_context != NULL)
                 {
                     free(iotHubClientInstance->message_user_context);
+                    iotHubClientInstance->message_user_context = NULL;
                 }
                 if (messageCallback == NULL)
                 {
-                    result = IoTHubClient_LL_SetMessageCallbackEx(iotHubClientInstance->IoTHubClientLLHandle, NULL, iotHubClientInstance->message_user_context);
+                    result = IoTHubClient_LL_SetMessageCallback_Ex(iotHubClientInstance->IoTHubClientLLHandle, NULL, iotHubClientInstance->message_user_context);
                 }
                 else if (iotHubClientInstance->created_with_transport_handle != 0)
                 {
@@ -1014,9 +1097,9 @@
                         iotHubClientInstance->message_user_context->iotHubClientHandle = iotHubClientHandle;
                         iotHubClientInstance->message_user_context->userContextCallback = userContextCallback;
 
-                        /* Codes_SRS_IOTHUBCLIENT_01_017: [IoTHubClient_SetMessageCallback shall call IoTHubClient_LL_SetMessageCallbackEx, while passing the IoTHubClient_LL handle created by IoTHubClient_Create and the local iothub_ll_message_callback wrapper of messageCallback and userContextCallback.] */
-                        /* Codes_SRS_IOTHUBCLIENT_01_018: [When IoTHubClient_LL_SetMessageCallbackEx is called, IoTHubClient_SetMessageCallback shall return the result of IoTHubClient_LL_SetMessageCallbackEx.] */
-                        result = IoTHubClient_LL_SetMessageCallbackEx(iotHubClientInstance->IoTHubClientLLHandle, iothub_ll_message_callback, iotHubClientInstance->message_user_context);
+                        /* Codes_SRS_IOTHUBCLIENT_01_017: [IoTHubClient_SetMessageCallback shall call IoTHubClient_LL_SetMessageCallback_Ex, while passing the IoTHubClient_LL handle created by IoTHubClient_Create and the local iothub_ll_message_callback wrapper of messageCallback and userContextCallback.] */
+                        /* Codes_SRS_IOTHUBCLIENT_01_018: [When IoTHubClient_LL_SetMessageCallback_Ex is called, IoTHubClient_SetMessageCallback shall return the result of IoTHubClient_LL_SetMessageCallback_Ex.] */
+                        result = IoTHubClient_LL_SetMessageCallback_Ex(iotHubClientInstance->IoTHubClientLLHandle, iothub_ll_message_callback, iotHubClientInstance->message_user_context);
                         if (result != IOTHUB_CLIENT_OK)
                         {
                             LogError("IoTHubClient_LL_SetMessageCallback failed");
@@ -1443,6 +1526,10 @@
         }
         else
         {
+            if (iotHubClientInstance->created_with_transport_handle == 0)
+            {
+                iotHubClientInstance->device_method_callback = deviceMethodCallback;
+            }
             /*Codes_SRS_IOTHUBCLIENT_12_014: [ If the transport handle is null and the worker thread is not initialized, the thread shall be started by calling IoTHubTransport_StartWorkerThread. ]*/
             if ((result = StartWorkerThreadIfNeeded(iotHubClientInstance)) != IOTHUB_CLIENT_OK)
             {
@@ -1452,12 +1539,38 @@
             }
             else
             {
-                /*Codes_SRS_IOTHUBCLIENT_12_016: [ IoTHubClient_SetDeviceMethodCallback shall call IoTHubClient_LL_SetDeviceMethodCallback, while passing the IoTHubClient_LL_handle created by IoTHubClient_LL_Create along with the parameters deviceMethodCallback and userContextCallback. ]*/
-                /*Codes_SRS_IOTHUBCLIENT_12_017: [ When IoTHubClient_LL_SetDeviceMethodCallback is called, IoTHubClient_SetDeviceMethodCallback shall return the result of IoTHubClient_LL_SetDeviceMethodCallback. ]*/
-                result = IoTHubClient_LL_SetDeviceMethodCallback(iotHubClientInstance->IoTHubClientLLHandle, deviceMethodCallback, userContextCallback);
-                if (result != IOTHUB_CLIENT_OK)
+                if (iotHubClientInstance->method_user_context)
+                {
+                    free(iotHubClientInstance->method_user_context);
+                    iotHubClientInstance->method_user_context = NULL;
+                }
+                if (deviceMethodCallback == NULL)
+                {
+                    result = IoTHubClient_LL_SetDeviceMethodCallback_Ex(iotHubClientInstance->IoTHubClientLLHandle, NULL, NULL);
+                }
+                else
                 {
-                    LogError("IoTHubClient_LL_SetDeviceMethodCallback failed");
+                    iotHubClientInstance->method_user_context = (IOTHUB_QUEUE_CONTEXT*)malloc(sizeof(IOTHUB_QUEUE_CONTEXT));
+                    if (iotHubClientInstance->method_user_context == NULL)
+                    {
+                        result = IOTHUB_CLIENT_ERROR;
+                        LogError("Failed allocating QUEUE_CONTEXT");
+                    }
+                    else
+                    {
+                        iotHubClientInstance->method_user_context->iotHubClientHandle = iotHubClientHandle;
+                        iotHubClientInstance->method_user_context->userContextCallback = userContextCallback;
+
+                        /*Codes_SRS_IOTHUBCLIENT_12_016: [ IoTHubClient_SetDeviceMethodCallback shall call IoTHubClient_LL_SetDeviceMethodCallback, while passing the IoTHubClient_LL_handle created by IoTHubClient_LL_Create along with the parameters deviceMethodCallback and userContextCallback. ]*/
+                        /*Codes_SRS_IOTHUBCLIENT_12_017: [ When IoTHubClient_LL_SetDeviceMethodCallback is called, IoTHubClient_SetDeviceMethodCallback shall return the result of IoTHubClient_LL_SetDeviceMethodCallback. ]*/
+                        result = IoTHubClient_LL_SetDeviceMethodCallback_Ex(iotHubClientInstance->IoTHubClientLLHandle, iothub_ll_device_method_callback, iotHubClientInstance->method_user_context);
+                        if (result != IOTHUB_CLIENT_OK)
+                        {
+                            LogError("IoTHubClient_LL_SetDeviceMethodCallback_Ex failed");
+                            free(iotHubClientInstance->method_user_context);
+                            iotHubClientInstance->method_user_context = NULL;
+                        }
+                    }
                 }
             }
 
@@ -1492,7 +1605,7 @@
         {
             if (iotHubClientInstance->created_with_transport_handle == 0)
             {
-                iotHubClientInstance->device_method_callback = inboundDeviceMethodCallback;
+                iotHubClientInstance->inbound_device_method_callback = inboundDeviceMethodCallback;
             }
             /*Codes_SRS_IOTHUBCLIENT_07_003: [ If the transport handle is NULL and the worker thread is not initialized, the thread shall be started by calling IoTHubTransport_StartWorkerThread. ]*/
             if ((result = StartWorkerThreadIfNeeded(iotHubClientInstance)) != IOTHUB_CLIENT_OK)
@@ -1503,15 +1616,20 @@
             }
             else
             {
-                if (iotHubClientInstance->created_with_transport_handle != 0 || inboundDeviceMethodCallback == NULL)
+                if (iotHubClientInstance->method_user_context)
+                {
+                    free(iotHubClientInstance->method_user_context);
+                    iotHubClientInstance->method_user_context = NULL;
+                }
+                if (inboundDeviceMethodCallback == NULL)
                 {
                     /* Codes_SRS_IOTHUBCLIENT_07_008: [ If inboundDeviceMethodCallback is NULL, IoTHubClient_SetDeviceMethodCallback_Ex shall call IoTHubClient_LL_SetDeviceMethodCallback_Ex, passing NULL for the iothub_ll_inbound_device_method_callback. ] */
                     result = IoTHubClient_LL_SetDeviceMethodCallback_Ex(iotHubClientInstance->IoTHubClientLLHandle, NULL, NULL);
                 }
                 else
                 {
-                    IOTHUB_QUEUE_CONTEXT* queue_context = (IOTHUB_QUEUE_CONTEXT*)malloc(sizeof(IOTHUB_QUEUE_CONTEXT));
-                    if (queue_context == NULL)
+                    iotHubClientInstance->method_user_context = (IOTHUB_QUEUE_CONTEXT*)malloc(sizeof(IOTHUB_QUEUE_CONTEXT));
+                    if (iotHubClientInstance->method_user_context == NULL)
                     {
                         result = IOTHUB_CLIENT_ERROR;
                         LogError("Failed allocating QUEUE_CONTEXT");
@@ -1519,14 +1637,16 @@
                     else
                     {
                         /*Codes_SRS_IOTHUBCLIENT_07_005: [ IoTHubClient_SetDeviceMethodCallback_Ex shall call IoTHubClient_LL_SetDeviceMethodCallback_Ex, while passing the IoTHubClient_LL_handle created by IoTHubClient_LL_Create along with the parameters iothub_ll_inbound_device_method_callback and IOTHUB_QUEUE_CONTEXT. ]*/
-                        queue_context->iotHubClientHandle = iotHubClientInstance;
-                        queue_context->userContextCallback = userContextCallback;
+                        iotHubClientInstance->method_user_context->iotHubClientHandle = iotHubClientHandle;
+                        iotHubClientInstance->method_user_context->userContextCallback = userContextCallback;
+
                         /* Codes_SRS_IOTHUBCLIENT_07_006: [ When IoTHubClient_LL_SetDeviceMethodCallback_Ex is called, IoTHubClient_SetDeviceMethodCallback_Ex shall return the result of IoTHubClient_LL_SetDeviceMethodCallback_Ex. ] */
-                        result = IoTHubClient_LL_SetDeviceMethodCallback_Ex(iotHubClientInstance->IoTHubClientLLHandle, iothub_ll_inbound_device_method_callback, queue_context);
+                        result = IoTHubClient_LL_SetDeviceMethodCallback_Ex(iotHubClientInstance->IoTHubClientLLHandle, iothub_ll_inbound_device_method_callback, iotHubClientInstance->method_user_context);
                         if (result != IOTHUB_CLIENT_OK)
                         {
-                            LogError("IoTHubClient_LL_SetDeviceMethodCallback failed");
-                            free(queue_context);
+                            LogError("IoTHubClient_LL_SetDeviceMethodCallback_Ex failed");
+                            free(iotHubClientInstance->method_user_context);
+                            iotHubClientInstance->method_user_context = NULL;
                         }
                     }
                 }
@@ -1577,26 +1697,32 @@
 {
     UPLOADTOBLOB_SAVED_DATA* savedData = (UPLOADTOBLOB_SAVED_DATA*)data;
 
-    /*it so happens that IoTHubClient_LL_UploadToBlob is thread-safe because there's no saved state in the handle and there are no globals, so no need to protect it*/
-    /*not having it protected means multiple simultaneous uploads can happen*/
-    /*Codes_SRS_IOTHUBCLIENT_02_054: [ The thread shall call IoTHubClient_LL_UploadToBlob passing the information packed in the structure. ]*/
-    if (IoTHubClient_LL_UploadToBlob(savedData->iotHubClientHandle->IoTHubClientLLHandle, savedData->destinationFileName, savedData->source, savedData->size) != IOTHUB_CLIENT_OK)
+    if (Lock(savedData->iotHubClientHandle->LockHandle) == LOCK_OK)
     {
-        LogError("unable to IoTHubClient_LL_UploadToBlob");
-        /*call the callback*/
+        IOTHUB_CLIENT_FILE_UPLOAD_RESULT upload_result;
+        /*it so happens that IoTHubClient_LL_UploadToBlob is thread-safe because there's no saved state in the handle and there are no globals, so no need to protect it*/
+        /*not having it protected means multiple simultaneous uploads can happen*/
+        /*Codes_SRS_IOTHUBCLIENT_02_054: [ The thread shall call IoTHubClient_LL_UploadToBlob passing the information packed in the structure. ]*/
+        if (IoTHubClient_LL_UploadToBlob(savedData->iotHubClientHandle->IoTHubClientLLHandle, savedData->destinationFileName, savedData->source, savedData->size) == IOTHUB_CLIENT_OK)
+        {
+            upload_result = FILE_UPLOAD_OK;
+        }
+        else
+        {
+            LogError("unable to IoTHubClient_LL_UploadToBlob");
+            upload_result = FILE_UPLOAD_ERROR;
+        }
+        (void)Unlock(savedData->iotHubClientHandle->LockHandle);
+
         if (savedData->iotHubClientFileUploadCallback != NULL)
         {
             /*Codes_SRS_IOTHUBCLIENT_02_055: [ If IoTHubClient_LL_UploadToBlob fails then the thread shall call iotHubClientFileUploadCallbackInternal passing as result FILE_UPLOAD_ERROR and as context the structure from SRS IOTHUBCLIENT 02 051. ]*/
-            savedData->iotHubClientFileUploadCallback(FILE_UPLOAD_ERROR, savedData->context);
+            savedData->iotHubClientFileUploadCallback(upload_result, savedData->context);
         }
     }
     else
     {
-        if (savedData->iotHubClientFileUploadCallback != NULL)
-        {
-            /*Codes_SRS_IOTHUBCLIENT_02_056: [ Otherwise the thread iotHubClientFileUploadCallbackInternal passing as result FILE_UPLOAD_OK and the structure from SRS IOTHUBCLIENT 02 051. ]*/
-            savedData->iotHubClientFileUploadCallback(FILE_UPLOAD_OK, savedData->context);
-        }
+        LogError("Lock failed");
     }
 
     /*Codes_SRS_IOTHUBCLIENT_02_071: [ The thread shall mark itself as disposable. ]*/