Microsoft Azure IoTHub client MQTT transport

Dependents:   STM32F746_iothub_client_sample_mqtt FXOS8700CQ_To_Azure_IoT f767zi_mqtt FXOS8700CQ_To_Azure_IoT ... more

Committer:
AzureIoTClient
Date:
Fri Jul 28 09:52:04 2017 -0700
Revision:
25:a35763780a87
Child:
36:3b9944257dd5
1.1.20

Who changed what in which revision?

UserRevisionLine numberNew contents of line
AzureIoTClient 25:a35763780a87 1 // Copyright (c) Microsoft. All rights reserved.
AzureIoTClient 25:a35763780a87 2 // Licensed under the MIT license. See LICENSE file in the project root for full license information.
AzureIoTClient 25:a35763780a87 3
AzureIoTClient 25:a35763780a87 4 #include "iothub_client_retry_control.h"
AzureIoTClient 25:a35763780a87 5
AzureIoTClient 25:a35763780a87 6 #include <math.h>
AzureIoTClient 25:a35763780a87 7
AzureIoTClient 25:a35763780a87 8 #include "azure_c_shared_utility/gballoc.h"
AzureIoTClient 25:a35763780a87 9 #include "azure_c_shared_utility/agenttime.h"
AzureIoTClient 25:a35763780a87 10 #include "azure_c_shared_utility/optimize_size.h"
AzureIoTClient 25:a35763780a87 11 #include "azure_c_shared_utility/xlogging.h"
AzureIoTClient 25:a35763780a87 12
AzureIoTClient 25:a35763780a87 13 #define RESULT_OK 0
AzureIoTClient 25:a35763780a87 14 #define INDEFINITE_TIME ((time_t)-1)
AzureIoTClient 25:a35763780a87 15
AzureIoTClient 25:a35763780a87 16 typedef struct RETRY_CONTROL_INSTANCE_TAG
AzureIoTClient 25:a35763780a87 17 {
AzureIoTClient 25:a35763780a87 18 IOTHUB_CLIENT_RETRY_POLICY policy;
AzureIoTClient 25:a35763780a87 19 unsigned int max_retry_time_in_secs;
AzureIoTClient 25:a35763780a87 20
AzureIoTClient 25:a35763780a87 21 unsigned int initial_wait_time_in_secs;
AzureIoTClient 25:a35763780a87 22 unsigned int max_jitter_percent;
AzureIoTClient 25:a35763780a87 23
AzureIoTClient 25:a35763780a87 24 unsigned int retry_count;
AzureIoTClient 25:a35763780a87 25 time_t first_retry_time;
AzureIoTClient 25:a35763780a87 26 time_t last_retry_time;
AzureIoTClient 25:a35763780a87 27 unsigned int current_wait_time_in_secs;
AzureIoTClient 25:a35763780a87 28 } RETRY_CONTROL_INSTANCE;
AzureIoTClient 25:a35763780a87 29
AzureIoTClient 25:a35763780a87 30 typedef int (*RETRY_ACTION_EVALUATION_FUNCTION)(RETRY_CONTROL_INSTANCE* retry_state, RETRY_ACTION* retry_action);
AzureIoTClient 25:a35763780a87 31
AzureIoTClient 25:a35763780a87 32
AzureIoTClient 25:a35763780a87 33 // ========== Helper Functions ========== //
AzureIoTClient 25:a35763780a87 34
AzureIoTClient 25:a35763780a87 35 static int evaluate_retry_action_fixed_interval(RETRY_CONTROL_INSTANCE* retry_control, RETRY_ACTION* retry_action)
AzureIoTClient 25:a35763780a87 36 {
AzureIoTClient 25:a35763780a87 37 int result;
AzureIoTClient 25:a35763780a87 38
AzureIoTClient 25:a35763780a87 39 time_t current_time;
AzureIoTClient 25:a35763780a87 40
AzureIoTClient 25:a35763780a87 41 if ((current_time = get_time(NULL)) == INDEFINITE_TIME)
AzureIoTClient 25:a35763780a87 42 {
AzureIoTClient 25:a35763780a87 43 LogError("Cannot evaluate if should retry (get_time failed)");
AzureIoTClient 25:a35763780a87 44 result = __FAILURE__;
AzureIoTClient 25:a35763780a87 45 }
AzureIoTClient 25:a35763780a87 46 else
AzureIoTClient 25:a35763780a87 47 {
AzureIoTClient 25:a35763780a87 48 if (retry_control->max_retry_time_in_secs > 0 &&
AzureIoTClient 25:a35763780a87 49 get_difftime(current_time, retry_control->last_retry_time) >= retry_control->max_retry_time_in_secs)
AzureIoTClient 25:a35763780a87 50 {
AzureIoTClient 25:a35763780a87 51 *retry_action = RETRY_ACTION_STOP_RETRYING;
AzureIoTClient 25:a35763780a87 52 }
AzureIoTClient 25:a35763780a87 53 else
AzureIoTClient 25:a35763780a87 54 {
AzureIoTClient 25:a35763780a87 55 if (get_difftime(current_time, retry_control->last_retry_time) >= retry_control->current_wait_time_in_secs)
AzureIoTClient 25:a35763780a87 56 {
AzureIoTClient 25:a35763780a87 57 *retry_action = RETRY_ACTION_RETRY_NOW;
AzureIoTClient 25:a35763780a87 58 retry_control->last_retry_time = current_time;
AzureIoTClient 25:a35763780a87 59 }
AzureIoTClient 25:a35763780a87 60 else
AzureIoTClient 25:a35763780a87 61 {
AzureIoTClient 25:a35763780a87 62 *retry_action = RETRY_ACTION_RETRY_LATER;
AzureIoTClient 25:a35763780a87 63 }
AzureIoTClient 25:a35763780a87 64 }
AzureIoTClient 25:a35763780a87 65
AzureIoTClient 25:a35763780a87 66 result = RESULT_OK;
AzureIoTClient 25:a35763780a87 67 }
AzureIoTClient 25:a35763780a87 68
AzureIoTClient 25:a35763780a87 69 return result;
AzureIoTClient 25:a35763780a87 70 }
AzureIoTClient 25:a35763780a87 71
AzureIoTClient 25:a35763780a87 72
AzureIoTClient 25:a35763780a87 73 // ---------- Set/Retrieve Options Helpers ----------//
AzureIoTClient 25:a35763780a87 74
AzureIoTClient 25:a35763780a87 75 static void* retry_control_clone_option(const char* name, const void* value)
AzureIoTClient 25:a35763780a87 76 {
AzureIoTClient 25:a35763780a87 77 void* result;
AzureIoTClient 25:a35763780a87 78
AzureIoTClient 25:a35763780a87 79 if ((name == NULL) || (value == NULL))
AzureIoTClient 25:a35763780a87 80 {
AzureIoTClient 25:a35763780a87 81 LogError("Failed to clone option (either name (%p) or value (%p) are NULL)", name, value);
AzureIoTClient 25:a35763780a87 82 result = NULL;
AzureIoTClient 25:a35763780a87 83 }
AzureIoTClient 25:a35763780a87 84 else if (strcmp(RETRY_CONTROL_OPTION_INITIAL_WAIT_TIME_IN_SECS, name) == 0 ||
AzureIoTClient 25:a35763780a87 85 strcmp(RETRY_CONTROL_OPTION_MAX_JITTER_PERCENT, name) == 0)
AzureIoTClient 25:a35763780a87 86 {
AzureIoTClient 25:a35763780a87 87 unsigned int* cloned_value;
AzureIoTClient 25:a35763780a87 88
AzureIoTClient 25:a35763780a87 89 if ((cloned_value = (unsigned int*)malloc(sizeof(unsigned int))) == NULL)
AzureIoTClient 25:a35763780a87 90 {
AzureIoTClient 25:a35763780a87 91 LogError("Failed to clone option '%p' (malloc failed)", name);
AzureIoTClient 25:a35763780a87 92 result = NULL;
AzureIoTClient 25:a35763780a87 93 }
AzureIoTClient 25:a35763780a87 94 else
AzureIoTClient 25:a35763780a87 95 {
AzureIoTClient 25:a35763780a87 96 *cloned_value = *(unsigned int*)value;
AzureIoTClient 25:a35763780a87 97
AzureIoTClient 25:a35763780a87 98 result = (void*)cloned_value;
AzureIoTClient 25:a35763780a87 99 }
AzureIoTClient 25:a35763780a87 100 }
AzureIoTClient 25:a35763780a87 101 else
AzureIoTClient 25:a35763780a87 102 {
AzureIoTClient 25:a35763780a87 103 LogError("Failed to clone option (option with name '%s' is not suppported)", name);
AzureIoTClient 25:a35763780a87 104 result = NULL;
AzureIoTClient 25:a35763780a87 105 }
AzureIoTClient 25:a35763780a87 106
AzureIoTClient 25:a35763780a87 107 return result;
AzureIoTClient 25:a35763780a87 108 }
AzureIoTClient 25:a35763780a87 109
AzureIoTClient 25:a35763780a87 110 static void retry_control_destroy_option(const char* name, const void* value)
AzureIoTClient 25:a35763780a87 111 {
AzureIoTClient 25:a35763780a87 112 if ((name == NULL) || (value == NULL))
AzureIoTClient 25:a35763780a87 113 {
AzureIoTClient 25:a35763780a87 114 LogError("Failed to destroy option (either name (%p) or value (%p) are NULL)", name, value);
AzureIoTClient 25:a35763780a87 115 }
AzureIoTClient 25:a35763780a87 116 else if (strcmp(RETRY_CONTROL_OPTION_INITIAL_WAIT_TIME_IN_SECS, name) == 0 ||
AzureIoTClient 25:a35763780a87 117 strcmp(RETRY_CONTROL_OPTION_MAX_JITTER_PERCENT, name) == 0)
AzureIoTClient 25:a35763780a87 118 {
AzureIoTClient 25:a35763780a87 119 free((void*)value);
AzureIoTClient 25:a35763780a87 120 }
AzureIoTClient 25:a35763780a87 121 else
AzureIoTClient 25:a35763780a87 122 {
AzureIoTClient 25:a35763780a87 123 LogError("Failed to destroy option (option with name '%s' is not suppported)", name);
AzureIoTClient 25:a35763780a87 124 }
AzureIoTClient 25:a35763780a87 125 }
AzureIoTClient 25:a35763780a87 126
AzureIoTClient 25:a35763780a87 127 // ========== _should_retry() Auxiliary Functions ========== //
AzureIoTClient 25:a35763780a87 128
AzureIoTClient 25:a35763780a87 129 static int evaluate_retry_action(RETRY_CONTROL_INSTANCE* retry_control, RETRY_ACTION* retry_action)
AzureIoTClient 25:a35763780a87 130 {
AzureIoTClient 25:a35763780a87 131 int result;
AzureIoTClient 25:a35763780a87 132
AzureIoTClient 25:a35763780a87 133 // Codes_SRS_IOTHUB_CLIENT_RETRY_CONTROL_09_019: [If `retry_control->retry_count` is 0, `retry_action` shall be set to RETRY_ACTION_RETRY_NOW]
AzureIoTClient 25:a35763780a87 134 if (retry_control->retry_count == 0)
AzureIoTClient 25:a35763780a87 135 {
AzureIoTClient 25:a35763780a87 136 *retry_action = RETRY_ACTION_RETRY_NOW;
AzureIoTClient 25:a35763780a87 137 result = RESULT_OK;
AzureIoTClient 25:a35763780a87 138 }
AzureIoTClient 25:a35763780a87 139 // Codes_SRS_IOTHUB_CLIENT_RETRY_CONTROL_09_020: [If `retry_control->last_retry_time` is INDEFINITE_TIME and policy is not IOTHUB_CLIENT_RETRY_IMMEDIATE, the evaluation function shall return non-zero]
AzureIoTClient 25:a35763780a87 140 else if (retry_control->last_retry_time == INDEFINITE_TIME &&
AzureIoTClient 25:a35763780a87 141 retry_control->policy != IOTHUB_CLIENT_RETRY_IMMEDIATE)
AzureIoTClient 25:a35763780a87 142 {
AzureIoTClient 25:a35763780a87 143 LogError("Failed to evaluate retry action (last_retry_time is INDEFINITE_TIME)");
AzureIoTClient 25:a35763780a87 144 result = __FAILURE__;
AzureIoTClient 25:a35763780a87 145 }
AzureIoTClient 25:a35763780a87 146 else
AzureIoTClient 25:a35763780a87 147 {
AzureIoTClient 25:a35763780a87 148 time_t current_time;
AzureIoTClient 25:a35763780a87 149
AzureIoTClient 25:a35763780a87 150 // Codes_SRS_IOTHUB_CLIENT_RETRY_CONTROL_09_021: [`current_time` shall be set using get_time()]
AzureIoTClient 25:a35763780a87 151 if ((current_time = get_time(NULL)) == INDEFINITE_TIME)
AzureIoTClient 25:a35763780a87 152 {
AzureIoTClient 25:a35763780a87 153 // Codes_SRS_IOTHUB_CLIENT_RETRY_CONTROL_09_022: [If get_time() fails, the evaluation function shall return non-zero]
AzureIoTClient 25:a35763780a87 154 LogError("Failed to evaluate retry action (get_time() failed)");
AzureIoTClient 25:a35763780a87 155 result = __FAILURE__;
AzureIoTClient 25:a35763780a87 156 }
AzureIoTClient 25:a35763780a87 157 // Codes_SRS_IOTHUB_CLIENT_RETRY_CONTROL_09_023: [If `retry_control->max_retry_time_in_secs` is not 0 and (`current_time` - `retry_control->first_retry_time`) is greater than or equal to `retry_control->max_retry_time_in_secs`, `retry_action` shall be set to RETRY_ACTION_STOP_RETRYING]
AzureIoTClient 25:a35763780a87 158 else if (retry_control->max_retry_time_in_secs > 0 &&
AzureIoTClient 25:a35763780a87 159 get_difftime(current_time, retry_control->first_retry_time) >= retry_control->max_retry_time_in_secs)
AzureIoTClient 25:a35763780a87 160 {
AzureIoTClient 25:a35763780a87 161 *retry_action = RETRY_ACTION_STOP_RETRYING;
AzureIoTClient 25:a35763780a87 162
AzureIoTClient 25:a35763780a87 163 // Codes_SRS_IOTHUB_CLIENT_RETRY_CONTROL_09_026: [If no errors occur, the evaluation function shall return 0]
AzureIoTClient 25:a35763780a87 164 result = RESULT_OK;
AzureIoTClient 25:a35763780a87 165 }
AzureIoTClient 25:a35763780a87 166 // Codes_SRS_IOTHUB_CLIENT_RETRY_CONTROL_09_028: [If `retry_control->policy` is IOTHUB_CLIENT_RETRY_IMMEDIATE, retry_action shall be set to RETRY_ACTION_RETRY_NOW]
AzureIoTClient 25:a35763780a87 167 else if (retry_control->policy == IOTHUB_CLIENT_RETRY_IMMEDIATE)
AzureIoTClient 25:a35763780a87 168 {
AzureIoTClient 25:a35763780a87 169 *retry_action = RETRY_ACTION_RETRY_NOW;
AzureIoTClient 25:a35763780a87 170
AzureIoTClient 25:a35763780a87 171 // Codes_SRS_IOTHUB_CLIENT_RETRY_CONTROL_09_026: [If no errors occur, the evaluation function shall return 0]
AzureIoTClient 25:a35763780a87 172 result = RESULT_OK;
AzureIoTClient 25:a35763780a87 173 }
AzureIoTClient 25:a35763780a87 174 // Codes_SRS_IOTHUB_CLIENT_RETRY_CONTROL_09_024: [Otherwise, if (`current_time` - `retry_control->last_retry_time`) is less than `retry_control->current_wait_time_in_secs`, `retry_action` shall be set to RETRY_ACTION_RETRY_LATER]
AzureIoTClient 25:a35763780a87 175 else if (get_difftime(current_time, retry_control->last_retry_time) < retry_control->current_wait_time_in_secs)
AzureIoTClient 25:a35763780a87 176 {
AzureIoTClient 25:a35763780a87 177 *retry_action = RETRY_ACTION_RETRY_LATER;
AzureIoTClient 25:a35763780a87 178
AzureIoTClient 25:a35763780a87 179 // Codes_SRS_IOTHUB_CLIENT_RETRY_CONTROL_09_026: [If no errors occur, the evaluation function shall return 0]
AzureIoTClient 25:a35763780a87 180 result = RESULT_OK;
AzureIoTClient 25:a35763780a87 181 }
AzureIoTClient 25:a35763780a87 182 // Codes_SRS_IOTHUB_CLIENT_RETRY_CONTROL_09_025: [Otherwise, if (`current_time` - `retry_control->last_retry_time`) is greater or equal to `retry_control->current_wait_time_in_secs`, `retry_action` shall be set to RETRY_ACTION_RETRY_NOW]
AzureIoTClient 25:a35763780a87 183 else
AzureIoTClient 25:a35763780a87 184 {
AzureIoTClient 25:a35763780a87 185 *retry_action = RETRY_ACTION_RETRY_NOW;
AzureIoTClient 25:a35763780a87 186
AzureIoTClient 25:a35763780a87 187 // Codes_SRS_IOTHUB_CLIENT_RETRY_CONTROL_09_026: [If no errors occur, the evaluation function shall return 0]
AzureIoTClient 25:a35763780a87 188 result = RESULT_OK;
AzureIoTClient 25:a35763780a87 189 }
AzureIoTClient 25:a35763780a87 190 }
AzureIoTClient 25:a35763780a87 191
AzureIoTClient 25:a35763780a87 192 return result;
AzureIoTClient 25:a35763780a87 193 }
AzureIoTClient 25:a35763780a87 194
AzureIoTClient 25:a35763780a87 195 static unsigned int calculate_next_wait_time(RETRY_CONTROL_INSTANCE* retry_control)
AzureIoTClient 25:a35763780a87 196 {
AzureIoTClient 25:a35763780a87 197 unsigned int result;
AzureIoTClient 25:a35763780a87 198
AzureIoTClient 25:a35763780a87 199 // Codes_SRS_IOTHUB_CLIENT_RETRY_CONTROL_09_029: [If `retry_control->policy` is IOTHUB_CLIENT_RETRY_INTERVAL, `calculate_next_wait_time` shall return `retry_control->initial_wait_time_in_secs`]
AzureIoTClient 25:a35763780a87 200 if (retry_control->policy == IOTHUB_CLIENT_RETRY_INTERVAL)
AzureIoTClient 25:a35763780a87 201 {
AzureIoTClient 25:a35763780a87 202 result = retry_control->initial_wait_time_in_secs;
AzureIoTClient 25:a35763780a87 203 }
AzureIoTClient 25:a35763780a87 204 // Codes_SRS_IOTHUB_CLIENT_RETRY_CONTROL_09_030: [If `retry_control->policy` is IOTHUB_CLIENT_RETRY_LINEAR_BACKOFF, `calculate_next_wait_time` shall return (`retry_control->initial_wait_time_in_secs` * (`retry_control->retry_count`))]
AzureIoTClient 25:a35763780a87 205 else if (retry_control->policy == IOTHUB_CLIENT_RETRY_LINEAR_BACKOFF)
AzureIoTClient 25:a35763780a87 206 {
AzureIoTClient 25:a35763780a87 207 result = retry_control->initial_wait_time_in_secs * (retry_control->retry_count);
AzureIoTClient 25:a35763780a87 208 }
AzureIoTClient 25:a35763780a87 209 // Codes_SRS_IOTHUB_CLIENT_RETRY_CONTROL_09_031: [If `retry_control->policy` is IOTHUB_CLIENT_RETRY_EXPONENTIAL_BACKOFF, `calculate_next_wait_time` shall return (pow(2, `retry_control->retry_count` - 1) * `retry_control->initial_wait_time_in_secs`)]
AzureIoTClient 25:a35763780a87 210 else if (retry_control->policy == IOTHUB_CLIENT_RETRY_EXPONENTIAL_BACKOFF)
AzureIoTClient 25:a35763780a87 211 {
AzureIoTClient 25:a35763780a87 212 result = (unsigned int)(pow(2, retry_control->retry_count - 1) * retry_control->initial_wait_time_in_secs);
AzureIoTClient 25:a35763780a87 213 }
AzureIoTClient 25:a35763780a87 214 // Codes_SRS_IOTHUB_CLIENT_RETRY_CONTROL_09_032: [If `retry_control->policy` is IOTHUB_CLIENT_RETRY_EXPONENTIAL_BACKOFF_WITH_JITTER, `calculate_next_wait_time` shall return ((pow(2, `retry_control->retry_count` - 1) * `retry_control->initial_wait_time_in_secs`) * (1 + (`retry_control->max_jitter_percent` / 100) * (rand() / RAND_MAX)))]
AzureIoTClient 25:a35763780a87 215 else if (retry_control->policy == IOTHUB_CLIENT_RETRY_EXPONENTIAL_BACKOFF_WITH_JITTER)
AzureIoTClient 25:a35763780a87 216 {
AzureIoTClient 25:a35763780a87 217 double jitter_percent = (retry_control->max_jitter_percent / 100.0) * (rand() / ((double)RAND_MAX));
AzureIoTClient 25:a35763780a87 218
AzureIoTClient 25:a35763780a87 219 result = (unsigned int)(pow(2, retry_control->retry_count - 1) * retry_control->initial_wait_time_in_secs * (1 + jitter_percent));
AzureIoTClient 25:a35763780a87 220 }
AzureIoTClient 25:a35763780a87 221 // Codes_SRS_IOTHUB_CLIENT_RETRY_CONTROL_09_033: [If `retry_control->policy` is IOTHUB_CLIENT_RETRY_RANDOM, `calculate_next_wait_time` shall return (`retry_control->initial_wait_time_in_secs` * (rand() / RAND_MAX))]
AzureIoTClient 25:a35763780a87 222 else if (retry_control->policy == IOTHUB_CLIENT_RETRY_RANDOM)
AzureIoTClient 25:a35763780a87 223 {
AzureIoTClient 25:a35763780a87 224 double random_percent = ((double)rand() / (double)RAND_MAX);
AzureIoTClient 25:a35763780a87 225 result = (unsigned int)(retry_control->initial_wait_time_in_secs * random_percent);
AzureIoTClient 25:a35763780a87 226 }
AzureIoTClient 25:a35763780a87 227 else
AzureIoTClient 25:a35763780a87 228 {
AzureIoTClient 25:a35763780a87 229 LogError("Failed to calculate the next wait time (policy %d is not expected)", retry_control->policy);
AzureIoTClient 25:a35763780a87 230
AzureIoTClient 25:a35763780a87 231 result = 0;
AzureIoTClient 25:a35763780a87 232 }
AzureIoTClient 25:a35763780a87 233
AzureIoTClient 25:a35763780a87 234 return result;
AzureIoTClient 25:a35763780a87 235 }
AzureIoTClient 25:a35763780a87 236
AzureIoTClient 25:a35763780a87 237
AzureIoTClient 25:a35763780a87 238 // ========== Public API ========== //
AzureIoTClient 25:a35763780a87 239
AzureIoTClient 25:a35763780a87 240 int is_timeout_reached(time_t start_time, unsigned int timeout_in_secs, bool* is_timed_out)
AzureIoTClient 25:a35763780a87 241 {
AzureIoTClient 25:a35763780a87 242 int result;
AzureIoTClient 25:a35763780a87 243
AzureIoTClient 25:a35763780a87 244 // Codes_SRS_IOTHUB_CLIENT_RETRY_CONTROL_09_057: [If `start_time` is INDEFINITE_TIME, `is_timeout_reached` shall fail and return non-zero]
AzureIoTClient 25:a35763780a87 245 if (start_time == INDEFINITE_TIME)
AzureIoTClient 25:a35763780a87 246 {
AzureIoTClient 25:a35763780a87 247 LogError("Failed to verify timeout (start_time is INDEFINITE)");
AzureIoTClient 25:a35763780a87 248 result = __FAILURE__;
AzureIoTClient 25:a35763780a87 249 }
AzureIoTClient 25:a35763780a87 250 // Codes_SRS_IOTHUB_CLIENT_RETRY_CONTROL_09_058: [If `is_timed_out` is NULL, `is_timeout_reached` shall fail and return non-zero]
AzureIoTClient 25:a35763780a87 251 else if (is_timed_out == NULL)
AzureIoTClient 25:a35763780a87 252 {
AzureIoTClient 25:a35763780a87 253 LogError("Failed to verify timeout (is_timed_out is NULL)");
AzureIoTClient 25:a35763780a87 254 result = __FAILURE__;
AzureIoTClient 25:a35763780a87 255 }
AzureIoTClient 25:a35763780a87 256 else
AzureIoTClient 25:a35763780a87 257 {
AzureIoTClient 25:a35763780a87 258 time_t current_time;
AzureIoTClient 25:a35763780a87 259
AzureIoTClient 25:a35763780a87 260 // Codes_SRS_IOTHUB_CLIENT_RETRY_CONTROL_09_059: [`is_timeout_reached` shall obtain the `current_time` using get_time()]
AzureIoTClient 25:a35763780a87 261 if ((current_time = get_time(NULL)) == INDEFINITE_TIME)
AzureIoTClient 25:a35763780a87 262 {
AzureIoTClient 25:a35763780a87 263 // Codes_SRS_IOTHUB_CLIENT_RETRY_CONTROL_09_060: [If get_time() fails, `is_timeout_reached` shall fail and return non-zero]
AzureIoTClient 25:a35763780a87 264 LogError("Failed to verify timeout (get_time failed)");
AzureIoTClient 25:a35763780a87 265 result = __FAILURE__;
AzureIoTClient 25:a35763780a87 266 }
AzureIoTClient 25:a35763780a87 267 else
AzureIoTClient 25:a35763780a87 268 {
AzureIoTClient 25:a35763780a87 269 // Codes_SRS_IOTHUB_CLIENT_RETRY_CONTROL_09_061: [If (`current_time` - `start_time`) is greater or equal to `timeout_in_secs`, `is_timed_out` shall be set to true]
AzureIoTClient 25:a35763780a87 270 if (get_difftime(current_time, start_time) >= timeout_in_secs)
AzureIoTClient 25:a35763780a87 271 {
AzureIoTClient 25:a35763780a87 272 *is_timed_out = true;
AzureIoTClient 25:a35763780a87 273 }
AzureIoTClient 25:a35763780a87 274 // Codes_SRS_IOTHUB_CLIENT_RETRY_CONTROL_09_062: [If (`current_time` - `start_time`) is less than `timeout_in_secs`, `is_timed_out` shall be set to false]
AzureIoTClient 25:a35763780a87 275 else
AzureIoTClient 25:a35763780a87 276 {
AzureIoTClient 25:a35763780a87 277 *is_timed_out = false;
AzureIoTClient 25:a35763780a87 278 }
AzureIoTClient 25:a35763780a87 279
AzureIoTClient 25:a35763780a87 280 // Codes_SRS_IOTHUB_CLIENT_RETRY_CONTROL_09_063: [If no errors occur, `is_timeout_reached` shall return 0]
AzureIoTClient 25:a35763780a87 281 result = RESULT_OK;
AzureIoTClient 25:a35763780a87 282 }
AzureIoTClient 25:a35763780a87 283 }
AzureIoTClient 25:a35763780a87 284
AzureIoTClient 25:a35763780a87 285 return result;
AzureIoTClient 25:a35763780a87 286 }
AzureIoTClient 25:a35763780a87 287
AzureIoTClient 25:a35763780a87 288 void retry_control_reset(RETRY_CONTROL_HANDLE retry_control_handle)
AzureIoTClient 25:a35763780a87 289 {
AzureIoTClient 25:a35763780a87 290 // Codes_SRS_IOTHUB_CLIENT_RETRY_CONTROL_09_034: [If `retry_control_handle` is NULL, `retry_control_reset` shall return]
AzureIoTClient 25:a35763780a87 291 if (retry_control_handle == NULL)
AzureIoTClient 25:a35763780a87 292 {
AzureIoTClient 25:a35763780a87 293 LogError("Failed to reset the retry control (retry_state_handle is NULL)");
AzureIoTClient 25:a35763780a87 294 }
AzureIoTClient 25:a35763780a87 295 else
AzureIoTClient 25:a35763780a87 296 {
AzureIoTClient 25:a35763780a87 297 RETRY_CONTROL_INSTANCE* retry_control = (RETRY_CONTROL_INSTANCE*)retry_control_handle;
AzureIoTClient 25:a35763780a87 298
AzureIoTClient 25:a35763780a87 299 // Codes_SRS_IOTHUB_CLIENT_RETRY_CONTROL_09_035: [`retry_control` shall have fields `retry_count` and `current_wait_time_in_secs` set to 0 (zero), `first_retry_time` and `last_retry_time` set to INDEFINITE_TIME]
AzureIoTClient 25:a35763780a87 300 retry_control->retry_count = 0;
AzureIoTClient 25:a35763780a87 301 retry_control->current_wait_time_in_secs = 0;
AzureIoTClient 25:a35763780a87 302 retry_control->first_retry_time = INDEFINITE_TIME;
AzureIoTClient 25:a35763780a87 303 retry_control->last_retry_time = INDEFINITE_TIME;
AzureIoTClient 25:a35763780a87 304 }
AzureIoTClient 25:a35763780a87 305 }
AzureIoTClient 25:a35763780a87 306
AzureIoTClient 25:a35763780a87 307 RETRY_CONTROL_HANDLE retry_control_create(IOTHUB_CLIENT_RETRY_POLICY policy, unsigned int max_retry_time_in_secs)
AzureIoTClient 25:a35763780a87 308 {
AzureIoTClient 25:a35763780a87 309 RETRY_CONTROL_INSTANCE* retry_control;
AzureIoTClient 25:a35763780a87 310
AzureIoTClient 25:a35763780a87 311 // Codes_SRS_IOTHUB_CLIENT_RETRY_CONTROL_09_002: [`retry_control_create` shall allocate memory for the retry control instance structure (a.k.a. `retry_control`)]
AzureIoTClient 25:a35763780a87 312 if ((retry_control = (RETRY_CONTROL_INSTANCE*)malloc(sizeof(RETRY_CONTROL_INSTANCE))) == NULL)
AzureIoTClient 25:a35763780a87 313 {
AzureIoTClient 25:a35763780a87 314 // Codes_SRS_IOTHUB_CLIENT_RETRY_CONTROL_09_003: [If malloc fails, `retry_control_create` shall fail and return NULL]
AzureIoTClient 25:a35763780a87 315 LogError("Failed creating the retry control (malloc failed)");
AzureIoTClient 25:a35763780a87 316 }
AzureIoTClient 25:a35763780a87 317 else
AzureIoTClient 25:a35763780a87 318 {
AzureIoTClient 25:a35763780a87 319 // Codes_SRS_IOTHUB_CLIENT_RETRY_CONTROL_09_004: [The parameters passed to `retry_control_create` shall be saved into `retry_control`]
AzureIoTClient 25:a35763780a87 320 memset(retry_control, 0, sizeof(RETRY_CONTROL_INSTANCE));
AzureIoTClient 25:a35763780a87 321 retry_control->policy = policy;
AzureIoTClient 25:a35763780a87 322 retry_control->max_retry_time_in_secs = max_retry_time_in_secs;
AzureIoTClient 25:a35763780a87 323
AzureIoTClient 25:a35763780a87 324 // Codes_SRS_IOTHUB_CLIENT_RETRY_CONTROL_09_005: [If `policy` is IOTHUB_CLIENT_RETRY_EXPONENTIAL_BACKOFF or IOTHUB_CLIENT_RETRY_EXPONENTIAL_BACKOFF_WITH_JITTER, `retry_control->initial_wait_time_in_secs` shall be set to 1]
AzureIoTClient 25:a35763780a87 325 if (retry_control->policy == IOTHUB_CLIENT_RETRY_EXPONENTIAL_BACKOFF ||
AzureIoTClient 25:a35763780a87 326 retry_control->policy == IOTHUB_CLIENT_RETRY_EXPONENTIAL_BACKOFF_WITH_JITTER)
AzureIoTClient 25:a35763780a87 327 {
AzureIoTClient 25:a35763780a87 328 retry_control->initial_wait_time_in_secs = 1;
AzureIoTClient 25:a35763780a87 329 }
AzureIoTClient 25:a35763780a87 330 // Codes_SRS_IOTHUB_CLIENT_RETRY_CONTROL_09_006: [Otherwise `retry_control->initial_wait_time_in_secs` shall be set to 5]
AzureIoTClient 25:a35763780a87 331 else
AzureIoTClient 25:a35763780a87 332 {
AzureIoTClient 25:a35763780a87 333 retry_control->initial_wait_time_in_secs = 5;
AzureIoTClient 25:a35763780a87 334 }
AzureIoTClient 25:a35763780a87 335
AzureIoTClient 25:a35763780a87 336 // Codes_SRS_IOTHUB_CLIENT_RETRY_CONTROL_09_007: [`retry_control->max_jitter_percent` shall be set to 5]
AzureIoTClient 25:a35763780a87 337 retry_control->max_jitter_percent = 5;
AzureIoTClient 25:a35763780a87 338
AzureIoTClient 25:a35763780a87 339 // Codes_SRS_IOTHUB_CLIENT_RETRY_CONTROL_09_008: [The remaining fields in `retry_control` shall be initialized according to retry_control_reset()]
AzureIoTClient 25:a35763780a87 340 retry_control_reset(retry_control);
AzureIoTClient 25:a35763780a87 341 }
AzureIoTClient 25:a35763780a87 342
AzureIoTClient 25:a35763780a87 343 // Codes_SRS_IOTHUB_CLIENT_RETRY_CONTROL_09_009: [If no errors occur, `retry_control_create` shall return a handle to `retry_control`]
AzureIoTClient 25:a35763780a87 344 return (RETRY_CONTROL_HANDLE)retry_control;
AzureIoTClient 25:a35763780a87 345 }
AzureIoTClient 25:a35763780a87 346
AzureIoTClient 25:a35763780a87 347 void retry_control_destroy(RETRY_CONTROL_HANDLE retry_control_handle)
AzureIoTClient 25:a35763780a87 348 {
AzureIoTClient 25:a35763780a87 349 // Codes_SRS_IOTHUB_CLIENT_RETRY_CONTROL_09_055: [If `retry_control_handle` is NULL, `retry_control_destroy` shall return]
AzureIoTClient 25:a35763780a87 350 if (retry_control_handle == NULL)
AzureIoTClient 25:a35763780a87 351 {
AzureIoTClient 25:a35763780a87 352 LogError("Failed to destroy the retry control (retry_control_handle is NULL)");
AzureIoTClient 25:a35763780a87 353 }
AzureIoTClient 25:a35763780a87 354 else
AzureIoTClient 25:a35763780a87 355 {
AzureIoTClient 25:a35763780a87 356 // Codes_SRS_IOTHUB_CLIENT_RETRY_CONTROL_09_056: [`retry_control_destroy` shall destroy `retry_control_handle` using free()]
AzureIoTClient 25:a35763780a87 357 free(retry_control_handle);
AzureIoTClient 25:a35763780a87 358 }
AzureIoTClient 25:a35763780a87 359 }
AzureIoTClient 25:a35763780a87 360
AzureIoTClient 25:a35763780a87 361 int retry_control_should_retry(RETRY_CONTROL_HANDLE retry_control_handle, RETRY_ACTION* retry_action)
AzureIoTClient 25:a35763780a87 362 {
AzureIoTClient 25:a35763780a87 363 int result;
AzureIoTClient 25:a35763780a87 364
AzureIoTClient 25:a35763780a87 365 // Codes_SRS_IOTHUB_CLIENT_RETRY_CONTROL_09_010: [If `retry_control_handle` or `retry_action` are NULL, `retry_control_should_retry` shall fail and return non-zero]
AzureIoTClient 25:a35763780a87 366 if ((retry_control_handle == NULL) || (retry_action == NULL))
AzureIoTClient 25:a35763780a87 367 {
AzureIoTClient 25:a35763780a87 368 LogError("Failed to evaluate if retry should be attempted (either retry_control_handle (%p) or retry_action (%p) are NULL)", retry_control_handle, retry_action);
AzureIoTClient 25:a35763780a87 369 result = __FAILURE__;
AzureIoTClient 25:a35763780a87 370 }
AzureIoTClient 25:a35763780a87 371 else
AzureIoTClient 25:a35763780a87 372 {
AzureIoTClient 25:a35763780a87 373 RETRY_CONTROL_INSTANCE* retry_control = (RETRY_CONTROL_INSTANCE*)retry_control_handle;
AzureIoTClient 25:a35763780a87 374
AzureIoTClient 25:a35763780a87 375 // Codes_SRS_IOTHUB_CLIENT_RETRY_CONTROL_09_027: [If `retry_control->policy` is IOTHUB_CLIENT_RETRY_NONE, retry_action shall be set to RETRY_ACTION_STOP_RETRYING and return immediatelly with result 0]
AzureIoTClient 25:a35763780a87 376 if (retry_control->policy == IOTHUB_CLIENT_RETRY_NONE)
AzureIoTClient 25:a35763780a87 377 {
AzureIoTClient 25:a35763780a87 378 *retry_action = RETRY_ACTION_STOP_RETRYING;
AzureIoTClient 25:a35763780a87 379 result = RESULT_OK;
AzureIoTClient 25:a35763780a87 380 }
AzureIoTClient 25:a35763780a87 381 // Codes_SRS_IOTHUB_CLIENT_RETRY_CONTROL_09_011: [If `retry_control->first_retry_time` is INDEFINITE_TIME, it shall be set using get_time()]
AzureIoTClient 25:a35763780a87 382 else if (retry_control->first_retry_time == INDEFINITE_TIME && (retry_control->first_retry_time = get_time(NULL)) == INDEFINITE_TIME)
AzureIoTClient 25:a35763780a87 383 {
AzureIoTClient 25:a35763780a87 384 // Codes_SRS_IOTHUB_CLIENT_RETRY_CONTROL_09_012: [If get_time() fails, `retry_control_should_retry` shall fail and return non-zero]
AzureIoTClient 25:a35763780a87 385 LogError("Failed to evaluate if retry should be attempted (get_time() failed)");
AzureIoTClient 25:a35763780a87 386 result = __FAILURE__;
AzureIoTClient 25:a35763780a87 387 }
AzureIoTClient 25:a35763780a87 388 // Codes_SRS_IOTHUB_CLIENT_RETRY_CONTROL_09_013: [evaluate_retry_action() shall be invoked]
AzureIoTClient 25:a35763780a87 389 else if (evaluate_retry_action(retry_control, retry_action) != RESULT_OK)
AzureIoTClient 25:a35763780a87 390 {
AzureIoTClient 25:a35763780a87 391 // Codes_SRS_IOTHUB_CLIENT_RETRY_CONTROL_09_014: [If evaluate_retry_action() fails, `retry_control_should_retry` shall fail and return non-zero]
AzureIoTClient 25:a35763780a87 392 LogError("Failed to evaluate if retry should be attempted (evaluate_retry_action() failed)");
AzureIoTClient 25:a35763780a87 393 result = __FAILURE__;
AzureIoTClient 25:a35763780a87 394 }
AzureIoTClient 25:a35763780a87 395 else
AzureIoTClient 25:a35763780a87 396 {
AzureIoTClient 25:a35763780a87 397 if (*retry_action == RETRY_ACTION_RETRY_NOW)
AzureIoTClient 25:a35763780a87 398 {
AzureIoTClient 25:a35763780a87 399 // Codes_SRS_IOTHUB_CLIENT_RETRY_CONTROL_09_015: [If `retry_action` is set to RETRY_ACTION_RETRY_NOW, `retry_control->retry_count` shall be incremented by 1]
AzureIoTClient 25:a35763780a87 400 retry_control->retry_count++;
AzureIoTClient 25:a35763780a87 401
AzureIoTClient 25:a35763780a87 402 if (retry_control->policy != IOTHUB_CLIENT_RETRY_IMMEDIATE)
AzureIoTClient 25:a35763780a87 403 {
AzureIoTClient 25:a35763780a87 404 // Codes_SRS_IOTHUB_CLIENT_RETRY_CONTROL_09_016: [If `retry_action` is set to RETRY_ACTION_RETRY_NOW and policy is not IOTHUB_CLIENT_RETRY_IMMEDIATE, `retry_control->last_retry_time` shall be set using get_time()]
AzureIoTClient 25:a35763780a87 405 retry_control->last_retry_time = get_time(NULL);
AzureIoTClient 25:a35763780a87 406
AzureIoTClient 25:a35763780a87 407 // Codes_SRS_IOTHUB_CLIENT_RETRY_CONTROL_09_017: [If `retry_action` is set to RETRY_ACTION_RETRY_NOW and policy is not IOTHUB_CLIENT_RETRY_IMMEDIATE, `retry_control->current_wait_time_in_secs` shall be set using calculate_next_wait_time()]
AzureIoTClient 25:a35763780a87 408 retry_control->current_wait_time_in_secs = calculate_next_wait_time(retry_control);
AzureIoTClient 25:a35763780a87 409 }
AzureIoTClient 25:a35763780a87 410 }
AzureIoTClient 25:a35763780a87 411
AzureIoTClient 25:a35763780a87 412 // Codes_SRS_IOTHUB_CLIENT_RETRY_CONTROL_09_018: [If no errors occur, `retry_control_should_retry` shall return 0]
AzureIoTClient 25:a35763780a87 413 result = RESULT_OK;
AzureIoTClient 25:a35763780a87 414 }
AzureIoTClient 25:a35763780a87 415 }
AzureIoTClient 25:a35763780a87 416
AzureIoTClient 25:a35763780a87 417 return result;
AzureIoTClient 25:a35763780a87 418 }
AzureIoTClient 25:a35763780a87 419
AzureIoTClient 25:a35763780a87 420 int retry_control_set_option(RETRY_CONTROL_HANDLE retry_control_handle, const char* name, const void* value)
AzureIoTClient 25:a35763780a87 421 {
AzureIoTClient 25:a35763780a87 422 int result;
AzureIoTClient 25:a35763780a87 423
AzureIoTClient 25:a35763780a87 424 // Codes_SRS_IOTHUB_CLIENT_RETRY_CONTROL_09_036: [If `retry_control_handle`, `name` or `value` are NULL, `retry_control_set_option` shall fail and return non-zero]
AzureIoTClient 25:a35763780a87 425 if (retry_control_handle == NULL || name == NULL || value == NULL)
AzureIoTClient 25:a35763780a87 426 {
AzureIoTClient 25:a35763780a87 427 LogError("Failed to set option (either retry_state_handle (%p), name (%p) or value (%p) are NULL)", retry_control_handle, name, value);
AzureIoTClient 25:a35763780a87 428 result = __FAILURE__;
AzureIoTClient 25:a35763780a87 429 }
AzureIoTClient 25:a35763780a87 430 else
AzureIoTClient 25:a35763780a87 431 {
AzureIoTClient 25:a35763780a87 432 RETRY_CONTROL_INSTANCE* retry_control = (RETRY_CONTROL_INSTANCE*)retry_control_handle;
AzureIoTClient 25:a35763780a87 433
AzureIoTClient 25:a35763780a87 434 if (strcmp(RETRY_CONTROL_OPTION_INITIAL_WAIT_TIME_IN_SECS, name) == 0)
AzureIoTClient 25:a35763780a87 435 {
AzureIoTClient 25:a35763780a87 436 unsigned int cast_value = *((unsigned int*)value);
AzureIoTClient 25:a35763780a87 437
AzureIoTClient 25:a35763780a87 438 // Codes_SRS_IOTHUB_CLIENT_RETRY_CONTROL_09_037: [If `name` is "initial_wait_time_in_secs" and `value` is less than 1, `retry_control_set_option` shall fail and return non-zero]
AzureIoTClient 25:a35763780a87 439 if (cast_value < 1)
AzureIoTClient 25:a35763780a87 440 {
AzureIoTClient 25:a35763780a87 441 LogError("Failed to set option '%s' (value must be equal or greater to 1)", name);
AzureIoTClient 25:a35763780a87 442 result = __FAILURE__;
AzureIoTClient 25:a35763780a87 443 }
AzureIoTClient 25:a35763780a87 444 else
AzureIoTClient 25:a35763780a87 445 {
AzureIoTClient 25:a35763780a87 446 // Codes_SRS_IOTHUB_CLIENT_RETRY_CONTROL_09_038: [If `name` is "initial_wait_time_in_secs", `value` shall be saved on `retry_control->initial_wait_time_in_secs`]
AzureIoTClient 25:a35763780a87 447 retry_control->initial_wait_time_in_secs = cast_value;
AzureIoTClient 25:a35763780a87 448
AzureIoTClient 25:a35763780a87 449 // Codes_SRS_IOTHUB_CLIENT_RETRY_CONTROL_09_044: [If no errors occur, retry_control_set_option shall return 0]
AzureIoTClient 25:a35763780a87 450 result = RESULT_OK;
AzureIoTClient 25:a35763780a87 451 }
AzureIoTClient 25:a35763780a87 452 }
AzureIoTClient 25:a35763780a87 453 else if (strcmp(RETRY_CONTROL_OPTION_MAX_JITTER_PERCENT, name) == 0)
AzureIoTClient 25:a35763780a87 454 {
AzureIoTClient 25:a35763780a87 455 unsigned int cast_value = *((unsigned int*)value);
AzureIoTClient 25:a35763780a87 456
AzureIoTClient 25:a35763780a87 457 // Codes_SRS_IOTHUB_CLIENT_RETRY_CONTROL_09_039: [If `name` is "max_jitter_percent" and `value` is less than 0 or greater than 100, `retry_control_set_option` shall fail and return non-zero]
AzureIoTClient 25:a35763780a87 458 if (cast_value > 100) // it's unsigned int, it doesn't need to be checked for less than zero.
AzureIoTClient 25:a35763780a87 459 {
AzureIoTClient 25:a35763780a87 460 LogError("Failed to set option '%s' (value must be in the range 0 to 100)", name);
AzureIoTClient 25:a35763780a87 461 result = __FAILURE__;
AzureIoTClient 25:a35763780a87 462 }
AzureIoTClient 25:a35763780a87 463 else
AzureIoTClient 25:a35763780a87 464 {
AzureIoTClient 25:a35763780a87 465 // Codes_SRS_IOTHUB_CLIENT_RETRY_CONTROL_09_040: [If `name` is "max_jitter_percent", value shall be saved on `retry_control->max_jitter_percent`]
AzureIoTClient 25:a35763780a87 466 retry_control->max_jitter_percent = cast_value;
AzureIoTClient 25:a35763780a87 467
AzureIoTClient 25:a35763780a87 468 // Codes_SRS_IOTHUB_CLIENT_RETRY_CONTROL_09_044: [If no errors occur, retry_control_set_option shall return 0]
AzureIoTClient 25:a35763780a87 469 result = RESULT_OK;
AzureIoTClient 25:a35763780a87 470 }
AzureIoTClient 25:a35763780a87 471 }
AzureIoTClient 25:a35763780a87 472 else if (strcmp(RETRY_CONTROL_OPTION_SAVED_OPTIONS, name) == 0)
AzureIoTClient 25:a35763780a87 473 {
AzureIoTClient 25:a35763780a87 474 // Codes_SRS_IOTHUB_CLIENT_RETRY_CONTROL_09_041: [If `name` is "retry_control_options", value shall be fed to `retry_control` using OptionHandler_FeedOptions]
AzureIoTClient 25:a35763780a87 475 if (OptionHandler_FeedOptions((OPTIONHANDLER_HANDLE)value, retry_control_handle) != OPTIONHANDLER_OK)
AzureIoTClient 25:a35763780a87 476 {
AzureIoTClient 25:a35763780a87 477 // Codes_SRS_IOTHUB_CLIENT_RETRY_CONTROL_09_042: [If OptionHandler_FeedOptions fails, `retry_control_set_option` shall fail and return non-zero]
AzureIoTClient 25:a35763780a87 478 LogError("messenger_set_option failed (OptionHandler_FeedOptions failed)");
AzureIoTClient 25:a35763780a87 479 result = __FAILURE__;
AzureIoTClient 25:a35763780a87 480 }
AzureIoTClient 25:a35763780a87 481 else
AzureIoTClient 25:a35763780a87 482 {
AzureIoTClient 25:a35763780a87 483 // Codes_SRS_IOTHUB_CLIENT_RETRY_CONTROL_09_044: [If no errors occur, `retry_control_set_option` shall return 0]
AzureIoTClient 25:a35763780a87 484 result = RESULT_OK;
AzureIoTClient 25:a35763780a87 485 }
AzureIoTClient 25:a35763780a87 486 }
AzureIoTClient 25:a35763780a87 487 // Codes_SRS_IOTHUB_CLIENT_RETRY_CONTROL_09_043: [If `name` is not a supported option, `retry_control_set_option` shall fail and return non-zero]
AzureIoTClient 25:a35763780a87 488 else
AzureIoTClient 25:a35763780a87 489 {
AzureIoTClient 25:a35763780a87 490 LogError("messenger_set_option failed (option with name '%s' is not suppported)", name);
AzureIoTClient 25:a35763780a87 491 result = __FAILURE__;
AzureIoTClient 25:a35763780a87 492 }
AzureIoTClient 25:a35763780a87 493 }
AzureIoTClient 25:a35763780a87 494
AzureIoTClient 25:a35763780a87 495 return result;
AzureIoTClient 25:a35763780a87 496 }
AzureIoTClient 25:a35763780a87 497
AzureIoTClient 25:a35763780a87 498 OPTIONHANDLER_HANDLE retry_control_retrieve_options(RETRY_CONTROL_HANDLE retry_control_handle)
AzureIoTClient 25:a35763780a87 499 {
AzureIoTClient 25:a35763780a87 500 OPTIONHANDLER_HANDLE result;
AzureIoTClient 25:a35763780a87 501
AzureIoTClient 25:a35763780a87 502 // Codes_SRS_IOTHUB_CLIENT_RETRY_CONTROL_09_045: [If `retry_control_handle`, `retry_control_retrieve_options` shall fail and return NULL]
AzureIoTClient 25:a35763780a87 503 if (retry_control_handle == NULL)
AzureIoTClient 25:a35763780a87 504 {
AzureIoTClient 25:a35763780a87 505 LogError("Failed to retrieve options (retry_state_handle is NULL)");
AzureIoTClient 25:a35763780a87 506 result = NULL;
AzureIoTClient 25:a35763780a87 507 }
AzureIoTClient 25:a35763780a87 508 else
AzureIoTClient 25:a35763780a87 509 {
AzureIoTClient 25:a35763780a87 510 // Codes_SRS_IOTHUB_CLIENT_RETRY_CONTROL_09_046: [An instance of OPTIONHANDLER_HANDLE (a.k.a. `options`) shall be created using OptionHandler_Create]
AzureIoTClient 25:a35763780a87 511 OPTIONHANDLER_HANDLE options = OptionHandler_Create(retry_control_clone_option, retry_control_destroy_option, (pfSetOption)retry_control_set_option);
AzureIoTClient 25:a35763780a87 512
AzureIoTClient 25:a35763780a87 513 if (options == NULL)
AzureIoTClient 25:a35763780a87 514 {
AzureIoTClient 25:a35763780a87 515 // Codes_SRS_IOTHUB_CLIENT_RETRY_CONTROL_09_047: [If OptionHandler_Create fails, `retry_control_retrieve_options` shall fail and return NULL]
AzureIoTClient 25:a35763780a87 516 LogError("Failed to retrieve options (OptionHandler_Create failed)");
AzureIoTClient 25:a35763780a87 517 result = NULL;
AzureIoTClient 25:a35763780a87 518 }
AzureIoTClient 25:a35763780a87 519 else
AzureIoTClient 25:a35763780a87 520 {
AzureIoTClient 25:a35763780a87 521 RETRY_CONTROL_INSTANCE* retry_control = (RETRY_CONTROL_INSTANCE*)retry_control_handle;
AzureIoTClient 25:a35763780a87 522
AzureIoTClient 25:a35763780a87 523 // Codes_SRS_IOTHUB_CLIENT_RETRY_CONTROL_09_050: [`retry_control->initial_wait_time_in_secs` shall be added to `options` using OptionHandler_Add]
AzureIoTClient 25:a35763780a87 524 if (OptionHandler_AddOption(options, RETRY_CONTROL_OPTION_INITIAL_WAIT_TIME_IN_SECS, (void*)&retry_control->initial_wait_time_in_secs) != OPTIONHANDLER_OK)
AzureIoTClient 25:a35763780a87 525 {
AzureIoTClient 25:a35763780a87 526 // Codes_SRS_IOTHUB_CLIENT_RETRY_CONTROL_09_052: [If any call to OptionHandler_Add fails, `retry_control_retrieve_options` shall fail and return NULL]
AzureIoTClient 25:a35763780a87 527 LogError("Failed to retrieve options (OptionHandler_Create failed for option '%s')", RETRY_CONTROL_OPTION_INITIAL_WAIT_TIME_IN_SECS);
AzureIoTClient 25:a35763780a87 528 result = NULL;
AzureIoTClient 25:a35763780a87 529 }
AzureIoTClient 25:a35763780a87 530 // Codes_SRS_IOTHUB_CLIENT_RETRY_CONTROL_09_051: [`retry_control->max_jitter_percent` shall be added to `options` using OptionHandler_Add]
AzureIoTClient 25:a35763780a87 531 else if (OptionHandler_AddOption(options, RETRY_CONTROL_OPTION_MAX_JITTER_PERCENT, (void*)&retry_control->max_jitter_percent) != OPTIONHANDLER_OK)
AzureIoTClient 25:a35763780a87 532 {
AzureIoTClient 25:a35763780a87 533 // Codes_SRS_IOTHUB_CLIENT_RETRY_CONTROL_09_052: [If any call to OptionHandler_Add fails, `retry_control_retrieve_options` shall fail and return NULL]
AzureIoTClient 25:a35763780a87 534 LogError("Failed to retrieve options (OptionHandler_Create failed for option '%s')", RETRY_CONTROL_OPTION_INITIAL_WAIT_TIME_IN_SECS);
AzureIoTClient 25:a35763780a87 535 result = NULL;
AzureIoTClient 25:a35763780a87 536 }
AzureIoTClient 25:a35763780a87 537 else
AzureIoTClient 25:a35763780a87 538 {
AzureIoTClient 25:a35763780a87 539 // Codes_SRS_IOTHUB_CLIENT_RETRY_CONTROL_09_054: [If no errors occur, `retry_control_retrieve_options` shall return the OPTIONHANDLER_HANDLE instance]
AzureIoTClient 25:a35763780a87 540 result = options;
AzureIoTClient 25:a35763780a87 541 }
AzureIoTClient 25:a35763780a87 542
AzureIoTClient 25:a35763780a87 543 if (result == NULL)
AzureIoTClient 25:a35763780a87 544 {
AzureIoTClient 25:a35763780a87 545 // Codes_SRS_IOTHUB_CLIENT_RETRY_CONTROL_09_053: [If any failures occur, `retry_control_retrieve_options` shall release any memory it has allocated]
AzureIoTClient 25:a35763780a87 546 OptionHandler_Destroy(options);
AzureIoTClient 25:a35763780a87 547 }
AzureIoTClient 25:a35763780a87 548 }
AzureIoTClient 25:a35763780a87 549 }
AzureIoTClient 25:a35763780a87 550
AzureIoTClient 25:a35763780a87 551 return result;
AzureIoTClient 25:a35763780a87 552 }