Microsoft Azure IoTHub client AMQP transport

Dependents:   sht15_remote_monitoring RobotArmDemo iothub_client_sample_amqp iothub_client_sample_amqp ... more

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

Committer:
AzureIoTClient
Date:
Mon Sep 11 09:22:16 2017 -0700
Revision:
41:71c01aa3df1a
Parent:
34:51d158b409d2
Child:
42:c2eaa912a28c
1.1.23

Who changed what in which revision?

UserRevisionLine numberNew contents of line
AzureIoTClient 30:20a85b733111 1 // Copyright (c) Microsoft. All rights reserved.
AzureIoTClient 30:20a85b733111 2 // Licensed under the MIT license. See LICENSE file in the project root for full license information.
AzureIoTClient 30:20a85b733111 3
AzureIoTClient 30:20a85b733111 4 #include <stdlib.h>
AzureIoTClient 30:20a85b733111 5 #include "iothubtransport_amqp_cbs_auth.h"
AzureIoTClient 30:20a85b733111 6 #include "azure_c_shared_utility/optimize_size.h"
AzureIoTClient 30:20a85b733111 7 #include "azure_c_shared_utility/gballoc.h"
AzureIoTClient 30:20a85b733111 8 #include "azure_c_shared_utility/agenttime.h"
AzureIoTClient 30:20a85b733111 9 #include "azure_c_shared_utility/xlogging.h"
AzureIoTClient 30:20a85b733111 10 #include "azure_c_shared_utility/sastoken.h"
AzureIoTClient 30:20a85b733111 11
AzureIoTClient 30:20a85b733111 12 #define RESULT_OK 0
AzureIoTClient 30:20a85b733111 13 #define INDEFINITE_TIME ((time_t)(-1))
AzureIoTClient 30:20a85b733111 14 #define SAS_TOKEN_TYPE "servicebus.windows.net:sastoken"
AzureIoTClient 30:20a85b733111 15 #define IOTHUB_DEVICES_PATH_FMT "%s/devices/%s"
AzureIoTClient 30:20a85b733111 16 #define DEFAULT_CBS_REQUEST_TIMEOUT_SECS UINT32_MAX
AzureIoTClient 30:20a85b733111 17 #define DEFAULT_SAS_TOKEN_LIFETIME_SECS 3600
AzureIoTClient 30:20a85b733111 18 #define DEFAULT_SAS_TOKEN_REFRESH_TIME_SECS 1800
AzureIoTClient 30:20a85b733111 19
AzureIoTClient 30:20a85b733111 20 typedef struct AUTHENTICATION_INSTANCE_TAG
AzureIoTClient 30:20a85b733111 21 {
AzureIoTClient 34:51d158b409d2 22 const char* device_id;
AzureIoTClient 34:51d158b409d2 23 STRING_HANDLE iothub_host_fqdn;
AzureIoTClient 34:51d158b409d2 24
AzureIoTClient 34:51d158b409d2 25 ON_AUTHENTICATION_STATE_CHANGED_CALLBACK on_state_changed_callback;
AzureIoTClient 34:51d158b409d2 26 void* on_state_changed_callback_context;
AzureIoTClient 30:20a85b733111 27
AzureIoTClient 34:51d158b409d2 28 ON_AUTHENTICATION_ERROR_CALLBACK on_error_callback;
AzureIoTClient 34:51d158b409d2 29 void* on_error_callback_context;
AzureIoTClient 34:51d158b409d2 30
AzureIoTClient 34:51d158b409d2 31 size_t cbs_request_timeout_secs;
AzureIoTClient 34:51d158b409d2 32 size_t sas_token_lifetime_secs;
AzureIoTClient 34:51d158b409d2 33 size_t sas_token_refresh_time_secs;
AzureIoTClient 30:20a85b733111 34
AzureIoTClient 34:51d158b409d2 35 AUTHENTICATION_STATE state;
AzureIoTClient 34:51d158b409d2 36 CBS_HANDLE cbs_handle;
AzureIoTClient 34:51d158b409d2 37
AzureIoTClient 34:51d158b409d2 38 bool is_cbs_put_token_in_progress;
AzureIoTClient 34:51d158b409d2 39 bool is_sas_token_refresh_in_progress;
AzureIoTClient 30:20a85b733111 40
AzureIoTClient 34:51d158b409d2 41 time_t current_sas_token_put_time;
AzureIoTClient 30:20a85b733111 42
AzureIoTClient 34:51d158b409d2 43 // Auth module used to generating handle authorization
AzureIoTClient 34:51d158b409d2 44 // with either SAS Token, x509 Certs, and Device SAS Token
AzureIoTClient 34:51d158b409d2 45 IOTHUB_AUTHORIZATION_HANDLE authorization_module;
AzureIoTClient 30:20a85b733111 46 } AUTHENTICATION_INSTANCE;
AzureIoTClient 30:20a85b733111 47
AzureIoTClient 30:20a85b733111 48
AzureIoTClient 30:20a85b733111 49 // Helper functions:
AzureIoTClient 30:20a85b733111 50
AzureIoTClient 30:20a85b733111 51 static int get_seconds_since_epoch(double *seconds)
AzureIoTClient 30:20a85b733111 52 {
AzureIoTClient 34:51d158b409d2 53 int result;
AzureIoTClient 34:51d158b409d2 54 time_t current_time;
AzureIoTClient 30:20a85b733111 55
AzureIoTClient 34:51d158b409d2 56 if ((current_time = get_time(NULL)) == INDEFINITE_TIME)
AzureIoTClient 34:51d158b409d2 57 {
AzureIoTClient 34:51d158b409d2 58 LogError("Failed getting the current local time (get_time() failed)");
AzureIoTClient 34:51d158b409d2 59 result = __FAILURE__;
AzureIoTClient 34:51d158b409d2 60 }
AzureIoTClient 34:51d158b409d2 61 else
AzureIoTClient 34:51d158b409d2 62 {
AzureIoTClient 34:51d158b409d2 63 *seconds = get_difftime(current_time, (time_t)0);
AzureIoTClient 30:20a85b733111 64
AzureIoTClient 34:51d158b409d2 65 result = RESULT_OK;
AzureIoTClient 34:51d158b409d2 66 }
AzureIoTClient 30:20a85b733111 67
AzureIoTClient 34:51d158b409d2 68 return result;
AzureIoTClient 30:20a85b733111 69 }
AzureIoTClient 30:20a85b733111 70
AzureIoTClient 30:20a85b733111 71 static void update_state(AUTHENTICATION_INSTANCE* instance, AUTHENTICATION_STATE new_state)
AzureIoTClient 30:20a85b733111 72 {
AzureIoTClient 34:51d158b409d2 73 if (new_state != instance->state)
AzureIoTClient 34:51d158b409d2 74 {
AzureIoTClient 34:51d158b409d2 75 AUTHENTICATION_STATE previous_state = instance->state;
AzureIoTClient 34:51d158b409d2 76 instance->state = new_state;
AzureIoTClient 30:20a85b733111 77
AzureIoTClient 34:51d158b409d2 78 if (instance->on_state_changed_callback != NULL)
AzureIoTClient 34:51d158b409d2 79 {
AzureIoTClient 34:51d158b409d2 80 instance->on_state_changed_callback(instance->on_state_changed_callback_context, previous_state, new_state);
AzureIoTClient 34:51d158b409d2 81 }
AzureIoTClient 34:51d158b409d2 82 }
AzureIoTClient 30:20a85b733111 83 }
AzureIoTClient 30:20a85b733111 84
AzureIoTClient 30:20a85b733111 85 static void notify_error(AUTHENTICATION_INSTANCE* instance, AUTHENTICATION_ERROR_CODE error_code)
AzureIoTClient 30:20a85b733111 86 {
AzureIoTClient 34:51d158b409d2 87 if (instance->on_error_callback != NULL)
AzureIoTClient 34:51d158b409d2 88 {
AzureIoTClient 34:51d158b409d2 89 instance->on_error_callback(instance->on_error_callback_context, error_code);
AzureIoTClient 34:51d158b409d2 90 }
AzureIoTClient 30:20a85b733111 91 }
AzureIoTClient 30:20a85b733111 92
AzureIoTClient 30:20a85b733111 93 static int verify_cbs_put_token_timeout(AUTHENTICATION_INSTANCE* instance, bool* is_timed_out)
AzureIoTClient 30:20a85b733111 94 {
AzureIoTClient 34:51d158b409d2 95 int result;
AzureIoTClient 30:20a85b733111 96
AzureIoTClient 34:51d158b409d2 97 if (instance->current_sas_token_put_time == INDEFINITE_TIME)
AzureIoTClient 34:51d158b409d2 98 {
AzureIoTClient 34:51d158b409d2 99 result = __FAILURE__;
AzureIoTClient 34:51d158b409d2 100 LogError("Failed verifying if cbs_put_token has timed out (current_sas_token_put_time is not set)");
AzureIoTClient 34:51d158b409d2 101 }
AzureIoTClient 34:51d158b409d2 102 else
AzureIoTClient 34:51d158b409d2 103 {
AzureIoTClient 34:51d158b409d2 104 time_t current_time;
AzureIoTClient 30:20a85b733111 105
AzureIoTClient 34:51d158b409d2 106 if ((current_time = get_time(NULL)) == INDEFINITE_TIME)
AzureIoTClient 34:51d158b409d2 107 {
AzureIoTClient 34:51d158b409d2 108 result = __FAILURE__;
AzureIoTClient 34:51d158b409d2 109 LogError("Failed verifying if cbs_put_token has timed out (get_time failed)");
AzureIoTClient 34:51d158b409d2 110 }
AzureIoTClient 34:51d158b409d2 111 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_083: [authentication_do_work() shall check for authentication timeout comparing the current time since `instance->current_sas_token_put_time` to `instance->cbs_request_timeout_secs`]
AzureIoTClient 34:51d158b409d2 112 else if ((uint32_t)get_difftime(current_time, instance->current_sas_token_put_time) >= instance->cbs_request_timeout_secs)
AzureIoTClient 34:51d158b409d2 113 {
AzureIoTClient 34:51d158b409d2 114 *is_timed_out = true;
AzureIoTClient 34:51d158b409d2 115 result = RESULT_OK;
AzureIoTClient 34:51d158b409d2 116 }
AzureIoTClient 34:51d158b409d2 117 else
AzureIoTClient 34:51d158b409d2 118 {
AzureIoTClient 34:51d158b409d2 119 *is_timed_out = false;
AzureIoTClient 34:51d158b409d2 120 result = RESULT_OK;
AzureIoTClient 34:51d158b409d2 121 }
AzureIoTClient 34:51d158b409d2 122 }
AzureIoTClient 30:20a85b733111 123
AzureIoTClient 34:51d158b409d2 124 return result;
AzureIoTClient 30:20a85b733111 125 }
AzureIoTClient 30:20a85b733111 126
AzureIoTClient 30:20a85b733111 127 static int verify_sas_token_refresh_timeout(AUTHENTICATION_INSTANCE* instance, bool* is_timed_out)
AzureIoTClient 30:20a85b733111 128 {
AzureIoTClient 34:51d158b409d2 129 int result;
AzureIoTClient 30:20a85b733111 130
AzureIoTClient 34:51d158b409d2 131 if (instance->current_sas_token_put_time == INDEFINITE_TIME)
AzureIoTClient 34:51d158b409d2 132 {
AzureIoTClient 34:51d158b409d2 133 result = __FAILURE__;
AzureIoTClient 34:51d158b409d2 134 LogError("Failed verifying if SAS token refresh timed out (current_sas_token_put_time is not set)");
AzureIoTClient 34:51d158b409d2 135 }
AzureIoTClient 30:20a85b733111 136 else
AzureIoTClient 30:20a85b733111 137 {
AzureIoTClient 34:51d158b409d2 138 time_t current_time;
AzureIoTClient 34:51d158b409d2 139
AzureIoTClient 34:51d158b409d2 140 if ((current_time = get_time(NULL)) == INDEFINITE_TIME)
AzureIoTClient 30:20a85b733111 141 {
AzureIoTClient 34:51d158b409d2 142 result = __FAILURE__;
AzureIoTClient 34:51d158b409d2 143 LogError("Failed verifying if SAS token refresh timed out (get_time failed)");
AzureIoTClient 34:51d158b409d2 144 }
AzureIoTClient 34:51d158b409d2 145 else if ((uint32_t)get_difftime(current_time, instance->current_sas_token_put_time) >= instance->sas_token_refresh_time_secs)
AzureIoTClient 34:51d158b409d2 146 {
AzureIoTClient 34:51d158b409d2 147 *is_timed_out = true;
AzureIoTClient 34:51d158b409d2 148 result = RESULT_OK;
AzureIoTClient 34:51d158b409d2 149 }
AzureIoTClient 34:51d158b409d2 150 else
AzureIoTClient 34:51d158b409d2 151 {
AzureIoTClient 34:51d158b409d2 152 *is_timed_out = false;
AzureIoTClient 34:51d158b409d2 153 result = RESULT_OK;
AzureIoTClient 30:20a85b733111 154 }
AzureIoTClient 30:20a85b733111 155 }
AzureIoTClient 30:20a85b733111 156
AzureIoTClient 34:51d158b409d2 157 return result;
AzureIoTClient 30:20a85b733111 158 }
AzureIoTClient 30:20a85b733111 159
AzureIoTClient 34:51d158b409d2 160 static STRING_HANDLE create_devices_path(STRING_HANDLE iothub_host_fqdn, const char* device_id)
AzureIoTClient 30:20a85b733111 161 {
AzureIoTClient 34:51d158b409d2 162 STRING_HANDLE devices_path;
AzureIoTClient 34:51d158b409d2 163 if ((devices_path = STRING_construct_sprintf(IOTHUB_DEVICES_PATH_FMT, STRING_c_str(iothub_host_fqdn), device_id)) == NULL)
AzureIoTClient 34:51d158b409d2 164 {
AzureIoTClient 34:51d158b409d2 165 LogError("Failed creating devices_path (STRING_new failed)");
AzureIoTClient 34:51d158b409d2 166 }
AzureIoTClient 34:51d158b409d2 167 return devices_path;
AzureIoTClient 30:20a85b733111 168 }
AzureIoTClient 30:20a85b733111 169
AzureIoTClient 30:20a85b733111 170 static void on_cbs_put_token_complete_callback(void* context, CBS_OPERATION_RESULT operation_result, unsigned int status_code, const char* status_description)
AzureIoTClient 30:20a85b733111 171 {
AzureIoTClient 30:20a85b733111 172 #ifdef NO_LOGGING
AzureIoTClient 34:51d158b409d2 173 UNUSED(status_code);
AzureIoTClient 34:51d158b409d2 174 UNUSED(status_description);
AzureIoTClient 30:20a85b733111 175 #endif
AzureIoTClient 34:51d158b409d2 176 AUTHENTICATION_INSTANCE* instance = (AUTHENTICATION_INSTANCE*)context;
AzureIoTClient 30:20a85b733111 177
AzureIoTClient 34:51d158b409d2 178 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_095: [`instance->is_sas_token_refresh_in_progress` and `instance->is_cbs_put_token_in_progress` shall be set to FALSE]
AzureIoTClient 34:51d158b409d2 179 instance->is_cbs_put_token_in_progress = false;
AzureIoTClient 30:20a85b733111 180
AzureIoTClient 34:51d158b409d2 181 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_091: [If `result` is CBS_OPERATION_RESULT_OK `instance->state` shall be set to AUTHENTICATION_STATE_STARTED and `instance->on_state_changed_callback` invoked]
AzureIoTClient 34:51d158b409d2 182 if (operation_result == CBS_OPERATION_RESULT_OK)
AzureIoTClient 34:51d158b409d2 183 {
AzureIoTClient 34:51d158b409d2 184 update_state(instance, AUTHENTICATION_STATE_STARTED);
AzureIoTClient 34:51d158b409d2 185 }
AzureIoTClient 34:51d158b409d2 186 else
AzureIoTClient 34:51d158b409d2 187 {
AzureIoTClient 34:51d158b409d2 188 LogError("CBS reported status code %u, error: '%s' for put-token operation for device '%s'", status_code, status_description, instance->device_id);
AzureIoTClient 30:20a85b733111 189
AzureIoTClient 34:51d158b409d2 190 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_092: [If `result` is not CBS_OPERATION_RESULT_OK `instance->state` shall be set to AUTHENTICATION_STATE_ERROR and `instance->on_state_changed_callback` invoked]
AzureIoTClient 34:51d158b409d2 191 update_state(instance, AUTHENTICATION_STATE_ERROR);
AzureIoTClient 30:20a85b733111 192
AzureIoTClient 34:51d158b409d2 193 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_094: [If `result` is not CBS_OPERATION_RESULT_OK and `instance->is_sas_token_refresh_in_progress` is TRUE, `instance->on_error_callback`shall be invoked with AUTHENTICATION_ERROR_SAS_REFRESH_FAILED]
AzureIoTClient 34:51d158b409d2 194 if (instance->is_sas_token_refresh_in_progress)
AzureIoTClient 34:51d158b409d2 195 {
AzureIoTClient 34:51d158b409d2 196 notify_error(instance, AUTHENTICATION_ERROR_SAS_REFRESH_FAILED);
AzureIoTClient 34:51d158b409d2 197 }
AzureIoTClient 34:51d158b409d2 198 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_093: [If `result` is not CBS_OPERATION_RESULT_OK and `instance->is_sas_token_refresh_in_progress` is FALSE, `instance->on_error_callback`shall be invoked with AUTHENTICATION_ERROR_AUTH_FAILED]
AzureIoTClient 34:51d158b409d2 199 else
AzureIoTClient 34:51d158b409d2 200 {
AzureIoTClient 34:51d158b409d2 201 notify_error(instance, AUTHENTICATION_ERROR_AUTH_FAILED);
AzureIoTClient 34:51d158b409d2 202 }
AzureIoTClient 34:51d158b409d2 203 }
AzureIoTClient 30:20a85b733111 204
AzureIoTClient 34:51d158b409d2 205 instance->is_sas_token_refresh_in_progress = false;
AzureIoTClient 30:20a85b733111 206 }
AzureIoTClient 30:20a85b733111 207
AzureIoTClient 34:51d158b409d2 208 static int put_SAS_token_to_cbs(AUTHENTICATION_INSTANCE* instance, STRING_HANDLE cbs_audience, char* sas_token)
AzureIoTClient 30:20a85b733111 209 {
AzureIoTClient 34:51d158b409d2 210 int result;
AzureIoTClient 30:20a85b733111 211
AzureIoTClient 34:51d158b409d2 212 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_043: [authentication_do_work() shall set `instance->is_cbs_put_token_in_progress` to TRUE]
AzureIoTClient 34:51d158b409d2 213 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_057: [authentication_do_work() shall set `instance->is_cbs_put_token_in_progress` to TRUE]
AzureIoTClient 34:51d158b409d2 214 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_075: [authentication_do_work() shall set `instance->is_cbs_put_token_in_progress` to TRUE]
AzureIoTClient 34:51d158b409d2 215 instance->is_cbs_put_token_in_progress = true;
AzureIoTClient 30:20a85b733111 216
AzureIoTClient 34:51d158b409d2 217 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_046: [The SAS token provided shall be sent to CBS using cbs_put_token(), using `servicebus.windows.net:sastoken` as token type, `devices_path` as audience and passing on_cbs_put_token_complete_callback]
AzureIoTClient 34:51d158b409d2 218 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_058: [The SAS token shall be sent to CBS using cbs_put_token(), using `servicebus.windows.net:sastoken` as token type, `devices_path` as audience and passing on_cbs_put_token_complete_callback]
AzureIoTClient 34:51d158b409d2 219 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_076: [The SAS token shall be sent to CBS using cbs_put_token(), using `servicebus.windows.net:sastoken` as token type, `devices_path` as audience and passing on_cbs_put_token_complete_callback]
AzureIoTClient 30:20a85b733111 220 const char* cbs_audience_c_str = STRING_c_str(cbs_audience);
AzureIoTClient 34:51d158b409d2 221 if (cbs_put_token_async(instance->cbs_handle, SAS_TOKEN_TYPE, cbs_audience_c_str, sas_token, on_cbs_put_token_complete_callback, instance) != RESULT_OK)
AzureIoTClient 34:51d158b409d2 222 {
AzureIoTClient 34:51d158b409d2 223 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_048: [If cbs_put_token() failed, authentication_do_work() shall set `instance->is_cbs_put_token_in_progress` to FALSE, destroy `devices_path` and return]
AzureIoTClient 34:51d158b409d2 224 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_060: [If cbs_put_token() fails, `instance->is_cbs_put_token_in_progress` shall be set to FALSE]
AzureIoTClient 34:51d158b409d2 225 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_078: [If cbs_put_token() fails, `instance->is_cbs_put_token_in_progress` shall be set to FALSE]
AzureIoTClient 34:51d158b409d2 226 instance->is_cbs_put_token_in_progress = false;
AzureIoTClient 34:51d158b409d2 227 result = __FAILURE__;
AzureIoTClient 34:51d158b409d2 228 LogError("Failed putting SAS token to CBS for device '%s' (cbs_put_token failed)", instance->device_id);
AzureIoTClient 34:51d158b409d2 229 }
AzureIoTClient 34:51d158b409d2 230 else
AzureIoTClient 34:51d158b409d2 231 {
AzureIoTClient 34:51d158b409d2 232 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_047: [If cbs_put_token() succeeds, authentication_do_work() shall set `instance->current_sas_token_put_time` with current time]
AzureIoTClient 34:51d158b409d2 233 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_059: [If cbs_put_token() succeeds, authentication_do_work() shall set `instance->current_sas_token_put_time` with current time]
AzureIoTClient 34:51d158b409d2 234 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_077: [If cbs_put_token() succeeds, authentication_do_work() shall set `instance->current_sas_token_put_time` with the current time]
AzureIoTClient 34:51d158b409d2 235 time_t current_time;
AzureIoTClient 30:20a85b733111 236
AzureIoTClient 34:51d158b409d2 237 if ((current_time = get_time(NULL)) == INDEFINITE_TIME)
AzureIoTClient 34:51d158b409d2 238 {
AzureIoTClient 34:51d158b409d2 239 LogError("Failed setting current_sas_token_put_time for device '%s' (get_time() failed)", instance->device_id);
AzureIoTClient 34:51d158b409d2 240 }
AzureIoTClient 30:20a85b733111 241
AzureIoTClient 34:51d158b409d2 242 instance->current_sas_token_put_time = current_time; // If it failed, fear not. `current_sas_token_put_time` shall be checked for INDEFINITE_TIME wherever it is used.
AzureIoTClient 30:20a85b733111 243
AzureIoTClient 34:51d158b409d2 244 result = RESULT_OK;
AzureIoTClient 34:51d158b409d2 245 }
AzureIoTClient 30:20a85b733111 246
AzureIoTClient 34:51d158b409d2 247 return result;
AzureIoTClient 30:20a85b733111 248 }
AzureIoTClient 30:20a85b733111 249
AzureIoTClient 34:51d158b409d2 250 static int create_and_put_SAS_token_to_cbs(AUTHENTICATION_INSTANCE* instance)
AzureIoTClient 30:20a85b733111 251 {
AzureIoTClient 34:51d158b409d2 252 int result;
AzureIoTClient 34:51d158b409d2 253 char* sas_token;
AzureIoTClient 34:51d158b409d2 254 STRING_HANDLE devices_path;
AzureIoTClient 30:20a85b733111 255
AzureIoTClient 34:51d158b409d2 256 if ((devices_path = create_devices_path(instance->iothub_host_fqdn, instance->device_id)) == NULL)
AzureIoTClient 34:51d158b409d2 257 {
AzureIoTClient 34:51d158b409d2 258 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_054: [If `devices_path` failed to be created, authentication_do_work() shall fail and return]
AzureIoTClient 34:51d158b409d2 259 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_072: [If `devices_path` failed to be created, authentication_do_work() shall fail and return]
AzureIoTClient 34:51d158b409d2 260 result = __FAILURE__;
AzureIoTClient 34:51d158b409d2 261 sas_token = NULL;
AzureIoTClient 34:51d158b409d2 262 LogError("Failed creating a SAS token (create_devices_path() failed)");
AzureIoTClient 34:51d158b409d2 263 }
AzureIoTClient 34:51d158b409d2 264 else
AzureIoTClient 34:51d158b409d2 265 {
AzureIoTClient 34:51d158b409d2 266 /* Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_07_001: [ authentication_do_work() shall determine what credential type is used SAS_TOKEN or DEVICE_KEY by calling IoTHubClient_Auth_Get_Credential_Type ] */
AzureIoTClient 34:51d158b409d2 267 IOTHUB_CREDENTIAL_TYPE cred_type = IoTHubClient_Auth_Get_Credential_Type(instance->authorization_module);
AzureIoTClient 41:71c01aa3df1a 268 if (cred_type == IOTHUB_CREDENTIAL_TYPE_DEVICE_KEY || cred_type == IOTHUB_CREDENTIAL_TYPE_DEVICE_AUTH)
AzureIoTClient 34:51d158b409d2 269 {
AzureIoTClient 34:51d158b409d2 270 double seconds_since_epoch;
AzureIoTClient 34:51d158b409d2 271 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_053: [A STRING_HANDLE, referred to as `devices_path`, shall be created from the following parts: iothub_host_fqdn + "/devices/" + device_id]
AzureIoTClient 34:51d158b409d2 272 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_071: [A STRING_HANDLE, referred to as `devices_path`, shall be created from the following parts: iothub_host_fqdn + "/devices/" + device_id]
AzureIoTClient 34:51d158b409d2 273 if (get_seconds_since_epoch(&seconds_since_epoch) != RESULT_OK)
AzureIoTClient 34:51d158b409d2 274 {
AzureIoTClient 34:51d158b409d2 275 result = __FAILURE__;
AzureIoTClient 34:51d158b409d2 276 sas_token = NULL;
AzureIoTClient 34:51d158b409d2 277 LogError("Failed creating a SAS token (get_seconds_since_epoch() failed)");
AzureIoTClient 34:51d158b409d2 278 }
AzureIoTClient 34:51d158b409d2 279 else
AzureIoTClient 34:51d158b409d2 280 {
AzureIoTClient 34:51d158b409d2 281 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_052: [The SAS token expiration time shall be calculated adding `instance->sas_token_lifetime_secs` to the current number of seconds since epoch time UTC]
AzureIoTClient 34:51d158b409d2 282 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_070: [The SAS token expiration time shall be calculated adding `instance->sas_token_lifetime_secs` to the current number of seconds since epoch time UTC]
AzureIoTClient 34:51d158b409d2 283 size_t sas_token_expiration_time_secs = (size_t)seconds_since_epoch + instance->sas_token_lifetime_secs;
AzureIoTClient 30:20a85b733111 284
AzureIoTClient 34:51d158b409d2 285 /* Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_049: [authentication_do_work() shall create a SAS token using IoTHubClient_Auth_Get_SasToken, unless it has failed previously] */
AzureIoTClient 34:51d158b409d2 286 sas_token = IoTHubClient_Auth_Get_SasToken(instance->authorization_module, STRING_c_str(devices_path), sas_token_expiration_time_secs);
AzureIoTClient 34:51d158b409d2 287 if (sas_token == NULL)
AzureIoTClient 34:51d158b409d2 288 {
AzureIoTClient 34:51d158b409d2 289 LogError("failure getting sas token.");
AzureIoTClient 34:51d158b409d2 290 result = __FAILURE__;
AzureIoTClient 34:51d158b409d2 291 }
AzureIoTClient 34:51d158b409d2 292 else
AzureIoTClient 34:51d158b409d2 293 {
AzureIoTClient 34:51d158b409d2 294 result = RESULT_OK;
AzureIoTClient 34:51d158b409d2 295 }
AzureIoTClient 34:51d158b409d2 296 }
AzureIoTClient 34:51d158b409d2 297 }
AzureIoTClient 34:51d158b409d2 298 else if (cred_type == IOTHUB_CREDENTIAL_TYPE_SAS_TOKEN)
AzureIoTClient 34:51d158b409d2 299 {
AzureIoTClient 34:51d158b409d2 300 /* Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_07_002: [ If credential Type is SAS_TOKEN authentication_do_work() shall validate the sas_token, and fail if it's not valid. ] */
AzureIoTClient 34:51d158b409d2 301 SAS_TOKEN_STATUS token_status = IoTHubClient_Auth_Is_SasToken_Valid(instance->authorization_module);
AzureIoTClient 34:51d158b409d2 302 if (token_status == SAS_TOKEN_STATUS_INVALID)
AzureIoTClient 34:51d158b409d2 303 {
AzureIoTClient 34:51d158b409d2 304 LogError("sas token is invalid.");
AzureIoTClient 34:51d158b409d2 305 sas_token = NULL;
AzureIoTClient 34:51d158b409d2 306 result = __FAILURE__;
AzureIoTClient 34:51d158b409d2 307 }
AzureIoTClient 34:51d158b409d2 308 else if (token_status == SAS_TOKEN_STATUS_FAILED)
AzureIoTClient 34:51d158b409d2 309 {
AzureIoTClient 34:51d158b409d2 310 LogError("testing Sas Token failed.");
AzureIoTClient 34:51d158b409d2 311 sas_token = NULL;
AzureIoTClient 34:51d158b409d2 312 result = __FAILURE__;
AzureIoTClient 34:51d158b409d2 313 }
AzureIoTClient 34:51d158b409d2 314 else
AzureIoTClient 34:51d158b409d2 315 {
AzureIoTClient 34:51d158b409d2 316 /* Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_049: [authentication_do_work() shall create a SAS token using IoTHubClient_Auth_Get_SasToken, unless it has failed previously] */
AzureIoTClient 34:51d158b409d2 317 sas_token = IoTHubClient_Auth_Get_SasToken(instance->authorization_module, NULL, 0);
AzureIoTClient 34:51d158b409d2 318 if (sas_token == NULL)
AzureIoTClient 34:51d158b409d2 319 {
AzureIoTClient 34:51d158b409d2 320 LogError("failure getting sas Token.");
AzureIoTClient 34:51d158b409d2 321 result = __FAILURE__;
AzureIoTClient 34:51d158b409d2 322 }
AzureIoTClient 34:51d158b409d2 323 else
AzureIoTClient 34:51d158b409d2 324 {
AzureIoTClient 34:51d158b409d2 325 result = RESULT_OK;
AzureIoTClient 34:51d158b409d2 326 }
AzureIoTClient 34:51d158b409d2 327 }
AzureIoTClient 34:51d158b409d2 328 }
AzureIoTClient 41:71c01aa3df1a 329 else if (cred_type == IOTHUB_CREDENTIAL_TYPE_X509 || cred_type == IOTHUB_CREDENTIAL_TYPE_X509_ECC)
AzureIoTClient 34:51d158b409d2 330 {
AzureIoTClient 34:51d158b409d2 331 sas_token = NULL;
AzureIoTClient 34:51d158b409d2 332 result = RESULT_OK;
AzureIoTClient 34:51d158b409d2 333 }
AzureIoTClient 34:51d158b409d2 334 else
AzureIoTClient 34:51d158b409d2 335 {
AzureIoTClient 34:51d158b409d2 336 LogError("failure unknown credential type found.");
AzureIoTClient 34:51d158b409d2 337 sas_token = NULL;
AzureIoTClient 34:51d158b409d2 338 result = __FAILURE__;
AzureIoTClient 34:51d158b409d2 339 }
AzureIoTClient 30:20a85b733111 340
AzureIoTClient 30:20a85b733111 341
AzureIoTClient 34:51d158b409d2 342 if (sas_token != NULL)
AzureIoTClient 34:51d158b409d2 343 {
AzureIoTClient 34:51d158b409d2 344 if (put_SAS_token_to_cbs(instance, devices_path, sas_token) != RESULT_OK)
AzureIoTClient 34:51d158b409d2 345 {
AzureIoTClient 34:51d158b409d2 346 result = __FAILURE__;
AzureIoTClient 34:51d158b409d2 347 LogError("Failed putting SAS token to CBS");
AzureIoTClient 34:51d158b409d2 348 }
AzureIoTClient 34:51d158b409d2 349 else
AzureIoTClient 34:51d158b409d2 350 {
AzureIoTClient 34:51d158b409d2 351 result = RESULT_OK;
AzureIoTClient 34:51d158b409d2 352 }
AzureIoTClient 34:51d158b409d2 353 free(sas_token);
AzureIoTClient 34:51d158b409d2 354 }
AzureIoTClient 34:51d158b409d2 355
AzureIoTClient 34:51d158b409d2 356 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_081: [authentication_do_work() shall free the memory it allocated for `devices_path`, `sasTokenKeyName` and SAS token]
AzureIoTClient 34:51d158b409d2 357 STRING_delete(devices_path);
AzureIoTClient 34:51d158b409d2 358 }
AzureIoTClient 34:51d158b409d2 359 return result;
AzureIoTClient 30:20a85b733111 360 }
AzureIoTClient 30:20a85b733111 361
AzureIoTClient 30:20a85b733111 362 // ---------- Set/Retrieve Options Helpers ----------//
AzureIoTClient 30:20a85b733111 363 static void* authentication_clone_option(const char* name, const void* value)
AzureIoTClient 30:20a85b733111 364 {
AzureIoTClient 34:51d158b409d2 365 void* result;
AzureIoTClient 30:20a85b733111 366
AzureIoTClient 34:51d158b409d2 367 if (name == NULL)
AzureIoTClient 34:51d158b409d2 368 {
AzureIoTClient 34:51d158b409d2 369 LogError("Failed to clone authentication option (name is NULL)");
AzureIoTClient 34:51d158b409d2 370 result = NULL;
AzureIoTClient 34:51d158b409d2 371 }
AzureIoTClient 34:51d158b409d2 372 else if (value == NULL)
AzureIoTClient 34:51d158b409d2 373 {
AzureIoTClient 34:51d158b409d2 374 LogError("Failed to clone authentication option (value is NULL)");
AzureIoTClient 34:51d158b409d2 375 result = NULL;
AzureIoTClient 34:51d158b409d2 376 }
AzureIoTClient 34:51d158b409d2 377 else
AzureIoTClient 34:51d158b409d2 378 {
AzureIoTClient 34:51d158b409d2 379 if (strcmp(AUTHENTICATION_OPTION_CBS_REQUEST_TIMEOUT_SECS, name) == 0 ||
AzureIoTClient 34:51d158b409d2 380 strcmp(AUTHENTICATION_OPTION_SAS_TOKEN_REFRESH_TIME_SECS, name) == 0 ||
AzureIoTClient 34:51d158b409d2 381 strcmp(AUTHENTICATION_OPTION_SAS_TOKEN_LIFETIME_SECS, name) == 0 ||
AzureIoTClient 34:51d158b409d2 382 strcmp(AUTHENTICATION_OPTION_SAVED_OPTIONS, name) == 0)
AzureIoTClient 34:51d158b409d2 383 {
AzureIoTClient 34:51d158b409d2 384 result = (void*)value;
AzureIoTClient 34:51d158b409d2 385 }
AzureIoTClient 34:51d158b409d2 386 else
AzureIoTClient 34:51d158b409d2 387 {
AzureIoTClient 34:51d158b409d2 388 LogError("Failed to clone authentication option (option with name '%s' is not suppported)", name);
AzureIoTClient 34:51d158b409d2 389 result = NULL;
AzureIoTClient 34:51d158b409d2 390 }
AzureIoTClient 34:51d158b409d2 391 }
AzureIoTClient 30:20a85b733111 392
AzureIoTClient 34:51d158b409d2 393 return result;
AzureIoTClient 30:20a85b733111 394 }
AzureIoTClient 30:20a85b733111 395
AzureIoTClient 30:20a85b733111 396 static void authentication_destroy_option(const char* name, const void* value)
AzureIoTClient 30:20a85b733111 397 {
AzureIoTClient 34:51d158b409d2 398 if (name == NULL)
AzureIoTClient 34:51d158b409d2 399 {
AzureIoTClient 34:51d158b409d2 400 LogError("Failed to destroy authentication option (name is NULL)");
AzureIoTClient 34:51d158b409d2 401 }
AzureIoTClient 34:51d158b409d2 402 else if (value == NULL)
AzureIoTClient 34:51d158b409d2 403 {
AzureIoTClient 34:51d158b409d2 404 LogError("Failed to destroy authentication option (value is NULL)");
AzureIoTClient 34:51d158b409d2 405 }
AzureIoTClient 34:51d158b409d2 406 else
AzureIoTClient 34:51d158b409d2 407 {
AzureIoTClient 34:51d158b409d2 408 if (strcmp(name, AUTHENTICATION_OPTION_SAVED_OPTIONS) == 0)
AzureIoTClient 34:51d158b409d2 409 {
AzureIoTClient 34:51d158b409d2 410 OptionHandler_Destroy((OPTIONHANDLER_HANDLE)value);
AzureIoTClient 34:51d158b409d2 411 }
AzureIoTClient 34:51d158b409d2 412 }
AzureIoTClient 30:20a85b733111 413 }
AzureIoTClient 30:20a85b733111 414
AzureIoTClient 30:20a85b733111 415 // Public APIs:
AzureIoTClient 30:20a85b733111 416 int authentication_start(AUTHENTICATION_HANDLE authentication_handle, const CBS_HANDLE cbs_handle)
AzureIoTClient 30:20a85b733111 417 {
AzureIoTClient 34:51d158b409d2 418 int result;
AzureIoTClient 30:20a85b733111 419
AzureIoTClient 34:51d158b409d2 420 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_025: [If authentication_handle is NULL, authentication_start() shall fail and return __FAILURE__ as error code]
AzureIoTClient 34:51d158b409d2 421 if (authentication_handle == NULL)
AzureIoTClient 34:51d158b409d2 422 {
AzureIoTClient 34:51d158b409d2 423 result = __FAILURE__;
AzureIoTClient 34:51d158b409d2 424 LogError("authentication_start failed (authentication_handle is NULL)");
AzureIoTClient 34:51d158b409d2 425 }
AzureIoTClient 34:51d158b409d2 426 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_026: [If `cbs_handle` is NULL, authentication_start() shall fail and return __FAILURE__ as error code]
AzureIoTClient 34:51d158b409d2 427 else if (cbs_handle == NULL)
AzureIoTClient 34:51d158b409d2 428 {
AzureIoTClient 34:51d158b409d2 429 result = __FAILURE__;
AzureIoTClient 34:51d158b409d2 430 LogError("authentication_start failed (cbs_handle is NULL)");
AzureIoTClient 34:51d158b409d2 431 }
AzureIoTClient 34:51d158b409d2 432 else
AzureIoTClient 34:51d158b409d2 433 {
AzureIoTClient 34:51d158b409d2 434 AUTHENTICATION_INSTANCE* instance = (AUTHENTICATION_INSTANCE*)authentication_handle;
AzureIoTClient 34:51d158b409d2 435
AzureIoTClient 34:51d158b409d2 436 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_027: [If authenticate state has been started already, authentication_start() shall fail and return __FAILURE__ as error code]
AzureIoTClient 34:51d158b409d2 437 if (instance->state != AUTHENTICATION_STATE_STOPPED)
AzureIoTClient 34:51d158b409d2 438 {
AzureIoTClient 34:51d158b409d2 439 result = __FAILURE__;
AzureIoTClient 34:51d158b409d2 440 LogError("authentication_start failed (messenger has already been started; current state: %d)", instance->state);
AzureIoTClient 34:51d158b409d2 441 }
AzureIoTClient 34:51d158b409d2 442 else
AzureIoTClient 34:51d158b409d2 443 {
AzureIoTClient 34:51d158b409d2 444 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_028: [authentication_start() shall save `cbs_handle` on `instance->cbs_handle`]
AzureIoTClient 34:51d158b409d2 445 instance->cbs_handle = cbs_handle;
AzureIoTClient 30:20a85b733111 446
AzureIoTClient 34:51d158b409d2 447 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_029: [If no failures occur, `instance->state` shall be set to AUTHENTICATION_STATE_STARTING and `instance->on_state_changed_callback` invoked]
AzureIoTClient 34:51d158b409d2 448 update_state(instance, AUTHENTICATION_STATE_STARTING);
AzureIoTClient 30:20a85b733111 449
AzureIoTClient 34:51d158b409d2 450 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_030: [If no failures occur, authentication_start() shall return 0]
AzureIoTClient 34:51d158b409d2 451 result = RESULT_OK;
AzureIoTClient 34:51d158b409d2 452 }
AzureIoTClient 34:51d158b409d2 453 }
AzureIoTClient 30:20a85b733111 454
AzureIoTClient 34:51d158b409d2 455 return result;
AzureIoTClient 30:20a85b733111 456 }
AzureIoTClient 30:20a85b733111 457
AzureIoTClient 30:20a85b733111 458 int authentication_stop(AUTHENTICATION_HANDLE authentication_handle)
AzureIoTClient 30:20a85b733111 459 {
AzureIoTClient 34:51d158b409d2 460 int result;
AzureIoTClient 34:51d158b409d2 461
AzureIoTClient 34:51d158b409d2 462 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_031: [If `authentication_handle` is NULL, authentication_stop() shall fail and return __FAILURE__]
AzureIoTClient 34:51d158b409d2 463 if (authentication_handle == NULL)
AzureIoTClient 34:51d158b409d2 464 {
AzureIoTClient 34:51d158b409d2 465 result = __FAILURE__;
AzureIoTClient 34:51d158b409d2 466 LogError("authentication_stop failed (authentication_handle is NULL)");
AzureIoTClient 34:51d158b409d2 467 }
AzureIoTClient 34:51d158b409d2 468 else
AzureIoTClient 34:51d158b409d2 469 {
AzureIoTClient 34:51d158b409d2 470 AUTHENTICATION_INSTANCE* instance = (AUTHENTICATION_INSTANCE*)authentication_handle;
AzureIoTClient 30:20a85b733111 471
AzureIoTClient 34:51d158b409d2 472 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_032: [If `instance->state` is AUTHENTICATION_STATE_STOPPED, authentication_stop() shall fail and return __FAILURE__]
AzureIoTClient 34:51d158b409d2 473 if (instance->state == AUTHENTICATION_STATE_STOPPED)
AzureIoTClient 34:51d158b409d2 474 {
AzureIoTClient 34:51d158b409d2 475 result = __FAILURE__;
AzureIoTClient 34:51d158b409d2 476 LogError("authentication_stop failed (messenger is already stopped)");
AzureIoTClient 34:51d158b409d2 477 }
AzureIoTClient 34:51d158b409d2 478 else
AzureIoTClient 34:51d158b409d2 479 {
AzureIoTClient 34:51d158b409d2 480 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_033: [`instance->cbs_handle` shall be set to NULL]
AzureIoTClient 34:51d158b409d2 481 instance->cbs_handle = NULL;
AzureIoTClient 30:20a85b733111 482
AzureIoTClient 34:51d158b409d2 483 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_034: [`instance->state` shall be set to AUTHENTICATION_STATE_STOPPED and `instance->on_state_changed_callback` invoked]
AzureIoTClient 34:51d158b409d2 484 update_state(instance, AUTHENTICATION_STATE_STOPPED);
AzureIoTClient 30:20a85b733111 485
AzureIoTClient 34:51d158b409d2 486 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_035: [authentication_stop() shall return success code 0]
AzureIoTClient 34:51d158b409d2 487 result = RESULT_OK;
AzureIoTClient 34:51d158b409d2 488 }
AzureIoTClient 34:51d158b409d2 489 }
AzureIoTClient 30:20a85b733111 490
AzureIoTClient 34:51d158b409d2 491 return result;
AzureIoTClient 30:20a85b733111 492 }
AzureIoTClient 30:20a85b733111 493
AzureIoTClient 30:20a85b733111 494 void authentication_destroy(AUTHENTICATION_HANDLE authentication_handle)
AzureIoTClient 30:20a85b733111 495 {
AzureIoTClient 34:51d158b409d2 496 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_106: [If authentication_handle is NULL, authentication_destroy() shall return]
AzureIoTClient 34:51d158b409d2 497 if (authentication_handle == NULL)
AzureIoTClient 34:51d158b409d2 498 {
AzureIoTClient 34:51d158b409d2 499 LogError("authentication_destroy failed (authentication_handle is NULL)");
AzureIoTClient 34:51d158b409d2 500 }
AzureIoTClient 34:51d158b409d2 501 else
AzureIoTClient 34:51d158b409d2 502 {
AzureIoTClient 34:51d158b409d2 503 AUTHENTICATION_INSTANCE* instance = (AUTHENTICATION_INSTANCE*)authentication_handle;
AzureIoTClient 30:20a85b733111 504
AzureIoTClient 34:51d158b409d2 505 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_107: [If `instance->state` is AUTHENTICATION_STATE_STARTING or AUTHENTICATION_STATE_STARTED, authentication_stop() shall be invoked and its result ignored]
AzureIoTClient 34:51d158b409d2 506 if (instance->state != AUTHENTICATION_STATE_STOPPED)
AzureIoTClient 34:51d158b409d2 507 {
AzureIoTClient 34:51d158b409d2 508 (void)authentication_stop(authentication_handle);
AzureIoTClient 34:51d158b409d2 509 }
AzureIoTClient 34:51d158b409d2 510 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_108: [authentication_destroy() shall destroy all resouces used by this module]
AzureIoTClient 34:51d158b409d2 511 if (instance->iothub_host_fqdn != NULL)
AzureIoTClient 34:51d158b409d2 512 STRING_delete(instance->iothub_host_fqdn);
AzureIoTClient 34:51d158b409d2 513
AzureIoTClient 34:51d158b409d2 514 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_108: [authentication_destroy() shall destroy all resouces used by this module]
AzureIoTClient 34:51d158b409d2 515 free(instance);
AzureIoTClient 34:51d158b409d2 516 }
AzureIoTClient 30:20a85b733111 517 }
AzureIoTClient 30:20a85b733111 518
AzureIoTClient 30:20a85b733111 519 AUTHENTICATION_HANDLE authentication_create(const AUTHENTICATION_CONFIG* config)
AzureIoTClient 30:20a85b733111 520 {
AzureIoTClient 34:51d158b409d2 521 AUTHENTICATION_HANDLE result;
AzureIoTClient 30:20a85b733111 522
AzureIoTClient 34:51d158b409d2 523 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_001: [If parameter `config` is NULL, authentication_create() shall fail and return NULL.]
AzureIoTClient 34:51d158b409d2 524 if (config == NULL)
AzureIoTClient 34:51d158b409d2 525 {
AzureIoTClient 34:51d158b409d2 526 result = NULL;
AzureIoTClient 34:51d158b409d2 527 LogError("authentication_create failed (config is NULL)");
AzureIoTClient 34:51d158b409d2 528 }
AzureIoTClient 34:51d158b409d2 529 else if (config->authorization_module == NULL)
AzureIoTClient 34:51d158b409d2 530 {
AzureIoTClient 34:51d158b409d2 531 result = NULL;
AzureIoTClient 34:51d158b409d2 532 LogError("authentication_create failed (config->authorization_module is NULL)");
AzureIoTClient 34:51d158b409d2 533 }
AzureIoTClient 34:51d158b409d2 534 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_004: [If `config->iothub_host_fqdn` is NULL, authentication_create() shall fail and return NULL.]
AzureIoTClient 34:51d158b409d2 535 else if (config->iothub_host_fqdn == NULL)
AzureIoTClient 34:51d158b409d2 536 {
AzureIoTClient 34:51d158b409d2 537 result = NULL;
AzureIoTClient 34:51d158b409d2 538 LogError("authentication_create failed (config->iothub_host_fqdn is NULL)");
AzureIoTClient 34:51d158b409d2 539 }
AzureIoTClient 34:51d158b409d2 540 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_005: [If `config->on_state_changed_callback` is NULL, authentication_create() shall fail and return NULL]
AzureIoTClient 34:51d158b409d2 541 else if (config->on_state_changed_callback == NULL)
AzureIoTClient 34:51d158b409d2 542 {
AzureIoTClient 34:51d158b409d2 543 result = NULL;
AzureIoTClient 34:51d158b409d2 544 LogError("authentication_create failed (config->on_state_changed_callback is NULL)");
AzureIoTClient 34:51d158b409d2 545 }
AzureIoTClient 34:51d158b409d2 546 else
AzureIoTClient 34:51d158b409d2 547 {
AzureIoTClient 34:51d158b409d2 548 AUTHENTICATION_INSTANCE* instance;
AzureIoTClient 30:20a85b733111 549
AzureIoTClient 34:51d158b409d2 550 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_006: [authentication_create() shall allocate memory for a new authenticate state structure AUTHENTICATION_INSTANCE.]
AzureIoTClient 34:51d158b409d2 551 if ((instance = (AUTHENTICATION_INSTANCE*)malloc(sizeof(AUTHENTICATION_INSTANCE))) == NULL)
AzureIoTClient 34:51d158b409d2 552 {
AzureIoTClient 34:51d158b409d2 553 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_007: [If malloc() fails, authentication_create() shall fail and return NULL.]
AzureIoTClient 34:51d158b409d2 554 result = NULL;
AzureIoTClient 34:51d158b409d2 555 LogError("authentication_create failed (malloc failed)");
AzureIoTClient 34:51d158b409d2 556 }
AzureIoTClient 34:51d158b409d2 557 else
AzureIoTClient 34:51d158b409d2 558 {
AzureIoTClient 34:51d158b409d2 559 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_123: [authentication_create() shall initialize all fields of `instance` with 0 using memset().]
AzureIoTClient 34:51d158b409d2 560 memset(instance, 0, sizeof(AUTHENTICATION_INSTANCE));
AzureIoTClient 30:20a85b733111 561
AzureIoTClient 34:51d158b409d2 562 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_008: [authentication_create() shall save the device_id into the `instance->device_id`]
AzureIoTClient 34:51d158b409d2 563 if ((instance->device_id = IoTHubClient_Auth_Get_DeviceId(config->authorization_module) ) == NULL)
AzureIoTClient 34:51d158b409d2 564 {
AzureIoTClient 34:51d158b409d2 565 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_009: [If STRING_construct() fails, authentication_create() shall fail and return NULL]
AzureIoTClient 34:51d158b409d2 566 result = NULL;
AzureIoTClient 34:51d158b409d2 567 LogError("authentication_create failed (config->device_id could not be copied; STRING_construct failed)");
AzureIoTClient 34:51d158b409d2 568 }
AzureIoTClient 34:51d158b409d2 569 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_016: [If provided, authentication_create() shall save a copy of `config->iothub_host_fqdn` into `instance->iothub_host_fqdn`]
AzureIoTClient 34:51d158b409d2 570 else if ((instance->iothub_host_fqdn = STRING_construct(config->iothub_host_fqdn)) == NULL)
AzureIoTClient 34:51d158b409d2 571 {
AzureIoTClient 34:51d158b409d2 572 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_017: [If STRING_clone() fails to copy `config->iothub_host_fqdn`, authentication_create() shall fail and return NULL]
AzureIoTClient 34:51d158b409d2 573 result = NULL;
AzureIoTClient 34:51d158b409d2 574 LogError("authentication_create failed (config->iothub_host_fqdn could not be copied; STRING_construct failed)");
AzureIoTClient 34:51d158b409d2 575 }
AzureIoTClient 34:51d158b409d2 576 else
AzureIoTClient 34:51d158b409d2 577 {
AzureIoTClient 34:51d158b409d2 578 instance->state = AUTHENTICATION_STATE_STOPPED;
AzureIoTClient 34:51d158b409d2 579
AzureIoTClient 34:51d158b409d2 580 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_018: [authentication_create() shall save `config->on_state_changed_callback` and `config->on_state_changed_callback_context` into `instance->on_state_changed_callback` and `instance->on_state_changed_callback_context`.]
AzureIoTClient 34:51d158b409d2 581 instance->on_state_changed_callback = config->on_state_changed_callback;
AzureIoTClient 34:51d158b409d2 582 instance->on_state_changed_callback_context = config->on_state_changed_callback_context;
AzureIoTClient 30:20a85b733111 583
AzureIoTClient 34:51d158b409d2 584 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_019: [authentication_create() shall save `config->on_error_callback` and `config->on_error_callback_context` into `instance->on_error_callback` and `instance->on_error_callback_context`.]
AzureIoTClient 34:51d158b409d2 585 instance->on_error_callback = config->on_error_callback;
AzureIoTClient 34:51d158b409d2 586 instance->on_error_callback_context = config->on_error_callback_context;
AzureIoTClient 30:20a85b733111 587
AzureIoTClient 34:51d158b409d2 588 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_021: [authentication_create() shall set `instance->cbs_request_timeout_secs` with the default value of UINT32_MAX]
AzureIoTClient 34:51d158b409d2 589 instance->cbs_request_timeout_secs = DEFAULT_CBS_REQUEST_TIMEOUT_SECS;
AzureIoTClient 34:51d158b409d2 590 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_022: [authentication_create() shall set `instance->sas_token_lifetime_secs` with the default value of one hour]
AzureIoTClient 34:51d158b409d2 591 instance->sas_token_lifetime_secs = DEFAULT_SAS_TOKEN_LIFETIME_SECS;
AzureIoTClient 34:51d158b409d2 592 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_023: [authentication_create() shall set `instance->sas_token_refresh_time_secs` with the default value of 30 minutes]
AzureIoTClient 34:51d158b409d2 593 instance->sas_token_refresh_time_secs = DEFAULT_SAS_TOKEN_REFRESH_TIME_SECS;
AzureIoTClient 30:20a85b733111 594
AzureIoTClient 34:51d158b409d2 595 instance->authorization_module = config->authorization_module;
AzureIoTClient 30:20a85b733111 596
AzureIoTClient 34:51d158b409d2 597 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_024: [If no failure occurs, authentication_create() shall return a reference to the AUTHENTICATION_INSTANCE handle]
AzureIoTClient 34:51d158b409d2 598 result = (AUTHENTICATION_HANDLE)instance;
AzureIoTClient 34:51d158b409d2 599 }
AzureIoTClient 30:20a85b733111 600
AzureIoTClient 34:51d158b409d2 601 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_020: [If any failure occurs, authentication_create() shall free any memory it allocated previously]
AzureIoTClient 34:51d158b409d2 602 if (result == NULL)
AzureIoTClient 34:51d158b409d2 603 {
AzureIoTClient 34:51d158b409d2 604 authentication_destroy((AUTHENTICATION_HANDLE)instance);
AzureIoTClient 34:51d158b409d2 605 }
AzureIoTClient 34:51d158b409d2 606 }
AzureIoTClient 34:51d158b409d2 607 }
AzureIoTClient 34:51d158b409d2 608
AzureIoTClient 30:20a85b733111 609 return result;
AzureIoTClient 30:20a85b733111 610 }
AzureIoTClient 30:20a85b733111 611
AzureIoTClient 30:20a85b733111 612 void authentication_do_work(AUTHENTICATION_HANDLE authentication_handle)
AzureIoTClient 30:20a85b733111 613 {
AzureIoTClient 34:51d158b409d2 614 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_036: [If authentication_handle is NULL, authentication_do_work() shall fail and return]
AzureIoTClient 34:51d158b409d2 615 if (authentication_handle == NULL)
AzureIoTClient 34:51d158b409d2 616 {
AzureIoTClient 34:51d158b409d2 617 LogError("authentication_do_work failed (authentication_handle is NULL)");
AzureIoTClient 34:51d158b409d2 618 }
AzureIoTClient 34:51d158b409d2 619 else
AzureIoTClient 34:51d158b409d2 620 {
AzureIoTClient 34:51d158b409d2 621 AUTHENTICATION_INSTANCE* instance = (AUTHENTICATION_INSTANCE*)authentication_handle;
AzureIoTClient 34:51d158b409d2 622
AzureIoTClient 34:51d158b409d2 623 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_038: [If `instance->is_cbs_put_token_in_progress` is TRUE, authentication_do_work() shall only verify the authentication timeout]
AzureIoTClient 34:51d158b409d2 624 if (instance->is_cbs_put_token_in_progress)
AzureIoTClient 34:51d158b409d2 625 {
AzureIoTClient 34:51d158b409d2 626 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_084: [If no timeout has occurred, authentication_do_work() shall return]
AzureIoTClient 30:20a85b733111 627
AzureIoTClient 34:51d158b409d2 628 bool is_timed_out;
AzureIoTClient 34:51d158b409d2 629 if (verify_cbs_put_token_timeout(instance, &is_timed_out) == RESULT_OK && is_timed_out)
AzureIoTClient 34:51d158b409d2 630 {
AzureIoTClient 34:51d158b409d2 631 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_085: [`instance->is_cbs_put_token_in_progress` shall be set to FALSE]
AzureIoTClient 34:51d158b409d2 632 instance->is_cbs_put_token_in_progress = false;
AzureIoTClient 34:51d158b409d2 633
AzureIoTClient 34:51d158b409d2 634 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_086: [`instance->state` shall be updated to AUTHENTICATION_STATE_ERROR and `instance->on_state_changed_callback` invoked]
AzureIoTClient 34:51d158b409d2 635 update_state(instance, AUTHENTICATION_STATE_ERROR);
AzureIoTClient 30:20a85b733111 636
AzureIoTClient 34:51d158b409d2 637 if (instance->is_sas_token_refresh_in_progress)
AzureIoTClient 34:51d158b409d2 638 {
AzureIoTClient 34:51d158b409d2 639 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_087: [If `instance->is_sas_token_refresh_in_progress` is TRUE, `instance->on_error_callback` shall be invoked with AUTHENTICATION_ERROR_SAS_REFRESH_TIMEOUT]
AzureIoTClient 34:51d158b409d2 640 notify_error(instance, AUTHENTICATION_ERROR_SAS_REFRESH_TIMEOUT);
AzureIoTClient 34:51d158b409d2 641 }
AzureIoTClient 34:51d158b409d2 642 else
AzureIoTClient 34:51d158b409d2 643 {
AzureIoTClient 34:51d158b409d2 644 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_088: [If `instance->is_sas_token_refresh_in_progress` is FALSE, `instance->on_error_callback` shall be invoked with AUTHENTICATION_ERROR_AUTH_TIMEOUT]
AzureIoTClient 34:51d158b409d2 645 notify_error(instance, AUTHENTICATION_ERROR_AUTH_TIMEOUT);
AzureIoTClient 34:51d158b409d2 646 }
AzureIoTClient 30:20a85b733111 647
AzureIoTClient 34:51d158b409d2 648 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_089: [`instance->is_sas_token_refresh_in_progress` shall be set to FALSE]
AzureIoTClient 34:51d158b409d2 649 instance->is_sas_token_refresh_in_progress = false;
AzureIoTClient 34:51d158b409d2 650 }
AzureIoTClient 34:51d158b409d2 651 }
AzureIoTClient 34:51d158b409d2 652 else if (instance->state == AUTHENTICATION_STATE_STARTED)
AzureIoTClient 34:51d158b409d2 653 {
AzureIoTClient 34:51d158b409d2 654 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_040: [If `instance->state` is AUTHENTICATION_STATE_STARTED and user-provided SAS token was used, authentication_do_work() shall return]
AzureIoTClient 34:51d158b409d2 655 if (IoTHubClient_Auth_Get_Credential_Type(instance->authorization_module) == IOTHUB_CREDENTIAL_TYPE_DEVICE_KEY)
AzureIoTClient 34:51d158b409d2 656 {
AzureIoTClient 34:51d158b409d2 657 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_039: [If `instance->state` is AUTHENTICATION_STATE_STARTED and device keys were used, authentication_do_work() shall only verify the SAS token refresh time]
AzureIoTClient 34:51d158b409d2 658 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_065: [The SAS token shall be refreshed if the current time minus `instance->current_sas_token_put_time` equals or exceeds `instance->sas_token_refresh_time_secs`]
AzureIoTClient 34:51d158b409d2 659 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_066: [If SAS token does not need to be refreshed, authentication_do_work() shall return]
AzureIoTClient 34:51d158b409d2 660 bool is_timed_out;
AzureIoTClient 34:51d158b409d2 661 if (verify_sas_token_refresh_timeout(instance, &is_timed_out) == RESULT_OK && is_timed_out)
AzureIoTClient 34:51d158b409d2 662 {
AzureIoTClient 34:51d158b409d2 663 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_119: [authentication_do_work() shall set `instance->is_sas_token_refresh_in_progress` to TRUE]
AzureIoTClient 34:51d158b409d2 664 instance->is_sas_token_refresh_in_progress = true;
AzureIoTClient 30:20a85b733111 665
AzureIoTClient 34:51d158b409d2 666 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_067: [authentication_do_work() shall create a SAS token using `instance->device_primary_key`, unless it has failed previously]
AzureIoTClient 34:51d158b409d2 667 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_069: [If using `instance->device_primary_key` has failed previously, a SAS token shall be created using `instance->device_secondary_key`]
AzureIoTClient 34:51d158b409d2 668 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_068: [If using `instance->device_primary_key` has failed previously and `instance->device_secondary_key` is not provided, authentication_do_work() shall fail and return]
AzureIoTClient 34:51d158b409d2 669 if (create_and_put_SAS_token_to_cbs(instance) != RESULT_OK)
AzureIoTClient 34:51d158b409d2 670 {
AzureIoTClient 34:51d158b409d2 671 LogError("Failed refreshing SAS token '%'", instance->device_id);
AzureIoTClient 34:51d158b409d2 672 }
AzureIoTClient 30:20a85b733111 673
AzureIoTClient 34:51d158b409d2 674 if (!instance->is_cbs_put_token_in_progress)
AzureIoTClient 34:51d158b409d2 675 {
AzureIoTClient 34:51d158b409d2 676 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_120: [If cbs_put_token() fails, `instance->is_sas_token_refresh_in_progress` shall be set to FALSE]
AzureIoTClient 34:51d158b409d2 677 instance->is_sas_token_refresh_in_progress = false;
AzureIoTClient 30:20a85b733111 678
AzureIoTClient 34:51d158b409d2 679 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_079: [If cbs_put_token() fails, `instance->state` shall be updated to AUTHENTICATION_STATE_ERROR and `instance->on_state_changed_callback` invoked]
AzureIoTClient 34:51d158b409d2 680 update_state(instance, AUTHENTICATION_STATE_ERROR);
AzureIoTClient 30:20a85b733111 681
AzureIoTClient 34:51d158b409d2 682 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_080: [If cbs_put_token() fails, `instance->on_error_callback` shall be invoked with AUTHENTICATION_ERROR_SAS_REFRESH_FAILED]
AzureIoTClient 34:51d158b409d2 683 notify_error(instance, AUTHENTICATION_ERROR_SAS_REFRESH_FAILED);
AzureIoTClient 34:51d158b409d2 684 }
AzureIoTClient 34:51d158b409d2 685 }
AzureIoTClient 34:51d158b409d2 686 }
AzureIoTClient 34:51d158b409d2 687 }
AzureIoTClient 34:51d158b409d2 688 else if (instance->state == AUTHENTICATION_STATE_STARTING)
AzureIoTClient 34:51d158b409d2 689 {
AzureIoTClient 34:51d158b409d2 690 if (create_and_put_SAS_token_to_cbs(instance) != RESULT_OK)
AzureIoTClient 34:51d158b409d2 691 {
AzureIoTClient 34:51d158b409d2 692 LogError("Failed authenticating device '%s' using device keys", instance->device_id);
AzureIoTClient 34:51d158b409d2 693 }
AzureIoTClient 30:20a85b733111 694
AzureIoTClient 34:51d158b409d2 695 if (!instance->is_cbs_put_token_in_progress)
AzureIoTClient 34:51d158b409d2 696 {
AzureIoTClient 34:51d158b409d2 697 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_061: [If cbs_put_token() fails, `instance->state` shall be updated to AUTHENTICATION_STATE_ERROR and `instance->on_state_changed_callback` invoked]
AzureIoTClient 34:51d158b409d2 698 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_121: [If cbs_put_token() fails, `instance->state` shall be updated to AUTHENTICATION_STATE_ERROR and `instance->on_state_changed_callback` invoked]
AzureIoTClient 34:51d158b409d2 699 update_state(instance, AUTHENTICATION_STATE_ERROR);
AzureIoTClient 30:20a85b733111 700
AzureIoTClient 34:51d158b409d2 701 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_062: [If cbs_put_token() fails, `instance->on_error_callback` shall be invoked with AUTHENTICATION_ERROR_AUTH_FAILED]
AzureIoTClient 34:51d158b409d2 702 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_122: [If cbs_put_token() fails, `instance->on_error_callback` shall be invoked with AUTHENTICATION_ERROR_AUTH_FAILED]
AzureIoTClient 34:51d158b409d2 703 notify_error(instance, AUTHENTICATION_ERROR_AUTH_FAILED);
AzureIoTClient 34:51d158b409d2 704 }
AzureIoTClient 34:51d158b409d2 705 }
AzureIoTClient 34:51d158b409d2 706 else
AzureIoTClient 34:51d158b409d2 707 {
AzureIoTClient 34:51d158b409d2 708 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_037: [If `instance->state` is not AUTHENTICATION_STATE_STARTING or AUTHENTICATION_STATE_STARTED, authentication_do_work() shall fail and return]
AzureIoTClient 34:51d158b409d2 709 // Nothing to be done.
AzureIoTClient 34:51d158b409d2 710 }
AzureIoTClient 34:51d158b409d2 711 }
AzureIoTClient 30:20a85b733111 712 }
AzureIoTClient 30:20a85b733111 713
AzureIoTClient 30:20a85b733111 714 int authentication_set_option(AUTHENTICATION_HANDLE authentication_handle, const char* name, void* value)
AzureIoTClient 30:20a85b733111 715 {
AzureIoTClient 34:51d158b409d2 716 int result;
AzureIoTClient 30:20a85b733111 717
AzureIoTClient 34:51d158b409d2 718 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_097: [If `authentication_handle` or `name` or `value` is NULL, authentication_set_option shall fail and return a non-zero value]
AzureIoTClient 34:51d158b409d2 719 if (authentication_handle == NULL || name == NULL || value == NULL)
AzureIoTClient 34:51d158b409d2 720 {
AzureIoTClient 34:51d158b409d2 721 LogError("authentication_set_option failed (one of the followin are NULL: authentication_handle=%p, name=%p, value=%p)",
AzureIoTClient 34:51d158b409d2 722 authentication_handle, name, value);
AzureIoTClient 34:51d158b409d2 723 result = __FAILURE__;
AzureIoTClient 34:51d158b409d2 724 }
AzureIoTClient 34:51d158b409d2 725 else
AzureIoTClient 34:51d158b409d2 726 {
AzureIoTClient 34:51d158b409d2 727 AUTHENTICATION_INSTANCE* instance = (AUTHENTICATION_INSTANCE*)authentication_handle;
AzureIoTClient 30:20a85b733111 728
AzureIoTClient 34:51d158b409d2 729 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_098: [If name matches AUTHENTICATION_OPTION_CBS_REQUEST_TIMEOUT_SECS, `value` shall be saved on `instance->cbs_request_timeout_secs`]
AzureIoTClient 34:51d158b409d2 730 if (strcmp(AUTHENTICATION_OPTION_CBS_REQUEST_TIMEOUT_SECS, name) == 0)
AzureIoTClient 34:51d158b409d2 731 {
AzureIoTClient 34:51d158b409d2 732 instance->cbs_request_timeout_secs = *((size_t*)value);
AzureIoTClient 34:51d158b409d2 733 result = RESULT_OK;
AzureIoTClient 34:51d158b409d2 734 }
AzureIoTClient 34:51d158b409d2 735 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_124: [If name matches AUTHENTICATION_OPTION_SAS_TOKEN_REFRESH_TIME_SECS, `value` shall be saved on `instance->sas_token_refresh_time_secs`]
AzureIoTClient 34:51d158b409d2 736 else if (strcmp(AUTHENTICATION_OPTION_SAS_TOKEN_REFRESH_TIME_SECS, name) == 0)
AzureIoTClient 34:51d158b409d2 737 {
AzureIoTClient 34:51d158b409d2 738 instance->sas_token_refresh_time_secs = *((size_t*)value);
AzureIoTClient 34:51d158b409d2 739 result = RESULT_OK;
AzureIoTClient 34:51d158b409d2 740 }
AzureIoTClient 34:51d158b409d2 741 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_125: [If name matches AUTHENTICATION_OPTION_SAS_TOKEN_LIFETIME_SECS, `value` shall be saved on `instance->sas_token_lifetime_secs`]
AzureIoTClient 34:51d158b409d2 742 else if (strcmp(AUTHENTICATION_OPTION_SAS_TOKEN_LIFETIME_SECS, name) == 0)
AzureIoTClient 34:51d158b409d2 743 {
AzureIoTClient 34:51d158b409d2 744 instance->sas_token_lifetime_secs = *((size_t*)value);
AzureIoTClient 34:51d158b409d2 745 result = RESULT_OK;
AzureIoTClient 34:51d158b409d2 746 }
AzureIoTClient 34:51d158b409d2 747 else if (strcmp(AUTHENTICATION_OPTION_SAVED_OPTIONS, name) == 0)
AzureIoTClient 34:51d158b409d2 748 {
AzureIoTClient 34:51d158b409d2 749 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_098: [If name matches AUTHENTICATION_OPTION_SAVED_OPTIONS, `value` shall be applied using OptionHandler_FeedOptions]
AzureIoTClient 34:51d158b409d2 750 if (OptionHandler_FeedOptions((OPTIONHANDLER_HANDLE)value, authentication_handle) != OPTIONHANDLER_OK)
AzureIoTClient 34:51d158b409d2 751 {
AzureIoTClient 34:51d158b409d2 752 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_126: [If OptionHandler_FeedOptions fails, authentication_set_option shall fail and return a non-zero value]
AzureIoTClient 34:51d158b409d2 753 LogError("authentication_set_option failed (OptionHandler_FeedOptions failed)");
AzureIoTClient 34:51d158b409d2 754 result = __FAILURE__;
AzureIoTClient 34:51d158b409d2 755 }
AzureIoTClient 34:51d158b409d2 756 else
AzureIoTClient 34:51d158b409d2 757 {
AzureIoTClient 34:51d158b409d2 758 result = RESULT_OK;
AzureIoTClient 34:51d158b409d2 759 }
AzureIoTClient 34:51d158b409d2 760 }
AzureIoTClient 34:51d158b409d2 761 else
AzureIoTClient 34:51d158b409d2 762 {
AzureIoTClient 34:51d158b409d2 763 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_128: [If name does not match any supported option, authentication_set_option shall fail and return a non-zero value]
AzureIoTClient 34:51d158b409d2 764 LogError("authentication_set_option failed (option with name '%s' is not suppported)", name);
AzureIoTClient 34:51d158b409d2 765 result = __FAILURE__;
AzureIoTClient 34:51d158b409d2 766 }
AzureIoTClient 34:51d158b409d2 767 }
AzureIoTClient 30:20a85b733111 768
AzureIoTClient 34:51d158b409d2 769 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_099: [If no errors occur, authentication_set_option shall return 0]
AzureIoTClient 34:51d158b409d2 770 return result;
AzureIoTClient 30:20a85b733111 771 }
AzureIoTClient 30:20a85b733111 772
AzureIoTClient 30:20a85b733111 773 OPTIONHANDLER_HANDLE authentication_retrieve_options(AUTHENTICATION_HANDLE authentication_handle)
AzureIoTClient 30:20a85b733111 774 {
AzureIoTClient 34:51d158b409d2 775 OPTIONHANDLER_HANDLE result;
AzureIoTClient 30:20a85b733111 776
AzureIoTClient 34:51d158b409d2 777 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_100: [If `authentication_handle` is NULL, authentication_retrieve_options shall fail and return NULL]
AzureIoTClient 34:51d158b409d2 778 if (authentication_handle == NULL)
AzureIoTClient 34:51d158b409d2 779 {
AzureIoTClient 34:51d158b409d2 780 LogError("Failed to retrieve options from authentication instance (authentication_handle is NULL)");
AzureIoTClient 34:51d158b409d2 781 result = NULL;
AzureIoTClient 34:51d158b409d2 782 }
AzureIoTClient 34:51d158b409d2 783 else
AzureIoTClient 34:51d158b409d2 784 {
AzureIoTClient 34:51d158b409d2 785 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_101: [An OPTIONHANDLER_HANDLE instance shall be created using OptionHandler_Create]
AzureIoTClient 34:51d158b409d2 786 OPTIONHANDLER_HANDLE options = OptionHandler_Create(authentication_clone_option, authentication_destroy_option, (pfSetOption)authentication_set_option);
AzureIoTClient 30:20a85b733111 787
AzureIoTClient 34:51d158b409d2 788 if (options == NULL)
AzureIoTClient 34:51d158b409d2 789 {
AzureIoTClient 34:51d158b409d2 790 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_102: [If an OPTIONHANDLER_HANDLE instance fails to be created, authentication_retrieve_options shall fail and return NULL]
AzureIoTClient 34:51d158b409d2 791 LogError("Failed to retrieve options from authentication instance (OptionHandler_Create failed)");
AzureIoTClient 34:51d158b409d2 792 result = NULL;
AzureIoTClient 34:51d158b409d2 793 }
AzureIoTClient 34:51d158b409d2 794 else
AzureIoTClient 34:51d158b409d2 795 {
AzureIoTClient 34:51d158b409d2 796 AUTHENTICATION_INSTANCE* instance = (AUTHENTICATION_INSTANCE*)authentication_handle;
AzureIoTClient 30:20a85b733111 797
AzureIoTClient 34:51d158b409d2 798 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_103: [Each option of `instance` shall be added to the OPTIONHANDLER_HANDLE instance using OptionHandler_AddOption]
AzureIoTClient 34:51d158b409d2 799 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_104: [If OptionHandler_AddOption fails, authentication_retrieve_options shall fail and return NULL]
AzureIoTClient 34:51d158b409d2 800 if (OptionHandler_AddOption(options, AUTHENTICATION_OPTION_CBS_REQUEST_TIMEOUT_SECS, (void*)&instance->cbs_request_timeout_secs) != OPTIONHANDLER_OK)
AzureIoTClient 34:51d158b409d2 801 {
AzureIoTClient 34:51d158b409d2 802 LogError("Failed to retrieve options from authentication instance (OptionHandler_Create failed for option '%s')", AUTHENTICATION_OPTION_CBS_REQUEST_TIMEOUT_SECS);
AzureIoTClient 34:51d158b409d2 803 result = NULL;
AzureIoTClient 34:51d158b409d2 804 }
AzureIoTClient 34:51d158b409d2 805 else if (OptionHandler_AddOption(options, AUTHENTICATION_OPTION_SAS_TOKEN_REFRESH_TIME_SECS, (void*)&instance->sas_token_refresh_time_secs) != OPTIONHANDLER_OK)
AzureIoTClient 34:51d158b409d2 806 {
AzureIoTClient 34:51d158b409d2 807 LogError("Failed to retrieve options from authentication instance (OptionHandler_Create failed for option '%s')", AUTHENTICATION_OPTION_SAS_TOKEN_REFRESH_TIME_SECS);
AzureIoTClient 34:51d158b409d2 808 result = NULL;
AzureIoTClient 34:51d158b409d2 809 }
AzureIoTClient 34:51d158b409d2 810 else if (OptionHandler_AddOption(options, AUTHENTICATION_OPTION_SAS_TOKEN_LIFETIME_SECS, (void*)&instance->sas_token_lifetime_secs) != OPTIONHANDLER_OK)
AzureIoTClient 34:51d158b409d2 811 {
AzureIoTClient 34:51d158b409d2 812 LogError("Failed to retrieve options from authentication instance (OptionHandler_Create failed for option '%s')", AUTHENTICATION_OPTION_SAS_TOKEN_LIFETIME_SECS);
AzureIoTClient 34:51d158b409d2 813 result = NULL;
AzureIoTClient 34:51d158b409d2 814 }
AzureIoTClient 34:51d158b409d2 815 else
AzureIoTClient 34:51d158b409d2 816 {
AzureIoTClient 34:51d158b409d2 817 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_127: [If no failures occur, authentication_retrieve_options shall return the OPTIONHANDLER_HANDLE instance]
AzureIoTClient 34:51d158b409d2 818 result = options;
AzureIoTClient 34:51d158b409d2 819 }
AzureIoTClient 30:20a85b733111 820
AzureIoTClient 34:51d158b409d2 821 if (result == NULL)
AzureIoTClient 34:51d158b409d2 822 {
AzureIoTClient 34:51d158b409d2 823 // Codes_SRS_IOTHUBTRANSPORT_AMQP_AUTH_09_105: [If authentication_retrieve_options fails, any allocated memory shall be freed]
AzureIoTClient 34:51d158b409d2 824 OptionHandler_Destroy(options);
AzureIoTClient 34:51d158b409d2 825 }
AzureIoTClient 34:51d158b409d2 826 }
AzureIoTClient 34:51d158b409d2 827 }
AzureIoTClient 34:51d158b409d2 828 return result;
AzureIoTClient 30:20a85b733111 829 }