Xin Zhang / azure-iot-c-sdk-f767zi

Dependents:   samplemqtt

Committer:
XinZhangMS
Date:
Thu Aug 23 06:52:14 2018 +0000
Revision:
0:f7f1f0d76dd6
azure-c-sdk for mbed os supporting NUCLEO_F767ZI

Who changed what in which revision?

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