Microsoft Azure IoTHub client MQTT transport
Dependents: STM32F746_iothub_client_sample_mqtt FXOS8700CQ_To_Azure_IoT f767zi_mqtt FXOS8700CQ_To_Azure_IoT ... more
iothub_client_retry_control.c@25:a35763780a87, 2017-07-28 (annotated)
- 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?
User | Revision | Line number | New 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 | } |