├── .github ├── .cSpellWords.txt ├── CODEOWNERS ├── CONTRIBUTING.md ├── memory_statistics_config.json ├── pull_request_template.md └── workflows │ ├── ci.yml │ ├── doxygen.yml │ └── release.yml ├── .gitignore ├── .gitmodules ├── CHANGELOG.md ├── LICENSE ├── MISRA.md ├── README.md ├── SECURITY.md ├── backoffAlgorithmFilePaths.cmake ├── cspell.config.yaml ├── docs └── doxygen │ ├── code_examples │ └── backoff_algorithm_posix.c │ ├── config.doxyfile │ ├── include │ └── size_table.md │ ├── layout.xml │ ├── pages.dox │ └── style.css ├── manifest.yml ├── source ├── backoff_algorithm.c └── include │ ├── backoff_algorithm.h │ └── stdint.readme ├── test ├── CMakeLists.txt └── unit-test │ ├── CMakeLists.txt │ ├── backoff_algorithm_utest.c │ ├── catch_assert.h │ └── unity_build.cmake └── tools ├── coverity ├── README.md └── misra.config └── unity ├── coverage.cmake ├── create_test.cmake └── project.yml /.github/.cSpellWords.txt: -------------------------------------------------------------------------------- 1 | cbmc 2 | CBMC 3 | cbor 4 | CBOR 5 | cmock 6 | Cmock 7 | CMock 8 | CMOCK 9 | coremqtt 10 | coverity 11 | Coverity 12 | CSDK 13 | ctest 14 | DCMOCK 15 | DCOV 16 | decihours 17 | Decihours 18 | DECIHOURS 19 | DNDEBUG 20 | DUNITY 21 | getpacketid 22 | isystem 23 | lcov 24 | misra 25 | Misra 26 | MISRA 27 | MQTT 28 | mypy 29 | nondet 30 | Nondet 31 | NONDET 32 | pylint 33 | pytest 34 | pyyaml 35 | sinclude 36 | UNACKED 37 | unpadded 38 | Unpadded 39 | UNPADDED 40 | UNSUB 41 | UNSUBACK 42 | unsubscriptions 43 | utest 44 | vect 45 | Vect 46 | VECT 47 | Wunused 48 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Each line is a file pattern followed by one or more owners. 2 | 3 | # These owners will be the default owners for everything in 4 | # the repo. Unless a later match takes precedence, 5 | # @global-owner1 and @global-owner2 will be requested for 6 | # review when someone opens a pull request. 7 | * @FreeRTOS/pr-bar-raiser 8 | 9 | # Order is important; the last matching pattern takes the most 10 | # precedence. When someone opens a pull request that only 11 | # modifies JS files, only @js-owner and not the global 12 | # owner(s) will be requested for a review. 13 | # *.c FreeRTOS/pr-bar-raiser 14 | 15 | # You can also use email addresses if you prefer. They'll be 16 | # used to look up users just like we do for commit author 17 | # emails. 18 | # *.go docs@example.com 19 | 20 | # In this example, @doctocat owns any files in the build/logs 21 | # directory at the root of the repository and any of its 22 | # subdirectories. 23 | # /build/logs/ @doctocat 24 | 25 | # The `docs/*` pattern will match files like 26 | # `docs/getting-started.md` but not further nested files like 27 | # `docs/build-app/troubleshooting.md`. 28 | # docs/* docs@example.com 29 | 30 | # In this example, @octocat owns any file in an apps directory 31 | # anywhere in your repository. 32 | # apps/ @octocat 33 | 34 | # In this example, @doctocat owns any file in the `/docs` 35 | # directory in the root of your repository and any of its 36 | # subdirectories. 37 | # /docs/ @doctocat -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional 4 | documentation, we greatly value feedback and contributions from our community. 5 | 6 | Please read through this document before submitting any issues or pull requests to ensure we have all the necessary 7 | information to effectively respond to your bug report or contribution. 8 | 9 | 10 | ## Reporting Bugs/Feature Requests 11 | 12 | We welcome you to use the GitHub issue tracker to report bugs or suggest features. 13 | 14 | When filing an issue, please check [existing open](https://github.com/FreeRTOS/backoffAlgorithm/issues), or [recently closed](https://github.com/FreeRTOS/backoffAlgorithm/issues?q=is%3Aissue+is%3Aclosed), issues to make sure somebody else hasn't already 15 | reported the issue. Please try to include as much information as you can. Details like these are incredibly useful: 16 | 17 | * A reproducible test case or series of steps 18 | * The version of our code being used 19 | * Any modifications you've made relevant to the bug 20 | * Anything unusual about your environment or deployment 21 | 22 | 23 | ## Contributing via Pull Requests 24 | Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that: 25 | 26 | 1. You are working against the latest source on the *main* branch. 27 | 1. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already. 28 | 1. You open an issue to discuss any significant work - we would hate for your time to be wasted. 29 | 30 | To send us a pull request, please: 31 | 32 | 1. Fork the repository. 33 | 1. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change. 34 | 1. Ensure that your contributions conform to the [style guide](https://docs.aws.amazon.com/embedded-csdk/202011.00/lib-ref/docs/doxygen/output/html/guide_developer_styleguide.html). 35 | 1. Format your code with uncrustify, using the config available in [FreeRTOS/CI-CD-Github-Actions](https://github.com/FreeRTOS/CI-CD-Github-Actions/blob/main/formatting/uncrustify.cfg). 36 | 1. Ensure local tests pass. 37 | 1. Commit to your fork using clear commit messages. 38 | 1. Send us a pull request, answering any default questions in the pull request interface. 39 | 1. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation. 40 | 41 | GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and 42 | [creating a pull request](https://help.github.com/articles/creating-a-pull-request/). 43 | 44 | 45 | ## Finding contributions to work on 46 | Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels ((enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any ['help wanted'](https://github.com/FreeRTOS/backoffAlgorithm/labels?q=help+wanted) issues is a great place to start. 47 | 48 | 49 | ## Code of Conduct 50 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 51 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 52 | opensource-codeofconduct@amazon.com with any additional questions or comments. 53 | 54 | 55 | ## Security issue notifications 56 | If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](https://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue. 57 | 58 | 59 | ## Licensing 60 | 61 | See the [LICENSE](../LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution. 62 | 63 | We may ask you to sign a [Contributor License Agreement (CLA)](https://en.wikipedia.org/wiki/Contributor_License_Agreement) for larger changes. 64 | -------------------------------------------------------------------------------- /.github/memory_statistics_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "lib_name": "backoffAlgorithm", 3 | "src": [ 4 | "source/backoff_algorithm.c" 5 | ], 6 | "include": [ 7 | "source/include" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | Description 4 | ----------- 5 | 6 | 7 | Test Steps 8 | ----------- 9 | 10 | 11 | Checklist: 12 | ---------- 13 | 14 | 15 | - [ ] I have tested my changes. No regression in existing tests. 16 | - [ ] I have modified and/or added unit-tests to cover the code changes in this Pull Request. 17 | 18 | Related Issue 19 | ----------- 20 | 21 | 22 | By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. 23 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI Checks 2 | on: 3 | push: 4 | branches: ["**"] 5 | pull_request: 6 | branches: [main] 7 | workflow_dispatch: 8 | jobs: 9 | unittest: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Clone This Repo 13 | uses: actions/checkout@v3 14 | - name: Build 15 | run: | 16 | sudo apt-get install -y lcov sed 17 | cmake -S test -B build/ \ 18 | -G "Unix Makefiles" \ 19 | -DCMAKE_BUILD_TYPE=Debug \ 20 | -DUNITTEST=ON \ 21 | -DBUILD_CLONE_SUBMODULES=ON \ 22 | -DCMAKE_C_FLAGS='--coverage -Wall -Wextra -Werror' 23 | make -C build/ all 24 | - name: Test 25 | run: | 26 | cd build/ 27 | ctest -E system --output-on-failure 28 | cd .. 29 | - name: Run Coverage 30 | run: | 31 | make -C build/ coverage 32 | declare -a EXCLUDE=("\*test\*" "\*CMakeCCompilerId\*" "\*mocks\*") 33 | echo ${EXCLUDE[@]} | xargs lcov --rc lcov_branch_coverage=1 -r build/coverage.info -o build/coverage.info 34 | lcov --rc lcov_branch_coverage=1 --list build/coverage.info 35 | - name: Check Coverage 36 | uses: FreeRTOS/CI-CD-Github-Actions/coverage-cop@main 37 | with: 38 | coverage-file: ./build/coverage.info 39 | 40 | build-code-example: 41 | runs-on: ubuntu-latest 42 | steps: 43 | - name: Clone This Repo 44 | uses: actions/checkout@v3 45 | - name: Build code example 46 | run: | 47 | cmake -S test -B Build -DBUILD_CODE_EXAMPLE=ON 48 | make -C Build code_example_posix -j8 49 | 50 | complexity: 51 | runs-on: ubuntu-latest 52 | steps: 53 | - uses: actions/checkout@v3 54 | - name: Check complexity 55 | uses: FreeRTOS/CI-CD-Github-Actions/complexity@main 56 | with: 57 | path: ./ 58 | 59 | doxygen: 60 | runs-on: ubuntu-latest 61 | steps: 62 | - uses: actions/checkout@v3 63 | - name: Run doxygen build 64 | uses: FreeRTOS/CI-CD-Github-Actions/doxygen@main 65 | with: 66 | path: ./ 67 | 68 | spell-check: 69 | runs-on: ubuntu-latest 70 | steps: 71 | - name: Clone This Repo 72 | uses: actions/checkout@v3 73 | - name: Run spellings check 74 | uses: FreeRTOS/CI-CD-Github-Actions/spellings@main 75 | with: 76 | path: ./ 77 | 78 | formatting: 79 | runs-on: ubuntu-20.04 80 | steps: 81 | - uses: actions/checkout@v3 82 | - name: Check formatting 83 | uses: FreeRTOS/CI-CD-Github-Actions/formatting@main 84 | with: 85 | path: ./ 86 | 87 | git-secrets: 88 | runs-on: ubuntu-latest 89 | steps: 90 | - uses: actions/checkout@v3 91 | - name: Checkout awslabs/git-secrets 92 | uses: actions/checkout@v3 93 | with: 94 | repository: awslabs/git-secrets 95 | ref: master 96 | path: git-secrets 97 | - name: Install git-secrets 98 | run: cd git-secrets && sudo make install && cd .. 99 | - name: Run git-secrets 100 | run: | 101 | git-secrets --register-aws 102 | git-secrets --scan 103 | 104 | custom-standard-c-header: 105 | runs-on: ubuntu-latest 106 | steps: 107 | - name: Clone This Repo 108 | uses: actions/checkout@v3 109 | - name: Build 110 | run: | 111 | mkdir -p override-include 112 | cp source/include/stdint.readme override-include/stdint.h 113 | cmake -S test -B build/ \ 114 | -G "Unix Makefiles" \ 115 | -DCOV_ANALYSIS=ON \ 116 | -DCMAKE_C_FLAGS='-Wall -Wextra -Werror -I../override-include' 117 | make -C build/ coverity_analysis 118 | 119 | memory_statistics: 120 | runs-on: ubuntu-latest 121 | steps: 122 | - uses: actions/checkout@v3 123 | with: 124 | submodules: "recursive" 125 | - name: Install Python3 126 | uses: actions/setup-python@v3 127 | with: 128 | python-version: "3.11.0" 129 | - name: Measure sizes 130 | uses: FreeRTOS/CI-CD-Github-Actions/memory_statistics@main 131 | with: 132 | config: .github/memory_statistics_config.json 133 | check_against: docs/doxygen/include/size_table.md 134 | 135 | link-verifier: 136 | runs-on: ubuntu-latest 137 | steps: 138 | - uses: actions/checkout@v3 139 | - name: Check Links 140 | env: 141 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 142 | uses: FreeRTOS/CI-CD-Github-Actions/link-verifier@main 143 | with: 144 | path: ./ 145 | 146 | verify-manifest: 147 | runs-on: ubuntu-latest 148 | steps: 149 | - uses: actions/checkout@v3 150 | with: 151 | submodules: true 152 | fetch-depth: 0 153 | 154 | # At time of writing the gitmodules are set not to pull 155 | # Even when using fetch submodules. Need to run this command 156 | # To force it to grab them. 157 | - name: Perform Recursive Clone 158 | shell: bash 159 | run: git submodule update --checkout --init --recursive 160 | 161 | - name: Run manifest verifier 162 | uses: FreeRTOS/CI-CD-GitHub-Actions/manifest-verifier@main 163 | with: 164 | path: ./ 165 | fail-on-incorrect-version: true 166 | -------------------------------------------------------------------------------- /.github/workflows/doxygen.yml: -------------------------------------------------------------------------------- 1 | name: Doxygen Generation 2 | on: 3 | push: 4 | branches: [main] 5 | workflow_dispatch: 6 | jobs: 7 | doxygen-generation: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - name: Doxygen generation 11 | uses: FreeRTOS/CI-CD-Github-Actions/doxygen-generation@main 12 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release automation 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | commit_id: 7 | description: 'Commit ID to tag and create a release for' 8 | required: true 9 | version_number: 10 | description: 'Release Version Number (Eg, v1.0.0)' 11 | required: true 12 | 13 | jobs: 14 | tag-commit: 15 | name: Tag commit 16 | runs-on: ubuntu-latest 17 | steps: 18 | - name: Checkout code 19 | uses: actions/checkout@v4 20 | with: 21 | ref: ${{ github.event.inputs.commit_id }} 22 | - name: Configure git identity 23 | env: 24 | ACTOR: ${{ github.actor }} 25 | run: | 26 | git config --global user.name "$ACTOR" 27 | git config --global user.email "$ACTOR"@users.noreply.github.com 28 | - name: create a new branch that references commit id 29 | env: 30 | VERSION_NUMBER: ${{ github.event.inputs.version_number }} 31 | COMMIT_ID: ${{ github.event.inputs.commit_id }} 32 | run: git checkout -b "$VERSION_NUMBER" "$COMMIT_ID" 33 | - name: Generate SBOM 34 | uses: FreeRTOS/CI-CD-Github-Actions/sbom-generator@main 35 | with: 36 | repo_path: ./ 37 | source_path: ./source 38 | - name: commit SBOM file 39 | env: 40 | VERSION_NUMBER: ${{ github.event.inputs.version_number }} 41 | run: | 42 | git add . 43 | git commit -m 'Update SBOM' 44 | git push -u origin "$VERSION_NUMBER" 45 | - name: Tag Commit and Push to remote 46 | env: 47 | VERSION_NUMBER: ${{ github.event.inputs.version_number }} 48 | run: | 49 | git tag "$VERSION_NUMBER" -a -m "backoffAlgorithm Library $VERSION_NUMBER" 50 | git push origin --tags 51 | - name: Verify tag on remote 52 | env: 53 | VERSION_NUMBER: ${{ github.event.inputs.version_number }} 54 | COMMIT_ID: ${{ github.event.inputs.commit_id }} 55 | run: | 56 | git tag -d "$VERSION_NUMBER" 57 | git remote update 58 | git checkout tags/"$VERSION_NUMBER" 59 | git diff "$COMMIT_ID" tags/"$VERSION_NUMBER" 60 | create-zip: 61 | needs: tag-commit 62 | name: Create ZIP and verify package for release asset. 63 | runs-on: ubuntu-latest 64 | steps: 65 | - name: Install ZIP tools 66 | run: sudo apt-get install zip unzip 67 | - name: Checkout code 68 | uses: actions/checkout@v4 69 | with: 70 | ref: ${{ github.event.inputs.commit_id }} 71 | path: backoffAlgorithm 72 | submodules: recursive 73 | - name: Checkout disabled submodules 74 | run: | 75 | cd backoffAlgorithm 76 | git submodule update --init --checkout --recursive 77 | - name: Create ZIP 78 | env: 79 | VERSION_NUMBER: ${{ github.event.inputs.version_number }} 80 | run: | 81 | zip -r backoffAlgorithm-"$VERSION_NUMBER".zip backoffAlgorithm -x "*.git*" 82 | ls ./ 83 | - name: Validate created ZIP 84 | env: 85 | VERSION_NUMBER: ${{ github.event.inputs.version_number }} 86 | run: | 87 | mkdir zip-check 88 | mv backoffAlgorithm-"$VERSION_NUMBER".zip zip-check 89 | cd zip-check 90 | unzip backoffAlgorithm-"$VERSION_NUMBER".zip -d backoffAlgorithm-"$VERSION_NUMBER" 91 | ls backoffAlgorithm-"$VERSION_NUMBER" 92 | diff -r -x "*.git*" backoffAlgorithm-"$VERSION_NUMBER"/backoffAlgorithm/ ../backoffAlgorithm/ 93 | cd ../ 94 | - name: Build 95 | env: 96 | VERSION_NUMBER: ${{ github.event.inputs.version_number }} 97 | run: | 98 | cd zip-check/backoffAlgorithm-"$VERSION_NUMBER"/backoffAlgorithm 99 | sudo apt-get install -y lcov 100 | cmake -S test -B build/ \ 101 | -G "Unix Makefiles" \ 102 | -DCMAKE_BUILD_TYPE=Debug \ 103 | -DBUILD_CLONE_SUBMODULES=ON \ 104 | -DCMAKE_C_FLAGS='--coverage -Wall -Wextra -Werror' 105 | make -C build/ all 106 | - name: Test 107 | env: 108 | VERSION_NUMBER: ${{ github.event.inputs.version_number }} 109 | run: | 110 | cd zip-check/backoffAlgorithm-"$VERSION_NUMBER"/backoffAlgorithm/build/ 111 | ctest -E system --output-on-failure 112 | cd .. 113 | - name: Create artifact of ZIP 114 | uses: actions/upload-artifact@v4 115 | with: 116 | name: backoffAlgorithm-${{ github.event.inputs.version_number }}.zip 117 | path: zip-check/backoffAlgorithm-${{ github.event.inputs.version_number }}.zip 118 | deploy-doxygen: 119 | needs: tag-commit 120 | name: Deploy doxygen documentation 121 | runs-on: ubuntu-latest 122 | steps: 123 | - name: Doxygen generation 124 | uses: FreeRTOS/CI-CD-Github-Actions/doxygen-generation@main 125 | with: 126 | ref: ${{ github.event.inputs.version_number }} 127 | add_release: "true" 128 | create-release: 129 | needs: 130 | - create-zip 131 | - deploy-doxygen 132 | name: Create Release and Upload Release Asset 133 | runs-on: ubuntu-latest 134 | steps: 135 | - name: Create Release 136 | id: create_release 137 | uses: actions/create-release@v1 138 | env: 139 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 140 | with: 141 | tag_name: ${{ github.event.inputs.version_number }} 142 | release_name: ${{ github.event.inputs.version_number }} 143 | body: Release ${{ github.event.inputs.version_number }} of the backoffAlgorithm Library. 144 | draft: false 145 | prerelease: false 146 | - name: Download ZIP artifact 147 | uses: actions/download-artifact@v4 148 | with: 149 | name: backoffAlgorithm-${{ github.event.inputs.version_number }}.zip 150 | - name: Upload Release Asset 151 | id: upload-release-asset 152 | uses: actions/upload-release-asset@v1 153 | env: 154 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 155 | with: 156 | upload_url: ${{ steps.create_release.outputs.upload_url }} 157 | asset_path: ./backoffAlgorithm-${{ github.event.inputs.version_number }}.zip 158 | asset_name: backoffAlgorithm-${{ github.event.inputs.version_number }}.zip 159 | asset_content_type: application/zip 160 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore documentation output. 2 | **/docs/**/output/* 3 | 4 | # Ignore CMake build directory. 5 | build/ 6 | 7 | # Ignore build artifacts 8 | *.o 9 | 10 | # Ignore code coverage artifacts 11 | *.gcda 12 | *.gcno 13 | *.gcov -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "test/unit-test/Unity"] 2 | path = test/unit-test/Unity 3 | url = https://github.com/ThrowTheSwitch/Unity 4 | update = none 5 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog for backoffAlgorithm Library 2 | 3 | ## v1.4.1 (June 2024) 4 | 5 | ### Changes 6 | - Fix doxygen deployment on Github. 7 | 8 | ## v1.4.0 (May 2024) 9 | 10 | ### Changes 11 | - [#51](https://github.com/FreeRTOS/backoffAlgorithm/pull/51) Update MISRA Check Information. 12 | - [#45](https://github.com/FreeRTOS/backoffAlgorithm/pull/45) Update doxygen version to 1.9.6. 13 | 14 | ## v1.3.0 (October 2022) 15 | 16 | ### Changes 17 | 18 | - [#38](https://github.com/FreeRTOS/backoffAlgorithm/pull/38) MISRA compliance update 19 | 20 | ## v1.2.0 (November 2021) 21 | 22 | ### Changes 23 | 24 | - [#31](https://github.com/FreeRTOS/backoffAlgorithm/pull/31) Update doxygen version for documentation. 25 | - [#30](https://github.com/FreeRTOS/backoffAlgorithm/pull/30) Add code examples to documentation. 26 | 27 | ## v1.1.0 (July 2021) 28 | 29 | ### Changes 30 | 31 | - [#29](https://github.com/FreeRTOS/backoffAlgorithm/pull/29) Set BACKOFF_ALGORITHM_RETRY_FOREVER to be nonzero and add header guards for C++ linkage. 32 | - [#27](https://github.com/FreeRTOS/backoffAlgorithm/pull/27) Fix incorrect comment about use of BACKOFF_ALGORITHM_RETRY_FOREVER constant in BackoffAlgorithm_GetNextBackoff API. 33 | 34 | ## v1.0.1 (February 2021) 35 | 36 | ### Changes 37 | 38 | - [#24](https://github.com/FreeRTOS/backoffAlgorithm/pull/24) Fix MISRA 10.4 and 10.7 rule violations, and add documentation of MISRA compliance. 39 | - [#18](https://github.com/FreeRTOS/backoffAlgorithm/pull/18), [#19](https://github.com/FreeRTOS/backoffAlgorithm/pull/19), and [#20](https://github.com/FreeRTOS/backoffAlgorithm/pull/20) Documentation fixes. 40 | 41 | ## v1.0.0 (December 2020) 42 | 43 | This is the first release of the backoffAlgorithm library in this repository. 44 | 45 | The backoffAlgorithm library is a utility library to calculate backoff period using an exponential backoff with jitter algorithm for retrying network operations (like failed network connection with server). 46 | This library uses the "Full Jitter" strategy for the exponential backoff with jitter algorithm. 47 | More information about the algorithm can be seen in the [Exponential Backoff and Jitter](https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/) AWS blog. 48 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /MISRA.md: -------------------------------------------------------------------------------- 1 | # MISRA Compliance 2 | 3 | The backoffAlgorithm library files conform to the 4 | [MISRA C:2012](https://www.misra.org.uk) guidelines, with some noted exceptions. 5 | Compliance is checked with Coverity static analysis. The specific deviations, 6 | suppressed inline, are listed below. 7 | 8 | Additionally, 9 | [MISRA configuration file](https://github.com/FreeRTOS/backoffAlgorithm/blob/main/tools/coverity/misra.config) 10 | contains the project wide deviations. 11 | 12 | ### Suppressed with Coverity Comments 13 | 14 | To find the violation references in the source files run grep on the source code 15 | with ( Assuming rule 11.4 violation; with justification in point 2 ): 16 | 17 | ``` 18 | grep 'MISRA Ref 11.4.2' . -rI 19 | ``` 20 | 21 | _None._ 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## backoffAlgorithm Library 2 | 3 | **[API Documentation Pages for current and previous releases of this library can be found here](https://freertos.github.io/backoffAlgorithm/)** 4 | 5 | This repository contains the backoffAlgorithm library, a utility library to 6 | calculate backoff period using an exponential backoff with jitter algorithm for 7 | retrying network operations (like failed network connection with server). This 8 | library uses the "Full Jitter" strategy for the exponential backoff with jitter 9 | algorithm. More information about the algorithm can be seen in the 10 | [Exponential Backoff and Jitter](https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/) 11 | AWS blog. 12 | 13 | The backoffAlgorithm library is distributed under the 14 | [MIT Open Source License](LICENSE). 15 | 16 | Exponential backoff with jitter is typically used when retrying a failed network 17 | connection or operation request with the server. An exponential backoff with 18 | jitter helps to mitigate failed network operations with servers, that are caused 19 | due to network congestion or high request load on the server, by spreading out 20 | retry requests across multiple devices attempting network operations. Besides, 21 | in an environment with poor connectivity, a client can get disconnected at any 22 | time. A backoff strategy helps the client to conserve battery by not repeatedly 23 | attempting reconnections when they are unlikely to succeed. 24 | 25 | See memory requirements for this library 26 | [here](./docs/doxygen/include/size_table.md). 27 | 28 | **backoffAlgorithm v1.4.1 29 | [source code](https://github.com/FreeRTOS/backoffAlgorithm/tree/v1.4.1/source) 30 | is part of the 31 | [FreeRTOS 202406.00 LTS](https://github.com/FreeRTOS/FreeRTOS-LTS/tree/202406.00-LTS) 32 | release.** 33 | 34 | ## Reference example 35 | 36 | The example below shows how to use the backoffAlgorithm library on a POSIX 37 | platform to retry a DNS resolution query for `amazon.com`. 38 | 39 | ```c 40 | #include "backoff_algorithm.h" 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | 47 | /* The maximum number of retries for the example code. */ 48 | #define RETRY_MAX_ATTEMPTS ( 5U ) 49 | 50 | /* The maximum back-off delay (in milliseconds) for between retries in the example. */ 51 | #define RETRY_MAX_BACKOFF_DELAY_MS ( 5000U ) 52 | 53 | /* The base back-off delay (in milliseconds) for retry configuration in the example. */ 54 | #define RETRY_BACKOFF_BASE_MS ( 500U ) 55 | 56 | int main() 57 | { 58 | /* Variables used in this example. */ 59 | BackoffAlgorithmStatus_t retryStatus = BackoffAlgorithmSuccess; 60 | BackoffAlgorithmContext_t retryParams; 61 | char serverAddress[] = "amazon.com"; 62 | uint16_t nextRetryBackoff = 0; 63 | 64 | int32_t dnsStatus = -1; 65 | struct addrinfo hints; 66 | struct addrinfo ** pListHead = NULL; 67 | struct timespec tp; 68 | 69 | /* Add hints to retrieve only TCP sockets in getaddrinfo. */ 70 | ( void ) memset( &hints, 0, sizeof( hints ) ); 71 | 72 | /* Address family of either IPv4 or IPv6. */ 73 | hints.ai_family = AF_UNSPEC; 74 | /* TCP Socket. */ 75 | hints.ai_socktype = ( int32_t ) SOCK_STREAM; 76 | hints.ai_protocol = IPPROTO_TCP; 77 | 78 | /* Initialize reconnect attempts and interval. */ 79 | BackoffAlgorithm_InitializeParams( &retryParams, 80 | RETRY_BACKOFF_BASE_MS, 81 | RETRY_MAX_BACKOFF_DELAY_MS, 82 | RETRY_MAX_ATTEMPTS ); 83 | 84 | 85 | /* Seed the pseudo random number generator used in this example (with call to 86 | * rand() function provided by ISO C standard library) for use in backoff period 87 | * calculation when retrying failed DNS resolution. */ 88 | 89 | /* Get current time to seed pseudo random number generator. */ 90 | ( void ) clock_gettime( CLOCK_REALTIME, &tp ); 91 | /* Seed pseudo random number generator with seconds. */ 92 | srand( tp.tv_sec ); 93 | 94 | do 95 | { 96 | /* Perform a DNS lookup on the given host name. */ 97 | dnsStatus = getaddrinfo( serverAddress, NULL, &hints, pListHead ); 98 | 99 | /* Retry if DNS resolution query failed. */ 100 | if( dnsStatus != 0 ) 101 | { 102 | /* Generate a random number and get back-off value (in milliseconds) for the next retry. 103 | * Note: It is recommended to use a random number generator that is seeded with 104 | * device-specific entropy source so that backoff calculation across devices is different 105 | * and possibility of network collision between devices attempting retries can be avoided. 106 | * 107 | * For the simplicity of this code example, the pseudo random number generator, rand() 108 | * function is used. */ 109 | retryStatus = BackoffAlgorithm_GetNextBackoff( &retryParams, rand(), &nextRetryBackoff ); 110 | 111 | /* Wait for the calculated backoff period before the next retry attempt of querying DNS. 112 | * As usleep() takes nanoseconds as the parameter, we multiply the backoff period by 1000. */ 113 | ( void ) usleep( nextRetryBackoff * 1000U ); 114 | } 115 | } while( ( dnsStatus != 0 ) && ( retryStatus != BackoffAlgorithmRetriesExhausted ) ); 116 | 117 | return dnsStatus; 118 | } 119 | ``` 120 | 121 | ## Building the library 122 | 123 | A compiler that supports **C90 or later** such as _gcc_ is required to build the 124 | library. 125 | 126 | Additionally, the library uses a header file introduced in ISO C99, `stdint.h`. 127 | For compilers that do not provide this header file, the 128 | [source/include](source/include) directory contains 129 | [stdint.readme](source/include/stdint.readme), which can be renamed to 130 | `stdint.h` to build the backoffAlgorithm library. 131 | 132 | For instance, if the example above is copied to a file named `example.c`, _gcc_ 133 | can be used like so: 134 | 135 | ```bash 136 | gcc -I source/include example.c source/backoff_algorithm.c -o example 137 | ./example 138 | ``` 139 | 140 | _gcc_ can also produce an output file to be linked: 141 | 142 | ```bash 143 | gcc -I source/include -c source/backoff_algorithm.c 144 | ``` 145 | 146 | ## Building unit tests 147 | 148 | ### Checkout Unity Submodule 149 | 150 | By default, the submodules in this repository are configured with `update=none` 151 | in [.gitmodules](.gitmodules), to avoid increasing clone time and disk space 152 | usage of other repositories (like 153 | [amazon-freertos](https://github.com/aws/amazon-freertos) that submodules this 154 | repository). 155 | 156 | To build unit tests, the submodule dependency of Unity is required. Use the 157 | following command to clone the submodule: 158 | 159 | ``` 160 | git submodule update --checkout --init --recursive test/unit-test/Unity 161 | ``` 162 | 163 | ### Platform Prerequisites 164 | 165 | - For running unit tests 166 | - C89 or later compiler like gcc 167 | - CMake 3.13.0 or later 168 | - For running the coverage target, gcov is additionally required. 169 | 170 | ### Steps to build Unit Tests 171 | 172 | 1. Go to the root directory of this repository. (Make sure that the **Unity** 173 | submodule is cloned as described [above](#checkout-unity-submodule).) 174 | 175 | 1. Create build directory: `mkdir build && cd build` 176 | 177 | 1. Run _cmake_ while inside build directory: `cmake -S ../test` 178 | 179 | 1. Run this command to build the library and unit tests: `make all` 180 | 181 | 1. The generated test executables will be present in `build/bin/tests` folder. 182 | 183 | 1. Run `ctest` to execute all tests and view the test run summary. 184 | 185 | ## Contributing 186 | 187 | See [CONTRIBUTING.md](./.github/CONTRIBUTING.md) for information on 188 | contributing. 189 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | ## Reporting a Vulnerability 2 | 3 | If you discover a potential security issue in this project, we ask that you notify AWS/Amazon Security 4 | via our [vulnerability reporting page](https://aws.amazon.com/security/vulnerability-reporting/) or directly via email to aws-security@amazon.com. 5 | Please do **not** create a public github issue. 6 | -------------------------------------------------------------------------------- /backoffAlgorithmFilePaths.cmake: -------------------------------------------------------------------------------- 1 | # This file is to add source files and include directories 2 | # into variables so that it can be reused from different repositories 3 | # in their Cmake based build system by including this file. 4 | # 5 | # Files specific to the repository such as test runner, platform tests 6 | # are not added to the variables. 7 | 8 | # Backoff Algorithm library source files. 9 | set( BACKOFF_ALGORITHM_SOURCES 10 | "${CMAKE_CURRENT_LIST_DIR}/source/backoff_algorithm.c" ) 11 | 12 | # Backoff Algorithm library Public Include directories. 13 | set( BACKOFF_ALGORITHM_INCLUDE_PUBLIC_DIRS 14 | "${CMAKE_CURRENT_LIST_DIR}/source/include" ) 15 | -------------------------------------------------------------------------------- /cspell.config.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | $schema: https://raw.githubusercontent.com/streetsidesoftware/cspell/main/cspell.schema.json 3 | version: '0.2' 4 | # Allows things like stringLength 5 | allowCompoundWords: true 6 | 7 | # Read files not to spell check from the git ignore 8 | useGitignore: true 9 | 10 | # Language settings for C 11 | languageSettings: 12 | - caseSensitive: false 13 | enabled: true 14 | languageId: c 15 | locale: "*" 16 | 17 | # Add a dictionary, and the path to the word list 18 | dictionaryDefinitions: 19 | - name: freertos-words 20 | path: '.github/.cSpellWords.txt' 21 | addWords: true 22 | 23 | dictionaries: 24 | - freertos-words 25 | 26 | # Paths and files to ignore 27 | ignorePaths: 28 | - 'dependency' 29 | - 'docs' 30 | - 'ThirdParty' 31 | - 'History.txt' 32 | -------------------------------------------------------------------------------- /docs/doxygen/code_examples/backoff_algorithm_posix.c: -------------------------------------------------------------------------------- 1 | #include "backoff_algorithm.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | /* The maximum number of retries for the example code. */ 9 | #define RETRY_MAX_ATTEMPTS ( 5U ) 10 | 11 | /* The maximum back-off delay (in milliseconds) for between retries in the example. */ 12 | #define RETRY_MAX_BACKOFF_DELAY_MS ( 5000U ) 13 | 14 | /* The base back-off delay (in milliseconds) for retry configuration in the example. */ 15 | #define RETRY_BACKOFF_BASE_MS ( 500U ) 16 | 17 | int main() 18 | { 19 | /* @[code_example_backoffalgorithm_initializeparams] */ 20 | /* Variables used in this example. */ 21 | BackoffAlgorithmStatus_t retryStatus = BackoffAlgorithmSuccess; 22 | BackoffAlgorithmContext_t retryParams; 23 | char serverAddress[] = "amazon.com"; 24 | uint16_t nextRetryBackoff = 0; 25 | 26 | /* Initialize reconnect attempts and interval. */ 27 | BackoffAlgorithm_InitializeParams( &retryParams, 28 | RETRY_BACKOFF_BASE_MS, 29 | RETRY_MAX_BACKOFF_DELAY_MS, 30 | RETRY_MAX_ATTEMPTS ); 31 | /* @[code_example_backoffalgorithm_initializeparams] */ 32 | 33 | int32_t dnsStatus = -1; 34 | struct addrinfo hints; 35 | struct addrinfo ** pListHead = NULL; 36 | struct timespec tp; 37 | 38 | /* Add hints to retrieve only TCP sockets in getaddrinfo. */ 39 | ( void ) memset( &hints, 0, sizeof( hints ) ); 40 | 41 | /* Address family of either IPv4 or IPv6. */ 42 | hints.ai_family = AF_UNSPEC; 43 | /* TCP Socket. */ 44 | hints.ai_socktype = ( int32_t ) SOCK_STREAM; 45 | hints.ai_protocol = IPPROTO_TCP; 46 | 47 | /* @[code_example_backoffalgorithm_getnextbackoff] */ 48 | 49 | /* Seed the pseudo random number generator used in this example (with call to 50 | * rand() function provided by ISO C standard library) for use in backoff period 51 | * calculation when retrying failed DNS resolution. */ 52 | 53 | /* Get current time to seed pseudo random number generator. */ 54 | ( void ) clock_gettime( CLOCK_REALTIME, &tp ); 55 | /* Seed pseudo random number generator with seconds. */ 56 | srand( tp.tv_sec ); 57 | 58 | do 59 | { 60 | /* Perform a DNS lookup on the given host name. */ 61 | dnsStatus = getaddrinfo( serverAddress, NULL, &hints, pListHead ); 62 | 63 | /* Retry if DNS resolution query failed. */ 64 | if( dnsStatus != 0 ) 65 | { 66 | /* Generate a random number and get back-off value (in milliseconds) for the next retry. 67 | * Note: It is recommended to use a random number generator that is seeded with 68 | * device-specific entropy source so that backoff calculation across devices is different 69 | * and possibility of network collision between devices attempting retries can be avoided. 70 | * 71 | * For the simplicity of this code example, the pseudo random number generator, rand() 72 | * function is used. */ 73 | retryStatus = BackoffAlgorithm_GetNextBackoff( &retryParams, rand(), &nextRetryBackoff ); 74 | 75 | /* Wait for the calculated backoff period before the next retry attempt of querying DNS. 76 | * As usleep() takes nanoseconds as the parameter, we multiply the backoff period by 1000. */ 77 | ( void ) usleep( nextRetryBackoff * 1000U ); 78 | } 79 | } while( ( dnsStatus != 0 ) && ( retryStatus != BackoffAlgorithmRetriesExhausted ) ); 80 | 81 | /* @[code_example_backoffalgorithm_getnextbackoff] */ 82 | 83 | return dnsStatus; 84 | } 85 | -------------------------------------------------------------------------------- /docs/doxygen/include/size_table.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
Code Size of backoffAlgorithm (example generated with GCC for ARM Cortex-M)
File
With -O1 Optimization
With -Os Optimization
backoff_algorithm.c
0.1K
0.1K
Total estimates
0.1K
0.1K
21 | -------------------------------------------------------------------------------- /docs/doxygen/layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | -------------------------------------------------------------------------------- /docs/doxygen/pages.dox: -------------------------------------------------------------------------------- 1 | /** 2 | @mainpage Overview 3 | @anchor BackOff Algorithm 4 | @brief backoffAlgorithm Library 5 | 6 |

7 | A library that calculates the back-off period for a retry attempt using exponential back-off with jitter algorithm. 8 | This library uses the "Full Jitter" strategy for the exponential back-off with jitter algorithm. 9 | 10 | More information about the algorithm can be seen in the [Exponential Backoff and Jitter](https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/) AWS blog. 11 | 12 | Exponential backoff with jitter is typically used when retrying a failed network 13 | connection or operation request with the server. An exponential backoff with jitter helps to 14 | mitigate failed network operations with servers, that are caused due to network congestion or high request load on 15 | the server, by spreading out retry requests across multiple devices attempting network operations. 16 | Besides, in an environment with poor connectivity, a client can get disconnected at any time. 17 | A backoff strategy helps the client to conserve battery by not repeatedly attempting reconnections when they are 18 | unlikely to succeed. 19 | 20 | Before retrying the failed communication to the server, there is a delay period. 21 | In this delay period, the task that is retrying must sleep for some random amount 22 | of milliseconds between 0 and the lesser of the backoff window (related to the retry attempt) 23 | and a predefined maximum delay value. The backoff window is doubled with each retry 24 | attempt until the maximum delay value is reached.
25 | 26 | > sleep_ms = random_between( 0, min( 2attempts_count * base_ms, maximum_ms ) ) 27 | 28 | The library is written in C and designed to be compliant with ISO C90 and MISRA C:2012. 29 | 30 | For a reference example of using the library, refer to the related README section in the repository [here](https://github.com/FreeRTOS/backoffAlgorithm#reference-example). 31 | 32 |

33 | 34 | @section backoff_algorithm_memory_requirements Memory Requirements 35 | @brief Memory requirements of the backoffAlgorithm library. 36 | 37 | @include{doc} size_table.md 38 | 39 | @section backoff_algorithm_design Design 40 | @brief backoffAlgorithm Library Design 41 | 42 |

Memory Usage

43 |

44 | All functions in the backoffAlgorithm library operate only on the buffer provided and use only 45 | local variables on the stack. 46 |

47 | 48 |

Random Number Generation

49 |

50 | The library takes a random number each time it calculates the backoff period value for the 51 | retry attempt. To avoid calculation of the same random numbers across your fleet of devices 52 | attempting retry of network operations, it is RECOMMENDED to generate the random number with 53 | a random number generator that is seeded with an entropy source unique to the device. 54 |

55 | 56 |

Compliance & Coverage

57 |

58 | The backoffAlgorithm library is designed to be compliant with ISO C90 and MISRA C:2012. 59 | All functions are written to have minimal complexity. Unit tests are written to cover 60 | every path of execution and achieve 100% branch coverage. 61 |

62 | */ 63 | 64 | /** 65 | @page backoff_algorithm_example Code Example for backoffAlgorithm API 66 | @brief Example POSIX application that retries DNS resolution operation with exponential backoff-and-jitter using the backoffAlgorithm library. 67 | 68 | @include backoff_algorithm_posix.c 69 | */ 70 | 71 | /** 72 | @page backoff_algorithm_functions Functions 73 | @brief Primary functions of the backoffAlgorithm library:

74 | @subpage define_backoffalgorithm_initializeparams
75 | @subpage define_backoffalgorithm_getnextbackoff
76 | 77 | For a code example of using backoffAlgorithm library for retrying operations with exponential back-off and jitter, refer to @ref backoff_algorithm_example. 78 | 79 | @page define_backoffalgorithm_initializeparams BackoffAlgorithm_InitializeParams 80 | @snippet backoff_algorithm.h define_backoffalgorithm_initializeparams 81 | @copydoc BackoffAlgorithm_InitializeParams 82 | 83 | From the @ref backoff_algorithm_example, following is the part relevant to the @ref BackoffAlgorithm_InitializeParams API. 84 | @snippet backoff_algorithm_posix.c code_example_backoffalgorithm_initializeparams 85 | 86 | @page define_backoffalgorithm_getnextbackoff BackoffAlgorithm_GetNextBackoff 87 | @copydoc BackoffAlgorithm_GetNextBackoff 88 | 89 | From the @ref backoff_algorithm_example, following is the part relevant to the @ref BackoffAlgorithm_GetNextBackoff API. 90 | @snippet backoff_algorithm_posix.c code_example_backoffalgorithm_getnextbackoff 91 | 92 | */ 93 | 94 | 95 | 96 | /** 97 | @defgroup backoff_algorithm_struct_types Parameter Structure 98 | @brief Structure passed as parameter to [backoffAlgorithm library functions](@ref backoff_algorithm_functions) 99 | */ 100 | 101 | /** 102 | @defgroup backoff_algorithm_enum_types Enumerated Types 103 | @brief Enumerated types of the backoffAlgorithm library 104 | */ 105 | 106 | /** 107 | @defgroup backoff_algorithm_constants Constants 108 | @brief Constants defined in the backoffAlgorithm library 109 | */ 110 | -------------------------------------------------------------------------------- /docs/doxygen/style.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Stylesheet for Doxygen HTML output. 3 | * 4 | * This file defines styles for custom elements in the header/footer and 5 | * overrides some of the default Doxygen styles. 6 | * 7 | * Styles in this file do not affect the treeview sidebar. 8 | */ 9 | 10 | /* Set the margins to place a small amount of whitespace on the left and right 11 | * side of the page. */ 12 | div.contents { 13 | margin-left:4em; 14 | margin-right:4em; 15 | } 16 | 17 | /* Justify text in paragraphs. */ 18 | p { 19 | text-align: justify; 20 | } 21 | 22 | /* Style of section headings. */ 23 | h1 { 24 | border-bottom: 1px solid #879ECB; 25 | color: #354C7B; 26 | font-size: 160%; 27 | font-weight: normal; 28 | padding-bottom: 4px; 29 | padding-top: 8px; 30 | } 31 | 32 | /* Style of subsection headings. */ 33 | h2:not(.memtitle):not(.groupheader) { 34 | font-size: 125%; 35 | margin-bottom: 0px; 36 | margin-top: 16px; 37 | padding: 0px; 38 | } 39 | 40 | /* Style of paragraphs immediately after subsection headings. */ 41 | h2 + p { 42 | margin: 0px; 43 | padding: 0px; 44 | } 45 | 46 | /* Style of subsection headings. */ 47 | h3 { 48 | font-size: 100%; 49 | margin-bottom: 0px; 50 | margin-left: 2em; 51 | margin-right: 2em; 52 | } 53 | 54 | /* Style of paragraphs immediately after subsubsection headings. */ 55 | h3 + p { 56 | margin-top: 0px; 57 | margin-left: 2em; 58 | margin-right: 2em; 59 | } 60 | 61 | /* Style of the prefix "AWS IoT Device SDK C" that appears in the header. */ 62 | #csdkprefix { 63 | color: #757575; 64 | } 65 | 66 | /* Style of the "Return to main page" link that appears in the header. */ 67 | #returntomain { 68 | padding: 0.5em; 69 | } 70 | 71 | /* Style of the dividers on Configuration Settings pages. */ 72 | div.configpagedivider { 73 | margin-left: 0px !important; 74 | margin-right: 0px !important; 75 | margin-top: 20px !important; 76 | } 77 | 78 | /* Style of configuration setting names. */ 79 | dl.section.user ~ h1 { 80 | border-bottom: none; 81 | color: #000000; 82 | font-family: monospace, fixed; 83 | font-size: 16px; 84 | margin-bottom: 0px; 85 | margin-left: 2em; 86 | margin-top: 1.5em; 87 | } 88 | 89 | /* Style of paragraphs on a configuration settings page. */ 90 | dl.section.user ~ * { 91 | margin-bottom: 10px; 92 | margin-left: 4em; 93 | margin-right: 4em; 94 | margin-top: 0px; 95 | } 96 | 97 | /* Hide the configuration setting marker. */ 98 | dl.section.user { 99 | display: none; 100 | } 101 | 102 | /* Overrides for code fragments and lines. */ 103 | div.fragment { 104 | background: #ffffff; 105 | border: none; 106 | padding: 5px; 107 | } 108 | 109 | div.line { 110 | color: #3a3a3a; 111 | } 112 | 113 | /* Overrides for code syntax highlighting colors. */ 114 | span.comment { 115 | color: #008000; 116 | } 117 | 118 | span.keyword, span.keywordtype, span.keywordflow { 119 | color: #0000ff; 120 | } 121 | 122 | span.preprocessor { 123 | color: #50015a; 124 | } 125 | 126 | span.stringliteral, span.charliteral { 127 | color: #800c0c; 128 | } 129 | 130 | a.code, a.code:visited, a.line, a.line:visited { 131 | color: #496194; 132 | } 133 | -------------------------------------------------------------------------------- /manifest.yml: -------------------------------------------------------------------------------- 1 | name : "backoffAlgorithm" 2 | version: "v1.4.1" 3 | description: | 4 | "Algorithm for calculating exponential backoff with jitter for network retry attempts.\n" 5 | license: "MIT" 6 | 7 | dependencies: 8 | - name: "Unity" 9 | version: v2.6.0 10 | license: "MIT" 11 | repository: 12 | type: "git" 13 | url: "https://github.com/ThrowTheSwitch/Unity.git" 14 | path: test/unit-test/Unity -------------------------------------------------------------------------------- /source/backoff_algorithm.c: -------------------------------------------------------------------------------- 1 | /* 2 | * backoffAlgorithm v1.4.1 3 | * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | * 5 | * SPDX-License-Identifier: MIT 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 8 | * this software and associated documentation files (the "Software"), to deal in 9 | * the Software without restriction, including without limitation the rights to 10 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 11 | * the Software, and to permit persons to whom the Software is furnished to do so, 12 | * subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 19 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 21 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | /** 26 | * @file backoff_algorithm.c 27 | * @brief Implementation of the backoff algorithm API for a "Full Jitter" exponential backoff 28 | * with jitter strategy. 29 | */ 30 | 31 | /* Standard includes. */ 32 | #include 33 | #include 34 | 35 | /* Include API header. */ 36 | #include "backoff_algorithm.h" 37 | 38 | /*-----------------------------------------------------------*/ 39 | 40 | BackoffAlgorithmStatus_t BackoffAlgorithm_GetNextBackoff( BackoffAlgorithmContext_t * pRetryContext, 41 | uint32_t randomValue, 42 | uint16_t * pNextBackOff ) 43 | { 44 | BackoffAlgorithmStatus_t status = BackoffAlgorithmSuccess; 45 | 46 | assert( pRetryContext != NULL ); 47 | assert( pNextBackOff != NULL ); 48 | 49 | /* If maxRetryAttempts state of the context is set to the maximum, retry forever. */ 50 | if( ( pRetryContext->maxRetryAttempts == BACKOFF_ALGORITHM_RETRY_FOREVER ) || 51 | ( pRetryContext->attemptsDone < pRetryContext->maxRetryAttempts ) ) 52 | { 53 | /* The next backoff value is a random value between 0 and the maximum jitter value 54 | * for the retry attempt. */ 55 | 56 | /* Choose a random value for back-off time between 0 and the max jitter value. */ 57 | *pNextBackOff = ( uint16_t ) ( randomValue % ( pRetryContext->nextJitterMax + ( uint32_t ) 1U ) ); 58 | 59 | /* Increment the retry attempt. */ 60 | pRetryContext->attemptsDone++; 61 | 62 | /* Double the max jitter value for the next retry attempt, only 63 | * if the new value will be less than the max backoff time value. */ 64 | if( pRetryContext->nextJitterMax < ( pRetryContext->maxBackoffDelay / 2U ) ) 65 | { 66 | pRetryContext->nextJitterMax += pRetryContext->nextJitterMax; 67 | } 68 | else 69 | { 70 | pRetryContext->nextJitterMax = pRetryContext->maxBackoffDelay; 71 | } 72 | } 73 | else 74 | { 75 | /* When max retry attempts are exhausted, let application know by 76 | * returning BackoffAlgorithmRetriesExhausted. Application may choose to 77 | * restart the retry process after calling BackoffAlgorithm_InitializeParams(). */ 78 | status = BackoffAlgorithmRetriesExhausted; 79 | } 80 | 81 | return status; 82 | } 83 | 84 | /*-----------------------------------------------------------*/ 85 | 86 | void BackoffAlgorithm_InitializeParams( BackoffAlgorithmContext_t * pContext, 87 | uint16_t backOffBase, 88 | uint16_t maxBackOff, 89 | uint32_t maxAttempts ) 90 | { 91 | assert( pContext != NULL ); 92 | 93 | /* Initialize the context with parameters used in calculating the backoff 94 | * value for the next retry attempt. */ 95 | pContext->nextJitterMax = backOffBase; 96 | pContext->maxBackoffDelay = maxBackOff; 97 | pContext->maxRetryAttempts = maxAttempts; 98 | 99 | /* The total number of retry attempts is zero at initialization. */ 100 | pContext->attemptsDone = 0; 101 | } 102 | 103 | /*-----------------------------------------------------------*/ 104 | -------------------------------------------------------------------------------- /source/include/backoff_algorithm.h: -------------------------------------------------------------------------------- 1 | /* 2 | * backoffAlgorithm v1.4.1 3 | * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | * 5 | * SPDX-License-Identifier: MIT 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 8 | * this software and associated documentation files (the "Software"), to deal in 9 | * the Software without restriction, including without limitation the rights to 10 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 11 | * the Software, and to permit persons to whom the Software is furnished to do so, 12 | * subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 19 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 21 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | /** 26 | * @file backoff_algorithm.h 27 | * @brief API for calculating backoff period for retry attempts using 28 | * exponential backoff with jitter algorithm. 29 | * This library represents the "Full Jitter" backoff strategy explained in the 30 | * following document. 31 | * https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/ 32 | * 33 | */ 34 | 35 | #ifndef BACKOFF_ALGORITHM_H_ 36 | #define BACKOFF_ALGORITHM_H_ 37 | 38 | /* Standard include. */ 39 | #include 40 | 41 | /* *INDENT-OFF* */ 42 | #ifdef __cplusplus 43 | extern "C" { 44 | #endif 45 | /* *INDENT-ON* */ 46 | 47 | /** 48 | * @ingroup backoff_algorithm_constants 49 | * @brief Constant to represent unlimited number of retry attempts. 50 | */ 51 | #define BACKOFF_ALGORITHM_RETRY_FOREVER ( UINT32_MAX ) 52 | 53 | /** 54 | * @ingroup backoff_algorithm_enum_types 55 | * @brief Status for @ref BackoffAlgorithm_GetNextBackoff. 56 | */ 57 | typedef enum BackoffAlgorithmStatus 58 | { 59 | BackoffAlgorithmSuccess = 0, /**< @brief The function successfully calculated the next back-off value. */ 60 | BackoffAlgorithmRetriesExhausted /**< @brief The function exhausted all retry attempts. */ 61 | } BackoffAlgorithmStatus_t; 62 | 63 | /** 64 | * @ingroup backoff_algorithm_struct_types 65 | * @brief Represents parameters required for calculating the back-off delay for the 66 | * next retry attempt. 67 | */ 68 | typedef struct BackoffAlgorithmContext 69 | { 70 | /** 71 | * @brief The maximum backoff delay (in milliseconds) between consecutive retry attempts. 72 | */ 73 | uint16_t maxBackoffDelay; 74 | 75 | /** 76 | * @brief The total number of retry attempts completed. 77 | * This value is incremented on every call to #BackoffAlgorithm_GetNextBackoff API. 78 | */ 79 | uint32_t attemptsDone; 80 | 81 | /** 82 | * @brief The maximum backoff value (in milliseconds) for the next retry attempt. 83 | */ 84 | uint16_t nextJitterMax; 85 | 86 | /** 87 | * @brief The maximum number of retry attempts. 88 | */ 89 | uint32_t maxRetryAttempts; 90 | } BackoffAlgorithmContext_t; 91 | 92 | /** 93 | * @brief Initializes the context for using backoff algorithm. The parameters 94 | * are required for calculating the next retry backoff delay. 95 | * This function must be called by the application before the first new retry attempt. 96 | * 97 | * @param[out] pContext The context to initialize with parameters required 98 | * for the next backoff delay calculation function. 99 | * @param[in] maxBackOff The maximum backoff delay (in milliseconds) between 100 | * consecutive retry attempts. 101 | * @param[in] backOffBase The base value (in milliseconds) of backoff delay to 102 | * use in the exponential backoff and jitter model. 103 | * @param[in] maxAttempts The maximum number of retry attempts. Set the value to 104 | * #BACKOFF_ALGORITHM_RETRY_FOREVER to retry for ever. 105 | */ 106 | /* @[define_backoffalgorithm_initializeparams] */ 107 | void BackoffAlgorithm_InitializeParams( BackoffAlgorithmContext_t * pContext, 108 | uint16_t backOffBase, 109 | uint16_t maxBackOff, 110 | uint32_t maxAttempts ); 111 | /* @[define_backoffalgorithm_initializeparams] */ 112 | 113 | /** 114 | * @brief Simple exponential backoff and jitter function that provides the 115 | * delay value for the next retry attempt. 116 | * After a failure of an operation that needs to be retried, the application 117 | * should use this function to obtain the backoff delay value for the next retry, 118 | * and then wait for the backoff time period before retrying the operation. 119 | * 120 | * @param[in, out] pRetryContext Structure containing parameters for the next backoff 121 | * value calculation. 122 | * @param[in] randomValue The random value to use for calculation of the backoff period. 123 | * The random value should be in the range of [0, UINT32_MAX]. 124 | * @param[out] pNextBackOff This will be populated with the backoff value (in milliseconds) 125 | * for the next retry attempt. The value does not exceed the maximum backoff delay 126 | * configured in the context. 127 | * 128 | * @note For generating a random number, it is recommended to use a Random Number Generator 129 | * that is seeded with a device-specific entropy source so that possibility of collisions 130 | * between multiple devices retrying the network operations can be mitigated. 131 | * 132 | * @return #BackoffAlgorithmSuccess after a successful sleep; 133 | * #BackoffAlgorithmRetriesExhausted when all attempts are exhausted. 134 | */ 135 | /* @[define_backoffalgorithm_getnextbackoff] */ 136 | BackoffAlgorithmStatus_t BackoffAlgorithm_GetNextBackoff( BackoffAlgorithmContext_t * pRetryContext, 137 | uint32_t randomValue, 138 | uint16_t * pNextBackOff ); 139 | /* @[define_backoffalgorithm_getnextbackoff] */ 140 | 141 | /* *INDENT-OFF* */ 142 | #ifdef __cplusplus 143 | } 144 | #endif 145 | /* *INDENT-ON* */ 146 | 147 | #endif /* ifndef BACKOFF_ALGORITHM_H_ */ 148 | -------------------------------------------------------------------------------- /source/include/stdint.readme: -------------------------------------------------------------------------------- 1 | #ifndef _STDINT_H 2 | #define _STDINT_H 3 | 4 | /******************************************************************************* 5 | * THIS IS NOT A FULL stdint.h IMPLEMENTATION - It only contains the definitions 6 | * necessary to build the library code. It is provided to allow the library to 7 | * be built using compilers that do not provide their own stdint.h definition. 8 | * 9 | * To use this file: 10 | * 11 | * 1) Copy this file into a directory that is in your compiler's include path. 12 | * The directory must be part of the include path for system header file, 13 | * for example passed using gcc's "-I" or "-isystem" options. 14 | * 15 | * 2) Rename the copied file stdint.h. 16 | * 17 | */ 18 | 19 | typedef signed char int8_t; 20 | typedef unsigned char uint8_t; 21 | typedef short int16_t; 22 | typedef unsigned short uint16_t; 23 | typedef long int32_t; 24 | typedef unsigned long uint32_t; 25 | typedef long long int64_t; 26 | typedef unsigned long long uint64_t; 27 | 28 | #define INT8_MAX ( ( signed char ) 127 ) 29 | #define UINT8_MAX ( ( unsigned char ) 255 ) 30 | #define INT16_MAX ( ( short ) 32767 ) 31 | #define UINT16_MAX ( ( unsigned short ) 65535 ) 32 | #define INT32_MAX 2147483647L 33 | #define UINT32_MAX 4294967295UL 34 | #define INT64_MAX 9223372036854775807LL 35 | #define UINT64_MAX 18446744073709551615ULL 36 | 37 | #endif /* _STDINT_H */ 38 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required( VERSION 3.13.0 ) 2 | project( "backoffAlgorithm unit test" 3 | VERSION 1.4.1 4 | LANGUAGES C ) 5 | 6 | # Allow the project to be organized into folders. 7 | set_property( GLOBAL PROPERTY USE_FOLDERS ON ) 8 | 9 | # Use C90. 10 | set( CMAKE_C_STANDARD 90 ) 11 | set( CMAKE_C_STANDARD_REQUIRED ON ) 12 | 13 | # Do not allow in-source build. 14 | if( ${PROJECT_SOURCE_DIR} STREQUAL ${PROJECT_BINARY_DIR} ) 15 | message( FATAL_ERROR "In-source build is not allowed. Please build in a separate directory, such as ${PROJECT_SOURCE_DIR}/build." ) 16 | endif() 17 | 18 | # Set global path variables. 19 | get_filename_component(__MODULE_ROOT_DIR "${CMAKE_CURRENT_LIST_DIR}/.." ABSOLUTE) 20 | set( MODULE_ROOT_DIR ${__MODULE_ROOT_DIR} CACHE INTERNAL "backoffAlgorithm source root." ) 21 | set( UNIT_TEST_DIR ${MODULE_ROOT_DIR}/test/unit-test CACHE INTERNAL "backoffAlgorithm unit test directory." ) 22 | set( UNITY_DIR ${UNIT_TEST_DIR}/Unity CACHE INTERNAL "Unity library source directory." ) 23 | 24 | # Configure options to always show in CMake GUI. 25 | option( UNITTEST 26 | "Set this to ON to build unit tests. This will clone the required Unity test framework submodule if it is not cloned already." 27 | OFF ) 28 | option( COV_ANALYSIS 29 | "Set this to ON to build coverity analysis project." 30 | OFF ) 31 | 32 | # Set output directories. 33 | set( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin ) 34 | set( CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib ) 35 | set( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib ) 36 | 37 | # Include filepaths for source and include. 38 | include( ${MODULE_ROOT_DIR}/backoffAlgorithmFilePaths.cmake ) 39 | 40 | # ================================ Coverity Analysis Configuration ================================= 41 | if( COV_ANALYSIS ) 42 | 43 | # Target for Coverity analysis that builds the library. 44 | add_library( coverity_analysis 45 | ${BACKOFF_ALGORITHM_SOURCES} ) 46 | 47 | # Backoff Algorithm library public include path. 48 | target_include_directories( coverity_analysis 49 | PUBLIC 50 | ${BACKOFF_ALGORITHM_INCLUDE_PUBLIC_DIRS} ) 51 | 52 | # Disable logging/assert() calls when building the Coverity analysis target 53 | target_compile_options(coverity_analysis PUBLIC -DNDEBUG ) 54 | endif() 55 | 56 | # ==================================== Unit Test Configuration ==================================== 57 | 58 | if(${BUILD_CODE_EXAMPLE}) 59 | 60 | # Target for code example binary. 61 | add_executable( code_example_posix 62 | ${MODULE_ROOT_DIR}/docs/doxygen/code_examples/backoff_algorithm_posix.c 63 | ${BACKOFF_ALGORITHM_SOURCES} ) 64 | 65 | # Backoff Algorithm library public include path. 66 | target_include_directories( code_example_posix 67 | PUBLIC 68 | ${BACKOFF_ALGORITHM_INCLUDE_PUBLIC_DIRS} ) 69 | endif() 70 | 71 | # ==================================== Unit Test Configuration ==================================== 72 | 73 | if( UNITTEST ) 74 | 75 | # Include Unity build configuration. 76 | include( unit-test/unity_build.cmake ) 77 | 78 | # Check if the Unity source directory exists, and if not present, clone the submodule 79 | # if BUILD_CLONE_SUBMODULES configuration is enabled. 80 | if( NOT EXISTS ${UNITY_DIR}/src ) 81 | # Attempt to clone Unity. 82 | if( ${BUILD_CLONE_SUBMODULES} ) 83 | clone_unity() 84 | else() 85 | message( FATAL_ERROR "The required submodule Unity does not exist. Either clone it manually, or set BUILD_CLONE_SUBMODULES to 1 to automatically clone it during build." ) 86 | endif() 87 | 88 | endif() 89 | 90 | # Add unit test and coverage configuration. 91 | 92 | # Use CTest utility for managing test runs. This has to be added BEFORE 93 | # defining test targets with add_test() 94 | enable_testing() 95 | 96 | # Add build targets for Unity and Unit, required for unit testing. 97 | add_unity_targets() 98 | 99 | # Add function to enable Unity based tests and coverage. 100 | include( ${MODULE_ROOT_DIR}/tools/unity/create_test.cmake ) 101 | 102 | # Include build configuration for unit tests. 103 | add_subdirectory( unit-test ) 104 | 105 | # ==================================== Coverage Analysis configuration ============================ 106 | 107 | # Add a target for running coverage on tests. 108 | add_custom_target( coverage 109 | COMMAND ${CMAKE_COMMAND} -DUNITY_DIR=${UNITY_DIR} 110 | -P ${MODULE_ROOT_DIR}/tools/unity/coverage.cmake 111 | DEPENDS unity backoff_algorithm_utest 112 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR} 113 | ) 114 | 115 | endif() 116 | -------------------------------------------------------------------------------- /test/unit-test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Include file path configuration for backoff algorithm library. 2 | include(${MODULE_ROOT_DIR}/backoffAlgorithmFilePaths.cmake) 3 | 4 | project ("backoff algorithm unit test") 5 | cmake_minimum_required (VERSION 3.2.0) 6 | 7 | # ==================== Define your project name (edit) ======================== 8 | set(project_name "backoff_algorithm") 9 | 10 | # ===================== Create your mock here (edit) ======================== 11 | 12 | # list the files to mock here 13 | list(APPEND mock_list 14 | "" 15 | ) 16 | 17 | # list the directories your mocks need 18 | list(APPEND mock_include_list 19 | "" 20 | ) 21 | #list the definitions of your mocks to control what to be included 22 | list(APPEND mock_define_list 23 | "" 24 | ) 25 | 26 | # ================= Create the library under test here (edit) ================== 27 | 28 | # list the files you would like to test here 29 | list(APPEND real_source_files 30 | ${BACKOFF_ALGORITHM_SOURCES} 31 | ) 32 | # list the directories the module under test includes 33 | list(APPEND real_include_directories 34 | ${BACKOFF_ALGORITHM_INCLUDE_PUBLIC_DIRS} 35 | ) 36 | 37 | # ===================== Create UnitTest Code here (edit) ===================== 38 | 39 | # list the directories your test needs to include 40 | list(APPEND test_include_directories 41 | ${BACKOFF_ALGORITHM_INCLUDE_PUBLIC_DIRS} 42 | ${CMAKE_CURRENT_LIST_DIR} 43 | ) 44 | 45 | # ============================= (end edit) =================================== 46 | 47 | set(mock_name "${project_name}_mock") 48 | set(real_name "${project_name}_real") 49 | 50 | create_real_library(${real_name} 51 | "${real_source_files}" 52 | "${real_include_directories}" 53 | "" 54 | ) 55 | 56 | list(APPEND utest_link_list 57 | lib${real_name}.a 58 | ) 59 | 60 | list(APPEND utest_dep_list 61 | ${real_name} 62 | ) 63 | 64 | set(utest_name "${project_name}_utest") 65 | set(utest_source "${project_name}_utest.c") 66 | create_test(${utest_name} 67 | ${utest_source} 68 | "${utest_link_list}" 69 | "${utest_dep_list}" 70 | "${test_include_directories}" 71 | ) 72 | -------------------------------------------------------------------------------- /test/unit-test/backoff_algorithm_utest.c: -------------------------------------------------------------------------------- 1 | /* 2 | * backoffAlgorithm v1.4.1 3 | * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | * 5 | * SPDX-License-Identifier: MIT 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 8 | * this software and associated documentation files (the "Software"), to deal in 9 | * the Software without restriction, including without limitation the rights to 10 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 11 | * the Software, and to permit persons to whom the Software is furnished to do so, 12 | * subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 19 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 21 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | /* Unity include. */ 30 | #include "unity.h" 31 | 32 | /* Include utility for catching assert failures. */ 33 | #include "catch_assert.h" 34 | 35 | /* Backoff Algorithm library include */ 36 | #include "backoff_algorithm.h" 37 | 38 | #define TEST_BACKOFF_BASE_VALUE ( 1000 ) 39 | #define TEST_BACKOFF_MAX_VALUE ( 10000 ) 40 | #define TEST_MAX_ATTEMPTS ( 5 ) 41 | /* Parameters to track the next max jitter or number of attempts done. */ 42 | static BackoffAlgorithmContext_t retryParams; 43 | /* Return value of #BackoffAlgorithm_GetNextBackoff. */ 44 | static BackoffAlgorithmStatus_t BackoffAlgorithmStatus; 45 | static uint16_t nextBackoff; 46 | static uint32_t testRandomVal; 47 | 48 | /* ============================ UNITY FIXTURES ============================ */ 49 | 50 | /* Called before each test method. */ 51 | void setUp() 52 | { 53 | /* Initialize context. */ 54 | BackoffAlgorithm_InitializeParams( &retryParams, 55 | TEST_BACKOFF_BASE_VALUE, 56 | TEST_BACKOFF_MAX_VALUE, 57 | TEST_MAX_ATTEMPTS ); 58 | } 59 | 60 | /* Called after each test method. */ 61 | void tearDown() 62 | { 63 | testRandomVal = 0; 64 | BackoffAlgorithmStatus = BackoffAlgorithmSuccess; 65 | nextBackoff = 0; 66 | } 67 | 68 | /* Called at the beginning of the whole suite. */ 69 | void suiteSetUp() 70 | { 71 | } 72 | 73 | /* Called at the end of the whole suite. */ 74 | int suiteTearDown( int numFailures ) 75 | { 76 | return numFailures; 77 | } 78 | 79 | /* ========================================================================== */ 80 | 81 | /** 82 | * @brief Helper method to make assertions on data of the context object. 83 | */ 84 | static void verifyContextData( BackoffAlgorithmContext_t * pContext, 85 | uint32_t expectedAttemptsDone, 86 | uint16_t expectedNextJitterMax, 87 | uint16_t expectedMaxBackoff, 88 | uint32_t expectedMaxAttempts ) 89 | { 90 | TEST_ASSERT_EQUAL( expectedNextJitterMax, pContext->nextJitterMax ); 91 | TEST_ASSERT_EQUAL( expectedAttemptsDone, pContext->attemptsDone ); 92 | TEST_ASSERT_EQUAL( expectedMaxAttempts, pContext->maxRetryAttempts ); 93 | TEST_ASSERT_EQUAL( expectedMaxBackoff, pContext->maxBackoffDelay ); 94 | } 95 | 96 | /** 97 | * @brief Test that #BackoffAlgorithm_InitializeParams encounters an assert 98 | * failure when a NULL context parameter is passed. 99 | */ 100 | void test_BackoffAlgorithm_InitializeParams_Invalid_Context( void ) 101 | { 102 | catch_assert( BackoffAlgorithm_InitializeParams( NULL /* Invalid context */, 103 | TEST_BACKOFF_BASE_VALUE, 104 | TEST_BACKOFF_MAX_VALUE, 105 | TEST_MAX_ATTEMPTS ) ); 106 | } 107 | 108 | /** 109 | * @brief Test that #BackoffAlgorithm_InitializeParams initializes the context 110 | * data as expected. 111 | */ 112 | void test_BackoffAlgorithm_InitializeParams_Sets_Jitter_Correctly( void ) 113 | { 114 | BackoffAlgorithm_InitializeParams( &retryParams, 115 | TEST_BACKOFF_BASE_VALUE, 116 | TEST_BACKOFF_MAX_VALUE, 117 | TEST_MAX_ATTEMPTS ); 118 | verifyContextData( &retryParams, 119 | 0, 120 | TEST_BACKOFF_BASE_VALUE, 121 | TEST_BACKOFF_MAX_VALUE, 122 | TEST_MAX_ATTEMPTS ); 123 | } 124 | 125 | /** 126 | * @brief Test that #BackoffAlgorithm_GetNextBackoff returns the expected next back-off 127 | * value and updates the contents of the context as expected when the random value 128 | * generated is lower than the max jitter value for the retry attempts. 129 | * 130 | * This test assumes that the max jitter value has not reached the configured 131 | * maximum back-off value. 132 | */ 133 | void test_BackoffAlgorithm_GetNextBackoff_Success_RandVal_Less_Than_Jitter_Max( void ) 134 | { 135 | int iter = 1; 136 | uint16_t expectedAttemptsDone = 0; 137 | uint16_t expectedNextJitterMax = TEST_BACKOFF_BASE_VALUE; 138 | uint16_t expectedNextBackoff = 0; 139 | 140 | for( ; iter < 2; iter++ ) 141 | { 142 | /* Set the random value as a value lower than 143 | * the jitter max value for the next retry attempt. */ 144 | testRandomVal = retryParams.nextJitterMax / 2; 145 | 146 | /* As the random value is less than the max jitter value, the expected 147 | * next backoff value should remain the same as the random value. */ 148 | expectedNextBackoff = testRandomVal; 149 | 150 | /* The jitter max value should double with the above call for use in next call. */ 151 | expectedNextJitterMax *= 2; 152 | 153 | /* The number of attempts should be updated by the above API call. */ 154 | expectedAttemptsDone++; 155 | 156 | TEST_ASSERT_LESS_THAN( TEST_BACKOFF_MAX_VALUE, expectedNextJitterMax ); 157 | 158 | /* Call the BackoffAlgorithm_GetNextBackoff API a couple times. */ 159 | TEST_ASSERT_EQUAL( BackoffAlgorithmSuccess, 160 | BackoffAlgorithm_GetNextBackoff( &retryParams, testRandomVal, &nextBackoff ) ); 161 | TEST_ASSERT_EQUAL( expectedNextBackoff, nextBackoff ); 162 | 163 | /* Verify that the context data for expected data after the API call. */ 164 | verifyContextData( &retryParams, 165 | expectedAttemptsDone, 166 | expectedNextJitterMax, 167 | TEST_BACKOFF_MAX_VALUE, 168 | TEST_MAX_ATTEMPTS ); 169 | } 170 | } 171 | 172 | /** 173 | * @brief Test that #BackoffAlgorithm_GetNextBackoff returns the expected next back-off 174 | * value and updates the contents of the context when the random value generated 175 | * is higher than the max jitter value for the retry attempts. 176 | * 177 | * This test assumes that the max jitter value has not reached the configured 178 | * maximum back-off value. 179 | */ 180 | void test_BackoffAlgorithm_GetNextBackoff_Success_RandVal_More_Than_Jitter_Max( void ) 181 | { 182 | int iter = 1; 183 | uint16_t expectedAttemptsDone = 0; 184 | uint16_t expectedNextJitterMax = TEST_BACKOFF_BASE_VALUE; 185 | 186 | for( ; iter < 2; iter++ ) 187 | { 188 | /* Set the random value as a value greater than 189 | * the jitter max value for the next retry attempt. */ 190 | testRandomVal = retryParams.nextJitterMax + 1; 191 | 192 | /* The jitter max value should double with the above call for use in next call. */ 193 | expectedNextJitterMax *= 2; 194 | TEST_ASSERT_LESS_THAN( TEST_BACKOFF_MAX_VALUE, expectedNextJitterMax ); 195 | 196 | /* The number of attempts should be updated by the above API call. */ 197 | expectedAttemptsDone++; 198 | 199 | /* As the random value is greater than the jitter max value, the expected 200 | * next backoff value should be truncated to a value within the jitter window 201 | * for the retry attempt. */ 202 | uint16_t expectedNextBackoff = ( testRandomVal % ( retryParams.nextJitterMax + 1U ) ); 203 | 204 | /* Call the BackoffAlgorithm_GetNextBackoff API a couple times. */ 205 | TEST_ASSERT_EQUAL( BackoffAlgorithmSuccess, 206 | BackoffAlgorithm_GetNextBackoff( &retryParams, testRandomVal, &nextBackoff ) ); 207 | TEST_ASSERT_EQUAL( expectedNextBackoff, nextBackoff ); 208 | 209 | /* Verify that the context data for expected data after the API call. */ 210 | verifyContextData( &retryParams, 211 | expectedAttemptsDone, 212 | expectedNextJitterMax, 213 | TEST_BACKOFF_MAX_VALUE, 214 | TEST_MAX_ATTEMPTS ); 215 | } 216 | } 217 | 218 | /** 219 | * @brief Tests the #BackoffAlgorithm_GetNextBackoff API when the next back-off value 220 | * is requested for exhausted retry attempts. 221 | */ 222 | void test_BackoffAlgorithm_GetNextBackoff_Attempts_Exhausted() 223 | { 224 | /* Update the context data to represent that maximum configured number of 225 | * retry attempts have been completed. */ 226 | retryParams.attemptsDone = TEST_MAX_ATTEMPTS; 227 | 228 | /* Call the BackoffAlgorithm_GetNextBackoff API. */ 229 | TEST_ASSERT_EQUAL( BackoffAlgorithmRetriesExhausted, 230 | BackoffAlgorithm_GetNextBackoff( &retryParams, testRandomVal, &nextBackoff ) ); 231 | /* Make sure that the value of the output parameter has not changed. */ 232 | TEST_ASSERT_EQUAL( 0, nextBackoff ); 233 | 234 | /* Make sure that the context data has not changed as the call to 235 | * BackoffAlgorithm_GetNextBackoff failed. */ 236 | verifyContextData( &retryParams, 237 | TEST_MAX_ATTEMPTS /* Number of attempts shouldn't change */, 238 | TEST_BACKOFF_BASE_VALUE, 239 | TEST_BACKOFF_MAX_VALUE, 240 | TEST_MAX_ATTEMPTS ); 241 | } 242 | 243 | /** 244 | * @brief Tests that the #BackoffAlgorithm_GetNextBackoff API does not calculate a backoff period 245 | * beyond the configured maximum backoff period. 246 | */ 247 | void test_BackoffAlgorithm_GetNextBackoff_Returns_Cap_Backoff( void ) 248 | { 249 | /* Initialize to 0 attempts, so the max value of next jitter will increase. */ 250 | retryParams.attemptsDone = 0U; 251 | 252 | /* Update the next jitter value to greater than half the maximum backoff so 253 | * that the BackoffAlgorithm_GetNextBackoff API updates the next jitter value to 254 | * the configured maximum backoff value. */ 255 | retryParams.nextJitterMax = ( TEST_BACKOFF_MAX_VALUE / 2U ) + 1; 256 | 257 | /* Set the random value equal to the current jitter max value. 258 | * Thus, the BackoffAlgorithm_GetNextBackoff API should return the random value as 259 | * the next back-off value. */ 260 | testRandomVal = retryParams.nextJitterMax; 261 | uint16_t expectedBackoffVal = testRandomVal; 262 | 263 | /* Call the BackoffAlgorithm_GetNextBackoff API. */ 264 | TEST_ASSERT_EQUAL( BackoffAlgorithmSuccess, 265 | BackoffAlgorithm_GetNextBackoff( &retryParams, testRandomVal, &nextBackoff ) ); 266 | /* Make sure that the expected value is returned for the next backoff. */ 267 | TEST_ASSERT_EQUAL( expectedBackoffVal, nextBackoff ); 268 | 269 | /* Verify that the next jitter max value has been set to the cap back-off value 270 | * configured in the context. */ 271 | verifyContextData( &retryParams, 272 | 1, 273 | TEST_BACKOFF_MAX_VALUE /* New jitter max */, 274 | TEST_BACKOFF_MAX_VALUE, 275 | TEST_MAX_ATTEMPTS ); 276 | 277 | 278 | /* Now, set the random value as the maximum back-off value to 279 | * expect that the next back-off value returned by the API is the maximum 280 | * back-off value.*/ 281 | testRandomVal = TEST_BACKOFF_MAX_VALUE; 282 | 283 | /* Call BackoffAlgorithm_GetNextBackoff API again to verify that it now returns the 284 | * cap value as the next back-off value. */ 285 | TEST_ASSERT_EQUAL( BackoffAlgorithmSuccess, 286 | BackoffAlgorithm_GetNextBackoff( &retryParams, testRandomVal, &nextBackoff ) ); 287 | /* Make sure that the capped backoff value is returned as the next backoff value . */ 288 | TEST_ASSERT_EQUAL( TEST_BACKOFF_MAX_VALUE, nextBackoff ); 289 | 290 | /* Verify that the context data for expected data after the API call. */ 291 | verifyContextData( &retryParams, 292 | 2, 293 | TEST_BACKOFF_MAX_VALUE /* jitter max remains unchanged */, 294 | TEST_BACKOFF_MAX_VALUE, 295 | TEST_MAX_ATTEMPTS ); 296 | } 297 | 298 | /** 299 | * @brief Tests the #BackoffAlgorithm_GetNextBackoff API when the next jitter max value 300 | * is one lower than half of the maximum backoff value. This tests that the API does not 301 | * update the next jitter max to the maximum backoff value in this case. 302 | */ 303 | void test_BackoffAlgorithm_GetNextBackoff_NextJitterMax_Below_Cap_Backoff( void ) 304 | { 305 | /* Initialize context. 306 | * Use the configuration constant of retrying forever to achieve branch coverage in tests 307 | * for the configuration. */ 308 | BackoffAlgorithm_InitializeParams( &retryParams, 309 | TEST_BACKOFF_BASE_VALUE, 310 | TEST_BACKOFF_MAX_VALUE, 311 | BACKOFF_ALGORITHM_RETRY_FOREVER ); 312 | 313 | /* Initialize to 0 attempts, so the max value of next jitter will increase. */ 314 | retryParams.attemptsDone = 0U; 315 | 316 | /* Set the random value to zero to test that the BackoffAlgorithm_GetNextBackoff 317 | * API will return zero as the next back-off value.*/ 318 | testRandomVal = 0; 319 | 320 | /* Update the next jitter max value to one less than half of max backoff 321 | * to make sure that the BackoffAlgorithm_GetNextBackoff API does not update it 322 | * to the cap value in the call.*/ 323 | retryParams.nextJitterMax = ( TEST_BACKOFF_MAX_VALUE / 2U ) - 1; 324 | 325 | /* Call the BackoffAlgorithm_GetNextBackoff API. */ 326 | TEST_ASSERT_EQUAL( BackoffAlgorithmSuccess, 327 | BackoffAlgorithm_GetNextBackoff( &retryParams, testRandomVal, &nextBackoff ) ); 328 | /* Make sure that zero is returned as the next backoff value . */ 329 | TEST_ASSERT_EQUAL( 0, nextBackoff ); 330 | 331 | /* Verify that the context data for expected data after the API call. */ 332 | verifyContextData( &retryParams, 333 | 1, 334 | TEST_BACKOFF_MAX_VALUE - 2U /* next jitter max value */, 335 | TEST_BACKOFF_MAX_VALUE, 336 | BACKOFF_ALGORITHM_RETRY_FOREVER ); 337 | } 338 | 339 | /** 340 | * @brief Tests that the #BackoffAlgorithm_GetNextBackoff API encounters assert failures 341 | * when called with invalid parameters. 342 | */ 343 | void test_BackoffAlgorithm_GetNextBackoff_Invalid_Params() 344 | { 345 | /* Invalid context. */ 346 | catch_assert( BackoffAlgorithm_GetNextBackoff( NULL, testRandomVal, &nextBackoff ) ); 347 | 348 | /* Invalid output parameter for next back-off. */ 349 | catch_assert( BackoffAlgorithm_GetNextBackoff( &retryParams, testRandomVal, NULL ) ); 350 | } 351 | -------------------------------------------------------------------------------- /test/unit-test/catch_assert.h: -------------------------------------------------------------------------------- 1 | /* 2 | * backoffAlgorithm v1.4.1 3 | * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | * 5 | * SPDX-License-Identifier: MIT 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 8 | * this software and associated documentation files (the "Software"), to deal in 9 | * the Software without restriction, including without limitation the rights to 10 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 11 | * the Software, and to permit persons to whom the Software is furnished to do so, 12 | * subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 19 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 21 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | /* 26 | * How to catch an assert: 27 | * - save a jump buffer where execution will resume after the assert 28 | * - setup a handler for the abort signal, call longjmp within 29 | * - optional - close stderr ( fd 2 ) to discard the assert message 30 | * 31 | * Unity also does a longjmp within its TEST_ASSERT* macros, 32 | * so the macro below restores stderr and the prior abort handler 33 | * before calling the Unity macro. 34 | */ 35 | 36 | #ifndef CATCH_ASSERT_H_ 37 | #define CATCH_ASSERT_H_ 38 | 39 | #include 40 | #include 41 | #include 42 | 43 | #ifndef CATCH_JMPBUF 44 | #define CATCH_JMPBUF waypoint_ 45 | #endif 46 | 47 | static jmp_buf CATCH_JMPBUF; 48 | 49 | #pragma GCC diagnostic push 50 | #pragma GCC diagnostic ignored "-Wunused-function" 51 | static void catchHandler_( int signal ) 52 | { 53 | longjmp( CATCH_JMPBUF, signal ); 54 | } 55 | #pragma GCC diagnostic pop 56 | 57 | #define catch_assert( x ) \ 58 | do { \ 59 | int try = 0, catch = 0; \ 60 | int saveFd = dup( 2 ); \ 61 | struct sigaction sa = { 0 }, saveSa; \ 62 | sa.sa_handler = catchHandler_; \ 63 | sigaction( SIGABRT, &sa, &saveSa ); \ 64 | close( 2 ); \ 65 | if( setjmp( CATCH_JMPBUF ) == 0 ) \ 66 | { \ 67 | try++; \ 68 | x; \ 69 | } \ 70 | else \ 71 | { \ 72 | catch++; \ 73 | } \ 74 | sigaction( SIGABRT, &saveSa, NULL ); \ 75 | dup2( saveFd, 2 ); \ 76 | close( saveFd ); \ 77 | TEST_ASSERT_EQUAL( try, catch ); \ 78 | } while( 0 ) 79 | 80 | #endif /* ifndef CATCH_ASSERT_H_ */ 81 | -------------------------------------------------------------------------------- /test/unit-test/unity_build.cmake: -------------------------------------------------------------------------------- 1 | # Macro utility to clone the Unity submodule. 2 | macro( clone_unity ) 3 | find_package( Git REQUIRED ) 4 | message( "Cloning submodule Unity." ) 5 | execute_process( COMMAND rm -rf ${UNITY_DIR} 6 | COMMAND ${GIT_EXECUTABLE} submodule update --checkout --init --recursive ${UNITY_DIR} 7 | WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} 8 | RESULT_VARIABLE UNITY_CLONE_RESULT ) 9 | 10 | if( NOT ${UNITY_CLONE_RESULT} STREQUAL "0" ) 11 | message( FATAL_ERROR "Failed to clone Unity submodule." ) 12 | endif() 13 | endmacro() 14 | 15 | # Macro utility to add library targets for Unity and Unity to build configuration. 16 | macro( add_unity_targets ) 17 | # Build Configuration for Unity and Unity libraries. 18 | list( APPEND UNITY_INCLUDE_DIRS 19 | "${UNITY_DIR}/src/" 20 | "${UNITY_DIR}/extras/fixture/src" 21 | "${UNITY_DIR}/extras/memory/src" 22 | ) 23 | 24 | add_library( unity STATIC 25 | "${UNITY_DIR}/src/unity.c" 26 | "${UNITY_DIR}/extras/fixture/src/unity_fixture.c" 27 | "${UNITY_DIR}/extras/memory/src/unity_memory.c" 28 | ) 29 | 30 | set_target_properties( unity PROPERTIES 31 | ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib 32 | POSITION_INDEPENDENT_CODE ON 33 | ) 34 | 35 | target_include_directories( unity PUBLIC 36 | ${UNITY_INCLUDE_DIRS} 37 | ) 38 | endmacro() 39 | -------------------------------------------------------------------------------- /tools/coverity/README.md: -------------------------------------------------------------------------------- 1 | # Static code analysis for backoffAlgorithm library 2 | This directory is made for the purpose of statically testing the MISRA C:2012 compliance of backoffAlgorithm using 3 | [Synopsys Coverity](https://www.synopsys.com/software-integrity/security-testing/static-analysis-sast.html) static analysis tool. 4 | To that end, this directory provides a [configuration file](https://github.com/FreeRTOS/backoffAlgorithm/blob/main/tools/coverity/misra.config) to use when 5 | building a binary for the tool to analyze. 6 | 7 | > **Note** 8 | For generating the report as outlined below, we have used Coverity version 2023.6.1. 9 | 10 | For details regarding the suppressed violations in the report (which can be generated using the instructions described below), please 11 | see the [MISRA.md](https://github.com/FreeRTOS/backoffAlgorithm/blob/main/MISRA.md) file. 12 | 13 | ## Getting Started 14 | ### Prerequisites 15 | You can run this on a platform supported by Coverity. The list and other details can be found [here](https://documentation.blackduck.com/bundle/coverity-docs/page/deploy-install-guide/topics/supported_platforms_for_coverity_analysis.html). 16 | To compile and run the Coverity target successfully, you must have the following: 17 | 18 | 1. CMake version > 3.13.0 (You can check whether you have this by typing `cmake --version`) 19 | 2. GCC compiler 20 | - You can see the downloading and installation instructions [here](https://gcc.gnu.org/install/). 21 | 3. Download the repo and include the submodules using the following commands. 22 | - `git clone --recurse-submodules git@github.com:FreeRTOS/backoffAlgorithm.git ./backoffAlgorithm` 23 | - `cd ./backoffAlgorithm` 24 | - `git submodule update --checkout --init --recursive` 25 | 26 | ### To build and run coverity: 27 | Go to the root directory of the library and run the following commands in terminal: 28 | 1. Update the compiler configuration in Coverity 29 | ~~~ 30 | cov-configure --force --compiler cc --comptype gcc 31 | ~~~ 32 | 2. Create the build files using CMake in a `build` directory 33 | ~~~ 34 | cmake -B build -S test -DCOV_ANALYSIS=1 35 | ~~~ 36 | 3. Go to the build directory and copy the coverity configuration file 37 | ~~~ 38 | cd build/ 39 | ~~~ 40 | 4. Build the static analysis target 41 | ~~~ 42 | cov-build --emit-complementary-info --dir cov-out make coverity_analysis 43 | ~~~ 44 | 5. Go to the Coverity output directory (`cov-out`) and begin Coverity static analysis 45 | ~~~ 46 | cd cov-out/ 47 | cov-analyze --dir . --coding-standard-config ../../tools/coverity/misra.config --tu-pattern "file('.*/source/.*')" 48 | ~~~ 49 | 6. Format the errors in HTML format so that it is more readable while removing the test and build directory from the report 50 | ~~~ 51 | cov-format-errors --dir . --file "source" --exclude-files '(/build/|/test/)' --html-output html-out; 52 | ~~~ 53 | 7. Format the errors in JSON format to perform a jq query to get a simplified list of any exceptions. 54 | NOTE: A blank output means there are no defects that aren't being suppressed by the config or inline comments. 55 | ~~~ 56 | cov-format-errors --dir . --file "source" --exclude-files '(/build/|/test/)' --json-output-v2 defects.json; 57 | echo -e "\n-------------------------Non-Suppresed Deviations, if any, Listed Below-------------------------\n"; 58 | jq '.issues[] | .events[] | .eventTag ' defects.json | sort | uniq -c | sort -nr; 59 | echo -e "\n-------------------------Non-Suppresed Deviations, if any, Listed Above-------------------------\n"; 60 | ~~~ 61 | 62 | For your convenience the commands above are below to be copy/pasted into a UNIX command friendly terminal. 63 | ~~~ 64 | cov-configure --force --compiler cc --comptype gcc; 65 | cmake -B build -S test -DCOV_ANALYSIS=1; 66 | cd build/; 67 | cov-build --emit-complementary-info --dir cov-out make coverity_analysis; 68 | cd cov-out/ 69 | cov-analyze --dir . --coding-standard-config ../../tools/coverity/misra.config; 70 | cov-format-errors --dir . --file "source" --exclude-files '(/build/|/test/)' --html-output html-out; 71 | cov-format-errors --dir . --file "source" --exclude-files '(/build/|/test/)' --json-output-v2 defects.json; 72 | echo -e "\n-------------------------Non-Suppresed Deviations, if any, Listed Below-------------------------\n"; 73 | jq '.issues[] | .events[] | .eventTag ' defects.json | sort | uniq -c | sort -nr; 74 | echo -e "\n-------------------------Non-Suppresed Deviations, if any, Listed Above-------------------------\n"; 75 | cd ../../; 76 | ~~~ 77 | 78 | You should now have the HTML formatted violations list in a directory named `build/cov-out/html-output`. 79 | With the current configuration and the provided project, you should not see any deviations. -------------------------------------------------------------------------------- /tools/coverity/misra.config: -------------------------------------------------------------------------------- 1 | { 2 | "version" : "2.0", 3 | "standard" : "c2012", 4 | "title" : "Coverity MISRA Configuration", 5 | "deviations" : [ 6 | { 7 | "deviation" : "Directive 4.9", 8 | "reason" : "Allow inclusion of function like macros. Logging is done using function like macros." 9 | }, 10 | { 11 | "deviation" : "Rule 2.4", 12 | "reason" : "Allow unused tags. Some compilers warn if types are not tagged." 13 | }, 14 | { 15 | "deviation" : "Rule 3.1", 16 | "reason" : "Allow nested comments. Documentation blocks contain comments for example code." 17 | }, 18 | { 19 | "deviation" : "Rule 8.7", 20 | "reason" : "API functions are not used by library. They must be externally visible in order to be used by the application." 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /tools/unity/coverage.cmake: -------------------------------------------------------------------------------- 1 | # Taken from amazon-freertos repository 2 | cmake_minimum_required(VERSION 3.13) 3 | set(BINARY_DIR ${CMAKE_BINARY_DIR}) 4 | # reset coverage counters 5 | execute_process( 6 | COMMAND lcov --directory ${CMAKE_BINARY_DIR} 7 | --base-directory ${CMAKE_BINARY_DIR} 8 | --zerocounters 9 | 10 | COMMAND mkdir -p ${CMAKE_BINARY_DIR}/coverage 11 | ) 12 | # make the initial/baseline capture a zeroed out files 13 | execute_process( COMMAND lcov --directory ${CMAKE_BINARY_DIR} 14 | --base-directory ${CMAKE_BINARY_DIR} 15 | --initial 16 | --capture 17 | --rc lcov_branch_coverage=1 18 | --rc genhtml_branch_coverage=1 19 | --output-file=${CMAKE_BINARY_DIR}/base_coverage.info 20 | ) 21 | file(GLOB files "${CMAKE_BINARY_DIR}/bin/tests/*") 22 | 23 | set(REPORT_FILE ${CMAKE_BINARY_DIR}/utest_report.txt) 24 | file(WRITE ${REPORT_FILE} "") 25 | # execute all files in bin directory, gathering the output to show it in CI 26 | foreach(testname ${files}) 27 | get_filename_component(test 28 | ${testname} 29 | NAME_WLE 30 | ) 31 | message("Running ${testname}") 32 | execute_process(COMMAND ${testname} OUTPUT_FILE ${CMAKE_BINARY_DIR}/${test}_out.txt) 33 | 34 | file(READ ${CMAKE_BINARY_DIR}/${test}_out.txt CONTENTS) 35 | file(APPEND ${REPORT_FILE} "${CONTENTS}") 36 | endforeach() 37 | 38 | # generate Junit style xml output 39 | execute_process(COMMAND ruby 40 | ${UNITY_DIR}/auto/parse_output.rb 41 | -xml ${REPORT_FILE} 42 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR} 43 | ) 44 | 45 | # capture data after running the tests 46 | execute_process( 47 | COMMAND lcov --capture 48 | --rc lcov_branch_coverage=1 49 | --rc genhtml_branch_coverage=1 50 | --base-directory ${CMAKE_BINARY_DIR} 51 | --directory ${CMAKE_BINARY_DIR} 52 | --output-file ${CMAKE_BINARY_DIR}/second_coverage.info 53 | ) 54 | 55 | # combile baseline results (zeros) with the one after running the tests 56 | execute_process( 57 | COMMAND lcov --base-directory ${CMAKE_BINARY_DIR} 58 | --directory ${CMAKE_BINARY_DIR} 59 | --add-tracefile ${CMAKE_BINARY_DIR}/base_coverage.info 60 | --add-tracefile ${CMAKE_BINARY_DIR}/second_coverage.info 61 | --output-file ${CMAKE_BINARY_DIR}/coverage.info 62 | --no-external 63 | --rc lcov_branch_coverage=1 64 | ) 65 | execute_process( 66 | COMMAND genhtml --rc lcov_branch_coverage=1 67 | --branch-coverage 68 | --output-directory ${CMAKE_BINARY_DIR}/coverage 69 | ${CMAKE_BINARY_DIR}/coverage.info 70 | ) 71 | -------------------------------------------------------------------------------- /tools/unity/create_test.cmake: -------------------------------------------------------------------------------- 1 | # Taken from amazon-freertos repository 2 | 3 | #function to create the test executable 4 | function(create_test test_name 5 | test_src 6 | link_list 7 | dep_list 8 | include_list) 9 | include (CTest) 10 | get_filename_component(test_src_absolute ${test_src} ABSOLUTE) 11 | add_custom_command(OUTPUT ${test_name}_runner.c 12 | COMMAND ruby 13 | ${UNITY_DIR}/auto/generate_test_runner.rb 14 | ${MODULE_ROOT_DIR}/tools/unity/project.yml 15 | ${test_src_absolute} 16 | ${test_name}_runner.c 17 | DEPENDS ${test_src} 18 | ) 19 | add_executable(${test_name} ${test_src} ${test_name}_runner.c) 20 | set_target_properties(${test_name} PROPERTIES 21 | COMPILE_FLAG "-O0 -ggdb" 22 | RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/tests" 23 | INSTALL_RPATH_USE_LINK_PATH TRUE 24 | LINK_FLAGS " \ 25 | -Wl,-rpath,${CMAKE_BINARY_DIR}/lib \ 26 | -Wl,-rpath,${CMAKE_CURRENT_BINARY_DIR}/lib" 27 | ) 28 | target_include_directories(${test_name} PUBLIC 29 | ${include_list} 30 | ) 31 | 32 | target_link_directories(${test_name} PUBLIC 33 | ${CMAKE_CURRENT_BINARY_DIR} 34 | ) 35 | 36 | # link all libraries sent through parameters 37 | foreach(link IN LISTS link_list) 38 | target_link_libraries(${test_name} ${link}) 39 | endforeach() 40 | 41 | # add dependency to all the dep_list parameter 42 | foreach(dependency IN LISTS dep_list) 43 | add_dependencies(${test_name} ${dependency}) 44 | target_link_libraries(${test_name} ${dependency}) 45 | endforeach() 46 | target_link_libraries(${test_name} -lgcov unity) 47 | target_link_directories(${test_name} PUBLIC 48 | ${CMAKE_CURRENT_BINARY_DIR}/lib 49 | ) 50 | add_test(NAME ${test_name} 51 | COMMAND ${CMAKE_BINARY_DIR}/bin/tests/${test_name} 52 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR} 53 | ) 54 | endfunction() 55 | 56 | function(create_real_library target 57 | src_file 58 | real_include_list) 59 | add_library(${target} STATIC 60 | ${src_file} 61 | ) 62 | target_include_directories(${target} PUBLIC 63 | ${real_include_list} 64 | ) 65 | set_target_properties(${target} PROPERTIES 66 | COMPILE_FLAGS "-Wextra -Wpedantic \ 67 | -fprofile-arcs -ftest-coverage -fprofile-generate \ 68 | -Wno-unused-but-set-variable" 69 | LINK_FLAGS "-fprofile-arcs -ftest-coverage \ 70 | -fprofile-generate " 71 | ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lib 72 | ) 73 | endfunction() 74 | -------------------------------------------------------------------------------- /tools/unity/project.yml: -------------------------------------------------------------------------------- 1 | :unity: 2 | :when_no_prototypes: :warn 3 | :enforce_strict_ordering: TRUE 4 | :treat_as: 5 | uint8: HEX8 6 | uint16: HEX16 7 | uint32: UINT32 8 | int8: INT8 9 | bool: UINT8 10 | :treat_externs: :exclude 11 | :weak: __attribute__((weak)) 12 | :treat_externs: :include 13 | --------------------------------------------------------------------------------