From 036ec83b65cebefc2636f12a172681c9cf14edd9 Mon Sep 17 00:00:00 2001 From: Archit Aggarwal Date: Tue, 24 Nov 2020 14:54:31 -0800 Subject: [PATCH] Replace exponential_backoff with submodule to FreeRTOS/backoffAlgorithm (#419) A new repository, FreeRTOS/backoffAlgorithm, has been created for hosting the library for backoff calculation. This repo replaces the FreeRTOS-Plus/Source/Utilities/exponential_backoff with the submodule to the new repository, and updates all the demos that use retry logic to use the backoffAlgorithm API --- .gitmodules | 3 + .../Device_Defender_Demo/WIN32.vcxproj | 6 +- .../WIN32.vcxproj.filters | 4 +- .../Device_Shadow_Demo/WIN32.vcxproj | 6 +- .../Device_Shadow_Demo/WIN32.vcxproj.filters | 4 +- .../Jobs_Demo/WIN32.vcxproj | 6 +- .../Jobs_Demo/WIN32.vcxproj.filters | 4 +- .../AWS/Mqtt_Demo_Helpers/mqtt_demo_helpers.c | 81 +++++- .../Http_Demo_Helpers/http_demo_utils.c | 17 +- .../DemoTasks/BasicTLSMQTTExample.c | 126 +++++++-- .../MQTT_Basic_TLS/WIN32.vcxproj | 6 +- .../MQTT_Basic_TLS/WIN32.vcxproj.filters | 4 +- .../DemoTasks/KeepAliveMQTTExample.c | 125 +++++++-- .../MQTT_Keep_Alive/WIN32.vcxproj | 6 +- .../MQTT_Keep_Alive/WIN32.vcxproj.filters | 4 +- .../DemoTasks/MultitaskMQTTExample.c | 79 +++++- .../MQTT_Multitask/WIN32.vcxproj | 6 +- .../MQTT_Multitask/WIN32.vcxproj.filters | 4 +- .../DemoTasks/MutualAuthMQTTExample.c | 126 +++++++-- .../MQTT_Mutual_Auth/WIN32.vcxproj | 6 +- .../MQTT_Mutual_Auth/WIN32.vcxproj.filters | 4 +- .../DemoTasks/PlaintextMQTTExample.c | 126 +++++++-- .../MQTT_Plain_Text/WIN32.vcxproj | 6 +- .../MQTT_Plain_Text/WIN32.vcxproj.filters | 4 +- .../DemoTasks/SerializerMQTTExample.c | 125 +++++++-- .../MQTT_Serializer/WIN32.vcxproj | 4 +- .../MQTT_Serializer/WIN32.vcxproj.filters | 2 +- .../WIN32.vcxproj | 6 +- .../WIN32.vcxproj.filters | 4 +- .../Source/Utilities/backoff_algorithm | 1 + .../exponential_backoff/exponential_backoff.c | 101 -------- .../exponential_backoff/exponential_backoff.h | 245 ------------------ FreeRTOS-Plus/Source/Utilities/readme.txt | 2 +- 33 files changed, 699 insertions(+), 554 deletions(-) create mode 160000 FreeRTOS-Plus/Source/Utilities/backoff_algorithm delete mode 100644 FreeRTOS-Plus/Source/Utilities/exponential_backoff/exponential_backoff.c delete mode 100644 FreeRTOS-Plus/Source/Utilities/exponential_backoff/exponential_backoff.h diff --git a/.gitmodules b/.gitmodules index 9ac800c5a6..ced7326556 100644 --- a/.gitmodules +++ b/.gitmodules @@ -34,3 +34,6 @@ [submodule "FreeRTOS-Plus/Source/Application-Protocols/coreHTTP"] path = FreeRTOS-Plus/Source/Application-Protocols/coreHTTP url = https://github.com/FreeRTOS/coreHTTP +[submodule "FreeRTOS-Plus/Source/Utilities/backoff_algorithm"] + path = FreeRTOS-Plus/Source/Utilities/backoff_algorithm + url = https://github.com/FreeRTOS/backoffAlgorithm.git diff --git a/FreeRTOS-Plus/Demo/AWS/Device_Defender_Windows_Simulator/Device_Defender_Demo/WIN32.vcxproj b/FreeRTOS-Plus/Demo/AWS/Device_Defender_Windows_Simulator/Device_Defender_Demo/WIN32.vcxproj index c276dcc55d..1f06b434a5 100644 --- a/FreeRTOS-Plus/Demo/AWS/Device_Defender_Windows_Simulator/Device_Defender_Demo/WIN32.vcxproj +++ b/FreeRTOS-Plus/Demo/AWS/Device_Defender_Windows_Simulator/Device_Defender_Demo/WIN32.vcxproj @@ -58,7 +58,7 @@ Disabled - ..\..\..\..\..\Source\FreeRTOS-Plus-Trace\Include;..\..\..\..\..\FreeRTOS-Plus\Source\FreeRTOS-Plus-TCP\include;..\..\..\..\..\FreeRTOS-Plus\Source\FreeRTOS-Plus-TCP\portable\BufferManagement;..\..\..\..\..\FreeRTOS-Plus\Source\FreeRTOS-Plus-TCP\portable\Compiler\MSVC;..\..\..\..\..\FreeRTOS-Plus\Source\Utilities\logging;..\..\..\Common\WinPCap;..\..\..\..\..\FreeRTOS\Source\include;..\..\..\..\..\FreeRTOS\Source\portable\MSVC-MingW;..\..\..\..\Source\Application-Protocols\coreMQTT\source\include;..\..\..\..\Source\Application-Protocols\coreMQTT\source\interface;..\..\..\..\Source\Utilities\exponential_backoff;..\..\..\..\Source\Application-Protocols\network_transport\freertos_plus_tcp;..\..\..\..\Source\Application-Protocols\network_transport\freertos_plus_tcp\using_mbedtls;..\..\..\..\Source\Utilities\mbedtls_freertos;..\..\..\..\..\Source\mbedtls_utils;..\..\..\..\ThirdParty\mbedtls\include;..\..\..\..\Source\AWS\device-defender\source\include;..\..\..\..\Source\coreJSON\source\include;..\..\Mqtt_Demo_Helpers;..\..\..\..\Source\FreeRTOS-Plus-TCP\tools\tcp_utilities\include;.;%(AdditionalIncludeDirectories) + ..\..\..\..\..\Source\FreeRTOS-Plus-Trace\Include;..\..\..\..\..\FreeRTOS-Plus\Source\FreeRTOS-Plus-TCP\include;..\..\..\..\..\FreeRTOS-Plus\Source\FreeRTOS-Plus-TCP\portable\BufferManagement;..\..\..\..\..\FreeRTOS-Plus\Source\FreeRTOS-Plus-TCP\portable\Compiler\MSVC;..\..\..\..\..\FreeRTOS-Plus\Source\Utilities\logging;..\..\..\Common\WinPCap;..\..\..\..\..\FreeRTOS\Source\include;..\..\..\..\..\FreeRTOS\Source\portable\MSVC-MingW;..\..\..\..\Source\Application-Protocols\coreMQTT\source\include;..\..\..\..\Source\Application-Protocols\coreMQTT\source\interface;..\..\..\..\Source\Utilities\backoff_algorithm\source\include;..\..\..\..\Source\Application-Protocols\network_transport\freertos_plus_tcp;..\..\..\..\Source\Application-Protocols\network_transport\freertos_plus_tcp\using_mbedtls;..\..\..\..\Source\Utilities\mbedtls_freertos;..\..\..\..\..\Source\mbedtls_utils;..\..\..\..\ThirdParty\mbedtls\include;..\..\..\..\Source\AWS\device-defender\source\include;..\..\..\..\Source\coreJSON\source\include;..\..\Mqtt_Demo_Helpers;..\..\..\..\Source\FreeRTOS-Plus-TCP\tools\tcp_utilities\include;.;%(AdditionalIncludeDirectories) MBEDTLS_CONFIG_FILE="mbedtls_config.h";WIN32;_DEBUG;_CONSOLE;_WIN32_WINNT=0x0500;WINVER=0x400;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) false EnableFastChecks @@ -160,7 +160,7 @@ - + @@ -528,7 +528,7 @@ - + diff --git a/FreeRTOS-Plus/Demo/AWS/Device_Defender_Windows_Simulator/Device_Defender_Demo/WIN32.vcxproj.filters b/FreeRTOS-Plus/Demo/AWS/Device_Defender_Windows_Simulator/Device_Defender_Demo/WIN32.vcxproj.filters index 091147d7e6..3fdd825fda 100644 --- a/FreeRTOS-Plus/Demo/AWS/Device_Defender_Windows_Simulator/Device_Defender_Demo/WIN32.vcxproj.filters +++ b/FreeRTOS-Plus/Demo/AWS/Device_Defender_Windows_Simulator/Device_Defender_Demo/WIN32.vcxproj.filters @@ -152,7 +152,7 @@ FreeRTOS+\FreeRTOS IoT Libraries\platform\mbedtls - + FreeRTOS+\FreeRTOS IoT Libraries\platform\freertos @@ -500,7 +500,7 @@ FreeRTOS+\FreeRTOS IoT Libraries\platform - + FreeRTOS+\FreeRTOS IoT Libraries\platform diff --git a/FreeRTOS-Plus/Demo/AWS/Device_Shadow_Windows_Simulator/Device_Shadow_Demo/WIN32.vcxproj b/FreeRTOS-Plus/Demo/AWS/Device_Shadow_Windows_Simulator/Device_Shadow_Demo/WIN32.vcxproj index 53fd79aca7..afe43ae400 100644 --- a/FreeRTOS-Plus/Demo/AWS/Device_Shadow_Windows_Simulator/Device_Shadow_Demo/WIN32.vcxproj +++ b/FreeRTOS-Plus/Demo/AWS/Device_Shadow_Windows_Simulator/Device_Shadow_Demo/WIN32.vcxproj @@ -58,7 +58,7 @@ Disabled - ..\..\..\..\..\Source\FreeRTOS-Plus-Trace\Include;..\..\..\..\..\FreeRTOS-Plus\Source\FreeRTOS-Plus-TCP\include;..\..\..\..\..\FreeRTOS-Plus\Source\FreeRTOS-Plus-TCP\portable\BufferManagement;..\..\..\..\..\FreeRTOS-Plus\Source\FreeRTOS-Plus-TCP\portable\Compiler\MSVC;..\..\..\..\..\FreeRTOS-Plus\Source\Utilities\logging;..\..\..\Common\WinPCap;..\..\..\..\..\FreeRTOS\Source\include;..\..\..\..\..\FreeRTOS\Source\portable\MSVC-MingW;..\..\..\..\Source\Application-Protocols\coreMQTT\source\include;..\..\..\..\Source\Application-Protocols\coreMQTT\source\interface;..\..\..\..\Source\Utilities\exponential_backoff;..\..\..\..\Source\Application-Protocols\network_transport\freertos_plus_tcp;..\..\..\..\Source\Application-Protocols\network_transport\freertos_plus_tcp\using_mbedtls;..\..\..\..\Source\Utilities\mbedtls_freertos;..\..\..\..\..\Source\mbedtls_utils;..\..\..\..\ThirdParty\mbedtls\include;..\..\..\..\Source\AWS\device-shadow\source\include;..\..\..\..\Source\coreJSON\source\include;..\..\Mqtt_Demo_Helpers;.;%(AdditionalIncludeDirectories) + ..\..\..\..\..\Source\FreeRTOS-Plus-Trace\Include;..\..\..\..\..\FreeRTOS-Plus\Source\FreeRTOS-Plus-TCP\include;..\..\..\..\..\FreeRTOS-Plus\Source\FreeRTOS-Plus-TCP\portable\BufferManagement;..\..\..\..\..\FreeRTOS-Plus\Source\FreeRTOS-Plus-TCP\portable\Compiler\MSVC;..\..\..\..\..\FreeRTOS-Plus\Source\Utilities\logging;..\..\..\Common\WinPCap;..\..\..\..\..\FreeRTOS\Source\include;..\..\..\..\..\FreeRTOS\Source\portable\MSVC-MingW;..\..\..\..\Source\Application-Protocols\coreMQTT\source\include;..\..\..\..\Source\Application-Protocols\coreMQTT\source\interface;..\..\..\..\Source\Utilities\backoff_algorithm\source\include;..\..\..\..\Source\Application-Protocols\network_transport\freertos_plus_tcp;..\..\..\..\Source\Application-Protocols\network_transport\freertos_plus_tcp\using_mbedtls;..\..\..\..\Source\Utilities\mbedtls_freertos;..\..\..\..\..\Source\mbedtls_utils;..\..\..\..\ThirdParty\mbedtls\include;..\..\..\..\Source\AWS\device-shadow\source\include;..\..\..\..\Source\coreJSON\source\include;..\..\Mqtt_Demo_Helpers;.;%(AdditionalIncludeDirectories) MBEDTLS_CONFIG_FILE="mbedtls_config.h";WIN32;_DEBUG;_CONSOLE;_WIN32_WINNT=0x0500;WINVER=0x400;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) false EnableFastChecks @@ -159,7 +159,7 @@ - + @@ -523,7 +523,7 @@ - + diff --git a/FreeRTOS-Plus/Demo/AWS/Device_Shadow_Windows_Simulator/Device_Shadow_Demo/WIN32.vcxproj.filters b/FreeRTOS-Plus/Demo/AWS/Device_Shadow_Windows_Simulator/Device_Shadow_Demo/WIN32.vcxproj.filters index e269a4139b..b1dc2f954a 100644 --- a/FreeRTOS-Plus/Demo/AWS/Device_Shadow_Windows_Simulator/Device_Shadow_Demo/WIN32.vcxproj.filters +++ b/FreeRTOS-Plus/Demo/AWS/Device_Shadow_Windows_Simulator/Device_Shadow_Demo/WIN32.vcxproj.filters @@ -156,7 +156,7 @@ FreeRTOS+\FreeRTOS IoT Libraries\platform\mbedtls - + FreeRTOS+\FreeRTOS IoT Libraries\platform\freertos @@ -504,7 +504,7 @@ FreeRTOS+\FreeRTOS IoT Libraries\platform - + FreeRTOS+\FreeRTOS IoT Libraries\platform diff --git a/FreeRTOS-Plus/Demo/AWS/Jobs_Windows_Simulator/Jobs_Demo/WIN32.vcxproj b/FreeRTOS-Plus/Demo/AWS/Jobs_Windows_Simulator/Jobs_Demo/WIN32.vcxproj index 5c5e14a582..99a70284c5 100755 --- a/FreeRTOS-Plus/Demo/AWS/Jobs_Windows_Simulator/Jobs_Demo/WIN32.vcxproj +++ b/FreeRTOS-Plus/Demo/AWS/Jobs_Windows_Simulator/Jobs_Demo/WIN32.vcxproj @@ -58,7 +58,7 @@ Disabled - ..\..\..\..\..\Source\FreeRTOS-Plus-Trace\Include;..\..\..\..\..\FreeRTOS-Plus\Source\FreeRTOS-Plus-TCP\include;..\..\..\..\..\FreeRTOS-Plus\Source\FreeRTOS-Plus-TCP\portable\BufferManagement;..\..\..\..\..\FreeRTOS-Plus\Source\FreeRTOS-Plus-TCP\portable\Compiler\MSVC;..\..\..\..\..\FreeRTOS-Plus\Source\Utilities\logging;..\..\..\Common\WinPCap;..\..\..\..\..\FreeRTOS\Source\include;..\..\..\..\..\FreeRTOS\Source\portable\MSVC-MingW;..\..\..\..\Source\Application-Protocols\coreMQTT\source\include;..\..\..\..\Source\Application-Protocols\coreMQTT\source\interface;..\..\..\..\Source\Utilities\exponential_backoff;..\..\..\..\Source\Application-Protocols\network_transport\freertos_plus_tcp;..\..\..\..\Source\Application-Protocols\network_transport\freertos_plus_tcp\using_mbedtls;..\..\..\..\Source\Utilities\mbedtls_freertos;..\..\..\..\..\Source\mbedtls_utils;..\..\..\..\ThirdParty\mbedtls\include;..\..\..\..\Source\AWS\jobs\source\include;..\..\..\..\Source\coreJSON\source\include;..\..\Mqtt_Demo_Helpers;.;%(AdditionalIncludeDirectories) + ..\..\..\..\..\Source\FreeRTOS-Plus-Trace\Include;..\..\..\..\..\FreeRTOS-Plus\Source\FreeRTOS-Plus-TCP\include;..\..\..\..\..\FreeRTOS-Plus\Source\FreeRTOS-Plus-TCP\portable\BufferManagement;..\..\..\..\..\FreeRTOS-Plus\Source\FreeRTOS-Plus-TCP\portable\Compiler\MSVC;..\..\..\..\..\FreeRTOS-Plus\Source\Utilities\logging;..\..\..\Common\WinPCap;..\..\..\..\..\FreeRTOS\Source\include;..\..\..\..\..\FreeRTOS\Source\portable\MSVC-MingW;..\..\..\..\Source\Application-Protocols\coreMQTT\source\include;..\..\..\..\Source\Application-Protocols\coreMQTT\source\interface;..\..\..\..\Source\Utilities\backoff_algorithm\source\include;..\..\..\..\Source\Application-Protocols\network_transport\freertos_plus_tcp;..\..\..\..\Source\Application-Protocols\network_transport\freertos_plus_tcp\using_mbedtls;..\..\..\..\Source\Utilities\mbedtls_freertos;..\..\..\..\..\Source\mbedtls_utils;..\..\..\..\ThirdParty\mbedtls\include;..\..\..\..\Source\AWS\jobs\source\include;..\..\..\..\Source\coreJSON\source\include;..\..\Mqtt_Demo_Helpers;.;%(AdditionalIncludeDirectories) MBEDTLS_CONFIG_FILE="mbedtls_config.h";WIN32;_DEBUG;_CONSOLE;_WIN32_WINNT=0x0500;WINVER=0x400;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) false EnableFastChecks @@ -159,7 +159,7 @@ - + @@ -523,7 +523,7 @@ - + diff --git a/FreeRTOS-Plus/Demo/AWS/Jobs_Windows_Simulator/Jobs_Demo/WIN32.vcxproj.filters b/FreeRTOS-Plus/Demo/AWS/Jobs_Windows_Simulator/Jobs_Demo/WIN32.vcxproj.filters index e269a4139b..b1dc2f954a 100644 --- a/FreeRTOS-Plus/Demo/AWS/Jobs_Windows_Simulator/Jobs_Demo/WIN32.vcxproj.filters +++ b/FreeRTOS-Plus/Demo/AWS/Jobs_Windows_Simulator/Jobs_Demo/WIN32.vcxproj.filters @@ -156,7 +156,7 @@ FreeRTOS+\FreeRTOS IoT Libraries\platform\mbedtls - + FreeRTOS+\FreeRTOS IoT Libraries\platform\freertos @@ -504,7 +504,7 @@ FreeRTOS+\FreeRTOS IoT Libraries\platform - + FreeRTOS+\FreeRTOS IoT Libraries\platform diff --git a/FreeRTOS-Plus/Demo/AWS/Mqtt_Demo_Helpers/mqtt_demo_helpers.c b/FreeRTOS-Plus/Demo/AWS/Mqtt_Demo_Helpers/mqtt_demo_helpers.c index c14fb04918..20c3b3e111 100755 --- a/FreeRTOS-Plus/Demo/AWS/Mqtt_Demo_Helpers/mqtt_demo_helpers.c +++ b/FreeRTOS-Plus/Demo/AWS/Mqtt_Demo_Helpers/mqtt_demo_helpers.c @@ -51,7 +51,7 @@ #include "core_mqtt.h" /* Exponential backoff retry include. */ -#include "exponential_backoff.h" +#include "backoff_algorithm.h" /* Transport interface implementation include header for TLS. */ #include "using_mbedtls.h" @@ -84,6 +84,23 @@ /*-----------------------------------------------------------*/ +/** + * @brief The maximum number of retries for network operation with server. + */ +#define RETRY_MAX_ATTEMPTS ( 5U ) + +/** + * @brief The maximum back-off delay (in milliseconds) for retrying failed operation + * with server. + */ +#define RETRY_MAX_BACKOFF_DELAY_MS ( 5000U ) + +/** + * @brief The base back-off delay (in milliseconds) to use for network operation retry + * attempts. + */ +#define RETRY_BACKOFF_BASE_MS ( 500U ) + /** * @brief Timeout for receiving CONNACK packet in milliseconds. */ @@ -220,6 +237,22 @@ static PublishPackets_t outgoingPublishPackets[ MAX_OUTGOING_PUBLISHES ] = { 0 } /*-----------------------------------------------------------*/ +/** + * @brief A wrapper to the "uxRand()" random number generator so that it + * can be passed to the backoffAlgorithm library for retry logic. + * + * This function implements the #BackoffAlgorithm_RNG_T type interface + * in the backoffAlgorithm library API. + * + * @note The "uxRand" function represents a pseudo random number generator. + * However, it is recommended to use a True Randon Number Generator (TRNG) + * for generating unique device-specific random values to avoid possibility + * of network collisions from multiple devices retrying network operations. + * + * @return The generated randon number. This function ALWAYS succeeds. + */ +static int32_t prvGenerateRandomNumber(); + /** * @brief Connect to MQTT broker with reconnection retries. * @@ -285,12 +318,20 @@ static uint32_t prvGetTimeMs( void ); /*-----------------------------------------------------------*/ +static int32_t prvGenerateRandomNumber() +{ + return( uxRand() & INT32_MAX ); +} + +/*-----------------------------------------------------------*/ + static TlsTransportStatus_t prvConnectToServerWithBackoffRetries( NetworkContext_t * pxNetworkContext ) { TlsTransportStatus_t xNetworkStatus = TLS_TRANSPORT_SUCCESS; - RetryUtilsStatus_t xRetryUtilsStatus = RetryUtilsSuccess; - RetryUtilsParams_t xReconnectParams = { 0 }; + BackoffAlgorithmStatus_t xBackoffAlgStatus = BackoffAlgorithmSuccess; + BackoffAlgorithmContext_t xReconnectParams = { 0 }; NetworkCredentials_t xNetworkCredentials = { 0 }; + uint16_t usNextRetryBackOff = 0U; /* ALPN protocols must be a NULL-terminated list of strings. Therefore, * the first entry will contain the actual ALPN protocol string while the @@ -318,9 +359,15 @@ static TlsTransportStatus_t prvConnectToServerWithBackoffRetries( NetworkContext #endif xNetworkCredentials.pAlpnProtos = pcAlpnProtocols; - /* Initialize reconnect attempts and interval. */ - RetryUtils_ParamsReset( &xReconnectParams ); - xReconnectParams.maxRetryAttempts = MAX_RETRY_ATTEMPTS; + /* Initialize reconnect attempts and interval. + * Note: This utility uses a pseudo random number generator for use with the backoff + * algorithm. However, it is recommended to use a True Random Number generator to + * avoid possibility of collisions between multiple devices retrying connection. */ + BackoffAlgorithm_InitializeParams( &xReconnectParams, + RETRY_BACKOFF_BASE_MS, + RETRY_MAX_BACKOFF_DELAY_MS, + RETRY_MAX_ATTEMPTS, + prvGenerateRandomNumber ); /* Attempt to connect to MQTT broker. If connection fails, retry after * a timeout. Timeout value will exponentially increase until maximum @@ -343,16 +390,22 @@ static TlsTransportStatus_t prvConnectToServerWithBackoffRetries( NetworkContext if( xNetworkStatus != TLS_TRANSPORT_SUCCESS ) { - LogWarn( ( "Connection to the broker failed. Retrying connection with backoff and jitter." ) ); - xRetryUtilsStatus = RetryUtils_BackoffAndSleep( &xReconnectParams ); - } + /* Get back-off value (in milliseconds) for the next connection retry. */ + xBackoffAlgStatus = BackoffAlgorithm_GetNextBackoff( &xReconnectParams, &usNextRetryBackOff ); + configASSERT( xBackoffAlgStatus != BackoffAlgorithmRngFailure ); - if( xRetryUtilsStatus == RetryUtilsRetriesExhausted ) - { - LogError( ( "Connection to the broker failed, all attempts exhausted." ) ); - xNetworkStatus = TLS_TRANSPORT_CONNECT_FAILURE; + if( xBackoffAlgStatus == BackoffAlgorithmRetriesExhausted ) + { + LogError( ( "Connection to the broker failed, all attempts exhausted." ) ); + } + else if( xBackoffAlgStatus == BackoffAlgorithmSuccess ) + { + LogWarn( ( "Connection to the broker failed. " + "Retrying connection with backoff and jitter." ) ); + vTaskDelay( pdMS_TO_TICKS( usNextRetryBackOff ) ); + } } - } while( ( xNetworkStatus != TLS_TRANSPORT_SUCCESS ) && ( xRetryUtilsStatus == RetryUtilsSuccess ) ); + } while( ( xNetworkStatus != TLS_TRANSPORT_SUCCESS ) && ( xBackoffAlgStatus == BackoffAlgorithmSuccess ) ); return xNetworkStatus; } diff --git a/FreeRTOS-Plus/Demo/coreHTTP_Windows_Simulator/Http_Demo_Helpers/http_demo_utils.c b/FreeRTOS-Plus/Demo/coreHTTP_Windows_Simulator/Http_Demo_Helpers/http_demo_utils.c index 824c3131dc..861a7eacfc 100644 --- a/FreeRTOS-Plus/Demo/coreHTTP_Windows_Simulator/Http_Demo_Helpers/http_demo_utils.c +++ b/FreeRTOS-Plus/Demo/coreHTTP_Windows_Simulator/Http_Demo_Helpers/http_demo_utils.c @@ -26,7 +26,7 @@ #include "http_demo_utils.h" /* Exponential backoff retry include. */ -#include "exponential_backoff.h" +#include "backoff_algorithm.h" /* Parser utilities. */ #include "http_parser.h" @@ -38,15 +38,18 @@ BaseType_t connectToServerWithBackoffRetries( TransportConnect_t connectFunction { BaseType_t xReturn = pdFAIL; /* Status returned by the retry utilities. */ - RetryUtilsStatus_t xRetryUtilsStatus = RetryUtilsSuccess; + BackoffAlgorithmStatus_t xBackoffAlgStatus = BackoffAlgorithmSuccess; /* Struct containing the next backoff time. */ - RetryUtilsParams_t xReconnectParams; + BackoffAlgorithmContext_t xReconnectParams; assert( connectFunction != NULL ); /* Initialize reconnect attempts and interval */ - RetryUtils_ParamsReset( &xReconnectParams ); - xReconnectParams.maxRetryAttempts = MAX_RETRY_ATTEMPTS; + BackoffAlgorithm_InitializeParams( &xReconnectParams, + RETRY_BACKOFF_BASE_MS, + RETRY_MAX_BACKOFF_DELAY_MS, + RETRY_MAX_ATTEMPTS, + prvGenerateRandomNumber ); /* Attempt to connect to the HTTP server. If connection fails, retry after a * timeout. The timeout value will exponentially increase until either the @@ -63,9 +66,9 @@ BaseType_t connectToServerWithBackoffRetries( TransportConnect_t connectFunction LogInfo( ( "Retry attempt %lu out of maximum retry attempts %lu.", ( xReconnectParams.attemptsDone + 1 ), MAX_RETRY_ATTEMPTS ) ); - xRetryUtilsStatus = RetryUtils_BackoffAndSleep( &xReconnectParams ); + xBackoffAlgStatus = BackoffAlgorithm_GetNextBackoff( &xReconnectParams, &usNextBackoff ); } - } while( ( xReturn == pdFAIL ) && ( xRetryUtilsStatus == RetryUtilsSuccess ) ); + } while( ( xReturn == pdFAIL ) && ( xBackoffAlgStatus == BackoffAlgorithmSuccess ) ); if( xReturn == pdFAIL ) { diff --git a/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Basic_TLS/DemoTasks/BasicTLSMQTTExample.c b/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Basic_TLS/DemoTasks/BasicTLSMQTTExample.c index d6bdda02a8..d797f27435 100644 --- a/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Basic_TLS/DemoTasks/BasicTLSMQTTExample.c +++ b/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Basic_TLS/DemoTasks/BasicTLSMQTTExample.c @@ -54,7 +54,7 @@ #include "core_mqtt.h" /* Exponential backoff retry include. */ -#include "exponential_backoff.h" +#include "backoff_algorithm.h" /* Transport interface implementation include header for TLS. */ #include "using_mbedtls.h" @@ -97,6 +97,23 @@ /*-----------------------------------------------------------*/ +/** + * @brief The maximum number of retries for network operation with server. + */ +#define mqttexampleRETRY_MAX_ATTEMPTS ( 5U ) + +/** + * @brief The maximum back-off delay (in milliseconds) for retrying failed operation + * with server. + */ +#define mqttexampleRETRY_MAX_BACKOFF_DELAY_MS ( 5000U ) + +/** + * @brief The base back-off delay (in milliseconds) to use for network operation retry + * attempts. + */ +#define mqttexampleRETRY_BACKOFF_BASE_MS ( 500U ) + /** * @brief Timeout for receiving CONNACK packet in milliseconds. */ @@ -176,6 +193,22 @@ */ static void prvMQTTDemoTask( void * pvParameters ); +/** + * @brief A wrapper to the "uxRand()" random number generator so that it + * can be passed to the backoffAlgorithm library for retry logic. + * + * This function implements the #BackoffAlgorithm_RNG_T type interface + * in the backoffAlgorithm library API. + * + * @note The "uxRand" function represents a pseudo random number generator. + * However, it is recommended to use a True Randon Number Generator (TRNG) + * for generating unique device-specific random values to avoid possibility + * of network collisions from multiple devices retrying network operations. + * + * @return The generated randon number. This function ALWAYS succeeds. + */ +static int32_t prvGenerateRandomNumber(); + /** * @brief Connect to MQTT broker with reconnection retries. * @@ -407,7 +440,7 @@ static void prvMQTTDemoTask( void * pvParameters ) /* If the server rejected the subscription request, attempt to resubscribe to the * topic. Attempts are made according to the exponential backoff retry strategy - * implemented in retryUtils. */ + * implemented in BackoffAlgorithm. */ prvMQTTSubscribeWithBackoffRetries( &xMQTTContext ); /* Process incoming packet from the broker. After sending a subscribe packet, the @@ -475,20 +508,35 @@ static void prvMQTTDemoTask( void * pvParameters ) } /*-----------------------------------------------------------*/ +static int32_t prvGenerateRandomNumber() +{ + return( uxRand() & INT32_MAX ); +} + +/*-----------------------------------------------------------*/ + static TlsTransportStatus_t prvConnectToServerWithBackoffRetries( NetworkCredentials_t * pxNetworkCredentials, NetworkContext_t * pxNetworkContext ) { TlsTransportStatus_t xNetworkStatus; - RetryUtilsStatus_t xRetryUtilsStatus = RetryUtilsSuccess; - RetryUtilsParams_t xReconnectParams; + BackoffAlgorithmStatus_t xBackoffAlgStatus = BackoffAlgorithmSuccess; + BackoffAlgorithmContext_t xReconnectParams; + uint16_t usNextRetryBackOff = 0U; /* Set the credentials for establishing a TLS connection. */ pxNetworkCredentials->pRootCa = ( const unsigned char * ) democonfigROOT_CA_PEM; pxNetworkCredentials->rootCaSize = sizeof( democonfigROOT_CA_PEM ); pxNetworkCredentials->disableSni = democonfigDISABLE_SNI; - /* Initialize reconnect attempts and interval. */ - RetryUtils_ParamsReset( &xReconnectParams ); - xReconnectParams.maxRetryAttempts = MAX_RETRY_ATTEMPTS; + + /* Initialize reconnect attempts and interval. + * Note: This demo is using pseudo random number generator for the backoff + * algorithm. However, it is recommended to use a True Random Number generator to + * avoid possibility of collisions between multiple devices retrying connection. */ + BackoffAlgorithm_InitializeParams( &xReconnectParams, + mqttexampleRETRY_BACKOFF_BASE_MS, + mqttexampleRETRY_MAX_BACKOFF_DELAY_MS, + mqttexampleRETRY_MAX_ATTEMPTS, + prvGenerateRandomNum ); /* Attempt to connect to the MQTT broker. If connection fails, retry after * a timeout. Timeout value will exponentially increase until maximum @@ -512,16 +560,22 @@ static TlsTransportStatus_t prvConnectToServerWithBackoffRetries( NetworkCredent if( xNetworkStatus != TLS_TRANSPORT_SUCCESS ) { - LogWarn( ( "Connection to the broker failed. Retrying connection with backoff and jitter." ) ); - xRetryUtilsStatus = RetryUtils_BackoffAndSleep( &xReconnectParams ); - } + /* Get back-off value (in milliseconds) for the next connection retry. */ + xBackoffAlgStatus = BackoffAlgorithm_GetNextBackoff( &xReconnectParams, &usNextRetryBackOff ); + configASSERT( xBackoffAlgStatus != BackoffAlgorithmRngFailure ); - if( xRetryUtilsStatus == RetryUtilsRetriesExhausted ) - { - LogError( ( "Connection to the broker failed, all attempts exhausted." ) ); - xNetworkStatus = TLS_TRANSPORT_CONNECT_FAILURE; + if( xBackoffAlgStatus == BackoffAlgorithmRetriesExhausted ) + { + LogError( ( "Connection to the broker failed, all attempts exhausted." ) ); + } + else if( xBackoffAlgStatus == BackoffAlgorithmSuccess ) + { + LogWarn( ( "Connection to the broker failed. " + "Retrying connection with backoff and jitter." ) ); + vTaskDelay( pdMS_TO_TICKS( usNextRetryBackOff ) ); + } } - } while( ( xNetworkStatus != TLS_TRANSPORT_SUCCESS ) && ( xRetryUtilsStatus == RetryUtilsSuccess ) ); + } while( ( xNetworkStatus != TLS_TRANSPORT_SUCCESS ) && ( xBackoffAlgStatus == BackoffAlgorithmSuccess ) ); return xNetworkStatus; } @@ -605,8 +659,9 @@ static void prvUpdateSubAckStatus( MQTTPacketInfo_t * pxPacketInfo ) static void prvMQTTSubscribeWithBackoffRetries( MQTTContext_t * pxMQTTContext ) { MQTTStatus_t xResult = MQTTSuccess; - RetryUtilsStatus_t xRetryUtilsStatus = RetryUtilsSuccess; - RetryUtilsParams_t xRetryParams; + BackoffAlgorithmStatus_t xBackoffAlgStatus = BackoffAlgorithmSuccess; + BackoffAlgorithmContext_t xRetryParams; + uint16_t usNextRetryBackOff = 0U; MQTTSubscribeInfo_t xMQTTSubscription[ mqttexampleTOPIC_COUNT ]; bool xFailedSubscribeToTopic = false; uint32_t ulTopicCount = 0U; @@ -623,9 +678,15 @@ static void prvMQTTSubscribeWithBackoffRetries( MQTTContext_t * pxMQTTContext ) xMQTTSubscription[ 0 ].pTopicFilter = mqttexampleTOPIC; xMQTTSubscription[ 0 ].topicFilterLength = ( uint16_t ) strlen( mqttexampleTOPIC ); - /* Initialize retry attempts and interval. */ - RetryUtils_ParamsReset( &xRetryParams ); - xRetryParams.maxRetryAttempts = MAX_RETRY_ATTEMPTS; + /* Initialize context for backoff retry attempts if SUBSCRIBE request fails. + * Note: This demo is using pseudo random number generator for the backoff + * algorithm. However, it is recommended to use a True Random Number generator to + * avoid possibility of collisions between multiple devices retrying network operations. */ + BackoffAlgorithm_InitializeParams( &xRetryParams, + mqttexampleRETRY_BACKOFF_BASE_MS, + mqttexampleRETRY_MAX_BACKOFF_DELAY_MS, + mqttexampleRETRY_MAX_ATTEMPTS, + prvGenerateRandomNum ); do { @@ -666,16 +727,31 @@ static void prvMQTTSubscribeWithBackoffRetries( MQTTContext_t * pxMQTTContext ) { if( xTopicFilterContext[ ulTopicCount ].xSubAckStatus == MQTTSubAckFailure ) { - LogWarn( ( "Server rejected subscription request. Attempting to re-subscribe to topic %s.", - xTopicFilterContext[ ulTopicCount ].pcTopicFilter ) ); xFailedSubscribeToTopic = true; - xRetryUtilsStatus = RetryUtils_BackoffAndSleep( &xRetryParams ); + + /* Get back-off value (in milliseconds) for the next connection retry. */ + xBackoffAlgStatus = BackoffAlgorithm_GetNextBackoff( &xRetryParams, &usNextRetryBackOff ); + configASSERT( xBackoffAlgStatus != BackoffAlgorithmRngFailure ); + + if( xBackoffAlgStatus == BackoffAlgorithmRetriesExhausted ) + { + LogError( ( "Server rejected subscription request. All retry attempts have exhausted. Topic=%s", + xTopicFilterContext[ ulTopicCount ].pcTopicFilter ) ); + } + else if( xBackoffAlgStatus == BackoffAlgorithmSuccess ) + { + LogWarn( ( "Server rejected subscription request. Attempting to re-subscribe to topic %s.", + xTopicFilterContext[ ulTopicCount ].pcTopicFilter ) ); + /* Backoff before the next re-subscribe attempt. */ + vTaskDelay( pdMS_TO_TICKS( usNextRetryBackOff ) ); + } + break; } } - configASSERT( xRetryUtilsStatus != RetryUtilsRetriesExhausted ); - } while( ( xFailedSubscribeToTopic == true ) && ( xRetryUtilsStatus == RetryUtilsSuccess ) ); + configASSERT( xBackoffAlgStatus != BackoffAlgorithmRetriesExhausted ); + } while( ( xFailedSubscribeToTopic == true ) && ( xBackoffAlgStatus == BackoffAlgorithmSuccess ) ); } /*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Basic_TLS/WIN32.vcxproj b/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Basic_TLS/WIN32.vcxproj index 6605f09f6a..1a83574f51 100644 --- a/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Basic_TLS/WIN32.vcxproj +++ b/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Basic_TLS/WIN32.vcxproj @@ -58,7 +58,7 @@ Disabled - ..\..\..\..\Source\FreeRTOS-Plus-Trace\Include;..\..\..\..\FreeRTOS-Plus\Source\FreeRTOS-Plus-TCP\include;..\..\..\..\FreeRTOS-Plus\Source\FreeRTOS-Plus-TCP\portable\BufferManagement;..\..\..\..\FreeRTOS-Plus\Source\FreeRTOS-Plus-TCP\portable\Compiler\MSVC;..\..\..\..\FreeRTOS-Plus\Source\Utilities\logging;..\common\WinPCap;..\..\..\..\FreeRTOS\Source\include;..\..\..\..\FreeRTOS\Source\portable\MSVC-MingW;..\..\..\Source\Application-Protocols\coreMQTT\source\include;..\..\..\Source\Application-Protocols\coreMQTT\source\interface;..\..\..\Source\Utilities\exponential_backoff;..\..\..\Source\Application-Protocols\network_transport\freertos_plus_tcp;..\..\..\Source\Application-Protocols\network_transport\freertos_plus_tcp\using_mbedtls;..\..\..\Source\Utilities\mbedtls_freertos;..\..\..\..\Source\mbedtls_utils;..\..\..\ThirdParty\mbedtls\include;.;%(AdditionalIncludeDirectories) + ..\..\..\..\Source\FreeRTOS-Plus-Trace\Include;..\..\..\..\FreeRTOS-Plus\Source\FreeRTOS-Plus-TCP\include;..\..\..\..\FreeRTOS-Plus\Source\FreeRTOS-Plus-TCP\portable\BufferManagement;..\..\..\..\FreeRTOS-Plus\Source\FreeRTOS-Plus-TCP\portable\Compiler\MSVC;..\..\..\..\FreeRTOS-Plus\Source\Utilities\logging;..\common\WinPCap;..\..\..\..\FreeRTOS\Source\include;..\..\..\..\FreeRTOS\Source\portable\MSVC-MingW;..\..\..\Source\Application-Protocols\coreMQTT\source\include;..\..\..\Source\Application-Protocols\coreMQTT\source\interface;..\..\..\Source\Utilities\backoff_algorithm\source\include;..\..\..\Source\Application-Protocols\network_transport\freertos_plus_tcp;..\..\..\Source\Application-Protocols\network_transport\freertos_plus_tcp\using_mbedtls;..\..\..\Source\Utilities\mbedtls_freertos;..\..\..\..\Source\mbedtls_utils;..\..\..\ThirdParty\mbedtls\include;.;%(AdditionalIncludeDirectories) MBEDTLS_CONFIG_FILE="mbedtls_config.h";WIN32;_DEBUG;_CONSOLE;_WIN32_WINNT=0x0500;WINVER=0x400;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) false EnableFastChecks @@ -159,7 +159,7 @@ - + @@ -520,7 +520,7 @@ - + diff --git a/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Basic_TLS/WIN32.vcxproj.filters b/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Basic_TLS/WIN32.vcxproj.filters index 5143965294..47b2388da1 100644 --- a/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Basic_TLS/WIN32.vcxproj.filters +++ b/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Basic_TLS/WIN32.vcxproj.filters @@ -393,7 +393,7 @@ FreeRTOS+\FreeRTOS IoT Libraries\platform\mbedtls - + FreeRTOS+\FreeRTOS IoT Libraries\platform\freertos @@ -489,7 +489,7 @@ FreeRTOS+\FreeRTOS IoT Libraries\platform - + FreeRTOS+\FreeRTOS IoT Libraries\platform diff --git a/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Keep_Alive/DemoTasks/KeepAliveMQTTExample.c b/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Keep_Alive/DemoTasks/KeepAliveMQTTExample.c index f360cb52bf..aade4aece2 100644 --- a/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Keep_Alive/DemoTasks/KeepAliveMQTTExample.c +++ b/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Keep_Alive/DemoTasks/KeepAliveMQTTExample.c @@ -57,7 +57,7 @@ #include "core_mqtt.h" /* Exponential backoff retry include. */ -#include "exponential_backoff.h" +#include "backoff_algorithm.h" /* Transport interface include. */ #include "using_plaintext.h" @@ -97,6 +97,23 @@ /*-----------------------------------------------------------*/ +/** + * @brief The maximum number of retries for network operation with server. + */ +#define mqttexampleRETRY_MAX_ATTEMPTS ( 5U ) + +/** + * @brief The maximum back-off delay (in milliseconds) for retrying failed operation + * with server. + */ +#define mqttexampleRETRY_MAX_BACKOFF_DELAY_MS ( 5000U ) + +/** + * @brief The base back-off delay (in milliseconds) to use for network operation retry + * attempts. + */ +#define mqttexampleRETRY_BACKOFF_BASE_MS ( 500U ) + /** * @brief Timeout for receiving CONNACK packet in milliseconds. */ @@ -198,6 +215,22 @@ */ static void prvMQTTDemoTask( void * pvParameters ); +/** + * @brief A wrapper to the "uxRand()" random number generator so that it + * can be passed to the backoffAlgorithm library for retry logic. + * + * This function implements the #BackoffAlgorithm_RNG_T type interface + * in the backoffAlgorithm library API. + * + * @note The "uxRand" function represents a pseudo random number generator. + * However, it is recommended to use a True Randon Number Generator (TRNG) + * for generating unique device-specific random values to avoid possibility + * of network collisions from multiple devices retrying network operations. + * + * @return The generated randon number. This function ALWAYS succeeds. + */ +static int32_t prvGenerateRandomNumber(); + /** * @brief Connect to MQTT broker with reconnection retries. * @@ -508,7 +541,7 @@ static void prvMQTTDemoTask( void * pvParameters ) /* If the server rejected the subscription request, attempt to resubscribe * to the topic. Attempts are made according to the exponential backoff retry - * strategy declared in exponential_backoff.h. */ + * strategy declared in backoff_algorithm.h. */ prvMQTTSubscribeWithBackoffRetries( &xMQTTContext ); /************************ Send PINGREQ packet. ************************/ @@ -601,15 +634,29 @@ static void prvMQTTDemoTask( void * pvParameters ) } /*-----------------------------------------------------------*/ +static int32_t prvGenerateRandomNumber() +{ + return( uxRand() & INT32_MAX ); +} + +/*-----------------------------------------------------------*/ + static PlaintextTransportStatus_t prvConnectToServerWithBackoffRetries( NetworkContext_t * pxNetworkContext ) { PlaintextTransportStatus_t xNetworkStatus; - RetryUtilsStatus_t xRetryUtilsStatus = RetryUtilsSuccess; - RetryUtilsParams_t xReconnectParams; + BackoffAlgorithmStatus_t xBackoffAlgStatus = BackoffAlgorithmSuccess; + BackoffAlgorithmContext_t xReconnectParams; + uint16_t usNextRetryBackOff = 0U; - /* Initialize reconnect attempts and interval. */ - RetryUtils_ParamsReset( &xReconnectParams ); - xReconnectParams.maxRetryAttempts = MAX_RETRY_ATTEMPTS; + /* Initialize reconnect attempts and interval. + * Note: This demo is using pseudo random number generator for the backoff + * algorithm. However, it is recommended to use a True Random Number generator to + * avoid possibility of collisions between multiple devices retrying connection. */ + BackoffAlgorithm_InitializeParams( &xReconnectParams, + mqttexampleRETRY_BACKOFF_BASE_MS, + mqttexampleRETRY_MAX_BACKOFF_DELAY_MS, + mqttexampleRETRY_MAX_ATTEMPTS, + prvGenerateRandomNumber ); /* Attempt to connect to MQTT broker. If connection fails, retry after * a timeout. Timeout value will exponentially increase till maximum @@ -631,16 +678,22 @@ static PlaintextTransportStatus_t prvConnectToServerWithBackoffRetries( NetworkC if( xNetworkStatus != PLAINTEXT_TRANSPORT_SUCCESS ) { - LogWarn( ( "Connection to the broker failed. Retrying connection with backoff and jitter." ) ); - xRetryUtilsStatus = RetryUtils_BackoffAndSleep( &xReconnectParams ); - } + /* Get back-off value (in milliseconds) for the next connection retry. */ + xBackoffAlgStatus = BackoffAlgorithm_GetNextBackoff( &xReconnectParams, &usNextRetryBackOff ); + configASSERT( xBackoffAlgStatus != BackoffAlgorithmRngFailure ); - if( xRetryUtilsStatus == RetryUtilsRetriesExhausted ) - { - LogError( ( "Connection to the broker failed, all attempts exhausted." ) ); - xNetworkStatus = PLAINTEXT_TRANSPORT_CONNECT_FAILURE; + if( xBackoffAlgStatus == BackoffAlgorithmRetriesExhausted ) + { + LogError( ( "Connection to the broker failed, all attempts exhausted." ) ); + } + else if( xBackoffAlgStatus == BackoffAlgorithmSuccess ) + { + LogWarn( ( "Connection to the broker failed. " + "Retrying connection with backoff and jitter." ) ); + vTaskDelay( pdMS_TO_TICKS( usNextRetryBackOff ) ); + } } - } while( ( xNetworkStatus != PLAINTEXT_TRANSPORT_SUCCESS ) && ( xRetryUtilsStatus == RetryUtilsSuccess ) ); + } while( ( xNetworkStatus != PLAINTEXT_TRANSPORT_SUCCESS ) && ( xBackoffAlgStatus == BackoffAlgorithmSuccess ) ); return xNetworkStatus; } @@ -723,12 +776,13 @@ static void prvUpdateSubAckStatus( MQTTPacketInfo_t * pxPacketInfo ) static void prvMQTTSubscribeWithBackoffRetries( MQTTContext_t * pxMQTTContext ) { MQTTStatus_t xResult = MQTTSuccess; - RetryUtilsStatus_t xRetryUtilsStatus = RetryUtilsSuccess; - RetryUtilsParams_t xRetryParams; + BackoffAlgorithmStatus_t xBackoffAlgStatus = BackoffAlgorithmSuccess; + BackoffAlgorithmContext_t xRetryParams; MQTTSubscribeInfo_t xMQTTSubscription[ mqttexampleTOPIC_COUNT ]; BaseType_t xTimerStatus; bool xFailedSubscribeToTopic = false; uint32_t ulTopicCount = 0U; + uint16_t usNextRetryBackOff = 0U; /* Some fields are not used by this demo so start with everything at 0. */ ( void ) memset( ( void * ) &xMQTTSubscription, 0x00, sizeof( xMQTTSubscription ) ); @@ -742,9 +796,15 @@ static void prvMQTTSubscribeWithBackoffRetries( MQTTContext_t * pxMQTTContext ) xMQTTSubscription[ 0 ].pTopicFilter = mqttexampleTOPIC; xMQTTSubscription[ 0 ].topicFilterLength = ( uint16_t ) strlen( mqttexampleTOPIC ); - /* Initialize retry attempts and interval. */ - RetryUtils_ParamsReset( &xRetryParams ); - xRetryParams.maxRetryAttempts = MAX_RETRY_ATTEMPTS; + /* Initialize context for backoff retry attempts if SUBSCRIBE request fails. + * Note: This demo is using pseudo random number generator for the backoff + * algorithm. However, it is recommended to use a True Random Number generator to + * avoid possibility of collisions between multiple devices retrying network operations. */ + BackoffAlgorithm_InitializeParams( &xRetryParams, + mqttexampleRETRY_BACKOFF_BASE_MS, + mqttexampleRETRY_MAX_BACKOFF_DELAY_MS, + mqttexampleRETRY_MAX_ATTEMPTS, + prvGenerateRandomNumber ); do { @@ -802,16 +862,31 @@ static void prvMQTTSubscribeWithBackoffRetries( MQTTContext_t * pxMQTTContext ) { if( xTopicFilterContext[ ulTopicCount ].xSubAckStatus == MQTTSubAckFailure ) { - LogWarn( ( "Server rejected subscription request. Attempting to re-subscribe to topic %s.", - xTopicFilterContext[ ulTopicCount ].pcTopicFilter ) ); xFailedSubscribeToTopic = true; - xRetryUtilsStatus = RetryUtils_BackoffAndSleep( &xRetryParams ); + + /* Get back-off value (in milliseconds) for the next connection retry. */ + xBackoffAlgStatus = BackoffAlgorithm_GetNextBackoff( &xRetryParams, &usNextRetryBackOff ); + configASSERT( xBackoffAlgStatus != BackoffAlgorithmRngFailure ); + + if( xBackoffAlgStatus == BackoffAlgorithmRetriesExhausted ) + { + LogError( ( "Server rejected subscription request. All retry attempts have exhausted. Topic=%s", + xTopicFilterContext[ ulTopicCount ].pcTopicFilter ) ); + } + else if( xBackoffAlgStatus == BackoffAlgorithmSuccess ) + { + LogWarn( ( "Server rejected subscription request. Attempting to re-subscribe to topic %s.", + xTopicFilterContext[ ulTopicCount ].pcTopicFilter ) ); + /* Backoff before the next re-subscribe attempt. */ + vTaskDelay( pdMS_TO_TICKS( usNextRetryBackOff ) ); + } + break; } } - configASSERT( xRetryUtilsStatus != RetryUtilsRetriesExhausted ); - } while( ( xFailedSubscribeToTopic == true ) && ( xRetryUtilsStatus == RetryUtilsSuccess ) ); + configASSERT( xBackoffAlgStatus != BackoffAlgorithmRetriesExhausted ); + } while( ( xFailedSubscribeToTopic == true ) && ( xBackoffAlgStatus == BackoffAlgorithmSuccess ) ); } /*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Keep_Alive/WIN32.vcxproj b/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Keep_Alive/WIN32.vcxproj index bbf981cba2..d463d2c979 100644 --- a/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Keep_Alive/WIN32.vcxproj +++ b/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Keep_Alive/WIN32.vcxproj @@ -58,7 +58,7 @@ Disabled - ..\..\..\..\Source\FreeRTOS-Plus-Trace\Include;..\..\..\..\FreeRTOS-Plus\Source\FreeRTOS-Plus-TCP\include;..\..\..\..\FreeRTOS-Plus\Source\FreeRTOS-Plus-TCP\portable\BufferManagement;..\..\..\..\FreeRTOS-Plus\Source\FreeRTOS-Plus-TCP\portable\Compiler\MSVC;..\..\..\..\FreeRTOS-Plus\Source\Utilities\logging;..\Common\WinPCap;..\..\..\..\FreeRTOS\Source\include;..\..\..\..\FreeRTOS\Source\portable\MSVC-MingW;..\..\..\Source\Application-Protocols\coreMQTT\source\include;..\..\..\Source\Application-Protocols\coreMQTT\source\interface;..\..\..\Source\Utilities\exponential_backoff;..\..\..\Source\Application-Protocols\network_transport\freertos_plus_tcp;..\..\..\Source\Application-Protocols\network_transport\freertos_plus_tcp\using_plaintext;.;%(AdditionalIncludeDirectories) + ..\..\..\..\Source\FreeRTOS-Plus-Trace\Include;..\..\..\..\FreeRTOS-Plus\Source\FreeRTOS-Plus-TCP\include;..\..\..\..\FreeRTOS-Plus\Source\FreeRTOS-Plus-TCP\portable\BufferManagement;..\..\..\..\FreeRTOS-Plus\Source\FreeRTOS-Plus-TCP\portable\Compiler\MSVC;..\..\..\..\FreeRTOS-Plus\Source\Utilities\logging;..\Common\WinPCap;..\..\..\..\FreeRTOS\Source\include;..\..\..\..\FreeRTOS\Source\portable\MSVC-MingW;..\..\..\Source\Application-Protocols\coreMQTT\source\include;..\..\..\Source\Application-Protocols\coreMQTT\source\interface;..\..\..\Source\Utilities\backoff_algorithm\source\include;..\..\..\Source\Application-Protocols\network_transport\freertos_plus_tcp;..\..\..\Source\Application-Protocols\network_transport\freertos_plus_tcp\using_plaintext;.;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_CONSOLE;_WIN32_WINNT=0x0500;WINVER=0x400;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) false EnableFastChecks @@ -159,7 +159,7 @@ - + @@ -196,7 +196,7 @@ - + diff --git a/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Keep_Alive/WIN32.vcxproj.filters b/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Keep_Alive/WIN32.vcxproj.filters index 53bfa625b2..c8475f1245 100644 --- a/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Keep_Alive/WIN32.vcxproj.filters +++ b/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Keep_Alive/WIN32.vcxproj.filters @@ -123,7 +123,7 @@ FreeRTOS+\FreeRTOS IoT Libraries\platform - + FreeRTOS+\FreeRTOS IoT Libraries\platform @@ -216,7 +216,7 @@ FreeRTOS+\FreeRTOS IoT Libraries\platform - + FreeRTOS+\FreeRTOS IoT Libraries\platform diff --git a/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Multitask/DemoTasks/MultitaskMQTTExample.c b/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Multitask/DemoTasks/MultitaskMQTTExample.c index c0ba6a8653..d4cd4f96b6 100644 --- a/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Multitask/DemoTasks/MultitaskMQTTExample.c +++ b/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Multitask/DemoTasks/MultitaskMQTTExample.c @@ -89,7 +89,7 @@ #include "core_mqtt_state.h" /* Exponential backoff retry include. */ -#include "exponential_backoff.h" +#include "backoff_algorithm.h" /* Transport interface include. */ #if defined( democonfigUSE_TLS ) && ( democonfigUSE_TLS == 1 ) @@ -109,6 +109,22 @@ #define mqttexampleNETWORK_BUFFER_SIZE ( 1024U ) #endif +/** + * @brief The maximum number of retries for network operation with server. + */ +#define mqttexampleRETRY_MAX_ATTEMPTS ( 5U ) + +/** + * @brief The maximum back-off delay (in milliseconds) for retrying failed operation + * with server. + */ +#define mqttexampleRETRY_MAX_BACKOFF_DELAY_MS ( 5000U ) + +/** + * @brief The base back-off delay (in milliseconds) to use for network operation retry + * attempts. + */ +#define mqttexampleRETRY_BACKOFF_BASE_MS ( 500U ) /** * @brief Timeout for receiving CONNACK packet in milliseconds. @@ -393,6 +409,22 @@ static MQTTStatus_t prvMQTTConnect( MQTTContext_t * pxMQTTContext, */ static MQTTStatus_t prvResumeSession( bool xSessionPresent ); +/** + * @brief A wrapper to the "uxRand()" random number generator so that it + * can be passed to the backoffAlgorithm library for retry logic. + * + * This function implements the #BackoffAlgorithm_RNG_T type interface + * in the backoffAlgorithm library API. + * + * @note The "uxRand" function represents a pseudo random number generator. + * However, it is recommended to use a True Randon Number Generator (TRNG) + * for generating unique device-specific random values to avoid possibility + * of network collisions from multiple devices retrying network operations. + * + * @return The generated randon number. This function ALWAYS succeeds. + */ +static int32_t prvGenerateRandomNumber(); + /** * @brief Form a TCP connection to a server. * @@ -956,11 +988,19 @@ static MQTTStatus_t prvResumeSession( bool xSessionPresent ) /*-----------------------------------------------------------*/ +static int32_t prvGenerateRandomNumber() +{ + return( uxRand() & INT32_MAX ); +} + +/*-----------------------------------------------------------*/ + static BaseType_t prvSocketConnect( NetworkContext_t * pxNetworkContext ) { BaseType_t xConnected = pdFAIL; - RetryUtilsStatus_t xRetryUtilsStatus = RetryUtilsSuccess; - RetryUtilsParams_t xReconnectParams; + BackoffAlgorithmStatus_t xBackoffAlgStatus = BackoffAlgorithmSuccess; + BackoffAlgorithmContext_t xReconnectParams; + uint16_t usNextRetryBackOff = 0U; #if defined( democonfigUSE_TLS ) && ( democonfigUSE_TLS == 1 ) TlsTransportStatus_t xNetworkStatus = TLS_TRANSPORT_CONNECT_FAILURE; @@ -997,9 +1037,15 @@ static BaseType_t prvSocketConnect( NetworkContext_t * pxNetworkContext ) #endif /* if defined( democonfigUSE_TLS ) && ( democonfigUSE_TLS == 1 ) */ /* We will use a retry mechanism with an exponential backoff mechanism and - * jitter. We initialize reconnect attempts and interval here. */ - xReconnectParams.maxRetryAttempts = MAX_RETRY_ATTEMPTS; - RetryUtils_ParamsReset( &xReconnectParams ); + * jitter. We initialize the context required for backoff period calculation here. + * Note: This demo is using pseudo random number generator for the backoff + * algorithm. However, it is recommended to use a True Random Number generator to + * avoid possibility of collisions between multiple devices retrying connection. */ + BackoffAlgorithm_InitializeParams( &xReconnectParams, + mqttexampleRETRY_BACKOFF_BASE_MS, + mqttexampleRETRY_MAX_BACKOFF_DELAY_MS, + mqttexampleRETRY_MAX_ATTEMPTS, + prvGenerateRandomNumber ); /* Attempt to connect to MQTT broker. If connection fails, retry after a * timeout. Timeout value will exponentially increase until the maximum @@ -1035,15 +1081,22 @@ static BaseType_t prvSocketConnect( NetworkContext_t * pxNetworkContext ) if( !xConnected ) { - LogWarn( ( "Connection to the broker failed. Retrying connection with backoff and jitter." ) ); - xRetryUtilsStatus = RetryUtils_BackoffAndSleep( &xReconnectParams ); - } + /* Get back-off value (in milliseconds) for the next connection retry. */ + xBackoffAlgStatus = BackoffAlgorithm_GetNextBackoff( &xReconnectParams, &usNextRetryBackOff ); + configASSERT( xBackoffAlgStatus != BackoffAlgorithmRngFailure ); - if( xRetryUtilsStatus == RetryUtilsRetriesExhausted ) - { - LogError( ( "Connection to the broker failed. All attempts exhausted." ) ); + if( xBackoffAlgStatus == BackoffAlgorithmRetriesExhausted ) + { + LogError( ( "Connection to the broker failed, all attempts exhausted." ) ); + } + else if( xBackoffAlgStatus == BackoffAlgorithmSuccess ) + { + LogWarn( ( "Connection to the broker failed. " + "Retrying connection with backoff and jitter." ) ); + vTaskDelay( pdMS_TO_TICKS( usNextRetryBackOff ) ); + } } - } while( ( xConnected != pdPASS ) && ( xRetryUtilsStatus == RetryUtilsSuccess ) ); + } while( ( xConnected != pdPASS ) && ( xBackoffAlgStatus == BackoffAlgorithmSuccess ) ); /* Set the socket wakeup callback. */ if( xConnected ) diff --git a/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Multitask/WIN32.vcxproj b/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Multitask/WIN32.vcxproj index 6b6c96ff7f..8ca9ac726e 100644 --- a/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Multitask/WIN32.vcxproj +++ b/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Multitask/WIN32.vcxproj @@ -58,7 +58,7 @@ Disabled - ..\..\..\..\Source\FreeRTOS-Plus-Trace\Include;..\..\..\..\FreeRTOS-Plus\Source\FreeRTOS-Plus-TCP\include;..\..\..\..\FreeRTOS-Plus\Source\FreeRTOS-Plus-TCP\portable\BufferManagement;..\..\..\..\FreeRTOS-Plus\Source\FreeRTOS-Plus-TCP\portable\Compiler\MSVC;..\..\..\..\FreeRTOS-Plus\Source\Utilities\logging;..\common\WinPCap;..\..\..\..\FreeRTOS\Source\include;..\..\..\..\FreeRTOS\Source\portable\MSVC-MingW;..\..\..\Source\Application-Protocols\coreMQTT\source\include;..\..\..\Source\Application-Protocols\coreMQTT\source\interface;..\..\..\Source\Utilities\exponential_backoff;..\..\..\Source\Application-Protocols\network_transport\freertos_plus_tcp;..\..\..\Source\Application-Protocols\network_transport\freertos_plus_tcp\using_plaintext;..\..\..\Source\Application-Protocols\network_transport\freertos_plus_tcp\using_mbedtls;..\..\..\Source\Utilities\mbedtls_freertos;..\..\..\..\Source\mbedtls_utils;..\..\..\ThirdParty\mbedtls\include;.;%(AdditionalIncludeDirectories) + ..\..\..\..\Source\FreeRTOS-Plus-Trace\Include;..\..\..\..\FreeRTOS-Plus\Source\FreeRTOS-Plus-TCP\include;..\..\..\..\FreeRTOS-Plus\Source\FreeRTOS-Plus-TCP\portable\BufferManagement;..\..\..\..\FreeRTOS-Plus\Source\FreeRTOS-Plus-TCP\portable\Compiler\MSVC;..\..\..\..\FreeRTOS-Plus\Source\Utilities\logging;..\common\WinPCap;..\..\..\..\FreeRTOS\Source\include;..\..\..\..\FreeRTOS\Source\portable\MSVC-MingW;..\..\..\Source\Application-Protocols\coreMQTT\source\include;..\..\..\Source\Application-Protocols\coreMQTT\source\interface;..\..\..\Source\Utilities\backoff_algorithm\source\include;..\..\..\Source\Application-Protocols\network_transport\freertos_plus_tcp;..\..\..\Source\Application-Protocols\network_transport\freertos_plus_tcp\using_plaintext;..\..\..\Source\Application-Protocols\network_transport\freertos_plus_tcp\using_mbedtls;..\..\..\Source\Utilities\mbedtls_freertos;..\..\..\..\Source\mbedtls_utils;..\..\..\ThirdParty\mbedtls\include;.;%(AdditionalIncludeDirectories) MBEDTLS_CONFIG_FILE="mbedtls_config.h";WIN32;_DEBUG;_CONSOLE;_WIN32_WINNT=0x0500;WINVER=0x400;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) false EnableFastChecks @@ -159,7 +159,7 @@ - + @@ -522,7 +522,7 @@ - + diff --git a/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Multitask/WIN32.vcxproj.filters b/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Multitask/WIN32.vcxproj.filters index 04f7c6d55c..2521eb7d69 100644 --- a/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Multitask/WIN32.vcxproj.filters +++ b/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Multitask/WIN32.vcxproj.filters @@ -393,7 +393,7 @@ FreeRTOS+\FreeRTOS IoT Libraries\platform\mbedtls - + FreeRTOS+\FreeRTOS IoT Libraries\platform\freertos @@ -492,7 +492,7 @@ FreeRTOS+\FreeRTOS IoT Libraries\platform - + FreeRTOS+\FreeRTOS IoT Libraries\platform diff --git a/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Mutual_Auth/DemoTasks/MutualAuthMQTTExample.c b/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Mutual_Auth/DemoTasks/MutualAuthMQTTExample.c index 11896d3f5e..785b52c2d0 100644 --- a/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Mutual_Auth/DemoTasks/MutualAuthMQTTExample.c +++ b/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Mutual_Auth/DemoTasks/MutualAuthMQTTExample.c @@ -55,7 +55,7 @@ #include "core_mqtt.h" /* Exponential backoff retry include. */ -#include "exponential_backoff.h" +#include "backoff_algorithm.h" /* Transport interface implementation include header for TLS. */ #include "using_mbedtls.h" @@ -128,6 +128,23 @@ /*-----------------------------------------------------------*/ +/** + * @brief The maximum number of retries for network operation with server. + */ +#define mqttexampleRETRY_MAX_ATTEMPTS ( 5U ) + +/** + * @brief The maximum back-off delay (in milliseconds) for retrying failed operation + * with server. + */ +#define mqttexampleRETRY_MAX_BACKOFF_DELAY_MS ( 5000U ) + +/** + * @brief The base back-off delay (in milliseconds) to use for network operation retry + * attempts. + */ +#define mqttexampleRETRY_BACKOFF_BASE_MS ( 500U ) + /** * @brief Timeout for receiving CONNACK packet in milliseconds. */ @@ -265,6 +282,22 @@ */ static void prvMQTTDemoTask( void * pvParameters ); +/** + * @brief A wrapper to the "uxRand()" random number generator so that it + * can be passed to the backoffAlgorithm library for retry logic. + * + * This function implements the #BackoffAlgorithm_RNG_T type interface + * in the backoffAlgorithm library API. + * + * @note The "uxRand" function represents a pseudo random number generator. + * However, it is recommended to use a True Randon Number Generator (TRNG) + * for generating unique device-specific random values to avoid possibility + * of network collisions from multiple devices retrying network operations. + * + * @return The generated randon number. This function ALWAYS succeeds. + */ +static int32_t prvGenerateRandomNumber(); + /** * @brief Connect to MQTT broker with reconnection retries. * @@ -494,7 +527,7 @@ static void prvMQTTDemoTask( void * pvParameters ) /* If server rejected the subscription request, attempt to resubscribe to * topic. Attempts are made according to the exponential backoff retry - * strategy implemented in retryUtils. */ + * strategy implemented in BackoffAlgorithm. */ prvMQTTSubscribeWithBackoffRetries( &xMQTTContext ); /****************** Publish and Keep Alive Loop. **********************/ @@ -557,12 +590,20 @@ static void prvMQTTDemoTask( void * pvParameters ) } /*-----------------------------------------------------------*/ +static int32_t prvGenerateRandomNumber() +{ + return( uxRand() & INT32_MAX ); +} + +/*-----------------------------------------------------------*/ + static TlsTransportStatus_t prvConnectToServerWithBackoffRetries( NetworkCredentials_t * pxNetworkCredentials, NetworkContext_t * pxNetworkContext ) { TlsTransportStatus_t xNetworkStatus; - RetryUtilsStatus_t xRetryUtilsStatus = RetryUtilsSuccess; - RetryUtilsParams_t xReconnectParams; + BackoffAlgorithmStatus_t xBackoffAlgStatus = BackoffAlgorithmSuccess; + BackoffAlgorithmContext_t xReconnectParams; + uint16_t usNextRetryBackOff = 0U; #ifdef democonfigUSE_AWS_IOT_CORE_BROKER @@ -590,9 +631,16 @@ static TlsTransportStatus_t prvConnectToServerWithBackoffRetries( NetworkCredent pxNetworkCredentials->pPrivateKey = ( const unsigned char * ) democonfigCLIENT_PRIVATE_KEY_PEM; pxNetworkCredentials->privateKeySize = sizeof( democonfigCLIENT_PRIVATE_KEY_PEM ); #endif - /* Initialize reconnect attempts and interval. */ - RetryUtils_ParamsReset( &xReconnectParams ); - xReconnectParams.maxRetryAttempts = MAX_RETRY_ATTEMPTS; + + /* Initialize reconnect attempts and interval. + * Note: This demo is using pseudo random number generator for the backoff + * algorithm. However, it is recommended to use a True Random Number generator to + * avoid possibility of collisions between multiple devices retrying connection. */ + BackoffAlgorithm_InitializeParams( &xReconnectParams, + mqttexampleRETRY_BACKOFF_BASE_MS, + mqttexampleRETRY_MAX_BACKOFF_DELAY_MS, + mqttexampleRETRY_MAX_ATTEMPTS, + prvGenerateRandomNumber ); /* Attempt to connect to MQTT broker. If connection fails, retry after * a timeout. Timeout value will exponentially increase till maximum @@ -616,16 +664,22 @@ static TlsTransportStatus_t prvConnectToServerWithBackoffRetries( NetworkCredent if( xNetworkStatus != TLS_TRANSPORT_SUCCESS ) { - LogWarn( ( "Connection to the broker failed. Retrying connection with backoff and jitter." ) ); - xRetryUtilsStatus = RetryUtils_BackoffAndSleep( &xReconnectParams ); - } + /* Get back-off value (in milliseconds) for the next connection retry. */ + xBackoffAlgStatus = BackoffAlgorithm_GetNextBackoff( &xReconnectParams, &usNextRetryBackOff ); + configASSERT( xBackoffAlgStatus != BackoffAlgorithmRngFailure ); - if( xRetryUtilsStatus == RetryUtilsRetriesExhausted ) - { - LogError( ( "Connection to the broker failed, all attempts exhausted." ) ); - xNetworkStatus = TLS_TRANSPORT_CONNECT_FAILURE; + if( xBackoffAlgStatus == BackoffAlgorithmRetriesExhausted ) + { + LogError( ( "Connection to the broker failed, all attempts exhausted." ) ); + } + else if( xBackoffAlgStatus == BackoffAlgorithmSuccess ) + { + LogWarn( ( "Connection to the broker failed. " + "Retrying connection with backoff and jitter." ) ); + vTaskDelay( pdMS_TO_TICKS( usNextRetryBackOff ) ); + } } - } while( ( xNetworkStatus != TLS_TRANSPORT_SUCCESS ) && ( xRetryUtilsStatus == RetryUtilsSuccess ) ); + } while( ( xNetworkStatus != TLS_TRANSPORT_SUCCESS ) && ( xBackoffAlgStatus == BackoffAlgorithmSuccess ) ); return xNetworkStatus; } @@ -732,8 +786,9 @@ static void prvUpdateSubAckStatus( MQTTPacketInfo_t * pxPacketInfo ) static void prvMQTTSubscribeWithBackoffRetries( MQTTContext_t * pxMQTTContext ) { MQTTStatus_t xResult = MQTTSuccess; - RetryUtilsStatus_t xRetryUtilsStatus = RetryUtilsSuccess; - RetryUtilsParams_t xRetryParams; + BackoffAlgorithmStatus_t xBackoffAlgStatus = BackoffAlgorithmSuccess; + BackoffAlgorithmContext_t xRetryParams; + uint16_t usNextRetryBackOff = 0U; MQTTSubscribeInfo_t xMQTTSubscription[ mqttexampleTOPIC_COUNT ]; bool xFailedSubscribeToTopic = false; uint32_t ulTopicCount = 0U; @@ -750,9 +805,15 @@ static void prvMQTTSubscribeWithBackoffRetries( MQTTContext_t * pxMQTTContext ) xMQTTSubscription[ 0 ].pTopicFilter = mqttexampleTOPIC; xMQTTSubscription[ 0 ].topicFilterLength = ( uint16_t ) strlen( mqttexampleTOPIC ); - /* Initialize retry attempts and interval. */ - RetryUtils_ParamsReset( &xRetryParams ); - xRetryParams.maxRetryAttempts = MAX_RETRY_ATTEMPTS; + /* Initialize context for backoff retry attempts if SUBSCRIBE request fails. + * Note: This demo is using pseudo random number generator for the backoff + * algorithm. However, it is recommended to use a True Random Number generator to + * avoid possibility of collisions between multiple devices retrying network operations. */ + BackoffAlgorithm_InitializeParams( &xRetryParams, + mqttexampleRETRY_BACKOFF_BASE_MS, + mqttexampleRETRY_MAX_BACKOFF_DELAY_MS, + mqttexampleRETRY_MAX_ATTEMPTS, + prvGenerateRandomNumber ); do { @@ -793,16 +854,31 @@ static void prvMQTTSubscribeWithBackoffRetries( MQTTContext_t * pxMQTTContext ) { if( xTopicFilterContext[ ulTopicCount ].xSubAckStatus == MQTTSubAckFailure ) { - LogWarn( ( "Server rejected subscription request. Attempting to re-subscribe to topic %s.", - xTopicFilterContext[ ulTopicCount ].pcTopicFilter ) ); xFailedSubscribeToTopic = true; - xRetryUtilsStatus = RetryUtils_BackoffAndSleep( &xRetryParams ); + + /* Get back-off value (in milliseconds) for the next connection retry. */ + xBackoffAlgStatus = BackoffAlgorithm_GetNextBackoff( &xRetryParams, &usNextRetryBackOff ); + configASSERT( xBackoffAlgStatus != BackoffAlgorithmRngFailure ); + + if( xBackoffAlgStatus == BackoffAlgorithmRetriesExhausted ) + { + LogError( ( "Server rejected subscription request. All retry attempts have exhausted. Topic=%s", + xTopicFilterContext[ ulTopicCount ].pcTopicFilter ) ); + } + else if( xBackoffAlgStatus == BackoffAlgorithmSuccess ) + { + LogWarn( ( "Server rejected subscription request. Attempting to re-subscribe to topic %s.", + xTopicFilterContext[ ulTopicCount ].pcTopicFilter ) ); + /* Backoff before the next re-subscribe attempt. */ + vTaskDelay( pdMS_TO_TICKS( usNextRetryBackOff ) ); + } + break; } } - configASSERT( xRetryUtilsStatus != RetryUtilsRetriesExhausted ); - } while( ( xFailedSubscribeToTopic == true ) && ( xRetryUtilsStatus == RetryUtilsSuccess ) ); + configASSERT( xBackoffAlgStatus != BackoffAlgorithmRetriesExhausted ); + } while( ( xFailedSubscribeToTopic == true ) && ( xBackoffAlgStatus == BackoffAlgorithmSuccess ) ); } /*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Mutual_Auth/WIN32.vcxproj b/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Mutual_Auth/WIN32.vcxproj index 68fe9541dd..0d699023a0 100644 --- a/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Mutual_Auth/WIN32.vcxproj +++ b/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Mutual_Auth/WIN32.vcxproj @@ -58,7 +58,7 @@ Disabled - ..\..\..\..\Source\FreeRTOS-Plus-Trace\Include;..\..\..\..\FreeRTOS-Plus\Source\FreeRTOS-Plus-TCP\include;..\..\..\..\FreeRTOS-Plus\Source\FreeRTOS-Plus-TCP\portable\BufferManagement;..\..\..\..\FreeRTOS-Plus\Source\FreeRTOS-Plus-TCP\portable\Compiler\MSVC;..\..\..\..\FreeRTOS-Plus\Source\Utilities\logging;..\common\WinPCap;..\..\..\..\FreeRTOS\Source\include;..\..\..\..\FreeRTOS\Source\portable\MSVC-MingW;..\..\..\Source\Application-Protocols\coreMQTT\source\include;..\..\..\Source\Application-Protocols\coreMQTT\source\interface;..\..\..\Source\Utilities\exponential_backoff;..\..\..\Source\Application-Protocols\network_transport\freertos_plus_tcp;..\..\..\Source\Application-Protocols\network_transport\freertos_plus_tcp\using_mbedtls;..\..\..\Source\Utilities\mbedtls_freertos;..\..\..\..\Source\mbedtls_utils;..\..\..\ThirdParty\mbedtls\include;.;%(AdditionalIncludeDirectories) + ..\..\..\..\Source\FreeRTOS-Plus-Trace\Include;..\..\..\..\FreeRTOS-Plus\Source\FreeRTOS-Plus-TCP\include;..\..\..\..\FreeRTOS-Plus\Source\FreeRTOS-Plus-TCP\portable\BufferManagement;..\..\..\..\FreeRTOS-Plus\Source\FreeRTOS-Plus-TCP\portable\Compiler\MSVC;..\..\..\..\FreeRTOS-Plus\Source\Utilities\logging;..\common\WinPCap;..\..\..\..\FreeRTOS\Source\include;..\..\..\..\FreeRTOS\Source\portable\MSVC-MingW;..\..\..\Source\Application-Protocols\coreMQTT\source\include;..\..\..\Source\Application-Protocols\coreMQTT\source\interface;..\..\..\Source\Utilities\backoff_algorithm\source\include;..\..\..\Source\Application-Protocols\network_transport\freertos_plus_tcp;..\..\..\Source\Application-Protocols\network_transport\freertos_plus_tcp\using_mbedtls;..\..\..\Source\Utilities\mbedtls_freertos;..\..\..\..\Source\mbedtls_utils;..\..\..\ThirdParty\mbedtls\include;.;%(AdditionalIncludeDirectories) MBEDTLS_CONFIG_FILE="mbedtls_config.h";WIN32;_DEBUG;_CONSOLE;_WIN32_WINNT=0x0500;WINVER=0x400;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) false EnableFastChecks @@ -159,7 +159,7 @@ - + @@ -520,7 +520,7 @@ - + diff --git a/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Mutual_Auth/WIN32.vcxproj.filters b/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Mutual_Auth/WIN32.vcxproj.filters index 30e699ad3e..7d2108fe46 100644 --- a/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Mutual_Auth/WIN32.vcxproj.filters +++ b/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Mutual_Auth/WIN32.vcxproj.filters @@ -393,7 +393,7 @@ FreeRTOS+\FreeRTOS IoT Libraries\platform\mbedtls - + FreeRTOS+\FreeRTOS IoT Libraries\platform\freertos @@ -489,7 +489,7 @@ FreeRTOS+\FreeRTOS IoT Libraries\platform - + FreeRTOS+\FreeRTOS IoT Libraries\platform diff --git a/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Plain_Text/DemoTasks/PlaintextMQTTExample.c b/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Plain_Text/DemoTasks/PlaintextMQTTExample.c index cb25ff5902..da3975c76e 100644 --- a/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Plain_Text/DemoTasks/PlaintextMQTTExample.c +++ b/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Plain_Text/DemoTasks/PlaintextMQTTExample.c @@ -53,7 +53,7 @@ #include "core_mqtt.h" /* Exponential backoff retry include. */ -#include "exponential_backoff.h" +#include "backoff_algorithm.h" /* Transport interface include. */ #include "using_plaintext.h" @@ -93,6 +93,24 @@ /*-----------------------------------------------------------*/ +/** + * @brief The maximum number of retries for network operation with server. + */ +#define mqttexampleRETRY_MAX_ATTEMPTS ( 5U ) + +/** + * @brief The maximum back-off delay (in milliseconds) for retrying failed operation + * with server. + */ +#define mqttexampleRETRY_MAX_BACKOFF_DELAY_MS ( 5000U ) + +/** + * @brief The base back-off delay (in milliseconds) to use for network operation retry + * attempts. + */ +#define mqttexampleRETRY_BACKOFF_BASE_MS ( 500U ) + + /** * @brief Timeout for receiving CONNACK packet in milliseconds. */ @@ -166,6 +184,22 @@ */ static void prvMQTTDemoTask( void * pvParameters ); +/** + * @brief A wrapper to the "uxRand()" random number generator so that it + * can be passed to the backoffAlgorithm library for retry logic. + * + * This function implements the #BackoffAlgorithm_RNG_T type interface + * in the backoffAlgorithm library API. + * + * @note The "uxRand" function represents a pseudo random number generator. + * However, it is recommended to use a True Randon Number Generator (TRNG) + * for generating unique device-specific random values to avoid possibility + * of network collisions from multiple devices retrying network operations. + * + * @return The generated randon number. This function ALWAYS succeeds. + */ +static int32_t prvGenerateRandomNumber(); + /** * @brief Connect to MQTT broker with reconnection retries. * @@ -370,7 +404,7 @@ static void prvMQTTDemoTask( void * pvParameters ) /* If server rejected the subscription request, attempt to resubscribe to * the topic. Attempts are made according to the exponential backoff retry - * strategy declared in exponential_backoff.h. */ + * strategy declared in backoff_algorithm.h. */ prvMQTTSubscribeWithBackoffRetries( &xMQTTContext ); /******************* Publish and Keep Alive Loop. *********************/ @@ -434,15 +468,29 @@ static void prvMQTTDemoTask( void * pvParameters ) } /*-----------------------------------------------------------*/ +static int32_t prvGenerateRandomNumber() +{ + return( uxRand() & INT32_MAX ); +} + +/*-----------------------------------------------------------*/ + static PlaintextTransportStatus_t prvConnectToServerWithBackoffRetries( NetworkContext_t * pxNetworkContext ) { PlaintextTransportStatus_t xNetworkStatus; - RetryUtilsStatus_t xRetryUtilsStatus = RetryUtilsSuccess; - RetryUtilsParams_t xReconnectParams; + BackoffAlgorithmStatus_t xBackoffAlgStatus = BackoffAlgorithmSuccess; + BackoffAlgorithmContext_t xReconnectParams; + uint16_t usNextRetryBackOff = 0U; - /* Initialize reconnect attempts and interval. */ - RetryUtils_ParamsReset( &xReconnectParams ); - xReconnectParams.maxRetryAttempts = MAX_RETRY_ATTEMPTS; + /* Initialize reconnect attempts and interval. + * Note: This demo is using pseudo random number generator for the backoff + * algorithm. However, it is recommended to use a True Random Number generator to + * avoid possibility of collisions between multiple devices retrying connection. */ + BackoffAlgorithm_InitializeParams( &xReconnectParams, + mqttexampleRETRY_BACKOFF_BASE_MS, + mqttexampleRETRY_MAX_BACKOFF_DELAY_MS, + mqttexampleRETRY_MAX_ATTEMPTS, + prvGenerateRandomNumber ); /* Attempt to connect to MQTT broker. If connection fails, retry after * a timeout. Timeout value will exponentially increase till maximum @@ -464,16 +512,22 @@ static PlaintextTransportStatus_t prvConnectToServerWithBackoffRetries( NetworkC if( xNetworkStatus != PLAINTEXT_TRANSPORT_SUCCESS ) { - LogWarn( ( "Connection to the broker failed. Retrying connection with backoff and jitter." ) ); - xRetryUtilsStatus = RetryUtils_BackoffAndSleep( &xReconnectParams ); - } + /* Get back-off value (in milliseconds) for the next connection retry. */ + xBackoffAlgStatus = BackoffAlgorithm_GetNextBackoff( &xReconnectParams, &usNextRetryBackOff ); + configASSERT( xBackoffAlgStatus != BackoffAlgorithmRngFailure ); - if( xRetryUtilsStatus == RetryUtilsRetriesExhausted ) - { - LogError( ( "Connection to the broker failed, all attempts exhausted." ) ); - xNetworkStatus = PLAINTEXT_TRANSPORT_CONNECT_FAILURE; + if( xBackoffAlgStatus == BackoffAlgorithmRetriesExhausted ) + { + LogError( ( "Connection to the broker failed, all attempts exhausted." ) ); + } + else if( xBackoffAlgStatus == BackoffAlgorithmSuccess ) + { + LogWarn( ( "Connection to the broker failed. " + "Retrying connection with backoff and jitter." ) ); + vTaskDelay( pdMS_TO_TICKS( usNextRetryBackOff ) ); + } } - } while( ( xNetworkStatus != PLAINTEXT_TRANSPORT_SUCCESS ) && ( xRetryUtilsStatus == RetryUtilsSuccess ) ); + } while( ( xNetworkStatus != PLAINTEXT_TRANSPORT_SUCCESS ) && ( xBackoffAlgStatus == BackoffAlgorithmSuccess ) ); return xNetworkStatus; } @@ -555,8 +609,9 @@ static void prvUpdateSubAckStatus( MQTTPacketInfo_t * pxPacketInfo ) static void prvMQTTSubscribeWithBackoffRetries( MQTTContext_t * pxMQTTContext ) { MQTTStatus_t xResult = MQTTSuccess; - RetryUtilsStatus_t xRetryUtilsStatus = RetryUtilsSuccess; - RetryUtilsParams_t xRetryParams; + BackoffAlgorithmStatus_t xBackoffAlgStatus = BackoffAlgorithmSuccess; + BackoffAlgorithmContext_t xRetryParams; + uint16_t usNextRetryBackOff = 0U; MQTTSubscribeInfo_t xMQTTSubscription[ mqttexampleTOPIC_COUNT ]; bool xFailedSubscribeToTopic = false; uint32_t ulTopicCount = 0U; @@ -573,9 +628,15 @@ static void prvMQTTSubscribeWithBackoffRetries( MQTTContext_t * pxMQTTContext ) xMQTTSubscription[ 0 ].pTopicFilter = mqttexampleTOPIC; xMQTTSubscription[ 0 ].topicFilterLength = ( uint16_t ) strlen( mqttexampleTOPIC ); - /* Initialize retry attempts and interval. */ - RetryUtils_ParamsReset( &xRetryParams ); - xRetryParams.maxRetryAttempts = MAX_RETRY_ATTEMPTS; + /* Initialize context for backoff retry attempts if SUBSCRIBE request fails. + * Note: This demo is using pseudo random number generator for the backoff + * algorithm. However, it is recommended to use a True Random Number generator to + * avoid possibility of collisions between multiple devices retrying network operations. */ + BackoffAlgorithm_InitializeParams( &xRetryParams, + mqttexampleRETRY_BACKOFF_BASE_MS, + mqttexampleRETRY_MAX_BACKOFF_DELAY_MS, + mqttexampleRETRY_MAX_ATTEMPTS, + prvGenerateRandomNumber ); do { @@ -616,16 +677,31 @@ static void prvMQTTSubscribeWithBackoffRetries( MQTTContext_t * pxMQTTContext ) { if( xTopicFilterContext[ ulTopicCount ].xSubAckStatus == MQTTSubAckFailure ) { - LogWarn( ( "Server rejected subscription request. Attempting to re-subscribe to topic %s.", - xTopicFilterContext[ ulTopicCount ].pcTopicFilter ) ); xFailedSubscribeToTopic = true; - xRetryUtilsStatus = RetryUtils_BackoffAndSleep( &xRetryParams ); + + /* Get back-off value (in milliseconds) for the next connection retry. */ + xBackoffAlgStatus = BackoffAlgorithm_GetNextBackoff( &xRetryParams, &usNextRetryBackOff ); + configASSERT( xBackoffAlgStatus != BackoffAlgorithmRngFailure ); + + if( xBackoffAlgStatus == BackoffAlgorithmRetriesExhausted ) + { + LogError( ( "Server rejected subscription request. All retry attempts have exhausted. Topic=%s", + xTopicFilterContext[ ulTopicCount ].pcTopicFilter ) ); + } + else if( xBackoffAlgStatus == BackoffAlgorithmSuccess ) + { + LogWarn( ( "Server rejected subscription request. Attempting to re-subscribe to topic %s.", + xTopicFilterContext[ ulTopicCount ].pcTopicFilter ) ); + /* Backoff before the next re-subscribe attempt. */ + vTaskDelay( pdMS_TO_TICKS( usNextRetryBackOff ) ); + } + break; } } - configASSERT( xRetryUtilsStatus != RetryUtilsRetriesExhausted ); - } while( ( xFailedSubscribeToTopic == true ) && ( xRetryUtilsStatus == RetryUtilsSuccess ) ); + configASSERT( xBackoffAlgStatus != BackoffAlgorithmRetriesExhausted ); + } while( ( xFailedSubscribeToTopic == true ) && ( xBackoffAlgStatus == BackoffAlgorithmSuccess ) ); } /*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Plain_Text/WIN32.vcxproj b/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Plain_Text/WIN32.vcxproj index dda51cdb8f..27a1274aab 100644 --- a/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Plain_Text/WIN32.vcxproj +++ b/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Plain_Text/WIN32.vcxproj @@ -58,7 +58,7 @@ Disabled - ..\..\..\..\Source\FreeRTOS-Plus-Trace\Include;..\..\..\..\FreeRTOS-Plus\Source\FreeRTOS-Plus-TCP\include;..\..\..\..\FreeRTOS-Plus\Source\FreeRTOS-Plus-TCP\portable\BufferManagement;..\..\..\..\FreeRTOS-Plus\Source\FreeRTOS-Plus-TCP\portable\Compiler\MSVC;..\..\..\..\FreeRTOS-Plus\Source\Utilities\logging;..\Common\WinPCap;..\..\..\..\FreeRTOS\Source\include;..\..\..\..\FreeRTOS\Source\portable\MSVC-MingW;..\..\..\Source\Application-Protocols\coreMQTT\source\include;..\..\..\Source\Application-Protocols\coreMQTT\source\interface;..\..\..\Source\Utilities\exponential_backoff;..\..\..\Source\Application-Protocols\network_transport\freertos_plus_tcp;..\..\..\Source\Application-Protocols\network_transport\freertos_plus_tcp\using_plaintext;.;%(AdditionalIncludeDirectories) + ..\..\..\..\Source\FreeRTOS-Plus-Trace\Include;..\..\..\..\FreeRTOS-Plus\Source\FreeRTOS-Plus-TCP\include;..\..\..\..\FreeRTOS-Plus\Source\FreeRTOS-Plus-TCP\portable\BufferManagement;..\..\..\..\FreeRTOS-Plus\Source\FreeRTOS-Plus-TCP\portable\Compiler\MSVC;..\..\..\..\FreeRTOS-Plus\Source\Utilities\logging;..\Common\WinPCap;..\..\..\..\FreeRTOS\Source\include;..\..\..\..\FreeRTOS\Source\portable\MSVC-MingW;..\..\..\Source\Application-Protocols\coreMQTT\source\include;..\..\..\Source\Application-Protocols\coreMQTT\source\interface;..\..\..\Source\Utilities\backoff_algorithm\source\include;..\..\..\Source\Application-Protocols\network_transport\freertos_plus_tcp;..\..\..\Source\Application-Protocols\network_transport\freertos_plus_tcp\using_plaintext;.;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_CONSOLE;_WIN32_WINNT=0x0500;WINVER=0x400;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) false EnableFastChecks @@ -159,7 +159,7 @@ - + @@ -196,7 +196,7 @@ - + diff --git a/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Plain_Text/WIN32.vcxproj.filters b/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Plain_Text/WIN32.vcxproj.filters index cc23ad0ee3..9416b4d916 100644 --- a/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Plain_Text/WIN32.vcxproj.filters +++ b/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Plain_Text/WIN32.vcxproj.filters @@ -126,7 +126,7 @@ FreeRTOS+\FreeRTOS IoT Libraries\platform - + FreeRTOS+\FreeRTOS IoT Libraries\platform @@ -219,7 +219,7 @@ FreeRTOS+\FreeRTOS IoT Libraries\platform - + FreeRTOS+\FreeRTOS IoT Libraries\platform diff --git a/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Serializer/DemoTasks/SerializerMQTTExample.c b/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Serializer/DemoTasks/SerializerMQTTExample.c index 9efd405785..b705eb5b81 100644 --- a/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Serializer/DemoTasks/SerializerMQTTExample.c +++ b/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Serializer/DemoTasks/SerializerMQTTExample.c @@ -61,7 +61,7 @@ #include "core_mqtt_serializer.h" /* Exponential backoff retry include. */ -#include "exponential_backoff.h" +#include "backoff_algorithm.h" /*-----------------------------------------------------------*/ @@ -122,6 +122,23 @@ */ #define mqttexampleSHARED_BUFFER_SIZE ( 500U ) +/** + * @brief The maximum number of retries for network operation with server. + */ +#define mqttexampleRETRY_MAX_ATTEMPTS ( 5U ) + +/** + * @brief The maximum back-off delay (in milliseconds) for retrying failed operation + * with server. + */ +#define mqttexampleRETRY_MAX_BACKOFF_DELAY_MS ( 5000U ) + +/** + * @brief The base back-off delay (in milliseconds) to use for network operation retry + * attempts. + */ +#define mqttexampleRETRY_BACKOFF_BASE_MS ( 500U ) + /** * @brief Time to wait between each cycle of the demo implemented by prvMQTTDemoTask(). */ @@ -172,6 +189,22 @@ static void prvMQTTDemoTask( void * pvParameters ); */ static Socket_t prvCreateTCPConnectionToBroker( void ); +/** + * @brief A wrapper to the "uxRand()" random number generator so that it + * can be passed to the backoffAlgorithm library for retry logic. + * + * This function implements the #BackoffAlgorithm_RNG_T type interface + * in the backoffAlgorithm library API. + * + * @note The "uxRand" function represents a pseudo random number generator. + * However, it is recommended to use a True Randon Number Generator (TRNG) + * for generating unique device-specific random values to avoid possibility + * of network collisions from multiple devices retrying network operations. + * + * @return The generated randon number. This function ALWAYS succeeds. + */ +static int32_t prvGenerateRandomNumber(); + /** * @brief Connect to MQTT broker with reconnection retries. * @@ -421,7 +454,7 @@ static void prvMQTTDemoTask( void * pvParameters ) /* If the server rejected the subscription request, attempt to resubscribe * to the topic. Attempts are made according to the exponential backoff - * retry strategy declared in exponential_backoff.h. */ + * retry strategy declared in backoff_algorithm.h. */ prvMQTTSubscribeWithBackoffRetries( xMQTTSocket ); /**************************** Publish and Keep-Alive Loop. ******************************/ @@ -610,15 +643,29 @@ static Socket_t prvCreateTCPConnectionToBroker( void ) } /*-----------------------------------------------------------*/ +static int32_t prvGenerateRandomNumber() +{ + return( uxRand() & INT32_MAX ); +} + +/*-----------------------------------------------------------*/ + static Socket_t prvConnectToServerWithBackoffRetries() { Socket_t xSocket; - RetryUtilsStatus_t xRetryUtilsStatus = RetryUtilsSuccess; - RetryUtilsParams_t xReconnectParams; + BackoffAlgorithmStatus_t xBackoffAlgStatus = BackoffAlgorithmSuccess; + BackoffAlgorithmContext_t xReconnectParams; + uint16_t usNextRetryBackOff = 0U; - /* Initialize reconnect attempts and interval. */ - RetryUtils_ParamsReset( &xReconnectParams ); - xReconnectParams.maxRetryAttempts = MAX_RETRY_ATTEMPTS; + /* Initialize reconnect attempts and interval. + * Note: This demo is using pseudo random number generator for the backoff + * algorithm. However, it is recommended to use a True Random Number generator to + * avoid possibility of collisions between multiple devices retrying connection. */ + BackoffAlgorithm_InitializeParams( &xReconnectParams, + mqttexampleRETRY_BACKOFF_BASE_MS, + mqttexampleRETRY_MAX_BACKOFF_DELAY_MS, + mqttexampleRETRY_MAX_ATTEMPTS, + prvGenerateRandomNumber ); /* Attempt to connect to MQTT broker. If connection fails, retry after * a timeout. Timeout value will exponentially increase till maximum @@ -636,16 +683,22 @@ static Socket_t prvConnectToServerWithBackoffRetries() if( xSocket == FREERTOS_INVALID_SOCKET ) { - LogWarn( ( "Connection to the broker failed. Retrying connection with backoff and jitter." ) ); - xRetryUtilsStatus = RetryUtils_BackoffAndSleep( &xReconnectParams ); - } + /* Get back-off value (in milliseconds) for the next connection retry. */ + xBackoffAlgStatus = BackoffAlgorithm_GetNextBackoff( &xReconnectParams, &usNextRetryBackOff ); + configASSERT( xBackoffAlgStatus != BackoffAlgorithmRngFailure ); - if( xRetryUtilsStatus == RetryUtilsRetriesExhausted ) - { - LogError( ( "Connection to the broker failed, all attempts exhausted." ) ); - xSocket = FREERTOS_INVALID_SOCKET; + if( xBackoffAlgStatus == BackoffAlgorithmRetriesExhausted ) + { + LogError( ( "Connection to the broker failed, all attempts exhausted." ) ); + } + else if( xBackoffAlgStatus == BackoffAlgorithmSuccess ) + { + LogWarn( ( "Connection to the broker failed. " + "Retrying connection with backoff and jitter." ) ); + vTaskDelay( pdMS_TO_TICKS( usNextRetryBackOff ) ); + } } - } while( ( xSocket == FREERTOS_INVALID_SOCKET ) && ( xRetryUtilsStatus == RetryUtilsSuccess ) ); + } while( ( xSocket == FREERTOS_INVALID_SOCKET ) && ( xBackoffAlgStatus == BackoffAlgorithmSuccess ) ); return xSocket; } @@ -812,13 +865,20 @@ static void prvMQTTSubscribeToTopic( Socket_t xMQTTSocket ) static void prvMQTTSubscribeWithBackoffRetries( Socket_t xMQTTSocket ) { uint32_t ulTopicCount = 0U; - RetryUtilsStatus_t xRetryUtilsStatus = RetryUtilsSuccess; - RetryUtilsParams_t xRetryParams; + BackoffAlgorithmStatus_t xBackoffAlgStatus = BackoffAlgorithmSuccess; + BackoffAlgorithmContext_t xRetryParams; + uint16_t usNextRetryBackOff = 0U; bool xFailedSubscribeToTopic = false; - /* Initialize retry attempts and interval. */ - RetryUtils_ParamsReset( &xRetryParams ); - xRetryParams.maxRetryAttempts = MAX_RETRY_ATTEMPTS; + /* Initialize context for backoff retry attempts if SUBSCRIBE request fails. + * Note: This demo is using pseudo random number generator for the backoff + * algorithm. However, it is recommended to use a True Random Number generator to + * avoid possibility of collisions between multiple devices retrying network operations. */ + BackoffAlgorithm_InitializeParams( &xRetryParams, + mqttexampleRETRY_BACKOFF_BASE_MS, + mqttexampleRETRY_MAX_BACKOFF_DELAY_MS, + mqttexampleRETRY_MAX_ATTEMPTS, + prvGenerateRandomNumber ); do { @@ -854,16 +914,31 @@ static void prvMQTTSubscribeWithBackoffRetries( Socket_t xMQTTSocket ) { if( xTopicFilterContext[ ulTopicCount ].xSubAckSuccess == false ) { - LogWarn( ( "Server rejected subscription request. Attempting to re-subscribe to topic %s.", - xTopicFilterContext[ ulTopicCount ].pcTopicFilter ) ); xFailedSubscribeToTopic = true; - xRetryUtilsStatus = RetryUtils_BackoffAndSleep( &xRetryParams ); + + /* Get back-off value (in milliseconds) for the next connection retry. */ + xBackoffAlgStatus = BackoffAlgorithm_GetNextBackoff( &xRetryParams, &usNextRetryBackOff ); + configASSERT( xBackoffAlgStatus != BackoffAlgorithmRngFailure ); + + if( xBackoffAlgStatus == BackoffAlgorithmRetriesExhausted ) + { + LogError( ( "Server rejected subscription request. All retry attempts have exhausted. Topic=%s", + xTopicFilterContext[ ulTopicCount ].pcTopicFilter ) ); + } + else if( xBackoffAlgStatus == BackoffAlgorithmSuccess ) + { + LogWarn( ( "Server rejected subscription request. Attempting to re-subscribe to topic %s.", + xTopicFilterContext[ ulTopicCount ].pcTopicFilter ) ); + /* Backoff before the next re-subscribe attempt. */ + vTaskDelay( pdMS_TO_TICKS( usNextRetryBackOff ) ); + } + break; } } - configASSERT( xRetryUtilsStatus != RetryUtilsRetriesExhausted ); - } while( ( xFailedSubscribeToTopic == true ) && ( xRetryUtilsStatus == RetryUtilsSuccess ) ); + configASSERT( xBackoffAlgStatus != BackoffAlgorithmRetriesExhausted ); + } while( ( xFailedSubscribeToTopic == true ) && ( xBackoffAlgStatus == BackoffAlgorithmSuccess ) ); } /*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Serializer/WIN32.vcxproj b/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Serializer/WIN32.vcxproj index 1df88f7d2d..b934a6479c 100644 --- a/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Serializer/WIN32.vcxproj +++ b/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Serializer/WIN32.vcxproj @@ -58,7 +58,7 @@ Disabled - ..\..\..\..\Source\FreeRTOS-Plus-Trace\Include;..\..\..\..\FreeRTOS-Plus\Source\FreeRTOS-Plus-TCP\include;..\..\..\..\FreeRTOS-Plus\Source\FreeRTOS-Plus-TCP\portable\BufferManagement;..\..\..\..\FreeRTOS-Plus\Source\FreeRTOS-Plus-TCP\portable\Compiler\MSVC;..\..\..\..\FreeRTOS-Plus\Source\Utilities\logging;..\Common\WinPCap;..\..\..\..\FreeRTOS\Source\include;..\..\..\..\FreeRTOS\Source\portable\MSVC-MingW;..\..\..\Source\Utilities\exponential_backoff;..\..\..\Source\Application-Protocols\coreMQTT\source\include;..\..\..\Source\Application-Protocols\coreMQTT\source\interface;.;%(AdditionalIncludeDirectories) + ..\..\..\..\Source\FreeRTOS-Plus-Trace\Include;..\..\..\..\FreeRTOS-Plus\Source\FreeRTOS-Plus-TCP\include;..\..\..\..\FreeRTOS-Plus\Source\FreeRTOS-Plus-TCP\portable\BufferManagement;..\..\..\..\FreeRTOS-Plus\Source\FreeRTOS-Plus-TCP\portable\Compiler\MSVC;..\..\..\..\FreeRTOS-Plus\Source\Utilities\logging;..\Common\WinPCap;..\..\..\..\FreeRTOS\Source\include;..\..\..\..\FreeRTOS\Source\portable\MSVC-MingW;..\..\..\Source\Utilities\backoff_algorithm\source\include;..\..\..\Source\Application-Protocols\coreMQTT\source\include;..\..\..\Source\Application-Protocols\coreMQTT\source\interface;.;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_CONSOLE;_WIN32_WINNT=0x0500;WINVER=0x400;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) false EnableFastChecks @@ -157,7 +157,7 @@ - + diff --git a/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Serializer/WIN32.vcxproj.filters b/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Serializer/WIN32.vcxproj.filters index 28070be2e0..c32d370438 100644 --- a/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Serializer/WIN32.vcxproj.filters +++ b/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Serializer/WIN32.vcxproj.filters @@ -114,7 +114,7 @@ FreeRTOS+\FreeRTOS IoT Libraries\standard\coreMQTT\src - + FreeRTOS+\FreeRTOS IoT Libraries\platform diff --git a/FreeRTOS-Plus/Demo/corePKCS11_MQTT_Mutual_Auth_Windows_Simulator/WIN32.vcxproj b/FreeRTOS-Plus/Demo/corePKCS11_MQTT_Mutual_Auth_Windows_Simulator/WIN32.vcxproj index 912d531900..e2720f0f35 100644 --- a/FreeRTOS-Plus/Demo/corePKCS11_MQTT_Mutual_Auth_Windows_Simulator/WIN32.vcxproj +++ b/FreeRTOS-Plus/Demo/corePKCS11_MQTT_Mutual_Auth_Windows_Simulator/WIN32.vcxproj @@ -58,7 +58,7 @@ Disabled - ..\..\Source\FreeRTOS-Plus-Trace\Include;..\..\..\FreeRTOS-Plus\Source\FreeRTOS-Plus-TCP\include;..\..\..\FreeRTOS-Plus\Source\FreeRTOS-Plus-TCP\portable\BufferManagement;..\..\..\FreeRTOS-Plus\Source\FreeRTOS-Plus-TCP\portable\Compiler\MSVC;..\..\..\FreeRTOS-Plus\Source\Utilities\logging;..\coreMQTT_Windows_Simulator\Common;..\coreMQTT_Windows_Simulator\common\WinPCap;..\..\..\FreeRTOS\Source\include;..\..\..\FreeRTOS\Source\portable\MSVC-MingW;..\..\Source\corePKCS11\source\include;..\..\Source\corePKCS11\3rdparty\pkcs11;..\..\Source\Application-Protocols\coreMQTT\source\include;..\..\Source\Application-Protocols\coreMQTT\source\interface;..\..\Source\Utilities\exponential_backoff;..\..\Source\Application-Protocols\network_transport\freertos_plus_tcp;..\..\Source\Application-Protocols\network_transport\freertos_plus_tcp\using_mbedtls_pkcs11;..\..\Source\Utilities\mbedtls_freertos;..\..\Source\mbedtls_utils;..\..\ThirdParty\mbedtls\include;.;%(AdditionalIncludeDirectories) + ..\..\Source\FreeRTOS-Plus-Trace\Include;..\..\..\FreeRTOS-Plus\Source\FreeRTOS-Plus-TCP\include;..\..\..\FreeRTOS-Plus\Source\FreeRTOS-Plus-TCP\portable\BufferManagement;..\..\..\FreeRTOS-Plus\Source\FreeRTOS-Plus-TCP\portable\Compiler\MSVC;..\..\..\FreeRTOS-Plus\Source\Utilities\logging;..\coreMQTT_Windows_Simulator\Common;..\coreMQTT_Windows_Simulator\common\WinPCap;..\..\..\FreeRTOS\Source\include;..\..\..\FreeRTOS\Source\portable\MSVC-MingW;..\..\Source\corePKCS11\source\include;..\..\Source\corePKCS11\3rdparty\pkcs11;..\..\Source\Application-Protocols\coreMQTT\source\include;..\..\Source\Application-Protocols\coreMQTT\source\interface;..\..\Source\Utilities\backoff_algorithm\source\include;..\..\Source\Application-Protocols\network_transport\freertos_plus_tcp;..\..\Source\Application-Protocols\network_transport\freertos_plus_tcp\using_mbedtls_pkcs11;..\..\Source\Utilities\mbedtls_freertos;..\..\Source\mbedtls_utils;..\..\ThirdParty\mbedtls\include;.;%(AdditionalIncludeDirectories) MBEDTLS_CONFIG_FILE="mbedtls_config.h";WIN32;_DEBUG;_CONSOLE;_WIN32_WINNT=0x0500;WINVER=0x400;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) false EnableFastChecks @@ -159,7 +159,7 @@ - + @@ -290,7 +290,7 @@ - + diff --git a/FreeRTOS-Plus/Demo/corePKCS11_MQTT_Mutual_Auth_Windows_Simulator/WIN32.vcxproj.filters b/FreeRTOS-Plus/Demo/corePKCS11_MQTT_Mutual_Auth_Windows_Simulator/WIN32.vcxproj.filters index 5b00cde29c..6100efc9e5 100644 --- a/FreeRTOS-Plus/Demo/corePKCS11_MQTT_Mutual_Auth_Windows_Simulator/WIN32.vcxproj.filters +++ b/FreeRTOS-Plus/Demo/corePKCS11_MQTT_Mutual_Auth_Windows_Simulator/WIN32.vcxproj.filters @@ -175,7 +175,7 @@ Transport - + Transport @@ -541,7 +541,7 @@ FreeRTOS+\FreeRTOS IoT Libraries\platform - + FreeRTOS+\FreeRTOS IoT Libraries\platform diff --git a/FreeRTOS-Plus/Source/Utilities/backoff_algorithm b/FreeRTOS-Plus/Source/Utilities/backoff_algorithm new file mode 160000 index 0000000000..bc5ce2ed93 --- /dev/null +++ b/FreeRTOS-Plus/Source/Utilities/backoff_algorithm @@ -0,0 +1 @@ +Subproject commit bc5ce2ed93ac063d75a4d3661e5253477c4e4fef diff --git a/FreeRTOS-Plus/Source/Utilities/exponential_backoff/exponential_backoff.c b/FreeRTOS-Plus/Source/Utilities/exponential_backoff/exponential_backoff.c deleted file mode 100644 index 7546884b25..0000000000 --- a/FreeRTOS-Plus/Source/Utilities/exponential_backoff/exponential_backoff.c +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/** - * @file exponential_backoff.c - * @brief Utility implementation of backoff logic, used for attempting retries of failed processes. - */ - -/* Standard includes. */ -#include - -/* Kernel includes. */ -#include "FreeRTOS.h" -#include "task.h" - -#include "exponential_backoff.h" - -#define MILLISECONDS_PER_SECOND ( 1000U ) /**< @brief Milliseconds per second. */ - -extern UBaseType_t uxRand( void ); - -/*-----------------------------------------------------------*/ - -RetryUtilsStatus_t RetryUtils_BackoffAndSleep( RetryUtilsParams_t * pRetryParams ) -{ - RetryUtilsStatus_t status = RetryUtilsRetriesExhausted; - uint32_t backOffDelayMs = 0; - - /* If pRetryParams->maxRetryAttempts is set to 0, try forever. */ - if( ( pRetryParams->attemptsDone < pRetryParams->maxRetryAttempts ) || - ( 0U == pRetryParams->maxRetryAttempts ) ) - { - /* Choose a random value for back-off time between 0 and the max jitter value. */ - backOffDelayMs = uxRand() % pRetryParams->nextJitterMax; - - /* Wait for backoff time to expire for the next retry. */ - vTaskDelay( pdMS_TO_TICKS( backOffDelayMs * MILLISECONDS_PER_SECOND ) ); - - /* Increment backoff counts. */ - pRetryParams->attemptsDone++; - - /* Double the max jitter value for the next retry attempt, only - * if the new value will be less than the max backoff time value. */ - if( pRetryParams->nextJitterMax < ( MAX_RETRY_BACKOFF_SECONDS / 2U ) ) - { - pRetryParams->nextJitterMax += pRetryParams->nextJitterMax; - } - else - { - pRetryParams->nextJitterMax = MAX_RETRY_BACKOFF_SECONDS; - } - - status = RetryUtilsSuccess; - } - else - { - /* When max retry attempts are exhausted, let application know by - * returning RetryUtilsRetriesExhausted. Application may choose to - * restart the retry process after calling RetryUtils_ParamsReset(). */ - status = RetryUtilsRetriesExhausted; - RetryUtils_ParamsReset( pRetryParams ); - } - - return status; -} - -/*-----------------------------------------------------------*/ - -void RetryUtils_ParamsReset( RetryUtilsParams_t * pRetryParams ) -{ - uint32_t jitter = 0; - - /* Reset attempts done to zero so that the next retry cycle can start. */ - pRetryParams->attemptsDone = 0; - - /* Calculate jitter value using picking a random number. */ - jitter = ( uxRand() % MAX_JITTER_VALUE_SECONDS ); - - /* Reset the backoff value to the initial time out value plus jitter. */ - pRetryParams->nextJitterMax = INITIAL_RETRY_BACKOFF_SECONDS + jitter; -} - -/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Plus/Source/Utilities/exponential_backoff/exponential_backoff.h b/FreeRTOS-Plus/Source/Utilities/exponential_backoff/exponential_backoff.h deleted file mode 100644 index b075478181..0000000000 --- a/FreeRTOS-Plus/Source/Utilities/exponential_backoff/exponential_backoff.h +++ /dev/null @@ -1,245 +0,0 @@ -/* - * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/** - * @file exponential_backoff.h - * @brief Declaration of the exponential backoff retry logic utility functions - * and constants. - */ - -#ifndef EXPONENTIAL_BACKOFF_H -#define EXPONENTIAL_BACKOFF_H - -/* Standard include. */ -#include - -/** - * @page retryutils_page Retry Utilities - * @brief An abstraction of utilities for retrying with exponential back off and - * jitter. - * - * @section retryutils_overview Overview - * The retry utilities are a set of APIs that aid in retrying with exponential - * backoff and jitter. Exponential backoff with jitter is strongly recommended - * for retrying failed actions over the network with servers. Please see - * https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/ for - * more information about the benefits with AWS. - * - * Exponential backoff with jitter is typically used when retrying a failed - * connection to the server. In an environment with poor connectivity, a client - * can get disconnected at any time. A backoff strategy helps the client to - * conserve battery by not repeatedly attempting reconnections when they are - * unlikely to succeed. - * - * Before retrying the failed communication to the server there is a quiet period. - * In this quiet period, the task that is retrying must sleep for some random - * amount of seconds between 0 and the lesser of a base value and a predefined - * maximum. The base is doubled with each retry attempt until the maximum is - * reached.
- * - * > sleep_seconds = random_between( 0, min( 2attempts_count * base_seconds, maximum_seconds ) ) - * - * @section retryutils_implementation Implementing Retry Utils - * - * The functions that must be implemented are:
- * - @ref RetryUtils_ParamsReset - * - @ref RetryUtils_BackoffAndSleep - * - * The functions are used as shown in the diagram below. This is the exponential - * backoff with jitter loop: - * - * @image html exponential_backoff_flow.png width=25% - * - * The following steps give guidance on implementing the Retry Utils. An example - * implementation of the Retry Utils for the FreeRTOS platform can be found in file - * @ref exponential_backoff.c. - * - * -# Implementing @ref RetryUtils_ParamsReset - * @snippet this define_retryutils_paramsreset - *
- * This function initializes @ref RetryUtilsParams_t. It is expected to set - * @ref RetryUtilsParams_t.attemptsDone to zero. It is also expected to set - * @ref RetryUtilsParams_t.nextJitterMax to @ref INITIAL_RETRY_BACKOFF_SECONDS - * plus some random amount of seconds, jitter. This jitter is a random number - * between 0 and @ref MAX_JITTER_VALUE_SECONDS. This function must be called - * before entering the exponential backoff with jitter loop using - * @ref RetryUtils_BackoffAndSleep.

- * Please follow the example below to implement your own @ref RetryUtils_ParamsReset. - * The lines with FIXME comments should be updated. - * @code{c} - * void RetryUtils_ParamsReset( RetryUtilsParams_t * pRetryParams ) - * { - * uint32_t jitter = 0; - * - * // Reset attempts done to zero so that the next retry cycle can start. - * pRetryParams->attemptsDone = 0; - * - * // Seed pseudo random number generator with the current time. FIXME: Your - * // system may have another method to retrieve the current time to seed the - * // pseudo random number generator. - * srand( time( NULL ) ); - * - * // Calculate jitter value using picking a random number. - * jitter = ( rand() % MAX_JITTER_VALUE_SECONDS ); - * - * // Reset the backoff value to the initial time out value plus jitter. - * pRetryParams->nextJitterMax = INITIAL_RETRY_BACKOFF_SECONDS + jitter; - * } - * @endcode
- * - * -# Implementing @ref RetryUtils_BackoffAndSleep - * @snippet this define_retryutils_backoffandsleep - *
- * When this function is invoked, the calling task is expected to sleep a random - * number of seconds between 0 and @ref RetryUtilsParams_t.nextJitterMax. After - * sleeping this function must double @ref RetryUtilsParams_t.nextJitterMax, but - * not exceeding @ref MAX_RETRY_BACKOFF_SECONDS. When @ref RetryUtilsParams_t.maxRetryAttempts - * are reached this function should return @ref RetryUtilsRetriesExhausted, unless - * @ref RetryUtilsParams_t.maxRetryAttempts is set to zero. - * When @ref RetryUtilsRetriesExhausted is returned the calling application can - * stop trying with a failure, or it can call @ref RetryUtils_ParamsReset again - * and restart the exponential back off with jitter loop.

- * Please follow the example below to implement your own @ref RetryUtils_BackoffAndSleep. - * The lines with FIXME comments should be updated. - * @code{c} - * RetryUtilsStatus_t RetryUtils_BackoffAndSleep( RetryUtilsParams_t * pRetryParams ) - * { - * RetryUtilsStatus_t status = RetryUtilsRetriesExhausted; - * // The quiet period delay in seconds. - * int backOffDelay = 0; - * - * // If pRetryParams->maxRetryAttempts is set to 0, try forever. - * if( ( pRetryParams->attemptsDone < pRetryParams->maxRetryAttempts ) || - * ( 0U == pRetryParams->maxRetryAttempts ) ) - * { - * // Choose a random value for back-off time between 0 and the max jitter value. - * backOffDelay = rand() % pRetryParams->nextJitterMax; - * - * // Wait for backoff time to expire for the next retry. - * ( void ) myThreadSleepFunction( backOffDelay ); // FIXME: Replace with your system's thread sleep function. - * - * // Increment backoff counts. - * pRetryParams->attemptsDone++; - * - * // Double the max jitter value for the next retry attempt, only - * // if the new value will be less than the max backoff time value. - * if( pRetryParams->nextJitterMax < ( MAX_RETRY_BACKOFF_SECONDS / 2U ) ) - * { - * pRetryParams->nextJitterMax += pRetryParams->nextJitterMax; - * } - * else - * { - * pRetryParams->nextJitterMax = MAX_RETRY_BACKOFF_SECONDS; - * } - * - * status = RetryUtilsSuccess; - * } - * else - * { - * // When max retry attempts are exhausted, let application know by - * // returning RetryUtilsRetriesExhausted. Application may choose to - * // restart the retry process after calling RetryUtils_ParamsReset(). - * status = RetryUtilsRetriesExhausted; - * RetryUtils_ParamsReset( pRetryParams ); - * } - * - * return status; - * } - * @endcode - */ - -/** - * @brief Max number of retry attempts. Set this value to 0 if the client must - * retry forever. - */ -#define MAX_RETRY_ATTEMPTS 4U - -/** - * @brief Initial fixed backoff value in seconds between two successive - * retries. A random jitter value is added to every backoff value. - */ -#define INITIAL_RETRY_BACKOFF_SECONDS 1U - -/** - * @brief Max backoff value in seconds. - */ -#define MAX_RETRY_BACKOFF_SECONDS 128U - -/** - * @brief Max jitter value in seconds. - */ -#define MAX_JITTER_VALUE_SECONDS 5U - -/** - * @brief Status for @ref RetryUtils_BackoffAndSleep. - */ -typedef enum RetryUtilsStatus -{ - RetryUtilsSuccess = 0, /**< @brief The function returned successfully after sleeping. */ - RetryUtilsRetriesExhausted /**< @brief The function exhausted all retry attempts. */ -} RetryUtilsStatus_t; - -/** - * @brief Represents parameters required for retry logic. - */ -typedef struct RetryUtilsParams -{ - /** - * @brief Max number of retry attempts. Set this value to 0 if the client must - * retry forever. - */ - uint32_t maxRetryAttempts; - - /** - * @brief The cumulative count of backoff delay cycles completed - * for retries. - */ - uint32_t attemptsDone; - - /** - * @brief The max jitter value for backoff time in retry attempt. - */ - uint32_t nextJitterMax; -} RetryUtilsParams_t; - - -/** - * @brief Resets the retry timeout value and number of attempts. - * This function must be called by the application before a new retry attempt. - * - * @param[in, out] pRetryParams Structure containing attempts done and timeout - * value. - */ -void RetryUtils_ParamsReset( RetryUtilsParams_t * pRetryParams ); - -/** - * @brief Simple platform specific exponential backoff function. The application - * must use this function between retry failures to add exponential delay. - * This function will block the calling task for the current timeout value. - * - * @param[in, out] pRetryParams Structure containing retry parameters. - * - * @return #RetryUtilsSuccess after a successful sleep, #RetryUtilsRetriesExhausted - * when all attempts are exhausted. - */ -RetryUtilsStatus_t RetryUtils_BackoffAndSleep( RetryUtilsParams_t * pRetryParams ); - -#endif /* ifndef EXPONENTIAL_BACKOFF_H */ diff --git a/FreeRTOS-Plus/Source/Utilities/readme.txt b/FreeRTOS-Plus/Source/Utilities/readme.txt index a0be51fcc9..11da9ca785 100644 --- a/FreeRTOS-Plus/Source/Utilities/readme.txt +++ b/FreeRTOS-Plus/Source/Utilities/readme.txt @@ -1,6 +1,6 @@ Directories: -+ Utilities/exponential_backoff contains a utility that calculates an ++ Utilities/backoff_algorithm contains a utility that calculates an exponential back off time, with some jitter. It is used to ensure fleets of IoT devices that become disconnected don't all try and reconnect at the same time.