From 3ce2674afa6f427d31e5740835da3e2b6e16475a Mon Sep 17 00:00:00 2001 From: Igor Abdrakhimov Date: Thu, 28 Mar 2024 15:51:56 -0700 Subject: [PATCH 01/47] Add sanitizer CI job --- .github/workflows/ci.yml | 12 ++++++++ CMakeLists.txt | 2 ++ devicedefender/CMakeLists.txt | 46 +++++++++++++++-------------- devicedefender/tests/CMakeLists.txt | 1 + iotdevicecommon/CMakeLists.txt | 45 ++++++++++++++-------------- 5 files changed, 62 insertions(+), 44 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8b0187019..fb70657fe 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -683,3 +683,15 @@ jobs: - name: Check for edits to code-generated files run: | ./utils/check_codegen_edits.py + + clang-sanitizers: + runs-on: ubuntu-22.04 # latest + strategy: + matrix: + sanitizers: ["thread", "address,undefined"] + steps: + # We can't use the `uses: docker://image` version yet, GitHub lacks authentication for actions -> packages + - name: Build ${{ env.PACKAGE_NAME }} + run: | + aws s3 cp s3://aws-crt-test-stuff/ci/${{ env.BUILDER_VERSION }}/linux-container-ci.sh ./linux-container-ci.sh && chmod a+x ./linux-container-ci.sh + ./linux-container-ci.sh ${{ env.BUILDER_VERSION }} aws-crt-${{ env.LINUX_BASE_IMAGE }} build -p ${{ env.PACKAGE_NAME }} --compiler=clang-12 --cmake-extra=-DENABLE_SANITIZERS=ON --cmake-extra=-DSANITIZERS="${{ matrix.sanitizers }}" diff --git a/CMakeLists.txt b/CMakeLists.txt index 1d929a52a..24d8db064 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -74,6 +74,8 @@ else() set(IN_SOURCE_BUILD OFF) endif() +include(AwsSanitizers) + aws_use_package(aws-crt-cpp) add_subdirectory(jobs) diff --git a/devicedefender/CMakeLists.txt b/devicedefender/CMakeLists.txt index 4040ca76f..ff04c3339 100644 --- a/devicedefender/CMakeLists.txt +++ b/devicedefender/CMakeLists.txt @@ -45,27 +45,27 @@ if (WIN32) endif () endif() -add_library(IotDeviceDefender-cpp ${AWS_IOTDEVICEDEFENDER_CPP_SRC}) +add_library(${PROJECT_NAME} ${AWS_IOTDEVICEDEFENDER_CPP_SRC}) -set_target_properties(IotDeviceDefender-cpp PROPERTIES LINKER_LANGUAGE CXX) +set_target_properties(${PROJECT_NAME} PROPERTIES LINKER_LANGUAGE CXX) set(CMAKE_C_FLAGS_DEBUGOPT "") #set warnings if (MSVC) - target_compile_options(IotDeviceDefender-cpp PRIVATE /W4 /WX) + target_compile_options(${PROJECT_NAME} PRIVATE /W4 /WX) else () - target_compile_options(IotDeviceDefender-cpp PRIVATE -Wall -Wno-long-long -pedantic -Werror) + target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wno-long-long -pedantic -Werror) endif () -target_compile_definitions(IotDeviceDefender-cpp PRIVATE $<$:DEBUG_BUILD>) +target_compile_definitions(${PROJECT_NAME} PRIVATE $<$:DEBUG_BUILD>) if (BUILD_SHARED_LIBS) - target_compile_definitions(IotDeviceDefender-cpp PUBLIC "-DAWS_IOTDEVICEDEFENDER_USE_IMPORT_EXPORT") - target_compile_definitions(IotDeviceDefender-cpp PRIVATE "-DAWS_IOTDEVICEDEFENDER_EXPORTS") + target_compile_definitions(${PROJECT_NAME} PUBLIC "-DAWS_IOTDEVICEDEFENDER_USE_IMPORT_EXPORT") + target_compile_definitions(${PROJECT_NAME} PRIVATE "-DAWS_IOTDEVICEDEFENDER_EXPORTS") - install(TARGETS IotDeviceDefender-cpp - EXPORT IotDeviceDefender-cpp-targets + install(TARGETS ${PROJECT_NAME} + EXPORT ${PROJECT_NAME}-targets ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT Development @@ -77,20 +77,20 @@ if (BUILD_SHARED_LIBS) DESTINATION ${RUNTIME_DIRECTORY} COMPONENT Runtime) - install(TARGETS IotDeviceDefender-cpp - EXPORT IotDeviceDefender-cpp-targets + install(TARGETS ${PROJECT_NAME} + EXPORT ${PROJECT_NAME}-targets LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} NAMELINK_ONLY COMPONENT Development) else() - install(TARGETS IotDeviceDefender-cpp - EXPORT IotDeviceDefender-cpp-targets + install(TARGETS ${PROJECT_NAME} + EXPORT ${PROJECT_NAME}-targets ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT Development) endif() -target_include_directories(IotDeviceDefender-cpp PUBLIC +target_include_directories(${PROJECT_NAME} PUBLIC $ $) @@ -101,7 +101,9 @@ if (BUILD_DEPS) endif() endif() -target_link_libraries(IotDeviceDefender-cpp IotDeviceCommon-cpp) +aws_add_sanitizers(${PROJECT_NAME}) + +target_link_libraries(${PROJECT_NAME} IotDeviceCommon-cpp) install(FILES ${AWS_IOTDEVICEDEFENDER_HEADERS} DESTINATION "include/aws/iotdevicedefender/" COMPONENT Development) @@ -114,22 +116,22 @@ endif() include(CMakePackageConfigHelpers) if (DEFINED SIMPLE_VERSION) write_basic_package_version_file( - "${CMAKE_CURRENT_BINARY_DIR}/iotdevicedefender-cpp-config-version.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake" COMPATIBILITY SameMajorVersion ) endif() -install(EXPORT "IotDeviceDefender-cpp-targets" - DESTINATION "${CMAKE_INSTALL_LIBDIR}/IotDeviceDefender-cpp/cmake/${TARGET_DIR}" +install(EXPORT "${PROJECT_NAME}-targets" + DESTINATION "${CMAKE_INSTALL_LIBDIR}/${PROJECT_NAME}/cmake/${TARGET_DIR}" NAMESPACE AWS:: COMPONENT Development) -configure_file("cmake/iotdevicedefender-cpp-config.cmake" - "${CMAKE_CURRENT_BINARY_DIR}/iotdevicedefender-cpp-config.cmake" +configure_file("cmake/${PROJECT_NAME}-config.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake" @ONLY) -install(FILES "${CMAKE_CURRENT_BINARY_DIR}/iotdevicedefender-cpp-config.cmake" - DESTINATION "${CMAKE_INSTALL_LIBDIR}/IotDeviceDefender-cpp/cmake/" +install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake" + DESTINATION "${CMAKE_INSTALL_LIBDIR}/${PROJECT_NAME}/cmake/" COMPONENT Development) if (BUILD_TESTING) diff --git a/devicedefender/tests/CMakeLists.txt b/devicedefender/tests/CMakeLists.txt index 4ec1f7c32..59706fd98 100644 --- a/devicedefender/tests/CMakeLists.txt +++ b/devicedefender/tests/CMakeLists.txt @@ -19,4 +19,5 @@ if (UNIX AND NOT APPLE) add_net_test_case(Mqtt5DeviceDefenderCustomMetricSuccess) add_net_test_case(Mqtt5DeviceDefenderCustomMetricFail) generate_cpp_test_driver(${TEST_BINARY_NAME}) + aws_add_sanitizers(${TEST_BINARY_NAME}) endif() diff --git a/iotdevicecommon/CMakeLists.txt b/iotdevicecommon/CMakeLists.txt index 05fbcb0c8..344c92003 100644 --- a/iotdevicecommon/CMakeLists.txt +++ b/iotdevicecommon/CMakeLists.txt @@ -46,27 +46,27 @@ endif() aws_use_package(aws-c-iot) -add_library(IotDeviceCommon-cpp ${AWS_IOTDEVICECOMMON_CPP_SRC}) +add_library(${PROJECT_NAME} ${AWS_IOTDEVICECOMMON_CPP_SRC}) -set_target_properties(IotDeviceCommon-cpp PROPERTIES LINKER_LANGUAGE CXX) +set_target_properties(${PROJECT_NAME} PROPERTIES LINKER_LANGUAGE CXX) set(CMAKE_C_FLAGS_DEBUGOPT "") #set warnings if (MSVC) - target_compile_options(IotDeviceCommon-cpp PRIVATE /W4 /WX) + target_compile_options(${PROJECT_NAME} PRIVATE /W4 /WX) else () - target_compile_options(IotDeviceCommon-cpp PRIVATE -Wall -Wno-long-long -pedantic -Werror) + target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wno-long-long -pedantic -Werror) endif () -target_compile_definitions(IotDeviceCommon-cpp PRIVATE $<$:DEBUG_BUILD>) +target_compile_definitions(${PROJECT_NAME} PRIVATE $<$:DEBUG_BUILD>) if (BUILD_SHARED_LIBS) - target_compile_definitions(IotDeviceCommon-cpp PUBLIC "-DAWS_IOTDEVICECOMMON_USE_IMPORT_EXPORT") - target_compile_definitions(IotDeviceCommon-cpp PRIVATE "-DAWS_IOTDEVICECOMMON_EXPORTS") + target_compile_definitions(${PROJECT_NAME} PUBLIC "-DAWS_IOTDEVICECOMMON_USE_IMPORT_EXPORT") + target_compile_definitions(${PROJECT_NAME} PRIVATE "-DAWS_IOTDEVICECOMMON_EXPORTS") - install(TARGETS IotDeviceCommon-cpp - EXPORT IotDeviceCommon-cpp-targets + install(TARGETS ${PROJECT_NAME} + EXPORT ${PROJECT_NAME}-targets ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT Development @@ -78,20 +78,20 @@ if (BUILD_SHARED_LIBS) DESTINATION ${RUNTIME_DIRECTORY} COMPONENT Runtime) - install(TARGETS IotDeviceCommon-cpp - EXPORT IotDeviceCommon-cpp-targets + install(TARGETS ${PROJECT_NAME} + EXPORT ${PROJECT_NAME}-targets LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} NAMELINK_ONLY COMPONENT Development) else() - install(TARGETS IotDeviceCommon-cpp - EXPORT IotDeviceCommon-cpp-targets + install(TARGETS ${PROJECT_NAME} + EXPORT ${PROJECT_NAME}-targets ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT Development) endif() -target_include_directories(IotDeviceCommon-cpp PUBLIC +target_include_directories(${PROJECT_NAME} PUBLIC $ $) @@ -102,7 +102,8 @@ if (BUILD_DEPS) aws_use_package(aws-c-iot) endif() -target_link_libraries(IotDeviceCommon-cpp ${DEP_AWS_LIBS}) +aws_add_sanitizers(${PROJECT_NAME}) +target_link_libraries(${PROJECT_NAME} ${DEP_AWS_LIBS}) install(FILES ${AWS_IOTDEVICECOMMON_HEADERS} DESTINATION "include/aws/iotdevicecommon/" COMPONENT Development) @@ -115,20 +116,20 @@ endif() include(CMakePackageConfigHelpers) if (DEFINED SIMPLE_VERSION) write_basic_package_version_file( - "${CMAKE_CURRENT_BINARY_DIR}/iotdevicecommon-cpp-config-version.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake" COMPATIBILITY SameMajorVersion ) endif() -install(EXPORT "IotDeviceCommon-cpp-targets" - DESTINATION "${CMAKE_INSTALL_LIBDIR}/IotDeviceCommon-cpp/cmake/${TARGET_DIR}" +install(EXPORT "${PROJECT_NAME}-targets" + DESTINATION "${CMAKE_INSTALL_LIBDIR}/${PROJECT_NAME}/cmake/${TARGET_DIR}" NAMESPACE AWS:: COMPONENT Development) -configure_file("cmake/iotdevicecommon-cpp-config.cmake" - "${CMAKE_CURRENT_BINARY_DIR}/iotdevicecommon-cpp-config.cmake" +configure_file("cmake/${PROJECT_NAME}-config.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake" @ONLY) -install(FILES "${CMAKE_CURRENT_BINARY_DIR}/iotdevicecommon-cpp-config.cmake" - DESTINATION "${CMAKE_INSTALL_LIBDIR}/IotDeviceCommon-cpp/cmake/" +install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake" + DESTINATION "${CMAKE_INSTALL_LIBDIR}/${PROJECT_NAME}/cmake/" COMPONENT Development) From 1a87c51c53cf5bbeea063818c428546ff88b85be Mon Sep 17 00:00:00 2001 From: Igor Abdrakhimov Date: Thu, 28 Mar 2024 15:54:14 -0700 Subject: [PATCH 02/47] Add creds for sanitizer job --- .github/workflows/ci.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fb70657fe..d5ba554d1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -690,6 +690,11 @@ jobs: matrix: sanitizers: ["thread", "address,undefined"] steps: + - name: configure AWS credentials (containers) + uses: aws-actions/configure-aws-credentials@v2 + with: + role-to-assume: ${{ env.CI_IOT_CONTAINERS }} + aws-region: ${{ env.AWS_DEFAULT_REGION }} # We can't use the `uses: docker://image` version yet, GitHub lacks authentication for actions -> packages - name: Build ${{ env.PACKAGE_NAME }} run: | From 408187f1bdca0d486a993dcfa46dc9250e5d3965 Mon Sep 17 00:00:00 2001 From: Igor Abdrakhimov Date: Thu, 28 Mar 2024 15:56:59 -0700 Subject: [PATCH 03/47] Add permissions to CI job --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d5ba554d1..650e0684a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -689,6 +689,8 @@ jobs: strategy: matrix: sanitizers: ["thread", "address,undefined"] + permissions: + id-token: write # This is required for requesting the JWT steps: - name: configure AWS credentials (containers) uses: aws-actions/configure-aws-credentials@v2 From 514efcb182d6a7d1177eb41b732250f2b389d993 Mon Sep 17 00:00:00 2001 From: Igor Abdrakhimov Date: Thu, 28 Mar 2024 16:07:42 -0700 Subject: [PATCH 04/47] Fix device defender cmake configs --- devicedefender/CMakeLists.txt | 8 ++++---- iotdevicecommon/CMakeLists.txt | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/devicedefender/CMakeLists.txt b/devicedefender/CMakeLists.txt index ff04c3339..c249fb0f0 100644 --- a/devicedefender/CMakeLists.txt +++ b/devicedefender/CMakeLists.txt @@ -116,7 +116,7 @@ endif() include(CMakePackageConfigHelpers) if (DEFINED SIMPLE_VERSION) write_basic_package_version_file( - "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/iotdevicedefender-cpp-config-version.cmake" COMPATIBILITY SameMajorVersion ) endif() @@ -126,11 +126,11 @@ install(EXPORT "${PROJECT_NAME}-targets" NAMESPACE AWS:: COMPONENT Development) -configure_file("cmake/${PROJECT_NAME}-config.cmake" - "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake" +configure_file("cmake/iotdevicedefender-cpp-config.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/iotdevicedefender-cpp-config.cmake" @ONLY) -install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake" +install(FILES "${CMAKE_CURRENT_BINARY_DIR}/iotdevicedefender-cpp-config.cmake" DESTINATION "${CMAKE_INSTALL_LIBDIR}/${PROJECT_NAME}/cmake/" COMPONENT Development) diff --git a/iotdevicecommon/CMakeLists.txt b/iotdevicecommon/CMakeLists.txt index 344c92003..254eb6560 100644 --- a/iotdevicecommon/CMakeLists.txt +++ b/iotdevicecommon/CMakeLists.txt @@ -116,7 +116,7 @@ endif() include(CMakePackageConfigHelpers) if (DEFINED SIMPLE_VERSION) write_basic_package_version_file( - "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/iotdevicecommon-cpp-config-version.cmake" COMPATIBILITY SameMajorVersion ) endif() @@ -126,10 +126,10 @@ install(EXPORT "${PROJECT_NAME}-targets" NAMESPACE AWS:: COMPONENT Development) -configure_file("cmake/${PROJECT_NAME}-config.cmake" - "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake" +configure_file("cmake/iotdevicecommon-cpp-config.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/iotdevicecommon-cpp-config.cmake" @ONLY) -install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake" +install(FILES "${CMAKE_CURRENT_BINARY_DIR}/iotdevicecommon-cpp-config.cmake" DESTINATION "${CMAKE_INSTALL_LIBDIR}/${PROJECT_NAME}/cmake/" COMPONENT Development) From b3170b04a402edb44d2d8b71b8954c09a3184c0d Mon Sep 17 00:00:00 2001 From: Igor Abdrakhimov Date: Thu, 28 Mar 2024 16:18:26 -0700 Subject: [PATCH 05/47] Fix target_link_libraries --- devicedefender/CMakeLists.txt | 2 +- iotdevicecommon/CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/devicedefender/CMakeLists.txt b/devicedefender/CMakeLists.txt index c249fb0f0..0e39e82e2 100644 --- a/devicedefender/CMakeLists.txt +++ b/devicedefender/CMakeLists.txt @@ -103,7 +103,7 @@ endif() aws_add_sanitizers(${PROJECT_NAME}) -target_link_libraries(${PROJECT_NAME} IotDeviceCommon-cpp) +target_link_libraries(${PROJECT_NAME} PUBLIC IotDeviceCommon-cpp) install(FILES ${AWS_IOTDEVICEDEFENDER_HEADERS} DESTINATION "include/aws/iotdevicedefender/" COMPONENT Development) diff --git a/iotdevicecommon/CMakeLists.txt b/iotdevicecommon/CMakeLists.txt index 254eb6560..c38e55e07 100644 --- a/iotdevicecommon/CMakeLists.txt +++ b/iotdevicecommon/CMakeLists.txt @@ -103,7 +103,7 @@ if (BUILD_DEPS) endif() aws_add_sanitizers(${PROJECT_NAME}) -target_link_libraries(${PROJECT_NAME} ${DEP_AWS_LIBS}) +target_link_libraries(${PROJECT_NAME} PUBLIC ${DEP_AWS_LIBS}) install(FILES ${AWS_IOTDEVICECOMMON_HEADERS} DESTINATION "include/aws/iotdevicecommon/" COMPONENT Development) From edec814b343782a599297f3b36acd9c24956492b Mon Sep 17 00:00:00 2001 From: Igor Abdrakhimov Date: Thu, 28 Mar 2024 17:20:01 -0700 Subject: [PATCH 06/47] Check if sanitizer works --- devicedefender/tests/DeviceDefenderTest.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/devicedefender/tests/DeviceDefenderTest.cpp b/devicedefender/tests/DeviceDefenderTest.cpp index cb75c418c..561b87e6e 100644 --- a/devicedefender/tests/DeviceDefenderTest.cpp +++ b/devicedefender/tests/DeviceDefenderTest.cpp @@ -147,6 +147,9 @@ static int s_TestMqtt5DeviceDefenderResourceSafety(Aws::Crt::Allocator *allocato Aws::Crt::Io::TlsContext tlsContext(tlsCtxOptions, Aws::Crt::Io::TlsMode::CLIENT, allocator); ASSERT_TRUE(tlsContext); + int *leaked = new int; + (void)leaked; + Aws::Crt::Io::SocketOptions socketOptions; socketOptions.SetConnectTimeoutMs(3000); From 030eb69971ba52488225b6fcf902176ba7335307 Mon Sep 17 00:00:00 2001 From: Igor Abdrakhimov Date: Mon, 1 Apr 2024 09:16:48 -0700 Subject: [PATCH 07/47] Revert leak check --- devicedefender/tests/DeviceDefenderTest.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/devicedefender/tests/DeviceDefenderTest.cpp b/devicedefender/tests/DeviceDefenderTest.cpp index 561b87e6e..cb75c418c 100644 --- a/devicedefender/tests/DeviceDefenderTest.cpp +++ b/devicedefender/tests/DeviceDefenderTest.cpp @@ -147,9 +147,6 @@ static int s_TestMqtt5DeviceDefenderResourceSafety(Aws::Crt::Allocator *allocato Aws::Crt::Io::TlsContext tlsContext(tlsCtxOptions, Aws::Crt::Io::TlsMode::CLIENT, allocator); ASSERT_TRUE(tlsContext); - int *leaked = new int; - (void)leaked; - Aws::Crt::Io::SocketOptions socketOptions; socketOptions.SetConnectTimeoutMs(3000); From 8172f6783d56eb3a273e74fcda1b7d1f624ac3d0 Mon Sep 17 00:00:00 2001 From: Igor Abdrakhimov Date: Mon, 1 Apr 2024 09:24:52 -0700 Subject: [PATCH 08/47] Enable sanitizer for jobs --- .github/workflows/ci.yml | 16 +++++++- jobs/CMakeLists.txt | 38 ++++++++++--------- .../tests/JobsExecution/CMakeLists.txt | 2 + 3 files changed, 37 insertions(+), 19 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 650e0684a..b4e8066b9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -697,8 +697,22 @@ jobs: with: role-to-assume: ${{ env.CI_IOT_CONTAINERS }} aws-region: ${{ env.AWS_DEFAULT_REGION }} - # We can't use the `uses: docker://image` version yet, GitHub lacks authentication for actions -> packages - name: Build ${{ env.PACKAGE_NAME }} run: | aws s3 cp s3://aws-crt-test-stuff/ci/${{ env.BUILDER_VERSION }}/linux-container-ci.sh ./linux-container-ci.sh && chmod a+x ./linux-container-ci.sh ./linux-container-ci.sh ${{ env.BUILDER_VERSION }} aws-crt-${{ env.LINUX_BASE_IMAGE }} build -p ${{ env.PACKAGE_NAME }} --compiler=clang-12 --cmake-extra=-DENABLE_SANITIZERS=ON --cmake-extra=-DSANITIZERS="${{ matrix.sanitizers }}" + - name: configure AWS credentials (Jobs) + uses: aws-actions/configure-aws-credentials@v2 + with: + role-to-assume: ${{ env.CI_JOBS_SERVICE_CLIENT_ROLE }} + aws-region: ${{ env.AWS_DEFAULT_REGION }} + - name: run mqtt3 Jobs serviceTests + working-directory: ./aws-iot-device-sdk-cpp-v2/servicetests + run: | + export PYTHONPATH=${{ github.workspace }}/aws-iot-device-sdk-cpp-v2/utils + python3 ./test_cases/test_jobs_execution.py --config-file ${{ env.CI_SERVICE_TESTS_CFG_FOLDER }}/mqtt3_jobs_cfg.json + - name: run mqtt5 Jobs serviceTests + working-directory: ./aws-iot-device-sdk-cpp-v2/servicetests + run: | + export PYTHONPATH=${{ github.workspace }}/aws-iot-device-sdk-cpp-v2/utils + python3 ./test_cases/test_jobs_execution.py --config-file ${{ env.CI_SERVICE_TESTS_CFG_FOLDER }}/mqtt5_jobs_cfg.json diff --git a/jobs/CMakeLists.txt b/jobs/CMakeLists.txt index b1d054924..e28d87b21 100644 --- a/jobs/CMakeLists.txt +++ b/jobs/CMakeLists.txt @@ -46,27 +46,27 @@ if (WIN32) endif () endif() -add_library(IotJobs-cpp ${AWS_IOTJOBS_CPP_SRC}) +add_library(${PROJECT_NAME} ${AWS_IOTJOBS_CPP_SRC}) -set_target_properties(IotJobs-cpp PROPERTIES LINKER_LANGUAGE CXX) +set_target_properties(${PROJECT_NAME} PROPERTIES LINKER_LANGUAGE CXX) set(CMAKE_C_FLAGS_DEBUGOPT "") #set warnings if (MSVC) - target_compile_options(IotJobs-cpp PRIVATE /W4 /WX) + target_compile_options(${PROJECT_NAME} PRIVATE /W4 /WX) else () - target_compile_options(IotJobs-cpp PRIVATE -Wall -Wno-long-long -pedantic -Werror) + target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wno-long-long -pedantic -Werror) endif () -target_compile_definitions(IotJobs-cpp PRIVATE $<$:DEBUG_BUILD>) +target_compile_definitions(${PROJECT_NAME} PRIVATE $<$:DEBUG_BUILD>) if (BUILD_SHARED_LIBS) - target_compile_definitions(IotJobs-cpp PUBLIC "-DAWS_IOTJOBS_USE_IMPORT_EXPORT") - target_compile_definitions(IotJobs-cpp PRIVATE "-DAWS_IOTJOBS_EXPORTS") + target_compile_definitions(${PROJECT_NAME} PUBLIC "-DAWS_IOTJOBS_USE_IMPORT_EXPORT") + target_compile_definitions(${PROJECT_NAME} PRIVATE "-DAWS_IOTJOBS_EXPORTS") - install(TARGETS IotJobs-cpp - EXPORT IotJobs-cpp-targets + install(TARGETS ${PROJECT_NAME} + EXPORT ${PROJECT_NAME}-targets ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT Development @@ -78,20 +78,20 @@ if (BUILD_SHARED_LIBS) DESTINATION ${RUNTIME_DIRECTORY} COMPONENT Runtime) - install(TARGETS IotJobs-cpp - EXPORT IotJobs-cpp-targets + install(TARGETS ${PROJECT_NAME} + EXPORT ${PROJECT_NAME}-targets LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} NAMELINK_ONLY COMPONENT Development) else() - install(TARGETS IotJobs-cpp - EXPORT IotJobs-cpp-targets + install(TARGETS ${PROJECT_NAME} + EXPORT ${PROJECT_NAME}-targets ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT Development) endif() -target_include_directories(IotJobs-cpp PUBLIC +target_include_directories(${PROJECT_NAME} PUBLIC $ $) @@ -101,7 +101,9 @@ if (BUILD_DEPS) endif() endif() -target_link_libraries(IotJobs-cpp ${DEP_AWS_LIBS}) +aws_add_sanitizers(${PROJECT_NAME}) + +target_link_libraries(${PROJECT_NAME} PUBLIC ${DEP_AWS_LIBS}) install(FILES ${AWS_IOTJOBS_HEADERS} DESTINATION "include/aws/iotjobs/" COMPONENT Development) @@ -119,8 +121,8 @@ if (DEFINED SIMPLE_VERSION) ) endif() -install(EXPORT "IotJobs-cpp-targets" - DESTINATION "${CMAKE_INSTALL_LIBDIR}/IotJobs-cpp/cmake/${TARGET_DIR}" +install(EXPORT "${PROJECT_NAME}-targets" + DESTINATION "${CMAKE_INSTALL_LIBDIR}/${PROJECT_NAME}/cmake/${TARGET_DIR}" NAMESPACE AWS:: COMPONENT Development) @@ -129,5 +131,5 @@ configure_file("cmake/iotjobs-cpp-config.cmake" @ONLY) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/iotjobs-cpp-config.cmake" - DESTINATION "${CMAKE_INSTALL_LIBDIR}/IotJobs-cpp/cmake/" + DESTINATION "${CMAKE_INSTALL_LIBDIR}/${PROJECT_NAME}/cmake/" COMPONENT Development) diff --git a/servicetests/tests/JobsExecution/CMakeLists.txt b/servicetests/tests/JobsExecution/CMakeLists.txt index 70577d337..9a6e20b46 100644 --- a/servicetests/tests/JobsExecution/CMakeLists.txt +++ b/servicetests/tests/JobsExecution/CMakeLists.txt @@ -25,4 +25,6 @@ find_package(IotJobs-cpp REQUIRED) install(TARGETS ${PROJECT_NAME} DESTINATION bin) +aws_add_sanitizers(${PROJECT_NAME}) + target_link_libraries(${PROJECT_NAME} PRIVATE AWS::aws-crt-cpp AWS::IotJobs-cpp) From 9691b6056cc3e7f4a8c43c77f0c29242ca8f8499 Mon Sep 17 00:00:00 2001 From: Igor Abdrakhimov Date: Mon, 1 Apr 2024 09:25:07 -0700 Subject: [PATCH 09/47] Verify sanitizer works --- jobs/source/IotJobsClient.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/jobs/source/IotJobsClient.cpp b/jobs/source/IotJobsClient.cpp index c0cb1cf0c..4f1df2a1b 100644 --- a/jobs/source/IotJobsClient.cpp +++ b/jobs/source/IotJobsClient.cpp @@ -31,6 +31,9 @@ namespace Aws IotJobsClient::IotJobsClient(const std::shared_ptr &connection) : m_connection(connection) { + // TODO Remove. + int *leak = new int; + (void)leak; } IotJobsClient::IotJobsClient(const std::shared_ptr &mqtt5Client) From 1f5a388a8aec6923fb5182aa9567b807f0e7ec1b Mon Sep 17 00:00:00 2001 From: Igor Abdrakhimov Date: Mon, 1 Apr 2024 12:16:31 -0700 Subject: [PATCH 10/47] Fix adding sanitizer in tests --- servicetests/tests/JobsExecution/CMakeLists.txt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/servicetests/tests/JobsExecution/CMakeLists.txt b/servicetests/tests/JobsExecution/CMakeLists.txt index 9a6e20b46..09bcd927e 100644 --- a/servicetests/tests/JobsExecution/CMakeLists.txt +++ b/servicetests/tests/JobsExecution/CMakeLists.txt @@ -23,6 +23,20 @@ endif () find_package(aws-crt-cpp REQUIRED) find_package(IotJobs-cpp REQUIRED) +if (UNIX AND NOT APPLE) + include(GNUInstallDirs) +elseif(NOT DEFINED CMAKE_INSTALL_LIBDIR) + set(CMAKE_INSTALL_LIBDIR "lib") + + if (${CMAKE_INSTALL_LIBDIR} STREQUAL "lib64") + set(FIND_LIBRARY_USE_LIB64_PATHS true) + endif() +endif() + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_PREFIX_PATH}/${CMAKE_INSTALL_LIBDIR}/cmake") + +include(AwsSanitizers) + install(TARGETS ${PROJECT_NAME} DESTINATION bin) aws_add_sanitizers(${PROJECT_NAME}) From 4fcc0dc0c63c563507c56781752845bf4f27ff41 Mon Sep 17 00:00:00 2001 From: Igor Abdrakhimov Date: Mon, 1 Apr 2024 13:41:17 -0700 Subject: [PATCH 11/47] Fix sanitizer for tests --- servicetests/tests/JobsExecution/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/servicetests/tests/JobsExecution/CMakeLists.txt b/servicetests/tests/JobsExecution/CMakeLists.txt index 09bcd927e..5efff50e7 100644 --- a/servicetests/tests/JobsExecution/CMakeLists.txt +++ b/servicetests/tests/JobsExecution/CMakeLists.txt @@ -35,10 +35,10 @@ endif() list(APPEND CMAKE_MODULE_PATH "${CMAKE_PREFIX_PATH}/${CMAKE_INSTALL_LIBDIR}/cmake") -include(AwsSanitizers) - install(TARGETS ${PROJECT_NAME} DESTINATION bin) +include(AwsSanitizers) +enable_language(C) aws_add_sanitizers(${PROJECT_NAME}) target_link_libraries(${PROJECT_NAME} PRIVATE AWS::aws-crt-cpp AWS::IotJobs-cpp) From d2083054ea54c27907a6534751c757f7fd46c939 Mon Sep 17 00:00:00 2001 From: Igor Abdrakhimov Date: Mon, 1 Apr 2024 14:01:56 -0700 Subject: [PATCH 12/47] Change building --- .github/workflows/ci.yml | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b4e8066b9..50dae4c06 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -688,19 +688,21 @@ jobs: runs-on: ubuntu-22.04 # latest strategy: matrix: - sanitizers: ["thread", "address,undefined"] + sanitizer-variants: ["tsan", "asan"] permissions: id-token: write # This is required for requesting the JWT steps: - - name: configure AWS credentials (containers) - uses: aws-actions/configure-aws-credentials@v2 - with: - role-to-assume: ${{ env.CI_IOT_CONTAINERS }} - aws-region: ${{ env.AWS_DEFAULT_REGION }} - - name: Build ${{ env.PACKAGE_NAME }} + - name: Build ${{ env.PACKAGE_NAME }} + consumers run: | - aws s3 cp s3://aws-crt-test-stuff/ci/${{ env.BUILDER_VERSION }}/linux-container-ci.sh ./linux-container-ci.sh && chmod a+x ./linux-container-ci.sh - ./linux-container-ci.sh ${{ env.BUILDER_VERSION }} aws-crt-${{ env.LINUX_BASE_IMAGE }} build -p ${{ env.PACKAGE_NAME }} --compiler=clang-12 --cmake-extra=-DENABLE_SANITIZERS=ON --cmake-extra=-DSANITIZERS="${{ matrix.sanitizers }}" + echo "Downloading source" + git clone --recursive https://github.com/aws/aws-iot-device-sdk-cpp-v2.git --branch ${{ env.HEAD_REF || github.ref_name }} + echo "Running builder" + python -c "from urllib.request import urlretrieve; urlretrieve('${{ env.BUILDER_HOST }}/${{ env.BUILDER_SOURCE }}/${{ env.BUILDER_VERSION }}/builder.pyz?run=${{ env.RUN }}', 'builder.pyz')" + python builder.pyz build -p ${{ env.PACKAGE_NAME }} --variant ${{ matrix.sanitizer-variants }} + - name: Running samples in CI setup + run: | + python3 -m pip install boto3 + sudo apt-get update -y - name: configure AWS credentials (Jobs) uses: aws-actions/configure-aws-credentials@v2 with: From 673b32f068bd15e445d22af8e4c3270d78f78925 Mon Sep 17 00:00:00 2001 From: Igor Abdrakhimov Date: Mon, 1 Apr 2024 14:04:51 -0700 Subject: [PATCH 13/47] Define builder variants --- builder.json | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/builder.json b/builder.json index 2a014ee07..e52c753c0 100644 --- a/builder.json +++ b/builder.json @@ -28,6 +28,26 @@ "!build_steps": [ "build" ] + }, + "tsan": { + "compilers": { + "clang": { + "cmake_args": [ + "-DENABLE_SANITIZERS=ON", + "-DSANTIZERS=thread" + ] + } + } + }, + "asan": { + "compilers": { + "clang": { + "cmake_args": [ + "-DENABLE_SANITIZERS=ON", + "-DSANTIZERS=address,undefines" + ] + } + } } } } From 1395a76f6c5ebfa7aaee1b3ae46738c04d0748d0 Mon Sep 17 00:00:00 2001 From: Igor Abdrakhimov Date: Mon, 1 Apr 2024 14:07:13 -0700 Subject: [PATCH 14/47] Fix typo --- builder.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builder.json b/builder.json index e52c753c0..56c64fd35 100644 --- a/builder.json +++ b/builder.json @@ -44,7 +44,7 @@ "clang": { "cmake_args": [ "-DENABLE_SANITIZERS=ON", - "-DSANTIZERS=address,undefines" + "-DSANTIZERS=address,undefined" ] } } From 1ca715cc71812f6832864bc92331c4549c556ee5 Mon Sep 17 00:00:00 2001 From: Igor Abdrakhimov Date: Mon, 1 Apr 2024 14:33:05 -0700 Subject: [PATCH 15/47] Fix builder.json --- builder.json | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/builder.json b/builder.json index 56c64fd35..ad4fe6b80 100644 --- a/builder.json +++ b/builder.json @@ -30,24 +30,16 @@ ] }, "tsan": { - "compilers": { - "clang": { - "cmake_args": [ - "-DENABLE_SANITIZERS=ON", - "-DSANTIZERS=thread" - ] - } - } + "cmake_args": [ + "-DENABLE_SANITIZERS=ON", + "-DSANITIZERS=thread" + ] }, "asan": { - "compilers": { - "clang": { - "cmake_args": [ - "-DENABLE_SANITIZERS=ON", - "-DSANTIZERS=address,undefined" - ] - } - } + "cmake_args": [ + "-DENABLE_SANITIZERS=ON", + "-DSANTIIZERS=address,undefined" + ] } } } From ce3c5786e9c61361a0206bd84d62c847983fea44 Mon Sep 17 00:00:00 2001 From: Igor Abdrakhimov Date: Mon, 1 Apr 2024 16:52:25 -0700 Subject: [PATCH 16/47] Enable sanitizer for all --- .github/workflows/ci.yml | 203 ++++++++++++++++++ discovery/CMakeLists.txt | 1 + eventstream_rpc/CMakeLists.txt | 4 +- eventstream_rpc/tests/CMakeLists.txt | 1 + greengrass_ipc/CMakeLists.txt | 4 +- identity/CMakeLists.txt | 1 + .../basic_report/CMakeLists.txt | 18 +- .../mqtt5_basic_report/CMakeLists.txt | 18 +- .../fleet_provisioning/CMakeLists.txt | 16 ++ .../mqtt5_fleet_provisioning/CMakeLists.txt | 16 ++ .../greengrass/basic_discovery/CMakeLists.txt | 16 ++ samples/greengrass/ipc/CMakeLists.txt | 16 ++ samples/jobs/job_execution/CMakeLists.txt | 16 ++ .../jobs/mqtt5_job_execution/CMakeLists.txt | 16 ++ samples/mqtt/basic_connect/CMakeLists.txt | 18 +- samples/mqtt/cognito_connect/CMakeLists.txt | 18 +- .../custom_authorizer_connect/CMakeLists.txt | 18 +- samples/mqtt/pkcs11_connect/CMakeLists.txt | 18 +- samples/mqtt/pkcs12_connect/CMakeLists.txt | 18 +- samples/mqtt/websocket_connect/CMakeLists.txt | 18 +- .../mqtt/windows_cert_connect/CMakeLists.txt | 16 ++ .../CMakeLists.txt | 18 +- samples/mqtt5/mqtt5_pubsub/CMakeLists.txt | 18 +- .../mqtt5_shared_subscription/CMakeLists.txt | 18 +- samples/pub_sub/basic_pub_sub/CMakeLists.txt | 18 +- samples/pub_sub/cycle_pub_sub/CMakeLists.txt | 18 +- .../secure_tunnel/CMakeLists.txt | 18 +- .../tunnel_notification/CMakeLists.txt | 16 ++ .../shadow/mqtt5_shadow_sync/CMakeLists.txt | 16 ++ samples/shadow/shadow_sync/CMakeLists.txt | 16 ++ secure_tunneling/CMakeLists.txt | 39 ++-- secure_tunneling/tests/CMakeLists.txt | 18 +- .../tests/JobsExecution/CMakeLists.txt | 4 +- shadow/CMakeLists.txt | 38 ++-- 34 files changed, 667 insertions(+), 58 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 50dae4c06..10cc437ce 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -686,7 +686,9 @@ jobs: clang-sanitizers: runs-on: ubuntu-22.04 # latest + continue-on-error: true # TODO temporary for debugging purpose strategy: + fail-fast: false # TODO temporary for debugging purpose matrix: sanitizer-variants: ["tsan", "asan"] permissions: @@ -703,18 +705,219 @@ jobs: run: | python3 -m pip install boto3 sudo apt-get update -y + - name: configure AWS credentials (Fleet provisioning) + if: always() + uses: aws-actions/configure-aws-credentials@v2 + with: + role-to-assume: ${{ env.CI_FLEET_PROVISIONING_ROLE }} + aws-region: ${{ env.AWS_DEFAULT_REGION }} + - name: run Fleet Provisioning service client test for MQTT311 + if: always() + working-directory: ./aws-iot-device-sdk-cpp-v2/servicetests + run: | + export PYTHONPATH=${{ github.workspace }}/aws-iot-device-sdk-cpp-v2/utils + python3 ./test_cases/test_fleet_provisioning.py --config-file test_cases/mqtt3_fleet_provisioning_cfg.json --thing-name-prefix Fleet_Thing_ + - name: run Fleet Provisioning service client test for MQTT5 + if: always() + working-directory: ./aws-iot-device-sdk-cpp-v2/servicetests + run: | + export PYTHONPATH=${{ github.workspace }}/aws-iot-device-sdk-cpp-v2/utils + python3 ./test_cases/test_fleet_provisioning.py --config-file test_cases/mqtt5_fleet_provisioning_cfg.json --thing-name-prefix Fleet_Thing_ + - name: run Fleet Provisioning with CSR service client test for MQTT311 + if: always() + working-directory: ./aws-iot-device-sdk-cpp-v2/servicetests + run: | + export PYTHONPATH=${{ github.workspace }}/aws-iot-device-sdk-cpp-v2/utils + python3 ./test_cases/test_fleet_provisioning.py --config-file test_cases/mqtt3_fleet_provisioning_with_csr_cfg.json --thing-name-prefix Fleet_Thing_ + - name: run Fleet Provisioning with CSR service client test for MQTT5 + if: always() + working-directory: ./aws-iot-device-sdk-cpp-v2/servicetests + run: | + export PYTHONPATH=${{ github.workspace }}/aws-iot-device-sdk-cpp-v2/utils + python3 ./test_cases/test_fleet_provisioning.py --config-file test_cases/mqtt5_fleet_provisioning_with_csr_cfg.json --thing-name-prefix Fleet_Thing_ - name: configure AWS credentials (Jobs) + if: always() uses: aws-actions/configure-aws-credentials@v2 with: role-to-assume: ${{ env.CI_JOBS_SERVICE_CLIENT_ROLE }} aws-region: ${{ env.AWS_DEFAULT_REGION }} - name: run mqtt3 Jobs serviceTests + if: always() working-directory: ./aws-iot-device-sdk-cpp-v2/servicetests run: | export PYTHONPATH=${{ github.workspace }}/aws-iot-device-sdk-cpp-v2/utils python3 ./test_cases/test_jobs_execution.py --config-file ${{ env.CI_SERVICE_TESTS_CFG_FOLDER }}/mqtt3_jobs_cfg.json - name: run mqtt5 Jobs serviceTests + if: always() working-directory: ./aws-iot-device-sdk-cpp-v2/servicetests run: | export PYTHONPATH=${{ github.workspace }}/aws-iot-device-sdk-cpp-v2/utils python3 ./test_cases/test_jobs_execution.py --config-file ${{ env.CI_SERVICE_TESTS_CFG_FOLDER }}/mqtt5_jobs_cfg.json + - name: configure AWS credentials (Shadow) + if: always() + uses: aws-actions/configure-aws-credentials@v2 + with: + role-to-assume: ${{ env.CI_SHADOW_SERVICE_CLIENT_ROLE }} + aws-region: ${{ env.AWS_DEFAULT_REGION }} + - name: run Shadow service client test for MQTT5 + if: always() + working-directory: ./aws-iot-device-sdk-cpp-v2/servicetests + run: | + export PYTHONPATH=${{ github.workspace }}/aws-iot-device-sdk-cpp-v2/utils + python3 ./test_cases/test_shadow_update.py --config-file test_cases/mqtt5_shadow_cfg.json + - name: run Shadow service client test for MQTT311 + if: always() + working-directory: ./aws-iot-device-sdk-cpp-v2/servicetests + run: | + export PYTHONPATH=${{ github.workspace }}/aws-iot-device-sdk-cpp-v2/utils + python3 ./test_cases/test_shadow_update.py --config-file test_cases/mqtt3_shadow_cfg.json + - name: run Named Shadow service client test for MQTT311 + if: always() + working-directory: ./aws-iot-device-sdk-cpp-v2/servicetests + run: | + export PYTHONPATH=${{ github.workspace }}/aws-iot-device-sdk-cpp-v2/utils + python3 ./test_cases/test_shadow_update.py --config-file test_cases/mqtt3_named_shadow_cfg.json + - name: run Named Shadow service client test for MQTT5 + if: always() + working-directory: ./aws-iot-device-sdk-cpp-v2/servicetests + run: | + export PYTHONPATH=${{ github.workspace }}/aws-iot-device-sdk-cpp-v2/utils + python3 ./test_cases/test_shadow_update.py --config-file test_cases/mqtt5_named_shadow_cfg.json + - name: configure AWS credentials (Connect and PubSub) + if: always() + uses: aws-actions/configure-aws-credentials@v2 + with: + role-to-assume: ${{ env.CI_PUBSUB_ROLE }} + aws-region: ${{ env.AWS_DEFAULT_REGION }} + - name: run Basic Connect sample + if: always() + run: | + python3 ${{ env.CI_UTILS_FOLDER }}/run_sample_ci.py --file ${{ env.CI_SAMPLES_CFG_FOLDER }}/ci_run_basic_connect_cfg.json + - name: run Websocket Connect sample + if: always() + run: | + python3 ${{ env.CI_UTILS_FOLDER }}/run_sample_ci.py --file ${{ env.CI_SAMPLES_CFG_FOLDER }}/ci_run_websocket_connect_cfg.json + - name: run MQTT3 PubSub sample + if: always() + run: | + python3 ${{ env.CI_UTILS_FOLDER }}/run_sample_ci.py --file ${{ env.CI_SAMPLES_CFG_FOLDER }}/ci_run_pubsub_cfg.json + - name: run PKCS11 Connect sample + if: always() + run: | + mkdir -p /tmp/tokens + export SOFTHSM2_CONF=/tmp/softhsm2.conf + echo "directories.tokendir = /tmp/tokens" > /tmp/softhsm2.conf + python3 ${{ env.CI_UTILS_FOLDER }}/run_sample_ci.py --file ${{ env.CI_SAMPLES_CFG_FOLDER }}/ci_run_pkcs11_connect_cfg.json + - name: configure AWS credentials (MQTT5) + if: always() + uses: aws-actions/configure-aws-credentials@v2 + with: + role-to-assume: ${{ env.CI_MQTT5_ROLE }} + aws-region: ${{ env.AWS_DEFAULT_REGION }} + - name: run MQTT5 PubSub sample + if: always() + run: | + python3 ${{ env.CI_UTILS_FOLDER }}/run_sample_ci.py --file ${{ env.CI_SAMPLES_CFG_FOLDER }}/ci_run_mqtt5_pubsub_cfg.json + - name: run MQTT5 Shared Subscription sample + if: always() + run: | + python3 ${{ env.CI_UTILS_FOLDER }}/run_sample_ci.py --file ${{ env.CI_SAMPLES_CFG_FOLDER }}/ci_run_mqtt5_shared_subscription_cfg.json + - name: configure AWS credentials (Jobs) + if: always() + uses: aws-actions/configure-aws-credentials@v2 + with: + role-to-assume: ${{ env.CI_JOBS_ROLE }} + aws-region: ${{ env.AWS_DEFAULT_REGION }} + - name: run Jobs sample + if: always() + run: | + python3 ${{ env.CI_UTILS_FOLDER }}/run_sample_ci.py --file ${{ env.CI_SAMPLES_CFG_FOLDER }}/ci_run_jobs_cfg.json + - name: run Mqtt5 Jobs sample + if: always() + run: | + python3 ${{ env.CI_UTILS_FOLDER }}/run_sample_ci.py --file ${{ env.CI_SAMPLES_CFG_FOLDER }}/ci_run_jobs_mqtt5_cfg.json + - name: configure AWS credentials (Cognito) + if: always() + uses: aws-actions/configure-aws-credentials@v2 + with: + role-to-assume: ${{ env.CI_COGNITO_ROLE }} + aws-region: ${{ env.AWS_DEFAULT_REGION }} + - name: run CognitoConnect sample + if: always() + run: | + python3 ${{ env.CI_UTILS_FOLDER }}/run_sample_ci.py --file ${{ env.CI_SAMPLES_CFG_FOLDER }}/ci_run_cognito_connect_cfg.json + - name: configure AWS credentials (Custom Authorizer) + if: always() + uses: aws-actions/configure-aws-credentials@v2 + with: + role-to-assume: ${{ env.CI_CUSTOM_AUTHORIZER_ROLE }} + aws-region: ${{ env.AWS_DEFAULT_REGION }} + - name: run CustomAuthorizerConnect sample + if: always() + run: | + python3 ${{ env.CI_UTILS_FOLDER }}/run_sample_ci.py --file ${{ env.CI_SAMPLES_CFG_FOLDER }}/ci_run_custom_authorizer_connect_cfg.json + - name: configure AWS credentials (Shadow) + if: always() + uses: aws-actions/configure-aws-credentials@v2 + with: + role-to-assume: ${{ env.CI_SHADOW_ROLE }} + aws-region: ${{ env.AWS_DEFAULT_REGION }} + - name: run Shadow sample + if: always() + run: | + python3 ${{ env.CI_UTILS_FOLDER }}/run_sample_ci.py --file ${{ env.CI_SAMPLES_CFG_FOLDER }}/ci_run_shadow_cfg.json + - name: run Mqtt5 Shadow sample + if: always() + run: | + python3 ${{ env.CI_UTILS_FOLDER }}/run_sample_ci.py --file ${{ env.CI_SAMPLES_CFG_FOLDER }}/ci_run_shadow_mqtt5_cfg.json + - name: configure AWS credentials (Fleet provisioning) + if: always() + uses: aws-actions/configure-aws-credentials@v2 + with: + role-to-assume: ${{ env.CI_FLEET_PROVISIONING_ROLE }} + aws-region: ${{ env.AWS_DEFAULT_REGION }} + - name: run Fleet Provisioning sample + if: always() + run: | + echo "Generating UUID for IoT thing" + Sample_UUID=$(python3 -c "import uuid; print (uuid.uuid4())") + python3 ${{ env.CI_UTILS_FOLDER }}/run_sample_ci.py --file ${{ env.CI_SAMPLES_CFG_FOLDER }}/ci_run_fleet_provisioning_cfg.json --input_uuid ${Sample_UUID} + python3 ${{ env.CI_UTILS_FOLDER }}/delete_iot_thing_ci.py --thing_name "Fleet_Thing_${Sample_UUID}" --region "us-east-1" + - name: run Mqtt5 Fleet Provisioning sample + if: always() + run: | + echo "Generating UUID for IoT thing" + Sample_UUID=$(python3 -c "import uuid; print (uuid.uuid4())") + python3 ${{ env.CI_UTILS_FOLDER }}/run_sample_ci.py --file ${{ env.CI_SAMPLES_CFG_FOLDER }}/ci_run_fleet_provisioning_mqtt5_cfg.json --input_uuid ${Sample_UUID} + python3 ${{ env.CI_UTILS_FOLDER }}/delete_iot_thing_ci.py --thing_name "Fleet_Thing_${Sample_UUID}" --region "us-east-1" + - name: configure AWS credentials (Secure tunneling) + if: always() + uses: aws-actions/configure-aws-credentials@v2 + with: + role-to-assume: ${{ env.CI_SECURE_TUNNEL }} + aws-region: ${{ env.AWS_DEFAULT_REGION }} + # Secure Tunneling has special requirements, so it uses a different Python file + - name: run Secure Tunneling sample + if: always() + run: | + python3 ${{ env.CI_UTILS_FOLDER }}/run_secure_tunnel_ci.py --sample_file "./aws-iot-device-sdk-cpp-v2/build/samples/secure_tunneling/secure_tunnel/secure-tunnel" --sample_region ${{ env.AWS_DEFAULT_REGION }} + - name: configure AWS credentials (X509) + if: always() + uses: aws-actions/configure-aws-credentials@v2 + with: + role-to-assume: ${{ env.CI_X509_ROLE }} + aws-region: ${{ env.AWS_DEFAULT_REGION }} + - name: run X509 sample + if: always() + run: | + python3 ${{ env.CI_UTILS_FOLDER }}/run_sample_ci.py --file ${{ env.CI_SAMPLES_CFG_FOLDER }}/ci_run_x509_connect_cfg.json + - name: configure AWS credentials (Greengrass) + if: always() + uses: aws-actions/configure-aws-credentials@v2 + with: + role-to-assume: ${{ env.CI_GREENGRASS_ROLE }} + aws-region: ${{ env.AWS_DEFAULT_REGION }} + - name: run Greengrass Discovery sample + if: always() + run: | + python3 ${{ env.CI_UTILS_FOLDER }}/run_sample_ci.py --file ${{ env.CI_SAMPLES_CFG_FOLDER }}/ci_run_greengrass_discovery_cfg.json diff --git a/discovery/CMakeLists.txt b/discovery/CMakeLists.txt index 58e364e36..84f48ca47 100644 --- a/discovery/CMakeLists.txt +++ b/discovery/CMakeLists.txt @@ -99,6 +99,7 @@ if (BUILD_DEPS) endif() endif() +aws_add_sanitizer(${PROJECT_NAME}) target_link_libraries(Discovery-cpp ${DEP_AWS_LIBS}) install(FILES ${AWS_DISCOVERY_HEADERS} DESTINATION "include/aws/discovery/" COMPONENT Development) diff --git a/eventstream_rpc/CMakeLists.txt b/eventstream_rpc/CMakeLists.txt index 5e5aa13b6..1d6e0c397 100644 --- a/eventstream_rpc/CMakeLists.txt +++ b/eventstream_rpc/CMakeLists.txt @@ -97,8 +97,8 @@ if (NOT IS_SUBDIRECTORY_INCLUDE) aws_use_package(aws-crt-cpp) endif() - -target_link_libraries(EventstreamRpc-cpp ${DEP_AWS_LIBS}) +aws_add_sanitizer(${PROJECT_NAME}) +target_link_libraries(EventstreamRpc-cpp PUBLIC ${DEP_AWS_LIBS}) install(FILES ${AWS_EVENTSTREAMRPC_HEADERS} DESTINATION "include/aws/eventstreamrpc/" COMPONENT Development) diff --git a/eventstream_rpc/tests/CMakeLists.txt b/eventstream_rpc/tests/CMakeLists.txt index 988b2ef12..6d7d99d3d 100644 --- a/eventstream_rpc/tests/CMakeLists.txt +++ b/eventstream_rpc/tests/CMakeLists.txt @@ -47,6 +47,7 @@ add_test_case(OperateWhileDisconnected) #add_test_case(EchoOperation) #add_test_case(StressTestClient) generate_cpp_test_driver(${TEST_BINARY_NAME}) +aws_add_sanitizer(${TEST_BINARY_NAME}) target_include_directories(${TEST_BINARY_NAME} PUBLIC $ $) diff --git a/greengrass_ipc/CMakeLists.txt b/greengrass_ipc/CMakeLists.txt index 1e66deb48..a2fc34301 100644 --- a/greengrass_ipc/CMakeLists.txt +++ b/greengrass_ipc/CMakeLists.txt @@ -105,8 +105,8 @@ if (NOT IS_SUBDIRECTORY_INCLUDE) aws_use_package(aws-crt-cpp) endif() - -target_link_libraries(GreengrassIpc-cpp ${DEP_AWS_LIBS}) +aws_add_sanitizer(${PROJECT_NAME}) +target_link_libraries(GreengrassIpc-cpp PUBLIC ${DEP_AWS_LIBS}) install(FILES ${AWS_GREENGRASSIPC_HEADERS} DESTINATION "include/aws/greengrass/" COMPONENT Development) diff --git a/identity/CMakeLists.txt b/identity/CMakeLists.txt index e843c0ff5..d0eb1173f 100644 --- a/identity/CMakeLists.txt +++ b/identity/CMakeLists.txt @@ -91,6 +91,7 @@ else() COMPONENT Development) endif() +aws_add_sanitizer(${PROJECT_NAME}) target_include_directories(IotIdentity-cpp PUBLIC $ $) diff --git a/samples/device_defender/basic_report/CMakeLists.txt b/samples/device_defender/basic_report/CMakeLists.txt index a973fcb4b..8336a35f7 100644 --- a/samples/device_defender/basic_report/CMakeLists.txt +++ b/samples/device_defender/basic_report/CMakeLists.txt @@ -24,6 +24,22 @@ if (UNIX AND NOT APPLE) find_package(IotDeviceCommon-cpp REQUIRED) find_package(IotDeviceDefender-cpp REQUIRED) - target_link_libraries(${PROJECT_NAME} AWS::aws-crt-cpp AWS::IotDeviceCommon-cpp AWS::IotDeviceDefender-cpp) + if (UNIX AND NOT APPLE) + include(GNUInstallDirs) + elseif(NOT DEFINED CMAKE_INSTALL_LIBDIR) + set(CMAKE_INSTALL_LIBDIR "lib") + + if (${CMAKE_INSTALL_LIBDIR} STREQUAL "lib64") + set(FIND_LIBRARY_USE_LIB64_PATHS true) + endif() + endif() + + list(APPEND CMAKE_MODULE_PATH "${CMAKE_PREFIX_PATH}/${CMAKE_INSTALL_LIBDIR}/cmake") + + include(AwsSanitizers) + enable_language(C) + aws_add_sanitizers(${PROJECT_NAME}) + + target_link_libraries(${PROJECT_NAME} PRIVATE AWS::aws-crt-cpp AWS::IotDeviceCommon-cpp AWS::IotDeviceDefender-cpp) endif() diff --git a/samples/device_defender/mqtt5_basic_report/CMakeLists.txt b/samples/device_defender/mqtt5_basic_report/CMakeLists.txt index ecb8ef996..ed4ee9b06 100644 --- a/samples/device_defender/mqtt5_basic_report/CMakeLists.txt +++ b/samples/device_defender/mqtt5_basic_report/CMakeLists.txt @@ -24,6 +24,22 @@ if (UNIX AND NOT APPLE) find_package(IotDeviceCommon-cpp REQUIRED) find_package(IotDeviceDefender-cpp REQUIRED) - target_link_libraries(${PROJECT_NAME} AWS::aws-crt-cpp AWS::IotDeviceCommon-cpp AWS::IotDeviceDefender-cpp) + if (UNIX AND NOT APPLE) + include(GNUInstallDirs) + elseif(NOT DEFINED CMAKE_INSTALL_LIBDIR) + set(CMAKE_INSTALL_LIBDIR "lib") + + if (${CMAKE_INSTALL_LIBDIR} STREQUAL "lib64") + set(FIND_LIBRARY_USE_LIB64_PATHS true) + endif() + endif() + + list(APPEND CMAKE_MODULE_PATH "${CMAKE_PREFIX_PATH}/${CMAKE_INSTALL_LIBDIR}/cmake") + + include(AwsSanitizers) + enable_language(C) + aws_add_sanitizers(${PROJECT_NAME}) + + target_link_libraries(${PROJECT_NAME} PRIVATE AWS::aws-crt-cpp AWS::IotDeviceCommon-cpp AWS::IotDeviceDefender-cpp) endif() diff --git a/samples/fleet_provisioning/fleet_provisioning/CMakeLists.txt b/samples/fleet_provisioning/fleet_provisioning/CMakeLists.txt index 52b9fb458..71d2badd3 100644 --- a/samples/fleet_provisioning/fleet_provisioning/CMakeLists.txt +++ b/samples/fleet_provisioning/fleet_provisioning/CMakeLists.txt @@ -25,4 +25,20 @@ find_package(IotIdentity-cpp REQUIRED) install(TARGETS ${PROJECT_NAME} DESTINATION bin) +if (UNIX AND NOT APPLE) + include(GNUInstallDirs) +elseif(NOT DEFINED CMAKE_INSTALL_LIBDIR) + set(CMAKE_INSTALL_LIBDIR "lib") + + if (${CMAKE_INSTALL_LIBDIR} STREQUAL "lib64") + set(FIND_LIBRARY_USE_LIB64_PATHS true) + endif() +endif() + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_PREFIX_PATH}/${CMAKE_INSTALL_LIBDIR}/cmake") + +include(AwsSanitizers) +enable_language(C) +aws_add_sanitizers(${PROJECT_NAME}) + target_link_libraries(${PROJECT_NAME} PRIVATE AWS::aws-crt-cpp AWS::IotIdentity-cpp) diff --git a/samples/fleet_provisioning/mqtt5_fleet_provisioning/CMakeLists.txt b/samples/fleet_provisioning/mqtt5_fleet_provisioning/CMakeLists.txt index b13a3f34d..966a85621 100644 --- a/samples/fleet_provisioning/mqtt5_fleet_provisioning/CMakeLists.txt +++ b/samples/fleet_provisioning/mqtt5_fleet_provisioning/CMakeLists.txt @@ -25,4 +25,20 @@ find_package(IotIdentity-cpp REQUIRED) install(TARGETS ${PROJECT_NAME} DESTINATION bin) +if (UNIX AND NOT APPLE) + include(GNUInstallDirs) +elseif(NOT DEFINED CMAKE_INSTALL_LIBDIR) + set(CMAKE_INSTALL_LIBDIR "lib") + + if (${CMAKE_INSTALL_LIBDIR} STREQUAL "lib64") + set(FIND_LIBRARY_USE_LIB64_PATHS true) + endif() +endif() + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_PREFIX_PATH}/${CMAKE_INSTALL_LIBDIR}/cmake") + +include(AwsSanitizers) +enable_language(C) +aws_add_sanitizers(${PROJECT_NAME}) + target_link_libraries(${PROJECT_NAME} PRIVATE AWS::aws-crt-cpp AWS::IotIdentity-cpp) diff --git a/samples/greengrass/basic_discovery/CMakeLists.txt b/samples/greengrass/basic_discovery/CMakeLists.txt index 05bdb5a6d..e63301041 100644 --- a/samples/greengrass/basic_discovery/CMakeLists.txt +++ b/samples/greengrass/basic_discovery/CMakeLists.txt @@ -25,4 +25,20 @@ find_package(Discovery-cpp REQUIRED) install(TARGETS ${PROJECT_NAME} DESTINATION bin) +if (UNIX AND NOT APPLE) + include(GNUInstallDirs) +elseif(NOT DEFINED CMAKE_INSTALL_LIBDIR) + set(CMAKE_INSTALL_LIBDIR "lib") + + if (${CMAKE_INSTALL_LIBDIR} STREQUAL "lib64") + set(FIND_LIBRARY_USE_LIB64_PATHS true) + endif() +endif() + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_PREFIX_PATH}/${CMAKE_INSTALL_LIBDIR}/cmake") + +include(AwsSanitizers) +enable_language(C) +aws_add_sanitizers(${PROJECT_NAME}) + target_link_libraries(${PROJECT_NAME} PRIVATE AWS::aws-crt-cpp AWS::Discovery-cpp) diff --git a/samples/greengrass/ipc/CMakeLists.txt b/samples/greengrass/ipc/CMakeLists.txt index 646a7868f..af828820c 100644 --- a/samples/greengrass/ipc/CMakeLists.txt +++ b/samples/greengrass/ipc/CMakeLists.txt @@ -25,4 +25,20 @@ find_package(GreengrassIpc-cpp REQUIRED) install(TARGETS ${PROJECT_NAME} DESTINATION bin) +if (UNIX AND NOT APPLE) + include(GNUInstallDirs) +elseif(NOT DEFINED CMAKE_INSTALL_LIBDIR) + set(CMAKE_INSTALL_LIBDIR "lib") + + if (${CMAKE_INSTALL_LIBDIR} STREQUAL "lib64") + set(FIND_LIBRARY_USE_LIB64_PATHS true) + endif() +endif() + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_PREFIX_PATH}/${CMAKE_INSTALL_LIBDIR}/cmake") + +include(AwsSanitizers) +enable_language(C) +aws_add_sanitizers(${PROJECT_NAME}) + target_link_libraries(${PROJECT_NAME} PRIVATE AWS::aws-crt-cpp AWS::EventstreamRpc-cpp AWS::GreengrassIpc-cpp) diff --git a/samples/jobs/job_execution/CMakeLists.txt b/samples/jobs/job_execution/CMakeLists.txt index a0ce228b7..0681de27a 100644 --- a/samples/jobs/job_execution/CMakeLists.txt +++ b/samples/jobs/job_execution/CMakeLists.txt @@ -25,4 +25,20 @@ find_package(IotJobs-cpp REQUIRED) install(TARGETS ${PROJECT_NAME} DESTINATION bin) +if (UNIX AND NOT APPLE) + include(GNUInstallDirs) +elseif(NOT DEFINED CMAKE_INSTALL_LIBDIR) + set(CMAKE_INSTALL_LIBDIR "lib") + + if (${CMAKE_INSTALL_LIBDIR} STREQUAL "lib64") + set(FIND_LIBRARY_USE_LIB64_PATHS true) + endif() +endif() + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_PREFIX_PATH}/${CMAKE_INSTALL_LIBDIR}/cmake") + +include(AwsSanitizers) +enable_language(C) +aws_add_sanitizers(${PROJECT_NAME}) + target_link_libraries(${PROJECT_NAME} PRIVATE AWS::aws-crt-cpp AWS::IotJobs-cpp) diff --git a/samples/jobs/mqtt5_job_execution/CMakeLists.txt b/samples/jobs/mqtt5_job_execution/CMakeLists.txt index 0affcba5c..08dfe6e74 100644 --- a/samples/jobs/mqtt5_job_execution/CMakeLists.txt +++ b/samples/jobs/mqtt5_job_execution/CMakeLists.txt @@ -25,4 +25,20 @@ find_package(IotJobs-cpp REQUIRED) install(TARGETS ${PROJECT_NAME} DESTINATION bin) +if (UNIX AND NOT APPLE) + include(GNUInstallDirs) +elseif(NOT DEFINED CMAKE_INSTALL_LIBDIR) + set(CMAKE_INSTALL_LIBDIR "lib") + + if (${CMAKE_INSTALL_LIBDIR} STREQUAL "lib64") + set(FIND_LIBRARY_USE_LIB64_PATHS true) + endif() +endif() + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_PREFIX_PATH}/${CMAKE_INSTALL_LIBDIR}/cmake") + +include(AwsSanitizers) +enable_language(C) +aws_add_sanitizers(${PROJECT_NAME}) + target_link_libraries(${PROJECT_NAME} PRIVATE AWS::aws-crt-cpp AWS::IotJobs-cpp) diff --git a/samples/mqtt/basic_connect/CMakeLists.txt b/samples/mqtt/basic_connect/CMakeLists.txt index f80d0d512..ade2c301e 100644 --- a/samples/mqtt/basic_connect/CMakeLists.txt +++ b/samples/mqtt/basic_connect/CMakeLists.txt @@ -22,4 +22,20 @@ endif () find_package(aws-crt-cpp REQUIRED) -target_link_libraries(${PROJECT_NAME} AWS::aws-crt-cpp) +if (UNIX AND NOT APPLE) + include(GNUInstallDirs) +elseif(NOT DEFINED CMAKE_INSTALL_LIBDIR) + set(CMAKE_INSTALL_LIBDIR "lib") + + if (${CMAKE_INSTALL_LIBDIR} STREQUAL "lib64") + set(FIND_LIBRARY_USE_LIB64_PATHS true) + endif() +endif() + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_PREFIX_PATH}/${CMAKE_INSTALL_LIBDIR}/cmake") + +include(AwsSanitizers) +enable_language(C) +aws_add_sanitizers(${PROJECT_NAME}) + +target_link_libraries(${PROJECT_NAME} PRIVATE AWS::aws-crt-cpp) diff --git a/samples/mqtt/cognito_connect/CMakeLists.txt b/samples/mqtt/cognito_connect/CMakeLists.txt index 4e5f2a8b0..6a82cea4b 100644 --- a/samples/mqtt/cognito_connect/CMakeLists.txt +++ b/samples/mqtt/cognito_connect/CMakeLists.txt @@ -22,4 +22,20 @@ endif () find_package(aws-crt-cpp REQUIRED) -target_link_libraries(${PROJECT_NAME} AWS::aws-crt-cpp) +if (UNIX AND NOT APPLE) + include(GNUInstallDirs) +elseif(NOT DEFINED CMAKE_INSTALL_LIBDIR) + set(CMAKE_INSTALL_LIBDIR "lib") + + if (${CMAKE_INSTALL_LIBDIR} STREQUAL "lib64") + set(FIND_LIBRARY_USE_LIB64_PATHS true) + endif() +endif() + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_PREFIX_PATH}/${CMAKE_INSTALL_LIBDIR}/cmake") + +include(AwsSanitizers) +enable_language(C) +aws_add_sanitizers(${PROJECT_NAME}) + +target_link_libraries(${PROJECT_NAME} PRIVATE AWS::aws-crt-cpp) diff --git a/samples/mqtt/custom_authorizer_connect/CMakeLists.txt b/samples/mqtt/custom_authorizer_connect/CMakeLists.txt index 4a758056b..10425cd18 100644 --- a/samples/mqtt/custom_authorizer_connect/CMakeLists.txt +++ b/samples/mqtt/custom_authorizer_connect/CMakeLists.txt @@ -22,4 +22,20 @@ endif () find_package(aws-crt-cpp REQUIRED) -target_link_libraries(${PROJECT_NAME} AWS::aws-crt-cpp) +if (UNIX AND NOT APPLE) + include(GNUInstallDirs) +elseif(NOT DEFINED CMAKE_INSTALL_LIBDIR) + set(CMAKE_INSTALL_LIBDIR "lib") + + if (${CMAKE_INSTALL_LIBDIR} STREQUAL "lib64") + set(FIND_LIBRARY_USE_LIB64_PATHS true) + endif() +endif() + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_PREFIX_PATH}/${CMAKE_INSTALL_LIBDIR}/cmake") + +include(AwsSanitizers) +enable_language(C) +aws_add_sanitizers(${PROJECT_NAME}) + +target_link_libraries(${PROJECT_NAME} PRIVATE AWS::aws-crt-cpp) diff --git a/samples/mqtt/pkcs11_connect/CMakeLists.txt b/samples/mqtt/pkcs11_connect/CMakeLists.txt index e1f3c5d4e..e55aa52f0 100644 --- a/samples/mqtt/pkcs11_connect/CMakeLists.txt +++ b/samples/mqtt/pkcs11_connect/CMakeLists.txt @@ -32,4 +32,20 @@ endif() find_package(aws-crt-cpp REQUIRED) -target_link_libraries(${PROJECT_NAME} AWS::aws-crt-cpp) +if (UNIX AND NOT APPLE) + include(GNUInstallDirs) +elseif(NOT DEFINED CMAKE_INSTALL_LIBDIR) + set(CMAKE_INSTALL_LIBDIR "lib") + + if (${CMAKE_INSTALL_LIBDIR} STREQUAL "lib64") + set(FIND_LIBRARY_USE_LIB64_PATHS true) + endif() +endif() + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_PREFIX_PATH}/${CMAKE_INSTALL_LIBDIR}/cmake") + +include(AwsSanitizers) +enable_language(C) +aws_add_sanitizers(${PROJECT_NAME}) + +target_link_libraries(${PROJECT_NAME} PRIVATE AWS::aws-crt-cpp) diff --git a/samples/mqtt/pkcs12_connect/CMakeLists.txt b/samples/mqtt/pkcs12_connect/CMakeLists.txt index b257f8b37..8da66acb3 100644 --- a/samples/mqtt/pkcs12_connect/CMakeLists.txt +++ b/samples/mqtt/pkcs12_connect/CMakeLists.txt @@ -22,4 +22,20 @@ endif () find_package(aws-crt-cpp REQUIRED) -target_link_libraries(${PROJECT_NAME} AWS::aws-crt-cpp) +if (UNIX AND NOT APPLE) + include(GNUInstallDirs) +elseif(NOT DEFINED CMAKE_INSTALL_LIBDIR) + set(CMAKE_INSTALL_LIBDIR "lib") + + if (${CMAKE_INSTALL_LIBDIR} STREQUAL "lib64") + set(FIND_LIBRARY_USE_LIB64_PATHS true) + endif() +endif() + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_PREFIX_PATH}/${CMAKE_INSTALL_LIBDIR}/cmake") + +include(AwsSanitizers) +enable_language(C) +aws_add_sanitizers(${PROJECT_NAME}) + +target_link_libraries(${PROJECT_NAME} PRIVATE AWS::aws-crt-cpp) diff --git a/samples/mqtt/websocket_connect/CMakeLists.txt b/samples/mqtt/websocket_connect/CMakeLists.txt index 9b99fc7c2..8b98987ba 100644 --- a/samples/mqtt/websocket_connect/CMakeLists.txt +++ b/samples/mqtt/websocket_connect/CMakeLists.txt @@ -22,4 +22,20 @@ endif () find_package(aws-crt-cpp REQUIRED) -target_link_libraries(${PROJECT_NAME} AWS::aws-crt-cpp) +if (UNIX AND NOT APPLE) + include(GNUInstallDirs) +elseif(NOT DEFINED CMAKE_INSTALL_LIBDIR) + set(CMAKE_INSTALL_LIBDIR "lib") + + if (${CMAKE_INSTALL_LIBDIR} STREQUAL "lib64") + set(FIND_LIBRARY_USE_LIB64_PATHS true) + endif() +endif() + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_PREFIX_PATH}/${CMAKE_INSTALL_LIBDIR}/cmake") + +include(AwsSanitizers) +enable_language(C) +aws_add_sanitizers(${PROJECT_NAME}) + +target_link_libraries(${PROJECT_NAME} PRIVATE AWS::aws-crt-cpp) diff --git a/samples/mqtt/windows_cert_connect/CMakeLists.txt b/samples/mqtt/windows_cert_connect/CMakeLists.txt index 551a5dcc1..20c0dd6ab 100644 --- a/samples/mqtt/windows_cert_connect/CMakeLists.txt +++ b/samples/mqtt/windows_cert_connect/CMakeLists.txt @@ -22,4 +22,20 @@ endif () find_package(aws-crt-cpp REQUIRED) +if (UNIX AND NOT APPLE) + include(GNUInstallDirs) +elseif(NOT DEFINED CMAKE_INSTALL_LIBDIR) + set(CMAKE_INSTALL_LIBDIR "lib") + + if (${CMAKE_INSTALL_LIBDIR} STREQUAL "lib64") + set(FIND_LIBRARY_USE_LIB64_PATHS true) + endif() +endif() + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_PREFIX_PATH}/${CMAKE_INSTALL_LIBDIR}/cmake") + +include(AwsSanitizers) +enable_language(C) +aws_add_sanitizers(${PROJECT_NAME}) + target_link_libraries(${PROJECT_NAME} PRIVATE AWS::aws-crt-cpp) diff --git a/samples/mqtt/x509_credentials_provider_connect/CMakeLists.txt b/samples/mqtt/x509_credentials_provider_connect/CMakeLists.txt index da58e6d30..bb39b5ad0 100644 --- a/samples/mqtt/x509_credentials_provider_connect/CMakeLists.txt +++ b/samples/mqtt/x509_credentials_provider_connect/CMakeLists.txt @@ -22,4 +22,20 @@ endif () find_package(aws-crt-cpp REQUIRED) -target_link_libraries(${PROJECT_NAME} AWS::aws-crt-cpp) +if (UNIX AND NOT APPLE) + include(GNUInstallDirs) +elseif(NOT DEFINED CMAKE_INSTALL_LIBDIR) + set(CMAKE_INSTALL_LIBDIR "lib") + + if (${CMAKE_INSTALL_LIBDIR} STREQUAL "lib64") + set(FIND_LIBRARY_USE_LIB64_PATHS true) + endif() +endif() + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_PREFIX_PATH}/${CMAKE_INSTALL_LIBDIR}/cmake") + +include(AwsSanitizers) +enable_language(C) +aws_add_sanitizers(${PROJECT_NAME}) + +target_link_libraries(${PROJECT_NAME} PRIVATE AWS::aws-crt-cpp) diff --git a/samples/mqtt5/mqtt5_pubsub/CMakeLists.txt b/samples/mqtt5/mqtt5_pubsub/CMakeLists.txt index b2d6ddafa..9ef212e26 100644 --- a/samples/mqtt5/mqtt5_pubsub/CMakeLists.txt +++ b/samples/mqtt5/mqtt5_pubsub/CMakeLists.txt @@ -22,4 +22,20 @@ endif () find_package(aws-crt-cpp REQUIRED) -target_link_libraries(${PROJECT_NAME} AWS::aws-crt-cpp) +if (UNIX AND NOT APPLE) + include(GNUInstallDirs) +elseif(NOT DEFINED CMAKE_INSTALL_LIBDIR) + set(CMAKE_INSTALL_LIBDIR "lib") + + if (${CMAKE_INSTALL_LIBDIR} STREQUAL "lib64") + set(FIND_LIBRARY_USE_LIB64_PATHS true) + endif() +endif() + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_PREFIX_PATH}/${CMAKE_INSTALL_LIBDIR}/cmake") + +include(AwsSanitizers) +enable_language(C) +aws_add_sanitizers(${PROJECT_NAME}) + +target_link_libraries(${PROJECT_NAME} PRIVATE AWS::aws-crt-cpp) diff --git a/samples/mqtt5/mqtt5_shared_subscription/CMakeLists.txt b/samples/mqtt5/mqtt5_shared_subscription/CMakeLists.txt index b366a1618..c3bba6c53 100644 --- a/samples/mqtt5/mqtt5_shared_subscription/CMakeLists.txt +++ b/samples/mqtt5/mqtt5_shared_subscription/CMakeLists.txt @@ -22,4 +22,20 @@ endif () find_package(aws-crt-cpp REQUIRED) -target_link_libraries(${PROJECT_NAME} AWS::aws-crt-cpp) +if (UNIX AND NOT APPLE) + include(GNUInstallDirs) +elseif(NOT DEFINED CMAKE_INSTALL_LIBDIR) + set(CMAKE_INSTALL_LIBDIR "lib") + + if (${CMAKE_INSTALL_LIBDIR} STREQUAL "lib64") + set(FIND_LIBRARY_USE_LIB64_PATHS true) + endif() +endif() + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_PREFIX_PATH}/${CMAKE_INSTALL_LIBDIR}/cmake") + +include(AwsSanitizers) +enable_language(C) +aws_add_sanitizers(${PROJECT_NAME}) + +target_link_libraries(${PROJECT_NAME} PRIVATE AWS::aws-crt-cpp) diff --git a/samples/pub_sub/basic_pub_sub/CMakeLists.txt b/samples/pub_sub/basic_pub_sub/CMakeLists.txt index c50d4227f..71a3a85c6 100644 --- a/samples/pub_sub/basic_pub_sub/CMakeLists.txt +++ b/samples/pub_sub/basic_pub_sub/CMakeLists.txt @@ -22,4 +22,20 @@ endif () find_package(aws-crt-cpp REQUIRED) -target_link_libraries(${PROJECT_NAME} AWS::aws-crt-cpp) +if (UNIX AND NOT APPLE) + include(GNUInstallDirs) +elseif(NOT DEFINED CMAKE_INSTALL_LIBDIR) + set(CMAKE_INSTALL_LIBDIR "lib") + + if (${CMAKE_INSTALL_LIBDIR} STREQUAL "lib64") + set(FIND_LIBRARY_USE_LIB64_PATHS true) + endif() +endif() + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_PREFIX_PATH}/${CMAKE_INSTALL_LIBDIR}/cmake") + +include(AwsSanitizers) +enable_language(C) +aws_add_sanitizers(${PROJECT_NAME}) + +target_link_libraries(${PROJECT_NAME} PRIVATE AWS::aws-crt-cpp) diff --git a/samples/pub_sub/cycle_pub_sub/CMakeLists.txt b/samples/pub_sub/cycle_pub_sub/CMakeLists.txt index 9b11689e2..6d3525fef 100644 --- a/samples/pub_sub/cycle_pub_sub/CMakeLists.txt +++ b/samples/pub_sub/cycle_pub_sub/CMakeLists.txt @@ -22,4 +22,20 @@ endif () find_package(aws-crt-cpp REQUIRED) -target_link_libraries(${PROJECT_NAME} AWS::aws-crt-cpp) +if (UNIX AND NOT APPLE) + include(GNUInstallDirs) +elseif(NOT DEFINED CMAKE_INSTALL_LIBDIR) + set(CMAKE_INSTALL_LIBDIR "lib") + + if (${CMAKE_INSTALL_LIBDIR} STREQUAL "lib64") + set(FIND_LIBRARY_USE_LIB64_PATHS true) + endif() +endif() + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_PREFIX_PATH}/${CMAKE_INSTALL_LIBDIR}/cmake") + +include(AwsSanitizers) +enable_language(C) +aws_add_sanitizers(${PROJECT_NAME}) + +target_link_libraries(${PROJECT_NAME} PRIVATE AWS::aws-crt-cpp) diff --git a/samples/secure_tunneling/secure_tunnel/CMakeLists.txt b/samples/secure_tunneling/secure_tunnel/CMakeLists.txt index 489c0a4b8..0e1def3a2 100644 --- a/samples/secure_tunneling/secure_tunnel/CMakeLists.txt +++ b/samples/secure_tunneling/secure_tunnel/CMakeLists.txt @@ -26,4 +26,20 @@ find_package(IotSecureTunneling-cpp REQUIRED) install(TARGETS ${PROJECT_NAME} DESTINATION bin) -target_link_libraries(${PROJECT_NAME} AWS::aws-crt-cpp AWS::IotDeviceCommon-cpp AWS::IotSecureTunneling-cpp) +if (UNIX AND NOT APPLE) + include(GNUInstallDirs) +elseif(NOT DEFINED CMAKE_INSTALL_LIBDIR) + set(CMAKE_INSTALL_LIBDIR "lib") + + if (${CMAKE_INSTALL_LIBDIR} STREQUAL "lib64") + set(FIND_LIBRARY_USE_LIB64_PATHS true) + endif() +endif() + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_PREFIX_PATH}/${CMAKE_INSTALL_LIBDIR}/cmake") + +include(AwsSanitizers) +enable_language(C) +aws_add_sanitizers(${PROJECT_NAME}) + +target_link_libraries(${PROJECT_NAME} PRIVATE AWS::aws-crt-cpp AWS::IotDeviceCommon-cpp AWS::IotSecureTunneling-cpp) diff --git a/samples/secure_tunneling/tunnel_notification/CMakeLists.txt b/samples/secure_tunneling/tunnel_notification/CMakeLists.txt index fd25af565..e232a4560 100644 --- a/samples/secure_tunneling/tunnel_notification/CMakeLists.txt +++ b/samples/secure_tunneling/tunnel_notification/CMakeLists.txt @@ -26,4 +26,20 @@ find_package(IotSecureTunneling-cpp REQUIRED) install(TARGETS ${PROJECT_NAME} DESTINATION bin) +if (UNIX AND NOT APPLE) + include(GNUInstallDirs) +elseif(NOT DEFINED CMAKE_INSTALL_LIBDIR) + set(CMAKE_INSTALL_LIBDIR "lib") + + if (${CMAKE_INSTALL_LIBDIR} STREQUAL "lib64") + set(FIND_LIBRARY_USE_LIB64_PATHS true) + endif() +endif() + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_PREFIX_PATH}/${CMAKE_INSTALL_LIBDIR}/cmake") + +include(AwsSanitizers) +enable_language(C) +aws_add_sanitizers(${PROJECT_NAME}) + target_link_libraries(${PROJECT_NAME} PRIVATE AWS::aws-crt-cpp AWS::IotDeviceCommon-cpp AWS::IotSecureTunneling-cpp) diff --git a/samples/shadow/mqtt5_shadow_sync/CMakeLists.txt b/samples/shadow/mqtt5_shadow_sync/CMakeLists.txt index 34e17996f..a249538f3 100644 --- a/samples/shadow/mqtt5_shadow_sync/CMakeLists.txt +++ b/samples/shadow/mqtt5_shadow_sync/CMakeLists.txt @@ -25,4 +25,20 @@ find_package(IotShadow-cpp REQUIRED) install(TARGETS ${PROJECT_NAME} DESTINATION bin) +if (UNIX AND NOT APPLE) + include(GNUInstallDirs) +elseif(NOT DEFINED CMAKE_INSTALL_LIBDIR) + set(CMAKE_INSTALL_LIBDIR "lib") + + if (${CMAKE_INSTALL_LIBDIR} STREQUAL "lib64") + set(FIND_LIBRARY_USE_LIB64_PATHS true) + endif() +endif() + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_PREFIX_PATH}/${CMAKE_INSTALL_LIBDIR}/cmake") + +include(AwsSanitizers) +enable_language(C) +aws_add_sanitizers(${PROJECT_NAME}) + target_link_libraries(${PROJECT_NAME} PRIVATE AWS::aws-crt-cpp AWS::IotShadow-cpp) diff --git a/samples/shadow/shadow_sync/CMakeLists.txt b/samples/shadow/shadow_sync/CMakeLists.txt index 45c4e76eb..6abb119fd 100644 --- a/samples/shadow/shadow_sync/CMakeLists.txt +++ b/samples/shadow/shadow_sync/CMakeLists.txt @@ -25,4 +25,20 @@ find_package(IotShadow-cpp REQUIRED) install(TARGETS ${PROJECT_NAME} DESTINATION bin) +if (UNIX AND NOT APPLE) + include(GNUInstallDirs) +elseif(NOT DEFINED CMAKE_INSTALL_LIBDIR) + set(CMAKE_INSTALL_LIBDIR "lib") + + if (${CMAKE_INSTALL_LIBDIR} STREQUAL "lib64") + set(FIND_LIBRARY_USE_LIB64_PATHS true) + endif() +endif() + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_PREFIX_PATH}/${CMAKE_INSTALL_LIBDIR}/cmake") + +include(AwsSanitizers) +enable_language(C) +aws_add_sanitizers(${PROJECT_NAME}) + target_link_libraries(${PROJECT_NAME} PRIVATE AWS::aws-crt-cpp AWS::IotShadow-cpp) diff --git a/secure_tunneling/CMakeLists.txt b/secure_tunneling/CMakeLists.txt index 224b767c6..208e82226 100644 --- a/secure_tunneling/CMakeLists.txt +++ b/secure_tunneling/CMakeLists.txt @@ -44,27 +44,27 @@ if (WIN32) endif () endif() -add_library(IotSecureTunneling-cpp ${AWS_IOTSECURETUNNELING_CPP_SRC}) +add_library(${PROJECT_NAME} ${AWS_IOTSECURETUNNELING_CPP_SRC}) -set_target_properties(IotSecureTunneling-cpp PROPERTIES LINKER_LANGUAGE CXX) +set_target_properties(${PROJECT_NAME} PROPERTIES LINKER_LANGUAGE CXX) set(CMAKE_C_FLAGS_DEBUGOPT "") #set warnings if (MSVC) - target_compile_options(IotSecureTunneling-cpp PRIVATE /W4 /WX) + target_compile_options(${PROJECT_NAME} PRIVATE /W4 /WX) else () - target_compile_options(IotSecureTunneling-cpp PRIVATE -Wall -Wno-long-long -pedantic -Werror) + target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wno-long-long -pedantic -Werror) endif () -target_compile_definitions(IotSecureTunneling-cpp PRIVATE $<$:DEBUG_BUILD>) +target_compile_definitions(${PROJECT_NAME} PRIVATE $<$:DEBUG_BUILD>) if (BUILD_SHARED_LIBS) - target_compile_definitions(IotSecureTunneling-cpp PUBLIC "-DAWS_IOTSECURETUNNELING_USE_IMPORT_EXPORT") - target_compile_definitions(IotSecureTunneling-cpp PRIVATE "-DAWS_IOTSECURETUNNELING_EXPORTS") + target_compile_definitions(${PROJECT_NAME} PUBLIC "-DAWS_IOTSECURETUNNELING_USE_IMPORT_EXPORT") + target_compile_definitions(${PROJECT_NAME} PRIVATE "-DAWS_IOTSECURETUNNELING_EXPORTS") - install(TARGETS IotSecureTunneling-cpp - EXPORT IotSecureTunneling-cpp-targets + install(TARGETS ${PROJECT_NAME} + EXPORT ${PROJECT_NAME}-targets ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT Development @@ -76,20 +76,20 @@ if (BUILD_SHARED_LIBS) DESTINATION ${RUNTIME_DIRECTORY} COMPONENT Runtime) - install(TARGETS IotSecureTunneling-cpp - EXPORT IotSecureTunneling-cpp-targets + install(TARGETS ${PROJECT_NAME} + EXPORT ${PROJECT_NAME}-targets LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} NAMELINK_ONLY COMPONENT Development) else() - install(TARGETS IotSecureTunneling-cpp - EXPORT IotSecureTunneling-cpp-targets + install(TARGETS ${PROJECT_NAME} + EXPORT ${PROJECT_NAME}-targets ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT Development) endif() -target_include_directories(IotSecureTunneling-cpp PUBLIC +target_include_directories(${PROJECT_NAME} PUBLIC $ $) @@ -100,7 +100,9 @@ if (BUILD_DEPS) endif() endif() -target_link_libraries(IotSecureTunneling-cpp IotDeviceCommon-cpp) +aws_add_sanitizers(${PROJECT_NAME}) + +target_link_libraries(${PROJECT_NAME} PUBLIC IotDeviceCommon-cpp) install(FILES ${AWS_IOTSECURETUNNELING_HEADERS} DESTINATION "include/aws/iotsecuretunneling/" COMPONENT Development) @@ -118,8 +120,8 @@ if (DEFINED SIMPLE_VERSION) ) endif() -install(EXPORT "IotSecureTunneling-cpp-targets" - DESTINATION "${CMAKE_INSTALL_LIBDIR}/IotSecureTunneling-cpp/cmake/${TARGET_DIR}" +install(EXPORT "${PROJECT_NAME}-targets" + DESTINATION "${CMAKE_INSTALL_LIBDIR}/${PROJECT_NAME}/cmake/${TARGET_DIR}" NAMESPACE AWS:: COMPONENT Development) @@ -128,6 +130,5 @@ configure_file("cmake/iotsecuretunneling-cpp-config.cmake" @ONLY) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/iotsecuretunneling-cpp-config.cmake" - DESTINATION "${CMAKE_INSTALL_LIBDIR}/IotSecureTunneling-cpp/cmake/" + DESTINATION "${CMAKE_INSTALL_LIBDIR}/${PROJECT_NAME}/cmake/" COMPONENT Development) - diff --git a/secure_tunneling/tests/CMakeLists.txt b/secure_tunneling/tests/CMakeLists.txt index c4ddfecc6..c29124e83 100644 --- a/secure_tunneling/tests/CMakeLists.txt +++ b/secure_tunneling/tests/CMakeLists.txt @@ -26,4 +26,20 @@ find_package(IotSecureTunneling-cpp REQUIRED) install(TARGETS ${PROJECT_NAME} DESTINATION bin) -target_link_libraries(${PROJECT_NAME} AWS::aws-crt-cpp AWS::IotDeviceCommon-cpp AWS::IotSecureTunneling-cpp) +if (UNIX AND NOT APPLE) + include(GNUInstallDirs) +elseif(NOT DEFINED CMAKE_INSTALL_LIBDIR) + set(CMAKE_INSTALL_LIBDIR "lib") + + if (${CMAKE_INSTALL_LIBDIR} STREQUAL "lib64") + set(FIND_LIBRARY_USE_LIB64_PATHS true) + endif() +endif() + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_PREFIX_PATH}/${CMAKE_INSTALL_LIBDIR}/cmake") + +include(AwsSanitizers) +enable_language(C) +aws_add_sanitizers(${PROJECT_NAME}) + +target_link_libraries(${PROJECT_NAME} PRIVATE AWS::aws-crt-cpp AWS::IotDeviceCommon-cpp AWS::IotSecureTunneling-cpp) diff --git a/servicetests/tests/JobsExecution/CMakeLists.txt b/servicetests/tests/JobsExecution/CMakeLists.txt index 5efff50e7..64ffbea46 100644 --- a/servicetests/tests/JobsExecution/CMakeLists.txt +++ b/servicetests/tests/JobsExecution/CMakeLists.txt @@ -23,6 +23,8 @@ endif () find_package(aws-crt-cpp REQUIRED) find_package(IotJobs-cpp REQUIRED) +install(TARGETS ${PROJECT_NAME} DESTINATION bin) + if (UNIX AND NOT APPLE) include(GNUInstallDirs) elseif(NOT DEFINED CMAKE_INSTALL_LIBDIR) @@ -35,8 +37,6 @@ endif() list(APPEND CMAKE_MODULE_PATH "${CMAKE_PREFIX_PATH}/${CMAKE_INSTALL_LIBDIR}/cmake") -install(TARGETS ${PROJECT_NAME} DESTINATION bin) - include(AwsSanitizers) enable_language(C) aws_add_sanitizers(${PROJECT_NAME}) diff --git a/shadow/CMakeLists.txt b/shadow/CMakeLists.txt index 771a462a8..830291777 100644 --- a/shadow/CMakeLists.txt +++ b/shadow/CMakeLists.txt @@ -46,27 +46,27 @@ if (WIN32) endif () endif() -add_library(IotShadow-cpp ${AWS_IOTSHADOW_CPP_SRC}) +add_library(${PROJECT_NAME} ${AWS_IOTSHADOW_CPP_SRC}) -set_target_properties(IotShadow-cpp PROPERTIES LINKER_LANGUAGE CXX) +set_target_properties(${PROJECT_NAME} PROPERTIES LINKER_LANGUAGE CXX) set(CMAKE_C_FLAGS_DEBUGOPT "") #set warnings if (MSVC) - target_compile_options(IotShadow-cpp PRIVATE /W4 /WX) + target_compile_options(${PROJECT_NAME} PRIVATE /W4 /WX) else () - target_compile_options(IotShadow-cpp PRIVATE -Wall -Wno-long-long -pedantic -Werror) + target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wno-long-long -pedantic -Werror) endif () -target_compile_definitions(IotShadow-cpp PRIVATE $<$:DEBUG_BUILD>) +target_compile_definitions(${PROJECT_NAME} PRIVATE $<$:DEBUG_BUILD>) if (BUILD_SHARED_LIBS) - target_compile_definitions(IotShadow-cpp PUBLIC "-DAWS_IOTSHADOW_USE_IMPORT_EXPORT") - target_compile_definitions(IotShadow-cpp PRIVATE "-DAWS_IOTSHADOW_EXPORTS") + target_compile_definitions(${PROJECT_NAME} PUBLIC "-DAWS_IOTSHADOW_USE_IMPORT_EXPORT") + target_compile_definitions(${PROJECT_NAME} PRIVATE "-DAWS_IOTSHADOW_EXPORTS") - install(TARGETS IotShadow-cpp - EXPORT IotShadow-cpp-targets + install(TARGETS ${PROJECT_NAME} + EXPORT ${PROJECT_NAME}-targets ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT Development @@ -78,20 +78,20 @@ if (BUILD_SHARED_LIBS) DESTINATION ${RUNTIME_DIRECTORY} COMPONENT Runtime) - install(TARGETS IotShadow-cpp - EXPORT IotShadow-cpp-targets + install(TARGETS ${PROJECT_NAME} + EXPORT ${PROJECT_NAME}-targets LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} NAMELINK_ONLY COMPONENT Development) else() - install(TARGETS IotShadow-cpp - EXPORT IotShadow-cpp-targets + install(TARGETS ${PROJECT_NAME} + EXPORT ${PROJECT_NAME}-targets ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT Development) endif() -target_include_directories(IotShadow-cpp PUBLIC +target_include_directories(${PROJECT_NAME} PUBLIC $ $) @@ -101,7 +101,9 @@ if (BUILD_DEPS) endif() endif() -target_link_libraries(IotShadow-cpp ${DEP_AWS_LIBS}) +aws_add_sanitizers(${PROJECT_NAME}) + +target_link_libraries(${PROJECT_NAME} PUBLIC ${DEP_AWS_LIBS}) install(FILES ${AWS_IOTSHADOW_HEADERS} DESTINATION "include/aws/iotshadow/" COMPONENT Development) @@ -119,8 +121,8 @@ if (DEFINED SIMPLE_VERSION) ) endif() -install(EXPORT "IotShadow-cpp-targets" - DESTINATION "${CMAKE_INSTALL_LIBDIR}/IotShadow-cpp/cmake/${TARGET_DIR}" +install(EXPORT "${PROJECT_NAME}-targets" + DESTINATION "${CMAKE_INSTALL_LIBDIR}/${PROJECT_NAME}/cmake/${TARGET_DIR}" NAMESPACE AWS:: COMPONENT Development) @@ -129,5 +131,5 @@ configure_file("cmake/iotshadow-cpp-config.cmake" @ONLY) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/iotshadow-cpp-config.cmake" - DESTINATION "${CMAKE_INSTALL_LIBDIR}/IotShadow-cpp/cmake/" + DESTINATION "${CMAKE_INSTALL_LIBDIR}/${PROJECT_NAME}/cmake/" COMPONENT Development) From 8f421eca0bd9619a50e0fbb05f0dfb194c0277f0 Mon Sep 17 00:00:00 2001 From: Igor Abdrakhimov Date: Mon, 1 Apr 2024 17:00:12 -0700 Subject: [PATCH 17/47] Fix typo --- discovery/CMakeLists.txt | 2 +- eventstream_rpc/CMakeLists.txt | 2 +- eventstream_rpc/tests/CMakeLists.txt | 2 +- greengrass_ipc/CMakeLists.txt | 2 +- identity/CMakeLists.txt | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/discovery/CMakeLists.txt b/discovery/CMakeLists.txt index 84f48ca47..9e409d1c4 100644 --- a/discovery/CMakeLists.txt +++ b/discovery/CMakeLists.txt @@ -99,7 +99,7 @@ if (BUILD_DEPS) endif() endif() -aws_add_sanitizer(${PROJECT_NAME}) +aws_add_sanitizers(${PROJECT_NAME}) target_link_libraries(Discovery-cpp ${DEP_AWS_LIBS}) install(FILES ${AWS_DISCOVERY_HEADERS} DESTINATION "include/aws/discovery/" COMPONENT Development) diff --git a/eventstream_rpc/CMakeLists.txt b/eventstream_rpc/CMakeLists.txt index 1d6e0c397..2a890005c 100644 --- a/eventstream_rpc/CMakeLists.txt +++ b/eventstream_rpc/CMakeLists.txt @@ -97,7 +97,7 @@ if (NOT IS_SUBDIRECTORY_INCLUDE) aws_use_package(aws-crt-cpp) endif() -aws_add_sanitizer(${PROJECT_NAME}) +aws_add_sanitizers(${PROJECT_NAME}) target_link_libraries(EventstreamRpc-cpp PUBLIC ${DEP_AWS_LIBS}) install(FILES ${AWS_EVENTSTREAMRPC_HEADERS} DESTINATION "include/aws/eventstreamrpc/" COMPONENT Development) diff --git a/eventstream_rpc/tests/CMakeLists.txt b/eventstream_rpc/tests/CMakeLists.txt index 6d7d99d3d..34f726082 100644 --- a/eventstream_rpc/tests/CMakeLists.txt +++ b/eventstream_rpc/tests/CMakeLists.txt @@ -47,7 +47,7 @@ add_test_case(OperateWhileDisconnected) #add_test_case(EchoOperation) #add_test_case(StressTestClient) generate_cpp_test_driver(${TEST_BINARY_NAME}) -aws_add_sanitizer(${TEST_BINARY_NAME}) +aws_add_sanitizers(${TEST_BINARY_NAME}) target_include_directories(${TEST_BINARY_NAME} PUBLIC $ $) diff --git a/greengrass_ipc/CMakeLists.txt b/greengrass_ipc/CMakeLists.txt index a2fc34301..4950105cb 100644 --- a/greengrass_ipc/CMakeLists.txt +++ b/greengrass_ipc/CMakeLists.txt @@ -105,7 +105,7 @@ if (NOT IS_SUBDIRECTORY_INCLUDE) aws_use_package(aws-crt-cpp) endif() -aws_add_sanitizer(${PROJECT_NAME}) +aws_add_sanitizers(${PROJECT_NAME}) target_link_libraries(GreengrassIpc-cpp PUBLIC ${DEP_AWS_LIBS}) install(FILES ${AWS_GREENGRASSIPC_HEADERS} DESTINATION "include/aws/greengrass/" COMPONENT Development) diff --git a/identity/CMakeLists.txt b/identity/CMakeLists.txt index d0eb1173f..60ead73e2 100644 --- a/identity/CMakeLists.txt +++ b/identity/CMakeLists.txt @@ -91,7 +91,7 @@ else() COMPONENT Development) endif() -aws_add_sanitizer(${PROJECT_NAME}) +aws_add_sanitizers(${PROJECT_NAME}) target_include_directories(IotIdentity-cpp PUBLIC $ $) From aa3f06a3b63dcde374bb01c5a50a6f1d66759ba7 Mon Sep 17 00:00:00 2001 From: Igor Abdrakhimov Date: Mon, 1 Apr 2024 17:03:25 -0700 Subject: [PATCH 18/47] Fun with gg --- greengrass_ipc/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/greengrass_ipc/CMakeLists.txt b/greengrass_ipc/CMakeLists.txt index 4950105cb..3edc398cd 100644 --- a/greengrass_ipc/CMakeLists.txt +++ b/greengrass_ipc/CMakeLists.txt @@ -45,7 +45,7 @@ if (WIN32) endif() add_library(GreengrassIpc-cpp ${AWS_GREENGRASSIPC_CPP_SRC}) -target_link_libraries(GreengrassIpc-cpp EventstreamRpc-cpp) +target_link_libraries(GreengrassIpc-cpp PUBLIC EventstreamRpc-cpp) set_target_properties(GreengrassIpc-cpp PROPERTIES LINKER_LANGUAGE CXX) From 219304fc87b412a28875ca360517e1e3b582ba7a Mon Sep 17 00:00:00 2001 From: Igor Abdrakhimov Date: Mon, 1 Apr 2024 17:06:43 -0700 Subject: [PATCH 19/47] Fix target_link_library --- discovery/CMakeLists.txt | 2 +- identity/CMakeLists.txt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/discovery/CMakeLists.txt b/discovery/CMakeLists.txt index 9e409d1c4..4c5f4d9d0 100644 --- a/discovery/CMakeLists.txt +++ b/discovery/CMakeLists.txt @@ -100,7 +100,7 @@ if (BUILD_DEPS) endif() aws_add_sanitizers(${PROJECT_NAME}) -target_link_libraries(Discovery-cpp ${DEP_AWS_LIBS}) +target_link_libraries(Discovery-cpp PUBLIC ${DEP_AWS_LIBS}) install(FILES ${AWS_DISCOVERY_HEADERS} DESTINATION "include/aws/discovery/" COMPONENT Development) diff --git a/identity/CMakeLists.txt b/identity/CMakeLists.txt index 60ead73e2..e3795145d 100644 --- a/identity/CMakeLists.txt +++ b/identity/CMakeLists.txt @@ -91,7 +91,6 @@ else() COMPONENT Development) endif() -aws_add_sanitizers(${PROJECT_NAME}) target_include_directories(IotIdentity-cpp PUBLIC $ $) @@ -102,7 +101,8 @@ if (BUILD_DEPS) endif() endif() -target_link_libraries(IotIdentity-cpp ${DEP_AWS_LIBS}) +aws_add_sanitizers(${PROJECT_NAME}) +target_link_libraries(IotIdentity-cpp PUBLIC ${DEP_AWS_LIBS}) install(FILES ${AWS_IOTIDENTITY_HEADERS} DESTINATION "include/aws/iotidentity/" COMPONENT Development) From 64201321e884567451003c9bd6eb971eee44e752 Mon Sep 17 00:00:00 2001 From: Igor Abdrakhimov Date: Mon, 1 Apr 2024 17:17:49 -0700 Subject: [PATCH 20/47] Install softhsm --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 10cc437ce..34ca1a6a9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -705,6 +705,8 @@ jobs: run: | python3 -m pip install boto3 sudo apt-get update -y + sudo apt-get install softhsm -y + softhsm2-util --version - name: configure AWS credentials (Fleet provisioning) if: always() uses: aws-actions/configure-aws-credentials@v2 From c6f2980b9a448d7d78c4d3b272ad9ffa7b9f8590 Mon Sep 17 00:00:00 2001 From: Igor Abdrakhimov Date: Mon, 1 Apr 2024 17:17:59 -0700 Subject: [PATCH 21/47] Remove test leak --- jobs/source/IotJobsClient.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/jobs/source/IotJobsClient.cpp b/jobs/source/IotJobsClient.cpp index 4f1df2a1b..c0cb1cf0c 100644 --- a/jobs/source/IotJobsClient.cpp +++ b/jobs/source/IotJobsClient.cpp @@ -31,9 +31,6 @@ namespace Aws IotJobsClient::IotJobsClient(const std::shared_ptr &connection) : m_connection(connection) { - // TODO Remove. - int *leak = new int; - (void)leak; } IotJobsClient::IotJobsClient(const std::shared_ptr &mqtt5Client) From 1ffefd572c2ad221b98e9f4e01f3dce91f00c853 Mon Sep 17 00:00:00 2001 From: Igor Abdrakhimov Date: Tue, 30 Apr 2024 11:45:51 -0700 Subject: [PATCH 22/47] Remove extra params in running samples --- utils/run_sample_ci.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/run_sample_ci.py b/utils/run_sample_ci.py index 1e87c537e..1be61fd91 100644 --- a/utils/run_sample_ci.py +++ b/utils/run_sample_ci.py @@ -290,7 +290,7 @@ def launch_sample(): elif (config_json['language'] == "CPP"): try: sample_return = subprocess.run( - args=config_json_arguments_list, executable=config_json['sample_file'], timeout=600, stderr=subprocess.STDOUT, stdout=subprocess.PIPE) + args=config_json_arguments_list, executable=config_json['sample_file'], timeout=600) exit_code = sample_return.returncode except subprocess.TimeoutExpired as timeOut: sys.exit(-1) From 5128e10945a4d6d4a3f3bc79f68ff4ac75a4f5e1 Mon Sep 17 00:00:00 2001 From: Igor Abdrakhimov Date: Tue, 30 Apr 2024 14:57:32 -0700 Subject: [PATCH 23/47] Capture and print --- utils/run_sample_ci.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/utils/run_sample_ci.py b/utils/run_sample_ci.py index 1be61fd91..0d0669e80 100644 --- a/utils/run_sample_ci.py +++ b/utils/run_sample_ci.py @@ -290,7 +290,8 @@ def launch_sample(): elif (config_json['language'] == "CPP"): try: sample_return = subprocess.run( - args=config_json_arguments_list, executable=config_json['sample_file'], timeout=600) + args=config_json_arguments_list, executable=config_json['sample_file'], timeout=600, capture_output=True, text=True) + print(sample_return.stdout) exit_code = sample_return.returncode except subprocess.TimeoutExpired as timeOut: sys.exit(-1) From 91d09b7549c1b8efebfe523dae242504e98adc1f Mon Sep 17 00:00:00 2001 From: Igor Abdrakhimov Date: Tue, 30 Apr 2024 15:08:34 -0700 Subject: [PATCH 24/47] fixup --- utils/run_sample_ci.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/utils/run_sample_ci.py b/utils/run_sample_ci.py index 0d0669e80..fbfa034ef 100644 --- a/utils/run_sample_ci.py +++ b/utils/run_sample_ci.py @@ -291,7 +291,10 @@ def launch_sample(): try: sample_return = subprocess.run( args=config_json_arguments_list, executable=config_json['sample_file'], timeout=600, capture_output=True, text=True) + print("stdout:") print(sample_return.stdout) + print("stderr:") + print(sample_return.stderr) exit_code = sample_return.returncode except subprocess.TimeoutExpired as timeOut: sys.exit(-1) From 72b2582b90dce4dcf2dfc55f78aa124dd4812f74 Mon Sep 17 00:00:00 2001 From: Igor Abdrakhimov Date: Wed, 1 May 2024 13:55:37 -0700 Subject: [PATCH 25/47] Fix memory and data race issues --- servicetests/tests/JobsExecution/main.cpp | 218 +++++++++++----------- 1 file changed, 113 insertions(+), 105 deletions(-) diff --git a/servicetests/tests/JobsExecution/main.cpp b/servicetests/tests/JobsExecution/main.cpp index 667f8e092..030af92cb 100644 --- a/servicetests/tests/JobsExecution/main.cpp +++ b/servicetests/tests/JobsExecution/main.cpp @@ -38,10 +38,114 @@ using namespace Aws::Crt; using namespace Aws::Iotjobs; -void getAvailableJobs( - Aws::Crt::String thingName, - IotJobsClient &jobsClient, - std::vector &availableJobs); +class AvailableJobsHandler +{ + public: + void receiveAvailableJobs(const Aws::Crt::String &thingName, IotJobsClient &jobsClient) + { + GetPendingJobExecutionsSubscriptionRequest subscriptionRequest; + subscriptionRequest.ThingName = thingName; + + auto handler = [this](Aws::Iotjobs::GetPendingJobExecutionsResponse *response, int ioErr) { + fprintf(stderr, "running the jobs handler\n"); + if (ioErr) + { + fprintf(stderr, "Error %d occurred\n", ioErr); + exit(1); + } + if (response) + { + if (response->InProgressJobs.has_value()) + { + for (const JobExecutionSummary &job : response->InProgressJobs.value()) + { + std::lock_guard lock(m_jobsMutex); + m_availableJobs.push_back(job.JobId.value()); + fprintf(stderr, "In Progress jobs %s\n", job.JobId->c_str()); + } + } + else + { + fprintf(stderr, "In Progress jobs: empty\n"); + } + if (response->QueuedJobs.has_value()) + { + for (const JobExecutionSummary &job : response->QueuedJobs.value()) + { + std::lock_guard lock(m_jobsMutex); + m_availableJobs.push_back(job.JobId.value()); + fprintf(stderr, "Queued jobs %s\n", job.JobId->c_str()); + } + } + else + { + fprintf(stderr, "Queued jobs: empty\n"); + } + } + m_getResponse.set_value(); + }; + + auto err_handler = [](Aws::Iotjobs::RejectedError *rejectedError, int ioErr) { + if (ioErr) + { + fprintf(stderr, "Error %d occurred\n", ioErr); + exit(1); + } + if (rejectedError) + { + fprintf( + stderr, + "Service Error %d occurred. Message %s\n", + (int)rejectedError->Code.value(), + rejectedError->Message->c_str()); + } + fprintf(stderr, "Error handler\n"); + exit(-1); + }; + + auto publishHandler = [this](int ioErr) { + if (ioErr) + { + fprintf(stderr, "Error %d occurred\n", ioErr); + exit(1); + } + m_publishDescribeJobExeCompletedPromise.set_value(); + }; + + jobsClient.SubscribeToGetPendingJobExecutionsAccepted( + subscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, handler, publishHandler); + m_publishDescribeJobExeCompletedPromise.get_future().wait(); + + m_publishDescribeJobExeCompletedPromise = std::promise(); + jobsClient.SubscribeToGetPendingJobExecutionsRejected( + subscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, err_handler, publishHandler); + m_publishDescribeJobExeCompletedPromise.get_future().wait(); + + m_publishDescribeJobExeCompletedPromise = std::promise(); + GetPendingJobExecutionsRequest publishRequest; + publishRequest.ThingName = thingName; + jobsClient.PublishGetPendingJobExecutions(publishRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, publishHandler); + m_publishDescribeJobExeCompletedPromise.get_future().wait(); + + if (m_getResponse.get_future().wait_for(std::chrono::seconds(10)) == std::future_status::timeout) + { + fprintf(stderr, "get available jobs error timedout\n"); + exit(-1); + } + } + + std::vector getAvailableJobs() const + { + std::lock_guard lock(m_jobsMutex); + return m_availableJobs; + } + + private: + std::vector m_availableJobs; + mutable std::mutex m_jobsMutex; + std::promise m_getResponse; + std::promise m_publishDescribeJobExeCompletedPromise; +}; std::shared_ptr build_mqtt3_client( Utils::cmdData &cmdData, @@ -178,7 +282,7 @@ std::shared_ptr build_mqtt5_client( int main(int argc, char *argv[]) { - fprintf(stdout, "Starting the jobs execution programm\n"); + fprintf(stdout, "Starting the jobs execution program\n"); /************************ Setup ****************************/ // Do the global initialization for the API @@ -215,10 +319,11 @@ int main(int argc, char *argv[]) exit(-1); } /************************ Run the sample ****************************/ + AvailableJobsHandler handler; if (connectionCompletedPromise.get_future().get()) { - std::vector availableJobs; - getAvailableJobs(cmdData.input_thingName, *jobsClient, availableJobs); + handler.receiveAvailableJobs(cmdData.input_thingName, *jobsClient); + auto availableJobs = handler.getAvailableJobs(); for (auto jobid : availableJobs) { DescribeJobExecutionSubscriptionRequest describeJobExecutionSubscriptionRequest; @@ -298,7 +403,7 @@ int main(int argc, char *argv[]) }; jobsClient->PublishDescribeJobExecution( - std::move(describeJobExecutionRequest), AWS_MQTT_QOS_AT_LEAST_ONCE, publishHandler); + describeJobExecutionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, publishHandler); publishDescribeJobExeCompletedPromise.get_future().wait(); Aws::Crt::String currentJobId; @@ -466,100 +571,3 @@ int main(int argc, char *argv[]) } return 0; } - -void getAvailableJobs( - Aws::Crt::String thingName, - IotJobsClient &jobsClient, - std::vector &availableJobs) -{ - std::promise getResponse; - std::promise publishDescribeJobExeCompletedPromise; - - GetPendingJobExecutionsSubscriptionRequest subscriptionRequest; - subscriptionRequest.ThingName = thingName; - - auto handler = [&](Aws::Iotjobs::GetPendingJobExecutionsResponse *response, int ioErr) { - fprintf(stderr, "running the jobs handler\n"); - if (ioErr) - { - fprintf(stderr, "Error %d occurred\n", ioErr); - exit(1); - } - if (response) - { - if (response->InProgressJobs.has_value()) - { - for (JobExecutionSummary job : response->InProgressJobs.value()) - { - availableJobs.push_back(job.JobId.value()); - fprintf(stderr, "In Progress jobs %s\n", job.JobId->c_str()); - } - } - else - { - fprintf(stderr, "In Progress jobs: empty\n"); - } - if (response->QueuedJobs.has_value()) - { - for (JobExecutionSummary job : response->QueuedJobs.value()) - { - availableJobs.push_back(job.JobId.value()); - fprintf(stderr, "Queued jobs %s\n", job.JobId->c_str()); - } - } - else - { - fprintf(stderr, "Queued jobs: empty\n"); - } - } - getResponse.set_value(); - }; - - auto err_handler = [&](Aws::Iotjobs::RejectedError *rejectedError, int ioErr) { - if (ioErr) - { - fprintf(stderr, "Error %d occurred\n", ioErr); - exit(1); - } - if (rejectedError) - { - fprintf( - stderr, - "Service Error %d occurred. Message %s\n", - (int)rejectedError->Code.value(), - rejectedError->Message->c_str()); - } - fprintf(stderr, "Error handler\n"); - exit(-1); - }; - - auto publishHandler = [&](int ioErr) { - if (ioErr) - { - fprintf(stderr, "Error %d occurred\n", ioErr); - exit(1); - } - publishDescribeJobExeCompletedPromise.set_value(); - }; - - jobsClient.SubscribeToGetPendingJobExecutionsAccepted( - subscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, handler, publishHandler); - publishDescribeJobExeCompletedPromise.get_future().wait(); - - publishDescribeJobExeCompletedPromise = std::promise(); - jobsClient.SubscribeToGetPendingJobExecutionsRejected( - subscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, err_handler, publishHandler); - publishDescribeJobExeCompletedPromise.get_future().wait(); - - publishDescribeJobExeCompletedPromise = std::promise(); - GetPendingJobExecutionsRequest publishRequest; - publishRequest.ThingName = thingName; - jobsClient.PublishGetPendingJobExecutions(publishRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, publishHandler); - publishDescribeJobExeCompletedPromise.get_future().wait(); - - if (getResponse.get_future().wait_for(std::chrono::seconds(10)) == std::future_status::timeout) - { - fprintf(stderr, "get available jobs error timedout\n"); - exit(-1); - } -} From d4468baf969513010f4a05515b7abdf5fd328ea5 Mon Sep 17 00:00:00 2001 From: Igor Abdrakhimov Date: Wed, 1 May 2024 16:25:28 -0700 Subject: [PATCH 26/47] Refactor jobs service test --- samples/jobs/mqtt5_job_execution/main.cpp | 1 + .../tests/JobsExecution/CMakeLists.txt | 1 + .../tests/JobsExecution/JobsExecution.cpp | 379 ++++++++++++++++++ .../tests/JobsExecution/JobsExecution.h | 39 ++ servicetests/tests/JobsExecution/main.cpp | 349 +--------------- 5 files changed, 430 insertions(+), 339 deletions(-) create mode 100644 servicetests/tests/JobsExecution/JobsExecution.cpp create mode 100644 servicetests/tests/JobsExecution/JobsExecution.h diff --git a/samples/jobs/mqtt5_job_execution/main.cpp b/samples/jobs/mqtt5_job_execution/main.cpp index 65e91d520..7c0cb5bdb 100644 --- a/samples/jobs/mqtt5_job_execution/main.cpp +++ b/samples/jobs/mqtt5_job_execution/main.cpp @@ -209,6 +209,7 @@ int main(int argc, char *argv[]) } else { + fprintf(stderr, "No pending jobs, exiting\n"); exit(-1); } } diff --git a/servicetests/tests/JobsExecution/CMakeLists.txt b/servicetests/tests/JobsExecution/CMakeLists.txt index 64ffbea46..834189e41 100644 --- a/servicetests/tests/JobsExecution/CMakeLists.txt +++ b/servicetests/tests/JobsExecution/CMakeLists.txt @@ -4,6 +4,7 @@ project(job-execution CXX) file(GLOB SRC_FILES "*.cpp" + "*.h" "../../../samples/utils/CommandLineUtils.cpp" "../../../samples/utils/CommandLineUtils.h" ) diff --git a/servicetests/tests/JobsExecution/JobsExecution.cpp b/servicetests/tests/JobsExecution/JobsExecution.cpp new file mode 100644 index 000000000..7921b3ae7 --- /dev/null +++ b/servicetests/tests/JobsExecution/JobsExecution.cpp @@ -0,0 +1,379 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include "JobsExecution.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace Aws::Crt; +using namespace Aws::Iotjobs; + +JobsExecution::JobsExecution(std::shared_ptr jobsClient, Aws::Crt::String thingName) + : m_jobsClient(std::move(jobsClient)), m_thingName(std::move(thingName)), m_currentExecutionNumber(), m_currentVersionNumber() +{ +} + +Aws::Crt::Vector JobsExecution::getAvailableJobs() +{ + GetPendingJobExecutionsSubscriptionRequest subscriptionRequest; + subscriptionRequest.ThingName = m_thingName; + + auto handler = [this](Aws::Iotjobs::GetPendingJobExecutionsResponse *response, int ioErr) { + fprintf(stderr, "running the jobs handler\n"); + if (ioErr) + { + fprintf(stderr, "Error %d occurred\n", ioErr); + exit(1); + } + if (response) + { + if (response->InProgressJobs.has_value()) + { + for (const JobExecutionSummary &job : response->InProgressJobs.value()) + { + std::lock_guard lock(m_jobsMutex); + m_availableJobs.push_back(job.JobId.value()); + fprintf(stderr, "In Progress jobs %s\n", job.JobId->c_str()); + } + } + else + { + fprintf(stderr, "In Progress jobs: empty\n"); + } + if (response->QueuedJobs.has_value()) + { + for (const JobExecutionSummary &job : response->QueuedJobs.value()) + { + std::lock_guard lock(m_jobsMutex); + m_availableJobs.push_back(job.JobId.value()); + fprintf(stderr, "Queued jobs %s\n", job.JobId->c_str()); + } + } + else + { + fprintf(stderr, "Queued jobs: empty\n"); + } + } + m_getResponse.set_value(); + }; + + auto err_handler = [](Aws::Iotjobs::RejectedError *rejectedError, int ioErr) { + if (ioErr) + { + fprintf(stderr, "Error %d occurred\n", ioErr); + exit(1); + } + if (rejectedError) + { + fprintf( + stderr, + "Service Error %d occurred. Message %s\n", + (int)rejectedError->Code.value(), + rejectedError->Message->c_str()); + } + fprintf(stderr, "Error handler\n"); + exit(-1); + }; + + std::promise publishDescribeJobExeCompletedPromise; + + auto publishHandler = [&publishDescribeJobExeCompletedPromise](int ioErr) { + if (ioErr) + { + fprintf(stderr, "Error %d occurred\n", ioErr); + exit(1); + } + publishDescribeJobExeCompletedPromise.set_value(); + }; + + m_jobsClient->SubscribeToGetPendingJobExecutionsAccepted( + subscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, handler, publishHandler); + publishDescribeJobExeCompletedPromise.get_future().wait(); + + publishDescribeJobExeCompletedPromise = std::promise(); + m_jobsClient->SubscribeToGetPendingJobExecutionsRejected( + subscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, err_handler, publishHandler); + publishDescribeJobExeCompletedPromise.get_future().wait(); + + publishDescribeJobExeCompletedPromise = std::promise(); + GetPendingJobExecutionsRequest publishRequest; + publishRequest.ThingName = m_thingName; + m_jobsClient->PublishGetPendingJobExecutions(publishRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, publishHandler); + publishDescribeJobExeCompletedPromise.get_future().wait(); + + if (m_getResponse.get_future().wait_for(std::chrono::seconds(10)) == std::future_status::timeout) + { + fprintf(stderr, "get available jobs error timedout\n"); + exit(-1); + } + + std::lock_guard lock(m_jobsMutex); + return m_availableJobs; +} + +void JobsExecution::describeJob(const String &jobId) { + DescribeJobExecutionSubscriptionRequest describeJobExecutionSubscriptionRequest; + describeJobExecutionSubscriptionRequest.ThingName = m_thingName; + describeJobExecutionSubscriptionRequest.JobId = jobId; + + /** + * This isn't absolutely necessary but since we're doing a publish almost immediately afterwards, + * to be cautious make sure the subscribe has finished before doing the publish. + */ + std::promise subAckedPromise; + auto subAckHandler = [&subAckedPromise](int) { + // if error code returns it will be recorded by the other callback + subAckedPromise.set_value(); + }; + auto subscriptionHandler = [&](DescribeJobExecutionResponse *response, int ioErr) { + if (ioErr) + { + fprintf(stderr, "Error %d occurred\n", ioErr); + return; + } + if (response) + { + fprintf(stdout, "Received Job:\n"); + fprintf(stdout, "Job Id: %s\n", response->Execution->JobId->c_str()); + fprintf(stdout, "ClientToken: %s\n", response->ClientToken->c_str()); + fprintf(stdout, "Execution Status: %s\n", JobStatusMarshaller::ToString(*response->Execution->Status)); + } + }; + + m_jobsClient->SubscribeToDescribeJobExecutionAccepted( + describeJobExecutionSubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, subscriptionHandler, subAckHandler); + subAckedPromise.get_future().wait(); + + subAckedPromise = std::promise(); + + auto failureHandler = [](RejectedError *rejectedError, int ioErr) { + if (ioErr) + { + fprintf(stderr, "Error %d occurred\n", ioErr); + return; + } + if (rejectedError) + { + fprintf( + stderr, + "Service Error %d occurred. Message %s\n", + (int)rejectedError->Code.value(), + rejectedError->Message->c_str()); + return; + } + }; + + m_jobsClient->SubscribeToDescribeJobExecutionRejected( + describeJobExecutionSubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, failureHandler, subAckHandler); + subAckedPromise.get_future().wait(); + + DescribeJobExecutionRequest describeJobExecutionRequest; + describeJobExecutionRequest.ThingName = m_thingName; + describeJobExecutionRequest.JobId = jobId; + describeJobExecutionRequest.IncludeJobDocument = true; + Aws::Crt::UUID uuid; + describeJobExecutionRequest.ClientToken = uuid.ToString(); + std::promise publishDescribeJobExeCompletedPromise; + + auto publishHandler = [&publishDescribeJobExeCompletedPromise](int ioErr) { + if (ioErr) + { + fprintf(stderr, "Error %d occurred\n", ioErr); + exit(1); + } + publishDescribeJobExeCompletedPromise.set_value(); + }; + + m_jobsClient->PublishDescribeJobExecution(describeJobExecutionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, publishHandler); + publishDescribeJobExeCompletedPromise.get_future().wait(); +} + +void JobsExecution::startNextPendingJob() { + std::promise subAckedPromise; + auto subAckHandler = [&subAckedPromise](int) { + // if error code returns it will be recorded by the other callback + subAckedPromise.set_value(); + }; + + auto failureHandler = [](RejectedError *rejectedError, int ioErr) { + if (ioErr) + { + fprintf(stderr, "Error %d occurred\n", ioErr); + return; + } + if (rejectedError) + { + fprintf( + stderr, + "Service Error %d occurred. Message %s\n", + (int)rejectedError->Code.value(), + rejectedError->Message->c_str()); + return; + } + }; + + Aws::Crt::String jobId; + + auto OnSubscribeToStartNextPendingJobExecutionAcceptedResponse = [this](StartNextJobExecutionResponse *response, + int ioErr) { + if (ioErr) + { + fprintf(stderr, "Error %d occurred\n", ioErr); + exit(1); + } + if (response && response->Execution.has_value()) + { + fprintf(stdout, "Start Job %s\n", response->Execution.value().JobId.value().c_str()); + // Make tsan happy. + std::lock_guard lock(m_jobsMutex); + m_currentJobId = response->Execution->JobId.value(); + m_currentExecutionNumber = response->Execution->ExecutionNumber.value(); + m_currentVersionNumber = response->Execution->VersionNumber.value(); + } + else + { + fprintf(stdout, "Could not get Job Id, exiting\n"); + exit(-1); + } + + m_pendingExecutionPromise.set_value(); + }; + + StartNextPendingJobExecutionSubscriptionRequest subscriptionRequest; + subscriptionRequest.ThingName = m_thingName; + subAckedPromise = std::promise(); + m_jobsClient->SubscribeToStartNextPendingJobExecutionAccepted( + subscriptionRequest, + AWS_MQTT_QOS_AT_LEAST_ONCE, + OnSubscribeToStartNextPendingJobExecutionAcceptedResponse, + subAckHandler); + + subAckedPromise.get_future().wait(); + + subAckedPromise = std::promise(); + m_jobsClient->SubscribeToStartNextPendingJobExecutionRejected( + subscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, failureHandler, subAckHandler); + + subAckedPromise.get_future().wait(); + + StartNextPendingJobExecutionRequest publishRequest; + publishRequest.ThingName = m_thingName; + publishRequest.StepTimeoutInMinutes = 15L; + + std::promise publishDescribeJobExeCompletedPromise; + + auto publishHandler = [&publishDescribeJobExeCompletedPromise](int ioErr) { + if (ioErr) + { + fprintf(stderr, "Error %d occurred\n", ioErr); + exit(1); + } + publishDescribeJobExeCompletedPromise.set_value(); + }; + m_jobsClient->PublishStartNextPendingJobExecution(publishRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, publishHandler); + + m_pendingExecutionPromise.get_future().wait(); +} + +void JobsExecution::updateCurrentJobStatus(Aws::Iotjobs::JobStatus jobStatus) +{ + Aws::Crt::String jobId; + int64_t currentExecutionNumber; + int32_t currentVersionNumber; + + { + // Make tsan happy. + std::lock_guard lock(m_jobsMutex); + jobId = m_currentJobId; + currentExecutionNumber = m_currentExecutionNumber; + currentVersionNumber = m_currentVersionNumber; + } + + std::promise subAckedPromise; + auto subAckHandler = [&subAckedPromise](int) { + // if error code returns it will be recorded by the other callback + subAckedPromise.set_value(); + }; + + auto failureHandler = [](RejectedError *rejectedError, int ioErr) { + if (ioErr) + { + fprintf(stderr, "Error %d occurred\n", ioErr); + return; + } + if (rejectedError) + { + fprintf( + stderr, + "Service Error %d occurred. Message %s\n", + (int)rejectedError->Code.value(), + rejectedError->Message->c_str()); + return; + } + }; + + m_pendingExecutionPromise = std::promise(); + auto OnSubscribeToUpdateJobExecutionAcceptedResponse = [this, jobId](UpdateJobExecutionResponse *response, int ioErr) { + (void)response; + if (ioErr) + { + fprintf(stderr, "Error %d occurred\n", ioErr); + exit(1); + } + fprintf(stdout, "Marked Job %s IN_PROGRESS", jobId.c_str()); + m_pendingExecutionPromise.set_value(); + }; + UpdateJobExecutionSubscriptionRequest subscriptionRequest; + subscriptionRequest.ThingName = m_thingName; + subscriptionRequest.JobId = jobId; + + subAckedPromise = std::promise(); + m_jobsClient->SubscribeToUpdateJobExecutionAccepted( + subscriptionRequest, + AWS_MQTT_QOS_AT_LEAST_ONCE, + OnSubscribeToUpdateJobExecutionAcceptedResponse, + subAckHandler); + subAckedPromise.get_future().wait(); + + subAckedPromise = std::promise(); + m_jobsClient->SubscribeToUpdateJobExecutionRejected( + subscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, failureHandler, subAckHandler); + subAckedPromise.get_future().wait(); + + std::promise publishDescribeJobExeCompletedPromise; + + auto publishHandler = [&publishDescribeJobExeCompletedPromise](int ioErr) { + if (ioErr) + { + fprintf(stderr, "Error %d occurred\n", ioErr); + exit(1); + } + publishDescribeJobExeCompletedPromise.set_value(); + }; + + UpdateJobExecutionRequest publishRequest; + publishRequest.ThingName = m_thingName; + publishRequest.JobId = jobId; + publishRequest.ExecutionNumber = currentExecutionNumber; + publishRequest.Status = jobStatus; + publishRequest.ExpectedVersion = currentVersionNumber++; + m_jobsClient->PublishUpdateJobExecution(publishRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, publishHandler); + + m_pendingExecutionPromise.get_future().wait(); +} diff --git a/servicetests/tests/JobsExecution/JobsExecution.h b/servicetests/tests/JobsExecution/JobsExecution.h new file mode 100644 index 000000000..e39940f67 --- /dev/null +++ b/servicetests/tests/JobsExecution/JobsExecution.h @@ -0,0 +1,39 @@ +#pragma once + +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include +#include + +#include + +class JobsExecution +{ + public: + JobsExecution(std::shared_ptr jobsClient, Aws::Crt::String thingName); + + Aws::Crt::Vector getAvailableJobs(); + + void describeJob(const Aws::Crt::String &jobId); + + void startNextPendingJob(); + + void updateCurrentJobStatus(Aws::Iotjobs::JobStatus jobStatus); + + private: + std::shared_ptr m_jobsClient; + const Aws::Crt::String m_thingName; + + Aws::Crt::Vector m_availableJobs; + std::mutex m_jobsMutex; + std::promise m_getResponse; + + Aws::Crt::String m_currentJobId; + int64_t m_currentExecutionNumber; + int32_t m_currentVersionNumber; + + std::promise m_pendingExecutionPromise; +}; diff --git a/servicetests/tests/JobsExecution/main.cpp b/servicetests/tests/JobsExecution/main.cpp index 030af92cb..89e9d6248 100644 --- a/servicetests/tests/JobsExecution/main.cpp +++ b/servicetests/tests/JobsExecution/main.cpp @@ -4,7 +4,6 @@ */ #include #include -#include #include #include @@ -26,127 +25,15 @@ #include #include -#include #include -#include -#include #include -#include #include "../../../samples/utils/CommandLineUtils.h" +#include "JobsExecution.h" using namespace Aws::Crt; using namespace Aws::Iotjobs; -class AvailableJobsHandler -{ - public: - void receiveAvailableJobs(const Aws::Crt::String &thingName, IotJobsClient &jobsClient) - { - GetPendingJobExecutionsSubscriptionRequest subscriptionRequest; - subscriptionRequest.ThingName = thingName; - - auto handler = [this](Aws::Iotjobs::GetPendingJobExecutionsResponse *response, int ioErr) { - fprintf(stderr, "running the jobs handler\n"); - if (ioErr) - { - fprintf(stderr, "Error %d occurred\n", ioErr); - exit(1); - } - if (response) - { - if (response->InProgressJobs.has_value()) - { - for (const JobExecutionSummary &job : response->InProgressJobs.value()) - { - std::lock_guard lock(m_jobsMutex); - m_availableJobs.push_back(job.JobId.value()); - fprintf(stderr, "In Progress jobs %s\n", job.JobId->c_str()); - } - } - else - { - fprintf(stderr, "In Progress jobs: empty\n"); - } - if (response->QueuedJobs.has_value()) - { - for (const JobExecutionSummary &job : response->QueuedJobs.value()) - { - std::lock_guard lock(m_jobsMutex); - m_availableJobs.push_back(job.JobId.value()); - fprintf(stderr, "Queued jobs %s\n", job.JobId->c_str()); - } - } - else - { - fprintf(stderr, "Queued jobs: empty\n"); - } - } - m_getResponse.set_value(); - }; - - auto err_handler = [](Aws::Iotjobs::RejectedError *rejectedError, int ioErr) { - if (ioErr) - { - fprintf(stderr, "Error %d occurred\n", ioErr); - exit(1); - } - if (rejectedError) - { - fprintf( - stderr, - "Service Error %d occurred. Message %s\n", - (int)rejectedError->Code.value(), - rejectedError->Message->c_str()); - } - fprintf(stderr, "Error handler\n"); - exit(-1); - }; - - auto publishHandler = [this](int ioErr) { - if (ioErr) - { - fprintf(stderr, "Error %d occurred\n", ioErr); - exit(1); - } - m_publishDescribeJobExeCompletedPromise.set_value(); - }; - - jobsClient.SubscribeToGetPendingJobExecutionsAccepted( - subscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, handler, publishHandler); - m_publishDescribeJobExeCompletedPromise.get_future().wait(); - - m_publishDescribeJobExeCompletedPromise = std::promise(); - jobsClient.SubscribeToGetPendingJobExecutionsRejected( - subscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, err_handler, publishHandler); - m_publishDescribeJobExeCompletedPromise.get_future().wait(); - - m_publishDescribeJobExeCompletedPromise = std::promise(); - GetPendingJobExecutionsRequest publishRequest; - publishRequest.ThingName = thingName; - jobsClient.PublishGetPendingJobExecutions(publishRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, publishHandler); - m_publishDescribeJobExeCompletedPromise.get_future().wait(); - - if (m_getResponse.get_future().wait_for(std::chrono::seconds(10)) == std::future_status::timeout) - { - fprintf(stderr, "get available jobs error timedout\n"); - exit(-1); - } - } - - std::vector getAvailableJobs() const - { - std::lock_guard lock(m_jobsMutex); - return m_availableJobs; - } - - private: - std::vector m_availableJobs; - mutable std::mutex m_jobsMutex; - std::promise m_getResponse; - std::promise m_publishDescribeJobExeCompletedPromise; -}; - std::shared_ptr build_mqtt3_client( Utils::cmdData &cmdData, std::shared_ptr &connection, @@ -281,7 +168,6 @@ std::shared_ptr build_mqtt5_client( int main(int argc, char *argv[]) { - fprintf(stdout, "Starting the jobs execution program\n"); /************************ Setup ****************************/ @@ -319,234 +205,19 @@ int main(int argc, char *argv[]) exit(-1); } /************************ Run the sample ****************************/ - AvailableJobsHandler handler; if (connectionCompletedPromise.get_future().get()) { - handler.receiveAvailableJobs(cmdData.input_thingName, *jobsClient); - auto availableJobs = handler.getAvailableJobs(); - for (auto jobid : availableJobs) + JobsExecution jobsExecution(jobsClient, cmdData.input_thingName); + auto availableJobs = jobsExecution.getAvailableJobs(); + for (const auto &jobId : availableJobs) { - DescribeJobExecutionSubscriptionRequest describeJobExecutionSubscriptionRequest; - describeJobExecutionSubscriptionRequest.ThingName = cmdData.input_thingName; - describeJobExecutionSubscriptionRequest.JobId = jobid; - - /** - * This isn't absolutely necessary but since we're doing a publish almost immediately afterwards, - * to be cautious make sure the subscribe has finished before doing the publish. - */ - std::promise subAckedPromise; - auto subAckHandler = [&](int) { - // if error code returns it will be recorded by the other callback - subAckedPromise.set_value(); - }; - auto subscriptionHandler = [&](DescribeJobExecutionResponse *response, int ioErr) { - if (ioErr) - { - fprintf(stderr, "Error %d occurred\n", ioErr); - return; - } - if (response) - { - fprintf(stdout, "Received Job:\n"); - fprintf(stdout, "Job Id: %s\n", response->Execution->JobId->c_str()); - fprintf(stdout, "ClientToken: %s\n", response->ClientToken->c_str()); - fprintf( - stdout, "Execution Status: %s\n", JobStatusMarshaller::ToString(*response->Execution->Status)); - } - }; - - jobsClient->SubscribeToDescribeJobExecutionAccepted( - describeJobExecutionSubscriptionRequest, - AWS_MQTT_QOS_AT_LEAST_ONCE, - subscriptionHandler, - subAckHandler); - subAckedPromise.get_future().wait(); - - subAckedPromise = std::promise(); - - auto failureHandler = [&](RejectedError *rejectedError, int ioErr) { - if (ioErr) - { - fprintf(stderr, "Error %d occurred\n", ioErr); - return; - } - if (rejectedError) - { - fprintf( - stderr, - "Service Error %d occurred. Message %s\n", - (int)rejectedError->Code.value(), - rejectedError->Message->c_str()); - return; - } - }; - - jobsClient->SubscribeToDescribeJobExecutionRejected( - describeJobExecutionSubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, failureHandler, subAckHandler); - subAckedPromise.get_future().wait(); - - DescribeJobExecutionRequest describeJobExecutionRequest; - describeJobExecutionRequest.ThingName = cmdData.input_thingName; - describeJobExecutionRequest.JobId = jobid; - describeJobExecutionRequest.IncludeJobDocument = true; - Aws::Crt::UUID uuid; - describeJobExecutionRequest.ClientToken = uuid.ToString(); - std::promise publishDescribeJobExeCompletedPromise; - - auto publishHandler = [&](int ioErr) { - if (ioErr) - { - fprintf(stderr, "Error %d occurred\n", ioErr); - exit(1); - } - publishDescribeJobExeCompletedPromise.set_value(); - }; - - jobsClient->PublishDescribeJobExecution( - describeJobExecutionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, publishHandler); - publishDescribeJobExeCompletedPromise.get_future().wait(); - - Aws::Crt::String currentJobId; - int64_t currentExecutionNumber; - int32_t currentVersionNumber; - - std::promise pendingExecutionPromise; - - { - auto OnSubscribeToStartNextPendingJobExecutionAcceptedResponse = - [&](StartNextJobExecutionResponse *response, int ioErr) { - if (ioErr) - { - fprintf(stderr, "Error %d occurred\n", ioErr); - exit(1); - } - if (response) - { - fprintf(stdout, "Start Job %s\n", response->Execution.value().JobId.value().c_str()); - currentJobId = response->Execution->JobId.value(); - currentExecutionNumber = response->Execution->ExecutionNumber.value(); - currentVersionNumber = response->Execution->VersionNumber.value(); - } - else - { - fprintf(stdout, "Could not get Job Id exiting\n"); - exit(-1); - } - - pendingExecutionPromise.set_value(); - }; - - StartNextPendingJobExecutionSubscriptionRequest subscriptionRequest; - subscriptionRequest.ThingName = cmdData.input_thingName; - subAckedPromise = std::promise(); - jobsClient->SubscribeToStartNextPendingJobExecutionAccepted( - subscriptionRequest, - AWS_MQTT_QOS_AT_LEAST_ONCE, - OnSubscribeToStartNextPendingJobExecutionAcceptedResponse, - subAckHandler); - - subAckedPromise.get_future().wait(); - - subAckedPromise = std::promise(); - jobsClient->SubscribeToStartNextPendingJobExecutionRejected( - subscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, failureHandler, subAckHandler); - - subAckedPromise.get_future().wait(); - - StartNextPendingJobExecutionRequest publishRequest; - publishRequest.ThingName = cmdData.input_thingName; - publishRequest.StepTimeoutInMinutes = 15L; - - publishDescribeJobExeCompletedPromise = std::promise(); - jobsClient->PublishStartNextPendingJobExecution( - publishRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, publishHandler); - - pendingExecutionPromise.get_future().wait(); - } - - { - pendingExecutionPromise = std::promise(); - auto OnSubscribeToUpdateJobExecutionAcceptedResponse = [&](UpdateJobExecutionResponse *response, - int ioErr) { - (void)response; - if (ioErr) - { - fprintf(stderr, "Error %d occurred\n", ioErr); - exit(1); - } - fprintf(stdout, "Marked Job %s IN_PROGRESS", currentJobId.c_str()); - pendingExecutionPromise.set_value(); - }; - UpdateJobExecutionSubscriptionRequest subscriptionRequest; - subscriptionRequest.ThingName = cmdData.input_thingName; - subscriptionRequest.JobId = currentJobId; - - subAckedPromise = std::promise(); - jobsClient->SubscribeToUpdateJobExecutionAccepted( - subscriptionRequest, - AWS_MQTT_QOS_AT_LEAST_ONCE, - OnSubscribeToUpdateJobExecutionAcceptedResponse, - subAckHandler); - subAckedPromise.get_future().wait(); - - subAckedPromise = std::promise(); - jobsClient->SubscribeToUpdateJobExecutionRejected( - subscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, failureHandler, subAckHandler); - subAckedPromise.get_future().wait(); - - publishDescribeJobExeCompletedPromise = std::promise(); - UpdateJobExecutionRequest publishRequest; - publishRequest.ThingName = cmdData.input_thingName; - publishRequest.JobId = currentJobId; - publishRequest.ExecutionNumber = currentExecutionNumber; - publishRequest.Status = JobStatus::IN_PROGRESS; - publishRequest.ExpectedVersion = currentVersionNumber++; - jobsClient->PublishUpdateJobExecution(publishRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, publishHandler); - - pendingExecutionPromise.get_future().wait(); - } - - // Pretend doing some work - std::this_thread::sleep_for(std::chrono::milliseconds(1000)); - - { - pendingExecutionPromise = std::promise(); - UpdateJobExecutionSubscriptionRequest subscriptionRequest; - subscriptionRequest.ThingName = cmdData.input_thingName; - subscriptionRequest.JobId = currentJobId; - - auto subscribeHandler = [&](UpdateJobExecutionResponse *response, int ioErr) { - (void)response; - if (ioErr) - { - fprintf(stderr, "Error %d occurred\n", ioErr); - exit(1); - } - fprintf(stdout, "Marked job %s currentJobId SUCCEEDED", currentJobId.c_str()); - pendingExecutionPromise.set_value(); - }; - subAckedPromise = std::promise(); - jobsClient->SubscribeToUpdateJobExecutionAccepted( - subscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, subscribeHandler, subAckHandler); - subAckedPromise.get_future().wait(); - - subAckedPromise = std::promise(); - jobsClient->SubscribeToUpdateJobExecutionRejected( - subscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, failureHandler, subAckHandler); - subAckedPromise.get_future().wait(); - - UpdateJobExecutionRequest publishRequest; - publishRequest.ThingName = cmdData.input_thingName; - publishRequest.JobId = currentJobId; - publishRequest.ExecutionNumber = currentExecutionNumber; - publishRequest.Status = JobStatus::SUCCEEDED; - publishRequest.ExpectedVersion = currentVersionNumber++; - - publishDescribeJobExeCompletedPromise = std::promise(); - jobsClient->PublishUpdateJobExecution(publishRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, publishHandler); + jobsExecution.describeJob(jobId); + } - pendingExecutionPromise.get_future().wait(); - } + for (size_t idx = 0; idx < availableJobs.size(); ++idx) + { + jobsExecution.startNextPendingJob(); + jobsExecution.updateCurrentJobStatus(Aws::Iotjobs::JobStatus::SUCCEEDED); } } // Wait just a little bit to let the console print From f5ca4b5d7de7a354b1c20d36cd3185b3dd3be9db Mon Sep 17 00:00:00 2001 From: Igor Abdrakhimov Date: Thu, 2 May 2024 10:15:26 -0700 Subject: [PATCH 27/47] Remove mqtt3 client from comd utils --- samples/utils/CommandLineUtils.h | 1 - 1 file changed, 1 deletion(-) diff --git a/samples/utils/CommandLineUtils.h b/samples/utils/CommandLineUtils.h index d5a0ea961..a4f1a3af8 100644 --- a/samples/utils/CommandLineUtils.h +++ b/samples/utils/CommandLineUtils.h @@ -194,7 +194,6 @@ namespace Utils const char **m_endPosition = nullptr; Aws::Crt::Map m_registeredCommands; - Aws::Iot::MqttClient m_internal_client; Aws::Crt::Http::HttpClientConnectionProxyOptions GetProxyOptionsForMQTTConnection(); std::shared_ptr GetClientConnectionForMQTTConnection( Aws::Iot::MqttClient *client, From 7880f0da88d4494d33690a1efcfcd738ab3edd50 Mon Sep 17 00:00:00 2001 From: Igor Abdrakhimov Date: Thu, 2 May 2024 10:19:36 -0700 Subject: [PATCH 28/47] Fix format --- .../tests/JobsExecution/JobsExecution.cpp | 58 ++++++++++--------- 1 file changed, 31 insertions(+), 27 deletions(-) diff --git a/servicetests/tests/JobsExecution/JobsExecution.cpp b/servicetests/tests/JobsExecution/JobsExecution.cpp index 7921b3ae7..3b894537b 100644 --- a/servicetests/tests/JobsExecution/JobsExecution.cpp +++ b/servicetests/tests/JobsExecution/JobsExecution.cpp @@ -25,7 +25,8 @@ using namespace Aws::Crt; using namespace Aws::Iotjobs; JobsExecution::JobsExecution(std::shared_ptr jobsClient, Aws::Crt::String thingName) - : m_jobsClient(std::move(jobsClient)), m_thingName(std::move(thingName)), m_currentExecutionNumber(), m_currentVersionNumber() + : m_jobsClient(std::move(jobsClient)), m_thingName(std::move(thingName)), m_currentExecutionNumber(), + m_currentVersionNumber() { } @@ -127,7 +128,8 @@ Aws::Crt::Vector JobsExecution::getAvailableJobs() return m_availableJobs; } -void JobsExecution::describeJob(const String &jobId) { +void JobsExecution::describeJob(const String &jobId) +{ DescribeJobExecutionSubscriptionRequest describeJobExecutionSubscriptionRequest; describeJobExecutionSubscriptionRequest.ThingName = m_thingName; describeJobExecutionSubscriptionRequest.JobId = jobId; @@ -204,7 +206,8 @@ void JobsExecution::describeJob(const String &jobId) { publishDescribeJobExeCompletedPromise.get_future().wait(); } -void JobsExecution::startNextPendingJob() { +void JobsExecution::startNextPendingJob() +{ std::promise subAckedPromise; auto subAckHandler = [&subAckedPromise](int) { // if error code returns it will be recorded by the other callback @@ -230,30 +233,30 @@ void JobsExecution::startNextPendingJob() { Aws::Crt::String jobId; - auto OnSubscribeToStartNextPendingJobExecutionAcceptedResponse = [this](StartNextJobExecutionResponse *response, - int ioErr) { - if (ioErr) - { - fprintf(stderr, "Error %d occurred\n", ioErr); - exit(1); - } - if (response && response->Execution.has_value()) - { - fprintf(stdout, "Start Job %s\n", response->Execution.value().JobId.value().c_str()); - // Make tsan happy. - std::lock_guard lock(m_jobsMutex); - m_currentJobId = response->Execution->JobId.value(); - m_currentExecutionNumber = response->Execution->ExecutionNumber.value(); - m_currentVersionNumber = response->Execution->VersionNumber.value(); - } - else - { - fprintf(stdout, "Could not get Job Id, exiting\n"); - exit(-1); - } + auto OnSubscribeToStartNextPendingJobExecutionAcceptedResponse = + [this](StartNextJobExecutionResponse *response, int ioErr) { + if (ioErr) + { + fprintf(stderr, "Error %d occurred\n", ioErr); + exit(1); + } + if (response && response->Execution.has_value()) + { + fprintf(stdout, "Start Job %s\n", response->Execution.value().JobId.value().c_str()); + // Make tsan happy. + std::lock_guard lock(m_jobsMutex); + m_currentJobId = response->Execution->JobId.value(); + m_currentExecutionNumber = response->Execution->ExecutionNumber.value(); + m_currentVersionNumber = response->Execution->VersionNumber.value(); + } + else + { + fprintf(stdout, "Could not get Job Id, exiting\n"); + exit(-1); + } - m_pendingExecutionPromise.set_value(); - }; + m_pendingExecutionPromise.set_value(); + }; StartNextPendingJobExecutionSubscriptionRequest subscriptionRequest; subscriptionRequest.ThingName = m_thingName; @@ -329,7 +332,8 @@ void JobsExecution::updateCurrentJobStatus(Aws::Iotjobs::JobStatus jobStatus) }; m_pendingExecutionPromise = std::promise(); - auto OnSubscribeToUpdateJobExecutionAcceptedResponse = [this, jobId](UpdateJobExecutionResponse *response, int ioErr) { + auto OnSubscribeToUpdateJobExecutionAcceptedResponse = [this, + jobId](UpdateJobExecutionResponse *response, int ioErr) { (void)response; if (ioErr) { From 07865005be0acc42eb3651e9a213ba04cf097f28 Mon Sep 17 00:00:00 2001 From: Igor Abdrakhimov Date: Thu, 2 May 2024 10:34:09 -0700 Subject: [PATCH 29/47] Add wait --- servicetests/tests/JobsExecution/JobsExecution.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/servicetests/tests/JobsExecution/JobsExecution.cpp b/servicetests/tests/JobsExecution/JobsExecution.cpp index 3b894537b..7f9b5ee9e 100644 --- a/servicetests/tests/JobsExecution/JobsExecution.cpp +++ b/servicetests/tests/JobsExecution/JobsExecution.cpp @@ -379,5 +379,6 @@ void JobsExecution::updateCurrentJobStatus(Aws::Iotjobs::JobStatus jobStatus) publishRequest.ExpectedVersion = currentVersionNumber++; m_jobsClient->PublishUpdateJobExecution(publishRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, publishHandler); + publishDescribeJobExeCompletedPromise.get_future().wait(); m_pendingExecutionPromise.get_future().wait(); } From 56ff250aa6bb8696f4a76c776f1105400206c445 Mon Sep 17 00:00:00 2001 From: Igor Abdrakhimov Date: Thu, 2 May 2024 10:49:33 -0700 Subject: [PATCH 30/47] fixup --- .../tests/JobsExecution/JobsExecution.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/servicetests/tests/JobsExecution/JobsExecution.cpp b/servicetests/tests/JobsExecution/JobsExecution.cpp index 7f9b5ee9e..98f193f5c 100644 --- a/servicetests/tests/JobsExecution/JobsExecution.cpp +++ b/servicetests/tests/JobsExecution/JobsExecution.cpp @@ -333,14 +333,14 @@ void JobsExecution::updateCurrentJobStatus(Aws::Iotjobs::JobStatus jobStatus) m_pendingExecutionPromise = std::promise(); auto OnSubscribeToUpdateJobExecutionAcceptedResponse = [this, - jobId](UpdateJobExecutionResponse *response, int ioErr) { + jobId, jobStatus](UpdateJobExecutionResponse *response, int ioErr) { (void)response; if (ioErr) { fprintf(stderr, "Error %d occurred\n", ioErr); exit(1); } - fprintf(stdout, "Marked Job %s IN_PROGRESS", jobId.c_str()); + fprintf(stdout, "Marked Job %s %s\n", jobId.c_str(), JobStatusMarshaller::ToString(jobStatus)); m_pendingExecutionPromise.set_value(); }; UpdateJobExecutionSubscriptionRequest subscriptionRequest; @@ -360,15 +360,18 @@ void JobsExecution::updateCurrentJobStatus(Aws::Iotjobs::JobStatus jobStatus) subscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, failureHandler, subAckHandler); subAckedPromise.get_future().wait(); - std::promise publishDescribeJobExeCompletedPromise; + std::promise publishPromise; - auto publishHandler = [&publishDescribeJobExeCompletedPromise](int ioErr) { + auto publishHandler = [&publishPromise](int ioErr) { if (ioErr) { fprintf(stderr, "Error %d occurred\n", ioErr); exit(1); } - publishDescribeJobExeCompletedPromise.set_value(); + else { + fprintf(stdout, "Publish handler done\n"); + } + publishPromise.set_value(); }; UpdateJobExecutionRequest publishRequest; @@ -379,6 +382,6 @@ void JobsExecution::updateCurrentJobStatus(Aws::Iotjobs::JobStatus jobStatus) publishRequest.ExpectedVersion = currentVersionNumber++; m_jobsClient->PublishUpdateJobExecution(publishRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, publishHandler); - publishDescribeJobExeCompletedPromise.get_future().wait(); + publishPromise.get_future().wait(); m_pendingExecutionPromise.get_future().wait(); } From 99c9a6aca60ee44a7a58dfb70a8c6ad0a65aa557 Mon Sep 17 00:00:00 2001 From: Igor Abdrakhimov Date: Thu, 2 May 2024 11:12:25 -0700 Subject: [PATCH 31/47] Use stderr --- .../tests/JobsExecution/JobsExecution.cpp | 16 ++++++++-------- servicetests/tests/JobsExecution/main.cpp | 16 ++++++++-------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/servicetests/tests/JobsExecution/JobsExecution.cpp b/servicetests/tests/JobsExecution/JobsExecution.cpp index 98f193f5c..e3b224145 100644 --- a/servicetests/tests/JobsExecution/JobsExecution.cpp +++ b/servicetests/tests/JobsExecution/JobsExecution.cpp @@ -151,10 +151,10 @@ void JobsExecution::describeJob(const String &jobId) } if (response) { - fprintf(stdout, "Received Job:\n"); - fprintf(stdout, "Job Id: %s\n", response->Execution->JobId->c_str()); - fprintf(stdout, "ClientToken: %s\n", response->ClientToken->c_str()); - fprintf(stdout, "Execution Status: %s\n", JobStatusMarshaller::ToString(*response->Execution->Status)); + fprintf(stderr, "Received Job:\n"); + fprintf(stderr, "Job Id: %s\n", response->Execution->JobId->c_str()); + fprintf(stderr, "ClientToken: %s\n", response->ClientToken->c_str()); + fprintf(stderr, "Execution Status: %s\n", JobStatusMarshaller::ToString(*response->Execution->Status)); } }; @@ -242,7 +242,7 @@ void JobsExecution::startNextPendingJob() } if (response && response->Execution.has_value()) { - fprintf(stdout, "Start Job %s\n", response->Execution.value().JobId.value().c_str()); + fprintf(stderr, "Start Job %s\n", response->Execution.value().JobId.value().c_str()); // Make tsan happy. std::lock_guard lock(m_jobsMutex); m_currentJobId = response->Execution->JobId.value(); @@ -251,7 +251,7 @@ void JobsExecution::startNextPendingJob() } else { - fprintf(stdout, "Could not get Job Id, exiting\n"); + fprintf(stderr, "Could not get Job Id, exiting\n"); exit(-1); } @@ -340,7 +340,7 @@ void JobsExecution::updateCurrentJobStatus(Aws::Iotjobs::JobStatus jobStatus) fprintf(stderr, "Error %d occurred\n", ioErr); exit(1); } - fprintf(stdout, "Marked Job %s %s\n", jobId.c_str(), JobStatusMarshaller::ToString(jobStatus)); + fprintf(stderr, "Marked Job %s %s\n", jobId.c_str(), JobStatusMarshaller::ToString(jobStatus)); m_pendingExecutionPromise.set_value(); }; UpdateJobExecutionSubscriptionRequest subscriptionRequest; @@ -369,7 +369,7 @@ void JobsExecution::updateCurrentJobStatus(Aws::Iotjobs::JobStatus jobStatus) exit(1); } else { - fprintf(stdout, "Publish handler done\n"); + fprintf(stderr, "Publish handler done\n"); } publishPromise.set_value(); }; diff --git a/servicetests/tests/JobsExecution/main.cpp b/servicetests/tests/JobsExecution/main.cpp index 89e9d6248..175e55553 100644 --- a/servicetests/tests/JobsExecution/main.cpp +++ b/servicetests/tests/JobsExecution/main.cpp @@ -76,12 +76,12 @@ std::shared_ptr build_mqtt3_client( auto onConnectionCompleted = [&](Mqtt::MqttConnection &, int errorCode, Mqtt::ReturnCode returnCode, bool) { if (errorCode) { - fprintf(stdout, "Connection failed with error %s\n", ErrorDebugString(errorCode)); + fprintf(stderr, "Connection failed with error %s\n", ErrorDebugString(errorCode)); connectionCompletedPromise.set_value(false); } else { - fprintf(stdout, "Connection completed with return code %d\n", returnCode); + fprintf(stderr, "Connection completed with return code %d\n", returnCode); connectionCompletedPromise.set_value(true); } }; @@ -89,7 +89,7 @@ std::shared_ptr build_mqtt3_client( // Invoked when a disconnect has been completed auto onDisconnect = [&](Mqtt::MqttConnection & /*conn*/) { { - fprintf(stdout, "Disconnect completed\n"); + fprintf(stderr, "Disconnect completed\n"); connectionClosedPromise.set_value(); } }; @@ -135,18 +135,18 @@ std::shared_ptr build_mqtt5_client( builder->WithClientConnectionSuccessCallback( [&connectionCompletedPromise](const Mqtt5::OnConnectionSuccessEventData &eventData) { fprintf( - stdout, + stderr, "Mqtt5 Client connection succeed, clientid: %s.\n", eventData.negotiatedSettings->getClientId().c_str()); connectionCompletedPromise.set_value(true); }); builder->WithClientConnectionFailureCallback([&connectionCompletedPromise]( const Mqtt5::OnConnectionFailureEventData &eventData) { - fprintf(stdout, "Mqtt5 Client connection failed with error: %s.\n", aws_error_debug_str(eventData.errorCode)); + fprintf(stderr, "Mqtt5 Client connection failed with error: %s.\n", aws_error_debug_str(eventData.errorCode)); connectionCompletedPromise.set_value(false); }); builder->WithClientStoppedCallback([&connectionClosedPromise](const Mqtt5::OnStoppedEventData &) { - fprintf(stdout, "Mqtt5 Client stopped.\n"); + fprintf(stderr, "Mqtt5 Client stopped.\n"); connectionClosedPromise.set_value(); }); @@ -154,7 +154,7 @@ std::shared_ptr build_mqtt5_client( if (client5 == nullptr) { fprintf( - stdout, "Failed to Init Mqtt5Client with error code %d: %s.\n", LastError(), ErrorDebugString(LastError())); + stderr, "Failed to Init Mqtt5Client with error code %d: %s.\n", LastError(), ErrorDebugString(LastError())); exit(-1); } @@ -168,7 +168,7 @@ std::shared_ptr build_mqtt5_client( int main(int argc, char *argv[]) { - fprintf(stdout, "Starting the jobs execution program\n"); + fprintf(stderr, "Starting the jobs execution program\n"); /************************ Setup ****************************/ // Do the global initialization for the API From 91a6867c0e2359c377edea35119cef8cf8c3bb3f Mon Sep 17 00:00:00 2001 From: Igor Abdrakhimov Date: Thu, 2 May 2024 11:37:11 -0700 Subject: [PATCH 32/47] Use cmake_args in samples and tests --- .builder/actions/build_samples.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.builder/actions/build_samples.py b/.builder/actions/build_samples.py index d007b769d..1fb6a7274 100644 --- a/.builder/actions/build_samples.py +++ b/.builder/actions/build_samples.py @@ -64,6 +64,7 @@ def run(self, env): '-DCMAKE_BUILD_TYPE=RelWithDebInfo']) # append extra cmake configs steps[-1].extend(cmd_args.cmake_extra) + steps[-1].extend(env.config['cmake_args']) steps.append(['cmake', '--build', build_path, '--config', 'RelWithDebInfo']) @@ -77,6 +78,7 @@ def run(self, env): '-DCMAKE_BUILD_TYPE=RelWithDebInfo']) # append extra cmake configs steps[-1].extend(cmd_args.cmake_extra) + steps[-1].extend(env.config['cmake_args']) steps.append(['cmake', '--build', build_path, '--config', 'RelWithDebInfo']) @@ -90,6 +92,7 @@ def run(self, env): '-DCMAKE_BUILD_TYPE=RelWithDebInfo']) # append extra cmake configs steps[-1].extend(cmd_args.cmake_extra) + steps[-1].extend(env.config['cmake_args']) steps.append(['cmake', '--build', build_path, '--config', 'RelWithDebInfo']) @@ -101,6 +104,7 @@ def run(self, env): f'-H{sample_path}', f'-DCMAKE_PREFIX_PATH={env.install_dir}', '-DCMAKE_BUILD_TYPE=RelWithDebInfo']) + steps[-1].extend(env.config['cmake_args']) steps.append(['cmake', '--build', build_path, '--config', 'RelWithDebInfo']) From 4c9c41d3e3aa72d089f38fe33a7f1b20eb68061a Mon Sep 17 00:00:00 2001 From: Igor Abdrakhimov Date: Thu, 2 May 2024 12:43:13 -0700 Subject: [PATCH 33/47] Try to remove lock --- servicetests/tests/JobsExecution/JobsExecution.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/servicetests/tests/JobsExecution/JobsExecution.cpp b/servicetests/tests/JobsExecution/JobsExecution.cpp index e3b224145..f79330892 100644 --- a/servicetests/tests/JobsExecution/JobsExecution.cpp +++ b/servicetests/tests/JobsExecution/JobsExecution.cpp @@ -243,8 +243,6 @@ void JobsExecution::startNextPendingJob() if (response && response->Execution.has_value()) { fprintf(stderr, "Start Job %s\n", response->Execution.value().JobId.value().c_str()); - // Make tsan happy. - std::lock_guard lock(m_jobsMutex); m_currentJobId = response->Execution->JobId.value(); m_currentExecutionNumber = response->Execution->ExecutionNumber.value(); m_currentVersionNumber = response->Execution->VersionNumber.value(); @@ -301,8 +299,6 @@ void JobsExecution::updateCurrentJobStatus(Aws::Iotjobs::JobStatus jobStatus) int32_t currentVersionNumber; { - // Make tsan happy. - std::lock_guard lock(m_jobsMutex); jobId = m_currentJobId; currentExecutionNumber = m_currentExecutionNumber; currentVersionNumber = m_currentVersionNumber; From 510d644183ce2eda5f6c61c701fd9384941ba67f Mon Sep 17 00:00:00 2001 From: Igor Abdrakhimov Date: Fri, 3 May 2024 11:54:55 -0700 Subject: [PATCH 34/47] Revert jobs service test --- .../tests/JobsExecution/CMakeLists.txt | 17 - .../tests/JobsExecution/JobsExecution.cpp | 383 ------------------ .../tests/JobsExecution/JobsExecution.h | 39 -- servicetests/tests/JobsExecution/main.cpp | 357 +++++++++++++++- 4 files changed, 339 insertions(+), 457 deletions(-) delete mode 100644 servicetests/tests/JobsExecution/JobsExecution.cpp delete mode 100644 servicetests/tests/JobsExecution/JobsExecution.h diff --git a/servicetests/tests/JobsExecution/CMakeLists.txt b/servicetests/tests/JobsExecution/CMakeLists.txt index 834189e41..70577d337 100644 --- a/servicetests/tests/JobsExecution/CMakeLists.txt +++ b/servicetests/tests/JobsExecution/CMakeLists.txt @@ -4,7 +4,6 @@ project(job-execution CXX) file(GLOB SRC_FILES "*.cpp" - "*.h" "../../../samples/utils/CommandLineUtils.cpp" "../../../samples/utils/CommandLineUtils.h" ) @@ -26,20 +25,4 @@ find_package(IotJobs-cpp REQUIRED) install(TARGETS ${PROJECT_NAME} DESTINATION bin) -if (UNIX AND NOT APPLE) - include(GNUInstallDirs) -elseif(NOT DEFINED CMAKE_INSTALL_LIBDIR) - set(CMAKE_INSTALL_LIBDIR "lib") - - if (${CMAKE_INSTALL_LIBDIR} STREQUAL "lib64") - set(FIND_LIBRARY_USE_LIB64_PATHS true) - endif() -endif() - -list(APPEND CMAKE_MODULE_PATH "${CMAKE_PREFIX_PATH}/${CMAKE_INSTALL_LIBDIR}/cmake") - -include(AwsSanitizers) -enable_language(C) -aws_add_sanitizers(${PROJECT_NAME}) - target_link_libraries(${PROJECT_NAME} PRIVATE AWS::aws-crt-cpp AWS::IotJobs-cpp) diff --git a/servicetests/tests/JobsExecution/JobsExecution.cpp b/servicetests/tests/JobsExecution/JobsExecution.cpp deleted file mode 100644 index f79330892..000000000 --- a/servicetests/tests/JobsExecution/JobsExecution.cpp +++ /dev/null @@ -1,383 +0,0 @@ -/** - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0. - */ - -#include "JobsExecution.h" - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace Aws::Crt; -using namespace Aws::Iotjobs; - -JobsExecution::JobsExecution(std::shared_ptr jobsClient, Aws::Crt::String thingName) - : m_jobsClient(std::move(jobsClient)), m_thingName(std::move(thingName)), m_currentExecutionNumber(), - m_currentVersionNumber() -{ -} - -Aws::Crt::Vector JobsExecution::getAvailableJobs() -{ - GetPendingJobExecutionsSubscriptionRequest subscriptionRequest; - subscriptionRequest.ThingName = m_thingName; - - auto handler = [this](Aws::Iotjobs::GetPendingJobExecutionsResponse *response, int ioErr) { - fprintf(stderr, "running the jobs handler\n"); - if (ioErr) - { - fprintf(stderr, "Error %d occurred\n", ioErr); - exit(1); - } - if (response) - { - if (response->InProgressJobs.has_value()) - { - for (const JobExecutionSummary &job : response->InProgressJobs.value()) - { - std::lock_guard lock(m_jobsMutex); - m_availableJobs.push_back(job.JobId.value()); - fprintf(stderr, "In Progress jobs %s\n", job.JobId->c_str()); - } - } - else - { - fprintf(stderr, "In Progress jobs: empty\n"); - } - if (response->QueuedJobs.has_value()) - { - for (const JobExecutionSummary &job : response->QueuedJobs.value()) - { - std::lock_guard lock(m_jobsMutex); - m_availableJobs.push_back(job.JobId.value()); - fprintf(stderr, "Queued jobs %s\n", job.JobId->c_str()); - } - } - else - { - fprintf(stderr, "Queued jobs: empty\n"); - } - } - m_getResponse.set_value(); - }; - - auto err_handler = [](Aws::Iotjobs::RejectedError *rejectedError, int ioErr) { - if (ioErr) - { - fprintf(stderr, "Error %d occurred\n", ioErr); - exit(1); - } - if (rejectedError) - { - fprintf( - stderr, - "Service Error %d occurred. Message %s\n", - (int)rejectedError->Code.value(), - rejectedError->Message->c_str()); - } - fprintf(stderr, "Error handler\n"); - exit(-1); - }; - - std::promise publishDescribeJobExeCompletedPromise; - - auto publishHandler = [&publishDescribeJobExeCompletedPromise](int ioErr) { - if (ioErr) - { - fprintf(stderr, "Error %d occurred\n", ioErr); - exit(1); - } - publishDescribeJobExeCompletedPromise.set_value(); - }; - - m_jobsClient->SubscribeToGetPendingJobExecutionsAccepted( - subscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, handler, publishHandler); - publishDescribeJobExeCompletedPromise.get_future().wait(); - - publishDescribeJobExeCompletedPromise = std::promise(); - m_jobsClient->SubscribeToGetPendingJobExecutionsRejected( - subscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, err_handler, publishHandler); - publishDescribeJobExeCompletedPromise.get_future().wait(); - - publishDescribeJobExeCompletedPromise = std::promise(); - GetPendingJobExecutionsRequest publishRequest; - publishRequest.ThingName = m_thingName; - m_jobsClient->PublishGetPendingJobExecutions(publishRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, publishHandler); - publishDescribeJobExeCompletedPromise.get_future().wait(); - - if (m_getResponse.get_future().wait_for(std::chrono::seconds(10)) == std::future_status::timeout) - { - fprintf(stderr, "get available jobs error timedout\n"); - exit(-1); - } - - std::lock_guard lock(m_jobsMutex); - return m_availableJobs; -} - -void JobsExecution::describeJob(const String &jobId) -{ - DescribeJobExecutionSubscriptionRequest describeJobExecutionSubscriptionRequest; - describeJobExecutionSubscriptionRequest.ThingName = m_thingName; - describeJobExecutionSubscriptionRequest.JobId = jobId; - - /** - * This isn't absolutely necessary but since we're doing a publish almost immediately afterwards, - * to be cautious make sure the subscribe has finished before doing the publish. - */ - std::promise subAckedPromise; - auto subAckHandler = [&subAckedPromise](int) { - // if error code returns it will be recorded by the other callback - subAckedPromise.set_value(); - }; - auto subscriptionHandler = [&](DescribeJobExecutionResponse *response, int ioErr) { - if (ioErr) - { - fprintf(stderr, "Error %d occurred\n", ioErr); - return; - } - if (response) - { - fprintf(stderr, "Received Job:\n"); - fprintf(stderr, "Job Id: %s\n", response->Execution->JobId->c_str()); - fprintf(stderr, "ClientToken: %s\n", response->ClientToken->c_str()); - fprintf(stderr, "Execution Status: %s\n", JobStatusMarshaller::ToString(*response->Execution->Status)); - } - }; - - m_jobsClient->SubscribeToDescribeJobExecutionAccepted( - describeJobExecutionSubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, subscriptionHandler, subAckHandler); - subAckedPromise.get_future().wait(); - - subAckedPromise = std::promise(); - - auto failureHandler = [](RejectedError *rejectedError, int ioErr) { - if (ioErr) - { - fprintf(stderr, "Error %d occurred\n", ioErr); - return; - } - if (rejectedError) - { - fprintf( - stderr, - "Service Error %d occurred. Message %s\n", - (int)rejectedError->Code.value(), - rejectedError->Message->c_str()); - return; - } - }; - - m_jobsClient->SubscribeToDescribeJobExecutionRejected( - describeJobExecutionSubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, failureHandler, subAckHandler); - subAckedPromise.get_future().wait(); - - DescribeJobExecutionRequest describeJobExecutionRequest; - describeJobExecutionRequest.ThingName = m_thingName; - describeJobExecutionRequest.JobId = jobId; - describeJobExecutionRequest.IncludeJobDocument = true; - Aws::Crt::UUID uuid; - describeJobExecutionRequest.ClientToken = uuid.ToString(); - std::promise publishDescribeJobExeCompletedPromise; - - auto publishHandler = [&publishDescribeJobExeCompletedPromise](int ioErr) { - if (ioErr) - { - fprintf(stderr, "Error %d occurred\n", ioErr); - exit(1); - } - publishDescribeJobExeCompletedPromise.set_value(); - }; - - m_jobsClient->PublishDescribeJobExecution(describeJobExecutionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, publishHandler); - publishDescribeJobExeCompletedPromise.get_future().wait(); -} - -void JobsExecution::startNextPendingJob() -{ - std::promise subAckedPromise; - auto subAckHandler = [&subAckedPromise](int) { - // if error code returns it will be recorded by the other callback - subAckedPromise.set_value(); - }; - - auto failureHandler = [](RejectedError *rejectedError, int ioErr) { - if (ioErr) - { - fprintf(stderr, "Error %d occurred\n", ioErr); - return; - } - if (rejectedError) - { - fprintf( - stderr, - "Service Error %d occurred. Message %s\n", - (int)rejectedError->Code.value(), - rejectedError->Message->c_str()); - return; - } - }; - - Aws::Crt::String jobId; - - auto OnSubscribeToStartNextPendingJobExecutionAcceptedResponse = - [this](StartNextJobExecutionResponse *response, int ioErr) { - if (ioErr) - { - fprintf(stderr, "Error %d occurred\n", ioErr); - exit(1); - } - if (response && response->Execution.has_value()) - { - fprintf(stderr, "Start Job %s\n", response->Execution.value().JobId.value().c_str()); - m_currentJobId = response->Execution->JobId.value(); - m_currentExecutionNumber = response->Execution->ExecutionNumber.value(); - m_currentVersionNumber = response->Execution->VersionNumber.value(); - } - else - { - fprintf(stderr, "Could not get Job Id, exiting\n"); - exit(-1); - } - - m_pendingExecutionPromise.set_value(); - }; - - StartNextPendingJobExecutionSubscriptionRequest subscriptionRequest; - subscriptionRequest.ThingName = m_thingName; - subAckedPromise = std::promise(); - m_jobsClient->SubscribeToStartNextPendingJobExecutionAccepted( - subscriptionRequest, - AWS_MQTT_QOS_AT_LEAST_ONCE, - OnSubscribeToStartNextPendingJobExecutionAcceptedResponse, - subAckHandler); - - subAckedPromise.get_future().wait(); - - subAckedPromise = std::promise(); - m_jobsClient->SubscribeToStartNextPendingJobExecutionRejected( - subscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, failureHandler, subAckHandler); - - subAckedPromise.get_future().wait(); - - StartNextPendingJobExecutionRequest publishRequest; - publishRequest.ThingName = m_thingName; - publishRequest.StepTimeoutInMinutes = 15L; - - std::promise publishDescribeJobExeCompletedPromise; - - auto publishHandler = [&publishDescribeJobExeCompletedPromise](int ioErr) { - if (ioErr) - { - fprintf(stderr, "Error %d occurred\n", ioErr); - exit(1); - } - publishDescribeJobExeCompletedPromise.set_value(); - }; - m_jobsClient->PublishStartNextPendingJobExecution(publishRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, publishHandler); - - m_pendingExecutionPromise.get_future().wait(); -} - -void JobsExecution::updateCurrentJobStatus(Aws::Iotjobs::JobStatus jobStatus) -{ - Aws::Crt::String jobId; - int64_t currentExecutionNumber; - int32_t currentVersionNumber; - - { - jobId = m_currentJobId; - currentExecutionNumber = m_currentExecutionNumber; - currentVersionNumber = m_currentVersionNumber; - } - - std::promise subAckedPromise; - auto subAckHandler = [&subAckedPromise](int) { - // if error code returns it will be recorded by the other callback - subAckedPromise.set_value(); - }; - - auto failureHandler = [](RejectedError *rejectedError, int ioErr) { - if (ioErr) - { - fprintf(stderr, "Error %d occurred\n", ioErr); - return; - } - if (rejectedError) - { - fprintf( - stderr, - "Service Error %d occurred. Message %s\n", - (int)rejectedError->Code.value(), - rejectedError->Message->c_str()); - return; - } - }; - - m_pendingExecutionPromise = std::promise(); - auto OnSubscribeToUpdateJobExecutionAcceptedResponse = [this, - jobId, jobStatus](UpdateJobExecutionResponse *response, int ioErr) { - (void)response; - if (ioErr) - { - fprintf(stderr, "Error %d occurred\n", ioErr); - exit(1); - } - fprintf(stderr, "Marked Job %s %s\n", jobId.c_str(), JobStatusMarshaller::ToString(jobStatus)); - m_pendingExecutionPromise.set_value(); - }; - UpdateJobExecutionSubscriptionRequest subscriptionRequest; - subscriptionRequest.ThingName = m_thingName; - subscriptionRequest.JobId = jobId; - - subAckedPromise = std::promise(); - m_jobsClient->SubscribeToUpdateJobExecutionAccepted( - subscriptionRequest, - AWS_MQTT_QOS_AT_LEAST_ONCE, - OnSubscribeToUpdateJobExecutionAcceptedResponse, - subAckHandler); - subAckedPromise.get_future().wait(); - - subAckedPromise = std::promise(); - m_jobsClient->SubscribeToUpdateJobExecutionRejected( - subscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, failureHandler, subAckHandler); - subAckedPromise.get_future().wait(); - - std::promise publishPromise; - - auto publishHandler = [&publishPromise](int ioErr) { - if (ioErr) - { - fprintf(stderr, "Error %d occurred\n", ioErr); - exit(1); - } - else { - fprintf(stderr, "Publish handler done\n"); - } - publishPromise.set_value(); - }; - - UpdateJobExecutionRequest publishRequest; - publishRequest.ThingName = m_thingName; - publishRequest.JobId = jobId; - publishRequest.ExecutionNumber = currentExecutionNumber; - publishRequest.Status = jobStatus; - publishRequest.ExpectedVersion = currentVersionNumber++; - m_jobsClient->PublishUpdateJobExecution(publishRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, publishHandler); - - publishPromise.get_future().wait(); - m_pendingExecutionPromise.get_future().wait(); -} diff --git a/servicetests/tests/JobsExecution/JobsExecution.h b/servicetests/tests/JobsExecution/JobsExecution.h deleted file mode 100644 index e39940f67..000000000 --- a/servicetests/tests/JobsExecution/JobsExecution.h +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once - -/** - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0. - */ - -#include -#include - -#include - -class JobsExecution -{ - public: - JobsExecution(std::shared_ptr jobsClient, Aws::Crt::String thingName); - - Aws::Crt::Vector getAvailableJobs(); - - void describeJob(const Aws::Crt::String &jobId); - - void startNextPendingJob(); - - void updateCurrentJobStatus(Aws::Iotjobs::JobStatus jobStatus); - - private: - std::shared_ptr m_jobsClient; - const Aws::Crt::String m_thingName; - - Aws::Crt::Vector m_availableJobs; - std::mutex m_jobsMutex; - std::promise m_getResponse; - - Aws::Crt::String m_currentJobId; - int64_t m_currentExecutionNumber; - int32_t m_currentVersionNumber; - - std::promise m_pendingExecutionPromise; -}; diff --git a/servicetests/tests/JobsExecution/main.cpp b/servicetests/tests/JobsExecution/main.cpp index 175e55553..667f8e092 100644 --- a/servicetests/tests/JobsExecution/main.cpp +++ b/servicetests/tests/JobsExecution/main.cpp @@ -4,6 +4,7 @@ */ #include #include +#include #include #include @@ -25,15 +26,23 @@ #include #include +#include #include +#include +#include #include +#include #include "../../../samples/utils/CommandLineUtils.h" -#include "JobsExecution.h" using namespace Aws::Crt; using namespace Aws::Iotjobs; +void getAvailableJobs( + Aws::Crt::String thingName, + IotJobsClient &jobsClient, + std::vector &availableJobs); + std::shared_ptr build_mqtt3_client( Utils::cmdData &cmdData, std::shared_ptr &connection, @@ -76,12 +85,12 @@ std::shared_ptr build_mqtt3_client( auto onConnectionCompleted = [&](Mqtt::MqttConnection &, int errorCode, Mqtt::ReturnCode returnCode, bool) { if (errorCode) { - fprintf(stderr, "Connection failed with error %s\n", ErrorDebugString(errorCode)); + fprintf(stdout, "Connection failed with error %s\n", ErrorDebugString(errorCode)); connectionCompletedPromise.set_value(false); } else { - fprintf(stderr, "Connection completed with return code %d\n", returnCode); + fprintf(stdout, "Connection completed with return code %d\n", returnCode); connectionCompletedPromise.set_value(true); } }; @@ -89,7 +98,7 @@ std::shared_ptr build_mqtt3_client( // Invoked when a disconnect has been completed auto onDisconnect = [&](Mqtt::MqttConnection & /*conn*/) { { - fprintf(stderr, "Disconnect completed\n"); + fprintf(stdout, "Disconnect completed\n"); connectionClosedPromise.set_value(); } }; @@ -135,18 +144,18 @@ std::shared_ptr build_mqtt5_client( builder->WithClientConnectionSuccessCallback( [&connectionCompletedPromise](const Mqtt5::OnConnectionSuccessEventData &eventData) { fprintf( - stderr, + stdout, "Mqtt5 Client connection succeed, clientid: %s.\n", eventData.negotiatedSettings->getClientId().c_str()); connectionCompletedPromise.set_value(true); }); builder->WithClientConnectionFailureCallback([&connectionCompletedPromise]( const Mqtt5::OnConnectionFailureEventData &eventData) { - fprintf(stderr, "Mqtt5 Client connection failed with error: %s.\n", aws_error_debug_str(eventData.errorCode)); + fprintf(stdout, "Mqtt5 Client connection failed with error: %s.\n", aws_error_debug_str(eventData.errorCode)); connectionCompletedPromise.set_value(false); }); builder->WithClientStoppedCallback([&connectionClosedPromise](const Mqtt5::OnStoppedEventData &) { - fprintf(stderr, "Mqtt5 Client stopped.\n"); + fprintf(stdout, "Mqtt5 Client stopped.\n"); connectionClosedPromise.set_value(); }); @@ -154,7 +163,7 @@ std::shared_ptr build_mqtt5_client( if (client5 == nullptr) { fprintf( - stderr, "Failed to Init Mqtt5Client with error code %d: %s.\n", LastError(), ErrorDebugString(LastError())); + stdout, "Failed to Init Mqtt5Client with error code %d: %s.\n", LastError(), ErrorDebugString(LastError())); exit(-1); } @@ -168,7 +177,8 @@ std::shared_ptr build_mqtt5_client( int main(int argc, char *argv[]) { - fprintf(stderr, "Starting the jobs execution program\n"); + + fprintf(stdout, "Starting the jobs execution programm\n"); /************************ Setup ****************************/ // Do the global initialization for the API @@ -207,17 +217,231 @@ int main(int argc, char *argv[]) /************************ Run the sample ****************************/ if (connectionCompletedPromise.get_future().get()) { - JobsExecution jobsExecution(jobsClient, cmdData.input_thingName); - auto availableJobs = jobsExecution.getAvailableJobs(); - for (const auto &jobId : availableJobs) + std::vector availableJobs; + getAvailableJobs(cmdData.input_thingName, *jobsClient, availableJobs); + for (auto jobid : availableJobs) { - jobsExecution.describeJob(jobId); - } + DescribeJobExecutionSubscriptionRequest describeJobExecutionSubscriptionRequest; + describeJobExecutionSubscriptionRequest.ThingName = cmdData.input_thingName; + describeJobExecutionSubscriptionRequest.JobId = jobid; - for (size_t idx = 0; idx < availableJobs.size(); ++idx) - { - jobsExecution.startNextPendingJob(); - jobsExecution.updateCurrentJobStatus(Aws::Iotjobs::JobStatus::SUCCEEDED); + /** + * This isn't absolutely necessary but since we're doing a publish almost immediately afterwards, + * to be cautious make sure the subscribe has finished before doing the publish. + */ + std::promise subAckedPromise; + auto subAckHandler = [&](int) { + // if error code returns it will be recorded by the other callback + subAckedPromise.set_value(); + }; + auto subscriptionHandler = [&](DescribeJobExecutionResponse *response, int ioErr) { + if (ioErr) + { + fprintf(stderr, "Error %d occurred\n", ioErr); + return; + } + if (response) + { + fprintf(stdout, "Received Job:\n"); + fprintf(stdout, "Job Id: %s\n", response->Execution->JobId->c_str()); + fprintf(stdout, "ClientToken: %s\n", response->ClientToken->c_str()); + fprintf( + stdout, "Execution Status: %s\n", JobStatusMarshaller::ToString(*response->Execution->Status)); + } + }; + + jobsClient->SubscribeToDescribeJobExecutionAccepted( + describeJobExecutionSubscriptionRequest, + AWS_MQTT_QOS_AT_LEAST_ONCE, + subscriptionHandler, + subAckHandler); + subAckedPromise.get_future().wait(); + + subAckedPromise = std::promise(); + + auto failureHandler = [&](RejectedError *rejectedError, int ioErr) { + if (ioErr) + { + fprintf(stderr, "Error %d occurred\n", ioErr); + return; + } + if (rejectedError) + { + fprintf( + stderr, + "Service Error %d occurred. Message %s\n", + (int)rejectedError->Code.value(), + rejectedError->Message->c_str()); + return; + } + }; + + jobsClient->SubscribeToDescribeJobExecutionRejected( + describeJobExecutionSubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, failureHandler, subAckHandler); + subAckedPromise.get_future().wait(); + + DescribeJobExecutionRequest describeJobExecutionRequest; + describeJobExecutionRequest.ThingName = cmdData.input_thingName; + describeJobExecutionRequest.JobId = jobid; + describeJobExecutionRequest.IncludeJobDocument = true; + Aws::Crt::UUID uuid; + describeJobExecutionRequest.ClientToken = uuid.ToString(); + std::promise publishDescribeJobExeCompletedPromise; + + auto publishHandler = [&](int ioErr) { + if (ioErr) + { + fprintf(stderr, "Error %d occurred\n", ioErr); + exit(1); + } + publishDescribeJobExeCompletedPromise.set_value(); + }; + + jobsClient->PublishDescribeJobExecution( + std::move(describeJobExecutionRequest), AWS_MQTT_QOS_AT_LEAST_ONCE, publishHandler); + publishDescribeJobExeCompletedPromise.get_future().wait(); + + Aws::Crt::String currentJobId; + int64_t currentExecutionNumber; + int32_t currentVersionNumber; + + std::promise pendingExecutionPromise; + + { + auto OnSubscribeToStartNextPendingJobExecutionAcceptedResponse = + [&](StartNextJobExecutionResponse *response, int ioErr) { + if (ioErr) + { + fprintf(stderr, "Error %d occurred\n", ioErr); + exit(1); + } + if (response) + { + fprintf(stdout, "Start Job %s\n", response->Execution.value().JobId.value().c_str()); + currentJobId = response->Execution->JobId.value(); + currentExecutionNumber = response->Execution->ExecutionNumber.value(); + currentVersionNumber = response->Execution->VersionNumber.value(); + } + else + { + fprintf(stdout, "Could not get Job Id exiting\n"); + exit(-1); + } + + pendingExecutionPromise.set_value(); + }; + + StartNextPendingJobExecutionSubscriptionRequest subscriptionRequest; + subscriptionRequest.ThingName = cmdData.input_thingName; + subAckedPromise = std::promise(); + jobsClient->SubscribeToStartNextPendingJobExecutionAccepted( + subscriptionRequest, + AWS_MQTT_QOS_AT_LEAST_ONCE, + OnSubscribeToStartNextPendingJobExecutionAcceptedResponse, + subAckHandler); + + subAckedPromise.get_future().wait(); + + subAckedPromise = std::promise(); + jobsClient->SubscribeToStartNextPendingJobExecutionRejected( + subscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, failureHandler, subAckHandler); + + subAckedPromise.get_future().wait(); + + StartNextPendingJobExecutionRequest publishRequest; + publishRequest.ThingName = cmdData.input_thingName; + publishRequest.StepTimeoutInMinutes = 15L; + + publishDescribeJobExeCompletedPromise = std::promise(); + jobsClient->PublishStartNextPendingJobExecution( + publishRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, publishHandler); + + pendingExecutionPromise.get_future().wait(); + } + + { + pendingExecutionPromise = std::promise(); + auto OnSubscribeToUpdateJobExecutionAcceptedResponse = [&](UpdateJobExecutionResponse *response, + int ioErr) { + (void)response; + if (ioErr) + { + fprintf(stderr, "Error %d occurred\n", ioErr); + exit(1); + } + fprintf(stdout, "Marked Job %s IN_PROGRESS", currentJobId.c_str()); + pendingExecutionPromise.set_value(); + }; + UpdateJobExecutionSubscriptionRequest subscriptionRequest; + subscriptionRequest.ThingName = cmdData.input_thingName; + subscriptionRequest.JobId = currentJobId; + + subAckedPromise = std::promise(); + jobsClient->SubscribeToUpdateJobExecutionAccepted( + subscriptionRequest, + AWS_MQTT_QOS_AT_LEAST_ONCE, + OnSubscribeToUpdateJobExecutionAcceptedResponse, + subAckHandler); + subAckedPromise.get_future().wait(); + + subAckedPromise = std::promise(); + jobsClient->SubscribeToUpdateJobExecutionRejected( + subscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, failureHandler, subAckHandler); + subAckedPromise.get_future().wait(); + + publishDescribeJobExeCompletedPromise = std::promise(); + UpdateJobExecutionRequest publishRequest; + publishRequest.ThingName = cmdData.input_thingName; + publishRequest.JobId = currentJobId; + publishRequest.ExecutionNumber = currentExecutionNumber; + publishRequest.Status = JobStatus::IN_PROGRESS; + publishRequest.ExpectedVersion = currentVersionNumber++; + jobsClient->PublishUpdateJobExecution(publishRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, publishHandler); + + pendingExecutionPromise.get_future().wait(); + } + + // Pretend doing some work + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + + { + pendingExecutionPromise = std::promise(); + UpdateJobExecutionSubscriptionRequest subscriptionRequest; + subscriptionRequest.ThingName = cmdData.input_thingName; + subscriptionRequest.JobId = currentJobId; + + auto subscribeHandler = [&](UpdateJobExecutionResponse *response, int ioErr) { + (void)response; + if (ioErr) + { + fprintf(stderr, "Error %d occurred\n", ioErr); + exit(1); + } + fprintf(stdout, "Marked job %s currentJobId SUCCEEDED", currentJobId.c_str()); + pendingExecutionPromise.set_value(); + }; + subAckedPromise = std::promise(); + jobsClient->SubscribeToUpdateJobExecutionAccepted( + subscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, subscribeHandler, subAckHandler); + subAckedPromise.get_future().wait(); + + subAckedPromise = std::promise(); + jobsClient->SubscribeToUpdateJobExecutionRejected( + subscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, failureHandler, subAckHandler); + subAckedPromise.get_future().wait(); + + UpdateJobExecutionRequest publishRequest; + publishRequest.ThingName = cmdData.input_thingName; + publishRequest.JobId = currentJobId; + publishRequest.ExecutionNumber = currentExecutionNumber; + publishRequest.Status = JobStatus::SUCCEEDED; + publishRequest.ExpectedVersion = currentVersionNumber++; + + publishDescribeJobExeCompletedPromise = std::promise(); + jobsClient->PublishUpdateJobExecution(publishRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, publishHandler); + + pendingExecutionPromise.get_future().wait(); + } } } // Wait just a little bit to let the console print @@ -242,3 +466,100 @@ int main(int argc, char *argv[]) } return 0; } + +void getAvailableJobs( + Aws::Crt::String thingName, + IotJobsClient &jobsClient, + std::vector &availableJobs) +{ + std::promise getResponse; + std::promise publishDescribeJobExeCompletedPromise; + + GetPendingJobExecutionsSubscriptionRequest subscriptionRequest; + subscriptionRequest.ThingName = thingName; + + auto handler = [&](Aws::Iotjobs::GetPendingJobExecutionsResponse *response, int ioErr) { + fprintf(stderr, "running the jobs handler\n"); + if (ioErr) + { + fprintf(stderr, "Error %d occurred\n", ioErr); + exit(1); + } + if (response) + { + if (response->InProgressJobs.has_value()) + { + for (JobExecutionSummary job : response->InProgressJobs.value()) + { + availableJobs.push_back(job.JobId.value()); + fprintf(stderr, "In Progress jobs %s\n", job.JobId->c_str()); + } + } + else + { + fprintf(stderr, "In Progress jobs: empty\n"); + } + if (response->QueuedJobs.has_value()) + { + for (JobExecutionSummary job : response->QueuedJobs.value()) + { + availableJobs.push_back(job.JobId.value()); + fprintf(stderr, "Queued jobs %s\n", job.JobId->c_str()); + } + } + else + { + fprintf(stderr, "Queued jobs: empty\n"); + } + } + getResponse.set_value(); + }; + + auto err_handler = [&](Aws::Iotjobs::RejectedError *rejectedError, int ioErr) { + if (ioErr) + { + fprintf(stderr, "Error %d occurred\n", ioErr); + exit(1); + } + if (rejectedError) + { + fprintf( + stderr, + "Service Error %d occurred. Message %s\n", + (int)rejectedError->Code.value(), + rejectedError->Message->c_str()); + } + fprintf(stderr, "Error handler\n"); + exit(-1); + }; + + auto publishHandler = [&](int ioErr) { + if (ioErr) + { + fprintf(stderr, "Error %d occurred\n", ioErr); + exit(1); + } + publishDescribeJobExeCompletedPromise.set_value(); + }; + + jobsClient.SubscribeToGetPendingJobExecutionsAccepted( + subscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, handler, publishHandler); + publishDescribeJobExeCompletedPromise.get_future().wait(); + + publishDescribeJobExeCompletedPromise = std::promise(); + jobsClient.SubscribeToGetPendingJobExecutionsRejected( + subscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, err_handler, publishHandler); + publishDescribeJobExeCompletedPromise.get_future().wait(); + + publishDescribeJobExeCompletedPromise = std::promise(); + GetPendingJobExecutionsRequest publishRequest; + publishRequest.ThingName = thingName; + jobsClient.PublishGetPendingJobExecutions(publishRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, publishHandler); + publishDescribeJobExeCompletedPromise.get_future().wait(); + + if (getResponse.get_future().wait_for(std::chrono::seconds(10)) == std::future_status::timeout) + { + fprintf(stderr, "get available jobs error timedout\n"); + exit(-1); + } +} From 600076bc7518f313bef43da5b6dbe21887036f38 Mon Sep 17 00:00:00 2001 From: Igor Abdrakhimov Date: Fri, 3 May 2024 11:59:56 -0700 Subject: [PATCH 35/47] Enable sanitizers for service tests --- .../tests/FleetProvisioning/CMakeLists.txt | 16 ++++++++++++++++ servicetests/tests/JobsExecution/CMakeLists.txt | 16 ++++++++++++++++ servicetests/tests/ShadowUpdate/CMakeLists.txt | 16 ++++++++++++++++ 3 files changed, 48 insertions(+) diff --git a/servicetests/tests/FleetProvisioning/CMakeLists.txt b/servicetests/tests/FleetProvisioning/CMakeLists.txt index efcb43bdc..e01f57e42 100644 --- a/servicetests/tests/FleetProvisioning/CMakeLists.txt +++ b/servicetests/tests/FleetProvisioning/CMakeLists.txt @@ -25,4 +25,20 @@ find_package(IotIdentity-cpp REQUIRED) install(TARGETS ${PROJECT_NAME} DESTINATION bin) +if (UNIX AND NOT APPLE) + include(GNUInstallDirs) +elseif(NOT DEFINED CMAKE_INSTALL_LIBDIR) + set(CMAKE_INSTALL_LIBDIR "lib") + + if (${CMAKE_INSTALL_LIBDIR} STREQUAL "lib64") + set(FIND_LIBRARY_USE_LIB64_PATHS true) + endif() +endif() + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_PREFIX_PATH}/${CMAKE_INSTALL_LIBDIR}/cmake") + +include(AwsSanitizers) +enable_language(C) +aws_add_sanitizers(${PROJECT_NAME}) + target_link_libraries(${PROJECT_NAME} PRIVATE AWS::aws-crt-cpp AWS::IotIdentity-cpp) diff --git a/servicetests/tests/JobsExecution/CMakeLists.txt b/servicetests/tests/JobsExecution/CMakeLists.txt index 70577d337..64ffbea46 100644 --- a/servicetests/tests/JobsExecution/CMakeLists.txt +++ b/servicetests/tests/JobsExecution/CMakeLists.txt @@ -25,4 +25,20 @@ find_package(IotJobs-cpp REQUIRED) install(TARGETS ${PROJECT_NAME} DESTINATION bin) +if (UNIX AND NOT APPLE) + include(GNUInstallDirs) +elseif(NOT DEFINED CMAKE_INSTALL_LIBDIR) + set(CMAKE_INSTALL_LIBDIR "lib") + + if (${CMAKE_INSTALL_LIBDIR} STREQUAL "lib64") + set(FIND_LIBRARY_USE_LIB64_PATHS true) + endif() +endif() + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_PREFIX_PATH}/${CMAKE_INSTALL_LIBDIR}/cmake") + +include(AwsSanitizers) +enable_language(C) +aws_add_sanitizers(${PROJECT_NAME}) + target_link_libraries(${PROJECT_NAME} PRIVATE AWS::aws-crt-cpp AWS::IotJobs-cpp) diff --git a/servicetests/tests/ShadowUpdate/CMakeLists.txt b/servicetests/tests/ShadowUpdate/CMakeLists.txt index 3e10518c6..7a87b4856 100644 --- a/servicetests/tests/ShadowUpdate/CMakeLists.txt +++ b/servicetests/tests/ShadowUpdate/CMakeLists.txt @@ -25,4 +25,20 @@ find_package(IotShadow-cpp REQUIRED) install(TARGETS ${PROJECT_NAME} DESTINATION bin) +if (UNIX AND NOT APPLE) + include(GNUInstallDirs) +elseif(NOT DEFINED CMAKE_INSTALL_LIBDIR) + set(CMAKE_INSTALL_LIBDIR "lib") + + if (${CMAKE_INSTALL_LIBDIR} STREQUAL "lib64") + set(FIND_LIBRARY_USE_LIB64_PATHS true) + endif() +endif() + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_PREFIX_PATH}/${CMAKE_INSTALL_LIBDIR}/cmake") + +include(AwsSanitizers) +enable_language(C) +aws_add_sanitizers(${PROJECT_NAME}) + target_link_libraries(${PROJECT_NAME} PRIVATE AWS::aws-crt-cpp AWS::IotShadow-cpp) From 48331ee25edf3c989059c56ac53acd0d96017e73 Mon Sep 17 00:00:00 2001 From: Igor Abdrakhimov Date: Wed, 10 Jul 2024 10:01:32 -0700 Subject: [PATCH 36/47] Fix typo in cmake args --- builder.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builder.json b/builder.json index d7778a2ec..f1b1b3787 100644 --- a/builder.json +++ b/builder.json @@ -38,7 +38,7 @@ "asan": { "cmake_args": [ "-DENABLE_SANITIZERS=ON", - "-DSANTIIZERS=address,undefined" + "-DSANITIZERS=address,undefined" ] }, "build_gg_samples_only": { From 20526fd6142dc01dda3c1cea2f7ddb6ae5f1630b Mon Sep 17 00:00:00 2001 From: Igor Abdrakhimov Date: Thu, 11 Jul 2024 15:07:33 -0700 Subject: [PATCH 37/47] Use promises to sync fleet provisioning sample --- .../fleet_provisioning/main.cpp | 640 +++++++++--------- 1 file changed, 317 insertions(+), 323 deletions(-) diff --git a/samples/fleet_provisioning/fleet_provisioning/main.cpp b/samples/fleet_provisioning/fleet_provisioning/main.cpp index 3fb3d55c4..77798caf9 100644 --- a/samples/fleet_provisioning/fleet_provisioning/main.cpp +++ b/samples/fleet_provisioning/fleet_provisioning/main.cpp @@ -4,8 +4,6 @@ */ #include #include -#include -#include #include @@ -21,29 +19,12 @@ #include #include -#include -#include -#include #include -#include -#include -#include -#include -#include -#include #include "../../utils/CommandLineUtils.h" using namespace Aws::Crt; using namespace Aws::Iotidentity; -using namespace std::this_thread; // sleep_for, sleep_until -using namespace std::chrono; // nanoseconds, system_clock, seconds - -static void sleep(int sleeptime) -{ - std::cout << "Sleeping for " << sleeptime << " seconds..." << std::endl; - sleep_until(system_clock::now() + seconds(sleeptime)); -} static std::string getFileData(std::string const &fileName) { @@ -78,7 +59,7 @@ int main(int argc, char *argv[]) /** * In a real world application you probably don't want to enforce synchronous behavior - * but this is a sample console application, so we'll just do that with a condition variable. + * but this is a sample console application, so we'll just do that with a promise. */ std::promise connectionCompletedPromise; std::promise connectionClosedPromise; @@ -147,321 +128,334 @@ int main(int argc, char *argv[]) exit(-1); } - if (connectionCompletedPromise.get_future().get()) + if (!connectionCompletedPromise.get_future().get()) { - IotIdentityClient identityClient(connection); - - std::promise csrPublishCompletedPromise; - std::promise csrAcceptedCompletedPromise; - std::promise csrRejectedCompletedPromise; - - std::promise keysPublishCompletedPromise; - std::promise keysAcceptedCompletedPromise; - std::promise keysRejectedCompletedPromise; - - std::promise registerPublishCompletedPromise; - std::promise registerAcceptedCompletedPromise; - std::promise registerRejectedCompletedPromise; - - auto onCsrPublishSubAck = [&](int ioErr) { - if (ioErr != AWS_OP_SUCCESS) - { - fprintf(stderr, "Error publishing to CreateCertificateFromCsr: %s\n", ErrorDebugString(ioErr)); - exit(-1); - } - - csrPublishCompletedPromise.set_value(); - }; - - auto onCsrAcceptedSubAck = [&](int ioErr) { - if (ioErr != AWS_OP_SUCCESS) - { - fprintf( - stderr, "Error subscribing to CreateCertificateFromCsr accepted: %s\n", ErrorDebugString(ioErr)); - exit(-1); - } + return -1; + } + + IotIdentityClient identityClient(connection); + + /* + * Use promises to enforce synchronous behavior, so it's easier to follow the workflow. + */ + std::promise csrPublishPubAckCompletedPromise; + std::promise csrAcceptedSubAckCompletedPromise; + std::promise csrRejectedSubAckCompletedPromise; + std::promise csrAcceptedCompletedPromise; + + std::promise keysPublishPubAckCompletedPromise; + std::promise keysAcceptedSubAckCompletedPromise; + std::promise keysRejectedSubAckCompletedPromise; + std::promise keysAcceptedCompletedPromise; + + std::promise registerPublishPubAckCompletedPromise; + std::promise registerAcceptedSubAckCompletedPromise; + std::promise registerRejectedSubAckCompletedPromise; + std::promise registerAcceptedCompletedPromise; + + auto onCsrPublishPubAck = [&](int ioErr) { + if (ioErr != AWS_OP_SUCCESS) + { + fprintf(stderr, "Error publishing to CreateCertificateFromCsr: %s\n", ErrorDebugString(ioErr)); + exit(-1); + } + csrPublishPubAckCompletedPromise.set_value(); + }; + + auto onCsrAcceptedSubAck = [&](int ioErr) { + if (ioErr != AWS_OP_SUCCESS) + { + fprintf(stderr, "Error subscribing to CreateCertificateFromCsr accepted: %s\n", ErrorDebugString(ioErr)); + exit(-1); + } + csrAcceptedSubAckCompletedPromise.set_value(); + }; + + auto onCsrRejectedSubAck = [&](int ioErr) { + if (ioErr != AWS_OP_SUCCESS) + { + fprintf(stderr, "Error subscribing to CreateCertificateFromCsr rejected: %s\n", ErrorDebugString(ioErr)); + exit(-1); + } + csrRejectedSubAckCompletedPromise.set_value(); + }; + auto onCsrAccepted = [&](CreateCertificateFromCsrResponse *response, int ioErr) { + if (ioErr == AWS_OP_SUCCESS) + { + fprintf(stdout, "CreateCertificateFromCsrResponse certificateId: %s.\n", response->CertificateId->c_str()); + token = *response->CertificateOwnershipToken; csrAcceptedCompletedPromise.set_value(); - }; - - auto onCsrRejectedSubAck = [&](int ioErr) { - if (ioErr != AWS_OP_SUCCESS) - { - fprintf( - stderr, "Error subscribing to CreateCertificateFromCsr rejected: %s\n", ErrorDebugString(ioErr)); - exit(-1); - } - csrRejectedCompletedPromise.set_value(); - }; - - auto onCsrAccepted = [&](CreateCertificateFromCsrResponse *response, int ioErr) { - if (ioErr == AWS_OP_SUCCESS) - { - fprintf( - stdout, "CreateCertificateFromCsrResponse certificateId: %s.\n", response->CertificateId->c_str()); - token = *response->CertificateOwnershipToken; - } - else - { - fprintf(stderr, "Error on subscription: %s.\n", ErrorDebugString(ioErr)); - exit(-1); - } - }; - - auto onCsrRejected = [&](ErrorResponse *error, int ioErr) { - if (ioErr == AWS_OP_SUCCESS) - { - fprintf( - stdout, - "CreateCertificateFromCsr failed with statusCode %d, errorMessage %s and errorCode %s.", - *error->StatusCode, - error->ErrorMessage->c_str(), - error->ErrorCode->c_str()); - exit(-1); - } - else - { - fprintf(stderr, "Error on subscription: %s.\n", ErrorDebugString(ioErr)); - exit(-1); - } - }; - - auto onKeysPublishSubAck = [&](int ioErr) { - if (ioErr != AWS_OP_SUCCESS) - { - fprintf(stderr, "Error publishing to CreateKeysAndCertificate: %s\n", ErrorDebugString(ioErr)); - exit(-1); - } - - keysPublishCompletedPromise.set_value(); - }; - - auto onKeysAcceptedSubAck = [&](int ioErr) { - if (ioErr != AWS_OP_SUCCESS) - { - fprintf( - stderr, "Error subscribing to CreateKeysAndCertificate accepted: %s\n", ErrorDebugString(ioErr)); - exit(-1); - } + } + else + { + fprintf(stderr, "Error on subscription: %s.\n", ErrorDebugString(ioErr)); + exit(-1); + } + }; + auto onCsrRejected = [&](ErrorResponse *error, int ioErr) { + if (ioErr == AWS_OP_SUCCESS) + { + fprintf( + stdout, + "CreateCertificateFromCsr failed with statusCode %d, errorMessage %s and errorCode %s.", + *error->StatusCode, + error->ErrorMessage->c_str(), + error->ErrorCode->c_str()); + exit(-1); + } + else + { + fprintf(stderr, "Error on subscription: %s.\n", ErrorDebugString(ioErr)); + exit(-1); + } + }; + + auto onKeysPublishPubAck = [&](int ioErr) { + if (ioErr != AWS_OP_SUCCESS) + { + fprintf(stderr, "Error publishing to CreateKeysAndCertificate: %s\n", ErrorDebugString(ioErr)); + exit(-1); + } + + keysPublishPubAckCompletedPromise.set_value(); + }; + + auto onKeysAcceptedSubAck = [&](int ioErr) { + if (ioErr != AWS_OP_SUCCESS) + { + fprintf(stderr, "Error subscribing to CreateKeysAndCertificate accepted: %s\n", ErrorDebugString(ioErr)); + exit(-1); + } + + keysAcceptedSubAckCompletedPromise.set_value(); + }; + + auto onKeysRejectedSubAck = [&](int ioErr) { + if (ioErr != AWS_OP_SUCCESS) + { + fprintf(stderr, "Error subscribing to CreateKeysAndCertificate rejected: %s\n", ErrorDebugString(ioErr)); + exit(-1); + } + keysRejectedSubAckCompletedPromise.set_value(); + }; + + auto onKeysAccepted = [&](CreateKeysAndCertificateResponse *response, int ioErr) { + if (ioErr == AWS_OP_SUCCESS) + { + fprintf(stdout, "CreateKeysAndCertificateResponse certificateId: %s.\n", response->CertificateId->c_str()); + token = *response->CertificateOwnershipToken; keysAcceptedCompletedPromise.set_value(); - }; - - auto onKeysRejectedSubAck = [&](int ioErr) { - if (ioErr != AWS_OP_SUCCESS) - { - fprintf( - stderr, "Error subscribing to CreateKeysAndCertificate rejected: %s\n", ErrorDebugString(ioErr)); - exit(-1); - } - keysRejectedCompletedPromise.set_value(); - }; - - auto onKeysAccepted = [&](CreateKeysAndCertificateResponse *response, int ioErr) { - if (ioErr == AWS_OP_SUCCESS) - { - fprintf( - stdout, "CreateKeysAndCertificateResponse certificateId: %s.\n", response->CertificateId->c_str()); - token = *response->CertificateOwnershipToken; - } - else - { - fprintf(stderr, "Error on subscription: %s.\n", ErrorDebugString(ioErr)); - exit(-1); - } - }; - - auto onKeysRejected = [&](ErrorResponse *error, int ioErr) { - if (ioErr == AWS_OP_SUCCESS) - { - fprintf( - stdout, - "CreateKeysAndCertificate failed with statusCode %d, errorMessage %s and errorCode %s.", - *error->StatusCode, - error->ErrorMessage->c_str(), - error->ErrorCode->c_str()); - exit(-1); - } - else - { - fprintf(stderr, "Error on subscription: %s.\n", ErrorDebugString(ioErr)); - exit(-1); - } - }; - - auto onRegisterAcceptedSubAck = [&](int ioErr) { - if (ioErr != AWS_OP_SUCCESS) - { - fprintf(stderr, "Error subscribing to RegisterThing accepted: %s\n", ErrorDebugString(ioErr)); - exit(-1); - } + } + else + { + fprintf(stderr, "Error on subscription: %s.\n", ErrorDebugString(ioErr)); + exit(-1); + } + }; + + auto onKeysRejected = [&](ErrorResponse *error, int ioErr) { + if (ioErr == AWS_OP_SUCCESS) + { + fprintf( + stdout, + "CreateKeysAndCertificate failed with statusCode %d, errorMessage %s and errorCode %s.", + *error->StatusCode, + error->ErrorMessage->c_str(), + error->ErrorCode->c_str()); + exit(-1); + } + else + { + fprintf(stderr, "Error on subscription: %s.\n", ErrorDebugString(ioErr)); + exit(-1); + } + }; + + auto onRegisterAcceptedSubAck = [&](int ioErr) { + if (ioErr != AWS_OP_SUCCESS) + { + fprintf(stderr, "Error subscribing to RegisterThing accepted: %s\n", ErrorDebugString(ioErr)); + exit(-1); + } + + registerAcceptedSubAckCompletedPromise.set_value(); + }; + + auto onRegisterRejectedSubAck = [&](int ioErr) { + if (ioErr != AWS_OP_SUCCESS) + { + fprintf(stderr, "Error subscribing to RegisterThing rejected: %s\n", ErrorDebugString(ioErr)); + exit(-1); + } + registerRejectedSubAckCompletedPromise.set_value(); + }; + auto onRegisterAccepted = [&](RegisterThingResponse *response, int ioErr) { + if (ioErr == AWS_OP_SUCCESS) + { + fprintf(stdout, "RegisterThingResponse ThingName: %s.\n", response->ThingName->c_str()); registerAcceptedCompletedPromise.set_value(); - }; - - auto onRegisterRejectedSubAck = [&](int ioErr) { - if (ioErr != AWS_OP_SUCCESS) - { - fprintf(stderr, "Error subscribing to RegisterThing rejected: %s\n", ErrorDebugString(ioErr)); - exit(-1); - } - registerRejectedCompletedPromise.set_value(); - }; - - auto onRegisterAccepted = [&](RegisterThingResponse *response, int ioErr) { - if (ioErr == AWS_OP_SUCCESS) - { - fprintf(stdout, "RegisterThingResponse ThingName: %s.\n", response->ThingName->c_str()); - } - else - { - fprintf(stderr, "Error on subscription: %s.\n", ErrorDebugString(ioErr)); - exit(-1); - } - }; - - auto onRegisterRejected = [&](ErrorResponse *error, int ioErr) { - if (ioErr == AWS_OP_SUCCESS) - { - fprintf( - stdout, - "RegisterThing failed with statusCode %d, errorMessage %s and errorCode %s.", - *error->StatusCode, - error->ErrorMessage->c_str(), - error->ErrorCode->c_str()); - } - else - { - fprintf(stderr, "Error on subscription: %s.\n", ErrorDebugString(ioErr)); - exit(-1); - } - }; - - auto onRegisterPublishSubAck = [&](int ioErr) { - if (ioErr != AWS_OP_SUCCESS) - { - fprintf(stderr, "Error publishing to RegisterThing: %s\n", ErrorDebugString(ioErr)); - exit(-1); - } - - registerPublishCompletedPromise.set_value(); - }; - - if (csrFile.empty()) + } + else { - // CreateKeysAndCertificate workflow - std::cout << "Subscribing to CreateKeysAndCertificate Accepted and Rejected topics" << std::endl; - CreateKeysAndCertificateSubscriptionRequest keySubscriptionRequest; - identityClient.SubscribeToCreateKeysAndCertificateAccepted( - keySubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onKeysAccepted, onKeysAcceptedSubAck); - - identityClient.SubscribeToCreateKeysAndCertificateRejected( - keySubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onKeysRejected, onKeysRejectedSubAck); - - std::cout << "Publishing to CreateKeysAndCertificate topic" << std::endl; - CreateKeysAndCertificateRequest createKeysAndCertificateRequest; - identityClient.PublishCreateKeysAndCertificate( - createKeysAndCertificateRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onKeysPublishSubAck); - - std::cout << "Subscribing to RegisterThing Accepted and Rejected topics" << std::endl; - RegisterThingSubscriptionRequest registerSubscriptionRequest; - registerSubscriptionRequest.TemplateName = cmdData.input_templateName; - - identityClient.SubscribeToRegisterThingAccepted( - registerSubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onRegisterAccepted, onRegisterAcceptedSubAck); - - identityClient.SubscribeToRegisterThingRejected( - registerSubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onRegisterRejected, onRegisterRejectedSubAck); - - sleep(1); - - std::cout << "Publishing to RegisterThing topic" << std::endl; - RegisterThingRequest registerThingRequest; - registerThingRequest.TemplateName = cmdData.input_templateName; - - const Aws::Crt::String jsonValue = cmdData.input_templateParameters; - Aws::Crt::JsonObject value(jsonValue); - Map pm = value.View().GetAllObjects(); - Aws::Crt::Map params = - Aws::Crt::Map(); - - for (const auto &x : pm) - { - params.emplace(x.first, x.second.AsString()); - } - - registerThingRequest.Parameters = params; - registerThingRequest.CertificateOwnershipToken = token; - - identityClient.PublishRegisterThing( - registerThingRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onRegisterPublishSubAck); - sleep(1); - - keysPublishCompletedPromise.get_future().wait(); - keysAcceptedCompletedPromise.get_future().wait(); - keysRejectedCompletedPromise.get_future().wait(); - registerPublishCompletedPromise.get_future().wait(); - registerAcceptedCompletedPromise.get_future().wait(); - registerRejectedCompletedPromise.get_future().wait(); + fprintf(stderr, "Error on subscription: %s.\n", ErrorDebugString(ioErr)); + exit(-1); + } + }; + + auto onRegisterRejected = [&](ErrorResponse *error, int ioErr) { + if (ioErr == AWS_OP_SUCCESS) + { + fprintf( + stdout, + "RegisterThing failed with statusCode %d, errorMessage %s and errorCode %s.", + *error->StatusCode, + error->ErrorMessage->c_str(), + error->ErrorCode->c_str()); } else { - // CreateCertificateFromCsr workflow - std::cout << "Subscribing to CreateCertificateFromCsr Accepted and Rejected topics" << std::endl; - CreateCertificateFromCsrSubscriptionRequest csrSubscriptionRequest; - identityClient.SubscribeToCreateCertificateFromCsrAccepted( - csrSubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onCsrAccepted, onCsrAcceptedSubAck); - - identityClient.SubscribeToCreateCertificateFromCsrRejected( - csrSubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onCsrRejected, onCsrRejectedSubAck); - - std::cout << "Publishing to CreateCertificateFromCsr topic" << std::endl; - CreateCertificateFromCsrRequest createCertificateFromCsrRequest; - createCertificateFromCsrRequest.CertificateSigningRequest = csrFile; - identityClient.PublishCreateCertificateFromCsr( - createCertificateFromCsrRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onCsrPublishSubAck); - - std::cout << "Subscribing to RegisterThing Accepted and Rejected topics" << std::endl; - RegisterThingSubscriptionRequest registerSubscriptionRequest; - registerSubscriptionRequest.TemplateName = cmdData.input_templateName; - - identityClient.SubscribeToRegisterThingAccepted( - registerSubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onRegisterAccepted, onRegisterAcceptedSubAck); - - identityClient.SubscribeToRegisterThingRejected( - registerSubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onRegisterRejected, onRegisterRejectedSubAck); - - sleep(2); - - std::cout << "Publishing to RegisterThing topic" << std::endl; - RegisterThingRequest registerThingRequest; - registerThingRequest.TemplateName = cmdData.input_templateName; - - const Aws::Crt::String jsonValue = cmdData.input_templateParameters; - Aws::Crt::JsonObject value(jsonValue); - Map pm = value.View().GetAllObjects(); - Aws::Crt::Map params = - Aws::Crt::Map(); - - for (const auto &x : pm) - { - params.emplace(x.first, x.second.AsString()); - } - - registerThingRequest.Parameters = params; - registerThingRequest.CertificateOwnershipToken = token; - - identityClient.PublishRegisterThing( - registerThingRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onRegisterPublishSubAck); - sleep(2); - - csrPublishCompletedPromise.get_future().wait(); - csrAcceptedCompletedPromise.get_future().wait(); - csrRejectedCompletedPromise.get_future().wait(); - registerPublishCompletedPromise.get_future().wait(); - registerAcceptedCompletedPromise.get_future().wait(); - registerRejectedCompletedPromise.get_future().wait(); + fprintf(stderr, "Error on subscription: %s.\n", ErrorDebugString(ioErr)); + exit(-1); + } + }; + + auto onRegisterPublishPubAck = [&](int ioErr) { + if (ioErr != AWS_OP_SUCCESS) + { + fprintf(stderr, "Error publishing to RegisterThing: %s\n", ErrorDebugString(ioErr)); + exit(-1); + } + + registerPublishPubAckCompletedPromise.set_value(); + }; + + if (csrFile.empty()) + { + // CreateKeysAndCertificate workflow + fprintf(stdout, "Subscribing to CreateKeysAndCertificate Accepted and Rejected topics\n"); + CreateKeysAndCertificateSubscriptionRequest keySubscriptionRequest; + identityClient.SubscribeToCreateKeysAndCertificateAccepted( + keySubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onKeysAccepted, onKeysAcceptedSubAck); + identityClient.SubscribeToCreateKeysAndCertificateRejected( + keySubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onKeysRejected, onKeysRejectedSubAck); + + // Wait for the subscriptions to the accept and reject key/certificates topics to be established. + keysAcceptedSubAckCompletedPromise.get_future().wait(); + keysRejectedSubAckCompletedPromise.get_future().wait(); + + // Now, when we subscribed to the keys and certificates topics, we can make a request for a certificate. + fprintf(stdout, "Publishing to CreateKeysAndCertificate topic\n"); + CreateKeysAndCertificateRequest createKeysAndCertificateRequest; + identityClient.PublishCreateKeysAndCertificate( + createKeysAndCertificateRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onKeysPublishPubAck); + keysPublishPubAckCompletedPromise.get_future().wait(); + + // Wait for a certificate token. + keysAcceptedCompletedPromise.get_future().wait(); + + fprintf(stdout, "Subscribing to RegisterThing Accepted and Rejected topics\n"); + RegisterThingSubscriptionRequest registerSubscriptionRequest; + registerSubscriptionRequest.TemplateName = cmdData.input_templateName; + + identityClient.SubscribeToRegisterThingAccepted( + registerSubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onRegisterAccepted, onRegisterAcceptedSubAck); + + identityClient.SubscribeToRegisterThingRejected( + registerSubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onRegisterRejected, onRegisterRejectedSubAck); + + // Wait for the subscriptions to the accept and reject RegisterThing topics to be established. + registerAcceptedSubAckCompletedPromise.get_future().wait(); + registerRejectedSubAckCompletedPromise.get_future().wait(); + + fprintf(stdout, "Publishing to RegisterThing topic\n"); + RegisterThingRequest registerThingRequest; + registerThingRequest.TemplateName = cmdData.input_templateName; + + const Aws::Crt::String jsonValue = cmdData.input_templateParameters; + Aws::Crt::JsonObject value(jsonValue); + Map pm = value.View().GetAllObjects(); + Aws::Crt::Map params = Aws::Crt::Map(); + + for (const auto &x : pm) + { + params.emplace(x.first, x.second.AsString()); } + + registerThingRequest.Parameters = params; + registerThingRequest.CertificateOwnershipToken = token; + + identityClient.PublishRegisterThing(registerThingRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onRegisterPublishPubAck); + registerPublishPubAckCompletedPromise.get_future().wait(); + + // Wait for registering a thing to succeed. + registerAcceptedCompletedPromise.get_future().wait(); + } + else + { + // CreateCertificateFromCsr workflow + fprintf(stdout, "Subscribing to CreateCertificateFromCsr Accepted and Rejected topics\n"); + CreateCertificateFromCsrSubscriptionRequest csrSubscriptionRequest; + identityClient.SubscribeToCreateCertificateFromCsrAccepted( + csrSubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onCsrAccepted, onCsrAcceptedSubAck); + + identityClient.SubscribeToCreateCertificateFromCsrRejected( + csrSubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onCsrRejected, onCsrRejectedSubAck); + + // Wait for the subscriptions to the accept and reject certificates topics to be established. + csrAcceptedSubAckCompletedPromise.get_future().wait(); + csrRejectedSubAckCompletedPromise.get_future().wait(); + + // Now, when we subscribed to the certificates topics, we can make a request for a certificate. + fprintf(stdout, "Publishing to CreateCertificateFromCsr topic\n"); + CreateCertificateFromCsrRequest createCertificateFromCsrRequest; + createCertificateFromCsrRequest.CertificateSigningRequest = csrFile; + identityClient.PublishCreateCertificateFromCsr( + createCertificateFromCsrRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onCsrPublishPubAck); + csrPublishPubAckCompletedPromise.get_future().wait(); + + // Wait for a certificate token. + csrAcceptedCompletedPromise.get_future().wait(); + + fprintf(stdout, "Subscribing to RegisterThing Accepted and Rejected topics\n"); + RegisterThingSubscriptionRequest registerSubscriptionRequest; + registerSubscriptionRequest.TemplateName = cmdData.input_templateName; + + identityClient.SubscribeToRegisterThingAccepted( + registerSubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onRegisterAccepted, onRegisterAcceptedSubAck); + + identityClient.SubscribeToRegisterThingRejected( + registerSubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onRegisterRejected, onRegisterRejectedSubAck); + + // Wait for the subscriptions to the accept and reject RegisterThing topics to be established. + registerAcceptedSubAckCompletedPromise.get_future().wait(); + registerRejectedSubAckCompletedPromise.get_future().wait(); + + fprintf(stdout, "Publishing to RegisterThing topic\n"); + RegisterThingRequest registerThingRequest; + registerThingRequest.TemplateName = cmdData.input_templateName; + + const Aws::Crt::String jsonValue = cmdData.input_templateParameters; + Aws::Crt::JsonObject value(jsonValue); + Map pm = value.View().GetAllObjects(); + Aws::Crt::Map params = Aws::Crt::Map(); + + for (const auto &x : pm) + { + params.emplace(x.first, x.second.AsString()); + } + + registerThingRequest.Parameters = params; + registerThingRequest.CertificateOwnershipToken = token; + + identityClient.PublishRegisterThing(registerThingRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onRegisterPublishPubAck); + + registerPublishPubAckCompletedPromise.get_future().wait(); + + // Wait for registering a thing to succeed. + registerAcceptedCompletedPromise.get_future().wait(); } // Disconnect From b6492d71a22be63ca7725766a13cbc0cc12694c5 Mon Sep 17 00:00:00 2001 From: Igor Abdrakhimov Date: Thu, 11 Jul 2024 15:17:00 -0700 Subject: [PATCH 38/47] Use promises to sync mqtt5 fleet provisioning sample --- .../mqtt5_fleet_provisioning/main.cpp | 646 +++++++++--------- 1 file changed, 320 insertions(+), 326 deletions(-) diff --git a/samples/fleet_provisioning/mqtt5_fleet_provisioning/main.cpp b/samples/fleet_provisioning/mqtt5_fleet_provisioning/main.cpp index 994d83a56..1fecd4c9d 100644 --- a/samples/fleet_provisioning/mqtt5_fleet_provisioning/main.cpp +++ b/samples/fleet_provisioning/mqtt5_fleet_provisioning/main.cpp @@ -22,29 +22,12 @@ #include #include -#include -#include -#include #include -#include -#include -#include -#include -#include -#include #include "../../utils/CommandLineUtils.h" using namespace Aws::Crt; using namespace Aws::Iotidentity; -using namespace std::this_thread; // sleep_for, sleep_until -using namespace std::chrono; // nanoseconds, system_clock, seconds - -static void sleep(int sleeptime) -{ - std::cout << "Sleeping for " << sleeptime << " seconds..." << std::endl; - sleep_until(system_clock::now() + seconds(sleeptime)); -} static std::string getFileData(std::string const &fileName) { @@ -141,321 +124,332 @@ int main(int argc, char *argv[]) exit(-1); } - if (connectionPromise.get_future().get()) + if (!connectionPromise.get_future().get()) { - IotIdentityClient identityClient(client); - - std::promise csrPublishCompletedPromise; - std::promise csrAcceptedCompletedPromise; - std::promise csrRejectedCompletedPromise; - - std::promise keysPublishCompletedPromise; - std::promise keysAcceptedCompletedPromise; - std::promise keysRejectedCompletedPromise; - - std::promise registerPublishCompletedPromise; - std::promise registerAcceptedCompletedPromise; - std::promise registerRejectedCompletedPromise; - - auto onCsrPublishSubAck = [&](int ioErr) { - if (ioErr != AWS_OP_SUCCESS) - { - fprintf(stderr, "Error publishing to CreateCertificateFromCsr: %s\n", ErrorDebugString(ioErr)); - exit(-1); - } - - csrPublishCompletedPromise.set_value(); - }; - - auto onCsrAcceptedSubAck = [&](int ioErr) { - if (ioErr != AWS_OP_SUCCESS) - { - fprintf( - stderr, "Error subscribing to CreateCertificateFromCsr accepted: %s\n", ErrorDebugString(ioErr)); - exit(-1); - } - - csrAcceptedCompletedPromise.set_value(); - }; - - auto onCsrRejectedSubAck = [&](int ioErr) { - if (ioErr != AWS_OP_SUCCESS) - { - fprintf( - stderr, "Error subscribing to CreateCertificateFromCsr rejected: %s\n", ErrorDebugString(ioErr)); - exit(-1); - } - csrRejectedCompletedPromise.set_value(); - }; - - auto onCsrAccepted = [&](CreateCertificateFromCsrResponse *response, int ioErr) { - if (ioErr == AWS_OP_SUCCESS) - { - fprintf( - stdout, "CreateCertificateFromCsrResponse certificateId: %s.\n", response->CertificateId->c_str()); - token = *response->CertificateOwnershipToken; - } - else - { - fprintf(stderr, "Error on subscription: %s.\n", ErrorDebugString(ioErr)); - exit(-1); - } - }; - - auto onCsrRejected = [&](ErrorResponse *error, int ioErr) { - if (ioErr == AWS_OP_SUCCESS) - { - fprintf( - stdout, - "CreateCertificateFromCsr failed with statusCode %d, errorMessage %s and errorCode %s.", - *error->StatusCode, - error->ErrorMessage->c_str(), - error->ErrorCode->c_str()); - exit(-1); - } - else - { - fprintf(stderr, "Error on subscription: %s.\n", ErrorDebugString(ioErr)); - exit(-1); - } - }; - - auto onKeysPublishSubAck = [&](int ioErr) { - if (ioErr != AWS_OP_SUCCESS) - { - fprintf(stderr, "Error publishing to CreateKeysAndCertificate: %s\n", ErrorDebugString(ioErr)); - exit(-1); - } - - keysPublishCompletedPromise.set_value(); - }; - - auto onKeysAcceptedSubAck = [&](int ioErr) { - if (ioErr != AWS_OP_SUCCESS) - { - fprintf( - stderr, "Error subscribing to CreateKeysAndCertificate accepted: %s\n", ErrorDebugString(ioErr)); - exit(-1); - } - - keysAcceptedCompletedPromise.set_value(); - }; - - auto onKeysRejectedSubAck = [&](int ioErr) { - if (ioErr != AWS_OP_SUCCESS) - { - fprintf( - stderr, "Error subscribing to CreateKeysAndCertificate rejected: %s\n", ErrorDebugString(ioErr)); - exit(-1); - } - keysRejectedCompletedPromise.set_value(); - }; - - auto onKeysAccepted = [&](CreateKeysAndCertificateResponse *response, int ioErr) { - if (ioErr == AWS_OP_SUCCESS) - { - fprintf( - stdout, "CreateKeysAndCertificateResponse certificateId: %s.\n", response->CertificateId->c_str()); - token = *response->CertificateOwnershipToken; - } - else - { - fprintf(stderr, "Error on subscription: %s.\n", ErrorDebugString(ioErr)); - exit(-1); - } - }; - - auto onKeysRejected = [&](ErrorResponse *error, int ioErr) { - if (ioErr == AWS_OP_SUCCESS) - { - fprintf( - stdout, - "CreateKeysAndCertificate failed with statusCode %d, errorMessage %s and errorCode %s.", - *error->StatusCode, - error->ErrorMessage->c_str(), - error->ErrorCode->c_str()); - exit(-1); - } - else - { - fprintf(stderr, "Error on subscription: %s.\n", ErrorDebugString(ioErr)); - exit(-1); - } - }; - - auto onRegisterAcceptedSubAck = [&](int ioErr) { - if (ioErr != AWS_OP_SUCCESS) - { - fprintf(stderr, "Error subscribing to RegisterThing accepted: %s\n", ErrorDebugString(ioErr)); - exit(-1); - } - - registerAcceptedCompletedPromise.set_value(); - }; - - auto onRegisterRejectedSubAck = [&](int ioErr) { - if (ioErr != AWS_OP_SUCCESS) - { - fprintf(stderr, "Error subscribing to RegisterThing rejected: %s\n", ErrorDebugString(ioErr)); - exit(-1); - } - registerRejectedCompletedPromise.set_value(); - }; - - auto onRegisterAccepted = [&](RegisterThingResponse *response, int ioErr) { - if (ioErr == AWS_OP_SUCCESS) - { - fprintf(stdout, "RegisterThingResponse ThingName: %s.\n", response->ThingName->c_str()); - } - else - { - fprintf(stderr, "Error on subscription: %s.\n", ErrorDebugString(ioErr)); - exit(-1); - } - }; - - auto onRegisterRejected = [&](ErrorResponse *error, int ioErr) { - if (ioErr == AWS_OP_SUCCESS) - { - fprintf( - stdout, - "RegisterThing failed with statusCode %d, errorMessage %s and errorCode %s.", - *error->StatusCode, - error->ErrorMessage->c_str(), - error->ErrorCode->c_str()); - } - else - { - fprintf(stderr, "Error on subscription: %s.\n", ErrorDebugString(ioErr)); - exit(-1); - } - }; - - auto onRegisterPublishSubAck = [&](int ioErr) { - if (ioErr != AWS_OP_SUCCESS) - { - fprintf(stderr, "Error publishing to RegisterThing: %s\n", ErrorDebugString(ioErr)); - exit(-1); - } - - registerPublishCompletedPromise.set_value(); - }; - - if (csrFile.empty()) + return -1; + } + IotIdentityClient identityClient(client); + + /* + * Use promises to enforce synchronous behavior, so it's easier to follow the workflow. + */ + std::promise csrPublishPubAckCompletedPromise; + std::promise csrAcceptedSubAckCompletedPromise; + std::promise csrRejectedSubAckCompletedPromise; + std::promise csrAcceptedCompletedPromise; + + std::promise keysPublishPubAckCompletedPromise; + std::promise keysAcceptedSubAckCompletedPromise; + std::promise keysRejectedSubAckCompletedPromise; + std::promise keysAcceptedCompletedPromise; + + std::promise registerPublishPubAckCompletedPromise; + std::promise registerAcceptedSubAckCompletedPromise; + std::promise registerRejectedSubAckCompletedPromise; + std::promise registerAcceptedCompletedPromise; + + auto onCsrPublishPubAck = [&](int ioErr) { + if (ioErr != AWS_OP_SUCCESS) + { + fprintf(stderr, "Error publishing to CreateCertificateFromCsr: %s\n", ErrorDebugString(ioErr)); + exit(-1); + } + + csrPublishPubAckCompletedPromise.set_value(); + }; + + auto onCsrAcceptedSubAck = [&](int ioErr) { + if (ioErr != AWS_OP_SUCCESS) + { + fprintf(stderr, "Error subscribing to CreateCertificateFromCsr accepted: %s\n", ErrorDebugString(ioErr)); + exit(-1); + } + + csrAcceptedSubAckCompletedPromise.set_value(); + }; + + auto onCsrRejectedSubAck = [&](int ioErr) { + if (ioErr != AWS_OP_SUCCESS) + { + fprintf(stderr, "Error subscribing to CreateCertificateFromCsr rejected: %s\n", ErrorDebugString(ioErr)); + exit(-1); + } + csrRejectedSubAckCompletedPromise.set_value(); + }; + + auto onCsrAccepted = [&](CreateCertificateFromCsrResponse *response, int ioErr) { + if (ioErr == AWS_OP_SUCCESS) + { + fprintf(stdout, "CreateCertificateFromCsrResponse certificateId: %s.\n", response->CertificateId->c_str()); + token = *response->CertificateOwnershipToken; + } + else + { + fprintf(stderr, "Error on subscription: %s.\n", ErrorDebugString(ioErr)); + exit(-1); + } + }; + + auto onCsrRejected = [&](ErrorResponse *error, int ioErr) { + if (ioErr == AWS_OP_SUCCESS) { - // CreateKeysAndCertificate workflow - std::cout << "Subscribing to CreateKeysAndCertificate Accepted and Rejected topics" << std::endl; - CreateKeysAndCertificateSubscriptionRequest keySubscriptionRequest; - identityClient.SubscribeToCreateKeysAndCertificateAccepted( - keySubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onKeysAccepted, onKeysAcceptedSubAck); - - identityClient.SubscribeToCreateKeysAndCertificateRejected( - keySubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onKeysRejected, onKeysRejectedSubAck); - - std::cout << "Publishing to CreateKeysAndCertificate topic" << std::endl; - CreateKeysAndCertificateRequest createKeysAndCertificateRequest; - identityClient.PublishCreateKeysAndCertificate( - createKeysAndCertificateRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onKeysPublishSubAck); - - std::cout << "Subscribing to RegisterThing Accepted and Rejected topics" << std::endl; - RegisterThingSubscriptionRequest registerSubscriptionRequest; - registerSubscriptionRequest.TemplateName = cmdData.input_templateName; - - identityClient.SubscribeToRegisterThingAccepted( - registerSubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onRegisterAccepted, onRegisterAcceptedSubAck); - - identityClient.SubscribeToRegisterThingRejected( - registerSubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onRegisterRejected, onRegisterRejectedSubAck); - - sleep(1); - - std::cout << "Publishing to RegisterThing topic" << std::endl; - RegisterThingRequest registerThingRequest; - registerThingRequest.TemplateName = cmdData.input_templateName; - - const Aws::Crt::String jsonValue = cmdData.input_templateParameters; - Aws::Crt::JsonObject value(jsonValue); - Map pm = value.View().GetAllObjects(); - Aws::Crt::Map params = - Aws::Crt::Map(); - - for (const auto &x : pm) - { - params.emplace(x.first, x.second.AsString()); - } - - registerThingRequest.Parameters = params; - registerThingRequest.CertificateOwnershipToken = token; - - identityClient.PublishRegisterThing( - registerThingRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onRegisterPublishSubAck); - sleep(1); - - keysPublishCompletedPromise.get_future().wait(); - keysAcceptedCompletedPromise.get_future().wait(); - keysRejectedCompletedPromise.get_future().wait(); - registerPublishCompletedPromise.get_future().wait(); - registerAcceptedCompletedPromise.get_future().wait(); - registerRejectedCompletedPromise.get_future().wait(); + fprintf( + stdout, + "CreateCertificateFromCsr failed with statusCode %d, errorMessage %s and errorCode %s.", + *error->StatusCode, + error->ErrorMessage->c_str(), + error->ErrorCode->c_str()); + exit(-1); } else { - // CreateCertificateFromCsr workflow - std::cout << "Subscribing to CreateCertificateFromCsr Accepted and Rejected topics" << std::endl; - CreateCertificateFromCsrSubscriptionRequest csrSubscriptionRequest; - identityClient.SubscribeToCreateCertificateFromCsrAccepted( - csrSubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onCsrAccepted, onCsrAcceptedSubAck); - - identityClient.SubscribeToCreateCertificateFromCsrRejected( - csrSubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onCsrRejected, onCsrRejectedSubAck); - - std::cout << "Publishing to CreateCertificateFromCsr topic" << std::endl; - CreateCertificateFromCsrRequest createCertificateFromCsrRequest; - createCertificateFromCsrRequest.CertificateSigningRequest = csrFile; - identityClient.PublishCreateCertificateFromCsr( - createCertificateFromCsrRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onCsrPublishSubAck); - - std::cout << "Subscribing to RegisterThing Accepted and Rejected topics" << std::endl; - RegisterThingSubscriptionRequest registerSubscriptionRequest; - registerSubscriptionRequest.TemplateName = cmdData.input_templateName; - - identityClient.SubscribeToRegisterThingAccepted( - registerSubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onRegisterAccepted, onRegisterAcceptedSubAck); - - identityClient.SubscribeToRegisterThingRejected( - registerSubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onRegisterRejected, onRegisterRejectedSubAck); - - sleep(2); - - std::cout << "Publishing to RegisterThing topic" << std::endl; - RegisterThingRequest registerThingRequest; - registerThingRequest.TemplateName = cmdData.input_templateName; - - const Aws::Crt::String jsonValue = cmdData.input_templateParameters; - Aws::Crt::JsonObject value(jsonValue); - Map pm = value.View().GetAllObjects(); - Aws::Crt::Map params = - Aws::Crt::Map(); - - for (const auto &x : pm) - { - params.emplace(x.first, x.second.AsString()); - } - - registerThingRequest.Parameters = params; - registerThingRequest.CertificateOwnershipToken = token; - - identityClient.PublishRegisterThing( - registerThingRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onRegisterPublishSubAck); - sleep(2); - - csrPublishCompletedPromise.get_future().wait(); - csrAcceptedCompletedPromise.get_future().wait(); - csrRejectedCompletedPromise.get_future().wait(); - registerPublishCompletedPromise.get_future().wait(); - registerAcceptedCompletedPromise.get_future().wait(); - registerRejectedCompletedPromise.get_future().wait(); + fprintf(stderr, "Error on subscription: %s.\n", ErrorDebugString(ioErr)); + exit(-1); + } + }; + + auto onKeysPublishPubAck = [&](int ioErr) { + if (ioErr != AWS_OP_SUCCESS) + { + fprintf(stderr, "Error publishing to CreateKeysAndCertificate: %s\n", ErrorDebugString(ioErr)); + exit(-1); } + + keysPublishPubAckCompletedPromise.set_value(); + }; + + auto onKeysAcceptedSubAck = [&](int ioErr) { + if (ioErr != AWS_OP_SUCCESS) + { + fprintf(stderr, "Error subscribing to CreateKeysAndCertificate accepted: %s\n", ErrorDebugString(ioErr)); + exit(-1); + } + + keysAcceptedSubAckCompletedPromise.set_value(); + }; + + auto onKeysRejectedSubAck = [&](int ioErr) { + if (ioErr != AWS_OP_SUCCESS) + { + fprintf(stderr, "Error subscribing to CreateKeysAndCertificate rejected: %s\n", ErrorDebugString(ioErr)); + exit(-1); + } + keysRejectedSubAckCompletedPromise.set_value(); + }; + + auto onKeysAccepted = [&](CreateKeysAndCertificateResponse *response, int ioErr) { + if (ioErr == AWS_OP_SUCCESS) + { + fprintf(stdout, "CreateKeysAndCertificateResponse certificateId: %s.\n", response->CertificateId->c_str()); + token = *response->CertificateOwnershipToken; + } + else + { + fprintf(stderr, "Error on subscription: %s.\n", ErrorDebugString(ioErr)); + exit(-1); + } + }; + + auto onKeysRejected = [&](ErrorResponse *error, int ioErr) { + if (ioErr == AWS_OP_SUCCESS) + { + fprintf( + stdout, + "CreateKeysAndCertificate failed with statusCode %d, errorMessage %s and errorCode %s.", + *error->StatusCode, + error->ErrorMessage->c_str(), + error->ErrorCode->c_str()); + exit(-1); + } + else + { + fprintf(stderr, "Error on subscription: %s.\n", ErrorDebugString(ioErr)); + exit(-1); + } + }; + + auto onRegisterAcceptedSubAck = [&](int ioErr) { + if (ioErr != AWS_OP_SUCCESS) + { + fprintf(stderr, "Error subscribing to RegisterThing accepted: %s\n", ErrorDebugString(ioErr)); + exit(-1); + } + + registerAcceptedSubAckCompletedPromise.set_value(); + }; + + auto onRegisterRejectedSubAck = [&](int ioErr) { + if (ioErr != AWS_OP_SUCCESS) + { + fprintf(stderr, "Error subscribing to RegisterThing rejected: %s\n", ErrorDebugString(ioErr)); + exit(-1); + } + registerRejectedSubAckCompletedPromise.set_value(); + }; + + auto onRegisterAccepted = [&](RegisterThingResponse *response, int ioErr) { + if (ioErr == AWS_OP_SUCCESS) + { + fprintf(stdout, "RegisterThingResponse ThingName: %s.\n", response->ThingName->c_str()); + } + else + { + fprintf(stderr, "Error on subscription: %s.\n", ErrorDebugString(ioErr)); + exit(-1); + } + }; + + auto onRegisterRejected = [&](ErrorResponse *error, int ioErr) { + if (ioErr == AWS_OP_SUCCESS) + { + fprintf( + stdout, + "RegisterThing failed with statusCode %d, errorMessage %s and errorCode %s.", + *error->StatusCode, + error->ErrorMessage->c_str(), + error->ErrorCode->c_str()); + } + else + { + fprintf(stderr, "Error on subscription: %s.\n", ErrorDebugString(ioErr)); + exit(-1); + } + }; + + auto onRegisterPublishPubAck = [&](int ioErr) { + if (ioErr != AWS_OP_SUCCESS) + { + fprintf(stderr, "Error publishing to RegisterThing: %s\n", ErrorDebugString(ioErr)); + exit(-1); + } + + registerPublishPubAckCompletedPromise.set_value(); + }; + + if (csrFile.empty()) + { + // CreateKeysAndCertificate workflow + fprintf(stdout, "Subscribing to CreateKeysAndCertificate Accepted and Rejected topics\n"); + CreateKeysAndCertificateSubscriptionRequest keySubscriptionRequest; + identityClient.SubscribeToCreateKeysAndCertificateAccepted( + keySubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onKeysAccepted, onKeysAcceptedSubAck); + identityClient.SubscribeToCreateKeysAndCertificateRejected( + keySubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onKeysRejected, onKeysRejectedSubAck); + + // Wait for the subscriptions to the accept and reject key/certificates topics to be established. + keysAcceptedSubAckCompletedPromise.get_future().wait(); + keysRejectedSubAckCompletedPromise.get_future().wait(); + + // Now, when we subscribed to the keys and certificates topics, we can make a request for a certificate. + fprintf(stdout, "Publishing to CreateKeysAndCertificate topic\n"); + CreateKeysAndCertificateRequest createKeysAndCertificateRequest; + identityClient.PublishCreateKeysAndCertificate( + createKeysAndCertificateRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onKeysPublishPubAck); + keysPublishPubAckCompletedPromise.get_future().wait(); + + // Wait for a certificate token. + keysAcceptedCompletedPromise.get_future().wait(); + + fprintf(stdout, "Subscribing to RegisterThing Accepted and Rejected topics\n"); + RegisterThingSubscriptionRequest registerSubscriptionRequest; + registerSubscriptionRequest.TemplateName = cmdData.input_templateName; + + identityClient.SubscribeToRegisterThingAccepted( + registerSubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onRegisterAccepted, onRegisterAcceptedSubAck); + + identityClient.SubscribeToRegisterThingRejected( + registerSubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onRegisterRejected, onRegisterRejectedSubAck); + + // Wait for the subscriptions to the accept and reject RegisterThing topics to be established. + registerAcceptedSubAckCompletedPromise.get_future().wait(); + registerRejectedSubAckCompletedPromise.get_future().wait(); + + fprintf(stdout, "Publishing to RegisterThing topic\n"); + RegisterThingRequest registerThingRequest; + registerThingRequest.TemplateName = cmdData.input_templateName; + + const Aws::Crt::String jsonValue = cmdData.input_templateParameters; + Aws::Crt::JsonObject value(jsonValue); + Map pm = value.View().GetAllObjects(); + Aws::Crt::Map params = Aws::Crt::Map(); + + for (const auto &x : pm) + { + params.emplace(x.first, x.second.AsString()); + } + + registerThingRequest.Parameters = params; + registerThingRequest.CertificateOwnershipToken = token; + + identityClient.PublishRegisterThing(registerThingRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onRegisterPublishPubAck); + registerPublishPubAckCompletedPromise.get_future().wait(); + + // Wait for registering a thing to succeed. + registerAcceptedCompletedPromise.get_future().wait(); + } + else + { + // CreateCertificateFromCsr workflow + fprintf(stdout, "Subscribing to CreateCertificateFromCsr Accepted and Rejected topics\n"); + CreateCertificateFromCsrSubscriptionRequest csrSubscriptionRequest; + identityClient.SubscribeToCreateCertificateFromCsrAccepted( + csrSubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onCsrAccepted, onCsrAcceptedSubAck); + + identityClient.SubscribeToCreateCertificateFromCsrRejected( + csrSubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onCsrRejected, onCsrRejectedSubAck); + + // Wait for the subscriptions to the accept and reject certificates topics to be established. + csrAcceptedSubAckCompletedPromise.get_future().wait(); + csrRejectedSubAckCompletedPromise.get_future().wait(); + + // Now, when we subscribed to the certificates topics, we can make a request for a certificate. + fprintf(stdout, "Publishing to CreateCertificateFromCsr topic\n"); + CreateCertificateFromCsrRequest createCertificateFromCsrRequest; + createCertificateFromCsrRequest.CertificateSigningRequest = csrFile; + identityClient.PublishCreateCertificateFromCsr( + createCertificateFromCsrRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onCsrPublishPubAck); + csrPublishPubAckCompletedPromise.get_future().wait(); + + // Wait for a certificate token. + csrAcceptedCompletedPromise.get_future().wait(); + + fprintf(stdout, "Subscribing to RegisterThing Accepted and Rejected topics\n"); + RegisterThingSubscriptionRequest registerSubscriptionRequest; + registerSubscriptionRequest.TemplateName = cmdData.input_templateName; + + identityClient.SubscribeToRegisterThingAccepted( + registerSubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onRegisterAccepted, onRegisterAcceptedSubAck); + + identityClient.SubscribeToRegisterThingRejected( + registerSubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onRegisterRejected, onRegisterRejectedSubAck); + + // Wait for the subscriptions to the accept and reject RegisterThing topics to be established. + registerAcceptedSubAckCompletedPromise.get_future().wait(); + registerRejectedSubAckCompletedPromise.get_future().wait(); + + fprintf(stdout, "Publishing to RegisterThing topic\n"); + RegisterThingRequest registerThingRequest; + registerThingRequest.TemplateName = cmdData.input_templateName; + + const Aws::Crt::String jsonValue = cmdData.input_templateParameters; + Aws::Crt::JsonObject value(jsonValue); + Map pm = value.View().GetAllObjects(); + Aws::Crt::Map params = Aws::Crt::Map(); + + for (const auto &x : pm) + { + params.emplace(x.first, x.second.AsString()); + } + + registerThingRequest.Parameters = params; + registerThingRequest.CertificateOwnershipToken = token; + + identityClient.PublishRegisterThing(registerThingRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onRegisterPublishPubAck); + + registerPublishPubAckCompletedPromise.get_future().wait(); + + // Wait for registering a thing to succeed. + registerAcceptedCompletedPromise.get_future().wait(); } // Disconnect From 4c998164b890008e17523bd6971d674090b67f64 Mon Sep 17 00:00:00 2001 From: Igor Abdrakhimov Date: Thu, 11 Jul 2024 15:43:36 -0700 Subject: [PATCH 39/47] Fix mqtt5 fleet provisioning sample --- samples/fleet_provisioning/mqtt5_fleet_provisioning/main.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/samples/fleet_provisioning/mqtt5_fleet_provisioning/main.cpp b/samples/fleet_provisioning/mqtt5_fleet_provisioning/main.cpp index 1fecd4c9d..3007019f6 100644 --- a/samples/fleet_provisioning/mqtt5_fleet_provisioning/main.cpp +++ b/samples/fleet_provisioning/mqtt5_fleet_provisioning/main.cpp @@ -182,6 +182,7 @@ int main(int argc, char *argv[]) { fprintf(stdout, "CreateCertificateFromCsrResponse certificateId: %s.\n", response->CertificateId->c_str()); token = *response->CertificateOwnershipToken; + csrAcceptedCompletedPromise.set_value(); } else { @@ -242,6 +243,7 @@ int main(int argc, char *argv[]) { fprintf(stdout, "CreateKeysAndCertificateResponse certificateId: %s.\n", response->CertificateId->c_str()); token = *response->CertificateOwnershipToken; + keysAcceptedCompletedPromise.set_value(); } else { @@ -291,6 +293,7 @@ int main(int argc, char *argv[]) if (ioErr == AWS_OP_SUCCESS) { fprintf(stdout, "RegisterThingResponse ThingName: %s.\n", response->ThingName->c_str()); + registerAcceptedCompletedPromise.set_value(); } else { From fb2fa06d20a7da702fc4ad829df771ecedd262e7 Mon Sep 17 00:00:00 2001 From: Igor Abdrakhimov Date: Thu, 11 Jul 2024 16:26:50 -0700 Subject: [PATCH 40/47] Refactor fleet provisioning sample --- .../fleet_provisioning/main.cpp | 482 +++++++++--------- 1 file changed, 236 insertions(+), 246 deletions(-) diff --git a/samples/fleet_provisioning/fleet_provisioning/main.cpp b/samples/fleet_provisioning/fleet_provisioning/main.cpp index 77798caf9..33531c21b 100644 --- a/samples/fleet_provisioning/fleet_provisioning/main.cpp +++ b/samples/fleet_provisioning/fleet_provisioning/main.cpp @@ -34,6 +34,201 @@ static std::string getFileData(std::string const &fileName) return str; } +/** + * Auxiliary structure for holding data used when creating a certificate. + */ +struct CreateCertificateContext +{ + std::promise pubAckPromise; + std::promise acceptedSubAckPromise; + std::promise rejectedSubAckPromise; + std::promise tokenReceivedPromise; + std::string token; +}; + +/** + * Keys-And-Certificate workflow. + * + * @note Subscriptions created here will be active even after the function completes. So, all variables accessed in the + * callbacks must be alive for the whole duration of the identityClient's lifetime. An instance of + * CreateCertificateContext is used to store variables used by the callbacks. + */ +void useKeysAndCertificate(IotIdentityClient &identityClient, CreateCertificateContext &ctx) +{ + auto onKeysPublishPubAck = [&ctx](int ioErr) { + if (ioErr != AWS_OP_SUCCESS) + { + fprintf(stderr, "Error publishing to CreateKeysAndCertificate: %s\n", ErrorDebugString(ioErr)); + exit(-1); + } + ctx.pubAckPromise.set_value(); + }; + + auto onKeysAcceptedSubAck = [&ctx](int ioErr) { + if (ioErr != AWS_OP_SUCCESS) + { + fprintf(stderr, "Error subscribing to CreateKeysAndCertificate accepted: %s\n", ErrorDebugString(ioErr)); + exit(-1); + } + ctx.acceptedSubAckPromise.set_value(); + }; + + auto onKeysRejectedSubAck = [&ctx](int ioErr) { + if (ioErr != AWS_OP_SUCCESS) + { + fprintf(stderr, "Error subscribing to CreateKeysAndCertificate rejected: %s\n", ErrorDebugString(ioErr)); + exit(-1); + } + ctx.rejectedSubAckPromise.set_value(); + }; + + auto onKeysAccepted = [&ctx](CreateKeysAndCertificateResponse *response, int ioErr) { + if (ioErr == AWS_OP_SUCCESS) + { + fprintf(stdout, "CreateKeysAndCertificateResponse certificateId: %s.\n", response->CertificateId->c_str()); + ctx.token = *response->CertificateOwnershipToken; + ctx.tokenReceivedPromise.set_value(); + } + else + { + fprintf(stderr, "Error on subscription: %s.\n", ErrorDebugString(ioErr)); + exit(-1); + } + }; + + auto onKeysRejected = [&](ErrorResponse *error, int ioErr) { + if (ioErr == AWS_OP_SUCCESS) + { + fprintf( + stdout, + "CreateKeysAndCertificate failed with statusCode %d, errorMessage %s and errorCode %s.", + *error->StatusCode, + error->ErrorMessage->c_str(), + error->ErrorCode->c_str()); + exit(-1); + } + else + { + fprintf(stderr, "Error on subscription: %s.\n", ErrorDebugString(ioErr)); + exit(-1); + } + }; + + fprintf(stdout, "Subscribing to CreateKeysAndCertificate Accepted and Rejected topics\n"); + CreateKeysAndCertificateSubscriptionRequest keySubscriptionRequest; + identityClient.SubscribeToCreateKeysAndCertificateAccepted( + keySubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onKeysAccepted, onKeysAcceptedSubAck); + identityClient.SubscribeToCreateKeysAndCertificateRejected( + keySubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onKeysRejected, onKeysRejectedSubAck); + + // Wait for the subscriptions to the accept and reject keys-and-certificate topics to be established. + ctx.acceptedSubAckPromise.get_future().wait(); + ctx.rejectedSubAckPromise.get_future().wait(); + + // Now, when we subscribed to the keys and certificate topics, we can make a request for a certificate. + fprintf(stdout, "Publishing to CreateKeysAndCertificate topic\n"); + CreateKeysAndCertificateRequest createKeysAndCertificateRequest; + identityClient.PublishCreateKeysAndCertificate( + createKeysAndCertificateRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onKeysPublishPubAck); + ctx.pubAckPromise.get_future().wait(); + + // Wait for a certificate token. + ctx.tokenReceivedPromise.get_future().wait(); +} + +/** + * Certificate-From-CSR workflow. + * + * @note Subscriptions created here will be active even after the function completes. So, all variables accessed in the + * callbacks must be alive for the whole duration of the identityClient's lifetime. An instance of + * CreateCertificateContext is used to store variables used by the callbacks. + */ +void useCsr(IotIdentityClient &identityClient, CreateCertificateContext &ctx, const String &csrFile) +{ + auto onCsrPublishPubAck = [&ctx](int ioErr) { + if (ioErr != AWS_OP_SUCCESS) + { + fprintf(stderr, "Error publishing to CreateCertificateFromCsr: %s\n", ErrorDebugString(ioErr)); + exit(-1); + } + ctx.pubAckPromise.set_value(); + }; + + auto onCsrAcceptedSubAck = [&ctx](int ioErr) { + if (ioErr != AWS_OP_SUCCESS) + { + fprintf(stderr, "Error subscribing to CreateCertificateFromCsr accepted: %s\n", ErrorDebugString(ioErr)); + exit(-1); + } + ctx.acceptedSubAckPromise.set_value(); + }; + + auto onCsrRejectedSubAck = [&ctx](int ioErr) { + if (ioErr != AWS_OP_SUCCESS) + { + fprintf(stderr, "Error subscribing to CreateCertificateFromCsr rejected: %s\n", ErrorDebugString(ioErr)); + exit(-1); + } + ctx.rejectedSubAckPromise.set_value(); + }; + + auto onCsrAccepted = [&ctx](CreateCertificateFromCsrResponse *response, int ioErr) { + if (ioErr == AWS_OP_SUCCESS) + { + fprintf(stdout, "CreateCertificateFromCsrResponse certificateId: %s.\n", response->CertificateId->c_str()); + ctx.token = *response->CertificateOwnershipToken; + ctx.tokenReceivedPromise.set_value(); + } + else + { + fprintf(stderr, "Error on subscription: %s.\n", ErrorDebugString(ioErr)); + exit(-1); + } + }; + + auto onCsrRejected = [&](ErrorResponse *error, int ioErr) { + if (ioErr == AWS_OP_SUCCESS) + { + fprintf( + stdout, + "CreateCertificateFromCsr failed with statusCode %d, errorMessage %s and errorCode %s.", + *error->StatusCode, + error->ErrorMessage->c_str(), + error->ErrorCode->c_str()); + exit(-1); + } + else + { + fprintf(stderr, "Error on subscription: %s.\n", ErrorDebugString(ioErr)); + exit(-1); + } + }; + + // CreateCertificateFromCsr workflow + fprintf(stdout, "Subscribing to CreateCertificateFromCsr Accepted and Rejected topics\n"); + CreateCertificateFromCsrSubscriptionRequest csrSubscriptionRequest; + identityClient.SubscribeToCreateCertificateFromCsrAccepted( + csrSubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onCsrAccepted, onCsrAcceptedSubAck); + + identityClient.SubscribeToCreateCertificateFromCsrRejected( + csrSubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onCsrRejected, onCsrRejectedSubAck); + + // Wait for the subscriptions to the accept and reject certificates topics to be established. + ctx.acceptedSubAckPromise.get_future().wait(); + ctx.rejectedSubAckPromise.get_future().wait(); + + // Now, when we subscribed to the certificates topics, we can make a request for a certificate. + fprintf(stdout, "Publishing to CreateCertificateFromCsr topic\n"); + CreateCertificateFromCsrRequest createCertificateFromCsrRequest; + createCertificateFromCsrRequest.CertificateSigningRequest = csrFile; + identityClient.PublishCreateCertificateFromCsr( + createCertificateFromCsrRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onCsrPublishPubAck); + ctx.pubAckPromise.get_future().wait(); + + // Wait for a certificate token. + ctx.tokenReceivedPromise.get_future().wait(); +} + int main(int argc, char *argv[]) { /************************ Setup ****************************/ @@ -42,7 +237,6 @@ int main(int argc, char *argv[]) ApiHandle apiHandle; // Variables for the sample String csrFile; - String token; RegisterThingResponse registerThingResponse; /** @@ -54,7 +248,7 @@ int main(int argc, char *argv[]) if (cmdData.input_csrPath != "") { - csrFile = getFileData(cmdData.input_csrPath.c_str()).c_str(); + csrFile = getFileData(cmdData.input_csrPath.c_str()); } /** @@ -138,141 +332,12 @@ int main(int argc, char *argv[]) /* * Use promises to enforce synchronous behavior, so it's easier to follow the workflow. */ - std::promise csrPublishPubAckCompletedPromise; - std::promise csrAcceptedSubAckCompletedPromise; - std::promise csrRejectedSubAckCompletedPromise; - std::promise csrAcceptedCompletedPromise; - - std::promise keysPublishPubAckCompletedPromise; - std::promise keysAcceptedSubAckCompletedPromise; - std::promise keysRejectedSubAckCompletedPromise; - std::promise keysAcceptedCompletedPromise; std::promise registerPublishPubAckCompletedPromise; std::promise registerAcceptedSubAckCompletedPromise; std::promise registerRejectedSubAckCompletedPromise; std::promise registerAcceptedCompletedPromise; - auto onCsrPublishPubAck = [&](int ioErr) { - if (ioErr != AWS_OP_SUCCESS) - { - fprintf(stderr, "Error publishing to CreateCertificateFromCsr: %s\n", ErrorDebugString(ioErr)); - exit(-1); - } - csrPublishPubAckCompletedPromise.set_value(); - }; - - auto onCsrAcceptedSubAck = [&](int ioErr) { - if (ioErr != AWS_OP_SUCCESS) - { - fprintf(stderr, "Error subscribing to CreateCertificateFromCsr accepted: %s\n", ErrorDebugString(ioErr)); - exit(-1); - } - csrAcceptedSubAckCompletedPromise.set_value(); - }; - - auto onCsrRejectedSubAck = [&](int ioErr) { - if (ioErr != AWS_OP_SUCCESS) - { - fprintf(stderr, "Error subscribing to CreateCertificateFromCsr rejected: %s\n", ErrorDebugString(ioErr)); - exit(-1); - } - csrRejectedSubAckCompletedPromise.set_value(); - }; - - auto onCsrAccepted = [&](CreateCertificateFromCsrResponse *response, int ioErr) { - if (ioErr == AWS_OP_SUCCESS) - { - fprintf(stdout, "CreateCertificateFromCsrResponse certificateId: %s.\n", response->CertificateId->c_str()); - token = *response->CertificateOwnershipToken; - csrAcceptedCompletedPromise.set_value(); - } - else - { - fprintf(stderr, "Error on subscription: %s.\n", ErrorDebugString(ioErr)); - exit(-1); - } - }; - - auto onCsrRejected = [&](ErrorResponse *error, int ioErr) { - if (ioErr == AWS_OP_SUCCESS) - { - fprintf( - stdout, - "CreateCertificateFromCsr failed with statusCode %d, errorMessage %s and errorCode %s.", - *error->StatusCode, - error->ErrorMessage->c_str(), - error->ErrorCode->c_str()); - exit(-1); - } - else - { - fprintf(stderr, "Error on subscription: %s.\n", ErrorDebugString(ioErr)); - exit(-1); - } - }; - - auto onKeysPublishPubAck = [&](int ioErr) { - if (ioErr != AWS_OP_SUCCESS) - { - fprintf(stderr, "Error publishing to CreateKeysAndCertificate: %s\n", ErrorDebugString(ioErr)); - exit(-1); - } - - keysPublishPubAckCompletedPromise.set_value(); - }; - - auto onKeysAcceptedSubAck = [&](int ioErr) { - if (ioErr != AWS_OP_SUCCESS) - { - fprintf(stderr, "Error subscribing to CreateKeysAndCertificate accepted: %s\n", ErrorDebugString(ioErr)); - exit(-1); - } - - keysAcceptedSubAckCompletedPromise.set_value(); - }; - - auto onKeysRejectedSubAck = [&](int ioErr) { - if (ioErr != AWS_OP_SUCCESS) - { - fprintf(stderr, "Error subscribing to CreateKeysAndCertificate rejected: %s\n", ErrorDebugString(ioErr)); - exit(-1); - } - keysRejectedSubAckCompletedPromise.set_value(); - }; - - auto onKeysAccepted = [&](CreateKeysAndCertificateResponse *response, int ioErr) { - if (ioErr == AWS_OP_SUCCESS) - { - fprintf(stdout, "CreateKeysAndCertificateResponse certificateId: %s.\n", response->CertificateId->c_str()); - token = *response->CertificateOwnershipToken; - keysAcceptedCompletedPromise.set_value(); - } - else - { - fprintf(stderr, "Error on subscription: %s.\n", ErrorDebugString(ioErr)); - exit(-1); - } - }; - - auto onKeysRejected = [&](ErrorResponse *error, int ioErr) { - if (ioErr == AWS_OP_SUCCESS) - { - fprintf( - stdout, - "CreateKeysAndCertificate failed with statusCode %d, errorMessage %s and errorCode %s.", - *error->StatusCode, - error->ErrorMessage->c_str(), - error->ErrorCode->c_str()); - exit(-1); - } - else - { - fprintf(stderr, "Error on subscription: %s.\n", ErrorDebugString(ioErr)); - exit(-1); - } - }; - auto onRegisterAcceptedSubAck = [&](int ioErr) { if (ioErr != AWS_OP_SUCCESS) { @@ -332,132 +397,57 @@ int main(int argc, char *argv[]) registerPublishPubAckCompletedPromise.set_value(); }; + CreateCertificateContext certificateContext; + if (csrFile.empty()) { - // CreateKeysAndCertificate workflow - fprintf(stdout, "Subscribing to CreateKeysAndCertificate Accepted and Rejected topics\n"); - CreateKeysAndCertificateSubscriptionRequest keySubscriptionRequest; - identityClient.SubscribeToCreateKeysAndCertificateAccepted( - keySubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onKeysAccepted, onKeysAcceptedSubAck); - identityClient.SubscribeToCreateKeysAndCertificateRejected( - keySubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onKeysRejected, onKeysRejectedSubAck); - - // Wait for the subscriptions to the accept and reject key/certificates topics to be established. - keysAcceptedSubAckCompletedPromise.get_future().wait(); - keysRejectedSubAckCompletedPromise.get_future().wait(); - - // Now, when we subscribed to the keys and certificates topics, we can make a request for a certificate. - fprintf(stdout, "Publishing to CreateKeysAndCertificate topic\n"); - CreateKeysAndCertificateRequest createKeysAndCertificateRequest; - identityClient.PublishCreateKeysAndCertificate( - createKeysAndCertificateRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onKeysPublishPubAck); - keysPublishPubAckCompletedPromise.get_future().wait(); - - // Wait for a certificate token. - keysAcceptedCompletedPromise.get_future().wait(); - - fprintf(stdout, "Subscribing to RegisterThing Accepted and Rejected topics\n"); - RegisterThingSubscriptionRequest registerSubscriptionRequest; - registerSubscriptionRequest.TemplateName = cmdData.input_templateName; - - identityClient.SubscribeToRegisterThingAccepted( - registerSubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onRegisterAccepted, onRegisterAcceptedSubAck); - - identityClient.SubscribeToRegisterThingRejected( - registerSubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onRegisterRejected, onRegisterRejectedSubAck); - - // Wait for the subscriptions to the accept and reject RegisterThing topics to be established. - registerAcceptedSubAckCompletedPromise.get_future().wait(); - registerRejectedSubAckCompletedPromise.get_future().wait(); - - fprintf(stdout, "Publishing to RegisterThing topic\n"); - RegisterThingRequest registerThingRequest; - registerThingRequest.TemplateName = cmdData.input_templateName; - - const Aws::Crt::String jsonValue = cmdData.input_templateParameters; - Aws::Crt::JsonObject value(jsonValue); - Map pm = value.View().GetAllObjects(); - Aws::Crt::Map params = Aws::Crt::Map(); - - for (const auto &x : pm) - { - params.emplace(x.first, x.second.AsString()); - } - - registerThingRequest.Parameters = params; - registerThingRequest.CertificateOwnershipToken = token; - - identityClient.PublishRegisterThing(registerThingRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onRegisterPublishPubAck); - registerPublishPubAckCompletedPromise.get_future().wait(); - - // Wait for registering a thing to succeed. - registerAcceptedCompletedPromise.get_future().wait(); + useKeysAndCertificate(identityClient, certificateContext); } else { - // CreateCertificateFromCsr workflow - fprintf(stdout, "Subscribing to CreateCertificateFromCsr Accepted and Rejected topics\n"); - CreateCertificateFromCsrSubscriptionRequest csrSubscriptionRequest; - identityClient.SubscribeToCreateCertificateFromCsrAccepted( - csrSubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onCsrAccepted, onCsrAcceptedSubAck); - - identityClient.SubscribeToCreateCertificateFromCsrRejected( - csrSubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onCsrRejected, onCsrRejectedSubAck); - - // Wait for the subscriptions to the accept and reject certificates topics to be established. - csrAcceptedSubAckCompletedPromise.get_future().wait(); - csrRejectedSubAckCompletedPromise.get_future().wait(); - - // Now, when we subscribed to the certificates topics, we can make a request for a certificate. - fprintf(stdout, "Publishing to CreateCertificateFromCsr topic\n"); - CreateCertificateFromCsrRequest createCertificateFromCsrRequest; - createCertificateFromCsrRequest.CertificateSigningRequest = csrFile; - identityClient.PublishCreateCertificateFromCsr( - createCertificateFromCsrRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onCsrPublishPubAck); - csrPublishPubAckCompletedPromise.get_future().wait(); - - // Wait for a certificate token. - csrAcceptedCompletedPromise.get_future().wait(); - - fprintf(stdout, "Subscribing to RegisterThing Accepted and Rejected topics\n"); - RegisterThingSubscriptionRequest registerSubscriptionRequest; - registerSubscriptionRequest.TemplateName = cmdData.input_templateName; - - identityClient.SubscribeToRegisterThingAccepted( - registerSubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onRegisterAccepted, onRegisterAcceptedSubAck); - - identityClient.SubscribeToRegisterThingRejected( - registerSubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onRegisterRejected, onRegisterRejectedSubAck); - - // Wait for the subscriptions to the accept and reject RegisterThing topics to be established. - registerAcceptedSubAckCompletedPromise.get_future().wait(); - registerRejectedSubAckCompletedPromise.get_future().wait(); - - fprintf(stdout, "Publishing to RegisterThing topic\n"); - RegisterThingRequest registerThingRequest; - registerThingRequest.TemplateName = cmdData.input_templateName; - - const Aws::Crt::String jsonValue = cmdData.input_templateParameters; - Aws::Crt::JsonObject value(jsonValue); - Map pm = value.View().GetAllObjects(); - Aws::Crt::Map params = Aws::Crt::Map(); - - for (const auto &x : pm) - { - params.emplace(x.first, x.second.AsString()); - } + useCsr(identityClient, certificateContext, csrFile); + } - registerThingRequest.Parameters = params; - registerThingRequest.CertificateOwnershipToken = token; + // After certificate is obtained, it's time to register a thing. + fprintf(stdout, "Subscribing to RegisterThing Accepted and Rejected topics\n"); + RegisterThingSubscriptionRequest registerSubscriptionRequest; + registerSubscriptionRequest.TemplateName = cmdData.input_templateName; - identityClient.PublishRegisterThing(registerThingRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onRegisterPublishPubAck); + identityClient.SubscribeToRegisterThingAccepted( + registerSubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onRegisterAccepted, onRegisterAcceptedSubAck); - registerPublishPubAckCompletedPromise.get_future().wait(); + identityClient.SubscribeToRegisterThingRejected( + registerSubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onRegisterRejected, onRegisterRejectedSubAck); - // Wait for registering a thing to succeed. - registerAcceptedCompletedPromise.get_future().wait(); + // Wait for the subscriptions to the accept and reject RegisterThing topics to be established. + registerAcceptedSubAckCompletedPromise.get_future().wait(); + registerRejectedSubAckCompletedPromise.get_future().wait(); + + fprintf(stdout, "Publishing to RegisterThing topic\n"); + RegisterThingRequest registerThingRequest; + registerThingRequest.TemplateName = cmdData.input_templateName; + + const Aws::Crt::String jsonValue = cmdData.input_templateParameters; + Aws::Crt::JsonObject value(jsonValue); + Map pm = value.View().GetAllObjects(); + Aws::Crt::Map params = Aws::Crt::Map(); + + for (const auto &x : pm) + { + params.emplace(x.first, x.second.AsString()); } + registerThingRequest.Parameters = params; + // NOTE: In a real application creating multiple certificates you'll probably need to protect token var with + // a critical section. This sample makes only one request for a certificate, so no data race is possible. + registerThingRequest.CertificateOwnershipToken = certificateContext.token; + + identityClient.PublishRegisterThing(registerThingRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onRegisterPublishPubAck); + registerPublishPubAckCompletedPromise.get_future().wait(); + + // Wait for registering a thing to succeed. + registerAcceptedCompletedPromise.get_future().wait(); + // Disconnect if (connection->Disconnect()) { From c6d0d802cb8a1e707e2b7c6a16168c16cf39fdf2 Mon Sep 17 00:00:00 2001 From: Igor Abdrakhimov Date: Thu, 11 Jul 2024 16:31:52 -0700 Subject: [PATCH 41/47] Fix token type --- samples/fleet_provisioning/fleet_provisioning/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/fleet_provisioning/fleet_provisioning/main.cpp b/samples/fleet_provisioning/fleet_provisioning/main.cpp index 33531c21b..d91612301 100644 --- a/samples/fleet_provisioning/fleet_provisioning/main.cpp +++ b/samples/fleet_provisioning/fleet_provisioning/main.cpp @@ -43,7 +43,7 @@ struct CreateCertificateContext std::promise acceptedSubAckPromise; std::promise rejectedSubAckPromise; std::promise tokenReceivedPromise; - std::string token; + String token; }; /** From 75043386b011623a1b2c082faac74c7a2667a2e0 Mon Sep 17 00:00:00 2001 From: Igor Abdrakhimov Date: Thu, 11 Jul 2024 16:36:06 -0700 Subject: [PATCH 42/47] fixup --- samples/fleet_provisioning/fleet_provisioning/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/fleet_provisioning/fleet_provisioning/main.cpp b/samples/fleet_provisioning/fleet_provisioning/main.cpp index d91612301..a517b1e29 100644 --- a/samples/fleet_provisioning/fleet_provisioning/main.cpp +++ b/samples/fleet_provisioning/fleet_provisioning/main.cpp @@ -248,7 +248,7 @@ int main(int argc, char *argv[]) if (cmdData.input_csrPath != "") { - csrFile = getFileData(cmdData.input_csrPath.c_str()); + csrFile = getFileData(cmdData.input_csrPath.c_str()).c_str(); } /** From 69e7aba52a37ae66329874be457b107f3f49f4a7 Mon Sep 17 00:00:00 2001 From: Igor Abdrakhimov Date: Thu, 11 Jul 2024 16:48:44 -0700 Subject: [PATCH 43/47] Refactor mqtt5 fleet provisioning sample --- .../fleet_provisioning/main.cpp | 10 +- .../mqtt5_fleet_provisioning/main.cpp | 488 +++++++++--------- 2 files changed, 238 insertions(+), 260 deletions(-) diff --git a/samples/fleet_provisioning/fleet_provisioning/main.cpp b/samples/fleet_provisioning/fleet_provisioning/main.cpp index a517b1e29..1dbcd0ea2 100644 --- a/samples/fleet_provisioning/fleet_provisioning/main.cpp +++ b/samples/fleet_provisioning/fleet_provisioning/main.cpp @@ -47,7 +47,7 @@ struct CreateCertificateContext }; /** - * Keys-And-Certificate workflow. + * Keys-and-Certificate workflow. * * @note Subscriptions created here will be active even after the function completes. So, all variables accessed in the * callbacks must be alive for the whole duration of the identityClient's lifetime. An instance of @@ -137,7 +137,7 @@ void useKeysAndCertificate(IotIdentityClient &identityClient, CreateCertificateC } /** - * Certificate-From-CSR workflow. + * Certificate-from-CSR workflow. * * @note Subscriptions created here will be active even after the function completes. So, all variables accessed in the * callbacks must be alive for the whole duration of the identityClient's lifetime. An instance of @@ -329,10 +329,6 @@ int main(int argc, char *argv[]) IotIdentityClient identityClient(connection); - /* - * Use promises to enforce synchronous behavior, so it's easier to follow the workflow. - */ - std::promise registerPublishPubAckCompletedPromise; std::promise registerAcceptedSubAckCompletedPromise; std::promise registerRejectedSubAckCompletedPromise; @@ -397,8 +393,8 @@ int main(int argc, char *argv[]) registerPublishPubAckCompletedPromise.set_value(); }; + // Create certificate. CreateCertificateContext certificateContext; - if (csrFile.empty()) { useKeysAndCertificate(identityClient, certificateContext); diff --git a/samples/fleet_provisioning/mqtt5_fleet_provisioning/main.cpp b/samples/fleet_provisioning/mqtt5_fleet_provisioning/main.cpp index 3007019f6..21ed958a8 100644 --- a/samples/fleet_provisioning/mqtt5_fleet_provisioning/main.cpp +++ b/samples/fleet_provisioning/mqtt5_fleet_provisioning/main.cpp @@ -4,8 +4,6 @@ */ #include #include -#include -#include #include #include #include @@ -37,6 +35,201 @@ static std::string getFileData(std::string const &fileName) return str; } +/** + * Auxiliary structure for holding data used when creating a certificate. + */ +struct CreateCertificateContext +{ + std::promise pubAckPromise; + std::promise acceptedSubAckPromise; + std::promise rejectedSubAckPromise; + std::promise tokenReceivedPromise; + String token; +}; + +/** + * Keys-and-Certificate workflow. + * + * @note Subscriptions created here will be active even after the function completes. So, all variables accessed in the + * callbacks must be alive for the whole duration of the identityClient's lifetime. An instance of + * CreateCertificateContext is used to store variables used by the callbacks. + */ +void useKeysAndCertificate(IotIdentityClient &identityClient, CreateCertificateContext &ctx) +{ + auto onKeysPublishPubAck = [&ctx](int ioErr) { + if (ioErr != AWS_OP_SUCCESS) + { + fprintf(stderr, "Error publishing to CreateKeysAndCertificate: %s\n", ErrorDebugString(ioErr)); + exit(-1); + } + ctx.pubAckPromise.set_value(); + }; + + auto onKeysAcceptedSubAck = [&ctx](int ioErr) { + if (ioErr != AWS_OP_SUCCESS) + { + fprintf(stderr, "Error subscribing to CreateKeysAndCertificate accepted: %s\n", ErrorDebugString(ioErr)); + exit(-1); + } + ctx.acceptedSubAckPromise.set_value(); + }; + + auto onKeysRejectedSubAck = [&ctx](int ioErr) { + if (ioErr != AWS_OP_SUCCESS) + { + fprintf(stderr, "Error subscribing to CreateKeysAndCertificate rejected: %s\n", ErrorDebugString(ioErr)); + exit(-1); + } + ctx.rejectedSubAckPromise.set_value(); + }; + + auto onKeysAccepted = [&ctx](CreateKeysAndCertificateResponse *response, int ioErr) { + if (ioErr == AWS_OP_SUCCESS) + { + fprintf(stdout, "CreateKeysAndCertificateResponse certificateId: %s.\n", response->CertificateId->c_str()); + ctx.token = *response->CertificateOwnershipToken; + ctx.tokenReceivedPromise.set_value(); + } + else + { + fprintf(stderr, "Error on subscription: %s.\n", ErrorDebugString(ioErr)); + exit(-1); + } + }; + + auto onKeysRejected = [&](ErrorResponse *error, int ioErr) { + if (ioErr == AWS_OP_SUCCESS) + { + fprintf( + stdout, + "CreateKeysAndCertificate failed with statusCode %d, errorMessage %s and errorCode %s.", + *error->StatusCode, + error->ErrorMessage->c_str(), + error->ErrorCode->c_str()); + exit(-1); + } + else + { + fprintf(stderr, "Error on subscription: %s.\n", ErrorDebugString(ioErr)); + exit(-1); + } + }; + + fprintf(stdout, "Subscribing to CreateKeysAndCertificate Accepted and Rejected topics\n"); + CreateKeysAndCertificateSubscriptionRequest keySubscriptionRequest; + identityClient.SubscribeToCreateKeysAndCertificateAccepted( + keySubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onKeysAccepted, onKeysAcceptedSubAck); + identityClient.SubscribeToCreateKeysAndCertificateRejected( + keySubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onKeysRejected, onKeysRejectedSubAck); + + // Wait for the subscriptions to the accept and reject keys-and-certificate topics to be established. + ctx.acceptedSubAckPromise.get_future().wait(); + ctx.rejectedSubAckPromise.get_future().wait(); + + // Now, when we subscribed to the keys and certificate topics, we can make a request for a certificate. + fprintf(stdout, "Publishing to CreateKeysAndCertificate topic\n"); + CreateKeysAndCertificateRequest createKeysAndCertificateRequest; + identityClient.PublishCreateKeysAndCertificate( + createKeysAndCertificateRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onKeysPublishPubAck); + ctx.pubAckPromise.get_future().wait(); + + // Wait for a certificate token. + ctx.tokenReceivedPromise.get_future().wait(); +} + +/** + * Certificate-from-CSR workflow. + * + * @note Subscriptions created here will be active even after the function completes. So, all variables accessed in the + * callbacks must be alive for the whole duration of the identityClient's lifetime. An instance of + * CreateCertificateContext is used to store variables used by the callbacks. + */ +void useCsr(IotIdentityClient &identityClient, CreateCertificateContext &ctx, const String &csrFile) +{ + auto onCsrPublishPubAck = [&ctx](int ioErr) { + if (ioErr != AWS_OP_SUCCESS) + { + fprintf(stderr, "Error publishing to CreateCertificateFromCsr: %s\n", ErrorDebugString(ioErr)); + exit(-1); + } + ctx.pubAckPromise.set_value(); + }; + + auto onCsrAcceptedSubAck = [&ctx](int ioErr) { + if (ioErr != AWS_OP_SUCCESS) + { + fprintf(stderr, "Error subscribing to CreateCertificateFromCsr accepted: %s\n", ErrorDebugString(ioErr)); + exit(-1); + } + ctx.acceptedSubAckPromise.set_value(); + }; + + auto onCsrRejectedSubAck = [&ctx](int ioErr) { + if (ioErr != AWS_OP_SUCCESS) + { + fprintf(stderr, "Error subscribing to CreateCertificateFromCsr rejected: %s\n", ErrorDebugString(ioErr)); + exit(-1); + } + ctx.rejectedSubAckPromise.set_value(); + }; + + auto onCsrAccepted = [&ctx](CreateCertificateFromCsrResponse *response, int ioErr) { + if (ioErr == AWS_OP_SUCCESS) + { + fprintf(stdout, "CreateCertificateFromCsrResponse certificateId: %s.\n", response->CertificateId->c_str()); + ctx.token = *response->CertificateOwnershipToken; + ctx.tokenReceivedPromise.set_value(); + } + else + { + fprintf(stderr, "Error on subscription: %s.\n", ErrorDebugString(ioErr)); + exit(-1); + } + }; + + auto onCsrRejected = [&](ErrorResponse *error, int ioErr) { + if (ioErr == AWS_OP_SUCCESS) + { + fprintf( + stdout, + "CreateCertificateFromCsr failed with statusCode %d, errorMessage %s and errorCode %s.", + *error->StatusCode, + error->ErrorMessage->c_str(), + error->ErrorCode->c_str()); + exit(-1); + } + else + { + fprintf(stderr, "Error on subscription: %s.\n", ErrorDebugString(ioErr)); + exit(-1); + } + }; + + // CreateCertificateFromCsr workflow + fprintf(stdout, "Subscribing to CreateCertificateFromCsr Accepted and Rejected topics\n"); + CreateCertificateFromCsrSubscriptionRequest csrSubscriptionRequest; + identityClient.SubscribeToCreateCertificateFromCsrAccepted( + csrSubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onCsrAccepted, onCsrAcceptedSubAck); + + identityClient.SubscribeToCreateCertificateFromCsrRejected( + csrSubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onCsrRejected, onCsrRejectedSubAck); + + // Wait for the subscriptions to the accept and reject certificates topics to be established. + ctx.acceptedSubAckPromise.get_future().wait(); + ctx.rejectedSubAckPromise.get_future().wait(); + + // Now, when we subscribed to the certificates topics, we can make a request for a certificate. + fprintf(stdout, "Publishing to CreateCertificateFromCsr topic\n"); + CreateCertificateFromCsrRequest createCertificateFromCsrRequest; + createCertificateFromCsrRequest.CertificateSigningRequest = csrFile; + identityClient.PublishCreateCertificateFromCsr( + createCertificateFromCsrRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onCsrPublishPubAck); + ctx.pubAckPromise.get_future().wait(); + + // Wait for a certificate token. + ctx.tokenReceivedPromise.get_future().wait(); +} + int main(int argc, char *argv[]) { /************************ Setup ****************************/ @@ -45,7 +238,6 @@ int main(int argc, char *argv[]) ApiHandle apiHandle; // Variables for the sample String csrFile; - String token; RegisterThingResponse registerThingResponse; /** @@ -130,146 +322,11 @@ int main(int argc, char *argv[]) } IotIdentityClient identityClient(client); - /* - * Use promises to enforce synchronous behavior, so it's easier to follow the workflow. - */ - std::promise csrPublishPubAckCompletedPromise; - std::promise csrAcceptedSubAckCompletedPromise; - std::promise csrRejectedSubAckCompletedPromise; - std::promise csrAcceptedCompletedPromise; - - std::promise keysPublishPubAckCompletedPromise; - std::promise keysAcceptedSubAckCompletedPromise; - std::promise keysRejectedSubAckCompletedPromise; - std::promise keysAcceptedCompletedPromise; - std::promise registerPublishPubAckCompletedPromise; std::promise registerAcceptedSubAckCompletedPromise; std::promise registerRejectedSubAckCompletedPromise; std::promise registerAcceptedCompletedPromise; - auto onCsrPublishPubAck = [&](int ioErr) { - if (ioErr != AWS_OP_SUCCESS) - { - fprintf(stderr, "Error publishing to CreateCertificateFromCsr: %s\n", ErrorDebugString(ioErr)); - exit(-1); - } - - csrPublishPubAckCompletedPromise.set_value(); - }; - - auto onCsrAcceptedSubAck = [&](int ioErr) { - if (ioErr != AWS_OP_SUCCESS) - { - fprintf(stderr, "Error subscribing to CreateCertificateFromCsr accepted: %s\n", ErrorDebugString(ioErr)); - exit(-1); - } - - csrAcceptedSubAckCompletedPromise.set_value(); - }; - - auto onCsrRejectedSubAck = [&](int ioErr) { - if (ioErr != AWS_OP_SUCCESS) - { - fprintf(stderr, "Error subscribing to CreateCertificateFromCsr rejected: %s\n", ErrorDebugString(ioErr)); - exit(-1); - } - csrRejectedSubAckCompletedPromise.set_value(); - }; - - auto onCsrAccepted = [&](CreateCertificateFromCsrResponse *response, int ioErr) { - if (ioErr == AWS_OP_SUCCESS) - { - fprintf(stdout, "CreateCertificateFromCsrResponse certificateId: %s.\n", response->CertificateId->c_str()); - token = *response->CertificateOwnershipToken; - csrAcceptedCompletedPromise.set_value(); - } - else - { - fprintf(stderr, "Error on subscription: %s.\n", ErrorDebugString(ioErr)); - exit(-1); - } - }; - - auto onCsrRejected = [&](ErrorResponse *error, int ioErr) { - if (ioErr == AWS_OP_SUCCESS) - { - fprintf( - stdout, - "CreateCertificateFromCsr failed with statusCode %d, errorMessage %s and errorCode %s.", - *error->StatusCode, - error->ErrorMessage->c_str(), - error->ErrorCode->c_str()); - exit(-1); - } - else - { - fprintf(stderr, "Error on subscription: %s.\n", ErrorDebugString(ioErr)); - exit(-1); - } - }; - - auto onKeysPublishPubAck = [&](int ioErr) { - if (ioErr != AWS_OP_SUCCESS) - { - fprintf(stderr, "Error publishing to CreateKeysAndCertificate: %s\n", ErrorDebugString(ioErr)); - exit(-1); - } - - keysPublishPubAckCompletedPromise.set_value(); - }; - - auto onKeysAcceptedSubAck = [&](int ioErr) { - if (ioErr != AWS_OP_SUCCESS) - { - fprintf(stderr, "Error subscribing to CreateKeysAndCertificate accepted: %s\n", ErrorDebugString(ioErr)); - exit(-1); - } - - keysAcceptedSubAckCompletedPromise.set_value(); - }; - - auto onKeysRejectedSubAck = [&](int ioErr) { - if (ioErr != AWS_OP_SUCCESS) - { - fprintf(stderr, "Error subscribing to CreateKeysAndCertificate rejected: %s\n", ErrorDebugString(ioErr)); - exit(-1); - } - keysRejectedSubAckCompletedPromise.set_value(); - }; - - auto onKeysAccepted = [&](CreateKeysAndCertificateResponse *response, int ioErr) { - if (ioErr == AWS_OP_SUCCESS) - { - fprintf(stdout, "CreateKeysAndCertificateResponse certificateId: %s.\n", response->CertificateId->c_str()); - token = *response->CertificateOwnershipToken; - keysAcceptedCompletedPromise.set_value(); - } - else - { - fprintf(stderr, "Error on subscription: %s.\n", ErrorDebugString(ioErr)); - exit(-1); - } - }; - - auto onKeysRejected = [&](ErrorResponse *error, int ioErr) { - if (ioErr == AWS_OP_SUCCESS) - { - fprintf( - stdout, - "CreateKeysAndCertificate failed with statusCode %d, errorMessage %s and errorCode %s.", - *error->StatusCode, - error->ErrorMessage->c_str(), - error->ErrorCode->c_str()); - exit(-1); - } - else - { - fprintf(stderr, "Error on subscription: %s.\n", ErrorDebugString(ioErr)); - exit(-1); - } - }; - auto onRegisterAcceptedSubAck = [&](int ioErr) { if (ioErr != AWS_OP_SUCCESS) { @@ -329,132 +386,57 @@ int main(int argc, char *argv[]) registerPublishPubAckCompletedPromise.set_value(); }; + // Create certificate. + CreateCertificateContext certificateContext; if (csrFile.empty()) { - // CreateKeysAndCertificate workflow - fprintf(stdout, "Subscribing to CreateKeysAndCertificate Accepted and Rejected topics\n"); - CreateKeysAndCertificateSubscriptionRequest keySubscriptionRequest; - identityClient.SubscribeToCreateKeysAndCertificateAccepted( - keySubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onKeysAccepted, onKeysAcceptedSubAck); - identityClient.SubscribeToCreateKeysAndCertificateRejected( - keySubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onKeysRejected, onKeysRejectedSubAck); - - // Wait for the subscriptions to the accept and reject key/certificates topics to be established. - keysAcceptedSubAckCompletedPromise.get_future().wait(); - keysRejectedSubAckCompletedPromise.get_future().wait(); - - // Now, when we subscribed to the keys and certificates topics, we can make a request for a certificate. - fprintf(stdout, "Publishing to CreateKeysAndCertificate topic\n"); - CreateKeysAndCertificateRequest createKeysAndCertificateRequest; - identityClient.PublishCreateKeysAndCertificate( - createKeysAndCertificateRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onKeysPublishPubAck); - keysPublishPubAckCompletedPromise.get_future().wait(); - - // Wait for a certificate token. - keysAcceptedCompletedPromise.get_future().wait(); - - fprintf(stdout, "Subscribing to RegisterThing Accepted and Rejected topics\n"); - RegisterThingSubscriptionRequest registerSubscriptionRequest; - registerSubscriptionRequest.TemplateName = cmdData.input_templateName; - - identityClient.SubscribeToRegisterThingAccepted( - registerSubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onRegisterAccepted, onRegisterAcceptedSubAck); - - identityClient.SubscribeToRegisterThingRejected( - registerSubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onRegisterRejected, onRegisterRejectedSubAck); - - // Wait for the subscriptions to the accept and reject RegisterThing topics to be established. - registerAcceptedSubAckCompletedPromise.get_future().wait(); - registerRejectedSubAckCompletedPromise.get_future().wait(); - - fprintf(stdout, "Publishing to RegisterThing topic\n"); - RegisterThingRequest registerThingRequest; - registerThingRequest.TemplateName = cmdData.input_templateName; - - const Aws::Crt::String jsonValue = cmdData.input_templateParameters; - Aws::Crt::JsonObject value(jsonValue); - Map pm = value.View().GetAllObjects(); - Aws::Crt::Map params = Aws::Crt::Map(); - - for (const auto &x : pm) - { - params.emplace(x.first, x.second.AsString()); - } - - registerThingRequest.Parameters = params; - registerThingRequest.CertificateOwnershipToken = token; - - identityClient.PublishRegisterThing(registerThingRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onRegisterPublishPubAck); - registerPublishPubAckCompletedPromise.get_future().wait(); - - // Wait for registering a thing to succeed. - registerAcceptedCompletedPromise.get_future().wait(); + useKeysAndCertificate(identityClient, certificateContext); } else { - // CreateCertificateFromCsr workflow - fprintf(stdout, "Subscribing to CreateCertificateFromCsr Accepted and Rejected topics\n"); - CreateCertificateFromCsrSubscriptionRequest csrSubscriptionRequest; - identityClient.SubscribeToCreateCertificateFromCsrAccepted( - csrSubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onCsrAccepted, onCsrAcceptedSubAck); - - identityClient.SubscribeToCreateCertificateFromCsrRejected( - csrSubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onCsrRejected, onCsrRejectedSubAck); - - // Wait for the subscriptions to the accept and reject certificates topics to be established. - csrAcceptedSubAckCompletedPromise.get_future().wait(); - csrRejectedSubAckCompletedPromise.get_future().wait(); - - // Now, when we subscribed to the certificates topics, we can make a request for a certificate. - fprintf(stdout, "Publishing to CreateCertificateFromCsr topic\n"); - CreateCertificateFromCsrRequest createCertificateFromCsrRequest; - createCertificateFromCsrRequest.CertificateSigningRequest = csrFile; - identityClient.PublishCreateCertificateFromCsr( - createCertificateFromCsrRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onCsrPublishPubAck); - csrPublishPubAckCompletedPromise.get_future().wait(); - - // Wait for a certificate token. - csrAcceptedCompletedPromise.get_future().wait(); - - fprintf(stdout, "Subscribing to RegisterThing Accepted and Rejected topics\n"); - RegisterThingSubscriptionRequest registerSubscriptionRequest; - registerSubscriptionRequest.TemplateName = cmdData.input_templateName; - - identityClient.SubscribeToRegisterThingAccepted( - registerSubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onRegisterAccepted, onRegisterAcceptedSubAck); - - identityClient.SubscribeToRegisterThingRejected( - registerSubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onRegisterRejected, onRegisterRejectedSubAck); - - // Wait for the subscriptions to the accept and reject RegisterThing topics to be established. - registerAcceptedSubAckCompletedPromise.get_future().wait(); - registerRejectedSubAckCompletedPromise.get_future().wait(); - - fprintf(stdout, "Publishing to RegisterThing topic\n"); - RegisterThingRequest registerThingRequest; - registerThingRequest.TemplateName = cmdData.input_templateName; - - const Aws::Crt::String jsonValue = cmdData.input_templateParameters; - Aws::Crt::JsonObject value(jsonValue); - Map pm = value.View().GetAllObjects(); - Aws::Crt::Map params = Aws::Crt::Map(); - - for (const auto &x : pm) - { - params.emplace(x.first, x.second.AsString()); - } + useCsr(identityClient, certificateContext, csrFile); + } - registerThingRequest.Parameters = params; - registerThingRequest.CertificateOwnershipToken = token; + // After certificate is obtained, it's time to register a thing. + fprintf(stdout, "Subscribing to RegisterThing Accepted and Rejected topics\n"); + RegisterThingSubscriptionRequest registerSubscriptionRequest; + registerSubscriptionRequest.TemplateName = cmdData.input_templateName; - identityClient.PublishRegisterThing(registerThingRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onRegisterPublishPubAck); + identityClient.SubscribeToRegisterThingAccepted( + registerSubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onRegisterAccepted, onRegisterAcceptedSubAck); - registerPublishPubAckCompletedPromise.get_future().wait(); + identityClient.SubscribeToRegisterThingRejected( + registerSubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onRegisterRejected, onRegisterRejectedSubAck); - // Wait for registering a thing to succeed. - registerAcceptedCompletedPromise.get_future().wait(); + // Wait for the subscriptions to the accept and reject RegisterThing topics to be established. + registerAcceptedSubAckCompletedPromise.get_future().wait(); + registerRejectedSubAckCompletedPromise.get_future().wait(); + + fprintf(stdout, "Publishing to RegisterThing topic\n"); + RegisterThingRequest registerThingRequest; + registerThingRequest.TemplateName = cmdData.input_templateName; + + const Aws::Crt::String jsonValue = cmdData.input_templateParameters; + Aws::Crt::JsonObject value(jsonValue); + Map pm = value.View().GetAllObjects(); + Aws::Crt::Map params = Aws::Crt::Map(); + + for (const auto &x : pm) + { + params.emplace(x.first, x.second.AsString()); } + registerThingRequest.Parameters = params; + // NOTE: In a real application creating multiple certificates you'll probably need to protect token var with + // a critical section. This sample makes only one request for a certificate, so no data race is possible. + registerThingRequest.CertificateOwnershipToken = certificateContext.token; + + identityClient.PublishRegisterThing(registerThingRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onRegisterPublishPubAck); + registerPublishPubAckCompletedPromise.get_future().wait(); + + // Wait for registering a thing to succeed. + registerAcceptedCompletedPromise.get_future().wait(); + // Disconnect if (client->Stop()) { From 3dd5dfbe00f71492017a6b5db5e39250fe336291 Mon Sep 17 00:00:00 2001 From: Igor Abdrakhimov Date: Thu, 11 Jul 2024 17:23:14 -0700 Subject: [PATCH 44/47] Refactor fleet provisioning sample further --- .../fleet_provisioning/main.cpp | 303 ++++++++++-------- 1 file changed, 173 insertions(+), 130 deletions(-) diff --git a/samples/fleet_provisioning/fleet_provisioning/main.cpp b/samples/fleet_provisioning/fleet_provisioning/main.cpp index 1dbcd0ea2..8e5579ca4 100644 --- a/samples/fleet_provisioning/fleet_provisioning/main.cpp +++ b/samples/fleet_provisioning/fleet_provisioning/main.cpp @@ -2,6 +2,14 @@ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0. */ + +/** + * A sample application demonstrating usage of AWS IoT Fleet provisioning. + * + * In a real world application you probably don't want to enforce synchronous behavior. But this is a sample console + * application, so all actions, like creating a certificate or registering a thing, are performed in synchronous manner. + */ + #include #include @@ -34,6 +42,15 @@ static std::string getFileData(std::string const &fileName) return str; } +/** + * Auxiliary structure for holding data used by MQTT connection. + */ +struct ConnectionContext +{ + std::promise connectionCompletedPromise; + std::promise connectionClosedPromise; +}; + /** * Auxiliary structure for holding data used when creating a certificate. */ @@ -46,6 +63,85 @@ struct CreateCertificateContext String token; }; +/** + * Auxiliary structure for holding data used when registering a thing. + */ +struct RegisterThingContext +{ + std::promise pubAckPromise; + std::promise acceptedSubAckPromise; + std::promise rejectedSubAckPromise; + std::promise thingCreatedPromise; +}; + +/** + * Create MQTT3 connection. + */ +std::shared_ptr createConnection(const Utils::cmdData &cmdData, ConnectionContext &ctx) +{ + /** + * In a real world application you probably don't want to enforce synchronous behavior + * but this is a sample console application, so we'll just do that with a promise. + */ + + // Invoked when a MQTT connect has completed or failed + auto onConnectionCompleted = [&ctx](Mqtt::MqttConnection &, int errorCode, Mqtt::ReturnCode returnCode, bool) { + if (errorCode) + { + fprintf(stdout, "Connection failed with error %s\n", ErrorDebugString(errorCode)); + ctx.connectionCompletedPromise.set_value(false); + } + else + { + fprintf(stdout, "Connection completed with return code %d\n", returnCode); + ctx.connectionCompletedPromise.set_value(true); + } + }; + + // Invoked when a disconnect has been completed + auto onDisconnect = [&ctx](Mqtt::MqttConnection & /*conn*/) { + { + fprintf(stdout, "Disconnect completed\n"); + ctx.connectionClosedPromise.set_value(); + } + }; + + // Create the MQTT builder and populate it with data from cmdData. + auto clientConfigBuilder = + Aws::Iot::MqttClientConnectionConfigBuilder(cmdData.input_cert.c_str(), cmdData.input_key.c_str()); + clientConfigBuilder.WithEndpoint(cmdData.input_endpoint); + if (cmdData.input_ca != "") + { + clientConfigBuilder.WithCertificateAuthority(cmdData.input_ca.c_str()); + } + + // Create the MQTT connection from the MQTT builder + auto clientConfig = clientConfigBuilder.Build(); + if (!clientConfig) + { + fprintf( + stderr, + "Client Configuration initialization failed with error %s\n", + Aws::Crt::ErrorDebugString(clientConfig.LastError())); + exit(-1); + } + Aws::Iot::MqttClient client = Aws::Iot::MqttClient(); + auto connection = client.NewConnection(clientConfig); + if (!*connection) + { + fprintf( + stderr, + "MQTT Connection Creation failed with error %s\n", + Aws::Crt::ErrorDebugString(connection->LastError())); + exit(-1); + } + + connection->OnConnectionCompleted = std::move(onConnectionCompleted); + connection->OnDisconnect = std::move(onDisconnect); + + return connection; +} + /** * Keys-and-Certificate workflow. * @@ -53,7 +149,7 @@ struct CreateCertificateContext * callbacks must be alive for the whole duration of the identityClient's lifetime. An instance of * CreateCertificateContext is used to store variables used by the callbacks. */ -void useKeysAndCertificate(IotIdentityClient &identityClient, CreateCertificateContext &ctx) +void createKeysAndCertificate(IotIdentityClient &identityClient, CreateCertificateContext &ctx) { auto onKeysPublishPubAck = [&ctx](int ioErr) { if (ioErr != AWS_OP_SUCCESS) @@ -143,7 +239,7 @@ void useKeysAndCertificate(IotIdentityClient &identityClient, CreateCertificateC * callbacks must be alive for the whole duration of the identityClient's lifetime. An instance of * CreateCertificateContext is used to store variables used by the callbacks. */ -void useCsr(IotIdentityClient &identityClient, CreateCertificateContext &ctx, const String &csrFile) +void createCertificateFromCsr(IotIdentityClient &identityClient, CreateCertificateContext &ctx, const String &csrFile) { auto onCsrPublishPubAck = [&ctx](int ioErr) { if (ioErr != AWS_OP_SUCCESS) @@ -229,119 +325,22 @@ void useCsr(IotIdentityClient &identityClient, CreateCertificateContext &ctx, co ctx.tokenReceivedPromise.get_future().wait(); } -int main(int argc, char *argv[]) +/** + * Provision an AWS IoT thing using a pre-defined template. + */ +void registerThing( + IotIdentityClient &identityClient, + RegisterThingContext &ctx, + const Utils::cmdData &cmdData, + const String &token) { - /************************ Setup ****************************/ - - // Do the global initialization for the API - ApiHandle apiHandle; - // Variables for the sample - String csrFile; - RegisterThingResponse registerThingResponse; - - /** - * cmdData is the arguments/input from the command line placed into a single struct for - * use in this sample. This handles all of the command line parsing, validating, etc. - * See the Utils/CommandLineUtils for more information. - */ - Utils::cmdData cmdData = Utils::parseSampleInputFleetProvisioning(argc, argv, &apiHandle); - - if (cmdData.input_csrPath != "") - { - csrFile = getFileData(cmdData.input_csrPath.c_str()).c_str(); - } - - /** - * In a real world application you probably don't want to enforce synchronous behavior - * but this is a sample console application, so we'll just do that with a promise. - */ - std::promise connectionCompletedPromise; - std::promise connectionClosedPromise; - - // Invoked when a MQTT connect has completed or failed - auto onConnectionCompleted = [&](Mqtt::MqttConnection &, int errorCode, Mqtt::ReturnCode returnCode, bool) { - if (errorCode) - { - fprintf(stdout, "Connection failed with error %s\n", ErrorDebugString(errorCode)); - connectionCompletedPromise.set_value(false); - } - else - { - fprintf(stdout, "Connection completed with return code %d\n", returnCode); - connectionCompletedPromise.set_value(true); - } - }; - - // Invoked when a disconnect has been completed - auto onDisconnect = [&](Mqtt::MqttConnection & /*conn*/) { - { - fprintf(stdout, "Disconnect completed\n"); - connectionClosedPromise.set_value(); - } - }; - - // Create the MQTT builder and populate it with data from cmdData. - auto clientConfigBuilder = - Aws::Iot::MqttClientConnectionConfigBuilder(cmdData.input_cert.c_str(), cmdData.input_key.c_str()); - clientConfigBuilder.WithEndpoint(cmdData.input_endpoint); - if (cmdData.input_ca != "") - { - clientConfigBuilder.WithCertificateAuthority(cmdData.input_ca.c_str()); - } - - // Create the MQTT connection from the MQTT builder - auto clientConfig = clientConfigBuilder.Build(); - if (!clientConfig) - { - fprintf( - stderr, - "Client Configuration initialization failed with error %s\n", - Aws::Crt::ErrorDebugString(clientConfig.LastError())); - exit(-1); - } - Aws::Iot::MqttClient client = Aws::Iot::MqttClient(); - auto connection = client.NewConnection(clientConfig); - if (!*connection) - { - fprintf( - stderr, - "MQTT Connection Creation failed with error %s\n", - Aws::Crt::ErrorDebugString(connection->LastError())); - exit(-1); - } - - connection->OnConnectionCompleted = std::move(onConnectionCompleted); - connection->OnDisconnect = std::move(onDisconnect); - - /************************ Run the sample ****************************/ - - fprintf(stdout, "Connecting...\n"); - if (!connection->Connect(cmdData.input_clientId.c_str(), true, 0)) - { - fprintf(stderr, "MQTT Connection failed with error %s\n", ErrorDebugString(connection->LastError())); - exit(-1); - } - - if (!connectionCompletedPromise.get_future().get()) - { - return -1; - } - - IotIdentityClient identityClient(connection); - - std::promise registerPublishPubAckCompletedPromise; - std::promise registerAcceptedSubAckCompletedPromise; - std::promise registerRejectedSubAckCompletedPromise; - std::promise registerAcceptedCompletedPromise; - auto onRegisterAcceptedSubAck = [&](int ioErr) { if (ioErr != AWS_OP_SUCCESS) { fprintf(stderr, "Error subscribing to RegisterThing accepted: %s\n", ErrorDebugString(ioErr)); exit(-1); } - - registerAcceptedSubAckCompletedPromise.set_value(); + ctx.acceptedSubAckPromise.set_value(); }; auto onRegisterRejectedSubAck = [&](int ioErr) { @@ -350,14 +349,14 @@ int main(int argc, char *argv[]) fprintf(stderr, "Error subscribing to RegisterThing rejected: %s\n", ErrorDebugString(ioErr)); exit(-1); } - registerRejectedSubAckCompletedPromise.set_value(); + ctx.rejectedSubAckPromise.set_value(); }; auto onRegisterAccepted = [&](RegisterThingResponse *response, int ioErr) { if (ioErr == AWS_OP_SUCCESS) { fprintf(stdout, "RegisterThingResponse ThingName: %s.\n", response->ThingName->c_str()); - registerAcceptedCompletedPromise.set_value(); + ctx.thingCreatedPromise.set_value(); } else { @@ -389,22 +388,9 @@ int main(int argc, char *argv[]) fprintf(stderr, "Error publishing to RegisterThing: %s\n", ErrorDebugString(ioErr)); exit(-1); } - - registerPublishPubAckCompletedPromise.set_value(); + ctx.pubAckPromise.set_value(); }; - // Create certificate. - CreateCertificateContext certificateContext; - if (csrFile.empty()) - { - useKeysAndCertificate(identityClient, certificateContext); - } - else - { - useCsr(identityClient, certificateContext, csrFile); - } - - // After certificate is obtained, it's time to register a thing. fprintf(stdout, "Subscribing to RegisterThing Accepted and Rejected topics\n"); RegisterThingSubscriptionRequest registerSubscriptionRequest; registerSubscriptionRequest.TemplateName = cmdData.input_templateName; @@ -416,8 +402,8 @@ int main(int argc, char *argv[]) registerSubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onRegisterRejected, onRegisterRejectedSubAck); // Wait for the subscriptions to the accept and reject RegisterThing topics to be established. - registerAcceptedSubAckCompletedPromise.get_future().wait(); - registerRejectedSubAckCompletedPromise.get_future().wait(); + ctx.acceptedSubAckPromise.get_future().wait(); + ctx.rejectedSubAckPromise.get_future().wait(); fprintf(stdout, "Publishing to RegisterThing topic\n"); RegisterThingRequest registerThingRequest; @@ -436,18 +422,75 @@ int main(int argc, char *argv[]) registerThingRequest.Parameters = params; // NOTE: In a real application creating multiple certificates you'll probably need to protect token var with // a critical section. This sample makes only one request for a certificate, so no data race is possible. - registerThingRequest.CertificateOwnershipToken = certificateContext.token; + registerThingRequest.CertificateOwnershipToken = token; identityClient.PublishRegisterThing(registerThingRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onRegisterPublishPubAck); - registerPublishPubAckCompletedPromise.get_future().wait(); + ctx.pubAckPromise.get_future().wait(); // Wait for registering a thing to succeed. - registerAcceptedCompletedPromise.get_future().wait(); + ctx.thingCreatedPromise.get_future().wait(); +} + +int main(int argc, char *argv[]) +{ + /************************ Setup ****************************/ + + // Do the global initialization for the API + ApiHandle apiHandle; + // Variables for the sample + String csrFile; + + /** + * cmdData is the arguments/input from the command line placed into a single struct for + * use in this sample. This handles all of the command line parsing, validating, etc. + * See the Utils/CommandLineUtils for more information. + */ + Utils::cmdData cmdData = Utils::parseSampleInputFleetProvisioning(argc, argv, &apiHandle); + + if (cmdData.input_csrPath != "") + { + csrFile = getFileData(cmdData.input_csrPath.c_str()).c_str(); + } + + ConnectionContext connectionContext; + auto connection = createConnection(cmdData, connectionContext); + + /************************ Run the sample ****************************/ + + fprintf(stdout, "Connecting...\n"); + if (!connection->Connect(cmdData.input_clientId.c_str(), true, 0)) + { + fprintf(stderr, "MQTT Connection failed with error %s\n", ErrorDebugString(connection->LastError())); + exit(-1); + } + + if (!connectionContext.connectionCompletedPromise.get_future().get()) + { + exit(-1); + } + + // Create fleet provisioning client. + IotIdentityClient identityClient(connection); + + // Create certificate. + CreateCertificateContext certificateContext; + if (csrFile.empty()) + { + createKeysAndCertificate(identityClient, certificateContext); + } + else + { + createCertificateFromCsr(identityClient, certificateContext, csrFile); + } + + // After certificate is obtained, it's time to register a thing. + RegisterThingContext registerThingContext; + registerThing(identityClient, registerThingContext, cmdData, certificateContext.token); // Disconnect if (connection->Disconnect()) { - connectionClosedPromise.get_future().wait(); + connectionContext.connectionClosedPromise.get_future().wait(); } return 0; From 67f23319c700547a3e0af1d55977a27852f2b649 Mon Sep 17 00:00:00 2001 From: Igor Abdrakhimov Date: Thu, 11 Jul 2024 17:32:30 -0700 Subject: [PATCH 45/47] Refactor mqtt5 fleet provisioning sample further --- .../mqtt5_fleet_provisioning/main.cpp | 279 ++++++++++-------- 1 file changed, 157 insertions(+), 122 deletions(-) diff --git a/samples/fleet_provisioning/mqtt5_fleet_provisioning/main.cpp b/samples/fleet_provisioning/mqtt5_fleet_provisioning/main.cpp index 21ed958a8..4389636f2 100644 --- a/samples/fleet_provisioning/mqtt5_fleet_provisioning/main.cpp +++ b/samples/fleet_provisioning/mqtt5_fleet_provisioning/main.cpp @@ -35,6 +35,17 @@ static std::string getFileData(std::string const &fileName) return str; } +/** + * Auxiliary structure for holding data used by MQTT connection. + */ +struct Mqtt5ClientContext +{ + std::promise connectionPromise; + std::promise stoppedPromise; + std::promise disconnectPromise; + std::promise subscribeSuccess; +}; + /** * Auxiliary structure for holding data used when creating a certificate. */ @@ -47,6 +58,74 @@ struct CreateCertificateContext String token; }; +/** + * Auxiliary structure for holding data used when registering a thing. + */ +struct RegisterThingContext +{ + std::promise pubAckPromise; + std::promise acceptedSubAckPromise; + std::promise rejectedSubAckPromise; + std::promise thingCreatedPromise; +}; + +/** + * Create MQTT5 client. + */ +std::shared_ptr createMqtt5Client(Mqtt5ClientContext &ctx, const Utils::cmdData &cmdData) +{ + // Create the MQTT5 builder and populate it with data from cmdData. + Aws::Iot::Mqtt5ClientBuilder *builder = Aws::Iot::Mqtt5ClientBuilder::NewMqtt5ClientBuilderWithMtlsFromPath( + cmdData.input_endpoint, cmdData.input_cert.c_str(), cmdData.input_key.c_str()); + + // Check if the builder setup correctly. + if (builder == nullptr) + { + printf( + "Failed to setup mqtt5 client builder with error code %d: %s", LastError(), ErrorDebugString(LastError())); + exit(-1); + } + + // Setup connection options + std::shared_ptr connectOptions = std::make_shared(); + connectOptions->WithClientId(cmdData.input_clientId); + builder->WithConnectOptions(connectOptions); + if (cmdData.input_port != 0) + { + builder->WithPort(static_cast(cmdData.input_port)); + } + + // Setup lifecycle callbacks + builder->WithClientConnectionSuccessCallback([&ctx](const Mqtt5::OnConnectionSuccessEventData &eventData) { + fprintf( + stdout, + "Mqtt5 Client connection succeed, clientid: %s.\n", + eventData.negotiatedSettings->getClientId().c_str()); + ctx.connectionPromise.set_value(true); + }); + builder->WithClientConnectionFailureCallback([&ctx](const Mqtt5::OnConnectionFailureEventData &eventData) { + fprintf(stdout, "Mqtt5 Client connection failed with error: %s.\n", aws_error_debug_str(eventData.errorCode)); + ctx.connectionPromise.set_value(false); + }); + builder->WithClientStoppedCallback([&ctx](const Mqtt5::OnStoppedEventData &) { + fprintf(stdout, "Mqtt5 Client stopped.\n"); + ctx.stoppedPromise.set_value(); + }); + builder->WithClientAttemptingConnectCallback([](const Mqtt5::OnAttemptingConnectEventData &) { + fprintf(stdout, "Mqtt5 Client attempting connection...\n"); + }); + builder->WithClientDisconnectionCallback([&ctx](const Mqtt5::OnDisconnectionEventData &eventData) { + fprintf(stdout, "Mqtt5 Client disconnection with reason: %s.\n", aws_error_debug_str(eventData.errorCode)); + ctx.disconnectPromise.set_value(); + }); + + // Create Mqtt5Client + std::shared_ptr client = builder->Build(); + delete builder; + + return client; +} + /** * Keys-and-Certificate workflow. * @@ -54,7 +133,7 @@ struct CreateCertificateContext * callbacks must be alive for the whole duration of the identityClient's lifetime. An instance of * CreateCertificateContext is used to store variables used by the callbacks. */ -void useKeysAndCertificate(IotIdentityClient &identityClient, CreateCertificateContext &ctx) +void createKeysAndCertificate(IotIdentityClient &identityClient, CreateCertificateContext &ctx) { auto onKeysPublishPubAck = [&ctx](int ioErr) { if (ioErr != AWS_OP_SUCCESS) @@ -144,7 +223,7 @@ void useKeysAndCertificate(IotIdentityClient &identityClient, CreateCertificateC * callbacks must be alive for the whole duration of the identityClient's lifetime. An instance of * CreateCertificateContext is used to store variables used by the callbacks. */ -void useCsr(IotIdentityClient &identityClient, CreateCertificateContext &ctx, const String &csrFile) +void createCertificateFromCsr(IotIdentityClient &identityClient, CreateCertificateContext &ctx, const String &csrFile) { auto onCsrPublishPubAck = [&ctx](int ioErr) { if (ioErr != AWS_OP_SUCCESS) @@ -230,111 +309,22 @@ void useCsr(IotIdentityClient &identityClient, CreateCertificateContext &ctx, co ctx.tokenReceivedPromise.get_future().wait(); } -int main(int argc, char *argv[]) +/** + * Provision an AWS IoT thing using a pre-defined template. + */ +void registerThing( + IotIdentityClient &identityClient, + RegisterThingContext &ctx, + const Utils::cmdData &cmdData, + const String &token) { - /************************ Setup ****************************/ - - // Do the global initialization for the API - ApiHandle apiHandle; - // Variables for the sample - String csrFile; - RegisterThingResponse registerThingResponse; - - /** - * cmdData is the arguments/input from the command line placed into a single struct for - * use in this sample. This handles all of the command line parsing, validating, etc. - * See the Utils/CommandLineUtils for more information. - */ - Utils::cmdData cmdData = Utils::parseSampleInputFleetProvisioning(argc, argv, &apiHandle); - - if (cmdData.input_csrPath != "") - { - csrFile = getFileData(cmdData.input_csrPath.c_str()).c_str(); - } - - // Create the MQTT5 builder and populate it with data from cmdData. - Aws::Iot::Mqtt5ClientBuilder *builder = Aws::Iot::Mqtt5ClientBuilder::NewMqtt5ClientBuilderWithMtlsFromPath( - cmdData.input_endpoint, cmdData.input_cert.c_str(), cmdData.input_key.c_str()); - - // Check if the builder setup correctly. - if (builder == nullptr) - { - printf( - "Failed to setup mqtt5 client builder with error code %d: %s", LastError(), ErrorDebugString(LastError())); - return -1; - } - - // Setup connection options - std::shared_ptr connectOptions = std::make_shared(); - connectOptions->WithClientId(cmdData.input_clientId); - builder->WithConnectOptions(connectOptions); - if (cmdData.input_port != 0) - { - builder->WithPort(static_cast(cmdData.input_port)); - } - - std::promise connectionPromise; - std::promise stoppedPromise; - std::promise disconnectPromise; - std::promise subscribeSuccess; - - // Setup lifecycle callbacks - builder->WithClientConnectionSuccessCallback( - [&connectionPromise](const Mqtt5::OnConnectionSuccessEventData &eventData) { - fprintf( - stdout, - "Mqtt5 Client connection succeed, clientid: %s.\n", - eventData.negotiatedSettings->getClientId().c_str()); - connectionPromise.set_value(true); - }); - builder->WithClientConnectionFailureCallback([&connectionPromise]( - const Mqtt5::OnConnectionFailureEventData &eventData) { - fprintf(stdout, "Mqtt5 Client connection failed with error: %s.\n", aws_error_debug_str(eventData.errorCode)); - connectionPromise.set_value(false); - }); - builder->WithClientStoppedCallback([&stoppedPromise](const Mqtt5::OnStoppedEventData &) { - fprintf(stdout, "Mqtt5 Client stopped.\n"); - stoppedPromise.set_value(); - }); - builder->WithClientAttemptingConnectCallback([](const Mqtt5::OnAttemptingConnectEventData &) { - fprintf(stdout, "Mqtt5 Client attempting connection...\n"); - }); - builder->WithClientDisconnectionCallback([&disconnectPromise](const Mqtt5::OnDisconnectionEventData &eventData) { - fprintf(stdout, "Mqtt5 Client disconnection with reason: %s.\n", aws_error_debug_str(eventData.errorCode)); - disconnectPromise.set_value(); - }); - - // Create Mqtt5Client - std::shared_ptr client = builder->Build(); - delete builder; - /************************ Run the sample ****************************/ - - fprintf(stdout, "Connecting...\n"); - if (!client->Start()) - { - fprintf(stderr, "MQTT5 Connection failed to start"); - exit(-1); - } - - if (!connectionPromise.get_future().get()) - { - return -1; - } - IotIdentityClient identityClient(client); - - std::promise registerPublishPubAckCompletedPromise; - std::promise registerAcceptedSubAckCompletedPromise; - std::promise registerRejectedSubAckCompletedPromise; - std::promise registerAcceptedCompletedPromise; - auto onRegisterAcceptedSubAck = [&](int ioErr) { if (ioErr != AWS_OP_SUCCESS) { fprintf(stderr, "Error subscribing to RegisterThing accepted: %s\n", ErrorDebugString(ioErr)); exit(-1); } - - registerAcceptedSubAckCompletedPromise.set_value(); + ctx.acceptedSubAckPromise.set_value(); }; auto onRegisterRejectedSubAck = [&](int ioErr) { @@ -343,14 +333,14 @@ int main(int argc, char *argv[]) fprintf(stderr, "Error subscribing to RegisterThing rejected: %s\n", ErrorDebugString(ioErr)); exit(-1); } - registerRejectedSubAckCompletedPromise.set_value(); + ctx.rejectedSubAckPromise.set_value(); }; auto onRegisterAccepted = [&](RegisterThingResponse *response, int ioErr) { if (ioErr == AWS_OP_SUCCESS) { fprintf(stdout, "RegisterThingResponse ThingName: %s.\n", response->ThingName->c_str()); - registerAcceptedCompletedPromise.set_value(); + ctx.thingCreatedPromise.set_value(); } else { @@ -382,22 +372,9 @@ int main(int argc, char *argv[]) fprintf(stderr, "Error publishing to RegisterThing: %s\n", ErrorDebugString(ioErr)); exit(-1); } - - registerPublishPubAckCompletedPromise.set_value(); + ctx.pubAckPromise.set_value(); }; - // Create certificate. - CreateCertificateContext certificateContext; - if (csrFile.empty()) - { - useKeysAndCertificate(identityClient, certificateContext); - } - else - { - useCsr(identityClient, certificateContext, csrFile); - } - - // After certificate is obtained, it's time to register a thing. fprintf(stdout, "Subscribing to RegisterThing Accepted and Rejected topics\n"); RegisterThingSubscriptionRequest registerSubscriptionRequest; registerSubscriptionRequest.TemplateName = cmdData.input_templateName; @@ -409,8 +386,8 @@ int main(int argc, char *argv[]) registerSubscriptionRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onRegisterRejected, onRegisterRejectedSubAck); // Wait for the subscriptions to the accept and reject RegisterThing topics to be established. - registerAcceptedSubAckCompletedPromise.get_future().wait(); - registerRejectedSubAckCompletedPromise.get_future().wait(); + ctx.acceptedSubAckPromise.get_future().wait(); + ctx.rejectedSubAckPromise.get_future().wait(); fprintf(stdout, "Publishing to RegisterThing topic\n"); RegisterThingRequest registerThingRequest; @@ -429,18 +406,76 @@ int main(int argc, char *argv[]) registerThingRequest.Parameters = params; // NOTE: In a real application creating multiple certificates you'll probably need to protect token var with // a critical section. This sample makes only one request for a certificate, so no data race is possible. - registerThingRequest.CertificateOwnershipToken = certificateContext.token; + registerThingRequest.CertificateOwnershipToken = token; identityClient.PublishRegisterThing(registerThingRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onRegisterPublishPubAck); - registerPublishPubAckCompletedPromise.get_future().wait(); + ctx.pubAckPromise.get_future().wait(); // Wait for registering a thing to succeed. - registerAcceptedCompletedPromise.get_future().wait(); + ctx.thingCreatedPromise.get_future().wait(); +} + +int main(int argc, char *argv[]) +{ + /************************ Setup ****************************/ + + // Do the global initialization for the API + ApiHandle apiHandle; + // Variables for the sample + String csrFile; + RegisterThingResponse registerThingResponse; + + /** + * cmdData is the arguments/input from the command line placed into a single struct for + * use in this sample. This handles all of the command line parsing, validating, etc. + * See the Utils/CommandLineUtils for more information. + */ + Utils::cmdData cmdData = Utils::parseSampleInputFleetProvisioning(argc, argv, &apiHandle); + + if (cmdData.input_csrPath != "") + { + csrFile = getFileData(cmdData.input_csrPath.c_str()).c_str(); + } + + Mqtt5ClientContext mqtt5ClientContext; + auto client = createMqtt5Client(mqtt5ClientContext, cmdData); + + /************************ Run the sample ****************************/ + + fprintf(stdout, "Connecting...\n"); + if (!client->Start()) + { + fprintf(stderr, "MQTT5 Connection failed to start"); + exit(-1); + } + + if (!mqtt5ClientContext.connectionPromise.get_future().get()) + { + return -1; + } + + // Create fleet provisioning client. + IotIdentityClient identityClient(client); + + // Create certificate. + CreateCertificateContext certificateContext; + if (csrFile.empty()) + { + createKeysAndCertificate(identityClient, certificateContext); + } + else + { + createCertificateFromCsr(identityClient, certificateContext, csrFile); + } + + // After certificate is obtained, it's time to register a thing. + RegisterThingContext registerThingContext; + registerThing(identityClient, registerThingContext, cmdData, certificateContext.token); // Disconnect if (client->Stop()) { - stoppedPromise.get_future().wait(); + mqtt5ClientContext.stoppedPromise.get_future().wait(); } return 0; From c9775a599023891eda1e06756c285f3ac323e12e Mon Sep 17 00:00:00 2001 From: Igor Abdrakhimov Date: Thu, 11 Jul 2024 17:48:18 -0700 Subject: [PATCH 46/47] fixup --- .../fleet_provisioning/main.cpp | 24 ++++++--------- .../mqtt5_fleet_provisioning/main.cpp | 29 ++++++++++--------- 2 files changed, 24 insertions(+), 29 deletions(-) diff --git a/samples/fleet_provisioning/fleet_provisioning/main.cpp b/samples/fleet_provisioning/fleet_provisioning/main.cpp index 8e5579ca4..f4f5fdfd5 100644 --- a/samples/fleet_provisioning/fleet_provisioning/main.cpp +++ b/samples/fleet_provisioning/fleet_provisioning/main.cpp @@ -6,8 +6,8 @@ /** * A sample application demonstrating usage of AWS IoT Fleet provisioning. * - * In a real world application you probably don't want to enforce synchronous behavior. But this is a sample console - * application, so all actions, like creating a certificate or registering a thing, are performed in synchronous manner. + * It's easier to follow a synchronous workflow, when events happen one after another. For that reason, this sample + * performs all actions, like connecting to a server or registering a thing, in synchronous manner. */ #include @@ -34,12 +34,12 @@ using namespace Aws::Crt; using namespace Aws::Iotidentity; -static std::string getFileData(std::string const &fileName) +static String getFileData(const String &fileName) { - std::ifstream ifs(fileName); + std::ifstream ifs(fileName.c_str()); std::string str; getline(ifs, str, (char)ifs.eof()); - return str; + return str.c_str(); } /** @@ -437,8 +437,6 @@ int main(int argc, char *argv[]) // Do the global initialization for the API ApiHandle apiHandle; - // Variables for the sample - String csrFile; /** * cmdData is the arguments/input from the command line placed into a single struct for @@ -447,11 +445,6 @@ int main(int argc, char *argv[]) */ Utils::cmdData cmdData = Utils::parseSampleInputFleetProvisioning(argc, argv, &apiHandle); - if (cmdData.input_csrPath != "") - { - csrFile = getFileData(cmdData.input_csrPath.c_str()).c_str(); - } - ConnectionContext connectionContext; auto connection = createConnection(cmdData, connectionContext); @@ -474,13 +467,14 @@ int main(int argc, char *argv[]) // Create certificate. CreateCertificateContext certificateContext; - if (csrFile.empty()) + if (cmdData.input_csrPath != "") { - createKeysAndCertificate(identityClient, certificateContext); + auto csrFile = getFileData(cmdData.input_csrPath); + createCertificateFromCsr(identityClient, certificateContext, csrFile); } else { - createCertificateFromCsr(identityClient, certificateContext, csrFile); + createKeysAndCertificate(identityClient, certificateContext); } // After certificate is obtained, it's time to register a thing. diff --git a/samples/fleet_provisioning/mqtt5_fleet_provisioning/main.cpp b/samples/fleet_provisioning/mqtt5_fleet_provisioning/main.cpp index 4389636f2..c84b8b3b9 100644 --- a/samples/fleet_provisioning/mqtt5_fleet_provisioning/main.cpp +++ b/samples/fleet_provisioning/mqtt5_fleet_provisioning/main.cpp @@ -2,6 +2,14 @@ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0. */ + +/** + * A sample application demonstrating usage of AWS IoT Fleet provisioning with MQTT5 client. + * + * It's easier to follow a synchronous workflow, when events happen one after another. For that reason, this sample + * performs all actions, like connecting to a server or registering a thing, in synchronous manner. + */ + #include #include #include @@ -27,12 +35,12 @@ using namespace Aws::Crt; using namespace Aws::Iotidentity; -static std::string getFileData(std::string const &fileName) +static String getFileData(const String &fileName) { - std::ifstream ifs(fileName); + std::ifstream ifs(fileName.c_str()); std::string str; getline(ifs, str, (char)ifs.eof()); - return str; + return str.c_str(); } /** @@ -421,9 +429,6 @@ int main(int argc, char *argv[]) // Do the global initialization for the API ApiHandle apiHandle; - // Variables for the sample - String csrFile; - RegisterThingResponse registerThingResponse; /** * cmdData is the arguments/input from the command line placed into a single struct for @@ -432,11 +437,6 @@ int main(int argc, char *argv[]) */ Utils::cmdData cmdData = Utils::parseSampleInputFleetProvisioning(argc, argv, &apiHandle); - if (cmdData.input_csrPath != "") - { - csrFile = getFileData(cmdData.input_csrPath.c_str()).c_str(); - } - Mqtt5ClientContext mqtt5ClientContext; auto client = createMqtt5Client(mqtt5ClientContext, cmdData); @@ -459,13 +459,14 @@ int main(int argc, char *argv[]) // Create certificate. CreateCertificateContext certificateContext; - if (csrFile.empty()) + if (cmdData.input_csrPath != "") { - createKeysAndCertificate(identityClient, certificateContext); + auto csrFile = getFileData(cmdData.input_csrPath); + createCertificateFromCsr(identityClient, certificateContext, csrFile); } else { - createCertificateFromCsr(identityClient, certificateContext, csrFile); + createKeysAndCertificate(identityClient, certificateContext); } // After certificate is obtained, it's time to register a thing. From 5718ba217b4e43bb2adbd0d26931b794937584bb Mon Sep 17 00:00:00 2001 From: Igor Abdrakhimov Date: Fri, 12 Jul 2024 09:40:15 -0700 Subject: [PATCH 47/47] Use promise for cert token --- .../fleet_provisioning/main.cpp | 20 +++++++------------ .../mqtt5_fleet_provisioning/main.cpp | 20 +++++++------------ 2 files changed, 14 insertions(+), 26 deletions(-) diff --git a/samples/fleet_provisioning/fleet_provisioning/main.cpp b/samples/fleet_provisioning/fleet_provisioning/main.cpp index f4f5fdfd5..105577ecf 100644 --- a/samples/fleet_provisioning/fleet_provisioning/main.cpp +++ b/samples/fleet_provisioning/fleet_provisioning/main.cpp @@ -59,8 +59,7 @@ struct CreateCertificateContext std::promise pubAckPromise; std::promise acceptedSubAckPromise; std::promise rejectedSubAckPromise; - std::promise tokenReceivedPromise; - String token; + std::promise tokenPromise; }; /** @@ -182,8 +181,7 @@ void createKeysAndCertificate(IotIdentityClient &identityClient, CreateCertifica if (ioErr == AWS_OP_SUCCESS) { fprintf(stdout, "CreateKeysAndCertificateResponse certificateId: %s.\n", response->CertificateId->c_str()); - ctx.token = *response->CertificateOwnershipToken; - ctx.tokenReceivedPromise.set_value(); + ctx.tokenPromise.set_value(*response->CertificateOwnershipToken); } else { @@ -227,9 +225,6 @@ void createKeysAndCertificate(IotIdentityClient &identityClient, CreateCertifica identityClient.PublishCreateKeysAndCertificate( createKeysAndCertificateRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onKeysPublishPubAck); ctx.pubAckPromise.get_future().wait(); - - // Wait for a certificate token. - ctx.tokenReceivedPromise.get_future().wait(); } /** @@ -272,8 +267,7 @@ void createCertificateFromCsr(IotIdentityClient &identityClient, CreateCertifica if (ioErr == AWS_OP_SUCCESS) { fprintf(stdout, "CreateCertificateFromCsrResponse certificateId: %s.\n", response->CertificateId->c_str()); - ctx.token = *response->CertificateOwnershipToken; - ctx.tokenReceivedPromise.set_value(); + ctx.tokenPromise.set_value(*response->CertificateOwnershipToken); } else { @@ -320,9 +314,6 @@ void createCertificateFromCsr(IotIdentityClient &identityClient, CreateCertifica identityClient.PublishCreateCertificateFromCsr( createCertificateFromCsrRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onCsrPublishPubAck); ctx.pubAckPromise.get_future().wait(); - - // Wait for a certificate token. - ctx.tokenReceivedPromise.get_future().wait(); } /** @@ -477,9 +468,12 @@ int main(int argc, char *argv[]) createKeysAndCertificate(identityClient, certificateContext); } + // Wait for a certificate token to be obtained. + auto token = certificateContext.tokenPromise.get_future().get(); + // After certificate is obtained, it's time to register a thing. RegisterThingContext registerThingContext; - registerThing(identityClient, registerThingContext, cmdData, certificateContext.token); + registerThing(identityClient, registerThingContext, cmdData, token); // Disconnect if (connection->Disconnect()) diff --git a/samples/fleet_provisioning/mqtt5_fleet_provisioning/main.cpp b/samples/fleet_provisioning/mqtt5_fleet_provisioning/main.cpp index c84b8b3b9..0670619c2 100644 --- a/samples/fleet_provisioning/mqtt5_fleet_provisioning/main.cpp +++ b/samples/fleet_provisioning/mqtt5_fleet_provisioning/main.cpp @@ -62,8 +62,7 @@ struct CreateCertificateContext std::promise pubAckPromise; std::promise acceptedSubAckPromise; std::promise rejectedSubAckPromise; - std::promise tokenReceivedPromise; - String token; + std::promise tokenPromise; }; /** @@ -174,8 +173,7 @@ void createKeysAndCertificate(IotIdentityClient &identityClient, CreateCertifica if (ioErr == AWS_OP_SUCCESS) { fprintf(stdout, "CreateKeysAndCertificateResponse certificateId: %s.\n", response->CertificateId->c_str()); - ctx.token = *response->CertificateOwnershipToken; - ctx.tokenReceivedPromise.set_value(); + ctx.tokenPromise.set_value(*response->CertificateOwnershipToken); } else { @@ -219,9 +217,6 @@ void createKeysAndCertificate(IotIdentityClient &identityClient, CreateCertifica identityClient.PublishCreateKeysAndCertificate( createKeysAndCertificateRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onKeysPublishPubAck); ctx.pubAckPromise.get_future().wait(); - - // Wait for a certificate token. - ctx.tokenReceivedPromise.get_future().wait(); } /** @@ -264,8 +259,7 @@ void createCertificateFromCsr(IotIdentityClient &identityClient, CreateCertifica if (ioErr == AWS_OP_SUCCESS) { fprintf(stdout, "CreateCertificateFromCsrResponse certificateId: %s.\n", response->CertificateId->c_str()); - ctx.token = *response->CertificateOwnershipToken; - ctx.tokenReceivedPromise.set_value(); + ctx.tokenPromise.set_value(*response->CertificateOwnershipToken); } else { @@ -312,9 +306,6 @@ void createCertificateFromCsr(IotIdentityClient &identityClient, CreateCertifica identityClient.PublishCreateCertificateFromCsr( createCertificateFromCsrRequest, AWS_MQTT_QOS_AT_LEAST_ONCE, onCsrPublishPubAck); ctx.pubAckPromise.get_future().wait(); - - // Wait for a certificate token. - ctx.tokenReceivedPromise.get_future().wait(); } /** @@ -469,9 +460,12 @@ int main(int argc, char *argv[]) createKeysAndCertificate(identityClient, certificateContext); } + // Wait for a certificate token to be obtained. + auto token = certificateContext.tokenPromise.get_future().get(); + // After certificate is obtained, it's time to register a thing. RegisterThingContext registerThingContext; - registerThing(identityClient, registerThingContext, cmdData, certificateContext.token); + registerThing(identityClient, registerThingContext, cmdData, token); // Disconnect if (client->Stop())