diff --git a/.github/workflows/update-submodules.yml b/.github/workflows/update-submodules.yml index 13d8aa3cce..3bbc122f58 100644 --- a/.github/workflows/update-submodules.yml +++ b/.github/workflows/update-submodules.yml @@ -8,7 +8,7 @@ on: required: true default: main allowed: - description: 'Optional regex pattern passed to `grep` to update only the specified library submodules, e.g. "ota\|jobs" updates only libraries with "ota" or "jobs" in the name.' + description: 'Optional regex pattern passed to `grep` to update only the specified library submodules, e.g. "jobs" updates only libraries with "jobs" in the name.' required: false default: .* diff --git a/.gitmodules b/.gitmodules index 9fffcaf184..37f2bd9eb8 100644 --- a/.gitmodules +++ b/.gitmodules @@ -33,10 +33,6 @@ path = libraries/standard/backoffAlgorithm branch = main url = https://github.com/FreeRTOS/backoffAlgorithm.git -[submodule "libraries/aws/ota-for-aws-iot-embedded-sdk"] - path = libraries/aws/ota-for-aws-iot-embedded-sdk - branch = main - url = https://github.com/aws/ota-for-aws-iot-embedded-sdk.git [submodule "demos/jobs/jobs_demo_mosquitto/libmosquitto"] path = demos/jobs/jobs_demo_mosquitto/libmosquitto url = https://github.com/eclipse/mosquitto.git diff --git a/CHANGELOG.md b/CHANGELOG.md index a2a3cbbf9d..8aa54022fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,27 @@ # Changelog for AWS IoT Device SDK for Embedded C +## 202412.00 (December 2024) + +### Major Changes + +- [#1929](https://github.com/aws/aws-iot-device-sdk-embedded-C/pull/1929) This release brings the following changes: + - Include [202406.01-LTS](https://github.com/FreeRTOS/FreeRTOS-LTS/releases/tag/202406.01-LTS) versions of coreMQTT, corePKCS11, coreHTTP, coreJSON, backoffAlgorithm, AWS IoT Device Shadow, AWS IoT Jobs, AWS IoT Device Defender, AWS IoT Fleet Provisioning and SigV4 libraries. + - Remove the OTA library and its associated demo. + + NOTE: We recommend transitioning to the [new modular and composable OTA approach](https://freertos.org/Documentation/03-Libraries/07-Modular-over-the-air-updates/01-Over-the-air-updates) . To get started, see the new [OTA reference demo](https://github.com/FreeRTOS/Lab-Project-ota-example-for-AWS-IoT-Core?tab=readme-ov-file). + - Update MbedTLS version to v3.5.1 + - Update readme instructions for demos for better user experience. + +### Minor Changes + +- [#1843](https://github.com/aws/aws-iot-device-sdk-embedded-C/pull/1845), [#1848](https://github.com/aws/aws-iot-device-sdk-embedded-C/pull/1848), [#1860](https://github.com/aws/aws-iot-device-sdk-embedded-C/pull/1860), [#1859](https://github.com/aws/aws-iot-device-sdk-embedded-C/pull/1859), [#1861](https://github.com/aws/aws-iot-device-sdk-embedded-C/pull/1861), [#1870](https://github.com/aws/aws-iot-device-sdk-embedded-C/pull/1870), [#1845](https://github.com/aws/aws-iot-device-sdk-embedded-C/pull/1845) Minor bug fixes and improvements. +- [#1850](https://github.com/aws/aws-iot-device-sdk-embedded-C/pull/1850) Remove installation instructions. +- [#1850](https://github.com/aws/aws-iot-device-sdk-embedded-C/pull/1852) Add CI Workflows to build the non-aws demos on incoming pull-requests. +- [#1844](https://github.com/aws/aws-iot-device-sdk-embedded-C/pull/1844) Update doxygen to 1.9.6. +- [#1875](https://github.com/aws/aws-iot-device-sdk-embedded-C/pull/1875) Add a Fleet provisioning demo to get certificate and private key via CreateKeysAndCertificate API. +- [#1899](https://github.com/aws/aws-iot-device-sdk-embedded-C/pull/1899) Add Tunnelmole as an open source tunneling option in addition to ngrok. +- [#1901](https://github.com/aws/aws-iot-device-sdk-embedded-C/pull/1901) Add a HTTP demo to generate a pre-signed URL to an S3 object file. + ## 202211.00 (November 2022) ### Major Changes diff --git a/MISRA.md b/MISRA.md index f98fe34e77..fba6e625d7 100644 --- a/MISRA.md +++ b/MISRA.md @@ -36,4 +36,4 @@ Deviations from the MISRA standard are listed below: | Rule 11.8 | Required | An OpenSSL API `SSL_set_tlsext_host_name`, which is used in the TLS transport implementation, internally casts a string literal to a `void *` pointer. | | Rule 13.4 | Required | A POSIX-specific macro utility `FD_SET` is flagged for this violation. This macro utility, whose implementation is supplied by the system, is used in the transport implementation. | | Rule 14.4 | Required | A POSIX-specific macro utility `FD_ZERO` is flagged for this violation. This macro utility, whose implementation is supplied by the system, is used in the transport implementation. | -| Rule 21.6 | Required | The Standard Library input/output functions for opening and closing files are used by the OpenSSL transport implementation, since the OpenSSL API `PEM_read_X509` to read PEM files takes `FILE *` as an argument. The standard C library file handling functions are also used in POSIX platform implementation of OTA. | +| Rule 21.6 | Required | The Standard Library input/output functions for opening and closing files are used by the OpenSSL transport implementation, since the OpenSSL API `PEM_read_X509` to read PEM files takes `FILE *` as an argument. | diff --git a/README.md b/README.md index ba7b76c5ca..78fdc24391 100755 --- a/README.md +++ b/README.md @@ -20,6 +20,7 @@ * [Sending metrics to AWS IoT](#sending-metrics-to-aws-iot) * [Versioning](#versioning) * [Releases and Documentation](#releases-and-documentation) + * [202412.00](#20241200) * [202211.00](#20221100) * [202108.00](#20210800) * [202103.00](#20210300) @@ -32,7 +33,6 @@ * [Porting coreHTTP](#porting-corehttp) * [Porting AWS IoT Device Shadow](#porting-aws-iot-device-shadow) * [Porting AWS IoT Device Defender](#porting-aws-iot-device-defender) - * [Porting AWS IoT Over-the-air Update](#porting-aws-iot-over-the-air-update) * [Migration guide from v3.1.5 to 202009.00 and newer releases](#migration-guide-from-v315-to-20200900-and-newer-releases) * [MQTT Migration](#mqtt-migration) * [Shadow Migration](#shadow-migration) @@ -52,8 +52,6 @@ * [Configuring the S3 demos](#configuring-the-s3-demos) * [Setup for AWS IoT Jobs demo](#setup-for-aws-iot-jobs-demo) * [Setup for the Greengrass local auth demo](#setup-for-the-greengrass-local-auth-demo) - * [Prerequisites for the AWS Over-The-Air Update (OTA) demos](#prerequisites-for-the-aws-over-the-air-update-ota-demos) - * [Scheduling an OTA Update Job](#scheduling-an-ota-update-job) * [Building and Running Demos](#building-and-running-demos) * [Build a single demo](#build-a-single-demo) * [Build all configured demos](#build-all-configured-demos) @@ -141,11 +139,7 @@ See memory requirements for the latest release [here](https://aws.github.io/aws- #### AWS IoT Over-the-air Update -The [AWS IoT Over-the-air Update](https://github.com/aws/ota-for-aws-iot-embedded-sdk) (OTA) library enables you to manage the notification of a newly available update, download the update, and perform cryptographic verification of the firmware update. Using the OTA library, you can logically separate firmware updates from the application running on your devices. You can also use the library to send other files (e.g. images, certificates) to one or more devices registered with AWS IoT. More details about OTA library can be found in [AWS IoT Over-the-air Update documentation](https://docs.aws.amazon.com/freertos/latest/userguide/freertos-ota-dev.html). - -The AWS IoT Over-the-air Update library has a dependency on [coreJSON](https://github.com/FreeRTOS/coreJSON) for parsing of JSON job document and [tinyCBOR](https://github.com/intel/tinycbor.git) for decoding encoded data streams, other than the standard C library. It can be used with any MQTT library, HTTP library, and operating system (e.g. Linux, FreeRTOS) (see [demos](demos/ota) with coreMQTT and coreHTTP over Linux). - -See memory requirements for the latest release [here](https://aws.github.io/aws-iot-device-sdk-embedded-C/202211.00/libraries/aws/ota-for-aws-iot-embedded-sdk/docs/doxygen/output/html/index.html#ota_memory_requirements). +Removed since v2022412.00. We recommend transitioning to the [new modular and composable OTA approach](https://freertos.org/Documentation/03-Libraries/07-Modular-over-the-air-updates/01-Over-the-air-updates) . To get started, see the new [OTA reference demo](https://github.com/FreeRTOS/Lab-Project-ota-example-for-AWS-IoT-Core?tab=readme-ov-file). #### AWS IoT Fleet Provisioning @@ -228,6 +222,12 @@ For example, a second release in June 2021 would be 202106.01. Although the SDK All of the released versions of the C-SDK libraries are available as git tags. For example, the last release of the v3 SDK version is available at [tag 3.1.5](https://github.com/aws/aws-iot-device-sdk-embedded-C/tree/v3.1.5). +### 202412.00 + +This release includes [202406.01-LTS](https://github.com/FreeRTOS/FreeRTOS-LTS/releases/tag/202406.01-LTS) versions of coreMQTT, corePKCS11, coreHTTP, coreJSON, backoffAlgorithm, AWS IoT Device Shadow, AWS IoT Jobs, AWS IoT Device Defender, AWS IoT Fleet Provisioning and SigV4 libraries. + + Additionally it updates the MbedTLS version to v3.5.1 and removes the OTA library and its associated demo. We recommend transitioning to the [new modular and composable OTA approach](https://freertos.org/Documentation/03-Libraries/07-Modular-over-the-air-updates/01-Over-the-air-updates) . To get started, see the new [OTA reference demo](https://github.com/FreeRTOS/Lab-Project-ota-example-for-AWS-IoT-Core?tab=readme-ov-file). + ### 202211.00 [API documentation of 202211.00 release](https://aws.github.io/aws-iot-device-sdk-embedded-C/202211.00/index.html) @@ -297,10 +297,6 @@ Guide for porting AWS IoT Device Shadow library is available [here](https://aws. Guide for porting AWS IoT Device Defender library is available [here](https://aws.github.io/aws-iot-device-sdk-embedded-C/202211.00/libraries/aws/device-defender-for-aws-iot-embedded-sdk/docs/doxygen/output/html/defender_porting.html). -### Porting AWS IoT Over-the-air Update - -Guide for porting OTA library to your platform is available [here](https://aws.github.io/aws-iot-device-sdk-embedded-C/202211.00/libraries/aws/ota-for-aws-iot-embedded-sdk/docs/doxygen/output/html/ota_porting.html). - ## Migration guide from v3.1.5 to 202009.00 and newer releases ### MQTT Migration @@ -379,8 +375,7 @@ Dependency | Version | Usage #### AWS IoT Account Setup -You need to setup an AWS account and access the AWS IoT console for running the AWS IoT Device Shadow library, AWS IoT Device Defender library, AWS IoT Jobs library, -AWS IoT OTA library and coreHTTP S3 download demos. +You need to setup an AWS account and access the AWS IoT console for running the AWS IoT Device Shadow library, AWS IoT Device Defender library, AWS IoT Jobs library, and coreHTTP S3 download demos. Also, the AWS account can be used for running the MQTT mutual auth demo against AWS IoT broker. Note that running the AWS IoT Device Defender, AWS IoT Jobs and AWS IoT Device Shadow library demos require the setup of a Thing resource for the device running the demo. Follow the links to: @@ -443,7 +438,7 @@ cmake -S . -Bbuild -DAWS_IOT_ENDPOINT="" -DROOT_CA_CERT_P An Amazon Root CA certificate can be downloaded from [here](https://www.amazontrust.com/repository/). -To create a provisioning template and claim credentials, sign into your AWS account and visit [here][create_provtemplate]. Make sure to enable the "Use the AWS IoT registry to manage your device fleet" option. Once +To create a provisioning template and claim credentials, sign into your AWS account and follow the steps given in the [readme.md in the demo folder](./demos/fleet_provisioning/readme.md) and visit [here][create_provtemplate]. Make sure to enable the "Use the AWS IoT registry to manage your device fleet" option. Once you have created the template and credentials, modify the claim certificate's policy to match the [sample policy][sample_claim_policy]. In order to set these configurations manually, edit `demo_config.h` in the demo folder to `#define` the following: @@ -505,38 +500,21 @@ The following creates a job that specifies a Linux Kernel link for downloading. --targets arn:aws:iot:us-west-2::thing/ \ --document '{"url":"https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.8.5.tar.xz"}' ``` +3. Run the demo using this command: +``` +./build/bin/jobs_demo_mosquitto \ +-n \ +-h \ +--certfile \ +--keyfile +``` +Note: Replace the placeholders in angle brackets with your specific information. + #### Setup for the Greengrass local auth demo For setting up the Greengrass local auth demo, see [the README in the demo folder](./demos/greengrass/greengrass_demo_local_auth/README.md). -#### Prerequisites for the AWS Over-The-Air Update (OTA) demos - -1. To perform a successful OTA update, you need to complete the prerequisites mentioned [here](https://docs.aws.amazon.com/freertos/latest/userguide/ota-prereqs.html). -1. A code signing certificate is required to authenticate the update. A code signing certificate based on the SHA-256 ECDSA algorithm will work with the current demos. An example of how to generate this kind of certificate can be found [here](https://docs.aws.amazon.com/freertos/latest/userguide/ota-code-sign-cert-esp.html). -1. The code signing certificate can be either baked into firmware as a string, or stored as a file. - 1. For baked in certificate method, copy the certificate to signingcredentialSIGNING_CERTIFICATE_PEM in [ota_pal_posix.c](https://github.com/aws/aws-iot-device-sdk-embedded-C/blob/main/platform/posix/ota_pal/source/ota_pal_posix.c). - 2. For file storage method, store the certificate as a file and supply the file path in "Path name of code signing certificate on device" field when creating the OTA job in AWS IoT Console. - -#### Scheduling an OTA Update Job - -After you build and run the initial executable you will have to create another executable and schedule an OTA update job with this image. -1. Increase the version of the application by setting macro `APP_VERSION_BUILD` in `demos/ota/ota_demo_core_[mqtt/http]/demo_config.h` to a different version than what is running. -1. Rebuild the application using the [build steps](#building-and-running-demos) below into a different directory, say `build-dir-2`. -1. Rename the demo executable to reflect the change, e.g. `mv ota_demo_core_mqtt ota_demo_core_mqtt2` -1. Create an OTA job: - 1. Go to the [AWS IoT Core console](https://console.aws.amazon.com/iot/). - 1. Manage → Jobs → Create → Create a FreeRTOS OTA update job → Select the corresponding name for your device from the thing list. - 1. Sign a new firmware → Create a new profile → Select any SHA-ECDSA signing platform → Upload the code signing certificate(from prerequisites) and provide its path on the device. - 1. Select the image → Select the bucket you created during the [prerequisite steps](#prerequisites-for-the-aws-over-the-air-update-ota-demos) → Upload the binary `build-dir-2/bin/ota_demo2`. - 1. The path on device should be the absolute path to place the executable and the binary name: e.g. `/home/ubuntu/aws-iot-device-sdk-embedded-C-staging/build-dir/bin/ota_demo_core_mqtt2`. - 1. Select the IAM role created during the [prerequisite steps](#prerequisites-for-the-aws-over-the-air-update-ota-demos). - 1. Create the Job. -1. Run the initial executable again with the following command: `sudo ./ota_demo_core_mqtt` or `sudo ./ota_demo_core_http`. -1. After the initial executable has finished running, go to the directory where the downloaded firmware image resides which is the path name used when creating an OTA job. -1. Change the permissions of the downloaded firmware to make it executable, as it may be downloaded with read (user default) permissions only: `chmod 775 ota_demo_core_mqtt2` -1. Run the downloaded firmware image with the following command: `sudo ./ota_demo_core_mqtt2` - ### Building and Running Demos Before building the demos, ensure you have installed the [prerequisite software](#prerequisites). On Ubuntu 18.04 and 20.04, `gcc`, `cmake`, and OpenSSL can be installed with: @@ -563,8 +541,6 @@ mqtt_demo_mutual_auth mqtt_demo_plaintext mqtt_demo_serializer mqtt_demo_subscription_manager -ota_demo_core_http -ota_demo_core_mqtt pkcs11_demo_management_and_rng pkcs11_demo_mechanisms_and_digests pkcs11_demo_objects @@ -629,6 +605,7 @@ Any version after 1.6.14 will drop privileges as soon as the configuration file openssl req -x509 -nodes -sha256 -days 365 -newkey rsa:2048 -keyout ca.key -out ca.crt ``` + You will be prompted to configure the Common Name (CN) after running the following command. It's crucial to enter the same value that was specified for the `BROKER_ENDPOINT` macro in the demo_config.h file. In this particular instance, the correct value to enter is simply "localhost". ```sh # Generate server key and certificate.# Provide the Subject field information as appropriate for Server certificate. Make sure the Common Name (CN) field is different from the root CA certificate. openssl req -nodes -sha256 -new -keyout server.key -out server.csr # Sign with the CA cert. @@ -668,18 +645,30 @@ Run httpbin through port 80: docker pull kennethreitz/httpbin docker run -p 80:80 kennethreitz/httpbin ``` +The `kennetheitz/httpbin` docker image is not compatible with linux/arm64 platform that is used by Mac machines. Hence instead of that use `mccutchen/go-httpbin`. +```sh +#To install the image run: + +$ docker pull mccutchen/go-httpbin + +#To run the server on local host on port 80 run + +$ docker run -p 80:8080 mccutchen/go-httpbin +``` + `SERVER_HOST` defined in `demos/http/http_demo_plaintext/demo_config.h` can now be set to `localhost`. To run `http_demo_basic_tls`, you could use either [Tunnelmole](https://github.com/robbie-cahill/tunnelmole-client), an open source tunneling tool, or [ngrok](https://ngrok.com/download), a popular closed source tunneling tool, to create an HTTPS tunnel to the httpbin server currently hosted on port 80: **Using Tunnelmole** + First, install Tunnelmole. On Linux, Mac and Windows Subsystem for Linux, use ```sh curl -O https://tunnelmole.com/sh/install.sh && sudo bash install.sh ``` - +The above may not function correctly on ARM machines like mac. As an alternative, you can clone the repository and build the application from its source code. For Windows without WSL, [download tmole.exe](https://tunnelmole.com/downloads/tmole.exe) and add it to your [PATH](https://www.wikihow.com/Change-the-PATH-Environment-Variable-on-Windows). Then run `tmole 80` @@ -702,7 +691,17 @@ Set `SERVER_HOST` in `demos/http/http_demo_basic_tls/demo_config.h` to the https Set `SERVER_HOST` in `demos/http/http_demo_basic_tls/demo_config.h` to the https link provided by ngrok, without `https://` preceding it. -You must also download the Root CA certificate provided by the ngrok https link and set `ROOT_CA_CERT_PATH` in `demos/http/http_demo_basic_tls/demo_config.h` to the file path of the downloaded certificate. +**Getting the Root CA** + +Download the Root CA certificate from the obtained https link. To obtain this: + +1. Open the https link in your browser. +2. Click on the https lock button in the url bar. +3. Download the chain of certificates. +4. Locate the last certificate in the chain - this is your required Root CA certificate. +5. Copy this certificate and paste it into a new .pem file. + +Set the macro ROOT_CA_CERT_PATH in demo_config.h to the file path of your newly created Root CA certificate. ## Generating Documentation Note: For pre-generated documentation, please visit [Releases and Documentation](#releases-and-documentation) section. diff --git a/demos/CMakeLists.txt b/demos/CMakeLists.txt index 61af98555c..215bc780b8 100644 --- a/demos/CMakeLists.txt +++ b/demos/CMakeLists.txt @@ -26,8 +26,6 @@ check_symbol_exists(fork "unistd.h" HAVE_FORK) if(${LIB_RT} STREQUAL "LIB_RT-NOTFOUND") set(librt_demos "http_demo_s3_download_multithreaded" - "ota_demo_core_http" - "ota_demo_core_mqtt" ) message( WARNING "rt library could not be found. Demos that use it will be excluded from the default target." ) foreach(demo_name ${librt_demos}) @@ -46,8 +44,6 @@ if(NOT ${OpenSSL_FOUND}) "mqtt_demo_basic_tls" "mqtt_demo_mutual_auth" "mqtt_demo_subscription_manager" - "ota_demo_core_http" - "ota_demo_core_mqtt" "shadow_demo_main" "greengrass_demo_local_auth" ) @@ -56,16 +52,6 @@ if(NOT ${OpenSSL_FOUND}) set_target_properties(${demo_name} PROPERTIES EXCLUDE_FROM_ALL true) endforeach() endif() -if(NOT ${Threads_FOUND}) - set(thread_demos - "ota_demo_core_http" - "ota_demo_core_mqtt" - ) - message( WARNING "Threads library could not be found. Demos that use it will be excluded from the default target." ) - foreach(demo_name ${thread_demos}) - set_target_properties(${demo_name} PROPERTIES EXCLUDE_FROM_ALL true) - endforeach() -endif() if(NOT HAVE_FORK) set(fork_demos "http_demo_s3_download_multithreaded" diff --git a/demos/fleet_provisioning/fleet_provisioning_keys_cert/pkcs11_operations.c b/demos/fleet_provisioning/fleet_provisioning_keys_cert/pkcs11_operations.c index a8a853225c..5d4ed672fc 100644 --- a/demos/fleet_provisioning/fleet_provisioning_keys_cert/pkcs11_operations.c +++ b/demos/fleet_provisioning/fleet_provisioning_keys_cert/pkcs11_operations.c @@ -44,11 +44,11 @@ /* MbedTLS include. */ #include "mbedtls/ctr_drbg.h" #include "mbedtls/entropy.h" -#include "mbedtls/entropy_poll.h" +#include "entropy_poll.h" #include "mbedtls/error.h" #include "mbedtls/oid.h" #include "mbedtls/pk.h" -#include "mbedtls/pk_internal.h" +#include "pk_wrap.h" #include "mbedtls/sha256.h" #include "mbedtls/x509_crt.h" #include "mbedtls/x509_csr.h" @@ -537,10 +537,15 @@ static CK_RV provisionPrivateKey( CK_SESSION_HANDLE session, mbedtls_pk_type_t mbedKeyType = MBEDTLS_PK_NONE; int mbedResult = 0; mbedtls_pk_context mbedPkContext = { 0 }; + mbedtls_ctr_drbg_context ctr_drbg = { 0 }; + mbedtls_entropy_context entropy = { 0 }; mbedtls_pk_init( &mbedPkContext ); + mbedtls_entropy_init( &entropy ); + mbedtls_ctr_drbg_init( &ctr_drbg ); + mbedtls_ctr_drbg_seed( &ctr_drbg, mbedtls_entropy_func, &entropy, NULL, 0 ); mbedResult = mbedtls_pk_parse_key( &mbedPkContext, ( const uint8_t * ) privateKey, - privateKeyLength, NULL, 0 ); + privateKeyLength, NULL, 0, mbedtls_ctr_drbg_random, &ctr_drbg ); if( mbedResult != 0 ) { diff --git a/demos/fleet_provisioning/fleet_provisioning_keys_cert/pkcs11_operations.h b/demos/fleet_provisioning/fleet_provisioning_keys_cert/pkcs11_operations.h index c22b94f60f..2745b44c4a 100644 --- a/demos/fleet_provisioning/fleet_provisioning_keys_cert/pkcs11_operations.h +++ b/demos/fleet_provisioning/fleet_provisioning_keys_cert/pkcs11_operations.h @@ -27,6 +27,11 @@ #include #include +/** + * @brief To access the private members of the MbedTLS structs + */ +#define MBEDTLS_ALLOW_PRIVATE_ACCESS + /* corePKCS11 include. */ #include "core_pkcs11.h" diff --git a/demos/fleet_provisioning/fleet_provisioning_with_csr/pkcs11_operations.c b/demos/fleet_provisioning/fleet_provisioning_with_csr/pkcs11_operations.c index bc4c8b3d6d..2b5aa712db 100644 --- a/demos/fleet_provisioning/fleet_provisioning_with_csr/pkcs11_operations.c +++ b/demos/fleet_provisioning/fleet_provisioning_with_csr/pkcs11_operations.c @@ -44,11 +44,11 @@ /* MbedTLS include. */ #include "mbedtls/ctr_drbg.h" #include "mbedtls/entropy.h" -#include "mbedtls/entropy_poll.h" +#include "entropy_poll.h" #include "mbedtls/error.h" #include "mbedtls/oid.h" #include "mbedtls/pk.h" -#include "mbedtls/pk_internal.h" +#include "pk_wrap.h" #include "mbedtls/sha256.h" #include "mbedtls/x509_crt.h" #include "mbedtls/x509_csr.h" @@ -239,15 +239,17 @@ static int extractEcPublicKey( CK_SESSION_HANDLE p11Session, * @param[in] pHash Data to sign. * @param[in] hashLen Length of #pHash. * @param[out] pSig The signature + * @param[in] sig_size Unused * @param[out] pSigLen The length of the signature. * @param[in] pRng Unused. * @param[in] pRngContext Unused. */ -static int32_t privateKeySigningCallback( void * pContext, +static int32_t privateKeySigningCallback( mbedtls_pk_context * pContext, mbedtls_md_type_t mdAlg, const unsigned char * pHash, size_t hashLen, unsigned char * pSig, + size_t sig_size, size_t * pSigLen, int ( * pRng )( void *, unsigned char *, size_t ), void * pRngContext ); @@ -636,10 +638,15 @@ static CK_RV provisionPrivateKey( CK_SESSION_HANDLE session, mbedtls_pk_type_t mbedKeyType = MBEDTLS_PK_NONE; int mbedResult = 0; mbedtls_pk_context mbedPkContext = { 0 }; + mbedtls_ctr_drbg_context ctr_drbg = { 0 }; + mbedtls_entropy_context entropy = { 0 }; mbedtls_pk_init( &mbedPkContext ); + mbedtls_entropy_init( &entropy ); + mbedtls_ctr_drbg_init( &ctr_drbg ); + mbedtls_ctr_drbg_seed( &ctr_drbg, mbedtls_entropy_func, &entropy, NULL, 0 ); mbedResult = mbedtls_pk_parse_key( &mbedPkContext, ( const uint8_t * ) privateKey, - privateKeyLength, NULL, 0 ); + privateKeyLength, NULL, 0, mbedtls_ctr_drbg_random, &ctr_drbg ); if( mbedResult != 0 ) { @@ -900,11 +907,12 @@ static int extractEcPublicKey( CK_SESSION_HANDLE p11Session, /*-----------------------------------------------------------*/ -static int32_t privateKeySigningCallback( void * pContext, +static int32_t privateKeySigningCallback( mbedtls_pk_context * pContext, mbedtls_md_type_t mdAlg, const unsigned char * pHash, size_t hashLen, unsigned char * pSig, + size_t sig_size, size_t * pSigLen, int ( * pRng )( void *, unsigned char *, size_t ), void * pRngContext ) @@ -921,6 +929,7 @@ static int32_t privateKeySigningCallback( void * pContext, ( void ) ( pRng ); ( void ) ( pRngContext ); ( void ) ( mdAlg ); + ( void ) ( sig_size ); /* Sanity check buffer length. */ if( hashLen > sizeof( toBeSigned ) ) diff --git a/demos/fleet_provisioning/fleet_provisioning_with_csr/pkcs11_operations.h b/demos/fleet_provisioning/fleet_provisioning_with_csr/pkcs11_operations.h index 21b4528018..f2675ffcab 100644 --- a/demos/fleet_provisioning/fleet_provisioning_with_csr/pkcs11_operations.h +++ b/demos/fleet_provisioning/fleet_provisioning_with_csr/pkcs11_operations.h @@ -27,6 +27,11 @@ #include #include +/** + * @brief To access the private members of the MbedTLS structs + */ +#define MBEDTLS_ALLOW_PRIVATE_ACCESS + /* corePKCS11 include. */ #include "core_pkcs11.h" diff --git a/demos/fleet_provisioning/readme.md b/demos/fleet_provisioning/readme.md new file mode 100644 index 0000000000..c38d76d0b4 --- /dev/null +++ b/demos/fleet_provisioning/readme.md @@ -0,0 +1,39 @@ +## Setup for Fleet Provisioning Demos + +### Create the Provisioning Policy + +1. Log in to your AWS account and open AWS IoT Core. +2. Navigate to Security > Policies > Create policy. +3. Enter a relevant policy name. +4. Copy the contents from demos/fleet_provisioning/fleet_provisioning_with_csr (or fleet_provisioning_keys_cert_demo)/example_claim_policy.json. +5. Paste the copied content into the policy document on the AWS console. +6. Click "Create policy". + +### Create the Claim Certificate +1. In AWS IoT Core, go to Security > Certificates > Add certificate. +2. Set the "Certificate Status" to active. +3. Download the certificate files from the provided prompt. +4. Update the demo_config.h file: + - Set CLAIM_CERT_PATH to the path of the downloaded certificate. + - Set CLAIM_PRIVATE_KEY_PATH to the path of the downloaded private key. Note: You can also set these values using command line parameters. +5. Select the certificate, click "Attach policies", choose your provisioning policy, and click "Attach policy". + +### Create the IAM Role for AWS IoT +1. Go to the IAM Identity Center. +2. Create a new IAM role. +3. When prompted, select AWS IoT as the service. + +### Create Fleet Provisioning Template +1. Navigate to AWS IoT Core > Connect many devices > Connect many devices > Create provisioning template. +2. Choose "Provisioning devices with claim certificates" and click "Next". +3. Set the status to active. +4. Enter a template name. +5. Select the IAM role you created earlier (or create a new one if needed). +6. Choose the provisioning policy you created earlier (or create a new one if needed). +7. Select "Don't use a pre-provisioning action". +8. Enable the automatic thing creation option and click "Next". +9. Select or create a policy for your device's permissions (e.g., connecting to IoT, subscribing/publishing to topics). +10. Click "Next", review the settings, and create the template. + +### Configure the Demo +Set all necessary macro values in the demo_config.h file. Alternatively, you can provide these values through command line parameters. \ No newline at end of file diff --git a/demos/greengrass/greengrass_demo_local_auth/README.md b/demos/greengrass/greengrass_demo_local_auth/README.md index 4b0ec2c95c..a03ae310cf 100644 --- a/demos/greengrass/greengrass_demo_local_auth/README.md +++ b/demos/greengrass/greengrass_demo_local_auth/README.md @@ -50,13 +50,50 @@ For setting up the Greengrass core, see [the Greengrass getting started guide](h Next you will need to set up a Root CA for your Greengrass device. -On the Greengrass core, run the following command: +On the Greengrass core, run the following: +1. Create private key for the CA certificate ```sh -openssl req -x509 -new -nodes -key ca.key -sha256 -days 1826 -out ca.crt +openssl genrsa -out ca.key 2048 ``` +2. Use the private key of CA to generate a self signed certificate +```sh +openssl req -x509 -new -nodes \ +-key ca.key \ +-sha256 -days 1024 \ +-out ca.pem +``` +3. Create a private key for the Thing device. +```sh +openssl genrsa -out thing_private.key 2048 +``` +4. Using the private key, create a certificate signing request +```sh +openssl req -new \ +-key thing_private.key \ +-out thing_csr.csr +``` +5. Using the CSR, root CA and private key of root CA , create the client certificate +```sh +openssl x509 -req \ +-in thing_csr.csr \ +-CA ca.pem \ +-CAkey ca.key \ +-CAcreateserial \ +-out thing_cert.pem \ +-days 500 -sha256 +``` +6. Register the CA certificate to AWS IoT by going to AWS console → AWS IoT → Security → Certificates authorities → Register CA certificate. Upload the CA certificate and CA status to active, leave other settings as default. Click on Register. + +7. Register the Device certificate to AWS IoT + + * Go to console → AWS IoT → Security → Certificates → Add certificate → Register certificates. + * Select your Registered CA from the dropdown. + * Upload your device certificate (thing_cert.pem) and Activate it by selecting the certificate and clicking on the Activate button + +8. Create a new thing and link it with this new certificate thing_cert.pem and set the value of the macro `THING_NAME` in demo_config.h file to the name of this new thing -This will create a custom CA cert ca.crt and private key ca.key. +9. Set the value of the macro `CLIENT_CERT_PATH` to the path of thing_cert.pem and the value of the macro `CLIENT_PRIVATE_KEY_PATH` to the path of thing_private.key ### Configuring the GG core for local auth and MQTT @@ -68,7 +105,7 @@ Deploy the following components to your Greengrass core: Set the configuration for the aws.greengrass.clientdevices.Auth component based off the [provided config](./greengrass_auth_conf.json). Ensure the certificate -paths match the files created for your custom CA above. +paths match the files created for your custom CA above and their absolute paths are written after `file://`. This config will allow associated Things to publish and subscribe to any topic on the Greengrass core broker. diff --git a/demos/http/common/include/http_demo_s3_utils.h b/demos/http/common/include/http_demo_s3_utils.h index e705593d30..f6cb5a74a7 100644 --- a/demos/http/common/include/http_demo_s3_utils.h +++ b/demos/http/common/include/http_demo_s3_utils.h @@ -91,12 +91,6 @@ extern size_t securityTokenLen; */ extern const char * pExpiration; -/** - * @brief Length of expiration time for the temporary credentials retrieved - * from AWS IoT credential provider service. - */ -size_t expirationLen; - /** * @brief Retrieve the temporary credentials from AWS IOT Credential Provider. * diff --git a/demos/http/common/src/http_demo_s3_utils.c b/demos/http/common/src/http_demo_s3_utils.c index f814c27e96..7ab4dba668 100644 --- a/demos/http/common/src/http_demo_s3_utils.c +++ b/demos/http/common/src/http_demo_s3_utils.c @@ -36,6 +36,7 @@ /* MBEDTLS API header. */ #include "mbedtls/sha256.h" +#include "mbedtls/compat-2.x.h" /* OpenSSL transport header. */ #include "openssl_posix.h" diff --git a/demos/lexicon.txt b/demos/lexicon.txt index 54b18faf50..4f8ed6b37b 100644 --- a/demos/lexicon.txt +++ b/demos/lexicon.txt @@ -428,13 +428,6 @@ optionalquery org os ota -otaagentstatestopped -otafile -otahttpinitfailed -otahttprequestfailed -otahttpsuccess -otamqttsuccess -otapalimagestatevalid outcsrlength outform outgoingpublishpackets diff --git a/demos/ota/common/include/mqtt_subscription_manager.h b/demos/ota/common/include/mqtt_subscription_manager.h deleted file mode 100644 index 6937e0eeec..0000000000 --- a/demos/ota/common/include/mqtt_subscription_manager.h +++ /dev/null @@ -1,143 +0,0 @@ -/* - * AWS IoT Device SDK for Embedded C 202211.00 - * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/** - * @file mqtt_subscription_manager.h - * @brief The API of a subscription manager for handling subscription callbacks - * to topic filters in MQTT operations. - */ - -#ifndef MQTT_SUBSCRIPTION_MANAGER_H_ -#define MQTT_SUBSCRIPTION_MANAGER_H_ - -/**************************************************/ -/******* DO NOT CHANGE the following order ********/ -/**************************************************/ - -/* Logging related header files are required to be included in the following order: - * 1. Include the header file "logging_levels.h". - * 2. Define LIBRARY_LOG_NAME and LIBRARY_LOG_LEVEL. - * 3. Include the header file "logging_stack.h". - */ - -/* Include header that defines log levels. */ -#include "logging_levels.h" - -/* Logging configuration for the Subscription Manager module. */ -#ifndef LIBRARY_LOG_NAME - #define LIBRARY_LOG_NAME "Subscription Manager" -#endif -#ifndef LIBRARY_LOG_LEVEL - #define LIBRARY_LOG_LEVEL LOG_DEBUG -#endif - -#include "logging_stack.h" - -/************ End of logging configuration ****************/ - -/* Include MQTT library. */ -#include "core_mqtt.h" - -/* Enumeration type for return status value from Subscription Manager API. */ -typedef enum SubscriptionManagerStatus -{ - /** - * @brief Success return value from Subscription Manager API. - */ - SUBSCRIPTION_MANAGER_SUCCESS = 1, - - /** - * @brief Failure return value due to registry being full. - */ - SUBSCRIPTION_MANAGER_REGISTRY_FULL = 2, - - /** - * @brief Failure return value due to an already existing record in the - * registry for a new callback registration's requested topic filter. - */ - SUBSCRIPTION_MANAGER_RECORD_EXISTS = 3 -} SubscriptionManagerStatus_t; - - -/** - * @brief Callback type to be registered for a topic filter with the subscription manager. - * - * For incoming PUBLISH messages received on topics that match the registered topic filter, - * the callback would be invoked by the subscription manager. - * - * @param[in] pContext The context associated with the MQTT connection. - * @param[in] pPublishInfo The incoming PUBLISH message information. - */ -typedef void (* SubscriptionManagerCallback_t )( MQTTContext_t * pContext, - MQTTPublishInfo_t * pPublishInfo ); - -/** - * @brief Dispatches the incoming PUBLISH message to the callbacks that have their - * registered topic filters matching the incoming PUBLISH topic name. The dispatch - * handler will invoke all these callbacks with matching topic filters. - * - * @param[in] pContext The context associated with the MQTT connection. - * @param[in] pPublishInfo The incoming PUBLISH message information. - */ -void SubscriptionManager_DispatchHandler( MQTTContext_t * pContext, - MQTTPublishInfo_t * pPublishInfo ); - -/** - * @brief Utility to register a callback for a topic filter in the subscription manager. - * - * The callback will be invoked when an incoming PUBLISH message is received on - * a topic that matches the topic filter, @a pTopicFilter. The subscription manager - * accepts wildcard topic filters. - * - * @param[in] pTopicFilter The topic filter to register the callback for. - * @param[in] topicFilterLength The length of the topic filter string. - * @param[in] callback The callback to be registered for the topic filter. - * - * @note The subscription manager does not allow more than one callback to be registered - * for the same topic filter. - * @note The passed topic filter, @a pTopicFilter, is saved in the registry. - * The application must not free or alter the content of the topic filter memory - * until the callback for the topic filter is removed from the subscription manager. - * - * @return Returns one of the following: - * - #SUBSCRIPTION_MANAGER_SUCCESS if registration of the callback is successful. - * - #SUBSCRIPTION_MANAGER_REGISTRY_FULL if the registration failed due to registry - * being already full. - * - #SUBSCRIPTION_MANAGER_RECORD_EXISTS, if a registered callback already exists for - * the requested topic filter in the subscription manager. - */ -SubscriptionManagerStatus_t SubscriptionManager_RegisterCallback( const char * pTopicFilter, - uint16_t topicFilterLength, - SubscriptionManagerCallback_t pCallback ); - -/** - * @brief Utility to remove the callback registered for a topic filter from the - * subscription manager. - * - * @param[in] pTopicFilter The topic filter to remove from the subscription manager. - * @param[in] topicFilterLength The length of the topic filter string. - */ -void SubscriptionManager_RemoveCallback( const char * pTopicFilter, - uint16_t topicFilterLength ); - - -#endif /* ifndef MQTT_SUBSCRIPTION_MANAGER_H_ */ diff --git a/demos/ota/common/src/mqtt_subscription_manager.c b/demos/ota/common/src/mqtt_subscription_manager.c deleted file mode 100644 index 34673d8b07..0000000000 --- a/demos/ota/common/src/mqtt_subscription_manager.c +++ /dev/null @@ -1,218 +0,0 @@ -/* - * AWS IoT Device SDK for Embedded C 202211.00 - * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/** - * @file mqtt_subscription_manager.c - * @brief Implementation of the API of a subscription manager for handling subscription callbacks - * to topic filters in MQTT operations. - */ - -/* Standard includes. */ -#include -#include - -/* Include demo config. */ -#include "demo_config.h" - -/* Include header for the subscription manager. */ -#include "mqtt_subscription_manager.h" - - -/** - * @brief Represents a registered record of the topic filter and its associated callback - * in the subscription manager registry. - */ -typedef struct SubscriptionManagerRecord -{ - const char * pTopicFilter; - uint16_t topicFilterLength; - SubscriptionManagerCallback_t callback; -} SubscriptionManagerRecord_t; - -/** - * @brief The default value for the maximum size of the callback registry in the - * subscription manager. - */ -#ifndef MAX_SUBSCRIPTION_CALLBACK_RECORDS - #define MAX_SUBSCRIPTION_CALLBACK_RECORDS 5 -#endif - -/** - * @brief The registry to store records of topic filters and their subscription callbacks. - */ -static SubscriptionManagerRecord_t callbackRecordList[ MAX_SUBSCRIPTION_CALLBACK_RECORDS ] = { 0 }; - -/*-----------------------------------------------------------*/ - -void SubscriptionManager_DispatchHandler( MQTTContext_t * pContext, - MQTTPublishInfo_t * pPublishInfo ) -{ - bool matchStatus = false; - size_t listIndex = 0u; - - assert( pPublishInfo != NULL ); - assert( pContext != NULL ); - - /* Iterate through record list to find matching topics, and invoke their callbacks. */ - for( listIndex = 0; listIndex < MAX_SUBSCRIPTION_CALLBACK_RECORDS; listIndex++ ) - { - if( ( callbackRecordList[ listIndex ].pTopicFilter != NULL ) && - ( MQTT_MatchTopic( pPublishInfo->pTopicName, - pPublishInfo->topicNameLength, - callbackRecordList[ listIndex ].pTopicFilter, - callbackRecordList[ listIndex ].topicFilterLength, - &matchStatus ) == MQTTSuccess ) && - ( matchStatus == true ) ) - { - LogInfo( ( "Invoking subscription callback of matching topic filter: " - "TopicFilter=%.*s, TopicName=%.*s", - callbackRecordList[ listIndex ].topicFilterLength, - callbackRecordList[ listIndex ].pTopicFilter, - pPublishInfo->topicNameLength, - pPublishInfo->pTopicName ) ); - - /* Invoke the callback associated with the record as the topics match. */ - callbackRecordList[ listIndex ].callback( pContext, pPublishInfo ); - } - } -} - -/*-----------------------------------------------------------*/ - -SubscriptionManagerStatus_t SubscriptionManager_RegisterCallback( const char * pTopicFilter, - uint16_t topicFilterLength, - SubscriptionManagerCallback_t callback ) -{ - assert( pTopicFilter != NULL ); - assert( topicFilterLength != 0 ); - assert( callback != NULL ); - - SubscriptionManagerStatus_t returnStatus; - size_t availableIndex = MAX_SUBSCRIPTION_CALLBACK_RECORDS; - bool recordExists = false; - size_t index = 0u; - - /* Search for the first available spot in the list to store the record, and also check if - * a record for the topic filter already exists. */ - while( ( recordExists == false ) && ( index < MAX_SUBSCRIPTION_CALLBACK_RECORDS ) ) - { - /* Check if the index represents an empty spot in the registry. If we had already - * found an empty spot in the list, we will not update it. */ - if( ( availableIndex == MAX_SUBSCRIPTION_CALLBACK_RECORDS ) && - ( callbackRecordList[ index ].pTopicFilter == NULL ) ) - { - availableIndex = index; - } - - /* Check if the current record's topic filter in the registry matches the topic filter - * we are trying to register. */ - else if( ( callbackRecordList[ index ].topicFilterLength == topicFilterLength ) && - ( strncmp( pTopicFilter, callbackRecordList[ index ].pTopicFilter, topicFilterLength ) - == 0 ) ) - { - recordExists = true; - } - - index++; - } - - if( recordExists == true ) - { - /* The record for the topic filter already exists. */ - LogError( ( "Failed to register callback: Record for topic filter already exists: TopicFilter=%.*s", - topicFilterLength, - pTopicFilter ) ); - - returnStatus = SUBSCRIPTION_MANAGER_RECORD_EXISTS; - } - else if( availableIndex == MAX_SUBSCRIPTION_CALLBACK_RECORDS ) - { - /* The registry is full. */ - LogError( ( "Unable to register callback: Registry list is full: TopicFilter=%.*s, MaxRegistrySize=%u", - topicFilterLength, - pTopicFilter, - MAX_SUBSCRIPTION_CALLBACK_RECORDS ) ); - - returnStatus = SUBSCRIPTION_MANAGER_REGISTRY_FULL; - } - else - { - callbackRecordList[ availableIndex ].pTopicFilter = pTopicFilter; - callbackRecordList[ availableIndex ].topicFilterLength = topicFilterLength; - callbackRecordList[ availableIndex ].callback = callback; - - returnStatus = SUBSCRIPTION_MANAGER_SUCCESS; - - LogDebug( ( "Added callback to registry: TopicFilter=%.*s", - topicFilterLength, - pTopicFilter ) ); - } - - return returnStatus; -} - -/*-----------------------------------------------------------*/ - -void SubscriptionManager_RemoveCallback( const char * pTopicFilter, - uint16_t topicFilterLength ) -{ - assert( pTopicFilter != NULL ); - assert( topicFilterLength != 0 ); - - size_t index; - SubscriptionManagerRecord_t * pRecord = NULL; - - /* Iterate through the records list to find the matching record. */ - for( index = 0; index < MAX_SUBSCRIPTION_CALLBACK_RECORDS; index++ ) - { - pRecord = &callbackRecordList[ index ]; - - /* Only match the non-empty records. */ - if( pRecord->pTopicFilter != NULL ) - { - if( ( topicFilterLength == pRecord->topicFilterLength ) && - ( strncmp( pTopicFilter, pRecord->pTopicFilter, topicFilterLength ) == 0 ) ) - { - break; - } - } - } - - /* Delete the record by clearing the found entry in the records list. */ - if( index < MAX_SUBSCRIPTION_CALLBACK_RECORDS ) - { - pRecord->pTopicFilter = NULL; - pRecord->topicFilterLength = 0u; - pRecord->callback = NULL; - - LogDebug( ( "Deleted callback record for topic filter: TopicFilter=%.*s", - topicFilterLength, - pTopicFilter ) ); - } - else - { - LogWarn( ( "Attempted to remove callback for un-registered topic filter: TopicFilter=%.*s", - topicFilterLength, - pTopicFilter ) ); - } -} -/*-----------------------------------------------------------*/ diff --git a/demos/ota/ota_demo_core_http/CMakeLists.txt b/demos/ota/ota_demo_core_http/CMakeLists.txt deleted file mode 100644 index da38631135..0000000000 --- a/demos/ota/ota_demo_core_http/CMakeLists.txt +++ /dev/null @@ -1,75 +0,0 @@ -set( DEMO_NAME "ota_demo_core_http" ) - -# Include required library's source and header path variables. -include( ${ROOT_DIR}/libraries/aws/ota-for-aws-iot-embedded-sdk/otaFilePaths.cmake ) -include( ${ROOT_DIR}/libraries/standard/coreMQTT/mqttFilePaths.cmake ) -include( ${ROOT_DIR}/libraries/standard/coreHTTP/httpFilePaths.cmake ) - -# Include backoffAlgorithm library file path configuration. -include( ${ROOT_DIR}/libraries/standard/backoffAlgorithm/backoffAlgorithmFilePaths.cmake ) - -# Disable some warnings for llhttp sources. -set_source_files_properties( - ${HTTP_SOURCES} - PROPERTIES - COMPILE_FLAGS "-Wno-unused-parameter" -) - -# Demo target. -add_executable( - ${DEMO_NAME} - "${DEMO_NAME}.c" - "${DEMOS_DIR}/ota/common/src/mqtt_subscription_manager.c" - "${DEMOS_DIR}/http/common/src/http_demo_url_utils.c" - ${OTA_SOURCES} - ${OTA_OS_POSIX_SOURCES} - ${OTA_MQTT_SOURCES} - ${OTA_HTTP_SOURCES} - ${MQTT_SOURCES} - ${MQTT_SERIALIZER_SOURCES} - ${HTTP_SOURCES} - ${BACKOFF_ALGORITHM_SOURCES} -) - -target_link_libraries( - ${DEMO_NAME} - PRIVATE - ${LIB_RT} - ota_pal - Threads::Threads - clock_posix - openssl_posix - aws_iot_json - tinycbor -) - -target_include_directories( - ${DEMO_NAME} - PUBLIC - "${DEMOS_DIR}/ota/common/include" - "${DEMOS_DIR}/http/common/include" - "${CMAKE_CURRENT_LIST_DIR}" - "${LOGGING_INCLUDE_DIRS}" - ${BACKOFF_ALGORITHM_INCLUDE_PUBLIC_DIRS} - ${OTA_INCLUDE_PUBLIC_DIRS} - ${OTA_INCLUDE_PRIVATE_DIRS} - ${OTA_INCLUDE_OS_POSIX_DIRS} - ${MQTT_INCLUDE_PUBLIC_DIRS} - ${HTTP_INCLUDE_PUBLIC_DIRS} - ${AWS_DEMO_INCLUDE_DIRS} -) - -set_macro_definitions(TARGETS ${DEMO_NAME} - REQUIRED - "AWS_IOT_ENDPOINT" - "ROOT_CA_CERT_PATH" - "ROOT_CA_CERT_PATH_HTTP" - "CLIENT_CERT_PATH" - "CLIENT_PRIVATE_KEY_PATH" - "CLIENT_IDENTIFIER" - OPTIONAL - "CLIENT_USERNAME" - "CLIENT_PASSWORD" - "OS_NAME" - "OS_VERSION" - "HARDWARE_PLATFORM_NAME") diff --git a/demos/ota/ota_demo_core_http/core_http_config.h b/demos/ota/ota_demo_core_http/core_http_config.h deleted file mode 100644 index 8b6c9b959f..0000000000 --- a/demos/ota/ota_demo_core_http/core_http_config.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * AWS IoT Device SDK for Embedded C 202211.00 - * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef CORE_HTTP_CONFIG_H_ -#define CORE_HTTP_CONFIG_H_ - -/**************************************************/ -/******* DO NOT CHANGE the following order ********/ -/**************************************************/ - -/* Include logging header files and define logging macros in the following order: - * 1. Include the header file "logging_levels.h". - * 2. Define the LIBRARY_LOG_NAME and LIBRARY_LOG_LEVEL macros depending on - * the logging configuration for HTTP. - * 3. Include the header file "logging_stack.h", if logging is enabled for HTTP. - */ - -#include "logging_levels.h" - -/* Logging configuration for the HTTP library. */ -#ifndef LIBRARY_LOG_NAME - #define LIBRARY_LOG_NAME "HTTP" -#endif - -#ifndef LIBRARY_LOG_LEVEL - #define LIBRARY_LOG_LEVEL LOG_INFO -#endif - -#include "logging_stack.h" - - -/************ End of logging configuration ****************/ - -#endif /* ifndef CORE_HTTP_CONFIG_H_ */ diff --git a/demos/ota/ota_demo_core_http/core_mqtt_config.h b/demos/ota/ota_demo_core_http/core_mqtt_config.h deleted file mode 100644 index 3e84572ab5..0000000000 --- a/demos/ota/ota_demo_core_http/core_mqtt_config.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * AWS IoT Device SDK for Embedded C 202211.00 - * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef CORE_MQTT_CONFIG_H_ -#define CORE_MQTT_CONFIG_H_ - -/**************************************************/ -/******* DO NOT CHANGE the following order ********/ -/**************************************************/ - -/* Include logging header files and define logging macros in the following order: - * 1. Include the header file "logging_levels.h". - * 2. Define the LIBRARY_LOG_NAME and LIBRARY_LOG_LEVEL macros depending on - * the logging configuration for MQTT. - * 3. Include the header file "logging_stack.h", if logging is enabled for MQTT. - */ - -#include "logging_levels.h" - -/* Logging configuration for the MQTT library. */ -#ifndef LIBRARY_LOG_NAME - #define LIBRARY_LOG_NAME "MQTT" -#endif - -#ifndef LIBRARY_LOG_LEVEL - #define LIBRARY_LOG_LEVEL LOG_INFO -#endif - -#include "logging_stack.h" - -/************ End of logging configuration ****************/ - -/** - * @brief Determines the maximum number of MQTT PUBLISH messages, pending - * acknowledgement at a time, that are supported for incoming and outgoing - * direction of messages, separately. - * - * QoS 1 and 2 MQTT PUBLISHes require acknowledgement from the server before - * they can be completed. While they are awaiting the acknowledgement, the - * client must maintain information about their state. The value of this - * macro sets the limit on how many simultaneous PUBLISH states an MQTT - * context maintains, separately, for both incoming and outgoing direction of - * PUBLISHes. - * - * @note The MQTT context maintains separate state records for outgoing - * and incoming PUBLISHes, and thus, 2 * MQTT_STATE_ARRAY_MAX_COUNT amount - * of memory is statically allocated for the state records. - */ -#define MQTT_STATE_ARRAY_MAX_COUNT 10U - -/** - * @brief Number of milliseconds to wait for a ping response to a ping - * request as part of the keep-alive mechanism. - * - * If a ping response is not received before this timeout, then - * #MQTT_ProcessLoop will return #MQTTKeepAliveTimeout. - */ -#define MQTT_PINGRESP_TIMEOUT_MS ( 5000U ) - - -#endif /* ifndef CORE_MQTT_CONFIG_H_ */ diff --git a/demos/ota/ota_demo_core_http/demo_config.h b/demos/ota/ota_demo_core_http/demo_config.h deleted file mode 100644 index 3da22402f8..0000000000 --- a/demos/ota/ota_demo_core_http/demo_config.h +++ /dev/null @@ -1,188 +0,0 @@ -/* - * AWS IoT Device SDK for Embedded C 202211.00 - * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef DEMO_CONFIG_H_ -#define DEMO_CONFIG_H_ - -/**************************************************/ -/******* DO NOT CHANGE the following order ********/ -/**************************************************/ - -/* Logging related header files are required to be included in the following order: - * 1. Include the header file "logging_levels.h". - * 2. Define LIBRARY_LOG_NAME and LIBRARY_LOG_LEVEL. - * 3. Include the header file "logging_stack.h". - */ - -/* Include header that defines log levels. */ -#include "logging_levels.h" - -/* Logging configuration for the Demo. */ -#ifndef LIBRARY_LOG_NAME - #define LIBRARY_LOG_NAME "OTA_DEMO_HTTP" -#endif -#ifndef LIBRARY_LOG_LEVEL - #define LIBRARY_LOG_LEVEL LOG_INFO -#endif - -#include "logging_stack.h" - -/************ End of logging configuration ****************/ - -/** - * @brief Details of the MQTT broker to connect to. - * - * @note Your AWS IoT Core endpoint can be found in the AWS IoT console under - * Settings/Custom Endpoint, or using the describe-endpoint API. - * - * #define AWS_IOT_ENDPOINT "...insert here..." - */ - -/** - * @brief AWS IoT MQTT broker port number. - * - * In general, port 8883 is for secured MQTT connections. - * - * @note Port 443 requires use of the ALPN TLS extension with the ALPN protocol - * name. When using port 8883, ALPN is not required. - */ -#define AWS_MQTT_PORT ( 8883 ) - -/** - * @brief AWS IoT Core server port number for HTTPS connections. - * - * For this demo, an X.509 certificate is used to verify the client. - * - * @note Port 443 requires use of the ALPN TLS extension with the ALPN protocol - * name being x-amzn-http-ca. When using port 8443, ALPN is not required. - */ -#ifndef AWS_HTTPS_PORT - #define AWS_HTTPS_PORT 443 -#endif - - -/** - * @brief Path of the file containing the server's root CA certificate. - * - * This certificate is used to identify the AWS IoT server and is publicly - * available. Refer to the AWS documentation available in the link below - * https://docs.aws.amazon.com/iot/latest/developerguide/server-authentication.html#server-authentication-certs - * - * Amazon's root CA certificate is automatically downloaded to the certificates - * directory from @ref https://www.amazontrust.com/repository/AmazonRootCA1.pem - * using the CMake build system. - * - * @note This certificate should be PEM-encoded. - * @note This path is relative from the demo binary created. Update - * ROOT_CA_CERT_PATH to the absolute path if this demo is executed from elsewhere. - */ -#ifndef ROOT_CA_CERT_PATH - #define ROOT_CA_CERT_PATH "certificates/AmazonRootCA1.crt" -#endif - -/** - * @brief Path of the file containing the server's root CA certificate for TLS - * authentication. - * - * This certificate is used to identify the AWS IoT server and is publicly - * available. Refer to the AWS documentation available in the link below - * https://docs.aws.amazon.com/iot/latest/developerguide/server-authentication.html#server-authentication-certs - * - * Amazon's root CA certificate is automatically downloaded to the certificates - * directory from @ref https://www.amazontrust.com/repository/AmazonRootCA1.pem - * using the CMake build system. - * - * @note This certificate should be PEM-encoded. - */ -#ifndef ROOT_CA_CERT_PATH_HTTP - #define ROOT_CA_CERT_PATH_HTTP ROOT_CA_CERT_PATH -#endif - -/** - * @brief Path of the file containing the client certificate. - * - * Refer to the AWS documentation below for details regarding client - * authentication. - * https://docs.aws.amazon.com/iot/latest/developerguide/client-authentication.html - * - * @note This certificate should be PEM-encoded. - * - * #define CLIENT_CERT_PATH "...insert here..." - */ - -/** - * @brief Path of the file containing the client's private key. - * - * Refer to the AWS documentation below for details regarding client - * authentication. - * https://docs.aws.amazon.com/iot/latest/developerguide/client-authentication.html - * - * @note This private key should be PEM-encoded. - * - * #define CLIENT_PRIVATE_KEY_PATH "...insert here..." - */ - -/** - * @brief MQTT Client identifier. - * - * No two clients may use the same client identifier simultaneously. - */ -#ifndef CLIENT_IDENTIFIER - #define CLIENT_IDENTIFIER "testclient" -#endif - -/** - * @brief Configure application version. - */ - -#define APP_VERSION_MAJOR 0 -#define APP_VERSION_MINOR 9 -#define APP_VERSION_BUILD 3 - -/** - * @brief The name of the operating system that the application is running on. - * The current value is given as an example. Please update for your specific - * operating system. - */ -#define OS_NAME "Ubuntu" - -/** - * @brief The version of the operating system that the application is running - * on. The current value is given as an example. Please update for your specific - * operating system version. - */ -#define OS_VERSION "18.04 LTS" - -/** - * @brief The name of the hardware platform the application is running on. The - * current value is given as an example. Please update for your specific - * hardware platform. - */ -#define HARDWARE_PLATFORM_NAME "PC" - -/** - * @brief The name of the MQTT library used and its version, following an "@" - * symbol. - */ -#define OTA_LIB "otalib@1.0.0" - -#endif /* ifndef DEMO_CONFIG_H */ diff --git a/demos/ota/ota_demo_core_http/ota_config.h b/demos/ota/ota_demo_core_http/ota_config.h deleted file mode 100644 index 8f6b63e8e4..0000000000 --- a/demos/ota/ota_demo_core_http/ota_config.h +++ /dev/null @@ -1,185 +0,0 @@ -/* - * AWS IoT Device SDK for Embedded C 202211.00 - * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/** - * @file ota_config.h - * @brief OTA user configurable settings. - */ - -#ifndef OTA_CONFIG_H_ -#define OTA_CONFIG_H_ - -/**************************************************/ -/******* DO NOT CHANGE the following order ********/ -/**************************************************/ - -/* Logging related header files are required to be included in the following order: - * 1. Include the header file "logging_levels.h". - * 2. Define LIBRARY_LOG_NAME and LIBRARY_LOG_LEVEL. - * 3. Include the header file "logging_stack.h". - */ - -/* Include header that defines log levels. */ -#include "logging_levels.h" - -/* Configure name and log level for the OTA library. */ -#ifndef LIBRARY_LOG_NAME - #define LIBRARY_LOG_NAME "OTA" -#endif -#ifndef LIBRARY_LOG_LEVEL - #define LIBRARY_LOG_LEVEL LOG_INFO -#endif - -#include "logging_stack.h" - -/************ End of logging configuration ****************/ - -/** - * @brief Log base 2 of the size of the file data block message (excluding the header). - * - * 10 bits yields a data block size of 1KB. - */ -#define otaconfigLOG2_FILE_BLOCK_SIZE 12UL - -/** - * @brief Size of the file data block message (excluding the header). - * - */ -#define otaconfigFILE_BLOCK_SIZE ( 1UL << otaconfigLOG2_FILE_BLOCK_SIZE ) - -/** - * @brief Milliseconds to wait for the self test phase to succeed before we force reset. - */ -#define otaconfigSELF_TEST_RESPONSE_WAIT_MS 16000U - -/** - * @brief Milliseconds to wait before requesting data blocks from the OTA service if nothing is happening. - * - * The wait timer is reset whenever a data block is received from the OTA service so we will only send - * the request message after being idle for this amount of time. - */ -#define otaconfigFILE_REQUEST_WAIT_MS 10000U - -/** - * @brief The maximum allowed length of the thing name used by the OTA agent. - * - * AWS IoT requires Thing names to be unique for each device that connects to the broker. - * Likewise, the OTA agent requires the developer to construct and pass in the Thing name when - * initializing the OTA agent. The agent uses this size to allocate static storage for the - * Thing name used in all OTA base topics. Namely $aws/things/ - */ -#define otaconfigMAX_THINGNAME_LEN 64U - -/** - * @brief The maximum number of data blocks requested from OTA streaming service. - * - * This configuration parameter is sent with data requests and represents the maximum number of - * data blocks the service will send in response. The maximum limit for this must be calculated - * from the maximum data response limit (128 KB from service) divided by the block size. - * For example if block size is set as 1 KB then the maximum number of data blocks that we can - * request is 128/1 = 128 blocks. Configure this parameter to this maximum limit or lower based on - * how many data blocks response is expected for each data requests. - * Please note that this must be set larger than zero. - * - */ -#define otaconfigMAX_NUM_BLOCKS_REQUEST 1U - -/** - * @brief The maximum number of requests allowed to send without a response before we abort. - * - * This configuration parameter sets the maximum number of times the requests are made over - * the selected communication channel before aborting and returning error. - * - */ -#define otaconfigMAX_NUM_REQUEST_MOMENTUM 32U - -/** - * @brief The number of data buffers reserved by the OTA agent. - * - * This configurations parameter sets the maximum number of static data buffers used by - * the OTA agent for job and file data blocks received. - */ -#define otaconfigMAX_NUM_OTA_DATA_BUFFERS 2U - -/** - * @brief How frequently the device will report its OTA progress to the cloud. - * - * Device will update the job status with the number of blocks it has received every certain - * number of blocks it receives. For example, 25 means device will update job status every 25 blocks - * it receives. - */ -#define otaconfigOTA_UPDATE_STATUS_FREQUENCY 25U - -/** - * @brief Allow update to same or lower version. - * - * Set this to 1 to allow version update to a lower or the same version. This configurations parameter - * disables version check and allows update to a same or lower version. This is provided for - * testing purpose. It is RECOMMENDED to always update to higher version and keep this - * configuration disabled. - */ -#define otaconfigAllowDowngrade 0U - -/** - * @brief The protocol selected for OTA control operations. - * - * This configurations parameter sets the default protocol for all the OTA control - * operations like requesting OTA job, updating the job status etc. - * - * Note - Only MQTT is supported at this time for control operations. - */ -#define configENABLED_CONTROL_PROTOCOL ( OTA_CONTROL_OVER_MQTT ) - -/** - * @brief The protocol selected for OTA data operations. - * - * This configurations parameter sets the protocols selected for the data operations - * like requesting file blocks from the service. - * - * Note - Both MQTT and HTTP is supported for data transfer. This configuration parameter - * can be set to following - - * Enable data over MQTT - ( OTA_DATA_OVER_MQTT ) - * Enable data over HTTP - ( OTA_DATA_OVER_HTTP) - * Enable data over both MQTT & HTTP ( OTA_DATA_OVER_MQTT | OTA_DATA_OVER_HTTP ) - */ -#define configENABLED_DATA_PROTOCOLS ( OTA_DATA_OVER_HTTP ) - -/** - * @brief The preferred protocol selected for OTA data operations. - * - * Primary data protocol will be the protocol used for downloading file if more than - * one protocol is selected while creating OTA job. Default primary data protocol is MQTT - * and following update here to switch to HTTP as primary. - * - * Note - use OTA_DATA_OVER_HTTP for HTTP as primary data protocol. - */ -#define configOTA_PRIMARY_DATA_PROTOCOL ( OTA_DATA_OVER_HTTP ) - -/** - * @brief Data type to represent a file. - * - * It is used to represent a file received via OTA. The file is declared as - * the pointer of this type: otaconfigOTA_FILE_TYPE * pFile. - */ -#define otaconfigOTA_FILE_TYPE FILE - -#endif /* OTA_CONFIG_H_ */ diff --git a/demos/ota/ota_demo_core_http/ota_demo_core_http.c b/demos/ota/ota_demo_core_http/ota_demo_core_http.c deleted file mode 100644 index 7fdc25bf11..0000000000 --- a/demos/ota/ota_demo_core_http/ota_demo_core_http.c +++ /dev/null @@ -1,2274 +0,0 @@ -/* - * AWS IoT Device SDK for Embedded C 202211.00 - * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/** - * @file ota_demo_core_http.c - * @brief OTA update example using coreMQTT and coreHTTP. - */ - -/* Standard includes. */ -#include -#include -#include -#include - -/* Include Demo Config as the first non-system header. */ -#include "demo_config.h" - -/* OpenSSL sockets transport implementation. */ -#include "openssl_posix.h" - -/* Clock for timer. */ -#include "clock.h" - -/* pthread include. */ -#include -#include - -/* MQTT include. */ -#include "core_mqtt.h" -#include "mqtt_subscription_manager.h" - -/* HTTP include. */ -#include "core_http_client.h" - -/* Common HTTP demo utilities. */ -#include "http_demo_url_utils.h" - -/*Include backoff algorithm header for retry logic.*/ -#include "backoff_algorithm.h" - -/* OTA Library include. */ -#include "ota.h" -#include "ota_config.h" - -/* OTA Library Interface include. */ -#include "ota_os_posix.h" -#include "ota_mqtt_interface.h" -#include "ota_pal_posix.h" - -/* Include firmware version struct definition. */ -#include "ota_appversion32.h" - -/* AWS IoT Core TLS ALPN definitions for MQTT authentication */ -#include "aws_iot_alpn_defs.h" - -/** - * These configuration settings are required to run the OTA demo which uses mutual authentication. - * Throw compilation error if the below configs are not defined. - */ -#ifndef AWS_IOT_ENDPOINT - #error "Please define AWS IoT MQTT broker endpoint(AWS_IOT_ENDPOINT) in demo_config.h." -#endif -#ifndef ROOT_CA_CERT_PATH - #error "Please define path to Root CA certificate of the MQTT broker(ROOT_CA_CERT_PATH) in demo_config.h." -#endif -#ifndef ROOT_CA_CERT_PATH_HTTP - #error "Please define path to Root CA certificate of the HTTPS server(ROOT_CA_CERT_PATH_HTTP) in demo_config.h." -#endif -#ifndef CLIENT_IDENTIFIER - #error "Please define a unique client identifier, CLIENT_IDENTIFIER, in demo_config.h." -#endif -#ifndef CLIENT_CERT_PATH - #error "Please define path to client certificate(CLIENT_CERT_PATH) in demo_config.h." -#endif -#ifndef CLIENT_PRIVATE_KEY_PATH - #error "Please define path to client private key(CLIENT_PRIVATE_KEY_PATH) in demo_config.h." -#endif - -/** - * @brief Length of MQTT server host name. - */ -#define AWS_IOT_ENDPOINT_LENGTH ( ( uint16_t ) ( sizeof( AWS_IOT_ENDPOINT ) - 1 ) ) - -/** - * @brief Length of client identifier. - */ -#define CLIENT_IDENTIFIER_LENGTH ( ( uint16_t ) ( sizeof( CLIENT_IDENTIFIER ) - 1 ) ) - -/** - * @brief Transport timeout in milliseconds for transport send and receive. - */ -#define TRANSPORT_SEND_RECV_TIMEOUT_MS ( 1000U ) - -/** - * @brief Timeout for receiving CONNACK packet in milli seconds. - */ -#define CONNACK_RECV_TIMEOUT_MS ( 2000U ) - -/** - * @brief The maximum time interval in seconds which is allowed to elapse - * between two Control Packets. - * - * It is the responsibility of the Client to ensure that the interval between - * Control Packets being sent does not exceed the this Keep Alive value. In the - * absence of sending any other Control Packets, the Client MUST send a - * PINGREQ Packet. - */ -#define MQTT_KEEP_ALIVE_INTERVAL_SECONDS ( 60U ) - -/** - * @brief Maximum number or retries to publish a message in case of failures. - */ -#define MQTT_PUBLISH_RETRY_MAX_ATTEMPS ( 3U ) - -/** - * @brief Period for demo loop sleep in milliseconds. - */ -#define OTA_EXAMPLE_LOOP_SLEEP_PERIOD_MS ( 5U ) - -/** - * @brief The delay used in the main OTA Demo task loop to periodically output the OTA - * statistics like number of packets received, dropped, processed and queued per connection. - */ -#define OTA_EXAMPLE_TASK_DELAY_MS ( 1000U ) - -/** - * @brief The timeout for waiting for the agent to get suspended after closing the - * connection. - */ -#define OTA_SUSPEND_TIMEOUT_MS ( 5000U ) - -/** - * @brief Period for waiting on ack. - */ -#define MQTT_ACK_TIMEOUT_MS ( 5000U ) - -/** - * @brief The timeout for waiting before exiting the OTA demo. - */ -#define OTA_DEMO_EXIT_TIMEOUT_MS ( 3000U ) - -/** - * @brief The maximum size of the file paths used in the demo. - */ -#define OTA_MAX_FILE_PATH_SIZE ( 260U ) - -/** - * @brief The maximum size of the stream name required for downloading update file - * from streaming service. - */ -#define OTA_MAX_STREAM_NAME_SIZE ( 128U ) - -/** - * @brief The maximum back-off delay (in milliseconds) for retrying connection to server. - */ -#define CONNECTION_RETRY_MAX_BACKOFF_DELAY_MS ( 5000U ) - -/** - * @brief The base back-off delay (in milliseconds) to use for connection retry attempts. - */ -#define CONNECTION_RETRY_BACKOFF_BASE_MS ( 500U ) - -/** - * @brief Number of milliseconds in a second. - */ -#define NUM_MILLISECONDS_IN_SECOND ( 1000U ) - -/** - * @brief Maximum size of the url. - */ -#define OTA_MAX_URL_SIZE ( 2048U ) - -/** - * @brief Maximum size of the auth scheme. - */ -#define OTA_MAX_AUTH_SCHEME_SIZE ( 2048U ) - -/** - * @brief Size of the network buffer to receive the MQTT message. - * - * The largest message size is data size from the AWS IoT streaming service, - * otaconfigFILE_BLOCK_SIZE + extra for headers. - */ - -#define OTA_NETWORK_BUFFER_SIZE ( otaconfigFILE_BLOCK_SIZE + OTA_MAX_URL_SIZE + 128 ) - -/** - * @brief The maximum number of retries for connecting to server. - */ -#define CONNECTION_RETRY_MAX_ATTEMPTS ( 5U ) - -/** - * @brief The maximum size of the HTTP header. - */ -#define HTTP_HEADER_SIZE_MAX ( 1024U ) - -/* HTTP buffers used for http request and response. */ -#define HTTP_USER_BUFFER_LENGTH ( otaconfigFILE_BLOCK_SIZE + HTTP_HEADER_SIZE_MAX ) - -/** - * @brief The MQTT metrics string expected by AWS IoT. - */ -#define METRICS_STRING "?SDK=" OS_NAME "&Version=" OS_VERSION "&Platform=" HARDWARE_PLATFORM_NAME "&OTALib=" OTA_LIB - -/** - * @brief The length of the MQTT metrics string expected by AWS IoT. - */ -#define METRICS_STRING_LENGTH ( ( uint16_t ) ( sizeof( METRICS_STRING ) - 1 ) ) - - -#ifdef CLIENT_USERNAME - -/** - * @brief Append the username with the metrics string if #CLIENT_USERNAME is defined. - * - * This is to support both metrics reporting and username/password based client - * authentication by AWS IoT. - */ - #define CLIENT_USERNAME_WITH_METRICS CLIENT_USERNAME METRICS_STRING -#endif - -/** - * @brief The common prefix for all OTA topics. - */ -#define OTA_TOPIC_PREFIX "$aws/things/+/" - -/** - * @brief The string used for jobs topics. - */ -#define OTA_TOPIC_JOBS "jobs" - -/** - * @brief The string used for streaming service topics. - */ -#define OTA_TOPIC_STREAM "streams" - -/** - * @brief HTTP response codes used in this demo. - */ -#define HTTP_RESPONSE_PARTIAL_CONTENT ( 206 ) -#define HTTP_RESPONSE_BAD_REQUEST ( 400 ) -#define HTTP_RESPONSE_FORBIDDEN ( 403 ) -#define HTTP_RESPONSE_NOT_FOUND ( 404 ) - -/** - * @brief The length of the outgoing publish records array used by the coreMQTT - * library to track QoS > 0 packet ACKS for outgoing publishes. - */ -#define OUTGOING_PUBLISH_RECORD_LEN ( 10U ) - -/** - * @brief The length of the incoming publish records array used by the coreMQTT - * library to track QoS > 0 packet ACKS for incoming publishes. - */ -#define INCOMING_PUBLISH_RECORD_LEN ( 10U ) - -/*-----------------------------------------------------------*/ - -/* Linkage for error reporting. */ -extern int errno; - -/** - * @brief Struct for firmware version. - */ -const AppVersion32_t appFirmwareVersion = -{ - .u.x.major = APP_VERSION_MAJOR, - .u.x.minor = APP_VERSION_MINOR, - .u.x.build = APP_VERSION_BUILD, -}; - -/* Each compilation unit must define the NetworkContext struct. */ -struct NetworkContext -{ - OpensslParams_t * pParams; -}; - -/** - * @brief Network connection context used in this demo for MQTT connection. - */ -static NetworkContext_t networkContextMqtt; - -/** - * @brief Network connection context used for HTTP connection. - */ -static NetworkContext_t networkContextHttp; - - -/** - * @brief The host address string extracted from the pre-signed URL. - * - * @note S3_PRESIGNED_GET_URL_LENGTH is set as the array length here as the - * length of the host name string cannot exceed this value. - */ -static char serverHost[ 256 ]; - -/** - * @brief A buffer used in the demo for storing HTTP request headers and - * HTTP response headers and body. - * - * @note This demo shows how the same buffer can be re-used for storing the HTTP - * response after the HTTP request is sent out. However, the user can also - * decide to use separate buffers for storing the HTTP request and response. - */ -static uint8_t httpUserBuffer[ HTTP_USER_BUFFER_LENGTH ]; - -/* The transport layer interface used by the HTTP Client library. */ -TransportInterface_t transportInterfaceHttp = { NULL }; - -/** - * @brief MQTT connection context used in this demo. - */ -static MQTTContext_t mqttContext; - -/** - * @brief Keep a flag for indicating if the MQTT connection is alive. - */ -static bool mqttSessionEstablished = false; - -/** - * @brief Structure for openssl parameters for TLS session used by MQTT connection. - */ -static OpensslParams_t opensslParamsForMqtt; - -/** - * @brief Structure for openssl parameters for TLS session used by HTTP connection. - */ -static OpensslParams_t opensslParamsForHttp; - -/** - * @brief Mutex for synchronizing coreMQTT API calls. - */ -static pthread_mutex_t mqttMutex; - -/** - * @brief The host address string extracted from the pre-signed URL. - * - * @note S3_PRESIGNED_GET_URL_LENGTH is set as the array length here as the - * length of the host name string cannot exceed this value. - */ -static char serverHost[ 256 ]; - -/** - * @brief The length of the host address found in the pre-signed URL. - */ -static size_t serverHostLength; - -/** - * @brief Semaphore for synchronizing buffer operations. - */ -static sem_t bufferSemaphore; - -/** - * @brief Semaphore for synchronizing wait for ack. - */ -static sem_t ackSemaphore; - -/** - * @brief Enum for type of OTA job messages received. - */ -typedef enum jobMessageType -{ - jobMessageTypeNextGetAccepted = 0, - jobMessageTypeNextNotify, - jobMessageTypeMax -} jobMessageType_t; - -/** - * @brief The network buffer must remain valid when OTA library task is running. - */ -static uint8_t otaNetworkBuffer[ OTA_NETWORK_BUFFER_SIZE ]; - -/** - * @brief The location of the path within the pre-signed URL. - */ -static const char * pPath; - -/** - * @brief Update File path buffer. - */ -uint8_t updateFilePath[ OTA_MAX_FILE_PATH_SIZE ]; - -/** - * @brief Certificate File path buffer. - */ -uint8_t certFilePath[ OTA_MAX_FILE_PATH_SIZE ]; - -/** - * @brief Stream name buffer. - */ -uint8_t streamName[ OTA_MAX_STREAM_NAME_SIZE ]; - -/** - * @brief Decode memory. - */ -uint8_t decodeMem[ otaconfigFILE_BLOCK_SIZE ]; - -/** - * @brief Bitmap memory. - */ -uint8_t bitmap[ OTA_MAX_BLOCK_BITMAP_SIZE ]; - -/** - * @brief Certificate File path buffer. - */ -uint8_t updateUrl[ OTA_MAX_URL_SIZE ]; - -/** - * @brief Auth scheme buffer. - */ -uint8_t authScheme[ OTA_MAX_URL_SIZE ]; - -/** - * @brief Event buffer. - */ -static OtaEventData_t eventBuffer[ otaconfigMAX_NUM_OTA_DATA_BUFFERS ]; - -/** - * @brief The buffer passed to the OTA Agent from application while initializing. - */ -static OtaAppBuffer_t otaBuffer = -{ - .pUpdateFilePath = updateFilePath, - .updateFilePathsize = OTA_MAX_FILE_PATH_SIZE, - .pCertFilePath = certFilePath, - .certFilePathSize = OTA_MAX_FILE_PATH_SIZE, - .pDecodeMemory = decodeMem, - .decodeMemorySize = otaconfigFILE_BLOCK_SIZE, - .pFileBitmap = bitmap, - .fileBitmapSize = OTA_MAX_BLOCK_BITMAP_SIZE, - .pUrl = updateUrl, - .urlSize = OTA_MAX_URL_SIZE, - .pAuthScheme = authScheme, - .authSchemeSize = OTA_MAX_AUTH_SCHEME_SIZE -}; - -/** - * @brief Array to track the outgoing publish records for outgoing publishes - * with QoS > 0. - * - * This is passed into #MQTT_InitStatefulQoS to allow for QoS > 0. - * - */ -static MQTTPubAckInfo_t pOutgoingPublishRecords[ OUTGOING_PUBLISH_RECORD_LEN ]; - -/** - * @brief Array to track the incoming publish records for incoming publishes - * with QoS > 0. - * - * This is passed into #MQTT_InitStatefulQoS to allow for QoS > 0. - * - */ -static MQTTPubAckInfo_t pIncomingPublishRecords[ INCOMING_PUBLISH_RECORD_LEN ]; - -/*-----------------------------------------------------------*/ - -/** - * @brief Retry logic to establish a connection to the server. - * - * If the connection fails, keep retrying with exponentially increasing - * timeout value, until max retries, max timeout or successful connect. - * - * @param[in] pNetworkContext Network context to connect on. - * @return int EXIT_FAILURE if connection failed after retries. - */ -static int connectToServerWithBackoffRetries( NetworkContext_t * pNetworkContext ); - -/** - * @brief Sends an MQTT CONNECT packet over the already connected TCP socket. - * - * @param[in] pMqttContext MQTT context pointer. - * @param[in] createCleanSession Creates a new MQTT session if true. - * If false, tries to establish the existing session if there was session - * already present in broker. - * @param[out] pSessionPresent Session was already present in the broker or not. - * Session present response is obtained from the CONNACK from broker. - * - * @return EXIT_SUCCESS if an MQTT session is established; - * EXIT_FAILURE otherwise. - */ -static int establishMqttSession( MQTTContext_t * pMqttContext ); - -/** - * @brief Publish message to a topic. - * - * This function publishes a message to a given topic & QoS. - * - * @param[in] pTopic Mqtt topic filter. - * - * @param[in] topicLen Length of the topic filter. - * - * @param[in] pMsg Message to publish. - * - * @param[in] msgSize Message size. - * - * @param[in] qos Quality of Service - * - * @return OtaMqttSuccess if success , other error code on failure. - */ -static OtaMqttStatus_t mqttPublish( const char * const pTopic, - uint16_t topicLen, - const char * pMsg, - uint32_t msgSize, - uint8_t qos ); - -/** - * @brief Subscribe to the Mqtt topics. - * - * This function subscribes to the Mqtt topics with the Quality of service - * received as parameter. This function also registers a callback for the - * topicfilter. - * - * @param[in] pTopicFilter Mqtt topic filter. - * - * @param[in] topicFilterLength Length of the topic filter. - * - * @param[in] qos Quality of Service - * - * @return OtaMqttSuccess if success , other error code on failure. - */ -static OtaMqttStatus_t mqttSubscribe( const char * pTopicFilter, - uint16_t topicFilterLength, - uint8_t qos ); - -/** - * @brief Unsubscribe to the Mqtt topics. - * - * This function unsubscribes to the Mqtt topics with the Quality of service - * received as parameter. - * - * @param[in] pTopicFilter Mqtt topic filter. - * - * @param[in] topicFilterLength Length of the topic filter. - * - * @param[qos] qos Quality of Service - * - * @return OtaMqttSuccess if success , other error code on failure. - */ -static OtaMqttStatus_t mqttUnsubscribe( const char * pTopicFilter, - uint16_t topicFilterLength, - uint8_t qos ); - -/** - * @brief Handle HTTP response. - * - * @param[in] pResponse Pointer to http response buffer. - * @return OtaHttpStatus_t OtaHttpSuccess if success or failure code otherwise. - */ -static OtaHttpStatus_t handleHttpResponse( const HTTPResponse_t * pResponse ); - -/** - * @brief Initialize OTA Http interface. - * - * @param[in] pUrl Pointer to the pre-signed url for downloading update file. - * @return OtaHttpStatus_t OtaHttpSuccess if success , - * OtaHttpInitFailed on failure. - */ -static OtaHttpStatus_t httpInit( char * pUrl ); - -/** - * @brief Request file block over HTTP. - * - * @param[in] rangeStart Starting index of the file data - * @param[in] rangeEnd Last index of the file data - * @return OtaHttpStatus_t OtaHttpSuccess if success , - * other errors on failure. - */ -static OtaHttpStatus_t httpRequest( uint32_t rangeStart, - uint32_t rangeEnd ); - -/** - * @brief Deinitialize and cleanup of the HTTP connection. - * - * @return OtaHttpStatus_t OtaHttpSuccess if success , - * OtaHttpRequestFailed on failure. - */ -static OtaHttpStatus_t httpDeinit( void ); - -/** - * @brief Initialize MQTT by setting up transport interface and network. - * - * @param[in] pMqttContext Structure representing MQTT connection. - * @param[in] pNetworkContext Network context to connect on. - * @return int EXIT_SUCCESS if MQTT component is initialized - */ -static int initializeMqtt( MQTTContext_t * pMqttContext, - NetworkContext_t * pNetworkContext ); - -/** - * @brief Attempt to connect to the MQTT broker. - * - * @return int EXIT_SUCCESS if a connection is established. - */ -static int establishConnection( void ); - -/** - * @brief Disconnect from the MQTT broker. - * - */ -static void disconnect( void ); - -/** - * @brief Thread to call the OTA agent task. - * - * @param[in] pParam Can be used to pass down functionality to the agent task - * @return void* returning null. - */ -static void * otaThread( void * pParam ); - -/** - * @brief Start OTA demo. - * - * @return EXIT_SUCCESS or EXIT_FAILURE. - */ -static int startOTADemo( void ); - -/** - * @brief Set OTA interfaces. - * - * @param[in] pOtaInterfaces pointer to OTA interface structure. - * - * @return None. - */ -static void setOtaInterfaces( OtaInterfaces_t * pOtaInterfaces ); - -/** - * @brief Random number to be used as a back-off value for retrying connection. - * - * @return uint32_t The generated random number. - */ -static uint32_t generateRandomNumber(); - -/* Callbacks used to handle different events. */ - -/** - * @brief The OTA agent has completed the update job or it is in - * self test mode. If it was accepted, we want to activate the new image. - * This typically means we should reset the device to run the new firmware. - * If now is not a good time to reset the device, it may be activated later - * by your user code. If the update was rejected, just return without doing - * anything and we'll wait for another job. If it reported that we should - * start test mode, normally we would perform some kind of system checks to - * make sure our new firmware does the basic things we think it should do - * but we'll just go ahead and set the image as accepted for demo purposes. - * The accept function varies depending on your platform. Refer to the OTA - * PAL implementation for your platform in aws_ota_pal.c to see what it - * does for you. - * - * @param[in] event Event from OTA lib of type OtaJobEvent_t. - * @return None. - */ -static void otaAppCallback( OtaJobEvent_t event, - void * pData ); - -/** - * @brief callback to use with the MQTT context to notify incoming packet events. - * - * @param[in] pMqttContext MQTT context which stores the connection. - * @param[in] pPacketInfo Parameters of the incoming packet. - * @param[in] pDeserializedInfo Deserialized packet information to be dispatched by - * the subscription manager to event callbacks. - */ -static void mqttEventCallback( MQTTContext_t * pMqttContext, - MQTTPacketInfo_t * pPacketInfo, - MQTTDeserializedInfo_t * pDeserializedInfo ); - -/** - * @brief Callback registered with the OTA library that notifies the OTA agent - * of an incoming PUBLISH containing a job document. - * - * @param[in] pContext MQTT context which stores the connection. - * @param[in] pPublishInfo MQTT packet information which stores details of the - * job document. - */ -static void mqttJobCallback( MQTTContext_t * pContext, - MQTTPublishInfo_t * pPublishInfo ); - -/** - * @brief Callback that notifies the OTA library when a data block is received. - * - * @param[in] pContext MQTT context which stores the connection. - * @param[in] pPublishInfo MQTT packet that stores the information of the file block. - */ -static void mqttDataCallback( MQTTContext_t * pContext, - MQTTPublishInfo_t * pPublishInfo ); - -static SubscriptionManagerCallback_t otaMessageCallback[] = { mqttJobCallback, mqttDataCallback }; - -/*-----------------------------------------------------------*/ - -void otaEventBufferFree( OtaEventData_t * const pxBuffer ) -{ - if( sem_wait( &bufferSemaphore ) == 0 ) - { - pxBuffer->bufferUsed = false; - ( void ) sem_post( &bufferSemaphore ); - } - else - { - LogError( ( "Failed to get buffer semaphore: " - ",errno=%s", - strerror( errno ) ) ); - } -} - -/*-----------------------------------------------------------*/ - -OtaEventData_t * otaEventBufferGet( void ) -{ - uint32_t ulIndex = 0; - OtaEventData_t * pFreeBuffer = NULL; - - if( sem_wait( &bufferSemaphore ) == 0 ) - { - for( ulIndex = 0; ulIndex < otaconfigMAX_NUM_OTA_DATA_BUFFERS; ulIndex++ ) - { - if( eventBuffer[ ulIndex ].bufferUsed == false ) - { - eventBuffer[ ulIndex ].bufferUsed = true; - pFreeBuffer = &eventBuffer[ ulIndex ]; - break; - } - } - - ( void ) sem_post( &bufferSemaphore ); - } - else - { - LogError( ( "Failed to get buffer semaphore: " - ",errno=%s", - strerror( errno ) ) ); - } - - return pFreeBuffer; -} - -/*-----------------------------------------------------------*/ - -static void otaAppCallback( OtaJobEvent_t event, - void * pData ) -{ - OtaErr_t err = OtaErrUninitialized; - - switch( event ) - { - case OtaJobEventActivate: - LogInfo( ( "Received OtaJobEventActivate callback from OTA Agent." ) ); - - /* Activate the new firmware image. */ - OTA_ActivateNewImage(); - - /* Shutdown OTA Agent, if it is required that the unsubscribe operations are not - * performed while shutting down please set the second parameter to 0 instead of 1. */ - OTA_Shutdown( 0, 1 ); - - /* Requires manual activation of new image.*/ - LogError( ( "New image activation failed." ) ); - - break; - - case OtaJobEventFail: - LogInfo( ( "Received OtaJobEventFail callback from OTA Agent." ) ); - - /* Nothing special to do. The OTA agent handles it. */ - break; - - case OtaJobEventStartTest: - - /* This demo just accepts the image since it was a good OTA update and networking - * and services are all working (or we would not have made it this far). If this - * were some custom device that wants to test other things before validating new - * image, this would be the place to kick off those tests before calling - * OTA_SetImageState() with the final result of either accepted or rejected. */ - - LogInfo( ( "Received OtaJobEventStartTest callback from OTA Agent." ) ); - err = OTA_SetImageState( OtaImageStateAccepted ); - - if( err != OtaErrNone ) - { - LogError( ( " Failed to set image state as accepted." ) ); - } - - break; - - case OtaJobEventProcessed: - LogDebug( ( "Received OtaJobEventProcessed callback from OTA Agent." ) ); - - if( pData != NULL ) - { - otaEventBufferFree( ( OtaEventData_t * ) pData ); - } - - break; - - case OtaJobEventSelfTestFailed: - LogDebug( ( "Received OtaJobEventSelfTestFailed callback from OTA Agent." ) ); - - /* Requires manual activation of previous image as self-test for - * new image downloaded failed.*/ - LogError( ( "Self-test failed, shutting down OTA Agent." ) ); - - /* Shutdown OTA Agent, if it is required that the unsubscribe operations are not - * performed while shutting down please set the second parameter to 0 instead of 1. */ - OTA_Shutdown( 0, 1 ); - - - break; - - default: - LogDebug( ( "Received invalid callback event from OTA Agent." ) ); - } -} - -jobMessageType_t getJobMessageType( const char * pTopicName, - uint16_t topicNameLength ) -{ - uint16_t index = 0U; - MQTTStatus_t mqttStatus = MQTTSuccess; - bool isMatch = false; - jobMessageType_t jobMessageIndex = jobMessageTypeMax; - - /* For suppressing compiler-warning: unused variable. */ - ( void ) mqttStatus; - - /* Lookup table for OTA job message string. */ - static const char * const pJobTopicFilters[ jobMessageTypeMax ] = - { - OTA_TOPIC_PREFIX OTA_TOPIC_JOBS "/$next/get/accepted", - OTA_TOPIC_PREFIX OTA_TOPIC_JOBS "/notify-next", - }; - - /* Match the input topic filter against the wild-card pattern of topics filters - * relevant for the OTA Update service to determine the type of topic filter. */ - for( ; index < jobMessageTypeMax; index++ ) - { - mqttStatus = MQTT_MatchTopic( pTopicName, - topicNameLength, - pJobTopicFilters[ index ], - strlen( pJobTopicFilters[ index ] ), - &isMatch ); - assert( mqttStatus == MQTTSuccess ); - - if( isMatch ) - { - jobMessageIndex = index; - break; - } - } - - return jobMessageIndex; -} - -/*-----------------------------------------------------------*/ - -static void mqttJobCallback( MQTTContext_t * pContext, - MQTTPublishInfo_t * pPublishInfo ) -{ - OtaEventData_t * pData; - OtaEventMsg_t eventMsg = { 0 }; - jobMessageType_t jobMessageType = 0; - - assert( pPublishInfo != NULL ); - assert( pContext != NULL ); - - ( void ) pContext; - - jobMessageType = getJobMessageType( pPublishInfo->pTopicName, pPublishInfo->topicNameLength ); - - switch( jobMessageType ) - { - case jobMessageTypeNextGetAccepted: - case jobMessageTypeNextNotify: - - pData = otaEventBufferGet(); - - if( pData != NULL ) - { - memcpy( pData->data, pPublishInfo->pPayload, pPublishInfo->payloadLength ); - pData->dataLength = pPublishInfo->payloadLength; - eventMsg.eventId = OtaAgentEventReceivedJobDocument; - eventMsg.pEventData = pData; - - /* Send job document received event. */ - OTA_SignalEvent( &eventMsg ); - } - else - { - LogError( ( "No OTA data buffers available." ) ); - } - - break; - - default: - LogInfo( ( "Received job message %s size %ld.\n\n", - pPublishInfo->pTopicName, - pPublishInfo->payloadLength ) ); - } -} - -/*-----------------------------------------------------------*/ - -static void mqttDataCallback( MQTTContext_t * pContext, - MQTTPublishInfo_t * pPublishInfo ) -{ - OtaEventData_t * pData; - OtaEventMsg_t eventMsg = { 0 }; - - assert( pPublishInfo != NULL ); - assert( pContext != NULL ); - - ( void ) pContext; - - LogInfo( ( "Received data message callback, size %zu.\n\n", pPublishInfo->payloadLength ) ); - - pData = otaEventBufferGet(); - - if( pData != NULL ) - { - memcpy( pData->data, pPublishInfo->pPayload, pPublishInfo->payloadLength ); - pData->dataLength = pPublishInfo->payloadLength; - eventMsg.eventId = OtaAgentEventReceivedFileBlock; - eventMsg.pEventData = pData; - - /* Send job document received event. */ - OTA_SignalEvent( &eventMsg ); - } - else - { - LogError( ( "No OTA data buffers available." ) ); - } -} - -/*-----------------------------------------------------------*/ - -static void mqttEventCallback( MQTTContext_t * pMqttContext, - MQTTPacketInfo_t * pPacketInfo, - MQTTDeserializedInfo_t * pDeserializedInfo ) -{ - assert( pMqttContext != NULL ); - assert( pPacketInfo != NULL ); - assert( pDeserializedInfo != NULL ); - - /* Handle incoming publish. The lower 4 bits of the publish packet - * type is used for the dup, QoS, and retain flags. Hence masking - * out the lower bits to check if the packet is publish. */ - if( ( pPacketInfo->type & 0xF0U ) == MQTT_PACKET_TYPE_PUBLISH ) - { - assert( pDeserializedInfo->pPublishInfo != NULL ); - /* Handle incoming publish. */ - SubscriptionManager_DispatchHandler( pMqttContext, pDeserializedInfo->pPublishInfo ); - } - else - { - /* Handle other packets. */ - switch( pPacketInfo->type ) - { - case MQTT_PACKET_TYPE_SUBACK: - LogInfo( ( "Received SUBACK.\n\n" ) ); - break; - - case MQTT_PACKET_TYPE_UNSUBACK: - LogInfo( ( "Received UNSUBACK.\n\n" ) ); - break; - - case MQTT_PACKET_TYPE_PINGRESP: - - /* Nothing to be done from application as library handles - * PINGRESP. */ - LogWarn( ( "PINGRESP should not be handled by the application " - "callback when using MQTT_ProcessLoop.\n\n" ) ); - break; - - case MQTT_PACKET_TYPE_PUBACK: - LogInfo( ( "PUBACK received for packet id %u.\n\n", - pDeserializedInfo->packetIdentifier ) ); - sem_post( &ackSemaphore ); - break; - - /* Any other packet type is invalid. */ - default: - LogError( ( "Unknown packet type received:(%02x).\n\n", - pPacketInfo->type ) ); - } - } -} - -/*-----------------------------------------------------------*/ - -static uint32_t generateRandomNumber() -{ - return( rand() ); -} - -/*-----------------------------------------------------------*/ - -static int initializeMqtt( MQTTContext_t * pMqttContext, - NetworkContext_t * pNetworkContext ) -{ - int returnStatus = EXIT_SUCCESS; - MQTTStatus_t mqttStatus = MQTTBadParameter; - MQTTFixedBuffer_t networkBuffer; - TransportInterface_t transport = { NULL }; - - assert( pMqttContext != NULL ); - assert( pNetworkContext != NULL ); - - /* Fill in TransportInterface send and receive function pointers. - * For this demo, TCP sockets are used to send and receive data - * from network. Network context is SSL context for OpenSSL.*/ - transport.pNetworkContext = pNetworkContext; - transport.send = Openssl_Send; - transport.recv = Openssl_Recv; - transport.writev = NULL; - - /* Fill the values for network buffer. */ - networkBuffer.pBuffer = otaNetworkBuffer; - networkBuffer.size = OTA_NETWORK_BUFFER_SIZE; - - /* Initialize MQTT library. */ - mqttStatus = MQTT_Init( pMqttContext, - &transport, - Clock_GetTimeMs, - mqttEventCallback, - &networkBuffer ); - - if( mqttStatus != MQTTSuccess ) - { - returnStatus = EXIT_FAILURE; - LogError( ( "MQTT_Init failed: Status = %s.", MQTT_Status_strerror( mqttStatus ) ) ); - } - else - { - mqttStatus = MQTT_InitStatefulQoS( pMqttContext, - pOutgoingPublishRecords, - OUTGOING_PUBLISH_RECORD_LEN, - pIncomingPublishRecords, - INCOMING_PUBLISH_RECORD_LEN ); - - if( mqttStatus != MQTTSuccess ) - { - returnStatus = EXIT_FAILURE; - LogError( ( "MQTT_InitStatefulQoS failed: Status = %s.", MQTT_Status_strerror( mqttStatus ) ) ); - } - } - - return returnStatus; -} - -/*-----------------------------------------------------------*/ - -static int connectToServerWithBackoffRetries( NetworkContext_t * pNetworkContext ) -{ - int returnStatus = EXIT_SUCCESS; - BackoffAlgorithmStatus_t backoffAlgStatus = BackoffAlgorithmSuccess; - OpensslStatus_t opensslStatus = OPENSSL_SUCCESS; - BackoffAlgorithmContext_t reconnectParams; - ServerInfo_t serverInfo; - OpensslCredentials_t opensslCredentials; - uint16_t nextRetryBackOff; - - /* Initialize information to connect to the MQTT broker. */ - serverInfo.pHostName = AWS_IOT_ENDPOINT; - serverInfo.hostNameLength = AWS_IOT_ENDPOINT_LENGTH; - serverInfo.port = AWS_MQTT_PORT; - - /* Initialize credentials for establishing TLS session. */ - memset( &opensslCredentials, 0, sizeof( OpensslCredentials_t ) ); - opensslCredentials.pRootCaPath = ROOT_CA_CERT_PATH; - - /* If #CLIENT_USERNAME is defined, username/password is used for authenticating - * the client. */ - #ifndef CLIENT_USERNAME - opensslCredentials.pClientCertPath = CLIENT_CERT_PATH; - opensslCredentials.pPrivateKeyPath = CLIENT_PRIVATE_KEY_PATH; - #endif - - /* AWS IoT requires devices to send the Server Name Indication (SNI) - * extension to the Transport Layer Security (TLS) protocol and provide - * the complete endpoint address in the host_name field. Details about - * SNI for AWS IoT can be found in the link below. - * https://docs.aws.amazon.com/iot/latest/developerguide/transport-security.html */ - opensslCredentials.sniHostName = AWS_IOT_ENDPOINT; - - if( AWS_MQTT_PORT == 443 ) - { - /* Pass the ALPN protocol name depending on the port being used. - * Please see more details about the ALPN protocol for the AWS IoT MQTT - * endpoint in the link below. - * https://aws.amazon.com/blogs/iot/mqtt-with-tls-client-authentication-on-port-443-why-it-is-useful-and-how-it-works/ - * - * For username and password based authentication in AWS IoT, - * #AWS_IOT_PASSWORD_ALPN is used. More details can be found in the - * link below. - * https://docs.aws.amazon.com/iot/latest/developerguide/custom-authentication.html - */ - #ifdef CLIENT_USERNAME - opensslCredentials.pAlpnProtos = AWS_IOT_ALPN_MQTT_CUSTOM_AUTH_OPENSSL; - opensslCredentials.alpnProtosLen = AWS_IOT_ALPN_MQTT_CUSTOM_AUTH_OPENSSL_LEN; - #else - opensslCredentials.pAlpnProtos = AWS_IOT_ALPN_MQTT_CA_AUTH_OPENSSL; - opensslCredentials.alpnProtosLen = AWS_IOT_ALPN_MQTT_CA_AUTH_OPENSSL_LEN; - #endif - } - - /* Initialize reconnect attempts and interval */ - BackoffAlgorithm_InitializeParams( &reconnectParams, - CONNECTION_RETRY_BACKOFF_BASE_MS, - CONNECTION_RETRY_MAX_BACKOFF_DELAY_MS, - CONNECTION_RETRY_MAX_ATTEMPTS ); - - /* Attempt to connect to MQTT broker. If connection fails, retry after - * a timeout. Timeout value will exponentially increase until maximum - * attempts are reached. - */ - do - { - /* Establish a TLS session with the MQTT broker. This example connects - * to the MQTT broker as specified in AWS_IOT_ENDPOINT and AWS_MQTT_PORT - * at the demo config header. */ - LogInfo( ( "Establishing a TLS session to %.*s:%d.", - AWS_IOT_ENDPOINT_LENGTH, - AWS_IOT_ENDPOINT, - AWS_MQTT_PORT ) ); - opensslStatus = Openssl_Connect( pNetworkContext, - &serverInfo, - &opensslCredentials, - TRANSPORT_SEND_RECV_TIMEOUT_MS, - TRANSPORT_SEND_RECV_TIMEOUT_MS ); - - if( opensslStatus != OPENSSL_SUCCESS ) - { - /* Generate a random number and get back-off value (in milliseconds) for the next connection retry. */ - backoffAlgStatus = BackoffAlgorithm_GetNextBackoff( &reconnectParams, generateRandomNumber(), &nextRetryBackOff ); - - if( backoffAlgStatus == BackoffAlgorithmRetriesExhausted ) - { - LogError( ( "Connection to the broker failed, all attempts exhausted." ) ); - returnStatus = EXIT_FAILURE; - } - else if( backoffAlgStatus == BackoffAlgorithmSuccess ) - { - LogWarn( ( "Connection to the broker failed. Retrying connection " - "after %hu ms backoff.", - ( unsigned short ) nextRetryBackOff ) ); - Clock_SleepMs( nextRetryBackOff ); - } - } - } while( ( opensslStatus != OPENSSL_SUCCESS ) && ( backoffAlgStatus == BackoffAlgorithmSuccess ) ); - - return returnStatus; -} - -/*-----------------------------------------------------------*/ - -static int establishMqttSession( MQTTContext_t * pMqttContext ) -{ - int returnStatus = EXIT_SUCCESS; - MQTTStatus_t mqttStatus = MQTTBadParameter; - MQTTConnectInfo_t connectInfo = { 0 }; - - bool sessionPresent = false; - - assert( pMqttContext != NULL ); - - /* Establish MQTT session by sending a CONNECT packet. */ - - /* If #createCleanSession is true, start with a clean session - * i.e. direct the MQTT broker to discard any previous session data. - * If #createCleanSession is false, directs the broker to attempt to - * reestablish a session which was already present. */ - connectInfo.cleanSession = true; - - /* The client identifier is used to uniquely identify this MQTT client to - * the MQTT broker. In a production device the identifier can be something - * unique, such as a device serial number. */ - connectInfo.pClientIdentifier = CLIENT_IDENTIFIER; - connectInfo.clientIdentifierLength = CLIENT_IDENTIFIER_LENGTH; - - /* The maximum time interval in seconds which is allowed to elapse - * between two Control Packets. - * It is the responsibility of the Client to ensure that the interval between - * Control Packets being sent does not exceed the this Keep Alive value. In the - * absence of sending any other Control Packets, the Client MUST send a - * PINGREQ Packet. */ - connectInfo.keepAliveSeconds = MQTT_KEEP_ALIVE_INTERVAL_SECONDS; - - /* Use the username and password for authentication, if they are defined. - * Refer to the AWS IoT documentation below for details regarding client - * authentication with a username and password. - * https://docs.aws.amazon.com/iot/latest/developerguide/custom-authentication.html - * An authorizer setup needs to be done, as mentioned in the above link, to use - * username/password based client authentication. - * - * The username field is populated with voluntary metrics to AWS IoT. - * The metrics collected by AWS IoT are the operating system, the operating - * system's version, the hardware platform, and the MQTT Client library - * information. These metrics help AWS IoT improve security and provide - * better technical support. - * - * If client authentication is based on username/password in AWS IoT, - * the metrics string is appended to the username to support both client - * authentication and metrics collection. */ - #ifdef CLIENT_USERNAME - connectInfo.pUserName = CLIENT_USERNAME_WITH_METRICS; - connectInfo.userNameLength = strlen( CLIENT_USERNAME_WITH_METRICS ); - connectInfo.pPassword = CLIENT_PASSWORD; - connectInfo.passwordLength = strlen( CLIENT_PASSWORD ); - #else - connectInfo.pUserName = METRICS_STRING; - connectInfo.userNameLength = METRICS_STRING_LENGTH; - /* Password for authentication is not used. */ - connectInfo.pPassword = NULL; - connectInfo.passwordLength = 0U; - #endif /* ifdef CLIENT_USERNAME */ - - if( pthread_mutex_lock( &mqttMutex ) == 0 ) - { - /* Send MQTT CONNECT packet to broker. */ - mqttStatus = MQTT_Connect( pMqttContext, &connectInfo, NULL, CONNACK_RECV_TIMEOUT_MS, &sessionPresent ); - - pthread_mutex_unlock( &mqttMutex ); - } - else - { - LogError( ( "Failed to acquire mutex for executing MQTT_Connect" - ",errno=%s", - strerror( errno ) ) ); - } - - if( mqttStatus != MQTTSuccess ) - { - returnStatus = EXIT_FAILURE; - LogError( ( "Connection with MQTT broker failed with status %s.", - MQTT_Status_strerror( mqttStatus ) ) ); - } - else - { - LogInfo( ( "MQTT connection successfully established with broker.\n\n" ) ); - } - - return returnStatus; -} - -/*-----------------------------------------------------------*/ - -static int establishConnection( void ) -{ - int returnStatus = EXIT_FAILURE; - - /* Set the pParams member of the network context with desired transport. */ - networkContextMqtt.pParams = &opensslParamsForMqtt; - - /* Attempt to connect to the MQTT broker. If connection fails, retry after - * a timeout. Timeout value will be exponentially increased till the maximum - * attempts are reached or maximum timeout value is reached. The function - * returns EXIT_FAILURE if the TCP connection cannot be established to - * broker after configured number of attempts. */ - returnStatus = connectToServerWithBackoffRetries( &networkContextMqtt ); - - if( returnStatus != EXIT_SUCCESS ) - { - /* Log error to indicate connection failure. */ - LogError( ( "Failed to connect to MQTT broker %.*s.", - AWS_IOT_ENDPOINT_LENGTH, - AWS_IOT_ENDPOINT ) ); - } - else - { - /* Establish MQTT session on top of TCP+TLS connection. */ - LogInfo( ( "Creating an MQTT connection to %.*s.", - AWS_IOT_ENDPOINT_LENGTH, - AWS_IOT_ENDPOINT ) ); - - /* Sends an MQTT Connect packet using the established TLS session, - * then waits for connection acknowledgment (CONNACK) packet. */ - returnStatus = establishMqttSession( &mqttContext ); - - if( returnStatus != EXIT_SUCCESS ) - { - LogError( ( "Failed creating an MQTT connection to %.*s.", - AWS_IOT_ENDPOINT_LENGTH, - AWS_IOT_ENDPOINT ) ); - } - else - { - LogDebug( ( "Success creating MQTT connection to %.*s.", - AWS_IOT_ENDPOINT_LENGTH, - AWS_IOT_ENDPOINT ) ); - - mqttSessionEstablished = true; - } - } - - return returnStatus; -} - -/*-----------------------------------------------------------*/ - -static void disconnect( void ) -{ - /* Disconnect from broker. */ - LogInfo( ( "Disconnecting the MQTT connection with %s.", AWS_IOT_ENDPOINT ) ); - - if( mqttSessionEstablished == true ) - { - if( pthread_mutex_lock( &mqttMutex ) == 0 ) - { - /* Disconnect MQTT session. */ - MQTT_Disconnect( &mqttContext ); - - /* Clear the mqtt session flag. */ - mqttSessionEstablished = false; - - pthread_mutex_unlock( &mqttMutex ); - } - else - { - LogError( ( "Failed to acquire mutex to execute MQTT_Disconnect" - ",errno=%s", - strerror( errno ) ) ); - } - } - else - { - LogError( ( "MQTT already disconnected." ) ); - } - - /* End TLS session, then close TCP connection. */ - ( void ) Openssl_Disconnect( &networkContextMqtt ); -} - -static int32_t connectToS3Server( NetworkContext_t * pNetworkContext, - const char * pUrl ) -{ - int32_t returnStatus = EXIT_SUCCESS; - HTTPStatus_t httpStatus = HTTPSuccess; - - /* The location of the host address within the pre-signed URL. */ - const char * pAddress = NULL; - - /* Status returned by OpenSSL transport implementation. */ - OpensslStatus_t opensslStatus; - /* Credentials to establish the TLS connection. */ - OpensslCredentials_t opensslCredentials; - /* Information about the server to send the HTTP requests. */ - ServerInfo_t serverInfo; - - /* Initialize TLS credentials. */ - ( void ) memset( &opensslCredentials, 0, sizeof( opensslCredentials ) ); - opensslCredentials.pRootCaPath = ROOT_CA_CERT_PATH_HTTP; - - /* Retrieve the address location and length from S3_PRESIGNED_GET_URL. */ - if( pUrl != NULL ) - { - /* Retrieve the address location and length from S3_PRESIGNED_GET_URL. */ - httpStatus = getUrlAddress( pUrl, - strlen( pUrl ), - &pAddress, - &serverHostLength ); - - if( httpStatus != HTTPSuccess ) - { - LogError( ( "URL %s parsing failed. Error code: %d", - pUrl, - httpStatus ) ); - } - - /* serverHost should consist only of the host address. */ - memcpy( serverHost, pAddress, serverHostLength ); - serverHost[ serverHostLength ] = '\0'; - } - - if( returnStatus != EXIT_FAILURE ) - { - /* Initialize server information. */ - serverInfo.pHostName = serverHost; - serverInfo.hostNameLength = serverHostLength; - serverInfo.port = AWS_HTTPS_PORT; - - /* Establish a TLS session with the HTTP server. This example connects - * to the HTTP server as specified in SERVER_HOST and HTTPS_PORT in - * demo_config.h. */ - LogInfo( ( "Establishing a TLS session with %s:%d.", - serverHost, - AWS_HTTPS_PORT ) ); - - opensslStatus = Openssl_Connect( pNetworkContext, - &serverInfo, - &opensslCredentials, - TRANSPORT_SEND_RECV_TIMEOUT_MS, - TRANSPORT_SEND_RECV_TIMEOUT_MS ); - - returnStatus = ( opensslStatus == OPENSSL_SUCCESS ) ? EXIT_SUCCESS : EXIT_FAILURE; - } - - return returnStatus; -} - -/*-----------------------------------------------------------*/ - -static OtaHttpStatus_t handleHttpResponse( const HTTPResponse_t * pResponse ) -{ - /* Return error code. */ - OtaHttpStatus_t ret = OtaHttpRequestFailed; - - OtaEventData_t * pData; - OtaEventMsg_t eventMsg = { 0 }; - - switch( pResponse->statusCode ) - { - case HTTP_RESPONSE_PARTIAL_CONTENT: - /* Get buffer to send event & data. */ - pData = otaEventBufferGet(); - - if( pData != NULL ) - { - /* Get the data from response buffer. */ - memcpy( pData->data, pResponse->pBody, pResponse->bodyLen ); - pData->dataLength = pResponse->bodyLen; - - /* Send job document received event. */ - eventMsg.eventId = OtaAgentEventReceivedFileBlock; - eventMsg.pEventData = pData; - OTA_SignalEvent( &eventMsg ); - - ret = OtaHttpSuccess; - } - else - { - LogError( ( "Error: No OTA data buffers available." ) ); - - ret = OtaHttpRequestFailed; - } - - break; - - case HTTP_RESPONSE_BAD_REQUEST: - case HTTP_RESPONSE_FORBIDDEN: - case HTTP_RESPONSE_NOT_FOUND: - /* Request the job document to get new url. */ - eventMsg.eventId = OtaAgentEventRequestJobDocument; - eventMsg.pEventData = NULL; - OTA_SignalEvent( &eventMsg ); - - ret = OtaHttpSuccess; - break; - - default: - LogError( ( "Unhandled http response code: =%d.", - pResponse->statusCode ) ); - - ret = OtaHttpRequestFailed; - } - - return ret; -} - -static OtaHttpStatus_t httpInit( char * pUrl ) -{ - /* OTA lib return error code. */ - OtaHttpStatus_t ret = OtaHttpSuccess; - - /* HTTPS Client library return status. */ - HTTPStatus_t httpStatus = HTTPSuccess; - - /* Return value from libraries. */ - int32_t returnStatus = EXIT_SUCCESS; - - /* The length of the path within the pre-signed URL. This variable is - * defined in order to store the length returned from parsing the URL, but - * it is unused. The path used for the requests in this demo needs all the - * query information following the location of the object, to the end of the - * S3 presigned URL. */ - size_t pathLen = 0; - - /* Set the pParams member of the network context with desired transport. */ - networkContextHttp.pParams = &opensslParamsForHttp; - - /* Establish HTTPs connection */ - LogInfo( ( "Performing TLS handshake on top of the TCP connection." ) ); - - /* Attempt to connect to the HTTPs server. If connection fails, retry after - * a timeout. Timeout value will be exponentially increased till the maximum - * attempts are reached or maximum timeout value is reached. The function - * returns EXIT_FAILURE if the TCP connection cannot be established to - * broker after configured number of attempts. */ - returnStatus = connectToS3Server( &networkContextHttp, pUrl ); - - if( returnStatus == EXIT_SUCCESS ) - { - /* Define the transport interface. */ - ( void ) memset( &transportInterfaceHttp, 0, sizeof( transportInterfaceHttp ) ); - transportInterfaceHttp.recv = Openssl_Recv; - transportInterfaceHttp.send = Openssl_Send; - transportInterfaceHttp.pNetworkContext = &networkContextHttp; - - /* Retrieve the path location from url. This - * function returns the length of the path without the query into - * pathLen, which is left unused in this demo. */ - httpStatus = getUrlPath( pUrl, - strlen( pUrl ), - &pPath, - &pathLen ); - - ret = ( httpStatus == HTTPSuccess ) ? OtaHttpSuccess : OtaHttpInitFailed; - } - else - { - /* Log an error to indicate connection failure after all - * reconnect attempts are over. */ - LogError( ( "Failed to connect to HTTP server %s.", - serverHost ) ); - - ret = OtaHttpInitFailed; - } - - return ret; -} - -static OtaHttpStatus_t httpRequest( uint32_t rangeStart, - uint32_t rangeEnd ) -{ - /* OTA lib return error code. */ - OtaHttpStatus_t ret = OtaHttpSuccess; - - /* Configurations of the initial request headers that are passed to - * #HTTPClient_InitializeRequestHeaders. */ - HTTPRequestInfo_t requestInfo; - /* Represents a response returned from an HTTP server. */ - HTTPResponse_t response; - /* Represents header data that will be sent in an HTTP request. */ - HTTPRequestHeaders_t requestHeaders; - - /* Return value of all methods from the HTTP Client library API. */ - HTTPStatus_t httpStatus = HTTPSuccess; - - /* Reconnection required flag. */ - bool reconnectRequired = false; - - /* Initialize all HTTP Client library API structs to 0. */ - ( void ) memset( &requestInfo, 0, sizeof( requestInfo ) ); - ( void ) memset( &response, 0, sizeof( response ) ); - ( void ) memset( &requestHeaders, 0, sizeof( requestHeaders ) ); - - /* Initialize the request object. */ - requestInfo.pHost = serverHost; - requestInfo.hostLen = serverHostLength; - requestInfo.pMethod = HTTP_METHOD_GET; - requestInfo.methodLen = sizeof( HTTP_METHOD_GET ) - 1; - requestInfo.pPath = pPath; - requestInfo.pathLen = strlen( pPath ); - - /* Set "Connection" HTTP header to "keep-alive" so that multiple requests - * can be sent over the same established TCP connection. */ - requestInfo.reqFlags = HTTP_REQUEST_KEEP_ALIVE_FLAG; - - /* Set the buffer used for storing request headers. */ - requestHeaders.pBuffer = httpUserBuffer; - requestHeaders.bufferLen = HTTP_USER_BUFFER_LENGTH; - - httpStatus = HTTPClient_InitializeRequestHeaders( &requestHeaders, - &requestInfo ); - - HTTPClient_AddRangeHeader( &requestHeaders, rangeStart, rangeEnd ); - - if( httpStatus == HTTPSuccess ) - { - /* Initialize the response object. The same buffer used for storing - * request headers is reused here. */ - response.pBuffer = httpUserBuffer; - response.bufferLen = HTTP_USER_BUFFER_LENGTH; - - /* Send the request and receive the response. */ - httpStatus = HTTPClient_Send( &transportInterfaceHttp, - &requestHeaders, - NULL, - 0, - &response, - 0 ); - } - else - { - LogError( ( "Failed to initialize HTTP request headers: Error=%s.", - HTTPClient_strerror( httpStatus ) ) ); - } - - if( httpStatus != HTTPSuccess ) - { - if( ( httpStatus == HTTPNoResponse ) || ( httpStatus == HTTPNetworkError ) ) - { - reconnectRequired = true; - } - else - { - LogError( ( "HTTPClient_Send failed: Error=%s.", - HTTPClient_strerror( httpStatus ) ) ); - - ret = OtaHttpRequestFailed; - } - } - else - { - /* Check if reconnection required. */ - if( response.respFlags & HTTP_RESPONSE_CONNECTION_CLOSE_FLAG ) - { - reconnectRequired = true; - } - - /* Handle the http response received. */ - ret = handleHttpResponse( &response ); - } - - if( reconnectRequired == true ) - { - /* End TLS session, then close TCP connection. */ - ( void ) Openssl_Disconnect( &networkContextHttp ); - - /* Try establishing connection to S3 server again. */ - if( connectToS3Server( &networkContextHttp, NULL ) == EXIT_SUCCESS ) - { - ret = OtaHttpSuccess; - } - else - { - /* Log an error to indicate connection failure after all - * reconnect attempts are over. */ - LogError( ( "Failed to connect to HTTP server %s.", - serverHost ) ); - - ret = OtaHttpRequestFailed; - } - } - - return ret; -} - -static OtaHttpStatus_t httpDeinit( void ) -{ - OtaHttpStatus_t ret = OtaHttpSuccess; - - /* Nothing special to do here .*/ - - return ret; -} - - -/*-----------------------------------------------------------*/ - -static void registerSubscriptionManagerCallback( const char * pTopicFilter, - uint16_t topicFilterLength ) -{ - bool isMatch = false; - MQTTStatus_t mqttStatus = MQTTSuccess; - SubscriptionManagerStatus_t subscriptionStatus = SUBSCRIPTION_MANAGER_SUCCESS; - - uint16_t index = 0U; - - /* For suppressing compiler-warning: unused variable. */ - ( void ) mqttStatus; - - /* Lookup table for OTA message string. */ - static const char * const pWildCardTopicFilters[] = - { - OTA_TOPIC_PREFIX OTA_TOPIC_JOBS "/#", - OTA_TOPIC_PREFIX OTA_TOPIC_STREAM "/#" - }; - - /* Match the input topic filter against the wild-card pattern of topics filters - * relevant for the OTA Update service to determine the type of topic filter. */ - for( ; index < 2; index++ ) - { - mqttStatus = MQTT_MatchTopic( pTopicFilter, - topicFilterLength, - pWildCardTopicFilters[ index ], - strlen( pWildCardTopicFilters[ index ] ), - &isMatch ); - assert( mqttStatus == MQTTSuccess ); - - if( isMatch ) - { - /* Register callback to subscription manager. */ - subscriptionStatus = SubscriptionManager_RegisterCallback( pWildCardTopicFilters[ index ], - strlen( pWildCardTopicFilters[ index ] ), - otaMessageCallback[ index ] ); - - if( subscriptionStatus != SUBSCRIPTION_MANAGER_SUCCESS ) - { - LogWarn( ( "Failed to register a callback to subscription manager with error = %d.", - subscriptionStatus ) ); - } - - break; - } - } -} - - - -/*-----------------------------------------------------------*/ - -static OtaMqttStatus_t mqttSubscribe( const char * pTopicFilter, - uint16_t topicFilterLength, - uint8_t qos ) -{ - OtaMqttStatus_t otaRet = OtaMqttSuccess; - - MQTTStatus_t mqttStatus = MQTTBadParameter; - MQTTContext_t * pMqttContext = &mqttContext; - MQTTSubscribeInfo_t pSubscriptionList[ 1 ]; - - assert( pMqttContext != NULL ); - assert( pTopicFilter != NULL ); - assert( topicFilterLength > 0 ); - - ( void ) qos; - - /* Start with everything at 0. */ - ( void ) memset( ( void * ) pSubscriptionList, 0x00, sizeof( pSubscriptionList ) ); - - /* Set the topic and topic length. */ - pSubscriptionList[ 0 ].pTopicFilter = pTopicFilter; - pSubscriptionList[ 0 ].topicFilterLength = topicFilterLength; - - if( pthread_mutex_lock( &mqttMutex ) == 0 ) - { - /* Send SUBSCRIBE packet. */ - mqttStatus = MQTT_Subscribe( pMqttContext, - pSubscriptionList, - sizeof( pSubscriptionList ) / sizeof( MQTTSubscribeInfo_t ), - MQTT_GetPacketId( pMqttContext ) ); - - pthread_mutex_unlock( &mqttMutex ); - } - else - { - LogError( ( "Failed to acquire mqtt mutex for executing MQTT_Subscribe" - ",errno=%s", - strerror( errno ) ) ); - } - - if( mqttStatus != MQTTSuccess ) - { - LogError( ( "Failed to send SUBSCRIBE packet to broker with error = %u.", - mqttStatus ) ); - - otaRet = OtaMqttSubscribeFailed; - } - else - { - LogInfo( ( "SUBSCRIBE topic %.*s to broker.\n\n", - topicFilterLength, - pTopicFilter ) ); - - registerSubscriptionManagerCallback( pTopicFilter, topicFilterLength ); - } - - return otaRet; -} - -static OtaMqttStatus_t mqttPublish( const char * const pTopic, - uint16_t topicLen, - const char * pMsg, - uint32_t msgSize, - uint8_t qos ) -{ - OtaMqttStatus_t otaRet = OtaMqttSuccess; - - MQTTStatus_t mqttStatus = MQTTBadParameter; - MQTTPublishInfo_t publishInfo = { 0 }; - MQTTContext_t * pMqttContext = &mqttContext; - struct timespec ts = { 0 }; - int ret; - - /* Set the required publish parameters. */ - publishInfo.pTopicName = pTopic; - publishInfo.topicNameLength = topicLen; - publishInfo.qos = qos; - publishInfo.pPayload = pMsg; - publishInfo.payloadLength = msgSize; - - if( pthread_mutex_lock( &mqttMutex ) == 0 ) - { - mqttStatus = MQTT_Publish( pMqttContext, - &publishInfo, - MQTT_GetPacketId( pMqttContext ) ); - - if( mqttStatus != MQTTSuccess ) - { - LogError( ( "Failed to send PUBLISH packet to broker with error = %u.", mqttStatus ) ); - - otaRet = OtaMqttPublishFailed; - } - - pthread_mutex_unlock( &mqttMutex ); - } - else - { - LogError( ( "Failed to acquire mqtt mutex for executing MQTT_Publish" - ",errno=%s", - strerror( errno ) ) ); - - otaRet = OtaMqttPublishFailed; - } - - if( ( mqttStatus == MQTTSuccess ) && ( qos == 1 ) ) - { - /* Calculate relative interval as current time plus number of seconds. */ - clock_gettime( CLOCK_REALTIME, &ts ); - ts.tv_sec += MQTT_ACK_TIMEOUT_MS; - - while( ( ret = sem_timedwait( &ackSemaphore, &ts ) ) == -1 && errno == EINTR ) - { - continue; - } - - if( ret == -1 ) - { - LogError( ( "Failed to receive ack for publish." - ",errno=%s", - strerror( errno ) ) ); - - otaRet = OtaMqttPublishFailed; - } - } - - return otaRet; -} - -/*-----------------------------------------------------------*/ - -static OtaMqttStatus_t mqttUnsubscribe( const char * pTopicFilter, - uint16_t topicFilterLength, - uint8_t qos ) -{ - OtaMqttStatus_t otaRet = OtaMqttSuccess; - MQTTStatus_t mqttStatus = MQTTBadParameter; - - MQTTSubscribeInfo_t pSubscriptionList[ 1 ]; - MQTTContext_t * pMqttContext = &mqttContext; - - ( void ) qos; - - /* Start with everything at 0. */ - ( void ) memset( ( void * ) pSubscriptionList, 0x00, sizeof( pSubscriptionList ) ); - - /* Set the QoS , topic and topic length. */ - pSubscriptionList[ 0 ].qos = qos; - pSubscriptionList[ 0 ].pTopicFilter = pTopicFilter; - pSubscriptionList[ 0 ].topicFilterLength = topicFilterLength; - - if( pthread_mutex_lock( &mqttMutex ) == 0 ) - { - /* Send UNSUBSCRIBE packet. */ - mqttStatus = MQTT_Unsubscribe( pMqttContext, - pSubscriptionList, - sizeof( pSubscriptionList ) / sizeof( MQTTSubscribeInfo_t ), - MQTT_GetPacketId( pMqttContext ) ); - - pthread_mutex_unlock( &mqttMutex ); - } - else - { - LogError( ( "Failed to acquire mutex for executing MQTT_Unsubscribe" - ",errno=%s", - strerror( errno ) ) ); - } - - if( mqttStatus != MQTTSuccess ) - { - LogError( ( "Failed to send UNSUBSCRIBE packet to broker with error = %u.", - mqttStatus ) ); - - otaRet = OtaMqttUnsubscribeFailed; - } - else - { - LogInfo( ( "UNSUBSCRIBE topic %.*s to broker.\n\n", - topicFilterLength, - pTopicFilter ) ); - } - - return otaRet; -} - -/*-----------------------------------------------------------*/ - -static void setOtaInterfaces( OtaInterfaces_t * pOtaInterfaces ) -{ - /* Initialize OTA library OS Interface. */ - pOtaInterfaces->os.event.init = Posix_OtaInitEvent; - pOtaInterfaces->os.event.send = Posix_OtaSendEvent; - pOtaInterfaces->os.event.recv = Posix_OtaReceiveEvent; - pOtaInterfaces->os.event.deinit = Posix_OtaDeinitEvent; - pOtaInterfaces->os.timer.start = Posix_OtaStartTimer; - pOtaInterfaces->os.timer.stop = Posix_OtaStopTimer; - pOtaInterfaces->os.timer.delete = Posix_OtaDeleteTimer; - pOtaInterfaces->os.mem.malloc = STDC_Malloc; - pOtaInterfaces->os.mem.free = STDC_Free; - - /* Initialize the OTA library MQTT Interface.*/ - pOtaInterfaces->mqtt.subscribe = mqttSubscribe; - pOtaInterfaces->mqtt.publish = mqttPublish; - pOtaInterfaces->mqtt.unsubscribe = mqttUnsubscribe; - - /* Initialize the OTA library HTTP Interface.*/ - pOtaInterfaces->http.init = httpInit; - pOtaInterfaces->http.request = httpRequest; - pOtaInterfaces->http.deinit = httpDeinit; - - /* Initialize the OTA library PAL Interface.*/ - pOtaInterfaces->pal.getPlatformImageState = otaPal_GetPlatformImageState; - pOtaInterfaces->pal.setPlatformImageState = otaPal_SetPlatformImageState; - pOtaInterfaces->pal.writeBlock = otaPal_WriteBlock; - pOtaInterfaces->pal.activate = otaPal_ActivateNewImage; - pOtaInterfaces->pal.closeFile = otaPal_CloseFile; - pOtaInterfaces->pal.reset = otaPal_ResetDevice; - pOtaInterfaces->pal.abort = otaPal_Abort; - pOtaInterfaces->pal.createFile = otaPal_CreateFileForRx; -} - -/*-----------------------------------------------------------*/ - -static void * otaThread( void * pParam ) -{ - /* Calling OTA agent task. */ - OTA_EventProcessingTask( pParam ); - LogInfo( ( "OTA Agent stopped." ) ); - return NULL; -} - -/*-----------------------------------------------------------*/ -static int startOTADemo( void ) -{ - /* Status indicating a successful demo or not. */ - int returnStatus = EXIT_SUCCESS; - - /* coreMQTT library return status. */ - MQTTStatus_t mqttStatus = MQTTBadParameter; - - /* OTA library return status. */ - OtaErr_t otaRet = OtaErrNone; - - /* OTA Agent state returned from calling OTA_GetState.*/ - OtaState_t state = OtaAgentStateStopped; - - /* OTA event message used for sending event to OTA Agent.*/ - OtaEventMsg_t eventMsg = { 0 }; - - /* OTA library packet statistics per job.*/ - OtaAgentStatistics_t otaStatistics = { 0 }; - - /* OTA Agent thread handle.*/ - pthread_t threadHandle; - - /* Status return from call to pthread_join. */ - int returnJoin = 0; - - /* OTA interface context required for library interface functions.*/ - OtaInterfaces_t otaInterfaces; - - /* Maximum time to wait for the OTA agent to get suspended. */ - int16_t suspendTimeout; - - /* Set OTA Library interfaces.*/ - setOtaInterfaces( &otaInterfaces ); - - /****************************** Init OTA Library. ******************************/ - - if( returnStatus == EXIT_SUCCESS ) - { - if( ( otaRet = OTA_Init( &otaBuffer, - &otaInterfaces, - ( const uint8_t * ) ( CLIENT_IDENTIFIER ), - otaAppCallback ) ) != OtaErrNone ) - { - LogError( ( "Failed to initialize OTA Agent, exiting = %u.", - otaRet ) ); - - returnStatus = EXIT_FAILURE; - } - } - - /****************************** Create OTA Task. ******************************/ - - if( returnStatus == EXIT_SUCCESS ) - { - if( pthread_create( &threadHandle, NULL, otaThread, NULL ) != 0 ) - { - LogError( ( "Failed to create OTA thread: " - ",errno=%s", - strerror( errno ) ) ); - - returnStatus = EXIT_FAILURE; - } - } - - /****************************** OTA Demo loop. ******************************/ - - if( returnStatus == EXIT_SUCCESS ) - { - /* Wait till OTA library is stopped, output statistics for currently running - * OTA job */ - while( ( ( state = OTA_GetState() ) != OtaAgentStateStopped ) ) - { - if( mqttSessionEstablished != true ) - { - /* Connect to MQTT broker and create MQTT connection. */ - if( EXIT_SUCCESS == establishConnection() ) - { - mqttSessionEstablished = true; - - /* Check if OTA process was suspended and resume if required. */ - if( state == OtaAgentStateSuspended ) - { - /* Resume OTA operations. */ - OTA_Resume(); - } - else - { - /* Send start event to OTA Agent.*/ - eventMsg.eventId = OtaAgentEventStart; - OTA_SignalEvent( &eventMsg ); - } - } - } - - if( mqttSessionEstablished == true ) - { - /* Acquire the mqtt mutex lock. */ - if( pthread_mutex_lock( &mqttMutex ) == 0 ) - { - /* Loop to receive packet from transport interface. */ - mqttStatus = MQTT_ProcessLoop( &mqttContext ); - - pthread_mutex_unlock( &mqttMutex ); - } - else - { - LogError( ( "Failed to acquire mutex to execute process loop" - ",errno=%s", - strerror( errno ) ) ); - } - - if( ( mqttStatus == MQTTSuccess ) || ( mqttStatus == MQTTNeedMoreBytes ) ) - { - /* Get OTA statistics for currently executing job. */ - OTA_GetStatistics( &otaStatistics ); - - LogInfo( ( " Received: %u Queued: %u Processed: %u Dropped: %u", - otaStatistics.otaPacketsReceived, - otaStatistics.otaPacketsQueued, - otaStatistics.otaPacketsProcessed, - otaStatistics.otaPacketsDropped ) ); - - Clock_SleepMs( OTA_EXAMPLE_LOOP_SLEEP_PERIOD_MS ); - } - else - { - LogError( ( "MQTT_ProcessLoop returned with status = %s.", - MQTT_Status_strerror( mqttStatus ) ) ); - - /* Disconnect from broker and close connection. */ - disconnect(); - - /* Set connection flag to false. */ - mqttSessionEstablished = false; - - /* Suspend OTA operations. */ - otaRet = OTA_Suspend(); - - if( otaRet != OtaErrNone ) - { - LogError( ( "OTA failed to suspend. " - "StatusCode=%d.", otaRet ) ); - } - else - { - suspendTimeout = OTA_SUSPEND_TIMEOUT_MS; - - while( ( ( state = OTA_GetState() ) != OtaAgentStateSuspended ) && ( suspendTimeout > 0 ) ) - { - /* Wait for OTA Library state to suspend */ - Clock_SleepMs( OTA_EXAMPLE_TASK_DELAY_MS ); - suspendTimeout -= OTA_EXAMPLE_TASK_DELAY_MS; - } - } - } - } - } - } - - /****************************** Wait for OTA Thread. ******************************/ - - if( returnStatus == EXIT_SUCCESS ) - { - returnJoin = pthread_join( threadHandle, NULL ); - - if( returnJoin != 0 ) - { - LogError( ( "Failed to join thread" - ",error code = %d", - returnJoin ) ); - - returnStatus = EXIT_FAILURE; - } - } - - return returnStatus; -} - -/*-----------------------------------------------------------*/ - -/** - * @brief Entry point of demo. - * - * This example initializes the OTA library to enable OTA updates via the - * MQTT broker. It simply connects to the MQTT broker with the users - * credentials and spins in an indefinite loop to allow MQTT messages to be - * forwarded to the OTA agent for possible processing. The OTA agent does all - * of the real work; checking to see if the message topic is one destined for - * the OTA agent. If not, it is simply ignored. - */ -int main( int argc, - char ** argv ) -{ - ( void ) argc; - ( void ) argv; - - /* Return error status. */ - int returnStatus = EXIT_SUCCESS; - - /* Semaphore initialization flag. */ - bool bufferSemInitialized = false; - bool ackSemInitialized = false; - bool mqttMutexInitialized = false; - - /* Maximum time in milliseconds to wait before exiting demo . */ - int16_t waitTimeoutMs = OTA_DEMO_EXIT_TIMEOUT_MS; - - LogInfo( ( "OTA over HTTP demo, Application version %u.%u.%u", - appFirmwareVersion.u.x.major, - appFirmwareVersion.u.x.minor, - appFirmwareVersion.u.x.build ) ); - - /* Initialize semaphore for buffer operations. */ - if( sem_init( &bufferSemaphore, 0, 1 ) != 0 ) - { - LogError( ( "Failed to initialize buffer semaphore" - ",errno=%s", - strerror( errno ) ) ); - - returnStatus = EXIT_FAILURE; - } - else - { - bufferSemInitialized = true; - } - - /* Initialize semaphore for ack. */ - if( sem_init( &ackSemaphore, 0, 0 ) != 0 ) - { - LogError( ( "Failed to initialize ack semaphore" - ",errno=%s", - strerror( errno ) ) ); - - returnStatus = EXIT_FAILURE; - } - else - { - ackSemInitialized = true; - } - - /* Initialize mutex for coreMQTT APIs. */ - if( pthread_mutex_init( &mqttMutex, NULL ) != 0 ) - { - LogError( ( "Failed to initialize mutex for mqtt apis" - ",errno=%s", - strerror( errno ) ) ); - - returnStatus = EXIT_FAILURE; - } - else - { - mqttMutexInitialized = true; - } - - if( returnStatus == EXIT_SUCCESS ) - { - /* Initialize MQTT library. Initialization of the MQTT library needs to be - * done only once in this demo. */ - returnStatus = initializeMqtt( &mqttContext, &networkContextMqtt ); - } - - if( returnStatus == EXIT_SUCCESS ) - { - /* Start OTA demo. */ - returnStatus = startOTADemo(); - } - - /* Disconnect from broker and close connection. */ - disconnect(); - - /* Disconnect from S3 and close connection. */ - Openssl_Disconnect( &networkContextHttp ); - - if( bufferSemInitialized == true ) - { - /* Cleanup semaphore created for buffer operations. */ - if( sem_destroy( &bufferSemaphore ) != 0 ) - { - LogError( ( "Failed to destroy buffer semaphore" - ",errno=%s", - strerror( errno ) ) ); - - returnStatus = EXIT_FAILURE; - } - } - - if( ackSemInitialized == true ) - { - /* Cleanup semaphore created for ack. */ - if( sem_destroy( &ackSemaphore ) != 0 ) - { - LogError( ( "Failed to destroy ack semaphore" - ",errno=%s", - strerror( errno ) ) ); - - returnStatus = EXIT_FAILURE; - } - } - - if( mqttMutexInitialized == true ) - { - /* Cleanup mutex created for buffer operations. */ - if( pthread_mutex_destroy( &mqttMutex ) != 0 ) - { - LogError( ( "Failed to destroy mutex for mqtt apis" - ",errno=%s", - strerror( errno ) ) ); - - returnStatus = EXIT_FAILURE; - } - } - - /* Wait and log message before exiting demo. */ - while( waitTimeoutMs > 0 ) - { - Clock_SleepMs( OTA_EXAMPLE_TASK_DELAY_MS ); - waitTimeoutMs -= OTA_EXAMPLE_TASK_DELAY_MS; - - LogError( ( "Exiting demo in %d sec", waitTimeoutMs / 1000 ) ); - } - - return returnStatus; -} diff --git a/demos/ota/ota_demo_core_mqtt/CMakeLists.txt b/demos/ota/ota_demo_core_mqtt/CMakeLists.txt deleted file mode 100644 index e0df7ed4da..0000000000 --- a/demos/ota/ota_demo_core_mqtt/CMakeLists.txt +++ /dev/null @@ -1,61 +0,0 @@ -set( DEMO_NAME "ota_demo_core_mqtt" ) - -# Include required library's source and header path variables. -include( ${ROOT_DIR}/libraries/aws/ota-for-aws-iot-embedded-sdk/otaFilePaths.cmake ) -include( ${ROOT_DIR}/libraries/standard/coreMQTT/mqttFilePaths.cmake ) - -# Include backoffAlgorithm library file path configuration. -include( ${ROOT_DIR}/libraries/standard/backoffAlgorithm/backoffAlgorithmFilePaths.cmake ) - -# Demo target. -add_executable( - ${DEMO_NAME} - "${DEMO_NAME}.c" - "${DEMOS_DIR}/ota/common/src/mqtt_subscription_manager.c" - ${OTA_SOURCES} - ${OTA_OS_POSIX_SOURCES} - ${OTA_MQTT_SOURCES} - ${MQTT_SOURCES} - ${MQTT_SERIALIZER_SOURCES} - ${BACKOFF_ALGORITHM_SOURCES} -) - -target_link_libraries( - ${DEMO_NAME} - PRIVATE - ${LIB_RT} - ota_pal - Threads::Threads - clock_posix - openssl_posix - aws_iot_json - tinycbor -) - -target_include_directories( - ${DEMO_NAME} - PUBLIC - "${DEMOS_DIR}/ota/common/include" - "${CMAKE_CURRENT_LIST_DIR}" - "${LOGGING_INCLUDE_DIRS}" - ${BACKOFF_ALGORITHM_INCLUDE_PUBLIC_DIRS} - ${OTA_INCLUDE_PUBLIC_DIRS} - ${OTA_INCLUDE_PRIVATE_DIRS} - ${OTA_INCLUDE_OS_POSIX_DIRS} - ${MQTT_INCLUDE_PUBLIC_DIRS} - ${AWS_DEMO_INCLUDE_DIRS} -) - -set_macro_definitions(TARGETS ${DEMO_NAME} - REQUIRED - "AWS_IOT_ENDPOINT" - "ROOT_CA_CERT_PATH" - "CLIENT_CERT_PATH" - "CLIENT_PRIVATE_KEY_PATH" - "CLIENT_IDENTIFIER" - OPTIONAL - "CLIENT_USERNAME" - "CLIENT_PASSWORD" - "OS_NAME" - "OS_VERSION" - "HARDWARE_PLATFORM_NAME") diff --git a/demos/ota/ota_demo_core_mqtt/core_mqtt_config.h b/demos/ota/ota_demo_core_mqtt/core_mqtt_config.h deleted file mode 100644 index 3e84572ab5..0000000000 --- a/demos/ota/ota_demo_core_mqtt/core_mqtt_config.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * AWS IoT Device SDK for Embedded C 202211.00 - * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef CORE_MQTT_CONFIG_H_ -#define CORE_MQTT_CONFIG_H_ - -/**************************************************/ -/******* DO NOT CHANGE the following order ********/ -/**************************************************/ - -/* Include logging header files and define logging macros in the following order: - * 1. Include the header file "logging_levels.h". - * 2. Define the LIBRARY_LOG_NAME and LIBRARY_LOG_LEVEL macros depending on - * the logging configuration for MQTT. - * 3. Include the header file "logging_stack.h", if logging is enabled for MQTT. - */ - -#include "logging_levels.h" - -/* Logging configuration for the MQTT library. */ -#ifndef LIBRARY_LOG_NAME - #define LIBRARY_LOG_NAME "MQTT" -#endif - -#ifndef LIBRARY_LOG_LEVEL - #define LIBRARY_LOG_LEVEL LOG_INFO -#endif - -#include "logging_stack.h" - -/************ End of logging configuration ****************/ - -/** - * @brief Determines the maximum number of MQTT PUBLISH messages, pending - * acknowledgement at a time, that are supported for incoming and outgoing - * direction of messages, separately. - * - * QoS 1 and 2 MQTT PUBLISHes require acknowledgement from the server before - * they can be completed. While they are awaiting the acknowledgement, the - * client must maintain information about their state. The value of this - * macro sets the limit on how many simultaneous PUBLISH states an MQTT - * context maintains, separately, for both incoming and outgoing direction of - * PUBLISHes. - * - * @note The MQTT context maintains separate state records for outgoing - * and incoming PUBLISHes, and thus, 2 * MQTT_STATE_ARRAY_MAX_COUNT amount - * of memory is statically allocated for the state records. - */ -#define MQTT_STATE_ARRAY_MAX_COUNT 10U - -/** - * @brief Number of milliseconds to wait for a ping response to a ping - * request as part of the keep-alive mechanism. - * - * If a ping response is not received before this timeout, then - * #MQTT_ProcessLoop will return #MQTTKeepAliveTimeout. - */ -#define MQTT_PINGRESP_TIMEOUT_MS ( 5000U ) - - -#endif /* ifndef CORE_MQTT_CONFIG_H_ */ diff --git a/demos/ota/ota_demo_core_mqtt/demo_config.h b/demos/ota/ota_demo_core_mqtt/demo_config.h deleted file mode 100644 index 073f968100..0000000000 --- a/demos/ota/ota_demo_core_mqtt/demo_config.h +++ /dev/null @@ -1,159 +0,0 @@ -/* - * AWS IoT Device SDK for Embedded C 202211.00 - * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef DEMO_CONFIG_H_ -#define DEMO_CONFIG_H_ - -/**************************************************/ -/******* DO NOT CHANGE the following order ********/ -/**************************************************/ - -/* Logging related header files are required to be included in the following order: - * 1. Include the header file "logging_levels.h". - * 2. Define LIBRARY_LOG_NAME and LIBRARY_LOG_LEVEL. - * 3. Include the header file "logging_stack.h". - */ - -/* Include header that defines log levels. */ -#include "logging_levels.h" - -/* Logging configuration for the Demo. */ -#ifndef LIBRARY_LOG_NAME - #define LIBRARY_LOG_NAME "DEMO" -#endif -#ifndef LIBRARY_LOG_LEVEL - #define LIBRARY_LOG_LEVEL LOG_INFO -#endif - -#include "logging_stack.h" - -/************ End of logging configuration ****************/ - -/** - * @brief Details of the MQTT broker to connect to. - * - * @note Your AWS IoT Core endpoint can be found in the AWS IoT console under - * Settings/Custom Endpoint, or using the describe-endpoint API. - * - * #define AWS_IOT_ENDPOINT "...insert here..." - */ - -/** - * @brief AWS IoT MQTT broker port number. - * - * In general, port 8883 is for secured MQTT connections. - * - * @note Port 443 requires use of the ALPN TLS extension with the ALPN protocol - * name. When using port 8883, ALPN is not required. - */ -#define AWS_MQTT_PORT ( 8883 ) - - - -/** - * @brief Path of the file containing the server's root CA certificate. - * - * This certificate is used to identify the AWS IoT server and is publicly - * available. Refer to the AWS documentation available in the link below - * https://docs.aws.amazon.com/iot/latest/developerguide/server-authentication.html#server-authentication-certs - * - * Amazon's root CA certificate is automatically downloaded to the certificates - * directory from @ref https://www.amazontrust.com/repository/AmazonRootCA1.pem - * using the CMake build system. - * - * @note This certificate should be PEM-encoded. - * @note This path is relative from the demo binary created. Update - * ROOT_CA_CERT_PATH to the absolute path if this demo is executed from elsewhere. - */ -#ifndef ROOT_CA_CERT_PATH - #define ROOT_CA_CERT_PATH "certificates/AmazonRootCA1.crt" -#endif - -/** - * @brief Path of the file containing the client certificate. - * - * Refer to the AWS documentation below for details regarding client - * authentication. - * https://docs.aws.amazon.com/iot/latest/developerguide/client-authentication.html - * - * @note This certificate should be PEM-encoded. - * - * #define CLIENT_CERT_PATH "...insert here..." - */ - -/** - * @brief Path of the file containing the client's private key. - * - * Refer to the AWS documentation below for details regarding client - * authentication. - * https://docs.aws.amazon.com/iot/latest/developerguide/client-authentication.html - * - * @note This private key should be PEM-encoded. - * - * #define CLIENT_PRIVATE_KEY_PATH "...insert here..." - */ - -/** - * @brief MQTT client identifier. - * - * No two clients may use the same client identifier simultaneously. - */ -#ifndef CLIENT_IDENTIFIER - #define CLIENT_IDENTIFIER "testclient" -#endif - -/** - * @brief Configure application version. - */ - -#define APP_VERSION_MAJOR 0 -#define APP_VERSION_MINOR 9 -#define APP_VERSION_BUILD 2 - -/** - * @brief The name of the operating system that the application is running on. - * The current value is given as an example. Please update for your specific - * operating system. - */ -#define OS_NAME "Ubuntu" - -/** - * @brief The version of the operating system that the application is running - * on. The current value is given as an example. Please update for your specific - * operating system version. - */ -#define OS_VERSION "18.04 LTS" - -/** - * @brief The name of the hardware platform the application is running on. The - * current value is given as an example. Please update for your specific - * hardware platform. - */ -#define HARDWARE_PLATFORM_NAME "PC" - -/** - * @brief The name of the library used and its version, following an "@" - * symbol. - */ -#define OTA_LIB "otalib@1.0.0" - -#endif /* ifndef DEMO_CONFIG_H */ diff --git a/demos/ota/ota_demo_core_mqtt/ota_config.h b/demos/ota/ota_demo_core_mqtt/ota_config.h deleted file mode 100644 index b1a3b5db59..0000000000 --- a/demos/ota/ota_demo_core_mqtt/ota_config.h +++ /dev/null @@ -1,186 +0,0 @@ -/* - * AWS IoT Device SDK for Embedded C 202211.00 - * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/** - * @file ota_config.h - * @brief OTA user configurable settings. - */ - -#ifndef OTA_CONFIG_H_ -#define OTA_CONFIG_H_ - -/**************************************************/ -/******* DO NOT CHANGE the following order ********/ -/**************************************************/ - -/* Logging related header files are required to be included in the following order: - * 1. Include the header file "logging_levels.h". - * 2. Define LIBRARY_LOG_NAME and LIBRARY_LOG_LEVEL. - * 3. Include the header file "logging_stack.h". - */ - -/* Include header that defines log levels. */ -#include "logging_levels.h" - -/* Configure name and log level for the OTA library. */ -#ifndef LIBRARY_LOG_NAME - #define LIBRARY_LOG_NAME "OTA" -#endif -#ifndef LIBRARY_LOG_LEVEL - #define LIBRARY_LOG_LEVEL LOG_INFO -#endif - -#include "logging_stack.h" - -/************ End of logging configuration ****************/ - -/** - * @brief Log base 2 of the size of the file data block message (excluding the header). - * - * 10 bits yields a data block size of 1KB. - */ -#define otaconfigLOG2_FILE_BLOCK_SIZE 12UL - - -/** - * @brief Size of the file data block message (excluding the header). - * - */ -#define otaconfigFILE_BLOCK_SIZE ( 1UL << otaconfigLOG2_FILE_BLOCK_SIZE ) - -/** - * @brief Milliseconds to wait for the self test phase to succeed before we force reset. - */ -#define otaconfigSELF_TEST_RESPONSE_WAIT_MS 16000U - -/** - * @brief Milliseconds to wait before requesting data blocks from the OTA service if nothing is happening. - * - * The wait timer is reset whenever a data block is received from the OTA service so we will only send - * the request message after being idle for this amount of time. - */ -#define otaconfigFILE_REQUEST_WAIT_MS 10000U - -/** - * @brief The maximum allowed length of the thing name used by the OTA agent. - * - * AWS IoT requires Thing names to be unique for each device that connects to the broker. - * Likewise, the OTA agent requires the developer to construct and pass in the Thing name when - * initializing the OTA agent. The agent uses this size to allocate static storage for the - * Thing name used in all OTA base topics. Namely $aws/things/ - */ -#define otaconfigMAX_THINGNAME_LEN 64U - -/** - * @brief The maximum number of data blocks requested from OTA streaming service. - * - * This configuration parameter is sent with data requests and represents the maximum number of - * data blocks the service will send in response. The maximum limit for this must be calculated - * from the maximum data response limit (128 KB from service) divided by the block size. - * For example if block size is set as 1 KB then the maximum number of data blocks that we can - * request is 128/1 = 128 blocks. Configure this parameter to this maximum limit or lower based on - * how many data blocks response is expected for each data requests. - * @note This must be set larger than zero. - * - */ -#define otaconfigMAX_NUM_BLOCKS_REQUEST 8U - -/** - * @brief The maximum number of requests allowed to send without a response before we abort. - * - * This configuration parameter sets the maximum number of times the requests are made over - * the selected communication channel before aborting and returning error. - * - */ -#define otaconfigMAX_NUM_REQUEST_MOMENTUM 32U - -/** - * @brief The number of data buffers reserved by the OTA agent. - * - * This configurations parameter sets the maximum number of static data buffers used by - * the OTA agent for job and file data blocks received. - */ -#define otaconfigMAX_NUM_OTA_DATA_BUFFERS 10U - -/** - * @brief How frequently the device will report its OTA progress to the cloud. - * - * Device will update the job status with the number of blocks it has received every certain - * number of blocks it receives. For example, 25 means device will update job status every 25 blocks - * it receives. - */ -#define otaconfigOTA_UPDATE_STATUS_FREQUENCY 25U - -/** - * @brief Allow update to same or lower version. - * - * Set this to 1 to allow downgrade or same version update. This configurations parameter - * disables version check and allows update to a same or lower version. This is provided for - * testing purpose and it is recommended to always update to higher version and keep this - * configuration disabled. - */ -#define otaconfigAllowDowngrade 0U - -/** - * @brief The protocol selected for OTA control operations. - * - * This configurations parameter sets the default protocol for all the OTA control - * operations like requesting OTA job, updating the job status etc. - * - * Note - Only MQTT is supported at this time for control operations. - */ -#define configENABLED_CONTROL_PROTOCOL ( OTA_CONTROL_OVER_MQTT ) - -/** - * @brief The protocol selected for OTA data operations. - * - * This configurations parameter sets the protocols selected for the data operations - * like requesting file blocks from the service. - * - * Note - Both MQTT and HTTP is supported for data transfer. This configuration parameter - * can be set to following - - * Enable data over MQTT - ( OTA_DATA_OVER_MQTT ) - * Enable data over HTTP - ( OTA_DATA_OVER_HTTP) - * Enable data over both MQTT & HTTP ( OTA_DATA_OVER_MQTT | OTA_DATA_OVER_HTTP ) - */ -#define configENABLED_DATA_PROTOCOLS ( OTA_DATA_OVER_MQTT ) - -/** - * @brief The preferred protocol selected for OTA data operations. - * - * Primary data protocol will be the protocol used for downloading file if more than - * one protocol is selected while creating OTA job. Default primary data protocol is MQTT - * and following update here to switch to HTTP as primary. - * - * Note - use OTA_DATA_OVER_HTTP for HTTP as primary data protocol. - */ -#define configOTA_PRIMARY_DATA_PROTOCOL ( OTA_DATA_OVER_MQTT ) - -/** - * @brief Data type to represent a file. - * - * It is used to represent a file received via OTA. The file is declared as - * the pointer of this type: otaconfigOTA_FILE_TYPE * pFile. - */ -#define otaconfigOTA_FILE_TYPE FILE - -#endif /* OTA_CONFIG_H_ */ diff --git a/demos/ota/ota_demo_core_mqtt/ota_demo_core_mqtt.c b/demos/ota/ota_demo_core_mqtt/ota_demo_core_mqtt.c deleted file mode 100644 index 50fd0a19bb..0000000000 --- a/demos/ota/ota_demo_core_mqtt/ota_demo_core_mqtt.c +++ /dev/null @@ -1,1813 +0,0 @@ -/* - * AWS IoT Device SDK for Embedded C 202211.00 - * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/** - * @file ota_demo_core_mqtt.c - * @brief OTA update example using coreMQTT. - */ - -/* Standard includes. */ -#include -#include -#include -#include - -/* Include Demo Config as the first non-system header. */ -#include "demo_config.h" - -/* OpenSSL sockets transport implementation. */ -#include "openssl_posix.h" - -/* Clock for timer. */ -#include "clock.h" - -/* pthread include. */ -#include -#include - -/* MQTT include. */ -#include "core_mqtt.h" -#include "mqtt_subscription_manager.h" - -/*Include backoff algorithm header for retry logic.*/ -#include "backoff_algorithm.h" - -/* OTA Library include. */ -#include "ota.h" -#include "ota_config.h" - -/* OTA Library Interface include. */ -#include "ota_os_posix.h" -#include "ota_mqtt_interface.h" -#include "ota_pal_posix.h" - -/* Include firmware version struct definition. */ -#include "ota_appversion32.h" - -/* AWS IoT Core TLS ALPN definitions for MQTT authentication */ -#include "aws_iot_alpn_defs.h" - -/** - * These configuration settings are required to run the OTA demo which uses mutual authentication. - * Throw compilation error if the below configs are not defined. - */ -#ifndef AWS_IOT_ENDPOINT - #error "Please define AWS IoT MQTT broker endpoint(AWS_IOT_ENDPOINT) in demo_config.h." -#endif -#ifndef ROOT_CA_CERT_PATH - #error "Please define path to Root CA certificate of the MQTT broker(ROOT_CA_CERT_PATH) in demo_config.h." -#endif -#ifndef CLIENT_IDENTIFIER - #error "Please define a unique client identifier, CLIENT_IDENTIFIER, in demo_config.h." -#endif -#ifndef CLIENT_CERT_PATH - #error "Please define path to client certificate(CLIENT_CERT_PATH) in demo_config.h." -#endif -#ifndef CLIENT_PRIVATE_KEY_PATH - #error "Please define path to client private key(CLIENT_PRIVATE_KEY_PATH) in demo_config.h." -#endif - -/** - * @brief Length of MQTT server host name. - */ -#define AWS_IOT_ENDPOINT_LENGTH ( ( uint16_t ) ( sizeof( AWS_IOT_ENDPOINT ) - 1 ) ) - -/** - * @brief Length of client identifier. - */ -#define CLIENT_IDENTIFIER_LENGTH ( ( uint16_t ) ( sizeof( CLIENT_IDENTIFIER ) - 1 ) ) - -/** - * @brief Transport timeout in milliseconds for transport send and receive. - */ -#define TRANSPORT_SEND_RECV_TIMEOUT_MS ( 1000U ) - -/** - * @brief Timeout for receiving CONNACK packet in milli seconds. - */ -#define CONNACK_RECV_TIMEOUT_MS ( 2000U ) - -/** - * @brief The maximum time interval in seconds which is allowed to elapse - * between two Control Packets. - * - * It is the responsibility of the Client to ensure that the interval between - * Control Packets being sent does not exceed the this Keep Alive value. In the - * absence of sending any other Control Packets, the Client MUST send a - * PINGREQ Packet. - */ -#define MQTT_KEEP_ALIVE_INTERVAL_SECONDS ( 60U ) - -/** - * @brief Period for waiting on ack. - */ -#define MQTT_ACK_TIMEOUT_MS ( 5000U ) - -/** - * @brief Period for demo loop sleep in milliseconds. - */ -#define OTA_EXAMPLE_LOOP_SLEEP_PERIOD_MS ( 5U ) - -/** - * @brief Size of the network buffer to receive the MQTT message. - * - * The largest message size is data size from the AWS IoT streaming service, - * otaconfigFILE_BLOCK_SIZE + extra for headers. - */ - -#define OTA_NETWORK_BUFFER_SIZE ( otaconfigFILE_BLOCK_SIZE + 128 ) - -/** - * @brief The delay used in the main OTA Demo task loop to periodically output the OTA - * statistics like number of packets received, dropped, processed and queued per connection. - */ -#define OTA_EXAMPLE_TASK_DELAY_MS ( 1000U ) - -/** - * @brief The timeout for waiting for the agent to get suspended after closing the - * connection. - */ -#define OTA_SUSPEND_TIMEOUT_MS ( 5000U ) - -/** - * @brief The timeout for waiting before exiting the OTA demo. - */ -#define OTA_DEMO_EXIT_TIMEOUT_MS ( 3000U ) - -/** - * @brief The maximum size of the file paths used in the demo. - */ -#define OTA_MAX_FILE_PATH_SIZE ( 260U ) - -/** - * @brief The maximum size of the stream name required for downloading update file - * from streaming service. - */ -#define OTA_MAX_STREAM_NAME_SIZE ( 128U ) - -/** - * @brief The maximum back-off delay (in milliseconds) for retrying connection to server. - */ -#define CONNECTION_RETRY_MAX_BACKOFF_DELAY_MS ( 5000U ) - -/** - * @brief The base back-off delay (in milliseconds) to use for connection retry attempts. - */ -#define CONNECTION_RETRY_BACKOFF_BASE_MS ( 500U ) - -/** - * @brief Number of milliseconds in a second. - */ -#define NUM_MILLISECONDS_IN_SECOND ( 1000U ) - -/** - * @brief The maximum number of retries for connecting to server. - */ -#define CONNECTION_RETRY_MAX_ATTEMPTS ( 5U ) - -/** - * @brief The MQTT metrics string expected by AWS IoT. - */ -#define METRICS_STRING "?SDK=" OS_NAME "&Version=" OS_VERSION "&Platform=" HARDWARE_PLATFORM_NAME "&OTALib=" OTA_LIB - -/** - * @brief The length of the MQTT metrics string expected by AWS IoT. - */ -#define METRICS_STRING_LENGTH ( ( uint16_t ) ( sizeof( METRICS_STRING ) - 1 ) ) - - -#ifdef CLIENT_USERNAME - -/** - * @brief Append the username with the metrics string if #CLIENT_USERNAME is defined. - * - * This is to support both metrics reporting and username/password based client - * authentication by AWS IoT. - */ - #define CLIENT_USERNAME_WITH_METRICS CLIENT_USERNAME METRICS_STRING -#endif - -/** - * @brief The common prefix for all OTA topics. - */ -#define OTA_TOPIC_PREFIX "$aws/things/+/" - -/** - * @brief The string used for jobs topics. - */ -#define OTA_TOPIC_JOBS "jobs" - -/** - * @brief The string used for streaming service topics. - */ -#define OTA_TOPIC_STREAM "streams" - -/** - * @brief The length of the outgoing publish records array used by the coreMQTT - * library to track QoS > 0 packet ACKS for outgoing publishes. - */ -#define OUTGOING_PUBLISH_RECORD_LEN ( 10U ) - -/** - * @brief The length of the incoming publish records array used by the coreMQTT - * library to track QoS > 0 packet ACKS for incoming publishes. - */ -#define INCOMING_PUBLISH_RECORD_LEN ( 10U ) - -/*-----------------------------------------------------------*/ - -/* Linkage for error reporting. */ -extern int errno; - -/** - * @brief Struct for firmware version. - */ -const AppVersion32_t appFirmwareVersion = -{ - .u.x.major = APP_VERSION_MAJOR, - .u.x.minor = APP_VERSION_MINOR, - .u.x.build = APP_VERSION_BUILD, -}; - -/* Each compilation unit must define the NetworkContext struct. */ -struct NetworkContext -{ - OpensslParams_t * pParams; -}; - -/** - * @brief Network connection context used in this demo. - */ -static NetworkContext_t networkContext; - -/** - * @brief MQTT connection context used in this demo. - */ -static MQTTContext_t mqttContext; - -/** - * @brief Keep a flag for indicating if the MQTT connection is alive. - */ -static bool mqttSessionEstablished = false; - -/** - * @brief Structure for openssl parameters. - */ -static OpensslParams_t opensslParams; - -/** - * @brief Mutex for synchronizing coreMQTT API calls. - */ -static pthread_mutex_t mqttMutex; - -/** - * @brief Semaphore for synchronizing buffer operations. - */ -static sem_t bufferSemaphore; - -/** - * @brief Semaphore for synchronizing wait for ack. - */ -static sem_t ackSemaphore; - -/** - * @brief Enum for type of OTA job messages received. - */ -typedef enum jobMessageType -{ - jobMessageTypeNextGetAccepted = 0, - jobMessageTypeNextNotify, - jobMessageTypeMax -} jobMessageType_t; - -/** - * @brief The network buffer must remain valid when OTA library task is running. - */ -static uint8_t otaNetworkBuffer[ OTA_NETWORK_BUFFER_SIZE ]; - -/** - * @brief Update File path buffer. - */ -uint8_t updateFilePath[ OTA_MAX_FILE_PATH_SIZE ]; - -/** - * @brief Certificate File path buffer. - */ -uint8_t certFilePath[ OTA_MAX_FILE_PATH_SIZE ]; - -/** - * @brief Stream name buffer. - */ -uint8_t streamName[ OTA_MAX_STREAM_NAME_SIZE ]; - -/** - * @brief Decode memory. - */ -uint8_t decodeMem[ otaconfigFILE_BLOCK_SIZE ]; - -/** - * @brief Bitmap memory. - */ -uint8_t bitmap[ OTA_MAX_BLOCK_BITMAP_SIZE ]; - -/** - * @brief Event buffer. - */ -static OtaEventData_t eventBuffer[ otaconfigMAX_NUM_OTA_DATA_BUFFERS ]; - -/** - * @brief The buffer passed to the OTA Agent from application while initializing. - */ -static OtaAppBuffer_t otaBuffer = -{ - .pUpdateFilePath = updateFilePath, - .updateFilePathsize = OTA_MAX_FILE_PATH_SIZE, - .pCertFilePath = certFilePath, - .certFilePathSize = OTA_MAX_FILE_PATH_SIZE, - .pStreamName = streamName, - .streamNameSize = OTA_MAX_STREAM_NAME_SIZE, - .pDecodeMemory = decodeMem, - .decodeMemorySize = otaconfigFILE_BLOCK_SIZE, - .pFileBitmap = bitmap, - .fileBitmapSize = OTA_MAX_BLOCK_BITMAP_SIZE -}; - -/** - * @brief Array to track the outgoing publish records for outgoing publishes - * with QoS > 0. - * - * This is passed into #MQTT_InitStatefulQoS to allow for QoS > 0. - * - */ -static MQTTPubAckInfo_t pOutgoingPublishRecords[ OUTGOING_PUBLISH_RECORD_LEN ]; - -/** - * @brief Array to track the incoming publish records for incoming publishes - * with QoS > 0. - * - * This is passed into #MQTT_InitStatefulQoS to allow for QoS > 0. - * - */ -static MQTTPubAckInfo_t pIncomingPublishRecords[ INCOMING_PUBLISH_RECORD_LEN ]; - -/*-----------------------------------------------------------*/ - -/** - * @brief Sends an MQTT CONNECT packet over the already connected TCP socket. - * - * @param[in] pMqttContext MQTT context pointer. - * @param[in] createCleanSession Creates a new MQTT session if true. - * If false, tries to establish the existing session if there was session - * already present in broker. - * @param[out] pSessionPresent Session was already present in the broker or not. - * Session present response is obtained from the CONNACK from broker. - * - * @return EXIT_SUCCESS if an MQTT session is established; - * EXIT_FAILURE otherwise. - */ -static int establishMqttSession( MQTTContext_t * pMqttContext ); - - -/** - * @brief Publish message to a topic. - * - * This function publishes a message to a given topic & QoS. - * - * @param[in] pacTopic Mqtt topic filter. - * - * @param[in] topicLen Length of the topic filter. - * - * @param[in] pMsg Message to publish. - * - * @param[in] msgSize Message size. - * - * @param[in] qos Quality of Service - * - * @return OtaMqttSuccess if success , other error code on failure. - */ -static OtaMqttStatus_t mqttPublish( const char * const pacTopic, - uint16_t topicLen, - const char * pMsg, - uint32_t msgSize, - uint8_t qos ); - -/** - * @brief Subscribe to the MQTT topic filter, and registers the handler for the topic filter with the subscription manager. - * - * This function subscribes to the Mqtt topics with the Quality of service - * received as parameter. This function also registers a callback for the - * topicfilter. - * - * @param[in] pTopicFilter Mqtt topic filter. - * - * @param[in] topicFilterLength Length of the topic filter. - * - * @param[in] qos Quality of Service - * - * @return OtaMqttSuccess if success , other error code on failure. - */ -static OtaMqttStatus_t mqttSubscribe( const char * pTopicFilter, - uint16_t topicFilterLength, - uint8_t qos ); - -/** - * @brief Unsubscribe to the Mqtt topics. - * - * This function unsubscribes to the Mqtt topics with the Quality of service - * received as parameter. - * - * @param[in] pTopicFilter Mqtt topic filter. - * - * @param[in] topicFilterLength Length of the topic filter. - * - * @param[qos] qos Quality of Service - * - * @return OtaMqttSuccess if success , other error code on failure. - */ -static OtaMqttStatus_t mqttUnsubscribe( const char * pTopicFilter, - uint16_t topicFilterLength, - uint8_t qos ); - -/** - * @brief Thread to call the OTA agent task. - * - * @param[in] pParam Can be used to pass down functionality to the agent task - * @return void* returning null. - */ -static void * otaThread( void * pParam ); - -/** - * @brief Start OTA demo. - * - * The OTA task is created with initializing the OTA agent and - * setting the required interfaces. The demo loop then starts, - * establishing an MQTT connection with the broker and waiting - * for an update. After a successful update the OTA agent requests - * a manual reset to the downloaded executable. - * - * @return EXIT_SUCCESS or EXIT_FAILURE. - */ -static int startOTADemo( void ); - -/** - * @brief Set OTA interfaces. - * - * @param[in] pOtaInterfaces pointer to OTA interface structure. - */ -static void setOtaInterfaces( OtaInterfaces_t * pOtaInterfaces ); - -/** - * @brief Disconnect from the MQTT broker and close connection. - * - */ -static void disconnect( void ); - -/** - * @brief Attempt to connect to the MQTT broker. - * - * @return int EXIT_SUCCESS if a connection is established. - */ -static int establishConnection( void ); - -/** - * @brief Initialize MQTT by setting up transport interface and network. - * - * @param[in] pMqttContext Structure representing MQTT connection. - * @param[in] pNetworkContext Network context to connect on. - * @return int EXIT_SUCCESS if MQTT component is initialized - */ -static int initializeMqtt( MQTTContext_t * pMqttContext, - NetworkContext_t * pNetworkContext ); - -/** - * @brief Retry logic to establish a connection to the server. - * - * If the connection fails, keep retrying with exponentially increasing - * timeout value, until max retries, max timeout or successful connect. - * - * @param[in] pNetworkContext Network context to connect on. - * @return int EXIT_FAILURE if connection failed after retries. - */ -static int connectToServerWithBackoffRetries( NetworkContext_t * pNetworkContext ); - -/** - * @brief Random number to be used as a back-off value for retrying connection. - * - * @return uint32_t The generated random number. - */ -static uint32_t generateRandomNumber(); - -/* Callbacks used to handle different events. */ - -/** - * @brief The OTA agent has completed the update job or it is in - * self test mode. If it was accepted, we want to activate the new image. - * This typically means we should reset the device to run the new firmware. - * If now is not a good time to reset the device, it may be activated later - * by your user code. If the update was rejected, just return without doing - * anything and we'll wait for another job. If it reported that we should - * start test mode, normally we would perform some kind of system checks to - * make sure our new firmware does the basic things we think it should do - * but we'll just go ahead and set the image as accepted for demo purposes. - * The accept function varies depending on your platform. Refer to the OTA - * PAL implementation for your platform in aws_ota_pal.c to see what it - * does for you. - * - * @param[in] event Event from OTA lib of type OtaJobEvent_t. - * @return None. - */ -static void otaAppCallback( OtaJobEvent_t event, - void * pData ); - -/** - * @brief callback to use with the MQTT context to notify incoming packet events. - * - * @param[in] pMqttContext MQTT context which stores the connection. - * @param[in] pPacketInfo Parameters of the incoming packet. - * @param[in] pDeserializedInfo Deserialized packet information to be dispatched by - * the subscription manager to event callbacks. - */ -static void mqttEventCallback( MQTTContext_t * pMqttContext, - MQTTPacketInfo_t * pPacketInfo, - MQTTDeserializedInfo_t * pDeserializedInfo ); - -/** - * @brief Callback registered with the OTA library that notifies the OTA agent - * of an incoming PUBLISH containing a job document. - * - * @param[in] pContext MQTT context which stores the connection. - * @param[in] pPublishInfo MQTT packet information which stores details of the - * job document. - */ -static void mqttJobCallback( MQTTContext_t * pContext, - MQTTPublishInfo_t * pPublishInfo ); - -/** - * @brief Callback that notifies the OTA library when a data block is received. - * - * @param[in] pContext MQTT context which stores the connection. - * @param[in] pPublishInfo MQTT packet that stores the information of the file block. - */ -static void mqttDataCallback( MQTTContext_t * pContext, - MQTTPublishInfo_t * pPublishInfo ); - -static SubscriptionManagerCallback_t otaMessageCallback[] = { mqttJobCallback, mqttDataCallback }; - -/*-----------------------------------------------------------*/ - -void otaEventBufferFree( OtaEventData_t * const pxBuffer ) -{ - if( sem_wait( &bufferSemaphore ) == 0 ) - { - pxBuffer->bufferUsed = false; - ( void ) sem_post( &bufferSemaphore ); - } - else - { - LogError( ( "Failed to get buffer semaphore: " - ",errno=%s", - strerror( errno ) ) ); - } -} - -/*-----------------------------------------------------------*/ - -OtaEventData_t * otaEventBufferGet( void ) -{ - uint32_t ulIndex = 0; - OtaEventData_t * pFreeBuffer = NULL; - - if( sem_wait( &bufferSemaphore ) == 0 ) - { - for( ulIndex = 0; ulIndex < otaconfigMAX_NUM_OTA_DATA_BUFFERS; ulIndex++ ) - { - if( eventBuffer[ ulIndex ].bufferUsed == false ) - { - eventBuffer[ ulIndex ].bufferUsed = true; - pFreeBuffer = &eventBuffer[ ulIndex ]; - break; - } - } - - ( void ) sem_post( &bufferSemaphore ); - } - else - { - LogError( ( "Failed to get buffer semaphore: " - ",errno=%s", - strerror( errno ) ) ); - } - - return pFreeBuffer; -} - -/*-----------------------------------------------------------*/ - -static void otaAppCallback( OtaJobEvent_t event, - void * pData ) -{ - OtaErr_t err = OtaErrUninitialized; - - switch( event ) - { - case OtaJobEventActivate: - LogInfo( ( "Received OtaJobEventActivate callback from OTA Agent." ) ); - - /* Activate the new firmware image. */ - OTA_ActivateNewImage(); - - /* Shutdown OTA Agent, if it is required that the unsubscribe operations are not - * performed while shutting down please set the second parameter to 0 instead of 1. */ - OTA_Shutdown( 0, 1 ); - - /* Requires manual activation of new image.*/ - LogError( ( "New image activation failed." ) ); - - break; - - case OtaJobEventFail: - LogInfo( ( "Received OtaJobEventFail callback from OTA Agent." ) ); - - /* Nothing special to do. The OTA agent handles it. */ - break; - - case OtaJobEventStartTest: - - /* This demo just accepts the image since it was a good OTA update and networking - * and services are all working (or we would not have made it this far). If this - * were some custom device that wants to test other things before validating new - * image, this would be the place to kick off those tests before calling - * OTA_SetImageState() with the final result of either accepted or rejected. */ - - LogInfo( ( "Received OtaJobEventStartTest callback from OTA Agent." ) ); - err = OTA_SetImageState( OtaImageStateAccepted ); - - if( err != OtaErrNone ) - { - LogError( ( " Failed to set image state as accepted." ) ); - } - - break; - - case OtaJobEventProcessed: - LogDebug( ( "Received OtaJobEventProcessed callback from OTA Agent." ) ); - - if( pData != NULL ) - { - otaEventBufferFree( ( OtaEventData_t * ) pData ); - } - - break; - - case OtaJobEventSelfTestFailed: - LogDebug( ( "Received OtaJobEventSelfTestFailed callback from OTA Agent." ) ); - - /* Requires manual activation of previous image as self-test for - * new image downloaded failed.*/ - LogError( ( "Self-test failed, shutting down OTA Agent." ) ); - - /* Shutdown OTA Agent, if it is required that the unsubscribe operations are not - * performed while shutting down please set the second parameter to 0 instead of 1. */ - OTA_Shutdown( 0, 1 ); - - break; - - default: - LogDebug( ( "Received invalid callback event from OTA Agent." ) ); - } -} - -jobMessageType_t getJobMessageType( const char * pTopicName, - uint16_t topicNameLength ) -{ - uint16_t index = 0U; - MQTTStatus_t mqttStatus = MQTTSuccess; - bool isMatch = false; - jobMessageType_t jobMessageIndex = jobMessageTypeMax; - - /* For suppressing compiler-warning: unused variable. */ - ( void ) mqttStatus; - - /* Lookup table for OTA job message string. */ - static const char * const pJobTopicFilters[ jobMessageTypeMax ] = - { - OTA_TOPIC_PREFIX OTA_TOPIC_JOBS "/$next/get/accepted", - OTA_TOPIC_PREFIX OTA_TOPIC_JOBS "/notify-next", - }; - - /* Match the input topic filter against the wild-card pattern of topics filters - * relevant for the OTA Update service to determine the type of topic filter. */ - for( ; index < jobMessageTypeMax; index++ ) - { - mqttStatus = MQTT_MatchTopic( pTopicName, - topicNameLength, - pJobTopicFilters[ index ], - strlen( pJobTopicFilters[ index ] ), - &isMatch ); - assert( mqttStatus == MQTTSuccess ); - - if( isMatch ) - { - jobMessageIndex = index; - break; - } - } - - return jobMessageIndex; -} - -/*-----------------------------------------------------------*/ - -static void mqttJobCallback( MQTTContext_t * pContext, - MQTTPublishInfo_t * pPublishInfo ) -{ - OtaEventData_t * pData; - OtaEventMsg_t eventMsg = { 0 }; - jobMessageType_t jobMessageType = 0; - - assert( pPublishInfo != NULL ); - assert( pContext != NULL ); - - ( void ) pContext; - - jobMessageType = getJobMessageType( pPublishInfo->pTopicName, pPublishInfo->topicNameLength ); - - switch( jobMessageType ) - { - case jobMessageTypeNextGetAccepted: - case jobMessageTypeNextNotify: - - pData = otaEventBufferGet(); - - if( pData != NULL ) - { - memcpy( pData->data, pPublishInfo->pPayload, pPublishInfo->payloadLength ); - pData->dataLength = pPublishInfo->payloadLength; - eventMsg.eventId = OtaAgentEventReceivedJobDocument; - eventMsg.pEventData = pData; - - /* Send job document received event. */ - OTA_SignalEvent( &eventMsg ); - } - else - { - LogError( ( "No OTA data buffers available." ) ); - } - - break; - - default: - LogInfo( ( "Received job message %s size %ld.\n\n", - pPublishInfo->pTopicName, - pPublishInfo->payloadLength ) ); - } -} - -/*-----------------------------------------------------------*/ - -static void mqttDataCallback( MQTTContext_t * pContext, - MQTTPublishInfo_t * pPublishInfo ) -{ - OtaEventData_t * pData; - OtaEventMsg_t eventMsg = { 0 }; - - assert( pPublishInfo != NULL ); - assert( pContext != NULL ); - - ( void ) pContext; - - LogInfo( ( "Received data message callback, size %zu.\n\n", pPublishInfo->payloadLength ) ); - - pData = otaEventBufferGet(); - - if( pData != NULL ) - { - memcpy( pData->data, pPublishInfo->pPayload, pPublishInfo->payloadLength ); - pData->dataLength = pPublishInfo->payloadLength; - eventMsg.eventId = OtaAgentEventReceivedFileBlock; - eventMsg.pEventData = pData; - - /* Send job document received event. */ - OTA_SignalEvent( &eventMsg ); - } - else - { - LogError( ( "No OTA data buffers available." ) ); - } -} - -/*-----------------------------------------------------------*/ - -static void mqttEventCallback( MQTTContext_t * pMqttContext, - MQTTPacketInfo_t * pPacketInfo, - MQTTDeserializedInfo_t * pDeserializedInfo ) -{ - assert( pMqttContext != NULL ); - assert( pPacketInfo != NULL ); - assert( pDeserializedInfo != NULL ); - - /* Handle incoming publish. The lower 4 bits of the publish packet - * type is used for the dup, QoS, and retain flags. Hence masking - * out the lower bits to check if the packet is publish. */ - if( ( pPacketInfo->type & 0xF0U ) == MQTT_PACKET_TYPE_PUBLISH ) - { - assert( pDeserializedInfo->pPublishInfo != NULL ); - /* Handle incoming publish. */ - SubscriptionManager_DispatchHandler( pMqttContext, pDeserializedInfo->pPublishInfo ); - } - else - { - /* Handle other packets. */ - switch( pPacketInfo->type ) - { - case MQTT_PACKET_TYPE_SUBACK: - LogInfo( ( "Received SUBACK.\n\n" ) ); - break; - - case MQTT_PACKET_TYPE_UNSUBACK: - LogInfo( ( "Received UNSUBACK.\n\n" ) ); - break; - - case MQTT_PACKET_TYPE_PINGRESP: - - /* Nothing to be done from application as library handles - * PINGRESP. */ - LogWarn( ( "PINGRESP should not be handled by the application " - "callback when using MQTT_ProcessLoop.\n\n" ) ); - break; - - case MQTT_PACKET_TYPE_PUBACK: - LogInfo( ( "PUBACK received for packet id %u.\n\n", - pDeserializedInfo->packetIdentifier ) ); - sem_post( &ackSemaphore ); - break; - - /* Any other packet type is invalid. */ - default: - LogError( ( "Unknown packet type received:(%02x).\n\n", - pPacketInfo->type ) ); - } - } -} - -/*-----------------------------------------------------------*/ - -static uint32_t generateRandomNumber() -{ - return( rand() ); -} - -/*-----------------------------------------------------------*/ - -static int initializeMqtt( MQTTContext_t * pMqttContext, - NetworkContext_t * pNetworkContext ) -{ - int returnStatus = EXIT_SUCCESS; - MQTTStatus_t mqttStatus = MQTTBadParameter; - MQTTFixedBuffer_t networkBuffer; - TransportInterface_t transport = { NULL }; - - assert( pMqttContext != NULL ); - assert( pNetworkContext != NULL ); - - /* Fill in TransportInterface send and receive function pointers. - * For this demo, TCP sockets are used to send and receive data - * from network. TLS over TCP channel is used as the transport - * layer for the MQTT connection. Network context is SSL context - * for OpenSSL.*/ - transport.pNetworkContext = pNetworkContext; - transport.send = Openssl_Send; - transport.recv = Openssl_Recv; - transport.writev = NULL; - - /* Fill the values for network buffer. */ - networkBuffer.pBuffer = otaNetworkBuffer; - networkBuffer.size = OTA_NETWORK_BUFFER_SIZE; - - /* Initialize MQTT library. */ - mqttStatus = MQTT_Init( pMqttContext, - &transport, - Clock_GetTimeMs, - mqttEventCallback, - &networkBuffer ); - - if( mqttStatus != MQTTSuccess ) - { - returnStatus = EXIT_FAILURE; - LogError( ( "MQTT_Init failed: Status = %s.", MQTT_Status_strerror( mqttStatus ) ) ); - } - else - { - mqttStatus = MQTT_InitStatefulQoS( pMqttContext, - pOutgoingPublishRecords, - OUTGOING_PUBLISH_RECORD_LEN, - pIncomingPublishRecords, - INCOMING_PUBLISH_RECORD_LEN ); - - if( mqttStatus != MQTTSuccess ) - { - returnStatus = EXIT_FAILURE; - LogError( ( "MQTT_InitStatefulQoS failed: Status = %s.", MQTT_Status_strerror( mqttStatus ) ) ); - } - } - - return returnStatus; -} - -/*-----------------------------------------------------------*/ - -static int connectToServerWithBackoffRetries( NetworkContext_t * pNetworkContext ) -{ - int returnStatus = EXIT_SUCCESS; - BackoffAlgorithmStatus_t backoffAlgStatus = BackoffAlgorithmSuccess; - OpensslStatus_t opensslStatus = OPENSSL_SUCCESS; - BackoffAlgorithmContext_t reconnectParams; - ServerInfo_t serverInfo; - OpensslCredentials_t opensslCredentials; - uint16_t nextRetryBackOff; - - /* Initialize information to connect to the MQTT broker. */ - serverInfo.pHostName = AWS_IOT_ENDPOINT; - serverInfo.hostNameLength = AWS_IOT_ENDPOINT_LENGTH; - serverInfo.port = AWS_MQTT_PORT; - - /* Initialize credentials for establishing TLS session. */ - memset( &opensslCredentials, 0, sizeof( OpensslCredentials_t ) ); - opensslCredentials.pRootCaPath = ROOT_CA_CERT_PATH; - - /* If #CLIENT_USERNAME is defined, username/password is used for authenticating - * the client. */ - #ifndef CLIENT_USERNAME - opensslCredentials.pClientCertPath = CLIENT_CERT_PATH; - opensslCredentials.pPrivateKeyPath = CLIENT_PRIVATE_KEY_PATH; - #endif - - /* AWS IoT requires devices to send the Server Name Indication (SNI) - * extension to the Transport Layer Security (TLS) protocol and provide - * the complete endpoint address in the host_name field. Details about - * SNI for AWS IoT can be found in the link below. - * https://docs.aws.amazon.com/iot/latest/developerguide/transport-security.html */ - opensslCredentials.sniHostName = AWS_IOT_ENDPOINT; - - if( AWS_MQTT_PORT == 443 ) - { - /* Pass the ALPN protocol name depending on the port being used. - * Please see more details about the ALPN protocol for the AWS IoT MQTT - * endpoint in the link below. - * https://aws.amazon.com/blogs/iot/mqtt-with-tls-client-authentication-on-port-443-why-it-is-useful-and-how-it-works/ - * - * For username and password based authentication in AWS IoT, - * #AWS_IOT_PASSWORD_ALPN is used. More details can be found in the - * link below. - * https://docs.aws.amazon.com/iot/latest/developerguide/custom-authentication.html - */ - #ifdef CLIENT_USERNAME - opensslCredentials.pAlpnProtos = AWS_IOT_ALPN_MQTT_CUSTOM_AUTH_OPENSSL; - opensslCredentials.alpnProtosLen = AWS_IOT_ALPN_MQTT_CUSTOM_AUTH_OPENSSL_LEN; - #else - opensslCredentials.pAlpnProtos = AWS_IOT_ALPN_MQTT_CA_AUTH_OPENSSL; - opensslCredentials.alpnProtosLen = AWS_IOT_ALPN_MQTT_CA_AUTH_OPENSSL_LEN; - #endif - } - - /* Initialize reconnect attempts and interval */ - BackoffAlgorithm_InitializeParams( &reconnectParams, - CONNECTION_RETRY_BACKOFF_BASE_MS, - CONNECTION_RETRY_MAX_BACKOFF_DELAY_MS, - CONNECTION_RETRY_MAX_ATTEMPTS ); - - /* Attempt to connect to MQTT broker. If connection fails, retry after - * a timeout. Timeout value will exponentially increase until maximum - * attempts are reached. - */ - do - { - /* Establish a TLS session with the MQTT broker. This example connects - * to the MQTT broker as specified in AWS_IOT_ENDPOINT and AWS_MQTT_PORT - * at the demo config header. */ - LogInfo( ( "Establishing a TLS session to %.*s:%d.", - AWS_IOT_ENDPOINT_LENGTH, - AWS_IOT_ENDPOINT, - AWS_MQTT_PORT ) ); - opensslStatus = Openssl_Connect( pNetworkContext, - &serverInfo, - &opensslCredentials, - TRANSPORT_SEND_RECV_TIMEOUT_MS, - TRANSPORT_SEND_RECV_TIMEOUT_MS ); - - if( opensslStatus != OPENSSL_SUCCESS ) - { - /* Generate a random number and get back-off value (in milliseconds) for the next connection retry. */ - backoffAlgStatus = BackoffAlgorithm_GetNextBackoff( &reconnectParams, generateRandomNumber(), &nextRetryBackOff ); - - if( backoffAlgStatus == BackoffAlgorithmRetriesExhausted ) - { - LogError( ( "Connection to the broker failed, all attempts exhausted." ) ); - returnStatus = EXIT_FAILURE; - } - else if( backoffAlgStatus == BackoffAlgorithmSuccess ) - { - LogWarn( ( "Connection to the broker failed. Retrying connection " - "after %hu ms backoff.", - ( unsigned short ) nextRetryBackOff ) ); - Clock_SleepMs( nextRetryBackOff ); - } - } - } while( ( opensslStatus != OPENSSL_SUCCESS ) && ( backoffAlgStatus == BackoffAlgorithmSuccess ) ); - - return returnStatus; -} - -/*-----------------------------------------------------------*/ - -static int establishMqttSession( MQTTContext_t * pMqttContext ) -{ - int returnStatus = EXIT_SUCCESS; - MQTTStatus_t mqttStatus = MQTTBadParameter; - MQTTConnectInfo_t connectInfo = { 0 }; - - bool sessionPresent = false; - - assert( pMqttContext != NULL ); - - /* Establish MQTT session by sending a CONNECT packet. */ - - /* If #createCleanSession is true, start with a clean session - * i.e. direct the MQTT broker to discard any previous session data. - * If #createCleanSession is false, directs the broker to attempt to - * reestablish a session which was already present. */ - connectInfo.cleanSession = true; - - /* The client identifier is used to uniquely identify this MQTT client to - * the MQTT broker. In a production device the identifier can be something - * unique, such as a device serial number. */ - connectInfo.pClientIdentifier = CLIENT_IDENTIFIER; - connectInfo.clientIdentifierLength = CLIENT_IDENTIFIER_LENGTH; - - /* The maximum time interval in seconds which is allowed to elapse - * between two Control Packets. - * It is the responsibility of the Client to ensure that the interval between - * Control Packets being sent does not exceed the this Keep Alive value. In the - * absence of sending any other Control Packets, the Client MUST send a - * PINGREQ Packet. */ - connectInfo.keepAliveSeconds = MQTT_KEEP_ALIVE_INTERVAL_SECONDS; - - /* Use the username and password for authentication, if they are defined. - * Refer to the AWS IoT documentation below for details regarding client - * authentication with a username and password. - * https://docs.aws.amazon.com/iot/latest/developerguide/custom-authentication.html - * An authorizer setup needs to be done, as mentioned in the above link, to use - * username/password based client authentication. - * - * The username field is populated with voluntary metrics to AWS IoT. - * The metrics collected by AWS IoT are the operating system, the operating - * system's version, the hardware platform, and the MQTT Client library - * information. These metrics help AWS IoT improve security and provide - * better technical support. - * - * If client authentication is based on username/password in AWS IoT, - * the metrics string is appended to the username to support both client - * authentication and metrics collection. */ - #ifdef CLIENT_USERNAME - connectInfo.pUserName = CLIENT_USERNAME_WITH_METRICS; - connectInfo.userNameLength = strlen( CLIENT_USERNAME_WITH_METRICS ); - connectInfo.pPassword = CLIENT_PASSWORD; - connectInfo.passwordLength = strlen( CLIENT_PASSWORD ); - #else - connectInfo.pUserName = METRICS_STRING; - connectInfo.userNameLength = METRICS_STRING_LENGTH; - /* Password for authentication is not used. */ - connectInfo.pPassword = NULL; - connectInfo.passwordLength = 0U; - #endif /* ifdef CLIENT_USERNAME */ - - if( pthread_mutex_lock( &mqttMutex ) == 0 ) - { - /* Send MQTT CONNECT packet to broker. */ - mqttStatus = MQTT_Connect( pMqttContext, &connectInfo, NULL, CONNACK_RECV_TIMEOUT_MS, &sessionPresent ); - - pthread_mutex_unlock( &mqttMutex ); - } - else - { - LogError( ( "Failed to acquire mutex for executing MQTT_Connect" - ",errno=%s", - strerror( errno ) ) ); - } - - if( mqttStatus != MQTTSuccess ) - { - returnStatus = EXIT_FAILURE; - LogError( ( "Connection with MQTT broker failed with status %s.", - MQTT_Status_strerror( mqttStatus ) ) ); - } - else - { - LogInfo( ( "MQTT connection successfully established with broker.\n\n" ) ); - } - - return returnStatus; -} - -/*-----------------------------------------------------------*/ - -static int establishConnection( void ) -{ - int returnStatus = EXIT_FAILURE; - - /* Set the pParams member of the network context with desired transport. */ - networkContext.pParams = &opensslParams; - - /* Attempt to connect to the MQTT broker. If connection fails, retry after - * a timeout. Timeout value will be exponentially increased till the maximum - * attempts are reached or maximum timeout value is reached. The function - * returns EXIT_FAILURE if the TCP connection cannot be established to - * broker after configured number of attempts. */ - returnStatus = connectToServerWithBackoffRetries( &networkContext ); - - if( returnStatus != EXIT_SUCCESS ) - { - /* Log error to indicate connection failure. */ - LogError( ( "Failed to connect to MQTT broker %.*s.", - AWS_IOT_ENDPOINT_LENGTH, - AWS_IOT_ENDPOINT ) ); - } - else - { - /* Establish MQTT session on top of TCP+TLS connection. */ - LogInfo( ( "Creating an MQTT connection to %.*s.", - AWS_IOT_ENDPOINT_LENGTH, - AWS_IOT_ENDPOINT ) ); - - /* Sends an MQTT Connect packet using the established TLS session, - * then waits for connection acknowledgment (CONNACK) packet. */ - returnStatus = establishMqttSession( &mqttContext ); - - if( returnStatus != EXIT_SUCCESS ) - { - LogError( ( "Failed creating an MQTT connection to %.*s.", - AWS_IOT_ENDPOINT_LENGTH, - AWS_IOT_ENDPOINT ) ); - } - else - { - LogDebug( ( "Success creating MQTT connection to %.*s.", - AWS_IOT_ENDPOINT_LENGTH, - AWS_IOT_ENDPOINT ) ); - - mqttSessionEstablished = true; - } - } - - return returnStatus; -} - -/*-----------------------------------------------------------*/ - -static void disconnect( void ) -{ - /* Disconnect from broker. */ - LogInfo( ( "Disconnecting the MQTT connection with %s.", AWS_IOT_ENDPOINT ) ); - - if( mqttSessionEstablished == true ) - { - if( pthread_mutex_lock( &mqttMutex ) == 0 ) - { - /* Disconnect MQTT session. */ - MQTT_Disconnect( &mqttContext ); - - /* Clear the mqtt session flag. */ - mqttSessionEstablished = false; - - pthread_mutex_unlock( &mqttMutex ); - } - else - { - LogError( ( "Failed to acquire mutex to execute MQTT_Disconnect" - ",errno=%s", - strerror( errno ) ) ); - } - } - else - { - LogError( ( "MQTT already disconnected." ) ); - } - - /* End TLS session, then close TCP connection. */ - ( void ) Openssl_Disconnect( &networkContext ); -} - -/*-----------------------------------------------------------*/ - -static void registerSubscriptionManagerCallback( const char * pTopicFilter, - uint16_t topicFilterLength ) -{ - bool isMatch = false; - MQTTStatus_t mqttStatus = MQTTSuccess; - SubscriptionManagerStatus_t subscriptionStatus = SUBSCRIPTION_MANAGER_SUCCESS; - - uint16_t index = 0U; - - /* For suppressing compiler-warning: unused variable. */ - ( void ) mqttStatus; - - /* Lookup table for OTA message string. */ - static const char * const pWildCardTopicFilters[] = - { - OTA_TOPIC_PREFIX OTA_TOPIC_JOBS "/#", - OTA_TOPIC_PREFIX OTA_TOPIC_STREAM "/#" - }; - - /* Match the input topic filter against the wild-card pattern of topics filters - * relevant for the OTA Update service to determine the type of topic filter. */ - for( ; index < 2; index++ ) - { - mqttStatus = MQTT_MatchTopic( pTopicFilter, - topicFilterLength, - pWildCardTopicFilters[ index ], - strlen( pWildCardTopicFilters[ index ] ), - &isMatch ); - assert( mqttStatus == MQTTSuccess ); - - if( isMatch ) - { - /* Register callback to subscription manager. */ - subscriptionStatus = SubscriptionManager_RegisterCallback( pWildCardTopicFilters[ index ], - strlen( pWildCardTopicFilters[ index ] ), - otaMessageCallback[ index ] ); - - if( subscriptionStatus != SUBSCRIPTION_MANAGER_SUCCESS ) - { - LogWarn( ( "Failed to register a callback to subscription manager with error = %d.", - subscriptionStatus ) ); - } - - break; - } - } -} - -/*-----------------------------------------------------------*/ - -static OtaMqttStatus_t mqttSubscribe( const char * pTopicFilter, - uint16_t topicFilterLength, - uint8_t qos ) -{ - OtaMqttStatus_t otaRet = OtaMqttSuccess; - - MQTTStatus_t mqttStatus = MQTTBadParameter; - MQTTContext_t * pMqttContext = &mqttContext; - MQTTSubscribeInfo_t pSubscriptionList[ 1 ]; - - assert( pMqttContext != NULL ); - assert( pTopicFilter != NULL ); - assert( topicFilterLength > 0 ); - - ( void ) qos; - - /* Start with everything at 0. */ - ( void ) memset( ( void * ) pSubscriptionList, 0x00, sizeof( pSubscriptionList ) ); - - /* Set the topic and topic length. */ - pSubscriptionList[ 0 ].pTopicFilter = pTopicFilter; - pSubscriptionList[ 0 ].topicFilterLength = topicFilterLength; - - if( pthread_mutex_lock( &mqttMutex ) == 0 ) - { - /* Send SUBSCRIBE packet. */ - mqttStatus = MQTT_Subscribe( pMqttContext, - pSubscriptionList, - sizeof( pSubscriptionList ) / sizeof( MQTTSubscribeInfo_t ), - MQTT_GetPacketId( pMqttContext ) ); - - pthread_mutex_unlock( &mqttMutex ); - } - else - { - LogError( ( "Failed to acquire mqtt mutex for executing MQTT_Subscribe" - ",errno=%s", - strerror( errno ) ) ); - } - - if( mqttStatus != MQTTSuccess ) - { - LogError( ( "Failed to send SUBSCRIBE packet to broker with error = %u.", - mqttStatus ) ); - - otaRet = OtaMqttSubscribeFailed; - } - else - { - LogInfo( ( "SUBSCRIBE topic %.*s to broker.\n\n", - topicFilterLength, - pTopicFilter ) ); - - registerSubscriptionManagerCallback( pTopicFilter, topicFilterLength ); - } - - return otaRet; -} - -/*-----------------------------------------------------------*/ - -static OtaMqttStatus_t mqttPublish( const char * const pacTopic, - uint16_t topicLen, - const char * pMsg, - uint32_t msgSize, - uint8_t qos ) -{ - OtaMqttStatus_t otaRet = OtaMqttSuccess; - - MQTTStatus_t mqttStatus = MQTTBadParameter; - MQTTPublishInfo_t publishInfo = { 0 }; - MQTTContext_t * pMqttContext = &mqttContext; - struct timespec ts = { 0 }; - int ret; - - /* Set the required publish parameters. */ - publishInfo.pTopicName = pacTopic; - publishInfo.topicNameLength = topicLen; - publishInfo.qos = qos; - publishInfo.pPayload = pMsg; - publishInfo.payloadLength = msgSize; - - if( pthread_mutex_lock( &mqttMutex ) == 0 ) - { - mqttStatus = MQTT_Publish( pMqttContext, - &publishInfo, - MQTT_GetPacketId( pMqttContext ) ); - - if( mqttStatus != MQTTSuccess ) - { - LogError( ( "Failed to send PUBLISH packet to broker with error = %u.", mqttStatus ) ); - - otaRet = OtaMqttPublishFailed; - } - - pthread_mutex_unlock( &mqttMutex ); - } - else - { - LogError( ( "Failed to acquire mqtt mutex for executing MQTT_Publish" - ",errno=%s", - strerror( errno ) ) ); - - otaRet = OtaMqttPublishFailed; - } - - if( ( mqttStatus == MQTTSuccess ) && ( qos == 1 ) ) - { - /* Calculate relative interval as current time plus number of seconds. */ - clock_gettime( CLOCK_REALTIME, &ts ); - ts.tv_sec += MQTT_ACK_TIMEOUT_MS; - - while( ( ret = sem_timedwait( &ackSemaphore, &ts ) ) == -1 && errno == EINTR ) - { - continue; - } - - if( ret == -1 ) - { - LogError( ( "Failed to receive ack for publish." - ",errno=%s", - strerror( errno ) ) ); - - otaRet = OtaMqttPublishFailed; - } - } - - return otaRet; -} - -/*-----------------------------------------------------------*/ - -static OtaMqttStatus_t mqttUnsubscribe( const char * pTopicFilter, - uint16_t topicFilterLength, - uint8_t qos ) -{ - OtaMqttStatus_t otaRet = OtaMqttSuccess; - MQTTStatus_t mqttStatus = MQTTBadParameter; - - MQTTSubscribeInfo_t pSubscriptionList[ 1 ]; - MQTTContext_t * pMqttContext = &mqttContext; - - ( void ) qos; - - /* Start with everything at 0. */ - ( void ) memset( ( void * ) pSubscriptionList, 0x00, sizeof( pSubscriptionList ) ); - - /* Set the topic and topic length. */ - pSubscriptionList[ 0 ].pTopicFilter = pTopicFilter; - pSubscriptionList[ 0 ].topicFilterLength = topicFilterLength; - - if( pthread_mutex_lock( &mqttMutex ) == 0 ) - { - /* Send UNSUBSCRIBE packet. */ - mqttStatus = MQTT_Unsubscribe( pMqttContext, - pSubscriptionList, - sizeof( pSubscriptionList ) / sizeof( MQTTSubscribeInfo_t ), - MQTT_GetPacketId( pMqttContext ) ); - - pthread_mutex_unlock( &mqttMutex ); - } - else - { - LogError( ( "Failed to acquire mutex for executing MQTT_Unsubscribe" - ",errno=%s", - strerror( errno ) ) ); - } - - if( mqttStatus != MQTTSuccess ) - { - LogError( ( "Failed to send UNSUBSCRIBE packet to broker with error = %u.", - mqttStatus ) ); - - otaRet = OtaMqttUnsubscribeFailed; - } - else - { - LogInfo( ( "UNSUBSCRIBE topic %.*s to broker.\n\n", - topicFilterLength, - pTopicFilter ) ); - } - - return otaRet; -} - -/*-----------------------------------------------------------*/ - -static void setOtaInterfaces( OtaInterfaces_t * pOtaInterfaces ) -{ - /* Initialize OTA library OS Interface. */ - pOtaInterfaces->os.event.init = Posix_OtaInitEvent; - pOtaInterfaces->os.event.send = Posix_OtaSendEvent; - pOtaInterfaces->os.event.recv = Posix_OtaReceiveEvent; - pOtaInterfaces->os.event.deinit = Posix_OtaDeinitEvent; - pOtaInterfaces->os.timer.start = Posix_OtaStartTimer; - pOtaInterfaces->os.timer.stop = Posix_OtaStopTimer; - pOtaInterfaces->os.timer.delete = Posix_OtaDeleteTimer; - pOtaInterfaces->os.mem.malloc = STDC_Malloc; - pOtaInterfaces->os.mem.free = STDC_Free; - - /* Initialize the OTA library MQTT Interface.*/ - pOtaInterfaces->mqtt.subscribe = mqttSubscribe; - pOtaInterfaces->mqtt.publish = mqttPublish; - pOtaInterfaces->mqtt.unsubscribe = mqttUnsubscribe; - - /* Initialize the OTA library PAL Interface.*/ - pOtaInterfaces->pal.getPlatformImageState = otaPal_GetPlatformImageState; - pOtaInterfaces->pal.setPlatformImageState = otaPal_SetPlatformImageState; - pOtaInterfaces->pal.writeBlock = otaPal_WriteBlock; - pOtaInterfaces->pal.activate = otaPal_ActivateNewImage; - pOtaInterfaces->pal.closeFile = otaPal_CloseFile; - pOtaInterfaces->pal.reset = otaPal_ResetDevice; - pOtaInterfaces->pal.abort = otaPal_Abort; - pOtaInterfaces->pal.createFile = otaPal_CreateFileForRx; -} - -/*-----------------------------------------------------------*/ - -static void * otaThread( void * pParam ) -{ - /* Calling OTA agent task. */ - OTA_EventProcessingTask( pParam ); - LogInfo( ( "OTA Agent stopped." ) ); - return NULL; -} -/*-----------------------------------------------------------*/ -static int startOTADemo( void ) -{ - /* Status indicating a successful demo or not. */ - int returnStatus = EXIT_SUCCESS; - - /* coreMQTT library return status. */ - MQTTStatus_t mqttStatus = MQTTBadParameter; - - /* OTA library return status. */ - OtaErr_t otaRet = OtaErrNone; - - /* OTA Agent state returned from calling OTA_GetAgentState.*/ - OtaState_t state = OtaAgentStateStopped; - - /* OTA event message used for sending event to OTA Agent.*/ - OtaEventMsg_t eventMsg = { 0 }; - - /* OTA library packet statistics per job.*/ - OtaAgentStatistics_t otaStatistics = { 0 }; - - /* OTA Agent thread handle.*/ - pthread_t threadHandle; - - /* Status return from call to pthread_join. */ - int returnJoin = 0; - - /* OTA interface context required for library interface functions.*/ - OtaInterfaces_t otaInterfaces; - - /* Maximum time to wait for the OTA agent to get suspended. */ - int16_t suspendTimeout; - - /* Set OTA Library interfaces.*/ - setOtaInterfaces( &otaInterfaces ); - - LogInfo( ( "OTA over MQTT demo, Application version %u.%u.%u", - appFirmwareVersion.u.x.major, - appFirmwareVersion.u.x.minor, - appFirmwareVersion.u.x.build ) ); - - /****************************** Init OTA Library. ******************************/ - - if( returnStatus == EXIT_SUCCESS ) - { - if( ( otaRet = OTA_Init( &otaBuffer, - &otaInterfaces, - ( const uint8_t * ) ( CLIENT_IDENTIFIER ), - otaAppCallback ) ) != OtaErrNone ) - { - LogError( ( "Failed to initialize OTA Agent, exiting = %u.", - otaRet ) ); - - returnStatus = EXIT_FAILURE; - } - } - - /****************************** Create OTA Task. ******************************/ - - if( returnStatus == EXIT_SUCCESS ) - { - if( pthread_create( &threadHandle, NULL, otaThread, NULL ) != 0 ) - { - LogError( ( "Failed to create OTA thread: " - ",errno=%s", - strerror( errno ) ) ); - - returnStatus = EXIT_FAILURE; - } - } - - /****************************** OTA Demo loop. ******************************/ - - if( returnStatus == EXIT_SUCCESS ) - { - /* Wait till OTA library is stopped, output statistics for currently running - * OTA job */ - while( ( ( state = OTA_GetState() ) != OtaAgentStateStopped ) ) - { - if( mqttSessionEstablished != true ) - { - /* Connect to MQTT broker and create MQTT connection. */ - if( EXIT_SUCCESS == establishConnection() ) - { - /* Check if OTA process was suspended and resume if required. */ - if( state == OtaAgentStateSuspended ) - { - /* Resume OTA operations. */ - OTA_Resume(); - } - else - { - /* Send start event to OTA Agent.*/ - eventMsg.eventId = OtaAgentEventStart; - OTA_SignalEvent( &eventMsg ); - } - } - } - - if( mqttSessionEstablished == true ) - { - /* Acquire the mqtt mutex lock. */ - if( pthread_mutex_lock( &mqttMutex ) == 0 ) - { - /* Loop to receive packet from transport interface. */ - mqttStatus = MQTT_ProcessLoop( &mqttContext ); - - pthread_mutex_unlock( &mqttMutex ); - } - else - { - LogError( ( "Failed to acquire mutex to execute process loop" - ",errno=%s", - strerror( errno ) ) ); - } - - if( ( mqttStatus == MQTTSuccess ) || ( mqttStatus == MQTTNeedMoreBytes ) ) - { - /* Get OTA statistics for currently executing job. */ - OTA_GetStatistics( &otaStatistics ); - - LogInfo( ( " Received: %u Queued: %u Processed: %u Dropped: %u", - otaStatistics.otaPacketsReceived, - otaStatistics.otaPacketsQueued, - otaStatistics.otaPacketsProcessed, - otaStatistics.otaPacketsDropped ) ); - - /* Delay to allow data to buffer for MQTT_ProcessLoop. */ - Clock_SleepMs( OTA_EXAMPLE_LOOP_SLEEP_PERIOD_MS ); - } - else - { - LogError( ( "MQTT_ProcessLoop returned with status = %s.", - MQTT_Status_strerror( mqttStatus ) ) ); - - /* Disconnect from broker and close connection. */ - disconnect(); - - /* Suspend OTA operations. */ - otaRet = OTA_Suspend(); - - if( otaRet == OtaErrNone ) - { - suspendTimeout = OTA_SUSPEND_TIMEOUT_MS; - - while( ( ( state = OTA_GetState() ) != OtaAgentStateSuspended ) && ( suspendTimeout > 0 ) ) - { - /* Wait for OTA Library state to suspend */ - Clock_SleepMs( OTA_EXAMPLE_TASK_DELAY_MS ); - suspendTimeout -= OTA_EXAMPLE_TASK_DELAY_MS; - } - } - else - { - LogError( ( "OTA failed to suspend. " - "StatusCode=%d.", otaRet ) ); - } - } - } - } - } - - /****************************** Wait for OTA Thread. ******************************/ - - if( returnStatus == EXIT_SUCCESS ) - { - returnJoin = pthread_join( threadHandle, NULL ); - - if( returnJoin != 0 ) - { - LogError( ( "Failed to join thread" - ",error code = %d", - returnJoin ) ); - - returnStatus = EXIT_FAILURE; - } - } - - return returnStatus; -} - -/*-----------------------------------------------------------*/ - -/** - * @brief Entry point of demo. - * - * This example initializes the OTA library to enable OTA updates via the - * MQTT broker. It simply connects to the MQTT broker with the users - * credentials and spins in an indefinite loop to allow MQTT messages to be - * forwarded to the OTA agent for possible processing. The OTA agent does all - * of the real work; checking to see if the message topic is one destined for - * the OTA agent. If not, it is simply ignored. - */ -int main( int argc, - char ** argv ) -{ - ( void ) argc; - ( void ) argv; - - /* Return error status. */ - int returnStatus = EXIT_SUCCESS; - - /* Semaphore initialization flag. */ - bool bufferSemInitialized = false; - bool ackSemInitialized = false; - bool mqttMutexInitialized = false; - - /* Maximum time in milliseconds to wait before exiting demo . */ - int16_t waitTimeoutMs = OTA_DEMO_EXIT_TIMEOUT_MS; - - /* Initialize semaphore for buffer operations. */ - if( sem_init( &bufferSemaphore, 0, 1 ) != 0 ) - { - LogError( ( "Failed to initialize buffer semaphore" - ",errno=%s", - strerror( errno ) ) ); - - returnStatus = EXIT_FAILURE; - } - else - { - bufferSemInitialized = true; - } - - /* Initialize semaphore for ack. */ - if( sem_init( &ackSemaphore, 0, 0 ) != 0 ) - { - LogError( ( "Failed to initialize ack semaphore" - ",errno=%s", - strerror( errno ) ) ); - - returnStatus = EXIT_FAILURE; - } - else - { - ackSemInitialized = true; - } - - /* Initialize mutex for coreMQTT APIs. */ - if( pthread_mutex_init( &mqttMutex, NULL ) != 0 ) - { - LogError( ( "Failed to initialize mutex for mqtt apis" - ",errno=%s", - strerror( errno ) ) ); - - returnStatus = EXIT_FAILURE; - } - else - { - mqttMutexInitialized = true; - } - - if( returnStatus == EXIT_SUCCESS ) - { - /* Initialize MQTT library. Initialization of the MQTT library needs to be - * done only once in this demo. */ - returnStatus = initializeMqtt( &mqttContext, &networkContext ); - } - - if( returnStatus == EXIT_SUCCESS ) - { - /* Start OTA demo. */ - returnStatus = startOTADemo(); - } - - /* Disconnect from broker and close connection. */ - disconnect(); - - if( bufferSemInitialized == true ) - { - /* Cleanup semaphore created for buffer operations. */ - if( sem_destroy( &bufferSemaphore ) != 0 ) - { - LogError( ( "Failed to destroy buffer semaphore" - ",errno=%s", - strerror( errno ) ) ); - - returnStatus = EXIT_FAILURE; - } - } - - if( ackSemInitialized == true ) - { - /* Cleanup semaphore created for ack. */ - if( sem_destroy( &ackSemaphore ) != 0 ) - { - LogError( ( "Failed to destroy ack semaphore" - ",errno=%s", - strerror( errno ) ) ); - - returnStatus = EXIT_FAILURE; - } - } - - if( mqttMutexInitialized == true ) - { - /* Cleanup mutex created for MQTT operations. */ - if( pthread_mutex_destroy( &mqttMutex ) != 0 ) - { - LogError( ( "Failed to destroy mutex for mqtt apis" - ",errno=%s", - strerror( errno ) ) ); - - returnStatus = EXIT_FAILURE; - } - } - - /* Wait and log message before exiting demo. */ - while( waitTimeoutMs > 0 ) - { - Clock_SleepMs( OTA_EXAMPLE_TASK_DELAY_MS ); - waitTimeoutMs -= OTA_EXAMPLE_TASK_DELAY_MS; - - LogError( ( "Exiting demo in %d sec", waitTimeoutMs / 1000 ) ); - } - - return returnStatus; -} diff --git a/docs/doxygen/building.dox b/docs/doxygen/building.dox index ecd224277c..ac4386c9ed 100644 --- a/docs/doxygen/building.dox +++ b/docs/doxygen/building.dox @@ -23,8 +23,7 @@ Linux platform. This SDK builds with [CMake](https://cmake.org/), a cross-platfo @section aws_iot_setup AWS IoT Account Setup @brief Setting up AWS IoT to run demos. -You need to setup an AWS account and access the AWS IoT console for running the AWS IoT Device Shadow library, AWS IoT Device Defender library, AWS IoT Jobs library, -AWS IoT OTA library and coreHTTP S3 download demos. +You need to setup an AWS account and access the AWS IoT console for running the AWS IoT Device Shadow library, AWS IoT Device Defender library, AWS IoT Jobs library, and coreHTTP S3 download demos. Also, the AWS account can be used for running the MQTT mutual auth demo against AWS IoT broker. Note that running the AWS IoT Device Defender, AWS IoT Jobs and AWS IoT Device Shadow library demos require the setup of a Thing resource for the device running the demo. - [Setup an AWS account](https://portal.aws.amazon.com/billing/signup#/start). @@ -111,56 +110,6 @@ Note: A pre-signed GET URL is required for all HTTP S3 demos. For upload demos, - `--key` : The name of the existing object you wish to download (GET), or the name of the object you wish to upload (PUT). - `--region` : The name of the region in which your S3 bucket was created. If this is not passed in, the region configured in AWS CLI (or us-east-1, if not configured) will be used. - -@section configuring_ota_demos Configuring the Over-the-air Update Demos -@brief Configurations and Prerequisites for the OTA Demo - -## Requirements for OTA demo - -### Prerequisites -
    -
  1. To perform a successful OTA update you would need to complete the prerequisites mentioned here: https://docs.aws.amazon.com/freertos/latest/userguide/ota-prereqs.html
  2. -
  3. A code signing certificate is required to authenticate the update. A code signing certificate based on the SHA-256 ECDSA algorithm will work with the current demos. An example of how to generate this kind of certificate can be found here: https://docs.aws.amazon.com/freertos/latest/userguide/ota-code-sign-cert-esp.html
  4. -
