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:
Mon Mar 05 17:39:14 2018 -0800
Revision:
50:f3a92c6c6534
Parent:
39:e98d5df6dc74
Child:
51:269e65571b39
1.2.0

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