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:
Fri Aug 11 14:01:56 2017 -0700
Revision:
39:e98d5df6dc74
Child:
50:f3a92c6c6534
1.1.21

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