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 "azure_c_shared_utility/optimize_size.h"
XinZhangMS 0:f7f1f0d76dd6 6 #include "azure_c_shared_utility/gballoc.h"
XinZhangMS 0:f7f1f0d76dd6 7 #include "azure_c_shared_utility/agenttime.h"
XinZhangMS 0:f7f1f0d76dd6 8 #include "azure_c_shared_utility/xlogging.h"
XinZhangMS 0:f7f1f0d76dd6 9 #include "azure_c_shared_utility/strings.h"
XinZhangMS 0:f7f1f0d76dd6 10 #include "internal/iothubtransport_amqp_cbs_auth.h"
XinZhangMS 0:f7f1f0d76dd6 11 #include "internal/iothubtransport_amqp_device.h"
XinZhangMS 0:f7f1f0d76dd6 12 #include "internal/iothubtransport_amqp_telemetry_messenger.h"
XinZhangMS 0:f7f1f0d76dd6 13 #include "internal/iothubtransport_amqp_twin_messenger.h"
XinZhangMS 0:f7f1f0d76dd6 14
XinZhangMS 0:f7f1f0d76dd6 15 DEFINE_ENUM_STRINGS(DEVICE_STATE, DEVICE_STATE_VALUES);
XinZhangMS 0:f7f1f0d76dd6 16 DEFINE_ENUM_STRINGS(DEVICE_AUTH_MODE, DEVICE_AUTH_MODE_VALUES);
XinZhangMS 0:f7f1f0d76dd6 17 DEFINE_ENUM_STRINGS(DEVICE_SEND_STATUS, DEVICE_SEND_STATUS_VALUES);
XinZhangMS 0:f7f1f0d76dd6 18 DEFINE_ENUM_STRINGS(D2C_EVENT_SEND_RESULT, D2C_EVENT_SEND_RESULT_VALUES);
XinZhangMS 0:f7f1f0d76dd6 19 DEFINE_ENUM_STRINGS(DEVICE_MESSAGE_DISPOSITION_RESULT, DEVICE_MESSAGE_DISPOSITION_RESULT_VALUES);
XinZhangMS 0:f7f1f0d76dd6 20 DEFINE_ENUM_STRINGS(DEVICE_TWIN_UPDATE_RESULT, DEVICE_TWIN_UPDATE_RESULT_STRINGS);
XinZhangMS 0:f7f1f0d76dd6 21 DEFINE_ENUM_STRINGS(DEVICE_TWIN_UPDATE_TYPE, DEVICE_TWIN_UPDATE_TYPE_STRINGS)
XinZhangMS 0:f7f1f0d76dd6 22
XinZhangMS 0:f7f1f0d76dd6 23 #define RESULT_OK 0
XinZhangMS 0:f7f1f0d76dd6 24 #define INDEFINITE_TIME ((time_t)-1)
XinZhangMS 0:f7f1f0d76dd6 25 #define DEFAULT_AUTH_STATE_CHANGED_TIMEOUT_SECS 60
XinZhangMS 0:f7f1f0d76dd6 26 #define DEFAULT_MSGR_STATE_CHANGED_TIMEOUT_SECS 60
XinZhangMS 0:f7f1f0d76dd6 27
XinZhangMS 0:f7f1f0d76dd6 28 static const char* DEVICE_OPTION_SAVED_AUTH_OPTIONS = "saved_device_auth_options";
XinZhangMS 0:f7f1f0d76dd6 29 static const char* DEVICE_OPTION_SAVED_MESSENGER_OPTIONS = "saved_device_messenger_options";
XinZhangMS 0:f7f1f0d76dd6 30
XinZhangMS 0:f7f1f0d76dd6 31 typedef struct DEVICE_INSTANCE_TAG
XinZhangMS 0:f7f1f0d76dd6 32 {
XinZhangMS 0:f7f1f0d76dd6 33 DEVICE_CONFIG* config;
XinZhangMS 0:f7f1f0d76dd6 34 DEVICE_STATE state;
XinZhangMS 0:f7f1f0d76dd6 35
XinZhangMS 0:f7f1f0d76dd6 36 SESSION_HANDLE session_handle;
XinZhangMS 0:f7f1f0d76dd6 37 CBS_HANDLE cbs_handle;
XinZhangMS 0:f7f1f0d76dd6 38
XinZhangMS 0:f7f1f0d76dd6 39 AUTHENTICATION_HANDLE authentication_handle;
XinZhangMS 0:f7f1f0d76dd6 40 AUTHENTICATION_STATE auth_state;
XinZhangMS 0:f7f1f0d76dd6 41 AUTHENTICATION_ERROR_CODE auth_error_code;
XinZhangMS 0:f7f1f0d76dd6 42 time_t auth_state_last_changed_time;
XinZhangMS 0:f7f1f0d76dd6 43 size_t auth_state_change_timeout_secs;
XinZhangMS 0:f7f1f0d76dd6 44
XinZhangMS 0:f7f1f0d76dd6 45 TELEMETRY_MESSENGER_HANDLE messenger_handle;
XinZhangMS 0:f7f1f0d76dd6 46 TELEMETRY_MESSENGER_STATE msgr_state;
XinZhangMS 0:f7f1f0d76dd6 47 time_t msgr_state_last_changed_time;
XinZhangMS 0:f7f1f0d76dd6 48 size_t msgr_state_change_timeout_secs;
XinZhangMS 0:f7f1f0d76dd6 49
XinZhangMS 0:f7f1f0d76dd6 50 ON_DEVICE_C2D_MESSAGE_RECEIVED on_message_received_callback;
XinZhangMS 0:f7f1f0d76dd6 51 void* on_message_received_context;
XinZhangMS 0:f7f1f0d76dd6 52
XinZhangMS 0:f7f1f0d76dd6 53 TWIN_MESSENGER_HANDLE twin_messenger_handle;
XinZhangMS 0:f7f1f0d76dd6 54 TWIN_MESSENGER_STATE twin_msgr_state;
XinZhangMS 0:f7f1f0d76dd6 55 time_t twin_msgr_state_last_changed_time;
XinZhangMS 0:f7f1f0d76dd6 56 size_t twin_msgr_state_change_timeout_secs;
XinZhangMS 0:f7f1f0d76dd6 57 DEVICE_TWIN_UPDATE_RECEIVED_CALLBACK on_device_twin_update_received_callback;
XinZhangMS 0:f7f1f0d76dd6 58 void* on_device_twin_update_received_context;
XinZhangMS 0:f7f1f0d76dd6 59 } AMQP_DEVICE_INSTANCE;
XinZhangMS 0:f7f1f0d76dd6 60
XinZhangMS 0:f7f1f0d76dd6 61 typedef struct DEVICE_SEND_EVENT_TASK_TAG
XinZhangMS 0:f7f1f0d76dd6 62 {
XinZhangMS 0:f7f1f0d76dd6 63 ON_DEVICE_D2C_EVENT_SEND_COMPLETE on_event_send_complete_callback;
XinZhangMS 0:f7f1f0d76dd6 64 void* on_event_send_complete_context;
XinZhangMS 0:f7f1f0d76dd6 65 } DEVICE_SEND_EVENT_TASK;
XinZhangMS 0:f7f1f0d76dd6 66
XinZhangMS 0:f7f1f0d76dd6 67 typedef struct DEVICE_SEND_TWIN_UPDATE_CONTEXT_TAG
XinZhangMS 0:f7f1f0d76dd6 68 {
XinZhangMS 0:f7f1f0d76dd6 69 DEVICE_SEND_TWIN_UPDATE_COMPLETE_CALLBACK on_send_twin_update_complete_callback;
XinZhangMS 0:f7f1f0d76dd6 70 void* context;
XinZhangMS 0:f7f1f0d76dd6 71 } DEVICE_SEND_TWIN_UPDATE_CONTEXT;
XinZhangMS 0:f7f1f0d76dd6 72
XinZhangMS 0:f7f1f0d76dd6 73 // Internal state control
XinZhangMS 0:f7f1f0d76dd6 74 static void update_state(AMQP_DEVICE_INSTANCE* instance, DEVICE_STATE new_state)
XinZhangMS 0:f7f1f0d76dd6 75 {
XinZhangMS 0:f7f1f0d76dd6 76 if (new_state != instance->state)
XinZhangMS 0:f7f1f0d76dd6 77 {
XinZhangMS 0:f7f1f0d76dd6 78 DEVICE_STATE previous_state = instance->state;
XinZhangMS 0:f7f1f0d76dd6 79 instance->state = new_state;
XinZhangMS 0:f7f1f0d76dd6 80
XinZhangMS 0:f7f1f0d76dd6 81 if (instance->config->on_state_changed_callback != NULL)
XinZhangMS 0:f7f1f0d76dd6 82 {
XinZhangMS 0:f7f1f0d76dd6 83 instance->config->on_state_changed_callback(instance->config->on_state_changed_context, previous_state, new_state);
XinZhangMS 0:f7f1f0d76dd6 84 }
XinZhangMS 0:f7f1f0d76dd6 85 }
XinZhangMS 0:f7f1f0d76dd6 86 }
XinZhangMS 0:f7f1f0d76dd6 87
XinZhangMS 0:f7f1f0d76dd6 88 static int is_timeout_reached(time_t start_time, size_t timeout_in_secs, int *is_timed_out)
XinZhangMS 0:f7f1f0d76dd6 89 {
XinZhangMS 0:f7f1f0d76dd6 90 int result;
XinZhangMS 0:f7f1f0d76dd6 91
XinZhangMS 0:f7f1f0d76dd6 92 if (start_time == INDEFINITE_TIME)
XinZhangMS 0:f7f1f0d76dd6 93 {
XinZhangMS 0:f7f1f0d76dd6 94 LogError("Failed to verify timeout (start_time is INDEFINITE)");
XinZhangMS 0:f7f1f0d76dd6 95 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 96 }
XinZhangMS 0:f7f1f0d76dd6 97 else
XinZhangMS 0:f7f1f0d76dd6 98 {
XinZhangMS 0:f7f1f0d76dd6 99 time_t current_time;
XinZhangMS 0:f7f1f0d76dd6 100
XinZhangMS 0:f7f1f0d76dd6 101 if ((current_time = get_time(NULL)) == INDEFINITE_TIME)
XinZhangMS 0:f7f1f0d76dd6 102 {
XinZhangMS 0:f7f1f0d76dd6 103 LogError("Failed to verify timeout (get_time failed)");
XinZhangMS 0:f7f1f0d76dd6 104 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 105 }
XinZhangMS 0:f7f1f0d76dd6 106 else
XinZhangMS 0:f7f1f0d76dd6 107 {
XinZhangMS 0:f7f1f0d76dd6 108 if (get_difftime(current_time, start_time) >= timeout_in_secs)
XinZhangMS 0:f7f1f0d76dd6 109 {
XinZhangMS 0:f7f1f0d76dd6 110 *is_timed_out = 1;
XinZhangMS 0:f7f1f0d76dd6 111 }
XinZhangMS 0:f7f1f0d76dd6 112 else
XinZhangMS 0:f7f1f0d76dd6 113 {
XinZhangMS 0:f7f1f0d76dd6 114 *is_timed_out = 0;
XinZhangMS 0:f7f1f0d76dd6 115 }
XinZhangMS 0:f7f1f0d76dd6 116
XinZhangMS 0:f7f1f0d76dd6 117 result = RESULT_OK;
XinZhangMS 0:f7f1f0d76dd6 118 }
XinZhangMS 0:f7f1f0d76dd6 119 }
XinZhangMS 0:f7f1f0d76dd6 120
XinZhangMS 0:f7f1f0d76dd6 121 return result;
XinZhangMS 0:f7f1f0d76dd6 122 }
XinZhangMS 0:f7f1f0d76dd6 123
XinZhangMS 0:f7f1f0d76dd6 124
XinZhangMS 0:f7f1f0d76dd6 125 //---------- Callback Handlers ----------//
XinZhangMS 0:f7f1f0d76dd6 126
XinZhangMS 0:f7f1f0d76dd6 127 static D2C_EVENT_SEND_RESULT get_d2c_event_send_result_from(TELEMETRY_MESSENGER_EVENT_SEND_COMPLETE_RESULT result)
XinZhangMS 0:f7f1f0d76dd6 128 {
XinZhangMS 0:f7f1f0d76dd6 129 D2C_EVENT_SEND_RESULT d2c_esr;
XinZhangMS 0:f7f1f0d76dd6 130
XinZhangMS 0:f7f1f0d76dd6 131 switch (result)
XinZhangMS 0:f7f1f0d76dd6 132 {
XinZhangMS 0:f7f1f0d76dd6 133 case TELEMETRY_MESSENGER_EVENT_SEND_COMPLETE_RESULT_OK:
XinZhangMS 0:f7f1f0d76dd6 134 d2c_esr = D2C_EVENT_SEND_COMPLETE_RESULT_OK;
XinZhangMS 0:f7f1f0d76dd6 135 break;
XinZhangMS 0:f7f1f0d76dd6 136 case TELEMETRY_MESSENGER_EVENT_SEND_COMPLETE_RESULT_ERROR_CANNOT_PARSE:
XinZhangMS 0:f7f1f0d76dd6 137 d2c_esr = D2C_EVENT_SEND_COMPLETE_RESULT_ERROR_CANNOT_PARSE;
XinZhangMS 0:f7f1f0d76dd6 138 break;
XinZhangMS 0:f7f1f0d76dd6 139 case TELEMETRY_MESSENGER_EVENT_SEND_COMPLETE_RESULT_ERROR_FAIL_SENDING:
XinZhangMS 0:f7f1f0d76dd6 140 d2c_esr = D2C_EVENT_SEND_COMPLETE_RESULT_ERROR_FAIL_SENDING;
XinZhangMS 0:f7f1f0d76dd6 141 break;
XinZhangMS 0:f7f1f0d76dd6 142 case TELEMETRY_MESSENGER_EVENT_SEND_COMPLETE_RESULT_ERROR_TIMEOUT:
XinZhangMS 0:f7f1f0d76dd6 143 d2c_esr = D2C_EVENT_SEND_COMPLETE_RESULT_ERROR_TIMEOUT;
XinZhangMS 0:f7f1f0d76dd6 144 break;
XinZhangMS 0:f7f1f0d76dd6 145 case TELEMETRY_MESSENGER_EVENT_SEND_COMPLETE_RESULT_MESSENGER_DESTROYED:
XinZhangMS 0:f7f1f0d76dd6 146 d2c_esr = D2C_EVENT_SEND_COMPLETE_RESULT_DEVICE_DESTROYED;
XinZhangMS 0:f7f1f0d76dd6 147 break;
XinZhangMS 0:f7f1f0d76dd6 148 default:
XinZhangMS 0:f7f1f0d76dd6 149 // This is not expected. All states should be mapped.
XinZhangMS 0:f7f1f0d76dd6 150 d2c_esr = D2C_EVENT_SEND_COMPLETE_RESULT_ERROR_UNKNOWN;
XinZhangMS 0:f7f1f0d76dd6 151 break;
XinZhangMS 0:f7f1f0d76dd6 152 };
XinZhangMS 0:f7f1f0d76dd6 153
XinZhangMS 0:f7f1f0d76dd6 154 return d2c_esr;
XinZhangMS 0:f7f1f0d76dd6 155 }
XinZhangMS 0:f7f1f0d76dd6 156
XinZhangMS 0:f7f1f0d76dd6 157 static void on_event_send_complete_messenger_callback(IOTHUB_MESSAGE_LIST* iothub_message, TELEMETRY_MESSENGER_EVENT_SEND_COMPLETE_RESULT ev_send_comp_result, void* context)
XinZhangMS 0:f7f1f0d76dd6 158 {
XinZhangMS 0:f7f1f0d76dd6 159 if (iothub_message == NULL || context == NULL)
XinZhangMS 0:f7f1f0d76dd6 160 {
XinZhangMS 0:f7f1f0d76dd6 161 LogError("on_event_send_complete_messenger_callback was invoked, but either iothub_message (%p) or context (%p) are NULL", iothub_message, context);
XinZhangMS 0:f7f1f0d76dd6 162 }
XinZhangMS 0:f7f1f0d76dd6 163 else
XinZhangMS 0:f7f1f0d76dd6 164 {
XinZhangMS 0:f7f1f0d76dd6 165 DEVICE_SEND_EVENT_TASK* send_task = (DEVICE_SEND_EVENT_TASK*)context;
XinZhangMS 0:f7f1f0d76dd6 166
XinZhangMS 0:f7f1f0d76dd6 167 // Codes_SRS_DEVICE_09_059: [If `ev_send_comp_result` is TELEMETRY_MESSENGER_EVENT_SEND_COMPLETE_RESULT_OK, D2C_EVENT_SEND_COMPLETE_RESULT_OK shall be reported as `event_send_complete`]
XinZhangMS 0:f7f1f0d76dd6 168 // Codes_SRS_DEVICE_09_060: [If `ev_send_comp_result` is TELEMETRY_MESSENGER_EVENT_SEND_COMPLETE_RESULT_ERROR_CANNOT_PARSE, D2C_EVENT_SEND_COMPLETE_RESULT_ERROR_CANNOT_PARSE shall be reported as `event_send_complete`]
XinZhangMS 0:f7f1f0d76dd6 169 // Codes_SRS_DEVICE_09_061: [If `ev_send_comp_result` is TELEMETRY_MESSENGER_EVENT_SEND_COMPLETE_RESULT_ERROR_FAIL_SENDING, D2C_EVENT_SEND_COMPLETE_RESULT_ERROR_FAIL_SENDING shall be reported as `event_send_complete`]
XinZhangMS 0:f7f1f0d76dd6 170 // Codes_SRS_DEVICE_09_062: [If `ev_send_comp_result` is TELEMETRY_MESSENGER_EVENT_SEND_COMPLETE_RESULT_ERROR_TIMEOUT, D2C_EVENT_SEND_COMPLETE_RESULT_ERROR_TIMEOUT shall be reported as `event_send_complete`]
XinZhangMS 0:f7f1f0d76dd6 171 // Codes_SRS_DEVICE_09_063: [If `ev_send_comp_result` is TELEMETRY_MESSENGER_EVENT_SEND_COMPLETE_RESULT_MESSENGER_DESTROYED, D2C_EVENT_SEND_COMPLETE_RESULT_DEVICE_DESTROYED shall be reported as `event_send_complete`]
XinZhangMS 0:f7f1f0d76dd6 172 D2C_EVENT_SEND_RESULT device_send_result = get_d2c_event_send_result_from(ev_send_comp_result);
XinZhangMS 0:f7f1f0d76dd6 173
XinZhangMS 0:f7f1f0d76dd6 174 // Codes_SRS_DEVICE_09_064: [If provided, the user callback and context saved in `send_task` shall be invoked passing the device `event_send_complete`]
XinZhangMS 0:f7f1f0d76dd6 175 if (send_task->on_event_send_complete_callback != NULL)
XinZhangMS 0:f7f1f0d76dd6 176 {
XinZhangMS 0:f7f1f0d76dd6 177 send_task->on_event_send_complete_callback(iothub_message, device_send_result, send_task->on_event_send_complete_context);
XinZhangMS 0:f7f1f0d76dd6 178 }
XinZhangMS 0:f7f1f0d76dd6 179
XinZhangMS 0:f7f1f0d76dd6 180 // Codes_SRS_DEVICE_09_065: [The memory allocated for `send_task` shall be released]
XinZhangMS 0:f7f1f0d76dd6 181 free(send_task);
XinZhangMS 0:f7f1f0d76dd6 182 }
XinZhangMS 0:f7f1f0d76dd6 183 }
XinZhangMS 0:f7f1f0d76dd6 184
XinZhangMS 0:f7f1f0d76dd6 185 static void on_authentication_error_callback(void* context, AUTHENTICATION_ERROR_CODE error_code)
XinZhangMS 0:f7f1f0d76dd6 186 {
XinZhangMS 0:f7f1f0d76dd6 187 if (context == NULL)
XinZhangMS 0:f7f1f0d76dd6 188 {
XinZhangMS 0:f7f1f0d76dd6 189 LogError("on_authentication_error_callback was invoked with error %d, but context is NULL", error_code);
XinZhangMS 0:f7f1f0d76dd6 190 }
XinZhangMS 0:f7f1f0d76dd6 191 else
XinZhangMS 0:f7f1f0d76dd6 192 {
XinZhangMS 0:f7f1f0d76dd6 193 AMQP_DEVICE_INSTANCE* instance = (AMQP_DEVICE_INSTANCE*)context;
XinZhangMS 0:f7f1f0d76dd6 194 instance->auth_error_code = error_code;
XinZhangMS 0:f7f1f0d76dd6 195 }
XinZhangMS 0:f7f1f0d76dd6 196 }
XinZhangMS 0:f7f1f0d76dd6 197
XinZhangMS 0:f7f1f0d76dd6 198 static void on_authentication_state_changed_callback(void* context, AUTHENTICATION_STATE previous_state, AUTHENTICATION_STATE new_state)
XinZhangMS 0:f7f1f0d76dd6 199 {
XinZhangMS 0:f7f1f0d76dd6 200 if (context == NULL)
XinZhangMS 0:f7f1f0d76dd6 201 {
XinZhangMS 0:f7f1f0d76dd6 202 LogError("on_authentication_state_changed_callback was invoked with new_state %d, but context is NULL", new_state);
XinZhangMS 0:f7f1f0d76dd6 203 }
XinZhangMS 0:f7f1f0d76dd6 204 else if (new_state != previous_state)
XinZhangMS 0:f7f1f0d76dd6 205 {
XinZhangMS 0:f7f1f0d76dd6 206 AMQP_DEVICE_INSTANCE* instance = (AMQP_DEVICE_INSTANCE*)context;
XinZhangMS 0:f7f1f0d76dd6 207 instance->auth_state = new_state;
XinZhangMS 0:f7f1f0d76dd6 208
XinZhangMS 0:f7f1f0d76dd6 209 if ((instance->auth_state_last_changed_time = get_time(NULL)) == INDEFINITE_TIME)
XinZhangMS 0:f7f1f0d76dd6 210 {
XinZhangMS 0:f7f1f0d76dd6 211 LogError("Device '%s' failed to set time of last authentication state change (get_time failed)", instance->config->device_id);
XinZhangMS 0:f7f1f0d76dd6 212 }
XinZhangMS 0:f7f1f0d76dd6 213 }
XinZhangMS 0:f7f1f0d76dd6 214 }
XinZhangMS 0:f7f1f0d76dd6 215
XinZhangMS 0:f7f1f0d76dd6 216 static void on_messenger_state_changed_callback(void* context, TELEMETRY_MESSENGER_STATE previous_state, TELEMETRY_MESSENGER_STATE new_state)
XinZhangMS 0:f7f1f0d76dd6 217 {
XinZhangMS 0:f7f1f0d76dd6 218 if (context == NULL)
XinZhangMS 0:f7f1f0d76dd6 219 {
XinZhangMS 0:f7f1f0d76dd6 220 LogError("on_messenger_state_changed_callback was invoked with new_state %d, but context is NULL", new_state);
XinZhangMS 0:f7f1f0d76dd6 221 }
XinZhangMS 0:f7f1f0d76dd6 222 else if (new_state != previous_state)
XinZhangMS 0:f7f1f0d76dd6 223 {
XinZhangMS 0:f7f1f0d76dd6 224 AMQP_DEVICE_INSTANCE* instance = (AMQP_DEVICE_INSTANCE*)context;
XinZhangMS 0:f7f1f0d76dd6 225 instance->msgr_state = new_state;
XinZhangMS 0:f7f1f0d76dd6 226
XinZhangMS 0:f7f1f0d76dd6 227 if ((instance->msgr_state_last_changed_time = get_time(NULL)) == INDEFINITE_TIME)
XinZhangMS 0:f7f1f0d76dd6 228 {
XinZhangMS 0:f7f1f0d76dd6 229 LogError("Device '%s' failed to set time of last messenger state change (get_time failed)", instance->config->device_id);
XinZhangMS 0:f7f1f0d76dd6 230 }
XinZhangMS 0:f7f1f0d76dd6 231 }
XinZhangMS 0:f7f1f0d76dd6 232 }
XinZhangMS 0:f7f1f0d76dd6 233
XinZhangMS 0:f7f1f0d76dd6 234 static DEVICE_TWIN_UPDATE_RESULT get_device_twin_update_result_from(TWIN_REPORT_STATE_RESULT result)
XinZhangMS 0:f7f1f0d76dd6 235 {
XinZhangMS 0:f7f1f0d76dd6 236 DEVICE_TWIN_UPDATE_RESULT device_result;
XinZhangMS 0:f7f1f0d76dd6 237
XinZhangMS 0:f7f1f0d76dd6 238 switch (result)
XinZhangMS 0:f7f1f0d76dd6 239 {
XinZhangMS 0:f7f1f0d76dd6 240 case TWIN_REPORT_STATE_RESULT_SUCCESS:
XinZhangMS 0:f7f1f0d76dd6 241 device_result = DEVICE_TWIN_UPDATE_RESULT_OK;
XinZhangMS 0:f7f1f0d76dd6 242 break;
XinZhangMS 0:f7f1f0d76dd6 243 case TWIN_REPORT_STATE_RESULT_ERROR:
XinZhangMS 0:f7f1f0d76dd6 244 device_result = DEVICE_TWIN_UPDATE_RESULT_ERROR;
XinZhangMS 0:f7f1f0d76dd6 245 break;
XinZhangMS 0:f7f1f0d76dd6 246 default:
XinZhangMS 0:f7f1f0d76dd6 247 device_result = DEVICE_TWIN_UPDATE_RESULT_ERROR;
XinZhangMS 0:f7f1f0d76dd6 248 };
XinZhangMS 0:f7f1f0d76dd6 249
XinZhangMS 0:f7f1f0d76dd6 250 return device_result;
XinZhangMS 0:f7f1f0d76dd6 251 }
XinZhangMS 0:f7f1f0d76dd6 252
XinZhangMS 0:f7f1f0d76dd6 253 static void on_report_state_complete_callback(TWIN_REPORT_STATE_RESULT result, TWIN_REPORT_STATE_REASON reason, int status_code, const void* context)
XinZhangMS 0:f7f1f0d76dd6 254 {
XinZhangMS 0:f7f1f0d76dd6 255 (void)reason;
XinZhangMS 0:f7f1f0d76dd6 256
XinZhangMS 0:f7f1f0d76dd6 257 if (context == NULL)
XinZhangMS 0:f7f1f0d76dd6 258 {
XinZhangMS 0:f7f1f0d76dd6 259 LogError("Invalid argument (context is NULL)");
XinZhangMS 0:f7f1f0d76dd6 260 }
XinZhangMS 0:f7f1f0d76dd6 261 else
XinZhangMS 0:f7f1f0d76dd6 262 {
XinZhangMS 0:f7f1f0d76dd6 263 DEVICE_SEND_TWIN_UPDATE_CONTEXT* twin_ctx = (DEVICE_SEND_TWIN_UPDATE_CONTEXT*)context;
XinZhangMS 0:f7f1f0d76dd6 264
XinZhangMS 0:f7f1f0d76dd6 265 // Codes_SRS_DEVICE_09_141: [on_send_twin_update_complete_callback (if provided by user) shall be invoked passing the corresponding device result and `status_code`]
XinZhangMS 0:f7f1f0d76dd6 266 if (twin_ctx->on_send_twin_update_complete_callback != NULL)
XinZhangMS 0:f7f1f0d76dd6 267 {
XinZhangMS 0:f7f1f0d76dd6 268 DEVICE_TWIN_UPDATE_RESULT device_result;
XinZhangMS 0:f7f1f0d76dd6 269
XinZhangMS 0:f7f1f0d76dd6 270 device_result = get_device_twin_update_result_from(result);
XinZhangMS 0:f7f1f0d76dd6 271
XinZhangMS 0:f7f1f0d76dd6 272 twin_ctx->on_send_twin_update_complete_callback(device_result, status_code, twin_ctx->context);
XinZhangMS 0:f7f1f0d76dd6 273 }
XinZhangMS 0:f7f1f0d76dd6 274
XinZhangMS 0:f7f1f0d76dd6 275 // Codes_SRS_DEVICE_09_142: [Memory allocated for `context` shall be released]
XinZhangMS 0:f7f1f0d76dd6 276 free(twin_ctx);
XinZhangMS 0:f7f1f0d76dd6 277 }
XinZhangMS 0:f7f1f0d76dd6 278 }
XinZhangMS 0:f7f1f0d76dd6 279
XinZhangMS 0:f7f1f0d76dd6 280 static void on_twin_state_update_callback(TWIN_UPDATE_TYPE update_type, const char* payload, size_t size, const void* context)
XinZhangMS 0:f7f1f0d76dd6 281 {
XinZhangMS 0:f7f1f0d76dd6 282 if (payload == NULL || context == NULL)
XinZhangMS 0:f7f1f0d76dd6 283 {
XinZhangMS 0:f7f1f0d76dd6 284 LogError("Invalid argument (context=%p, payload=%p)", context, payload);
XinZhangMS 0:f7f1f0d76dd6 285 }
XinZhangMS 0:f7f1f0d76dd6 286 else
XinZhangMS 0:f7f1f0d76dd6 287 {
XinZhangMS 0:f7f1f0d76dd6 288 AMQP_DEVICE_INSTANCE* instance = (AMQP_DEVICE_INSTANCE*)context;
XinZhangMS 0:f7f1f0d76dd6 289
XinZhangMS 0:f7f1f0d76dd6 290 DEVICE_TWIN_UPDATE_TYPE device_update_type;
XinZhangMS 0:f7f1f0d76dd6 291
XinZhangMS 0:f7f1f0d76dd6 292 if (update_type == TWIN_UPDATE_TYPE_COMPLETE)
XinZhangMS 0:f7f1f0d76dd6 293 {
XinZhangMS 0:f7f1f0d76dd6 294 device_update_type = DEVICE_TWIN_UPDATE_TYPE_COMPLETE;
XinZhangMS 0:f7f1f0d76dd6 295 }
XinZhangMS 0:f7f1f0d76dd6 296 else
XinZhangMS 0:f7f1f0d76dd6 297 {
XinZhangMS 0:f7f1f0d76dd6 298 device_update_type = DEVICE_TWIN_UPDATE_TYPE_PARTIAL;
XinZhangMS 0:f7f1f0d76dd6 299 }
XinZhangMS 0:f7f1f0d76dd6 300
XinZhangMS 0:f7f1f0d76dd6 301 // Codes_SRS_DEVICE_09_151: [on_device_twin_update_received_callback (provided by user) shall be invoked passing the corresponding update type, `payload` and `size`]
XinZhangMS 0:f7f1f0d76dd6 302 instance->on_device_twin_update_received_callback(device_update_type, (const unsigned char*)payload, size, instance->on_device_twin_update_received_context);
XinZhangMS 0:f7f1f0d76dd6 303 }
XinZhangMS 0:f7f1f0d76dd6 304 }
XinZhangMS 0:f7f1f0d76dd6 305
XinZhangMS 0:f7f1f0d76dd6 306 static void on_twin_messenger_state_changed_callback(void* context, TWIN_MESSENGER_STATE previous_state, TWIN_MESSENGER_STATE new_state)
XinZhangMS 0:f7f1f0d76dd6 307 {
XinZhangMS 0:f7f1f0d76dd6 308 if (context != NULL && new_state != previous_state)
XinZhangMS 0:f7f1f0d76dd6 309 {
XinZhangMS 0:f7f1f0d76dd6 310 AMQP_DEVICE_INSTANCE* instance = (AMQP_DEVICE_INSTANCE*)context;
XinZhangMS 0:f7f1f0d76dd6 311 instance->twin_msgr_state = new_state;
XinZhangMS 0:f7f1f0d76dd6 312
XinZhangMS 0:f7f1f0d76dd6 313 if ((instance->twin_msgr_state_last_changed_time = get_time(NULL)) == INDEFINITE_TIME)
XinZhangMS 0:f7f1f0d76dd6 314 {
XinZhangMS 0:f7f1f0d76dd6 315 LogError("Failed setting time of last twin messenger state changed event");
XinZhangMS 0:f7f1f0d76dd6 316 }
XinZhangMS 0:f7f1f0d76dd6 317 }
XinZhangMS 0:f7f1f0d76dd6 318 }
XinZhangMS 0:f7f1f0d76dd6 319
XinZhangMS 0:f7f1f0d76dd6 320
XinZhangMS 0:f7f1f0d76dd6 321 //---------- Message Dispostion ----------//
XinZhangMS 0:f7f1f0d76dd6 322
XinZhangMS 0:f7f1f0d76dd6 323 static DEVICE_MESSAGE_DISPOSITION_INFO* create_device_message_disposition_info_from(TELEMETRY_MESSENGER_MESSAGE_DISPOSITION_INFO* messenger_disposition_info)
XinZhangMS 0:f7f1f0d76dd6 324 {
XinZhangMS 0:f7f1f0d76dd6 325 DEVICE_MESSAGE_DISPOSITION_INFO* device_disposition_info;
XinZhangMS 0:f7f1f0d76dd6 326
XinZhangMS 0:f7f1f0d76dd6 327 if ((device_disposition_info = (DEVICE_MESSAGE_DISPOSITION_INFO*)malloc(sizeof(DEVICE_MESSAGE_DISPOSITION_INFO))) == NULL)
XinZhangMS 0:f7f1f0d76dd6 328 {
XinZhangMS 0:f7f1f0d76dd6 329 LogError("Failed creating DEVICE_MESSAGE_DISPOSITION_INFO (malloc failed)");
XinZhangMS 0:f7f1f0d76dd6 330 }
XinZhangMS 0:f7f1f0d76dd6 331 else if (mallocAndStrcpy_s(&device_disposition_info->source, messenger_disposition_info->source) != RESULT_OK)
XinZhangMS 0:f7f1f0d76dd6 332 {
XinZhangMS 0:f7f1f0d76dd6 333 LogError("Failed creating DEVICE_MESSAGE_DISPOSITION_INFO (mallocAndStrcpy_s failed)");
XinZhangMS 0:f7f1f0d76dd6 334 free(device_disposition_info);
XinZhangMS 0:f7f1f0d76dd6 335 device_disposition_info = NULL;
XinZhangMS 0:f7f1f0d76dd6 336 }
XinZhangMS 0:f7f1f0d76dd6 337 else
XinZhangMS 0:f7f1f0d76dd6 338 {
XinZhangMS 0:f7f1f0d76dd6 339 device_disposition_info->message_id = messenger_disposition_info->message_id;
XinZhangMS 0:f7f1f0d76dd6 340 }
XinZhangMS 0:f7f1f0d76dd6 341
XinZhangMS 0:f7f1f0d76dd6 342 return device_disposition_info;
XinZhangMS 0:f7f1f0d76dd6 343 }
XinZhangMS 0:f7f1f0d76dd6 344
XinZhangMS 0:f7f1f0d76dd6 345 static void destroy_device_disposition_info(DEVICE_MESSAGE_DISPOSITION_INFO* disposition_info)
XinZhangMS 0:f7f1f0d76dd6 346 {
XinZhangMS 0:f7f1f0d76dd6 347 free(disposition_info->source);
XinZhangMS 0:f7f1f0d76dd6 348 free(disposition_info);
XinZhangMS 0:f7f1f0d76dd6 349 }
XinZhangMS 0:f7f1f0d76dd6 350
XinZhangMS 0:f7f1f0d76dd6 351 static TELEMETRY_MESSENGER_MESSAGE_DISPOSITION_INFO* create_messenger_disposition_info(DEVICE_MESSAGE_DISPOSITION_INFO* device_disposition_info)
XinZhangMS 0:f7f1f0d76dd6 352 {
XinZhangMS 0:f7f1f0d76dd6 353 TELEMETRY_MESSENGER_MESSAGE_DISPOSITION_INFO* messenger_disposition_info;
XinZhangMS 0:f7f1f0d76dd6 354
XinZhangMS 0:f7f1f0d76dd6 355 if ((messenger_disposition_info = (TELEMETRY_MESSENGER_MESSAGE_DISPOSITION_INFO*)malloc(sizeof(TELEMETRY_MESSENGER_MESSAGE_DISPOSITION_INFO))) == NULL)
XinZhangMS 0:f7f1f0d76dd6 356 {
XinZhangMS 0:f7f1f0d76dd6 357 LogError("Failed creating TELEMETRY_MESSENGER_MESSAGE_DISPOSITION_INFO (malloc failed)");
XinZhangMS 0:f7f1f0d76dd6 358 }
XinZhangMS 0:f7f1f0d76dd6 359 else if (mallocAndStrcpy_s(&messenger_disposition_info->source, device_disposition_info->source) != RESULT_OK)
XinZhangMS 0:f7f1f0d76dd6 360 {
XinZhangMS 0:f7f1f0d76dd6 361 LogError("Failed creating TELEMETRY_MESSENGER_MESSAGE_DISPOSITION_INFO (mallocAndStrcpy_s failed)");
XinZhangMS 0:f7f1f0d76dd6 362 free(messenger_disposition_info);
XinZhangMS 0:f7f1f0d76dd6 363 messenger_disposition_info = NULL;
XinZhangMS 0:f7f1f0d76dd6 364 }
XinZhangMS 0:f7f1f0d76dd6 365 else
XinZhangMS 0:f7f1f0d76dd6 366 {
XinZhangMS 0:f7f1f0d76dd6 367 messenger_disposition_info->message_id = (delivery_number)device_disposition_info->message_id;
XinZhangMS 0:f7f1f0d76dd6 368 }
XinZhangMS 0:f7f1f0d76dd6 369
XinZhangMS 0:f7f1f0d76dd6 370 return messenger_disposition_info;
XinZhangMS 0:f7f1f0d76dd6 371 }
XinZhangMS 0:f7f1f0d76dd6 372
XinZhangMS 0:f7f1f0d76dd6 373 static void destroy_messenger_disposition_info(TELEMETRY_MESSENGER_MESSAGE_DISPOSITION_INFO* messenger_disposition_info)
XinZhangMS 0:f7f1f0d76dd6 374 {
XinZhangMS 0:f7f1f0d76dd6 375 free(messenger_disposition_info->source);
XinZhangMS 0:f7f1f0d76dd6 376 free(messenger_disposition_info);
XinZhangMS 0:f7f1f0d76dd6 377 }
XinZhangMS 0:f7f1f0d76dd6 378
XinZhangMS 0:f7f1f0d76dd6 379 static TELEMETRY_MESSENGER_DISPOSITION_RESULT get_messenger_message_disposition_result_from(DEVICE_MESSAGE_DISPOSITION_RESULT device_disposition_result)
XinZhangMS 0:f7f1f0d76dd6 380 {
XinZhangMS 0:f7f1f0d76dd6 381 TELEMETRY_MESSENGER_DISPOSITION_RESULT messenger_disposition_result;
XinZhangMS 0:f7f1f0d76dd6 382
XinZhangMS 0:f7f1f0d76dd6 383 switch (device_disposition_result)
XinZhangMS 0:f7f1f0d76dd6 384 {
XinZhangMS 0:f7f1f0d76dd6 385 case DEVICE_MESSAGE_DISPOSITION_RESULT_NONE:
XinZhangMS 0:f7f1f0d76dd6 386 messenger_disposition_result = TELEMETRY_MESSENGER_DISPOSITION_RESULT_NONE;
XinZhangMS 0:f7f1f0d76dd6 387 break;
XinZhangMS 0:f7f1f0d76dd6 388 case DEVICE_MESSAGE_DISPOSITION_RESULT_ACCEPTED:
XinZhangMS 0:f7f1f0d76dd6 389 messenger_disposition_result = TELEMETRY_MESSENGER_DISPOSITION_RESULT_ACCEPTED;
XinZhangMS 0:f7f1f0d76dd6 390 break;
XinZhangMS 0:f7f1f0d76dd6 391 case DEVICE_MESSAGE_DISPOSITION_RESULT_REJECTED:
XinZhangMS 0:f7f1f0d76dd6 392 messenger_disposition_result = TELEMETRY_MESSENGER_DISPOSITION_RESULT_REJECTED;
XinZhangMS 0:f7f1f0d76dd6 393 break;
XinZhangMS 0:f7f1f0d76dd6 394 case DEVICE_MESSAGE_DISPOSITION_RESULT_RELEASED:
XinZhangMS 0:f7f1f0d76dd6 395 messenger_disposition_result = TELEMETRY_MESSENGER_DISPOSITION_RESULT_RELEASED;
XinZhangMS 0:f7f1f0d76dd6 396 break;
XinZhangMS 0:f7f1f0d76dd6 397 default:
XinZhangMS 0:f7f1f0d76dd6 398 LogError("Failed to get the corresponding TELEMETRY_MESSENGER_DISPOSITION_RESULT (%d is not supported)", device_disposition_result);
XinZhangMS 0:f7f1f0d76dd6 399 messenger_disposition_result = TELEMETRY_MESSENGER_DISPOSITION_RESULT_RELEASED;
XinZhangMS 0:f7f1f0d76dd6 400 break;
XinZhangMS 0:f7f1f0d76dd6 401 }
XinZhangMS 0:f7f1f0d76dd6 402
XinZhangMS 0:f7f1f0d76dd6 403 return messenger_disposition_result;
XinZhangMS 0:f7f1f0d76dd6 404 }
XinZhangMS 0:f7f1f0d76dd6 405
XinZhangMS 0:f7f1f0d76dd6 406 static TELEMETRY_MESSENGER_DISPOSITION_RESULT on_messenger_message_received_callback(IOTHUB_MESSAGE_HANDLE iothub_message_handle, TELEMETRY_MESSENGER_MESSAGE_DISPOSITION_INFO* disposition_info, void* context)
XinZhangMS 0:f7f1f0d76dd6 407 {
XinZhangMS 0:f7f1f0d76dd6 408 TELEMETRY_MESSENGER_DISPOSITION_RESULT msgr_disposition_result;
XinZhangMS 0:f7f1f0d76dd6 409
XinZhangMS 0:f7f1f0d76dd6 410 // Codes_SRS_DEVICE_09_070: [If `iothub_message_handle` or `context` is NULL, on_messenger_message_received_callback shall return TELEMETRY_MESSENGER_DISPOSITION_RESULT_RELEASED]
XinZhangMS 0:f7f1f0d76dd6 411 if (iothub_message_handle == NULL || context == NULL)
XinZhangMS 0:f7f1f0d76dd6 412 {
XinZhangMS 0:f7f1f0d76dd6 413 LogError("Failed receiving incoming C2D message (message handle (%p) or context (%p) is NULL)", iothub_message_handle, context);
XinZhangMS 0:f7f1f0d76dd6 414 msgr_disposition_result = TELEMETRY_MESSENGER_DISPOSITION_RESULT_RELEASED;
XinZhangMS 0:f7f1f0d76dd6 415 }
XinZhangMS 0:f7f1f0d76dd6 416 else
XinZhangMS 0:f7f1f0d76dd6 417 {
XinZhangMS 0:f7f1f0d76dd6 418 AMQP_DEVICE_INSTANCE* device_instance = (AMQP_DEVICE_INSTANCE*)context;
XinZhangMS 0:f7f1f0d76dd6 419
XinZhangMS 0:f7f1f0d76dd6 420 if (device_instance->on_message_received_callback == NULL)
XinZhangMS 0:f7f1f0d76dd6 421 {
XinZhangMS 0:f7f1f0d76dd6 422 LogError("Device '%s' failed receiving incoming C2D message (callback is NULL)", device_instance->config->device_id);
XinZhangMS 0:f7f1f0d76dd6 423 msgr_disposition_result = TELEMETRY_MESSENGER_DISPOSITION_RESULT_RELEASED;
XinZhangMS 0:f7f1f0d76dd6 424 }
XinZhangMS 0:f7f1f0d76dd6 425 else
XinZhangMS 0:f7f1f0d76dd6 426 {
XinZhangMS 0:f7f1f0d76dd6 427 DEVICE_MESSAGE_DISPOSITION_INFO* device_message_disposition_info;
XinZhangMS 0:f7f1f0d76dd6 428
XinZhangMS 0:f7f1f0d76dd6 429 // Codes_SRS_DEVICE_09_119: [A DEVICE_MESSAGE_DISPOSITION_INFO instance shall be created containing a copy of `disposition_info->source` and `disposition_info->message_id`]
XinZhangMS 0:f7f1f0d76dd6 430 if ((device_message_disposition_info = create_device_message_disposition_info_from(disposition_info)) == NULL)
XinZhangMS 0:f7f1f0d76dd6 431 {
XinZhangMS 0:f7f1f0d76dd6 432 // Codes_SRS_DEVICE_09_120: [If the DEVICE_MESSAGE_DISPOSITION_INFO instance fails to be created, on_messenger_message_received_callback shall return TELEMETRY_MESSENGER_DISPOSITION_RESULT_RELEASED]
XinZhangMS 0:f7f1f0d76dd6 433 LogError("Device '%s' failed receiving incoming C2D message (failed creating DEVICE_MESSAGE_DISPOSITION_INFO)", device_instance->config->device_id);
XinZhangMS 0:f7f1f0d76dd6 434 msgr_disposition_result = TELEMETRY_MESSENGER_DISPOSITION_RESULT_RELEASED;
XinZhangMS 0:f7f1f0d76dd6 435 }
XinZhangMS 0:f7f1f0d76dd6 436 else
XinZhangMS 0:f7f1f0d76dd6 437 {
XinZhangMS 0:f7f1f0d76dd6 438 // Codes_SRS_DEVICE_09_071: [The user callback shall be invoked, passing the context it provided]
XinZhangMS 0:f7f1f0d76dd6 439 DEVICE_MESSAGE_DISPOSITION_RESULT device_disposition_result = device_instance->on_message_received_callback(iothub_message_handle, device_message_disposition_info, device_instance->on_message_received_context);
XinZhangMS 0:f7f1f0d76dd6 440
XinZhangMS 0:f7f1f0d76dd6 441 // Codes_SRS_DEVICE_09_072: [If the user callback returns DEVICE_MESSAGE_DISPOSITION_RESULT_ACCEPTED, on_messenger_message_received_callback shall return TELEMETRY_MESSENGER_DISPOSITION_RESULT_ACCEPTED]
XinZhangMS 0:f7f1f0d76dd6 442 // Codes_SRS_DEVICE_09_073: [If the user callback returns DEVICE_MESSAGE_DISPOSITION_RESULT_REJECTED, on_messenger_message_received_callback shall return TELEMETRY_MESSENGER_DISPOSITION_RESULT_REJECTED]
XinZhangMS 0:f7f1f0d76dd6 443 // Codes_SRS_DEVICE_09_074: [If the user callback returns DEVICE_MESSAGE_DISPOSITION_RESULT_RELEASED, on_messenger_message_received_callback shall return TELEMETRY_MESSENGER_DISPOSITION_RESULT_RELEASED]
XinZhangMS 0:f7f1f0d76dd6 444 msgr_disposition_result = get_messenger_message_disposition_result_from(device_disposition_result);
XinZhangMS 0:f7f1f0d76dd6 445
XinZhangMS 0:f7f1f0d76dd6 446 // Codes_SRS_DEVICE_09_121: [on_messenger_message_received_callback shall release the memory allocated for DEVICE_MESSAGE_DISPOSITION_INFO]
XinZhangMS 0:f7f1f0d76dd6 447 destroy_device_disposition_info(device_message_disposition_info);
XinZhangMS 0:f7f1f0d76dd6 448 }
XinZhangMS 0:f7f1f0d76dd6 449 }
XinZhangMS 0:f7f1f0d76dd6 450 }
XinZhangMS 0:f7f1f0d76dd6 451
XinZhangMS 0:f7f1f0d76dd6 452 return msgr_disposition_result;
XinZhangMS 0:f7f1f0d76dd6 453 }
XinZhangMS 0:f7f1f0d76dd6 454
XinZhangMS 0:f7f1f0d76dd6 455
XinZhangMS 0:f7f1f0d76dd6 456 //---------- Configuration Helpers ----------//
XinZhangMS 0:f7f1f0d76dd6 457
XinZhangMS 0:f7f1f0d76dd6 458 static void destroy_device_config(DEVICE_CONFIG* config)
XinZhangMS 0:f7f1f0d76dd6 459 {
XinZhangMS 0:f7f1f0d76dd6 460 if (config != NULL)
XinZhangMS 0:f7f1f0d76dd6 461 {
XinZhangMS 0:f7f1f0d76dd6 462 free(config->product_info);
XinZhangMS 0:f7f1f0d76dd6 463 free(config->iothub_host_fqdn);
XinZhangMS 0:f7f1f0d76dd6 464 free(config);
XinZhangMS 0:f7f1f0d76dd6 465 }
XinZhangMS 0:f7f1f0d76dd6 466 }
XinZhangMS 0:f7f1f0d76dd6 467
XinZhangMS 0:f7f1f0d76dd6 468 static DEVICE_CONFIG* clone_device_config(DEVICE_CONFIG *config)
XinZhangMS 0:f7f1f0d76dd6 469 {
XinZhangMS 0:f7f1f0d76dd6 470 DEVICE_CONFIG* new_config;
XinZhangMS 0:f7f1f0d76dd6 471
XinZhangMS 0:f7f1f0d76dd6 472 if ((new_config = (DEVICE_CONFIG*)malloc(sizeof(DEVICE_CONFIG))) == NULL)
XinZhangMS 0:f7f1f0d76dd6 473 {
XinZhangMS 0:f7f1f0d76dd6 474 LogError("Failed copying the DEVICE_CONFIG (malloc failed)");
XinZhangMS 0:f7f1f0d76dd6 475 }
XinZhangMS 0:f7f1f0d76dd6 476 else
XinZhangMS 0:f7f1f0d76dd6 477 {
XinZhangMS 0:f7f1f0d76dd6 478 int result;
XinZhangMS 0:f7f1f0d76dd6 479 memset(new_config, 0, sizeof(DEVICE_CONFIG));
XinZhangMS 0:f7f1f0d76dd6 480
XinZhangMS 0:f7f1f0d76dd6 481 if (config->product_info != NULL &&
XinZhangMS 0:f7f1f0d76dd6 482 mallocAndStrcpy_s(&new_config->product_info, config->product_info) != RESULT_OK)
XinZhangMS 0:f7f1f0d76dd6 483 {
XinZhangMS 0:f7f1f0d76dd6 484 LogError("Failed copying the DEVICE_CONFIG (failed copying product_info)");
XinZhangMS 0:f7f1f0d76dd6 485 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 486 }
XinZhangMS 0:f7f1f0d76dd6 487 else if (mallocAndStrcpy_s(&new_config->iothub_host_fqdn, config->iothub_host_fqdn) != RESULT_OK)
XinZhangMS 0:f7f1f0d76dd6 488 {
XinZhangMS 0:f7f1f0d76dd6 489 LogError("Failed copying the DEVICE_CONFIG (failed copying iothub_host_fqdn)");
XinZhangMS 0:f7f1f0d76dd6 490 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 491 }
XinZhangMS 0:f7f1f0d76dd6 492 else
XinZhangMS 0:f7f1f0d76dd6 493 {
XinZhangMS 0:f7f1f0d76dd6 494 new_config->authorization_module = config->authorization_module;
XinZhangMS 0:f7f1f0d76dd6 495 new_config->authentication_mode = config->authentication_mode;
XinZhangMS 0:f7f1f0d76dd6 496 new_config->on_state_changed_callback = config->on_state_changed_callback;
XinZhangMS 0:f7f1f0d76dd6 497 new_config->on_state_changed_context = config->on_state_changed_context;
XinZhangMS 0:f7f1f0d76dd6 498 new_config->device_id = IoTHubClient_Auth_Get_DeviceId(config->authorization_module);
XinZhangMS 0:f7f1f0d76dd6 499 new_config->module_id = IoTHubClient_Auth_Get_ModuleId(config->authorization_module);
XinZhangMS 0:f7f1f0d76dd6 500 result = RESULT_OK;
XinZhangMS 0:f7f1f0d76dd6 501 }
XinZhangMS 0:f7f1f0d76dd6 502
XinZhangMS 0:f7f1f0d76dd6 503 if (result != RESULT_OK)
XinZhangMS 0:f7f1f0d76dd6 504 {
XinZhangMS 0:f7f1f0d76dd6 505 destroy_device_config(new_config);
XinZhangMS 0:f7f1f0d76dd6 506 new_config = NULL;
XinZhangMS 0:f7f1f0d76dd6 507 }
XinZhangMS 0:f7f1f0d76dd6 508 }
XinZhangMS 0:f7f1f0d76dd6 509
XinZhangMS 0:f7f1f0d76dd6 510 return new_config;
XinZhangMS 0:f7f1f0d76dd6 511 }
XinZhangMS 0:f7f1f0d76dd6 512
XinZhangMS 0:f7f1f0d76dd6 513 static void set_authentication_config(AMQP_DEVICE_INSTANCE* device_instance, AUTHENTICATION_CONFIG* auth_config)
XinZhangMS 0:f7f1f0d76dd6 514 {
XinZhangMS 0:f7f1f0d76dd6 515 DEVICE_CONFIG *device_config = device_instance->config;
XinZhangMS 0:f7f1f0d76dd6 516
XinZhangMS 0:f7f1f0d76dd6 517 auth_config->device_id = device_config->device_id;
XinZhangMS 0:f7f1f0d76dd6 518 auth_config->module_id = device_config->module_id;
XinZhangMS 0:f7f1f0d76dd6 519 auth_config->iothub_host_fqdn = device_config->iothub_host_fqdn;
XinZhangMS 0:f7f1f0d76dd6 520 auth_config->on_error_callback = on_authentication_error_callback;
XinZhangMS 0:f7f1f0d76dd6 521 auth_config->on_error_callback_context = device_instance;
XinZhangMS 0:f7f1f0d76dd6 522 auth_config->on_state_changed_callback = on_authentication_state_changed_callback;
XinZhangMS 0:f7f1f0d76dd6 523 auth_config->on_state_changed_callback_context = device_instance;
XinZhangMS 0:f7f1f0d76dd6 524 auth_config->authorization_module = device_config->authorization_module;
XinZhangMS 0:f7f1f0d76dd6 525 }
XinZhangMS 0:f7f1f0d76dd6 526
XinZhangMS 0:f7f1f0d76dd6 527 // Create and Destroy Helpers
XinZhangMS 0:f7f1f0d76dd6 528 static void internal_destroy_device(AMQP_DEVICE_INSTANCE* instance)
XinZhangMS 0:f7f1f0d76dd6 529 {
XinZhangMS 0:f7f1f0d76dd6 530 if (instance != NULL)
XinZhangMS 0:f7f1f0d76dd6 531 {
XinZhangMS 0:f7f1f0d76dd6 532 if (instance->messenger_handle != NULL)
XinZhangMS 0:f7f1f0d76dd6 533 {
XinZhangMS 0:f7f1f0d76dd6 534 telemetry_messenger_destroy(instance->messenger_handle);
XinZhangMS 0:f7f1f0d76dd6 535 }
XinZhangMS 0:f7f1f0d76dd6 536
XinZhangMS 0:f7f1f0d76dd6 537 if (instance->twin_messenger_handle != NULL)
XinZhangMS 0:f7f1f0d76dd6 538 {
XinZhangMS 0:f7f1f0d76dd6 539 twin_messenger_destroy(instance->twin_messenger_handle);
XinZhangMS 0:f7f1f0d76dd6 540 }
XinZhangMS 0:f7f1f0d76dd6 541
XinZhangMS 0:f7f1f0d76dd6 542 if (instance->authentication_handle != NULL)
XinZhangMS 0:f7f1f0d76dd6 543 {
XinZhangMS 0:f7f1f0d76dd6 544 authentication_destroy(instance->authentication_handle);
XinZhangMS 0:f7f1f0d76dd6 545 }
XinZhangMS 0:f7f1f0d76dd6 546
XinZhangMS 0:f7f1f0d76dd6 547 destroy_device_config(instance->config);
XinZhangMS 0:f7f1f0d76dd6 548 free(instance);
XinZhangMS 0:f7f1f0d76dd6 549 }
XinZhangMS 0:f7f1f0d76dd6 550 }
XinZhangMS 0:f7f1f0d76dd6 551
XinZhangMS 0:f7f1f0d76dd6 552 static int create_authentication_instance(AMQP_DEVICE_INSTANCE *instance)
XinZhangMS 0:f7f1f0d76dd6 553 {
XinZhangMS 0:f7f1f0d76dd6 554 int result;
XinZhangMS 0:f7f1f0d76dd6 555 AUTHENTICATION_CONFIG auth_config;
XinZhangMS 0:f7f1f0d76dd6 556
XinZhangMS 0:f7f1f0d76dd6 557 set_authentication_config(instance, &auth_config);
XinZhangMS 0:f7f1f0d76dd6 558
XinZhangMS 0:f7f1f0d76dd6 559 if ((instance->authentication_handle = authentication_create(&auth_config)) == NULL)
XinZhangMS 0:f7f1f0d76dd6 560 {
XinZhangMS 0:f7f1f0d76dd6 561 LogError("Failed creating the AUTHENTICATION_HANDLE (authentication_create failed)");
XinZhangMS 0:f7f1f0d76dd6 562 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 563 }
XinZhangMS 0:f7f1f0d76dd6 564 else
XinZhangMS 0:f7f1f0d76dd6 565 {
XinZhangMS 0:f7f1f0d76dd6 566 result = RESULT_OK;
XinZhangMS 0:f7f1f0d76dd6 567 }
XinZhangMS 0:f7f1f0d76dd6 568
XinZhangMS 0:f7f1f0d76dd6 569 return result;
XinZhangMS 0:f7f1f0d76dd6 570 }
XinZhangMS 0:f7f1f0d76dd6 571
XinZhangMS 0:f7f1f0d76dd6 572 static int create_telemetry_messenger_instance(AMQP_DEVICE_INSTANCE* instance, const char* pi)
XinZhangMS 0:f7f1f0d76dd6 573 {
XinZhangMS 0:f7f1f0d76dd6 574 int result;
XinZhangMS 0:f7f1f0d76dd6 575
XinZhangMS 0:f7f1f0d76dd6 576 TELEMETRY_MESSENGER_CONFIG messenger_config;
XinZhangMS 0:f7f1f0d76dd6 577 messenger_config.device_id = instance->config->device_id;
XinZhangMS 0:f7f1f0d76dd6 578 messenger_config.module_id = instance->config->module_id;
XinZhangMS 0:f7f1f0d76dd6 579 messenger_config.iothub_host_fqdn = instance->config->iothub_host_fqdn;
XinZhangMS 0:f7f1f0d76dd6 580 messenger_config.on_state_changed_callback = on_messenger_state_changed_callback;
XinZhangMS 0:f7f1f0d76dd6 581 messenger_config.on_state_changed_context = instance;
XinZhangMS 0:f7f1f0d76dd6 582
XinZhangMS 0:f7f1f0d76dd6 583 if ((instance->messenger_handle = telemetry_messenger_create(&messenger_config, pi)) == NULL)
XinZhangMS 0:f7f1f0d76dd6 584 {
XinZhangMS 0:f7f1f0d76dd6 585 LogError("Failed creating the TELEMETRY_MESSENGER_HANDLE (messenger_create failed)");
XinZhangMS 0:f7f1f0d76dd6 586 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 587 }
XinZhangMS 0:f7f1f0d76dd6 588 else
XinZhangMS 0:f7f1f0d76dd6 589 {
XinZhangMS 0:f7f1f0d76dd6 590 result = RESULT_OK;
XinZhangMS 0:f7f1f0d76dd6 591 }
XinZhangMS 0:f7f1f0d76dd6 592
XinZhangMS 0:f7f1f0d76dd6 593 return result;
XinZhangMS 0:f7f1f0d76dd6 594 }
XinZhangMS 0:f7f1f0d76dd6 595
XinZhangMS 0:f7f1f0d76dd6 596 static int create_twin_messenger(AMQP_DEVICE_INSTANCE* instance)
XinZhangMS 0:f7f1f0d76dd6 597 {
XinZhangMS 0:f7f1f0d76dd6 598 int result;
XinZhangMS 0:f7f1f0d76dd6 599 TWIN_MESSENGER_CONFIG twin_msgr_config;
XinZhangMS 0:f7f1f0d76dd6 600
XinZhangMS 0:f7f1f0d76dd6 601 twin_msgr_config.client_version = instance->config->product_info;
XinZhangMS 0:f7f1f0d76dd6 602 twin_msgr_config.device_id = instance->config->device_id;
XinZhangMS 0:f7f1f0d76dd6 603 twin_msgr_config.module_id = instance->config->module_id;
XinZhangMS 0:f7f1f0d76dd6 604 twin_msgr_config.iothub_host_fqdn = instance->config->iothub_host_fqdn;
XinZhangMS 0:f7f1f0d76dd6 605 twin_msgr_config.on_state_changed_callback = on_twin_messenger_state_changed_callback;
XinZhangMS 0:f7f1f0d76dd6 606 twin_msgr_config.on_state_changed_context = (void*)instance;
XinZhangMS 0:f7f1f0d76dd6 607
XinZhangMS 0:f7f1f0d76dd6 608 if ((instance->twin_messenger_handle = twin_messenger_create(&twin_msgr_config)) == NULL)
XinZhangMS 0:f7f1f0d76dd6 609 {
XinZhangMS 0:f7f1f0d76dd6 610 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 611 }
XinZhangMS 0:f7f1f0d76dd6 612 else
XinZhangMS 0:f7f1f0d76dd6 613 {
XinZhangMS 0:f7f1f0d76dd6 614 result = RESULT_OK;
XinZhangMS 0:f7f1f0d76dd6 615 }
XinZhangMS 0:f7f1f0d76dd6 616
XinZhangMS 0:f7f1f0d76dd6 617 return result;
XinZhangMS 0:f7f1f0d76dd6 618 }
XinZhangMS 0:f7f1f0d76dd6 619
XinZhangMS 0:f7f1f0d76dd6 620
XinZhangMS 0:f7f1f0d76dd6 621 // ---------- Set/Retrieve Options Helpers ----------//
XinZhangMS 0:f7f1f0d76dd6 622
XinZhangMS 0:f7f1f0d76dd6 623 static void* device_clone_option(const char* name, const void* value)
XinZhangMS 0:f7f1f0d76dd6 624 {
XinZhangMS 0:f7f1f0d76dd6 625 void* result;
XinZhangMS 0:f7f1f0d76dd6 626
XinZhangMS 0:f7f1f0d76dd6 627 if (name == NULL || value == NULL)
XinZhangMS 0:f7f1f0d76dd6 628 {
XinZhangMS 0:f7f1f0d76dd6 629 LogError("Failed to clone device option (either name (%p) or value (%p) is NULL)", name, value);
XinZhangMS 0:f7f1f0d76dd6 630 result = NULL;
XinZhangMS 0:f7f1f0d76dd6 631 }
XinZhangMS 0:f7f1f0d76dd6 632 else
XinZhangMS 0:f7f1f0d76dd6 633 {
XinZhangMS 0:f7f1f0d76dd6 634 if (strcmp(DEVICE_OPTION_SAVED_AUTH_OPTIONS, name) == 0 ||
XinZhangMS 0:f7f1f0d76dd6 635 strcmp(DEVICE_OPTION_SAVED_MESSENGER_OPTIONS, name) == 0)
XinZhangMS 0:f7f1f0d76dd6 636 {
XinZhangMS 0:f7f1f0d76dd6 637 if ((result = (void*)OptionHandler_Clone((OPTIONHANDLER_HANDLE)value)) == NULL)
XinZhangMS 0:f7f1f0d76dd6 638 {
XinZhangMS 0:f7f1f0d76dd6 639 LogError("Failed to clone device option (OptionHandler_Clone failed for option %s)", name);
XinZhangMS 0:f7f1f0d76dd6 640 }
XinZhangMS 0:f7f1f0d76dd6 641 }
XinZhangMS 0:f7f1f0d76dd6 642 else
XinZhangMS 0:f7f1f0d76dd6 643 {
XinZhangMS 0:f7f1f0d76dd6 644 LogError("Failed to clone device option (option with name '%s' is not suppported)", name);
XinZhangMS 0:f7f1f0d76dd6 645 result = NULL;
XinZhangMS 0:f7f1f0d76dd6 646 }
XinZhangMS 0:f7f1f0d76dd6 647 }
XinZhangMS 0:f7f1f0d76dd6 648
XinZhangMS 0:f7f1f0d76dd6 649 return result;
XinZhangMS 0:f7f1f0d76dd6 650 }
XinZhangMS 0:f7f1f0d76dd6 651
XinZhangMS 0:f7f1f0d76dd6 652 static void device_destroy_option(const char* name, const void* value)
XinZhangMS 0:f7f1f0d76dd6 653 {
XinZhangMS 0:f7f1f0d76dd6 654 if (name == NULL || value == NULL)
XinZhangMS 0:f7f1f0d76dd6 655 {
XinZhangMS 0:f7f1f0d76dd6 656 LogError("Failed to destroy device option (either name (%p) or value (%p) is NULL)", name, value);
XinZhangMS 0:f7f1f0d76dd6 657 }
XinZhangMS 0:f7f1f0d76dd6 658 else
XinZhangMS 0:f7f1f0d76dd6 659 {
XinZhangMS 0:f7f1f0d76dd6 660 if (strcmp(name, DEVICE_OPTION_SAVED_AUTH_OPTIONS) == 0 ||
XinZhangMS 0:f7f1f0d76dd6 661 strcmp(name, DEVICE_OPTION_SAVED_MESSENGER_OPTIONS) == 0)
XinZhangMS 0:f7f1f0d76dd6 662 {
XinZhangMS 0:f7f1f0d76dd6 663 OptionHandler_Destroy((OPTIONHANDLER_HANDLE)value);
XinZhangMS 0:f7f1f0d76dd6 664 }
XinZhangMS 0:f7f1f0d76dd6 665 else
XinZhangMS 0:f7f1f0d76dd6 666 {
XinZhangMS 0:f7f1f0d76dd6 667 LogError("Failed to clone device option (option with name '%s' is not suppported)", name);
XinZhangMS 0:f7f1f0d76dd6 668 }
XinZhangMS 0:f7f1f0d76dd6 669 }
XinZhangMS 0:f7f1f0d76dd6 670 }
XinZhangMS 0:f7f1f0d76dd6 671
XinZhangMS 0:f7f1f0d76dd6 672
XinZhangMS 0:f7f1f0d76dd6 673 //---------- Public APIs ----------//
XinZhangMS 0:f7f1f0d76dd6 674
XinZhangMS 0:f7f1f0d76dd6 675 AMQP_DEVICE_HANDLE device_create(DEVICE_CONFIG *config)
XinZhangMS 0:f7f1f0d76dd6 676 {
XinZhangMS 0:f7f1f0d76dd6 677 AMQP_DEVICE_INSTANCE *instance;
XinZhangMS 0:f7f1f0d76dd6 678
XinZhangMS 0:f7f1f0d76dd6 679 // Codes_SRS_DEVICE_09_001: [If config, authorization_module or iothub_host_fqdn or on_state_changed_callback are NULL then device_create shall fail and return NULL]
XinZhangMS 0:f7f1f0d76dd6 680 if (config == NULL)
XinZhangMS 0:f7f1f0d76dd6 681 {
XinZhangMS 0:f7f1f0d76dd6 682 LogError("Failed creating the device instance (config is NULL)");
XinZhangMS 0:f7f1f0d76dd6 683 instance = NULL;
XinZhangMS 0:f7f1f0d76dd6 684 }
XinZhangMS 0:f7f1f0d76dd6 685 else if (config->iothub_host_fqdn == NULL)
XinZhangMS 0:f7f1f0d76dd6 686 {
XinZhangMS 0:f7f1f0d76dd6 687 LogError("Failed creating the device instance (config->iothub_host_fqdn is NULL)");
XinZhangMS 0:f7f1f0d76dd6 688 instance = NULL;
XinZhangMS 0:f7f1f0d76dd6 689 }
XinZhangMS 0:f7f1f0d76dd6 690 else if (config->on_state_changed_callback == NULL)
XinZhangMS 0:f7f1f0d76dd6 691 {
XinZhangMS 0:f7f1f0d76dd6 692 LogError("Failed creating the device instance (config->on_state_changed_callback is NULL)");
XinZhangMS 0:f7f1f0d76dd6 693 instance = NULL;
XinZhangMS 0:f7f1f0d76dd6 694 }
XinZhangMS 0:f7f1f0d76dd6 695 else if (config->authorization_module == NULL)
XinZhangMS 0:f7f1f0d76dd6 696 {
XinZhangMS 0:f7f1f0d76dd6 697 LogError("Failed creating the device instance (config->authorization_module is NULL)");
XinZhangMS 0:f7f1f0d76dd6 698 instance = NULL;
XinZhangMS 0:f7f1f0d76dd6 699 }
XinZhangMS 0:f7f1f0d76dd6 700 // Codes_SRS_DEVICE_09_002: [device_create shall allocate memory for the device instance structure]
XinZhangMS 0:f7f1f0d76dd6 701 else if ((instance = (AMQP_DEVICE_INSTANCE*)malloc(sizeof(AMQP_DEVICE_INSTANCE))) == NULL)
XinZhangMS 0:f7f1f0d76dd6 702 {
XinZhangMS 0:f7f1f0d76dd6 703 // Codes_SRS_DEVICE_09_003: [If malloc fails, device_create shall fail and return NULL]
XinZhangMS 0:f7f1f0d76dd6 704 LogError("Failed creating the device instance (malloc failed)");
XinZhangMS 0:f7f1f0d76dd6 705 }
XinZhangMS 0:f7f1f0d76dd6 706 else
XinZhangMS 0:f7f1f0d76dd6 707 {
XinZhangMS 0:f7f1f0d76dd6 708 int result;
XinZhangMS 0:f7f1f0d76dd6 709
XinZhangMS 0:f7f1f0d76dd6 710 memset(instance, 0, sizeof(AMQP_DEVICE_INSTANCE));
XinZhangMS 0:f7f1f0d76dd6 711
XinZhangMS 0:f7f1f0d76dd6 712 // Codes_SRS_DEVICE_09_004: [All `config` parameters shall be saved into `instance`]
XinZhangMS 0:f7f1f0d76dd6 713 if ((instance->config = clone_device_config(config)) == NULL)
XinZhangMS 0:f7f1f0d76dd6 714 {
XinZhangMS 0:f7f1f0d76dd6 715 // Codes_SRS_DEVICE_09_005: [If any `config` parameters fail to be saved into `instance`, device_create shall fail and return NULL]
XinZhangMS 0:f7f1f0d76dd6 716 LogError("Failed creating the device instance for device '%s' (failed copying the configuration)", config->device_id);
XinZhangMS 0:f7f1f0d76dd6 717 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 718 }
XinZhangMS 0:f7f1f0d76dd6 719 // Codes_SRS_DEVICE_09_006: [If `instance->authentication_mode` is DEVICE_AUTH_MODE_CBS, `instance->authentication_handle` shall be set using authentication_create()]
XinZhangMS 0:f7f1f0d76dd6 720 else if (instance->config->authentication_mode == DEVICE_AUTH_MODE_CBS &&
XinZhangMS 0:f7f1f0d76dd6 721 create_authentication_instance(instance) != RESULT_OK)
XinZhangMS 0:f7f1f0d76dd6 722 {
XinZhangMS 0:f7f1f0d76dd6 723 // Codes_SRS_DEVICE_09_007: [If the AUTHENTICATION_HANDLE fails to be created, device_create shall fail and return NULL]
XinZhangMS 0:f7f1f0d76dd6 724 LogError("Failed creating the device instance for device '%s' (failed creating the authentication instance)", instance->config->device_id);
XinZhangMS 0:f7f1f0d76dd6 725 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 726 }
XinZhangMS 0:f7f1f0d76dd6 727 // Codes_SRS_DEVICE_09_008: [`instance->messenger_handle` shall be set using telemetry_messenger_create()]
XinZhangMS 0:f7f1f0d76dd6 728 else if (create_telemetry_messenger_instance(instance, config->product_info) != RESULT_OK)
XinZhangMS 0:f7f1f0d76dd6 729 {
XinZhangMS 0:f7f1f0d76dd6 730 // Codes_SRS_DEVICE_09_009: [If the TELEMETRY_MESSENGER_HANDLE fails to be created, device_create shall fail and return NULL]
XinZhangMS 0:f7f1f0d76dd6 731 LogError("Failed creating the device instance for device '%s' (failed creating the messenger instance)", instance->config->device_id);
XinZhangMS 0:f7f1f0d76dd6 732 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 733 }
XinZhangMS 0:f7f1f0d76dd6 734 // Codes_SRS_DEVICE_09_122: [`instance->twin_messenger_handle` shall be set using twin_messenger_create()]
XinZhangMS 0:f7f1f0d76dd6 735 else if (create_twin_messenger(instance) != RESULT_OK)
XinZhangMS 0:f7f1f0d76dd6 736 {
XinZhangMS 0:f7f1f0d76dd6 737 // Codes_SRS_DEVICE_09_123: [If the TWIN_MESSENGER_HANDLE fails to be created, device_create shall fail and return NULL]
XinZhangMS 0:f7f1f0d76dd6 738 LogError("Failed creating the twin messenger for device '%s'", instance->config->device_id);
XinZhangMS 0:f7f1f0d76dd6 739 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 740 }
XinZhangMS 0:f7f1f0d76dd6 741 else
XinZhangMS 0:f7f1f0d76dd6 742 {
XinZhangMS 0:f7f1f0d76dd6 743 instance->auth_state = AUTHENTICATION_STATE_STOPPED;
XinZhangMS 0:f7f1f0d76dd6 744 instance->msgr_state = TELEMETRY_MESSENGER_STATE_STOPPED;
XinZhangMS 0:f7f1f0d76dd6 745 instance->twin_msgr_state = TWIN_MESSENGER_STATE_STOPPED;
XinZhangMS 0:f7f1f0d76dd6 746 instance->state = DEVICE_STATE_STOPPED;
XinZhangMS 0:f7f1f0d76dd6 747 instance->auth_state_last_changed_time = INDEFINITE_TIME;
XinZhangMS 0:f7f1f0d76dd6 748 instance->auth_state_change_timeout_secs = DEFAULT_AUTH_STATE_CHANGED_TIMEOUT_SECS;
XinZhangMS 0:f7f1f0d76dd6 749 instance->msgr_state_last_changed_time = INDEFINITE_TIME;
XinZhangMS 0:f7f1f0d76dd6 750 instance->msgr_state_change_timeout_secs = DEFAULT_MSGR_STATE_CHANGED_TIMEOUT_SECS;
XinZhangMS 0:f7f1f0d76dd6 751 instance->twin_msgr_state_last_changed_time = INDEFINITE_TIME;
XinZhangMS 0:f7f1f0d76dd6 752 instance->twin_msgr_state_change_timeout_secs = DEFAULT_MSGR_STATE_CHANGED_TIMEOUT_SECS;
XinZhangMS 0:f7f1f0d76dd6 753
XinZhangMS 0:f7f1f0d76dd6 754 result = RESULT_OK;
XinZhangMS 0:f7f1f0d76dd6 755 }
XinZhangMS 0:f7f1f0d76dd6 756
XinZhangMS 0:f7f1f0d76dd6 757 if (result != RESULT_OK)
XinZhangMS 0:f7f1f0d76dd6 758 {
XinZhangMS 0:f7f1f0d76dd6 759 // Codes_SRS_DEVICE_09_010: [If device_create fails it shall release all memory it has allocated]
XinZhangMS 0:f7f1f0d76dd6 760 internal_destroy_device(instance);
XinZhangMS 0:f7f1f0d76dd6 761 instance = NULL;
XinZhangMS 0:f7f1f0d76dd6 762 }
XinZhangMS 0:f7f1f0d76dd6 763 }
XinZhangMS 0:f7f1f0d76dd6 764
XinZhangMS 0:f7f1f0d76dd6 765 // Codes_SRS_DEVICE_09_011: [If device_create succeeds it shall return a handle to its `instance` structure]
XinZhangMS 0:f7f1f0d76dd6 766 return (AMQP_DEVICE_HANDLE)instance;
XinZhangMS 0:f7f1f0d76dd6 767 }
XinZhangMS 0:f7f1f0d76dd6 768
XinZhangMS 0:f7f1f0d76dd6 769 int device_start_async(AMQP_DEVICE_HANDLE handle, SESSION_HANDLE session_handle, CBS_HANDLE cbs_handle)
XinZhangMS 0:f7f1f0d76dd6 770 {
XinZhangMS 0:f7f1f0d76dd6 771 int result;
XinZhangMS 0:f7f1f0d76dd6 772
XinZhangMS 0:f7f1f0d76dd6 773 // Codes_SRS_DEVICE_09_017: [If `handle` is NULL, device_start_async shall return a non-zero result]
XinZhangMS 0:f7f1f0d76dd6 774 if (handle == NULL)
XinZhangMS 0:f7f1f0d76dd6 775 {
XinZhangMS 0:f7f1f0d76dd6 776 LogError("Failed starting device (handle is NULL)");
XinZhangMS 0:f7f1f0d76dd6 777 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 778 }
XinZhangMS 0:f7f1f0d76dd6 779 else
XinZhangMS 0:f7f1f0d76dd6 780 {
XinZhangMS 0:f7f1f0d76dd6 781 AMQP_DEVICE_INSTANCE* instance = (AMQP_DEVICE_INSTANCE*)handle;
XinZhangMS 0:f7f1f0d76dd6 782
XinZhangMS 0:f7f1f0d76dd6 783 // Codes_SRS_DEVICE_09_018: [If the device state is not DEVICE_STATE_STOPPED, device_start_async shall return a non-zero result]
XinZhangMS 0:f7f1f0d76dd6 784 if (instance->state != DEVICE_STATE_STOPPED)
XinZhangMS 0:f7f1f0d76dd6 785 {
XinZhangMS 0:f7f1f0d76dd6 786 LogError("Failed starting device (device is not stopped)");
XinZhangMS 0:f7f1f0d76dd6 787 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 788 }
XinZhangMS 0:f7f1f0d76dd6 789 // Codes_SRS_DEVICE_09_019: [If `session_handle` is NULL, device_start_async shall return a non-zero result]
XinZhangMS 0:f7f1f0d76dd6 790 else if (session_handle == NULL)
XinZhangMS 0:f7f1f0d76dd6 791 {
XinZhangMS 0:f7f1f0d76dd6 792 LogError("Failed starting device (session_handle is NULL)");
XinZhangMS 0:f7f1f0d76dd6 793 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 794 }
XinZhangMS 0:f7f1f0d76dd6 795 // Codes_SRS_DEVICE_09_020: [If using CBS authentication and `cbs_handle` is NULL, device_start_async shall return a non-zero result]
XinZhangMS 0:f7f1f0d76dd6 796 else if (instance->config->authentication_mode == DEVICE_AUTH_MODE_CBS && cbs_handle == NULL)
XinZhangMS 0:f7f1f0d76dd6 797 {
XinZhangMS 0:f7f1f0d76dd6 798 LogError("Failed starting device (device using CBS authentication, but cbs_handle is NULL)");
XinZhangMS 0:f7f1f0d76dd6 799 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 800 }
XinZhangMS 0:f7f1f0d76dd6 801 else
XinZhangMS 0:f7f1f0d76dd6 802 {
XinZhangMS 0:f7f1f0d76dd6 803 // Codes_SRS_DEVICE_09_021: [`session_handle` and `cbs_handle` shall be saved into the `instance`]
XinZhangMS 0:f7f1f0d76dd6 804 instance->session_handle = session_handle;
XinZhangMS 0:f7f1f0d76dd6 805 instance->cbs_handle = cbs_handle;
XinZhangMS 0:f7f1f0d76dd6 806
XinZhangMS 0:f7f1f0d76dd6 807 // Codes_SRS_DEVICE_09_022: [The device state shall be updated to DEVICE_STATE_STARTING, and state changed callback invoked]
XinZhangMS 0:f7f1f0d76dd6 808 update_state(instance, DEVICE_STATE_STARTING);
XinZhangMS 0:f7f1f0d76dd6 809
XinZhangMS 0:f7f1f0d76dd6 810 // Codes_SRS_DEVICE_09_023: [If no failures occur, device_start_async shall return 0]
XinZhangMS 0:f7f1f0d76dd6 811 result = RESULT_OK;
XinZhangMS 0:f7f1f0d76dd6 812 }
XinZhangMS 0:f7f1f0d76dd6 813 }
XinZhangMS 0:f7f1f0d76dd6 814
XinZhangMS 0:f7f1f0d76dd6 815 return result;
XinZhangMS 0:f7f1f0d76dd6 816 }
XinZhangMS 0:f7f1f0d76dd6 817
XinZhangMS 0:f7f1f0d76dd6 818 // @brief
XinZhangMS 0:f7f1f0d76dd6 819 // stops a device instance (stops messenger and authentication) synchronously.
XinZhangMS 0:f7f1f0d76dd6 820 // @returns
XinZhangMS 0:f7f1f0d76dd6 821 // 0 if the function succeeds, non-zero otherwise.
XinZhangMS 0:f7f1f0d76dd6 822 int device_stop(AMQP_DEVICE_HANDLE handle)
XinZhangMS 0:f7f1f0d76dd6 823 {
XinZhangMS 0:f7f1f0d76dd6 824 int result;
XinZhangMS 0:f7f1f0d76dd6 825
XinZhangMS 0:f7f1f0d76dd6 826 // Codes_SRS_DEVICE_09_024: [If `handle` is NULL, device_stop shall return a non-zero result]
XinZhangMS 0:f7f1f0d76dd6 827 if (handle == NULL)
XinZhangMS 0:f7f1f0d76dd6 828 {
XinZhangMS 0:f7f1f0d76dd6 829 LogError("Failed stopping device (handle is NULL)");
XinZhangMS 0:f7f1f0d76dd6 830 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 831 }
XinZhangMS 0:f7f1f0d76dd6 832 else
XinZhangMS 0:f7f1f0d76dd6 833 {
XinZhangMS 0:f7f1f0d76dd6 834 AMQP_DEVICE_INSTANCE* instance = (AMQP_DEVICE_INSTANCE*)handle;
XinZhangMS 0:f7f1f0d76dd6 835
XinZhangMS 0:f7f1f0d76dd6 836 // Codes_SRS_DEVICE_09_025: [If the device state is already DEVICE_STATE_STOPPED or DEVICE_STATE_STOPPING, device_stop shall return a non-zero result]
XinZhangMS 0:f7f1f0d76dd6 837 if (instance->state == DEVICE_STATE_STOPPED || instance->state == DEVICE_STATE_STOPPING)
XinZhangMS 0:f7f1f0d76dd6 838 {
XinZhangMS 0:f7f1f0d76dd6 839 LogError("Failed stopping device '%s' (device is already stopped or stopping)", instance->config->device_id);
XinZhangMS 0:f7f1f0d76dd6 840 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 841 }
XinZhangMS 0:f7f1f0d76dd6 842 else
XinZhangMS 0:f7f1f0d76dd6 843 {
XinZhangMS 0:f7f1f0d76dd6 844 // Codes_SRS_DEVICE_09_026: [The device state shall be updated to DEVICE_STATE_STOPPING, and state changed callback invoked]
XinZhangMS 0:f7f1f0d76dd6 845 update_state(instance, DEVICE_STATE_STOPPING);
XinZhangMS 0:f7f1f0d76dd6 846
XinZhangMS 0:f7f1f0d76dd6 847 // Codes_SRS_DEVICE_09_027: [If `instance->messenger_handle` state is not TELEMETRY_MESSENGER_STATE_STOPPED, messenger_stop shall be invoked]
XinZhangMS 0:f7f1f0d76dd6 848 if (instance->msgr_state != TELEMETRY_MESSENGER_STATE_STOPPED &&
XinZhangMS 0:f7f1f0d76dd6 849 instance->msgr_state != TELEMETRY_MESSENGER_STATE_STOPPING &&
XinZhangMS 0:f7f1f0d76dd6 850 telemetry_messenger_stop(instance->messenger_handle) != RESULT_OK)
XinZhangMS 0:f7f1f0d76dd6 851 {
XinZhangMS 0:f7f1f0d76dd6 852 // Codes_SRS_DEVICE_09_028: [If messenger_stop fails, the `instance` state shall be updated to DEVICE_STATE_ERROR_MSG and the function shall return non-zero result]
XinZhangMS 0:f7f1f0d76dd6 853 LogError("Failed stopping device '%s' (telemetry_messenger_stop failed)", instance->config->device_id);
XinZhangMS 0:f7f1f0d76dd6 854 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 855 update_state(instance, DEVICE_STATE_ERROR_MSG);
XinZhangMS 0:f7f1f0d76dd6 856 }
XinZhangMS 0:f7f1f0d76dd6 857 // Codes_SRS_DEVICE_09_131: [If `instance->twin_messenger_handle` state is not TWIN_MESSENGER_STATE_STOPPED, twin_messenger_stop shall be invoked]
XinZhangMS 0:f7f1f0d76dd6 858 else if (instance->twin_msgr_state != TWIN_MESSENGER_STATE_STOPPED &&
XinZhangMS 0:f7f1f0d76dd6 859 instance->twin_msgr_state != TWIN_MESSENGER_STATE_STOPPING &&
XinZhangMS 0:f7f1f0d76dd6 860 twin_messenger_stop(instance->twin_messenger_handle) != RESULT_OK)
XinZhangMS 0:f7f1f0d76dd6 861 {
XinZhangMS 0:f7f1f0d76dd6 862 // Codes_SRS_DEVICE_09_132: [If twin_messenger_stop fails, the `instance` state shall be updated to DEVICE_STATE_ERROR_MSG and the function shall return non-zero result]
XinZhangMS 0:f7f1f0d76dd6 863 LogError("Failed stopping device '%s' (twin_messenger_stop failed)", instance->config->device_id);
XinZhangMS 0:f7f1f0d76dd6 864 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 865 update_state(instance, DEVICE_STATE_ERROR_MSG);
XinZhangMS 0:f7f1f0d76dd6 866 }
XinZhangMS 0:f7f1f0d76dd6 867 // Codes_SRS_DEVICE_09_029: [If CBS authentication is used, if `instance->authentication_handle` state is not AUTHENTICATION_STATE_STOPPED, authentication_stop shall be invoked]
XinZhangMS 0:f7f1f0d76dd6 868 else if (instance->config->authentication_mode == DEVICE_AUTH_MODE_CBS &&
XinZhangMS 0:f7f1f0d76dd6 869 instance->auth_state != AUTHENTICATION_STATE_STOPPED &&
XinZhangMS 0:f7f1f0d76dd6 870 authentication_stop(instance->authentication_handle) != RESULT_OK)
XinZhangMS 0:f7f1f0d76dd6 871 {
XinZhangMS 0:f7f1f0d76dd6 872 // Codes_SRS_DEVICE_09_030: [If authentication_stop fails, the `instance` state shall be updated to DEVICE_STATE_ERROR_AUTH and the function shall return non-zero result]
XinZhangMS 0:f7f1f0d76dd6 873 LogError("Failed stopping device '%s' (authentication_stop failed)", instance->config->device_id);
XinZhangMS 0:f7f1f0d76dd6 874 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 875 update_state(instance, DEVICE_STATE_ERROR_AUTH);
XinZhangMS 0:f7f1f0d76dd6 876 }
XinZhangMS 0:f7f1f0d76dd6 877 else
XinZhangMS 0:f7f1f0d76dd6 878 {
XinZhangMS 0:f7f1f0d76dd6 879 // Codes_SRS_DEVICE_09_031: [The device state shall be updated to DEVICE_STATE_STOPPED, and state changed callback invoked]
XinZhangMS 0:f7f1f0d76dd6 880 update_state(instance, DEVICE_STATE_STOPPED);
XinZhangMS 0:f7f1f0d76dd6 881
XinZhangMS 0:f7f1f0d76dd6 882 // Codes_SRS_DEVICE_09_032: [If no failures occur, device_stop shall return 0]
XinZhangMS 0:f7f1f0d76dd6 883 result = RESULT_OK;
XinZhangMS 0:f7f1f0d76dd6 884 }
XinZhangMS 0:f7f1f0d76dd6 885 }
XinZhangMS 0:f7f1f0d76dd6 886 }
XinZhangMS 0:f7f1f0d76dd6 887
XinZhangMS 0:f7f1f0d76dd6 888 return result;
XinZhangMS 0:f7f1f0d76dd6 889 }
XinZhangMS 0:f7f1f0d76dd6 890
XinZhangMS 0:f7f1f0d76dd6 891 void device_do_work(AMQP_DEVICE_HANDLE handle)
XinZhangMS 0:f7f1f0d76dd6 892 {
XinZhangMS 0:f7f1f0d76dd6 893 // Codes_SRS_DEVICE_09_033: [If `handle` is NULL, device_do_work shall return]
XinZhangMS 0:f7f1f0d76dd6 894 if (handle == NULL)
XinZhangMS 0:f7f1f0d76dd6 895 {
XinZhangMS 0:f7f1f0d76dd6 896 LogError("Failed to perform device_do_work (handle is NULL)");
XinZhangMS 0:f7f1f0d76dd6 897 }
XinZhangMS 0:f7f1f0d76dd6 898 else
XinZhangMS 0:f7f1f0d76dd6 899 {
XinZhangMS 0:f7f1f0d76dd6 900 // Cranking the state monster:
XinZhangMS 0:f7f1f0d76dd6 901 AMQP_DEVICE_INSTANCE* instance = (AMQP_DEVICE_INSTANCE*)handle;
XinZhangMS 0:f7f1f0d76dd6 902
XinZhangMS 0:f7f1f0d76dd6 903 if (instance->state == DEVICE_STATE_STARTING)
XinZhangMS 0:f7f1f0d76dd6 904 {
XinZhangMS 0:f7f1f0d76dd6 905 // Codes_SRS_DEVICE_09_034: [If CBS authentication is used and authentication state is AUTHENTICATION_STATE_STOPPED, authentication_start shall be invoked]
XinZhangMS 0:f7f1f0d76dd6 906 if (instance->config->authentication_mode == DEVICE_AUTH_MODE_CBS)
XinZhangMS 0:f7f1f0d76dd6 907 {
XinZhangMS 0:f7f1f0d76dd6 908 if (instance->auth_state == AUTHENTICATION_STATE_STOPPED)
XinZhangMS 0:f7f1f0d76dd6 909 {
XinZhangMS 0:f7f1f0d76dd6 910 if (authentication_start(instance->authentication_handle, instance->cbs_handle) != RESULT_OK)
XinZhangMS 0:f7f1f0d76dd6 911 {
XinZhangMS 0:f7f1f0d76dd6 912 // Codes_SRS_DEVICE_09_035: [If authentication_start fails, the device state shall be updated to DEVICE_STATE_ERROR_AUTH]
XinZhangMS 0:f7f1f0d76dd6 913 LogError("Device '%s' failed to be authenticated (authentication_start failed)", instance->config->device_id);
XinZhangMS 0:f7f1f0d76dd6 914
XinZhangMS 0:f7f1f0d76dd6 915 update_state(instance, DEVICE_STATE_ERROR_AUTH);
XinZhangMS 0:f7f1f0d76dd6 916 }
XinZhangMS 0:f7f1f0d76dd6 917 }
XinZhangMS 0:f7f1f0d76dd6 918 // Codes_SRS_DEVICE_09_036: [If authentication state is AUTHENTICATION_STATE_STARTING, the device shall track the time since last event change and timeout if needed]
XinZhangMS 0:f7f1f0d76dd6 919 else if (instance->auth_state == AUTHENTICATION_STATE_STARTING)
XinZhangMS 0:f7f1f0d76dd6 920 {
XinZhangMS 0:f7f1f0d76dd6 921 int is_timed_out;
XinZhangMS 0:f7f1f0d76dd6 922 if (is_timeout_reached(instance->auth_state_last_changed_time, instance->auth_state_change_timeout_secs, &is_timed_out) != RESULT_OK)
XinZhangMS 0:f7f1f0d76dd6 923 {
XinZhangMS 0:f7f1f0d76dd6 924 LogError("Device '%s' failed verifying the timeout for authentication start (is_timeout_reached failed)", instance->config->device_id);
XinZhangMS 0:f7f1f0d76dd6 925 update_state(instance, DEVICE_STATE_ERROR_AUTH);
XinZhangMS 0:f7f1f0d76dd6 926 }
XinZhangMS 0:f7f1f0d76dd6 927 // Codes_SRS_DEVICE_09_037: [If authentication_start times out, the device state shall be updated to DEVICE_STATE_ERROR_AUTH_TIMEOUT]
XinZhangMS 0:f7f1f0d76dd6 928 else if (is_timed_out == 1)
XinZhangMS 0:f7f1f0d76dd6 929 {
XinZhangMS 0:f7f1f0d76dd6 930 LogError("Device '%s' authentication did not complete starting within expected timeout (%d)", instance->config->device_id, instance->auth_state_change_timeout_secs);
XinZhangMS 0:f7f1f0d76dd6 931
XinZhangMS 0:f7f1f0d76dd6 932 update_state(instance, DEVICE_STATE_ERROR_AUTH_TIMEOUT);
XinZhangMS 0:f7f1f0d76dd6 933 }
XinZhangMS 0:f7f1f0d76dd6 934 }
XinZhangMS 0:f7f1f0d76dd6 935 else if (instance->auth_state == AUTHENTICATION_STATE_ERROR)
XinZhangMS 0:f7f1f0d76dd6 936 {
XinZhangMS 0:f7f1f0d76dd6 937 // Codes_SRS_DEVICE_09_038: [If authentication state is AUTHENTICATION_STATE_ERROR and error code is AUTH_FAILED, the device state shall be updated to DEVICE_STATE_ERROR_AUTH]
XinZhangMS 0:f7f1f0d76dd6 938 if (instance->auth_error_code == AUTHENTICATION_ERROR_AUTH_FAILED)
XinZhangMS 0:f7f1f0d76dd6 939 {
XinZhangMS 0:f7f1f0d76dd6 940 update_state(instance, DEVICE_STATE_ERROR_AUTH);
XinZhangMS 0:f7f1f0d76dd6 941 }
XinZhangMS 0:f7f1f0d76dd6 942 // Codes_SRS_DEVICE_09_039: [If authentication state is AUTHENTICATION_STATE_ERROR and error code is TIMEOUT, the device state shall be updated to DEVICE_STATE_ERROR_AUTH_TIMEOUT]
XinZhangMS 0:f7f1f0d76dd6 943 else // DEVICE_STATE_ERROR_TIMEOUT
XinZhangMS 0:f7f1f0d76dd6 944 {
XinZhangMS 0:f7f1f0d76dd6 945 update_state(instance, DEVICE_STATE_ERROR_AUTH_TIMEOUT);
XinZhangMS 0:f7f1f0d76dd6 946 }
XinZhangMS 0:f7f1f0d76dd6 947 }
XinZhangMS 0:f7f1f0d76dd6 948 // There is no AUTHENTICATION_STATE_STOPPING
XinZhangMS 0:f7f1f0d76dd6 949 }
XinZhangMS 0:f7f1f0d76dd6 950
XinZhangMS 0:f7f1f0d76dd6 951 // Codes_SRS_DEVICE_09_040: [Messenger shall not be started if using CBS authentication and authentication start has not completed yet]
XinZhangMS 0:f7f1f0d76dd6 952 // Codes_SRS_DEVICE_09_124: [TWIN Messenger shall not be started if using CBS authentication and authentication start has not completed yet]
XinZhangMS 0:f7f1f0d76dd6 953 if (instance->config->authentication_mode == DEVICE_AUTH_MODE_X509 || instance->auth_state == AUTHENTICATION_STATE_STARTED)
XinZhangMS 0:f7f1f0d76dd6 954 {
XinZhangMS 0:f7f1f0d76dd6 955 size_t number_of_messengers_started = 0;
XinZhangMS 0:f7f1f0d76dd6 956
XinZhangMS 0:f7f1f0d76dd6 957 // Codes_SRS_DEVICE_09_041: [If messenger state is TELEMETRY_MESSENGER_STATE_STOPPED, messenger_start shall be invoked]
XinZhangMS 0:f7f1f0d76dd6 958 if (instance->msgr_state == TELEMETRY_MESSENGER_STATE_STOPPED)
XinZhangMS 0:f7f1f0d76dd6 959 {
XinZhangMS 0:f7f1f0d76dd6 960 // Codes_SRS_DEVICE_09_042: [If messenger_start fails, the device state shall be updated to DEVICE_STATE_ERROR_MSG]
XinZhangMS 0:f7f1f0d76dd6 961 if (telemetry_messenger_start(instance->messenger_handle, instance->session_handle) != RESULT_OK)
XinZhangMS 0:f7f1f0d76dd6 962 {
XinZhangMS 0:f7f1f0d76dd6 963 LogError("Device '%s' messenger failed to be started (messenger_start failed)", instance->config->device_id);
XinZhangMS 0:f7f1f0d76dd6 964
XinZhangMS 0:f7f1f0d76dd6 965 update_state(instance, DEVICE_STATE_ERROR_MSG);
XinZhangMS 0:f7f1f0d76dd6 966 }
XinZhangMS 0:f7f1f0d76dd6 967 }
XinZhangMS 0:f7f1f0d76dd6 968 // Codes_SRS_DEVICE_09_043: [If messenger state is TELEMETRY_MESSENGER_STATE_STARTING, the device shall track the time since last event change and timeout if needed]
XinZhangMS 0:f7f1f0d76dd6 969 else if (instance->msgr_state == TELEMETRY_MESSENGER_STATE_STARTING)
XinZhangMS 0:f7f1f0d76dd6 970 {
XinZhangMS 0:f7f1f0d76dd6 971 int is_timed_out;
XinZhangMS 0:f7f1f0d76dd6 972 if (is_timeout_reached(instance->msgr_state_last_changed_time, instance->msgr_state_change_timeout_secs, &is_timed_out) != RESULT_OK)
XinZhangMS 0:f7f1f0d76dd6 973 {
XinZhangMS 0:f7f1f0d76dd6 974 LogError("Device '%s' failed verifying the timeout for messenger start (is_timeout_reached failed)", instance->config->device_id);
XinZhangMS 0:f7f1f0d76dd6 975
XinZhangMS 0:f7f1f0d76dd6 976 update_state(instance, DEVICE_STATE_ERROR_MSG);
XinZhangMS 0:f7f1f0d76dd6 977 }
XinZhangMS 0:f7f1f0d76dd6 978 // Codes_SRS_DEVICE_09_044: [If messenger_start times out, the device state shall be updated to DEVICE_STATE_ERROR_MSG]
XinZhangMS 0:f7f1f0d76dd6 979 else if (is_timed_out == 1)
XinZhangMS 0:f7f1f0d76dd6 980 {
XinZhangMS 0:f7f1f0d76dd6 981 LogError("Device '%s' messenger did not complete starting within expected timeout (%d)", instance->config->device_id, instance->msgr_state_change_timeout_secs);
XinZhangMS 0:f7f1f0d76dd6 982
XinZhangMS 0:f7f1f0d76dd6 983 update_state(instance, DEVICE_STATE_ERROR_MSG);
XinZhangMS 0:f7f1f0d76dd6 984 }
XinZhangMS 0:f7f1f0d76dd6 985 }
XinZhangMS 0:f7f1f0d76dd6 986 // Codes_SRS_DEVICE_09_045: [If messenger state is TELEMETRY_MESSENGER_STATE_ERROR, the device state shall be updated to DEVICE_STATE_ERROR_MSG]
XinZhangMS 0:f7f1f0d76dd6 987 else if (instance->msgr_state == TELEMETRY_MESSENGER_STATE_ERROR)
XinZhangMS 0:f7f1f0d76dd6 988 {
XinZhangMS 0:f7f1f0d76dd6 989 LogError("Device '%s' messenger failed to be started (messenger got into error state)", instance->config->device_id);
XinZhangMS 0:f7f1f0d76dd6 990
XinZhangMS 0:f7f1f0d76dd6 991 update_state(instance, DEVICE_STATE_ERROR_MSG);
XinZhangMS 0:f7f1f0d76dd6 992 }
XinZhangMS 0:f7f1f0d76dd6 993 // Codes_SRS_DEVICE_09_046: [If messenger state is TELEMETRY_MESSENGER_STATE_STARTED, the device state shall be updated to DEVICE_STATE_STARTED]
XinZhangMS 0:f7f1f0d76dd6 994 else if (instance->msgr_state == TELEMETRY_MESSENGER_STATE_STARTED)
XinZhangMS 0:f7f1f0d76dd6 995 {
XinZhangMS 0:f7f1f0d76dd6 996 number_of_messengers_started++;
XinZhangMS 0:f7f1f0d76dd6 997 }
XinZhangMS 0:f7f1f0d76dd6 998
XinZhangMS 0:f7f1f0d76dd6 999 // Codes_SRS_DEVICE_09_125: [If TWIN messenger state is TWIN_MESSENGER_STATE_STOPPED, twin_messenger_start shall be invoked]
XinZhangMS 0:f7f1f0d76dd6 1000 if (instance->twin_msgr_state == TWIN_MESSENGER_STATE_STOPPED)
XinZhangMS 0:f7f1f0d76dd6 1001 {
XinZhangMS 0:f7f1f0d76dd6 1002 if (twin_messenger_start(instance->twin_messenger_handle, instance->session_handle) != RESULT_OK)
XinZhangMS 0:f7f1f0d76dd6 1003 {
XinZhangMS 0:f7f1f0d76dd6 1004 // Codes_SRS_DEVICE_09_126: [If twin_messenger_start fails, the device state shall be updated to DEVICE_STATE_ERROR_MSG]
XinZhangMS 0:f7f1f0d76dd6 1005 LogError("Device '%s' twin messenger failed to be started (messenger_start failed)", instance->config->device_id);
XinZhangMS 0:f7f1f0d76dd6 1006
XinZhangMS 0:f7f1f0d76dd6 1007 update_state(instance, DEVICE_STATE_ERROR_MSG);
XinZhangMS 0:f7f1f0d76dd6 1008 }
XinZhangMS 0:f7f1f0d76dd6 1009 }
XinZhangMS 0:f7f1f0d76dd6 1010 else if (instance->twin_msgr_state == TWIN_MESSENGER_STATE_STARTING)
XinZhangMS 0:f7f1f0d76dd6 1011 {
XinZhangMS 0:f7f1f0d76dd6 1012 int is_timed_out;
XinZhangMS 0:f7f1f0d76dd6 1013 if (is_timeout_reached(instance->twin_msgr_state_last_changed_time, instance->twin_msgr_state_change_timeout_secs, &is_timed_out) != RESULT_OK)
XinZhangMS 0:f7f1f0d76dd6 1014 {
XinZhangMS 0:f7f1f0d76dd6 1015 LogError("Device '%s' failed verifying the timeout for twin messenger start (is_timeout_reached failed)", instance->config->device_id);
XinZhangMS 0:f7f1f0d76dd6 1016
XinZhangMS 0:f7f1f0d76dd6 1017 update_state(instance, DEVICE_STATE_ERROR_MSG);
XinZhangMS 0:f7f1f0d76dd6 1018 }
XinZhangMS 0:f7f1f0d76dd6 1019 // Codes_SRS_DEVICE_09_127: [If TWIN messenger state is TWIN_MESSENGER_STATE_STARTING, the device shall track the time since last event change and timeout if needed]
XinZhangMS 0:f7f1f0d76dd6 1020 else if (is_timed_out == 1)
XinZhangMS 0:f7f1f0d76dd6 1021 {
XinZhangMS 0:f7f1f0d76dd6 1022 // Codes_SRS_DEVICE_09_128: [If twin_messenger_start times out, the device state shall be updated to DEVICE_STATE_ERROR_MSG]
XinZhangMS 0:f7f1f0d76dd6 1023 LogError("Device '%s' twin messenger did not complete starting within expected timeout (%d)", instance->config->device_id, instance->twin_msgr_state_change_timeout_secs);
XinZhangMS 0:f7f1f0d76dd6 1024
XinZhangMS 0:f7f1f0d76dd6 1025 update_state(instance, DEVICE_STATE_ERROR_MSG);
XinZhangMS 0:f7f1f0d76dd6 1026 }
XinZhangMS 0:f7f1f0d76dd6 1027 }
XinZhangMS 0:f7f1f0d76dd6 1028 // Codes_SRS_DEVICE_09_129: [If TWIN messenger state is TWIN_MESSENGER_STATE_ERROR, the device state shall be updated to DEVICE_STATE_ERROR_MSG]
XinZhangMS 0:f7f1f0d76dd6 1029 else if (instance->twin_msgr_state == TWIN_MESSENGER_STATE_ERROR)
XinZhangMS 0:f7f1f0d76dd6 1030 {
XinZhangMS 0:f7f1f0d76dd6 1031 LogError("Device '%s' twin messenger failed to be started (messenger got into error state)", instance->config->device_id);
XinZhangMS 0:f7f1f0d76dd6 1032
XinZhangMS 0:f7f1f0d76dd6 1033 update_state(instance, DEVICE_STATE_ERROR_MSG);
XinZhangMS 0:f7f1f0d76dd6 1034 }
XinZhangMS 0:f7f1f0d76dd6 1035 // Codes_SRS_DEVICE_09_130: [If TWIN messenger state is TWIN_MESSENGER_STATE_STARTED, the device state shall be updated to DEVICE_STATE_STARTED]
XinZhangMS 0:f7f1f0d76dd6 1036 else if (instance->twin_msgr_state == TWIN_MESSENGER_STATE_STARTED)
XinZhangMS 0:f7f1f0d76dd6 1037 {
XinZhangMS 0:f7f1f0d76dd6 1038 number_of_messengers_started++;
XinZhangMS 0:f7f1f0d76dd6 1039 }
XinZhangMS 0:f7f1f0d76dd6 1040
XinZhangMS 0:f7f1f0d76dd6 1041 if (number_of_messengers_started == 2)
XinZhangMS 0:f7f1f0d76dd6 1042 {
XinZhangMS 0:f7f1f0d76dd6 1043 update_state(instance, DEVICE_STATE_STARTED);
XinZhangMS 0:f7f1f0d76dd6 1044 }
XinZhangMS 0:f7f1f0d76dd6 1045 }
XinZhangMS 0:f7f1f0d76dd6 1046 }
XinZhangMS 0:f7f1f0d76dd6 1047 else if (instance->state == DEVICE_STATE_STARTED)
XinZhangMS 0:f7f1f0d76dd6 1048 {
XinZhangMS 0:f7f1f0d76dd6 1049 // Codes_SRS_DEVICE_09_047: [If CBS authentication is used and authentication state is not AUTHENTICATION_STATE_STARTED, the device state shall be updated to DEVICE_STATE_ERROR_AUTH]
XinZhangMS 0:f7f1f0d76dd6 1050 if (instance->config->authentication_mode == DEVICE_AUTH_MODE_CBS &&
XinZhangMS 0:f7f1f0d76dd6 1051 instance->auth_state != AUTHENTICATION_STATE_STARTED)
XinZhangMS 0:f7f1f0d76dd6 1052 {
XinZhangMS 0:f7f1f0d76dd6 1053 LogError("Device '%s' is started but authentication reported unexpected state %d", instance->config->device_id, instance->auth_state);
XinZhangMS 0:f7f1f0d76dd6 1054
XinZhangMS 0:f7f1f0d76dd6 1055 if (instance->auth_state != AUTHENTICATION_STATE_ERROR)
XinZhangMS 0:f7f1f0d76dd6 1056 {
XinZhangMS 0:f7f1f0d76dd6 1057 if (instance->auth_error_code == AUTHENTICATION_ERROR_AUTH_FAILED)
XinZhangMS 0:f7f1f0d76dd6 1058 {
XinZhangMS 0:f7f1f0d76dd6 1059 update_state(instance, DEVICE_STATE_ERROR_AUTH);
XinZhangMS 0:f7f1f0d76dd6 1060 }
XinZhangMS 0:f7f1f0d76dd6 1061 else // AUTHENTICATION_ERROR_AUTH_TIMEOUT
XinZhangMS 0:f7f1f0d76dd6 1062 {
XinZhangMS 0:f7f1f0d76dd6 1063 update_state(instance, DEVICE_STATE_ERROR_AUTH_TIMEOUT);
XinZhangMS 0:f7f1f0d76dd6 1064 }
XinZhangMS 0:f7f1f0d76dd6 1065 }
XinZhangMS 0:f7f1f0d76dd6 1066 else
XinZhangMS 0:f7f1f0d76dd6 1067 {
XinZhangMS 0:f7f1f0d76dd6 1068 update_state(instance, DEVICE_STATE_ERROR_AUTH);
XinZhangMS 0:f7f1f0d76dd6 1069 }
XinZhangMS 0:f7f1f0d76dd6 1070 }
XinZhangMS 0:f7f1f0d76dd6 1071 else
XinZhangMS 0:f7f1f0d76dd6 1072 {
XinZhangMS 0:f7f1f0d76dd6 1073 // Codes_SRS_DEVICE_09_048: [If messenger state is not TELEMETRY_MESSENGER_STATE_STARTED, the device state shall be updated to DEVICE_STATE_ERROR_MSG]
XinZhangMS 0:f7f1f0d76dd6 1074 if (instance->msgr_state != TELEMETRY_MESSENGER_STATE_STARTED)
XinZhangMS 0:f7f1f0d76dd6 1075 {
XinZhangMS 0:f7f1f0d76dd6 1076 LogError("Device '%s' is started but messenger reported unexpected state %d", instance->config->device_id, instance->msgr_state);
XinZhangMS 0:f7f1f0d76dd6 1077 update_state(instance, DEVICE_STATE_ERROR_MSG);
XinZhangMS 0:f7f1f0d76dd6 1078 }
XinZhangMS 0:f7f1f0d76dd6 1079
XinZhangMS 0:f7f1f0d76dd6 1080 // Codes_SRS_DEVICE_09_133: [If TWIN messenger state is not TWIN_MESSENGER_STATE_STARTED, the device state shall be updated to DEVICE_STATE_ERROR_MSG]
XinZhangMS 0:f7f1f0d76dd6 1081 if (instance->twin_msgr_state != TWIN_MESSENGER_STATE_STARTED)
XinZhangMS 0:f7f1f0d76dd6 1082 {
XinZhangMS 0:f7f1f0d76dd6 1083 LogError("Device '%s' is started but TWIN messenger reported unexpected state %d", instance->config->device_id, instance->msgr_state);
XinZhangMS 0:f7f1f0d76dd6 1084 update_state(instance, DEVICE_STATE_ERROR_MSG);
XinZhangMS 0:f7f1f0d76dd6 1085 }
XinZhangMS 0:f7f1f0d76dd6 1086 }
XinZhangMS 0:f7f1f0d76dd6 1087 }
XinZhangMS 0:f7f1f0d76dd6 1088
XinZhangMS 0:f7f1f0d76dd6 1089 // Invoking the do_works():
XinZhangMS 0:f7f1f0d76dd6 1090 if (instance->config->authentication_mode == DEVICE_AUTH_MODE_CBS)
XinZhangMS 0:f7f1f0d76dd6 1091 {
XinZhangMS 0:f7f1f0d76dd6 1092 if (instance->auth_state != AUTHENTICATION_STATE_STOPPED && instance->auth_state != AUTHENTICATION_STATE_ERROR)
XinZhangMS 0:f7f1f0d76dd6 1093 {
XinZhangMS 0:f7f1f0d76dd6 1094 // Codes_SRS_DEVICE_09_049: [If CBS is used for authentication and `instance->authentication_handle` state is not STOPPED or ERROR, authentication_do_work shall be invoked]
XinZhangMS 0:f7f1f0d76dd6 1095 authentication_do_work(instance->authentication_handle);
XinZhangMS 0:f7f1f0d76dd6 1096 }
XinZhangMS 0:f7f1f0d76dd6 1097 }
XinZhangMS 0:f7f1f0d76dd6 1098
XinZhangMS 0:f7f1f0d76dd6 1099 if (instance->msgr_state != TELEMETRY_MESSENGER_STATE_STOPPED && instance->msgr_state != TELEMETRY_MESSENGER_STATE_ERROR)
XinZhangMS 0:f7f1f0d76dd6 1100 {
XinZhangMS 0:f7f1f0d76dd6 1101 // Codes_SRS_DEVICE_09_050: [If `instance->messenger_handle` state is not STOPPED or ERROR, telemetry_messenger_do_work shall be invoked]
XinZhangMS 0:f7f1f0d76dd6 1102 telemetry_messenger_do_work(instance->messenger_handle);
XinZhangMS 0:f7f1f0d76dd6 1103 }
XinZhangMS 0:f7f1f0d76dd6 1104
XinZhangMS 0:f7f1f0d76dd6 1105 if (instance->twin_msgr_state != TWIN_MESSENGER_STATE_STOPPED && instance->twin_msgr_state != TWIN_MESSENGER_STATE_ERROR)
XinZhangMS 0:f7f1f0d76dd6 1106 {
XinZhangMS 0:f7f1f0d76dd6 1107 // Codes_SRS_DEVICE_09_134: [If `instance->twin_messenger_handle` state is not STOPPED or ERROR, twin_messenger_do_work shall be invoked]
XinZhangMS 0:f7f1f0d76dd6 1108 twin_messenger_do_work(instance->twin_messenger_handle);
XinZhangMS 0:f7f1f0d76dd6 1109 }
XinZhangMS 0:f7f1f0d76dd6 1110 }
XinZhangMS 0:f7f1f0d76dd6 1111 }
XinZhangMS 0:f7f1f0d76dd6 1112
XinZhangMS 0:f7f1f0d76dd6 1113 void device_destroy(AMQP_DEVICE_HANDLE handle)
XinZhangMS 0:f7f1f0d76dd6 1114 {
XinZhangMS 0:f7f1f0d76dd6 1115 // Codes_SRS_DEVICE_09_012: [If `handle` is NULL, device_destroy shall return]
XinZhangMS 0:f7f1f0d76dd6 1116 if (handle == NULL)
XinZhangMS 0:f7f1f0d76dd6 1117 {
XinZhangMS 0:f7f1f0d76dd6 1118 LogError("Failed destroying device handle (handle is NULL)");
XinZhangMS 0:f7f1f0d76dd6 1119 }
XinZhangMS 0:f7f1f0d76dd6 1120 else
XinZhangMS 0:f7f1f0d76dd6 1121 {
XinZhangMS 0:f7f1f0d76dd6 1122 AMQP_DEVICE_INSTANCE* instance = (AMQP_DEVICE_INSTANCE*)handle;
XinZhangMS 0:f7f1f0d76dd6 1123 // Codes_SRS_DEVICE_09_013: [If the device is in state DEVICE_STATE_STARTED or DEVICE_STATE_STARTING, device_stop() shall be invoked]
XinZhangMS 0:f7f1f0d76dd6 1124 if (instance->state == DEVICE_STATE_STARTED || instance->state == DEVICE_STATE_STARTING)
XinZhangMS 0:f7f1f0d76dd6 1125 {
XinZhangMS 0:f7f1f0d76dd6 1126 (void)device_stop((AMQP_DEVICE_HANDLE)instance);
XinZhangMS 0:f7f1f0d76dd6 1127 }
XinZhangMS 0:f7f1f0d76dd6 1128
XinZhangMS 0:f7f1f0d76dd6 1129 // Codes_SRS_DEVICE_09_014: [`instance->messenger_handle shall be destroyed using telemetry_messenger_destroy()`]
XinZhangMS 0:f7f1f0d76dd6 1130 // Codes_SRS_DEVICE_09_015: [If created, `instance->authentication_handle` shall be destroyed using authentication_destroy()`]
XinZhangMS 0:f7f1f0d76dd6 1131 // Codes_SRS_DEVICE_09_016: [The contents of `instance->config` shall be detroyed and then it shall be freed]
XinZhangMS 0:f7f1f0d76dd6 1132 internal_destroy_device((AMQP_DEVICE_INSTANCE*)handle);
XinZhangMS 0:f7f1f0d76dd6 1133 }
XinZhangMS 0:f7f1f0d76dd6 1134 }
XinZhangMS 0:f7f1f0d76dd6 1135
XinZhangMS 0:f7f1f0d76dd6 1136 int device_send_event_async(AMQP_DEVICE_HANDLE handle, IOTHUB_MESSAGE_LIST* message, ON_DEVICE_D2C_EVENT_SEND_COMPLETE on_device_d2c_event_send_complete_callback, void* context)
XinZhangMS 0:f7f1f0d76dd6 1137 {
XinZhangMS 0:f7f1f0d76dd6 1138 int result;
XinZhangMS 0:f7f1f0d76dd6 1139
XinZhangMS 0:f7f1f0d76dd6 1140 // Codes_SRS_DEVICE_09_051: [If `handle` are `message` are NULL, device_send_event_async shall return a non-zero result]
XinZhangMS 0:f7f1f0d76dd6 1141 if (handle == NULL || message == NULL)
XinZhangMS 0:f7f1f0d76dd6 1142 {
XinZhangMS 0:f7f1f0d76dd6 1143 LogError("Failed sending event (either handle (%p) or message (%p) are NULL)", handle, message);
XinZhangMS 0:f7f1f0d76dd6 1144 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 1145 }
XinZhangMS 0:f7f1f0d76dd6 1146 else
XinZhangMS 0:f7f1f0d76dd6 1147 {
XinZhangMS 0:f7f1f0d76dd6 1148 DEVICE_SEND_EVENT_TASK* send_task;
XinZhangMS 0:f7f1f0d76dd6 1149
XinZhangMS 0:f7f1f0d76dd6 1150 // Codes_SRS_DEVICE_09_052: [A structure (`send_task`) shall be created to track the send state of the message]
XinZhangMS 0:f7f1f0d76dd6 1151 if ((send_task = (DEVICE_SEND_EVENT_TASK*)malloc(sizeof(DEVICE_SEND_EVENT_TASK))) == NULL)
XinZhangMS 0:f7f1f0d76dd6 1152 {
XinZhangMS 0:f7f1f0d76dd6 1153 // Codes_SRS_DEVICE_09_053: [If `send_task` fails to be created, device_send_event_async shall return a non-zero value]
XinZhangMS 0:f7f1f0d76dd6 1154 LogError("Failed sending event (failed creating task to send event)");
XinZhangMS 0:f7f1f0d76dd6 1155 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 1156 }
XinZhangMS 0:f7f1f0d76dd6 1157 else
XinZhangMS 0:f7f1f0d76dd6 1158 {
XinZhangMS 0:f7f1f0d76dd6 1159 AMQP_DEVICE_INSTANCE* instance = (AMQP_DEVICE_INSTANCE*)handle;
XinZhangMS 0:f7f1f0d76dd6 1160
XinZhangMS 0:f7f1f0d76dd6 1161 // Codes_SRS_DEVICE_09_054: [`send_task` shall contain the user callback and the context provided]
XinZhangMS 0:f7f1f0d76dd6 1162 memset(send_task, 0, sizeof(DEVICE_SEND_EVENT_TASK));
XinZhangMS 0:f7f1f0d76dd6 1163 send_task->on_event_send_complete_callback = on_device_d2c_event_send_complete_callback;
XinZhangMS 0:f7f1f0d76dd6 1164 send_task->on_event_send_complete_context = context;
XinZhangMS 0:f7f1f0d76dd6 1165
XinZhangMS 0:f7f1f0d76dd6 1166 // Codes_SRS_DEVICE_09_055: [The message shall be sent using telemetry_messenger_send_async, passing `on_event_send_complete_messenger_callback` and `send_task`]
XinZhangMS 0:f7f1f0d76dd6 1167 if (telemetry_messenger_send_async(instance->messenger_handle, message, on_event_send_complete_messenger_callback, (void*)send_task) != RESULT_OK)
XinZhangMS 0:f7f1f0d76dd6 1168 {
XinZhangMS 0:f7f1f0d76dd6 1169 // Codes_SRS_DEVICE_09_056: [If telemetry_messenger_send_async fails, device_send_event_async shall return a non-zero value]
XinZhangMS 0:f7f1f0d76dd6 1170 LogError("Failed sending event (telemetry_messenger_send_async failed)");
XinZhangMS 0:f7f1f0d76dd6 1171 // Codes_SRS_DEVICE_09_057: [If any failures occur, device_send_event_async shall release all memory it has allocated]
XinZhangMS 0:f7f1f0d76dd6 1172 free(send_task);
XinZhangMS 0:f7f1f0d76dd6 1173 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 1174 }
XinZhangMS 0:f7f1f0d76dd6 1175 else
XinZhangMS 0:f7f1f0d76dd6 1176 {
XinZhangMS 0:f7f1f0d76dd6 1177 // Codes_SRS_DEVICE_09_058: [If no failures occur, device_send_event_async shall return 0]
XinZhangMS 0:f7f1f0d76dd6 1178 result = RESULT_OK;
XinZhangMS 0:f7f1f0d76dd6 1179 }
XinZhangMS 0:f7f1f0d76dd6 1180 }
XinZhangMS 0:f7f1f0d76dd6 1181 }
XinZhangMS 0:f7f1f0d76dd6 1182
XinZhangMS 0:f7f1f0d76dd6 1183 return result;
XinZhangMS 0:f7f1f0d76dd6 1184 }
XinZhangMS 0:f7f1f0d76dd6 1185
XinZhangMS 0:f7f1f0d76dd6 1186 int device_get_send_status(AMQP_DEVICE_HANDLE handle, DEVICE_SEND_STATUS *send_status)
XinZhangMS 0:f7f1f0d76dd6 1187 {
XinZhangMS 0:f7f1f0d76dd6 1188 int result;
XinZhangMS 0:f7f1f0d76dd6 1189
XinZhangMS 0:f7f1f0d76dd6 1190
XinZhangMS 0:f7f1f0d76dd6 1191 // Codes_SRS_DEVICE_09_105: [If `handle` or `send_status` is NULL, device_get_send_status shall return a non-zero result]
XinZhangMS 0:f7f1f0d76dd6 1192 if (handle == NULL || send_status == NULL)
XinZhangMS 0:f7f1f0d76dd6 1193 {
XinZhangMS 0:f7f1f0d76dd6 1194 LogError("Failed getting the device messenger send status (NULL parameter received; handle=%p, send_status=%p)", handle, send_status);
XinZhangMS 0:f7f1f0d76dd6 1195 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 1196 }
XinZhangMS 0:f7f1f0d76dd6 1197 else
XinZhangMS 0:f7f1f0d76dd6 1198 {
XinZhangMS 0:f7f1f0d76dd6 1199 AMQP_DEVICE_INSTANCE* instance = (AMQP_DEVICE_INSTANCE*)handle;
XinZhangMS 0:f7f1f0d76dd6 1200 TELEMETRY_MESSENGER_SEND_STATUS messenger_send_status;
XinZhangMS 0:f7f1f0d76dd6 1201
XinZhangMS 0:f7f1f0d76dd6 1202 // Codes_SRS_DEVICE_09_106: [The status of `instance->messenger_handle` shall be obtained using telemetry_messenger_get_send_status]
XinZhangMS 0:f7f1f0d76dd6 1203 if (telemetry_messenger_get_send_status(instance->messenger_handle, &messenger_send_status) != RESULT_OK)
XinZhangMS 0:f7f1f0d76dd6 1204 {
XinZhangMS 0:f7f1f0d76dd6 1205 // Codes_SRS_DEVICE_09_107: [If telemetry_messenger_get_send_status fails, device_get_send_status shall return a non-zero result]
XinZhangMS 0:f7f1f0d76dd6 1206 LogError("Failed getting the device messenger send status (telemetry_messenger_get_send_status failed)");
XinZhangMS 0:f7f1f0d76dd6 1207 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 1208 }
XinZhangMS 0:f7f1f0d76dd6 1209 else
XinZhangMS 0:f7f1f0d76dd6 1210 {
XinZhangMS 0:f7f1f0d76dd6 1211 // Codes_SRS_DEVICE_09_108: [If telemetry_messenger_get_send_status returns TELEMETRY_MESSENGER_SEND_STATUS_IDLE, device_get_send_status return status DEVICE_SEND_STATUS_IDLE]
XinZhangMS 0:f7f1f0d76dd6 1212 if (messenger_send_status == TELEMETRY_MESSENGER_SEND_STATUS_IDLE)
XinZhangMS 0:f7f1f0d76dd6 1213 {
XinZhangMS 0:f7f1f0d76dd6 1214 *send_status = DEVICE_SEND_STATUS_IDLE;
XinZhangMS 0:f7f1f0d76dd6 1215 }
XinZhangMS 0:f7f1f0d76dd6 1216 // Codes_SRS_DEVICE_09_109: [If telemetry_messenger_get_send_status returns TELEMETRY_MESSENGER_SEND_STATUS_BUSY, device_get_send_status return status DEVICE_SEND_STATUS_BUSY]
XinZhangMS 0:f7f1f0d76dd6 1217 else // i.e., messenger_send_status == TELEMETRY_MESSENGER_SEND_STATUS_BUSY
XinZhangMS 0:f7f1f0d76dd6 1218 {
XinZhangMS 0:f7f1f0d76dd6 1219 *send_status = DEVICE_SEND_STATUS_BUSY;
XinZhangMS 0:f7f1f0d76dd6 1220 }
XinZhangMS 0:f7f1f0d76dd6 1221
XinZhangMS 0:f7f1f0d76dd6 1222 // Codes_SRS_DEVICE_09_110: [If device_get_send_status succeeds, it shall return zero as result]
XinZhangMS 0:f7f1f0d76dd6 1223 result = RESULT_OK;
XinZhangMS 0:f7f1f0d76dd6 1224 }
XinZhangMS 0:f7f1f0d76dd6 1225 }
XinZhangMS 0:f7f1f0d76dd6 1226
XinZhangMS 0:f7f1f0d76dd6 1227 return result;
XinZhangMS 0:f7f1f0d76dd6 1228 }
XinZhangMS 0:f7f1f0d76dd6 1229
XinZhangMS 0:f7f1f0d76dd6 1230 int device_subscribe_message(AMQP_DEVICE_HANDLE handle, ON_DEVICE_C2D_MESSAGE_RECEIVED on_message_received_callback, void* context)
XinZhangMS 0:f7f1f0d76dd6 1231 {
XinZhangMS 0:f7f1f0d76dd6 1232 int result;
XinZhangMS 0:f7f1f0d76dd6 1233
XinZhangMS 0:f7f1f0d76dd6 1234 // Codes_SRS_DEVICE_09_066: [If `handle` or `on_message_received_callback` or `context` is NULL, device_subscribe_message shall return a non-zero result]
XinZhangMS 0:f7f1f0d76dd6 1235 if (handle == NULL || on_message_received_callback == NULL || context == NULL)
XinZhangMS 0:f7f1f0d76dd6 1236 {
XinZhangMS 0:f7f1f0d76dd6 1237 LogError("Failed subscribing to C2D messages (either handle (%p), on_message_received_callback (%p) or context (%p) is NULL)",
XinZhangMS 0:f7f1f0d76dd6 1238 handle, on_message_received_callback, context);
XinZhangMS 0:f7f1f0d76dd6 1239 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 1240 }
XinZhangMS 0:f7f1f0d76dd6 1241 else
XinZhangMS 0:f7f1f0d76dd6 1242 {
XinZhangMS 0:f7f1f0d76dd6 1243 AMQP_DEVICE_INSTANCE* instance = (AMQP_DEVICE_INSTANCE*)handle;
XinZhangMS 0:f7f1f0d76dd6 1244
XinZhangMS 0:f7f1f0d76dd6 1245 // Codes_SRS_DEVICE_09_067: [telemetry_messenger_subscribe_for_messages shall be invoked passing `on_messenger_message_received_callback` and the user callback and context]
XinZhangMS 0:f7f1f0d76dd6 1246 if (telemetry_messenger_subscribe_for_messages(instance->messenger_handle, on_messenger_message_received_callback, handle) != RESULT_OK)
XinZhangMS 0:f7f1f0d76dd6 1247 {
XinZhangMS 0:f7f1f0d76dd6 1248 // Codes_SRS_DEVICE_09_068: [If telemetry_messenger_subscribe_for_messages fails, device_subscribe_message shall return a non-zero result]
XinZhangMS 0:f7f1f0d76dd6 1249 LogError("Failed subscribing to C2D messages (telemetry_messenger_subscribe_for_messages failed)");
XinZhangMS 0:f7f1f0d76dd6 1250 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 1251 }
XinZhangMS 0:f7f1f0d76dd6 1252 else
XinZhangMS 0:f7f1f0d76dd6 1253 {
XinZhangMS 0:f7f1f0d76dd6 1254 instance->on_message_received_callback = on_message_received_callback;
XinZhangMS 0:f7f1f0d76dd6 1255 instance->on_message_received_context = context;
XinZhangMS 0:f7f1f0d76dd6 1256
XinZhangMS 0:f7f1f0d76dd6 1257 // Codes_SRS_DEVICE_09_069: [If no failures occur, device_subscribe_message shall return 0]
XinZhangMS 0:f7f1f0d76dd6 1258 result = RESULT_OK;
XinZhangMS 0:f7f1f0d76dd6 1259 }
XinZhangMS 0:f7f1f0d76dd6 1260 }
XinZhangMS 0:f7f1f0d76dd6 1261
XinZhangMS 0:f7f1f0d76dd6 1262 return result;
XinZhangMS 0:f7f1f0d76dd6 1263 }
XinZhangMS 0:f7f1f0d76dd6 1264
XinZhangMS 0:f7f1f0d76dd6 1265 int device_unsubscribe_message(AMQP_DEVICE_HANDLE handle)
XinZhangMS 0:f7f1f0d76dd6 1266 {
XinZhangMS 0:f7f1f0d76dd6 1267 int result;
XinZhangMS 0:f7f1f0d76dd6 1268
XinZhangMS 0:f7f1f0d76dd6 1269 // Codes_SRS_DEVICE_09_076: [If `handle` is NULL, device_unsubscribe_message shall return a non-zero result]
XinZhangMS 0:f7f1f0d76dd6 1270 if (handle == NULL)
XinZhangMS 0:f7f1f0d76dd6 1271 {
XinZhangMS 0:f7f1f0d76dd6 1272 LogError("Failed unsubscribing to C2D messages (handle is NULL)");
XinZhangMS 0:f7f1f0d76dd6 1273 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 1274 }
XinZhangMS 0:f7f1f0d76dd6 1275 else
XinZhangMS 0:f7f1f0d76dd6 1276 {
XinZhangMS 0:f7f1f0d76dd6 1277 AMQP_DEVICE_INSTANCE* instance = (AMQP_DEVICE_INSTANCE*)handle;
XinZhangMS 0:f7f1f0d76dd6 1278
XinZhangMS 0:f7f1f0d76dd6 1279 // Codes_SRS_DEVICE_09_077: [telemetry_messenger_unsubscribe_for_messages shall be invoked passing `instance->messenger_handle`]
XinZhangMS 0:f7f1f0d76dd6 1280 if (telemetry_messenger_unsubscribe_for_messages(instance->messenger_handle) != RESULT_OK)
XinZhangMS 0:f7f1f0d76dd6 1281 {
XinZhangMS 0:f7f1f0d76dd6 1282 // Codes_SRS_DEVICE_09_078: [If telemetry_messenger_unsubscribe_for_messages fails, device_unsubscribe_message shall return a non-zero result]
XinZhangMS 0:f7f1f0d76dd6 1283 LogError("Failed unsubscribing to C2D messages (telemetry_messenger_unsubscribe_for_messages failed)");
XinZhangMS 0:f7f1f0d76dd6 1284 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 1285 }
XinZhangMS 0:f7f1f0d76dd6 1286 else
XinZhangMS 0:f7f1f0d76dd6 1287 {
XinZhangMS 0:f7f1f0d76dd6 1288 // Codes_SRS_DEVICE_09_079: [If no failures occur, device_unsubscribe_message shall return 0]
XinZhangMS 0:f7f1f0d76dd6 1289 result = RESULT_OK;
XinZhangMS 0:f7f1f0d76dd6 1290 }
XinZhangMS 0:f7f1f0d76dd6 1291 }
XinZhangMS 0:f7f1f0d76dd6 1292 return result;
XinZhangMS 0:f7f1f0d76dd6 1293 }
XinZhangMS 0:f7f1f0d76dd6 1294
XinZhangMS 0:f7f1f0d76dd6 1295 int device_send_message_disposition(AMQP_DEVICE_HANDLE device_handle, DEVICE_MESSAGE_DISPOSITION_INFO* disposition_info, DEVICE_MESSAGE_DISPOSITION_RESULT disposition_result)
XinZhangMS 0:f7f1f0d76dd6 1296 {
XinZhangMS 0:f7f1f0d76dd6 1297 int result;
XinZhangMS 0:f7f1f0d76dd6 1298
XinZhangMS 0:f7f1f0d76dd6 1299 // Codes_SRS_DEVICE_09_111: [If `device_handle` or `disposition_info` are NULL, device_send_message_disposition() shall fail and return __FAILURE__]
XinZhangMS 0:f7f1f0d76dd6 1300 if (device_handle == NULL || disposition_info == NULL)
XinZhangMS 0:f7f1f0d76dd6 1301 {
XinZhangMS 0:f7f1f0d76dd6 1302 LogError("Failed sending message disposition (either device_handle (%p) or disposition_info (%p) are NULL)", device_handle, disposition_info);
XinZhangMS 0:f7f1f0d76dd6 1303 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 1304 }
XinZhangMS 0:f7f1f0d76dd6 1305 // Codes_SRS_DEVICE_09_112: [If `disposition_info->source` is NULL, device_send_message_disposition() shall fail and return __FAILURE__]
XinZhangMS 0:f7f1f0d76dd6 1306 else if (disposition_info->source == NULL)
XinZhangMS 0:f7f1f0d76dd6 1307 {
XinZhangMS 0:f7f1f0d76dd6 1308 LogError("Failed sending message disposition (disposition_info->source is NULL)");
XinZhangMS 0:f7f1f0d76dd6 1309 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 1310 }
XinZhangMS 0:f7f1f0d76dd6 1311 else
XinZhangMS 0:f7f1f0d76dd6 1312 {
XinZhangMS 0:f7f1f0d76dd6 1313 AMQP_DEVICE_INSTANCE* device = (AMQP_DEVICE_INSTANCE*)device_handle;
XinZhangMS 0:f7f1f0d76dd6 1314 TELEMETRY_MESSENGER_MESSAGE_DISPOSITION_INFO* messenger_disposition_info;
XinZhangMS 0:f7f1f0d76dd6 1315
XinZhangMS 0:f7f1f0d76dd6 1316 // Codes_SRS_DEVICE_09_113: [A TELEMETRY_MESSENGER_MESSAGE_DISPOSITION_INFO instance shall be created with a copy of the `source` and `message_id` contained in `disposition_info`]
XinZhangMS 0:f7f1f0d76dd6 1317 if ((messenger_disposition_info = create_messenger_disposition_info(disposition_info)) == NULL)
XinZhangMS 0:f7f1f0d76dd6 1318 {
XinZhangMS 0:f7f1f0d76dd6 1319 // Codes_SRS_DEVICE_09_114: [If the TELEMETRY_MESSENGER_MESSAGE_DISPOSITION_INFO fails to be created, device_send_message_disposition() shall fail and return __FAILURE__]
XinZhangMS 0:f7f1f0d76dd6 1320 LogError("Failed sending message disposition (failed to create TELEMETRY_MESSENGER_MESSAGE_DISPOSITION_INFO)");
XinZhangMS 0:f7f1f0d76dd6 1321 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 1322 }
XinZhangMS 0:f7f1f0d76dd6 1323 else
XinZhangMS 0:f7f1f0d76dd6 1324 {
XinZhangMS 0:f7f1f0d76dd6 1325 TELEMETRY_MESSENGER_DISPOSITION_RESULT messenger_disposition_result = get_messenger_message_disposition_result_from(disposition_result);
XinZhangMS 0:f7f1f0d76dd6 1326
XinZhangMS 0:f7f1f0d76dd6 1327 // Codes_SRS_DEVICE_09_115: [`telemetry_messenger_send_message_disposition()` shall be invoked passing the TELEMETRY_MESSENGER_MESSAGE_DISPOSITION_INFO instance and the corresponding TELEMETRY_MESSENGER_DISPOSITION_RESULT]
XinZhangMS 0:f7f1f0d76dd6 1328 if (telemetry_messenger_send_message_disposition(device->messenger_handle, messenger_disposition_info, messenger_disposition_result) != RESULT_OK)
XinZhangMS 0:f7f1f0d76dd6 1329 {
XinZhangMS 0:f7f1f0d76dd6 1330 // Codes_SRS_DEVICE_09_116: [If `telemetry_messenger_send_message_disposition()` fails, device_send_message_disposition() shall fail and return __FAILURE__]
XinZhangMS 0:f7f1f0d76dd6 1331 LogError("Failed sending message disposition (telemetry_messenger_send_message_disposition failed)");
XinZhangMS 0:f7f1f0d76dd6 1332 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 1333 }
XinZhangMS 0:f7f1f0d76dd6 1334 else
XinZhangMS 0:f7f1f0d76dd6 1335 {
XinZhangMS 0:f7f1f0d76dd6 1336 // Codes_SRS_DEVICE_09_118: [If no failures occurr, device_send_message_disposition() shall return 0]
XinZhangMS 0:f7f1f0d76dd6 1337 result = RESULT_OK;
XinZhangMS 0:f7f1f0d76dd6 1338 }
XinZhangMS 0:f7f1f0d76dd6 1339
XinZhangMS 0:f7f1f0d76dd6 1340 // Codes_SRS_DEVICE_09_117: [device_send_message_disposition() shall destroy the TELEMETRY_MESSENGER_MESSAGE_DISPOSITION_INFO instance]
XinZhangMS 0:f7f1f0d76dd6 1341 destroy_messenger_disposition_info(messenger_disposition_info);
XinZhangMS 0:f7f1f0d76dd6 1342 }
XinZhangMS 0:f7f1f0d76dd6 1343 }
XinZhangMS 0:f7f1f0d76dd6 1344
XinZhangMS 0:f7f1f0d76dd6 1345 return result;
XinZhangMS 0:f7f1f0d76dd6 1346 }
XinZhangMS 0:f7f1f0d76dd6 1347
XinZhangMS 0:f7f1f0d76dd6 1348 int device_set_retry_policy(AMQP_DEVICE_HANDLE handle, IOTHUB_CLIENT_RETRY_POLICY policy, size_t retry_timeout_limit_in_seconds)
XinZhangMS 0:f7f1f0d76dd6 1349 {
XinZhangMS 0:f7f1f0d76dd6 1350 (void)retry_timeout_limit_in_seconds;
XinZhangMS 0:f7f1f0d76dd6 1351 (void)policy;
XinZhangMS 0:f7f1f0d76dd6 1352 int result;
XinZhangMS 0:f7f1f0d76dd6 1353
XinZhangMS 0:f7f1f0d76dd6 1354 // Codes_SRS_DEVICE_09_080: [If `handle` is NULL, device_set_retry_policy shall return a non-zero result]
XinZhangMS 0:f7f1f0d76dd6 1355 if (handle == NULL)
XinZhangMS 0:f7f1f0d76dd6 1356 {
XinZhangMS 0:f7f1f0d76dd6 1357 LogError("Failed setting retry policy (handle is NULL)");
XinZhangMS 0:f7f1f0d76dd6 1358 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 1359 }
XinZhangMS 0:f7f1f0d76dd6 1360 else
XinZhangMS 0:f7f1f0d76dd6 1361 {
XinZhangMS 0:f7f1f0d76dd6 1362 // Codes_SRS_DEVICE_09_081: [device_set_retry_policy shall return a non-zero result]
XinZhangMS 0:f7f1f0d76dd6 1363 LogError("Failed setting retry policy (functionality not supported)");
XinZhangMS 0:f7f1f0d76dd6 1364 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 1365 }
XinZhangMS 0:f7f1f0d76dd6 1366
XinZhangMS 0:f7f1f0d76dd6 1367 return result;
XinZhangMS 0:f7f1f0d76dd6 1368 }
XinZhangMS 0:f7f1f0d76dd6 1369
XinZhangMS 0:f7f1f0d76dd6 1370 int device_set_option(AMQP_DEVICE_HANDLE handle, const char* name, void* value)
XinZhangMS 0:f7f1f0d76dd6 1371 {
XinZhangMS 0:f7f1f0d76dd6 1372 int result;
XinZhangMS 0:f7f1f0d76dd6 1373
XinZhangMS 0:f7f1f0d76dd6 1374 // Codes_SRS_DEVICE_09_082: [If `handle` or `name` or `value` are NULL, device_set_option shall return a non-zero result]
XinZhangMS 0:f7f1f0d76dd6 1375 if (handle == NULL || name == NULL || value == NULL)
XinZhangMS 0:f7f1f0d76dd6 1376 {
XinZhangMS 0:f7f1f0d76dd6 1377 LogError("failed setting device option (one of the followin are NULL: _handle=%p, name=%p, value=%p)",
XinZhangMS 0:f7f1f0d76dd6 1378 handle, name, value);
XinZhangMS 0:f7f1f0d76dd6 1379 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 1380 }
XinZhangMS 0:f7f1f0d76dd6 1381 else
XinZhangMS 0:f7f1f0d76dd6 1382 {
XinZhangMS 0:f7f1f0d76dd6 1383 AMQP_DEVICE_INSTANCE* instance = (AMQP_DEVICE_INSTANCE*)handle;
XinZhangMS 0:f7f1f0d76dd6 1384
XinZhangMS 0:f7f1f0d76dd6 1385 if (strcmp(DEVICE_OPTION_CBS_REQUEST_TIMEOUT_SECS, name) == 0 ||
XinZhangMS 0:f7f1f0d76dd6 1386 strcmp(DEVICE_OPTION_SAS_TOKEN_REFRESH_TIME_SECS, name) == 0 ||
XinZhangMS 0:f7f1f0d76dd6 1387 strcmp(DEVICE_OPTION_SAS_TOKEN_LIFETIME_SECS, name) == 0)
XinZhangMS 0:f7f1f0d76dd6 1388 {
XinZhangMS 0:f7f1f0d76dd6 1389 // Codes_SRS_DEVICE_09_083: [If `name` refers to authentication but CBS authentication is not used, device_set_option shall return a non-zero result]
XinZhangMS 0:f7f1f0d76dd6 1390 if (instance->authentication_handle == NULL)
XinZhangMS 0:f7f1f0d76dd6 1391 {
XinZhangMS 0:f7f1f0d76dd6 1392 LogError("failed setting option for device '%s' (cannot set authentication option '%s'; not using CBS authentication)", instance->config->device_id, name);
XinZhangMS 0:f7f1f0d76dd6 1393 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 1394 }
XinZhangMS 0:f7f1f0d76dd6 1395 // Codes_SRS_DEVICE_09_084: [If `name` refers to authentication, it shall be passed along with `value` to authentication_set_option]
XinZhangMS 0:f7f1f0d76dd6 1396 else if(authentication_set_option(instance->authentication_handle, name, value) != RESULT_OK)
XinZhangMS 0:f7f1f0d76dd6 1397 {
XinZhangMS 0:f7f1f0d76dd6 1398 // Codes_SRS_DEVICE_09_085: [If authentication_set_option fails, device_set_option shall return a non-zero result]
XinZhangMS 0:f7f1f0d76dd6 1399 LogError("failed setting option for device '%s' (failed setting authentication option '%s')", instance->config->device_id, name);
XinZhangMS 0:f7f1f0d76dd6 1400 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 1401 }
XinZhangMS 0:f7f1f0d76dd6 1402 else
XinZhangMS 0:f7f1f0d76dd6 1403 {
XinZhangMS 0:f7f1f0d76dd6 1404 result = RESULT_OK;
XinZhangMS 0:f7f1f0d76dd6 1405 }
XinZhangMS 0:f7f1f0d76dd6 1406 }
XinZhangMS 0:f7f1f0d76dd6 1407 else if (strcmp(DEVICE_OPTION_EVENT_SEND_TIMEOUT_SECS, name) == 0)
XinZhangMS 0:f7f1f0d76dd6 1408 {
XinZhangMS 0:f7f1f0d76dd6 1409 // Codes_SRS_DEVICE_09_086: [If `name` refers to messenger module, it shall be passed along with `value` to telemetry_messenger_set_option]
XinZhangMS 0:f7f1f0d76dd6 1410 if (telemetry_messenger_set_option(instance->messenger_handle, TELEMETRY_MESSENGER_OPTION_EVENT_SEND_TIMEOUT_SECS, value) != RESULT_OK)
XinZhangMS 0:f7f1f0d76dd6 1411 {
XinZhangMS 0:f7f1f0d76dd6 1412 // Codes_SRS_DEVICE_09_087: [If telemetry_messenger_set_option fails, device_set_option shall return a non-zero result]
XinZhangMS 0:f7f1f0d76dd6 1413 LogError("failed setting option for device '%s' (failed setting messenger option '%s')", instance->config->device_id, name);
XinZhangMS 0:f7f1f0d76dd6 1414 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 1415 }
XinZhangMS 0:f7f1f0d76dd6 1416 else
XinZhangMS 0:f7f1f0d76dd6 1417 {
XinZhangMS 0:f7f1f0d76dd6 1418 result = RESULT_OK;
XinZhangMS 0:f7f1f0d76dd6 1419 }
XinZhangMS 0:f7f1f0d76dd6 1420 }
XinZhangMS 0:f7f1f0d76dd6 1421 else if (strcmp(DEVICE_OPTION_SAVED_AUTH_OPTIONS, name) == 0)
XinZhangMS 0:f7f1f0d76dd6 1422 {
XinZhangMS 0:f7f1f0d76dd6 1423 // Codes_SRS_DEVICE_09_088: [If `name` is DEVICE_OPTION_SAVED_AUTH_OPTIONS but CBS authentication is not being used, device_set_option shall return a non-zero result]
XinZhangMS 0:f7f1f0d76dd6 1424 if (instance->authentication_handle == NULL)
XinZhangMS 0:f7f1f0d76dd6 1425 {
XinZhangMS 0:f7f1f0d76dd6 1426 LogError("failed setting option for device '%s' (cannot set authentication option '%s'; not using CBS authentication)", instance->config->device_id, name);
XinZhangMS 0:f7f1f0d76dd6 1427 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 1428 }
XinZhangMS 0:f7f1f0d76dd6 1429 else if (OptionHandler_FeedOptions((OPTIONHANDLER_HANDLE)value, instance->authentication_handle) != OPTIONHANDLER_OK)
XinZhangMS 0:f7f1f0d76dd6 1430 {
XinZhangMS 0:f7f1f0d76dd6 1431 // Codes_SRS_DEVICE_09_091: [If any call to OptionHandler_FeedOptions fails, device_set_option shall return a non-zero result]
XinZhangMS 0:f7f1f0d76dd6 1432 LogError("failed setting option for device '%s' (OptionHandler_FeedOptions failed for authentication instance)", instance->config->device_id);
XinZhangMS 0:f7f1f0d76dd6 1433 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 1434 }
XinZhangMS 0:f7f1f0d76dd6 1435 else
XinZhangMS 0:f7f1f0d76dd6 1436 {
XinZhangMS 0:f7f1f0d76dd6 1437 result = RESULT_OK;
XinZhangMS 0:f7f1f0d76dd6 1438 }
XinZhangMS 0:f7f1f0d76dd6 1439 }
XinZhangMS 0:f7f1f0d76dd6 1440 else if (strcmp(DEVICE_OPTION_SAVED_MESSENGER_OPTIONS, name) == 0)
XinZhangMS 0:f7f1f0d76dd6 1441 {
XinZhangMS 0:f7f1f0d76dd6 1442 // Codes_SRS_DEVICE_09_089: [If `name` is DEVICE_OPTION_SAVED_MESSENGER_OPTIONS, `value` shall be fed to `instance->messenger_handle` using OptionHandler_FeedOptions]
XinZhangMS 0:f7f1f0d76dd6 1443 if (OptionHandler_FeedOptions((OPTIONHANDLER_HANDLE)value, instance->messenger_handle) != OPTIONHANDLER_OK)
XinZhangMS 0:f7f1f0d76dd6 1444 {
XinZhangMS 0:f7f1f0d76dd6 1445 // Codes_SRS_DEVICE_09_091: [If any call to OptionHandler_FeedOptions fails, device_set_option shall return a non-zero result]
XinZhangMS 0:f7f1f0d76dd6 1446 LogError("failed setting option for device '%s' (OptionHandler_FeedOptions failed for messenger instance)", instance->config->device_id);
XinZhangMS 0:f7f1f0d76dd6 1447 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 1448 }
XinZhangMS 0:f7f1f0d76dd6 1449 else
XinZhangMS 0:f7f1f0d76dd6 1450 {
XinZhangMS 0:f7f1f0d76dd6 1451 result = RESULT_OK;
XinZhangMS 0:f7f1f0d76dd6 1452 }
XinZhangMS 0:f7f1f0d76dd6 1453 }
XinZhangMS 0:f7f1f0d76dd6 1454 else if (strcmp(DEVICE_OPTION_SAVED_OPTIONS, name) == 0)
XinZhangMS 0:f7f1f0d76dd6 1455 {
XinZhangMS 0:f7f1f0d76dd6 1456 // Codes_SRS_DEVICE_09_090: [If `name` is DEVICE_OPTION_SAVED_OPTIONS, `value` shall be fed to `instance` using OptionHandler_FeedOptions]
XinZhangMS 0:f7f1f0d76dd6 1457 if (OptionHandler_FeedOptions((OPTIONHANDLER_HANDLE)value, handle) != OPTIONHANDLER_OK)
XinZhangMS 0:f7f1f0d76dd6 1458 {
XinZhangMS 0:f7f1f0d76dd6 1459 // Codes_SRS_DEVICE_09_091: [If any call to OptionHandler_FeedOptions fails, device_set_option shall return a non-zero result]
XinZhangMS 0:f7f1f0d76dd6 1460 LogError("failed setting option for device '%s' (OptionHandler_FeedOptions failed)", instance->config->device_id);
XinZhangMS 0:f7f1f0d76dd6 1461 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 1462 }
XinZhangMS 0:f7f1f0d76dd6 1463 else
XinZhangMS 0:f7f1f0d76dd6 1464 {
XinZhangMS 0:f7f1f0d76dd6 1465 result = RESULT_OK;
XinZhangMS 0:f7f1f0d76dd6 1466 }
XinZhangMS 0:f7f1f0d76dd6 1467 }
XinZhangMS 0:f7f1f0d76dd6 1468 else
XinZhangMS 0:f7f1f0d76dd6 1469 {
XinZhangMS 0:f7f1f0d76dd6 1470 // Codes_SRS_DEVICE_09_092: [If no failures occur, device_set_option shall return 0]
XinZhangMS 0:f7f1f0d76dd6 1471 LogError("failed setting option for device '%s' (option with name '%s' is not suppported)", instance->config->device_id, name);
XinZhangMS 0:f7f1f0d76dd6 1472 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 1473 }
XinZhangMS 0:f7f1f0d76dd6 1474 }
XinZhangMS 0:f7f1f0d76dd6 1475
XinZhangMS 0:f7f1f0d76dd6 1476 return result;
XinZhangMS 0:f7f1f0d76dd6 1477 }
XinZhangMS 0:f7f1f0d76dd6 1478
XinZhangMS 0:f7f1f0d76dd6 1479 OPTIONHANDLER_HANDLE device_retrieve_options(AMQP_DEVICE_HANDLE handle)
XinZhangMS 0:f7f1f0d76dd6 1480 {
XinZhangMS 0:f7f1f0d76dd6 1481 OPTIONHANDLER_HANDLE result;
XinZhangMS 0:f7f1f0d76dd6 1482
XinZhangMS 0:f7f1f0d76dd6 1483 // Codes_SRS_DEVICE_09_093: [If `handle` is NULL, device_retrieve_options shall return NULL]
XinZhangMS 0:f7f1f0d76dd6 1484 if (handle == NULL)
XinZhangMS 0:f7f1f0d76dd6 1485 {
XinZhangMS 0:f7f1f0d76dd6 1486 LogError("Failed to retrieve options from device instance (handle is NULL)");
XinZhangMS 0:f7f1f0d76dd6 1487 result = NULL;
XinZhangMS 0:f7f1f0d76dd6 1488 }
XinZhangMS 0:f7f1f0d76dd6 1489 else
XinZhangMS 0:f7f1f0d76dd6 1490 {
XinZhangMS 0:f7f1f0d76dd6 1491 // Codes_SRS_DEVICE_09_094: [A OPTIONHANDLER_HANDLE instance, aka `options` shall be created using OptionHandler_Create]
XinZhangMS 0:f7f1f0d76dd6 1492 OPTIONHANDLER_HANDLE options = OptionHandler_Create(device_clone_option, device_destroy_option, (pfSetOption)device_set_option);
XinZhangMS 0:f7f1f0d76dd6 1493
XinZhangMS 0:f7f1f0d76dd6 1494 if (options == NULL)
XinZhangMS 0:f7f1f0d76dd6 1495 {
XinZhangMS 0:f7f1f0d76dd6 1496 // Codes_SRS_DEVICE_09_095: [If OptionHandler_Create fails, device_retrieve_options shall return NULL]
XinZhangMS 0:f7f1f0d76dd6 1497 LogError("Failed to retrieve options from device instance (OptionHandler_Create failed)");
XinZhangMS 0:f7f1f0d76dd6 1498 result = NULL;
XinZhangMS 0:f7f1f0d76dd6 1499 }
XinZhangMS 0:f7f1f0d76dd6 1500 else
XinZhangMS 0:f7f1f0d76dd6 1501 {
XinZhangMS 0:f7f1f0d76dd6 1502 AMQP_DEVICE_INSTANCE* instance = (AMQP_DEVICE_INSTANCE*)handle;
XinZhangMS 0:f7f1f0d76dd6 1503
XinZhangMS 0:f7f1f0d76dd6 1504 OPTIONHANDLER_HANDLE dependency_options = NULL;
XinZhangMS 0:f7f1f0d76dd6 1505
XinZhangMS 0:f7f1f0d76dd6 1506 // Codes_SRS_DEVICE_09_096: [If CBS authentication is used, `instance->authentication_handle` options shall be retrieved using authentication_retrieve_options]
XinZhangMS 0:f7f1f0d76dd6 1507 if (instance->authentication_handle != NULL &&
XinZhangMS 0:f7f1f0d76dd6 1508 (dependency_options = authentication_retrieve_options(instance->authentication_handle)) == NULL)
XinZhangMS 0:f7f1f0d76dd6 1509 {
XinZhangMS 0:f7f1f0d76dd6 1510 // Codes_SRS_DEVICE_09_097: [If authentication_retrieve_options fails, device_retrieve_options shall return NULL]
XinZhangMS 0:f7f1f0d76dd6 1511 LogError("Failed to retrieve options from device '%s' (failed to retrieve options from authentication instance)", instance->config->device_id);
XinZhangMS 0:f7f1f0d76dd6 1512 result = NULL;
XinZhangMS 0:f7f1f0d76dd6 1513 }
XinZhangMS 0:f7f1f0d76dd6 1514 // Codes_SRS_DEVICE_09_098: [The authentication options shall be added to `options` using OptionHandler_AddOption as DEVICE_OPTION_SAVED_AUTH_OPTIONS]
XinZhangMS 0:f7f1f0d76dd6 1515 else if (instance->authentication_handle != NULL &&
XinZhangMS 0:f7f1f0d76dd6 1516 OptionHandler_AddOption(options, DEVICE_OPTION_SAVED_AUTH_OPTIONS, (const void*)dependency_options) != OPTIONHANDLER_OK)
XinZhangMS 0:f7f1f0d76dd6 1517 {
XinZhangMS 0:f7f1f0d76dd6 1518 // Codes_SRS_DEVICE_09_102: [If any call to OptionHandler_AddOption fails, device_retrieve_options shall return NULL]
XinZhangMS 0:f7f1f0d76dd6 1519 LogError("Failed to retrieve options from device '%s' (OptionHandler_AddOption failed for option '%s')", instance->config->device_id, DEVICE_OPTION_SAVED_AUTH_OPTIONS);
XinZhangMS 0:f7f1f0d76dd6 1520 result = NULL;
XinZhangMS 0:f7f1f0d76dd6 1521 }
XinZhangMS 0:f7f1f0d76dd6 1522 // Codes_SRS_DEVICE_09_099: [`instance->messenger_handle` options shall be retrieved using telemetry_messenger_retrieve_options]
XinZhangMS 0:f7f1f0d76dd6 1523 else if ((dependency_options = telemetry_messenger_retrieve_options(instance->messenger_handle)) == NULL)
XinZhangMS 0:f7f1f0d76dd6 1524 {
XinZhangMS 0:f7f1f0d76dd6 1525 // Codes_SRS_DEVICE_09_100: [If telemetry_messenger_retrieve_options fails, device_retrieve_options shall return NULL]
XinZhangMS 0:f7f1f0d76dd6 1526 LogError("Failed to retrieve options from device '%s' (failed to retrieve options from messenger instance)", instance->config->device_id);
XinZhangMS 0:f7f1f0d76dd6 1527 result = NULL;
XinZhangMS 0:f7f1f0d76dd6 1528 }
XinZhangMS 0:f7f1f0d76dd6 1529 // Codes_SRS_DEVICE_09_101: [The messenger options shall be added to `options` using OptionHandler_AddOption as DEVICE_OPTION_SAVED_MESSENGER_OPTIONS]
XinZhangMS 0:f7f1f0d76dd6 1530 else if (OptionHandler_AddOption(options, DEVICE_OPTION_SAVED_MESSENGER_OPTIONS, (const void*)dependency_options) != OPTIONHANDLER_OK)
XinZhangMS 0:f7f1f0d76dd6 1531 {
XinZhangMS 0:f7f1f0d76dd6 1532 // Codes_SRS_DEVICE_09_102: [If any call to OptionHandler_AddOption fails, device_retrieve_options shall return NULL]
XinZhangMS 0:f7f1f0d76dd6 1533 LogError("Failed to retrieve options from device '%s' (OptionHandler_AddOption failed for option '%s')", instance->config->device_id, DEVICE_OPTION_SAVED_MESSENGER_OPTIONS);
XinZhangMS 0:f7f1f0d76dd6 1534 result = NULL;
XinZhangMS 0:f7f1f0d76dd6 1535 }
XinZhangMS 0:f7f1f0d76dd6 1536 else
XinZhangMS 0:f7f1f0d76dd6 1537 {
XinZhangMS 0:f7f1f0d76dd6 1538 // Codes_SRS_DEVICE_09_104: [If no failures occur, a handle to `options` shall be return]
XinZhangMS 0:f7f1f0d76dd6 1539 result = options;
XinZhangMS 0:f7f1f0d76dd6 1540 }
XinZhangMS 0:f7f1f0d76dd6 1541
XinZhangMS 0:f7f1f0d76dd6 1542 if (result == NULL)
XinZhangMS 0:f7f1f0d76dd6 1543 {
XinZhangMS 0:f7f1f0d76dd6 1544 // Codes_SRS_DEVICE_09_103: [If any failure occurs, any memory allocated by device_retrieve_options shall be destroyed]
XinZhangMS 0:f7f1f0d76dd6 1545 OptionHandler_Destroy(options);
XinZhangMS 0:f7f1f0d76dd6 1546 }
XinZhangMS 0:f7f1f0d76dd6 1547 }
XinZhangMS 0:f7f1f0d76dd6 1548 }
XinZhangMS 0:f7f1f0d76dd6 1549
XinZhangMS 0:f7f1f0d76dd6 1550 return result;
XinZhangMS 0:f7f1f0d76dd6 1551 }
XinZhangMS 0:f7f1f0d76dd6 1552
XinZhangMS 0:f7f1f0d76dd6 1553 int device_send_twin_update_async(AMQP_DEVICE_HANDLE handle, CONSTBUFFER_HANDLE data, DEVICE_SEND_TWIN_UPDATE_COMPLETE_CALLBACK on_send_twin_update_complete_callback, void* context)
XinZhangMS 0:f7f1f0d76dd6 1554 {
XinZhangMS 0:f7f1f0d76dd6 1555 int result;
XinZhangMS 0:f7f1f0d76dd6 1556
XinZhangMS 0:f7f1f0d76dd6 1557 // Codes_SRS_DEVICE_09_135: [If `handle` or `data` are NULL, device_send_twin_update_async shall return a non-zero result]
XinZhangMS 0:f7f1f0d76dd6 1558 if (handle == NULL || data == NULL)
XinZhangMS 0:f7f1f0d76dd6 1559 {
XinZhangMS 0:f7f1f0d76dd6 1560 LogError("Invalid argument (handle=%p, data=%p)", handle, data);
XinZhangMS 0:f7f1f0d76dd6 1561 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 1562 }
XinZhangMS 0:f7f1f0d76dd6 1563 else
XinZhangMS 0:f7f1f0d76dd6 1564 {
XinZhangMS 0:f7f1f0d76dd6 1565 AMQP_DEVICE_INSTANCE* instance = (AMQP_DEVICE_INSTANCE*)handle;
XinZhangMS 0:f7f1f0d76dd6 1566 DEVICE_SEND_TWIN_UPDATE_CONTEXT* twin_ctx;
XinZhangMS 0:f7f1f0d76dd6 1567
XinZhangMS 0:f7f1f0d76dd6 1568 // Codes_SRS_DEVICE_09_136: [A structure (`twin_ctx`) shall be created to track the send state of the twin report]
XinZhangMS 0:f7f1f0d76dd6 1569 if ((twin_ctx = (DEVICE_SEND_TWIN_UPDATE_CONTEXT*)malloc(sizeof(DEVICE_SEND_TWIN_UPDATE_CONTEXT))) == NULL)
XinZhangMS 0:f7f1f0d76dd6 1570 {
XinZhangMS 0:f7f1f0d76dd6 1571 // Codes_SRS_DEVICE_09_137: [If `twin_ctx` fails to be created, device_send_twin_update_async shall return a non-zero value]
XinZhangMS 0:f7f1f0d76dd6 1572 LogError("Cannot send twin update (failed creating TWIN context)");
XinZhangMS 0:f7f1f0d76dd6 1573 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 1574 }
XinZhangMS 0:f7f1f0d76dd6 1575 else
XinZhangMS 0:f7f1f0d76dd6 1576 {
XinZhangMS 0:f7f1f0d76dd6 1577 twin_ctx->on_send_twin_update_complete_callback = on_send_twin_update_complete_callback;
XinZhangMS 0:f7f1f0d76dd6 1578 twin_ctx->context = context;
XinZhangMS 0:f7f1f0d76dd6 1579
XinZhangMS 0:f7f1f0d76dd6 1580 // Codes_SRS_DEVICE_09_138: [The twin report shall be sent using twin_messenger_report_state_async, passing `on_report_state_complete_callback` and `twin_ctx`]
XinZhangMS 0:f7f1f0d76dd6 1581 if (twin_messenger_report_state_async(instance->twin_messenger_handle, data, on_report_state_complete_callback, (const void*)twin_ctx) != 0)
XinZhangMS 0:f7f1f0d76dd6 1582 {
XinZhangMS 0:f7f1f0d76dd6 1583 // Codes_SRS_DEVICE_09_139: [If twin_messenger_report_state_async fails, device_send_twin_update_async shall return a non-zero value]
XinZhangMS 0:f7f1f0d76dd6 1584 LogError("Cannot send twin update (failed creating TWIN messenger)");
XinZhangMS 0:f7f1f0d76dd6 1585 free(twin_ctx);
XinZhangMS 0:f7f1f0d76dd6 1586 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 1587 }
XinZhangMS 0:f7f1f0d76dd6 1588 else
XinZhangMS 0:f7f1f0d76dd6 1589 {
XinZhangMS 0:f7f1f0d76dd6 1590 // Codes_SRS_DEVICE_09_140: [If no failures occur, device_send_twin_update_async shall return 0]
XinZhangMS 0:f7f1f0d76dd6 1591 result = RESULT_OK;
XinZhangMS 0:f7f1f0d76dd6 1592 }
XinZhangMS 0:f7f1f0d76dd6 1593 }
XinZhangMS 0:f7f1f0d76dd6 1594 }
XinZhangMS 0:f7f1f0d76dd6 1595
XinZhangMS 0:f7f1f0d76dd6 1596 return result;
XinZhangMS 0:f7f1f0d76dd6 1597 }
XinZhangMS 0:f7f1f0d76dd6 1598
XinZhangMS 0:f7f1f0d76dd6 1599 int device_subscribe_for_twin_updates(AMQP_DEVICE_HANDLE handle, DEVICE_TWIN_UPDATE_RECEIVED_CALLBACK on_device_twin_update_received_callback, void* context)
XinZhangMS 0:f7f1f0d76dd6 1600 {
XinZhangMS 0:f7f1f0d76dd6 1601 int result;
XinZhangMS 0:f7f1f0d76dd6 1602
XinZhangMS 0:f7f1f0d76dd6 1603 // Codes_SRS_DEVICE_09_143: [If `handle` or `on_device_twin_update_received_callback` are NULL, device_subscribe_for_twin_updates shall return a non-zero result]
XinZhangMS 0:f7f1f0d76dd6 1604 if (handle == NULL || on_device_twin_update_received_callback == NULL)
XinZhangMS 0:f7f1f0d76dd6 1605 {
XinZhangMS 0:f7f1f0d76dd6 1606 LogError("Invalid argument (handle=%p, on_device_twin_update_received_callback=%p)", handle, on_device_twin_update_received_callback);
XinZhangMS 0:f7f1f0d76dd6 1607 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 1608 }
XinZhangMS 0:f7f1f0d76dd6 1609 else
XinZhangMS 0:f7f1f0d76dd6 1610 {
XinZhangMS 0:f7f1f0d76dd6 1611 AMQP_DEVICE_INSTANCE* instance = (AMQP_DEVICE_INSTANCE*)handle;
XinZhangMS 0:f7f1f0d76dd6 1612
XinZhangMS 0:f7f1f0d76dd6 1613 DEVICE_TWIN_UPDATE_RECEIVED_CALLBACK previous_callback = instance->on_device_twin_update_received_callback;
XinZhangMS 0:f7f1f0d76dd6 1614 void* previous_context = instance->on_device_twin_update_received_context;
XinZhangMS 0:f7f1f0d76dd6 1615
XinZhangMS 0:f7f1f0d76dd6 1616 instance->on_device_twin_update_received_callback = on_device_twin_update_received_callback;
XinZhangMS 0:f7f1f0d76dd6 1617 instance->on_device_twin_update_received_context = context;
XinZhangMS 0:f7f1f0d76dd6 1618
XinZhangMS 0:f7f1f0d76dd6 1619 // Codes_SRS_DEVICE_09_144: [twin_messenger_subscribe shall be invoked passing `on_twin_state_update_callback`]
XinZhangMS 0:f7f1f0d76dd6 1620 if (twin_messenger_subscribe(instance->twin_messenger_handle, on_twin_state_update_callback, (void*)instance) != 0)
XinZhangMS 0:f7f1f0d76dd6 1621 {
XinZhangMS 0:f7f1f0d76dd6 1622 // Codes_SRS_DEVICE_09_145: [If twin_messenger_subscribe fails, device_subscribe_for_twin_updates shall return a non-zero value]
XinZhangMS 0:f7f1f0d76dd6 1623 LogError("Failed subscribing for device twin updates");
XinZhangMS 0:f7f1f0d76dd6 1624 instance->on_device_twin_update_received_callback = previous_callback;
XinZhangMS 0:f7f1f0d76dd6 1625 instance->on_device_twin_update_received_context = previous_context;
XinZhangMS 0:f7f1f0d76dd6 1626 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 1627 }
XinZhangMS 0:f7f1f0d76dd6 1628 else
XinZhangMS 0:f7f1f0d76dd6 1629 {
XinZhangMS 0:f7f1f0d76dd6 1630 // Codes_SRS_DEVICE_09_146: [If no failures occur, device_subscribe_for_twin_updates shall return 0]
XinZhangMS 0:f7f1f0d76dd6 1631 result = RESULT_OK;
XinZhangMS 0:f7f1f0d76dd6 1632 }
XinZhangMS 0:f7f1f0d76dd6 1633 }
XinZhangMS 0:f7f1f0d76dd6 1634
XinZhangMS 0:f7f1f0d76dd6 1635 return result;
XinZhangMS 0:f7f1f0d76dd6 1636 }
XinZhangMS 0:f7f1f0d76dd6 1637
XinZhangMS 0:f7f1f0d76dd6 1638 int device_unsubscribe_for_twin_updates(AMQP_DEVICE_HANDLE handle)
XinZhangMS 0:f7f1f0d76dd6 1639 {
XinZhangMS 0:f7f1f0d76dd6 1640 int result;
XinZhangMS 0:f7f1f0d76dd6 1641
XinZhangMS 0:f7f1f0d76dd6 1642
XinZhangMS 0:f7f1f0d76dd6 1643 // Codes_SRS_DEVICE_09_147: [If `handle` is NULL, device_unsubscribe_for_twin_updates shall return a non-zero result]
XinZhangMS 0:f7f1f0d76dd6 1644 if (handle == NULL)
XinZhangMS 0:f7f1f0d76dd6 1645 {
XinZhangMS 0:f7f1f0d76dd6 1646 LogError("Invalid argument (handle is NULL)");
XinZhangMS 0:f7f1f0d76dd6 1647 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 1648 }
XinZhangMS 0:f7f1f0d76dd6 1649 else
XinZhangMS 0:f7f1f0d76dd6 1650 {
XinZhangMS 0:f7f1f0d76dd6 1651 AMQP_DEVICE_INSTANCE* instance = (AMQP_DEVICE_INSTANCE*)handle;
XinZhangMS 0:f7f1f0d76dd6 1652
XinZhangMS 0:f7f1f0d76dd6 1653 // Codes_SRS_DEVICE_09_148: [twin_messenger_unsubscribe shall be invoked passing `on_twin_state_update_callback`]
XinZhangMS 0:f7f1f0d76dd6 1654 if (twin_messenger_unsubscribe(instance->twin_messenger_handle) != 0)
XinZhangMS 0:f7f1f0d76dd6 1655 {
XinZhangMS 0:f7f1f0d76dd6 1656 // Codes_SRS_DEVICE_09_149: [If twin_messenger_unsubscribe fails, device_unsubscribe_for_twin_updates shall return a non-zero value]
XinZhangMS 0:f7f1f0d76dd6 1657 LogError("Failed unsubscribing for device twin updates");
XinZhangMS 0:f7f1f0d76dd6 1658 result = __FAILURE__;
XinZhangMS 0:f7f1f0d76dd6 1659 }
XinZhangMS 0:f7f1f0d76dd6 1660 else
XinZhangMS 0:f7f1f0d76dd6 1661 {
XinZhangMS 0:f7f1f0d76dd6 1662 instance->on_device_twin_update_received_callback = NULL;
XinZhangMS 0:f7f1f0d76dd6 1663 instance->on_device_twin_update_received_context = NULL;
XinZhangMS 0:f7f1f0d76dd6 1664 // Codes_SRS_DEVICE_09_150: [If no failures occur, device_unsubscribe_for_twin_updates shall return 0]
XinZhangMS 0:f7f1f0d76dd6 1665 result = RESULT_OK;
XinZhangMS 0:f7f1f0d76dd6 1666 }
XinZhangMS 0:f7f1f0d76dd6 1667 }
XinZhangMS 0:f7f1f0d76dd6 1668
XinZhangMS 0:f7f1f0d76dd6 1669 return result;
XinZhangMS 0:f7f1f0d76dd6 1670 }