[修改] 增加freeRTOS
1. 版本FreeRTOSv202212.01,命名为kernel;
This commit is contained in:
63
kernel/FreeRTOS-Plus/Source/AWS/device-defender/.github/CONTRIBUTING.md
vendored
Normal file
63
kernel/FreeRTOS-Plus/Source/AWS/device-defender/.github/CONTRIBUTING.md
vendored
Normal file
@ -0,0 +1,63 @@
|
||||
# Contributing Guidelines
|
||||
|
||||
Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional
|
||||
documentation, we greatly value feedback and contributions from our community.
|
||||
|
||||
Please read through this document before submitting any issues or pull requests to ensure we have all the necessary
|
||||
information to effectively respond to your bug report or contribution.
|
||||
|
||||
|
||||
## Reporting Bugs/Feature Requests
|
||||
|
||||
We welcome you to use the GitHub issue tracker to report bugs or suggest features.
|
||||
|
||||
When filing an issue, please check [existing open](https://github.com/aws/Device-Defender-for-AWS-IoT-embedded-sdk/issues), or [recently closed](https://github.com/aws/Device-Defender-for-AWS-IoT-embedded-sdk/issues?q=is%3Aissue+is%3Aclosed), issues to make sure somebody else hasn't already
|
||||
reported the issue. Please try to include as much information as you can. Details like these are incredibly useful:
|
||||
|
||||
* A reproducible test case or series of steps
|
||||
* The version of our code being used
|
||||
* Any modifications you've made relevant to the bug
|
||||
* Anything unusual about your environment or deployment
|
||||
|
||||
|
||||
## Contributing via Pull Requests
|
||||
Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that:
|
||||
|
||||
1. You are working against the latest source on the *main* branch.
|
||||
1. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already.
|
||||
1. You open an issue to discuss any significant work - we would hate for your time to be wasted.
|
||||
|
||||
To send us a pull request, please:
|
||||
|
||||
1. Fork the repository.
|
||||
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.
|
||||
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).
|
||||
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).
|
||||
1. Ensure local tests pass.
|
||||
1. Commit to your fork using clear commit messages.
|
||||
1. Send us a pull request, answering any default questions in the pull request interface.
|
||||
1. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation.
|
||||
|
||||
GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and
|
||||
[creating a pull request](https://help.github.com/articles/creating-a-pull-request/).
|
||||
|
||||
|
||||
## Finding contributions to work on
|
||||
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/aws/Device-Defender-for-AWS-IoT-embedded-sdk/labels?q=help+wanted) issues is a great place to start.
|
||||
|
||||
|
||||
## Code of Conduct
|
||||
This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct).
|
||||
For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact
|
||||
opensource-codeofconduct@amazon.com with any additional questions or comments.
|
||||
|
||||
|
||||
## Security issue notifications
|
||||
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.
|
||||
|
||||
|
||||
## Licensing
|
||||
|
||||
See the [LICENSE](../LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution.
|
||||
|
||||
We may ask you to sign a [Contributor License Agreement (CLA)](https://en.wikipedia.org/wiki/Contributor_License_Agreement) for larger changes.
|
||||
12
kernel/FreeRTOS-Plus/Source/AWS/device-defender/.github/memory_statistics_config.json
vendored
Normal file
12
kernel/FreeRTOS-Plus/Source/AWS/device-defender/.github/memory_statistics_config.json
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"lib_name": "AWS IoT Device Defender",
|
||||
"src": [
|
||||
"source/defender.c"
|
||||
],
|
||||
"include": [
|
||||
"source/include"
|
||||
],
|
||||
"compiler_flags": [
|
||||
"DEFENDER_DO_NOT_USE_CUSTOM_CONFIG"
|
||||
]
|
||||
}
|
||||
113
kernel/FreeRTOS-Plus/Source/AWS/device-defender/.github/workflows/ci.yml
vendored
Normal file
113
kernel/FreeRTOS-Plus/Source/AWS/device-defender/.github/workflows/ci.yml
vendored
Normal file
@ -0,0 +1,113 @@
|
||||
name: CI Checks
|
||||
on:
|
||||
push:
|
||||
branches: ["**"]
|
||||
pull_request:
|
||||
branches: [main]
|
||||
workflow_dispatch:
|
||||
jobs:
|
||||
unittest:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Clone This Repo
|
||||
uses: actions/checkout@v2
|
||||
- name: Build
|
||||
run: |
|
||||
sudo apt-get install -y lcov
|
||||
cmake -S test -B build/ \
|
||||
-G "Unix Makefiles" \
|
||||
-DCMAKE_BUILD_TYPE=Debug \
|
||||
-DBUILD_CLONE_SUBMODULES=ON \
|
||||
-DCMAKE_C_FLAGS='--coverage -Wall -Wextra -Werror -DNDEBUG'
|
||||
make -C build/ all
|
||||
- name: Test
|
||||
run: |
|
||||
cd build/
|
||||
ctest -E system --output-on-failure
|
||||
cd ..
|
||||
- name: Run Coverage
|
||||
run: |
|
||||
make -C build/ coverage
|
||||
declare -a EXCLUDE=("\*test\*" "\*CMakeCCompilerId\*" "\*mocks\*")
|
||||
echo ${EXCLUDE[@]} | xargs lcov --rc lcov_branch_coverage=1 -r build/coverage.info -o build/coverage.info
|
||||
lcov --rc lcov_branch_coverage=1 --list build/coverage.info
|
||||
- name: Check Coverage
|
||||
uses: FreeRTOS/CI-CD-Github-Actions/coverage-cop@main
|
||||
with:
|
||||
path: ./build/coverage.info
|
||||
build-with-default-config:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Clone This Repo
|
||||
uses: actions/checkout@v2
|
||||
- name: Build
|
||||
run: |
|
||||
cmake -S test -B build/ \
|
||||
-G "Unix Makefiles" \
|
||||
-DCMAKE_BUILD_TYPE=Debug \
|
||||
-DCMAKE_C_FLAGS='-Wall -Wextra -Werror -DDEFENDER_DO_NOT_USE_CUSTOM_CONFIG'
|
||||
make -C build/ all
|
||||
complexity:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Check complexity
|
||||
uses: FreeRTOS/CI-CD-Github-Actions/complexity@main
|
||||
with:
|
||||
path: ./
|
||||
doxygen:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Run doxygen build
|
||||
uses: FreeRTOS/CI-CD-Github-Actions/doxygen@main
|
||||
with:
|
||||
path: ./
|
||||
spell-check:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Clone This Repo
|
||||
uses: actions/checkout@v2
|
||||
- name: Run spellings check
|
||||
uses: FreeRTOS/CI-CD-Github-Actions/spellings@main
|
||||
with:
|
||||
path: ./
|
||||
formatting:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Check formatting
|
||||
uses: FreeRTOS/CI-CD-Github-Actions/formatting@main
|
||||
with:
|
||||
path: ./
|
||||
git-secrets:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Checkout awslabs/git-secrets
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: awslabs/git-secrets
|
||||
ref: master
|
||||
path: git-secrets
|
||||
- name: Install git-secrets
|
||||
run: cd git-secrets && sudo make install && cd ..
|
||||
- name: Run git-secrets
|
||||
run: |
|
||||
git-secrets --register-aws
|
||||
git-secrets --scan
|
||||
memory_statistics:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
- name: Install Python3
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: '3.7.10'
|
||||
- name: Measure sizes
|
||||
uses: FreeRTOS/CI-CD-Github-Actions/memory_statistics@main
|
||||
with:
|
||||
config: .github/memory_statistics_config.json
|
||||
check_against: docs/doxygen/include/size_table.md
|
||||
11
kernel/FreeRTOS-Plus/Source/AWS/device-defender/.github/workflows/doxygen.yml
vendored
Normal file
11
kernel/FreeRTOS-Plus/Source/AWS/device-defender/.github/workflows/doxygen.yml
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
name: Doxygen Generation
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
workflow_dispatch:
|
||||
jobs:
|
||||
doxygen-generation:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Doxygen generation
|
||||
uses: FreeRTOS/CI-CD-Github-Actions/doxygen-generation@main
|
||||
139
kernel/FreeRTOS-Plus/Source/AWS/device-defender/.github/workflows/release.yml
vendored
Normal file
139
kernel/FreeRTOS-Plus/Source/AWS/device-defender/.github/workflows/release.yml
vendored
Normal file
@ -0,0 +1,139 @@
|
||||
name: Release automation
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
commit_id:
|
||||
description: 'Commit ID to tag and create a release for'
|
||||
required: true
|
||||
version_number:
|
||||
description: 'Release Version Number (Eg, v1.0.0)'
|
||||
required: true
|
||||
|
||||
jobs:
|
||||
tag-commit:
|
||||
name: Tag commit
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
ref: ${{ github.event.inputs.commit_id }}
|
||||
- name: Configure git identity
|
||||
run: |
|
||||
git config --global user.name ${{ github.actor }}
|
||||
git config --global user.email ${{ github.actor }}@users.noreply.github.com
|
||||
- name: create a new branch that references commit id
|
||||
run: git checkout -b ${{ github.event.inputs.version_number }} ${{ github.event.inputs.commit_id }}
|
||||
- name: Generate SBOM
|
||||
uses: FreeRTOS/CI-CD-Github-Actions/sbom-generator@main
|
||||
with:
|
||||
repo_path: ./
|
||||
source_path: ./source
|
||||
- name: commit SBOM file
|
||||
run: |
|
||||
git add .
|
||||
git commit -m 'Update SBOM'
|
||||
git push -u origin ${{ github.event.inputs.version_number }}
|
||||
- name: Tag Commit and Push to remote
|
||||
run: |
|
||||
git tag ${{ github.event.inputs.version_number }} -a -m "AWS IoT Device Defender ${{ github.event.inputs.version_number }}"
|
||||
git push origin --tags
|
||||
- name: Verify tag on remote
|
||||
run: |
|
||||
git tag -d ${{ github.event.inputs.version_number }}
|
||||
git remote update
|
||||
git checkout tags/${{ github.event.inputs.version_number }}
|
||||
git diff ${{ github.event.inputs.commit_id }} tags/${{ github.event.inputs.version_number }}
|
||||
create-zip:
|
||||
needs: tag-commit
|
||||
name: Create ZIP and verify package for release asset.
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Install ZIP tools
|
||||
run: sudo apt-get install zip unzip
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
ref: ${{ github.event.inputs.commit_id }}
|
||||
path: Device-Defender-for-AWS-IoT-embedded-sdk
|
||||
submodules: recursive
|
||||
- name: Checkout disabled submodules
|
||||
run: |
|
||||
cd Device-Defender-for-AWS-IoT-embedded-sdk
|
||||
git submodule update --init --checkout --recursive
|
||||
- name: Create ZIP
|
||||
run: |
|
||||
zip -r Device-Defender-for-AWS-IoT-embedded-sdk-${{ github.event.inputs.version_number }}.zip Device-Defender-for-AWS-IoT-embedded-sdk -x "*.git*"
|
||||
ls ./
|
||||
- name: Validate created ZIP
|
||||
run: |
|
||||
mkdir zip-check
|
||||
mv Device-Defender-for-AWS-IoT-embedded-sdk-${{ github.event.inputs.version_number }}.zip zip-check
|
||||
cd zip-check
|
||||
unzip Device-Defender-for-AWS-IoT-embedded-sdk-${{ github.event.inputs.version_number }}.zip -d Device-Defender-for-AWS-IoT-embedded-sdk-${{ github.event.inputs.version_number }}
|
||||
ls Device-Defender-for-AWS-IoT-embedded-sdk-${{ github.event.inputs.version_number }}
|
||||
diff -r -x "*.git*" Device-Defender-for-AWS-IoT-embedded-sdk-${{ github.event.inputs.version_number }}/Device-Defender-for-AWS-IoT-embedded-sdk/ ../Device-Defender-for-AWS-IoT-embedded-sdk/
|
||||
cd ../
|
||||
- name: Build
|
||||
run: |
|
||||
cd zip-check/Device-Defender-for-AWS-IoT-embedded-sdk-${{ github.event.inputs.version_number }}/Device-Defender-for-AWS-IoT-embedded-sdk
|
||||
sudo apt-get install -y lcov
|
||||
cmake -S test -B build/ \
|
||||
-G "Unix Makefiles" \
|
||||
-DCMAKE_BUILD_TYPE=Debug \
|
||||
-DBUILD_CLONE_SUBMODULES=ON \
|
||||
-DCMAKE_C_FLAGS='--coverage -Wall -Wextra -Werror -DNDEBUG'
|
||||
make -C build/ all
|
||||
- name: Test
|
||||
run: |
|
||||
cd zip-check/Device-Defender-for-AWS-IoT-embedded-sdk-${{ github.event.inputs.version_number }}/Device-Defender-for-AWS-IoT-embedded-sdk/build/
|
||||
ctest -E system --output-on-failure
|
||||
cd ..
|
||||
- name: Create artifact of ZIP
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: Device-Defender-for-AWS-IoT-embedded-sdk-${{ github.event.inputs.version_number }}.zip
|
||||
path: zip-check/Device-Defender-for-AWS-IoT-embedded-sdk-${{ github.event.inputs.version_number }}.zip
|
||||
deploy-doxygen:
|
||||
needs: tag-commit
|
||||
name: Deploy doxygen documentation
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Doxygen generation
|
||||
uses: FreeRTOS/CI-CD-Github-Actions/doxygen-generation@main
|
||||
with:
|
||||
ref: ${{ github.event.inputs.version_number }}
|
||||
add_release: "true"
|
||||
create-release:
|
||||
needs:
|
||||
- create-zip
|
||||
- deploy-doxygen
|
||||
name: Create Release and Upload Release Asset
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Create Release
|
||||
id: create_release
|
||||
uses: actions/create-release@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tag_name: ${{ github.event.inputs.version_number }}
|
||||
release_name: ${{ github.event.inputs.version_number }}
|
||||
body: Release ${{ github.event.inputs.version_number }} of AWS IoT Device Defender.
|
||||
draft: false
|
||||
prerelease: false
|
||||
- name: Download ZIP artifact
|
||||
uses: actions/download-artifact@v2
|
||||
with:
|
||||
name: Device-Defender-for-AWS-IoT-embedded-sdk-${{ github.event.inputs.version_number }}.zip
|
||||
- name: Upload Release Asset
|
||||
id: upload-release-asset
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: ./Device-Defender-for-AWS-IoT-embedded-sdk-${{ github.event.inputs.version_number }}.zip
|
||||
asset_name: Device-Defender-for-AWS-IoT-embedded-sdk-${{ github.event.inputs.version_number }}.zip
|
||||
asset_content_type: application/zip
|
||||
13
kernel/FreeRTOS-Plus/Source/AWS/device-defender/.gitignore
vendored
Normal file
13
kernel/FreeRTOS-Plus/Source/AWS/device-defender/.gitignore
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
# Ignore documentation output.
|
||||
**/docs/**/output/*
|
||||
|
||||
# Ignore CMake build directory.
|
||||
build/
|
||||
|
||||
# Ignore build artifacts.
|
||||
*.o
|
||||
|
||||
# Ignore code coverage artifacts.
|
||||
*.gcda
|
||||
*.gcno
|
||||
*.gcov
|
||||
4
kernel/FreeRTOS-Plus/Source/AWS/device-defender/.gitmodules
vendored
Normal file
4
kernel/FreeRTOS-Plus/Source/AWS/device-defender/.gitmodules
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
[submodule "test/unit-test/Unity"]
|
||||
path = test/unit-test/Unity
|
||||
url = https://github.com/ThrowTheSwitch/Unity
|
||||
update = none
|
||||
39
kernel/FreeRTOS-Plus/Source/AWS/device-defender/CHANGELOG.md
Normal file
39
kernel/FreeRTOS-Plus/Source/AWS/device-defender/CHANGELOG.md
Normal file
@ -0,0 +1,39 @@
|
||||
# Changelog for AWS IoT Device Defender Library
|
||||
|
||||
## v1.3.0 (October 2022)
|
||||
|
||||
### Updates
|
||||
- [#60](https://github.com/aws/Device-Defender-for-AWS-IoT-embedded-sdk/pull/60) MISRA Compliance Update
|
||||
- [#59](https://github.com/aws/Device-Defender-for-AWS-IoT-embedded-sdk/pull/59) Update CBMC starter kit
|
||||
- [#56](https://github.com/aws/Device-Defender-for-AWS-IoT-embedded-sdk/pull/56) Loop invariant update
|
||||
|
||||
|
||||
## v1.2.0 (November 2021)
|
||||
|
||||
### Updates
|
||||
- [#50](https://github.com/aws/Device-Defender-for-AWS-IoT-embedded-sdk/pull/50) Update doxygen version for documentation
|
||||
|
||||
## v1.1.1 (July 2021)
|
||||
|
||||
### Updates
|
||||
- [#45](https://github.com/aws/Device-Defender-for-AWS-IoT-embedded-sdk/pull/45) Remove parentheses from key name macros to enable concatenating them with other string literals.
|
||||
|
||||
## v1.1.0 (March 2021)
|
||||
|
||||
### Updates
|
||||
- [#36](https://github.com/aws/device-defender-for-aws-iot-embedded-sdk/pull/36) Add macros to API for [custom metrics](https://docs.aws.amazon.com/iot/latest/developerguide/dd-detect-custom-metrics.html) feature of AWS IoT Device Defender service.
|
||||
|
||||
## v1.0.1 (December 2020)
|
||||
|
||||
### Updates
|
||||
- [#28](https://github.com/aws/device-defender-for-aws-iot-embedded-sdk/pull/28) Cast logging arguments to C types matching the format specifiers.
|
||||
|
||||
### Other
|
||||
- [#23](https://github.com/aws/device-defender-for-aws-iot-embedded-sdk/pull/23) Formatting update.
|
||||
- [#25](https://github.com/aws/device-defender-for-aws-iot-embedded-sdk/pull/25), [#30](https://github.com/aws/device-defender-for-aws-iot-embedded-sdk/pull/30) Github actions updates.
|
||||
- [#26](https://github.com/aws/device-defender-for-aws-iot-embedded-sdk/pull/26), [#29](https://github.com/aws/device-defender-for-aws-iot-embedded-sdk/pull/29) Github repository chores.
|
||||
|
||||
## v1.0.0 (November 2020)
|
||||
|
||||
This is the first release of the AWS IoT Device Defender Client Library in this
|
||||
repository.
|
||||
20
kernel/FreeRTOS-Plus/Source/AWS/device-defender/LICENSE
Normal file
20
kernel/FreeRTOS-Plus/Source/AWS/device-defender/LICENSE
Normal file
@ -0,0 +1,20 @@
|
||||
MIT License
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
16
kernel/FreeRTOS-Plus/Source/AWS/device-defender/MISRA.md
Normal file
16
kernel/FreeRTOS-Plus/Source/AWS/device-defender/MISRA.md
Normal file
@ -0,0 +1,16 @@
|
||||
# MISRA Compliance
|
||||
|
||||
The Device Defender Client Library files conform to the [MISRA C:2012](https://www.misra.org.uk)
|
||||
guidelines, with some noted exceptions. Compliance is checked with Coverity static analysis.
|
||||
The specific deviations, suppressed inline, are listed below.
|
||||
|
||||
Additionally, [MISRA configuration file](https://github.com/aws/Device-Defender-for-AWS-IoT-embedded-sdk/blob/main/tools/coverity/misra.config) contains the project wide deviations.
|
||||
|
||||
### Suppressed with Coverity Comments
|
||||
To find the violation references in the source files run grep on the source code
|
||||
with ( Assuming rule 11.4 violation; with justification in point 2 ):
|
||||
```
|
||||
grep 'MISRA Ref 11.4.2' . -rI
|
||||
```
|
||||
|
||||
*None.*
|
||||
119
kernel/FreeRTOS-Plus/Source/AWS/device-defender/README.md
Normal file
119
kernel/FreeRTOS-Plus/Source/AWS/device-defender/README.md
Normal file
@ -0,0 +1,119 @@
|
||||
# AWS IoT Device Defender Library
|
||||
|
||||
The Device Defender library enables you to send device metrics to the [AWS IoT Device Defender Service](https://aws.amazon.com/iot-device-defender/).
|
||||
This library also supports custom metrics, a feature that helps you monitor operational health metrics that are unique to your fleet or use case. For example, you can define a new metric to monitor the memory usage or CPU usage on your devices.
|
||||
This library has no dependencies on any additional libraries other than the
|
||||
standard C library, and therefore, can be used with any MQTT client library.
|
||||
This library is distributed under the [MIT Open Source License](LICENSE).
|
||||
|
||||
This library has gone through code quality checks including verification that no
|
||||
function has a [GNU Complexity](https://www.gnu.org/software/complexity/manual/complexity.html)
|
||||
score over 8, and checks against deviations from mandatory rules in the
|
||||
[MISRA coding standard](https://www.misra.org.uk).
|
||||
Deviations from the MISRA C:2012 guidelines are documented under [MISRA Deviations](MISRA.md).
|
||||
This library has also undergone static code analysis using [Coverity static analysis](https://scan.coverity.com/),
|
||||
and validation of memory safety through the [CBMC automated reasoning tool](https://www.cprover.org/cbmc/).
|
||||
|
||||
See memory requirements for this library [here](./docs/doxygen/include/size_table.md).
|
||||
|
||||
**AWS IoT Device Defender v1.3.0 [source code](https://github.com/aws/Device-Defender-for-AWS-IoT-embedded-sdk/tree/v1.3.0/source) is part of the [FreeRTOS 202210.00 LTS](https://github.com/FreeRTOS/FreeRTOS-LTS/tree/202210.00-LTS) release.**
|
||||
|
||||
**AWS IoT Device Defender v1.1.0 [source code](https://github.com/aws/Device-Defender-for-AWS-IoT-embedded-sdk/tree/v1.1.0/source) is part of the [FreeRTOS 202012.01 LTS](https://github.com/FreeRTOS/FreeRTOS-LTS/tree/202012.01-LTS) release.**
|
||||
|
||||
## AWS IoT Device Defender Client Config File
|
||||
|
||||
The AWS IoT Device Defender Client Library exposes build configuration macros
|
||||
that are required for building the library. A list of all the configurations and
|
||||
their default values are defined in
|
||||
[defender_config_defaults.h](source/include/defender_config_defaults.h).
|
||||
To provide custom values for the configuration macros, a config file named
|
||||
`defender_config.h` can be provided by the application to the library.
|
||||
|
||||
By default, a `defender_config.h` config file is required to build the library.
|
||||
To disable this requirement and build the library with default configuration
|
||||
values, provide `DEFENDER_DO_NOT_USE_CUSTOM_CONFIG` as a compile time
|
||||
preprocessor macro.
|
||||
|
||||
**Thus, the Device Defender client library can be built by either**:
|
||||
* Defining a `defender_config.h` file in the application, and adding it to the
|
||||
include directories list of the library.
|
||||
|
||||
**OR**
|
||||
|
||||
* Defining the `DEFENDER_DO_NOT_USE_CUSTOM_CONFIG` preprocessor macro for the
|
||||
library build.
|
||||
|
||||
## Building the Library
|
||||
|
||||
The [defenderFilePaths.cmake](defenderFilePaths.cmake) file contains the
|
||||
information of all source files and the header include paths required to build
|
||||
the Device Defender client library.
|
||||
|
||||
As mentioned in the previous section, either a custom config file
|
||||
(i.e. `defender_config.h`) or `DEFENDER_DO_NOT_USE_CUSTOM_CONFIG` macro needs to
|
||||
be provided to build the Device Defender client library.
|
||||
|
||||
For a CMake example of building the Device Defender client library with the
|
||||
`defenderFilePaths.cmake` file, refer to the `coverity_analysis` library target
|
||||
in [test/CMakeLists.txt](test/CMakeLists.txt) file.
|
||||
|
||||
## Building Unit Tests
|
||||
|
||||
### Platform Prerequisites
|
||||
|
||||
- For running unit tests:
|
||||
- **C90 compiler** like gcc.
|
||||
- **CMake 3.13.0 or later**.
|
||||
- **Ruby 2.0.0 or later** is additionally required for the CMock test framework (that we use).
|
||||
- For running the coverage target, **gcov** and **lcov** are additionally required.
|
||||
|
||||
### Steps to build **Unit Tests**
|
||||
|
||||
1. Go to the root directory of this repository.
|
||||
|
||||
1. Run the *cmake* command: `cmake -S test -B build -DBUILD_CLONE_SUBMODULES=ON`.
|
||||
|
||||
1. Run this command to build the library and unit tests: `make -C build all`.
|
||||
|
||||
1. The generated test executables will be present in `build/bin/tests` folder.
|
||||
|
||||
1. Run `cd build && ctest` to execute all tests and view the test run summary.
|
||||
|
||||
## CBMC
|
||||
|
||||
To learn more about CBMC and proofs specifically, review the training material [here](https://model-checking.github.io/cbmc-training).
|
||||
|
||||
The `test/cbmc/proofs` directory contains CBMC proofs.
|
||||
|
||||
In order to run these proofs you will need to install CBMC and other tools by following the instructions [here](https://model-checking.github.io/cbmc-training/installation.html).
|
||||
|
||||
## Reference examples
|
||||
|
||||
The AWS IoT Embedded C-SDK repository contains a demo showing the use of AWS IoT
|
||||
Device Defender Client Library [here](https://github.com/aws/aws-iot-device-sdk-embedded-C/tree/main/demos/defender/defender_demo_json)
|
||||
on a POSIX platform.
|
||||
|
||||
## Documentation
|
||||
|
||||
### Existing documentation
|
||||
For pre-generated documentation, please see the documentation linked in the locations below:
|
||||
|
||||
| Location |
|
||||
| :-: |
|
||||
| [AWS IoT Device SDK for Embedded C](https://github.com/aws/aws-iot-device-sdk-embedded-C#releases-and-documentation) |
|
||||
| [FreeRTOS.org](https://freertos.org/Documentation/api-ref/device-defender-for-aws-iot-embedded-sdk/docs/doxygen/output/html/index.html) |
|
||||
|
||||
Note that the latest included version of the AWS IoT Device Defender library may differ across repositories.
|
||||
|
||||
### Generating documentation
|
||||
|
||||
The Doxygen references were created using Doxygen version 1.9.2. To generate the
|
||||
Doxygen pages, please run the following command from the root of this repository:
|
||||
|
||||
```shell
|
||||
doxygen docs/doxygen/config.doxyfile
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
||||
See [CONTRIBUTING.md](./.github/CONTRIBUTING.md) for information on contributing.
|
||||
@ -0,0 +1,5 @@
|
||||
## Reporting a Vulnerability
|
||||
|
||||
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/) or directly via email to aws-security@amazon.com.
|
||||
Please do **not** create a public github issue.
|
||||
@ -0,0 +1,14 @@
|
||||
# This file is to add source files and include directories
|
||||
# into variables so that it can be reused from different repositories
|
||||
# in their Cmake based build system by including this file.
|
||||
#
|
||||
# Files specific to the repository such as test runner, platform tests
|
||||
# are not added to the variables.
|
||||
|
||||
# Device Defender library source files.
|
||||
set( DEFENDER_SOURCES
|
||||
"${CMAKE_CURRENT_LIST_DIR}/source/defender.c" )
|
||||
|
||||
# Device Defender library public include directories.
|
||||
set( DEFENDER_INCLUDE_PUBLIC_DIRS
|
||||
"${CMAKE_CURRENT_LIST_DIR}/source/include" )
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,20 @@
|
||||
<table>
|
||||
<tr>
|
||||
<td colspan="3"><center><b>Code Size of AWS IoT Device Defender (example generated with GCC for ARM Cortex-M)</b></center></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>File</b></td>
|
||||
<td><b><center>With -O1 Optimization</center></b></td>
|
||||
<td><b><center>With -Os Optimization</center></b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>defender.c</td>
|
||||
<td><center>1.1K</center></td>
|
||||
<td><center>0.6K</center></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Total estimates</b></td>
|
||||
<td><b><center>1.1K</center></b></td>
|
||||
<td><b><center>0.6K</center></b></td>
|
||||
</tr>
|
||||
</table>
|
||||
@ -0,0 +1,228 @@
|
||||
<doxygenlayout version="1.0">
|
||||
<!-- Generated by doxygen 1.8.20 -->
|
||||
<!-- Navigation index tabs for HTML output -->
|
||||
<navindex>
|
||||
<tab type="mainpage" visible="yes" title=""/>
|
||||
<tab type="pages" visible="yes" title="" intro=""/>
|
||||
<!-- Hide the default "Data Structures" tab and use the "Modules" tab for data
|
||||
structures. This allows internal data structures to be hidden. -->
|
||||
<tab type="modules" visible="yes" title="Data types and Constants" intro="This library defines the following data types and constants."/>
|
||||
<tab type="namespaces" visible="yes" title="">
|
||||
<tab type="namespacelist" visible="yes" title="" intro=""/>
|
||||
<tab type="namespacemembers" visible="yes" title="" intro=""/>
|
||||
</tab>
|
||||
<tab type="interfaces" visible="no" title="">
|
||||
<tab type="interfacelist" visible="no" title="" intro=""/>
|
||||
<tab type="interfaceindex" visible="no" title=""/>
|
||||
<tab type="interfacehierarchy" visible="yes" title="" intro=""/>
|
||||
</tab>
|
||||
<tab type="classes" visible="no" title="">
|
||||
<tab type="classlist" visible="no" title="" intro=""/>
|
||||
<tab type="classindex" visible="no" title=""/>
|
||||
<tab type="hierarchy" visible="no" title="" intro=""/>
|
||||
<tab type="classmembers" visible="no" title="" intro=""/>
|
||||
</tab>
|
||||
<tab type="structs" visible="no" title="">
|
||||
<tab type="structlist" visible="no" title="" intro=""/>
|
||||
<tab type="structindex" visible="no" title=""/>
|
||||
</tab>
|
||||
<tab type="exceptions" visible="no" title="">
|
||||
<tab type="exceptionlist" visible="no" title="" intro=""/>
|
||||
<tab type="exceptionindex" visible="no" title=""/>
|
||||
<tab type="exceptionhierarchy" visible="yes" title="" intro=""/>
|
||||
</tab>
|
||||
<tab type="files" visible="no" title="">
|
||||
<tab type="filelist" visible="yes" title="Files" intro="The following files are associated with this library."/>
|
||||
<tab type="globals" visible="no" title="" intro=""/>
|
||||
</tab>
|
||||
<tab type="examples" visible="yes" title="" intro=""/>
|
||||
</navindex>
|
||||
|
||||
<!-- Layout definition for a class page -->
|
||||
<class>
|
||||
<briefdescription visible="yes"/>
|
||||
<includes visible="$SHOW_INCLUDE_FILES"/>
|
||||
<inheritancegraph visible="$CLASS_GRAPH"/>
|
||||
<collaborationgraph visible="$COLLABORATION_GRAPH"/>
|
||||
<memberdecl>
|
||||
<nestedclasses visible="yes" title=""/>
|
||||
<publictypes title=""/>
|
||||
<services title=""/>
|
||||
<interfaces title=""/>
|
||||
<publicslots title=""/>
|
||||
<signals title=""/>
|
||||
<publicmethods title=""/>
|
||||
<publicstaticmethods title=""/>
|
||||
<publicattributes title=""/>
|
||||
<publicstaticattributes title=""/>
|
||||
<protectedtypes title=""/>
|
||||
<protectedslots title=""/>
|
||||
<protectedmethods title=""/>
|
||||
<protectedstaticmethods title=""/>
|
||||
<protectedattributes title=""/>
|
||||
<protectedstaticattributes title=""/>
|
||||
<packagetypes title=""/>
|
||||
<packagemethods title=""/>
|
||||
<packagestaticmethods title=""/>
|
||||
<packageattributes title=""/>
|
||||
<packagestaticattributes title=""/>
|
||||
<properties title=""/>
|
||||
<events title=""/>
|
||||
<privatetypes title=""/>
|
||||
<privateslots title=""/>
|
||||
<privatemethods title=""/>
|
||||
<privatestaticmethods title=""/>
|
||||
<privateattributes title=""/>
|
||||
<privatestaticattributes title=""/>
|
||||
<friends title=""/>
|
||||
<related title="" subtitle=""/>
|
||||
<membergroups visible="yes"/>
|
||||
</memberdecl>
|
||||
<detaileddescription title=""/>
|
||||
<memberdef>
|
||||
<inlineclasses title=""/>
|
||||
<typedefs title=""/>
|
||||
<enums title=""/>
|
||||
<services title=""/>
|
||||
<interfaces title=""/>
|
||||
<constructors title=""/>
|
||||
<functions title=""/>
|
||||
<related title=""/>
|
||||
<variables title=""/>
|
||||
<properties title=""/>
|
||||
<events title=""/>
|
||||
</memberdef>
|
||||
<allmemberslink visible="yes"/>
|
||||
<usedfiles visible="$SHOW_USED_FILES"/>
|
||||
<authorsection visible="yes"/>
|
||||
</class>
|
||||
|
||||
<!-- Layout definition for a namespace page -->
|
||||
<namespace>
|
||||
<briefdescription visible="yes"/>
|
||||
<memberdecl>
|
||||
<nestednamespaces visible="yes" title=""/>
|
||||
<constantgroups visible="yes" title=""/>
|
||||
<interfaces visible="yes" title=""/>
|
||||
<classes visible="yes" title=""/>
|
||||
<structs visible="yes" title=""/>
|
||||
<exceptions visible="yes" title=""/>
|
||||
<typedefs title=""/>
|
||||
<sequences title=""/>
|
||||
<dictionaries title=""/>
|
||||
<enums title=""/>
|
||||
<functions title=""/>
|
||||
<variables title=""/>
|
||||
<membergroups visible="yes"/>
|
||||
</memberdecl>
|
||||
<detaileddescription title=""/>
|
||||
<memberdef>
|
||||
<inlineclasses title=""/>
|
||||
<typedefs title=""/>
|
||||
<sequences title=""/>
|
||||
<dictionaries title=""/>
|
||||
<enums title=""/>
|
||||
<functions title=""/>
|
||||
<variables title=""/>
|
||||
</memberdef>
|
||||
<authorsection visible="yes"/>
|
||||
</namespace>
|
||||
|
||||
<!-- Layout definition for a file page -->
|
||||
<file>
|
||||
<briefdescription visible="yes"/>
|
||||
<includes visible="$SHOW_INCLUDE_FILES"/>
|
||||
<includegraph visible="$INCLUDE_GRAPH"/>
|
||||
<includedbygraph visible="$INCLUDED_BY_GRAPH"/>
|
||||
<sourcelink visible="yes"/>
|
||||
<memberdecl>
|
||||
<interfaces visible="yes" title=""/>
|
||||
<classes visible="yes" title=""/>
|
||||
<structs visible="yes" title=""/>
|
||||
<exceptions visible="yes" title=""/>
|
||||
<namespaces visible="yes" title=""/>
|
||||
<constantgroups visible="yes" title=""/>
|
||||
<defines title=""/>
|
||||
<typedefs title=""/>
|
||||
<sequences title=""/>
|
||||
<dictionaries title=""/>
|
||||
<enums title=""/>
|
||||
<functions title=""/>
|
||||
<variables title=""/>
|
||||
<membergroups visible="yes"/>
|
||||
</memberdecl>
|
||||
<detaileddescription title=""/>
|
||||
<memberdef>
|
||||
<inlineclasses title=""/>
|
||||
<defines title=""/>
|
||||
<typedefs title=""/>
|
||||
<sequences title=""/>
|
||||
<dictionaries title=""/>
|
||||
<enums title=""/>
|
||||
<functions title=""/>
|
||||
<variables title=""/>
|
||||
</memberdef>
|
||||
<authorsection/>
|
||||
</file>
|
||||
|
||||
<!-- Layout definition for a group page -->
|
||||
<group>
|
||||
<briefdescription visible="yes"/>
|
||||
<groupgraph visible="$GROUP_GRAPHS"/>
|
||||
<memberdecl>
|
||||
<nestedgroups visible="yes" title=""/>
|
||||
<dirs visible="yes" title=""/>
|
||||
<files visible="yes" title=""/>
|
||||
<namespaces visible="yes" title=""/>
|
||||
<classes visible="yes" title=""/>
|
||||
<defines title=""/>
|
||||
<typedefs title=""/>
|
||||
<sequences title=""/>
|
||||
<dictionaries title=""/>
|
||||
<enums title=""/>
|
||||
<enumvalues title=""/>
|
||||
<functions title=""/>
|
||||
<variables title=""/>
|
||||
<signals title=""/>
|
||||
<publicslots title=""/>
|
||||
<protectedslots title=""/>
|
||||
<privateslots title=""/>
|
||||
<events title=""/>
|
||||
<properties title=""/>
|
||||
<friends title=""/>
|
||||
<membergroups visible="yes"/>
|
||||
</memberdecl>
|
||||
<detaileddescription title=""/>
|
||||
<memberdef>
|
||||
<pagedocs/>
|
||||
<inlineclasses title=""/>
|
||||
<defines title=""/>
|
||||
<typedefs title=""/>
|
||||
<sequences title=""/>
|
||||
<dictionaries title=""/>
|
||||
<enums title=""/>
|
||||
<enumvalues title=""/>
|
||||
<functions title=""/>
|
||||
<variables title=""/>
|
||||
<signals title=""/>
|
||||
<publicslots title=""/>
|
||||
<protectedslots title=""/>
|
||||
<privateslots title=""/>
|
||||
<events title=""/>
|
||||
<properties title=""/>
|
||||
<friends title=""/>
|
||||
</memberdef>
|
||||
<authorsection visible="yes"/>
|
||||
</group>
|
||||
|
||||
<!-- Layout definition for a directory page -->
|
||||
<directory>
|
||||
<briefdescription visible="yes"/>
|
||||
<directorygraph visible="yes"/>
|
||||
<memberdecl>
|
||||
<dirs visible="yes"/>
|
||||
<files visible="yes"/>
|
||||
</memberdecl>
|
||||
<detaileddescription title=""/>
|
||||
</directory>
|
||||
</doxygenlayout>
|
||||
@ -0,0 +1,83 @@
|
||||
/**
|
||||
@mainpage Overview
|
||||
@anchor defender
|
||||
@brief AWS IoT Device Defender Client Library
|
||||
|
||||
> AWS IoT Device Defender is a security service that allows you to audit the configuration of your devices, monitor connected devices to detect abnormal behavior, and mitigate security risks. It gives you the ability to enforce consistent security policies across your AWS IoT device fleet and respond quickly when devices are compromised.
|
||||
<span style="float:right;margin-right:4em"> — <i>Description of Device Defender from AWS IoT documentation [https://docs.aws.amazon.com/iot/latest/developerguide/device-defender.html](https://docs.aws.amazon.com/iot/latest/developerguide/device-defender.html)</i></span><br>
|
||||
|
||||
AWS IoT Device Defender lets you continuously monitor security metrics from devices for deviations from what you have defined as appropriate behavior for each device. If something doesn’t look right, AWS IoT Device Defender sends out an alert so you can take action to remediate the issue.
|
||||
|
||||
The AWS IoT Device Defender Client Library provides a convenience API for interacting with AWS IoT Device Defender service. This library is independent of the MQTT library. Applications can use this library to assemble and parse the Device Defender MQTT topics, then use any MQTT library to publish/subscribe to those topics. Features of this library include:
|
||||
- It is stateless. It does not use any global/static memory.
|
||||
- It depends on the standard C library only.
|
||||
|
||||
@section defender_memory_requirements Memory Requirements
|
||||
@brief Memory requirements of the AWS IoT Device Defender Client Library.
|
||||
|
||||
@include{doc} size_table.md
|
||||
*/
|
||||
|
||||
/**
|
||||
@page defender_design Design
|
||||
AWS IoT Device Defender Client Library Design
|
||||
|
||||
The AWS IoT Device Defender Client Library provides macros and functions to assemble and parse MQTT topic strings reserved for the Device Defender. Applications can use this library in conjunction with any MQTT library to interact with the AWS IoT Device Defender service.
|
||||
|
||||
The diagram below demonstrates how an application uses the Device Defender Client Library, an MQTT library, and a JSON library to interact with the AWS IoT Device Defender service.
|
||||
|
||||
\image html defender_design_operations.png "Device Defender Client Library Demo Operation Diagram" width=1000px
|
||||
*/
|
||||
|
||||
/**
|
||||
@page defender_config Configurations
|
||||
@brief Configurations of the AWS IoT Device Defender Client Library.
|
||||
<!-- @par configpagestyle allows the @section titles to be styled according to style.css -->
|
||||
@par configpagestyle
|
||||
|
||||
Configuration settings are C pre-processor constants. They can be set with a `\#define` in the config file (`defender_config.h`) or by using a compiler option such as -D in gcc.
|
||||
|
||||
@section DEFENDER_DO_NOT_USE_CUSTOM_CONFIG
|
||||
@copydoc DEFENDER_DO_NOT_USE_CUSTOM_CONFIG
|
||||
|
||||
@section DEFENDER_USE_LONG_KEYS
|
||||
@copydoc DEFENDER_USE_LONG_KEYS
|
||||
|
||||
@section defender_logerror LogError
|
||||
@copydoc LogError
|
||||
|
||||
@section defender_logwarn LogWarn
|
||||
@copydoc LogWarn
|
||||
|
||||
@section defender_loginfo LogInfo
|
||||
@copydoc LogInfo
|
||||
|
||||
@section defender_logdebug LogDebug
|
||||
@copydoc LogDebug
|
||||
*/
|
||||
|
||||
/**
|
||||
@page defender_functions Functions
|
||||
@brief Primary functions of the AWS IoT Device Defender Client Library:<br><br>
|
||||
@subpage defender_gettopic_function <br>
|
||||
@subpage defender_matchtopic_function <br>
|
||||
|
||||
@page defender_gettopic_function Defender_GetTopic
|
||||
@snippet defender.h declare_defender_gettopic
|
||||
@copydoc Defender_GetTopic
|
||||
|
||||
@page defender_matchtopic_function Defender_MatchTopic
|
||||
@snippet defender.h declare_defender_matchtopic
|
||||
@copydoc Defender_MatchTopic
|
||||
*/
|
||||
|
||||
<!-- We do not use doxygen ALIASes here because there have been issues in the past versions with "^^" newlines within the alias definition. -->
|
||||
/**
|
||||
@defgroup defender_enum_types Enumerated Types
|
||||
@brief Enumerated types of the AWS IoT Device Defender Client Library
|
||||
*/
|
||||
|
||||
/**
|
||||
@defgroup defender_constants Constants
|
||||
@brief Constants defined in the AWS IoT Device Defender Client Library
|
||||
*/
|
||||
@ -0,0 +1,22 @@
|
||||
/**
|
||||
@page defender_porting Porting Guide
|
||||
@brief Guide for porting the AWS IoT Device Defender Client Library to a new platform.
|
||||
|
||||
@section defender_porting_config Configuration Macros
|
||||
@brief Configuration macros that can be set the config header `defender_config.h`, or passed in as compiler options.
|
||||
|
||||
The following optional logging macros are used throughout the library:
|
||||
- @ref LogError
|
||||
- @ref LogWarn
|
||||
- @ref LogInfo
|
||||
- @ref LogDebug
|
||||
|
||||
@see [Configurations](@ref defender_config) for more information.
|
||||
|
||||
@note Regardless of whether the above macros are defined in
|
||||
`defender_config.h` or passed as compiler options, by default the
|
||||
`defender_config.h` file is needed to build the AWS IoT Device Defender Client
|
||||
Library. To disable this requirement and build the library with default
|
||||
configuration values, provide `DEFENDER_DO_NOT_USE_CUSTOM_CONFIG` as a compile
|
||||
time preprocessor macro.
|
||||
*/
|
||||
@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Stylesheet for Doxygen HTML output.
|
||||
*
|
||||
* This file defines styles for custom elements in the header/footer and
|
||||
* overrides some of the default Doxygen styles.
|
||||
*
|
||||
* Styles in this file do not affect the treeview sidebar.
|
||||
*/
|
||||
|
||||
/* Set the margins to place a small amount of whitespace on the left and right
|
||||
* side of the page. */
|
||||
div.contents {
|
||||
margin-left:4em;
|
||||
margin-right:4em;
|
||||
}
|
||||
|
||||
/* Justify text in paragraphs. */
|
||||
p {
|
||||
text-align: justify;
|
||||
}
|
||||
|
||||
/* Style of section headings. */
|
||||
h1 {
|
||||
border-bottom: 1px solid #879ECB;
|
||||
color: #354C7B;
|
||||
font-size: 160%;
|
||||
font-weight: normal;
|
||||
padding-bottom: 4px;
|
||||
padding-top: 8px;
|
||||
}
|
||||
|
||||
/* Style of subsection headings. */
|
||||
h2:not(.memtitle):not(.groupheader) {
|
||||
font-size: 125%;
|
||||
margin-bottom: 0px;
|
||||
margin-top: 16px;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
/* Style of paragraphs immediately after subsection headings. */
|
||||
h2 + p {
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
/* Style of subsection headings. */
|
||||
h3 {
|
||||
font-size: 100%;
|
||||
margin-bottom: 0px;
|
||||
margin-left: 2em;
|
||||
margin-right: 2em;
|
||||
}
|
||||
|
||||
/* Style of paragraphs immediately after subsubsection headings. */
|
||||
h3 + p {
|
||||
margin-top: 0px;
|
||||
margin-left: 2em;
|
||||
margin-right: 2em;
|
||||
}
|
||||
|
||||
/* Style of the prefix "AWS IoT Device SDK C" that appears in the header. */
|
||||
#csdkprefix {
|
||||
color: #757575;
|
||||
}
|
||||
|
||||
/* Style of the "Return to main page" link that appears in the header. */
|
||||
#returntomain {
|
||||
padding: 0.5em;
|
||||
}
|
||||
|
||||
/* Style of the dividers on Configuration Settings pages. */
|
||||
div.configpagedivider {
|
||||
margin-left: 0px !important;
|
||||
margin-right: 0px !important;
|
||||
margin-top: 20px !important;
|
||||
}
|
||||
|
||||
/* Style of configuration setting names. */
|
||||
dl.section.user ~ h1 {
|
||||
border-bottom: none;
|
||||
color: #000000;
|
||||
font-family: monospace, fixed;
|
||||
font-size: 16px;
|
||||
margin-bottom: 0px;
|
||||
margin-left: 2em;
|
||||
margin-top: 1.5em;
|
||||
}
|
||||
|
||||
/* Style of paragraphs on a configuration settings page. */
|
||||
dl.section.user ~ * {
|
||||
margin-bottom: 10px;
|
||||
margin-left: 4em;
|
||||
margin-right: 4em;
|
||||
margin-top: 0px;
|
||||
}
|
||||
|
||||
/* Hide the configuration setting marker. */
|
||||
dl.section.user {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Overrides for code fragments and lines. */
|
||||
div.fragment {
|
||||
background: #ffffff;
|
||||
border: none;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
div.line {
|
||||
color: #3a3a3a;
|
||||
}
|
||||
|
||||
/* Overrides for code syntax highlighting colors. */
|
||||
span.comment {
|
||||
color: #008000;
|
||||
}
|
||||
|
||||
span.keyword, span.keywordtype, span.keywordflow {
|
||||
color: #0000ff;
|
||||
}
|
||||
|
||||
span.preprocessor {
|
||||
color: #50015a;
|
||||
}
|
||||
|
||||
span.stringliteral, span.charliteral {
|
||||
color: #800c0c;
|
||||
}
|
||||
|
||||
a.code, a.code:visited, a.line, a.line:visited {
|
||||
color: #496194;
|
||||
}
|
||||
@ -0,0 +1,66 @@
|
||||
@startuml
|
||||
skinparam dpi 300
|
||||
skinparam classFontSize 8
|
||||
skinparam classFontName Helvetica
|
||||
autonumber
|
||||
|
||||
participant "User Application" as App
|
||||
participant "Defender Library" as Defender
|
||||
participant "MQTT Client" as MQTT
|
||||
participant "TCP Stack" as TCP
|
||||
participant "JSON Library" as JSON
|
||||
|
||||
activate App
|
||||
App -> Defender : Generate Accepted and Rejected Topic Strings
|
||||
|
||||
activate Defender
|
||||
Defender -> App : Accepted and Rejected Topic Strings
|
||||
deactivate Defender
|
||||
|
||||
App -> MQTT : Subscribe to Accepted and Rejected Topics
|
||||
|
||||
activate MQTT
|
||||
MQTT -> App : Subscription Successful
|
||||
deactivate MQTT
|
||||
|
||||
loop Forever
|
||||
App -> TCP : Get Metrics
|
||||
|
||||
activate TCP
|
||||
TCP -> App : Metrics
|
||||
deactivate TCP
|
||||
|
||||
App -> JSON : Generate Report
|
||||
|
||||
activate JSON
|
||||
JSON -> App : Report
|
||||
deactivate JSON
|
||||
|
||||
App -> Defender : Generate Publish Topic String
|
||||
|
||||
activate Defender
|
||||
Defender -> App : Publish Topic String
|
||||
deactivate Defender
|
||||
|
||||
App -> MQTT : Publish Report
|
||||
|
||||
activate MQTT
|
||||
MQTT -> App : Published
|
||||
MQTT -> App : Incoming Publish Message Received
|
||||
deactivate MQTT
|
||||
|
||||
App -> Defender : Is this a Defender Message?
|
||||
|
||||
activate Defender
|
||||
Defender -> App : Yes/No
|
||||
note right
|
||||
The Defender library also tells if the report was accepted by
|
||||
|
||||
the service or not.
|
||||
endnote
|
||||
deactivate Defender
|
||||
end
|
||||
|
||||
deactivate App
|
||||
|
||||
@enduml
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 255 KiB |
100
kernel/FreeRTOS-Plus/Source/AWS/device-defender/lexicon.txt
Normal file
100
kernel/FreeRTOS-Plus/Source/AWS/device-defender/lexicon.txt
Normal file
@ -0,0 +1,100 @@
|
||||
addr
|
||||
api
|
||||
apis
|
||||
aws
|
||||
bi
|
||||
bo
|
||||
br
|
||||
bufferlength
|
||||
cbor
|
||||
colspan
|
||||
com
|
||||
cond
|
||||
config
|
||||
configpagestyle
|
||||
const
|
||||
copydoc
|
||||
css
|
||||
defenderapi
|
||||
defenderbadparameter
|
||||
defenderbuffertoosmall
|
||||
defendercborreportaccepted
|
||||
defendercborreportpublish
|
||||
defendercborreportrejected
|
||||
defendererror
|
||||
defenderinvalidtopic
|
||||
defenderjsonreportaccepted
|
||||
defenderjsonreportpublish
|
||||
defenderjsonreportrejected
|
||||
defendernomatch
|
||||
defenderstatus
|
||||
defendersuccess
|
||||
defendertopic
|
||||
defgroup
|
||||
developerguide
|
||||
doesn
|
||||
doxygen
|
||||
endcode
|
||||
endcond
|
||||
endif
|
||||
enum
|
||||
gcc
|
||||
getdeviceserialnumber
|
||||
gettopic
|
||||
github
|
||||
hed
|
||||
html
|
||||
https
|
||||
inc
|
||||
ingroup
|
||||
iot
|
||||
iso
|
||||
json
|
||||
logdebug
|
||||
logerror
|
||||
loginfo
|
||||
logwarn
|
||||
mainpage
|
||||
matchapi
|
||||
matchtopic
|
||||
md
|
||||
mdash
|
||||
memcpy
|
||||
misra
|
||||
mit
|
||||
mqtt
|
||||
noninfringement
|
||||
ns
|
||||
os
|
||||
param
|
||||
pbuffer
|
||||
png
|
||||
po
|
||||
posix
|
||||
poutapi
|
||||
poutlength
|
||||
poutthingnamelength
|
||||
ppoutthingname
|
||||
pre
|
||||
premainingtopic
|
||||
pthingname
|
||||
ptopic
|
||||
remainingtopiclength
|
||||
remediate
|
||||
rm
|
||||
sdk
|
||||
spdx
|
||||
strlen
|
||||
sublicense
|
||||
tcp
|
||||
td
|
||||
thingname
|
||||
thingnamelength
|
||||
toolchain
|
||||
topicbuffer
|
||||
topiclength
|
||||
tr
|
||||
udp
|
||||
uint
|
||||
utest
|
||||
xa
|
||||
@ -0,0 +1,5 @@
|
||||
name : "Device-Defender-for-AWS-IoT-embedded-sdk"
|
||||
version: "v1.3.0"
|
||||
description: |
|
||||
"Client library for using the AWS IoT Device Defender service on embedded devices.\n"
|
||||
license: "MIT"
|
||||
29
kernel/FreeRTOS-Plus/Source/AWS/device-defender/sbom.spdx
Normal file
29
kernel/FreeRTOS-Plus/Source/AWS/device-defender/sbom.spdx
Normal file
@ -0,0 +1,29 @@
|
||||
SPDXVersion: SPDX-2.2
|
||||
DataLicense: CC0-1.0
|
||||
SPDXID: SPDXRef-DOCUMENT
|
||||
DocumentName: Device-Defender-for-AWS-IoT-embedded-sdk
|
||||
DocumentNamespace: https://github.com/FreeRTOS/Device-Defender-for-AWS-IoT-embedded-sdk/blob/v1.3.0/sbom.spdx
|
||||
Creator: Amazon Web Services
|
||||
Created: 2022-10-14T16:05:06Z
|
||||
CreatorComment: NOASSERTION
|
||||
DocumentComment: NOASSERTION
|
||||
|
||||
PackageName: Device-Defender-for-AWS-IoT-embedded-sdk
|
||||
SPDXID: SPDXRef-Package-Device-Defender-for-AWS-IoT-embedded-sdk
|
||||
PackageVersion: v1.3.0
|
||||
PackageDownloadLocation: https://github.com/aws/Device-Defender-for-AWS-IoT-embedded-sdk/tree/v1.3.0
|
||||
PackageLicenseConcluded: MIT
|
||||
FilesAnalyzed: True
|
||||
PackageVerificationCode: 4d479d686c4b6b508c16b39fd8aff8cb7636f78c
|
||||
PackageCopyrightText: NOASSERTION
|
||||
PackageSummary: NOASSERTION
|
||||
PackageDescription: "Client library for using the AWS IoT Device Defender service on embedded devices.\n"
|
||||
|
||||
|
||||
FileName: ./defender.c
|
||||
SPDXID: SPDXRef-File-defender.c
|
||||
FileChecksum: SHA1: 900abb6b6d98d5fb419800481739c448cffc90a8
|
||||
LicenseConcluded: MIT
|
||||
FileCopyrightText: NOASSERTION
|
||||
FileComment: NOASSERTION
|
||||
|
||||
@ -0,0 +1,573 @@
|
||||
/*
|
||||
* AWS IoT Device Defender Client v1.3.0
|
||||
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file defender.c
|
||||
* @brief Implementation of the AWS IoT Device Defender Client Library.
|
||||
*/
|
||||
|
||||
/* Standard includes. */
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
/* Defender API include. */
|
||||
#include "defender.h"
|
||||
|
||||
/**
|
||||
* @brief Get the topic length for a given defender API.
|
||||
*
|
||||
* @param[in] thingNameLength The length of the thing name as registered with AWS IoT.
|
||||
* @param[in] api The defender API value.
|
||||
*
|
||||
* @return The topic length for the given defender API.
|
||||
*/
|
||||
static uint16_t getTopicLength( uint16_t thingNameLength,
|
||||
DefenderTopic_t api );
|
||||
|
||||
/**
|
||||
* @brief Write the format and suffix part for the given defender API to the buffer.
|
||||
*
|
||||
* Format: json or cbor.
|
||||
* Suffix: /accepted or /rejected or empty.
|
||||
*
|
||||
* @param[in] pBuffer The buffer to write the format and suffix part into.
|
||||
* @param[in] api The defender API value.
|
||||
*
|
||||
* @note This function assumes that the buffer is large enough to hold the
|
||||
* value.
|
||||
*/
|
||||
static void writeFormatAndSuffix( char * pBuffer,
|
||||
DefenderTopic_t api );
|
||||
|
||||
/**
|
||||
* @brief Check if the unparsed topic so far starts with the defender prefix.
|
||||
*
|
||||
* The defender prefix is "$aws/things/".
|
||||
*
|
||||
* @param[in] pRemainingTopic Starting location of the unparsed topic.
|
||||
* @param[in] remainingTopicLength The length of the unparsed topic.
|
||||
*
|
||||
* @return #DefenderSuccess if the unparsed topic starts with the defender
|
||||
* prefix; #DefenderNoMatch otherwise.
|
||||
*/
|
||||
static DefenderStatus_t matchPrefix( const char * pRemainingTopic,
|
||||
uint16_t remainingTopicLength );
|
||||
|
||||
/**
|
||||
* @brief Extract the length of thing name in the unparsed topic so far.
|
||||
*
|
||||
* The end of thing name is marked by a forward slash. A zero length thing name
|
||||
* is not valid.
|
||||
*
|
||||
* This function extracts the same thing name from the following topic strings:
|
||||
* - $aws/things/THING_NAME/defender/metrics/json
|
||||
* - $aws/things/THING_NAME
|
||||
* The second topic is not a valid defender topic and the matching will fail
|
||||
* when we try to match the bridge part.
|
||||
*
|
||||
* @param[in] pRemainingTopic Starting location of the unparsed topic.
|
||||
* @param[in] remainingTopicLength The length of the unparsed topic.
|
||||
* @param[out] pOutThingNameLength The length of the thing name in the topic string.
|
||||
*
|
||||
* @return #DefenderSuccess if a valid thing name is found; #DefenderNoMatch
|
||||
* otherwise.
|
||||
*/
|
||||
static DefenderStatus_t extractThingNameLength( const char * pRemainingTopic,
|
||||
uint16_t remainingTopicLength,
|
||||
uint16_t * pOutThingNameLength );
|
||||
|
||||
/**
|
||||
* @brief Check if the unparsed topic so far starts with the defender bridge.
|
||||
*
|
||||
* The defender bridge is "/defender/metrics/".
|
||||
*
|
||||
* @param[in] pRemainingTopic Starting location of the unparsed topic.
|
||||
* @param[in] remainingTopicLength The length of the unparsed topic.
|
||||
*
|
||||
* @return #DefenderSuccess if the unparsed topic starts with the defender
|
||||
* bridge; #DefenderNoMatch otherwise.
|
||||
*/
|
||||
static DefenderStatus_t matchBridge( const char * pRemainingTopic,
|
||||
uint16_t remainingTopicLength );
|
||||
|
||||
/**
|
||||
* @brief Check if the unparsed topic so far exactly matches one of the defender
|
||||
* api topics.
|
||||
*
|
||||
* The defender api topics are the following:
|
||||
* - json
|
||||
* - json/accepted
|
||||
* - json/rejected
|
||||
* - cbor
|
||||
* - cbor/accepted
|
||||
* - cbor/rejected
|
||||
*
|
||||
* The function also outputs the defender API value if a match is found.
|
||||
*
|
||||
* @param[in] pRemainingTopic Starting location of the unparsed topic.
|
||||
* @param[in] remainingTopicLength The length of the unparsed topic.
|
||||
* @param[out] pOutApi The defender topic API value.
|
||||
*
|
||||
* @return #DefenderSuccess if the unparsed topic exactly matches one of the
|
||||
* defender api topics; #DefenderNoMatch otherwise.
|
||||
*/
|
||||
static DefenderStatus_t matchApi( const char * pRemainingTopic,
|
||||
uint16_t remainingTopicLength,
|
||||
DefenderTopic_t * pOutApi );
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static uint16_t getTopicLength( uint16_t thingNameLength,
|
||||
DefenderTopic_t api )
|
||||
{
|
||||
uint16_t topicLength = 0U;
|
||||
|
||||
assert( ( thingNameLength != 0U ) && ( thingNameLength <= DEFENDER_THINGNAME_MAX_LENGTH ) );
|
||||
assert( ( api > DefenderInvalidTopic ) && ( api < DefenderMaxTopic ) );
|
||||
|
||||
switch( api )
|
||||
{
|
||||
case DefenderJsonReportPublish:
|
||||
topicLength = DEFENDER_API_LENGTH_JSON_PUBLISH( thingNameLength );
|
||||
break;
|
||||
|
||||
case DefenderJsonReportAccepted:
|
||||
topicLength = DEFENDER_API_LENGTH_JSON_ACCEPTED( thingNameLength );
|
||||
break;
|
||||
|
||||
case DefenderJsonReportRejected:
|
||||
topicLength = DEFENDER_API_LENGTH_JSON_REJECTED( thingNameLength );
|
||||
break;
|
||||
|
||||
case DefenderCborReportPublish:
|
||||
topicLength = DEFENDER_API_LENGTH_CBOR_PUBLISH( thingNameLength );
|
||||
break;
|
||||
|
||||
case DefenderCborReportAccepted:
|
||||
topicLength = DEFENDER_API_LENGTH_CBOR_ACCEPTED( thingNameLength );
|
||||
break;
|
||||
|
||||
/* The default is here just to silence compiler warnings in a way which
|
||||
* does not bring coverage down. The assert at the beginning of this
|
||||
* function ensures that the only api value hitting this case can be
|
||||
* DefenderCborReportRejected. */
|
||||
case DefenderCborReportRejected:
|
||||
default:
|
||||
topicLength = DEFENDER_API_LENGTH_CBOR_REJECTED( thingNameLength );
|
||||
break;
|
||||
}
|
||||
|
||||
return topicLength;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void writeFormatAndSuffix( char * pBuffer,
|
||||
DefenderTopic_t api )
|
||||
{
|
||||
/* The following variables are to address MISRA Rule 7.4 violation of
|
||||
* passing const char * for const void * param of memcpy. */
|
||||
const char * pDefenderApiJsonFormat = DEFENDER_API_JSON_FORMAT;
|
||||
const char * pDefenderApiCborFormat = DEFENDER_API_CBOR_FORMAT;
|
||||
const char * pDefenderApiAcceptedSuffix = DEFENDER_API_ACCEPTED_SUFFIX;
|
||||
const char * pDefenderApiRejectedSuffix = DEFENDER_API_REJECTED_SUFFIX;
|
||||
|
||||
assert( pBuffer != NULL );
|
||||
assert( ( api > DefenderInvalidTopic ) && ( api < DefenderMaxTopic ) );
|
||||
|
||||
switch( api )
|
||||
{
|
||||
case DefenderJsonReportPublish:
|
||||
( void ) memcpy( ( void * ) pBuffer,
|
||||
( const void * ) pDefenderApiJsonFormat,
|
||||
( size_t ) DEFENDER_API_LENGTH_JSON_FORMAT );
|
||||
break;
|
||||
|
||||
case DefenderJsonReportAccepted:
|
||||
( void ) memcpy( ( void * ) pBuffer,
|
||||
( const void * ) pDefenderApiJsonFormat,
|
||||
( size_t ) DEFENDER_API_LENGTH_JSON_FORMAT );
|
||||
( void ) memcpy( ( void * ) &( pBuffer[ DEFENDER_API_LENGTH_JSON_FORMAT ] ),
|
||||
( const void * ) pDefenderApiAcceptedSuffix,
|
||||
( size_t ) DEFENDER_API_LENGTH_ACCEPTED_SUFFIX );
|
||||
break;
|
||||
|
||||
case DefenderJsonReportRejected:
|
||||
( void ) memcpy( ( void * ) pBuffer,
|
||||
( const void * ) pDefenderApiJsonFormat,
|
||||
DEFENDER_API_LENGTH_JSON_FORMAT );
|
||||
( void ) memcpy( ( void * ) &( pBuffer[ DEFENDER_API_LENGTH_JSON_FORMAT ] ),
|
||||
( const void * ) pDefenderApiRejectedSuffix,
|
||||
( size_t ) DEFENDER_API_LENGTH_REJECTED_SUFFIX );
|
||||
break;
|
||||
|
||||
case DefenderCborReportPublish:
|
||||
( void ) memcpy( ( void * ) pBuffer,
|
||||
( const void * ) pDefenderApiCborFormat,
|
||||
( size_t ) DEFENDER_API_LENGTH_CBOR_FORMAT );
|
||||
break;
|
||||
|
||||
case DefenderCborReportAccepted:
|
||||
( void ) memcpy( ( void * ) pBuffer,
|
||||
( const void * ) pDefenderApiCborFormat,
|
||||
DEFENDER_API_LENGTH_CBOR_FORMAT );
|
||||
( void ) memcpy( ( void * ) &( pBuffer[ DEFENDER_API_LENGTH_CBOR_FORMAT ] ),
|
||||
( const void * ) pDefenderApiAcceptedSuffix,
|
||||
( size_t ) DEFENDER_API_LENGTH_ACCEPTED_SUFFIX );
|
||||
break;
|
||||
|
||||
/* The default is here just to silence compiler warnings in a way which
|
||||
* does not bring coverage down. The assert at the beginning of this
|
||||
* function ensures that the only api value hitting this case can be
|
||||
* DefenderCborReportRejected. */
|
||||
case DefenderCborReportRejected:
|
||||
default:
|
||||
( void ) memcpy( ( void * ) pBuffer,
|
||||
( const void * ) pDefenderApiCborFormat,
|
||||
( size_t ) DEFENDER_API_LENGTH_CBOR_FORMAT );
|
||||
( void ) memcpy( ( void * ) &( pBuffer[ DEFENDER_API_LENGTH_CBOR_FORMAT ] ),
|
||||
( const void * ) pDefenderApiRejectedSuffix,
|
||||
( size_t ) DEFENDER_API_LENGTH_REJECTED_SUFFIX );
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static DefenderStatus_t matchPrefix( const char * pRemainingTopic,
|
||||
uint16_t remainingTopicLength )
|
||||
{
|
||||
DefenderStatus_t ret = DefenderNoMatch;
|
||||
|
||||
assert( pRemainingTopic != NULL );
|
||||
|
||||
if( remainingTopicLength >= DEFENDER_API_LENGTH_PREFIX )
|
||||
{
|
||||
if( strncmp( pRemainingTopic,
|
||||
DEFENDER_API_PREFIX,
|
||||
( size_t ) DEFENDER_API_LENGTH_PREFIX ) == 0 )
|
||||
{
|
||||
ret = DefenderSuccess;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static DefenderStatus_t extractThingNameLength( const char * pRemainingTopic,
|
||||
uint16_t remainingTopicLength,
|
||||
uint16_t * pOutThingNameLength )
|
||||
{
|
||||
DefenderStatus_t ret = DefenderNoMatch;
|
||||
uint16_t i = 0U;
|
||||
|
||||
assert( pRemainingTopic != NULL );
|
||||
assert( pOutThingNameLength != NULL );
|
||||
|
||||
/* Find the first forward slash. It marks the end of the thing name. */
|
||||
for( i = 0U; i < remainingTopicLength; i++ )
|
||||
{
|
||||
if( pRemainingTopic[ i ] == '/' )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Zero length thing name is not valid. */
|
||||
if( i > 0U )
|
||||
{
|
||||
*pOutThingNameLength = i;
|
||||
ret = DefenderSuccess;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static DefenderStatus_t matchBridge( const char * pRemainingTopic,
|
||||
uint16_t remainingTopicLength )
|
||||
{
|
||||
DefenderStatus_t ret = DefenderNoMatch;
|
||||
|
||||
assert( pRemainingTopic != NULL );
|
||||
|
||||
if( remainingTopicLength >= DEFENDER_API_LENGTH_BRIDGE )
|
||||
{
|
||||
if( strncmp( pRemainingTopic,
|
||||
DEFENDER_API_BRIDGE,
|
||||
( size_t ) DEFENDER_API_LENGTH_BRIDGE ) == 0 )
|
||||
{
|
||||
ret = DefenderSuccess;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static DefenderStatus_t matchApi( const char * pRemainingTopic,
|
||||
uint16_t remainingTopicLength,
|
||||
DefenderTopic_t * pOutApi )
|
||||
{
|
||||
DefenderStatus_t ret = DefenderNoMatch;
|
||||
uint16_t i = 0U;
|
||||
/* Table of defender APIs. */
|
||||
static const DefenderTopic_t defenderApi[] =
|
||||
{
|
||||
DefenderJsonReportPublish,
|
||||
DefenderJsonReportAccepted,
|
||||
DefenderJsonReportRejected,
|
||||
DefenderCborReportPublish,
|
||||
DefenderCborReportAccepted,
|
||||
DefenderCborReportRejected,
|
||||
};
|
||||
/* Table of topic API strings in the same order as the above defenderApi table. */
|
||||
static const char * const defenderApiTopic[] =
|
||||
{
|
||||
DEFENDER_API_JSON_FORMAT,
|
||||
DEFENDER_API_JSON_FORMAT DEFENDER_API_ACCEPTED_SUFFIX,
|
||||
DEFENDER_API_JSON_FORMAT DEFENDER_API_REJECTED_SUFFIX,
|
||||
DEFENDER_API_CBOR_FORMAT,
|
||||
DEFENDER_API_CBOR_FORMAT DEFENDER_API_ACCEPTED_SUFFIX,
|
||||
DEFENDER_API_CBOR_FORMAT DEFENDER_API_REJECTED_SUFFIX,
|
||||
};
|
||||
/* Table of topic API string lengths in the same order as the above defenderApi table. */
|
||||
static const uint16_t defenderApiTopicLength[] =
|
||||
{
|
||||
DEFENDER_API_LENGTH_JSON_FORMAT,
|
||||
DEFENDER_API_LENGTH_JSON_FORMAT + DEFENDER_API_LENGTH_ACCEPTED_SUFFIX,
|
||||
DEFENDER_API_LENGTH_JSON_FORMAT + DEFENDER_API_LENGTH_REJECTED_SUFFIX,
|
||||
DEFENDER_API_LENGTH_CBOR_FORMAT,
|
||||
DEFENDER_API_LENGTH_CBOR_FORMAT + DEFENDER_API_LENGTH_ACCEPTED_SUFFIX,
|
||||
DEFENDER_API_LENGTH_CBOR_FORMAT + DEFENDER_API_LENGTH_REJECTED_SUFFIX,
|
||||
};
|
||||
|
||||
for( i = 0U; i < sizeof( defenderApi ) / sizeof( defenderApi[ 0 ] ); i++ )
|
||||
{
|
||||
if( ( remainingTopicLength == defenderApiTopicLength[ i ] ) &&
|
||||
( strncmp( pRemainingTopic,
|
||||
defenderApiTopic[ i ],
|
||||
( size_t ) defenderApiTopicLength[ i ] ) == 0 ) )
|
||||
{
|
||||
*pOutApi = defenderApi[ i ];
|
||||
ret = DefenderSuccess;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
DefenderStatus_t Defender_GetTopic( char * pBuffer,
|
||||
uint16_t bufferLength,
|
||||
const char * pThingName,
|
||||
uint16_t thingNameLength,
|
||||
DefenderTopic_t api,
|
||||
uint16_t * pOutLength )
|
||||
{
|
||||
DefenderStatus_t ret = DefenderSuccess;
|
||||
uint16_t topicLength = 0U, offset = 0U;
|
||||
|
||||
/* The following variables are to address MISRA Rule 7.4 violation of
|
||||
* passing const char * for const void * param of memcpy. */
|
||||
const char * pDefenderApiPrefix = DEFENDER_API_PREFIX;
|
||||
const char * pDefenderApiBridge = DEFENDER_API_BRIDGE;
|
||||
|
||||
if( ( pBuffer == NULL ) ||
|
||||
( pThingName == NULL ) ||
|
||||
( thingNameLength == 0U ) || ( thingNameLength > DEFENDER_THINGNAME_MAX_LENGTH ) ||
|
||||
( api <= DefenderInvalidTopic ) || ( api >= DefenderMaxTopic ) ||
|
||||
( pOutLength == NULL ) )
|
||||
{
|
||||
ret = DefenderBadParameter;
|
||||
|
||||
LogError( ( "Invalid input parameter. pBuffer: %p, bufferLength: %u, "
|
||||
"pThingName: %p, thingNameLength: %u, api: %d, pOutLength: %p.",
|
||||
( const void * ) pBuffer,
|
||||
( unsigned int ) bufferLength,
|
||||
( const void * ) pThingName,
|
||||
( unsigned int ) thingNameLength,
|
||||
api,
|
||||
( void * ) pOutLength ) );
|
||||
}
|
||||
|
||||
if( ret == DefenderSuccess )
|
||||
{
|
||||
topicLength = getTopicLength( thingNameLength, api );
|
||||
|
||||
if( bufferLength < topicLength )
|
||||
{
|
||||
ret = DefenderBufferTooSmall;
|
||||
|
||||
LogError( ( "The buffer is too small to hold the topic string. "
|
||||
"Provided buffer size: %u, Required buffer size: %u.",
|
||||
( unsigned int ) bufferLength,
|
||||
( unsigned int ) topicLength ) );
|
||||
}
|
||||
}
|
||||
|
||||
if( ret == DefenderSuccess )
|
||||
{
|
||||
/* At this point, it is certain that we have a large enough buffer to
|
||||
* write the topic string into. */
|
||||
|
||||
/* Write prefix first. */
|
||||
( void ) memcpy( ( void * ) &( pBuffer[ offset ] ),
|
||||
( const void * ) pDefenderApiPrefix,
|
||||
( size_t ) DEFENDER_API_LENGTH_PREFIX );
|
||||
offset += DEFENDER_API_LENGTH_PREFIX;
|
||||
|
||||
/* Write thing name next. */
|
||||
( void ) memcpy( ( void * ) &( pBuffer[ offset ] ),
|
||||
( const void * ) pThingName,
|
||||
( size_t ) thingNameLength );
|
||||
offset += thingNameLength;
|
||||
|
||||
/* Write bridge next. */
|
||||
( void ) memcpy( ( void * ) &( pBuffer[ offset ] ),
|
||||
( const void * ) pDefenderApiBridge,
|
||||
( size_t ) DEFENDER_API_LENGTH_BRIDGE );
|
||||
offset += DEFENDER_API_LENGTH_BRIDGE;
|
||||
|
||||
/* Write report format and suffix. */
|
||||
writeFormatAndSuffix( &( pBuffer[ offset ] ), api );
|
||||
|
||||
*pOutLength = topicLength;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
DefenderStatus_t Defender_MatchTopic( const char * pTopic,
|
||||
uint16_t topicLength,
|
||||
DefenderTopic_t * pOutApi,
|
||||
const char ** ppOutThingName,
|
||||
uint16_t * pOutThingNameLength )
|
||||
{
|
||||
DefenderStatus_t ret = DefenderSuccess;
|
||||
uint16_t remainingTopicLength = 0U, consumedTopicLength = 0U, thingNameLength = 0U;
|
||||
|
||||
if( ( pTopic == NULL ) || ( pOutApi == NULL ) )
|
||||
{
|
||||
ret = DefenderBadParameter;
|
||||
LogError( ( "Invalid input parameter. pTopic: %p, pOutApi: %p.",
|
||||
( const void * ) pTopic,
|
||||
( void * ) pOutApi ) );
|
||||
}
|
||||
|
||||
/* Nothing is consumed yet. */
|
||||
remainingTopicLength = topicLength;
|
||||
consumedTopicLength = 0;
|
||||
|
||||
if( ret == DefenderSuccess )
|
||||
{
|
||||
ret = matchPrefix( &( pTopic[ consumedTopicLength ] ),
|
||||
remainingTopicLength );
|
||||
|
||||
if( ret == DefenderSuccess )
|
||||
{
|
||||
remainingTopicLength -= DEFENDER_API_LENGTH_PREFIX;
|
||||
consumedTopicLength += DEFENDER_API_LENGTH_PREFIX;
|
||||
}
|
||||
else
|
||||
{
|
||||
LogDebug( ( "The topic does not contain defender prefix $aws/things/." ) );
|
||||
}
|
||||
}
|
||||
|
||||
if( ret == DefenderSuccess )
|
||||
{
|
||||
ret = extractThingNameLength( &( pTopic[ consumedTopicLength ] ),
|
||||
remainingTopicLength,
|
||||
&( thingNameLength ) );
|
||||
|
||||
if( ret == DefenderSuccess )
|
||||
{
|
||||
remainingTopicLength -= thingNameLength;
|
||||
consumedTopicLength += thingNameLength;
|
||||
}
|
||||
else
|
||||
{
|
||||
LogDebug( ( "The topic does not contain a valid thing name." ) );
|
||||
}
|
||||
}
|
||||
|
||||
if( ret == DefenderSuccess )
|
||||
{
|
||||
ret = matchBridge( &( pTopic[ consumedTopicLength ] ),
|
||||
remainingTopicLength );
|
||||
|
||||
if( ret == DefenderSuccess )
|
||||
{
|
||||
remainingTopicLength -= DEFENDER_API_LENGTH_BRIDGE;
|
||||
consumedTopicLength += DEFENDER_API_LENGTH_BRIDGE;
|
||||
}
|
||||
else
|
||||
{
|
||||
LogDebug( ( "The topic does not contain the defender bridge /defender/metrics/." ) );
|
||||
}
|
||||
}
|
||||
|
||||
if( ret == DefenderSuccess )
|
||||
{
|
||||
ret = matchApi( &( pTopic[ consumedTopicLength ] ),
|
||||
remainingTopicLength,
|
||||
pOutApi );
|
||||
|
||||
if( ret != DefenderSuccess )
|
||||
{
|
||||
LogDebug( ( "The topic does not contain valid report format or suffix "
|
||||
" needed to be a valid defender topic." ) );
|
||||
}
|
||||
}
|
||||
|
||||
/* Update the out parameters for thing name and thing length location, if we
|
||||
* successfully matched the topic. */
|
||||
if( ret == DefenderSuccess )
|
||||
{
|
||||
if( ppOutThingName != NULL )
|
||||
{
|
||||
/* Thing name comes after the defender prefix. */
|
||||
*ppOutThingName = &( pTopic[ DEFENDER_API_LENGTH_PREFIX ] );
|
||||
}
|
||||
|
||||
if( pOutThingNameLength != NULL )
|
||||
{
|
||||
*pOutThingNameLength = thingNameLength;
|
||||
}
|
||||
}
|
||||
|
||||
/* Update the output parameter for API if the topic did not match. In case
|
||||
* of a match, it is updated in the matchApi function. */
|
||||
if( ret == DefenderNoMatch )
|
||||
{
|
||||
*pOutApi = DefenderInvalidTopic;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
@ -0,0 +1,805 @@
|
||||
/*
|
||||
* AWS IoT Device Defender Client v1.3.0
|
||||
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file defender.h
|
||||
* @brief Interface for the AWS IoT Device Defender Client Library.
|
||||
*/
|
||||
|
||||
#ifndef DEFENDER_H_
|
||||
#define DEFENDER_H_
|
||||
|
||||
/* Standard includes. */
|
||||
#include <stdint.h>
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/* *INDENT-ON* */
|
||||
|
||||
/* DEFENDER_DO_NOT_USE_CUSTOM_CONFIG allows building the Device Defender library
|
||||
* without a config file. If a config file is provided, DEFENDER_DO_NOT_USE_CUSTOM_CONFIG
|
||||
* macro must not be defined.
|
||||
*/
|
||||
#ifndef DEFENDER_DO_NOT_USE_CUSTOM_CONFIG
|
||||
#include "defender_config.h"
|
||||
#endif
|
||||
|
||||
/* Default config values. */
|
||||
#include "defender_config_defaults.h"
|
||||
|
||||
/**
|
||||
* @ingroup defender_enum_types
|
||||
* @brief Return codes from defender APIs.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
DefenderError = 0, /**< Generic Error. */
|
||||
DefenderSuccess, /**< Success. */
|
||||
DefenderNoMatch, /**< The provided topic does not match any defender topic. */
|
||||
DefenderBadParameter, /**< Invalid parameters were passed. */
|
||||
DefenderBufferTooSmall /**< The output buffer is too small. */
|
||||
} DefenderStatus_t;
|
||||
|
||||
/**
|
||||
* @ingroup defender_enum_types
|
||||
* @brief Topic values for subscription requests.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
DefenderInvalidTopic = -1, /**< Invalid topic. */
|
||||
DefenderJsonReportPublish, /**< Topic for publishing a JSON report. */
|
||||
DefenderJsonReportAccepted, /**< Topic for getting a JSON report accepted response. */
|
||||
DefenderJsonReportRejected, /**< Topic for getting a JSON report rejected response. */
|
||||
DefenderCborReportPublish, /**< Topic for publishing a CBOR report. */
|
||||
DefenderCborReportAccepted, /**< Topic for getting a CBOR report accepted response. */
|
||||
DefenderCborReportRejected, /**< Topic for getting a CBOR report rejected response. */
|
||||
DefenderMaxTopic
|
||||
} DefenderTopic_t;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* @brief Helper macro to calculate the length of a string literal.
|
||||
*/
|
||||
#define STRING_LITERAL_LENGTH( literal ) ( ( uint16_t ) ( sizeof( literal ) - 1U ) )
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* @ingroup defender_constants
|
||||
* @brief Maximum length of a thing's name as permitted by AWS IoT Core.
|
||||
*/
|
||||
#define DEFENDER_THINGNAME_MAX_LENGTH 128U
|
||||
|
||||
/**
|
||||
* @ingroup defender_constants
|
||||
* @brief Minimum period between 2 consecutive defender reports sent by the
|
||||
* device.
|
||||
*
|
||||
* This is as per AWS IoT Device Defender Service reference.
|
||||
*/
|
||||
#define DEFENDER_REPORT_MIN_PERIOD_SECONDS 300
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* A Defender topic has the following format:
|
||||
*
|
||||
* <Prefix><Thing Name><Bridge><Report Format><Suffix>
|
||||
*
|
||||
* Where:
|
||||
* <Prefix> = $aws/things/
|
||||
* <Thing Name> = Name of the thing.
|
||||
* <Bridge> = /defender/metrics/
|
||||
* <Report Format> = json or cbor
|
||||
* <Suffix> = /accepted or /rejected or empty
|
||||
*
|
||||
* Examples:
|
||||
* $aws/things/THING_NAME/defender/metrics/json
|
||||
* $aws/things/THING_NAME/defender/metrics/json/accepted
|
||||
* $aws/things/THING_NAME/defender/metrics/json/rejected
|
||||
* $aws/things/THING_NAME/defender/metrics/cbor
|
||||
* $aws/things/THING_NAME/defender/metrics/cbor/accepted
|
||||
* $aws/things/THING_NAME/defender/metrics/json/rejected
|
||||
*/
|
||||
|
||||
/**
|
||||
* @cond DOXYGEN_IGNORE
|
||||
* Doxygen should ignore these macros as they are private.
|
||||
*/
|
||||
|
||||
#define DEFENDER_API_PREFIX "$aws/things/"
|
||||
#define DEFENDER_API_LENGTH_PREFIX STRING_LITERAL_LENGTH( DEFENDER_API_PREFIX )
|
||||
|
||||
#define DEFENDER_API_BRIDGE "/defender/metrics/"
|
||||
#define DEFENDER_API_LENGTH_BRIDGE STRING_LITERAL_LENGTH( DEFENDER_API_BRIDGE )
|
||||
|
||||
#define DEFENDER_API_JSON_FORMAT "json"
|
||||
#define DEFENDER_API_LENGTH_JSON_FORMAT STRING_LITERAL_LENGTH( DEFENDER_API_JSON_FORMAT )
|
||||
|
||||
#define DEFENDER_API_CBOR_FORMAT "cbor"
|
||||
#define DEFENDER_API_LENGTH_CBOR_FORMAT STRING_LITERAL_LENGTH( DEFENDER_API_CBOR_FORMAT )
|
||||
|
||||
#define DEFENDER_API_ACCEPTED_SUFFIX "/accepted"
|
||||
#define DEFENDER_API_LENGTH_ACCEPTED_SUFFIX STRING_LITERAL_LENGTH( DEFENDER_API_ACCEPTED_SUFFIX )
|
||||
|
||||
#define DEFENDER_API_REJECTED_SUFFIX "/rejected"
|
||||
#define DEFENDER_API_LENGTH_REJECTED_SUFFIX STRING_LITERAL_LENGTH( DEFENDER_API_REJECTED_SUFFIX )
|
||||
|
||||
#define DEFENDER_API_NULL_SUFFIX ""
|
||||
#define DEFENDER_API_LENGTH_NULL_SUFFIX ( 0U )
|
||||
|
||||
/** @endcond */
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* @cond DOXYGEN_IGNORE
|
||||
* Doxygen should ignore this macro as it is private.
|
||||
*/
|
||||
|
||||
/* Defender API topic lengths. */
|
||||
#define DEFENDER_API_COMMON_LENGTH( thingNameLength, reportFormatLength, suffixLength ) \
|
||||
( DEFENDER_API_LENGTH_PREFIX + \
|
||||
( thingNameLength ) + \
|
||||
DEFENDER_API_LENGTH_BRIDGE + \
|
||||
( reportFormatLength ) + \
|
||||
( suffixLength ) )
|
||||
|
||||
/** @endcond */
|
||||
|
||||
/**
|
||||
* @brief Length of the topic string for publishing a JSON report.
|
||||
*
|
||||
* @param[in] thingNameLength Length of the thing name as registered with AWS IoT Core.
|
||||
*/
|
||||
#define DEFENDER_API_LENGTH_JSON_PUBLISH( thingNameLength ) \
|
||||
DEFENDER_API_COMMON_LENGTH( thingNameLength, \
|
||||
DEFENDER_API_LENGTH_JSON_FORMAT, \
|
||||
DEFENDER_API_LENGTH_NULL_SUFFIX )
|
||||
|
||||
/**
|
||||
* @brief Length of the topic string for getting a JSON report accepted response.
|
||||
*
|
||||
* @param[in] thingNameLength Length of the thing name as registered with AWS IoT Core.
|
||||
*/
|
||||
#define DEFENDER_API_LENGTH_JSON_ACCEPTED( thingNameLength ) \
|
||||
DEFENDER_API_COMMON_LENGTH( thingNameLength, \
|
||||
DEFENDER_API_LENGTH_JSON_FORMAT, \
|
||||
DEFENDER_API_LENGTH_ACCEPTED_SUFFIX )
|
||||
|
||||
/**
|
||||
* @brief Length of the topic string for getting a JSON report rejected response.
|
||||
*
|
||||
* @param[in] thingNameLength Length of the thing name as registered with AWS IoT Core.
|
||||
*/
|
||||
#define DEFENDER_API_LENGTH_JSON_REJECTED( thingNameLength ) \
|
||||
DEFENDER_API_COMMON_LENGTH( thingNameLength, \
|
||||
DEFENDER_API_LENGTH_JSON_FORMAT, \
|
||||
DEFENDER_API_LENGTH_REJECTED_SUFFIX )
|
||||
|
||||
/**
|
||||
* @brief Length of the topic string for publishing a CBOR report.
|
||||
*
|
||||
* @param[in] thingNameLength Length of the thing name as registered with AWS IoT Core.
|
||||
*/
|
||||
#define DEFENDER_API_LENGTH_CBOR_PUBLISH( thingNameLength ) \
|
||||
DEFENDER_API_COMMON_LENGTH( thingNameLength, \
|
||||
DEFENDER_API_LENGTH_CBOR_FORMAT, \
|
||||
DEFENDER_API_LENGTH_NULL_SUFFIX )
|
||||
|
||||
/**
|
||||
* @brief Length of the topic string for getting a CBOR report accepted response.
|
||||
*
|
||||
* @param[in] thingNameLength Length of the thing name. as registered with AWS IoT Core.
|
||||
*/
|
||||
#define DEFENDER_API_LENGTH_CBOR_ACCEPTED( thingNameLength ) \
|
||||
DEFENDER_API_COMMON_LENGTH( thingNameLength, \
|
||||
DEFENDER_API_LENGTH_CBOR_FORMAT, \
|
||||
DEFENDER_API_LENGTH_ACCEPTED_SUFFIX )
|
||||
|
||||
/**
|
||||
* @brief Length of the topic string for getting a CBOR report rejected response.
|
||||
*
|
||||
* @param[in] thingNameLength Length of the thing name as registered with AWS IoT Core.
|
||||
*/
|
||||
#define DEFENDER_API_LENGTH_CBOR_REJECTED( thingNameLength ) \
|
||||
DEFENDER_API_COMMON_LENGTH( thingNameLength, \
|
||||
DEFENDER_API_LENGTH_CBOR_FORMAT, \
|
||||
DEFENDER_API_LENGTH_REJECTED_SUFFIX )
|
||||
|
||||
/**
|
||||
* @brief Maximum length of the topic string for any defender operation.
|
||||
*
|
||||
* @param[in] thingNameLength Length of the thing name as registered with AWS IoT Core.
|
||||
*/
|
||||
#define DEFENDER_API_MAX_LENGTH( thingNameLength ) \
|
||||
DEFENDER_API_LENGTH_CBOR_ACCEPTED( thingNameLength )
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* @cond DOXYGEN_IGNORE
|
||||
* Doxygen should ignore this macro as it is private.
|
||||
*/
|
||||
|
||||
/* Defender API topics. */
|
||||
#define DEFENDER_API_COMMON( thingName, reportFormat, suffix ) \
|
||||
( DEFENDER_API_PREFIX \
|
||||
thingName \
|
||||
DEFENDER_API_BRIDGE \
|
||||
reportFormat \
|
||||
suffix )
|
||||
|
||||
/** @endcond */
|
||||
|
||||
/**
|
||||
* @brief Topic string for publishing a JSON report.
|
||||
*
|
||||
* This macro should be used when the thing name is known at the compile time.
|
||||
* If the thing name is not known at compile time, the #Defender_GetTopic API
|
||||
* should be used instead.
|
||||
*
|
||||
* @param thingName The thing name as registered with AWS IoT Core.
|
||||
*/
|
||||
#define DEFENDER_API_JSON_PUBLISH( thingName ) \
|
||||
DEFENDER_API_COMMON( thingName, \
|
||||
DEFENDER_API_JSON_FORMAT, \
|
||||
DEFENDER_API_NULL_SUFFIX )
|
||||
|
||||
/**
|
||||
* @brief Topic string for getting a JSON report accepted response.
|
||||
*
|
||||
* This macro should be used when the thing name is known at the compile time.
|
||||
* If the thing name is not known at compile time, the #Defender_GetTopic API
|
||||
* should be used instead.
|
||||
*
|
||||
* @param thingName The thing name as registered with AWS IoT Core.
|
||||
*/
|
||||
#define DEFENDER_API_JSON_ACCEPTED( thingName ) \
|
||||
DEFENDER_API_COMMON( thingName, \
|
||||
DEFENDER_API_JSON_FORMAT, \
|
||||
DEFENDER_API_ACCEPTED_SUFFIX )
|
||||
|
||||
/**
|
||||
* @brief Topic string for getting a JSON report rejected response.
|
||||
*
|
||||
* This macro should be used when the thing name is known at the compile time.
|
||||
* If the thing name is not known at compile time, the #Defender_GetTopic API
|
||||
* should be used instead.
|
||||
*
|
||||
* @param thingName The thing name as registered with AWS IoT Core.
|
||||
*/
|
||||
#define DEFENDER_API_JSON_REJECTED( thingName ) \
|
||||
DEFENDER_API_COMMON( thingName, \
|
||||
DEFENDER_API_JSON_FORMAT, \
|
||||
DEFENDER_API_REJECTED_SUFFIX )
|
||||
|
||||
/**
|
||||
* @brief Topic string for publishing a CBOR report.
|
||||
*
|
||||
* This macro should be used when the thing name is known at the compile time.
|
||||
* If the thing name is not known at compile time, the #Defender_GetTopic API
|
||||
* should be used instead.
|
||||
*
|
||||
* @param thingName The thing name as registered with AWS IoT Core.
|
||||
*/
|
||||
#define DEFENDER_API_CBOR_PUBLISH( thingName ) \
|
||||
DEFENDER_API_COMMON( thingName, \
|
||||
DEFENDER_API_CBOR_FORMAT, \
|
||||
DEFENDER_API_NULL_SUFFIX )
|
||||
|
||||
/**
|
||||
* @brief Topic string for getting a CBOR report accepted response.
|
||||
*
|
||||
* This macro should be used when the thing name is known at the compile time.
|
||||
* If the thing name is not known at compile time, the #Defender_GetTopic API
|
||||
* should be used instead.
|
||||
*
|
||||
* @param thingName The thing name as registered with AWS IoT Core.
|
||||
*/
|
||||
#define DEFENDER_API_CBOR_ACCEPTED( thingName ) \
|
||||
DEFENDER_API_COMMON( thingName, \
|
||||
DEFENDER_API_CBOR_FORMAT, \
|
||||
DEFENDER_API_ACCEPTED_SUFFIX )
|
||||
|
||||
/**
|
||||
* @brief Topic string for getting a CBOR report rejected response.
|
||||
*
|
||||
* This macro should be used when the thing name is known at the compile time.
|
||||
* If the thing name is not known at compile time, the #Defender_GetTopic API
|
||||
* should be used instead.
|
||||
*
|
||||
* @param thingName The thing name as registered with AWS IoT Core.
|
||||
*/
|
||||
#define DEFENDER_API_CBOR_REJECTED( thingName ) \
|
||||
DEFENDER_API_COMMON( thingName, \
|
||||
DEFENDER_API_CBOR_FORMAT, \
|
||||
DEFENDER_API_REJECTED_SUFFIX )
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* @cond DOXYGEN_IGNORE
|
||||
* Doxygen should ignore this macro as it is private.
|
||||
*/
|
||||
|
||||
/* Keys used in defender report. */
|
||||
#if ( defined( DEFENDER_USE_LONG_KEYS ) && ( DEFENDER_USE_LONG_KEYS == 1 ) )
|
||||
#define DEFENDER_REPORT_SELECT_KEY( longKey, shortKey ) longKey
|
||||
#else
|
||||
#define DEFENDER_REPORT_SELECT_KEY( longKey, shortKey ) shortKey
|
||||
#endif
|
||||
|
||||
/** @endcond */
|
||||
|
||||
/**
|
||||
* @ingroup defender_constants
|
||||
* @brief "header" key in the defender report.
|
||||
*/
|
||||
#define DEFENDER_REPORT_HEADER_KEY DEFENDER_REPORT_SELECT_KEY( "header", "hed" )
|
||||
|
||||
/**
|
||||
* @ingroup defender_constants
|
||||
* @brief Length of the "header" key in the defender report.
|
||||
*/
|
||||
#define DEFENDER_REPORT_LENGTH_HEADER_KEY STRING_LITERAL_LENGTH( DEFENDER_REPORT_HEADER_KEY )
|
||||
|
||||
/**
|
||||
* @ingroup defender_constants
|
||||
* @brief "metrics" key in the defender report.
|
||||
*/
|
||||
#define DEFENDER_REPORT_METRICS_KEY DEFENDER_REPORT_SELECT_KEY( "metrics", "met" )
|
||||
|
||||
/**
|
||||
* @ingroup defender_constants
|
||||
* @brief Length of the "metrics" key in the defender report.
|
||||
*/
|
||||
#define DEFENDER_REPORT_LENGTH_METRICS_KEY STRING_LITERAL_LENGTH( DEFENDER_REPORT_METRICS_KEY )
|
||||
|
||||
/**
|
||||
* @ingroup defender_constants
|
||||
* @brief "report_id" key in the defender report.
|
||||
*/
|
||||
#define DEFENDER_REPORT_ID_KEY DEFENDER_REPORT_SELECT_KEY( "report_id", "rid" )
|
||||
|
||||
/**
|
||||
* @ingroup defender_constants
|
||||
* @brief Length of the "report_id" key in the defender report.
|
||||
*/
|
||||
#define DEFENDER_REPORT_LENGTH_ID_KEY STRING_LITERAL_LENGTH( DEFENDER_REPORT_ID_KEY )
|
||||
|
||||
/**
|
||||
* @ingroup defender_constants
|
||||
* @brief "version" key in the defender report.
|
||||
*/
|
||||
#define DEFENDER_REPORT_VERSION_KEY DEFENDER_REPORT_SELECT_KEY( "version", "v" )
|
||||
|
||||
/**
|
||||
* @ingroup defender_constants
|
||||
* @brief Length of the "version" key in the defender report.
|
||||
*/
|
||||
#define DEFENDER_REPORT_LENGTH_VERSION_KEY STRING_LITERAL_LENGTH( DEFENDER_REPORT_VERSION_KEY )
|
||||
|
||||
/**
|
||||
* @ingroup defender_constants
|
||||
* @brief "tcp_connections" key in the defender report.
|
||||
*/
|
||||
#define DEFENDER_REPORT_TCP_CONNECTIONS_KEY DEFENDER_REPORT_SELECT_KEY( "tcp_connections", "tc" )
|
||||
|
||||
/**
|
||||
* @ingroup defender_constants
|
||||
* @brief Length of the "tcp_connections" key in the defender report.
|
||||
*/
|
||||
#define DEFENDER_REPORT_LENGTH_TCP_CONNECTIONS_KEY STRING_LITERAL_LENGTH( DEFENDER_REPORT_TCP_CONNECTIONS_KEY )
|
||||
|
||||
/**
|
||||
* @ingroup defender_constants
|
||||
* @brief "established_connections" key in the defender report.
|
||||
*/
|
||||
#define DEFENDER_REPORT_ESTABLISHED_CONNECTIONS_KEY DEFENDER_REPORT_SELECT_KEY( "established_connections", "ec" )
|
||||
|
||||
/**
|
||||
* @ingroup defender_constants
|
||||
* @brief Length of the "established_connections" key in the defender report.
|
||||
*/
|
||||
#define DEFENDER_REPORT_LENGTH_ESTABLISHED_CONNECTIONS_KEY STRING_LITERAL_LENGTH( DEFENDER_REPORT_ESTABLISHED_CONNECTIONS_KEY )
|
||||
|
||||
/**
|
||||
* @ingroup defender_constants
|
||||
* @brief "connections" key in the defender report.
|
||||
*/
|
||||
#define DEFENDER_REPORT_CONNECTIONS_KEY DEFENDER_REPORT_SELECT_KEY( "connections", "cs" )
|
||||
|
||||
/**
|
||||
* @ingroup defender_constants
|
||||
* @brief Length of the "connections" key in the defender report.
|
||||
*/
|
||||
#define DEFENDER_REPORT_LENGTH_CONNECTIONS_KEY STRING_LITERAL_LENGTH( DEFENDER_REPORT_CONNECTIONS_KEY )
|
||||
|
||||
/**
|
||||
* @ingroup defender_constants
|
||||
* @brief "remote_addr" key in the defender report.
|
||||
*/
|
||||
#define DEFENDER_REPORT_REMOTE_ADDR_KEY DEFENDER_REPORT_SELECT_KEY( "remote_addr", "rad" )
|
||||
|
||||
/**
|
||||
* @ingroup defender_constants
|
||||
* @brief Length of the "remote_addr" key in the defender report.
|
||||
*/
|
||||
#define DEFENDER_REPORT_LENGTH_REMOTE_ADDR_KEY STRING_LITERAL_LENGTH( DEFENDER_REPORT_REMOTE_ADDR_KEY )
|
||||
|
||||
/**
|
||||
* @ingroup defender_constants
|
||||
* @brief "local_port" key in the defender report.
|
||||
*/
|
||||
#define DEFENDER_REPORT_LOCAL_PORT_KEY DEFENDER_REPORT_SELECT_KEY( "local_port", "lp" )
|
||||
|
||||
/**
|
||||
* @ingroup defender_constants
|
||||
* @brief Length of the "local_port" key in the defender report.
|
||||
*/
|
||||
#define DEFENDER_REPORT_LENGTH_LOCAL_PORT_KEY STRING_LITERAL_LENGTH( DEFENDER_REPORT_LOCAL_PORT_KEY )
|
||||
|
||||
/**
|
||||
* @ingroup defender_constants
|
||||
* @brief "local_interface" key in the defender report.
|
||||
*/
|
||||
#define DEFENDER_REPORT_LOCAL_INTERFACE_KEY DEFENDER_REPORT_SELECT_KEY( "local_interface", "li" )
|
||||
|
||||
/**
|
||||
* @ingroup defender_constants
|
||||
* @brief Length of the "local_interface" key in the defender report.
|
||||
*/
|
||||
#define DEFENDER_REPORT_LENGTH_LOCAL_INTERFACE_KEY STRING_LITERAL_LENGTH( DEFENDER_REPORT_LOCAL_INTERFACE_KEY )
|
||||
|
||||
/**
|
||||
* @ingroup defender_constants
|
||||
* @brief "total" key in the defender report.
|
||||
*/
|
||||
#define DEFENDER_REPORT_TOTAL_KEY DEFENDER_REPORT_SELECT_KEY( "total", "t" )
|
||||
|
||||
/**
|
||||
* @ingroup defender_constants
|
||||
* @brief Length of the "total" key in the defender report.
|
||||
*/
|
||||
#define DEFENDER_REPORT_LENGTH_TOTAL_KEY STRING_LITERAL_LENGTH( DEFENDER_REPORT_TOTAL_KEY )
|
||||
|
||||
/**
|
||||
* @ingroup defender_constants
|
||||
* @brief "listening_tcp_ports" key in the defender report.
|
||||
*/
|
||||
#define DEFENDER_REPORT_TCP_LISTENING_PORTS_KEY DEFENDER_REPORT_SELECT_KEY( "listening_tcp_ports", "tp" )
|
||||
|
||||
/**
|
||||
* @ingroup defender_constants
|
||||
* @brief Length of the "listening_tcp_ports" key in the defender report.
|
||||
*/
|
||||
#define DEFENDER_REPORT_LENGTH_TCP_LISTENING_PORTS_KEY STRING_LITERAL_LENGTH( DEFENDER_REPORT_TCP_LISTENING_PORTS_KEY )
|
||||
|
||||
/**
|
||||
* @ingroup defender_constants
|
||||
* @brief "ports" key in the defender report.
|
||||
*/
|
||||
#define DEFENDER_REPORT_PORTS_KEY DEFENDER_REPORT_SELECT_KEY( "ports", "pts" )
|
||||
|
||||
/**
|
||||
* @ingroup defender_constants
|
||||
* @brief Length of the "ports" key in the defender report.
|
||||
*/
|
||||
#define DEFENDER_REPORT_LENGTH_PORTS_KEY STRING_LITERAL_LENGTH( DEFENDER_REPORT_PORTS_KEY )
|
||||
|
||||
/**
|
||||
* @ingroup defender_constants
|
||||
* @brief "port" key in the defender report.
|
||||
*/
|
||||
#define DEFENDER_REPORT_PORT_KEY DEFENDER_REPORT_SELECT_KEY( "port", "pt" )
|
||||
|
||||
/**
|
||||
* @ingroup defender_constants
|
||||
* @brief Length of the "port" key in the defender report.
|
||||
*/
|
||||
#define DEFENDER_REPORT_LENGTH_PORT_KEY STRING_LITERAL_LENGTH( DEFENDER_REPORT_PORT_KEY )
|
||||
|
||||
/**
|
||||
* @ingroup defender_constants
|
||||
* @brief "interface" key in the defender report.
|
||||
*/
|
||||
#define DEFENDER_REPORT_INTERFACE_KEY DEFENDER_REPORT_SELECT_KEY( "interface", "if" )
|
||||
|
||||
/**
|
||||
* @ingroup defender_constants
|
||||
* @brief Length of the "interface" key in the defender report.
|
||||
*/
|
||||
#define DEFENDER_REPORT_LENGTH_INTERFACE_KEY STRING_LITERAL_LENGTH( DEFENDER_REPORT_INTERFACE_KEY )
|
||||
|
||||
/**
|
||||
* @ingroup defender_constants
|
||||
* @brief "listening_udp_ports" key in the defender report.
|
||||
*/
|
||||
#define DEFENDER_REPORT_UDP_LISTENING_PORTS_KEY DEFENDER_REPORT_SELECT_KEY( "listening_udp_ports", "up" )
|
||||
|
||||
/**
|
||||
* @ingroup defender_constants
|
||||
* @brief Length of the "listening_udp_ports" key in the defender report.
|
||||
*/
|
||||
#define DEFENDER_REPORT_LENGTH_UDP_LISTENING_PORTS_KEY STRING_LITERAL_LENGTH( DEFENDER_REPORT_UDP_LISTENING_PORTS_KEY )
|
||||
|
||||
/**
|
||||
* @ingroup defender_constants
|
||||
* @brief "network_stats" key in the defender report.
|
||||
*/
|
||||
#define DEFENDER_REPORT_NETWORK_STATS_KEY DEFENDER_REPORT_SELECT_KEY( "network_stats", "ns" )
|
||||
|
||||
/**
|
||||
* @ingroup defender_constants
|
||||
* @brief Length of the "network_stats" key in the defender report.
|
||||
*/
|
||||
#define DEFENDER_REPORT_LENGTH_NETWORK_STATS_KEY STRING_LITERAL_LENGTH( DEFENDER_REPORT_NETWORK_STATS_KEY )
|
||||
|
||||
/**
|
||||
* @ingroup defender_constants
|
||||
* @brief "bytes_in" key in the defender report.
|
||||
*/
|
||||
#define DEFENDER_REPORT_BYTES_IN_KEY DEFENDER_REPORT_SELECT_KEY( "bytes_in", "bi" )
|
||||
|
||||
/**
|
||||
* @ingroup defender_constants
|
||||
* @brief Length of the "bytes_in" key in the defender report.
|
||||
*/
|
||||
#define DEFENDER_REPORT_LENGTH_BYTES_IN_KEY STRING_LITERAL_LENGTH( DEFENDER_REPORT_BYTES_IN_KEY )
|
||||
|
||||
/**
|
||||
* @ingroup defender_constants
|
||||
* @brief "bytes_out" key in the defender report.
|
||||
*/
|
||||
#define DEFENDER_REPORT_BYTES_OUT_KEY DEFENDER_REPORT_SELECT_KEY( "bytes_out", "bo" )
|
||||
|
||||
/**
|
||||
* @ingroup defender_constants
|
||||
* @brief Length of the "bytes_out" key in the defender report.
|
||||
*/
|
||||
#define DEFENDER_REPORT_LENGTH_BYTES_OUT_KEY STRING_LITERAL_LENGTH( DEFENDER_REPORT_BYTES_OUT_KEY )
|
||||
|
||||
/**
|
||||
* @ingroup defender_constants
|
||||
* @brief "packets_in" key in the defender report.
|
||||
*/
|
||||
#define DEFENDER_REPORT_PKTS_IN_KEY DEFENDER_REPORT_SELECT_KEY( "packets_in", "pi" )
|
||||
|
||||
/**
|
||||
* @ingroup defender_constants
|
||||
* @brief Length of the "packets_in" key in the defender report.
|
||||
*/
|
||||
#define DEFENDER_REPORT_LENGTH_PKTS_IN_KEY STRING_LITERAL_LENGTH( DEFENDER_REPORT_PKTS_IN_KEY )
|
||||
|
||||
/**
|
||||
* @ingroup defender_constants
|
||||
* @brief "packets_out" key in the defender report.
|
||||
*/
|
||||
#define DEFENDER_REPORT_PKTS_OUT_KEY DEFENDER_REPORT_SELECT_KEY( "packets_out", "po" )
|
||||
|
||||
/**
|
||||
* @ingroup defender_constants
|
||||
* @brief Length of the "packets_out" key in the defender report.
|
||||
*/
|
||||
#define DEFENDER_REPORT_LENGTH_PKS_OUT_KEY STRING_LITERAL_LENGTH( DEFENDER_REPORT_LENGTH_PKS_OUT_KEY )
|
||||
|
||||
/**
|
||||
* @ingroup defender_constants
|
||||
* @brief "custom_metrics" key in the defender report.
|
||||
*/
|
||||
#define DEFENDER_REPORT_CUSTOM_METRICS_KEY DEFENDER_REPORT_SELECT_KEY( "custom_metrics", "cmet" )
|
||||
|
||||
/**
|
||||
* @ingroup defender_constants
|
||||
* @brief Length of the "custom_metrics" key in the defender report.
|
||||
*/
|
||||
#define DEFENDER_REPORT_LENGTH_CUSTOM_METRICS_KEY STRING_LITERAL_LENGTH( DEFENDER_REPORT_LENGTH_CUSTOM_METRICS_KEY )
|
||||
|
||||
/**
|
||||
* @ingroup defender_constants
|
||||
* @brief "number" key in the defender report.
|
||||
*/
|
||||
#define DEFENDER_REPORT_NUMBER_KEY "number"
|
||||
|
||||
/**
|
||||
* @ingroup defender_constants
|
||||
* @brief Length of the "number" key in the defender report.
|
||||
*/
|
||||
#define DEFENDER_REPORT_LENGTH_NUMBER_KEY STRING_LITERAL_LENGTH( DEFENDER_REPORT_LENGTH_NUMBER_KEY )
|
||||
|
||||
/**
|
||||
* @ingroup defender_constants
|
||||
* @brief "number_list" key in the defender report.
|
||||
*/
|
||||
#define DEFENDER_REPORT_NUMBER_LIST_KEY "number_list"
|
||||
|
||||
/**
|
||||
* @ingroup defender_constants
|
||||
* @brief Length of the "number_list" key in the defender report.
|
||||
*/
|
||||
#define DEFENDER_REPORT_LENGTH_NUMBER_LIST_KEY STRING_LITERAL_LENGTH( DEFENDER_REPORT_LENGTH_NUMBER_LIST_KEY )
|
||||
|
||||
/**
|
||||
* @ingroup defender_constants
|
||||
* @brief "string_list" key in the defender report.
|
||||
*/
|
||||
#define DEFENDER_REPORT_STRING_LIST_KEY "string_list"
|
||||
|
||||
/**
|
||||
* @ingroup defender_constants
|
||||
* @brief Length of the "string_list" key in the defender report.
|
||||
*/
|
||||
#define DEFENDER_REPORT_LENGTH_STRING_LIST_KEY STRING_LITERAL_LENGTH( DEFENDER_REPORT_LENGTH_STRING_LIST_KEY )
|
||||
|
||||
/**
|
||||
* @ingroup defender_constants
|
||||
* @brief "ip_list" key in the defender report.
|
||||
*/
|
||||
#define DEFENDER_REPORT_IP_LIST_KEY "ip_list"
|
||||
|
||||
/**
|
||||
* @ingroup defender_constants
|
||||
* @brief Length of the "ip_list" key in the defender report.
|
||||
*/
|
||||
#define DEFENDER_REPORT_LENGTH_IP_LIST_KEY STRING_LITERAL_LENGTH( DEFENDER_REPORT_LENGTH_IP_LIST_KEY )
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* @brief Populate the topic string for a Device Defender operation.
|
||||
*
|
||||
* @param[in] pBuffer The buffer to write the topic string into.
|
||||
* @param[in] bufferLength The length of the buffer.
|
||||
* @param[in] pThingName The device's thingName as registered with AWS IoT.
|
||||
* @param[in] thingNameLength The length of the thing name.
|
||||
* @param[in] api The desired Device Defender API.
|
||||
* @param[out] pOutLength The length of the topic string written to the buffer.
|
||||
*
|
||||
* @return #DefenderSuccess if the topic string is written to the buffer;
|
||||
* #DefenderBadParameter if invalid parameters are passed;
|
||||
* #DefenderBufferTooSmall if the buffer cannot hold the full topic string.
|
||||
*
|
||||
* <b>Example</b>
|
||||
* @code{c}
|
||||
*
|
||||
* // The following example shows how to use the Defender_GetTopic API to
|
||||
* // generate a topic string for getting a JSON report accepted response.
|
||||
*
|
||||
* #define TOPIC_BUFFER_LENGTH ( 256U )
|
||||
*
|
||||
* // Every device should have a unique thing name registered with AWS IoT Core.
|
||||
* // This example assumes that the device has a unique serial number which is
|
||||
* // registered as the thing name with AWS IoT Core.
|
||||
* const char * pThingName = GetDeviceSerialNumber();
|
||||
* uint16_t thingNameLength = ( uint16_t )strlen( pThingname );
|
||||
* char topicBuffer[ TOPIC_BUFFER_LENGTH ] = { 0 };
|
||||
* uint16_t topicLength = 0;
|
||||
* DefenderStatus_t status = DefenderSuccess;
|
||||
*
|
||||
* status = Defender_GetTopic( &( topicBuffer[ 0 ] ),
|
||||
* TOPIC_BUFFER_LENGTH,
|
||||
* pThingName,
|
||||
* thingNameLength,
|
||||
* DefenderJsonReportAccepted,
|
||||
* &( topicLength ) );
|
||||
*
|
||||
* if( status == DefenderSuccess )
|
||||
* {
|
||||
* // The buffer topicBuffer contains the topic string of length
|
||||
* // topicLength for getting a JSON report accepted response. Subscribe
|
||||
* // to this topic using an MQTT client of your choice.
|
||||
* }
|
||||
* @endcode
|
||||
*/
|
||||
/* @[declare_defender_gettopic] */
|
||||
DefenderStatus_t Defender_GetTopic( char * pBuffer,
|
||||
uint16_t bufferLength,
|
||||
const char * pThingName,
|
||||
uint16_t thingNameLength,
|
||||
DefenderTopic_t api,
|
||||
uint16_t * pOutLength );
|
||||
/* @[declare_defender_gettopic] */
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* @brief Check if the given topic is one of the Device Defender topics.
|
||||
*
|
||||
* The function outputs which API the topic is for. It also optionally outputs
|
||||
* the starting location and length of the thing name in the given topic.
|
||||
*
|
||||
* @param[in] pTopic The topic string to check.
|
||||
* @param[in] topicLength The length of the topic string.
|
||||
* @param[out] pOutApi The defender topic API value.
|
||||
* @param[out] ppOutThingName Optional parameter to output the beginning of the
|
||||
* thing name in the topic string. Pass NULL if not needed.
|
||||
* @param[out] pOutThingNameLength Optional parameter to output the length of
|
||||
* the thing name in the topic string. Pass NULL if not needed.
|
||||
*
|
||||
* @return #DefenderSuccess if the topic is one of the defender topics;
|
||||
* #DefenderBadParameter if invalid parameters are passed;
|
||||
* #DefenderNoMatch if the topic is NOT one of the defender topics (parameter
|
||||
* pOutApi gets #DefenderInvalidTopic).
|
||||
*
|
||||
* <b>Example</b>
|
||||
* @code{c}
|
||||
*
|
||||
* // The following example shows how to use the Defender_MatchTopic API to
|
||||
* // check if an incoming MQTT publish message is a Device Defender message.
|
||||
*
|
||||
* DefenderTopic_t api;
|
||||
* DefenderStatus_t status = DefenderSuccess;
|
||||
*
|
||||
* // pTopic and topicLength are the topic string and length of the topic on
|
||||
* // which the publish message is received. These are usually provided by the
|
||||
* // MQTT client used. We pass the last two argument as NULL as we are not
|
||||
* // interested in the thing name in the topic string.
|
||||
* status = Defender_MatchTopic( pTopic,
|
||||
* topicLength,
|
||||
* &( api ),
|
||||
* NULL,
|
||||
* NULL );
|
||||
*
|
||||
* if( status == DefenderSuccess )
|
||||
* {
|
||||
* if( api == DefenderJsonReportAccepted )
|
||||
* {
|
||||
* // The published JSON report was accepted by the AWS IoT Device
|
||||
* // Defender service. You can parse the response using your choice
|
||||
* // of JSON parser and ensure that the report Id is same as was sent
|
||||
* // in the defender report.
|
||||
* }
|
||||
* else if( api == DefenderJsonReportRejected )
|
||||
* {
|
||||
* // The published JSON report was rejected by the AWS IoT Device
|
||||
* // Defender service.
|
||||
* }
|
||||
* else
|
||||
* {
|
||||
* // Unexpected response.
|
||||
* }
|
||||
* }
|
||||
* @endcode
|
||||
*/
|
||||
/* @[declare_defender_matchtopic] */
|
||||
DefenderStatus_t Defender_MatchTopic( const char * pTopic,
|
||||
uint16_t topicLength,
|
||||
DefenderTopic_t * pOutApi,
|
||||
const char ** ppOutThingName,
|
||||
uint16_t * pOutThingNameLength );
|
||||
/* @[declare_defender_matchtopic] */
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
/* *INDENT-ON* */
|
||||
|
||||
#endif /* DEFENDER_H_ */
|
||||
@ -0,0 +1,181 @@
|
||||
/*
|
||||
* AWS IoT Device Defender Client v1.3.0
|
||||
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file defender_config_defaults.h
|
||||
* @brief Default config values for the AWS IoT Device Defender Client Library.
|
||||
*/
|
||||
|
||||
#ifndef DEFENDER_CONFIG_DEFAULTS_H_
|
||||
#define DEFENDER_CONFIG_DEFAULTS_H_
|
||||
|
||||
/* The macro definition for DEFENDER_DO_NOT_USE_CUSTOM_CONFIG is for Doxygen
|
||||
* documentation only. */
|
||||
|
||||
/**
|
||||
* @brief Define this macro to build the AWS IoT Device Defender Client Library
|
||||
* without the custom config file defender_config.h.
|
||||
*
|
||||
* Without the custom config, the the AWS IoT Device Defender Client Library
|
||||
* builds with default values of config macros defined in the
|
||||
* defender_config_defaults.h file.
|
||||
*
|
||||
* If a custom config file is provided, then DEFENDER_DO_NOT_USE_CUSTOM_CONFIG
|
||||
* must not be defined.
|
||||
*
|
||||
* <b>Default value</b>: DEFENDER_DO_NOT_USE_CUSTOM_CONFIG is <b>not</b> defined
|
||||
* by default and the library expects a defender_config.h file.
|
||||
*/
|
||||
#ifdef DOXYGEN
|
||||
#define DEFENDER_DO_NOT_USE_CUSTOM_CONFIG
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Set it to 1 to enable use of long key names in the defender report.
|
||||
*
|
||||
* AWS IoT Device Defender Service supports both long and short names for keys
|
||||
* in the report sent by a device. For example,
|
||||
*
|
||||
* A device defender report using long key names:
|
||||
* @code{c}
|
||||
* {
|
||||
* "header": {
|
||||
* "report_id": 1530304554,
|
||||
* "version": "1.0"
|
||||
* },
|
||||
* "metrics": {
|
||||
* "network_stats": {
|
||||
* "bytes_in": 29358693495,
|
||||
* "bytes_out": 26485035,
|
||||
* "packets_in": 10013573555,
|
||||
* "packets_out": 11382615
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
* An equivalent report using short key names:
|
||||
* @code{c}
|
||||
* {
|
||||
* "hed": {
|
||||
* "rid": 1530304554,
|
||||
* "v": "1.0"
|
||||
* },
|
||||
* "met": {
|
||||
* "ns": {
|
||||
* "bi": 29358693495,
|
||||
* "bo": 26485035,
|
||||
* "pi": 10013573555,
|
||||
* "po": 11382615
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
* <b>Default value</b>: 0 as short key names are preferred option for resource
|
||||
* constrained devices because they result in smaller report size. If you want
|
||||
* to use long key names instead, set DEFENDER_USE_LONG_KEYS to 1 in the
|
||||
* defender_config.h file.
|
||||
*/
|
||||
#ifndef DEFENDER_USE_LONG_KEYS
|
||||
#define DEFENDER_USE_LONG_KEYS 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Macro used in the Device Defender client library to log error messages.
|
||||
*
|
||||
* To enable error logging, this macro should be mapped to an
|
||||
* application-specific logging implementation.
|
||||
*
|
||||
* @note This logging macro is called in the Device Defender client library with
|
||||
* parameters wrapped in double parentheses to be ISO C89/C90 standard
|
||||
* compliant. For a reference POSIX implementation of the logging macros, refer
|
||||
* to the defender_config.h file, and the logging-stack in demos folder of the
|
||||
* [AWS IoT Embedded C SDK repository](https://github.com/aws/aws-iot-device-sdk-embedded-C).
|
||||
*
|
||||
* <b>Default value</b>: Error logs are turned off, and no code is generated
|
||||
* for calls to the macro in the Device Defender client library on compilation.
|
||||
*/
|
||||
#ifndef LogError
|
||||
#define LogError( message )
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Macro used in the Device Defender client library to log warning messages.
|
||||
*
|
||||
* To enable warning logging, this macro should be mapped to an
|
||||
* application-specific logging implementation.
|
||||
*
|
||||
* @note This logging macro is called in the Device Defender client library with
|
||||
* parameters wrapped in double parentheses to be ISO C89/C90 standard
|
||||
* compliant. For a reference POSIX implementation of the logging macros, refer
|
||||
* to the defender_config.h file, and the logging-stack in demos folder of the
|
||||
* [AWS IoT Embedded C SDK repository](https://github.com/aws/aws-iot-device-sdk-embedded-C).
|
||||
*
|
||||
* <b>Default value</b>: Warning logs are turned off, and no code is generated
|
||||
* for calls to the macro in the Device Defender client library on compilation.
|
||||
*/
|
||||
#ifndef LogWarn
|
||||
#define LogWarn( message )
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Macro used in the Device Defender client library to log info messages.
|
||||
*
|
||||
* To enable info logging, this macro should be mapped to an
|
||||
* application-specific logging implementation.
|
||||
*
|
||||
* @note This logging macro is called in the Device Defender client library with
|
||||
* parameters wrapped in double parentheses to be ISO C89/C90 standard
|
||||
* compliant. For a reference POSIX implementation of the logging macros, refer
|
||||
* to the defender_config.h file, and the logging-stack in demos folder of the
|
||||
* [AWS IoT Embedded C SDK repository](https://github.com/aws/aws-iot-device-sdk-embedded-C).
|
||||
*
|
||||
* <b>Default value</b>: Info logs are turned off, and no code is generated for
|
||||
* calls to the macro in the Device Defender client library on compilation.
|
||||
*/
|
||||
#ifndef LogInfo
|
||||
#define LogInfo( message )
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Macro used in the Device Defender client library to log debug messages.
|
||||
*
|
||||
* To enable debug logging, this macro should be mapped to an
|
||||
* application-specific logging implementation.
|
||||
*
|
||||
* @note This logging macro is called in the Device Defender client library with
|
||||
* parameters wrapped in double parentheses to be ISO C89/C90 standard
|
||||
* compliant. For a reference POSIX implementation of the logging macros, refer
|
||||
* to the defender_config.h file, and the logging-stack in demos folder of the
|
||||
* [AWS IoT Embedded C SDK repository](https://github.com/aws/aws-iot-device-sdk-embedded-C).
|
||||
*
|
||||
* <b>Default value</b>: Debug logs are turned off, and no code is generated for
|
||||
* calls to the macro in the Device Defender client library on compilation.
|
||||
*/
|
||||
#ifndef LogDebug
|
||||
#define LogDebug( message )
|
||||
#endif
|
||||
|
||||
#endif /* DEFENDER_CONFIG_DEFAULTS_H_ */
|
||||
@ -0,0 +1,87 @@
|
||||
cmake_minimum_required ( VERSION 3.13.0 )
|
||||
project ( "Defender unit test"
|
||||
VERSION 1.0.0
|
||||
LANGUAGES C )
|
||||
|
||||
# Allow the project to be organized into folders.
|
||||
set_property( GLOBAL PROPERTY USE_FOLDERS ON )
|
||||
|
||||
# Use C90.
|
||||
set( CMAKE_C_STANDARD 90 )
|
||||
set( CMAKE_C_STANDARD_REQUIRED ON )
|
||||
|
||||
# Do not allow in-source build.
|
||||
if( ${PROJECT_SOURCE_DIR} STREQUAL ${PROJECT_BINARY_DIR} )
|
||||
message( FATAL_ERROR "In-source build is not allowed. Please build in a separate directory, such as ${PROJECT_SOURCE_DIR}/build." )
|
||||
endif()
|
||||
|
||||
# Set global path variable.
|
||||
get_filename_component( __MODULE_ROOT_DIR "${CMAKE_CURRENT_LIST_DIR}/.." ABSOLUTE )
|
||||
set( MODULE_ROOT_DIR ${__MODULE_ROOT_DIR} CACHE INTERNAL "Device Defender repository root." )
|
||||
set( UNIT_TEST_DIR ${MODULE_ROOT_DIR}/test/unit-test CACHE INTERNAL "Device Defender unit test directory." )
|
||||
set( UNITY_DIR ${UNIT_TEST_DIR}/Unity CACHE INTERNAL "Unity library source directory." )
|
||||
|
||||
# Configure options to always show in CMake GUI.
|
||||
option( BUILD_CLONE_SUBMODULES
|
||||
"Set this to ON to automatically clone any required Git submodules. When OFF, submodules must be manually cloned."
|
||||
ON )
|
||||
|
||||
# Set output directories.
|
||||
set( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin )
|
||||
set( CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib )
|
||||
set( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib )
|
||||
|
||||
# ====================== Coverity Analysis Configuration ======================
|
||||
|
||||
# Include filepaths for source and include.
|
||||
include( ${MODULE_ROOT_DIR}/defenderFilePaths.cmake )
|
||||
|
||||
# Target for Coverity analysis that builds the library.
|
||||
add_library( coverity_analysis
|
||||
${DEFENDER_SOURCES} )
|
||||
|
||||
# Device Defender public include path.
|
||||
target_include_directories( coverity_analysis
|
||||
PUBLIC
|
||||
${DEFENDER_INCLUDE_PUBLIC_DIRS}
|
||||
"${CMAKE_CURRENT_LIST_DIR}/include" )
|
||||
|
||||
# Disable logging/assert() calls when building the Coverity analysis target
|
||||
target_compile_options(coverity_analysis PUBLIC -DNDEBUG -DDISABLE_LOGGING )
|
||||
|
||||
# ============================ Test Configuration ============================
|
||||
|
||||
# Include Unity build configuration.
|
||||
include( unit-test/unity_build.cmake )
|
||||
|
||||
# Check if the Unity source directory exists. If it does not exist and the
|
||||
# BUILD_CLONE_SUBMODULES configuration is enabled, clone the Unity submodule.
|
||||
if( NOT EXISTS ${UNITY_DIR}/src )
|
||||
# Attempt to clone Unity.
|
||||
if( ${BUILD_CLONE_SUBMODULES} )
|
||||
clone_unity()
|
||||
else()
|
||||
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." )
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Use CTest utility for managing test runs.
|
||||
enable_testing()
|
||||
|
||||
# Add build target for Unity, required for unit testing.
|
||||
add_unity_target()
|
||||
|
||||
# Add functions to enable Unity based tests and coverage.
|
||||
include( ${MODULE_ROOT_DIR}/tools/unity/create_test.cmake )
|
||||
|
||||
# Include build configuration for unit tests.
|
||||
add_subdirectory( unit-test )
|
||||
|
||||
# ====================== Coverage Analysis configuration ======================
|
||||
|
||||
# Add a target for running coverage on tests.
|
||||
add_custom_target( coverage
|
||||
COMMAND ${CMAKE_COMMAND} -DUNITY_DIR=${UNITY_DIR}
|
||||
-P ${MODULE_ROOT_DIR}/tools/unity/coverage.cmake
|
||||
DEPENDS unity defender_utest
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR} )
|
||||
24
kernel/FreeRTOS-Plus/Source/AWS/device-defender/test/cbmc/.gitignore
vendored
Normal file
24
kernel/FreeRTOS-Plus/Source/AWS/device-defender/test/cbmc/.gitignore
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
# Emitted when running CBMC proofs
|
||||
proofs/**/logs
|
||||
proofs/**/gotos
|
||||
proofs/**/report
|
||||
proofs/**/html
|
||||
proofs/output
|
||||
|
||||
# Emitted by CBMC Viewer
|
||||
TAGS-*
|
||||
|
||||
# Emitted by Arpa
|
||||
arpa_cmake/
|
||||
arpa-validation-logs/
|
||||
Makefile.arpa
|
||||
|
||||
# Emitted by litani
|
||||
.ninja_deps
|
||||
.ninja_log
|
||||
.litani_cache_dir
|
||||
|
||||
# These files should be overwritten whenever prepare.py runs
|
||||
cbmc-batch.yaml
|
||||
|
||||
__pycache__/
|
||||
@ -0,0 +1,6 @@
|
||||
CBMC proof include files
|
||||
========================
|
||||
|
||||
This directory contains include files written for CBMC proof. It is
|
||||
common to write some code to model aspects of the system under test,
|
||||
and the header files for this code go here.
|
||||
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* AWS IoT Device Defender Client v1.3.0
|
||||
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file Defender_GetTopic_harness.c
|
||||
* @brief Implements the proof harness for Defender_GetTopic function.
|
||||
*/
|
||||
|
||||
#include "defender.h"
|
||||
|
||||
void harness()
|
||||
{
|
||||
char * pTopicBuffer;
|
||||
uint16_t topicBufferLength;
|
||||
char * pThingName;
|
||||
uint16_t thingNameLength;
|
||||
DefenderTopic_t api;
|
||||
uint16_t * pOutLength;
|
||||
|
||||
__CPROVER_assume( topicBufferLength < CBMC_MAX_OBJECT_SIZE );
|
||||
|
||||
/* +1 is to ensure that we run the function for invalid thing name length as
|
||||
* well. */
|
||||
__CPROVER_assume( thingNameLength <= ( DEFENDER_THINGNAME_MAX_LENGTH + 1 ) );
|
||||
|
||||
pTopicBuffer = malloc( topicBufferLength );
|
||||
pThingName = malloc( thingNameLength );
|
||||
pOutLength = malloc( sizeof( *pOutLength ) );
|
||||
|
||||
Defender_GetTopic( pTopicBuffer,
|
||||
topicBufferLength,
|
||||
pThingName,
|
||||
thingNameLength,
|
||||
api,
|
||||
pOutLength );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
@ -0,0 +1,20 @@
|
||||
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
# SPDX-License-Identifier: MIT-0
|
||||
|
||||
HARNESS_ENTRY=harness
|
||||
HARNESS_FILE=Defender_GetTopic_harness
|
||||
|
||||
# This should be a unique identifier for this proof, and will appear on the
|
||||
# Litani dashboard. It can be human-readable and contain spaces if you wish.
|
||||
PROOF_UID = Defender_GetTopic
|
||||
|
||||
DEFINES +=
|
||||
INCLUDES +=
|
||||
|
||||
REMOVE_FUNCTION_BODY +=
|
||||
UNWINDSET +=
|
||||
|
||||
PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
|
||||
PROJECT_SOURCES += $(SRCDIR)/source/defender.c
|
||||
|
||||
include ../Makefile.common
|
||||
@ -0,0 +1,20 @@
|
||||
Defender_GetTopic proof
|
||||
==============
|
||||
|
||||
This directory contains a memory safety proof for Defender_GetTopic.
|
||||
|
||||
To run the proof.
|
||||
-------------
|
||||
|
||||
* Add cbmc, goto-cc, goto-instrument, goto-analyzer, and cbmc-viewer
|
||||
to your path.
|
||||
* Run "make".
|
||||
* Open html/index.html in a web browser.
|
||||
|
||||
To use [`arpa`](https://github.com/awslabs/aws-proof-build-assistant) to simplify writing Makefiles.
|
||||
-------------
|
||||
|
||||
* Run "make arpa" to generate a Makefile.arpa that contains relevant build information for the proof.
|
||||
* Use Makefile.arpa as the starting point for your proof Makefile by:
|
||||
1. Modifying Makefile.arpa (if required).
|
||||
2. Including Makefile.arpa into the existing proof Makefile (add `sinclude Makefile.arpa` at the bottom of the Makefile, right before `include ../Makefile.common`).
|
||||
@ -0,0 +1 @@
|
||||
# This file marks this directory as containing a CBMC proof.
|
||||
@ -0,0 +1,7 @@
|
||||
{ "expected-missing-functions":
|
||||
[
|
||||
|
||||
],
|
||||
"proof-name": "Defender_GetTopic",
|
||||
"proof-root": "test/cbmc/proofs"
|
||||
}
|
||||
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* AWS IoT Device Defender Client v1.3.0
|
||||
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file Defender_MatchTopic_harness.c
|
||||
* @brief Implements the proof harness for Defender_MatchTopic function.
|
||||
*/
|
||||
|
||||
#include "defender.h"
|
||||
|
||||
void harness()
|
||||
{
|
||||
const char * pTopic;
|
||||
uint16_t topicLength;
|
||||
DefenderTopic_t * pOutApi;
|
||||
const char ** ppOutThingName;
|
||||
uint16_t * pOutThingNameLength;
|
||||
|
||||
__CPROVER_assume( topicLength < TOPIC_STRING_LENGTH_MAX );
|
||||
|
||||
pTopic = malloc( topicLength );
|
||||
pOutApi = malloc( sizeof( *pOutApi ) );
|
||||
ppOutThingName = malloc( sizeof( *ppOutThingName ) );
|
||||
pOutThingNameLength = malloc( sizeof( *pOutThingNameLength ) );
|
||||
|
||||
Defender_MatchTopic( pTopic,
|
||||
topicLength,
|
||||
pOutApi,
|
||||
ppOutThingName,
|
||||
pOutThingNameLength );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
@ -0,0 +1,47 @@
|
||||
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
# SPDX-License-Identifier: MIT-0
|
||||
|
||||
HARNESS_ENTRY=harness
|
||||
HARNESS_FILE=Defender_MatchTopic_harness
|
||||
|
||||
# This should be a unique identifier for this proof, and will appear on the
|
||||
# Litani dashboard. It can be human-readable and contain spaces if you wish.
|
||||
PROOF_UID = Defender_MatchTopic
|
||||
|
||||
# The topic length is bounded to reduce the proof run time. Memory safety on the
|
||||
# buffer holding the topic string can be proven within a reasonable bound. It
|
||||
# adds no value to the proof to input the largest possible topic string accepted
|
||||
# by AWS (64KB).
|
||||
TOPIC_STRING_LENGTH_MAX=200
|
||||
|
||||
DEFINES += -DTOPIC_STRING_LENGTH_MAX=$(TOPIC_STRING_LENGTH_MAX)
|
||||
INCLUDES +=
|
||||
|
||||
REMOVE_FUNCTION_BODY +=
|
||||
|
||||
# The longest strncmp is in matchBridge function which matches DEFENDER_API_BRIDGE
|
||||
# length of which is 19. We unwind one more time than the bridge length.
|
||||
DEFENDER_API_BRIDGE_LENGTH=20
|
||||
UNWINDSET += strncmp.0:$(DEFENDER_API_BRIDGE_LENGTH)
|
||||
|
||||
# Enough to unwind the extractThingNameLength loop TOPIC_STRING_LENGTH_MAX times
|
||||
# as thingname in the topic string can not be longer than the topic string
|
||||
# length.
|
||||
UNWINDSET += __CPROVER_file_local_defender_c_extractThingNameLength.0:$(TOPIC_STRING_LENGTH_MAX)
|
||||
|
||||
# Total defender APIs are 6:
|
||||
# DefenderJsonReportPublish
|
||||
# DefenderJsonReportAccepted
|
||||
# DefenderJsonReportRejected
|
||||
# DefenderCborReportPublish
|
||||
# DefenderCborReportAccepted
|
||||
# DefenderCborReportRejected
|
||||
#
|
||||
# We unwind one more than the total API count.
|
||||
DEFENDER_API_COUNT=7
|
||||
UNWINDSET += __CPROVER_file_local_defender_c_matchApi.0:$(DEFENDER_API_COUNT)
|
||||
|
||||
PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
|
||||
PROJECT_SOURCES += $(SRCDIR)/source/defender.c
|
||||
|
||||
include ../Makefile.common
|
||||
@ -0,0 +1,20 @@
|
||||
Defender_MatchTopic proof
|
||||
==============
|
||||
|
||||
This directory contains a memory safety proof for Defender_MatchTopic.
|
||||
|
||||
To run the proof.
|
||||
-------------
|
||||
|
||||
* Add cbmc, goto-cc, goto-instrument, goto-analyzer, and cbmc-viewer
|
||||
to your path.
|
||||
* Run "make".
|
||||
* Open html/index.html in a web browser.
|
||||
|
||||
To use [`arpa`](https://github.com/awslabs/aws-proof-build-assistant) to simplify writing Makefiles.
|
||||
-------------
|
||||
|
||||
* Run "make arpa" to generate a Makefile.arpa that contains relevant build information for the proof.
|
||||
* Use Makefile.arpa as the starting point for your proof Makefile by:
|
||||
1. Modifying Makefile.arpa (if required).
|
||||
2. Including Makefile.arpa into the existing proof Makefile (add `sinclude Makefile.arpa` at the bottom of the Makefile, right before `include ../Makefile.common`).
|
||||
@ -0,0 +1 @@
|
||||
# This file marks this directory as containing a CBMC proof.
|
||||
@ -0,0 +1,7 @@
|
||||
{ "expected-missing-functions":
|
||||
[
|
||||
|
||||
],
|
||||
"proof-name": "Defender_MatchTopic",
|
||||
"proof-root": "test/cbmc/proofs"
|
||||
}
|
||||
@ -0,0 +1,62 @@
|
||||
# -*- mode: makefile -*-
|
||||
# The first line sets the emacs major mode to Makefile
|
||||
|
||||
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
# SPDX-License-Identifier: MIT-0
|
||||
|
||||
################################################################
|
||||
# Use this file to give project-specific definitions of the command
|
||||
# line arguments to pass to CBMC tools like goto-cc to build the goto
|
||||
# binaries and cbmc to do the property and coverage checking.
|
||||
#
|
||||
# Use this file to override most default definitions of variables in
|
||||
# Makefile.common.
|
||||
################################################################
|
||||
|
||||
# Name of this proof project, displayed in proof reports. For example,
|
||||
# "s2n" or "Amazon FreeRTOS". For projects with multiple proof roots,
|
||||
# this may be overridden on the command-line to Make, for example
|
||||
#
|
||||
# make PROJECT_NAME="FreeRTOS MQTT" report
|
||||
#
|
||||
PROJECT_NAME = "FreeRTOS Device Defender"
|
||||
|
||||
# Path to litani executable, relative to the root of the repository.
|
||||
# This applies even for projects with multiple proof roots.
|
||||
LITANI ?= litani
|
||||
|
||||
# Flags to pass to goto-cc for compilation (typically those passed to gcc -c)
|
||||
COMPILE_FLAGS += -fPIC
|
||||
COMPILE_FLAGS += -std=gnu90
|
||||
|
||||
# Flags to pass to goto-cc for linking (typically those passed to gcc)
|
||||
# LINK_FLAGS =
|
||||
|
||||
# Preprocessor include paths -I...
|
||||
# Consider adding
|
||||
# INCLUDES += -I$(CBMC_ROOT)/include
|
||||
# You will want to decide what order that comes in relative to the other
|
||||
# include directories in your project.
|
||||
#
|
||||
INCLUDES += -I$(SRCDIR)/test/cbmc/include
|
||||
INCLUDES += -I$(SRCDIR)/source/include
|
||||
INCLUDES += -I$(SRCDIR)/source
|
||||
INCLUDES += -I$(SRCDIR)/test/include
|
||||
|
||||
# Preprocessor definitions -D...
|
||||
DEFINES += -Ddefender_EXPORTS
|
||||
|
||||
# Path to arpa executable
|
||||
# ARPA =
|
||||
|
||||
# Flags to pass to cmake for building the project
|
||||
# ARPA_CMAKE_FLAGS =
|
||||
|
||||
# Additional CBMC flags used for property checking
|
||||
# TODO - Remove these once they are in the starter kit.
|
||||
CHECKFLAGS += --pointer-primitive-check
|
||||
CHECKFLAGS += --malloc-may-fail
|
||||
CHECKFLAGS += --malloc-fail-null
|
||||
|
||||
COVERFLAGS += --malloc-may-fail
|
||||
COVERFLAGS += --malloc-fail-null
|
||||
@ -0,0 +1,10 @@
|
||||
# -*- mode: makefile -*-
|
||||
# The first line sets the emacs major mode to Makefile
|
||||
|
||||
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
# SPDX-License-Identifier: MIT-0
|
||||
|
||||
################################################################
|
||||
# Use this file to give project-specific targets, including targets
|
||||
# that may depend on targets defined in Makefile.common.
|
||||
################################################################
|
||||
@ -0,0 +1,11 @@
|
||||
# -*- mode: makefile -*-
|
||||
# The first line sets the emacs major mode to Makefile
|
||||
|
||||
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
# SPDX-License-Identifier: MIT-0
|
||||
|
||||
################################################################
|
||||
# Use this file to define project-specific targets and definitions for
|
||||
# unit testing or continuous integration that may depend on targets
|
||||
# defined in Makefile.common
|
||||
################################################################
|
||||
@ -0,0 +1 @@
|
||||
SRCDIR ?= $(abspath $(PROOF_ROOT)/../../..)
|
||||
@ -0,0 +1,999 @@
|
||||
# -*- mode: makefile -*-
|
||||
# The first line sets the emacs major mode to Makefile
|
||||
|
||||
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
# SPDX-License-Identifier: MIT-0
|
||||
|
||||
CBMC_STARTER_KIT_VERSION = CBMC starter kit 2.5
|
||||
|
||||
################################################################
|
||||
# The CBMC Starter Kit depends on the files Makefile.common and
|
||||
# run-cbmc-proofs.py. They are installed by the setup script
|
||||
# cbmc-starter-kit-setup and updated to the latest version by the
|
||||
# update script cbmc-starter-kit-update. For more information about
|
||||
# the starter kit and these files and these scripts, see
|
||||
# https://model-checking.github.io/cbmc-starter-kit
|
||||
#
|
||||
# Makefile.common implements what we consider to be some best
|
||||
# practices for using cbmc for software verification.
|
||||
#
|
||||
# Section I gives default values for a large number of Makefile
|
||||
# variables that control
|
||||
# * how your code is built (include paths, etc),
|
||||
# * what program transformations are applied to your code (loop
|
||||
# unwinding, etc), and
|
||||
# * what properties cbmc checks for in your code (memory safety, etc).
|
||||
#
|
||||
# These variables are defined below with definitions of the form
|
||||
# VARIABLE ?= DEFAULT_VALUE
|
||||
# meaning VARIABLE is set to DEFAULT_VALUE if VARIABLE has not already
|
||||
# been given a value.
|
||||
#
|
||||
# For your project, you can override these default values with
|
||||
# project-specific definitions in Makefile-project-defines.
|
||||
#
|
||||
# For any individual proof, you can override these default values and
|
||||
# project-specific values with proof-specific definitions in the
|
||||
# Makefile for your proof.
|
||||
#
|
||||
# The definitions in the proof Makefile override definitions in the
|
||||
# project Makefile-project-defines which override definitions in this
|
||||
# Makefile.common.
|
||||
#
|
||||
# Section II uses the values defined in Section I to build your code, run
|
||||
# your proof, and build a report of your results. You should not need
|
||||
# to modify or override anything in Section II, but you may want to
|
||||
# read it to understand how the values defined in Section I control
|
||||
# things.
|
||||
#
|
||||
# To use Makefile.common, set variables as described above as needed,
|
||||
# and then for each proof,
|
||||
#
|
||||
# * Create a subdirectory <DIR>.
|
||||
# * Write a proof harness (a function) with the name <HARNESS_ENTRY>
|
||||
# in a file with the name <DIR>/<HARNESS_FILE>.c
|
||||
# * Write a makefile with the name <DIR>/Makefile that looks
|
||||
# something like
|
||||
#
|
||||
# HARNESS_FILE=<HARNESS_FILE>
|
||||
# HARNESS_ENTRY=<HARNESS_ENTRY>
|
||||
# PROOF_UID=<PROOF_UID>
|
||||
#
|
||||
# PROJECT_SOURCES += $(SRCDIR)/libraries/api_1.c
|
||||
# PROJECT_SOURCES += $(SRCDIR)/libraries/api_2.c
|
||||
#
|
||||
# PROOF_SOURCES += $(PROOFDIR)/harness.c
|
||||
# PROOF_SOURCES += $(SRCDIR)/cbmc/proofs/stub_a.c
|
||||
# PROOF_SOURCES += $(SRCDIR)/cbmc/proofs/stub_b.c
|
||||
#
|
||||
# UNWINDSET += foo.0:3
|
||||
# UNWINDSET += bar.1:6
|
||||
#
|
||||
# REMOVE_FUNCTION_BODY += api_stub_a
|
||||
# REMOVE_FUNCTION_BODY += api_stub_b
|
||||
#
|
||||
# DEFINES = -DDEBUG=0
|
||||
#
|
||||
# include ../Makefile.common
|
||||
#
|
||||
# * Change directory to <DIR> and run make
|
||||
#
|
||||
# The proof setup script cbmc-starter-kit-setup-proof from the CBMC
|
||||
# Starter Kit will do most of this for, creating a directory and
|
||||
# writing a basic Makefile and proof harness into it that you can edit
|
||||
# as described above.
|
||||
#
|
||||
# Warning: If you get results that are hard to explain, consider
|
||||
# running "make clean" or "make veryclean" before "make" if you get
|
||||
# results that are hard to explain. Dependency handling in this
|
||||
# Makefile.common may not be perfect.
|
||||
|
||||
SHELL=/bin/bash
|
||||
|
||||
default: report
|
||||
|
||||
################################################################
|
||||
################################################################
|
||||
## Section I: This section gives common variable definitions.
|
||||
##
|
||||
## Override these definitions in Makefile-project-defines or
|
||||
## your proof Makefile.
|
||||
##
|
||||
## Remember that Makefile.common and Makefile-project-defines are
|
||||
## included into the proof Makefile in your proof directory, so all
|
||||
## relative pathnames defined there should be relative to your proof
|
||||
## directory.
|
||||
|
||||
################################################################
|
||||
# Define the layout of the source tree and the proof subtree
|
||||
#
|
||||
# Generally speaking,
|
||||
#
|
||||
# SRCDIR = the root of the repository
|
||||
# CBMC_ROOT = /srcdir/cbmc
|
||||
# PROOF_ROOT = /srcdir/cbmc/proofs
|
||||
# PROOF_SOURCE = /srcdir/cbmc/sources
|
||||
# PROOF_INCLUDE = /srcdir/cbmc/include
|
||||
# PROOF_STUB = /srcdir/cbmc/stubs
|
||||
# PROOFDIR = the directory containing the Makefile for your proof
|
||||
#
|
||||
# The path /srcdir/cbmc used in the example above is determined by the
|
||||
# setup script cbmc-starter-kit-setup. Projects usually create a cbmc
|
||||
# directory somewhere in the source tree, and run the setup script in
|
||||
# that directory. The value of CBMC_ROOT becomes the absolute path to
|
||||
# that directory.
|
||||
#
|
||||
# The location of that cbmc directory in the source tree affects the
|
||||
# definition of SRCDIR, which is defined in terms of the relative path
|
||||
# from a proof directory to the repository root. The definition is
|
||||
# usually determined by the setup script cbmc-starter-kit-setup and
|
||||
# written to Makefile-template-defines, but you can override it for a
|
||||
# project in Makefile-project-defines and for a specific proof in the
|
||||
# Makefile for the proof.
|
||||
|
||||
# Absolute path to the directory containing this Makefile.common
|
||||
# See https://ftp.gnu.org/old-gnu/Manuals/make-3.80/html_node/make_17.html
|
||||
#
|
||||
# Note: We compute the absolute paths to the makefiles in MAKEFILE_LIST
|
||||
# before we filter the list of makefiles for %/Makefile.common.
|
||||
# Otherwise an invocation of the form "make -f Makefile.common" will set
|
||||
# MAKEFILE_LIST to "Makefile.common" which will fail to match the
|
||||
# pattern %/Makefile.common.
|
||||
#
|
||||
MAKEFILE_PATHS = $(foreach makefile,$(MAKEFILE_LIST),$(abspath $(makefile)))
|
||||
PROOF_ROOT = $(dir $(filter %/Makefile.common,$(MAKEFILE_PATHS)))
|
||||
|
||||
CBMC_ROOT = $(shell dirname $(PROOF_ROOT))
|
||||
PROOF_SOURCE = $(CBMC_ROOT)/sources
|
||||
PROOF_INCLUDE = $(CBMC_ROOT)/include
|
||||
PROOF_STUB = $(CBMC_ROOT)/stubs
|
||||
|
||||
# Project-specific definitions to override default definitions below
|
||||
# * Makefile-project-defines will never be overwritten
|
||||
# * Makefile-template-defines may be overwritten when the starter
|
||||
# kit is updated
|
||||
sinclude $(PROOF_ROOT)/Makefile-project-defines
|
||||
sinclude $(PROOF_ROOT)/Makefile-template-defines
|
||||
|
||||
# SRCDIR is the path to the root of the source tree
|
||||
# This is a default definition that is frequently overridden in
|
||||
# another Makefile, see the discussion of SRCDIR above.
|
||||
SRCDIR ?= $(abspath ../..)
|
||||
|
||||
# PROOFDIR is the path to the directory containing the proof harness
|
||||
PROOFDIR ?= $(abspath .)
|
||||
|
||||
################################################################
|
||||
# Define how to run CBMC
|
||||
|
||||
# Do property checking with the external SAT solver given by
|
||||
# EXTERNAL_SAT_SOLVER. Do coverage checking with the default solver,
|
||||
# since coverage checking requires the use of an incremental solver.
|
||||
# The EXTERNAL_SAT_SOLVER variable is typically set (if it is at all)
|
||||
# as an environment variable or as a makefile variable in
|
||||
# Makefile-project-defines.
|
||||
#
|
||||
# For a particular proof, if the default solver is faster, do property
|
||||
# checking with the default solver by including this definition in the
|
||||
# proof Makefile:
|
||||
# USE_EXTERNAL_SAT_SOLVER =
|
||||
#
|
||||
ifneq ($(strip $(EXTERNAL_SAT_SOLVER)),)
|
||||
USE_EXTERNAL_SAT_SOLVER ?= --external-sat-solver $(EXTERNAL_SAT_SOLVER)
|
||||
endif
|
||||
CHECKFLAGS += $(USE_EXTERNAL_SAT_SOLVER)
|
||||
|
||||
# Job pools
|
||||
# For version of Litani that are new enough (where `litani print-capabilities`
|
||||
# prints "pools"), proofs for which `EXPENSIVE = true` is set can be added to a
|
||||
# "job pool" that restricts how many expensive proofs are run at a time. All
|
||||
# other proofs will be built in parallel as usual.
|
||||
#
|
||||
# In more detail: all compilation, instrumentation, and report jobs are run with
|
||||
# full parallelism as usual, even for expensive proofs. The CBMC jobs for
|
||||
# non-expensive proofs are also run in parallel. The only difference is that the
|
||||
# CBMC safety checks and coverage checks for expensive proofs are run with a
|
||||
# restricted parallelism level. At any one time, only N of these jobs are run at
|
||||
# once, amongst all the proofs.
|
||||
#
|
||||
# To configure N, Litani needs to be initialized with a pool called "expensive".
|
||||
# For example, to only run two CBMC safety/coverage jobs at a time from amongst
|
||||
# all the proofs, you would initialize litani like
|
||||
# litani init --pools expensive:2
|
||||
# The run-cbmc-proofs.py script takes care of this initialization through the
|
||||
# --expensive-jobs-parallelism flag.
|
||||
#
|
||||
# To enable this feature, set
|
||||
# the ENABLE_POOLS variable when running Make, like
|
||||
# `make ENABLE_POOLS=true report`
|
||||
# The run-cbmc-proofs.py script takes care of this through the
|
||||
# --restrict-expensive-jobs flag.
|
||||
|
||||
ifeq ($(strip $(ENABLE_POOLS)),)
|
||||
POOL =
|
||||
else ifeq ($(strip $(EXPENSIVE)),)
|
||||
POOL =
|
||||
else
|
||||
POOL = --pool expensive
|
||||
endif
|
||||
|
||||
# Similar to the pool feature above. If Litani is new enough, enable
|
||||
# profiling CBMC's memory use.
|
||||
ifeq ($(strip $(ENABLE_MEMORY_PROFILING)),)
|
||||
MEMORY_PROFILING =
|
||||
else
|
||||
MEMORY_PROFILING = --profile-memory
|
||||
endif
|
||||
|
||||
# Property checking flags
|
||||
#
|
||||
# Each variable below controls a specific property checking flag
|
||||
# within CBMC. If desired, a property flag can be disabled within
|
||||
# a particular proof by nulling the corresponding variable. For
|
||||
# instance, the following line:
|
||||
#
|
||||
# CHECK_FLAG_POINTER_CHECK =
|
||||
#
|
||||
# would disable the --pointer-check CBMC flag within:
|
||||
# * an entire project when added to Makefile-project-defines
|
||||
# * a specific proof when added to the harness Makefile
|
||||
|
||||
CBMC_FLAG_MALLOC_MAY_FAIL ?= --malloc-may-fail
|
||||
CBMC_FLAG_MALLOC_FAIL_NULL ?= --malloc-fail-null
|
||||
CBMC_FLAG_BOUNDS_CHECK ?= --bounds-check
|
||||
CBMC_FLAG_CONVERSION_CHECK ?= --conversion-check
|
||||
CBMC_FLAG_DIV_BY_ZERO_CHECK ?= --div-by-zero-check
|
||||
CBMC_FLAG_FLOAT_OVERFLOW_CHECK ?= --float-overflow-check
|
||||
CBMC_FLAG_NAN_CHECK ?= --nan-check
|
||||
CBMC_FLAG_POINTER_CHECK ?= --pointer-check
|
||||
CBMC_FLAG_POINTER_OVERFLOW_CHECK ?= --pointer-overflow-check
|
||||
CBMC_FLAG_POINTER_PRIMITIVE_CHECK ?= --pointer-primitive-check
|
||||
CBMC_FLAG_SIGNED_OVERFLOW_CHECK ?= --signed-overflow-check
|
||||
CBMC_FLAG_UNDEFINED_SHIFT_CHECK ?= --undefined-shift-check
|
||||
CBMC_FLAG_UNSIGNED_OVERFLOW_CHECK ?= --unsigned-overflow-check
|
||||
CBMC_FLAG_UNWINDING_ASSERTIONS ?= --unwinding-assertions
|
||||
CBMC_FLAG_UNWIND ?= --unwind 1
|
||||
CBMC_FLAG_FLUSH ?= --flush
|
||||
|
||||
# CBMC flags used for property checking and coverage checking
|
||||
|
||||
CBMCFLAGS += $(CBMC_FLAG_UNWIND) $(CBMC_UNWINDSET) $(CBMC_FLAG_FLUSH)
|
||||
|
||||
# CBMC flags used for property checking
|
||||
|
||||
CHECKFLAGS += $(CBMC_FLAG_MALLOC_MAY_FAIL)
|
||||
CHECKFLAGS += $(CBMC_FLAG_MALLOC_FAIL_NULL)
|
||||
CHECKFLAGS += $(CBMC_FLAG_BOUNDS_CHECK)
|
||||
CHECKFLAGS += $(CBMC_FLAG_CONVERSION_CHECK)
|
||||
CHECKFLAGS += $(CBMC_FLAG_DIV_BY_ZERO_CHECK)
|
||||
CHECKFLAGS += $(CBMC_FLAG_FLOAT_OVERFLOW_CHECK)
|
||||
CHECKFLAGS += $(CBMC_FLAG_NAN_CHECK)
|
||||
CHECKFLAGS += $(CBMC_FLAG_POINTER_CHECK)
|
||||
CHECKFLAGS += $(CBMC_FLAG_POINTER_OVERFLOW_CHECK)
|
||||
CHECKFLAGS += $(CBMC_FLAG_POINTER_PRIMITIVE_CHECK)
|
||||
CHECKFLAGS += $(CBMC_FLAG_SIGNED_OVERFLOW_CHECK)
|
||||
CHECKFLAGS += $(CBMC_FLAG_UNDEFINED_SHIFT_CHECK)
|
||||
CHECKFLAGS += $(CBMC_FLAG_UNSIGNED_OVERFLOW_CHECK)
|
||||
CHECKFLAGS += $(CBMC_FLAG_UNWINDING_ASSERTIONS)
|
||||
|
||||
# CBMC flags used for coverage checking
|
||||
|
||||
COVERFLAGS += $(CBMC_FLAG_MALLOC_MAY_FAIL)
|
||||
COVERFLAGS += $(CBMC_FLAG_MALLOC_FAIL_NULL)
|
||||
|
||||
# Additional CBMC flag to CBMC control verbosity.
|
||||
#
|
||||
# Meaningful values are
|
||||
# 0 none
|
||||
# 1 only errors
|
||||
# 2 + warnings
|
||||
# 4 + results
|
||||
# 6 + status/phase information
|
||||
# 8 + statistical information
|
||||
# 9 + progress information
|
||||
# 10 + debug info
|
||||
#
|
||||
# Uncomment the following line or set in Makefile-project-defines
|
||||
# CBMC_VERBOSITY ?= --verbosity 4
|
||||
|
||||
# Additional CBMC flag to control how CBMC treats static variables.
|
||||
#
|
||||
# NONDET_STATIC is a list of flags of the form --nondet-static
|
||||
# and --nondet-static-exclude VAR. The --nondet-static flag causes
|
||||
# CBMC to initialize static variables with unconstrained value
|
||||
# (ignoring initializers and default zero-initialization). The
|
||||
# --nondet-static-exclude VAR excludes VAR for the variables
|
||||
# initialized with unconstrained values.
|
||||
NONDET_STATIC ?=
|
||||
|
||||
# Flags to pass to goto-cc for compilation and linking
|
||||
COMPILE_FLAGS ?= -Wall
|
||||
LINK_FLAGS ?= -Wall
|
||||
EXPORT_FILE_LOCAL_SYMBOLS ?= --export-file-local-symbols
|
||||
|
||||
# Preprocessor include paths -I...
|
||||
INCLUDES ?=
|
||||
|
||||
# Preprocessor definitions -D...
|
||||
DEFINES ?=
|
||||
|
||||
# CBMC object model
|
||||
#
|
||||
# CBMC_OBJECT_BITS is the number of bits in a pointer CBMC uses for
|
||||
# the id of the object to which a pointer is pointing. CBMC uses 8
|
||||
# bits for the object id by default. The remaining bits in the pointer
|
||||
# are used for offset into the object. This limits the size of the
|
||||
# objects that CBMC can model. This Makefile defines this bound on
|
||||
# object size to be CBMC_MAX_OBJECT_SIZE. You are likely to get
|
||||
# unexpected results if you try to malloc an object larger than this
|
||||
# bound.
|
||||
CBMC_OBJECT_BITS ?= 8
|
||||
|
||||
# CBMC loop unwinding (Normally set in the proof Makefile)
|
||||
#
|
||||
# UNWINDSET is a list of pairs of the form foo.1:4 meaning that
|
||||
# CBMC should unwind loop 1 in function foo no more than 4 times.
|
||||
# For historical reasons, the number 4 is one more than the number
|
||||
# of times CBMC actually unwinds the loop.
|
||||
UNWINDSET ?=
|
||||
|
||||
# CBMC early loop unwinding (Normally set in the proof Makefile)
|
||||
#
|
||||
# Most users can ignore this variable.
|
||||
#
|
||||
# This variable exists to support the use of loop and function
|
||||
# contracts, two features under development for CBMC. Checking the
|
||||
# assigns clause for function contracts and loop invariants currently
|
||||
# assumes loop-free bodies for loops and functions with contracts
|
||||
# (possibly after replacing nested loops with their own loop
|
||||
# contracts). To satisfy this requirement, it may be necessary to
|
||||
# unwind some loops before the function contract and loop invariant
|
||||
# transformations are applied to the goto program. This variable
|
||||
# EARLY_UNWINDSET is identical to UNWINDSET, and we assume that the
|
||||
# loops mentioned in EARLY_UNWINDSET and UNWINDSET are disjoint.
|
||||
EARLY_UNWINDSET ?=
|
||||
|
||||
# CBMC function removal (Normally set set in the proof Makefile)
|
||||
#
|
||||
# REMOVE_FUNCTION_BODY is a list of function names. CBMC will "undefine"
|
||||
# the function, and CBMC will treat the function as having no side effects
|
||||
# and returning an unconstrained value of the appropriate return type.
|
||||
# The list should include the names of functions being stubbed out.
|
||||
REMOVE_FUNCTION_BODY ?=
|
||||
|
||||
# CBMC function pointer restriction (Normally set in the proof Makefile)
|
||||
#
|
||||
# RESTRICT_FUNCTION_POINTER is a list of function pointer restriction
|
||||
# instructions of the form:
|
||||
#
|
||||
# <fun_id>.function_pointer_call.<N>/<fun_id>[,<fun_id>]*
|
||||
#
|
||||
# The function pointer call number <N> in the specified function gets
|
||||
# rewritten to a case switch over a finite list of functions.
|
||||
# If some possible target functions are omitted from the list a counter
|
||||
# example trace will be found by CBMC, i.e. the transformation is sound.
|
||||
# If the target functions are file-local symbols, then mangled names must
|
||||
# be used.
|
||||
RESTRICT_FUNCTION_POINTER ?=
|
||||
|
||||
# The project source files (Normally set set in the proof Makefile)
|
||||
#
|
||||
# PROJECT_SOURCES is the list of project source files to compile,
|
||||
# including the source file defining the function under test.
|
||||
PROJECT_SOURCES ?=
|
||||
|
||||
# The proof source files (Normally set in the proof Makefile)
|
||||
#
|
||||
# PROOF_SOURCES is the list of proof source files to compile, including
|
||||
# the proof harness, and including any function stubs being used.
|
||||
PROOF_SOURCES ?=
|
||||
|
||||
# The number of seconds that CBMC should be allowed to run for before
|
||||
# being forcefully terminated. Currently, this is set to be less than
|
||||
# the time limit for a CodeBuild job, which is eight hours. If a proof
|
||||
# run takes longer than the time limit of the CI environment, the
|
||||
# environment will halt the proof run without updating the Litani
|
||||
# report, making the proof run appear to "hang".
|
||||
CBMC_TIMEOUT ?= 21600
|
||||
|
||||
# Proof writers could add function contracts in their source code.
|
||||
# These contracts are ignored by default, but may be enabled in two distinct
|
||||
# contexts using the following two variables:
|
||||
# 1. To check whether one or more function contracts are sound with respect to
|
||||
# the function implementation, CHECK_FUNCTION_CONTRACTS should be a list of
|
||||
# function names.
|
||||
# 2. To replace calls to certain functions with their correspondent function
|
||||
# contracts, USE_FUNCTION_CONTRACTS should be a list of function names.
|
||||
# One must check separately whether a function contract is sound before
|
||||
# replacing it in calling contexts.
|
||||
CHECK_FUNCTION_CONTRACTS ?=
|
||||
CBMC_CHECK_FUNCTION_CONTRACTS := $(patsubst %,--enforce-contract %, $(CHECK_FUNCTION_CONTRACTS))
|
||||
|
||||
USE_FUNCTION_CONTRACTS ?=
|
||||
CBMC_USE_FUNCTION_CONTRACTS := $(patsubst %,--replace-call-with-contract %, $(USE_FUNCTION_CONTRACTS))
|
||||
|
||||
# Similarly, proof writers could also add loop contracts in their source code
|
||||
# to obtain unbounded correctness proofs. Unlike function contracts, loop
|
||||
# contracts are not reusable and thus are checked and used simultaneously.
|
||||
# These contracts are also ignored by default, but may be enabled by setting
|
||||
# the APPLY_LOOP_CONTRACTS variable to 1.
|
||||
APPLY_LOOP_CONTRACTS ?= 0
|
||||
ifeq ($(APPLY_LOOP_CONTRACTS),1)
|
||||
CBMC_APPLY_LOOP_CONTRACTS ?= --apply-loop-contracts
|
||||
endif
|
||||
|
||||
# Silence makefile output (eg, long litani commands) unless VERBOSE is set.
|
||||
ifndef VERBOSE
|
||||
MAKEFLAGS := $(MAKEFLAGS) -s
|
||||
endif
|
||||
|
||||
################################################################
|
||||
################################################################
|
||||
## Section II: This section defines the process of running a proof
|
||||
##
|
||||
## There should be no reason to edit anything below this line.
|
||||
|
||||
################################################################
|
||||
# Paths
|
||||
|
||||
CBMC ?= cbmc
|
||||
GOTO_ANALYZER ?= goto-analyzer
|
||||
GOTO_CC ?= goto-cc
|
||||
GOTO_INSTRUMENT ?= goto-instrument
|
||||
CRANGLER ?= crangler
|
||||
VIEWER ?= cbmc-viewer
|
||||
MAKE_SOURCE ?= make-source
|
||||
VIEWER2 ?= cbmc-viewer
|
||||
CMAKE ?= cmake
|
||||
|
||||
GOTODIR ?= $(PROOFDIR)/gotos
|
||||
LOGDIR ?= $(PROOFDIR)/logs
|
||||
|
||||
PROJECT ?= project
|
||||
PROOF ?= proof
|
||||
|
||||
HARNESS_GOTO ?= $(GOTODIR)/$(HARNESS_FILE)
|
||||
PROJECT_GOTO ?= $(GOTODIR)/$(PROJECT)
|
||||
PROOF_GOTO ?= $(GOTODIR)/$(PROOF)
|
||||
|
||||
################################################################
|
||||
# Useful macros for values that are hard to reference
|
||||
SPACE :=$() $()
|
||||
COMMA :=,
|
||||
|
||||
################################################################
|
||||
# Set C compiler defines
|
||||
|
||||
CBMCFLAGS += --object-bits $(CBMC_OBJECT_BITS)
|
||||
COMPILE_FLAGS += --object-bits $(CBMC_OBJECT_BITS)
|
||||
|
||||
DEFINES += -DCBMC=1
|
||||
DEFINES += -DCBMC_OBJECT_BITS=$(CBMC_OBJECT_BITS)
|
||||
DEFINES += -DCBMC_MAX_OBJECT_SIZE="(SIZE_MAX>>(CBMC_OBJECT_BITS+1))"
|
||||
|
||||
# CI currently assumes cbmc invocation has at most one --unwindset
|
||||
ifdef UNWINDSET
|
||||
ifneq ($(strip $(UNWINDSET)),"")
|
||||
CBMC_UNWINDSET := --unwindset $(subst $(SPACE),$(COMMA),$(strip $(UNWINDSET)))
|
||||
endif
|
||||
endif
|
||||
ifdef EARLY_UNWINDSET
|
||||
ifneq ($(strip $(EARLY_UNWINDSET)),"")
|
||||
CBMC_EARLY_UNWINDSET := --unwindset $(subst $(SPACE),$(COMMA),$(strip $(EARLY_UNWINDSET)))
|
||||
endif
|
||||
endif
|
||||
|
||||
CBMC_REMOVE_FUNCTION_BODY := $(patsubst %,--remove-function-body %, $(REMOVE_FUNCTION_BODY))
|
||||
CBMC_RESTRICT_FUNCTION_POINTER := $(patsubst %,--restrict-function-pointer %, $(RESTRICT_FUNCTION_POINTER))
|
||||
|
||||
################################################################
|
||||
# Targets for rewriting source files with crangler
|
||||
|
||||
# Construct crangler configuration files
|
||||
#
|
||||
# REWRITTEN_SOURCES is a list of crangler output files source.i.
|
||||
# This target assumes that for each source.i
|
||||
# * source.i_SOURCE is the path to a source file,
|
||||
# * source.i_FUNCTIONS is a list of functions (may be empty)
|
||||
# * source.i_OBJECTS is a list of variables (may be empty)
|
||||
# This target constructs the crangler configuration file source.i.json
|
||||
# of the form
|
||||
# {
|
||||
# "sources": [ "/proj/code.c" ],
|
||||
# "includes": [ "/proj/include" ],
|
||||
# "defines": [ "VAR=1" ],
|
||||
# "functions": [ {"function_name": ["remove static"]} ],
|
||||
# "objects": [ {"variable_name": ["remove static"]} ],
|
||||
# "output": "source.i"
|
||||
# }
|
||||
# to remove the static attribute from function_name and variable_name
|
||||
# in the source file source.c and write the result to source.i.
|
||||
#
|
||||
# This target assumes that filenames include no spaces and that
|
||||
# the INCLUDES and DEFINES variables include no spaces after -I
|
||||
# and -D. For example, use "-DVAR=1" and not "-D VAR=1".
|
||||
#
|
||||
# Define *_SOURCE, *_FUNCTIONS, and *_OBJECTS in the proof Makefile.
|
||||
# The string source.i is usually an absolute path $(PROOFDIR)/code.i
|
||||
# to a file in the proof directory that contains the proof Makefile.
|
||||
# The proof Makefile usually includes the definitions
|
||||
# $(PROOFDIR)/code.i_SOURCE = /proj/code.c
|
||||
# $(PROOFDIR)/code.i_FUNCTIONS = function_name
|
||||
# $(PROOFDIR)/code.i_OBJECTS = variable_name
|
||||
# Because these definitions refer to PROOFDIR that is defined in this
|
||||
# Makefile.common, these definitions must appear after the inclusion
|
||||
# of Makefile.common in the proof Makefile.
|
||||
#
|
||||
$(foreach rs,$(REWRITTEN_SOURCES),$(eval $(rs).json: $($(rs)_SOURCE)))
|
||||
$(foreach rs,$(REWRITTEN_SOURCES),$(rs).json):
|
||||
echo '{'\
|
||||
'"sources": ['\
|
||||
'"$($(@:.json=)_SOURCE)"'\
|
||||
'],'\
|
||||
'"includes": ['\
|
||||
'$(subst $(SPACE),$(COMMA),$(patsubst -I%,"%",$(strip $(INCLUDES))))' \
|
||||
'],'\
|
||||
'"defines": ['\
|
||||
'$(subst $(SPACE),$(COMMA),$(patsubst -D%,"%",$(subst ",\",$(strip $(DEFINES)))))' \
|
||||
'],'\
|
||||
'"functions": ['\
|
||||
'{'\
|
||||
'$(subst ~, ,$(subst $(SPACE),$(COMMA),$(patsubst %,"%":["remove~static"],$($(@:.json=)_FUNCTIONS))))' \
|
||||
'}'\
|
||||
'],'\
|
||||
'"objects": ['\
|
||||
'{'\
|
||||
'$(subst ~, ,$(subst $(SPACE),$(COMMA),$(patsubst %,"%":["remove~static"],$($(@:.json=)_OBJECTS))))' \
|
||||
'}'\
|
||||
'],'\
|
||||
'"output": "$(@:.json=)"'\
|
||||
'}' > $@
|
||||
|
||||
# Rewrite source files with crangler
|
||||
#
|
||||
$(foreach rs,$(REWRITTEN_SOURCES),$(eval $(rs): $(rs).json))
|
||||
$(REWRITTEN_SOURCES):
|
||||
$(LITANI) add-job \
|
||||
--command \
|
||||
'$(CRANGLER) $@.json' \
|
||||
--inputs $($@_SOURCE) \
|
||||
--outputs $@ \
|
||||
--stdout-file $(LOGDIR)/crangler-$(subst /,_,$(subst .,_,$@))-log.txt \
|
||||
--interleave-stdout-stderr \
|
||||
--pipeline-name "$(PROOF_UID)" \
|
||||
--ci-stage build \
|
||||
--description "$(PROOF_UID): removing static"
|
||||
|
||||
################################################################
|
||||
# Build targets that make the relevant .goto files
|
||||
|
||||
# Compile project sources
|
||||
$(PROJECT_GOTO)1.goto: $(PROJECT_SOURCES) $(REWRITTEN_SOURCES)
|
||||
$(LITANI) add-job \
|
||||
--command \
|
||||
'$(GOTO_CC) $(CBMC_VERBOSITY) $(COMPILE_FLAGS) $(EXPORT_FILE_LOCAL_SYMBOLS) $(INCLUDES) $(DEFINES) $^ -o $@' \
|
||||
--inputs $^ \
|
||||
--outputs $@ \
|
||||
--stdout-file $(LOGDIR)/project_sources-log.txt \
|
||||
--pipeline-name "$(PROOF_UID)" \
|
||||
--ci-stage build \
|
||||
--description "$(PROOF_UID): building project binary"
|
||||
|
||||
# Compile proof sources
|
||||
$(PROOF_GOTO)1.goto: $(PROOF_SOURCES)
|
||||
$(LITANI) add-job \
|
||||
--command \
|
||||
'$(GOTO_CC) $(CBMC_VERBOSITY) $(COMPILE_FLAGS) $(EXPORT_FILE_LOCAL_SYMBOLS) $(INCLUDES) $(DEFINES) $^ -o $@' \
|
||||
--inputs $^ \
|
||||
--outputs $@ \
|
||||
--stdout-file $(LOGDIR)/proof_sources-log.txt \
|
||||
--pipeline-name "$(PROOF_UID)" \
|
||||
--ci-stage build \
|
||||
--description "$(PROOF_UID): building proof binary"
|
||||
|
||||
# Remove function bodies from project sources
|
||||
$(PROJECT_GOTO)2.goto: $(PROJECT_GOTO)1.goto
|
||||
$(LITANI) add-job \
|
||||
--command \
|
||||
'$(GOTO_INSTRUMENT) $(CBMC_VERBOSITY) $(CBMC_REMOVE_FUNCTION_BODY) $^ $@' \
|
||||
--inputs $^ \
|
||||
--outputs $@ \
|
||||
--stdout-file $(LOGDIR)/remove_function_body-log.txt \
|
||||
--pipeline-name "$(PROOF_UID)" \
|
||||
--ci-stage build \
|
||||
--description "$(PROOF_UID): removing function bodies from project sources"
|
||||
|
||||
# Link project and proof sources into the proof harness
|
||||
$(HARNESS_GOTO)1.goto: $(PROOF_GOTO)1.goto $(PROJECT_GOTO)2.goto
|
||||
$(LITANI) add-job \
|
||||
--command '$(GOTO_CC) $(CBMC_VERBOSITY) --function $(HARNESS_ENTRY) $^ $(LINK_FLAGS) -o $@' \
|
||||
--inputs $^ \
|
||||
--outputs $@ \
|
||||
--stdout-file $(LOGDIR)/link_proof_project-log.txt \
|
||||
--pipeline-name "$(PROOF_UID)" \
|
||||
--ci-stage build \
|
||||
--description "$(PROOF_UID): linking project to proof"
|
||||
|
||||
# Restrict function pointers
|
||||
$(HARNESS_GOTO)2.goto: $(HARNESS_GOTO)1.goto
|
||||
$(LITANI) add-job \
|
||||
--command \
|
||||
'$(GOTO_INSTRUMENT) $(CBMC_VERBOSITY) $(CBMC_RESTRICT_FUNCTION_POINTER) $^ $@' \
|
||||
--inputs $^ \
|
||||
--outputs $@ \
|
||||
--stdout-file $(LOGDIR)/restrict_function_pointer-log.txt \
|
||||
--pipeline-name "$(PROOF_UID)" \
|
||||
--ci-stage build \
|
||||
--description "$(PROOF_UID): restricting function pointers in project sources"
|
||||
|
||||
# Fill static variable with unconstrained values
|
||||
$(HARNESS_GOTO)3.goto: $(HARNESS_GOTO)2.goto
|
||||
$(LITANI) add-job \
|
||||
--command \
|
||||
'$(GOTO_INSTRUMENT) $(CBMC_VERBOSITY) $(NONDET_STATIC) $^ $@' \
|
||||
--inputs $^ \
|
||||
--outputs $@ \
|
||||
--stdout-file $(LOGDIR)/nondet_static-log.txt \
|
||||
--pipeline-name "$(PROOF_UID)" \
|
||||
--ci-stage build \
|
||||
--description "$(PROOF_UID): setting static variables to nondet"
|
||||
|
||||
# Omit unused functions (sharpens coverage calculations)
|
||||
$(HARNESS_GOTO)4.goto: $(HARNESS_GOTO)3.goto
|
||||
$(LITANI) add-job \
|
||||
--command \
|
||||
'$(GOTO_INSTRUMENT) $(CBMC_VERBOSITY) --drop-unused-functions $^ $@' \
|
||||
--inputs $^ \
|
||||
--outputs $@ \
|
||||
--stdout-file $(LOGDIR)/drop_unused_functions-log.txt \
|
||||
--pipeline-name "$(PROOF_UID)" \
|
||||
--ci-stage build \
|
||||
--description "$(PROOF_UID): dropping unused functions"
|
||||
|
||||
# Omit initialization of unused global variables (reduces problem size)
|
||||
$(HARNESS_GOTO)5.goto: $(HARNESS_GOTO)4.goto
|
||||
$(LITANI) add-job \
|
||||
--command \
|
||||
'$(GOTO_INSTRUMENT) $(CBMC_VERBOSITY) --slice-global-inits $^ $@' \
|
||||
--inputs $^ \
|
||||
--outputs $@ \
|
||||
--stdout-file $(LOGDIR)/slice_global_inits-log.txt \
|
||||
--pipeline-name "$(PROOF_UID)" \
|
||||
--ci-stage build \
|
||||
--description "$(PROOF_UID): slicing global initializations"
|
||||
|
||||
# Replace function calls with function contracts
|
||||
# This must be done before enforcing function contracts,
|
||||
# since contract enforcement inlines all function calls.
|
||||
$(HARNESS_GOTO)6.goto: $(HARNESS_GOTO)5.goto
|
||||
$(LITANI) add-job \
|
||||
--command \
|
||||
'$(GOTO_INSTRUMENT) $(CBMC_VERBOSITY) $(CBMC_USE_FUNCTION_CONTRACTS) $^ $@' \
|
||||
--inputs $^ \
|
||||
--outputs $@ \
|
||||
--stdout-file $(LOGDIR)/use_function_contracts-log.txt \
|
||||
--pipeline-name "$(PROOF_UID)" \
|
||||
--ci-stage build \
|
||||
--description "$(PROOF_UID): replacing function calls with function contracts"
|
||||
|
||||
# Unwind loops for loop and function contracts
|
||||
$(HARNESS_GOTO)7.goto: $(HARNESS_GOTO)6.goto
|
||||
$(LITANI) add-job \
|
||||
--command \
|
||||
'$(GOTO_INSTRUMENT) $(CBMC_VERBOSITY) $(CBMC_EARLY_UNWINDSET) $(CBMC_FLAG_UNWINDING_ASSERTIONS) $^ $@' \
|
||||
--inputs $^ \
|
||||
--outputs $@ \
|
||||
--stdout-file $(LOGDIR)/unwind_loops-log.txt \
|
||||
--pipeline-name "$(PROOF_UID)" \
|
||||
--ci-stage build \
|
||||
--description "$(PROOF_UID): unwinding loops"
|
||||
|
||||
# Apply loop contracts
|
||||
$(HARNESS_GOTO)8.goto: $(HARNESS_GOTO)7.goto
|
||||
$(LITANI) add-job \
|
||||
--command \
|
||||
'$(GOTO_INSTRUMENT) $(CBMC_VERBOSITY) $(CBMC_APPLY_LOOP_CONTRACTS) $^ $@' \
|
||||
--inputs $^ \
|
||||
--outputs $@ \
|
||||
--stdout-file $(LOGDIR)/apply_loop_contracts-log.txt \
|
||||
--pipeline-name "$(PROOF_UID)" \
|
||||
--ci-stage build \
|
||||
--description "$(PROOF_UID): applying loop contracts"
|
||||
|
||||
# Check function contracts
|
||||
$(HARNESS_GOTO)9.goto: $(HARNESS_GOTO)8.goto
|
||||
$(LITANI) add-job \
|
||||
--command \
|
||||
'$(GOTO_INSTRUMENT) $(CBMC_VERBOSITY) $(CBMC_CHECK_FUNCTION_CONTRACTS) $^ $@' \
|
||||
--inputs $^ \
|
||||
--outputs $@ \
|
||||
--stdout-file $(LOGDIR)/check_function_contracts-log.txt \
|
||||
--pipeline-name "$(PROOF_UID)" \
|
||||
--ci-stage build \
|
||||
--description "$(PROOF_UID): checking function contracts"
|
||||
|
||||
# Final name for proof harness
|
||||
$(HARNESS_GOTO).goto: $(HARNESS_GOTO)9.goto
|
||||
$(LITANI) add-job \
|
||||
--command 'cp $< $@' \
|
||||
--inputs $^ \
|
||||
--outputs $@ \
|
||||
--pipeline-name "$(PROOF_UID)" \
|
||||
--ci-stage build \
|
||||
--description "$(PROOF_UID): copying final goto-binary"
|
||||
|
||||
################################################################
|
||||
# Targets to run the analysis commands
|
||||
|
||||
$(LOGDIR)/result.txt: $(HARNESS_GOTO).goto
|
||||
$(LITANI) add-job \
|
||||
$(POOL) \
|
||||
--command \
|
||||
'$(CBMC) $(CBMC_VERBOSITY) $(CBMCFLAGS) $(CBMC_FLAG_UNWINDING_ASSERTIONS) $(CHECKFLAGS) --trace $<' \
|
||||
--inputs $^ \
|
||||
--outputs $@ \
|
||||
--ci-stage test \
|
||||
--stdout-file $@ \
|
||||
$(MEMORY_PROFILING) \
|
||||
--ignore-returns 10 \
|
||||
--timeout $(CBMC_TIMEOUT) \
|
||||
--pipeline-name "$(PROOF_UID)" \
|
||||
--tags "stats-group:safety checks" \
|
||||
--stderr-file $(LOGDIR)/result-err-log.txt \
|
||||
--description "$(PROOF_UID): checking safety properties"
|
||||
|
||||
$(LOGDIR)/result.xml: $(HARNESS_GOTO).goto
|
||||
$(LITANI) add-job \
|
||||
$(POOL) \
|
||||
--command \
|
||||
'$(CBMC) $(CBMC_VERBOSITY) $(CBMCFLAGS) $(CBMC_FLAG_UNWINDING_ASSERTIONS) $(CHECKFLAGS) --trace --xml-ui $<' \
|
||||
--inputs $^ \
|
||||
--outputs $@ \
|
||||
--ci-stage test \
|
||||
--stdout-file $@ \
|
||||
$(MEMORY_PROFILING) \
|
||||
--ignore-returns 10 \
|
||||
--timeout $(CBMC_TIMEOUT) \
|
||||
--pipeline-name "$(PROOF_UID)" \
|
||||
--tags "stats-group:safety checks" \
|
||||
--stderr-file $(LOGDIR)/result-err-log.txt \
|
||||
--description "$(PROOF_UID): checking safety properties"
|
||||
|
||||
$(LOGDIR)/property.xml: $(HARNESS_GOTO).goto
|
||||
$(LITANI) add-job \
|
||||
--command \
|
||||
'$(CBMC) $(CBMC_VERBOSITY) $(CBMCFLAGS) $(CBMC_FLAG_UNWINDING_ASSERTIONS) $(CHECKFLAGS) --show-properties --xml-ui $<' \
|
||||
--inputs $^ \
|
||||
--outputs $@ \
|
||||
--ci-stage test \
|
||||
--stdout-file $@ \
|
||||
--ignore-returns 10 \
|
||||
--pipeline-name "$(PROOF_UID)" \
|
||||
--stderr-file $(LOGDIR)/property-err-log.txt \
|
||||
--description "$(PROOF_UID): printing safety properties"
|
||||
|
||||
$(LOGDIR)/coverage.xml: $(HARNESS_GOTO).goto
|
||||
$(LITANI) add-job \
|
||||
$(POOL) \
|
||||
--command \
|
||||
'$(CBMC) $(CBMC_VERBOSITY) $(CBMCFLAGS) $(COVERFLAGS) --cover location --xml-ui $<' \
|
||||
--inputs $^ \
|
||||
--outputs $@ \
|
||||
--ci-stage test \
|
||||
--stdout-file $@ \
|
||||
$(MEMORY_PROFILING) \
|
||||
--ignore-returns 10 \
|
||||
--timeout $(CBMC_TIMEOUT) \
|
||||
--pipeline-name "$(PROOF_UID)" \
|
||||
--tags "stats-group:coverage computation" \
|
||||
--stderr-file $(LOGDIR)/coverage-err-log.txt \
|
||||
--description "$(PROOF_UID): calculating coverage"
|
||||
|
||||
define VIEWER_CMD
|
||||
$(VIEWER) \
|
||||
--result $(LOGDIR)/result.txt \
|
||||
--block $(LOGDIR)/coverage.xml \
|
||||
--property $(LOGDIR)/property.xml \
|
||||
--srcdir $(SRCDIR) \
|
||||
--goto $(HARNESS_GOTO).goto \
|
||||
--htmldir $(PROOFDIR)/html
|
||||
endef
|
||||
export VIEWER_CMD
|
||||
|
||||
$(PROOFDIR)/html: $(LOGDIR)/result.txt $(LOGDIR)/property.xml $(LOGDIR)/coverage.xml
|
||||
$(LITANI) add-job \
|
||||
--command "$$VIEWER_CMD" \
|
||||
--inputs $^ \
|
||||
--outputs $(PROOFDIR)/html \
|
||||
--pipeline-name "$(PROOF_UID)" \
|
||||
--ci-stage report \
|
||||
--stdout-file $(LOGDIR)/viewer-log.txt \
|
||||
--description "$(PROOF_UID): generating report"
|
||||
|
||||
|
||||
# Caution: run make-source before running property and coverage checking
|
||||
# The current make-source script removes the goto binary
|
||||
$(LOGDIR)/source.json:
|
||||
mkdir -p $(dir $@)
|
||||
$(RM) -r $(GOTODIR)
|
||||
$(MAKE_SOURCE) --srcdir $(SRCDIR) --wkdir $(PROOFDIR) > $@
|
||||
$(RM) -r $(GOTODIR)
|
||||
|
||||
define VIEWER2_CMD
|
||||
$(VIEWER2) \
|
||||
--result $(LOGDIR)/result.xml \
|
||||
--coverage $(LOGDIR)/coverage.xml \
|
||||
--property $(LOGDIR)/property.xml \
|
||||
--srcdir $(SRCDIR) \
|
||||
--goto $(HARNESS_GOTO).goto \
|
||||
--reportdir $(PROOFDIR)/report \
|
||||
--config $(PROOFDIR)/cbmc-viewer.json
|
||||
endef
|
||||
export VIEWER2_CMD
|
||||
|
||||
# Omit logs/source.json from report generation until make-sources
|
||||
# works correctly with Makefiles that invoke the compiler with
|
||||
# mutliple source files at once.
|
||||
$(PROOFDIR)/report: $(LOGDIR)/result.xml $(LOGDIR)/property.xml $(LOGDIR)/coverage.xml
|
||||
$(LITANI) add-job \
|
||||
--command "$$VIEWER2_CMD" \
|
||||
--inputs $^ \
|
||||
--outputs $(PROOFDIR)/report \
|
||||
--pipeline-name "$(PROOF_UID)" \
|
||||
--stdout-file $(LOGDIR)/viewer-log.txt \
|
||||
--ci-stage report \
|
||||
--description "$(PROOF_UID): generating report"
|
||||
|
||||
litani-path:
|
||||
@echo $(LITANI)
|
||||
|
||||
# ##############################################################
|
||||
# Phony Rules
|
||||
#
|
||||
# These rules provide a convenient way to run a single proof up to a
|
||||
# certain stage. Users can browse into a proof directory and run
|
||||
# "make -Bj 3 report" to generate a report for just that proof, or
|
||||
# "make goto" to build the goto binary. Under the hood, this runs litani
|
||||
# for just that proof.
|
||||
|
||||
_goto: $(HARNESS_GOTO).goto
|
||||
goto:
|
||||
@ echo Running 'litani init'
|
||||
$(LITANI) init --project $(PROJECT_NAME)
|
||||
@ echo Running 'litani add-job'
|
||||
$(MAKE) -B _goto
|
||||
@ echo Running 'litani build'
|
||||
$(LITANI) run-build
|
||||
|
||||
_result: $(LOGDIR)/result.txt
|
||||
result:
|
||||
@ echo Running 'litani init'
|
||||
$(LITANI) init --project $(PROJECT_NAME)
|
||||
@ echo Running 'litani add-job'
|
||||
$(MAKE) -B _result
|
||||
@ echo Running 'litani build'
|
||||
$(LITANI) run-build
|
||||
|
||||
_property: $(LOGDIR)/property.xml
|
||||
property:
|
||||
@ echo Running 'litani init'
|
||||
$(LITANI) init --project $(PROJECT_NAME)
|
||||
@ echo Running 'litani add-job'
|
||||
$(MAKE) -B _property
|
||||
@ echo Running 'litani build'
|
||||
$(LITANI) run-build
|
||||
|
||||
_coverage: $(LOGDIR)/coverage.xml
|
||||
coverage:
|
||||
@ echo Running 'litani init'
|
||||
$(LITANI) init --project $(PROJECT_NAME)
|
||||
@ echo Running 'litani add-job'
|
||||
$(MAKE) -B _coverage
|
||||
@ echo Running 'litani build'
|
||||
$(LITANI) run-build
|
||||
|
||||
# Choose the invocation of cbmc-viewer depending on which version of
|
||||
# cbmc-viewer is installed. The --version flag is not implemented in
|
||||
# version 1 --- it is an "unrecognized argument" --- but it is
|
||||
# implemented in version 2.
|
||||
_report1: $(PROOFDIR)/html
|
||||
_report2: $(PROOFDIR)/report
|
||||
_report:
|
||||
(cbmc-viewer --version 2>&1 | grep "unrecognized argument" > /dev/null) && \
|
||||
$(MAKE) -B _report1 || $(MAKE) -B _report2
|
||||
|
||||
report report1 report2:
|
||||
@ echo Running 'litani init'
|
||||
$(LITANI) init --project $(PROJECT_NAME)
|
||||
@ echo Running 'litani add-job'
|
||||
$(MAKE) -B _report
|
||||
@ echo Running 'litani build'
|
||||
$(LITANI) run-build
|
||||
|
||||
################################################################
|
||||
# Targets to clean up after ourselves
|
||||
clean:
|
||||
-$(RM) $(DEPENDENT_GOTOS)
|
||||
-$(RM) TAGS*
|
||||
-$(RM) *~ \#*
|
||||
-$(RM) $(REWRITTEN_SOURCES) $(foreach rs,$(REWRITTEN_SOURCES),$(rs).json)
|
||||
|
||||
veryclean: clean
|
||||
-$(RM) -r html report
|
||||
-$(RM) -r $(LOGDIR) $(GOTODIR)
|
||||
|
||||
.PHONY: \
|
||||
_coverage \
|
||||
_goto \
|
||||
_property \
|
||||
_report \
|
||||
_report2 \
|
||||
_result \
|
||||
clean \
|
||||
coverage \
|
||||
goto \
|
||||
litani-path \
|
||||
property \
|
||||
report \
|
||||
report2 \
|
||||
result \
|
||||
setup_dependencies \
|
||||
testdeps \
|
||||
veryclean \
|
||||
#
|
||||
|
||||
################################################################
|
||||
|
||||
# Rule for generating cbmc-batch.yaml, used by the CI at
|
||||
# https://github.com/awslabs/aws-batch-cbmc/
|
||||
|
||||
JOB_OS ?= ubuntu16
|
||||
JOB_MEMORY ?= 32000
|
||||
|
||||
# Proofs that are expected to fail should set EXPECTED to
|
||||
# "FAILED" in their Makefile. Values other than SUCCESSFUL
|
||||
# or FAILED will cause a CI error.
|
||||
EXPECTED ?= SUCCESSFUL
|
||||
|
||||
define yaml_encode_options
|
||||
"$(shell echo $(1) | sed 's/ ,/ /g' | sed 's/ /;/g')"
|
||||
endef
|
||||
|
||||
CI_FLAGS = $(CBMCFLAGS) $(CHECKFLAGS) $(COVERFLAGS)
|
||||
|
||||
cbmc-batch.yaml:
|
||||
@$(RM) $@
|
||||
@echo 'build_memory: $(JOB_MEMORY)' > $@
|
||||
@echo 'cbmcflags: $(strip $(call yaml_encode_options,$(CI_FLAGS)))' >> $@
|
||||
@echo 'coverage_memory: $(JOB_MEMORY)' >> $@
|
||||
@echo 'expected: $(EXPECTED)' >> $@
|
||||
@echo 'goto: $(HARNESS_GOTO).goto' >> $@
|
||||
@echo 'jobos: $(JOB_OS)' >> $@
|
||||
@echo 'property_memory: $(JOB_MEMORY)' >> $@
|
||||
@echo 'report_memory: $(JOB_MEMORY)' >> $@
|
||||
|
||||
.PHONY: cbmc-batch.yaml
|
||||
|
||||
################################################################
|
||||
|
||||
# Run "make echo-proof-uid" to print the proof ID of a proof. This can be
|
||||
# used by scripts to ensure that every proof has an ID, that there are
|
||||
# no duplicates, etc.
|
||||
|
||||
.PHONY: echo-proof-uid
|
||||
echo-proof-uid:
|
||||
@echo $(PROOF_UID)
|
||||
|
||||
.PHONY: echo-project-name
|
||||
echo-project-name:
|
||||
@echo $(PROJECT_NAME)
|
||||
|
||||
################################################################
|
||||
|
||||
# Project-specific targets requiring values defined above
|
||||
sinclude $(PROOF_ROOT)/Makefile-project-targets
|
||||
|
||||
# CI-specific targets to drive cbmc in CI
|
||||
sinclude $(PROOF_ROOT)/Makefile-project-testing
|
||||
|
||||
################################################################
|
||||
@ -0,0 +1,27 @@
|
||||
CBMC proofs
|
||||
===========
|
||||
|
||||
This directory contains the CBMC proofs. Each proof is in its own
|
||||
directory.
|
||||
|
||||
This directory includes four Makefiles.
|
||||
|
||||
One Makefile describes the basic workflow for building and running proofs:
|
||||
|
||||
* Makefile.common:
|
||||
* make: builds the goto binary, does the cbmc property checking
|
||||
and coverage checking, and builds the final report.
|
||||
* make goto: builds the goto binary
|
||||
* make result: does cbmc property checking
|
||||
* make coverage: does cbmc coverage checking
|
||||
* make report: builds the final report
|
||||
|
||||
Three included Makefiles describe project-specific settings and can override
|
||||
definitions in Makefile.common:
|
||||
|
||||
* Makefile-project-defines: definitions like compiler flags
|
||||
required to build the goto binaries, and definitions to override
|
||||
definitions in Makefile.common.
|
||||
* Makefile-project-targets: other make targets needed for the project
|
||||
* Makefile-project-testing: other definitions and targets needed for
|
||||
unit testing or continuous integration.
|
||||
@ -0,0 +1,92 @@
|
||||
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
# SPDX-License-Identifier: MIT-0
|
||||
|
||||
import json
|
||||
import logging
|
||||
|
||||
|
||||
def _get_max_length_per_column_list(data):
|
||||
ret = [len(item) + 1 for item in data[0]]
|
||||
for row in data[1:]:
|
||||
for idx, item in enumerate(row):
|
||||
ret[idx] = max(ret[idx], len(item) + 1)
|
||||
return ret
|
||||
|
||||
|
||||
def _get_table_header_separator(max_length_per_column_list):
|
||||
line_sep = ""
|
||||
for max_length_of_word_in_col in max_length_per_column_list:
|
||||
line_sep += "|" + "-" * (max_length_of_word_in_col + 1)
|
||||
line_sep += "|\n"
|
||||
return line_sep
|
||||
|
||||
|
||||
def _get_entries(max_length_per_column_list, row_data):
|
||||
entries = []
|
||||
for row in row_data:
|
||||
entry = ""
|
||||
for idx, word in enumerate(row):
|
||||
max_length_of_word_in_col = max_length_per_column_list[idx]
|
||||
space_formatted_word = (max_length_of_word_in_col - len(word)) * " "
|
||||
entry += "| " + word + space_formatted_word
|
||||
entry += "|\n"
|
||||
entries.append(entry)
|
||||
return entries
|
||||
|
||||
|
||||
def _get_rendered_table(data):
|
||||
table = []
|
||||
max_length_per_column_list = _get_max_length_per_column_list(data)
|
||||
entries = _get_entries(max_length_per_column_list, data)
|
||||
for idx, entry in enumerate(entries):
|
||||
if idx == 1:
|
||||
line_sep = _get_table_header_separator(max_length_per_column_list)
|
||||
table.append(line_sep)
|
||||
table.append(entry)
|
||||
table.append("\n")
|
||||
return "".join(table)
|
||||
|
||||
|
||||
def _get_status_and_proof_summaries(run_dict):
|
||||
"""Parse a dict representing a Litani run and create lists summarizing the
|
||||
proof results.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
run_dict
|
||||
A dictionary representing a Litani run.
|
||||
|
||||
Returns
|
||||
-------
|
||||
A list of 2 lists.
|
||||
The first sub-list maps a status to the number of proofs with that status.
|
||||
The second sub-list maps each proof to its status.
|
||||
"""
|
||||
count_statuses = {}
|
||||
proofs = [["Proof", "Status"]]
|
||||
for proof_pipeline in run_dict["pipelines"]:
|
||||
status_pretty_name = proof_pipeline["status"].title().replace("_", " ")
|
||||
try:
|
||||
count_statuses[status_pretty_name] += 1
|
||||
except KeyError:
|
||||
count_statuses[status_pretty_name] = 1
|
||||
proof = proof_pipeline["name"]
|
||||
proofs.append([proof, status_pretty_name])
|
||||
statuses = [["Status", "Count"]]
|
||||
for status, count in count_statuses.items():
|
||||
statuses.append([status, str(count)])
|
||||
return [statuses, proofs]
|
||||
|
||||
|
||||
def print_proof_results(out_file):
|
||||
"""
|
||||
Print 2 strings that summarize the proof results.
|
||||
When printing, each string will render as a GitHub flavored Markdown table.
|
||||
"""
|
||||
try:
|
||||
with open(out_file, encoding='utf-8') as run_json:
|
||||
run_dict = json.load(run_json)
|
||||
for summary in _get_status_and_proof_summaries(run_dict):
|
||||
print(_get_rendered_table(summary))
|
||||
except Exception as ex: # pylint: disable=broad-except
|
||||
logging.critical("Could not print results. Exception: %s", str(ex))
|
||||
@ -0,0 +1,414 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
# SPDX-License-Identifier: MIT-0
|
||||
|
||||
|
||||
import argparse
|
||||
import asyncio
|
||||
import json
|
||||
import logging
|
||||
import math
|
||||
import os
|
||||
import pathlib
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
from lib.summarize import print_proof_results
|
||||
|
||||
|
||||
DESCRIPTION = "Configure and run all CBMC proofs in parallel"
|
||||
|
||||
# Keep the epilog hard-wrapped at 70 characters, as it gets printed
|
||||
# verbatim in the terminal. 70 characters stops here --------------> |
|
||||
EPILOG = """
|
||||
This tool automates the process of running `make report` in each of
|
||||
the CBMC proof directories. The tool calculates the dependency graph
|
||||
of all tasks needed to build, run, and report on all the proofs, and
|
||||
executes these tasks in parallel.
|
||||
|
||||
The tool is roughly equivalent to doing this:
|
||||
|
||||
litani init --project "my-cool-project";
|
||||
|
||||
find . -name cbmc-proof.txt | while read -r proof; do
|
||||
pushd $(dirname ${proof});
|
||||
|
||||
# The `make _report` rule adds a single proof to litani
|
||||
# without running it
|
||||
make _report;
|
||||
|
||||
popd;
|
||||
done
|
||||
|
||||
litani run-build;
|
||||
|
||||
except that it is much faster and provides some convenience options.
|
||||
The CBMC CI runs this script with no arguments to build and run all
|
||||
proofs in parallel. The value of "my-cool-project" is taken from the
|
||||
PROJECT_NAME variable in Makefile-project-defines.
|
||||
|
||||
The --no-standalone argument omits the `litani init` and `litani
|
||||
run-build`; use it when you want to add additional proof jobs, not
|
||||
just the CBMC ones. In that case, you would run `litani init`
|
||||
yourself; then run `run-cbmc-proofs --no-standalone`; add any
|
||||
additional jobs that you want to execute with `litani add-job`; and
|
||||
finally run `litani run-build`.
|
||||
|
||||
The litani dashboard will be written under the `output` directory; the
|
||||
cbmc-viewer reports remain in the `$PROOF_DIR/report` directory. The
|
||||
HTML dashboard from the latest Litani run will always be symlinked to
|
||||
`output/latest/html/index.html`, so you can keep that page open in
|
||||
your browser and reload the page whenever you re-run this script.
|
||||
"""
|
||||
# 70 characters stops here ----------------------------------------> |
|
||||
|
||||
|
||||
def get_project_name():
|
||||
cmd = [
|
||||
"make",
|
||||
"--no-print-directory",
|
||||
"-f", "Makefile.common",
|
||||
"echo-project-name",
|
||||
]
|
||||
logging.debug(" ".join(cmd))
|
||||
proc = subprocess.run(cmd, universal_newlines=True, stdout=subprocess.PIPE, check=False)
|
||||
if proc.returncode:
|
||||
logging.critical("could not run make to determine project name")
|
||||
sys.exit(1)
|
||||
if not proc.stdout.strip():
|
||||
logging.warning(
|
||||
"project name has not been set; using generic name instead. "
|
||||
"Set the PROJECT_NAME value in Makefile-project-defines to "
|
||||
"remove this warning")
|
||||
return "<PROJECT NAME HERE>"
|
||||
return proc.stdout.strip()
|
||||
|
||||
|
||||
def get_args():
|
||||
pars = argparse.ArgumentParser(
|
||||
description=DESCRIPTION, epilog=EPILOG,
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter)
|
||||
for arg in [{
|
||||
"flags": ["-j", "--parallel-jobs"],
|
||||
"type": int,
|
||||
"metavar": "N",
|
||||
"help": "run at most N proof jobs in parallel",
|
||||
}, {
|
||||
"flags": ["--fail-on-proof-failure"],
|
||||
"action": "store_true",
|
||||
"help": "exit with return code `10' if any proof failed"
|
||||
" (default: exit 0)",
|
||||
}, {
|
||||
"flags": ["--no-standalone"],
|
||||
"action": "store_true",
|
||||
"help": "only configure proofs: do not initialize nor run",
|
||||
}, {
|
||||
"flags": ["-p", "--proofs"],
|
||||
"nargs": "+",
|
||||
"metavar": "DIR",
|
||||
"help": "only run proof in directory DIR (can pass more than one)",
|
||||
}, {
|
||||
"flags": ["--project-name"],
|
||||
"metavar": "NAME",
|
||||
"default": get_project_name(),
|
||||
"help": "project name for report. Default: %(default)s",
|
||||
}, {
|
||||
"flags": ["--marker-file"],
|
||||
"metavar": "FILE",
|
||||
"default": "cbmc-proof.txt",
|
||||
"help": (
|
||||
"name of file that marks proof directories. Default: "
|
||||
"%(default)s"),
|
||||
}, {
|
||||
"flags": ["--no-memory-profile"],
|
||||
"action": "store_true",
|
||||
"help": "disable memory profiling, even if Litani supports it"
|
||||
}, {
|
||||
"flags": ["--no-expensive-limit"],
|
||||
"action": "store_true",
|
||||
"help": "do not limit parallelism of 'EXPENSIVE' jobs",
|
||||
}, {
|
||||
"flags": ["--expensive-jobs-parallelism"],
|
||||
"metavar": "N",
|
||||
"default": 1,
|
||||
"type": int,
|
||||
"help": (
|
||||
"how many proof jobs marked 'EXPENSIVE' to run in parallel. "
|
||||
"Default: %(default)s"),
|
||||
}, {
|
||||
"flags": ["--verbose"],
|
||||
"action": "store_true",
|
||||
"help": "verbose output",
|
||||
}, {
|
||||
"flags": ["--debug"],
|
||||
"action": "store_true",
|
||||
"help": "debug output",
|
||||
}, {
|
||||
"flags": ["--summarize"],
|
||||
"action": "store_true",
|
||||
"help": "summarize proof results with two tables on stdout",
|
||||
}, {
|
||||
"flags": ["--version"],
|
||||
"action": "version",
|
||||
"version": "CBMC starter kit 2.5",
|
||||
"help": "display version and exit"
|
||||
}]:
|
||||
flags = arg.pop("flags")
|
||||
pars.add_argument(*flags, **arg)
|
||||
return pars.parse_args()
|
||||
|
||||
|
||||
def set_up_logging(verbose):
|
||||
if verbose:
|
||||
level = logging.DEBUG
|
||||
else:
|
||||
level = logging.WARNING
|
||||
logging.basicConfig(
|
||||
format="run-cbmc-proofs: %(message)s", level=level)
|
||||
|
||||
|
||||
def task_pool_size():
|
||||
ret = os.cpu_count()
|
||||
if ret is None or ret < 3:
|
||||
return 1
|
||||
return ret - 2
|
||||
|
||||
|
||||
def print_counter(counter):
|
||||
# pylint: disable=consider-using-f-string
|
||||
print("\rConfiguring CBMC proofs: "
|
||||
"{complete:{width}} / {total:{width}}".format(**counter), end="", file=sys.stderr)
|
||||
|
||||
|
||||
def get_proof_dirs(proof_root, proof_list, marker_file):
|
||||
if proof_list is not None:
|
||||
proofs_remaining = list(proof_list)
|
||||
else:
|
||||
proofs_remaining = []
|
||||
|
||||
for root, _, fyles in os.walk(proof_root):
|
||||
proof_name = str(pathlib.Path(root).name)
|
||||
if root != str(proof_root) and ".litani_cache_dir" in fyles:
|
||||
pathlib.Path(f"{root}/.litani_cache_dir").unlink()
|
||||
if proof_list and proof_name not in proof_list:
|
||||
continue
|
||||
if proof_list and proof_name in proofs_remaining:
|
||||
proofs_remaining.remove(proof_name)
|
||||
if marker_file in fyles:
|
||||
yield root
|
||||
|
||||
if proofs_remaining:
|
||||
logging.critical(
|
||||
"The following proofs were not found: %s",
|
||||
", ".join(proofs_remaining))
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def run_build(litani, jobs, fail_on_proof_failure, summarize):
|
||||
cmd = [str(litani), "run-build"]
|
||||
if jobs:
|
||||
cmd.extend(["-j", str(jobs)])
|
||||
if fail_on_proof_failure:
|
||||
cmd.append("--fail-on-pipeline-failure")
|
||||
if summarize:
|
||||
out_file = pathlib.Path(tempfile.gettempdir(), "run.json").resolve()
|
||||
cmd.extend(["--out-file", str(out_file)])
|
||||
|
||||
logging.debug(" ".join(cmd))
|
||||
proc = subprocess.run(cmd, check=False)
|
||||
|
||||
if proc.returncode and not fail_on_proof_failure:
|
||||
logging.critical("Failed to run litani run-build")
|
||||
sys.exit(1)
|
||||
|
||||
if summarize:
|
||||
print_proof_results(out_file)
|
||||
out_file.unlink()
|
||||
|
||||
if proc.returncode:
|
||||
logging.error("One or more proofs failed")
|
||||
sys.exit(10)
|
||||
|
||||
def get_litani_path(proof_root):
|
||||
cmd = [
|
||||
"make",
|
||||
"--no-print-directory",
|
||||
f"PROOF_ROOT={proof_root}",
|
||||
"-f", "Makefile.common",
|
||||
"litani-path",
|
||||
]
|
||||
logging.debug(" ".join(cmd))
|
||||
proc = subprocess.run(cmd, universal_newlines=True, stdout=subprocess.PIPE, check=False)
|
||||
if proc.returncode:
|
||||
logging.critical("Could not determine path to litani")
|
||||
sys.exit(1)
|
||||
return proc.stdout.strip()
|
||||
|
||||
|
||||
def get_litani_capabilities(litani_path):
|
||||
cmd = [litani_path, "print-capabilities"]
|
||||
proc = subprocess.run(
|
||||
cmd, text=True, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, check=False)
|
||||
if proc.returncode:
|
||||
return []
|
||||
try:
|
||||
return json.loads(proc.stdout)
|
||||
except RuntimeError:
|
||||
logging.warning("Could not load litani capabilities: '%s'", proc.stdout)
|
||||
return []
|
||||
|
||||
|
||||
def check_uid_uniqueness(proof_dir, proof_uids):
|
||||
with (pathlib.Path(proof_dir) / "Makefile").open() as handle:
|
||||
for line in handle:
|
||||
match = re.match(r"^PROOF_UID\s*=\s*(?P<uid>\w+)", line)
|
||||
if not match:
|
||||
continue
|
||||
if match["uid"] not in proof_uids:
|
||||
proof_uids[match["uid"]] = proof_dir
|
||||
return
|
||||
|
||||
logging.critical(
|
||||
"The Makefile in directory '%s' should have a different "
|
||||
"PROOF_UID than the Makefile in directory '%s'",
|
||||
proof_dir, proof_uids[match["uid"]])
|
||||
sys.exit(1)
|
||||
|
||||
logging.critical(
|
||||
"The Makefile in directory '%s' should contain a line like", proof_dir)
|
||||
logging.critical("PROOF_UID = ...")
|
||||
logging.critical("with a unique identifier for the proof.")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def should_enable_memory_profiling(litani_caps, args):
|
||||
if args.no_memory_profile:
|
||||
return False
|
||||
return "memory_profile" in litani_caps
|
||||
|
||||
|
||||
def should_enable_pools(litani_caps, args):
|
||||
if args.no_expensive_limit:
|
||||
return False
|
||||
return "pools" in litani_caps
|
||||
|
||||
|
||||
async def configure_proof_dirs( # pylint: disable=too-many-arguments
|
||||
queue, counter, proof_uids, enable_pools, enable_memory_profiling, debug):
|
||||
while True:
|
||||
print_counter(counter)
|
||||
path = str(await queue.get())
|
||||
|
||||
check_uid_uniqueness(path, proof_uids)
|
||||
|
||||
pools = ["ENABLE_POOLS=true"] if enable_pools else []
|
||||
profiling = [
|
||||
"ENABLE_MEMORY_PROFILING=true"] if enable_memory_profiling else []
|
||||
|
||||
# Allow interactive tasks to preempt proof configuration
|
||||
proc = await asyncio.create_subprocess_exec(
|
||||
"nice", "-n", "15", "make", *pools,
|
||||
*profiling, "-B", "_report", "" if debug else "--quiet", cwd=path,
|
||||
stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE)
|
||||
stdout, stderr = await proc.communicate()
|
||||
logging.debug("returncode: %s", str(proc.returncode))
|
||||
logging.debug("stdout:")
|
||||
for line in stdout.decode().splitlines():
|
||||
logging.debug(line)
|
||||
logging.debug("stderr:")
|
||||
for line in stderr.decode().splitlines():
|
||||
logging.debug(line)
|
||||
|
||||
counter["fail" if proc.returncode else "pass"].append(path)
|
||||
counter["complete"] += 1
|
||||
|
||||
print_counter(counter)
|
||||
queue.task_done()
|
||||
|
||||
|
||||
async def main(): # pylint: disable=too-many-locals
|
||||
args = get_args()
|
||||
set_up_logging(args.verbose)
|
||||
|
||||
proof_root = pathlib.Path(os.getcwd())
|
||||
litani = get_litani_path(proof_root)
|
||||
|
||||
litani_caps = get_litani_capabilities(litani)
|
||||
enable_pools = should_enable_pools(litani_caps, args)
|
||||
init_pools = [
|
||||
"--pools", f"expensive:{args.expensive_jobs_parallelism}"
|
||||
] if enable_pools else []
|
||||
|
||||
if not args.no_standalone:
|
||||
cmd = [
|
||||
str(litani), "init", *init_pools, "--project", args.project_name,
|
||||
"--no-print-out-dir",
|
||||
]
|
||||
|
||||
if "output_directory_flags" in litani_caps:
|
||||
out_prefix = proof_root / "output"
|
||||
out_symlink = out_prefix / "latest"
|
||||
out_index = out_symlink / "html" / "index.html"
|
||||
cmd.extend([
|
||||
"--output-prefix", str(out_prefix),
|
||||
"--output-symlink", str(out_symlink),
|
||||
])
|
||||
print(
|
||||
"\nFor your convenience, the output of this run will be symbolically linked to ",
|
||||
out_index, "\n")
|
||||
|
||||
logging.debug(" ".join(cmd))
|
||||
proc = subprocess.run(cmd, check=False)
|
||||
if proc.returncode:
|
||||
logging.critical("Failed to run litani init")
|
||||
sys.exit(1)
|
||||
|
||||
proof_dirs = list(get_proof_dirs(
|
||||
proof_root, args.proofs, args.marker_file))
|
||||
if not proof_dirs:
|
||||
logging.critical("No proof directories found")
|
||||
sys.exit(1)
|
||||
|
||||
proof_queue = asyncio.Queue()
|
||||
for proof_dir in proof_dirs:
|
||||
proof_queue.put_nowait(proof_dir)
|
||||
|
||||
counter = {
|
||||
"pass": [],
|
||||
"fail": [],
|
||||
"complete": 0,
|
||||
"total": len(proof_dirs),
|
||||
"width": int(math.log10(len(proof_dirs))) + 1
|
||||
}
|
||||
|
||||
proof_uids = {}
|
||||
tasks = []
|
||||
|
||||
enable_memory_profiling = should_enable_memory_profiling(litani_caps, args)
|
||||
|
||||
for _ in range(task_pool_size()):
|
||||
task = asyncio.create_task(configure_proof_dirs(
|
||||
proof_queue, counter, proof_uids, enable_pools,
|
||||
enable_memory_profiling, args.debug))
|
||||
tasks.append(task)
|
||||
|
||||
await proof_queue.join()
|
||||
|
||||
print_counter(counter)
|
||||
print("", file=sys.stderr)
|
||||
|
||||
if counter["fail"]:
|
||||
logging.critical(
|
||||
"Failed to configure the following proofs:\n%s", "\n".join(
|
||||
[str(f) for f in counter["fail"]]))
|
||||
sys.exit(1)
|
||||
|
||||
if not args.no_standalone:
|
||||
run_build(litani, args.parallel_jobs, args.fail_on_proof_failure, args.summarize)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@ -0,0 +1,6 @@
|
||||
CBMC proof source code
|
||||
======================
|
||||
|
||||
This directory contains source code written for CBMC proofs. It is
|
||||
common to write some code to model aspects of the system under test,
|
||||
and this code goes here.
|
||||
@ -0,0 +1,6 @@
|
||||
CBMC proof stubs
|
||||
======================
|
||||
|
||||
This directory contains the stubs written for CBMC proofs. It is
|
||||
common to stub out functionality like network send and receive methods
|
||||
when writing a CBMC proof, and the code for these stubs goes here.
|
||||
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* AWS IoT Device Defender Client v1.3.0
|
||||
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file defender_config.h
|
||||
* @brief Config values for testing the AWS IoT Device Defender Client Library.
|
||||
*/
|
||||
|
||||
#ifndef DEFENDER_CONFIG_H_
|
||||
#define DEFENDER_CONFIG_H_
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef DISABLE_LOGGING
|
||||
#ifndef LogError
|
||||
#define LogError( message )
|
||||
#endif
|
||||
#ifndef LogWarn
|
||||
#define LogWarn( message )
|
||||
#endif
|
||||
|
||||
#ifndef LogInfo
|
||||
#define LogInfo( message )
|
||||
#endif
|
||||
|
||||
#ifndef LogDebug
|
||||
#define LogDebug( message )
|
||||
#endif
|
||||
|
||||
#else /* ! DISABLE_LOGGING */
|
||||
#define LogError( message ) printf( "Error: " ); printf message; printf( "\n" )
|
||||
|
||||
#define LogWarn( message ) printf( "Warn: " ); printf message; printf( "\n" )
|
||||
|
||||
#define LogInfo( message ) printf( "Info: " ); printf message; printf( "\n" )
|
||||
|
||||
#define LogDebug( message ) printf( "Debug: " ); printf message; printf( "\n" )
|
||||
#endif /* DISABLE_LOGGING */
|
||||
|
||||
#endif /* DEFENDER_CONFIG_H_ */
|
||||
@ -0,0 +1,46 @@
|
||||
# Include filepaths for Device Defender library.
|
||||
include( ${MODULE_ROOT_DIR}/defenderFilePaths.cmake )
|
||||
|
||||
set( library_name "defender" )
|
||||
set( library_target_name "${library_name}_target" )
|
||||
set( utest_binary_name "${library_name}_utest" )
|
||||
|
||||
# =========================== Library ==============================
|
||||
|
||||
# List of library source files.
|
||||
list( APPEND library_source_files
|
||||
${DEFENDER_SOURCES} )
|
||||
|
||||
# List of library include directories.
|
||||
list( APPEND library_include_directories
|
||||
${DEFENDER_INCLUDE_PUBLIC_DIRS}
|
||||
"${CMAKE_CURRENT_LIST_DIR}/../include" )
|
||||
|
||||
# Create a target for building library.
|
||||
create_library_target( ${library_target_name}
|
||||
"${library_source_files}"
|
||||
"${library_include_directories}" )
|
||||
|
||||
# =========================== Test Binary ==============================
|
||||
|
||||
# The source file containing the unit tests.
|
||||
set( utest_source_file "defender_utest.c" )
|
||||
|
||||
# The list of include directories for the test binary target.
|
||||
list( APPEND utest_include_directories
|
||||
${DEFENDER_INCLUDE_PUBLIC_DIRS} )
|
||||
|
||||
# Libraries to be linked while building the test binary.
|
||||
list( APPEND utest_link_list
|
||||
lib${library_target_name}.a )
|
||||
|
||||
# The targets on which the test binary target depends.
|
||||
list( APPEND utest_dep_list
|
||||
${library_target_name} )
|
||||
|
||||
# Create a target for the test binary.
|
||||
create_test_binary_target( ${utest_binary_name}
|
||||
${utest_source_file}
|
||||
"${utest_link_list}"
|
||||
"${utest_dep_list}"
|
||||
"${test_include_directories}" )
|
||||
@ -0,0 +1,823 @@
|
||||
/*
|
||||
* AWS IoT Device Defender Client v1.3.0
|
||||
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file defender_utest.c
|
||||
* @brief Unit tests for the Device Defender library.
|
||||
*/
|
||||
|
||||
/* Standard includes. */
|
||||
#include <string.h>
|
||||
|
||||
/* Test framework include. */
|
||||
#include "unity.h"
|
||||
|
||||
/* Defender API include. */
|
||||
#include "defender.h"
|
||||
|
||||
/* Thing name used in the tests. */
|
||||
#define TEST_THING_NAME "TestThing"
|
||||
#define TEST_THING_NAME_LENGTH STRING_LITERAL_LENGTH( TEST_THING_NAME )
|
||||
|
||||
/* Topics used in the tests. */
|
||||
#define TEST_JSON_PUBLISH_TOPIC "$aws/things/" TEST_THING_NAME "/defender/metrics/json"
|
||||
#define TEST_JSON_PUBLISH_TOPIC_LENGTH STRING_LITERAL_LENGTH( TEST_JSON_PUBLISH_TOPIC )
|
||||
|
||||
#define TEST_JSON_ACCEPTED_TOPIC "$aws/things/" TEST_THING_NAME "/defender/metrics/json/accepted"
|
||||
#define TEST_JSON_ACCEPTED_TOPIC_LENGTH STRING_LITERAL_LENGTH( TEST_JSON_ACCEPTED_TOPIC )
|
||||
|
||||
#define TEST_JSON_REJECTED_TOPIC "$aws/things/" TEST_THING_NAME "/defender/metrics/json/rejected"
|
||||
#define TEST_JSON_REJECTED_TOPIC_LENGTH STRING_LITERAL_LENGTH( TEST_JSON_REJECTED_TOPIC )
|
||||
|
||||
#define TEST_CBOR_PUBLISH_TOPIC "$aws/things/" TEST_THING_NAME "/defender/metrics/cbor"
|
||||
#define TEST_CBOR_PUBLISH_TOPIC_LENGTH STRING_LITERAL_LENGTH( TEST_CBOR_PUBLISH_TOPIC )
|
||||
|
||||
#define TEST_CBOR_ACCEPTED_TOPIC "$aws/things/" TEST_THING_NAME "/defender/metrics/cbor/accepted"
|
||||
#define TEST_CBOR_ACCEPTED_TOPIC_LENGTH STRING_LITERAL_LENGTH( TEST_CBOR_ACCEPTED_TOPIC )
|
||||
|
||||
#define TEST_CBOR_REJECTED_TOPIC "$aws/things/" TEST_THING_NAME "/defender/metrics/cbor/rejected"
|
||||
#define TEST_CBOR_REJECTED_TOPIC_LENGTH STRING_LITERAL_LENGTH( TEST_CBOR_REJECTED_TOPIC )
|
||||
|
||||
/* Length of the topic buffer used in tests. Guard buffers are placed before and
|
||||
* after the topic buffer to verify that defender APIs do not write out of
|
||||
* bounds. The memory layout is:
|
||||
*
|
||||
* +--------------+-------------------------------+------------+
|
||||
* | Guard | Writable Topic Buffer | Guard |
|
||||
* +--------------+-------------------------------+------------+
|
||||
*
|
||||
* Both guard buffers are filled with a known pattern before each test and are
|
||||
* verified to remain unchanged after each test.
|
||||
*/
|
||||
#define TEST_TOPIC_BUFFER_PREFIX_GUARD_LENGTH 32
|
||||
#define TEST_TOPIC_BUFFER_WRITABLE_LENGTH 256
|
||||
#define TEST_TOPIC_BUFFER_SUFFIX_GUARD_LENGTH 32
|
||||
#define TEST_TOPIC_BUFFER_TOTAL_LENGTH \
|
||||
( TEST_TOPIC_BUFFER_PREFIX_GUARD_LENGTH + \
|
||||
TEST_TOPIC_BUFFER_WRITABLE_LENGTH + \
|
||||
TEST_TOPIC_BUFFER_SUFFIX_GUARD_LENGTH )
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* @brief Topic buffer used in tests.
|
||||
*/
|
||||
static char testTopicBuffer[ TEST_TOPIC_BUFFER_TOTAL_LENGTH ];
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* ============================ UNITY FIXTURES ============================ */
|
||||
|
||||
/* Called before each test method. */
|
||||
void setUp()
|
||||
{
|
||||
/* Initialize the topic buffer with 0xA5. */
|
||||
memset( &( testTopicBuffer[ 0 ] ), 0xA5, TEST_TOPIC_BUFFER_TOTAL_LENGTH );
|
||||
}
|
||||
|
||||
/* Called after each test method. */
|
||||
void tearDown()
|
||||
{
|
||||
/* Prefix and Suffix guard buffers must never change. */
|
||||
TEST_ASSERT_EACH_EQUAL_HEX8( 0xA5,
|
||||
&( testTopicBuffer[ 0 ] ),
|
||||
TEST_TOPIC_BUFFER_PREFIX_GUARD_LENGTH );
|
||||
TEST_ASSERT_EACH_EQUAL_HEX8( 0xA5,
|
||||
&( testTopicBuffer[ TEST_TOPIC_BUFFER_PREFIX_GUARD_LENGTH +
|
||||
TEST_TOPIC_BUFFER_WRITABLE_LENGTH ] ),
|
||||
TEST_TOPIC_BUFFER_SUFFIX_GUARD_LENGTH );
|
||||
}
|
||||
|
||||
/* Called at the beginning of the whole suite. */
|
||||
void suiteSetUp()
|
||||
{
|
||||
}
|
||||
|
||||
/* Called at the end of the whole suite. */
|
||||
int suiteTearDown( int numFailures )
|
||||
{
|
||||
return numFailures;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* @brief Test that macros generates expected strings.
|
||||
*/
|
||||
void test_Defender_MacrosString( void )
|
||||
{
|
||||
TEST_ASSERT_EQUAL_STRING_LEN( TEST_JSON_PUBLISH_TOPIC,
|
||||
DEFENDER_API_JSON_PUBLISH( TEST_THING_NAME ),
|
||||
TEST_JSON_PUBLISH_TOPIC_LENGTH );
|
||||
|
||||
TEST_ASSERT_EQUAL_STRING_LEN( TEST_JSON_ACCEPTED_TOPIC,
|
||||
DEFENDER_API_JSON_ACCEPTED( TEST_THING_NAME ),
|
||||
TEST_JSON_ACCEPTED_TOPIC_LENGTH );
|
||||
|
||||
TEST_ASSERT_EQUAL_STRING_LEN( TEST_JSON_REJECTED_TOPIC,
|
||||
DEFENDER_API_JSON_REJECTED( TEST_THING_NAME ),
|
||||
TEST_JSON_REJECTED_TOPIC_LENGTH );
|
||||
|
||||
TEST_ASSERT_EQUAL_STRING_LEN( TEST_CBOR_PUBLISH_TOPIC,
|
||||
DEFENDER_API_CBOR_PUBLISH( TEST_THING_NAME ),
|
||||
TEST_CBOR_PUBLISH_TOPIC_LENGTH );
|
||||
|
||||
TEST_ASSERT_EQUAL_STRING_LEN( TEST_CBOR_ACCEPTED_TOPIC,
|
||||
DEFENDER_API_CBOR_ACCEPTED( TEST_THING_NAME ),
|
||||
TEST_CBOR_ACCEPTED_TOPIC_LENGTH );
|
||||
|
||||
TEST_ASSERT_EQUAL_STRING_LEN( TEST_CBOR_REJECTED_TOPIC,
|
||||
DEFENDER_API_CBOR_REJECTED( TEST_THING_NAME ),
|
||||
TEST_CBOR_REJECTED_TOPIC_LENGTH );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* @brief Test that macros generates expected string lengths.
|
||||
*/
|
||||
void test_Defender_MacrosLength( void )
|
||||
{
|
||||
TEST_ASSERT_EQUAL( TEST_JSON_PUBLISH_TOPIC_LENGTH,
|
||||
DEFENDER_API_LENGTH_JSON_PUBLISH( TEST_THING_NAME_LENGTH ) );
|
||||
|
||||
TEST_ASSERT_EQUAL( TEST_JSON_ACCEPTED_TOPIC_LENGTH,
|
||||
DEFENDER_API_LENGTH_JSON_ACCEPTED( TEST_THING_NAME_LENGTH ) );
|
||||
|
||||
TEST_ASSERT_EQUAL( TEST_JSON_REJECTED_TOPIC_LENGTH,
|
||||
DEFENDER_API_LENGTH_JSON_REJECTED( TEST_THING_NAME_LENGTH ) );
|
||||
|
||||
TEST_ASSERT_EQUAL( TEST_CBOR_PUBLISH_TOPIC_LENGTH,
|
||||
DEFENDER_API_LENGTH_CBOR_PUBLISH( TEST_THING_NAME_LENGTH ) );
|
||||
|
||||
TEST_ASSERT_EQUAL( TEST_CBOR_ACCEPTED_TOPIC_LENGTH,
|
||||
DEFENDER_API_LENGTH_CBOR_ACCEPTED( TEST_THING_NAME_LENGTH ) );
|
||||
|
||||
TEST_ASSERT_EQUAL( TEST_CBOR_REJECTED_TOPIC_LENGTH,
|
||||
DEFENDER_API_LENGTH_CBOR_REJECTED( TEST_THING_NAME_LENGTH ) );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void test_Defender_GetTopic_BadParams( void )
|
||||
{
|
||||
DefenderStatus_t ret;
|
||||
uint16_t topicLength;
|
||||
|
||||
/* Null buffer. */
|
||||
ret = Defender_GetTopic( NULL,
|
||||
TEST_TOPIC_BUFFER_WRITABLE_LENGTH,
|
||||
TEST_THING_NAME,
|
||||
TEST_THING_NAME_LENGTH,
|
||||
DefenderJsonReportPublish,
|
||||
&( topicLength ) );
|
||||
TEST_ASSERT_EQUAL( DefenderBadParameter, ret );
|
||||
TEST_ASSERT_EACH_EQUAL_HEX8( 0xA5,
|
||||
&( testTopicBuffer[ TEST_TOPIC_BUFFER_PREFIX_GUARD_LENGTH ] ),
|
||||
TEST_TOPIC_BUFFER_WRITABLE_LENGTH );
|
||||
|
||||
/* NULL thing name. */
|
||||
ret = Defender_GetTopic( &( testTopicBuffer[ TEST_TOPIC_BUFFER_PREFIX_GUARD_LENGTH ] ),
|
||||
TEST_TOPIC_BUFFER_WRITABLE_LENGTH,
|
||||
NULL,
|
||||
TEST_THING_NAME_LENGTH,
|
||||
DefenderJsonReportPublish,
|
||||
&( topicLength ) );
|
||||
TEST_ASSERT_EQUAL( DefenderBadParameter, ret );
|
||||
TEST_ASSERT_EACH_EQUAL_HEX8( 0xA5,
|
||||
&( testTopicBuffer[ TEST_TOPIC_BUFFER_PREFIX_GUARD_LENGTH ] ),
|
||||
TEST_TOPIC_BUFFER_WRITABLE_LENGTH );
|
||||
|
||||
/* Zero length thing name. */
|
||||
ret = Defender_GetTopic( &( testTopicBuffer[ TEST_TOPIC_BUFFER_PREFIX_GUARD_LENGTH ] ),
|
||||
TEST_TOPIC_BUFFER_WRITABLE_LENGTH,
|
||||
TEST_THING_NAME,
|
||||
0,
|
||||
DefenderJsonReportPublish,
|
||||
&( topicLength ) );
|
||||
TEST_ASSERT_EQUAL( DefenderBadParameter, ret );
|
||||
TEST_ASSERT_EACH_EQUAL_HEX8( 0xA5,
|
||||
&( testTopicBuffer[ TEST_TOPIC_BUFFER_PREFIX_GUARD_LENGTH ] ),
|
||||
TEST_TOPIC_BUFFER_WRITABLE_LENGTH );
|
||||
|
||||
/* Thing name length more than the maximum allowed. */
|
||||
ret = Defender_GetTopic( &( testTopicBuffer[ TEST_TOPIC_BUFFER_PREFIX_GUARD_LENGTH ] ),
|
||||
TEST_TOPIC_BUFFER_WRITABLE_LENGTH,
|
||||
TEST_THING_NAME,
|
||||
DEFENDER_THINGNAME_MAX_LENGTH + 1,
|
||||
DefenderJsonReportPublish,
|
||||
&( topicLength ) );
|
||||
TEST_ASSERT_EQUAL( DefenderBadParameter, ret );
|
||||
TEST_ASSERT_EACH_EQUAL_HEX8( 0xA5,
|
||||
&( testTopicBuffer[ TEST_TOPIC_BUFFER_PREFIX_GUARD_LENGTH ] ),
|
||||
TEST_TOPIC_BUFFER_WRITABLE_LENGTH );
|
||||
|
||||
/* Invalid api. */
|
||||
ret = Defender_GetTopic( &( testTopicBuffer[ TEST_TOPIC_BUFFER_PREFIX_GUARD_LENGTH ] ),
|
||||
TEST_TOPIC_BUFFER_WRITABLE_LENGTH,
|
||||
TEST_THING_NAME,
|
||||
TEST_THING_NAME_LENGTH,
|
||||
DefenderInvalidTopic,
|
||||
&( topicLength ) );
|
||||
TEST_ASSERT_EQUAL( DefenderBadParameter, ret );
|
||||
TEST_ASSERT_EACH_EQUAL_HEX8( 0xA5,
|
||||
&( testTopicBuffer[ TEST_TOPIC_BUFFER_PREFIX_GUARD_LENGTH ] ),
|
||||
TEST_TOPIC_BUFFER_WRITABLE_LENGTH );
|
||||
|
||||
/* Invalid api. */
|
||||
ret = Defender_GetTopic( &( testTopicBuffer[ TEST_TOPIC_BUFFER_PREFIX_GUARD_LENGTH ] ),
|
||||
TEST_TOPIC_BUFFER_WRITABLE_LENGTH,
|
||||
TEST_THING_NAME,
|
||||
TEST_THING_NAME_LENGTH,
|
||||
DefenderMaxTopic,
|
||||
&( topicLength ) );
|
||||
TEST_ASSERT_EQUAL( DefenderBadParameter, ret );
|
||||
TEST_ASSERT_EACH_EQUAL_HEX8( 0xA5,
|
||||
&( testTopicBuffer[ TEST_TOPIC_BUFFER_PREFIX_GUARD_LENGTH ] ),
|
||||
TEST_TOPIC_BUFFER_WRITABLE_LENGTH );
|
||||
|
||||
/* NULL output parameter. */
|
||||
ret = Defender_GetTopic( &( testTopicBuffer[ TEST_TOPIC_BUFFER_PREFIX_GUARD_LENGTH ] ),
|
||||
TEST_TOPIC_BUFFER_WRITABLE_LENGTH,
|
||||
TEST_THING_NAME,
|
||||
TEST_THING_NAME_LENGTH,
|
||||
DefenderJsonReportPublish,
|
||||
NULL );
|
||||
TEST_ASSERT_EQUAL( DefenderBadParameter, ret );
|
||||
TEST_ASSERT_EACH_EQUAL_HEX8( 0xA5,
|
||||
&( testTopicBuffer[ TEST_TOPIC_BUFFER_PREFIX_GUARD_LENGTH ] ),
|
||||
TEST_TOPIC_BUFFER_WRITABLE_LENGTH );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void test_Defender_GetTopic_BufferTooSmall( void )
|
||||
{
|
||||
DefenderStatus_t ret;
|
||||
uint16_t topicLength;
|
||||
|
||||
ret = Defender_GetTopic( &( testTopicBuffer[ TEST_TOPIC_BUFFER_PREFIX_GUARD_LENGTH ] ),
|
||||
5, /* Length too small to fit the entire topic. */
|
||||
TEST_THING_NAME,
|
||||
TEST_THING_NAME_LENGTH,
|
||||
DefenderJsonReportPublish,
|
||||
&( topicLength ) );
|
||||
TEST_ASSERT_EQUAL( DefenderBufferTooSmall, ret );
|
||||
TEST_ASSERT_EACH_EQUAL_HEX8( 0xA5,
|
||||
&( testTopicBuffer[ TEST_TOPIC_BUFFER_PREFIX_GUARD_LENGTH ] ),
|
||||
TEST_TOPIC_BUFFER_WRITABLE_LENGTH );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void test_Defender_GetTopic_JsonPublishHappyPath( void )
|
||||
{
|
||||
DefenderStatus_t ret;
|
||||
uint16_t topicLength;
|
||||
|
||||
ret = Defender_GetTopic( &( testTopicBuffer[ TEST_TOPIC_BUFFER_PREFIX_GUARD_LENGTH ] ),
|
||||
TEST_TOPIC_BUFFER_WRITABLE_LENGTH,
|
||||
TEST_THING_NAME,
|
||||
TEST_THING_NAME_LENGTH,
|
||||
DefenderJsonReportPublish,
|
||||
&( topicLength ) );
|
||||
|
||||
TEST_ASSERT_EQUAL( DefenderSuccess, ret );
|
||||
TEST_ASSERT_EQUAL( TEST_JSON_PUBLISH_TOPIC_LENGTH, topicLength );
|
||||
|
||||
TEST_ASSERT_EQUAL_STRING_LEN( TEST_JSON_PUBLISH_TOPIC,
|
||||
&( testTopicBuffer[ TEST_TOPIC_BUFFER_PREFIX_GUARD_LENGTH ] ),
|
||||
topicLength );
|
||||
|
||||
TEST_ASSERT_EACH_EQUAL_HEX8( 0xA5,
|
||||
&( testTopicBuffer[ TEST_TOPIC_BUFFER_PREFIX_GUARD_LENGTH + topicLength ] ),
|
||||
TEST_TOPIC_BUFFER_WRITABLE_LENGTH - topicLength );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void test_Defender_GetTopic_JsonAcceptedHappyPath( void )
|
||||
{
|
||||
DefenderStatus_t ret;
|
||||
uint16_t topicLength;
|
||||
|
||||
ret = Defender_GetTopic( &( testTopicBuffer[ TEST_TOPIC_BUFFER_PREFIX_GUARD_LENGTH ] ),
|
||||
TEST_TOPIC_BUFFER_WRITABLE_LENGTH,
|
||||
TEST_THING_NAME,
|
||||
TEST_THING_NAME_LENGTH,
|
||||
DefenderJsonReportAccepted,
|
||||
&( topicLength ) );
|
||||
|
||||
TEST_ASSERT_EQUAL( DefenderSuccess, ret );
|
||||
TEST_ASSERT_EQUAL( TEST_JSON_ACCEPTED_TOPIC_LENGTH, topicLength );
|
||||
|
||||
TEST_ASSERT_EQUAL_STRING_LEN( TEST_JSON_ACCEPTED_TOPIC,
|
||||
&( testTopicBuffer[ TEST_TOPIC_BUFFER_PREFIX_GUARD_LENGTH ] ),
|
||||
topicLength );
|
||||
|
||||
TEST_ASSERT_EACH_EQUAL_HEX8( 0xA5,
|
||||
&( testTopicBuffer[ TEST_TOPIC_BUFFER_PREFIX_GUARD_LENGTH + topicLength ] ),
|
||||
TEST_TOPIC_BUFFER_WRITABLE_LENGTH - topicLength );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void test_Defender_GetTopic_JsonRejectedHappyPath( void )
|
||||
{
|
||||
DefenderStatus_t ret;
|
||||
uint16_t topicLength;
|
||||
|
||||
ret = Defender_GetTopic( &( testTopicBuffer[ TEST_TOPIC_BUFFER_PREFIX_GUARD_LENGTH ] ),
|
||||
TEST_TOPIC_BUFFER_WRITABLE_LENGTH,
|
||||
TEST_THING_NAME,
|
||||
TEST_THING_NAME_LENGTH,
|
||||
DefenderJsonReportRejected,
|
||||
&( topicLength ) );
|
||||
|
||||
TEST_ASSERT_EQUAL( DefenderSuccess, ret );
|
||||
TEST_ASSERT_EQUAL( TEST_JSON_REJECTED_TOPIC_LENGTH, topicLength );
|
||||
|
||||
TEST_ASSERT_EQUAL_STRING_LEN( TEST_JSON_REJECTED_TOPIC,
|
||||
&( testTopicBuffer[ TEST_TOPIC_BUFFER_PREFIX_GUARD_LENGTH ] ),
|
||||
topicLength );
|
||||
|
||||
TEST_ASSERT_EACH_EQUAL_HEX8( 0xA5,
|
||||
&( testTopicBuffer[ TEST_TOPIC_BUFFER_PREFIX_GUARD_LENGTH + topicLength ] ),
|
||||
TEST_TOPIC_BUFFER_WRITABLE_LENGTH - topicLength );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void test_Defender_GetTopic_CborPublishHappyPath( void )
|
||||
{
|
||||
DefenderStatus_t ret;
|
||||
uint16_t topicLength;
|
||||
|
||||
ret = Defender_GetTopic( &( testTopicBuffer[ TEST_TOPIC_BUFFER_PREFIX_GUARD_LENGTH ] ),
|
||||
TEST_TOPIC_BUFFER_WRITABLE_LENGTH,
|
||||
TEST_THING_NAME,
|
||||
TEST_THING_NAME_LENGTH,
|
||||
DefenderCborReportPublish,
|
||||
&( topicLength ) );
|
||||
|
||||
TEST_ASSERT_EQUAL( DefenderSuccess, ret );
|
||||
TEST_ASSERT_EQUAL( TEST_CBOR_PUBLISH_TOPIC_LENGTH, topicLength );
|
||||
|
||||
TEST_ASSERT_EQUAL_STRING_LEN( TEST_CBOR_PUBLISH_TOPIC,
|
||||
&( testTopicBuffer[ TEST_TOPIC_BUFFER_PREFIX_GUARD_LENGTH ] ),
|
||||
topicLength );
|
||||
|
||||
TEST_ASSERT_EACH_EQUAL_HEX8( 0xA5,
|
||||
&( testTopicBuffer[ TEST_TOPIC_BUFFER_PREFIX_GUARD_LENGTH + topicLength ] ),
|
||||
TEST_TOPIC_BUFFER_WRITABLE_LENGTH - topicLength );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void test_Defender_GetTopic_CborAcceptedHappyPath( void )
|
||||
{
|
||||
DefenderStatus_t ret;
|
||||
uint16_t topicLength;
|
||||
|
||||
ret = Defender_GetTopic( &( testTopicBuffer[ TEST_TOPIC_BUFFER_PREFIX_GUARD_LENGTH ] ),
|
||||
TEST_TOPIC_BUFFER_WRITABLE_LENGTH,
|
||||
TEST_THING_NAME,
|
||||
TEST_THING_NAME_LENGTH,
|
||||
DefenderCborReportAccepted,
|
||||
&( topicLength ) );
|
||||
|
||||
TEST_ASSERT_EQUAL( DefenderSuccess, ret );
|
||||
TEST_ASSERT_EQUAL( TEST_CBOR_ACCEPTED_TOPIC_LENGTH, topicLength );
|
||||
|
||||
TEST_ASSERT_EQUAL_STRING_LEN( TEST_CBOR_ACCEPTED_TOPIC,
|
||||
&( testTopicBuffer[ TEST_TOPIC_BUFFER_PREFIX_GUARD_LENGTH ] ),
|
||||
topicLength );
|
||||
|
||||
TEST_ASSERT_EACH_EQUAL_HEX8( 0xA5,
|
||||
&( testTopicBuffer[ TEST_TOPIC_BUFFER_PREFIX_GUARD_LENGTH + topicLength ] ),
|
||||
TEST_TOPIC_BUFFER_WRITABLE_LENGTH - topicLength );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void test_Defender_GetTopic_CborRejectedHappyPath( void )
|
||||
{
|
||||
DefenderStatus_t ret;
|
||||
uint16_t topicLength;
|
||||
|
||||
ret = Defender_GetTopic( &( testTopicBuffer[ TEST_TOPIC_BUFFER_PREFIX_GUARD_LENGTH ] ),
|
||||
TEST_TOPIC_BUFFER_WRITABLE_LENGTH,
|
||||
TEST_THING_NAME,
|
||||
TEST_THING_NAME_LENGTH,
|
||||
DefenderCborReportRejected,
|
||||
&( topicLength ) );
|
||||
|
||||
TEST_ASSERT_EQUAL( DefenderSuccess, ret );
|
||||
TEST_ASSERT_EQUAL( TEST_CBOR_REJECTED_TOPIC_LENGTH, topicLength );
|
||||
|
||||
TEST_ASSERT_EQUAL_STRING_LEN( TEST_CBOR_REJECTED_TOPIC,
|
||||
&( testTopicBuffer[ TEST_TOPIC_BUFFER_PREFIX_GUARD_LENGTH ] ),
|
||||
topicLength );
|
||||
|
||||
TEST_ASSERT_EACH_EQUAL_HEX8( 0xA5,
|
||||
&( testTopicBuffer[ TEST_TOPIC_BUFFER_PREFIX_GUARD_LENGTH + topicLength ] ),
|
||||
TEST_TOPIC_BUFFER_WRITABLE_LENGTH - topicLength );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void test_Defender_MatchTopic_BadParams( void )
|
||||
{
|
||||
DefenderStatus_t ret;
|
||||
const char * pThingName;
|
||||
uint16_t thingNameLength;
|
||||
DefenderTopic_t api;
|
||||
|
||||
/* NULL topic. */
|
||||
ret = Defender_MatchTopic( NULL,
|
||||
TEST_JSON_PUBLISH_TOPIC_LENGTH,
|
||||
&( api ),
|
||||
&( pThingName ),
|
||||
&( thingNameLength ) );
|
||||
TEST_ASSERT_EQUAL( DefenderBadParameter, ret );
|
||||
|
||||
/* NULL output parameter. */
|
||||
ret = Defender_MatchTopic( TEST_JSON_PUBLISH_TOPIC,
|
||||
TEST_JSON_PUBLISH_TOPIC_LENGTH,
|
||||
NULL,
|
||||
&( pThingName ),
|
||||
&( thingNameLength ) );
|
||||
TEST_ASSERT_EQUAL( DefenderBadParameter, ret );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void test_Defender_MatchTopic_IncompletePrefix( void )
|
||||
{
|
||||
DefenderStatus_t ret;
|
||||
const char * pThingName;
|
||||
uint16_t thingNameLength;
|
||||
DefenderTopic_t api;
|
||||
|
||||
ret = Defender_MatchTopic( "$aws/things",
|
||||
STRING_LITERAL_LENGTH( "$aws/things" ),
|
||||
&( api ),
|
||||
&( pThingName ),
|
||||
&( thingNameLength ) );
|
||||
TEST_ASSERT_EQUAL( DefenderNoMatch, ret );
|
||||
TEST_ASSERT_EQUAL( DefenderInvalidTopic, api );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void test_Defender_MatchTopic_InvalidPrefix( void )
|
||||
{
|
||||
DefenderStatus_t ret;
|
||||
const char * pThingName;
|
||||
uint16_t thingNameLength;
|
||||
DefenderTopic_t api;
|
||||
|
||||
ret = Defender_MatchTopic( "$aws/jobs/things/TestThing/defender/metrics/json",
|
||||
STRING_LITERAL_LENGTH( "$aws/jobs/things/TestThing/defender/metrics/json" ),
|
||||
&( api ),
|
||||
&( pThingName ),
|
||||
&( thingNameLength ) );
|
||||
TEST_ASSERT_EQUAL( DefenderNoMatch, ret );
|
||||
TEST_ASSERT_EQUAL( DefenderInvalidTopic, api );
|
||||
|
||||
ret = Defender_MatchTopic( "$aws/things/jobs/TestThing/defender/metrics/json",
|
||||
STRING_LITERAL_LENGTH( "$aws/jobs/TestThing/defender/metrics/json" ),
|
||||
&( api ),
|
||||
&( pThingName ),
|
||||
&( thingNameLength ) );
|
||||
TEST_ASSERT_EQUAL( DefenderNoMatch, ret );
|
||||
TEST_ASSERT_EQUAL( DefenderInvalidTopic, api );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void test_Defender_MatchTopic_MissingThingName( void )
|
||||
{
|
||||
DefenderStatus_t ret;
|
||||
const char * pThingName;
|
||||
uint16_t thingNameLength;
|
||||
DefenderTopic_t api;
|
||||
|
||||
ret = Defender_MatchTopic( "$aws/things/",
|
||||
STRING_LITERAL_LENGTH( "$aws/things/" ),
|
||||
&( api ),
|
||||
&( pThingName ),
|
||||
&( thingNameLength ) );
|
||||
TEST_ASSERT_EQUAL( DefenderNoMatch, ret );
|
||||
TEST_ASSERT_EQUAL( DefenderInvalidTopic, api );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void test_Defender_MatchTopic_IncompleteBridge( void )
|
||||
{
|
||||
DefenderStatus_t ret;
|
||||
const char * pThingName;
|
||||
uint16_t thingNameLength;
|
||||
DefenderTopic_t api;
|
||||
|
||||
ret = Defender_MatchTopic( "$aws/things/TestThing",
|
||||
STRING_LITERAL_LENGTH( "$aws/things/TestThing" ),
|
||||
&( api ),
|
||||
&( pThingName ),
|
||||
&( thingNameLength ) );
|
||||
TEST_ASSERT_EQUAL( DefenderNoMatch, ret );
|
||||
TEST_ASSERT_EQUAL( DefenderInvalidTopic, api );
|
||||
|
||||
ret = Defender_MatchTopic( "$aws/things/TestThing/",
|
||||
STRING_LITERAL_LENGTH( "$aws/things/TestThing/" ),
|
||||
&( api ),
|
||||
&( pThingName ),
|
||||
&( thingNameLength ) );
|
||||
TEST_ASSERT_EQUAL( DefenderNoMatch, ret );
|
||||
TEST_ASSERT_EQUAL( DefenderInvalidTopic, api );
|
||||
|
||||
ret = Defender_MatchTopic( "$aws/things/TestThing/defender",
|
||||
STRING_LITERAL_LENGTH( "$aws/things/TestThing/defender" ),
|
||||
&( api ),
|
||||
&( pThingName ),
|
||||
&( thingNameLength ) );
|
||||
TEST_ASSERT_EQUAL( DefenderNoMatch, ret );
|
||||
TEST_ASSERT_EQUAL( DefenderInvalidTopic, api );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void test_Defender_MatchTopic_InvalidBridge( void )
|
||||
{
|
||||
DefenderStatus_t ret;
|
||||
const char * pThingName;
|
||||
uint16_t thingNameLength;
|
||||
DefenderTopic_t api;
|
||||
|
||||
ret = Defender_MatchTopic( "$aws/things/TestThing/shadow/metrics/json",
|
||||
STRING_LITERAL_LENGTH( "$aws/things/TestThing/shadow/metrics/json" ),
|
||||
&( api ),
|
||||
&( pThingName ),
|
||||
&( thingNameLength ) );
|
||||
TEST_ASSERT_EQUAL( DefenderNoMatch, ret );
|
||||
TEST_ASSERT_EQUAL( DefenderInvalidTopic, api );
|
||||
|
||||
ret = Defender_MatchTopic( "$aws/things/TestThing/defender/defender/metrics/json",
|
||||
STRING_LITERAL_LENGTH( "$aws/things/TestThing/defender/defender/metrics/json" ),
|
||||
&( api ),
|
||||
&( pThingName ),
|
||||
&( thingNameLength ) );
|
||||
TEST_ASSERT_EQUAL( DefenderNoMatch, ret );
|
||||
TEST_ASSERT_EQUAL( DefenderInvalidTopic, api );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void test_Defender_MatchTopic_IncompleteFormat( void )
|
||||
{
|
||||
DefenderStatus_t ret;
|
||||
const char * pThingName;
|
||||
uint16_t thingNameLength;
|
||||
DefenderTopic_t api;
|
||||
|
||||
ret = Defender_MatchTopic( "$aws/things/TestThing/defender/metrics",
|
||||
STRING_LITERAL_LENGTH( "$aws/things/TestThing/defender/metrics" ),
|
||||
&( api ),
|
||||
&( pThingName ),
|
||||
&( thingNameLength ) );
|
||||
TEST_ASSERT_EQUAL( DefenderNoMatch, ret );
|
||||
TEST_ASSERT_EQUAL( DefenderInvalidTopic, api );
|
||||
|
||||
ret = Defender_MatchTopic( "$aws/things/TestThing/defender/metrics/",
|
||||
STRING_LITERAL_LENGTH( "$aws/things/TestThing/defender/metrics/" ),
|
||||
&( api ),
|
||||
&( pThingName ),
|
||||
&( thingNameLength ) );
|
||||
TEST_ASSERT_EQUAL( DefenderNoMatch, ret );
|
||||
TEST_ASSERT_EQUAL( DefenderInvalidTopic, api );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void test_Defender_MatchTopic_InvalidFormat( void )
|
||||
{
|
||||
DefenderStatus_t ret;
|
||||
const char * pThingName;
|
||||
uint16_t thingNameLength;
|
||||
DefenderTopic_t api;
|
||||
|
||||
ret = Defender_MatchTopic( "$aws/things/TestThing/defender/metrics/xml",
|
||||
STRING_LITERAL_LENGTH( "$aws/things/TestThing/defender/metrics/xml" ),
|
||||
&( api ),
|
||||
&( pThingName ),
|
||||
&( thingNameLength ) );
|
||||
TEST_ASSERT_EQUAL( DefenderNoMatch, ret );
|
||||
TEST_ASSERT_EQUAL( DefenderInvalidTopic, api );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void test_Defender_MatchTopic_InvalidSuffix( void )
|
||||
{
|
||||
DefenderStatus_t ret;
|
||||
const char * pThingName;
|
||||
uint16_t thingNameLength;
|
||||
DefenderTopic_t api;
|
||||
|
||||
ret = Defender_MatchTopic( "$aws/things/TestThing/defender/metrics/json/delta",
|
||||
STRING_LITERAL_LENGTH( "$aws/things/TestThing/defender/metrics/json/delta" ),
|
||||
&( api ),
|
||||
&( pThingName ),
|
||||
&( thingNameLength ) );
|
||||
TEST_ASSERT_EQUAL( DefenderNoMatch, ret );
|
||||
TEST_ASSERT_EQUAL( DefenderInvalidTopic, api );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void test_Defender_MatchTopic_ExtraData( void )
|
||||
{
|
||||
DefenderStatus_t ret;
|
||||
const char * pThingName;
|
||||
uint16_t thingNameLength;
|
||||
DefenderTopic_t api;
|
||||
|
||||
ret = Defender_MatchTopic( "$aws/things/TestThing/defender/metrics/json/gibberish",
|
||||
STRING_LITERAL_LENGTH( "$aws/things/TestThing/defender/metrics/json/gibberish" ),
|
||||
&( api ),
|
||||
&( pThingName ),
|
||||
&( thingNameLength ) );
|
||||
TEST_ASSERT_EQUAL( DefenderNoMatch, ret );
|
||||
TEST_ASSERT_EQUAL( DefenderInvalidTopic, api );
|
||||
|
||||
ret = Defender_MatchTopic( "$aws/things/TestThing/defender/metrics/json/accepted/gibberish",
|
||||
STRING_LITERAL_LENGTH( "$aws/things/TestThing/defender/metrics/json/accepted/gibberish" ),
|
||||
&( api ),
|
||||
&( pThingName ),
|
||||
&( thingNameLength ) );
|
||||
TEST_ASSERT_EQUAL( DefenderNoMatch, ret );
|
||||
TEST_ASSERT_EQUAL( DefenderInvalidTopic, api );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void test_Defender_MatchTopic_JsonPublishHappyPath( void )
|
||||
{
|
||||
DefenderStatus_t ret;
|
||||
const char * pThingName;
|
||||
uint16_t thingNameLength;
|
||||
DefenderTopic_t api;
|
||||
|
||||
ret = Defender_MatchTopic( TEST_JSON_PUBLISH_TOPIC,
|
||||
TEST_JSON_PUBLISH_TOPIC_LENGTH,
|
||||
&( api ),
|
||||
&( pThingName ),
|
||||
&( thingNameLength ) );
|
||||
|
||||
TEST_ASSERT_EQUAL( DefenderSuccess, ret );
|
||||
TEST_ASSERT_EQUAL( DefenderJsonReportPublish, api );
|
||||
TEST_ASSERT_EQUAL_PTR( TEST_JSON_PUBLISH_TOPIC + DEFENDER_API_LENGTH_PREFIX, pThingName );
|
||||
TEST_ASSERT_EQUAL( TEST_THING_NAME_LENGTH, thingNameLength );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void test_Defender_MatchTopic_JsonAcceptedHappyPath( void )
|
||||
{
|
||||
DefenderStatus_t ret;
|
||||
const char * pThingName;
|
||||
uint16_t thingNameLength;
|
||||
DefenderTopic_t api;
|
||||
|
||||
ret = Defender_MatchTopic( TEST_JSON_ACCEPTED_TOPIC,
|
||||
TEST_JSON_ACCEPTED_TOPIC_LENGTH,
|
||||
&( api ),
|
||||
&( pThingName ),
|
||||
&( thingNameLength ) );
|
||||
|
||||
TEST_ASSERT_EQUAL( DefenderSuccess, ret );
|
||||
TEST_ASSERT_EQUAL( DefenderJsonReportAccepted, api );
|
||||
TEST_ASSERT_EQUAL_PTR( TEST_JSON_ACCEPTED_TOPIC + DEFENDER_API_LENGTH_PREFIX, pThingName );
|
||||
TEST_ASSERT_EQUAL( TEST_THING_NAME_LENGTH, thingNameLength );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void test_Defender_MatchTopic_JsonRejectedHappyPath( void )
|
||||
{
|
||||
DefenderStatus_t ret;
|
||||
const char * pThingName;
|
||||
uint16_t thingNameLength;
|
||||
DefenderTopic_t api;
|
||||
|
||||
ret = Defender_MatchTopic( TEST_JSON_REJECTED_TOPIC,
|
||||
TEST_JSON_REJECTED_TOPIC_LENGTH,
|
||||
&( api ),
|
||||
&( pThingName ),
|
||||
&( thingNameLength ) );
|
||||
|
||||
TEST_ASSERT_EQUAL( DefenderSuccess, ret );
|
||||
TEST_ASSERT_EQUAL( DefenderJsonReportRejected, api );
|
||||
TEST_ASSERT_EQUAL_PTR( TEST_JSON_REJECTED_TOPIC + DEFENDER_API_LENGTH_PREFIX, pThingName );
|
||||
TEST_ASSERT_EQUAL( TEST_THING_NAME_LENGTH, thingNameLength );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void test_Defender_MatchTopic_CborPublishHappyPath( void )
|
||||
{
|
||||
DefenderStatus_t ret;
|
||||
const char * pThingName;
|
||||
uint16_t thingNameLength;
|
||||
DefenderTopic_t api;
|
||||
|
||||
ret = Defender_MatchTopic( TEST_CBOR_PUBLISH_TOPIC,
|
||||
TEST_CBOR_PUBLISH_TOPIC_LENGTH,
|
||||
&( api ),
|
||||
&( pThingName ),
|
||||
&( thingNameLength ) );
|
||||
|
||||
TEST_ASSERT_EQUAL( DefenderSuccess, ret );
|
||||
TEST_ASSERT_EQUAL( DefenderCborReportPublish, api );
|
||||
TEST_ASSERT_EQUAL_PTR( TEST_CBOR_PUBLISH_TOPIC + DEFENDER_API_LENGTH_PREFIX, pThingName );
|
||||
TEST_ASSERT_EQUAL( TEST_THING_NAME_LENGTH, thingNameLength );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void test_Defender_MatchTopic_CborAcceptedHappyPath( void )
|
||||
{
|
||||
DefenderStatus_t ret;
|
||||
const char * pThingName;
|
||||
uint16_t thingNameLength;
|
||||
DefenderTopic_t api;
|
||||
|
||||
ret = Defender_MatchTopic( TEST_CBOR_ACCEPTED_TOPIC,
|
||||
TEST_CBOR_ACCEPTED_TOPIC_LENGTH,
|
||||
&( api ),
|
||||
&( pThingName ),
|
||||
&( thingNameLength ) );
|
||||
|
||||
TEST_ASSERT_EQUAL( DefenderSuccess, ret );
|
||||
TEST_ASSERT_EQUAL( DefenderCborReportAccepted, api );
|
||||
TEST_ASSERT_EQUAL_PTR( TEST_CBOR_ACCEPTED_TOPIC + DEFENDER_API_LENGTH_PREFIX, pThingName );
|
||||
TEST_ASSERT_EQUAL( TEST_THING_NAME_LENGTH, thingNameLength );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void test_Defender_MatchTopic_CborRejectedHappyPath( void )
|
||||
{
|
||||
DefenderStatus_t ret;
|
||||
const char * pThingName;
|
||||
uint16_t thingNameLength;
|
||||
DefenderTopic_t api;
|
||||
|
||||
ret = Defender_MatchTopic( TEST_CBOR_REJECTED_TOPIC,
|
||||
TEST_CBOR_REJECTED_TOPIC_LENGTH,
|
||||
&( api ),
|
||||
&( pThingName ),
|
||||
&( thingNameLength ) );
|
||||
|
||||
TEST_ASSERT_EQUAL( DefenderSuccess, ret );
|
||||
TEST_ASSERT_EQUAL( DefenderCborReportRejected, api );
|
||||
TEST_ASSERT_EQUAL_PTR( TEST_CBOR_REJECTED_TOPIC + DEFENDER_API_LENGTH_PREFIX, pThingName );
|
||||
TEST_ASSERT_EQUAL( TEST_THING_NAME_LENGTH, thingNameLength );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void test_Defender_MatchTopic_MissingOptionalParams( void )
|
||||
{
|
||||
DefenderStatus_t ret;
|
||||
const char * pThingName;
|
||||
uint16_t thingNameLength;
|
||||
DefenderTopic_t api;
|
||||
|
||||
/* Missing output param for returning thing name. */
|
||||
ret = Defender_MatchTopic( TEST_JSON_PUBLISH_TOPIC,
|
||||
TEST_JSON_PUBLISH_TOPIC_LENGTH,
|
||||
&( api ),
|
||||
NULL,
|
||||
&( thingNameLength ) );
|
||||
|
||||
TEST_ASSERT_EQUAL( DefenderSuccess, ret );
|
||||
TEST_ASSERT_EQUAL( DefenderJsonReportPublish, api );
|
||||
TEST_ASSERT_EQUAL( TEST_THING_NAME_LENGTH, thingNameLength );
|
||||
|
||||
/* Missing output param for returning thing name length. */
|
||||
ret = Defender_MatchTopic( TEST_JSON_PUBLISH_TOPIC,
|
||||
TEST_JSON_PUBLISH_TOPIC_LENGTH,
|
||||
&( api ),
|
||||
&( pThingName ),
|
||||
NULL );
|
||||
|
||||
TEST_ASSERT_EQUAL( DefenderSuccess, ret );
|
||||
TEST_ASSERT_EQUAL( DefenderJsonReportPublish, api );
|
||||
TEST_ASSERT_EQUAL_PTR( TEST_JSON_PUBLISH_TOPIC + DEFENDER_API_LENGTH_PREFIX, pThingName );
|
||||
|
||||
/* Missing output param for returning both thing name and thing name
|
||||
* length. */
|
||||
ret = Defender_MatchTopic( TEST_JSON_PUBLISH_TOPIC,
|
||||
TEST_JSON_PUBLISH_TOPIC_LENGTH,
|
||||
&( api ),
|
||||
NULL,
|
||||
NULL );
|
||||
|
||||
TEST_ASSERT_EQUAL( DefenderSuccess, ret );
|
||||
TEST_ASSERT_EQUAL( DefenderJsonReportPublish, api );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
@ -0,0 +1,32 @@
|
||||
# Macro to clone the Unity submodule.
|
||||
macro( clone_unity )
|
||||
find_package( Git REQUIRED )
|
||||
message( "Cloning Unity submodule." )
|
||||
execute_process( COMMAND rm -rf ${UNITY_DIR}
|
||||
COMMAND ${GIT_EXECUTABLE} submodule update --checkout --init --recursive ${UNITY_DIR}
|
||||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
|
||||
RESULT_VARIABLE UNITY_CLONE_RESULT )
|
||||
|
||||
if( NOT ${UNITY_CLONE_RESULT} STREQUAL "0" )
|
||||
message( FATAL_ERROR "Failed to clone Unity submodule." )
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
# Macro to add library target for Unity to build configuration.
|
||||
macro( add_unity_target )
|
||||
add_library( unity STATIC
|
||||
"${UNITY_DIR}/src/unity.c"
|
||||
"${UNITY_DIR}/extras/fixture/src/unity_fixture.c"
|
||||
"${UNITY_DIR}/extras/memory/src/unity_memory.c" )
|
||||
|
||||
target_include_directories( unity PUBLIC
|
||||
"${UNITY_DIR}/src/"
|
||||
"${UNITY_DIR}/extras/fixture/src"
|
||||
"${UNITY_DIR}/extras/memory/src" )
|
||||
|
||||
set_target_properties( unity PROPERTIES
|
||||
ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib
|
||||
POSITION_INDEPENDENT_CODE ON )
|
||||
|
||||
target_link_libraries( unity )
|
||||
endmacro()
|
||||
@ -0,0 +1,79 @@
|
||||
# Static code analysis for Device-Defender-for-AWS-IoT-embedded-sdk library
|
||||
This directory is made for the purpose of statically testing the MISRA C:2012 compliance of Device-Defender-for-AWS-IoT-embedded-sdk using
|
||||
[Synopsys Coverity](https://www.synopsys.com/software-integrity/security-testing/static-analysis-sast.html) static analysis tool.
|
||||
To that end, this directory provides a [configuration file](https://github.com/aws/Device-Defender-for-AWS-IoT-embedded-sdk/blob/main/tools/coverity/misra.config) to use when
|
||||
building a binary for the tool to analyze.
|
||||
|
||||
> **Note**
|
||||
For generating the report as outlined below, we have used Coverity version 2018.09.
|
||||
|
||||
For details regarding the suppressed violations in the report (which can be generated using the instructions described below), please
|
||||
see the [MISRA.md](https://github.com/aws/Device-Defender-for-AWS-IoT-embedded-sdk/blob/main/MISRA.md) file.
|
||||
|
||||
## Getting Started
|
||||
### Prerequisites
|
||||
You can run this on a platform supported by Coverity. The list and other details can be found [here](https://sig-docs.synopsys.com/polaris/topics/c_coverity-compatible-platforms.html).
|
||||
To compile and run the Coverity target successfully, you must have the following:
|
||||
|
||||
1. CMake version > 3.13.0 (You can check whether you have this by typing `cmake --version`)
|
||||
2. GCC compiler
|
||||
- You can see the downloading and installation instructions [here](https://gcc.gnu.org/install/).
|
||||
3. Download the repo and include the submodules using the following commands.
|
||||
- `git clone --recurse-submodules git@github.com:aws/Device-Defender-for-AWS-IoT-embedded-sdk.git ./Device-Defender-for-AWS-IoT-embedded-sdk`
|
||||
- `cd ./Device-Defender-for-AWS-IoT-embedded-sdk`
|
||||
- `git submodule update --checkout --init --recursive`
|
||||
|
||||
### To build and run coverity:
|
||||
Go to the root directory of the library and run the following commands in terminal:
|
||||
1. Update the compiler configuration in Coverity
|
||||
~~~
|
||||
cov-configure --force --compiler cc --comptype gcc
|
||||
~~~
|
||||
2. Create the build files using CMake in a `build` directory
|
||||
~~~
|
||||
cmake -B build -S test
|
||||
~~~
|
||||
3. Go to the build directory and copy the coverity configuration file
|
||||
~~~
|
||||
cd build/
|
||||
~~~
|
||||
4. Build the static analysis target
|
||||
~~~
|
||||
cov-build --emit-complementary-info --dir cov-out make coverity_analysis
|
||||
~~~
|
||||
5. Go to the Coverity output directory (`cov-out`) and begin Coverity static analysis
|
||||
~~~
|
||||
cd cov-out/
|
||||
cov-analyze --dir . --coding-standard-config ../../tools/coverity/misra.config --tu-pattern "file('.*/source/.*')"
|
||||
~~~
|
||||
6. Format the errors in HTML format so that it is more readable while removing the test and build directory from the report
|
||||
~~~
|
||||
cov-format-errors --dir . --file "source" --exclude-files '(/build/|/test/)' --html-output html-out;
|
||||
~~~
|
||||
7. Format the errors in JSON format to perform a jq query to get a simplified list of any exceptions.
|
||||
NOTE: A blank output means there are no defects that aren't being suppressed by the config or inline comments.
|
||||
~~~
|
||||
cov-format-errors --dir . --file "source" --exclude-files '(/build/|/test/)' --json-output-v2 defects.json;
|
||||
echo -e "\n-------------------------Non-Suppresed Deviations, if any, Listed Below-------------------------\n";
|
||||
jq '.issues[] | .events[] | .eventTag ' defects.json | sort | uniq -c | sort -nr;
|
||||
echo -e "\n-------------------------Non-Suppresed Deviations, if any, Listed Above-------------------------\n";
|
||||
~~~
|
||||
|
||||
For your convenience the commands above are below to be copy/pasted into a UNIX command friendly terminal.
|
||||
~~~
|
||||
cov-configure --force --compiler cc --comptype gcc;
|
||||
cmake -B build -S test;
|
||||
cd build/;
|
||||
cov-build --emit-complementary-info --dir cov-out make coverity_analysis;
|
||||
cd cov-out/
|
||||
cov-analyze --dir . --coding-standard-config ../../tools/coverity/misra.config;
|
||||
cov-format-errors --dir . --file "source" --exclude-files '(/build/|/test/)' --html-output html-out;
|
||||
cov-format-errors --dir . --file "source" --exclude-files '(/build/|/test/)' --json-output-v2 defects.json;
|
||||
echo -e "\n-------------------------Non-Suppresed Deviations, if any, Listed Below-------------------------\n";
|
||||
jq '.issues[] | .events[] | .eventTag ' defects.json | sort | uniq -c | sort -nr;
|
||||
echo -e "\n-------------------------Non-Suppresed Deviations, if any, Listed Above-------------------------\n";
|
||||
cd ../../;
|
||||
~~~
|
||||
|
||||
You should now have the HTML formatted violations list in a directory named `build/cov-out/html-output`.
|
||||
With the current configuration and the provided project, you should not see any deviations.
|
||||
@ -0,0 +1,27 @@
|
||||
// MISRA C-2012 Rules
|
||||
|
||||
{
|
||||
version : "2.0",
|
||||
standard : "c2012",
|
||||
title: "Coverity MISRA Configuration",
|
||||
deviations : [
|
||||
{
|
||||
deviation: "Directive 4.9",
|
||||
category: "Advisory",
|
||||
reason: "Allow inclusion of function like macros. The `assert` macro is used throughout the library for parameter validation, and logging is done using function like macros."
|
||||
},
|
||||
{
|
||||
deviation: "Rule 2.5",
|
||||
reason: "Allow unused macros. Library headers may define macros intended for the application's use, but not used by a specific file."
|
||||
},
|
||||
{
|
||||
deviation: "Rule 3.1",
|
||||
category: "Required",
|
||||
reason: "Allow nested comments. Documentation blocks contain comments for example code."
|
||||
},
|
||||
{
|
||||
deviation: "Rule 8.7",
|
||||
reason: "API functions are not used by library. They must be externally visible in order to be used by the application."
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -0,0 +1,69 @@
|
||||
cmake_minimum_required( VERSION 3.13 )
|
||||
set( BINARY_DIR ${CMAKE_BINARY_DIR} )
|
||||
|
||||
# Reset coverage counters.
|
||||
execute_process( COMMAND lcov --directory ${CMAKE_BINARY_DIR}
|
||||
--base-directory ${CMAKE_BINARY_DIR}
|
||||
--zerocounters )
|
||||
|
||||
# Create directory for results.
|
||||
execute_process( COMMAND mkdir -p ${CMAKE_BINARY_DIR}/coverage )
|
||||
|
||||
# Generate "baseline" coverage data with zero coverage for every instrumented
|
||||
# line. This is later combined with the coverage data from test run to ensure
|
||||
# that the percentage of total lines covered is correct even when not all source
|
||||
# code files were loaded during the test.
|
||||
execute_process( COMMAND lcov --directory ${CMAKE_BINARY_DIR}
|
||||
--base-directory ${CMAKE_BINARY_DIR}
|
||||
--initial
|
||||
--capture
|
||||
--rc lcov_branch_coverage=1
|
||||
--rc genhtml_branch_coverage=1
|
||||
--output-file=${CMAKE_BINARY_DIR}/base_coverage.info )
|
||||
|
||||
# Capture all the test binaries.
|
||||
file( GLOB files "${CMAKE_BINARY_DIR}/bin/tests/*" )
|
||||
|
||||
# Create an empty report file.
|
||||
set( REPORT_FILE ${CMAKE_BINARY_DIR}/utest_report.txt )
|
||||
file( WRITE ${REPORT_FILE} "" )
|
||||
|
||||
# Execute all test binaries and capture all the output in the report file.
|
||||
foreach( testname ${files} )
|
||||
get_filename_component( test ${testname} NAME_WLE )
|
||||
message( "Running ${testname}" )
|
||||
execute_process( COMMAND ${testname} OUTPUT_FILE ${CMAKE_BINARY_DIR}/${test}_out.txt )
|
||||
|
||||
# Append the test run output to the report file.
|
||||
file( READ ${CMAKE_BINARY_DIR}/${test}_out.txt CONTENTS )
|
||||
file( APPEND ${REPORT_FILE} "${CONTENTS}" )
|
||||
endforeach()
|
||||
|
||||
# Generate Junit style xml output.
|
||||
execute_process( COMMAND ruby
|
||||
${UNITY_DIR}/auto/parse_output.rb
|
||||
-xml ${REPORT_FILE}
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR} )
|
||||
|
||||
# Capture coverage data after test run.
|
||||
execute_process( COMMAND lcov --capture
|
||||
--rc lcov_branch_coverage=1
|
||||
--rc genhtml_branch_coverage=1
|
||||
--base-directory ${CMAKE_BINARY_DIR}
|
||||
--directory ${CMAKE_BINARY_DIR}
|
||||
--output-file ${CMAKE_BINARY_DIR}/second_coverage.info )
|
||||
|
||||
# Combine baseline coverage data (zeros) with the coverage data from test run.
|
||||
execute_process( COMMAND lcov --base-directory ${CMAKE_BINARY_DIR}
|
||||
--directory ${CMAKE_BINARY_DIR}
|
||||
--add-tracefile ${CMAKE_BINARY_DIR}/base_coverage.info
|
||||
--add-tracefile ${CMAKE_BINARY_DIR}/second_coverage.info
|
||||
--output-file ${CMAKE_BINARY_DIR}/coverage.info
|
||||
--no-external
|
||||
--rc lcov_branch_coverage=1 )
|
||||
|
||||
# Generate HTML Report.
|
||||
execute_process( COMMAND genhtml --rc lcov_branch_coverage=1
|
||||
--branch-coverage
|
||||
--output-directory ${CMAKE_BINARY_DIR}/coverage
|
||||
${CMAKE_BINARY_DIR}/coverage.info )
|
||||
@ -0,0 +1,64 @@
|
||||
# Function to create the test executable.
|
||||
function( create_test_binary_target test_name
|
||||
test_src
|
||||
link_list
|
||||
dep_list
|
||||
include_list )
|
||||
include ( CTest )
|
||||
get_filename_component( test_src_absolute ${test_src} ABSOLUTE )
|
||||
|
||||
# Generate test runner file.
|
||||
add_custom_command( OUTPUT ${test_name}_runner.c
|
||||
COMMAND ruby ${UNITY_DIR}/auto/generate_test_runner.rb
|
||||
${MODULE_ROOT_DIR}/tools/unity/project.yml
|
||||
${test_src_absolute}
|
||||
${test_name}_runner.c
|
||||
DEPENDS ${test_src} )
|
||||
|
||||
add_executable( ${test_name} ${test_src} ${test_name}_runner.c )
|
||||
|
||||
set_target_properties( ${test_name} PROPERTIES
|
||||
COMPILE_FLAG "-O0 -ggdb"
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/tests"
|
||||
INSTALL_RPATH_USE_LINK_PATH TRUE
|
||||
LINK_FLAGS "-Wl,-rpath,${CMAKE_BINARY_DIR}/lib \
|
||||
-Wl,-rpath,${CMAKE_CURRENT_BINARY_DIR}/lib" )
|
||||
|
||||
target_include_directories( ${test_name} PUBLIC ${mocks_dir} ${include_list} )
|
||||
|
||||
target_link_directories( ${test_name} PUBLIC ${CMAKE_CURRENT_BINARY_DIR} )
|
||||
|
||||
# Link all libraries sent through parameters.
|
||||
foreach( link IN LISTS link_list )
|
||||
target_link_libraries( ${test_name} ${link} )
|
||||
endforeach()
|
||||
|
||||
# Add dependency to all the dep_list parameter.
|
||||
foreach( dependency IN LISTS dep_list )
|
||||
add_dependencies( ${test_name} ${dependency} )
|
||||
target_link_libraries( ${test_name} ${dependency} )
|
||||
endforeach()
|
||||
|
||||
target_link_libraries( ${test_name} -lgcov unity )
|
||||
target_link_directories( ${test_name} PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/lib )
|
||||
|
||||
add_test( NAME ${test_name}
|
||||
COMMAND ${CMAKE_BINARY_DIR}/bin/tests/${test_name}
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR} )
|
||||
endfunction()
|
||||
|
||||
# Function to create target for library under test.
|
||||
function( create_library_target target_name
|
||||
src_file
|
||||
include_list )
|
||||
add_library( ${target_name} STATIC ${src_file} )
|
||||
target_include_directories( ${target_name} PUBLIC ${include_list} )
|
||||
|
||||
set_target_properties( ${target_name} PROPERTIES
|
||||
COMPILE_FLAGS "-Wextra -Wpedantic \
|
||||
-fprofile-arcs -ftest-coverage -fprofile-generate \
|
||||
-Wno-unused-but-set-variable"
|
||||
LINK_FLAGS "-fprofile-arcs -ftest-coverage \
|
||||
-fprofile-generate "
|
||||
ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lib )
|
||||
endfunction()
|
||||
@ -0,0 +1,12 @@
|
||||
:unity:
|
||||
:when_no_prototypes: :warn
|
||||
:enforce_strict_ordering: TRUE
|
||||
:treat_as:
|
||||
uint8: HEX8
|
||||
uint16: HEX16
|
||||
uint32: UINT32
|
||||
int8: INT8
|
||||
bool: UINT8
|
||||
:treat_externs: :exclude
|
||||
:weak: __attribute__((weak))
|
||||
:treat_externs: :include
|
||||
63
kernel/FreeRTOS-Plus/Source/AWS/device-shadow/.github/CONTRIBUTING.md
vendored
Normal file
63
kernel/FreeRTOS-Plus/Source/AWS/device-shadow/.github/CONTRIBUTING.md
vendored
Normal file
@ -0,0 +1,63 @@
|
||||
# Contributing Guidelines
|
||||
|
||||
Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional
|
||||
documentation, we greatly value feedback and contributions from our community.
|
||||
|
||||
Please read through this document before submitting any issues or pull requests to ensure we have all the necessary
|
||||
information to effectively respond to your bug report or contribution.
|
||||
|
||||
|
||||
## Reporting Bugs/Feature Requests
|
||||
|
||||
We welcome you to use the GitHub issue tracker to report bugs or suggest features.
|
||||
|
||||
When filing an issue, please check [existing open](https://github.com/aws/Device-Shadow-for-AWS-IoT-embedded-sdk/issues), or [recently closed](https://github.com/aws/Device-Shadow-for-AWS-IoT-embedded-sdk/issues?q=is%3Aissue+is%3Aclosed), issues to make sure somebody else hasn't already
|
||||
reported the issue. Please try to include as much information as you can. Details like these are incredibly useful:
|
||||
|
||||
* A reproducible test case or series of steps
|
||||
* The version of our code being used
|
||||
* Any modifications you've made relevant to the bug
|
||||
* Anything unusual about your environment or deployment
|
||||
|
||||
|
||||
## Contributing via Pull Requests
|
||||
Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that:
|
||||
|
||||
1. You are working against the latest source on the *main* branch.
|
||||
1. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already.
|
||||
1. You open an issue to discuss any significant work - we would hate for your time to be wasted.
|
||||
|
||||
To send us a pull request, please:
|
||||
|
||||
1. Fork the repository.
|
||||
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.
|
||||
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).
|
||||
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).
|
||||
1. Ensure local tests pass.
|
||||
1. Commit to your fork using clear commit messages.
|
||||
1. Send us a pull request, answering any default questions in the pull request interface.
|
||||
1. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation.
|
||||
|
||||
GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and
|
||||
[creating a pull request](https://help.github.com/articles/creating-a-pull-request/).
|
||||
|
||||
|
||||
## Finding contributions to work on
|
||||
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/aws/Device-Shadow-for-AWS-IoT-embedded-sdk/labels?q=help+wanted) issues is a great place to start.
|
||||
|
||||
|
||||
## Code of Conduct
|
||||
This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct).
|
||||
For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact
|
||||
opensource-codeofconduct@amazon.com with any additional questions or comments.
|
||||
|
||||
|
||||
## Security issue notifications
|
||||
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.
|
||||
|
||||
|
||||
## Licensing
|
||||
|
||||
See the [LICENSE](../LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution.
|
||||
|
||||
We may ask you to sign a [Contributor License Agreement (CLA)](https://en.wikipedia.org/wiki/Contributor_License_Agreement) for larger changes.
|
||||
12
kernel/FreeRTOS-Plus/Source/AWS/device-shadow/.github/memory_statistics_config.json
vendored
Normal file
12
kernel/FreeRTOS-Plus/Source/AWS/device-shadow/.github/memory_statistics_config.json
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"lib_name": "AWS IoT Device Shadow",
|
||||
"src": [
|
||||
"source/shadow.c"
|
||||
],
|
||||
"include": [
|
||||
"source/include"
|
||||
],
|
||||
"compiler_flags": [
|
||||
"SHADOW_DO_NOT_USE_CUSTOM_CONFIG"
|
||||
]
|
||||
}
|
||||
117
kernel/FreeRTOS-Plus/Source/AWS/device-shadow/.github/workflows/ci.yml
vendored
Normal file
117
kernel/FreeRTOS-Plus/Source/AWS/device-shadow/.github/workflows/ci.yml
vendored
Normal file
@ -0,0 +1,117 @@
|
||||
name: CI Checks
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ["**"]
|
||||
pull_request:
|
||||
branches: [main]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
unittest:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Clone This Repo
|
||||
uses: actions/checkout@v2
|
||||
- name: Build
|
||||
run: |
|
||||
sudo apt-get install -y lcov
|
||||
cmake -S test -B build/ \
|
||||
-G "Unix Makefiles" \
|
||||
-DCMAKE_BUILD_TYPE=Debug \
|
||||
-DBUILD_CLONE_SUBMODULES=ON \
|
||||
-DCMAKE_C_FLAGS='--coverage -Wall -Wextra -Werror -DNDEBUG'
|
||||
make -C build/ all
|
||||
- name: Test
|
||||
run: |
|
||||
cd build/
|
||||
ctest -E system --output-on-failure
|
||||
cd ..
|
||||
- name: Coverage
|
||||
run: |
|
||||
make -C build/ coverage
|
||||
lcov --rc lcov_branch_coverage=1 --remove build/coverage.info '*test*' --output-file build/coverage.info
|
||||
lcov --rc lcov_branch_coverage=1 --remove build/coverage.info '*CMakeCCompilerId*' --output-file build/coverage.info
|
||||
lcov --rc lcov_branch_coverage=1 --remove build/coverage.info '*mocks*' --output-file build/coverage.info
|
||||
lcov --list build/coverage.info
|
||||
- name: Check Coverage
|
||||
uses: FreeRTOS/CI-CD-Github-Actions/coverage-cop@main
|
||||
with:
|
||||
path: ./build/coverage.info
|
||||
build-with-default-config:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Clone This Repo
|
||||
uses: actions/checkout@v2
|
||||
- name: Build
|
||||
run: |
|
||||
cmake -S test -B build/ \
|
||||
-G "Unix Makefiles" \
|
||||
-DCMAKE_BUILD_TYPE=Debug \
|
||||
-DBUILD_CLONE_SUBMODULES=ON \
|
||||
-DCMAKE_C_FLAGS='-Wall -Wextra -Werror -DSHADOW_DO_NOT_USE_CUSTOM_CONFIG'
|
||||
make -C build/ all
|
||||
complexity:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Check complexity
|
||||
uses: FreeRTOS/CI-CD-Github-Actions/complexity@main
|
||||
with:
|
||||
path: ./
|
||||
doxygen:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Run doxygen build
|
||||
uses: FreeRTOS/CI-CD-Github-Actions/doxygen@main
|
||||
with:
|
||||
path: ./
|
||||
spell-check:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Clone This Repo
|
||||
uses: actions/checkout@v2
|
||||
- name: Run spellings check
|
||||
uses: FreeRTOS/CI-CD-Github-Actions/spellings@main
|
||||
with:
|
||||
path: ./
|
||||
formatting:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Check formatting
|
||||
uses: FreeRTOS/CI-CD-Github-Actions/formatting@main
|
||||
with:
|
||||
path: ./
|
||||
git-secrets:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Checkout awslabs/git-secrets
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: awslabs/git-secrets
|
||||
ref: master
|
||||
path: git-secrets
|
||||
- name: Install git-secrets
|
||||
run: cd git-secrets && sudo make install && cd ..
|
||||
- name: Run git-secrets
|
||||
run: |
|
||||
git-secrets --register-aws
|
||||
git-secrets --scan
|
||||
memory_statistics:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
- name: Install Python3
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: '3.7.10'
|
||||
- name: Measure sizes
|
||||
uses: FreeRTOS/CI-CD-Github-Actions/memory_statistics@main
|
||||
with:
|
||||
config: .github/memory_statistics_config.json
|
||||
check_against: docs/doxygen/include/size_table.md
|
||||
11
kernel/FreeRTOS-Plus/Source/AWS/device-shadow/.github/workflows/doxygen.yml
vendored
Normal file
11
kernel/FreeRTOS-Plus/Source/AWS/device-shadow/.github/workflows/doxygen.yml
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
name: Doxygen Generation
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
workflow_dispatch:
|
||||
jobs:
|
||||
doxygen-generation:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Doxygen generation
|
||||
uses: FreeRTOS/CI-CD-Github-Actions/doxygen-generation@main
|
||||
139
kernel/FreeRTOS-Plus/Source/AWS/device-shadow/.github/workflows/release.yml
vendored
Normal file
139
kernel/FreeRTOS-Plus/Source/AWS/device-shadow/.github/workflows/release.yml
vendored
Normal file
@ -0,0 +1,139 @@
|
||||
name: Release automation
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
commit_id:
|
||||
description: 'Commit ID to tag and create a release for'
|
||||
required: true
|
||||
version_number:
|
||||
description: 'Release Version Number (Eg, v1.0.0)'
|
||||
required: true
|
||||
|
||||
jobs:
|
||||
tag-commit:
|
||||
name: Tag commit
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
ref: ${{ github.event.inputs.commit_id }}
|
||||
- name: Configure git identity
|
||||
run: |
|
||||
git config --global user.name ${{ github.actor }}
|
||||
git config --global user.email ${{ github.actor }}@users.noreply.github.com
|
||||
- name: create a new branch that references commit id
|
||||
run: git checkout -b ${{ github.event.inputs.version_number }} ${{ github.event.inputs.commit_id }}
|
||||
- name: Generate SBOM
|
||||
uses: FreeRTOS/CI-CD-Github-Actions/sbom-generator@main
|
||||
with:
|
||||
repo_path: ./
|
||||
source_path: ./source
|
||||
- name: commit SBOM file
|
||||
run: |
|
||||
git add .
|
||||
git commit -m 'Update SBOM'
|
||||
git push -u origin ${{ github.event.inputs.version_number }}
|
||||
- name: Tag Commit and Push to remote
|
||||
run: |
|
||||
git tag ${{ github.event.inputs.version_number }} -a -m "AWS IoT Device Shadow ${{ github.event.inputs.version_number }}"
|
||||
git push origin --tags
|
||||
- name: Verify tag on remote
|
||||
run: |
|
||||
git tag -d ${{ github.event.inputs.version_number }}
|
||||
git remote update
|
||||
git checkout tags/${{ github.event.inputs.version_number }}
|
||||
git diff ${{ github.event.inputs.commit_id }} tags/${{ github.event.inputs.version_number }}
|
||||
create-zip:
|
||||
needs: tag-commit
|
||||
name: Create ZIP and verify package for release asset.
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Install ZIP tools
|
||||
run: sudo apt-get install zip unzip
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
ref: ${{ github.event.inputs.commit_id }}
|
||||
path: Device-Shadow-for-AWS-IoT-embedded-sdk
|
||||
submodules: recursive
|
||||
- name: Checkout disabled submodules
|
||||
run: |
|
||||
cd Device-Shadow-for-AWS-IoT-embedded-sdk
|
||||
git submodule update --init --checkout --recursive
|
||||
- name: Create ZIP
|
||||
run: |
|
||||
zip -r Device-Shadow-for-AWS-IoT-embedded-sdk-${{ github.event.inputs.version_number }}.zip Device-Shadow-for-AWS-IoT-embedded-sdk -x "*.git*"
|
||||
ls ./
|
||||
- name: Validate created ZIP
|
||||
run: |
|
||||
mkdir zip-check
|
||||
mv Device-Shadow-for-AWS-IoT-embedded-sdk-${{ github.event.inputs.version_number }}.zip zip-check
|
||||
cd zip-check
|
||||
unzip Device-Shadow-for-AWS-IoT-embedded-sdk-${{ github.event.inputs.version_number }}.zip -d Device-Shadow-for-AWS-IoT-embedded-sdk-${{ github.event.inputs.version_number }}
|
||||
ls Device-Shadow-for-AWS-IoT-embedded-sdk-${{ github.event.inputs.version_number }}
|
||||
diff -r -x "*.git*" Device-Shadow-for-AWS-IoT-embedded-sdk-${{ github.event.inputs.version_number }}/Device-Shadow-for-AWS-IoT-embedded-sdk/ ../Device-Shadow-for-AWS-IoT-embedded-sdk/
|
||||
cd ../
|
||||
- name: Build
|
||||
run: |
|
||||
cd zip-check/Device-Shadow-for-AWS-IoT-embedded-sdk-${{ github.event.inputs.version_number }}/Device-Shadow-for-AWS-IoT-embedded-sdk
|
||||
sudo apt-get install -y lcov
|
||||
cmake -S test -B build/ \
|
||||
-G "Unix Makefiles" \
|
||||
-DCMAKE_BUILD_TYPE=Debug \
|
||||
-DBUILD_CLONE_SUBMODULES=ON \
|
||||
-DCMAKE_C_FLAGS='--coverage -Wall -Wextra -Werror -DNDEBUG'
|
||||
make -C build/ all
|
||||
- name: Test
|
||||
run: |
|
||||
cd zip-check/Device-Shadow-for-AWS-IoT-embedded-sdk-${{ github.event.inputs.version_number }}/Device-Shadow-for-AWS-IoT-embedded-sdk/build/
|
||||
ctest -E system --output-on-failure
|
||||
cd ..
|
||||
- name: Create artifact of ZIP
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: Device-Shadow-for-AWS-IoT-embedded-sdk-${{ github.event.inputs.version_number }}.zip
|
||||
path: zip-check/Device-Shadow-for-AWS-IoT-embedded-sdk-${{ github.event.inputs.version_number }}.zip
|
||||
deploy-doxygen:
|
||||
needs: tag-commit
|
||||
name: Deploy doxygen documentation
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Doxygen generation
|
||||
uses: FreeRTOS/CI-CD-Github-Actions/doxygen-generation@main
|
||||
with:
|
||||
ref: ${{ github.event.inputs.version_number }}
|
||||
add_release: "true"
|
||||
create-release:
|
||||
needs:
|
||||
- create-zip
|
||||
- deploy-doxygen
|
||||
name: Create Release and Upload Release Asset
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Create Release
|
||||
id: create_release
|
||||
uses: actions/create-release@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tag_name: ${{ github.event.inputs.version_number }}
|
||||
release_name: ${{ github.event.inputs.version_number }}
|
||||
body: Release ${{ github.event.inputs.version_number }} of the AWS IoT Device Shadow.
|
||||
draft: false
|
||||
prerelease: false
|
||||
- name: Download ZIP artifact
|
||||
uses: actions/download-artifact@v2
|
||||
with:
|
||||
name: Device-Shadow-for-AWS-IoT-embedded-sdk-${{ github.event.inputs.version_number }}.zip
|
||||
- name: Upload Release Asset
|
||||
id: upload-release-asset
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: ./Device-Shadow-for-AWS-IoT-embedded-sdk-${{ github.event.inputs.version_number }}.zip
|
||||
asset_name: Device-Shadow-for-AWS-IoT-embedded-sdk-${{ github.event.inputs.version_number }}.zip
|
||||
asset_content_type: application/zip
|
||||
13
kernel/FreeRTOS-Plus/Source/AWS/device-shadow/.gitignore
vendored
Normal file
13
kernel/FreeRTOS-Plus/Source/AWS/device-shadow/.gitignore
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
# Ignore documentation output.
|
||||
**/docs/**/output/*
|
||||
|
||||
# Ignore CMake build directory.
|
||||
build/
|
||||
|
||||
# Ignore build artifacts
|
||||
*.o
|
||||
|
||||
# Ignore code coverage artifacts
|
||||
*.gcda
|
||||
*.gcno
|
||||
*.gcov
|
||||
4
kernel/FreeRTOS-Plus/Source/AWS/device-shadow/.gitmodules
vendored
Normal file
4
kernel/FreeRTOS-Plus/Source/AWS/device-shadow/.gitmodules
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
[submodule "test/unit-test/CMock"]
|
||||
path = test/unit-test/CMock
|
||||
url = https://github.com/ThrowTheSwitch/CMock
|
||||
update = none
|
||||
54
kernel/FreeRTOS-Plus/Source/AWS/device-shadow/CHANGELOG.md
Normal file
54
kernel/FreeRTOS-Plus/Source/AWS/device-shadow/CHANGELOG.md
Normal file
@ -0,0 +1,54 @@
|
||||
# Changelog for AWS IoT Device Shadow library
|
||||
|
||||
|
||||
## v1.3.0 (October 2022)
|
||||
|
||||
### Other
|
||||
- [#102](https://github.com/aws/Device-Shadow-for-AWS-IoT-embedded-sdk/pull/102) MISRA C:2012 compliance update
|
||||
- [#101](https://github.com/aws/Device-Shadow-for-AWS-IoT-embedded-sdk/pull/101) Update CBMC starter kit
|
||||
- [#98](https://github.com/aws/Device-Shadow-for-AWS-IoT-embedded-sdk/pull/98) Loop invariant update
|
||||
|
||||
## v1.2.0 (November 2021)
|
||||
|
||||
### Other
|
||||
- [#93](https://github.com/aws/Device-Shadow-for-AWS-IoT-embedded-sdk/pull/93) Rename master references to main.
|
||||
- [#94](https://github.com/aws/Device-Shadow-for-AWS-IoT-embedded-sdk/pull/94) Updated CBMC proof.
|
||||
|
||||
## v1.1.1 (July 2021)
|
||||
|
||||
### Other
|
||||
- [#85](https://github.com/aws/Device-Shadow-for-AWS-IoT-embedded-sdk/pull/85) Fix CBMC proof for `Shadow_AssembleTopicString` API.
|
||||
- [#88](https://github.com/aws/Device-Shadow-for-AWS-IoT-embedded-sdk/pull/88) Update broken MISRA link
|
||||
|
||||
## v1.1.0 (March 2021)
|
||||
|
||||
### Updates
|
||||
- [#56](https://github.com/aws/device-shadow-for-aws-iot-embedded-sdk/pull/56), [#56](https://github.com/aws/device-shadow-for-aws-iot-embedded-sdk/pull/72) and [#73](https://github.com/aws/device-shadow-for-aws-iot-embedded-sdk/pull/73) Add support for named shadow, a feature of the AWS IoT Device Shadow service that allows you to create multiple shadows for a single IoT device.
|
||||
|
||||
### Other
|
||||
- [#74](https://github.com/aws/device-shadow-for-aws-iot-embedded-sdk/pull/74) Add CBMC proof for `Shadow_MatchTopic` API.
|
||||
|
||||
## v1.0.2 (December 2020)
|
||||
|
||||
### Updates
|
||||
- [#60](https://github.com/aws/device-shadow-for-aws-iot-embedded-sdk/pull/60) Cast logging arguments to C types matching the format specifier.
|
||||
|
||||
### Other
|
||||
- [#51](https://github.com/aws/device-shadow-for-aws-iot-embedded-sdk/pull/51) Formatting update.
|
||||
- [#57](https://github.com/aws/device-shadow-for-aws-iot-embedded-sdk/pull/57) Fix a broken link.
|
||||
- [#54](https://github.com/aws/device-shadow-for-aws-iot-embedded-sdk/pull/54), [#62](https://github.com/aws/device-shadow-for-aws-iot-embedded-sdk/pull/62) Github actions update.
|
||||
- [#58](https://github.com/aws/device-shadow-for-aws-iot-embedded-sdk/pull/58), [#61](https://github.com/aws/device-shadow-for-aws-iot-embedded-sdk/pull/61) Github repo chores
|
||||
- [#53](https://github.com/aws/device-shadow-for-aws-iot-embedded-sdk/pull/53) CBMC automation update.
|
||||
|
||||
## v1.0.1 (November 2020)
|
||||
|
||||
### Updates
|
||||
- [#41](https://github.com/aws/device-shadow-for-aws-iot-embedded-sdk/pull/41) Resolve build warning from visual studio due to terminator character.
|
||||
- [#35](https://github.com/aws/device-shadow-for-aws-iot-embedded-sdk/pull/35) Configure submodules to not be cloned by default.
|
||||
|
||||
### Other
|
||||
- [#19](https://github.com/aws/device-shadow-for-aws-iot-embedded-sdk/pull/19), [#27](https://github.com/aws/device-shadow-for-aws-iot-embedded-sdk/pull/27), [#29](https://github.com/aws/device-shadow-for-aws-iot-embedded-sdk/pull/29), [#32](https://github.com/aws/device-shadow-for-aws-iot-embedded-sdk/pull/32),[#34](https://github.com/aws/device-shadow-for-aws-iot-embedded-sdk/pull/34), [#43](https://github.com/aws/device-shadow-for-aws-iot-embedded-sdk/pull/43),[#44](https://github.com/aws/device-shadow-for-aws-iot-embedded-sdk/pull/44) Minor documentation updates.
|
||||
|
||||
## v1.0.0 (September 2020)
|
||||
|
||||
This is the first release of the Device Shadow library in this repository.
|
||||
21
kernel/FreeRTOS-Plus/Source/AWS/device-shadow/LICENSE
Normal file
21
kernel/FreeRTOS-Plus/Source/AWS/device-shadow/LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
15
kernel/FreeRTOS-Plus/Source/AWS/device-shadow/MISRA.md
Normal file
15
kernel/FreeRTOS-Plus/Source/AWS/device-shadow/MISRA.md
Normal file
@ -0,0 +1,15 @@
|
||||
# MISRA Compliance
|
||||
|
||||
The Device Shadow Library files conform to the [MISRA C:2012](https://www.misra.org.uk)
|
||||
guidelines, with some noted exceptions. Compliance is checked with Coverity static analysis.
|
||||
The specific deviations, suppressed inline, are listed below.
|
||||
|
||||
Additionally, [MISRA configuration file](https://github.com/aws/Device-Shadow-for-AWS-IoT-embedded-sdk/blob/main/tools/coverity/misra.config) contains the project wide deviations.
|
||||
|
||||
### Suppressed with Coverity Comments
|
||||
To find the violation references in the source files run grep on the source code
|
||||
with ( Assuming rule 11.4 violation; with justification in point 2 ):
|
||||
```
|
||||
grep 'MISRA Ref 11.4.2' . -rI
|
||||
|
||||
*None.*
|
||||
103
kernel/FreeRTOS-Plus/Source/AWS/device-shadow/README.md
Normal file
103
kernel/FreeRTOS-Plus/Source/AWS/device-shadow/README.md
Normal file
@ -0,0 +1,103 @@
|
||||
# AWS IoT Device Shadow library
|
||||
|
||||
The AWS IoT Device Shadow library enables you to store and retrieve the current state (the “shadow”) of every registered device. The device’s shadow is a persistent, virtual representation of your device that you can interact with from AWS IoT Core even if the device is offline. The device state is captured as its “shadow” within a [JSON](https://www.json.org/) document. The device can send commands over MQTT to get, update and delete its latest state as well as receive notifications over MQTT about changes in its state. Each device’s shadow is uniquely identified by the name of the corresponding “thing”, a representation of a specific device or logical entity on the AWS Cloud. See [Managing Devices with AWS IoT](https://docs.aws.amazon.com/iot/latest/developerguide/iot-thing-management.html) for more information on IoT "thing". More details about AWS IoT Device Shadow can be found in [AWS IoT documentation](https://docs.aws.amazon.com/iot/latest/developerguide/iot-device-shadows.html). This library is distributed under the [MIT Open Source License](LICENSE).
|
||||
|
||||
**Note**: From [v1.1.0](https://github.com/aws/Device-Shadow-for-AWS-IoT-embedded-sdk/tree/v1.1.0) release onwards, you can used named shadow, a feature of the AWS IoT Device Shadow service that allows you to create multiple shadows for a single IoT device.
|
||||
|
||||
This library has gone through code quality checks including verification that no function has a [GNU Complexity](https://www.gnu.org/software/complexity/manual/complexity.html) score over 8, and checks against deviations from mandatory rules in the [MISRA coding standard](https://www.misra.org.uk). Deviations from the MISRA C:2012 guidelines are documented under [MISRA Deviations](MISRA.md). This library has also undergone both static code analysis from [Coverity static analysis](https://scan.coverity.com/), and validation of memory safety through the [CBMC automated reasoning tool](https://www.cprover.org/cbmc/).
|
||||
|
||||
See memory requirements for this library [here](https://docs.aws.amazon.com/embedded-csdk/202103.00/lib-ref/libraries/aws/device-shadow-for-aws-iot-embedded-sdk/docs/doxygen/output/html/index.html#shadow_memory_requirements).
|
||||
|
||||
**AWS IoT Device Shadow v1.3.0 [source code](https://github.com/aws/Device-Shadow-for-AWS-IoT-embedded-sdk/tree/v1.3.0) is part of the [FreeRTOS 202210.00 LTS](https://github.com/FreeRTOS/FreeRTOS-LTS/tree/202210.00-LTS) release.**
|
||||
|
||||
**AWS IoT Device Shadow v1.0.2 [source code](https://github.com/aws/Device-Shadow-for-AWS-IoT-embedded-sdk/tree/v1.0.2) is part of the [FreeRTOS 202012.00 LTS](https://github.com/FreeRTOS/FreeRTOS-LTS/tree/202012.00-LTS) release.**
|
||||
|
||||
### AWS IoT Device Shadow Config File
|
||||
The AWS IoT Device Shadow library exposes configuration macros that are required for building the library.
|
||||
A list of all the configurations and their default values are defined in [shadow_config_defaults.h](source/include/shadow_config_defaults.h).
|
||||
To provide custom values for the configuration macros, a custom config file named `shadow_config.h` can be provided by the user application to the library.
|
||||
|
||||
By default, a `shadow_config.h` custom config is required to build the library. To disable this requirement
|
||||
and build the library with default configuration values, provide `SHADOW_DO_NOT_USE_CUSTOM_CONFIG` as a compile time preprocessor macro.
|
||||
|
||||
## Building the Library
|
||||
|
||||
The [shadowFilePaths.cmake](shadowFilePaths.cmake) file contains the information of all source files and the header include path required to build the AWS IoT Device Shadow library.
|
||||
|
||||
As mentioned in the [previous section](#aws-iot-device-shadow-config-file), either a custom config file (i.e. `shadow_config.h`) OR the `SHADOW_DO_NOT_USE_CUSTOM_CONFIG` macro needs to be provided to build the AWS IoT Device Shadow library.
|
||||
|
||||
For a CMake example of building the AWS IoT Device Shadow library with the `shadowFilePaths.cmake` file, refer to the `coverity_analysis` library target in [test/CMakeLists.txt](test/CMakeLists.txt) file.
|
||||
|
||||
## Building Unit Tests
|
||||
|
||||
### Checkout CMock Submodule
|
||||
By default, the submodules in this repository are configured with `update=none` in [.gitmodules](.gitmodules) to avoid increasing clone time and disk space usage of other repositories (like [amazon-freertos](https://github.com/aws/amazon-freertos) that submodules this repository).
|
||||
|
||||
|
||||
To build unit tests, the submodule dependency of CMock is required. Use the following command to clone the submodule:
|
||||
```
|
||||
git submodule update --checkout --init --recursive --test/unit-test/CMock
|
||||
```
|
||||
|
||||
### Platform Prerequisites
|
||||
|
||||
- For building the library, **CMake 3.13.0** or later and a **C90 compiler**.
|
||||
- For running unit tests, **Ruby 2.0.0** or later is additionally required for the CMock test framework (that we use).
|
||||
- For running the coverage target, **gcov** and **lcov** are additionally required.
|
||||
|
||||
### Steps to build unit tests
|
||||
|
||||
1. Go to the root directory of this repository. (Make sure that the **CMock** submodule is cloned as described [above](#checkout-cmock-submodule).)
|
||||
|
||||
1. Run the *cmake* command: `cmake -S test -B build`
|
||||
|
||||
1. Run this command to build the library and unit tests: `make -C build all`
|
||||
|
||||
1. The generated test executables will be present in `build/bin/tests` folder.
|
||||
|
||||
1. Run `cd build && ctest` to execute all tests and view the test run summary.
|
||||
|
||||
## CBMC
|
||||
|
||||
To learn more about CBMC and proofs specifically, review the training material [here](https://model-checking.github.io/cbmc-training).
|
||||
|
||||
The `test/cbmc/proofs` directory contains CBMC proofs.
|
||||
|
||||
In order to run these proofs you will need to install CBMC and other tools by following the instructions [here](https://model-checking.github.io/cbmc-training/installation.html).
|
||||
|
||||
## Reference examples
|
||||
|
||||
Please refer to the demos of the AWS IoT Device Shadow library in the following locations for reference examples on POSIX and FreeRTOS platforms:
|
||||
|
||||
| Platform | Location | Transport Interface Implementation <br> (for [coreMQTT](https://github.com/FreeRTOS/coreMQTT) stack) </br> |
|
||||
| :-: | :-: | :-: |
|
||||
| POSIX | [AWS IoT Device SDK for Embedded C](https://github.com/aws/aws-iot-device-sdk-embedded-C/tree/main/demos/shadow/shadow_demo_main) | POSIX sockets for TCP/IP and OpenSSL for TLS stack
|
||||
| FreeRTOS | [FreeRTOS/FreeRTOS](https://github.com/FreeRTOS/FreeRTOS/tree/main/FreeRTOS-Plus/Demo/AWS/Device_Shadow_Windows_Simulator) | FreeRTOS+TCP for TCP/IP and mbedTLS for TLS stack |
|
||||
| FreeRTOS | [FreeRTOS AWS Reference Integrations](https://github.com/aws/amazon-freertos/tree/main/demos/device_shadow_for_aws) | Based on Secure Sockets Abstraction |
|
||||
|
||||
## Documentation
|
||||
|
||||
### Existing Documentation
|
||||
|
||||
For pre-generated documentation, please see the documentation linked in the locations below:
|
||||
|
||||
| Location |
|
||||
| :-: |
|
||||
| [AWS IoT Device SDK for Embedded C](https://github.com/aws/aws-iot-device-sdk-embedded-C#releases-and-documentation) |
|
||||
| [FreeRTOS.org](https://freertos.org/Documentation/api-ref/device-shadow-for-aws-iot-embedded-sdk/docs/doxygen/output/html/index.html) |
|
||||
|
||||
Note that the latest included version of IoT Device Shadow library may differ across repositories.
|
||||
|
||||
|
||||
## Generating documentation
|
||||
|
||||
The Doxygen references were created using Doxygen version 1.9.2. To generate the
|
||||
Doxygen pages, please run the following command from the root of this repository:
|
||||
|
||||
```shell
|
||||
doxygen docs/doxygen/config.doxyfile
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
||||
See [CONTRIBUTING.md](./.github/CONTRIBUTING.md) for information on contributing.
|
||||
@ -0,0 +1,5 @@
|
||||
## Reporting a Vulnerability
|
||||
|
||||
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/) or directly via email to aws-security@amazon.com.
|
||||
Please do **not** create a public github issue.
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,20 @@
|
||||
<table>
|
||||
<tr>
|
||||
<td colspan="3"><center><b>Code Size of AWS IoT Device Shadow (example generated with GCC for ARM Cortex-M)</b></center></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>File</b></td>
|
||||
<td><b><center>With -O1 Optimization</center></b></td>
|
||||
<td><b><center>With -Os Optimization</center></b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>shadow.c</td>
|
||||
<td><center>1.2K</center></td>
|
||||
<td><center>0.9K</center></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Total estimates</b></td>
|
||||
<td><b><center>1.2K</center></b></td>
|
||||
<td><b><center>0.9K</center></b></td>
|
||||
</tr>
|
||||
</table>
|
||||
@ -0,0 +1,228 @@
|
||||
<doxygenlayout version="1.0">
|
||||
<!-- Generated by doxygen 1.8.20 -->
|
||||
<!-- Navigation index tabs for HTML output -->
|
||||
<navindex>
|
||||
<tab type="mainpage" visible="yes" title=""/>
|
||||
<tab type="pages" visible="yes" title="" intro=""/>
|
||||
<!-- Hide the default "Data Structures" tab and use the "Modules" tab for data
|
||||
structures. This allows internal data structures to be hidden. -->
|
||||
<tab type="modules" visible="yes" title="Data types and Constants" intro="This library defines the following data types and constants."/>
|
||||
<tab type="namespaces" visible="yes" title="">
|
||||
<tab type="namespacelist" visible="yes" title="" intro=""/>
|
||||
<tab type="namespacemembers" visible="yes" title="" intro=""/>
|
||||
</tab>
|
||||
<tab type="interfaces" visible="no" title="">
|
||||
<tab type="interfacelist" visible="no" title="" intro=""/>
|
||||
<tab type="interfaceindex" visible="no" title=""/>
|
||||
<tab type="interfacehierarchy" visible="yes" title="" intro=""/>
|
||||
</tab>
|
||||
<tab type="classes" visible="no" title="">
|
||||
<tab type="classlist" visible="no" title="" intro=""/>
|
||||
<tab type="classindex" visible="no" title=""/>
|
||||
<tab type="hierarchy" visible="no" title="" intro=""/>
|
||||
<tab type="classmembers" visible="no" title="" intro=""/>
|
||||
</tab>
|
||||
<tab type="structs" visible="no" title="">
|
||||
<tab type="structlist" visible="no" title="" intro=""/>
|
||||
<tab type="structindex" visible="no" title=""/>
|
||||
</tab>
|
||||
<tab type="exceptions" visible="no" title="">
|
||||
<tab type="exceptionlist" visible="no" title="" intro=""/>
|
||||
<tab type="exceptionindex" visible="no" title=""/>
|
||||
<tab type="exceptionhierarchy" visible="yes" title="" intro=""/>
|
||||
</tab>
|
||||
<tab type="files" visible="no" title="">
|
||||
<tab type="filelist" visible="yes" title="Files" intro="The following files are associated with this library."/>
|
||||
<tab type="globals" visible="no" title="" intro=""/>
|
||||
</tab>
|
||||
<tab type="examples" visible="yes" title="" intro=""/>
|
||||
</navindex>
|
||||
|
||||
<!-- Layout definition for a class page -->
|
||||
<class>
|
||||
<briefdescription visible="yes"/>
|
||||
<includes visible="$SHOW_INCLUDE_FILES"/>
|
||||
<inheritancegraph visible="$CLASS_GRAPH"/>
|
||||
<collaborationgraph visible="$COLLABORATION_GRAPH"/>
|
||||
<memberdecl>
|
||||
<nestedclasses visible="yes" title=""/>
|
||||
<publictypes title=""/>
|
||||
<services title=""/>
|
||||
<interfaces title=""/>
|
||||
<publicslots title=""/>
|
||||
<signals title=""/>
|
||||
<publicmethods title=""/>
|
||||
<publicstaticmethods title=""/>
|
||||
<publicattributes title=""/>
|
||||
<publicstaticattributes title=""/>
|
||||
<protectedtypes title=""/>
|
||||
<protectedslots title=""/>
|
||||
<protectedmethods title=""/>
|
||||
<protectedstaticmethods title=""/>
|
||||
<protectedattributes title=""/>
|
||||
<protectedstaticattributes title=""/>
|
||||
<packagetypes title=""/>
|
||||
<packagemethods title=""/>
|
||||
<packagestaticmethods title=""/>
|
||||
<packageattributes title=""/>
|
||||
<packagestaticattributes title=""/>
|
||||
<properties title=""/>
|
||||
<events title=""/>
|
||||
<privatetypes title=""/>
|
||||
<privateslots title=""/>
|
||||
<privatemethods title=""/>
|
||||
<privatestaticmethods title=""/>
|
||||
<privateattributes title=""/>
|
||||
<privatestaticattributes title=""/>
|
||||
<friends title=""/>
|
||||
<related title="" subtitle=""/>
|
||||
<membergroups visible="yes"/>
|
||||
</memberdecl>
|
||||
<detaileddescription title=""/>
|
||||
<memberdef>
|
||||
<inlineclasses title=""/>
|
||||
<typedefs title=""/>
|
||||
<enums title=""/>
|
||||
<services title=""/>
|
||||
<interfaces title=""/>
|
||||
<constructors title=""/>
|
||||
<functions title=""/>
|
||||
<related title=""/>
|
||||
<variables title=""/>
|
||||
<properties title=""/>
|
||||
<events title=""/>
|
||||
</memberdef>
|
||||
<allmemberslink visible="yes"/>
|
||||
<usedfiles visible="$SHOW_USED_FILES"/>
|
||||
<authorsection visible="yes"/>
|
||||
</class>
|
||||
|
||||
<!-- Layout definition for a namespace page -->
|
||||
<namespace>
|
||||
<briefdescription visible="yes"/>
|
||||
<memberdecl>
|
||||
<nestednamespaces visible="yes" title=""/>
|
||||
<constantgroups visible="yes" title=""/>
|
||||
<interfaces visible="yes" title=""/>
|
||||
<classes visible="yes" title=""/>
|
||||
<structs visible="yes" title=""/>
|
||||
<exceptions visible="yes" title=""/>
|
||||
<typedefs title=""/>
|
||||
<sequences title=""/>
|
||||
<dictionaries title=""/>
|
||||
<enums title=""/>
|
||||
<functions title=""/>
|
||||
<variables title=""/>
|
||||
<membergroups visible="yes"/>
|
||||
</memberdecl>
|
||||
<detaileddescription title=""/>
|
||||
<memberdef>
|
||||
<inlineclasses title=""/>
|
||||
<typedefs title=""/>
|
||||
<sequences title=""/>
|
||||
<dictionaries title=""/>
|
||||
<enums title=""/>
|
||||
<functions title=""/>
|
||||
<variables title=""/>
|
||||
</memberdef>
|
||||
<authorsection visible="yes"/>
|
||||
</namespace>
|
||||
|
||||
<!-- Layout definition for a file page -->
|
||||
<file>
|
||||
<briefdescription visible="yes"/>
|
||||
<includes visible="$SHOW_INCLUDE_FILES"/>
|
||||
<includegraph visible="$INCLUDE_GRAPH"/>
|
||||
<includedbygraph visible="$INCLUDED_BY_GRAPH"/>
|
||||
<sourcelink visible="yes"/>
|
||||
<memberdecl>
|
||||
<interfaces visible="yes" title=""/>
|
||||
<classes visible="yes" title=""/>
|
||||
<structs visible="yes" title=""/>
|
||||
<exceptions visible="yes" title=""/>
|
||||
<namespaces visible="yes" title=""/>
|
||||
<constantgroups visible="yes" title=""/>
|
||||
<defines title=""/>
|
||||
<typedefs title=""/>
|
||||
<sequences title=""/>
|
||||
<dictionaries title=""/>
|
||||
<enums title=""/>
|
||||
<functions title=""/>
|
||||
<variables title=""/>
|
||||
<membergroups visible="yes"/>
|
||||
</memberdecl>
|
||||
<detaileddescription title=""/>
|
||||
<memberdef>
|
||||
<inlineclasses title=""/>
|
||||
<defines title=""/>
|
||||
<typedefs title=""/>
|
||||
<sequences title=""/>
|
||||
<dictionaries title=""/>
|
||||
<enums title=""/>
|
||||
<functions title=""/>
|
||||
<variables title=""/>
|
||||
</memberdef>
|
||||
<authorsection/>
|
||||
</file>
|
||||
|
||||
<!-- Layout definition for a group page -->
|
||||
<group>
|
||||
<briefdescription visible="yes"/>
|
||||
<groupgraph visible="$GROUP_GRAPHS"/>
|
||||
<memberdecl>
|
||||
<nestedgroups visible="yes" title=""/>
|
||||
<dirs visible="yes" title=""/>
|
||||
<files visible="yes" title=""/>
|
||||
<namespaces visible="yes" title=""/>
|
||||
<classes visible="yes" title=""/>
|
||||
<defines title=""/>
|
||||
<typedefs title=""/>
|
||||
<sequences title=""/>
|
||||
<dictionaries title=""/>
|
||||
<enums title=""/>
|
||||
<enumvalues title=""/>
|
||||
<functions title=""/>
|
||||
<variables title=""/>
|
||||
<signals title=""/>
|
||||
<publicslots title=""/>
|
||||
<protectedslots title=""/>
|
||||
<privateslots title=""/>
|
||||
<events title=""/>
|
||||
<properties title=""/>
|
||||
<friends title=""/>
|
||||
<membergroups visible="yes"/>
|
||||
</memberdecl>
|
||||
<detaileddescription title=""/>
|
||||
<memberdef>
|
||||
<pagedocs/>
|
||||
<inlineclasses title=""/>
|
||||
<defines title=""/>
|
||||
<typedefs title=""/>
|
||||
<sequences title=""/>
|
||||
<dictionaries title=""/>
|
||||
<enums title=""/>
|
||||
<enumvalues title=""/>
|
||||
<functions title=""/>
|
||||
<variables title=""/>
|
||||
<signals title=""/>
|
||||
<publicslots title=""/>
|
||||
<protectedslots title=""/>
|
||||
<privateslots title=""/>
|
||||
<events title=""/>
|
||||
<properties title=""/>
|
||||
<friends title=""/>
|
||||
</memberdef>
|
||||
<authorsection visible="yes"/>
|
||||
</group>
|
||||
|
||||
<!-- Layout definition for a directory page -->
|
||||
<directory>
|
||||
<briefdescription visible="yes"/>
|
||||
<directorygraph visible="yes"/>
|
||||
<memberdecl>
|
||||
<dirs visible="yes"/>
|
||||
<files visible="yes"/>
|
||||
</memberdecl>
|
||||
<detaileddescription title=""/>
|
||||
</directory>
|
||||
</doxygenlayout>
|
||||
@ -0,0 +1,80 @@
|
||||
/**
|
||||
@mainpage Overview
|
||||
@anchor shadow
|
||||
@brief AWS IoT Device Shadow library
|
||||
|
||||
> Device Shadows can make a device’s state available to apps and other services whether the device is connected to AWS IoT or not. AWS IoT thing objects can have multiple named shadows so that your IoT solution has more options for connecting your devices to other apps and services. AWS IoT thing objects do not have any named shadows until they are created explicitly; however, an unnamed, classic shadow is created for a thing when the thing is created.
|
||||
<span style="float:right;margin-right:4em"> — <i>Description of Device Shadow from AWS IoT documentation [https://docs.aws.amazon.com/iot/latest/developerguide/iot-device-shadows.html](https://docs.aws.amazon.com/iot/latest/developerguide/iot-device-shadows.html)</i></span><br>
|
||||
|
||||
A device's shadow is stored as a JSON document, and available via AWS even if the associated device goes offline. Common use cases for Device Shadow include backing up device state, or sending commands to devices.
|
||||
|
||||
Embedded devices often use MQTT to interact with Device Shadow. This library provides a convenience API for handling MQTT topics reserved for Device Shadow. This library is independent of the MQTT library. Applications can use the macros and functions of this library to assemble and parse the Device Shadow MQTT topics, then use any MQTT library to publish/subscribe to those topics. Features of this library include:
|
||||
- It is stateless. It does not use any global/static memory.
|
||||
- It depends on standard C library (string.h and stdint.h) only.
|
||||
|
||||
@section shadow_memory_requirements Memory Requirements
|
||||
@brief Memory requirements of the Shadow library.
|
||||
|
||||
@include{doc} size_table.md
|
||||
*/
|
||||
|
||||
/**
|
||||
@page shadow_design Design
|
||||
Shadow Library Design
|
||||
|
||||
The Device Shadow library is designed as a set of convenience macros and functions that are used to assemble and parse MQTT topic strings reserved for the Device Shadow. It does not wrap any function of the MQTT stack underneath. An application can use any MQTT library of its choice to interact with the Device Shadow service.
|
||||
|
||||
The diagram below demonstrates how an application uses the Device Shadow library, a MQTT library, and a JSON library to interact with the Device Shadow service.
|
||||
|
||||
\image html shadow_design_operation.png "Shadow Demo operation diagram" width=1000px
|
||||
*/
|
||||
|
||||
/**
|
||||
@page shadow_config Configurations
|
||||
@brief Configurations of the Shadow Library.
|
||||
<!-- @par configpagestyle allows the @section titles to be styled according to style.css -->
|
||||
@par configpagestyle
|
||||
|
||||
Some configuration settings are C pre-processor constants, and some are function-like macros for logging. They can be set with a `\#define` in the config file (**shadow_config.h**) or by using a compiler option such as -D in gcc.
|
||||
|
||||
@section SHADOW_DO_NOT_USE_CUSTOM_CONFIG
|
||||
@copydoc SHADOW_DO_NOT_USE_CUSTOM_CONFIG
|
||||
|
||||
@section shadow_logerror LogError
|
||||
@copydoc LogError
|
||||
|
||||
@section shadow_logwarn LogWarn
|
||||
@copydoc LogWarn
|
||||
|
||||
@section shadow_loginfo LogInfo
|
||||
@copydoc LogInfo
|
||||
|
||||
@section shadow_logdebug LogDebug
|
||||
@copydoc LogDebug
|
||||
*/
|
||||
|
||||
/**
|
||||
@page shadow_functions Functions
|
||||
@brief Primary functions of the Shadow library:<br><br>
|
||||
@subpage shadow_matchtopicstring_function <br>
|
||||
@subpage shadow_assembletopicstring_function <br>
|
||||
|
||||
@page shadow_matchtopicstring_function Shadow_MatchTopicString
|
||||
@snippet shadow.h declare_shadow_matchtopicstring
|
||||
@copydoc Shadow_MatchTopicString
|
||||
|
||||
@page shadow_assembletopicstring_function Shadow_AssembleTopicString
|
||||
@snippet shadow.h declare_shadow_assembletopicstring
|
||||
@copydoc Shadow_AssembleTopicString
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@defgroup shadow_enum_types Enumerated Types
|
||||
@brief Enumerated types of the Shadow library
|
||||
*/
|
||||
|
||||
/**
|
||||
@defgroup shadow_constants Constants
|
||||
@brief Constants defined in the Shadow library
|
||||
*/
|
||||
@ -0,0 +1,19 @@
|
||||
/**
|
||||
@page shadow_porting Porting Guide
|
||||
@brief Guide for porting Shadow to a new platform.
|
||||
|
||||
@section shadow_porting_config Configuration Macros
|
||||
@brief Settings that can be set as macros in the config header `shadow_config.h`, or passed in as compiler options.
|
||||
|
||||
The following optional logging macros are used throughout the library:
|
||||
- @ref LogError
|
||||
- @ref LogWarn
|
||||
- @ref LogInfo
|
||||
- @ref LogDebug
|
||||
|
||||
@see [Configurations](@ref shadow_config) for more information.
|
||||
|
||||
@note Regardless of whether the following macros are defined in `shadow_config.h` or passed as compiler options,
|
||||
the `shadow_config.h` file must be included to build the Shadow library. To disable this requirement
|
||||
and build the library with default configuration values, provide `SHADOW_DO_NOT_USE_CUSTOM_CONFIG` as a compile time preprocessor macro.
|
||||
*/
|
||||
@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Stylesheet for Doxygen HTML output.
|
||||
*
|
||||
* This file defines styles for custom elements in the header/footer and
|
||||
* overrides some of the default Doxygen styles.
|
||||
*
|
||||
* Styles in this file do not affect the treeview sidebar.
|
||||
*/
|
||||
|
||||
/* Set the margins to place a small amount of whitespace on the left and right
|
||||
* side of the page. */
|
||||
div.contents {
|
||||
margin-left:4em;
|
||||
margin-right:4em;
|
||||
}
|
||||
|
||||
/* Justify text in paragraphs. */
|
||||
p {
|
||||
text-align: justify;
|
||||
}
|
||||
|
||||
/* Style of section headings. */
|
||||
h1 {
|
||||
border-bottom: 1px solid #879ECB;
|
||||
color: #354C7B;
|
||||
font-size: 160%;
|
||||
font-weight: normal;
|
||||
padding-bottom: 4px;
|
||||
padding-top: 8px;
|
||||
}
|
||||
|
||||
/* Style of subsection headings. */
|
||||
h2:not(.memtitle):not(.groupheader) {
|
||||
font-size: 125%;
|
||||
margin-bottom: 0px;
|
||||
margin-top: 16px;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
/* Style of paragraphs immediately after subsection headings. */
|
||||
h2 + p {
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
/* Style of subsection headings. */
|
||||
h3 {
|
||||
font-size: 100%;
|
||||
margin-bottom: 0px;
|
||||
margin-left: 2em;
|
||||
margin-right: 2em;
|
||||
}
|
||||
|
||||
/* Style of paragraphs immediately after subsubsection headings. */
|
||||
h3 + p {
|
||||
margin-top: 0px;
|
||||
margin-left: 2em;
|
||||
margin-right: 2em;
|
||||
}
|
||||
|
||||
/* Style of the prefix "AWS IoT Device SDK C" that appears in the header. */
|
||||
#csdkprefix {
|
||||
color: #757575;
|
||||
}
|
||||
|
||||
/* Style of the "Return to main page" link that appears in the header. */
|
||||
#returntomain {
|
||||
padding: 0.5em;
|
||||
}
|
||||
|
||||
/* Style of the dividers on Configuration Settings pages. */
|
||||
div.configpagedivider {
|
||||
margin-left: 0px !important;
|
||||
margin-right: 0px !important;
|
||||
margin-top: 20px !important;
|
||||
}
|
||||
|
||||
/* Style of configuration setting names. */
|
||||
dl.section.user ~ h1 {
|
||||
border-bottom: none;
|
||||
color: #000000;
|
||||
font-family: monospace, fixed;
|
||||
font-size: 16px;
|
||||
margin-bottom: 0px;
|
||||
margin-left: 2em;
|
||||
margin-top: 1.5em;
|
||||
}
|
||||
|
||||
/* Style of paragraphs on a configuration settings page. */
|
||||
dl.section.user ~ * {
|
||||
margin-bottom: 10px;
|
||||
margin-left: 4em;
|
||||
margin-right: 4em;
|
||||
margin-top: 0px;
|
||||
}
|
||||
|
||||
/* Hide the configuration setting marker. */
|
||||
dl.section.user {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Overrides for code fragments and lines. */
|
||||
div.fragment {
|
||||
background: #ffffff;
|
||||
border: none;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
div.line {
|
||||
color: #3a3a3a;
|
||||
}
|
||||
|
||||
/* Overrides for code syntax highlighting colors. */
|
||||
span.comment {
|
||||
color: #008000;
|
||||
}
|
||||
|
||||
span.keyword, span.keywordtype, span.keywordflow {
|
||||
color: #0000ff;
|
||||
}
|
||||
|
||||
span.preprocessor {
|
||||
color: #50015a;
|
||||
}
|
||||
|
||||
span.stringliteral, span.charliteral {
|
||||
color: #800c0c;
|
||||
}
|
||||
|
||||
a.code, a.code:visited, a.line, a.line:visited {
|
||||
color: #496194;
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 279 KiB |
@ -0,0 +1,65 @@
|
||||
@startuml
|
||||
skinparam classFontSize 8
|
||||
skinparam classFontName Helvetica
|
||||
autonumber
|
||||
|
||||
box "Application" #LightGreen
|
||||
participant "Application" as application
|
||||
participant "Callback" as callback
|
||||
end box
|
||||
|
||||
box "Libraries" #LightBlue
|
||||
participant "JSON" as json
|
||||
|
||||
participant "Shadow" as shadow
|
||||
|
||||
participant "MQTT" as mqtt
|
||||
|
||||
end box
|
||||
|
||||
activate application
|
||||
application -> mqtt : Establish\nMQTT Connection\nwith\ncallback function
|
||||
|
||||
|
||||
activate mqtt
|
||||
mqtt -> mqtt : Initialization with the callback
|
||||
mqtt -> : Connect to the broker
|
||||
mqtt -> application : Return from MQTT library
|
||||
deactivate mqtt
|
||||
|
||||
application -> shadow : Get shadow topics
|
||||
|
||||
activate shadow
|
||||
shadow -> application : Return assembled\nshadow topics
|
||||
deactivate shadow
|
||||
|
||||
application -> mqtt : Subscribe to the shadow topics
|
||||
|
||||
activate mqtt
|
||||
mqtt -> : Subscribe to the\nshadow topic to the broker
|
||||
mqtt -> application : Return Success
|
||||
deactivate mqtt
|
||||
application -> mqtt : Publish messages on\nthe shadow topic
|
||||
|
||||
|
||||
activate mqtt
|
||||
mqtt -> : Publish message on the shadow topic to the broker
|
||||
mqtt <- : Incoming message
|
||||
mqtt -> callback : Trigger callback function
|
||||
activate callback
|
||||
callback -> shadow : Parse the topic
|
||||
activate shadow
|
||||
shadow -> callback : Return the parsed result
|
||||
deactivate shadow
|
||||
callback -> json : Parse key/value from shadow topic payload
|
||||
activate json
|
||||
json -> callback : Return parsed key/value
|
||||
deactivate json
|
||||
callback -> mqtt : Return from the callback
|
||||
deactivate callback
|
||||
mqtt -> application : Return from MQTT library
|
||||
deactivate mqtt
|
||||
|
||||
deactivate application
|
||||
|
||||
@enduml
|
||||
117
kernel/FreeRTOS-Plus/Source/AWS/device-shadow/lexicon.txt
Normal file
117
kernel/FreeRTOS-Plus/Source/AWS/device-shadow/lexicon.txt
Normal file
@ -0,0 +1,117 @@
|
||||
api
|
||||
app
|
||||
aws
|
||||
br
|
||||
buffersize
|
||||
cbmc
|
||||
colspan
|
||||
com
|
||||
config
|
||||
configpagestyle
|
||||
configs
|
||||
const
|
||||
copydoc
|
||||
css
|
||||
defgroup
|
||||
developerguide
|
||||
device-shadow-limits
|
||||
doxygen
|
||||
endcode
|
||||
endif
|
||||
endlink
|
||||
gcc
|
||||
generatedtopicstringlength
|
||||
getshadowoperationlength
|
||||
gettopicstring
|
||||
github
|
||||
gr
|
||||
html
|
||||
http
|
||||
https
|
||||
ifndef
|
||||
inc
|
||||
ingroup
|
||||
init
|
||||
iot
|
||||
iot-core
|
||||
iso
|
||||
json
|
||||
logdebug
|
||||
logerror
|
||||
loginfo
|
||||
logwarn
|
||||
mainpage
|
||||
malloc
|
||||
matchtopic
|
||||
maxallowedlength
|
||||
md
|
||||
mdash
|
||||
messagetype
|
||||
mit
|
||||
mqtt
|
||||
myshadow
|
||||
myshadowname
|
||||
mything
|
||||
mythingname
|
||||
noninfringement
|
||||
op
|
||||
operationlength
|
||||
os
|
||||
outlength
|
||||
param
|
||||
pconsumedtopiclength
|
||||
pmessagetype
|
||||
pname
|
||||
pnamelength
|
||||
png
|
||||
posix
|
||||
poutlength
|
||||
pre
|
||||
pshadowname
|
||||
pshadownamelength
|
||||
pstring
|
||||
psubstring
|
||||
pthingname
|
||||
pthingnamelength
|
||||
ptopic
|
||||
ptopicbuffer
|
||||
ptopicname
|
||||
rm
|
||||
sdk
|
||||
shadowname
|
||||
shadownamelength
|
||||
shadowstatus
|
||||
shadowtopicstringtypedelete
|
||||
shadowtopicstringtypedeleteaccepted
|
||||
shadowtopicstringtypedeleterejected
|
||||
shadowtopicstringtypeget
|
||||
shadowtopicstringtypegetaccepted
|
||||
shadowtopicstringtypegetrejected
|
||||
shadowtopicstringtypemaxnum
|
||||
shadowtopicstringtypeupdate
|
||||
shadowtopicstringtypeupdateaccepted
|
||||
shadowtopicstringtypeupdatedelta
|
||||
shadowtopicstringtypeupdatedocuments
|
||||
shadowtopicstringtypeupdaterejected
|
||||
sizeof
|
||||
spdx
|
||||
stdint
|
||||
stringlength
|
||||
strlen
|
||||
structs
|
||||
sublicense
|
||||
substringlength
|
||||
suffixlength
|
||||
td
|
||||
testshadowname
|
||||
testthingname
|
||||
thingname
|
||||
thingnamelength
|
||||
toolchain
|
||||
topicbuffer
|
||||
topiclength
|
||||
topicnamelength
|
||||
topictype
|
||||
tr
|
||||
un
|
||||
utest
|
||||
@ -0,0 +1,5 @@
|
||||
name : "Device-Shadow-for-AWS-IoT-embedded-sdk"
|
||||
version: "v1.3.0"
|
||||
description: |
|
||||
"Client library for using the AWS IoT Device Shadow service on embedded devices.\n"
|
||||
license: "MIT"
|
||||
29
kernel/FreeRTOS-Plus/Source/AWS/device-shadow/sbom.spdx
Normal file
29
kernel/FreeRTOS-Plus/Source/AWS/device-shadow/sbom.spdx
Normal file
@ -0,0 +1,29 @@
|
||||
SPDXVersion: SPDX-2.2
|
||||
DataLicense: CC0-1.0
|
||||
SPDXID: SPDXRef-DOCUMENT
|
||||
DocumentName: Device-Shadow-for-AWS-IoT-embedded-sdk
|
||||
DocumentNamespace: https://github.com/FreeRTOS/Device-Shadow-for-AWS-IoT-embedded-sdk/blob/v1.3.0/sbom.spdx
|
||||
Creator: Amazon Web Services
|
||||
Created: 2022-10-14T16:03:17Z
|
||||
CreatorComment: NOASSERTION
|
||||
DocumentComment: NOASSERTION
|
||||
|
||||
PackageName: Device-Shadow-for-AWS-IoT-embedded-sdk
|
||||
SPDXID: SPDXRef-Package-Device-Shadow-for-AWS-IoT-embedded-sdk
|
||||
PackageVersion: v1.3.0
|
||||
PackageDownloadLocation: https://github.com/aws/Device-Shadow-for-AWS-IoT-embedded-sdk/tree/v1.3.0
|
||||
PackageLicenseConcluded: MIT
|
||||
FilesAnalyzed: True
|
||||
PackageVerificationCode: eea9cfc97b4c00c8b223b64bce009510c51de318
|
||||
PackageCopyrightText: NOASSERTION
|
||||
PackageSummary: NOASSERTION
|
||||
PackageDescription: "Client library for using the AWS IoT Device Shadow service on embedded devices.\n"
|
||||
|
||||
|
||||
FileName: ./shadow.c
|
||||
SPDXID: SPDXRef-File-shadow.c
|
||||
FileChecksum: SHA1: d5d54161800420ae72f7034c9f153a4b5c781e3c
|
||||
LicenseConcluded: MIT
|
||||
FileCopyrightText: NOASSERTION
|
||||
FileComment: NOASSERTION
|
||||
|
||||
@ -0,0 +1,14 @@
|
||||
# This file is to add source files and include directories
|
||||
# into variables so that it can be reused from different repositories
|
||||
# in their Cmake based build system by including this file.
|
||||
#
|
||||
# Files specific to the repository such as test runner, platform tests
|
||||
# are not added to the variables.
|
||||
|
||||
# SHADOW library source files.
|
||||
set( SHADOW_SOURCES
|
||||
"${CMAKE_CURRENT_LIST_DIR}/source/shadow.c" )
|
||||
|
||||
# SHADOW library Public Include directories.
|
||||
set( SHADOW_INCLUDE_PUBLIC_DIRS
|
||||
"${CMAKE_CURRENT_LIST_DIR}/source/include" )
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,137 @@
|
||||
/*
|
||||
* AWS IoT Device Shadow v1.3.0
|
||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file shadow_config_defaults.h
|
||||
* @brief This represents the default values for the configuration macros
|
||||
* for the Shadow library.
|
||||
*
|
||||
* @note This file SHOULD NOT be modified. If custom values are needed for
|
||||
* any configuration macro, a shadow_config.h file should be provided to
|
||||
* the Shadow library to override the default values defined in this file.
|
||||
* To use the custom config file, the SHADOW_DO_NOT_USE_CUSTOM_CONFIG preprocessor
|
||||
* macro SHOULD NOT be set.
|
||||
*/
|
||||
|
||||
#ifndef SHADOW_CONFIG_DEFAULTS_H_
|
||||
#define SHADOW_CONFIG_DEFAULTS_H_
|
||||
|
||||
/* The macro definition for SHADOW_DO_NOT_USE_CUSTOM_CONFIG is for Doxygen
|
||||
* documentation only. */
|
||||
|
||||
/**
|
||||
* @brief Define this macro to build the Shadow library without the custom config
|
||||
* file shadow_config.h.
|
||||
*
|
||||
* Without the custom config, the Shadow library builds with
|
||||
* default values of config macros defined in shadow_config_defaults.h file.
|
||||
*
|
||||
* If a custom config is provided, then SHADOW_DO_NOT_USE_CUSTOM_CONFIG should not
|
||||
* be defined.
|
||||
*/
|
||||
#ifdef DOXYGEN
|
||||
#define SHADOW_DO_NOT_USE_CUSTOM_CONFIG
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Macro that is called in the Shadow library for logging "Error" level
|
||||
* messages.
|
||||
*
|
||||
* To enable error level logging in the Shadow library, this macro should be mapped to the
|
||||
* application-specific logging implementation that supports error logging.
|
||||
*
|
||||
* @note This logging macro is called in the Shadow library with parameters wrapped in
|
||||
* double parentheses to be ISO C89/C90 standard compliant. For a reference
|
||||
* POSIX implementation of the logging macros, refer to shadow_config.h files, and the
|
||||
* logging-stack in demos folder of the
|
||||
* [AWS IoT Embedded C SDK repository](https://github.com/aws/aws-iot-device-sdk-embedded-C).
|
||||
*
|
||||
* <b>Default value</b>: Error logging is turned off, and no code is generated for calls
|
||||
* to the macro in the Shadow library on compilation.
|
||||
*/
|
||||
#ifndef LogError
|
||||
#define LogError( message )
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Macro that is called in the Shadow library for logging "Warning" level
|
||||
* messages.
|
||||
*
|
||||
* To enable warning level logging in the Shadow library, this macro should be mapped to the
|
||||
* application-specific logging implementation that supports warning logging.
|
||||
*
|
||||
* @note This logging macro is called in the Shadow library with parameters wrapped in
|
||||
* double parentheses to be ISO C89/C90 standard compliant. For a reference
|
||||
* POSIX implementation of the logging macros, refer to shadow_config.h files, and the
|
||||
* logging-stack in demos folder of the
|
||||
* [AWS IoT Embedded C SDK repository](https://github.com/aws/aws-iot-device-sdk-embedded-C).
|
||||
*
|
||||
* <b>Default value</b>: Warning logs are turned off, and no code is generated for calls
|
||||
* to the macro in the Shadow library on compilation.
|
||||
*/
|
||||
#ifndef LogWarn
|
||||
#define LogWarn( message )
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Macro that is called in the Shadow library for logging "Info" level
|
||||
* messages.
|
||||
*
|
||||
* To enable info level logging in the Shadow library, this macro should be mapped to the
|
||||
* application-specific logging implementation that supports info logging.
|
||||
*
|
||||
* @note This logging macro is called in the Shadow library with parameters wrapped in
|
||||
* double parentheses to be ISO C89/C90 standard compliant. For a reference
|
||||
* POSIX implementation of the logging macros, refer to shadow_config.h files, and the
|
||||
* logging-stack in demos folder of the
|
||||
* [AWS IoT Embedded C SDK repository](https://github.com/aws/aws-iot-device-sdk-embedded-C).
|
||||
*
|
||||
* <b>Default value</b>: Info logging is turned off, and no code is generated for calls
|
||||
* to the macro in the Shadow library on compilation.
|
||||
*/
|
||||
#ifndef LogInfo
|
||||
#define LogInfo( message )
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Macro that is called in the Shadow library for logging "Debug" level
|
||||
* messages.
|
||||
*
|
||||
* To enable debug level logging from Shadow library, this macro should be mapped to the
|
||||
* application-specific logging implementation that supports debug logging.
|
||||
*
|
||||
* @note This logging macro is called in the Shadow library with parameters wrapped in
|
||||
* double parentheses to be ISO C89/C90 standard compliant. For a reference
|
||||
* POSIX implementation of the logging macros, refer to shadow_config.h files, and the
|
||||
* logging-stack in demos folder of the
|
||||
* [AWS IoT Embedded C SDK repository](https://github.com/aws/aws-iot-device-sdk-embedded-C).
|
||||
*
|
||||
* <b>Default value</b>: Debug logging is turned off, and no code is generated for calls
|
||||
* to the macro in the Shadow library on compilation.
|
||||
*/
|
||||
#ifndef LogDebug
|
||||
#define LogDebug( message )
|
||||
#endif
|
||||
|
||||
#endif /* ifndef SHADOW_CONFIG_DEFAULTS_H_ */
|
||||
962
kernel/FreeRTOS-Plus/Source/AWS/device-shadow/source/shadow.c
Normal file
962
kernel/FreeRTOS-Plus/Source/AWS/device-shadow/source/shadow.c
Normal file
@ -0,0 +1,962 @@
|
||||
/*
|
||||
* AWS IoT Device Shadow v1.3.0
|
||||
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file shadow.c
|
||||
* @brief Implements the user-facing functions of the Shadow library.
|
||||
*/
|
||||
|
||||
/* Standard includes. */
|
||||
#include <string.h>
|
||||
|
||||
/* Shadow includes. */
|
||||
#include "shadow.h"
|
||||
|
||||
|
||||
/**
|
||||
* @brief Maximum shadow name length.
|
||||
* Refer to https://docs.aws.amazon.com/general/latest/gr/iot-core.html#device-shadow-limits
|
||||
* for more details about the Device Shadow limits.
|
||||
*/
|
||||
#define SHADOW_NAME_MAX_LENGTH ( 64U )
|
||||
|
||||
/**
|
||||
* @brief Maximum thing name length.
|
||||
* Refer to https://docs.aws.amazon.com/general/latest/gr/iot-core.html#device-shadow-limits
|
||||
* for more details about the Device Shadow limits.
|
||||
*/
|
||||
#define SHADOW_THINGNAME_MAX_LENGTH ( 128U )
|
||||
|
||||
/**
|
||||
* @brief The string representing "/shadow/update/accepted".
|
||||
*/
|
||||
#define SHADOW_OP_UPDATE_ACCEPTED SHADOW_OP_UPDATE SHADOW_SUFFIX_ACCEPTED
|
||||
|
||||
/**
|
||||
* @brief The string representing "/shadow/update/rejected".
|
||||
*/
|
||||
#define SHADOW_OP_UPDATE_REJECTED SHADOW_OP_UPDATE SHADOW_SUFFIX_REJECTED
|
||||
|
||||
/**
|
||||
* @brief The string representing "/shadow/update/delta".
|
||||
*/
|
||||
#define SHADOW_OP_UPDATE_DELTA SHADOW_OP_UPDATE SHADOW_SUFFIX_DELTA
|
||||
|
||||
/**
|
||||
* @brief The string representing "/shadow/update/document".
|
||||
*/
|
||||
#define SHADOW_OP_UPDATE_DOCUMENTS SHADOW_OP_UPDATE SHADOW_SUFFIX_DOCUMENTS
|
||||
|
||||
/**
|
||||
* @brief The string representing "/shadow/delete/accepted".
|
||||
*/
|
||||
#define SHADOW_OP_DELETE_ACCEPTED SHADOW_OP_DELETE SHADOW_SUFFIX_ACCEPTED
|
||||
|
||||
/**
|
||||
* @brief The string representing "/shadow/delete/accepted".
|
||||
*/
|
||||
#define SHADOW_OP_DELETE_REJECTED SHADOW_OP_DELETE SHADOW_SUFFIX_REJECTED
|
||||
|
||||
/**
|
||||
* @brief The string representing "/shadow/get/accepted".
|
||||
*/
|
||||
#define SHADOW_OP_GET_ACCEPTED SHADOW_OP_GET SHADOW_SUFFIX_ACCEPTED
|
||||
|
||||
/**
|
||||
* @brief The string representing "/shadow/get/accepted".
|
||||
*/
|
||||
#define SHADOW_OP_GET_REJECTED SHADOW_OP_GET SHADOW_SUFFIX_REJECTED
|
||||
|
||||
/**
|
||||
* @brief The length of "/shadow/update/accepted".
|
||||
*/
|
||||
#define SHADOW_OP_UPDATE_ACCEPTED_LENGTH ( SHADOW_OP_UPDATE_LENGTH + SHADOW_SUFFIX_ACCEPTED_LENGTH )
|
||||
|
||||
/**
|
||||
* @brief The length of "/shadow/update/rejected".
|
||||
*/
|
||||
#define SHADOW_OP_UPDATE_REJECTED_LENGTH ( SHADOW_OP_UPDATE_LENGTH + SHADOW_SUFFIX_REJECTED_LENGTH )
|
||||
|
||||
/**
|
||||
* @brief The length of "/shadow/update/document".
|
||||
*/
|
||||
#define SHADOW_OP_UPDATE_DOCUMENTS_LENGTH ( SHADOW_OP_UPDATE_LENGTH + SHADOW_SUFFIX_DOCUMENTS_LENGTH )
|
||||
|
||||
/**
|
||||
* @brief The length of "/shadow/update/rejected".
|
||||
*/
|
||||
#define SHADOW_OP_UPDATE_DELTA_LENGTH ( SHADOW_OP_UPDATE_LENGTH + SHADOW_SUFFIX_DELTA_LENGTH )
|
||||
|
||||
/**
|
||||
* @brief The length of "/shadow/get/accepted".
|
||||
*/
|
||||
#define SHADOW_OP_GET_ACCEPTED_LENGTH ( SHADOW_OP_GET_LENGTH + SHADOW_SUFFIX_ACCEPTED_LENGTH )
|
||||
|
||||
/**
|
||||
* @brief The length of "/shadow/get/rejected".
|
||||
*/
|
||||
#define SHADOW_OP_GET_REJECTED_LENGTH ( SHADOW_OP_GET_LENGTH + SHADOW_SUFFIX_REJECTED_LENGTH )
|
||||
|
||||
/**
|
||||
* @brief The length of "/shadow/get/accepted".
|
||||
*/
|
||||
#define SHADOW_OP_DELETE_ACCEPTED_LENGTH ( SHADOW_OP_DELETE_LENGTH + SHADOW_SUFFIX_ACCEPTED_LENGTH )
|
||||
|
||||
/**
|
||||
* @brief The length of "/shadow/delete/rejected".
|
||||
*/
|
||||
#define SHADOW_OP_DELETE_REJECTED_LENGTH ( SHADOW_OP_DELETE_LENGTH + SHADOW_SUFFIX_REJECTED_LENGTH )
|
||||
|
||||
/**
|
||||
* @brief Check if Shadow_MatchTopicString has valid parameters.
|
||||
*
|
||||
* @param[in] pTopic Pointer to the topic string.
|
||||
* @param[in] topicLength Length of pTopic.
|
||||
* @param[in] pMessageType Pointer to caller-supplied memory for returning the type of the shadow message.
|
||||
*
|
||||
* @return Return SHADOW_SUCCESS if the parameters are valid;
|
||||
* return SHADOW_BAD_PARAMETER if not.
|
||||
*/
|
||||
static ShadowStatus_t validateMatchTopicParameters( const char * pTopic,
|
||||
uint16_t topicLength,
|
||||
const ShadowMessageType_t * pMessageType );
|
||||
|
||||
/**
|
||||
* @brief Check if Shadow_AssembleTopicString has valid parameters.
|
||||
*
|
||||
* @param[in] topicType Shadow topic type.
|
||||
* @param[in] pThingName Thing Name string.
|
||||
* @param[in] thingNameLength Length of Thing Name string pointed to by pThingName.
|
||||
* @param[in] pShadowName Shadow Name string.
|
||||
* @param[in] shadowNameLength Length of Shadow Name string pointed to by pShadowName.
|
||||
* @param[in] pTopicBuffer Pointer to the topic buffer.
|
||||
* @param[in] pOutLength Pointer to the length of the topic created.
|
||||
*
|
||||
* @return Return SHADOW_SUCCESS if the parameters are valid;
|
||||
* return SHADOW_BAD_PARAMETER if not.
|
||||
*/
|
||||
static ShadowStatus_t validateAssembleTopicParameters( ShadowTopicStringType_t topicType,
|
||||
const char * pThingName,
|
||||
uint8_t thingNameLength,
|
||||
const char * pShadowName,
|
||||
uint8_t shadowNameLength,
|
||||
const char * pTopicBuffer,
|
||||
const uint16_t * pOutLength );
|
||||
|
||||
/**
|
||||
* @brief Determine if the string contains the substring.
|
||||
*
|
||||
* @param[in] pString Pointer to the string.
|
||||
* @param[in] stringLength Length of pString.
|
||||
* @param[in] pSubString Pointer to the substring.
|
||||
* @param[in] subStringLength Length of pSubString.
|
||||
*
|
||||
* @return Return SHADOW_SUCCESS if it contains;
|
||||
* return SHADOW_FAIL if not.
|
||||
*/
|
||||
static ShadowStatus_t containsSubString( const char * pString,
|
||||
uint16_t stringLength,
|
||||
const char * pSubString,
|
||||
uint16_t subStringLength );
|
||||
|
||||
/**
|
||||
* @brief Check if the Thing or Shadow Name is valid.
|
||||
*
|
||||
* @param[in] pString Pointer to the starting of a name.
|
||||
* @param[in] stringLength Length of pString.
|
||||
* @param[in] maxAllowedLength Maximum allowed length of the Thing or Shadow name.
|
||||
* @param[out] pNameLength Pointer to caller-supplied memory for returning the length of the Thing or Shadow Name.
|
||||
*
|
||||
* @return Return SHADOW_SUCCESS if it is valid;
|
||||
* return SHADOW_FAIL if it is not.
|
||||
*/
|
||||
static ShadowStatus_t validateName( const char * pString,
|
||||
uint16_t stringLength,
|
||||
uint8_t maxAllowedLength,
|
||||
uint8_t * pNameLength );
|
||||
|
||||
/**
|
||||
* @brief Extract the Shadow message type from a string.
|
||||
*
|
||||
* @param[in] pString Pointer to the string.
|
||||
* @param[in] stringLength Length of pString.
|
||||
* @param[out] pMessageType Pointer to caller-supplied memory for returning the type of the shadow message.
|
||||
*
|
||||
* @return Return SHADOW_SUCCESS if successfully extracted;
|
||||
* return SHADOW_MESSAGE_TYPE_PARSE_FAILED if failed.
|
||||
*/
|
||||
static ShadowStatus_t extractShadowMessageType( const char * pString,
|
||||
uint16_t stringLength,
|
||||
ShadowMessageType_t * pMessageType );
|
||||
|
||||
/**
|
||||
* @brief Extract the Thing name from a topic string.
|
||||
*
|
||||
* @param[in] pTopic Pointer to the topic string.
|
||||
* @param[in] topicLength Length of pTopic.
|
||||
* @param[in,out] pConsumedTopicLength Pointer to caller-supplied memory for returning the consumed topic length.
|
||||
* @param[out] pThingNameLength Pointer to caller-supplied memory for returning the Thing name length.
|
||||
*
|
||||
* @return Return SHADOW_SUCCESS if successfully extracted;
|
||||
* return SHADOW_THINGNAME_PARSE_FAILED if Thing name parsing fails.
|
||||
*/
|
||||
static ShadowStatus_t extractThingName( const char * pTopic,
|
||||
uint16_t topicLength,
|
||||
uint16_t * pConsumedTopicLength,
|
||||
uint8_t * pThingNameLength );
|
||||
|
||||
/**
|
||||
* @brief Extract the classic shadow root OR the named shadow root and shadow name from a topic string.
|
||||
*
|
||||
* @param[in] pTopic Pointer to the topic string.
|
||||
* @param[in] topicLength Length of pTopic.
|
||||
* @param[in,out] pConsumedTopicLength Pointer to caller-supplied memory for returning the consumed topic length.
|
||||
* @param[out] pShadowNameLength Pointer to caller-supplied memory for returning the shadow name length.
|
||||
*
|
||||
* @return Return SHADOW_SUCCESS if successfully extracted;
|
||||
* return SHADOW_ROOT_PARSE_FAILED shadow root parsing fails.
|
||||
* return SHADOW_SHADOWNAME_PARSE_FAILED shadow name parsing fails.
|
||||
*/
|
||||
static ShadowStatus_t extractShadowRootAndName( const char * pTopic,
|
||||
uint16_t topicLength,
|
||||
uint16_t * pConsumedTopicLength,
|
||||
uint8_t * pShadowNameLength );
|
||||
|
||||
/**
|
||||
* @brief Get the shadow operation string for a given shadow topic type.
|
||||
*
|
||||
* @param[in] topicType The given shadow topic type.
|
||||
*
|
||||
* @return The shadow operation string for the given shadow type.
|
||||
*/
|
||||
static const char * getShadowOperationString( ShadowTopicStringType_t topicType );
|
||||
|
||||
/**
|
||||
* @brief Get the shadow operation string length for a given shadow topic type.
|
||||
*
|
||||
* @param[in] topicType The given shadow topic type.
|
||||
*
|
||||
* @return The shadow operation string length for the given shadow type.
|
||||
*/
|
||||
static uint16_t getShadowOperationLength( ShadowTopicStringType_t topicType );
|
||||
|
||||
/**
|
||||
* @brief Creates a shadow topic string
|
||||
*
|
||||
* @param[in] topicType The type of shadow topic to be constructed.
|
||||
* @param[in] pThingName Pointer to the Thing name.
|
||||
* @param[in] thingNameLength The length of the Thing name.
|
||||
* @param[in] pShadowName Pointer to the Shadow name.
|
||||
* @param[in] shadowNameLength The length of the Shadow name.
|
||||
* @param[out] pTopicBuffer Pointer to caller-supplied memory for returning the constructed shadow topic string.
|
||||
*/
|
||||
static void createShadowTopicString( ShadowTopicStringType_t topicType,
|
||||
const char * pThingName,
|
||||
uint8_t thingNameLength,
|
||||
const char * pShadowName,
|
||||
uint8_t shadowNameLength,
|
||||
char * pTopicBuffer );
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static ShadowStatus_t validateMatchTopicParameters( const char * pTopic,
|
||||
uint16_t topicLength,
|
||||
const ShadowMessageType_t * pMessageType )
|
||||
{
|
||||
ShadowStatus_t shadowStatus = SHADOW_SUCCESS;
|
||||
|
||||
if( ( pTopic == NULL ) ||
|
||||
( topicLength == 0U ) ||
|
||||
( pMessageType == NULL ) )
|
||||
{
|
||||
shadowStatus = SHADOW_BAD_PARAMETER;
|
||||
LogError( ( "Invalid input parameters pTopic: %p, topicLength: %u, pMessageType: %p.",
|
||||
( const void * ) pTopic,
|
||||
( unsigned int ) topicLength,
|
||||
( const void * ) pMessageType ) );
|
||||
}
|
||||
|
||||
return shadowStatus;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static ShadowStatus_t validateAssembleTopicParameters( ShadowTopicStringType_t topicType,
|
||||
const char * pThingName,
|
||||
uint8_t thingNameLength,
|
||||
const char * pShadowName,
|
||||
uint8_t shadowNameLength,
|
||||
const char * pTopicBuffer,
|
||||
const uint16_t * pOutLength )
|
||||
{
|
||||
ShadowStatus_t shadowStatus = SHADOW_BAD_PARAMETER;
|
||||
|
||||
if( ( pTopicBuffer == NULL ) ||
|
||||
( pThingName == NULL ) ||
|
||||
( thingNameLength == 0U ) ||
|
||||
( ( pShadowName == NULL ) && ( shadowNameLength > 0U ) ) ||
|
||||
( topicType >= ShadowTopicStringTypeMaxNum ) ||
|
||||
( pOutLength == NULL ) )
|
||||
{
|
||||
LogError( ( "Invalid input parameters pTopicBuffer: %p, pThingName: %p, thingNameLength: %u,\
|
||||
pShadowName: %p, shadowNameLength: %u, topicType: %d, pOutLength: %p.",
|
||||
( const void * ) pTopicBuffer,
|
||||
( const void * ) pThingName,
|
||||
( unsigned int ) thingNameLength,
|
||||
( const void * ) pShadowName,
|
||||
( unsigned int ) shadowNameLength,
|
||||
( int ) topicType,
|
||||
( const void * ) pOutLength ) );
|
||||
}
|
||||
else if( thingNameLength > SHADOW_THINGNAME_MAX_LENGTH )
|
||||
{
|
||||
LogError( ( "Invalid thingNamelength. Thing name length of %u exceeds maximum allowed length %u.",
|
||||
( unsigned int ) thingNameLength,
|
||||
( unsigned int ) SHADOW_THINGNAME_MAX_LENGTH ) );
|
||||
}
|
||||
else if( shadowNameLength > SHADOW_NAME_MAX_LENGTH )
|
||||
{
|
||||
LogError( ( "Invalid shadowNameLength. Shadow name length of %u exceeds maximum allowed length %u.",
|
||||
( unsigned int ) shadowNameLength,
|
||||
( unsigned int ) SHADOW_NAME_MAX_LENGTH ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Validations passed .*/
|
||||
shadowStatus = SHADOW_SUCCESS;
|
||||
}
|
||||
|
||||
return shadowStatus;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static ShadowStatus_t containsSubString( const char * pString,
|
||||
uint16_t stringLength,
|
||||
const char * pSubString,
|
||||
uint16_t subStringLength )
|
||||
{
|
||||
ShadowStatus_t returnStatus = SHADOW_FAIL;
|
||||
|
||||
/* The string must be at least as long as the substring to contain it
|
||||
* completely. */
|
||||
if( stringLength >= subStringLength )
|
||||
{
|
||||
/* We are only checking up to subStringLength characters in the original
|
||||
* string. The string may be longer and contain additional characters. */
|
||||
if( strncmp( pString, pSubString, ( size_t ) subStringLength ) == 0 )
|
||||
{
|
||||
returnStatus = SHADOW_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return returnStatus;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static ShadowStatus_t validateName( const char * pString,
|
||||
uint16_t stringLength,
|
||||
uint8_t maxAllowedLength,
|
||||
uint8_t * pNameLength )
|
||||
{
|
||||
uint16_t index = 0U;
|
||||
ShadowStatus_t returnStatus = SHADOW_FAIL;
|
||||
uint8_t parsedName = 0U;
|
||||
|
||||
for( ; index < stringLength; index++ )
|
||||
{
|
||||
/* The name should always be terminated by a forward slash */
|
||||
if( pString[ index ] == ( char ) '/' )
|
||||
{
|
||||
parsedName = 1U;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( parsedName == 1U )
|
||||
{
|
||||
if( index == 0U )
|
||||
{
|
||||
LogDebug( ( "Not a Shadow topic. Unable to find a %s name in the topic.",
|
||||
( maxAllowedLength == SHADOW_THINGNAME_MAX_LENGTH ) ? "Thing" : "Shadow" ) );
|
||||
}
|
||||
else if( index > maxAllowedLength )
|
||||
{
|
||||
LogDebug( ( "Not a Shadow topic. Extracted %s name length of %u exceeds maximum allowed length %u.",
|
||||
( maxAllowedLength == SHADOW_THINGNAME_MAX_LENGTH ) ? "Thing" : "Shadow",
|
||||
( unsigned int ) index,
|
||||
( unsigned int ) maxAllowedLength ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Only accept names of greater than zero length.
|
||||
* The variable `index` will not exceed the 8 bit integer width here
|
||||
* since it will be lesser than the 8 bit integer `maxAllowedLength`. */
|
||||
*pNameLength = ( uint8_t ) index;
|
||||
returnStatus = SHADOW_SUCCESS;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LogDebug( ( "Not a Shadow topic. Unable to find a %s name in the topic.",
|
||||
( maxAllowedLength == SHADOW_THINGNAME_MAX_LENGTH ) ? "Thing" : "Shadow" ) );
|
||||
}
|
||||
|
||||
return returnStatus;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static ShadowStatus_t extractThingName( const char * pTopic,
|
||||
uint16_t topicLength,
|
||||
uint16_t * pConsumedTopicLength,
|
||||
uint8_t * pThingNameLength )
|
||||
{
|
||||
/* Extract thing name. */
|
||||
ShadowStatus_t shadowStatus = validateName( &( pTopic[ *pConsumedTopicLength ] ),
|
||||
topicLength - *pConsumedTopicLength,
|
||||
SHADOW_THINGNAME_MAX_LENGTH,
|
||||
pThingNameLength );
|
||||
|
||||
if( shadowStatus != SHADOW_SUCCESS )
|
||||
{
|
||||
shadowStatus = SHADOW_THINGNAME_PARSE_FAILED;
|
||||
}
|
||||
else
|
||||
{
|
||||
*pConsumedTopicLength += *pThingNameLength;
|
||||
}
|
||||
|
||||
return shadowStatus;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static ShadowStatus_t extractShadowRootAndName( const char * pTopic,
|
||||
uint16_t topicLength,
|
||||
uint16_t * pConsumedTopicLength,
|
||||
uint8_t * pShadowNameLength )
|
||||
{
|
||||
/* Look for the named shadow root */
|
||||
ShadowStatus_t shadowStatus = containsSubString( &( pTopic[ *pConsumedTopicLength ] ),
|
||||
topicLength - *pConsumedTopicLength,
|
||||
SHADOW_NAMED_ROOT,
|
||||
SHADOW_NAMED_ROOT_LENGTH );
|
||||
|
||||
if( shadowStatus == SHADOW_SUCCESS )
|
||||
{
|
||||
/* Topic is a named shadow */
|
||||
*pConsumedTopicLength += SHADOW_NAMED_ROOT_LENGTH;
|
||||
|
||||
/* Extract shadow name. */
|
||||
shadowStatus = validateName( &( pTopic[ *pConsumedTopicLength ] ),
|
||||
topicLength - *pConsumedTopicLength,
|
||||
SHADOW_NAME_MAX_LENGTH,
|
||||
pShadowNameLength );
|
||||
|
||||
if( shadowStatus != SHADOW_SUCCESS )
|
||||
{
|
||||
shadowStatus = SHADOW_SHADOWNAME_PARSE_FAILED;
|
||||
}
|
||||
else
|
||||
{
|
||||
*pConsumedTopicLength += *pShadowNameLength;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Not a named shadow. Try to match the classic shadow root. */
|
||||
shadowStatus = containsSubString( &( pTopic[ *pConsumedTopicLength ] ),
|
||||
topicLength - *pConsumedTopicLength,
|
||||
SHADOW_CLASSIC_ROOT,
|
||||
SHADOW_CLASSIC_ROOT_LENGTH );
|
||||
|
||||
if( shadowStatus == SHADOW_SUCCESS )
|
||||
{
|
||||
*pConsumedTopicLength += SHADOW_CLASSIC_ROOT_LENGTH;
|
||||
}
|
||||
else
|
||||
{
|
||||
shadowStatus = SHADOW_ROOT_PARSE_FAILED;
|
||||
LogDebug( ( "Not a Shadow topic. Failed to parse shadow root in pTopic %.*s", topicLength, pTopic ) );
|
||||
}
|
||||
}
|
||||
|
||||
return shadowStatus;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static ShadowStatus_t extractShadowMessageType( const char * pString,
|
||||
uint16_t stringLength,
|
||||
ShadowMessageType_t * pMessageType )
|
||||
{
|
||||
uint32_t index = 0U;
|
||||
ShadowStatus_t returnStatus = SHADOW_FAIL;
|
||||
|
||||
/* Lookup table for Shadow message string. */
|
||||
static const char * const pMessageStrings[ ShadowMessageTypeMaxNum ] =
|
||||
{
|
||||
SHADOW_OP_GET_ACCEPTED,
|
||||
SHADOW_OP_GET_REJECTED,
|
||||
SHADOW_OP_DELETE_ACCEPTED,
|
||||
SHADOW_OP_DELETE_REJECTED,
|
||||
SHADOW_OP_UPDATE_ACCEPTED,
|
||||
SHADOW_OP_UPDATE_REJECTED,
|
||||
SHADOW_OP_UPDATE_DOCUMENTS,
|
||||
SHADOW_OP_UPDATE_DELTA
|
||||
};
|
||||
|
||||
/* Lookup table for Shadow message string length. */
|
||||
static const uint16_t pMessageStringsLength[ ShadowMessageTypeMaxNum ] =
|
||||
{
|
||||
SHADOW_OP_GET_ACCEPTED_LENGTH,
|
||||
SHADOW_OP_GET_REJECTED_LENGTH,
|
||||
SHADOW_OP_DELETE_ACCEPTED_LENGTH,
|
||||
SHADOW_OP_DELETE_REJECTED_LENGTH,
|
||||
SHADOW_OP_UPDATE_ACCEPTED_LENGTH,
|
||||
SHADOW_OP_UPDATE_REJECTED_LENGTH,
|
||||
SHADOW_OP_UPDATE_DOCUMENTS_LENGTH,
|
||||
SHADOW_OP_UPDATE_DELTA_LENGTH
|
||||
};
|
||||
|
||||
/* Lookup table for Shadow message types. */
|
||||
static const ShadowMessageType_t pMessageTypes[ ShadowMessageTypeMaxNum ] =
|
||||
{
|
||||
ShadowMessageTypeGetAccepted,
|
||||
ShadowMessageTypeGetRejected,
|
||||
ShadowMessageTypeDeleteAccepted,
|
||||
ShadowMessageTypeDeleteRejected,
|
||||
ShadowMessageTypeUpdateAccepted,
|
||||
ShadowMessageTypeUpdateRejected,
|
||||
ShadowMessageTypeUpdateDocuments,
|
||||
ShadowMessageTypeUpdateDelta
|
||||
};
|
||||
|
||||
for( ; index < ( uint32_t ) ( sizeof( pMessageStrings ) / sizeof( pMessageStrings[ 0 ] ) ); index++ )
|
||||
{
|
||||
returnStatus = containsSubString( pString,
|
||||
stringLength,
|
||||
pMessageStrings[ index ],
|
||||
pMessageStringsLength[ index ] );
|
||||
|
||||
/* If the operation string matches, there must not be any other extra
|
||||
* character remaining in the string. */
|
||||
if( returnStatus == SHADOW_SUCCESS )
|
||||
{
|
||||
if( stringLength != pMessageStringsLength[ index ] )
|
||||
{
|
||||
returnStatus = SHADOW_FAIL;
|
||||
}
|
||||
else
|
||||
{
|
||||
*pMessageType = pMessageTypes[ index ];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( returnStatus != SHADOW_SUCCESS )
|
||||
{
|
||||
LogDebug( ( "Not a Shadow topic. Failed to match shadow message type in pString %.*s", stringLength, pString ) );
|
||||
}
|
||||
|
||||
return returnStatus;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static const char * getShadowOperationString( ShadowTopicStringType_t topicType )
|
||||
{
|
||||
const char * shadowOperationString = NULL;
|
||||
|
||||
switch( topicType )
|
||||
{
|
||||
case ShadowTopicStringTypeGet:
|
||||
shadowOperationString = SHADOW_OP_GET;
|
||||
break;
|
||||
|
||||
case ShadowTopicStringTypeGetAccepted:
|
||||
shadowOperationString = SHADOW_OP_GET_ACCEPTED;
|
||||
break;
|
||||
|
||||
case ShadowTopicStringTypeGetRejected:
|
||||
shadowOperationString = SHADOW_OP_GET_REJECTED;
|
||||
break;
|
||||
|
||||
case ShadowTopicStringTypeDelete:
|
||||
shadowOperationString = SHADOW_OP_DELETE;
|
||||
break;
|
||||
|
||||
case ShadowTopicStringTypeDeleteAccepted:
|
||||
shadowOperationString = SHADOW_OP_DELETE_ACCEPTED;
|
||||
break;
|
||||
|
||||
case ShadowTopicStringTypeDeleteRejected:
|
||||
shadowOperationString = SHADOW_OP_DELETE_REJECTED;
|
||||
break;
|
||||
|
||||
case ShadowTopicStringTypeUpdate:
|
||||
shadowOperationString = SHADOW_OP_UPDATE;
|
||||
break;
|
||||
|
||||
case ShadowTopicStringTypeUpdateAccepted:
|
||||
shadowOperationString = SHADOW_OP_UPDATE_ACCEPTED;
|
||||
break;
|
||||
|
||||
case ShadowTopicStringTypeUpdateRejected:
|
||||
shadowOperationString = SHADOW_OP_UPDATE_REJECTED;
|
||||
break;
|
||||
|
||||
case ShadowTopicStringTypeUpdateDocuments:
|
||||
shadowOperationString = SHADOW_OP_UPDATE_DOCUMENTS;
|
||||
break;
|
||||
|
||||
case ShadowTopicStringTypeUpdateDelta:
|
||||
/* topicType >= ShadowTopicStringTypeMaxNum check is covered at entry of Shadow_AssembleTopicString. */
|
||||
default:
|
||||
shadowOperationString = SHADOW_OP_UPDATE_DELTA;
|
||||
break;
|
||||
}
|
||||
|
||||
return shadowOperationString;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static uint16_t getShadowOperationLength( ShadowTopicStringType_t topicType )
|
||||
{
|
||||
uint16_t shadowOperationLength = 0U;
|
||||
|
||||
switch( topicType )
|
||||
{
|
||||
case ShadowTopicStringTypeGet:
|
||||
shadowOperationLength = SHADOW_OP_GET_LENGTH;
|
||||
break;
|
||||
|
||||
case ShadowTopicStringTypeGetAccepted:
|
||||
shadowOperationLength = SHADOW_OP_GET_ACCEPTED_LENGTH;
|
||||
break;
|
||||
|
||||
case ShadowTopicStringTypeGetRejected:
|
||||
shadowOperationLength = SHADOW_OP_GET_REJECTED_LENGTH;
|
||||
break;
|
||||
|
||||
case ShadowTopicStringTypeDelete:
|
||||
shadowOperationLength = SHADOW_OP_DELETE_LENGTH;
|
||||
break;
|
||||
|
||||
case ShadowTopicStringTypeDeleteAccepted:
|
||||
shadowOperationLength = SHADOW_OP_DELETE_ACCEPTED_LENGTH;
|
||||
break;
|
||||
|
||||
case ShadowTopicStringTypeDeleteRejected:
|
||||
shadowOperationLength = SHADOW_OP_DELETE_REJECTED_LENGTH;
|
||||
break;
|
||||
|
||||
case ShadowTopicStringTypeUpdate:
|
||||
shadowOperationLength = SHADOW_OP_UPDATE_LENGTH;
|
||||
break;
|
||||
|
||||
case ShadowTopicStringTypeUpdateAccepted:
|
||||
shadowOperationLength = SHADOW_OP_UPDATE_ACCEPTED_LENGTH;
|
||||
break;
|
||||
|
||||
case ShadowTopicStringTypeUpdateRejected:
|
||||
shadowOperationLength = SHADOW_OP_UPDATE_REJECTED_LENGTH;
|
||||
break;
|
||||
|
||||
case ShadowTopicStringTypeUpdateDocuments:
|
||||
shadowOperationLength = SHADOW_OP_UPDATE_DOCUMENTS_LENGTH;
|
||||
break;
|
||||
|
||||
case ShadowTopicStringTypeUpdateDelta:
|
||||
/* topicType >= ShadowTopicStringTypeMaxNum check is covered at entry of Shadow_AssembleTopicString. */
|
||||
default:
|
||||
shadowOperationLength = SHADOW_OP_UPDATE_DELTA_LENGTH;
|
||||
break;
|
||||
}
|
||||
|
||||
return shadowOperationLength;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void createShadowTopicString( ShadowTopicStringType_t topicType,
|
||||
const char * pThingName,
|
||||
uint8_t thingNameLength,
|
||||
const char * pShadowName,
|
||||
uint8_t shadowNameLength,
|
||||
char * pTopicBuffer )
|
||||
{
|
||||
uint16_t offset = 0U, operationStringLength = 0U;
|
||||
const char * pShadowPrefix = SHADOW_PREFIX;
|
||||
const char * pOperationString = NULL;
|
||||
const char * pClassicShadowRoot = SHADOW_CLASSIC_ROOT;
|
||||
const char * pNamedShadowRoot = SHADOW_NAMED_ROOT;
|
||||
|
||||
/* Copy the Shadow topic prefix into the topic buffer. */
|
||||
( void ) memcpy( ( void * ) pTopicBuffer,
|
||||
( const void * ) pShadowPrefix,
|
||||
( size_t ) SHADOW_PREFIX_LENGTH );
|
||||
offset = ( uint16_t ) ( offset + SHADOW_PREFIX_LENGTH );
|
||||
|
||||
/* Copy the Thing Name into the topic buffer. */
|
||||
( void ) memcpy( ( void * ) &( pTopicBuffer[ offset ] ),
|
||||
( const void * ) pThingName,
|
||||
( size_t ) thingNameLength );
|
||||
offset = ( uint16_t ) ( offset + thingNameLength );
|
||||
|
||||
/* Are we assembling a named shadow? */
|
||||
if( shadowNameLength > 0U )
|
||||
{
|
||||
/* Copy the named Shadow topic root into the topic buffer. */
|
||||
( void ) memcpy( ( void * ) &( pTopicBuffer[ offset ] ),
|
||||
( const void * ) pNamedShadowRoot,
|
||||
( size_t ) SHADOW_NAMED_ROOT_LENGTH );
|
||||
offset = ( uint16_t ) ( offset + SHADOW_NAMED_ROOT_LENGTH );
|
||||
|
||||
/* Copy the Shadow Name into the topic buffer. */
|
||||
( void ) memcpy( ( void * ) &( pTopicBuffer[ offset ] ),
|
||||
( const void * ) pShadowName,
|
||||
( size_t ) shadowNameLength );
|
||||
offset = ( uint16_t ) ( offset + shadowNameLength );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Copy the Classic Shadow topic root into the topic buffer. */
|
||||
( void ) memcpy( ( void * ) &( pTopicBuffer[ offset ] ),
|
||||
( const void * ) pClassicShadowRoot,
|
||||
( size_t ) SHADOW_CLASSIC_ROOT_LENGTH );
|
||||
offset = ( uint16_t ) ( offset + SHADOW_CLASSIC_ROOT_LENGTH );
|
||||
}
|
||||
|
||||
pOperationString = getShadowOperationString( topicType );
|
||||
operationStringLength = getShadowOperationLength( topicType );
|
||||
/* Copy the Shadow operation string into the topic buffer. */
|
||||
( void ) memcpy( ( void * ) &( pTopicBuffer[ offset ] ),
|
||||
( const void * ) pOperationString,
|
||||
( size_t ) operationStringLength );
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
ShadowStatus_t Shadow_MatchTopicString( const char * pTopic,
|
||||
uint16_t topicLength,
|
||||
ShadowMessageType_t * pMessageType,
|
||||
const char ** pThingName,
|
||||
uint8_t * pThingNameLength,
|
||||
const char ** pShadowName,
|
||||
uint8_t * pShadowNameLength )
|
||||
{
|
||||
uint16_t consumedTopicLength = 0U;
|
||||
ShadowStatus_t shadowStatus = SHADOW_SUCCESS;
|
||||
uint8_t thingNameLength = 0;
|
||||
uint8_t shadowNameLength = 0;
|
||||
|
||||
shadowStatus = validateMatchTopicParameters( pTopic, topicLength, pMessageType );
|
||||
|
||||
/* A shadow topic string takes one of the two forms.
|
||||
* Classic shadow:
|
||||
* $aws/things/<thingName>/shadow/<operation>
|
||||
* $aws/things/<thingName>/shadow/<operation>/<suffix>
|
||||
* Named shadow:
|
||||
* $aws/things/<thingName>/shadow/name/<shadowName>/<operation>
|
||||
* $aws/things/<thingName>/shadow/name/<shadowName>/<operation>/<suffix>
|
||||
*
|
||||
* We need to match the following things:
|
||||
* 1. Prefix ($aws/things).
|
||||
* 2. Thing Name.
|
||||
* 3. Classic shadow root (/shadow) OR Named shadow root (/shadow/name) and shadow name
|
||||
* 4. Shadow operation and suffix.
|
||||
*/
|
||||
if( shadowStatus == SHADOW_SUCCESS )
|
||||
{
|
||||
/* First match the prefix. */
|
||||
shadowStatus = containsSubString( &( pTopic[ consumedTopicLength ] ),
|
||||
topicLength - consumedTopicLength,
|
||||
SHADOW_PREFIX,
|
||||
SHADOW_PREFIX_LENGTH );
|
||||
|
||||
if( shadowStatus == SHADOW_SUCCESS )
|
||||
{
|
||||
consumedTopicLength += SHADOW_PREFIX_LENGTH;
|
||||
}
|
||||
else
|
||||
{
|
||||
LogDebug( ( "Not a Shadow topic. Failed to parse shadow topic prefix in pTopic %.*s", topicLength, pTopic ) );
|
||||
}
|
||||
}
|
||||
|
||||
if( shadowStatus == SHADOW_SUCCESS )
|
||||
{
|
||||
/* Extract thing name. */
|
||||
shadowStatus = extractThingName( pTopic,
|
||||
topicLength,
|
||||
&consumedTopicLength,
|
||||
&thingNameLength );
|
||||
}
|
||||
|
||||
if( shadowStatus == SHADOW_SUCCESS )
|
||||
{
|
||||
shadowStatus = extractShadowRootAndName( pTopic,
|
||||
topicLength,
|
||||
&consumedTopicLength,
|
||||
&shadowNameLength );
|
||||
}
|
||||
|
||||
if( shadowStatus == SHADOW_SUCCESS )
|
||||
{
|
||||
/* Extract shadow message type. */
|
||||
shadowStatus = extractShadowMessageType( &( pTopic[ consumedTopicLength ] ),
|
||||
topicLength - consumedTopicLength,
|
||||
pMessageType );
|
||||
|
||||
if( shadowStatus != SHADOW_SUCCESS )
|
||||
{
|
||||
shadowStatus = SHADOW_MESSAGE_TYPE_PARSE_FAILED;
|
||||
LogDebug( ( "Not a Shadow topic. Shadow message type is not in pTopic %.*s, failed to parse shadow message type.", topicLength, pTopic ) );
|
||||
}
|
||||
}
|
||||
|
||||
if( shadowStatus == SHADOW_SUCCESS )
|
||||
{
|
||||
/* Update the out parameters if we successfully matched the topic. */
|
||||
if( pThingName != NULL )
|
||||
{
|
||||
/* Thing name comes after shadow prefix. */
|
||||
*pThingName = &( pTopic[ SHADOW_PREFIX_LENGTH ] );
|
||||
}
|
||||
|
||||
if( pThingNameLength != NULL )
|
||||
{
|
||||
*pThingNameLength = thingNameLength;
|
||||
}
|
||||
|
||||
if( pShadowName != NULL )
|
||||
{
|
||||
*pShadowName = &( pTopic[ SHADOW_PREFIX_LENGTH + thingNameLength +
|
||||
SHADOW_NAMED_ROOT_LENGTH ] );
|
||||
}
|
||||
|
||||
if( pShadowNameLength != NULL )
|
||||
{
|
||||
*pShadowNameLength = shadowNameLength;
|
||||
}
|
||||
}
|
||||
|
||||
return shadowStatus;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
ShadowStatus_t Shadow_AssembleTopicString( ShadowTopicStringType_t topicType,
|
||||
const char * pThingName,
|
||||
uint8_t thingNameLength,
|
||||
const char * pShadowName,
|
||||
uint8_t shadowNameLength,
|
||||
char * pTopicBuffer,
|
||||
uint16_t bufferSize,
|
||||
uint16_t * pOutLength )
|
||||
{
|
||||
uint16_t generatedTopicStringLength = 0U;
|
||||
|
||||
ShadowStatus_t shadowStatus = validateAssembleTopicParameters( topicType,
|
||||
pThingName,
|
||||
thingNameLength,
|
||||
pShadowName,
|
||||
shadowNameLength,
|
||||
pTopicBuffer,
|
||||
pOutLength );
|
||||
|
||||
if( shadowStatus == SHADOW_SUCCESS )
|
||||
{
|
||||
generatedTopicStringLength = SHADOW_PREFIX_LENGTH + /* Prefix ("$aws/things/"). */
|
||||
thingNameLength + /* Thing name. */
|
||||
( ( shadowNameLength > 0U ) ? /* Handle named or classic shadow */
|
||||
( SHADOW_NAMED_ROOT_LENGTH + shadowNameLength ) :
|
||||
SHADOW_CLASSIC_ROOT_LENGTH ) +
|
||||
getShadowOperationLength( topicType ); /* Shadow operation. */
|
||||
|
||||
if( bufferSize < generatedTopicStringLength )
|
||||
{
|
||||
shadowStatus = SHADOW_BUFFER_TOO_SMALL;
|
||||
LogError( ( "Input bufferSize too small, bufferSize %u, required %u.",
|
||||
( unsigned int ) bufferSize,
|
||||
( unsigned int ) generatedTopicStringLength ) );
|
||||
}
|
||||
}
|
||||
|
||||
if( shadowStatus == SHADOW_SUCCESS )
|
||||
{
|
||||
/* With everything validated, now create the topic string */
|
||||
createShadowTopicString( topicType,
|
||||
pThingName,
|
||||
thingNameLength,
|
||||
pShadowName,
|
||||
shadowNameLength,
|
||||
pTopicBuffer );
|
||||
|
||||
/* Return the generated topic string length to the caller. */
|
||||
*pOutLength = generatedTopicStringLength;
|
||||
}
|
||||
|
||||
return shadowStatus;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
ShadowStatus_t Shadow_MatchTopic( const char * pTopic,
|
||||
uint16_t topicLength,
|
||||
ShadowMessageType_t * pMessageType,
|
||||
const char ** pThingName,
|
||||
uint16_t * pThingNameLength )
|
||||
{
|
||||
/* Shadow_MatchTopicString takes a pointer to a 8 bit unsigned integer for
|
||||
* output parameter Thing name length, whereas Shadow_MatchTopic takes a
|
||||
* pointer to a 16 bit integer. The maximum possible Thing name length is
|
||||
* 128 bytes and hence unsigned 8 bit integer is large enough to hold the
|
||||
* Thing name length. Refer to #SHADOW_THINGNAME_MAX_LENGTH for more details.
|
||||
* Passing a pointer to 16 bit integer directly to Shadow_MatchTopicString
|
||||
* may create data inconsistencies depending on the byte ordering in the
|
||||
* device platform. Hence, a local variable of 8 bit integer width is used for
|
||||
* the call to Shadow_MatchTopicString, and its value is copied to the 16 bit
|
||||
* integer pointer passed to Shadow_MatchTopic. */
|
||||
uint8_t thingNameLength = 0U;
|
||||
ShadowStatus_t shadowStatus = Shadow_MatchTopicString( pTopic,
|
||||
topicLength,
|
||||
pMessageType,
|
||||
pThingName,
|
||||
&thingNameLength,
|
||||
NULL,
|
||||
NULL );
|
||||
|
||||
/* Update the output parameter for Thing name length. */
|
||||
if( pThingNameLength != NULL )
|
||||
{
|
||||
*pThingNameLength = thingNameLength;
|
||||
}
|
||||
|
||||
return shadowStatus;
|
||||
}
|
||||
@ -0,0 +1,94 @@
|
||||
cmake_minimum_required ( VERSION 3.13.0 )
|
||||
project ( "Shadow unit test"
|
||||
VERSION 1.0.0
|
||||
LANGUAGES C )
|
||||
|
||||
# Allow the project to be organized into folders.
|
||||
set_property( GLOBAL PROPERTY USE_FOLDERS ON )
|
||||
|
||||
# Use C90.
|
||||
set( CMAKE_C_STANDARD 90 )
|
||||
set( CMAKE_C_STANDARD_REQUIRED ON )
|
||||
|
||||
# Do not allow in-source build.
|
||||
if( ${PROJECT_SOURCE_DIR} STREQUAL ${PROJECT_BINARY_DIR} )
|
||||
message( FATAL_ERROR "In-source build is not allowed. Please build in a separate directory, such as ${PROJECT_SOURCE_DIR}/build." )
|
||||
endif()
|
||||
|
||||
# Set global path variables.
|
||||
get_filename_component(__MODULE_ROOT_DIR "${CMAKE_CURRENT_LIST_DIR}/.." ABSOLUTE)
|
||||
set(MODULE_ROOT_DIR ${__MODULE_ROOT_DIR} CACHE INTERNAL "Shadow repository root.")
|
||||
|
||||
# Configure options to always show in CMake GUI.
|
||||
option( BUILD_CLONE_SUBMODULES
|
||||
"Set this to ON to automatically clone any required Git submodules. When OFF, submodules must be manually cloned."
|
||||
OFF )
|
||||
|
||||
# Set output directories.
|
||||
set( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin )
|
||||
set( CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib )
|
||||
set( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib )
|
||||
|
||||
# ========================== Coverity Analysis Configuration =======================================
|
||||
|
||||
# Coverity can run off the unit test targets, but this avoids calling unnecessary
|
||||
# unit testing tools like gcov and CMock.
|
||||
|
||||
# Include filepaths for source and include.
|
||||
include( ${MODULE_ROOT_DIR}/shadowFilePaths.cmake )
|
||||
|
||||
# Target for Coverity analysis that builds the library.
|
||||
add_library( coverity_analysis
|
||||
${SHADOW_SOURCES} )
|
||||
|
||||
# Shadow public include path.
|
||||
target_include_directories( coverity_analysis
|
||||
PUBLIC
|
||||
${SHADOW_INCLUDE_PUBLIC_DIRS}
|
||||
"${CMAKE_CURRENT_LIST_DIR}/include" )
|
||||
|
||||
target_compile_options(coverity_analysis PUBLIC -DNDEBUG -DDISABLE_LOGGING )
|
||||
|
||||
# ==================================== Test Configuration ========================================
|
||||
|
||||
# Define a CMock resource path.
|
||||
set( CMOCK_DIR ${MODULE_ROOT_DIR}/test/unit-test/CMock CACHE INTERNAL "CMock library source directory." )
|
||||
|
||||
# Include CMock build configuration.
|
||||
include( unit-test/cmock_build.cmake )
|
||||
|
||||
# Check if the CMock source directory exists, and if not present, clone the submodule
|
||||
# if BUILD_CLONE_SUBMODULES configuration is enabled.
|
||||
if( NOT EXISTS ${CMOCK_DIR}/src )
|
||||
# Attempt to clone CMock.
|
||||
if( ${BUILD_CLONE_SUBMODULES} )
|
||||
clone_cmock()
|
||||
else()
|
||||
message( FATAL_ERROR "The required submodule CMock does not exist. Either clone it manually, or set BUILD_CLONE_SUBMODULES to 1 to automatically clone it during build." )
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Add unit test and coverage configuration.
|
||||
|
||||
# Use CTest utility for managing test runs. This has to be added BEFORE
|
||||
# defining test targets with add_test()
|
||||
enable_testing()
|
||||
|
||||
# Add build targets for CMock and Unit, required for unit testing.
|
||||
add_cmock_targets()
|
||||
|
||||
# Add function to enable CMock based tests and coverage.
|
||||
include( ${MODULE_ROOT_DIR}/tools/cmock/create_test.cmake )
|
||||
|
||||
# Include build configuration for unit tests.
|
||||
add_subdirectory( unit-test )
|
||||
|
||||
# ==================================== Coverage Analysis configuration ============================
|
||||
|
||||
# Add a target for running coverage on tests.
|
||||
add_custom_target( coverage
|
||||
COMMAND ${CMAKE_COMMAND} -DCMOCK_DIR=${CMOCK_DIR}
|
||||
-P ${MODULE_ROOT_DIR}/tools/cmock/coverage.cmake
|
||||
DEPENDS cmock unity shadow_utest
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
|
||||
)
|
||||
24
kernel/FreeRTOS-Plus/Source/AWS/device-shadow/test/cbmc/.gitignore
vendored
Normal file
24
kernel/FreeRTOS-Plus/Source/AWS/device-shadow/test/cbmc/.gitignore
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
# Emitted when running CBMC proofs
|
||||
proofs/**/logs
|
||||
proofs/**/gotos
|
||||
proofs/**/report
|
||||
proofs/**/html
|
||||
proofs/output
|
||||
|
||||
# Emitted by CBMC Viewer
|
||||
TAGS-*
|
||||
|
||||
# Emitted by Arpa
|
||||
arpa_cmake/
|
||||
arpa-validation-logs/
|
||||
Makefile.arpa
|
||||
|
||||
# Emitted by litani
|
||||
.ninja_deps
|
||||
.ninja_log
|
||||
.litani_cache_dir
|
||||
|
||||
# These files should be overwritten whenever prepare.py runs
|
||||
cbmc-batch.yaml
|
||||
|
||||
__pycache__/
|
||||
@ -0,0 +1,6 @@
|
||||
CBMC proof include files
|
||||
========================
|
||||
|
||||
This directory contains include files written for CBMC proof. It is
|
||||
common to write some code to model aspects of the system under test,
|
||||
and the header files for this code go here.
|
||||
@ -0,0 +1,30 @@
|
||||
# -*- mode: makefile -*-
|
||||
# The first line sets the emacs major mode to Makefile
|
||||
|
||||
################################################################
|
||||
# Use this file to give project-specific definitions of the command
|
||||
# line arguments to pass to CBMC tools like goto-cc to build the goto
|
||||
# binaries and cbmc to do the property and coverage checking.
|
||||
#
|
||||
# Use this file to override most default definitions of variables in
|
||||
# Makefile.common.
|
||||
################################################################
|
||||
|
||||
# Flags to pass to goto-cc for compilation (typically those passed to gcc -c)
|
||||
COMPILE_FLAGS += -fPIC
|
||||
COMPILE_FLAGS += -std=gnu90
|
||||
|
||||
LITANI ?= litani
|
||||
PROJECT_NAME = "FreeRTOS coreShadow"
|
||||
|
||||
# Flags to pass to goto-cc for linking (typically those passed to gcc)
|
||||
# LINK_FLAGS =
|
||||
|
||||
# Preprocessor include paths -I...
|
||||
INCLUDES += -I$(SRCDIR)/test/cbmc/include
|
||||
INCLUDES += -I$(SRCDIR)/source/include
|
||||
INCLUDES += -I$(SRCDIR)/source
|
||||
INCLUDES += -I$(SRCDIR)/test/include
|
||||
|
||||
# Preprocessor definitions -D...
|
||||
DEFINES += -Dshadow_EXPORTS
|
||||
@ -0,0 +1,10 @@
|
||||
# -*- mode: makefile -*-
|
||||
# The first line sets the emacs major mode to Makefile
|
||||
|
||||
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
# SPDX-License-Identifier: MIT-0
|
||||
|
||||
################################################################
|
||||
# Use this file to give project-specific targets, including targets
|
||||
# that may depend on targets defined in Makefile.common.
|
||||
################################################################
|
||||
@ -0,0 +1,11 @@
|
||||
# -*- mode: makefile -*-
|
||||
# The first line sets the emacs major mode to Makefile
|
||||
|
||||
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
# SPDX-License-Identifier: MIT-0
|
||||
|
||||
################################################################
|
||||
# Use this file to define project-specific targets and definitions for
|
||||
# unit testing or continuous integration that may depend on targets
|
||||
# defined in Makefile.common
|
||||
################################################################
|
||||
@ -0,0 +1 @@
|
||||
SRCDIR ?= $(abspath $(PROOF_ROOT)/../../..)
|
||||
@ -0,0 +1,999 @@
|
||||
# -*- mode: makefile -*-
|
||||
# The first line sets the emacs major mode to Makefile
|
||||
|
||||
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
# SPDX-License-Identifier: MIT-0
|
||||
|
||||
CBMC_STARTER_KIT_VERSION = CBMC starter kit 2.5
|
||||
|
||||
################################################################
|
||||
# The CBMC Starter Kit depends on the files Makefile.common and
|
||||
# run-cbmc-proofs.py. They are installed by the setup script
|
||||
# cbmc-starter-kit-setup and updated to the latest version by the
|
||||
# update script cbmc-starter-kit-update. For more information about
|
||||
# the starter kit and these files and these scripts, see
|
||||
# https://model-checking.github.io/cbmc-starter-kit
|
||||
#
|
||||
# Makefile.common implements what we consider to be some best
|
||||
# practices for using cbmc for software verification.
|
||||
#
|
||||
# Section I gives default values for a large number of Makefile
|
||||
# variables that control
|
||||
# * how your code is built (include paths, etc),
|
||||
# * what program transformations are applied to your code (loop
|
||||
# unwinding, etc), and
|
||||
# * what properties cbmc checks for in your code (memory safety, etc).
|
||||
#
|
||||
# These variables are defined below with definitions of the form
|
||||
# VARIABLE ?= DEFAULT_VALUE
|
||||
# meaning VARIABLE is set to DEFAULT_VALUE if VARIABLE has not already
|
||||
# been given a value.
|
||||
#
|
||||
# For your project, you can override these default values with
|
||||
# project-specific definitions in Makefile-project-defines.
|
||||
#
|
||||
# For any individual proof, you can override these default values and
|
||||
# project-specific values with proof-specific definitions in the
|
||||
# Makefile for your proof.
|
||||
#
|
||||
# The definitions in the proof Makefile override definitions in the
|
||||
# project Makefile-project-defines which override definitions in this
|
||||
# Makefile.common.
|
||||
#
|
||||
# Section II uses the values defined in Section I to build your code, run
|
||||
# your proof, and build a report of your results. You should not need
|
||||
# to modify or override anything in Section II, but you may want to
|
||||
# read it to understand how the values defined in Section I control
|
||||
# things.
|
||||
#
|
||||
# To use Makefile.common, set variables as described above as needed,
|
||||
# and then for each proof,
|
||||
#
|
||||
# * Create a subdirectory <DIR>.
|
||||
# * Write a proof harness (a function) with the name <HARNESS_ENTRY>
|
||||
# in a file with the name <DIR>/<HARNESS_FILE>.c
|
||||
# * Write a makefile with the name <DIR>/Makefile that looks
|
||||
# something like
|
||||
#
|
||||
# HARNESS_FILE=<HARNESS_FILE>
|
||||
# HARNESS_ENTRY=<HARNESS_ENTRY>
|
||||
# PROOF_UID=<PROOF_UID>
|
||||
#
|
||||
# PROJECT_SOURCES += $(SRCDIR)/libraries/api_1.c
|
||||
# PROJECT_SOURCES += $(SRCDIR)/libraries/api_2.c
|
||||
#
|
||||
# PROOF_SOURCES += $(PROOFDIR)/harness.c
|
||||
# PROOF_SOURCES += $(SRCDIR)/cbmc/proofs/stub_a.c
|
||||
# PROOF_SOURCES += $(SRCDIR)/cbmc/proofs/stub_b.c
|
||||
#
|
||||
# UNWINDSET += foo.0:3
|
||||
# UNWINDSET += bar.1:6
|
||||
#
|
||||
# REMOVE_FUNCTION_BODY += api_stub_a
|
||||
# REMOVE_FUNCTION_BODY += api_stub_b
|
||||
#
|
||||
# DEFINES = -DDEBUG=0
|
||||
#
|
||||
# include ../Makefile.common
|
||||
#
|
||||
# * Change directory to <DIR> and run make
|
||||
#
|
||||
# The proof setup script cbmc-starter-kit-setup-proof from the CBMC
|
||||
# Starter Kit will do most of this for, creating a directory and
|
||||
# writing a basic Makefile and proof harness into it that you can edit
|
||||
# as described above.
|
||||
#
|
||||
# Warning: If you get results that are hard to explain, consider
|
||||
# running "make clean" or "make veryclean" before "make" if you get
|
||||
# results that are hard to explain. Dependency handling in this
|
||||
# Makefile.common may not be perfect.
|
||||
|
||||
SHELL=/bin/bash
|
||||
|
||||
default: report
|
||||
|
||||
################################################################
|
||||
################################################################
|
||||
## Section I: This section gives common variable definitions.
|
||||
##
|
||||
## Override these definitions in Makefile-project-defines or
|
||||
## your proof Makefile.
|
||||
##
|
||||
## Remember that Makefile.common and Makefile-project-defines are
|
||||
## included into the proof Makefile in your proof directory, so all
|
||||
## relative pathnames defined there should be relative to your proof
|
||||
## directory.
|
||||
|
||||
################################################################
|
||||
# Define the layout of the source tree and the proof subtree
|
||||
#
|
||||
# Generally speaking,
|
||||
#
|
||||
# SRCDIR = the root of the repository
|
||||
# CBMC_ROOT = /srcdir/cbmc
|
||||
# PROOF_ROOT = /srcdir/cbmc/proofs
|
||||
# PROOF_SOURCE = /srcdir/cbmc/sources
|
||||
# PROOF_INCLUDE = /srcdir/cbmc/include
|
||||
# PROOF_STUB = /srcdir/cbmc/stubs
|
||||
# PROOFDIR = the directory containing the Makefile for your proof
|
||||
#
|
||||
# The path /srcdir/cbmc used in the example above is determined by the
|
||||
# setup script cbmc-starter-kit-setup. Projects usually create a cbmc
|
||||
# directory somewhere in the source tree, and run the setup script in
|
||||
# that directory. The value of CBMC_ROOT becomes the absolute path to
|
||||
# that directory.
|
||||
#
|
||||
# The location of that cbmc directory in the source tree affects the
|
||||
# definition of SRCDIR, which is defined in terms of the relative path
|
||||
# from a proof directory to the repository root. The definition is
|
||||
# usually determined by the setup script cbmc-starter-kit-setup and
|
||||
# written to Makefile-template-defines, but you can override it for a
|
||||
# project in Makefile-project-defines and for a specific proof in the
|
||||
# Makefile for the proof.
|
||||
|
||||
# Absolute path to the directory containing this Makefile.common
|
||||
# See https://ftp.gnu.org/old-gnu/Manuals/make-3.80/html_node/make_17.html
|
||||
#
|
||||
# Note: We compute the absolute paths to the makefiles in MAKEFILE_LIST
|
||||
# before we filter the list of makefiles for %/Makefile.common.
|
||||
# Otherwise an invocation of the form "make -f Makefile.common" will set
|
||||
# MAKEFILE_LIST to "Makefile.common" which will fail to match the
|
||||
# pattern %/Makefile.common.
|
||||
#
|
||||
MAKEFILE_PATHS = $(foreach makefile,$(MAKEFILE_LIST),$(abspath $(makefile)))
|
||||
PROOF_ROOT = $(dir $(filter %/Makefile.common,$(MAKEFILE_PATHS)))
|
||||
|
||||
CBMC_ROOT = $(shell dirname $(PROOF_ROOT))
|
||||
PROOF_SOURCE = $(CBMC_ROOT)/sources
|
||||
PROOF_INCLUDE = $(CBMC_ROOT)/include
|
||||
PROOF_STUB = $(CBMC_ROOT)/stubs
|
||||
|
||||
# Project-specific definitions to override default definitions below
|
||||
# * Makefile-project-defines will never be overwritten
|
||||
# * Makefile-template-defines may be overwritten when the starter
|
||||
# kit is updated
|
||||
sinclude $(PROOF_ROOT)/Makefile-project-defines
|
||||
sinclude $(PROOF_ROOT)/Makefile-template-defines
|
||||
|
||||
# SRCDIR is the path to the root of the source tree
|
||||
# This is a default definition that is frequently overridden in
|
||||
# another Makefile, see the discussion of SRCDIR above.
|
||||
SRCDIR ?= $(abspath ../..)
|
||||
|
||||
# PROOFDIR is the path to the directory containing the proof harness
|
||||
PROOFDIR ?= $(abspath .)
|
||||
|
||||
################################################################
|
||||
# Define how to run CBMC
|
||||
|
||||
# Do property checking with the external SAT solver given by
|
||||
# EXTERNAL_SAT_SOLVER. Do coverage checking with the default solver,
|
||||
# since coverage checking requires the use of an incremental solver.
|
||||
# The EXTERNAL_SAT_SOLVER variable is typically set (if it is at all)
|
||||
# as an environment variable or as a makefile variable in
|
||||
# Makefile-project-defines.
|
||||
#
|
||||
# For a particular proof, if the default solver is faster, do property
|
||||
# checking with the default solver by including this definition in the
|
||||
# proof Makefile:
|
||||
# USE_EXTERNAL_SAT_SOLVER =
|
||||
#
|
||||
ifneq ($(strip $(EXTERNAL_SAT_SOLVER)),)
|
||||
USE_EXTERNAL_SAT_SOLVER ?= --external-sat-solver $(EXTERNAL_SAT_SOLVER)
|
||||
endif
|
||||
CHECKFLAGS += $(USE_EXTERNAL_SAT_SOLVER)
|
||||
|
||||
# Job pools
|
||||
# For version of Litani that are new enough (where `litani print-capabilities`
|
||||
# prints "pools"), proofs for which `EXPENSIVE = true` is set can be added to a
|
||||
# "job pool" that restricts how many expensive proofs are run at a time. All
|
||||
# other proofs will be built in parallel as usual.
|
||||
#
|
||||
# In more detail: all compilation, instrumentation, and report jobs are run with
|
||||
# full parallelism as usual, even for expensive proofs. The CBMC jobs for
|
||||
# non-expensive proofs are also run in parallel. The only difference is that the
|
||||
# CBMC safety checks and coverage checks for expensive proofs are run with a
|
||||
# restricted parallelism level. At any one time, only N of these jobs are run at
|
||||
# once, amongst all the proofs.
|
||||
#
|
||||
# To configure N, Litani needs to be initialized with a pool called "expensive".
|
||||
# For example, to only run two CBMC safety/coverage jobs at a time from amongst
|
||||
# all the proofs, you would initialize litani like
|
||||
# litani init --pools expensive:2
|
||||
# The run-cbmc-proofs.py script takes care of this initialization through the
|
||||
# --expensive-jobs-parallelism flag.
|
||||
#
|
||||
# To enable this feature, set
|
||||
# the ENABLE_POOLS variable when running Make, like
|
||||
# `make ENABLE_POOLS=true report`
|
||||
# The run-cbmc-proofs.py script takes care of this through the
|
||||
# --restrict-expensive-jobs flag.
|
||||
|
||||
ifeq ($(strip $(ENABLE_POOLS)),)
|
||||
POOL =
|
||||
else ifeq ($(strip $(EXPENSIVE)),)
|
||||
POOL =
|
||||
else
|
||||
POOL = --pool expensive
|
||||
endif
|
||||
|
||||
# Similar to the pool feature above. If Litani is new enough, enable
|
||||
# profiling CBMC's memory use.
|
||||
ifeq ($(strip $(ENABLE_MEMORY_PROFILING)),)
|
||||
MEMORY_PROFILING =
|
||||
else
|
||||
MEMORY_PROFILING = --profile-memory
|
||||
endif
|
||||
|
||||
# Property checking flags
|
||||
#
|
||||
# Each variable below controls a specific property checking flag
|
||||
# within CBMC. If desired, a property flag can be disabled within
|
||||
# a particular proof by nulling the corresponding variable. For
|
||||
# instance, the following line:
|
||||
#
|
||||
# CHECK_FLAG_POINTER_CHECK =
|
||||
#
|
||||
# would disable the --pointer-check CBMC flag within:
|
||||
# * an entire project when added to Makefile-project-defines
|
||||
# * a specific proof when added to the harness Makefile
|
||||
|
||||
CBMC_FLAG_MALLOC_MAY_FAIL ?= --malloc-may-fail
|
||||
CBMC_FLAG_MALLOC_FAIL_NULL ?= --malloc-fail-null
|
||||
CBMC_FLAG_BOUNDS_CHECK ?= --bounds-check
|
||||
CBMC_FLAG_CONVERSION_CHECK ?= --conversion-check
|
||||
CBMC_FLAG_DIV_BY_ZERO_CHECK ?= --div-by-zero-check
|
||||
CBMC_FLAG_FLOAT_OVERFLOW_CHECK ?= --float-overflow-check
|
||||
CBMC_FLAG_NAN_CHECK ?= --nan-check
|
||||
CBMC_FLAG_POINTER_CHECK ?= --pointer-check
|
||||
CBMC_FLAG_POINTER_OVERFLOW_CHECK ?= --pointer-overflow-check
|
||||
CBMC_FLAG_POINTER_PRIMITIVE_CHECK ?= --pointer-primitive-check
|
||||
CBMC_FLAG_SIGNED_OVERFLOW_CHECK ?= --signed-overflow-check
|
||||
CBMC_FLAG_UNDEFINED_SHIFT_CHECK ?= --undefined-shift-check
|
||||
CBMC_FLAG_UNSIGNED_OVERFLOW_CHECK ?= --unsigned-overflow-check
|
||||
CBMC_FLAG_UNWINDING_ASSERTIONS ?= --unwinding-assertions
|
||||
CBMC_FLAG_UNWIND ?= --unwind 1
|
||||
CBMC_FLAG_FLUSH ?= --flush
|
||||
|
||||
# CBMC flags used for property checking and coverage checking
|
||||
|
||||
CBMCFLAGS += $(CBMC_FLAG_UNWIND) $(CBMC_UNWINDSET) $(CBMC_FLAG_FLUSH)
|
||||
|
||||
# CBMC flags used for property checking
|
||||
|
||||
CHECKFLAGS += $(CBMC_FLAG_MALLOC_MAY_FAIL)
|
||||
CHECKFLAGS += $(CBMC_FLAG_MALLOC_FAIL_NULL)
|
||||
CHECKFLAGS += $(CBMC_FLAG_BOUNDS_CHECK)
|
||||
CHECKFLAGS += $(CBMC_FLAG_CONVERSION_CHECK)
|
||||
CHECKFLAGS += $(CBMC_FLAG_DIV_BY_ZERO_CHECK)
|
||||
CHECKFLAGS += $(CBMC_FLAG_FLOAT_OVERFLOW_CHECK)
|
||||
CHECKFLAGS += $(CBMC_FLAG_NAN_CHECK)
|
||||
CHECKFLAGS += $(CBMC_FLAG_POINTER_CHECK)
|
||||
CHECKFLAGS += $(CBMC_FLAG_POINTER_OVERFLOW_CHECK)
|
||||
CHECKFLAGS += $(CBMC_FLAG_POINTER_PRIMITIVE_CHECK)
|
||||
CHECKFLAGS += $(CBMC_FLAG_SIGNED_OVERFLOW_CHECK)
|
||||
CHECKFLAGS += $(CBMC_FLAG_UNDEFINED_SHIFT_CHECK)
|
||||
CHECKFLAGS += $(CBMC_FLAG_UNSIGNED_OVERFLOW_CHECK)
|
||||
CHECKFLAGS += $(CBMC_FLAG_UNWINDING_ASSERTIONS)
|
||||
|
||||
# CBMC flags used for coverage checking
|
||||
|
||||
COVERFLAGS += $(CBMC_FLAG_MALLOC_MAY_FAIL)
|
||||
COVERFLAGS += $(CBMC_FLAG_MALLOC_FAIL_NULL)
|
||||
|
||||
# Additional CBMC flag to CBMC control verbosity.
|
||||
#
|
||||
# Meaningful values are
|
||||
# 0 none
|
||||
# 1 only errors
|
||||
# 2 + warnings
|
||||
# 4 + results
|
||||
# 6 + status/phase information
|
||||
# 8 + statistical information
|
||||
# 9 + progress information
|
||||
# 10 + debug info
|
||||
#
|
||||
# Uncomment the following line or set in Makefile-project-defines
|
||||
# CBMC_VERBOSITY ?= --verbosity 4
|
||||
|
||||
# Additional CBMC flag to control how CBMC treats static variables.
|
||||
#
|
||||
# NONDET_STATIC is a list of flags of the form --nondet-static
|
||||
# and --nondet-static-exclude VAR. The --nondet-static flag causes
|
||||
# CBMC to initialize static variables with unconstrained value
|
||||
# (ignoring initializers and default zero-initialization). The
|
||||
# --nondet-static-exclude VAR excludes VAR for the variables
|
||||
# initialized with unconstrained values.
|
||||
NONDET_STATIC ?=
|
||||
|
||||
# Flags to pass to goto-cc for compilation and linking
|
||||
COMPILE_FLAGS ?= -Wall
|
||||
LINK_FLAGS ?= -Wall
|
||||
EXPORT_FILE_LOCAL_SYMBOLS ?= --export-file-local-symbols
|
||||
|
||||
# Preprocessor include paths -I...
|
||||
INCLUDES ?=
|
||||
|
||||
# Preprocessor definitions -D...
|
||||
DEFINES ?=
|
||||
|
||||
# CBMC object model
|
||||
#
|
||||
# CBMC_OBJECT_BITS is the number of bits in a pointer CBMC uses for
|
||||
# the id of the object to which a pointer is pointing. CBMC uses 8
|
||||
# bits for the object id by default. The remaining bits in the pointer
|
||||
# are used for offset into the object. This limits the size of the
|
||||
# objects that CBMC can model. This Makefile defines this bound on
|
||||
# object size to be CBMC_MAX_OBJECT_SIZE. You are likely to get
|
||||
# unexpected results if you try to malloc an object larger than this
|
||||
# bound.
|
||||
CBMC_OBJECT_BITS ?= 8
|
||||
|
||||
# CBMC loop unwinding (Normally set in the proof Makefile)
|
||||
#
|
||||
# UNWINDSET is a list of pairs of the form foo.1:4 meaning that
|
||||
# CBMC should unwind loop 1 in function foo no more than 4 times.
|
||||
# For historical reasons, the number 4 is one more than the number
|
||||
# of times CBMC actually unwinds the loop.
|
||||
UNWINDSET ?=
|
||||
|
||||
# CBMC early loop unwinding (Normally set in the proof Makefile)
|
||||
#
|
||||
# Most users can ignore this variable.
|
||||
#
|
||||
# This variable exists to support the use of loop and function
|
||||
# contracts, two features under development for CBMC. Checking the
|
||||
# assigns clause for function contracts and loop invariants currently
|
||||
# assumes loop-free bodies for loops and functions with contracts
|
||||
# (possibly after replacing nested loops with their own loop
|
||||
# contracts). To satisfy this requirement, it may be necessary to
|
||||
# unwind some loops before the function contract and loop invariant
|
||||
# transformations are applied to the goto program. This variable
|
||||
# EARLY_UNWINDSET is identical to UNWINDSET, and we assume that the
|
||||
# loops mentioned in EARLY_UNWINDSET and UNWINDSET are disjoint.
|
||||
EARLY_UNWINDSET ?=
|
||||
|
||||
# CBMC function removal (Normally set set in the proof Makefile)
|
||||
#
|
||||
# REMOVE_FUNCTION_BODY is a list of function names. CBMC will "undefine"
|
||||
# the function, and CBMC will treat the function as having no side effects
|
||||
# and returning an unconstrained value of the appropriate return type.
|
||||
# The list should include the names of functions being stubbed out.
|
||||
REMOVE_FUNCTION_BODY ?=
|
||||
|
||||
# CBMC function pointer restriction (Normally set in the proof Makefile)
|
||||
#
|
||||
# RESTRICT_FUNCTION_POINTER is a list of function pointer restriction
|
||||
# instructions of the form:
|
||||
#
|
||||
# <fun_id>.function_pointer_call.<N>/<fun_id>[,<fun_id>]*
|
||||
#
|
||||
# The function pointer call number <N> in the specified function gets
|
||||
# rewritten to a case switch over a finite list of functions.
|
||||
# If some possible target functions are omitted from the list a counter
|
||||
# example trace will be found by CBMC, i.e. the transformation is sound.
|
||||
# If the target functions are file-local symbols, then mangled names must
|
||||
# be used.
|
||||
RESTRICT_FUNCTION_POINTER ?=
|
||||
|
||||
# The project source files (Normally set set in the proof Makefile)
|
||||
#
|
||||
# PROJECT_SOURCES is the list of project source files to compile,
|
||||
# including the source file defining the function under test.
|
||||
PROJECT_SOURCES ?=
|
||||
|
||||
# The proof source files (Normally set in the proof Makefile)
|
||||
#
|
||||
# PROOF_SOURCES is the list of proof source files to compile, including
|
||||
# the proof harness, and including any function stubs being used.
|
||||
PROOF_SOURCES ?=
|
||||
|
||||
# The number of seconds that CBMC should be allowed to run for before
|
||||
# being forcefully terminated. Currently, this is set to be less than
|
||||
# the time limit for a CodeBuild job, which is eight hours. If a proof
|
||||
# run takes longer than the time limit of the CI environment, the
|
||||
# environment will halt the proof run without updating the Litani
|
||||
# report, making the proof run appear to "hang".
|
||||
CBMC_TIMEOUT ?= 21600
|
||||
|
||||
# Proof writers could add function contracts in their source code.
|
||||
# These contracts are ignored by default, but may be enabled in two distinct
|
||||
# contexts using the following two variables:
|
||||
# 1. To check whether one or more function contracts are sound with respect to
|
||||
# the function implementation, CHECK_FUNCTION_CONTRACTS should be a list of
|
||||
# function names.
|
||||
# 2. To replace calls to certain functions with their correspondent function
|
||||
# contracts, USE_FUNCTION_CONTRACTS should be a list of function names.
|
||||
# One must check separately whether a function contract is sound before
|
||||
# replacing it in calling contexts.
|
||||
CHECK_FUNCTION_CONTRACTS ?=
|
||||
CBMC_CHECK_FUNCTION_CONTRACTS := $(patsubst %,--enforce-contract %, $(CHECK_FUNCTION_CONTRACTS))
|
||||
|
||||
USE_FUNCTION_CONTRACTS ?=
|
||||
CBMC_USE_FUNCTION_CONTRACTS := $(patsubst %,--replace-call-with-contract %, $(USE_FUNCTION_CONTRACTS))
|
||||
|
||||
# Similarly, proof writers could also add loop contracts in their source code
|
||||
# to obtain unbounded correctness proofs. Unlike function contracts, loop
|
||||
# contracts are not reusable and thus are checked and used simultaneously.
|
||||
# These contracts are also ignored by default, but may be enabled by setting
|
||||
# the APPLY_LOOP_CONTRACTS variable to 1.
|
||||
APPLY_LOOP_CONTRACTS ?= 0
|
||||
ifeq ($(APPLY_LOOP_CONTRACTS),1)
|
||||
CBMC_APPLY_LOOP_CONTRACTS ?= --apply-loop-contracts
|
||||
endif
|
||||
|
||||
# Silence makefile output (eg, long litani commands) unless VERBOSE is set.
|
||||
ifndef VERBOSE
|
||||
MAKEFLAGS := $(MAKEFLAGS) -s
|
||||
endif
|
||||
|
||||
################################################################
|
||||
################################################################
|
||||
## Section II: This section defines the process of running a proof
|
||||
##
|
||||
## There should be no reason to edit anything below this line.
|
||||
|
||||
################################################################
|
||||
# Paths
|
||||
|
||||
CBMC ?= cbmc
|
||||
GOTO_ANALYZER ?= goto-analyzer
|
||||
GOTO_CC ?= goto-cc
|
||||
GOTO_INSTRUMENT ?= goto-instrument
|
||||
CRANGLER ?= crangler
|
||||
VIEWER ?= cbmc-viewer
|
||||
MAKE_SOURCE ?= make-source
|
||||
VIEWER2 ?= cbmc-viewer
|
||||
CMAKE ?= cmake
|
||||
|
||||
GOTODIR ?= $(PROOFDIR)/gotos
|
||||
LOGDIR ?= $(PROOFDIR)/logs
|
||||
|
||||
PROJECT ?= project
|
||||
PROOF ?= proof
|
||||
|
||||
HARNESS_GOTO ?= $(GOTODIR)/$(HARNESS_FILE)
|
||||
PROJECT_GOTO ?= $(GOTODIR)/$(PROJECT)
|
||||
PROOF_GOTO ?= $(GOTODIR)/$(PROOF)
|
||||
|
||||
################################################################
|
||||
# Useful macros for values that are hard to reference
|
||||
SPACE :=$() $()
|
||||
COMMA :=,
|
||||
|
||||
################################################################
|
||||
# Set C compiler defines
|
||||
|
||||
CBMCFLAGS += --object-bits $(CBMC_OBJECT_BITS)
|
||||
COMPILE_FLAGS += --object-bits $(CBMC_OBJECT_BITS)
|
||||
|
||||
DEFINES += -DCBMC=1
|
||||
DEFINES += -DCBMC_OBJECT_BITS=$(CBMC_OBJECT_BITS)
|
||||
DEFINES += -DCBMC_MAX_OBJECT_SIZE="(SIZE_MAX>>(CBMC_OBJECT_BITS+1))"
|
||||
|
||||
# CI currently assumes cbmc invocation has at most one --unwindset
|
||||
ifdef UNWINDSET
|
||||
ifneq ($(strip $(UNWINDSET)),"")
|
||||
CBMC_UNWINDSET := --unwindset $(subst $(SPACE),$(COMMA),$(strip $(UNWINDSET)))
|
||||
endif
|
||||
endif
|
||||
ifdef EARLY_UNWINDSET
|
||||
ifneq ($(strip $(EARLY_UNWINDSET)),"")
|
||||
CBMC_EARLY_UNWINDSET := --unwindset $(subst $(SPACE),$(COMMA),$(strip $(EARLY_UNWINDSET)))
|
||||
endif
|
||||
endif
|
||||
|
||||
CBMC_REMOVE_FUNCTION_BODY := $(patsubst %,--remove-function-body %, $(REMOVE_FUNCTION_BODY))
|
||||
CBMC_RESTRICT_FUNCTION_POINTER := $(patsubst %,--restrict-function-pointer %, $(RESTRICT_FUNCTION_POINTER))
|
||||
|
||||
################################################################
|
||||
# Targets for rewriting source files with crangler
|
||||
|
||||
# Construct crangler configuration files
|
||||
#
|
||||
# REWRITTEN_SOURCES is a list of crangler output files source.i.
|
||||
# This target assumes that for each source.i
|
||||
# * source.i_SOURCE is the path to a source file,
|
||||
# * source.i_FUNCTIONS is a list of functions (may be empty)
|
||||
# * source.i_OBJECTS is a list of variables (may be empty)
|
||||
# This target constructs the crangler configuration file source.i.json
|
||||
# of the form
|
||||
# {
|
||||
# "sources": [ "/proj/code.c" ],
|
||||
# "includes": [ "/proj/include" ],
|
||||
# "defines": [ "VAR=1" ],
|
||||
# "functions": [ {"function_name": ["remove static"]} ],
|
||||
# "objects": [ {"variable_name": ["remove static"]} ],
|
||||
# "output": "source.i"
|
||||
# }
|
||||
# to remove the static attribute from function_name and variable_name
|
||||
# in the source file source.c and write the result to source.i.
|
||||
#
|
||||
# This target assumes that filenames include no spaces and that
|
||||
# the INCLUDES and DEFINES variables include no spaces after -I
|
||||
# and -D. For example, use "-DVAR=1" and not "-D VAR=1".
|
||||
#
|
||||
# Define *_SOURCE, *_FUNCTIONS, and *_OBJECTS in the proof Makefile.
|
||||
# The string source.i is usually an absolute path $(PROOFDIR)/code.i
|
||||
# to a file in the proof directory that contains the proof Makefile.
|
||||
# The proof Makefile usually includes the definitions
|
||||
# $(PROOFDIR)/code.i_SOURCE = /proj/code.c
|
||||
# $(PROOFDIR)/code.i_FUNCTIONS = function_name
|
||||
# $(PROOFDIR)/code.i_OBJECTS = variable_name
|
||||
# Because these definitions refer to PROOFDIR that is defined in this
|
||||
# Makefile.common, these definitions must appear after the inclusion
|
||||
# of Makefile.common in the proof Makefile.
|
||||
#
|
||||
$(foreach rs,$(REWRITTEN_SOURCES),$(eval $(rs).json: $($(rs)_SOURCE)))
|
||||
$(foreach rs,$(REWRITTEN_SOURCES),$(rs).json):
|
||||
echo '{'\
|
||||
'"sources": ['\
|
||||
'"$($(@:.json=)_SOURCE)"'\
|
||||
'],'\
|
||||
'"includes": ['\
|
||||
'$(subst $(SPACE),$(COMMA),$(patsubst -I%,"%",$(strip $(INCLUDES))))' \
|
||||
'],'\
|
||||
'"defines": ['\
|
||||
'$(subst $(SPACE),$(COMMA),$(patsubst -D%,"%",$(subst ",\",$(strip $(DEFINES)))))' \
|
||||
'],'\
|
||||
'"functions": ['\
|
||||
'{'\
|
||||
'$(subst ~, ,$(subst $(SPACE),$(COMMA),$(patsubst %,"%":["remove~static"],$($(@:.json=)_FUNCTIONS))))' \
|
||||
'}'\
|
||||
'],'\
|
||||
'"objects": ['\
|
||||
'{'\
|
||||
'$(subst ~, ,$(subst $(SPACE),$(COMMA),$(patsubst %,"%":["remove~static"],$($(@:.json=)_OBJECTS))))' \
|
||||
'}'\
|
||||
'],'\
|
||||
'"output": "$(@:.json=)"'\
|
||||
'}' > $@
|
||||
|
||||
# Rewrite source files with crangler
|
||||
#
|
||||
$(foreach rs,$(REWRITTEN_SOURCES),$(eval $(rs): $(rs).json))
|
||||
$(REWRITTEN_SOURCES):
|
||||
$(LITANI) add-job \
|
||||
--command \
|
||||
'$(CRANGLER) $@.json' \
|
||||
--inputs $($@_SOURCE) \
|
||||
--outputs $@ \
|
||||
--stdout-file $(LOGDIR)/crangler-$(subst /,_,$(subst .,_,$@))-log.txt \
|
||||
--interleave-stdout-stderr \
|
||||
--pipeline-name "$(PROOF_UID)" \
|
||||
--ci-stage build \
|
||||
--description "$(PROOF_UID): removing static"
|
||||
|
||||
################################################################
|
||||
# Build targets that make the relevant .goto files
|
||||
|
||||
# Compile project sources
|
||||
$(PROJECT_GOTO)1.goto: $(PROJECT_SOURCES) $(REWRITTEN_SOURCES)
|
||||
$(LITANI) add-job \
|
||||
--command \
|
||||
'$(GOTO_CC) $(CBMC_VERBOSITY) $(COMPILE_FLAGS) $(EXPORT_FILE_LOCAL_SYMBOLS) $(INCLUDES) $(DEFINES) $^ -o $@' \
|
||||
--inputs $^ \
|
||||
--outputs $@ \
|
||||
--stdout-file $(LOGDIR)/project_sources-log.txt \
|
||||
--pipeline-name "$(PROOF_UID)" \
|
||||
--ci-stage build \
|
||||
--description "$(PROOF_UID): building project binary"
|
||||
|
||||
# Compile proof sources
|
||||
$(PROOF_GOTO)1.goto: $(PROOF_SOURCES)
|
||||
$(LITANI) add-job \
|
||||
--command \
|
||||
'$(GOTO_CC) $(CBMC_VERBOSITY) $(COMPILE_FLAGS) $(EXPORT_FILE_LOCAL_SYMBOLS) $(INCLUDES) $(DEFINES) $^ -o $@' \
|
||||
--inputs $^ \
|
||||
--outputs $@ \
|
||||
--stdout-file $(LOGDIR)/proof_sources-log.txt \
|
||||
--pipeline-name "$(PROOF_UID)" \
|
||||
--ci-stage build \
|
||||
--description "$(PROOF_UID): building proof binary"
|
||||
|
||||
# Remove function bodies from project sources
|
||||
$(PROJECT_GOTO)2.goto: $(PROJECT_GOTO)1.goto
|
||||
$(LITANI) add-job \
|
||||
--command \
|
||||
'$(GOTO_INSTRUMENT) $(CBMC_VERBOSITY) $(CBMC_REMOVE_FUNCTION_BODY) $^ $@' \
|
||||
--inputs $^ \
|
||||
--outputs $@ \
|
||||
--stdout-file $(LOGDIR)/remove_function_body-log.txt \
|
||||
--pipeline-name "$(PROOF_UID)" \
|
||||
--ci-stage build \
|
||||
--description "$(PROOF_UID): removing function bodies from project sources"
|
||||
|
||||
# Link project and proof sources into the proof harness
|
||||
$(HARNESS_GOTO)1.goto: $(PROOF_GOTO)1.goto $(PROJECT_GOTO)2.goto
|
||||
$(LITANI) add-job \
|
||||
--command '$(GOTO_CC) $(CBMC_VERBOSITY) --function $(HARNESS_ENTRY) $^ $(LINK_FLAGS) -o $@' \
|
||||
--inputs $^ \
|
||||
--outputs $@ \
|
||||
--stdout-file $(LOGDIR)/link_proof_project-log.txt \
|
||||
--pipeline-name "$(PROOF_UID)" \
|
||||
--ci-stage build \
|
||||
--description "$(PROOF_UID): linking project to proof"
|
||||
|
||||
# Restrict function pointers
|
||||
$(HARNESS_GOTO)2.goto: $(HARNESS_GOTO)1.goto
|
||||
$(LITANI) add-job \
|
||||
--command \
|
||||
'$(GOTO_INSTRUMENT) $(CBMC_VERBOSITY) $(CBMC_RESTRICT_FUNCTION_POINTER) $^ $@' \
|
||||
--inputs $^ \
|
||||
--outputs $@ \
|
||||
--stdout-file $(LOGDIR)/restrict_function_pointer-log.txt \
|
||||
--pipeline-name "$(PROOF_UID)" \
|
||||
--ci-stage build \
|
||||
--description "$(PROOF_UID): restricting function pointers in project sources"
|
||||
|
||||
# Fill static variable with unconstrained values
|
||||
$(HARNESS_GOTO)3.goto: $(HARNESS_GOTO)2.goto
|
||||
$(LITANI) add-job \
|
||||
--command \
|
||||
'$(GOTO_INSTRUMENT) $(CBMC_VERBOSITY) $(NONDET_STATIC) $^ $@' \
|
||||
--inputs $^ \
|
||||
--outputs $@ \
|
||||
--stdout-file $(LOGDIR)/nondet_static-log.txt \
|
||||
--pipeline-name "$(PROOF_UID)" \
|
||||
--ci-stage build \
|
||||
--description "$(PROOF_UID): setting static variables to nondet"
|
||||
|
||||
# Omit unused functions (sharpens coverage calculations)
|
||||
$(HARNESS_GOTO)4.goto: $(HARNESS_GOTO)3.goto
|
||||
$(LITANI) add-job \
|
||||
--command \
|
||||
'$(GOTO_INSTRUMENT) $(CBMC_VERBOSITY) --drop-unused-functions $^ $@' \
|
||||
--inputs $^ \
|
||||
--outputs $@ \
|
||||
--stdout-file $(LOGDIR)/drop_unused_functions-log.txt \
|
||||
--pipeline-name "$(PROOF_UID)" \
|
||||
--ci-stage build \
|
||||
--description "$(PROOF_UID): dropping unused functions"
|
||||
|
||||
# Omit initialization of unused global variables (reduces problem size)
|
||||
$(HARNESS_GOTO)5.goto: $(HARNESS_GOTO)4.goto
|
||||
$(LITANI) add-job \
|
||||
--command \
|
||||
'$(GOTO_INSTRUMENT) $(CBMC_VERBOSITY) --slice-global-inits $^ $@' \
|
||||
--inputs $^ \
|
||||
--outputs $@ \
|
||||
--stdout-file $(LOGDIR)/slice_global_inits-log.txt \
|
||||
--pipeline-name "$(PROOF_UID)" \
|
||||
--ci-stage build \
|
||||
--description "$(PROOF_UID): slicing global initializations"
|
||||
|
||||
# Replace function calls with function contracts
|
||||
# This must be done before enforcing function contracts,
|
||||
# since contract enforcement inlines all function calls.
|
||||
$(HARNESS_GOTO)6.goto: $(HARNESS_GOTO)5.goto
|
||||
$(LITANI) add-job \
|
||||
--command \
|
||||
'$(GOTO_INSTRUMENT) $(CBMC_VERBOSITY) $(CBMC_USE_FUNCTION_CONTRACTS) $^ $@' \
|
||||
--inputs $^ \
|
||||
--outputs $@ \
|
||||
--stdout-file $(LOGDIR)/use_function_contracts-log.txt \
|
||||
--pipeline-name "$(PROOF_UID)" \
|
||||
--ci-stage build \
|
||||
--description "$(PROOF_UID): replacing function calls with function contracts"
|
||||
|
||||
# Unwind loops for loop and function contracts
|
||||
$(HARNESS_GOTO)7.goto: $(HARNESS_GOTO)6.goto
|
||||
$(LITANI) add-job \
|
||||
--command \
|
||||
'$(GOTO_INSTRUMENT) $(CBMC_VERBOSITY) $(CBMC_EARLY_UNWINDSET) $(CBMC_FLAG_UNWINDING_ASSERTIONS) $^ $@' \
|
||||
--inputs $^ \
|
||||
--outputs $@ \
|
||||
--stdout-file $(LOGDIR)/unwind_loops-log.txt \
|
||||
--pipeline-name "$(PROOF_UID)" \
|
||||
--ci-stage build \
|
||||
--description "$(PROOF_UID): unwinding loops"
|
||||
|
||||
# Apply loop contracts
|
||||
$(HARNESS_GOTO)8.goto: $(HARNESS_GOTO)7.goto
|
||||
$(LITANI) add-job \
|
||||
--command \
|
||||
'$(GOTO_INSTRUMENT) $(CBMC_VERBOSITY) $(CBMC_APPLY_LOOP_CONTRACTS) $^ $@' \
|
||||
--inputs $^ \
|
||||
--outputs $@ \
|
||||
--stdout-file $(LOGDIR)/apply_loop_contracts-log.txt \
|
||||
--pipeline-name "$(PROOF_UID)" \
|
||||
--ci-stage build \
|
||||
--description "$(PROOF_UID): applying loop contracts"
|
||||
|
||||
# Check function contracts
|
||||
$(HARNESS_GOTO)9.goto: $(HARNESS_GOTO)8.goto
|
||||
$(LITANI) add-job \
|
||||
--command \
|
||||
'$(GOTO_INSTRUMENT) $(CBMC_VERBOSITY) $(CBMC_CHECK_FUNCTION_CONTRACTS) $^ $@' \
|
||||
--inputs $^ \
|
||||
--outputs $@ \
|
||||
--stdout-file $(LOGDIR)/check_function_contracts-log.txt \
|
||||
--pipeline-name "$(PROOF_UID)" \
|
||||
--ci-stage build \
|
||||
--description "$(PROOF_UID): checking function contracts"
|
||||
|
||||
# Final name for proof harness
|
||||
$(HARNESS_GOTO).goto: $(HARNESS_GOTO)9.goto
|
||||
$(LITANI) add-job \
|
||||
--command 'cp $< $@' \
|
||||
--inputs $^ \
|
||||
--outputs $@ \
|
||||
--pipeline-name "$(PROOF_UID)" \
|
||||
--ci-stage build \
|
||||
--description "$(PROOF_UID): copying final goto-binary"
|
||||
|
||||
################################################################
|
||||
# Targets to run the analysis commands
|
||||
|
||||
$(LOGDIR)/result.txt: $(HARNESS_GOTO).goto
|
||||
$(LITANI) add-job \
|
||||
$(POOL) \
|
||||
--command \
|
||||
'$(CBMC) $(CBMC_VERBOSITY) $(CBMCFLAGS) $(CBMC_FLAG_UNWINDING_ASSERTIONS) $(CHECKFLAGS) --trace $<' \
|
||||
--inputs $^ \
|
||||
--outputs $@ \
|
||||
--ci-stage test \
|
||||
--stdout-file $@ \
|
||||
$(MEMORY_PROFILING) \
|
||||
--ignore-returns 10 \
|
||||
--timeout $(CBMC_TIMEOUT) \
|
||||
--pipeline-name "$(PROOF_UID)" \
|
||||
--tags "stats-group:safety checks" \
|
||||
--stderr-file $(LOGDIR)/result-err-log.txt \
|
||||
--description "$(PROOF_UID): checking safety properties"
|
||||
|
||||
$(LOGDIR)/result.xml: $(HARNESS_GOTO).goto
|
||||
$(LITANI) add-job \
|
||||
$(POOL) \
|
||||
--command \
|
||||
'$(CBMC) $(CBMC_VERBOSITY) $(CBMCFLAGS) $(CBMC_FLAG_UNWINDING_ASSERTIONS) $(CHECKFLAGS) --trace --xml-ui $<' \
|
||||
--inputs $^ \
|
||||
--outputs $@ \
|
||||
--ci-stage test \
|
||||
--stdout-file $@ \
|
||||
$(MEMORY_PROFILING) \
|
||||
--ignore-returns 10 \
|
||||
--timeout $(CBMC_TIMEOUT) \
|
||||
--pipeline-name "$(PROOF_UID)" \
|
||||
--tags "stats-group:safety checks" \
|
||||
--stderr-file $(LOGDIR)/result-err-log.txt \
|
||||
--description "$(PROOF_UID): checking safety properties"
|
||||
|
||||
$(LOGDIR)/property.xml: $(HARNESS_GOTO).goto
|
||||
$(LITANI) add-job \
|
||||
--command \
|
||||
'$(CBMC) $(CBMC_VERBOSITY) $(CBMCFLAGS) $(CBMC_FLAG_UNWINDING_ASSERTIONS) $(CHECKFLAGS) --show-properties --xml-ui $<' \
|
||||
--inputs $^ \
|
||||
--outputs $@ \
|
||||
--ci-stage test \
|
||||
--stdout-file $@ \
|
||||
--ignore-returns 10 \
|
||||
--pipeline-name "$(PROOF_UID)" \
|
||||
--stderr-file $(LOGDIR)/property-err-log.txt \
|
||||
--description "$(PROOF_UID): printing safety properties"
|
||||
|
||||
$(LOGDIR)/coverage.xml: $(HARNESS_GOTO).goto
|
||||
$(LITANI) add-job \
|
||||
$(POOL) \
|
||||
--command \
|
||||
'$(CBMC) $(CBMC_VERBOSITY) $(CBMCFLAGS) $(COVERFLAGS) --cover location --xml-ui $<' \
|
||||
--inputs $^ \
|
||||
--outputs $@ \
|
||||
--ci-stage test \
|
||||
--stdout-file $@ \
|
||||
$(MEMORY_PROFILING) \
|
||||
--ignore-returns 10 \
|
||||
--timeout $(CBMC_TIMEOUT) \
|
||||
--pipeline-name "$(PROOF_UID)" \
|
||||
--tags "stats-group:coverage computation" \
|
||||
--stderr-file $(LOGDIR)/coverage-err-log.txt \
|
||||
--description "$(PROOF_UID): calculating coverage"
|
||||
|
||||
define VIEWER_CMD
|
||||
$(VIEWER) \
|
||||
--result $(LOGDIR)/result.txt \
|
||||
--block $(LOGDIR)/coverage.xml \
|
||||
--property $(LOGDIR)/property.xml \
|
||||
--srcdir $(SRCDIR) \
|
||||
--goto $(HARNESS_GOTO).goto \
|
||||
--htmldir $(PROOFDIR)/html
|
||||
endef
|
||||
export VIEWER_CMD
|
||||
|
||||
$(PROOFDIR)/html: $(LOGDIR)/result.txt $(LOGDIR)/property.xml $(LOGDIR)/coverage.xml
|
||||
$(LITANI) add-job \
|
||||
--command "$$VIEWER_CMD" \
|
||||
--inputs $^ \
|
||||
--outputs $(PROOFDIR)/html \
|
||||
--pipeline-name "$(PROOF_UID)" \
|
||||
--ci-stage report \
|
||||
--stdout-file $(LOGDIR)/viewer-log.txt \
|
||||
--description "$(PROOF_UID): generating report"
|
||||
|
||||
|
||||
# Caution: run make-source before running property and coverage checking
|
||||
# The current make-source script removes the goto binary
|
||||
$(LOGDIR)/source.json:
|
||||
mkdir -p $(dir $@)
|
||||
$(RM) -r $(GOTODIR)
|
||||
$(MAKE_SOURCE) --srcdir $(SRCDIR) --wkdir $(PROOFDIR) > $@
|
||||
$(RM) -r $(GOTODIR)
|
||||
|
||||
define VIEWER2_CMD
|
||||
$(VIEWER2) \
|
||||
--result $(LOGDIR)/result.xml \
|
||||
--coverage $(LOGDIR)/coverage.xml \
|
||||
--property $(LOGDIR)/property.xml \
|
||||
--srcdir $(SRCDIR) \
|
||||
--goto $(HARNESS_GOTO).goto \
|
||||
--reportdir $(PROOFDIR)/report \
|
||||
--config $(PROOFDIR)/cbmc-viewer.json
|
||||
endef
|
||||
export VIEWER2_CMD
|
||||
|
||||
# Omit logs/source.json from report generation until make-sources
|
||||
# works correctly with Makefiles that invoke the compiler with
|
||||
# mutliple source files at once.
|
||||
$(PROOFDIR)/report: $(LOGDIR)/result.xml $(LOGDIR)/property.xml $(LOGDIR)/coverage.xml
|
||||
$(LITANI) add-job \
|
||||
--command "$$VIEWER2_CMD" \
|
||||
--inputs $^ \
|
||||
--outputs $(PROOFDIR)/report \
|
||||
--pipeline-name "$(PROOF_UID)" \
|
||||
--stdout-file $(LOGDIR)/viewer-log.txt \
|
||||
--ci-stage report \
|
||||
--description "$(PROOF_UID): generating report"
|
||||
|
||||
litani-path:
|
||||
@echo $(LITANI)
|
||||
|
||||
# ##############################################################
|
||||
# Phony Rules
|
||||
#
|
||||
# These rules provide a convenient way to run a single proof up to a
|
||||
# certain stage. Users can browse into a proof directory and run
|
||||
# "make -Bj 3 report" to generate a report for just that proof, or
|
||||
# "make goto" to build the goto binary. Under the hood, this runs litani
|
||||
# for just that proof.
|
||||
|
||||
_goto: $(HARNESS_GOTO).goto
|
||||
goto:
|
||||
@ echo Running 'litani init'
|
||||
$(LITANI) init --project $(PROJECT_NAME)
|
||||
@ echo Running 'litani add-job'
|
||||
$(MAKE) -B _goto
|
||||
@ echo Running 'litani build'
|
||||
$(LITANI) run-build
|
||||
|
||||
_result: $(LOGDIR)/result.txt
|
||||
result:
|
||||
@ echo Running 'litani init'
|
||||
$(LITANI) init --project $(PROJECT_NAME)
|
||||
@ echo Running 'litani add-job'
|
||||
$(MAKE) -B _result
|
||||
@ echo Running 'litani build'
|
||||
$(LITANI) run-build
|
||||
|
||||
_property: $(LOGDIR)/property.xml
|
||||
property:
|
||||
@ echo Running 'litani init'
|
||||
$(LITANI) init --project $(PROJECT_NAME)
|
||||
@ echo Running 'litani add-job'
|
||||
$(MAKE) -B _property
|
||||
@ echo Running 'litani build'
|
||||
$(LITANI) run-build
|
||||
|
||||
_coverage: $(LOGDIR)/coverage.xml
|
||||
coverage:
|
||||
@ echo Running 'litani init'
|
||||
$(LITANI) init --project $(PROJECT_NAME)
|
||||
@ echo Running 'litani add-job'
|
||||
$(MAKE) -B _coverage
|
||||
@ echo Running 'litani build'
|
||||
$(LITANI) run-build
|
||||
|
||||
# Choose the invocation of cbmc-viewer depending on which version of
|
||||
# cbmc-viewer is installed. The --version flag is not implemented in
|
||||
# version 1 --- it is an "unrecognized argument" --- but it is
|
||||
# implemented in version 2.
|
||||
_report1: $(PROOFDIR)/html
|
||||
_report2: $(PROOFDIR)/report
|
||||
_report:
|
||||
(cbmc-viewer --version 2>&1 | grep "unrecognized argument" > /dev/null) && \
|
||||
$(MAKE) -B _report1 || $(MAKE) -B _report2
|
||||
|
||||
report report1 report2:
|
||||
@ echo Running 'litani init'
|
||||
$(LITANI) init --project $(PROJECT_NAME)
|
||||
@ echo Running 'litani add-job'
|
||||
$(MAKE) -B _report
|
||||
@ echo Running 'litani build'
|
||||
$(LITANI) run-build
|
||||
|
||||
################################################################
|
||||
# Targets to clean up after ourselves
|
||||
clean:
|
||||
-$(RM) $(DEPENDENT_GOTOS)
|
||||
-$(RM) TAGS*
|
||||
-$(RM) *~ \#*
|
||||
-$(RM) $(REWRITTEN_SOURCES) $(foreach rs,$(REWRITTEN_SOURCES),$(rs).json)
|
||||
|
||||
veryclean: clean
|
||||
-$(RM) -r html report
|
||||
-$(RM) -r $(LOGDIR) $(GOTODIR)
|
||||
|
||||
.PHONY: \
|
||||
_coverage \
|
||||
_goto \
|
||||
_property \
|
||||
_report \
|
||||
_report2 \
|
||||
_result \
|
||||
clean \
|
||||
coverage \
|
||||
goto \
|
||||
litani-path \
|
||||
property \
|
||||
report \
|
||||
report2 \
|
||||
result \
|
||||
setup_dependencies \
|
||||
testdeps \
|
||||
veryclean \
|
||||
#
|
||||
|
||||
################################################################
|
||||
|
||||
# Rule for generating cbmc-batch.yaml, used by the CI at
|
||||
# https://github.com/awslabs/aws-batch-cbmc/
|
||||
|
||||
JOB_OS ?= ubuntu16
|
||||
JOB_MEMORY ?= 32000
|
||||
|
||||
# Proofs that are expected to fail should set EXPECTED to
|
||||
# "FAILED" in their Makefile. Values other than SUCCESSFUL
|
||||
# or FAILED will cause a CI error.
|
||||
EXPECTED ?= SUCCESSFUL
|
||||
|
||||
define yaml_encode_options
|
||||
"$(shell echo $(1) | sed 's/ ,/ /g' | sed 's/ /;/g')"
|
||||
endef
|
||||
|
||||
CI_FLAGS = $(CBMCFLAGS) $(CHECKFLAGS) $(COVERFLAGS)
|
||||
|
||||
cbmc-batch.yaml:
|
||||
@$(RM) $@
|
||||
@echo 'build_memory: $(JOB_MEMORY)' > $@
|
||||
@echo 'cbmcflags: $(strip $(call yaml_encode_options,$(CI_FLAGS)))' >> $@
|
||||
@echo 'coverage_memory: $(JOB_MEMORY)' >> $@
|
||||
@echo 'expected: $(EXPECTED)' >> $@
|
||||
@echo 'goto: $(HARNESS_GOTO).goto' >> $@
|
||||
@echo 'jobos: $(JOB_OS)' >> $@
|
||||
@echo 'property_memory: $(JOB_MEMORY)' >> $@
|
||||
@echo 'report_memory: $(JOB_MEMORY)' >> $@
|
||||
|
||||
.PHONY: cbmc-batch.yaml
|
||||
|
||||
################################################################
|
||||
|
||||
# Run "make echo-proof-uid" to print the proof ID of a proof. This can be
|
||||
# used by scripts to ensure that every proof has an ID, that there are
|
||||
# no duplicates, etc.
|
||||
|
||||
.PHONY: echo-proof-uid
|
||||
echo-proof-uid:
|
||||
@echo $(PROOF_UID)
|
||||
|
||||
.PHONY: echo-project-name
|
||||
echo-project-name:
|
||||
@echo $(PROJECT_NAME)
|
||||
|
||||
################################################################
|
||||
|
||||
# Project-specific targets requiring values defined above
|
||||
sinclude $(PROOF_ROOT)/Makefile-project-targets
|
||||
|
||||
# CI-specific targets to drive cbmc in CI
|
||||
sinclude $(PROOF_ROOT)/Makefile-project-testing
|
||||
|
||||
################################################################
|
||||
@ -0,0 +1,27 @@
|
||||
CBMC proofs
|
||||
===========
|
||||
|
||||
This directory contains the CBMC proofs. Each proof is in its own
|
||||
directory.
|
||||
|
||||
This directory includes four Makefiles.
|
||||
|
||||
One Makefile describes the basic workflow for building and running proofs:
|
||||
|
||||
* Makefile.common:
|
||||
* make: builds the goto binary, does the cbmc property checking
|
||||
and coverage checking, and builds the final report.
|
||||
* make goto: builds the goto binary
|
||||
* make result: does cbmc property checking
|
||||
* make coverage: does cbmc coverage checking
|
||||
* make report: builds the final report
|
||||
|
||||
Three included Makefiles describe project-specific settings and can override
|
||||
definitions in Makefile.common:
|
||||
|
||||
* Makefile-project-defines: definitions like compiler flags
|
||||
required to build the goto binaries, and definitions to override
|
||||
definitions in Makefile.common.
|
||||
* Makefile-project-targets: other make targets needed for the project
|
||||
* Makefile-project-testing: other definitions and targets needed for
|
||||
unit testing or continuous integration.
|
||||
@ -0,0 +1,34 @@
|
||||
#
|
||||
# Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
# this software and associated documentation files (the "Software"), to deal in
|
||||
# the Software without restriction, including without limitation the rights to
|
||||
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
# the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
# subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
|
||||
HARNESS_ENTRY=harness
|
||||
HARNESS_FILE=Shadow_AssembleTopicString_harness
|
||||
PROOF_UID = Shadow_AssembleTopicString
|
||||
|
||||
DEFINES +=
|
||||
INCLUDES +=
|
||||
|
||||
REMOVE_FUNCTION_BODY +=
|
||||
|
||||
PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
|
||||
PROJECT_SOURCES += $(SRCDIR)/source/shadow.c
|
||||
|
||||
include ../Makefile.common
|
||||
@ -0,0 +1,10 @@
|
||||
Shadow_AssembleTopicString proof
|
||||
==============
|
||||
|
||||
This directory contains a memory safety proof for Shadow_AssembleTopicString.
|
||||
|
||||
To run the proof.
|
||||
* Add cbmc, goto-cc, goto-instrument, goto-analyzer, and cbmc-viewer
|
||||
to your path.
|
||||
* Run "make".
|
||||
* Open html/index.html in a web browser.
|
||||
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* AWS IoT Device Shadow v1.3.0
|
||||
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file Shadow_AssembleTopicString_harness.c
|
||||
* @brief Implements the proof harness for Shadow_AssembleTopicString function.
|
||||
*/
|
||||
|
||||
#include "shadow.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
void harness()
|
||||
{
|
||||
char * topicBuffer;
|
||||
uint16_t bufferSize;
|
||||
uint16_t * pOutLength;
|
||||
char * pThingName;
|
||||
uint8_t thingNameLength;
|
||||
char * pShadowName;
|
||||
uint8_t shadowNameLength;
|
||||
uint8_t topicType;
|
||||
|
||||
topicBuffer = malloc( bufferSize );
|
||||
pOutLength = malloc( sizeof( *pOutLength ) );
|
||||
pThingName = malloc( thingNameLength );
|
||||
pShadowName = malloc( shadowNameLength );
|
||||
|
||||
Shadow_AssembleTopicString( topicType,
|
||||
pThingName,
|
||||
thingNameLength,
|
||||
pShadowName,
|
||||
shadowNameLength,
|
||||
topicBuffer,
|
||||
bufferSize,
|
||||
pOutLength );
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
# This file marks this directory as containing a CBMC proof.
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user