[修改] 增加freeRTOS
1. 版本FreeRTOSv202212.01,命名为kernel;
This commit is contained in:
63
kernel/FreeRTOS-Plus/Source/Application-Protocols/coreSNTP/.github/CONTRIBUTING.md
vendored
Normal file
63
kernel/FreeRTOS-Plus/Source/Application-Protocols/coreSNTP/.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/FreeRTOS/backoffAlgorithm/issues), or [recently closed](https://github.com/FreeRTOS/backoffAlgorithm/issues?q=is%3Aissue+is%3Aclosed), issues to make sure somebody else hasn't already
|
||||
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/FreeRTOS/backoffAlgorithm/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.
|
||||
13
kernel/FreeRTOS-Plus/Source/Application-Protocols/coreSNTP/.github/memory_statistics_config.json
vendored
Normal file
13
kernel/FreeRTOS-Plus/Source/Application-Protocols/coreSNTP/.github/memory_statistics_config.json
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"lib_name" : "coreSNTP",
|
||||
"src": [
|
||||
"source/core_sntp_client.c",
|
||||
"source/core_sntp_serializer.c"
|
||||
],
|
||||
"include": [
|
||||
"source/include"
|
||||
],
|
||||
"compiler_flags": [
|
||||
"SNTP_DO_NOT_USE_CUSTOM_CONFIG"
|
||||
]
|
||||
}
|
||||
174
kernel/FreeRTOS-Plus/Source/Application-Protocols/coreSNTP/.github/workflows/ci.yml
vendored
Normal file
174
kernel/FreeRTOS-Plus/Source/Application-Protocols/coreSNTP/.github/workflows/ci.yml
vendored
Normal file
@ -0,0 +1,174 @@
|
||||
name: CI Checks
|
||||
on:
|
||||
push:
|
||||
branches: ["**"]
|
||||
pull_request:
|
||||
branches: [main]
|
||||
workflow_dispatch:
|
||||
jobs:
|
||||
build-check:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Clone This Repo
|
||||
uses: actions/checkout@v2
|
||||
- name: Build Library in Debug mode
|
||||
run: |
|
||||
cmake -S test -B build/ \
|
||||
-G "Unix Makefiles" \
|
||||
-DCMAKE_BUILD_TYPE=Debug \
|
||||
-DCMAKE_C_FLAGS='-O0 -Wall -Wextra -Werror -Wformat -Wformat-security -Warray-bounds'
|
||||
make -C build/ coverity_analysis -j8
|
||||
- name: Build Library in Release mode
|
||||
run: |
|
||||
rm -rf ./build
|
||||
cmake -S test -B build/ -G "Unix Makefiles" \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_C_FLAGS='-Wall -Wextra -Werror -DNDEBUG -Wformat -Wformat-security -Warray-bounds'
|
||||
make -C build/ coverity_analysis -j8
|
||||
build-code-example:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Clone This Repo
|
||||
uses: actions/checkout@v2
|
||||
- name: Build Code Example used in Doxygen
|
||||
run: |
|
||||
cmake -S test -B Build -DBUILD_CODE_EXAMPLE=ON
|
||||
make -C Build code_example_posix -j8
|
||||
unittest-with-sanitizer:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Clone This Repo
|
||||
uses: actions/checkout@v2
|
||||
- name: Build Library and Unit Tests with Sanitizer
|
||||
run: |
|
||||
CFLAGS="-O0 -Wall -Wexta -Werror"
|
||||
CFLAGS+=" -D_FORTIFY_SOURCE=2"
|
||||
CFLAGS+=" -Wformat"
|
||||
CLFAGS+=" -Wformat-security"
|
||||
CFLAGS+=" -Warray-bounds"
|
||||
CFLAGS+=" -fsanitize=address,undefined"
|
||||
CFLAGS+=" -fsanitize=pointer-compare -fsanitize=pointer-subtract"
|
||||
CFLAGS+=" -fsanitize-recover=undefined"
|
||||
CFLAGS+=" -fsanitize-address-use-after-scope"
|
||||
CFLAGS+=" -fsanitize-undefined-trap-on-error"
|
||||
CFLAGS=" -fstack-protector-all -DLOGGING_LEVEL_DEBUG=1"
|
||||
cmake -S test -B build/ \
|
||||
-G "Unix Makefiles" \
|
||||
-DCMAKE_BUILD_TYPE=Debug \
|
||||
-DBUILD_UNIT_TESTS=ON \
|
||||
-DCMAKE_C_FLAGS="${CFLAGS}"
|
||||
make -C build all -j8
|
||||
- name: Run unit tests with sanitizer
|
||||
run: |
|
||||
cd build
|
||||
ctest -E system --output-on-failure
|
||||
cd ..
|
||||
unittest-for-coverage:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Clone This Repo
|
||||
uses: actions/checkout@v2
|
||||
- name: Build
|
||||
run: |
|
||||
sudo apt-get install -y lcov sed
|
||||
# Build with logging enabled.
|
||||
cmake -S test -B build/ \
|
||||
-G "Unix Makefiles" \
|
||||
-DCMAKE_BUILD_TYPE=Debug \
|
||||
-DBUILD_UNIT_TESTS=ON \
|
||||
-DCMAKE_C_FLAGS='--coverage -Wall -Wextra -Werror -DNDEBUG -Wno-error=pedantic -Wno-variadic-macros -DLOGGING_LEVEL_DEBUG=1'
|
||||
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
|
||||
complexity:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Check complexity
|
||||
uses: FreeRTOS/CI-CD-Github-Actions/complexity@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: ./
|
||||
exclude-dirs: .git
|
||||
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
|
||||
link-verifier:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Setup Python for link verifier action
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: '3.8'
|
||||
- name: Check Links
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
uses: FreeRTOS/CI-CD-GitHub-Actions/link-verifier@main
|
||||
with:
|
||||
path: ./
|
||||
exclude-dirs: cbmc
|
||||
include-file-types: .c,.h,.dox
|
||||
doxygen:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Run doxygen build
|
||||
uses: FreeRTOS/CI-CD-Github-Actions/doxygen@main
|
||||
with:
|
||||
path: ./
|
||||
memory_statistics:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install Python3
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: '3.7.x'
|
||||
- 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/Application-Protocols/coreSNTP/.github/workflows/doxygen.yml
vendored
Normal file
11
kernel/FreeRTOS-Plus/Source/Application-Protocols/coreSNTP/.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
|
||||
174
kernel/FreeRTOS-Plus/Source/Application-Protocols/coreSNTP/.github/workflows/release.yml
vendored
Normal file
174
kernel/FreeRTOS-Plus/Source/Application-Protocols/coreSNTP/.github/workflows/release.yml
vendored
Normal file
@ -0,0 +1,174 @@
|
||||
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
|
||||
delete_existing_tag_release:
|
||||
description: 'Is this a re-release of existing tag/release? (Default: false)'
|
||||
default: 'false'
|
||||
required: false
|
||||
jobs:
|
||||
clean-existing-tag-and-release:
|
||||
if: ${{ github.event.inputs.delete_existing_tag_release == 'true' }}
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
VERSION_NUM: ${{ github.event.inputs.version_number }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
- name: Check if tag exists
|
||||
run: |
|
||||
git fetch origin
|
||||
if git tag --list $VERSION_NUM
|
||||
then
|
||||
echo "Deleting existing tag for $VERSION_NUM"
|
||||
git push origin --delete tags/$VERSION_NUM
|
||||
fi
|
||||
- name: Check if release exists
|
||||
run: |
|
||||
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-key 23F3D4EA75716059
|
||||
sudo apt-add-repository https://cli.github.com/packages
|
||||
sudo apt update
|
||||
sudo apt-get install gh
|
||||
if gh release list | grep $VERSION_NUM
|
||||
then
|
||||
echo "Deleting existing release for $VERSION_NUM"
|
||||
gh release delete --yes $VERSION_NUM
|
||||
fi
|
||||
tag-commit:
|
||||
if: ${{ ( github.event.inputs.delete_existing_tag_release == 'true' && success() ) || ( github.event.inputs.delete_existing_tag_release == 'false' && always() ) }}
|
||||
needs: clean-existing-tag-and-release
|
||||
name: Generate SBOM and 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 "coreSNTP Library ${{ 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:
|
||||
if: ${{ ( github.event.inputs.delete_existing_tag_release == 'true' && success() ) || ( github.event.inputs.delete_existing_tag_release == 'false' && always() ) }}
|
||||
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: coreSNTP
|
||||
submodules: recursive
|
||||
- name: Checkout disabled submodules
|
||||
run: |
|
||||
cd coreSNTP
|
||||
git submodule update --init --checkout --recursive
|
||||
- name: Create ZIP
|
||||
run: |
|
||||
zip -r coreSNTP-${{ github.event.inputs.version_number }}.zip coreSNTP -x "*.git*"
|
||||
ls ./
|
||||
- name: Validate created ZIP
|
||||
run: |
|
||||
mkdir zip-check
|
||||
mv coreSNTP-${{ github.event.inputs.version_number }}.zip zip-check
|
||||
cd zip-check
|
||||
unzip coreSNTP-${{ github.event.inputs.version_number }}.zip -d coreSNTP-${{ github.event.inputs.version_number }}
|
||||
ls coreSNTP-${{ github.event.inputs.version_number }}
|
||||
diff -r -x "*.git*" coreSNTP-${{ github.event.inputs.version_number }}/coreSNTP/ ../coreSNTP/
|
||||
cd ../
|
||||
- name: Build
|
||||
run: |
|
||||
cd zip-check/coreSNTP-${{ github.event.inputs.version_number }}/coreSNTP
|
||||
sudo apt-get install -y lcov
|
||||
cmake -S test -B build/ \
|
||||
-G "Unix Makefiles" \
|
||||
-DCMAKE_BUILD_TYPE=Debug \
|
||||
-DBUILD_UNIT_TESTS=ON \
|
||||
-DCMAKE_C_FLAGS='--coverage -Wall -Wextra -DNDEBUG'
|
||||
make -C build/ all
|
||||
- name: Test
|
||||
run: |
|
||||
cd zip-check/coreSNTP-${{ github.event.inputs.version_number }}/coreSNTP/build/
|
||||
ctest -E system --output-on-failure
|
||||
cd ..
|
||||
- name: Create artifact of ZIP
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: coreSNTP-${{ github.event.inputs.version_number }}.zip
|
||||
path: zip-check/coreSNTP-${{ 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
|
||||
if: ${{ ( github.event.inputs.delete_existing_tag_release == 'true' && success() ) || ( github.event.inputs.delete_existing_tag_release == 'false' && always() ) }}
|
||||
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 coreSNTP Library.
|
||||
draft: false
|
||||
prerelease: false
|
||||
- name: Download ZIP artifact
|
||||
uses: actions/download-artifact@v2
|
||||
with:
|
||||
name: coreSNTP-${{ 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: ./coreSNTP-${{ github.event.inputs.version_number }}.zip
|
||||
asset_name: coreSNTP-${{ github.event.inputs.version_number }}.zip
|
||||
asset_content_type: application/zip
|
||||
13
kernel/FreeRTOS-Plus/Source/Application-Protocols/coreSNTP/.gitignore
vendored
Normal file
13
kernel/FreeRTOS-Plus/Source/Application-Protocols/coreSNTP/.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/Application-Protocols/coreSNTP/.gitmodules
vendored
Normal file
4
kernel/FreeRTOS-Plus/Source/Application-Protocols/coreSNTP/.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
|
||||
@ -0,0 +1,30 @@
|
||||
path_classifiers:
|
||||
library:
|
||||
- exclude: /
|
||||
extraction:
|
||||
# Provide build configuration for the C files.
|
||||
cpp:
|
||||
prepare:
|
||||
packages:
|
||||
- g++
|
||||
after_prepare:
|
||||
- export CFLAGS='-Isource/include -Wall -Wextra -Werror -Wformat -Wformat-security -Warray-bounds -DSNTP_DO_NOT_USE_CUSTOM_CONFIG'
|
||||
index:
|
||||
build_command:
|
||||
- g++ $CFLAGS -c source/core_sntp_client.c source/core_sntp_serializer.c
|
||||
|
||||
csharp:
|
||||
after_prepare:
|
||||
- false
|
||||
go:
|
||||
after_prepare:
|
||||
- false
|
||||
java:
|
||||
after_prepare:
|
||||
- false
|
||||
javascript:
|
||||
after_prepare:
|
||||
- false
|
||||
python:
|
||||
after_prepare:
|
||||
- false
|
||||
@ -0,0 +1,21 @@
|
||||
# Changelog for coreSNTP Library
|
||||
|
||||
## v1.2.0 (October 2022)
|
||||
|
||||
### Changes
|
||||
- [#63](https://github.com/FreeRTOS/coreSNTP/pull/63) Move user config includes from header to C files.
|
||||
- [#61](https://github.com/FreeRTOS/coreSNTP/pull/61) MISRA C:2012 compliance update
|
||||
- [#60](https://github.com/FreeRTOS/coreSNTP/pull/60) Update CBMC Starter kit
|
||||
- [#57](https://github.com/FreeRTOS/coreSNTP/pull/57) Loop Invariant Update
|
||||
|
||||
## v1.1.0 (November 2021)
|
||||
|
||||
### Changes
|
||||
- [#52](https://github.com/FreeRTOS/coreSNTP/pull/52) Change license from MIT-0 to MIT.
|
||||
- [#47](https://github.com/FreeRTOS/coreSNTP/pull/47) Update doxygen version used for documentation to 1.9.2.
|
||||
|
||||
## v1.0.0 (July 2021)
|
||||
|
||||
This is the first release of an coreSNTP client library in this repository.
|
||||
|
||||
This library implements an SNTP client for the [SNTPv4 specification](https://tools.ietf.org/html/rfc4330). It is optimized for resource-constrained devices, and does not allocate any memory.
|
||||
@ -0,0 +1,19 @@
|
||||
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.
|
||||
@ -0,0 +1,18 @@
|
||||
# MISRA Compliance
|
||||
|
||||
The coreSNTP 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/FreeRTOS/coreSNTP/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.5 violation; with justification in point 1 ):
|
||||
```
|
||||
grep 'MISRA Ref 11.5.1' . -rI
|
||||
```
|
||||
#### Rule 11.5
|
||||
_Ref 11.5.1_
|
||||
- MISRA C-2012 Rule 11.5 Allow casts from `void *`. The library casts the byte
|
||||
array information received network to a `SntpPacket_t *` for parsing SNTP packet.
|
||||
@ -0,0 +1,100 @@
|
||||
## coreSNTP Library
|
||||
|
||||
This repository contains the coreSNTP library, a client library to use Simple Network Time Protocol (SNTP) to synchronize device clocks with internet time. This library implements the SNTPv4 specification defined in [RFC 4330](https://tools.ietf.org/html/rfc4330).
|
||||
|
||||
An SNTP client can request time from both NTP and SNTP servers. According to the SNTPv4 specification, "_To an NTP or SNTP server, NTP and SNTP clients are indistinguishable; to an NTP or SNTP client, NTP and SNTP servers are indistinguishable._", thereby, allowing SNTP clients to request time from NTP servers.
|
||||
|
||||
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](./docs/doxygen/include/size_table.md).
|
||||
|
||||
**coreSNTP v1.2.0 [source code](https://github.com/FreeRTOS/coreSNTP/tree/v1.2.0/source) is part of the [FreeRTOS 202210.00 LTS](https://github.com/FreeRTOS/FreeRTOS-LTS/tree/202210.00-LTS) release.**
|
||||
|
||||
### Documentation
|
||||
|
||||
The API reference documentation for the coreSNTP library version released in [FreeRTOS/FreeRTOS](https://github.com/FreeRTOS/FreeRTOS) can be viewed from the [freertos.org website](https://freertos.org/coresntp/index.html).
|
||||
|
||||
## Cloning this repository
|
||||
This repo uses [Git Submodules](https://git-scm.com/book/en/v2/Git-Tools-Submodules) to bring in dependent components.
|
||||
|
||||
To clone using HTTPS:
|
||||
```
|
||||
git clone https://github.com/FreeRTOS/coreSNTP.git --recurse-submodules
|
||||
```
|
||||
Using SSH:
|
||||
```
|
||||
git clone git@github.com:FreeRTOS/coreSNTP.git --recurse-submodules
|
||||
```
|
||||
|
||||
If you have downloaded the repo without using the `--recurse-submodules` argument, you need to run:
|
||||
```
|
||||
git submodule update --init --recursive
|
||||
```
|
||||
|
||||
## Building the library
|
||||
|
||||
You can build the coreSNTP source files that are in the [source](source/) directory, and add [source/include](source/include) to your compiler's include path.
|
||||
|
||||
If using CMake, the [coreSntpFilePaths.cmake](coreSntpFilePaths.cmake) file contains the above information of the source files and the header include path from this repository.
|
||||
|
||||
## Reference Example
|
||||
|
||||
A reference example of using the coreSNTP library can be viewed in the `FreeRTOS/FreeRTOS` repository [here](https://github.com/FreeRTOS/FreeRTOS/tree/main/FreeRTOS-Plus/Demo/coreSNTP_Windows_Simulator).
|
||||
The demo application showcases use of the library in order to create an SNTP client for periodic time synchronization of the system clock.
|
||||
|
||||
## Building Unit Tests
|
||||
|
||||
The unit tests for the library use CMock/Unity unit testing framework.
|
||||
|
||||
### Checkout CMock Submodule
|
||||
|
||||
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
|
||||
```
|
||||
|
||||
### Unit Test 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. (Make sure that the **CMock** submodule is cloned as described [above](#checkout-cmock-submodule))
|
||||
|
||||
1. Run the *cmake* command: `cmake -S test -B build -DBUILD_UNIT_TESTS=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 proofs
|
||||
|
||||
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).
|
||||
|
||||
## 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.
|
||||
|
||||
## License
|
||||
|
||||
This library is licensed under the MIT License. See the [LICENSE](LICENSE) file.
|
||||
@ -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,15 @@
|
||||
# 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.
|
||||
|
||||
# coreSNTP library source files.
|
||||
set( CORE_SNTP_SOURCES
|
||||
"${CMAKE_CURRENT_LIST_DIR}/source/core_sntp_serializer.c"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/source/core_sntp_client.c" )
|
||||
|
||||
# coreSNTP library Public Include directories.
|
||||
set( CORE_SNTP_INCLUDE_PUBLIC_DIRS
|
||||
"${CMAKE_CURRENT_LIST_DIR}/source/include" )
|
||||
@ -0,0 +1,272 @@
|
||||
#include <stdlib.h>
|
||||
#include <netdb.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/socket.h>
|
||||
#include <poll.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include "core_sntp_client.h"
|
||||
|
||||
/* @[code_example_sntpdnsresolve] */
|
||||
/* Example POSIX implementation of SntpDnsReolve_t interface. */
|
||||
static bool resolveDns( const SntpServerInfo_t * pServerAddr,
|
||||
uint32_t * pIpV4Addr )
|
||||
{
|
||||
bool status = false;
|
||||
int32_t dnsStatus = -1;
|
||||
struct addrinfo hints;
|
||||
struct addrinfo * pListHead = NULL;
|
||||
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
|
||||
hints.ai_socktype = ( int32_t ) SOCK_STREAM;
|
||||
hints.ai_protocol = IPPROTO_TCP;
|
||||
|
||||
dnsStatus = getaddrinfo( pServerAddr->pServerName, NULL, &hints, &pListHead );
|
||||
|
||||
if( dnsStatus == 0 )
|
||||
{
|
||||
struct sockaddr_in * pAddrInfo = ( struct sockaddr_in * ) pListHead->ai_addr;
|
||||
inet_ntop( pAddrInfo->sin_family,
|
||||
&pAddrInfo->sin_addr,
|
||||
( int8_t * ) pIpV4Addr,
|
||||
INET_ADDRSTRLEN );
|
||||
|
||||
status = true;
|
||||
}
|
||||
|
||||
freeaddrinfo( pListHead );
|
||||
|
||||
return status;
|
||||
}
|
||||
/* @[code_example_sntpdnsresolve] */
|
||||
|
||||
/* @[code_example_networkcontext] */
|
||||
/* Example definition of NetworkContext_t for UDP socket operations. */
|
||||
struct NetworkContext
|
||||
{
|
||||
int udpSocket;
|
||||
};
|
||||
/* @[code_example_networkcontext] */
|
||||
|
||||
/* @[code_example_udptransport_sendto] */
|
||||
/* Example POSIX implementation of the UdpTransportSendTo_t function of UDP transport interface. */
|
||||
static int32_t UdpTransport_Send( NetworkContext_t * pNetworkContext,
|
||||
uint32_t serverAddr,
|
||||
uint16_t serverPort,
|
||||
const void * pBuffer,
|
||||
uint16_t bytesToSend )
|
||||
{
|
||||
int32_t bytesSent = -1, pollStatus = 1;
|
||||
struct pollfd pollFds;
|
||||
|
||||
pollFds.events = POLLOUT | POLLPRI;
|
||||
pollFds.revents = 0;
|
||||
pollFds.fd = pNetworkContext->udpSocket;
|
||||
|
||||
/* Check if there is data to read from the socket. */
|
||||
pollStatus = poll( &pollFds, 1, 0 );
|
||||
|
||||
if( pollStatus > 0 )
|
||||
{
|
||||
struct sockaddr_in addrInfo;
|
||||
addrInfo.sin_family = AF_INET;
|
||||
addrInfo.sin_port = htons( serverPort );
|
||||
addrInfo.sin_addr.s_addr = htonl( serverAddr );
|
||||
|
||||
bytesSent = sendto( pNetworkContext->udpSocket,
|
||||
pBuffer,
|
||||
bytesToSend, 0,
|
||||
( const struct sockaddr * ) &addrInfo,
|
||||
sizeof( addrInfo ) );
|
||||
}
|
||||
else if( pollStatus == 0 )
|
||||
{
|
||||
bytesSent = 0;
|
||||
}
|
||||
|
||||
return bytesSent;
|
||||
}
|
||||
/* @[code_example_udptransport_sendto] */
|
||||
|
||||
/* @[code_example_udptransport_recvfrom] */
|
||||
/* Example POSIX implementation of the UdpTransportRecvFrom_t function of UDP transport interface. */
|
||||
static int32_t UdpTransport_Recv( NetworkContext_t * pNetworkContext,
|
||||
uint32_t serverAddr,
|
||||
uint16_t serverPort,
|
||||
void * pBuffer,
|
||||
uint16_t bytesToRecv )
|
||||
{
|
||||
int32_t bytesReceived = -1, pollStatus = 1;
|
||||
struct pollfd pollFds;
|
||||
|
||||
pollFds.events = POLLIN | POLLPRI;
|
||||
pollFds.revents = 0;
|
||||
pollFds.fd = pNetworkContext->udpSocket;
|
||||
|
||||
/* Check if there is data to read from the socket. */
|
||||
pollStatus = poll( &pollFds, 1, 0 );
|
||||
|
||||
if( pollStatus > 0 )
|
||||
{
|
||||
struct sockaddr_in addrInfo;
|
||||
addrInfo.sin_family = AF_INET;
|
||||
addrInfo.sin_port = htons( serverPort );
|
||||
addrInfo.sin_addr.s_addr = htonl( serverAddr );
|
||||
socklen_t addrLen = sizeof( addrInfo );
|
||||
|
||||
bytesReceived = recvfrom( pNetworkContext->udpSocket, pBuffer,
|
||||
bytesToRecv, 0,
|
||||
( struct sockaddr * ) &addrInfo,
|
||||
&addrLen );
|
||||
}
|
||||
else if( pollStatus == 0 )
|
||||
{
|
||||
bytesReceived = 0;
|
||||
}
|
||||
|
||||
return bytesReceived;
|
||||
}
|
||||
/* @[code_example_udptransport_recvfrom] */
|
||||
|
||||
/* @[code_example_sntpsettime] */
|
||||
/* Example implementation of the SntpSetTime_t interface for POSIX platforms. */
|
||||
static void sntpClient_SetTime( const SntpServerInfo_t * pTimeServer,
|
||||
const SntpTimestamp_t * pServerTime,
|
||||
int64_t clockOffsetMs,
|
||||
SntpLeapSecondInfo_t leapSecondInfo )
|
||||
{
|
||||
/* @[code_example_sntp_converttounixtime] */
|
||||
uint32_t unixSecs;
|
||||
uint32_t unixMs;
|
||||
SntpStatus_t status = Sntp_ConvertToUnixTime( pServerTime, &unixSecs, &unixMs );
|
||||
|
||||
/* @[code_example_sntp_converttounixtime] */
|
||||
assert( status == SntpSuccess );
|
||||
|
||||
struct timespec serverTime =
|
||||
{
|
||||
.tv_sec = unixSecs,
|
||||
.tv_nsec = unixMs * 1000
|
||||
};
|
||||
|
||||
clock_settime( CLOCK_REALTIME, &serverTime );
|
||||
}
|
||||
/* @[code_example_sntpsettime] */
|
||||
|
||||
/* @[code_example_sntpgettime] */
|
||||
/* Example implementation of the SntpGetTime_t interface for POSIX platforms. */
|
||||
static void sntpClient_GetTime( SntpTimestamp_t * pCurrentTime )
|
||||
{
|
||||
struct timespec currTime;
|
||||
|
||||
( void ) clock_gettime( CLOCK_REALTIME, &currTime );
|
||||
|
||||
pCurrentTime->seconds = currTime.tv_sec;
|
||||
pCurrentTime->fractions = ( currTime.tv_sec / 1000 ) * SNTP_FRACTION_VALUE_PER_MICROSECOND;
|
||||
}
|
||||
/* @[code_example_sntpgettime] */
|
||||
|
||||
/* Configuration constants for the example SNTP client. */
|
||||
|
||||
/* Following Time Servers are used for illustrating the usage of library API.
|
||||
* The library can be configured to use ANY time server, whether publicly available
|
||||
* time service like NTP Pool or a privately owned NTP server. */
|
||||
#define TEST_TIME_SERVER_1 "0.pool.ntp.org"
|
||||
#define TEST_TIME_SERVER_2 "1.pool.ntp.org"
|
||||
|
||||
#define SERVER_RESPONSE_TIMEOUT_MS 3000
|
||||
#define TIME_REQUEST_SEND_WAIT_TIME_MS 2000
|
||||
#define TIME_REQUEST_RECEIVE_WAIT_TIME_MS 1000
|
||||
|
||||
#define SYSTEM_CLOCK_FREQUENCY_TOLERANCE_PPM 500
|
||||
#define SYSTEM_CLOCK_DESIRED_ACCURACY_MS 300
|
||||
|
||||
int main( void )
|
||||
{
|
||||
/* @[code_example_sntp_init] */
|
||||
/* Memory for network buffer. */
|
||||
uint8_t networkBuffer[ SNTP_PACKET_BASE_SIZE ];
|
||||
|
||||
/* Create UDP socket. */
|
||||
NetworkContext_t udpContext;
|
||||
|
||||
udpContext.udpSocket = socket( AF_INET, SOCK_DGRAM, 0 );
|
||||
|
||||
/* Setup list of time servers. */
|
||||
SntpServerInfo_t pTimeServers[] =
|
||||
{
|
||||
{
|
||||
.port = SNTP_DEFAULT_SERVER_PORT,
|
||||
.pServerName = TEST_TIME_SERVER_1,
|
||||
.serverNameLen = strlen( TEST_TIME_SERVER_1 )
|
||||
},
|
||||
{
|
||||
.port = SNTP_DEFAULT_SERVER_PORT,
|
||||
.pServerName = TEST_TIME_SERVER_2,
|
||||
.serverNameLen = strlen( TEST_TIME_SERVER_2 )
|
||||
}
|
||||
};
|
||||
|
||||
/* Set the UDP transport interface object. */
|
||||
UdpTransportInterface_t udpTransportIntf;
|
||||
|
||||
udpTransportIntf.pUserContext = &udpContext;
|
||||
udpTransportIntf.sendTo = UdpTransport_Send;
|
||||
udpTransportIntf.recvFrom = UdpTransport_Recv;
|
||||
|
||||
/* Context variable. */
|
||||
SntpContext_t context;
|
||||
|
||||
/* Initialize context. */
|
||||
SntpStatus_t status = Sntp_Init( &context,
|
||||
pTimeServers,
|
||||
sizeof( pTimeServers ) / sizeof( SntpServerInfo_t ),
|
||||
SERVER_RESPONSE_TIMEOUT_MS,
|
||||
networkBuffer,
|
||||
SNTP_PACKET_BASE_SIZE,
|
||||
resolveDns,
|
||||
sntpClient_GetTime,
|
||||
sntpClient_SetTime,
|
||||
&udpTransportIntf,
|
||||
NULL );
|
||||
|
||||
assert( status == SntpSuccess );
|
||||
/* @[code_example_sntp_init] */
|
||||
|
||||
/* Calculate the polling interval period for the SNTP client. */
|
||||
/* @[code_example_sntp_calculatepollinterval] */
|
||||
uint32_t pollingIntervalPeriod;
|
||||
|
||||
status = Sntp_CalculatePollInterval( SYSTEM_CLOCK_FREQUENCY_TOLERANCE_PPM,
|
||||
SYSTEM_CLOCK_DESIRED_ACCURACY_MS,
|
||||
&pollingIntervalPeriod );
|
||||
/* @[code_example_sntp_calculatepollinterval] */
|
||||
assert( status == SntpSuccess );
|
||||
|
||||
/* Loop of SNTP client for period time synchronization. */
|
||||
/* @[code_example_sntp_send_receive] */
|
||||
while( 1 )
|
||||
{
|
||||
status = Sntp_SendTimeRequest( &context,
|
||||
rand() % UINT32_MAX,
|
||||
TIME_REQUEST_SEND_WAIT_TIME_MS );
|
||||
assert( status == SntpSuccess );
|
||||
|
||||
do
|
||||
{
|
||||
status = Sntp_ReceiveTimeResponse( &context, TIME_REQUEST_RECEIVE_WAIT_TIME_MS );
|
||||
} while( status == SntpNoResponseReceived );
|
||||
|
||||
assert( status == SntpSuccess );
|
||||
|
||||
/* Delay of poll interval period before next time synchronization. */
|
||||
sleep( pollingIntervalPeriod );
|
||||
}
|
||||
|
||||
/* @[code_example_sntp_send_receive] */
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
After Width: | Height: | Size: 31 KiB |
@ -0,0 +1,25 @@
|
||||
<table>
|
||||
<tr>
|
||||
<td colspan="3"><center><b>Code Size of coreSNTP (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>core_sntp_client.c</td>
|
||||
<td><center>1.5K</center></td>
|
||||
<td><center>1.2K</center></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>core_sntp_serializer.c</td>
|
||||
<td><center>1.0K</center></td>
|
||||
<td><center>0.8K</center></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Total estimates</b></td>
|
||||
<td><b><center>2.5K</center></b></td>
|
||||
<td><b><center>2.0K</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,157 @@
|
||||
/**
|
||||
@mainpage Overview
|
||||
@anchor sntp
|
||||
@brief <b>coreSNTP Library</b>
|
||||
|
||||
The coreSNTP library provides a client for the <b>Simple Network Time Protocol (SNTP)</b> to allow devices to synchronize their system clocks with internet time. This library implements the SNTPv4 specification defined in [RFC 4330](https://tools.ietf.org/html/rfc4330).
|
||||
<p>
|
||||
An SNTP client can request time from both NTP and SNTP servers. According to the SNTPv4 specification,
|
||||
> <i>To an NTP or SNTP server, NTP and SNTP clients are indistinguishable; to an NTP or SNTP client, NTP and SNTP servers are indistinguishable.</i>
|
||||
<span style="float:right;margin-right:4em"> — <i>[RFC4330](https://tools.ietf.org/html/rfc4330)</i></span><br>
|
||||
|
||||
This library is optimized for resource constrained embedded devices. Features of this library include:
|
||||
- Fully synchronous API, to allow applications to completely manage their concurrency and multi-threading method.
|
||||
- Operations on fixed buffers, so that applications may control their memory allocation strategy.
|
||||
- Flexibility to develop an application with either:
|
||||
- The <b>serializer/de-serializer API</b> which allows complete control over the operations of the SNTP client.
|
||||
OR
|
||||
- The <b>client API</b> that handles operations of communicating over the network, performing authentication, and handling rejected server responses.
|
||||
</p>
|
||||
|
||||
@section sntp_memory_requirements Memory Requirements
|
||||
@brief Memory requirements of the coreSNTP library.
|
||||
|
||||
@include{doc} size_table.md
|
||||
|
||||
@section sntp_design Design
|
||||
@brief <b>coreSNTP Library Design</b>
|
||||
|
||||
<p>
|
||||
|
||||
The coreSNTP library provides 2 API layers:
|
||||
1. <b>Serializer/Deserializer and Utilities</b> - This layer provides functionality for serializing SNTP time requests and deserializing SNTP response packets, as well as some utility functions helpful in setting up an SNTP client in an application.
|
||||
2. <b>Client</b> - This layer provides **managed** functionality for network operations including DNS resolution, sending and receiving SNTP packets over UDP, authenticating servers for security (if enabled), and handling of
|
||||
server rejection of time requests.
|
||||
**Note**: This <b>client API</b> layer performs network and authentication operations through user-defined implementation of interfaces exposed by the library.
|
||||
|
||||
Following is the architecture diagram of the library. It showcases the 2 tiers of the library and the interfaces on which the **Managed Client** layer depends on.
|
||||
|
||||
\image html Dependency_Architecture_Diagram.png
|
||||
|
||||
@section mqtt_interfaces Interfaces and Callbacks
|
||||
|
||||
As visible in the above architecture diagram, the <b>Managed Client</b> API layer depends on the following interfaces that are user-defined for platform-specific operations:
|
||||
- <b>[DNS Resolve Interface](@ref SntpResolveDns_t) </b> - This allows library to resolve DNS addresses of time servers by the application.
|
||||
- <b>[UDP Transport Interface](@ref UdpTransportInterface_t) </b> - This allows library to send and receive SNTP packets over network UDP layer to communicate with SNTP/NTP servers.
|
||||
- <b>[Get Time Interface](@ref SntpGetTime_t)</b> - This allows library to obtain system time for tracking timeouts as well as creating SNTP time requests.
|
||||
- <b>[Set Time Interface](@ref SntpSetTime_t)</b> - This allows library to notify application about updating system time with the latest time provided by server as well as the system clock drift calculated by library.
|
||||
- <b>[Authentication Interface](@ref SntpAuthenticationInterface_t) (Optional)</b> - This allows library to perform mutual authentication in communicating with time servers for security. It is RECOMMENDED that applications enable authentication when communicating with time servers.
|
||||
|
||||
</p>
|
||||
*/
|
||||
|
||||
/**
|
||||
@page core_sntp_config Configurations
|
||||
@brief Configurations of the coreSNTP Library.
|
||||
<!-- @par configpagestyle allows the @section titles to be styled according to style.css -->
|
||||
@par configpagestyle
|
||||
|
||||
All the configurations settings for the coreSNTP library are function-like macros for logging. They can be set with a `\#define` in the config file (`core_sntp_config.h`) or by using a compiler option such as -D in gcc.
|
||||
|
||||
@section SNTP_DO_NOT_USE_CUSTOM_CONFIG
|
||||
@copydoc SNTP_DO_NOT_USE_CUSTOM_CONFIG
|
||||
|
||||
@section sntp_logerror LogError
|
||||
@copydoc LogError
|
||||
|
||||
@section sntp_logwarn LogWarn
|
||||
@copydoc LogWarn
|
||||
|
||||
@section sntp_loginfo LogInfo
|
||||
@copydoc LogInfo
|
||||
|
||||
@section sntp_logdebug LogDebug
|
||||
@copydoc LogDebug
|
||||
*/
|
||||
|
||||
/**
|
||||
@page sntp_functions Functions
|
||||
@brief Primary functions of the SNTP library:<br><br>
|
||||
@subpage sntp_init_function <br>
|
||||
@subpage sntp_sendtimerequest_function <br>
|
||||
@subpage sntp_receivetimeresponse_function <br>
|
||||
@subpage sntp_serializerequest_function <br>
|
||||
@subpage sntp_deserializeresponse_function <br>
|
||||
@subpage sntp_calculatepollinterval_function <br>
|
||||
@subpage sntp_converttounixtime_function <br>
|
||||
|
||||
@page sntp_init_function Sntp_Init
|
||||
@snippet core_sntp_client.h define_sntp_init
|
||||
@copydoc Sntp_Init
|
||||
|
||||
For an example POSIX application of using the coreSNTP library APIs to create an SNTP client, refer to @ref code_example.
|
||||
Below is the part of the code example relevant to the @ref Sntp_Init API.
|
||||
@snippet example_sntp_client_posix.c code_example_sntp_init
|
||||
|
||||
@page sntp_sendtimerequest_function Sntp_SendTimeRequest
|
||||
@copydoc Sntp_SendTimeRequest
|
||||
|
||||
For an example POSIX application of using the coreSNTP library APIs to create an SNTP client, refer to @ref code_example.
|
||||
Below is the part of the code example relevant to the @ref Sntp_ReceiveTimeResponse API.
|
||||
@snippet example_sntp_client_posix.c code_example_sntp_send_receive
|
||||
|
||||
@page sntp_receivetimeresponse_function Sntp_ReceiveTimeResponse
|
||||
@copydoc Sntp_ReceiveTimeResponse
|
||||
|
||||
For an example POSIX application of the coreSNTP library APIs to create an SNTP client, refer to @ref code_example.
|
||||
Below is the part of the example application relevant to the @ref Sntp_ReceiveTimeResponse API.
|
||||
@snippet example_sntp_client_posix.c code_example_sntp_send_receive
|
||||
|
||||
@page sntp_serializerequest_function Sntp_SerializeRequest
|
||||
@copydoc Sntp_SerializeRequest
|
||||
|
||||
@page sntp_deserializeresponse_function Sntp_DeserializeResponse
|
||||
@copydoc Sntp_DeserializeResponse
|
||||
|
||||
@page sntp_calculatepollinterval_function Sntp_CalculatePollInterval
|
||||
@copydoc Sntp_CalculatePollInterval
|
||||
|
||||
Here is a code example of using the API.
|
||||
@snippet example_sntp_client_posix.c code_example_sntp_calculatepollinterval
|
||||
|
||||
@page sntp_converttounixtime_function Sntp_ConvertToUnixTime
|
||||
@copydoc Sntp_ConvertToUnixTime
|
||||
|
||||
Here is a code example of using the API.
|
||||
@snippet example_sntp_client_posix.c code_example_sntp_converttounixtime
|
||||
*/
|
||||
|
||||
/**
|
||||
@page code_example Example application of using coreSNTP APIs
|
||||
@brief Example application of setting up an SNTP client with coreSNTP Library on POSIX platforms.
|
||||
|
||||
This code ONLY showcases how coreSNTP library APIs can be used. For best practices on running an SNTP client,
|
||||
refer to the [FreeRTOS Demo on GitHub](https://github.com/FreeRTOS/FreeRTOS/tree/main/FreeRTOS-Plus/Demo/coreSNTP_Windows_Simulator).<br>
|
||||
@include example_sntp_client_posix.c
|
||||
*/
|
||||
|
||||
<!-- We do not use doxygen ALIASes here because there have been issues in the past versions with "^^" newlines within the alias definition. -->
|
||||
/**
|
||||
@defgroup sntp_enum_types Enumerated Types
|
||||
@brief Enumerated types of the coreSNTP library
|
||||
*/
|
||||
|
||||
/**
|
||||
@defgroup sntp_callback_types Callback Types
|
||||
@brief Callback function pointer types of the coreSNTP library
|
||||
*/
|
||||
|
||||
/**
|
||||
@defgroup sntp_struct_types Struct Types
|
||||
@brief Struct types of the coreSNTP library
|
||||
*/
|
||||
|
||||
/**
|
||||
@defgroup sntp_constants Constants
|
||||
@brief Constants defined in the coreSNTP library
|
||||
*/
|
||||
@ -0,0 +1,118 @@
|
||||
/**
|
||||
@page sntp_porting Porting Guide
|
||||
@brief Guide for porting coreSNTP library to a new platform.
|
||||
|
||||
A port of coreSNTP library for a new platform must provide the following components:
|
||||
1. [Logging Configuration Macros](@ref sntp_porting_config)
|
||||
2. [DNS Resolve Function](@ref sntp_porting_dnsresolve)
|
||||
3. [UDP Transport Interface](@ref sntp_porting_transport)
|
||||
4. [Get Time Function](@ref sntp_porting_gettime)
|
||||
5. [Set Time Function](@ref sntp_porting_settime)
|
||||
6. [Authentication Interface](@ref sntp_porting_authentication)
|
||||
|
||||
@section sntp_porting_config Configuration Macros for Logging
|
||||
@brief Macros for enabling logging that can be defined through the config header `core_sntp_config.h`, or passed in as compiler options.
|
||||
|
||||
@note If a custom configuration header `core_sntp_config.h` is not provided, then the @ref SNTP_DO_NOT_USE_CUSTOM_CONFIG macro must be defined.
|
||||
|
||||
@see [Configurations](@ref core_sntp_config)
|
||||
|
||||
The following logging macros are used throughout the library:
|
||||
- @ref LogError
|
||||
- @ref LogWarn
|
||||
- @ref LogInfo
|
||||
- @ref LogDebug
|
||||
|
||||
Here is an example implementation of logging macros for POSIX platforms
|
||||
@snippet core_sntp_config.h code_example_loggingmacros
|
||||
|
||||
@section sntp_porting_dnsresolve DNS Resolve Function
|
||||
@brief The coreSNTP library requires a DNS Resolve interface that must be implemented to obtain the latest IPv4
|
||||
address information of a time server before sending it a time request.
|
||||
|
||||
@see [DNS Resolve Function](@ref SntpResolveDns_t)
|
||||
|
||||
@note The coreSNTP library will re-resolve the DNS name of a time server on each attempt of requesting time from it.
|
||||
For efficiency of DNS resolution operations, your implementation can utilize DNS caching of resolved domains if
|
||||
your platform supports it.
|
||||
|
||||
@snippet example_sntp_client_posix.c code_example_sntpdnsresolve
|
||||
|
||||
@section sntp_porting_transport UDP Transport Interface
|
||||
@brief The coreSNTP library requires a UDP transport interface that must be implemented
|
||||
in order to send and receive SNTP packets over the network.
|
||||
|
||||
@see [UDP Transport Interface](@ref UdpTransportInterface_t)
|
||||
|
||||
@note For security against unwanted server response packets, it is RECOMMENDED that the UDP socket that is used
|
||||
for implementing the UDP transport interface functions of performing network I/O is kept open ONLY during
|
||||
duration of an SNTP request-response iteration as opposed to keeping it always open across iterations. One way to achieve this is to open a new UDP socket before calling @ref Sntp_SendTimeRequest API and close it after receiving server response (or timeout) with the @ref Sntp_ReceiveTimeResponse API.
|
||||
|
||||
A port must implement functions corresponding to the following functions pointers:
|
||||
- [UDP Transport Send](@ref UdpTransportSendTo_t): A function to send bytes on the network over UDP. It is RECOMMENDED to implement this function as non-blocking so the total block time can be managed by the @ref Sntp_SendTimeRequest API.
|
||||
|
||||
@snippet example_sntp_client_posix.c code_example_udptransport_sendto
|
||||
|
||||
- [UDP Transport Receive](@ref UdpTransportRecvFrom_t): A function to receive bytes from the network over UDP. It is RECOMMENDED to implement this function as non-blocking so the total block time can be managed by the @ref Sntp_ReceiveTimeResponse API.
|
||||
|
||||
@snippet example_sntp_client_posix.c code_example_udptransport_recvfrom
|
||||
|
||||
The above two functions take in a pointer to a @ref NetworkContext_t, the typename of a
|
||||
`struct NetworkContext`. The NetworkContext struct must also be defined by the port, and
|
||||
ought to contain any information necessary to send and receive data with the @ref UdpTransportSendTo_t
|
||||
and @ref UdpTransportRecvFrom_t implementations, respectively:
|
||||
|
||||
@snippet example_sntp_client_posix.c code_example_networkcontext
|
||||
|
||||
@section sntp_porting_gettime Get Time Function
|
||||
@brief The coreSNTP library uses this function to obtain time from system for tracking timeout
|
||||
durations as well as generating SNTP request packet.
|
||||
|
||||
@see @ref SntpGetTime_t
|
||||
|
||||
If the device does not have real-world time information (on device boot-up for example), it is
|
||||
acceptable for this function to provide the system-time that does not match the real-world time, because once a
|
||||
time information is received from a time server, the system time can be corrected to match the real-world time.
|
||||
Refer to the next section on how to correct the system time.
|
||||
|
||||
@snippet example_sntp_client_posix.c code_example_sntpgettime
|
||||
|
||||
@section sntp_porting_settime Set Time Function
|
||||
@brief The coreSNTP library calls this function to notify the device about the latest time received
|
||||
from a time server as well as the clock drift of the system time from the server time.
|
||||
|
||||
@snippet example_sntp_client_posix.c code_example_sntpsettime
|
||||
|
||||
@see @ref SntpSetTime_t
|
||||
|
||||
Platforms should implement this function to perform clock disciple operation on the system clock, that is appropriate for
|
||||
the clock accuracy needs of the application.
|
||||
|
||||
@section sntp_porting_authentication Authentication Interface
|
||||
@brief The coreSNTP library exposes an authentication interface to allow customer-chosen authentication mechanism to be used
|
||||
in SNTP communication with time server(s) for security.
|
||||
|
||||
@note It is RECOMMENDED to enable authentication in communication with your time server(s) of choice to protect against attacks
|
||||
that modify or spoof server responses. The SNTPv4 protocol is flexible to be used with any symmetric-key or asymmetric key
|
||||
cryptographic algorithm depending on the support provided by time servers of your choice. For an example of using AES-128-CMAC
|
||||
as the authentication algorithm, please refer to [coreSNTP demo in FreeRTOS/FreeRTOS repository](https://github.com/FreeRTOS/FreeRTOS/tree/main/FreeRTOS-Plus/Demo/coreSNTP_Windows_Simulator).
|
||||
|
||||
|
||||
@see @ref SntpAuthenticationInterface_t
|
||||
A port that uses authentication to communicate with time server must implement the following function pointers:
|
||||
- [Add client authentication code](@ref SntpGenerateAuthCode_t): A function to generate and append authentication data for client to be validated
|
||||
by the time server. The first @ref SNTP_PACKET_BASE_SIZE bytes in the buffer supplied to this function contains the SNTP request data which can be used to
|
||||
generate the authentication code. The generated authentication code SHOULD be written to the same buffer after the first @ref SNTP_PACKET_BASE_SIZE bytes.
|
||||
This function should also return the number of authentication bytes appended to the library through an output parameter, so that the library knows about the
|
||||
total size of the SNTP packet.
|
||||
|
||||
- [Validate server authentication](@ref SntpValidateServerAuth_t): A function to validate the authentication code in a received SNTP time response from the
|
||||
network to confirm that the expected server is the sender of the response and the timestamps in the packet are trustworthy to
|
||||
update system time. This server authentication data is usually validated by checking that the data can be regenerated by the client from
|
||||
the first #SNTP_PACKET_BASE_SIZE bytes of the received SNTP packet from the network.
|
||||
|
||||
The above two functions take in a pointer to a @ref SntpAuthContext_t, the typename of a `struct SntpAuthContext`. The `SntpAuthContext` struct must
|
||||
also be defined by the port, to store necessary information (like a PKCS#11 label representing credential secret) for performing cryptographic generation
|
||||
and validation operations in the @ref SntpGenerateAuthCode_t and @ref SntpValidateServerAuth_t functions respectively.
|
||||
|
||||
*/
|
||||
@ -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,262 @@
|
||||
actualabsdiff
|
||||
aes
|
||||
alarmservernotsynchronized
|
||||
api
|
||||
apis
|
||||
ascii
|
||||
auth
|
||||
authcodesize
|
||||
authintf
|
||||
aws
|
||||
backoff
|
||||
beforelooptime
|
||||
blocktimems
|
||||
br
|
||||
buffersize
|
||||
bytesorerror
|
||||
bytesremaining
|
||||
bytessent
|
||||
bytestorecv
|
||||
bytestorecv
|
||||
bytestosend
|
||||
bytestosend
|
||||
cbmc
|
||||
clienttime
|
||||
clienttimesec
|
||||
clienttxtime
|
||||
clockfreqtolerance
|
||||
clockoffsetms
|
||||
cmac
|
||||
com
|
||||
config
|
||||
configpagestyle
|
||||
configs
|
||||
const
|
||||
copydoc
|
||||
coresntp
|
||||
coverity
|
||||
css
|
||||
currenttimelist
|
||||
de
|
||||
deamon
|
||||
december
|
||||
defgroup
|
||||
deserialization
|
||||
deserialize
|
||||
deserializer
|
||||
deserializeresponse
|
||||
deserializing
|
||||
desiredaccuracy
|
||||
diff
|
||||
dns
|
||||
doxygen
|
||||
endcode
|
||||
endian
|
||||
endif
|
||||
enum
|
||||
expectedbytestosend
|
||||
expectedinterval
|
||||
expectedtxtime
|
||||
faqs
|
||||
feb
|
||||
firstorderdiff
|
||||
fracs
|
||||
fracsinnetorder
|
||||
fracsinnetorder
|
||||
freertos
|
||||
gcc
|
||||
getsystemtimefunc
|
||||
getsystemtimefunc
|
||||
gettimefunc
|
||||
github
|
||||
gov
|
||||
hsm
|
||||
html
|
||||
htonl
|
||||
https
|
||||
ietf
|
||||
ifdef
|
||||
ifndef
|
||||
inc
|
||||
ingroup
|
||||
inlooptime
|
||||
int
|
||||
iot
|
||||
ip
|
||||
iso
|
||||
jan
|
||||
january
|
||||
june
|
||||
kod
|
||||
lastrequesttime
|
||||
leapsecondinfo
|
||||
leapversionmode
|
||||
logdebug
|
||||
logerror
|
||||
loginfo
|
||||
logwarn
|
||||
lsb
|
||||
mainpage
|
||||
md
|
||||
mdash
|
||||
misra
|
||||
mit
|
||||
mtu
|
||||
networkcontext
|
||||
networkinterfacereceivestub
|
||||
networkinterfacesendstub
|
||||
nist
|
||||
noleapsecond
|
||||
noninfringement
|
||||
ntp
|
||||
ntpv
|
||||
numofservers
|
||||
oldertime
|
||||
org
|
||||
origintime
|
||||
overflown
|
||||
packetsize
|
||||
param
|
||||
pauthcodesize
|
||||
pauthcodesize
|
||||
pauthintf
|
||||
pauthintf
|
||||
pbuffer
|
||||
pclientrxtime
|
||||
pclienttime
|
||||
pclienttxtime
|
||||
pclockoffset
|
||||
pcontext
|
||||
pcurrenttime
|
||||
phasresponsetimedout
|
||||
pkcs
|
||||
pml
|
||||
pnetworkbuffer
|
||||
pnetworkbuffer
|
||||
pnetworkcontext
|
||||
pnetworkcontext
|
||||
pnetworkintf
|
||||
png
|
||||
poldertime
|
||||
positivediff
|
||||
posix
|
||||
ppacket
|
||||
pparsedresponse
|
||||
ppm
|
||||
ppollinterval
|
||||
preadstarttime
|
||||
prequestpacket
|
||||
prequesttime
|
||||
prequesttxtime
|
||||
presponsebuffer
|
||||
presponsecode
|
||||
presponsedata
|
||||
presponsepacket
|
||||
presponserxtime
|
||||
printf
|
||||
pserveraddr
|
||||
pservername
|
||||
pserverrxtime
|
||||
pservertime
|
||||
pservertxtime
|
||||
psntptime
|
||||
ptime
|
||||
ptimeserver
|
||||
ptimeservers
|
||||
ptr
|
||||
ptransportintf
|
||||
pudptransportintf
|
||||
punixtimemicrosecs
|
||||
punixtimesecs
|
||||
pusercontext
|
||||
pwordmemory
|
||||
randomnum
|
||||
randomnumber
|
||||
receivetime
|
||||
recv
|
||||
recvfrom
|
||||
refid
|
||||
reftime
|
||||
rejectedresponsecode
|
||||
resolvednsfunc
|
||||
responsesize
|
||||
responsetimeoutms
|
||||
retryable
|
||||
rfc
|
||||
rootdelay
|
||||
rootdisp
|
||||
rootdispersion
|
||||
rstr
|
||||
rx
|
||||
sdk
|
||||
secsinnetorder
|
||||
secsinnetorder
|
||||
sendsntppacket
|
||||
sendto
|
||||
serializerequest
|
||||
serveraddr
|
||||
servernamelen
|
||||
serverport
|
||||
serverresponsetimeoutms
|
||||
servertime
|
||||
servertimesec
|
||||
servertxtime
|
||||
setsystemtimeatindex
|
||||
setsystemtimefunc
|
||||
signedfirstorderdiffrecv
|
||||
signedfirstorderdiffsend
|
||||
sizeof
|
||||
sntp
|
||||
sntpauthcontext
|
||||
sntpbuffertoosmall
|
||||
sntpclockoffsetoverflow
|
||||
sntperrorautherror
|
||||
sntperrorauthfailure
|
||||
sntperrorbadparameter
|
||||
sntperrorbuffertoosmall
|
||||
sntperrorchangeserver
|
||||
sntperrorcontextnotinitialized
|
||||
sntperrordnsfailure
|
||||
sntperrornetworkfailure
|
||||
sntperrorresponsetimeout
|
||||
sntperrorsendtimeout
|
||||
sntperrortimenotsupported
|
||||
sntpinvalidresponse
|
||||
sntpnoresponse
|
||||
sntpnoresponsereceived
|
||||
sntppacketsize
|
||||
sntprejectedresponse
|
||||
sntprejectedresponsechangeserver
|
||||
sntprejectedresponseothercode
|
||||
sntprejectedresponseretrywithbackoff
|
||||
sntpservernotauthenticated
|
||||
sntpsuccess
|
||||
sntptimestamp
|
||||
sntpv
|
||||
sntpzeropollinterval
|
||||
spdx
|
||||
startingpos
|
||||
startingpos
|
||||
struct
|
||||
sublicense
|
||||
testbuffer
|
||||
testclockoffsetcalculation
|
||||
timebeforeloop
|
||||
timediffsec
|
||||
timeoutms
|
||||
timeserver
|
||||
transmittime
|
||||
trng
|
||||
tx
|
||||
typename
|
||||
udp
|
||||
udprecvretcodes
|
||||
udpsendretcodes
|
||||
uint
|
||||
unix
|
||||
utc
|
||||
validateserverauth
|
||||
wordmemory
|
||||
wordval
|
||||
www
|
||||
xffff
|
||||
@ -0,0 +1,5 @@
|
||||
name : "coreSNTP"
|
||||
version: "v1.2.0"
|
||||
description: |
|
||||
"SNTP client library to allow embedded devices to synchronize time with time servers.\n"
|
||||
license: "MIT"
|
||||
@ -0,0 +1,36 @@
|
||||
SPDXVersion: SPDX-2.2
|
||||
DataLicense: CC0-1.0
|
||||
SPDXID: SPDXRef-DOCUMENT
|
||||
DocumentName: coreSNTP
|
||||
DocumentNamespace: https://github.com/FreeRTOS/coreSNTP/blob/v1.2.0/sbom.spdx
|
||||
Creator: Amazon Web Services
|
||||
Created: 2022-10-14T20:34:14Z
|
||||
CreatorComment: NOASSERTION
|
||||
DocumentComment: NOASSERTION
|
||||
|
||||
PackageName: coreSNTP
|
||||
SPDXID: SPDXRef-Package-coreSNTP
|
||||
PackageVersion: v1.2.0
|
||||
PackageDownloadLocation: https://github.com/FreeRTOS/coreSNTP/tree/v1.2.0
|
||||
PackageLicenseConcluded: MIT
|
||||
FilesAnalyzed: True
|
||||
PackageVerificationCode: ab422c2e6c223d05b532b98e28c94f6c49ccaba0
|
||||
PackageCopyrightText: NOASSERTION
|
||||
PackageSummary: NOASSERTION
|
||||
PackageDescription: "SNTP client library to allow embedded devices to synchronize time with time servers.\n"
|
||||
|
||||
|
||||
FileName: ./core_sntp_serializer.c
|
||||
SPDXID: SPDXRef-File-core_sntp_serializer.c
|
||||
FileChecksum: SHA1: 7106d519417e32fdb3a26a5e03410e855e2f5ce0
|
||||
LicenseConcluded: MIT
|
||||
FileCopyrightText: NOASSERTION
|
||||
FileComment: NOASSERTION
|
||||
|
||||
FileName: ./core_sntp_client.c
|
||||
SPDXID: SPDXRef-File-core_sntp_client.c
|
||||
FileChecksum: SHA1: 9f1b5c57812deb30376ab76e11d09e81ce09c2fe
|
||||
LicenseConcluded: MIT
|
||||
FileCopyrightText: NOASSERTION
|
||||
FileComment: NOASSERTION
|
||||
|
||||
@ -0,0 +1,959 @@
|
||||
/*
|
||||
* coreSNTP v1.2.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 core_sntp_client.c
|
||||
* @brief Implementation of the client API of the coreSNTP library.
|
||||
*/
|
||||
|
||||
/* Standard includes. */
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
/* SNTP client library API include. */
|
||||
#include "core_sntp_client.h"
|
||||
|
||||
#include "core_sntp_config_defaults.h"
|
||||
|
||||
/**
|
||||
* @brief Utility to convert fractions part of SNTP timestamp to milliseconds.
|
||||
*
|
||||
* @param[in] fractions The fractions value in an SNTP timestamp.
|
||||
*/
|
||||
#define FRACTIONS_TO_MS( fractions ) \
|
||||
( fractions / ( SNTP_FRACTION_VALUE_PER_MICROSECOND * 1000U ) )
|
||||
|
||||
SntpStatus_t Sntp_Init( SntpContext_t * pContext,
|
||||
const SntpServerInfo_t * pTimeServers,
|
||||
size_t numOfServers,
|
||||
uint32_t serverResponseTimeoutMs,
|
||||
uint8_t * pNetworkBuffer,
|
||||
size_t bufferSize,
|
||||
SntpResolveDns_t resolveDnsFunc,
|
||||
SntpGetTime_t getSystemTimeFunc,
|
||||
SntpSetTime_t setSystemTimeFunc,
|
||||
const UdpTransportInterface_t * pTransportIntf,
|
||||
const SntpAuthenticationInterface_t * pAuthIntf )
|
||||
{
|
||||
SntpStatus_t status = SntpSuccess;
|
||||
|
||||
/* Validate pointer parameters are not NULL. */
|
||||
if( ( pContext == NULL ) || ( pTimeServers == NULL ) ||
|
||||
( pNetworkBuffer == NULL ) || ( resolveDnsFunc == NULL ) ||
|
||||
( getSystemTimeFunc == NULL ) || ( setSystemTimeFunc == NULL ) ||
|
||||
( pTransportIntf == NULL ) )
|
||||
{
|
||||
LogError( ( "Invalid parameter: Pointer parameters (except pAuthIntf) cannot be NULL" ) );
|
||||
|
||||
status = SntpErrorBadParameter;
|
||||
}
|
||||
/* Validate the length of the servers list.*/
|
||||
else if( numOfServers == 0U )
|
||||
{
|
||||
LogError( ( "Invalid parameter: Size of server list cannot be zero" ) );
|
||||
status = SntpErrorBadParameter;
|
||||
}
|
||||
/* Validate that the UDP transport interface functions are valid. */
|
||||
else if( ( pTransportIntf->recvFrom == NULL ) || ( pTransportIntf->sendTo == NULL ) )
|
||||
{
|
||||
LogError( ( "Invalid parameter: Function members of UDP transport interface cannot be NULL" ) );
|
||||
status = SntpErrorBadParameter;
|
||||
}
|
||||
|
||||
/* If an authentication interface is provided, validate that its function pointer
|
||||
* members are valid. */
|
||||
else if( ( pAuthIntf != NULL ) &&
|
||||
( ( pAuthIntf->generateClientAuth == NULL ) ||
|
||||
( pAuthIntf->validateServerAuth == NULL ) ) )
|
||||
{
|
||||
LogError( ( "Invalid parameter: Function members of authentication interface cannot be NULL" ) );
|
||||
status = SntpErrorBadParameter;
|
||||
}
|
||||
else if( bufferSize < SNTP_PACKET_BASE_SIZE )
|
||||
{
|
||||
LogError( ( "Cannot initialize context: Passed network buffer size is less than %u bytes: "
|
||||
"bufferSize=%lu", SNTP_PACKET_BASE_SIZE, ( unsigned long ) bufferSize ) );
|
||||
status = SntpErrorBufferTooSmall;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Reset the context memory to zero. */
|
||||
( void ) memset( pContext, 0, sizeof( SntpContext_t ) );
|
||||
|
||||
/* Set the members of the context with passed parameters. */
|
||||
pContext->pTimeServers = pTimeServers;
|
||||
pContext->numOfServers = numOfServers;
|
||||
|
||||
pContext->responseTimeoutMs = serverResponseTimeoutMs;
|
||||
|
||||
pContext->pNetworkBuffer = pNetworkBuffer;
|
||||
pContext->bufferSize = bufferSize;
|
||||
|
||||
pContext->resolveDnsFunc = resolveDnsFunc;
|
||||
pContext->getTimeFunc = getSystemTimeFunc;
|
||||
pContext->setTimeFunc = setSystemTimeFunc;
|
||||
|
||||
/* Copy contents of UDP transport interface to context. */
|
||||
( void ) memcpy( &pContext->networkIntf, pTransportIntf, sizeof( UdpTransportInterface_t ) );
|
||||
|
||||
/* If authentication interface has been passed, copy its contents to the context. */
|
||||
if( pAuthIntf != NULL )
|
||||
{
|
||||
( void ) memcpy( &pContext->authIntf, pAuthIntf, sizeof( SntpAuthenticationInterface_t ) );
|
||||
}
|
||||
|
||||
/* Initialize the packet size member to the standard minimum SNTP packet size.*/
|
||||
pContext->sntpPacketSize = SNTP_PACKET_BASE_SIZE;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Utility to calculate the difference in milliseconds between 2
|
||||
* SNTP timestamps.
|
||||
*
|
||||
* @param[in] pCurrentTime The more recent timestamp.
|
||||
* @param[in] pOlderTime The older timestamp.
|
||||
*
|
||||
* @note This functions supports the edge case of SNTP timestamp overflow
|
||||
* when @p pCurrentTime represents time in NTP era 1 (i.e. time since 7 Feb 2036)
|
||||
* and the @p OlderTime represents time in NTP era 0 (i.e. time since 1st Jan 1900).
|
||||
*
|
||||
* @return Returns the calculated time duration between the two timestamps.
|
||||
*
|
||||
* @note This function returns the calculated time difference as unsigned 64 bit
|
||||
* to avoid integer overflow when converting time difference between the seconds part
|
||||
* of the timestamps, which are 32 bits wide, to milliseconds.
|
||||
*/
|
||||
static uint64_t calculateElapsedTimeMs( const SntpTimestamp_t * pCurrentTime,
|
||||
const SntpTimestamp_t * pOlderTime )
|
||||
{
|
||||
uint64_t timeDiffMs = 0UL;
|
||||
uint32_t timeDiffSec = 0U;
|
||||
|
||||
assert( pCurrentTime != NULL );
|
||||
assert( pOlderTime != NULL );
|
||||
|
||||
/* Detect if SNTP time has overflown between the 2 timestamps. */
|
||||
if( pCurrentTime->seconds < pOlderTime->seconds )
|
||||
{
|
||||
/* Handle the SNTP time overflow by calculating the actual time
|
||||
* duration from pOlderTime, that exists in NTP era 0, to pCurrentTime,
|
||||
* that exists in NTP era 1. */
|
||||
timeDiffSec = ( UINT32_MAX - pOlderTime->seconds ) + /* Time in NTP era 0. */
|
||||
1U + /* Epoch time in NTP era 1, i.e. 7 Feb 2036 6h:14m:28s. */
|
||||
pCurrentTime->seconds; /* Time in NTP era 1. */
|
||||
|
||||
timeDiffMs = ( uint64_t ) timeDiffSec * 1000UL;
|
||||
}
|
||||
else
|
||||
{
|
||||
timeDiffSec = ( pCurrentTime->seconds - pOlderTime->seconds );
|
||||
timeDiffMs = ( uint64_t ) timeDiffSec * 1000UL;
|
||||
}
|
||||
|
||||
if( pCurrentTime->fractions > pOlderTime->fractions )
|
||||
{
|
||||
timeDiffMs += ( ( uint64_t ) pCurrentTime->fractions - ( uint64_t ) pOlderTime->fractions ) /
|
||||
( SNTP_FRACTION_VALUE_PER_MICROSECOND * 1000UL );
|
||||
}
|
||||
else
|
||||
{
|
||||
timeDiffMs -= ( ( uint64_t ) pOlderTime->fractions - ( uint64_t ) pCurrentTime->fractions ) /
|
||||
( SNTP_FRACTION_VALUE_PER_MICROSECOND * 1000UL );
|
||||
}
|
||||
|
||||
return timeDiffMs;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Validates the content of the SNTP context passed to the APIs to
|
||||
* check whether it represents an initialized context.
|
||||
*
|
||||
* @param[in] pContext The SNTP context to validate.
|
||||
*
|
||||
* @return Returns one of the following:
|
||||
* - #SntpSuccess if the context is verified to be initialized.
|
||||
* - #SntpErrorBadParameter if the context is NULL.
|
||||
* - #SntpErrorContextNotInitialized if the context is validated to be initialized.
|
||||
*/
|
||||
static SntpStatus_t validateContext( const SntpContext_t * pContext )
|
||||
{
|
||||
SntpStatus_t status = SntpSuccess;
|
||||
|
||||
/* Check if the context parameter is invalid. */
|
||||
if( pContext == NULL )
|
||||
{
|
||||
status = SntpErrorBadParameter;
|
||||
LogError( ( "Invalid context parameter: Context is NULL" ) );
|
||||
}
|
||||
|
||||
/* Validate pointer parameters are not NULL. */
|
||||
else if( ( pContext->pTimeServers == NULL ) || ( pContext->pNetworkBuffer == NULL ) ||
|
||||
( pContext->resolveDnsFunc == NULL ) ||
|
||||
( pContext->getTimeFunc == NULL ) || ( pContext->setTimeFunc == NULL ) )
|
||||
{
|
||||
status = SntpErrorContextNotInitialized;
|
||||
}
|
||||
|
||||
/* Validate the size of the configured servers list, network buffer size and the state
|
||||
* variable for the SNTP packet size.*/
|
||||
else if( ( pContext->numOfServers == 0U ) || ( pContext->bufferSize < SNTP_PACKET_BASE_SIZE ) ||
|
||||
( pContext->sntpPacketSize < SNTP_PACKET_BASE_SIZE ) )
|
||||
{
|
||||
status = SntpErrorContextNotInitialized;
|
||||
}
|
||||
/* Validate that the UDP transport interface functions are valid. */
|
||||
else if( ( pContext->networkIntf.recvFrom == NULL ) || ( pContext->networkIntf.sendTo == NULL ) )
|
||||
{
|
||||
status = SntpErrorContextNotInitialized;
|
||||
}
|
||||
|
||||
/* If an authentication interface is provided, validate that both its function pointer
|
||||
* members are valid. */
|
||||
else if( ( ( pContext->authIntf.generateClientAuth != NULL ) && ( pContext->authIntf.validateServerAuth == NULL ) ) ||
|
||||
( ( pContext->authIntf.generateClientAuth == NULL ) && ( pContext->authIntf.validateServerAuth != NULL ) ) )
|
||||
{
|
||||
status = SntpErrorContextNotInitialized;
|
||||
}
|
||||
else
|
||||
{
|
||||
status = SntpSuccess;
|
||||
}
|
||||
|
||||
if( status == SntpErrorContextNotInitialized )
|
||||
{
|
||||
LogError( ( "Invalid context parameter: Context is not initialized with Sntp_Init" ) );
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sends SNTP request packet to the passed server over the network
|
||||
* using transport interface's send function.
|
||||
*
|
||||
* @note For the case of zero byte transmissions over the network, this function
|
||||
* repeatedly retries the send operation by calling the transport interface
|
||||
* until either:
|
||||
* 1. The requested number of bytes @p packetSize have been sent.
|
||||
* OR
|
||||
* 2. There is an error in sending data over the network.
|
||||
*
|
||||
* @note This function treats partial data transmissions as error as UDP
|
||||
* transport protocol does not support partial sends.
|
||||
*
|
||||
* @param[in] pNetworkIntf The UDP transport interface to use for
|
||||
* sending data over the network.
|
||||
* @param[in] timeServer The IPv4 address of the server to send the
|
||||
* SNTP request packet to.
|
||||
* @param[in] serverPort The port of the @p timeServer to send the
|
||||
* request to.
|
||||
* @param[in] getTimeFunc The function to query system time for
|
||||
* tracking retry time period of no data transmissions.
|
||||
* @param[in] pPacket The buffer containing the SNTP packet data
|
||||
* to send over the network.
|
||||
* @param[in] packetSize The size of data in the SNTP request packet.
|
||||
* @param[in] timeoutMs The timeout period for retry attempts of sending
|
||||
* SNTP request packet over the network.
|
||||
*
|
||||
* @return Returns #SntpSuccess on successful transmission of the entire
|
||||
* SNTP request packet over the network; #SntpErrorNetworkFailure
|
||||
* to indicate failure from transport interface; #SntpErrorSendTimeout if
|
||||
* time request could not be sent over the network within the @p timeoutMs
|
||||
* duration.
|
||||
*/
|
||||
static SntpStatus_t sendSntpPacket( const UdpTransportInterface_t * pNetworkIntf,
|
||||
uint32_t timeServer,
|
||||
uint16_t serverPort,
|
||||
SntpGetTime_t getTimeFunc,
|
||||
const uint8_t * pPacket,
|
||||
uint16_t packetSize,
|
||||
uint32_t timeoutMs )
|
||||
{
|
||||
const uint8_t * pIndex = pPacket;
|
||||
int32_t bytesSent = 0;
|
||||
SntpTimestamp_t lastSendTime;
|
||||
bool shouldRetry = false;
|
||||
SntpStatus_t status = SntpErrorSendTimeout;
|
||||
|
||||
assert( pPacket != NULL );
|
||||
assert( getTimeFunc != NULL );
|
||||
assert( pNetworkIntf != NULL );
|
||||
assert( packetSize >= SNTP_PACKET_BASE_SIZE );
|
||||
|
||||
/* Record the starting time of attempting to send data. This begins the retry timeout
|
||||
* window. */
|
||||
getTimeFunc( &lastSendTime );
|
||||
|
||||
/* Loop until the entire packet is sent. */
|
||||
do
|
||||
{
|
||||
/* Reset flag for retrying send operation for the iteration. If request packet cannot be
|
||||
* sent and timeout has not occurred, the flag will be set later for the next iteration. */
|
||||
shouldRetry = false;
|
||||
|
||||
bytesSent = pNetworkIntf->sendTo( pNetworkIntf->pUserContext,
|
||||
timeServer,
|
||||
serverPort,
|
||||
pIndex,
|
||||
packetSize );
|
||||
|
||||
if( bytesSent < 0 )
|
||||
{
|
||||
LogError( ( "Unable to send request packet: Transport send failed. "
|
||||
"ErrorCode=%ld.", ( long int ) bytesSent ) );
|
||||
status = SntpErrorNetworkFailure;
|
||||
}
|
||||
else if( bytesSent == 0 )
|
||||
{
|
||||
/* No bytes were sent over the network. Retry send if we have not timed out. */
|
||||
|
||||
SntpTimestamp_t currentTime;
|
||||
uint64_t elapsedTimeMs;
|
||||
|
||||
getTimeFunc( ¤tTime );
|
||||
|
||||
/* Calculate time elapsed since last data was sent over network. */
|
||||
elapsedTimeMs = calculateElapsedTimeMs( ¤tTime, &lastSendTime );
|
||||
|
||||
/* Check for timeout if we have been waiting to send any data over the network. */
|
||||
if( elapsedTimeMs >= timeoutMs )
|
||||
{
|
||||
LogError( ( "Unable to send request packet: Timed out retrying send: "
|
||||
"SendRetryTimeout=%ums", timeoutMs ) );
|
||||
status = SntpErrorSendTimeout;
|
||||
}
|
||||
else
|
||||
{
|
||||
shouldRetry = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* Partial sends are not supported by UDP, which only supports sending the entire datagram as a whole.
|
||||
* Thus, if the transport send function returns status representing partial send, it will be treated as failure. */
|
||||
else if( bytesSent != ( int32_t ) packetSize )
|
||||
{
|
||||
LogError( ( "Unable to send request packet: Transport send returned unexpected bytes sent. "
|
||||
"ReturnCode=%ld, ExpectedCode=%u", ( long int ) bytesSent, packetSize ) );
|
||||
|
||||
status = SntpErrorNetworkFailure;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The time request packet has been sent over the network. */
|
||||
status = SntpSuccess;
|
||||
}
|
||||
} while( shouldRetry == true );
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Adds client authentication data to SNTP request packet by calling the
|
||||
* authentication interface.
|
||||
*
|
||||
* @param[in] pContext The SNTP context.
|
||||
*
|
||||
* @return Returns one of the following:
|
||||
* - #SntpSuccess if the interface function successfully appends client
|
||||
* authentication data.
|
||||
* - #SntpErrorAuthFailure when the interface returns either an error OR an
|
||||
* incorrect size of the client authentication data.
|
||||
*/
|
||||
static SntpStatus_t addClientAuthentication( SntpContext_t * pContext )
|
||||
{
|
||||
SntpStatus_t status = SntpSuccess;
|
||||
uint16_t authDataSize = 0U;
|
||||
|
||||
assert( pContext != NULL );
|
||||
assert( pContext->authIntf.generateClientAuth != NULL );
|
||||
assert( pContext->currentServerIndex <= pContext->numOfServers );
|
||||
|
||||
status = pContext->authIntf.generateClientAuth( pContext->authIntf.pAuthContext,
|
||||
&pContext->pTimeServers[ pContext->currentServerIndex ],
|
||||
pContext->pNetworkBuffer,
|
||||
pContext->bufferSize,
|
||||
&authDataSize );
|
||||
|
||||
if( status != SntpSuccess )
|
||||
{
|
||||
LogError( ( "Unable to send time request: Client authentication function failed: "
|
||||
"RetStatus=%s", Sntp_StatusToStr( status ) ) );
|
||||
}
|
||||
|
||||
/* Sanity check that the returned authentication data size fits in the remaining space
|
||||
* of the request buffer besides the first #SNTP_PACKET_BASE_SIZE bytes. */
|
||||
else if( authDataSize > ( pContext->bufferSize - SNTP_PACKET_BASE_SIZE ) )
|
||||
{
|
||||
LogError( ( "Unable to send time request: Invalid authentication code size: "
|
||||
"AuthCodeSize=%lu, NetworkBufferSize=%lu",
|
||||
( unsigned long ) authDataSize, ( unsigned long ) pContext->bufferSize ) );
|
||||
status = SntpErrorAuthFailure;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* With the authentication data added. calculate total SNTP request packet size. The same
|
||||
* size would be expected in the SNTP response from server. */
|
||||
pContext->sntpPacketSize = SNTP_PACKET_BASE_SIZE + authDataSize;
|
||||
|
||||
LogInfo( ( "Appended client authentication code to SNTP request packet:"
|
||||
" AuthCodeSize=%lu, TotalPacketSize=%lu",
|
||||
( unsigned long ) authDataSize,
|
||||
( unsigned long ) pContext->sntpPacketSize ) );
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
SntpStatus_t Sntp_SendTimeRequest( SntpContext_t * pContext,
|
||||
uint32_t randomNumber,
|
||||
uint32_t blockTimeMs )
|
||||
{
|
||||
SntpStatus_t status = SntpSuccess;
|
||||
|
||||
/* Validate the context parameter. */
|
||||
status = validateContext( pContext );
|
||||
|
||||
if( status == SntpSuccess )
|
||||
{
|
||||
const SntpServerInfo_t * pServer = NULL;
|
||||
|
||||
/* Set local variable for the currently indexed server to use for time
|
||||
* query. */
|
||||
pServer = &pContext->pTimeServers[ pContext->currentServerIndex ];
|
||||
|
||||
LogDebug( ( "Using server %.*s for time query", ( int ) pServer->serverNameLen, pServer->pServerName ) );
|
||||
|
||||
/* Perform DNS resolution of the currently indexed server in the list
|
||||
* of configured servers. */
|
||||
if( pContext->resolveDnsFunc( pServer, &pContext->currentServerAddr ) == false )
|
||||
{
|
||||
LogError( ( "Unable to send time request: DNS resolution failed: Server=%.*s",
|
||||
( int ) pServer->serverNameLen, pServer->pServerName ) );
|
||||
|
||||
status = SntpErrorDnsFailure;
|
||||
}
|
||||
else
|
||||
{
|
||||
LogDebug( ( "Server DNS resolved: Address=0x%08X", pContext->currentServerAddr ) );
|
||||
}
|
||||
|
||||
if( status == SntpSuccess )
|
||||
{
|
||||
/* Obtain current system time to generate SNTP request packet. */
|
||||
pContext->getTimeFunc( &pContext->lastRequestTime );
|
||||
|
||||
LogDebug( ( "Obtained current time for SNTP request packet: Time=%us %ums",
|
||||
pContext->lastRequestTime.seconds, FRACTIONS_TO_MS( pContext->lastRequestTime.fractions ) ) );
|
||||
|
||||
/* Generate SNTP request packet with the current system time and
|
||||
* the passed random number. */
|
||||
status = Sntp_SerializeRequest( &pContext->lastRequestTime,
|
||||
randomNumber,
|
||||
pContext->pNetworkBuffer,
|
||||
pContext->bufferSize );
|
||||
|
||||
/* The serialization should be successful as all parameter validation has
|
||||
* been done before. */
|
||||
assert( status == SntpSuccess );
|
||||
}
|
||||
|
||||
/* If an authentication interface has been configured, call the function to append client
|
||||
* authentication data to SNTP request buffer. */
|
||||
if( ( status == SntpSuccess ) && ( pContext->authIntf.generateClientAuth != NULL ) )
|
||||
{
|
||||
status = addClientAuthentication( pContext );
|
||||
}
|
||||
|
||||
if( status == SntpSuccess )
|
||||
{
|
||||
LogInfo( ( "Sending serialized SNTP request packet to the server: Addr=%u, Port=%u",
|
||||
pContext->currentServerAddr,
|
||||
pContext->pTimeServers[ pContext->currentServerIndex ].port ) );
|
||||
|
||||
/* Send the request packet over the network to the time server. */
|
||||
status = sendSntpPacket( &pContext->networkIntf,
|
||||
pContext->currentServerAddr,
|
||||
pContext->pTimeServers[ pContext->currentServerIndex ].port,
|
||||
pContext->getTimeFunc,
|
||||
pContext->pNetworkBuffer,
|
||||
pContext->sntpPacketSize,
|
||||
blockTimeMs );
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Utility to update the SNTP context to rotate the server of use for subsequent
|
||||
* time request(s).
|
||||
*
|
||||
* @note If there is no next server remaining, after the current server's index, in the list of
|
||||
* configured servers, the server rotation algorithm wraps around to the first server in the list.
|
||||
* The wrap around is done so that an application using the library for a long-running SNTP client
|
||||
* functionality (like a daemon task) does not become dysfunctional after all configured time
|
||||
* servers have been used up. Time synchronization can be a critical functionality for a system
|
||||
* and the wrap around logic ensures that the SNTP client continues to function in such a case.
|
||||
*
|
||||
* @note Server rotation is performed ONLY when either of:
|
||||
* - The current server responds with a rejection for time request.
|
||||
* OR
|
||||
* - The current server response wait has timed out.
|
||||
*/
|
||||
static void rotateServerForNextTimeQuery( SntpContext_t * pContext )
|
||||
{
|
||||
size_t nextServerIndex = ( pContext->currentServerIndex + 1U ) % pContext->numOfServers;
|
||||
|
||||
LogInfo( ( "Rotating server for next time query: PreviousServer=%.*s, NextServer=%.*s",
|
||||
( int ) pContext->pTimeServers[ pContext->currentServerIndex ].serverNameLen,
|
||||
pContext->pTimeServers[ pContext->currentServerIndex ].pServerName,
|
||||
( int ) pContext->pTimeServers[ nextServerIndex ].serverNameLen,
|
||||
pContext->pTimeServers[ nextServerIndex ].pServerName ) );
|
||||
|
||||
pContext->currentServerIndex = nextServerIndex;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief This function attempts to receive the SNTP response packet from a server.
|
||||
*
|
||||
* @note This function treats reads of data sizes less than the expected server response packet,
|
||||
* as an error as UDP does not support partial reads. Such a scenario can exist either due:
|
||||
* - An error in the server sending its response with smaller packet size than the request packet OR
|
||||
* - A malicious attacker spoofing or modifying server response OR
|
||||
* - An error in the UDP transport interface implementation for read operation.
|
||||
*
|
||||
* @param[in] pTransportIntf The UDP transport interface to use for receiving data from
|
||||
* the network.
|
||||
* @param[in] timeServer The server to read the response from the network.
|
||||
* @param[in] serverPort The port of the server to read the response from.
|
||||
* @param[in, out] pBuffer This will be filled with the server response read from the
|
||||
* network.
|
||||
* @param[in] responseSize The size of server response to read from the network.
|
||||
*
|
||||
* @return It returns one of the following:
|
||||
* - #SntpSuccess if an SNTP response packet is received from the network.
|
||||
* - #SntpNoResponseReceived if a server response is not received from the network.
|
||||
* - #SntpErrorNetworkFailure if there is an internal failure in reading from the network
|
||||
* in the user-defined transport interface.
|
||||
*/
|
||||
static SntpStatus_t receiveSntpResponse( const UdpTransportInterface_t * pTransportIntf,
|
||||
uint32_t timeServer,
|
||||
uint16_t serverPort,
|
||||
uint8_t * pBuffer,
|
||||
uint16_t responseSize )
|
||||
{
|
||||
SntpStatus_t status = SntpNoResponseReceived;
|
||||
int32_t bytesRead = 0;
|
||||
|
||||
assert( pTransportIntf != NULL );
|
||||
assert( pTransportIntf->recvFrom != NULL );
|
||||
assert( pBuffer != NULL );
|
||||
assert( responseSize >= SNTP_PACKET_BASE_SIZE );
|
||||
|
||||
bytesRead = pTransportIntf->recvFrom( pTransportIntf->pUserContext,
|
||||
timeServer,
|
||||
serverPort,
|
||||
pBuffer,
|
||||
responseSize );
|
||||
|
||||
/* Negative return code indicates error. */
|
||||
if( bytesRead < 0 )
|
||||
{
|
||||
status = SntpErrorNetworkFailure;
|
||||
LogError( ( "Unable to receive server response: Transport receive failed: Code=%ld",
|
||||
( long int ) bytesRead ) );
|
||||
}
|
||||
/* If the packet was not available on the network, check whether we can retry. */
|
||||
else if( bytesRead == 0 )
|
||||
{
|
||||
status = SntpNoResponseReceived;
|
||||
}
|
||||
|
||||
/* Partial reads are not supported by UDP, which only supports receiving the entire datagram as a whole.
|
||||
* Thus, if the transport receive function returns reception of partial data, it will be treated as failure. */
|
||||
else if( bytesRead != ( int32_t ) responseSize )
|
||||
{
|
||||
LogError( ( "Failed to receive server response: Transport recv returned less than expected bytes."
|
||||
"ExpectedBytes=%u, ReadBytes=%ld", responseSize, ( long int ) bytesRead ) );
|
||||
status = SntpErrorNetworkFailure;
|
||||
}
|
||||
else
|
||||
{
|
||||
LogDebug( ( "Received server response: PacketSize=%ld", ( long int ) bytesRead ) );
|
||||
status = SntpSuccess;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Processes the response from a server by de-serializing the SNTP packet to
|
||||
* validate the server (if an authentication interface has been configured), determine
|
||||
* whether server has accepted or rejected the time request, and update the system clock
|
||||
* if the server responded positively with time.
|
||||
*
|
||||
* @param[in] pContext The SNTP context representing the SNTP client.
|
||||
* @param[in] pResponseRxTime The time of receiving the server response from the network.
|
||||
*
|
||||
* @return It returns one of the following:
|
||||
* - #SntpSuccess if the server response is successfully de-serialized and system clock
|
||||
* updated.
|
||||
* - #SntpErrorAuthFailure if there is internal failure in user-defined authentication
|
||||
* interface when validating server from the response.
|
||||
* - #SntpServerNotAuthenticated if the server failed authenticated check in the user-defined
|
||||
* interface.
|
||||
* - #SntpRejectedResponse if the server has rejected the time request in its response.
|
||||
* - #SntpInvalidResponse if the server response failed sanity checks.
|
||||
*/
|
||||
static SntpStatus_t processServerResponse( SntpContext_t * pContext,
|
||||
const SntpTimestamp_t * pResponseRxTime )
|
||||
{
|
||||
SntpStatus_t status = SntpSuccess;
|
||||
const SntpServerInfo_t * pServer = &pContext->pTimeServers[ pContext->currentServerIndex ];
|
||||
|
||||
assert( pContext != NULL );
|
||||
assert( pResponseRxTime != NULL );
|
||||
|
||||
if( pContext->authIntf.validateServerAuth != NULL )
|
||||
{
|
||||
/* Verify the server from the authentication data in the SNTP response packet. */
|
||||
status = pContext->authIntf.validateServerAuth( pContext->authIntf.pAuthContext,
|
||||
pServer,
|
||||
pContext->pNetworkBuffer,
|
||||
pContext->sntpPacketSize );
|
||||
assert( ( status == SntpSuccess ) || ( status == SntpErrorAuthFailure ) ||
|
||||
( status == SntpServerNotAuthenticated ) );
|
||||
|
||||
if( status != SntpSuccess )
|
||||
{
|
||||
LogError( ( "Unable to use server response: Server authentication function failed: "
|
||||
"ReturnStatus=%s", Sntp_StatusToStr( status ) ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
LogDebug( ( "Server response has been validated: Server=%.*s", ( int ) pServer->serverNameLen, pServer->pServerName ) );
|
||||
}
|
||||
}
|
||||
|
||||
if( status == SntpSuccess )
|
||||
{
|
||||
SntpResponseData_t parsedResponse;
|
||||
|
||||
/* De-serialize response packet to determine whether the server accepted or rejected
|
||||
* the request for time. Also, calculate the system clock offset if the server responded
|
||||
* with time. */
|
||||
status = Sntp_DeserializeResponse( &pContext->lastRequestTime,
|
||||
pResponseRxTime,
|
||||
pContext->pNetworkBuffer,
|
||||
pContext->sntpPacketSize,
|
||||
&parsedResponse );
|
||||
|
||||
/* We do not expect the following errors to be returned as the context
|
||||
* has been validated in the Sntp_ReceiveTimeResponse API. */
|
||||
assert( status != SntpErrorBadParameter );
|
||||
assert( status != SntpErrorBufferTooSmall );
|
||||
|
||||
if( ( status == SntpRejectedResponseChangeServer ) ||
|
||||
( status == SntpRejectedResponseRetryWithBackoff ) ||
|
||||
( status == SntpRejectedResponseOtherCode ) )
|
||||
{
|
||||
/* Server has rejected the time request. Thus, we will rotate to the next time server
|
||||
* in the list. */
|
||||
rotateServerForNextTimeQuery( pContext );
|
||||
|
||||
LogError( ( "Unable to use server response: Server has rejected request for time: RejectionCode=%.*s",
|
||||
( int ) SNTP_KISS_OF_DEATH_CODE_LENGTH, ( char * ) &parsedResponse.rejectedResponseCode ) );
|
||||
status = SntpRejectedResponse;
|
||||
}
|
||||
else if( status == SntpInvalidResponse )
|
||||
{
|
||||
LogError( ( "Unable to use server response: Server response failed sanity checks." ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Server has responded successfully with time, and we have calculated the clock offset
|
||||
* of system clock relative to the server.*/
|
||||
LogDebug( ( "Updating system time: ServerTime=%u %ums ClockOffset=%lums",
|
||||
parsedResponse.serverTime.seconds, FRACTIONS_TO_MS( parsedResponse.serverTime.fractions ),
|
||||
parsedResponse.clockOffsetMs ) );
|
||||
|
||||
/* Update the system clock with the calculated offset. */
|
||||
pContext->setTimeFunc( pServer, &parsedResponse.serverTime,
|
||||
parsedResponse.clockOffsetMs, parsedResponse.leapSecondType );
|
||||
|
||||
status = SntpSuccess;
|
||||
}
|
||||
}
|
||||
|
||||
/* Reset the last request time state in context to protect against replay attacks.
|
||||
* Note: The last request time is not cleared when a rejection response packet is received and the client does
|
||||
* has not authenticated server from the response. This is because clearing of the state causes the coreSNTP
|
||||
* library to discard any subsequent server response packets (as the "originate timestamp" of those packets will
|
||||
* not match the last request time value of the context), and thus, an attacker can cause Denial of Service
|
||||
* attacks by spoofing server response before the actual server is able to respond.
|
||||
*/
|
||||
if( ( status == SntpSuccess ) ||
|
||||
( ( pContext->authIntf.validateServerAuth != NULL ) && ( status == SntpRejectedResponse ) ) )
|
||||
{
|
||||
/* In the attack of SNTP request packet being replayed, the replayed request packet is serviced by
|
||||
* SNTP/NTP server with SNTP response (as servers are stateless) and client receives the response
|
||||
* containing new values of server timestamps but the stale value of "originate timestamp".
|
||||
* To prevent the coreSNTP library from servicing such a server response (associated with the replayed
|
||||
* SNTP request packet), the last request timestamp state is cleared in the context after receiving the
|
||||
* first valid server response. Therefore, any subsequent server response(s) from replayed client request
|
||||
* packets can be invalidated due to the "originate timestamp" not matching the last request time stored
|
||||
* in the context.
|
||||
* Note: If an attacker spoofs a server response with a zero "originate timestamp" after the coreSNTP
|
||||
* library (i.e. the SNTP client) has cleared the internal state to zero, the spoofed packet will be
|
||||
* discarded as the coreSNTP serializer does not accept server responses with zero value for timestamps.
|
||||
*/
|
||||
pContext->lastRequestTime.seconds = 0U;
|
||||
pContext->lastRequestTime.fractions = 0U;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Determines whether a retry attempt should be made to receive server response packet from the network
|
||||
* depending on the timing constraints of server response timeout, @p responseTimeoutMs, and the block time
|
||||
* period, @p blockTimeMs, passed. If neither of the time windows have expired, the function determines that the
|
||||
* read operation can be re-tried.
|
||||
*
|
||||
* @param[in] pCurrentTime The current time in the system used for calculating elapsed time windows.
|
||||
* @param[in] pReadStartTime The time of the first read attempt in the current set of read tries occurring
|
||||
* from the Sntp_ReceiveTimeRequest API call by the application. This time is used for calculating the elapsed
|
||||
* time to determine whether the block time has expired.
|
||||
* @param[in] pRequestTime The time of sending the SNTP request to the server for which the response is
|
||||
* awaited. This time is used for calculating total elapsed elapsed time of waiting for server response to
|
||||
* determine if a server response timeout has occurred.
|
||||
* @param[in] responseTimeoutMs The server response timeout configuration.
|
||||
* @param[in] blockTimeMs The maximum block time of waiting for server response across read tries in the current
|
||||
* call made by application to Sntp_ReceiveTimeResponse API.
|
||||
* @param[out] pHasResponseTimedOut This will be populated with state to indicate whether the wait for server
|
||||
* response has timed out.
|
||||
*
|
||||
* @return Returns true for retrying read operation of server response; false on either server response timeout
|
||||
* OR completion of block time window.
|
||||
*/
|
||||
static bool decideAboutReadRetry( const SntpTimestamp_t * pCurrentTime,
|
||||
const SntpTimestamp_t * pReadStartTime,
|
||||
const SntpTimestamp_t * pRequestTime,
|
||||
uint32_t responseTimeoutMs,
|
||||
uint32_t blockTimeMs,
|
||||
bool * pHasResponseTimedOut )
|
||||
{
|
||||
uint64_t timeSinceRequestMs = 0UL;
|
||||
uint64_t timeElapsedInReadAttempts = 0UL;
|
||||
bool shouldRetry = false;
|
||||
|
||||
assert( pCurrentTime != NULL );
|
||||
assert( pReadStartTime != NULL );
|
||||
assert( pRequestTime != NULL );
|
||||
assert( pHasResponseTimedOut != NULL );
|
||||
|
||||
/* Calculate time elapsed since the time request was sent to the server
|
||||
* to determine whether the server response has timed out. */
|
||||
timeSinceRequestMs = calculateElapsedTimeMs( pCurrentTime, pRequestTime );
|
||||
|
||||
/* Calculate the time elapsed across all the read attempts so far to determine
|
||||
* whether the block time window for reading server response has expired. */
|
||||
timeElapsedInReadAttempts = calculateElapsedTimeMs( pCurrentTime, pReadStartTime );
|
||||
|
||||
/* Check whether a response timeout has occurred to inform whether we should
|
||||
* wait for server response anymore. */
|
||||
if( timeSinceRequestMs >= ( uint64_t ) responseTimeoutMs )
|
||||
{
|
||||
shouldRetry = false;
|
||||
*pHasResponseTimedOut = true;
|
||||
|
||||
LogError( ( "Unable to receive response: Server response has timed out: "
|
||||
"RequestTime=%us %ums, TimeoutDuration=%ums, ElapsedTime=%lu",
|
||||
pRequestTime->seconds, FRACTIONS_TO_MS( pRequestTime->fractions ),
|
||||
responseTimeoutMs, timeSinceRequestMs ) );
|
||||
}
|
||||
/* Check whether the block time window has expired to determine whether read can be retried. */
|
||||
else if( timeElapsedInReadAttempts >= ( uint64_t ) blockTimeMs )
|
||||
{
|
||||
shouldRetry = false;
|
||||
LogDebug( ( "Did not receive server response: Read block time has expired: "
|
||||
"BlockTime=%ums, ResponseWaitElapsedTime=%lums",
|
||||
blockTimeMs, timeSinceRequestMs ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
shouldRetry = true;
|
||||
LogDebug( ( "Did not receive server response: Retrying read: "
|
||||
"BlockTime=%ums, ResponseWaitElapsedTime=%lums, ResponseTimeout=%u",
|
||||
blockTimeMs, timeSinceRequestMs, responseTimeoutMs ) );
|
||||
}
|
||||
|
||||
return shouldRetry;
|
||||
}
|
||||
|
||||
SntpStatus_t Sntp_ReceiveTimeResponse( SntpContext_t * pContext,
|
||||
uint32_t blockTimeMs )
|
||||
{
|
||||
SntpStatus_t status = SntpNoResponseReceived;
|
||||
bool hasResponseTimedOut = false;
|
||||
|
||||
/* Validate the context parameter. */
|
||||
status = validateContext( pContext );
|
||||
|
||||
if( status == SntpSuccess )
|
||||
{
|
||||
SntpTimestamp_t startTime, currentTime;
|
||||
const SntpTimestamp_t * pRequestTime = &pContext->lastRequestTime;
|
||||
bool shouldRetry = false;
|
||||
|
||||
/* Record time before read attempts so that it can be used as base time for
|
||||
* for tracking the block time window across read retries. */
|
||||
pContext->getTimeFunc( &startTime );
|
||||
|
||||
do
|
||||
{
|
||||
/* Reset the retry read operation flag. If the server response is not received in the current iteration's read
|
||||
* attempt and the wait has not timed out, the flag will be set to perform a retry. */
|
||||
shouldRetry = false;
|
||||
|
||||
/* Make an attempt to read the server response from the network. */
|
||||
status = receiveSntpResponse( &pContext->networkIntf,
|
||||
pContext->currentServerAddr,
|
||||
pContext->pTimeServers[ pContext->currentServerIndex ].port,
|
||||
pContext->pNetworkBuffer,
|
||||
pContext->sntpPacketSize );
|
||||
|
||||
/* If the server response is received, deserialize it, validate the server
|
||||
* (if authentication interface is provided), and update system time with
|
||||
* the calculated clock offset. */
|
||||
if( status == SntpSuccess )
|
||||
{
|
||||
/* Get current time to de-serialize the receive server response packet. */
|
||||
pContext->getTimeFunc( ¤tTime );
|
||||
|
||||
status = processServerResponse( pContext, ¤tTime );
|
||||
}
|
||||
else if( status == SntpNoResponseReceived )
|
||||
{
|
||||
/* Get current time to determine whether another attempt for reading the packet can
|
||||
* be made. */
|
||||
pContext->getTimeFunc( ¤tTime );
|
||||
|
||||
/* Set the flag to retry read of server response from the network. */
|
||||
shouldRetry = decideAboutReadRetry( ¤tTime,
|
||||
&startTime,
|
||||
pRequestTime,
|
||||
pContext->responseTimeoutMs,
|
||||
blockTimeMs,
|
||||
&hasResponseTimedOut );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Empty else marker. */
|
||||
}
|
||||
} while( shouldRetry == true );
|
||||
|
||||
/* If the wait for server response to the time request has timed out, rotate the server of use in the
|
||||
* context for subsequent time request(s). Also, update the return status to indicate response timeout. */
|
||||
if( hasResponseTimedOut == true )
|
||||
{
|
||||
status = SntpErrorResponseTimeout;
|
||||
|
||||
/* Rotate server to the next in the list of configured servers in the context. */
|
||||
rotateServerForNextTimeQuery( pContext );
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
const char * Sntp_StatusToStr( SntpStatus_t status )
|
||||
{
|
||||
const char * pString = NULL;
|
||||
|
||||
switch( status )
|
||||
{
|
||||
case SntpSuccess:
|
||||
pString = "SntpSuccess";
|
||||
break;
|
||||
|
||||
case SntpErrorBadParameter:
|
||||
pString = "SntpErrorBadParameter";
|
||||
break;
|
||||
|
||||
case SntpRejectedResponseChangeServer:
|
||||
pString = "SntpRejectedResponseChangeServer";
|
||||
break;
|
||||
|
||||
case SntpRejectedResponseRetryWithBackoff:
|
||||
pString = "SntpRejectedResponseRetryWithBackoff";
|
||||
break;
|
||||
|
||||
case SntpRejectedResponseOtherCode:
|
||||
pString = "SntpRejectedResponseOtherCode";
|
||||
break;
|
||||
|
||||
case SntpErrorBufferTooSmall:
|
||||
pString = "SntpErrorBufferTooSmall";
|
||||
break;
|
||||
|
||||
case SntpInvalidResponse:
|
||||
pString = "SntpInvalidResponse";
|
||||
break;
|
||||
|
||||
case SntpZeroPollInterval:
|
||||
pString = "SntpZeroPollInterval";
|
||||
break;
|
||||
|
||||
case SntpErrorTimeNotSupported:
|
||||
pString = "SntpErrorTimeNotSupported";
|
||||
break;
|
||||
|
||||
case SntpErrorDnsFailure:
|
||||
pString = "SntpErrorDnsFailure";
|
||||
break;
|
||||
|
||||
case SntpErrorNetworkFailure:
|
||||
pString = "SntpErrorNetworkFailure";
|
||||
break;
|
||||
|
||||
case SntpServerNotAuthenticated:
|
||||
pString = "SntpServerNotAuthenticated";
|
||||
break;
|
||||
|
||||
case SntpErrorAuthFailure:
|
||||
pString = "SntpErrorAuthFailure";
|
||||
break;
|
||||
|
||||
default:
|
||||
pString = "Invalid status code!";
|
||||
break;
|
||||
}
|
||||
|
||||
return pString;
|
||||
}
|
||||
@ -0,0 +1,853 @@
|
||||
/*
|
||||
* coreSNTP v1.2.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 core_sntp_serializer.c
|
||||
* @brief Implementation of the Serializer API of the coreSNTP library.
|
||||
*/
|
||||
|
||||
/* Standard includes. */
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
|
||||
/* Include API header. */
|
||||
#include "core_sntp_serializer.h"
|
||||
|
||||
#include "core_sntp_config_defaults.h"
|
||||
|
||||
/**
|
||||
* @brief The version of SNTP supported by the coreSNTP library by complying
|
||||
* with the SNTPv4 specification defined in [RFC 4330](https://tools.ietf.org/html/rfc4330).
|
||||
*/
|
||||
#define SNTP_VERSION ( 4U )
|
||||
|
||||
/**
|
||||
* @brief The bit mask for the "Mode" information in the first byte of an SNTP packet.
|
||||
* The "Mode" field occupies bits 0-2 of the byte.
|
||||
* @note Refer to the [RFC 4330 Section 4](https://tools.ietf.org/html/rfc4330#section-4)
|
||||
* for more information.
|
||||
*/
|
||||
#define SNTP_MODE_BITS_MASK ( 0x07U )
|
||||
|
||||
/**
|
||||
* @brief The value indicating a "client" in the "Mode" field of an SNTP packet.
|
||||
* @note Refer to the [RFC 4330 Section 4](https://tools.ietf.org/html/rfc4330#section-4)
|
||||
* for more information.
|
||||
*/
|
||||
#define SNTP_MODE_CLIENT ( 3U )
|
||||
|
||||
/**
|
||||
* @brief The value indicating a "server" in the "Mode" field of an SNTP packet.
|
||||
* @note Refer to the [RFC 4330 Section 4](https://tools.ietf.org/html/rfc4330#section-4)
|
||||
* for more information.
|
||||
*/
|
||||
#define SNTP_MODE_SERVER ( 4U )
|
||||
|
||||
/**
|
||||
* @brief The position of the least significant bit of the "Leap Indicator" field
|
||||
* in first byte of an SNTP packet. The "Leap Indicator" field occupies bits 6-7 of the byte.
|
||||
* @note Refer to the [RFC 4330 Section 4](https://tools.ietf.org/html/rfc4330#section-4)
|
||||
* for more information.
|
||||
*/
|
||||
#define SNTP_LEAP_INDICATOR_LSB_POSITION ( 6 )
|
||||
|
||||
/**
|
||||
* @brief Value of Stratum field in SNTP packet representing a Kiss-o'-Death message
|
||||
* from server.
|
||||
*/
|
||||
#define SNTP_KISS_OF_DEATH_STRATUM ( 0U )
|
||||
|
||||
/**
|
||||
* @brief The position of least significant bit of the "Version" information
|
||||
* in the first byte of an SNTP packet. "Version" field occupies bits 3-5 of
|
||||
* the byte.
|
||||
* @note Refer to the [RFC 4330 Section 4](https://tools.ietf.org/html/rfc4330#section-4)
|
||||
* for more information.
|
||||
*/
|
||||
#define SNTP_VERSION_LSB_POSITION ( 3 )
|
||||
|
||||
/**
|
||||
* @brief The integer value of the Kiss-o'-Death ASCII code, "DENY", used
|
||||
* for comparison with data in an SNTP response.
|
||||
* @note Refer to [RFC 4330 Section 8](https://tools.ietf.org/html/rfc4330#section-8)
|
||||
* for more information.
|
||||
*/
|
||||
#define KOD_CODE_DENY_UINT_VALUE ( 0x44454e59U )
|
||||
|
||||
/**
|
||||
* @brief The integer value of the Kiss-o'-Death ASCII code, "RSTR", used
|
||||
* for comparison with data in an SNTP response.
|
||||
* @note Refer to [RFC 4330 Section 8](https://tools.ietf.org/html/rfc4330#section-8)
|
||||
* for more information.
|
||||
*/
|
||||
#define KOD_CODE_RSTR_UINT_VALUE ( 0x52535452U )
|
||||
|
||||
/**
|
||||
* @brief The integer value of the Kiss-o'-Death ASCII code, "RATE", used
|
||||
* for comparison with data in an SNTP response.
|
||||
* @note Refer to [RFC 4330 Section 8](https://tools.ietf.org/html/rfc4330#section-8)
|
||||
* for more information.
|
||||
*/
|
||||
#define KOD_CODE_RATE_UINT_VALUE ( 0x52415445U )
|
||||
|
||||
/**
|
||||
* @brief Macro to represent exactly half of the total number of seconds in an NTP era.
|
||||
* As 32 bits are used to represent the "seconds" part of an SNTP timestamp, the half of
|
||||
* the total range of seconds in an NTP era is 2^31 seconds, which represents ~68 years.
|
||||
*
|
||||
* @note This macro represents the edge case of calculating the client system clock-offset
|
||||
* relative to server time as the library ASSUMES that the client and server times are within
|
||||
* 2^31 seconds apart in duration. This is done to support calculating clock-offset for the
|
||||
* cases when server and client systems are in adjacent NTP eras, which can occur when NTP time
|
||||
* wraps around in 2036, and the relative NTP era presence of client and server times is
|
||||
* determined based on comparing first order difference values between all possible NTP era
|
||||
* configurations of the systems.
|
||||
*/
|
||||
#define CLOCK_OFFSET_MAX_TIME_DIFFERENCE ( ( ( ( int64_t ) INT32_MAX + 1 ) * 1000 ) )
|
||||
|
||||
/**
|
||||
* @brief Macro to represent the total number of milliseconds that are represented in an
|
||||
* NTP era period. This macro represents a duration of ~136 years.
|
||||
*
|
||||
* @note Rationale for calculation: The "seconds" part of an NTP timestamp is represented in
|
||||
* unsigned 32 bit width, thus, the total range of seconds it represents is 2^32,
|
||||
* i.e. (UINT32_MAX + 1).
|
||||
*/
|
||||
#define TOTAL_MILLISECONDS_IN_NTP_ERA ( ( ( int64_t ) UINT32_MAX + 1 ) * 1000 )
|
||||
|
||||
/**
|
||||
* @brief Structure representing an SNTP packet header.
|
||||
* For more information on SNTP packet format, refer to
|
||||
* [RFC 4330 Section 4](https://tools.ietf.org/html/rfc4330#section-4).
|
||||
*
|
||||
* @note This does not include extension fields for authentication data
|
||||
* for secure SNTP communication. Authentication data follows the
|
||||
* packet header represented by this structure.
|
||||
*/
|
||||
typedef struct SntpPacket
|
||||
{
|
||||
/**
|
||||
* @brief Bits 6-7 leap indicator, bits 3-5 are version number, bits 0-2 are mode
|
||||
*/
|
||||
uint8_t leapVersionMode;
|
||||
|
||||
/**
|
||||
* @brief stratum
|
||||
*/
|
||||
uint8_t stratum;
|
||||
|
||||
/**
|
||||
* @brief poll interval
|
||||
*/
|
||||
uint8_t poll;
|
||||
|
||||
/**
|
||||
* @brief precision
|
||||
*/
|
||||
uint8_t precision;
|
||||
|
||||
/**
|
||||
* @brief root delay
|
||||
*/
|
||||
uint32_t rootDelay;
|
||||
|
||||
/**
|
||||
* @brief root dispersion
|
||||
*/
|
||||
uint32_t rootDispersion;
|
||||
|
||||
/**
|
||||
* @brief reference ID
|
||||
*/
|
||||
uint32_t refId;
|
||||
|
||||
/**
|
||||
* @brief reference time
|
||||
*/
|
||||
SntpTimestamp_t refTime;
|
||||
|
||||
/**
|
||||
* @brief origin timestamp
|
||||
*/
|
||||
SntpTimestamp_t originTime;
|
||||
|
||||
/**
|
||||
* @brief receive timestamp
|
||||
*/
|
||||
SntpTimestamp_t receiveTime;
|
||||
|
||||
/**
|
||||
* @brief transmit timestamp
|
||||
*/
|
||||
SntpTimestamp_t transmitTime;
|
||||
} SntpPacket_t;
|
||||
|
||||
/**
|
||||
* @brief Utility macro to fill 32-bit integer in word-sized
|
||||
* memory in network byte (or Big Endian) order.
|
||||
*
|
||||
* @param[out] pWordMemory Pointer to the word-sized memory in which
|
||||
* the 32-bit integer will be filled.
|
||||
* @param[in] data The 32-bit integer to fill in the @p wordMemory
|
||||
* in network byte order.
|
||||
*
|
||||
* @note This utility ensures that data is filled in memory
|
||||
* in expected network byte order, as an assignment operation
|
||||
* (like *pWordMemory = word) can cause undesired side-effect
|
||||
* of network-byte ordering getting reversed on Little Endian platforms.
|
||||
*/
|
||||
static void fillWordMemoryInNetworkOrder( uint32_t * pWordMemory,
|
||||
uint32_t data )
|
||||
{
|
||||
assert( pWordMemory != NULL );
|
||||
|
||||
*( ( uint8_t * ) pWordMemory ) = ( uint8_t ) ( data >> 24 );
|
||||
*( ( uint8_t * ) pWordMemory + 1 ) = ( uint8_t ) ( ( data >> 16 ) & 0x000000FFU );
|
||||
*( ( uint8_t * ) pWordMemory + 2 ) = ( uint8_t ) ( ( data >> 8 ) & 0x000000FFU );
|
||||
*( ( uint8_t * ) pWordMemory + 3 ) = ( uint8_t ) ( ( data ) & 0x000000FFU );
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Utility macro to generate a 32-bit integer from memory containing
|
||||
* integer in network (or Big Endian) byte order.
|
||||
* @param[in] ptr Pointer to the memory containing 32-bit integer in network
|
||||
* byte order.
|
||||
*
|
||||
* @return The host representation of the 32-bit integer in the passed word
|
||||
* memory.
|
||||
*/
|
||||
static uint32_t readWordFromNetworkByteOrderMemory( const uint32_t * ptr )
|
||||
{
|
||||
const uint8_t * pMemStartByte = ( const uint8_t * ) ptr;
|
||||
|
||||
assert( ptr != NULL );
|
||||
|
||||
return ( uint32_t ) ( ( ( uint32_t ) *( pMemStartByte ) << 24 ) |
|
||||
( 0x00FF0000U & ( ( uint32_t ) *( pMemStartByte + 1 ) << 16 ) ) |
|
||||
( 0x0000FF00U & ( ( uint32_t ) *( pMemStartByte + 2 ) << 8 ) ) |
|
||||
( ( uint32_t ) *( pMemStartByte + 3 ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Utility to return absolute (or positively signed) value of an signed
|
||||
* 64 bit integer.
|
||||
*
|
||||
* @param[in] value The integer to return the absolute value of.
|
||||
*
|
||||
* @return The absolute value of @p value.
|
||||
*/
|
||||
static int64_t absoluteOf( int64_t value )
|
||||
{
|
||||
return ( value >= 0 ) ? value : ( ( int64_t ) 0 - value );
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Utility to determine whether a timestamp represents a zero
|
||||
* timestamp value.
|
||||
*
|
||||
* @note This utility is used to determine whether a timestamp value is
|
||||
* invalid. According to the SNTPv4 specification, a zero timestamp value
|
||||
* is considered invalid.
|
||||
*
|
||||
* @param[in] pTime The timestamp whose value is to be inspected for
|
||||
* zero value.
|
||||
*
|
||||
* @return `true` if the timestamp is zero; otherwise `false`.
|
||||
*/
|
||||
static bool isZeroTimestamp( const SntpTimestamp_t * pTime )
|
||||
{
|
||||
bool isSecondsZero = ( pTime->seconds == 0U ) ? true : false;
|
||||
bool isFractionsZero = ( pTime->fractions == 0U ) ? true : false;
|
||||
|
||||
return( isSecondsZero && isFractionsZero );
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Utility to convert the "fractions" part of an SNTP timestamp to milliseconds
|
||||
* duration of time.
|
||||
* @param[in] fractions The fractions value.
|
||||
*
|
||||
* @return The milliseconds equivalent of the @p fractions value.
|
||||
*/
|
||||
static uint32_t fractionsToMs( uint32_t fractions )
|
||||
{
|
||||
return( fractions / ( 1000U * SNTP_FRACTION_VALUE_PER_MICROSECOND ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Utility to safely calculate difference between server and client timestamps and
|
||||
* return the difference in the resolution of milliseconds as a signed 64 bit integer.
|
||||
* The calculated value represents the effective subtraction as ( @p serverTimeSec - @p clientTimeSec ).
|
||||
*
|
||||
* @note This utility SUPPORTS the cases of server and client timestamps being in different NTP eras,
|
||||
* and ASSUMES that the server and client systems are within 68 years of each other.
|
||||
* To handle the case of different NTP eras, this function calculates difference values for all
|
||||
* possible combinations of NTP eras of server and client times (i.e. 1. both timestamps in same era,
|
||||
* 2. server timestamp one era ahead, and 3. client timestamp being one era ahead), and determines
|
||||
* the NTP era configuration by choosing the difference value of the smallest absolute value.
|
||||
*
|
||||
* @param[in] pServerTime The server timestamp.
|
||||
* @param[in] pClientTime The client timestamp.
|
||||
*
|
||||
* @return The calculated difference between server and client times as a signed 64 bit integer.
|
||||
*/
|
||||
static int64_t safeTimeDifference( const SntpTimestamp_t * pServerTime,
|
||||
const SntpTimestamp_t * pClientTime )
|
||||
{
|
||||
int64_t eraAdjustedDiff = 0;
|
||||
|
||||
/* Convert the timestamps into 64 bit signed integer values of milliseconds. */
|
||||
int64_t serverTime = ( ( int64_t ) pServerTime->seconds * 1000 ) + ( int64_t ) fractionsToMs( pServerTime->fractions );
|
||||
int64_t clientTime = ( ( int64_t ) pClientTime->seconds * 1000 ) + ( int64_t ) fractionsToMs( pClientTime->fractions );
|
||||
|
||||
/* The difference between the 2 timestamps is calculated by determining the whether the timestamps
|
||||
* are present in the same NTP era or adjacent NTP eras (i.e. the NTP timestamp overflow case). */
|
||||
|
||||
/* First, calculate the first order time difference assuming that server and client times
|
||||
* are in the same NTP era. */
|
||||
int64_t diffWithNoEraAdjustment = serverTime - clientTime;
|
||||
|
||||
/* Store the absolute value of the time difference which will be used for comparison with
|
||||
* different cases of relative NTP era configuration of client and server times. */
|
||||
int64_t absSameEraDiff = absoluteOf( diffWithNoEraAdjustment );
|
||||
|
||||
/* If the absolute difference value is 2^31 seconds, it means that the server and client times are
|
||||
* away by exactly half the range of SNTP timestamp "second" values representable in unsigned 32 bits.
|
||||
* In such a case, irrespective of whether the 2 systems exist in the same or adjacent NTP eras, the
|
||||
* time difference calculated between the systems will ALWAYS yield the same value when viewed from
|
||||
* all NTP era configurations of the times.
|
||||
* For such a case, we will ASSUME that the server time is AHEAD of client time, and thus, generate
|
||||
* a positive clock-offset value.
|
||||
*/
|
||||
if( absSameEraDiff == CLOCK_OFFSET_MAX_TIME_DIFFERENCE )
|
||||
{
|
||||
/* It does not matter whether server and client are in the same era for this
|
||||
* special case as the difference value for both same and adjacent eras will yield
|
||||
* the same absolute value of 2^31.*/
|
||||
eraAdjustedDiff = CLOCK_OFFSET_MAX_TIME_DIFFERENCE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Determine if server time belongs to an NTP era different than the client time, and accordingly
|
||||
* choose the 64 bit representation of the first order difference to account for the era.
|
||||
* The logic for determining the relative era presence of the timestamps is by calculating the
|
||||
* first order difference (of "Server Time - Client Time") for all the 3 different era combinations
|
||||
* (1. both timestamps in same era, 2. server time one era ahead, 3. client time one era ahead)
|
||||
* and choosing the NTP era configuration that has the smallest first order difference value.
|
||||
*/
|
||||
int64_t diffWithServerEraAdjustment = serverTime + TOTAL_MILLISECONDS_IN_NTP_ERA -
|
||||
clientTime; /* This helps determine whether server is an
|
||||
* era ahead of client time. */
|
||||
int64_t diffWithClientEraAdjustment = serverTime -
|
||||
( TOTAL_MILLISECONDS_IN_NTP_ERA + clientTime ); /* This helps determine whether server is an
|
||||
* era behind of client time. */
|
||||
|
||||
/* Store the absolute value equivalents of all the time difference configurations
|
||||
* for easier comparison to smallest value from them. */
|
||||
int64_t absServerEraAheadDiff = absoluteOf( diffWithServerEraAdjustment );
|
||||
int64_t absClientEraAheadDiff = absoluteOf( diffWithClientEraAdjustment );
|
||||
|
||||
/* Determine the correct relative era of client and server times by checking which era
|
||||
* configuration of difference value represents the least difference. */
|
||||
if( ( absSameEraDiff <= absServerEraAheadDiff ) && ( absSameEraDiff <= absClientEraAheadDiff ) )
|
||||
{
|
||||
/* Both server and client times are in the same era. */
|
||||
eraAdjustedDiff = diffWithNoEraAdjustment;
|
||||
}
|
||||
/* Check if server time is an NTP era ahead of client time. */
|
||||
else if( absServerEraAheadDiff < absSameEraDiff )
|
||||
{
|
||||
/* Server time is in NTP era 1 while client time is in NTP era 0. */
|
||||
eraAdjustedDiff = diffWithServerEraAdjustment;
|
||||
}
|
||||
/* Now, we know that the client time is an era ahead of server time. */
|
||||
else
|
||||
{
|
||||
/* Server time is in NTP era 0 while client time is in NTP era 1. */
|
||||
eraAdjustedDiff = diffWithClientEraAdjustment;
|
||||
}
|
||||
}
|
||||
|
||||
return eraAdjustedDiff;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Utility to calculate clock offset of system relative to the
|
||||
* server using the on-wire protocol specified in the NTPv4 specification.
|
||||
* For more information on on-wire protocol, refer to
|
||||
* [RFC 5905 Section 8](https://tools.ietf.org/html/rfc5905#section-8).
|
||||
*
|
||||
* @note The following diagram explains the calculation of the clock
|
||||
* offset:
|
||||
*
|
||||
* T2 T3
|
||||
* --------------------------------- <----- *SNTP/NTP server*
|
||||
* /\ \
|
||||
* / \
|
||||
* Request* / \ *Response*
|
||||
* / \/
|
||||
* --------------------------------- <----- *SNTP client*
|
||||
* T1 T4
|
||||
*
|
||||
* The four most recent timestamps, T1 through T4, are used to compute
|
||||
* the clock offset of SNTP client relative to the server where:
|
||||
*
|
||||
* T1 = Client Request Transmit Time
|
||||
* T2 = Server Receive Time (of client request)
|
||||
* T3 = Server Response Transmit Time
|
||||
* T4 = Client Receive Time (of server response)
|
||||
*
|
||||
* Clock Offset = T(NTP/SNTP server) - T(SNTP client)
|
||||
* = [( T2 - T1 ) + ( T3 - T4 )]
|
||||
* ---------------------------
|
||||
* 2
|
||||
*
|
||||
* @note Both NTPv4 and SNTPv4 specifications suggest calculating the
|
||||
* clock offset value, if possible. As the timestamp format uses 64 bit
|
||||
* integer and there exist 2 orders of arithmetic calculations on the
|
||||
* timestamp values (subtraction followed by addition as shown in the
|
||||
* diagram above), the clock offset for the system can be calculated
|
||||
* ONLY if the value can be represented in 62 significant bits and 2 sign
|
||||
* bits i.e. if the system clock is within 34 years (in the future or past)
|
||||
* of the server time.
|
||||
*
|
||||
* @param[in] pClientTxTime The system time of sending the SNTP request.
|
||||
* This is the same as "T1" in the above diagram.
|
||||
* @param[in] pServerRxTime The server time of receiving the SNTP request
|
||||
* packet from the client. This is the same as "T2" in the above diagram.
|
||||
* @param[in] pServerTxTime The server time of sending the SNTP response
|
||||
* packet. This is the same as "T3" in the above diagram.
|
||||
* @param[in] pClientRxTime The system time of receiving the SNTP response
|
||||
* from the server. This is the same as "T4" in the above diagram.
|
||||
* @param[out] pClockOffset This will be filled with the calculated offset value
|
||||
* of the system clock relative to the server time with the assumption that the
|
||||
* system clock is within 68 years of server time.
|
||||
*/
|
||||
static void calculateClockOffset( const SntpTimestamp_t * pClientTxTime,
|
||||
const SntpTimestamp_t * pServerRxTime,
|
||||
const SntpTimestamp_t * pServerTxTime,
|
||||
const SntpTimestamp_t * pClientRxTime,
|
||||
int64_t * pClockOffset )
|
||||
{
|
||||
/* Variable for storing the first-order difference between timestamps. */
|
||||
int64_t firstOrderDiffSend = 0;
|
||||
int64_t firstOrderDiffRecv = 0;
|
||||
|
||||
assert( pClientTxTime != NULL );
|
||||
assert( pServerRxTime != NULL );
|
||||
assert( pServerTxTime != NULL );
|
||||
assert( pClientRxTime != NULL );
|
||||
assert( pClockOffset != NULL );
|
||||
|
||||
/* Perform first order difference of timestamps on the network send path i.e. T2 - T1.
|
||||
* Note: The calculated difference value will always represent years in the range of
|
||||
*[-68 years, +68 years]. */
|
||||
firstOrderDiffSend = safeTimeDifference( pServerRxTime, pClientTxTime );
|
||||
|
||||
/* Perform first order difference of timestamps on the network receive path i.e. T3 - T4.
|
||||
* Note: The calculated difference value will always represent years in the range of
|
||||
*[-68 years, +68 years]. */
|
||||
firstOrderDiffRecv = safeTimeDifference( pServerTxTime, pClientRxTime );
|
||||
|
||||
/* Now calculate the system clock-offset relative to server time as the average of the
|
||||
* first order difference of timestamps in both directions of network path.
|
||||
* Note: This will ALWAYS represent offset in the range of [-68 years, +68 years]. */
|
||||
*pClockOffset = ( firstOrderDiffSend + firstOrderDiffRecv ) / 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Parse a SNTP response packet by determining whether it is a rejected
|
||||
* or accepted response to an SNTP request, and accordingly, populate the
|
||||
* @p pParsedResponse parameter with the parsed data.
|
||||
*
|
||||
* @note If the server has rejected the request with the a Kiss-o'-Death message,
|
||||
* then this function will set the associated rejection code in the output parameter
|
||||
* while setting the remaining members to zero.
|
||||
* If the server has accepted the time request, then the function will set the
|
||||
* rejectedResponseCode member of the output parameter to #SNTP_KISS_OF_DEATH_CODE_NONE,
|
||||
* and set the other the members with appropriate data extracted from the response
|
||||
* packet.
|
||||
*
|
||||
* @param[in] pResponsePacket The SNTP response packet from server to parse.
|
||||
* @param[in] pRequestTxTime The system time (in SNTP timestamp format) of
|
||||
* sending the SNTP request to server.
|
||||
* @param[in] pResponseRxTime The system time (in SNTP timestamp format) of
|
||||
* receiving the SNTP response from server.
|
||||
* @param[out] pParsedResponse The parameter that will be populated with data
|
||||
* parsed from the response packet, @p pResponsePacket.
|
||||
*
|
||||
* @return This function returns one of the following:
|
||||
* - #SntpSuccess if the server response does not represent a Kiss-o'-Death
|
||||
* message.
|
||||
* - #SntpRejectedResponseChangeServer if the server rejected with a code
|
||||
* indicating that client cannot be retry requests to it.
|
||||
* - #SntpRejectedResponseRetryWithBackoff if the server rejected with a code
|
||||
* indicating that client should back-off before retrying request.
|
||||
* - #SntpRejectedResponseOtherCode if the server rejected with a code
|
||||
* other than "DENY", "RSTR" and "RATE".
|
||||
*/
|
||||
static SntpStatus_t parseValidSntpResponse( const SntpPacket_t * pResponsePacket,
|
||||
const SntpTimestamp_t * pRequestTxTime,
|
||||
const SntpTimestamp_t * pResponseRxTime,
|
||||
SntpResponseData_t * pParsedResponse )
|
||||
{
|
||||
SntpStatus_t status = SntpSuccess;
|
||||
|
||||
assert( pResponsePacket != NULL );
|
||||
assert( pResponseRxTime != NULL );
|
||||
assert( pParsedResponse != NULL );
|
||||
|
||||
/* Clear the output parameter memory to zero. */
|
||||
( void ) memset( pParsedResponse, 0, sizeof( *pParsedResponse ) );
|
||||
|
||||
/* Determine if the server has accepted or rejected the request for time. */
|
||||
if( pResponsePacket->stratum == SNTP_KISS_OF_DEATH_STRATUM )
|
||||
{
|
||||
/* Server has sent a Kiss-o'-Death message i.e. rejected the request. */
|
||||
|
||||
/* Extract the kiss-code sent by the server from the "Reference ID" field
|
||||
* of the SNTP packet. */
|
||||
pParsedResponse->rejectedResponseCode =
|
||||
readWordFromNetworkByteOrderMemory( &pResponsePacket->refId );
|
||||
|
||||
/* Determine the return code based on the Kiss-o'-Death code. */
|
||||
switch( pParsedResponse->rejectedResponseCode )
|
||||
{
|
||||
case KOD_CODE_DENY_UINT_VALUE:
|
||||
case KOD_CODE_RSTR_UINT_VALUE:
|
||||
status = SntpRejectedResponseChangeServer;
|
||||
break;
|
||||
|
||||
case KOD_CODE_RATE_UINT_VALUE:
|
||||
status = SntpRejectedResponseRetryWithBackoff;
|
||||
break;
|
||||
|
||||
default:
|
||||
status = SntpRejectedResponseOtherCode;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Server has responded successfully to the time request. */
|
||||
|
||||
SntpTimestamp_t serverRxTime;
|
||||
|
||||
/* Map of integer value to SntpLeapSecondInfo_t enumeration type for the
|
||||
* "Leap Indicator" field in the first byte of an SNTP packet.
|
||||
* Note: This map is used to not violate MISRA Rule 10.5 when directly
|
||||
* converting an integer to enumeration type.
|
||||
*/
|
||||
const SntpLeapSecondInfo_t leapIndicatorTypeMap[] =
|
||||
{
|
||||
NoLeapSecond,
|
||||
LastMinuteHas61Seconds,
|
||||
LastMinuteHas59Seconds,
|
||||
AlarmServerNotSynchronized
|
||||
};
|
||||
|
||||
/* Set the Kiss-o'-Death code value to NULL as server has responded favorably
|
||||
* to the time request. */
|
||||
pParsedResponse->rejectedResponseCode = SNTP_KISS_OF_DEATH_CODE_NONE;
|
||||
|
||||
/* Fill the output parameter with the server time which is the
|
||||
* "transmit" time in the response packet. */
|
||||
pParsedResponse->serverTime.seconds =
|
||||
readWordFromNetworkByteOrderMemory( &pResponsePacket->transmitTime.seconds );
|
||||
pParsedResponse->serverTime.fractions =
|
||||
readWordFromNetworkByteOrderMemory( &pResponsePacket->transmitTime.fractions );
|
||||
|
||||
/* Extract information of any upcoming leap second from the response. */
|
||||
pParsedResponse->leapSecondType = leapIndicatorTypeMap[
|
||||
( pResponsePacket->leapVersionMode >> SNTP_LEAP_INDICATOR_LSB_POSITION ) ];
|
||||
|
||||
/* Store the "receive" time in SNTP response packet in host order. */
|
||||
serverRxTime.seconds =
|
||||
readWordFromNetworkByteOrderMemory( &pResponsePacket->receiveTime.seconds );
|
||||
serverRxTime.fractions =
|
||||
readWordFromNetworkByteOrderMemory( &pResponsePacket->receiveTime.fractions );
|
||||
|
||||
/* Calculate system clock offset relative to server time, if possible, within
|
||||
* the 64 bit integer width of the SNTP timestamp. */
|
||||
calculateClockOffset( pRequestTxTime,
|
||||
&serverRxTime,
|
||||
&pParsedResponse->serverTime,
|
||||
pResponseRxTime,
|
||||
&pParsedResponse->clockOffsetMs );
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
SntpStatus_t Sntp_SerializeRequest( SntpTimestamp_t * pRequestTime,
|
||||
uint32_t randomNumber,
|
||||
void * pBuffer,
|
||||
size_t bufferSize )
|
||||
{
|
||||
SntpStatus_t status = SntpSuccess;
|
||||
|
||||
if( pRequestTime == NULL )
|
||||
{
|
||||
status = SntpErrorBadParameter;
|
||||
}
|
||||
else if( pBuffer == NULL )
|
||||
{
|
||||
status = SntpErrorBadParameter;
|
||||
}
|
||||
else if( bufferSize < SNTP_PACKET_BASE_SIZE )
|
||||
{
|
||||
status = SntpErrorBufferTooSmall;
|
||||
}
|
||||
|
||||
/* Zero timestamps for client request time is not allowed to protect against
|
||||
* attack spoofing server response containing zero value for "originate timestamp".
|
||||
* Note: In SNTP/NTP communication, the "originate timestamp" of a valid server response
|
||||
* matches the "transmit timestamp" in corresponding client request packet. */
|
||||
else if( isZeroTimestamp( pRequestTime ) == true )
|
||||
{
|
||||
status = SntpErrorBadParameter;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* MISRA Ref 11.5.1 [Void pointer assignment] */
|
||||
/* More details at: https://github.com/FreeRTOS/coreSNTP/blob/main/MISRA.md#rule-115 */
|
||||
/* coverity[misra_c_2012_rule_11_5_violation] */
|
||||
SntpPacket_t * pRequestPacket = ( SntpPacket_t * ) pBuffer;
|
||||
|
||||
/* Fill the buffer with zero as most fields are zero for a standard SNTP
|
||||
* request packet.*/
|
||||
( void ) memset( pBuffer, 0, sizeof( SntpPacket_t ) );
|
||||
|
||||
/* Set the first byte of the request packet for "Version" and "Mode" fields */
|
||||
pRequestPacket->leapVersionMode = 0U /* Leap Indicator */ |
|
||||
( SNTP_VERSION << SNTP_VERSION_LSB_POSITION ) /* Version Number */ |
|
||||
SNTP_MODE_CLIENT /* Mode */;
|
||||
|
||||
|
||||
/* Add passed random number to non-significant bits of the fractions part
|
||||
* of the transmit timestamp.
|
||||
* This is suggested by the SNTPv4 (and NTPv4) specification(s)
|
||||
* to protect against replay attacks. Refer to RFC 4330 Section 3 for
|
||||
* more information.
|
||||
* Adding random bits to the least significant 16 bits of the fractions
|
||||
* part of the timestamp affects only ~15 microseconds of information
|
||||
* (calculated as 0xFFFF * 232 picoseconds).
|
||||
*/
|
||||
pRequestTime->fractions = ( pRequestTime->fractions
|
||||
| ( randomNumber >> 16 ) );
|
||||
|
||||
/* Update the request buffer with request timestamp in network byte order. */
|
||||
fillWordMemoryInNetworkOrder( &pRequestPacket->transmitTime.seconds,
|
||||
pRequestTime->seconds );
|
||||
fillWordMemoryInNetworkOrder( &pRequestPacket->transmitTime.fractions,
|
||||
pRequestTime->fractions );
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
SntpStatus_t Sntp_DeserializeResponse( const SntpTimestamp_t * pRequestTime,
|
||||
const SntpTimestamp_t * pResponseRxTime,
|
||||
const void * pResponseBuffer,
|
||||
size_t bufferSize,
|
||||
SntpResponseData_t * pParsedResponse )
|
||||
{
|
||||
SntpStatus_t status = SntpSuccess;
|
||||
/* MISRA Ref 11.5.1 [Void pointer assignment] */
|
||||
/* More details at: https://github.com/FreeRTOS/coreSNTP/blob/main/MISRA.md#rule-115 */
|
||||
/* coverity[misra_c_2012_rule_11_5_violation] */
|
||||
const SntpPacket_t * pResponsePacket = ( const SntpPacket_t * ) pResponseBuffer;
|
||||
|
||||
if( ( pRequestTime == NULL ) || ( pResponseRxTime == NULL ) ||
|
||||
( pResponseBuffer == NULL ) || ( pParsedResponse == NULL ) )
|
||||
{
|
||||
status = SntpErrorBadParameter;
|
||||
}
|
||||
else if( bufferSize < SNTP_PACKET_BASE_SIZE )
|
||||
{
|
||||
status = SntpErrorBufferTooSmall;
|
||||
}
|
||||
|
||||
/* Zero timestamps for client request time is not allowed to protect against
|
||||
* attack spoofing server response containing zero value for "originate timestamp".
|
||||
* Note: In SNTP/NTP communication, the "originate timestamp" of a valid server response
|
||||
* matches the "transmit timestamp" in corresponding client request packet. */
|
||||
else if( isZeroTimestamp( pRequestTime ) == true )
|
||||
{
|
||||
status = SntpErrorBadParameter;
|
||||
}
|
||||
/* Check if the packet represents a server in the "Mode" field. */
|
||||
else if( ( pResponsePacket->leapVersionMode & SNTP_MODE_BITS_MASK ) != SNTP_MODE_SERVER )
|
||||
{
|
||||
status = SntpInvalidResponse;
|
||||
}
|
||||
|
||||
/* Check if any of the timestamps in the response packet are zero, which is invalid.
|
||||
* Note: This is done to protect against a nuanced server spoofing attack where if the
|
||||
* SNTP client resets its internal state of "Client transmit timestamp" (OR "originate
|
||||
* timestamp" from server perspective) to zero as a protection against replay attack, an
|
||||
* an attacker with this knowledge of the client operation can spoof a server response
|
||||
* containing the "originate timestamp" as zero. Thus, to protect against such attack,
|
||||
* a server response packet with any zero timestamp is rejected. */
|
||||
else if( ( isZeroTimestamp( &pResponsePacket->originTime ) == true ) ||
|
||||
( isZeroTimestamp( &pResponsePacket->receiveTime ) == true ) ||
|
||||
( isZeroTimestamp( &pResponsePacket->transmitTime ) == true ) )
|
||||
{
|
||||
status = SntpInvalidResponse;
|
||||
}
|
||||
|
||||
|
||||
/* Validate that the server has sent the client's request timestamp in the
|
||||
* "originate" timestamp field of the response. */
|
||||
else if( ( pRequestTime->seconds !=
|
||||
readWordFromNetworkByteOrderMemory( &pResponsePacket->originTime.seconds ) ) ||
|
||||
( pRequestTime->fractions !=
|
||||
readWordFromNetworkByteOrderMemory( &pResponsePacket->originTime.fractions ) ) )
|
||||
|
||||
{
|
||||
status = SntpInvalidResponse;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* As the response packet is valid, parse more information from it and
|
||||
* populate the output parameter. */
|
||||
|
||||
status = parseValidSntpResponse( pResponsePacket,
|
||||
pRequestTime,
|
||||
pResponseRxTime,
|
||||
pParsedResponse );
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
SntpStatus_t Sntp_CalculatePollInterval( uint16_t clockFreqTolerance,
|
||||
uint16_t desiredAccuracy,
|
||||
uint32_t * pPollInterval )
|
||||
{
|
||||
SntpStatus_t status = SntpSuccess;
|
||||
|
||||
if( ( clockFreqTolerance == 0U ) || ( desiredAccuracy == 0U ) || ( pPollInterval == NULL ) )
|
||||
{
|
||||
status = SntpErrorBadParameter;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t exactIntervalForAccuracy = 0U;
|
||||
uint8_t log2PollInterval = 0U;
|
||||
|
||||
/* Calculate the poll interval required for achieving the exact desired clock accuracy
|
||||
* with the following formulae:
|
||||
*
|
||||
* System Clock Drift Rate ( microseconds / second ) = Clock Frequency Tolerance (in PPM )
|
||||
* Maximum Clock Drift ( milliseconds ) = Desired Accuracy ( milliseconds )
|
||||
*
|
||||
* Poll Interval ( seconds ) = Maximum Clock Drift
|
||||
* ---------------------------
|
||||
* System Clock Drift Rate
|
||||
*
|
||||
* = Maximum Drift ( milliseconds ) * 1000 ( microseconds / millisecond )
|
||||
* ------------------------------------------------------------------------
|
||||
* System Clock Drift Rate ( microseconds / second )
|
||||
*
|
||||
* = Desired Accuracy * 1000
|
||||
* ------------------------------
|
||||
* Clock Frequency Tolerance
|
||||
*/
|
||||
exactIntervalForAccuracy = ( ( uint32_t ) desiredAccuracy * 1000U ) / clockFreqTolerance;
|
||||
|
||||
/* Check if calculated poll interval value falls in the supported range of seconds. */
|
||||
if( exactIntervalForAccuracy == 0U )
|
||||
{
|
||||
/* Poll interval value is less than 1 second, and is not supported by the function. */
|
||||
status = SntpZeroPollInterval;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* To calculate the log 2 value of the exact poll interval value, first determine the highest
|
||||
* bit set in the value. */
|
||||
while( exactIntervalForAccuracy != 0U )
|
||||
{
|
||||
log2PollInterval++;
|
||||
exactIntervalForAccuracy /= 2U;
|
||||
}
|
||||
|
||||
/* Convert the highest bit in the exact poll interval value to the nearest integer
|
||||
* value lower or equal to the log2 of the exact poll interval value. */
|
||||
log2PollInterval--;
|
||||
|
||||
/* Calculate the poll interval as the closest exponent of 2 value that achieves
|
||||
* equal or higher accuracy than the desired accuracy. */
|
||||
*pPollInterval = ( ( ( uint32_t ) 1U ) << log2PollInterval );
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
SntpStatus_t Sntp_ConvertToUnixTime( const SntpTimestamp_t * pSntpTime,
|
||||
uint32_t * pUnixTimeSecs,
|
||||
uint32_t * pUnixTimeMicrosecs )
|
||||
{
|
||||
SntpStatus_t status = SntpSuccess;
|
||||
|
||||
if( ( pSntpTime == NULL ) || ( pUnixTimeSecs == NULL ) || ( pUnixTimeMicrosecs == NULL ) )
|
||||
{
|
||||
status = SntpErrorBadParameter;
|
||||
}
|
||||
/* Check if passed time does not lie in the [UNIX epoch in 1970, UNIX time overflow in 2038] time range. */
|
||||
else if( ( pSntpTime->seconds > SNTP_TIME_AT_LARGEST_UNIX_TIME_SECS ) &&
|
||||
( pSntpTime->seconds < SNTP_TIME_AT_UNIX_EPOCH_SECS ) )
|
||||
{
|
||||
/* The SNTP timestamp is outside the supported time range for conversion. */
|
||||
status = SntpErrorTimeNotSupported;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Handle case when timestamp represents date in SNTP era 1
|
||||
* (i.e. time from 7 Feb 2036 6:28:16 UTC onwards). */
|
||||
if( pSntpTime->seconds <= SNTP_TIME_AT_LARGEST_UNIX_TIME_SECS )
|
||||
{
|
||||
/* Unix Time ( seconds ) = Seconds Duration in
|
||||
* [UNIX epoch, SNTP Era 1 Epoch Time]
|
||||
* +
|
||||
* Sntp Time since Era 1 Epoch
|
||||
*/
|
||||
*pUnixTimeSecs = UNIX_TIME_SECS_AT_SNTP_ERA_1_SMALLEST_TIME + pSntpTime->seconds;
|
||||
}
|
||||
/* Handle case when SNTP timestamp is in SNTP era 1 time range. */
|
||||
else
|
||||
{
|
||||
*pUnixTimeSecs = pSntpTime->seconds - SNTP_TIME_AT_UNIX_EPOCH_SECS;
|
||||
}
|
||||
|
||||
/* Convert SNTP fractions to microseconds for UNIX time. */
|
||||
*pUnixTimeMicrosecs = pSntpTime->fractions / SNTP_FRACTION_VALUE_PER_MICROSECOND;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
@ -0,0 +1,655 @@
|
||||
/*
|
||||
* coreSNTP v1.2.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 core_sntp_client.h
|
||||
* @brief API of an SNTPv4 client library that can send time requests and receive time response to/from
|
||||
* SNTP/NTP servers. The library follows the Best Practices suggested in the the SNTPv4 specification,
|
||||
* [RFC 4330](https://tools.ietf.org/html/rfc4330).
|
||||
* The library can be used to run an SNTP client in a dedicated deamon task to periodically synchronize
|
||||
* time from the Internet.
|
||||
*/
|
||||
|
||||
#ifndef CORE_SNTP_CLIENT_H_
|
||||
#define CORE_SNTP_CLIENT_H_
|
||||
|
||||
/* Standard include. */
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/* Include coreSNTP Serializer header. */
|
||||
#include "core_sntp_serializer.h"
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/* *INDENT-ON* */
|
||||
|
||||
/**
|
||||
* @ingroup sntp_constants
|
||||
* @brief The default UDP port supported by SNTP/NTP servers for client-server
|
||||
* communication.
|
||||
*
|
||||
* @note It is possible for a server to use a different port number than
|
||||
* the default port when using the Network Time Security protocol as the security
|
||||
* mechanism for SNTP communication. For more information, refer to Section 4.1.8
|
||||
* of [RFC 8915](https://tools.ietf.org/html/rfc8915).
|
||||
*/
|
||||
#define SNTP_DEFAULT_SERVER_PORT ( 123U )
|
||||
|
||||
/**
|
||||
* @ingroup sntp_struct_types
|
||||
* @brief Structure representing information for a time server.
|
||||
*/
|
||||
typedef struct SntpServerInfo
|
||||
{
|
||||
const char * pServerName; /**<@brief The time server name. */
|
||||
size_t serverNameLen; /**<@brief The length of the server name.*/
|
||||
uint16_t port; /**<@brief The UDP port supported by the server
|
||||
* for SNTP/NTP communication. */
|
||||
} SntpServerInfo_t;
|
||||
|
||||
/**
|
||||
* @ingroup sntp_callback_types
|
||||
* @brief Interface for user-defined function to resolve time server domain-name
|
||||
* to an IPv4 address.
|
||||
* The SNTP client library attempts to resolve the DNS of the time-server being
|
||||
* used every time the @ref Sntp_SendTimeRequest API is called.
|
||||
*
|
||||
* @param[in] pServerAddr The time-server whose IPv4 address is to be resolved.
|
||||
* @param[out] pIpV4Addr This should be filled with the resolved IPv4 address.
|
||||
* of @p pTimeServer.
|
||||
*
|
||||
* @return `true` if DNS resolution is successful; otherwise `false` to represent
|
||||
* failure.
|
||||
*/
|
||||
typedef bool ( * SntpResolveDns_t )( const SntpServerInfo_t * pServerAddr,
|
||||
uint32_t * pIpV4Addr );
|
||||
|
||||
/**
|
||||
* @ingroup sntp_callback_types
|
||||
* @brief Interface for user-defined function to obtain the current system time
|
||||
* in SNTP timestamp format.
|
||||
*
|
||||
* @note If your platform follows UNIX representation of time, the
|
||||
* #SNTP_TIME_AT_UNIX_EPOCH_SECS and #SNTP_FRACTION_VALUE_PER_MICROSECOND macros
|
||||
* can be used to convert UNIX time to SNTP timestamp.
|
||||
*
|
||||
* @param[out] pCurrentTime This should be filled with the current system time
|
||||
* in SNTP timestamp format.
|
||||
*
|
||||
* @return `true` if obtaining system time is successful; otherwise `false` to
|
||||
* represent failure.
|
||||
*/
|
||||
typedef void ( * SntpGetTime_t )( SntpTimestamp_t * pCurrentTime );
|
||||
|
||||
/**
|
||||
* @ingroup sntp_callback_types
|
||||
* @brief Interface for user-defined function to update the system clock time
|
||||
* so that it is synchronized the time server used for getting current time.
|
||||
*
|
||||
* @param[in] pTimeServer The time server used to request time.
|
||||
* @param[in] pServerTime The current time returned by the @p pTimeServer.
|
||||
* @param[in] clockOffsetMs The calculated clock offset (in milliseconds) of the
|
||||
* system relative to the server time.
|
||||
* @param[in] leapSecondInfo Information about whether there is about an upcoming
|
||||
* leap second adjustment of insertion or deletion in the last minute before midnight
|
||||
* on the last day of the current month. For more information on leap seconds, refer
|
||||
* to https://www.nist.gov/pml/time-and-frequency-division/leap-seconds-faqs. Depending
|
||||
* on the accuracy requirements of the system clock, the user can choose to account
|
||||
* for the leap second or ignore it in their system clock update logic.
|
||||
*
|
||||
* @note If the @p clockOffsetMs is positive, then the system time is BEHIND the server time,
|
||||
* and if the @p clockOffsetMs, the system time is AHEAD of the server time. To correct the
|
||||
* system time, the user can use either of "step", "slew" OR combination of the two clock
|
||||
* discipline methodologies depending on the application needs.
|
||||
* If the application requires a smooth time continuum of system time, then the "slew"
|
||||
* discipline methodology can be used with the clock offset value, @p clockOffSetMs, to correct
|
||||
* the system clock gradually with a "slew rate".
|
||||
* If the application can accept sudden jump in time (forward or backward), then
|
||||
* the "step" discipline methodology can be used to directly update the system
|
||||
* clock with the current server time, @p pServerTime, every time the coreSNTP library
|
||||
* calls the interface.
|
||||
*/
|
||||
typedef void ( * SntpSetTime_t )( const SntpServerInfo_t * pTimeServer,
|
||||
const SntpTimestamp_t * pServerTime,
|
||||
int64_t clockOffsetMs,
|
||||
SntpLeapSecondInfo_t leapSecondInfo );
|
||||
|
||||
/**
|
||||
* @ingroup sntp_struct_types
|
||||
* @typedef NetworkContext_t
|
||||
* @brief A user-defined type for context that is passed to the transport interface functions.
|
||||
* It MUST be defined by the user to use the library.
|
||||
* It is of incomplete type to allow user to define to the needs of their transport
|
||||
* interface implementation.
|
||||
*/
|
||||
struct NetworkContext;
|
||||
typedef struct NetworkContext NetworkContext_t;
|
||||
|
||||
/**
|
||||
* @ingroup sntp_callback_types
|
||||
* @brief Interface for user-defined function to send time request as a single datagram
|
||||
* to server on the network over User Datagram Protocol (UDP).
|
||||
*
|
||||
* @note It is RECOMMENDED that the send operation is non-blocking, i.e. it
|
||||
* SHOULD immediately return when the entire UDP data cannot be sent over the
|
||||
* network. In such a case, the coreSNTP library will re-try send operation
|
||||
* for a maximum period of blocking time passed to the @ref Sntp_SendTimeRequest API.
|
||||
*
|
||||
* @note If the size of the SNTP packet exceeds the Maximum Transmission Unit (MTU)
|
||||
* supported by the network interface of the device, the user-defined implementation
|
||||
* MAY either support fragmentation of UDP packets OR use a size for authentication data
|
||||
* that allows the SNTP packet to fit within the MTU required size threshold. (Note that
|
||||
* the size of SNTP packet is #SNTP_PACKET_BASE_SIZE + authentication data.)
|
||||
*
|
||||
* @param[in,out] pNetworkContext The user defined NetworkContext_t which
|
||||
* is opaque to the coreSNTP library.
|
||||
* @param[in] serverAddr The IPv4 address of the time server to send the data to.
|
||||
* @param[in] serverPort The port of the server to send data to.
|
||||
* @param[in] pBuffer The buffer containing the data to send over the network.
|
||||
* @param[in] bytesToSend The size of data in @p pBuffer to send.
|
||||
*
|
||||
* @return The function SHOULD return one of the following integer codes:
|
||||
* - @p bytesToSend when all requested data is successfully transmitted over the
|
||||
* network.
|
||||
* - 0 when no data could be sent over the network (due to network buffer being
|
||||
* full, for example), and the send operation can be retried.
|
||||
* - < 0 when the send operation failed to send any data due to an internal error,
|
||||
* and operation cannot be retried.
|
||||
*/
|
||||
typedef int32_t ( * UdpTransportSendTo_t )( NetworkContext_t * pNetworkContext,
|
||||
uint32_t serverAddr,
|
||||
uint16_t serverPort,
|
||||
const void * pBuffer,
|
||||
uint16_t bytesToSend );
|
||||
|
||||
/**
|
||||
* @ingroup sntp_callback_types
|
||||
* @brief Interface for user-defined function to receive the server response, to a time
|
||||
* request (sent through the @ref UdpTransportSendTo_t function), from the network over
|
||||
* User Datagram Protocol (UDP).
|
||||
*
|
||||
* @note It is RECOMMENDED that the read operation is non-blocking, i.e. it
|
||||
* SHOULD immediately return when no data is available on the network.
|
||||
* In such a case, the coreSNTP library will re-try send operation for a maximum period
|
||||
* of blocking time passed through the @ref Sntp_ReceiveTimeResponse API.
|
||||
*
|
||||
* @note If the size of the SNTP response packet from the server exceeds the
|
||||
* Maximum Transmission Unit (MTU) supported by the network interface of the device,
|
||||
* the user-defined implementation of the interface MAY either support receiving and
|
||||
* assembling fragmented UDP packets OR use an authentication data size that allows
|
||||
* SNTP packet to fit within the MTU required packet size threshold. (Note that
|
||||
* the size of SNTP packet is #SNTP_PACKET_BASE_SIZE + authentication data.)
|
||||
*
|
||||
* @param[in,out] pNetworkContext The user defined NetworkContext_t which
|
||||
* is opaque to the coreSNTP library.
|
||||
* @param[in] serverAddr The IPv4 address of the time server to receive data from.
|
||||
* @param[in] serverPort The port of the server to receive data from.
|
||||
* @param[out] pBuffer This SHOULD be filled with data received from the network.
|
||||
* @param[in] bytesToRecv The expected number of bytes to receive from the
|
||||
* server.
|
||||
*
|
||||
* @return The function SHOULD return one of the following integer codes:
|
||||
* - @p bytesToRecv value if all the requested number of bytes are received
|
||||
* from the network.
|
||||
* - ZERO when no data is available on the network, and the operation can be
|
||||
* retried.
|
||||
* - < 0 when the read operation failed due to internal error, and operation cannot
|
||||
* be retried.
|
||||
*/
|
||||
typedef int32_t ( * UdpTransportRecvFrom_t )( NetworkContext_t * pNetworkContext,
|
||||
uint32_t serverAddr,
|
||||
uint16_t serverPort,
|
||||
void * pBuffer,
|
||||
uint16_t bytesToRecv );
|
||||
|
||||
/**
|
||||
* @ingroup sntp_struct_types
|
||||
* @brief Struct representing the UDP transport interface for user-defined functions
|
||||
* that coreSNTP library depends on for performing read/write network operations.
|
||||
*/
|
||||
typedef struct UdpTransportIntf
|
||||
{
|
||||
NetworkContext_t * pUserContext; /**<@brief The user-defined context for storing
|
||||
* network socket information. */
|
||||
UdpTransportSendTo_t sendTo; /**<@brief The user-defined UDP send function. */
|
||||
UdpTransportRecvFrom_t recvFrom; /**<@brief The user-defined UDP receive function. */
|
||||
} UdpTransportInterface_t;
|
||||
|
||||
/**
|
||||
* @ingroup sntp_struct_types
|
||||
* @typedef SntpAuthContext_t
|
||||
* @brief A user-defined type for context that is passed to the authentication interface functions.
|
||||
* It MUST be defined by the user to use the library.
|
||||
* It is of incomplete type to allow user to defined to the the needs of their authentication
|
||||
* interface implementation.
|
||||
*/
|
||||
struct SntpAuthContext;
|
||||
typedef struct SntpAuthContext SntpAuthContext_t;
|
||||
|
||||
/**
|
||||
* @ingroup sntp_callback_types
|
||||
* @brief Interface for user-defined function to generate and append
|
||||
* authentication code in an SNTP request buffer for the SNTP client to be
|
||||
* authenticated by the time server, if a security mechanism is used.
|
||||
*
|
||||
* The user can choose to implement with any security mechanism, symmetric
|
||||
* key-based (like AES-CMAC) or asymmetric key-based (like Network Time Security),
|
||||
* depending on the security mechanism supported by the time server being used
|
||||
* to synchronize time with.
|
||||
*
|
||||
* @note The function SHOULD generate the authentication data for the first
|
||||
* #SNTP_PACKET_BASE_SIZE bytes of SNTP request packet present in the passed buffer
|
||||
* @p pBuffer, and fill the generated authentication data after #SNTP_PACKET_BASE_SIZE
|
||||
* bytes in the buffer.
|
||||
*
|
||||
* @param[in,out] pContext The user defined NetworkContext_t which
|
||||
* is opaque to the coreSNTP library.
|
||||
* @param[in] pTimeServer The time server being used to request time from.
|
||||
* This parameter is useful to choose the security mechanism when multiple time
|
||||
* servers are configured in the library, and they require different security
|
||||
* mechanisms or authentication credentials to use.
|
||||
* @param[in, out] pBuffer This buffer SHOULD be filled with the authentication
|
||||
* code generated from the #SNTP_PACKET_BASE_SIZE bytes of SNTP request data
|
||||
* present in it.
|
||||
* @param[in] bufferSize The maximum amount of data that can be held by the buffer,
|
||||
* @p pBuffer.
|
||||
* @param[out] pAuthCodeSize This should be filled with size of the authentication
|
||||
* data appended to the SNTP request buffer, @p pBuffer. This value plus
|
||||
* #SNTP_PACKET_BASE_SIZE should not exceed the buffer size, @p bufferSize.
|
||||
*
|
||||
* @return The function SHOULD return one of the following integer codes:
|
||||
* - #SntpSuccess when the authentication data is successfully appended to @p pBuffer.
|
||||
* - #SntpErrorBufferTooSmall when the user-supplied buffer (to the SntpContext_t through
|
||||
* @ref Sntp_Init) is not large enough to hold authentication data.
|
||||
* - #SntpErrorAuthFailure for failure to generate authentication data due to internal
|
||||
* error.
|
||||
*/
|
||||
typedef SntpStatus_t (* SntpGenerateAuthCode_t )( SntpAuthContext_t * pContext,
|
||||
const SntpServerInfo_t * pTimeServer,
|
||||
void * pBuffer,
|
||||
size_t bufferSize,
|
||||
uint16_t * pAuthCodeSize );
|
||||
|
||||
/**
|
||||
* @ingroup sntp_callback_types
|
||||
* @brief Interface for user-defined function to authenticate server by validating
|
||||
* the authentication code present in its SNTP response to a time request, if
|
||||
* a security mechanism is supported by the server.
|
||||
*
|
||||
* The user can choose to implement with any security mechanism, symmetric
|
||||
* key-based (like AES-CMAC) or asymmetric key-based (like Network Time Security),
|
||||
* depending on the security mechanism supported by the time server being used
|
||||
* to synchronize time with.
|
||||
*
|
||||
* @note In an SNTP response, the authentication code is present only after the
|
||||
* first #SNTP_PACKET_BASE_SIZE bytes. Depending on the security mechanism used,
|
||||
* the first #SNTP_PACKET_BASE_SIZE bytes MAY be used in validating the
|
||||
* authentication data sent by the server.
|
||||
*
|
||||
* @param[in,out] pContext The user defined NetworkContext_t which
|
||||
* is opaque to the coreSNTP library.
|
||||
* @param[in] pTimeServer The time server that has to be authenticated from its
|
||||
* SNTP response.
|
||||
* This parameter is useful to choose the security mechanism when multiple time
|
||||
* servers are configured in the library, and they require different security
|
||||
* mechanisms or authentication credentials to use.
|
||||
* @param[in] pResponseData The SNTP response from the server that contains the
|
||||
* authentication code after the first #SNTP_PACKET_BASE_SIZE bytes.
|
||||
* @param[in] responseSize The total size of the response from the server.
|
||||
*
|
||||
* @return The function SHOULD return one of the following integer codes:
|
||||
* - #SntpSuccess when the server is successfully authenticated.
|
||||
* - #SntpServerNotAuthenticated when server could not be authenticated.
|
||||
* - #SntpErrorAuthFailure for failure to authenticate server due to internal
|
||||
* error.
|
||||
*/
|
||||
typedef SntpStatus_t (* SntpValidateServerAuth_t )( SntpAuthContext_t * pContext,
|
||||
const SntpServerInfo_t * pTimeServer,
|
||||
const void * pResponseData,
|
||||
uint16_t responseSize );
|
||||
|
||||
/**
|
||||
* @ingroup sntp_struct_types
|
||||
* @brief Struct representing the authentication interface for securely
|
||||
* communicating with time servers.
|
||||
*
|
||||
* @note Using a security mechanism is OPTIONAL for using the coreSNTP
|
||||
* library i.e. a user does not need to define the authentication interface
|
||||
* if they are not using a security mechanism for SNTP communication.
|
||||
*/
|
||||
typedef struct SntpAuthenticationIntf
|
||||
{
|
||||
/**
|
||||
*@brief The user-defined context for storing information like
|
||||
* key credentials required for cryptographic operations in the
|
||||
* security mechanism used for communicating with server.
|
||||
*/
|
||||
SntpAuthContext_t * pAuthContext;
|
||||
|
||||
/**
|
||||
* @brief The user-defined function for appending client authentication data.
|
||||
* */
|
||||
SntpGenerateAuthCode_t generateClientAuth;
|
||||
|
||||
/**
|
||||
* @brief The user-defined function for authenticating server from its SNTP
|
||||
* response.
|
||||
*/
|
||||
SntpValidateServerAuth_t validateServerAuth;
|
||||
} SntpAuthenticationInterface_t;
|
||||
|
||||
/**
|
||||
* @ingroup sntp_struct_types
|
||||
* @brief Structure for a context that stores state for managing a long-running
|
||||
* SNTP client that periodically polls time and synchronizes system clock.
|
||||
*/
|
||||
typedef struct SntpContext
|
||||
{
|
||||
/**
|
||||
* @brief List of time servers in decreasing priority order configured
|
||||
* for the SNTP client.
|
||||
* Only a single server is configured for use at a time across polling
|
||||
* attempts until the server rejects a time request or there is a response
|
||||
* timeout, after which, the next server in the list is used for subsequent
|
||||
* polling requests.
|
||||
*/
|
||||
const SntpServerInfo_t * pTimeServers;
|
||||
|
||||
/**
|
||||
* @brief Number of servers configured for use.
|
||||
*/
|
||||
size_t numOfServers;
|
||||
|
||||
/**
|
||||
* @brief The index for the currently configured time server for time querying
|
||||
* from the list of time servers in @ref pTimeServers.
|
||||
*/
|
||||
size_t currentServerIndex;
|
||||
|
||||
/**
|
||||
* @brief The user-supplied buffer for storing network data of both SNTP requests
|
||||
* and SNTP response.
|
||||
*/
|
||||
uint8_t * pNetworkBuffer;
|
||||
|
||||
/**
|
||||
* @brief The size of the network buffer.
|
||||
*/
|
||||
size_t bufferSize;
|
||||
|
||||
/**
|
||||
* @brief The user-supplied function for resolving DNS name of time servers.
|
||||
*/
|
||||
SntpResolveDns_t resolveDnsFunc;
|
||||
|
||||
/**
|
||||
* @brief The user-supplied function for obtaining the current system time.
|
||||
*/
|
||||
SntpGetTime_t getTimeFunc;
|
||||
|
||||
/**
|
||||
* @brief The user-supplied function for correcting system time after receiving
|
||||
* time from a server.
|
||||
*/
|
||||
SntpSetTime_t setTimeFunc;
|
||||
|
||||
/**
|
||||
* @brief The user-defined interface for performing User Datagram Protocol (UDP)
|
||||
* send and receive network operations.
|
||||
*/
|
||||
UdpTransportInterface_t networkIntf;
|
||||
|
||||
/**
|
||||
* @brief The user-defined interface for incorporating security mechanism of
|
||||
* adding client authentication in SNTP request as well as authenticating server
|
||||
* from SNTP response.
|
||||
*
|
||||
* @note If the application will not use security mechanism for any of the
|
||||
* configured servers, then this interface can be undefined.
|
||||
*/
|
||||
SntpAuthenticationInterface_t authIntf;
|
||||
|
||||
/**
|
||||
* @brief Cache of the resolved Ipv4 address of the current server being used for
|
||||
* time synchronization.
|
||||
* As a Best Practice functionality, the client library attempts to resolve the
|
||||
* DNS of the time-server every time the @ref Sntp_SendTimeRequest API is called.
|
||||
*/
|
||||
uint32_t currentServerAddr;
|
||||
|
||||
/**
|
||||
* @brief Cache of the timestamp of sending the last time request to a server
|
||||
* for replay attack protection by checking that the server response contains
|
||||
* the same timestamp in its "originate timestamp" field.
|
||||
*/
|
||||
SntpTimestamp_t lastRequestTime;
|
||||
|
||||
/**
|
||||
* @brief State member for storing the size of the SNTP packet that includes
|
||||
* both #SNTP_PACKET_BASE_SIZE bytes plus any authentication data, if a security
|
||||
* mechanism is used.
|
||||
* This value is used for expecting the same size for an SNTP response
|
||||
* from the server.
|
||||
*/
|
||||
uint16_t sntpPacketSize;
|
||||
|
||||
/**
|
||||
* @brief The timeout duration (in milliseconds) for receiving a response, through
|
||||
* @ref Sntp_ReceiveTimeResponse API, from a server after the request for time is
|
||||
* sent to it through @ref Sntp_SendTimeRequest API.
|
||||
*/
|
||||
uint32_t responseTimeoutMs;
|
||||
} SntpContext_t;
|
||||
|
||||
/**
|
||||
* @brief Initializes a context for SNTP client communication with SNTP/NTP
|
||||
* servers.
|
||||
*
|
||||
* @param[out] pContext The user-supplied memory for the context that will be
|
||||
* initialized to represent an SNTP client.
|
||||
* @param[in] pTimeServers The list of decreasing order of priority of time
|
||||
* servers that should be used by the SNTP client. This list MUST stay in
|
||||
* scope for all the time of use of the context.
|
||||
* @param[in] numOfServers The number of servers in the list, @p pTimeServers.
|
||||
* @param[in] serverResponseTimeoutMs The timeout duration (in milliseconds) for
|
||||
* receiving server response for time requests. The same timeout value is used for
|
||||
* each server in the @p pTimeServers list.
|
||||
* @param[in] pNetworkBuffer The user-supplied memory that will be used for
|
||||
* storing network data for SNTP client-server communication. The buffer
|
||||
* MUST stay in scope for all the time of use of the context.
|
||||
* @param[in] bufferSize The size of the passed buffer @p pNetworkBuffer. The buffer
|
||||
* SHOULD be appropriately sized for storing an entire SNTP packet which includes
|
||||
* both #SNTP_PACKET_BASE_SIZE bytes of standard SNTP packet size, and space for
|
||||
* authentication data, if security mechanism is used to communicate with any of
|
||||
* the time servers configured for use.
|
||||
* @param[in] resolveDnsFunc The user-defined function for DNS resolution of time
|
||||
* server.
|
||||
* @param[in] getSystemTimeFunc The user-defined function for querying system
|
||||
* time.
|
||||
* @param[in] setSystemTimeFunc The user-defined function for correcting system
|
||||
* time for every successful time response received from a server.
|
||||
* @param[in] pTransportIntf The user-defined function for performing network
|
||||
* send/recv operations over UDP.
|
||||
* @param[in] pAuthIntf The user-defined interface for generating client authentication
|
||||
* in SNTP requests and authenticating servers in SNTP responses, if security mechanism
|
||||
* is used in SNTP communication with server(s). If security mechanism is not used in
|
||||
* communication with any of the configured servers (in @p pTimeServers), then the
|
||||
* @ref SntpAuthenticationInterface_t does not need to be defined and this parameter
|
||||
* can be NULL.
|
||||
*
|
||||
* @return This function returns one of the following:
|
||||
* - #SntpSuccess if the context is initialized.
|
||||
* - #SntpErrorBadParameter if any of the passed parameters in invalid.
|
||||
* - #SntpErrorBufferTooSmall if the buffer does not have the minimum size
|
||||
* required for a valid SNTP response packet.
|
||||
*/
|
||||
/* @[define_sntp_init] */
|
||||
SntpStatus_t Sntp_Init( SntpContext_t * pContext,
|
||||
const SntpServerInfo_t * pTimeServers,
|
||||
size_t numOfServers,
|
||||
uint32_t serverResponseTimeoutMs,
|
||||
uint8_t * pNetworkBuffer,
|
||||
size_t bufferSize,
|
||||
SntpResolveDns_t resolveDnsFunc,
|
||||
SntpGetTime_t getSystemTimeFunc,
|
||||
SntpSetTime_t setSystemTimeFunc,
|
||||
const UdpTransportInterface_t * pTransportIntf,
|
||||
const SntpAuthenticationInterface_t * pAuthIntf );
|
||||
/* @[define_sntp_init] */
|
||||
|
||||
|
||||
/**
|
||||
* @brief Sends a request for time from the currently configured server (in the
|
||||
* context).
|
||||
* If the user has provided an authentication interface, the client
|
||||
* authentication code is appended to the request before sending over the network
|
||||
* by calling the @ref SntpGenerateAuthCode_t function of the
|
||||
* @ref SntpAuthenticationInterface_t.
|
||||
*
|
||||
* @note This function will ONLY send a request if there is a server available
|
||||
* in the configured list that has not rejected an earlier request for time.
|
||||
* This adheres to the Best Practice functionality specified in [Section 10 Point 8
|
||||
* of SNTPv4 specification](https://tools.ietf.org/html/rfc4330#section-10).
|
||||
*
|
||||
* @param[in] pContext The context representing an SNTPv4 client.
|
||||
* @param[in] randomNumber A random number serializing the SNTP request packet
|
||||
* to protect against spoofing attacks by attackers that are off the network path
|
||||
* of the SNTP client-server communication. This mechanism is suggested by SNTPv4
|
||||
* specification in [RFC 4330 Section 3](https://tools.ietf.org/html/rfc4330#section-3).
|
||||
* @param[in] blockTimeMs The maximum duration of time (in milliseconds) the function will
|
||||
* block on attempting to send time request to the server over the network. If a zero
|
||||
* block time value is provided, then the function will attempt to send the packet ONLY
|
||||
* once.
|
||||
*
|
||||
* @note It is RECOMMENDED that a True Random Number Generator is used to generate the
|
||||
* random number by using a hardware module, like Hardware Security Module (HSM), Secure Element,
|
||||
* etc, as the entropy source.
|
||||
*
|
||||
* @return The API function returns one of the following:
|
||||
* - #SntpSuccess if a time request is successfully sent to the currently configured
|
||||
* time server in the context.
|
||||
* - #SntpErrorBadParameter if an invalid context is passed to the function.
|
||||
* - #SntpErrorContextNotInitialized if an uninitialized or invalid context is passed
|
||||
* to the function.
|
||||
* - #SntpErrorDnsFailure if there is failure in the user-defined function for
|
||||
* DNS resolution of the time server.
|
||||
* - #SntpErrorNetworkFailure if the SNTP request could not be sent over the network
|
||||
* through the user-defined transport interface.
|
||||
* - #SntpErrorAuthFailure if there was a failure in generating the client
|
||||
* authentication code in the user-defined authentication interface.
|
||||
* - #SntpErrorSendTimeout if the time request packet could not be sent over the
|
||||
* network for the entire @p blockTimeMs duration.
|
||||
*/
|
||||
/* @[define_sntp_sendtimerequest] */
|
||||
SntpStatus_t Sntp_SendTimeRequest( SntpContext_t * pContext,
|
||||
uint32_t randomNumber,
|
||||
uint32_t blockTimeMs );
|
||||
/* @[define_sntp_sendtimerequest] */
|
||||
|
||||
|
||||
/**
|
||||
* @brief Receives a time response from the server that has been requested for time with
|
||||
* the @ref Sntp_SendTimeRequest API function.
|
||||
* Once an accepted response containing time from server is received, this function calls
|
||||
* the user-defined @ref SntpSetTime_t function to update the system time.
|
||||
*
|
||||
* @note If the user has provided an authentication interface to the client
|
||||
* (through @ref Sntp_Init), the server response is authenticated by calling the
|
||||
* @ref SntpValidateServerAuth_t function of the @ref SntpAuthenticationInterface_t interface.
|
||||
*
|
||||
* @note On receiving a successful server response containing server time,
|
||||
* this API calculates the clock offset value of the system clock relative to the
|
||||
* server before calling the user-defined @ref SntpSetTime_t function for updating
|
||||
* the system time.
|
||||
*
|
||||
* @note For correct calculation of clock-offset, the server and client times MUST be within
|
||||
* ~68 years (or 2^31 seconds) of each other. In the special case when the server and client
|
||||
* times are exactly 2^31 seconds apart, the library ASSUMES that the server time is ahead
|
||||
* of the client time, and returns the positive clock-offset value of INT32_MAX seconds.
|
||||
*
|
||||
* @note This API will rotate the server of use in the library for the next time request
|
||||
* (through the @ref Sntp_SendTimeRequest) if either of following events occur:
|
||||
* - The server has responded with a rejection for the time request.
|
||||
* OR
|
||||
* - The server response wait has timed out.
|
||||
* If all the servers configured in the context have been used, the API will rotate server for
|
||||
* time query back to the first server in the list which will be used in next time request.
|
||||
*
|
||||
* @param[in] pContext The context representing an SNTPv4 client.
|
||||
* @param[in] blockTimeMs The maximum duration of time (in milliseconds) the function will
|
||||
* block on receiving a response from the server unless either the response is received
|
||||
* OR a response timeout occurs.
|
||||
*
|
||||
* @note This function can be called multiple times with zero or small blocking times
|
||||
* to poll whether server response is received until either the response response is
|
||||
* received from the server OR a response timeout has occurred.
|
||||
*
|
||||
* @return This API functions returns one of the following:
|
||||
* - #SntpSuccess if a successful server response is received.
|
||||
* - #SntpErrorContextNotInitialized if an uninitialized or invalid context is passed
|
||||
* to the function.
|
||||
* - #SntpErrorBadParameter if an invalid context is passed to the function.
|
||||
* - #SntpErrorNetworkFailure if there is a failure in the user-defined transport
|
||||
* - #SntpErrorAuthFailure if an internal error occurs in the user-defined
|
||||
* authentication interface when validating the server response.
|
||||
* - #SntpServerNotAuthenticated when the server could not be authenticated from
|
||||
* its response with the user-defined authentication interface.
|
||||
* - #SntpInvalidResponse if the server response fails sanity checks expected in an
|
||||
* SNTP response packet.
|
||||
* - #SntpErrorResponseTimeout if a timeout has occurred in receiving response from
|
||||
* the server.
|
||||
* - #SntpRejectedResponse if the server responded with a rejection for the time
|
||||
* request.
|
||||
*/
|
||||
/* @[define_sntp_receivetimeresponse] */
|
||||
SntpStatus_t Sntp_ReceiveTimeResponse( SntpContext_t * pContext,
|
||||
uint32_t blockTimeMs );
|
||||
/* @[define_sntp_receivetimeresponse] */
|
||||
|
||||
/**
|
||||
* @brief Converts @ref SntpStatus_t to its equivalent
|
||||
* string.
|
||||
*
|
||||
* @note The returned string MUST NOT be modified.
|
||||
*
|
||||
* @param[in] status The status to convert to a string.
|
||||
*
|
||||
* @return The string representation of the status
|
||||
* code.
|
||||
*/
|
||||
/* @[define_sntp_statustostr] */
|
||||
const char * Sntp_StatusToStr( SntpStatus_t status );
|
||||
/* @[define_sntp_statustostr] */
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
/* *INDENT-ON* */
|
||||
|
||||
#endif /* ifndef CORE_SNTP_CLIENT_H_ */
|
||||
@ -0,0 +1,144 @@
|
||||
/*
|
||||
* coreSNTP v1.2.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 core_sntp_config_defaults.h
|
||||
* @brief This file represents the default values for the configuration macros
|
||||
* of the coreSNTP library.
|
||||
*
|
||||
* @note This file SHOULD NOT be modified. If custom values are needed for
|
||||
* any configuration macro, a core_sntp_config.h file should be provided to
|
||||
* the SNTP library to override the default values defined in this file.
|
||||
* To build the library with the core_sntp_config.h file, make sure to
|
||||
* not set the SNTP_DO_NOT_USE_CUSTOM_CONFIG preprocessor macro.
|
||||
*/
|
||||
|
||||
#ifndef CORE_SNTP_CONFIG_DEFAULTS_H_
|
||||
#define CORE_SNTP_CONFIG_DEFAULTS_H_
|
||||
|
||||
/* The macro definition for SNTP_DO_NOT_USE_CUSTOM_CONFIG is for Doxygen
|
||||
* documentation only. */
|
||||
|
||||
/**
|
||||
* @brief Define this macro to build the SNTP library without the custom config
|
||||
* file core_sntp_config.h.
|
||||
*
|
||||
* Without the custom config, the SNTP library builds with
|
||||
* default values of config macros defined in core_sntp_config_defaults.h file.
|
||||
*
|
||||
* If a custom config is provided, then SNTP_DO_NOT_USE_CUSTOM_CONFIG should not
|
||||
* be defined.
|
||||
*/
|
||||
#ifdef DOXYGEN
|
||||
#define SNTP_DO_NOT_USE_CUSTOM_CONFIG
|
||||
#endif
|
||||
|
||||
/* SNTP_DO_NOT_USE_CUSTOM_CONFIG allows building the SNTP library
|
||||
* without a custom config. If a custom config is provided, the
|
||||
* SNTP_DO_NOT_USE_CUSTOM_CONFIG macro should not be defined. */
|
||||
#ifndef SNTP_DO_NOT_USE_CUSTOM_CONFIG
|
||||
#include "core_sntp_config.h"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Macro that is called in the SNTP library for logging "Error" level
|
||||
* messages.
|
||||
*
|
||||
* To enable error level logging in the SNTP library, this macro should be mapped to the
|
||||
* application-specific logging implementation that supports error logging.
|
||||
*
|
||||
* @note This logging macro is called in the SNTP 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 core_sntp_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 SNTP library on compilation.
|
||||
*/
|
||||
#ifndef LogError
|
||||
#define LogError( message )
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Macro that is called in the SNTP library for logging "Warning" level
|
||||
* messages.
|
||||
*
|
||||
* To enable warning level logging in the SNTP library, this macro should be mapped to the
|
||||
* application-specific logging implementation that supports warning logging.
|
||||
*
|
||||
* @note This logging macro is called in the SNTP 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 core_sntp_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 SNTP library on compilation.
|
||||
*/
|
||||
#ifndef LogWarn
|
||||
#define LogWarn( message )
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Macro that is called in the SNTP library for logging "Info" level
|
||||
* messages.
|
||||
*
|
||||
* To enable info level logging in the SNTP library, this macro should be mapped to the
|
||||
* application-specific logging implementation that supports info logging.
|
||||
*
|
||||
* @note This logging macro is called in the SNTP 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 core_sntp_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 SNTP library on compilation.
|
||||
*/
|
||||
#ifndef LogInfo
|
||||
#define LogInfo( message )
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Macro that is called in the SNTP library for logging "Debug" level
|
||||
* messages.
|
||||
*
|
||||
* To enable debug level logging from SNTP library, this macro should be mapped to the
|
||||
* application-specific logging implementation that supports debug logging.
|
||||
*
|
||||
* @note This logging macro is called in the SNTP 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 core_sntp_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 SNTP library on compilation.
|
||||
*/
|
||||
#ifndef LogDebug
|
||||
#define LogDebug( message )
|
||||
#endif
|
||||
|
||||
#endif /* ifndef CORE_SNTP_CONFIG_DEFAULTS_H_ */
|
||||
@ -0,0 +1,535 @@
|
||||
/*
|
||||
* coreSNTP v1.2.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 core_sntp_serializer.h
|
||||
* @brief API for serializing SNTP request packets and, and de-serializing SNTP
|
||||
* response packets.
|
||||
* This API layer adheres to the SNTPv4 specification defined in
|
||||
* [RFC 4330](https://tools.ietf.org/html/rfc4330).
|
||||
*/
|
||||
|
||||
#ifndef CORE_SNTP_SERIALIZER_H_
|
||||
#define CORE_SNTP_SERIALIZER_H_
|
||||
|
||||
/* Standard include. */
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/* *INDENT-ON* */
|
||||
|
||||
/**
|
||||
* @ingroup sntp_constants
|
||||
* @brief The base packet size of request and response of the (S)NTP protocol.
|
||||
* @note This is the packet size without any authentication headers for security
|
||||
* mechanism. If the application uses a security mechanism for communicating with
|
||||
* an (S)NTP server, it can add authentication data after the SNTP packet is
|
||||
* serialized with the @ref Sntp_SerializeRequest API function.
|
||||
*/
|
||||
#define SNTP_PACKET_BASE_SIZE ( 48U )
|
||||
|
||||
/**
|
||||
* @ingroup sntp_constants
|
||||
* @brief Number of SNTP timestamp fractions in 1 microsecond.
|
||||
*
|
||||
* The fraction's part of an SNTP timestamp is 32-bits wide, thereby, giving a
|
||||
* resolution of 2^(-32) seconds ~ 232 picoseconds.
|
||||
*
|
||||
* @note The application can use this value to convert microseconds part of system
|
||||
* time into SNTP timestamp fractions. For example, if the microseconds
|
||||
* part of system time is n microseconds, the fractions value to be used for the
|
||||
* SNTP timestamp part will be n * SNTP_FRACTION_VALUE_PER_MICROSECOND.
|
||||
*/
|
||||
#define SNTP_FRACTION_VALUE_PER_MICROSECOND ( 4295U )
|
||||
|
||||
/**
|
||||
* @ingroup sntp_constants
|
||||
* @brief The seconds part of SNTP time at the UNIX epoch time, which represents
|
||||
* an offset of 70 years (in seconds) between SNTP epoch and UNIX epoch time.
|
||||
* SNTP uses 1st Jan 1900 UTC as the epoch time, whereas UNIX standard uses
|
||||
* 1st Jan 1970 UTC as the epoch time, thereby, causing an offset of 70 years
|
||||
* between them.
|
||||
*
|
||||
* Difference of 70 years = ((70 * 365) + 17 leap days) * 24 * 3600 seconds
|
||||
*
|
||||
* @note If your system follows UNIX time, the application can use this value to
|
||||
* convert seconds part of a system time to seconds part of the equivalent SNTP
|
||||
* time. For example, if the seconds part of system time is n seconds, the seconds
|
||||
* value to be used for the SNTP timestamp will be n + SNTP_TO_UNIX_OFFSET_SECS.
|
||||
*/
|
||||
#define SNTP_TIME_AT_UNIX_EPOCH_SECS ( 2208988800U )
|
||||
|
||||
/**
|
||||
* @ingroup sntp_constants
|
||||
* @brief The seconds value of SNTP timestamp for the largest UNIX time when
|
||||
* using signed 32-bit integer for seconds.
|
||||
* The largest time representable with a 32-bit signed integer in UNIX time
|
||||
* is 19 Jan 2038 3h 14m 7s UTC. However, as the SNTP time overflows at
|
||||
* 7 Feb 2036 6h 28m 16s UTC, therefore, the SNTP time for the largest UNIX time
|
||||
* represents the time duration between the 2 timestamps.
|
||||
*
|
||||
* SNTP Time at Largest Time Duration in the range
|
||||
* Signed 32-bit UNIX time = [7 Feb 2036 6:28:16, 19 Jan 2038 3:14:07]
|
||||
*/
|
||||
#define SNTP_TIME_AT_LARGEST_UNIX_TIME_SECS ( 61505151U )
|
||||
|
||||
/**
|
||||
* @ingroup sntp_constants
|
||||
* @brief The UNIX time (in seconds) at the smallest SNTP time in era 1,
|
||||
* i.e. UNIX time at 7 Feb 2036 6:28:16 UTC/
|
||||
*
|
||||
* Time Duration = 7 Feb 6:28:16 UTC (SNTP Era 1 Epoch) -
|
||||
* 1 Jan 1970 0:0:0 UTC (UNIX epoch)
|
||||
* = 66 years, 37 days, 6 hours, 28 minutes and 16 seconds
|
||||
* = ((66 * 365) + 16 leap days) * 24 * 3600) + (6 * 3600)
|
||||
* + (28 * 60) + 16
|
||||
*/
|
||||
#define UNIX_TIME_SECS_AT_SNTP_ERA_1_SMALLEST_TIME ( 2085978496U )
|
||||
|
||||
/**
|
||||
* @ingroup sntp_constants
|
||||
* @brief The fixed-length of any Kiss-o'-Death message ASCII code sent
|
||||
* in an SNTP server response.
|
||||
* @note An SNTP server sends a Kiss-o'-Death message to reject a time request
|
||||
* from the client. For more information on the Kiss-o'-Death codes, refer to the
|
||||
* [SNTPv4 specification Section 8](https://tools.ietf.org/html/rfc4330#section-8).
|
||||
*/
|
||||
#define SNTP_KISS_OF_DEATH_CODE_LENGTH ( 4U )
|
||||
|
||||
/**
|
||||
* @ingroup sntp_constants
|
||||
* @brief The value for the #SntpResponseData_t.rejectedResponseCode member
|
||||
* when that the server response packet does not contain a Kiss-o'-Death
|
||||
* message, and therefore, does not have a "kiss code".
|
||||
* The server sends a "kiss-code" only when it rejects an SNTP request
|
||||
* with a Kiss-o'-Death message.
|
||||
*/
|
||||
#define SNTP_KISS_OF_DEATH_CODE_NONE ( 0U )
|
||||
|
||||
/**
|
||||
* @ingroup sntp_enum_types
|
||||
* @brief Enumeration of status codes that can be returned
|
||||
* by the coreSNTP Library API.
|
||||
*/
|
||||
typedef enum SntpStatus
|
||||
{
|
||||
/**
|
||||
* @brief Successful operation of an SNTP API.
|
||||
*/
|
||||
SntpSuccess,
|
||||
|
||||
/**
|
||||
* @brief Invalid parameter passed to an API function.
|
||||
*/
|
||||
SntpErrorBadParameter,
|
||||
|
||||
/**
|
||||
* @brief Server sent a Kiss-o'-Death message to reject the request for time.
|
||||
* This status can be returned by the @ref Sntp_ReceiveTimeResponse API.
|
||||
*/
|
||||
SntpRejectedResponse,
|
||||
|
||||
/**
|
||||
* @brief Server sent a Kiss-o'-Death message with non-retryable code (i.e. DENY or RSTR).
|
||||
*/
|
||||
SntpRejectedResponseChangeServer,
|
||||
|
||||
/**
|
||||
* @brief Server sent a Kiss-o'-Death message with a RATE code, which means that
|
||||
* client should back-off before retrying.
|
||||
*/
|
||||
SntpRejectedResponseRetryWithBackoff,
|
||||
|
||||
/**
|
||||
* @brief Server sent a Kiss-o'-Death message with a code, specific to the server.
|
||||
* Application can inspect the ASCII kiss-code from @ref Sntp_DeserializeResponse API.
|
||||
*/
|
||||
SntpRejectedResponseOtherCode,
|
||||
|
||||
/**
|
||||
* @brief Application provided insufficient buffer space for serializing
|
||||
* or de-serializing an SNTP packet.
|
||||
* The minimum size of an SNTP packet is #SNTP_PACKET_BASE_SIZE
|
||||
* bytes. */
|
||||
SntpErrorBufferTooSmall,
|
||||
|
||||
/**
|
||||
* @brief Server response failed validation checks for expected data in SNTP packet.
|
||||
*/
|
||||
SntpInvalidResponse,
|
||||
|
||||
/**
|
||||
* @brief Poll interval value is under 1 second which cannot be calculated
|
||||
* by @ref Sntp_CalculatePollInterval.
|
||||
*/
|
||||
SntpZeroPollInterval,
|
||||
|
||||
/**
|
||||
* @brief SNTP timestamp cannot be converted to UNIX time as time does not lie
|
||||
* in time range supported by Sntp_ConvertToUnixTime.
|
||||
*/
|
||||
SntpErrorTimeNotSupported,
|
||||
|
||||
/**
|
||||
* @brief The user-defined DNS resolution interface, @ref SntpResolveDns_t, failed to resolve
|
||||
* address for a time server. This status is returned by the @ref Sntp_SendTimeRequest API.
|
||||
*/
|
||||
SntpErrorDnsFailure,
|
||||
|
||||
/**
|
||||
* @brief Networking operation of sending or receiving SNTP packet through the user-defined UDP
|
||||
* transport interface, @ref UdpTransportInterface_t, failed.
|
||||
* This status is returned by either of @ref Sntp_SendTimeRequest OR @ref Sntp_ReceiveTimeResponse
|
||||
* APIs.
|
||||
*/
|
||||
SntpErrorNetworkFailure,
|
||||
|
||||
/**
|
||||
* @brief Time server is not authenticated from the authentication data in its response.
|
||||
* This status can be returned by the user-supplied definition of the
|
||||
* @ref SntpValidateServerAuth_t authentication interface.
|
||||
*/
|
||||
SntpServerNotAuthenticated,
|
||||
|
||||
/**
|
||||
* @brief Failure from the user-supplied authentication interface, @ref SntpAuthenticationInterface_t,
|
||||
* in either generating authentication data for SNTP request OR validating the authentication
|
||||
* data in SNTP response from server.
|
||||
*/
|
||||
SntpErrorAuthFailure,
|
||||
|
||||
/**
|
||||
* @brief A timeout occurred in sending time request packet over the network to a server through the
|
||||
* @ref Sntp_SendTimeRequest API.
|
||||
*/
|
||||
SntpErrorSendTimeout,
|
||||
|
||||
/**
|
||||
* @brief A timeout has occurred in receiving server response with the @ref Sntp_ReceiveTimeResponse
|
||||
* API.
|
||||
*/
|
||||
SntpErrorResponseTimeout,
|
||||
|
||||
/**
|
||||
* @brief No SNTP packet for server response is received from the network by the
|
||||
* @ref Sntp_ReceiveTimeResponse API.
|
||||
*/
|
||||
SntpNoResponseReceived,
|
||||
|
||||
/**
|
||||
* @brief The SNTP context passed to @ref Sntp_SendTimeRequest or @ref Sntp_ReceiveTimeResponse APIs is
|
||||
* is uninitialized.
|
||||
*/
|
||||
SntpErrorContextNotInitialized
|
||||
} SntpStatus_t;
|
||||
|
||||
/**
|
||||
* @ingroup sntp_enum_types
|
||||
* @brief Enumeration for leap second information that an SNTP server can
|
||||
* send its response to a time request. An SNTP server sends information about
|
||||
* whether there is an upcoming leap second adjustment in the last day of the
|
||||
* current month.
|
||||
*
|
||||
* @note A leap second is an adjustment made in atomic clock time because Earth's rotation
|
||||
* can be inconsistent. Leap seconds are usually incorporated as an extra second insertion
|
||||
* or second deletion in the last minute before midnight i.e. in the minute of 23h:59m UTC
|
||||
* on the last day of June or December. For more information on leap seconds, refer to
|
||||
* https://www.nist.gov/pml/time-and-frequency-division/leap-seconds-faqs.
|
||||
*/
|
||||
typedef enum SntpLeapSecondInfo
|
||||
{
|
||||
NoLeapSecond = 0x00, /** <@brief There is no upcoming leap second adjustment. */
|
||||
LastMinuteHas61Seconds = 0x01, /** <@brief A leap second should be inserted in the last minute before midnight. */
|
||||
LastMinuteHas59Seconds = 0x02, /** <@brief A leap second should be deleted from the last minute before midnight. */
|
||||
AlarmServerNotSynchronized = 0x03 /** <@brief An alarm condition meaning that server's time is not synchronized
|
||||
* to an upstream NTP (or SNTP) server. */
|
||||
} SntpLeapSecondInfo_t;
|
||||
|
||||
/**
|
||||
* @ingroup sntp_struct_types
|
||||
* @brief Structure representing an SNTP timestamp.
|
||||
*
|
||||
* @note The SNTP timestamp uses 1st January 1900 0h 0m 0s Coordinated Universal Time (UTC)
|
||||
* as the primary epoch i.e. the timestamp represents current time as the amount of time since
|
||||
* the epoch time.
|
||||
* Refer to the [SNTPv4 specification](https://tools.ietf.org/html/rfc4330#section-3) for more
|
||||
* information of the SNTP timestamp format.
|
||||
*/
|
||||
typedef struct SntpTimestamp
|
||||
{
|
||||
uint32_t seconds; /**< @brief Number of seconds since epoch time. */
|
||||
uint32_t fractions; /**< @brief The fractions part of the SNTP timestamp with resolution
|
||||
* of 2^(-32) ~ 232 picoseconds. */
|
||||
} SntpTimestamp_t;
|
||||
|
||||
/**
|
||||
* @ingroup sntp_struct_types
|
||||
* @brief Structure representing data parsed from an SNTP response from server
|
||||
* as well as data of arithmetic calculations derived from the response.
|
||||
*/
|
||||
typedef struct SntpResponse
|
||||
{
|
||||
/**
|
||||
* @brief The timestamp sent by the server.
|
||||
*/
|
||||
SntpTimestamp_t serverTime;
|
||||
|
||||
/**
|
||||
* @brief The information of an upcoming leap second in the
|
||||
* server response.
|
||||
*/
|
||||
SntpLeapSecondInfo_t leapSecondType;
|
||||
|
||||
/**
|
||||
* @brief If a server responded with Kiss-o'-Death message to reject
|
||||
* time request, this is the fixed length ASCII code sequence for the
|
||||
* rejection.
|
||||
*
|
||||
* The Kiss-o'-Death code is always #SNTP_KISS_OF_DEATH_CODE_LENGTH
|
||||
* bytes long.
|
||||
*
|
||||
* @note If the server does not send a Kiss-o'-Death message in its
|
||||
* response, this value will be #SNTP_KISS_OF_DEATH_CODE_NONE.
|
||||
*/
|
||||
uint32_t rejectedResponseCode;
|
||||
|
||||
/**
|
||||
* @brief The offset (in milliseconds) of the system clock relative to the server time
|
||||
* calculated from timestamps in the client SNTP request and server SNTP response packets.
|
||||
* If the the system time is BEHIND the server time, then the clock-offset value is > 0.
|
||||
* If the system time is AHEAD of the server time, then the clock-offset value is < 0.
|
||||
*
|
||||
* @note This information can be used to synchronize the system clock with a "slew",
|
||||
* "step" OR combination of the two clock correction methodologies depending on the degree
|
||||
* of system clock drift (represented by the clock-offset) and the application's
|
||||
* tolerance for system clock error.
|
||||
*
|
||||
* @note The library calculates the clock-offset value using the On-Wire
|
||||
* protocol suggested by the NTPv4 specification. For more information,
|
||||
* refer to https://tools.ietf.org/html/rfc5905#section-8.
|
||||
*
|
||||
* @note The library ASSUMES that the server and client systems are within
|
||||
* ~68 years of each other clock, whether in the same NTP era or across adjacent
|
||||
* NTP eras. Thus, the client and system times MUST be within ~68 years (or
|
||||
* 2^31 seconds exactly) of each other for correct calculation of clock-offset.
|
||||
*
|
||||
* @note When the server and client times are exactly 2^31 (or INT32_MAX + 1 )
|
||||
* seconds apart, the library ASSUMES that the server time is ahead of the client
|
||||
* time, and return the clock-offset value of INT32_MAX.
|
||||
*/
|
||||
int64_t clockOffsetMs;
|
||||
} SntpResponseData_t;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Serializes an SNTP request packet to use for querying a
|
||||
* time server.
|
||||
*
|
||||
* This function will fill only #SNTP_PACKET_BASE_SIZE bytes of data in the
|
||||
* passed buffer.
|
||||
*
|
||||
* @param[in, out] pRequestTime The current time of the system, expressed as time
|
||||
* since the SNTP epoch (i.e. 0h of 1st Jan 1900 ). This time will be serialized
|
||||
* in the SNTP request packet. The function will use this parameter to return the
|
||||
* timestamp serialized in the SNTP request. To protect against attacks spoofing
|
||||
* server responses, the timestamp MUST NOT be zero in value.
|
||||
* @param[in] randomNumber A random number (generated by a True Random Generator)
|
||||
* for use in the SNTP request packet to protect against replay attacks as suggested
|
||||
* by SNTPv4 specification. For more information, refer to
|
||||
* [RFC 4330 Section 3](https://tools.ietf.org/html/rfc4330#section-3).
|
||||
* @param[out] pBuffer The buffer that will be populated with the serialized
|
||||
* SNTP request packet.
|
||||
* @param[in] bufferSize The size of the @p pBuffer buffer. It should be at least
|
||||
* #SNTP_PACKET_BASE_SIZE bytes in size.
|
||||
*
|
||||
* @note It is recommended to use a True Random Generator (TRNG) to generate
|
||||
* the random number.
|
||||
* @note The application MUST save the @p pRequestTime value for de-serializing
|
||||
* the server response with @ref Sntp_DeserializeResponse API.
|
||||
*
|
||||
* @return This function returns one of the following:
|
||||
* - #SntpSuccess when serialization operation is successful.
|
||||
* - #SntpErrorBadParameter if an invalid parameter is passed.
|
||||
* - #SntpErrorBufferTooSmall if the buffer does not have the minimum size
|
||||
* for serializing an SNTP request packet.
|
||||
*/
|
||||
/* @[define_sntp_serializerequest] */
|
||||
SntpStatus_t Sntp_SerializeRequest( SntpTimestamp_t * pRequestTime,
|
||||
uint32_t randomNumber,
|
||||
void * pBuffer,
|
||||
size_t bufferSize );
|
||||
/* @[define_sntp_serializerequest] */
|
||||
|
||||
/**
|
||||
* @brief De-serializes an SNTP packet received from a server as a response
|
||||
* to a SNTP request.
|
||||
*
|
||||
* This function will parse only the #SNTP_PACKET_BASE_SIZE bytes of data
|
||||
* in the passed buffer.
|
||||
*
|
||||
* @note If the server has sent a Kiss-o'-Death message to reject the associated
|
||||
* time request, the API function will return the appropriate return code and,
|
||||
* also, provide the ASCII code (of fixed length, #SNTP_KISS_OF_DEATH_CODE_LENGTH bytes)
|
||||
* in the #SntpResponseData_t.rejectedResponseCode member of @p pParsedResponse parameter,
|
||||
* parsed from the response packet.
|
||||
* The application SHOULD respect the server rejection and take appropriate action
|
||||
* based on the rejection code.
|
||||
* If the server response represents an accepted SNTP client request, then the API
|
||||
* function will set the #SntpResponseData_t.rejectedResponseCode member of
|
||||
* @p pParsedResponse parameter to #SNTP_KISS_OF_DEATH_CODE_NONE.
|
||||
*
|
||||
* @note If the server has positively responded with its clock time, then this API
|
||||
* function will calculate the clock-offset. For the clock-offset to be correctly
|
||||
* calculated, the system clock MUST be within ~68 years (or 2^31 seconds) of the server
|
||||
* time mentioned. This function supports clock-offset calculation when server and client
|
||||
* timestamps are in adjacent NTP eras, with one system is in NTP era 0 (i.e. before 7 Feb 2036
|
||||
* 6h:28m:14s UTC) and another system in NTP era 1 (on or after 7 Feb 2036 6h:28m:14s UTC).
|
||||
*
|
||||
* @note In the special case when the server and client times are exactly 2^31 seconds apart,
|
||||
* the library ASSUMES that the server time is ahead of the client time, and returns the
|
||||
* positive clock-offset value of INT32_MAX seconds.
|
||||
*
|
||||
* @param[in] pRequestTime The system time used in the SNTP request packet
|
||||
* that is associated with the server response. This MUST be the same as the
|
||||
* time returned by the @ref Sntp_SerializeRequest API. To protect against attacks
|
||||
* spoofing server responses, this timestamp MUST NOT be zero in value.
|
||||
* @param[in] pResponseRxTime The time of the system, expressed as time since the
|
||||
* SNTP epoch (i.e. 0h of 1st Jan 1900 ), at receiving SNTP response from server.
|
||||
* This time will be used to calculate system clock offset relative to server.
|
||||
* @param[in] pResponseBuffer The buffer containing the SNTP response from the
|
||||
* server.
|
||||
* @param[in] bufferSize The size of the @p pResponseBuffer containing the SNTP
|
||||
* response. It MUST be at least #SNTP_PACKET_BASE_SIZE bytes
|
||||
* long for a valid SNTP response.
|
||||
* @param[out] pParsedResponse The information parsed from the SNTP response packet.
|
||||
* If possible to calculate without overflow, it also contains the system clock
|
||||
* offset relative to the server time.
|
||||
*
|
||||
* @return This function returns one of the following:
|
||||
* - #SntpSuccess if the de-serialization operation is successful.
|
||||
* - #SntpErrorBadParameter if an invalid parameter is passed.
|
||||
* - #SntpErrorBufferTooSmall if the buffer does not have the minimum size
|
||||
* required for a valid SNTP response packet.
|
||||
* - #SntpInvalidResponse if the response fails sanity checks expected in an
|
||||
* SNTP response.
|
||||
* - #SntpRejectedResponseChangeServer if the server rejected with a code
|
||||
* indicating that client cannot be retry requests to it.
|
||||
* - #SntpRejectedResponseRetryWithBackoff if the server rejected with a code
|
||||
* indicating that client should back-off before retrying request.
|
||||
* - #SntpRejectedResponseOtherCode if the server rejected with a code that
|
||||
* application can inspect in the @p pParsedResponse parameter.
|
||||
*/
|
||||
/* @[define_sntp_deserializeresponse] */
|
||||
SntpStatus_t Sntp_DeserializeResponse( const SntpTimestamp_t * pRequestTime,
|
||||
const SntpTimestamp_t * pResponseRxTime,
|
||||
const void * pResponseBuffer,
|
||||
size_t bufferSize,
|
||||
SntpResponseData_t * pParsedResponse );
|
||||
/* @[define_sntp_deserializeresponse] */
|
||||
|
||||
/**
|
||||
* @brief Utility to calculate the poll interval of sending periodic time queries
|
||||
* to servers to achieve a desired system clock accuracy for a given
|
||||
* frequency tolerance of the system clock.
|
||||
*
|
||||
* For example, from the SNTPv4 specification, "if the frequency tolerance
|
||||
* is 200 parts per million (PPM) and the required accuracy is one minute,
|
||||
* the maximum timeout is about 3.5 days". In this example, the system
|
||||
* clock frequency tolerance is 200 PPM and the desired accuracy is
|
||||
* 60000 milliseconds (or 1 minute) for which this API function
|
||||
* will return the maximum poll interval value as 2^18 seconds (or ~3 days).
|
||||
*
|
||||
* @note The poll interval returned is a power of 2, which is the
|
||||
* standard way to represent the value. According to the SNTPv4 specification
|
||||
* Best Practices, an SNTP client SHOULD NOT have a poll interval less than 15 seconds.
|
||||
* https://tools.ietf.org/html/rfc4330#section-10. This API function DOES NOT
|
||||
* support poll interval calculation less than 1 second.
|
||||
*
|
||||
* @param[in] clockFreqTolerance The frequency tolerance of system clock
|
||||
* in parts per million (PPM) units. This parameter MUST be non-zero.
|
||||
* @param[in] desiredAccuracy The acceptable maximum drift, in milliseconds,
|
||||
* for the system clock. The maximum value (0xFFFF) represents ~1 minute of
|
||||
* desired clock accuracy. This parameter MUST be non-zero.
|
||||
* @param[out] pPollInterval This is filled with the poll interval, in seconds
|
||||
* calculated as the closest power of 2 value that will achieve either the
|
||||
* exact desired or higher clock accuracy @p desiredAccuracy, for the given clock
|
||||
* frequency tolerance, @p clockFreqTolerance.
|
||||
*
|
||||
* @return Returns one of the following:
|
||||
* - #SntpSuccess if calculation is successful.
|
||||
* - #SntpErrorBadParameter for an invalid parameter passed to the function.
|
||||
* - #SntpZeroPollInterval if calculated poll interval is less than 1 second.
|
||||
*/
|
||||
/* @[define_sntp_calculatepollinterval] */
|
||||
SntpStatus_t Sntp_CalculatePollInterval( uint16_t clockFreqTolerance,
|
||||
uint16_t desiredAccuracy,
|
||||
uint32_t * pPollInterval );
|
||||
/* @[define_sntp_calculatepollinterval] */
|
||||
|
||||
|
||||
/**
|
||||
* @brief Utility to convert SNTP timestamp (that uses 1st Jan 1900 as the epoch) to
|
||||
* UNIX timestamp (that uses 1st Jan 1970 as the epoch).
|
||||
*
|
||||
* @note This function can ONLY handle conversions of SNTP timestamps that lie in the
|
||||
* range from 1st Jan 1970 0h 0m 0s, the UNIX epoch time, to 19th Jan 2038 3h 14m 7s,
|
||||
* the maximum UNIX time that can be represented in a signed 32 bit integer. (The
|
||||
* limitation is to support systems that use signed 32-bit integer to represent the
|
||||
* seconds part of the UNIX time.)
|
||||
*
|
||||
* @note This function supports overflow of the SNTP timestamp (from the 7 Feb 2036
|
||||
* 6h 28m 16s time, i.e. SNTP era 1) by treating the timestamps with seconds part
|
||||
* in the range [0, 61,505,152] seconds where the upper limit represents the UNIX
|
||||
* overflow time (i.e. 19 Jan 2038 3h 14m 7s) for systems that use signed 32-bit
|
||||
* integer to represent time.
|
||||
*
|
||||
* @param[in] pSntpTime The SNTP timestamp to convert to UNIX time.
|
||||
* @param[out] pUnixTimeSecs This will be filled with the seconds part of the
|
||||
* UNIX time equivalent of the SNTP time, @p pSntpTime.
|
||||
* @param[out] pUnixTimeMicrosecs This will be filled with the microseconds part
|
||||
* of the UNIX time equivalent of the SNTP time, @p pSntpTime.
|
||||
*
|
||||
* @return Returns one of the following:
|
||||
* - #SntpSuccess if conversion to UNIX time is successful
|
||||
* - #SntpErrorBadParameter if any of the passed parameters are NULL.
|
||||
* - #SntpErrorTimeNotSupported if the passed SNTP time does not lie in the
|
||||
* supported time range.
|
||||
*/
|
||||
/* @[define_sntp_converttounixtime] */
|
||||
SntpStatus_t Sntp_ConvertToUnixTime( const SntpTimestamp_t * pSntpTime,
|
||||
uint32_t * pUnixTimeSecs,
|
||||
uint32_t * pUnixTimeMicrosecs );
|
||||
/* @[define_sntp_converttounixtime] */
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
/* *INDENT-ON* */
|
||||
|
||||
#endif /* ifndef CORE_SNTP_SERIALIZER_H_ */
|
||||
@ -0,0 +1,103 @@
|
||||
cmake_minimum_required( VERSION 3.13.0 )
|
||||
project( "coreSNTP unit test"
|
||||
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 "coreSNTP source root." )
|
||||
set( UNIT_TEST_DIR ${MODULE_ROOT_DIR}/test/unit-test CACHE INTERNAL "coreSNTP unit test directory." )
|
||||
set( CMOCK_DIR ${UNIT_TEST_DIR}/CMock 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."
|
||||
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 =================================
|
||||
|
||||
# Include filepaths for source and include.
|
||||
include( ${MODULE_ROOT_DIR}/coreSntpFilePaths.cmake )
|
||||
|
||||
# Target for Coverity analysis that builds the library.
|
||||
add_library( coverity_analysis
|
||||
${CORE_SNTP_SOURCES} )
|
||||
|
||||
# Add coreSNTP library public include path.
|
||||
target_include_directories( coverity_analysis
|
||||
PUBLIC
|
||||
${CORE_SNTP_INCLUDE_PUBLIC_DIRS} )
|
||||
|
||||
# Build SNTP library target without custom config dependency.
|
||||
target_compile_definitions( coverity_analysis PUBLIC SNTP_DO_NOT_USE_CUSTOM_CONFIG=1 )
|
||||
|
||||
# Build without debug enabled when performing static analysis
|
||||
target_compile_options(coverity_analysis PUBLIC -DNDEBUG )
|
||||
|
||||
# ==================================== Code Example Build ====================================
|
||||
|
||||
if(${BUILD_CODE_EXAMPLE})
|
||||
# Target for Coverity analysis that builds the library.
|
||||
add_executable( code_example_posix
|
||||
${MODULE_ROOT_DIR}/docs/doxygen/code_examples/example_sntp_client_posix.c )
|
||||
|
||||
# Add coreSNTP library public include path.
|
||||
target_link_libraries( code_example_posix
|
||||
coverity_analysis )
|
||||
|
||||
endif()
|
||||
|
||||
# ==================================== Unit Test Configuration ====================================
|
||||
|
||||
if(${BUILD_UNIT_TESTS})
|
||||
# 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.
|
||||
clone_cmock()
|
||||
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, required for unit testing.
|
||||
add_cmock_targets()
|
||||
|
||||
# Add function to enable CMock/Unity based tests and coverage.
|
||||
include( ${MODULE_ROOT_DIR}/tools/cmock/create_test.cmake )
|
||||
|
||||
# Include build configuration for unit tests.
|
||||
add_subdirectory( unit-test )
|
||||
endif()
|
||||
|
||||
# ==================================== 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 core_sntp_client_utest core_sntp_serializer_utest
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
|
||||
)
|
||||
24
kernel/FreeRTOS-Plus/Source/Application-Protocols/coreSNTP/test/cbmc/.gitignore
vendored
Normal file
24
kernel/FreeRTOS-Plus/Source/Application-Protocols/coreSNTP/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,53 @@
|
||||
/*
|
||||
* coreSNTP v1.2.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 core_sntp_cbmc_state.h
|
||||
* @brief Allocation and assumption utilities for the SNTP library CBMC proofs.
|
||||
*/
|
||||
#ifndef CORE_SNTP_CBMC_STATE_H_
|
||||
#define CORE_SNTP_CBMC_STATE_H_
|
||||
|
||||
#include "core_sntp_client.h"
|
||||
|
||||
/* Application defined Network context. */
|
||||
struct NetworkContext
|
||||
{
|
||||
void * networkContext;
|
||||
};
|
||||
|
||||
/* Application defined authentication context. */
|
||||
struct SntpAuthContext
|
||||
{
|
||||
void * authContext;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Allocate a #SntpContext_t object.
|
||||
*
|
||||
* @return NULL or allocated #SntpContext_t memory.
|
||||
*/
|
||||
SntpContext_t * unconstrainedCoreSntpContext();
|
||||
|
||||
#endif /* ifndef CORE_SNTP_CBMC_STATE_H_ */
|
||||
@ -0,0 +1,177 @@
|
||||
/*
|
||||
* coreSNTP v1.2.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 core_sntp_config_defaults.h
|
||||
* @brief This file represents the default values for the configuration macros
|
||||
* of the coreSNTP library.
|
||||
*
|
||||
* @note This file SHOULD NOT be modified. If custom values are needed for
|
||||
* any configuration macro, a core_sntp_config.h file should be provided to
|
||||
* the SNTP library to override the default values defined in this file.
|
||||
* To build the library with the core_sntp_config.h file, make sure to
|
||||
* not set the SNTP_DO_NOT_USE_CUSTOM_CONFIG preprocessor macro.
|
||||
*/
|
||||
|
||||
#ifndef CORE_SNTP_CONFIG_DEFAULTS_H_
|
||||
#define CORE_SNTP_CONFIG_DEFAULTS_H_
|
||||
|
||||
/* The macro definition for SNTP_DO_NOT_USE_CUSTOM_CONFIG is for Doxygen
|
||||
* documentation only. */
|
||||
|
||||
/**
|
||||
* @brief Define this macro to build the SNTP library without the custom config
|
||||
* file core_sntp_config.h.
|
||||
*
|
||||
* Without the custom config, the SNTP library builds with
|
||||
* default values of config macros defined in core_sntp_config_defaults.h file.
|
||||
*
|
||||
* If a custom config is provided, then SNTP_DO_NOT_USE_CUSTOM_CONFIG should not
|
||||
* be defined.
|
||||
*/
|
||||
#ifdef DOXYGEN
|
||||
#define SNTP_DO_NOT_USE_CUSTOM_CONFIG
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief The maximum duration between non-empty network reads while
|
||||
* receiving an SNTP packet via the #Sntp_ReceiveTimeResponse API function.
|
||||
*
|
||||
* When an incoming SNTP packet is detected, the transport receive function
|
||||
* may be called multiple times until all of the expected number of bytes of the
|
||||
* packet are received. This timeout represents the maximum polling duration that
|
||||
* is allowed without any data reception from the network for the incoming packet.
|
||||
*
|
||||
* If the timeout expires, the #Sntp_ReceiveTimeResponse function will return
|
||||
* #SntpErrorNetworkFailure.
|
||||
*
|
||||
* <b>Possible values:</b> Any positive 16 bit integer. Recommended to use a
|
||||
* small timeout value. <br>
|
||||
* <b>Default value:</b> `10`
|
||||
*/
|
||||
#ifndef SNTP_RECV_POLLING_TIMEOUT_MS
|
||||
#define SNTP_RECV_POLLING_TIMEOUT_MS ( 10U )
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief The maximum duration between non-empty network transmissions while
|
||||
* sending an SNTP packet via the #Sntp_SendTimeRequest API function.
|
||||
*
|
||||
* When sending an SNTP packet, the transport send function may be called multiple
|
||||
* times until all of the required number of bytes are sent.
|
||||
* This timeout represents the maximum duration that is allowed for no data
|
||||
* transmission over the network through the transport send function.
|
||||
*
|
||||
* If the timeout expires, the #Sntp_SendTimeRequest function will return
|
||||
* #SntpErrorNetworkFailure.
|
||||
*
|
||||
* <b>Possible values:</b> Any positive 16 bit integer. Recommended to use a small
|
||||
* timeout value. <br>
|
||||
* <b>Default value:</b> `10`
|
||||
*/
|
||||
#ifndef SNTP_SEND_RETRY_TIMEOUT_MS
|
||||
#define SNTP_SEND_RETRY_TIMEOUT_MS ( 10U )
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Macro that is called in the SNTP library for logging "Error" level
|
||||
* messages.
|
||||
*
|
||||
* To enable error level logging in the SNTP library, this macro should be mapped to the
|
||||
* application-specific logging implementation that supports error logging.
|
||||
*
|
||||
* @note This logging macro is called in the SNTP 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 core_sntp_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 SNTP library on compilation.
|
||||
*/
|
||||
#ifndef LogError
|
||||
#define LogError( message )
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Macro that is called in the SNTP library for logging "Warning" level
|
||||
* messages.
|
||||
*
|
||||
* To enable warning level logging in the SNTP library, this macro should be mapped to the
|
||||
* application-specific logging implementation that supports warning logging.
|
||||
*
|
||||
* @note This logging macro is called in the SNTP 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 core_sntp_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 SNTP library on compilation.
|
||||
*/
|
||||
#ifndef LogWarn
|
||||
#define LogWarn( message )
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Macro that is called in the SNTP library for logging "Info" level
|
||||
* messages.
|
||||
*
|
||||
* To enable info level logging in the SNTP library, this macro should be mapped to the
|
||||
* application-specific logging implementation that supports info logging.
|
||||
*
|
||||
* @note This logging macro is called in the SNTP 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 core_sntp_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 SNTP library on compilation.
|
||||
*/
|
||||
#ifndef LogInfo
|
||||
#define LogInfo( message )
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Macro that is called in the SNTP library for logging "Debug" level
|
||||
* messages.
|
||||
*
|
||||
* To enable debug level logging from SNTP library, this macro should be mapped to the
|
||||
* application-specific logging implementation that supports debug logging.
|
||||
*
|
||||
* @note This logging macro is called in the SNTP 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 core_sntp_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 SNTP library on compilation.
|
||||
*/
|
||||
#ifndef LogDebug
|
||||
#define LogDebug( message )
|
||||
#endif
|
||||
|
||||
#endif /* ifndef CORE_SNTP_CONFIG_DEFAULTS_H_ */
|
||||
@ -0,0 +1,153 @@
|
||||
/*
|
||||
* coreSNTP v1.2.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 core_sntp_stubs_stubs.h
|
||||
* @brief Stubs definitions of UDP transport interface and authentication interface of coreSNTP API.
|
||||
*/
|
||||
#ifndef CORE_SNTP_CBMC_STUBS_H_
|
||||
#define CORE_SNTP_CBMC_STUBS_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "core_sntp_client.h"
|
||||
|
||||
/**
|
||||
* @brief Application defined network interface send function.
|
||||
*
|
||||
* @param[in] pNetworkContext Application defined network interface context.
|
||||
* @param[in] serverAddr Server address to which application sends data.
|
||||
* @param[in] serverPort Server port to which application sends data.
|
||||
* @param[out] pBuffer SNTP network send buffer.
|
||||
* @param[in] bytesToSend Number of bytes to send over the network.
|
||||
*
|
||||
* @return Any value from INT32_MIN to INT32_MAX.
|
||||
*/
|
||||
int32_t NetworkInterfaceSendStub( NetworkContext_t * pNetworkContext,
|
||||
uint32_t serverAddr,
|
||||
uint16_t serverPort,
|
||||
const void * pBuffer,
|
||||
uint16_t bytesToSend );
|
||||
|
||||
/**
|
||||
* @brief Application defined network interface receive function.
|
||||
*
|
||||
* @param[in] pNetworkContext Application defined network interface context.
|
||||
* @param[in] serverAddr Server address from which application receives data.
|
||||
* @param[in] serverPort Server port from which application receives data.
|
||||
* @param[out] pBuffer SNTP network receive buffer.
|
||||
* @param[in] bytesToRecv SNTP requested bytes.
|
||||
*
|
||||
* @return Any value from INT32_MIN to INT32_MAX.
|
||||
*/
|
||||
int32_t NetworkInterfaceReceiveStub( NetworkContext_t * pNetworkContext,
|
||||
uint32_t serverAddr,
|
||||
uint16_t serverPort,
|
||||
void * pBuffer,
|
||||
uint16_t bytesToRecv );
|
||||
|
||||
/**
|
||||
* @brief Application defined function to generate and append
|
||||
* authentication code in an SNTP request buffer for the SNTP client to be
|
||||
* authenticated by the time server, if a security mechanism is used.
|
||||
*
|
||||
* @param[in] pContext Application defined authentication interface context.
|
||||
* @param[in] pTimeServer The time server being used to request time from.
|
||||
* This parameter is useful to choose the security mechanism when multiple time
|
||||
* servers are configured in the library, and they require different security
|
||||
* mechanisms or authentication credentials to use.
|
||||
* @param[in] pBuffer SNTP request buffer.
|
||||
* @param[in] bufferSize The maximum amount of data that can be held by the buffer.
|
||||
* @param[out] pAuthCodeSize This should be filled with size of the authentication
|
||||
* data appended to the SNTP request buffer, @p pBuffer.
|
||||
*
|
||||
* @return The function SHOULD return one of the following integer codes:
|
||||
* - #SntpSuccess when the authentication data is successfully appended to @p pBuffer.
|
||||
* - #SntpErrorBufferTooSmall when the user-supplied buffer (to the SntpContext_t through
|
||||
* @ref Sntp_Init) is not large enough to hold authentication data.
|
||||
*/
|
||||
SntpStatus_t GenerateClientAuthStub( SntpAuthContext_t * pContext,
|
||||
const SntpServerInfo_t * pTimeServer,
|
||||
void * pBuffer,
|
||||
size_t bufferSize,
|
||||
uint16_t * pAuthCodeSize );
|
||||
|
||||
/**
|
||||
* @brief Application defined function to authenticate server by validating
|
||||
* the authentication code present in its SNTP response to a time request, if
|
||||
* a security mechanism is supported by the server.
|
||||
*
|
||||
* @param[in,out] pContext The application defined NetworkContext_t which
|
||||
* is opaque to the coreSNTP library.
|
||||
* @param[in] pTimeServer The time server that has to be authenticated from its
|
||||
* SNTP response.
|
||||
* @param[in] pResponseData The SNTP response from the server that contains the
|
||||
* authentication code after the first #SNTP_PACKET_BASE_SIZE bytes.
|
||||
* @param[in] responseSize The total size of the response from the server.
|
||||
*
|
||||
* @return The function ALWAYS returns #SntpSuccess
|
||||
*/
|
||||
SntpStatus_t ValidateServerAuthStub( SntpAuthContext_t * pContext,
|
||||
const SntpServerInfo_t * pTimeServer,
|
||||
const void * pResponseData,
|
||||
uint16_t responseSize );
|
||||
|
||||
/**
|
||||
* @brief Application defined function to resolve time server domain-name
|
||||
* to an IPv4 address.
|
||||
*
|
||||
* @param[in] pTimeServer The time-server whose IPv4 address is to be resolved.
|
||||
* @param[out] pIpV4Addr This should be filled with the resolved IPv4 address.
|
||||
* of @p pTimeServer.
|
||||
*
|
||||
* @return `true` if DNS resolution is successful; otherwise `false` to represent
|
||||
* failure.
|
||||
*/
|
||||
bool ResolveDnsFuncStub( const SntpServerInfo_t * pServerAddr,
|
||||
uint32_t * pIpV4Addr );
|
||||
|
||||
/**
|
||||
* @brief Application defined function to obtain the current system time
|
||||
* in SNTP timestamp format.
|
||||
*
|
||||
* @param[out] pCurrentTime This should be filled with the current system time
|
||||
* in SNTP timestamp format.
|
||||
*/
|
||||
void GetTimeFuncStub( SntpTimestamp_t * pCurrentTime );
|
||||
|
||||
/**
|
||||
* @brief Application defined function to update the system clock time
|
||||
* so that it is synchronized the time server used for getting current time.
|
||||
*
|
||||
* @param[in] pTimeServer The time server used to request time.
|
||||
* @param[in] pServerTime The current time returned by the @p pTimeServer.
|
||||
* @param[in] clockOffSetMs The calculated clock offset of the system relative
|
||||
* to the server time.
|
||||
*/
|
||||
void SetTimeFuncStub( const SntpServerInfo_t * pTimeServer,
|
||||
const SntpTimestamp_t * pServerTime,
|
||||
int64_t clockOffsetMs );
|
||||
|
||||
#endif /* ifndef CORE_SNTP_CBMC_STUBS_H_ */
|
||||
@ -0,0 +1,39 @@
|
||||
# -*- 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.
|
||||
################################################################
|
||||
|
||||
# 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
|
||||
|
||||
# Preprocessor definitions -D...
|
||||
# DEFINES =
|
||||
|
||||
# Path to arpa executable
|
||||
# ARPA =
|
||||
|
||||
# Flags to pass to cmake for building the project
|
||||
# ARPA_CMAKE_FLAGS =
|
||||
@ -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,20 @@
|
||||
PROOF_ROOT ?= $(abspath .)
|
||||
|
||||
# Absolute path to the root of the source tree.
|
||||
#
|
||||
SRCDIR ?= $(abspath $(PROOF_ROOT)/../../..)
|
||||
|
||||
|
||||
# Absolute path to the litani script.
|
||||
#
|
||||
LITANI ?= litani
|
||||
|
||||
|
||||
# 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 = "coreSNTP"
|
||||
|
||||
@ -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,24 @@
|
||||
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
# SPDX-License-Identifier: MIT-0
|
||||
|
||||
HARNESS_ENTRY = harness
|
||||
HARNESS_FILE = Sntp_CalculatePollInterval_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 = Sntp_CalculatePollInterval
|
||||
|
||||
# Bound for loop unwinding for loop in Sntp_CalculatePollInterval function. Unwinding
|
||||
# the loop 33 times will be enough as the unsigned 32 integer can take value upto 2^32.
|
||||
MAX_BOUND_FOR_LOOP=33
|
||||
|
||||
DEFINES +=
|
||||
INCLUDES +=
|
||||
|
||||
REMOVE_FUNCTION_BODY +=
|
||||
UNWINDSET += Sntp_CalculatePollInterval.0:$(MAX_BOUND_FOR_LOOP)
|
||||
|
||||
PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
|
||||
PROJECT_SOURCES += $(SRCDIR)/source/core_sntp_serializer.c
|
||||
|
||||
include ../Makefile.common
|
||||
@ -0,0 +1,23 @@
|
||||
Sntp_CalculatePollInterval proof
|
||||
==============
|
||||
|
||||
This directory contains a memory safety proof for Sntp_CalculatePollInterval.
|
||||
|
||||
The proof runs within 3 minutes on a t2.2xlarge. It provides complete coverage of:
|
||||
* Sntp_CalculatePollInterval()
|
||||
|
||||
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,43 @@
|
||||
/*
|
||||
* coreSNTP v1.2.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 Sntp_CalculatePollInterval_harness.c
|
||||
* @brief Implements the proof harness for Sntp_CalculatePollInterval function.
|
||||
*/
|
||||
|
||||
#include "core_sntp_serializer.h"
|
||||
|
||||
void harness()
|
||||
{
|
||||
uint16_t clockFreqTolerance;
|
||||
uint16_t desiredAccuracy;
|
||||
uint32_t * pPollInterval;
|
||||
SntpStatus_t sntpStatus;
|
||||
|
||||
pPollInterval = malloc( sizeof( uint32_t ) );
|
||||
sntpStatus = Sntp_CalculatePollInterval( clockFreqTolerance, desiredAccuracy, pPollInterval );
|
||||
|
||||
__CPROVER_assert( ( sntpStatus == SntpErrorBadParameter || sntpStatus == SntpSuccess || sntpStatus == SntpZeroPollInterval ), "The return value is not a valid SNTP status." );
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
# This file marks this directory as containing a CBMC proof.
|
||||
@ -0,0 +1,7 @@
|
||||
{ "expected-missing-functions":
|
||||
[
|
||||
|
||||
],
|
||||
"proof-name": "Sntp_CalculatePollInterval",
|
||||
"proof-root": "test/cbmc/proofs"
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
# SPDX-License-Identifier: MIT-0
|
||||
|
||||
HARNESS_ENTRY = harness
|
||||
HARNESS_FILE = Sntp_ConvertToUnixTime_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 = Sntp_ConvertToUnixTime
|
||||
|
||||
DEFINES +=
|
||||
INCLUDES +=
|
||||
|
||||
REMOVE_FUNCTION_BODY +=
|
||||
UNWINDSET +=
|
||||
|
||||
PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
|
||||
PROJECT_SOURCES += $(SRCDIR)/source/core_sntp_serializer.c
|
||||
|
||||
include ../Makefile.common
|
||||
@ -0,0 +1,23 @@
|
||||
Sntp_ConvertToUnixTime proof
|
||||
==============
|
||||
|
||||
This directory contains a memory safety proof for Sntp_ConvertToUnixTime.
|
||||
|
||||
The proof runs within 3 minutes on a t2.2xlarge. It provides complete coverage of:
|
||||
* Sntp_ConvertToUnixTime()
|
||||
|
||||
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,46 @@
|
||||
/*
|
||||
* coreSNTP v1.2.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 Sntp_ConvertToUnixTime_harness.c
|
||||
* @brief Implements the proof harness for Sntp_ConvertToUnixTime function.
|
||||
*/
|
||||
|
||||
#include "core_sntp_serializer.h"
|
||||
|
||||
void harness()
|
||||
{
|
||||
SntpTimestamp_t * pSntpTime;
|
||||
uint32_t * pUnixTimeSecs;
|
||||
uint32_t * pUnixTimeMicrosecs;
|
||||
SntpStatus_t sntpStatus;
|
||||
|
||||
pSntpTime = malloc( sizeof( SntpTimestamp_t ) );
|
||||
pUnixTimeSecs = malloc( sizeof( uint32_t ) );
|
||||
pUnixTimeMicrosecs = malloc( sizeof( uint32_t ) );
|
||||
|
||||
sntpStatus = Sntp_ConvertToUnixTime( pSntpTime, pUnixTimeSecs, pUnixTimeMicrosecs );
|
||||
|
||||
__CPROVER_assert( ( sntpStatus == SntpErrorBadParameter || sntpStatus == SntpErrorTimeNotSupported || sntpStatus == SntpSuccess ), "The return value is not a valid SNTP Status" );
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
# This file marks this directory as containing a CBMC proof.
|
||||
@ -0,0 +1,7 @@
|
||||
{ "expected-missing-functions":
|
||||
[
|
||||
|
||||
],
|
||||
"proof-name": "Sntp_ConvertToUnixTime",
|
||||
"proof-root": "test/cbmc/proofs"
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
# SPDX-License-Identifier: MIT-0
|
||||
|
||||
HARNESS_ENTRY = harness
|
||||
HARNESS_FILE = Sntp_DeserializeResponse_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 = Sntp_DeserializeResponse
|
||||
|
||||
DEFINES +=
|
||||
INCLUDES +=
|
||||
|
||||
REMOVE_FUNCTION_BODY +=
|
||||
UNWINDSET +=
|
||||
|
||||
PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
|
||||
PROJECT_SOURCES += $(SRCDIR)/source/core_sntp_serializer.c
|
||||
|
||||
include ../Makefile.common
|
||||
@ -0,0 +1,20 @@
|
||||
Sntp_DeserializeResponse proof
|
||||
==============
|
||||
|
||||
This directory contains a memory safety proof for Sntp_DeserializeResponse.
|
||||
|
||||
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,54 @@
|
||||
/*
|
||||
* coreSNTP v1.2.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 Sntp_DeserializeResponse_harness.c
|
||||
* @brief Implements the proof harness for Sntp_DeserializeResponse function.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "core_sntp_serializer.h"
|
||||
|
||||
void harness()
|
||||
{
|
||||
SntpTimestamp_t * pRequestTime;
|
||||
SntpTimestamp_t * pResponseRxTime;
|
||||
void * pResponseBuffer;
|
||||
size_t bufferSize;
|
||||
SntpResponseData_t * pParsedResponse;
|
||||
SntpStatus_t sntpStatus;
|
||||
|
||||
__CPROVER_assume( bufferSize < CBMC_MAX_OBJECT_SIZE );
|
||||
|
||||
pRequestTime = malloc( sizeof( SntpTimestamp_t ) );
|
||||
pResponseRxTime = malloc( sizeof( SntpTimestamp_t ) );
|
||||
pResponseBuffer = malloc( bufferSize );
|
||||
pParsedResponse = malloc( sizeof( SntpResponseData_t ) );
|
||||
|
||||
sntpStatus = Sntp_DeserializeResponse( pRequestTime, pResponseRxTime, pResponseBuffer, bufferSize, pParsedResponse );
|
||||
|
||||
__CPROVER_assert( ( sntpStatus == SntpErrorBadParameter ) || ( sntpStatus == SntpErrorBufferTooSmall ) ||
|
||||
( sntpStatus == SntpInvalidResponse ) || ( sntpStatus == SntpSuccess ) || ( sntpStatus == SntpRejectedResponseChangeServer ) ||
|
||||
( sntpStatus == SntpRejectedResponseRetryWithBackoff ) || ( sntpStatus == SntpRejectedResponseOtherCode ), "This is a valid sntp return status" );
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
# This file marks this directory as containing a CBMC proof.
|
||||
@ -0,0 +1,7 @@
|
||||
{ "expected-missing-functions":
|
||||
[
|
||||
|
||||
],
|
||||
"proof-name": "Sntp_DeserializeResponse",
|
||||
"proof-root": "test/cbmc/proofs"
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
# SPDX-License-Identifier: MIT-0
|
||||
|
||||
HARNESS_ENTRY = harness
|
||||
HARNESS_FILE = Sntp_Init_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 = Sntp_Init
|
||||
|
||||
DEFINES +=
|
||||
INCLUDES +=
|
||||
|
||||
REMOVE_FUNCTION_BODY +=
|
||||
UNWINDSET +=
|
||||
|
||||
PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
|
||||
PROJECT_SOURCES += $(SRCDIR)/source/core_sntp_client.c
|
||||
|
||||
include ../Makefile.common
|
||||
@ -0,0 +1,15 @@
|
||||
Sntp_Init proof
|
||||
==============
|
||||
|
||||
This directory contains a memory safety proof for Sntp_Init.
|
||||
|
||||
The proof runs within 3 minutes on a t2.2xlarge. It provides complete coverage of:
|
||||
* Sntp_Init()
|
||||
|
||||
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,62 @@
|
||||
/*
|
||||
* coreSNTP v1.2.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 Sntp_Init_harness.c
|
||||
* @brief Implements the proof harness for Sntp_Init function.
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include "core_sntp_client.h"
|
||||
|
||||
void harness()
|
||||
{
|
||||
SntpContext_t * pContext;
|
||||
SntpServerInfo_t * pTimeServers;
|
||||
size_t numOfServers;
|
||||
uint32_t serverResponseTimeoutMs;
|
||||
uint8_t * pNetworkBuffer;
|
||||
size_t bufferSize;
|
||||
SntpResolveDns_t resolveDnsFunc;
|
||||
SntpGetTime_t getSystemTimeFunc;
|
||||
SntpSetTime_t setSystemTimeFunc;
|
||||
UdpTransportInterface_t * pTransportIntf;
|
||||
SntpAuthenticationInterface_t * pAuthIntf;
|
||||
SntpStatus_t sntpStatus;
|
||||
|
||||
pContext = malloc( sizeof( SntpContext_t ) );
|
||||
pTimeServers = malloc( sizeof( SntpServerInfo_t ) );
|
||||
|
||||
__CPROVER_assume( bufferSize < CBMC_MAX_OBJECT_SIZE );
|
||||
|
||||
pNetworkBuffer = malloc( bufferSize );
|
||||
pTransportIntf = malloc( sizeof( UdpTransportInterface_t ) );
|
||||
pAuthIntf = malloc( sizeof( SntpAuthenticationInterface_t ) );
|
||||
|
||||
sntpStatus = Sntp_Init( pContext, pTimeServers, numOfServers, serverResponseTimeoutMs, pNetworkBuffer,
|
||||
bufferSize, resolveDnsFunc, getSystemTimeFunc, setSystemTimeFunc,
|
||||
pTransportIntf, pAuthIntf );
|
||||
|
||||
__CPROVER_assert( ( sntpStatus == SntpErrorBadParameter || sntpStatus == SntpSuccess || sntpStatus == SntpErrorBufferTooSmall ), "The return value is not a valid SNTP Status" );
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
# This file marks this directory as containing a CBMC proof.
|
||||
@ -0,0 +1,7 @@
|
||||
{ "expected-missing-functions":
|
||||
[
|
||||
|
||||
],
|
||||
"proof-name": "Sntp_Init",
|
||||
"proof-root": "test/cbmc/proofs"
|
||||
}
|
||||
@ -0,0 +1,43 @@
|
||||
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
# SPDX-License-Identifier: MIT-0
|
||||
|
||||
HARNESS_ENTRY = harness
|
||||
HARNESS_FILE = Sntp_ReceiveTimeResponse_harness
|
||||
|
||||
# Please see test/cbmc/stubs/core_sntp_stubs.c for
|
||||
# more information on MAX_NETWORK_RECV_TRIES.
|
||||
MAX_NETWORK_RECV_TRIES=5
|
||||
|
||||
# Bound on the timeout in Sntp_ReceiveTimeResponse. This timeout is bounded because
|
||||
# memory saftey can be proven in a only a single iteration.
|
||||
# Each iteration will try to receive a single packet in its entirey. With a time
|
||||
# out of 1 we can get coverage of the entire function. Another iteration will
|
||||
# performed unnecessarily duplicating of the proof.
|
||||
SNTP_RECEIVE_TIMEOUT=1
|
||||
|
||||
# Maximum number of sntp time servers
|
||||
MAX_NO_OF_SERVERS=5
|
||||
|
||||
# Maximum number of attempts in outer loop of Sntp_ReceiveTimeResponse needed to receive a response from server.
|
||||
MAX_ITERATIONS_RECEIVE_RESPONSE=1
|
||||
|
||||
# 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 = Sntp_ReceiveTimeResponse
|
||||
|
||||
DEFINES +=-DMAX_NO_OF_SERVERS=$(MAX_NO_OF_SERVERS)
|
||||
DEFINES +=-DSNTP_RECEIVE_TIMEOUT=$(SNTP_RECEIVE_TIMEOUT)
|
||||
INCLUDES +=
|
||||
|
||||
REMOVE_FUNCTION_BODY +=Sntp_DeserializeResponse
|
||||
UNWINDSET +=__CPROVER_file_local_core_sntp_client_c_receiveSntpResponse.0:$(shell expr $(MAX_NETWORK_RECV_TRIES) + 1 )
|
||||
UNWINDSET +=__CPROVER_file_local_core_sntp_client_c_Sntp_ReceiveTimeResponse.0:$(shell expr $(MAX_ITERATIONS_RECEIVE_RESPONSE) + 1 )
|
||||
UNWINDSET +=unconstrainedCoreSntpContext.0:$(shell expr $(MAX_NO_OF_SERVERS) + 1 )
|
||||
|
||||
|
||||
PROOF_SOURCES += $(SRCDIR)/test/cbmc/sources/core_sntp_cbmc_state.c
|
||||
PROOF_SOURCES += $(SRCDIR)/test/cbmc/stubs/core_sntp_stubs.c
|
||||
PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
|
||||
PROJECT_SOURCES += $(SRCDIR)/source/core_sntp_client.c
|
||||
|
||||
include ../Makefile.common
|
||||
@ -0,0 +1,20 @@
|
||||
Sntp_ReceiveTimeResponse proof
|
||||
==============
|
||||
|
||||
This directory contains a memory safety proof for Sntp_ReceiveTimeResponse.
|
||||
|
||||
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,62 @@
|
||||
/*
|
||||
* coreSNTP v1.2.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 Sntp_ReceiveTimeResponse_harness.c
|
||||
* @brief Implements the proof harness for Sntp_ReceiveTimeResponse function.
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include "core_sntp_cbmc_state.h"
|
||||
#include "core_sntp_stubs.h"
|
||||
#include "core_sntp_client.h"
|
||||
|
||||
void harness()
|
||||
{
|
||||
SntpContext_t * pContext;
|
||||
uint32_t blockTimeMs;
|
||||
SntpStatus_t sntpStatus;
|
||||
|
||||
pContext = unconstrainedCoreSntpContext();
|
||||
|
||||
if( pContext != NULL )
|
||||
{
|
||||
/* Setting the initial value of request time to check for response timeout
|
||||
* while reading data from network. */
|
||||
GetTimeFuncStub( &pContext->lastRequestTime );
|
||||
}
|
||||
|
||||
/* The SNTP_RECEIVE_TIMEOUT is used here to control the number of loops
|
||||
* when receiving on the network. The default is used here because memory
|
||||
* safety can be proven in only a few iterations. Please see this proof's
|
||||
* Makefile for more information. */
|
||||
__CPROVER_assume( blockTimeMs < SNTP_RECEIVE_TIMEOUT );
|
||||
|
||||
sntpStatus = Sntp_ReceiveTimeResponse( pContext, blockTimeMs );
|
||||
|
||||
__CPROVER_assert( ( sntpStatus == SntpErrorBadParameter || sntpStatus == SntpSuccess ||
|
||||
sntpStatus == SntpNoResponseReceived || sntpStatus == SntpRejectedResponse ||
|
||||
sntpStatus == SntpErrorResponseTimeout || sntpStatus == SntpErrorNetworkFailure ),
|
||||
"The return value is not a valid coreSNTP Status" );
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
# This file marks this directory as containing a CBMC proof.
|
||||
@ -0,0 +1,7 @@
|
||||
{ "expected-missing-functions":
|
||||
[
|
||||
|
||||
],
|
||||
"proof-name": "Sntp_ReceiveTimeResponse",
|
||||
"proof-root": "test/cbmc/proofs"
|
||||
}
|
||||
@ -0,0 +1,40 @@
|
||||
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
# SPDX-License-Identifier: MIT-0
|
||||
|
||||
HARNESS_ENTRY = harness
|
||||
HARNESS_FILE = Sntp_SendTimeRequest_harness
|
||||
|
||||
# Please see test/cbmc/stubs/core_sntp_stubs.c for
|
||||
# more information on MAX_NETWORK_SEND_TRIES.
|
||||
MAX_NETWORK_SEND_TRIES=3
|
||||
|
||||
# Bound on the timeout in Sntp_ReceiveTimeResponse. This timeout is bounded because
|
||||
# memory saftey can be proven in a only a single iteration.
|
||||
# Each iteration will try to receive a single packet in its entirey. With a time
|
||||
# out of 1 we can get coverage of the entire function. Another iteration will
|
||||
# performed unnecessarily duplicating of the proof.
|
||||
SNTP_SEND_TIMEOUT=1
|
||||
|
||||
# Maximum number of sntp time servers
|
||||
MAX_NO_OF_SERVERS=5
|
||||
|
||||
# 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 = Sntp_SendTimeRequest
|
||||
|
||||
DEFINES +=-DMAX_NO_OF_SERVERS=$(MAX_NO_OF_SERVERS)
|
||||
DEFINES +=-DSNTP_SEND_TIMEOUT=$(SNTP_SEND_TIMEOUT)
|
||||
INCLUDES +=
|
||||
|
||||
# Providing a stub for this function as we have already have a separate proof
|
||||
# for this function
|
||||
REMOVE_FUNCTION_BODY +=Sntp_SerializeRequest
|
||||
UNWINDSET +=__CPROVER_file_local_core_sntp_client_c_sendSntpPacket.0:$(MAX_NETWORK_SEND_TRIES)
|
||||
UNWINDSET +=unconstrainedCoreSntpContext.0:$(shell expr $(MAX_NO_OF_SERVERS) + 1 )
|
||||
|
||||
PROOF_SOURCES += $(SRCDIR)/test/cbmc/sources/core_sntp_cbmc_state.c
|
||||
PROOF_SOURCES += $(SRCDIR)/test/cbmc/stubs/core_sntp_stubs.c
|
||||
PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
|
||||
PROJECT_SOURCES += $(SRCDIR)/source/core_sntp_client.c
|
||||
|
||||
include ../Makefile.common
|
||||
@ -0,0 +1,19 @@
|
||||
Sntp_SendTimeRequest proof
|
||||
==============
|
||||
|
||||
This directory contains a memory safety proof for Sntp_SendTimeRequest.
|
||||
|
||||
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.
|
||||
|
||||
-------------
|
||||
|
||||
* 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,56 @@
|
||||
/*
|
||||
* coreSNTP v1.2.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 Sntp_SendTimeRequest_harness.c
|
||||
* @brief Implements the proof harness for Sntp_SendTimeRequest function.
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include "core_sntp_client.h"
|
||||
#include "core_sntp_cbmc_state.h"
|
||||
|
||||
void harness()
|
||||
{
|
||||
SntpContext_t * pContext;
|
||||
uint32_t randomNumber;
|
||||
SntpStatus_t sntpStatus;
|
||||
uint32_t blockTimeMs;
|
||||
|
||||
pContext = unconstrainedCoreSntpContext();
|
||||
|
||||
/* The SNTP_SEND_TIMEOUT is used here to control the number of loops
|
||||
* when sending data on the network. The default is used here because memory
|
||||
* safety can be proven in only a few iterations. Please see this proof's
|
||||
* Makefile for more information. */
|
||||
__CPROVER_assume( blockTimeMs < SNTP_SEND_TIMEOUT );
|
||||
|
||||
sntpStatus = Sntp_SendTimeRequest( pContext, randomNumber, blockTimeMs );
|
||||
|
||||
__CPROVER_assert( ( sntpStatus == SntpErrorBadParameter || sntpStatus == SntpSuccess ||
|
||||
sntpStatus == SntpErrorContextNotInitialized || sntpStatus == SntpErrorSendTimeout ||
|
||||
sntpStatus == SntpErrorBufferTooSmall || sntpStatus == SntpErrorDnsFailure ||
|
||||
sntpStatus == SntpErrorAuthFailure || sntpStatus == SntpErrorNetworkFailure ),
|
||||
"The return value is not a valid coreSNTP Status" );
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
# This file marks this directory as containing a CBMC proof.
|
||||
@ -0,0 +1,7 @@
|
||||
{ "expected-missing-functions":
|
||||
[
|
||||
|
||||
],
|
||||
"proof-name": "Sntp_SendTimeRequest",
|
||||
"proof-root": "test/cbmc/proofs"
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
# SPDX-License-Identifier: MIT-0
|
||||
|
||||
HARNESS_ENTRY = harness
|
||||
HARNESS_FILE = Sntp_SerializeRequest_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 = Sntp_SerializeRequest
|
||||
|
||||
DEFINES +=
|
||||
INCLUDES +=
|
||||
|
||||
REMOVE_FUNCTION_BODY +=
|
||||
UNWINDSET +=
|
||||
|
||||
PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
|
||||
PROJECT_SOURCES += $(SRCDIR)/source/core_sntp_serializer.c
|
||||
|
||||
include ../Makefile.common
|
||||
@ -0,0 +1,23 @@
|
||||
Sntp_SerializeRequest proof
|
||||
==============
|
||||
|
||||
This directory contains a memory safety proof for Sntp_SerializeRequest.
|
||||
|
||||
The proof runs within 3 minutes on a t2.2xlarge. It provides complete coverage of:
|
||||
* Sntp_SerializeRequest()
|
||||
|
||||
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,50 @@
|
||||
/*
|
||||
* coreSNTP v1.2.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 Sntp_SerializeRequest_harness.c
|
||||
* @brief Implements the proof harness for Sntp_SerializeRequest function.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "core_sntp_serializer.h"
|
||||
|
||||
void harness()
|
||||
{
|
||||
SntpTimestamp_t * pRequestTime;
|
||||
uint32_t randomNumber;
|
||||
void * pBuffer;
|
||||
size_t bufferSize;
|
||||
SntpStatus_t sntpStatus;
|
||||
|
||||
pRequestTime = malloc( sizeof( SntpTimestamp_t ) );
|
||||
|
||||
__CPROVER_assume( bufferSize < CBMC_MAX_OBJECT_SIZE );
|
||||
|
||||
pBuffer = malloc( bufferSize );
|
||||
|
||||
sntpStatus = Sntp_SerializeRequest( pRequestTime, randomNumber, pBuffer, bufferSize );
|
||||
|
||||
__CPROVER_assert( ( sntpStatus == SntpErrorBadParameter || sntpStatus == SntpErrorBufferTooSmall || sntpStatus == SntpSuccess ), "The return value is not a valid SNTP Status" );
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
# This file marks this directory as containing a CBMC proof.
|
||||
@ -0,0 +1,7 @@
|
||||
{ "expected-missing-functions":
|
||||
[
|
||||
|
||||
],
|
||||
"proof-name": "Sntp_SerializeRequest",
|
||||
"proof-root": "test/cbmc/proofs"
|
||||
}
|
||||
@ -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,113 @@
|
||||
/*
|
||||
* coreSNTP v1.2.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 core_sntp_cbmc_state.c
|
||||
* @brief Implements the functions defined in core_sntp_cbmc_state.h.
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include "core_sntp_client.h"
|
||||
#include "core_sntp_cbmc_state.h"
|
||||
#include "core_sntp_stubs.h"
|
||||
|
||||
SntpContext_t * unconstrainedCoreSntpContext()
|
||||
{
|
||||
SntpServerInfo_t * pTimeServers;
|
||||
SntpContext_t * pContext;
|
||||
size_t currentServerIndex;
|
||||
size_t numOfServers;
|
||||
uint32_t serverResponseTimeoutMs;
|
||||
uint8_t * pNetworkBuffer;
|
||||
size_t bufferSize;
|
||||
UdpTransportInterface_t * pNetworkIntf;
|
||||
SntpAuthenticationInterface_t * pAuthIntf;
|
||||
SntpStatus_t sntpStatus = SntpSuccess;
|
||||
|
||||
pContext = malloc( sizeof( SntpContext_t ) );
|
||||
|
||||
__CPROVER_assume( numOfServers < MAX_NO_OF_SERVERS );
|
||||
__CPROVER_assume( serverResponseTimeoutMs < CBMC_MAX_OBJECT_SIZE );
|
||||
__CPROVER_assume( currentServerIndex < CBMC_MAX_OBJECT_SIZE );
|
||||
|
||||
if( numOfServers == 0 )
|
||||
{
|
||||
pTimeServers = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
pTimeServers = malloc( numOfServers * sizeof( SntpServerInfo_t ) );
|
||||
}
|
||||
|
||||
if( pTimeServers != NULL )
|
||||
{
|
||||
for( size_t i = 0; i < numOfServers; i++ )
|
||||
{
|
||||
__CPROVER_assume( pTimeServers[ i ].serverNameLen < CBMC_MAX_OBJECT_SIZE );
|
||||
__CPROVER_assume( pTimeServers[ i ].port < CBMC_MAX_OBJECT_SIZE );
|
||||
pTimeServers[ i ].pServerName = malloc( pTimeServers[ i ].serverNameLen );
|
||||
}
|
||||
}
|
||||
|
||||
__CPROVER_assume( bufferSize < CBMC_MAX_OBJECT_SIZE );
|
||||
pNetworkBuffer = malloc( bufferSize );
|
||||
|
||||
pNetworkIntf = malloc( sizeof( UdpTransportInterface_t ) );
|
||||
|
||||
if( pNetworkIntf != NULL )
|
||||
{
|
||||
pNetworkIntf->pUserContext = malloc( sizeof( NetworkContext_t ) );
|
||||
pNetworkIntf->sendTo = NetworkInterfaceSendStub;
|
||||
pNetworkIntf->recvFrom = NetworkInterfaceReceiveStub;
|
||||
}
|
||||
|
||||
pAuthIntf = malloc( sizeof( SntpAuthenticationInterface_t ) );
|
||||
|
||||
if( pAuthIntf != NULL )
|
||||
{
|
||||
pAuthIntf->pAuthContext = malloc( sizeof( SntpAuthContext_t ) );
|
||||
pAuthIntf->generateClientAuth = GenerateClientAuthStub;
|
||||
pAuthIntf->validateServerAuth = ValidateServerAuthStub;
|
||||
}
|
||||
|
||||
/* It is part of the API contract to call Sntp_Init() with the SntpContext_t
|
||||
* before any other function in core_sntp_client.h. */
|
||||
if( pContext != NULL )
|
||||
{
|
||||
pContext->currentServerIndex = currentServerIndex;
|
||||
sntpStatus = Sntp_Init( pContext, pTimeServers, numOfServers, serverResponseTimeoutMs, pNetworkBuffer,
|
||||
bufferSize, ResolveDnsFuncStub, GetTimeFuncStub, SetTimeFuncStub,
|
||||
pNetworkIntf, pAuthIntf );
|
||||
}
|
||||
|
||||
/* If the SntpContext_t initialization failed, then set the context to NULL
|
||||
* so that function under harness will return immediately upon a NULL
|
||||
* parameter check. */
|
||||
if( sntpStatus != SntpSuccess )
|
||||
{
|
||||
pContext = NULL;
|
||||
}
|
||||
|
||||
return pContext;
|
||||
}
|
||||
@ -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,236 @@
|
||||
/*
|
||||
* coreSNTP v1.2.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 core_sntp_stubs.c
|
||||
* @brief Definition of stubs for UDP transport and authentication interfaces of coreSNTP API.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "core_sntp_client.h"
|
||||
#include "core_sntp_serializer.h"
|
||||
#include "core_sntp_stubs.h"
|
||||
|
||||
#define TEST_TIMESTAMP \
|
||||
{ \
|
||||
.seconds = UINT32_MAX, \
|
||||
.fractions = 1000 \
|
||||
}
|
||||
|
||||
/* An exclusive bound on the times that the NetworkInterfaceSendStub will be
|
||||
* invoked before returning a loop terminating value. This is usually defined
|
||||
* in the Makefile of the harnessed function. */
|
||||
#ifndef MAX_NETWORK_SEND_TRIES
|
||||
#define MAX_NETWORK_SEND_TRIES 2
|
||||
#endif
|
||||
|
||||
/* An exclusive bound on the times that the NetworkInterfaceReceiveStub will
|
||||
* return an unbound value. At this value and beyond, the
|
||||
* NetworkInterfaceReceiveStub will return zero on every call. */
|
||||
#ifndef MAX_NETWORK_RECV_TRIES
|
||||
#define MAX_NETWORK_RECV_TRIES 5
|
||||
#endif
|
||||
|
||||
static SntpTimestamp_t testTime = TEST_TIMESTAMP;
|
||||
|
||||
int32_t NetworkInterfaceReceiveStub( NetworkContext_t * pNetworkContext,
|
||||
uint32_t serverAddr,
|
||||
uint16_t serverPort,
|
||||
void * pBuffer,
|
||||
uint16_t bytesToRecv )
|
||||
{
|
||||
__CPROVER_assert( pBuffer != NULL,
|
||||
"NetworkInterfaceReceiveStub pBuffer is NULL." );
|
||||
|
||||
__CPROVER_assert( __CPROVER_w_ok( pBuffer, bytesToRecv ),
|
||||
"NetworkInterfaceReceiveStub pBuffer is not writable up to bytesToRecv." );
|
||||
|
||||
/* The havoc fills the buffer with unconstrained values. */
|
||||
__CPROVER_havoc_object( pBuffer );
|
||||
|
||||
int32_t bytesOrError;
|
||||
static size_t tries = 0;
|
||||
|
||||
/* It is a bug for the application defined transport receive function to return
|
||||
* more than bytesToRecv. */
|
||||
__CPROVER_assume( bytesOrError <= ( int32_t ) bytesToRecv );
|
||||
|
||||
if( tries < ( MAX_NETWORK_RECV_TRIES - 1 ) )
|
||||
{
|
||||
tries++;
|
||||
}
|
||||
else
|
||||
{
|
||||
tries = 0;
|
||||
|
||||
bytesOrError = SNTP_PACKET_BASE_SIZE;
|
||||
}
|
||||
|
||||
return bytesOrError;
|
||||
}
|
||||
int32_t NetworkInterfaceSendStub( NetworkContext_t * pNetworkContext,
|
||||
uint32_t serverAddr,
|
||||
uint16_t serverPort,
|
||||
const void * pBuffer,
|
||||
uint16_t bytesToSend )
|
||||
{
|
||||
__CPROVER_assert( pBuffer != NULL,
|
||||
"NetworkInterfaceSendStub pBuffer is NULL." );
|
||||
|
||||
__CPROVER_assert( __CPROVER_r_ok( pBuffer, bytesToSend ),
|
||||
"NetworkInterfaceSendStub pBuffer is not readable up to bytesToSend." );
|
||||
|
||||
/* The number of tries to send the message before this invocation. */
|
||||
static size_t tries = 0;
|
||||
|
||||
int32_t bytesOrError;
|
||||
|
||||
/* It is a bug for the application defined transport send function to return
|
||||
* more than bytesToSend. */
|
||||
__CPROVER_assume( bytesOrError <= ( int32_t ) bytesToSend );
|
||||
|
||||
/* If the maximum tries are reached, then return a timeout. In the SNTP library
|
||||
* this stub is wrapped in a loop that will not end until the bytesOrError
|
||||
* returned is negative. This means we could loop possibly INT32_MAX
|
||||
* iterations. Looping for INT32_MAX times adds no value to the proof.
|
||||
* What matters is that the SNTP library can handle all the possible values
|
||||
* that could be returned. */
|
||||
if( tries < ( MAX_NETWORK_SEND_TRIES - 1 ) )
|
||||
{
|
||||
tries++;
|
||||
}
|
||||
else
|
||||
{
|
||||
tries = 0;
|
||||
/* This ensures that all the remaining bytes are sent in the last try. */
|
||||
bytesOrError = bytesToSend;
|
||||
}
|
||||
|
||||
return bytesOrError;
|
||||
}
|
||||
|
||||
SntpStatus_t GenerateClientAuthStub( SntpAuthContext_t * pContext,
|
||||
const SntpServerInfo_t * pTimeServer,
|
||||
void * pBuffer,
|
||||
size_t bufferSize,
|
||||
uint16_t * pAuthCodeSize )
|
||||
{
|
||||
__CPROVER_assert( pTimeServer != NULL,
|
||||
"GenerateClientAuthStub Time Server is NULL." );
|
||||
|
||||
__CPROVER_assert( pBuffer != NULL,
|
||||
"GenerateClientAuthStub pBuffer is NULL." );
|
||||
|
||||
SntpStatus_t sntpStatus = SntpSuccess;
|
||||
|
||||
if( bufferSize <= SNTP_PACKET_BASE_SIZE )
|
||||
{
|
||||
sntpStatus = SntpErrorBufferTooSmall;
|
||||
}
|
||||
else
|
||||
{
|
||||
*pAuthCodeSize = SNTP_PACKET_BASE_SIZE;
|
||||
}
|
||||
|
||||
return sntpStatus;
|
||||
}
|
||||
|
||||
SntpStatus_t ValidateServerAuthStub( SntpAuthContext_t * pContext,
|
||||
const SntpServerInfo_t * pTimeServer,
|
||||
const void * pResponseData,
|
||||
uint16_t responseSize )
|
||||
{
|
||||
return SntpSuccess;
|
||||
}
|
||||
|
||||
bool ResolveDnsFuncStub( const SntpServerInfo_t * pServerAddr,
|
||||
uint32_t * pIpV4Addr )
|
||||
{
|
||||
__CPROVER_assert( pServerAddr != NULL,
|
||||
"ResolveDnsFuncStub pServerAddr is NULL." );
|
||||
|
||||
/* For the proofs, returning a non deterministic boolean value
|
||||
* will be good enough. */
|
||||
return nondet_bool();
|
||||
}
|
||||
|
||||
void GetTimeFuncStub( SntpTimestamp_t * pCurrentTime )
|
||||
{
|
||||
__CPROVER_assert( pCurrentTime != NULL,
|
||||
"GetTimeFuncStub pCurrentTime is NULL." );
|
||||
|
||||
bool value = nondet_bool();
|
||||
|
||||
if( value )
|
||||
{
|
||||
testTime.fractions = testTime.fractions + ( uint32_t ) 100000000;
|
||||
}
|
||||
else
|
||||
{
|
||||
testTime.fractions = testTime.fractions - ( uint32_t ) 1;
|
||||
}
|
||||
|
||||
*pCurrentTime = testTime;
|
||||
}
|
||||
|
||||
void SetTimeFuncStub( const SntpServerInfo_t * pTimeServer,
|
||||
const SntpTimestamp_t * pServerTime,
|
||||
int64_t clockOffsetMs )
|
||||
{
|
||||
__CPROVER_assert( pTimeServer != NULL,
|
||||
"SetTimeFuncStub pTimeServer is NULL." );
|
||||
|
||||
__CPROVER_assert( pServerTime != NULL,
|
||||
"SetTimeFuncStub pServerTime is NULL." );
|
||||
}
|
||||
|
||||
SntpStatus_t Sntp_SerializeRequest( SntpTimestamp_t * pRequestTime,
|
||||
uint32_t randomNumber,
|
||||
void * pBuffer,
|
||||
size_t bufferSize )
|
||||
{
|
||||
__CPROVER_assert( pRequestTime != NULL,
|
||||
"Sntp_SerializeRequest pRequestTime is NULL." );
|
||||
|
||||
__CPROVER_assert( pBuffer != NULL,
|
||||
"Sntp_SerializeRequest pBuffer is NULL." );
|
||||
|
||||
return SntpSuccess;
|
||||
}
|
||||
|
||||
SntpStatus_t Sntp_DeserializeResponse( const SntpTimestamp_t * pRequestTime,
|
||||
const SntpTimestamp_t * pResponseRxTime,
|
||||
const void * pResponseBuffer,
|
||||
size_t bufferSize,
|
||||
SntpResponseData_t * pParsedResponse )
|
||||
{
|
||||
if( nondet_bool() )
|
||||
{
|
||||
return SntpSuccess;
|
||||
}
|
||||
else
|
||||
{
|
||||
return SntpRejectedResponseRetryWithBackoff;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,103 @@
|
||||
# Include file path configuration for coreSNTP library.
|
||||
include(${MODULE_ROOT_DIR}/coreSntpFilePaths.cmake)
|
||||
|
||||
project ("coreSNTP unit tests")
|
||||
cmake_minimum_required (VERSION 3.2.0)
|
||||
|
||||
# ==================== Define your project name ========================
|
||||
set(project_name "core_sntp")
|
||||
|
||||
# ===================== Create your mock here ========================
|
||||
|
||||
# list the files to mock here
|
||||
list(APPEND mock_list
|
||||
"${MODULE_ROOT_DIR}/source/include/core_sntp_serializer.h"
|
||||
)
|
||||
|
||||
# list the directories your mocks need
|
||||
list(APPEND mock_include_list
|
||||
${CORE_SNTP_INCLUDE_PUBLIC_DIRS}
|
||||
)
|
||||
#list the definitions of your mocks to control what to be included
|
||||
list(APPEND mock_define_list
|
||||
""
|
||||
)
|
||||
|
||||
# ================= Create the library under test here ==================
|
||||
|
||||
# list the files you would like to test here
|
||||
list(APPEND real_source_files
|
||||
${CORE_SNTP_SOURCES}
|
||||
)
|
||||
|
||||
# list the directories the module under test includes
|
||||
list(APPEND real_include_directories
|
||||
${CORE_SNTP_INCLUDE_PUBLIC_DIRS}
|
||||
${CMAKE_CURRENT_LIST_DIR}
|
||||
)
|
||||
|
||||
# ===================== Create UnitTest Code here =====================
|
||||
|
||||
# list the directories your test needs to include
|
||||
list(APPEND test_include_directories
|
||||
${CORE_SNTP_INCLUDE_PUBLIC_DIRS}
|
||||
${CMAKE_CURRENT_LIST_DIR}
|
||||
)
|
||||
|
||||
# ============================= Create unit test targets ===================================
|
||||
|
||||
set(mock_name "${project_name}_mock")
|
||||
set(real_name "${project_name}_real")
|
||||
|
||||
create_mock_list(${mock_name}
|
||||
"${mock_list}"
|
||||
"${MODULE_ROOT_DIR}/tools/cmock/project.yml"
|
||||
"${mock_include_list}"
|
||||
"${mock_define_list}"
|
||||
)
|
||||
|
||||
create_real_library(${real_name}
|
||||
"${real_source_files}"
|
||||
"${real_include_directories}"
|
||||
"${mock_name}"
|
||||
)
|
||||
|
||||
# As both Mock and Real libraries targets contain the
|
||||
# symbols for the core_sntp_serializer.c file, the linking
|
||||
# order has the mock library first for the core_sntp_client_utest.c
|
||||
# to use the mock for Serializer API calls.
|
||||
list(APPEND utest_link_list
|
||||
-l${mock_name}
|
||||
lib${real_name}.a
|
||||
)
|
||||
|
||||
list(APPEND utest_dep_list
|
||||
${real_name}
|
||||
)
|
||||
|
||||
# core_sntp_client_utest target
|
||||
set(utest_name "${project_name}_client_utest")
|
||||
set(utest_source "${project_name}_client_utest.c")
|
||||
create_test(${utest_name}
|
||||
${utest_source}
|
||||
"${utest_link_list}"
|
||||
"${utest_dep_list}"
|
||||
"${test_include_directories}"
|
||||
)
|
||||
|
||||
# Redefine the linking list as the mock is not needed for
|
||||
# the core_sntp_serializer tests.
|
||||
set(utest_link_list "")
|
||||
list(APPEND utest_link_list
|
||||
lib${real_name}.a
|
||||
)
|
||||
|
||||
# core_sntp_serializer_utest target
|
||||
set(utest_name "${project_name}_serializer_utest")
|
||||
set(utest_source "${project_name}_serializer_utest.c")
|
||||
create_test(${utest_name}
|
||||
${utest_source}
|
||||
"${utest_link_list}"
|
||||
"${utest_dep_list}"
|
||||
"${test_include_directories}"
|
||||
)
|
||||
@ -0,0 +1,58 @@
|
||||
# Macro utility to clone the CMock submodule.
|
||||
macro( clone_cmock )
|
||||
find_package( Git REQUIRED )
|
||||
message( "Cloning submodule CMock." )
|
||||
execute_process( COMMAND rm -rf ${CMOCK_DIR}
|
||||
COMMAND ${GIT_EXECUTABLE} submodule update --checkout --init --recursive ${CMOCK_DIR}
|
||||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
|
||||
RESULT_VARIABLE CMOCK_CLONE_RESULT )
|
||||
|
||||
if( NOT ${CMOCK_CLONE_RESULT} STREQUAL "0" )
|
||||
message( FATAL_ERROR "Failed to clone CMock submodule." )
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
# Macro utility to add library targets for Unity and CMock to build configuration.
|
||||
macro( add_cmock_targets )
|
||||
# Build Configuration for CMock and Unity libraries.
|
||||
list( APPEND CMOCK_INCLUDE_DIRS
|
||||
"${CMOCK_DIR}/vendor/unity/src/"
|
||||
"${CMOCK_DIR}/vendor/unity/extras/fixture/src"
|
||||
"${CMOCK_DIR}/vendor/unity/extras/memory/src"
|
||||
"${CMOCK_DIR}/src"
|
||||
)
|
||||
|
||||
add_library(cmock STATIC
|
||||
"${CMOCK_DIR}/src/cmock.c"
|
||||
)
|
||||
|
||||
set_target_properties(cmock PROPERTIES
|
||||
ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib
|
||||
POSITION_INDEPENDENT_CODE ON
|
||||
COMPILE_FLAGS "-Og"
|
||||
)
|
||||
|
||||
target_include_directories(cmock PUBLIC
|
||||
${CMOCK_DIR}/src
|
||||
${CMOCK_DIR}/vendor/unity/src/
|
||||
${CMOCK_DIR}/examples
|
||||
${CMOCK_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
add_library(unity STATIC
|
||||
"${CMOCK_DIR}/vendor/unity/src/unity.c"
|
||||
"${CMOCK_DIR}/vendor/unity/extras/fixture/src/unity_fixture.c"
|
||||
"${CMOCK_DIR}/vendor/unity/extras/memory/src/unity_memory.c"
|
||||
)
|
||||
|
||||
set_target_properties(unity PROPERTIES
|
||||
ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib
|
||||
POSITION_INDEPENDENT_CODE ON
|
||||
)
|
||||
|
||||
target_include_directories(unity PUBLIC
|
||||
${CMOCK_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
target_link_libraries(cmock unity)
|
||||
endmacro()
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* coreSNTP v1.2.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 core_sntp_config.h
|
||||
* @brief This header sets configuration macros for the SNTP library.
|
||||
*/
|
||||
#ifndef CORE_SNTP_CONFIG_H_
|
||||
#define CORE_SNTP_CONFIG_H_
|
||||
|
||||
/* Standard include. */
|
||||
#include <stdio.h>
|
||||
|
||||
/* @[code_example_loggingmacros] */
|
||||
/************* Define Logging Macros using printf function ***********/
|
||||
|
||||
#define PrintfError( ... ) printf( "Error: "__VA_ARGS__ ); printf( "\n" )
|
||||
#define PrintfWarn( ... ) printf( "Warn: "__VA_ARGS__ ); printf( "\n" )
|
||||
#define PrintfInfo( ... ) printf( "Info: " __VA_ARGS__ ); printf( "\n" )
|
||||
#define PrintfDebug( ... ) printf( "Debug: " __VA_ARGS__ ); printf( "\n" )
|
||||
|
||||
#ifdef LOGGING_LEVEL_ERROR
|
||||
#define LogError( message ) PrintfError message
|
||||
#elif defined( LOGGING_LEVEL_WARNING )
|
||||
#define LogError( message ) PrintfError message
|
||||
#define LogWarn( message ) PrintfWarn message
|
||||
#elif defined( LOGGING_LEVEL_INFO )
|
||||
#define LogError( message ) PrintfError message
|
||||
#define LogWarn( message ) PrintfWarn message
|
||||
#define LogInfo( message ) PrintfInfo message
|
||||
#elif defined( LOGGING_LEVEL_DEBUG )
|
||||
#define LogError( message ) PrintfError message
|
||||
#define LogWarn( message ) PrintfWarn message
|
||||
#define LogInfo( message ) PrintfInfo message
|
||||
#define LogDebug( message ) PrintfDebug message
|
||||
#endif /* ifdef LOGGING_LEVEL_ERROR */
|
||||
|
||||
/**************************************************/
|
||||
/* @[code_example_loggingmacros] */
|
||||
|
||||
#endif /* ifndef CORE_SNTP_CONFIG_H_ */
|
||||
@ -0,0 +1,967 @@
|
||||
/*
|
||||
* coreSNTP v1.2.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.
|
||||
*/
|
||||
|
||||
/* Standard includes. */
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/* POSIX include. */
|
||||
#include <arpa/inet.h>
|
||||
|
||||
/* Unity include. */
|
||||
#include "unity.h"
|
||||
|
||||
/* coreSNTP Serializer API include */
|
||||
#include "core_sntp_serializer.h"
|
||||
|
||||
#define TEST_TIMESTAMP \
|
||||
{ \
|
||||
.seconds = UINT32_MAX, \
|
||||
.fractions = 1000 \
|
||||
}
|
||||
|
||||
#define ZERO_TIMESTAMP \
|
||||
{ \
|
||||
.seconds = 0, \
|
||||
.fractions = 0 \
|
||||
}
|
||||
|
||||
/* Bits 3-5 are used for Version in 1st byte of SNTP packet. */
|
||||
#define SNTP_PACKET_VERSION_VAL ( 4 /* Version */ << 3 /* Bits 3-5 used in byte */ )
|
||||
|
||||
/* Values for "Mode" field in an SNTP packet. */
|
||||
#define SNTP_PACKET_MODE_SERVER ( 4 )
|
||||
#define SNTP_PACKET_MODE_CLIENT ( 3 )
|
||||
|
||||
/* The least significant bit position of "Leap Indicator" field
|
||||
* in the first byte of an SNTP packet. */
|
||||
#define SNTP_PACKET_LEAP_INDICATOR_LSB ( 6 )
|
||||
|
||||
/* The byte positions of SNTP packet fields in the 48 bytes sized
|
||||
* packet format. */
|
||||
#define SNTP_PACKET_STRATUM_BYTE_POS ( 1 )
|
||||
#define SNTP_PACKET_KOD_CODE_FIRST_BYTE_POS ( 12 )
|
||||
#define SNTP_PACKET_ORIGIN_TIME_FIRST_BYTE_POS ( 24 )
|
||||
#define SNTP_PACKET_RX_TIMESTAMP_FIRST_BYTE_POS ( 32 )
|
||||
#define SNTP_PACKET_TX_TIMESTAMP_FIRST_BYTE_POS ( 40 )
|
||||
|
||||
/* Values of "Stratum" field in an SNTP packet. */
|
||||
#define SNTP_PACKET_STRATUM_KOD ( 0 )
|
||||
#define SNTP_PACKET_STRATUM_SECONDARY_SERVER ( 15 )
|
||||
|
||||
/* ASCII string codes that a server can send in a Kiss-o'-Death response. */
|
||||
#define KOD_CODE_DENY "DENY"
|
||||
#define KOD_CODE_RSTR "RSTR"
|
||||
#define KOD_CODE_RATE "RATE"
|
||||
#define KOD_CODE_OTHER_EXAMPLE_1 "AUTH"
|
||||
#define KOD_CODE_OTHER_EXAMPLE_2 "CRYP"
|
||||
|
||||
#define YEARS_20_IN_SECONDS ( ( 20 * 365 + 20 / 4 ) * 24 * 3600 )
|
||||
#define YEARS_68_IN_SECONDS ( ( 68 * 365 + 68 / 4 ) * 24 * 3600 )
|
||||
|
||||
/* Macro utility to convert the fixed-size Kiss-o'-Death ASCII code
|
||||
* to integer.*/
|
||||
#define INTEGER_VAL_OF_KOD_CODE( codePtr ) \
|
||||
( ( uint32_t ) ( ( ( uint32_t ) codePtr[ 0 ] << 24 ) | \
|
||||
( ( uint32_t ) codePtr[ 1 ] << 16 ) | \
|
||||
( ( uint32_t ) codePtr[ 2 ] << 8 ) | \
|
||||
( ( uint32_t ) codePtr[ 3 ] ) ) )
|
||||
|
||||
/* Buffer used for SNTP requests and responses in tests. */
|
||||
static uint8_t testBuffer[ SNTP_PACKET_BASE_SIZE ];
|
||||
|
||||
static SntpResponseData_t parsedData;
|
||||
|
||||
static SntpTimestamp_t zeroTimestamp = ZERO_TIMESTAMP;
|
||||
|
||||
/* ============================ Helper Functions ============================ */
|
||||
|
||||
/* Utility macro to convert seconds to milliseconds. */
|
||||
static uint64_t TO_MS( uint64_t seconds )
|
||||
{
|
||||
return( seconds * 1000 );
|
||||
}
|
||||
|
||||
static void addTimestampToResponseBuffer( SntpTimestamp_t * pTime,
|
||||
uint8_t * pResponseBuffer,
|
||||
size_t startingPos )
|
||||
{
|
||||
/* Convert the request time into network byte order to use to fill in buffer. */
|
||||
uint32_t secs = pTime->seconds;
|
||||
uint32_t fracs = pTime->fractions;
|
||||
|
||||
pResponseBuffer[ startingPos ] = secs >> 24; /* seconds, byte 1*/
|
||||
pResponseBuffer[ startingPos + 1 ] = secs >> 16; /* seconds, byte 2 */
|
||||
pResponseBuffer[ startingPos + 2 ] = secs >> 8; /* seconds, byte 3 */
|
||||
pResponseBuffer[ startingPos + 3 ] = secs; /* seconds, byte 4 */
|
||||
pResponseBuffer[ startingPos + 4 ] = fracs >> 24; /* fractions, byte 1*/
|
||||
pResponseBuffer[ startingPos + 5 ] = fracs >> 16; /* fractions, byte 2 */
|
||||
pResponseBuffer[ startingPos + 6 ] = fracs >> 8; /* fractions, byte 3 */
|
||||
pResponseBuffer[ startingPos + 7 ] = fracs; /* fractions, byte 4 */
|
||||
}
|
||||
|
||||
static void fillValidSntpResponseData( uint8_t * pBuffer,
|
||||
SntpTimestamp_t * pRequestTime )
|
||||
{
|
||||
/* Clear the buffer. */
|
||||
memset( pBuffer, 0, SNTP_PACKET_BASE_SIZE );
|
||||
|
||||
/* Set the "Version" and "Mode" fields in the first byte of SNTP packet. */
|
||||
pBuffer[ 0 ] = SNTP_PACKET_VERSION_VAL | SNTP_PACKET_MODE_SERVER;
|
||||
|
||||
/* Set the SNTP response packet to contain the "originate" timestamp
|
||||
* correctly, as matching the SNTP request timestamp. */
|
||||
addTimestampToResponseBuffer( pRequestTime,
|
||||
pBuffer,
|
||||
SNTP_PACKET_ORIGIN_TIME_FIRST_BYTE_POS );
|
||||
|
||||
SntpTimestamp_t testTime = TEST_TIMESTAMP;
|
||||
|
||||
/* Set the SNTP response packet to contain the "receive" timestamp
|
||||
* correctly, as matching the SNTP request timestamp. */
|
||||
addTimestampToResponseBuffer( &testTime,
|
||||
pBuffer,
|
||||
SNTP_PACKET_RX_TIMESTAMP_FIRST_BYTE_POS );
|
||||
|
||||
/* Set the SNTP response packet to contain the "transmit" timestamp
|
||||
* correctly, as matching the SNTP request timestamp. */
|
||||
addTimestampToResponseBuffer( &testTime,
|
||||
pBuffer,
|
||||
SNTP_PACKET_TX_TIMESTAMP_FIRST_BYTE_POS );
|
||||
|
||||
/* Set the "Stratum" byte in the response packet to represent a
|
||||
* secondary NTP server. */
|
||||
pBuffer[ SNTP_PACKET_STRATUM_BYTE_POS ] = SNTP_PACKET_STRATUM_SECONDARY_SERVER;
|
||||
}
|
||||
|
||||
/* Common test code that fills SNTP response packet with server times and validates
|
||||
* that @ref Sntp_DeserializeResponse API correctly calculates the clock offset. */
|
||||
static void testClockOffsetCalculation( SntpTimestamp_t * clientTxTime,
|
||||
SntpTimestamp_t * serverRxTime,
|
||||
SntpTimestamp_t * serverTxTime,
|
||||
SntpTimestamp_t * clientRxTime,
|
||||
SntpStatus_t expectedStatus,
|
||||
int64_t expectedClockOffsetMs )
|
||||
{
|
||||
/* Update the response packet with the server time. */
|
||||
addTimestampToResponseBuffer( clientTxTime,
|
||||
testBuffer,
|
||||
SNTP_PACKET_ORIGIN_TIME_FIRST_BYTE_POS );
|
||||
addTimestampToResponseBuffer( serverRxTime,
|
||||
testBuffer,
|
||||
SNTP_PACKET_RX_TIMESTAMP_FIRST_BYTE_POS );
|
||||
addTimestampToResponseBuffer( serverTxTime,
|
||||
testBuffer,
|
||||
SNTP_PACKET_TX_TIMESTAMP_FIRST_BYTE_POS );
|
||||
|
||||
/* Call the API under test. */
|
||||
TEST_ASSERT_EQUAL( expectedStatus, Sntp_DeserializeResponse( clientTxTime,
|
||||
clientRxTime,
|
||||
testBuffer,
|
||||
sizeof( testBuffer ),
|
||||
&parsedData ) );
|
||||
|
||||
/* Make sure that the API has indicated in the output parameter that
|
||||
* clock-offset could not be calculated. */
|
||||
TEST_ASSERT_EQUAL( expectedClockOffsetMs, parsedData.clockOffsetMs );
|
||||
|
||||
/* Validate other fields in the output parameter. */
|
||||
TEST_ASSERT_EQUAL( 0, memcmp( &parsedData.serverTime, serverTxTime, sizeof( SntpTimestamp_t ) ) );
|
||||
TEST_ASSERT_EQUAL( NoLeapSecond, parsedData.leapSecondType );
|
||||
TEST_ASSERT_EQUAL( SNTP_KISS_OF_DEATH_CODE_NONE, parsedData.rejectedResponseCode );
|
||||
}
|
||||
|
||||
/* ============================ UNITY FIXTURES ============================ */
|
||||
|
||||
/* Called before each test method. */
|
||||
void setUp()
|
||||
{
|
||||
memset( &parsedData, 0, sizeof( parsedData ) );
|
||||
}
|
||||
|
||||
/* 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 @ref Sntp_SerializeRequest with invalid parameters.
|
||||
*/
|
||||
void test_SerializeRequest_InvalidParams( void )
|
||||
{
|
||||
SntpTimestamp_t testTime = TEST_TIMESTAMP;
|
||||
|
||||
/* Pass invalid time object. */
|
||||
TEST_ASSERT_EQUAL( SntpErrorBadParameter,
|
||||
Sntp_SerializeRequest( NULL,
|
||||
( rand() % UINT32_MAX ),
|
||||
testBuffer,
|
||||
sizeof( testBuffer ) ) );
|
||||
|
||||
/* Pass invalid buffer. */
|
||||
TEST_ASSERT_EQUAL( SntpErrorBadParameter,
|
||||
Sntp_SerializeRequest( &testTime,
|
||||
( rand() % UINT32_MAX ),
|
||||
NULL,
|
||||
sizeof( testBuffer ) ) );
|
||||
|
||||
/* Pass zero timestamp for request time. */
|
||||
TEST_ASSERT_EQUAL( SntpErrorBadParameter,
|
||||
Sntp_SerializeRequest( &zeroTimestamp,
|
||||
( rand() % UINT32_MAX ),
|
||||
testBuffer,
|
||||
sizeof( testBuffer ) ) );
|
||||
|
||||
/* Pass a buffer size less than 48 bytes of minimum SNTP packet size. */
|
||||
TEST_ASSERT_EQUAL( SntpErrorBufferTooSmall,
|
||||
Sntp_SerializeRequest( &testTime,
|
||||
( rand() % UINT32_MAX ),
|
||||
testBuffer,
|
||||
1 ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Validate the serialization operation of the @ref Sntp_SerializeRequest API.
|
||||
*/
|
||||
void test_SerializeRequest_NominalCase( void )
|
||||
{
|
||||
SntpTimestamp_t testTime = TEST_TIMESTAMP;
|
||||
const uint32_t randomVal = 0xAABBCCDD;
|
||||
|
||||
/* Expected transmit timestamp in the SNTP request packet. */
|
||||
const SntpTimestamp_t expectedTxTime =
|
||||
{
|
||||
.seconds = testTime.seconds,
|
||||
.fractions = ( testTime.fractions | ( randomVal >> 16 ) )
|
||||
};
|
||||
|
||||
/* The expected serialization of the SNTP request packet. */
|
||||
uint8_t expectedSerialization[ SNTP_PACKET_BASE_SIZE ] =
|
||||
{
|
||||
0x00 /* Leap Indicator */ | 0x20 /* Version */ | 0x03, /* Client Mode */
|
||||
0x00, /* stratum */
|
||||
0x00, /* poll interval */
|
||||
0x00, /* precision */
|
||||
0x00, 0x00, 0x00, 0x00, /* root delay */
|
||||
0x00, 0x00, 0x00, 0x00, /* root dispersion */
|
||||
0x00, 0x00, 0x00, 0x00, /* reference ID */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* reference time */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* origin timestamp */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* receive timestamp */
|
||||
expectedTxTime.seconds >> 24, /* transmit timestamp - seconds, byte 1 */
|
||||
expectedTxTime.seconds >> 16, /* transmit timestamp - seconds, byte 2 */
|
||||
expectedTxTime.seconds >> 8, /* transmit timestamp - seconds, byte 3 */
|
||||
expectedTxTime.seconds, /* transmit timestamp - seconds, byte 4 */
|
||||
expectedTxTime.fractions >> 24, /* transmit timestamp - fractions, byte 1 */
|
||||
expectedTxTime.fractions >> 16, /* transmit timestamp - fractions, byte 2 */
|
||||
expectedTxTime.fractions >> 8, /* transmit timestamp - fractions, byte 3 */
|
||||
expectedTxTime.fractions, /* transmit timestamp - fractions, byte 4 */
|
||||
};
|
||||
|
||||
/* Call the API under test. */
|
||||
TEST_ASSERT_EQUAL( SntpSuccess,
|
||||
Sntp_SerializeRequest( &testTime,
|
||||
randomVal,
|
||||
testBuffer,
|
||||
sizeof( testBuffer ) ) );
|
||||
|
||||
/* Validate that serialization operation by the API. */
|
||||
TEST_ASSERT_EQUAL_UINT8_ARRAY( expectedSerialization,
|
||||
testBuffer,
|
||||
SNTP_PACKET_BASE_SIZE );
|
||||
|
||||
/* Check that the request timestamp object has been updated with the random value. */
|
||||
TEST_ASSERT_EQUAL( 0, memcmp( &expectedTxTime,
|
||||
&testTime,
|
||||
sizeof( SntpTimestamp_t ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test @ref Sntp_DeserializeResponse with invalid parameters.
|
||||
*/
|
||||
void test_DeserializeResponse_InvalidParams( void )
|
||||
{
|
||||
SntpTimestamp_t testTime = TEST_TIMESTAMP;
|
||||
|
||||
/* Pass invalid time objects. */
|
||||
TEST_ASSERT_EQUAL( SntpErrorBadParameter,
|
||||
Sntp_DeserializeResponse( NULL,
|
||||
&testTime,
|
||||
testBuffer,
|
||||
sizeof( testBuffer ),
|
||||
&parsedData ) );
|
||||
TEST_ASSERT_EQUAL( SntpErrorBadParameter,
|
||||
Sntp_DeserializeResponse( &testTime,
|
||||
NULL,
|
||||
testBuffer,
|
||||
sizeof( testBuffer ),
|
||||
&parsedData ) );
|
||||
|
||||
/* Pass invalid buffer. */
|
||||
TEST_ASSERT_EQUAL( SntpErrorBadParameter,
|
||||
Sntp_DeserializeResponse( &testTime,
|
||||
&testTime,
|
||||
NULL,
|
||||
sizeof( testBuffer ),
|
||||
&parsedData ) );
|
||||
|
||||
/* Pass a buffer size less than 48 bytes of minimum SNTP packet size. */
|
||||
TEST_ASSERT_EQUAL( SntpErrorBufferTooSmall,
|
||||
Sntp_DeserializeResponse( &testTime,
|
||||
&testTime,
|
||||
testBuffer,
|
||||
sizeof( testBuffer ) / 2,
|
||||
&parsedData ) );
|
||||
|
||||
/* Pass invalid output parameter. */
|
||||
TEST_ASSERT_EQUAL( SntpErrorBadParameter,
|
||||
Sntp_DeserializeResponse( &testTime,
|
||||
&testTime,
|
||||
testBuffer,
|
||||
sizeof( testBuffer ),
|
||||
NULL ) );
|
||||
|
||||
/* Pass zero timestamp for request time. */
|
||||
TEST_ASSERT_EQUAL( SntpErrorBadParameter,
|
||||
Sntp_DeserializeResponse( &zeroTimestamp,
|
||||
&testTime,
|
||||
testBuffer,
|
||||
sizeof( testBuffer ),
|
||||
&parsedData ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test that @ref Sntp_DeserializeResponse API can detect invalid
|
||||
* SNTP response packets.
|
||||
*/
|
||||
void test_DeserializeResponse_Invalid_Responses( void )
|
||||
{
|
||||
SntpTimestamp_t clientTime = TEST_TIMESTAMP;
|
||||
|
||||
/* Fill buffer with general SNTP response data. */
|
||||
fillValidSntpResponseData( testBuffer, &clientTime );
|
||||
|
||||
/* ******* Test when SNTP packet does not a non-server value in the "Mode" field. **** */
|
||||
testBuffer[ 0 ] = SNTP_PACKET_VERSION_VAL | SNTP_PACKET_MODE_CLIENT;
|
||||
|
||||
/* Call the API under test. */
|
||||
TEST_ASSERT_EQUAL( SntpInvalidResponse, Sntp_DeserializeResponse( &clientTime,
|
||||
&clientTime,
|
||||
testBuffer,
|
||||
sizeof( testBuffer ),
|
||||
&parsedData ) );
|
||||
|
||||
|
||||
/* Set the Mode field to the correct value for Server. */
|
||||
testBuffer[ 0 ] = SNTP_PACKET_VERSION_VAL | SNTP_PACKET_MODE_SERVER;
|
||||
|
||||
/************** Test when "originate timestamp" is zero ***************/
|
||||
addTimestampToResponseBuffer( &zeroTimestamp,
|
||||
testBuffer,
|
||||
SNTP_PACKET_ORIGIN_TIME_FIRST_BYTE_POS );
|
||||
/* Call the API under test. */
|
||||
TEST_ASSERT_EQUAL( SntpInvalidResponse, Sntp_DeserializeResponse( &clientTime,
|
||||
&clientTime,
|
||||
testBuffer,
|
||||
sizeof( testBuffer ),
|
||||
&parsedData ) );
|
||||
|
||||
/* Set the "originate timestamp" to a non-zero value for the next test. */
|
||||
addTimestampToResponseBuffer( &clientTime,
|
||||
testBuffer,
|
||||
SNTP_PACKET_ORIGIN_TIME_FIRST_BYTE_POS );
|
||||
|
||||
|
||||
/************** Test when "receive timestamp" is zero ***************/
|
||||
addTimestampToResponseBuffer( &zeroTimestamp,
|
||||
testBuffer,
|
||||
SNTP_PACKET_RX_TIMESTAMP_FIRST_BYTE_POS );
|
||||
/* Call the API under test. */
|
||||
TEST_ASSERT_EQUAL( SntpInvalidResponse, Sntp_DeserializeResponse( &clientTime,
|
||||
&clientTime,
|
||||
testBuffer,
|
||||
sizeof( testBuffer ),
|
||||
&parsedData ) );
|
||||
|
||||
/* Set the "receive timestamp" to a non-zero value for the next test. */
|
||||
addTimestampToResponseBuffer( &clientTime,
|
||||
testBuffer,
|
||||
SNTP_PACKET_RX_TIMESTAMP_FIRST_BYTE_POS );
|
||||
|
||||
|
||||
/************** Test when "transmit timestamp" is zero ***************/
|
||||
addTimestampToResponseBuffer( &zeroTimestamp,
|
||||
testBuffer,
|
||||
SNTP_PACKET_TX_TIMESTAMP_FIRST_BYTE_POS );
|
||||
/* Call the API under test. */
|
||||
TEST_ASSERT_EQUAL( SntpInvalidResponse, Sntp_DeserializeResponse( &clientTime,
|
||||
&clientTime,
|
||||
testBuffer,
|
||||
sizeof( testBuffer ),
|
||||
&parsedData ) );
|
||||
|
||||
/* Set the "transmit timestamp" to a non-zero value for the next test. */
|
||||
addTimestampToResponseBuffer( &clientTime,
|
||||
testBuffer,
|
||||
SNTP_PACKET_TX_TIMESTAMP_FIRST_BYTE_POS );
|
||||
|
||||
|
||||
/******** Test when SNTP response packet does not have "originate" timestamp matching
|
||||
* the "transmit" time sent by the client in the SNTP request. ************/
|
||||
SntpTimestamp_t originateTime = TEST_TIMESTAMP;
|
||||
|
||||
|
||||
/* Test when only the seconds part of the "originate" timestamp does not match
|
||||
* the client request time .*/
|
||||
originateTime.seconds = clientTime.seconds + 1;
|
||||
addTimestampToResponseBuffer( &originateTime,
|
||||
testBuffer,
|
||||
SNTP_PACKET_ORIGIN_TIME_FIRST_BYTE_POS );
|
||||
|
||||
/* Call the API under test. */
|
||||
TEST_ASSERT_EQUAL( SntpInvalidResponse, Sntp_DeserializeResponse( &clientTime,
|
||||
&clientTime,
|
||||
testBuffer,
|
||||
sizeof( testBuffer ),
|
||||
&parsedData ) );
|
||||
|
||||
/* Test when only the fractions part of the "originate" timestamp does not match
|
||||
* the client request time .*/
|
||||
originateTime.seconds = clientTime.seconds;
|
||||
originateTime.fractions = clientTime.fractions + 1;
|
||||
addTimestampToResponseBuffer( &originateTime,
|
||||
testBuffer,
|
||||
SNTP_PACKET_ORIGIN_TIME_FIRST_BYTE_POS );
|
||||
|
||||
|
||||
/* Call the API under test. */
|
||||
TEST_ASSERT_EQUAL( SntpInvalidResponse, Sntp_DeserializeResponse( &clientTime,
|
||||
&clientTime,
|
||||
testBuffer,
|
||||
sizeof( testBuffer ),
|
||||
&parsedData ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test @ref Sntp_DeserializeResponse API to de-serialize Kiss-o'-Death
|
||||
* responses from SNTP server.
|
||||
*
|
||||
* The API should return an error code appropriate for the Kiss-o'-Death code
|
||||
* and update the member of output parameter to point the ASCII string code
|
||||
* in the response packet.
|
||||
*/
|
||||
void test_DeserializeResponse_KoD_packets( void )
|
||||
{
|
||||
/* Use same value for request and response times, as API should not process
|
||||
* them for Kiss-o'-Death response packets. */
|
||||
SntpTimestamp_t testTime = TEST_TIMESTAMP;
|
||||
uint32_t KodCodeNetworkOrder = 0;
|
||||
|
||||
/* Populate the buffer with a valid SNTP response before converting it
|
||||
* into a Kiss-o'-Death message. */
|
||||
fillValidSntpResponseData( testBuffer, &testTime );
|
||||
|
||||
/* Update the "Stratum" field in the buffer to make the packet a Kiss-o'-Death message. */
|
||||
testBuffer[ SNTP_PACKET_STRATUM_BYTE_POS ] = SNTP_PACKET_STRATUM_KOD;
|
||||
|
||||
/* Common test code for testing de-serialization of Kiss-o'-Death packet containing a specific
|
||||
* code with@ref Sntp_DeserializeResponse API. */
|
||||
#define TEST_API_FOR_KOD_CODE( code, expectedStatus ) \
|
||||
do { \
|
||||
KodCodeNetworkOrder = INTEGER_VAL_OF_KOD_CODE( code ); \
|
||||
testBuffer[ SNTP_PACKET_KOD_CODE_FIRST_BYTE_POS ] = KodCodeNetworkOrder >> 24; \
|
||||
testBuffer[ SNTP_PACKET_KOD_CODE_FIRST_BYTE_POS + 1 ] = KodCodeNetworkOrder >> 16; \
|
||||
testBuffer[ SNTP_PACKET_KOD_CODE_FIRST_BYTE_POS + 2 ] = KodCodeNetworkOrder >> 8; \
|
||||
testBuffer[ SNTP_PACKET_KOD_CODE_FIRST_BYTE_POS + 3 ] = KodCodeNetworkOrder; \
|
||||
\
|
||||
/* Call API under test. */ \
|
||||
TEST_ASSERT_EQUAL( expectedStatus, \
|
||||
Sntp_DeserializeResponse( &testTime, \
|
||||
&testTime, \
|
||||
testBuffer, \
|
||||
sizeof( testBuffer ), \
|
||||
&parsedData ) ); \
|
||||
\
|
||||
/* Test that API has populated the output parameter with the parsed \
|
||||
* KoD code. */ \
|
||||
TEST_ASSERT_EQUAL( INTEGER_VAL_OF_KOD_CODE( code ), \
|
||||
parsedData.rejectedResponseCode ); \
|
||||
\
|
||||
} while( 0 )
|
||||
|
||||
/* Test Kiss-o'-Death server response with "DENY" code. */
|
||||
TEST_API_FOR_KOD_CODE( KOD_CODE_DENY, SntpRejectedResponseChangeServer );
|
||||
|
||||
/* Test Kiss-o'-Death server response with "RSTR" code. */
|
||||
TEST_API_FOR_KOD_CODE( KOD_CODE_RSTR, SntpRejectedResponseChangeServer );
|
||||
|
||||
/* Test Kiss-o'-Death server response with "RATE" code. */
|
||||
TEST_API_FOR_KOD_CODE( KOD_CODE_RATE, SntpRejectedResponseRetryWithBackoff );
|
||||
|
||||
/* ***** Test de-serialization of Kiss-o'-Death server response with other codes ***** */
|
||||
TEST_API_FOR_KOD_CODE( KOD_CODE_OTHER_EXAMPLE_1, SntpRejectedResponseOtherCode );
|
||||
TEST_API_FOR_KOD_CODE( KOD_CODE_OTHER_EXAMPLE_2, SntpRejectedResponseOtherCode );
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test that @ref Sntp_DeserializeResponse API can process an accepted
|
||||
* SNTP server response, and compute clock-offset when the server and client times
|
||||
* are >= 68 years apart.
|
||||
*/
|
||||
void test_DeserializeResponse_AcceptedResponse_ClockOffset_Edge_Cases( void )
|
||||
{
|
||||
SntpTimestamp_t clientTime = TEST_TIMESTAMP;
|
||||
|
||||
/* Fill buffer with general SNTP response data. */
|
||||
fillValidSntpResponseData( testBuffer, &clientTime );
|
||||
|
||||
/* Test when the client is 68 years ahead of server time .*/
|
||||
SntpTimestamp_t serverTime =
|
||||
{
|
||||
clientTime.seconds - YEARS_68_IN_SECONDS,
|
||||
clientTime.fractions
|
||||
};
|
||||
testClockOffsetCalculation( &clientTime, &serverTime,
|
||||
&serverTime, &clientTime,
|
||||
SntpSuccess,
|
||||
TO_MS( -YEARS_68_IN_SECONDS ) );
|
||||
|
||||
/* Now test when the client is 68 years ahead of server time .*/
|
||||
serverTime.seconds = clientTime.seconds + YEARS_68_IN_SECONDS;
|
||||
testClockOffsetCalculation( &clientTime, &serverTime,
|
||||
&serverTime, &clientTime,
|
||||
SntpSuccess,
|
||||
TO_MS( YEARS_68_IN_SECONDS ) );
|
||||
|
||||
/* Now test special cases when the server and client times are (INT32_MAX + 1) =
|
||||
* 2^31 apart seconds apart. The library should ALWAYS think that server
|
||||
* is ahead of the client in this special case, and thus return the maximum
|
||||
* signed 32 bit integer as the clock-offset.
|
||||
*/
|
||||
/* Case when "Server Time - Client Time" results in negative value. */
|
||||
serverTime.seconds = clientTime.seconds + INT32_MAX + 1;
|
||||
testClockOffsetCalculation( &clientTime, &serverTime,
|
||||
&serverTime, &clientTime,
|
||||
SntpSuccess,
|
||||
TO_MS( ( int64_t ) INT32_MAX + 1 ) );
|
||||
/* Test when "Server Time - Client Time" results in positive value. */
|
||||
serverTime.seconds = UINT32_MAX;
|
||||
clientTime.seconds = serverTime.seconds - INT32_MAX - 1;
|
||||
testClockOffsetCalculation( &clientTime, &serverTime,
|
||||
&serverTime, &clientTime,
|
||||
SntpSuccess,
|
||||
TO_MS( ( int64_t ) INT32_MAX + 1 ) );
|
||||
|
||||
/* Reset client time to UINT32_MAX */
|
||||
clientTime.seconds = UINT32_MAX;
|
||||
|
||||
/* Now test cases when the server and client times are exactly
|
||||
* INT32_MAX seconds apart. */
|
||||
serverTime.seconds = clientTime.seconds - INT32_MAX;
|
||||
testClockOffsetCalculation( &clientTime, &serverTime,
|
||||
&serverTime, &clientTime,
|
||||
SntpSuccess,
|
||||
TO_MS( -INT32_MAX ) );
|
||||
serverTime.seconds = clientTime.seconds + INT32_MAX;
|
||||
testClockOffsetCalculation( &clientTime, &serverTime,
|
||||
&serverTime, &clientTime,
|
||||
SntpSuccess,
|
||||
TO_MS( INT32_MAX ) );
|
||||
|
||||
/* Reset client and server times to be 68 years apart. */
|
||||
clientTime.seconds = UINT32_MAX;
|
||||
serverTime.seconds = UINT32_MAX + YEARS_68_IN_SECONDS;
|
||||
|
||||
/* Now test the contrived case when only the send network path
|
||||
* represents timestamps that overflow but the receive network path
|
||||
* has timestamps that do not overflow.
|
||||
* As only the single network path contains time difference of 68 years,
|
||||
* the expected clock-offset, being an average of the network paths, is
|
||||
* 34 years of duration. */
|
||||
testClockOffsetCalculation( &clientTime, &serverTime, /* Send Path times are 68 years apart */
|
||||
&serverTime, &serverTime, /* Receive path times are the same. */
|
||||
SntpSuccess,
|
||||
TO_MS( YEARS_68_IN_SECONDS / 2 ) ); /* Expected offset of 34 years. */
|
||||
|
||||
/* Now test the contrived case when only the receive network path
|
||||
* represents timestamps that overflow but the send network path
|
||||
* has timestamps that do not overflow.
|
||||
* As only the single network path contains time difference of 68 years,
|
||||
* the expected clock-offset, being an average of the network paths, is
|
||||
* 34 years of duration. */
|
||||
testClockOffsetCalculation( &clientTime, &clientTime, /* Send Path times are the same, i.e. don't overflow */
|
||||
&serverTime, &clientTime, /* Receive path times are 68 years apart. */
|
||||
SntpSuccess,
|
||||
TO_MS( YEARS_68_IN_SECONDS / 2 ) ); /* Expected offset of 34 years. */
|
||||
}
|
||||
|
||||
void test_Sntp_DeserializeResponse_ClockOffset_Milliseconds_Cases( void )
|
||||
{
|
||||
SntpTimestamp_t clientTime =
|
||||
{
|
||||
.seconds = 0,
|
||||
/* 500 milliseconds. */
|
||||
.fractions = 500 * 1000 * SNTP_FRACTION_VALUE_PER_MICROSECOND
|
||||
};
|
||||
|
||||
/* Fill buffer with general SNTP response data. */
|
||||
fillValidSntpResponseData( testBuffer, &clientTime );
|
||||
|
||||
SntpTimestamp_t serverTime =
|
||||
{
|
||||
.seconds = clientTime.seconds,
|
||||
.fractions = clientTime.fractions
|
||||
};
|
||||
|
||||
/* Test when server is ahead of client time. */
|
||||
serverTime.fractions = 700 * 1000 * SNTP_FRACTION_VALUE_PER_MICROSECOND; /* 700 milliseconds. */
|
||||
testClockOffsetCalculation( &clientTime, &serverTime, /* Send Path times are 68 years apart */
|
||||
&serverTime, &clientTime, /* Receive path times are the same. */
|
||||
SntpSuccess, 200 );
|
||||
|
||||
/* Test when server is behind client time. */
|
||||
serverTime.fractions = 100 * 1000 * SNTP_FRACTION_VALUE_PER_MICROSECOND; /* 100 milliseconds. */
|
||||
testClockOffsetCalculation( &clientTime, &serverTime, /* Send Path times are 68 years apart */
|
||||
&serverTime, &clientTime, /* Receive path times are the same. */
|
||||
SntpSuccess, -400 );
|
||||
|
||||
/* Test when complex case of NTP time overflow with client being ahead of server by 3900 milliseconds. */
|
||||
serverTime.seconds = UINT32_MAX - 3; /* 4 seconds behind in "seconds" value. */
|
||||
serverTime.fractions = 600 * 1000 * SNTP_FRACTION_VALUE_PER_MICROSECOND; /* 100 milliseconds ahead. */
|
||||
testClockOffsetCalculation( &clientTime, &serverTime, /* Send Path times are 68 years apart */
|
||||
&serverTime, &clientTime, /* Receive path times are the same. */
|
||||
SntpSuccess, -3900 );
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test that @ref Sntp_DeserializeResponse API can process an accepted
|
||||
* SNTP server response, and calculate the clock offset for non-overflow cases
|
||||
* (i.e. when the client and server times are within 34 years of each other).
|
||||
*/
|
||||
void test_DeserializeResponse_AcceptedResponse_Nominal_Case( void )
|
||||
{
|
||||
SntpTimestamp_t clientTxTime = TEST_TIMESTAMP;
|
||||
|
||||
/* Fill buffer with general SNTP response data. */
|
||||
fillValidSntpResponseData( testBuffer, &clientTxTime );
|
||||
|
||||
/* Use the the same values for Rx and Tx times for server and client in the first couple
|
||||
* of tests for simplicity. */
|
||||
|
||||
/* ==================Test when client and server are in same NTP era.================ */
|
||||
|
||||
/* Test when the client is 20 years ahead of server time to generate a negative offset
|
||||
* result.*/
|
||||
SntpTimestamp_t serverTxTime =
|
||||
{
|
||||
clientTxTime.seconds - YEARS_20_IN_SECONDS,
|
||||
clientTxTime.fractions
|
||||
};
|
||||
int32_t expectedOffset = -YEARS_20_IN_SECONDS;
|
||||
|
||||
testClockOffsetCalculation( &clientTxTime, &serverTxTime,
|
||||
&serverTxTime, &clientTxTime,
|
||||
SntpSuccess, TO_MS( expectedOffset ) );
|
||||
|
||||
/* Now test for the client being 20 years behind server time to generate a positive
|
||||
* offset result.*/
|
||||
serverTxTime.seconds = UINT32_MAX;
|
||||
clientTxTime.seconds = UINT32_MAX - YEARS_20_IN_SECONDS;
|
||||
expectedOffset = YEARS_20_IN_SECONDS;
|
||||
|
||||
testClockOffsetCalculation( &clientTxTime, &serverTxTime,
|
||||
&serverTxTime, &clientTxTime,
|
||||
SntpSuccess, TO_MS( expectedOffset ) );
|
||||
|
||||
/* ==================Test when client and server are in different NTP eras.================ */
|
||||
|
||||
/* Test when the server is ahead of client to generate a positive clock offset result.*/
|
||||
clientTxTime.seconds = UINT32_MAX; /* Client is in NTP era 0. */
|
||||
serverTxTime.seconds = UINT32_MAX + YEARS_20_IN_SECONDS; /* Server is in NTP era 1. */
|
||||
expectedOffset = YEARS_20_IN_SECONDS;
|
||||
|
||||
testClockOffsetCalculation( &clientTxTime, &serverTxTime,
|
||||
&serverTxTime, &clientTxTime,
|
||||
SntpSuccess, TO_MS( expectedOffset ) );
|
||||
|
||||
/* Test when the client is ahead of server to generate a negative clock offset result.*/
|
||||
clientTxTime.seconds = UINT32_MAX + YEARS_20_IN_SECONDS; /* Client is in NTP era 1. */
|
||||
serverTxTime.seconds = UINT32_MAX; /* Server is in NTP era 0. */
|
||||
expectedOffset = -YEARS_20_IN_SECONDS;
|
||||
|
||||
testClockOffsetCalculation( &clientTxTime, &serverTxTime,
|
||||
&serverTxTime, &clientTxTime,
|
||||
SntpSuccess, TO_MS( expectedOffset ) );
|
||||
|
||||
/* Now test with different values for T1 (client Tx), T2 (server Rx), T3 (server Tx) and T4 (client Rx)
|
||||
* that are used in the clock-offset calculation.
|
||||
* The test case uses 2 seconds as network delay on both Client -> Server and Server -> Client path
|
||||
* and 2 seconds for server processing time between receiving SNTP request and sending SNTP response */
|
||||
clientTxTime.seconds = UINT32_MAX;
|
||||
SntpTimestamp_t serverRxTime =
|
||||
{
|
||||
clientTxTime.seconds + YEARS_20_IN_SECONDS + 2,
|
||||
serverTxTime.fractions
|
||||
};
|
||||
serverTxTime.seconds = serverRxTime.seconds + 2;
|
||||
SntpTimestamp_t clientRxTime =
|
||||
{
|
||||
clientTxTime.seconds + 6, /* 2 seconds each for Client -> Server, Server -> Server,
|
||||
* Server -> Client */
|
||||
clientTxTime.fractions
|
||||
};
|
||||
expectedOffset = YEARS_20_IN_SECONDS;
|
||||
|
||||
testClockOffsetCalculation( &clientTxTime, &serverRxTime,
|
||||
&serverTxTime, &clientRxTime,
|
||||
SntpSuccess, TO_MS( expectedOffset ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test that @ref Sntp_DeserializeResponse API can de-serialize leap-second
|
||||
* information in an accepted SNTP response packet from a server.
|
||||
*/
|
||||
void test_DeserializeResponse_AcceptedResponse_LeapSecond( void )
|
||||
{
|
||||
SntpTimestamp_t clientTime = TEST_TIMESTAMP;
|
||||
SntpTimestamp_t serverTime = TEST_TIMESTAMP;
|
||||
|
||||
/* Fill buffer with general SNTP response data. */
|
||||
fillValidSntpResponseData( testBuffer, &clientTime );
|
||||
|
||||
/* Update the response packet with the server time. */
|
||||
addTimestampToResponseBuffer( &serverTime,
|
||||
testBuffer,
|
||||
SNTP_PACKET_RX_TIMESTAMP_FIRST_BYTE_POS );
|
||||
addTimestampToResponseBuffer( &serverTime,
|
||||
testBuffer,
|
||||
SNTP_PACKET_TX_TIMESTAMP_FIRST_BYTE_POS );
|
||||
|
||||
#define TEST_LEAP_SECOND_DESERIALIZATION( expectedLeapSecond ) \
|
||||
do { \
|
||||
/* Call the API under test. */ \
|
||||
TEST_ASSERT_EQUAL( SntpSuccess, Sntp_DeserializeResponse( &clientTime, \
|
||||
&clientTime, \
|
||||
testBuffer, \
|
||||
sizeof( testBuffer ), \
|
||||
&parsedData ) ); \
|
||||
\
|
||||
/* As the clock and server times are same, the clock offset, should be zero. */ \
|
||||
TEST_ASSERT_EQUAL( 0, parsedData.clockOffsetMs ); \
|
||||
\
|
||||
/* Validate other fields in the output parameter. */ \
|
||||
TEST_ASSERT_EQUAL( 0, memcmp( &parsedData.serverTime, &serverTime, sizeof( SntpTimestamp_t ) ) ); \
|
||||
TEST_ASSERT_EQUAL( expectedLeapSecond, parsedData.leapSecondType ); \
|
||||
TEST_ASSERT_EQUAL( SNTP_KISS_OF_DEATH_CODE_NONE, parsedData.rejectedResponseCode ); \
|
||||
} while( 0 )
|
||||
|
||||
/* Update SNTP response packet to indicate an upcoming leap second insertion. */
|
||||
testBuffer[ 0 ] = ( LastMinuteHas61Seconds << SNTP_PACKET_LEAP_INDICATOR_LSB ) |
|
||||
SNTP_PACKET_VERSION_VAL | SNTP_PACKET_MODE_SERVER;
|
||||
TEST_LEAP_SECOND_DESERIALIZATION( LastMinuteHas61Seconds );
|
||||
|
||||
/* Update SNTP response packet to indicate an upcoming leap second deletion. */
|
||||
testBuffer[ 0 ] = ( LastMinuteHas59Seconds << SNTP_PACKET_LEAP_INDICATOR_LSB ) |
|
||||
SNTP_PACKET_VERSION_VAL | SNTP_PACKET_MODE_SERVER;
|
||||
TEST_LEAP_SECOND_DESERIALIZATION( LastMinuteHas59Seconds );
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Tests the @ref Sntp_CalculatePollInterval utility function returns
|
||||
* error for invalid parameters passed to the API.
|
||||
*/
|
||||
void test_CalculatePollInterval_InvalidParams( void )
|
||||
{
|
||||
uint32_t pollInterval = 0;
|
||||
|
||||
/* Test with invalid clock frequency. */
|
||||
TEST_ASSERT_EQUAL( SntpErrorBadParameter, Sntp_CalculatePollInterval( 0,
|
||||
100,
|
||||
&pollInterval ) );
|
||||
/* Test with invalid desired accuracy. */
|
||||
TEST_ASSERT_EQUAL( SntpErrorBadParameter, Sntp_CalculatePollInterval( 100,
|
||||
0,
|
||||
&pollInterval ) );
|
||||
|
||||
/* Test with invalid output parameter. */
|
||||
TEST_ASSERT_EQUAL( SntpErrorBadParameter, Sntp_CalculatePollInterval( 100,
|
||||
50,
|
||||
NULL ) );
|
||||
|
||||
/* Test with parameters that cause poll interval value of less than 1 second. */
|
||||
TEST_ASSERT_EQUAL( SntpZeroPollInterval, Sntp_CalculatePollInterval( 10000 /* High Error Clock. */,
|
||||
1 /* High Accuracy Requirement */,
|
||||
&pollInterval ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Tests the @ref Sntp_CalculatePollInterval utility function calculates
|
||||
* the poll interval period as the closes power of 2 value for achieving the
|
||||
* desired clock accuracy.
|
||||
*/
|
||||
void test_CalculatePollInterval_Nominal( void )
|
||||
{
|
||||
uint32_t pollInterval = 0;
|
||||
uint32_t expectedInterval = 0;
|
||||
|
||||
/* Test the SNTPv4 specification example of 200 PPM clock frequency and
|
||||
* 1 minute of desired accuracy. */
|
||||
expectedInterval = 0x00040000;
|
||||
TEST_ASSERT_EQUAL( SntpSuccess, Sntp_CalculatePollInterval( 200 /* Clock Tolerance */,
|
||||
1 /* minute */ * 60 * 1000 /* Desired Accuracy */,
|
||||
&pollInterval ) );
|
||||
TEST_ASSERT_EQUAL( expectedInterval, pollInterval );
|
||||
|
||||
/* Test another case where the exact poll interval for achieving desired frequency
|
||||
* is an exponent of 2 value. For 512 seconds (or 2^9) poll interval, the maximum
|
||||
* clock drift with 125 PPM is 125 * 512 = 64000 microseconds = 64 milliseconds. */
|
||||
expectedInterval = 0x00000200;
|
||||
TEST_ASSERT_EQUAL( SntpSuccess, Sntp_CalculatePollInterval( 125 /* Clock Tolerance (PPM) */,
|
||||
64 /* Desired Accuracy (ms)*/,
|
||||
&pollInterval ) );
|
||||
|
||||
/* Test for maximum possible value of calculated poll interval when the clock frequency
|
||||
* tolerance is minimum (i.e. 1 PPM or high accuracy system clock ) but the desired accuracy
|
||||
* is very low (i.e. largest value of 16 bit parameter as 65535 ms OR ~ 1 minute).
|
||||
* This test proves that the 32-bit
|
||||
* width of poll integer value can hold the largest calculation of poll interval value. */
|
||||
expectedInterval = 0x02000000; /* 536,870,912 seconds OR ~ 17 years */
|
||||
TEST_ASSERT_EQUAL( SntpSuccess, Sntp_CalculatePollInterval( 1 /* Clock Tolerance (PPM) */,
|
||||
UINT16_MAX /* Desired Accuracy (ms)*/,
|
||||
&pollInterval ) );
|
||||
TEST_ASSERT_EQUAL( expectedInterval, pollInterval );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Tests the @ref Sntp_ConvertToUnixTime utility function returns
|
||||
* expected error when invalid parameters or unsupported timestamps are passed.
|
||||
*/
|
||||
void test_ConvertToUnixTime_InvalidParams( void )
|
||||
{
|
||||
SntpTimestamp_t sntpTime;
|
||||
|
||||
/* Use same memory for UNIX seconds and microseconds as we are not
|
||||
* testing those values. */
|
||||
uint32_t unixTime;
|
||||
|
||||
/* Test with NULL SNTP time. */
|
||||
TEST_ASSERT_EQUAL( SntpErrorBadParameter, Sntp_ConvertToUnixTime( NULL,
|
||||
&unixTime,
|
||||
&unixTime ) );
|
||||
/* Test with NULL output parameters. */
|
||||
TEST_ASSERT_EQUAL( SntpErrorBadParameter, Sntp_ConvertToUnixTime( &sntpTime,
|
||||
NULL,
|
||||
&unixTime ) );
|
||||
TEST_ASSERT_EQUAL( SntpErrorBadParameter, Sntp_ConvertToUnixTime( &sntpTime,
|
||||
&unixTime,
|
||||
NULL ) );
|
||||
|
||||
/* Test with time before UNIX epoch or 1st Jan 1970 .*/
|
||||
sntpTime.seconds = SNTP_TIME_AT_UNIX_EPOCH_SECS - 5;
|
||||
TEST_ASSERT_EQUAL( SntpErrorTimeNotSupported, Sntp_ConvertToUnixTime( &sntpTime,
|
||||
&unixTime,
|
||||
&unixTime ) );
|
||||
|
||||
/* Test with timestamp that after largest UNIX time for signed 32-bit integer systems
|
||||
* (i.e. after 18 Jan 2036 3:14:07) */
|
||||
sntpTime.seconds = SNTP_TIME_AT_LARGEST_UNIX_TIME_SECS + 5;
|
||||
TEST_ASSERT_EQUAL( SntpErrorTimeNotSupported, Sntp_ConvertToUnixTime( &sntpTime,
|
||||
&unixTime,
|
||||
&unixTime ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Tests the @ref Sntp_ConvertToUnixTime utility function returns
|
||||
* expected error when invalid parameters or unsupported timestamps are passed.
|
||||
*/
|
||||
void test_ConvertToUnixTime_Nominal( void )
|
||||
{
|
||||
SntpTimestamp_t sntpTime = TEST_TIMESTAMP;
|
||||
uint32_t unixTimeSecs;
|
||||
uint32_t unixTimeMs;
|
||||
|
||||
#define TEST_SNTP_TO_UNIX_CONVERSION( sntpTimeSecs, sntpTimeFracs, \
|
||||
expectedUnixTimeSecs, expectedUnixTimeMs ) \
|
||||
do { \
|
||||
/* Set the SNTP timestamps. */ \
|
||||
sntpTime.seconds = sntpTimeSecs; \
|
||||
sntpTime.fractions = sntpTimeFracs; \
|
||||
\
|
||||
/* Call API under test. */ \
|
||||
TEST_ASSERT_EQUAL( SntpSuccess, Sntp_ConvertToUnixTime( &sntpTime, \
|
||||
&unixTimeSecs, \
|
||||
&unixTimeMs ) ); \
|
||||
/* Validate the generated UNIX time. */ \
|
||||
TEST_ASSERT_EQUAL( expectedUnixTimeSecs, unixTimeSecs ); \
|
||||
TEST_ASSERT_EQUAL( expectedUnixTimeMs, unixTimeMs ); \
|
||||
} while( 0 )
|
||||
|
||||
/* Test with SNTP time at UNIX epoch. .*/
|
||||
TEST_SNTP_TO_UNIX_CONVERSION( SNTP_TIME_AT_UNIX_EPOCH_SECS, /* Sntp Seconds. */
|
||||
0 /* Sntp Fractions. */,
|
||||
0 /* Unix Seconds */,
|
||||
0 /* Unix Microseconds */ );
|
||||
|
||||
/* Test with SNTP time in the range between UNIX epoch and Smallest SNTP time in Era 1 .*/
|
||||
TEST_SNTP_TO_UNIX_CONVERSION( SNTP_TIME_AT_UNIX_EPOCH_SECS + 1000 /* Sntp Seconds. */,
|
||||
500 /* Sntp Fractions. */,
|
||||
1000 /* Unix Seconds */,
|
||||
500 / SNTP_FRACTION_VALUE_PER_MICROSECOND /* Unix Microseconds */ );
|
||||
|
||||
/* Test with SNTP time at largest SNTP time in Era 0 .*/
|
||||
TEST_SNTP_TO_UNIX_CONVERSION( UINT32_MAX /* Sntp Seconds. */,
|
||||
0 /* Sntp Fractions. */,
|
||||
UINT32_MAX - SNTP_TIME_AT_UNIX_EPOCH_SECS, /* Unix Seconds */
|
||||
0 /* Unix Microseconds */ );
|
||||
|
||||
/* Test with SNTP time at smallest SNTP time in Era 1 .*/
|
||||
TEST_SNTP_TO_UNIX_CONVERSION( UINT32_MAX + 1 /* Sntp Seconds. */,
|
||||
0 /* Sntp Fractions. */,
|
||||
UNIX_TIME_SECS_AT_SNTP_ERA_1_SMALLEST_TIME, /* Unix Seconds */
|
||||
0 /* Unix Microseconds */ );
|
||||
|
||||
/* Test SNTP time in the range [SNTP Era 1 Epoch, 32-bit signed UNIX max time] .*/
|
||||
TEST_SNTP_TO_UNIX_CONVERSION( UINT32_MAX + 1000 /* Sntp Seconds. */,
|
||||
4000 /* Sntp Fractions. */,
|
||||
UNIX_TIME_SECS_AT_SNTP_ERA_1_SMALLEST_TIME + 999, /* Unix Seconds */
|
||||
4000 / SNTP_FRACTION_VALUE_PER_MICROSECOND /* Unix Microseconds */ );
|
||||
|
||||
/* Test with SNTP time that represents the 32-bit signed maximum UNIX time
|
||||
* (i.e. at 19 Jan 2038 3:14:07 ) .*/
|
||||
TEST_SNTP_TO_UNIX_CONVERSION( SNTP_TIME_AT_LARGEST_UNIX_TIME_SECS /* Sntp Seconds. */,
|
||||
0 /* Sntp Fractions. */,
|
||||
INT32_MAX, /* Unix Seconds */
|
||||
0 /* Unix Microseconds */ );
|
||||
}
|
||||
@ -0,0 +1,38 @@
|
||||
# Macro utility to clone the Unity submodule.
|
||||
macro( clone_unity )
|
||||
find_package( Git REQUIRED )
|
||||
message( "Cloning submodule Unity." )
|
||||
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 utility to add library targets for Unity and Unity to build configuration.
|
||||
macro( add_unity_targets )
|
||||
# Build Configuration for Unity and Unity libraries.
|
||||
list( APPEND UNITY_INCLUDE_DIRS
|
||||
"${UNITY_DIR}/src/"
|
||||
"${UNITY_DIR}/extras/fixture/src"
|
||||
"${UNITY_DIR}/extras/memory/src"
|
||||
)
|
||||
|
||||
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"
|
||||
)
|
||||
|
||||
set_target_properties( unity PROPERTIES
|
||||
ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib
|
||||
POSITION_INDEPENDENT_CODE ON
|
||||
)
|
||||
|
||||
target_include_directories( unity PUBLIC
|
||||
${UNITY_INCLUDE_DIRS}
|
||||
)
|
||||
endmacro()
|
||||
@ -0,0 +1,70 @@
|
||||
# Taken from amazon-freertos repository
|
||||
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
|
||||
|
||||
COMMAND mkdir -p ${CMAKE_BINARY_DIR}/coverage
|
||||
)
|
||||
# make the initial/baseline capture a zeroed out files
|
||||
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
|
||||
)
|
||||
file(GLOB files "${CMAKE_BINARY_DIR}/bin/tests/*")
|
||||
|
||||
set(REPORT_FILE ${CMAKE_BINARY_DIR}/utest_report.txt)
|
||||
file(WRITE ${REPORT_FILE} "")
|
||||
# execute all files in bin directory, gathering the output to show it in CI
|
||||
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)
|
||||
|
||||
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 data after running the tests
|
||||
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
|
||||
)
|
||||
|
||||
# combile baseline results (zeros) with the one after running the tests
|
||||
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
|
||||
)
|
||||
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,168 @@
|
||||
# Taken from amazon-freertos repository
|
||||
|
||||
#function to create the test executable
|
||||
function(create_test test_name
|
||||
test_src
|
||||
link_list
|
||||
dep_list
|
||||
include_list)
|
||||
set(mocks_dir "${CMAKE_CURRENT_BINARY_DIR}/mocks")
|
||||
include (CTest)
|
||||
get_filename_component(test_src_absolute ${test_src} ABSOLUTE)
|
||||
add_custom_command(OUTPUT ${test_name}_runner.c
|
||||
COMMAND ruby
|
||||
${CMOCK_DIR}/vendor/unity/auto/generate_test_runner.rb
|
||||
${MODULE_ROOT_DIR}/tools/cmock/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()
|
||||
|
||||
# Run the C preprocessor on target files.
|
||||
# Takes a CMAKE list of arguments to pass to the C compiler
|
||||
function(preprocess_mock_list mock_name file_list compiler_args)
|
||||
set_property(GLOBAL PROPERTY ${mock_name}_processed TRUE)
|
||||
foreach (target_file IN LISTS file_list)
|
||||
# Has to be TARGET ALL so the file is pre-processed before CMOCK
|
||||
# is executed on the file.
|
||||
add_custom_command(OUTPUT ${target_file}.backup
|
||||
COMMAND scp ${target_file} ${target_file}.backup
|
||||
VERBATIM COMMAND ${CMAKE_C_COMPILER} -E ${compiler_args} ${target_file} > ${target_file}.out
|
||||
)
|
||||
add_custom_target(pre_${mock_name}
|
||||
COMMAND mv ${target_file}.out ${target_file}
|
||||
DEPENDS ${target_file}.backup
|
||||
)
|
||||
endforeach()
|
||||
|
||||
# Clean up temporary files that were created.
|
||||
# First we test to see if the backup file still exists. If it does we revert
|
||||
# the change made to the original file.
|
||||
foreach (target_file IN LISTS file_list)
|
||||
add_custom_command(TARGET ${mock_name}
|
||||
POST_BUILD
|
||||
COMMAND test ! -e ${target_file}.backup || mv ${target_file}.backup ${target_file}
|
||||
)
|
||||
endforeach()
|
||||
endfunction()
|
||||
|
||||
# Generates a mock library based on a module's header file
|
||||
# places the generated source file in the build directory
|
||||
# @param mock_name: name of the target name
|
||||
# @param mock_list list of header files to mock
|
||||
# @param cmock_config configuration file of the cmock framework
|
||||
# @param mock_include_list include list for the target
|
||||
# @param mock_define_list special definitions to control compilation
|
||||
function(create_mock_list mock_name
|
||||
mock_list
|
||||
cmock_config
|
||||
mock_include_list
|
||||
mock_define_list)
|
||||
set(mocks_dir "${CMAKE_CURRENT_BINARY_DIR}/mocks")
|
||||
add_library(${mock_name} SHARED)
|
||||
foreach (mock_file IN LISTS mock_list)
|
||||
get_filename_component(mock_file_abs
|
||||
${mock_file}
|
||||
ABSOLUTE
|
||||
)
|
||||
get_filename_component(mock_file_name
|
||||
${mock_file}
|
||||
NAME_WLE
|
||||
)
|
||||
get_filename_component(mock_file_dir
|
||||
${mock_file}
|
||||
DIRECTORY
|
||||
)
|
||||
add_custom_command (
|
||||
OUTPUT ${mocks_dir}/mock_${mock_file_name}.c
|
||||
COMMAND ruby
|
||||
${CMOCK_DIR}/lib/cmock.rb
|
||||
-o${cmock_config} ${mock_file_abs}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
)
|
||||
target_sources(${mock_name} PUBLIC
|
||||
${mocks_dir}/mock_${mock_file_name}.c
|
||||
)
|
||||
|
||||
target_include_directories(${mock_name} PUBLIC
|
||||
${mock_file_dir}
|
||||
)
|
||||
endforeach()
|
||||
target_include_directories(${mock_name} PUBLIC
|
||||
${mocks_dir}
|
||||
${mock_include_list}
|
||||
)
|
||||
set_target_properties(${mock_name} PROPERTIES
|
||||
LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lib
|
||||
POSITION_INDEPENDENT_CODE ON
|
||||
)
|
||||
target_compile_definitions(${mock_name} PUBLIC
|
||||
${mock_define_list}
|
||||
)
|
||||
target_link_libraries(${mock_name} cmock unity)
|
||||
endfunction()
|
||||
|
||||
|
||||
function(create_real_library target
|
||||
src_file
|
||||
real_include_list
|
||||
mock_name)
|
||||
add_library(${target} STATIC
|
||||
${src_file}
|
||||
)
|
||||
target_include_directories(${target} PUBLIC
|
||||
${real_include_list}
|
||||
)
|
||||
set_target_properties(${target} 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
|
||||
)
|
||||
if(NOT(mock_name STREQUAL ""))
|
||||
add_dependencies(${target} ${mock_name})
|
||||
target_link_libraries(${target}
|
||||
-l${mock_name}
|
||||
-lgcov
|
||||
)
|
||||
endif()
|
||||
endfunction()
|
||||
@ -0,0 +1,26 @@
|
||||
# Taken from amazon-freertos repository
|
||||
:cmock:
|
||||
:mock_prefix: mock_
|
||||
:when_no_prototypes: :warn
|
||||
:enforce_strict_ordering: TRUE
|
||||
:plugins:
|
||||
- :ignore
|
||||
- :ignore_arg
|
||||
- :expect_any_args
|
||||
- :array
|
||||
- :callback
|
||||
- :return_thru_ptr
|
||||
:callback_include_count: true # include a count arg when calling the callback
|
||||
:callback_after_arg_check: false # check arguments before calling the callback
|
||||
:treat_as:
|
||||
uint8: HEX8
|
||||
uint16: HEX16
|
||||
uint32: UINT32
|
||||
int8: INT8
|
||||
bool: UINT8
|
||||
:includes: # This will add these includes to each mock.
|
||||
- <stdbool.h>
|
||||
- <stdint.h>
|
||||
:treat_externs: :exclude # Now the extern-ed functions will be mocked.
|
||||
:weak: __attribute__((weak))
|
||||
:treat_externs: :include
|
||||
@ -0,0 +1,79 @@
|
||||
# Static code analysis for coreSNTP Library
|
||||
This directory is made for the purpose of statically testing the MISRA C:2012 compliance of coreSNTP Library 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/FreeRTOS/coreSNTP/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/FreeRTOS/coreSNTP/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:FreeRTOS/coreSNTP.git ./coreSNTP`
|
||||
- `cd ./coreSNTP`
|
||||
- `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 --tu-pattern "file('.*/source/.*')";
|
||||
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,30 @@
|
||||
// MISRA C-2012 Rules
|
||||
|
||||
{
|
||||
version : "2.0",
|
||||
standard : "c2012",
|
||||
title: "Coverity MISRA Configuration",
|
||||
deviations : [
|
||||
// Disable the following rules.
|
||||
{
|
||||
deviation: "Directive 4.9",
|
||||
reason: "Allow inclusion of function like macros. Asserts and logging are done using function like macros."
|
||||
},
|
||||
{
|
||||
deviation: "Rule 2.4",
|
||||
reason: "Allow unused tags. Some compilers warn if types are not tagged."
|
||||
},
|
||||
{
|
||||
deviation: "Rule 2.5",
|
||||
reason: "Allow unused macros. coreSNTP Library headers define macros intended for the application's use, but are not used by the agent."
|
||||
},
|
||||
{
|
||||
deviation: "Rule 3.1",
|
||||
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."
|
||||
},
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user