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:
Tue Sep 11 11:12:42 2018 -0700
Revision:
41:410450f16a9f
Parent:
39:6231984e0179
1.2.9

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