Microsoft Azure IoTHub client AMQP transport

Dependents:   sht15_remote_monitoring RobotArmDemo iothub_client_sample_amqp iothub_client_sample_amqp ... more

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

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

Who changed what in which revision?

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