Microsoft Azure IoTHub client AMQP transport

Dependents:   sht15_remote_monitoring RobotArmDemo iothub_client_sample_amqp iothub_client_sample_amqp ... more

This library implements the AMQP transport for Microsoft Azure IoTHub client. The code is replicated from https://github.com/Azure/azure-iot-sdks

Committer:
AzureIoTClient
Date:
Thu Oct 04 09:14:47 2018 -0700
Revision:
57:56ac1346c70d
Parent:
56:8704100b3b54
1.2.10

Who changed what in which revision?

UserRevisionLine numberNew contents of line
AzureIoTClient 39:e98d5df6dc74 1 // Copyright (c) Microsoft. All rights reserved.
AzureIoTClient 39:e98d5df6dc74 2 // Licensed under the MIT license. See LICENSE file in the project root for full license information.
AzureIoTClient 39:e98d5df6dc74 3
AzureIoTClient 39:e98d5df6dc74 4 #include <stdlib.h>
AzureIoTClient 39:e98d5df6dc74 5 #include <stdint.h>
AzureIoTClient 39:e98d5df6dc74 6 #include <stdbool.h>
AzureIoTClient 39:e98d5df6dc74 7 #include "azure_c_shared_utility/optimize_size.h"
AzureIoTClient 39:e98d5df6dc74 8 #include "azure_c_shared_utility/crt_abstractions.h"
AzureIoTClient 39:e98d5df6dc74 9 #include "azure_c_shared_utility/gballoc.h"
AzureIoTClient 56:8704100b3b54 10 #include "azure_c_shared_utility/agenttime.h"
AzureIoTClient 39:e98d5df6dc74 11 #include "azure_c_shared_utility/xlogging.h"
AzureIoTClient 39:e98d5df6dc74 12 #include "azure_c_shared_utility/uniqueid.h"
AzureIoTClient 39:e98d5df6dc74 13 #include "azure_c_shared_utility/singlylinkedlist.h"
AzureIoTClient 50:f3a92c6c6534 14 #include "azure_uamqp_c/amqp_definitions_fields.h"
AzureIoTClient 39:e98d5df6dc74 15 #include "azure_uamqp_c/messaging.h"
AzureIoTClient 53:e21e1e88460f 16 #include "internal/iothub_client_private.h"
AzureIoTClient 53:e21e1e88460f 17 #include "internal/iothubtransport_amqp_messenger.h"
AzureIoTClient 53:e21e1e88460f 18 #include "internal/iothubtransport_amqp_twin_messenger.h"
AzureIoTClient 39:e98d5df6dc74 19
AzureIoTClient 39:e98d5df6dc74 20 DEFINE_ENUM_STRINGS(TWIN_MESSENGER_SEND_STATUS, TWIN_MESSENGER_SEND_STATUS_VALUES);
AzureIoTClient 39:e98d5df6dc74 21 DEFINE_ENUM_STRINGS(TWIN_REPORT_STATE_RESULT, TWIN_REPORT_STATE_RESULT_VALUES);
AzureIoTClient 39:e98d5df6dc74 22 DEFINE_ENUM_STRINGS(TWIN_REPORT_STATE_REASON, TWIN_REPORT_STATE_REASON_VALUES);
AzureIoTClient 39:e98d5df6dc74 23 DEFINE_ENUM_STRINGS(TWIN_MESSENGER_STATE, TWIN_MESSENGER_STATE_VALUES);
AzureIoTClient 39:e98d5df6dc74 24 DEFINE_ENUM_STRINGS(TWIN_UPDATE_TYPE, TWIN_UPDATE_TYPE_VALUES);
AzureIoTClient 39:e98d5df6dc74 25
AzureIoTClient 39:e98d5df6dc74 26
AzureIoTClient 39:e98d5df6dc74 27 #define RESULT_OK 0
AzureIoTClient 39:e98d5df6dc74 28 #define INDEFINITE_TIME ((time_t)(-1))
AzureIoTClient 39:e98d5df6dc74 29
AzureIoTClient 56:8704100b3b54 30 #define CLIENT_VERSION_PROPERTY_NAME "com.microsoft:client-version"
AzureIoTClient 39:e98d5df6dc74 31 #define UNIQUE_ID_BUFFER_SIZE 37
AzureIoTClient 39:e98d5df6dc74 32
AzureIoTClient 39:e98d5df6dc74 33 #define EMPTY_TWIN_BODY_DATA ((const unsigned char*)" ")
AzureIoTClient 39:e98d5df6dc74 34 #define EMPTY_TWIN_BODY_SIZE 1
AzureIoTClient 39:e98d5df6dc74 35
AzureIoTClient 56:8704100b3b54 36 #define TWIN_MESSAGE_PROPERTY_OPERATION "operation"
AzureIoTClient 56:8704100b3b54 37 #define TWIN_MESSAGE_PROPERTY_RESOURCE "resource"
AzureIoTClient 56:8704100b3b54 38 #define TWIN_MESSAGE_PROPERTY_VERSION "version"
AzureIoTClient 56:8704100b3b54 39 #define TWIN_MESSAGE_PROPERTY_STATUS "status"
AzureIoTClient 39:e98d5df6dc74 40
AzureIoTClient 56:8704100b3b54 41 #define TWIN_RESOURCE_DESIRED "/notifications/twin/properties/desired"
AzureIoTClient 56:8704100b3b54 42 #define TWIN_RESOURCE_REPORTED "/properties/reported"
AzureIoTClient 39:e98d5df6dc74 43
AzureIoTClient 56:8704100b3b54 44 #define TWIN_CORRELATION_ID_PROPERTY_NAME "com.microsoft:channel-correlation-id"
AzureIoTClient 56:8704100b3b54 45 #define TWIN_API_VERSION_PROPERTY_NAME "com.microsoft:api-version"
AzureIoTClient 56:8704100b3b54 46 #define TWIN_CORRELATION_ID_PROPERTY_FORMAT "twin:%s"
AzureIoTClient 56:8704100b3b54 47 #define TWIN_API_VERSION_NUMBER "2016-11-14"
AzureIoTClient 39:e98d5df6dc74 48
AzureIoTClient 56:8704100b3b54 49 #define DEFAULT_MAX_TWIN_SUBSCRIPTION_ERROR_COUNT 3
AzureIoTClient 56:8704100b3b54 50 #define DEFAULT_TWIN_OPERATION_TIMEOUT_SECS 300.0
AzureIoTClient 39:e98d5df6dc74 51
AzureIoTClient 56:8704100b3b54 52 static char* DEFAULT_TWIN_SEND_LINK_SOURCE_NAME = "twin";
AzureIoTClient 56:8704100b3b54 53 static char* DEFAULT_TWIN_RECEIVE_LINK_TARGET_NAME = "twin";
AzureIoTClient 39:e98d5df6dc74 54
AzureIoTClient 56:8704100b3b54 55 static const char* TWIN_OPERATION_PATCH = "PATCH";
AzureIoTClient 56:8704100b3b54 56 static const char* TWIN_OPERATION_GET = "GET";
AzureIoTClient 56:8704100b3b54 57 static const char* TWIN_OPERATION_PUT = "PUT";
AzureIoTClient 56:8704100b3b54 58 static const char* TWIN_OPERATION_DELETE = "DELETE";
AzureIoTClient 39:e98d5df6dc74 59
AzureIoTClient 39:e98d5df6dc74 60
AzureIoTClient 39:e98d5df6dc74 61 #define TWIN_OPERATION_TYPE_STRINGS \
AzureIoTClient 56:8704100b3b54 62 TWIN_OPERATION_TYPE_PATCH, \
AzureIoTClient 56:8704100b3b54 63 TWIN_OPERATION_TYPE_GET, \
AzureIoTClient 56:8704100b3b54 64 TWIN_OPERATION_TYPE_PUT, \
AzureIoTClient 56:8704100b3b54 65 TWIN_OPERATION_TYPE_DELETE
AzureIoTClient 39:e98d5df6dc74 66
AzureIoTClient 39:e98d5df6dc74 67 DEFINE_LOCAL_ENUM(TWIN_OPERATION_TYPE, TWIN_OPERATION_TYPE_STRINGS);
AzureIoTClient 39:e98d5df6dc74 68
AzureIoTClient 39:e98d5df6dc74 69 #define TWIN_SUBSCRIPTION_STATE_STRINGS \
AzureIoTClient 56:8704100b3b54 70 TWIN_SUBSCRIPTION_STATE_NOT_SUBSCRIBED, \
AzureIoTClient 56:8704100b3b54 71 TWIN_SUBSCRIPTION_STATE_GET_COMPLETE_PROPERTIES, \
AzureIoTClient 56:8704100b3b54 72 TWIN_SUBSCRIPTION_STATE_GETTING_COMPLETE_PROPERTIES, \
AzureIoTClient 56:8704100b3b54 73 TWIN_SUBSCRIPTION_STATE_SUBSCRIBE_FOR_UPDATES, \
AzureIoTClient 56:8704100b3b54 74 TWIN_SUBSCRIPTION_STATE_SUBSCRIBING, \
AzureIoTClient 56:8704100b3b54 75 TWIN_SUBSCRIPTION_STATE_SUBSCRIBED, \
AzureIoTClient 56:8704100b3b54 76 TWIN_SUBSCRIPTION_STATE_UNSUBSCRIBE, \
AzureIoTClient 56:8704100b3b54 77 TWIN_SUBSCRIPTION_STATE_UNSUBSCRIBING
AzureIoTClient 39:e98d5df6dc74 78
AzureIoTClient 56:8704100b3b54 79 // Suppress unused function warning for TWIN_SUBSCRIPTION_STATEstrings
AzureIoTClient 50:f3a92c6c6534 80 #ifdef __APPLE__
AzureIoTClient 50:f3a92c6c6534 81 #pragma clang diagnostic push
AzureIoTClient 50:f3a92c6c6534 82 #pragma clang diagnostic ignored "-Wunused-function"
AzureIoTClient 50:f3a92c6c6534 83 #endif
AzureIoTClient 39:e98d5df6dc74 84 DEFINE_LOCAL_ENUM(TWIN_SUBSCRIPTION_STATE, TWIN_SUBSCRIPTION_STATE_STRINGS);
AzureIoTClient 50:f3a92c6c6534 85 #ifdef __APPLE__
AzureIoTClient 50:f3a92c6c6534 86 #pragma clang diagnostic pop
AzureIoTClient 50:f3a92c6c6534 87 #endif
AzureIoTClient 39:e98d5df6dc74 88
AzureIoTClient 39:e98d5df6dc74 89 typedef struct TWIN_MESSENGER_INSTANCE_TAG
AzureIoTClient 39:e98d5df6dc74 90 {
AzureIoTClient 56:8704100b3b54 91 char* client_version;
AzureIoTClient 56:8704100b3b54 92 char* device_id;
AzureIoTClient 56:8704100b3b54 93 char* module_id;
AzureIoTClient 56:8704100b3b54 94 char* iothub_host_fqdn;
AzureIoTClient 39:e98d5df6dc74 95
AzureIoTClient 56:8704100b3b54 96 TWIN_MESSENGER_STATE state;
AzureIoTClient 56:8704100b3b54 97
AzureIoTClient 56:8704100b3b54 98 SINGLYLINKEDLIST_HANDLE pending_patches;
AzureIoTClient 56:8704100b3b54 99 SINGLYLINKEDLIST_HANDLE operations;
AzureIoTClient 39:e98d5df6dc74 100
AzureIoTClient 56:8704100b3b54 101 TWIN_MESSENGER_STATE_CHANGED_CALLBACK on_state_changed_callback;
AzureIoTClient 56:8704100b3b54 102 void* on_state_changed_context;
AzureIoTClient 39:e98d5df6dc74 103
AzureIoTClient 56:8704100b3b54 104 TWIN_SUBSCRIPTION_STATE subscription_state;
AzureIoTClient 56:8704100b3b54 105 size_t subscription_error_count;
AzureIoTClient 56:8704100b3b54 106 TWIN_STATE_UPDATE_CALLBACK on_message_received_callback;
AzureIoTClient 56:8704100b3b54 107 void* on_message_received_context;
AzureIoTClient 39:e98d5df6dc74 108
AzureIoTClient 56:8704100b3b54 109 AMQP_MESSENGER_HANDLE amqp_msgr;
AzureIoTClient 56:8704100b3b54 110 AMQP_MESSENGER_STATE amqp_msgr_state;
AzureIoTClient 56:8704100b3b54 111 bool amqp_msgr_is_subscribed;
AzureIoTClient 39:e98d5df6dc74 112 } TWIN_MESSENGER_INSTANCE;
AzureIoTClient 39:e98d5df6dc74 113
AzureIoTClient 39:e98d5df6dc74 114 typedef struct TWIN_PATCH_OPERATION_CONTEXT_TAG
AzureIoTClient 39:e98d5df6dc74 115 {
AzureIoTClient 56:8704100b3b54 116 CONSTBUFFER_HANDLE data;
AzureIoTClient 56:8704100b3b54 117 TWIN_MESSENGER_REPORT_STATE_COMPLETE_CALLBACK on_report_state_complete_callback;
AzureIoTClient 56:8704100b3b54 118 const void* on_report_state_complete_context;
AzureIoTClient 56:8704100b3b54 119 time_t time_enqueued;
AzureIoTClient 39:e98d5df6dc74 120 } TWIN_PATCH_OPERATION_CONTEXT;
AzureIoTClient 39:e98d5df6dc74 121
AzureIoTClient 39:e98d5df6dc74 122 typedef struct TWIN_OPERATION_CONTEXT_TAG
AzureIoTClient 39:e98d5df6dc74 123 {
AzureIoTClient 56:8704100b3b54 124 TWIN_OPERATION_TYPE type;
AzureIoTClient 56:8704100b3b54 125 TWIN_MESSENGER_INSTANCE* msgr;
AzureIoTClient 56:8704100b3b54 126 char* correlation_id;
AzureIoTClient 56:8704100b3b54 127 TWIN_MESSENGER_REPORT_STATE_COMPLETE_CALLBACK on_report_state_complete_callback;
AzureIoTClient 56:8704100b3b54 128 const void* on_report_state_complete_context;
AzureIoTClient 56:8704100b3b54 129 time_t time_sent;
AzureIoTClient 39:e98d5df6dc74 130 } TWIN_OPERATION_CONTEXT;
AzureIoTClient 39:e98d5df6dc74 131
AzureIoTClient 39:e98d5df6dc74 132
AzureIoTClient 39:e98d5df6dc74 133
AzureIoTClient 39:e98d5df6dc74 134
AzureIoTClient 39:e98d5df6dc74 135 static void update_state(TWIN_MESSENGER_INSTANCE* twin_msgr, TWIN_MESSENGER_STATE new_state)
AzureIoTClient 39:e98d5df6dc74 136 {
AzureIoTClient 56:8704100b3b54 137 if (new_state != twin_msgr->state)
AzureIoTClient 56:8704100b3b54 138 {
AzureIoTClient 56:8704100b3b54 139 TWIN_MESSENGER_STATE previous_state = twin_msgr->state;
AzureIoTClient 56:8704100b3b54 140 twin_msgr->state = new_state;
AzureIoTClient 39:e98d5df6dc74 141
AzureIoTClient 56:8704100b3b54 142 if (twin_msgr->on_state_changed_callback != NULL)
AzureIoTClient 56:8704100b3b54 143 {
AzureIoTClient 56:8704100b3b54 144 twin_msgr->on_state_changed_callback(twin_msgr->on_state_changed_context, previous_state, new_state);
AzureIoTClient 56:8704100b3b54 145 }
AzureIoTClient 56:8704100b3b54 146 }
AzureIoTClient 39:e98d5df6dc74 147 }
AzureIoTClient 39:e98d5df6dc74 148
AzureIoTClient 39:e98d5df6dc74 149 //---------- AMQP Helper Functions ----------//
AzureIoTClient 39:e98d5df6dc74 150
AzureIoTClient 39:e98d5df6dc74 151 static int set_message_correlation_id(MESSAGE_HANDLE message, const char* value)
AzureIoTClient 39:e98d5df6dc74 152 {
AzureIoTClient 56:8704100b3b54 153 int result;
AzureIoTClient 56:8704100b3b54 154 PROPERTIES_HANDLE properties = NULL;
AzureIoTClient 39:e98d5df6dc74 155
AzureIoTClient 56:8704100b3b54 156 if (message_get_properties(message, &properties) != 0)
AzureIoTClient 56:8704100b3b54 157 {
AzureIoTClient 56:8704100b3b54 158 LogError("Failed getting the AMQP message properties");
AzureIoTClient 56:8704100b3b54 159 result = __FAILURE__;
AzureIoTClient 56:8704100b3b54 160 }
AzureIoTClient 56:8704100b3b54 161 else if (properties == NULL && (properties = properties_create()) == NULL)
AzureIoTClient 56:8704100b3b54 162 {
AzureIoTClient 56:8704100b3b54 163 LogError("Failed creating properties for AMQP message");
AzureIoTClient 56:8704100b3b54 164 result = __FAILURE__;
AzureIoTClient 56:8704100b3b54 165 }
AzureIoTClient 56:8704100b3b54 166 else
AzureIoTClient 56:8704100b3b54 167 {
AzureIoTClient 56:8704100b3b54 168 AMQP_VALUE amqp_value;
AzureIoTClient 39:e98d5df6dc74 169
AzureIoTClient 56:8704100b3b54 170 if ((amqp_value = amqpvalue_create_string(value)) == NULL)
AzureIoTClient 56:8704100b3b54 171 {
AzureIoTClient 56:8704100b3b54 172 LogError("Failed creating AMQP value for correlation-id");
AzureIoTClient 56:8704100b3b54 173 result = __FAILURE__;
AzureIoTClient 56:8704100b3b54 174 }
AzureIoTClient 56:8704100b3b54 175 else
AzureIoTClient 56:8704100b3b54 176 {
AzureIoTClient 56:8704100b3b54 177 if (properties_set_correlation_id(properties, amqp_value) != RESULT_OK)
AzureIoTClient 56:8704100b3b54 178 {
AzureIoTClient 56:8704100b3b54 179 LogError("Failed setting the correlation id");
AzureIoTClient 56:8704100b3b54 180 result = __FAILURE__;
AzureIoTClient 56:8704100b3b54 181 }
AzureIoTClient 56:8704100b3b54 182 else if (message_set_properties(message, properties) != RESULT_OK)
AzureIoTClient 56:8704100b3b54 183 {
AzureIoTClient 56:8704100b3b54 184 LogError("Failed setting the AMQP message properties");
AzureIoTClient 56:8704100b3b54 185 result = __FAILURE__;
AzureIoTClient 56:8704100b3b54 186 }
AzureIoTClient 56:8704100b3b54 187 else
AzureIoTClient 56:8704100b3b54 188 {
AzureIoTClient 56:8704100b3b54 189 result = RESULT_OK;
AzureIoTClient 56:8704100b3b54 190 }
AzureIoTClient 39:e98d5df6dc74 191
AzureIoTClient 56:8704100b3b54 192 amqpvalue_destroy(amqp_value);
AzureIoTClient 56:8704100b3b54 193 }
AzureIoTClient 39:e98d5df6dc74 194
AzureIoTClient 56:8704100b3b54 195 properties_destroy(properties);
AzureIoTClient 56:8704100b3b54 196 }
AzureIoTClient 39:e98d5df6dc74 197
AzureIoTClient 56:8704100b3b54 198 return result;
AzureIoTClient 39:e98d5df6dc74 199 }
AzureIoTClient 39:e98d5df6dc74 200
AzureIoTClient 39:e98d5df6dc74 201 static int get_message_correlation_id(MESSAGE_HANDLE message, char** correlation_id)
AzureIoTClient 39:e98d5df6dc74 202 {
AzureIoTClient 56:8704100b3b54 203 int result;
AzureIoTClient 39:e98d5df6dc74 204
AzureIoTClient 56:8704100b3b54 205 PROPERTIES_HANDLE properties;
AzureIoTClient 56:8704100b3b54 206 AMQP_VALUE amqp_value;
AzureIoTClient 39:e98d5df6dc74 207
AzureIoTClient 56:8704100b3b54 208 if (message_get_properties(message, &properties) != 0)
AzureIoTClient 56:8704100b3b54 209 {
AzureIoTClient 56:8704100b3b54 210 LogError("Failed getting AMQP message properties");
AzureIoTClient 56:8704100b3b54 211 result = __FAILURE__;
AzureIoTClient 56:8704100b3b54 212 }
AzureIoTClient 56:8704100b3b54 213 else if (properties == NULL)
AzureIoTClient 56:8704100b3b54 214 {
AzureIoTClient 56:8704100b3b54 215 *correlation_id = NULL;
AzureIoTClient 56:8704100b3b54 216 result = RESULT_OK;
AzureIoTClient 56:8704100b3b54 217 }
AzureIoTClient 56:8704100b3b54 218 else
AzureIoTClient 56:8704100b3b54 219 {
AzureIoTClient 56:8704100b3b54 220 if (properties_get_correlation_id(properties, &amqp_value) != 0 || amqp_value == NULL)
AzureIoTClient 56:8704100b3b54 221 {
AzureIoTClient 56:8704100b3b54 222 *correlation_id = NULL;
AzureIoTClient 56:8704100b3b54 223 result = RESULT_OK;
AzureIoTClient 56:8704100b3b54 224 }
AzureIoTClient 56:8704100b3b54 225 else
AzureIoTClient 56:8704100b3b54 226 {
AzureIoTClient 56:8704100b3b54 227 const char* value;
AzureIoTClient 39:e98d5df6dc74 228
AzureIoTClient 56:8704100b3b54 229 if (amqpvalue_get_string(amqp_value, &value) != 0)
AzureIoTClient 56:8704100b3b54 230 {
AzureIoTClient 56:8704100b3b54 231 LogError("Failed retrieving string from AMQP value");
AzureIoTClient 56:8704100b3b54 232 result = __FAILURE__;
AzureIoTClient 56:8704100b3b54 233 }
AzureIoTClient 56:8704100b3b54 234 else if (mallocAndStrcpy_s(correlation_id, value) != 0)
AzureIoTClient 56:8704100b3b54 235 {
AzureIoTClient 56:8704100b3b54 236 LogError("Failed cloning correlation-id");
AzureIoTClient 56:8704100b3b54 237 result = __FAILURE__;
AzureIoTClient 56:8704100b3b54 238 }
AzureIoTClient 56:8704100b3b54 239 else
AzureIoTClient 56:8704100b3b54 240 {
AzureIoTClient 56:8704100b3b54 241 result = RESULT_OK;
AzureIoTClient 56:8704100b3b54 242 }
AzureIoTClient 56:8704100b3b54 243 }
AzureIoTClient 39:e98d5df6dc74 244
AzureIoTClient 56:8704100b3b54 245 properties_destroy(properties);
AzureIoTClient 56:8704100b3b54 246 }
AzureIoTClient 39:e98d5df6dc74 247
AzureIoTClient 56:8704100b3b54 248 return result;
AzureIoTClient 39:e98d5df6dc74 249 }
AzureIoTClient 39:e98d5df6dc74 250
AzureIoTClient 39:e98d5df6dc74 251 static int add_map_item(AMQP_VALUE map, const char* name, const char* value)
AzureIoTClient 39:e98d5df6dc74 252 {
AzureIoTClient 56:8704100b3b54 253 int result;
AzureIoTClient 56:8704100b3b54 254 AMQP_VALUE amqp_value_name;
AzureIoTClient 56:8704100b3b54 255
AzureIoTClient 56:8704100b3b54 256 if ((amqp_value_name = amqpvalue_create_symbol(name)) == NULL)
AzureIoTClient 56:8704100b3b54 257 {
AzureIoTClient 56:8704100b3b54 258 LogError("Failed creating AMQP_VALUE for name");
AzureIoTClient 56:8704100b3b54 259 result = __FAILURE__;
AzureIoTClient 56:8704100b3b54 260 }
AzureIoTClient 56:8704100b3b54 261 else
AzureIoTClient 56:8704100b3b54 262 {
AzureIoTClient 56:8704100b3b54 263 AMQP_VALUE amqp_value_value = NULL;
AzureIoTClient 39:e98d5df6dc74 264
AzureIoTClient 56:8704100b3b54 265 if (value == NULL && (amqp_value_value = amqpvalue_create_null()) == NULL)
AzureIoTClient 56:8704100b3b54 266 {
AzureIoTClient 56:8704100b3b54 267 LogError("Failed creating AMQP_VALUE for NULL value");
AzureIoTClient 56:8704100b3b54 268 result = __FAILURE__;
AzureIoTClient 56:8704100b3b54 269 }
AzureIoTClient 56:8704100b3b54 270 else if (value != NULL && (amqp_value_value = amqpvalue_create_string(value)) == NULL)
AzureIoTClient 56:8704100b3b54 271 {
AzureIoTClient 56:8704100b3b54 272 LogError("Failed creating AMQP_VALUE for value");
AzureIoTClient 56:8704100b3b54 273 result = __FAILURE__;
AzureIoTClient 56:8704100b3b54 274 }
AzureIoTClient 56:8704100b3b54 275 else
AzureIoTClient 56:8704100b3b54 276 {
AzureIoTClient 56:8704100b3b54 277 if (amqpvalue_set_map_value(map, amqp_value_name, amqp_value_value) != 0)
AzureIoTClient 56:8704100b3b54 278 {
AzureIoTClient 56:8704100b3b54 279 LogError("Failed adding key/value pair to map");
AzureIoTClient 56:8704100b3b54 280 result = __FAILURE__;
AzureIoTClient 56:8704100b3b54 281 }
AzureIoTClient 56:8704100b3b54 282 else
AzureIoTClient 56:8704100b3b54 283 {
AzureIoTClient 56:8704100b3b54 284 result = RESULT_OK;
AzureIoTClient 56:8704100b3b54 285 }
AzureIoTClient 39:e98d5df6dc74 286
AzureIoTClient 56:8704100b3b54 287 amqpvalue_destroy(amqp_value_value);
AzureIoTClient 56:8704100b3b54 288 }
AzureIoTClient 39:e98d5df6dc74 289
AzureIoTClient 56:8704100b3b54 290 amqpvalue_destroy(amqp_value_name);
AzureIoTClient 56:8704100b3b54 291 }
AzureIoTClient 39:e98d5df6dc74 292
AzureIoTClient 56:8704100b3b54 293 return result;
AzureIoTClient 39:e98d5df6dc74 294 }
AzureIoTClient 39:e98d5df6dc74 295
AzureIoTClient 39:e98d5df6dc74 296 static int add_amqp_message_annotation(MESSAGE_HANDLE message, AMQP_VALUE msg_annotations_map)
AzureIoTClient 39:e98d5df6dc74 297 {
AzureIoTClient 56:8704100b3b54 298 int result;
AzureIoTClient 56:8704100b3b54 299 AMQP_VALUE msg_annotations;
AzureIoTClient 39:e98d5df6dc74 300
AzureIoTClient 56:8704100b3b54 301 if ((msg_annotations = amqpvalue_create_message_annotations(msg_annotations_map)) == NULL)
AzureIoTClient 56:8704100b3b54 302 {
AzureIoTClient 56:8704100b3b54 303 LogError("Failed creating new AMQP message annotations");
AzureIoTClient 56:8704100b3b54 304 result = __FAILURE__;
AzureIoTClient 56:8704100b3b54 305 }
AzureIoTClient 56:8704100b3b54 306 else
AzureIoTClient 56:8704100b3b54 307 {
AzureIoTClient 56:8704100b3b54 308 if (message_set_message_annotations(message, (annotations)msg_annotations) != 0)
AzureIoTClient 56:8704100b3b54 309 {
AzureIoTClient 56:8704100b3b54 310 LogError("Failed setting AMQP message annotations");
AzureIoTClient 56:8704100b3b54 311 result = __FAILURE__;
AzureIoTClient 56:8704100b3b54 312 }
AzureIoTClient 56:8704100b3b54 313 else
AzureIoTClient 56:8704100b3b54 314 {
AzureIoTClient 56:8704100b3b54 315 result = RESULT_OK;
AzureIoTClient 56:8704100b3b54 316 }
AzureIoTClient 39:e98d5df6dc74 317
AzureIoTClient 56:8704100b3b54 318 annotations_destroy(msg_annotations);
AzureIoTClient 56:8704100b3b54 319 }
AzureIoTClient 39:e98d5df6dc74 320
AzureIoTClient 56:8704100b3b54 321 return result;
AzureIoTClient 39:e98d5df6dc74 322 }
AzureIoTClient 39:e98d5df6dc74 323
AzureIoTClient 39:e98d5df6dc74 324
AzureIoTClient 39:e98d5df6dc74 325 //---------- TWIN Helpers ----------//
AzureIoTClient 39:e98d5df6dc74 326
AzureIoTClient 39:e98d5df6dc74 327 static char* generate_unique_id()
AzureIoTClient 39:e98d5df6dc74 328 {
AzureIoTClient 56:8704100b3b54 329 char* result;
AzureIoTClient 39:e98d5df6dc74 330
AzureIoTClient 56:8704100b3b54 331 if ((result = (char*)malloc(sizeof(char) * UNIQUE_ID_BUFFER_SIZE + 1)) == NULL)
AzureIoTClient 56:8704100b3b54 332 {
AzureIoTClient 56:8704100b3b54 333 LogError("Failed generating an unique tag (malloc failed)");
AzureIoTClient 56:8704100b3b54 334 }
AzureIoTClient 56:8704100b3b54 335 else
AzureIoTClient 56:8704100b3b54 336 {
AzureIoTClient 56:8704100b3b54 337 memset(result, 0, sizeof(char) * UNIQUE_ID_BUFFER_SIZE + 1);
AzureIoTClient 39:e98d5df6dc74 338
AzureIoTClient 56:8704100b3b54 339 if (UniqueId_Generate(result, UNIQUE_ID_BUFFER_SIZE) != UNIQUEID_OK)
AzureIoTClient 56:8704100b3b54 340 {
AzureIoTClient 56:8704100b3b54 341 LogError("Failed generating an unique tag (UniqueId_Generate failed)");
AzureIoTClient 56:8704100b3b54 342 free(result);
AzureIoTClient 56:8704100b3b54 343 result = NULL;
AzureIoTClient 56:8704100b3b54 344 }
AzureIoTClient 56:8704100b3b54 345 }
AzureIoTClient 39:e98d5df6dc74 346
AzureIoTClient 56:8704100b3b54 347 return result;
AzureIoTClient 39:e98d5df6dc74 348 }
AzureIoTClient 39:e98d5df6dc74 349
AzureIoTClient 39:e98d5df6dc74 350 static char* generate_twin_correlation_id()
AzureIoTClient 39:e98d5df6dc74 351 {
AzureIoTClient 56:8704100b3b54 352 char* result;
AzureIoTClient 56:8704100b3b54 353 char* unique_id;
AzureIoTClient 39:e98d5df6dc74 354
AzureIoTClient 56:8704100b3b54 355 if ((unique_id = generate_unique_id()) == NULL)
AzureIoTClient 56:8704100b3b54 356 {
AzureIoTClient 56:8704100b3b54 357 LogError("Failed generating unique ID for correlation-id");
AzureIoTClient 56:8704100b3b54 358 result = NULL;
AzureIoTClient 56:8704100b3b54 359 }
AzureIoTClient 56:8704100b3b54 360 else
AzureIoTClient 56:8704100b3b54 361 {
AzureIoTClient 56:8704100b3b54 362 if ((result = (char*)malloc(strlen(TWIN_CORRELATION_ID_PROPERTY_FORMAT) + strlen(unique_id) + 1)) == NULL)
AzureIoTClient 56:8704100b3b54 363 {
AzureIoTClient 56:8704100b3b54 364 LogError("Failed allocating correlation-id");
AzureIoTClient 56:8704100b3b54 365 result = NULL;
AzureIoTClient 56:8704100b3b54 366 }
AzureIoTClient 56:8704100b3b54 367 else
AzureIoTClient 56:8704100b3b54 368 {
AzureIoTClient 56:8704100b3b54 369 (void)sprintf(result, TWIN_CORRELATION_ID_PROPERTY_FORMAT, unique_id);
AzureIoTClient 56:8704100b3b54 370 }
AzureIoTClient 39:e98d5df6dc74 371
AzureIoTClient 56:8704100b3b54 372 free(unique_id);
AzureIoTClient 56:8704100b3b54 373 }
AzureIoTClient 39:e98d5df6dc74 374
AzureIoTClient 56:8704100b3b54 375 return result;
AzureIoTClient 39:e98d5df6dc74 376 }
AzureIoTClient 39:e98d5df6dc74 377
AzureIoTClient 39:e98d5df6dc74 378 static TWIN_OPERATION_CONTEXT* create_twin_operation_context(TWIN_MESSENGER_INSTANCE* twin_msgr, TWIN_OPERATION_TYPE type)
AzureIoTClient 39:e98d5df6dc74 379 {
AzureIoTClient 56:8704100b3b54 380 TWIN_OPERATION_CONTEXT* result;
AzureIoTClient 39:e98d5df6dc74 381
AzureIoTClient 56:8704100b3b54 382 if ((result = (TWIN_OPERATION_CONTEXT*)malloc(sizeof(TWIN_OPERATION_CONTEXT))) == NULL)
AzureIoTClient 56:8704100b3b54 383 {
AzureIoTClient 56:8704100b3b54 384 LogError("Failed creating context for %s (%s)", ENUM_TO_STRING(TWIN_OPERATION_TYPE, type), twin_msgr->device_id);
AzureIoTClient 56:8704100b3b54 385 }
AzureIoTClient 56:8704100b3b54 386 else
AzureIoTClient 56:8704100b3b54 387 {
AzureIoTClient 56:8704100b3b54 388 memset(result, 0, sizeof(TWIN_OPERATION_CONTEXT));
AzureIoTClient 39:e98d5df6dc74 389
AzureIoTClient 56:8704100b3b54 390 if ((result->correlation_id = generate_unique_id()) == NULL)
AzureIoTClient 56:8704100b3b54 391 {
AzureIoTClient 56:8704100b3b54 392 LogError("Failed setting context correlation-id (%s, %s)", ENUM_TO_STRING(TWIN_OPERATION_TYPE, type), twin_msgr->device_id);
AzureIoTClient 56:8704100b3b54 393 free(result);
AzureIoTClient 56:8704100b3b54 394 result = NULL;
AzureIoTClient 56:8704100b3b54 395 }
AzureIoTClient 56:8704100b3b54 396 else
AzureIoTClient 56:8704100b3b54 397 {
AzureIoTClient 56:8704100b3b54 398 result->type = type;
AzureIoTClient 56:8704100b3b54 399 result->msgr = twin_msgr;
AzureIoTClient 56:8704100b3b54 400 }
AzureIoTClient 56:8704100b3b54 401 }
AzureIoTClient 39:e98d5df6dc74 402
AzureIoTClient 56:8704100b3b54 403 return result;
AzureIoTClient 39:e98d5df6dc74 404 }
AzureIoTClient 39:e98d5df6dc74 405
AzureIoTClient 39:e98d5df6dc74 406 static bool find_twin_operation_by_correlation_id(LIST_ITEM_HANDLE list_item, const void* match_context)
AzureIoTClient 39:e98d5df6dc74 407 {
AzureIoTClient 56:8704100b3b54 408 TWIN_OPERATION_CONTEXT* twin_op_ctx = (TWIN_OPERATION_CONTEXT*)singlylinkedlist_item_get_value(list_item);
AzureIoTClient 56:8704100b3b54 409 return (strcmp(twin_op_ctx->correlation_id, (const char*)match_context) == 0);
AzureIoTClient 39:e98d5df6dc74 410 }
AzureIoTClient 39:e98d5df6dc74 411
AzureIoTClient 39:e98d5df6dc74 412 static bool find_twin_operation_by_type(LIST_ITEM_HANDLE list_item, const void* match_context)
AzureIoTClient 39:e98d5df6dc74 413 {
AzureIoTClient 56:8704100b3b54 414 TWIN_OPERATION_CONTEXT* twin_op_ctx = (TWIN_OPERATION_CONTEXT*)singlylinkedlist_item_get_value(list_item);
AzureIoTClient 56:8704100b3b54 415 return (twin_op_ctx->type == *(TWIN_OPERATION_TYPE*)match_context);
AzureIoTClient 39:e98d5df6dc74 416 }
AzureIoTClient 39:e98d5df6dc74 417
AzureIoTClient 39:e98d5df6dc74 418 static void destroy_twin_operation_context(TWIN_OPERATION_CONTEXT* op_ctx)
AzureIoTClient 39:e98d5df6dc74 419 {
AzureIoTClient 56:8704100b3b54 420 free(op_ctx->correlation_id);
AzureIoTClient 56:8704100b3b54 421 free(op_ctx);
AzureIoTClient 39:e98d5df6dc74 422 }
AzureIoTClient 39:e98d5df6dc74 423
AzureIoTClient 39:e98d5df6dc74 424 static int add_twin_operation_context_to_queue(TWIN_OPERATION_CONTEXT* twin_op_ctx)
AzureIoTClient 39:e98d5df6dc74 425 {
AzureIoTClient 56:8704100b3b54 426 int result;
AzureIoTClient 39:e98d5df6dc74 427
AzureIoTClient 56:8704100b3b54 428 if (singlylinkedlist_add(twin_op_ctx->msgr->operations, (const void*)twin_op_ctx) == NULL)
AzureIoTClient 56:8704100b3b54 429 {
AzureIoTClient 56:8704100b3b54 430 LogError("Failed adding TWIN operation context to queue (%s, %s)", ENUM_TO_STRING(TWIN_OPERATION_TYPE, twin_op_ctx->type), twin_op_ctx->correlation_id);
AzureIoTClient 56:8704100b3b54 431 result = __FAILURE__;
AzureIoTClient 56:8704100b3b54 432 }
AzureIoTClient 56:8704100b3b54 433 else
AzureIoTClient 56:8704100b3b54 434 {
AzureIoTClient 56:8704100b3b54 435 result = RESULT_OK;
AzureIoTClient 56:8704100b3b54 436 }
AzureIoTClient 39:e98d5df6dc74 437
AzureIoTClient 56:8704100b3b54 438 return result;
AzureIoTClient 39:e98d5df6dc74 439 }
AzureIoTClient 39:e98d5df6dc74 440
AzureIoTClient 39:e98d5df6dc74 441 static int remove_twin_operation_context_from_queue(TWIN_OPERATION_CONTEXT* twin_op_ctx)
AzureIoTClient 39:e98d5df6dc74 442 {
AzureIoTClient 56:8704100b3b54 443 int result;
AzureIoTClient 56:8704100b3b54 444 LIST_ITEM_HANDLE list_item;
AzureIoTClient 39:e98d5df6dc74 445
AzureIoTClient 56:8704100b3b54 446 if ((list_item = singlylinkedlist_find(twin_op_ctx->msgr->operations, find_twin_operation_by_correlation_id, (const void*)twin_op_ctx->correlation_id)) == NULL)
AzureIoTClient 56:8704100b3b54 447 {
AzureIoTClient 56:8704100b3b54 448 result = RESULT_OK;
AzureIoTClient 56:8704100b3b54 449 }
AzureIoTClient 56:8704100b3b54 450 else if (singlylinkedlist_remove(twin_op_ctx->msgr->operations, list_item) != 0)
AzureIoTClient 56:8704100b3b54 451 {
AzureIoTClient 56:8704100b3b54 452 LogError("Failed removing TWIN operation context from queue (%s, %s, %s)",
AzureIoTClient 56:8704100b3b54 453 twin_op_ctx->msgr->device_id, ENUM_TO_STRING(TWIN_OPERATION_TYPE, twin_op_ctx->type), twin_op_ctx->correlation_id);
AzureIoTClient 56:8704100b3b54 454 result = __FAILURE__;
AzureIoTClient 56:8704100b3b54 455 }
AzureIoTClient 56:8704100b3b54 456 else
AzureIoTClient 56:8704100b3b54 457 {
AzureIoTClient 56:8704100b3b54 458 result = RESULT_OK;
AzureIoTClient 56:8704100b3b54 459 }
AzureIoTClient 39:e98d5df6dc74 460
AzureIoTClient 56:8704100b3b54 461 return result;
AzureIoTClient 39:e98d5df6dc74 462 }
AzureIoTClient 39:e98d5df6dc74 463
AzureIoTClient 39:e98d5df6dc74 464
AzureIoTClient 39:e98d5df6dc74 465 //---------- TWIN <-> AMQP Translation Functions ----------//
AzureIoTClient 39:e98d5df6dc74 466
AzureIoTClient 39:e98d5df6dc74 467 static int parse_incoming_twin_message(MESSAGE_HANDLE message,
AzureIoTClient 56:8704100b3b54 468 char** correlation_id,
AzureIoTClient 56:8704100b3b54 469 bool* has_version, int64_t* version,
AzureIoTClient 56:8704100b3b54 470 bool* has_status_code, int* status_code,
AzureIoTClient 56:8704100b3b54 471 bool* has_twin_report, BINARY_DATA* twin_report)
AzureIoTClient 39:e98d5df6dc74 472 {
AzureIoTClient 56:8704100b3b54 473 int result;
AzureIoTClient 39:e98d5df6dc74 474
AzureIoTClient 56:8704100b3b54 475 if (get_message_correlation_id(message, correlation_id) != 0)
AzureIoTClient 56:8704100b3b54 476 {
AzureIoTClient 56:8704100b3b54 477 LogError("Failed retrieving correlation ID from received TWIN message.");
AzureIoTClient 56:8704100b3b54 478 result = __FAILURE__;
AzureIoTClient 56:8704100b3b54 479 }
AzureIoTClient 56:8704100b3b54 480 else
AzureIoTClient 56:8704100b3b54 481 {
AzureIoTClient 56:8704100b3b54 482 annotations message_annotations;
AzureIoTClient 39:e98d5df6dc74 483
AzureIoTClient 56:8704100b3b54 484 if (message_get_message_annotations(message, &message_annotations) != 0)
AzureIoTClient 56:8704100b3b54 485 {
AzureIoTClient 56:8704100b3b54 486 LogError("Failed getting TWIN message annotations");
AzureIoTClient 56:8704100b3b54 487 result = __FAILURE__;
AzureIoTClient 56:8704100b3b54 488 }
AzureIoTClient 56:8704100b3b54 489 else
AzureIoTClient 56:8704100b3b54 490 {
AzureIoTClient 56:8704100b3b54 491 result = RESULT_OK;
AzureIoTClient 39:e98d5df6dc74 492
AzureIoTClient 56:8704100b3b54 493 if (message_annotations == NULL)
AzureIoTClient 56:8704100b3b54 494 {
AzureIoTClient 56:8704100b3b54 495 *has_version = false;
AzureIoTClient 56:8704100b3b54 496 *has_status_code = false;
AzureIoTClient 56:8704100b3b54 497 }
AzureIoTClient 56:8704100b3b54 498 else
AzureIoTClient 56:8704100b3b54 499 {
AzureIoTClient 56:8704100b3b54 500 uint32_t pair_count;
AzureIoTClient 56:8704100b3b54 501 if (amqpvalue_get_map_pair_count((AMQP_VALUE)message_annotations, &pair_count) != 0)
AzureIoTClient 56:8704100b3b54 502 {
AzureIoTClient 56:8704100b3b54 503 LogError("Failed getting TWIN message annotations count");
AzureIoTClient 56:8704100b3b54 504 result = __FAILURE__;
AzureIoTClient 56:8704100b3b54 505 }
AzureIoTClient 56:8704100b3b54 506 else
AzureIoTClient 56:8704100b3b54 507 {
AzureIoTClient 56:8704100b3b54 508 uint32_t i;
AzureIoTClient 39:e98d5df6dc74 509
AzureIoTClient 56:8704100b3b54 510 *has_status_code = false;
AzureIoTClient 56:8704100b3b54 511 *has_version = false;
AzureIoTClient 39:e98d5df6dc74 512
AzureIoTClient 56:8704100b3b54 513 for (i = 0; i < pair_count; i++)
AzureIoTClient 56:8704100b3b54 514 {
AzureIoTClient 56:8704100b3b54 515 AMQP_VALUE amqp_map_key;
AzureIoTClient 56:8704100b3b54 516 AMQP_VALUE amqp_map_value;
AzureIoTClient 39:e98d5df6dc74 517
AzureIoTClient 56:8704100b3b54 518 if (amqpvalue_get_map_key_value_pair((AMQP_VALUE)message_annotations, i, &amqp_map_key, &amqp_map_value) != 0)
AzureIoTClient 56:8704100b3b54 519 {
AzureIoTClient 56:8704100b3b54 520 LogError("Failed getting AMQP map key/value pair (%d)", i);
AzureIoTClient 56:8704100b3b54 521 result = __FAILURE__;
AzureIoTClient 56:8704100b3b54 522 }
AzureIoTClient 56:8704100b3b54 523 else
AzureIoTClient 56:8704100b3b54 524 {
AzureIoTClient 56:8704100b3b54 525 const char* map_key_name;
AzureIoTClient 39:e98d5df6dc74 526
AzureIoTClient 56:8704100b3b54 527 if (amqpvalue_get_symbol(amqp_map_key, &map_key_name) != 0)
AzureIoTClient 56:8704100b3b54 528 {
AzureIoTClient 56:8704100b3b54 529 LogError("Failed getting AMQP value symbol");
AzureIoTClient 56:8704100b3b54 530 result = __FAILURE__;
AzureIoTClient 56:8704100b3b54 531 break;
AzureIoTClient 56:8704100b3b54 532 }
AzureIoTClient 56:8704100b3b54 533 else
AzureIoTClient 56:8704100b3b54 534 {
AzureIoTClient 56:8704100b3b54 535 if (strcmp(TWIN_MESSAGE_PROPERTY_STATUS, map_key_name) == 0)
AzureIoTClient 56:8704100b3b54 536 {
AzureIoTClient 56:8704100b3b54 537 if (amqpvalue_get_type(amqp_map_value) != AMQP_TYPE_INT)
AzureIoTClient 56:8704100b3b54 538 {
AzureIoTClient 56:8704100b3b54 539 LogError("TWIN message status property expected to be INT");
AzureIoTClient 56:8704100b3b54 540 result = __FAILURE__;
AzureIoTClient 56:8704100b3b54 541 break;
AzureIoTClient 56:8704100b3b54 542 }
AzureIoTClient 56:8704100b3b54 543 else if (amqpvalue_get_int(amqp_map_value, status_code) != 0)
AzureIoTClient 56:8704100b3b54 544 {
AzureIoTClient 56:8704100b3b54 545 LogError("Failed getting TWIN message status code value");
AzureIoTClient 56:8704100b3b54 546 result = __FAILURE__;
AzureIoTClient 56:8704100b3b54 547 break;
AzureIoTClient 56:8704100b3b54 548 }
AzureIoTClient 56:8704100b3b54 549 else
AzureIoTClient 56:8704100b3b54 550 {
AzureIoTClient 56:8704100b3b54 551 *has_status_code = true;
AzureIoTClient 56:8704100b3b54 552 }
AzureIoTClient 56:8704100b3b54 553 }
AzureIoTClient 56:8704100b3b54 554 else if (strcmp(TWIN_MESSAGE_PROPERTY_VERSION, map_key_name) == 0)
AzureIoTClient 56:8704100b3b54 555 {
AzureIoTClient 56:8704100b3b54 556 if (amqpvalue_get_type(amqp_map_value) != AMQP_TYPE_LONG)
AzureIoTClient 56:8704100b3b54 557 {
AzureIoTClient 56:8704100b3b54 558 LogError("TWIN message version property expected to be LONG");
AzureIoTClient 56:8704100b3b54 559 result = __FAILURE__;
AzureIoTClient 56:8704100b3b54 560 break;
AzureIoTClient 56:8704100b3b54 561 }
AzureIoTClient 56:8704100b3b54 562 else if (amqpvalue_get_long(amqp_map_value, version) != 0)
AzureIoTClient 56:8704100b3b54 563 {
AzureIoTClient 56:8704100b3b54 564 LogError("Failed getting TWIN message version value");
AzureIoTClient 56:8704100b3b54 565 result = __FAILURE__;
AzureIoTClient 56:8704100b3b54 566 break;
AzureIoTClient 56:8704100b3b54 567 }
AzureIoTClient 56:8704100b3b54 568 else
AzureIoTClient 56:8704100b3b54 569 {
AzureIoTClient 56:8704100b3b54 570 *has_version = true;
AzureIoTClient 56:8704100b3b54 571 }
AzureIoTClient 56:8704100b3b54 572 }
AzureIoTClient 39:e98d5df6dc74 573
AzureIoTClient 56:8704100b3b54 574 amqpvalue_destroy(amqp_map_value);
AzureIoTClient 56:8704100b3b54 575 }
AzureIoTClient 39:e98d5df6dc74 576
AzureIoTClient 56:8704100b3b54 577 amqpvalue_destroy(amqp_map_key);
AzureIoTClient 56:8704100b3b54 578 }
AzureIoTClient 56:8704100b3b54 579 }
AzureIoTClient 56:8704100b3b54 580 }
AzureIoTClient 39:e98d5df6dc74 581
AzureIoTClient 56:8704100b3b54 582 amqpvalue_destroy(message_annotations);
AzureIoTClient 56:8704100b3b54 583 }
AzureIoTClient 39:e98d5df6dc74 584
AzureIoTClient 56:8704100b3b54 585 if (result == RESULT_OK)
AzureIoTClient 56:8704100b3b54 586 {
AzureIoTClient 56:8704100b3b54 587 MESSAGE_BODY_TYPE body_type;
AzureIoTClient 39:e98d5df6dc74 588
AzureIoTClient 56:8704100b3b54 589 if (message_get_body_type(message, &body_type) != 0)
AzureIoTClient 56:8704100b3b54 590 {
AzureIoTClient 56:8704100b3b54 591 LogError("Failed getting TWIN message body type");
AzureIoTClient 56:8704100b3b54 592 result = __FAILURE__;
AzureIoTClient 56:8704100b3b54 593 }
AzureIoTClient 56:8704100b3b54 594 else if (body_type == MESSAGE_BODY_TYPE_DATA)
AzureIoTClient 56:8704100b3b54 595 {
AzureIoTClient 56:8704100b3b54 596 size_t body_count;
AzureIoTClient 39:e98d5df6dc74 597
AzureIoTClient 56:8704100b3b54 598 if (message_get_body_amqp_data_count(message, &body_count) != 0)
AzureIoTClient 56:8704100b3b54 599 {
AzureIoTClient 56:8704100b3b54 600 LogError("Failed getting TWIN message body count");
AzureIoTClient 56:8704100b3b54 601 result = __FAILURE__;
AzureIoTClient 56:8704100b3b54 602 }
AzureIoTClient 56:8704100b3b54 603 else if (body_count != 1)
AzureIoTClient 56:8704100b3b54 604 {
AzureIoTClient 56:8704100b3b54 605 LogError("Unexpected number of TWIN message bodies (%d)", body_count);
AzureIoTClient 56:8704100b3b54 606 result = __FAILURE__;
AzureIoTClient 56:8704100b3b54 607 }
AzureIoTClient 56:8704100b3b54 608 else if (message_get_body_amqp_data_in_place(message, 0, twin_report) != 0)
AzureIoTClient 56:8704100b3b54 609 {
AzureIoTClient 56:8704100b3b54 610 LogError("Failed getting TWIN message body");
AzureIoTClient 56:8704100b3b54 611 result = __FAILURE__;
AzureIoTClient 56:8704100b3b54 612 }
AzureIoTClient 56:8704100b3b54 613 else
AzureIoTClient 56:8704100b3b54 614 {
AzureIoTClient 56:8704100b3b54 615 *has_twin_report = true;
AzureIoTClient 56:8704100b3b54 616 }
AzureIoTClient 56:8704100b3b54 617 }
AzureIoTClient 56:8704100b3b54 618 else if (body_type != MESSAGE_BODY_TYPE_NONE)
AzureIoTClient 56:8704100b3b54 619 {
AzureIoTClient 56:8704100b3b54 620 LogError("Unexpected TWIN message body %d", body_type);
AzureIoTClient 56:8704100b3b54 621 result = __FAILURE__;
AzureIoTClient 56:8704100b3b54 622 }
AzureIoTClient 56:8704100b3b54 623 else
AzureIoTClient 56:8704100b3b54 624 {
AzureIoTClient 56:8704100b3b54 625 *has_twin_report = false;
AzureIoTClient 56:8704100b3b54 626 }
AzureIoTClient 56:8704100b3b54 627 }
AzureIoTClient 56:8704100b3b54 628 }
AzureIoTClient 39:e98d5df6dc74 629
AzureIoTClient 56:8704100b3b54 630 if (result != RESULT_OK)
AzureIoTClient 56:8704100b3b54 631 {
AzureIoTClient 56:8704100b3b54 632 free(*correlation_id);
AzureIoTClient 56:8704100b3b54 633 *correlation_id = NULL;
AzureIoTClient 56:8704100b3b54 634 }
AzureIoTClient 56:8704100b3b54 635 }
AzureIoTClient 39:e98d5df6dc74 636
AzureIoTClient 56:8704100b3b54 637 return result;
AzureIoTClient 39:e98d5df6dc74 638 }
AzureIoTClient 39:e98d5df6dc74 639
AzureIoTClient 39:e98d5df6dc74 640 static void destroy_link_attach_properties(MAP_HANDLE properties)
AzureIoTClient 39:e98d5df6dc74 641 {
AzureIoTClient 56:8704100b3b54 642 Map_Destroy(properties);
AzureIoTClient 39:e98d5df6dc74 643 }
AzureIoTClient 39:e98d5df6dc74 644
AzureIoTClient 39:e98d5df6dc74 645 static MAP_HANDLE create_link_attach_properties(TWIN_MESSENGER_INSTANCE* twin_msgr)
AzureIoTClient 39:e98d5df6dc74 646 {
AzureIoTClient 56:8704100b3b54 647 MAP_HANDLE result;
AzureIoTClient 39:e98d5df6dc74 648
AzureIoTClient 56:8704100b3b54 649 if ((result = Map_Create(NULL)) == NULL)
AzureIoTClient 56:8704100b3b54 650 {
AzureIoTClient 56:8704100b3b54 651 LogError("Failed creating map for AMQP link properties (%s)", twin_msgr->device_id);
AzureIoTClient 56:8704100b3b54 652 }
AzureIoTClient 56:8704100b3b54 653 else
AzureIoTClient 56:8704100b3b54 654 {
AzureIoTClient 56:8704100b3b54 655 char* correlation_id;
AzureIoTClient 39:e98d5df6dc74 656
AzureIoTClient 56:8704100b3b54 657 if ((correlation_id = generate_twin_correlation_id()) == NULL)
AzureIoTClient 56:8704100b3b54 658 {
AzureIoTClient 56:8704100b3b54 659 LogError("Failed adding AMQP link property ");
AzureIoTClient 56:8704100b3b54 660 destroy_link_attach_properties(result);
AzureIoTClient 56:8704100b3b54 661 result = NULL;
AzureIoTClient 56:8704100b3b54 662 }
AzureIoTClient 56:8704100b3b54 663 else
AzureIoTClient 56:8704100b3b54 664 {
AzureIoTClient 56:8704100b3b54 665 if (Map_Add(result, CLIENT_VERSION_PROPERTY_NAME, twin_msgr->client_version) != MAP_OK)
AzureIoTClient 56:8704100b3b54 666 {
AzureIoTClient 56:8704100b3b54 667 LogError("Failed adding AMQP link property 'client version' (%s)", twin_msgr->device_id);
AzureIoTClient 56:8704100b3b54 668 destroy_link_attach_properties(result);
AzureIoTClient 56:8704100b3b54 669 result = NULL;
AzureIoTClient 56:8704100b3b54 670 }
AzureIoTClient 56:8704100b3b54 671 else if (Map_Add(result, TWIN_CORRELATION_ID_PROPERTY_NAME, correlation_id) != MAP_OK)
AzureIoTClient 56:8704100b3b54 672 {
AzureIoTClient 56:8704100b3b54 673 LogError("Failed adding AMQP link property 'correlation-id' (%s)", twin_msgr->device_id);
AzureIoTClient 56:8704100b3b54 674 destroy_link_attach_properties(result);
AzureIoTClient 56:8704100b3b54 675 result = NULL;
AzureIoTClient 56:8704100b3b54 676 }
AzureIoTClient 56:8704100b3b54 677 else if (Map_Add(result, TWIN_API_VERSION_PROPERTY_NAME, TWIN_API_VERSION_NUMBER) != MAP_OK)
AzureIoTClient 56:8704100b3b54 678 {
AzureIoTClient 56:8704100b3b54 679 LogError("Failed adding AMQP link property 'api-version' (%s)", twin_msgr->device_id);
AzureIoTClient 56:8704100b3b54 680 destroy_link_attach_properties(result);
AzureIoTClient 56:8704100b3b54 681 result = NULL;
AzureIoTClient 56:8704100b3b54 682 }
AzureIoTClient 39:e98d5df6dc74 683
AzureIoTClient 56:8704100b3b54 684 free(correlation_id);
AzureIoTClient 56:8704100b3b54 685 }
AzureIoTClient 56:8704100b3b54 686 }
AzureIoTClient 39:e98d5df6dc74 687
AzureIoTClient 56:8704100b3b54 688 return result;
AzureIoTClient 39:e98d5df6dc74 689 }
AzureIoTClient 39:e98d5df6dc74 690
AzureIoTClient 39:e98d5df6dc74 691 static const char* get_twin_operation_name(TWIN_OPERATION_TYPE op_type)
AzureIoTClient 39:e98d5df6dc74 692 {
AzureIoTClient 56:8704100b3b54 693 const char* result;
AzureIoTClient 39:e98d5df6dc74 694
AzureIoTClient 56:8704100b3b54 695 switch (op_type)
AzureIoTClient 56:8704100b3b54 696 {
AzureIoTClient 56:8704100b3b54 697 default:
AzureIoTClient 56:8704100b3b54 698 LogError("Unrecognized TWIN operation (%s)", ENUM_TO_STRING(TWIN_OPERATION_TYPE, op_type));
AzureIoTClient 56:8704100b3b54 699 result = NULL;
AzureIoTClient 56:8704100b3b54 700 break;
AzureIoTClient 56:8704100b3b54 701 case TWIN_OPERATION_TYPE_PATCH:
AzureIoTClient 56:8704100b3b54 702 result = TWIN_OPERATION_PATCH;
AzureIoTClient 56:8704100b3b54 703 break;
AzureIoTClient 56:8704100b3b54 704 case TWIN_OPERATION_TYPE_GET:
AzureIoTClient 56:8704100b3b54 705 result = TWIN_OPERATION_GET;
AzureIoTClient 56:8704100b3b54 706 break;
AzureIoTClient 56:8704100b3b54 707 case TWIN_OPERATION_TYPE_PUT:
AzureIoTClient 56:8704100b3b54 708 result = TWIN_OPERATION_PUT;
AzureIoTClient 56:8704100b3b54 709 break;
AzureIoTClient 56:8704100b3b54 710 case TWIN_OPERATION_TYPE_DELETE:
AzureIoTClient 56:8704100b3b54 711 result = TWIN_OPERATION_DELETE;
AzureIoTClient 56:8704100b3b54 712 break;
AzureIoTClient 56:8704100b3b54 713 }
AzureIoTClient 39:e98d5df6dc74 714
AzureIoTClient 56:8704100b3b54 715 return result;
AzureIoTClient 39:e98d5df6dc74 716 }
AzureIoTClient 39:e98d5df6dc74 717
AzureIoTClient 39:e98d5df6dc74 718 static MESSAGE_HANDLE create_amqp_message_for_twin_operation(TWIN_OPERATION_TYPE op_type, char* correlation_id, CONSTBUFFER_HANDLE data)
AzureIoTClient 39:e98d5df6dc74 719 {
AzureIoTClient 56:8704100b3b54 720 MESSAGE_HANDLE result;
AzureIoTClient 56:8704100b3b54 721 const char* twin_op_name;
AzureIoTClient 39:e98d5df6dc74 722
AzureIoTClient 56:8704100b3b54 723 if ((twin_op_name = get_twin_operation_name(op_type))== NULL)
AzureIoTClient 56:8704100b3b54 724 {
AzureIoTClient 56:8704100b3b54 725 result = NULL;
AzureIoTClient 56:8704100b3b54 726 }
AzureIoTClient 56:8704100b3b54 727 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_063: [An `amqp_message` (MESSAGE_HANDLE) shall be created using message_create()]
AzureIoTClient 56:8704100b3b54 728 else if ((result = message_create()) == NULL)
AzureIoTClient 56:8704100b3b54 729 {
AzureIoTClient 56:8704100b3b54 730 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_064: [If message_create() fails, message_create_for_twin_operation shall fail and return NULL]
AzureIoTClient 56:8704100b3b54 731 LogError("Failed creating AMQP message (%s)", twin_op_name);
AzureIoTClient 56:8704100b3b54 732 }
AzureIoTClient 56:8704100b3b54 733 else
AzureIoTClient 56:8704100b3b54 734 {
AzureIoTClient 56:8704100b3b54 735 AMQP_VALUE msg_annotations_map;
AzureIoTClient 39:e98d5df6dc74 736
AzureIoTClient 56:8704100b3b54 737 if ((msg_annotations_map = amqpvalue_create_map()) == NULL)
AzureIoTClient 56:8704100b3b54 738 {
AzureIoTClient 56:8704100b3b54 739 LogError("Failed creating map for message annotations");
AzureIoTClient 56:8704100b3b54 740 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_072: [If any errors occur, message_create_for_twin_operation shall release all memory it has allocated]
AzureIoTClient 56:8704100b3b54 741 message_destroy(result);
AzureIoTClient 56:8704100b3b54 742 result = NULL;
AzureIoTClient 56:8704100b3b54 743 }
AzureIoTClient 56:8704100b3b54 744 else
AzureIoTClient 56:8704100b3b54 745 {
AzureIoTClient 56:8704100b3b54 746 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_065: [`operation=<op_type>` (GET/PATCH/PUT/DELETE) must be added to the `amqp_message` annotations]
AzureIoTClient 56:8704100b3b54 747 if (add_map_item(msg_annotations_map, TWIN_MESSAGE_PROPERTY_OPERATION, twin_op_name) != RESULT_OK)
AzureIoTClient 56:8704100b3b54 748 {
AzureIoTClient 56:8704100b3b54 749 LogError("Failed adding operation to AMQP message annotations (%s)", twin_op_name);
AzureIoTClient 56:8704100b3b54 750 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_072: [If any errors occur, message_create_for_twin_operation shall release all memory it has allocated]
AzureIoTClient 56:8704100b3b54 751 message_destroy(result);
AzureIoTClient 56:8704100b3b54 752 result = NULL;
AzureIoTClient 56:8704100b3b54 753 }
AzureIoTClient 56:8704100b3b54 754 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_066: [If `op_type` is PATCH, `resource=/properties/reported` must be added to the `amqp_message` annotations]
AzureIoTClient 56:8704100b3b54 755 else if ((op_type == TWIN_OPERATION_TYPE_PATCH) &&
AzureIoTClient 56:8704100b3b54 756 add_map_item(msg_annotations_map, TWIN_MESSAGE_PROPERTY_RESOURCE, TWIN_RESOURCE_REPORTED) != RESULT_OK)
AzureIoTClient 56:8704100b3b54 757 {
AzureIoTClient 56:8704100b3b54 758 LogError("Failed adding resource to AMQP message annotations (%s)", twin_op_name);
AzureIoTClient 56:8704100b3b54 759 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_072: [If any errors occur, message_create_for_twin_operation shall release all memory it has allocated]
AzureIoTClient 56:8704100b3b54 760 message_destroy(result);
AzureIoTClient 56:8704100b3b54 761 result = NULL;
AzureIoTClient 56:8704100b3b54 762 }
AzureIoTClient 56:8704100b3b54 763 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_067: [If `op_type` is PUT or DELETE, `resource=/notifications/twin/properties/desired` must be added to the `amqp_message` annotations]
AzureIoTClient 56:8704100b3b54 764 else if ((op_type == TWIN_OPERATION_TYPE_PUT || op_type == TWIN_OPERATION_TYPE_DELETE) &&
AzureIoTClient 56:8704100b3b54 765 add_map_item(msg_annotations_map, TWIN_MESSAGE_PROPERTY_RESOURCE, TWIN_RESOURCE_DESIRED) != RESULT_OK)
AzureIoTClient 56:8704100b3b54 766 {
AzureIoTClient 56:8704100b3b54 767 LogError("Failed adding resource to AMQP message annotations (%s)", twin_op_name);
AzureIoTClient 56:8704100b3b54 768 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_072: [If any errors occur, message_create_for_twin_operation shall release all memory it has allocated]
AzureIoTClient 56:8704100b3b54 769 message_destroy(result);
AzureIoTClient 56:8704100b3b54 770 result = NULL;
AzureIoTClient 56:8704100b3b54 771 }
AzureIoTClient 56:8704100b3b54 772 else if (add_amqp_message_annotation(result, msg_annotations_map) != RESULT_OK)
AzureIoTClient 56:8704100b3b54 773 {
AzureIoTClient 56:8704100b3b54 774 LogError("Failed adding annotations to AMQP message (%s)", twin_op_name);
AzureIoTClient 56:8704100b3b54 775 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_072: [If any errors occur, message_create_for_twin_operation shall release all memory it has allocated]
AzureIoTClient 56:8704100b3b54 776 message_destroy(result);
AzureIoTClient 56:8704100b3b54 777 result = NULL;
AzureIoTClient 56:8704100b3b54 778 }
AzureIoTClient 56:8704100b3b54 779 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_068: [The `correlation-id` property of `amqp_message` shall be set with an UUID string]
AzureIoTClient 56:8704100b3b54 780 else if (set_message_correlation_id(result, correlation_id) != RESULT_OK)
AzureIoTClient 56:8704100b3b54 781 {
AzureIoTClient 56:8704100b3b54 782 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_069: [If setting `correlation-id` fails, message_create_for_twin_operation shall fail and return NULL]
AzureIoTClient 56:8704100b3b54 783 LogError("Failed AMQP message correlation-id (%s)", twin_op_name);
AzureIoTClient 56:8704100b3b54 784 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_072: [If any errors occur, message_create_for_twin_operation shall release all memory it has allocated]
AzureIoTClient 56:8704100b3b54 785 message_destroy(result);
AzureIoTClient 56:8704100b3b54 786 result = NULL;
AzureIoTClient 56:8704100b3b54 787 }
AzureIoTClient 56:8704100b3b54 788 else
AzureIoTClient 56:8704100b3b54 789 {
AzureIoTClient 56:8704100b3b54 790 BINARY_DATA binary_data;
AzureIoTClient 39:e98d5df6dc74 791
AzureIoTClient 56:8704100b3b54 792 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_070: [If `data` is not NULL, it shall be added to `amqp_message` using message_add_body_amqp_data()]
AzureIoTClient 56:8704100b3b54 793 if (data != NULL)
AzureIoTClient 56:8704100b3b54 794 {
AzureIoTClient 56:8704100b3b54 795 const CONSTBUFFER* data_buffer;
AzureIoTClient 56:8704100b3b54 796 data_buffer = CONSTBUFFER_GetContent(data);
AzureIoTClient 56:8704100b3b54 797 binary_data.bytes = data_buffer->buffer;
AzureIoTClient 56:8704100b3b54 798 binary_data.length = data_buffer->size;
AzureIoTClient 56:8704100b3b54 799 }
AzureIoTClient 56:8704100b3b54 800 else
AzureIoTClient 56:8704100b3b54 801 {
AzureIoTClient 56:8704100b3b54 802 binary_data.bytes = EMPTY_TWIN_BODY_DATA;
AzureIoTClient 56:8704100b3b54 803 binary_data.length = EMPTY_TWIN_BODY_SIZE;
AzureIoTClient 56:8704100b3b54 804 }
AzureIoTClient 39:e98d5df6dc74 805
AzureIoTClient 56:8704100b3b54 806 if (message_add_body_amqp_data(result, binary_data) != 0)
AzureIoTClient 56:8704100b3b54 807 {
AzureIoTClient 56:8704100b3b54 808 LogError("Failed adding twin patch data to AMQP message body");
AzureIoTClient 56:8704100b3b54 809 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_072: [If any errors occur, message_create_for_twin_operation shall release all memory it has allocated]
AzureIoTClient 56:8704100b3b54 810 message_destroy(result);
AzureIoTClient 56:8704100b3b54 811 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_071: [If message_add_body_amqp_data() fails, message_create_for_twin_operation shall fail and return NULL]
AzureIoTClient 56:8704100b3b54 812 result = NULL;
AzureIoTClient 56:8704100b3b54 813 }
AzureIoTClient 56:8704100b3b54 814 }
AzureIoTClient 39:e98d5df6dc74 815
AzureIoTClient 56:8704100b3b54 816 amqpvalue_destroy(msg_annotations_map);
AzureIoTClient 56:8704100b3b54 817 }
AzureIoTClient 56:8704100b3b54 818 }
AzureIoTClient 39:e98d5df6dc74 819
AzureIoTClient 56:8704100b3b54 820 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_073: [If no errors occur, message_create_for_twin_operation shall return `amqp_message`]
AzureIoTClient 56:8704100b3b54 821 return result;
AzureIoTClient 39:e98d5df6dc74 822 }
AzureIoTClient 39:e98d5df6dc74 823
AzureIoTClient 39:e98d5df6dc74 824 static TWIN_REPORT_STATE_RESULT get_twin_messenger_result_from(AMQP_MESSENGER_SEND_RESULT amqp_send_result)
AzureIoTClient 39:e98d5df6dc74 825 {
AzureIoTClient 56:8704100b3b54 826 TWIN_REPORT_STATE_RESULT result;
AzureIoTClient 39:e98d5df6dc74 827
AzureIoTClient 56:8704100b3b54 828 switch (amqp_send_result)
AzureIoTClient 56:8704100b3b54 829 {
AzureIoTClient 56:8704100b3b54 830 case AMQP_MESSENGER_SEND_RESULT_SUCCESS:
AzureIoTClient 56:8704100b3b54 831 result = TWIN_REPORT_STATE_RESULT_SUCCESS;
AzureIoTClient 56:8704100b3b54 832 break;
AzureIoTClient 56:8704100b3b54 833 case AMQP_MESSENGER_SEND_RESULT_CANCELLED:
AzureIoTClient 56:8704100b3b54 834 result = TWIN_REPORT_STATE_RESULT_CANCELLED;
AzureIoTClient 56:8704100b3b54 835 break;
AzureIoTClient 56:8704100b3b54 836 case AMQP_MESSENGER_SEND_RESULT_ERROR:
AzureIoTClient 56:8704100b3b54 837 result = TWIN_REPORT_STATE_RESULT_ERROR;
AzureIoTClient 56:8704100b3b54 838 break;
AzureIoTClient 56:8704100b3b54 839 default:
AzureIoTClient 56:8704100b3b54 840 LogError("Unrecognized enum value %s", ENUM_TO_STRING(AMQP_MESSENGER_SEND_RESULT, amqp_send_result));
AzureIoTClient 56:8704100b3b54 841 result = TWIN_REPORT_STATE_RESULT_ERROR;
AzureIoTClient 56:8704100b3b54 842 break;
AzureIoTClient 56:8704100b3b54 843 };
AzureIoTClient 39:e98d5df6dc74 844
AzureIoTClient 56:8704100b3b54 845 return result;
AzureIoTClient 39:e98d5df6dc74 846 }
AzureIoTClient 39:e98d5df6dc74 847
AzureIoTClient 39:e98d5df6dc74 848 static TWIN_REPORT_STATE_REASON get_twin_messenger_reason_from(AMQP_MESSENGER_REASON amqp_reason)
AzureIoTClient 39:e98d5df6dc74 849 {
AzureIoTClient 56:8704100b3b54 850 TWIN_REPORT_STATE_REASON result;
AzureIoTClient 39:e98d5df6dc74 851
AzureIoTClient 56:8704100b3b54 852 switch (amqp_reason)
AzureIoTClient 56:8704100b3b54 853 {
AzureIoTClient 56:8704100b3b54 854 case AMQP_MESSENGER_REASON_NONE:
AzureIoTClient 56:8704100b3b54 855 result = TWIN_REPORT_STATE_REASON_NONE;
AzureIoTClient 56:8704100b3b54 856 break;
AzureIoTClient 56:8704100b3b54 857 case AMQP_MESSENGER_REASON_FAIL_SENDING:
AzureIoTClient 56:8704100b3b54 858 result = TWIN_REPORT_STATE_REASON_FAIL_SENDING;
AzureIoTClient 56:8704100b3b54 859 break;
AzureIoTClient 56:8704100b3b54 860 case AMQP_MESSENGER_REASON_TIMEOUT:
AzureIoTClient 56:8704100b3b54 861 result = TWIN_REPORT_STATE_REASON_TIMEOUT;
AzureIoTClient 56:8704100b3b54 862 break;
AzureIoTClient 56:8704100b3b54 863 case AMQP_MESSENGER_REASON_MESSENGER_DESTROYED:
AzureIoTClient 56:8704100b3b54 864 result = TWIN_REPORT_STATE_REASON_MESSENGER_DESTROYED;
AzureIoTClient 56:8704100b3b54 865 break;
AzureIoTClient 56:8704100b3b54 866 case AMQP_MESSENGER_REASON_CANNOT_PARSE:
AzureIoTClient 56:8704100b3b54 867 result = TWIN_REPORT_STATE_REASON_NONE;
AzureIoTClient 56:8704100b3b54 868 break;
AzureIoTClient 56:8704100b3b54 869 default:
AzureIoTClient 56:8704100b3b54 870 LogError("Unrecognized enum value %s (%d)", ENUM_TO_STRING(AMQP_MESSENGER_REASON, amqp_reason), amqp_reason);
AzureIoTClient 56:8704100b3b54 871 result = TWIN_REPORT_STATE_REASON_NONE;
AzureIoTClient 56:8704100b3b54 872 break;
AzureIoTClient 56:8704100b3b54 873 };
AzureIoTClient 39:e98d5df6dc74 874
AzureIoTClient 56:8704100b3b54 875 return result;
AzureIoTClient 39:e98d5df6dc74 876 }
AzureIoTClient 39:e98d5df6dc74 877
AzureIoTClient 39:e98d5df6dc74 878 static void on_amqp_send_complete_callback(AMQP_MESSENGER_SEND_RESULT result, AMQP_MESSENGER_REASON reason, void* context)
AzureIoTClient 39:e98d5df6dc74 879 {
AzureIoTClient 56:8704100b3b54 880 // Applicable to TWIN requests for reported state PATCH, GET, PUT, DELETE.
AzureIoTClient 39:e98d5df6dc74 881
AzureIoTClient 56:8704100b3b54 882 if (context == NULL)
AzureIoTClient 56:8704100b3b54 883 {
AzureIoTClient 56:8704100b3b54 884 LogError("Invalid argument (context is NULL)");
AzureIoTClient 56:8704100b3b54 885 }
AzureIoTClient 56:8704100b3b54 886 else
AzureIoTClient 56:8704100b3b54 887 {
AzureIoTClient 56:8704100b3b54 888 TWIN_OPERATION_CONTEXT* twin_op_ctx = (TWIN_OPERATION_CONTEXT*)context;
AzureIoTClient 39:e98d5df6dc74 889
AzureIoTClient 56:8704100b3b54 890 if (result != AMQP_MESSENGER_SEND_RESULT_SUCCESS)
AzureIoTClient 56:8704100b3b54 891 {
AzureIoTClient 56:8704100b3b54 892 if (twin_op_ctx->type == TWIN_OPERATION_TYPE_PATCH)
AzureIoTClient 56:8704100b3b54 893 {
AzureIoTClient 56:8704100b3b54 894 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_095: [If operation is a reported state PATCH, if a failure occurs `on_report_state_complete_callback` shall be invoked with TWIN_REPORT_STATE_RESULT_ERROR, status code from the AMQP response and the saved context]
AzureIoTClient 56:8704100b3b54 895 if (twin_op_ctx->on_report_state_complete_callback != NULL)
AzureIoTClient 56:8704100b3b54 896 {
AzureIoTClient 56:8704100b3b54 897 TWIN_REPORT_STATE_RESULT callback_result;
AzureIoTClient 56:8704100b3b54 898 TWIN_REPORT_STATE_REASON callback_reason;
AzureIoTClient 39:e98d5df6dc74 899
AzureIoTClient 56:8704100b3b54 900 callback_result = get_twin_messenger_result_from(result);
AzureIoTClient 56:8704100b3b54 901 callback_reason = get_twin_messenger_reason_from(reason);
AzureIoTClient 39:e98d5df6dc74 902
AzureIoTClient 56:8704100b3b54 903 twin_op_ctx->on_report_state_complete_callback(callback_result, callback_reason, 0, (void*)twin_op_ctx->on_report_state_complete_context);
AzureIoTClient 56:8704100b3b54 904 }
AzureIoTClient 56:8704100b3b54 905 }
AzureIoTClient 56:8704100b3b54 906 else if (reason != AMQP_MESSENGER_REASON_MESSENGER_DESTROYED)
AzureIoTClient 56:8704100b3b54 907 {
AzureIoTClient 56:8704100b3b54 908 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_096: [If operation is a GET/PUT/DELETE, if a failure occurs the TWIN messenger shall attempt to subscribe/unsubscribe again]
AzureIoTClient 56:8704100b3b54 909 LogError("Failed sending TWIN operation request (%s, %s, %s, %s, %s)",
AzureIoTClient 56:8704100b3b54 910 twin_op_ctx->msgr->device_id,
AzureIoTClient 56:8704100b3b54 911 ENUM_TO_STRING(TWIN_OPERATION_TYPE, twin_op_ctx->type),
AzureIoTClient 56:8704100b3b54 912 twin_op_ctx->correlation_id,
AzureIoTClient 56:8704100b3b54 913 ENUM_TO_STRING(AMQP_MESSENGER_SEND_RESULT, result), ENUM_TO_STRING(AMQP_MESSENGER_REASON, reason));
AzureIoTClient 39:e98d5df6dc74 914
AzureIoTClient 56:8704100b3b54 915 if (twin_op_ctx->type == TWIN_OPERATION_TYPE_GET &&
AzureIoTClient 56:8704100b3b54 916 twin_op_ctx->msgr->subscription_state == TWIN_SUBSCRIPTION_STATE_GETTING_COMPLETE_PROPERTIES)
AzureIoTClient 56:8704100b3b54 917 {
AzureIoTClient 56:8704100b3b54 918 twin_op_ctx->msgr->subscription_state = TWIN_SUBSCRIPTION_STATE_GET_COMPLETE_PROPERTIES;
AzureIoTClient 56:8704100b3b54 919 twin_op_ctx->msgr->subscription_error_count++;
AzureIoTClient 56:8704100b3b54 920 }
AzureIoTClient 56:8704100b3b54 921 else if (twin_op_ctx->type == TWIN_OPERATION_TYPE_PUT &&
AzureIoTClient 56:8704100b3b54 922 twin_op_ctx->msgr->subscription_state == TWIN_SUBSCRIPTION_STATE_GETTING_COMPLETE_PROPERTIES)
AzureIoTClient 56:8704100b3b54 923 {
AzureIoTClient 56:8704100b3b54 924 twin_op_ctx->msgr->subscription_state = TWIN_SUBSCRIPTION_STATE_GET_COMPLETE_PROPERTIES;
AzureIoTClient 56:8704100b3b54 925 twin_op_ctx->msgr->subscription_error_count++;
AzureIoTClient 56:8704100b3b54 926 }
AzureIoTClient 56:8704100b3b54 927 }
AzureIoTClient 39:e98d5df6dc74 928
AzureIoTClient 56:8704100b3b54 929 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_097: [If a failure occurred, the current operation shall be removed from `twin_msgr->operations`]
AzureIoTClient 56:8704100b3b54 930 if (remove_twin_operation_context_from_queue(twin_op_ctx) != RESULT_OK)
AzureIoTClient 56:8704100b3b54 931 {
AzureIoTClient 56:8704100b3b54 932 update_state(twin_op_ctx->msgr, TWIN_MESSENGER_STATE_ERROR);
AzureIoTClient 56:8704100b3b54 933 }
AzureIoTClient 56:8704100b3b54 934 else
AzureIoTClient 56:8704100b3b54 935 {
AzureIoTClient 56:8704100b3b54 936 destroy_twin_operation_context(twin_op_ctx);
AzureIoTClient 56:8704100b3b54 937 }
AzureIoTClient 56:8704100b3b54 938 }
AzureIoTClient 56:8704100b3b54 939 }
AzureIoTClient 39:e98d5df6dc74 940 }
AzureIoTClient 39:e98d5df6dc74 941
AzureIoTClient 39:e98d5df6dc74 942 static int send_twin_operation_request(TWIN_MESSENGER_INSTANCE* twin_msgr, TWIN_OPERATION_CONTEXT* op_ctx, CONSTBUFFER_HANDLE data)
AzureIoTClient 39:e98d5df6dc74 943 {
AzureIoTClient 56:8704100b3b54 944 int result;
AzureIoTClient 56:8704100b3b54 945 MESSAGE_HANDLE amqp_message;
AzureIoTClient 39:e98d5df6dc74 946
AzureIoTClient 56:8704100b3b54 947 if ((amqp_message = create_amqp_message_for_twin_operation(op_ctx->type, op_ctx->correlation_id, data)) == NULL)
AzureIoTClient 56:8704100b3b54 948 {
AzureIoTClient 56:8704100b3b54 949 LogError("Failed creating request message (%s, %s, %s)", twin_msgr->device_id, ENUM_TO_STRING(TWIN_OPERATION_TYPE, op_ctx->type), op_ctx->correlation_id);
AzureIoTClient 56:8704100b3b54 950 result = __FAILURE__;
AzureIoTClient 56:8704100b3b54 951 }
AzureIoTClient 56:8704100b3b54 952 else
AzureIoTClient 56:8704100b3b54 953 {
AzureIoTClient 56:8704100b3b54 954 if ((op_ctx->time_sent = get_time(NULL)) == INDEFINITE_TIME)
AzureIoTClient 56:8704100b3b54 955 {
AzureIoTClient 56:8704100b3b54 956 LogError("Failed setting TWIN operation sent time (%s, %s, %s)", twin_msgr->device_id, ENUM_TO_STRING(TWIN_OPERATION_TYPE, op_ctx->type), op_ctx->correlation_id);
AzureIoTClient 56:8704100b3b54 957 result = __FAILURE__;
AzureIoTClient 56:8704100b3b54 958 }
AzureIoTClient 56:8704100b3b54 959 else if (amqp_messenger_send_async(twin_msgr->amqp_msgr, amqp_message, on_amqp_send_complete_callback, (void*)op_ctx) != 0)
AzureIoTClient 56:8704100b3b54 960 {
AzureIoTClient 56:8704100b3b54 961 LogError("Failed sending request message for (%s, %s, %s)", twin_msgr->device_id, ENUM_TO_STRING(TWIN_OPERATION_TYPE, op_ctx->type), op_ctx->correlation_id);
AzureIoTClient 56:8704100b3b54 962 result = __FAILURE__;
AzureIoTClient 56:8704100b3b54 963 }
AzureIoTClient 56:8704100b3b54 964 else
AzureIoTClient 56:8704100b3b54 965 {
AzureIoTClient 56:8704100b3b54 966 result = RESULT_OK;
AzureIoTClient 56:8704100b3b54 967 }
AzureIoTClient 39:e98d5df6dc74 968
AzureIoTClient 56:8704100b3b54 969 message_destroy(amqp_message);
AzureIoTClient 56:8704100b3b54 970 }
AzureIoTClient 39:e98d5df6dc74 971
AzureIoTClient 56:8704100b3b54 972 return result;
AzureIoTClient 39:e98d5df6dc74 973 }
AzureIoTClient 39:e98d5df6dc74 974
AzureIoTClient 39:e98d5df6dc74 975
AzureIoTClient 39:e98d5df6dc74 976 //---------- Internal Helpers----------//
AzureIoTClient 39:e98d5df6dc74 977
AzureIoTClient 39:e98d5df6dc74 978 static bool remove_expired_twin_patch_request(const void* item, const void* match_context, bool* continue_processing)
AzureIoTClient 39:e98d5df6dc74 979 {
AzureIoTClient 56:8704100b3b54 980 bool remove_item;
AzureIoTClient 39:e98d5df6dc74 981
AzureIoTClient 56:8704100b3b54 982 if (item == NULL || match_context == NULL || continue_processing == NULL)
AzureIoTClient 56:8704100b3b54 983 {
AzureIoTClient 56:8704100b3b54 984 LogError("Invalid argument (item=%p, match_context=%p, continue_processing=%p)", item, match_context, continue_processing);
AzureIoTClient 56:8704100b3b54 985 remove_item = false;
AzureIoTClient 56:8704100b3b54 986 }
AzureIoTClient 56:8704100b3b54 987 else
AzureIoTClient 56:8704100b3b54 988 {
AzureIoTClient 39:e98d5df6dc74 989
AzureIoTClient 56:8704100b3b54 990 time_t current_time = *(time_t*)match_context;
AzureIoTClient 56:8704100b3b54 991 TWIN_PATCH_OPERATION_CONTEXT* twin_patch_ctx = (TWIN_PATCH_OPERATION_CONTEXT*)item;
AzureIoTClient 39:e98d5df6dc74 992
AzureIoTClient 56:8704100b3b54 993 if (get_difftime(current_time, twin_patch_ctx->time_enqueued) >= DEFAULT_TWIN_OPERATION_TIMEOUT_SECS)
AzureIoTClient 56:8704100b3b54 994 {
AzureIoTClient 56:8704100b3b54 995 remove_item = true;
AzureIoTClient 56:8704100b3b54 996 *continue_processing = true;
AzureIoTClient 39:e98d5df6dc74 997
AzureIoTClient 56:8704100b3b54 998 if (twin_patch_ctx->on_report_state_complete_callback != NULL)
AzureIoTClient 56:8704100b3b54 999 {
AzureIoTClient 56:8704100b3b54 1000 twin_patch_ctx->on_report_state_complete_callback(TWIN_REPORT_STATE_RESULT_ERROR, TWIN_REPORT_STATE_REASON_TIMEOUT, 0, twin_patch_ctx->on_report_state_complete_context);
AzureIoTClient 56:8704100b3b54 1001 }
AzureIoTClient 39:e98d5df6dc74 1002
AzureIoTClient 56:8704100b3b54 1003 CONSTBUFFER_Destroy(twin_patch_ctx->data);
AzureIoTClient 56:8704100b3b54 1004 free(twin_patch_ctx);
AzureIoTClient 56:8704100b3b54 1005 }
AzureIoTClient 56:8704100b3b54 1006 else
AzureIoTClient 56:8704100b3b54 1007 {
AzureIoTClient 56:8704100b3b54 1008 remove_item = false;
AzureIoTClient 56:8704100b3b54 1009 *continue_processing = false;
AzureIoTClient 56:8704100b3b54 1010 }
AzureIoTClient 56:8704100b3b54 1011 }
AzureIoTClient 39:e98d5df6dc74 1012
AzureIoTClient 56:8704100b3b54 1013 return remove_item;
AzureIoTClient 39:e98d5df6dc74 1014 }
AzureIoTClient 39:e98d5df6dc74 1015
AzureIoTClient 39:e98d5df6dc74 1016 static bool remove_expired_twin_operation_request(const void* item, const void* match_context, bool* continue_processing)
AzureIoTClient 39:e98d5df6dc74 1017 {
AzureIoTClient 56:8704100b3b54 1018 bool result;
AzureIoTClient 39:e98d5df6dc74 1019
AzureIoTClient 56:8704100b3b54 1020 if (item == NULL || match_context == NULL || continue_processing == NULL)
AzureIoTClient 56:8704100b3b54 1021 {
AzureIoTClient 56:8704100b3b54 1022 LogError("Invalid argument (item=%p, match_context=%p, continue_processing=%p)", item, match_context, continue_processing);
AzureIoTClient 56:8704100b3b54 1023 result = false;
AzureIoTClient 56:8704100b3b54 1024 }
AzureIoTClient 56:8704100b3b54 1025 else
AzureIoTClient 56:8704100b3b54 1026 {
AzureIoTClient 56:8704100b3b54 1027 TWIN_OPERATION_CONTEXT* twin_op_ctx = (TWIN_OPERATION_CONTEXT*)item;
AzureIoTClient 56:8704100b3b54 1028 TWIN_MESSENGER_INSTANCE* twin_msgr = twin_op_ctx->msgr;
AzureIoTClient 56:8704100b3b54 1029 time_t current_time = *(time_t*)match_context;
AzureIoTClient 39:e98d5df6dc74 1030
AzureIoTClient 56:8704100b3b54 1031 if (get_difftime(current_time, twin_op_ctx->time_sent) < DEFAULT_TWIN_OPERATION_TIMEOUT_SECS)
AzureIoTClient 56:8704100b3b54 1032 {
AzureIoTClient 56:8704100b3b54 1033 result = false;
AzureIoTClient 56:8704100b3b54 1034 // All next elements in the list have a later time_sent, so they won't be expired, and don't need to be removed.
AzureIoTClient 56:8704100b3b54 1035 *continue_processing = false;
AzureIoTClient 56:8704100b3b54 1036 }
AzureIoTClient 56:8704100b3b54 1037 else
AzureIoTClient 56:8704100b3b54 1038 {
AzureIoTClient 56:8704100b3b54 1039 LogError("Twin operation timed out (%s, %s, %s)", twin_msgr->device_id, ENUM_TO_STRING(TWIN_OPERATION_TYPE, twin_op_ctx->type), twin_op_ctx->correlation_id);
AzureIoTClient 56:8704100b3b54 1040 result = true;
AzureIoTClient 56:8704100b3b54 1041 *continue_processing = true;
AzureIoTClient 39:e98d5df6dc74 1042
AzureIoTClient 56:8704100b3b54 1043 if (twin_op_ctx->type == TWIN_OPERATION_TYPE_PATCH)
AzureIoTClient 56:8704100b3b54 1044 {
AzureIoTClient 56:8704100b3b54 1045 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_081: [If a timed-out item is a reported property PATCH, `on_report_state_complete_callback` shall be invoked with RESULT_ERROR and REASON_TIMEOUT]
AzureIoTClient 56:8704100b3b54 1046 if (twin_op_ctx->on_report_state_complete_callback != NULL)
AzureIoTClient 56:8704100b3b54 1047 {
AzureIoTClient 56:8704100b3b54 1048 twin_op_ctx->on_report_state_complete_callback(TWIN_REPORT_STATE_RESULT_ERROR, TWIN_REPORT_STATE_REASON_TIMEOUT, 0, twin_op_ctx->on_report_state_complete_context);
AzureIoTClient 56:8704100b3b54 1049 }
AzureIoTClient 56:8704100b3b54 1050 }
AzureIoTClient 56:8704100b3b54 1051 else if (twin_op_ctx->type == TWIN_OPERATION_TYPE_GET)
AzureIoTClient 56:8704100b3b54 1052 {
AzureIoTClient 56:8704100b3b54 1053 if (twin_msgr->subscription_state == TWIN_SUBSCRIPTION_STATE_GETTING_COMPLETE_PROPERTIES)
AzureIoTClient 56:8704100b3b54 1054 {
AzureIoTClient 56:8704100b3b54 1055 twin_msgr->subscription_state = TWIN_SUBSCRIPTION_STATE_GET_COMPLETE_PROPERTIES;
AzureIoTClient 56:8704100b3b54 1056 twin_msgr->subscription_error_count++;
AzureIoTClient 56:8704100b3b54 1057 }
AzureIoTClient 56:8704100b3b54 1058 }
AzureIoTClient 56:8704100b3b54 1059 else if (twin_op_ctx->type == TWIN_OPERATION_TYPE_PUT)
AzureIoTClient 56:8704100b3b54 1060 {
AzureIoTClient 56:8704100b3b54 1061 if (twin_msgr->subscription_state == TWIN_SUBSCRIPTION_STATE_SUBSCRIBING)
AzureIoTClient 56:8704100b3b54 1062 {
AzureIoTClient 56:8704100b3b54 1063 twin_msgr->subscription_state = TWIN_SUBSCRIPTION_STATE_SUBSCRIBE_FOR_UPDATES;
AzureIoTClient 56:8704100b3b54 1064 twin_msgr->subscription_error_count++;
AzureIoTClient 56:8704100b3b54 1065 }
AzureIoTClient 56:8704100b3b54 1066 }
AzureIoTClient 56:8704100b3b54 1067 else if (twin_op_ctx->type == TWIN_OPERATION_TYPE_DELETE)
AzureIoTClient 56:8704100b3b54 1068 {
AzureIoTClient 56:8704100b3b54 1069 if (twin_msgr->subscription_state == TWIN_SUBSCRIPTION_STATE_UNSUBSCRIBING)
AzureIoTClient 56:8704100b3b54 1070 {
AzureIoTClient 56:8704100b3b54 1071 twin_msgr->subscription_state = TWIN_SUBSCRIPTION_STATE_UNSUBSCRIBE;
AzureIoTClient 56:8704100b3b54 1072 twin_msgr->subscription_error_count++;
AzureIoTClient 56:8704100b3b54 1073 }
AzureIoTClient 56:8704100b3b54 1074 }
AzureIoTClient 39:e98d5df6dc74 1075
AzureIoTClient 56:8704100b3b54 1076 destroy_twin_operation_context(twin_op_ctx);
AzureIoTClient 56:8704100b3b54 1077 }
AzureIoTClient 56:8704100b3b54 1078 }
AzureIoTClient 39:e98d5df6dc74 1079
AzureIoTClient 56:8704100b3b54 1080 return result;
AzureIoTClient 39:e98d5df6dc74 1081 }
AzureIoTClient 39:e98d5df6dc74 1082
AzureIoTClient 39:e98d5df6dc74 1083 static void process_timeouts(TWIN_MESSENGER_INSTANCE* twin_msgr)
AzureIoTClient 39:e98d5df6dc74 1084 {
AzureIoTClient 56:8704100b3b54 1085 time_t current_time;
AzureIoTClient 39:e98d5df6dc74 1086
AzureIoTClient 56:8704100b3b54 1087 if ((current_time = get_time(NULL)) == INDEFINITE_TIME)
AzureIoTClient 56:8704100b3b54 1088 {
AzureIoTClient 56:8704100b3b54 1089 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_082: [If any failure occurs while verifying/removing timed-out items `twin_msgr->state` shall be set to TWIN_MESSENGER_STATE_ERROR and user informed]
AzureIoTClient 56:8704100b3b54 1090 LogError("Failed obtaining current time (%s)", twin_msgr->device_id);
AzureIoTClient 56:8704100b3b54 1091 update_state(twin_msgr, TWIN_MESSENGER_STATE_ERROR);
AzureIoTClient 56:8704100b3b54 1092 }
AzureIoTClient 56:8704100b3b54 1093 else
AzureIoTClient 56:8704100b3b54 1094 {
AzureIoTClient 56:8704100b3b54 1095 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_080: [twin_messenger_do_work() shall remove and destroy any timed out items from `twin_msgr->pending_patches` and `twin_msgr->operations`]
AzureIoTClient 56:8704100b3b54 1096 (void)singlylinkedlist_remove_if(twin_msgr->pending_patches, remove_expired_twin_patch_request, (const void*)&current_time);
AzureIoTClient 56:8704100b3b54 1097 (void)singlylinkedlist_remove_if(twin_msgr->operations, remove_expired_twin_operation_request, (const void*)&current_time);
AzureIoTClient 56:8704100b3b54 1098 }
AzureIoTClient 39:e98d5df6dc74 1099 }
AzureIoTClient 39:e98d5df6dc74 1100
AzureIoTClient 39:e98d5df6dc74 1101 static bool send_pending_twin_patch(const void* item, const void* match_context, bool* continue_processing)
AzureIoTClient 39:e98d5df6dc74 1102 {
AzureIoTClient 56:8704100b3b54 1103 bool result;
AzureIoTClient 39:e98d5df6dc74 1104
AzureIoTClient 56:8704100b3b54 1105 if (item == NULL || match_context == NULL || continue_processing == NULL)
AzureIoTClient 56:8704100b3b54 1106 {
AzureIoTClient 56:8704100b3b54 1107 LogError("Invalid argument (item=%p, match_context=%p, continue_processing=%p)", item, match_context, continue_processing);
AzureIoTClient 56:8704100b3b54 1108 result = false;
AzureIoTClient 56:8704100b3b54 1109 }
AzureIoTClient 56:8704100b3b54 1110 else
AzureIoTClient 56:8704100b3b54 1111 {
AzureIoTClient 56:8704100b3b54 1112 TWIN_MESSENGER_INSTANCE* twin_msgr = (TWIN_MESSENGER_INSTANCE*)match_context;
AzureIoTClient 56:8704100b3b54 1113 TWIN_PATCH_OPERATION_CONTEXT* twin_patch_ctx = (TWIN_PATCH_OPERATION_CONTEXT*)item;
AzureIoTClient 56:8704100b3b54 1114 TWIN_OPERATION_CONTEXT* twin_op_ctx;
AzureIoTClient 39:e98d5df6dc74 1115
AzureIoTClient 56:8704100b3b54 1116 if ((twin_op_ctx = create_twin_operation_context(twin_msgr, TWIN_OPERATION_TYPE_PATCH)) == NULL)
AzureIoTClient 56:8704100b3b54 1117 {
AzureIoTClient 56:8704100b3b54 1118 LogError("Failed creating context for sending reported state (%s)", twin_msgr->device_id);
AzureIoTClient 39:e98d5df6dc74 1119
AzureIoTClient 56:8704100b3b54 1120 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_061: [If any other failure occurs sending the PATCH request, `on_report_state_complete_callback` shall be invoked with RESULT_ERROR and REASON_INTERNAL_ERROR]
AzureIoTClient 56:8704100b3b54 1121 if (twin_patch_ctx->on_report_state_complete_callback != NULL)
AzureIoTClient 56:8704100b3b54 1122 {
AzureIoTClient 56:8704100b3b54 1123 twin_patch_ctx->on_report_state_complete_callback(TWIN_REPORT_STATE_RESULT_ERROR, TWIN_REPORT_STATE_REASON_INTERNAL_ERROR, 0, twin_patch_ctx->on_report_state_complete_context);
AzureIoTClient 56:8704100b3b54 1124 }
AzureIoTClient 56:8704100b3b54 1125 }
AzureIoTClient 56:8704100b3b54 1126 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_062: [If amqp_send_async() succeeds, the PATCH request shall be queued into `twin_msgr->operations`]
AzureIoTClient 56:8704100b3b54 1127 else if (add_twin_operation_context_to_queue(twin_op_ctx) != RESULT_OK)
AzureIoTClient 56:8704100b3b54 1128 {
AzureIoTClient 56:8704100b3b54 1129 LogError("Failed adding TWIN operation context to queue (%s)", twin_msgr->device_id);
AzureIoTClient 39:e98d5df6dc74 1130
AzureIoTClient 56:8704100b3b54 1131 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_061: [If any other failure occurs sending the PATCH request, `on_report_state_complete_callback` shall be invoked with RESULT_ERROR and REASON_INTERNAL_ERROR]
AzureIoTClient 56:8704100b3b54 1132 if (twin_patch_ctx->on_report_state_complete_callback != NULL)
AzureIoTClient 56:8704100b3b54 1133 {
AzureIoTClient 56:8704100b3b54 1134 twin_patch_ctx->on_report_state_complete_callback(TWIN_REPORT_STATE_RESULT_ERROR, TWIN_REPORT_STATE_REASON_INTERNAL_ERROR, 0, twin_patch_ctx->on_report_state_complete_context);
AzureIoTClient 56:8704100b3b54 1135 }
AzureIoTClient 39:e98d5df6dc74 1136
AzureIoTClient 56:8704100b3b54 1137 destroy_twin_operation_context(twin_op_ctx);
AzureIoTClient 56:8704100b3b54 1138 }
AzureIoTClient 56:8704100b3b54 1139 else
AzureIoTClient 56:8704100b3b54 1140 {
AzureIoTClient 56:8704100b3b54 1141 twin_op_ctx->on_report_state_complete_callback = twin_patch_ctx->on_report_state_complete_callback;
AzureIoTClient 56:8704100b3b54 1142 twin_op_ctx->on_report_state_complete_context = twin_patch_ctx->on_report_state_complete_context;
AzureIoTClient 39:e98d5df6dc74 1143
AzureIoTClient 56:8704100b3b54 1144 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_059: [If reported property PATCH shall be sent as an uAMQP MESSAGE_HANDLE instance using amqp_send_async() passing `on_amqp_send_complete_callback`]
AzureIoTClient 56:8704100b3b54 1145 if (send_twin_operation_request(twin_msgr, twin_op_ctx, twin_patch_ctx->data) != RESULT_OK)
AzureIoTClient 56:8704100b3b54 1146 {
AzureIoTClient 56:8704100b3b54 1147 LogError("Failed sending reported state (%s)", twin_msgr->device_id);
AzureIoTClient 39:e98d5df6dc74 1148
AzureIoTClient 56:8704100b3b54 1149 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_060: [If amqp_send_async() fails, `on_report_state_complete_callback` shall be invoked with RESULT_ERROR and REASON_FAIL_SENDING]
AzureIoTClient 56:8704100b3b54 1150 if (twin_patch_ctx->on_report_state_complete_callback != NULL)
AzureIoTClient 56:8704100b3b54 1151 {
AzureIoTClient 56:8704100b3b54 1152 twin_patch_ctx->on_report_state_complete_callback(TWIN_REPORT_STATE_RESULT_ERROR, TWIN_REPORT_STATE_REASON_FAIL_SENDING, 0, twin_patch_ctx->on_report_state_complete_context);
AzureIoTClient 56:8704100b3b54 1153 }
AzureIoTClient 39:e98d5df6dc74 1154
AzureIoTClient 56:8704100b3b54 1155 (void)remove_twin_operation_context_from_queue(twin_op_ctx);
AzureIoTClient 56:8704100b3b54 1156 destroy_twin_operation_context(twin_op_ctx);
AzureIoTClient 56:8704100b3b54 1157 }
AzureIoTClient 56:8704100b3b54 1158 }
AzureIoTClient 39:e98d5df6dc74 1159
AzureIoTClient 56:8704100b3b54 1160 CONSTBUFFER_Destroy(twin_patch_ctx->data);
AzureIoTClient 56:8704100b3b54 1161 free(twin_patch_ctx);
AzureIoTClient 39:e98d5df6dc74 1162
AzureIoTClient 56:8704100b3b54 1163 *continue_processing = true;
AzureIoTClient 56:8704100b3b54 1164 result = true;
AzureIoTClient 56:8704100b3b54 1165 }
AzureIoTClient 39:e98d5df6dc74 1166
AzureIoTClient 56:8704100b3b54 1167 return result;
AzureIoTClient 39:e98d5df6dc74 1168 }
AzureIoTClient 39:e98d5df6dc74 1169
AzureIoTClient 39:e98d5df6dc74 1170 static void process_twin_subscription(TWIN_MESSENGER_INSTANCE* twin_msgr)
AzureIoTClient 39:e98d5df6dc74 1171 {
AzureIoTClient 56:8704100b3b54 1172 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_078: [If failures occur sending subscription requests to the service for more than 3 times, TWIN messenger shall set its state to TWIN_MESSENGER_STATE_ERROR and inform the user]
AzureIoTClient 56:8704100b3b54 1173 if (twin_msgr->subscription_error_count >= DEFAULT_MAX_TWIN_SUBSCRIPTION_ERROR_COUNT)
AzureIoTClient 56:8704100b3b54 1174 {
AzureIoTClient 56:8704100b3b54 1175 LogError("Maximum number of TWIN subscription-related failures reached (%s, %d)", twin_msgr->device_id, twin_msgr->subscription_error_count);
AzureIoTClient 56:8704100b3b54 1176 update_state(twin_msgr, TWIN_MESSENGER_STATE_ERROR);
AzureIoTClient 56:8704100b3b54 1177 }
AzureIoTClient 56:8704100b3b54 1178 else
AzureIoTClient 56:8704100b3b54 1179 {
AzureIoTClient 56:8704100b3b54 1180 TWIN_OPERATION_TYPE op_type = TWIN_OPERATION_TYPE_PATCH;
AzureIoTClient 56:8704100b3b54 1181 TWIN_SUBSCRIPTION_STATE next_subscription_state = twin_msgr->subscription_state;
AzureIoTClient 39:e98d5df6dc74 1182
AzureIoTClient 56:8704100b3b54 1183 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_074: [If subscribing, twin_messenger_do_work() shall request a complete desired properties report]
AzureIoTClient 56:8704100b3b54 1184 if (twin_msgr->subscription_state == TWIN_SUBSCRIPTION_STATE_GET_COMPLETE_PROPERTIES)
AzureIoTClient 56:8704100b3b54 1185 {
AzureIoTClient 56:8704100b3b54 1186 op_type = TWIN_OPERATION_TYPE_GET;
AzureIoTClient 56:8704100b3b54 1187 next_subscription_state = TWIN_SUBSCRIPTION_STATE_GETTING_COMPLETE_PROPERTIES;
AzureIoTClient 56:8704100b3b54 1188 }
AzureIoTClient 56:8704100b3b54 1189 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_075: [If a complete desired report has been received, the TWIN messenger shall request partial updates to desired properties]
AzureIoTClient 56:8704100b3b54 1190 else if (twin_msgr->subscription_state == TWIN_SUBSCRIPTION_STATE_SUBSCRIBE_FOR_UPDATES)
AzureIoTClient 56:8704100b3b54 1191 {
AzureIoTClient 56:8704100b3b54 1192 op_type = TWIN_OPERATION_TYPE_PUT;
AzureIoTClient 56:8704100b3b54 1193 next_subscription_state = TWIN_SUBSCRIPTION_STATE_SUBSCRIBING;
AzureIoTClient 56:8704100b3b54 1194 }
AzureIoTClient 56:8704100b3b54 1195 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_076: [If unsubscribing, twin_messenger_do_work() shall send a DELETE request to the service]
AzureIoTClient 56:8704100b3b54 1196 else if (twin_msgr->subscription_state == TWIN_SUBSCRIPTION_STATE_UNSUBSCRIBE)
AzureIoTClient 56:8704100b3b54 1197 {
AzureIoTClient 56:8704100b3b54 1198 op_type = TWIN_OPERATION_TYPE_PUT;
AzureIoTClient 56:8704100b3b54 1199 next_subscription_state = TWIN_SUBSCRIPTION_STATE_UNSUBSCRIBING;
AzureIoTClient 56:8704100b3b54 1200 }
AzureIoTClient 39:e98d5df6dc74 1201
AzureIoTClient 56:8704100b3b54 1202 if (next_subscription_state != twin_msgr->subscription_state)
AzureIoTClient 56:8704100b3b54 1203 {
AzureIoTClient 56:8704100b3b54 1204 TWIN_OPERATION_CONTEXT* twin_op_ctx;
AzureIoTClient 39:e98d5df6dc74 1205
AzureIoTClient 56:8704100b3b54 1206 if ((twin_op_ctx = create_twin_operation_context(twin_msgr, op_type)) == NULL)
AzureIoTClient 56:8704100b3b54 1207 {
AzureIoTClient 56:8704100b3b54 1208 LogError("Failed creating a context for TWIN request (%s, %s)", twin_msgr->device_id, ENUM_TO_STRING(TWIN_OPERATION_TYPE, op_type));
AzureIoTClient 56:8704100b3b54 1209 update_state(twin_msgr, TWIN_MESSENGER_STATE_ERROR);
AzureIoTClient 56:8704100b3b54 1210 }
AzureIoTClient 56:8704100b3b54 1211 else
AzureIoTClient 56:8704100b3b54 1212 {
AzureIoTClient 56:8704100b3b54 1213 if (add_twin_operation_context_to_queue(twin_op_ctx) != RESULT_OK)
AzureIoTClient 56:8704100b3b54 1214 {
AzureIoTClient 56:8704100b3b54 1215 LogError("Failed queueing TWIN request context (%s, %s)", twin_msgr->device_id, ENUM_TO_STRING(TWIN_OPERATION_TYPE, op_type));
AzureIoTClient 56:8704100b3b54 1216 destroy_twin_operation_context(twin_op_ctx);
AzureIoTClient 56:8704100b3b54 1217 update_state(twin_msgr, TWIN_MESSENGER_STATE_ERROR);
AzureIoTClient 56:8704100b3b54 1218 }
AzureIoTClient 56:8704100b3b54 1219 else if (send_twin_operation_request(twin_msgr, twin_op_ctx, NULL) != RESULT_OK)
AzureIoTClient 56:8704100b3b54 1220 {
AzureIoTClient 56:8704100b3b54 1221 LogError("Failed sending TWIN request (%s, %s)", twin_msgr->device_id, ENUM_TO_STRING(TWIN_OPERATION_TYPE, op_type));
AzureIoTClient 39:e98d5df6dc74 1222
AzureIoTClient 56:8704100b3b54 1223 (void)remove_twin_operation_context_from_queue(twin_op_ctx);
AzureIoTClient 56:8704100b3b54 1224 destroy_twin_operation_context(twin_op_ctx);
AzureIoTClient 56:8704100b3b54 1225 update_state(twin_msgr, TWIN_MESSENGER_STATE_ERROR);
AzureIoTClient 56:8704100b3b54 1226 }
AzureIoTClient 56:8704100b3b54 1227 else
AzureIoTClient 56:8704100b3b54 1228 {
AzureIoTClient 56:8704100b3b54 1229 twin_msgr->subscription_state = next_subscription_state;
AzureIoTClient 56:8704100b3b54 1230 }
AzureIoTClient 56:8704100b3b54 1231 }
AzureIoTClient 56:8704100b3b54 1232 }
AzureIoTClient 56:8704100b3b54 1233 }
AzureIoTClient 39:e98d5df6dc74 1234 }
AzureIoTClient 39:e98d5df6dc74 1235
AzureIoTClient 39:e98d5df6dc74 1236 static bool cancel_all_pending_twin_operations(const void* item, const void* match_context, bool* continue_processing)
AzureIoTClient 39:e98d5df6dc74 1237 {
AzureIoTClient 56:8704100b3b54 1238 bool result;
AzureIoTClient 39:e98d5df6dc74 1239
AzureIoTClient 56:8704100b3b54 1240 if (item == NULL || continue_processing == NULL)
AzureIoTClient 56:8704100b3b54 1241 {
AzureIoTClient 56:8704100b3b54 1242 LogError("Invalid argument (item=%p, continue_processing=%p)", item, continue_processing);
AzureIoTClient 56:8704100b3b54 1243 result = false;
AzureIoTClient 56:8704100b3b54 1244 }
AzureIoTClient 56:8704100b3b54 1245 else
AzureIoTClient 56:8704100b3b54 1246 {
AzureIoTClient 56:8704100b3b54 1247 TWIN_OPERATION_CONTEXT* twin_op_ctx = (TWIN_OPERATION_CONTEXT*)item;
AzureIoTClient 56:8704100b3b54 1248 (void)match_context;
AzureIoTClient 39:e98d5df6dc74 1249
AzureIoTClient 56:8704100b3b54 1250 if (twin_op_ctx->type == TWIN_OPERATION_TYPE_PATCH)
AzureIoTClient 56:8704100b3b54 1251 {
AzureIoTClient 56:8704100b3b54 1252 if (twin_op_ctx->on_report_state_complete_callback != NULL)
AzureIoTClient 56:8704100b3b54 1253 {
AzureIoTClient 56:8704100b3b54 1254 twin_op_ctx->on_report_state_complete_callback(TWIN_REPORT_STATE_RESULT_CANCELLED, TWIN_REPORT_STATE_REASON_MESSENGER_DESTROYED, 0, twin_op_ctx->on_report_state_complete_context);
AzureIoTClient 56:8704100b3b54 1255 }
AzureIoTClient 56:8704100b3b54 1256 }
AzureIoTClient 39:e98d5df6dc74 1257
AzureIoTClient 56:8704100b3b54 1258 destroy_twin_operation_context(twin_op_ctx);
AzureIoTClient 39:e98d5df6dc74 1259
AzureIoTClient 56:8704100b3b54 1260 *continue_processing = true;
AzureIoTClient 56:8704100b3b54 1261 result = true;
AzureIoTClient 56:8704100b3b54 1262 }
AzureIoTClient 39:e98d5df6dc74 1263
AzureIoTClient 56:8704100b3b54 1264 return result;
AzureIoTClient 39:e98d5df6dc74 1265 }
AzureIoTClient 39:e98d5df6dc74 1266
AzureIoTClient 39:e98d5df6dc74 1267 static bool cancel_pending_twin_patch_operation(const void* item, const void* match_context, bool* continue_processing)
AzureIoTClient 39:e98d5df6dc74 1268 {
AzureIoTClient 56:8704100b3b54 1269 bool result;
AzureIoTClient 39:e98d5df6dc74 1270
AzureIoTClient 56:8704100b3b54 1271 if (item == NULL)
AzureIoTClient 56:8704100b3b54 1272 {
AzureIoTClient 56:8704100b3b54 1273 LogError("Invalid argument (item is NULL)");
AzureIoTClient 56:8704100b3b54 1274 *continue_processing = false;
AzureIoTClient 56:8704100b3b54 1275 result = false;
AzureIoTClient 56:8704100b3b54 1276 }
AzureIoTClient 56:8704100b3b54 1277 else
AzureIoTClient 56:8704100b3b54 1278 {
AzureIoTClient 56:8704100b3b54 1279 TWIN_PATCH_OPERATION_CONTEXT* twin_patch_ctx = (TWIN_PATCH_OPERATION_CONTEXT*)item;
AzureIoTClient 56:8704100b3b54 1280 (void)match_context;
AzureIoTClient 39:e98d5df6dc74 1281
AzureIoTClient 56:8704100b3b54 1282 if (twin_patch_ctx->on_report_state_complete_callback != NULL)
AzureIoTClient 56:8704100b3b54 1283 {
AzureIoTClient 56:8704100b3b54 1284 twin_patch_ctx->on_report_state_complete_callback(TWIN_REPORT_STATE_RESULT_CANCELLED, TWIN_REPORT_STATE_REASON_MESSENGER_DESTROYED, 0, twin_patch_ctx->on_report_state_complete_context);
AzureIoTClient 56:8704100b3b54 1285 }
AzureIoTClient 39:e98d5df6dc74 1286
AzureIoTClient 56:8704100b3b54 1287 CONSTBUFFER_Destroy(twin_patch_ctx->data);
AzureIoTClient 56:8704100b3b54 1288 free(twin_patch_ctx);
AzureIoTClient 39:e98d5df6dc74 1289
AzureIoTClient 56:8704100b3b54 1290 *continue_processing = true;
AzureIoTClient 56:8704100b3b54 1291 result = true;
AzureIoTClient 56:8704100b3b54 1292 }
AzureIoTClient 39:e98d5df6dc74 1293
AzureIoTClient 56:8704100b3b54 1294 return result;
AzureIoTClient 39:e98d5df6dc74 1295 }
AzureIoTClient 39:e98d5df6dc74 1296
AzureIoTClient 39:e98d5df6dc74 1297 static void internal_twin_messenger_destroy(TWIN_MESSENGER_INSTANCE* twin_msgr)
AzureIoTClient 39:e98d5df6dc74 1298 {
AzureIoTClient 56:8704100b3b54 1299 if (twin_msgr->amqp_msgr != NULL)
AzureIoTClient 56:8704100b3b54 1300 {
AzureIoTClient 56:8704100b3b54 1301 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_099: [`twin_msgr->amqp_messenger` shall be destroyed using amqp_messenger_destroy()]
AzureIoTClient 56:8704100b3b54 1302 amqp_messenger_destroy(twin_msgr->amqp_msgr);
AzureIoTClient 56:8704100b3b54 1303 }
AzureIoTClient 39:e98d5df6dc74 1304
AzureIoTClient 56:8704100b3b54 1305 if (twin_msgr->pending_patches != NULL)
AzureIoTClient 56:8704100b3b54 1306 {
AzureIoTClient 56:8704100b3b54 1307 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_100: [All elements of `twin_msgr->pending_patches` shall be removed, invoking `on_report_state_complete_callback` for each with TWIN_REPORT_STATE_REASON_MESSENGER_DESTROYED]
AzureIoTClient 56:8704100b3b54 1308 if (singlylinkedlist_remove_if(twin_msgr->pending_patches, cancel_pending_twin_patch_operation, twin_msgr) != 0)
AzureIoTClient 56:8704100b3b54 1309 {
AzureIoTClient 56:8704100b3b54 1310 LogError("Failed removing pending desired properties PATCH operation (%s)", twin_msgr->device_id);
AzureIoTClient 56:8704100b3b54 1311 }
AzureIoTClient 39:e98d5df6dc74 1312
AzureIoTClient 56:8704100b3b54 1313 singlylinkedlist_destroy(twin_msgr->pending_patches);
AzureIoTClient 56:8704100b3b54 1314 }
AzureIoTClient 39:e98d5df6dc74 1315
AzureIoTClient 56:8704100b3b54 1316 if (twin_msgr->operations != NULL)
AzureIoTClient 56:8704100b3b54 1317 {
AzureIoTClient 56:8704100b3b54 1318 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_101: [All elements of `twin_msgr->operations` shall be removed, invoking `on_report_state_complete_callback` for each PATCH with TWIN_REPORT_STATE_REASON_MESSENGER_DESTROYED]
AzureIoTClient 56:8704100b3b54 1319 singlylinkedlist_remove_if(twin_msgr->operations, cancel_all_pending_twin_operations, (const void*)twin_msgr);
AzureIoTClient 56:8704100b3b54 1320 singlylinkedlist_destroy(twin_msgr->operations);
AzureIoTClient 56:8704100b3b54 1321 }
AzureIoTClient 39:e98d5df6dc74 1322
AzureIoTClient 56:8704100b3b54 1323 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_102: [twin_messenger_destroy() shall release all memory allocated for and within `twin_msgr`]
AzureIoTClient 56:8704100b3b54 1324 if (twin_msgr->client_version != NULL)
AzureIoTClient 56:8704100b3b54 1325 {
AzureIoTClient 56:8704100b3b54 1326 free(twin_msgr->client_version);
AzureIoTClient 56:8704100b3b54 1327 }
AzureIoTClient 39:e98d5df6dc74 1328
AzureIoTClient 56:8704100b3b54 1329 if (twin_msgr->device_id != NULL)
AzureIoTClient 56:8704100b3b54 1330 {
AzureIoTClient 56:8704100b3b54 1331 free(twin_msgr->device_id);
AzureIoTClient 56:8704100b3b54 1332 }
AzureIoTClient 39:e98d5df6dc74 1333
AzureIoTClient 56:8704100b3b54 1334 if (twin_msgr->module_id != NULL)
AzureIoTClient 56:8704100b3b54 1335 {
AzureIoTClient 56:8704100b3b54 1336 free(twin_msgr->module_id);
AzureIoTClient 56:8704100b3b54 1337 }
AzureIoTClient 39:e98d5df6dc74 1338
AzureIoTClient 56:8704100b3b54 1339 if (twin_msgr->iothub_host_fqdn != NULL)
AzureIoTClient 56:8704100b3b54 1340 {
AzureIoTClient 56:8704100b3b54 1341 free(twin_msgr->iothub_host_fqdn);
AzureIoTClient 56:8704100b3b54 1342 }
AzureIoTClient 56:8704100b3b54 1343
AzureIoTClient 56:8704100b3b54 1344 free(twin_msgr);
AzureIoTClient 39:e98d5df6dc74 1345 }
AzureIoTClient 39:e98d5df6dc74 1346
AzureIoTClient 39:e98d5df6dc74 1347
AzureIoTClient 39:e98d5df6dc74 1348 //---------- Internal Callbacks ----------//
AzureIoTClient 39:e98d5df6dc74 1349
AzureIoTClient 39:e98d5df6dc74 1350 static AMQP_MESSENGER_DISPOSITION_RESULT on_amqp_message_received_callback(MESSAGE_HANDLE message, AMQP_MESSENGER_MESSAGE_DISPOSITION_INFO* disposition_info, void* context)
AzureIoTClient 39:e98d5df6dc74 1351 {
AzureIoTClient 39:e98d5df6dc74 1352
AzureIoTClient 56:8704100b3b54 1353 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_084: [If `message` or `context` are NULL, on_amqp_message_received_callback shall return immediately]
AzureIoTClient 56:8704100b3b54 1354 AMQP_MESSENGER_DISPOSITION_RESULT disposition_result;
AzureIoTClient 39:e98d5df6dc74 1355
AzureIoTClient 56:8704100b3b54 1356 if (message == NULL || context == NULL)
AzureIoTClient 56:8704100b3b54 1357 {
AzureIoTClient 56:8704100b3b54 1358 LogError("Invalid argument (message=%p, context=%p)", message, context);
AzureIoTClient 56:8704100b3b54 1359 disposition_result = AMQP_MESSENGER_DISPOSITION_RESULT_REJECTED;
AzureIoTClient 56:8704100b3b54 1360 }
AzureIoTClient 56:8704100b3b54 1361 else
AzureIoTClient 56:8704100b3b54 1362 {
AzureIoTClient 56:8704100b3b54 1363 TWIN_MESSENGER_INSTANCE* twin_msgr = (TWIN_MESSENGER_INSTANCE*)context;
AzureIoTClient 39:e98d5df6dc74 1364
AzureIoTClient 56:8704100b3b54 1365 char* correlation_id;
AzureIoTClient 56:8704100b3b54 1366
AzureIoTClient 56:8704100b3b54 1367 bool has_status_code;
AzureIoTClient 56:8704100b3b54 1368 int status_code;
AzureIoTClient 56:8704100b3b54 1369
AzureIoTClient 56:8704100b3b54 1370 bool has_version;
AzureIoTClient 56:8704100b3b54 1371 int64_t version;
AzureIoTClient 39:e98d5df6dc74 1372
AzureIoTClient 56:8704100b3b54 1373 bool has_twin_report;
AzureIoTClient 56:8704100b3b54 1374 BINARY_DATA twin_report;
AzureIoTClient 39:e98d5df6dc74 1375
AzureIoTClient 56:8704100b3b54 1376 amqp_messenger_destroy_disposition_info(disposition_info);
AzureIoTClient 56:8704100b3b54 1377 disposition_result = AMQP_MESSENGER_DISPOSITION_RESULT_ACCEPTED;
AzureIoTClient 39:e98d5df6dc74 1378
AzureIoTClient 56:8704100b3b54 1379 if (parse_incoming_twin_message(message, &correlation_id, &has_version, &version, &has_status_code, &status_code, &has_twin_report, &twin_report) != 0)
AzureIoTClient 56:8704100b3b54 1380 {
AzureIoTClient 56:8704100b3b54 1381 LogError("Failed parsing incoming TWIN message (%s)", twin_msgr->device_id);
AzureIoTClient 56:8704100b3b54 1382 }
AzureIoTClient 56:8704100b3b54 1383 else
AzureIoTClient 56:8704100b3b54 1384 {
AzureIoTClient 56:8704100b3b54 1385 if (correlation_id != NULL)
AzureIoTClient 56:8704100b3b54 1386 {
AzureIoTClient 56:8704100b3b54 1387 // It is supposed to be a request sent previously (reported properties PATCH, GET, PUT or DELETE).
AzureIoTClient 39:e98d5df6dc74 1388
AzureIoTClient 56:8704100b3b54 1389 LIST_ITEM_HANDLE list_item;
AzureIoTClient 56:8704100b3b54 1390 if ((list_item = singlylinkedlist_find(twin_msgr->operations, find_twin_operation_by_correlation_id, (const void*)correlation_id)) == NULL)
AzureIoTClient 56:8704100b3b54 1391 {
AzureIoTClient 56:8704100b3b54 1392 LogError("Could not find context of TWIN incoming message (%s, %s)", twin_msgr->device_id, correlation_id);
AzureIoTClient 56:8704100b3b54 1393 }
AzureIoTClient 56:8704100b3b54 1394 else
AzureIoTClient 56:8704100b3b54 1395 {
AzureIoTClient 56:8704100b3b54 1396 TWIN_OPERATION_CONTEXT* twin_op_ctx;
AzureIoTClient 39:e98d5df6dc74 1397
AzureIoTClient 56:8704100b3b54 1398 if ((twin_op_ctx = (TWIN_OPERATION_CONTEXT*)singlylinkedlist_item_get_value(list_item)) == NULL)
AzureIoTClient 56:8704100b3b54 1399 {
AzureIoTClient 56:8704100b3b54 1400 LogError("Could not get context for incoming TWIN message (%s, %s)", twin_msgr->device_id, correlation_id);
AzureIoTClient 56:8704100b3b54 1401 }
AzureIoTClient 56:8704100b3b54 1402 else
AzureIoTClient 56:8704100b3b54 1403 {
AzureIoTClient 56:8704100b3b54 1404 if (twin_op_ctx->type == TWIN_OPERATION_TYPE_PATCH)
AzureIoTClient 56:8704100b3b54 1405 {
AzureIoTClient 56:8704100b3b54 1406 if (!has_status_code)
AzureIoTClient 56:8704100b3b54 1407 {
AzureIoTClient 56:8704100b3b54 1408 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_086: [If `message` is a failed response for a PATCH request, the `on_report_state_complete_callback` shall be invoked if provided passing RESULT_ERROR and the status_code zero]
AzureIoTClient 56:8704100b3b54 1409 LogError("Received an incoming TWIN message for a PATCH operation, but with no status code (%s, %s)", twin_msgr->device_id, correlation_id);
AzureIoTClient 56:8704100b3b54 1410
AzureIoTClient 56:8704100b3b54 1411 disposition_result = AMQP_MESSENGER_DISPOSITION_RESULT_REJECTED;
AzureIoTClient 39:e98d5df6dc74 1412
AzureIoTClient 56:8704100b3b54 1413 if (twin_op_ctx->on_report_state_complete_callback != NULL)
AzureIoTClient 56:8704100b3b54 1414 {
AzureIoTClient 56:8704100b3b54 1415 twin_op_ctx->on_report_state_complete_callback(TWIN_REPORT_STATE_RESULT_ERROR, TWIN_REPORT_STATE_REASON_INVALID_RESPONSE, 0, twin_op_ctx->on_report_state_complete_context);
AzureIoTClient 56:8704100b3b54 1416 }
AzureIoTClient 56:8704100b3b54 1417 }
AzureIoTClient 56:8704100b3b54 1418 else
AzureIoTClient 56:8704100b3b54 1419 {
AzureIoTClient 56:8704100b3b54 1420 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_085: [If `message` is a success response for a PATCH request, the `on_report_state_complete_callback` shall be invoked if provided passing RESULT_SUCCESS and the status_code received]
AzureIoTClient 56:8704100b3b54 1421 if (twin_op_ctx->on_report_state_complete_callback != NULL)
AzureIoTClient 56:8704100b3b54 1422 {
AzureIoTClient 56:8704100b3b54 1423 twin_op_ctx->on_report_state_complete_callback(TWIN_REPORT_STATE_RESULT_SUCCESS, TWIN_REPORT_STATE_REASON_NONE, status_code, twin_op_ctx->on_report_state_complete_context);
AzureIoTClient 56:8704100b3b54 1424 }
AzureIoTClient 56:8704100b3b54 1425 }
AzureIoTClient 56:8704100b3b54 1426 }
AzureIoTClient 56:8704100b3b54 1427 else if (twin_op_ctx->type == TWIN_OPERATION_TYPE_GET)
AzureIoTClient 56:8704100b3b54 1428 {
AzureIoTClient 56:8704100b3b54 1429 if (!has_twin_report)
AzureIoTClient 56:8704100b3b54 1430 {
AzureIoTClient 56:8704100b3b54 1431 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_089: [If `message` is a failed response for a GET request, the TWIN messenger shall attempt to send another GET request]
AzureIoTClient 56:8704100b3b54 1432 LogError("Received an incoming TWIN message for a GET operation, but with no report (%s, %s)", twin_msgr->device_id, correlation_id);
AzureIoTClient 39:e98d5df6dc74 1433
AzureIoTClient 56:8704100b3b54 1434 disposition_result = AMQP_MESSENGER_DISPOSITION_RESULT_REJECTED;
AzureIoTClient 39:e98d5df6dc74 1435
AzureIoTClient 56:8704100b3b54 1436 if (twin_op_ctx->msgr->on_message_received_callback != NULL)
AzureIoTClient 56:8704100b3b54 1437 {
AzureIoTClient 56:8704100b3b54 1438 twin_op_ctx->msgr->on_message_received_callback(TWIN_UPDATE_TYPE_COMPLETE, NULL, 0, twin_op_ctx->msgr->on_message_received_context);
AzureIoTClient 56:8704100b3b54 1439 }
AzureIoTClient 39:e98d5df6dc74 1440
AzureIoTClient 56:8704100b3b54 1441 if (twin_msgr->subscription_state == TWIN_SUBSCRIPTION_STATE_GETTING_COMPLETE_PROPERTIES)
AzureIoTClient 56:8704100b3b54 1442 {
AzureIoTClient 56:8704100b3b54 1443 twin_msgr->subscription_state = TWIN_SUBSCRIPTION_STATE_GET_COMPLETE_PROPERTIES;
AzureIoTClient 56:8704100b3b54 1444 twin_msgr->subscription_error_count++;
AzureIoTClient 56:8704100b3b54 1445 }
AzureIoTClient 56:8704100b3b54 1446 }
AzureIoTClient 56:8704100b3b54 1447 else
AzureIoTClient 56:8704100b3b54 1448 {
AzureIoTClient 56:8704100b3b54 1449 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_087: [If `message` is a success response for a GET request, `on_message_received_callback` shall be invoked with TWIN_UPDATE_TYPE_COMPLETE and the message body received]
AzureIoTClient 56:8704100b3b54 1450 if (twin_op_ctx->msgr->on_message_received_callback != NULL)
AzureIoTClient 56:8704100b3b54 1451 {
AzureIoTClient 56:8704100b3b54 1452 twin_op_ctx->msgr->on_message_received_callback(TWIN_UPDATE_TYPE_COMPLETE, (const char*)twin_report.bytes, twin_report.length, twin_op_ctx->msgr->on_message_received_context);
AzureIoTClient 56:8704100b3b54 1453 }
AzureIoTClient 39:e98d5df6dc74 1454
AzureIoTClient 56:8704100b3b54 1455 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_088: [If `message` is a success response for a GET request, the TWIN messenger shall trigger the subscription for partial updates]
AzureIoTClient 56:8704100b3b54 1456 if (twin_msgr->subscription_state == TWIN_SUBSCRIPTION_STATE_GETTING_COMPLETE_PROPERTIES)
AzureIoTClient 56:8704100b3b54 1457 {
AzureIoTClient 56:8704100b3b54 1458 twin_msgr->subscription_state = TWIN_SUBSCRIPTION_STATE_SUBSCRIBE_FOR_UPDATES;
AzureIoTClient 56:8704100b3b54 1459 twin_msgr->subscription_error_count = 0;
AzureIoTClient 56:8704100b3b54 1460 }
AzureIoTClient 56:8704100b3b54 1461 }
AzureIoTClient 56:8704100b3b54 1462 }
AzureIoTClient 56:8704100b3b54 1463 else if (twin_op_ctx->type == TWIN_OPERATION_TYPE_PUT)
AzureIoTClient 56:8704100b3b54 1464 {
AzureIoTClient 56:8704100b3b54 1465 if (twin_msgr->subscription_state == TWIN_SUBSCRIPTION_STATE_SUBSCRIBED)
AzureIoTClient 56:8704100b3b54 1466 {
AzureIoTClient 56:8704100b3b54 1467 bool subscription_succeeded = true;
AzureIoTClient 56:8704100b3b54 1468
AzureIoTClient 56:8704100b3b54 1469 if (!has_status_code)
AzureIoTClient 56:8704100b3b54 1470 {
AzureIoTClient 56:8704100b3b54 1471 LogError("Received an incoming TWIN message for a PUT operation, but with no status code (%s, %s)", twin_msgr->device_id, correlation_id);
AzureIoTClient 56:8704100b3b54 1472
AzureIoTClient 56:8704100b3b54 1473 subscription_succeeded = false;
AzureIoTClient 56:8704100b3b54 1474 }
AzureIoTClient 56:8704100b3b54 1475 else if (status_code < 200 || status_code >= 300)
AzureIoTClient 56:8704100b3b54 1476 {
AzureIoTClient 56:8704100b3b54 1477 LogError("Received status code %d for TWIN subscription request (%s, %s)", status_code, twin_msgr->device_id, correlation_id);
AzureIoTClient 39:e98d5df6dc74 1478
AzureIoTClient 56:8704100b3b54 1479 subscription_succeeded = false;
AzureIoTClient 56:8704100b3b54 1480 }
AzureIoTClient 39:e98d5df6dc74 1481
AzureIoTClient 56:8704100b3b54 1482 if (twin_msgr->subscription_state == TWIN_SUBSCRIPTION_STATE_SUBSCRIBING)
AzureIoTClient 56:8704100b3b54 1483 {
AzureIoTClient 56:8704100b3b54 1484 if (subscription_succeeded)
AzureIoTClient 56:8704100b3b54 1485 {
AzureIoTClient 56:8704100b3b54 1486 twin_msgr->subscription_state = TWIN_SUBSCRIPTION_STATE_SUBSCRIBED;
AzureIoTClient 56:8704100b3b54 1487 twin_msgr->subscription_error_count = 0;
AzureIoTClient 56:8704100b3b54 1488 }
AzureIoTClient 56:8704100b3b54 1489 else
AzureIoTClient 56:8704100b3b54 1490 {
AzureIoTClient 56:8704100b3b54 1491 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_090: [If `message` is a failed response for a PUT request, the TWIN messenger shall attempt to send another PUT request]
AzureIoTClient 56:8704100b3b54 1492 twin_msgr->subscription_state = TWIN_SUBSCRIPTION_STATE_SUBSCRIBE_FOR_UPDATES;
AzureIoTClient 56:8704100b3b54 1493 twin_msgr->subscription_error_count++;
AzureIoTClient 56:8704100b3b54 1494 }
AzureIoTClient 56:8704100b3b54 1495 }
AzureIoTClient 56:8704100b3b54 1496 }
AzureIoTClient 56:8704100b3b54 1497 }
AzureIoTClient 56:8704100b3b54 1498 else if (twin_op_ctx->type == TWIN_OPERATION_TYPE_DELETE)
AzureIoTClient 56:8704100b3b54 1499 {
AzureIoTClient 56:8704100b3b54 1500 if (twin_msgr->subscription_state == TWIN_SUBSCRIPTION_STATE_NOT_SUBSCRIBED)
AzureIoTClient 56:8704100b3b54 1501 {
AzureIoTClient 56:8704100b3b54 1502 bool unsubscription_succeeded = true;
AzureIoTClient 56:8704100b3b54 1503
AzureIoTClient 56:8704100b3b54 1504 if (!has_status_code)
AzureIoTClient 56:8704100b3b54 1505 {
AzureIoTClient 56:8704100b3b54 1506 LogError("Received an incoming TWIN message for a DELETE operation, but with no status code (%s, %s)", twin_msgr->device_id, correlation_id);
AzureIoTClient 39:e98d5df6dc74 1507
AzureIoTClient 56:8704100b3b54 1508 unsubscription_succeeded = false;
AzureIoTClient 56:8704100b3b54 1509 }
AzureIoTClient 56:8704100b3b54 1510 else if (status_code < 200 || status_code >= 300)
AzureIoTClient 56:8704100b3b54 1511 {
AzureIoTClient 56:8704100b3b54 1512 LogError("Received status code %d for TWIN unsubscription request (%s, %s)", status_code, twin_msgr->device_id, correlation_id);
AzureIoTClient 56:8704100b3b54 1513
AzureIoTClient 56:8704100b3b54 1514 unsubscription_succeeded = false;
AzureIoTClient 56:8704100b3b54 1515 }
AzureIoTClient 39:e98d5df6dc74 1516
AzureIoTClient 56:8704100b3b54 1517 if (twin_msgr->subscription_state == TWIN_SUBSCRIPTION_STATE_UNSUBSCRIBING)
AzureIoTClient 56:8704100b3b54 1518 {
AzureIoTClient 56:8704100b3b54 1519 if (unsubscription_succeeded)
AzureIoTClient 56:8704100b3b54 1520 {
AzureIoTClient 56:8704100b3b54 1521 twin_msgr->subscription_state = TWIN_SUBSCRIPTION_STATE_NOT_SUBSCRIBED;
AzureIoTClient 56:8704100b3b54 1522 twin_msgr->subscription_error_count = 0;
AzureIoTClient 56:8704100b3b54 1523 }
AzureIoTClient 56:8704100b3b54 1524 else
AzureIoTClient 56:8704100b3b54 1525 {
AzureIoTClient 56:8704100b3b54 1526 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_091: [If `message` is a failed response for a DELETE request, the TWIN messenger shall attempt to send another DELETE request]
AzureIoTClient 56:8704100b3b54 1527 twin_msgr->subscription_state = TWIN_SUBSCRIPTION_STATE_UNSUBSCRIBE;
AzureIoTClient 56:8704100b3b54 1528 twin_msgr->subscription_error_count++;
AzureIoTClient 56:8704100b3b54 1529 }
AzureIoTClient 56:8704100b3b54 1530 }
AzureIoTClient 56:8704100b3b54 1531 }
AzureIoTClient 56:8704100b3b54 1532 }
AzureIoTClient 56:8704100b3b54 1533
AzureIoTClient 56:8704100b3b54 1534 destroy_twin_operation_context(twin_op_ctx);
AzureIoTClient 56:8704100b3b54 1535 }
AzureIoTClient 39:e98d5df6dc74 1536
AzureIoTClient 56:8704100b3b54 1537 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_092: [The corresponding TWIN request shall be removed from `twin_msgr->operations` and destroyed]
AzureIoTClient 56:8704100b3b54 1538 if (singlylinkedlist_remove(twin_msgr->operations, list_item) != 0)
AzureIoTClient 56:8704100b3b54 1539 {
AzureIoTClient 56:8704100b3b54 1540 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_093: [The corresponding TWIN request failed to be removed from `twin_msgr->operations`, `twin_msgr->state` shall be set to TWIN_MESSENGER_STATE_ERROR and informed to the user]
AzureIoTClient 56:8704100b3b54 1541 LogError("Failed removing context for incoming TWIN message (%s, %s)",
AzureIoTClient 56:8704100b3b54 1542 twin_msgr->device_id, correlation_id);
AzureIoTClient 39:e98d5df6dc74 1543
AzureIoTClient 56:8704100b3b54 1544 update_state(twin_msgr, TWIN_MESSENGER_STATE_ERROR);
AzureIoTClient 56:8704100b3b54 1545 }
AzureIoTClient 56:8704100b3b54 1546 }
AzureIoTClient 39:e98d5df6dc74 1547
AzureIoTClient 56:8704100b3b54 1548 free(correlation_id);
AzureIoTClient 56:8704100b3b54 1549 }
AzureIoTClient 56:8704100b3b54 1550 else if (has_twin_report)
AzureIoTClient 56:8704100b3b54 1551 {
AzureIoTClient 56:8704100b3b54 1552 // It is supposed to be a desired properties delta update.
AzureIoTClient 39:e98d5df6dc74 1553
AzureIoTClient 56:8704100b3b54 1554 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_094: [If `message` is not a client request, `on_message_received_callback` shall be invoked with TWIN_UPDATE_TYPE_PARTIAL and the message body received]
AzureIoTClient 56:8704100b3b54 1555 if (twin_msgr->on_message_received_callback != NULL)
AzureIoTClient 56:8704100b3b54 1556 {
AzureIoTClient 56:8704100b3b54 1557 twin_msgr->on_message_received_callback(TWIN_UPDATE_TYPE_PARTIAL, (const char*)twin_report.bytes, twin_report.length, twin_msgr->on_message_received_context);
AzureIoTClient 56:8704100b3b54 1558 }
AzureIoTClient 56:8704100b3b54 1559 }
AzureIoTClient 56:8704100b3b54 1560 else
AzureIoTClient 56:8704100b3b54 1561 {
AzureIoTClient 56:8704100b3b54 1562 LogError("Received TWIN message with no correlation-id and no report (%s)", twin_msgr->device_id);
AzureIoTClient 56:8704100b3b54 1563 }
AzureIoTClient 56:8704100b3b54 1564 }
AzureIoTClient 56:8704100b3b54 1565 }
AzureIoTClient 39:e98d5df6dc74 1566
AzureIoTClient 56:8704100b3b54 1567 return disposition_result;
AzureIoTClient 39:e98d5df6dc74 1568 }
AzureIoTClient 39:e98d5df6dc74 1569
AzureIoTClient 39:e98d5df6dc74 1570 static void on_amqp_messenger_state_changed_callback(void* context, AMQP_MESSENGER_STATE previous_state, AMQP_MESSENGER_STATE new_state)
AzureIoTClient 39:e98d5df6dc74 1571 {
AzureIoTClient 56:8704100b3b54 1572 if (context == NULL)
AzureIoTClient 56:8704100b3b54 1573 {
AzureIoTClient 56:8704100b3b54 1574 LogError("Invalid argument (context is NULL)");
AzureIoTClient 56:8704100b3b54 1575 }
AzureIoTClient 56:8704100b3b54 1576 else if (new_state != previous_state)
AzureIoTClient 56:8704100b3b54 1577 {
AzureIoTClient 56:8704100b3b54 1578 TWIN_MESSENGER_INSTANCE* twin_msgr = (TWIN_MESSENGER_INSTANCE*)context;
AzureIoTClient 39:e98d5df6dc74 1579
AzureIoTClient 56:8704100b3b54 1580 if (twin_msgr->state == TWIN_MESSENGER_STATE_STARTING && new_state == AMQP_MESSENGER_STATE_STARTED)
AzureIoTClient 56:8704100b3b54 1581 {
AzureIoTClient 56:8704100b3b54 1582 if (twin_msgr->amqp_msgr_is_subscribed)
AzureIoTClient 56:8704100b3b54 1583 {
AzureIoTClient 56:8704100b3b54 1584 update_state(twin_msgr, TWIN_MESSENGER_STATE_STARTED);
AzureIoTClient 56:8704100b3b54 1585 }
AzureIoTClient 56:8704100b3b54 1586 // Else, it shall wait for the moment the AMQP msgr is subscribed.
AzureIoTClient 56:8704100b3b54 1587 }
AzureIoTClient 56:8704100b3b54 1588 else if (twin_msgr->state == TWIN_MESSENGER_STATE_STOPPING && new_state == TWIN_MESSENGER_STATE_STOPPED)
AzureIoTClient 56:8704100b3b54 1589 {
AzureIoTClient 56:8704100b3b54 1590 if (!twin_msgr->amqp_msgr_is_subscribed)
AzureIoTClient 56:8704100b3b54 1591 {
AzureIoTClient 56:8704100b3b54 1592 update_state(twin_msgr, TWIN_MESSENGER_STATE_STOPPED);
AzureIoTClient 56:8704100b3b54 1593 }
AzureIoTClient 56:8704100b3b54 1594 // Else, it shall wait for the moment the AMQP msgr is unsubscribed.
AzureIoTClient 56:8704100b3b54 1595 }
AzureIoTClient 56:8704100b3b54 1596 else if ((twin_msgr->state == TWIN_MESSENGER_STATE_STARTING && new_state == AMQP_MESSENGER_STATE_STARTING) ||
AzureIoTClient 56:8704100b3b54 1597 (twin_msgr->state == TWIN_MESSENGER_STATE_STOPPING && new_state == AMQP_MESSENGER_STATE_STOPPING))
AzureIoTClient 56:8704100b3b54 1598 {
AzureIoTClient 56:8704100b3b54 1599 // Do nothing, this is expected.
AzureIoTClient 56:8704100b3b54 1600 }
AzureIoTClient 56:8704100b3b54 1601 else
AzureIoTClient 56:8704100b3b54 1602 {
AzureIoTClient 56:8704100b3b54 1603 LogError("Unexpected AMQP messenger state (%s, %s, %s)",
AzureIoTClient 56:8704100b3b54 1604 twin_msgr->device_id, ENUM_TO_STRING(TWIN_MESSENGER_STATE, twin_msgr->state), ENUM_TO_STRING(AMQP_MESSENGER_STATE, new_state));
AzureIoTClient 39:e98d5df6dc74 1605
AzureIoTClient 56:8704100b3b54 1606 update_state(twin_msgr, TWIN_MESSENGER_STATE_ERROR);
AzureIoTClient 56:8704100b3b54 1607 }
AzureIoTClient 56:8704100b3b54 1608
AzureIoTClient 56:8704100b3b54 1609 twin_msgr->amqp_msgr_state = new_state;
AzureIoTClient 56:8704100b3b54 1610 }
AzureIoTClient 39:e98d5df6dc74 1611 }
AzureIoTClient 39:e98d5df6dc74 1612
AzureIoTClient 39:e98d5df6dc74 1613 static void on_amqp_messenger_subscription_changed_callback(void* context, bool is_subscribed)
AzureIoTClient 39:e98d5df6dc74 1614 {
AzureIoTClient 56:8704100b3b54 1615 if (context == NULL)
AzureIoTClient 56:8704100b3b54 1616 {
AzureIoTClient 56:8704100b3b54 1617 LogError("Invalid argument (context is NULL)");
AzureIoTClient 56:8704100b3b54 1618 }
AzureIoTClient 56:8704100b3b54 1619 else
AzureIoTClient 56:8704100b3b54 1620 {
AzureIoTClient 56:8704100b3b54 1621 TWIN_MESSENGER_INSTANCE* twin_msgr = (TWIN_MESSENGER_INSTANCE*)context;
AzureIoTClient 39:e98d5df6dc74 1622
AzureIoTClient 56:8704100b3b54 1623 if (twin_msgr->state == TWIN_MESSENGER_STATE_STARTING && is_subscribed)
AzureIoTClient 56:8704100b3b54 1624 {
AzureIoTClient 56:8704100b3b54 1625 if (twin_msgr->amqp_msgr_state == AMQP_MESSENGER_STATE_STARTED)
AzureIoTClient 56:8704100b3b54 1626 {
AzureIoTClient 56:8704100b3b54 1627 update_state(twin_msgr, TWIN_MESSENGER_STATE_STARTED);
AzureIoTClient 56:8704100b3b54 1628 }
AzureIoTClient 56:8704100b3b54 1629 // Else, it shall wait for the moment the AMQP msgr is STARTED.
AzureIoTClient 56:8704100b3b54 1630 }
AzureIoTClient 56:8704100b3b54 1631 else if (twin_msgr->state == TWIN_MESSENGER_STATE_STOPPING && !is_subscribed)
AzureIoTClient 56:8704100b3b54 1632 {
AzureIoTClient 56:8704100b3b54 1633 if (twin_msgr->amqp_msgr_state == AMQP_MESSENGER_STATE_STOPPED)
AzureIoTClient 56:8704100b3b54 1634 {
AzureIoTClient 56:8704100b3b54 1635 update_state(twin_msgr, TWIN_MESSENGER_STATE_STOPPED);
AzureIoTClient 56:8704100b3b54 1636 }
AzureIoTClient 56:8704100b3b54 1637 // Else, it shall wait for the moment the AMQP msgr is STOPPED.
AzureIoTClient 56:8704100b3b54 1638 }
AzureIoTClient 56:8704100b3b54 1639 else
AzureIoTClient 56:8704100b3b54 1640 {
AzureIoTClient 56:8704100b3b54 1641 LogError("Unexpected AMQP messenger state (%s, %s, %d)",
AzureIoTClient 56:8704100b3b54 1642 twin_msgr->device_id, ENUM_TO_STRING(TWIN_MESSENGER_STATE, twin_msgr->state), is_subscribed);
AzureIoTClient 39:e98d5df6dc74 1643
AzureIoTClient 56:8704100b3b54 1644 update_state(twin_msgr, TWIN_MESSENGER_STATE_ERROR);
AzureIoTClient 56:8704100b3b54 1645 }
AzureIoTClient 39:e98d5df6dc74 1646
AzureIoTClient 56:8704100b3b54 1647 twin_msgr->amqp_msgr_is_subscribed = is_subscribed;
AzureIoTClient 56:8704100b3b54 1648 }
AzureIoTClient 39:e98d5df6dc74 1649 }
AzureIoTClient 39:e98d5df6dc74 1650
AzureIoTClient 39:e98d5df6dc74 1651
AzureIoTClient 39:e98d5df6dc74 1652 //---------- Public APIs ----------//
AzureIoTClient 39:e98d5df6dc74 1653
AzureIoTClient 39:e98d5df6dc74 1654 TWIN_MESSENGER_HANDLE twin_messenger_create(const TWIN_MESSENGER_CONFIG* messenger_config)
AzureIoTClient 39:e98d5df6dc74 1655 {
AzureIoTClient 56:8704100b3b54 1656 TWIN_MESSENGER_INSTANCE* twin_msgr;
AzureIoTClient 39:e98d5df6dc74 1657
AzureIoTClient 56:8704100b3b54 1658 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_001: [If parameter `messenger_config` is NULL, twin_messenger_create() shall return NULL]
AzureIoTClient 56:8704100b3b54 1659 if (messenger_config == NULL)
AzureIoTClient 56:8704100b3b54 1660 {
AzureIoTClient 56:8704100b3b54 1661 LogError("Invalid argument (messenger_config is NULL)");
AzureIoTClient 56:8704100b3b54 1662 twin_msgr = NULL;
AzureIoTClient 56:8704100b3b54 1663 }
AzureIoTClient 56:8704100b3b54 1664 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_002: [If `messenger_config`'s `device_id`, `iothub_host_fqdn` or `client_version` is NULL, twin_messenger_create() shall return NULL]
AzureIoTClient 56:8704100b3b54 1665 else if (messenger_config->device_id == NULL || messenger_config->iothub_host_fqdn == NULL || messenger_config->client_version == NULL)
AzureIoTClient 56:8704100b3b54 1666 {
AzureIoTClient 56:8704100b3b54 1667 LogError("Invalid argument (device_id=%p, iothub_host_fqdn=%p, client_version=%p)",
AzureIoTClient 56:8704100b3b54 1668 messenger_config->device_id, messenger_config->iothub_host_fqdn, messenger_config->client_version);
AzureIoTClient 56:8704100b3b54 1669 twin_msgr = NULL;
AzureIoTClient 56:8704100b3b54 1670 }
AzureIoTClient 56:8704100b3b54 1671 else
AzureIoTClient 56:8704100b3b54 1672 {
AzureIoTClient 56:8704100b3b54 1673 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_003: [twin_messenger_create() shall allocate memory for the messenger instance structure (aka `twin_msgr`)]
AzureIoTClient 56:8704100b3b54 1674 if ((twin_msgr = (TWIN_MESSENGER_INSTANCE*)malloc(sizeof(TWIN_MESSENGER_INSTANCE))) == NULL)
AzureIoTClient 56:8704100b3b54 1675 {
AzureIoTClient 56:8704100b3b54 1676 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_004: [If malloc() fails, twin_messenger_create() shall fail and return NULL]
AzureIoTClient 56:8704100b3b54 1677 LogError("Failed allocating TWIN_MESSENGER_INSTANCE (%s)", messenger_config->device_id);
AzureIoTClient 56:8704100b3b54 1678 }
AzureIoTClient 56:8704100b3b54 1679 else
AzureIoTClient 56:8704100b3b54 1680 {
AzureIoTClient 56:8704100b3b54 1681 MAP_HANDLE link_attach_properties;
AzureIoTClient 56:8704100b3b54 1682
AzureIoTClient 56:8704100b3b54 1683 memset(twin_msgr, 0, sizeof(TWIN_MESSENGER_INSTANCE));
AzureIoTClient 56:8704100b3b54 1684 twin_msgr->state = TWIN_MESSENGER_STATE_STOPPED;
AzureIoTClient 56:8704100b3b54 1685 twin_msgr->subscription_state = TWIN_SUBSCRIPTION_STATE_NOT_SUBSCRIBED;
AzureIoTClient 56:8704100b3b54 1686 twin_msgr->amqp_msgr_state = AMQP_MESSENGER_STATE_STOPPED;
AzureIoTClient 39:e98d5df6dc74 1687
AzureIoTClient 56:8704100b3b54 1688 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_005: [twin_messenger_create() shall save a copy of `messenger_config` info into `twin_msgr`]
AzureIoTClient 56:8704100b3b54 1689 if (mallocAndStrcpy_s(&twin_msgr->client_version, messenger_config->client_version) != 0)
AzureIoTClient 56:8704100b3b54 1690 {
AzureIoTClient 56:8704100b3b54 1691 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_006: [If any `messenger_config` info fails to be copied, twin_messenger_create() shall fail and return NULL]
AzureIoTClient 56:8704100b3b54 1692 LogError("Failed copying client_version (%s)", messenger_config->device_id);
AzureIoTClient 56:8704100b3b54 1693 internal_twin_messenger_destroy(twin_msgr);
AzureIoTClient 56:8704100b3b54 1694 twin_msgr = NULL;
AzureIoTClient 56:8704100b3b54 1695 }
AzureIoTClient 56:8704100b3b54 1696 else if (mallocAndStrcpy_s(&twin_msgr->device_id, messenger_config->device_id) != 0)
AzureIoTClient 56:8704100b3b54 1697 {
AzureIoTClient 56:8704100b3b54 1698 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_006: [If any `messenger_config` info fails to be copied, twin_messenger_create() shall fail and return NULL]
AzureIoTClient 56:8704100b3b54 1699 LogError("Failed copying device_id (%s)", messenger_config->device_id);
AzureIoTClient 56:8704100b3b54 1700 internal_twin_messenger_destroy(twin_msgr);
AzureIoTClient 56:8704100b3b54 1701 twin_msgr = NULL;
AzureIoTClient 56:8704100b3b54 1702 }
AzureIoTClient 56:8704100b3b54 1703 else if ((messenger_config->module_id != NULL) && (mallocAndStrcpy_s(&twin_msgr->module_id, messenger_config->module_id) != 0))
AzureIoTClient 56:8704100b3b54 1704 {
AzureIoTClient 56:8704100b3b54 1705 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_006: [If any `messenger_config` info fails to be copied, twin_messenger_create() shall fail and return NULL]
AzureIoTClient 56:8704100b3b54 1706 LogError("Failed copying module_id (%s)", messenger_config->device_id);
AzureIoTClient 56:8704100b3b54 1707 internal_twin_messenger_destroy(twin_msgr);
AzureIoTClient 56:8704100b3b54 1708 twin_msgr = NULL;
AzureIoTClient 56:8704100b3b54 1709 }
AzureIoTClient 56:8704100b3b54 1710 else if (mallocAndStrcpy_s(&twin_msgr->iothub_host_fqdn, messenger_config->iothub_host_fqdn) != 0)
AzureIoTClient 56:8704100b3b54 1711 {
AzureIoTClient 56:8704100b3b54 1712 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_006: [If any `messenger_config` info fails to be copied, twin_messenger_create() shall fail and return NULL]
AzureIoTClient 56:8704100b3b54 1713 LogError("Failed copying iothub_host_fqdn (%s)", messenger_config->device_id);
AzureIoTClient 56:8704100b3b54 1714 internal_twin_messenger_destroy(twin_msgr);
AzureIoTClient 56:8704100b3b54 1715 twin_msgr = NULL;
AzureIoTClient 56:8704100b3b54 1716 }
AzureIoTClient 56:8704100b3b54 1717 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_007: [`twin_msgr->pending_patches` shall be set using singlylinkedlist_create()]
AzureIoTClient 56:8704100b3b54 1718 else if ((twin_msgr->pending_patches = singlylinkedlist_create()) == NULL)
AzureIoTClient 56:8704100b3b54 1719 {
AzureIoTClient 56:8704100b3b54 1720 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_008: [If singlylinkedlist_create() fails, twin_messenger_create() shall fail and return NULL]
AzureIoTClient 56:8704100b3b54 1721 LogError("Failed creating list for queueing patches (%s)", messenger_config->device_id);
AzureIoTClient 56:8704100b3b54 1722 internal_twin_messenger_destroy(twin_msgr);
AzureIoTClient 56:8704100b3b54 1723 twin_msgr = NULL;
AzureIoTClient 56:8704100b3b54 1724 }
AzureIoTClient 56:8704100b3b54 1725 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_009: [`twin_msgr->operations` shall be set using singlylinkedlist_create()]
AzureIoTClient 56:8704100b3b54 1726 else if ((twin_msgr->operations = singlylinkedlist_create()) == NULL)
AzureIoTClient 56:8704100b3b54 1727 {
AzureIoTClient 56:8704100b3b54 1728 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_010: [If singlylinkedlist_create() fails, twin_messenger_create() shall fail and return NULL]
AzureIoTClient 56:8704100b3b54 1729 LogError("Failed creating list for operations (%s)", messenger_config->device_id);
AzureIoTClient 56:8704100b3b54 1730 internal_twin_messenger_destroy(twin_msgr);
AzureIoTClient 56:8704100b3b54 1731 twin_msgr = NULL;
AzureIoTClient 56:8704100b3b54 1732 }
AzureIoTClient 56:8704100b3b54 1733 else if ((link_attach_properties = create_link_attach_properties(twin_msgr)) == NULL)
AzureIoTClient 56:8704100b3b54 1734 {
AzureIoTClient 56:8704100b3b54 1735 LogError("Failed creating link attach properties (%s)", messenger_config->device_id);
AzureIoTClient 56:8704100b3b54 1736 internal_twin_messenger_destroy(twin_msgr);
AzureIoTClient 56:8704100b3b54 1737 twin_msgr = NULL;
AzureIoTClient 56:8704100b3b54 1738 }
AzureIoTClient 56:8704100b3b54 1739 else
AzureIoTClient 56:8704100b3b54 1740 {
AzureIoTClient 39:e98d5df6dc74 1741
AzureIoTClient 56:8704100b3b54 1742 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_012: [`amqp_msgr_config->client_version` shall be set with `twin_msgr->client_version`]
AzureIoTClient 56:8704100b3b54 1743 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_013: [`amqp_msgr_config->device_id` shall be set with `twin_msgr->device_id`]
AzureIoTClient 56:8704100b3b54 1744 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_014: [`amqp_msgr_config->iothub_host_fqdn` shall be set with `twin_msgr->iothub_host_fqdn`]
AzureIoTClient 56:8704100b3b54 1745 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_015: [`amqp_msgr_config` shall have "twin/" as send link target suffix and receive link source suffix]
AzureIoTClient 56:8704100b3b54 1746 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_016: [`amqp_msgr_config` shall have send and receive link attach properties set as "com.microsoft:client-version" = `twin_msgr->client_version`, "com.microsoft:channel-correlation-id" = `twin:<UUID>`, "com.microsoft:api-version" = "2016-11-14"]
AzureIoTClient 56:8704100b3b54 1747 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_017: [`amqp_msgr_config` shall be set with `on_amqp_messenger_state_changed_callback` and `on_amqp_messenger_subscription_changed_callback` callbacks]
AzureIoTClient 56:8704100b3b54 1748 AMQP_MESSENGER_CONFIG amqp_msgr_config;
AzureIoTClient 56:8704100b3b54 1749 amqp_msgr_config.client_version = twin_msgr->client_version;
AzureIoTClient 56:8704100b3b54 1750 amqp_msgr_config.device_id = twin_msgr->device_id;
AzureIoTClient 56:8704100b3b54 1751 amqp_msgr_config.module_id = twin_msgr->module_id;
AzureIoTClient 56:8704100b3b54 1752 amqp_msgr_config.iothub_host_fqdn = twin_msgr->iothub_host_fqdn;
AzureIoTClient 56:8704100b3b54 1753 amqp_msgr_config.send_link.target_suffix = DEFAULT_TWIN_SEND_LINK_SOURCE_NAME;
AzureIoTClient 56:8704100b3b54 1754 amqp_msgr_config.send_link.attach_properties = link_attach_properties;
AzureIoTClient 56:8704100b3b54 1755 amqp_msgr_config.send_link.snd_settle_mode = sender_settle_mode_settled;
AzureIoTClient 56:8704100b3b54 1756 amqp_msgr_config.send_link.rcv_settle_mode = receiver_settle_mode_first;
AzureIoTClient 56:8704100b3b54 1757 amqp_msgr_config.receive_link.source_suffix = DEFAULT_TWIN_RECEIVE_LINK_TARGET_NAME;
AzureIoTClient 56:8704100b3b54 1758 amqp_msgr_config.receive_link.attach_properties = link_attach_properties;
AzureIoTClient 56:8704100b3b54 1759 amqp_msgr_config.receive_link.snd_settle_mode = sender_settle_mode_settled;
AzureIoTClient 56:8704100b3b54 1760 amqp_msgr_config.receive_link.rcv_settle_mode = receiver_settle_mode_first;
AzureIoTClient 56:8704100b3b54 1761 amqp_msgr_config.on_state_changed_callback = on_amqp_messenger_state_changed_callback;
AzureIoTClient 56:8704100b3b54 1762 amqp_msgr_config.on_state_changed_context = (void*)twin_msgr;
AzureIoTClient 56:8704100b3b54 1763 amqp_msgr_config.on_subscription_changed_callback = on_amqp_messenger_subscription_changed_callback;
AzureIoTClient 56:8704100b3b54 1764 amqp_msgr_config.on_subscription_changed_context = (void*)twin_msgr;
AzureIoTClient 39:e98d5df6dc74 1765
AzureIoTClient 56:8704100b3b54 1766 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_011: [`twin_msgr->amqp_msgr` shall be set using amqp_messenger_create(), passing a AMQP_MESSENGER_CONFIG instance `amqp_msgr_config`]
AzureIoTClient 56:8704100b3b54 1767 if ((twin_msgr->amqp_msgr = amqp_messenger_create(&amqp_msgr_config)) == NULL)
AzureIoTClient 56:8704100b3b54 1768 {
AzureIoTClient 56:8704100b3b54 1769 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_018: [If amqp_messenger_create() fails, twin_messenger_create() shall fail and return NULL]
AzureIoTClient 56:8704100b3b54 1770 LogError("Failed creating the AMQP messenger (%s)", messenger_config->device_id);
AzureIoTClient 56:8704100b3b54 1771 internal_twin_messenger_destroy(twin_msgr);
AzureIoTClient 56:8704100b3b54 1772 twin_msgr = NULL;
AzureIoTClient 56:8704100b3b54 1773 }
AzureIoTClient 56:8704100b3b54 1774 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_019: [`twin_msgr->amqp_msgr` shall subscribe for AMQP messages by calling amqp_messenger_subscribe_for_messages() passing `on_amqp_message_received`]
AzureIoTClient 56:8704100b3b54 1775 else if (amqp_messenger_subscribe_for_messages(twin_msgr->amqp_msgr, on_amqp_message_received_callback, (void*)twin_msgr))
AzureIoTClient 56:8704100b3b54 1776 {
AzureIoTClient 56:8704100b3b54 1777 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_020: [If amqp_messenger_subscribe_for_messages() fails, twin_messenger_create() shall fail and return NULL]
AzureIoTClient 56:8704100b3b54 1778 LogError("Failed subscribing for AMQP messages (%s)", messenger_config->device_id);
AzureIoTClient 56:8704100b3b54 1779 internal_twin_messenger_destroy(twin_msgr);
AzureIoTClient 56:8704100b3b54 1780 twin_msgr = NULL;
AzureIoTClient 56:8704100b3b54 1781 }
AzureIoTClient 56:8704100b3b54 1782 else
AzureIoTClient 56:8704100b3b54 1783 {
AzureIoTClient 56:8704100b3b54 1784 // Codes_SRS_IOTHUBTRANSPORT_TWIN_MESSENGER_09_013: [`messenger_config->on_state_changed_callback` shall be saved into `twin_msgr->on_state_changed_callback`]
AzureIoTClient 56:8704100b3b54 1785 twin_msgr->on_state_changed_callback = messenger_config->on_state_changed_callback;
AzureIoTClient 39:e98d5df6dc74 1786
AzureIoTClient 56:8704100b3b54 1787 // Codes_SRS_IOTHUBTRANSPORT_TWIN_MESSENGER_09_014: [`messenger_config->on_state_changed_context` shall be saved into `twin_msgr->on_state_changed_context`]
AzureIoTClient 56:8704100b3b54 1788 twin_msgr->on_state_changed_context = messenger_config->on_state_changed_context;
AzureIoTClient 56:8704100b3b54 1789 }
AzureIoTClient 39:e98d5df6dc74 1790
AzureIoTClient 56:8704100b3b54 1791 destroy_link_attach_properties(link_attach_properties);
AzureIoTClient 56:8704100b3b54 1792 }
AzureIoTClient 56:8704100b3b54 1793 }
AzureIoTClient 56:8704100b3b54 1794 }
AzureIoTClient 39:e98d5df6dc74 1795
AzureIoTClient 56:8704100b3b54 1796 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_021: [If no failures occurr, twin_messenger_create() shall return a handle to `twin_msgr`]
AzureIoTClient 56:8704100b3b54 1797 return (TWIN_MESSENGER_HANDLE)twin_msgr;
AzureIoTClient 39:e98d5df6dc74 1798 }
AzureIoTClient 39:e98d5df6dc74 1799
AzureIoTClient 39:e98d5df6dc74 1800 int twin_messenger_report_state_async(TWIN_MESSENGER_HANDLE twin_msgr_handle, CONSTBUFFER_HANDLE data, TWIN_MESSENGER_REPORT_STATE_COMPLETE_CALLBACK on_report_state_complete_callback, const void* context)
AzureIoTClient 39:e98d5df6dc74 1801 {
AzureIoTClient 56:8704100b3b54 1802 int result;
AzureIoTClient 39:e98d5df6dc74 1803
AzureIoTClient 56:8704100b3b54 1804 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_022: [If `twin_msgr_handle` or `data` are NULL, twin_messenger_report_state_async() shall fail and return a non-zero value]
AzureIoTClient 56:8704100b3b54 1805 if (twin_msgr_handle == NULL || data == NULL)
AzureIoTClient 56:8704100b3b54 1806 {
AzureIoTClient 56:8704100b3b54 1807 LogError("Invalid argument (twin_msgr_handle=%p, data=%p)", twin_msgr_handle, data);
AzureIoTClient 56:8704100b3b54 1808 result = __FAILURE__;
AzureIoTClient 56:8704100b3b54 1809 }
AzureIoTClient 56:8704100b3b54 1810 else
AzureIoTClient 56:8704100b3b54 1811 {
AzureIoTClient 56:8704100b3b54 1812 TWIN_MESSENGER_INSTANCE* twin_msgr = (TWIN_MESSENGER_INSTANCE*)twin_msgr_handle;
AzureIoTClient 56:8704100b3b54 1813 TWIN_PATCH_OPERATION_CONTEXT* twin_patch_ctx;
AzureIoTClient 39:e98d5df6dc74 1814
AzureIoTClient 56:8704100b3b54 1815 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_023: [twin_messenger_report_state_async() shall allocate memory for a TWIN_PATCH_OPERATION_CONTEXT structure (aka `twin_op_ctx`)]
AzureIoTClient 56:8704100b3b54 1816 if ((twin_patch_ctx = (TWIN_PATCH_OPERATION_CONTEXT*)malloc(sizeof(TWIN_PATCH_OPERATION_CONTEXT))) == NULL)
AzureIoTClient 56:8704100b3b54 1817 {
AzureIoTClient 56:8704100b3b54 1818 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_024: [If malloc() fails, twin_messenger_report_state_async() shall fail and return a non-zero value]
AzureIoTClient 56:8704100b3b54 1819 LogError("Failed creating context for sending reported state (%s)", twin_msgr->device_id);
AzureIoTClient 56:8704100b3b54 1820 result = __FAILURE__;
AzureIoTClient 56:8704100b3b54 1821 }
AzureIoTClient 56:8704100b3b54 1822 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_025: [`twin_op_ctx` shall have a copy of `data`]
AzureIoTClient 56:8704100b3b54 1823 else if ((twin_patch_ctx->data = CONSTBUFFER_Clone(data)) == NULL)
AzureIoTClient 56:8704100b3b54 1824 {
AzureIoTClient 56:8704100b3b54 1825 LogError("Failed cloning TWIN patch request data (%s)", twin_msgr->device_id);
AzureIoTClient 56:8704100b3b54 1826 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_031: [If any failure occurs, twin_messenger_report_state_async() shall free any memory it has allocated]
AzureIoTClient 56:8704100b3b54 1827 free(twin_patch_ctx);
AzureIoTClient 56:8704100b3b54 1828 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_026: [If `data` fails to be copied, twin_messenger_report_state_async() shall fail and return a non-zero value]
AzureIoTClient 56:8704100b3b54 1829 result = __FAILURE__;
AzureIoTClient 56:8704100b3b54 1830 }
AzureIoTClient 56:8704100b3b54 1831 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_027: [`twin_op_ctx->time_enqueued` shall be set using get_time]
AzureIoTClient 56:8704100b3b54 1832 else if ((twin_patch_ctx->time_enqueued = get_time(NULL)) == INDEFINITE_TIME)
AzureIoTClient 56:8704100b3b54 1833 {
AzureIoTClient 56:8704100b3b54 1834 LogError("Failed setting reported state enqueue time (%s)", twin_msgr->device_id);
AzureIoTClient 56:8704100b3b54 1835 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_031: [If any failure occurs, twin_messenger_report_state_async() shall free any memory it has allocated]
AzureIoTClient 56:8704100b3b54 1836 CONSTBUFFER_Destroy(twin_patch_ctx->data);
AzureIoTClient 56:8704100b3b54 1837 free(twin_patch_ctx);
AzureIoTClient 56:8704100b3b54 1838 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_028: [If `twin_op_ctx->time_enqueued` fails to be set, twin_messenger_report_state_async() shall fail and return a non-zero value]
AzureIoTClient 56:8704100b3b54 1839 result = __FAILURE__;
AzureIoTClient 56:8704100b3b54 1840 }
AzureIoTClient 56:8704100b3b54 1841 else
AzureIoTClient 56:8704100b3b54 1842 {
AzureIoTClient 56:8704100b3b54 1843 twin_patch_ctx->on_report_state_complete_callback = on_report_state_complete_callback;
AzureIoTClient 56:8704100b3b54 1844 twin_patch_ctx->on_report_state_complete_context = context;
AzureIoTClient 39:e98d5df6dc74 1845
AzureIoTClient 56:8704100b3b54 1846 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_029: [`twin_op_ctx` shall be added to `twin_msgr->pending_patches` using singlylinkedlist_add()]
AzureIoTClient 56:8704100b3b54 1847 if (singlylinkedlist_add(twin_msgr->pending_patches, twin_patch_ctx) == NULL)
AzureIoTClient 56:8704100b3b54 1848 {
AzureIoTClient 56:8704100b3b54 1849 LogError("Failed adding TWIN patch request to queue (%s)", twin_msgr->device_id);
AzureIoTClient 56:8704100b3b54 1850 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_031: [If any failure occurs, twin_messenger_report_state_async() shall free any memory it has allocated]
AzureIoTClient 56:8704100b3b54 1851 CONSTBUFFER_Destroy(twin_patch_ctx->data);
AzureIoTClient 56:8704100b3b54 1852 free(twin_patch_ctx);
AzureIoTClient 56:8704100b3b54 1853 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_030: [If singlylinkedlist_add() fails, twin_messenger_report_state_async() shall fail and return a non-zero value]
AzureIoTClient 56:8704100b3b54 1854 result = __FAILURE__;
AzureIoTClient 56:8704100b3b54 1855 }
AzureIoTClient 56:8704100b3b54 1856 else
AzureIoTClient 56:8704100b3b54 1857 {
AzureIoTClient 56:8704100b3b54 1858 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_032: [If no failures occur, twin_messenger_report_state_async() shall return zero]
AzureIoTClient 56:8704100b3b54 1859 result = RESULT_OK;
AzureIoTClient 56:8704100b3b54 1860 }
AzureIoTClient 56:8704100b3b54 1861 }
AzureIoTClient 56:8704100b3b54 1862 }
AzureIoTClient 39:e98d5df6dc74 1863
AzureIoTClient 56:8704100b3b54 1864 return result;
AzureIoTClient 39:e98d5df6dc74 1865 }
AzureIoTClient 39:e98d5df6dc74 1866
AzureIoTClient 39:e98d5df6dc74 1867 int twin_messenger_subscribe(TWIN_MESSENGER_HANDLE twin_msgr_handle, TWIN_STATE_UPDATE_CALLBACK on_twin_state_update_callback, void* context)
AzureIoTClient 39:e98d5df6dc74 1868 {
AzureIoTClient 56:8704100b3b54 1869 int result;
AzureIoTClient 39:e98d5df6dc74 1870
AzureIoTClient 56:8704100b3b54 1871 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_037: [If `twin_msgr_handle` or `on_twin_state_update_callback` are NULL, twin_messenger_subscribe() shall fail and return a non-zero value]
AzureIoTClient 56:8704100b3b54 1872 if (twin_msgr_handle == NULL || on_twin_state_update_callback == NULL)
AzureIoTClient 56:8704100b3b54 1873 {
AzureIoTClient 56:8704100b3b54 1874 LogError("Invalid argument (twin_msgr_handle=%p, on_twin_state_update_callback=%p)", twin_msgr_handle, on_twin_state_update_callback);
AzureIoTClient 56:8704100b3b54 1875 result = __FAILURE__;
AzureIoTClient 56:8704100b3b54 1876 }
AzureIoTClient 56:8704100b3b54 1877 else
AzureIoTClient 56:8704100b3b54 1878 {
AzureIoTClient 56:8704100b3b54 1879 TWIN_MESSENGER_INSTANCE* twin_msgr = (TWIN_MESSENGER_INSTANCE*)twin_msgr_handle;
AzureIoTClient 39:e98d5df6dc74 1880
AzureIoTClient 56:8704100b3b54 1881 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_038: [If `twin_msgr` is already subscribed, twin_messenger_subscribe() shall return zero]
AzureIoTClient 56:8704100b3b54 1882 if (twin_msgr->subscription_state != TWIN_SUBSCRIPTION_STATE_NOT_SUBSCRIBED)
AzureIoTClient 56:8704100b3b54 1883 {
AzureIoTClient 56:8704100b3b54 1884 result = RESULT_OK;
AzureIoTClient 56:8704100b3b54 1885 }
AzureIoTClient 56:8704100b3b54 1886 else
AzureIoTClient 56:8704100b3b54 1887 {
AzureIoTClient 56:8704100b3b54 1888 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_039: [`on_twin_state_update_callback` and `context` shall be saved on `twin_msgr`]
AzureIoTClient 56:8704100b3b54 1889 twin_msgr->on_message_received_callback = on_twin_state_update_callback;
AzureIoTClient 56:8704100b3b54 1890 twin_msgr->on_message_received_context = context;
AzureIoTClient 56:8704100b3b54 1891 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_040: [twin_messenger_subscribe() shall change `twin_msgr->subscription_state` to TWIN_SUBSCRIPTION_STATE_GET_COMPLETE_PROPERTIES]
AzureIoTClient 56:8704100b3b54 1892 twin_msgr->subscription_state = TWIN_SUBSCRIPTION_STATE_GET_COMPLETE_PROPERTIES;
AzureIoTClient 56:8704100b3b54 1893 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_041: [If no failures occurr, twin_messenger_subscribe() shall return 0]
AzureIoTClient 56:8704100b3b54 1894 result = RESULT_OK;
AzureIoTClient 56:8704100b3b54 1895 }
AzureIoTClient 56:8704100b3b54 1896 }
AzureIoTClient 39:e98d5df6dc74 1897
AzureIoTClient 56:8704100b3b54 1898 return result;
AzureIoTClient 39:e98d5df6dc74 1899 }
AzureIoTClient 39:e98d5df6dc74 1900
AzureIoTClient 39:e98d5df6dc74 1901 int twin_messenger_unsubscribe(TWIN_MESSENGER_HANDLE twin_msgr_handle)
AzureIoTClient 39:e98d5df6dc74 1902 {
AzureIoTClient 56:8704100b3b54 1903 int result;
AzureIoTClient 39:e98d5df6dc74 1904
AzureIoTClient 56:8704100b3b54 1905 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_042: [If `twin_msgr_handle` is NULL, twin_messenger_unsubscribe() shall fail and return a non-zero value]
AzureIoTClient 56:8704100b3b54 1906 if (twin_msgr_handle == NULL)
AzureIoTClient 56:8704100b3b54 1907 {
AzureIoTClient 56:8704100b3b54 1908 LogError("Invalid argument (twin_msgr_handle is NULL)");
AzureIoTClient 56:8704100b3b54 1909 result = __FAILURE__;
AzureIoTClient 56:8704100b3b54 1910 }
AzureIoTClient 56:8704100b3b54 1911 else
AzureIoTClient 56:8704100b3b54 1912 {
AzureIoTClient 56:8704100b3b54 1913 TWIN_MESSENGER_INSTANCE* twin_msgr = (TWIN_MESSENGER_INSTANCE*)twin_msgr_handle;
AzureIoTClient 56:8704100b3b54 1914 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_043: [twin_messenger_subscribe() shall change `twin_msgr->subscription_state` to TWIN_SUBSCRIPTION_STATE_UNSUBSCRIBE]
AzureIoTClient 56:8704100b3b54 1915 twin_msgr->subscription_state = TWIN_SUBSCRIPTION_STATE_UNSUBSCRIBE;
AzureIoTClient 56:8704100b3b54 1916 twin_msgr->on_message_received_callback = NULL;
AzureIoTClient 56:8704100b3b54 1917 twin_msgr->on_message_received_context = NULL;
AzureIoTClient 56:8704100b3b54 1918 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_044: [If no failures occurr, twin_messenger_unsubscribe() shall return zero]
AzureIoTClient 56:8704100b3b54 1919 result = RESULT_OK;
AzureIoTClient 56:8704100b3b54 1920 }
AzureIoTClient 39:e98d5df6dc74 1921
AzureIoTClient 56:8704100b3b54 1922 return result;
AzureIoTClient 39:e98d5df6dc74 1923 }
AzureIoTClient 39:e98d5df6dc74 1924
AzureIoTClient 39:e98d5df6dc74 1925 int twin_messenger_get_send_status(TWIN_MESSENGER_HANDLE twin_msgr_handle, TWIN_MESSENGER_SEND_STATUS* send_status)
AzureIoTClient 39:e98d5df6dc74 1926 {
AzureIoTClient 56:8704100b3b54 1927 int result;
AzureIoTClient 39:e98d5df6dc74 1928
AzureIoTClient 56:8704100b3b54 1929 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_033: [If `twin_msgr_handle` or `send_status` are NULL, twin_messenger_get_send_status() shall fail and return a non-zero value]
AzureIoTClient 56:8704100b3b54 1930 if (twin_msgr_handle == NULL || send_status == NULL)
AzureIoTClient 56:8704100b3b54 1931 {
AzureIoTClient 56:8704100b3b54 1932 LogError("Invalid argument (twin_msgr_handle=%p, send_status=%p)", twin_msgr_handle, send_status);
AzureIoTClient 56:8704100b3b54 1933 result = __FAILURE__;
AzureIoTClient 56:8704100b3b54 1934 }
AzureIoTClient 56:8704100b3b54 1935 else
AzureIoTClient 56:8704100b3b54 1936 {
AzureIoTClient 56:8704100b3b54 1937 TWIN_MESSENGER_INSTANCE* twin_msgr = (TWIN_MESSENGER_INSTANCE*)twin_msgr_handle;
AzureIoTClient 56:8704100b3b54 1938 TWIN_OPERATION_TYPE twin_op_type = TWIN_OPERATION_TYPE_PATCH;
AzureIoTClient 39:e98d5df6dc74 1939
AzureIoTClient 56:8704100b3b54 1940 if (singlylinkedlist_get_head_item(twin_msgr->pending_patches) != NULL ||
AzureIoTClient 56:8704100b3b54 1941 singlylinkedlist_find(twin_msgr->operations, find_twin_operation_by_type, &twin_op_type))
AzureIoTClient 56:8704100b3b54 1942 {
AzureIoTClient 56:8704100b3b54 1943 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_034: [If `twin_msgr->pending_patches` or `twin_msgr->operations` have any TWIN patch requests, send_status shall be set to TWIN_MESSENGER_SEND_STATUS_BUSY]
AzureIoTClient 56:8704100b3b54 1944 *send_status = TWIN_MESSENGER_SEND_STATUS_BUSY;
AzureIoTClient 56:8704100b3b54 1945 }
AzureIoTClient 56:8704100b3b54 1946 else
AzureIoTClient 56:8704100b3b54 1947 {
AzureIoTClient 56:8704100b3b54 1948 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_035: [Otherwise, send_status shall be set to TWIN_MESSENGER_SEND_STATUS_IDLE]
AzureIoTClient 56:8704100b3b54 1949 *send_status = TWIN_MESSENGER_SEND_STATUS_IDLE;
AzureIoTClient 56:8704100b3b54 1950 }
AzureIoTClient 39:e98d5df6dc74 1951
AzureIoTClient 56:8704100b3b54 1952 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_036: [If no failures occur, twin_messenger_get_send_status() shall return 0]
AzureIoTClient 56:8704100b3b54 1953 result = RESULT_OK;
AzureIoTClient 56:8704100b3b54 1954 }
AzureIoTClient 39:e98d5df6dc74 1955
AzureIoTClient 56:8704100b3b54 1956 return result;
AzureIoTClient 39:e98d5df6dc74 1957 }
AzureIoTClient 39:e98d5df6dc74 1958
AzureIoTClient 39:e98d5df6dc74 1959 int twin_messenger_start(TWIN_MESSENGER_HANDLE twin_msgr_handle, SESSION_HANDLE session_handle)
AzureIoTClient 39:e98d5df6dc74 1960 {
AzureIoTClient 56:8704100b3b54 1961 int result;
AzureIoTClient 39:e98d5df6dc74 1962
AzureIoTClient 56:8704100b3b54 1963 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_045: [If `twin_msgr_handle` or `session_handle` are NULL, twin_messenger_start() shall fail and return a non-zero value]
AzureIoTClient 56:8704100b3b54 1964 if (twin_msgr_handle == NULL || session_handle == NULL)
AzureIoTClient 56:8704100b3b54 1965 {
AzureIoTClient 56:8704100b3b54 1966 LogError("Invalid argument (twin_msgr_handle=%p, session_handle=%p)", twin_msgr_handle, session_handle);
AzureIoTClient 56:8704100b3b54 1967 result = __FAILURE__;
AzureIoTClient 56:8704100b3b54 1968 }
AzureIoTClient 56:8704100b3b54 1969 else
AzureIoTClient 56:8704100b3b54 1970 {
AzureIoTClient 56:8704100b3b54 1971 TWIN_MESSENGER_INSTANCE* twin_msgr = (TWIN_MESSENGER_INSTANCE*)twin_msgr_handle;
AzureIoTClient 39:e98d5df6dc74 1972
AzureIoTClient 56:8704100b3b54 1973 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_048: [If no failures occurr, `twin_msgr->state` shall be set to TWIN_MESSENGER_STATE_STARTING, and `twin_msgr->on_state_changed_callback` invoked if provided]
AzureIoTClient 56:8704100b3b54 1974 update_state(twin_msgr, TWIN_MESSENGER_STATE_STARTING);
AzureIoTClient 39:e98d5df6dc74 1975
AzureIoTClient 56:8704100b3b54 1976 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_046: [amqp_messenger_start() shall be invoked passing `twin_msgr->amqp_msgr` and `session_handle`]
AzureIoTClient 56:8704100b3b54 1977 if (amqp_messenger_start(twin_msgr->amqp_msgr, session_handle) != 0)
AzureIoTClient 56:8704100b3b54 1978 {
AzureIoTClient 56:8704100b3b54 1979 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_047: [If amqp_messenger_start() fails, twin_messenger_start() fail and return a non-zero value]
AzureIoTClient 56:8704100b3b54 1980 LogError("Failed starting the AMQP messenger (%s)", twin_msgr->device_id);
AzureIoTClient 56:8704100b3b54 1981 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_049: [If any failures occurr, `twin_msgr->state` shall be set to TWIN_MESSENGER_STATE_ERROR, and `twin_msgr->on_state_changed_callback` invoked if provided]
AzureIoTClient 56:8704100b3b54 1982 update_state(twin_msgr, TWIN_MESSENGER_STATE_ERROR);
AzureIoTClient 56:8704100b3b54 1983 result = __FAILURE__;
AzureIoTClient 56:8704100b3b54 1984 }
AzureIoTClient 56:8704100b3b54 1985 else
AzureIoTClient 56:8704100b3b54 1986 {
AzureIoTClient 56:8704100b3b54 1987 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_050: [If no failures occurr, twin_messenger_start() shall return 0]
AzureIoTClient 56:8704100b3b54 1988 result = RESULT_OK;
AzureIoTClient 56:8704100b3b54 1989 }
AzureIoTClient 56:8704100b3b54 1990 }
AzureIoTClient 39:e98d5df6dc74 1991
AzureIoTClient 56:8704100b3b54 1992 return result;
AzureIoTClient 39:e98d5df6dc74 1993 }
AzureIoTClient 39:e98d5df6dc74 1994
AzureIoTClient 39:e98d5df6dc74 1995 int twin_messenger_stop(TWIN_MESSENGER_HANDLE twin_msgr_handle)
AzureIoTClient 39:e98d5df6dc74 1996 {
AzureIoTClient 56:8704100b3b54 1997 int result;
AzureIoTClient 39:e98d5df6dc74 1998
AzureIoTClient 56:8704100b3b54 1999 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_051: [If `twin_msgr_handle` is NULL, twin_messenger_stop() shall fail and return a non-zero value]
AzureIoTClient 56:8704100b3b54 2000 if (twin_msgr_handle == NULL)
AzureIoTClient 56:8704100b3b54 2001 {
AzureIoTClient 56:8704100b3b54 2002 LogError("Invalid argument (twin_msgr_handle is NULL)");
AzureIoTClient 56:8704100b3b54 2003 result = __FAILURE__;
AzureIoTClient 56:8704100b3b54 2004 }
AzureIoTClient 56:8704100b3b54 2005 else
AzureIoTClient 56:8704100b3b54 2006 {
AzureIoTClient 56:8704100b3b54 2007 TWIN_MESSENGER_INSTANCE* twin_msgr = (TWIN_MESSENGER_INSTANCE*)twin_msgr_handle;
AzureIoTClient 39:e98d5df6dc74 2008
AzureIoTClient 56:8704100b3b54 2009 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_054: [`twin_msgr->state` shall be set to TWIN_MESSENGER_STATE_STOPPING, and `twin_msgr->on_state_changed_callback` invoked if provided]
AzureIoTClient 56:8704100b3b54 2010 update_state(twin_msgr, TWIN_MESSENGER_STATE_STOPPING);
AzureIoTClient 39:e98d5df6dc74 2011
AzureIoTClient 56:8704100b3b54 2012 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_052: [amqp_messenger_stop() shall be invoked passing `twin_msgr->amqp_msgr`]
AzureIoTClient 56:8704100b3b54 2013 if (amqp_messenger_stop(twin_msgr->amqp_msgr) != 0)
AzureIoTClient 56:8704100b3b54 2014 {
AzureIoTClient 56:8704100b3b54 2015 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_053: [If amqp_messenger_stop() fails, twin_messenger_stop() fail and return a non-zero value]
AzureIoTClient 56:8704100b3b54 2016 LogError("Failed stopping the AMQP messenger (%s)", twin_msgr->device_id);
AzureIoTClient 56:8704100b3b54 2017 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_055: [If any failures occurr, `twin_msgr->state` shall be set to TWIN_MESSENGER_STATE_ERROR, and `twin_msgr->on_state_changed_callback` invoked if provided]
AzureIoTClient 56:8704100b3b54 2018 update_state(twin_msgr, TWIN_MESSENGER_STATE_ERROR);
AzureIoTClient 56:8704100b3b54 2019 result = __FAILURE__;
AzureIoTClient 56:8704100b3b54 2020 }
AzureIoTClient 56:8704100b3b54 2021 else
AzureIoTClient 56:8704100b3b54 2022 {
AzureIoTClient 56:8704100b3b54 2023 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_056: [If no failures occurr, twin_messenger_stop() shall return 0]
AzureIoTClient 56:8704100b3b54 2024 result = RESULT_OK;
AzureIoTClient 56:8704100b3b54 2025 }
AzureIoTClient 56:8704100b3b54 2026 }
AzureIoTClient 39:e98d5df6dc74 2027
AzureIoTClient 56:8704100b3b54 2028 return result;
AzureIoTClient 39:e98d5df6dc74 2029 }
AzureIoTClient 39:e98d5df6dc74 2030
AzureIoTClient 39:e98d5df6dc74 2031 void twin_messenger_do_work(TWIN_MESSENGER_HANDLE twin_msgr_handle)
AzureIoTClient 39:e98d5df6dc74 2032 {
AzureIoTClient 56:8704100b3b54 2033 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_057: [If `twin_msgr_handle` is NULL, twin_messenger_do_work() shall return immediately]
AzureIoTClient 56:8704100b3b54 2034 if (twin_msgr_handle != NULL)
AzureIoTClient 56:8704100b3b54 2035 {
AzureIoTClient 56:8704100b3b54 2036 TWIN_MESSENGER_INSTANCE* twin_msgr = (TWIN_MESSENGER_INSTANCE*)twin_msgr_handle;
AzureIoTClient 39:e98d5df6dc74 2037
AzureIoTClient 56:8704100b3b54 2038 if (twin_msgr->state == TWIN_MESSENGER_STATE_STARTED)
AzureIoTClient 56:8704100b3b54 2039 {
AzureIoTClient 56:8704100b3b54 2040 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_058: [If `twin_msgr->state` is TWIN_MESSENGER_STATE_STARTED, twin_messenger_do_work() shall send the PATCHES in `twin_msgr->pending_patches`, removing them from the list]
AzureIoTClient 56:8704100b3b54 2041 (void)singlylinkedlist_remove_if(twin_msgr->pending_patches, send_pending_twin_patch, (const void*)twin_msgr);
AzureIoTClient 39:e98d5df6dc74 2042
AzureIoTClient 56:8704100b3b54 2043 process_twin_subscription(twin_msgr);
AzureIoTClient 56:8704100b3b54 2044 }
AzureIoTClient 39:e98d5df6dc74 2045
AzureIoTClient 56:8704100b3b54 2046 process_timeouts(twin_msgr);
AzureIoTClient 39:e98d5df6dc74 2047
AzureIoTClient 56:8704100b3b54 2048 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_083: [twin_messenger_do_work() shall invoke amqp_messenger_do_work() passing `twin_msgr->amqp_msgr`]
AzureIoTClient 56:8704100b3b54 2049 amqp_messenger_do_work(twin_msgr->amqp_msgr);
AzureIoTClient 56:8704100b3b54 2050 }
AzureIoTClient 39:e98d5df6dc74 2051 }
AzureIoTClient 39:e98d5df6dc74 2052
AzureIoTClient 39:e98d5df6dc74 2053 void twin_messenger_destroy(TWIN_MESSENGER_HANDLE twin_msgr_handle)
AzureIoTClient 39:e98d5df6dc74 2054 {
AzureIoTClient 56:8704100b3b54 2055 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_098: [If `twin_msgr_handle` is NULL, twin_messenger_destroy() shall return immediately]
AzureIoTClient 56:8704100b3b54 2056 if (twin_msgr_handle == NULL)
AzureIoTClient 56:8704100b3b54 2057 {
AzureIoTClient 56:8704100b3b54 2058 LogError("Invalid argument (twin_msgr_handle is NULL)");
AzureIoTClient 56:8704100b3b54 2059 }
AzureIoTClient 56:8704100b3b54 2060 else
AzureIoTClient 56:8704100b3b54 2061 {
AzureIoTClient 56:8704100b3b54 2062 internal_twin_messenger_destroy((TWIN_MESSENGER_INSTANCE*)twin_msgr_handle);
AzureIoTClient 56:8704100b3b54 2063 }
AzureIoTClient 39:e98d5df6dc74 2064 }
AzureIoTClient 39:e98d5df6dc74 2065
AzureIoTClient 39:e98d5df6dc74 2066 int twin_messenger_set_option(TWIN_MESSENGER_HANDLE twin_msgr_handle, const char* name, void* value)
AzureIoTClient 39:e98d5df6dc74 2067 {
AzureIoTClient 56:8704100b3b54 2068 int result;
AzureIoTClient 39:e98d5df6dc74 2069
AzureIoTClient 56:8704100b3b54 2070 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_103: [If `twin_msgr_handle` or `name` or `value` are NULL, twin_messenger_set_option() shall fail and return a non-zero value]
AzureIoTClient 56:8704100b3b54 2071 if (twin_msgr_handle == NULL || name == NULL || value == NULL)
AzureIoTClient 56:8704100b3b54 2072 {
AzureIoTClient 56:8704100b3b54 2073 LogError("Invalid argument (twin_msgr_handle=%p, name=%p, value=%p)", twin_msgr_handle, name, value);
AzureIoTClient 56:8704100b3b54 2074 result = __FAILURE__;
AzureIoTClient 56:8704100b3b54 2075 }
AzureIoTClient 56:8704100b3b54 2076 else
AzureIoTClient 56:8704100b3b54 2077 {
AzureIoTClient 56:8704100b3b54 2078 TWIN_MESSENGER_INSTANCE* twin_msgr = (TWIN_MESSENGER_INSTANCE*)twin_msgr_handle;
AzureIoTClient 39:e98d5df6dc74 2079
AzureIoTClient 56:8704100b3b54 2080 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_104: [amqp_messenger_set_option() shall be invoked passing `name` and `option`]
AzureIoTClient 56:8704100b3b54 2081 if (amqp_messenger_set_option(twin_msgr->amqp_msgr, name, value) != RESULT_OK)
AzureIoTClient 56:8704100b3b54 2082 {
AzureIoTClient 56:8704100b3b54 2083 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_105: [If amqp_messenger_set_option() fails, twin_messenger_set_option() shall fail and return a non-zero value]
AzureIoTClient 56:8704100b3b54 2084 LogError("Failed setting TWIN messenger option (%s, %s)", twin_msgr->device_id, name);
AzureIoTClient 56:8704100b3b54 2085 result = __FAILURE__;
AzureIoTClient 56:8704100b3b54 2086 }
AzureIoTClient 56:8704100b3b54 2087 else
AzureIoTClient 56:8704100b3b54 2088 {
AzureIoTClient 56:8704100b3b54 2089 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_106: [If no errors occur, twin_messenger_set_option shall return zero]
AzureIoTClient 56:8704100b3b54 2090 result = RESULT_OK;
AzureIoTClient 56:8704100b3b54 2091 }
AzureIoTClient 56:8704100b3b54 2092 }
AzureIoTClient 39:e98d5df6dc74 2093
AzureIoTClient 56:8704100b3b54 2094 return result;
AzureIoTClient 39:e98d5df6dc74 2095 }
AzureIoTClient 39:e98d5df6dc74 2096
AzureIoTClient 39:e98d5df6dc74 2097 OPTIONHANDLER_HANDLE twin_messenger_retrieve_options(TWIN_MESSENGER_HANDLE twin_msgr_handle)
AzureIoTClient 39:e98d5df6dc74 2098 {
AzureIoTClient 56:8704100b3b54 2099 OPTIONHANDLER_HANDLE result;
AzureIoTClient 39:e98d5df6dc74 2100
AzureIoTClient 56:8704100b3b54 2101 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_107: [If `twin_msgr_handle` is NULL, twin_messenger_retrieve_options shall fail and return NULL]
AzureIoTClient 56:8704100b3b54 2102 if (twin_msgr_handle == NULL)
AzureIoTClient 56:8704100b3b54 2103 {
AzureIoTClient 56:8704100b3b54 2104 LogError("Invalid argument (twin_msgr_handle is NULL)");
AzureIoTClient 56:8704100b3b54 2105 result = NULL;
AzureIoTClient 56:8704100b3b54 2106 }
AzureIoTClient 56:8704100b3b54 2107 else
AzureIoTClient 56:8704100b3b54 2108 {
AzureIoTClient 56:8704100b3b54 2109 TWIN_MESSENGER_INSTANCE* twin_msgr = (TWIN_MESSENGER_INSTANCE*)twin_msgr_handle;
AzureIoTClient 39:e98d5df6dc74 2110
AzureIoTClient 56:8704100b3b54 2111 // Codes_IOTHUBTRANSPORT_AMQP_TWIN_MESSENGER_09_108: [twin_messenger_retrieve_options() shall return the result of amqp_messenger_retrieve_options()]
AzureIoTClient 56:8704100b3b54 2112 if ((result = amqp_messenger_retrieve_options(twin_msgr->amqp_msgr)) == NULL)
AzureIoTClient 56:8704100b3b54 2113 {
AzureIoTClient 56:8704100b3b54 2114 LogError("Failed TWIN messenger options (%s)", twin_msgr->device_id);
AzureIoTClient 56:8704100b3b54 2115 }
AzureIoTClient 56:8704100b3b54 2116 }
AzureIoTClient 39:e98d5df6dc74 2117
AzureIoTClient 56:8704100b3b54 2118 return result;
AzureIoTClient 50:f3a92c6c6534 2119 }