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_ll.c
- Revision:
- 61:8b85a4e797cf
- Parent:
- 60:41648c4e7036
- Child:
- 62:5a4cdacf5090
diff -r 41648c4e7036 -r 8b85a4e797cf iothub_client_ll.c --- a/iothub_client_ll.c Fri Feb 24 14:00:43 2017 -0800 +++ b/iothub_client_ll.c Fri Mar 10 11:47:36 2017 -0800 @@ -12,9 +12,9 @@ #include "azure_c_shared_utility/constbuffer.h" #include "iothub_client_ll.h" +#include "iothub_transport_ll.h" #include "iothub_client_private.h" #include "iothub_client_version.h" -#include "iothub_transport_ll.h" #include <stdint.h> #ifndef DONT_USE_UPLOADTOBLOB @@ -27,6 +27,22 @@ DEFINE_ENUM_STRINGS(IOTHUB_CLIENT_RESULT, IOTHUB_CLIENT_RESULT_VALUES); DEFINE_ENUM_STRINGS(IOTHUB_CLIENT_CONFIRMATION_RESULT, IOTHUB_CLIENT_CONFIRMATION_RESULT_VALUES); +#define MESSAGE_CALLBACK_TYPE_VALUES \ + MESSAGE_CALLBACK_TYPE_NONE, \ + MESSAGE_CALLBACK_TYPE_SYNC, \ + MESSAGE_CALLBACK_TYPE_ASYNC + +DEFINE_ENUM(MESSAGE_CALLBACK_TYPE, MESSAGE_CALLBACK_TYPE_VALUES) +DEFINE_ENUM_STRINGS(MESSAGE_CALLBACK_TYPE, MESSAGE_CALLBACK_TYPE_VALUES) + +typedef struct IOTHUB_MESSAGE_CALLBACK_DATA_TAG +{ + MESSAGE_CALLBACK_TYPE messageCallbackType; + IOTHUB_CLIENT_MESSAGE_CALLBACK_ASYNC callbackSync; + IOTHUB_CLIENT_MESSAGE_CALLBACK_ASYNC_EX callbackAsync; + void* messageUserContextCallback; +}IOTHUB_MESSAGE_CALLBACK_DATA; + typedef struct IOTHUB_CLIENT_LL_HANDLE_DATA_TAG { DLIST_ENTRY waitingToSend; @@ -36,8 +52,7 @@ bool isSharedTransport; IOTHUB_DEVICE_HANDLE deviceHandle; TRANSPORT_PROVIDER_FIELDS; - IOTHUB_CLIENT_MESSAGE_CALLBACK_ASYNC messageCallback; - void* messageUserContextCallback; + IOTHUB_MESSAGE_CALLBACK_DATA messageCallback; IOTHUB_CLIENT_CONNECTION_STATUS_CALLBACK conStatusCallback; void* conStatusUserContextCallback; time_t lastMessageReceiveTime; @@ -392,6 +407,7 @@ static void setTransportProtocol(IOTHUB_CLIENT_LL_HANDLE_DATA* handleData, TRANSPORT_PROVIDER* protocol) { + handleData->IoTHubTransport_SendMessageDisposition = protocol->IoTHubTransport_SendMessageDisposition; handleData->IoTHubTransport_GetHostname = protocol->IoTHubTransport_GetHostname; handleData->IoTHubTransport_SetOption = protocol->IoTHubTransport_SetOption; handleData->IoTHubTransport_Create = protocol->IoTHubTransport_Create; @@ -467,8 +483,10 @@ DList_InitializeListHead(&(handleData->iot_msg_queue)); DList_InitializeListHead(&(handleData->iot_ack_queue)); setTransportProtocol(handleData, (TRANSPORT_PROVIDER*)config->protocol()); - handleData->messageCallback = NULL; - handleData->messageUserContextCallback = NULL; + handleData->messageCallback.messageCallbackType = MESSAGE_CALLBACK_TYPE_NONE; + handleData->messageCallback.callbackSync = NULL; + handleData->messageCallback.callbackAsync = NULL; + handleData->messageCallback.messageUserContextCallback = NULL; handleData->deviceTwinCallback = NULL; handleData->deviceTwinContextCallback = NULL; handleData->deviceMethodCallback = NULL; @@ -638,8 +656,10 @@ DList_InitializeListHead(&(handleData->waitingToSend)); DList_InitializeListHead(&(handleData->iot_msg_queue)); DList_InitializeListHead(&(handleData->iot_ack_queue)); - handleData->messageCallback = NULL; - handleData->messageUserContextCallback = NULL; + handleData->messageCallback.messageCallbackType = MESSAGE_CALLBACK_TYPE_NONE; + handleData->messageCallback.callbackSync = NULL; + handleData->messageCallback.callbackAsync = NULL; + handleData->messageCallback.messageUserContextCallback = NULL; handleData->deviceTwinCallback = NULL; handleData->deviceTwinContextCallback = NULL; handleData->deviceMethodCallback = NULL; @@ -832,42 +852,158 @@ IOTHUB_CLIENT_RESULT IoTHubClient_LL_SetMessageCallback(IOTHUB_CLIENT_LL_HANDLE iotHubClientHandle, IOTHUB_CLIENT_MESSAGE_CALLBACK_ASYNC messageCallback, void* userContextCallback) { IOTHUB_CLIENT_RESULT result; - /*Codes_SRS_IOTHUBCLIENT_LL_02_016: [IoTHubClient_LL_SetMessageCallback shall fail and return IOTHUB_CLIENT_INVALID_ARG if parameter iotHubClientHandle is NULL.] */ if (iotHubClientHandle == NULL) { + /*Codes_SRS_IOTHUBCLIENT_LL_02_016: [IoTHubClient_LL_SetMessageCallback shall fail and return IOTHUB_CLIENT_INVALID_ARG if parameter iotHubClientHandle is NULL.] */ + LogError("Invalid argument - iotHubClientHandle is NULL"); result = IOTHUB_CLIENT_INVALID_ARG; - LOG_ERROR_RESULT; } else { IOTHUB_CLIENT_LL_HANDLE_DATA* handleData = (IOTHUB_CLIENT_LL_HANDLE_DATA*)iotHubClientHandle; if (messageCallback == NULL) { - /*Codes_SRS_IOTHUBCLIENT_LL_02_019: [If parameter messageCallback is NULL then IoTHubClient_LL_SetMessageCallback shall call the underlying layer's _Unsubscribe function and return IOTHUB_CLIENT_OK.] */ - handleData->IoTHubTransport_Unsubscribe(handleData->deviceHandle); - handleData->messageCallback = NULL; - handleData->messageUserContextCallback = NULL; - result = IOTHUB_CLIENT_OK; + if (handleData->messageCallback.messageCallbackType == MESSAGE_CALLBACK_TYPE_NONE) + { + /*Codes_SRS_IOTHUBCLIENT_LL_10_010: [If parameter messageCallback is NULL and the _SetMessageCallback had not been called to subscribe for messages, then IoTHubClient_LL_SetMessageCallback shall fail and return IOTHUB_CLIENT_ERROR.] */ + LogError("not currently set to accept or process incoming messages."); + result = IOTHUB_CLIENT_ERROR; + } + else if (handleData->messageCallback.messageCallbackType == MESSAGE_CALLBACK_TYPE_ASYNC) + { + /*Codes_SRS_IOTHUBCLIENT_LL_10_010: [If parameter messageCallback is NULL and the _SetMessageCallback had not been called to subscribe for messages, then IoTHubClient_LL_SetMessageCallback shall fail and return IOTHUB_CLIENT_ERROR.] */ + LogError("Invalid workflow sequence. Please unsubscribe using the IoTHubClient_LL_SetMessageCallbackEx function."); + result = IOTHUB_CLIENT_ERROR; + } + else + { + /*Codes_SRS_IOTHUBCLIENT_LL_02_019: [If parameter messageCallback is NULL then IoTHubClient_LL_SetMessageCallback shall call the underlying layer's _Unsubscribe function and return IOTHUB_CLIENT_OK.] */ + handleData->IoTHubTransport_Unsubscribe(handleData->deviceHandle); + handleData->messageCallback.messageCallbackType = MESSAGE_CALLBACK_TYPE_NONE; + handleData->messageCallback.callbackSync = NULL; + handleData->messageCallback.callbackAsync = NULL; + handleData->messageCallback.messageUserContextCallback = NULL; + result = IOTHUB_CLIENT_OK; + } } else { - /*Codes_SRS_IOTHUBCLIENT_LL_02_017: [If parameter messageCallback is non-NULL then IoTHubClient_LL_SetMessageCallback shall call the underlying layer's _Subscribe function.]*/ - if (handleData->IoTHubTransport_Subscribe(handleData->deviceHandle) == 0) + if (handleData->messageCallback.messageCallbackType == MESSAGE_CALLBACK_TYPE_ASYNC) { - handleData->messageCallback = messageCallback; - handleData->messageUserContextCallback = userContextCallback; - result = IOTHUB_CLIENT_OK; + /* Codes_SRS_IOTHUBCLIENT_LL_10_011: [If parameter messageCallback is non-NULL and the _SetMessageCallbackEx had been used to susbscribe for messages, then IoTHubClient_LL_SetMessageCallback shall fail and return IOTHUB_CLIENT_ERROR.] */ + LogError("Invalid workflow sequence. Please unsubscribe using the IoTHubClient_LL_SetMessageCallbackEx function before subscribing with MessageCallback."); + result = IOTHUB_CLIENT_ERROR; } else { - handleData->messageCallback = NULL; - handleData->messageUserContextCallback = NULL; - /*Codes_SRS_IOTHUBCLIENT_LL_02_018: [If the underlying layer's _Subscribe function fails, then IoTHubClient_LL_SetMessageCallback shall fail and return IOTHUB_CLIENT_ERROR. Otherwise IoTHubClient_LL_SetMessageCallback shall succeed and return IOTHUB_CLIENT_OK.]*/ - result = IOTHUB_CLIENT_ERROR; + if (handleData->IoTHubTransport_Subscribe(handleData->deviceHandle) == 0) + { + /*Codes_SRS_IOTHUBCLIENT_LL_02_017: [If parameter messageCallback is non-NULL then IoTHubClient_LL_SetMessageCallback shall call the underlying layer's _Subscribe function.]*/ + handleData->messageCallback.messageCallbackType = MESSAGE_CALLBACK_TYPE_SYNC; + handleData->messageCallback.callbackSync = messageCallback; + handleData->messageCallback.messageUserContextCallback = userContextCallback; + result = IOTHUB_CLIENT_OK; + } + else + { + /*Codes_SRS_IOTHUBCLIENT_LL_02_018: [If the underlying layer's _Subscribe function fails, then IoTHubClient_LL_SetMessageCallback shall fail and return IOTHUB_CLIENT_ERROR. Otherwise IoTHubClient_LL_SetMessageCallback shall succeed and return IOTHUB_CLIENT_OK.]*/ + handleData->messageCallback.messageCallbackType = MESSAGE_CALLBACK_TYPE_NONE; + handleData->messageCallback.callbackSync = NULL; + handleData->messageCallback.callbackAsync = NULL; + handleData->messageCallback.messageUserContextCallback = NULL; + result = IOTHUB_CLIENT_ERROR; + } } } } + return result; +} +IOTHUB_CLIENT_RESULT IoTHubClient_LL_SetMessageCallbackEx(IOTHUB_CLIENT_LL_HANDLE iotHubClientHandle, IOTHUB_CLIENT_MESSAGE_CALLBACK_ASYNC_EX messageCallback, void* userContextCallback) +{ + IOTHUB_CLIENT_RESULT result; + if (iotHubClientHandle == NULL) + { + /*Codes_SRS_IOTHUBCLIENT_LL_10_021: [IoTHubClient_LL_SetMessageCallbackEx shall fail and return IOTHUB_CLIENT_INVALID_ARG if parameter iotHubClientHandle is NULL.]*/ + LogError("Invalid argument - iotHubClientHandle is NULL"); + result = IOTHUB_CLIENT_INVALID_ARG; + } + else + { + IOTHUB_CLIENT_LL_HANDLE_DATA* handleData = (IOTHUB_CLIENT_LL_HANDLE_DATA*)iotHubClientHandle; + if (messageCallback == NULL) + { + if (handleData->messageCallback.messageCallbackType == MESSAGE_CALLBACK_TYPE_NONE) + { + /*Codes_SRS_IOTHUBCLIENT_LL_10_018: [If parameter messageCallback is NULL and IoTHubClient_LL_SetMessageCallbackEx had not been used to subscribe for messages, then IoTHubClient_LL_SetMessageCallbackEx shall fail and return IOTHUB_CLIENT_ERROR.] */ + LogError("not currently set to accept or process incoming messages."); + result = IOTHUB_CLIENT_ERROR; + } + else if (handleData->messageCallback.messageCallbackType == MESSAGE_CALLBACK_TYPE_SYNC) + { + /*Codes_SRS_IOTHUBCLIENT_LL_10_019: [If parameter messageCallback is NULL and IoTHubClient_LL_SetMessageCallback had been used to subscribe for messages, then IoTHubClient_LL_SetMessageCallbackEx shall fail and return IOTHUB_CLIENT_ERROR.] */ + LogError("Invalid workflow sequence. Please unsubscribe using the IoTHubClient_LL_SetMessageCallback function."); + result = IOTHUB_CLIENT_ERROR; + } + else + { + /*Codes_SRS_IOTHUBCLIENT_LL_10_023: [If parameter messageCallback is NULL then IoTHubClient_LL_SetMessageCallbackEx shall call the underlying layer's _Unsubscribe function and return IOTHUB_CLIENT_OK.] */ + handleData->IoTHubTransport_Unsubscribe(handleData->deviceHandle); + handleData->messageCallback.messageCallbackType = MESSAGE_CALLBACK_TYPE_NONE; + handleData->messageCallback.callbackSync = NULL; + handleData->messageCallback.callbackAsync = NULL; + handleData->messageCallback.messageUserContextCallback = NULL; + result = IOTHUB_CLIENT_OK; + } + } + else + { + if (handleData->messageCallback.messageCallbackType == MESSAGE_CALLBACK_TYPE_SYNC) + { + /*Codes_SRS_IOTHUBCLIENT_LL_10_020: [If parameter messageCallback is non-NULL, and IoTHubClient_LL_SetMessageCallback had been used to subscribe for messages, then IoTHubClient_LL_SetMessageCallbackEx shall fail and return IOTHUB_CLIENT_ERROR.] */ + LogError("Invalid workflow sequence. Please unsubscribe using the IoTHubClient_LL_MessageCallbackEx function before subscribing with MessageCallback."); + result = IOTHUB_CLIENT_ERROR; + } + else + { + if (handleData->IoTHubTransport_Subscribe(handleData->deviceHandle) == 0) + { + /*Codes_SRS_IOTHUBCLIENT_LL_10_024: [If parameter messageCallback is non-NULL then IoTHubClient_LL_SetMessageCallbackEx shall call the underlying layer's _Subscribe function.]*/ + handleData->messageCallback.messageCallbackType = MESSAGE_CALLBACK_TYPE_ASYNC; + handleData->messageCallback.callbackAsync = messageCallback; + handleData->messageCallback.messageUserContextCallback = userContextCallback; + result = IOTHUB_CLIENT_OK; + } + else + { + /*Codes_SRS_IOTHUBCLIENT_LL_10_025: [If the underlying layer's _Subscribe function fails, then IoTHubClient_LL_SetMessageCallbackEx shall fail and return IOTHUB_CLIENT_ERROR. Otherwise IoTHubClient_LL_SetMessageCallbackEx shall succeed and return IOTHUB_CLIENT_OK.] */ + handleData->messageCallback.messageCallbackType = MESSAGE_CALLBACK_TYPE_NONE; + handleData->messageCallback.callbackSync = NULL; + handleData->messageCallback.callbackAsync = NULL; + handleData->messageCallback.messageUserContextCallback = NULL; + result = IOTHUB_CLIENT_ERROR; + } + } + } + } + return result; +} + +IOTHUB_CLIENT_RESULT IoTHubClient_LL_SendMessageDisposition(IOTHUB_CLIENT_LL_HANDLE iotHubClientHandle, MESSAGE_CALLBACK_INFO* message_data, IOTHUBMESSAGE_DISPOSITION_RESULT disposition) +{ + IOTHUB_CLIENT_RESULT result; + if ((iotHubClientHandle == NULL) || (message_data == NULL)) + { + /*Codes_SRS_IOTHUBCLIENT_LL_10_026: [IoTHubClient_LL_SendMessageDisposition shall fail and return IOTHUB_CLIENT_INVALID_ARG if parameter iotHubClientHandle is NULL.]*/ + LogError("Invalid argument handle=%p, message=%p", iotHubClientHandle, message_data); + result = IOTHUB_CLIENT_INVALID_ARG; + } + else + { + IOTHUB_CLIENT_LL_HANDLE_DATA* handleData = (IOTHUB_CLIENT_LL_HANDLE_DATA*)iotHubClientHandle; + /*Codes_SRS_IOTHUBCLIENT_LL_10_027: [IoTHubClient_LL_SendMessageDisposition shall return the result from calling the underlying layer's _Send_Message_Disposition.]*/ + result = handleData->IoTHubTransport_SendMessageDisposition(message_data, disposition); + } return result; } @@ -1110,14 +1246,20 @@ } } -IOTHUBMESSAGE_DISPOSITION_RESULT IoTHubClient_LL_MessageCallback(IOTHUB_CLIENT_LL_HANDLE handle, IOTHUB_MESSAGE_HANDLE message) +bool IoTHubClient_LL_MessageCallback(IOTHUB_CLIENT_LL_HANDLE handle, MESSAGE_CALLBACK_INFO* messageData) { - int result; - /*Codes_SRS_IOTHUBCLIENT_LL_02_029: [If parameter handle is NULL then IoTHubClient_LL_MessageCallback shall return IOTHUBMESSAGE_ABANDONED.] */ - if (handle == NULL) + bool result; + if ((handle == NULL) || messageData == NULL) { - LogError("invalid argument"); - result = IOTHUBMESSAGE_ABANDONED; + /*Codes_SRS_IOTHUBCLIENT_LL_02_029: [If parameter handle is NULL then IoTHubClient_LL_MessageCallback shall return IOTHUBMESSAGE_ABANDONED.] */ + LogError("invalid argument: handle(%p), messageData(%p)", handle, messageData); + result = false; + } + else if (messageData->messageHandle == NULL) + { + /*Codes_SRS_IOTHUBCLIENT_LL_10_004: [If messageHandle field of paramger messageData is NULL then IoTHubClient_LL_MessageCallback shall return IOTHUBMESSAGE_ABANDONED.] */ + LogError("invalid argument messageData->messageHandle(NULL)"); + result = false; } else { @@ -1125,26 +1267,52 @@ /* Codes_SRS_IOTHUBCLIENT_LL_09_004: [IoTHubClient_LL_GetLastMessageReceiveTime shall return lastMessageReceiveTime in localtime] */ handleData->lastMessageReceiveTime = get_time(NULL); - - /*Codes_SRS_IOTHUBCLIENT_LL_02_030: [IoTHubClient_LL_MessageCallback shall invoke the last callback function (the parameter messageCallback to IoTHubClient_LL_SetMessageCallback) passing the message and the passed userContextCallback.]*/ - if (handleData->messageCallback != NULL) + switch (handleData->messageCallback.messageCallbackType) { - result = handleData->messageCallback(message, handleData->messageUserContextCallback); - } - else - { - /*Codes_SRS_IOTHUBCLIENT_LL_02_032: [If the last callback function was NULL, then IoTHubClient_LL_MessageCallback shall return IOTHUBMESSAGE_ABANDONED.] */ - LogError("user callback was NULL"); - result = IOTHUBMESSAGE_ABANDONED; + case MESSAGE_CALLBACK_TYPE_NONE: + { + /*Codes_SRS_IOTHUBCLIENT_LL_02_032: [If the client is not subscribed to receive messages then IoTHubClient_LL_MessageCallback shall return false.] */ + LogError("Invalid workflow - not currently set up to accept messages"); + result = false; + break; + } + case MESSAGE_CALLBACK_TYPE_SYNC: + { + /*Codes_SRS_IOTHUBCLIENT_LL_02_030: [If messageCallbackType is LEGACY then IoTHubClient_LL_MessageCallback shall invoke the last callback function (the parameter messageCallback to IoTHubClient_LL_SetMessageCallback) passing the message and the passed userContextCallback.]*/ + IOTHUBMESSAGE_DISPOSITION_RESULT cb_result = handleData->messageCallback.callbackSync(messageData->messageHandle, handleData->messageCallback.messageUserContextCallback); + + /*Codes_SRS_IOTHUBCLIENT_LL_10_007: [If messageCallbackType is LEGACY then IoTHubClient_LL_MessageCallback shall send the message disposition as returned by the client to the underlying layer.] */ + if (handleData->IoTHubTransport_SendMessageDisposition(messageData, cb_result) != IOTHUB_CLIENT_OK) + { + LogError("IoTHubTransport_SendMessageDisposition failed"); + } + result = true; + break; + } + case MESSAGE_CALLBACK_TYPE_ASYNC: + { + /* Codes_SRS_IOTHUBCLIENT_LL_10_009: [If messageCallbackType is ASYNC then IoTHubClient_LL_MessageCallback shall return what messageCallbacEx returns.] */ + result = handleData->messageCallback.callbackAsync(messageData, handleData->messageCallback.messageUserContextCallback); + if (!result) + { + LogError("messageCallbackEx failed"); + } + break; + } + default: + { + LogError("Invalid state"); + result = false; + break; + } } } - /*Codes_SRS_IOTHUBCLIENT_LL_02_031: [Then IoTHubClient_LL_MessageCallback shall return what the user function returns.]*/ - return (IOTHUBMESSAGE_DISPOSITION_RESULT) result; + return result; } -void IotHubClient_LL_ConnectionStatusCallBack(IOTHUB_CLIENT_LL_HANDLE handle, IOTHUB_CLIENT_CONNECTION_STATUS status, IOTHUB_CLIENT_CONNECTION_STATUS_REASON reason) +void IoTHubClient_LL_ConnectionStatusCallBack(IOTHUB_CLIENT_LL_HANDLE handle, IOTHUB_CLIENT_CONNECTION_STATUS status, IOTHUB_CLIENT_CONNECTION_STATUS_REASON reason) { - /*Codes_SRS_IOTHUBCLIENT_LL_25_113: [If parameter connectionStatus is NULL or parameter handle is NULL then IotHubClient_LL_ConnectionStatusCallBack shall return.]*/ + /*Codes_SRS_IOTHUBCLIENT_LL_25_113: [If parameter connectionStatus is NULL or parameter handle is NULL then IoTHubClient_LL_ConnectionStatusCallBack shall return.]*/ if (handle == NULL) { /*"shall return"*/ @@ -1154,7 +1322,7 @@ { IOTHUB_CLIENT_LL_HANDLE_DATA* handleData = (IOTHUB_CLIENT_LL_HANDLE_DATA*)handle; - /*Codes_SRS_IOTHUBCLIENT_LL_25_114: [IotHubClient_LL_ConnectionStatusCallBack shall call non-callback set by the user from IoTHubClient_LL_SetConnectionStatusCallback passing the status, reason and the passed userContextCallback.]*/ + /*Codes_SRS_IOTHUBCLIENT_LL_25_114: [IoTHubClient_LL_ConnectionStatusCallBack shall call non-callback set by the user from IoTHubClient_LL_SetConnectionStatusCallback passing the status, reason and the passed userContextCallback.]*/ if (handleData->conStatusCallback != NULL) { handleData->conStatusCallback(status, reason, handleData->conStatusUserContextCallback);