Skip to content

Commit 8a9a665

Browse files
authored
Simplify API by removing RNG interface (#8)
To improve usability of API, the existing BackoffAlgorithm_RNG_t interface for passing a random number generator function to the library is removed in this PR. This helps avoid the need of "wrappers" around platform-specific RNGs to pass to the library. Instead, the application can generate the random number using their platform-specific RNG and just directly pass to the library for calculating the next retry backoff period.
1 parent c5e8198 commit 8a9a665

File tree

6 files changed

+131
-217
lines changed

6 files changed

+131
-217
lines changed

README.md

Lines changed: 24 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
## backOffAlgorithm Library
1+
## backoffAlgorithm Library
22

33
This repository contains the backoffAlgorithm library, a utility library to calculate backoff period for network operation retries (like failed network connection with server) using an exponential backoff with jitter algorithm. The backoffAlgorithm library is distributed under the [MIT Open Source License](LICENSE).
44

@@ -22,6 +22,7 @@ The example below shows how to use the backoffAlgorithm library to retry a DNS r
2222
#include <stdlib.h>
2323
#include <string.h>
2424
#include <netdb.h>
25+
#include <time.h>
2526

2627
/* The maximum number of retries for the example code. */
2728
#define RETRY_MAX_ATTEMPTS ( 5U )
@@ -32,28 +33,6 @@ The example below shows how to use the backoffAlgorithm library to retry a DNS r
3233
/* The base back-off delay (in milliseconds) for retry configuration in the example. */
3334
#define RETRY_BACKOFF_BASE_MS ( 500U )
3435

35-
/**
36-
* A random number generator to provide to the backoffAlgorithm
37-
* library.
38-
*
39-
* This function is used in the exponential backoff with jitter algorithm
40-
* to calculate the backoff value for the next retry attempt.
41-
*
42-
* It is recommended to either use a True Random Number Generator (TRNG) for
43-
* calculation of unique back-off values in devices so that collision between
44-
* devices attempting retries at the same intervals can be avoided.
45-
*
46-
* For the simplicity of the code example, this function is a pseudo
47-
* random number generator.
48-
*
49-
* @return The generated random number. This example function ALWAYS succeeds
50-
* in generating a random number.
51-
*/
52-
static int32_t pseudoRng()
53-
{
54-
return( rand() % ( INT32_MAX ) );
55-
}
56-
5736
int main()
5837
{
5938
/* Variables used in this example. */
@@ -65,6 +44,7 @@ int main()
6544
int32_t dnsStatus = -1;
6645
struct addrinfo hints;
6746
struct addrinfo ** pListHead;
47+
struct timespec tp;
6848

6949
/* Add hints to retrieve only TCP sockets in getaddrinfo. */
7050
( void ) memset( &hints, 0, sizeof( hints ) );
@@ -77,10 +57,19 @@ int main()
7757

7858
/* Initialize reconnect attempts and interval. */
7959
BackoffAlgorithm_InitializeParams( &retryParams,
80-
RETRY_BACKOFF_BASE_MS,
81-
RETRY_MAX_BACKOFF_DELAY_MS,
82-
RETRY_MAX_ATTEMPTS,
83-
pseudoRng );
60+
RETRY_BACKOFF_BASE_MS,
61+
RETRY_MAX_BACKOFF_DELAY_MS,
62+
RETRY_MAX_ATTEMPTS );
63+
64+
65+
/* Seed the pseudo random number generator used in this example (with call to
66+
* rand() function provided by ISO C standard library) for use in backoff period
67+
* calculation when retrying failed DNS resolution. */
68+
69+
/* Get current time to seed pseudo random number generator. */
70+
( void ) clock_gettime( CLOCK_REALTIME, &tp );
71+
/* Seed pseudo random number generator with seconds. */
72+
srand( tp.tv_sec );
8473

8574
do
8675
{
@@ -90,8 +79,14 @@ int main()
9079
/* Retry if DNS resolution query failed. */
9180
if( dnsStatus != 0 )
9281
{
93-
/* Get back-off value (in milliseconds) for the next retry. */
94-
retryStatus = BackoffAlgorithm_GetNextBackoff( &retryParams, &nextRetryBackOff );
82+
/* Generate a random number and get back-off value (in milliseconds) for the next retry.
83+
* Note: It is recommended to use a random number generator that is seeded with
84+
* device-specific entropy source so that backoff calculation in devices is different
85+
* and possibility of network collision between devices attempting retries can be avoided.
86+
*
87+
* For the simplicity of the code example, the pseudo random number generator, rand() function
88+
* is used. */
89+
retryStatus = BackoffAlgorithm_GetNextBackoff( &retryParams, rand(), &nextRetryBackOff );
9590
}
9691
} while( ( dnsStatus != 0 ) && ( retryStatus != BackoffAlgorithmRetriesExhausted ) );
9792

docs/doxygen/pages.dox

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ For a reference example of using the library, refer to the related README sectio
3636

3737
<table>
3838
<tr>
39-
<td colspan="4"><center><b>Code size of backoffAlgorithm library files (sizes generated with [GCC for ARM Cortex-M toolchain](https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm/downloads/9-2020-q2-update))</b></center></td>
39+
<td colspan="4"><center><b>Code size (in bytes) of backoffAlgorithm library files (sizes generated with [GCC for ARM Cortex-M toolchain](https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm/downloads/9-2020-q2-update))</b></center></td>
4040
</tr>
4141
<tr>
4242
<td><b>File</b></td>
@@ -46,9 +46,9 @@ For a reference example of using the library, refer to the related README sectio
4646
</tr>
4747
<tr>
4848
<td>backoff_algorithm.c</td>
49-
<td>0.6K</td>
50-
<td>0.2K</td>
51-
<td>0.2K</td>
49+
<td>678</td>
50+
<td>140</td>
51+
<td>136</td>
5252
</tr>
5353
</table>
5454

@@ -61,13 +61,12 @@ All functions in the backoffAlgorithm library operate only on the buffer provide
6161
local variables on the stack.
6262
</p>
6363

64-
<h3>Random Number Generator</h3>
64+
<h3>Random Number Generation</h3>
6565
<p>
66-
The library requires a platform-specific random number generator for the "jitter"
67-
part of the algorithm when generating the next backoff value. To avoid calculation
68-
of the same random numbers across your fleet of devices attempting retry of network
69-
operations, it is RECOMMENDED to provide a random number generator that is seeded with
70-
an entropy source unique to the device.
66+
The library takes a random number each time it calculates the backoff period value for the
67+
retry attempt. To avoid calculation of the same random numbers across your fleet of devices
68+
attempting retry of network operations, it is RECOMMENDED to generate the random number with
69+
a random number generator that is seeded with an entropy source unique to the device.
7170
</p>
7271

7372
<h3>Compliance & Coverage</h3>

lexicon.txt

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@ api
22
apis
33
aws
44
backoff
5+
backoff
56
backoffalgorithm
7+
backoffalgorithmretriesexhausted
8+
backoffalgorithmrngfailure
9+
backoffalgorithmsuccess
610
backoffbase
711
br
812
com
@@ -13,6 +17,7 @@ getaddrinfo
1317
https
1418
ifndef
1519
inc
20+
ingroup
1621
iot
1722
longjmp
1823
maxattempts
@@ -21,20 +26,17 @@ min
2126
mockrng
2227
noninfringement
2328
param
29+
pcontext
2430
pnextbackoff
2531
pretrycontext
2632
pretryparams
2733
prng
28-
backoffalgorithmretriesexhausted
29-
backoffalgorithmrngfailure
30-
backoffalgorithmsuccess
34+
randomvalue
3135
rng
3236
sdk
3337
shouldn
3438
stderr
3539
sublicense
3640
tcp
37-
utils
38-
ingroup
39-
backoff
40-
pcontext
41+
trng
42+
utils

source/backoff_algorithm.c

Lines changed: 16 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,10 @@
3636
/*-----------------------------------------------------------*/
3737

3838
BackoffAlgorithmStatus_t BackoffAlgorithm_GetNextBackoff( BackoffAlgorithmContext_t * pRetryContext,
39+
uint32_t randomValue,
3940
uint16_t * pNextBackOff )
4041
{
4142
BackoffAlgorithmStatus_t status = BackoffAlgorithmSuccess;
42-
int32_t randomVal = 0;
4343

4444
assert( pRetryContext != NULL );
4545
assert( pNextBackOff != NULL );
@@ -48,34 +48,24 @@ BackoffAlgorithmStatus_t BackoffAlgorithm_GetNextBackoff( BackoffAlgorithmContex
4848
if( ( pRetryContext->attemptsDone < pRetryContext->maxRetryAttempts ) ||
4949
( pRetryContext->maxRetryAttempts == BACKOFF_ALGORITHM_RETRY_FOREVER ) )
5050
{
51-
/* Generate a random number. */
52-
randomVal = pRetryContext->pRng();
51+
/* The next backoff value is a random value between 0 and the maximum jitter value
52+
* for the retry attempt. */
5353

54-
if( randomVal < 0 )
54+
/* Choose a random value for back-off time between 0 and the max jitter value. */
55+
*pNextBackOff = ( uint16_t ) ( randomValue % ( pRetryContext->nextJitterMax + 1U ) );
56+
57+
/* Increment the retry attempt. */
58+
pRetryContext->attemptsDone++;
59+
60+
/* Double the max jitter value for the next retry attempt, only
61+
* if the new value will be less than the max backoff time value. */
62+
if( pRetryContext->nextJitterMax < ( pRetryContext->maxBackoffDelay / 2U ) )
5563
{
56-
status = BackoffAlgorithmRngFailure;
64+
pRetryContext->nextJitterMax += pRetryContext->nextJitterMax;
5765
}
5866
else
5967
{
60-
/* The next backoff value is a random value between 0 and the maximum jitter value
61-
* for the retry attempt. */
62-
63-
/* Choose a random value for back-off time between 0 and the max jitter value. */
64-
*pNextBackOff = ( uint16_t ) ( randomVal % ( pRetryContext->nextJitterMax + 1U ) );
65-
66-
/* Increment the retry attempt. */
67-
pRetryContext->attemptsDone++;
68-
69-
/* Double the max jitter value for the next retry attempt, only
70-
* if the new value will be less than the max backoff time value. */
71-
if( pRetryContext->nextJitterMax < ( pRetryContext->maxBackOffDelay / 2U ) )
72-
{
73-
pRetryContext->nextJitterMax += pRetryContext->nextJitterMax;
74-
}
75-
else
76-
{
77-
pRetryContext->nextJitterMax = pRetryContext->maxBackOffDelay;
78-
}
68+
pRetryContext->nextJitterMax = pRetryContext->maxBackoffDelay;
7969
}
8070
}
8171
else
@@ -94,17 +84,15 @@ BackoffAlgorithmStatus_t BackoffAlgorithm_GetNextBackoff( BackoffAlgorithmContex
9484
void BackoffAlgorithm_InitializeParams( BackoffAlgorithmContext_t * pContext,
9585
uint16_t backOffBase,
9686
uint16_t maxBackOff,
97-
uint32_t maxAttempts,
98-
BackoffAlgorithm_RNG_t pRng )
87+
uint32_t maxAttempts )
9988
{
10089
assert( pContext != NULL );
10190

10291
/* Initialize the context with parameters used in calculating the backoff
10392
* value for the next retry attempt. */
10493
pContext->nextJitterMax = backOffBase;
105-
pContext->maxBackOffDelay = maxBackOff;
94+
pContext->maxBackoffDelay = maxBackOff;
10695
pContext->maxRetryAttempts = maxAttempts;
107-
pContext->pRng = pRng;
10896

10997
/* The total number of retry attempts is zero at initialization. */
11098
pContext->attemptsDone = 0;

source/include/backoff_algorithm.h

Lines changed: 11 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -42,28 +42,13 @@
4242
*/
4343
#define BACKOFF_ALGORITHM_RETRY_FOREVER 0
4444

45-
/**
46-
* @brief Interface for a random number generator.
47-
* The user should supply the platform-specific random number generator to the
48-
* library through the @ref BackoffAlgorithm_InitializeParams API function.
49-
*
50-
* @note It is recommended that a true random number generator is supplied
51-
* to the library. The random number generator should be seeded with an entropy
52-
* source in the system.
53-
*
54-
* @return The random number if successful; otherwise a negative value to indicate
55-
* failure.
56-
*/
57-
typedef int32_t ( * BackoffAlgorithm_RNG_t )();
58-
5945
/**
6046
* @ingroup backoff_algorithm_enum_types
6147
* @brief Status for @ref BackoffAlgorithm_GetNextBackoff.
6248
*/
6349
typedef enum BackoffAlgorithmStatus
6450
{
6551
BackoffAlgorithmSuccess = 0, /**< @brief The function successfully calculated the next back-off value. */
66-
BackoffAlgorithmRngFailure = 1, /**< @brief The function encountered failure in generating random number. */
6752
BackoffAlgorithmRetriesExhausted /**< @brief The function exhausted all retry attempts. */
6853
} BackoffAlgorithmStatus_t;
6954

@@ -77,7 +62,7 @@ typedef struct BackoffAlgorithmContext
7762
/**
7863
* @brief The maximum backoff delay (in milliseconds) between consecutive retry attempts.
7964
*/
80-
uint16_t maxBackOffDelay;
65+
uint16_t maxBackoffDelay;
8166

8267
/**
8368
* @brief The total number of retry attempts completed.
@@ -94,12 +79,6 @@ typedef struct BackoffAlgorithmContext
9479
* @brief The maximum number of retry attempts.
9580
*/
9681
uint32_t maxRetryAttempts;
97-
98-
/**
99-
* @brief The random number generator function used for calculating the
100-
* backoff value for the next retry attempt.
101-
*/
102-
BackoffAlgorithm_RNG_t pRng;
10382
} BackoffAlgorithmContext_t;
10483

10584
/**
@@ -115,15 +94,12 @@ typedef struct BackoffAlgorithmContext
11594
* use in the exponential backoff and jitter model.
11695
* @param[in] maxAttempts The maximum number of retry attempts. Set the value to
11796
* #BACKOFF_ALGORITHM_RETRY_FOREVER to retry for ever.
118-
* @param[in] pRng The platform-specific function to use for random number generation.
119-
* The random number generator should be seeded before calling this function.
12097
*/
12198
/* @[define_backoffalgorithm_initializeparams] */
12299
void BackoffAlgorithm_InitializeParams( BackoffAlgorithmContext_t * pContext,
123100
uint16_t backOffBase,
124101
uint16_t maxBackOff,
125-
uint32_t maxAttempts,
126-
BackoffAlgorithm_RNG_t pRng );
102+
uint32_t maxAttempts );
127103
/* @[define_backoffalgorithm_initializeparams] */
128104

129105
/**
@@ -135,15 +111,22 @@ void BackoffAlgorithm_InitializeParams( BackoffAlgorithmContext_t * pContext,
135111
*
136112
* @param[in, out] pRetryContext Structure containing parameters for the next backoff
137113
* value calculation.
114+
* @param[in] randomValue The random value to use for calculation of the backoff period.
115+
* The random value should be in the range of [0, UINT32_MAX].
138116
* @param[out] pNextBackOff This will be populated with the backoff value (in milliseconds)
139117
* for the next retry attempt. The value does not exceed the maximum backoff delay
140118
* configured in the context.
141119
*
142-
* @return #BackoffAlgorithmSuccess after a successful sleep, #BackoffAlgorithmRngFailure for a failure
143-
* in random number generation, #BackoffAlgorithmRetriesExhausted when all attempts are exhausted.
120+
* @note For generating a random number, it is recommended to use a Random Number Generator
121+
* that is seeded with a device-specific entropy source so that possibility of collisions
122+
* between multiple devices retrying the network operations can be mitigated.
123+
*
124+
* @return #BackoffAlgorithmSuccess after a successful sleep;
125+
* #BackoffAlgorithmRetriesExhausted when all attempts are exhausted.
144126
*/
145127
/* @[define_backoffalgorithm_getnextbackoff] */
146128
BackoffAlgorithmStatus_t BackoffAlgorithm_GetNextBackoff( BackoffAlgorithmContext_t * pRetryContext,
129+
uint32_t randomValue,
147130
uint16_t * pNextBackOff );
148131
/* @[define_backoffalgorithm_getnextbackoff] */
149132

0 commit comments

Comments
 (0)