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