Xin Zhang / azure-iot-c-sdk-f767zi

Dependents:   samplemqtt

Committer:
XinZhangMS
Date:
Thu Aug 23 06:52:14 2018 +0000
Revision:
0:f7f1f0d76dd6
azure-c-sdk for mbed os supporting NUCLEO_F767ZI

Who changed what in which revision?

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