- -### Configuration -You will need to specify the following parameters in the file demo_config.h (located in `demos/ota/ota_demo_[mqtt/http]/`) - -
    -
  1. AWS_IOT_ENDPOINT: This is the endpoint for your account. The endpoint should be for the region that your thing was created in. This can be found by going to the AWS IoT Core console, pressing the “Settings” tab on the left hand side of the page. It is under the section labeled “Custom endpoint”.
  2. -
  3. CLIENT_CERT_PATH: This is the client certificate that was downloaded when you created your thing. The path specified needs to be either an absolute path, or a path that is relative to the “cloned-repo-root-dir/build/bin" directory where the demo will be ran from.
  4. -
  5. CLIENT_PRIVATE_KEY_PATH: This is the client private key that was downloaded when you created your thing. The path specified needs to be either an absolute path, or a path that is relative to the “cloned-repo-root-dir/build/bin" directory where the demo will be ran from.
  6. -
  7. CLIENT_IDENTIFIER: This is the name of the thing you created during the OTA Prerequisites section.
  8. -
- -An example expected output: -@code{sh} -#define AWS_IOT_ENDPOINT "endpoint##-ats.iot.us-west-2.amazonaws.com" -#define CLIENT_CERT_PATH "/home/ubuntu/certificates/thing#-certificate.pem.crt" -#define CLIENT_PRIVATE_KEY_PATH "/home/ubuntu/certificates/thing#-private.pem.key" -#define CLIENT_IDENTIFIER "testclient" -@endcode - -### Scheduling an OTA Update Job -After you build and run the initial executable you will have to create another executable and schedule an OTA update job with this image. -
    -
  1. Increase the version of the application by setting macro `APP_VERSION_BUILD` in demos/ota_demo_core_[mqtt/http]/demo_config.h to a different version than what is running.
  2. -
  3. Rebuild the application using @ref building_demo_commmandline from below into a different directory, say build-dir-2
  4. -
  5. Rename the demo executable to reflect the change, e.g. `mv ota_demo_core_mqtt ota_demo_core_mqtt2`
  6. -
  7. Create an OTA job: -
      -
    1. Go to the AWS IoT Core console console.aws.amazon.com/iot/ (https://console.aws.amazon.com/iot/)
    2. -
    3. Manage → Jobs → Create → Create a FreeRTOS OTA update job → Select `testclient` from the thing list
    4. -
    5. Sign a new firmware → Create a new profile → Select any SHA-ECDSA signing platform → Upload the code signing certificate(from prerequisites) and provide its path on the device.
    6. -
    7. Select the image → Select the bucket you created in prerequisites → Upload the binary build-dir-2/bin/ota_demo2
    8. -
    9. The path on device should be the complete path to place the executable and the binary name: eg /home/ubuntu/aws-iot-device-sdk-embedded-C-staging/build-dir/bin/ota_demo_core_mqtt2
    10. -
    11. Select the IAM role created in prerequisites
    12. -
    13. Create the Job -
    -
  8. -
  9. Run the initial executable again with the following command: `sudo ./ota_demo_core_mqtt or sudo ./ota_demo_core_http`
  10. -
- @section building_demo_commmandline Build Steps @brief How to build the demo applications on the command-line. diff --git a/docs/doxygen/config.doxyfile b/docs/doxygen/config.doxyfile index f5f62b49b9..419f3ae9ea 100644 --- a/docs/doxygen/config.doxyfile +++ b/docs/doxygen/config.doxyfile @@ -2345,7 +2345,6 @@ TAGFILES = libraries/standard/coreMQTT/docs/doxygen/output/mqtt.ta libraries/aws/device-defender-for-aws-iot-embedded-sdk/docs/doxygen/output/defender.tag=../../../../libraries/aws/device-defender-for-aws-iot-embedded-sdk/docs/doxygen/output/html \ libraries/aws/jobs-for-aws-iot-embedded-sdk/docs/doxygen/output/jobs.tag=../../../../libraries/aws/jobs-for-aws-iot-embedded-sdk/docs/doxygen/output/html \ libraries/standard/backoffAlgorithm/docs/doxygen/output/backoffalgorithm.tag=../../../../libraries/standard/backoffAlgorithm/docs/doxygen/output/html \ - libraries/aws/ota-for-aws-iot-embedded-sdk/docs/doxygen/output/ota.tag=../../../../libraries/aws/ota-for-aws-iot-embedded-sdk/docs/doxygen/output/html \ libraries/aws/fleet-provisioning-for-aws-iot-embedded-sdk/docs/doxygen/output/fleet_provisioning.tag=../../../../libraries/aws/fleet-provisioning-for-aws-iot-embedded-sdk/docs/doxygen/output/html \ libraries/aws/sigv4-for-aws-iot-embedded-sdk/docs/doxygen/output/sigV4.tag=../../../../libraries/aws/sigv4-for-aws-iot-embedded-sdk/docs/doxygen/output/html diff --git a/docs/doxygen/demos/demos_main.dox b/docs/doxygen/demos/demos_main.dox index 4978432915..8378fc940f 100644 --- a/docs/doxygen/demos/demos_main.dox +++ b/docs/doxygen/demos/demos_main.dox @@ -9,6 +9,5 @@ Demos for the following libraries are provided: - @subpage shadow_demo - @subpage jobs_demo - @subpage defender_demo -- @subpage ota_demos - @subpage fleet_provisioning_demo */ diff --git a/docs/doxygen/demos/ota_demo.dox b/docs/doxygen/demos/ota_demo.dox deleted file mode 100644 index 3b8fb114af..0000000000 --- a/docs/doxygen/demos/ota_demo.dox +++ /dev/null @@ -1,42 +0,0 @@ -/** -@page ota_demos AWS IoT Over-the-air Update -@brief These demos demonstrate usage of the AWS IoT Over-the-air Update library. - -@section ota_demo_core_mqtt OTA over MQTT Demo -@brief A demo of OTA library to perform a firmware update using coreMQTT for data operations. - -

-This example demonstrates the use of OTA library to perform a device firmware update. The Linux application acts as an OTA client and AWS Services(AWS IoT, S3, Jobs etc.) are used to -send an update to the client. The demo uses the coreMQTT library to establish a connection to AWS IoT , then subscribes to OTA specific MQTT topics to receive a job. -After a user schedules a job, the client begins the download using coreMQTT to request, ingest, and store the data blocks, with the help of tinyCBOR to encode the data stream. -Once the image is downloaded, the file key signature, version, and image is verified to reset and display a successful update. Workflow for the demo is as follows: -- User builds initial application with version 0.9.2. -- User runs the application, establishes a connection to AWS IoT, and awaits a job. -- User increases the application version to 0.9.3, and rebuilds the executable. -- User schedules an OTA Update Job with the newer executable. -- OTA client receives the job document and verifies all the parameters. -- The new firmware is downloaded using coreMQTT and tinyCBOR. This is then verified by the OTA client. -- User runs the downloaded executable to notify AWS IoT of a successful update and display it on the console and device logs. - -

- -
-OTA over coreMQTT Demo Workflow -
-@image html ota_demo_core_mqtt.svg width=50% - -@section ota_demo_core_http OTA over HTTP Demo -@brief A demo of OTA library to perform a firmware update using coreHTTP for data operations. - -

-This example is a modification of the above demo to securely send a firmware image to the device by using coreHTTP for data plane operations. -While it still uses MQTT for control operations like pending job notifications and updating job status, this demo uses HTTP instead of -MQTT to download the file. -

- -
-OTA over coreHTTP Demo Workflow -
-@image html ota_demo_core_http.svg width=50% - -*/ diff --git a/docs/doxygen/images/ota_demo_core_http.pu b/docs/doxygen/images/ota_demo_core_http.pu deleted file mode 100644 index 0600aa96d0..0000000000 --- a/docs/doxygen/images/ota_demo_core_http.pu +++ /dev/null @@ -1,182 +0,0 @@ -@startuml -skinparam dpi 300 -skinparam classFontSize 8 -skinparam classFontName Helvetica -autonumber - -box "Application" #Mistyrose -participant OTADemo -end box -box "OTA Library" #LightGreen -participant OTAAgent -participant OTAPal -end box -box "Connectivity Libraries" #LightBlue -participant MQTT -participant HTTP -end box -box "Cloud AWS IoT \nService" #Darksalmon -participant AWSIoT - -== Initialization == -OTADemo -> MQTT : Create MQTT connection -activate OTADemo -activate MQTT -MQTT -> AWSIoT : Send data to server -activate AWSIoT -MQTT <-- AWSIoT -deactivate AWSIoT -OTADemo <-- MQTT -deactivate MQTT - -OTADemo -> OTAAgent :Initialize OTAAgent -activate OTAAgent -OTADemo <-- OTAAgent - -OTAAgent -> OTADemo : Subscibe to Job notification topics -deactivate OTAAgent -OTADemo -> MQTT : Subscribe -activate MQTT -MQTT -> AWSIoT : Send data to server -activate AWSIoT -MQTT <-- AWSIoT -deactivate AWSIoT -OTADemo <-- MQTT -deactivate -activate OTAAgent -OTADemo --> OTAAgent -deactivate OTADemo - -== Job Parsing == -OTAAgent -> OTAAgent : Wait for \nJob -MQTT <- AWSIoT : Job notification from server -deactivate OTAAgent -activate AWSIoT -activate MQTT -MQTT --> AWSIoT -deactivate AWSIoT - -MQTT -> OTADemo : MQTT Job callback -activate OTADemo -deactivate MQTT -OTADemo -> OTAAgent : Send Job Received event -activate OTAAgent -deactivate OTADemo -OTAAgent -> OTAAgent : Parse Job Document (json) (*2) -deactivate OTAAgent -== Connection Management == - -MQTT -> OTADemo : MQTT Disconnect Callback - -activate MQTT - -activate OTADemo -OTADemo -> OTAAgent : Suspend OTA -activate OTAAgent -deactivate MQTT -OTAAgent --> OTADemo -deactivate OTAAgent - -loop till connection succeed or max retries - -OTADemo -> MQTT : Re-connect MQTT -activate MQTT -MQTT -> AWSIoT : Send data to server -activate AWSIoT -MQTT <-- AWSIoT -deactivate AWSIoT -OTADemo <-- MQTT : Timeout -deactivate MQTT - -OTADemo -> OTADemo : Exponential Delay( multiplied by 2) -deactivate MQTT -end -OTADemo -> OTAAgent : Resume OTA Agent -deactivate OTADemo -activate OTAAgent - -== File Download == - -OTAAgent -> OTAPal : Create File for download -activate OTAPal -OTAAgent <-- OTAPal -deactivate OTAPal -loop Till file download is complete -OTAAgent -> OTADemo : Request File blocks -deactivate OTAAgent -activate OTADemo -activate HTTP -OTADemo -> HTTP : GET Request -HTTP -> AWSIoT : Send data to server -deactivate OTADemo -activate AWSIoT -HTTP <- AWSIoT : Packet containing\nfile blocks -deactivate AWSIoT -activate OTADemo -HTTP -> OTADemo : HTTP Response -deactivate HTTP -OTADemo -> OTAAgent : Process file block -deactivate MQTT -deactivate OTADemo -activate OTAAgent - -OTAAgent -> OTAAgent : Decode File Blocks (cbor) (*4) -OTAAgent -> OTAPal : Write File Blocks -activate OTAPal - -alt If last file block -OTAPal -> OTAPal : Verify cypto\nsignature -end -OTAAgent <-- OTAPal -deactivate OTAPal - - -alt Every 64(default) file blocks received -activate OTADemo -OTAAgent -> OTADemo : Update Job -deactivate OTAAgent -OTADemo -> MQTT : Publish - -activate MQTT -MQTT -> AWSIoT : Send data to server -activate AWSIoT -MQTT <-- AWSIoT -deactivate AWSIoT -MQTT --> OTADemo -deactivate MQTT -deactivate OTADemo -end -end -activate OTAAgent -== Activating Image == - -OTAAgent -> OTAPal : Set boot flags -activate OTAPal -OTAAgent <-- OTAPal -deactivate OTAPal -deactivate OTAAgent -activate OTADemo -activate MQTT -OTAAgent -> OTADemo : Update Job status -OTADemo -> MQTT : Publish - -MQTT -> AWSIoT : Send data to server -activate AWSIoT -MQTT <-- AWSIoT -deactivate AWSIoT -MQTT --> OTADemo -deactivate MQTT - -OTAAgent -> OTADemo : Callback for activation -activate OTADemo -OTADemo --> OTAAgent -deactivate OTADemo - -OTAAgent -> OTAPal : Activate Image -deactivate OTAAgent -activate OTAPal -OTAPal -> OTAPal :Reset -deactivate OTAPal -deactivate OTAAgent - -@enduml \ No newline at end of file diff --git a/docs/doxygen/images/ota_demo_core_http.svg b/docs/doxygen/images/ota_demo_core_http.svg deleted file mode 100644 index d6a364102f..0000000000 --- a/docs/doxygen/images/ota_demo_core_http.svg +++ /dev/null @@ -1,191 +0,0 @@ -ApplicationOTA LibraryConnectivity LibrariesCloud AWS IoTServiceOTADemoOTADemoOTAAgentOTAAgentOTAPalOTAPalMQTTMQTTHTTPHTTPAWSIoTAWSIoTInitialization1Create MQTT connection2Send data to server345Initialize OTAAgent67Subscibe to Job notification topics8Subscribe9Send data to server101112Job Parsing13Wait forJob14Job notification from server1516MQTT Job callback17Send Job Received event18Parse Job Document (json) (*2)Connection Management19MQTT Disconnect Callback20Suspend OTA21loop[till connection succeed or max retries]22Re-connect MQTT23Send data to server2425Timeout26Exponential Delay( multiplied by 2)27Resume OTA AgentFile Download28Create File for download29loop[Till file download is complete]30Request File blocks31GET Request32Send data to server33Packet containingfile blocks34HTTP Response35Process file block36Decode File Blocks (cbor) (*4)37Write File Blocksalt[If last file block]38Verify cyptosignature39alt[Every 64(default) file blocks received]40Update Job41Publish42Send data to server4344Activating Image45Set boot flags4647Update Job status48Publish49Send data to server505152Callback for activation5354Activate Image55Reset \ No newline at end of file diff --git a/docs/doxygen/images/ota_demo_core_mqtt.pu b/docs/doxygen/images/ota_demo_core_mqtt.pu deleted file mode 100644 index 8d8a498517..0000000000 --- a/docs/doxygen/images/ota_demo_core_mqtt.pu +++ /dev/null @@ -1,182 +0,0 @@ -@startuml -skinparam dpi 300 -skinparam classFontSize 8 -skinparam classFontName Helvetica -autonumber - -box "Application" #Mistyrose -participant OTADemo -end box -box "OTA Library" #LightGreen -participant OTAAgent -participant OTAPal -end box -box "Connectivity Libraries" #LightBlue -participant MQTT -end box -box "Cloud AWS IoT \nService" #Darksalmon -participant AWSIoT - -== Initialization == -OTADemo -> MQTT : Create MQTT connection -activate OTADemo -activate MQTT -MQTT -> AWSIoT : Send data to server -activate AWSIoT -MQTT <-- AWSIoT -deactivate AWSIoT -OTADemo <-- MQTT -deactivate MQTT - -OTADemo -> OTAAgent :Initialize OTAAgent -activate OTAAgent -OTADemo <-- OTAAgent - -OTAAgent -> OTADemo : Subscibe to Job\n& Data Topics(*1) -deactivate OTAAgent -OTADemo -> MQTT : Subscribe -activate MQTT -MQTT -> AWSIoT : Send data to server -activate AWSIoT -MQTT <-- AWSIoT -deactivate AWSIoT -OTADemo <-- MQTT -deactivate -activate OTAAgent -OTADemo --> OTAAgent -deactivate OTADemo - -== Job Parsing == -OTAAgent -> OTAAgent : Wait for \nJob -MQTT <- AWSIoT : Job notification from server -deactivate OTAAgent -activate AWSIoT -activate MQTT -MQTT --> AWSIoT -deactivate AWSIoT - -MQTT -> OTADemo : MQTT Job callback -activate OTADemo -deactivate MQTT -OTADemo -> OTAAgent : Send Job Received event -activate OTAAgent -deactivate OTADemo -OTAAgent -> OTAAgent : Parse Job Document (json) (*2) -deactivate OTAAgent -== Connection Management == - -MQTT -> OTADemo : MQTT Disconnect Callback - -activate MQTT - -activate OTADemo -OTADemo -> OTAAgent : Suspend OTA -activate OTAAgent -deactivate MQTT -OTAAgent --> OTADemo -deactivate OTAAgent - -loop till connection succeed or max retries - -OTADemo -> MQTT : Re-connect MQTT -activate MQTT -MQTT -> AWSIoT : Send data to server -activate AWSIoT -MQTT <-- AWSIoT -deactivate AWSIoT -OTADemo <-- MQTT : Timeout -deactivate MQTT - -OTADemo -> OTADemo : Exponential Delay( multiplied by 2) -deactivate MQTT -end -OTADemo -> OTAAgent : Resume OTA Agent -deactivate OTADemo -activate OTAAgent - -== File Download == - -OTAAgent -> OTAPal : Create File for download -activate OTAPal -OTAAgent <-- OTAPal -deactivate OTAPal -loop Till file download is complete -OTAAgent -> OTADemo : Request File blocks (cbor) (*3) -deactivate OTAAgent -activate OTADemo -activate MQTT -OTADemo -> MQTT : publish -MQTT -> AWSIoT : Send data to server -deactivate OTADemo -activate AWSIoT -MQTT <-- AWSIoT -MQTT <- AWSIoT : Packet containing\nfile blocks -deactivate AWSIoT -activate OTADemo -MQTT -> OTADemo : MQTT Data callback - -OTADemo -> OTAAgent : Process file block -deactivate MQTT -deactivate OTADemo -activate OTAAgent - -OTAAgent -> OTAAgent : Decode File Blocks (cbor) (*4) -OTAAgent -> OTAPal : Write File Blocks -activate OTAPal - -alt If last file block -OTAPal -> OTAPal : Verify cypto\nsignature -end -OTAAgent <-- OTAPal -deactivate OTAPal - - -alt Every 64(default) file blocks received -activate OTADemo -OTAAgent -> OTADemo : Update Job -deactivate OTAAgent -OTADemo -> MQTT : Publish - -activate MQTT -MQTT -> AWSIoT : Send data to server -activate AWSIoT -MQTT <-- AWSIoT -deactivate AWSIoT -MQTT --> OTADemo -deactivate MQTT -deactivate OTADemo -end -end -activate OTAAgent -== Activating Image == - -OTAAgent -> OTAPal : Set boot flags -activate OTAPal -OTAAgent <-- OTAPal -deactivate OTAPal -deactivate OTAAgent -activate OTADemo -activate MQTT -OTAAgent -> OTADemo : Update Job status -OTADemo -> MQTT : Publish - -MQTT -> AWSIoT : Send data to server -activate AWSIoT -MQTT <-- AWSIoT -deactivate AWSIoT -MQTT --> OTADemo -deactivate MQTT - -OTAAgent -> OTADemo : Callback for activation -activate OTADemo -OTADemo --> OTAAgent -deactivate OTADemo - -OTAAgent -> OTAPal : Activate Image -deactivate OTAAgent -activate OTAPal -OTAPal -> OTAPal :Reset -deactivate OTAPal -deactivate OTAAgent - -@enduml \ No newline at end of file diff --git a/docs/doxygen/images/ota_demo_core_mqtt.svg b/docs/doxygen/images/ota_demo_core_mqtt.svg deleted file mode 100644 index 167087e273..0000000000 --- a/docs/doxygen/images/ota_demo_core_mqtt.svg +++ /dev/null @@ -1,191 +0,0 @@ -ApplicationOTA LibraryConnectivity LibrariesCloud AWS IoTServiceOTADemoOTADemoOTAAgentOTAAgentOTAPalOTAPalMQTTMQTTAWSIoTAWSIoTInitialization1Create MQTT connection2Send data to server345Initialize OTAAgent67Subscibe to Job& Data Topics(*1)8Subscribe9Send data to server101112Job Parsing13Wait forJob14Job notification from server1516MQTT Job callback17Send Job Received event18Parse Job Document (json) (*2)Connection Management19MQTT Disconnect Callback20Suspend OTA21loop[till connection succeed or max retries]22Re-connect MQTT23Send data to server2425Timeout26Exponential Delay( multiplied by 2)27Resume OTA AgentFile Download28Create File for download29loop[Till file download is complete]30Request File blocks (cbor) (*3)31publish32Send data to server3334Packet containingfile blocks35MQTT Data callback36Process file block37Decode File Blocks (cbor) (*4)38Write File Blocksalt[If last file block]39Verify cyptosignature40alt[Every 64(default) file blocks received]41Update Job42Publish43Send data to server4445Activating Image46Set boot flags4748Update Job status49Publish50Send data to server515253Callback for activation5455Activate Image56Reset \ No newline at end of file diff --git a/docs/doxygen/pages.dox b/docs/doxygen/pages.dox index 155c21c44a..06bf54c442 100644 --- a/docs/doxygen/pages.dox +++ b/docs/doxygen/pages.dox @@ -11,7 +11,6 @@ The following libraries (along with their source repositories) are part of this - [AWS IoT Device Shadow client](@ref shadow) - [device-shadow-for-aws-iot-embedded-sdk](https://github.com/aws/device-shadow-for-aws-iot-embedded-sdk) - [AWS IoT Device Defender client](@ref defender) - [device-defender-for-aws-iot-embedded-sdk](https://github.com/aws/device-defender-for-aws-iot-embedded-sdk) - [AWS IoT Jobs client](@ref jobs) - [jobs-for-aws-iot-embedded-sdk](https://github.com/aws/jobs-for-aws-iot-embedded-sdk) -- [AWS IoT Over-the-air Update Library](@ref ota) - [ota-for-aws-iot-embedded-sdk](https://github.com/aws/ota-for-aws-iot-embedded-sdk) - [AWS IoT Fleet Provisioning Library](@ref fleet_provisioning) - [fleet-provisioning-for-aws-iot-embedded-sdk](https://github.com/aws/fleet-provisioning-for-aws-iot-embedded-sdk) - [AWS SigV4 Library](@ref sigv4) - [sigv4-for-aws-iot-embedded-sdk](https://github.com/aws/sigv4-for-aws-iot-embedded-sdk) */ diff --git a/libraries/3rdparty/CMakeLists.txt b/libraries/3rdparty/CMakeLists.txt index b6ac6ac419..84b02598c4 100644 --- a/libraries/3rdparty/CMakeLists.txt +++ b/libraries/3rdparty/CMakeLists.txt @@ -77,7 +77,7 @@ target_include_directories(mbedtls target_compile_definitions( mbedtls PUBLIC - -DMBEDTLS_CONFIG_FILE="mbedtls_config.h" + -DMBEDTLS_CONFIG_FILE="${ROOT_DIR}/platform/posix/include/mbedtls_config.h" ) set_source_files_properties( diff --git a/libraries/3rdparty/CMock b/libraries/3rdparty/CMock index 150573c742..9d092898ef 160000 --- a/libraries/3rdparty/CMock +++ b/libraries/3rdparty/CMock @@ -1 +1 @@ -Subproject commit 150573c742ce15061a0b675aa0f8e29c85008062 +Subproject commit 9d092898ef26ece140d9225e037274b64d4f851e diff --git a/libraries/3rdparty/mbedtls b/libraries/3rdparty/mbedtls index 8b3f26a5ac..edb8fec988 160000 --- a/libraries/3rdparty/mbedtls +++ b/libraries/3rdparty/mbedtls @@ -1 +1 @@ -Subproject commit 8b3f26a5ac38d4fdccbc5c5366229f3e01dafcc0 +Subproject commit edb8fec9882084344a314368ac7fd957a187519c diff --git a/libraries/3rdparty/tinycbor b/libraries/3rdparty/tinycbor index 9924cfed3b..d393c16f3e 160000 --- a/libraries/3rdparty/tinycbor +++ b/libraries/3rdparty/tinycbor @@ -1 +1 @@ -Subproject commit 9924cfed3b95ad6de299ae675064430fdb886216 +Subproject commit d393c16f3eb30d0c47e6f9d92db62272f0ec4dc7 diff --git a/libraries/aws/device-defender-for-aws-iot-embedded-sdk b/libraries/aws/device-defender-for-aws-iot-embedded-sdk index 747ae050e1..7059e19914 160000 --- a/libraries/aws/device-defender-for-aws-iot-embedded-sdk +++ b/libraries/aws/device-defender-for-aws-iot-embedded-sdk @@ -1 +1 @@ -Subproject commit 747ae050e1d22682c8c757fff48dba2760094505 +Subproject commit 7059e199149a540471b484b710a51fc665636f22 diff --git a/libraries/aws/device-shadow-for-aws-iot-embedded-sdk b/libraries/aws/device-shadow-for-aws-iot-embedded-sdk index 0c17830735..268a5a276d 160000 --- a/libraries/aws/device-shadow-for-aws-iot-embedded-sdk +++ b/libraries/aws/device-shadow-for-aws-iot-embedded-sdk @@ -1 +1 @@ -Subproject commit 0c17830735d83fe1e399af056820de0f4666f43c +Subproject commit 268a5a276d3c3f451575b5a042b4e8ad53f134b6 diff --git a/libraries/aws/fleet-provisioning-for-aws-iot-embedded-sdk b/libraries/aws/fleet-provisioning-for-aws-iot-embedded-sdk index 8ce2b28325..a97d53af33 160000 --- a/libraries/aws/fleet-provisioning-for-aws-iot-embedded-sdk +++ b/libraries/aws/fleet-provisioning-for-aws-iot-embedded-sdk @@ -1 +1 @@ -Subproject commit 8ce2b28325efb917c2e357aed2361e3fa6162ecf +Subproject commit a97d53af335f135c6ee9d608a3e80be8a3009a89 diff --git a/libraries/aws/jobs-for-aws-iot-embedded-sdk b/libraries/aws/jobs-for-aws-iot-embedded-sdk index 3e33c6a0ee..3ce91f5642 160000 --- a/libraries/aws/jobs-for-aws-iot-embedded-sdk +++ b/libraries/aws/jobs-for-aws-iot-embedded-sdk @@ -1 +1 @@ -Subproject commit 3e33c6a0eeaebb820a445a3d4b1a02896b3e557d +Subproject commit 3ce91f56427653705891a8668568cb247b97905f diff --git a/libraries/aws/ota-for-aws-iot-embedded-sdk b/libraries/aws/ota-for-aws-iot-embedded-sdk deleted file mode 160000 index 406415ef38..0000000000 --- a/libraries/aws/ota-for-aws-iot-embedded-sdk +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 406415ef38d9f0fbabd69735623008fd090043b3 diff --git a/libraries/aws/sigv4-for-aws-iot-embedded-sdk b/libraries/aws/sigv4-for-aws-iot-embedded-sdk index e828353290..68e0364a88 160000 --- a/libraries/aws/sigv4-for-aws-iot-embedded-sdk +++ b/libraries/aws/sigv4-for-aws-iot-embedded-sdk @@ -1 +1 @@ -Subproject commit e82835329069d804e0db883d69eb4e1124dd7f08 +Subproject commit 68e0364a883f0ededb6b43af9e271e469065dac3 diff --git a/libraries/standard/backoffAlgorithm b/libraries/standard/backoffAlgorithm index f4b3fcfe92..3cc0bf8c4d 160000 --- a/libraries/standard/backoffAlgorithm +++ b/libraries/standard/backoffAlgorithm @@ -1 +1 @@ -Subproject commit f4b3fcfe92002a3a7609e511fd05361b9e812021 +Subproject commit 3cc0bf8c4d41d7cd7aa2f1ded5075c87bf6b2bbb diff --git a/libraries/standard/coreHTTP b/libraries/standard/coreHTTP index 1749807ef2..12adee81dd 160000 --- a/libraries/standard/coreHTTP +++ b/libraries/standard/coreHTTP @@ -1 +1 @@ -Subproject commit 1749807ef26d17cc8e5a14ad1c57aba62ffb5b21 +Subproject commit 12adee81ddef588abada91672b34fd997b2a27ac diff --git a/libraries/standard/coreJSON b/libraries/standard/coreJSON index 8d216b5876..e3b7663f63 160000 --- a/libraries/standard/coreJSON +++ b/libraries/standard/coreJSON @@ -1 +1 @@ -Subproject commit 8d216b5876ba6953e8b60a20d32eae62992d09fe +Subproject commit e3b7663f6392d8c10e8db57506ec37e4801b145a diff --git a/libraries/standard/coreMQTT b/libraries/standard/coreMQTT index 000a574c0e..2beef04725 160000 --- a/libraries/standard/coreMQTT +++ b/libraries/standard/coreMQTT @@ -1 +1 @@ -Subproject commit 000a574c0eb7dcaa68caf3e70f06b32d8568c1d1 +Subproject commit 2beef04725328923e05e576b884212d53ec97af7 diff --git a/libraries/standard/corePKCS11 b/libraries/standard/corePKCS11 index c671c11f2d..a923b213d3 160000 --- a/libraries/standard/corePKCS11 +++ b/libraries/standard/corePKCS11 @@ -1 +1 @@ -Subproject commit c671c11f2de13c31e8eb9563858fb513b4c5b678 +Subproject commit a923b213d33c6538e92ba3c7971b2d859f881afb diff --git a/manifest.yml b/manifest.yml index 005ca373b6..6d81b2a482 100644 --- a/manifest.yml +++ b/manifest.yml @@ -1,5 +1,5 @@ name : "AWS_IoT_Device_SDK_for_Embedded_C" -version: "202211.00" +version: "202412.00" description: |- "The AWS IoT Device SDK for Embedded C is a collection of C source files that can be used in embedded applications to securely connect @@ -8,67 +8,61 @@ description: |- See dependencies for included libraries." dependencies: - name: "coreMQTT" - version: "000a574c0eb7dcaa68caf3e70f06b32d8568c1d1" + version: "v2.3.1" repository: type: "git" url: "https://github.com/FreeRTOS/coreMQTT" path: "libraries/standard/coreMQTT" - name: "coreJSON" - version: "8d216b5876ba6953e8b60a20d32eae62992d09fe" + version: "v3.3.0" repository: type: "git" url: "https://github.com/FreeRTOS/coreJSON" path: "libraries/standard/coreJSON" - name: "Device-Shadow-for-AWS-IoT-embedded-sdk" - version: "0c17830735d83fe1e399af056820de0f4666f43c" + version: "v1.4.1" repository: type: "git" url: "https://github.com/aws/Device-Shadow-for-AWS-IoT-embedded-sdk" path: "libraries/aws/device-shadow-for-aws-iot-embedded-sdk" - name: "coreHTTP" - version: "1749807ef26d17cc8e5a14ad1c57aba62ffb5b21" + version: "v3.1.1" repository: type: "git" url: "https://github.com/FreeRTOS/coreHTTP" path: "libraries/standard/coreHTTP" - name: "Device-Defender-for-AWS-IoT-embedded-sdk" - version: "747ae050e1d22682c8c757fff48dba2760094505" + version: "v1.4.0" repository: type: "git" url: "https://github.com/aws/Device-Defender-for-AWS-IoT-embedded-sdk" path: "libraries/aws/device-defender-for-aws-iot-embedded-sdk" - name: "Jobs-for-AWS-IoT-embedded-sdk" - version: "3e33c6a0eeaebb820a445a3d4b1a02896b3e557d" + version: "v1.5.1" repository: type: "git" url: "https://github.com/aws/Jobs-for-AWS-IoT-embedded-sdk" path: "libraries/aws/jobs-for-aws-iot-embedded-sdk" - - name: "OTA-for-AWS-IoT-embedded-sdk" - version: "406415ef38d9f0fbabd69735623008fd090043b3" - repository: - type: "git" - url: "https://github.com/aws/ota-for-aws-iot-embedded-sdk" - path: "libraries/aws/ota-for-aws-iot-embedded-sdk" - name: "backoffAlgorithm" - version: "f4b3fcfe92002a3a7609e511fd05361b9e812021" + version: "v1.4.1" repository: type: "git" url: "https://github.com/FreeRTOS/backoffAlgorithm" path: "libraries/standard/backoffAlgorithm" - name: "corePKCS11" - version: "c671c11f2de13c31e8eb9563858fb513b4c5b678" + version: "v3.6.1" repository: type: "git" url: "https://github.com/FreeRTOS/corePKCS11" path: "libraries/standard/corePKCS11" - name: "Fleet-Provisioning-for-AWS-IoT-embedded-sdk" - version: "8ce2b28325efb917c2e357aed2361e3fa6162ecf" + version: "v1.2.1" repository: type: "git" url: "https://github.com/aws/Fleet-Provisioning-for-AWS-IoT-embedded-sdk" path: "libraries/aws/fleet-provisioning-for-aws-iot-embedded-sdk" - name: "sigv4-for-AWS-IoT-embedded-sdk" - version: "e82835329069d804e0db883d69eb4e1124dd7f08" + version: "v1.3.0" repository: type: "git" url: "https://github.com/aws/SigV4-for-AWS-IoT-embedded-sdk" diff --git a/platform/CMakeLists.txt b/platform/CMakeLists.txt index 6f1e95faf9..923ee46bd5 100644 --- a/platform/CMakeLists.txt +++ b/platform/CMakeLists.txt @@ -19,6 +19,3 @@ find_library(LIB_RT ${LIB_RT_NAME}) # Add the posix targets add_subdirectory( ${PLATFORM_DIR}/posix ) - -# Add ota porting targets -add_subdirectory( ${PLATFORM_DIR}/posix/ota_pal ) diff --git a/platform/lexicon.txt b/platform/lexicon.txt index dd456f2945..65474b8a0d 100644 --- a/platform/lexicon.txt +++ b/platform/lexicon.txt @@ -141,48 +141,6 @@ openssl openssl_invalid_parameter org ota -otafile -otaimagestateaborted -otaimagestateaccepted -otaimagestateinvalid -otaimagestatependingcommit -otaimagestaterejected -otaimagestaterejected -otaimagestatetesting -otaimagestateunknown -otalastimagestate -otapal_closefile -otapalabortfailed -otapalactivatefailed -otapalbadimagestate -otapalbadsignercert -otapalbootinfocreatefailed -otapalbufferinsufficient -otapalcommitfailed -otapalcwdfailed -otapalfileabort -otapalfileclose -otapalfilegensuccess -otapalimagestateinvalid -otapalimagestatependingcommit -otapalimagestateunknown -otapalimagestatevalid -otapalnullfilecontext -otapalnullfilecontext -otapaloutofmemory -otapaloutofmemory -otapalrejectfailed -otapalrejectfailed -otapalrxfilecreatefailed -otapalrxfilecreatefailed -otapalrxfiletoolarge -otapalrxfiletoolarge -otapalsignaturecheckfailed -otapalsignaturecheckfailed -otapalsuccess -otapalsuccess -otapaluninitialized -otapaluninitialized paddrinfo palpnprotos param diff --git a/platform/posix/include/mbedtls_config.h b/platform/posix/include/mbedtls_config.h index 9d2047ab28..d2b1a90607 100644 --- a/platform/posix/include/mbedtls_config.h +++ b/platform/posix/include/mbedtls_config.h @@ -81,7 +81,9 @@ #define MBEDTLS_CTR_DRBG_C #define MBEDTLS_DEBUG_C #define MBEDTLS_ECDH_C +#define MBEDTLS_CAN_ECDH #define MBEDTLS_ECDSA_C +#define MBEDTLS_PK_CAN_ECDSA_SIGN #define MBEDTLS_ECP_C #define MBEDTLS_ENTROPY_C #define MBEDTLS_ERROR_C diff --git a/platform/posix/ota_pal/CMakeLists.txt b/platform/posix/ota_pal/CMakeLists.txt deleted file mode 100644 index c4a08096ec..0000000000 --- a/platform/posix/ota_pal/CMakeLists.txt +++ /dev/null @@ -1,15 +0,0 @@ -add_library(ota_pal INTERFACE) -target_sources(ota_pal - INTERFACE - "${CMAKE_CURRENT_SOURCE_DIR}/source/ota_pal_posix.c" -) - -target_include_directories( ota_pal - INTERFACE - ${CMAKE_CURRENT_LIST_DIR}/source/include - ${LOGGING_INCLUDE_DIRS} -) - -target_link_libraries( ota_pal - INTERFACE ${OPENSSL_CRYPTO_LIBRARY} -) diff --git a/platform/posix/ota_pal/source/include/ota_pal_posix.h b/platform/posix/ota_pal/source/include/ota_pal_posix.h deleted file mode 100644 index 12a59645fb..0000000000 --- a/platform/posix/ota_pal/source/include/ota_pal_posix.h +++ /dev/null @@ -1,229 +0,0 @@ -/* - * OTA PAL V2.0.1 for POSIX - * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef _OTA_PAL_H_ -#define _OTA_PAL_H_ - -/* *INDENT-OFF* */ -#ifdef __cplusplus - extern "C" { -#endif -/* *INDENT-ON* */ - -#include "ota.h" - -/** - * @brief Maximum file path length on Linux - */ -#define OTA_FILE_PATH_LENGTH_MAX 512 - -/** - * @brief The OTA platform interface status for generating - * absolute file path from the incoming relative file path. - */ -typedef enum OtaPalPathGenStatus -{ - OtaPalFileGenSuccess, /*!< @brief Absolute path generation success. */ - OtaPalCWDFailed, /*!< @brief getcwd failed to output path. */ - OtaPalBufferInsufficient /*!< @brief Buffer insufficient for storing the file path. */ -} OtaPalPathGenStatus_t; - -/** - * @brief Abort an OTA transfer. - * - * Aborts access to an existing open file represented by the OTA file context C. This is - * only valid for jobs that started successfully. - * - * @note The input OtaFileContext_t C is checked for NULL by the OTA agent before this - * function is called. - * This function may be called before the file is opened, so the file pointer C->fileHandle - * may be NULL when this function is called. - * - * @param[in] C OTA file context information. - * - * @return The OTA PAL layer error code combined with the MCU specific error code. See OTA Agent - * error codes information in ota.h. - * - * The file pointer will be set to NULL after this function returns. - * OtaPalSuccess is returned when aborting access to the open file was successful. - * OtaPalFileAbort is returned when aborting access to the open file context was unsuccessful. - */ -OtaPalStatus_t otaPal_Abort( OtaFileContext_t * const C ); - -/** - * @brief Create a new receive file for the data chunks as they come in. - * - * @note Opens the file indicated in the OTA file context in the MCU file system. - * - * @note The previous image may be present in the designated image download partition or file, so the - * partition or file must be completely erased or overwritten in this routine. - * - * @note The input OtaFileContext_t C is checked for NULL by the OTA agent before this - * function is called. - * The device file path is a required field in the OTA job document, so C->pFilePath is - * checked for NULL by the OTA agent before this function is called. - * - * @param[in] C OTA file context information. - * - * @return The OTA PAL layer error code combined with the MCU specific error code. See OTA Agent - * error codes information in ota.h. - * - * OtaPalSuccess is returned when file creation is successful. - * OtaPalRxFileTooLarge is returned if the file to be created exceeds the device's non-volatile memory size constraints. - * OtaPalBootInfoCreateFailed is returned if the bootloader information file creation fails. - * OtaPalRxFileCreateFailed is returned for other errors creating the file in the device's non-volatile memory. - */ -OtaPalStatus_t otaPal_CreateFileForRx( OtaFileContext_t * const C ); - -/* @brief Authenticate and close the underlying receive file in the specified OTA context. - * - * @note The input OtaFileContext_t C is checked for NULL by the OTA agent before this - * function is called. This function is called only at the end of block ingestion. - * otaPal_CreateFileForRx() must succeed before this function is reached, so - * C->fileHandle(or C->pFile) is never NULL. - * The certificate path on the device is a required job document field in the OTA Agent, - * so C->pCertFilepath is never NULL. - * The file signature key is required job document field in the OTA Agent, so C->pSignature will - * never be NULL. - * - * If the signature verification fails, file close should still be attempted. - * - * @param[in] C OTA file context information. - * - * @return The OTA PAL layer error code combined with the MCU specific error code. See OTA Agent - * error codes information in ota.h. - * - * OtaPalSuccess is returned on success. - * OtaPalSignatureCheckFailed is returned when cryptographic signature verification fails. - * OtaPalBadSignerCert is returned for errors in the certificate itself. - * OtaPalFileClose is returned when closing the file fails. - */ -OtaPalStatus_t otaPal_CloseFile( OtaFileContext_t * const C ); - -/** - * @brief Write a block of data to the specified file at the given offset. - * - * @note The input OtaFileContext_t C is checked for NULL by the OTA agent before this - * function is called. - * The file pointer/handle C->pFile, is checked for NULL by the OTA agent before this - * function is called. - * pData is checked for NULL by the OTA agent before this function is called. - * blockSize is validated for range by the OTA agent before this function is called. - * offset is validated by the OTA agent before this function is called. - * - * @param[in] C OTA file context information. - * @param[in] offset Byte offset to write to from the beginning of the file. - * @param[in] pData Pointer to the byte array of data to write. - * @param[in] blockSize The number of bytes to write. - * - * @return The number of bytes written on a success, or a negative error code from the platform - * abstraction layer. - */ -int16_t otaPal_WriteBlock( OtaFileContext_t * const C, - uint32_t ulOffset, - uint8_t * const pcData, - uint32_t ulBlockSize ); - -/** - * @brief Activate the newest MCU image received via OTA. - * - * This function activates the newest firmware received via OTA. It is typically just a reset of - * the device. - * - * @note This function SHOULD not return. If it does, the platform does not support - * an automatic reset or an error occurred. - * - * @return The OTA PAL layer error code combined with the MCU specific error code. See OTA Agent - * error codes information in ota.h. - */ -OtaPalStatus_t otaPal_ActivateNewImage( OtaFileContext_t * const C ); - -/** - * @brief Reset the device. - * - * This function shall reset the MCU and cause a reboot of the system. - * - * @note This function SHOULD not return. If it does, the platform does not support - * an automatic reset or an error occurred. - * - * @return The OTA PAL layer error code combined with the MCU specific error code. See OTA Agent - * error codes information in ota.h. - */ - -OtaPalStatus_t otaPal_ResetDevice( OtaFileContext_t * const C ); - -/** - * @brief Attempt to set the state of the OTA update image. - * - * Do whatever is required by the platform to Accept/Reject the OTA update image (or bundle). - * Refer to the PAL implementation to determine what happens on your platform. - * - * @param[in] C File context of type OtaFileContext_t. - * - * @param[in] eState The desired state of the OTA update image. - * - * @return The OtaPalStatus_t error code combined with the MCU specific error code. See ota.h for - * OTA major error codes and your specific PAL implementation for the sub error code. - * - * Major error codes returned are: - * - * OtaPalSuccess on success. - * OtaPalBadImageState: if you specify an invalid OtaImageState_t. No sub error code. - * OtaPalAbortFailed: failed to roll back the update image as requested by OtaImageStateAborted. - * OtaPalRejectFailed: failed to roll back the update image as requested by OtaImageStateRejected. - * OtaPalCommitFailed: failed to make the update image permanent as requested by OtaImageStateAccepted. - */ -OtaPalStatus_t otaPal_SetPlatformImageState( OtaFileContext_t * const C, - OtaImageState_t eState ); - -/** - * @brief Get the state of the OTA update image. - * - * We read this at OTA_Init time and when the latest OTA job reports itself in self - * test. If the update image is in the "pending commit" state, we start a self test - * timer to assure that we can successfully connect to the OTA services and accept - * the OTA update image within a reasonable amount of time (user configurable). If - * we don't satisfy that requirement, we assume there is something wrong with the - * firmware and automatically reset the device, causing it to roll back to the - * previously known working code. - * - * If the update image state is not in "pending commit," the self test timer is - * not started. - * - * @param[in] C File context of type OtaFileContext_t. - * - * @return An OtaPalImageState_t. One of the following: - * OtaPalImageStatePendingCommit (the new firmware image is in the self test phase) - * OtaPalImageStateValid (the new firmware image is already committed) - * OtaPalImageStateInvalid (the new firmware image is invalid or non-existent) - * - * NOTE: OtaPalImageStateUnknown should NEVER be returned and indicates an implementation error. - */ -OtaPalImageState_t otaPal_GetPlatformImageState( OtaFileContext_t * const C ); - -/* *INDENT-OFF* */ -#ifdef __cplusplus - } -#endif -/* *INDENT-ON* */ - -#endif /* ifndef _OTA_PAL_H_ */ diff --git a/platform/posix/ota_pal/source/ota_pal_posix.c b/platform/posix/ota_pal/source/ota_pal_posix.c deleted file mode 100644 index 3456846260..0000000000 --- a/platform/posix/ota_pal/source/ota_pal_posix.c +++ /dev/null @@ -1,756 +0,0 @@ -/* - * OTA PAL V2.0.1 for POSIX - * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - - - -/* OTA PAL implementation for POSIX platform. */ - -#include -#include -#include -#include -#include -#include -#include - -#include "ota.h" -#include "ota_pal_posix.h" - -#include -#include -#include -#include - -/** - * @brief Code signing certificate - * - * The certificate is used for OTA image signing. If a platform does not support a file - * system the signing certificate can be pasted here for testing purpose. - * - * PEM-encoded code signer certificate - * - * Must include the PEM header and footer: - * "-----BEGIN CERTIFICATE-----\n" - * "...base64 data...\n" - * "-----END CERTIFICATE-----\n"; - */ -static const char signingcredentialSIGNING_CERTIFICATE_PEM[] = "Paste code signing certificate here"; - -/** - * @brief Size of buffer used in file operations on this platform (POSIX). - */ -#define OTA_PAL_POSIX_BUF_SIZE ( ( size_t ) 4096U ) - -/** - * @brief Name of the file used for storing platform image state. - */ -#define OTA_PLATFORM_IMAGE_STATE_FILE "PlatformImageState.txt" - -/** - * @brief Specify the OTA signature algorithm we support on this platform. - */ -const char OTA_JsonFileSignatureKey[ OTA_FILE_SIG_KEY_STR_MAX_LENGTH ] = "sig-sha256-ecdsa"; - -/** - * @brief Read the specified signer certificate from the filesystem into a local buffer. The allocated - * memory becomes the property of the caller who is responsible for freeing it. - */ -static EVP_PKEY * Openssl_GetPkeyFromCertificate( uint8_t * pCertFilePath ); - -/** - * @brief Verify the signature of the input content with OpenSSL. - */ -static OtaPalMainStatus_t Openssl_DigestVerify( EVP_MD_CTX * pSigContext, - EVP_PKEY * pPkey, - FILE * pFile, - Sig_t * pSignature ); - -/** - * @brief Verify the signature of the specified file using OpenSSL. - */ -static OtaPalStatus_t otaPal_CheckFileSignature( OtaFileContext_t * const C ); - -/** - * @brief Get the absolute file path from the environment. - * - * @param realFilePath Buffer to store the file path + file name. - * @param pFilePath File name to append to the end of current path. - */ -static OtaPalPathGenStatus_t getFilePathFromCWD( char * realFilePath, - const char * pFilePath ); - -/*-----------------------------------------------------------*/ - -static EVP_PKEY * Openssl_GetPkeyFromCertificate( uint8_t * pCertFilePath ) -{ - BIO * pBio = NULL; - X509 * pCert = NULL; - EVP_PKEY * pPkey = NULL; - int32_t rc = 0; - - /* Read the cert file */ - pBio = BIO_new( BIO_s_file() ); - - if( pBio != NULL ) - { - /* coverity[misra_c_2012_rule_10_1_violation] */ - rc = BIO_read_filename( pBio, pCertFilePath ); - - if( rc != 1 ) - { - LogDebug( ( " No cert file, reading signer cert from header file\n" ) ); - - /* Get the signer cert from a predefined PEM string */ - BIO_free_all( pBio ); - pBio = BIO_new( BIO_s_mem() ); - - if( pBio != NULL ) - { - rc = BIO_puts( pBio, signingcredentialSIGNING_CERTIFICATE_PEM ); - - if( rc <= 0 ) - { - LogError( ( "Failed to write a PEM string to BIO stream" ) ); - } - } - else - { - LogError( ( "Failed to read certificate from a PEM string." ) ); - } - } - else - { - LogDebug( ( "Opened certificate file." ) ); - } - } - - if( ( pBio != NULL ) && ( rc > 0 ) ) - { - pCert = PEM_read_bio_X509( pBio, NULL, NULL, NULL ); - - if( pCert != NULL ) - { - LogDebug( ( "Getting the pkey from the X509 cert." ) ); - - /* Extract the public key */ - pPkey = X509_get_pubkey( pCert ); - - if( pPkey == NULL ) - { - LogError( ( "Failed to get pkey from the signer cert." ) ); - } - } - else - { - LogError( ( "Failed to load cert from either file or predefined string." ) ); - } - } - else - { - LogError( ( "Failed to read signer cert." ) ); - } - - BIO_free_all( pBio ); - X509_free( pCert ); - - /* pPkey should be freed by the caller */ - return pPkey; -} - - -static OtaPalMainStatus_t Openssl_DigestVerifyStart( EVP_MD_CTX * pSigContext, - EVP_PKEY * pPkey, - FILE * pFile, - uint8_t ** pBuf ) -{ - OtaPalMainStatus_t mainErr = OtaPalSignatureCheckFailed; - - assert( pBuf != NULL ); - assert( ( pSigContext != NULL ) && ( pPkey != NULL ) ); - - /* Verify an ECDSA-SHA256 signature. */ - if( ( pFile != NULL ) && - ( 1 == EVP_DigestVerifyInit( pSigContext, NULL, EVP_sha256(), NULL, pPkey ) ) ) - { - LogDebug( ( "Started signature verification." ) ); - - *pBuf = OPENSSL_malloc( OTA_PAL_POSIX_BUF_SIZE ); - - if( *pBuf == NULL ) - { - LogError( ( "Failed to allocate buffer memory." ) ); - mainErr = OtaPalOutOfMemory; - } - else - { - mainErr = OtaPalSuccess; - } - } - else - { - LogError( ( "File signature check failed at INIT." ) ); - } - - return mainErr; -} - -static bool Openssl_DigestVerifyUpdate( EVP_MD_CTX * pSigContext, - FILE * pFile, - uint8_t * pBuf ) -{ - size_t bytesRead; - - do - { - /* POSIX port using standard library */ - /* coverity[misra_c_2012_rule_21_6_violation] */ - bytesRead = fread( pBuf, 1U, OTA_PAL_POSIX_BUF_SIZE, pFile ); - - assert( bytesRead <= OTA_PAL_POSIX_BUF_SIZE ); - - /* feof returns non-zero if end of file is reached, otherwise it returns 0. When - * bytesRead is not equal to OTA_PAL_POSIX_BUF_SIZE, we should be reading last - * chunk and reach to end of file. */ - - /* POSIX port using standard library */ - /* coverity[misra_c_2012_rule_21_6_violation] */ - if( ( bytesRead < OTA_PAL_POSIX_BUF_SIZE ) && ( 0 == feof( pFile ) ) ) - { - break; - } - - /* Include the file chunk in the signature validation. Zero size is OK. */ - if( 1 != EVP_DigestVerifyUpdate( pSigContext, pBuf, bytesRead ) ) - { - break; - } - } while( bytesRead > 0UL ); - - /* POSIX port using standard library */ - /* coverity[misra_c_2012_rule_21_6_violation] */ - return( 0 != feof( pFile ) ? true : false ); -} - -static OtaPalMainStatus_t Openssl_DigestVerify( EVP_MD_CTX * pSigContext, - EVP_PKEY * pPkey, - FILE * pFile, - Sig_t * pSignature ) -{ - OtaPalMainStatus_t mainErr = OtaPalSignatureCheckFailed; - OtaPalMainStatus_t startErr; - uint8_t * pBuf; - - startErr = Openssl_DigestVerifyStart( pSigContext, pPkey, pFile, &pBuf ); - - if( OtaPalSuccess == startErr ) - { - /* Rewind the received file to the beginning. */ - /* POSIX port using standard library */ - /* coverity[misra_c_2012_rule_21_6_violation] */ - if( fseek( pFile, 0L, SEEK_SET ) == 0 ) - { - bool eof = Openssl_DigestVerifyUpdate( pSigContext, pFile, pBuf ); - - if( ( eof == true ) && ( 1 == EVP_DigestVerifyFinal( pSigContext, - pSignature->data, - pSignature->size ) ) ) - { - mainErr = OtaPalSuccess; - } - else - { - LogError( ( "File signature check failed at FINAL" ) ); - } - } - - /* Free the temporary file page buffer. */ - OPENSSL_free( pBuf ); - } - else - { - mainErr = startErr; - } - - return mainErr; -} - -static OtaPalStatus_t otaPal_CheckFileSignature( OtaFileContext_t * const C ) -{ - OtaPalMainStatus_t mainErr = OtaPalSignatureCheckFailed; - EVP_PKEY * pPkey = NULL; - EVP_MD_CTX * pSigContext = NULL; - - assert( C != NULL ); - - /* Extract the signer cert from the file. */ - pPkey = Openssl_GetPkeyFromCertificate( C->pCertFilepath ); - - /* Create a new signature context for verification purpose. */ - pSigContext = EVP_MD_CTX_new(); - - if( ( pPkey != NULL ) && ( pSigContext != NULL ) ) - { - /* Verify the signature. */ - mainErr = Openssl_DigestVerify( pSigContext, pPkey, C->pFile, C->pSignature ); - } - else - { - if( pSigContext == NULL ) - { - LogError( ( "File signature check failed at NEW sig context." ) ); - } - else - { - LogError( ( "File signature check failed at EXTRACT pkey from signer certificate." ) ); - mainErr = OtaPalBadSignerCert; - } - } - - /* Free up objects */ - EVP_MD_CTX_free( pSigContext ); - EVP_PKEY_free( pPkey ); - - return OTA_PAL_COMBINE_ERR( mainErr, 0 ); -} - -static OtaPalPathGenStatus_t getFilePathFromCWD( char * pCompleteFilePath, - const char * pFileName ) -{ - char * pCurrentDir = NULL; - OtaPalPathGenStatus_t status = OtaPalFileGenSuccess; - - /* Get current directory. */ - pCurrentDir = getcwd( pCompleteFilePath, OTA_FILE_PATH_LENGTH_MAX - 1 ); - - if( pCurrentDir == NULL ) - { - LogError( ( "Failed to get current working directory: %s", strerror( errno ) ) ); - status = OtaPalCWDFailed; - } - else - { - /* Add the filename . */ - if( strlen( pCompleteFilePath ) + strlen( pFileName ) + 2U > OTA_FILE_PATH_LENGTH_MAX ) - { - LogError( ( "Insufficient space to generate file path" ) ); - status = OtaPalBufferInsufficient; - } - else - { - strcat( pCompleteFilePath, "/" ); - strcat( pCompleteFilePath, pFileName ); - } - } - - return status; -} - -/*-----------------------------------------------------------*/ - -OtaPalStatus_t otaPal_Abort( OtaFileContext_t * const C ) -{ - /* Set default return status to uninitialized. */ - OtaPalMainStatus_t mainErr = OtaPalUninitialized; - int32_t subErr = 0; - int32_t lFileCloseResult; - - if( NULL != C ) - { - /* Close the OTA update file if it's open. */ - if( NULL != C->pFile ) - { - /* POSIX port using standard library */ - /* coverity[misra_c_2012_rule_21_6_violation] */ - lFileCloseResult = fclose( C->pFile ); - C->pFile = NULL; - - if( 0 == lFileCloseResult ) - { - LogInfo( ( "Closed file." ) ); - mainErr = OtaPalSuccess; - } - else /* Failed to close file. */ - { - LogError( ( "Failed to close file." ) ); - mainErr = OtaPalFileAbort; - subErr = errno; - } - } - else - { - /* Nothing to do. No open file associated with this context. */ - mainErr = OtaPalSuccess; - } - } - else /* Context was not valid. */ - { - LogError( ( "Parameter check failed: Input is NULL." ) ); - mainErr = OtaPalFileAbort; - } - - return OTA_PAL_COMBINE_ERR( mainErr, subErr ); -} - -OtaPalStatus_t otaPal_CreateFileForRx( OtaFileContext_t * const C ) -{ - OtaPalStatus_t result = OTA_PAL_COMBINE_ERR( OtaPalUninitialized, 0 ); - char realFilePath[ OTA_FILE_PATH_LENGTH_MAX ]; - OtaPalPathGenStatus_t status = OtaPalFileGenSuccess; - - if( C != NULL ) - { - if( ( C->pFilePath != NULL ) && ( ( strlen( ( const char * ) C->pFilePath ) + 1U ) > OTA_FILE_PATH_LENGTH_MAX ) ) - { - LogError( ( "File path exceed length limit." ) ); - result = OTA_PAL_COMBINE_ERR( OtaPalRxFileCreateFailed, 0 ); - } - else if( C->pFilePath != NULL ) - { - if( C->pFilePath[ 0 ] != ( uint8_t ) '/' ) - { - status = getFilePathFromCWD( realFilePath, ( const char * ) C->pFilePath ); - } - else - { - ( void ) memcpy( realFilePath, ( const char * ) C->pFilePath, strlen( ( const char * ) C->pFilePath ) + 1U ); - } - - if( status == OtaPalFileGenSuccess ) - { - /* POSIX port using standard library */ - /* coverity[misra_c_2012_rule_21_6_violation] */ - C->pFile = fopen( ( const char * ) realFilePath, "w+b" ); - - if( C->pFile != NULL ) - { - result = OTA_PAL_COMBINE_ERR( OtaPalSuccess, 0 ); - LogInfo( ( "Receive file created." ) ); - } - else - { - result = OTA_PAL_COMBINE_ERR( OtaPalRxFileCreateFailed, errno ); - LogError( ( "Failed to start operation: Operation already started. failed to open -- %s Path ", C->pFilePath ) ); - } - } - else - { - LogError( ( "Could not generate the absolute path for the file" ) ); - result = OTA_PAL_COMBINE_ERR( OtaPalRxFileCreateFailed, 0 ); - } - } - else - { - result = OTA_PAL_COMBINE_ERR( OtaPalRxFileCreateFailed, 0 ); - LogError( ( "Invalid file path provided." ) ); - } - } - else - { - result = OTA_PAL_COMBINE_ERR( OtaPalRxFileCreateFailed, 0 ); - LogError( ( "Invalid context provided." ) ); - } - - /* Exiting function without calling fclose. Context file handle state is managed by this API. */ - return result; -} - -OtaPalStatus_t otaPal_CloseFile( OtaFileContext_t * const C ) -{ - int32_t filerc = 0; - OtaPalMainStatus_t mainErr = OtaPalSuccess; - OtaPalSubStatus_t subErr = 0; - OtaPalStatus_t result; - - if( C != NULL ) - { - if( C->pSignature != NULL ) - { - /* Verify the file signature, close the file and return the signature verification result. */ - result = otaPal_CheckFileSignature( C ); - mainErr = OTA_PAL_MAIN_ERR( result ); - subErr = OTA_PAL_SUB_ERR( result ); - } - else - { - LogError( ( "Parameter check failed: OTA signature structure is NULL." ) ); - mainErr = OtaPalSignatureCheckFailed; - } - - /* Close the file. */ - /* POSIX port using standard library */ - /* coverity[misra_c_2012_rule_21_6_violation] */ - filerc = fclose( C->pFile ); - C->pFile = NULL; - - if( filerc != 0 ) - { - LogError( ( "Failed to close OTA update file." ) ); - mainErr = OtaPalFileClose; - subErr = ( uint32_t ) errno; - } - - if( mainErr == OtaPalSuccess ) - { - LogInfo( ( "%s signature verification passed.", OTA_JsonFileSignatureKey ) ); - - ( void ) otaPal_SetPlatformImageState( C, OtaImageStateTesting ); - } - else - { - LogError( ( "Failed to pass %s signature verification: %d.", - OTA_JsonFileSignatureKey, OTA_PAL_COMBINE_ERR( mainErr, subErr ) ) ); - - /* If we fail to verify the file signature that means the image is not valid. We need to set the image state to aborted. */ - ( void ) otaPal_SetPlatformImageState( C, OtaImageStateAborted ); - } - } - else /* Invalid OTA Context. */ - { - LogError( ( "Failed to close file: " - "Parameter check failed: " - "Invalid context." ) ); - mainErr = OtaPalFileClose; - } - - return OTA_PAL_COMBINE_ERR( mainErr, subErr ); -} - -int16_t otaPal_WriteBlock( OtaFileContext_t * const C, - uint32_t ulOffset, - uint8_t * const pcData, - uint32_t ulBlockSize ) -{ - int32_t filerc = 0; - size_t writeSize = 0; - - if( C != NULL ) - { - /* POSIX port using standard library */ - /* coverity[misra_c_2012_rule_21_6_violation] */ - filerc = fseek( C->pFile, ( int64_t ) ulOffset, SEEK_SET ); - - if( 0 == filerc ) - { - /* POSIX port using standard library */ - /* coverity[misra_c_2012_rule_21_6_violation] */ - writeSize = fwrite( pcData, 1, ulBlockSize, C->pFile ); - - if( writeSize != ulBlockSize ) - { - LogError( ( "Failed to write block to file: " - "fwrite returned error: " - "errno=%d", errno ) ); - - filerc = -1; - } - else - { - filerc = ( int32_t ) writeSize; - } - } - else - { - LogError( ( "fseek failed. fseek returned errno = %d", errno ) ); - filerc = -1; - } - } - else /* Invalid context or file pointer provided. */ - { - LogError( ( "Invalid context." ) ); - filerc = -1; - } - - return ( int16_t ) filerc; -} - -/* Return no error. POSIX implementation simply does nothing on activate. */ -OtaPalStatus_t otaPal_ActivateNewImage( OtaFileContext_t * const C ) -{ - ( void ) C; - - return OTA_PAL_COMBINE_ERR( OtaPalSuccess, 0 ); -} - -/* Set the final state of the last transferred (final) OTA file (or bundle). - * On POSIX, the state of the OTA image is stored in PlatformImageState.txt. */ -OtaPalStatus_t otaPal_SetPlatformImageState( OtaFileContext_t * const C, - OtaImageState_t eState ) -{ - OtaPalMainStatus_t mainErr = OtaPalBadImageState; - OtaPalPathGenStatus_t status = OtaPalFileGenSuccess; - int32_t subErr = 0; - FILE * pPlatformImageState = NULL; - char imageStateFile[ OTA_FILE_PATH_LENGTH_MAX ] = { 0 }; - - ( void ) C; - - if( ( eState != OtaImageStateUnknown ) && ( eState <= OtaLastImageState ) ) - { - /* Get file path for the image state file. */ - status = getFilePathFromCWD( imageStateFile, OTA_PLATFORM_IMAGE_STATE_FILE ); - - if( status == OtaPalFileGenSuccess ) - { - /* POSIX port using standard library */ - /* coverity[misra_c_2012_rule_21_6_violation] */ - pPlatformImageState = fopen( imageStateFile, "w+b" ); - } - else - { - LogError( ( "Could not generate the absolute path for the file" ) ); - } - - if( pPlatformImageState != NULL ) - { - /* Write the image state to PlatformImageState.txt. */ - /* POSIX port using standard library */ - /* coverity[misra_c_2012_rule_21_6_violation] */ - if( 1UL == fwrite( &eState, sizeof( OtaImageState_t ), 1, pPlatformImageState ) ) - { - /* Close PlatformImageState.txt. */ - /* POSIX port using standard library */ - /* coverity[misra_c_2012_rule_21_6_violation] */ - if( 0 == fclose( pPlatformImageState ) ) - { - mainErr = OtaPalSuccess; - } - else - { - LogError( ( "Unable to close image state file." ) ); - subErr = errno; - } - } - else - { - LogError( ( "Unable to write to image state file. error-- %d", errno ) ); - subErr = errno; - - /* The file should be closed, but errno passed out is fwrite error */ - /* POSIX port using standard library */ - /* coverity[misra_c_2012_rule_21_6_violation] */ - ( void ) fclose( pPlatformImageState ); - } - } - else - { - LogError( ( "Unable to open image state file. Path: %s error: %s", imageStateFile, strerror( errno ) ) ); - subErr = errno; - } - } - else /* Image state invalid. */ - { - LogError( ( "Invalid image state provided." ) ); - } - - /* Allow calls to fopen and fclose in this context. */ - return OTA_PAL_COMBINE_ERR( mainErr, subErr ); -} - -OtaPalStatus_t otaPal_ResetDevice( OtaFileContext_t * const C ) -{ - ( void ) C; - - /* Return no error. POSIX implementation does not reset device. */ - return OTA_PAL_COMBINE_ERR( OtaPalSuccess, 0 ); -} - -/* Get the state of the currently running image. - * - * On POSIX, this is simulated by looking for and reading the state from - * the PlatformImageState.txt file in the current working directory. - * - * We read this at OTA_Init time so we can tell if the MCU image is in self - * test mode. If it is, we expect a successful connection to the OTA services - * within a reasonable amount of time. If we don't satisfy that requirement, - * we assume there is something wrong with the firmware and reset the device, - * causing it to rollback to the previous code. On POSIX, this is not - * fully simulated as there is no easy way to reset the simulated device. - */ -OtaPalImageState_t otaPal_GetPlatformImageState( OtaFileContext_t * const C ) -{ - FILE * pPlatformImageState = NULL; - OtaImageState_t eSavedAgentState = OtaImageStateUnknown; - OtaPalImageState_t ePalState = OtaPalImageStateUnknown; - OtaPalPathGenStatus_t status = OtaPalFileGenSuccess; - char imageStateFile[ OTA_FILE_PATH_LENGTH_MAX ] = { 0 }; - - ( void ) C; - - /* Get file path for the image state file. */ - status = getFilePathFromCWD( imageStateFile, OTA_PLATFORM_IMAGE_STATE_FILE ); - - if( status != OtaPalFileGenSuccess ) - { - LogError( ( "Could not generate the absolute path for the file" ) ); - ePalState = OtaPalImageStateInvalid; - } - else - { - /* POSIX port using standard library */ - /* coverity[misra_c_2012_rule_21_6_violation] */ - pPlatformImageState = fopen( imageStateFile, "r+b" ); - - if( pPlatformImageState != NULL ) - { - /* POSIX port using standard library */ - /* coverity[misra_c_2012_rule_21_6_violation] */ - if( 1U != fread( &eSavedAgentState, sizeof( OtaImageState_t ), 1, pPlatformImageState ) ) - { - /* If an error occurred reading the file, mark the state as aborted. */ - LogError( ( "Failed to read image state file." ) ); - ePalState = OtaPalImageStateInvalid; - } - else - { - if( eSavedAgentState == OtaImageStateTesting ) - { - ePalState = OtaPalImageStatePendingCommit; - } - else if( eSavedAgentState == OtaImageStateAccepted ) - { - ePalState = OtaPalImageStateValid; - } - else - { - ePalState = OtaPalImageStateInvalid; - } - } - - /* POSIX port using standard library */ - /* coverity[misra_c_2012_rule_21_6_violation] */ - if( 0 != fclose( pPlatformImageState ) ) - { - LogError( ( "Failed to close image state file." ) ); - ePalState = OtaPalImageStateInvalid; - } - } - else - { - /* If no image state file exists, assume a factory image. */ - ePalState = OtaPalImageStateValid; /*lint !e64 Allow assignment. */ - } - } - - return ePalState; -} - -/*-----------------------------------------------------------*/ diff --git a/platform/posix/transport/CMakeLists.txt b/platform/posix/transport/CMakeLists.txt index c167a895d8..b2f5786b23 100644 --- a/platform/posix/transport/CMakeLists.txt +++ b/platform/posix/transport/CMakeLists.txt @@ -72,6 +72,7 @@ target_include_directories( "${COREPKCS11_LOCATION}/source/portable/os" ${CORE_PKCS11_3RDPARTY_LOCATION}/pkcs11 ${DEMOS_DIR}/pkcs11/common/include + ${ROOT_DIR}/libraries/3rdparty/mbedtls/library PRIVATE ${CORE_PKCS11_3RDPARTY_LOCATION}/mbedtls_utils ) diff --git a/platform/posix/transport/include/mbedtls_pkcs11_posix.h b/platform/posix/transport/include/mbedtls_pkcs11_posix.h index 076cec867c..18aafdbe7d 100644 --- a/platform/posix/transport/include/mbedtls_pkcs11_posix.h +++ b/platform/posix/transport/include/mbedtls_pkcs11_posix.h @@ -66,11 +66,16 @@ /* Standard includes. */ #include +/** + * @brief To access the private members of the MbedTLS structs + */ +#define MBEDTLS_ALLOW_PRIVATE_ACCESS + /* MbedTLS includes. */ #include "mbedtls/net_sockets.h" #include "mbedtls/ssl.h" #include "mbedtls/pk.h" -#include "mbedtls/pk_internal.h" +#include "pk_wrap.h" /* Transport interface include. */ #include "transport_interface.h" diff --git a/platform/posix/transport/src/mbedtls_pkcs11_posix.c b/platform/posix/transport/src/mbedtls_pkcs11_posix.c index ba75d643ac..b5f22af362 100644 --- a/platform/posix/transport/src/mbedtls_pkcs11_posix.c +++ b/platform/posix/transport/src/mbedtls_pkcs11_posix.c @@ -203,11 +203,12 @@ static bool initializeClientKeys( MbedtlsPkcs11Context_t * pContext, * * @return Zero on success. */ -static int32_t privateKeySigningCallback( void * pContext, +static int32_t privateKeySigningCallback( mbedtls_pk_context * pContext, mbedtls_md_type_t mdAlg, const unsigned char * pHash, size_t hashLen, unsigned char * pSig, + size_t sig_size, size_t * pSigLen, int32_t ( * pRng )( void *, unsigned char *, size_t ), void * pRngContext ); @@ -662,11 +663,12 @@ static bool initializeClientKeys( MbedtlsPkcs11Context_t * pContext, /*-----------------------------------------------------------*/ -static int32_t privateKeySigningCallback( void * pContext, +static int32_t privateKeySigningCallback( mbedtls_pk_context * pContext, mbedtls_md_type_t mdAlg, const unsigned char * pHash, size_t hashLen, unsigned char * pSig, + size_t sig_size, size_t * pSigLen, int32_t ( * pRng )( void *, unsigned char *, @@ -675,7 +677,7 @@ static int32_t privateKeySigningCallback( void * pContext, { CK_RV ret = CKR_OK; int32_t result = 0; - MbedtlsPkcs11Context_t * pMbedtlsPkcs11Context = ( MbedtlsPkcs11Context_t * ) pContext; + MbedtlsPkcs11Context_t * pMbedtlsPkcs11Context = ( MbedtlsPkcs11Context_t * ) pContext->pk_ctx; CK_MECHANISM mech = { 0 }; /* Buffer big enough to hold data to be signed. */ CK_BYTE toBeSigned[ 256 ]; @@ -685,6 +687,7 @@ static int32_t privateKeySigningCallback( void * pContext, ( void ) ( pRng ); ( void ) ( pRngContext ); ( void ) ( mdAlg ); + ( void ) ( sig_size ); assert( pContext != NULL ); assert( pHash != NULL ); diff --git a/tools/cmake/install.cmake b/tools/cmake/install.cmake index 157ebe8842..738842bbc3 100644 --- a/tools/cmake/install.cmake +++ b/tools/cmake/install.cmake @@ -4,7 +4,6 @@ set(FILEPATH_LOCATIONS ${MODULES_DIR}/aws/device-defender-for-aws-iot-embedded-sdk/defenderFilePaths.cmake ${MODULES_DIR}/aws/device-shadow-for-aws-iot-embedded-sdk/shadowFilePaths.cmake ${MODULES_DIR}/aws/jobs-for-aws-iot-embedded-sdk/jobsFilePaths.cmake - ${MODULES_DIR}/aws/ota-for-aws-iot-embedded-sdk/otaFilePaths.cmake ${MODULES_DIR}/standard/backoffAlgorithm/backoffAlgorithmFilePaths.cmake ${MODULES_DIR}/standard/coreHTTP/httpFilePaths.cmake ${MODULES_DIR}/standard/coreJSON/jsonFilePaths.cmake @@ -23,11 +22,8 @@ endforeach() set(LIBRARY_PREFIXES "DEFENDER" "SHADOW" - "JOBS" "JSON" - "OTA" - "OTA_HTTP" - "OTA_MQTT" + "JOBS" "BACKOFF_ALGORITHM" "HTTP" "MQTT" @@ -47,22 +43,9 @@ set(PKCS_EXTRA_INCLUDE_PRIVATE_DIRS PRIVATE "${CORE_PKCS11_3RDPARTY_LOCATION}/mbedtls_utils" "${COREPKCS11_LOCATION}/source/portable/os") -set(OTA_BACKENDS "OTA_HTTP" "OTA_MQTT") -foreach(ota_backend ${OTA_BACKENDS}) - set("${ota_backend}_EXTRA_INCLUDE_PUBLIC_DIRS" - ${OTA_INCLUDE_PUBLIC_DIRS}) - set("${ota_backend}_EXTRA_INCLUDE_PRIVATE_DIRS" - ${OTA_INCLUDE_PRIVATE_DIRS}) -endforeach() # Define any extra library dependencies, making sure to use the same prefix -# Note for this to work for OTA "JSON" must be before it in the prefix list -set(OTA_LIBRARY_DEPENDENCIES - aws_iot_json) -set(OTA_MQTT_LIBRARY_DEPENDENCIES - tinycbor) - if(NOT DEFINED INSTALL_LIBS) set(INSTALL_LIBS ${LIBRARY_PREFIXES}) endif() @@ -76,6 +59,11 @@ foreach(library_prefix ${LIBRARY_PREFIXES}) add_library("${library_name}" ${${library_prefix}_EXTRA_SOURCES} ${${library_prefix}_SOURCES}) + + if(${library_prefix} STREQUAL "JOBS") + target_include_directories("${library_name}" PUBLIC ${JSON_INCLUDE_PUBLIC_DIRS}) + target_link_libraries("${library_name}" PRIVATE aws_iot_json) + endif() else() continue() endif() @@ -98,9 +86,6 @@ foreach(library_prefix ${LIBRARY_PREFIXES}) # Allow a path to a custom config header to be passed through a CMake flag. set(config_prefix "${library_prefix}") - if(";${OTA_BACKENDS};" MATCHES ";${library_prefix};") - set(config_prefix "OTA") - endif() if(DEFINED "${config_prefix}_CUSTOM_CONFIG_DIR") target_include_directories("${library_name}" PRIVATE ${${config_prefix}_CUSTOM_CONFIG_DIR}) @@ -141,22 +126,7 @@ endforeach() # Install platform abstractions as shared libraries if enabled. if(INSTALL_PLATFORM_ABSTRACTIONS) set(PLATFORM_DIRECTORIES - ${COMMON_TRANSPORT_INCLUDE_PUBLIC_DIRS} - ${PLATFORM_DIR}/posix/ota_pal/source/include) - # Create target for POSIX port of OTA if LIB_RT is installed. - if(NOT(${LIB_RT} STREQUAL "LIB_RT-NOTFOUND")) - add_library(ota_posix - ${OTA_OS_POSIX_SOURCES}) - target_link_libraries(ota_posix PUBLIC ${LIB_RT} ota_pal) - target_include_directories(ota_posix PUBLIC - ${OTA_INCLUDE_PUBLIC_DIRS} - ${OTA_INCLUDE_OS_POSIX_DIRS}) - target_compile_definitions(ota_posix PRIVATE -DOTA_DO_NOT_USE_CUSTOM_CONFIG) - install(TARGETS ota_posix - LIBRARY DESTINATION "${CSDK_LIB_INSTALL_PATH}" - ARCHIVE DESTINATION "${CSDK_LIB_INSTALL_PATH}") - list(APPEND PLATFORM_DIRECTORIES ${OTA_INCLUDE_OS_POSIX_DIRS}) - endif() + ${COMMON_TRANSPORT_INCLUDE_PUBLIC_DIRS}) foreach(platform_dir ${PLATFORM_DIRECTORIES}) install(DIRECTORY ${platform_dir}/ DESTINATION ${CSDK_HEADER_INSTALL_PATH} FILES_MATCHING PATTERN "*.h" diff --git a/tools/release/README.md b/tools/release/README.md index 15137a1cd8..3b028fcdf1 100644 --- a/tools/release/README.md +++ b/tools/release/README.md @@ -58,7 +58,6 @@ python3 tools/release/release-verify.py \ --jobs-for-aws-iot-embedded-sdk-version \ --corepkcs11-version \ --backoffalgorithm-version \ ---ota-for-aws-iot-embedded-sdk \ --disable-cbmc-checks-for \ --disable-cbmc-checks-for \ --disable-jenkins-server-verify