source: azure_iot_hub_riscv/trunk/azure_iot_sdk/iothub_client/src/iothub_client_retry_control.c@ 453

Last change on this file since 453 was 453, checked in by coas-nagasima, 4 years ago

ファイルを追加

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