Microsoft Azure IoTHub client AMQP transport

Dependents:   sht15_remote_monitoring RobotArmDemo iothub_client_sample_amqp iothub_client_sample_amqp ... more

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

Committer:
AzureIoTClient
Date:
Thu Apr 06 14:10:35 2017 -0700
Revision:
32:babfd49032ff
Parent:
31:adadaef857c1
Child:
34:51d158b409d2
1.1.11

Who changed what in which revision?

UserRevisionLine numberNew contents of line
AzureIoTClient 25:63f7d371c030 1 // Copyright (c) Microsoft. All rights reserved.
AzureIoTClient 25:63f7d371c030 2 // Licensed under the MIT license. See LICENSE file in the project root for full license information.
AzureIoTClient 25:63f7d371c030 3
AzureIoTClient 25:63f7d371c030 4 #include <stdlib.h>
AzureIoTClient 25:63f7d371c030 5 #include <stdint.h>
AzureIoTClient 31:adadaef857c1 6 #include <stdbool.h>
AzureIoTClient 25:63f7d371c030 7 #include <time.h>
AzureIoTClient 25:63f7d371c030 8 #include <limits.h>
AzureIoTClient 29:7e8852b14e3b 9 #include "azure_c_shared_utility/optimize_size.h"
AzureIoTClient 25:63f7d371c030 10 #include "azure_c_shared_utility/agenttime.h"
AzureIoTClient 25:63f7d371c030 11 #include "azure_c_shared_utility/gballoc.h"
AzureIoTClient 25:63f7d371c030 12 #include "azure_c_shared_utility/crt_abstractions.h"
AzureIoTClient 30:20a85b733111 13 #include "azure_c_shared_utility/singlylinkedlist.h"
AzureIoTClient 25:63f7d371c030 14 #include "azure_c_shared_utility/doublylinkedlist.h"
AzureIoTClient 25:63f7d371c030 15 #include "azure_c_shared_utility/xlogging.h"
AzureIoTClient 25:63f7d371c030 16 #include "azure_c_shared_utility/platform.h"
AzureIoTClient 25:63f7d371c030 17 #include "azure_c_shared_utility/strings.h"
AzureIoTClient 25:63f7d371c030 18 #include "azure_c_shared_utility/urlencode.h"
AzureIoTClient 25:63f7d371c030 19 #include "azure_c_shared_utility/tlsio.h"
AzureIoTClient 30:20a85b733111 20 #include "azure_c_shared_utility/optionhandler.h"
AzureIoTClient 31:adadaef857c1 21 #include "azure_c_shared_utility/shared_util_options.h"
AzureIoTClient 31:adadaef857c1 22 #include "azure_c_shared_utility/macro_utils.h"
AzureIoTClient 25:63f7d371c030 23
AzureIoTClient 25:63f7d371c030 24 #include "azure_uamqp_c/cbs.h"
AzureIoTClient 30:20a85b733111 25 #include "azure_uamqp_c/session.h"
AzureIoTClient 25:63f7d371c030 26 #include "azure_uamqp_c/message.h"
AzureIoTClient 25:63f7d371c030 27 #include "azure_uamqp_c/messaging.h"
AzureIoTClient 25:63f7d371c030 28
AzureIoTClient 25:63f7d371c030 29 #include "iothub_client_ll.h"
AzureIoTClient 25:63f7d371c030 30 #include "iothub_client_options.h"
AzureIoTClient 25:63f7d371c030 31 #include "iothub_client_private.h"
AzureIoTClient 25:63f7d371c030 32 #ifdef WIP_C2D_METHODS_AMQP /* This feature is WIP, do not use yet */
AzureIoTClient 25:63f7d371c030 33 #include "iothubtransportamqp_methods.h"
AzureIoTClient 25:63f7d371c030 34 #endif
AzureIoTClient 32:babfd49032ff 35 #include "iothub_client_retry_control.h"
AzureIoTClient 25:63f7d371c030 36 #include "iothubtransport_amqp_common.h"
AzureIoTClient 30:20a85b733111 37 #include "iothubtransport_amqp_connection.h"
AzureIoTClient 30:20a85b733111 38 #include "iothubtransport_amqp_device.h"
AzureIoTClient 25:63f7d371c030 39 #include "iothub_client_version.h"
AzureIoTClient 25:63f7d371c030 40
AzureIoTClient 30:20a85b733111 41 #define RESULT_OK 0
AzureIoTClient 30:20a85b733111 42 #define INDEFINITE_TIME ((time_t)(-1))
AzureIoTClient 30:20a85b733111 43 #define DEFAULT_CBS_REQUEST_TIMEOUT_SECS 30
AzureIoTClient 30:20a85b733111 44 #define DEFAULT_DEVICE_STATE_CHANGE_TIMEOUT_SECS 60
AzureIoTClient 30:20a85b733111 45 #define DEFAULT_EVENT_SEND_TIMEOUT_SECS 300
AzureIoTClient 30:20a85b733111 46 #define DEFAULT_SAS_TOKEN_LIFETIME_SECS 3600
AzureIoTClient 30:20a85b733111 47 #define DEFAULT_SAS_TOKEN_REFRESH_TIME_SECS 1800
AzureIoTClient 30:20a85b733111 48 #define MAX_NUMBER_OF_DEVICE_FAILURES 5
AzureIoTClient 32:babfd49032ff 49 #define DEFAULT_RETRY_POLICY IOTHUB_CLIENT_RETRY_EXPONENTIAL_BACKOFF_WITH_JITTER
AzureIoTClient 32:babfd49032ff 50 // DEFAULT_MAX_RETRY_TIME_IN_SECS = 0 means infinite retry.
AzureIoTClient 32:babfd49032ff 51 #define DEFAULT_MAX_RETRY_TIME_IN_SECS 0
AzureIoTClient 25:63f7d371c030 52
AzureIoTClient 25:63f7d371c030 53
AzureIoTClient 30:20a85b733111 54 // ---------- Data Definitions ---------- //
AzureIoTClient 25:63f7d371c030 55
AzureIoTClient 30:20a85b733111 56 typedef enum AMQP_TRANSPORT_AUTHENTICATION_MODE_TAG
AzureIoTClient 25:63f7d371c030 57 {
AzureIoTClient 30:20a85b733111 58 AMQP_TRANSPORT_AUTHENTICATION_MODE_NOT_SET,
AzureIoTClient 30:20a85b733111 59 AMQP_TRANSPORT_AUTHENTICATION_MODE_CBS,
AzureIoTClient 30:20a85b733111 60 AMQP_TRANSPORT_AUTHENTICATION_MODE_X509
AzureIoTClient 30:20a85b733111 61 } AMQP_TRANSPORT_AUTHENTICATION_MODE;
AzureIoTClient 32:babfd49032ff 62 \
AzureIoTClient 32:babfd49032ff 63
AzureIoTClient 32:babfd49032ff 64 #define AMQP_TRANSPORT_STATE_STRINGS \
AzureIoTClient 32:babfd49032ff 65 AMQP_TRANSPORT_STATE_NOT_CONNECTED, \
AzureIoTClient 32:babfd49032ff 66 AMQP_TRANSPORT_STATE_CONNECTING, \
AzureIoTClient 32:babfd49032ff 67 AMQP_TRANSPORT_STATE_CONNECTED, \
AzureIoTClient 32:babfd49032ff 68 AMQP_TRANSPORT_STATE_RECONNECTION_REQUIRED, \
AzureIoTClient 32:babfd49032ff 69 AMQP_TRANSPORT_STATE_READY_FOR_RECONNECTION, \
AzureIoTClient 32:babfd49032ff 70 AMQP_TRANSPORT_STATE_RECONNECTING, \
AzureIoTClient 32:babfd49032ff 71 AMQP_TRANSPORT_STATE_BEING_DESTROYED
AzureIoTClient 32:babfd49032ff 72
AzureIoTClient 32:babfd49032ff 73 DEFINE_LOCAL_ENUM(AMQP_TRANSPORT_STATE, AMQP_TRANSPORT_STATE_STRINGS);
AzureIoTClient 32:babfd49032ff 74
AzureIoTClient 25:63f7d371c030 75
AzureIoTClient 30:20a85b733111 76 typedef struct AMQP_TRANSPORT_INSTANCE_TAG
AzureIoTClient 30:20a85b733111 77 {
AzureIoTClient 30:20a85b733111 78 STRING_HANDLE iothub_host_fqdn; // FQDN of the IoT Hub.
AzureIoTClient 30:20a85b733111 79 XIO_HANDLE tls_io; // TSL I/O transport.
AzureIoTClient 30:20a85b733111 80 AMQP_GET_IO_TRANSPORT underlying_io_transport_provider; // Pointer to the function that creates the TLS I/O (internal use only).
AzureIoTClient 30:20a85b733111 81 AMQP_CONNECTION_HANDLE amqp_connection; // Base amqp connection with service.
AzureIoTClient 30:20a85b733111 82 AMQP_CONNECTION_STATE amqp_connection_state; // Current state of the amqp_connection.
AzureIoTClient 30:20a85b733111 83 AMQP_TRANSPORT_AUTHENTICATION_MODE preferred_authentication_mode; // Used to avoid registered devices using different authentication modes.
AzureIoTClient 30:20a85b733111 84 SINGLYLINKEDLIST_HANDLE registered_devices; // List of devices currently registered in this transport.
AzureIoTClient 30:20a85b733111 85 bool is_trace_on; // Turns logging on and off.
AzureIoTClient 30:20a85b733111 86 OPTIONHANDLER_HANDLE saved_tls_options; // Here are the options from the xio layer if any is saved.
AzureIoTClient 32:babfd49032ff 87 AMQP_TRANSPORT_STATE state; // Current state of the transport.
AzureIoTClient 32:babfd49032ff 88 RETRY_CONTROL_HANDLE connection_retry_control; // Controls when the re-connection attempt should occur.
AzureIoTClient 31:adadaef857c1 89
AzureIoTClient 31:adadaef857c1 90 char* http_proxy_hostname;
AzureIoTClient 31:adadaef857c1 91 int http_proxy_port;
AzureIoTClient 31:adadaef857c1 92 char* http_proxy_username;
AzureIoTClient 31:adadaef857c1 93 char* http_proxy_password;
AzureIoTClient 30:20a85b733111 94
AzureIoTClient 30:20a85b733111 95 size_t option_sas_token_lifetime_secs; // Device-specific option.
AzureIoTClient 30:20a85b733111 96 size_t option_sas_token_refresh_time_secs; // Device-specific option.
AzureIoTClient 30:20a85b733111 97 size_t option_cbs_request_timeout_secs; // Device-specific option.
AzureIoTClient 30:20a85b733111 98 size_t option_send_event_timeout_secs; // Device-specific option.
AzureIoTClient 25:63f7d371c030 99 } AMQP_TRANSPORT_INSTANCE;
AzureIoTClient 25:63f7d371c030 100
AzureIoTClient 30:20a85b733111 101 typedef struct AMQP_TRANSPORT_DEVICE_INSTANCE_TAG
AzureIoTClient 25:63f7d371c030 102 {
AzureIoTClient 30:20a85b733111 103 STRING_HANDLE device_id; // Identity of the device.
AzureIoTClient 30:20a85b733111 104 DEVICE_HANDLE device_handle; // Logic unit that performs authentication, messaging, etc.
AzureIoTClient 30:20a85b733111 105 IOTHUB_CLIENT_LL_HANDLE iothub_client_handle; // Saved reference to the IoTHub LL Client.
AzureIoTClient 30:20a85b733111 106 AMQP_TRANSPORT_INSTANCE* transport_instance; // Saved reference to the transport the device is registered on.
AzureIoTClient 30:20a85b733111 107 PDLIST_ENTRY waiting_to_send; // List of events waiting to be sent to the iot hub (i.e., haven't been processed by the transport yet).
AzureIoTClient 30:20a85b733111 108 DEVICE_STATE device_state; // Current state of the device_handle instance.
AzureIoTClient 30:20a85b733111 109 size_t number_of_previous_failures; // Number of times the device has failed in sequence; this value is reset to 0 if device succeeds to authenticate, send and/or recv messages.
AzureIoTClient 30:20a85b733111 110 size_t number_of_send_event_complete_failures; // Number of times on_event_send_complete was called in row with an error.
AzureIoTClient 30:20a85b733111 111 time_t time_of_last_state_change; // Time the device_handle last changed state; used to track timeouts of device_start_async and device_stop.
AzureIoTClient 30:20a85b733111 112 unsigned int max_state_change_timeout_secs; // Maximum number of seconds allowed for device_handle to complete start and stop state changes.
AzureIoTClient 25:63f7d371c030 113 #ifdef WIP_C2D_METHODS_AMQP /* This feature is WIP, do not use yet */
AzureIoTClient 25:63f7d371c030 114 // the methods portion
AzureIoTClient 30:20a85b733111 115 IOTHUBTRANSPORT_AMQP_METHODS_HANDLE methods_handle; // Handle to instance of module that deals with device methods for AMQP.
AzureIoTClient 25:63f7d371c030 116 // is subscription for methods needed?
AzureIoTClient 30:20a85b733111 117 bool subscribe_methods_needed; // Indicates if should subscribe for device methods.
AzureIoTClient 25:63f7d371c030 118 // is the transport subscribed for methods?
AzureIoTClient 30:20a85b733111 119 bool subscribed_for_methods; // Indicates if device is subscribed for device methods.
AzureIoTClient 25:63f7d371c030 120 #endif
AzureIoTClient 30:20a85b733111 121 } AMQP_TRANSPORT_DEVICE_INSTANCE;
AzureIoTClient 25:63f7d371c030 122
AzureIoTClient 30:20a85b733111 123 typedef struct MESSAGE_DISPOSITION_CONTEXT_TAG
AzureIoTClient 30:20a85b733111 124 {
AzureIoTClient 30:20a85b733111 125 AMQP_TRANSPORT_DEVICE_INSTANCE* device_state;
AzureIoTClient 30:20a85b733111 126 char* link_name;
AzureIoTClient 30:20a85b733111 127 delivery_number message_id;
AzureIoTClient 30:20a85b733111 128 } MESSAGE_DISPOSITION_CONTEXT;
AzureIoTClient 25:63f7d371c030 129
AzureIoTClient 30:20a85b733111 130 // ---------- General Helpers ---------- //
AzureIoTClient 25:63f7d371c030 131
AzureIoTClient 31:adadaef857c1 132 static void free_proxy_data(AMQP_TRANSPORT_INSTANCE* amqp_transport_instance)
AzureIoTClient 31:adadaef857c1 133 {
AzureIoTClient 31:adadaef857c1 134 if (amqp_transport_instance->http_proxy_hostname != NULL)
AzureIoTClient 31:adadaef857c1 135 {
AzureIoTClient 31:adadaef857c1 136 free(amqp_transport_instance->http_proxy_hostname);
AzureIoTClient 31:adadaef857c1 137 amqp_transport_instance->http_proxy_hostname = NULL;
AzureIoTClient 31:adadaef857c1 138 }
AzureIoTClient 31:adadaef857c1 139
AzureIoTClient 31:adadaef857c1 140 if (amqp_transport_instance->http_proxy_username != NULL)
AzureIoTClient 31:adadaef857c1 141 {
AzureIoTClient 31:adadaef857c1 142 free(amqp_transport_instance->http_proxy_username);
AzureIoTClient 31:adadaef857c1 143 amqp_transport_instance->http_proxy_username = NULL;
AzureIoTClient 31:adadaef857c1 144 }
AzureIoTClient 31:adadaef857c1 145
AzureIoTClient 31:adadaef857c1 146 if (amqp_transport_instance->http_proxy_password != NULL)
AzureIoTClient 31:adadaef857c1 147 {
AzureIoTClient 31:adadaef857c1 148 free(amqp_transport_instance->http_proxy_password);
AzureIoTClient 31:adadaef857c1 149 amqp_transport_instance->http_proxy_password = NULL;
AzureIoTClient 31:adadaef857c1 150 }
AzureIoTClient 31:adadaef857c1 151 }
AzureIoTClient 31:adadaef857c1 152
AzureIoTClient 30:20a85b733111 153 static STRING_HANDLE get_target_iothub_fqdn(const IOTHUBTRANSPORT_CONFIG* config)
AzureIoTClient 25:63f7d371c030 154 {
AzureIoTClient 30:20a85b733111 155 STRING_HANDLE fqdn;
AzureIoTClient 30:20a85b733111 156
AzureIoTClient 30:20a85b733111 157 if (config->upperConfig->protocolGatewayHostName == NULL)
AzureIoTClient 30:20a85b733111 158 {
AzureIoTClient 30:20a85b733111 159 if ((fqdn = STRING_construct_sprintf("%s.%s", config->upperConfig->iotHubName, config->upperConfig->iotHubSuffix)) == NULL)
AzureIoTClient 30:20a85b733111 160 {
AzureIoTClient 30:20a85b733111 161 LogError("Failed to copy iotHubName and iotHubSuffix (STRING_construct_sprintf failed)");
AzureIoTClient 30:20a85b733111 162 }
AzureIoTClient 30:20a85b733111 163 }
AzureIoTClient 30:20a85b733111 164 else if ((fqdn = STRING_construct(config->upperConfig->protocolGatewayHostName)) == NULL)
AzureIoTClient 30:20a85b733111 165 {
AzureIoTClient 30:20a85b733111 166 LogError("Failed to copy protocolGatewayHostName (STRING_construct failed)");
AzureIoTClient 30:20a85b733111 167 }
AzureIoTClient 30:20a85b733111 168
AzureIoTClient 30:20a85b733111 169 return fqdn;
AzureIoTClient 25:63f7d371c030 170 }
AzureIoTClient 25:63f7d371c030 171
AzureIoTClient 32:babfd49032ff 172 static void update_state(AMQP_TRANSPORT_INSTANCE* transport_instance, AMQP_TRANSPORT_STATE new_state)
AzureIoTClient 32:babfd49032ff 173 {
AzureIoTClient 32:babfd49032ff 174 AMQP_TRANSPORT_STATE previous_state = transport_instance->state;
AzureIoTClient 32:babfd49032ff 175 transport_instance->state = new_state;
AzureIoTClient 32:babfd49032ff 176
AzureIoTClient 32:babfd49032ff 177 LogInfo("Transport state changed from %s to %s", ENUM_TO_STRING(AMQP_TRANSPORT_STATE, previous_state), ENUM_TO_STRING(AMQP_TRANSPORT_STATE, new_state));
AzureIoTClient 32:babfd49032ff 178 }
AzureIoTClient 32:babfd49032ff 179
AzureIoTClient 32:babfd49032ff 180 static void reset_retry_control(AMQP_TRANSPORT_DEVICE_INSTANCE* registered_device)
AzureIoTClient 32:babfd49032ff 181 {
AzureIoTClient 32:babfd49032ff 182 retry_control_reset(registered_device->transport_instance->connection_retry_control);
AzureIoTClient 32:babfd49032ff 183 }
AzureIoTClient 32:babfd49032ff 184
AzureIoTClient 25:63f7d371c030 185
AzureIoTClient 30:20a85b733111 186 // ---------- Register/Unregister Helpers ---------- //
AzureIoTClient 25:63f7d371c030 187
AzureIoTClient 30:20a85b733111 188 static void internal_destroy_amqp_device_instance(AMQP_TRANSPORT_DEVICE_INSTANCE *trdev_inst)
AzureIoTClient 25:63f7d371c030 189 {
AzureIoTClient 30:20a85b733111 190 #ifdef WIP_C2D_METHODS_AMQP /* This feature is WIP, do not use yet */
AzureIoTClient 30:20a85b733111 191 if (trdev_inst->methods_handle != NULL)
AzureIoTClient 30:20a85b733111 192 {
AzureIoTClient 30:20a85b733111 193 iothubtransportamqp_methods_destroy(trdev_inst->methods_handle);
AzureIoTClient 30:20a85b733111 194 }
AzureIoTClient 30:20a85b733111 195 #endif
AzureIoTClient 30:20a85b733111 196 if (trdev_inst->device_handle != NULL)
AzureIoTClient 30:20a85b733111 197 {
AzureIoTClient 30:20a85b733111 198 device_destroy(trdev_inst->device_handle);
AzureIoTClient 30:20a85b733111 199 }
AzureIoTClient 25:63f7d371c030 200
AzureIoTClient 30:20a85b733111 201 if (trdev_inst->device_id != NULL)
AzureIoTClient 30:20a85b733111 202 {
AzureIoTClient 30:20a85b733111 203 STRING_delete(trdev_inst->device_id);
AzureIoTClient 30:20a85b733111 204 }
AzureIoTClient 25:63f7d371c030 205
AzureIoTClient 30:20a85b733111 206 free(trdev_inst);
AzureIoTClient 25:63f7d371c030 207 }
AzureIoTClient 25:63f7d371c030 208
AzureIoTClient 30:20a85b733111 209 // @brief
AzureIoTClient 30:20a85b733111 210 // Saves the new state, if it is different than the previous one.
AzureIoTClient 30:20a85b733111 211 static void on_device_state_changed_callback(void* context, DEVICE_STATE previous_state, DEVICE_STATE new_state)
AzureIoTClient 25:63f7d371c030 212 {
AzureIoTClient 30:20a85b733111 213 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_061: [If `new_state` is the same as `previous_state`, on_device_state_changed_callback shall return]
AzureIoTClient 30:20a85b733111 214 if (context != NULL && new_state != previous_state)
AzureIoTClient 30:20a85b733111 215 {
AzureIoTClient 30:20a85b733111 216 AMQP_TRANSPORT_DEVICE_INSTANCE* registered_device = (AMQP_TRANSPORT_DEVICE_INSTANCE*)context;
AzureIoTClient 30:20a85b733111 217 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_062: [If `new_state` shall be saved into the `registered_device` instance]
AzureIoTClient 30:20a85b733111 218 registered_device->device_state = new_state;
AzureIoTClient 30:20a85b733111 219 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_063: [If `registered_device->time_of_last_state_change` shall be set using get_time()]
AzureIoTClient 30:20a85b733111 220 registered_device->time_of_last_state_change = get_time(NULL);
AzureIoTClient 31:adadaef857c1 221
AzureIoTClient 31:adadaef857c1 222 if (new_state == DEVICE_STATE_STARTED)
AzureIoTClient 31:adadaef857c1 223 {
AzureIoTClient 32:babfd49032ff 224 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_127: [If `new_state` is DEVICE_STATE_STARTED, retry_control_reset() shall be invoked passing `instance->connection_retry_control`]
AzureIoTClient 32:babfd49032ff 225 reset_retry_control(registered_device);
AzureIoTClient 32:babfd49032ff 226
AzureIoTClient 32:babfd49032ff 227 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_120: [If `new_state` is DEVICE_STATE_STARTED, IoTHubClient_LL_ConnectionStatusCallBack shall be invoked with IOTHUB_CLIENT_CONNECTION_AUTHENTICATED and IOTHUB_CLIENT_CONNECTION_OK]
AzureIoTClient 31:adadaef857c1 228 IoTHubClient_LL_ConnectionStatusCallBack(registered_device->iothub_client_handle, IOTHUB_CLIENT_CONNECTION_AUTHENTICATED, IOTHUB_CLIENT_CONNECTION_OK);
AzureIoTClient 31:adadaef857c1 229 }
AzureIoTClient 31:adadaef857c1 230 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_121: [If `new_state` is DEVICE_STATE_STOPPED, IoTHubClient_LL_ConnectionStatusCallBack shall be invoked with IOTHUB_CLIENT_CONNECTION_UNAUTHENTICATED and IOTHUB_CLIENT_CONNECTION_OK]
AzureIoTClient 31:adadaef857c1 231 else if (new_state == DEVICE_STATE_STOPPED)
AzureIoTClient 31:adadaef857c1 232 {
AzureIoTClient 31:adadaef857c1 233 IoTHubClient_LL_ConnectionStatusCallBack(registered_device->iothub_client_handle, IOTHUB_CLIENT_CONNECTION_UNAUTHENTICATED, IOTHUB_CLIENT_CONNECTION_OK);
AzureIoTClient 31:adadaef857c1 234 }
AzureIoTClient 31:adadaef857c1 235 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_122: [If `new_state` is DEVICE_STATE_ERROR_AUTH, IoTHubClient_LL_ConnectionStatusCallBack shall be invoked with IOTHUB_CLIENT_CONNECTION_UNAUTHENTICATED and IOTHUB_CLIENT_CONNECTION_BAD_CREDENTIAL]
AzureIoTClient 31:adadaef857c1 236 else if (new_state == DEVICE_STATE_ERROR_AUTH)
AzureIoTClient 31:adadaef857c1 237 {
AzureIoTClient 31:adadaef857c1 238 IoTHubClient_LL_ConnectionStatusCallBack(registered_device->iothub_client_handle, IOTHUB_CLIENT_CONNECTION_UNAUTHENTICATED, IOTHUB_CLIENT_CONNECTION_BAD_CREDENTIAL);
AzureIoTClient 31:adadaef857c1 239 }
AzureIoTClient 31:adadaef857c1 240 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_123: [If `new_state` is DEVICE_STATE_ERROR_AUTH_TIMEOUT or DEVICE_STATE_ERROR_MSG, IoTHubClient_LL_ConnectionStatusCallBack shall be invoked with IOTHUB_CLIENT_CONNECTION_UNAUTHENTICATED and IOTHUB_CLIENT_CONNECTION_COMMUNICATION_ERROR]
AzureIoTClient 31:adadaef857c1 241 else if (new_state == DEVICE_STATE_ERROR_AUTH_TIMEOUT || new_state == DEVICE_STATE_ERROR_MSG)
AzureIoTClient 31:adadaef857c1 242 {
AzureIoTClient 31:adadaef857c1 243 IoTHubClient_LL_ConnectionStatusCallBack(registered_device->iothub_client_handle, IOTHUB_CLIENT_CONNECTION_UNAUTHENTICATED, IOTHUB_CLIENT_CONNECTION_COMMUNICATION_ERROR);
AzureIoTClient 31:adadaef857c1 244 }
AzureIoTClient 30:20a85b733111 245 }
AzureIoTClient 25:63f7d371c030 246 }
AzureIoTClient 25:63f7d371c030 247
AzureIoTClient 30:20a85b733111 248 // @brief Auxiliary function to be used to find a device in the registered_devices list.
AzureIoTClient 30:20a85b733111 249 // @returns true if the device ids match, false otherwise.
AzureIoTClient 30:20a85b733111 250 static bool find_device_by_id_callback(LIST_ITEM_HANDLE list_item, const void* match_context)
AzureIoTClient 25:63f7d371c030 251 {
AzureIoTClient 30:20a85b733111 252 bool result;
AzureIoTClient 30:20a85b733111 253
AzureIoTClient 30:20a85b733111 254 if (match_context == NULL)
AzureIoTClient 30:20a85b733111 255 {
AzureIoTClient 30:20a85b733111 256 result = false;
AzureIoTClient 30:20a85b733111 257 }
AzureIoTClient 30:20a85b733111 258 else
AzureIoTClient 30:20a85b733111 259 {
AzureIoTClient 30:20a85b733111 260 AMQP_TRANSPORT_DEVICE_INSTANCE* device_instance = (AMQP_TRANSPORT_DEVICE_INSTANCE*)singlylinkedlist_item_get_value(list_item);
AzureIoTClient 25:63f7d371c030 261
AzureIoTClient 30:20a85b733111 262 if (device_instance == NULL ||
AzureIoTClient 30:20a85b733111 263 device_instance->device_id == NULL ||
AzureIoTClient 30:20a85b733111 264 STRING_c_str(device_instance->device_id) != match_context)
AzureIoTClient 30:20a85b733111 265 {
AzureIoTClient 30:20a85b733111 266 result = false;
AzureIoTClient 30:20a85b733111 267 }
AzureIoTClient 30:20a85b733111 268 else
AzureIoTClient 30:20a85b733111 269 {
AzureIoTClient 30:20a85b733111 270 result = true;
AzureIoTClient 30:20a85b733111 271 }
AzureIoTClient 30:20a85b733111 272 }
AzureIoTClient 30:20a85b733111 273
AzureIoTClient 30:20a85b733111 274 return result;
AzureIoTClient 25:63f7d371c030 275 }
AzureIoTClient 25:63f7d371c030 276
AzureIoTClient 30:20a85b733111 277 // @brief Verifies if a device is already registered within the transport that owns the list of registered devices.
AzureIoTClient 30:20a85b733111 278 // @remarks Returns the correspoding LIST_ITEM_HANDLE in registered_devices, if found.
AzureIoTClient 30:20a85b733111 279 // @returns true if the device is already in the list, false otherwise.
AzureIoTClient 30:20a85b733111 280 static bool is_device_registered_ex(SINGLYLINKEDLIST_HANDLE registered_devices, const char* device_id, LIST_ITEM_HANDLE *list_item)
AzureIoTClient 25:63f7d371c030 281 {
AzureIoTClient 30:20a85b733111 282 return ((*list_item = singlylinkedlist_find(registered_devices, find_device_by_id_callback, device_id)) != NULL ? 1 : 0);
AzureIoTClient 30:20a85b733111 283 }
AzureIoTClient 25:63f7d371c030 284
AzureIoTClient 30:20a85b733111 285 // @brief Verifies if a device is already registered within the transport that owns the list of registered devices.
AzureIoTClient 30:20a85b733111 286 // @returns true if the device is already in the list, false otherwise.
AzureIoTClient 30:20a85b733111 287 static bool is_device_registered(AMQP_TRANSPORT_DEVICE_INSTANCE* amqp_device_instance)
AzureIoTClient 30:20a85b733111 288 {
AzureIoTClient 30:20a85b733111 289 LIST_ITEM_HANDLE list_item;
AzureIoTClient 30:20a85b733111 290 const char* device_id = STRING_c_str(amqp_device_instance->device_id);
AzureIoTClient 30:20a85b733111 291 return is_device_registered_ex(amqp_device_instance->transport_instance->registered_devices, device_id, &list_item);
AzureIoTClient 25:63f7d371c030 292 }
AzureIoTClient 25:63f7d371c030 293
AzureIoTClient 30:20a85b733111 294
AzureIoTClient 30:20a85b733111 295 // ---------- Callbacks ---------- //
AzureIoTClient 30:20a85b733111 296
AzureIoTClient 30:20a85b733111 297 static MESSAGE_CALLBACK_INFO* MESSAGE_CALLBACK_INFO_Create(IOTHUB_MESSAGE_HANDLE message, DEVICE_MESSAGE_DISPOSITION_INFO* disposition_info, AMQP_TRANSPORT_DEVICE_INSTANCE* device_state)
AzureIoTClient 25:63f7d371c030 298 {
AzureIoTClient 30:20a85b733111 299 MESSAGE_CALLBACK_INFO* result;
AzureIoTClient 25:63f7d371c030 300
AzureIoTClient 30:20a85b733111 301 if ((result = (MESSAGE_CALLBACK_INFO*)malloc(sizeof(MESSAGE_CALLBACK_INFO))) == NULL)
AzureIoTClient 30:20a85b733111 302 {
AzureIoTClient 30:20a85b733111 303 LogError("Failed creating MESSAGE_CALLBACK_INFO (malloc failed)");
AzureIoTClient 30:20a85b733111 304 }
AzureIoTClient 30:20a85b733111 305 else
AzureIoTClient 30:20a85b733111 306 {
AzureIoTClient 30:20a85b733111 307 MESSAGE_DISPOSITION_CONTEXT* tc;
AzureIoTClient 25:63f7d371c030 308
AzureIoTClient 30:20a85b733111 309 if ((tc = (MESSAGE_DISPOSITION_CONTEXT*)malloc(sizeof(MESSAGE_DISPOSITION_CONTEXT))) == NULL)
AzureIoTClient 30:20a85b733111 310 {
AzureIoTClient 30:20a85b733111 311 LogError("Failed creating MESSAGE_DISPOSITION_CONTEXT (malloc failed)");
AzureIoTClient 30:20a85b733111 312 free(result);
AzureIoTClient 30:20a85b733111 313 result = NULL;
AzureIoTClient 30:20a85b733111 314 }
AzureIoTClient 30:20a85b733111 315 else
AzureIoTClient 30:20a85b733111 316 {
AzureIoTClient 30:20a85b733111 317 if (mallocAndStrcpy_s(&(tc->link_name), disposition_info->source) == 0)
AzureIoTClient 30:20a85b733111 318 {
AzureIoTClient 30:20a85b733111 319 tc->device_state = device_state;
AzureIoTClient 30:20a85b733111 320 tc->message_id = disposition_info->message_id;
AzureIoTClient 25:63f7d371c030 321
AzureIoTClient 30:20a85b733111 322 result->messageHandle = message;
AzureIoTClient 30:20a85b733111 323 result->transportContext = tc;
AzureIoTClient 30:20a85b733111 324 }
AzureIoTClient 30:20a85b733111 325 else
AzureIoTClient 30:20a85b733111 326 {
AzureIoTClient 30:20a85b733111 327 LogError("Failed creating MESSAGE_CALLBACK_INFO (mallocAndStrcyp_s failed)");
AzureIoTClient 30:20a85b733111 328 free(tc);
AzureIoTClient 30:20a85b733111 329 free(result);
AzureIoTClient 30:20a85b733111 330 result = NULL;
AzureIoTClient 30:20a85b733111 331 }
AzureIoTClient 30:20a85b733111 332 }
AzureIoTClient 30:20a85b733111 333 }
AzureIoTClient 25:63f7d371c030 334
AzureIoTClient 30:20a85b733111 335 return result;
AzureIoTClient 30:20a85b733111 336 }
AzureIoTClient 30:20a85b733111 337
AzureIoTClient 30:20a85b733111 338 static void MESSAGE_CALLBACK_INFO_Destroy(MESSAGE_CALLBACK_INFO* message_callback_info)
AzureIoTClient 30:20a85b733111 339 {
AzureIoTClient 30:20a85b733111 340 free(message_callback_info->transportContext->link_name);
AzureIoTClient 30:20a85b733111 341 free(message_callback_info->transportContext);
AzureIoTClient 30:20a85b733111 342 free(message_callback_info);
AzureIoTClient 25:63f7d371c030 343 }
AzureIoTClient 25:63f7d371c030 344
AzureIoTClient 30:20a85b733111 345 static DEVICE_MESSAGE_DISPOSITION_RESULT get_device_disposition_result_from(IOTHUBMESSAGE_DISPOSITION_RESULT iothubclient_disposition_result)
AzureIoTClient 25:63f7d371c030 346 {
AzureIoTClient 30:20a85b733111 347 DEVICE_MESSAGE_DISPOSITION_RESULT device_disposition_result;
AzureIoTClient 25:63f7d371c030 348
AzureIoTClient 30:20a85b733111 349 if (iothubclient_disposition_result == IOTHUBMESSAGE_ACCEPTED)
AzureIoTClient 30:20a85b733111 350 {
AzureIoTClient 30:20a85b733111 351 device_disposition_result = DEVICE_MESSAGE_DISPOSITION_RESULT_ACCEPTED;
AzureIoTClient 30:20a85b733111 352 }
AzureIoTClient 30:20a85b733111 353 else if (iothubclient_disposition_result == IOTHUBMESSAGE_ABANDONED)
AzureIoTClient 30:20a85b733111 354 {
AzureIoTClient 30:20a85b733111 355 device_disposition_result = DEVICE_MESSAGE_DISPOSITION_RESULT_RELEASED;
AzureIoTClient 30:20a85b733111 356 }
AzureIoTClient 30:20a85b733111 357 else if (iothubclient_disposition_result == IOTHUBMESSAGE_REJECTED)
AzureIoTClient 30:20a85b733111 358 {
AzureIoTClient 30:20a85b733111 359 device_disposition_result = DEVICE_MESSAGE_DISPOSITION_RESULT_REJECTED;
AzureIoTClient 30:20a85b733111 360 }
AzureIoTClient 30:20a85b733111 361 else
AzureIoTClient 30:20a85b733111 362 {
AzureIoTClient 30:20a85b733111 363 LogError("Failed getting corresponding DEVICE_MESSAGE_DISPOSITION_RESULT for IOTHUBMESSAGE_DISPOSITION_RESULT (%d is not supported)", iothubclient_disposition_result);
AzureIoTClient 30:20a85b733111 364 device_disposition_result = DEVICE_MESSAGE_DISPOSITION_RESULT_RELEASED;
AzureIoTClient 30:20a85b733111 365 }
AzureIoTClient 25:63f7d371c030 366
AzureIoTClient 30:20a85b733111 367 return device_disposition_result;
AzureIoTClient 25:63f7d371c030 368 }
AzureIoTClient 25:63f7d371c030 369
AzureIoTClient 30:20a85b733111 370 static DEVICE_MESSAGE_DISPOSITION_RESULT on_message_received(IOTHUB_MESSAGE_HANDLE message, DEVICE_MESSAGE_DISPOSITION_INFO* disposition_info, void* context)
AzureIoTClient 25:63f7d371c030 371 {
AzureIoTClient 30:20a85b733111 372 AMQP_TRANSPORT_DEVICE_INSTANCE* amqp_device_instance = (AMQP_TRANSPORT_DEVICE_INSTANCE*)context;
AzureIoTClient 30:20a85b733111 373 DEVICE_MESSAGE_DISPOSITION_RESULT device_disposition_result;
AzureIoTClient 30:20a85b733111 374 MESSAGE_CALLBACK_INFO* message_data;
AzureIoTClient 25:63f7d371c030 375
AzureIoTClient 30:20a85b733111 376 if ((message_data = MESSAGE_CALLBACK_INFO_Create(message, disposition_info, amqp_device_instance)) == NULL)
AzureIoTClient 30:20a85b733111 377 {
AzureIoTClient 30:20a85b733111 378 LogError("Failed processing message received (failed to assemble callback info)");
AzureIoTClient 30:20a85b733111 379 device_disposition_result = DEVICE_MESSAGE_DISPOSITION_RESULT_RELEASED;
AzureIoTClient 30:20a85b733111 380 }
AzureIoTClient 30:20a85b733111 381 else
AzureIoTClient 30:20a85b733111 382 {
AzureIoTClient 30:20a85b733111 383 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_089: [IoTHubClient_LL_MessageCallback() shall be invoked passing the client and the incoming message handles as parameters]
AzureIoTClient 30:20a85b733111 384 if (IoTHubClient_LL_MessageCallback(amqp_device_instance->iothub_client_handle, message_data) != true)
AzureIoTClient 30:20a85b733111 385 {
AzureIoTClient 30:20a85b733111 386 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_090: [If IoTHubClient_LL_MessageCallback() fails, on_message_received_callback shall return DEVICE_MESSAGE_DISPOSITION_RESULT_RELEASED]
AzureIoTClient 30:20a85b733111 387 LogError("Failed processing message received (IoTHubClient_LL_MessageCallback failed)");
AzureIoTClient 30:20a85b733111 388 IoTHubMessage_Destroy(message);
AzureIoTClient 30:20a85b733111 389 device_disposition_result = DEVICE_MESSAGE_DISPOSITION_RESULT_RELEASED;
AzureIoTClient 30:20a85b733111 390 }
AzureIoTClient 30:20a85b733111 391 else
AzureIoTClient 30:20a85b733111 392 {
AzureIoTClient 30:20a85b733111 393 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_091: [If IoTHubClient_LL_MessageCallback() succeeds, on_message_received_callback shall return DEVICE_MESSAGE_DISPOSITION_RESULT_NONE]
AzureIoTClient 30:20a85b733111 394 device_disposition_result = DEVICE_MESSAGE_DISPOSITION_RESULT_NONE;
AzureIoTClient 30:20a85b733111 395 }
AzureIoTClient 30:20a85b733111 396 }
AzureIoTClient 30:20a85b733111 397
AzureIoTClient 30:20a85b733111 398 return device_disposition_result;
AzureIoTClient 25:63f7d371c030 399 }
AzureIoTClient 25:63f7d371c030 400
AzureIoTClient 25:63f7d371c030 401
AzureIoTClient 25:63f7d371c030 402 #ifdef WIP_C2D_METHODS_AMQP /* This feature is WIP, do not use yet */
AzureIoTClient 25:63f7d371c030 403 static void on_methods_error(void* context)
AzureIoTClient 25:63f7d371c030 404 {
AzureIoTClient 25:63f7d371c030 405 /* Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_01_030: [ `on_methods_error` shall do nothing. ]*/
AzureIoTClient 25:63f7d371c030 406 (void)context;
AzureIoTClient 25:63f7d371c030 407 }
AzureIoTClient 25:63f7d371c030 408
AzureIoTClient 29:7e8852b14e3b 409 static void on_methods_unsubscribed(void* context)
AzureIoTClient 29:7e8852b14e3b 410 {
AzureIoTClient 31:adadaef857c1 411 /* Codes_SRS_IOTHUBTRANSPORT_AMQP_METHODS_12_001: [ `on_methods_unsubscribed` calls iothubtransportamqp_methods_unsubscribe. ]*/
AzureIoTClient 30:20a85b733111 412 AMQP_TRANSPORT_DEVICE_INSTANCE* device_state = (AMQP_TRANSPORT_DEVICE_INSTANCE*)context;
AzureIoTClient 31:adadaef857c1 413
AzureIoTClient 31:adadaef857c1 414 iothubtransportamqp_methods_unsubscribe(device_state->methods_handle);
AzureIoTClient 31:adadaef857c1 415 device_state->subscribed_for_methods = false;
AzureIoTClient 29:7e8852b14e3b 416 }
AzureIoTClient 29:7e8852b14e3b 417
AzureIoTClient 25:63f7d371c030 418 static int on_method_request_received(void* context, const char* method_name, const unsigned char* request, size_t request_size, IOTHUBTRANSPORT_AMQP_METHOD_HANDLE method_handle)
AzureIoTClient 25:63f7d371c030 419 {
AzureIoTClient 25:63f7d371c030 420 int result;
AzureIoTClient 30:20a85b733111 421 AMQP_TRANSPORT_DEVICE_INSTANCE* device_state = (AMQP_TRANSPORT_DEVICE_INSTANCE*)context;
AzureIoTClient 25:63f7d371c030 422
AzureIoTClient 26:ee14eed604f6 423 /* Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_01_017: [ `on_methods_request_received` shall call the `IoTHubClient_LL_DeviceMethodComplete` passing the method name, request buffer and size and the newly created BUFFER handle. ]*/
AzureIoTClient 26:ee14eed604f6 424 /* Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_01_022: [ The status code shall be the return value of the call to `IoTHubClient_LL_DeviceMethodComplete`. ]*/
AzureIoTClient 26:ee14eed604f6 425 if (IoTHubClient_LL_DeviceMethodComplete(device_state->iothub_client_handle, method_name, request, request_size, (void*)method_handle) != 0)
AzureIoTClient 25:63f7d371c030 426 {
AzureIoTClient 26:ee14eed604f6 427 LogError("Failure: IoTHubClient_LL_DeviceMethodComplete");
AzureIoTClient 29:7e8852b14e3b 428 result = __FAILURE__;
AzureIoTClient 25:63f7d371c030 429 }
AzureIoTClient 25:63f7d371c030 430 else
AzureIoTClient 25:63f7d371c030 431 {
AzureIoTClient 26:ee14eed604f6 432 result = 0;
AzureIoTClient 25:63f7d371c030 433 }
AzureIoTClient 25:63f7d371c030 434 return result;
AzureIoTClient 25:63f7d371c030 435 }
AzureIoTClient 25:63f7d371c030 436
AzureIoTClient 30:20a85b733111 437 static int subscribe_methods(AMQP_TRANSPORT_DEVICE_INSTANCE* deviceState)
AzureIoTClient 25:63f7d371c030 438 {
AzureIoTClient 25:63f7d371c030 439 int result;
AzureIoTClient 25:63f7d371c030 440
AzureIoTClient 29:7e8852b14e3b 441 if (deviceState->subscribed_for_methods)
AzureIoTClient 25:63f7d371c030 442 {
AzureIoTClient 25:63f7d371c030 443 result = 0;
AzureIoTClient 25:63f7d371c030 444 }
AzureIoTClient 25:63f7d371c030 445 else
AzureIoTClient 25:63f7d371c030 446 {
AzureIoTClient 30:20a85b733111 447 SESSION_HANDLE session_handle;
AzureIoTClient 30:20a85b733111 448
AzureIoTClient 30:20a85b733111 449 if ((amqp_connection_get_session_handle(deviceState->transport_instance->amqp_connection, &session_handle)) != RESULT_OK)
AzureIoTClient 30:20a85b733111 450 {
AzureIoTClient 30:20a85b733111 451 LogError("Device '%s' failed subscribing for methods (failed getting session handle)", STRING_c_str(deviceState->device_id));
AzureIoTClient 30:20a85b733111 452 result = __FAILURE__;
AzureIoTClient 30:20a85b733111 453 }
AzureIoTClient 25:63f7d371c030 454 /* Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_01_024: [ If the device authentication status is AUTHENTICATION_STATUS_OK and `IoTHubTransport_AMQP_Common_Subscribe_DeviceMethod` was called to register for methods, `IoTHubTransport_AMQP_Common_DoWork` shall call `iothubtransportamqp_methods_subscribe`. ]*/
AzureIoTClient 25:63f7d371c030 455 /* Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_01_027: [ The current session handle shall be passed to `iothubtransportamqp_methods_subscribe`. ]*/
AzureIoTClient 30:20a85b733111 456 else if (iothubtransportamqp_methods_subscribe(deviceState->methods_handle, session_handle, on_methods_error, deviceState, on_method_request_received, deviceState, on_methods_unsubscribed, deviceState) != 0)
AzureIoTClient 25:63f7d371c030 457 {
AzureIoTClient 25:63f7d371c030 458 LogError("Cannot subscribe for methods");
AzureIoTClient 29:7e8852b14e3b 459 result = __FAILURE__;
AzureIoTClient 25:63f7d371c030 460 }
AzureIoTClient 25:63f7d371c030 461 else
AzureIoTClient 25:63f7d371c030 462 {
AzureIoTClient 29:7e8852b14e3b 463 deviceState->subscribed_for_methods = true;
AzureIoTClient 25:63f7d371c030 464 result = 0;
AzureIoTClient 25:63f7d371c030 465 }
AzureIoTClient 25:63f7d371c030 466 }
AzureIoTClient 25:63f7d371c030 467
AzureIoTClient 25:63f7d371c030 468 return result;
AzureIoTClient 25:63f7d371c030 469 }
AzureIoTClient 25:63f7d371c030 470 #endif
AzureIoTClient 25:63f7d371c030 471
AzureIoTClient 30:20a85b733111 472
AzureIoTClient 30:20a85b733111 473 // ---------- Underlying TLS I/O Helpers ---------- //
AzureIoTClient 30:20a85b733111 474
AzureIoTClient 30:20a85b733111 475 // @brief
AzureIoTClient 30:20a85b733111 476 // Retrieves the options of the current underlying TLS I/O instance and saves in the transport instance.
AzureIoTClient 30:20a85b733111 477 // @remarks
AzureIoTClient 30:20a85b733111 478 // This is used when the new underlying I/O transport (TLS I/O, or WebSockets, etc) needs to be recreated,
AzureIoTClient 30:20a85b733111 479 // and the options previously set must persist.
AzureIoTClient 30:20a85b733111 480 //
AzureIoTClient 30:20a85b733111 481 // If no TLS I/O instance was created yet, results in failure.
AzureIoTClient 30:20a85b733111 482 // @returns
AzureIoTClient 30:20a85b733111 483 // 0 if succeeds, non-zero otherwise.
AzureIoTClient 30:20a85b733111 484 static int save_underlying_io_transport_options(AMQP_TRANSPORT_INSTANCE* transport_instance)
AzureIoTClient 25:63f7d371c030 485 {
AzureIoTClient 30:20a85b733111 486 int result;
AzureIoTClient 30:20a85b733111 487
AzureIoTClient 30:20a85b733111 488 if (transport_instance->tls_io == NULL)
AzureIoTClient 30:20a85b733111 489 {
AzureIoTClient 30:20a85b733111 490 LogError("failed saving underlying I/O transport options (tls_io instance is NULL)");
AzureIoTClient 30:20a85b733111 491 result = __FAILURE__;
AzureIoTClient 30:20a85b733111 492 }
AzureIoTClient 30:20a85b733111 493 else
AzureIoTClient 30:20a85b733111 494 {
AzureIoTClient 30:20a85b733111 495 OPTIONHANDLER_HANDLE fresh_options;
AzureIoTClient 25:63f7d371c030 496
AzureIoTClient 30:20a85b733111 497 if ((fresh_options = xio_retrieveoptions(transport_instance->tls_io)) == NULL)
AzureIoTClient 30:20a85b733111 498 {
AzureIoTClient 30:20a85b733111 499 LogError("failed saving underlying I/O transport options (tls_io instance is NULL)");
AzureIoTClient 30:20a85b733111 500 result = __FAILURE__;
AzureIoTClient 30:20a85b733111 501 }
AzureIoTClient 30:20a85b733111 502 else
AzureIoTClient 30:20a85b733111 503 {
AzureIoTClient 30:20a85b733111 504 OPTIONHANDLER_HANDLE previous_options = transport_instance->saved_tls_options;
AzureIoTClient 30:20a85b733111 505 transport_instance->saved_tls_options = fresh_options;
AzureIoTClient 30:20a85b733111 506
AzureIoTClient 30:20a85b733111 507 if (previous_options != NULL)
AzureIoTClient 30:20a85b733111 508 {
AzureIoTClient 30:20a85b733111 509 OptionHandler_Destroy(previous_options);
AzureIoTClient 30:20a85b733111 510 }
AzureIoTClient 30:20a85b733111 511
AzureIoTClient 30:20a85b733111 512 result = RESULT_OK;
AzureIoTClient 30:20a85b733111 513 }
AzureIoTClient 30:20a85b733111 514 }
AzureIoTClient 30:20a85b733111 515
AzureIoTClient 30:20a85b733111 516 return result;
AzureIoTClient 30:20a85b733111 517 }
AzureIoTClient 30:20a85b733111 518
AzureIoTClient 30:20a85b733111 519 static void destroy_underlying_io_transport_options(AMQP_TRANSPORT_INSTANCE* transport_instance)
AzureIoTClient 30:20a85b733111 520 {
AzureIoTClient 30:20a85b733111 521 if (transport_instance->saved_tls_options != NULL)
AzureIoTClient 30:20a85b733111 522 {
AzureIoTClient 30:20a85b733111 523 OptionHandler_Destroy(transport_instance->saved_tls_options);
AzureIoTClient 30:20a85b733111 524 transport_instance->saved_tls_options = NULL;
AzureIoTClient 30:20a85b733111 525 }
AzureIoTClient 25:63f7d371c030 526 }
AzureIoTClient 25:63f7d371c030 527
AzureIoTClient 30:20a85b733111 528 // @brief
AzureIoTClient 30:20a85b733111 529 // Applies TLS I/O options if previously saved to a new TLS I/O instance.
AzureIoTClient 30:20a85b733111 530 // @returns
AzureIoTClient 30:20a85b733111 531 // 0 if succeeds, non-zero otherwise.
AzureIoTClient 30:20a85b733111 532 static int restore_underlying_io_transport_options(AMQP_TRANSPORT_INSTANCE* transport_instance, XIO_HANDLE xio_handle)
AzureIoTClient 30:20a85b733111 533 {
AzureIoTClient 30:20a85b733111 534 int result;
AzureIoTClient 30:20a85b733111 535
AzureIoTClient 30:20a85b733111 536 if (transport_instance->saved_tls_options == NULL)
AzureIoTClient 30:20a85b733111 537 {
AzureIoTClient 30:20a85b733111 538 result = RESULT_OK;
AzureIoTClient 30:20a85b733111 539 }
AzureIoTClient 30:20a85b733111 540 else
AzureIoTClient 30:20a85b733111 541 {
AzureIoTClient 30:20a85b733111 542 if (OptionHandler_FeedOptions(transport_instance->saved_tls_options, xio_handle) != OPTIONHANDLER_OK)
AzureIoTClient 30:20a85b733111 543 {
AzureIoTClient 30:20a85b733111 544 LogError("Failed feeding existing options to new TLS instance.");
AzureIoTClient 30:20a85b733111 545 result = __FAILURE__;
AzureIoTClient 30:20a85b733111 546 }
AzureIoTClient 30:20a85b733111 547 else
AzureIoTClient 30:20a85b733111 548 {
AzureIoTClient 30:20a85b733111 549 result = RESULT_OK;
AzureIoTClient 30:20a85b733111 550 }
AzureIoTClient 30:20a85b733111 551 }
AzureIoTClient 30:20a85b733111 552
AzureIoTClient 30:20a85b733111 553 return result;
AzureIoTClient 30:20a85b733111 554 }
AzureIoTClient 30:20a85b733111 555
AzureIoTClient 30:20a85b733111 556 // @brief Destroys the XIO_HANDLE obtained with underlying_io_transport_provider(), saving its options beforehand.
AzureIoTClient 30:20a85b733111 557 static void destroy_underlying_io_transport(AMQP_TRANSPORT_INSTANCE* transport_instance)
AzureIoTClient 30:20a85b733111 558 {
AzureIoTClient 30:20a85b733111 559 if (transport_instance->tls_io != NULL)
AzureIoTClient 30:20a85b733111 560 {
AzureIoTClient 30:20a85b733111 561 xio_destroy(transport_instance->tls_io);
AzureIoTClient 30:20a85b733111 562 transport_instance->tls_io = NULL;
AzureIoTClient 30:20a85b733111 563 }
AzureIoTClient 30:20a85b733111 564 }
AzureIoTClient 30:20a85b733111 565
AzureIoTClient 30:20a85b733111 566 // @brief Invokes underlying_io_transport_provider() and retrieves a new XIO_HANDLE to use for I/O (TLS, or websockets, or w/e is supported).
AzureIoTClient 30:20a85b733111 567 // @param xio_handle: if successfull, set with the new XIO_HANDLE acquired; not changed otherwise.
AzureIoTClient 30:20a85b733111 568 // @returns 0 if successfull, non-zero otherwise.
AzureIoTClient 30:20a85b733111 569 static int get_new_underlying_io_transport(AMQP_TRANSPORT_INSTANCE* transport_instance, XIO_HANDLE *xio_handle)
AzureIoTClient 30:20a85b733111 570 {
AzureIoTClient 30:20a85b733111 571 int result;
AzureIoTClient 31:adadaef857c1 572 AMQP_TRANSPORT_PROXY_OPTIONS amqp_transport_proxy_options;
AzureIoTClient 30:20a85b733111 573
AzureIoTClient 31:adadaef857c1 574 /* Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_01_041: [ If the `proxy_data` option has been set, the proxy options shall be filled in the argument `amqp_transport_proxy_options` when calling the function `underlying_io_transport_provider()` to obtain the underlying IO handle. ]*/
AzureIoTClient 31:adadaef857c1 575 amqp_transport_proxy_options.host_address = transport_instance->http_proxy_hostname;
AzureIoTClient 31:adadaef857c1 576 amqp_transport_proxy_options.port = transport_instance->http_proxy_port;
AzureIoTClient 31:adadaef857c1 577 amqp_transport_proxy_options.username = transport_instance->http_proxy_username;
AzureIoTClient 31:adadaef857c1 578 amqp_transport_proxy_options.password = transport_instance->http_proxy_password;
AzureIoTClient 31:adadaef857c1 579
AzureIoTClient 31:adadaef857c1 580 /* Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_01_042: [ If no `proxy_data` option has been set, NULL shall be passed as the argument `amqp_transport_proxy_options` when calling the function `underlying_io_transport_provider()`. ]*/
AzureIoTClient 31:adadaef857c1 581 if ((*xio_handle = transport_instance->underlying_io_transport_provider(STRING_c_str(transport_instance->iothub_host_fqdn), amqp_transport_proxy_options.host_address == NULL ? NULL : &amqp_transport_proxy_options)) == NULL)
AzureIoTClient 30:20a85b733111 582 {
AzureIoTClient 30:20a85b733111 583 LogError("Failed to obtain a TLS I/O transport layer (underlying_io_transport_provider() failed)");
AzureIoTClient 30:20a85b733111 584 result = __FAILURE__;
AzureIoTClient 30:20a85b733111 585 }
AzureIoTClient 30:20a85b733111 586 else
AzureIoTClient 30:20a85b733111 587 {
AzureIoTClient 30:20a85b733111 588 if (restore_underlying_io_transport_options(transport_instance, *xio_handle) != RESULT_OK)
AzureIoTClient 30:20a85b733111 589 {
AzureIoTClient 30:20a85b733111 590 /*pessimistically hope TLS will fail, be recreated and options re-given*/
AzureIoTClient 30:20a85b733111 591 LogError("Failed to apply options previous saved to new underlying I/O transport instance.");
AzureIoTClient 30:20a85b733111 592 }
AzureIoTClient 30:20a85b733111 593
AzureIoTClient 30:20a85b733111 594 result = RESULT_OK;
AzureIoTClient 30:20a85b733111 595 }
AzureIoTClient 30:20a85b733111 596
AzureIoTClient 30:20a85b733111 597 return result;
AzureIoTClient 30:20a85b733111 598 }
AzureIoTClient 30:20a85b733111 599
AzureIoTClient 30:20a85b733111 600
AzureIoTClient 30:20a85b733111 601 // ---------- AMQP connection establishment/tear-down, connectry retry ---------- //
AzureIoTClient 30:20a85b733111 602
AzureIoTClient 30:20a85b733111 603 static void on_amqp_connection_state_changed(const void* context, AMQP_CONNECTION_STATE previous_state, AMQP_CONNECTION_STATE new_state)
AzureIoTClient 30:20a85b733111 604 {
AzureIoTClient 30:20a85b733111 605 if (context != NULL && new_state != previous_state)
AzureIoTClient 30:20a85b733111 606 {
AzureIoTClient 30:20a85b733111 607 AMQP_TRANSPORT_INSTANCE* transport_instance = (AMQP_TRANSPORT_INSTANCE*)context;
AzureIoTClient 30:20a85b733111 608
AzureIoTClient 30:20a85b733111 609 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_059: [`new_state` shall be saved in to the transport instance]
AzureIoTClient 30:20a85b733111 610 transport_instance->amqp_connection_state = new_state;
AzureIoTClient 30:20a85b733111 611
AzureIoTClient 30:20a85b733111 612 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_060: [If `new_state` is AMQP_CONNECTION_STATE_ERROR, the connection shall be flagged as faulty (so the connection retry logic can be triggered)]
AzureIoTClient 30:20a85b733111 613 if (new_state == AMQP_CONNECTION_STATE_ERROR)
AzureIoTClient 30:20a85b733111 614 {
AzureIoTClient 31:adadaef857c1 615 LogError("Transport received an ERROR from the amqp_connection (state changed %s -> %s); it will be flagged for connection retry.", ENUM_TO_STRING(AMQP_CONNECTION_STATE, previous_state), ENUM_TO_STRING(AMQP_CONNECTION_STATE, new_state));
AzureIoTClient 31:adadaef857c1 616
AzureIoTClient 32:babfd49032ff 617 update_state(transport_instance, AMQP_TRANSPORT_STATE_RECONNECTION_REQUIRED);
AzureIoTClient 32:babfd49032ff 618 }
AzureIoTClient 32:babfd49032ff 619 else if (new_state == AMQP_CONNECTION_STATE_OPENED)
AzureIoTClient 32:babfd49032ff 620 {
AzureIoTClient 32:babfd49032ff 621 update_state(transport_instance, AMQP_TRANSPORT_STATE_CONNECTED);
AzureIoTClient 31:adadaef857c1 622 }
AzureIoTClient 31:adadaef857c1 623 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_115: [If the AMQP connection is closed by the service side, the connection retry logic shall be triggered]
AzureIoTClient 32:babfd49032ff 624 else if (new_state == AMQP_CONNECTION_STATE_CLOSED && previous_state == AMQP_CONNECTION_STATE_OPENED && transport_instance->state != AMQP_TRANSPORT_STATE_BEING_DESTROYED)
AzureIoTClient 31:adadaef857c1 625 {
AzureIoTClient 31:adadaef857c1 626 LogError("amqp_connection was closed unexpectedly; connection retry will be triggered.");
AzureIoTClient 30:20a85b733111 627
AzureIoTClient 32:babfd49032ff 628 update_state(transport_instance, AMQP_TRANSPORT_STATE_RECONNECTION_REQUIRED);
AzureIoTClient 30:20a85b733111 629 }
AzureIoTClient 30:20a85b733111 630 }
AzureIoTClient 30:20a85b733111 631 }
AzureIoTClient 30:20a85b733111 632
AzureIoTClient 30:20a85b733111 633 static int establish_amqp_connection(AMQP_TRANSPORT_INSTANCE* transport_instance)
AzureIoTClient 25:63f7d371c030 634 {
AzureIoTClient 25:63f7d371c030 635 int result;
AzureIoTClient 25:63f7d371c030 636
AzureIoTClient 30:20a85b733111 637 if (transport_instance->preferred_authentication_mode == AMQP_TRANSPORT_AUTHENTICATION_MODE_NOT_SET)
AzureIoTClient 30:20a85b733111 638 {
AzureIoTClient 30:20a85b733111 639 LogError("Failed establishing connection (transport doesn't have a preferred authentication mode set; unexpected!).");
AzureIoTClient 30:20a85b733111 640 result = __FAILURE__;
AzureIoTClient 30:20a85b733111 641 }
AzureIoTClient 30:20a85b733111 642 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_023: [If `instance->tls_io` is NULL, it shall be set invoking instance->underlying_io_transport_provider()]
AzureIoTClient 30:20a85b733111 643 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_025: [When `instance->tls_io` is created, it shall be set with `instance->saved_tls_options` using OptionHandler_FeedOptions()]
AzureIoTClient 30:20a85b733111 644 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_111: [If OptionHandler_FeedOptions() fails, it shall be ignored]
AzureIoTClient 30:20a85b733111 645 else if (transport_instance->tls_io == NULL &&
AzureIoTClient 30:20a85b733111 646 get_new_underlying_io_transport(transport_instance, &transport_instance->tls_io) != RESULT_OK)
AzureIoTClient 30:20a85b733111 647 {
AzureIoTClient 30:20a85b733111 648 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_024: [If instance->underlying_io_transport_provider() fails, IoTHubTransport_AMQP_Common_DoWork shall fail and return]
AzureIoTClient 30:20a85b733111 649 LogError("Failed establishing connection (failed to obtain a TLS I/O transport layer).");
AzureIoTClient 30:20a85b733111 650 result = __FAILURE__;
AzureIoTClient 30:20a85b733111 651 }
AzureIoTClient 30:20a85b733111 652 else
AzureIoTClient 30:20a85b733111 653 {
AzureIoTClient 30:20a85b733111 654 AMQP_CONNECTION_CONFIG amqp_connection_config;
AzureIoTClient 30:20a85b733111 655 amqp_connection_config.iothub_host_fqdn = STRING_c_str(transport_instance->iothub_host_fqdn);
AzureIoTClient 30:20a85b733111 656 amqp_connection_config.underlying_io_transport = transport_instance->tls_io;
AzureIoTClient 30:20a85b733111 657 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_029: [`instance->is_trace_on` shall be set into `AMQP_CONNECTION_CONFIG->is_trace_on`]
AzureIoTClient 30:20a85b733111 658 amqp_connection_config.is_trace_on = transport_instance->is_trace_on;
AzureIoTClient 30:20a85b733111 659 amqp_connection_config.on_state_changed_callback = on_amqp_connection_state_changed;
AzureIoTClient 30:20a85b733111 660 amqp_connection_config.on_state_changed_context = transport_instance;
AzureIoTClient 25:63f7d371c030 661
AzureIoTClient 30:20a85b733111 662 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_027: [If `transport->preferred_authentication_method` is CBS, AMQP_CONNECTION_CONFIG shall be set with `create_sasl_io` = true and `create_cbs_connection` = true]
AzureIoTClient 30:20a85b733111 663 if (transport_instance->preferred_authentication_mode == AMQP_TRANSPORT_AUTHENTICATION_MODE_CBS)
AzureIoTClient 30:20a85b733111 664 {
AzureIoTClient 30:20a85b733111 665 amqp_connection_config.create_sasl_io = true;
AzureIoTClient 30:20a85b733111 666 amqp_connection_config.create_cbs_connection = true;
AzureIoTClient 30:20a85b733111 667 }
AzureIoTClient 30:20a85b733111 668 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_028: [If `transport->preferred_credential_method` is X509, AMQP_CONNECTION_CONFIG shall be set with `create_sasl_io` = false and `create_cbs_connection` = false]
AzureIoTClient 30:20a85b733111 669 else if (transport_instance->preferred_authentication_mode == AMQP_TRANSPORT_AUTHENTICATION_MODE_X509)
AzureIoTClient 30:20a85b733111 670 {
AzureIoTClient 30:20a85b733111 671 amqp_connection_config.create_sasl_io = false;
AzureIoTClient 30:20a85b733111 672 amqp_connection_config.create_cbs_connection = false;
AzureIoTClient 30:20a85b733111 673 }
AzureIoTClient 30:20a85b733111 674 // If new AMQP_TRANSPORT_AUTHENTICATION_MODE values are added, they need to be covered here.
AzureIoTClient 25:63f7d371c030 675
AzureIoTClient 30:20a85b733111 676 transport_instance->amqp_connection_state = AMQP_CONNECTION_STATE_CLOSED;
AzureIoTClient 30:20a85b733111 677
AzureIoTClient 32:babfd49032ff 678 if (transport_instance->state == AMQP_TRANSPORT_STATE_READY_FOR_RECONNECTION)
AzureIoTClient 32:babfd49032ff 679 {
AzureIoTClient 32:babfd49032ff 680 update_state(transport_instance, AMQP_TRANSPORT_STATE_RECONNECTING);
AzureIoTClient 32:babfd49032ff 681 }
AzureIoTClient 32:babfd49032ff 682 else
AzureIoTClient 32:babfd49032ff 683 {
AzureIoTClient 32:babfd49032ff 684 update_state(transport_instance, AMQP_TRANSPORT_STATE_CONNECTING);
AzureIoTClient 32:babfd49032ff 685 }
AzureIoTClient 32:babfd49032ff 686
AzureIoTClient 30:20a85b733111 687 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_026: [If `transport->connection` is NULL, it shall be created using amqp_connection_create()]
AzureIoTClient 30:20a85b733111 688 if ((transport_instance->amqp_connection = amqp_connection_create(&amqp_connection_config)) == NULL)
AzureIoTClient 30:20a85b733111 689 {
AzureIoTClient 30:20a85b733111 690 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_030: [If amqp_connection_create() fails, IoTHubTransport_AMQP_Common_DoWork shall fail and return]
AzureIoTClient 30:20a85b733111 691 LogError("Failed establishing connection (failed to create the amqp_connection instance).");
AzureIoTClient 30:20a85b733111 692 result = __FAILURE__;
AzureIoTClient 30:20a85b733111 693 }
AzureIoTClient 30:20a85b733111 694 else
AzureIoTClient 30:20a85b733111 695 {
AzureIoTClient 30:20a85b733111 696 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_110: [If amqp_connection_create() succeeds, IoTHubTransport_AMQP_Common_DoWork shall proceed to invoke amqp_connection_do_work]
AzureIoTClient 30:20a85b733111 697 result = RESULT_OK;
AzureIoTClient 30:20a85b733111 698 }
AzureIoTClient 30:20a85b733111 699 }
AzureIoTClient 25:63f7d371c030 700
AzureIoTClient 25:63f7d371c030 701 return result;
AzureIoTClient 25:63f7d371c030 702 }
AzureIoTClient 25:63f7d371c030 703
AzureIoTClient 30:20a85b733111 704 static void prepare_device_for_connection_retry(AMQP_TRANSPORT_DEVICE_INSTANCE* registered_device)
AzureIoTClient 25:63f7d371c030 705 {
AzureIoTClient 30:20a85b733111 706 #ifdef WIP_C2D_METHODS_AMQP /* This feature is WIP, do not use yet */
AzureIoTClient 30:20a85b733111 707 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_032: [ Each `instance->registered_devices` shall unsubscribe from receiving C2D method requests by calling `iothubtransportamqp_methods_unsubscribe`]
AzureIoTClient 30:20a85b733111 708 iothubtransportamqp_methods_unsubscribe(registered_device->methods_handle);
AzureIoTClient 30:20a85b733111 709 registered_device->subscribed_for_methods = 0;
AzureIoTClient 30:20a85b733111 710 #endif
AzureIoTClient 25:63f7d371c030 711
AzureIoTClient 30:20a85b733111 712 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_031: [device_stop() shall be invoked on all `instance->registered_devices` that are not already stopped]
AzureIoTClient 30:20a85b733111 713 if (registered_device->device_state != DEVICE_STATE_STOPPED)
AzureIoTClient 30:20a85b733111 714 {
AzureIoTClient 30:20a85b733111 715 if (device_stop(registered_device->device_handle) != RESULT_OK)
AzureIoTClient 30:20a85b733111 716 {
AzureIoTClient 30:20a85b733111 717 LogError("Failed preparing device '%s' for connection retry (device_stop failed)", STRING_c_str(registered_device->device_id));
AzureIoTClient 30:20a85b733111 718 }
AzureIoTClient 30:20a85b733111 719 }
AzureIoTClient 25:63f7d371c030 720
AzureIoTClient 30:20a85b733111 721 registered_device->number_of_previous_failures = 0;
AzureIoTClient 30:20a85b733111 722 registered_device->number_of_send_event_complete_failures = 0;
AzureIoTClient 25:63f7d371c030 723 }
AzureIoTClient 25:63f7d371c030 724
AzureIoTClient 30:20a85b733111 725 static void prepare_for_connection_retry(AMQP_TRANSPORT_INSTANCE* transport_instance)
AzureIoTClient 25:63f7d371c030 726 {
AzureIoTClient 32:babfd49032ff 727 LogInfo("Preparing transport for re-connection");
AzureIoTClient 32:babfd49032ff 728
AzureIoTClient 30:20a85b733111 729 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_034: [`instance->tls_io` options shall be saved on `instance->saved_tls_options` using xio_retrieveoptions()]
AzureIoTClient 30:20a85b733111 730 if (save_underlying_io_transport_options(transport_instance) != RESULT_OK)
AzureIoTClient 30:20a85b733111 731 {
AzureIoTClient 30:20a85b733111 732 LogError("Failed saving TLS I/O options while preparing for connection retry; failure will be ignored");
AzureIoTClient 30:20a85b733111 733 }
AzureIoTClient 25:63f7d371c030 734
AzureIoTClient 30:20a85b733111 735 LIST_ITEM_HANDLE list_item = singlylinkedlist_get_head_item(transport_instance->registered_devices);
AzureIoTClient 30:20a85b733111 736
AzureIoTClient 30:20a85b733111 737 while (list_item != NULL)
AzureIoTClient 30:20a85b733111 738 {
AzureIoTClient 30:20a85b733111 739 AMQP_TRANSPORT_DEVICE_INSTANCE* registered_device = (AMQP_TRANSPORT_DEVICE_INSTANCE*)singlylinkedlist_item_get_value(list_item);
AzureIoTClient 25:63f7d371c030 740
AzureIoTClient 30:20a85b733111 741 if (registered_device == NULL)
AzureIoTClient 30:20a85b733111 742 {
AzureIoTClient 30:20a85b733111 743 LogError("Failed preparing device for connection retry (singlylinkedlist_item_get_value failed)");
AzureIoTClient 30:20a85b733111 744 }
AzureIoTClient 30:20a85b733111 745 else
AzureIoTClient 30:20a85b733111 746 {
AzureIoTClient 30:20a85b733111 747 prepare_device_for_connection_retry(registered_device);
AzureIoTClient 30:20a85b733111 748 }
AzureIoTClient 25:63f7d371c030 749
AzureIoTClient 30:20a85b733111 750 list_item = singlylinkedlist_get_next_item(list_item);
AzureIoTClient 30:20a85b733111 751 }
AzureIoTClient 25:63f7d371c030 752
AzureIoTClient 30:20a85b733111 753 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_033: [`instance->connection` shall be destroyed using amqp_connection_destroy()]
AzureIoTClient 30:20a85b733111 754 amqp_connection_destroy(transport_instance->amqp_connection);
AzureIoTClient 30:20a85b733111 755 transport_instance->amqp_connection = NULL;
AzureIoTClient 30:20a85b733111 756 transport_instance->amqp_connection_state = AMQP_CONNECTION_STATE_CLOSED;
AzureIoTClient 25:63f7d371c030 757
AzureIoTClient 30:20a85b733111 758 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_035: [`instance->tls_io` shall be destroyed using xio_destroy()]
AzureIoTClient 30:20a85b733111 759 destroy_underlying_io_transport(transport_instance);
AzureIoTClient 32:babfd49032ff 760
AzureIoTClient 32:babfd49032ff 761 update_state(transport_instance, AMQP_TRANSPORT_STATE_READY_FOR_RECONNECTION);
AzureIoTClient 25:63f7d371c030 762 }
AzureIoTClient 25:63f7d371c030 763
AzureIoTClient 30:20a85b733111 764
AzureIoTClient 30:20a85b733111 765 // @brief Verifies if the crendentials used by the device match the requirements and authentication mode currently supported by the transport.
AzureIoTClient 30:20a85b733111 766 // @returns true if credentials are good, false otherwise.
AzureIoTClient 30:20a85b733111 767 static bool is_device_credential_acceptable(const IOTHUB_DEVICE_CONFIG* device_config, AMQP_TRANSPORT_AUTHENTICATION_MODE preferred_authentication_mode)
AzureIoTClient 25:63f7d371c030 768 {
AzureIoTClient 30:20a85b733111 769 bool result;
AzureIoTClient 25:63f7d371c030 770
AzureIoTClient 30:20a85b733111 771 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_03_003: [IoTHubTransport_AMQP_Common_Register shall return NULL if both deviceKey and deviceSasToken are not NULL.]
AzureIoTClient 30:20a85b733111 772 if ((device_config->deviceSasToken != NULL) && (device_config->deviceKey != NULL))
AzureIoTClient 30:20a85b733111 773 {
AzureIoTClient 30:20a85b733111 774 LogError("Credential of device '%s' is not acceptable (must provide EITHER deviceSasToken OR deviceKey)", device_config->deviceId);
AzureIoTClient 30:20a85b733111 775 result = false;
AzureIoTClient 30:20a85b733111 776 }
AzureIoTClient 30:20a85b733111 777 else if (preferred_authentication_mode == AMQP_TRANSPORT_AUTHENTICATION_MODE_NOT_SET)
AzureIoTClient 26:ee14eed604f6 778 {
AzureIoTClient 30:20a85b733111 779 result = true;
AzureIoTClient 30:20a85b733111 780 }
AzureIoTClient 30:20a85b733111 781 else if (preferred_authentication_mode == AMQP_TRANSPORT_AUTHENTICATION_MODE_X509 && (device_config->deviceKey != NULL || device_config->deviceSasToken != NULL))
AzureIoTClient 30:20a85b733111 782 {
AzureIoTClient 30:20a85b733111 783 LogError("Credential of device '%s' is not acceptable (transport is using X509 certificate authentication, but device config contains deviceKey or sasToken)", device_config->deviceId);
AzureIoTClient 30:20a85b733111 784 result = false;
AzureIoTClient 30:20a85b733111 785 }
AzureIoTClient 30:20a85b733111 786 else if (preferred_authentication_mode != AMQP_TRANSPORT_AUTHENTICATION_MODE_X509 && (device_config->deviceKey == NULL && device_config->deviceSasToken == NULL))
AzureIoTClient 30:20a85b733111 787 {
AzureIoTClient 30:20a85b733111 788 LogError("Credential of device '%s' is not acceptable (transport is using CBS authentication, but device config does not contain deviceKey nor sasToken)", device_config->deviceId);
AzureIoTClient 30:20a85b733111 789 result = false;
AzureIoTClient 26:ee14eed604f6 790 }
AzureIoTClient 26:ee14eed604f6 791 else
AzureIoTClient 26:ee14eed604f6 792 {
AzureIoTClient 30:20a85b733111 793 result = true;
AzureIoTClient 26:ee14eed604f6 794 }
AzureIoTClient 25:63f7d371c030 795
AzureIoTClient 26:ee14eed604f6 796 return result;
AzureIoTClient 25:63f7d371c030 797 }
AzureIoTClient 25:63f7d371c030 798
AzureIoTClient 25:63f7d371c030 799
AzureIoTClient 30:20a85b733111 800
AzureIoTClient 30:20a85b733111 801 //---------- DoWork Helpers ----------//
AzureIoTClient 30:20a85b733111 802
AzureIoTClient 30:20a85b733111 803 static IOTHUB_MESSAGE_LIST* get_next_event_to_send(AMQP_TRANSPORT_DEVICE_INSTANCE* registered_device)
AzureIoTClient 30:20a85b733111 804 {
AzureIoTClient 30:20a85b733111 805 IOTHUB_MESSAGE_LIST* message;
AzureIoTClient 30:20a85b733111 806
AzureIoTClient 30:20a85b733111 807 if (!DList_IsListEmpty(registered_device->waiting_to_send))
AzureIoTClient 30:20a85b733111 808 {
AzureIoTClient 30:20a85b733111 809 PDLIST_ENTRY list_entry = registered_device->waiting_to_send->Flink;
AzureIoTClient 30:20a85b733111 810 message = containingRecord(list_entry, IOTHUB_MESSAGE_LIST, entry);
AzureIoTClient 30:20a85b733111 811 (void)DList_RemoveEntryList(list_entry);
AzureIoTClient 30:20a85b733111 812 }
AzureIoTClient 30:20a85b733111 813 else
AzureIoTClient 30:20a85b733111 814 {
AzureIoTClient 30:20a85b733111 815 message = NULL;
AzureIoTClient 30:20a85b733111 816 }
AzureIoTClient 30:20a85b733111 817
AzureIoTClient 30:20a85b733111 818 return message;
AzureIoTClient 30:20a85b733111 819 }
AzureIoTClient 30:20a85b733111 820
AzureIoTClient 30:20a85b733111 821 // @brief "Parses" the D2C_EVENT_SEND_RESULT (from iothubtransport_amqp_device module) into a IOTHUB_CLIENT_CONFIRMATION_RESULT.
AzureIoTClient 30:20a85b733111 822 static IOTHUB_CLIENT_CONFIRMATION_RESULT get_iothub_client_confirmation_result_from(D2C_EVENT_SEND_RESULT result)
AzureIoTClient 30:20a85b733111 823 {
AzureIoTClient 30:20a85b733111 824 IOTHUB_CLIENT_CONFIRMATION_RESULT iothub_send_result;
AzureIoTClient 30:20a85b733111 825
AzureIoTClient 30:20a85b733111 826 switch (result)
AzureIoTClient 30:20a85b733111 827 {
AzureIoTClient 30:20a85b733111 828 case D2C_EVENT_SEND_COMPLETE_RESULT_OK:
AzureIoTClient 30:20a85b733111 829 iothub_send_result = IOTHUB_CLIENT_CONFIRMATION_OK;
AzureIoTClient 30:20a85b733111 830 break;
AzureIoTClient 30:20a85b733111 831 case D2C_EVENT_SEND_COMPLETE_RESULT_ERROR_CANNOT_PARSE:
AzureIoTClient 30:20a85b733111 832 case D2C_EVENT_SEND_COMPLETE_RESULT_ERROR_FAIL_SENDING:
AzureIoTClient 30:20a85b733111 833 iothub_send_result = IOTHUB_CLIENT_CONFIRMATION_ERROR;
AzureIoTClient 30:20a85b733111 834 break;
AzureIoTClient 30:20a85b733111 835 case D2C_EVENT_SEND_COMPLETE_RESULT_ERROR_TIMEOUT:
AzureIoTClient 30:20a85b733111 836 iothub_send_result = IOTHUB_CLIENT_CONFIRMATION_MESSAGE_TIMEOUT;
AzureIoTClient 30:20a85b733111 837 break;
AzureIoTClient 30:20a85b733111 838 case D2C_EVENT_SEND_COMPLETE_RESULT_DEVICE_DESTROYED:
AzureIoTClient 30:20a85b733111 839 iothub_send_result = IOTHUB_CLIENT_CONFIRMATION_BECAUSE_DESTROY;
AzureIoTClient 30:20a85b733111 840 break;
AzureIoTClient 30:20a85b733111 841 case D2C_EVENT_SEND_COMPLETE_RESULT_ERROR_UNKNOWN:
AzureIoTClient 30:20a85b733111 842 default:
AzureIoTClient 30:20a85b733111 843 iothub_send_result = IOTHUB_CLIENT_CONFIRMATION_ERROR;
AzureIoTClient 30:20a85b733111 844 break;
AzureIoTClient 30:20a85b733111 845 }
AzureIoTClient 30:20a85b733111 846
AzureIoTClient 30:20a85b733111 847 return iothub_send_result;
AzureIoTClient 30:20a85b733111 848 }
AzureIoTClient 30:20a85b733111 849
AzureIoTClient 30:20a85b733111 850 // @brief
AzureIoTClient 30:20a85b733111 851 // Callback function for device_send_event_async.
AzureIoTClient 30:20a85b733111 852 static void on_event_send_complete(IOTHUB_MESSAGE_LIST* message, D2C_EVENT_SEND_RESULT result, void* context)
AzureIoTClient 30:20a85b733111 853 {
AzureIoTClient 30:20a85b733111 854 AMQP_TRANSPORT_DEVICE_INSTANCE* registered_device = (AMQP_TRANSPORT_DEVICE_INSTANCE*)context;
AzureIoTClient 30:20a85b733111 855
AzureIoTClient 30:20a85b733111 856 if (result != D2C_EVENT_SEND_COMPLETE_RESULT_OK && result != D2C_EVENT_SEND_COMPLETE_RESULT_DEVICE_DESTROYED)
AzureIoTClient 30:20a85b733111 857 {
AzureIoTClient 30:20a85b733111 858 registered_device->number_of_send_event_complete_failures++;
AzureIoTClient 30:20a85b733111 859 }
AzureIoTClient 30:20a85b733111 860 else
AzureIoTClient 30:20a85b733111 861 {
AzureIoTClient 30:20a85b733111 862 registered_device->number_of_send_event_complete_failures = 0;
AzureIoTClient 30:20a85b733111 863 }
AzureIoTClient 30:20a85b733111 864
AzureIoTClient 30:20a85b733111 865 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_056: [If `message->callback` is not NULL, it shall invoked with the `iothub_send_result`]
AzureIoTClient 30:20a85b733111 866 if (message->callback != NULL)
AzureIoTClient 30:20a85b733111 867 {
AzureIoTClient 30:20a85b733111 868 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_050: [If result is D2C_EVENT_SEND_COMPLETE_RESULT_OK, `iothub_send_result` shall be set using IOTHUB_CLIENT_CONFIRMATION_OK]
AzureIoTClient 30:20a85b733111 869 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_051: [If result is D2C_EVENT_SEND_COMPLETE_RESULT_ERROR_CANNOT_PARSE, `iothub_send_result` shall be set using IOTHUB_CLIENT_CONFIRMATION_ERROR]
AzureIoTClient 30:20a85b733111 870 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_052: [If result is D2C_EVENT_SEND_COMPLETE_RESULT_ERROR_FAIL_SENDING, `iothub_send_result` shall be set using IOTHUB_CLIENT_CONFIRMATION_ERROR]
AzureIoTClient 30:20a85b733111 871 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_053: [If result is D2C_EVENT_SEND_COMPLETE_RESULT_ERROR_TIMEOUT, `iothub_send_result` shall be set using IOTHUB_CLIENT_CONFIRMATION_MESSAGE_TIMEOUT]
AzureIoTClient 30:20a85b733111 872 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_054: [If result is D2C_EVENT_SEND_COMPLETE_RESULT_DEVICE_DESTROYED, `iothub_send_result` shall be set using IOTHUB_CLIENT_CONFIRMATION_BECAUSE_DESTROY]
AzureIoTClient 30:20a85b733111 873 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_055: [If result is D2C_EVENT_SEND_COMPLETE_RESULT_ERROR_UNKNOWN, `iothub_send_result` shall be set using IOTHUB_CLIENT_CONFIRMATION_ERROR]
AzureIoTClient 30:20a85b733111 874 IOTHUB_CLIENT_CONFIRMATION_RESULT iothub_send_result = get_iothub_client_confirmation_result_from(result);
AzureIoTClient 30:20a85b733111 875
AzureIoTClient 30:20a85b733111 876 message->callback(iothub_send_result, message->context);
AzureIoTClient 30:20a85b733111 877 }
AzureIoTClient 30:20a85b733111 878
AzureIoTClient 30:20a85b733111 879 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_057: [`message->messageHandle` shall be destroyed using IoTHubMessage_Destroy]
AzureIoTClient 30:20a85b733111 880 IoTHubMessage_Destroy(message->messageHandle);
AzureIoTClient 30:20a85b733111 881 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_058: [`message` shall be destroyed using free]
AzureIoTClient 30:20a85b733111 882 free(message);
AzureIoTClient 30:20a85b733111 883 }
AzureIoTClient 30:20a85b733111 884
AzureIoTClient 30:20a85b733111 885 // @brief
AzureIoTClient 30:20a85b733111 886 // Gets events from wait to send list and sends to service in the order they were added.
AzureIoTClient 30:20a85b733111 887 // @returns
AzureIoTClient 30:20a85b733111 888 // 0 if all events could be sent to the next layer successfully, non-zero otherwise.
AzureIoTClient 30:20a85b733111 889 static int send_pending_events(AMQP_TRANSPORT_DEVICE_INSTANCE* device_state)
AzureIoTClient 30:20a85b733111 890 {
AzureIoTClient 30:20a85b733111 891 int result;
AzureIoTClient 30:20a85b733111 892 IOTHUB_MESSAGE_LIST* message;
AzureIoTClient 30:20a85b733111 893
AzureIoTClient 30:20a85b733111 894 result = RESULT_OK;
AzureIoTClient 30:20a85b733111 895
AzureIoTClient 30:20a85b733111 896 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_047: [If the registered device is started, each event on `registered_device->wait_to_send_list` shall be removed from the list and sent using device_send_event_async()]
AzureIoTClient 30:20a85b733111 897 while ((message = get_next_event_to_send(device_state)) != NULL)
AzureIoTClient 30:20a85b733111 898 {
AzureIoTClient 30:20a85b733111 899 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_048: [device_send_event_async() shall be invoked passing `on_event_send_complete`]
AzureIoTClient 30:20a85b733111 900 if (device_send_event_async(device_state->device_handle, message, on_event_send_complete, device_state) != RESULT_OK)
AzureIoTClient 30:20a85b733111 901 {
AzureIoTClient 30:20a85b733111 902 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_049: [If device_send_event_async() fails, `on_event_send_complete` shall be invoked passing EVENT_SEND_COMPLETE_RESULT_ERROR_FAIL_SENDING and return]
AzureIoTClient 30:20a85b733111 903 LogError("Device '%s' failed to send message (device_send_event_async failed)", STRING_c_str(device_state->device_id));
AzureIoTClient 30:20a85b733111 904 result = __FAILURE__;
AzureIoTClient 30:20a85b733111 905
AzureIoTClient 30:20a85b733111 906 on_event_send_complete(message, D2C_EVENT_SEND_COMPLETE_RESULT_ERROR_FAIL_SENDING, device_state);
AzureIoTClient 30:20a85b733111 907 break;
AzureIoTClient 30:20a85b733111 908 }
AzureIoTClient 30:20a85b733111 909 }
AzureIoTClient 30:20a85b733111 910
AzureIoTClient 30:20a85b733111 911 return result;
AzureIoTClient 30:20a85b733111 912 }
AzureIoTClient 30:20a85b733111 913
AzureIoTClient 30:20a85b733111 914 // @brief
AzureIoTClient 30:20a85b733111 915 // Auxiliary function for the public DoWork API, performing DoWork activities (authenticate, messaging) for a specific device.
AzureIoTClient 30:20a85b733111 916 // @requires
AzureIoTClient 30:20a85b733111 917 // The transport to have a valid instance of AMQP_CONNECTION (from which to obtain SESSION_HANDLE and CBS_HANDLE)
AzureIoTClient 30:20a85b733111 918 // @returns
AzureIoTClient 30:20a85b733111 919 // 0 if no errors occur, non-zero otherwise.
AzureIoTClient 30:20a85b733111 920 static int IoTHubTransport_AMQP_Common_Device_DoWork(AMQP_TRANSPORT_DEVICE_INSTANCE* registered_device)
AzureIoTClient 30:20a85b733111 921 {
AzureIoTClient 30:20a85b733111 922 int result;
AzureIoTClient 30:20a85b733111 923
AzureIoTClient 30:20a85b733111 924 if (registered_device->device_state != DEVICE_STATE_STARTED)
AzureIoTClient 30:20a85b733111 925 {
AzureIoTClient 30:20a85b733111 926 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_036: [If the device state is DEVICE_STATE_STOPPED, it shall be started]
AzureIoTClient 30:20a85b733111 927 if (registered_device->device_state == DEVICE_STATE_STOPPED)
AzureIoTClient 30:20a85b733111 928 {
AzureIoTClient 30:20a85b733111 929 SESSION_HANDLE session_handle;
AzureIoTClient 30:20a85b733111 930 CBS_HANDLE cbs_handle = NULL;
AzureIoTClient 30:20a85b733111 931
AzureIoTClient 30:20a85b733111 932 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_039: [amqp_connection_get_session_handle() shall be invoked on `instance->connection`]
AzureIoTClient 30:20a85b733111 933 if (amqp_connection_get_session_handle(registered_device->transport_instance->amqp_connection, &session_handle) != RESULT_OK)
AzureIoTClient 30:20a85b733111 934 {
AzureIoTClient 30:20a85b733111 935 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_040: [If amqp_connection_get_session_handle() fails, IoTHubTransport_AMQP_Common_DoWork shall fail and return]
AzureIoTClient 30:20a85b733111 936 LogError("Failed performing DoWork for device '%s' (failed to get the amqp_connection session_handle)", STRING_c_str(registered_device->device_id));
AzureIoTClient 30:20a85b733111 937 result = __FAILURE__;
AzureIoTClient 30:20a85b733111 938 }
AzureIoTClient 30:20a85b733111 939 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_037: [If transport is using CBS authentication, amqp_connection_get_cbs_handle() shall be invoked on `instance->connection`]
AzureIoTClient 30:20a85b733111 940 else if (registered_device->transport_instance->preferred_authentication_mode == AMQP_TRANSPORT_AUTHENTICATION_MODE_CBS &&
AzureIoTClient 30:20a85b733111 941 amqp_connection_get_cbs_handle(registered_device->transport_instance->amqp_connection, &cbs_handle) != RESULT_OK)
AzureIoTClient 30:20a85b733111 942 {
AzureIoTClient 30:20a85b733111 943 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_038: [If amqp_connection_get_cbs_handle() fails, IoTHubTransport_AMQP_Common_DoWork shall fail and return]
AzureIoTClient 30:20a85b733111 944 LogError("Failed performing DoWork for device '%s' (failed to get the amqp_connection cbs_handle)", STRING_c_str(registered_device->device_id));
AzureIoTClient 30:20a85b733111 945 result = __FAILURE__;
AzureIoTClient 30:20a85b733111 946 }
AzureIoTClient 30:20a85b733111 947 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_041: [The device handle shall be started using device_start_async()]
AzureIoTClient 30:20a85b733111 948 else if (device_start_async(registered_device->device_handle, session_handle, cbs_handle) != RESULT_OK)
AzureIoTClient 30:20a85b733111 949 {
AzureIoTClient 30:20a85b733111 950 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_042: [If device_start_async() fails, IoTHubTransport_AMQP_Common_DoWork shall fail and skip to the next registered device]
AzureIoTClient 30:20a85b733111 951 LogError("Failed performing DoWork for device '%s' (failed to start device)", STRING_c_str(registered_device->device_id));
AzureIoTClient 30:20a85b733111 952 result = __FAILURE__;
AzureIoTClient 30:20a85b733111 953 }
AzureIoTClient 30:20a85b733111 954 else
AzureIoTClient 30:20a85b733111 955 {
AzureIoTClient 30:20a85b733111 956 result = RESULT_OK;
AzureIoTClient 30:20a85b733111 957 }
AzureIoTClient 30:20a85b733111 958 }
AzureIoTClient 30:20a85b733111 959 else if (registered_device->device_state == DEVICE_STATE_STARTING ||
AzureIoTClient 30:20a85b733111 960 registered_device->device_state == DEVICE_STATE_STOPPING)
AzureIoTClient 30:20a85b733111 961 {
AzureIoTClient 30:20a85b733111 962 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_043: [If the device handle is in state DEVICE_STATE_STARTING or DEVICE_STATE_STOPPING, it shall be checked for state change timeout]
AzureIoTClient 30:20a85b733111 963 bool is_timed_out;
AzureIoTClient 30:20a85b733111 964 if (is_timeout_reached(registered_device->time_of_last_state_change, registered_device->max_state_change_timeout_secs, &is_timed_out) != RESULT_OK)
AzureIoTClient 30:20a85b733111 965 {
AzureIoTClient 30:20a85b733111 966 LogError("Failed performing DoWork for device '%s' (failed tracking timeout of device %d state)", STRING_c_str(registered_device->device_id), registered_device->device_state);
AzureIoTClient 30:20a85b733111 967 registered_device->device_state = DEVICE_STATE_ERROR_AUTH; // if time could not be calculated, the worst must be assumed.
AzureIoTClient 30:20a85b733111 968 result = __FAILURE__;
AzureIoTClient 30:20a85b733111 969 }
AzureIoTClient 30:20a85b733111 970 else if (is_timed_out)
AzureIoTClient 30:20a85b733111 971 {
AzureIoTClient 30:20a85b733111 972 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_044: [If the device times out in state DEVICE_STATE_STARTING or DEVICE_STATE_STOPPING, the registered device shall be marked with failure]
AzureIoTClient 30:20a85b733111 973 LogError("Failed performing DoWork for device '%s' (device failed to start or stop within expected timeout)", STRING_c_str(registered_device->device_id));
AzureIoTClient 30:20a85b733111 974 registered_device->device_state = DEVICE_STATE_ERROR_AUTH; // this will cause device to be stopped bellow on the next call to this function.
AzureIoTClient 30:20a85b733111 975 result = __FAILURE__;
AzureIoTClient 30:20a85b733111 976 }
AzureIoTClient 30:20a85b733111 977 else
AzureIoTClient 30:20a85b733111 978 {
AzureIoTClient 30:20a85b733111 979 result = RESULT_OK;
AzureIoTClient 30:20a85b733111 980 }
AzureIoTClient 30:20a85b733111 981 }
AzureIoTClient 30:20a85b733111 982 else // i.e., DEVICE_STATE_ERROR_AUTH || DEVICE_STATE_ERROR_AUTH_TIMEOUT || DEVICE_STATE_ERROR_MSG
AzureIoTClient 30:20a85b733111 983 {
AzureIoTClient 30:20a85b733111 984 LogError("Failed performing DoWork for device '%s' (device reported state %d; number of previous failures: %d)",
AzureIoTClient 30:20a85b733111 985 STRING_c_str(registered_device->device_id), registered_device->device_state, registered_device->number_of_previous_failures);
AzureIoTClient 30:20a85b733111 986
AzureIoTClient 30:20a85b733111 987 registered_device->number_of_previous_failures++;
AzureIoTClient 30:20a85b733111 988
AzureIoTClient 30:20a85b733111 989 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_046: [If the device has failed for MAX_NUMBER_OF_DEVICE_FAILURES in a row, it shall trigger a connection retry on the transport]
AzureIoTClient 30:20a85b733111 990 if (registered_device->number_of_previous_failures >= MAX_NUMBER_OF_DEVICE_FAILURES)
AzureIoTClient 30:20a85b733111 991 {
AzureIoTClient 30:20a85b733111 992 result = __FAILURE__;
AzureIoTClient 30:20a85b733111 993 }
AzureIoTClient 30:20a85b733111 994 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_045: [If the registered device has a failure, it shall be stopped using device_stop()]
AzureIoTClient 30:20a85b733111 995 else if (device_stop(registered_device->device_handle) != RESULT_OK)
AzureIoTClient 30:20a85b733111 996 {
AzureIoTClient 30:20a85b733111 997 LogError("Failed to stop reset device '%s' (device_stop failed)", STRING_c_str(registered_device->device_id));
AzureIoTClient 30:20a85b733111 998 result = __FAILURE__;
AzureIoTClient 30:20a85b733111 999 }
AzureIoTClient 30:20a85b733111 1000 else
AzureIoTClient 30:20a85b733111 1001 {
AzureIoTClient 30:20a85b733111 1002 result = RESULT_OK;
AzureIoTClient 30:20a85b733111 1003 }
AzureIoTClient 30:20a85b733111 1004 }
AzureIoTClient 30:20a85b733111 1005 }
AzureIoTClient 30:20a85b733111 1006 #ifdef WIP_C2D_METHODS_AMQP /* This feature is WIP, do not use yet */
AzureIoTClient 30:20a85b733111 1007 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_01_031: [ Once the device is authenticated, `iothubtransportamqp_methods_subscribe` shall be invoked (subsequent DoWork calls shall not call it if already subscribed). ]
AzureIoTClient 30:20a85b733111 1008 else if (registered_device->subscribe_methods_needed &&
AzureIoTClient 30:20a85b733111 1009 !registered_device->subscribed_for_methods &&
AzureIoTClient 30:20a85b733111 1010 subscribe_methods(registered_device) != RESULT_OK)
AzureIoTClient 30:20a85b733111 1011 {
AzureIoTClient 30:20a85b733111 1012 LogError("Failed performing DoWork for device '%s' (failed registering for device methods)", STRING_c_str(registered_device->device_id));
AzureIoTClient 30:20a85b733111 1013 registered_device->number_of_previous_failures++;
AzureIoTClient 30:20a85b733111 1014 result = __FAILURE__;
AzureIoTClient 30:20a85b733111 1015 }
AzureIoTClient 30:20a85b733111 1016 #endif
AzureIoTClient 30:20a85b733111 1017 else
AzureIoTClient 30:20a85b733111 1018 {
AzureIoTClient 30:20a85b733111 1019 if (send_pending_events(registered_device) != RESULT_OK)
AzureIoTClient 30:20a85b733111 1020 {
AzureIoTClient 30:20a85b733111 1021 LogError("Failed performing DoWork for device '%s' (failed sending pending events)", STRING_c_str(registered_device->device_id));
AzureIoTClient 30:20a85b733111 1022 registered_device->number_of_previous_failures++;
AzureIoTClient 30:20a85b733111 1023 result = __FAILURE__;
AzureIoTClient 30:20a85b733111 1024 }
AzureIoTClient 30:20a85b733111 1025 else
AzureIoTClient 30:20a85b733111 1026 {
AzureIoTClient 30:20a85b733111 1027 registered_device->number_of_previous_failures = 0;
AzureIoTClient 30:20a85b733111 1028 result = RESULT_OK;
AzureIoTClient 30:20a85b733111 1029 }
AzureIoTClient 30:20a85b733111 1030 }
AzureIoTClient 30:20a85b733111 1031
AzureIoTClient 30:20a85b733111 1032 // No harm in invoking this as API will simply exit if the state is not "started".
AzureIoTClient 30:20a85b733111 1033 device_do_work(registered_device->device_handle);
AzureIoTClient 30:20a85b733111 1034
AzureIoTClient 30:20a85b733111 1035 return result;
AzureIoTClient 30:20a85b733111 1036 }
AzureIoTClient 30:20a85b733111 1037
AzureIoTClient 30:20a85b733111 1038
AzureIoTClient 30:20a85b733111 1039 //---------- SetOption-ish Helpers ----------//
AzureIoTClient 30:20a85b733111 1040
AzureIoTClient 30:20a85b733111 1041 // @brief
AzureIoTClient 30:20a85b733111 1042 // Gets all the device-specific options and replicates them into this new registered device.
AzureIoTClient 30:20a85b733111 1043 // @returns
AzureIoTClient 30:20a85b733111 1044 // 0 if the function succeeds, non-zero otherwise.
AzureIoTClient 30:20a85b733111 1045 static int replicate_device_options_to(AMQP_TRANSPORT_DEVICE_INSTANCE* dev_instance, DEVICE_AUTH_MODE auth_mode)
AzureIoTClient 30:20a85b733111 1046 {
AzureIoTClient 30:20a85b733111 1047 int result;
AzureIoTClient 30:20a85b733111 1048
AzureIoTClient 30:20a85b733111 1049 if (device_set_option(
AzureIoTClient 30:20a85b733111 1050 dev_instance->device_handle,
AzureIoTClient 30:20a85b733111 1051 DEVICE_OPTION_EVENT_SEND_TIMEOUT_SECS,
AzureIoTClient 30:20a85b733111 1052 &dev_instance->transport_instance->option_send_event_timeout_secs) != RESULT_OK)
AzureIoTClient 30:20a85b733111 1053 {
AzureIoTClient 30:20a85b733111 1054 LogError("Failed to apply option DEVICE_OPTION_EVENT_SEND_TIMEOUT_SECS to device '%s' (device_set_option failed)", STRING_c_str(dev_instance->device_id));
AzureIoTClient 30:20a85b733111 1055 result = __FAILURE__;
AzureIoTClient 30:20a85b733111 1056 }
AzureIoTClient 30:20a85b733111 1057 else if (auth_mode == DEVICE_AUTH_MODE_CBS)
AzureIoTClient 30:20a85b733111 1058 {
AzureIoTClient 30:20a85b733111 1059 if (device_set_option(
AzureIoTClient 30:20a85b733111 1060 dev_instance->device_handle,
AzureIoTClient 30:20a85b733111 1061 DEVICE_OPTION_CBS_REQUEST_TIMEOUT_SECS,
AzureIoTClient 30:20a85b733111 1062 &dev_instance->transport_instance->option_cbs_request_timeout_secs) != RESULT_OK)
AzureIoTClient 30:20a85b733111 1063 {
AzureIoTClient 30:20a85b733111 1064 LogError("Failed to apply option DEVICE_OPTION_CBS_REQUEST_TIMEOUT_SECS to device '%s' (device_set_option failed)", STRING_c_str(dev_instance->device_id));
AzureIoTClient 30:20a85b733111 1065 result = __FAILURE__;
AzureIoTClient 30:20a85b733111 1066 }
AzureIoTClient 30:20a85b733111 1067 else if (device_set_option(
AzureIoTClient 30:20a85b733111 1068 dev_instance->device_handle,
AzureIoTClient 30:20a85b733111 1069 DEVICE_OPTION_SAS_TOKEN_LIFETIME_SECS,
AzureIoTClient 30:20a85b733111 1070 &dev_instance->transport_instance->option_sas_token_lifetime_secs) != RESULT_OK)
AzureIoTClient 30:20a85b733111 1071 {
AzureIoTClient 30:20a85b733111 1072 LogError("Failed to apply option DEVICE_OPTION_SAS_TOKEN_LIFETIME_SECS to device '%s' (device_set_option failed)", STRING_c_str(dev_instance->device_id));
AzureIoTClient 30:20a85b733111 1073 result = __FAILURE__;
AzureIoTClient 30:20a85b733111 1074 }
AzureIoTClient 30:20a85b733111 1075 else if (device_set_option(
AzureIoTClient 30:20a85b733111 1076 dev_instance->device_handle,
AzureIoTClient 30:20a85b733111 1077 DEVICE_OPTION_SAS_TOKEN_REFRESH_TIME_SECS,
AzureIoTClient 30:20a85b733111 1078 &dev_instance->transport_instance->option_sas_token_refresh_time_secs) != RESULT_OK)
AzureIoTClient 30:20a85b733111 1079 {
AzureIoTClient 30:20a85b733111 1080 LogError("Failed to apply option DEVICE_OPTION_SAS_TOKEN_REFRESH_TIME_SECS to device '%s' (device_set_option failed)", STRING_c_str(dev_instance->device_id));
AzureIoTClient 30:20a85b733111 1081 result = __FAILURE__;
AzureIoTClient 30:20a85b733111 1082 }
AzureIoTClient 30:20a85b733111 1083 else
AzureIoTClient 30:20a85b733111 1084 {
AzureIoTClient 30:20a85b733111 1085 result = RESULT_OK;
AzureIoTClient 30:20a85b733111 1086 }
AzureIoTClient 30:20a85b733111 1087 }
AzureIoTClient 30:20a85b733111 1088 else
AzureIoTClient 30:20a85b733111 1089 {
AzureIoTClient 30:20a85b733111 1090 result = RESULT_OK;
AzureIoTClient 30:20a85b733111 1091 }
AzureIoTClient 30:20a85b733111 1092
AzureIoTClient 30:20a85b733111 1093 return result;
AzureIoTClient 30:20a85b733111 1094 }
AzureIoTClient 30:20a85b733111 1095
AzureIoTClient 30:20a85b733111 1096 // @brief
AzureIoTClient 30:20a85b733111 1097 // Translates from the option names supported by iothubtransport_amqp_common to the ones supported by iothubtransport_amqp_device.
AzureIoTClient 30:20a85b733111 1098 static const char* get_device_option_name_from(const char* iothubclient_option_name)
AzureIoTClient 30:20a85b733111 1099 {
AzureIoTClient 30:20a85b733111 1100 const char* device_option_name;
AzureIoTClient 30:20a85b733111 1101
AzureIoTClient 30:20a85b733111 1102 if (strcmp(OPTION_SAS_TOKEN_LIFETIME, iothubclient_option_name) == 0)
AzureIoTClient 30:20a85b733111 1103 {
AzureIoTClient 30:20a85b733111 1104 device_option_name = DEVICE_OPTION_SAS_TOKEN_LIFETIME_SECS;
AzureIoTClient 30:20a85b733111 1105 }
AzureIoTClient 30:20a85b733111 1106 else if (strcmp(OPTION_SAS_TOKEN_REFRESH_TIME, iothubclient_option_name) == 0)
AzureIoTClient 30:20a85b733111 1107 {
AzureIoTClient 30:20a85b733111 1108 device_option_name = DEVICE_OPTION_SAS_TOKEN_REFRESH_TIME_SECS;
AzureIoTClient 30:20a85b733111 1109 }
AzureIoTClient 30:20a85b733111 1110 else if (strcmp(OPTION_CBS_REQUEST_TIMEOUT, iothubclient_option_name) == 0)
AzureIoTClient 30:20a85b733111 1111 {
AzureIoTClient 30:20a85b733111 1112 device_option_name = DEVICE_OPTION_CBS_REQUEST_TIMEOUT_SECS;
AzureIoTClient 30:20a85b733111 1113 }
AzureIoTClient 30:20a85b733111 1114 else if (strcmp(OPTION_EVENT_SEND_TIMEOUT_SECS, iothubclient_option_name) == 0)
AzureIoTClient 30:20a85b733111 1115 {
AzureIoTClient 30:20a85b733111 1116 device_option_name = DEVICE_OPTION_EVENT_SEND_TIMEOUT_SECS;
AzureIoTClient 30:20a85b733111 1117 }
AzureIoTClient 30:20a85b733111 1118 else
AzureIoTClient 30:20a85b733111 1119 {
AzureIoTClient 30:20a85b733111 1120 device_option_name = NULL;
AzureIoTClient 30:20a85b733111 1121 }
AzureIoTClient 30:20a85b733111 1122
AzureIoTClient 30:20a85b733111 1123 return device_option_name;
AzureIoTClient 30:20a85b733111 1124 }
AzureIoTClient 30:20a85b733111 1125
AzureIoTClient 30:20a85b733111 1126 // @brief
AzureIoTClient 30:20a85b733111 1127 // Auxiliary function invoked by IoTHubTransport_AMQP_Common_SetOption to set an option on every registered device.
AzureIoTClient 30:20a85b733111 1128 // @returns
AzureIoTClient 30:20a85b733111 1129 // 0 if it succeeds, non-zero otherwise.
AzureIoTClient 30:20a85b733111 1130 static int IoTHubTransport_AMQP_Common_Device_SetOption(TRANSPORT_LL_HANDLE handle, const char* option, void* value)
AzureIoTClient 30:20a85b733111 1131 {
AzureIoTClient 30:20a85b733111 1132 int result;
AzureIoTClient 30:20a85b733111 1133 const char* device_option;
AzureIoTClient 30:20a85b733111 1134
AzureIoTClient 30:20a85b733111 1135 if ((device_option = get_device_option_name_from(option)) == NULL)
AzureIoTClient 30:20a85b733111 1136 {
AzureIoTClient 30:20a85b733111 1137 LogError("failed setting option '%s' to registered device (could not match name to options supported by device)", option);
AzureIoTClient 30:20a85b733111 1138 result = __FAILURE__;
AzureIoTClient 30:20a85b733111 1139 }
AzureIoTClient 30:20a85b733111 1140 else
AzureIoTClient 30:20a85b733111 1141 {
AzureIoTClient 30:20a85b733111 1142 AMQP_TRANSPORT_INSTANCE* instance = (AMQP_TRANSPORT_INSTANCE*)handle;
AzureIoTClient 30:20a85b733111 1143 result = RESULT_OK;
AzureIoTClient 30:20a85b733111 1144
AzureIoTClient 30:20a85b733111 1145 LIST_ITEM_HANDLE list_item = singlylinkedlist_get_head_item(instance->registered_devices);
AzureIoTClient 30:20a85b733111 1146
AzureIoTClient 30:20a85b733111 1147 while (list_item != NULL)
AzureIoTClient 30:20a85b733111 1148 {
AzureIoTClient 30:20a85b733111 1149 AMQP_TRANSPORT_DEVICE_INSTANCE* registered_device;
AzureIoTClient 30:20a85b733111 1150
AzureIoTClient 30:20a85b733111 1151 if ((registered_device = (AMQP_TRANSPORT_DEVICE_INSTANCE*)singlylinkedlist_item_get_value(list_item)) == NULL)
AzureIoTClient 30:20a85b733111 1152 {
AzureIoTClient 30:20a85b733111 1153 LogError("failed setting option '%s' to registered device (singlylinkedlist_item_get_value failed)", option);
AzureIoTClient 30:20a85b733111 1154 result = __FAILURE__;
AzureIoTClient 30:20a85b733111 1155 break;
AzureIoTClient 30:20a85b733111 1156 }
AzureIoTClient 30:20a85b733111 1157 else if (device_set_option(registered_device->device_handle, device_option, value) != RESULT_OK)
AzureIoTClient 30:20a85b733111 1158 {
AzureIoTClient 30:20a85b733111 1159 LogError("failed setting option '%s' to registered device '%s' (device_set_option failed)",
AzureIoTClient 30:20a85b733111 1160 option, STRING_c_str(registered_device->device_id));
AzureIoTClient 30:20a85b733111 1161 result = __FAILURE__;
AzureIoTClient 30:20a85b733111 1162 break;
AzureIoTClient 30:20a85b733111 1163 }
AzureIoTClient 30:20a85b733111 1164
AzureIoTClient 30:20a85b733111 1165 list_item = singlylinkedlist_get_next_item(list_item);
AzureIoTClient 30:20a85b733111 1166 }
AzureIoTClient 30:20a85b733111 1167 }
AzureIoTClient 30:20a85b733111 1168
AzureIoTClient 30:20a85b733111 1169 return result;
AzureIoTClient 30:20a85b733111 1170 }
AzureIoTClient 30:20a85b733111 1171
AzureIoTClient 30:20a85b733111 1172 static void internal_destroy_instance(AMQP_TRANSPORT_INSTANCE* instance)
AzureIoTClient 30:20a85b733111 1173 {
AzureIoTClient 30:20a85b733111 1174 if (instance != NULL)
AzureIoTClient 30:20a85b733111 1175 {
AzureIoTClient 32:babfd49032ff 1176 update_state(instance, AMQP_TRANSPORT_STATE_BEING_DESTROYED);
AzureIoTClient 32:babfd49032ff 1177
AzureIoTClient 30:20a85b733111 1178 if (instance->registered_devices != NULL)
AzureIoTClient 30:20a85b733111 1179 {
AzureIoTClient 30:20a85b733111 1180 LIST_ITEM_HANDLE list_item = singlylinkedlist_get_head_item(instance->registered_devices);
AzureIoTClient 30:20a85b733111 1181
AzureIoTClient 30:20a85b733111 1182 while (list_item != NULL)
AzureIoTClient 30:20a85b733111 1183 {
AzureIoTClient 30:20a85b733111 1184 AMQP_TRANSPORT_DEVICE_INSTANCE* registered_device = (AMQP_TRANSPORT_DEVICE_INSTANCE*)singlylinkedlist_item_get_value(list_item);
AzureIoTClient 30:20a85b733111 1185 list_item = singlylinkedlist_get_next_item(list_item);
AzureIoTClient 30:20a85b733111 1186 IoTHubTransport_AMQP_Common_Unregister(registered_device);
AzureIoTClient 30:20a85b733111 1187 }
AzureIoTClient 30:20a85b733111 1188
AzureIoTClient 30:20a85b733111 1189 singlylinkedlist_destroy(instance->registered_devices);
AzureIoTClient 30:20a85b733111 1190 }
AzureIoTClient 30:20a85b733111 1191
AzureIoTClient 30:20a85b733111 1192 if (instance->amqp_connection != NULL)
AzureIoTClient 30:20a85b733111 1193 {
AzureIoTClient 30:20a85b733111 1194 amqp_connection_destroy(instance->amqp_connection);
AzureIoTClient 30:20a85b733111 1195 }
AzureIoTClient 30:20a85b733111 1196
AzureIoTClient 30:20a85b733111 1197 destroy_underlying_io_transport(instance);
AzureIoTClient 30:20a85b733111 1198 destroy_underlying_io_transport_options(instance);
AzureIoTClient 32:babfd49032ff 1199 retry_control_destroy(instance->connection_retry_control);
AzureIoTClient 30:20a85b733111 1200
AzureIoTClient 30:20a85b733111 1201 STRING_delete(instance->iothub_host_fqdn);
AzureIoTClient 30:20a85b733111 1202
AzureIoTClient 32:babfd49032ff 1203 /* SRS_IOTHUBTRANSPORT_AMQP_COMMON_01_043: [ `IoTHubTransport_AMQP_Common_Destroy` shall free the stored proxy options. ]*/
AzureIoTClient 31:adadaef857c1 1204 free_proxy_data(instance);
AzureIoTClient 31:adadaef857c1 1205
AzureIoTClient 30:20a85b733111 1206 free(instance);
AzureIoTClient 30:20a85b733111 1207 }
AzureIoTClient 30:20a85b733111 1208 }
AzureIoTClient 30:20a85b733111 1209
AzureIoTClient 32:babfd49032ff 1210 // ---------- SendMessageDisposition helpers ---------- //
AzureIoTClient 32:babfd49032ff 1211
AzureIoTClient 32:babfd49032ff 1212 static DEVICE_MESSAGE_DISPOSITION_INFO* create_device_message_disposition_info_from(MESSAGE_CALLBACK_INFO* message_data)
AzureIoTClient 32:babfd49032ff 1213 {
AzureIoTClient 32:babfd49032ff 1214 DEVICE_MESSAGE_DISPOSITION_INFO* result;
AzureIoTClient 32:babfd49032ff 1215
AzureIoTClient 32:babfd49032ff 1216 if ((result = (DEVICE_MESSAGE_DISPOSITION_INFO*)malloc(sizeof(DEVICE_MESSAGE_DISPOSITION_INFO))) == NULL)
AzureIoTClient 32:babfd49032ff 1217 {
AzureIoTClient 32:babfd49032ff 1218 LogError("Failed creating DEVICE_MESSAGE_DISPOSITION_INFO (malloc failed)");
AzureIoTClient 32:babfd49032ff 1219 }
AzureIoTClient 32:babfd49032ff 1220 else if (mallocAndStrcpy_s(&result->source, message_data->transportContext->link_name) != RESULT_OK)
AzureIoTClient 32:babfd49032ff 1221 {
AzureIoTClient 32:babfd49032ff 1222 LogError("Failed creating DEVICE_MESSAGE_DISPOSITION_INFO (mallocAndStrcpy_s failed)");
AzureIoTClient 32:babfd49032ff 1223 free(result);
AzureIoTClient 32:babfd49032ff 1224 result = NULL;
AzureIoTClient 32:babfd49032ff 1225 }
AzureIoTClient 32:babfd49032ff 1226 else
AzureIoTClient 32:babfd49032ff 1227 {
AzureIoTClient 32:babfd49032ff 1228 result->message_id = message_data->transportContext->message_id;
AzureIoTClient 32:babfd49032ff 1229 }
AzureIoTClient 32:babfd49032ff 1230
AzureIoTClient 32:babfd49032ff 1231 return result;
AzureIoTClient 32:babfd49032ff 1232 }
AzureIoTClient 32:babfd49032ff 1233
AzureIoTClient 32:babfd49032ff 1234 static void destroy_device_message_disposition_info(DEVICE_MESSAGE_DISPOSITION_INFO* device_message_disposition_info)
AzureIoTClient 32:babfd49032ff 1235 {
AzureIoTClient 32:babfd49032ff 1236 free(device_message_disposition_info->source);
AzureIoTClient 32:babfd49032ff 1237 free(device_message_disposition_info);
AzureIoTClient 32:babfd49032ff 1238 }
AzureIoTClient 32:babfd49032ff 1239
AzureIoTClient 30:20a85b733111 1240
AzureIoTClient 30:20a85b733111 1241 // ---------- API functions ---------- //
AzureIoTClient 25:63f7d371c030 1242
AzureIoTClient 25:63f7d371c030 1243 TRANSPORT_LL_HANDLE IoTHubTransport_AMQP_Common_Create(const IOTHUBTRANSPORT_CONFIG* config, AMQP_GET_IO_TRANSPORT get_io_transport)
AzureIoTClient 25:63f7d371c030 1244 {
AzureIoTClient 30:20a85b733111 1245 TRANSPORT_LL_HANDLE result;
AzureIoTClient 25:63f7d371c030 1246
AzureIoTClient 30:20a85b733111 1247 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_001: [If `config` or `config->upperConfig` or `get_io_transport` are NULL then IoTHubTransport_AMQP_Common_Create shall fail and return NULL.]
AzureIoTClient 30:20a85b733111 1248 if (config == NULL || config->upperConfig == NULL || get_io_transport == NULL)
AzureIoTClient 30:20a85b733111 1249 {
AzureIoTClient 30:20a85b733111 1250 LogError("IoTHub AMQP client transport null configuration parameter (config=%p, get_io_transport=%p).", config, get_io_transport);
AzureIoTClient 30:20a85b733111 1251 result = NULL;
AzureIoTClient 30:20a85b733111 1252 }
AzureIoTClient 30:20a85b733111 1253 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_002: [IoTHubTransport_AMQP_Common_Create shall fail and return NULL if `config->upperConfig->protocol` is NULL]
AzureIoTClient 30:20a85b733111 1254 else if (config->upperConfig->protocol == NULL)
AzureIoTClient 30:20a85b733111 1255 {
AzureIoTClient 30:20a85b733111 1256 LogError("Failed to create the AMQP transport common instance (NULL parameter received: protocol=%p, iotHubName=%p, iotHubSuffix=%p)",
AzureIoTClient 30:20a85b733111 1257 config->upperConfig->protocol, config->upperConfig->iotHubName, config->upperConfig->iotHubSuffix);
AzureIoTClient 30:20a85b733111 1258 result = NULL;
AzureIoTClient 30:20a85b733111 1259 }
AzureIoTClient 30:20a85b733111 1260 else
AzureIoTClient 30:20a85b733111 1261 {
AzureIoTClient 30:20a85b733111 1262 AMQP_TRANSPORT_INSTANCE* instance;
AzureIoTClient 25:63f7d371c030 1263
AzureIoTClient 30:20a85b733111 1264 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_003: [Memory shall be allocated for the transport's internal state structure (`instance`)]
AzureIoTClient 30:20a85b733111 1265 if ((instance = (AMQP_TRANSPORT_INSTANCE*)malloc(sizeof(AMQP_TRANSPORT_INSTANCE))) == NULL)
AzureIoTClient 30:20a85b733111 1266 {
AzureIoTClient 30:20a85b733111 1267 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_004: [If malloc() fails, IoTHubTransport_AMQP_Common_Create shall fail and return NULL]
AzureIoTClient 30:20a85b733111 1268 LogError("Could not allocate AMQP transport state (malloc failed)");
AzureIoTClient 30:20a85b733111 1269 result = NULL;
AzureIoTClient 30:20a85b733111 1270 }
AzureIoTClient 30:20a85b733111 1271 else
AzureIoTClient 30:20a85b733111 1272 {
AzureIoTClient 30:20a85b733111 1273 memset(instance, 0, sizeof(AMQP_TRANSPORT_INSTANCE));
AzureIoTClient 32:babfd49032ff 1274 instance->amqp_connection_state = AMQP_CONNECTION_STATE_CLOSED;
AzureIoTClient 32:babfd49032ff 1275 instance->preferred_authentication_mode = AMQP_TRANSPORT_AUTHENTICATION_MODE_NOT_SET;
AzureIoTClient 32:babfd49032ff 1276 instance->state = AMQP_TRANSPORT_STATE_NOT_CONNECTED;
AzureIoTClient 25:63f7d371c030 1277
AzureIoTClient 32:babfd49032ff 1278 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_124: [`instance->connection_retry_control` shall be set using retry_control_create(), passing defaults EXPONENTIAL_BACKOFF_WITH_JITTER and 0]
AzureIoTClient 32:babfd49032ff 1279 if ((instance->connection_retry_control = retry_control_create(DEFAULT_RETRY_POLICY, DEFAULT_MAX_RETRY_TIME_IN_SECS)) == NULL)
AzureIoTClient 32:babfd49032ff 1280 {
AzureIoTClient 32:babfd49032ff 1281 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_125: [If retry_control_create() fails, IoTHubTransport_AMQP_Common_Create shall fail and return NULL]
AzureIoTClient 32:babfd49032ff 1282 LogError("Failed to create the connection retry control.");
AzureIoTClient 32:babfd49032ff 1283 result = NULL;
AzureIoTClient 32:babfd49032ff 1284 }
AzureIoTClient 30:20a85b733111 1285 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_005: [If `config->upperConfig->protocolGatewayHostName` is NULL, `instance->iothub_target_fqdn` shall be set as `config->upperConfig->iotHubName` + "." + `config->upperConfig->iotHubSuffix`]
AzureIoTClient 30:20a85b733111 1286 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_006: [If `config->upperConfig->protocolGatewayHostName` is not NULL, `instance->iothub_target_fqdn` shall be set with a copy of it]
AzureIoTClient 32:babfd49032ff 1287 else if ((instance->iothub_host_fqdn = get_target_iothub_fqdn(config)) == NULL)
AzureIoTClient 30:20a85b733111 1288 {
AzureIoTClient 30:20a85b733111 1289 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_007: [If `instance->iothub_target_fqdn` fails to be set, IoTHubTransport_AMQP_Common_Create shall fail and return NULL]
AzureIoTClient 30:20a85b733111 1290 LogError("Failed to obtain the iothub target fqdn.");
AzureIoTClient 30:20a85b733111 1291 result = NULL;
AzureIoTClient 30:20a85b733111 1292 }
AzureIoTClient 30:20a85b733111 1293 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_008: [`instance->registered_devices` shall be set using singlylinkedlist_create()]
AzureIoTClient 30:20a85b733111 1294 else if ((instance->registered_devices = singlylinkedlist_create()) == NULL)
AzureIoTClient 30:20a85b733111 1295 {
AzureIoTClient 30:20a85b733111 1296 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_009: [If singlylinkedlist_create() fails, IoTHubTransport_AMQP_Common_Create shall fail and return NULL]
AzureIoTClient 30:20a85b733111 1297 LogError("Failed to initialize the internal list of registered devices (singlylinkedlist_create failed)");
AzureIoTClient 30:20a85b733111 1298 result = NULL;
AzureIoTClient 30:20a85b733111 1299 }
AzureIoTClient 30:20a85b733111 1300 else
AzureIoTClient 30:20a85b733111 1301 {
AzureIoTClient 30:20a85b733111 1302 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_010: [`get_io_transport` shall be saved on `instance->underlying_io_transport_provider`]
AzureIoTClient 30:20a85b733111 1303 instance->underlying_io_transport_provider = get_io_transport;
AzureIoTClient 32:babfd49032ff 1304 instance->is_trace_on = false;
AzureIoTClient 30:20a85b733111 1305 instance->option_sas_token_lifetime_secs = DEFAULT_SAS_TOKEN_LIFETIME_SECS;
AzureIoTClient 30:20a85b733111 1306 instance->option_sas_token_refresh_time_secs = DEFAULT_SAS_TOKEN_REFRESH_TIME_SECS;
AzureIoTClient 30:20a85b733111 1307 instance->option_cbs_request_timeout_secs = DEFAULT_CBS_REQUEST_TIMEOUT_SECS;
AzureIoTClient 30:20a85b733111 1308 instance->option_send_event_timeout_secs = DEFAULT_EVENT_SEND_TIMEOUT_SECS;
AzureIoTClient 32:babfd49032ff 1309
AzureIoTClient 30:20a85b733111 1310 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_012: [If IoTHubTransport_AMQP_Common_Create succeeds it shall return a pointer to `instance`.]
AzureIoTClient 30:20a85b733111 1311 result = (TRANSPORT_LL_HANDLE)instance;
AzureIoTClient 30:20a85b733111 1312 }
AzureIoTClient 25:63f7d371c030 1313
AzureIoTClient 30:20a85b733111 1314 if (result == NULL)
AzureIoTClient 30:20a85b733111 1315 {
AzureIoTClient 30:20a85b733111 1316 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_011: [If IoTHubTransport_AMQP_Common_Create fails it shall free any memory it allocated]
AzureIoTClient 30:20a85b733111 1317 internal_destroy_instance(instance);
AzureIoTClient 30:20a85b733111 1318 }
AzureIoTClient 30:20a85b733111 1319 }
AzureIoTClient 30:20a85b733111 1320 }
AzureIoTClient 25:63f7d371c030 1321
AzureIoTClient 26:ee14eed604f6 1322 return result;
AzureIoTClient 25:63f7d371c030 1323 }
AzureIoTClient 25:63f7d371c030 1324
AzureIoTClient 25:63f7d371c030 1325 IOTHUB_PROCESS_ITEM_RESULT IoTHubTransport_AMQP_Common_ProcessItem(TRANSPORT_LL_HANDLE handle, IOTHUB_IDENTITY_TYPE item_type, IOTHUB_IDENTITY_INFO* iothub_item)
AzureIoTClient 25:63f7d371c030 1326 {
AzureIoTClient 25:63f7d371c030 1327 (void)handle;
AzureIoTClient 25:63f7d371c030 1328 (void)item_type;
AzureIoTClient 25:63f7d371c030 1329 (void)iothub_item;
AzureIoTClient 25:63f7d371c030 1330 LogError("Currently Not Supported.");
AzureIoTClient 28:dc01bcb2cb01 1331 return IOTHUB_PROCESS_ERROR;
AzureIoTClient 25:63f7d371c030 1332 }
AzureIoTClient 25:63f7d371c030 1333
AzureIoTClient 25:63f7d371c030 1334 void IoTHubTransport_AMQP_Common_DoWork(TRANSPORT_LL_HANDLE handle, IOTHUB_CLIENT_LL_HANDLE iotHubClientHandle)
AzureIoTClient 25:63f7d371c030 1335 {
AzureIoTClient 30:20a85b733111 1336 (void)iotHubClientHandle; // unused as of now.
AzureIoTClient 30:20a85b733111 1337
AzureIoTClient 30:20a85b733111 1338 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_016: [If `handle` is NULL, IoTHubTransport_AMQP_Common_DoWork shall return without doing any work]
AzureIoTClient 25:63f7d371c030 1339 if (handle == NULL)
AzureIoTClient 25:63f7d371c030 1340 {
AzureIoTClient 25:63f7d371c030 1341 LogError("IoTHubClient DoWork failed: transport handle parameter is NULL.");
AzureIoTClient 25:63f7d371c030 1342 }
AzureIoTClient 25:63f7d371c030 1343 else
AzureIoTClient 25:63f7d371c030 1344 {
AzureIoTClient 30:20a85b733111 1345 AMQP_TRANSPORT_INSTANCE* transport_instance = (AMQP_TRANSPORT_INSTANCE*)handle;
AzureIoTClient 30:20a85b733111 1346 LIST_ITEM_HANDLE list_item;
AzureIoTClient 30:20a85b733111 1347
AzureIoTClient 32:babfd49032ff 1348 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_017: [If `instance->state` is `RECONNECTION_REQUIRED`, IoTHubTransport_AMQP_Common_DoWork shall attempt to trigger the connection-retry logic and return]
AzureIoTClient 32:babfd49032ff 1349 if (transport_instance->state == AMQP_TRANSPORT_STATE_RECONNECTION_REQUIRED)
AzureIoTClient 30:20a85b733111 1350 {
AzureIoTClient 32:babfd49032ff 1351 RETRY_ACTION retry_action;
AzureIoTClient 32:babfd49032ff 1352
AzureIoTClient 32:babfd49032ff 1353 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_126: [The connection retry shall be attempted only if retry_control_should_retry() returns RETRY_ACTION_NOW, or if it fails]
AzureIoTClient 32:babfd49032ff 1354 if (retry_control_should_retry(transport_instance->connection_retry_control, &retry_action) != RESULT_OK)
AzureIoTClient 32:babfd49032ff 1355 {
AzureIoTClient 32:babfd49032ff 1356 LogError("retry_control_should_retry() failed; assuming immediate connection retry for safety.");
AzureIoTClient 32:babfd49032ff 1357 retry_action = RETRY_ACTION_RETRY_NOW;
AzureIoTClient 32:babfd49032ff 1358 }
AzureIoTClient 30:20a85b733111 1359
AzureIoTClient 32:babfd49032ff 1360 if (retry_action == RETRY_ACTION_RETRY_NOW)
AzureIoTClient 32:babfd49032ff 1361 {
AzureIoTClient 32:babfd49032ff 1362 prepare_for_connection_retry(transport_instance);
AzureIoTClient 32:babfd49032ff 1363 }
AzureIoTClient 30:20a85b733111 1364 }
AzureIoTClient 30:20a85b733111 1365 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_018: [If there are no devices registered on the transport, IoTHubTransport_AMQP_Common_DoWork shall skip do_work for devices]
AzureIoTClient 30:20a85b733111 1366 else if ((list_item = singlylinkedlist_get_head_item(transport_instance->registered_devices)) != NULL)
AzureIoTClient 30:20a85b733111 1367 {
AzureIoTClient 30:20a85b733111 1368 // We need to check if there are devices, otherwise the amqp_connection won't be able to be created since
AzureIoTClient 30:20a85b733111 1369 // there is not a preferred authentication mode set yet on the transport.
AzureIoTClient 25:63f7d371c030 1370
AzureIoTClient 30:20a85b733111 1371 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_019: [If `instance->amqp_connection` is NULL, it shall be established]
AzureIoTClient 30:20a85b733111 1372 if (transport_instance->amqp_connection == NULL && establish_amqp_connection(transport_instance) != RESULT_OK)
AzureIoTClient 30:20a85b733111 1373 {
AzureIoTClient 30:20a85b733111 1374 LogError("AMQP transport failed to establish connection with service.");
AzureIoTClient 32:babfd49032ff 1375
AzureIoTClient 32:babfd49032ff 1376 update_state(transport_instance, AMQP_TRANSPORT_STATE_RECONNECTION_REQUIRED);
AzureIoTClient 30:20a85b733111 1377 }
AzureIoTClient 30:20a85b733111 1378 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_020: [If the amqp_connection is OPENED, the transport shall iterate through each registered device and perform a device-specific do_work on each]
AzureIoTClient 30:20a85b733111 1379 else if (transport_instance->amqp_connection_state == AMQP_CONNECTION_STATE_OPENED)
AzureIoTClient 30:20a85b733111 1380 {
AzureIoTClient 30:20a85b733111 1381 while (list_item != NULL)
AzureIoTClient 30:20a85b733111 1382 {
AzureIoTClient 30:20a85b733111 1383 AMQP_TRANSPORT_DEVICE_INSTANCE* registered_device;
AzureIoTClient 30:20a85b733111 1384
AzureIoTClient 30:20a85b733111 1385 if ((registered_device = (AMQP_TRANSPORT_DEVICE_INSTANCE*)singlylinkedlist_item_get_value(list_item)) == NULL)
AzureIoTClient 30:20a85b733111 1386 {
AzureIoTClient 30:20a85b733111 1387 LogError("Transport had an unexpected failure during DoWork (failed to fetch a registered_devices list item value)");
AzureIoTClient 30:20a85b733111 1388 }
AzureIoTClient 30:20a85b733111 1389 else if (registered_device->number_of_send_event_complete_failures >= MAX_NUMBER_OF_DEVICE_FAILURES)
AzureIoTClient 30:20a85b733111 1390 {
AzureIoTClient 30:20a85b733111 1391 LogError("Device '%s' reported a critical failure (events completed sending with failures); connection retry will be triggered.", STRING_c_str(registered_device->device_id));
AzureIoTClient 30:20a85b733111 1392
AzureIoTClient 32:babfd49032ff 1393 update_state(transport_instance, AMQP_TRANSPORT_STATE_RECONNECTION_REQUIRED);
AzureIoTClient 30:20a85b733111 1394 }
AzureIoTClient 30:20a85b733111 1395 else if (IoTHubTransport_AMQP_Common_Device_DoWork(registered_device) != RESULT_OK)
AzureIoTClient 30:20a85b733111 1396 {
AzureIoTClient 30:20a85b733111 1397 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_021: [If DoWork fails for the registered device for more than MAX_NUMBER_OF_DEVICE_FAILURES, connection retry shall be triggered]
AzureIoTClient 30:20a85b733111 1398 if (registered_device->number_of_previous_failures >= MAX_NUMBER_OF_DEVICE_FAILURES)
AzureIoTClient 30:20a85b733111 1399 {
AzureIoTClient 30:20a85b733111 1400 LogError("Device '%s' reported a critical failure; connection retry will be triggered.", STRING_c_str(registered_device->device_id));
AzureIoTClient 30:20a85b733111 1401
AzureIoTClient 32:babfd49032ff 1402 update_state(transport_instance, AMQP_TRANSPORT_STATE_RECONNECTION_REQUIRED);
AzureIoTClient 30:20a85b733111 1403 }
AzureIoTClient 30:20a85b733111 1404 }
AzureIoTClient 30:20a85b733111 1405
AzureIoTClient 30:20a85b733111 1406 list_item = singlylinkedlist_get_next_item(list_item);
AzureIoTClient 30:20a85b733111 1407 }
AzureIoTClient 30:20a85b733111 1408 }
AzureIoTClient 30:20a85b733111 1409 }
AzureIoTClient 30:20a85b733111 1410
AzureIoTClient 30:20a85b733111 1411 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_022: [If `instance->amqp_connection` is not NULL, amqp_connection_do_work shall be invoked]
AzureIoTClient 30:20a85b733111 1412 if (transport_instance->amqp_connection != NULL)
AzureIoTClient 26:ee14eed604f6 1413 {
AzureIoTClient 30:20a85b733111 1414 amqp_connection_do_work(transport_instance->amqp_connection);
AzureIoTClient 26:ee14eed604f6 1415 }
AzureIoTClient 25:63f7d371c030 1416 }
AzureIoTClient 25:63f7d371c030 1417 }
AzureIoTClient 25:63f7d371c030 1418
AzureIoTClient 25:63f7d371c030 1419 int IoTHubTransport_AMQP_Common_Subscribe(IOTHUB_DEVICE_HANDLE handle)
AzureIoTClient 25:63f7d371c030 1420 {
AzureIoTClient 25:63f7d371c030 1421 int result;
AzureIoTClient 25:63f7d371c030 1422
AzureIoTClient 30:20a85b733111 1423 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_084: [If `handle` is NULL, IoTHubTransport_AMQP_Common_Subscribe shall return a non-zero result]
AzureIoTClient 25:63f7d371c030 1424 if (handle == NULL)
AzureIoTClient 25:63f7d371c030 1425 {
AzureIoTClient 25:63f7d371c030 1426 LogError("Invalid handle to IoTHubClient AMQP transport device handle.");
AzureIoTClient 29:7e8852b14e3b 1427 result = __FAILURE__;
AzureIoTClient 25:63f7d371c030 1428 }
AzureIoTClient 25:63f7d371c030 1429 else
AzureIoTClient 25:63f7d371c030 1430 {
AzureIoTClient 30:20a85b733111 1431 AMQP_TRANSPORT_DEVICE_INSTANCE* amqp_device_instance = (AMQP_TRANSPORT_DEVICE_INSTANCE*)handle;
AzureIoTClient 30:20a85b733111 1432
AzureIoTClient 30:20a85b733111 1433 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_085: [If `amqp_device_instance` is not registered, IoTHubTransport_AMQP_Common_Subscribe shall return a non-zero result]
AzureIoTClient 30:20a85b733111 1434 if (!is_device_registered(amqp_device_instance))
AzureIoTClient 30:20a85b733111 1435 {
AzureIoTClient 30:20a85b733111 1436 LogError("Device '%s' failed subscribing to cloud-to-device messages (device is not registered)", STRING_c_str(amqp_device_instance->device_id));
AzureIoTClient 30:20a85b733111 1437 result = __FAILURE__;
AzureIoTClient 30:20a85b733111 1438 }
AzureIoTClient 30:20a85b733111 1439 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_086: [device_subscribe_message() shall be invoked passing `on_message_received_callback`]
AzureIoTClient 30:20a85b733111 1440 else if (device_subscribe_message(amqp_device_instance->device_handle, on_message_received, amqp_device_instance) != RESULT_OK)
AzureIoTClient 30:20a85b733111 1441 {
AzureIoTClient 30:20a85b733111 1442 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_087: [If device_subscribe_message() fails, IoTHubTransport_AMQP_Common_Subscribe shall return a non-zero result]
AzureIoTClient 30:20a85b733111 1443 LogError("Device '%s' failed subscribing to cloud-to-device messages (device_subscribe_message failed)", STRING_c_str(amqp_device_instance->device_id));
AzureIoTClient 30:20a85b733111 1444 result = __FAILURE__;
AzureIoTClient 30:20a85b733111 1445 }
AzureIoTClient 30:20a85b733111 1446 else
AzureIoTClient 30:20a85b733111 1447 {
AzureIoTClient 30:20a85b733111 1448 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_088: [If no failures occur, IoTHubTransport_AMQP_Common_Subscribe shall return 0]
AzureIoTClient 30:20a85b733111 1449 result = RESULT_OK;
AzureIoTClient 30:20a85b733111 1450 }
AzureIoTClient 25:63f7d371c030 1451 }
AzureIoTClient 25:63f7d371c030 1452
AzureIoTClient 25:63f7d371c030 1453 return result;
AzureIoTClient 25:63f7d371c030 1454 }
AzureIoTClient 25:63f7d371c030 1455
AzureIoTClient 25:63f7d371c030 1456 void IoTHubTransport_AMQP_Common_Unsubscribe(IOTHUB_DEVICE_HANDLE handle)
AzureIoTClient 25:63f7d371c030 1457 {
AzureIoTClient 30:20a85b733111 1458 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_093: [If `handle` is NULL, IoTHubTransport_AMQP_Common_Subscribe shall return]
AzureIoTClient 25:63f7d371c030 1459 if (handle == NULL)
AzureIoTClient 25:63f7d371c030 1460 {
AzureIoTClient 25:63f7d371c030 1461 LogError("Invalid handle to IoTHubClient AMQP transport device handle.");
AzureIoTClient 25:63f7d371c030 1462 }
AzureIoTClient 25:63f7d371c030 1463 else
AzureIoTClient 25:63f7d371c030 1464 {
AzureIoTClient 30:20a85b733111 1465 AMQP_TRANSPORT_DEVICE_INSTANCE* amqp_device_instance = (AMQP_TRANSPORT_DEVICE_INSTANCE*)handle;
AzureIoTClient 30:20a85b733111 1466
AzureIoTClient 30:20a85b733111 1467 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_094: [If `amqp_device_instance` is not registered, IoTHubTransport_AMQP_Common_Subscribe shall return]
AzureIoTClient 30:20a85b733111 1468 if (!is_device_registered(amqp_device_instance))
AzureIoTClient 30:20a85b733111 1469 {
AzureIoTClient 30:20a85b733111 1470 LogError("Device '%s' failed unsubscribing to cloud-to-device messages (device is not registered)", STRING_c_str(amqp_device_instance->device_id));
AzureIoTClient 30:20a85b733111 1471 }
AzureIoTClient 30:20a85b733111 1472 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_095: [device_unsubscribe_message() shall be invoked passing `amqp_device_instance->device_handle`]
AzureIoTClient 30:20a85b733111 1473 else if (device_unsubscribe_message(amqp_device_instance->device_handle) != RESULT_OK)
AzureIoTClient 30:20a85b733111 1474 {
AzureIoTClient 30:20a85b733111 1475 LogError("Device '%s' failed unsubscribing to cloud-to-device messages (device_unsubscribe_message failed)", STRING_c_str(amqp_device_instance->device_id));
AzureIoTClient 30:20a85b733111 1476 }
AzureIoTClient 25:63f7d371c030 1477 }
AzureIoTClient 25:63f7d371c030 1478 }
AzureIoTClient 25:63f7d371c030 1479
AzureIoTClient 25:63f7d371c030 1480 int IoTHubTransport_AMQP_Common_Subscribe_DeviceTwin(IOTHUB_DEVICE_HANDLE handle)
AzureIoTClient 25:63f7d371c030 1481 {
AzureIoTClient 25:63f7d371c030 1482 (void)handle;
AzureIoTClient 25:63f7d371c030 1483 /*Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_02_009: [ IoTHubTransport_AMQP_Common_Subscribe_DeviceTwin shall return a non-zero value. ]*/
AzureIoTClient 29:7e8852b14e3b 1484 int result = __FAILURE__;
AzureIoTClient 25:63f7d371c030 1485 LogError("IoTHubTransport_AMQP_Common_Subscribe_DeviceTwin Not supported");
AzureIoTClient 25:63f7d371c030 1486 return result;
AzureIoTClient 25:63f7d371c030 1487 }
AzureIoTClient 25:63f7d371c030 1488
AzureIoTClient 25:63f7d371c030 1489 void IoTHubTransport_AMQP_Common_Unsubscribe_DeviceTwin(IOTHUB_DEVICE_HANDLE handle)
AzureIoTClient 25:63f7d371c030 1490 {
AzureIoTClient 25:63f7d371c030 1491 (void)handle;
AzureIoTClient 25:63f7d371c030 1492 /*Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_02_010: [ IoTHubTransport_AMQP_Common_Unsubscribe_DeviceTwin shall return. ]*/
AzureIoTClient 25:63f7d371c030 1493 LogError("IoTHubTransport_AMQP_Common_Unsubscribe_DeviceTwin Not supported");
AzureIoTClient 25:63f7d371c030 1494 }
AzureIoTClient 25:63f7d371c030 1495
AzureIoTClient 25:63f7d371c030 1496 int IoTHubTransport_AMQP_Common_Subscribe_DeviceMethod(IOTHUB_DEVICE_HANDLE handle)
AzureIoTClient 25:63f7d371c030 1497 {
AzureIoTClient 25:63f7d371c030 1498 int result;
AzureIoTClient 25:63f7d371c030 1499
AzureIoTClient 25:63f7d371c030 1500 if (handle == NULL)
AzureIoTClient 25:63f7d371c030 1501 {
AzureIoTClient 25:63f7d371c030 1502 /* Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_01_004: [ If `handle` is NULL, `IoTHubTransport_AMQP_Common_Subscribe_DeviceMethod` shall fail and return a non-zero value. ] */
AzureIoTClient 25:63f7d371c030 1503 LogError("NULL handle");
AzureIoTClient 29:7e8852b14e3b 1504 result = __FAILURE__;
AzureIoTClient 25:63f7d371c030 1505 }
AzureIoTClient 25:63f7d371c030 1506 else
AzureIoTClient 25:63f7d371c030 1507 {
AzureIoTClient 25:63f7d371c030 1508 #ifdef WIP_C2D_METHODS_AMQP /* This feature is WIP, do not use yet */
AzureIoTClient 30:20a85b733111 1509 AMQP_TRANSPORT_DEVICE_INSTANCE* device_state = (AMQP_TRANSPORT_DEVICE_INSTANCE*)handle;
AzureIoTClient 25:63f7d371c030 1510 /* Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_01_026: [ `IoTHubTransport_AMQP_Common_Subscribe_DeviceMethod` shall remember that a subscribe is to be performed in the next call to DoWork and on success it shall return 0. ]*/
AzureIoTClient 25:63f7d371c030 1511 /* Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_01_005: [ If the transport is already subscribed to receive C2D method requests, `IoTHubTransport_AMQP_Common_Subscribe_DeviceMethod` shall perform no additional action and return 0. ]*/
AzureIoTClient 29:7e8852b14e3b 1512 device_state->subscribe_methods_needed = true;
AzureIoTClient 29:7e8852b14e3b 1513 device_state->subscribed_for_methods = false;
AzureIoTClient 25:63f7d371c030 1514 result = 0;
AzureIoTClient 25:63f7d371c030 1515 #else
AzureIoTClient 25:63f7d371c030 1516 LogError("Not implemented");
AzureIoTClient 29:7e8852b14e3b 1517 result = __FAILURE__;
AzureIoTClient 25:63f7d371c030 1518 #endif
AzureIoTClient 25:63f7d371c030 1519 }
AzureIoTClient 25:63f7d371c030 1520
AzureIoTClient 25:63f7d371c030 1521 return result;
AzureIoTClient 25:63f7d371c030 1522 }
AzureIoTClient 25:63f7d371c030 1523
AzureIoTClient 25:63f7d371c030 1524 void IoTHubTransport_AMQP_Common_Unsubscribe_DeviceMethod(IOTHUB_DEVICE_HANDLE handle)
AzureIoTClient 25:63f7d371c030 1525 {
AzureIoTClient 25:63f7d371c030 1526 if (handle == NULL)
AzureIoTClient 25:63f7d371c030 1527 {
AzureIoTClient 25:63f7d371c030 1528 /* Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_01_006: [ If `handle` is NULL, `IoTHubTransport_AMQP_Common_Unsubscribe_DeviceMethod` shall do nothing. ]*/
AzureIoTClient 25:63f7d371c030 1529 LogError("NULL handle");
AzureIoTClient 25:63f7d371c030 1530 }
AzureIoTClient 25:63f7d371c030 1531 else
AzureIoTClient 25:63f7d371c030 1532 {
AzureIoTClient 25:63f7d371c030 1533 #ifdef WIP_C2D_METHODS_AMQP /* This feature is WIP, do not use yet */
AzureIoTClient 30:20a85b733111 1534 AMQP_TRANSPORT_DEVICE_INSTANCE* device_state = (AMQP_TRANSPORT_DEVICE_INSTANCE*)handle;
AzureIoTClient 25:63f7d371c030 1535
AzureIoTClient 25:63f7d371c030 1536 /* Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_01_008: [ If the transport is not subscribed to receive C2D method requests then `IoTHubTransport_AMQP_Common_Unsubscribe_DeviceMethod` shall do nothing. ]*/
AzureIoTClient 29:7e8852b14e3b 1537 if (device_state->subscribe_methods_needed)
AzureIoTClient 25:63f7d371c030 1538 {
AzureIoTClient 25:63f7d371c030 1539 /* Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_01_007: [ `IoTHubTransport_AMQP_Common_Unsubscribe_DeviceMethod` shall unsubscribe from receiving C2D method requests by calling `iothubtransportamqp_methods_unsubscribe`. ]*/
AzureIoTClient 30:20a85b733111 1540 device_state->subscribed_for_methods = false;
AzureIoTClient 30:20a85b733111 1541 device_state->subscribe_methods_needed = false;
AzureIoTClient 30:20a85b733111 1542 iothubtransportamqp_methods_unsubscribe(device_state->methods_handle);
AzureIoTClient 25:63f7d371c030 1543 }
AzureIoTClient 25:63f7d371c030 1544 #else
AzureIoTClient 25:63f7d371c030 1545 LogError("Not implemented");
AzureIoTClient 25:63f7d371c030 1546 #endif
AzureIoTClient 25:63f7d371c030 1547 }
AzureIoTClient 25:63f7d371c030 1548 }
AzureIoTClient 25:63f7d371c030 1549
AzureIoTClient 26:ee14eed604f6 1550 int IoTHubTransport_AMQP_Common_DeviceMethod_Response(IOTHUB_DEVICE_HANDLE handle, METHOD_HANDLE methodId, const unsigned char* response, size_t response_size, int status_response)
AzureIoTClient 26:ee14eed604f6 1551 {
AzureIoTClient 26:ee14eed604f6 1552 (void)response;
AzureIoTClient 26:ee14eed604f6 1553 (void)response_size;
AzureIoTClient 26:ee14eed604f6 1554 (void)status_response;
AzureIoTClient 26:ee14eed604f6 1555 (void)methodId;
AzureIoTClient 26:ee14eed604f6 1556 int result;
AzureIoTClient 30:20a85b733111 1557 AMQP_TRANSPORT_DEVICE_INSTANCE* device_state = (AMQP_TRANSPORT_DEVICE_INSTANCE*)handle;
AzureIoTClient 26:ee14eed604f6 1558 if (device_state != NULL)
AzureIoTClient 26:ee14eed604f6 1559 {
AzureIoTClient 26:ee14eed604f6 1560 #ifdef WIP_C2D_METHODS_AMQP /* This feature is WIP, do not use yet */
AzureIoTClient 26:ee14eed604f6 1561 IOTHUBTRANSPORT_AMQP_METHOD_HANDLE saved_handle = (IOTHUBTRANSPORT_AMQP_METHOD_HANDLE)methodId;
AzureIoTClient 26:ee14eed604f6 1562 /* Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_01_019: [ `IoTHubTransport_AMQP_Common_DeviceMethod_Response` shall call `iothubtransportamqp_methods_respond` passing to it the `method_handle` argument, the response bytes, response size and the status code. ]*/
AzureIoTClient 26:ee14eed604f6 1563 if (iothubtransportamqp_methods_respond(saved_handle, response, response_size, status_response) != 0)
AzureIoTClient 26:ee14eed604f6 1564 {
AzureIoTClient 26:ee14eed604f6 1565 /* Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_01_029: [ If `iothubtransportamqp_methods_respond` fails, `on_methods_request_received` shall return a non-zero value. ]*/
AzureIoTClient 26:ee14eed604f6 1566 LogError("iothubtransportamqp_methods_respond failed");
AzureIoTClient 29:7e8852b14e3b 1567 result = __FAILURE__;
AzureIoTClient 26:ee14eed604f6 1568 }
AzureIoTClient 26:ee14eed604f6 1569 else
AzureIoTClient 26:ee14eed604f6 1570 {
AzureIoTClient 26:ee14eed604f6 1571 result = 0;
AzureIoTClient 26:ee14eed604f6 1572 }
AzureIoTClient 26:ee14eed604f6 1573 #else
AzureIoTClient 26:ee14eed604f6 1574 result = 0;
AzureIoTClient 26:ee14eed604f6 1575 LogError("Not implemented");
AzureIoTClient 26:ee14eed604f6 1576 #endif
AzureIoTClient 26:ee14eed604f6 1577 }
AzureIoTClient 26:ee14eed604f6 1578 else
AzureIoTClient 26:ee14eed604f6 1579 {
AzureIoTClient 29:7e8852b14e3b 1580 result = __FAILURE__;
AzureIoTClient 26:ee14eed604f6 1581 }
AzureIoTClient 26:ee14eed604f6 1582 return result;
AzureIoTClient 26:ee14eed604f6 1583 }
AzureIoTClient 26:ee14eed604f6 1584
AzureIoTClient 25:63f7d371c030 1585 IOTHUB_CLIENT_RESULT IoTHubTransport_AMQP_Common_GetSendStatus(IOTHUB_DEVICE_HANDLE handle, IOTHUB_CLIENT_STATUS *iotHubClientStatus)
AzureIoTClient 25:63f7d371c030 1586 {
AzureIoTClient 25:63f7d371c030 1587 IOTHUB_CLIENT_RESULT result;
AzureIoTClient 25:63f7d371c030 1588
AzureIoTClient 30:20a85b733111 1589 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_096: [If `handle` or `iotHubClientStatus` are NULL, IoTHubTransport_AMQP_Common_GetSendStatus shall return IOTHUB_CLIENT_INVALID_ARG]
AzureIoTClient 30:20a85b733111 1590 if (handle == NULL || iotHubClientStatus == NULL)
AzureIoTClient 25:63f7d371c030 1591 {
AzureIoTClient 25:63f7d371c030 1592 result = IOTHUB_CLIENT_INVALID_ARG;
AzureIoTClient 30:20a85b733111 1593 LogError("Failed retrieving the device send status (either handle (%p) or iotHubClientStatus (%p) are NULL)", handle, iotHubClientStatus);
AzureIoTClient 25:63f7d371c030 1594 }
AzureIoTClient 25:63f7d371c030 1595 else
AzureIoTClient 25:63f7d371c030 1596 {
AzureIoTClient 30:20a85b733111 1597 AMQP_TRANSPORT_DEVICE_INSTANCE* amqp_device_state = (AMQP_TRANSPORT_DEVICE_INSTANCE*)handle;
AzureIoTClient 25:63f7d371c030 1598
AzureIoTClient 30:20a85b733111 1599 DEVICE_SEND_STATUS device_send_status;
AzureIoTClient 30:20a85b733111 1600 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_097: [IoTHubTransport_AMQP_Common_GetSendStatus shall invoke device_get_send_status()]
AzureIoTClient 30:20a85b733111 1601 if (device_get_send_status(amqp_device_state->device_handle, &device_send_status) != RESULT_OK)
AzureIoTClient 30:20a85b733111 1602 {
AzureIoTClient 30:20a85b733111 1603 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_098: [If device_get_send_status() fails, IoTHubTransport_AMQP_Common_GetSendStatus shall return IOTHUB_CLIENT_ERROR]
AzureIoTClient 30:20a85b733111 1604 LogError("Failed retrieving the device send status (device_get_send_status failed)");
AzureIoTClient 30:20a85b733111 1605 result = IOTHUB_CLIENT_ERROR;
AzureIoTClient 30:20a85b733111 1606 }
AzureIoTClient 30:20a85b733111 1607 else
AzureIoTClient 30:20a85b733111 1608 {
AzureIoTClient 30:20a85b733111 1609 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_099: [If device_get_send_status() returns DEVICE_SEND_STATUS_BUSY, IoTHubTransport_AMQP_Common_GetSendStatus shall return IOTHUB_CLIENT_OK and status IOTHUB_CLIENT_SEND_STATUS_BUSY]
AzureIoTClient 30:20a85b733111 1610 if (device_send_status == DEVICE_SEND_STATUS_BUSY)
AzureIoTClient 30:20a85b733111 1611 {
AzureIoTClient 30:20a85b733111 1612 *iotHubClientStatus = IOTHUB_CLIENT_SEND_STATUS_BUSY;
AzureIoTClient 30:20a85b733111 1613 }
AzureIoTClient 30:20a85b733111 1614 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_100: [If device_get_send_status() returns DEVICE_SEND_STATUS_IDLE, IoTHubTransport_AMQP_Common_GetSendStatus shall return IOTHUB_CLIENT_OK and status IOTHUB_CLIENT_SEND_STATUS_IDLE]
AzureIoTClient 30:20a85b733111 1615 else // DEVICE_SEND_STATUS_IDLE
AzureIoTClient 30:20a85b733111 1616 {
AzureIoTClient 30:20a85b733111 1617 *iotHubClientStatus = IOTHUB_CLIENT_SEND_STATUS_IDLE;
AzureIoTClient 30:20a85b733111 1618 }
AzureIoTClient 25:63f7d371c030 1619
AzureIoTClient 30:20a85b733111 1620 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_109: [If no failures occur, IoTHubTransport_AMQP_Common_GetSendStatus shall return IOTHUB_CLIENT_OK]
AzureIoTClient 30:20a85b733111 1621 result = IOTHUB_CLIENT_OK;
AzureIoTClient 30:20a85b733111 1622 }
AzureIoTClient 25:63f7d371c030 1623 }
AzureIoTClient 25:63f7d371c030 1624
AzureIoTClient 25:63f7d371c030 1625 return result;
AzureIoTClient 25:63f7d371c030 1626 }
AzureIoTClient 25:63f7d371c030 1627
AzureIoTClient 25:63f7d371c030 1628 IOTHUB_CLIENT_RESULT IoTHubTransport_AMQP_Common_SetOption(TRANSPORT_LL_HANDLE handle, const char* option, const void* value)
AzureIoTClient 25:63f7d371c030 1629 {
AzureIoTClient 25:63f7d371c030 1630 IOTHUB_CLIENT_RESULT result;
AzureIoTClient 25:63f7d371c030 1631
AzureIoTClient 30:20a85b733111 1632 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_101: [If `handle`, `option` or `value` are NULL then IoTHubTransport_AMQP_Common_SetOption shall return IOTHUB_CLIENT_INVALID_ARG.]
AzureIoTClient 30:20a85b733111 1633 if ((handle == NULL) || (option == NULL) || (value == NULL))
AzureIoTClient 25:63f7d371c030 1634 {
AzureIoTClient 30:20a85b733111 1635 LogError("Invalid parameter (NULL) passed to AMQP transport SetOption (handle=%p, options=%p, value=%p)", handle, option, value);
AzureIoTClient 30:20a85b733111 1636 result = IOTHUB_CLIENT_INVALID_ARG;
AzureIoTClient 25:63f7d371c030 1637 }
AzureIoTClient 25:63f7d371c030 1638 else
AzureIoTClient 25:63f7d371c030 1639 {
AzureIoTClient 30:20a85b733111 1640 AMQP_TRANSPORT_INSTANCE* transport_instance = (AMQP_TRANSPORT_INSTANCE*)handle;
AzureIoTClient 30:20a85b733111 1641 bool is_device_specific_option;
AzureIoTClient 25:63f7d371c030 1642
AzureIoTClient 30:20a85b733111 1643 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_102: [If `option` is a device-specific option, it shall be saved and applied to each registered device using device_set_option()]
AzureIoTClient 30:20a85b733111 1644 if (strcmp(OPTION_SAS_TOKEN_LIFETIME, option) == 0)
AzureIoTClient 30:20a85b733111 1645 {
AzureIoTClient 30:20a85b733111 1646 is_device_specific_option = true;
AzureIoTClient 30:20a85b733111 1647 transport_instance->option_sas_token_lifetime_secs = *(size_t*)value;
AzureIoTClient 30:20a85b733111 1648 }
AzureIoTClient 30:20a85b733111 1649 else if (strcmp(OPTION_SAS_TOKEN_REFRESH_TIME, option) == 0)
AzureIoTClient 30:20a85b733111 1650 {
AzureIoTClient 30:20a85b733111 1651 is_device_specific_option = true;
AzureIoTClient 30:20a85b733111 1652 transport_instance->option_sas_token_refresh_time_secs = *(size_t*)value;
AzureIoTClient 30:20a85b733111 1653 }
AzureIoTClient 30:20a85b733111 1654 else if (strcmp(OPTION_CBS_REQUEST_TIMEOUT, option) == 0)
AzureIoTClient 30:20a85b733111 1655 {
AzureIoTClient 30:20a85b733111 1656 is_device_specific_option = true;
AzureIoTClient 30:20a85b733111 1657 transport_instance->option_cbs_request_timeout_secs = *(size_t*)value;
AzureIoTClient 30:20a85b733111 1658 }
AzureIoTClient 30:20a85b733111 1659 else if (strcmp(OPTION_EVENT_SEND_TIMEOUT_SECS, option) == 0)
AzureIoTClient 30:20a85b733111 1660 {
AzureIoTClient 30:20a85b733111 1661 is_device_specific_option = true;
AzureIoTClient 30:20a85b733111 1662 transport_instance->option_send_event_timeout_secs = *(size_t*)value;
AzureIoTClient 30:20a85b733111 1663 }
AzureIoTClient 30:20a85b733111 1664 else
AzureIoTClient 30:20a85b733111 1665 {
AzureIoTClient 30:20a85b733111 1666 is_device_specific_option = false;
AzureIoTClient 30:20a85b733111 1667 }
AzureIoTClient 25:63f7d371c030 1668
AzureIoTClient 30:20a85b733111 1669 if (is_device_specific_option)
AzureIoTClient 30:20a85b733111 1670 {
AzureIoTClient 30:20a85b733111 1671 if (IoTHubTransport_AMQP_Common_Device_SetOption(handle, option, (void*)value) != RESULT_OK)
AzureIoTClient 30:20a85b733111 1672 {
AzureIoTClient 30:20a85b733111 1673 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_103: [If device_set_option() fails, IoTHubTransport_AMQP_Common_SetOption shall return IOTHUB_CLIENT_ERROR]
AzureIoTClient 30:20a85b733111 1674 LogError("transport failed setting option '%s' (failed setting option on one or more registered devices)", option);
AzureIoTClient 30:20a85b733111 1675 result = IOTHUB_CLIENT_ERROR;
AzureIoTClient 30:20a85b733111 1676 }
AzureIoTClient 30:20a85b733111 1677 else
AzureIoTClient 30:20a85b733111 1678 {
AzureIoTClient 30:20a85b733111 1679 result = IOTHUB_CLIENT_OK;
AzureIoTClient 30:20a85b733111 1680 }
AzureIoTClient 30:20a85b733111 1681 }
AzureIoTClient 30:20a85b733111 1682 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_104: [If `option` is `logtrace`, `value` shall be saved and applied to `instance->connection` using amqp_connection_set_logging()]
AzureIoTClient 30:20a85b733111 1683 else if (strcmp(OPTION_LOG_TRACE, option) == 0)
AzureIoTClient 30:20a85b733111 1684 {
AzureIoTClient 30:20a85b733111 1685 transport_instance->is_trace_on = *((bool*)value);
AzureIoTClient 25:63f7d371c030 1686
AzureIoTClient 30:20a85b733111 1687 if (transport_instance->amqp_connection != NULL &&
AzureIoTClient 30:20a85b733111 1688 amqp_connection_set_logging(transport_instance->amqp_connection, transport_instance->is_trace_on) != RESULT_OK)
AzureIoTClient 30:20a85b733111 1689 {
AzureIoTClient 30:20a85b733111 1690 LogError("transport failed setting option '%s' (amqp_connection_set_logging failed)", option);
AzureIoTClient 30:20a85b733111 1691 result = IOTHUB_CLIENT_ERROR;
AzureIoTClient 30:20a85b733111 1692 }
AzureIoTClient 30:20a85b733111 1693 else
AzureIoTClient 30:20a85b733111 1694 {
AzureIoTClient 30:20a85b733111 1695 result = IOTHUB_CLIENT_OK;
AzureIoTClient 30:20a85b733111 1696 }
AzureIoTClient 30:20a85b733111 1697 }
AzureIoTClient 31:adadaef857c1 1698 else if (strcmp(OPTION_HTTP_PROXY, option) == 0)
AzureIoTClient 31:adadaef857c1 1699 {
AzureIoTClient 31:adadaef857c1 1700 /* Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_01_032: [ If `option` is `proxy_data`, `value` shall be used as an `HTTP_PROXY_OPTIONS*`. ]*/
AzureIoTClient 31:adadaef857c1 1701 HTTP_PROXY_OPTIONS* proxy_options = (HTTP_PROXY_OPTIONS*)value;
AzureIoTClient 31:adadaef857c1 1702
AzureIoTClient 31:adadaef857c1 1703 if (transport_instance->tls_io != NULL)
AzureIoTClient 31:adadaef857c1 1704 {
AzureIoTClient 31:adadaef857c1 1705 /* Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_01_038: [ If the underlying IO has already been created, then `IoTHubTransport_AMQP_Common_SetOption` shall fail and return `IOTHUB_CLIENT_ERROR`. ]*/
AzureIoTClient 31:adadaef857c1 1706 LogError("Cannot set proxy option once the underlying IO is created");
AzureIoTClient 31:adadaef857c1 1707 result = IOTHUB_CLIENT_ERROR;
AzureIoTClient 31:adadaef857c1 1708 }
AzureIoTClient 31:adadaef857c1 1709 else if (proxy_options->host_address == NULL)
AzureIoTClient 31:adadaef857c1 1710 {
AzureIoTClient 31:adadaef857c1 1711 /* Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_01_034: [ If `host_address` is NULL, `IoTHubTransport_AMQP_Common_SetOption` shall fail and return `IOTHUB_CLIENT_INVALID_ARG`. ]*/
AzureIoTClient 31:adadaef857c1 1712 LogError("NULL host_address in proxy options");
AzureIoTClient 31:adadaef857c1 1713 result = IOTHUB_CLIENT_INVALID_ARG;
AzureIoTClient 31:adadaef857c1 1714 }
AzureIoTClient 31:adadaef857c1 1715 /* Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_01_037: [ If only one of `username` and `password` is NULL, `IoTHubTransport_AMQP_Common_SetOption` shall fail and return `IOTHUB_CLIENT_INVALID_ARG`. ]*/
AzureIoTClient 31:adadaef857c1 1716 else if (((proxy_options->username == NULL) || (proxy_options->password == NULL)) &&
AzureIoTClient 31:adadaef857c1 1717 (proxy_options->username != proxy_options->password))
AzureIoTClient 31:adadaef857c1 1718 {
AzureIoTClient 31:adadaef857c1 1719 LogError("Only one of username and password for proxy settings was NULL");
AzureIoTClient 31:adadaef857c1 1720 result = IOTHUB_CLIENT_INVALID_ARG;
AzureIoTClient 31:adadaef857c1 1721 }
AzureIoTClient 31:adadaef857c1 1722 else
AzureIoTClient 31:adadaef857c1 1723 {
AzureIoTClient 31:adadaef857c1 1724 char* copied_proxy_hostname = NULL;
AzureIoTClient 31:adadaef857c1 1725 char* copied_proxy_username = NULL;
AzureIoTClient 31:adadaef857c1 1726 char* copied_proxy_password = NULL;
AzureIoTClient 31:adadaef857c1 1727
AzureIoTClient 31:adadaef857c1 1728 /* Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_01_033: [ The fields `host_address`, `port`, `username` and `password` shall be saved for later used (needed when creating the underlying IO to be used by the transport). ]*/
AzureIoTClient 31:adadaef857c1 1729 transport_instance->http_proxy_port = proxy_options->port;
AzureIoTClient 31:adadaef857c1 1730 if (mallocAndStrcpy_s(&copied_proxy_hostname, proxy_options->host_address) != 0)
AzureIoTClient 31:adadaef857c1 1731 {
AzureIoTClient 31:adadaef857c1 1732 /* Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_01_035: [ If copying `host_address`, `username` or `password` fails, `IoTHubTransport_AMQP_Common_SetOption` shall fail and return `IOTHUB_CLIENT_ERROR`. ]*/
AzureIoTClient 31:adadaef857c1 1733 LogError("Cannot copy HTTP proxy hostname");
AzureIoTClient 31:adadaef857c1 1734 result = IOTHUB_CLIENT_ERROR;
AzureIoTClient 31:adadaef857c1 1735 }
AzureIoTClient 31:adadaef857c1 1736 /* Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_01_036: [ `username` and `password` shall be allowed to be NULL. ]*/
AzureIoTClient 31:adadaef857c1 1737 else if ((proxy_options->username != NULL) && (mallocAndStrcpy_s(&copied_proxy_username, proxy_options->username) != 0))
AzureIoTClient 31:adadaef857c1 1738 {
AzureIoTClient 31:adadaef857c1 1739 /* Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_01_035: [ If copying `host_address`, `username` or `password` fails, `IoTHubTransport_AMQP_Common_SetOption` shall fail and return `IOTHUB_CLIENT_ERROR`. ]*/
AzureIoTClient 31:adadaef857c1 1740 free(copied_proxy_hostname);
AzureIoTClient 31:adadaef857c1 1741 LogError("Cannot copy HTTP proxy username");
AzureIoTClient 31:adadaef857c1 1742 result = IOTHUB_CLIENT_ERROR;
AzureIoTClient 31:adadaef857c1 1743 }
AzureIoTClient 31:adadaef857c1 1744 /* Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_01_036: [ `username` and `password` shall be allowed to be NULL. ]*/
AzureIoTClient 31:adadaef857c1 1745 else if ((proxy_options->password != NULL) && (mallocAndStrcpy_s(&copied_proxy_password, proxy_options->password) != 0))
AzureIoTClient 31:adadaef857c1 1746 {
AzureIoTClient 31:adadaef857c1 1747 /* Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_01_035: [ If copying `host_address`, `username` or `password` fails, `IoTHubTransport_AMQP_Common_SetOption` shall fail and return `IOTHUB_CLIENT_ERROR`. ]*/
AzureIoTClient 31:adadaef857c1 1748 if (copied_proxy_username != NULL)
AzureIoTClient 31:adadaef857c1 1749 {
AzureIoTClient 31:adadaef857c1 1750 free(copied_proxy_username);
AzureIoTClient 31:adadaef857c1 1751 }
AzureIoTClient 31:adadaef857c1 1752 free(copied_proxy_hostname);
AzureIoTClient 31:adadaef857c1 1753 LogError("Cannot copy HTTP proxy password");
AzureIoTClient 31:adadaef857c1 1754 result = IOTHUB_CLIENT_ERROR;
AzureIoTClient 31:adadaef857c1 1755 }
AzureIoTClient 31:adadaef857c1 1756 else
AzureIoTClient 31:adadaef857c1 1757 {
AzureIoTClient 31:adadaef857c1 1758 /* Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_01_040: [ When setting the proxy options succeeds any previously saved proxy options shall be freed. ]*/
AzureIoTClient 31:adadaef857c1 1759 free_proxy_data(transport_instance);
AzureIoTClient 31:adadaef857c1 1760
AzureIoTClient 31:adadaef857c1 1761 transport_instance->http_proxy_hostname = copied_proxy_hostname;
AzureIoTClient 31:adadaef857c1 1762 transport_instance->http_proxy_username = copied_proxy_username;
AzureIoTClient 31:adadaef857c1 1763 transport_instance->http_proxy_password = copied_proxy_password;
AzureIoTClient 31:adadaef857c1 1764
AzureIoTClient 31:adadaef857c1 1765 /* Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_01_039: [ If setting the `proxy_data` option succeeds, `IoTHubTransport_AMQP_Common_SetOption` shall return `IOTHUB_CLIENT_OK` ]*/
AzureIoTClient 31:adadaef857c1 1766 result = IOTHUB_CLIENT_OK;
AzureIoTClient 31:adadaef857c1 1767 }
AzureIoTClient 31:adadaef857c1 1768 }
AzureIoTClient 31:adadaef857c1 1769 }
AzureIoTClient 31:adadaef857c1 1770 else
AzureIoTClient 30:20a85b733111 1771 {
AzureIoTClient 30:20a85b733111 1772 result = IOTHUB_CLIENT_OK;
AzureIoTClient 30:20a85b733111 1773
AzureIoTClient 30:20a85b733111 1774 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_02_007: [ If `option` is `x509certificate` and the transport preferred authentication method is not x509 then IoTHubTransport_AMQP_Common_SetOption shall return IOTHUB_CLIENT_INVALID_ARG. ]
AzureIoTClient 30:20a85b733111 1775 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_02_008: [ If `option` is `x509privatekey` and the transport preferred authentication method is not x509 then IoTHubTransport_AMQP_Common_SetOption shall return IOTHUB_CLIENT_INVALID_ARG. ]
AzureIoTClient 30:20a85b733111 1776 if (strcmp(OPTION_X509_CERT, option) == 0 || strcmp(OPTION_X509_PRIVATE_KEY, option) == 0)
AzureIoTClient 30:20a85b733111 1777 {
AzureIoTClient 30:20a85b733111 1778 if (transport_instance->preferred_authentication_mode == AMQP_TRANSPORT_AUTHENTICATION_MODE_NOT_SET)
AzureIoTClient 30:20a85b733111 1779 {
AzureIoTClient 30:20a85b733111 1780 transport_instance->preferred_authentication_mode = AMQP_TRANSPORT_AUTHENTICATION_MODE_X509;
AzureIoTClient 30:20a85b733111 1781 }
AzureIoTClient 30:20a85b733111 1782 else if (transport_instance->preferred_authentication_mode != AMQP_TRANSPORT_AUTHENTICATION_MODE_X509)
AzureIoTClient 30:20a85b733111 1783 {
AzureIoTClient 30:20a85b733111 1784 LogError("transport failed setting option '%s' (preferred authentication method is not x509)", option);
AzureIoTClient 30:20a85b733111 1785 result = IOTHUB_CLIENT_INVALID_ARG;
AzureIoTClient 30:20a85b733111 1786 }
AzureIoTClient 30:20a85b733111 1787 }
AzureIoTClient 25:63f7d371c030 1788
AzureIoTClient 30:20a85b733111 1789 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_105: [If `option` does not match one of the options handled by this module, it shall be passed to `instance->tls_io` using xio_setoption()]
AzureIoTClient 30:20a85b733111 1790 if (result != IOTHUB_CLIENT_INVALID_ARG)
AzureIoTClient 30:20a85b733111 1791 {
AzureIoTClient 30:20a85b733111 1792 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_106: [If `instance->tls_io` is NULL, it shall be set invoking instance->underlying_io_transport_provider()]
AzureIoTClient 30:20a85b733111 1793 if (transport_instance->tls_io == NULL &&
AzureIoTClient 30:20a85b733111 1794 get_new_underlying_io_transport(transport_instance, &transport_instance->tls_io) != RESULT_OK)
AzureIoTClient 30:20a85b733111 1795 {
AzureIoTClient 30:20a85b733111 1796 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_107: [If instance->underlying_io_transport_provider() fails, IoTHubTransport_AMQP_Common_SetOption shall fail and return IOTHUB_CLIENT_ERROR]
AzureIoTClient 30:20a85b733111 1797 LogError("transport failed setting option '%s' (failed to obtain a TLS I/O transport).", option);
AzureIoTClient 30:20a85b733111 1798 result = IOTHUB_CLIENT_ERROR;
AzureIoTClient 30:20a85b733111 1799 }
AzureIoTClient 30:20a85b733111 1800 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_108: [When `instance->tls_io` is created, IoTHubTransport_AMQP_Common_SetOption shall apply `instance->saved_tls_options` with OptionHandler_FeedOptions()]
AzureIoTClient 30:20a85b733111 1801 else if (xio_setoption(transport_instance->tls_io, option, value) != RESULT_OK)
AzureIoTClient 30:20a85b733111 1802 {
AzureIoTClient 30:20a85b733111 1803 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_03_001: [If xio_setoption fails, IoTHubTransport_AMQP_Common_SetOption shall return IOTHUB_CLIENT_ERROR.]
AzureIoTClient 30:20a85b733111 1804 LogError("transport failed setting option '%s' (xio_setoption failed)", option);
AzureIoTClient 30:20a85b733111 1805 result = IOTHUB_CLIENT_ERROR;
AzureIoTClient 30:20a85b733111 1806 }
AzureIoTClient 30:20a85b733111 1807 else
AzureIoTClient 30:20a85b733111 1808 {
AzureIoTClient 30:20a85b733111 1809 if (save_underlying_io_transport_options(transport_instance) != RESULT_OK)
AzureIoTClient 30:20a85b733111 1810 {
AzureIoTClient 30:20a85b733111 1811 LogError("IoTHubTransport_AMQP_Common_SetOption failed to save underlying I/O options; failure will be ignored");
AzureIoTClient 30:20a85b733111 1812 }
AzureIoTClient 25:63f7d371c030 1813
AzureIoTClient 30:20a85b733111 1814 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_03_001: [If no failures occur, IoTHubTransport_AMQP_Common_SetOption shall return IOTHUB_CLIENT_OK.]
AzureIoTClient 30:20a85b733111 1815 result = IOTHUB_CLIENT_OK;
AzureIoTClient 30:20a85b733111 1816 }
AzureIoTClient 30:20a85b733111 1817 }
AzureIoTClient 30:20a85b733111 1818 }
AzureIoTClient 30:20a85b733111 1819 }
AzureIoTClient 25:63f7d371c030 1820
AzureIoTClient 25:63f7d371c030 1821 return result;
AzureIoTClient 25:63f7d371c030 1822 }
AzureIoTClient 25:63f7d371c030 1823
AzureIoTClient 25:63f7d371c030 1824 IOTHUB_DEVICE_HANDLE IoTHubTransport_AMQP_Common_Register(TRANSPORT_LL_HANDLE handle, const IOTHUB_DEVICE_CONFIG* device, IOTHUB_CLIENT_LL_HANDLE iotHubClientHandle, PDLIST_ENTRY waitingToSend)
AzureIoTClient 25:63f7d371c030 1825 {
AzureIoTClient 25:63f7d371c030 1826 #ifdef NO_LOGGING
AzureIoTClient 25:63f7d371c030 1827 UNUSED(iotHubClientHandle);
AzureIoTClient 25:63f7d371c030 1828 #endif
AzureIoTClient 25:63f7d371c030 1829
AzureIoTClient 30:20a85b733111 1830 IOTHUB_DEVICE_HANDLE result;
AzureIoTClient 30:20a85b733111 1831
AzureIoTClient 30:20a85b733111 1832 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_17_005: [If `handle`, `device`, `iotHubClientHandle` or `waitingToSend` is NULL, IoTHubTransport_AMQP_Common_Register shall return NULL]
AzureIoTClient 30:20a85b733111 1833 if ((handle == NULL) || (device == NULL) || (waitingToSend == NULL) || (iotHubClientHandle == NULL))
AzureIoTClient 25:63f7d371c030 1834 {
AzureIoTClient 30:20a85b733111 1835 LogError("invalid parameter TRANSPORT_LL_HANDLE handle=%p, const IOTHUB_DEVICE_CONFIG* device=%p, IOTHUB_CLIENT_LL_HANDLE iotHubClientHandle=%p, PDLIST_ENTRY waiting_to_send=%p",
AzureIoTClient 25:63f7d371c030 1836 handle, device, iotHubClientHandle, waitingToSend);
AzureIoTClient 30:20a85b733111 1837 result = NULL;
AzureIoTClient 25:63f7d371c030 1838 }
AzureIoTClient 30:20a85b733111 1839 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_03_002: [IoTHubTransport_AMQP_Common_Register shall return NULL if `device->deviceId` is NULL.]
AzureIoTClient 30:20a85b733111 1840 else if (device->deviceId == NULL)
AzureIoTClient 30:20a85b733111 1841 {
AzureIoTClient 30:20a85b733111 1842 LogError("Transport failed to register device (device_id provided is NULL)");
AzureIoTClient 30:20a85b733111 1843 result = NULL;
AzureIoTClient 30:20a85b733111 1844 }
AzureIoTClient 26:ee14eed604f6 1845 else
AzureIoTClient 26:ee14eed604f6 1846 {
AzureIoTClient 30:20a85b733111 1847 LIST_ITEM_HANDLE list_item;
AzureIoTClient 30:20a85b733111 1848 AMQP_TRANSPORT_INSTANCE* transport_instance = (AMQP_TRANSPORT_INSTANCE*)handle;
AzureIoTClient 25:63f7d371c030 1849
AzureIoTClient 30:20a85b733111 1850 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_064: [If the device is already registered, IoTHubTransport_AMQP_Common_Register shall fail and return NULL.]
AzureIoTClient 30:20a85b733111 1851 if (is_device_registered_ex(transport_instance->registered_devices, device->deviceId, &list_item))
AzureIoTClient 30:20a85b733111 1852 {
AzureIoTClient 30:20a85b733111 1853 LogError("IoTHubTransport_AMQP_Common_Register failed (device '%s' already registered on this transport instance)", device->deviceId);
AzureIoTClient 30:20a85b733111 1854 result = NULL;
AzureIoTClient 30:20a85b733111 1855 }
AzureIoTClient 30:20a85b733111 1856 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_065: [IoTHubTransport_AMQP_Common_Register shall fail and return NULL if the device is not using an authentication mode compatible with the currently used by the transport.]
AzureIoTClient 30:20a85b733111 1857 else if (!is_device_credential_acceptable(device, transport_instance->preferred_authentication_mode))
AzureIoTClient 26:ee14eed604f6 1858 {
AzureIoTClient 30:20a85b733111 1859 LogError("Transport failed to register device '%s' (device credential was not accepted)", device->deviceId);
AzureIoTClient 30:20a85b733111 1860 result = NULL;
AzureIoTClient 30:20a85b733111 1861 }
AzureIoTClient 26:ee14eed604f6 1862 else
AzureIoTClient 26:ee14eed604f6 1863 {
AzureIoTClient 30:20a85b733111 1864 AMQP_TRANSPORT_DEVICE_INSTANCE* amqp_device_instance;
AzureIoTClient 25:63f7d371c030 1865
AzureIoTClient 30:20a85b733111 1866 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_066: [IoTHubTransport_AMQP_Common_Register shall allocate an instance of AMQP_TRANSPORT_DEVICE_INSTANCE to store the state of the new registered device.]
AzureIoTClient 30:20a85b733111 1867 if ((amqp_device_instance = (AMQP_TRANSPORT_DEVICE_INSTANCE*)malloc(sizeof(AMQP_TRANSPORT_DEVICE_INSTANCE))) == NULL)
AzureIoTClient 26:ee14eed604f6 1868 {
AzureIoTClient 30:20a85b733111 1869 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_067: [If malloc fails, IoTHubTransport_AMQP_Common_Register shall fail and return NULL.]
AzureIoTClient 30:20a85b733111 1870 LogError("Transport failed to register device '%s' (failed to create the device state instance; malloc failed)", device->deviceId);
AzureIoTClient 30:20a85b733111 1871 result = NULL;
AzureIoTClient 30:20a85b733111 1872 }
AzureIoTClient 26:ee14eed604f6 1873 else
AzureIoTClient 26:ee14eed604f6 1874 {
AzureIoTClient 30:20a85b733111 1875 memset(amqp_device_instance, 0, sizeof(AMQP_TRANSPORT_DEVICE_INSTANCE));
AzureIoTClient 30:20a85b733111 1876
AzureIoTClient 30:20a85b733111 1877 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_068: [IoTHubTransport_AMQP_Common_Register shall save the handle references to the IoTHubClient, transport, waitingToSend list on `amqp_device_instance`.]
AzureIoTClient 30:20a85b733111 1878 amqp_device_instance->iothub_client_handle = iotHubClientHandle;
AzureIoTClient 30:20a85b733111 1879 amqp_device_instance->transport_instance = transport_instance;
AzureIoTClient 30:20a85b733111 1880 amqp_device_instance->waiting_to_send = waitingToSend;
AzureIoTClient 30:20a85b733111 1881 amqp_device_instance->device_state = DEVICE_STATE_STOPPED;
AzureIoTClient 30:20a85b733111 1882 amqp_device_instance->max_state_change_timeout_secs = DEFAULT_DEVICE_STATE_CHANGE_TIMEOUT_SECS;
AzureIoTClient 30:20a85b733111 1883
AzureIoTClient 25:63f7d371c030 1884 #ifdef WIP_C2D_METHODS_AMQP /* This feature is WIP, do not use yet */
AzureIoTClient 30:20a85b733111 1885 amqp_device_instance->subscribe_methods_needed = false;
AzureIoTClient 30:20a85b733111 1886 amqp_device_instance->subscribed_for_methods = false;
AzureIoTClient 25:63f7d371c030 1887 #endif
AzureIoTClient 30:20a85b733111 1888 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_069: [A copy of `config->deviceId` shall be saved into `device_state->device_id`]
AzureIoTClient 30:20a85b733111 1889 if ((amqp_device_instance->device_id = STRING_construct(device->deviceId)) == NULL)
AzureIoTClient 26:ee14eed604f6 1890 {
AzureIoTClient 30:20a85b733111 1891 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_070: [If STRING_construct() fails, IoTHubTransport_AMQP_Common_Register shall fail and return NULL]
AzureIoTClient 30:20a85b733111 1892 LogError("Transport failed to register device '%s' (failed to copy the deviceId)", device->deviceId);
AzureIoTClient 30:20a85b733111 1893 result = NULL;
AzureIoTClient 30:20a85b733111 1894 }
AzureIoTClient 26:ee14eed604f6 1895 else
AzureIoTClient 26:ee14eed604f6 1896 {
AzureIoTClient 30:20a85b733111 1897 DEVICE_CONFIG device_config;
AzureIoTClient 30:20a85b733111 1898 memset(&device_config, 0, sizeof(DEVICE_CONFIG));
AzureIoTClient 30:20a85b733111 1899 device_config.device_id = (char*)device->deviceId;
AzureIoTClient 30:20a85b733111 1900 device_config.iothub_host_fqdn = (char*)STRING_c_str(transport_instance->iothub_host_fqdn);
AzureIoTClient 30:20a85b733111 1901 device_config.device_primary_key = (char*)device->deviceKey;
AzureIoTClient 30:20a85b733111 1902 device_config.device_sas_token = (char*)device->deviceSasToken;
AzureIoTClient 30:20a85b733111 1903 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_072: [The configuration for device_create shall be set according to the authentication preferred by IOTHUB_DEVICE_CONFIG]
AzureIoTClient 30:20a85b733111 1904 device_config.authentication_mode = (device->deviceKey != NULL || device->deviceSasToken != NULL ? DEVICE_AUTH_MODE_CBS : DEVICE_AUTH_MODE_X509);
AzureIoTClient 30:20a85b733111 1905 device_config.on_state_changed_callback = on_device_state_changed_callback;
AzureIoTClient 30:20a85b733111 1906 device_config.on_state_changed_context = amqp_device_instance;
AzureIoTClient 30:20a85b733111 1907
AzureIoTClient 30:20a85b733111 1908 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_071: [`amqp_device_instance->device_handle` shall be set using device_create()]
AzureIoTClient 30:20a85b733111 1909 if ((amqp_device_instance->device_handle = device_create(&device_config)) == NULL)
AzureIoTClient 30:20a85b733111 1910 {
AzureIoTClient 30:20a85b733111 1911 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_073: [If device_create() fails, IoTHubTransport_AMQP_Common_Register shall fail and return NULL]
AzureIoTClient 30:20a85b733111 1912 LogError("Transport failed to register device '%s' (failed to create the DEVICE_HANDLE instance)", device->deviceId);
AzureIoTClient 30:20a85b733111 1913 result = NULL;
AzureIoTClient 30:20a85b733111 1914 }
AzureIoTClient 30:20a85b733111 1915 else
AzureIoTClient 30:20a85b733111 1916 {
AzureIoTClient 30:20a85b733111 1917 bool is_first_device_being_registered = (singlylinkedlist_get_head_item(transport_instance->registered_devices) == NULL);
AzureIoTClient 30:20a85b733111 1918
AzureIoTClient 25:63f7d371c030 1919 #ifdef WIP_C2D_METHODS_AMQP /* This feature is WIP, do not use yet */
AzureIoTClient 30:20a85b733111 1920 /* Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_01_010: [ `IoTHubTransport_AMQP_Common_Create` shall create a new iothubtransportamqp_methods instance by calling `iothubtransportamqp_methods_create` while passing to it the the fully qualified domain name and the device Id. ]*/
AzureIoTClient 30:20a85b733111 1921 amqp_device_instance->methods_handle = iothubtransportamqp_methods_create(STRING_c_str(transport_instance->iothub_host_fqdn), device->deviceId);
AzureIoTClient 30:20a85b733111 1922 if (amqp_device_instance->methods_handle == NULL)
AzureIoTClient 30:20a85b733111 1923 {
AzureIoTClient 30:20a85b733111 1924 /* Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_01_011: [ If `iothubtransportamqp_methods_create` fails, `IoTHubTransport_AMQP_Common_Create` shall fail and return NULL. ]*/
AzureIoTClient 30:20a85b733111 1925 LogError("Transport failed to register device '%s' (Cannot create the methods module)", device->deviceId);
AzureIoTClient 30:20a85b733111 1926 result = NULL;
AzureIoTClient 30:20a85b733111 1927 }
AzureIoTClient 30:20a85b733111 1928 else
AzureIoTClient 25:63f7d371c030 1929 #endif
AzureIoTClient 30:20a85b733111 1930 if (replicate_device_options_to(amqp_device_instance, device_config.authentication_mode) != RESULT_OK)
AzureIoTClient 30:20a85b733111 1931 {
AzureIoTClient 30:20a85b733111 1932 LogError("Transport failed to register device '%s' (failed to replicate options)", device->deviceId);
AzureIoTClient 30:20a85b733111 1933 result = NULL;
AzureIoTClient 30:20a85b733111 1934 }
AzureIoTClient 30:20a85b733111 1935 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_074: [IoTHubTransport_AMQP_Common_Register shall add the `amqp_device_instance` to `instance->registered_devices`]
AzureIoTClient 30:20a85b733111 1936 else if (singlylinkedlist_add(transport_instance->registered_devices, amqp_device_instance) == NULL)
AzureIoTClient 30:20a85b733111 1937 {
AzureIoTClient 30:20a85b733111 1938 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_075: [If it fails to add `amqp_device_instance`, IoTHubTransport_AMQP_Common_Register shall fail and return NULL]
AzureIoTClient 30:20a85b733111 1939 LogError("Transport failed to register device '%s' (singlylinkedlist_add failed)", device->deviceId);
AzureIoTClient 30:20a85b733111 1940 result = NULL;
AzureIoTClient 30:20a85b733111 1941 }
AzureIoTClient 30:20a85b733111 1942 else
AzureIoTClient 30:20a85b733111 1943 {
AzureIoTClient 30:20a85b733111 1944 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_076: [If the device is the first being registered on the transport, IoTHubTransport_AMQP_Common_Register shall save its authentication mode as the transport preferred authentication mode]
AzureIoTClient 30:20a85b733111 1945 if (transport_instance->preferred_authentication_mode == AMQP_TRANSPORT_AUTHENTICATION_MODE_NOT_SET &&
AzureIoTClient 30:20a85b733111 1946 is_first_device_being_registered)
AzureIoTClient 30:20a85b733111 1947 {
AzureIoTClient 30:20a85b733111 1948 if (device_config.authentication_mode == DEVICE_AUTH_MODE_CBS)
AzureIoTClient 30:20a85b733111 1949 {
AzureIoTClient 30:20a85b733111 1950 transport_instance->preferred_authentication_mode = AMQP_TRANSPORT_AUTHENTICATION_MODE_CBS;
AzureIoTClient 30:20a85b733111 1951 }
AzureIoTClient 30:20a85b733111 1952 else
AzureIoTClient 30:20a85b733111 1953 {
AzureIoTClient 30:20a85b733111 1954 transport_instance->preferred_authentication_mode = AMQP_TRANSPORT_AUTHENTICATION_MODE_X509;
AzureIoTClient 30:20a85b733111 1955 }
AzureIoTClient 30:20a85b733111 1956 }
AzureIoTClient 25:63f7d371c030 1957
AzureIoTClient 30:20a85b733111 1958 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_078: [IoTHubTransport_AMQP_Common_Register shall return a handle to `amqp_device_instance` as a IOTHUB_DEVICE_HANDLE]
AzureIoTClient 30:20a85b733111 1959 result = (IOTHUB_DEVICE_HANDLE)amqp_device_instance;
AzureIoTClient 30:20a85b733111 1960 }
AzureIoTClient 30:20a85b733111 1961 }
AzureIoTClient 26:ee14eed604f6 1962 }
AzureIoTClient 25:63f7d371c030 1963
AzureIoTClient 30:20a85b733111 1964 if (result == NULL)
AzureIoTClient 26:ee14eed604f6 1965 {
AzureIoTClient 30:20a85b733111 1966 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_077: [If IoTHubTransport_AMQP_Common_Register fails, it shall free all memory it allocated]
AzureIoTClient 30:20a85b733111 1967 internal_destroy_amqp_device_instance(amqp_device_instance);
AzureIoTClient 30:20a85b733111 1968 }
AzureIoTClient 26:ee14eed604f6 1969 }
AzureIoTClient 26:ee14eed604f6 1970 }
AzureIoTClient 26:ee14eed604f6 1971 }
AzureIoTClient 25:63f7d371c030 1972
AzureIoTClient 26:ee14eed604f6 1973 return result;
AzureIoTClient 25:63f7d371c030 1974 }
AzureIoTClient 25:63f7d371c030 1975
AzureIoTClient 25:63f7d371c030 1976 void IoTHubTransport_AMQP_Common_Unregister(IOTHUB_DEVICE_HANDLE deviceHandle)
AzureIoTClient 25:63f7d371c030 1977 {
AzureIoTClient 30:20a85b733111 1978 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_079: [if `deviceHandle` provided is NULL, IoTHubTransport_AMQP_Common_Unregister shall return.]
AzureIoTClient 26:ee14eed604f6 1979 if (deviceHandle == NULL)
AzureIoTClient 26:ee14eed604f6 1980 {
AzureIoTClient 30:20a85b733111 1981 LogError("Failed to unregister device (deviceHandle is NULL).");
AzureIoTClient 26:ee14eed604f6 1982 }
AzureIoTClient 26:ee14eed604f6 1983 else
AzureIoTClient 26:ee14eed604f6 1984 {
AzureIoTClient 30:20a85b733111 1985 AMQP_TRANSPORT_DEVICE_INSTANCE* registered_device = (AMQP_TRANSPORT_DEVICE_INSTANCE*)deviceHandle;
AzureIoTClient 30:20a85b733111 1986 const char* device_id;
AzureIoTClient 30:20a85b733111 1987 LIST_ITEM_HANDLE list_item;
AzureIoTClient 25:63f7d371c030 1988
AzureIoTClient 30:20a85b733111 1989 if ((device_id = STRING_c_str(registered_device->device_id)) == NULL)
AzureIoTClient 30:20a85b733111 1990 {
AzureIoTClient 30:20a85b733111 1991 LogError("Failed to unregister device (failed to get device id char ptr)");
AzureIoTClient 30:20a85b733111 1992 }
AzureIoTClient 30:20a85b733111 1993 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_080: [if `deviceHandle` has a NULL reference to its transport instance, IoTHubTransport_AMQP_Common_Unregister shall return.]
AzureIoTClient 30:20a85b733111 1994 else if (registered_device->transport_instance == NULL)
AzureIoTClient 30:20a85b733111 1995 {
AzureIoTClient 30:20a85b733111 1996 LogError("Failed to unregister device '%s' (deviceHandle does not have a transport state associated to).", device_id);
AzureIoTClient 30:20a85b733111 1997 }
AzureIoTClient 30:20a85b733111 1998 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_081: [If the device is not registered with this transport, IoTHubTransport_AMQP_Common_Unregister shall return]
AzureIoTClient 30:20a85b733111 1999 else if (!is_device_registered_ex(registered_device->transport_instance->registered_devices, device_id, &list_item))
AzureIoTClient 30:20a85b733111 2000 {
AzureIoTClient 30:20a85b733111 2001 LogError("Failed to unregister device '%s' (device is not registered within this transport).", device_id);
AzureIoTClient 30:20a85b733111 2002 }
AzureIoTClient 30:20a85b733111 2003 else
AzureIoTClient 30:20a85b733111 2004 {
AzureIoTClient 30:20a85b733111 2005 // Removing it first so the race hazzard is reduced between this function and DoWork. Best would be to use locks.
AzureIoTClient 30:20a85b733111 2006 if (singlylinkedlist_remove(registered_device->transport_instance->registered_devices, list_item) != RESULT_OK)
AzureIoTClient 30:20a85b733111 2007 {
AzureIoTClient 30:20a85b733111 2008 LogError("Failed to unregister device '%s' (singlylinkedlist_remove failed).", device_id);
AzureIoTClient 30:20a85b733111 2009 }
AzureIoTClient 30:20a85b733111 2010 else
AzureIoTClient 30:20a85b733111 2011 {
AzureIoTClient 30:20a85b733111 2012 // TODO: Q: should we go through waiting_to_send list and raise on_event_send_complete with BECAUSE_DESTROY ?
AzureIoTClient 25:63f7d371c030 2013
AzureIoTClient 30:20a85b733111 2014 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_01_012: [IoTHubTransport_AMQP_Common_Unregister shall destroy the C2D methods handler by calling iothubtransportamqp_methods_destroy]
AzureIoTClient 30:20a85b733111 2015 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_083: [IoTHubTransport_AMQP_Common_Unregister shall free all the memory allocated for the `device_instance`]
AzureIoTClient 30:20a85b733111 2016 internal_destroy_amqp_device_instance(registered_device);
AzureIoTClient 30:20a85b733111 2017 }
AzureIoTClient 30:20a85b733111 2018 }
AzureIoTClient 26:ee14eed604f6 2019 }
AzureIoTClient 25:63f7d371c030 2020 }
AzureIoTClient 25:63f7d371c030 2021
AzureIoTClient 25:63f7d371c030 2022 void IoTHubTransport_AMQP_Common_Destroy(TRANSPORT_LL_HANDLE handle)
AzureIoTClient 25:63f7d371c030 2023 {
AzureIoTClient 30:20a85b733111 2024 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_013: [If `handle` is NULL, IoTHubTransport_AMQP_Common_Destroy shall return immediatelly]
AzureIoTClient 30:20a85b733111 2025 if (handle == NULL)
AzureIoTClient 30:20a85b733111 2026 {
AzureIoTClient 30:20a85b733111 2027 LogError("Failed to destroy AMQP transport instance (handle is NULL)");
AzureIoTClient 30:20a85b733111 2028 }
AzureIoTClient 30:20a85b733111 2029 else
AzureIoTClient 30:20a85b733111 2030 {
AzureIoTClient 30:20a85b733111 2031 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_014: [IoTHubTransport_AMQP_Common_Destroy shall invoke IoTHubTransport_AMQP_Common_Unregister on each of its registered devices.]
AzureIoTClient 30:20a85b733111 2032 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_015: [All members of `instance` (including tls_io) shall be destroyed and its memory released]
AzureIoTClient 30:20a85b733111 2033 internal_destroy_instance((AMQP_TRANSPORT_INSTANCE*)handle);
AzureIoTClient 26:ee14eed604f6 2034 }
AzureIoTClient 25:63f7d371c030 2035 }
AzureIoTClient 25:63f7d371c030 2036
AzureIoTClient 25:63f7d371c030 2037 int IoTHubTransport_AMQP_Common_SetRetryPolicy(TRANSPORT_LL_HANDLE handle, IOTHUB_CLIENT_RETRY_POLICY retryPolicy, size_t retryTimeoutLimitInSeconds)
AzureIoTClient 25:63f7d371c030 2038 {
AzureIoTClient 25:63f7d371c030 2039 int result;
AzureIoTClient 32:babfd49032ff 2040
AzureIoTClient 32:babfd49032ff 2041 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_128: [If `handle` is NULL, `IoTHubTransport_AMQP_Common_SetRetryPolicy` shall fail and return non-zero.]
AzureIoTClient 32:babfd49032ff 2042 if (handle == NULL)
AzureIoTClient 32:babfd49032ff 2043 {
AzureIoTClient 32:babfd49032ff 2044 LogError("Cannot set retry policy (transport handle is NULL)");
AzureIoTClient 32:babfd49032ff 2045 result = __FAILURE__;
AzureIoTClient 32:babfd49032ff 2046 }
AzureIoTClient 32:babfd49032ff 2047 else
AzureIoTClient 32:babfd49032ff 2048 {
AzureIoTClient 32:babfd49032ff 2049 RETRY_CONTROL_HANDLE new_retry_control;
AzureIoTClient 25:63f7d371c030 2050
AzureIoTClient 32:babfd49032ff 2051 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_129: [`transport_instance->connection_retry_control` shall be set using retry_control_create(), passing `retryPolicy` and `retryTimeoutLimitInSeconds`.]
AzureIoTClient 32:babfd49032ff 2052 if ((new_retry_control = retry_control_create(retryPolicy, (unsigned int)retryTimeoutLimitInSeconds)) == NULL)
AzureIoTClient 32:babfd49032ff 2053 {
AzureIoTClient 32:babfd49032ff 2054 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_130: [If retry_control_create() fails, `IoTHubTransport_AMQP_Common_SetRetryPolicy` shall fail and return non-zero.]
AzureIoTClient 32:babfd49032ff 2055 LogError("Cannot set retry policy (retry_control_create failed)");
AzureIoTClient 32:babfd49032ff 2056 result = __FAILURE__;
AzureIoTClient 32:babfd49032ff 2057 }
AzureIoTClient 32:babfd49032ff 2058 else
AzureIoTClient 32:babfd49032ff 2059 {
AzureIoTClient 32:babfd49032ff 2060 AMQP_TRANSPORT_INSTANCE* transport_instance = (AMQP_TRANSPORT_INSTANCE*)handle;
AzureIoTClient 32:babfd49032ff 2061 RETRY_CONTROL_HANDLE previous_retry_control = transport_instance->connection_retry_control;
AzureIoTClient 25:63f7d371c030 2062
AzureIoTClient 32:babfd49032ff 2063 transport_instance->connection_retry_control = new_retry_control;
AzureIoTClient 32:babfd49032ff 2064
AzureIoTClient 32:babfd49032ff 2065 retry_control_destroy(previous_retry_control);
AzureIoTClient 32:babfd49032ff 2066
AzureIoTClient 32:babfd49032ff 2067 LogInfo("Retry policy set (%d, timeout = %d)", retryPolicy, retryTimeoutLimitInSeconds);
AzureIoTClient 32:babfd49032ff 2068
AzureIoTClient 32:babfd49032ff 2069 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_128: [If no errors occur, `IoTHubTransport_AMQP_Common_SetRetryPolicy` shall return zero.]
AzureIoTClient 32:babfd49032ff 2070 result = RESULT_OK;
AzureIoTClient 32:babfd49032ff 2071 }
AzureIoTClient 32:babfd49032ff 2072 }
AzureIoTClient 32:babfd49032ff 2073
AzureIoTClient 25:63f7d371c030 2074 return result;
AzureIoTClient 25:63f7d371c030 2075 }
AzureIoTClient 25:63f7d371c030 2076
AzureIoTClient 25:63f7d371c030 2077 STRING_HANDLE IoTHubTransport_AMQP_Common_GetHostname(TRANSPORT_LL_HANDLE handle)
AzureIoTClient 25:63f7d371c030 2078 {
AzureIoTClient 25:63f7d371c030 2079 STRING_HANDLE result;
AzureIoTClient 30:20a85b733111 2080
AzureIoTClient 30:20a85b733111 2081 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_02_001: [If `handle` is NULL, `IoTHubTransport_AMQP_Common_GetHostname` shall return NULL.]
AzureIoTClient 30:20a85b733111 2082 if (handle == NULL)
AzureIoTClient 25:63f7d371c030 2083 {
AzureIoTClient 30:20a85b733111 2084 LogError("Cannot provide the target host name (transport handle is NULL).");
AzureIoTClient 30:20a85b733111 2085
AzureIoTClient 30:20a85b733111 2086 result = NULL;
AzureIoTClient 30:20a85b733111 2087 }
AzureIoTClient 30:20a85b733111 2088 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_02_002: [IoTHubTransport_AMQP_Common_GetHostname shall return a copy of `instance->iothub_target_fqdn`.]
AzureIoTClient 30:20a85b733111 2089 else if ((result = STRING_clone(((AMQP_TRANSPORT_INSTANCE*)(handle))->iothub_host_fqdn)) == NULL)
AzureIoTClient 30:20a85b733111 2090 {
AzureIoTClient 30:20a85b733111 2091 LogError("Cannot provide the target host name (STRING_clone failed).");
AzureIoTClient 30:20a85b733111 2092 }
AzureIoTClient 30:20a85b733111 2093
AzureIoTClient 30:20a85b733111 2094 return result;
AzureIoTClient 30:20a85b733111 2095 }
AzureIoTClient 30:20a85b733111 2096
AzureIoTClient 30:20a85b733111 2097 IOTHUB_CLIENT_RESULT IoTHubTransport_AMQP_Common_SendMessageDisposition(MESSAGE_CALLBACK_INFO* message_data, IOTHUBMESSAGE_DISPOSITION_RESULT disposition)
AzureIoTClient 30:20a85b733111 2098 {
AzureIoTClient 30:20a85b733111 2099 IOTHUB_CLIENT_RESULT result;
AzureIoTClient 30:20a85b733111 2100 if (message_data == NULL)
AzureIoTClient 30:20a85b733111 2101 {
AzureIoTClient 30:20a85b733111 2102 /* Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_10_001: [If messageData is NULL, IoTHubTransport_AMQP_Common_SendMessageDisposition shall fail and return IOTHUB_CLIENT_INVALID_ARG.] */
AzureIoTClient 30:20a85b733111 2103 LogError("Failed sending message disposition (message_data is NULL)");
AzureIoTClient 30:20a85b733111 2104 result = IOTHUB_CLIENT_INVALID_ARG;
AzureIoTClient 25:63f7d371c030 2105 }
AzureIoTClient 25:63f7d371c030 2106 else
AzureIoTClient 25:63f7d371c030 2107 {
AzureIoTClient 30:20a85b733111 2108 /* Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_10_002: [If any of the messageData fields are NULL, IoTHubTransport_AMQP_Common_SendMessageDisposition shall fail and return IOTHUB_CLIENT_INVALID_ARG.] */
AzureIoTClient 30:20a85b733111 2109 if (message_data->messageHandle == NULL || message_data->transportContext == NULL)
AzureIoTClient 30:20a85b733111 2110 {
AzureIoTClient 30:20a85b733111 2111 LogError("Failed sending message disposition (message_data->messageHandle (%p) or message_data->transportContext (%p) are NULL)", message_data->messageHandle, message_data->transportContext);
AzureIoTClient 30:20a85b733111 2112 result = IOTHUB_CLIENT_INVALID_ARG;
AzureIoTClient 30:20a85b733111 2113 }
AzureIoTClient 30:20a85b733111 2114 else
AzureIoTClient 30:20a85b733111 2115 {
AzureIoTClient 30:20a85b733111 2116 DEVICE_MESSAGE_DISPOSITION_INFO* device_message_disposition_info;
AzureIoTClient 30:20a85b733111 2117
AzureIoTClient 30:20a85b733111 2118 /* Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_10_004: [IoTHubTransport_AMQP_Common_SendMessageDisposition shall convert the given IOTHUBMESSAGE_DISPOSITION_RESULT to the equivalent AMQP_VALUE and will return the result of calling messagereceiver_send_message_disposition. ] */
AzureIoTClient 30:20a85b733111 2119 DEVICE_MESSAGE_DISPOSITION_RESULT device_disposition_result = get_device_disposition_result_from(disposition);
AzureIoTClient 30:20a85b733111 2120
AzureIoTClient 30:20a85b733111 2121 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_112: [A DEVICE_MESSAGE_DISPOSITION_INFO instance shall be created with a copy of the `link_name` and `message_id` contained in `message_data`]
AzureIoTClient 30:20a85b733111 2122 if ((device_message_disposition_info = create_device_message_disposition_info_from(message_data)) == NULL)
AzureIoTClient 30:20a85b733111 2123 {
AzureIoTClient 30:20a85b733111 2124 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_113: [If the DEVICE_MESSAGE_DISPOSITION_INFO fails to be created, `IoTHubTransport_AMQP_Common_SendMessageDisposition()` shall fail and return IOTHUB_CLIENT_ERROR]
AzureIoTClient 30:20a85b733111 2125 LogError("Device '%s' failed sending message disposition (failed creating DEVICE_MESSAGE_DISPOSITION_RESULT)", STRING_c_str(message_data->transportContext->device_state->device_id));
AzureIoTClient 30:20a85b733111 2126 result = IOTHUB_CLIENT_ERROR;
AzureIoTClient 30:20a85b733111 2127 }
AzureIoTClient 30:20a85b733111 2128 else
AzureIoTClient 30:20a85b733111 2129 {
AzureIoTClient 30:20a85b733111 2130 /* Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_10_003: [IoTHubTransport_AMQP_Common_SendMessageDisposition shall fail and return IOTHUB_CLIENT_ERROR if the POST message fails, otherwise return IOTHUB_CLIENT_OK.] */
AzureIoTClient 30:20a85b733111 2131 if (device_send_message_disposition(message_data->transportContext->device_state->device_handle, device_message_disposition_info, device_disposition_result) != RESULT_OK)
AzureIoTClient 30:20a85b733111 2132 {
AzureIoTClient 30:20a85b733111 2133 LogError("Device '%s' failed sending message disposition (device_send_message_disposition failed)", STRING_c_str(message_data->transportContext->device_state->device_id));
AzureIoTClient 30:20a85b733111 2134 result = IOTHUB_CLIENT_ERROR;
AzureIoTClient 30:20a85b733111 2135 }
AzureIoTClient 30:20a85b733111 2136 else
AzureIoTClient 30:20a85b733111 2137 {
AzureIoTClient 30:20a85b733111 2138 IoTHubMessage_Destroy(message_data->messageHandle);
AzureIoTClient 30:20a85b733111 2139 MESSAGE_CALLBACK_INFO_Destroy(message_data);
AzureIoTClient 30:20a85b733111 2140 result = IOTHUB_CLIENT_OK;
AzureIoTClient 30:20a85b733111 2141 }
AzureIoTClient 30:20a85b733111 2142
AzureIoTClient 30:20a85b733111 2143 // Codes_SRS_IOTHUBTRANSPORT_AMQP_COMMON_09_114: [`IoTHubTransport_AMQP_Common_SendMessageDisposition()` shall destroy the DEVICE_MESSAGE_DISPOSITION_INFO instance]
AzureIoTClient 30:20a85b733111 2144 destroy_device_message_disposition_info(device_message_disposition_info);
AzureIoTClient 30:20a85b733111 2145 }
AzureIoTClient 30:20a85b733111 2146 }
AzureIoTClient 25:63f7d371c030 2147 }
AzureIoTClient 30:20a85b733111 2148
AzureIoTClient 25:63f7d371c030 2149 return result;
AzureIoTClient 25:63f7d371c030 2150 }
AzureIoTClient 25:63f7d371c030 2151