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