aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/restricted/aws/aws-crt-cpp
diff options
context:
space:
mode:
authordakovalkov <dakovalkov@yandex-team.com>2023-12-03 13:33:55 +0300
committerdakovalkov <dakovalkov@yandex-team.com>2023-12-03 14:04:39 +0300
commit2a718325637e5302334b6d0a6430f63168f8dbb3 (patch)
tree64be81080b7df9ec1d86d053a0c394ae53fcf1fe /contrib/restricted/aws/aws-crt-cpp
parente0d94a470142d95c3007e9c5d80380994940664a (diff)
downloadydb-2a718325637e5302334b6d0a6430f63168f8dbb3.tar.gz
Update contrib/libs/aws-sdk-cpp to 1.11.37
Diffstat (limited to 'contrib/restricted/aws/aws-crt-cpp')
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/CMakeLists.darwin-arm64.txt90
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/CMakeLists.darwin-x86_64.txt90
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/CMakeLists.linux-aarch64.txt91
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/CMakeLists.linux-x86_64.txt91
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/CMakeLists.txt19
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/CMakeLists.windows-x86_64.txt90
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/CODE_OF_CONDUCT.md4
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/CONTRIBUTING.md62
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/LICENSE202
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/NOTICE3
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/README.md144
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/include/aws/crt/Allocator.h47
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/include/aws/crt/Api.h218
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/include/aws/crt/Config.h11
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/include/aws/crt/DateTime.h198
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/include/aws/crt/Exports.h39
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/include/aws/crt/ImdsClient.h386
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/include/aws/crt/JsonObject.h406
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/include/aws/crt/Optional.h203
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/include/aws/crt/RefCounted.h68
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/include/aws/crt/StlAllocator.h63
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/include/aws/crt/StringUtils.h21
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/include/aws/crt/StringView.h864
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/include/aws/crt/Types.h165
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/include/aws/crt/UUID.h42
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/include/aws/crt/auth/Credentials.h585
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/include/aws/crt/auth/Signing.h99
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/include/aws/crt/auth/Sigv4Signing.h352
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/include/aws/crt/crypto/HMAC.h150
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/include/aws/crt/crypto/Hash.h168
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/include/aws/crt/endpoints/RuleEngine.h155
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/include/aws/crt/external/cJSON.h309
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/include/aws/crt/http/HttpConnection.h514
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/include/aws/crt/http/HttpConnectionManager.h127
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/include/aws/crt/http/HttpProxyStrategy.h116
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/include/aws/crt/http/HttpRequestResponse.h160
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/include/aws/crt/io/Bootstrap.h104
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/include/aws/crt/io/ChannelHandler.h238
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/include/aws/crt/io/EventLoopGroup.h74
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/include/aws/crt/io/HostResolver.h123
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/include/aws/crt/io/Pkcs11.h116
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/include/aws/crt/io/SocketOptions.h157
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/include/aws/crt/io/Stream.h173
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/include/aws/crt/io/TlsOptions.h453
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/include/aws/crt/io/Uri.h102
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/include/aws/crt/mqtt/Mqtt5Client.h770
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/include/aws/crt/mqtt/Mqtt5Packets.h2286
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/include/aws/crt/mqtt/Mqtt5Types.h120
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/include/aws/crt/mqtt/MqttClient.h532
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/include/aws/iot/Mqtt5Client.h548
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/include/aws/iot/MqttClient.h450
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/include/aws/iot/MqttCommon.h103
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/source/Allocator.cpp21
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/source/Api.cpp405
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/source/DateTime.cpp200
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/source/ImdsClient.cpp457
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/source/JsonObject.cpp596
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/source/StringUtils.cpp15
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/source/Types.cpp103
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/source/UUID.cpp54
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/source/auth/Credentials.cpp478
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/source/auth/Sigv4Signing.cpp274
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/source/crypto/HMAC.cpp173
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/source/crypto/Hash.cpp174
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/source/endpoints/RuleEngine.cpp169
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/source/external/cJSON.cpp3120
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/source/http/HttpConnection.cpp400
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/source/http/HttpConnectionManager.cpp236
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/source/http/HttpProxyStrategy.cpp196
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/source/http/HttpRequestResponse.cpp151
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/source/io/Bootstrap.cpp122
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/source/io/ChannelHandler.cpp217
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/source/io/EventLoopGroup.cpp71
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/source/io/HostResolver.cpp121
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/source/io/Pkcs11.cpp69
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/source/io/SocketOptions.cpp28
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/source/io/Stream.cpp211
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/source/io/TlsOptions.cpp520
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/source/io/Uri.cpp145
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/source/iot/Mqtt5Client.cpp641
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/source/iot/MqttClient.cpp541
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/source/iot/MqttCommon.cpp88
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/source/mqtt/Mqtt5Client.cpp743
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/source/mqtt/Mqtt5Packets.cpp1236
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/source/mqtt/MqttClient.cpp816
-rw-r--r--contrib/restricted/aws/aws-crt-cpp/ya.make102
86 files changed, 25594 insertions, 0 deletions
diff --git a/contrib/restricted/aws/aws-crt-cpp/CMakeLists.darwin-arm64.txt b/contrib/restricted/aws/aws-crt-cpp/CMakeLists.darwin-arm64.txt
new file mode 100644
index 0000000000..6c2e3fb3bc
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/CMakeLists.darwin-arm64.txt
@@ -0,0 +1,90 @@
+
+# This file was generated by the build system used internally in the Yandex monorepo.
+# Only simple modifications are allowed (adding source-files to targets, adding simple properties
+# like target_include_directories). These modifications will be ported to original
+# ya.make files by maintainers. Any complex modifications which can't be ported back to the
+# original buildsystem will not be accepted.
+
+
+
+add_library(restricted-aws-aws-crt-cpp)
+target_compile_options(restricted-aws-aws-crt-cpp PRIVATE
+ -DAWS_AUTH_USE_IMPORT_EXPORT
+ -DAWS_CAL_USE_IMPORT_EXPORT
+ -DAWS_CHECKSUMS_USE_IMPORT_EXPORT
+ -DAWS_COMMON_USE_IMPORT_EXPORT
+ -DAWS_COMPRESSION_USE_IMPORT_EXPORT
+ -DAWS_CRT_CPP_USE_IMPORT_EXPORT
+ -DAWS_EVENT_STREAM_USE_IMPORT_EXPORT
+ -DAWS_HTTP_USE_IMPORT_EXPORT
+ -DAWS_IO_USE_IMPORT_EXPORT
+ -DAWS_MQTT_USE_IMPORT_EXPORT
+ -DAWS_MQTT_WITH_WEBSOCKETS
+ -DAWS_S3_USE_IMPORT_EXPORT
+ -DAWS_SDKUTILS_USE_IMPORT_EXPORT
+ -DAWS_USE_EPOLL
+ -DCJSON_HIDE_SYMBOLS
+ -DS2N_CLONE_SUPPORTED
+ -DS2N_CPUID_AVAILABLE
+ -DS2N_FALL_THROUGH_SUPPORTED
+ -DS2N_FEATURES_AVAILABLE
+ -DS2N_KYBER512R3_AVX2_BMI2
+ -DS2N_LIBCRYPTO_SUPPORTS_EVP_MD5_SHA1_HASH
+ -DS2N_LIBCRYPTO_SUPPORTS_EVP_MD_CTX_SET_PKEY_CTX
+ -DS2N_LIBCRYPTO_SUPPORTS_EVP_RC4
+ -DS2N_MADVISE_SUPPORTED
+ -DS2N_PLATFORM_SUPPORTS_KTLS
+ -DS2N_STACKTRACE
+ -DS2N___RESTRICT__SUPPORTED
+ $<IF:$<CXX_COMPILER_ID:MSVC>,,-Wno-everything>
+)
+target_include_directories(restricted-aws-aws-crt-cpp PUBLIC
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/include
+)
+target_link_libraries(restricted-aws-aws-crt-cpp PUBLIC
+ contrib-libs-cxxsupp
+ restricted-aws-aws-c-auth
+ restricted-aws-aws-c-cal
+ restricted-aws-aws-c-common
+ restricted-aws-aws-c-event-stream
+ restricted-aws-aws-c-http
+ restricted-aws-aws-c-io
+ restricted-aws-aws-c-mqtt
+ restricted-aws-aws-c-s3
+ restricted-aws-aws-c-sdkutils
+)
+target_sources(restricted-aws-aws-crt-cpp PRIVATE
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/Allocator.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/Api.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/DateTime.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/ImdsClient.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/JsonObject.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/StringUtils.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/Types.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/UUID.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/auth/Credentials.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/auth/Sigv4Signing.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/crypto/HMAC.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/crypto/Hash.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/endpoints/RuleEngine.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/external/cJSON.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/http/HttpConnection.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/http/HttpConnectionManager.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/http/HttpProxyStrategy.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/http/HttpRequestResponse.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/io/Bootstrap.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/io/ChannelHandler.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/io/EventLoopGroup.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/io/HostResolver.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/io/Pkcs11.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/io/SocketOptions.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/io/Stream.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/io/TlsOptions.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/io/Uri.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/iot/Mqtt5Client.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/iot/MqttClient.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/iot/MqttCommon.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/mqtt/Mqtt5Client.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/mqtt/Mqtt5Packets.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/mqtt/MqttClient.cpp
+)
diff --git a/contrib/restricted/aws/aws-crt-cpp/CMakeLists.darwin-x86_64.txt b/contrib/restricted/aws/aws-crt-cpp/CMakeLists.darwin-x86_64.txt
new file mode 100644
index 0000000000..6c2e3fb3bc
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/CMakeLists.darwin-x86_64.txt
@@ -0,0 +1,90 @@
+
+# This file was generated by the build system used internally in the Yandex monorepo.
+# Only simple modifications are allowed (adding source-files to targets, adding simple properties
+# like target_include_directories). These modifications will be ported to original
+# ya.make files by maintainers. Any complex modifications which can't be ported back to the
+# original buildsystem will not be accepted.
+
+
+
+add_library(restricted-aws-aws-crt-cpp)
+target_compile_options(restricted-aws-aws-crt-cpp PRIVATE
+ -DAWS_AUTH_USE_IMPORT_EXPORT
+ -DAWS_CAL_USE_IMPORT_EXPORT
+ -DAWS_CHECKSUMS_USE_IMPORT_EXPORT
+ -DAWS_COMMON_USE_IMPORT_EXPORT
+ -DAWS_COMPRESSION_USE_IMPORT_EXPORT
+ -DAWS_CRT_CPP_USE_IMPORT_EXPORT
+ -DAWS_EVENT_STREAM_USE_IMPORT_EXPORT
+ -DAWS_HTTP_USE_IMPORT_EXPORT
+ -DAWS_IO_USE_IMPORT_EXPORT
+ -DAWS_MQTT_USE_IMPORT_EXPORT
+ -DAWS_MQTT_WITH_WEBSOCKETS
+ -DAWS_S3_USE_IMPORT_EXPORT
+ -DAWS_SDKUTILS_USE_IMPORT_EXPORT
+ -DAWS_USE_EPOLL
+ -DCJSON_HIDE_SYMBOLS
+ -DS2N_CLONE_SUPPORTED
+ -DS2N_CPUID_AVAILABLE
+ -DS2N_FALL_THROUGH_SUPPORTED
+ -DS2N_FEATURES_AVAILABLE
+ -DS2N_KYBER512R3_AVX2_BMI2
+ -DS2N_LIBCRYPTO_SUPPORTS_EVP_MD5_SHA1_HASH
+ -DS2N_LIBCRYPTO_SUPPORTS_EVP_MD_CTX_SET_PKEY_CTX
+ -DS2N_LIBCRYPTO_SUPPORTS_EVP_RC4
+ -DS2N_MADVISE_SUPPORTED
+ -DS2N_PLATFORM_SUPPORTS_KTLS
+ -DS2N_STACKTRACE
+ -DS2N___RESTRICT__SUPPORTED
+ $<IF:$<CXX_COMPILER_ID:MSVC>,,-Wno-everything>
+)
+target_include_directories(restricted-aws-aws-crt-cpp PUBLIC
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/include
+)
+target_link_libraries(restricted-aws-aws-crt-cpp PUBLIC
+ contrib-libs-cxxsupp
+ restricted-aws-aws-c-auth
+ restricted-aws-aws-c-cal
+ restricted-aws-aws-c-common
+ restricted-aws-aws-c-event-stream
+ restricted-aws-aws-c-http
+ restricted-aws-aws-c-io
+ restricted-aws-aws-c-mqtt
+ restricted-aws-aws-c-s3
+ restricted-aws-aws-c-sdkutils
+)
+target_sources(restricted-aws-aws-crt-cpp PRIVATE
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/Allocator.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/Api.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/DateTime.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/ImdsClient.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/JsonObject.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/StringUtils.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/Types.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/UUID.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/auth/Credentials.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/auth/Sigv4Signing.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/crypto/HMAC.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/crypto/Hash.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/endpoints/RuleEngine.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/external/cJSON.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/http/HttpConnection.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/http/HttpConnectionManager.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/http/HttpProxyStrategy.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/http/HttpRequestResponse.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/io/Bootstrap.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/io/ChannelHandler.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/io/EventLoopGroup.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/io/HostResolver.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/io/Pkcs11.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/io/SocketOptions.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/io/Stream.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/io/TlsOptions.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/io/Uri.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/iot/Mqtt5Client.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/iot/MqttClient.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/iot/MqttCommon.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/mqtt/Mqtt5Client.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/mqtt/Mqtt5Packets.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/mqtt/MqttClient.cpp
+)
diff --git a/contrib/restricted/aws/aws-crt-cpp/CMakeLists.linux-aarch64.txt b/contrib/restricted/aws/aws-crt-cpp/CMakeLists.linux-aarch64.txt
new file mode 100644
index 0000000000..04fd641c30
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/CMakeLists.linux-aarch64.txt
@@ -0,0 +1,91 @@
+
+# This file was generated by the build system used internally in the Yandex monorepo.
+# Only simple modifications are allowed (adding source-files to targets, adding simple properties
+# like target_include_directories). These modifications will be ported to original
+# ya.make files by maintainers. Any complex modifications which can't be ported back to the
+# original buildsystem will not be accepted.
+
+
+
+add_library(restricted-aws-aws-crt-cpp)
+target_compile_options(restricted-aws-aws-crt-cpp PRIVATE
+ -DAWS_AUTH_USE_IMPORT_EXPORT
+ -DAWS_CAL_USE_IMPORT_EXPORT
+ -DAWS_CHECKSUMS_USE_IMPORT_EXPORT
+ -DAWS_COMMON_USE_IMPORT_EXPORT
+ -DAWS_COMPRESSION_USE_IMPORT_EXPORT
+ -DAWS_CRT_CPP_USE_IMPORT_EXPORT
+ -DAWS_EVENT_STREAM_USE_IMPORT_EXPORT
+ -DAWS_HTTP_USE_IMPORT_EXPORT
+ -DAWS_IO_USE_IMPORT_EXPORT
+ -DAWS_MQTT_USE_IMPORT_EXPORT
+ -DAWS_MQTT_WITH_WEBSOCKETS
+ -DAWS_S3_USE_IMPORT_EXPORT
+ -DAWS_SDKUTILS_USE_IMPORT_EXPORT
+ -DAWS_USE_EPOLL
+ -DCJSON_HIDE_SYMBOLS
+ -DS2N_CLONE_SUPPORTED
+ -DS2N_CPUID_AVAILABLE
+ -DS2N_FALL_THROUGH_SUPPORTED
+ -DS2N_FEATURES_AVAILABLE
+ -DS2N_KYBER512R3_AVX2_BMI2
+ -DS2N_LIBCRYPTO_SUPPORTS_EVP_MD5_SHA1_HASH
+ -DS2N_LIBCRYPTO_SUPPORTS_EVP_MD_CTX_SET_PKEY_CTX
+ -DS2N_LIBCRYPTO_SUPPORTS_EVP_RC4
+ -DS2N_MADVISE_SUPPORTED
+ -DS2N_PLATFORM_SUPPORTS_KTLS
+ -DS2N_STACKTRACE
+ -DS2N___RESTRICT__SUPPORTED
+ $<IF:$<CXX_COMPILER_ID:MSVC>,,-Wno-everything>
+)
+target_include_directories(restricted-aws-aws-crt-cpp PUBLIC
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/include
+)
+target_link_libraries(restricted-aws-aws-crt-cpp PUBLIC
+ contrib-libs-linux-headers
+ contrib-libs-cxxsupp
+ restricted-aws-aws-c-auth
+ restricted-aws-aws-c-cal
+ restricted-aws-aws-c-common
+ restricted-aws-aws-c-event-stream
+ restricted-aws-aws-c-http
+ restricted-aws-aws-c-io
+ restricted-aws-aws-c-mqtt
+ restricted-aws-aws-c-s3
+ restricted-aws-aws-c-sdkutils
+)
+target_sources(restricted-aws-aws-crt-cpp PRIVATE
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/Allocator.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/Api.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/DateTime.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/ImdsClient.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/JsonObject.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/StringUtils.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/Types.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/UUID.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/auth/Credentials.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/auth/Sigv4Signing.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/crypto/HMAC.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/crypto/Hash.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/endpoints/RuleEngine.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/external/cJSON.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/http/HttpConnection.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/http/HttpConnectionManager.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/http/HttpProxyStrategy.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/http/HttpRequestResponse.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/io/Bootstrap.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/io/ChannelHandler.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/io/EventLoopGroup.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/io/HostResolver.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/io/Pkcs11.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/io/SocketOptions.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/io/Stream.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/io/TlsOptions.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/io/Uri.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/iot/Mqtt5Client.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/iot/MqttClient.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/iot/MqttCommon.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/mqtt/Mqtt5Client.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/mqtt/Mqtt5Packets.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/mqtt/MqttClient.cpp
+)
diff --git a/contrib/restricted/aws/aws-crt-cpp/CMakeLists.linux-x86_64.txt b/contrib/restricted/aws/aws-crt-cpp/CMakeLists.linux-x86_64.txt
new file mode 100644
index 0000000000..04fd641c30
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/CMakeLists.linux-x86_64.txt
@@ -0,0 +1,91 @@
+
+# This file was generated by the build system used internally in the Yandex monorepo.
+# Only simple modifications are allowed (adding source-files to targets, adding simple properties
+# like target_include_directories). These modifications will be ported to original
+# ya.make files by maintainers. Any complex modifications which can't be ported back to the
+# original buildsystem will not be accepted.
+
+
+
+add_library(restricted-aws-aws-crt-cpp)
+target_compile_options(restricted-aws-aws-crt-cpp PRIVATE
+ -DAWS_AUTH_USE_IMPORT_EXPORT
+ -DAWS_CAL_USE_IMPORT_EXPORT
+ -DAWS_CHECKSUMS_USE_IMPORT_EXPORT
+ -DAWS_COMMON_USE_IMPORT_EXPORT
+ -DAWS_COMPRESSION_USE_IMPORT_EXPORT
+ -DAWS_CRT_CPP_USE_IMPORT_EXPORT
+ -DAWS_EVENT_STREAM_USE_IMPORT_EXPORT
+ -DAWS_HTTP_USE_IMPORT_EXPORT
+ -DAWS_IO_USE_IMPORT_EXPORT
+ -DAWS_MQTT_USE_IMPORT_EXPORT
+ -DAWS_MQTT_WITH_WEBSOCKETS
+ -DAWS_S3_USE_IMPORT_EXPORT
+ -DAWS_SDKUTILS_USE_IMPORT_EXPORT
+ -DAWS_USE_EPOLL
+ -DCJSON_HIDE_SYMBOLS
+ -DS2N_CLONE_SUPPORTED
+ -DS2N_CPUID_AVAILABLE
+ -DS2N_FALL_THROUGH_SUPPORTED
+ -DS2N_FEATURES_AVAILABLE
+ -DS2N_KYBER512R3_AVX2_BMI2
+ -DS2N_LIBCRYPTO_SUPPORTS_EVP_MD5_SHA1_HASH
+ -DS2N_LIBCRYPTO_SUPPORTS_EVP_MD_CTX_SET_PKEY_CTX
+ -DS2N_LIBCRYPTO_SUPPORTS_EVP_RC4
+ -DS2N_MADVISE_SUPPORTED
+ -DS2N_PLATFORM_SUPPORTS_KTLS
+ -DS2N_STACKTRACE
+ -DS2N___RESTRICT__SUPPORTED
+ $<IF:$<CXX_COMPILER_ID:MSVC>,,-Wno-everything>
+)
+target_include_directories(restricted-aws-aws-crt-cpp PUBLIC
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/include
+)
+target_link_libraries(restricted-aws-aws-crt-cpp PUBLIC
+ contrib-libs-linux-headers
+ contrib-libs-cxxsupp
+ restricted-aws-aws-c-auth
+ restricted-aws-aws-c-cal
+ restricted-aws-aws-c-common
+ restricted-aws-aws-c-event-stream
+ restricted-aws-aws-c-http
+ restricted-aws-aws-c-io
+ restricted-aws-aws-c-mqtt
+ restricted-aws-aws-c-s3
+ restricted-aws-aws-c-sdkutils
+)
+target_sources(restricted-aws-aws-crt-cpp PRIVATE
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/Allocator.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/Api.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/DateTime.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/ImdsClient.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/JsonObject.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/StringUtils.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/Types.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/UUID.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/auth/Credentials.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/auth/Sigv4Signing.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/crypto/HMAC.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/crypto/Hash.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/endpoints/RuleEngine.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/external/cJSON.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/http/HttpConnection.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/http/HttpConnectionManager.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/http/HttpProxyStrategy.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/http/HttpRequestResponse.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/io/Bootstrap.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/io/ChannelHandler.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/io/EventLoopGroup.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/io/HostResolver.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/io/Pkcs11.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/io/SocketOptions.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/io/Stream.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/io/TlsOptions.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/io/Uri.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/iot/Mqtt5Client.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/iot/MqttClient.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/iot/MqttCommon.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/mqtt/Mqtt5Client.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/mqtt/Mqtt5Packets.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/mqtt/MqttClient.cpp
+)
diff --git a/contrib/restricted/aws/aws-crt-cpp/CMakeLists.txt b/contrib/restricted/aws/aws-crt-cpp/CMakeLists.txt
new file mode 100644
index 0000000000..2dce3a77fe
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/CMakeLists.txt
@@ -0,0 +1,19 @@
+
+# This file was generated by the build system used internally in the Yandex monorepo.
+# Only simple modifications are allowed (adding source-files to targets, adding simple properties
+# like target_include_directories). These modifications will be ported to original
+# ya.make files by maintainers. Any complex modifications which can't be ported back to the
+# original buildsystem will not be accepted.
+
+
+if (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" AND NOT HAVE_CUDA)
+ include(CMakeLists.linux-aarch64.txt)
+elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64")
+ include(CMakeLists.darwin-x86_64.txt)
+elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64")
+ include(CMakeLists.darwin-arm64.txt)
+elseif (WIN32 AND CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64" AND NOT HAVE_CUDA)
+ include(CMakeLists.windows-x86_64.txt)
+elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND NOT HAVE_CUDA)
+ include(CMakeLists.linux-x86_64.txt)
+endif()
diff --git a/contrib/restricted/aws/aws-crt-cpp/CMakeLists.windows-x86_64.txt b/contrib/restricted/aws/aws-crt-cpp/CMakeLists.windows-x86_64.txt
new file mode 100644
index 0000000000..6c2e3fb3bc
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/CMakeLists.windows-x86_64.txt
@@ -0,0 +1,90 @@
+
+# This file was generated by the build system used internally in the Yandex monorepo.
+# Only simple modifications are allowed (adding source-files to targets, adding simple properties
+# like target_include_directories). These modifications will be ported to original
+# ya.make files by maintainers. Any complex modifications which can't be ported back to the
+# original buildsystem will not be accepted.
+
+
+
+add_library(restricted-aws-aws-crt-cpp)
+target_compile_options(restricted-aws-aws-crt-cpp PRIVATE
+ -DAWS_AUTH_USE_IMPORT_EXPORT
+ -DAWS_CAL_USE_IMPORT_EXPORT
+ -DAWS_CHECKSUMS_USE_IMPORT_EXPORT
+ -DAWS_COMMON_USE_IMPORT_EXPORT
+ -DAWS_COMPRESSION_USE_IMPORT_EXPORT
+ -DAWS_CRT_CPP_USE_IMPORT_EXPORT
+ -DAWS_EVENT_STREAM_USE_IMPORT_EXPORT
+ -DAWS_HTTP_USE_IMPORT_EXPORT
+ -DAWS_IO_USE_IMPORT_EXPORT
+ -DAWS_MQTT_USE_IMPORT_EXPORT
+ -DAWS_MQTT_WITH_WEBSOCKETS
+ -DAWS_S3_USE_IMPORT_EXPORT
+ -DAWS_SDKUTILS_USE_IMPORT_EXPORT
+ -DAWS_USE_EPOLL
+ -DCJSON_HIDE_SYMBOLS
+ -DS2N_CLONE_SUPPORTED
+ -DS2N_CPUID_AVAILABLE
+ -DS2N_FALL_THROUGH_SUPPORTED
+ -DS2N_FEATURES_AVAILABLE
+ -DS2N_KYBER512R3_AVX2_BMI2
+ -DS2N_LIBCRYPTO_SUPPORTS_EVP_MD5_SHA1_HASH
+ -DS2N_LIBCRYPTO_SUPPORTS_EVP_MD_CTX_SET_PKEY_CTX
+ -DS2N_LIBCRYPTO_SUPPORTS_EVP_RC4
+ -DS2N_MADVISE_SUPPORTED
+ -DS2N_PLATFORM_SUPPORTS_KTLS
+ -DS2N_STACKTRACE
+ -DS2N___RESTRICT__SUPPORTED
+ $<IF:$<CXX_COMPILER_ID:MSVC>,,-Wno-everything>
+)
+target_include_directories(restricted-aws-aws-crt-cpp PUBLIC
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/include
+)
+target_link_libraries(restricted-aws-aws-crt-cpp PUBLIC
+ contrib-libs-cxxsupp
+ restricted-aws-aws-c-auth
+ restricted-aws-aws-c-cal
+ restricted-aws-aws-c-common
+ restricted-aws-aws-c-event-stream
+ restricted-aws-aws-c-http
+ restricted-aws-aws-c-io
+ restricted-aws-aws-c-mqtt
+ restricted-aws-aws-c-s3
+ restricted-aws-aws-c-sdkutils
+)
+target_sources(restricted-aws-aws-crt-cpp PRIVATE
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/Allocator.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/Api.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/DateTime.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/ImdsClient.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/JsonObject.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/StringUtils.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/Types.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/UUID.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/auth/Credentials.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/auth/Sigv4Signing.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/crypto/HMAC.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/crypto/Hash.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/endpoints/RuleEngine.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/external/cJSON.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/http/HttpConnection.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/http/HttpConnectionManager.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/http/HttpProxyStrategy.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/http/HttpRequestResponse.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/io/Bootstrap.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/io/ChannelHandler.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/io/EventLoopGroup.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/io/HostResolver.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/io/Pkcs11.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/io/SocketOptions.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/io/Stream.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/io/TlsOptions.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/io/Uri.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/iot/Mqtt5Client.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/iot/MqttClient.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/iot/MqttCommon.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/mqtt/Mqtt5Client.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/mqtt/Mqtt5Packets.cpp
+ ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/aws-crt-cpp/source/mqtt/MqttClient.cpp
+)
diff --git a/contrib/restricted/aws/aws-crt-cpp/CODE_OF_CONDUCT.md b/contrib/restricted/aws/aws-crt-cpp/CODE_OF_CONDUCT.md
new file mode 100644
index 0000000000..3b64466870
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/CODE_OF_CONDUCT.md
@@ -0,0 +1,4 @@
+## Code of Conduct
+This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct).
+For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact
+opensource-codeofconduct@amazon.com with any additional questions or comments.
diff --git a/contrib/restricted/aws/aws-crt-cpp/CONTRIBUTING.md b/contrib/restricted/aws/aws-crt-cpp/CONTRIBUTING.md
new file mode 100644
index 0000000000..666c37d6c0
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/CONTRIBUTING.md
@@ -0,0 +1,62 @@
+# Contributing Guidelines
+
+Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional
+documentation, we greatly value feedback and contributions from our community.
+
+Please read through this document before submitting any issues or pull requests to ensure we have all the necessary
+information to effectively respond to your bug report or contribution.
+
+
+## Reporting Bugs/Feature Requests
+
+We welcome you to use the GitHub issue tracker to report bugs or suggest features.
+
+When filing an issue, please check [existing open](https://github.com/awslabs/aws-crt-cpp/issues), or [recently closed](https://github.com/awslabs/aws-crt-cpp/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aclosed%20), issues to make sure somebody else hasn't already
+reported the issue. Please try to include as much information as you can. Details like these are incredibly useful:
+
+* A reproducible test case or series of steps
+* The version of our code being used
+* Any modifications you've made relevant to the bug
+* Anything unusual about your environment or deployment
+
+
+## Contributing via Pull Requests
+Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that:
+
+1. You are working against the latest source on the *main* branch.
+2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already.
+3. You open an issue to discuss any significant work - we would hate for your time to be wasted.
+
+To send us a pull request, please:
+
+1. Fork the repository.
+2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change.
+3. Ensure local tests pass.
+4. Commit to your fork using clear commit messages.
+5. Send us a pull request, answering any default questions in the pull request interface.
+6. Wait for a repository collaborator to look at your pull request, run the automated tests, and review. If additional changes or discussion is needed, a collaborator will get back to you, so please stay involved in the conversation.
+ * Note: pull requests from forks will not run the automated tests without collaborator involvement for security reasons. If you make a pull request and see that the tests are pending, this is normal and expected.
+
+GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and
+[creating a pull request](https://help.github.com/articles/creating-a-pull-request/).
+
+
+## Finding contributions to work on
+Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any ['help wanted'](https://github.com/awslabs/aws-crt-cpp/labels/help%20wanted) issues is a great place to start.
+
+
+## Code of Conduct
+This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct).
+For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact
+opensource-codeofconduct@amazon.com with any additional questions or comments.
+
+
+## Security issue notifications
+If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue.
+
+
+## Licensing
+
+See the [LICENSE](https://github.com/awslabs/aws-crt-cpp/blob/main/LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution.
+
+We may ask you to sign a [Contributor License Agreement (CLA)](http://en.wikipedia.org/wiki/Contributor_License_Agreement) for larger changes.
diff --git a/contrib/restricted/aws/aws-crt-cpp/LICENSE b/contrib/restricted/aws/aws-crt-cpp/LICENSE
new file mode 100644
index 0000000000..d645695673
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/contrib/restricted/aws/aws-crt-cpp/NOTICE b/contrib/restricted/aws/aws-crt-cpp/NOTICE
new file mode 100644
index 0000000000..8b820137a0
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/NOTICE
@@ -0,0 +1,3 @@
+AWS Crt Cpp
+Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+SPDX-License-Identifier: Apache-2.0.
diff --git a/contrib/restricted/aws/aws-crt-cpp/README.md b/contrib/restricted/aws/aws-crt-cpp/README.md
new file mode 100644
index 0000000000..ba5adf52e3
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/README.md
@@ -0,0 +1,144 @@
+## AWS Crt Cpp
+
+C++ wrapper around the aws-c-* libraries. Provides Cross-Platform Transport Protocols and SSL/TLS implementations for C++.
+
+### Documentation
+
+https://awslabs.github.io/aws-crt-cpp/
+
+### Currently Included:
+
+* aws-c-common: Cross-platform primitives and data structures.
+* aws-c-io: Cross-platform event-loops, non-blocking I/O, and TLS implementations.
+* aws-c-mqtt: MQTT client.
+* aws-c-auth: Auth signers such as Aws-auth sigv4
+* aws-c-http: HTTP 1.1 client, and websockets (H2 coming soon)
+* aws-checksums: Cross-Platform HW accelerated CRC32c and CRC32 with fallback to efficient SW implementations.
+* aws-c-event-stream: C99 implementation of the vnd.amazon.event-stream content-type.
+
+More protocols and utilities are coming soon, so stay tuned.
+
+## Building
+
+The C99 libraries are already included for your convenience as submodules.
+You should perform a recursive clone `git clone --recursive` or initialize the submodules via
+`git submodule update --init`. These dependencies are compiled by CMake as part of the build process.
+
+If you want to manage these dependencies manually (e.g. you're using them in other projects), configure CMake with
+`-DBUILD_DEPS=OFF` and `-DCMAKE_PREFIX_PATH=<install>` pointing to the absolute path where you have them installed.
+
+### MSVC
+If you want to use a statically linked MSVCRT (/MT, /MTd), you can add `-DSTATIC_CRT=ON` to your cmake configuration.
+
+### Apple Silicon (aka M1) and Universal Binaries
+
+aws-crt-cpp supports both `arm64` and `x86_64` architectures.
+Configure cmake with `-DCMAKE_OSX_ARCHITECTURES=arm64` to target Apple silicon,
+or `-DCMAKE_OSX_ARCHITECTURES=x86_64` to target Intel.
+If you wish to create a [universal binary](https://developer.apple.com/documentation/apple-silicon/building-a-universal-macos-binary),
+you should use `lipo` to combine the `x86_64` and `arm64` binaries.
+For example: `lipo -create -output universal_app x86_app arm_app`
+
+You SHOULD NOT build for both architectures simultaneously via `-DCMAKE_OSX_ARCHITECTURES="arm64;x86_64"`.
+aws-crt-cpp has not been tested in this configuration.
+aws-crt-cpp's cmake configuration scripts are known to get confused by this,
+and will not enable optimizations that would benefit an independent `arm64` or `x86_64` build.
+
+### OpenSSL and LibCrypto (Unix only)
+
+If your application uses OpenSSL, configure with `-DUSE_OPENSSL=ON`.
+
+aws-crt-cpp does not use OpenSSL for TLS.
+On Apple and Windows devices, the OS's default TLS library is used.
+On Unix devices, [s2n-tls](https://github.com/aws/s2n-tls) is used.
+But s2n-tls uses libcrypto, the cryptography math library bundled with OpenSSL.
+To simplify the build process, the source code for s2n-tls and libcrypto are
+included as git submodules and built along with aws-crt-cpp.
+But if your application is also loading the system installation of OpenSSL
+(i.e. your application uses libcurl which uses libssl which uses libcrypto)
+there may be crashes as the application tries to use two different versions of libcrypto at once.
+
+Setting `-DUSE_OPENSSL=ON` will cause aws-crt-cpp to link against your system's existing `libcrypto`,
+instead of building its own copy.
+
+You can ignore all this on Windows and Apple platforms, where aws-crt-cpp uses the OS's default libraries for TLS and cryptography math.
+
+## Dependencies?
+
+There are no non-OS dependencies that AWS does not own, maintain, and ship.
+
+## Common Usage
+
+To do anything with IO, you'll need to create a few objects that will be used by the rest of the library.
+
+For example:
+
+````
+ Aws::Crt::LoadErrorStrings();
+````
+
+Will load error strings for debugging purposes. Since the C libraries use error codes, this will allow you to print the corresponding
+error string for each error code.
+
+````
+ Aws::Crt::ApiHandle apiHandle;
+````
+This performs one-time static initialization of the library. You'll need it to do anything, so don't forget to create one.
+
+````
+ Aws::Crt::Io::EventLoopGroup eventLoopGroup(<number of threads you want>);
+````
+To use any of our APIs that perform IO you'll need at least one event-loop. An event-loop group is a collection of event-loops that
+protocol implementations will load balance across. If you won't have very many connections (say, more than 100 or so), then you
+most likely only want 1 thread. In this case, you want to pass a single instance of this to every client or server implementation of a protocol
+you use in your application. In some advanced use cases, you may want to reserve a thread for different types of IO tasks. In that case, you can have an
+instance of this class for each reservation.
+
+````
+ Aws::Crt::Io::TlsContextOptions tlsCtxOptions =
+ Aws::Crt::Io::TlsContextOptions::InitClientWithMtls(certificatePath.c_str(), keyPath.c_str());
+ /*
+ * If we have a custom CA, set that up here.
+ */
+ if (!caFile.empty())
+ {
+ tlsCtxOptions.OverrideDefaultTrustStore(nullptr, caFile.c_str());
+ }
+
+ uint16_t port = 8883;
+ if (Io::TlsContextOptions::IsAlpnSupported())
+ {
+ /*
+ * Use ALPN to negotiate the mqtt protocol on a normal
+ * TLS port if possible.
+ */
+ tlsCtxOptions.SetAlpnList("x-amzn-mqtt-ca");
+ port = 443;
+ }
+
+ Aws::Crt::Io::TlsContext tlsCtx(tlsCtxOptions, Io::TlsMode::CLIENT);
+````
+
+If you plan on using TLS, you will need a TlsContext. These are NOT CHEAP, so use as few as possible to perform your task.
+If you're in client mode and not doing anything fancy (e.g. mutual TLS), then you can likely get away with using a single
+instance for the entire application.
+
+````
+Aws::Crt::Io::ClientBootstrap bootstrap(eventLoopGroup);
+````
+
+Lastly, you will need a client or server bootstrap to use a client or server protocol implementation. Since everything is
+non-blocking and event driven, this handles most of the "callback hell" inherent in the design. Assuming you aren't partitioning
+threads for particular use-cases, you can have a single instance of this that you pass to multiple clients.
+
+## Mac-Only TLS Behavior
+
+Please note that on Mac, once a private key is used with a certificate, that certificate-key pair is imported into the Mac Keychain. All subsequent uses of that certificate will use the stored private key and ignore anything passed in programmatically. Beginning in v0.8.10, when a stored private key from the Keychain is used, the following will be logged at the "info" log level:
+
+```
+static: certificate has an existing certificate-key pair that was previously imported into the Keychain. Using key from Keychain instead of the one provided.
+```
+
+## License
+
+This library is licensed under the Apache 2.0 License.
diff --git a/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/Allocator.h b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/Allocator.h
new file mode 100644
index 0000000000..d0193a24b7
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/Allocator.h
@@ -0,0 +1,47 @@
+#pragma once
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+
+#include <aws/common/common.h>
+#include <aws/crt/Exports.h>
+
+namespace Aws
+{
+ namespace Crt
+ {
+ using Allocator = aws_allocator;
+
+ /**
+ * Each object from this library can use an explicit allocator.
+ * If you construct an object without specifying an allocator,
+ * then THIS allocator is used instead.
+ *
+ * You can customize this allocator when initializing
+ * \ref ApiHandle::ApiHandle(Allocator*) "ApiHandle".
+ */
+ AWS_CRT_CPP_API Allocator *ApiAllocator() noexcept;
+
+ /**
+ * Returns the default implementation of an Allocator.
+ *
+ * If you initialize \ref ApiHandle::ApiHandle(Allocator*) "ApiHandle"
+ * without specifying a custom allocator, then this implementation is used.
+ */
+ AWS_CRT_CPP_API Allocator *DefaultAllocatorImplementation() noexcept;
+
+ /**
+ * @deprecated Use DefaultAllocatorImplementation() instead.
+ * DefaultAllocator() is too easily confused with ApiAllocator().
+ */
+ AWS_CRT_CPP_API Allocator *DefaultAllocator() noexcept;
+
+ /**
+ * @deprecated Use ApiAllocator() instead, to avoid issues with delay-loaded DLLs.
+ * https://github.com/aws/aws-sdk-cpp/issues/1960
+ */
+ extern AWS_CRT_CPP_API Allocator *g_allocator;
+
+ } // namespace Crt
+} // namespace Aws
diff --git a/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/Api.h b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/Api.h
new file mode 100644
index 0000000000..74fde424cf
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/Api.h
@@ -0,0 +1,218 @@
+#pragma once
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+#include <aws/crt/Types.h>
+#include <aws/crt/crypto/HMAC.h>
+#include <aws/crt/crypto/Hash.h>
+#include <aws/crt/mqtt/Mqtt5Client.h>
+#include <aws/crt/mqtt/MqttClient.h>
+
+#include <aws/common/logging.h>
+
+namespace Aws
+{
+ namespace Crt
+ {
+ /**
+ * Detail level control for logging output
+ */
+ enum class LogLevel
+ {
+ None = AWS_LL_NONE,
+ Fatal = AWS_LL_FATAL,
+ Error = AWS_LL_ERROR,
+ Warn = AWS_LL_WARN,
+ Info = AWS_LL_INFO,
+ Debug = AWS_LL_DEBUG,
+ Trace = AWS_LL_TRACE,
+
+ Count
+ };
+
+ /**
+ * Should the API Handle destructor block on all shutdown/thread completion logic or not?
+ */
+ enum class ApiHandleShutdownBehavior
+ {
+ Blocking,
+ NonBlocking
+ };
+
+ /**
+ * A singleton object representing the init/cleanup state of the entire CRT. It's invalid to have more than one
+ * active simultaneously and it's also invalid to use CRT functionality without one active.
+ */
+ class AWS_CRT_CPP_API ApiHandle
+ {
+ public:
+ /**
+ * Customize the ApiAllocator(), which is be used by any objects
+ * constructed without an explicit allocator.
+ */
+ ApiHandle(Allocator *allocator) noexcept;
+ ApiHandle() noexcept;
+ ~ApiHandle();
+ ApiHandle(const ApiHandle &) = delete;
+ ApiHandle(ApiHandle &&) = delete;
+ ApiHandle &operator=(const ApiHandle &) = delete;
+ ApiHandle &operator=(ApiHandle &&) = delete;
+
+ /**
+ * Initialize logging in awscrt.
+ * @param level: Display messages of this importance and higher. LogLevel.NoLogs will disable
+ * logging.
+ * @param filename: Logging destination, a file path from the disk.
+ */
+ void InitializeLogging(LogLevel level, const char *filename);
+
+ /**
+ * Initialize logging in awscrt.
+ * @param level: Display messages of this importance and higher. LogLevel.NoLogs will disable
+ * logging.
+ * @param fp: The FILE object for logging destination.
+ */
+ void InitializeLogging(LogLevel level, FILE *fp);
+
+ /**
+ * Configures the shutdown behavior of the api handle instance
+ * @param behavior desired shutdown behavior
+ */
+ void SetShutdownBehavior(ApiHandleShutdownBehavior behavior);
+
+ /**
+ * BYO_CRYPTO: set callback for creating MD5 hashes.
+ * If using BYO_CRYPTO, you must call this.
+ */
+ void SetBYOCryptoNewMD5Callback(Crypto::CreateHashCallback &&callback);
+
+ /**
+ * BYO_CRYPTO: set callback for creating SHA256 hashes.
+ * If using BYO_CRYPTO, you must call this.
+ */
+ void SetBYOCryptoNewSHA256Callback(Crypto::CreateHashCallback &&callback);
+
+ /**
+ * BYO_CRYPTO: set callback for creating Streaming SHA256 HMAC objects.
+ * If using BYO_CRYPTO, you must call this.
+ */
+ void SetBYOCryptoNewSHA256HMACCallback(Crypto::CreateHMACCallback &&callback);
+
+ /**
+ * BYO_CRYPTO: set callback for creating a ClientTlsChannelHandler.
+ * If using BYO_CRYPTO, you must call this prior to creating any client channels in the
+ * application.
+ */
+ void SetBYOCryptoClientTlsCallback(Io::NewClientTlsHandlerCallback &&callback);
+
+ /**
+ * BYO_CRYPTO: set callbacks for the TlsContext.
+ * If using BYO_CRYPTO, you need to call this function prior to creating a TlsContext.
+ *
+ * @param newCallback Create custom implementation object, to be stored inside TlsContext.
+ * Return nullptr if failure occurs.
+ * @param deleteCallback Destroy object that was created by newCallback.
+ * @param alpnCallback Return whether ALPN is supported.
+ */
+ void SetBYOCryptoTlsContextCallbacks(
+ Io::NewTlsContextImplCallback &&newCallback,
+ Io::DeleteTlsContextImplCallback &&deleteCallback,
+ Io::IsTlsAlpnSupportedCallback &&alpnCallback);
+
+ /// @private
+ static const Io::NewTlsContextImplCallback &GetBYOCryptoNewTlsContextImplCallback();
+ /// @private
+ static const Io::DeleteTlsContextImplCallback &GetBYOCryptoDeleteTlsContextImplCallback();
+ /// @private
+ static const Io::IsTlsAlpnSupportedCallback &GetBYOCryptoIsTlsAlpnSupportedCallback();
+
+ /**
+ * Gets the static default ClientBootstrap, creating it if necessary.
+ *
+ * This default will be used when a ClientBootstrap is not explicitly passed but is needed
+ * to allow the process to function. An example of this would be in the MQTT connection creation workflow.
+ * The default ClientBootstrap will use the default EventLoopGroup and HostResolver, creating them if
+ * necessary.
+ *
+ * The default ClientBootstrap will be automatically managed and released by the API handle when it's
+ * resources are being freed, not requiring any manual memory management.
+ *
+ * @return ClientBootstrap* A pointer to the static default ClientBootstrap
+ */
+ static Io::ClientBootstrap *GetOrCreateStaticDefaultClientBootstrap();
+
+ /**
+ * Gets the static default EventLoopGroup, creating it if necessary.
+ *
+ * This default will be used when a EventLoopGroup is not explicitly passed but is needed
+ * to allow the process to function. An example of this would be in the MQTT connection creation workflow.
+ *
+ * The EventLoopGroup will automatically pick a default number of threads based on the system. You can
+ * manually adjust the number of threads being used by creating a EventLoopGroup and passing it through
+ * the SetDefaultEventLoopGroup function.
+ *
+ * The default EventLoopGroup will be automatically managed and released by the API handle when it's
+ * resources are being freed, not requiring any manual memory management.
+ *
+ * @return EventLoopGroup* A pointer to the static default EventLoopGroup
+ */
+ static Io::EventLoopGroup *GetOrCreateStaticDefaultEventLoopGroup();
+
+ /**
+ * Gets the static default HostResolver, creating it if necessary.
+ *
+ * This default will be used when a HostResolver is not explicitly passed but is needed
+ * to allow the process to function. An example of this would be in the MQTT connection creation workflow.
+ *
+ * The HostResolver will be set to have a maximum of 8 entries by default. You can
+ * manually adjust the maximum number of entries being used by creating a HostResolver and passing it
+ * through the SetDefaultEventLoopGroup function.
+ *
+ * The default HostResolver will be automatically managed and released by the API handle when it's
+ * resources are being freed, not requiring any manual memory management.
+ *
+ * @return HostResolver* A pointer to the static default HostResolver
+ */
+ static Io::HostResolver *GetOrCreateStaticDefaultHostResolver();
+
+ private:
+ void InitializeLoggingCommon(struct aws_logger_standard_options &options);
+
+ aws_logger m_logger;
+
+ ApiHandleShutdownBehavior m_shutdownBehavior;
+
+ static Io::ClientBootstrap *s_static_bootstrap;
+ static std::mutex s_lock_client_bootstrap;
+ static void ReleaseStaticDefaultClientBootstrap();
+
+ static Io::EventLoopGroup *s_static_event_loop_group;
+ static std::mutex s_lock_event_loop_group;
+ static void ReleaseStaticDefaultEventLoopGroup();
+
+ static int s_host_resolver_default_max_hosts;
+ static Io::HostResolver *s_static_default_host_resolver;
+ static std::mutex s_lock_default_host_resolver;
+ static void ReleaseStaticDefaultHostResolver();
+ };
+
+ /**
+ * Gets a string description of a CRT error code
+ * @param error error code to get a descriptive string for
+ * @return a string description of the error code
+ */
+ AWS_CRT_CPP_API const char *ErrorDebugString(int error) noexcept;
+
+ /**
+ * @return the value of the last aws error on the current thread. Return 0 if no aws-error raised before.
+ */
+ AWS_CRT_CPP_API int LastError() noexcept;
+
+ /**
+ * @return the value of the last aws error on the current thread. Return AWS_ERROR_UNKNOWN, if no aws-error
+ * raised before.
+ */
+ AWS_CRT_CPP_API int LastErrorOrUnknown() noexcept;
+ } // namespace Crt
+} // namespace Aws
diff --git a/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/Config.h b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/Config.h
new file mode 100644
index 0000000000..99d1aae4c6
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/Config.h
@@ -0,0 +1,11 @@
+#pragma once
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+
+#define AWS_CRT_CPP_VERSION "0.19.8"
+#define AWS_CRT_CPP_VERSION_MAJOR 0
+#define AWS_CRT_CPP_VERSION_MINOR 19
+#define AWS_CRT_CPP_VERSION_PATCH 8
+#define AWS_CRT_CPP_GIT_HASH ""
diff --git a/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/DateTime.h b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/DateTime.h
new file mode 100644
index 0000000000..1861d1620e
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/DateTime.h
@@ -0,0 +1,198 @@
+#pragma once
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+#include <aws/crt/Exports.h>
+
+#include <aws/crt/Types.h>
+
+#include <aws/common/date_time.h>
+
+#include <chrono>
+
+namespace Aws
+{
+ namespace Crt
+ {
+ enum class DateFormat
+ {
+ RFC822 = AWS_DATE_FORMAT_RFC822,
+ ISO_8601 = AWS_DATE_FORMAT_ISO_8601,
+ AutoDetect = AWS_DATE_FORMAT_AUTO_DETECT,
+ };
+
+ enum class Month
+ {
+ January = AWS_DATE_MONTH_JANUARY,
+ February = AWS_DATE_MONTH_FEBRUARY,
+ March = AWS_DATE_MONTH_MARCH,
+ April = AWS_DATE_MONTH_APRIL,
+ May = AWS_DATE_MONTH_MAY,
+ June = AWS_DATE_MONTH_JUNE,
+ July = AWS_DATE_MONTH_JULY,
+ August = AWS_DATE_MONTH_AUGUST,
+ September = AWS_DATE_MONTH_SEPTEMBER,
+ October = AWS_DATE_MONTH_OCTOBER,
+ November = AWS_DATE_MONTH_NOVEMBER,
+ December = AWS_DATE_MONTH_DECEMBER,
+ };
+
+ enum class DayOfWeek
+ {
+ Sunday = AWS_DATE_DAY_OF_WEEK_SUNDAY,
+ Monday = AWS_DATE_DAY_OF_WEEK_MONDAY,
+ Tuesday = AWS_DATE_DAY_OF_WEEK_TUESDAY,
+ Wednesday = AWS_DATE_DAY_OF_WEEK_WEDNESDAY,
+ Thursday = AWS_DATE_DAY_OF_WEEK_THURSDAY,
+ Friday = AWS_DATE_DAY_OF_WEEK_FRIDAY,
+ Saturday = AWS_DATE_DAY_OF_WEEK_SATURDAY,
+ };
+
+ class AWS_CRT_CPP_API DateTime final
+ {
+ public:
+ /**
+ * Initializes time point to epoch
+ */
+ DateTime() noexcept;
+
+ /**
+ * Initializes time point to any other arbitrary timepoint
+ */
+ DateTime(const std::chrono::system_clock::time_point &timepointToAssign) noexcept;
+
+ /**
+ * Initializes time point to millis Since epoch
+ */
+ DateTime(uint64_t millisSinceEpoch) noexcept;
+
+ /**
+ * Initializes time point to epoch time in seconds.millis
+ */
+ DateTime(double epoch_millis) noexcept;
+
+ /**
+ * Initializes time point to value represented by timestamp and format.
+ */
+ DateTime(const char *timestamp, DateFormat format) noexcept;
+
+ bool operator==(const DateTime &other) const noexcept;
+ bool operator<(const DateTime &other) const noexcept;
+ bool operator>(const DateTime &other) const noexcept;
+ bool operator!=(const DateTime &other) const noexcept;
+ bool operator<=(const DateTime &other) const noexcept;
+ bool operator>=(const DateTime &other) const noexcept;
+
+ DateTime operator+(const std::chrono::milliseconds &a) const noexcept;
+ DateTime operator-(const std::chrono::milliseconds &a) const noexcept;
+
+ /**
+ * Assign from seconds.millis since epoch.
+ */
+ DateTime &operator=(double secondsSinceEpoch) noexcept;
+
+ /**
+ * Assign from millis since epoch.
+ */
+ DateTime &operator=(uint64_t millisSinceEpoch) noexcept;
+
+ /**
+ * Assign from another time_point
+ */
+ DateTime &operator=(const std::chrono::system_clock::time_point &timepointToAssign) noexcept;
+
+ /**
+ * Assign from an ISO8601 or RFC822 formatted string
+ */
+ DateTime &operator=(const char *timestamp) noexcept;
+
+ explicit operator bool() const noexcept;
+ int GetLastError() const noexcept;
+
+ /**
+ * Convert dateTime to local time string using predefined format.
+ */
+ bool ToLocalTimeString(DateFormat format, ByteBuf &outputBuf) const noexcept;
+
+ /**
+ * Convert dateTime to GMT time string using predefined format.
+ */
+ bool ToGmtString(DateFormat format, ByteBuf &outputBuf) const noexcept;
+
+ /**
+ * Get the representation of this datetime as seconds.milliseconds since epoch
+ */
+ double SecondsWithMSPrecision() const noexcept;
+
+ /**
+ * Milliseconds since epoch of this datetime.
+ */
+ uint64_t Millis() const noexcept;
+
+ /**
+ * In the likely case this class doesn't do everything you need to do, here's a copy of the time_point
+ * structure. Have fun.
+ */
+ std::chrono::system_clock::time_point UnderlyingTimestamp() const noexcept;
+
+ /**
+ * Get the Year portion of this dateTime. localTime if true, return local time, otherwise return UTC
+ */
+ uint16_t GetYear(bool localTime = false) const noexcept;
+
+ /**
+ * Get the Month portion of this dateTime. localTime if true, return local time, otherwise return UTC
+ */
+ Month GetMonth(bool localTime = false) const noexcept;
+
+ /**
+ * Get the Day of the Month portion of this dateTime. localTime if true, return local time, otherwise return
+ * UTC
+ */
+ uint8_t GetDay(bool localTime = false) const noexcept;
+
+ /**
+ * Get the Day of the Week portion of this dateTime. localTime if true, return local time, otherwise return
+ * UTC
+ */
+ DayOfWeek GetDayOfWeek(bool localTime = false) const noexcept;
+
+ /**
+ * Get the Hour portion of this dateTime. localTime if true, return local time, otherwise return UTC
+ */
+ uint8_t GetHour(bool localTime = false) const noexcept;
+
+ /**
+ * Get the Minute portion of this dateTime. localTime if true, return local time, otherwise return UTC
+ */
+ uint8_t GetMinute(bool localTime = false) const noexcept;
+
+ /**
+ * Get the Second portion of this dateTime. localTime if true, return local time, otherwise return UTC
+ */
+ uint8_t GetSecond(bool localTime = false) const noexcept;
+
+ /**
+ * Get whether or not this dateTime is in Daylight savings time. localTime if true, return local time,
+ * otherwise return UTC
+ */
+ bool IsDST(bool localTime = false) const noexcept;
+
+ /**
+ * Get an instance of DateTime representing this very instant.
+ */
+ static DateTime Now() noexcept;
+
+ /**
+ * Computes the difference between two DateTime instances and returns the difference
+ * in milliseconds.
+ */
+ std::chrono::milliseconds operator-(const DateTime &other) const noexcept;
+
+ private:
+ aws_date_time m_date_time;
+ bool m_good;
+ };
+ } // namespace Crt
+} // namespace Aws
diff --git a/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/Exports.h b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/Exports.h
new file mode 100644
index 0000000000..bd171dc736
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/Exports.h
@@ -0,0 +1,39 @@
+#pragma once
+
+/*
+ *Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ *Licensed under the Apache License, Version 2.0 (the "License").
+ *You may not use this file except in compliance with the License.
+ *A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file is distributed
+ * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+#if defined(USE_WINDOWS_DLL_SEMANTICS) || defined(WIN32)
+# ifdef _MSC_VER
+# pragma warning(disable : 4251)
+# endif // _MSC_VER
+# ifdef AWS_CRT_CPP_USE_IMPORT_EXPORT
+# ifdef AWS_CRT_CPP_EXPORTS
+# define AWS_CRT_CPP_API __declspec(dllexport)
+# else
+# define AWS_CRT_CPP_API __declspec(dllimport)
+# endif /* AWS_CRT_CPP_API */
+# else
+# define AWS_CRT_CPP_API
+# endif // AWS_CRT_CPP_USE_IMPORT_EXPORT
+
+#else // defined (USE_WINDOWS_DLL_SEMANTICS) || defined (WIN32)
+# if ((__GNUC__ >= 4) || defined(__clang__)) && defined(AWS_CRT_CPP_USE_IMPORT_EXPORT) && \
+ defined(AWS_CRT_CPP_EXPORTS)
+# define AWS_CRT_CPP_API __attribute__((visibility("default")))
+# else
+# define AWS_CRT_CPP_API
+# endif // __GNUC__ >= 4 || defined(__clang__)
+#endif
diff --git a/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/ImdsClient.h b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/ImdsClient.h
new file mode 100644
index 0000000000..c73e2bf27c
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/ImdsClient.h
@@ -0,0 +1,386 @@
+#pragma once
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+
+#include <aws/crt/DateTime.h>
+#include <aws/crt/Exports.h>
+#include <aws/crt/Types.h>
+#include <functional>
+
+struct aws_credentials;
+struct aws_imds_client;
+struct aws_imds_instance_info;
+struct aws_imds_iam_profile;
+
+namespace Aws
+{
+
+ namespace Crt
+ {
+
+ namespace Io
+ {
+ class ClientBootstrap;
+ }
+
+ namespace Auth
+ {
+ class Credentials;
+ }
+
+ namespace Imds
+ {
+
+ struct AWS_CRT_CPP_API ImdsClientConfig
+ {
+ ImdsClientConfig() : Bootstrap(nullptr) {}
+
+ /**
+ * Connection bootstrap to use to create the http connection required to
+ * query resource from the Ec2 instance metadata service
+ *
+ * Note: If null, then the default ClientBootstrap is used
+ * (see Aws::Crt::ApiHandle::GetOrCreateStaticDefaultClientBootstrap)
+ */
+ Io::ClientBootstrap *Bootstrap;
+
+ /* Should add retry strategy support once that is available */
+ };
+
+ /**
+ * https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instancedata-data-categories.html
+ */
+ struct AWS_CRT_CPP_API IamProfileView
+ {
+ DateTime lastUpdated;
+ StringView instanceProfileArn;
+ StringView instanceProfileId;
+ };
+
+ /**
+ * A convenient class for you to persist data from IamProfileView, which has StringView members.
+ */
+ struct AWS_CRT_CPP_API IamProfile
+ {
+ IamProfile() {}
+ IamProfile(const IamProfileView &other);
+
+ IamProfile &operator=(const IamProfileView &other);
+
+ DateTime lastUpdated;
+ String instanceProfileArn;
+ String instanceProfileId;
+ };
+
+ /**
+ * Block of per-instance EC2-specific data
+ *
+ * https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-identity-documents.html
+ */
+ struct AWS_CRT_CPP_API InstanceInfoView
+ {
+ /* an array of StringView */
+ Vector<StringView> marketplaceProductCodes;
+ StringView availabilityZone;
+ StringView privateIp;
+ StringView version;
+ StringView instanceId;
+ /* an array of StringView */
+ Vector<StringView> billingProducts;
+ StringView instanceType;
+ StringView accountId;
+ StringView imageId;
+ DateTime pendingTime;
+ StringView architecture;
+ StringView kernelId;
+ StringView ramdiskId;
+ StringView region;
+ };
+
+ /**
+ * A convenient class for you to persist data from InstanceInfoView, which has StringView members.
+ */
+ struct AWS_CRT_CPP_API InstanceInfo
+ {
+ InstanceInfo() {}
+ InstanceInfo(const InstanceInfoView &other);
+
+ InstanceInfo &operator=(const InstanceInfoView &other);
+
+ /* an array of StringView */
+ Vector<String> marketplaceProductCodes;
+ String availabilityZone;
+ String privateIp;
+ String version;
+ String instanceId;
+ /* an array of StringView */
+ Vector<String> billingProducts;
+ String instanceType;
+ String accountId;
+ String imageId;
+ DateTime pendingTime;
+ String architecture;
+ String kernelId;
+ String ramdiskId;
+ String region;
+ };
+
+ using OnResourceAcquired = std::function<void(const StringView &resource, int errorCode, void *userData)>;
+ using OnVectorResourceAcquired =
+ std::function<void(const Vector<StringView> &resource, int errorCode, void *userData)>;
+ using OnCredentialsAcquired =
+ std::function<void(const Auth::Credentials &credentials, int errorCode, void *userData)>;
+ using OnIamProfileAcquired =
+ std::function<void(const IamProfileView &iamProfile, int errorCode, void *userData)>;
+ using OnInstanceInfoAcquired =
+ std::function<void(const InstanceInfoView &instanceInfo, int errorCode, void *userData)>;
+
+ class AWS_CRT_CPP_API ImdsClient
+ {
+ public:
+ ImdsClient(const ImdsClientConfig &config, Allocator *allocator = ApiAllocator()) noexcept;
+
+ ~ImdsClient();
+
+ ImdsClient(const ImdsClient &) = delete;
+ ImdsClient(ImdsClient &&) = delete;
+ ImdsClient &operator=(const ImdsClient &) = delete;
+ ImdsClient &operator=(ImdsClient &&) = delete;
+
+ aws_imds_client *GetUnderlyingHandle() { return m_client; }
+
+ /**
+ * Queries a generic resource (string) from the ec2 instance metadata document
+ *
+ * @param resourcePath path of the resource to query
+ * @param callback callback function to invoke on query success or failure
+ * @param userData opaque data to invoke the completion callback with
+ * @return AWS_OP_SUCCESS if the query was successfully started, AWS_OP_ERR otherwise
+ */
+ int GetResource(const StringView &resourcePath, OnResourceAcquired callback, void *userData);
+
+ /**
+ * Gets the ami id of the ec2 instance from the instance metadata document
+ *
+ * @param callback callback function to invoke on query success or failure
+ * @param userData opaque data to invoke the completion callback with
+ * @return AWS_OP_SUCCESS if the query was successfully started, AWS_OP_ERR otherwise
+ */
+ int GetAmiId(OnResourceAcquired callback, void *userData);
+
+ /**
+ * Gets the ami launch index of the ec2 instance from the instance metadata document
+ *
+ * @param callback callback function to invoke on query success or failure
+ * @param userData opaque data to invoke the completion callback with
+ * @return AWS_OP_SUCCESS if the query was successfully started, AWS_OP_ERR otherwise
+ */
+ int GetAmiLaunchIndex(OnResourceAcquired callback, void *userData);
+
+ /**
+ * Gets the ami manifest path of the ec2 instance from the instance metadata document
+ *
+ * @param callback callback function to invoke on query success or failure
+ * @param userData opaque data to invoke the completion callback with
+ * @return AWS_OP_SUCCESS if the query was successfully started, AWS_OP_ERR otherwise
+ */
+ int GetAmiManifestPath(OnResourceAcquired callback, void *userData);
+
+ /**
+ * Gets the list of ancestor ami ids of the ec2 instance from the instance metadata document
+ *
+ * @param callback callback function to invoke on query success or failure
+ * @param userData opaque data to invoke the completion callback with
+ * @return AWS_OP_SUCCESS if the query was successfully started, AWS_OP_ERR otherwise
+ */
+ int GetAncestorAmiIds(OnVectorResourceAcquired callback, void *userData);
+
+ /**
+ * Gets the instance-action of the ec2 instance from the instance metadata document
+ *
+ * @param callback callback function to invoke on query success or failure
+ * @param userData opaque data to invoke the completion callback with
+ * @return AWS_OP_SUCCESS if the query was successfully started, AWS_OP_ERR otherwise
+ */
+ int GetInstanceAction(OnResourceAcquired callback, void *userData);
+
+ /**
+ * Gets the instance id of the ec2 instance from the instance metadata document
+ *
+ * @param callback callback function to invoke on query success or failure
+ * @param userData opaque data to invoke the completion callback with
+ * @return AWS_OP_SUCCESS if the query was successfully started, AWS_OP_ERR otherwise
+ */
+ int GetInstanceId(OnResourceAcquired callback, void *userData);
+
+ /**
+ * Gets the instance type of the ec2 instance from the instance metadata document
+ *
+ * @param callback callback function to invoke on query success or failure
+ * @param userData opaque data to invoke the completion callback with
+ * @return AWS_OP_SUCCESS if the query was successfully started, AWS_OP_ERR otherwise
+ */
+ int GetInstanceType(OnResourceAcquired callback, void *userData);
+
+ /**
+ * Gets the mac address of the ec2 instance from the instance metadata document
+ *
+ * @param callback callback function to invoke on query success or failure
+ * @param userData opaque data to invoke the completion callback with
+ * @return AWS_OP_SUCCESS if the query was successfully started, AWS_OP_ERR otherwise
+ */
+ int GetMacAddress(OnResourceAcquired callback, void *userData);
+
+ /**
+ * Gets the private ip address of the ec2 instance from the instance metadata document
+ *
+ * @param callback callback function to invoke on query success or failure
+ * @param userData opaque data to invoke the completion callback with
+ * @return AWS_OP_SUCCESS if the query was successfully started, AWS_OP_ERR otherwise
+ */
+ int GetPrivateIpAddress(OnResourceAcquired callback, void *userData);
+
+ /**
+ * Gets the availability zone of the ec2 instance from the instance metadata document
+ *
+ * @param callback callback function to invoke on query success or failure
+ * @param userData opaque data to invoke the completion callback with
+ * @return AWS_OP_SUCCESS if the query was successfully started, AWS_OP_ERR otherwise
+ */
+ int GetAvailabilityZone(OnResourceAcquired callback, void *userData);
+
+ /**
+ * Gets the product codes of the ec2 instance from the instance metadata document
+ *
+ * @param callback callback function to invoke on query success or failure
+ * @param userData opaque data to invoke the completion callback with
+ * @return AWS_OP_SUCCESS if the query was successfully started, AWS_OP_ERR otherwise
+ */
+ int GetProductCodes(OnResourceAcquired callback, void *userData);
+
+ /**
+ * Gets the public key of the ec2 instance from the instance metadata document
+ *
+ * @param callback callback function to invoke on query success or failure
+ * @param userData opaque data to invoke the completion callback with
+ * @return AWS_OP_SUCCESS if the query was successfully started, AWS_OP_ERR otherwise
+ */
+ int GetPublicKey(OnResourceAcquired callback, void *userData);
+
+ /**
+ * Gets the ramdisk id of the ec2 instance from the instance metadata document
+ *
+ * @param callback callback function to invoke on query success or failure
+ * @param userData opaque data to invoke the completion callback with
+ * @return AWS_OP_SUCCESS if the query was successfully started, AWS_OP_ERR otherwise
+ */
+ int GetRamDiskId(OnResourceAcquired callback, void *userData);
+
+ /**
+ * Gets the reservation id of the ec2 instance from the instance metadata document
+ *
+ * @param callback callback function to invoke on query success or failure
+ * @param userData opaque data to invoke the completion callback with
+ * @return AWS_OP_SUCCESS if the query was successfully started, AWS_OP_ERR otherwise
+ */
+ int GetReservationId(OnResourceAcquired callback, void *userData);
+
+ /**
+ * Gets the list of the security groups of the ec2 instance from the instance metadata document
+ *
+ * @param callback callback function to invoke on query success or failure
+ * @param userData opaque data to invoke the completion callback with
+ * @return AWS_OP_SUCCESS if the query was successfully started, AWS_OP_ERR otherwise
+ */
+ int GetSecurityGroups(OnVectorResourceAcquired callback, void *userData);
+
+ /**
+ * Gets the list of block device mappings of the ec2 instance from the instance metadata document
+ *
+ * @param callback callback function to invoke on query success or failure
+ * @param userData opaque data to invoke the completion callback with
+ * @return AWS_OP_SUCCESS if the query was successfully started, AWS_OP_ERR otherwise
+ */
+ int GetBlockDeviceMapping(OnVectorResourceAcquired callback, void *userData);
+
+ /**
+ * Gets the attached iam role of the ec2 instance from the instance metadata document
+ *
+ * @param callback callback function to invoke on query success or failure
+ * @param userData opaque data to invoke the completion callback with
+ * @return AWS_OP_SUCCESS if the query was successfully started, AWS_OP_ERR otherwise
+ */
+ int GetAttachedIamRole(OnResourceAcquired callback, void *userData);
+
+ /**
+ * Gets temporary credentials based on the attached iam role of the ec2 instance
+ *
+ * @param iamRoleName iam role name to get temporary credentials through
+ * @param callback callback function to invoke on query success or failure
+ * @param userData opaque data to invoke the completion callback with
+ * @return AWS_OP_SUCCESS if the query was successfully started, AWS_OP_ERR otherwise
+ */
+ int GetCredentials(const StringView &iamRoleName, OnCredentialsAcquired callback, void *userData);
+
+ /**
+ * Gets the iam profile information of the ec2 instance from the instance metadata document
+ *
+ * @param callback callback function to invoke on query success or failure
+ * @param userData opaque data to invoke the completion callback with
+ * @return AWS_OP_SUCCESS if the query was successfully started, AWS_OP_ERR otherwise
+ */
+ int GetIamProfile(OnIamProfileAcquired callback, void *userData);
+
+ /**
+ * Gets the user data of the ec2 instance from the instance metadata document
+ *
+ * @param callback callback function to invoke on query success or failure
+ * @param userData opaque data to invoke the completion callback with
+ * @return AWS_OP_SUCCESS if the query was successfully started, AWS_OP_ERR otherwise
+ */
+ int GetUserData(OnResourceAcquired callback, void *userData);
+
+ /**
+ * Gets the signature of the ec2 instance from the instance metadata document
+ *
+ * @param callback callback function to invoke on query success or failure
+ * @param userData opaque data to invoke the completion callback with
+ * @return AWS_OP_SUCCESS if the query was successfully started, AWS_OP_ERR otherwise
+ */
+ int GetInstanceSignature(OnResourceAcquired callback, void *userData);
+
+ /**
+ * Gets the instance information data block of the ec2 instance from the instance metadata document
+ *
+ * @param callback callback function to invoke on query success or failure
+ * @param userData opaque data to invoke the completion callback with
+ * @return AWS_OP_SUCCESS if the query was successfully started, AWS_OP_ERR otherwise
+ */
+ int GetInstanceInfo(OnInstanceInfoAcquired callback, void *userData);
+
+ private:
+ static void s_onResourceAcquired(const aws_byte_buf *resource, int erroCode, void *userData);
+
+ static void s_onVectorResourceAcquired(const aws_array_list *array, int errorCode, void *userData);
+
+ static void s_onCredentialsAcquired(const aws_credentials *credentials, int errorCode, void *userData);
+
+ static void s_onIamProfileAcquired(
+ const aws_imds_iam_profile *iamProfileInfo,
+ int errorCode,
+ void *userData);
+
+ static void s_onInstanceInfoAcquired(
+ const aws_imds_instance_info *instanceInfo,
+ int error_code,
+ void *userData);
+
+ aws_imds_client *m_client;
+ Allocator *m_allocator;
+ };
+
+ } // namespace Imds
+ } // namespace Crt
+} // namespace Aws
diff --git a/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/JsonObject.h b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/JsonObject.h
new file mode 100644
index 0000000000..feca11eb4f
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/JsonObject.h
@@ -0,0 +1,406 @@
+#pragma once
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+#include <aws/crt/StlAllocator.h>
+#include <aws/crt/Types.h>
+
+namespace Aws
+{
+ struct cJSON;
+
+ namespace Crt
+ {
+ class JsonView;
+ /**
+ * JSON DOM manipulation class.
+ * To read or serialize use @ref View function.
+ */
+ class AWS_CRT_CPP_API JsonObject
+ {
+ public:
+ /**
+ * Constructs empty JSON DOM.
+ */
+ JsonObject();
+
+ /**
+ * Constructs a JSON DOM by parsing the input string.
+ */
+ JsonObject(const String &value);
+
+ /**
+ * Performs a deep copy of the JSON DOM parameter.
+ * Prefer using a @ref JsonView if copying is not needed.
+ */
+ JsonObject(const JsonObject &value);
+
+ /**
+ * Moves the ownership of the internal JSON DOM.
+ * No copying is performed.
+ */
+ JsonObject(JsonObject &&value) noexcept;
+
+ ~JsonObject();
+
+ /**
+ * Performs a deep copy of the JSON DOM parameter.
+ */
+ JsonObject &operator=(const JsonObject &other);
+
+ /**
+ * Moves the ownership of the internal JSON DOM of the parameter to the current object.
+ * No copying is performed.
+ * A DOM currently owned by the object will be freed prior to copying.
+ * @warning This will result in invalidating any outstanding views of the current DOM. However, views
+ * to the moved-from DOM would still valid.
+ */
+ JsonObject &operator=(JsonObject &&other) noexcept;
+
+ bool operator==(const JsonObject &other) const;
+ bool operator!=(const JsonObject &other) const;
+
+ /**
+ * Adds a string to the top level of this node with key.
+ */
+ JsonObject &WithString(const String &key, const String &value);
+ JsonObject &WithString(const char *key, const String &value);
+
+ /**
+ * Converts the current JSON node to a string.
+ */
+ JsonObject &AsString(const String &value);
+
+ /**
+ * Adds a bool value with key to the top level of this node.
+ */
+ JsonObject &WithBool(const String &key, bool value);
+ JsonObject &WithBool(const char *key, bool value);
+
+ /**
+ * Converts the current JSON node to a bool.
+ */
+ JsonObject &AsBool(bool value);
+
+ /**
+ * Adds an integer value at key at the top level of this node.
+ */
+ JsonObject &WithInteger(const String &key, int value);
+ JsonObject &WithInteger(const char *key, int value);
+
+ /**
+ * Converts the current JSON node to an integer.
+ */
+ JsonObject &AsInteger(int value);
+
+ /**
+ * Adds a 64-bit integer value at key to the top level of this node.
+ */
+ JsonObject &WithInt64(const String &key, int64_t value);
+ JsonObject &WithInt64(const char *key, int64_t value);
+
+ /**
+ * Converts the current JSON node to a 64-bit integer.
+ */
+ JsonObject &AsInt64(int64_t value);
+
+ /**
+ * Adds a double value at key at the top level of this node.
+ */
+ JsonObject &WithDouble(const String &key, double value);
+ JsonObject &WithDouble(const char *key, double value);
+
+ /**
+ * Converts the current JSON node to a double.
+ */
+ JsonObject &AsDouble(double value);
+
+ /**
+ * Adds an array of strings to the top level of this node at key.
+ */
+ JsonObject &WithArray(const String &key, const Vector<String> &array);
+ JsonObject &WithArray(const char *key, const Vector<String> &array);
+
+ /**
+ * Adds an array of arbitrary JSON objects to the top level of this node at key.
+ * The values in the array parameter will be deep-copied.
+ */
+ JsonObject &WithArray(const String &key, const Vector<JsonObject> &array);
+
+ /**
+ * Adds an array of arbitrary JSON objects to the top level of this node at key.
+ * The values in the array parameter will be moved-from.
+ */
+ JsonObject &WithArray(const String &key, Vector<JsonObject> &&array);
+
+ /**
+ * Converts the current JSON node to an array whose values are deep-copied from the array parameter.
+ */
+ JsonObject &AsArray(const Vector<JsonObject> &array);
+
+ /**
+ * Converts the current JSON node to an array whose values are moved from the array parameter.
+ */
+ JsonObject &AsArray(Vector<JsonObject> &&array);
+
+ /**
+ * Sets the current JSON node as null.
+ */
+ JsonObject &AsNull();
+
+ /**
+ * Adds a JSON object to the top level of this node at key.
+ * The object parameter is deep-copied.
+ */
+ JsonObject &WithObject(const String &key, const JsonObject &value);
+ JsonObject &WithObject(const char *key, const JsonObject &value);
+
+ /**
+ * Adds a JSON object to the top level of this node at key.
+ */
+ JsonObject &WithObject(const String &key, JsonObject &&value);
+ JsonObject &WithObject(const char *key, JsonObject &&value);
+
+ /**
+ * Converts the current JSON node to a JSON object by deep-copying the parameter.
+ */
+ JsonObject &AsObject(const JsonObject &value);
+
+ /**
+ * Converts the current JSON node to a JSON object by moving from the parameter.
+ */
+ JsonObject &AsObject(JsonObject &&value);
+
+ /**
+ * Returns true if the last parse request was successful. If this returns false,
+ * you can call GetErrorMessage() to find the cause.
+ */
+ inline bool WasParseSuccessful() const { return m_wasParseSuccessful; }
+
+ /**
+ * Returns the last error message from a failed parse attempt. Returns empty string if no error.
+ */
+ inline const String &GetErrorMessage() const { return m_errorMessage; }
+
+ /**
+ * Creates a view from the current root JSON node.
+ */
+ JsonView View() const;
+
+ private:
+ void Destroy();
+ JsonObject(cJSON *value);
+ cJSON *m_value;
+ bool m_wasParseSuccessful;
+ String m_errorMessage;
+ friend class JsonView;
+ };
+
+ /**
+ * Provides read-only view to an existing JsonObject. This allows lightweight copying without making deep
+ * copies of the JsonObject.
+ * Note: This class does not extend the lifetime of the given JsonObject. It's your responsibility to ensure
+ * the lifetime of the JsonObject is extended beyond the lifetime of its view.
+ */
+ class AWS_CRT_CPP_API JsonView
+ {
+ public:
+ /* constructors */
+ JsonView();
+ JsonView(const JsonObject &val);
+ JsonView &operator=(const JsonObject &val);
+
+ /**
+ * Gets a string from this node by its key.
+ */
+ String GetString(const String &key) const;
+ /**
+ * Gets a string from this node by its key.
+ */
+ String GetString(const char *key) const;
+
+ /**
+ * Returns the value of this node as a string.
+ * The behavior is undefined if the node is _not_ of type string.
+ */
+ String AsString() const;
+
+ /**
+ * Gets a boolean value from this node by its key.
+ */
+ bool GetBool(const String &key) const;
+ /**
+ * Gets a boolean value from this node by its key.
+ */
+ bool GetBool(const char *key) const;
+
+ /**
+ * Returns the value of this node as a boolean.
+ */
+ bool AsBool() const;
+
+ /**
+ * Gets an integer value from this node by its key.
+ * The integer is of the same size as an int on the machine.
+ */
+ int GetInteger(const String &key) const;
+ /**
+ * Gets an integer value from this node by its key.
+ * The integer is of the same size as an int on the machine.
+ */
+ int GetInteger(const char *key) const;
+
+ /**
+ * Returns the value of this node as an int.
+ */
+ int AsInteger() const;
+
+ /**
+ * Gets a 64-bit integer value from this node by its key.
+ * The value is 64-bit regardless of the platform/machine.
+ */
+ int64_t GetInt64(const String &key) const;
+ /**
+ * Gets a 64-bit integer value from this node by its key.
+ * The value is 64-bit regardless of the platform/machine.
+ */
+ int64_t GetInt64(const char *key) const;
+
+ /**
+ * Returns the value of this node as 64-bit integer.
+ */
+ int64_t AsInt64() const;
+
+ /**
+ * Gets a double precision floating-point value from this node by its key.
+ */
+ double GetDouble(const String &key) const;
+ /**
+ * Gets a double precision floating-point value from this node by its key.
+ */
+ double GetDouble(const char *key) const;
+
+ /**
+ * Returns the value of this node as a double precision floating-point.
+ */
+ double AsDouble() const;
+
+ /**
+ * Gets an array of JsonView objects from this node by its key.
+ */
+ Vector<JsonView> GetArray(const String &key) const;
+ /**
+ * Gets an array of JsonView objects from this node by its key.
+ */
+ Vector<JsonView> GetArray(const char *key) const;
+
+ /**
+ * Returns the value of this node as an array of JsonView objects.
+ */
+ Vector<JsonView> AsArray() const;
+
+ /**
+ * Gets a JsonView object from this node by its key.
+ */
+ JsonView GetJsonObject(const String &key) const;
+ /**
+ * Gets a JsonView object from this node by its key.
+ */
+ JsonView GetJsonObject(const char *key) const;
+
+ JsonObject GetJsonObjectCopy(const String &key) const;
+
+ JsonObject GetJsonObjectCopy(const char *key) const;
+
+ /**
+ * Returns the value of this node as a JsonView object.
+ */
+ JsonView AsObject() const;
+
+ /**
+ * Reads all json objects at the top level of this node (does not traverse the tree any further)
+ * along with their keys.
+ */
+ Map<String, JsonView> GetAllObjects() const;
+
+ /**
+ * Tests whether a value exists at the current node level for the given key.
+ * Returns true if a value has been found and its value is not null, false otherwise.
+ */
+ bool ValueExists(const String &key) const;
+ /**
+ * Tests whether a value exists at the current node level for the given key.
+ * Returns true if a value has been found and its value is not null, false otherwise.
+ */
+ bool ValueExists(const char *key) const;
+
+ /**
+ * Tests whether a key exists at the current node level.
+ */
+ bool KeyExists(const String &key) const;
+ /**
+ * Tests whether a key exists at the current node level.
+ */
+ bool KeyExists(const char *key) const;
+
+ /**
+ * Tests whether the current value is a JSON object.
+ */
+ bool IsObject() const;
+
+ /**
+ * Tests whether the current value is a boolean.
+ */
+ bool IsBool() const;
+
+ /**
+ * Tests whether the current value is a string.
+ */
+ bool IsString() const;
+
+ /**
+ * Tests whether the current value is an int or int64_t.
+ * Returns false if the value is floating-point.
+ */
+ bool IsIntegerType() const;
+
+ /**
+ * Tests whether the current value is a floating-point.
+ */
+ bool IsFloatingPointType() const;
+
+ /**
+ * Tests whether the current value is a JSON array.
+ */
+ bool IsListType() const;
+
+ /**
+ * Tests whether the current value is NULL.
+ */
+ bool IsNull() const;
+
+ /**
+ * Writes the current JSON view without whitespace characters starting at the current level to a string.
+ * @param treatAsObject if the current value is empty, writes out '{}' rather than an empty string.
+ */
+ String WriteCompact(bool treatAsObject = true) const;
+
+ /**
+ * Writes the current JSON view to a string in a human friendly format.
+ * @param treatAsObject if the current value is empty, writes out '{}' rather than an empty string.
+ */
+ String WriteReadable(bool treatAsObject = true) const;
+
+ /**
+ * Creates a deep copy of the JSON value rooted in the current JSON view.
+ */
+ JsonObject Materialize() const;
+
+ private:
+ JsonView(cJSON *val);
+ JsonView &operator=(cJSON *val);
+ cJSON *m_value;
+ };
+ } // namespace Crt
+} // namespace Aws
diff --git a/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/Optional.h b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/Optional.h
new file mode 100644
index 0000000000..5acc232557
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/Optional.h
@@ -0,0 +1,203 @@
+#pragma once
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+#include <utility>
+
+namespace Aws
+{
+ namespace Crt
+ {
+ /**
+ * Custom implementation of an Option type. std::optional requires C++17
+ * @tparam T type of the optional value
+ */
+ template <typename T> class Optional
+ {
+ public:
+ Optional() : m_value(nullptr) {}
+ Optional(const T &val)
+ {
+ new (m_storage) T(val);
+ m_value = reinterpret_cast<T *>(m_storage);
+ }
+
+ Optional(T &&val)
+ {
+ new (m_storage) T(std::forward<T>(val));
+ m_value = reinterpret_cast<T *>(m_storage);
+ }
+
+ ~Optional()
+ {
+ if (m_value)
+ {
+ m_value->~T();
+ }
+ }
+
+ template <typename U = T> Optional &operator=(U &&u)
+ {
+ if (m_value)
+ {
+ *m_value = std::forward<U>(u);
+ return *this;
+ }
+
+ new (m_storage) T(std::forward<U>(u));
+ m_value = reinterpret_cast<T *>(m_storage);
+
+ return *this;
+ }
+
+ Optional(const Optional<T> &other)
+ {
+ if (other.m_value)
+ {
+ new (m_storage) T(*other.m_value);
+ m_value = reinterpret_cast<T *>(m_storage);
+ }
+ else
+ {
+ m_value = nullptr;
+ }
+ }
+
+ Optional(Optional<T> &&other)
+ {
+ if (other.m_value)
+ {
+ new (m_storage) T(std::forward<T>(*other.m_value));
+ m_value = reinterpret_cast<T *>(m_storage);
+ }
+ else
+ {
+ m_value = nullptr;
+ }
+ }
+
+ Optional &operator=(const Optional &other)
+ {
+ if (this == &other)
+ {
+ return *this;
+ }
+
+ if (m_value)
+ {
+ if (other.m_value)
+ {
+ *m_value = *other.m_value;
+ }
+ else
+ {
+ m_value->~T();
+ m_value = nullptr;
+ }
+
+ return *this;
+ }
+
+ if (other.m_value)
+ {
+ new (m_storage) T(*other.m_value);
+ m_value = reinterpret_cast<T *>(m_storage);
+ }
+
+ return *this;
+ }
+
+ template <typename U = T> Optional<T> &operator=(const Optional<U> &other)
+ {
+ if (this == &other)
+ {
+ return *this;
+ }
+
+ if (m_value)
+ {
+ if (other.m_value)
+ {
+ *m_value = *other.m_value;
+ }
+ else
+ {
+ m_value->~T();
+ m_value = nullptr;
+ }
+
+ return *this;
+ }
+
+ if (other.m_value)
+ {
+ new (m_storage) T(*other.m_value);
+ m_value = reinterpret_cast<T *>(m_storage);
+ }
+
+ return *this;
+ }
+
+ template <typename U = T> Optional<T> &operator=(Optional<U> &&other)
+ {
+ if (this == &other)
+ {
+ return *this;
+ }
+
+ if (m_value)
+ {
+ if (other.m_value)
+ {
+ *m_value = std::forward<U>(*other.m_value);
+ }
+ else
+ {
+ m_value->~T();
+ m_value = nullptr;
+ }
+
+ return *this;
+ }
+
+ if (other.m_value)
+ {
+ new (m_storage) T(std::forward<U>(*other.m_value));
+ m_value = reinterpret_cast<T *>(m_storage);
+ }
+
+ return *this;
+ }
+
+ const T *operator->() const { return m_value; }
+ T *operator->() { return m_value; }
+ const T &operator*() const & { return *m_value; }
+ T &operator*() & { return *m_value; }
+ const T &&operator*() const && { return std::move(*m_value); }
+ T &&operator*() && { return std::move(*m_value); }
+
+ explicit operator bool() const noexcept { return m_value != nullptr; }
+ bool has_value() const noexcept { return m_value != nullptr; }
+
+ T &value() & { return *m_value; }
+ const T &value() const & { return *m_value; }
+
+ T &&value() && { return std::move(*m_value); }
+ const T &&value() const && { return std::move(*m_value); }
+
+ void reset()
+ {
+ if (m_value)
+ {
+ m_value->~T();
+ m_value = nullptr;
+ }
+ }
+
+ private:
+ alignas(T) char m_storage[sizeof(T)];
+ T *m_value;
+ };
+ } // namespace Crt
+} // namespace Aws
diff --git a/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/RefCounted.h b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/RefCounted.h
new file mode 100644
index 0000000000..d9ec11d818
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/RefCounted.h
@@ -0,0 +1,68 @@
+#pragma once
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+
+#include <aws/common/assert.h>
+#include <memory>
+#include <mutex>
+
+namespace Aws
+{
+ namespace Crt
+ {
+ /**
+ * Inherit from RefCounted to allow reference-counting from C code,
+ * which will keep your C++ object alive as long as the count is non-zero.
+ *
+ * A class must inherit from RefCounted and std::enable_shared_from_this.
+ * Your class must always be placed inside a shared_ptr (do not create on
+ * the stack, or keep on the heap as a raw pointer).
+ *
+ * Whenever the reference count goes from 0 to 1 a shared_ptr is created
+ * internally to keep this object alive. Whenever the reference count
+ * goes from 1 to 0 the internal shared_ptr is reset, allowing this object
+ * to be destroyed.
+ */
+ template <class T> class RefCounted
+ {
+ protected:
+ RefCounted() {}
+ ~RefCounted() {}
+
+ void AcquireRef()
+ {
+ m_mutex.lock();
+ if (m_count++ == 0)
+ {
+ m_strongPtr = static_cast<T *>(this)->shared_from_this();
+ }
+ m_mutex.unlock();
+ }
+
+ void ReleaseRef()
+ {
+ // Move contents of m_strongPtr to a temp so that this
+ // object can't be destroyed until the function exits.
+ std::shared_ptr<T> tmpStrongPtr;
+
+ m_mutex.lock();
+ AWS_ASSERT(m_count > 0 && "refcount has gone negative");
+ if (m_count-- == 1)
+ {
+ std::swap(m_strongPtr, tmpStrongPtr);
+ }
+ m_mutex.unlock();
+ }
+
+ private:
+ RefCounted(const RefCounted &) = delete;
+ RefCounted &operator=(const RefCounted &) = delete;
+
+ size_t m_count = 0;
+ std::shared_ptr<T> m_strongPtr;
+ std::mutex m_mutex;
+ };
+ } // namespace Crt
+} // namespace Aws
diff --git a/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/StlAllocator.h b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/StlAllocator.h
new file mode 100644
index 0000000000..13ec6ff68e
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/StlAllocator.h
@@ -0,0 +1,63 @@
+#pragma once
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+
+#include <aws/crt/Allocator.h>
+
+#include <memory>
+#include <type_traits>
+
+namespace Aws
+{
+ namespace Crt
+ {
+ /**
+ * Stateful allocator variant that uses an underlying CRT allocator
+ * @tparam T type that allocator can allocate
+ */
+ template <typename T> class StlAllocator : public std::allocator<T>
+ {
+ public:
+ using Base = std::allocator<T>;
+
+ StlAllocator() noexcept : Base() { m_allocator = ApiAllocator(); }
+
+ StlAllocator(Allocator *allocator) noexcept : Base() { m_allocator = allocator; }
+
+ StlAllocator(const StlAllocator<T> &a) noexcept : Base(a) { m_allocator = a.m_allocator; }
+
+ template <class U> StlAllocator(const StlAllocator<U> &a) noexcept : Base(a)
+ {
+ m_allocator = a.m_allocator;
+ }
+
+ ~StlAllocator() {}
+
+ using size_type = std::size_t;
+
+ template <typename U> struct rebind
+ {
+ typedef StlAllocator<U> other;
+ };
+
+ using RawPointer = typename std::allocator_traits<std::allocator<T>>::pointer;
+
+ RawPointer allocate(size_type n, const void *hint = nullptr)
+ {
+ (void)hint;
+ AWS_ASSERT(m_allocator);
+ return static_cast<RawPointer>(aws_mem_acquire(m_allocator, n * sizeof(T)));
+ }
+
+ void deallocate(RawPointer p, size_type)
+ {
+ AWS_ASSERT(m_allocator);
+ aws_mem_release(m_allocator, p);
+ }
+
+ Allocator *m_allocator;
+ };
+ } // namespace Crt
+} // namespace Aws
diff --git a/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/StringUtils.h b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/StringUtils.h
new file mode 100644
index 0000000000..7ab98c2b0f
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/StringUtils.h
@@ -0,0 +1,21 @@
+#pragma once
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+#include <aws/crt/Exports.h>
+
+#include <stddef.h>
+
+namespace Aws
+{
+ namespace Crt
+ {
+ /**
+ * C-string hash function
+ * @param str string to hash
+ * @return hash code of the string
+ */
+ size_t AWS_CRT_CPP_API HashString(const char *str) noexcept;
+ } // namespace Crt
+} // namespace Aws
diff --git a/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/StringView.h b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/StringView.h
new file mode 100644
index 0000000000..b8c6c66881
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/StringView.h
@@ -0,0 +1,864 @@
+#pragma once
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+
+/**
+ * To keep ABI compatability, we use CRT's own string view implementation even for C++ 17.
+ */
+
+#include <algorithm>
+#include <cassert>
+#include <iterator>
+#include <limits>
+#include <stddef.h>
+#include <type_traits>
+
+#if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
+# include <string_view>
+#endif
+
+namespace Aws
+{
+ namespace Crt
+ {
+ /**
+ * Custom string view implementation in order to meet C++11 baseline
+ * @tparam CharT
+ * @tparam Traits
+ */
+ template <typename CharT, typename Traits = std::char_traits<CharT>> class basic_string_view
+ {
+ public:
+ // types
+ using traits_type = Traits;
+ using value_type = CharT;
+ using pointer = value_type *;
+ using const_pointer = const value_type *;
+ using reference = value_type &;
+ using const_reference = const value_type &;
+ using const_iterator = const value_type *;
+ using iterator = const_iterator;
+ using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+ using reverse_iterator = const_reverse_iterator;
+ using size_type = size_t;
+ using difference_type = ptrdiff_t;
+ static constexpr size_type npos = static_cast<size_type>(-1);
+
+ // constructors and assignment
+
+ constexpr basic_string_view() noexcept : m_size{0}, m_data{nullptr} {}
+
+ constexpr basic_string_view(const basic_string_view &) noexcept = default;
+
+ constexpr basic_string_view(const CharT *s) noexcept : m_size{traits_type::length(s)}, m_data{s} {}
+
+ constexpr basic_string_view(const CharT *s, size_type count) noexcept : m_size{count}, m_data{s} {}
+
+ basic_string_view &operator=(const basic_string_view &) noexcept = default;
+
+#if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
+ constexpr basic_string_view(const std::basic_string_view<CharT, Traits> &other) noexcept
+ : m_size(other.size()), m_data(other.data())
+ {
+ }
+
+ basic_string_view &operator=(const std::basic_string_view<CharT, Traits> &other) noexcept
+ {
+ m_data = other->data();
+ m_size = other->size();
+ return *this;
+ }
+#endif
+ // iterators
+
+ constexpr const_iterator begin() const noexcept { return this->m_data; }
+
+ constexpr const_iterator end() const noexcept { return this->m_data + this->m_size; }
+
+ constexpr const_iterator cbegin() const noexcept { return this->m_data; }
+
+ constexpr const_iterator cend() const noexcept { return this->m_data + this->m_size; }
+
+ constexpr const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(this->end()); }
+
+ constexpr const_reverse_iterator rend() const noexcept { return const_reverse_iterator(this->begin()); }
+
+ constexpr const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator(this->end()); }
+
+ constexpr const_reverse_iterator crend() const noexcept { return const_reverse_iterator(this->begin()); }
+
+ constexpr size_type size() const noexcept { return this->m_size; }
+
+ constexpr size_type length() const noexcept { return this->m_size; }
+
+ constexpr size_type max_size() const noexcept { return (std::numeric_limits<size_type>::max)(); }
+
+ constexpr bool empty() const noexcept { return this->m_size == 0; }
+
+ // element accessors
+
+ const_reference operator[](size_type pos) const noexcept
+ {
+ assert(pos < m_size);
+ return *(this->m_data + pos);
+ }
+
+ const_reference at(size_type pos) const
+ {
+ assert(pos < m_size);
+ return *(this->m_data + pos);
+ }
+
+ const_reference front() const noexcept
+ {
+ assert(m_size > 0);
+ return *this->m_data;
+ }
+
+ const_reference back() const noexcept
+ {
+ assert(m_size > 0);
+ return *(this->m_data + this->m_size - 1);
+ }
+
+ constexpr const_pointer data() const noexcept { return this->m_data; }
+
+ // modifiers
+ void remove_prefix(size_type n) noexcept
+ {
+ assert(this->m_size >= n);
+ this->m_data += n;
+ this->m_size -= n;
+ }
+
+ void remove_suffix(size_type n) noexcept { this->m_size -= n; }
+
+ void swap(basic_string_view &other) noexcept
+ {
+ auto tmp = *this;
+ *this = other;
+ other = tmp;
+ }
+
+ // string operations
+ size_type copy(CharT *s, size_type n, size_type pos = 0) const
+ {
+ assert(pos <= size());
+ const size_type copyLen = (std::min)(n, m_size - pos);
+ traits_type::copy(s, data() + pos, copyLen);
+ return copyLen;
+ }
+
+ basic_string_view substr(size_type pos = 0, size_type n = npos) const noexcept(false)
+ {
+ assert(pos <= size());
+ const size_type copyLen = (std::min)(n, m_size - pos);
+ return basic_string_view{m_data + pos, copyLen};
+ }
+
+ int compare(const basic_string_view &s) const noexcept
+ {
+ const size_type compareLen = (std::min)(this->m_size, s.m_size);
+ int ret = traits_type::compare(this->m_data, s.m_data, compareLen);
+ if (ret == 0)
+ {
+ ret = _s_compare(this->m_size, s.m_size);
+ }
+ return ret;
+ }
+
+ constexpr int compare(size_type pos1, size_type n1, const basic_string_view &s) const
+ {
+ return this->substr(pos1, n1).compare(s);
+ }
+
+ constexpr int compare(
+ size_type pos1,
+ size_type n1,
+ const basic_string_view &s,
+ size_type pos2,
+ size_type n2) const
+ {
+ return this->substr(pos1, n1).compare(s.substr(pos2, n2));
+ }
+
+ constexpr int compare(const CharT *s) const noexcept { return this->compare(basic_string_view{s}); }
+
+ constexpr int compare(size_type pos1, size_type n1, const CharT *s) const
+ {
+ return this->substr(pos1, n1).compare(basic_string_view{s});
+ }
+
+ constexpr int compare(size_type pos1, size_type n1, const CharT *s, size_type n2) const noexcept(false)
+ {
+ return this->substr(pos1, n1).compare(basic_string_view(s, n2));
+ }
+
+ constexpr bool starts_with(const basic_string_view &other) const noexcept
+ {
+ return this->substr(0, other.size()) == other;
+ }
+
+ constexpr bool starts_with(CharT c) const noexcept
+ {
+ return !this->empty() && traits_type::eq(this->front(), c);
+ }
+
+ constexpr bool starts_with(const CharT *s) const noexcept
+ {
+ return this->starts_with(basic_string_view(s));
+ }
+
+ constexpr bool ends_with(const basic_string_view &other) const noexcept
+ {
+ return this->m_size >= other.m_size && this->compare(this->m_size - other.m_size, npos, other) == 0;
+ }
+
+ constexpr bool ends_with(CharT c) const noexcept
+ {
+ return !this->empty() && traits_type::eq(this->back(), c);
+ }
+
+ constexpr bool ends_with(const CharT *s) const noexcept { return this->ends_with(basic_string_view(s)); }
+
+ // find utilities
+ constexpr size_type find(const basic_string_view &s, size_type pos = 0) const noexcept
+ {
+ return this->find(s.m_data, pos, s.m_size);
+ }
+
+ size_type find(CharT c, size_type pos = 0) const noexcept
+ {
+ if (pos >= m_size)
+ {
+ return npos;
+ }
+ const CharT *r = Traits::find(m_data + pos, m_size - pos, c);
+ if (r == nullptr)
+ {
+ return npos;
+ }
+ return static_cast<size_type>(r - m_data);
+ }
+
+ size_type find(const CharT *s, size_type pos, size_type n) const noexcept
+ {
+ if (n && !s)
+ {
+ return npos;
+ }
+
+ if (pos > m_size)
+ {
+ return npos;
+ }
+
+ if (n == 0)
+ {
+ return pos;
+ }
+
+ const CharT *r = _s_search_substr(m_data + pos, m_data + m_size, s, s + n);
+
+ if (r == m_data + m_size)
+ {
+ return npos;
+ }
+ return static_cast<size_type>(r - m_data);
+ }
+
+ constexpr size_type find(const CharT *s, size_type pos = 0) const noexcept
+ {
+ return this->find(s, pos, traits_type::length(s));
+ }
+
+ size_type rfind(basic_string_view s, size_type pos = npos) const noexcept
+ {
+ if (s.m_size && !s.m_data)
+ {
+ return npos;
+ }
+ return this->rfind(s.m_data, pos, s.m_size);
+ }
+
+ size_type rfind(CharT c, size_type pos = npos) const noexcept
+ {
+ if (m_size <= 0)
+ {
+ return npos;
+ }
+
+ if (pos < m_size)
+ {
+ ++pos;
+ }
+ else
+ {
+ pos = m_size;
+ }
+
+ for (const CharT *ptr = m_data + pos; ptr != m_data;)
+ {
+ if (Traits::eq(*--ptr, c))
+ {
+ return static_cast<size_type>(ptr - m_data);
+ }
+ }
+ return npos;
+ }
+
+ size_type rfind(const CharT *s, size_type pos, size_type n) const noexcept
+ {
+ if (n && !s)
+ {
+ return npos;
+ }
+
+ pos = (std::min)(pos, m_size);
+ if (n < m_size - pos)
+ {
+ pos += n;
+ }
+ else
+ {
+ pos = m_size;
+ }
+ const CharT *r = _s_find_end(m_data, m_data + pos, s, s + n);
+ if (n > 0 && r == m_data + pos)
+ {
+ return npos;
+ }
+ return static_cast<size_type>(r - m_data);
+ }
+
+ constexpr size_type rfind(const CharT *s, size_type pos = npos) const noexcept
+ {
+ return this->rfind(s, pos, traits_type::length(s));
+ }
+
+ constexpr size_type find_first_of(basic_string_view s, size_type pos = 0) const noexcept
+ {
+ return this->find_first_of(s.m_data, pos, s.m_size);
+ }
+
+ constexpr size_type find_first_of(CharT c, size_type pos = 0) const noexcept { return this->find(c, pos); }
+
+ size_type find_first_of(const CharT *s, size_type pos, size_type n) const noexcept
+ {
+ if (pos >= m_size || !n || !s)
+ {
+ return npos;
+ }
+
+ const CharT *r = _s_find_first_of_ce(m_data + pos, m_data + m_size, s, s + n);
+
+ if (r == m_data + m_size)
+ {
+ return npos;
+ }
+
+ return static_cast<size_type>(r - m_data);
+ }
+
+ constexpr size_type find_first_of(const CharT *s, size_type pos = 0) const noexcept
+ {
+ return this->find_first_of(s, pos, traits_type::length(s));
+ }
+
+ constexpr size_type find_last_of(basic_string_view s, size_type pos = npos) const noexcept
+ {
+ return this->find_last_of(s.m_data, pos, s.m_size);
+ }
+
+ constexpr size_type find_last_of(CharT c, size_type pos = npos) const noexcept
+ {
+ return this->rfind(c, pos);
+ }
+
+ size_type find_last_of(const CharT *s, size_type pos, size_type n) const noexcept
+ {
+ if (!n || s == nullptr)
+ {
+ return npos;
+ }
+
+ if (pos < m_size)
+ {
+ ++pos;
+ }
+ else
+ {
+ pos = m_size;
+ }
+
+ for (const CharT *ptr = m_data + pos; ptr != m_data;)
+ {
+ const CharT *r = Traits::find(s, n, *--ptr);
+ if (r)
+ {
+ return static_cast<size_type>(ptr - m_data);
+ }
+ }
+
+ return npos;
+ }
+
+ constexpr size_type find_last_of(const CharT *s, size_type pos = npos) const noexcept
+ {
+ return this->find_last_of(s, pos, traits_type::length(s));
+ }
+
+ size_type find_first_not_of(basic_string_view s, size_type pos = 0) const noexcept
+ {
+ if (s.m_size && !s.m_data)
+ {
+ return npos;
+ }
+ return this->find_first_not_of(s.m_data, pos, s.m_size);
+ }
+
+ size_type find_first_not_of(CharT c, size_type pos = 0) const noexcept
+ {
+ if (!m_data || pos >= m_size)
+ {
+ return npos;
+ }
+
+ const CharT *pend = m_data + m_size;
+ for (const CharT *ptr = m_data + pos; ptr != pend; ++ptr)
+ {
+ if (!Traits::eq(*ptr, c))
+ {
+ return static_cast<size_type>(ptr - m_data);
+ }
+ }
+
+ return npos;
+ }
+
+ size_type find_first_not_of(const CharT *s, size_type pos, size_type n) const noexcept
+ {
+ if (n && s == nullptr)
+ {
+ return npos;
+ }
+
+ if (m_data == nullptr || pos >= m_size)
+ {
+ return npos;
+ }
+
+ const CharT *pend = m_data + m_size;
+ for (const CharT *ptr = m_data + pos; ptr != pend; ++ptr)
+ {
+ if (Traits::find(s, n, *ptr) == 0)
+ {
+ return static_cast<size_type>(ptr - m_data);
+ }
+ }
+
+ return npos;
+ }
+
+ constexpr size_type find_first_not_of(const CharT *s, size_type pos = 0) const noexcept
+ {
+ return this->find_first_not_of(s, pos, traits_type::length(s));
+ }
+
+ size_type find_last_not_of(basic_string_view s, size_type pos = npos) const noexcept
+ {
+ if (s.m_size && !s.m_data)
+ {
+ return npos;
+ }
+ return this->find_last_not_of(s.m_data, pos, s.m_size);
+ }
+
+ size_type find_last_not_of(CharT c, size_type pos = npos) const noexcept
+ {
+ if (pos < m_size)
+ {
+ ++pos;
+ }
+ else
+ {
+ pos = m_size;
+ }
+
+ for (const CharT *ptr = m_data + pos; ptr != m_data;)
+ {
+ if (!Traits::eq(*--ptr, c))
+ {
+ return static_cast<size_type>(ptr - m_data);
+ }
+ }
+ return npos;
+ }
+
+ size_type find_last_not_of(const CharT *s, size_type pos, size_type n) const noexcept
+ {
+ if (n && !s)
+ {
+ return npos;
+ }
+
+ if (pos < m_size)
+ {
+ ++pos;
+ }
+ else
+ {
+ pos = m_size;
+ }
+
+ for (const CharT *ptr = m_data + pos; ptr != m_data;)
+ {
+ if (Traits::find(s, n, *--ptr) == 0)
+ {
+ return static_cast<size_type>(ptr - m_data);
+ }
+ }
+ return npos;
+ }
+
+ constexpr size_type find_last_not_of(const CharT *s, size_type pos = npos) const noexcept
+ {
+ return this->find_last_not_of(s, pos, traits_type::length(s));
+ }
+
+ private:
+ static int _s_compare(size_type n1, size_type n2) noexcept
+ {
+ const difference_type diff = n1 - n2;
+
+ if (diff > (std::numeric_limits<int>::max)())
+ {
+ return (std::numeric_limits<int>::max)();
+ }
+
+ if (diff < (std::numeric_limits<int>::min)())
+ {
+ return (std::numeric_limits<int>::min)();
+ }
+
+ return static_cast<int>(diff);
+ }
+
+ static const CharT *_s_search_substr(
+ const CharT *first1,
+ const CharT *last1,
+ const CharT *first2,
+ const CharT *last2)
+ {
+ const ptrdiff_t length2 = last2 - first2;
+ if (length2 == 0)
+ {
+ return first1;
+ }
+
+ ptrdiff_t length1 = last1 - first1;
+ if (length1 < length2)
+ {
+ return last1;
+ }
+
+ while (true)
+ {
+ length1 = last1 - first1;
+ if (length1 < length2)
+ {
+ return last1;
+ }
+
+ first1 = Traits::find(first1, length1 - length2 + 1, *first2);
+ if (first1 == 0)
+ {
+ return last1;
+ }
+
+ if (Traits::compare(first1, first2, length2) == 0)
+ {
+ return first1;
+ }
+
+ ++first1;
+ }
+ }
+
+ static const CharT *_s_find_end(
+ const CharT *first1,
+ const CharT *last1,
+ const CharT *first2,
+ const CharT *last2)
+ {
+ const CharT *r = last1;
+ if (first2 == last2)
+ {
+ return r;
+ }
+
+ while (true)
+ {
+ while (true)
+ {
+ if (first1 == last1)
+ {
+ return r;
+ }
+ if (Traits::eq(*first1, *first2))
+ {
+ break;
+ }
+ ++first1;
+ }
+
+ const CharT *m1 = first1;
+ const CharT *m2 = first2;
+ while (true)
+ {
+ if (++m2 == last2)
+ {
+ r = first1;
+ ++first1;
+ break;
+ }
+ if (++m1 == last1)
+ {
+ return r;
+ }
+ if (!Traits::eq(*m1, *m2))
+ {
+ ++first1;
+ break;
+ }
+ }
+ }
+ }
+
+ static const CharT *_s_find_first_of_ce(
+ const CharT *first1,
+ const CharT *last1,
+ const CharT *first2,
+ const CharT *last2)
+ {
+ for (; first1 != last1; ++first1)
+ {
+ for (const CharT *ptr = first2; ptr != last2; ++ptr)
+ {
+ if (Traits::eq(*first1, *ptr))
+ {
+ return first1;
+ }
+ }
+ }
+ return last1;
+ }
+
+ size_type m_size;
+ const CharT *m_data;
+ };
+
+ // operator ==
+ template <class CharT, class Traits>
+ bool operator==(
+ const basic_string_view<CharT, Traits> &lhs,
+ const basic_string_view<CharT, Traits> &rhs) noexcept
+ {
+ return (lhs.size() != rhs.size()) ? false : lhs.compare(rhs) == 0;
+ }
+
+ template <class CharT, class Traits>
+ bool operator==(
+ const basic_string_view<CharT, Traits> &lhs,
+ typename std::common_type<basic_string_view<CharT, Traits>>::type &rhs) noexcept
+ {
+ return (lhs.size() != rhs.size()) ? false : lhs.compare(rhs) == 0;
+ }
+
+ template <class CharT, class Traits>
+ bool operator==(
+ typename std::common_type<basic_string_view<CharT, Traits>>::type &lhs,
+ const basic_string_view<CharT, Traits> &rhs) noexcept
+ {
+ return (lhs.size() != rhs.size()) ? false : lhs.compare(rhs) == 0;
+ }
+
+ // operator !=
+ template <class CharT, class Traits>
+ bool operator!=(
+ const basic_string_view<CharT, Traits> &lhs,
+ const basic_string_view<CharT, Traits> &rhs) noexcept
+ {
+ return (lhs.size() != rhs.size()) ? true : lhs.compare(rhs) != 0;
+ }
+
+ template <class CharT, class Traits>
+ bool operator!=(
+ const basic_string_view<CharT, Traits> &lhs,
+ typename std::common_type<basic_string_view<CharT, Traits>>::type &rhs) noexcept
+ {
+ return (lhs.size() != rhs.size()) ? true : lhs.compare(rhs) != 0;
+ }
+
+ template <class CharT, class Traits>
+ bool operator!=(
+ typename std::common_type<basic_string_view<CharT, Traits>>::type &lhs,
+ const basic_string_view<CharT, Traits> &rhs) noexcept
+ {
+ return (lhs.size() != rhs.size()) ? true : lhs.compare(rhs) != 0;
+ }
+
+ // operator <
+ template <class CharT, class Traits>
+ bool operator<(
+ const basic_string_view<CharT, Traits> &lhs,
+ const basic_string_view<CharT, Traits> &rhs) noexcept
+ {
+ return lhs.compare(rhs) < 0;
+ }
+
+ template <class CharT, class Traits>
+ constexpr bool operator<(
+ const basic_string_view<CharT, Traits> &lhs,
+ typename std::common_type<basic_string_view<CharT, Traits>>::type &rhs) noexcept
+ {
+ return lhs.compare(rhs) < 0;
+ }
+
+ template <class CharT, class Traits>
+ constexpr bool operator<(
+ typename std::common_type<basic_string_view<CharT, Traits>>::type &lhs,
+ const basic_string_view<CharT, Traits> &rhs) noexcept
+ {
+ return lhs.compare(rhs) < 0;
+ }
+
+ // operator >
+ template <class CharT, class Traits>
+ constexpr bool operator>(
+ const basic_string_view<CharT, Traits> &lhs,
+ const basic_string_view<CharT, Traits> &rhs) noexcept
+ {
+ return lhs.compare(rhs) > 0;
+ }
+
+ template <class CharT, class Traits>
+ constexpr bool operator>(
+ const basic_string_view<CharT, Traits> &lhs,
+ typename std::common_type<basic_string_view<CharT, Traits>>::type &rhs) noexcept
+ {
+ return lhs.compare(rhs) > 0;
+ }
+
+ template <class CharT, class Traits>
+ constexpr bool operator>(
+ typename std::common_type<basic_string_view<CharT, Traits>>::type &lhs,
+ const basic_string_view<CharT, Traits> &rhs) noexcept
+ {
+ return lhs.compare(rhs) > 0;
+ }
+
+ // operator <=
+ template <class CharT, class Traits>
+ constexpr bool operator<=(
+ const basic_string_view<CharT, Traits> &lhs,
+ const basic_string_view<CharT, Traits> &rhs) noexcept
+ {
+ return lhs.compare(rhs) <= 0;
+ }
+
+ template <class CharT, class Traits>
+ constexpr bool operator<=(
+ const basic_string_view<CharT, Traits> &lhs,
+ typename std::common_type<basic_string_view<CharT, Traits>>::type &rhs) noexcept
+ {
+ return lhs.compare(rhs) <= 0;
+ }
+
+ template <class CharT, class Traits>
+ constexpr bool operator<=(
+ typename std::common_type<basic_string_view<CharT, Traits>>::type &lhs,
+ const basic_string_view<CharT, Traits> &rhs) noexcept
+ {
+ return lhs.compare(rhs) <= 0;
+ }
+
+ // operator >=
+ template <class CharT, class Traits>
+ constexpr bool operator>=(
+ const basic_string_view<CharT, Traits> &lhs,
+ const basic_string_view<CharT, Traits> &rhs) noexcept
+ {
+ return lhs.compare(rhs) >= 0;
+ }
+
+ template <class CharT, class Traits>
+ constexpr bool operator>=(
+ const basic_string_view<CharT, Traits> &lhs,
+ typename std::common_type<basic_string_view<CharT, Traits>>::type &rhs) noexcept
+ {
+ return lhs.compare(rhs) >= 0;
+ }
+
+ template <class CharT, class Traits>
+ constexpr bool operator>=(
+ typename std::common_type<basic_string_view<CharT, Traits>>::type &lhs,
+ const basic_string_view<CharT, Traits> &rhs) noexcept
+ {
+ return lhs.compare(rhs) >= 0;
+ }
+
+ typedef basic_string_view<char> string_view;
+ typedef basic_string_view<char16_t> u16string_view;
+ typedef basic_string_view<char32_t> u32string_view;
+ typedef basic_string_view<wchar_t> wstring_view;
+
+ inline namespace literals
+ {
+ inline namespace string_view_literals
+ {
+ inline basic_string_view<char> operator"" _sv(const char *s, size_t length) noexcept
+ {
+ return basic_string_view<char>(s, length);
+ }
+
+ inline basic_string_view<wchar_t> operator"" _sv(const wchar_t *s, size_t length) noexcept
+ {
+ return basic_string_view<wchar_t>(s, length);
+ }
+
+ inline basic_string_view<char16_t> operator"" _sv(const char16_t *s, size_t length) noexcept
+ {
+ return basic_string_view<char16_t>(s, length);
+ }
+
+ inline basic_string_view<char32_t> operator"" _sv(const char32_t *s, size_t length) noexcept
+ {
+ return basic_string_view<char32_t>(s, length);
+ }
+ } // namespace string_view_literals
+
+ } // namespace literals
+
+ using StringView = string_view;
+ } // namespace Crt
+} // namespace Aws
+
+// hash
+namespace std
+{
+ template <class CharT, class Traits> struct hash<Aws::Crt::basic_string_view<CharT, Traits>>
+ {
+ size_t operator()(const Aws::Crt::basic_string_view<CharT, Traits> &val) const noexcept;
+ };
+
+ template <class CharT, class Traits>
+ size_t hash<Aws::Crt::basic_string_view<CharT, Traits>>::operator()(
+ const Aws::Crt::basic_string_view<CharT, Traits> &val) const noexcept
+ {
+ auto str = std::basic_string<CharT, Traits>(val.data(), val.size());
+ return std::hash<std::basic_string<CharT, Traits>>()(str);
+ }
+} // namespace std
diff --git a/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/Types.h b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/Types.h
new file mode 100644
index 0000000000..3972aa7aff
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/Types.h
@@ -0,0 +1,165 @@
+#pragma once
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+#include <aws/common/common.h>
+#include <aws/crt/Exports.h>
+#include <aws/crt/Optional.h>
+#include <aws/crt/StlAllocator.h>
+#include <aws/crt/StringView.h>
+#include <aws/io/socket.h>
+#include <aws/mqtt/mqtt.h>
+#include <functional>
+#include <list>
+#include <map>
+#include <sstream>
+#include <string>
+#include <unordered_map>
+#include <utility>
+#include <vector>
+
+struct aws_byte_buf;
+struct aws_byte_cursor;
+struct aws_socket_options;
+
+namespace Aws
+{
+ namespace Crt
+ {
+ using ByteBuf = aws_byte_buf;
+ using ByteCursor = aws_byte_cursor;
+
+ namespace Io
+ {
+ using IStream = std::basic_istream<char, std::char_traits<char>>;
+ } // namespace Io
+
+ namespace Mqtt
+ {
+ using QOS = aws_mqtt_qos;
+ using ReturnCode = aws_mqtt_connect_return_code;
+ } // namespace Mqtt
+
+ template <typename T> class StlAllocator;
+ using String = std::basic_string<char, std::char_traits<char>, StlAllocator<char>>;
+ using StringStream = std::basic_stringstream<char, std::char_traits<char>, StlAllocator<char>>;
+ template <typename K, typename V> using Map = std::map<K, V, std::less<K>, StlAllocator<std::pair<const K, V>>>;
+ template <typename K, typename V>
+ using UnorderedMap =
+ std::unordered_map<K, V, std::hash<K>, std::equal_to<K>, StlAllocator<std::pair<const K, V>>>;
+ template <typename K, typename V>
+ using MultiMap = std::multimap<K, V, std::less<K>, StlAllocator<std::pair<const K, V>>>;
+ template <typename T> using Vector = std::vector<T, StlAllocator<T>>;
+ template <typename T> using List = std::list<T, StlAllocator<T>>;
+
+ AWS_CRT_CPP_API ByteBuf ByteBufFromCString(const char *str) noexcept;
+ AWS_CRT_CPP_API ByteBuf ByteBufFromEmptyArray(const uint8_t *array, size_t len) noexcept;
+ AWS_CRT_CPP_API ByteBuf ByteBufFromArray(const uint8_t *array, size_t capacity) noexcept;
+ AWS_CRT_CPP_API ByteBuf ByteBufNewCopy(Allocator *alloc, const uint8_t *array, size_t len);
+ AWS_CRT_CPP_API void ByteBufDelete(ByteBuf &);
+
+ AWS_CRT_CPP_API ByteCursor ByteCursorFromCString(const char *str) noexcept;
+ AWS_CRT_CPP_API ByteCursor ByteCursorFromString(const Crt::String &str) noexcept;
+ AWS_CRT_CPP_API ByteCursor ByteCursorFromStringView(const Crt::StringView &str) noexcept;
+ AWS_CRT_CPP_API ByteCursor ByteCursorFromByteBuf(const ByteBuf &) noexcept;
+ AWS_CRT_CPP_API ByteCursor ByteCursorFromArray(const uint8_t *array, size_t len) noexcept;
+
+ AWS_CRT_CPP_API Vector<uint8_t> Base64Decode(const String &decode);
+ AWS_CRT_CPP_API String Base64Encode(const Vector<uint8_t> &encode);
+
+ template <typename RawType, typename TargetType> using TypeConvertor = std::function<TargetType(RawType)>;
+
+ /**
+ * Template function to convert an aws_array_list of RawType to a C++ like Vector of TargetType.
+ * A conversion function should be provided to do the type conversion
+ */
+ template <typename RawType, typename TargetType>
+ Vector<TargetType> ArrayListToVector(const aws_array_list *array, TypeConvertor<RawType, TargetType> conv)
+ {
+ Vector<TargetType> v;
+ size_t cnt = aws_array_list_length(array);
+ for (size_t i = 0; i < cnt; i++)
+ {
+ RawType t;
+ aws_array_list_get_at(array, &t, i);
+ v.emplace_back(conv(t));
+ }
+ return v;
+ }
+
+ /**
+ * Template function to convert an aws_array_list of RawType to a C++ like Vector of TargetType.
+ * This template assumes a direct constructor: TargetType(RawType) is available
+ */
+ template <typename RawType, typename TargetType>
+ Vector<TargetType> ArrayListToVector(const aws_array_list *array)
+ {
+ Vector<TargetType> v;
+ size_t cnt = aws_array_list_length(array);
+ for (size_t i = 0; i < cnt; i++)
+ {
+ RawType t;
+ aws_array_list_get_at(array, &t, i);
+ v.emplace_back(TargetType(t));
+ }
+ return v;
+ }
+
+ /**
+ * Template function to convert an aws_array_list of Type to a C++ like Vector of Type.
+ */
+ template <typename Type> Vector<Type> ArrayListToVector(const aws_array_list *array)
+ {
+ Vector<Type> v;
+ size_t cnt = aws_array_list_length(array);
+ for (size_t i = 0; i < cnt; i++)
+ {
+ Type t;
+ aws_array_list_get_at(array, &t, i);
+ v.emplace_back(t);
+ }
+ return v;
+ }
+
+ AWS_CRT_CPP_API inline StringView ByteCursorToStringView(const ByteCursor &bc)
+ {
+ return StringView(reinterpret_cast<char *>(bc.ptr), bc.len);
+ }
+
+ AWS_CRT_CPP_API inline ByteCursor StringViewToByteCursor(const StringView &sv)
+ {
+ ByteCursor bc;
+ bc.ptr = (uint8_t *)(sv.data());
+ bc.len = sv.size();
+ return bc;
+ }
+
+ template <typename T> void Delete(T *t, Allocator *allocator)
+ {
+ t->~T();
+ aws_mem_release(allocator, t);
+ }
+
+ template <typename T, typename... Args> T *New(Allocator *allocator, Args &&...args)
+ {
+ T *t = reinterpret_cast<T *>(aws_mem_acquire(allocator, sizeof(T)));
+ if (!t)
+ return nullptr;
+ return new (t) T(std::forward<Args>(args)...);
+ }
+
+ template <typename T, typename... Args> std::shared_ptr<T> MakeShared(Allocator *allocator, Args &&...args)
+ {
+ T *t = reinterpret_cast<T *>(aws_mem_acquire(allocator, sizeof(T)));
+ if (!t)
+ return nullptr;
+ new (t) T(std::forward<Args>(args)...);
+
+ return std::shared_ptr<T>(t, [allocator](T *obj) { Delete(obj, allocator); });
+ }
+
+ template <typename T> using ScopedResource = std::unique_ptr<T, std::function<void(T *)>>;
+
+ } // namespace Crt
+} // namespace Aws
diff --git a/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/UUID.h b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/UUID.h
new file mode 100644
index 0000000000..5ca53221cc
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/UUID.h
@@ -0,0 +1,42 @@
+#pragma once
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+#include <aws/crt/StlAllocator.h>
+#include <aws/crt/Types.h>
+
+#include <aws/common/uuid.h>
+
+namespace Aws
+{
+ namespace Crt
+ {
+ /**
+ * Utility class for creating UUIDs and serializing them to a string
+ */
+ class AWS_CRT_CPP_API UUID final
+ {
+ public:
+ UUID() noexcept;
+ UUID(const String &str) noexcept;
+
+ UUID &operator=(const String &str) noexcept;
+
+ bool operator==(const UUID &other) noexcept;
+ bool operator!=(const UUID &other) noexcept;
+ operator String() const;
+ operator ByteBuf() const noexcept;
+
+ inline operator bool() const noexcept { return m_good; }
+
+ int GetLastError() const noexcept;
+
+ String ToString() const;
+
+ private:
+ aws_uuid m_uuid;
+ bool m_good;
+ };
+ } // namespace Crt
+} // namespace Aws
diff --git a/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/auth/Credentials.h b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/auth/Credentials.h
new file mode 100644
index 0000000000..48181d1ce0
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/auth/Credentials.h
@@ -0,0 +1,585 @@
+#pragma once
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+
+#include <aws/crt/Exports.h>
+#include <aws/crt/Types.h>
+#include <aws/crt/http/HttpConnection.h>
+#include <aws/crt/io/TlsOptions.h>
+
+#include <chrono>
+#include <functional>
+
+struct aws_credentials;
+struct aws_credentials_provider;
+
+namespace Aws
+{
+ namespace Crt
+ {
+ namespace Io
+ {
+ class ClientBootstrap;
+ }
+
+ namespace Http
+ {
+ class HttpClientConnectionProxyOptions;
+ }
+
+ namespace Auth
+ {
+ /**
+ * A class to hold the basic components necessary for various AWS authentication protocols.
+ */
+ class AWS_CRT_CPP_API Credentials
+ {
+ public:
+ Credentials(const aws_credentials *credentials) noexcept;
+ Credentials(
+ ByteCursor access_key_id,
+ ByteCursor secret_access_key,
+ ByteCursor session_token,
+ uint64_t expiration_timepoint_in_seconds,
+ Allocator *allocator = ApiAllocator()) noexcept;
+
+ /**
+ * Create new anonymous Credentials.
+ * Use anonymous Credentials when you want to skip signing.
+ * @param allocator
+ */
+ Credentials(Allocator *allocator = ApiAllocator()) noexcept;
+
+ ~Credentials();
+
+ Credentials(const Credentials &) = delete;
+ Credentials(Credentials &&) = delete;
+ Credentials &operator=(const Credentials &) = delete;
+ Credentials &operator=(Credentials &&) = delete;
+
+ /**
+ * Gets the value of the access key component of aws credentials
+ */
+ ByteCursor GetAccessKeyId() const noexcept;
+
+ /**
+ * Gets the value of the secret access key component of aws credentials
+ */
+ ByteCursor GetSecretAccessKey() const noexcept;
+
+ /**
+ * Gets the value of the session token of aws credentials
+ */
+ ByteCursor GetSessionToken() const noexcept;
+
+ /**
+ * Gets the expiration timestamp for the credentials, or UINT64_MAX if no expiration
+ */
+ uint64_t GetExpirationTimepointInSeconds() const noexcept;
+
+ /**
+ * Validity check - returns true if the instance is valid, false otherwise
+ */
+ explicit operator bool() const noexcept;
+
+ /**
+ * Returns the underlying credentials implementation.
+ */
+ const aws_credentials *GetUnderlyingHandle() const noexcept { return m_credentials; }
+
+ private:
+ const aws_credentials *m_credentials;
+ };
+
+ /**
+ * Callback invoked by credentials providers when resolution succeeds (credentials will be non-null)
+ * or fails (credentials will be null)
+ */
+ using OnCredentialsResolved = std::function<void(std::shared_ptr<Credentials>, int errorCode)>;
+
+ /**
+ * Invoked when the native delegate credentials provider needs to fetch a credential.
+ */
+ using GetCredentialsHandler = std::function<std::shared_ptr<Credentials>()>;
+
+ /**
+ * Base interface for all credentials providers. Credentials providers are objects that
+ * retrieve AWS credentials from some source.
+ */
+ class AWS_CRT_CPP_API ICredentialsProvider : public std::enable_shared_from_this<ICredentialsProvider>
+ {
+ public:
+ virtual ~ICredentialsProvider() = default;
+
+ /**
+ * Asynchronous method to query for AWS credentials based on the internal provider implementation.
+ */
+ virtual bool GetCredentials(const OnCredentialsResolved &onCredentialsResolved) const = 0;
+
+ /**
+ * Returns the underlying credentials provider implementation. Support for credentials providers
+ * not based on a C implementation is theoretically possible, but requires some re-implementation to
+ * support provider chains and caching (whose implementations rely on links to C implementation
+ * providers)
+ */
+ virtual aws_credentials_provider *GetUnderlyingHandle() const noexcept = 0;
+
+ /**
+ * Validity check method
+ */
+ virtual bool IsValid() const noexcept = 0;
+ };
+
+ /**
+ * Configuration options for the static credentials provider
+ */
+ struct AWS_CRT_CPP_API CredentialsProviderStaticConfig
+ {
+ CredentialsProviderStaticConfig()
+ {
+ AWS_ZERO_STRUCT(AccessKeyId);
+ AWS_ZERO_STRUCT(SecretAccessKey);
+ AWS_ZERO_STRUCT(SessionToken);
+ }
+
+ /**
+ * The value of the access key component for the provider's static aws credentials
+ */
+ ByteCursor AccessKeyId;
+
+ /**
+ * The value of the secret access key component for the provider's static aws credentials
+ */
+ ByteCursor SecretAccessKey;
+
+ /**
+ * The value of the session token for the provider's static aws credentials
+ */
+ ByteCursor SessionToken;
+ };
+
+ /**
+ * Configuration options for the profile credentials provider
+ */
+ struct AWS_CRT_CPP_API CredentialsProviderProfileConfig
+ {
+ CredentialsProviderProfileConfig() : Bootstrap(nullptr), TlsContext(nullptr)
+ {
+ AWS_ZERO_STRUCT(ProfileNameOverride);
+ AWS_ZERO_STRUCT(ConfigFileNameOverride);
+ AWS_ZERO_STRUCT(CredentialsFileNameOverride);
+ }
+
+ /**
+ * Override profile name to use (instead of default) when the provider sources credentials
+ */
+ ByteCursor ProfileNameOverride;
+
+ /**
+ * Override file path (instead of '~/.aws/config' for the aws config file to use during
+ * credential sourcing
+ */
+ ByteCursor ConfigFileNameOverride;
+
+ /**
+ * Override file path (instead of '~/.aws/credentials' for the aws credentials file to use during
+ * credential sourcing
+ */
+ ByteCursor CredentialsFileNameOverride;
+
+ /**
+ * Connection bootstrap to use for any network connections made while sourcing credentials.
+ * (for example, a profile that uses assume-role will need to query STS).
+ */
+ Io::ClientBootstrap *Bootstrap;
+
+ /**
+ * Client TLS context to use for any secure network connections made while sourcing credentials
+ * (for example, a profile that uses assume-role will need to query STS).
+ *
+ * If a TLS context is needed, and you did not pass one in, it will be created automatically.
+ * However, you are encouraged to pass in a shared one since these are expensive objects.
+ * If using BYO_CRYPTO, you must provide the TLS context since it cannot be created automatically.
+ */
+ Io::TlsContext *TlsContext;
+ };
+
+ /**
+ * Configuration options for the Ec2 instance metadata service credentials provider
+ */
+ struct AWS_CRT_CPP_API CredentialsProviderImdsConfig
+ {
+ CredentialsProviderImdsConfig() : Bootstrap(nullptr) {}
+
+ /**
+ * Connection bootstrap to use to create the http connection required to
+ * query credentials from the Ec2 instance metadata service
+ *
+ * Note: If null, then the default ClientBootstrap is used
+ * (see Aws::Crt::ApiHandle::GetOrCreateStaticDefaultClientBootstrap)
+ */
+ Io::ClientBootstrap *Bootstrap;
+ };
+
+ /**
+ * Configuration options for a chain-of-responsibility-based credentials provider.
+ * This provider works by traversing the chain and returning the first positive
+ * result.
+ */
+ struct AWS_CRT_CPP_API CredentialsProviderChainConfig
+ {
+ CredentialsProviderChainConfig() : Providers() {}
+
+ /**
+ * The sequence of providers that make up the chain.
+ */
+ Vector<std::shared_ptr<ICredentialsProvider>> Providers;
+ };
+
+ /**
+ * Configuration options for a provider that caches the results of another provider
+ */
+ struct AWS_CRT_CPP_API CredentialsProviderCachedConfig
+ {
+ CredentialsProviderCachedConfig() : Provider(), CachedCredentialTTL() {}
+
+ /**
+ * The provider to cache credentials from
+ */
+ std::shared_ptr<ICredentialsProvider> Provider;
+
+ /**
+ * How long a cached credential set will be used for
+ */
+ std::chrono::milliseconds CachedCredentialTTL;
+ };
+
+ /**
+ * Configuration options for a provider that implements a cached provider chain
+ * based on the AWS SDK defaults:
+ *
+ * Cache-Of(Environment -> Profile -> IMDS)
+ */
+ struct AWS_CRT_CPP_API CredentialsProviderChainDefaultConfig
+ {
+ CredentialsProviderChainDefaultConfig() : Bootstrap(nullptr), TlsContext(nullptr) {}
+
+ /**
+ * Connection bootstrap to use for any network connections made while sourcing credentials.
+ *
+ * Note: If null, then the default ClientBootstrap is used
+ * (see Aws::Crt::ApiHandle::GetOrCreateStaticDefaultClientBootstrap)
+ */
+ Io::ClientBootstrap *Bootstrap;
+
+ /**
+ * Client TLS context to use for any secure network connections made while sourcing credentials.
+ *
+ * If not provided the default chain will construct a new one, but these
+ * are expensive objects so you are encouraged to pass in a shared one.
+ * Must be provided if using BYO_CRYPTO.
+ */
+ Io::TlsContext *TlsContext;
+ };
+
+ /**
+ * Configuration options for the X509 credentials provider
+ */
+ struct AWS_CRT_CPP_API CredentialsProviderX509Config
+ {
+ CredentialsProviderX509Config()
+ : Bootstrap(nullptr), TlsOptions(), ThingName(), RoleAlias(), Endpoint(), ProxyOptions()
+ {
+ }
+
+ /**
+ * Connection bootstrap to use to create the http connection required to
+ * query credentials from the x509 provider
+ *
+ * Note: If null, then the default ClientBootstrap is used
+ * (see Aws::Crt::ApiHandle::GetOrCreateStaticDefaultClientBootstrap)
+ */
+ Io::ClientBootstrap *Bootstrap;
+
+ /* TLS connection options that have been initialized with your x509 certificate and private key */
+ Io::TlsConnectionOptions TlsOptions;
+
+ /* IoT thing name you registered with AWS IOT for your device, it will be used in http request header */
+ String ThingName;
+
+ /* Iot role alias you created with AWS IoT for your IAM role, it will be used in http request path */
+ String RoleAlias;
+
+ /**
+ * AWS account specific endpoint that can be acquired using AWS CLI following instructions from the demo
+ * example: c2sakl5huz0afv.credentials.iot.us-east-1.amazonaws.com
+ *
+ * This a different endpoint than the IoT data mqtt broker endpoint.
+ */
+ String Endpoint;
+
+ /**
+ * (Optional) Http proxy configuration for the http request that fetches credentials
+ */
+ Optional<Http::HttpClientConnectionProxyOptions> ProxyOptions;
+ };
+
+ /**
+ * Configuration options for the delegate credentials provider
+ */
+ struct AWS_CRT_CPP_API CredentialsProviderDelegateConfig
+ {
+ /* handler to provider credentials */
+ GetCredentialsHandler Handler;
+ };
+
+ /**
+ * A pair defining an identity provider and a valid login token sourced from it.
+ */
+ struct AWS_CRT_CPP_API CognitoLoginPair
+ {
+
+ /**
+ * Name of an identity provider
+ */
+ String IdentityProviderName;
+
+ /**
+ * Valid login token source from the identity provider
+ */
+ String IdentityProviderToken;
+ };
+
+ /**
+ * Configuration options for the Cognito credentials provider
+ */
+ struct AWS_CRT_CPP_API CredentialsProviderCognitoConfig
+ {
+ CredentialsProviderCognitoConfig();
+
+ /**
+ * Cognito service regional endpoint to source credentials from.
+ */
+ String Endpoint;
+
+ /**
+ * Cognito identity to fetch credentials relative to.
+ */
+ String Identity;
+
+ /**
+ * Optional set of identity provider token pairs to allow for authenticated identity access.
+ */
+ Optional<Vector<CognitoLoginPair>> Logins;
+
+ /**
+ * Optional ARN of the role to be assumed when multiple roles were received in the token from the
+ * identity provider.
+ */
+ Optional<String> CustomRoleArn;
+
+ /**
+ * Connection bootstrap to use to create the http connection required to
+ * query credentials from the cognito provider
+ *
+ * Note: If null, then the default ClientBootstrap is used
+ * (see Aws::Crt::ApiHandle::GetOrCreateStaticDefaultClientBootstrap)
+ */
+ Io::ClientBootstrap *Bootstrap;
+
+ /**
+ * TLS configuration for secure socket connections.
+ */
+ Io::TlsContext TlsCtx;
+
+ /**
+ * (Optional) Http proxy configuration for the http request that fetches credentials
+ */
+ Optional<Http::HttpClientConnectionProxyOptions> ProxyOptions;
+ };
+
+ /**
+ * Configuration options for the STS credentials provider
+ */
+ struct AWS_CRT_CPP_API CredentialsProviderSTSConfig
+ {
+ CredentialsProviderSTSConfig();
+
+ /**
+ * Credentials provider to be used to sign the requests made to STS to fetch credentials.
+ */
+ std::shared_ptr<ICredentialsProvider> Provider;
+
+ /**
+ * Arn of the role to assume by fetching credentials for
+ */
+ String RoleArn;
+
+ /**
+ * Assumed role session identifier to be associated with the sourced credentials
+ */
+ String SessionName;
+
+ /**
+ * How long sourced credentials should remain valid for, in seconds. 900 is the minimum allowed value.
+ */
+ uint16_t DurationSeconds;
+
+ /**
+ * Connection bootstrap to use to create the http connection required to
+ * query credentials from the STS provider
+ *
+ * Note: If null, then the default ClientBootstrap is used
+ * (see Aws::Crt::ApiHandle::GetOrCreateStaticDefaultClientBootstrap)
+ */
+ Io::ClientBootstrap *Bootstrap;
+
+ /**
+ * TLS configuration for secure socket connections.
+ */
+ Io::TlsContext TlsCtx;
+
+ /**
+ * (Optional) Http proxy configuration for the http request that fetches credentials
+ */
+ Optional<Http::HttpClientConnectionProxyOptions> ProxyOptions;
+ };
+
+ /**
+ * Simple credentials provider implementation that wraps one of the internal C-based implementations.
+ *
+ * Contains a set of static factory methods for building each supported provider, as well as one for the
+ * default provider chain.
+ */
+ class AWS_CRT_CPP_API CredentialsProvider : public ICredentialsProvider
+ {
+ public:
+ CredentialsProvider(aws_credentials_provider *provider, Allocator *allocator = ApiAllocator()) noexcept;
+
+ virtual ~CredentialsProvider();
+
+ CredentialsProvider(const CredentialsProvider &) = delete;
+ CredentialsProvider(CredentialsProvider &&) = delete;
+ CredentialsProvider &operator=(const CredentialsProvider &) = delete;
+ CredentialsProvider &operator=(CredentialsProvider &&) = delete;
+
+ /**
+ * Asynchronous method to query for AWS credentials based on the internal provider implementation.
+ */
+ virtual bool GetCredentials(const OnCredentialsResolved &onCredentialsResolved) const override;
+
+ /**
+ * Returns the underlying credentials provider implementation.
+ */
+ virtual aws_credentials_provider *GetUnderlyingHandle() const noexcept override { return m_provider; }
+
+ /**
+ * Validity check method
+ */
+ virtual bool IsValid() const noexcept override { return m_provider != nullptr; }
+
+ /*
+ * Factory methods for all of the basic credentials provider types
+ */
+
+ /**
+ * Creates a provider that returns a fixed set of credentials
+ */
+ static std::shared_ptr<ICredentialsProvider> CreateCredentialsProviderStatic(
+ const CredentialsProviderStaticConfig &config,
+ Allocator *allocator = ApiAllocator());
+
+ /**
+ * Creates an anonymous provider that have anonymous credentials
+ * Use anonymous credentials when you want to skip signing
+ */
+ static std::shared_ptr<ICredentialsProvider> CreateCredentialsProviderAnonymous(
+ Allocator *allocator = ApiAllocator());
+
+ /**
+ * Creates a provider that returns credentials sourced from environment variables
+ */
+ static std::shared_ptr<ICredentialsProvider> CreateCredentialsProviderEnvironment(
+ Allocator *allocator = ApiAllocator());
+
+ /**
+ * Creates a provider that returns credentials sourced from config files
+ */
+ static std::shared_ptr<ICredentialsProvider> CreateCredentialsProviderProfile(
+ const CredentialsProviderProfileConfig &config,
+ Allocator *allocator = ApiAllocator());
+
+ /**
+ * Creates a provider that returns credentials sourced from Ec2 instance metadata service
+ */
+ static std::shared_ptr<ICredentialsProvider> CreateCredentialsProviderImds(
+ const CredentialsProviderImdsConfig &config,
+ Allocator *allocator = ApiAllocator());
+
+ /**
+ * Creates a provider that sources credentials by querying a series of providers and
+ * returning the first valid credential set encountered
+ */
+ static std::shared_ptr<ICredentialsProvider> CreateCredentialsProviderChain(
+ const CredentialsProviderChainConfig &config,
+ Allocator *allocator = ApiAllocator());
+
+ /*
+ * Creates a provider that puts a simple time-based cache in front of its queries
+ * to a subordinate provider.
+ */
+ static std::shared_ptr<ICredentialsProvider> CreateCredentialsProviderCached(
+ const CredentialsProviderCachedConfig &config,
+ Allocator *allocator = ApiAllocator());
+
+ /**
+ * Creates the SDK-standard default credentials provider which is a cache-fronted chain of:
+ *
+ * Environment -> Profile -> IMDS/ECS
+ *
+ */
+ static std::shared_ptr<ICredentialsProvider> CreateCredentialsProviderChainDefault(
+ const CredentialsProviderChainDefaultConfig &config,
+ Allocator *allocator = ApiAllocator());
+
+ /**
+ * Creates a provider that sources credentials from the IoT X509 provider service
+ *
+ */
+ static std::shared_ptr<ICredentialsProvider> CreateCredentialsProviderX509(
+ const CredentialsProviderX509Config &config,
+ Allocator *allocator = ApiAllocator());
+
+ /**
+ * Creates a provider that sources credentials from the provided function.
+ *
+ */
+ static std::shared_ptr<ICredentialsProvider> CreateCredentialsProviderDelegate(
+ const CredentialsProviderDelegateConfig &config,
+ Allocator *allocator = ApiAllocator());
+
+ /**
+ * Creates a provider that sources credentials from the Cognito Identity service
+ */
+ static std::shared_ptr<ICredentialsProvider> CreateCredentialsProviderCognito(
+ const CredentialsProviderCognitoConfig &config,
+ Allocator *allocator = ApiAllocator());
+
+ /**
+ * Creates a provider that sources credentials from STS
+ */
+ static std::shared_ptr<ICredentialsProvider> CreateCredentialsProviderSTS(
+ const CredentialsProviderSTSConfig &config,
+ Allocator *allocator = ApiAllocator());
+
+ private:
+ static void s_onCredentialsResolved(aws_credentials *credentials, int error_code, void *user_data);
+
+ Allocator *m_allocator;
+ aws_credentials_provider *m_provider;
+ };
+ } // namespace Auth
+ } // namespace Crt
+} // namespace Aws
diff --git a/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/auth/Signing.h b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/auth/Signing.h
new file mode 100644
index 0000000000..5723f00e2b
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/auth/Signing.h
@@ -0,0 +1,99 @@
+#pragma once
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+
+#include <aws/crt/Exports.h>
+
+#include <aws/auth/signing_config.h>
+
+#include <functional>
+#include <memory>
+
+namespace Aws
+{
+ namespace Crt
+ {
+ namespace Http
+ {
+ class HttpRequest;
+ }
+
+ namespace Auth
+ {
+ /**
+ * RTTI indicator for signing configuration. We currently only support a single type (AWS), but
+ * we could expand to others in the future if needed.
+ */
+ enum class SigningConfigType
+ {
+ Aws = AWS_SIGNING_CONFIG_AWS
+ };
+
+ /**
+ * HTTP signing callback. The second parameter is an aws error code, The signing was successful
+ * iff the error code is AWS_ERROR_SUCCESS.
+ */
+ using OnHttpRequestSigningComplete =
+ std::function<void(const std::shared_ptr<Aws::Crt::Http::HttpRequest> &, int)>;
+
+ /**
+ * Base class for all different signing configurations. Type functions as a
+ * primitive RTTI for downcasting.
+ */
+ class AWS_CRT_CPP_API ISigningConfig
+ {
+ public:
+ ISigningConfig() = default;
+ ISigningConfig(const ISigningConfig &) = delete;
+ ISigningConfig(ISigningConfig &&) = delete;
+ ISigningConfig &operator=(const ISigningConfig &) = delete;
+ ISigningConfig &operator=(ISigningConfig &&) = delete;
+
+ virtual ~ISigningConfig() = default;
+
+ /**
+ * RTTI query for the SigningConfig hierarchy
+ * @return the type of signing configuration
+ */
+ virtual SigningConfigType GetType(void) const = 0;
+ };
+
+ /**
+ * Abstract base for all http request signers. Asynchronous interface. Intended to
+ * be a tight wrapper around aws-c-* signer implementations.
+ */
+ class AWS_CRT_CPP_API IHttpRequestSigner
+ {
+ public:
+ IHttpRequestSigner() = default;
+ IHttpRequestSigner(const IHttpRequestSigner &) = delete;
+ IHttpRequestSigner(IHttpRequestSigner &&) = delete;
+ IHttpRequestSigner &operator=(const IHttpRequestSigner &) = delete;
+ IHttpRequestSigner &operator=(IHttpRequestSigner &&) = delete;
+
+ virtual ~IHttpRequestSigner() = default;
+
+ /**
+ * Signs an http request based on the signing implementation and supplied configuration
+ * @param request http request to sign
+ * @param config base signing configuration. Actual type should match the configuration expected
+ * by the signer implementation
+ * @param completionCallback completion function to invoke when signing has completed or failed
+ * @return true if the signing process was kicked off, false if there was a synchronous failure.
+ */
+ virtual bool SignRequest(
+ const std::shared_ptr<Aws::Crt::Http::HttpRequest> &request,
+ const ISigningConfig &config,
+ const OnHttpRequestSigningComplete &completionCallback) = 0;
+
+ /**
+ * @return Whether or not the signer is in a valid state
+ */
+ virtual bool IsValid() const = 0;
+ };
+
+ } // namespace Auth
+ } // namespace Crt
+} // namespace Aws
diff --git a/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/auth/Sigv4Signing.h b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/auth/Sigv4Signing.h
new file mode 100644
index 0000000000..e902b1363f
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/auth/Sigv4Signing.h
@@ -0,0 +1,352 @@
+#pragma once
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+
+#include <aws/crt/Exports.h>
+
+#include <aws/crt/DateTime.h>
+#include <aws/crt/Types.h>
+#include <aws/crt/auth/Signing.h>
+
+struct aws_signing_config_aws;
+
+namespace Aws
+{
+ namespace Crt
+ {
+ namespace Auth
+ {
+ class Credentials;
+ class ICredentialsProvider;
+
+ /**
+ * Enumeration indicating what version of the AWS signing process we should use.
+ */
+ enum class SigningAlgorithm
+ {
+ /**
+ * Standard AWS Sigv4 signing using a symmetric secret, per
+ * https://docs.aws.amazon.com/general/latest/gr/signature-version-4.html
+ */
+ SigV4 = AWS_SIGNING_ALGORITHM_V4,
+
+ /**
+ * A variant of AWS Sigv4 signing that uses ecdsa signatures based on an ECC key, rather than relying on
+ * a shared secret.
+ */
+ SigV4A = AWS_SIGNING_ALGORITHM_V4_ASYMMETRIC,
+ };
+
+ /**
+ * What kind of AWS signature should be computed?
+ */
+ enum class SignatureType
+ {
+ /**
+ * A signature for a full http request should be computed, with header updates applied to the signing
+ * result.
+ */
+ HttpRequestViaHeaders = AWS_ST_HTTP_REQUEST_HEADERS,
+
+ /**
+ * A signature for a full http request should be computed, with query param updates applied to the
+ * signing result.
+ */
+ HttpRequestViaQueryParams = AWS_ST_HTTP_REQUEST_QUERY_PARAMS,
+
+ /**
+ * Compute a signature for a payload chunk.
+ */
+ HttpRequestChunk = AWS_ST_HTTP_REQUEST_CHUNK,
+
+ /**
+ * Compute a signature for an event stream event.
+ *
+ * This option is not yet supported.
+ */
+ HttpRequestEvent = AWS_ST_HTTP_REQUEST_EVENT,
+ };
+
+ /**
+ * A collection of signed body constants. Some are specific to certain
+ * signature types, while others are just there to save time (empty sha, for example).
+ */
+ namespace SignedBodyValue
+ {
+ /**
+ * The SHA-256 of an empty string:
+ * 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'
+ * For use with `Aws::Crt::Auth::AwsSigningConfig.SetSignedBodyValue()`.
+ */
+ AWS_CRT_CPP_API const char *EmptySha256Str();
+
+ /**
+ * 'UNSIGNED-PAYLOAD'
+ * For use with `Aws::Crt::Auth::AwsSigningConfig.SetSignedBodyValue()`.
+ */
+ AWS_CRT_CPP_API const char *UnsignedPayloadStr();
+
+ /**
+ * 'STREAMING-AWS4-HMAC-SHA256-PAYLOAD'
+ * For use with `Aws::Crt::Auth::AwsSigningConfig.SetSignedBodyValue()`.
+ */
+ AWS_CRT_CPP_API const char *StreamingAws4HmacSha256PayloadStr();
+ /**
+ * 'STREAMING-AWS4-HMAC-SHA256-EVENTS'
+ * For use with `Aws::Crt::Auth::AwsSigningConfig.SetSignedBodyValue()`.
+ */
+ AWS_CRT_CPP_API const char *StreamingAws4HmacSha256EventsStr();
+
+ /** @deprecated to avoid issues with /DELAYLOAD on Windows. */
+ AWS_CRT_CPP_API extern const char *UnsignedPayload;
+ /** @deprecated to avoid issues with /DELAYLOAD on Windows. */
+ AWS_CRT_CPP_API extern const char *EmptySha256;
+ /** @deprecated to avoid issues with /DELAYLOAD on Windows. */
+ AWS_CRT_CPP_API extern const char *StreamingAws4HmacSha256Payload;
+ /** @deprecated to avoid issues with /DELAYLOAD on Windows. */
+ AWS_CRT_CPP_API extern const char *StreamingAws4HmacSha256Events;
+ } // namespace SignedBodyValue
+
+ /**
+ * Controls if signing adds a header containing the canonical request's body value
+ */
+ enum class SignedBodyHeaderType
+ {
+ /**
+ * Do not add a header
+ */
+ None = AWS_SBHT_NONE,
+
+ /**
+ * Add the "x-amz-content-sha256" header with the canonical request's body value
+ */
+ XAmzContentSha256 = AWS_SBHT_X_AMZ_CONTENT_SHA256,
+ };
+
+ using ShouldSignHeaderCb = bool (*)(const Crt::ByteCursor *, void *);
+
+ /**
+ * Wrapper around the configuration structure specific to the AWS
+ * Sigv4 signing process
+ */
+ class AWS_CRT_CPP_API AwsSigningConfig : public ISigningConfig
+ {
+ public:
+ AwsSigningConfig(Allocator *allocator = ApiAllocator());
+ virtual ~AwsSigningConfig();
+
+ virtual SigningConfigType GetType() const noexcept override { return SigningConfigType::Aws; }
+
+ /**
+ * @return the signing process we want to invoke
+ */
+ SigningAlgorithm GetSigningAlgorithm() const noexcept;
+
+ /**
+ * Sets the signing process we want to invoke
+ */
+ void SetSigningAlgorithm(SigningAlgorithm algorithm) noexcept;
+
+ /**
+ * @return the type of signature we want to calculate
+ */
+ SignatureType GetSignatureType() const noexcept;
+
+ /**
+ * Sets the type of signature we want to calculate
+ */
+ void SetSignatureType(SignatureType signatureType) noexcept;
+
+ /**
+ * @return the AWS region to sign against
+ */
+ const Crt::String &GetRegion() const noexcept;
+
+ /**
+ * Sets the AWS region to sign against
+ */
+ void SetRegion(const Crt::String &region) noexcept;
+
+ /**
+ * @return the (signing) name of the AWS service to sign a request for
+ */
+ const Crt::String &GetService() const noexcept;
+
+ /**
+ * Sets the (signing) name of the AWS service to sign a request for
+ */
+ void SetService(const Crt::String &service) noexcept;
+
+ /**
+ * @return the timestamp to use during the signing process.
+ */
+ DateTime GetSigningTimepoint() const noexcept;
+
+ /**
+ * Sets the timestamp to use during the signing process.
+ */
+ void SetSigningTimepoint(const DateTime &date) noexcept;
+
+ /*
+ * We assume the uri will be encoded once in preparation for transmission. Certain services
+ * do not decode before checking signature, requiring us to actually double-encode the uri in the
+ * canonical request in order to pass a signature check.
+ */
+
+ /**
+ * @return whether or not the signing process should perform a uri encode step before creating the
+ * canonical request.
+ */
+ bool GetUseDoubleUriEncode() const noexcept;
+
+ /**
+ * Sets whether or not the signing process should perform a uri encode step before creating the
+ * canonical request.
+ */
+ void SetUseDoubleUriEncode(bool useDoubleUriEncode) noexcept;
+
+ /**
+ * @return whether or not the uri paths should be normalized when building the canonical request
+ */
+ bool GetShouldNormalizeUriPath() const noexcept;
+
+ /**
+ * Sets whether or not the uri paths should be normalized when building the canonical request
+ */
+ void SetShouldNormalizeUriPath(bool shouldNormalizeUriPath) noexcept;
+
+ /**
+ * @return whether or not to omit the session token during signing. Only set to true when performing
+ * a websocket handshake with IoT Core.
+ */
+ bool GetOmitSessionToken() const noexcept;
+
+ /**
+ * Sets whether or not to omit the session token during signing. Only set to true when performing
+ * a websocket handshake with IoT Core.
+ */
+ void SetOmitSessionToken(bool omitSessionToken) noexcept;
+
+ /**
+ * @return the ShouldSignHeadersCb from the underlying config.
+ */
+ ShouldSignHeaderCb GetShouldSignHeaderCallback() const noexcept;
+
+ /**
+ * Sets a callback invoked during the signing process for white-listing headers that can be signed.
+ * If you do not set this, all headers will be signed.
+ */
+ void SetShouldSignHeaderCallback(ShouldSignHeaderCb shouldSignHeaderCb) noexcept;
+
+ /**
+ * @return the should_sign_header_ud from the underlying config.
+ */
+ void *GetShouldSignHeaderUserData() const noexcept;
+
+ /**
+ * Sets the userData you could get from the ShouldSignHeaderCb callback function.
+ */
+ void SetShouldSignHeaderUserData(void *userData) noexcept;
+
+ /**
+ * @return the string used as the canonical request's body value.
+ * If string is empty, a value is be calculated from the payload during signing.
+ */
+ const Crt::String &GetSignedBodyValue() const noexcept;
+
+ /**
+ * Sets the string to use as the canonical request's body value.
+ * If an empty string is set (the default), a value will be calculated from the payload during signing.
+ * Typically, this is the SHA-256 of the (request/chunk/event) payload, written as lowercase hex.
+ * If this has been precalculated, it can be set here.
+ * Special values used by certain services can also be set (see Aws::Crt::Auth::SignedBodyValue).
+ */
+ void SetSignedBodyValue(const Crt::String &signedBodyValue) noexcept;
+
+ /**
+ * @return the name of the header to add that stores the signed body value
+ */
+ SignedBodyHeaderType GetSignedBodyHeader() const noexcept;
+
+ /**
+ * Sets the name of the header to add that stores the signed body value
+ */
+ void SetSignedBodyHeader(SignedBodyHeaderType signedBodyHeader) noexcept;
+
+ /**
+ * @return (Query param signing only) Gets the amount of time, in seconds, the (pre)signed URI will be
+ * good for
+ */
+ uint64_t GetExpirationInSeconds() const noexcept;
+
+ /**
+ * (Query param signing only) Sets the amount of time, in seconds, the (pre)signed URI will be good for
+ */
+ void SetExpirationInSeconds(uint64_t expirationInSeconds) noexcept;
+
+ /*
+ * For Sigv4 signing, either the credentials provider or the credentials must be set.
+ * Credentials, if set, takes precedence over the provider.
+ */
+
+ /**
+ * @return the credentials provider to use for signing.
+ */
+ const std::shared_ptr<ICredentialsProvider> &GetCredentialsProvider() const noexcept;
+
+ /**
+ * Set the credentials provider to use for signing.
+ */
+ void SetCredentialsProvider(const std::shared_ptr<ICredentialsProvider> &credsProvider) noexcept;
+
+ /**
+ * @return the credentials to use for signing.
+ */
+ const std::shared_ptr<Credentials> &GetCredentials() const noexcept;
+
+ /**
+ * Set the credentials to use for signing.
+ */
+ void SetCredentials(const std::shared_ptr<Credentials> &credentials) noexcept;
+
+ /// @private
+ const struct aws_signing_config_aws *GetUnderlyingHandle() const noexcept;
+
+ private:
+ Allocator *m_allocator;
+ std::shared_ptr<ICredentialsProvider> m_credentialsProvider;
+ std::shared_ptr<Credentials> m_credentials;
+ struct aws_signing_config_aws m_config;
+ Crt::String m_signingRegion;
+ Crt::String m_serviceName;
+ Crt::String m_signedBodyValue;
+ };
+
+ /**
+ * Http request signer that performs Aws Sigv4 signing. Expects the signing configuration to be and
+ * instance of AwsSigningConfig
+ */
+ class AWS_CRT_CPP_API Sigv4HttpRequestSigner : public IHttpRequestSigner
+ {
+ public:
+ Sigv4HttpRequestSigner(Allocator *allocator = ApiAllocator());
+ virtual ~Sigv4HttpRequestSigner() = default;
+
+ bool IsValid() const override { return true; }
+
+ /**
+ * Signs an http request with AWS-auth sigv4. OnCompletionCallback will be invoked upon completion.
+ */
+ virtual bool SignRequest(
+ const std::shared_ptr<Aws::Crt::Http::HttpRequest> &request,
+ const ISigningConfig &config,
+ const OnHttpRequestSigningComplete &completionCallback) override;
+
+ private:
+ Allocator *m_allocator;
+ };
+ } // namespace Auth
+ } // namespace Crt
+} // namespace Aws
diff --git a/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/crypto/HMAC.h b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/crypto/HMAC.h
new file mode 100644
index 0000000000..e4452f6bc5
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/crypto/HMAC.h
@@ -0,0 +1,150 @@
+#pragma once
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+#include <aws/cal/hmac.h>
+#include <aws/crt/Exports.h>
+#include <aws/crt/Types.h>
+
+struct aws_hmac;
+namespace Aws
+{
+ namespace Crt
+ {
+ namespace Crypto
+ {
+ static const size_t SHA256_HMAC_DIGEST_SIZE = 32;
+
+ /**
+ * Computes a SHA256 HMAC with secret over input, and writes the digest to output. If truncateTo is
+ * non-zero, the digest will be truncated to the value of truncateTo. Returns true on success. If this
+ * function fails, Aws::Crt::LastError() will contain the error that occurred. Unless you're using
+ * 'truncateTo', output should have a minimum capacity of SHA256_HMAC_DIGEST_SIZE.
+ */
+ bool AWS_CRT_CPP_API ComputeSHA256HMAC(
+ Allocator *allocator,
+ const ByteCursor &secret,
+ const ByteCursor &input,
+ ByteBuf &output,
+ size_t truncateTo = 0) noexcept;
+
+ /**
+ * Computes a SHA256 HMAC using the default allocator with secret over input, and writes the digest to
+ * output. If truncateTo is non-zero, the digest will be truncated to the value of truncateTo. Returns true
+ * on success. If this function fails, Aws::Crt::LastError() will contain the error that occurred. Unless
+ * you're using 'truncateTo', output should have a minimum capacity of SHA256_HMAC_DIGEST_SIZE.
+ */
+ bool AWS_CRT_CPP_API ComputeSHA256HMAC(
+ const ByteCursor &secret,
+ const ByteCursor &input,
+ ByteBuf &output,
+ size_t truncateTo = 0) noexcept;
+ /**
+ * Streaming HMAC object. The typical use case is for computing the HMAC of an object that is too large to
+ * load into memory. You can call Update() multiple times as you load chunks of data into memory. When
+ * you're finished simply call Digest(). After Digest() is called, this object is no longer usable.
+ */
+ class AWS_CRT_CPP_API HMAC final
+ {
+ public:
+ ~HMAC();
+ HMAC(const HMAC &) = delete;
+ HMAC &operator=(const HMAC &) = delete;
+ HMAC(HMAC &&toMove);
+ HMAC &operator=(HMAC &&toMove);
+
+ /**
+ * Returns true if the instance is in a valid state, false otherwise.
+ */
+ inline operator bool() const noexcept { return m_good; }
+
+ /**
+ * Returns the value of the last aws error encountered by operations on this instance.
+ */
+ inline int LastError() const noexcept { return m_lastError; }
+
+ /**
+ * Creates an instance of a Streaming SHA256 HMAC.
+ */
+ static HMAC CreateSHA256HMAC(Allocator *allocator, const ByteCursor &secret) noexcept;
+
+ /**
+ * Creates an instance of a Streaming SHA256 HMAC using the Default Allocator.
+ */
+ static HMAC CreateSHA256HMAC(const ByteCursor &secret) noexcept;
+
+ /**
+ * Updates the running HMAC object with data in toHMAC. Returns true on success. Call
+ * LastError() for the reason this call failed.
+ */
+ bool Update(const ByteCursor &toHMAC) noexcept;
+
+ /**
+ * Finishes the running HMAC operation and writes the digest into output. The available capacity of
+ * output must be large enough for the digest. See: SHA256_DIGEST_SIZE and MD5_DIGEST_SIZE for size
+ * hints. 'truncateTo' is for if you want truncated output (e.g. you only want the first 16 bytes of a
+ * SHA256 digest. Returns true on success. Call LastError() for the reason this call failed.
+ */
+ bool Digest(ByteBuf &output, size_t truncateTo = 0) noexcept;
+
+ private:
+ HMAC(aws_hmac *hmac) noexcept;
+ HMAC() = delete;
+
+ aws_hmac *m_hmac;
+ bool m_good;
+ int m_lastError;
+ };
+
+ /**
+ * BYO_CRYPTO: Base class for custom HMAC implementations.
+ *
+ * If using BYO_CRYPTO, you must define concrete implementations for the required HMAC algorithms
+ * and set their creation callbacks via functions like ApiHandle.SetBYOCryptoNewSHA256HMACCallback().
+ */
+ class AWS_CRT_CPP_API ByoHMAC
+ {
+ public:
+ virtual ~ByoHMAC() = default;
+
+ /** @private
+ * this is called by the framework. If you're trying to create instances of this class manually,
+ * please don't. But if you do. Look at the other factory functions for reference.
+ */
+ aws_hmac *SeatForCInterop(const std::shared_ptr<ByoHMAC> &selfRef);
+
+ protected:
+ ByoHMAC(size_t digestSize, const ByteCursor &secret, Allocator *allocator = ApiAllocator());
+
+ /**
+ * Updates the running HMAC with to_hash.
+ * This can be called multiple times.
+ * Raise an AWS error and return false to indicate failure.
+ */
+ virtual bool UpdateInternal(const ByteCursor &toHash) noexcept = 0;
+
+ /**
+ * Complete the HMAC computation and write the final digest to output.
+ * This cannote be called more than once.
+ * If truncate_to is something other than 0, the output must be truncated to that number of bytes.
+ * Raise an AWS error and return false to indicate failure.
+ */
+ virtual bool DigestInternal(ByteBuf &output, size_t truncateTo = 0) noexcept = 0;
+
+ private:
+ static void s_Destroy(struct aws_hmac *hmac);
+ static int s_Update(struct aws_hmac *hmac, const struct aws_byte_cursor *buf);
+ static int s_Finalize(struct aws_hmac *hmac, struct aws_byte_buf *out);
+
+ static aws_hmac_vtable s_Vtable;
+ aws_hmac m_hmacValue;
+ std::shared_ptr<ByoHMAC> m_selfReference;
+ };
+
+ using CreateHMACCallback =
+ std::function<std::shared_ptr<ByoHMAC>(size_t digestSize, const ByteCursor &secret, Allocator *)>;
+
+ } // namespace Crypto
+ } // namespace Crt
+} // namespace Aws
diff --git a/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/crypto/Hash.h b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/crypto/Hash.h
new file mode 100644
index 0000000000..42b9a3ed34
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/crypto/Hash.h
@@ -0,0 +1,168 @@
+#pragma once
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+#include <aws/crt/Exports.h>
+#include <aws/crt/Types.h>
+
+#include <aws/cal/hash.h>
+
+struct aws_hash;
+namespace Aws
+{
+ namespace Crt
+ {
+ namespace Crypto
+ {
+ static const size_t SHA256_DIGEST_SIZE = 32;
+ static const size_t MD5_DIGEST_SIZE = 16;
+
+ /**
+ * Computes a SHA256 Hash over input, and writes the digest to output. If truncateTo is non-zero, the digest
+ * will be truncated to the value of truncateTo. Returns true on success. If this function fails,
+ * Aws::Crt::LastError() will contain the error that occurred. Unless you're using 'truncateTo', output
+ * should have a minimum capacity of SHA256_DIGEST_SIZE.
+ */
+ bool AWS_CRT_CPP_API ComputeSHA256(
+ Allocator *allocator,
+ const ByteCursor &input,
+ ByteBuf &output,
+ size_t truncateTo = 0) noexcept;
+
+ /**
+ * Computes a SHA256 Hash using the default allocator over input, and writes the digest to output. If
+ * truncateTo is non-zero, the digest will be truncated to the value of truncateTo. Returns true on success.
+ * If this function fails, Aws::Crt::LastError() will contain the error that occurred. Unless you're using
+ * 'truncateTo', output should have a minimum capacity of SHA256_DIGEST_SIZE.
+ */
+ bool AWS_CRT_CPP_API
+ ComputeSHA256(const ByteCursor &input, ByteBuf &output, size_t truncateTo = 0) noexcept;
+
+ /**
+ * Computes a MD5 Hash over input, and writes the digest to output. If truncateTo is non-zero, the digest
+ * will be truncated to the value of truncateTo. Returns true on success. If this function fails,
+ * Aws::Crt::LastError() will contain the error that occurred. Unless you're using 'truncateTo',
+ * output should have a minimum capacity of MD5_DIGEST_SIZE.
+ */
+ bool AWS_CRT_CPP_API ComputeMD5(
+ Allocator *allocator,
+ const ByteCursor &input,
+ ByteBuf &output,
+ size_t truncateTo = 0) noexcept;
+
+ /**
+ * Computes a MD5 Hash using the default allocator over input, and writes the digest to output. If
+ * truncateTo is non-zero, the digest will be truncated to the value of truncateTo. Returns true on success.
+ * If this function fails, Aws::Crt::LastError() will contain the error that occurred. Unless you're using
+ * 'truncateTo', output should have a minimum capacity of MD5_DIGEST_SIZE.
+ */
+ bool AWS_CRT_CPP_API ComputeMD5(const ByteCursor &input, ByteBuf &output, size_t truncateTo = 0) noexcept;
+
+ /**
+ * Streaming Hash object. The typical use case is for computing the hash of an object that is too large to
+ * load into memory. You can call Update() multiple times as you load chunks of data into memory. When
+ * you're finished simply call Digest(). After Digest() is called, this object is no longer usable.
+ */
+ class AWS_CRT_CPP_API Hash final
+ {
+ public:
+ ~Hash();
+ Hash(const Hash &) = delete;
+ Hash &operator=(const Hash &) = delete;
+ Hash(Hash &&toMove);
+ Hash &operator=(Hash &&toMove);
+
+ /**
+ * Returns true if the instance is in a valid state, false otherwise.
+ */
+ inline operator bool() const noexcept { return m_good; }
+
+ /**
+ * Returns the value of the last aws error encountered by operations on this instance.
+ */
+ inline int LastError() const noexcept { return m_lastError; }
+
+ /**
+ * Creates an instance of a Streaming SHA256 Hash.
+ */
+ static Hash CreateSHA256(Allocator *allocator = ApiAllocator()) noexcept;
+
+ /**
+ * Creates an instance of a Streaming MD5 Hash.
+ */
+ static Hash CreateMD5(Allocator *allocator = ApiAllocator()) noexcept;
+
+ /**
+ * Updates the running hash object with data in toHash. Returns true on success. Call
+ * LastError() for the reason this call failed.
+ */
+ bool Update(const ByteCursor &toHash) noexcept;
+
+ /**
+ * Finishes the running hash operation and writes the digest into output. The available capacity of
+ * output must be large enough for the digest. See: SHA256_DIGEST_SIZE and MD5_DIGEST_SIZE for size
+ * hints. 'truncateTo' is for if you want truncated output (e.g. you only want the first 16 bytes of a
+ * SHA256 digest. Returns true on success. Call LastError() for the reason this call failed.
+ */
+ bool Digest(ByteBuf &output, size_t truncateTo = 0) noexcept;
+
+ private:
+ Hash(aws_hash *hash) noexcept;
+ Hash() = delete;
+
+ aws_hash *m_hash;
+ bool m_good;
+ int m_lastError;
+ };
+
+ /**
+ * BYO_CRYPTO: Base class for custom hash implementations.
+ *
+ * If using BYO_CRYPTO, you must define concrete implementations for the required hash algorithms
+ * and set their creation callbacks via functions like ApiHandle.SetBYOCryptoNewMD5Callback().
+ */
+ class AWS_CRT_CPP_API ByoHash
+ {
+ public:
+ virtual ~ByoHash();
+
+ /** @private
+ * this is called by the framework. If you're trying to create instances of this class manually,
+ * please don't. But if you do. Look at the other factory functions for reference.
+ */
+ aws_hash *SeatForCInterop(const std::shared_ptr<ByoHash> &selfRef);
+
+ protected:
+ ByoHash(size_t digestSize, Allocator *allocator = ApiAllocator());
+
+ /**
+ * Update the running hash with to_hash.
+ * This can be called multiple times.
+ * Raise an AWS error and return false to indicate failure.
+ */
+ virtual bool UpdateInternal(const ByteCursor &toHash) noexcept = 0;
+
+ /**
+ * Complete the hash computation and write the final digest to output.
+ * This cannote be called more than once.
+ * If truncate_to is something other than 0, the output must be truncated to that number of bytes.
+ * Raise an AWS error and return false to indicate failure.
+ */
+ virtual bool DigestInternal(ByteBuf &output, size_t truncateTo = 0) noexcept = 0;
+
+ private:
+ static void s_Destroy(struct aws_hash *hash);
+ static int s_Update(struct aws_hash *hash, const struct aws_byte_cursor *buf);
+ static int s_Finalize(struct aws_hash *hash, struct aws_byte_buf *out);
+
+ static aws_hash_vtable s_Vtable;
+ aws_hash m_hashValue;
+ std::shared_ptr<ByoHash> m_selfReference;
+ };
+
+ using CreateHashCallback = std::function<std::shared_ptr<ByoHash>(size_t digestSize, Allocator *)>;
+
+ } // namespace Crypto
+ } // namespace Crt
+} // namespace Aws
diff --git a/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/endpoints/RuleEngine.h b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/endpoints/RuleEngine.h
new file mode 100644
index 0000000000..84baff71d9
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/endpoints/RuleEngine.h
@@ -0,0 +1,155 @@
+#pragma once
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+
+#include <aws/crt/Types.h>
+
+struct aws_endpoints_rule_engine;
+struct aws_endpoints_request_context;
+struct aws_endpoints_resolved_endpoint;
+
+namespace Aws
+{
+ namespace Crt
+ {
+ namespace Endpoints
+ {
+ /*
+ * Add parameter to the context.
+ * Only string and boolean values are supported.
+ * Adding parameter several times with the same name will overwrite
+ * previous values.
+ */
+ class AWS_CRT_CPP_API RequestContext final
+ {
+ public:
+ RequestContext(Allocator *allocator = ApiAllocator()) noexcept;
+ ~RequestContext();
+
+ /* TODO: move/copy semantics */
+ RequestContext(const RequestContext &) = delete;
+ RequestContext &operator=(const RequestContext &) = delete;
+ RequestContext(RequestContext &&) = delete;
+ RequestContext &operator=(RequestContext &&) = delete;
+
+ /**
+ * @return true if the instance is in a valid state, false otherwise.
+ */
+ operator bool() const noexcept { return m_requestContext != nullptr; }
+
+ /*
+ * Add string parameter.
+ * True if added successfully and false if failed.
+ * Aws::Crt::LastError() can be used to retrieve failure error code.
+ */
+ bool AddString(const ByteCursor &name, const ByteCursor &value);
+
+ /*
+ * Add boolean parameter.
+ * True if added successfully and false if failed.
+ * Aws::Crt::LastError() can be used to retrieve failure error code.
+ */
+ bool AddBoolean(const ByteCursor &name, bool value);
+
+ /// @private
+ aws_endpoints_request_context *GetNativeHandle() const noexcept { return m_requestContext; }
+
+ private:
+ Allocator *m_allocator;
+ aws_endpoints_request_context *m_requestContext;
+ };
+
+ /*
+ * Outcome of Endpoint Resolution.
+ * Outcome can be either endpoint (IsEndpoint) or error (IsError).
+ * Endpoint outcome means that engine was able to resolve context to
+ * an endpoint and outcome can have the following fields defined:
+ * - Url (required) - resolved url
+ * - Headers (optional) - additional headers to be included with request
+ * - Properties (optional) - custom list of properties associated
+ * with request (json blob to be interpreted by the caller.)
+ *
+ * Error outcome means that context could not be resolved to an endpoint.
+ * Outcome will have following fields:
+ * - Error (required) - error message providing more info on why
+ * endpoint could not be resolved.
+ */
+ class AWS_CRT_CPP_API ResolutionOutcome final
+ {
+ public:
+ ~ResolutionOutcome();
+
+ /* TODO: move/copy semantics */
+ ResolutionOutcome(const ResolutionOutcome &) = delete;
+ ResolutionOutcome &operator=(const ResolutionOutcome &) = delete;
+ ResolutionOutcome(ResolutionOutcome &&toMove) noexcept;
+ ResolutionOutcome &operator=(ResolutionOutcome &&);
+
+ bool IsEndpoint() const noexcept;
+ bool IsError() const noexcept;
+
+ /*
+ * Endpoint properties.
+ * Note: following fields are none if outcome is error.
+ * Headers and Properties are optional and could also be None.
+ */
+ Optional<StringView> GetUrl() const;
+ Optional<StringView> GetProperties() const;
+ Optional<UnorderedMap<StringView, Vector<StringView>>> GetHeaders() const;
+
+ /*
+ * Error properties.
+ * Note: following fields are none if outcome is error.
+ */
+ Optional<StringView> GetError() const;
+
+ /**
+ * @return true if the instance is in a valid state, false otherwise.
+ */
+ operator bool() const noexcept { return m_resolvedEndpoint != nullptr; }
+
+ /// @private For use by rule engine.
+ ResolutionOutcome(aws_endpoints_resolved_endpoint *impl);
+
+ private:
+ aws_endpoints_resolved_endpoint *m_resolvedEndpoint;
+ };
+
+ /**
+ * Endpoints Rule Engine.
+ */
+ class AWS_CRT_CPP_API RuleEngine final
+ {
+ public:
+ RuleEngine(
+ const ByteCursor &rulesetCursor,
+ const ByteCursor &partitionsCursor,
+ Allocator *allocator = ApiAllocator()) noexcept;
+ ~RuleEngine();
+
+ RuleEngine(const RuleEngine &) = delete;
+ RuleEngine &operator=(const RuleEngine &) = delete;
+ RuleEngine(RuleEngine &&) = delete;
+ RuleEngine &operator=(RuleEngine &&) = delete;
+
+ /**
+ * @return true if the instance is in a valid state, false otherwise.
+ */
+ operator bool() const noexcept { return m_ruleEngine != nullptr; }
+
+ /*
+ * Resolves rules against the provided context.
+ * If successful return will have resolution outcome.
+ * If not, return will be none and Aws::Crt::LastError() can be
+ * used to retrieve CRT error code.
+ */
+ Optional<ResolutionOutcome> Resolve(const RequestContext &context) const;
+
+ private:
+ aws_endpoints_rule_engine *m_ruleEngine;
+ };
+ } // namespace Endpoints
+ } // namespace Crt
+} // namespace Aws
diff --git a/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/external/cJSON.h b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/external/cJSON.h
new file mode 100644
index 0000000000..ee10f0225d
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/external/cJSON.h
@@ -0,0 +1,309 @@
+/*
+ Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+/** MODIFICATIONS:
+ * valueInt was moved up to improve alignment.
+ * Wrap all symbols in the Aws namespace as a short-term collision resolution
+ * Replace strcpy() with strncpy()
+ *
+ * Modifications licensed under:
+ *
+ * Copyright 2010-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file is distributed
+ * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+#ifndef cJSON__h
+#define cJSON__h
+
+namespace Aws {
+
+#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32))
+#define __WINDOWS__
+#endif
+
+#ifdef __WINDOWS__
+
+/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 3 define options:
+
+CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols
+CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default)
+CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol
+
+For *nix builds that support visibility attribute, you can define similar behavior by
+
+setting default visibility to hidden by adding
+-fvisibility=hidden (for gcc)
+or
+-xldscope=hidden (for sun cc)
+to CFLAGS
+
+then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does
+
+*/
+
+#define CJSON_CDECL __cdecl
+#define CJSON_STDCALL __stdcall
+
+/* export symbols by default, this is necessary for copy pasting the C and header file */
+#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS)
+#define CJSON_EXPORT_SYMBOLS
+#endif
+
+#if defined(CJSON_HIDE_SYMBOLS)
+#define CJSON_PUBLIC(type) type CJSON_STDCALL
+#elif defined(CJSON_EXPORT_SYMBOLS)
+#define CJSON_PUBLIC(type) __declspec(dllexport) type CJSON_STDCALL
+#elif defined(CJSON_IMPORT_SYMBOLS)
+#define CJSON_PUBLIC(type) __declspec(dllimport) type CJSON_STDCALL
+#endif
+#else /* !__WINDOWS__ */
+#define CJSON_CDECL
+#define CJSON_STDCALL
+
+#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY)
+#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type
+#else
+#define CJSON_PUBLIC(type) type
+#endif
+#endif
+
+/* project version */
+#define CJSON_VERSION_MAJOR 1
+#define CJSON_VERSION_MINOR 7
+#define CJSON_VERSION_PATCH 14
+
+#include <stddef.h>
+
+/* cJSON Types: */
+#define cJSON_Invalid (0)
+#define cJSON_False (1 << 0)
+#define cJSON_True (1 << 1)
+#define cJSON_NULL (1 << 2)
+#define cJSON_Number (1 << 3)
+#define cJSON_String (1 << 4)
+#define cJSON_Array (1 << 5)
+#define cJSON_Object (1 << 6)
+#define cJSON_Raw (1 << 7) /* raw json */
+
+#define cJSON_IsReference 256
+#define cJSON_StringIsConst 512
+
+/* The cJSON structure: */
+typedef struct cJSON
+{
+ /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
+ struct cJSON *next;
+ struct cJSON *prev;
+ /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
+ struct cJSON *child;
+
+ /* The type of the item, as above. */
+ int type;
+
+ /* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */
+ int valueint;
+ /* The item's string, if type==cJSON_String and type == cJSON_Raw */
+ char *valuestring;
+ /* The item's number, if type==cJSON_Number */
+ double valuedouble;
+
+ /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
+ char *string;
+} cJSON;
+
+typedef struct cJSON_Hooks
+{
+ /* malloc/free are CDECL on Windows regardless of the default calling convention of the compiler, so ensure the hooks allow passing those functions directly. */
+ void *(CJSON_CDECL *malloc_fn)(size_t sz);
+ void (CJSON_CDECL *free_fn)(void *ptr);
+} cJSON_Hooks;
+
+typedef int cJSON_bool;
+
+/* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them.
+ * This is to prevent stack overflows. */
+#ifndef CJSON_NESTING_LIMIT
+#define CJSON_NESTING_LIMIT 1000
+#endif
+
+/* returns the version of cJSON as a string */
+CJSON_PUBLIC(const char*) cJSON_Version(void);
+
+/* Supply malloc, realloc and free functions to cJSON */
+CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks);
+
+/* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */
+/* Supply a block of JSON, and this returns a cJSON object you can interrogate. */
+CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value);
+CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length);
+/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */
+/* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */
+CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated);
+CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated);
+
+/* Render a cJSON entity to text for transfer/storage. */
+CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item);
+/* Render a cJSON entity to text for transfer/storage without any formatting. */
+CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item);
+/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */
+CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt);
+/* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */
+/* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */
+CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format);
+/* Delete a cJSON entity and all subentities. */
+CJSON_PUBLIC(void) cJSON_Delete(cJSON *item);
+
+/* Returns the number of items in an array (or object). */
+CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array);
+/* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */
+CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index);
+/* Get item "string" from object. Case insensitive. */
+CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string);
+CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string);
+CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string);
+/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
+CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void);
+
+/* Check item type and return its value */
+CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item);
+CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item);
+
+/* These functions check the type of an item */
+CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item);
+CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item);
+CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item);
+CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item);
+CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item);
+CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item);
+CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item);
+CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item);
+CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item);
+CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item);
+
+/* These calls create a cJSON item of the appropriate type. */
+CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void);
+CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void);
+CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void);
+CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean);
+CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num);
+CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string);
+/* raw json */
+CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw);
+CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void);
+CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void);
+
+/* Create a string where valuestring references a string so
+ * it will not be freed by cJSON_Delete */
+CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string);
+/* Create an object/array that only references it's elements so
+ * they will not be freed by cJSON_Delete */
+CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child);
+CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child);
+
+/* These utilities create an Array of count items.
+ * The parameter count cannot be greater than the number of elements in the number array, otherwise array access will be out of bounds.*/
+CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count);
+CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count);
+CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count);
+CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count);
+
+/* Append item to the specified array/object. */
+CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item);
+CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);
+/* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object.
+ * WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before
+ * writing to `item->string` */
+CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item);
+/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */
+CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
+CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item);
+
+/* Remove/Detach items from Arrays/Objects. */
+CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item);
+CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which);
+CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which);
+CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string);
+CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string);
+CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string);
+CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string);
+
+/* Update array items. */
+CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */
+CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement);
+CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem);
+CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
+CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem);
+
+/* Duplicate a cJSON item */
+CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse);
+/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
+ * need to be released. With recurse!=0, it will duplicate any children connected to the item.
+ * The item->next and ->prev pointers are always zero on return from Duplicate. */
+/* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal.
+ * case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */
+CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive);
+
+/* Minify a strings, remove blank characters(such as ' ', '\t', '\r', '\n') from strings.
+ * The input pointer json cannot point to a read-only address area, such as a string constant,
+ * but should point to a readable and writable adress area. */
+CJSON_PUBLIC(void) cJSON_Minify(char *json);
+
+/* Helper functions for creating and adding items to an object at the same time.
+ * They return the added item or NULL on failure. */
+CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name);
+CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name);
+CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name);
+CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean);
+CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number);
+CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string);
+CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw);
+CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name);
+CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name);
+
+/* When assigning an integer value, it needs to be propagated to valuedouble too. */
+#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number))
+/* helper for the cJSON_SetNumberValue macro */
+CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number);
+#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number))
+/* Change the valuestring of a cJSON_String object, only takes effect when type of object is cJSON_String */
+CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring);
+
+/* Macro for iterating over an array or object */
+#define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next)
+
+/* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */
+CJSON_PUBLIC(void *) cJSON_malloc(size_t size);
+CJSON_PUBLIC(void) cJSON_free(void *object);
+
+}
+
+#endif
diff --git a/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/http/HttpConnection.h b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/http/HttpConnection.h
new file mode 100644
index 0000000000..1ae79cefd8
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/http/HttpConnection.h
@@ -0,0 +1,514 @@
+#pragma once
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+#include <aws/http/connection.h>
+#include <aws/http/proxy.h>
+#include <aws/http/request_response.h>
+
+#include <aws/crt/Types.h>
+#include <aws/crt/io/Bootstrap.h>
+#include <aws/crt/io/SocketOptions.h>
+#include <aws/crt/io/TlsOptions.h>
+
+#include <functional>
+#include <memory>
+
+namespace Aws
+{
+ namespace Crt
+ {
+ namespace Io
+ {
+ class ClientBootstrap;
+ }
+
+ namespace Http
+ {
+ class HttpClientConnection;
+ class HttpStream;
+ class HttpClientStream;
+ class HttpRequest;
+ class HttpProxyStrategy;
+ using HttpHeader = aws_http_header;
+
+ /**
+ * Invoked upon connection setup, whether it was successful or not. If the connection was
+ * successfully established, `connection` will be valid and errorCode will be AWS_ERROR_SUCCESS.
+ * Upon an error, `connection` will not be valid, and errorCode will contain the cause of the connection
+ * failure.
+ */
+ using OnConnectionSetup =
+ std::function<void(const std::shared_ptr<HttpClientConnection> &connection, int errorCode)>;
+
+ /**
+ * Invoked upon connection shutdown. `connection` will always be a valid pointer. `errorCode` will specify
+ * shutdown reason. A graceful connection close will set `errorCode` to AWS_ERROR_SUCCESS.
+ * Internally, the connection pointer will be unreferenced immediately after this call; if you took a
+ * reference to it in OnConnectionSetup(), you'll need to release your reference before the underlying
+ * memory is released. If you never took a reference to it, the resources for the connection will be
+ * immediately released after completion of this callback.
+ */
+ using OnConnectionShutdown = std::function<void(HttpClientConnection &connection, int errorCode)>;
+
+ /**
+ * Called as headers are received from the peer. `headersArray` will contain the header value
+ * read from the wire. The number of entries in `headersArray` are specified in `headersCount`.
+ *
+ * Keep in mind that this function will likely be called multiple times until all headers are received.
+ *
+ * On HttpStream, this function must be set.
+ */
+ using OnIncomingHeaders = std::function<void(
+ HttpStream &stream,
+ enum aws_http_header_block headerBlock,
+ const HttpHeader *headersArray,
+ std::size_t headersCount)>;
+
+ /**
+ * Invoked when the headers portion of the message has been completely received. `hasBody` will indicate
+ * if there is an incoming body.
+ *
+ * On HttpStream, this function can be empty.
+ */
+ using OnIncomingHeadersBlockDone =
+ std::function<void(HttpStream &stream, enum aws_http_header_block block)>;
+
+ /**
+ * Invoked as chunks of the body are read. `data` contains the data read from the wire. If chunked encoding
+ * was used, it will already be decoded (TBD).
+ *
+ * On HttpStream, this function can be empty if you are not expecting a body (e.g. a HEAD request).
+ */
+ using OnIncomingBody = std::function<void(HttpStream &stream, const ByteCursor &data)>;
+
+ /**
+ * Invoked upon completion of the stream. This means the request has been sent and a completed response
+ * has been received (in client mode), or the request has been received and the response has been completed.
+ *
+ * In H2, this will mean RST_STREAM state has been reached for the stream.
+ *
+ * On HttpStream, this function must be set.
+ */
+ using OnStreamComplete = std::function<void(HttpStream &stream, int errorCode)>;
+
+ /**
+ * POD structure used for setting up an Http Request
+ */
+ struct AWS_CRT_CPP_API HttpRequestOptions
+ {
+ /**
+ * The actual http request
+ */
+ HttpRequest *request;
+
+ /**
+ * See `OnIncomingHeaders` for more info. This value must be set.
+ */
+ OnIncomingHeaders onIncomingHeaders;
+ OnIncomingHeadersBlockDone onIncomingHeadersBlockDone;
+
+ /**
+ * See `OnIncomingBody` for more info. This value can be empty if you will not be receiving a body.
+ */
+ OnIncomingBody onIncomingBody;
+
+ /**
+ * See `OnStreamComplete` for more info. This value can be empty.
+ */
+ OnStreamComplete onStreamComplete;
+ };
+
+ /**
+ * Represents a single http message exchange (request/response) or in H2, it can also represent
+ * a PUSH_PROMISE followed by the accompanying Response.
+ */
+ class AWS_CRT_CPP_API HttpStream : public std::enable_shared_from_this<HttpStream>
+ {
+ public:
+ virtual ~HttpStream();
+ HttpStream(const HttpStream &) = delete;
+ HttpStream(HttpStream &&) = delete;
+ HttpStream &operator=(const HttpStream &) = delete;
+ HttpStream &operator=(HttpStream &&) = delete;
+
+ /**
+ * Get the underlying connection for the stream.
+ */
+ HttpClientConnection &GetConnection() const noexcept;
+
+ /**
+ * @return request's Http Response Code. Requires response headers to have been processed first. *
+ */
+ virtual int GetResponseStatusCode() const noexcept = 0;
+
+ /**
+ * Updates the read window on the connection. In Http 1.1 this relieves TCP back pressure, in H2
+ * this will trigger two WINDOW_UPDATE frames, one for the connection and one for the stream.
+ *
+ * You do not need to call this unless you utilized the `outWindowUpdateSize` in `OnIncomingBody`.
+ * See `OnIncomingBody` for more information.
+ *
+ * `incrementSize` is the amount to update the read window by.
+ */
+ void UpdateWindow(std::size_t incrementSize) noexcept;
+
+ protected:
+ aws_http_stream *m_stream;
+ std::shared_ptr<HttpClientConnection> m_connection;
+ HttpStream(const std::shared_ptr<HttpClientConnection> &connection) noexcept;
+
+ private:
+ OnIncomingHeaders m_onIncomingHeaders;
+ OnIncomingHeadersBlockDone m_onIncomingHeadersBlockDone;
+ OnIncomingBody m_onIncomingBody;
+ OnStreamComplete m_onStreamComplete;
+
+ static int s_onIncomingHeaders(
+ struct aws_http_stream *stream,
+ enum aws_http_header_block headerBlock,
+ const struct aws_http_header *headerArray,
+ size_t numHeaders,
+ void *userData) noexcept;
+ static int s_onIncomingHeaderBlockDone(
+ struct aws_http_stream *stream,
+ enum aws_http_header_block headerBlock,
+ void *userData) noexcept;
+ static int s_onIncomingBody(
+ struct aws_http_stream *stream,
+ const struct aws_byte_cursor *data,
+ void *userData) noexcept;
+ static void s_onStreamComplete(struct aws_http_stream *stream, int errorCode, void *userData) noexcept;
+
+ friend class HttpClientConnection;
+ };
+
+ struct ClientStreamCallbackData
+ {
+ ClientStreamCallbackData() : allocator(nullptr), stream(nullptr) {}
+ Allocator *allocator;
+ std::shared_ptr<HttpStream> stream;
+ };
+
+ /**
+ * Subclass that represents an http client's view of an HttpStream.
+ */
+ class AWS_CRT_CPP_API HttpClientStream final : public HttpStream
+ {
+ public:
+ ~HttpClientStream();
+ HttpClientStream(const HttpClientStream &) = delete;
+ HttpClientStream(HttpClientStream &&) = delete;
+ HttpClientStream &operator=(const HttpClientStream &) = delete;
+ HttpClientStream &operator=(HttpClientStream &&) = delete;
+
+ /**
+ * If this stream was initiated as a request, assuming the headers of the response has been
+ * received, this value contains the Http Response Code. *
+ */
+ virtual int GetResponseStatusCode() const noexcept override;
+
+ /**
+ * Activates the request's outgoing stream processing.
+ *
+ * Returns true on success, false otherwise.
+ */
+ bool Activate() noexcept;
+
+ private:
+ HttpClientStream(const std::shared_ptr<HttpClientConnection> &connection) noexcept;
+
+ ClientStreamCallbackData m_callbackData;
+ friend class HttpClientConnection;
+ };
+
+ /**
+ * @deprecated enum that designates what kind of authentication, if any, to use when connecting to a
+ * proxy server.
+ *
+ * Here for backwards compatibility. Has been superceded by proxy strategies.
+ */
+ enum class AwsHttpProxyAuthenticationType
+ {
+ None,
+ Basic,
+ };
+
+ /**
+ * Mirror of aws_http_proxy_connection_type enum. Indicates the basic http proxy behavior of the
+ * proxy we're connecting to.
+ */
+ enum class AwsHttpProxyConnectionType
+ {
+ /**
+ * Deprecated, but 0-valued for backwards compatibility
+ *
+ * If tls options are provided (for the main connection) then treat the proxy as a tunneling proxy
+ * If tls options are not provided (for the main connection), then treat the proxy as a forwarding
+ * proxy
+ */
+ Legacy = AWS_HPCT_HTTP_LEGACY,
+
+ /**
+ * Use the proxy to forward http requests. Attempting to use both this mode and TLS to the destination
+ * is a configuration error.
+ */
+ Forwarding = AWS_HPCT_HTTP_FORWARD,
+
+ /**
+ * Use the proxy to establish an http connection via a CONNECT request to the proxy. Works for both
+ * plaintext and tls connections.
+ */
+ Tunneling = AWS_HPCT_HTTP_TUNNEL,
+ };
+
+ /**
+ * Configuration structure that holds all proxy-related http connection options
+ */
+ class AWS_CRT_CPP_API HttpClientConnectionProxyOptions
+ {
+ public:
+ HttpClientConnectionProxyOptions();
+ HttpClientConnectionProxyOptions(const HttpClientConnectionProxyOptions &rhs) = default;
+ HttpClientConnectionProxyOptions(HttpClientConnectionProxyOptions &&rhs) = default;
+
+ HttpClientConnectionProxyOptions &operator=(const HttpClientConnectionProxyOptions &rhs) = default;
+ HttpClientConnectionProxyOptions &operator=(HttpClientConnectionProxyOptions &&rhs) = default;
+
+ ~HttpClientConnectionProxyOptions() = default;
+
+ /**
+ * Intended for internal use only. Initializes the C proxy configuration structure,
+ * aws_http_proxy_options, from an HttpClientConnectionProxyOptions instance.
+ *
+ * @param raw_options - output parameter containing low level proxy options to be passed to the C
+ * interface
+ *
+ */
+ void InitializeRawProxyOptions(struct aws_http_proxy_options &raw_options) const;
+
+ /**
+ * The name of the proxy server to connect through.
+ * Required.
+ */
+ String HostName;
+
+ /**
+ * The port of the proxy server to connect to.
+ * Required.
+ */
+ uint16_t Port;
+
+ /**
+ * Sets the TLS options for the connection to the proxy.
+ * Optional.
+ */
+ Optional<Io::TlsConnectionOptions> TlsOptions;
+
+ /**
+ * What kind of proxy connection to make
+ */
+ AwsHttpProxyConnectionType ProxyConnectionType;
+
+ /**
+ * Proxy strategy to use while negotiating the connection. Use null for no additional
+ * steps.
+ */
+ std::shared_ptr<HttpProxyStrategy> ProxyStrategy;
+
+ /**
+ * @deprecated What kind of authentication approach to use when connecting to the proxy
+ * Replaced by proxy strategy
+ *
+ * Backwards compatibility achieved by invoking CreateBasicHttpProxyStrategy if
+ * (1) ProxyStrategy is null
+ * (2) AuthType is AwsHttpProxyAuthenticationType::Basic
+ */
+ AwsHttpProxyAuthenticationType AuthType;
+
+ /**
+ * @deprecated The username to use if connecting to the proxy via basic authentication
+ * Replaced by using the result of CreateBasicHttpProxyStrategy()
+ */
+ String BasicAuthUsername;
+
+ /**
+ * @deprecated The password to use if connecting to the proxy via basic authentication
+ * Replaced by using the result of CreateBasicHttpProxyStrategy()
+ */
+ String BasicAuthPassword;
+ };
+
+ /**
+ * Configuration structure holding all options relating to http connection establishment
+ */
+ class AWS_CRT_CPP_API HttpClientConnectionOptions
+ {
+ public:
+ HttpClientConnectionOptions();
+ HttpClientConnectionOptions(const HttpClientConnectionOptions &rhs) = default;
+ HttpClientConnectionOptions(HttpClientConnectionOptions &&rhs) = default;
+
+ ~HttpClientConnectionOptions() = default;
+
+ HttpClientConnectionOptions &operator=(const HttpClientConnectionOptions &rhs) = default;
+ HttpClientConnectionOptions &operator=(HttpClientConnectionOptions &&rhs) = default;
+
+ /**
+ * The client bootstrap to use for setting up and tearing down connections.
+ * Note: If null, then the default ClientBootstrap is used
+ * (see Aws::Crt::ApiHandle::GetOrCreateStaticDefaultClientBootstrap)
+ */
+ Io::ClientBootstrap *Bootstrap;
+
+ /**
+ * The TCP read window allowed for Http 1.1 connections and Initial Windows for H2 connections.
+ */
+ size_t InitialWindowSize;
+
+ /**
+ * The callback invoked on connection establishment, whether success or failure.
+ * See `OnConnectionSetup` for more info.
+ * Required.
+ */
+ OnConnectionSetup OnConnectionSetupCallback;
+
+ /**
+ * The callback invoked on connection shutdown.
+ * See `OnConnectionShutdown` for more info.
+ * Required.
+ */
+ OnConnectionShutdown OnConnectionShutdownCallback;
+
+ /**
+ * The name of the http server to connect to.
+ * Required.
+ */
+ String HostName;
+
+ /**
+ * The port of the http server to connect to.
+ * Required.
+ */
+ uint16_t Port;
+
+ /**
+ * The socket options of the connection.
+ * Required.
+ */
+ Io::SocketOptions SocketOptions;
+
+ /**
+ * The TLS options for the http connection.
+ * Optional.
+ */
+ Optional<Io::TlsConnectionOptions> TlsOptions;
+
+ /**
+ * The proxy options for the http connection.
+ * Optional.
+ */
+ Optional<HttpClientConnectionProxyOptions> ProxyOptions;
+
+ /**
+ * If set to true, then the TCP read back pressure mechanism will be enabled. You should
+ * only use this if you're allowing http response body data to escape the callbacks. E.g. you're
+ * putting the data into a queue for another thread to process and need to make sure the memory
+ * usage is bounded. If this is enabled, you must call HttpStream::UpdateWindow() for every
+ * byte read from the OnIncomingBody callback.
+ */
+ bool ManualWindowManagement;
+ };
+
+ enum class HttpVersion
+ {
+ Unknown = AWS_HTTP_VERSION_UNKNOWN,
+ Http1_0 = AWS_HTTP_VERSION_1_0,
+ Http1_1 = AWS_HTTP_VERSION_1_1,
+ Http2 = AWS_HTTP_VERSION_2,
+ };
+
+ /**
+ * Represents a connection from a Http Client to a Server.
+ */
+ class AWS_CRT_CPP_API HttpClientConnection : public std::enable_shared_from_this<HttpClientConnection>
+ {
+ public:
+ virtual ~HttpClientConnection() = default;
+ HttpClientConnection(const HttpClientConnection &) = delete;
+ HttpClientConnection(HttpClientConnection &&) = delete;
+ HttpClientConnection &operator=(const HttpClientConnection &) = delete;
+ HttpClientConnection &operator=(HttpClientConnection &&) = delete;
+
+ /**
+ * Make a new client initiated request on this connection.
+ *
+ * If you take a reference to the return value, the memory and resources for the connection
+ * and stream will not be cleaned up until you release it. You can however, release the reference
+ * as soon as you don't need it anymore. The internal reference count ensures the resources will
+ * not be freed until the stream is completed.
+ *
+ * Returns an instance of HttpStream upon success and nullptr on failure.
+ *
+ * You must call HttpClientStream::Activate() to begin outgoing processing of the stream.
+ */
+ std::shared_ptr<HttpClientStream> NewClientStream(const HttpRequestOptions &requestOptions) noexcept;
+
+ /**
+ * @return true unless the connection is closed or closing.
+ */
+ bool IsOpen() const noexcept;
+
+ /**
+ * Initiate a shutdown of the connection. Sometimes, connections are persistent and you want
+ * to close them before shutting down your application or whatever is consuming this interface.
+ *
+ * Assuming `OnConnectionShutdown` has not already been invoked, it will be invoked as a result of this
+ * call.
+ */
+ void Close() noexcept;
+
+ /**
+ * @return protocol version the connection used
+ */
+ HttpVersion GetVersion() noexcept;
+
+ /**
+ * @return the value of the last aws error encountered by operations on this instance.
+ */
+ int LastError() const noexcept { return m_lastError; }
+
+ /**
+ * Create a new Https Connection to hostName:port, using `socketOptions` for tcp options and
+ * `tlsConnOptions` for TLS/SSL options. If `tlsConnOptions` is null http (plain-text) will be used.
+ *
+ * returns true on success, and false on failure. If false is returned, `onConnectionSetup` will not
+ * be invoked. On success, `onConnectionSetup` will be called, either with a connection, or an
+ * errorCode.
+ */
+ static bool CreateConnection(
+ const HttpClientConnectionOptions &connectionOptions,
+ Allocator *allocator) noexcept;
+
+ protected:
+ HttpClientConnection(aws_http_connection *m_connection, Allocator *allocator) noexcept;
+ aws_http_connection *m_connection;
+
+ private:
+ Allocator *m_allocator;
+ int m_lastError;
+
+ static void s_onClientConnectionSetup(
+ struct aws_http_connection *connection,
+ int error_code,
+ void *user_data) noexcept;
+ static void s_onClientConnectionShutdown(
+ struct aws_http_connection *connection,
+ int error_code,
+ void *user_data) noexcept;
+ };
+
+ } // namespace Http
+ } // namespace Crt
+} // namespace Aws
diff --git a/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/http/HttpConnectionManager.h b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/http/HttpConnectionManager.h
new file mode 100644
index 0000000000..0ecd9b48d7
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/http/HttpConnectionManager.h
@@ -0,0 +1,127 @@
+#pragma once
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+#include <aws/crt/http/HttpConnection.h>
+
+#include <atomic>
+#include <condition_variable>
+#include <future>
+#include <mutex>
+
+struct aws_http_connection_manager;
+
+namespace Aws
+{
+ namespace Crt
+ {
+ namespace Http
+ {
+ /**
+ * Invoked when a connection from the pool is available. If a connection was successfully obtained
+ * the connection shared_ptr can be seated into your own copy of connection. If it failed, errorCode
+ * will be non-zero.
+ */
+ using OnClientConnectionAvailable =
+ std::function<void(std::shared_ptr<HttpClientConnection>, int errorCode)>;
+
+ /**
+ * Configuration struct containing all options related to connection manager behavior
+ */
+ class AWS_CRT_CPP_API HttpClientConnectionManagerOptions
+ {
+ public:
+ HttpClientConnectionManagerOptions() noexcept;
+ HttpClientConnectionManagerOptions(const HttpClientConnectionManagerOptions &rhs) = default;
+ HttpClientConnectionManagerOptions(HttpClientConnectionManagerOptions &&rhs) = default;
+
+ HttpClientConnectionManagerOptions &operator=(const HttpClientConnectionManagerOptions &rhs) = default;
+ HttpClientConnectionManagerOptions &operator=(HttpClientConnectionManagerOptions &&rhs) = default;
+
+ /**
+ * The http connection options to use for each connection created by the manager
+ */
+ HttpClientConnectionOptions ConnectionOptions;
+
+ /**
+ * The maximum number of connections the manager is allowed to create/manage
+ */
+ size_t MaxConnections;
+
+ /** If set, initiate shutdown will return a future that will allow a user to block until the
+ * connection manager has completely released all resources. This isn't necessary during the normal
+ * flow of an application, but it is useful for scenarios, such as tests, that need deterministic
+ * shutdown ordering. Be aware, if you use this anywhere other than the main thread, you will most
+ * likely cause a deadlock. If this is set, you MUST call InitiateShutdown() before releasing your last
+ * reference to the connection manager.
+ */
+ bool EnableBlockingShutdown;
+ };
+
+ /**
+ * Manages a pool of connections to a specific endpoint using the same socket and tls options.
+ */
+ class AWS_CRT_CPP_API HttpClientConnectionManager final
+ : public std::enable_shared_from_this<HttpClientConnectionManager>
+ {
+ public:
+ ~HttpClientConnectionManager();
+
+ /**
+ * Acquires a connection from the pool. onClientConnectionAvailable will be invoked upon an available
+ * connection. Returns true if the connection request was successfully queued, returns false if it
+ * failed. On failure, onClientConnectionAvailable will not be invoked. After receiving a connection, it
+ * will automatically be cleaned up when your last reference to the shared_ptr is released.
+ *
+ * @param onClientConnectionAvailable callback to invoke when a connection becomes available or the
+ * acquisition attempt terminates
+ * @return true if the acquisition was successfully kicked off, false otherwise (no callback)
+ */
+ bool AcquireConnection(const OnClientConnectionAvailable &onClientConnectionAvailable) noexcept;
+
+ /**
+ * Starts shutdown of the connection manager. Returns a future to the connection manager's shutdown
+ * process. If EnableBlockingDestruct was enabled on the connection manager options, calling get() on
+ * the returned future will block until the last connection is released. If the option is not set, get()
+ * will immediately return.
+ * @return future which will complete when shutdown has completed
+ */
+ std::future<void> InitiateShutdown() noexcept;
+
+ /**
+ * Factory function for connection managers
+ *
+ * @param connectionManagerOptions connection manager configuration data
+ * @param allocator allocator to use
+ * @return a new connection manager instance
+ */
+ static std::shared_ptr<HttpClientConnectionManager> NewClientConnectionManager(
+ const HttpClientConnectionManagerOptions &connectionManagerOptions,
+ Allocator *allocator = ApiAllocator()) noexcept;
+
+ private:
+ HttpClientConnectionManager(
+ const HttpClientConnectionManagerOptions &options,
+ Allocator *allocator = ApiAllocator()) noexcept;
+
+ Allocator *m_allocator;
+
+ aws_http_connection_manager *m_connectionManager;
+
+ HttpClientConnectionManagerOptions m_options;
+ std::promise<void> m_shutdownPromise;
+ std::atomic<bool> m_releaseInvoked;
+
+ static void s_onConnectionSetup(
+ aws_http_connection *connection,
+ int errorCode,
+ void *userData) noexcept;
+
+ static void s_shutdownCompleted(void *userData) noexcept;
+
+ friend class ManagedConnection;
+ };
+ } // namespace Http
+ } // namespace Crt
+} // namespace Aws
diff --git a/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/http/HttpProxyStrategy.h b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/http/HttpProxyStrategy.h
new file mode 100644
index 0000000000..bf72490693
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/http/HttpProxyStrategy.h
@@ -0,0 +1,116 @@
+#pragma once
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+
+#include <aws/crt/Types.h>
+
+#include <memory>
+
+struct aws_http_proxy_strategy;
+
+namespace Aws
+{
+ namespace Crt
+ {
+ namespace Http
+ {
+ enum class AwsHttpProxyConnectionType;
+
+ /**
+ * Configuration for a proxy strategy that performs basic authentication
+ */
+ struct AWS_CRT_CPP_API HttpProxyStrategyBasicAuthConfig
+ {
+ HttpProxyStrategyBasicAuthConfig();
+
+ /**
+ * Basic auth can be applied either to forwarding or tunneling proxy connections, but we need
+ * to know the type ahead of time
+ */
+ AwsHttpProxyConnectionType ConnectionType;
+
+ /**
+ * Username to apply to the basic authentication process
+ */
+ String Username;
+
+ /**
+ * Password to apply to the basic authentication process
+ */
+ String Password;
+ };
+
+ using KerberosGetTokenFunction = std::function<bool(String &)>;
+ using NtlmGetTokenFunction = std::function<bool(const String &, String &)>;
+
+ /**
+ * Configuration for a proxy strategy that attempts to use kerberos and ntlm, based on authentication
+ * failure feedback from the proxy's responses to CONNECT attempts. The kerberos/ntlm callbacks are
+ * currently synchronous but invoked potentially from within event loop threads. This is not optimal
+ * but transitioning to fully async hasn't been a need yet.
+ *
+ * The adapative strategy will skip an authentication method whose callbacks are not supplied, so you
+ * can use this for purely kerberos or ntlm as well.
+ */
+ struct AWS_CRT_CPP_API HttpProxyStrategyAdaptiveConfig
+ {
+ HttpProxyStrategyAdaptiveConfig() : KerberosGetToken(), NtlmGetCredential(), NtlmGetToken() {}
+
+ /**
+ * User-supplied callback for fetching kerberos tokens
+ */
+ KerberosGetTokenFunction KerberosGetToken;
+
+ /**
+ * User-supplied callback for fetching an ntlm credential
+ */
+ KerberosGetTokenFunction NtlmGetCredential;
+
+ /**
+ * User-supplied callback for fetching an ntlm token
+ */
+ NtlmGetTokenFunction NtlmGetToken;
+ };
+
+ /**
+ * Wrapper class for a C-level proxy strategy - an object that allows the user to transform or modify
+ * the authentication logic when connecting to a proxy.
+ */
+ class AWS_CRT_CPP_API HttpProxyStrategy
+ {
+ public:
+ HttpProxyStrategy(struct aws_http_proxy_strategy *strategy);
+ virtual ~HttpProxyStrategy();
+
+ /// @private
+ struct aws_http_proxy_strategy *GetUnderlyingHandle() const noexcept { return m_strategy; }
+
+ /**
+ * Creates a proxy strategy that performs basic authentication
+ * @param config basic authentication configuration options
+ * @param allocator allocator to use
+ * @return a new basic authentication proxy strategy
+ */
+ static std::shared_ptr<HttpProxyStrategy> CreateBasicHttpProxyStrategy(
+ const HttpProxyStrategyBasicAuthConfig &config,
+ Allocator *allocator = ApiAllocator());
+
+ /**
+ * Creates a proxy strategy that, depending on configuration, can attempt kerberos and/or ntlm
+ * authentication when connecting to the proxy
+ * @param config the adaptive strategy configuration options
+ * @param allocator allocator to use
+ * @return a new adaptive proxy strategy
+ */
+ static std::shared_ptr<HttpProxyStrategy> CreateAdaptiveHttpProxyStrategy(
+ const HttpProxyStrategyAdaptiveConfig &config,
+ Allocator *allocator = ApiAllocator());
+
+ protected:
+ struct aws_http_proxy_strategy *m_strategy;
+ };
+ } // namespace Http
+ } // namespace Crt
+} // namespace Aws
diff --git a/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/http/HttpRequestResponse.h b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/http/HttpRequestResponse.h
new file mode 100644
index 0000000000..bf305e8b99
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/http/HttpRequestResponse.h
@@ -0,0 +1,160 @@
+#pragma once
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+
+#include <aws/crt/Exports.h>
+#include <aws/crt/Types.h>
+#include <aws/crt/io/Stream.h>
+
+struct aws_http_header;
+struct aws_http_message;
+
+namespace Aws
+{
+ namespace Crt
+ {
+ namespace Mqtt
+ {
+ class MqttConnection;
+ }
+ namespace Mqtt5
+ {
+ class Mqtt5Client;
+ }
+ namespace Http
+ {
+ using HttpHeader = aws_http_header;
+
+ /**
+ * Base class representing a mutable http request or response.
+ */
+ class AWS_CRT_CPP_API HttpMessage
+ {
+ public:
+ virtual ~HttpMessage();
+
+ HttpMessage(const HttpMessage &) = delete;
+ HttpMessage(HttpMessage &&) = delete;
+ HttpMessage &operator=(const HttpMessage &) = delete;
+ HttpMessage &operator=(HttpMessage &&) = delete;
+
+ /**
+ * Gets the input stream representing the message body
+ */
+ std::shared_ptr<Aws::Crt::Io::InputStream> GetBody() const noexcept;
+
+ /**
+ * Sets the input stream representing the message body
+ * @param body the input stream representing the message body
+ * @return success/failure
+ */
+ bool SetBody(const std::shared_ptr<Aws::Crt::Io::IStream> &body) noexcept;
+
+ /**
+ * Sets the input stream representing the message body
+ * @param body the input stream representing the message body
+ * @return success/failure
+ */
+ bool SetBody(const std::shared_ptr<Aws::Crt::Io::InputStream> &body) noexcept;
+
+ /**
+ * Gets the number of headers contained in this request
+ * @return the number of headers contained in this request
+ */
+ size_t GetHeaderCount() const noexcept;
+
+ /**
+ * Gets a particular header in the request
+ * @param index index of the header to fetch
+ * @return an option containing the requested header if the index is in bounds
+ */
+ Optional<HttpHeader> GetHeader(size_t index) const noexcept;
+
+ /**
+ * Adds a header to the request
+ * @param header header to add
+ * @return success/failure
+ */
+ bool AddHeader(const HttpHeader &header) noexcept;
+
+ /**
+ * Removes a header from the request
+ * @param index index of the header to remove
+ * @return success/failure
+ */
+ bool EraseHeader(size_t index) noexcept;
+
+ /**
+ * @return true/false if the underlying object is valid
+ */
+ operator bool() const noexcept { return m_message != nullptr; }
+
+ /// @private
+ struct aws_http_message *GetUnderlyingMessage() const noexcept { return m_message; }
+
+ protected:
+ HttpMessage(Allocator *allocator, struct aws_http_message *message) noexcept;
+
+ Allocator *m_allocator;
+ struct aws_http_message *m_message;
+ std::shared_ptr<Aws::Crt::Io::InputStream> m_bodyStream;
+ };
+
+ /**
+ * Class representing a mutable http request.
+ */
+ class AWS_CRT_CPP_API HttpRequest : public HttpMessage
+ {
+ friend class Mqtt::MqttConnection;
+ friend class Mqtt5::Mqtt5Client;
+
+ public:
+ HttpRequest(Allocator *allocator = ApiAllocator());
+
+ /**
+ * @return the value of the Http method associated with this request
+ */
+ Optional<ByteCursor> GetMethod() const noexcept;
+
+ /**
+ * Sets the value of the Http method associated with this request
+ */
+ bool SetMethod(ByteCursor method) noexcept;
+
+ /**
+ * @return the value of the URI-path associated with this request
+ */
+ Optional<ByteCursor> GetPath() const noexcept;
+
+ /**
+ * Sets the value of the URI-path associated with this request
+ */
+ bool SetPath(ByteCursor path) noexcept;
+
+ protected:
+ HttpRequest(Allocator *allocator, struct aws_http_message *message);
+ };
+
+ /**
+ * Class representing a mutable http response.
+ */
+ class AWS_CRT_CPP_API HttpResponse : public HttpMessage
+ {
+ public:
+ HttpResponse(Allocator *allocator = ApiAllocator());
+
+ /**
+ * @return the integral Http response code associated with this response
+ */
+ Optional<int> GetResponseCode() const noexcept;
+
+ /**
+ * Sets the integral Http response code associated with this response
+ */
+ bool SetResponseCode(int response) noexcept;
+ };
+ } // namespace Http
+ } // namespace Crt
+} // namespace Aws
diff --git a/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/io/Bootstrap.h b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/io/Bootstrap.h
new file mode 100644
index 0000000000..e1175f83ab
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/io/Bootstrap.h
@@ -0,0 +1,104 @@
+#pragma once
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+
+#include <aws/crt/Exports.h>
+#include <aws/crt/Types.h>
+#include <aws/crt/io/EventLoopGroup.h>
+#include <aws/crt/io/HostResolver.h>
+
+#include <aws/io/channel_bootstrap.h>
+#include <aws/io/host_resolver.h>
+
+#include <future>
+
+namespace Aws
+{
+ namespace Crt
+ {
+ namespace Io
+ {
+ using OnClientBootstrapShutdownComplete = std::function<void()>;
+
+ /**
+ * A ClientBootstrap handles creation and setup of socket connections
+ * to specific endpoints.
+ *
+ * Note that ClientBootstrap may not clean up all its behind-the-scenes
+ * resources immediately upon destruction. If you need to know when
+ * behind-the-scenes shutdown is complete, use SetShutdownCompleteCallback()
+ * or EnableBlockingShutdown() (only safe on main thread).
+ */
+ class AWS_CRT_CPP_API ClientBootstrap final
+ {
+ public:
+ /**
+ * @param elGroup: EventLoopGroup to use.
+ * @param resolver: DNS host resolver to use.
+ * @param allocator memory allocator to use
+ */
+ ClientBootstrap(
+ EventLoopGroup &elGroup,
+ HostResolver &resolver,
+ Allocator *allocator = ApiAllocator()) noexcept;
+
+ /**
+ * Uses the default EventLoopGroup and HostResolver.
+ * See Aws::Crt::ApiHandle::GetOrCreateStaticDefaultEventLoopGroup
+ * and Aws::Crt::ApiHandle::GetOrCreateStaticDefaultHostResolver
+ */
+ ClientBootstrap(Allocator *allocator = ApiAllocator()) noexcept;
+
+ ~ClientBootstrap();
+ ClientBootstrap(const ClientBootstrap &) = delete;
+ ClientBootstrap &operator=(const ClientBootstrap &) = delete;
+ ClientBootstrap(ClientBootstrap &&) = delete;
+ ClientBootstrap &operator=(ClientBootstrap &&) = delete;
+
+ /**
+ * @return true if the instance is in a valid state, false otherwise.
+ */
+ operator bool() const noexcept;
+
+ /**
+ * @return the value of the last aws error encountered by operations on this instance.
+ */
+ int LastError() const noexcept;
+
+ /**
+ * Set function to invoke when ClientBootstrap's behind-the-scenes
+ * resources finish shutting down. This function may be invoked
+ * on any thread. Shutdown begins when the ClientBootstrap's
+ * destructor runs.
+ */
+ void SetShutdownCompleteCallback(OnClientBootstrapShutdownComplete callback);
+
+ /**
+ * Force the ClientBootstrap's destructor to block until all
+ * behind-the-scenes resources finish shutting down.
+ *
+ * This isn't necessary during the normal flow of an application,
+ * but it is useful for scenarios, such as tests, that need deterministic
+ * shutdown ordering. Be aware, if you use this anywhere other
+ * than the main thread, YOU WILL MOST LIKELY CAUSE A DEADLOCK.
+ *
+ * Use SetShutdownCompleteCallback() for a thread-safe way to
+ * know when shutdown is complete.
+ */
+ void EnableBlockingShutdown() noexcept;
+
+ /// @private
+ aws_client_bootstrap *GetUnderlyingHandle() const noexcept;
+
+ private:
+ aws_client_bootstrap *m_bootstrap;
+ int m_lastError;
+ std::unique_ptr<class ClientBootstrapCallbackData> m_callbackData;
+ std::future<void> m_shutdownFuture;
+ bool m_enableBlockingShutdown;
+ };
+ } // namespace Io
+ } // namespace Crt
+} // namespace Aws
diff --git a/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/io/ChannelHandler.h b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/io/ChannelHandler.h
new file mode 100644
index 0000000000..7f5c8ecd99
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/io/ChannelHandler.h
@@ -0,0 +1,238 @@
+#pragma once
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+
+#include <aws/crt/Exports.h>
+#include <aws/crt/Types.h>
+#include <aws/io/channel.h>
+
+#include <chrono>
+#include <cstddef>
+
+struct aws_array_list;
+struct aws_io_message;
+
+namespace Aws
+{
+ namespace Crt
+ {
+ namespace Io
+ {
+ enum class ChannelDirection
+ {
+ Read,
+ Write,
+ };
+
+ enum class MessageType
+ {
+ ApplicationData,
+ };
+
+ enum class TaskStatus
+ {
+ RunReady,
+ Canceled,
+ };
+
+ /**
+ * Wrapper for aws-c-io channel handlers. The semantics are identical as the functions on
+ * aws_channel_handler.
+ *
+ * All virtual calls are made from the same thread (the channel's thread).
+ */
+ class AWS_CRT_CPP_API ChannelHandler
+ {
+ public:
+ virtual ~ChannelHandler() = default;
+
+ ChannelHandler(const ChannelHandler &) = delete;
+ ChannelHandler &operator=(const ChannelHandler &) = delete;
+
+ protected:
+ /**
+ * Called by the channel when a message is available for processing in the read direction. It is your
+ * responsibility to call aws_mem_release(message->allocator, message); on message when you are finished
+ * with it.
+ *
+ * Also keep in mind that your slot's internal window has been decremented. You'll want to call
+ * aws_channel_slot_increment_read_window() at some point in the future if you want to keep receiving
+ * data.
+ *
+ * @return AWS_OP_SUCCESS if the message is being processed.
+ * If the message cannot be processed raise an error and return AWS_OP_ERR
+ * and do NOT release the message, it will be released by the caller.
+ */
+ virtual int ProcessReadMessage(struct aws_io_message *message) = 0;
+
+ /**
+ * Called by the channel when a message is available for processing in the write direction. It is your
+ * responsibility to call aws_mem_release(message->allocator, message); on message when you are finished
+ * with it.
+ *
+ * @return AWS_OP_SUCCESS if the message is being processed.
+ * If the message cannot be processed raise an error and return AWS_OP_ERR
+ * and do NOT release the message, it will be released by the caller.
+ */
+ virtual int ProcessWriteMessage(struct aws_io_message *message) = 0;
+
+ /**
+ * Called by the channel when a downstream handler has issued a window increment. You'll want to update
+ * your internal state and likely propagate a window increment message of your own by calling
+ * IncrementUpstreamReadWindow()
+ *
+ * @return AWS_OP_SUCCESS if successful.
+ * Otherwise, raise an error and return AWS_OP_ERR.
+ */
+ virtual int IncrementReadWindow(size_t size) = 0;
+
+ /**
+ * The channel calls shutdown on all handlers twice, once to shut down reading, and once to shut down
+ * writing. Shutdown always begins with the left-most handler, and proceeds to the right with dir set to
+ * ChannelDirection::Read. Then shutdown is called on handlers from right to left with dir set to
+ * ChannelDirection::Write.
+ *
+ * The shutdown process does not need to complete immediately and may rely on scheduled tasks.
+ * The handler MUST call OnShutdownComplete() when it is finished,
+ * which propagates shutdown to the next handler. If 'freeScarceResourcesImmediately' is true,
+ * then resources vulnerable to denial-of-service attacks (such as sockets and file handles)
+ * must be closed immediately before the shutdown process complete.
+ */
+ virtual void ProcessShutdown(
+ ChannelDirection dir,
+ int errorCode,
+ bool freeScarceResourcesImmediately) = 0;
+
+ /**
+ * Called by the channel when the handler is added to a slot, to get the initial window size.
+ */
+ virtual size_t InitialWindowSize() = 0;
+
+ /**
+ * Called by the channel anytime a handler is added or removed, provides a hint for downstream
+ * handlers to avoid message fragmentation due to message overhead.
+ */
+ virtual size_t MessageOverhead() = 0;
+
+ /**
+ * Directs the channel handler to reset all of the internal statistics it tracks about itself.
+ */
+ virtual void ResetStatistics(){};
+
+ /**
+ * Adds a pointer to the handler's internal statistics (if they exist) to a list of statistics
+ * structures associated with the channel's handler chain.
+ */
+ virtual void GatherStatistics(struct aws_array_list *) {}
+
+ public:
+ /// @private
+ struct aws_channel_handler *SeatForCInterop(const std::shared_ptr<ChannelHandler> &selfRef);
+
+ /**
+ * Return whether the caller is on the same thread as the handler's channel.
+ */
+ bool ChannelsThreadIsCallersThread() const;
+
+ /**
+ * Initiate a shutdown of the handler's channel.
+ *
+ * If the channel is already shutting down, this call has no effect.
+ */
+ void ShutDownChannel(int errorCode);
+
+ /**
+ * Schedule a task to run on the next "tick" of the event loop.
+ * If the channel is completely shut down, the task will run with the 'Canceled' status.
+ */
+ void ScheduleTask(std::function<void(TaskStatus)> &&task);
+
+ /**
+ * Schedule a task to run after a desired length of time has passed.
+ * The task will run with the 'Canceled' status if the channel completes shutdown
+ * before that length of time elapses.
+ */
+ void ScheduleTask(std::function<void(TaskStatus)> &&task, std::chrono::nanoseconds run_in);
+
+ protected:
+ ChannelHandler(Allocator *allocator = ApiAllocator());
+
+ /**
+ * Acquire an aws_io_message from the channel's pool.
+ */
+ struct aws_io_message *AcquireMessageFromPool(MessageType messageType, size_t sizeHint);
+
+ /**
+ * Convenience function that invokes AcquireMessageFromPool(),
+ * asking for the largest reasonable DATA message that can be sent in the write direction,
+ * with upstream overhead accounted for.
+ */
+ struct aws_io_message *AcquireMaxSizeMessageForWrite();
+
+ /**
+ * Send a message in the read or write direction.
+ * Returns true if message successfully sent.
+ * If false is returned, you must release the message yourself.
+ */
+ bool SendMessage(struct aws_io_message *message, ChannelDirection direction);
+
+ /**
+ * Issue a window update notification upstream.
+ * Returns true if successful.
+ */
+ bool IncrementUpstreamReadWindow(size_t windowUpdateSize);
+
+ /**
+ * Must be called by a handler once they have finished their shutdown in the 'dir' direction.
+ * Propagates the shutdown process to the next handler in the channel.
+ */
+ void OnShutdownComplete(ChannelDirection direction, int errorCode, bool freeScarceResourcesImmediately);
+
+ /**
+ * Fetches the downstream read window.
+ * This gives you the information necessary to honor the read window.
+ * If you call send_message() and it exceeds this window, the message will be rejected.
+ */
+ size_t DownstreamReadWindow() const;
+
+ /**
+ * Fetches the current overhead of upstream handlers.
+ * This provides a hint to avoid fragmentation if you care.
+ */
+ size_t UpstreamMessageOverhead() const;
+
+ struct aws_channel_slot *GetSlot() const;
+
+ struct aws_channel_handler m_handler;
+ Allocator *m_allocator;
+
+ private:
+ std::shared_ptr<ChannelHandler> m_selfReference;
+ static struct aws_channel_handler_vtable s_vtable;
+
+ static void s_Destroy(struct aws_channel_handler *handler);
+ static int s_ProcessReadMessage(
+ struct aws_channel_handler *,
+ struct aws_channel_slot *,
+ struct aws_io_message *);
+ static int s_ProcessWriteMessage(
+ struct aws_channel_handler *,
+ struct aws_channel_slot *,
+ struct aws_io_message *);
+ static int s_IncrementReadWindow(struct aws_channel_handler *, struct aws_channel_slot *, size_t size);
+ static int s_ProcessShutdown(
+ struct aws_channel_handler *,
+ struct aws_channel_slot *,
+ enum aws_channel_direction,
+ int errorCode,
+ bool freeScarceResourcesImmediately);
+ static size_t s_InitialWindowSize(struct aws_channel_handler *);
+ static size_t s_MessageOverhead(struct aws_channel_handler *);
+ static void s_ResetStatistics(struct aws_channel_handler *);
+ static void s_GatherStatistics(struct aws_channel_handler *, struct aws_array_list *statsList);
+ };
+ } // namespace Io
+ } // namespace Crt
+} // namespace Aws
diff --git a/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/io/EventLoopGroup.h b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/io/EventLoopGroup.h
new file mode 100644
index 0000000000..0ef904f285
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/io/EventLoopGroup.h
@@ -0,0 +1,74 @@
+#pragma once
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+#include <aws/crt/Types.h>
+
+#include <aws/io/event_loop.h>
+
+namespace Aws
+{
+ namespace Crt
+ {
+ namespace Io
+ {
+ /**
+ * A collection of event loops.
+ *
+ * An event-loop is a thread for doing async work, such as I/O. Classes that need to do async work will ask
+ * the EventLoopGroup for an event-loop to use.
+ *
+ * The number of threads used depends on your use-case. IF you
+ * have a maximum of less than a few hundred connections 1 thread is the ideal
+ * threadCount.
+ *
+ * There should only be one instance of an EventLoopGroup per application and it
+ * should be passed to all network clients. One exception to this is if you
+ * want to peg different types of IO to different threads. In that case, you
+ * may want to have one event loop group dedicated to one IO activity and another
+ * dedicated to another type.
+ */
+ class AWS_CRT_CPP_API EventLoopGroup final
+ {
+ public:
+ /**
+ * @param threadCount: The number of event-loops to create, default will be 0, which will create one for
+ * each processor on the machine.
+ * @param allocator memory allocator to use.
+ */
+ EventLoopGroup(uint16_t threadCount = 0, Allocator *allocator = ApiAllocator()) noexcept;
+ /**
+ * @param cpuGroup: The CPU group (e.g. NUMA nodes) that all hardware threads are pinned to.
+ * @param threadCount: The number of event-loops to create, default will be 0, which will create one for
+ * each processor on the machine.
+ * @param allocator memory allocator to use.
+ */
+ EventLoopGroup(uint16_t cpuGroup, uint16_t threadCount, Allocator *allocator = ApiAllocator()) noexcept;
+ ~EventLoopGroup();
+ EventLoopGroup(const EventLoopGroup &) = delete;
+ EventLoopGroup(EventLoopGroup &&) noexcept;
+ EventLoopGroup &operator=(const EventLoopGroup &) = delete;
+ EventLoopGroup &operator=(EventLoopGroup &&) noexcept;
+
+ /**
+ * @return true if the instance is in a valid state, false otherwise.
+ */
+ operator bool() const;
+
+ /**
+ * @return the value of the last aws error encountered by operations on this instance.
+ */
+ int LastError() const;
+
+ /// @private
+ aws_event_loop_group *GetUnderlyingHandle() noexcept;
+
+ private:
+ aws_event_loop_group *m_eventLoopGroup;
+ int m_lastError;
+ };
+ } // namespace Io
+
+ } // namespace Crt
+} // namespace Aws
diff --git a/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/io/HostResolver.h b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/io/HostResolver.h
new file mode 100644
index 0000000000..dac0e60237
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/io/HostResolver.h
@@ -0,0 +1,123 @@
+#pragma once
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+#include <aws/crt/Types.h>
+
+#include <aws/io/host_resolver.h>
+
+#include <functional>
+
+namespace Aws
+{
+ namespace Crt
+ {
+ namespace Io
+ {
+ class EventLoopGroup;
+ class HostResolver;
+
+ using HostAddress = aws_host_address;
+
+ /**
+ * Invoked upon resolution of an address. You do not own the memory pointed to in addresses, if you persist
+ * the data, copy it first. If errorCode is AWS_ERROR_SUCCESS, the operation succeeded. Otherwise, the
+ * operation failed.
+ */
+ using OnHostResolved =
+ std::function<void(HostResolver &resolver, const Vector<HostAddress> &addresses, int errorCode)>;
+
+ /**
+ * Simple interface for DNS name lookup implementations
+ */
+ class AWS_CRT_CPP_API HostResolver
+ {
+ public:
+ virtual ~HostResolver();
+ virtual bool ResolveHost(const String &host, const OnHostResolved &onResolved) noexcept = 0;
+
+ /// @private
+ virtual aws_host_resolver *GetUnderlyingHandle() noexcept = 0;
+ /// @private
+ virtual aws_host_resolution_config *GetConfig() noexcept = 0;
+ };
+
+ /**
+ * A wrapper around the CRT default host resolution system that uses getaddrinfo() farmed off
+ * to separate threads in order to resolve names.
+ */
+ class AWS_CRT_CPP_API DefaultHostResolver final : public HostResolver
+ {
+ public:
+ /**
+ * Resolves DNS addresses.
+ *
+ * @param elGroup: EventLoopGroup to use.
+ * @param maxHosts: the number of unique hosts to maintain in the cache.
+ * @param maxTTL: how long to keep an address in the cache before evicting it.
+ * @param allocator memory allocator to use.
+ */
+ DefaultHostResolver(
+ EventLoopGroup &elGroup,
+ size_t maxHosts,
+ size_t maxTTL,
+ Allocator *allocator = ApiAllocator()) noexcept;
+
+ /**
+ * Resolves DNS addresses using the default EventLoopGroup.
+ *
+ * For more information on the default EventLoopGroup see
+ * Aws::Crt::ApiHandle::GetOrCreateStaticDefaultEventLoopGroup
+ *
+ * @param maxHosts: the number of unique hosts to maintain in the cache.
+ * @param maxTTL: how long to keep an address in the cache before evicting it.
+ * @param allocator memory allocator to use.
+ */
+ DefaultHostResolver(size_t maxHosts, size_t maxTTL, Allocator *allocator = ApiAllocator()) noexcept;
+
+ ~DefaultHostResolver();
+ DefaultHostResolver(const DefaultHostResolver &) = delete;
+ DefaultHostResolver &operator=(const DefaultHostResolver &) = delete;
+ DefaultHostResolver(DefaultHostResolver &&) = delete;
+ DefaultHostResolver &operator=(DefaultHostResolver &&) = delete;
+
+ /**
+ * @return true if the instance is in a valid state, false otherwise.
+ */
+ operator bool() const noexcept { return m_initialized; }
+
+ /**
+ * @return the value of the last aws error encountered by operations on this instance.
+ */
+ int LastError() const noexcept { return aws_last_error(); }
+
+ /**
+ * Kicks off an asynchronous resolution of host. onResolved will be invoked upon completion of the
+ * resolution.
+ * @return False, the resolution was not attempted. True, onResolved will be
+ * called with the result.
+ */
+ bool ResolveHost(const String &host, const OnHostResolved &onResolved) noexcept override;
+
+ /// @private
+ aws_host_resolver *GetUnderlyingHandle() noexcept override { return m_resolver; }
+ /// @private
+ aws_host_resolution_config *GetConfig() noexcept override { return &m_config; }
+
+ private:
+ aws_host_resolver *m_resolver;
+ aws_host_resolution_config m_config;
+ Allocator *m_allocator;
+ bool m_initialized;
+
+ static void s_onHostResolved(
+ struct aws_host_resolver *resolver,
+ const struct aws_string *host_name,
+ int err_code,
+ const struct aws_array_list *host_addresses,
+ void *user_data);
+ };
+ } // namespace Io
+ } // namespace Crt
+} // namespace Aws
diff --git a/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/io/Pkcs11.h b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/io/Pkcs11.h
new file mode 100644
index 0000000000..7f10baad83
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/io/Pkcs11.h
@@ -0,0 +1,116 @@
+#pragma once
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+
+#include <aws/crt/Types.h>
+
+struct aws_pkcs11_lib;
+
+namespace Aws
+{
+ namespace Crt
+ {
+ namespace Io
+ {
+ /**
+ * Handle to a loaded PKCS#11 library.
+ *
+ * For most use cases, a single instance of Pkcs11Lib should be used for the
+ * lifetime of your application.
+ */
+ class AWS_CRT_CPP_API Pkcs11Lib
+ {
+ public:
+ /**
+ * Controls how Pkcs11Lib calls `C_Initialize()` and `C_Finalize()`
+ * on the PKCS#11 library.
+ */
+ enum class InitializeFinalizeBehavior
+ {
+ /**
+ * Default behavior that accommodates most use cases.
+ *
+ * `C_Initialize()` is called on creation, and "already-initialized"
+ * errors are ignored. `C_Finalize()` is never called, just in case
+ * another part of your application is still using the PKCS#11 library.
+ */
+ Default,
+
+ /**
+ * Skip calling `C_Initialize()` and `C_Finalize()`.
+ *
+ * Use this if your application has already initialized the PKCS#11 library, and
+ * you do not want `C_Initialize()` called again.
+ */
+ Omit,
+
+ /**
+ * `C_Initialize()` is called on creation and `C_Finalize()` is
+ * called on cleanup.
+ *
+ * If `C_Initialize()` reports that's it's already initialized, this is
+ * treated as an error. Use this if you need perfect cleanup (ex: running
+ * valgrind with --leak-check).
+ */
+ Strict,
+ };
+
+ /**
+ * Load and initialize a PKCS#11 library.
+ *
+ * `C_Initialize()` and `C_Finalize()` are called on the PKCS#11
+ * library in the InitializeFinalizeBehavior::Default way.
+ *
+ * @param filename Name or path of PKCS#11 library file to load (UTF-8).
+ * Pass an empty string if your application already has PKCS#11 symbols linked in.
+ *
+ * @param allocator Memory allocator to use.
+ *
+ * @return If successful a `shared_ptr` containing the Pkcs11Lib is returned.
+ * If unsuccessful the `shared_ptr` will be empty, and Aws::Crt::LastError()
+ * will contain the error that occurred.
+ */
+ static std::shared_ptr<Pkcs11Lib> Create(const String &filename, Allocator *allocator = ApiAllocator());
+
+ /**
+ * Load a PKCS#11 library, specifying how `C_Initialize()` and `C_Finalize()` will be called.
+ *
+ * @param filename Name or path of PKCS#11 library file to load (UTF-8).
+ * Pass an empty string if your application already has PKCS#11 symbols linked in.
+ *
+ * @param initializeFinalizeBehavior Specifies how `C_Initialize()` and
+ * `C_Finalize()` will be called on the
+ * PKCS#11 library.
+ * @param allocator Memory allocator to use.
+ *
+ * @return If successful a `shared_ptr` containing the Pkcs11Lib is returned.
+ * If unsuccessful the `shared_ptr` will be empty, and Aws::Crt::LastError()
+ * will contain the error that occurred.
+ */
+ static std::shared_ptr<Pkcs11Lib> Create(
+ const String &filename,
+ InitializeFinalizeBehavior initializeFinalizeBehavior,
+ Allocator *allocator = ApiAllocator());
+
+ ~Pkcs11Lib();
+
+ /// @private
+ aws_pkcs11_lib *GetNativeHandle() { return impl; }
+
+ /// @private Use Create(...), this constructor is for internal use only
+ explicit Pkcs11Lib(aws_pkcs11_lib &impl);
+
+ private:
+ // no copy/move
+ Pkcs11Lib(const Pkcs11Lib &) = delete;
+ Pkcs11Lib(Pkcs11Lib &&) = delete;
+ Pkcs11Lib &operator=(const Pkcs11Lib &) = delete;
+ Pkcs11Lib &operator=(Pkcs11Lib &&) = delete;
+
+ aws_pkcs11_lib *impl = nullptr;
+ };
+ } // namespace Io
+ } // namespace Crt
+} // namespace Aws
diff --git a/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/io/SocketOptions.h b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/io/SocketOptions.h
new file mode 100644
index 0000000000..9f31250dde
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/io/SocketOptions.h
@@ -0,0 +1,157 @@
+#pragma once
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+
+#include <aws/crt/Exports.h>
+
+#include <aws/io/socket.h>
+
+namespace Aws
+{
+ namespace Crt
+ {
+ namespace Io
+ {
+ enum class SocketType
+ {
+ /**
+ * A streaming socket sends reliable messages over a two-way connection.
+ * This means TCP when used with IPV4/6, and Unix domain sockets, when used with
+ * AWS_SOCKET_LOCAL
+ */
+ Stream = AWS_SOCKET_STREAM,
+
+ /**
+ * A datagram socket is connectionless and sends unreliable messages.
+ * This means UDP when used with IPV4/6.
+ * LOCAL sockets are not compatible with DGRAM.
+ */
+ Dgram = AWS_SOCKET_DGRAM,
+ };
+
+ enum class SocketDomain
+ {
+ IPv4 = AWS_SOCKET_IPV4,
+ IPv6 = AWS_SOCKET_IPV6,
+ /**
+ * Unix domain sockets (or at least something like them)
+ */
+ Local = AWS_SOCKET_LOCAL,
+ };
+
+ /**
+ * Socket configuration options
+ */
+ class AWS_CRT_CPP_API SocketOptions
+ {
+ public:
+ SocketOptions();
+ SocketOptions(const SocketOptions &rhs) = default;
+ SocketOptions(SocketOptions &&rhs) = default;
+
+ SocketOptions &operator=(const SocketOptions &rhs) = default;
+ SocketOptions &operator=(SocketOptions &&rhs) = default;
+
+ /**
+ * Set socket type
+ * @param type: SocketType object.
+ */
+ void SetSocketType(SocketType type) { options.type = (enum aws_socket_type)type; }
+
+ /**
+ * @return the type of socket to use
+ */
+ SocketType GetSocketType() const { return (SocketType)options.type; }
+
+ /**
+ * Set socket domain
+ * @param domain: SocketDomain object.
+ */
+ void SetSocketDomain(SocketDomain domain) { options.domain = (enum aws_socket_domain)domain; }
+
+ /**
+ * @return the domain type to use with the socket
+ */
+ SocketDomain GetSocketDomain() const { return (SocketDomain)options.domain; }
+
+ /**
+ * Set connection timeout
+ * @param timeout: connection timeout in milliseconds.
+ */
+ void SetConnectTimeoutMs(uint32_t timeout) { options.connect_timeout_ms = timeout; }
+
+ /**
+ * @return the connection timeout in milliseconds to use with the socket
+ */
+ uint32_t GetConnectTimeoutMs() const { return options.connect_timeout_ms; }
+
+ /**
+ * Set keep alive interval seconds.
+ * @param keepAliveInterval: Duration, in seconds, between keepalive probes. If 0, then a default value
+ * is used.
+ */
+ void SetKeepAliveIntervalSec(uint16_t keepAliveInterval)
+ {
+ options.keep_alive_interval_sec = keepAliveInterval;
+ }
+
+ /**
+ * @return the (tcp) keep alive interval to use with the socket, in seconds
+ */
+ uint16_t GetKeepAliveIntervalSec() const { return options.keep_alive_interval_sec; }
+
+ /**
+ * Set keep alive time out seconds.
+ * @param keepAliveTimeout: interval, in seconds, that a connection must be idle for before keep alive
+ * probes begin to get sent out
+ */
+ void SetKeepAliveTimeoutSec(uint16_t keepAliveTimeout)
+ {
+ options.keep_alive_timeout_sec = keepAliveTimeout;
+ }
+
+ /**
+ * @return interval, in seconds, that a connection must be idle for before keep alive probes begin
+ * to get sent out
+ */
+ uint16_t GetKeepAliveTimeoutSec() const { return options.keep_alive_timeout_sec; }
+
+ /**
+ * Set keep alive max failed probes.
+ * @param maxProbes: The number of keepalive probes allowed to fail before a connection is considered
+ * lost.
+ */
+ void SetKeepAliveMaxFailedProbes(uint16_t maxProbes)
+ {
+ options.keep_alive_max_failed_probes = maxProbes;
+ }
+
+ /**
+ * @return number of keepalive probes allowed to fail before a connection is considered lost.
+ */
+ uint16_t GetKeepAliveMaxFailedProbes() const { return options.keep_alive_max_failed_probes; }
+
+ /**
+ * Set keep alive option.
+ * @param keepAlive: True, periodically transmit keepalive messages for detecting a disconnected peer.
+ */
+ void SetKeepAlive(bool keepAlive) { options.keepalive = keepAlive; }
+
+ /**
+ * @return true/false if the socket implementation should use TCP keepalive
+ */
+ bool GetKeepAlive() const { return options.keepalive; }
+
+ /// @private
+ aws_socket_options &GetImpl() { return options; }
+ /// @private
+ const aws_socket_options &GetImpl() const { return options; }
+
+ private:
+ aws_socket_options options;
+ };
+ } // namespace Io
+ } // namespace Crt
+} // namespace Aws
diff --git a/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/io/Stream.h b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/io/Stream.h
new file mode 100644
index 0000000000..cf6c49fa3e
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/io/Stream.h
@@ -0,0 +1,173 @@
+#pragma once
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+
+#include <aws/crt/Exports.h>
+#include <aws/crt/RefCounted.h>
+#include <aws/crt/Types.h>
+#include <aws/io/stream.h>
+
+namespace Aws
+{
+ namespace Crt
+ {
+ namespace Io
+ {
+ using StreamStatus = aws_stream_status;
+
+ /**
+ * @deprecated Use int64_t instead for offsets in public APIs.
+ */
+ using OffsetType = aws_off_t;
+
+ /**
+ * Controls the direction to seek from
+ */
+ enum class StreamSeekBasis
+ {
+ Begin = AWS_SSB_BEGIN,
+ End = AWS_SSB_END,
+ };
+
+ /***
+ * Interface for building an Object oriented stream that will be honored by the CRT's low-level
+ * aws_input_stream interface. To use, create a subclass of InputStream and define the abstract
+ * functions.
+ */
+ class AWS_CRT_CPP_API InputStream : public std::enable_shared_from_this<InputStream>,
+ public RefCounted<InputStream>
+ {
+ public:
+ virtual ~InputStream();
+
+ InputStream(const InputStream &) = delete;
+ InputStream &operator=(const InputStream &) = delete;
+ InputStream(InputStream &&) = delete;
+ InputStream &operator=(InputStream &&) = delete;
+
+ explicit operator bool() const noexcept { return IsValid(); }
+
+ /**
+ * @return true/false if this object is in a valid state
+ */
+ virtual bool IsValid() const noexcept = 0;
+
+ /// @private
+ aws_input_stream *GetUnderlyingStream() noexcept { return &m_underlying_stream; }
+
+ /**
+ * Reads data from the stream into a buffer
+ * @param dest buffer to add the read data into
+ * @return success/failure
+ */
+ bool Read(ByteBuf &dest) { return aws_input_stream_read(&m_underlying_stream, &dest) == 0; }
+
+ /**
+ * Moves the head of the stream to a new location
+ * @param offset how far to move, in bytes
+ * @param seekBasis what direction to move the head of stream
+ * @return success/failure
+ */
+ bool Seek(int64_t offset, StreamSeekBasis seekBasis)
+ {
+ return aws_input_stream_seek(&m_underlying_stream, offset, (aws_stream_seek_basis)seekBasis) == 0;
+ }
+
+ /**
+ * Gets the stream's current status
+ * @param status output parameter for the stream's status
+ * @return success/failure
+ */
+ bool GetStatus(StreamStatus &status)
+ {
+ return aws_input_stream_get_status(&m_underlying_stream, &status) == 0;
+ }
+
+ /**
+ * Gets the stream's length. Some streams may not be able to answer this.
+ * @param length output parameter for the length of the stream
+ * @return success/failure
+ */
+ bool GetLength(int64_t &length)
+ {
+ return aws_input_stream_get_length(&m_underlying_stream, &length) == 0;
+ }
+
+ protected:
+ Allocator *m_allocator;
+ aws_input_stream m_underlying_stream;
+
+ InputStream(Aws::Crt::Allocator *allocator = ApiAllocator());
+
+ /***
+ * Read up-to buffer::capacity - buffer::len into buffer::buffer
+ * Increment buffer::len by the amount you read in.
+ *
+ * @return true if nothing went wrong.
+ * Return true even if you read 0 bytes because the end-of-file has been reached.
+ * Return true even if you read 0 bytes because data is not currently available.
+ *
+ * Return false if an actual failure condition occurs,
+ * you SHOULD also raise an error via aws_raise_error().
+ */
+ virtual bool ReadImpl(ByteBuf &buffer) noexcept = 0;
+
+ /**
+ * @return the current status of the stream.
+ */
+ virtual StreamStatus GetStatusImpl() const noexcept = 0;
+
+ /**
+ * @return the total length of the available data for the stream.
+ * @return -1 if not available.
+ */
+ virtual int64_t GetLengthImpl() const noexcept = 0;
+
+ /**
+ * Seek's the stream to seekBasis based offset bytes.
+ *
+ * It is expected, that if seeking to the beginning of a stream,
+ * all error's are cleared if possible.
+ *
+ * @return true on success, false otherwise. You SHOULD raise an error via aws_raise_error()
+ * if a failure occurs.
+ */
+ virtual bool SeekImpl(int64_t offset, StreamSeekBasis seekBasis) noexcept = 0;
+
+ private:
+ static int s_Seek(aws_input_stream *stream, int64_t offset, enum aws_stream_seek_basis basis);
+ static int s_Read(aws_input_stream *stream, aws_byte_buf *dest);
+ static int s_GetStatus(aws_input_stream *stream, aws_stream_status *status);
+ static int s_GetLength(struct aws_input_stream *stream, int64_t *out_length);
+ static void s_Acquire(aws_input_stream *stream);
+ static void s_Release(aws_input_stream *stream);
+
+ static aws_input_stream_vtable s_vtable;
+ };
+
+ /***
+ * Implementation of Aws::Crt::Io::InputStream that wraps a std::input_stream.
+ */
+ class AWS_CRT_CPP_API StdIOStreamInputStream : public InputStream
+ {
+ public:
+ StdIOStreamInputStream(
+ std::shared_ptr<Aws::Crt::Io::IStream> stream,
+ Aws::Crt::Allocator *allocator = ApiAllocator()) noexcept;
+
+ bool IsValid() const noexcept override;
+
+ protected:
+ bool ReadImpl(ByteBuf &buffer) noexcept override;
+ StreamStatus GetStatusImpl() const noexcept override;
+ int64_t GetLengthImpl() const noexcept override;
+ bool SeekImpl(OffsetType offsetType, StreamSeekBasis seekBasis) noexcept override;
+
+ private:
+ std::shared_ptr<Aws::Crt::Io::IStream> m_stream;
+ };
+ } // namespace Io
+ } // namespace Crt
+} // namespace Aws
diff --git a/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/io/TlsOptions.h b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/io/TlsOptions.h
new file mode 100644
index 0000000000..afb543a92a
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/io/TlsOptions.h
@@ -0,0 +1,453 @@
+#pragma once
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+
+#include <aws/crt/Types.h>
+#include <aws/crt/io/ChannelHandler.h>
+#include <aws/io/tls_channel_handler.h>
+
+#include <functional>
+#include <memory>
+
+struct aws_tls_ctx_options;
+
+namespace Aws
+{
+ namespace Crt
+ {
+ namespace Io
+ {
+ class Pkcs11Lib;
+ class TlsContextPkcs11Options;
+
+ enum class TlsMode
+ {
+ CLIENT,
+ SERVER,
+ };
+
+ /**
+ * Top-level tls configuration options. These options are used to create a context from which
+ * per-connection TLS contexts can be created.
+ */
+ class AWS_CRT_CPP_API TlsContextOptions
+ {
+ friend class TlsContext;
+
+ public:
+ TlsContextOptions() noexcept;
+ virtual ~TlsContextOptions();
+ TlsContextOptions(const TlsContextOptions &) noexcept = delete;
+ TlsContextOptions &operator=(const TlsContextOptions &) noexcept = delete;
+ TlsContextOptions(TlsContextOptions &&) noexcept;
+ TlsContextOptions &operator=(TlsContextOptions &&) noexcept;
+
+ /**
+ * @return true if the instance is in a valid state, false otherwise.
+ */
+ explicit operator bool() const noexcept { return m_isInit; }
+
+ /**
+ * @return the value of the last aws error encountered by operations on this instance.
+ */
+ int LastError() const noexcept;
+
+ /**
+ * Initializes TlsContextOptions with secure by default options, with
+ * no client certificates.
+ */
+ static TlsContextOptions InitDefaultClient(Allocator *allocator = ApiAllocator()) noexcept;
+
+ /**
+ * Initializes TlsContextOptions for mutual TLS (mTLS), with
+ * client certificate and private key. These are paths to a file on disk. These files
+ * must be in the PEM format.
+ *
+ * NOTE: This is unsupported on iOS.
+ *
+ * @param cert_path: Path to certificate file.
+ * @param pkey_path: Path to private key file.
+ * @param allocator Memory allocator to use.
+ */
+ static TlsContextOptions InitClientWithMtls(
+ const char *cert_path,
+ const char *pkey_path,
+ Allocator *allocator = ApiAllocator()) noexcept;
+
+ /**
+ * Initializes TlsContextOptions for mutual TLS (mTLS), with
+ * client certificate and private key. These are in memory buffers. These buffers
+ * must be in the PEM format.
+ *
+ * NOTE: This is unsupported on iOS.
+ *
+ * @param cert: Certificate contents in memory.
+ * @param pkey: Private key contents in memory.
+ * @param allocator Memory allocator to use.
+ */
+ static TlsContextOptions InitClientWithMtls(
+ const ByteCursor &cert,
+ const ByteCursor &pkey,
+ Allocator *allocator = ApiAllocator()) noexcept;
+
+ /**
+ * Initializes TlsContextOptions for mutual TLS (mTLS),
+ * using a PKCS#11 library for private key operations.
+ *
+ * NOTE: This only works on Unix devices.
+ *
+ * @param pkcs11Options PKCS#11 options
+ * @param allocator Memory allocator to use.
+ */
+ static TlsContextOptions InitClientWithMtlsPkcs11(
+ const TlsContextPkcs11Options &pkcs11Options,
+ Allocator *allocator = ApiAllocator()) noexcept;
+
+ /**
+ * Initializes TlsContextOptions for mutual TLS (mTLS), with
+ * client certificate and private key in the PKCS#12 format.
+ *
+ * NOTE: This only works on Apple devices.
+ *
+ * @param pkcs12_path: Path to PKCS #12 file. The file is loaded from disk and stored internally. It
+ * must remain in memory for the lifetime of the returned object.
+ * @param pkcs12_pwd: Password to PKCS #12 file. It must remain in memory for the lifetime of the
+ * returned object.
+ * @param allocator Memory allocator to use.
+ */
+ static TlsContextOptions InitClientWithMtlsPkcs12(
+ const char *pkcs12_path,
+ const char *pkcs12_pwd,
+ Allocator *allocator = ApiAllocator()) noexcept;
+
+ /**
+ * @deprecated Custom keychain management is deprecated.
+ *
+ * By default the certificates and private keys are stored in the default keychain
+ * of the account of the process. If you instead wish to provide your own keychain
+ * for storing them, this makes the TlsContext to use that instead.
+ * NOTE: The password of your keychain must be empty.
+ *
+ * NOTE: This only works on MacOS.
+ */
+ bool SetKeychainPath(ByteCursor &keychain_path) noexcept;
+
+ /**
+ * Initializes TlsContextOptions for mutual TLS (mTLS),
+ * using a client certificate in a Windows certificate store.
+ *
+ * NOTE: This only works on Windows.
+ *
+ * @param windowsCertStorePath Path to certificate in a Windows certificate store.
+ * The path must use backslashes and end with the certificate's thumbprint.
+ * Example: `CurrentUser\MY\A11F8A9B5DF5B98BA3508FBCA575D09570E0D2C6`
+ * @param allocator The memory allocator to use.
+ */
+ static TlsContextOptions InitClientWithMtlsSystemPath(
+ const char *windowsCertStorePath,
+ Allocator *allocator = ApiAllocator()) noexcept;
+
+ /**
+ * @return true if alpn is supported by the underlying security provider, false
+ * otherwise.
+ */
+ static bool IsAlpnSupported() noexcept;
+
+ /**
+ * Sets the list of alpn protocols.
+ * @param alpnList: List of protocol names, delimited by ';'. This string must remain in memory for the
+ * lifetime of this object.
+ */
+ bool SetAlpnList(const char *alpnList) noexcept;
+
+ /**
+ * In client mode, this turns off x.509 validation. Don't do this unless you're testing.
+ * It's much better, to just override the default trust store and pass the self-signed
+ * certificate as the caFile argument.
+ *
+ * In server mode, this defaults to false. If you want to support mutual TLS from the server,
+ * you'll want to set this to true.
+ */
+ void SetVerifyPeer(bool verifyPeer) noexcept;
+
+ /**
+ * Sets the minimum TLS version allowed.
+ * @param minimumTlsVersion: The minimum TLS version.
+ */
+ void SetMinimumTlsVersion(aws_tls_versions minimumTlsVersion);
+
+ /**
+ * Sets the preferred TLS Cipher List
+ * @param cipher_pref: The preferred TLS cipher list.
+ */
+ void SetTlsCipherPreference(aws_tls_cipher_pref cipher_pref);
+
+ /**
+ * Overrides the default system trust store.
+ * @param caPath: Path to directory containing trusted certificates, which will overrides the
+ * default trust store. Only useful on Unix style systems where all anchors are stored in a directory
+ * (like /etc/ssl/certs). This string must remain in memory for the lifetime of this object.
+ * @param caFile: Path to file containing PEM armored chain of trusted CA certificates. This
+ * string must remain in memory for the lifetime of this object.
+ */
+ bool OverrideDefaultTrustStore(const char *caPath, const char *caFile) noexcept;
+
+ /**
+ * Overrides the default system trust store.
+ * @param ca: PEM armored chain of trusted CA certificates.
+ */
+ bool OverrideDefaultTrustStore(const ByteCursor &ca) noexcept;
+
+ /// @private
+ const aws_tls_ctx_options *GetUnderlyingHandle() const noexcept { return &m_options; }
+
+ private:
+ aws_tls_ctx_options m_options;
+ bool m_isInit;
+ };
+
+ /**
+ * Options for TLS, when using a PKCS#11 library for private key operations.
+ *
+ * @see TlsContextOptions::InitClientWithMtlsPkcs11()
+ */
+ class AWS_CRT_CPP_API TlsContextPkcs11Options final
+ {
+ public:
+ /**
+ * @param pkcs11Lib use this PKCS#11 library
+ * @param allocator Memory allocator to use.
+ */
+ TlsContextPkcs11Options(
+ const std::shared_ptr<Pkcs11Lib> &pkcs11Lib,
+ Allocator *allocator = ApiAllocator()) noexcept;
+
+ /**
+ * Use this PIN to log the user into the PKCS#11 token.
+ * Leave unspecified to log into a token with a "protected authentication path".
+ *
+ * @param pin PIN
+ */
+ void SetUserPin(const String &pin) noexcept;
+
+ /**
+ * Specify the slot ID containing a PKCS#11 token.
+ * If not specified, the token will be chosen based on other criteria (such as token label).
+ *
+ * @param id slot ID
+ */
+ void SetSlotId(const uint64_t id) noexcept;
+
+ /**
+ * Specify the label of the PKCS#11 token to use.
+ * If not specified, the token will be chosen based on other criteria (such as slot ID).
+ *
+ * @param label label of token
+ */
+ void SetTokenLabel(const String &label) noexcept;
+
+ /**
+ * Specify the label of the private key object on the PKCS#11 token.
+ * If not specified, the key will be chosen based on other criteria
+ * (such as being the only available private key on the token).
+ *
+ * @param label label of private key object
+ */
+ void SetPrivateKeyObjectLabel(const String &label) noexcept;
+
+ /**
+ * Use this X.509 certificate (file on disk).
+ * The certificate may be specified by other means instead (ex: SetCertificateFileContents())
+ *
+ * @param path path to PEM-formatted certificate file on disk.
+ */
+ void SetCertificateFilePath(const String &path) noexcept;
+
+ /**
+ * Use this X.509 certificate (contents in memory).
+ * The certificate may be specified by other means instead (ex: SetCertificateFilePath())
+ *
+ * @param contents contents of PEM-formatted certificate file.
+ */
+ void SetCertificateFileContents(const String &contents) noexcept;
+
+ /// @private
+ aws_tls_ctx_pkcs11_options GetUnderlyingHandle() const noexcept;
+
+ private:
+ std::shared_ptr<Pkcs11Lib> m_pkcs11Lib;
+ Optional<uint64_t> m_slotId;
+ Optional<String> m_userPin;
+ Optional<String> m_tokenLabel;
+ Optional<String> m_privateKeyObjectLabel;
+ Optional<String> m_certificateFilePath;
+ Optional<String> m_certificateFileContents;
+ };
+
+ /**
+ * Options specific to a single connection.
+ */
+ class AWS_CRT_CPP_API TlsConnectionOptions final
+ {
+ public:
+ TlsConnectionOptions() noexcept;
+ ~TlsConnectionOptions();
+ TlsConnectionOptions(const TlsConnectionOptions &) noexcept;
+ TlsConnectionOptions &operator=(const TlsConnectionOptions &) noexcept;
+ TlsConnectionOptions(TlsConnectionOptions &&options) noexcept;
+ TlsConnectionOptions &operator=(TlsConnectionOptions &&options) noexcept;
+
+ /**
+ * Sets SNI extension, and also the name used for X.509 validation. serverName is copied.
+ *
+ * @return true if the copy succeeded, or false otherwise.
+ */
+ bool SetServerName(ByteCursor &serverName) noexcept;
+
+ /**
+ * Sets list of protocols (semi-colon delimited in priority order) used for ALPN extension.
+ * alpnList is copied.
+ *
+ * @return true if the copy succeeded, or false otherwise.
+ */
+ bool SetAlpnList(const char *alpnList) noexcept;
+
+ /**
+ * @return true if the instance is in a valid state, false otherwise.
+ */
+ explicit operator bool() const noexcept { return isValid(); }
+
+ /**
+ * @return the value of the last aws error encountered by operations on this instance.
+ */
+ int LastError() const noexcept { return m_lastError; }
+
+ /// @private
+ const aws_tls_connection_options *GetUnderlyingHandle() const noexcept
+ {
+ return &m_tls_connection_options;
+ }
+
+ private:
+ bool isValid() const noexcept { return m_isInit; }
+
+ TlsConnectionOptions(aws_tls_ctx *ctx, Allocator *allocator) noexcept;
+ aws_tls_connection_options m_tls_connection_options;
+ aws_allocator *m_allocator;
+ int m_lastError;
+ bool m_isInit;
+
+ friend class TlsContext;
+ };
+
+ /**
+ * Stateful context for TLS with a given configuration. Per-connection TLS "contexts"
+ * (TlsConnectionOptions) are instantiated from this as needed.
+ */
+ class AWS_CRT_CPP_API TlsContext final
+ {
+ public:
+ TlsContext() noexcept;
+ TlsContext(TlsContextOptions &options, TlsMode mode, Allocator *allocator = ApiAllocator()) noexcept;
+ ~TlsContext() = default;
+ TlsContext(const TlsContext &) noexcept = default;
+ TlsContext &operator=(const TlsContext &) noexcept = default;
+ TlsContext(TlsContext &&) noexcept = default;
+ TlsContext &operator=(TlsContext &&) noexcept = default;
+
+ /**
+ * @return a new connection-specific TLS context that can be configured with per-connection options
+ * (server name, peer verification, etc...)
+ */
+ TlsConnectionOptions NewConnectionOptions() const noexcept;
+
+ /**
+ * @return true if the instance is in a valid state, false otherwise.
+ */
+ explicit operator bool() const noexcept { return isValid(); }
+
+ /**
+ * @return the value of the last aws error encountered by operations on this instance.
+ */
+ int GetInitializationError() const noexcept { return m_initializationError; }
+
+ /// @private
+ aws_tls_ctx *GetUnderlyingHandle() const noexcept { return m_ctx.get(); }
+
+ private:
+ bool isValid() const noexcept { return m_ctx && m_initializationError == AWS_ERROR_SUCCESS; }
+
+ std::shared_ptr<aws_tls_ctx> m_ctx;
+ int m_initializationError;
+ };
+
+ using NewTlsContextImplCallback = std::function<void *(TlsContextOptions &, TlsMode, Allocator *)>;
+ using DeleteTlsContextImplCallback = std::function<void(void *)>;
+ using IsTlsAlpnSupportedCallback = std::function<bool()>;
+
+ /**
+ * BYO_CRYPTO: TLS channel-handler base class.
+ */
+ class AWS_CRT_CPP_API TlsChannelHandler : public ChannelHandler
+ {
+ public:
+ virtual ~TlsChannelHandler();
+
+ /**
+ * @return negotiated protocol (or empty string if no agreed upon protocol)
+ */
+ virtual String GetProtocol() const = 0;
+
+ protected:
+ TlsChannelHandler(
+ struct aws_channel_slot *slot,
+ const struct aws_tls_connection_options &options,
+ Allocator *allocator = ApiAllocator());
+
+ /**
+ * Invoke this function from inside your handler after TLS negotiation completes. errorCode ==
+ * AWS_ERROR_SUCCESS or 0 means the session was successfully established and the connection should
+ * continue on.
+ */
+ void CompleteTlsNegotiation(int errorCode);
+
+ private:
+ aws_tls_on_negotiation_result_fn *m_OnNegotiationResult;
+ void *m_userData;
+
+ aws_byte_buf m_protocolByteBuf;
+ friend aws_byte_buf(::aws_tls_handler_protocol)(aws_channel_handler *);
+ };
+
+ /**
+ * BYO_CRYPTO: Client TLS channel-handler base class.
+ *
+ * If using BYO_CRYPTO, you must define a concrete implementation
+ * and set its creation callback via ApiHandle.SetBYOCryptoClientTlsCallback().
+ */
+ class AWS_CRT_CPP_API ClientTlsChannelHandler : public TlsChannelHandler
+ {
+ public:
+ /**
+ * Initiates the TLS session negotiation. This is called by the common runtime when it's time to start
+ * a new session.
+ */
+ virtual void StartNegotiation() = 0;
+
+ protected:
+ ClientTlsChannelHandler(
+ struct aws_channel_slot *slot,
+ const struct aws_tls_connection_options &options,
+ Allocator *allocator = ApiAllocator());
+ };
+
+ using NewClientTlsHandlerCallback = std::function<std::shared_ptr<ClientTlsChannelHandler>(
+ struct aws_channel_slot *slot,
+ const struct aws_tls_connection_options &options,
+ Allocator *allocator)>;
+
+ } // namespace Io
+ } // namespace Crt
+} // namespace Aws
diff --git a/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/io/Uri.h b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/io/Uri.h
new file mode 100644
index 0000000000..80833f2b12
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/io/Uri.h
@@ -0,0 +1,102 @@
+#pragma once
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+#include <aws/crt/Types.h>
+
+#include <aws/io/uri.h>
+
+namespace Aws
+{
+ namespace Crt
+ {
+ namespace Io
+ {
+ /**
+ * Contains a URI used for networking application protocols. This type is move-only.
+ */
+ class AWS_CRT_CPP_API Uri final
+ {
+ public:
+ Uri() noexcept;
+ ~Uri();
+
+ /**
+ * Parses `cursor` as a URI. Upon failure the bool() operator will return false and LastError()
+ * will contain the errorCode.
+ */
+ Uri(const ByteCursor &cursor, Allocator *allocator = ApiAllocator()) noexcept;
+
+ /**
+ * Builds a URI from `builderOptions`. Upon failure the bool() operator will return false and
+ * LastError() will contain the errorCode.
+ */
+ Uri(aws_uri_builder_options &builderOptions, Allocator *allocator = ApiAllocator()) noexcept;
+
+ Uri(const Uri &);
+ Uri &operator=(const Uri &);
+ Uri(Uri &&uri) noexcept;
+ Uri &operator=(Uri &&) noexcept;
+
+ /**
+ * @return true if the instance is in a valid state, false otherwise.
+ */
+ operator bool() const noexcept { return m_isInit; }
+
+ /**
+ * @return the value of the last aws error encountered by operations on this instance.
+ */
+ int LastError() const noexcept { return m_lastError; }
+
+ /**
+ * @return the scheme portion of the URI if present (e.g. https, http, ftp etc....)
+ */
+ ByteCursor GetScheme() const noexcept;
+
+ /**
+ * @return the authority portion of the URI if present. This will contain host name and port if
+ * specified.
+ * */
+ ByteCursor GetAuthority() const noexcept;
+
+ /**
+ * @return the path portion of the URI. If no path was present, this will be set to '/'.
+ */
+ ByteCursor GetPath() const noexcept;
+
+ /**
+ * @return the query string portion of the URI if present.
+ */
+ ByteCursor GetQueryString() const noexcept;
+
+ /**
+ * @return the host name portion of the authority. (port will not be in this value).
+ */
+ ByteCursor GetHostName() const noexcept;
+
+ /**
+ * @return the port portion of the authority if a port was specified. If it was not, this will
+ * be set to 0. In that case, it is your responsibility to determine the correct port
+ * based on the protocol you're using.
+ */
+ uint16_t GetPort() const noexcept;
+
+ /** @return the Path and Query portion of the URI. In the case of Http, this likely the value for the
+ * URI parameter.
+ */
+ ByteCursor GetPathAndQuery() const noexcept;
+
+ /**
+ * @return The full URI as it was passed to or parsed from the constructors.
+ */
+ ByteCursor GetFullUri() const noexcept;
+
+ private:
+ aws_uri m_uri;
+ int m_lastError;
+ bool m_isInit;
+ };
+ } // namespace Io
+ } // namespace Crt
+} // namespace Aws
diff --git a/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/mqtt/Mqtt5Client.h b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/mqtt/Mqtt5Client.h
new file mode 100644
index 0000000000..9968920197
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/mqtt/Mqtt5Client.h
@@ -0,0 +1,770 @@
+#pragma once
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+#include <aws/crt/http/HttpConnection.h>
+#include <aws/crt/mqtt/Mqtt5Types.h>
+
+namespace Aws
+{
+ namespace Crt
+ {
+ namespace Mqtt5
+ {
+ class ConnectPacket;
+ class ConnAckPacket;
+ class DisconnectPacket;
+ class Mqtt5Client;
+ class Mqtt5ClientOptions;
+ class NegotiatedSettings;
+ class PublishResult;
+ class PublishPacket;
+ class PubAckPacket;
+ class SubscribePacket;
+ class SubAckPacket;
+ class UnsubscribePacket;
+ class UnSubAckPacket;
+
+ struct AWS_CRT_CPP_API ReconnectOptions
+ {
+ /**
+ * Controls how the reconnect delay is modified in order to smooth out the distribution of reconnection
+ * attempt timepoints for a large set of reconnecting clients.
+ */
+ JitterMode m_reconnectMode;
+
+ /**
+ * Minimum amount of time to wait to reconnect after a disconnect. Exponential backoff is performed
+ * with jitter after each connection failure.
+ */
+ uint64_t m_minReconnectDelayMs;
+
+ /**
+ * Maximum amount of time to wait to reconnect after a disconnect. Exponential backoff is performed
+ * with jitter after each connection failure.
+ */
+ uint64_t m_maxReconnectDelayMs;
+
+ /**
+ * Amount of time that must elapse with an established connection before the reconnect delay is reset to
+ * the minimum. This helps alleviate bandwidth-waste in fast reconnect cycles due to permission failures
+ * on operations.
+ */
+ uint64_t m_minConnectedTimeToResetReconnectDelayMs;
+ };
+
+ /* Simple statistics about the current state of the client's queue of operations */
+ struct AWS_CRT_CPP_API Mqtt5ClientOperationStatistics
+ {
+ /*
+ * total number of operations submitted to the client that have not yet been completed. Unacked
+ * operations are a subset of this.
+ */
+ uint64_t incompleteOperationCount;
+
+ /*
+ * total packet size of operations submitted to the client that have not yet been completed. Unacked
+ * operations are a subset of this.
+ */
+ uint64_t incompleteOperationSize;
+
+ /*
+ * total number of operations that have been sent to the server and are waiting for a corresponding ACK
+ * before they can be completed.
+ */
+ uint64_t unackedOperationCount;
+
+ /*
+ * total packet size of operations that have been sent to the server and are waiting for a corresponding
+ * ACK before they can be completed.
+ */
+ uint64_t unackedOperationSize;
+ };
+
+ /**
+ * The data returned when AttemptingConnect is invoked in the LifecycleEvents callback.
+ * Currently empty, but may be used in the future for passing additional data.
+ */
+ struct AWS_CRT_CPP_API OnAttemptingConnectEventData
+ {
+ OnAttemptingConnectEventData() {}
+ };
+
+ /**
+ * The data returned when OnConnectionFailure is invoked in the LifecycleEvents callback.
+ */
+ struct AWS_CRT_CPP_API OnConnectionFailureEventData
+ {
+ OnConnectionFailureEventData() : errorCode(AWS_ERROR_SUCCESS), connAckPacket(nullptr) {}
+
+ int errorCode;
+ std::shared_ptr<ConnAckPacket> connAckPacket;
+ };
+
+ /**
+ * The data returned when OnConnectionSuccess is invoked in the LifecycleEvents callback.
+ */
+ struct AWS_CRT_CPP_API OnConnectionSuccessEventData
+ {
+ OnConnectionSuccessEventData() : connAckPacket(nullptr), negotiatedSettings(nullptr) {}
+
+ std::shared_ptr<ConnAckPacket> connAckPacket;
+ std::shared_ptr<NegotiatedSettings> negotiatedSettings;
+ };
+
+ /**
+ * The data returned when OnDisconnect is invoked in the LifecycleEvents callback.
+ */
+ struct AWS_CRT_CPP_API OnDisconnectionEventData
+ {
+ OnDisconnectionEventData() : errorCode(AWS_ERROR_SUCCESS), disconnectPacket(nullptr) {}
+
+ int errorCode;
+ std::shared_ptr<DisconnectPacket> disconnectPacket;
+ };
+
+ /**
+ * The data returned when OnStopped is invoked in the LifecycleEvents callback.
+ * Currently empty, but may be used in the future for passing additional data.
+ */
+ struct AWS_CRT_CPP_API OnStoppedEventData
+ {
+ OnStoppedEventData() {}
+ };
+
+ /**
+ * The data returned when a publish is made to a topic the MQTT5 client is subscribed to.
+ */
+ struct AWS_CRT_CPP_API PublishReceivedEventData
+ {
+ PublishReceivedEventData() : publishPacket(nullptr) {}
+ std::shared_ptr<PublishPacket> publishPacket;
+ };
+
+ /**
+ * Type signature of the callback invoked when connection succeed
+ * Mandatory event fields: client, connack_data, settings
+ */
+ using OnConnectionSuccessHandler = std::function<void(Mqtt5Client &, const OnConnectionSuccessEventData &)>;
+
+ /**
+ * Type signature of the callback invoked when connection failed
+ */
+ using OnConnectionFailureHandler = std::function<void(Mqtt5Client &, const OnConnectionFailureEventData &)>;
+
+ /**
+ * Type signature of the callback invoked when the internal connection is shutdown
+ */
+ using OnDisconnectionHandler = std::function<void(Mqtt5Client &, const OnDisconnectionEventData &)>;
+
+ /**
+ * Type signature of the callback invoked when attempting connect to client
+ * Mandatory event fields: client
+ */
+ using OnAttemptingConnectHandler = std::function<void(Mqtt5Client &, const OnAttemptingConnectEventData &)>;
+
+ /**
+ * Type signature of the callback invoked when client connection stopped
+ * Mandatory event fields: client
+ */
+ using OnStoppedHandler = std::function<void(Mqtt5Client &, const OnStoppedEventData &)>;
+
+ /**
+ * Type signature of the callback invoked when a Disconnection Comlete
+ *
+ */
+ using OnDisconnectCompletionHandler = std::function<void(std::shared_ptr<Mqtt5Client>, int)>;
+
+ /**
+ * Type signature of the callback invoked when a Publish Complete
+ */
+ using OnPublishCompletionHandler =
+ std::function<void(std::shared_ptr<Mqtt5Client>, int, std::shared_ptr<PublishResult>)>;
+
+ /**
+ * Type signature of the callback invoked when a Subscribe Complete
+ */
+ using OnSubscribeCompletionHandler =
+ std::function<void(std::shared_ptr<Mqtt5Client>, int, std::shared_ptr<SubAckPacket>)>;
+
+ /**
+ * Type signature of the callback invoked when a Unsubscribe Complete
+ */
+ using OnUnsubscribeCompletionHandler =
+ std::function<void(std::shared_ptr<Mqtt5Client>, int, std::shared_ptr<UnSubAckPacket>)>;
+
+ /**
+ * Type signature of the callback invoked when a PacketPublish message received (OnMessageHandler)
+ */
+ using OnPublishReceivedHandler = std::function<void(Mqtt5Client &, const PublishReceivedEventData &)>;
+
+ /**
+ * Callback for users to invoke upon completion of, presumably asynchronous, OnWebSocketHandshakeIntercept
+ * callback's initiated process.
+ */
+ using OnWebSocketHandshakeInterceptComplete =
+ std::function<void(const std::shared_ptr<Http::HttpRequest> &, int)>;
+
+ /**
+ * Invoked during websocket handshake to give users opportunity to transform an http request for purposes
+ * such as signing/authorization etc... Returning from this function does not continue the websocket
+ * handshake since some work flows may be asynchronous. To accommodate that, onComplete must be invoked upon
+ * completion of the signing process.
+ */
+ using OnWebSocketHandshakeIntercept =
+ std::function<void(std::shared_ptr<Http::HttpRequest>, const OnWebSocketHandshakeInterceptComplete &)>;
+
+ /**
+ * An MQTT5 client. This is a move-only type. Unless otherwise specified,
+ * all function arguments need only to live through the duration of the
+ * function call.
+ */
+ class AWS_CRT_CPP_API Mqtt5Client final : public std::enable_shared_from_this<Mqtt5Client>
+ {
+ public:
+ /**
+ * Factory function for mqtt5 client
+ *
+ * @param options: Mqtt5 Client Options
+ * @param allocator allocator to use
+ * @return a new mqtt5 client
+ */
+ static std::shared_ptr<Mqtt5Client> NewMqtt5Client(
+ const Mqtt5ClientOptions &options,
+ Allocator *allocator = ApiAllocator()) noexcept;
+
+ /**
+ * Get shared poitner of the Mqtt5Client. Mqtt5Client is inherited to enable_shared_from_this to help
+ * with memory safety.
+ *
+ * @return shared_ptr for the Mqtt5Client
+ */
+ std::shared_ptr<Mqtt5Client> getptr() { return shared_from_this(); }
+
+ /**
+ * @return true if the instance is in a valid state, false otherwise.
+ */
+ operator bool() const noexcept;
+
+ /**
+ * @return the value of the last aws error encountered by operations on this instance.
+ */
+ int LastError() const noexcept;
+
+ /**
+ * Notifies the MQTT5 client that you want it to attempt to connect to the configured endpoint.
+ * The client will attempt to stay connected using the properties of the reconnect-related parameters
+ * from the client configuration.
+ *
+ * @return bool: true if operation succeed, otherwise false.
+ */
+ bool Start() const noexcept;
+
+ /**
+ * Notifies the MQTT5 client that you want it to transition to the stopped state, disconnecting any
+ * existing connection and stopping subsequent reconnect attempts.
+ *
+ * @return bool: true if operation succeed, otherwise false
+ */
+ bool Stop() noexcept;
+
+ /**
+ * Notifies the MQTT5 client that you want it to transition to the stopped state, disconnecting any
+ * existing connection and stopping subsequent reconnect attempts.
+ *
+ * @param disconnectOptions (optional) properties of a DISCONNECT packet to send as part of the shutdown
+ * process
+ *
+ * @return bool: true if operation succeed, otherwise false
+ */
+ bool Stop(std::shared_ptr<DisconnectPacket> disconnectOptions) noexcept;
+
+ /**
+ * Tells the client to attempt to send a PUBLISH packet
+ *
+ * @param publishOptions: packet PUBLISH to send to the server
+ * @param onPublishCompletionCallback: callback on publish complete, default to NULL
+ *
+ * @return true if the publish operation succeed otherwise false
+ */
+ bool Publish(
+ std::shared_ptr<PublishPacket> publishOptions,
+ OnPublishCompletionHandler onPublishCompletionCallback = NULL) noexcept;
+
+ /**
+ * Tells the client to attempt to subscribe to one or more topic filters.
+ *
+ * @param subscribeOptions: SUBSCRIBE packet to send to the server
+ * @param onSubscribeCompletionCallback: callback on subscribe complete, default to NULL
+ *
+ * @return true if the subscription operation succeed otherwise false
+ */
+ bool Subscribe(
+ std::shared_ptr<SubscribePacket> subscribeOptions,
+ OnSubscribeCompletionHandler onSubscribeCompletionCallback = NULL) noexcept;
+
+ /**
+ * Tells the client to attempt to unsubscribe to one or more topic filters.
+ *
+ * @param unsubscribeOptions: UNSUBSCRIBE packet to send to the server
+ * @param onUnsubscribeCompletionCallback: callback on unsubscribe complete, default to NULL
+ *
+ * @return true if the unsubscription operation succeed otherwise false
+ */
+ bool Unsubscribe(
+ std::shared_ptr<UnsubscribePacket> unsubscribeOptions,
+ OnUnsubscribeCompletionHandler onUnsubscribeCompletionCallback = NULL) noexcept;
+
+ /**
+ * Get the statistics about the current state of the client's queue of operations
+ *
+ * @return Mqtt5ClientOperationStatistics
+ */
+ const Mqtt5ClientOperationStatistics &GetOperationStatistics() noexcept;
+
+ virtual ~Mqtt5Client();
+
+ private:
+ Mqtt5Client(const Mqtt5ClientOptions &options, Allocator *allocator = ApiAllocator()) noexcept;
+
+ /* Static Callbacks */
+ static void s_publishCompletionCallback(
+ enum aws_mqtt5_packet_type packet_type,
+ const void *packet,
+ int error_code,
+ void *complete_ctx);
+
+ static void s_subscribeCompletionCallback(
+ const struct aws_mqtt5_packet_suback_view *puback,
+ int error_code,
+ void *complete_ctx);
+
+ static void s_unsubscribeCompletionCallback(
+ const struct aws_mqtt5_packet_unsuback_view *puback,
+ int error_code,
+ void *complete_ctx);
+
+ static void s_lifeCycleEventCallback(const aws_mqtt5_client_lifecycle_event *event);
+
+ static void s_publishReceivedCallback(const aws_mqtt5_packet_publish_view *publish, void *user_data);
+
+ static void s_onWebsocketHandshake(
+ aws_http_message *rawRequest,
+ void *user_data,
+ aws_mqtt5_transform_websocket_handshake_complete_fn *complete_fn,
+ void *complete_ctx);
+
+ static void s_clientTerminationCompletion(void *complete_ctx);
+
+ /* The handler is set by clientoptions */
+ OnWebSocketHandshakeIntercept websocketInterceptor;
+ /**
+ * Callback handler trigged when client successfully establishes an MQTT connection
+ */
+ OnConnectionSuccessHandler onConnectionSuccess;
+
+ /**
+ * Callback handler trigged when client fails to establish an MQTT connection
+ */
+ OnConnectionFailureHandler onConnectionFailure;
+
+ /**
+ * Callback handler trigged when client's current MQTT connection is closed
+ */
+ OnDisconnectionHandler onDisconnection;
+
+ /**
+ * Callback handler trigged when client reaches the "Stopped" state
+ */
+ OnStoppedHandler onStopped;
+
+ /**
+ * Callback handler trigged when client begins an attempt to connect to the remote endpoint.
+ */
+ OnAttemptingConnectHandler onAttemptingConnect;
+
+ /**
+ * Callback handler trigged when an MQTT PUBLISH packet is received by the client
+ */
+ OnPublishReceivedHandler onPublishReceived;
+ aws_mqtt5_client *m_client;
+ Allocator *m_allocator;
+
+ Mqtt5ClientOperationStatistics m_operationStatistics;
+ std::condition_variable m_terminationCondition;
+ std::mutex m_terminationMutex;
+ bool m_terminationPredicate = false;
+ };
+
+ /**
+ * Configuration interface for mqtt5 clients
+ */
+ class AWS_CRT_CPP_API Mqtt5ClientOptions final
+ {
+
+ friend class Mqtt5Client;
+
+ public:
+ /**
+ * Default constructior of Mqtt5ClientOptions
+ */
+ Mqtt5ClientOptions(Crt::Allocator *allocator = ApiAllocator()) noexcept;
+
+ /**
+ * Sets host to connect to.
+ *
+ * @param hostname endpoint to connect to
+ *
+ * @return this option object
+ */
+ Mqtt5ClientOptions &withHostName(Crt::String hostname);
+
+ /**
+ * Set port to connect to
+ *
+ * @param port port to connect to
+ *
+ * @return this option object
+ */
+ Mqtt5ClientOptions &withPort(uint16_t port) noexcept;
+
+ /**
+ * Set booststrap for mqtt5 client
+ *
+ * @param bootStrap bootstrap used for mqtt5 client. The default ClientBootstrap see
+ * Aws::Crt::ApiHandle::GetOrCreateStaticDefaultClientBootstrap.
+ *
+ * @return this option object
+ */
+ Mqtt5ClientOptions &withBootstrap(Io::ClientBootstrap *bootStrap) noexcept;
+
+ /**
+ * Sets the aws socket options
+ *
+ * @param socketOptions Io::SocketOptions used to setup socket
+ *
+ * @return this option object
+ */
+ Mqtt5ClientOptions &withSocketOptions(Io::SocketOptions socketOptions) noexcept;
+
+ /**
+ * Sets the tls connection options
+ *
+ * @param tslOptions Io::TlsConnectionOptions
+ *
+ * @return this option object
+ */
+ Mqtt5ClientOptions &withTlsConnectionOptions(const Io::TlsConnectionOptions &tslOptions) noexcept;
+
+ /**
+ * Sets http proxy options.
+ *
+ * @param proxyOptions http proxy configuration for connection establishment
+ *
+ * @return this option object
+ */
+ Mqtt5ClientOptions &withHttpProxyOptions(
+ const Crt::Http::HttpClientConnectionProxyOptions &proxyOptions) noexcept;
+
+ /**
+ * Sets mqtt5 connection options
+ *
+ * @param packetConnect package connection options
+ *
+ * @return this option object
+ */
+ Mqtt5ClientOptions &withConnectOptions(std::shared_ptr<ConnectPacket> packetConnect) noexcept;
+
+ /**
+ * Sets session behavior. Overrides how the MQTT5 client should behave with respect to MQTT sessions.
+ *
+ * @param sessionBehavior
+ *
+ * @return this option object
+ */
+ Mqtt5ClientOptions &withSessionBehavior(ClientSessionBehaviorType sessionBehavior) noexcept;
+
+ /**
+ * Sets client extended validation and flow control, additional controls for client behavior with
+ * respect to operation validation and flow control; these checks go beyond the base MQTT5 spec to
+ * respect limits of specific MQTT brokers.
+ *
+ * @param clientExtendedValidationAndFlowControl
+ *
+ * @return this option object
+ */
+ Mqtt5ClientOptions &withClientExtendedValidationAndFlowControl(
+ ClientExtendedValidationAndFlowControl clientExtendedValidationAndFlowControl) noexcept;
+
+ /**
+ * Sets OfflineQueueBehavior, controls how disconnects affect the queued and in-progress operations
+ * tracked by the client. Also controls how new operations are handled while the client is not
+ * connected. In particular, if the client is not connected, then any operation that would be failed
+ * on disconnect (according to these rules) will also be rejected.
+ *
+ * @param offlineQueueBehavior
+ *
+ * @return this option object
+ */
+ Mqtt5ClientOptions &withOfflineQueueBehavior(
+ ClientOperationQueueBehaviorType offlineQueueBehavior) noexcept;
+
+ /**
+ * Sets ReconnectOptions. Reconnect options, includes retryJitterMode, min reconnect delay time and
+ * max reconnect delay time and reset reconnect delay time
+ *
+ * @param reconnectOptions
+ *
+ * @return this option object
+ */
+ Mqtt5ClientOptions &withReconnectOptions(ReconnectOptions reconnectOptions) noexcept;
+
+ /**
+ * Sets ping timeout (ms). Time interval to wait after sending a PINGREQ for a PINGRESP to arrive.
+ * If one does not arrive, the client will close the current connection.
+ *
+ * @param pingTimeoutMs
+ *
+ * @return this option object
+ */
+ Mqtt5ClientOptions &withPingTimeoutMs(uint32_t pingTimeoutMs) noexcept;
+
+ /**
+ * Sets Connack Timeout (ms). Time interval to wait after sending a CONNECT request for a CONNACK
+ * to arrive. If one does not arrive, the connection will be shut down.
+ *
+ * @param connackTimeoutMs
+ *
+ * @return this option object
+ */
+ Mqtt5ClientOptions &withConnackTimeoutMs(uint32_t connackTimeoutMs) noexcept;
+
+ /**
+ * Sets Operation Timeout(Seconds). Time interval to wait for an ack after sending a QoS 1+ PUBLISH,
+ * SUBSCRIBE, or UNSUBSCRIBE before failing the operation.
+ *
+ * @param ackTimeoutSeconds
+ *
+ * @return this option object
+ */
+ Mqtt5ClientOptions &withAckTimeoutSeconds(uint32_t ackTimeoutSeconds) noexcept;
+
+ /**
+ * Sets callback for transform HTTP request.
+ * This callback allows a custom transformation of the HTTP request that acts as the websocket
+ * handshake. Websockets will be used if this is set to a valid transformation callback. To use
+ * websockets but not perform a transformation, just set this as a trivial completion callback. If
+ * undefined, the connection will be made with direct MQTT.
+ *
+ * @param callback
+ *
+ * @return this option object
+ */
+ Mqtt5ClientOptions &withWebsocketHandshakeTransformCallback(
+ OnWebSocketHandshakeIntercept callback) noexcept;
+
+ /**
+ * Sets callback trigged when client successfully establishes an MQTT connection
+ *
+ * @param callback
+ *
+ * @return this option object
+ */
+ Mqtt5ClientOptions &withClientConnectionSuccessCallback(OnConnectionSuccessHandler callback) noexcept;
+
+ /**
+ * Sets callback trigged when client fails to establish an MQTT connection
+ *
+ * @param callback
+ *
+ * @return this option object
+ */
+ Mqtt5ClientOptions &withClientConnectionFailureCallback(OnConnectionFailureHandler callback) noexcept;
+
+ /**
+ * Sets callback trigged when client's current MQTT connection is closed
+ *
+ * @param callback
+ *
+ * @return this option object
+ */
+ Mqtt5ClientOptions &withClientDisconnectionCallback(OnDisconnectionHandler callback) noexcept;
+
+ /**
+ * Sets callback trigged when client reaches the "Stopped" state
+ *
+ * @param callback
+ *
+ * @return this option object
+ */
+ Mqtt5ClientOptions &withClientStoppedCallback(OnStoppedHandler callback) noexcept;
+
+ /**
+ * Sets callback trigged when client begins an attempt to connect to the remote endpoint.
+ *
+ * @param callback
+ *
+ * @return this option object
+ */
+ Mqtt5ClientOptions &withClientAttemptingConnectCallback(OnAttemptingConnectHandler callback) noexcept;
+
+ /**
+ * Sets callback trigged when a PUBLISH packet is received by the client
+ *
+ * @param callback
+ *
+ * @return this option object
+ */
+ Mqtt5ClientOptions &withPublishReceivedCallback(OnPublishReceivedHandler callback) noexcept;
+
+ /**
+ * Initializes the C aws_mqtt5_client_options from Mqtt5ClientOptions. For internal use
+ *
+ * @param raw_options - output parameter containing low level client options to be passed to the C
+ * interface
+ *
+ */
+ bool initializeRawOptions(aws_mqtt5_client_options &raw_options) const noexcept;
+
+ virtual ~Mqtt5ClientOptions();
+ Mqtt5ClientOptions(const Mqtt5ClientOptions &) = delete;
+ Mqtt5ClientOptions(Mqtt5ClientOptions &&) = delete;
+ Mqtt5ClientOptions &operator=(const Mqtt5ClientOptions &) = delete;
+ Mqtt5ClientOptions &operator=(Mqtt5ClientOptions &&) = delete;
+
+ private:
+ /**
+ * This callback allows a custom transformation of the HTTP request that acts as the websocket
+ * handshake. Websockets will be used if this is set to a valid transformation callback. To use
+ * websockets but not perform a transformation, just set this as a trivial completion callback. If
+ * undefined, the connection will be made with direct MQTT.
+ */
+ OnWebSocketHandshakeIntercept websocketHandshakeTransform;
+
+ /**
+ * Callback handler trigged when client successfully establishes an MQTT connection
+ */
+ OnConnectionSuccessHandler onConnectionSuccess;
+
+ /**
+ * Callback handler trigged when client fails to establish an MQTT connection
+ */
+ OnConnectionFailureHandler onConnectionFailure;
+
+ /**
+ * Callback handler trigged when client's current MQTT connection is closed
+ */
+ OnDisconnectionHandler onDisconnection;
+
+ /**
+ * Callback handler trigged when client reaches the "Stopped" state
+ *
+ * @param Mqtt5Client: The shared client
+ */
+ OnStoppedHandler onStopped;
+
+ /**
+ * Callback handler trigged when client begins an attempt to connect to the remote endpoint.
+ *
+ * @param Mqtt5Client: The shared client
+ */
+ OnAttemptingConnectHandler onAttemptingConnect;
+
+ /**
+ * Callback handler trigged when an MQTT PUBLISH packet is received by the client
+ *
+ * @param Mqtt5Client: The shared client
+ * @param PublishPacket: received Publish Packet
+ */
+ OnPublishReceivedHandler onPublishReceived;
+
+ /**
+ * Host name of the MQTT server to connect to.
+ */
+ Crt::String m_hostName;
+
+ /**
+ * Network port of the MQTT server to connect to.
+ */
+ uint16_t m_port;
+
+ /**
+ * Client bootstrap to use. In almost all cases, this can be left undefined.
+ */
+ Io::ClientBootstrap *m_bootstrap;
+
+ /**
+ * Controls socket properties of the underlying MQTT connections made by the client. Leave undefined to
+ * use defaults (no TCP keep alive, 10 second socket timeout).
+ */
+ Crt::Io::SocketOptions m_socketOptions;
+
+ /**
+ * TLS context for secure socket connections.
+ * If undefined, then a plaintext connection will be used.
+ */
+ Crt::Optional<Crt::Io::TlsConnectionOptions> m_tlsConnectionOptions;
+
+ /**
+ * Configures (tunneling) HTTP proxy usage when establishing MQTT connections
+ */
+ Crt::Optional<Crt::Http::HttpClientConnectionProxyOptions> m_proxyOptions;
+
+ /**
+ * All configurable options with respect to the CONNECT packet sent by the client, including the will.
+ * These connect properties will be used for every connection attempt made by the client.
+ */
+ std::shared_ptr<ConnectPacket> m_connectOptions;
+
+ /**
+ * Controls how the MQTT5 client should behave with respect to MQTT sessions.
+ */
+ ClientSessionBehaviorType m_sessionBehavior;
+
+ /**
+ * Additional controls for client behavior with respect to operation validation and flow control; these
+ * checks go beyond the base MQTT5 spec to respect limits of specific MQTT brokers.
+ */
+ ClientExtendedValidationAndFlowControl m_extendedValidationAndFlowControlOptions;
+
+ /**
+ * Controls how disconnects affect the queued and in-progress operations tracked by the client. Also
+ * controls how new operations are handled while the client is not connected. In particular, if the
+ * client is not connected, then any operation that would be failed on disconnect (according to these
+ * rules) will also be rejected.
+ */
+ ClientOperationQueueBehaviorType m_offlineQueueBehavior;
+
+ /**
+ * Reconnect options, includes retryJitterMode, min reconnect delay time and max reconnect delay time
+ */
+ ReconnectOptions m_reconnectionOptions;
+
+ /**
+ * Time interval to wait after sending a PINGREQ for a PINGRESP to arrive. If one does not arrive, the
+ * client will close the current connection.
+ */
+ uint32_t m_pingTimeoutMs;
+
+ /**
+ * Time interval to wait after sending a CONNECT request for a CONNACK to arrive. If one does not
+ * arrive, the connection will be shut down.
+ */
+ uint32_t m_connackTimeoutMs;
+
+ /**
+ * Time interval to wait for an ack after sending a QoS 1+ PUBLISH, SUBSCRIBE, or UNSUBSCRIBE before
+ * failing the operation.
+ */
+ uint32_t m_ackTimeoutSec;
+
+ /* Underlying Parameters */
+ Crt::Allocator *m_allocator;
+ aws_http_proxy_options m_httpProxyOptionsStorage;
+ aws_mqtt5_packet_connect_view m_packetConnectViewStorage;
+ };
+
+ } // namespace Mqtt5
+ } // namespace Crt
+} // namespace Aws
diff --git a/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/mqtt/Mqtt5Packets.h b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/mqtt/Mqtt5Packets.h
new file mode 100644
index 0000000000..9588d6e0ef
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/mqtt/Mqtt5Packets.h
@@ -0,0 +1,2286 @@
+#pragma once
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+
+#include <aws/crt/mqtt/Mqtt5Client.h>
+#include <aws/crt/mqtt/Mqtt5Packets.h>
+#include <aws/crt/mqtt/Mqtt5Types.h>
+
+namespace Aws
+{
+ namespace Crt
+ {
+ namespace Mqtt5
+ {
+
+ /**
+ * Data model for MQTT5 user properties.
+ *
+ * A user property is a name-value pair of utf-8 strings that can be added to mqtt5 packets.
+ */
+ class AWS_CRT_CPP_API UserProperty
+ {
+ public:
+ UserProperty(Crt::String key, Crt::String value) noexcept;
+
+ const Crt::String &getName() const noexcept { return m_name; };
+ const Crt::String &getValue() const noexcept { return m_value; }
+
+ ~UserProperty() noexcept;
+ UserProperty(const UserProperty &toCopy) noexcept;
+ UserProperty(UserProperty &&toMove) noexcept;
+ UserProperty &operator=(const UserProperty &toCopy) noexcept;
+ UserProperty &operator=(UserProperty &&toMove) noexcept;
+
+ private:
+ Crt::String m_name;
+ Crt::String m_value;
+ };
+
+ class AWS_CRT_CPP_API IPacket
+ {
+ public:
+ virtual PacketType getType() = 0;
+ };
+
+ /**
+ * Data model of an [MQTT5
+ * PUBLISH](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901100) packet
+ */
+ class AWS_CRT_CPP_API PublishPacket : public IPacket
+ {
+ public:
+ PublishPacket(
+ const aws_mqtt5_packet_publish_view &raw_options,
+ Allocator *allocator = ApiAllocator()) noexcept;
+ PublishPacket(Allocator *allocator = ApiAllocator()) noexcept;
+ PublishPacket(
+ Crt::String topic,
+ ByteCursor payload,
+ Mqtt5::QOS qos,
+ Allocator *allocator = ApiAllocator()) noexcept;
+ PacketType getType() override { return PacketType::AWS_MQTT5_PT_PUBLISH; };
+
+ /**
+ * Sets the payload for the publish message.
+ *
+ * See [MQTT5 Publish
+ * Payload](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901119)
+ *
+ * @param payload The payload for the publish message.
+ * @return The PublishPacket Object after setting the payload.
+ */
+ PublishPacket &withPayload(ByteCursor payload) noexcept;
+
+ /**
+ * Sets the MQTT quality of service level the message should be delivered with.
+ *
+ * See [MQTT5 QoS](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901103)
+ *
+ * @param packetQOS The MQTT quality of service level the message should be delivered with.
+ * @return The PublishPacket Object after setting the QOS.
+ */
+ PublishPacket &withQOS(Mqtt5::QOS packetQOS) noexcept;
+
+ /**
+ * Sets if this should be a retained message.
+ *
+ * See [MQTT5 Retain](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901104)
+ *
+ * @param retain if this is a retained message.
+ * @return The PublishPacket Object after setting the retain setting.
+ */
+ PublishPacket &withRetain(bool retain) noexcept;
+
+ /**
+ * Sets the topic this message should be published to.
+ * See [MQTT5 Topic Name](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901107)
+ *
+ * @param topic The topic this message should be published to.
+ * @return The PublishPacket Object after setting the topic.
+ */
+ PublishPacket &withTopic(Crt::String topic) noexcept;
+
+ /**
+ * Sets the property specifying the format of the payload data. The mqtt5 client does not enforce or use
+ * this value in a meaningful way.
+ *
+ * See [MQTT5 Payload Format
+ * Indicator](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901111)
+ *
+ * @param payloadFormat Property specifying the format of the payload data
+ * @return The PublishPacket Object after setting the payload format.
+ */
+ PublishPacket &withPayloadFormatIndicator(PayloadFormatIndicator payloadFormat) noexcept;
+
+ /**
+ * Sets the maximum amount of time allowed to elapse for message delivery before the server
+ * should instead delete the message (relative to a recipient).
+ *
+ * See [MQTT5 Message Expiry
+ * Interval](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901112)
+ *
+ * @param second The maximum amount of time allowed to elapse for message delivery
+ * before the server should instead delete the message (relative to a recipient).
+ * @return The PublishPacket Object after setting the message expiry interval.
+ */
+ PublishPacket &withMessageExpiryIntervalSec(uint32_t second) noexcept;
+
+ /**
+ * Sets the opaque topic string intended to assist with request/response implementations. Not
+ * internally meaningful to MQTT5 or this client.
+ *
+ * See [MQTT5 Response
+ * Topic](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901114)
+ * @param responseTopic
+ * @return The PublishPacket Object after setting the response topic.
+ */
+ PublishPacket &withResponseTopic(ByteCursor responseTopic) noexcept;
+
+ /**
+ * Sets the opaque binary data used to correlate between publish messages, as a potential method for
+ * request-response implementation. Not internally meaningful to MQTT5.
+ *
+ * See [MQTT5 Correlation
+ * Data](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901115)
+ *
+ * @param correlationData Opaque binary data used to correlate between publish messages
+ * @return The PublishPacket Object after setting the correlation data.
+ */
+ PublishPacket &withCorrelationData(ByteCursor correlationData) noexcept;
+
+ /**
+ * Sets the list of MQTT5 user properties included with the packet.
+ *
+ * See [MQTT5 User
+ * Property](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901116)
+ *
+ * @param userProperties List of MQTT5 user properties included with the packet.
+ * @return The PublishPacket Object after setting the user properties
+ */
+ PublishPacket &withUserProperties(const Vector<UserProperty> &userProperties) noexcept;
+
+ /**
+ * Sets the list of MQTT5 user properties included with the packet.
+ *
+ * See [MQTT5 User
+ * Property](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901116)
+ *
+ * @param userProperties List of MQTT5 user properties included with the packet.
+ * @return The PublishPacket Object after setting the user properties
+ */
+ PublishPacket &withUserProperties(Vector<UserProperty> &&userProperties) noexcept;
+
+ /**
+ * Put a MQTT5 user property to the back of the packet user property vector/list
+ *
+ * See [MQTT5 User
+ * Property](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901116)
+ *
+ * @param property set of userProperty of MQTT5 user properties included with the packet.
+ * @return The PublishPacket Object after setting the user property
+ */
+ PublishPacket &withUserProperty(UserProperty &&property) noexcept;
+
+ bool initializeRawOptions(aws_mqtt5_packet_publish_view &raw_options) noexcept;
+
+ /**
+ * The payload of the publish message.
+ *
+ * See [MQTT5 Publish
+ * Payload](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901119)
+ *
+ * @return The payload of the publish message.
+ */
+ const ByteCursor &getPayload() const noexcept;
+
+ /**
+ * Sent publishes - The MQTT quality of service level this message should be delivered with.
+ *
+ * Received publishes - The MQTT quality of service level this message was delivered at.
+ *
+ * See [MQTT5 QoS](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901103)
+ *
+ * @return The MQTT quality of service associated with this PUBLISH packet.
+ */
+ Mqtt5::QOS getQOS() const noexcept;
+
+ /**
+ * True if this is a retained message, false otherwise.
+ *
+ * Always set on received publishes.
+ *
+ * See [MQTT5 Retain](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901104)
+ *
+ * @return True if this is a retained message, false otherwise.
+ */
+ bool getRetain() const noexcept;
+
+ /**
+ * Sent publishes - The topic this message should be published to.
+ *
+ * Received publishes - The topic this message was published to.
+ *
+ * See [MQTT5 Topic Name](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901107)
+ * @return The topic associated with this PUBLISH packet.
+ */
+ const Crt::String &getTopic() const noexcept;
+
+ /**
+ * Property specifying the format of the payload data. The mqtt5 client does not enforce or use this
+ * value in a meaningful way.
+ *
+ * See [MQTT5 Payload Format
+ * Indicator](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901111)
+ *
+ * @return Property specifying the format of the payload data.
+ */
+ const Crt::Optional<PayloadFormatIndicator> &getPayloadFormatIndicator() const noexcept;
+
+ /**
+ * Sent publishes - indicates the maximum amount of time allowed to elapse for message delivery before
+ * the server should instead delete the message (relative to a recipient).
+ *
+ * Received publishes - indicates the remaining amount of time (from the server's perspective) before
+ * the message would have been deleted relative to the subscribing client.
+ *
+ * If left null, indicates no expiration timeout.
+ *
+ * See [MQTT5 Message Expiry
+ * Interval](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901112)
+ *
+ * @return The message expiry interval associated with this PUBLISH packet.
+ */
+ const Crt::Optional<uint32_t> &getMessageExpiryIntervalSec() const noexcept;
+
+ /**
+ * Opaque topic string intended to assist with request/response implementations. Not internally
+ * meaningful to MQTT5 or this client.
+ *
+ * See [MQTT5 Response
+ * Topic](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901114)
+ *
+ * @return ByteCursor to topic string intended to assist with request/response implementations.
+ */
+ const Crt::Optional<ByteCursor> &getResponseTopic() const noexcept;
+
+ /**
+ * Opaque binary data used to correlate between publish messages, as a potential method for
+ * request-response implementation. Not internally meaningful to MQTT5.
+ *
+ * See [MQTT5 Correlation
+ * Data](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901115)
+ *
+ * @return ByteCursor to opaque binary data used to correlate between publish messages.
+ */
+ const Crt::Optional<ByteCursor> &getCorrelationData() const noexcept;
+
+ /**
+ * Sent publishes - ignored
+ *
+ * Received publishes - the subscription identifiers of all the subscriptions this message matched.
+ *
+ * See [MQTT5 Subscription
+ * Identifier](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901117)
+ *
+ * @return the subscription identifiers of all the subscriptions this message matched.
+ */
+ const Crt::Vector<uint32_t> &getSubscriptionIdentifiers() const noexcept;
+
+ /**
+ * Property specifying the content type of the payload. Not internally meaningful to MQTT5.
+ *
+ * See [MQTT5 Content Type](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901118)
+ *
+ * @return ByteCursor to opaque binary data to the content type of the payload.
+ */
+ const Crt::Optional<ByteCursor> &getContentType() const noexcept;
+
+ /**
+ * List of MQTT5 user properties included with the packet.
+ *
+ * See [MQTT5 User
+ * Property](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901116)
+ *
+ * @return List of MQTT5 user properties included with the packet.
+ */
+ const Crt::Vector<UserProperty> &getUserProperties() const noexcept;
+
+ virtual ~PublishPacket();
+ PublishPacket(const PublishPacket &) = delete;
+ PublishPacket(PublishPacket &&) noexcept = delete;
+ PublishPacket &operator=(const PublishPacket &) = delete;
+ PublishPacket &operator=(PublishPacket &&) noexcept = delete;
+
+ private:
+ Allocator *m_allocator;
+
+ /**
+ * The payload of the publish message.
+ *
+ * See [MQTT5 Publish
+ * Payload](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901119)
+ */
+ ByteCursor m_payload;
+
+ /**
+ * Sent publishes - The MQTT quality of service level this message should be delivered with.
+ *
+ * Received publishes - The MQTT quality of service level this message was delivered at.
+ *
+ * See [MQTT5 QoS](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901103)
+ */
+ Mqtt5::QOS m_qos;
+
+ /**
+ * True if this is a retained message, false otherwise.
+ *
+ * Always set on received publishes, default to false
+ *
+ * See [MQTT5 Retain](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901104)
+ */
+ bool m_retain;
+
+ /**
+ * Sent publishes - The topic this message should be published to.
+ *
+ * Received publishes - The topic this message was published to.
+ *
+ * See [MQTT5 Topic Name](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901107)
+ */
+ Crt::String m_topicName;
+
+ /**
+ * Property specifying the format of the payload data. The mqtt5 client does not enforce or use this
+ * value in a meaningful way.
+ *
+ * See [MQTT5 Payload Format
+ * Indicator](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901111)
+ */
+ Crt::Optional<PayloadFormatIndicator> m_payloadFormatIndicator;
+
+ /**
+ * Sent publishes - indicates the maximum amount of time allowed to elapse for message delivery before
+ * the server should instead delete the message (relative to a recipient).
+ *
+ * Received publishes - indicates the remaining amount of time (from the server's perspective) before
+ * the message would have been deleted relative to the subscribing client.
+ *
+ * If left undefined, indicates no expiration timeout.
+ *
+ * See [MQTT5 Message Expiry
+ * Interval](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901112)
+ */
+ Crt::Optional<uint32_t> m_messageExpiryIntervalSec;
+
+ /**
+ * Opaque topic string intended to assist with request/response implementations. Not internally
+ * meaningful to MQTT5 or this client.
+ *
+ * See [MQTT5 Response
+ * Topic](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901114)
+ */
+ Crt::Optional<ByteCursor> m_responseTopic;
+
+ /**
+ * Opaque binary data used to correlate between publish messages, as a potential method for
+ * request-response implementation. Not internally meaningful to MQTT5.
+ *
+ * See [MQTT5 Correlation
+ * Data](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901115)
+ */
+ Crt::Optional<ByteCursor> m_correlationData;
+
+ /**
+ * Set of MQTT5 user properties included with the packet.
+ *
+ * See [MQTT5 User
+ * Property](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901116)
+ */
+ Crt::Vector<UserProperty> m_userProperties;
+
+ ///////////////////////////////////////////////////////////////////////////
+ // The following parameters are ignored when building publish operations */
+ ///////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Sent publishes - ignored
+ *
+ * Received publishes - the subscription identifiers of all the subscriptions this message matched.
+ *
+ * See [MQTT5 Subscription
+ * Identifier](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901117)
+ */
+ Crt::Vector<uint32_t> m_subscriptionIdentifiers;
+
+ /**
+ * Property specifying the content type of the payload. Not internally meaningful to MQTT5.
+ *
+ * See [MQTT5 Content Type](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901118)
+ */
+ Crt::Optional<ByteCursor> m_contentType;
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Underlying data storage for internal use
+ ///////////////////////////////////////////////////////////////////////////
+ ByteBuf m_payloadStorage;
+ ByteBuf m_contentTypeStorage;
+ ByteBuf m_correlationDataStorage;
+ Crt::String m_responseTopicString;
+ struct aws_mqtt5_user_property *m_userPropertiesStorage;
+ };
+
+ /**
+ * Mqtt behavior settings that are dynamically negotiated as part of the CONNECT/CONNACK exchange.
+ *
+ * While you can infer all of these values from a combination of
+ * (1) defaults as specified in the mqtt5 spec
+ * (2) your CONNECT settings
+ * (3) the CONNACK from the broker
+ *
+ * the client instead does the combining for you and emits a NegotiatedSettings object with final,
+ * authoritative values.
+ *
+ * Negotiated settings are communicated with every successful connection establishment.
+ */
+ class AWS_CRT_CPP_API NegotiatedSettings
+ {
+ public:
+ NegotiatedSettings(
+ const aws_mqtt5_negotiated_settings &negotiated_settings,
+
+ Allocator *allocator = ApiAllocator()) noexcept;
+
+ /**
+ * @return The maximum QoS allowed for publishes on this connection instance
+ */
+ Mqtt5::QOS getMaximumQOS() const noexcept;
+
+ /**
+ * @return The amount of time in seconds the server will retain the MQTT session after a disconnect.
+ */
+ uint32_t getSessionExpiryIntervalSec() const noexcept;
+
+ /**
+ * @return The number of in-flight QoS 1 and QoS 2 publications the server is willing to process
+ * concurrently.
+ */
+ uint16_t getReceiveMaximumFromServer() const noexcept;
+
+ /**
+ * @return The maximum packet size the server is willing to accept.
+ */
+ uint32_t getMaximumPacketSizeBytes() const noexcept;
+
+ /**
+ * The maximum amount of time in seconds between client packets. The client should use PINGREQs to
+ * ensure this limit is not breached. The server will disconnect the client for inactivity if no MQTT
+ * packet is received in a time interval equal to 1.5 x this value.
+ *
+ * @return The maximum amount of time in seconds between client packets.
+ */
+ uint16_t getServerKeepAlive() const noexcept;
+
+ /**
+ * @return Whether the server supports retained messages.
+ */
+ bool getRetainAvailable() const noexcept;
+
+ /**
+ * @return Whether the server supports wildcard subscriptions.
+ */
+ bool getWildcardSubscriptionsAvaliable() const noexcept;
+
+ /**
+ * @return Whether the server supports subscription identifiers
+ */
+ bool getSubscriptionIdentifiersAvaliable() const noexcept;
+
+ /**
+ * @return Whether the server supports shared subscriptions
+ */
+ bool getSharedSubscriptionsAvaliable() const noexcept;
+
+ /**
+ * @return Whether the client has rejoined an existing session.
+ */
+ bool getRejoinedSession() const noexcept;
+
+ /**
+ * The final client id in use by the newly-established connection. This will be the configured client
+ * id if one was given in the configuration, otherwise, if no client id was specified, this will be the
+ * client id assigned by the server. Reconnection attempts will always use the auto-assigned client id,
+ * allowing for auto-assigned session resumption.
+ *
+ * @return The final client id in use by the newly-established connection
+ */
+ const Crt::String &getClientId() const noexcept;
+
+ virtual ~NegotiatedSettings(){};
+ NegotiatedSettings(const NegotiatedSettings &) = delete;
+ NegotiatedSettings(NegotiatedSettings &&) noexcept = delete;
+ NegotiatedSettings &operator=(const NegotiatedSettings &) = delete;
+ NegotiatedSettings &operator=(NegotiatedSettings &&) noexcept = delete;
+
+ private:
+ /**
+ * The maximum QoS allowed for publishes on this connection instance
+ */
+ Mqtt5::QOS m_maximumQOS;
+
+ /**
+ * The amount of time in seconds the server will retain the MQTT session after a disconnect.
+ */
+ uint32_t m_sessionExpiryIntervalSec;
+
+ /**
+ * The number of in-flight QoS 1 and QoS2 publications the server is willing to process concurrently.
+ */
+ uint16_t m_receiveMaximumFromServer;
+
+ /**
+ * The maximum packet size the server is willing to accept.
+ */
+ uint32_t m_maximumPacketSizeBytes;
+
+ /**
+ * The maximum amount of time in seconds between client packets. The client should use PINGREQs to
+ * ensure this limit is not breached. The server will disconnect the client for inactivity if no MQTT
+ * packet is received in a time interval equal to 1.5 x this value.
+ */
+ uint16_t m_serverKeepAliveSec;
+
+ /**
+ * Whether the server supports retained messages.
+ */
+ bool m_retainAvailable;
+
+ /**
+ * Whether the server supports wildcard subscriptions.
+ */
+ bool m_wildcardSubscriptionsAvaliable;
+
+ /**
+ * Whether the server supports subscription identifiers
+ */
+ bool m_subscriptionIdentifiersAvaliable;
+
+ /**
+ * Whether the server supports shared subscriptions
+ */
+ bool m_sharedSubscriptionsAvaliable;
+
+ /**
+ * Whether the client has rejoined an existing session.
+ */
+ bool m_rejoinedSession;
+
+ /**
+ * The final client id in use by the newly-established connection. This will be the configured client
+ * id if one was given in the configuration, otherwise, if no client id was specified, this will be the
+ * client id assigned by the server. Reconnection attempts will always use the auto-assigned client id,
+ * allowing for auto-assigned session resumption.
+ */
+ Crt::String m_clientId;
+ };
+
+ /**
+ * Data model of an [MQTT5
+ * CONNECT](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901033) packet.
+ */
+ class AWS_CRT_CPP_API ConnectPacket : public IPacket
+ {
+ public:
+ /* Default constructor */
+ ConnectPacket(Allocator *allocator = ApiAllocator()) noexcept;
+
+ /* The packet type */
+ PacketType getType() override { return PacketType::AWS_MQTT5_PT_CONNECT; };
+
+ /**
+ * Sets the maximum time interval, in seconds, that is permitted to elapse between the point at which
+ * the client finishes transmitting one MQTT packet and the point it starts sending the next. The
+ * client will use PINGREQ packets to maintain this property.
+ *
+ * If the responding CONNACK contains a keep alive property value, then that is the negotiated keep
+ * alive value. Otherwise, the keep alive sent by the client is the negotiated value.
+ *
+ * See [MQTT5 Keep Alive](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901045)
+ *
+ * NOTE: The keepAliveIntervalSeconds HAS to be larger than the pingTimeoutMs time set in the
+ * Mqtt5ClientOptions.
+ *
+ * @param keepAliveInteralSeconds the maximum time interval, in seconds, that is permitted to elapse
+ * between the point at which the client finishes transmitting one MQTT packet and the point it starts
+ * sending the next.
+ * @return The ConnectPacket Object after setting the keep alive interval.
+ */
+ ConnectPacket &withKeepAliveIntervalSec(uint16_t keepAliveInteralSeconds) noexcept;
+
+ /**
+ * Sets the unique string identifying the client to the server. Used to restore session state between
+ * connections.
+ *
+ * If left empty, the broker will auto-assign a unique client id. When reconnecting, the mqtt5 client
+ * will always use the auto-assigned client id.
+ *
+ * See [MQTT5 Client
+ * Identifier](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901059)
+ *
+ * @param clientId A unique string identifying the client to the server.
+ * @return The ConnectPacket Object after setting the client ID.
+ */
+ ConnectPacket &withClientId(Crt::String clientId) noexcept;
+
+ /**
+ * Sets the string value that the server may use for client authentication and authorization.
+ *
+ * See [MQTT5 User Name](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901071)
+ *
+ * @param username The string value that the server may use for client authentication and authorization.
+ * @return The ConnectPacket Object after setting the username.
+ */
+ ConnectPacket &withUserName(Crt::String username) noexcept;
+
+ /**
+ * Sets the opaque binary data that the server may use for client authentication and authorization.
+ *
+ * See [MQTT5 Password](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901072)
+ *
+ * @param password Opaque binary data that the server may use for client authentication and
+ * authorization.
+ * @return The ConnectPacket Object after setting the password.
+ */
+ ConnectPacket &withPassword(ByteCursor password) noexcept;
+
+ /**
+ * Sets the time interval, in seconds, that the client requests the server to persist this connection's
+ * MQTT session state for. Has no meaning if the client has not been configured to rejoin sessions.
+ * Must be non-zero in order to successfully rejoin a session.
+ *
+ * If the responding CONNACK contains a session expiry property value, then that is the negotiated
+ * session expiry value. Otherwise, the session expiry sent by the client is the negotiated value.
+ *
+ * See [MQTT5 Session Expiry
+ * Interval](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901048)
+ *
+ * @param sessionExpiryIntervalSeconds A time interval, in seconds, that the client requests the server
+ * to persist this connection's MQTT session state for.
+ * @return The ConnectPacket Object after setting the session expiry interval.
+ */
+ ConnectPacket &withSessionExpiryIntervalSec(uint32_t sessionExpiryIntervalSeconds) noexcept;
+
+ /**
+ * Sets whether requests that the server send response information in the subsequent CONNACK. This
+ * response information may be used to set up request-response implementations over MQTT, but doing so
+ * is outside the scope of the MQTT5 spec and client.
+ *
+ * See [MQTT5 Request Response
+ * Information](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901052)
+ *
+ * @param requestResponseInformation If true, requests that the server send response information in the
+ * subsequent CONNACK.
+ * @return The ConnectPacket Object after setting the request response information.
+ */
+ ConnectPacket &withRequestResponseInformation(bool requestResponseInformation) noexcept;
+
+ /**
+ * Sets whether requests that the server send additional diagnostic information (via response string or
+ * user properties) in DISCONNECT or CONNACK packets from the server.
+ *
+ * See [MQTT5 Request Problem
+ * Information](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901053)
+ *
+ * @param requestProblemInformation If true, requests that the server send additional diagnostic
+ * information (via response string or user properties) in DISCONNECT or CONNACK packets from the
+ * server.
+ * @return The ConnectPacket Object after setting the request problem information.
+ */
+ ConnectPacket &withRequestProblemInformation(bool requestProblemInformation) noexcept;
+
+ /**
+ * Sets the maximum number of in-flight QoS 1 and 2 messages the client is willing to handle. If
+ * omitted, then no limit is requested.
+ *
+ * See [MQTT5 Receive
+ * Maximum](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901049)
+ *
+ * @param receiveMaximum The maximum number of in-flight QoS 1 and 2 messages the client is willing to
+ * handle.
+ * @return The ConnectPacket Object after setting the receive maximum.
+ */
+ ConnectPacket &withReceiveMaximum(uint16_t receiveMaximum) noexcept;
+
+ /**
+ * Sets the maximum packet size the client is willing to handle. If
+ * omitted, then no limit beyond the natural limits of MQTT packet size is requested.
+ *
+ * See [MQTT5 Maximum Packet
+ * Size](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901050)
+ *
+ * @param maximumPacketSizeBytes The maximum packet size the client is willing to handle
+ * @return The ConnectPacket Object after setting the maximum packet size.
+ */
+ ConnectPacket &withMaximumPacketSizeBytes(uint32_t maximumPacketSizeBytes) noexcept;
+
+ /**
+ * Sets the time interval, in seconds, that the server should wait (for a session reconnection) before
+ * sending the will message associated with the connection's session. If omitted, the server
+ * will send the will when the associated session is destroyed. If the session is destroyed before a
+ * will delay interval has elapsed, then the will must be sent at the time of session destruction.
+ *
+ * See [MQTT5 Will Delay
+ * Interval](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901062)
+ *
+ * @param willDelayIntervalSeconds A time interval, in seconds, that the server should wait (for a
+ * session reconnection) before sending the will message associated with the connection's session.
+ * @return The ConnectPacket Object after setting the will message delay interval.
+ */
+ ConnectPacket &withWillDelayIntervalSec(uint32_t willDelayIntervalSeconds) noexcept;
+
+ /**
+ * Sets the definition of a message to be published when the connection's session is destroyed by the
+ * server or when the will delay interval has elapsed, whichever comes first. If null, then nothing
+ * will be sent.
+ *
+ * See [MQTT5 Will](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901040)
+ *
+ * @param will The message to be published when the connection's session is destroyed by the server or
+ * when the will delay interval has elapsed, whichever comes first.
+ * @return The ConnectPacket Object after setting the will message.
+ */
+ ConnectPacket &withWill(std::shared_ptr<PublishPacket> will) noexcept;
+
+ /**
+ * Sets the list of MQTT5 user properties included with the packet.
+ *
+ * See [MQTT5 User
+ * Property](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901054)
+ *
+ * @param userProperties List of MQTT5 user properties included with the packet.
+ * @return The ConnectPacket Object after setting the user properties.
+ */
+ ConnectPacket &withUserProperties(const Vector<UserProperty> &userProperties) noexcept;
+
+ /**
+ * Sets the list of MQTT5 user properties included with the packet.
+ *
+ * See [MQTT5 User
+ * Property](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901054)
+ *
+ * @param userProperties List of MQTT5 user properties included with the packet.
+ * @return The ConnectPacket Object after setting the user properties.
+ */
+ ConnectPacket &withUserProperties(Vector<UserProperty> &&userProperties) noexcept;
+
+ /**
+ * Put a MQTT5 user property to the back of the packet user property vector/list
+ *
+ * See [MQTT5 User
+ * Property](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901116)
+ *
+ * @param property set of userProperty of MQTT5 user properties included with the packet.
+ * @return The ConnectPacket Object after setting the user property
+ */
+ ConnectPacket &withUserProperty(UserProperty &&property) noexcept;
+
+ /********************************************
+ * Access Functions
+ ********************************************/
+
+ /**
+ * The maximum time interval, in seconds, that is permitted to elapse between the point at which the
+ * client finishes transmitting one MQTT packet and the point it starts sending the next. The client
+ * will use PINGREQ packets to maintain this property.
+ *
+ * If the responding CONNACK contains a keep alive property value, then that is the negotiated keep
+ * alive value. Otherwise, the keep alive sent by the client is the negotiated value.
+ *
+ * See [MQTT5 Keep Alive](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901045)
+ *
+ * @return The maximum time interval, in seconds, that is permitted to elapse between the point at which
+ * the client finishes transmitting one MQTT packet and the point it starts sending the next.
+ */
+ uint16_t getKeepAliveIntervalSec() const noexcept;
+
+ /**
+ * A unique string identifying the client to the server. Used to restore session state between
+ * connections.
+ *
+ * If left empty, the broker will auto-assign a unique client id. When reconnecting, the mqtt5 client
+ * will always use the auto-assigned client id.
+ *
+ * See [MQTT5 Client
+ * Identifier](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901059)
+ *
+ * @return A unique string identifying the client to the server.
+ */
+ const Crt::String &getClientId() const noexcept;
+
+ /**
+ * A string value that the server may use for client authentication and authorization.
+ *
+ * See [MQTT5 User Name](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901071)
+ *
+ * @return A string value that the server may use for client authentication and authorization.
+ */
+ const Crt::Optional<Crt::String> &getUsername() const noexcept;
+
+ /**
+ * Opaque binary data that the server may use for client authentication and authorization.
+ *
+ * See [MQTT5 Password](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901072)
+ *
+ * @return Opaque binary data that the server may use for client authentication and authorization.
+ */
+ const Crt::Optional<Crt::ByteCursor> &getPassword() const noexcept;
+
+ /**
+ * A time interval, in seconds, that the client requests the server to persist this connection's MQTT
+ * session state for. Has no meaning if the client has not been configured to rejoin sessions. Must be
+ * non-zero in order to successfully rejoin a session.
+ *
+ * If the responding CONNACK contains a session expiry property value, then that is the negotiated
+ * session expiry value. Otherwise, the session expiry sent by the client is the negotiated value.
+ *
+ * See [MQTT5 Session Expiry
+ * Interval](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901048)
+ *
+ * @return A time interval, in seconds, that the client requests the server to persist this connection's
+ * MQTT session state for.
+ */
+ const Crt::Optional<uint32_t> &getSessionExpiryIntervalSec() const noexcept;
+
+ /**
+ * If true, requests that the server send response information in the subsequent CONNACK. This response
+ * information may be used to set up request-response implementations over MQTT, but doing so is outside
+ * the scope of the MQTT5 spec and client.
+ *
+ * See [MQTT5 Request Response
+ * Information](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901052)
+ *
+ * @return If true, requests that the server send response information in the subsequent CONNACK.
+ */
+ const Crt::Optional<bool> &getRequestResponseInformation() const noexcept;
+
+ /**
+ * If true, requests that the server send additional diagnostic information (via response string or
+ * user properties) in DISCONNECT or CONNACK packets from the server.
+ *
+ * See [MQTT5 Request Problem
+ * Information](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901053)
+ *
+ * @return If true, requests that the server send additional diagnostic information (via response string
+ * or user properties) in DISCONNECT or CONNACK packets from the server.
+ */
+ const Crt::Optional<bool> &getRequestProblemInformation() const noexcept;
+
+ /**
+ * Notifies the server of the maximum number of in-flight QoS 1 and 2 messages the client is willing to
+ * handle. If omitted or null, then no limit is requested.
+ *
+ * See [MQTT5 Receive
+ * Maximum](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901049)
+ *
+ * @return The maximum number of in-flight QoS 1 and 2 messages the client is willing to handle.
+ */
+ const Crt::Optional<uint16_t> &getReceiveMaximum() const noexcept;
+
+ /**
+ * Notifies the server of the maximum packet size the client is willing to handle. If
+ * omitted or null, then no limit beyond the natural limits of MQTT packet size is requested.
+ *
+ * See [MQTT5 Maximum Packet
+ * Size](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901050)
+ *
+ * @return The maximum packet size the client is willing to handle
+ */
+ const Crt::Optional<uint32_t> &getMaximumPacketSizeBytes() const noexcept;
+
+ /**
+ * A time interval, in seconds, that the server should wait (for a session reconnection) before sending
+ * the will message associated with the connection's session. If omitted or null, the server will send
+ * the will when the associated session is destroyed. If the session is destroyed before a will delay
+ * interval has elapsed, then the will must be sent at the time of session destruction.
+ *
+ * See [MQTT5 Will Delay
+ * Interval](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901062)
+ *
+ * @return A time interval, in seconds, that the server should wait (for a session reconnection) before
+ * sending the will message associated with the connection's session.
+ */
+ const Crt::Optional<uint32_t> &getWillDelayIntervalSec() const noexcept;
+
+ /**
+ * The definition of a message to be published when the connection's session is destroyed by the server
+ * or when the will delay interval has elapsed, whichever comes first. If null, then nothing will be
+ * sent.
+ *
+ * See [MQTT5 Will](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901040)
+ *
+ * @return The message to be published when the connection's session is destroyed by the server or when
+ * the will delay interval has elapsed, whichever comes first.
+ */
+ const Crt::Optional<std::shared_ptr<PublishPacket>> &getWill() const noexcept;
+
+ /**
+ * List of MQTT5 user properties included with the packet.
+ *
+ * See [MQTT5 User
+ * Property](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901054)
+ *
+ * @return List of MQTT5 user properties included with the packet.
+ */
+ const Crt::Vector<UserProperty> &getUserProperties() const noexcept;
+
+ /**
+ * Intended for internal use only. Initializes the C aws_mqtt5_packet_connack_view
+ * from PacketConnect
+ *
+ * @param raw_options - output parameter containing low level client options to be passed to the C
+ * @param allocator - memory Allocator
+ *
+ */
+ bool initializeRawOptions(aws_mqtt5_packet_connect_view &raw_options, Allocator *allocator) noexcept;
+
+ virtual ~ConnectPacket();
+ ConnectPacket(const ConnectPacket &) = delete;
+ ConnectPacket(ConnectPacket &&) noexcept = delete;
+ ConnectPacket &operator=(const ConnectPacket &) = delete;
+ ConnectPacket &operator=(ConnectPacket &&) noexcept = delete;
+
+ private:
+ Allocator *m_allocator;
+
+ /**
+ * The maximum time interval, in seconds, that is permitted to elapse between the point at which the
+ * client finishes transmitting one MQTT packet and the point it starts sending the next. The client
+ * will use PINGREQ packets to maintain this property.
+ *
+ * If the responding CONNACK contains a keep alive property value, then that is the negotiated keep
+ * alive value. Otherwise, the keep alive sent by the client is the negotiated value.
+ *
+ * See [MQTT5 Keep Alive](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901045)
+ */
+ uint16_t m_keepAliveIntervalSec;
+
+ /**
+ * A unique string identifying the client to the server. Used to restore session state between
+ * connections.
+ *
+ * If left empty, the broker will auto-assign a unique client id. When reconnecting, the mqtt5 client
+ * will always use the auto-assigned client id.
+ *
+ * See [MQTT5 Client
+ * Identifier](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901059)
+ */
+ Crt::String m_clientId;
+
+ /**
+ * A string value that the server may use for client authentication and authorization.
+ *
+ * See [MQTT5 User Name](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901071)
+ */
+ Crt::Optional<Crt::String> m_username;
+
+ /**
+ * Opaque binary data that the server may use for client authentication and authorization.
+ *
+ * See [MQTT5 Password](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901072)
+ */
+ Crt::Optional<ByteCursor> m_password;
+
+ /**
+ * A time interval, in seconds, that the client requests the server to persist this connection's MQTT
+ * session state for. Has no meaning if the client has not been configured to rejoin sessions. Must be
+ * non-zero in order to successfully rejoin a session.
+ *
+ * If the responding CONNACK contains a session expiry property value, then that is the negotiated
+ * session expiry value. Otherwise, the session expiry sent by the client is the negotiated value.
+ *
+ * See [MQTT5 Session Expiry
+ * Interval](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901048)
+ */
+ Crt::Optional<uint32_t> m_sessionExpiryIntervalSec;
+
+ /**
+ * If set to true, requests that the server send response information in the subsequent CONNACK. This
+ * response information may be used to set up request-response implementations over MQTT, but doing so
+ * is outside the scope of the MQTT5 spec and client.
+ *
+ * See [MQTT5 Request Response
+ * Information](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901052)
+ */
+ Crt::Optional<bool> m_requestResponseInformation;
+
+ /**
+ * If set to true, requests that the server send additional diagnostic information (via response string
+ * or user properties) in DISCONNECT or CONNACK packets from the server.
+ *
+ * See [MQTT5 Request Problem
+ * Information](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901053)
+ */
+ Crt::Optional<bool> m_requestProblemInformation;
+
+ /**
+ * Notifies the server of the maximum number of in-flight Qos 1 and 2 messages the client is willing to
+ * handle. If omitted, then no limit is requested.
+ *
+ * See [MQTT5 Receive
+ * Maximum](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901049)
+ */
+ Crt::Optional<uint16_t> m_receiveMaximum;
+
+ /**
+ * Notifies the server of the maximum packet size the client is willing to handle. If
+ * omitted, then no limit beyond the natural limits of MQTT packet size is requested.
+ *
+ * See [MQTT5 Maximum Packet
+ * Size](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901050)
+ */
+ Crt::Optional<uint32_t> m_maximumPacketSizeBytes;
+
+ /**
+ * A time interval, in seconds, that the server should wait (for a session reconnection) before sending
+ * the will message associated with the connection's session. If omitted, the server will send the will
+ * when the associated session is destroyed. If the session is destroyed before a will delay interval
+ * has elapsed, then the will must be sent at the time of session destruction.
+ *
+ * See [MQTT5 Will Delay
+ * Interval](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901062)
+ */
+ Crt::Optional<uint32_t> m_willDelayIntervalSeconds;
+
+ /**
+ * The definition of a message to be published when the connection's session is destroyed by the server
+ * or when the will delay interval has elapsed, whichever comes first. If undefined, then nothing will
+ * be sent.
+ *
+ * See [MQTT5 Will](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901040)
+ */
+ Crt::Optional<std::shared_ptr<PublishPacket>> m_will;
+
+ /**
+ * Set of MQTT5 user properties included with the packet.
+ *
+ * See [MQTT5 User
+ * Property](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901054)
+ */
+ Crt::Vector<UserProperty> m_userProperties;
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Underlying data storage for internal use
+ ///////////////////////////////////////////////////////////////////////////
+ struct aws_byte_cursor m_usernameCursor;
+ struct aws_byte_buf m_passowrdStorage;
+ struct aws_mqtt5_packet_publish_view m_willStorage;
+ struct aws_mqtt5_user_property *m_userPropertiesStorage;
+ uint8_t m_requestResponseInformationStorage;
+ uint8_t m_requestProblemInformationStorage;
+ };
+
+ /**
+ * Data model of an [MQTT5
+ * CONNACK](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901074) packet.
+ */
+ class AWS_CRT_CPP_API ConnAckPacket : public IPacket
+ {
+ public:
+ ConnAckPacket(
+ const aws_mqtt5_packet_connack_view &packet,
+ Allocator *allocator = ApiAllocator()) noexcept;
+
+ /* The packet type */
+ PacketType getType() override { return PacketType::AWS_MQTT5_PT_CONNACK; };
+
+ /**
+ * True if the client rejoined an existing session on the server, false otherwise.
+ *
+ * See [MQTT5 Session
+ * Present](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901078)
+ *
+ * @return True if the client rejoined an existing session on the server, false otherwise.
+ */
+ bool getSessionPresent() const noexcept;
+
+ /**
+ * Indicates either success or the reason for failure for the connection attempt.
+ *
+ * See [MQTT5 Connect Reason
+ * Code](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901079)
+ *
+ * @return Code indicating either success or the reason for failure for the connection attempt.
+ */
+ ConnectReasonCode getReasonCode() const noexcept;
+
+ /**
+ * A time interval, in seconds, that the server will persist this connection's MQTT session state
+ * for. If present, this value overrides any session expiry specified in the preceding CONNECT packet.
+ *
+ * See [MQTT5 Session Expiry
+ * Interval](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901082)
+ *
+ * @return A time interval, in seconds, that the server will persist this connection's MQTT session
+ * state for.
+ */
+ const Crt::Optional<uint32_t> &getSessionExpiryInterval() const noexcept;
+
+ /**
+ * The maximum amount of in-flight QoS 1 or 2 messages that the server is willing to handle at once. If
+ * omitted or null, the limit is based on the valid MQTT packet id space (65535).
+ *
+ * See [MQTT5 Receive
+ * Maximum](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901083)
+ *
+ * @return The maximum amount of in-flight QoS 1 or 2 messages that the server is willing to handle at
+ * once.
+ */
+ const Crt::Optional<uint16_t> &getReceiveMaximum() const noexcept;
+
+ /**
+ * The maximum message delivery quality of service that the server will allow on this connection.
+ *
+ * See [MQTT5 Maximum QoS](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901084)
+ *
+ * @return The maximum message delivery quality of service that the server will allow on this
+ * connection.
+ */
+ const Crt::Optional<QOS> &getMaximumQOS() const noexcept;
+
+ /**
+ * Indicates whether the server supports retained messages. If null, retained messages are
+ * supported.
+ *
+ * See [MQTT5 Retain
+ * Available](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901085)
+ *
+ * @return Whether the server supports retained messages
+ */
+ const Crt::Optional<bool> &getRetainAvailable() const noexcept;
+
+ /**
+ * Specifies the maximum packet size, in bytes, that the server is willing to accept. If null, there
+ * is no limit beyond what is imposed by the MQTT spec itself.
+ *
+ * See [MQTT5 Maximum Packet
+ * Size](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901086)
+ *
+ * @return The maximum packet size, in bytes, that the server is willing to accept.
+ */
+ const Crt::Optional<uint32_t> &getMaximumPacketSize() const noexcept;
+
+ /**
+ * Specifies a client identifier assigned to this connection by the server. Only valid when the client
+ * id of the preceding CONNECT packet was left empty.
+ *
+ * See [MQTT5 Assigned Client
+ * Identifier](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901087)
+ *
+ * @return Client identifier assigned to this connection by the server
+ */
+ const Crt::Optional<String> &getAssignedClientIdentifier() const noexcept;
+
+ /**
+ * Specifies the maximum topic alias value that the server will accept from the client.
+ *
+ * See [MQTT5 Topic Alias
+ * Maximum](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901088)
+ *
+ * @return maximum topic alias
+ */
+ const Crt::Optional<uint16_t> getTopicAliasMaximum() const noexcept;
+
+ /**
+ * Additional diagnostic information about the result of the connection attempt.
+ *
+ * See [MQTT5 Reason
+ * String](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901089)
+ *
+ * @return Additional diagnostic information about the result of the connection attempt.
+ */
+ const Crt::Optional<String> &getReasonString() const noexcept;
+
+ /**
+ * List of MQTT5 user properties included with the packet.
+ *
+ * See [MQTT5 User
+ * Property](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901090)
+ *
+ * @return List of MQTT5 user properties included with the packet.
+ */
+ const Vector<UserProperty> &getUserProperty() const noexcept;
+
+ /**
+ * Indicates whether the server supports wildcard subscriptions. If null, wildcard subscriptions
+ * are supported.
+ *
+ * See [MQTT5 Wildcard Subscriptions
+ * Available](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901091)
+ *
+ * @return Whether the server supports wildcard subscriptions.
+ */
+ const Crt::Optional<bool> &getWildcardSubscriptionsAvaliable() const noexcept;
+
+ /**
+ * Indicates whether the server supports subscription identifiers. If null, subscription identifiers
+ * are supported.
+ *
+ * See [MQTT5 Subscription Identifiers
+ * Available](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901092)
+ *
+ * @return whether the server supports subscription identifiers.
+ */
+ const Crt::Optional<bool> &getSubscriptionIdentifiersAvaliable() const noexcept;
+
+ /**
+ * Indicates whether the server supports shared subscription topic filters. If null, shared
+ * subscriptions are supported.
+ *
+ * See [MQTT5 Shared Subscriptions
+ * Available](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901093)
+ *
+ * @return whether the server supports shared subscription topic filters.
+ */
+ const Crt::Optional<bool> &getSharedSubscriptionsAvaliable() const noexcept;
+
+ /**
+ * Server-requested override of the keep alive interval, in seconds. If null, the keep alive value sent
+ * by the client should be used.
+ *
+ * See [MQTT5 Server Keep
+ * Alive](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901094)
+ *
+ * @return Server-requested override of the keep alive interval, in seconds
+ */
+ const Crt::Optional<uint16_t> &getServerKeepAlive() const noexcept;
+
+ /**
+ * A value that can be used in the creation of a response topic associated with this connection.
+ * MQTT5-based request/response is outside the purview of the MQTT5 spec and this client.
+ *
+ * See [MQTT5 Response
+ * Information](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901095)
+ *
+ * @return A value that can be used in the creation of a response topic associated with this connection.
+ */
+ const Crt::Optional<String> &getResponseInformation() const noexcept;
+
+ /**
+ * Property indicating an alternate server that the client may temporarily or permanently attempt
+ * to connect to instead of the configured endpoint. Will only be set if the reason code indicates
+ * another server may be used (ServerMoved, UseAnotherServer).
+ *
+ * See [MQTT5 Server
+ * Reference](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901096)
+ *
+ * @return Property indicating an alternate server that the client may temporarily or permanently
+ * attempt to connect to instead of the configured endpoint.
+ */
+ const Crt::Optional<String> &getServerReference() const noexcept;
+
+ virtual ~ConnAckPacket(){};
+ ConnAckPacket(const ConnAckPacket &) = delete;
+ ConnAckPacket(ConnAckPacket &&) noexcept = delete;
+ ConnAckPacket &operator=(const ConnAckPacket &) = delete;
+ ConnAckPacket &operator=(ConnAckPacket &&) noexcept = delete;
+
+ private:
+ /**
+ * True if the client rejoined an existing session on the server, false otherwise.
+ *
+ * See [MQTT5 Session
+ * Present](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901078)
+ */
+ bool m_sessionPresent;
+
+ /**
+ * Indicates either success or the reason for failure for the connection attempt.
+ *
+ * See [MQTT5 Connect Reason
+ * Code](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901079)
+ */
+ ConnectReasonCode m_reasonCode;
+
+ /**
+ * A time interval, in seconds, that the server will persist this connection's MQTT session state
+ * for. If present, this value overrides any session expiry specified in the preceding CONNECT packet.
+ *
+ * See [MQTT5 Session Expiry
+ * Interval](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901082)
+ */
+ Crt::Optional<uint32_t> m_sessionExpiryInterval;
+
+ /**
+ * The maximum amount of in-flight QoS 1 or 2 messages that the server is willing to handle at once. If
+ * omitted, the limit is based on the valid MQTT packet id space (65535).
+ *
+ * See [MQTT5 Receive
+ * Maximum](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901083)
+ */
+ Crt::Optional<uint16_t> m_receiveMaximum;
+
+ /**
+ * The maximum message delivery quality of service that the server will allow on this connection.
+ *
+ * See [MQTT5 Maximum QoS](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901084)
+ */
+ Crt::Optional<QOS> m_maximumQOS;
+
+ /**
+ * Indicates whether the server supports retained messages. If undefined, retained messages are
+ * supported.
+ *
+ * See [MQTT5 Retain
+ * Available](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901085)
+ */
+ Crt::Optional<bool> m_retainAvailable;
+
+ /**
+ * Specifies the maximum packet size, in bytes, that the server is willing to accept. If undefined,
+ * there is no limit beyond what is imposed by the MQTT spec itself.
+ *
+ * See [MQTT5 Maximum Packet
+ * Size](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901086)
+ */
+ Crt::Optional<uint32_t> m_maximumPacketSize;
+
+ /**
+ * Specifies a client identifier assigned to this connection by the server. Only valid when the client
+ * id of the preceding CONNECT packet was left empty.
+ *
+ * See [MQTT5 Assigned Client
+ * Identifier](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901087)
+ */
+ Crt::Optional<String> m_assignedClientIdentifier;
+
+ /**
+ * Specifies the maximum topic alias value that the server will accept from the client.
+ *
+ * See [MQTT5 Topic Alias
+ * Maximum](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901088)
+ */
+ Crt::Optional<uint16_t> m_topicAliasMaximum;
+
+ /**
+ * Additional diagnostic information about the result of the connection attempt.
+ *
+ * See [MQTT5 Reason
+ * String](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901089)
+ */
+ Crt::Optional<String> m_reasonString;
+
+ /**
+ * Indicates whether the server supports wildcard subscriptions. If undefined, wildcard subscriptions
+ * are supported.
+ *
+ * See [MQTT5 Wildcard Subscriptions
+ * Available](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901091)
+ */
+ Crt::Optional<bool> m_wildcardSubscriptionsAvaliable;
+
+ /**
+ * Indicates whether the server supports subscription identifiers. If undefined, subscription
+ * identifiers are supported.
+ *
+ * See [MQTT5 Subscription Identifiers
+ * Available](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901092)
+ */
+ Crt::Optional<bool> m_subscriptionIdentifiersAvaliable;
+
+ /**
+ * Indicates whether the server supports shared subscription topic filters. If undefined, shared
+ * subscriptions are supported.
+ *
+ * See [MQTT5 Shared Subscriptions
+ * Available](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901093)
+ */
+ Crt::Optional<bool> m_sharedSubscriptionsAvaliable;
+
+ /**
+ * Server-requested override of the keep alive interval, in seconds. If undefined, the keep alive value
+ * sent by the client should be used.
+ *
+ * See [MQTT5 Server Keep
+ * Alive](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901094)
+ */
+ Crt::Optional<uint16_t> m_serverKeepAlive;
+
+ /**
+ * A value that can be used in the creation of a response topic associated with this connection.
+ * MQTT5-based request/response is outside the purview of the MQTT5 spec and this client.
+ *
+ * See [MQTT5 Response
+ * Information](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901095)
+ */
+ Crt::Optional<String> m_responseInformation;
+
+ /**
+ * Property indicating an alternate server that the client may temporarily or permanently attempt
+ * to connect to instead of the configured endpoint. Will only be set if the reason code indicates
+ * another server may be used (ServerMoved, UseAnotherServer).
+ *
+ * See [MQTT5 Server
+ * Reference](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901096)
+ */
+ Crt::Optional<String> m_serverReference;
+
+ /**
+ * Set of MQTT5 user properties included with the packet.
+ *
+ * See [MQTT5 User
+ * Property](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901090)
+ */
+ Vector<UserProperty> m_userProperties;
+ };
+
+ /**
+ * Data model of an [MQTT5
+ * DISCONNECT](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901205) packet.
+ */
+ class AWS_CRT_CPP_API DisconnectPacket : public IPacket
+ {
+ public:
+ DisconnectPacket(Allocator *allocator = ApiAllocator()) noexcept;
+ DisconnectPacket(
+ const aws_mqtt5_packet_disconnect_view &raw_options,
+ Allocator *allocator = ApiAllocator()) noexcept;
+ /* The packet type */
+ PacketType getType() override { return PacketType::AWS_MQTT5_PT_DISCONNECT; };
+
+ bool initializeRawOptions(aws_mqtt5_packet_disconnect_view &raw_options) noexcept;
+
+ /**
+ * Sets the value indicating the reason that the sender is closing the connection
+ *
+ * See [MQTT5 Disconnect Reason
+ * Code](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901208)
+ *
+ * @param reasonCode Value indicating the reason that the sender is closing the connection
+ * @return The DisconnectPacket Object after setting the reason code.
+ */
+ DisconnectPacket &withReasonCode(const DisconnectReasonCode reasonCode) noexcept;
+
+ /**
+ * Sets the change to the session expiry interval negotiated at connection time as part of the
+ * disconnect. Only valid for DISCONNECT packets sent from client to server. It is not valid to
+ * attempt to change session expiry from zero to a non-zero value.
+ *
+ * See [MQTT5 Session Expiry
+ * Interval](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901211)
+ *
+ * @param sessionExpiryIntervalSeconds
+ * @return The DisconnectPacket Object after setting the session expiry interval.
+ */
+ DisconnectPacket &withSessionExpiryIntervalSec(const uint32_t sessionExpiryIntervalSeconds) noexcept;
+
+ /**
+ * Sets the additional diagnostic information about the reason that the sender is closing the connection
+ *
+ * See [MQTT5 Reason
+ * String](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901212)
+ *
+ * @param reasonString Additional diagnostic information about the reason that the sender is closing the
+ * connection
+ * @return The DisconnectPacket Object after setting the reason string.
+ */
+ DisconnectPacket &withReasonString(Crt::String reasonString) noexcept;
+
+ /**
+ * Sets the property indicating an alternate server that the client may temporarily or permanently
+ * attempt to connect to instead of the configured endpoint. Will only be set if the reason code
+ * indicates another server may be used (ServerMoved, UseAnotherServer).
+ *
+ * See [MQTT5 Server
+ * Reference](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901214)
+ *
+ * @param serverReference Property indicating an alternate server that the client may temporarily or
+ * permanently attempt to connect to instead of the configured endpoint.
+ * @return The DisconnectPacket Object after setting the server reference.
+ */
+ DisconnectPacket &withServerReference(Crt::String serverReference) noexcept;
+
+ /**
+ * Sets the list of MQTT5 user properties included with the packet.
+ *
+ * See [MQTT5 User
+ * Property](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901213)
+ *
+ * @param userProperties List of MQTT5 user properties included with the packet.
+ * @return The DisconnectPacket Object after setting the user properties.
+ */
+ DisconnectPacket &withUserProperties(const Vector<UserProperty> &userProperties) noexcept;
+
+ /**
+ * Sets the list of MQTT5 user properties included with the packet.
+ *
+ * See [MQTT5 User
+ * Property](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901213)
+ *
+ * @param userProperties List of MQTT5 user properties included with the packet.
+ * @return The DisconnectPacket Object after setting the user properties.
+ */
+ DisconnectPacket &withUserProperties(Vector<UserProperty> &&userProperties) noexcept;
+
+ /**
+ * Put a MQTT5 user property to the back of the packet user property vector/list
+ *
+ * See [MQTT5 User
+ * Property](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901116)
+ *
+ * @param property set of userProperty of MQTT5 user properties included with the packet.
+ * @return The ConnectPacket Object after setting the user property
+ */
+ DisconnectPacket &withUserProperty(UserProperty &&property) noexcept;
+
+ /**
+ * Value indicating the reason that the sender is closing the connection
+ *
+ * See [MQTT5 Disconnect Reason
+ * Code](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901208)
+ *
+ * @return Value indicating the reason that the sender is closing the connection
+ */
+ DisconnectReasonCode getReasonCode() const noexcept;
+
+ /**
+ * A change to the session expiry interval negotiated at connection time as part of the disconnect. Only
+ * valid for DISCONNECT packets sent from client to server. It is not valid to attempt to change
+ * session expiry from zero to a non-zero value.
+ *
+ * See [MQTT5 Session Expiry
+ * Interval](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901211)
+ *
+ * @return A change to the session expiry interval negotiated at connection time as part of the
+ * disconnect.
+ */
+ const Crt::Optional<uint32_t> &getSessionExpiryIntervalSec() const noexcept;
+
+ /**
+ * Additional diagnostic information about the reason that the sender is closing the connection
+ *
+ * See [MQTT5 Reason
+ * String](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901212)
+ *
+ * @return Additional diagnostic information about the reason that the sender is closing the connection
+ */
+ const Crt::Optional<Crt::String> &getReasonString() const noexcept;
+
+ /**
+ * Property indicating an alternate server that the client may temporarily or permanently attempt
+ * to connect to instead of the configured endpoint. Will only be set if the reason code indicates
+ * another server may be used (ServerMoved, UseAnotherServer).
+ *
+ * See [MQTT5 Server
+ * Reference](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901214)
+ *
+ * @return Property indicating an alternate server that the client may temporarily or permanently
+ * attempt to connect to instead of the configured endpoint.
+ */
+ const Crt::Optional<Crt::String> &getServerReference() const noexcept;
+
+ /**
+ * List of MQTT5 user properties included with the packet.
+ *
+ * See [MQTT5 User
+ * Property](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901213)
+ *
+ * @return List of MQTT5 user properties included with the packet.
+ */
+ const Crt::Vector<UserProperty> &getUserProperties() const noexcept;
+
+ virtual ~DisconnectPacket();
+ DisconnectPacket(const DisconnectPacket &) = delete;
+ DisconnectPacket(DisconnectPacket &&) noexcept = delete;
+ DisconnectPacket &operator=(const DisconnectPacket &) = delete;
+ DisconnectPacket &operator=(DisconnectPacket &&) noexcept = delete;
+
+ private:
+ Crt::Allocator *m_allocator;
+
+ /**
+ * Value indicating the reason that the sender is closing the connection
+ *
+ * See [MQTT5 Disconnect Reason
+ * Code](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901208)
+ */
+ DisconnectReasonCode m_reasonCode;
+
+ /**
+ * Requests a change to the session expiry interval negotiated at connection time as part of the
+ * disconnect. Only valid for DISCONNECT packets sent from client to server. It is not valid to
+ * attempt to change session expiry from zero to a non-zero value.
+ *
+ * See [MQTT5 Session Expiry
+ * Interval](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901211)
+ */
+ Crt::Optional<uint32_t> m_sessionExpiryIntervalSec;
+
+ /**
+ * Additional diagnostic information about the reason that the sender is closing the connection
+ *
+ * See [MQTT5 Reason
+ * String](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901212)
+ */
+ Crt::Optional<Crt::String> m_reasonString;
+
+ /**
+ * Property indicating an alternate server that the client may temporarily or permanently attempt
+ * to connect to instead of the configured endpoint. Will only be set if the reason code indicates
+ * another server may be used (ServerMoved, UseAnotherServer).
+ *
+ * See [MQTT5 Server
+ * Reference](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901214)
+ */
+ Crt::Optional<Crt::String> m_serverReference;
+
+ /**
+ * Set of MQTT5 user properties included with the packet.
+ *
+ * See [MQTT5 User
+ * Property](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901213)
+ */
+ Crt::Vector<UserProperty> m_userProperties;
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Underlying data storage for internal use
+ ///////////////////////////////////////////////////////////////////////////
+ struct aws_byte_cursor m_reasonStringCursor;
+ struct aws_byte_cursor m_serverReferenceCursor;
+ struct aws_mqtt5_user_property *m_userPropertiesStorage;
+ };
+
+ /**
+ * Data model of an [MQTT5
+ * PUBACK](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901121) packet
+ */
+ class AWS_CRT_CPP_API PubAckPacket : public IPacket
+ {
+ public:
+ PubAckPacket(
+ const aws_mqtt5_packet_puback_view &packet,
+ Allocator *allocator = ApiAllocator()) noexcept;
+
+ PacketType getType() override { return PacketType::AWS_MQTT5_PT_PUBACK; };
+
+ /**
+ * Success indicator or failure reason for the associated PUBLISH packet.
+ *
+ * See [MQTT5 PUBACK Reason
+ * Code](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901124)
+ *
+ * @return Success indicator or failure reason for the associated PUBLISH packet.
+ */
+ PubAckReasonCode getReasonCode() const noexcept;
+
+ /**
+ * Additional diagnostic information about the result of the PUBLISH attempt.
+ *
+ * See [MQTT5 Reason
+ * String](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901127)
+ *
+ * @return Additional diagnostic information about the result of the PUBLISH attempt.
+ */
+ const Crt::Optional<Crt::String> &getReasonString() const noexcept;
+
+ /**
+ * List of MQTT5 user properties included with the packet.
+ *
+ * See [MQTT5 User
+ * Property](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901128)
+ *
+ * @return List of MQTT5 user properties included with the packet.
+ */
+ const Crt::Vector<UserProperty> &getUserProperties() const noexcept;
+
+ virtual ~PubAckPacket(){};
+ PubAckPacket(const PubAckPacket &toCopy) noexcept = delete;
+ PubAckPacket(PubAckPacket &&toMove) noexcept = delete;
+ PubAckPacket &operator=(const PubAckPacket &toCopy) noexcept = delete;
+ PubAckPacket &operator=(PubAckPacket &&toMove) noexcept = delete;
+
+ private:
+ /**
+ * Success indicator or failure reason for the associated PUBLISH packet.
+ *
+ * See [MQTT5 PUBACK Reason
+ * Code](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901124)
+ */
+ PubAckReasonCode m_reasonCode;
+
+ /**
+ * Additional diagnostic information about the result of the PUBLISH attempt.
+ *
+ * See [MQTT5 Reason
+ * String](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901127)
+ */
+ Crt::Optional<Crt::String> m_reasonString;
+
+ /**
+ * Set of MQTT5 user properties included with the packet.
+ *
+ * See [MQTT5 User
+ * Property](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901128)
+ */
+ Crt::Vector<UserProperty> m_userProperties;
+ };
+
+ /**
+ * PublishResult returned with onPublishCompletionCallback after Publish get called
+ *
+ * Publish with QoS0: Ack will be nullptr
+ * QoS1: Ack will contains a PubAckPacket
+ */
+ class AWS_CRT_CPP_API PublishResult
+ {
+ public:
+ PublishResult(); // QoS 0 success
+ PublishResult(std::shared_ptr<PubAckPacket> puback); // Qos 1 success
+ PublishResult(int errorCode); // any failure
+
+ /**
+ * Get if the publish succeed or not
+ *
+ * @return true if error code == 0 and publish succeed
+ */
+ bool wasSuccessful() const { return m_errorCode == 0; };
+
+ /**
+ * Get the error code value
+ *
+ * @return the error code
+ */
+ int getErrorCode() const { return m_errorCode; };
+
+ /**
+ * Get Publish ack packet
+ *
+ * @return std::shared_ptr<IPacket> contains a PubAckPacket if client Publish with QoS1, otherwise
+ * nullptr.
+ */
+ std::shared_ptr<IPacket> getAck() const { return m_ack; };
+
+ ~PublishResult() noexcept;
+ PublishResult(const PublishResult &toCopy) noexcept = delete;
+ PublishResult(PublishResult &&toMove) noexcept = delete;
+ PublishResult &operator=(const PublishResult &toCopy) noexcept = delete;
+ PublishResult &operator=(PublishResult &&toMove) noexcept = delete;
+
+ private:
+ std::shared_ptr<IPacket> m_ack;
+ int m_errorCode;
+ };
+
+ /**
+ * Configures a single subscription within a Subscribe operation
+ *
+ * See [MQTT5 Subscription
+ * Options](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901169)
+ */
+ class AWS_CRT_CPP_API Subscription
+ {
+
+ public:
+ Subscription(Allocator *allocator = ApiAllocator());
+ Subscription(Crt::String topicFilter, Mqtt5::QOS qos, Allocator *allocator = ApiAllocator());
+
+ /**
+ * Sets topic filter to subscribe to
+ *
+ * See [MQTT5 Subscription
+ * Options](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901169)
+ *
+ * @param topicFilter string
+ * @return The Subscription Object after setting the reason string.
+ */
+ Subscription &withTopicFilter(Crt::String topicFilter) noexcept;
+
+ /**
+ * Sets Maximum QoS on which the subscriber will accept publish messages. Negotiated QoS may be
+ * different.
+ *
+ * See [MQTT5 Subscription
+ * Options](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901169)
+ *
+ * @param QOS
+ * @return The Subscription Object after setting the reason string.
+ */
+ Subscription &withQOS(Mqtt5::QOS QOS) noexcept;
+
+ /**
+ * Sets should the server not send publishes to a client when that client was the one who sent the
+ * publish? The value will be default to false.
+ *
+ * See [MQTT5 Subscription
+ * Options](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901169)
+ *
+ * @param noLocal bool
+ * @return The Subscription Object after setting the reason string.
+ */
+ Subscription &withNoLocal(bool noLocal) noexcept;
+
+ /**
+ * Sets should the server not send publishes to a client when that client was the one who sent the
+ * publish? The value will be default to false.
+ *
+ * See [MQTT5 Subscription
+ * Options](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901169)
+ *
+ * @param retain bool
+ * @return The Subscription Object after setting the reason string.
+ */
+ Subscription &withRetain(bool retain) noexcept;
+
+ /**
+ * Sets should messages sent due to this subscription keep the retain flag preserved on the message?
+ * The value will be default to false.
+ *
+ * See [MQTT5 Subscription
+ * Options](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901169)
+ *
+ * @param retainHandlingType
+ * @return The Subscription Object after setting the reason string.
+ */
+ Subscription &withRetainHandlingType(RetainHandlingType retainHandlingType) noexcept;
+
+ bool initializeRawOptions(aws_mqtt5_subscription_view &raw_options) const noexcept;
+
+ virtual ~Subscription(){};
+ Subscription(const Subscription &) noexcept;
+ Subscription(Subscription &&) noexcept;
+ Subscription &operator=(const Subscription &) noexcept;
+ Subscription &operator=(Subscription &&) noexcept;
+
+ private:
+ Allocator *m_allocator;
+
+ /**
+ * Topic filter to subscribe to
+ *
+ * See [MQTT5 Subscription
+ * Options](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901169)
+ */
+ Crt::String m_topicFilter;
+
+ /**
+ * Maximum QoS on which the subscriber will accept publish messages. Negotiated QoS may be different.
+ *
+ * See [MQTT5 Subscription
+ * Options](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901169)
+ */
+ Mqtt5::QOS m_qos;
+
+ /**
+ * Should the server not send publishes to a client when that client was the one who sent the publish?
+ * If undefined, this is assumed to be false.
+ *
+ * See [MQTT5 Subscription
+ * Options](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901169)
+ */
+ bool m_noLocal;
+
+ /**
+ * Should messages sent due to this subscription keep the retain flag preserved on the message? If
+ * undefined, this is assumed to be false.
+ *
+ * See [MQTT5 Subscription
+ * Options](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901169)
+ */
+ bool m_retain;
+
+ /**
+ * Should retained messages on matching topics be sent in reaction to this subscription? If undefined,
+ * this is assumed to be RetainHandlingType.SendOnSubscribe.
+ *
+ * See [MQTT5 Subscription
+ * Options](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901169)
+ */
+ RetainHandlingType m_retainHnadlingType;
+ };
+
+ /**
+ * Data model of an [MQTT5
+ * SUBSCRIBE](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901161) packet.
+ */
+ class AWS_CRT_CPP_API SubscribePacket : public IPacket
+ {
+ public:
+ SubscribePacket(Allocator *allocator = ApiAllocator()) noexcept;
+
+ /* The packet type */
+ PacketType getType() override { return PacketType::AWS_MQTT5_PT_SUBSCRIBE; };
+
+ /**
+ * Sets the list of MQTT5 user properties included with the packet.
+ *
+ * See [MQTT5 User
+ * Property](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901116)
+ *
+ * @param userProperties List of MQTT5 user properties included with the packet.
+ * @return the SubscribePacket Object after setting the reason string.
+ */
+ SubscribePacket &withUserProperties(const Vector<UserProperty> &userProperties) noexcept;
+
+ /**
+ * Sets the list of MQTT5 user properties included with the packet.
+ *
+ * See [MQTT5 User
+ * Property](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901116)
+ *
+ * @param userProperties List of MQTT5 user properties included with the packet.
+ * @return the SubscribePacket Object after setting the reason string.
+ */
+ SubscribePacket &withUserProperties(Vector<UserProperty> &&userProperties) noexcept;
+
+ /**
+ * Put a MQTT5 user property to the back of the packet user property vector/list
+ *
+ * See [MQTT5 User
+ * Property](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901116)
+ *
+ * @param property userProperty of MQTT5 user properties included with the packet.
+ * @return The SubscribePacket Object after setting the user property
+ */
+ SubscribePacket &withUserProperty(UserProperty &&property) noexcept;
+
+ /**
+ * Sets the value to associate with all subscriptions in this request. Publish packets that
+ * match a subscription in this request should include this identifier in the resulting message.
+ *
+ * See [MQTT5 Subscription
+ * Identifier](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901166)
+ *
+ * @param subscriptionIdentifier A positive long to associate with all subscriptions in this request.
+ * @return The SubscribePacket Object after setting the subscription identifier.
+ */
+ SubscribePacket &withSubscriptionIdentifier(uint32_t subscriptionIdentifier) noexcept;
+
+ /**
+ * Sets a list of subscriptions within the SUBSCRIBE packet.
+ *
+ * @param subscriptions vector of subscriptions to add within the SUBSCRIBE packet.
+ *
+ * @return The SubscribePacket Object after setting the subscription.
+ */
+ SubscribePacket &withSubscriptions(const Vector<Subscription> &subscriptions) noexcept;
+
+ /**
+ * Sets a list of subscriptions within the SUBSCRIBE packet.
+ *
+ * @param subscriptions vector of subscriptions to add within the SUBSCRIBE packet.
+ *
+ * @return The SubscribePacket Object after setting the subscription.
+ */
+ SubscribePacket &withSubscriptions(Crt::Vector<Subscription> &&subscriptions) noexcept;
+
+ /**
+ * Sets a single subscription within the SUBSCRIBE packet.
+ *
+ * @param subscription The subscription to add within the SUBSCRIBE packet.
+ *
+ * @return The SubscribePacket Object after setting the subscription.
+ */
+ SubscribePacket &withSubscription(Subscription &&subscription) noexcept;
+
+ bool initializeRawOptions(aws_mqtt5_packet_subscribe_view &raw_options) noexcept;
+
+ virtual ~SubscribePacket();
+ SubscribePacket(const SubscribePacket &) noexcept = delete;
+ SubscribePacket(SubscribePacket &&) noexcept = delete;
+ SubscribePacket &operator=(const SubscribePacket &) noexcept = delete;
+ SubscribePacket &operator=(SubscribePacket &&) noexcept = delete;
+
+ private:
+ Allocator *m_allocator;
+
+ /**
+ * List of topic filter subscriptions that the client wishes to listen to
+ *
+ * See [MQTT5 Subscribe
+ * Payload](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901168)
+ */
+ Crt::Vector<Subscription> m_subscriptions;
+
+ /**
+ * A positive integer to associate with all subscriptions in this request. Publish packets that match
+ * a subscription in this request should include this identifier in the resulting message.
+ *
+ * See [MQTT5 Subscription
+ * Identifier](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901166)
+ */
+ Crt::Optional<uint32_t> m_subscriptionIdentifier;
+
+ /**
+ * Set of MQTT5 user properties included with the packet.
+ *
+ * See [MQTT5 User
+ * Property](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901167)
+ */
+ Crt::Vector<UserProperty> m_userProperties;
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Underlying data storage for internal use
+ ///////////////////////////////////////////////////////////////////////////
+ struct aws_mqtt5_subscription_view *m_subscriptionViewStorage;
+ struct aws_mqtt5_user_property *m_userPropertiesStorage;
+ };
+
+ /**
+ * Data model of an [MQTT5
+ * SUBACK](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901171) packet.
+ */
+ class AWS_CRT_CPP_API SubAckPacket : public IPacket
+ {
+ public:
+ SubAckPacket(
+ const aws_mqtt5_packet_suback_view &packet,
+ Allocator *allocator = ApiAllocator()) noexcept;
+
+ /* The packet type */
+ PacketType getType() override { return PacketType::AWS_MQTT5_PT_SUBACK; };
+
+ /**
+ * Returns additional diagnostic information about the result of the SUBSCRIBE attempt.
+ *
+ * See [MQTT5 Reason
+ * String](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901176)
+ *
+ * @return Additional diagnostic information about the result of the SUBSCRIBE attempt.
+ */
+ const Crt::Optional<Crt::String> &getReasonString() const noexcept;
+
+ /**
+ * Returns list of MQTT5 user properties included with the packet.
+ *
+ * See [MQTT5 User
+ * Property](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901177)
+ *
+ * @return List of MQTT5 user properties included with the packet.
+ */
+ const Crt::Vector<UserProperty> &getUserProperties() const noexcept;
+
+ /**
+ * Returns list of reason codes indicating the result of each individual subscription entry in the
+ * associated SUBSCRIBE packet.
+ *
+ * See [MQTT5 Suback
+ * Payload](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901178)
+ *
+ * @return list of reason codes indicating the result of each individual subscription entry in the
+ * associated SUBSCRIBE packet.
+ */
+ const Crt::Vector<SubAckReasonCode> &getReasonCodes() const noexcept;
+
+ virtual ~SubAckPacket() { m_userProperties.clear(); };
+ SubAckPacket(const SubAckPacket &) noexcept = delete;
+ SubAckPacket(SubAckPacket &&) noexcept = delete;
+ SubAckPacket &operator=(const SubAckPacket &) noexcept = delete;
+ SubAckPacket &operator=(SubAckPacket &&) noexcept = delete;
+
+ private:
+ /**
+ * A list of reason codes indicating the result of each individual subscription entry in the
+ * associated SUBSCRIBE packet.
+ *
+ * See [MQTT5 Suback
+ * Payload](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901178)
+ */
+ Crt::Vector<SubAckReasonCode> m_reasonCodes;
+
+ /**
+ * Additional diagnostic information about the result of the SUBSCRIBE attempt.
+ *
+ * See [MQTT5 Reason
+ * String](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901176)
+ */
+ Crt::Optional<Crt::String> m_reasonString;
+
+ /**
+ * Set of MQTT5 user properties included with the packet.
+ *
+ * See [MQTT5 User
+ * Property](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901177)
+ */
+ Crt::Vector<UserProperty> m_userProperties;
+ };
+
+ /**
+ * Data model of an [MQTT5
+ * UNSUBSCRIBE](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901179) packet.
+ */
+ class AWS_CRT_CPP_API UnsubscribePacket : public IPacket
+ {
+ public:
+ UnsubscribePacket(Allocator *allocator = ApiAllocator()) noexcept;
+
+ /* The packet type */
+ PacketType getType() override { return PacketType::AWS_MQTT5_PT_UNSUBSCRIBE; };
+
+ /**
+ * Push back a topic filter that the client wishes to unsubscribe from.
+ *
+ * @param topicFilter that the client wishes to unsubscribe from
+ *
+ * @return The UnsubscribePacket Object after setting the subscription.
+ */
+ UnsubscribePacket &withTopicFilter(Crt::String topicFilter) noexcept;
+
+ /**
+ * Sets list of topic filter that the client wishes to unsubscribe from.
+ *
+ * @param topicFilters vector of subscription topic filters that the client wishes to unsubscribe from
+ *
+ * @return The UnsubscribePacket Object after setting the subscription.
+ */
+ UnsubscribePacket &withTopicFilters(Crt::Vector<String> topicFilters) noexcept;
+
+ /**
+ * Sets the list of MQTT5 user properties included with the packet.
+ *
+ * See [MQTT5 User
+ * Property](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901184)
+ *
+ * @param userProperties List of MQTT5 user properties included with the packet.
+ * @return The UnsubscribePacketBuilder after setting the user properties.
+ */
+ UnsubscribePacket &withUserProperties(const Vector<UserProperty> &userProperties) noexcept;
+
+ /**
+ * Sets the list of MQTT5 user properties included with the packet.
+ *
+ * See [MQTT5 User
+ * Property](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901184)
+ *
+ * @param userProperties List of MQTT5 user properties included with the packet.
+ * @return The UnsubscribePacketBuilder after setting the user properties.
+ */
+ UnsubscribePacket &withUserProperties(Vector<UserProperty> &&userProperties) noexcept;
+
+ /**
+ * Put a MQTT5 user property to the back of the packet user property vector/list
+ *
+ * See [MQTT5 User
+ * Property](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901116)
+ *
+ * @param property set of userProperty of MQTT5 user properties included with the packet.
+ * @return The PublishPacket Object after setting the user property
+ */
+ UnsubscribePacket &withUserProperty(UserProperty &&property) noexcept;
+
+ bool initializeRawOptions(aws_mqtt5_packet_unsubscribe_view &raw_options) noexcept;
+
+ virtual ~UnsubscribePacket();
+ UnsubscribePacket(const UnsubscribePacket &) noexcept = delete;
+ UnsubscribePacket(UnsubscribePacket &&) noexcept = delete;
+ UnsubscribePacket &operator=(const UnsubscribePacket &) noexcept = delete;
+ UnsubscribePacket &operator=(UnsubscribePacket &&) noexcept = delete;
+
+ private:
+ Allocator *m_allocator;
+
+ /**
+ * List of topic filters that the client wishes to unsubscribe from.
+ *
+ * See [MQTT5 Unsubscribe
+ * Payload](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901185)
+ */
+ Crt::Vector<String> m_topicFilters;
+
+ /**
+ * Set of MQTT5 user properties included with the packet.
+ *
+ * See [MQTT5 User
+ * Property](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901184)
+ */
+ Crt::Vector<UserProperty> m_userProperties;
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Underlying data storage for internal use
+ ///////////////////////////////////////////////////////////////////////////
+ struct aws_array_list m_topicFiltersList;
+ struct aws_mqtt5_user_property *m_userPropertiesStorage;
+ };
+
+ /**
+ * Data model of an [MQTT5
+ * UNSUBACK](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901187) packet.
+ */
+ class AWS_CRT_CPP_API UnSubAckPacket : public IPacket
+ {
+ public:
+ UnSubAckPacket(
+ const aws_mqtt5_packet_unsuback_view &packet,
+ Allocator *allocator = ApiAllocator()) noexcept;
+
+ /* The packet type */
+ PacketType getType() override { return PacketType::AWS_MQTT5_PT_UNSUBACK; };
+
+ /**
+ * Returns additional diagnostic information about the result of the UNSUBSCRIBE attempt.
+ *
+ * See [MQTT5 Reason
+ * String](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901192)
+ *
+ * @return Additional diagnostic information about the result of the UNSUBSCRIBE attempt.
+ */
+ const Crt::Optional<Crt::String> &getReasonString() const noexcept;
+
+ /**
+ * Returns list of MQTT5 user properties included with the packet.
+ *
+ * See [MQTT5 User
+ * Property](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901193)
+ *
+ * @return List of MQTT5 user properties included with the packet.
+ */
+ const Crt::Vector<UserProperty> &getUserProperties() const noexcept;
+
+ /**
+ * Returns a list of reason codes indicating the result of unsubscribing from each individual topic
+ * filter entry in the associated UNSUBSCRIBE packet.
+ *
+ * See [MQTT5 Unsuback
+ * Payload](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901194)
+ *
+ * @return A list of reason codes indicating the result of unsubscribing from each individual topic
+ * filter entry in the associated UNSUBSCRIBE packet.
+ */
+ const Crt::Vector<UnSubAckReasonCode> &getReasonCodes() const noexcept;
+
+ virtual ~UnSubAckPacket() { m_userProperties.clear(); };
+ UnSubAckPacket(const UnSubAckPacket &) noexcept = delete;
+ UnSubAckPacket(UnSubAckPacket &&) noexcept = delete;
+ UnSubAckPacket &operator=(const UnSubAckPacket &) noexcept = delete;
+ UnSubAckPacket &operator=(UnSubAckPacket &&) noexcept = delete;
+
+ private:
+ /**
+ * Additional diagnostic information about the result of the UNSUBSCRIBE attempt.
+ *
+ * See [MQTT5 Reason
+ * String](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901192)
+ */
+ Crt::Optional<Crt::String> m_reasonString;
+
+ /**
+ * Set of MQTT5 user properties included with the packet.
+ *
+ * See [MQTT5 User
+ * Property](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901193)
+ */
+ Crt::Vector<UserProperty> m_userProperties;
+
+ /**
+ * A list of reason codes indicating the result of unsubscribing from each individual topic filter entry
+ * in the associated UNSUBSCRIBE packet.
+ *
+ * See [MQTT5 Unsuback
+ * Payload](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901194)
+ */
+ Crt::Vector<UnSubAckReasonCode> m_reasonCodes;
+ };
+
+ } // namespace Mqtt5
+ } // namespace Crt
+} // namespace Aws
diff --git a/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/mqtt/Mqtt5Types.h b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/mqtt/Mqtt5Types.h
new file mode 100644
index 0000000000..b7aa4f3568
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/mqtt/Mqtt5Types.h
@@ -0,0 +1,120 @@
+#pragma once
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+#include <aws/mqtt/v5/mqtt5_client.h>
+#include <aws/mqtt/v5/mqtt5_types.h>
+
+namespace Aws
+{
+ namespace Crt
+ {
+ namespace Mqtt5
+ {
+ /**
+ * MQTT message delivery quality of service.
+ *
+ * Enum values match [MQTT5
+ * spec](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901234) encoding values.
+ */
+ using QOS = aws_mqtt5_qos;
+
+ /**
+ * Server return code for connect attempts.
+ *
+ * Enum values match [MQTT5
+ * spec](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901079) encoding values.
+ */
+ using ConnectReasonCode = aws_mqtt5_connect_reason_code;
+
+ /**
+ * Reason code inside DISCONNECT packets. Helps determine why a connection was terminated.
+ *
+ * Enum values match [MQTT5
+ * spec](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901208) encoding values.
+ */
+ using DisconnectReasonCode = aws_mqtt5_disconnect_reason_code;
+
+ /**
+ * Reason code inside PUBACK packets
+ *
+ * Data model of an [MQTT5
+ * PUBACK](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901121) packet
+ */
+ using PubAckReasonCode = aws_mqtt5_puback_reason_code;
+
+ /**
+ * Reason code inside PUBACK packets that indicates the result of the associated PUBLISH request.
+ *
+ * Enum values match [MQTT5
+ * spec](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901124) encoding values.
+ */
+ using SubAckReasonCode = aws_mqtt5_suback_reason_code;
+
+ /**
+ * Reason codes inside UNSUBACK packet payloads that specify the results for each topic filter in the
+ * associated UNSUBSCRIBE packet.
+ *
+ * Enum values match [MQTT5
+ * spec](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901194) encoding values.
+ */
+ using UnSubAckReasonCode = aws_mqtt5_unsuback_reason_code;
+
+ /**
+ * Controls how the MQTT5 client should behave with respect to MQTT sessions.
+ */
+ using ClientSessionBehaviorType = aws_mqtt5_client_session_behavior_type;
+
+ /**
+ * Additional controls for client behavior with respect to operation validation and flow control; these
+ * checks go beyond the MQTT5 spec to respect limits of specific MQTT brokers.
+ */
+ using ClientExtendedValidationAndFlowControl = aws_mqtt5_extended_validation_and_flow_control_options;
+
+ /**
+ * Controls how disconnects affect the queued and in-progress operations tracked by the client. Also
+ * controls how operations are handled while the client is not connected. In particular, if the client is
+ * not connected, then any operation that would be failed on disconnect (according to these rules) will be
+ * rejected.
+ */
+ using ClientOperationQueueBehaviorType = aws_mqtt5_client_operation_queue_behavior_type;
+
+ /**
+ * Controls how the reconnect delay is modified in order to smooth out the distribution of reconnection
+ * attempt timepoints for a large set of reconnecting clients.
+ *
+ * See [Exponential Backoff and
+ * Jitter](https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/)
+ */
+ using JitterMode = aws_exponential_backoff_jitter_mode;
+
+ /**
+ * Optional property describing a PUBLISH payload's format.
+ *
+ * Enum values match [MQTT5
+ * spec](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901111) encoding values.
+ */
+ using PayloadFormatIndicator = aws_mqtt5_payload_format_indicator;
+
+ /**
+ * Configures how retained messages should be handled when subscribing with a topic filter that matches
+ * topics with associated retained messages.
+ *
+ * Enum values match [MQTT5
+ * spec](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901169) encoding values.
+ */
+ using RetainHandlingType = aws_mqtt5_retain_handling_type;
+
+ /**
+ * Type of mqtt packet.
+ * Enum values match mqtt spec encoding values.
+ *
+ * https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901022
+ */
+ using PacketType = aws_mqtt5_packet_type;
+
+ } // namespace Mqtt5
+
+ } // namespace Crt
+} // namespace Aws
diff --git a/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/mqtt/MqttClient.h b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/mqtt/MqttClient.h
new file mode 100644
index 0000000000..03293237cb
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/include/aws/crt/mqtt/MqttClient.h
@@ -0,0 +1,532 @@
+#pragma once
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+#include <aws/crt/Exports.h>
+#include <aws/crt/StlAllocator.h>
+#include <aws/crt/Types.h>
+#include <aws/crt/http/HttpConnection.h>
+#include <aws/crt/io/SocketOptions.h>
+#include <aws/crt/io/TlsOptions.h>
+
+#include <aws/mqtt/client.h>
+
+#include <atomic>
+#include <functional>
+#include <memory>
+
+namespace Aws
+{
+ namespace Crt
+ {
+ namespace Io
+ {
+ class ClientBootstrap;
+ }
+
+ namespace Http
+ {
+ class HttpRequest;
+ }
+
+ namespace Mqtt
+ {
+ class MqttClient;
+ class MqttConnection;
+
+ /**
+ * Invoked Upon Connection loss.
+ */
+ using OnConnectionInterruptedHandler = std::function<void(MqttConnection &connection, int error)>;
+
+ /**
+ * Invoked Upon Connection resumed.
+ */
+ using OnConnectionResumedHandler =
+ std::function<void(MqttConnection &connection, ReturnCode connectCode, bool sessionPresent)>;
+
+ /**
+ * Invoked when a connack message is received, or an error occurred.
+ */
+ using OnConnectionCompletedHandler = std::function<
+ void(MqttConnection &connection, int errorCode, ReturnCode returnCode, bool sessionPresent)>;
+
+ /**
+ * Invoked when a suback message is received.
+ */
+ using OnSubAckHandler = std::function<
+ void(MqttConnection &connection, uint16_t packetId, const String &topic, QOS qos, int errorCode)>;
+
+ /**
+ * Invoked when a suback message for multiple topics is received.
+ */
+ using OnMultiSubAckHandler = std::function<void(
+ MqttConnection &connection,
+ uint16_t packetId,
+ const Vector<String> &topics,
+ QOS qos,
+ int errorCode)>;
+
+ /**
+ * Invoked when a disconnect message has been sent.
+ */
+ using OnDisconnectHandler = std::function<void(MqttConnection &connection)>;
+
+ /**
+ * Invoked upon receipt of a Publish message on a subscribed topic.
+ * @param connection The connection object
+ * @param topic The information channel to which the payload data was published.
+ * @param payload The payload data.
+ * @param dup DUP flag. If true, this might be re-delivery of an earlier
+ * attempt to send the message.
+ * @param qos Quality of Service used to deliver the message.
+ * @param retain Retain flag. If true, the message was sent as a result of
+ * a new subscription being made by the client.
+ */
+ using OnMessageReceivedHandler = std::function<void(
+ MqttConnection &connection,
+ const String &topic,
+ const ByteBuf &payload,
+ bool dup,
+ QOS qos,
+ bool retain)>;
+
+ /**
+ * @deprecated Use OnMessageReceivedHandler
+ */
+ using OnPublishReceivedHandler =
+ std::function<void(MqttConnection &connection, const String &topic, const ByteBuf &payload)>;
+
+ /**
+ * Invoked when an operation completes. For QoS 0, this is when the packet is passed to the tls
+ * layer. For QoS 1 (and 2, in theory) this is when the final ack packet is received from the server.
+ */
+ using OnOperationCompleteHandler =
+ std::function<void(MqttConnection &connection, uint16_t packetId, int errorCode)>;
+
+ /**
+ * Callback for users to invoke upon completion of, presumably asynchronous, OnWebSocketHandshakeIntercept
+ * callback's initiated process.
+ */
+ using OnWebSocketHandshakeInterceptComplete =
+ std::function<void(const std::shared_ptr<Http::HttpRequest> &, int errorCode)>;
+
+ /**
+ * Invoked during websocket handshake to give users opportunity to transform an http request for purposes
+ * such as signing/authorization etc... Returning from this function does not continue the websocket
+ * handshake since some work flows may be asynchronous. To accommodate that, onComplete must be invoked upon
+ * completion of the signing process.
+ */
+ using OnWebSocketHandshakeIntercept = std::function<
+ void(std::shared_ptr<Http::HttpRequest> req, const OnWebSocketHandshakeInterceptComplete &onComplete)>;
+
+ /* Simple statistics about the current state of the client's queue of operations */
+ struct AWS_CRT_CPP_API MqttConnectionOperationStatistics
+ {
+ /*
+ * total number of operations submitted to the connection that have not yet been completed. Unacked
+ * operations are a subset of this.
+ */
+ uint64_t incompleteOperationCount;
+
+ /*
+ * total packet size of operations submitted to the connection that have not yet been completed. Unacked
+ * operations are a subset of this.
+ */
+ uint64_t incompleteOperationSize;
+
+ /*
+ * total number of operations that have been sent to the server and are waiting for a corresponding ACK
+ * before they can be completed.
+ */
+ uint64_t unackedOperationCount;
+
+ /*
+ * total packet size of operations that have been sent to the server and are waiting for a corresponding
+ * ACK before they can be completed.
+ */
+ uint64_t unackedOperationSize;
+ };
+
+ /**
+ * Represents a persistent Mqtt Connection. The memory is owned by MqttClient.
+ * To get a new instance of this class, see MqttClient::NewConnection. Unless
+ * specified all function arguments need only to live through the duration of the
+ * function call.
+ */
+ class AWS_CRT_CPP_API MqttConnection final
+ {
+ friend class MqttClient;
+
+ public:
+ ~MqttConnection();
+ MqttConnection(const MqttConnection &) = delete;
+ MqttConnection(MqttConnection &&) = delete;
+ MqttConnection &operator=(const MqttConnection &) = delete;
+ MqttConnection &operator=(MqttConnection &&) = delete;
+
+ /**
+ * @return true if the instance is in a valid state, false otherwise.
+ */
+ operator bool() const noexcept;
+
+ /**
+ * @return the value of the last aws error encountered by operations on this instance.
+ */
+ int LastError() const noexcept;
+
+ /**
+ * Sets LastWill for the connection.
+ * @param topic topic the will message should be published to
+ * @param qos QOS the will message should be published with
+ * @param retain true if the will publish should be treated as a retained publish
+ * @param payload payload of the will message
+ * @return success/failure in setting the will
+ */
+ bool SetWill(const char *topic, QOS qos, bool retain, const ByteBuf &payload) noexcept;
+
+ /**
+ * Sets login credentials for the connection. The must get set before the Connect call
+ * if it is to be used.
+ * @param userName user name to add to the MQTT CONNECT packet
+ * @param password password to add to the MQTT CONNECT packet
+ * @return success/failure
+ */
+ bool SetLogin(const char *userName, const char *password) noexcept;
+
+ /**
+ * @deprecated Sets websocket proxy options. Replaced by SetHttpProxyOptions.
+ */
+ bool SetWebsocketProxyOptions(const Http::HttpClientConnectionProxyOptions &proxyOptions) noexcept;
+
+ /**
+ * Sets http proxy options. In order to use an http proxy with mqtt either
+ * (1) Websockets are used
+ * (2) Mqtt-over-tls is used and the ALPN list of the tls context contains a tag that resolves to mqtt
+ *
+ * @param proxyOptions proxy configuration for making the mqtt connection
+ *
+ * @return success/failure
+ */
+ bool SetHttpProxyOptions(const Http::HttpClientConnectionProxyOptions &proxyOptions) noexcept;
+
+ /**
+ * Customize time to wait between reconnect attempts.
+ * The time will start at min and multiply by 2 until max is reached.
+ * The time resets back to min after a successful connection.
+ * This function should only be called before Connect().
+ *
+ * @param min_seconds minimum time to wait before attempting a reconnect
+ * @param max_seconds maximum time to wait before attempting a reconnect
+ *
+ * @return success/failure
+ */
+ bool SetReconnectTimeout(uint64_t min_seconds, uint64_t max_seconds) noexcept;
+
+ /**
+ * Initiates the connection, OnConnectionCompleted will
+ * be invoked in an event-loop thread.
+ *
+ * @param clientId client identifier to use when establishing the mqtt connection
+ * @param cleanSession false to attempt to rejoin an existing session for the client id, true to skip
+ * and start with a new session
+ * @param keepAliveTimeSecs time interval to space mqtt pings apart by
+ * @param pingTimeoutMs timeout in milliseconds before the keep alive ping is considered to have failed
+ * @param protocolOperationTimeoutMs timeout in milliseconds to give up waiting for a response packet
+ * for an operation. Necessary due to throttling properties on certain server implementations that do
+ * not return an ACK for throttled operations.
+ *
+ * @return true if the connection attempt was successfully started (implying a callback will be invoked
+ * with the eventual result), false if it could not be started (no callback will happen)
+ */
+ bool Connect(
+ const char *clientId,
+ bool cleanSession,
+ uint16_t keepAliveTimeSecs = 0,
+ uint32_t pingTimeoutMs = 0,
+ uint32_t protocolOperationTimeoutMs = 0) noexcept;
+
+ /**
+ * Initiates disconnect, OnDisconnectHandler will be invoked in an event-loop thread.
+ * @return success/failure in initiating disconnect
+ */
+ bool Disconnect() noexcept;
+
+ /// @private
+ aws_mqtt_client_connection *GetUnderlyingConnection() noexcept;
+
+ /**
+ * Subscribes to topicFilter. OnMessageReceivedHandler will be invoked from an event-loop
+ * thread upon an incoming Publish message. OnSubAckHandler will be invoked
+ * upon receipt of a suback message.
+ *
+ * @param topicFilter topic filter to subscribe to
+ * @param qos maximum qos client is willing to receive matching messages on
+ * @param onMessage callback to invoke when a message is received based on matching this filter
+ * @param onSubAck callback to invoke with the server's response to the subscribe request
+ *
+ * @return packet id of the subscribe request, or 0 if the attempt failed synchronously
+ */
+ uint16_t Subscribe(
+ const char *topicFilter,
+ QOS qos,
+ OnMessageReceivedHandler &&onMessage,
+ OnSubAckHandler &&onSubAck) noexcept;
+
+ /**
+ * @deprecated Use alternate Subscribe()
+ */
+ uint16_t Subscribe(
+ const char *topicFilter,
+ QOS qos,
+ OnPublishReceivedHandler &&onPublish,
+ OnSubAckHandler &&onSubAck) noexcept;
+
+ /**
+ * Subscribes to multiple topicFilters. OnMessageReceivedHandler will be invoked from an event-loop
+ * thread upon an incoming Publish message. OnMultiSubAckHandler will be invoked
+ * upon receipt of a suback message.
+ *
+ * @param topicFilters list of pairs of topic filters and message callbacks to invoke on a matching
+ * publish
+ * @param qos maximum qos client is willing to receive matching messages on
+ * @param onOpComplete callback to invoke with the server's response to the subscribe request
+ *
+ * @return packet id of the subscribe request, or 0 if the attempt failed synchronously
+ */
+ uint16_t Subscribe(
+ const Vector<std::pair<const char *, OnMessageReceivedHandler>> &topicFilters,
+ QOS qos,
+ OnMultiSubAckHandler &&onOpComplete) noexcept;
+
+ /**
+ * @deprecated Use alternate Subscribe()
+ */
+ uint16_t Subscribe(
+ const Vector<std::pair<const char *, OnPublishReceivedHandler>> &topicFilters,
+ QOS qos,
+ OnMultiSubAckHandler &&onOpComplete) noexcept;
+
+ /**
+ * Installs a handler for all incoming publish messages, regardless of if Subscribe has been
+ * called on the topic.
+ *
+ * @param onMessage callback to invoke for all received messages
+ * @return success/failure
+ */
+ bool SetOnMessageHandler(OnMessageReceivedHandler &&onMessage) noexcept;
+
+ /**
+ * @deprecated Use alternate SetOnMessageHandler()
+ */
+ bool SetOnMessageHandler(OnPublishReceivedHandler &&onPublish) noexcept;
+
+ /**
+ * Unsubscribes from topicFilter. OnOperationCompleteHandler will be invoked upon receipt of
+ * an unsuback message.
+ *
+ * @param topicFilter topic filter to unsubscribe the session from
+ * @param onOpComplete callback to invoke on receipt of the server's UNSUBACK message
+ *
+ * @return packet id of the unsubscribe request, or 0 if the attempt failed synchronously
+ */
+ uint16_t Unsubscribe(const char *topicFilter, OnOperationCompleteHandler &&onOpComplete) noexcept;
+
+ /**
+ * Publishes to a topic.
+ *
+ * @param topic topic to publish to
+ * @param qos QOS to publish the message with
+ * @param retain should this message replace the current retained message of the topic?
+ * @param payload payload of the message
+ * @param onOpComplete completion callback to invoke when the operation is complete. If QoS is 0, then
+ * the callback is invoked when the message is passed to the tls handler, otherwise it's invoked
+ * on receipt of the final response from the server.
+ *
+ * @return packet id of the publish request, or 0 if the attempt failed synchronously
+ */
+ uint16_t Publish(
+ const char *topic,
+ QOS qos,
+ bool retain,
+ const ByteBuf &payload,
+ OnOperationCompleteHandler &&onOpComplete) noexcept;
+
+ /**
+ * Get the statistics about the current state of the connection's queue of operations
+ *
+ * @return MqttConnectionOperationStatistics
+ */
+ const MqttConnectionOperationStatistics &GetOperationStatistics() noexcept;
+
+ OnConnectionInterruptedHandler OnConnectionInterrupted;
+ OnConnectionResumedHandler OnConnectionResumed;
+ OnConnectionCompletedHandler OnConnectionCompleted;
+ OnDisconnectHandler OnDisconnect;
+ OnWebSocketHandshakeIntercept WebsocketInterceptor;
+
+ private:
+ aws_mqtt_client *m_owningClient;
+ aws_mqtt_client_connection *m_underlyingConnection;
+ String m_hostName;
+ uint16_t m_port;
+ Crt::Io::TlsContext m_tlsContext;
+ Io::TlsConnectionOptions m_tlsOptions;
+ Io::SocketOptions m_socketOptions;
+ Crt::Optional<Http::HttpClientConnectionProxyOptions> m_proxyOptions;
+ void *m_onAnyCbData;
+ bool m_useTls;
+ bool m_useWebsocket;
+ MqttConnectionOperationStatistics m_operationStatistics;
+
+ MqttConnection(
+ aws_mqtt_client *client,
+ const char *hostName,
+ uint16_t port,
+ const Io::SocketOptions &socketOptions,
+ const Crt::Io::TlsContext &tlsContext,
+ bool useWebsocket) noexcept;
+
+ MqttConnection(
+ aws_mqtt_client *client,
+ const char *hostName,
+ uint16_t port,
+ const Io::SocketOptions &socketOptions,
+ bool useWebsocket) noexcept;
+
+ static void s_onConnectionInterrupted(aws_mqtt_client_connection *, int errorCode, void *userData);
+ static void s_onConnectionCompleted(
+ aws_mqtt_client_connection *,
+ int errorCode,
+ enum aws_mqtt_connect_return_code returnCode,
+ bool sessionPresent,
+ void *userData);
+ static void s_onConnectionResumed(
+ aws_mqtt_client_connection *,
+ ReturnCode returnCode,
+ bool sessionPresent,
+ void *userData);
+
+ static void s_onDisconnect(aws_mqtt_client_connection *connection, void *userData);
+ static void s_onPublish(
+ aws_mqtt_client_connection *connection,
+ const aws_byte_cursor *topic,
+ const aws_byte_cursor *payload,
+ bool dup,
+ enum aws_mqtt_qos qos,
+ bool retain,
+ void *user_data);
+
+ static void s_onSubAck(
+ aws_mqtt_client_connection *connection,
+ uint16_t packetId,
+ const struct aws_byte_cursor *topic,
+ enum aws_mqtt_qos qos,
+ int error_code,
+ void *userdata);
+ static void s_onMultiSubAck(
+ aws_mqtt_client_connection *connection,
+ uint16_t packetId,
+ const struct aws_array_list *topic_subacks,
+ int error_code,
+ void *userdata);
+ static void s_onOpComplete(
+ aws_mqtt_client_connection *connection,
+ uint16_t packetId,
+ int errorCode,
+ void *userdata);
+
+ static void s_onWebsocketHandshake(
+ struct aws_http_message *request,
+ void *user_data,
+ aws_mqtt_transform_websocket_handshake_complete_fn *complete_fn,
+ void *complete_ctx);
+
+ static void s_connectionInit(
+ MqttConnection *self,
+ const char *hostName,
+ uint16_t port,
+ const Io::SocketOptions &socketOptions);
+ };
+
+ /**
+ * An MQTT client. This is a move-only type. Unless otherwise specified,
+ * all function arguments need only to live through the duration of the
+ * function call.
+ */
+ class AWS_CRT_CPP_API MqttClient final
+ {
+ public:
+ /**
+ * Initialize an MqttClient using bootstrap and allocator
+ */
+ MqttClient(Io::ClientBootstrap &bootstrap, Allocator *allocator = ApiAllocator()) noexcept;
+
+ /**
+ * Initialize an MqttClient using a allocator and the default ClientBootstrap
+ *
+ * For more information on the default ClientBootstrap see
+ * Aws::Crt::ApiHandle::GetOrCreateStaticDefaultClientBootstrap
+ */
+ MqttClient(Allocator *allocator = ApiAllocator()) noexcept;
+
+ ~MqttClient();
+ MqttClient(const MqttClient &) = delete;
+ MqttClient(MqttClient &&) noexcept;
+ MqttClient &operator=(const MqttClient &) = delete;
+ MqttClient &operator=(MqttClient &&) noexcept;
+
+ /**
+ * @return true if the instance is in a valid state, false otherwise.
+ */
+ operator bool() const noexcept;
+
+ /**
+ * @return the value of the last aws error encountered by operations on this instance.
+ */
+ int LastError() const noexcept;
+
+ /**
+ * Create a new connection object using TLS from the client. The client must outlive
+ * all of its connection instances.
+ *
+ * @param hostName endpoint to connect to
+ * @param port port to connect to
+ * @param socketOptions socket options to use when establishing the connection
+ * @param tlsContext tls context to use with the connection
+ * @param useWebsocket should the connection use websockets or should it use direct mqtt?
+ *
+ * @return a new connection object. Connect() will still need to be called after all further
+ * configuration is finished.
+ */
+ std::shared_ptr<MqttConnection> NewConnection(
+ const char *hostName,
+ uint16_t port,
+ const Io::SocketOptions &socketOptions,
+ const Crt::Io::TlsContext &tlsContext,
+ bool useWebsocket = false) noexcept;
+
+ /**
+ * Create a new connection object over plain text from the client. The client must outlive
+ * all of its connection instances.
+ * @param hostName endpoint to connect to
+ * @param port port to connect to
+ * @param socketOptions socket options to use when establishing the connection
+ * @param useWebsocket should the connection use websockets or should it use direct mqtt?
+ *
+ * @return a new connection object. Connect() will still need to be called after all further
+ * configuration is finished.
+ */
+ std::shared_ptr<MqttConnection> NewConnection(
+ const char *hostName,
+ uint16_t port,
+ const Io::SocketOptions &socketOptions,
+ bool useWebsocket = false) noexcept;
+
+ private:
+ aws_mqtt_client *m_client;
+ };
+ } // namespace Mqtt
+ } // namespace Crt
+} // namespace Aws
diff --git a/contrib/restricted/aws/aws-crt-cpp/include/aws/iot/Mqtt5Client.h b/contrib/restricted/aws/aws-crt-cpp/include/aws/iot/Mqtt5Client.h
new file mode 100644
index 0000000000..4c22917013
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/include/aws/iot/Mqtt5Client.h
@@ -0,0 +1,548 @@
+#pragma once
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+#include <aws/crt/Config.h>
+#include <aws/crt/Exports.h>
+#include <aws/crt/auth/Sigv4Signing.h>
+#include <aws/crt/mqtt/Mqtt5Client.h>
+#include <aws/iot/MqttCommon.h>
+
+#if !BYO_CRYPTO
+
+namespace Aws
+{
+ using namespace Crt::Mqtt5;
+
+ namespace Io
+ {
+ class ClientBootstrap;
+ class SocketOptions;
+ class TlsContextOptions;
+ class WebsocketConfig;
+ } // namespace Io
+
+ namespace Iot
+ {
+
+ /**
+ * Class encapsulating configuration for establishing an Aws IoT Mqtt5 Connectin with custom authorizer
+ */
+ class AWS_CRT_CPP_API Mqtt5CustomAuthConfig
+ {
+ public:
+ /**
+ * Create a custom authorizer configuration
+ */
+ Mqtt5CustomAuthConfig(Crt::Allocator *allocator = Crt::ApiAllocator()) noexcept;
+ virtual ~Mqtt5CustomAuthConfig();
+
+ Mqtt5CustomAuthConfig(const Mqtt5CustomAuthConfig &rhs);
+ Mqtt5CustomAuthConfig(Mqtt5CustomAuthConfig &&rhs) = delete;
+
+ Mqtt5CustomAuthConfig &operator=(const Mqtt5CustomAuthConfig &rhs);
+ Mqtt5CustomAuthConfig &operator=(Mqtt5CustomAuthConfig &&rhs) = delete;
+
+ Mqtt5CustomAuthConfig &WithAuthorizerName(Crt::String authName);
+ Mqtt5CustomAuthConfig &WithUsername(Crt::String username);
+ Mqtt5CustomAuthConfig &WithPassword(Crt::ByteCursor password);
+ Mqtt5CustomAuthConfig &WithTokenKeyName(Crt::String tokenKeyName);
+ Mqtt5CustomAuthConfig &WithTokenValue(Crt::String tokenValue);
+ Mqtt5CustomAuthConfig &WithTokenSignature(Crt::String tokenSignature);
+
+ const Crt::Optional<Crt::String> &GetAuthorizerName();
+ const Crt::Optional<Crt::String> &GetUsername();
+ const Crt::Optional<Crt::ByteCursor> &GetPassword();
+ const Crt::Optional<Crt::String> &GetTokenKeyName();
+ const Crt::Optional<Crt::String> &GetTokenValue();
+ const Crt::Optional<Crt::String> &GetTokenSignature();
+
+ private:
+ /**
+ * Name of the custom authorizer to use.
+ *
+ * Required if the endpoint does not have a default custom authorizer associated with it. It is strongly
+ * suggested to URL-encode this value; the SDK will not do so for you.
+ */
+ Crt::Optional<Crt::String> m_authorizerName;
+
+ /**
+ * The username to use with the custom authorizer. Query-string elements of this property value will be
+ * unioned with the query-string elements implied by other properties in this object.
+ *
+ * For example, if you set this to:
+ *
+ * 'MyUsername?someKey=someValue'
+ *
+ * and use {@link authorizerName} to specify the authorizer, the final username would look like:
+ *
+ * `MyUsername?someKey=someValue&x-amz-customauthorizer-name=<your authorizer's name>&...`
+ */
+ Crt::Optional<Crt::String> m_username;
+
+ /**
+ * The password to use with the custom authorizer. Becomes the MQTT5 CONNECT packet's password property.
+ * AWS IoT Core will base64 encode this binary data before passing it to the authorizer's lambda function.
+ */
+ Crt::Optional<Crt::ByteCursor> m_password;
+
+ /**
+ * Key used to extract the custom authorizer token from MQTT username query-string properties.
+ *
+ * Required if the custom authorizer has signing enabled. It is strongly suggested to URL-encode this
+ * value; the SDK will not do so for you.
+ */
+ Crt::Optional<Crt::String> m_tokenKeyName;
+
+ /**
+ * An opaque token value. This value must be signed by the private key associated with the custom authorizer
+ * and the result placed in the {@link tokenSignature} property.
+ *
+ * Required if the custom authorizer has signing enabled.
+ */
+ Crt::Optional<Crt::String> m_tokenValue;
+
+ /**
+ * The digital signature of the token value in the {@link tokenValue} property. The signature must be based
+ * on the private key associated with the custom authorizer. The signature must be base64 encoded.
+ *
+ * Required if the custom authorizer has signing enabled. It is strongly suggested to URL-encode this
+ * value; the SDK will not do so for you.
+ */
+ Crt::Optional<Crt::String> m_tokenSignature;
+
+ Crt::ByteBuf m_passwordStorage;
+ Crt::Allocator *m_allocator;
+ };
+
+ /**
+ * Represents a unique configuration for mqtt5 client and connection. Helps to setup Mqtt5ClientOptionsBuilder
+ * for mqtt5 client.
+ */
+ class AWS_CRT_CPP_API Mqtt5ClientBuilder final
+ {
+ public:
+ /**
+ * Set the builder up for MTLS using certPath and pkeyPath. These are files on disk and must be in the
+ * PEM format.
+ *
+ * @param hostName - AWS IoT endpoint to connect to
+ * @param certPath path to the X509 certificate (pem file) to use
+ * @param pkeyPath path to the private key (pem file) to use
+ * @param allocator memory allocator to use
+ *
+ * @return Mqtt5ClientBuilder
+ */
+ static Mqtt5ClientBuilder *NewMqtt5ClientBuilderWithMtlsFromPath(
+ const Crt::String hostName,
+ const char *certPath,
+ const char *pkeyPath,
+ Crt::Allocator *allocator = Crt::ApiAllocator()) noexcept;
+
+ /**
+ * Sets the builder up for MTLS using cert and pkey. These are in-memory buffers and must be in the PEM
+ * format.
+ *
+ * @param hostName - AWS IoT endpoint to connect to
+ * @param certPath buffer containing the X509 certificate in a PEM format
+ * @param pkeyPath buffer containing the private key in a PEM format
+ * @param allocator memory allocator to use
+ *
+ * @return Mqtt5ClientBuilder
+ */
+ static Mqtt5ClientBuilder *NewMqtt5ClientBuilderWithMtlsFromMemory(
+ const Crt::String hostName,
+ const Crt::ByteCursor &certPath,
+ const Crt::ByteCursor &pkeyPath,
+ Crt::Allocator *allocator = Crt::ApiAllocator()) noexcept;
+
+ /**
+ * Sets the builder up for MTLS, using a PKCS#11 library for private key operations.
+ *
+ * NOTE: This only works on Unix devices.
+ *
+ * @param hostName - AWS IoT endpoint to connect to
+ * @param pkcs11Options PKCS#11 options
+ * @param allocator memory allocator to use
+ *
+ * @return Mqtt5ClientBuilder
+ */
+ static Mqtt5ClientBuilder *NewMqtt5ClientBuilderWithMtlsPkcs11(
+ const Crt::String hostName,
+ const Crt::Io::TlsContextPkcs11Options &pkcs11Options,
+ Crt::Allocator *allocator = Crt::ApiAllocator()) noexcept;
+
+ /**
+ * Sets the builder up for MTLS, using a certificate in a Windows certificate store.
+ *
+ * NOTE: This only works on Windows.
+ *
+ * @param hostName - AWS IoT endpoint to connect to
+ * @param windowsCertStorePath Path to certificate in a Windows certificate store.
+ * The path must use backslashes and end with the certificate's thumbprint.
+ * Example: `CurrentUser\MY\A11F8A9B5DF5B98BA3508FBCA575D09570E0D2C6`
+ * @param allocator memory allocator to use
+ *
+ * @return Mqtt5ClientBuilder
+ */
+ static Mqtt5ClientBuilder *NewMqtt5ClientBuilderWithWindowsCertStorePath(
+ const Crt::String hostName,
+ const char *windowsCertStorePath,
+ Crt::Allocator *allocator = Crt::ApiAllocator()) noexcept;
+
+ /**
+ * Sets the builder up for Websocket connection.
+ *
+ * @param hostName - AWS IoT endpoint to connect to
+ * @param config websocket configuration information
+ * @param allocator memory allocator to use
+ *
+ * Mqtt5ClientBuilder
+ */
+ static Mqtt5ClientBuilder *NewMqtt5ClientBuilderWithWebsocket(
+ const Crt::String hostName,
+ const WebsocketConfig &config,
+ Crt::Allocator *allocator = Crt::ApiAllocator()) noexcept;
+
+ /**
+ * Sets the builder up for connection using authorization configuration.
+ *
+ * @param hostName - AWS IoT endpoint to connect to
+ * @param customAuthConfig custom authorization configuration information
+ * @param allocator memory allocator to use
+ *
+ * Mqtt5ClientBuilder
+ */
+ static Mqtt5ClientBuilder *NewMqtt5ClientBuilderWithCustomAuthorizer(
+ const Crt::String hostName,
+ const Mqtt5CustomAuthConfig &customAuthConfig,
+ Crt::Allocator *allocator) noexcept;
+
+ /**
+ * Sets the builder up for connection using authorization configuration using Websockets.
+ *
+ * @param hostName - AWS IoT endpoint to connect to
+ * @param customAuthConfig custom authorization configuration information
+ * @param config websocket configuration information
+ * @param allocator memory allocator to use
+ *
+ * Mqtt5ClientBuilder
+ */
+ static Mqtt5ClientBuilder *NewMqtt5ClientBuilderWithCustomAuthorizerWebsocket(
+ const Crt::String hostName,
+ const Mqtt5CustomAuthConfig &customAuthConfig,
+ const WebsocketConfig &config,
+ Crt::Allocator *allocator) noexcept;
+
+ /**
+ * Sets the host to connect to.
+ *
+ * @param hostname endpoint to connect to
+ *
+ * @return this option object
+ */
+ Mqtt5ClientBuilder &withHostName(Crt::String hostname);
+
+ /**
+ * Set port to connect to
+ *
+ * @param port port to connect to
+ *
+ * @return this option object
+ */
+ Mqtt5ClientBuilder &withPort(uint16_t port) noexcept;
+
+ /**
+ * Sets the certificate authority for the endpoint you're connecting to. This is a path to a file on disk
+ * and must be in PEM format.
+ *
+ * @param caPath path to the CA file in PEM format
+ *
+ * @return this builder object
+ */
+ Mqtt5ClientBuilder &WithCertificateAuthority(const char *caPath) noexcept;
+
+ /**
+ * Sets the certificate authority for the endpoint you're connecting to. This is an in-memory buffer and
+ * must be in PEM format.
+ *
+ * @param cert buffer containing the CA certificate in a PEM format
+ *
+ * @return this builder object
+ */
+ Mqtt5ClientBuilder &WithCertificateAuthority(const Crt::ByteCursor &cert) noexcept;
+
+ /**
+ * Sets http proxy options.
+ *
+ * @param proxyOptions http proxy configuration for connection establishment
+ *
+ * @return this option object
+ */
+ Mqtt5ClientBuilder &withHttpProxyOptions(
+ const Crt::Http::HttpClientConnectionProxyOptions &proxyOptions) noexcept;
+
+ /**
+ * Sets the custom authorizer settings. This function will modify the username, port, and TLS options.
+ *
+ * @return this builder object
+ */
+ Mqtt5ClientBuilder &WithCustomAuthorizer(const Iot::Mqtt5CustomAuthConfig &config) noexcept;
+
+ /**
+ * Sets mqtt5 connection options
+ *
+ * @param packetConnect package connection options
+ *
+ * @return this option object
+ */
+ Mqtt5ClientBuilder &withConnectOptions(std::shared_ptr<ConnectPacket> packetConnect) noexcept;
+
+ /**
+ * Sets session behavior. Overrides how the MQTT5 client should behave with respect to MQTT sessions.
+ *
+ * @param sessionBehavior how the MQTT5 client should behave with respect to MQTT sessions.
+ *
+ * @return this option object
+ */
+ Mqtt5ClientBuilder &withSessionBehavior(ClientSessionBehaviorType sessionBehavior) noexcept;
+
+ /**
+ * Sets client extended validation and flow control, additional controls for client behavior with
+ * respect to operation validation and flow control; these checks go beyond the base MQTT5 spec to
+ * respect limits of specific MQTT brokers.
+ *
+ * @param clientExtendedValidationAndFlowControl
+ *
+ * @return this option object
+ */
+ Mqtt5ClientBuilder &withClientExtendedValidationAndFlowControl(
+ ClientExtendedValidationAndFlowControl clientExtendedValidationAndFlowControl) noexcept;
+
+ /**
+ * Sets OfflineQueueBehavior, controls how disconnects affect the queued and in-progress operations
+ * tracked by the client. Also controls how new operations are handled while the client is not
+ * connected. In particular, if the client is not connected, then any operation that would be failed
+ * on disconnect (according to these rules) will also be rejected.
+ *
+ * @param offlineQueueBehavior
+ *
+ * @return this option object
+ */
+ Mqtt5ClientBuilder &withOfflineQueueBehavior(
+ ClientOperationQueueBehaviorType offlineQueueBehavior) noexcept;
+
+ /**
+ * Sets ReconnectOptions. Reconnect options includes retryJitterMode, min reconnect delay time and
+ * max reconnect delay time
+ *
+ * @param reconnectOptions
+ *
+ * @return this option object
+ */
+ Mqtt5ClientBuilder &withReconnectOptions(ReconnectOptions reconnectOptions) noexcept;
+
+ /**
+ * Sets minConnectedTimeToResetReconnectDelayMs, amount of time that must elapse with an established
+ * connection before the reconnect delay is reset to the minimum. This helps alleviate bandwidth-waste
+ * in fast reconnect cycles due to permission failures on operations.
+ *
+ * @param minConnectedTimeToResetReconnectDelayMs
+ *
+ * @return this option object
+ */
+ Mqtt5ClientBuilder &withMinConnectedTimeToResetReconnectDelayMs(
+ uint64_t minConnectedTimeToResetReconnectDelayMs) noexcept;
+
+ /**
+ * Sets ping timeout (ms). Time interval to wait after sending a PINGREQ for a PINGRESP to arrive.
+ * If one does not arrive, the client will close the current connection.
+ *
+ * @param pingTimeoutMs
+ *
+ * @return this option object
+ */
+ Mqtt5ClientBuilder &withPingTimeoutMs(uint32_t pingTimeoutMs) noexcept;
+
+ /**
+ * Sets Connack Timeout (ms). Time interval to wait after sending a CONNECT request for a CONNACK
+ * to arrive. If one does not arrive, the connection will be shut down.
+ *
+ * @param connackTimeoutMs
+ *
+ * @return this option object
+ */
+ Mqtt5ClientBuilder &withConnackTimeoutMs(uint32_t connackTimeoutMs) noexcept;
+
+ /**
+ * Sets Operation Timeout(Seconds). Time interval to wait for an ack after sending a QoS 1+ PUBLISH,
+ * SUBSCRIBE, or UNSUBSCRIBE before failing the operation.
+ *
+ * @param ackTimeoutSeconds
+ *
+ * @return this option object
+ */
+ Mqtt5ClientBuilder &withAckTimeoutSeconds(uint32_t ackTimeoutSeconds) noexcept;
+
+ /**
+ * Overrides the default SDK Name to send as a metric in the MQTT CONNECT packet.
+ *
+ * @param sdkName string to use as the SDK name parameter in the connection string
+ *
+ * @return this builder object
+ */
+ Mqtt5ClientBuilder &WithSdkName(const Crt::String &sdkName);
+
+ /**
+ * Overrides the default SDK Version to send as a metric in the MQTT CONNECT packet.
+ *
+ * @param sdkVersion string to use as the SDK version parameter in the connection string
+ *
+ * @return this builder object
+ */
+ Mqtt5ClientBuilder &WithSdkVersion(const Crt::String &sdkVersion);
+
+ /**
+ * Builds a client configuration object from the set options.
+ *
+ * @return a new client connection config instance
+ */
+ std::shared_ptr<Mqtt5Client> Build() noexcept;
+
+ /**
+ * @return true if the instance is in a valid state, false otherwise.
+ */
+ explicit operator bool() const noexcept { return m_lastError == 0; }
+
+ /**
+ * @return the value of the last aws error encountered by operations on this instance.
+ */
+ int LastError() const noexcept { return m_lastError ? m_lastError : AWS_ERROR_UNKNOWN; }
+
+ virtual ~Mqtt5ClientBuilder()
+ {
+ if (m_options)
+ {
+ delete m_options;
+ }
+ };
+ Mqtt5ClientBuilder(const Mqtt5ClientBuilder &) = delete;
+ Mqtt5ClientBuilder(Mqtt5ClientBuilder &&) = delete;
+ Mqtt5ClientBuilder &operator=(const Mqtt5ClientBuilder &) = delete;
+ Mqtt5ClientBuilder &operator=(Mqtt5ClientBuilder &&) = delete;
+
+ /**
+ * Setup callback trigged when client successfully establishes an MQTT connection
+ *
+ * @param callback
+ *
+ * @return this option object
+ */
+ Mqtt5ClientBuilder &withClientConnectionSuccessCallback(OnConnectionSuccessHandler callback) noexcept;
+
+ /**
+ * Setup callback trigged when client fails to establish an MQTT connection
+ *
+ * @param callback
+ *
+ * @return this option object
+ */
+ Mqtt5ClientBuilder &withClientConnectionFailureCallback(OnConnectionFailureHandler callback) noexcept;
+
+ /**
+ * Setup callback handler trigged when client's current MQTT connection is closed
+ *
+ * @param callback
+ *
+ * @return this option object
+ */
+ Mqtt5ClientBuilder &withClientDisconnectionCallback(OnDisconnectionHandler callback) noexcept;
+
+ /**
+ * Setup callback handler trigged when client reaches the "Stopped" state
+ *
+ * @param callback
+ *
+ * @return this option object
+ */
+ Mqtt5ClientBuilder &withClientStoppedCallback(OnStoppedHandler callback) noexcept;
+
+ /**
+ * Setup callback handler trigged when client begins an attempt to connect to the remote endpoint.
+ *
+ * @param callback
+ *
+ * @return this option object
+ */
+ Mqtt5ClientBuilder &withClientAttemptingConnectCallback(OnAttemptingConnectHandler callback) noexcept;
+
+ /**
+ * Setup callback handler trigged when an MQTT PUBLISH packet is received by the client
+ *
+ * @param callback
+ *
+ * @return this option object
+ */
+ Mqtt5ClientBuilder &withPublishReceivedCallback(OnPublishReceivedHandler callback) noexcept;
+
+ private:
+ // Common setup shared by all valid constructors
+ Mqtt5ClientBuilder(Crt::Allocator *allocator) noexcept;
+ // Common setup shared by all valid constructors
+ Mqtt5ClientBuilder(int error, Crt::Allocator *allocator) noexcept;
+
+ Crt::Allocator *m_allocator;
+
+ /**
+ * Network port of the MQTT server to connect to.
+ */
+ uint16_t m_port;
+
+ /**
+ * Client bootstrap to use. In almost all cases, this can be left undefined.
+ */
+ Io::ClientBootstrap *m_bootstrap;
+
+ /**
+ * TLS context for secure socket connections.
+ * If undefined, then a plaintext connection will be used.
+ */
+ Crt::Optional<Crt::Io::TlsContextOptions> m_tlsConnectionOptions;
+
+ /**
+ * Configures (tunneling) HTTP proxy usage when establishing MQTT connections
+ */
+ Crt::Optional<Crt::Http::HttpClientConnectionProxyOptions> m_proxyOptions;
+
+ /**
+ * Websocket related options. The clinet with use websocket for connection when set.
+ */
+ Crt::Optional<WebsocketConfig> m_websocketConfig;
+
+ /**
+ * Custom Authorizer Configuration
+ */
+ Crt::Optional<Mqtt5CustomAuthConfig> m_customAuthConfig;
+
+ /**
+ * All configurable options with respect to the CONNECT packet sent by the client, including the will.
+ * These connect properties will be used for every connection attempt made by the client.
+ */
+ std::shared_ptr<ConnectPacket> m_connectOptions;
+
+ Crt::Mqtt5::Mqtt5ClientOptions *m_options;
+
+ /* Error */
+ int m_lastError;
+
+ bool m_enableMetricsCollection;
+
+ Crt::String m_sdkName = "CPPv2";
+ Crt::String m_sdkVersion = AWS_CRT_CPP_VERSION;
+ };
+
+ } // namespace Iot
+} // namespace Aws
+
+#endif // !BYO_CRYPTO
diff --git a/contrib/restricted/aws/aws-crt-cpp/include/aws/iot/MqttClient.h b/contrib/restricted/aws/aws-crt-cpp/include/aws/iot/MqttClient.h
new file mode 100644
index 0000000000..7fc2d60e8a
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/include/aws/iot/MqttClient.h
@@ -0,0 +1,450 @@
+#pragma once
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+#include <aws/crt/Config.h>
+#include <aws/crt/Exports.h>
+#include <aws/crt/auth/Sigv4Signing.h>
+#include <aws/crt/mqtt/MqttClient.h>
+#include <aws/iot/MqttCommon.h>
+
+#if !BYO_CRYPTO
+
+namespace Aws
+{
+ namespace Iot
+ {
+ class MqttClient;
+
+ /**
+ * Represents a unique configuration for connecting to a single AWS IoT endpoint. You can use a single instance
+ * of this class PER endpoint you want to connect to. This object must live through the lifetime of your
+ * connection.
+ */
+ class AWS_CRT_CPP_API MqttClientConnectionConfig final
+ {
+ public:
+ static MqttClientConnectionConfig CreateInvalid(int lastError) noexcept;
+
+ /**
+ * Creates a client configuration for use with making new AWS Iot specific MQTT Connections with MTLS.
+ *
+ * @param endpoint endpoint to connect to
+ * @param port port to connect to
+ * @param socketOptions socket options to use when establishing the connection
+ * @param tlsContext tls context that should be used for all connections sourced from this config
+ */
+ MqttClientConnectionConfig(
+ const Crt::String &endpoint,
+ uint16_t port,
+ const Crt::Io::SocketOptions &socketOptions,
+ Crt::Io::TlsContext &&tlsContext);
+
+ /**
+ * Creates a client configuration for use with making new AWS Iot specific MQTT Connections with web
+ * sockets. interceptor: a callback invoked during web socket handshake giving you the opportunity to mutate
+ * the request for authorization/signing purposes. If not specified, it's assumed you don't need to sign the
+ * request. proxyOptions: optional, if you want to use a proxy with websockets, specify the configuration
+ * options here.
+ *
+ * If proxy options are used, the tlsContext is applied to the connection to the remote endpoint, NOT the
+ * proxy. To make a tls connection to the proxy itself, you'll want to specify tls options in proxyOptions.
+ *
+ * @param endpoint endpoint to connect to
+ * @param port port to connect to
+ * @param socketOptions socket options to use when establishing the connection
+ * @param tlsContext tls context that should be used for all connections sourced from this config
+ * @param interceptor websocket upgrade handshake transformation function
+ * @param proxyOptions proxy configuration options
+ */
+ MqttClientConnectionConfig(
+ const Crt::String &endpoint,
+ uint16_t port,
+ const Crt::Io::SocketOptions &socketOptions,
+ Crt::Io::TlsContext &&tlsContext,
+ Crt::Mqtt::OnWebSocketHandshakeIntercept &&interceptor,
+ const Crt::Optional<Crt::Http::HttpClientConnectionProxyOptions> &proxyOptions);
+
+ /**
+ * @return true if the instance is in a valid state, false otherwise.
+ */
+ explicit operator bool() const noexcept { return m_context ? true : false; }
+
+ /**
+ * @return the value of the last aws error encountered by operations on this instance.
+ */
+ int LastError() const noexcept { return m_lastError; }
+
+ private:
+ MqttClientConnectionConfig(int lastError) noexcept;
+
+ MqttClientConnectionConfig(
+ const Crt::String &endpoint,
+ uint16_t port,
+ const Crt::Io::SocketOptions &socketOptions,
+ Crt::Io::TlsContext &&tlsContext,
+ const Crt::Optional<Crt::Http::HttpClientConnectionProxyOptions> &proxyOptions);
+
+ Crt::String m_endpoint;
+ uint16_t m_port;
+ Crt::Io::TlsContext m_context;
+ Crt::Io::SocketOptions m_socketOptions;
+ Crt::Mqtt::OnWebSocketHandshakeIntercept m_webSocketInterceptor;
+ Crt::String m_username;
+ Crt::String m_password;
+ Crt::Optional<Crt::Http::HttpClientConnectionProxyOptions> m_proxyOptions;
+ int m_lastError;
+
+ friend class MqttClient;
+ friend class MqttClientConnectionConfigBuilder;
+ };
+
+ /**
+ * Represents configuration parameters for building a MqttClientConnectionConfig object. You can use a single
+ * instance of this class PER MqttClientConnectionConfig you want to generate. If you want to generate a config
+ * for a different endpoint or port etc... you need a new instance of this class.
+ */
+ class AWS_CRT_CPP_API MqttClientConnectionConfigBuilder final
+ {
+ public:
+ MqttClientConnectionConfigBuilder();
+
+ /**
+ * Sets the builder up for MTLS using certPath and pkeyPath. These are files on disk and must be in the PEM
+ * format.
+ *
+ * @param certPath path to the X509 certificate (pem file) to use
+ * @param pkeyPath path to the private key (pem file) to use
+ * @param allocator memory allocator to use
+ */
+ MqttClientConnectionConfigBuilder(
+ const char *certPath,
+ const char *pkeyPath,
+ Crt::Allocator *allocator = Crt::ApiAllocator()) noexcept;
+
+ /**
+ * Sets the builder up for MTLS using cert and pkey. These are in-memory buffers and must be in the PEM
+ * format.
+ *
+ * @param cert buffer containing the X509 certificate in a PEM format
+ * @param pkey buffer containing the private key in a PEM format
+ * @param allocator memory allocator to use
+ */
+ MqttClientConnectionConfigBuilder(
+ const Crt::ByteCursor &cert,
+ const Crt::ByteCursor &pkey,
+ Crt::Allocator *allocator = Crt::ApiAllocator()) noexcept;
+
+ /**
+ * Sets the builder up for MTLS, using a PKCS#11 library for private key operations.
+ *
+ * NOTE: This only works on Unix devices.
+ *
+ * @param pkcs11Options PKCS#11 options
+ * @param allocator memory allocator to use
+ */
+ MqttClientConnectionConfigBuilder(
+ const Crt::Io::TlsContextPkcs11Options &pkcs11Options,
+ Crt::Allocator *allocator = Crt::ApiAllocator()) noexcept;
+
+ /**
+ * Sets the builder up for MTLS, using a certificate in a Windows certificate store.
+ *
+ * NOTE: This only works on Windows.
+ *
+ * @param windowsCertStorePath Path to certificate in a Windows certificate store.
+ * The path must use backslashes and end with the certificate's thumbprint.
+ * Example: `CurrentUser\MY\A11F8A9B5DF5B98BA3508FBCA575D09570E0D2C6`
+ * @param allocator memory allocator to use
+ */
+ MqttClientConnectionConfigBuilder(
+ const char *windowsCertStorePath,
+ Crt::Allocator *allocator = Crt::ApiAllocator()) noexcept;
+
+ /**
+ * Sets the builder up for Websocket connection.
+ *
+ * @param config websocket configuration information
+ * @param allocator memory allocator to use
+ */
+ MqttClientConnectionConfigBuilder(
+ const WebsocketConfig &config,
+ Crt::Allocator *allocator = Crt::ApiAllocator()) noexcept;
+
+ /**
+ * Creates a new builder with default Tls options. This requires setting the connection details manually.
+ *
+ * @return a new builder with default Tls options
+ */
+ static MqttClientConnectionConfigBuilder NewDefaultBuilder() noexcept;
+
+ /**
+ * Sets endpoint to connect to.
+ *
+ * @param endpoint endpoint to connect to
+ *
+ * @return this builder object
+ */
+ MqttClientConnectionConfigBuilder &WithEndpoint(const Crt::String &endpoint);
+
+ /**
+ * Sets endpoint to connect to.
+ *
+ * @param endpoint endpoint to connect to
+ *
+ * @return this builder object
+ */
+ MqttClientConnectionConfigBuilder &WithEndpoint(Crt::String &&endpoint);
+
+ /**
+ * Overrides the default port. By default, if ALPN is supported, 443 will be used. Otherwise 8883 will be
+ * used. If you specify 443 and ALPN is not supported, we will still attempt to connect over 443 without
+ * ALPN.
+ *
+ * @param port port to connect to
+ *
+ * @return this builder object
+ */
+ MqttClientConnectionConfigBuilder &WithPortOverride(uint16_t port) noexcept;
+
+ /**
+ * Sets the certificate authority for the endpoint you're connecting to. This is a path to a file on disk
+ * and must be in PEM format.
+ *
+ * @param caPath path to the CA file in PEM format
+ *
+ * @return this builder object
+ */
+ MqttClientConnectionConfigBuilder &WithCertificateAuthority(const char *caPath) noexcept;
+
+ /**
+ * Sets the certificate authority for the endpoint you're connecting to. This is an in-memory buffer and
+ * must be in PEM format.
+ *
+ * @param cert buffer containing the CA certificate in a PEM format
+ *
+ * @return this builder object
+ */
+ MqttClientConnectionConfigBuilder &WithCertificateAuthority(const Crt::ByteCursor &cert) noexcept;
+
+ /**
+ * TCP option: Enables TCP keep alive. Defaults to off.
+ *
+ * @return this builder object
+ */
+ MqttClientConnectionConfigBuilder &WithTcpKeepAlive() noexcept;
+
+ /**
+ * TCP option: Sets the connect timeout. Defaults to 3 seconds.
+ *
+ * @param connectTimeoutMs socket connection timeout
+ *
+ * @return this builder object
+ */
+ MqttClientConnectionConfigBuilder &WithTcpConnectTimeout(uint32_t connectTimeoutMs) noexcept;
+
+ /**
+ * TCP option: Sets time before keep alive probes are sent. Defaults to kernel defaults
+ *
+ * @param keepAliveTimeoutSecs time interval of no activity, in seconds, before keep alive probes
+ * get sent
+ *
+ * @return this builder object
+ */
+ MqttClientConnectionConfigBuilder &WithTcpKeepAliveTimeout(uint16_t keepAliveTimeoutSecs) noexcept;
+
+ /**
+ * TCP option: Sets the frequency of sending keep alive probes in seconds once the keep alive timeout
+ * expires. Defaults to kernel defaults.
+ *
+ * @param keepAliveIntervalSecs the frequency of sending keep alive probes in seconds once the keep alive
+ * timeout expires
+ *
+ * @return this builder object
+ */
+ MqttClientConnectionConfigBuilder &WithTcpKeepAliveInterval(uint16_t keepAliveIntervalSecs) noexcept;
+
+ /**
+ * TCP option: Sets the amount of keep alive probes allowed to fail before the connection is terminated.
+ * Defaults to kernel defaults.
+ *
+ * @param maxProbes the amount of keep alive probes allowed to fail before the connection is terminated
+ *
+ * @return this builder object
+ */
+ MqttClientConnectionConfigBuilder &WithTcpKeepAliveMaxProbes(uint16_t maxProbes) noexcept;
+
+ /**
+ * Sets the minimum tls version that is acceptable for connection establishment
+ *
+ * @param minimumTlsVersion minimum tls version allowed in client connections
+ *
+ * @return this builder object
+ */
+ MqttClientConnectionConfigBuilder &WithMinimumTlsVersion(aws_tls_versions minimumTlsVersion) noexcept;
+
+ /**
+ * Sets http proxy options.
+ *
+ * @param proxyOptions proxy configuration options for connection establishment
+ *
+ * @return this builder object
+ */
+ MqttClientConnectionConfigBuilder &WithHttpProxyOptions(
+ const Crt::Http::HttpClientConnectionProxyOptions &proxyOptions) noexcept;
+
+ /**
+ * Whether to send the SDK name and version number in the MQTT CONNECT packet.
+ * Default is True.
+ *
+ * @param enabled true to send SDK version/name in the connect for metrics gathering purposes
+ *
+ * @return this builder object
+ */
+ MqttClientConnectionConfigBuilder &WithMetricsCollection(bool enabled);
+
+ /**
+ * Overrides the default SDK Name to send as a metric in the MQTT CONNECT packet.
+ *
+ * @param sdkName string to use as the SDK name parameter in the connection string
+ *
+ * @return this builder object
+ */
+ MqttClientConnectionConfigBuilder &WithSdkName(const Crt::String &sdkName);
+
+ /**
+ * Overrides the default SDK Version to send as a metric in the MQTT CONNECT packet.
+ *
+ * @param sdkVersion string to use as the SDK version parameter in the connection string
+ *
+ * @return this builder object
+ */
+ MqttClientConnectionConfigBuilder &WithSdkVersion(const Crt::String &sdkVersion);
+
+ /**
+ * Sets the custom authorizer settings. This function will modify the username, port, and TLS options.
+ *
+ * @param username The username to use with the custom authorizer. If an empty string is passed, it will
+ * check to see if a username has already been set (via WithUsername function). If no
+ * username is set then no username will be passed with the MQTT connection.
+ * @param authorizerName The name of the custom authorizer. If an empty string is passed, then
+ * 'x-amz-customauthorizer-name' will not be added with the MQTT connection.
+ * @param authorizerSignature The signature of the custom authorizer. If an empty string is passed, then
+ * 'x-amz-customauthorizer-signature' will not be added with the MQTT connection.
+ * @param password The password to use with the custom authorizer. If null is passed, then no password will
+ * be set.
+ *
+ * @return this builder object
+ */
+ MqttClientConnectionConfigBuilder &WithCustomAuthorizer(
+ const Crt::String &username,
+ const Crt::String &authorizerName,
+ const Crt::String &authorizerSignature,
+ const Crt::String &password) noexcept;
+
+ /**
+ * Sets username for the connection
+ *
+ * @param username the username that will be passed with the MQTT connection
+ *
+ * @return this builder object
+ */
+ MqttClientConnectionConfigBuilder &WithUsername(const Crt::String &username) noexcept;
+
+ /**
+ * Sets password for the connection
+ *
+ * @param password the password that will be passed with the MQTT connection
+ *
+ * @return this builder object
+ */
+ MqttClientConnectionConfigBuilder &WithPassword(const Crt::String &password) noexcept;
+
+ /**
+ * Builds a client configuration object from the set options.
+ *
+ * @return a new client connection config instance
+ */
+ MqttClientConnectionConfig Build() noexcept;
+
+ /**
+ * @return true if the instance is in a valid state, false otherwise.
+ */
+ explicit operator bool() const noexcept { return m_lastError == 0; }
+
+ /**
+ * @return the value of the last aws error encountered by operations on this instance.
+ */
+ int LastError() const noexcept { return m_lastError ? m_lastError : AWS_ERROR_UNKNOWN; }
+
+ private:
+ // Common setup shared by all valid constructors
+ MqttClientConnectionConfigBuilder(Crt::Allocator *allocator) noexcept;
+
+ // Helper function to add parameters to the username in the WithCustomAuthorizer function
+ Crt::String AddToUsernameParameter(
+ Crt::String currentUsername,
+ Crt::String parameterValue,
+ Crt::String parameterPreText);
+
+ Crt::Allocator *m_allocator;
+ Crt::String m_endpoint;
+ uint16_t m_portOverride;
+ Crt::Io::SocketOptions m_socketOptions;
+ Crt::Io::TlsContextOptions m_contextOptions;
+ Crt::Optional<WebsocketConfig> m_websocketConfig;
+ Crt::Optional<Crt::Http::HttpClientConnectionProxyOptions> m_proxyOptions;
+ bool m_enableMetricsCollection = true;
+ Crt::String m_sdkName = "CPPv2";
+ Crt::String m_sdkVersion;
+ Crt::String m_username = "";
+ Crt::String m_password = "";
+ bool m_isUsingCustomAuthorizer = false;
+
+ int m_lastError;
+ };
+
+ /**
+ * AWS IOT specific Mqtt Client. Sets defaults for using the AWS IOT service. You'll need an instance of
+ * MqttClientConnectionConfig to use. Once NewConnection returns, you use it's return value identically
+ * to how you would use Aws::Crt::Mqtt::MqttConnection
+ */
+ class AWS_CRT_CPP_API MqttClient final
+ {
+ public:
+ MqttClient(Crt::Io::ClientBootstrap &bootstrap, Crt::Allocator *allocator = Crt::ApiAllocator()) noexcept;
+
+ /**
+ * Constructs a new Mqtt Client object using the static default ClientBootstrap.
+ *
+ * For more information on the default ClientBootstrap see
+ * Aws::Crt::ApiHandle::GetOrCreateDefaultClientBootstrap
+ */
+ MqttClient(Crt::Allocator *allocator = Crt::ApiAllocator()) noexcept;
+
+ /**
+ * Creates a new mqtt connection from a connection configuration object
+ * @param config mqtt connection configuration
+ * @return a new mqtt connection
+ */
+ std::shared_ptr<Crt::Mqtt::MqttConnection> NewConnection(const MqttClientConnectionConfig &config) noexcept;
+
+ /**
+ * @return the value of the last aws error encountered by operations on this instance.
+ */
+ int LastError() const noexcept { return m_client.LastError(); }
+
+ /**
+ * @return true if the instance is in a valid state, false otherwise.
+ */
+ explicit operator bool() const noexcept { return m_client ? true : false; }
+
+ private:
+ Crt::Mqtt::MqttClient m_client;
+ int m_lastError;
+ };
+ } // namespace Iot
+} // namespace Aws
+
+#endif // !BYO_CRYPTO
diff --git a/contrib/restricted/aws/aws-crt-cpp/include/aws/iot/MqttCommon.h b/contrib/restricted/aws/aws-crt-cpp/include/aws/iot/MqttCommon.h
new file mode 100644
index 0000000000..80c4f14084
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/include/aws/iot/MqttCommon.h
@@ -0,0 +1,103 @@
+#pragma once
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+#include <aws/crt/Config.h>
+#include <aws/crt/Exports.h>
+#include <aws/crt/auth/Sigv4Signing.h>
+#include <aws/crt/mqtt/MqttClient.h>
+
+#if !BYO_CRYPTO
+
+namespace Aws
+{
+ namespace Iot
+ {
+
+ using CreateSigningConfig = std::function<std::shared_ptr<Crt::Auth::ISigningConfig>(void)>;
+
+ /**
+ * Class encapsulating configuration for establishing an Aws IoT mqtt connection via websockets
+ */
+ struct AWS_CRT_CPP_API WebsocketConfig
+ {
+ /**
+ * Create a websocket configuration for use with the default credentials provider chain. Signing region
+ * will be used for Sigv4 signature calculations.
+ *
+ * @param signingRegion Aws region that is being connected to. Required in order to properly sign the
+ * handshake upgrade request
+ * @param bootstrap client bootstrap to establish any connections needed by the default credentials
+ * provider chain which will get built for the user
+ * @param allocator memory allocator to use
+ */
+ WebsocketConfig(
+ const Crt::String &signingRegion,
+ Crt::Io::ClientBootstrap *bootstrap,
+ Crt::Allocator *allocator = Crt::ApiAllocator()) noexcept;
+
+ /**
+ * Create a websocket configuration for use with the default credentials provider chain and default
+ * ClientBootstrap. Signing region will be used for Sigv4 signature calculations.
+ *
+ * For more information on the default ClientBootstrap see
+ * Aws::Crt::ApiHandle::GetOrCreateDefaultClientBootstrap
+ *
+ * @param signingRegion Aws region that is being connected to. Required in order to properly sign the
+ * handshake upgrade request
+ * @param allocator memory allocator to use
+ */
+ WebsocketConfig(const Crt::String &signingRegion, Crt::Allocator *allocator = Crt::ApiAllocator()) noexcept;
+
+ /**
+ * Create a websocket configuration for use with a custom credentials provider. Signing region will be used
+ * for Sigv4 signature calculations.
+ *
+ * @param signingRegion Aws region that is being connected to. Required in order to properly sign the
+ * handshake upgrade request
+ * @param credentialsProvider credentials provider to source AWS credentials from
+ * @param allocator memory allocator to use
+ */
+ WebsocketConfig(
+ const Crt::String &signingRegion,
+ const std::shared_ptr<Crt::Auth::ICredentialsProvider> &credentialsProvider,
+ Crt::Allocator *allocator = Crt::ApiAllocator()) noexcept;
+
+ /**
+ * Create a websocket configuration for use with a custom credentials provider, and a custom signer.
+ *
+ * You'll need to provide a function for use with creating a signing Config and pass it to
+ * createSigningConfig.
+ *
+ * This is useful for cases use with:
+ * https://docs.aws.amazon.com/iot/latest/developerguide/custom-auth.html
+ *
+ * @param credentialsProvider credentials provider
+ * @param signer HTTP request signer
+ * @param createSigningConfig function that creates a signing config
+ */
+ WebsocketConfig(
+ const std::shared_ptr<Crt::Auth::ICredentialsProvider> &credentialsProvider,
+ const std::shared_ptr<Crt::Auth::IHttpRequestSigner> &signer,
+ CreateSigningConfig createSigningConfig) noexcept;
+
+ std::shared_ptr<Crt::Auth::ICredentialsProvider> CredentialsProvider;
+ std::shared_ptr<Crt::Auth::IHttpRequestSigner> Signer;
+ CreateSigningConfig CreateSigningConfigCb;
+
+ /**
+ * @deprecated Specify ProxyOptions to use a proxy with your websocket connection.
+ *
+ * If MqttClientConnectionConfigBuilder::m_proxyOptions is valid, then that will be used over
+ * this value.
+ */
+ Crt::Optional<Crt::Http::HttpClientConnectionProxyOptions> ProxyOptions;
+ Crt::String SigningRegion;
+ Crt::String ServiceName;
+ };
+
+ } // namespace Iot
+} // namespace Aws
+
+#endif // !BYO_CRYPTO
diff --git a/contrib/restricted/aws/aws-crt-cpp/source/Allocator.cpp b/contrib/restricted/aws/aws-crt-cpp/source/Allocator.cpp
new file mode 100644
index 0000000000..a27071ef5e
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/source/Allocator.cpp
@@ -0,0 +1,21 @@
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+#include <aws/crt/Allocator.h>
+
+namespace Aws
+{
+ namespace Crt
+ {
+
+ Allocator *DefaultAllocatorImplementation() noexcept { return aws_default_allocator(); }
+
+ Allocator *DefaultAllocator() noexcept { return DefaultAllocatorImplementation(); }
+
+ Allocator *g_allocator = Aws::Crt::DefaultAllocatorImplementation();
+
+ Allocator *ApiAllocator() noexcept { return g_allocator; }
+
+ } // namespace Crt
+} // namespace Aws
diff --git a/contrib/restricted/aws/aws-crt-cpp/source/Api.cpp b/contrib/restricted/aws/aws-crt-cpp/source/Api.cpp
new file mode 100644
index 0000000000..d7a7a03cf5
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/source/Api.cpp
@@ -0,0 +1,405 @@
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+#include <aws/crt/Api.h>
+#include <aws/crt/StlAllocator.h>
+#include <aws/crt/external/cJSON.h>
+#include <aws/crt/io/TlsOptions.h>
+
+#include <aws/auth/auth.h>
+#include <aws/common/ref_count.h>
+#include <aws/event-stream/event_stream.h>
+#include <aws/http/http.h>
+#include <aws/mqtt/mqtt.h>
+#include <aws/s3/s3.h>
+
+#include <thread>
+
+namespace Aws
+{
+ namespace Crt
+ {
+ static Crypto::CreateHashCallback s_BYOCryptoNewMD5Callback;
+ static Crypto::CreateHashCallback s_BYOCryptoNewSHA256Callback;
+ static Crypto::CreateHMACCallback s_BYOCryptoNewSHA256HMACCallback;
+ static Io::NewClientTlsHandlerCallback s_BYOCryptoNewClientTlsHandlerCallback;
+ static Io::NewTlsContextImplCallback s_BYOCryptoNewTlsContextImplCallback;
+ static Io::DeleteTlsContextImplCallback s_BYOCryptoDeleteTlsContextImplCallback;
+ static Io::IsTlsAlpnSupportedCallback s_BYOCryptoIsTlsAlpnSupportedCallback;
+
+ Io::ClientBootstrap *ApiHandle::s_static_bootstrap = nullptr;
+ Io::EventLoopGroup *ApiHandle::s_static_event_loop_group = nullptr;
+ int ApiHandle::s_host_resolver_default_max_hosts = 8;
+ Io::HostResolver *ApiHandle::s_static_default_host_resolver = nullptr;
+ std::mutex ApiHandle::s_lock_client_bootstrap;
+ std::mutex ApiHandle::s_lock_event_loop_group;
+ std::mutex ApiHandle::s_lock_default_host_resolver;
+
+ static void *s_cJSONAlloc(size_t sz) { return aws_mem_acquire(ApiAllocator(), sz); }
+
+ static void s_cJSONFree(void *ptr) { return aws_mem_release(ApiAllocator(), ptr); }
+
+ static void s_initApi(Allocator *allocator)
+ {
+ // sets up the StlAllocator for use.
+ g_allocator = allocator;
+ aws_mqtt_library_init(allocator);
+ aws_s3_library_init(allocator);
+ aws_event_stream_library_init(allocator);
+ aws_sdkutils_library_init(allocator);
+
+ cJSON_Hooks hooks;
+ hooks.malloc_fn = s_cJSONAlloc;
+ hooks.free_fn = s_cJSONFree;
+ cJSON_InitHooks(&hooks);
+ }
+
+ ApiHandle::ApiHandle(Allocator *allocator) noexcept
+ : m_logger(), m_shutdownBehavior(ApiHandleShutdownBehavior::Blocking)
+ {
+ s_initApi(allocator);
+ }
+
+ ApiHandle::ApiHandle() noexcept : m_logger(), m_shutdownBehavior(ApiHandleShutdownBehavior::Blocking)
+ {
+ s_initApi(DefaultAllocator());
+ }
+
+ ApiHandle::~ApiHandle()
+ {
+ ReleaseStaticDefaultClientBootstrap();
+ ReleaseStaticDefaultEventLoopGroup();
+ ReleaseStaticDefaultHostResolver();
+
+ if (m_shutdownBehavior == ApiHandleShutdownBehavior::Blocking)
+ {
+ aws_thread_join_all_managed();
+ }
+
+ if (aws_logger_get() == &m_logger)
+ {
+ aws_logger_set(NULL);
+ aws_logger_clean_up(&m_logger);
+ }
+
+ g_allocator = nullptr;
+ aws_s3_library_clean_up();
+ aws_mqtt_library_clean_up();
+ aws_event_stream_library_clean_up();
+ aws_sdkutils_library_clean_up();
+
+ s_BYOCryptoNewMD5Callback = nullptr;
+ s_BYOCryptoNewSHA256Callback = nullptr;
+ s_BYOCryptoNewSHA256HMACCallback = nullptr;
+ s_BYOCryptoNewClientTlsHandlerCallback = nullptr;
+ s_BYOCryptoNewTlsContextImplCallback = nullptr;
+ s_BYOCryptoDeleteTlsContextImplCallback = nullptr;
+ s_BYOCryptoIsTlsAlpnSupportedCallback = nullptr;
+ }
+
+ void ApiHandle::InitializeLogging(Aws::Crt::LogLevel level, const char *filename)
+ {
+ struct aws_logger_standard_options options;
+ AWS_ZERO_STRUCT(options);
+
+ options.level = (enum aws_log_level)level;
+ options.filename = filename;
+
+ InitializeLoggingCommon(options);
+ }
+
+ void ApiHandle::InitializeLogging(Aws::Crt::LogLevel level, FILE *fp)
+ {
+ struct aws_logger_standard_options options;
+ AWS_ZERO_STRUCT(options);
+
+ options.level = (enum aws_log_level)level;
+ options.file = fp;
+
+ InitializeLoggingCommon(options);
+ }
+
+ void ApiHandle::InitializeLoggingCommon(struct aws_logger_standard_options &options)
+ {
+ if (aws_logger_get() == &m_logger)
+ {
+ aws_logger_set(NULL);
+ aws_logger_clean_up(&m_logger);
+ if (options.level == AWS_LL_NONE)
+ {
+ AWS_ZERO_STRUCT(m_logger);
+ return;
+ }
+ }
+
+ if (aws_logger_init_standard(&m_logger, ApiAllocator(), &options))
+ {
+ return;
+ }
+
+ aws_logger_set(&m_logger);
+ }
+
+ void ApiHandle::SetShutdownBehavior(ApiHandleShutdownBehavior behavior) { m_shutdownBehavior = behavior; }
+
+#if BYO_CRYPTO
+ static struct aws_hash *s_MD5New(struct aws_allocator *allocator)
+ {
+ if (!s_BYOCryptoNewMD5Callback)
+ {
+ AWS_LOGF_ERROR(
+ AWS_LS_IO_TLS, "Must call ApiHandle::SetBYOCryptoNewMD5Callback() before MD5 hash can be created");
+ aws_raise_error(AWS_ERROR_UNIMPLEMENTED);
+ return nullptr;
+ }
+
+ auto hash = s_BYOCryptoNewMD5Callback(AWS_MD5_LEN, allocator);
+ if (!hash)
+ {
+ return nullptr;
+ }
+ return hash->SeatForCInterop(hash);
+ }
+
+ void ApiHandle::SetBYOCryptoNewMD5Callback(Crypto::CreateHashCallback &&callback)
+ {
+ s_BYOCryptoNewMD5Callback = std::move(callback);
+ aws_set_md5_new_fn(s_MD5New);
+ }
+
+ static struct aws_hash *s_Sha256New(struct aws_allocator *allocator)
+ {
+ if (!s_BYOCryptoNewSHA256Callback)
+ {
+ AWS_LOGF_ERROR(
+ AWS_LS_IO_TLS,
+ "Must call ApiHandle::SetBYOCryptoNewSHA256Callback() before SHA256 hash can be created");
+ aws_raise_error(AWS_ERROR_UNIMPLEMENTED);
+ return nullptr;
+ }
+
+ auto hash = s_BYOCryptoNewSHA256Callback(AWS_SHA256_LEN, allocator);
+ if (!hash)
+ {
+ return nullptr;
+ }
+ return hash->SeatForCInterop(hash);
+ }
+
+ void ApiHandle::SetBYOCryptoNewSHA256Callback(Crypto::CreateHashCallback &&callback)
+ {
+ s_BYOCryptoNewSHA256Callback = std::move(callback);
+ aws_set_sha256_new_fn(s_Sha256New);
+ }
+
+ static struct aws_hmac *s_sha256HMACNew(struct aws_allocator *allocator, const struct aws_byte_cursor *secret)
+ {
+ if (!s_BYOCryptoNewSHA256HMACCallback)
+ {
+ AWS_LOGF_ERROR(
+ AWS_LS_IO_TLS,
+ "Must call ApiHandle::SetBYOCryptoNewSHA256HMACCallback() before SHA256 HMAC can be created");
+ aws_raise_error(AWS_ERROR_UNIMPLEMENTED);
+ return nullptr;
+ }
+
+ auto hmac = s_BYOCryptoNewSHA256HMACCallback(AWS_SHA256_HMAC_LEN, *secret, allocator);
+ if (!hmac)
+ {
+ return nullptr;
+ }
+ return hmac->SeatForCInterop(hmac);
+ }
+
+ void ApiHandle::SetBYOCryptoNewSHA256HMACCallback(Crypto::CreateHMACCallback &&callback)
+ {
+ s_BYOCryptoNewSHA256HMACCallback = std::move(callback);
+ aws_set_sha256_hmac_new_fn(s_sha256HMACNew);
+ }
+
+ static struct aws_channel_handler *s_NewClientTlsHandler(
+ struct aws_allocator *allocator,
+ struct aws_tls_connection_options *options,
+ struct aws_channel_slot *slot,
+ void *)
+ {
+ if (!s_BYOCryptoNewClientTlsHandlerCallback)
+ {
+ AWS_LOGF_ERROR(
+ AWS_LS_IO_TLS,
+ "Must call ApiHandle::SetBYOCryptoClientTlsCallback() before client TLS handler can be created");
+ aws_raise_error(AWS_ERROR_UNIMPLEMENTED);
+ return nullptr;
+ }
+
+ auto clientHandlerSelfReferencing = s_BYOCryptoNewClientTlsHandlerCallback(slot, *options, allocator);
+ if (!clientHandlerSelfReferencing)
+ {
+ return nullptr;
+ }
+ return clientHandlerSelfReferencing->SeatForCInterop(clientHandlerSelfReferencing);
+ }
+
+ static int s_ClientTlsHandlerStartNegotiation(struct aws_channel_handler *handler, void *)
+ {
+ auto *clientHandler = reinterpret_cast<Io::ClientTlsChannelHandler *>(handler->impl);
+ if (clientHandler->ChannelsThreadIsCallersThread())
+ {
+ clientHandler->StartNegotiation();
+ }
+ else
+ {
+ clientHandler->ScheduleTask([clientHandler](Io::TaskStatus) { clientHandler->StartNegotiation(); });
+ }
+ return AWS_OP_SUCCESS;
+ }
+
+ void ApiHandle::SetBYOCryptoClientTlsCallback(Io::NewClientTlsHandlerCallback &&callback)
+ {
+ s_BYOCryptoNewClientTlsHandlerCallback = std::move(callback);
+ struct aws_tls_byo_crypto_setup_options setupOptions;
+ setupOptions.new_handler_fn = s_NewClientTlsHandler;
+ setupOptions.start_negotiation_fn = s_ClientTlsHandlerStartNegotiation;
+ setupOptions.user_data = nullptr;
+ aws_tls_byo_crypto_set_client_setup_options(&setupOptions);
+ }
+
+ void ApiHandle::SetBYOCryptoTlsContextCallbacks(
+ Io::NewTlsContextImplCallback &&newCallback,
+ Io::DeleteTlsContextImplCallback &&deleteCallback,
+ Io::IsTlsAlpnSupportedCallback &&alpnCallback)
+ {
+ s_BYOCryptoNewTlsContextImplCallback = newCallback;
+ s_BYOCryptoDeleteTlsContextImplCallback = deleteCallback;
+ s_BYOCryptoIsTlsAlpnSupportedCallback = alpnCallback;
+ }
+
+#else // BYO_CRYPTO
+ void ApiHandle::SetBYOCryptoNewMD5Callback(Crypto::CreateHashCallback &&)
+ {
+ AWS_LOGF_WARN(AWS_LS_IO_TLS, "SetBYOCryptoNewMD5Callback() has no effect unless compiled with BYO_CRYPTO");
+ }
+
+ void ApiHandle::SetBYOCryptoNewSHA256Callback(Crypto::CreateHashCallback &&)
+ {
+ AWS_LOGF_WARN(
+ AWS_LS_IO_TLS, "SetBYOCryptoNewSHA256Callback() has no effect unless compiled with BYO_CRYPTO");
+ }
+
+ void ApiHandle::SetBYOCryptoNewSHA256HMACCallback(Crypto::CreateHMACCallback &&)
+ {
+ AWS_LOGF_WARN(
+ AWS_LS_IO_TLS, "SetBYOCryptoNewSHA256HMACCallback() has no effect unless compiled with BYO_CRYPTO");
+ }
+
+ void ApiHandle::SetBYOCryptoClientTlsCallback(Io::NewClientTlsHandlerCallback &&)
+ {
+ AWS_LOGF_WARN(
+ AWS_LS_IO_TLS, "SetBYOCryptoClientTlsCallback() has no effect unless compiled with BYO_CRYPTO");
+ }
+
+ void ApiHandle::SetBYOCryptoTlsContextCallbacks(
+ Io::NewTlsContextImplCallback &&,
+ Io::DeleteTlsContextImplCallback &&,
+ Io::IsTlsAlpnSupportedCallback &&)
+ {
+ AWS_LOGF_WARN(
+ AWS_LS_IO_TLS, "SetBYOCryptoClientTlsCallback() has no effect unless compiled with BYO_CRYPTO");
+ }
+#endif // BYO_CRYPTO
+
+ Io::ClientBootstrap *ApiHandle::GetOrCreateStaticDefaultClientBootstrap()
+ {
+ std::lock_guard<std::mutex> lock(s_lock_client_bootstrap);
+ if (s_static_bootstrap == nullptr)
+ {
+ s_static_bootstrap = Aws::Crt::New<Io::ClientBootstrap>(
+ ApiAllocator(), *GetOrCreateStaticDefaultEventLoopGroup(), *GetOrCreateStaticDefaultHostResolver());
+ }
+ return s_static_bootstrap;
+ }
+
+ Io::EventLoopGroup *ApiHandle::GetOrCreateStaticDefaultEventLoopGroup()
+ {
+ std::lock_guard<std::mutex> lock(s_lock_event_loop_group);
+ if (s_static_event_loop_group == nullptr)
+ {
+ s_static_event_loop_group = Aws::Crt::New<Io::EventLoopGroup>(ApiAllocator(), (uint16_t)0);
+ }
+ return s_static_event_loop_group;
+ }
+
+ Io::HostResolver *ApiHandle::GetOrCreateStaticDefaultHostResolver()
+ {
+ std::lock_guard<std::mutex> lock(s_lock_default_host_resolver);
+ if (s_static_default_host_resolver == nullptr)
+ {
+ s_static_default_host_resolver = Aws::Crt::New<Io::DefaultHostResolver>(
+ ApiAllocator(), *GetOrCreateStaticDefaultEventLoopGroup(), 1, s_host_resolver_default_max_hosts);
+ }
+ return s_static_default_host_resolver;
+ }
+
+ void ApiHandle::ReleaseStaticDefaultClientBootstrap()
+ {
+ std::lock_guard<std::mutex> lock(s_lock_client_bootstrap);
+ if (s_static_bootstrap != nullptr)
+ {
+ Aws::Crt::Delete(s_static_bootstrap, ApiAllocator());
+ s_static_bootstrap = nullptr;
+ }
+ }
+
+ void ApiHandle::ReleaseStaticDefaultEventLoopGroup()
+ {
+ std::lock_guard<std::mutex> lock(s_lock_event_loop_group);
+ if (s_static_event_loop_group != nullptr)
+ {
+ Aws::Crt::Delete(s_static_event_loop_group, ApiAllocator());
+ s_static_event_loop_group = nullptr;
+ }
+ }
+
+ void ApiHandle::ReleaseStaticDefaultHostResolver()
+ {
+ std::lock_guard<std::mutex> lock(s_lock_default_host_resolver);
+ if (s_static_default_host_resolver != nullptr)
+ {
+ Aws::Crt::Delete(s_static_default_host_resolver, ApiAllocator());
+ s_static_default_host_resolver = nullptr;
+ }
+ }
+
+ const Io::NewTlsContextImplCallback &ApiHandle::GetBYOCryptoNewTlsContextImplCallback()
+ {
+ return s_BYOCryptoNewTlsContextImplCallback;
+ }
+
+ const Io::DeleteTlsContextImplCallback &ApiHandle::GetBYOCryptoDeleteTlsContextImplCallback()
+ {
+ return s_BYOCryptoDeleteTlsContextImplCallback;
+ }
+
+ const Io::IsTlsAlpnSupportedCallback &ApiHandle::GetBYOCryptoIsTlsAlpnSupportedCallback()
+ {
+ return s_BYOCryptoIsTlsAlpnSupportedCallback;
+ }
+
+ const char *ErrorDebugString(int error) noexcept { return aws_error_debug_str(error); }
+
+ int LastError() noexcept { return aws_last_error(); }
+
+ int LastErrorOrUnknown() noexcept
+ {
+ int last_error = aws_last_error();
+ if (last_error == AWS_ERROR_SUCCESS)
+ {
+ last_error = AWS_ERROR_UNKNOWN;
+ }
+
+ return last_error;
+ }
+
+ } // namespace Crt
+} // namespace Aws
diff --git a/contrib/restricted/aws/aws-crt-cpp/source/DateTime.cpp b/contrib/restricted/aws/aws-crt-cpp/source/DateTime.cpp
new file mode 100644
index 0000000000..8e550cc91f
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/source/DateTime.cpp
@@ -0,0 +1,200 @@
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+#include <aws/crt/DateTime.h>
+
+#include <chrono>
+
+namespace Aws
+{
+ namespace Crt
+ {
+ DateTime::DateTime() noexcept : m_good(true)
+ {
+ std::chrono::system_clock::time_point time;
+ aws_date_time_init_epoch_millis(
+ &m_date_time,
+ static_cast<uint64_t>(
+ std::chrono::duration_cast<std::chrono::milliseconds>(time.time_since_epoch()).count()));
+ }
+
+ DateTime::DateTime(const std::chrono::system_clock::time_point &timepointToAssign) noexcept : m_good(true)
+ {
+ aws_date_time_init_epoch_millis(
+ &m_date_time,
+ static_cast<uint64_t>(
+ std::chrono::duration_cast<std::chrono::milliseconds>(timepointToAssign.time_since_epoch())
+ .count()));
+ }
+
+ DateTime::DateTime(uint64_t millisSinceEpoch) noexcept : m_good(true)
+ {
+ aws_date_time_init_epoch_millis(&m_date_time, millisSinceEpoch);
+ }
+
+ DateTime::DateTime(double epoch_millis) noexcept : m_good(true)
+ {
+ aws_date_time_init_epoch_secs(&m_date_time, epoch_millis);
+ }
+
+ DateTime::DateTime(const char *timestamp, DateFormat format) noexcept
+ {
+ ByteBuf timeStampBuf = ByteBufFromCString(timestamp);
+
+ m_good =
+ (aws_date_time_init_from_str(&m_date_time, &timeStampBuf, static_cast<aws_date_format>(format)) ==
+ AWS_ERROR_SUCCESS);
+ }
+
+ bool DateTime::operator==(const DateTime &other) const noexcept
+ {
+ return aws_date_time_diff(&m_date_time, &other.m_date_time) == 0;
+ }
+
+ bool DateTime::operator<(const DateTime &other) const noexcept
+ {
+ return aws_date_time_diff(&m_date_time, &other.m_date_time) < 0;
+ }
+
+ bool DateTime::operator>(const DateTime &other) const noexcept
+ {
+ return aws_date_time_diff(&m_date_time, &other.m_date_time) > 0;
+ }
+
+ bool DateTime::operator!=(const DateTime &other) const noexcept { return !(*this == other); }
+
+ bool DateTime::operator<=(const DateTime &other) const noexcept
+ {
+ return aws_date_time_diff(&m_date_time, &other.m_date_time) <= 0;
+ }
+
+ bool DateTime::operator>=(const DateTime &other) const noexcept
+ {
+ return aws_date_time_diff(&m_date_time, &other.m_date_time) >= 0;
+ }
+
+ DateTime DateTime::operator+(const std::chrono::milliseconds &a) const noexcept
+ {
+ auto currentTime = aws_date_time_as_millis(&m_date_time);
+ currentTime += a.count();
+ return {currentTime};
+ }
+
+ DateTime DateTime::operator-(const std::chrono::milliseconds &a) const noexcept
+ {
+ auto currentTime = aws_date_time_as_millis(&m_date_time);
+ currentTime -= a.count();
+ return {currentTime};
+ }
+
+ DateTime &DateTime::operator=(double secondsSinceEpoch) noexcept
+ {
+ aws_date_time_init_epoch_secs(&m_date_time, secondsSinceEpoch);
+ m_good = true;
+ return *this;
+ }
+
+ DateTime &DateTime::operator=(uint64_t millisSinceEpoch) noexcept
+ {
+ aws_date_time_init_epoch_millis(&m_date_time, millisSinceEpoch);
+ m_good = true;
+ return *this;
+ }
+
+ DateTime &DateTime::operator=(const std::chrono::system_clock::time_point &timepointToAssign) noexcept
+ {
+ aws_date_time_init_epoch_millis(
+ &m_date_time,
+ static_cast<uint64_t>(
+ std::chrono::duration_cast<std::chrono::milliseconds>(timepointToAssign.time_since_epoch())
+ .count()));
+ m_good = true;
+ return *this;
+ }
+
+ DateTime &DateTime::operator=(const char *timestamp) noexcept
+ {
+ ByteBuf timeStampBuf = aws_byte_buf_from_c_str(timestamp);
+
+ m_good = aws_date_time_init_from_str(
+ &m_date_time, &timeStampBuf, static_cast<aws_date_format>(DateFormat::AutoDetect)) ==
+ AWS_ERROR_SUCCESS;
+ return *this;
+ }
+
+ DateTime::operator bool() const noexcept { return m_good; }
+
+ int DateTime::GetLastError() const noexcept { return aws_last_error(); }
+
+ bool DateTime::ToLocalTimeString(DateFormat format, ByteBuf &outputBuf) const noexcept
+ {
+ return (
+ aws_date_time_to_local_time_str(&m_date_time, static_cast<aws_date_format>(format), &outputBuf) ==
+ AWS_ERROR_SUCCESS);
+ }
+
+ bool DateTime::ToGmtString(DateFormat format, ByteBuf &outputBuf) const noexcept
+ {
+ return (
+ aws_date_time_to_utc_time_str(&m_date_time, static_cast<aws_date_format>(format), &outputBuf) ==
+ AWS_ERROR_SUCCESS);
+ }
+
+ double DateTime::SecondsWithMSPrecision() const noexcept { return aws_date_time_as_epoch_secs(&m_date_time); }
+
+ uint64_t DateTime::Millis() const noexcept { return aws_date_time_as_millis(&m_date_time); }
+
+ std::chrono::system_clock::time_point DateTime::UnderlyingTimestamp() const noexcept
+ {
+ return std::chrono::system_clock::from_time_t(m_date_time.timestamp);
+ }
+
+ uint16_t DateTime::GetYear(bool localTime) const noexcept
+ {
+ return aws_date_time_year(&m_date_time, localTime);
+ }
+
+ Month DateTime::GetMonth(bool localTime) const noexcept
+ {
+ return static_cast<Month>(aws_date_time_month(&m_date_time, localTime));
+ }
+
+ uint8_t DateTime::GetDay(bool localTime) const noexcept
+ {
+ return aws_date_time_month_day(&m_date_time, localTime);
+ }
+
+ DayOfWeek DateTime::GetDayOfWeek(bool localTime) const noexcept
+ {
+ return static_cast<DayOfWeek>(aws_date_time_day_of_week(&m_date_time, localTime));
+ }
+
+ uint8_t DateTime::GetHour(bool localTime) const noexcept { return aws_date_time_hour(&m_date_time, localTime); }
+
+ uint8_t DateTime::GetMinute(bool localTime) const noexcept
+ {
+ return aws_date_time_minute(&m_date_time, localTime);
+ }
+
+ uint8_t DateTime::GetSecond(bool localTime) const noexcept
+ {
+ return aws_date_time_second(&m_date_time, localTime);
+ }
+
+ bool DateTime::IsDST(bool localTime) const noexcept { return aws_date_time_dst(&m_date_time, localTime); }
+
+ DateTime DateTime::Now() noexcept
+ {
+ DateTime dateTime;
+ aws_date_time_init_now(&dateTime.m_date_time);
+ return dateTime;
+ }
+
+ std::chrono::milliseconds DateTime::operator-(const DateTime &other) const noexcept
+ {
+ auto diff = aws_date_time_diff(&m_date_time, &other.m_date_time);
+ return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::seconds(diff));
+ }
+ } // namespace Crt
+} // namespace Aws
diff --git a/contrib/restricted/aws/aws-crt-cpp/source/ImdsClient.cpp b/contrib/restricted/aws/aws-crt-cpp/source/ImdsClient.cpp
new file mode 100644
index 0000000000..cb9b1f9431
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/source/ImdsClient.cpp
@@ -0,0 +1,457 @@
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+
+#include <aws/auth/aws_imds_client.h>
+#include <aws/auth/credentials.h>
+#include <aws/crt/Api.h>
+#include <aws/crt/ImdsClient.h>
+#include <aws/crt/auth/Credentials.h>
+#include <aws/crt/http/HttpConnection.h>
+#include <aws/crt/io/Bootstrap.h>
+
+namespace Aws
+{
+ namespace Crt
+ {
+ namespace Imds
+ {
+ IamProfile::IamProfile(const IamProfileView &other)
+ : lastUpdated(other.lastUpdated),
+ instanceProfileArn(other.instanceProfileArn.data(), other.instanceProfileArn.size()),
+ instanceProfileId(other.instanceProfileId.data(), other.instanceProfileId.size())
+ {
+ }
+
+ IamProfile &IamProfile::operator=(const IamProfileView &other)
+ {
+ lastUpdated = other.lastUpdated;
+ instanceProfileArn = String(other.instanceProfileArn.data(), other.instanceProfileArn.size());
+ instanceProfileId = String(other.instanceProfileId.data(), other.instanceProfileId.size());
+ return *this;
+ }
+
+ InstanceInfo::InstanceInfo(const InstanceInfoView &other)
+ : availabilityZone(other.availabilityZone.data(), other.availabilityZone.size()),
+ privateIp(other.privateIp.data(), other.privateIp.size()),
+ version(other.version.data(), other.version.size()),
+ instanceId(other.instanceId.data(), other.instanceId.size()),
+ instanceType(other.instanceType.data(), other.instanceType.size()),
+ accountId(other.accountId.data(), other.accountId.size()),
+ imageId(other.imageId.data(), other.imageId.size()), pendingTime(other.pendingTime),
+ architecture(other.architecture.data(), other.architecture.size()),
+ kernelId(other.kernelId.data(), other.kernelId.size()),
+ ramdiskId(other.ramdiskId.data(), other.ramdiskId.size()),
+ region(other.region.data(), other.region.size())
+ {
+ for (const auto &m : other.marketplaceProductCodes)
+ {
+ marketplaceProductCodes.emplace_back(m.data(), m.size());
+ }
+
+ for (const auto &m : other.billingProducts)
+ {
+ billingProducts.emplace_back(m.data(), m.size());
+ }
+ }
+
+ InstanceInfo &InstanceInfo::operator=(const InstanceInfoView &other)
+ {
+ availabilityZone = {other.availabilityZone.data(), other.availabilityZone.size()};
+ privateIp = {other.privateIp.data(), other.privateIp.size()};
+ version = {other.version.data(), other.version.size()};
+ instanceId = {other.instanceId.data(), other.instanceId.size()};
+ instanceType = {other.instanceType.data(), other.instanceType.size()};
+ accountId = {other.accountId.data(), other.accountId.size()};
+ imageId = {other.imageId.data(), other.imageId.size()};
+ pendingTime = other.pendingTime;
+ architecture = {other.architecture.data(), other.architecture.size()};
+ kernelId = {other.kernelId.data(), other.kernelId.size()};
+ ramdiskId = {other.ramdiskId.data(), other.ramdiskId.size()};
+ region = {other.region.data(), other.region.size()};
+
+ for (const auto &m : other.marketplaceProductCodes)
+ {
+ marketplaceProductCodes.emplace_back(m.data(), m.size());
+ }
+
+ for (const auto &m : other.billingProducts)
+ {
+ billingProducts.emplace_back(m.data(), m.size());
+ }
+ return *this;
+ }
+
+ ImdsClient::ImdsClient(const ImdsClientConfig &config, Allocator *allocator) noexcept
+ {
+ struct aws_imds_client_options raw_config;
+ AWS_ZERO_STRUCT(raw_config);
+ if (config.Bootstrap != nullptr)
+ {
+ raw_config.bootstrap = config.Bootstrap->GetUnderlyingHandle();
+ }
+ else
+ {
+ raw_config.bootstrap = ApiHandle::GetOrCreateStaticDefaultClientBootstrap()->GetUnderlyingHandle();
+ }
+
+ m_client = aws_imds_client_new(allocator, &raw_config);
+ m_allocator = allocator;
+ }
+
+ ImdsClient::~ImdsClient()
+ {
+ if (m_client)
+ {
+ aws_imds_client_release(m_client);
+ m_client = nullptr;
+ }
+ }
+
+ template <typename T> struct WrappedCallbackArgs
+ {
+ WrappedCallbackArgs(Allocator *allocator, T callback, void *userData)
+ : allocator(allocator), callback(callback), userData(userData)
+ {
+ }
+ Allocator *allocator;
+ T callback;
+ void *userData;
+ };
+
+ void ImdsClient::s_onResourceAcquired(const aws_byte_buf *resource, int errorCode, void *userData)
+ {
+ WrappedCallbackArgs<OnResourceAcquired> *callbackArgs =
+ static_cast<WrappedCallbackArgs<OnResourceAcquired> *>(userData);
+ callbackArgs->callback(
+ ByteCursorToStringView(aws_byte_cursor_from_buf(resource)), errorCode, callbackArgs->userData);
+ Aws::Crt::Delete(callbackArgs, callbackArgs->allocator);
+ }
+
+ void ImdsClient::s_onVectorResourceAcquired(const aws_array_list *array, int errorCode, void *userData)
+ {
+ WrappedCallbackArgs<OnVectorResourceAcquired> *callbackArgs =
+ static_cast<WrappedCallbackArgs<OnVectorResourceAcquired> *>(userData);
+ callbackArgs->callback(
+ ArrayListToVector<ByteCursor, StringView>(array, ByteCursorToStringView),
+ errorCode,
+ callbackArgs->userData);
+ Aws::Crt::Delete(callbackArgs, callbackArgs->allocator);
+ }
+
+ void ImdsClient::s_onCredentialsAcquired(const aws_credentials *credentials, int errorCode, void *userData)
+ {
+ WrappedCallbackArgs<OnCredentialsAcquired> *callbackArgs =
+ static_cast<WrappedCallbackArgs<OnCredentialsAcquired> *>(userData);
+ auto credentialsPtr = Aws::Crt::MakeShared<Auth::Credentials>(callbackArgs->allocator, credentials);
+ callbackArgs->callback(credentials, errorCode, callbackArgs->userData);
+ Aws::Crt::Delete(callbackArgs, callbackArgs->allocator);
+ }
+
+ void ImdsClient::s_onIamProfileAcquired(
+ const aws_imds_iam_profile *iamProfileInfo,
+ int errorCode,
+ void *userData)
+ {
+ WrappedCallbackArgs<OnIamProfileAcquired> *callbackArgs =
+ static_cast<WrappedCallbackArgs<OnIamProfileAcquired> *>(userData);
+ IamProfileView iamProfile;
+ iamProfile.lastUpdated = aws_date_time_as_epoch_secs(&(iamProfileInfo->last_updated));
+ iamProfile.instanceProfileArn = ByteCursorToStringView(iamProfileInfo->instance_profile_arn);
+ iamProfile.instanceProfileId = ByteCursorToStringView(iamProfileInfo->instance_profile_id);
+ callbackArgs->callback(iamProfile, errorCode, callbackArgs->userData);
+ Aws::Crt::Delete(callbackArgs, callbackArgs->allocator);
+ }
+
+ void ImdsClient::s_onInstanceInfoAcquired(
+ const aws_imds_instance_info *instanceInfo,
+ int errorCode,
+ void *userData)
+ {
+ WrappedCallbackArgs<OnInstanceInfoAcquired> *callbackArgs =
+ static_cast<WrappedCallbackArgs<OnInstanceInfoAcquired> *>(userData);
+ InstanceInfoView info;
+ info.marketplaceProductCodes = ArrayListToVector<ByteCursor, StringView>(
+ &(instanceInfo->marketplace_product_codes), ByteCursorToStringView);
+ info.availabilityZone = ByteCursorToStringView(instanceInfo->availability_zone);
+ info.privateIp = ByteCursorToStringView(instanceInfo->private_ip);
+ info.version = ByteCursorToStringView(instanceInfo->version);
+ info.instanceId = ByteCursorToStringView(instanceInfo->instance_id);
+ info.billingProducts = ArrayListToVector<ByteCursor, StringView>(
+ &(instanceInfo->billing_products), ByteCursorToStringView);
+ info.instanceType = ByteCursorToStringView(instanceInfo->instance_type);
+ info.accountId = ByteCursorToStringView(instanceInfo->account_id);
+ info.imageId = ByteCursorToStringView(instanceInfo->image_id);
+ info.pendingTime = aws_date_time_as_epoch_secs(&(instanceInfo->pending_time));
+ info.architecture = ByteCursorToStringView(instanceInfo->architecture);
+ info.kernelId = ByteCursorToStringView(instanceInfo->kernel_id);
+ info.ramdiskId = ByteCursorToStringView(instanceInfo->ramdisk_id);
+ info.region = ByteCursorToStringView(instanceInfo->region);
+ callbackArgs->callback(info, errorCode, callbackArgs->userData);
+ Aws::Crt::Delete(callbackArgs, callbackArgs->allocator);
+ }
+
+ int ImdsClient::GetResource(const StringView &resourcePath, OnResourceAcquired callback, void *userData)
+ {
+ auto wrappedCallbackArgs = Aws::Crt::New<WrappedCallbackArgs<OnResourceAcquired>>(
+ m_allocator, m_allocator, callback, userData);
+ if (wrappedCallbackArgs == nullptr)
+ {
+ return AWS_OP_ERR;
+ }
+
+ return aws_imds_client_get_resource_async(
+ m_client, StringViewToByteCursor(resourcePath), s_onResourceAcquired, wrappedCallbackArgs);
+ }
+
+ int ImdsClient::GetAmiId(OnResourceAcquired callback, void *userData)
+ {
+ auto wrappedCallbackArgs = Aws::Crt::New<WrappedCallbackArgs<OnResourceAcquired>>(
+ m_allocator, m_allocator, callback, userData);
+ if (wrappedCallbackArgs == nullptr)
+ {
+ return AWS_OP_ERR;
+ }
+ return aws_imds_client_get_ami_id(m_client, s_onResourceAcquired, wrappedCallbackArgs);
+ }
+
+ int ImdsClient::GetAmiLaunchIndex(OnResourceAcquired callback, void *userData)
+ {
+ auto wrappedCallbackArgs = Aws::Crt::New<WrappedCallbackArgs<OnResourceAcquired>>(
+ m_allocator, m_allocator, callback, userData);
+ if (wrappedCallbackArgs == nullptr)
+ {
+ return AWS_OP_ERR;
+ }
+ return aws_imds_client_get_ami_launch_index(m_client, s_onResourceAcquired, wrappedCallbackArgs);
+ }
+
+ int ImdsClient::GetAmiManifestPath(OnResourceAcquired callback, void *userData)
+ {
+ auto wrappedCallbackArgs = Aws::Crt::New<WrappedCallbackArgs<OnResourceAcquired>>(
+ m_allocator, m_allocator, callback, userData);
+ if (wrappedCallbackArgs == nullptr)
+ {
+ return AWS_OP_ERR;
+ }
+ return aws_imds_client_get_ami_manifest_path(m_client, s_onResourceAcquired, wrappedCallbackArgs);
+ }
+
+ int ImdsClient::GetAncestorAmiIds(OnVectorResourceAcquired callback, void *userData)
+ {
+ auto wrappedCallbackArgs = Aws::Crt::New<WrappedCallbackArgs<OnVectorResourceAcquired>>(
+ m_allocator, m_allocator, callback, userData);
+ if (wrappedCallbackArgs == nullptr)
+ {
+ return AWS_OP_ERR;
+ }
+ return aws_imds_client_get_ancestor_ami_ids(m_client, s_onVectorResourceAcquired, wrappedCallbackArgs);
+ }
+
+ int ImdsClient::GetInstanceAction(OnResourceAcquired callback, void *userData)
+ {
+ auto wrappedCallbackArgs = Aws::Crt::New<WrappedCallbackArgs<OnResourceAcquired>>(
+ m_allocator, m_allocator, callback, userData);
+ if (wrappedCallbackArgs == nullptr)
+ {
+ return AWS_OP_ERR;
+ }
+ return aws_imds_client_get_instance_action(m_client, s_onResourceAcquired, wrappedCallbackArgs);
+ }
+
+ int ImdsClient::GetInstanceId(OnResourceAcquired callback, void *userData)
+ {
+ auto wrappedCallbackArgs = Aws::Crt::New<WrappedCallbackArgs<OnResourceAcquired>>(
+ m_allocator, m_allocator, callback, userData);
+ if (wrappedCallbackArgs == nullptr)
+ {
+ return AWS_OP_ERR;
+ }
+ return aws_imds_client_get_instance_id(m_client, s_onResourceAcquired, wrappedCallbackArgs);
+ }
+
+ int ImdsClient::GetInstanceType(OnResourceAcquired callback, void *userData)
+ {
+ auto wrappedCallbackArgs = Aws::Crt::New<WrappedCallbackArgs<OnResourceAcquired>>(
+ m_allocator, m_allocator, callback, userData);
+ if (wrappedCallbackArgs == nullptr)
+ {
+ return AWS_OP_ERR;
+ }
+ return aws_imds_client_get_instance_type(m_client, s_onResourceAcquired, wrappedCallbackArgs);
+ }
+
+ int ImdsClient::GetMacAddress(OnResourceAcquired callback, void *userData)
+ {
+ auto wrappedCallbackArgs = Aws::Crt::New<WrappedCallbackArgs<OnResourceAcquired>>(
+ m_allocator, m_allocator, callback, userData);
+ if (wrappedCallbackArgs == nullptr)
+ {
+ return AWS_OP_ERR;
+ }
+ return aws_imds_client_get_mac_address(m_client, s_onResourceAcquired, wrappedCallbackArgs);
+ }
+
+ int ImdsClient::GetPrivateIpAddress(OnResourceAcquired callback, void *userData)
+ {
+ auto wrappedCallbackArgs = Aws::Crt::New<WrappedCallbackArgs<OnResourceAcquired>>(
+ m_allocator, m_allocator, callback, userData);
+ if (wrappedCallbackArgs == nullptr)
+ {
+ return AWS_OP_ERR;
+ }
+ return aws_imds_client_get_private_ip_address(m_client, s_onResourceAcquired, wrappedCallbackArgs);
+ }
+
+ int ImdsClient::GetAvailabilityZone(OnResourceAcquired callback, void *userData)
+ {
+ auto wrappedCallbackArgs = Aws::Crt::New<WrappedCallbackArgs<OnResourceAcquired>>(
+ m_allocator, m_allocator, callback, userData);
+ if (wrappedCallbackArgs == nullptr)
+ {
+ return AWS_OP_ERR;
+ }
+ return aws_imds_client_get_availability_zone(m_client, s_onResourceAcquired, wrappedCallbackArgs);
+ }
+
+ int ImdsClient::GetProductCodes(OnResourceAcquired callback, void *userData)
+ {
+ auto wrappedCallbackArgs = Aws::Crt::New<WrappedCallbackArgs<OnResourceAcquired>>(
+ m_allocator, m_allocator, callback, userData);
+ if (wrappedCallbackArgs == nullptr)
+ {
+ return AWS_OP_ERR;
+ }
+ return aws_imds_client_get_product_codes(m_client, s_onResourceAcquired, wrappedCallbackArgs);
+ }
+
+ int ImdsClient::GetPublicKey(OnResourceAcquired callback, void *userData)
+ {
+ auto wrappedCallbackArgs = Aws::Crt::New<WrappedCallbackArgs<OnResourceAcquired>>(
+ m_allocator, m_allocator, callback, userData);
+ if (wrappedCallbackArgs == nullptr)
+ {
+ return AWS_OP_ERR;
+ }
+ return aws_imds_client_get_public_key(m_client, s_onResourceAcquired, wrappedCallbackArgs);
+ }
+
+ int ImdsClient::GetRamDiskId(OnResourceAcquired callback, void *userData)
+ {
+ auto wrappedCallbackArgs = Aws::Crt::New<WrappedCallbackArgs<OnResourceAcquired>>(
+ m_allocator, m_allocator, callback, userData);
+ if (wrappedCallbackArgs == nullptr)
+ {
+ return AWS_OP_ERR;
+ }
+ return aws_imds_client_get_ramdisk_id(m_client, s_onResourceAcquired, wrappedCallbackArgs);
+ }
+
+ int ImdsClient::GetReservationId(OnResourceAcquired callback, void *userData)
+ {
+ auto wrappedCallbackArgs = Aws::Crt::New<WrappedCallbackArgs<OnResourceAcquired>>(
+ m_allocator, m_allocator, callback, userData);
+ if (wrappedCallbackArgs == nullptr)
+ {
+ return AWS_OP_ERR;
+ }
+ return aws_imds_client_get_reservation_id(m_client, s_onResourceAcquired, wrappedCallbackArgs);
+ }
+
+ int ImdsClient::GetSecurityGroups(OnVectorResourceAcquired callback, void *userData)
+ {
+ auto wrappedCallbackArgs = Aws::Crt::New<WrappedCallbackArgs<OnVectorResourceAcquired>>(
+ m_allocator, m_allocator, callback, userData);
+ if (wrappedCallbackArgs == nullptr)
+ {
+ return AWS_OP_ERR;
+ }
+ return aws_imds_client_get_security_groups(m_client, s_onVectorResourceAcquired, wrappedCallbackArgs);
+ }
+
+ int ImdsClient::GetBlockDeviceMapping(OnVectorResourceAcquired callback, void *userData)
+ {
+ auto wrappedCallbackArgs = Aws::Crt::New<WrappedCallbackArgs<OnVectorResourceAcquired>>(
+ m_allocator, m_allocator, callback, userData);
+ if (wrappedCallbackArgs == nullptr)
+ {
+ return AWS_OP_ERR;
+ }
+ return aws_imds_client_get_block_device_mapping(
+ m_client, s_onVectorResourceAcquired, wrappedCallbackArgs);
+ }
+
+ int ImdsClient::GetAttachedIamRole(OnResourceAcquired callback, void *userData)
+ {
+ auto wrappedCallbackArgs = Aws::Crt::New<WrappedCallbackArgs<OnResourceAcquired>>(
+ m_allocator, m_allocator, callback, userData);
+ if (wrappedCallbackArgs == nullptr)
+ {
+ return AWS_OP_ERR;
+ }
+ return aws_imds_client_get_attached_iam_role(m_client, s_onResourceAcquired, wrappedCallbackArgs);
+ }
+
+ int ImdsClient::GetCredentials(
+ const StringView &iamRoleName,
+ OnCredentialsAcquired callback,
+ void *userData)
+ {
+ auto wrappedCallbackArgs = Aws::Crt::New<WrappedCallbackArgs<OnCredentialsAcquired>>(
+ m_allocator, m_allocator, callback, userData);
+ if (wrappedCallbackArgs == nullptr)
+ {
+ return AWS_OP_ERR;
+ }
+ return aws_imds_client_get_credentials(
+ m_client, StringViewToByteCursor(iamRoleName), s_onCredentialsAcquired, wrappedCallbackArgs);
+ }
+
+ int ImdsClient::GetIamProfile(OnIamProfileAcquired callback, void *userData)
+ {
+ auto wrappedCallbackArgs = Aws::Crt::New<WrappedCallbackArgs<OnIamProfileAcquired>>(
+ m_allocator, m_allocator, callback, userData);
+ if (wrappedCallbackArgs == nullptr)
+ {
+ return AWS_OP_ERR;
+ }
+ return aws_imds_client_get_iam_profile(m_client, s_onIamProfileAcquired, wrappedCallbackArgs);
+ }
+
+ int ImdsClient::GetUserData(OnResourceAcquired callback, void *userData)
+ {
+ auto wrappedCallbackArgs = Aws::Crt::New<WrappedCallbackArgs<OnResourceAcquired>>(
+ m_allocator, m_allocator, callback, userData);
+ if (wrappedCallbackArgs == nullptr)
+ {
+ return AWS_OP_ERR;
+ }
+ return aws_imds_client_get_user_data(m_client, s_onResourceAcquired, wrappedCallbackArgs);
+ }
+
+ int ImdsClient::GetInstanceSignature(OnResourceAcquired callback, void *userData)
+ {
+ auto wrappedCallbackArgs = Aws::Crt::New<WrappedCallbackArgs<OnResourceAcquired>>(
+ m_allocator, m_allocator, callback, userData);
+ if (wrappedCallbackArgs == nullptr)
+ {
+ return AWS_OP_ERR;
+ }
+ return aws_imds_client_get_instance_signature(m_client, s_onResourceAcquired, wrappedCallbackArgs);
+ }
+
+ int ImdsClient::GetInstanceInfo(OnInstanceInfoAcquired callback, void *userData)
+ {
+ auto wrappedCallbackArgs = Aws::Crt::New<WrappedCallbackArgs<OnInstanceInfoAcquired>>(
+ m_allocator, m_allocator, callback, userData);
+ if (wrappedCallbackArgs == nullptr)
+ {
+ return AWS_OP_ERR;
+ }
+ return aws_imds_client_get_instance_info(m_client, s_onInstanceInfoAcquired, wrappedCallbackArgs);
+ }
+ } // namespace Imds
+ } // namespace Crt
+
+} // namespace Aws
diff --git a/contrib/restricted/aws/aws-crt-cpp/source/JsonObject.cpp b/contrib/restricted/aws/aws-crt-cpp/source/JsonObject.cpp
new file mode 100644
index 0000000000..86a3ae73fc
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/source/JsonObject.cpp
@@ -0,0 +1,596 @@
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+
+#include <aws/crt/JsonObject.h>
+
+#include <aws/crt/external/cJSON.h>
+
+#include <algorithm>
+#include <iterator>
+
+namespace Aws
+{
+ namespace Crt
+ {
+ JsonObject::JsonObject() : m_wasParseSuccessful(true) { m_value = nullptr; }
+
+ JsonObject::JsonObject(cJSON *value)
+ : m_value(cJSON_Duplicate(value, 1 /* recurse */)), m_wasParseSuccessful(true)
+ {
+ }
+
+ JsonObject::JsonObject(const String &value) : m_wasParseSuccessful(true)
+ {
+ const char *return_parse_end;
+ m_value = cJSON_ParseWithLengthOpts(value.c_str(), value.length(), &return_parse_end, 0);
+
+ if (m_value == nullptr || cJSON_IsInvalid(m_value) == 1)
+ {
+ m_wasParseSuccessful = false;
+ m_errorMessage = "Failed to parse JSON at: ";
+ m_errorMessage += return_parse_end;
+ }
+ }
+
+ JsonObject::JsonObject(const JsonObject &value)
+ : m_value(cJSON_Duplicate(value.m_value, 1 /*recurse*/)), m_wasParseSuccessful(value.m_wasParseSuccessful),
+ m_errorMessage(value.m_errorMessage)
+ {
+ }
+
+ JsonObject::JsonObject(JsonObject &&value) noexcept
+ : m_value(value.m_value), m_wasParseSuccessful(value.m_wasParseSuccessful),
+ m_errorMessage(std::move(value.m_errorMessage))
+ {
+ value.m_value = nullptr;
+ }
+
+ void JsonObject::Destroy() { cJSON_Delete(m_value); }
+
+ JsonObject::~JsonObject() { Destroy(); }
+
+ JsonObject &JsonObject::operator=(const JsonObject &other)
+ {
+ if (this == &other)
+ {
+ return *this;
+ }
+
+ Destroy();
+ m_value = cJSON_Duplicate(other.m_value, 1 /*recurse*/);
+ m_wasParseSuccessful = other.m_wasParseSuccessful;
+ m_errorMessage = other.m_errorMessage;
+ return *this;
+ }
+
+ JsonObject &JsonObject::operator=(JsonObject &&other) noexcept
+ {
+ if (this == &other)
+ {
+ return *this;
+ }
+
+ using std::swap;
+ swap(m_value, other.m_value);
+ swap(m_errorMessage, other.m_errorMessage);
+ m_wasParseSuccessful = other.m_wasParseSuccessful;
+ return *this;
+ }
+
+ static void AddOrReplace(cJSON *root, const char *key, cJSON *value)
+ {
+ const auto existing = cJSON_GetObjectItemCaseSensitive(root, key);
+ if (existing != nullptr)
+ {
+ cJSON_ReplaceItemInObjectCaseSensitive(root, key, value);
+ }
+ else
+ {
+ cJSON_AddItemToObject(root, key, value);
+ }
+ }
+
+ JsonObject &JsonObject::WithString(const char *key, const String &value)
+ {
+ if (m_value == nullptr)
+ {
+ m_value = cJSON_CreateObject();
+ }
+
+ const auto val = cJSON_CreateString(value.c_str());
+ AddOrReplace(m_value, key, val);
+ return *this;
+ }
+
+ JsonObject &JsonObject::WithString(const String &key, const String &value)
+ {
+ return WithString(key.c_str(), value);
+ }
+
+ JsonObject &JsonObject::AsString(const String &value)
+ {
+ Destroy();
+ m_value = cJSON_CreateString(value.c_str());
+ return *this;
+ }
+
+ JsonObject &JsonObject::WithBool(const char *key, bool value)
+ {
+ if (m_value == nullptr)
+ {
+ m_value = cJSON_CreateObject();
+ }
+
+ const auto val = cJSON_CreateBool((cJSON_bool)value);
+ AddOrReplace(m_value, key, val);
+ return *this;
+ }
+
+ JsonObject &JsonObject::WithBool(const String &key, bool value) { return WithBool(key.c_str(), value); }
+
+ JsonObject &JsonObject::AsBool(bool value)
+ {
+ Destroy();
+ m_value = cJSON_CreateBool((cJSON_bool)value);
+ return *this;
+ }
+
+ JsonObject &JsonObject::WithInteger(const char *key, int value)
+ {
+ return WithDouble(key, static_cast<double>(value));
+ }
+
+ JsonObject &JsonObject::WithInteger(const String &key, int value)
+ {
+ return WithDouble(key.c_str(), static_cast<double>(value));
+ }
+
+ JsonObject &JsonObject::AsInteger(int value)
+ {
+ Destroy();
+ m_value = cJSON_CreateNumber(static_cast<double>(value));
+ return *this;
+ }
+
+ JsonObject &JsonObject::WithInt64(const char *key, int64_t value)
+ {
+ return WithDouble(key, static_cast<double>(value));
+ }
+
+ JsonObject &JsonObject::WithInt64(const String &key, int64_t value)
+ {
+ return WithDouble(key.c_str(), static_cast<double>(value));
+ }
+
+ JsonObject &JsonObject::AsInt64(int64_t value) { return AsDouble(static_cast<double>(value)); }
+
+ JsonObject &JsonObject::WithDouble(const char *key, double value)
+ {
+ if (m_value == nullptr)
+ {
+ m_value = cJSON_CreateObject();
+ }
+
+ const auto val = cJSON_CreateNumber(value);
+ AddOrReplace(m_value, key, val);
+ return *this;
+ }
+
+ JsonObject &JsonObject::WithDouble(const String &key, double value) { return WithDouble(key.c_str(), value); }
+
+ JsonObject &JsonObject::AsDouble(double value)
+ {
+ Destroy();
+ m_value = cJSON_CreateNumber(value);
+ return *this;
+ }
+
+ JsonObject &JsonObject::WithArray(const char *key, const Vector<String> &array)
+ {
+ if (m_value == nullptr)
+ {
+ m_value = cJSON_CreateObject();
+ }
+
+ auto arrayValue = cJSON_CreateArray();
+ for (const auto &i : array)
+ {
+ cJSON_AddItemToArray(arrayValue, cJSON_CreateString(i.c_str()));
+ }
+
+ AddOrReplace(m_value, key, arrayValue);
+ return *this;
+ }
+
+ JsonObject &JsonObject::WithArray(const String &key, const Vector<String> &array)
+ {
+ return WithArray(key.c_str(), array);
+ }
+
+ JsonObject &JsonObject::WithArray(const String &key, const Vector<JsonObject> &array)
+ {
+ if (m_value == nullptr)
+ {
+ m_value = cJSON_CreateObject();
+ }
+
+ auto arrayValue = cJSON_CreateArray();
+ for (const auto &i : array)
+ {
+ cJSON_AddItemToArray(arrayValue, cJSON_Duplicate(i.m_value, 1 /*recurse*/));
+ }
+
+ AddOrReplace(m_value, key.c_str(), arrayValue);
+ return *this;
+ }
+
+ JsonObject &JsonObject::WithArray(const String &key, Vector<JsonObject> &&array)
+ {
+ if (m_value == nullptr)
+ {
+ m_value = cJSON_CreateObject();
+ }
+
+ auto arrayValue = cJSON_CreateArray();
+ for (auto &i : array)
+ {
+ cJSON_AddItemToArray(arrayValue, i.m_value);
+ i.m_value = nullptr;
+ }
+
+ AddOrReplace(m_value, key.c_str(), arrayValue);
+ return *this;
+ }
+
+ JsonObject &JsonObject::AsArray(const Vector<JsonObject> &array)
+ {
+ auto arrayValue = cJSON_CreateArray();
+ for (const auto &i : array)
+ {
+ cJSON_AddItemToArray(arrayValue, cJSON_Duplicate(i.m_value, 1 /*recurse*/));
+ }
+
+ Destroy();
+ m_value = arrayValue;
+ return *this;
+ }
+
+ JsonObject &JsonObject::AsArray(Vector<JsonObject> &&array)
+ {
+ auto arrayValue = cJSON_CreateArray();
+ for (auto &i : array)
+ {
+ cJSON_AddItemToArray(arrayValue, i.m_value);
+ i.m_value = nullptr;
+ }
+
+ Destroy();
+ m_value = arrayValue;
+ return *this;
+ }
+
+ JsonObject &JsonObject::AsNull()
+ {
+ m_value = cJSON_CreateNull();
+ return *this;
+ }
+
+ JsonObject &JsonObject::WithObject(const char *key, const JsonObject &value)
+ {
+ if (m_value == nullptr)
+ {
+ m_value = cJSON_CreateObject();
+ }
+
+ const auto copy =
+ value.m_value == nullptr ? cJSON_CreateObject() : cJSON_Duplicate(value.m_value, 1 /*recurse*/);
+ AddOrReplace(m_value, key, copy);
+ return *this;
+ }
+
+ JsonObject &JsonObject::WithObject(const String &key, const JsonObject &value)
+ {
+ return WithObject(key.c_str(), value);
+ }
+
+ JsonObject &JsonObject::WithObject(const char *key, JsonObject &&value)
+ {
+ if (m_value == nullptr)
+ {
+ m_value = cJSON_CreateObject();
+ }
+
+ AddOrReplace(m_value, key, value.m_value == nullptr ? cJSON_CreateObject() : value.m_value);
+ value.m_value = nullptr;
+ return *this;
+ }
+
+ JsonObject &JsonObject::WithObject(const String &key, JsonObject &&value)
+ {
+ return WithObject(key.c_str(), std::move(value));
+ }
+
+ JsonObject &JsonObject::AsObject(const JsonObject &value)
+ {
+ *this = value;
+ return *this;
+ }
+
+ JsonObject &JsonObject::AsObject(JsonObject &&value)
+ {
+ *this = std::move(value);
+ return *this;
+ }
+
+ bool JsonObject::operator==(const JsonObject &other) const
+ {
+ return cJSON_Compare(m_value, other.m_value, 1 /*case-sensitive*/) != 0;
+ }
+
+ bool JsonObject::operator!=(const JsonObject &other) const { return !(*this == other); }
+
+ JsonView JsonObject::View() const { return *this; }
+
+ JsonView::JsonView() : m_value(nullptr) {}
+
+ JsonView::JsonView(const JsonObject &val) : m_value(val.m_value) {}
+
+ JsonView::JsonView(cJSON *val) : m_value(val) {}
+
+ JsonView &JsonView::operator=(const JsonObject &v)
+ {
+ m_value = v.m_value;
+ return *this;
+ }
+
+ JsonView &JsonView::operator=(cJSON *val)
+ {
+ m_value = val;
+ return *this;
+ }
+
+ String JsonView::GetString(const String &key) const { return GetString(key.c_str()); }
+
+ String JsonView::GetString(const char *key) const
+ {
+ AWS_ASSERT(m_value);
+ auto item = cJSON_GetObjectItemCaseSensitive(m_value, key);
+ auto str = cJSON_GetStringValue(item);
+ return str != nullptr ? str : "";
+ }
+
+ String JsonView::AsString() const
+ {
+ const char *str = cJSON_GetStringValue(m_value);
+ if (str == nullptr)
+ {
+ return {};
+ }
+ return str;
+ }
+
+ bool JsonView::GetBool(const String &key) const { return GetBool(key.c_str()); }
+
+ bool JsonView::GetBool(const char *key) const
+ {
+ AWS_ASSERT(m_value);
+ auto item = cJSON_GetObjectItemCaseSensitive(m_value, key);
+ AWS_ASSERT(item);
+ return cJSON_IsTrue(item) != 0;
+ }
+
+ bool JsonView::AsBool() const
+ {
+ AWS_ASSERT(cJSON_IsBool(m_value));
+ return cJSON_IsTrue(m_value) != 0;
+ }
+
+ int JsonView::GetInteger(const String &key) const { return GetInteger(key.c_str()); }
+
+ int JsonView::GetInteger(const char *key) const
+ {
+ AWS_ASSERT(m_value);
+ auto item = cJSON_GetObjectItemCaseSensitive(m_value, key);
+ AWS_ASSERT(item);
+ return item->valueint;
+ }
+
+ int JsonView::AsInteger() const
+ {
+ AWS_ASSERT(cJSON_IsNumber(m_value)); // can be double or value larger than int_max, but at least not UB
+ return m_value->valueint;
+ }
+
+ int64_t JsonView::GetInt64(const String &key) const { return static_cast<int64_t>(GetDouble(key)); }
+
+ int64_t JsonView::GetInt64(const char *key) const { return static_cast<int64_t>(GetDouble(key)); }
+
+ int64_t JsonView::AsInt64() const
+ {
+ AWS_ASSERT(cJSON_IsNumber(m_value));
+ return static_cast<int64_t>(m_value->valuedouble);
+ }
+
+ double JsonView::GetDouble(const String &key) const { return GetDouble(key.c_str()); }
+
+ double JsonView::GetDouble(const char *key) const
+ {
+ AWS_ASSERT(m_value);
+ auto item = cJSON_GetObjectItemCaseSensitive(m_value, key);
+ AWS_ASSERT(item);
+ return item->valuedouble;
+ }
+
+ double JsonView::AsDouble() const
+ {
+ AWS_ASSERT(cJSON_IsNumber(m_value));
+ return m_value->valuedouble;
+ }
+
+ JsonView JsonView::GetJsonObject(const String &key) const { return GetJsonObject(key.c_str()); }
+
+ JsonView JsonView::GetJsonObject(const char *key) const
+ {
+ AWS_ASSERT(m_value);
+ auto item = cJSON_GetObjectItemCaseSensitive(m_value, key);
+ return item;
+ }
+
+ JsonObject JsonView::GetJsonObjectCopy(const String &key) const { return GetJsonObjectCopy(key.c_str()); }
+
+ JsonObject JsonView::GetJsonObjectCopy(const char *key) const
+ {
+ AWS_ASSERT(m_value);
+ /* force a deep copy */
+ return JsonObject(cJSON_GetObjectItemCaseSensitive(m_value, key));
+ }
+
+ JsonView JsonView::AsObject() const
+ {
+ AWS_ASSERT(cJSON_IsObject(m_value));
+ return m_value;
+ }
+
+ Vector<JsonView> JsonView::GetArray(const String &key) const { return GetArray(key.c_str()); }
+
+ Vector<JsonView> JsonView::GetArray(const char *key) const
+ {
+ AWS_ASSERT(m_value);
+ auto array = cJSON_GetObjectItemCaseSensitive(m_value, key);
+ AWS_ASSERT(cJSON_IsArray(array));
+ Vector<JsonView> returnArray(static_cast<size_t>(cJSON_GetArraySize(array)));
+
+ auto element = array->child;
+ for (size_t i = 0; element != nullptr && i < returnArray.size(); ++i, element = element->next)
+ {
+ returnArray[i] = element;
+ }
+
+ return returnArray;
+ }
+
+ Vector<JsonView> JsonView::AsArray() const
+ {
+ AWS_ASSERT(cJSON_IsArray(m_value));
+ Vector<JsonView> returnArray(static_cast<size_t>(cJSON_GetArraySize(m_value)));
+
+ auto element = m_value->child;
+
+ for (size_t i = 0; element != nullptr && i < returnArray.size(); ++i, element = element->next)
+ {
+ returnArray[i] = element;
+ }
+
+ return returnArray;
+ }
+
+ Map<String, JsonView> JsonView::GetAllObjects() const
+ {
+ Map<String, JsonView> valueMap;
+ if (m_value == nullptr)
+ {
+ return valueMap;
+ }
+
+ for (auto iter = m_value->child; iter != nullptr; iter = iter->next)
+ {
+ valueMap.emplace(std::make_pair(String(iter->string), JsonView(iter)));
+ }
+
+ return valueMap;
+ }
+
+ bool JsonView::ValueExists(const String &key) const { return ValueExists(key.c_str()); }
+
+ bool JsonView::ValueExists(const char *key) const
+ {
+ if (cJSON_IsObject(m_value) == 0)
+ {
+ return false;
+ }
+
+ auto item = cJSON_GetObjectItemCaseSensitive(m_value, key);
+ return !(item == nullptr || cJSON_IsNull(item) != 0);
+ }
+
+ bool JsonView::KeyExists(const String &key) const { return KeyExists(key.c_str()); }
+
+ bool JsonView::KeyExists(const char *key) const
+ {
+ if (cJSON_IsObject(m_value) == 0)
+ {
+ return false;
+ }
+
+ return cJSON_GetObjectItemCaseSensitive(m_value, key) != nullptr;
+ }
+
+ bool JsonView::IsObject() const { return cJSON_IsObject(m_value) != 0; }
+
+ bool JsonView::IsBool() const { return cJSON_IsBool(m_value) != 0; }
+
+ bool JsonView::IsString() const { return cJSON_IsString(m_value) != 0; }
+
+ bool JsonView::IsIntegerType() const
+ {
+ if (cJSON_IsNumber(m_value) == 0)
+ {
+ return false;
+ }
+
+ return m_value->valuedouble == static_cast<int64_t>(m_value->valuedouble);
+ }
+
+ bool JsonView::IsFloatingPointType() const
+ {
+ if (cJSON_IsNumber(m_value) == 0)
+ {
+ return false;
+ }
+
+ return m_value->valuedouble != static_cast<int64_t>(m_value->valuedouble);
+ }
+
+ bool JsonView::IsListType() const { return cJSON_IsArray(m_value) != 0; }
+
+ bool JsonView::IsNull() const { return cJSON_IsNull(m_value) != 0; }
+
+ String JsonView::WriteCompact(bool treatAsObject) const
+ {
+ if (m_value == nullptr)
+ {
+ if (treatAsObject)
+ {
+ return "{}";
+ }
+ return "";
+ }
+
+ auto temp = cJSON_PrintUnformatted(m_value);
+ String out(temp);
+ cJSON_free(temp);
+ return out;
+ }
+
+ String JsonView::WriteReadable(bool treatAsObject) const
+ {
+ if (m_value == nullptr)
+ {
+ if (treatAsObject)
+ {
+ return "{\n}\n";
+ }
+ return "";
+ }
+
+ auto temp = cJSON_Print(m_value);
+ String out(temp);
+ cJSON_free(temp);
+ return out;
+ }
+
+ JsonObject JsonView::Materialize() const { return m_value; }
+ } // namespace Crt
+} // namespace Aws
diff --git a/contrib/restricted/aws/aws-crt-cpp/source/StringUtils.cpp b/contrib/restricted/aws/aws-crt-cpp/source/StringUtils.cpp
new file mode 100644
index 0000000000..5c6984f628
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/source/StringUtils.cpp
@@ -0,0 +1,15 @@
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+#include <aws/crt/StringUtils.h>
+
+#include <aws/common/hash_table.h>
+
+namespace Aws
+{
+ namespace Crt
+ {
+ size_t HashString(const char *str) noexcept { return (size_t)aws_hash_c_string(str); }
+ } // namespace Crt
+} // namespace Aws
diff --git a/contrib/restricted/aws/aws-crt-cpp/source/Types.cpp b/contrib/restricted/aws/aws-crt-cpp/source/Types.cpp
new file mode 100644
index 0000000000..89f0626242
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/source/Types.cpp
@@ -0,0 +1,103 @@
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+#include <aws/crt/Types.h>
+
+#include <aws/common/encoding.h>
+
+namespace Aws
+{
+ namespace Crt
+ {
+ ByteBuf ByteBufFromCString(const char *str) noexcept { return aws_byte_buf_from_c_str(str); }
+
+ ByteBuf ByteBufFromEmptyArray(const uint8_t *array, size_t len) noexcept
+ {
+ return aws_byte_buf_from_empty_array(array, len);
+ }
+
+ ByteBuf ByteBufFromArray(const uint8_t *array, size_t capacity) noexcept
+ {
+ return aws_byte_buf_from_array(array, capacity);
+ }
+
+ ByteBuf ByteBufNewCopy(Allocator *alloc, const uint8_t *array, size_t len)
+ {
+ ByteBuf retVal;
+ ByteBuf src = aws_byte_buf_from_array(array, len);
+ aws_byte_buf_init_copy(&retVal, alloc, &src);
+ return retVal;
+ }
+
+ void ByteBufDelete(ByteBuf &buf) { aws_byte_buf_clean_up(&buf); }
+
+ ByteCursor ByteCursorFromCString(const char *str) noexcept { return aws_byte_cursor_from_c_str(str); }
+
+ ByteCursor ByteCursorFromString(const Crt::String &str) noexcept
+ {
+ return aws_byte_cursor_from_array((const void *)str.data(), str.length());
+ }
+
+ ByteCursor ByteCursorFromStringView(const Crt::StringView &str) noexcept
+ {
+ return aws_byte_cursor_from_array((const void *)str.data(), str.length());
+ }
+
+ ByteCursor ByteCursorFromByteBuf(const ByteBuf &buf) noexcept { return aws_byte_cursor_from_buf(&buf); }
+
+ ByteCursor ByteCursorFromArray(const uint8_t *array, size_t len) noexcept
+ {
+ return aws_byte_cursor_from_array(array, len);
+ }
+
+ Vector<uint8_t> Base64Decode(const String &decode)
+ {
+ ByteCursor toDecode = ByteCursorFromString(decode);
+
+ size_t allocation_size = 0;
+
+ if (aws_base64_compute_decoded_len(&toDecode, &allocation_size) == AWS_OP_SUCCESS)
+ {
+ Vector<uint8_t> output(allocation_size, 0x00);
+ ByteBuf tempBuf = aws_byte_buf_from_array(output.data(), output.size());
+ tempBuf.len = 0;
+
+ if (aws_base64_decode(&toDecode, &tempBuf) == AWS_OP_SUCCESS)
+ {
+ return output;
+ }
+ }
+
+ return {};
+ }
+
+ String Base64Encode(const Vector<uint8_t> &encode)
+ {
+ ByteCursor toEncode = aws_byte_cursor_from_array((const void *)encode.data(), encode.size());
+
+ size_t allocation_size = 0;
+
+ if (aws_base64_compute_encoded_len(encode.size(), &allocation_size) == AWS_OP_SUCCESS)
+ {
+ String output(allocation_size, 0x00);
+ ByteBuf tempBuf = aws_byte_buf_from_array(output.data(), output.size());
+ tempBuf.len = 0;
+
+ if (aws_base64_encode(&toEncode, &tempBuf) == AWS_OP_SUCCESS)
+ {
+ // encoding appends a null terminator, and accounts for it in the encoded length,
+ // which makes the string 1 character too long
+ if (output.back() == 0)
+ {
+ output.pop_back();
+ }
+ return output;
+ }
+ }
+
+ return {};
+ }
+
+ } // namespace Crt
+} // namespace Aws
diff --git a/contrib/restricted/aws/aws-crt-cpp/source/UUID.cpp b/contrib/restricted/aws/aws-crt-cpp/source/UUID.cpp
new file mode 100644
index 0000000000..c985ea2778
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/source/UUID.cpp
@@ -0,0 +1,54 @@
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+#include <aws/crt/UUID.h>
+
+namespace Aws
+{
+ namespace Crt
+ {
+ UUID::UUID() noexcept : m_good(false)
+ {
+ if (aws_uuid_init(&m_uuid) == AWS_OP_SUCCESS)
+ {
+ m_good = true;
+ }
+ }
+
+ UUID::UUID(const String &str) noexcept : m_good(false)
+ {
+ auto strCur = aws_byte_cursor_from_c_str(str.c_str());
+ if (aws_uuid_init_from_str(&m_uuid, &strCur) == AWS_OP_SUCCESS)
+ {
+ m_good = true;
+ }
+ }
+
+ UUID &UUID::operator=(const String &str) noexcept
+ {
+ *this = UUID(str);
+ return *this;
+ }
+
+ bool UUID::operator==(const UUID &other) noexcept { return aws_uuid_equals(&m_uuid, &other.m_uuid); }
+
+ bool UUID::operator!=(const UUID &other) noexcept { return !aws_uuid_equals(&m_uuid, &other.m_uuid); }
+
+ String UUID::ToString() const
+ {
+ String uuidStr;
+ uuidStr.resize(AWS_UUID_STR_LEN);
+ auto outBuf = ByteBufFromEmptyArray(reinterpret_cast<const uint8_t *>(uuidStr.data()), uuidStr.capacity());
+ aws_uuid_to_str(&m_uuid, &outBuf);
+ uuidStr.resize(outBuf.len);
+ return uuidStr;
+ }
+
+ UUID::operator String() const { return ToString(); }
+
+ UUID::operator ByteBuf() const noexcept { return ByteBufFromArray(m_uuid.uuid_data, sizeof(m_uuid.uuid_data)); }
+
+ int UUID::GetLastError() const noexcept { return aws_last_error(); }
+ } // namespace Crt
+} // namespace Aws \ No newline at end of file
diff --git a/contrib/restricted/aws/aws-crt-cpp/source/auth/Credentials.cpp b/contrib/restricted/aws/aws-crt-cpp/source/auth/Credentials.cpp
new file mode 100644
index 0000000000..77e40c61a9
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/source/auth/Credentials.cpp
@@ -0,0 +1,478 @@
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+
+#include <aws/crt/auth/Credentials.h>
+
+#include <aws/crt/http/HttpConnection.h>
+#include <aws/crt/http/HttpProxyStrategy.h>
+
+#include <aws/auth/credentials.h>
+#include <aws/common/string.h>
+
+#include <algorithm>
+#include <aws/http/connection.h>
+
+#include <aws/crt/Api.h>
+
+namespace Aws
+{
+ namespace Crt
+ {
+ namespace Auth
+ {
+ Credentials::Credentials(const aws_credentials *credentials) noexcept : m_credentials(credentials)
+ {
+ if (credentials != nullptr)
+ {
+ aws_credentials_acquire(credentials);
+ }
+ }
+
+ Credentials::Credentials(
+ ByteCursor access_key_id,
+ ByteCursor secret_access_key,
+ ByteCursor session_token,
+ uint64_t expiration_timepoint_in_seconds,
+ Allocator *allocator) noexcept
+ : m_credentials(aws_credentials_new(
+ allocator,
+ access_key_id,
+ secret_access_key,
+ session_token,
+ expiration_timepoint_in_seconds))
+ {
+ }
+
+ Credentials::Credentials(Allocator *allocator) noexcept
+ : m_credentials(aws_credentials_new_anonymous(allocator))
+ {
+ }
+
+ Credentials::~Credentials()
+ {
+ aws_credentials_release(m_credentials);
+ m_credentials = nullptr;
+ }
+
+ ByteCursor Credentials::GetAccessKeyId() const noexcept
+ {
+ if (m_credentials)
+ {
+ return aws_credentials_get_access_key_id(m_credentials);
+ }
+ else
+ {
+ return ByteCursor{0, nullptr};
+ }
+ }
+
+ ByteCursor Credentials::GetSecretAccessKey() const noexcept
+ {
+ if (m_credentials)
+ {
+ return aws_credentials_get_secret_access_key(m_credentials);
+ }
+ else
+ {
+ return ByteCursor{0, nullptr};
+ }
+ }
+
+ ByteCursor Credentials::GetSessionToken() const noexcept
+ {
+ if (m_credentials)
+ {
+ return aws_credentials_get_session_token(m_credentials);
+ }
+ else
+ {
+ return ByteCursor{0, nullptr};
+ }
+ }
+
+ uint64_t Credentials::GetExpirationTimepointInSeconds() const noexcept
+ {
+ if (m_credentials)
+ {
+ return aws_credentials_get_expiration_timepoint_seconds(m_credentials);
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+ Credentials::operator bool() const noexcept { return m_credentials != nullptr; }
+
+ CredentialsProvider::CredentialsProvider(aws_credentials_provider *provider, Allocator *allocator) noexcept
+ : m_allocator(allocator), m_provider(provider)
+ {
+ }
+
+ CredentialsProvider::~CredentialsProvider()
+ {
+ if (m_provider)
+ {
+ aws_credentials_provider_release(m_provider);
+ m_provider = nullptr;
+ }
+ }
+
+ struct CredentialsProviderCallbackArgs
+ {
+ CredentialsProviderCallbackArgs() = default;
+
+ OnCredentialsResolved m_onCredentialsResolved;
+ std::shared_ptr<const CredentialsProvider> m_provider;
+ };
+
+ void CredentialsProvider::s_onCredentialsResolved(
+ aws_credentials *credentials,
+ int error_code,
+ void *user_data)
+ {
+ CredentialsProviderCallbackArgs *callbackArgs =
+ static_cast<CredentialsProviderCallbackArgs *>(user_data);
+
+ auto credentialsPtr =
+ Aws::Crt::MakeShared<Credentials>(callbackArgs->m_provider->m_allocator, credentials);
+
+ callbackArgs->m_onCredentialsResolved(credentialsPtr, error_code);
+
+ Aws::Crt::Delete(callbackArgs, callbackArgs->m_provider->m_allocator);
+ }
+
+ bool CredentialsProvider::GetCredentials(const OnCredentialsResolved &onCredentialsResolved) const
+ {
+ if (m_provider == nullptr)
+ {
+ return false;
+ }
+
+ auto callbackArgs = Aws::Crt::New<CredentialsProviderCallbackArgs>(m_allocator);
+ if (callbackArgs == nullptr)
+ {
+ return false;
+ }
+
+ callbackArgs->m_provider = std::static_pointer_cast<const CredentialsProvider>(shared_from_this());
+ callbackArgs->m_onCredentialsResolved = onCredentialsResolved;
+
+ aws_credentials_provider_get_credentials(m_provider, s_onCredentialsResolved, callbackArgs);
+
+ return true;
+ }
+
+ static std::shared_ptr<ICredentialsProvider> s_CreateWrappedProvider(
+ struct aws_credentials_provider *raw_provider,
+ Allocator *allocator)
+ {
+ if (raw_provider == nullptr)
+ {
+ return nullptr;
+ }
+
+ /* Switch to some kind of make_shared/allocate_shared when allocator support improves */
+ auto provider = Aws::Crt::MakeShared<CredentialsProvider>(allocator, raw_provider, allocator);
+ return std::static_pointer_cast<ICredentialsProvider>(provider);
+ }
+
+ std::shared_ptr<ICredentialsProvider> CredentialsProvider::CreateCredentialsProviderStatic(
+ const CredentialsProviderStaticConfig &config,
+ Allocator *allocator)
+ {
+ aws_credentials_provider_static_options staticOptions;
+ AWS_ZERO_STRUCT(staticOptions);
+ staticOptions.access_key_id = config.AccessKeyId;
+ staticOptions.secret_access_key = config.SecretAccessKey;
+ staticOptions.session_token = config.SessionToken;
+ return s_CreateWrappedProvider(
+ aws_credentials_provider_new_static(allocator, &staticOptions), allocator);
+ }
+
+ std::shared_ptr<ICredentialsProvider> CredentialsProvider::CreateCredentialsProviderAnonymous(
+ Allocator *allocator)
+ {
+ aws_credentials_provider_shutdown_options shutdown_options;
+ AWS_ZERO_STRUCT(shutdown_options);
+
+ return s_CreateWrappedProvider(
+ aws_credentials_provider_new_anonymous(allocator, &shutdown_options), allocator);
+ }
+
+ std::shared_ptr<ICredentialsProvider> CredentialsProvider::CreateCredentialsProviderEnvironment(
+ Allocator *allocator)
+ {
+ aws_credentials_provider_environment_options environmentOptions;
+ AWS_ZERO_STRUCT(environmentOptions);
+ return s_CreateWrappedProvider(
+ aws_credentials_provider_new_environment(allocator, &environmentOptions), allocator);
+ }
+
+ std::shared_ptr<ICredentialsProvider> CredentialsProvider::CreateCredentialsProviderProfile(
+ const CredentialsProviderProfileConfig &config,
+ Allocator *allocator)
+ {
+ struct aws_credentials_provider_profile_options raw_config;
+ AWS_ZERO_STRUCT(raw_config);
+
+ raw_config.config_file_name_override = config.ConfigFileNameOverride;
+ raw_config.credentials_file_name_override = config.CredentialsFileNameOverride;
+ raw_config.profile_name_override = config.ProfileNameOverride;
+ raw_config.bootstrap = config.Bootstrap ? config.Bootstrap->GetUnderlyingHandle() : nullptr;
+ raw_config.tls_ctx = config.TlsContext ? config.TlsContext->GetUnderlyingHandle() : nullptr;
+
+ return s_CreateWrappedProvider(aws_credentials_provider_new_profile(allocator, &raw_config), allocator);
+ }
+
+ std::shared_ptr<ICredentialsProvider> CredentialsProvider::CreateCredentialsProviderImds(
+ const CredentialsProviderImdsConfig &config,
+ Allocator *allocator)
+ {
+ struct aws_credentials_provider_imds_options raw_config;
+ AWS_ZERO_STRUCT(raw_config);
+
+ if (config.Bootstrap != nullptr)
+ {
+ raw_config.bootstrap = config.Bootstrap->GetUnderlyingHandle();
+ }
+ else
+ {
+ raw_config.bootstrap = ApiHandle::GetOrCreateStaticDefaultClientBootstrap()->GetUnderlyingHandle();
+ }
+
+ return s_CreateWrappedProvider(aws_credentials_provider_new_imds(allocator, &raw_config), allocator);
+ }
+
+ std::shared_ptr<ICredentialsProvider> CredentialsProvider::CreateCredentialsProviderChain(
+ const CredentialsProviderChainConfig &config,
+ Allocator *allocator)
+ {
+ Vector<aws_credentials_provider *> providers;
+ providers.reserve(config.Providers.size());
+
+ std::for_each(
+ config.Providers.begin(),
+ config.Providers.end(),
+ [&](const std::shared_ptr<ICredentialsProvider> &provider) {
+ providers.push_back(provider->GetUnderlyingHandle());
+ });
+
+ struct aws_credentials_provider_chain_options raw_config;
+ AWS_ZERO_STRUCT(raw_config);
+
+ raw_config.providers = providers.data();
+ raw_config.provider_count = config.Providers.size();
+
+ return s_CreateWrappedProvider(aws_credentials_provider_new_chain(allocator, &raw_config), allocator);
+ }
+
+ std::shared_ptr<ICredentialsProvider> CredentialsProvider::CreateCredentialsProviderCached(
+ const CredentialsProviderCachedConfig &config,
+ Allocator *allocator)
+ {
+ struct aws_credentials_provider_cached_options raw_config;
+ AWS_ZERO_STRUCT(raw_config);
+
+ raw_config.source = config.Provider->GetUnderlyingHandle();
+ raw_config.refresh_time_in_milliseconds = config.CachedCredentialTTL.count();
+
+ return s_CreateWrappedProvider(aws_credentials_provider_new_cached(allocator, &raw_config), allocator);
+ }
+
+ std::shared_ptr<ICredentialsProvider> CredentialsProvider::CreateCredentialsProviderChainDefault(
+ const CredentialsProviderChainDefaultConfig &config,
+ Allocator *allocator)
+ {
+ struct aws_credentials_provider_chain_default_options raw_config;
+ AWS_ZERO_STRUCT(raw_config);
+
+ raw_config.bootstrap =
+ config.Bootstrap ? config.Bootstrap->GetUnderlyingHandle()
+ : ApiHandle::GetOrCreateStaticDefaultClientBootstrap()->GetUnderlyingHandle();
+ raw_config.tls_ctx = config.TlsContext ? config.TlsContext->GetUnderlyingHandle() : nullptr;
+
+ return s_CreateWrappedProvider(
+ aws_credentials_provider_new_chain_default(allocator, &raw_config), allocator);
+ }
+
+ std::shared_ptr<ICredentialsProvider> CredentialsProvider::CreateCredentialsProviderX509(
+ const CredentialsProviderX509Config &config,
+ Allocator *allocator)
+ {
+ struct aws_credentials_provider_x509_options raw_config;
+ AWS_ZERO_STRUCT(raw_config);
+
+ raw_config.bootstrap =
+ config.Bootstrap ? config.Bootstrap->GetUnderlyingHandle()
+ : ApiHandle::GetOrCreateStaticDefaultClientBootstrap()->GetUnderlyingHandle();
+ raw_config.tls_connection_options = config.TlsOptions.GetUnderlyingHandle();
+ raw_config.thing_name = aws_byte_cursor_from_c_str(config.ThingName.c_str());
+ raw_config.role_alias = aws_byte_cursor_from_c_str(config.RoleAlias.c_str());
+ raw_config.endpoint = aws_byte_cursor_from_c_str(config.Endpoint.c_str());
+
+ struct aws_http_proxy_options proxy_options;
+ AWS_ZERO_STRUCT(proxy_options);
+ if (config.ProxyOptions.has_value())
+ {
+ const Http::HttpClientConnectionProxyOptions &proxy_config = config.ProxyOptions.value();
+ proxy_config.InitializeRawProxyOptions(proxy_options);
+
+ raw_config.proxy_options = &proxy_options;
+ }
+
+ return s_CreateWrappedProvider(aws_credentials_provider_new_x509(allocator, &raw_config), allocator);
+ }
+
+ struct DelegateCredentialsProviderCallbackArgs
+ {
+ DelegateCredentialsProviderCallbackArgs() = default;
+
+ Allocator *allocator;
+ GetCredentialsHandler m_Handler;
+ };
+
+ static int s_onDelegateGetCredentials(
+ void *delegate_user_data,
+ aws_on_get_credentials_callback_fn callback,
+ void *callback_user_data)
+ {
+ auto args = static_cast<DelegateCredentialsProviderCallbackArgs *>(delegate_user_data);
+ auto creds = args->m_Handler();
+ struct aws_credentials *m_credentials = (struct aws_credentials *)(void *)creds->GetUnderlyingHandle();
+ callback(m_credentials, AWS_ERROR_SUCCESS, callback_user_data);
+ return AWS_OP_SUCCESS;
+ }
+
+ static void s_onDelegateShutdownComplete(void *user_data)
+ {
+ auto args = static_cast<DelegateCredentialsProviderCallbackArgs *>(user_data);
+ Aws::Crt::Delete(args, args->allocator);
+ }
+
+ std::shared_ptr<ICredentialsProvider> CredentialsProvider::CreateCredentialsProviderDelegate(
+ const CredentialsProviderDelegateConfig &config,
+ Allocator *allocator)
+ {
+ struct aws_credentials_provider_delegate_options raw_config;
+ AWS_ZERO_STRUCT(raw_config);
+
+ auto delegateCallbackArgs = Aws::Crt::New<DelegateCredentialsProviderCallbackArgs>(allocator);
+ delegateCallbackArgs->allocator = allocator;
+ delegateCallbackArgs->m_Handler = config.Handler;
+ raw_config.delegate_user_data = delegateCallbackArgs;
+ raw_config.get_credentials = s_onDelegateGetCredentials;
+ aws_credentials_provider_shutdown_options options;
+ options.shutdown_callback = s_onDelegateShutdownComplete;
+ options.shutdown_user_data = delegateCallbackArgs;
+ raw_config.shutdown_options = options;
+ return s_CreateWrappedProvider(
+ aws_credentials_provider_new_delegate(allocator, &raw_config), allocator);
+ }
+
+ CredentialsProviderCognitoConfig::CredentialsProviderCognitoConfig() : Bootstrap(nullptr) {}
+
+ std::shared_ptr<ICredentialsProvider> CredentialsProvider::CreateCredentialsProviderCognito(
+ const CredentialsProviderCognitoConfig &config,
+ Allocator *allocator)
+ {
+ struct aws_credentials_provider_cognito_options raw_config;
+ AWS_ZERO_STRUCT(raw_config);
+
+ raw_config.endpoint = aws_byte_cursor_from_c_str(config.Endpoint.c_str());
+ raw_config.identity = aws_byte_cursor_from_c_str(config.Identity.c_str());
+
+ struct aws_byte_cursor custom_role_arn_cursor;
+ AWS_ZERO_STRUCT(custom_role_arn_cursor);
+ if (config.CustomRoleArn.has_value())
+ {
+ custom_role_arn_cursor = aws_byte_cursor_from_c_str(config.CustomRoleArn.value().c_str());
+ raw_config.custom_role_arn = &custom_role_arn_cursor;
+ }
+
+ Vector<struct aws_cognito_identity_provider_token_pair> logins;
+ if (config.Logins.has_value())
+ {
+ for (const auto &login_pair : config.Logins.value())
+ {
+ struct aws_cognito_identity_provider_token_pair cursor_login_pair;
+ AWS_ZERO_STRUCT(cursor_login_pair);
+
+ cursor_login_pair.identity_provider_name =
+ aws_byte_cursor_from_c_str(login_pair.IdentityProviderName.c_str());
+ cursor_login_pair.identity_provider_token =
+ aws_byte_cursor_from_c_str(login_pair.IdentityProviderToken.c_str());
+
+ logins.push_back(cursor_login_pair);
+ }
+
+ raw_config.login_count = logins.size();
+ raw_config.logins = logins.data();
+ }
+
+ raw_config.bootstrap =
+ config.Bootstrap ? config.Bootstrap->GetUnderlyingHandle()
+ : ApiHandle::GetOrCreateStaticDefaultClientBootstrap()->GetUnderlyingHandle();
+
+ raw_config.tls_ctx = config.TlsCtx.GetUnderlyingHandle();
+
+ struct aws_http_proxy_options proxy_options;
+ AWS_ZERO_STRUCT(proxy_options);
+ if (config.ProxyOptions.has_value())
+ {
+ const Http::HttpClientConnectionProxyOptions &proxy_config = config.ProxyOptions.value();
+ proxy_config.InitializeRawProxyOptions(proxy_options);
+
+ raw_config.http_proxy_options = &proxy_options;
+ }
+
+ return s_CreateWrappedProvider(
+ aws_credentials_provider_new_cognito_caching(allocator, &raw_config), allocator);
+ }
+
+ CredentialsProviderSTSConfig::CredentialsProviderSTSConfig() : Bootstrap(nullptr) {}
+
+ std::shared_ptr<ICredentialsProvider> CredentialsProvider::CreateCredentialsProviderSTS(
+ const CredentialsProviderSTSConfig &config,
+ Allocator *allocator)
+ {
+ if (config.Provider == nullptr)
+ {
+ AWS_LOGF_ERROR(
+ AWS_LS_AUTH_CREDENTIALS_PROVIDER,
+ "Failed to build STS credentials provider - missing required 'Provider' configuration "
+ "parameter");
+ return nullptr;
+ }
+
+ struct aws_credentials_provider_sts_options raw_config;
+ AWS_ZERO_STRUCT(raw_config);
+
+ raw_config.creds_provider = config.Provider->GetUnderlyingHandle();
+ raw_config.role_arn = aws_byte_cursor_from_c_str(config.RoleArn.c_str());
+ raw_config.session_name = aws_byte_cursor_from_c_str(config.SessionName.c_str());
+ raw_config.duration_seconds = config.DurationSeconds;
+
+ raw_config.bootstrap =
+ config.Bootstrap ? config.Bootstrap->GetUnderlyingHandle()
+ : ApiHandle::GetOrCreateStaticDefaultClientBootstrap()->GetUnderlyingHandle();
+
+ raw_config.tls_ctx = config.TlsCtx.GetUnderlyingHandle();
+
+ struct aws_http_proxy_options proxy_options;
+ AWS_ZERO_STRUCT(proxy_options);
+ if (config.ProxyOptions.has_value())
+ {
+ const Http::HttpClientConnectionProxyOptions &proxy_config = config.ProxyOptions.value();
+ proxy_config.InitializeRawProxyOptions(proxy_options);
+
+ raw_config.http_proxy_options = &proxy_options;
+ }
+
+ return s_CreateWrappedProvider(aws_credentials_provider_new_sts(allocator, &raw_config), allocator);
+ }
+ } // namespace Auth
+ } // namespace Crt
+} // namespace Aws
diff --git a/contrib/restricted/aws/aws-crt-cpp/source/auth/Sigv4Signing.cpp b/contrib/restricted/aws/aws-crt-cpp/source/auth/Sigv4Signing.cpp
new file mode 100644
index 0000000000..9586b85fab
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/source/auth/Sigv4Signing.cpp
@@ -0,0 +1,274 @@
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+
+#include <aws/crt/auth/Sigv4Signing.h>
+
+#include <aws/crt/auth/Credentials.h>
+#include <aws/crt/http/HttpRequestResponse.h>
+
+#include <aws/auth/signable.h>
+#include <aws/auth/signing.h>
+#include <aws/auth/signing_result.h>
+
+namespace Aws
+{
+ namespace Crt
+ {
+ namespace Auth
+ {
+ namespace SignedBodyValue
+ {
+ const char *EmptySha256 = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
+ const char *EmptySha256Str() { return EmptySha256; }
+
+ const char *UnsignedPayload = "UNSIGNED-PAYLOAD";
+ const char *UnsignedPayloadStr() { return UnsignedPayload; }
+
+ const char *StreamingAws4HmacSha256Payload = "STREAMING-AWS4-HMAC-SHA256-PAYLOAD";
+ const char *StreamingAws4HmacSha256PayloadStr() { return StreamingAws4HmacSha256Payload; }
+
+ const char *StreamingAws4HmacSha256Events = "STREAMING-AWS4-HMAC-SHA256-EVENTS";
+ const char *StreamingAws4HmacSha256EventsStr() { return StreamingAws4HmacSha256Events; }
+ } // namespace SignedBodyValue
+
+ AwsSigningConfig::AwsSigningConfig(Allocator *allocator)
+ : ISigningConfig(), m_allocator(allocator), m_credentialsProvider(nullptr), m_credentials(nullptr)
+ {
+ AWS_ZERO_STRUCT(m_config);
+
+ SetSigningAlgorithm(SigningAlgorithm::SigV4);
+ SetSignatureType(SignatureType::HttpRequestViaHeaders);
+ SetShouldNormalizeUriPath(true);
+ SetUseDoubleUriEncode(true);
+ SetOmitSessionToken(false);
+ SetSignedBodyHeader(SignedBodyHeaderType::None);
+ SetSigningTimepoint(DateTime::Now());
+ SetExpirationInSeconds(0);
+ m_config.config_type = AWS_SIGNING_CONFIG_AWS;
+ }
+
+ AwsSigningConfig::~AwsSigningConfig() { m_allocator = nullptr; }
+
+ SigningAlgorithm AwsSigningConfig::GetSigningAlgorithm() const noexcept
+ {
+ return static_cast<SigningAlgorithm>(m_config.algorithm);
+ }
+
+ void AwsSigningConfig::SetSigningAlgorithm(SigningAlgorithm algorithm) noexcept
+ {
+ m_config.algorithm = static_cast<aws_signing_algorithm>(algorithm);
+ }
+
+ SignatureType AwsSigningConfig::GetSignatureType() const noexcept
+ {
+ return static_cast<SignatureType>(m_config.signature_type);
+ }
+
+ void AwsSigningConfig::SetSignatureType(SignatureType signatureType) noexcept
+ {
+ m_config.signature_type = static_cast<aws_signature_type>(signatureType);
+ }
+
+ const Crt::String &AwsSigningConfig::GetRegion() const noexcept { return m_signingRegion; }
+
+ void AwsSigningConfig::SetRegion(const Crt::String &region) noexcept
+ {
+ m_signingRegion = region;
+ m_config.region = ByteCursorFromCString(m_signingRegion.c_str());
+ }
+
+ const Crt::String &AwsSigningConfig::GetService() const noexcept { return m_serviceName; }
+
+ void AwsSigningConfig::SetService(const Crt::String &service) noexcept
+ {
+ m_serviceName = service;
+ m_config.service = ByteCursorFromCString(m_serviceName.c_str());
+ }
+
+ DateTime AwsSigningConfig::GetSigningTimepoint() const noexcept
+ {
+ return {aws_date_time_as_millis(&m_config.date)};
+ }
+
+ void AwsSigningConfig::SetSigningTimepoint(const DateTime &date) noexcept
+ {
+ aws_date_time_init_epoch_millis(&m_config.date, date.Millis());
+ }
+
+ bool AwsSigningConfig::GetUseDoubleUriEncode() const noexcept
+ {
+ return m_config.flags.use_double_uri_encode;
+ }
+
+ void AwsSigningConfig::SetUseDoubleUriEncode(bool useDoubleUriEncode) noexcept
+ {
+ m_config.flags.use_double_uri_encode = useDoubleUriEncode;
+ }
+
+ bool AwsSigningConfig::GetShouldNormalizeUriPath() const noexcept
+ {
+ return m_config.flags.should_normalize_uri_path;
+ }
+
+ void AwsSigningConfig::SetShouldNormalizeUriPath(bool shouldNormalizeUriPath) noexcept
+ {
+ m_config.flags.should_normalize_uri_path = shouldNormalizeUriPath;
+ }
+
+ bool AwsSigningConfig::GetOmitSessionToken() const noexcept { return m_config.flags.omit_session_token; }
+
+ void AwsSigningConfig::SetOmitSessionToken(bool omitSessionToken) noexcept
+ {
+ m_config.flags.omit_session_token = omitSessionToken;
+ }
+
+ ShouldSignHeaderCb AwsSigningConfig::GetShouldSignHeaderCallback() const noexcept
+ {
+ return m_config.should_sign_header;
+ }
+
+ void AwsSigningConfig::SetShouldSignHeaderCallback(ShouldSignHeaderCb shouldSignHeaderCb) noexcept
+ {
+ m_config.should_sign_header = shouldSignHeaderCb;
+ }
+
+ void *AwsSigningConfig::GetShouldSignHeaderUserData() const noexcept
+ {
+ return m_config.should_sign_header_ud;
+ }
+
+ void AwsSigningConfig::SetShouldSignHeaderUserData(void *userData) noexcept
+ {
+ m_config.should_sign_header_ud = userData;
+ }
+
+ const Crt::String &AwsSigningConfig::GetSignedBodyValue() const noexcept { return m_signedBodyValue; }
+
+ void AwsSigningConfig::SetSignedBodyValue(const Crt::String &signedBodyValue) noexcept
+ {
+ m_signedBodyValue = signedBodyValue;
+ m_config.signed_body_value = ByteCursorFromString(m_signedBodyValue);
+ }
+
+ SignedBodyHeaderType AwsSigningConfig::GetSignedBodyHeader() const noexcept
+ {
+ return static_cast<SignedBodyHeaderType>(m_config.signed_body_header);
+ }
+
+ void AwsSigningConfig::SetSignedBodyHeader(SignedBodyHeaderType signedBodyHeader) noexcept
+ {
+ m_config.signed_body_header = static_cast<enum aws_signed_body_header_type>(signedBodyHeader);
+ }
+
+ uint64_t AwsSigningConfig::GetExpirationInSeconds() const noexcept
+ {
+ return m_config.expiration_in_seconds;
+ }
+
+ void AwsSigningConfig::SetExpirationInSeconds(uint64_t expirationInSeconds) noexcept
+ {
+ m_config.expiration_in_seconds = expirationInSeconds;
+ }
+
+ const std::shared_ptr<ICredentialsProvider> &AwsSigningConfig::GetCredentialsProvider() const noexcept
+ {
+ return m_credentialsProvider;
+ }
+
+ void AwsSigningConfig::SetCredentialsProvider(
+ const std::shared_ptr<ICredentialsProvider> &credsProvider) noexcept
+ {
+ m_credentialsProvider = credsProvider;
+ m_config.credentials_provider = m_credentialsProvider->GetUnderlyingHandle();
+ }
+
+ const std::shared_ptr<Credentials> &AwsSigningConfig::GetCredentials() const noexcept
+ {
+ return m_credentials;
+ }
+
+ void AwsSigningConfig::SetCredentials(const std::shared_ptr<Credentials> &credentials) noexcept
+ {
+ m_credentials = credentials;
+ m_config.credentials = m_credentials->GetUnderlyingHandle();
+ }
+
+ const struct aws_signing_config_aws *AwsSigningConfig::GetUnderlyingHandle() const noexcept
+ {
+ return &m_config;
+ }
+
+ /////////////////////////////////////////////////////////////////////////////////////////////
+
+ Sigv4HttpRequestSigner::Sigv4HttpRequestSigner(Aws::Crt::Allocator *allocator)
+ : IHttpRequestSigner(), m_allocator(allocator)
+ {
+ }
+
+ struct HttpSignerCallbackData
+ {
+ HttpSignerCallbackData() : Alloc(nullptr) {}
+ Allocator *Alloc;
+ ScopedResource<struct aws_signable> Signable;
+ OnHttpRequestSigningComplete OnRequestSigningComplete;
+ std::shared_ptr<Http::HttpRequest> Request;
+ };
+
+ static void s_http_signing_complete_fn(struct aws_signing_result *result, int errorCode, void *userdata)
+ {
+ auto cbData = reinterpret_cast<HttpSignerCallbackData *>(userdata);
+
+ if (errorCode == AWS_OP_SUCCESS)
+ {
+ aws_apply_signing_result_to_http_request(
+ cbData->Request->GetUnderlyingMessage(), cbData->Alloc, result);
+ }
+
+ cbData->OnRequestSigningComplete(cbData->Request, errorCode);
+ Crt::Delete(cbData, cbData->Alloc);
+ }
+
+ bool Sigv4HttpRequestSigner::SignRequest(
+ const std::shared_ptr<Aws::Crt::Http::HttpRequest> &request,
+ const ISigningConfig &config,
+ const OnHttpRequestSigningComplete &completionCallback)
+ {
+ if (config.GetType() != SigningConfigType::Aws)
+ {
+ aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
+ return false;
+ }
+
+ auto awsSigningConfig = static_cast<const AwsSigningConfig *>(&config);
+
+ if (!awsSigningConfig->GetCredentialsProvider() && !awsSigningConfig->GetCredentials())
+ {
+ aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
+ return false;
+ }
+
+ auto signerCallbackData = Crt::New<HttpSignerCallbackData>(m_allocator);
+
+ if (!signerCallbackData)
+ {
+ return false;
+ }
+
+ signerCallbackData->Alloc = m_allocator;
+ signerCallbackData->OnRequestSigningComplete = completionCallback;
+ signerCallbackData->Request = request;
+ signerCallbackData->Signable = ScopedResource<struct aws_signable>(
+ aws_signable_new_http_request(m_allocator, request->GetUnderlyingMessage()), aws_signable_destroy);
+
+ return aws_sign_request_aws(
+ m_allocator,
+ signerCallbackData->Signable.get(),
+ (aws_signing_config_base *)awsSigningConfig->GetUnderlyingHandle(),
+ s_http_signing_complete_fn,
+ signerCallbackData) == AWS_OP_SUCCESS;
+ }
+ } // namespace Auth
+ } // namespace Crt
+} // namespace Aws
diff --git a/contrib/restricted/aws/aws-crt-cpp/source/crypto/HMAC.cpp b/contrib/restricted/aws/aws-crt-cpp/source/crypto/HMAC.cpp
new file mode 100644
index 0000000000..403aff7d3f
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/source/crypto/HMAC.cpp
@@ -0,0 +1,173 @@
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+#include <aws/crt/crypto/HMAC.h>
+
+#include <aws/cal/hmac.h>
+
+namespace Aws
+{
+ namespace Crt
+ {
+ namespace Crypto
+ {
+ bool ComputeSHA256HMAC(
+ Allocator *allocator,
+ const ByteCursor &secret,
+ const ByteCursor &input,
+ ByteBuf &output,
+ size_t truncateTo) noexcept
+ {
+ return aws_sha256_hmac_compute(allocator, &secret, &input, &output, truncateTo) == AWS_OP_SUCCESS;
+ }
+
+ bool ComputeSHA256HMAC(
+ const ByteCursor &secret,
+ const ByteCursor &input,
+ ByteBuf &output,
+ size_t truncateTo) noexcept
+ {
+ return aws_sha256_hmac_compute(ApiAllocator(), &secret, &input, &output, truncateTo) == AWS_OP_SUCCESS;
+ }
+
+ HMAC::HMAC(aws_hmac *hmac) noexcept : m_hmac(hmac), m_good(false), m_lastError(0)
+ {
+ if (hmac)
+ {
+ m_good = true;
+ }
+ else
+ {
+ m_lastError = aws_last_error();
+ }
+ }
+
+ HMAC::~HMAC()
+ {
+ if (m_hmac)
+ {
+ aws_hmac_destroy(m_hmac);
+ m_hmac = nullptr;
+ }
+ }
+
+ HMAC::HMAC(HMAC &&toMove) : m_hmac(toMove.m_hmac), m_good(toMove.m_good), m_lastError(toMove.m_lastError)
+ {
+ toMove.m_hmac = nullptr;
+ toMove.m_good = false;
+ }
+
+ HMAC &HMAC::operator=(HMAC &&toMove)
+ {
+ if (&toMove != this)
+ {
+ *this = HMAC(std::move(toMove));
+ }
+
+ return *this;
+ }
+
+ HMAC HMAC::CreateSHA256HMAC(Allocator *allocator, const ByteCursor &secret) noexcept
+ {
+ return HMAC(aws_sha256_hmac_new(allocator, &secret));
+ }
+
+ HMAC HMAC::CreateSHA256HMAC(const ByteCursor &secret) noexcept
+ {
+ return HMAC(aws_sha256_hmac_new(ApiAllocator(), &secret));
+ }
+
+ bool HMAC::Update(const ByteCursor &toHMAC) noexcept
+ {
+ if (*this)
+ {
+ if (aws_hmac_update(m_hmac, &toHMAC))
+ {
+ m_lastError = aws_last_error();
+ m_good = false;
+ return false;
+ }
+ return true;
+ }
+
+ return false;
+ }
+
+ bool HMAC::Digest(ByteBuf &output, size_t truncateTo) noexcept
+ {
+ if (*this)
+ {
+ m_good = false;
+ if (aws_hmac_finalize(m_hmac, &output, truncateTo))
+ {
+ m_lastError = aws_last_error();
+ return false;
+ }
+ return true;
+ }
+
+ return false;
+ }
+
+ aws_hmac_vtable ByoHMAC::s_Vtable = {
+ "aws-crt-cpp-byo-crypto-hmac",
+ "aws-crt-cpp-byo-crypto",
+ ByoHMAC::s_Destroy,
+ ByoHMAC::s_Update,
+ ByoHMAC::s_Finalize,
+ };
+
+ ByoHMAC::ByoHMAC(size_t digestSize, const ByteCursor &, Allocator *allocator)
+ {
+ AWS_ZERO_STRUCT(m_hmacValue);
+ m_hmacValue.impl = reinterpret_cast<void *>(this);
+ m_hmacValue.digest_size = digestSize;
+ m_hmacValue.allocator = allocator;
+ m_hmacValue.good = true;
+ m_hmacValue.vtable = &s_Vtable;
+ }
+
+ aws_hmac *ByoHMAC::SeatForCInterop(const std::shared_ptr<ByoHMAC> &selfRef)
+ {
+ AWS_FATAL_ASSERT(this == selfRef.get());
+ m_selfReference = selfRef;
+ return &m_hmacValue;
+ }
+
+ void ByoHMAC::s_Destroy(struct aws_hmac *hmac)
+ {
+ auto *byoHash = reinterpret_cast<ByoHMAC *>(hmac->impl);
+ byoHash->m_selfReference = nullptr;
+ }
+
+ int ByoHMAC::s_Update(struct aws_hmac *hmac, const struct aws_byte_cursor *buf)
+ {
+ auto *byoHmac = reinterpret_cast<ByoHMAC *>(hmac->impl);
+ if (!byoHmac->m_hmacValue.good)
+ {
+ return aws_raise_error(AWS_ERROR_INVALID_STATE);
+ }
+ if (!byoHmac->UpdateInternal(*buf))
+ {
+ byoHmac->m_hmacValue.good = false;
+ return AWS_OP_ERR;
+ }
+ return AWS_OP_SUCCESS;
+ }
+
+ int ByoHMAC::s_Finalize(struct aws_hmac *hmac, struct aws_byte_buf *out)
+ {
+ auto *byoHmac = reinterpret_cast<ByoHMAC *>(hmac->impl);
+ if (!byoHmac->m_hmacValue.good)
+ {
+ return aws_raise_error(AWS_ERROR_INVALID_STATE);
+ }
+
+ bool success = byoHmac->DigestInternal(*out);
+ byoHmac->m_hmacValue.good = false;
+ return success ? AWS_OP_SUCCESS : AWS_OP_ERR;
+ }
+ } // namespace Crypto
+ } // namespace Crt
+} // namespace Aws
diff --git a/contrib/restricted/aws/aws-crt-cpp/source/crypto/Hash.cpp b/contrib/restricted/aws/aws-crt-cpp/source/crypto/Hash.cpp
new file mode 100644
index 0000000000..273d94da5e
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/source/crypto/Hash.cpp
@@ -0,0 +1,174 @@
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+#include <aws/crt/crypto/Hash.h>
+
+#include <aws/cal/hash.h>
+
+namespace Aws
+{
+ namespace Crt
+ {
+ namespace Crypto
+ {
+ bool ComputeSHA256(
+ Allocator *allocator,
+ const ByteCursor &input,
+ ByteBuf &output,
+ size_t truncateTo) noexcept
+ {
+ return aws_sha256_compute(allocator, &input, &output, truncateTo) == AWS_OP_SUCCESS;
+ }
+
+ bool ComputeSHA256(const ByteCursor &input, ByteBuf &output, size_t truncateTo) noexcept
+ {
+ return aws_sha256_compute(ApiAllocator(), &input, &output, truncateTo) == AWS_OP_SUCCESS;
+ }
+
+ bool ComputeMD5(Allocator *allocator, const ByteCursor &input, ByteBuf &output, size_t truncateTo) noexcept
+ {
+ return aws_md5_compute(allocator, &input, &output, truncateTo) == AWS_OP_SUCCESS;
+ }
+
+ bool ComputeMD5(const ByteCursor &input, ByteBuf &output, size_t truncateTo) noexcept
+ {
+ return aws_md5_compute(ApiAllocator(), &input, &output, truncateTo) == AWS_OP_SUCCESS;
+ }
+
+ Hash::Hash(aws_hash *hash) noexcept : m_hash(hash), m_good(false), m_lastError(0)
+ {
+ if (hash)
+ {
+ m_good = true;
+ }
+ else
+ {
+ m_lastError = aws_last_error();
+ }
+ }
+
+ Hash::~Hash()
+ {
+ if (m_hash)
+ {
+ aws_hash_destroy(m_hash);
+ m_hash = nullptr;
+ }
+ }
+
+ Hash::Hash(Hash &&toMove) : m_hash(toMove.m_hash), m_good(toMove.m_good), m_lastError(toMove.m_lastError)
+ {
+ toMove.m_hash = nullptr;
+ toMove.m_good = false;
+ }
+
+ Hash &Hash::operator=(Hash &&toMove)
+ {
+ if (&toMove != this)
+ {
+ *this = Hash(std::move(toMove));
+ }
+
+ return *this;
+ }
+
+ Hash Hash::CreateSHA256(Allocator *allocator) noexcept { return Hash(aws_sha256_new(allocator)); }
+
+ Hash Hash::CreateMD5(Allocator *allocator) noexcept { return Hash(aws_md5_new(allocator)); }
+
+ bool Hash::Update(const ByteCursor &toHash) noexcept
+ {
+ if (*this)
+ {
+ if (aws_hash_update(m_hash, &toHash))
+ {
+ m_lastError = aws_last_error();
+ m_good = false;
+ return false;
+ }
+ return true;
+ }
+
+ return false;
+ }
+
+ bool Hash::Digest(ByteBuf &output, size_t truncateTo) noexcept
+ {
+ if (*this)
+ {
+ m_good = false;
+ if (aws_hash_finalize(m_hash, &output, truncateTo))
+ {
+ m_lastError = aws_last_error();
+ return false;
+ }
+ return true;
+ }
+
+ return false;
+ }
+
+ aws_hash_vtable ByoHash::s_Vtable = {
+ "aws-crt-cpp-byo-crypto-hash",
+ "aws-crt-cpp-byo-crypto",
+ ByoHash::s_Destroy,
+ ByoHash::s_Update,
+ ByoHash::s_Finalize,
+ };
+
+ ByoHash::ByoHash(size_t digestSize, Allocator *allocator)
+ {
+ AWS_ZERO_STRUCT(m_hashValue);
+ m_hashValue.vtable = &s_Vtable;
+ m_hashValue.allocator = allocator;
+ m_hashValue.impl = reinterpret_cast<void *>(this);
+ m_hashValue.digest_size = digestSize;
+ m_hashValue.good = true;
+ }
+
+ ByoHash::~ByoHash() {}
+
+ aws_hash *ByoHash::SeatForCInterop(const std::shared_ptr<ByoHash> &selfRef)
+ {
+ AWS_FATAL_ASSERT(this == selfRef.get());
+ m_selfReference = selfRef;
+ return &m_hashValue;
+ }
+
+ void ByoHash::s_Destroy(struct aws_hash *hash)
+ {
+ auto *byoHash = reinterpret_cast<ByoHash *>(hash->impl);
+ byoHash->m_selfReference = nullptr;
+ }
+
+ int ByoHash::s_Update(struct aws_hash *hash, const struct aws_byte_cursor *buf)
+ {
+ auto *byoHash = reinterpret_cast<ByoHash *>(hash->impl);
+ if (!byoHash->m_hashValue.good)
+ {
+ return aws_raise_error(AWS_ERROR_INVALID_STATE);
+ }
+ if (!byoHash->UpdateInternal(*buf))
+ {
+ byoHash->m_hashValue.good = false;
+ return AWS_OP_ERR;
+ }
+ return AWS_OP_SUCCESS;
+ }
+
+ int ByoHash::s_Finalize(struct aws_hash *hash, struct aws_byte_buf *out)
+ {
+ auto *byoHash = reinterpret_cast<ByoHash *>(hash->impl);
+ if (!byoHash->m_hashValue.good)
+ {
+ return aws_raise_error(AWS_ERROR_INVALID_STATE);
+ }
+
+ bool success = byoHash->DigestInternal(*out);
+ byoHash->m_hashValue.good = false;
+ return success ? AWS_OP_SUCCESS : AWS_OP_ERR;
+ }
+ } // namespace Crypto
+ } // namespace Crt
+} // namespace Aws
diff --git a/contrib/restricted/aws/aws-crt-cpp/source/endpoints/RuleEngine.cpp b/contrib/restricted/aws/aws-crt-cpp/source/endpoints/RuleEngine.cpp
new file mode 100644
index 0000000000..b319508c93
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/source/endpoints/RuleEngine.cpp
@@ -0,0 +1,169 @@
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+#include <aws/common/string.h>
+#include <aws/crt/Api.h>
+#include <aws/crt/endpoints/RuleEngine.h>
+#include <aws/sdkutils/endpoints_rule_engine.h>
+#include <aws/sdkutils/partitions.h>
+
+namespace Aws
+{
+ namespace Crt
+ {
+ namespace Endpoints
+ {
+
+ RequestContext::RequestContext(Allocator *allocator) noexcept : m_allocator(allocator)
+ {
+ m_requestContext = aws_endpoints_request_context_new(allocator);
+ }
+
+ RequestContext::~RequestContext()
+ {
+ m_requestContext = aws_endpoints_request_context_release(m_requestContext);
+ }
+
+ bool RequestContext::AddString(const ByteCursor &name, const ByteCursor &value)
+ {
+ return AWS_OP_SUCCESS !=
+ aws_endpoints_request_context_add_string(m_allocator, m_requestContext, name, value);
+ }
+
+ bool RequestContext::AddBoolean(const ByteCursor &name, bool value)
+ {
+ return AWS_OP_SUCCESS !=
+ aws_endpoints_request_context_add_boolean(m_allocator, m_requestContext, name, value);
+ }
+
+ ResolutionOutcome::ResolutionOutcome(aws_endpoints_resolved_endpoint *impl) : m_resolvedEndpoint(impl) {}
+
+ ResolutionOutcome::ResolutionOutcome(ResolutionOutcome &&toMove) noexcept
+ : m_resolvedEndpoint(toMove.m_resolvedEndpoint)
+ {
+ toMove.m_resolvedEndpoint = nullptr;
+ }
+
+ ResolutionOutcome &ResolutionOutcome::operator=(ResolutionOutcome &&toMove)
+ {
+ if (&toMove != this)
+ {
+ *this = ResolutionOutcome(std::move(toMove));
+ }
+
+ return *this;
+ }
+
+ ResolutionOutcome::~ResolutionOutcome() { aws_endpoints_resolved_endpoint_release(m_resolvedEndpoint); }
+
+ bool ResolutionOutcome::IsEndpoint() const noexcept
+ {
+ return AWS_ENDPOINTS_RESOLVED_ENDPOINT == aws_endpoints_resolved_endpoint_get_type(m_resolvedEndpoint);
+ }
+
+ bool ResolutionOutcome::IsError() const noexcept
+ {
+ return AWS_ENDPOINTS_RESOLVED_ERROR == aws_endpoints_resolved_endpoint_get_type(m_resolvedEndpoint);
+ }
+
+ Optional<StringView> ResolutionOutcome::GetUrl() const
+ {
+ ByteCursor url;
+ if (aws_endpoints_resolved_endpoint_get_url(m_resolvedEndpoint, &url))
+ {
+ return Optional<StringView>();
+ }
+
+ return Optional<StringView>(ByteCursorToStringView(url));
+ }
+
+ inline StringView CrtStringToStringView(const aws_string *s)
+ {
+ ByteCursor key = aws_byte_cursor_from_string(s);
+ return ByteCursorToStringView(key);
+ }
+
+ Optional<UnorderedMap<StringView, Vector<StringView>>> ResolutionOutcome::GetHeaders() const
+ {
+ const aws_hash_table *resolved_headers = nullptr;
+
+ if (aws_endpoints_resolved_endpoint_get_headers(m_resolvedEndpoint, &resolved_headers))
+ {
+ return Optional<UnorderedMap<StringView, Vector<StringView>>>();
+ }
+
+ UnorderedMap<StringView, Vector<StringView>> headers;
+ for (struct aws_hash_iter iter = aws_hash_iter_begin(resolved_headers); !aws_hash_iter_done(&iter);
+ aws_hash_iter_next(&iter))
+ {
+ ByteCursor key = aws_byte_cursor_from_string((const aws_string *)iter.element.key);
+ const aws_array_list *array = (const aws_array_list *)iter.element.value;
+ headers.emplace(std::make_pair(
+ ByteCursorToStringView(key),
+ ArrayListToVector<aws_string *, StringView>(array, CrtStringToStringView)));
+ }
+
+ return Optional<UnorderedMap<StringView, Vector<StringView>>>(headers);
+ }
+
+ Optional<StringView> ResolutionOutcome::GetProperties() const
+ {
+ ByteCursor properties;
+ if (aws_endpoints_resolved_endpoint_get_properties(m_resolvedEndpoint, &properties))
+ {
+ return Optional<StringView>();
+ }
+
+ return Optional<StringView>(ByteCursorToStringView(properties));
+ }
+
+ Optional<StringView> ResolutionOutcome::GetError() const
+ {
+ ByteCursor error;
+ if (aws_endpoints_resolved_endpoint_get_error(m_resolvedEndpoint, &error))
+ {
+ return Optional<StringView>();
+ }
+
+ return Optional<StringView>(ByteCursorToStringView(error));
+ }
+
+ RuleEngine::RuleEngine(
+ const ByteCursor &rulesetCursor,
+ const ByteCursor &partitionsCursor,
+ Allocator *allocator) noexcept
+ : m_ruleEngine(nullptr)
+ {
+ auto ruleset = aws_endpoints_ruleset_new_from_string(allocator, rulesetCursor);
+ auto partitions = aws_partitions_config_new_from_string(allocator, partitionsCursor);
+ if (ruleset != NULL && partitions != NULL)
+ {
+ m_ruleEngine = aws_endpoints_rule_engine_new(allocator, ruleset, partitions);
+ }
+
+ if (ruleset != NULL)
+ {
+ aws_endpoints_ruleset_release(ruleset);
+ }
+
+ if (partitions != NULL)
+ {
+ aws_partitions_config_release(partitions);
+ }
+ }
+
+ RuleEngine::~RuleEngine() { m_ruleEngine = aws_endpoints_rule_engine_release(m_ruleEngine); }
+
+ Optional<ResolutionOutcome> RuleEngine::Resolve(const RequestContext &context) const
+ {
+ aws_endpoints_resolved_endpoint *resolved = NULL;
+ if (aws_endpoints_rule_engine_resolve(m_ruleEngine, context.GetNativeHandle(), &resolved))
+ {
+ return Optional<ResolutionOutcome>();
+ }
+ return Optional<ResolutionOutcome>(ResolutionOutcome(resolved));
+ }
+ } // namespace Endpoints
+ } // namespace Crt
+} // namespace Aws
diff --git a/contrib/restricted/aws/aws-crt-cpp/source/external/cJSON.cpp b/contrib/restricted/aws/aws-crt-cpp/source/external/cJSON.cpp
new file mode 100644
index 0000000000..f3db28d400
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/source/external/cJSON.cpp
@@ -0,0 +1,3120 @@
+/*
+ Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+/** MODIFICATIONS:
+ * valueInt was moved up to improve alignment.
+ * Wrap all symbols in the Aws namespace as a short-term collision resolution
+ * Replace strcpy() with strncpy()
+ *
+ * Modifications licensed under:
+ *
+ * Copyright 2010-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file is distributed
+ * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+/* cJSON */
+/* JSON parser in C. */
+
+/* disable warnings about old C89 functions in MSVC */
+#if !defined(_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER)
+#define _CRT_SECURE_NO_DEPRECATE
+#endif
+
+#ifdef __GNUC__
+#pragma GCC visibility push(default)
+#endif
+#if defined(_MSC_VER)
+#pragma warning (push)
+/* disable warning about single line comments in system headers */
+#pragma warning (disable : 4001)
+#endif
+
+#include <string.h>
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <ctype.h>
+#include <float.h>
+
+#ifdef ENABLE_LOCALES
+#include <locale.h>
+#endif
+
+#if defined(_MSC_VER)
+#pragma warning (pop)
+#endif
+#ifdef __GNUC__
+#pragma GCC visibility pop
+#endif
+
+#include <aws/crt/external/cJSON.h>
+
+/* define our own boolean type */
+// #ifdef true
+// #undef true
+// #endif
+// #define true ((cJSON_bool)1)
+
+// #ifdef false
+// #undef false
+// #endif
+// #define false ((cJSON_bool)0)
+
+/* define isnan and isinf for ANSI C, if in C99 or above, isnan and isinf has been defined in math.h */
+#ifndef isinf
+#define isinf(d) (isnan((d - d)) && !isnan(d))
+#endif
+#ifndef isnan
+#define isnan(d) (d != d)
+#endif
+
+#ifndef NAN
+#define NAN 0.0/0.0
+#endif
+
+typedef struct {
+ const unsigned char *json;
+ size_t position;
+} error;
+static error global_error = { NULL, 0 };
+
+namespace Aws {
+
+CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void)
+{
+ return (const char*) (global_error.json + global_error.position);
+}
+
+CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item)
+{
+ if (!cJSON_IsString(item))
+ {
+ return NULL;
+ }
+
+ return item->valuestring;
+}
+
+CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item)
+{
+ if (!cJSON_IsNumber(item))
+ {
+ return (double) NAN;
+ }
+
+ return item->valuedouble;
+}
+
+/* This is a safeguard to prevent copy-pasters from using incompatible C and header files */
+#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 14)
+ #error cJSON.h and cJSON.c have different versions. Make sure that both have the same.
+#endif
+
+CJSON_PUBLIC(const char*) cJSON_Version(void)
+{
+ static char version[15];
+ snprintf(version, sizeof(version), "%i.%i.%i", CJSON_VERSION_MAJOR, CJSON_VERSION_MINOR, CJSON_VERSION_PATCH);
+
+ return version;
+}
+
+/* Case insensitive string comparison, doesn't consider two NULL pointers equal though */
+static int case_insensitive_strcmp(const unsigned char *string1, const unsigned char *string2)
+{
+ if ((string1 == NULL) || (string2 == NULL))
+ {
+ return 1;
+ }
+
+ if (string1 == string2)
+ {
+ return 0;
+ }
+
+ for(; tolower(*string1) == tolower(*string2); (void)string1++, string2++)
+ {
+ if (*string1 == '\0')
+ {
+ return 0;
+ }
+ }
+
+ return tolower(*string1) - tolower(*string2);
+}
+
+typedef struct internal_hooks
+{
+ void *(CJSON_CDECL *allocate)(size_t size);
+ void (CJSON_CDECL *deallocate)(void *pointer);
+ void *(CJSON_CDECL *reallocate)(void *pointer, size_t size);
+} internal_hooks;
+
+#if defined(_MSC_VER)
+/* work around MSVC error C2322: '...' address of dllimport '...' is not static */
+static void * CJSON_CDECL internal_malloc(size_t size)
+{
+ return malloc(size);
+}
+static void CJSON_CDECL internal_free(void *pointer)
+{
+ free(pointer);
+}
+static void * CJSON_CDECL internal_realloc(void *pointer, size_t size)
+{
+ return realloc(pointer, size);
+}
+#else
+#define internal_malloc malloc
+#define internal_free free
+#define internal_realloc realloc
+#endif
+
+/* strlen of character literals resolved at compile time */
+#define static_strlen(string_literal) (sizeof(string_literal) - sizeof(""))
+
+static internal_hooks global_hooks = { internal_malloc, internal_free, internal_realloc };
+
+static unsigned char* cJSON_strdup(const unsigned char* string, const internal_hooks * const hooks)
+{
+ size_t length = 0;
+ unsigned char *copy = NULL;
+
+ if (string == NULL)
+ {
+ return NULL;
+ }
+
+ length = strlen((const char*)string) + sizeof("");
+ copy = (unsigned char*)hooks->allocate(length);
+ if (copy == NULL)
+ {
+ return NULL;
+ }
+ memcpy(copy, string, length);
+
+ return copy;
+}
+
+CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks)
+{
+ if (hooks == NULL)
+ {
+ /* Reset hooks */
+ global_hooks.allocate = malloc;
+ global_hooks.deallocate = free;
+ global_hooks.reallocate = realloc;
+ return;
+ }
+
+ global_hooks.allocate = malloc;
+ if (hooks->malloc_fn != NULL)
+ {
+ global_hooks.allocate = hooks->malloc_fn;
+ }
+
+ global_hooks.deallocate = free;
+ if (hooks->free_fn != NULL)
+ {
+ global_hooks.deallocate = hooks->free_fn;
+ }
+
+ /* use realloc only if both free and malloc are used */
+ global_hooks.reallocate = NULL;
+ if ((global_hooks.allocate == malloc) && (global_hooks.deallocate == free))
+ {
+ global_hooks.reallocate = realloc;
+ }
+}
+
+/* Internal constructor. */
+static cJSON *cJSON_New_Item(const internal_hooks * const hooks)
+{
+ cJSON* node = (cJSON*)hooks->allocate(sizeof(cJSON));
+ if (node)
+ {
+ memset(node, '\0', sizeof(cJSON));
+ }
+
+ return node;
+}
+
+/* Delete a cJSON structure. */
+CJSON_PUBLIC(void) cJSON_Delete(cJSON *item)
+{
+ cJSON *next = NULL;
+ while (item != NULL)
+ {
+ next = item->next;
+ if (!(item->type & cJSON_IsReference) && (item->child != NULL))
+ {
+ cJSON_Delete(item->child);
+ }
+ if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL))
+ {
+ global_hooks.deallocate(item->valuestring);
+ }
+ if (!(item->type & cJSON_StringIsConst) && (item->string != NULL))
+ {
+ global_hooks.deallocate(item->string);
+ }
+ global_hooks.deallocate(item);
+ item = next;
+ }
+}
+
+/* get the decimal point character of the current locale */
+static unsigned char get_decimal_point(void)
+{
+#ifdef ENABLE_LOCALES
+ struct lconv *lconv = localeconv();
+ return (unsigned char) lconv->decimal_point[0];
+#else
+ return '.';
+#endif
+}
+
+typedef struct
+{
+ const unsigned char *content;
+ size_t length;
+ size_t offset;
+ size_t depth; /* How deeply nested (in arrays/objects) is the input at the current offset. */
+ internal_hooks hooks;
+} parse_buffer;
+
+/* check if the given size is left to read in a given parse buffer (starting with 1) */
+#define can_read(buffer, size) ((buffer != NULL) && (((buffer)->offset + size) <= (buffer)->length))
+/* check if the buffer can be accessed at the given index (starting with 0) */
+#define can_access_at_index(buffer, index) ((buffer != NULL) && (((buffer)->offset + index) < (buffer)->length))
+#define cannot_access_at_index(buffer, index) (!can_access_at_index(buffer, index))
+/* get a pointer to the buffer at the position */
+#define buffer_at_offset(buffer) ((buffer)->content + (buffer)->offset)
+
+/* Parse the input text to generate a number, and populate the result into item. */
+static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_buffer)
+{
+ double number = 0;
+ unsigned char *after_end = NULL;
+ unsigned char number_c_string[64];
+ unsigned char decimal_point = get_decimal_point();
+ size_t i = 0;
+
+ if ((input_buffer == NULL) || (input_buffer->content == NULL))
+ {
+ return false;
+ }
+
+ /* copy the number into a temporary buffer and replace '.' with the decimal point
+ * of the current locale (for strtod)
+ * This also takes care of '\0' not necessarily being available for marking the end of the input */
+ for (i = 0; (i < (sizeof(number_c_string) - 1)) && can_access_at_index(input_buffer, i); i++)
+ {
+ switch (buffer_at_offset(input_buffer)[i])
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case '+':
+ case '-':
+ case 'e':
+ case 'E':
+ number_c_string[i] = buffer_at_offset(input_buffer)[i];
+ break;
+
+ case '.':
+ number_c_string[i] = decimal_point;
+ break;
+
+ default:
+ goto loop_end;
+ }
+ }
+loop_end:
+ number_c_string[i] = '\0';
+
+ number = strtod((const char*)number_c_string, (char**)&after_end);
+ if (number_c_string == after_end)
+ {
+ return false; /* parse_error */
+ }
+
+ item->valuedouble = number;
+
+ /* use saturation in case of overflow */
+ if (number >= INT_MAX)
+ {
+ item->valueint = INT_MAX;
+ }
+ else if (number <= (double)INT_MIN)
+ {
+ item->valueint = INT_MIN;
+ }
+ else
+ {
+ item->valueint = (int)number;
+ }
+
+ item->type = cJSON_Number;
+
+ input_buffer->offset += (size_t)(after_end - number_c_string);
+ return true;
+}
+
+/* don't ask me, but the original cJSON_SetNumberValue returns an integer or double */
+CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number)
+{
+ if (number >= INT_MAX)
+ {
+ object->valueint = INT_MAX;
+ }
+ else if (number <= (double)INT_MIN)
+ {
+ object->valueint = INT_MIN;
+ }
+ else
+ {
+ object->valueint = (int)number;
+ }
+
+ return object->valuedouble = number;
+}
+
+CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring)
+{
+ char *copy = NULL;
+ /* if object's type is not cJSON_String or is cJSON_IsReference, it should not set valuestring */
+ if (!(object->type & cJSON_String) || (object->type & cJSON_IsReference))
+ {
+ return NULL;
+ }
+ if (strlen(valuestring) <= strlen(object->valuestring))
+ {
+ memcpy(object->valuestring, valuestring, strlen(valuestring) + 1);
+ return object->valuestring;
+ }
+ copy = (char*) cJSON_strdup((const unsigned char*)valuestring, &global_hooks);
+ if (copy == NULL)
+ {
+ return NULL;
+ }
+ if (object->valuestring != NULL)
+ {
+ cJSON_free(object->valuestring);
+ }
+ object->valuestring = copy;
+
+ return copy;
+}
+
+typedef struct
+{
+ unsigned char *buffer;
+ size_t length;
+ size_t offset;
+ size_t depth; /* current nesting depth (for formatted printing) */
+ cJSON_bool noalloc;
+ cJSON_bool format; /* is this print a formatted print */
+ internal_hooks hooks;
+} printbuffer;
+
+/* realloc printbuffer if necessary to have at least "needed" bytes more */
+static unsigned char* ensure(printbuffer * const p, size_t needed)
+{
+ unsigned char *newbuffer = NULL;
+ size_t newsize = 0;
+
+ if ((p == NULL) || (p->buffer == NULL))
+ {
+ return NULL;
+ }
+
+ if ((p->length > 0) && (p->offset >= p->length))
+ {
+ /* make sure that offset is valid */
+ return NULL;
+ }
+
+ if (needed > INT_MAX)
+ {
+ /* sizes bigger than INT_MAX are currently not supported */
+ return NULL;
+ }
+
+ needed += p->offset + 1;
+ if (needed <= p->length)
+ {
+ return p->buffer + p->offset;
+ }
+
+ if (p->noalloc) {
+ return NULL;
+ }
+
+ /* calculate new buffer size */
+ if (needed > (INT_MAX / 2))
+ {
+ /* overflow of int, use INT_MAX if possible */
+ if (needed <= INT_MAX)
+ {
+ newsize = INT_MAX;
+ }
+ else
+ {
+ return NULL;
+ }
+ }
+ else
+ {
+ newsize = needed * 2;
+ }
+
+ if (p->hooks.reallocate != NULL)
+ {
+ /* reallocate with realloc if available */
+ newbuffer = (unsigned char*)p->hooks.reallocate(p->buffer, newsize);
+ if (newbuffer == NULL)
+ {
+ p->hooks.deallocate(p->buffer);
+ p->length = 0;
+ p->buffer = NULL;
+
+ return NULL;
+ }
+ }
+ else
+ {
+ /* otherwise reallocate manually */
+ newbuffer = (unsigned char*)p->hooks.allocate(newsize);
+ if (!newbuffer)
+ {
+ p->hooks.deallocate(p->buffer);
+ p->length = 0;
+ p->buffer = NULL;
+
+ return NULL;
+ }
+ if (newbuffer)
+ {
+ memcpy(newbuffer, p->buffer, p->offset + 1);
+ }
+ p->hooks.deallocate(p->buffer);
+ }
+ p->length = newsize;
+ p->buffer = newbuffer;
+
+ return newbuffer + p->offset;
+}
+
+/* calculate the new length of the string in a printbuffer and update the offset */
+static void update_offset(printbuffer * const buffer)
+{
+ const unsigned char *buffer_pointer = NULL;
+ if ((buffer == NULL) || (buffer->buffer == NULL))
+ {
+ return;
+ }
+ buffer_pointer = buffer->buffer + buffer->offset;
+
+ buffer->offset += strlen((const char*)buffer_pointer);
+}
+
+/* securely comparison of floating-point variables */
+static cJSON_bool compare_double(double a, double b)
+{
+ double maxVal = fabs(a) > fabs(b) ? fabs(a) : fabs(b);
+ return (fabs(a - b) <= maxVal * DBL_EPSILON);
+}
+
+/* Render the number nicely from the given item into a string. */
+static cJSON_bool print_number(const cJSON * const item, printbuffer * const output_buffer)
+{
+ unsigned char *output_pointer = NULL;
+ double d = item->valuedouble;
+ int length = 0;
+ size_t i = 0;
+ unsigned char number_buffer[26] = {0}; /* temporary buffer to print the number into */
+ unsigned char decimal_point = get_decimal_point();
+ double test = 0.0;
+
+ if (output_buffer == NULL)
+ {
+ return false;
+ }
+
+ /* This checks for NaN and Infinity */
+ if (isnan(d) || isinf(d))
+ {
+ length = snprintf((char*)number_buffer, sizeof(number_buffer), "null");
+ }
+ else
+ {
+ /* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */
+ length = snprintf((char*)number_buffer, sizeof(number_buffer), "%1.15g", d);
+
+ /* Check whether the original double can be recovered */
+ if ((sscanf((char*)number_buffer, "%lg", &test) != 1) || !compare_double((double)test, d))
+ {
+ /* If not, print with 17 decimal places of precision */
+ length = snprintf((char*)number_buffer, sizeof(number_buffer), "%1.17g", d);
+ }
+ }
+
+ /* snprintf failed or buffer overrun occurred */
+ if ((length < 0) || (length > (int)(sizeof(number_buffer) - 1)))
+ {
+ return false;
+ }
+
+ /* reserve appropriate space in the output */
+ output_pointer = ensure(output_buffer, (size_t)length + sizeof(""));
+ if (output_pointer == NULL)
+ {
+ return false;
+ }
+
+ /* copy the printed number to the output and replace locale
+ * dependent decimal point with '.' */
+ for (i = 0; i < ((size_t)length); i++)
+ {
+ if (number_buffer[i] == decimal_point)
+ {
+ output_pointer[i] = '.';
+ continue;
+ }
+
+ output_pointer[i] = number_buffer[i];
+ }
+ output_pointer[i] = '\0';
+
+ output_buffer->offset += (size_t)length;
+
+ return true;
+}
+
+/* parse 4 digit hexadecimal number */
+static unsigned parse_hex4(const unsigned char * const input)
+{
+ unsigned int h = 0;
+ size_t i = 0;
+
+ for (i = 0; i < 4; i++)
+ {
+ /* parse digit */
+ if ((input[i] >= '0') && (input[i] <= '9'))
+ {
+ h += (unsigned int) input[i] - '0';
+ }
+ else if ((input[i] >= 'A') && (input[i] <= 'F'))
+ {
+ h += (unsigned int) 10 + input[i] - 'A';
+ }
+ else if ((input[i] >= 'a') && (input[i] <= 'f'))
+ {
+ h += (unsigned int) 10 + input[i] - 'a';
+ }
+ else /* invalid */
+ {
+ return 0;
+ }
+
+ if (i < 3)
+ {
+ /* shift left to make place for the next nibble */
+ h = h << 4;
+ }
+ }
+
+ return h;
+}
+
+/* converts a UTF-16 literal to UTF-8
+ * A literal can be one or two sequences of the form \uXXXX */
+static unsigned char utf16_literal_to_utf8(const unsigned char * const input_pointer, const unsigned char * const input_end, unsigned char **output_pointer)
+{
+ long unsigned int codepoint = 0;
+ unsigned int first_code = 0;
+ const unsigned char *first_sequence = input_pointer;
+ unsigned char utf8_length = 0;
+ unsigned char utf8_position = 0;
+ unsigned char sequence_length = 0;
+ unsigned char first_byte_mark = 0;
+
+ if ((input_end - first_sequence) < 6)
+ {
+ /* input ends unexpectedly */
+ goto fail;
+ }
+
+ /* get the first utf16 sequence */
+ first_code = parse_hex4(first_sequence + 2);
+
+ /* check that the code is valid */
+ if (((first_code >= 0xDC00) && (first_code <= 0xDFFF)))
+ {
+ goto fail;
+ }
+
+ /* UTF16 surrogate pair */
+ if ((first_code >= 0xD800) && (first_code <= 0xDBFF))
+ {
+ const unsigned char *second_sequence = first_sequence + 6;
+ unsigned int second_code = 0;
+ sequence_length = 12; /* \uXXXX\uXXXX */
+
+ if ((input_end - second_sequence) < 6)
+ {
+ /* input ends unexpectedly */
+ goto fail;
+ }
+
+ if ((second_sequence[0] != '\\') || (second_sequence[1] != 'u'))
+ {
+ /* missing second half of the surrogate pair */
+ goto fail;
+ }
+
+ /* get the second utf16 sequence */
+ second_code = parse_hex4(second_sequence + 2);
+ /* check that the code is valid */
+ if ((second_code < 0xDC00) || (second_code > 0xDFFF))
+ {
+ /* invalid second half of the surrogate pair */
+ goto fail;
+ }
+
+
+ /* calculate the unicode codepoint from the surrogate pair */
+ codepoint = 0x10000 + (((first_code & 0x3FF) << 10) | (second_code & 0x3FF));
+ }
+ else
+ {
+ sequence_length = 6; /* \uXXXX */
+ codepoint = first_code;
+ }
+
+ /* encode as UTF-8
+ * takes at maximum 4 bytes to encode:
+ * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
+ if (codepoint < 0x80)
+ {
+ /* normal ascii, encoding 0xxxxxxx */
+ utf8_length = 1;
+ }
+ else if (codepoint < 0x800)
+ {
+ /* two bytes, encoding 110xxxxx 10xxxxxx */
+ utf8_length = 2;
+ first_byte_mark = 0xC0; /* 11000000 */
+ }
+ else if (codepoint < 0x10000)
+ {
+ /* three bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx */
+ utf8_length = 3;
+ first_byte_mark = 0xE0; /* 11100000 */
+ }
+ else if (codepoint <= 0x10FFFF)
+ {
+ /* four bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx */
+ utf8_length = 4;
+ first_byte_mark = 0xF0; /* 11110000 */
+ }
+ else
+ {
+ /* invalid unicode codepoint */
+ goto fail;
+ }
+
+ /* encode as utf8 */
+ for (utf8_position = (unsigned char)(utf8_length - 1); utf8_position > 0; utf8_position--)
+ {
+ /* 10xxxxxx */
+ (*output_pointer)[utf8_position] = (unsigned char)((codepoint | 0x80) & 0xBF);
+ codepoint >>= 6;
+ }
+ /* encode first byte */
+ if (utf8_length > 1)
+ {
+ (*output_pointer)[0] = (unsigned char)((codepoint | first_byte_mark) & 0xFF);
+ }
+ else
+ {
+ (*output_pointer)[0] = (unsigned char)(codepoint & 0x7F);
+ }
+
+ *output_pointer += utf8_length;
+
+ return sequence_length;
+
+fail:
+ return 0;
+}
+
+/* Parse the input text into an unescaped cinput, and populate item. */
+static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_buffer)
+{
+ const unsigned char *input_pointer = buffer_at_offset(input_buffer) + 1;
+ const unsigned char *input_end = buffer_at_offset(input_buffer) + 1;
+ unsigned char *output_pointer = NULL;
+ unsigned char *output = NULL;
+
+ /* not a string */
+ if (buffer_at_offset(input_buffer)[0] != '\"')
+ {
+ goto fail;
+ }
+
+ {
+ /* calculate approximate size of the output (overestimate) */
+ size_t allocation_length = 0;
+ size_t skipped_bytes = 0;
+ while (((size_t)(input_end - input_buffer->content) < input_buffer->length) && (*input_end != '\"'))
+ {
+ /* is escape sequence */
+ if (input_end[0] == '\\')
+ {
+ if ((size_t)(input_end + 1 - input_buffer->content) >= input_buffer->length)
+ {
+ /* prevent buffer overflow when last input character is a backslash */
+ goto fail;
+ }
+ skipped_bytes++;
+ input_end++;
+ }
+ input_end++;
+ }
+ if (((size_t)(input_end - input_buffer->content) >= input_buffer->length) || (*input_end != '\"'))
+ {
+ goto fail; /* string ended unexpectedly */
+ }
+
+ /* This is at most how much we need for the output */
+ allocation_length = (size_t) (input_end - buffer_at_offset(input_buffer)) - skipped_bytes;
+ output = (unsigned char*)input_buffer->hooks.allocate(allocation_length + sizeof(""));
+ if (output == NULL)
+ {
+ goto fail; /* allocation failure */
+ }
+ }
+
+ output_pointer = output;
+ /* loop through the string literal */
+ while (input_pointer < input_end)
+ {
+ if (*input_pointer != '\\')
+ {
+ *output_pointer++ = *input_pointer++;
+ }
+ /* escape sequence */
+ else
+ {
+ unsigned char sequence_length = 2;
+ if ((input_end - input_pointer) < 1)
+ {
+ goto fail;
+ }
+
+ switch (input_pointer[1])
+ {
+ case 'b':
+ *output_pointer++ = '\b';
+ break;
+ case 'f':
+ *output_pointer++ = '\f';
+ break;
+ case 'n':
+ *output_pointer++ = '\n';
+ break;
+ case 'r':
+ *output_pointer++ = '\r';
+ break;
+ case 't':
+ *output_pointer++ = '\t';
+ break;
+ case '\"':
+ case '\\':
+ case '/':
+ *output_pointer++ = input_pointer[1];
+ break;
+
+ /* UTF-16 literal */
+ case 'u':
+ sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer);
+ if (sequence_length == 0)
+ {
+ /* failed to convert UTF16-literal to UTF-8 */
+ goto fail;
+ }
+ break;
+
+ default:
+ goto fail;
+ }
+ input_pointer += sequence_length;
+ }
+ }
+
+ /* zero terminate the output */
+ *output_pointer = '\0';
+
+ item->type = cJSON_String;
+ item->valuestring = (char*)output;
+
+ input_buffer->offset = (size_t) (input_end - input_buffer->content);
+ input_buffer->offset++;
+
+ return true;
+
+fail:
+ if (output != NULL)
+ {
+ input_buffer->hooks.deallocate(output);
+ }
+
+ if (input_pointer != NULL)
+ {
+ input_buffer->offset = (size_t)(input_pointer - input_buffer->content);
+ }
+
+ return false;
+}
+
+/* Render the cstring provided to an escaped version that can be printed. */
+static cJSON_bool print_string_ptr(const unsigned char * const input, printbuffer * const output_buffer)
+{
+ const unsigned char *input_pointer = NULL;
+ unsigned char *output = NULL;
+ unsigned char *output_pointer = NULL;
+ size_t output_length = 0;
+ /* numbers of additional characters needed for escaping */
+ size_t escape_characters = 0;
+
+ if (output_buffer == NULL)
+ {
+ return false;
+ }
+
+ /* empty string */
+ if (input == NULL)
+ {
+ output = ensure(output_buffer, sizeof("\"\""));
+ if (output == NULL)
+ {
+ return false;
+ }
+ strncpy((char*)output, "\"\"", strlen("\"\"") + 1);
+
+ return true;
+ }
+
+ /* set "flag" to 1 if something needs to be escaped */
+ for (input_pointer = input; *input_pointer; input_pointer++)
+ {
+ switch (*input_pointer)
+ {
+ case '\"':
+ case '\\':
+ case '\b':
+ case '\f':
+ case '\n':
+ case '\r':
+ case '\t':
+ /* one character escape sequence */
+ escape_characters++;
+ break;
+ default:
+ if (*input_pointer < 32)
+ {
+ /* UTF-16 escape sequence uXXXX */
+ escape_characters += 5;
+ }
+ break;
+ }
+ }
+ output_length = (size_t)(input_pointer - input) + escape_characters;
+
+ output = ensure(output_buffer, output_length + sizeof("\"\""));
+ if (output == NULL)
+ {
+ return false;
+ }
+
+ /* no characters have to be escaped */
+ if (escape_characters == 0)
+ {
+ output[0] = '\"';
+ memcpy(output + 1, input, output_length);
+ output[output_length + 1] = '\"';
+ output[output_length + 2] = '\0';
+
+ return true;
+ }
+
+ output[0] = '\"';
+ output_pointer = output + 1;
+ /* copy the string */
+ for (input_pointer = input; *input_pointer != '\0'; (void)input_pointer++, output_pointer++)
+ {
+ if ((*input_pointer > 31) && (*input_pointer != '\"') && (*input_pointer != '\\'))
+ {
+ /* normal character, copy */
+ *output_pointer = *input_pointer;
+ }
+ else
+ {
+ /* character needs to be escaped */
+ *output_pointer++ = '\\';
+ switch (*input_pointer)
+ {
+ case '\\':
+ *output_pointer = '\\';
+ break;
+ case '\"':
+ *output_pointer = '\"';
+ break;
+ case '\b':
+ *output_pointer = 'b';
+ break;
+ case '\f':
+ *output_pointer = 'f';
+ break;
+ case '\n':
+ *output_pointer = 'n';
+ break;
+ case '\r':
+ *output_pointer = 'r';
+ break;
+ case '\t':
+ *output_pointer = 't';
+ break;
+ default:
+ /* escape and print as unicode codepoint */
+ snprintf((char*)output_pointer, output_buffer->length - (output_pointer - output_buffer->buffer), "u%04x", *input_pointer);
+ output_pointer += 4;
+ break;
+ }
+ }
+ }
+ output[output_length + 1] = '\"';
+ output[output_length + 2] = '\0';
+
+ return true;
+}
+
+/* Invoke print_string_ptr (which is useful) on an item. */
+static cJSON_bool print_string(const cJSON * const item, printbuffer * const p)
+{
+ return print_string_ptr((unsigned char*)item->valuestring, p);
+}
+
+/* Predeclare these prototypes. */
+static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer);
+static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer);
+static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer);
+static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer);
+static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer);
+static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer);
+
+/* Utility to jump whitespace and cr/lf */
+static parse_buffer *buffer_skip_whitespace(parse_buffer * const buffer)
+{
+ if ((buffer == NULL) || (buffer->content == NULL))
+ {
+ return NULL;
+ }
+
+ if (cannot_access_at_index(buffer, 0))
+ {
+ return buffer;
+ }
+
+ while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32))
+ {
+ buffer->offset++;
+ }
+
+ if (buffer->offset == buffer->length)
+ {
+ buffer->offset--;
+ }
+
+ return buffer;
+}
+
+/* skip the UTF-8 BOM (byte order mark) if it is at the beginning of a buffer */
+static parse_buffer *skip_utf8_bom(parse_buffer * const buffer)
+{
+ if ((buffer == NULL) || (buffer->content == NULL) || (buffer->offset != 0))
+ {
+ return NULL;
+ }
+
+ if (can_access_at_index(buffer, 4) && (strncmp((const char*)buffer_at_offset(buffer), "\xEF\xBB\xBF", 3) == 0))
+ {
+ buffer->offset += 3;
+ }
+
+ return buffer;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated)
+{
+ size_t buffer_length;
+
+ if (NULL == value)
+ {
+ return NULL;
+ }
+
+ /* Adding null character size due to require_null_terminated. */
+ buffer_length = strlen(value) + sizeof("");
+
+ return cJSON_ParseWithLengthOpts(value, buffer_length, return_parse_end, require_null_terminated);
+}
+
+/* Parse an object - create a new root, and populate. */
+CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated)
+{
+ parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } };
+ cJSON *item = NULL;
+
+ /* reset error position */
+ global_error.json = NULL;
+ global_error.position = 0;
+
+ if (value == NULL || 0 == buffer_length)
+ {
+ goto fail;
+ }
+
+ buffer.content = (const unsigned char*)value;
+ buffer.length = buffer_length;
+ buffer.offset = 0;
+ buffer.hooks = global_hooks;
+
+ item = cJSON_New_Item(&global_hooks);
+ if (item == NULL) /* memory fail */
+ {
+ goto fail;
+ }
+
+ if (!parse_value(item, buffer_skip_whitespace(skip_utf8_bom(&buffer))))
+ {
+ /* parse failure. ep is set. */
+ goto fail;
+ }
+
+ /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */
+ if (require_null_terminated)
+ {
+ buffer_skip_whitespace(&buffer);
+ if ((buffer.offset >= buffer.length) || buffer_at_offset(&buffer)[0] != '\0')
+ {
+ goto fail;
+ }
+ }
+ if (return_parse_end)
+ {
+ *return_parse_end = (const char*)buffer_at_offset(&buffer);
+ }
+
+ return item;
+
+fail:
+ if (item != NULL)
+ {
+ cJSON_Delete(item);
+ }
+
+ if (value != NULL)
+ {
+ error local_error;
+ local_error.json = (const unsigned char*)value;
+ local_error.position = 0;
+
+ if (buffer.offset < buffer.length)
+ {
+ local_error.position = buffer.offset;
+ }
+ else if (buffer.length > 0)
+ {
+ local_error.position = buffer.length - 1;
+ }
+
+ if (return_parse_end != NULL)
+ {
+ *return_parse_end = (const char*)local_error.json + local_error.position;
+ }
+
+ global_error = local_error;
+ }
+
+ return NULL;
+}
+
+/* Default options for cJSON_Parse */
+CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value)
+{
+ return cJSON_ParseWithOpts(value, 0, 0);
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length)
+{
+ return cJSON_ParseWithLengthOpts(value, buffer_length, 0, 0);
+}
+
+#define cjson_min(a, b) (((a) < (b)) ? (a) : (b))
+
+static unsigned char *print(const cJSON * const item, cJSON_bool format, const internal_hooks * const hooks)
+{
+ static const size_t default_buffer_size = 256;
+ printbuffer buffer[1];
+ unsigned char *printed = NULL;
+
+ memset(buffer, 0, sizeof(buffer));
+
+ /* create buffer */
+ buffer->buffer = (unsigned char*) hooks->allocate(default_buffer_size);
+ buffer->length = default_buffer_size;
+ buffer->format = format;
+ buffer->hooks = *hooks;
+ if (buffer->buffer == NULL)
+ {
+ goto fail;
+ }
+
+ /* print the value */
+ if (!print_value(item, buffer))
+ {
+ goto fail;
+ }
+ update_offset(buffer);
+
+ /* check if reallocate is available */
+ if (hooks->reallocate != NULL)
+ {
+ printed = (unsigned char*) hooks->reallocate(buffer->buffer, buffer->offset + 1);
+ if (printed == NULL) {
+ goto fail;
+ }
+ buffer->buffer = NULL;
+ }
+ else /* otherwise copy the JSON over to a new buffer */
+ {
+ printed = (unsigned char*) hooks->allocate(buffer->offset + 1);
+ if (printed == NULL)
+ {
+ goto fail;
+ }
+ memcpy(printed, buffer->buffer, cjson_min(buffer->length, buffer->offset + 1));
+ printed[buffer->offset] = '\0'; /* just to be sure */
+
+ /* free the buffer */
+ hooks->deallocate(buffer->buffer);
+ }
+
+ return printed;
+
+fail:
+ if (buffer->buffer != NULL)
+ {
+ hooks->deallocate(buffer->buffer);
+ }
+
+ if (printed != NULL)
+ {
+ hooks->deallocate(printed);
+ }
+
+ return NULL;
+}
+
+/* Render a cJSON item/entity/structure to text. */
+CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item)
+{
+ return (char*)print(item, true, &global_hooks);
+}
+
+CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item)
+{
+ return (char*)print(item, false, &global_hooks);
+}
+
+CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt)
+{
+ printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } };
+
+ if (prebuffer < 0)
+ {
+ return NULL;
+ }
+
+ p.buffer = (unsigned char*)global_hooks.allocate((size_t)prebuffer);
+ if (!p.buffer)
+ {
+ return NULL;
+ }
+
+ p.length = (size_t)prebuffer;
+ p.offset = 0;
+ p.noalloc = false;
+ p.format = fmt;
+ p.hooks = global_hooks;
+
+ if (!print_value(item, &p))
+ {
+ global_hooks.deallocate(p.buffer);
+ return NULL;
+ }
+
+ return (char*)p.buffer;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format)
+{
+ printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } };
+
+ if ((length < 0) || (buffer == NULL))
+ {
+ return false;
+ }
+
+ p.buffer = (unsigned char*)buffer;
+ p.length = (size_t)length;
+ p.offset = 0;
+ p.noalloc = true;
+ p.format = format;
+ p.hooks = global_hooks;
+
+ return print_value(item, &p);
+}
+
+/* Parser core - when encountering text, process appropriately. */
+static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer)
+{
+ if ((input_buffer == NULL) || (input_buffer->content == NULL))
+ {
+ return false; /* no input */
+ }
+
+ /* parse the different types of values */
+ /* null */
+ if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "null", 4) == 0))
+ {
+ item->type = cJSON_NULL;
+ input_buffer->offset += 4;
+ return true;
+ }
+ /* false */
+ if (can_read(input_buffer, 5) && (strncmp((const char*)buffer_at_offset(input_buffer), "false", 5) == 0))
+ {
+ item->type = cJSON_False;
+ input_buffer->offset += 5;
+ return true;
+ }
+ /* true */
+ if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "true", 4) == 0))
+ {
+ item->type = cJSON_True;
+ item->valueint = 1;
+ input_buffer->offset += 4;
+ return true;
+ }
+ /* string */
+ if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '\"'))
+ {
+ return parse_string(item, input_buffer);
+ }
+ /* number */
+ if (can_access_at_index(input_buffer, 0) && ((buffer_at_offset(input_buffer)[0] == '-') || ((buffer_at_offset(input_buffer)[0] >= '0') && (buffer_at_offset(input_buffer)[0] <= '9'))))
+ {
+ return parse_number(item, input_buffer);
+ }
+ /* array */
+ if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '['))
+ {
+ return parse_array(item, input_buffer);
+ }
+ /* object */
+ if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '{'))
+ {
+ return parse_object(item, input_buffer);
+ }
+
+ return false;
+}
+
+/* Render a value to text. */
+static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer)
+{
+ unsigned char *output = NULL;
+
+ if ((item == NULL) || (output_buffer == NULL))
+ {
+ return false;
+ }
+
+ switch ((item->type) & 0xFF)
+ {
+ case cJSON_NULL:
+ output = ensure(output_buffer, 5);
+ if (output == NULL)
+ {
+ return false;
+ }
+ strncpy((char*)output, "null", strlen("null") + 1);
+ return true;
+
+ case cJSON_False:
+ output = ensure(output_buffer, 6);
+ if (output == NULL)
+ {
+ return false;
+ }
+ strncpy((char*)output, "false", strlen("false") + 1);
+ return true;
+
+ case cJSON_True:
+ output = ensure(output_buffer, 5);
+ if (output == NULL)
+ {
+ return false;
+ }
+ strncpy((char*)output, "true", strlen("true") + 1);
+ return true;
+
+ case cJSON_Number:
+ return print_number(item, output_buffer);
+
+ case cJSON_Raw:
+ {
+ size_t raw_length = 0;
+ if (item->valuestring == NULL)
+ {
+ return false;
+ }
+
+ raw_length = strlen(item->valuestring) + sizeof("");
+ output = ensure(output_buffer, raw_length);
+ if (output == NULL)
+ {
+ return false;
+ }
+ memcpy(output, item->valuestring, raw_length);
+ return true;
+ }
+
+ case cJSON_String:
+ return print_string(item, output_buffer);
+
+ case cJSON_Array:
+ return print_array(item, output_buffer);
+
+ case cJSON_Object:
+ return print_object(item, output_buffer);
+
+ default:
+ return false;
+ }
+}
+
+/* Build an array from input text. */
+static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer)
+{
+ cJSON *head = NULL; /* head of the linked list */
+ cJSON *current_item = NULL;
+
+ if (input_buffer->depth >= CJSON_NESTING_LIMIT)
+ {
+ return false; /* to deeply nested */
+ }
+ input_buffer->depth++;
+
+ if (buffer_at_offset(input_buffer)[0] != '[')
+ {
+ /* not an array */
+ goto fail;
+ }
+
+ input_buffer->offset++;
+ buffer_skip_whitespace(input_buffer);
+ if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ']'))
+ {
+ /* empty array */
+ goto success;
+ }
+
+ /* check if we skipped to the end of the buffer */
+ if (cannot_access_at_index(input_buffer, 0))
+ {
+ input_buffer->offset--;
+ goto fail;
+ }
+
+ /* step back to character in front of the first element */
+ input_buffer->offset--;
+ /* loop through the comma separated array elements */
+ do
+ {
+ /* allocate next item */
+ cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks));
+ if (new_item == NULL)
+ {
+ goto fail; /* allocation failure */
+ }
+
+ /* attach next item to list */
+ if (head == NULL)
+ {
+ /* start the linked list */
+ current_item = head = new_item;
+ }
+ else
+ {
+ /* add to the end and advance */
+ current_item->next = new_item;
+ new_item->prev = current_item;
+ current_item = new_item;
+ }
+
+ /* parse next value */
+ input_buffer->offset++;
+ buffer_skip_whitespace(input_buffer);
+ if (!parse_value(current_item, input_buffer))
+ {
+ goto fail; /* failed to parse value */
+ }
+ buffer_skip_whitespace(input_buffer);
+ }
+ while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ','));
+
+ if (cannot_access_at_index(input_buffer, 0) || buffer_at_offset(input_buffer)[0] != ']')
+ {
+ goto fail; /* expected end of array */
+ }
+
+success:
+ input_buffer->depth--;
+
+ if (head != NULL) {
+ head->prev = current_item;
+ }
+
+ item->type = cJSON_Array;
+ item->child = head;
+
+ input_buffer->offset++;
+
+ return true;
+
+fail:
+ if (head != NULL)
+ {
+ cJSON_Delete(head);
+ }
+
+ return false;
+}
+
+/* Render an array to text */
+static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer)
+{
+ unsigned char *output_pointer = NULL;
+ size_t length = 0;
+ cJSON *current_element = item->child;
+
+ if (output_buffer == NULL)
+ {
+ return false;
+ }
+
+ /* Compose the output array. */
+ /* opening square bracket */
+ output_pointer = ensure(output_buffer, 1);
+ if (output_pointer == NULL)
+ {
+ return false;
+ }
+
+ *output_pointer = '[';
+ output_buffer->offset++;
+ output_buffer->depth++;
+
+ while (current_element != NULL)
+ {
+ if (!print_value(current_element, output_buffer))
+ {
+ return false;
+ }
+ update_offset(output_buffer);
+ if (current_element->next)
+ {
+ length = (size_t) (output_buffer->format ? 2 : 1);
+ output_pointer = ensure(output_buffer, length + 1);
+ if (output_pointer == NULL)
+ {
+ return false;
+ }
+ *output_pointer++ = ',';
+ if(output_buffer->format)
+ {
+ *output_pointer++ = ' ';
+ }
+ *output_pointer = '\0';
+ output_buffer->offset += length;
+ }
+ current_element = current_element->next;
+ }
+
+ output_pointer = ensure(output_buffer, 2);
+ if (output_pointer == NULL)
+ {
+ return false;
+ }
+ *output_pointer++ = ']';
+ *output_pointer = '\0';
+ output_buffer->depth--;
+
+ return true;
+}
+
+/* Build an object from the text. */
+static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer)
+{
+ cJSON *head = NULL; /* linked list head */
+ cJSON *current_item = NULL;
+
+ if (input_buffer->depth >= CJSON_NESTING_LIMIT)
+ {
+ return false; /* to deeply nested */
+ }
+ input_buffer->depth++;
+
+ if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '{'))
+ {
+ goto fail; /* not an object */
+ }
+
+ input_buffer->offset++;
+ buffer_skip_whitespace(input_buffer);
+ if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '}'))
+ {
+ goto success; /* empty object */
+ }
+
+ /* check if we skipped to the end of the buffer */
+ if (cannot_access_at_index(input_buffer, 0))
+ {
+ input_buffer->offset--;
+ goto fail;
+ }
+
+ /* step back to character in front of the first element */
+ input_buffer->offset--;
+ /* loop through the comma separated array elements */
+ do
+ {
+ /* allocate next item */
+ cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks));
+ if (new_item == NULL)
+ {
+ goto fail; /* allocation failure */
+ }
+
+ /* attach next item to list */
+ if (head == NULL)
+ {
+ /* start the linked list */
+ current_item = head = new_item;
+ }
+ else
+ {
+ /* add to the end and advance */
+ current_item->next = new_item;
+ new_item->prev = current_item;
+ current_item = new_item;
+ }
+
+ /* parse the name of the child */
+ input_buffer->offset++;
+ buffer_skip_whitespace(input_buffer);
+ if (!parse_string(current_item, input_buffer))
+ {
+ goto fail; /* failed to parse name */
+ }
+ buffer_skip_whitespace(input_buffer);
+
+ /* swap valuestring and string, because we parsed the name */
+ current_item->string = current_item->valuestring;
+ current_item->valuestring = NULL;
+
+ if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != ':'))
+ {
+ goto fail; /* invalid object */
+ }
+
+ /* parse the value */
+ input_buffer->offset++;
+ buffer_skip_whitespace(input_buffer);
+ if (!parse_value(current_item, input_buffer))
+ {
+ goto fail; /* failed to parse value */
+ }
+ buffer_skip_whitespace(input_buffer);
+ }
+ while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ','));
+
+ if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '}'))
+ {
+ goto fail; /* expected end of object */
+ }
+
+success:
+ input_buffer->depth--;
+
+ if (head != NULL) {
+ head->prev = current_item;
+ }
+
+ item->type = cJSON_Object;
+ item->child = head;
+
+ input_buffer->offset++;
+ return true;
+
+fail:
+ if (head != NULL)
+ {
+ cJSON_Delete(head);
+ }
+
+ return false;
+}
+
+/* Render an object to text. */
+static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer)
+{
+ unsigned char *output_pointer = NULL;
+ size_t length = 0;
+ cJSON *current_item = item->child;
+
+ if (output_buffer == NULL)
+ {
+ return false;
+ }
+
+ /* Compose the output: */
+ length = (size_t) (output_buffer->format ? 2 : 1); /* fmt: {\n */
+ output_pointer = ensure(output_buffer, length + 1);
+ if (output_pointer == NULL)
+ {
+ return false;
+ }
+
+ *output_pointer++ = '{';
+ output_buffer->depth++;
+ if (output_buffer->format)
+ {
+ *output_pointer++ = '\n';
+ }
+ output_buffer->offset += length;
+
+ while (current_item)
+ {
+ if (output_buffer->format)
+ {
+ size_t i;
+ output_pointer = ensure(output_buffer, output_buffer->depth);
+ if (output_pointer == NULL)
+ {
+ return false;
+ }
+ for (i = 0; i < output_buffer->depth; i++)
+ {
+ *output_pointer++ = '\t';
+ }
+ output_buffer->offset += output_buffer->depth;
+ }
+
+ /* print key */
+ if (!print_string_ptr((unsigned char*)current_item->string, output_buffer))
+ {
+ return false;
+ }
+ update_offset(output_buffer);
+
+ length = (size_t) (output_buffer->format ? 2 : 1);
+ output_pointer = ensure(output_buffer, length);
+ if (output_pointer == NULL)
+ {
+ return false;
+ }
+ *output_pointer++ = ':';
+ if (output_buffer->format)
+ {
+ *output_pointer++ = '\t';
+ }
+ output_buffer->offset += length;
+
+ /* print value */
+ if (!print_value(current_item, output_buffer))
+ {
+ return false;
+ }
+ update_offset(output_buffer);
+
+ /* print comma if not last */
+ length = ((size_t)(output_buffer->format ? 1 : 0) + (size_t)(current_item->next ? 1 : 0));
+ output_pointer = ensure(output_buffer, length + 1);
+ if (output_pointer == NULL)
+ {
+ return false;
+ }
+ if (current_item->next)
+ {
+ *output_pointer++ = ',';
+ }
+
+ if (output_buffer->format)
+ {
+ *output_pointer++ = '\n';
+ }
+ *output_pointer = '\0';
+ output_buffer->offset += length;
+
+ current_item = current_item->next;
+ }
+
+ output_pointer = ensure(output_buffer, output_buffer->format ? (output_buffer->depth + 1) : 2);
+ if (output_pointer == NULL)
+ {
+ return false;
+ }
+ if (output_buffer->format)
+ {
+ size_t i;
+ for (i = 0; i < (output_buffer->depth - 1); i++)
+ {
+ *output_pointer++ = '\t';
+ }
+ }
+ *output_pointer++ = '}';
+ *output_pointer = '\0';
+ output_buffer->depth--;
+
+ return true;
+}
+
+/* Get Array size/item / object item. */
+CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array)
+{
+ cJSON *child = NULL;
+ size_t size = 0;
+
+ if (array == NULL)
+ {
+ return 0;
+ }
+
+ child = array->child;
+
+ while(child != NULL)
+ {
+ size++;
+ child = child->next;
+ }
+
+ /* FIXME: Can overflow here. Cannot be fixed without breaking the API */
+
+ return (int)size;
+}
+
+static cJSON* get_array_item(const cJSON *array, size_t index)
+{
+ cJSON *current_child = NULL;
+
+ if (array == NULL)
+ {
+ return NULL;
+ }
+
+ current_child = array->child;
+ while ((current_child != NULL) && (index > 0))
+ {
+ index--;
+ current_child = current_child->next;
+ }
+
+ return current_child;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index)
+{
+ if (index < 0)
+ {
+ return NULL;
+ }
+
+ return get_array_item(array, (size_t)index);
+}
+
+static cJSON *get_object_item(const cJSON * const object, const char * const name, const cJSON_bool case_sensitive)
+{
+ cJSON *current_element = NULL;
+
+ if ((object == NULL) || (name == NULL))
+ {
+ return NULL;
+ }
+
+ current_element = object->child;
+ if (case_sensitive)
+ {
+ while ((current_element != NULL) && (current_element->string != NULL) && (strcmp(name, current_element->string) != 0))
+ {
+ current_element = current_element->next;
+ }
+ }
+ else
+ {
+ while ((current_element != NULL) && (case_insensitive_strcmp((const unsigned char*)name, (const unsigned char*)(current_element->string)) != 0))
+ {
+ current_element = current_element->next;
+ }
+ }
+
+ if ((current_element == NULL) || (current_element->string == NULL)) {
+ return NULL;
+ }
+
+ return current_element;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string)
+{
+ return get_object_item(object, string, false);
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string)
+{
+ return get_object_item(object, string, true);
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string)
+{
+ return cJSON_GetObjectItem(object, string) ? 1 : 0;
+}
+
+/* Utility for array list handling. */
+static void suffix_object(cJSON *prev, cJSON *item)
+{
+ prev->next = item;
+ item->prev = prev;
+}
+
+/* Utility for handling references. */
+static cJSON *create_reference(const cJSON *item, const internal_hooks * const hooks)
+{
+ cJSON *reference = NULL;
+ if (item == NULL)
+ {
+ return NULL;
+ }
+
+ reference = cJSON_New_Item(hooks);
+ if (reference == NULL)
+ {
+ return NULL;
+ }
+
+ memcpy(reference, item, sizeof(cJSON));
+ reference->string = NULL;
+ reference->type |= cJSON_IsReference;
+ reference->next = reference->prev = NULL;
+ return reference;
+}
+
+static cJSON_bool add_item_to_array(cJSON *array, cJSON *item)
+{
+ cJSON *child = NULL;
+
+ if ((item == NULL) || (array == NULL) || (array == item))
+ {
+ return false;
+ }
+
+ child = array->child;
+ /*
+ * To find the last item in array quickly, we use prev in array
+ */
+ if (child == NULL)
+ {
+ /* list is empty, start new one */
+ array->child = item;
+ item->prev = item;
+ item->next = NULL;
+ }
+ else
+ {
+ /* append to the end */
+ if (child->prev)
+ {
+ suffix_object(child->prev, item);
+ array->child->prev = item;
+ }
+ }
+
+ return true;
+}
+
+/* Add item to array/object. */
+CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item)
+{
+ return add_item_to_array(array, item);
+}
+
+#if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5))))
+ #pragma GCC diagnostic push
+#endif
+#ifdef __GNUC__
+#pragma GCC diagnostic ignored "-Wcast-qual"
+#endif
+/* helper function to cast away const */
+static void* cast_away_const(const void* string)
+{
+ return (void*)string;
+}
+#if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5))))
+ #pragma GCC diagnostic pop
+#endif
+
+
+static cJSON_bool add_item_to_object(cJSON * const object, const char * const string, cJSON * const item, const internal_hooks * const hooks, const cJSON_bool constant_key)
+{
+ char *new_key = NULL;
+ int new_type = cJSON_Invalid;
+
+ if ((object == NULL) || (string == NULL) || (item == NULL) || (object == item))
+ {
+ return false;
+ }
+
+ if (constant_key)
+ {
+ new_key = (char*)cast_away_const(string);
+ new_type = item->type | cJSON_StringIsConst;
+ }
+ else
+ {
+ new_key = (char*)cJSON_strdup((const unsigned char*)string, hooks);
+ if (new_key == NULL)
+ {
+ return false;
+ }
+
+ new_type = item->type & ~cJSON_StringIsConst;
+ }
+
+ if (!(item->type & cJSON_StringIsConst) && (item->string != NULL))
+ {
+ hooks->deallocate(item->string);
+ }
+
+ item->string = new_key;
+ item->type = new_type;
+
+ return add_item_to_array(object, item);
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item)
+{
+ return add_item_to_object(object, string, item, &global_hooks, false);
+}
+
+/* Add an item to an object with constant string as key */
+CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item)
+{
+ return add_item_to_object(object, string, item, &global_hooks, true);
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item)
+{
+ if (array == NULL)
+ {
+ return false;
+ }
+
+ return add_item_to_array(array, create_reference(item, &global_hooks));
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item)
+{
+ if ((object == NULL) || (string == NULL))
+ {
+ return false;
+ }
+
+ return add_item_to_object(object, string, create_reference(item, &global_hooks), &global_hooks, false);
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name)
+{
+ cJSON *null = cJSON_CreateNull();
+ if (add_item_to_object(object, name, null, &global_hooks, false))
+ {
+ return null;
+ }
+
+ cJSON_Delete(null);
+ return NULL;
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name)
+{
+ cJSON *true_item = cJSON_CreateTrue();
+ if (add_item_to_object(object, name, true_item, &global_hooks, false))
+ {
+ return true_item;
+ }
+
+ cJSON_Delete(true_item);
+ return NULL;
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name)
+{
+ cJSON *false_item = cJSON_CreateFalse();
+ if (add_item_to_object(object, name, false_item, &global_hooks, false))
+ {
+ return false_item;
+ }
+
+ cJSON_Delete(false_item);
+ return NULL;
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean)
+{
+ cJSON *bool_item = cJSON_CreateBool(boolean);
+ if (add_item_to_object(object, name, bool_item, &global_hooks, false))
+ {
+ return bool_item;
+ }
+
+ cJSON_Delete(bool_item);
+ return NULL;
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number)
+{
+ cJSON *number_item = cJSON_CreateNumber(number);
+ if (add_item_to_object(object, name, number_item, &global_hooks, false))
+ {
+ return number_item;
+ }
+
+ cJSON_Delete(number_item);
+ return NULL;
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string)
+{
+ cJSON *string_item = cJSON_CreateString(string);
+ if (add_item_to_object(object, name, string_item, &global_hooks, false))
+ {
+ return string_item;
+ }
+
+ cJSON_Delete(string_item);
+ return NULL;
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw)
+{
+ cJSON *raw_item = cJSON_CreateRaw(raw);
+ if (add_item_to_object(object, name, raw_item, &global_hooks, false))
+ {
+ return raw_item;
+ }
+
+ cJSON_Delete(raw_item);
+ return NULL;
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name)
+{
+ cJSON *object_item = cJSON_CreateObject();
+ if (add_item_to_object(object, name, object_item, &global_hooks, false))
+ {
+ return object_item;
+ }
+
+ cJSON_Delete(object_item);
+ return NULL;
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name)
+{
+ cJSON *array = cJSON_CreateArray();
+ if (add_item_to_object(object, name, array, &global_hooks, false))
+ {
+ return array;
+ }
+
+ cJSON_Delete(array);
+ return NULL;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item)
+{
+ if ((parent == NULL) || (item == NULL))
+ {
+ return NULL;
+ }
+
+ if (item != parent->child)
+ {
+ /* not the first element */
+ item->prev->next = item->next;
+ }
+ if (item->next != NULL)
+ {
+ /* not the last element */
+ item->next->prev = item->prev;
+ }
+
+ if (item == parent->child)
+ {
+ /* first element */
+ parent->child = item->next;
+ }
+ else if (item->next == NULL)
+ {
+ /* last element */
+ parent->child->prev = item->prev;
+ }
+
+ /* make sure the detached item doesn't point anywhere anymore */
+ item->prev = NULL;
+ item->next = NULL;
+
+ return item;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which)
+{
+ if (which < 0)
+ {
+ return NULL;
+ }
+
+ return cJSON_DetachItemViaPointer(array, get_array_item(array, (size_t)which));
+}
+
+CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which)
+{
+ cJSON_Delete(cJSON_DetachItemFromArray(array, which));
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string)
+{
+ cJSON *to_detach = cJSON_GetObjectItem(object, string);
+
+ return cJSON_DetachItemViaPointer(object, to_detach);
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string)
+{
+ cJSON *to_detach = cJSON_GetObjectItemCaseSensitive(object, string);
+
+ return cJSON_DetachItemViaPointer(object, to_detach);
+}
+
+CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string)
+{
+ cJSON_Delete(cJSON_DetachItemFromObject(object, string));
+}
+
+CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string)
+{
+ cJSON_Delete(cJSON_DetachItemFromObjectCaseSensitive(object, string));
+}
+
+/* Replace array/object items with new ones. */
+CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem)
+{
+ cJSON *after_inserted = NULL;
+
+ if (which < 0)
+ {
+ return false;
+ }
+
+ after_inserted = get_array_item(array, (size_t)which);
+ if (after_inserted == NULL)
+ {
+ return add_item_to_array(array, newitem);
+ }
+
+ newitem->next = after_inserted;
+ newitem->prev = after_inserted->prev;
+ after_inserted->prev = newitem;
+ if (after_inserted == array->child)
+ {
+ array->child = newitem;
+ }
+ else
+ {
+ newitem->prev->next = newitem;
+ }
+ return true;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement)
+{
+ if ((parent == NULL) || (replacement == NULL) || (item == NULL))
+ {
+ return false;
+ }
+
+ if (replacement == item)
+ {
+ return true;
+ }
+
+ replacement->next = item->next;
+ replacement->prev = item->prev;
+
+ if (replacement->next != NULL)
+ {
+ replacement->next->prev = replacement;
+ }
+ if (parent->child == item)
+ {
+ if (parent->child->prev == parent->child)
+ {
+ replacement->prev = replacement;
+ }
+ parent->child = replacement;
+ }
+ else
+ { /*
+ * To find the last item in array quickly, we use prev in array.
+ * We can't modify the last item's next pointer where this item was the parent's child
+ */
+ if (replacement->prev != NULL)
+ {
+ replacement->prev->next = replacement;
+ }
+ if (replacement->next == NULL)
+ {
+ parent->child->prev = replacement;
+ }
+ }
+
+ item->next = NULL;
+ item->prev = NULL;
+ cJSON_Delete(item);
+
+ return true;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem)
+{
+ if (which < 0)
+ {
+ return false;
+ }
+
+ return cJSON_ReplaceItemViaPointer(array, get_array_item(array, (size_t)which), newitem);
+}
+
+static cJSON_bool replace_item_in_object(cJSON *object, const char *string, cJSON *replacement, cJSON_bool case_sensitive)
+{
+ if ((replacement == NULL) || (string == NULL))
+ {
+ return false;
+ }
+
+ /* replace the name in the replacement */
+ if (!(replacement->type & cJSON_StringIsConst) && (replacement->string != NULL))
+ {
+ cJSON_free(replacement->string);
+ }
+ replacement->string = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks);
+ replacement->type &= ~cJSON_StringIsConst;
+
+ return cJSON_ReplaceItemViaPointer(object, get_object_item(object, string, case_sensitive), replacement);
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem)
+{
+ return replace_item_in_object(object, string, newitem, false);
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const char *string, cJSON *newitem)
+{
+ return replace_item_in_object(object, string, newitem, true);
+}
+
+/* Create basic types: */
+CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void)
+{
+ cJSON *item = cJSON_New_Item(&global_hooks);
+ if(item)
+ {
+ item->type = cJSON_NULL;
+ }
+
+ return item;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void)
+{
+ cJSON *item = cJSON_New_Item(&global_hooks);
+ if(item)
+ {
+ item->type = cJSON_True;
+ }
+
+ return item;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void)
+{
+ cJSON *item = cJSON_New_Item(&global_hooks);
+ if(item)
+ {
+ item->type = cJSON_False;
+ }
+
+ return item;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean)
+{
+ cJSON *item = cJSON_New_Item(&global_hooks);
+ if(item)
+ {
+ item->type = boolean ? cJSON_True : cJSON_False;
+ }
+
+ return item;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num)
+{
+ cJSON *item = cJSON_New_Item(&global_hooks);
+ if(item)
+ {
+ item->type = cJSON_Number;
+ item->valuedouble = num;
+
+ /* use saturation in case of overflow */
+ if (num >= INT_MAX)
+ {
+ item->valueint = INT_MAX;
+ }
+ else if (num <= (double)INT_MIN)
+ {
+ item->valueint = INT_MIN;
+ }
+ else
+ {
+ item->valueint = (int)num;
+ }
+ }
+
+ return item;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string)
+{
+ cJSON *item = cJSON_New_Item(&global_hooks);
+ if(item)
+ {
+ item->type = cJSON_String;
+ item->valuestring = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks);
+ if(!item->valuestring)
+ {
+ cJSON_Delete(item);
+ return NULL;
+ }
+ }
+
+ return item;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string)
+{
+ cJSON *item = cJSON_New_Item(&global_hooks);
+ if (item != NULL)
+ {
+ item->type = cJSON_String | cJSON_IsReference;
+ item->valuestring = (char*)cast_away_const(string);
+ }
+
+ return item;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child)
+{
+ cJSON *item = cJSON_New_Item(&global_hooks);
+ if (item != NULL) {
+ item->type = cJSON_Object | cJSON_IsReference;
+ item->child = (cJSON*)cast_away_const(child);
+ }
+
+ return item;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child) {
+ cJSON *item = cJSON_New_Item(&global_hooks);
+ if (item != NULL) {
+ item->type = cJSON_Array | cJSON_IsReference;
+ item->child = (cJSON*)cast_away_const(child);
+ }
+
+ return item;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw)
+{
+ cJSON *item = cJSON_New_Item(&global_hooks);
+ if(item)
+ {
+ item->type = cJSON_Raw;
+ item->valuestring = (char*)cJSON_strdup((const unsigned char*)raw, &global_hooks);
+ if(!item->valuestring)
+ {
+ cJSON_Delete(item);
+ return NULL;
+ }
+ }
+
+ return item;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void)
+{
+ cJSON *item = cJSON_New_Item(&global_hooks);
+ if(item)
+ {
+ item->type=cJSON_Array;
+ }
+
+ return item;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void)
+{
+ cJSON *item = cJSON_New_Item(&global_hooks);
+ if (item)
+ {
+ item->type = cJSON_Object;
+ }
+
+ return item;
+}
+
+/* Create Arrays: */
+CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count)
+{
+ size_t i = 0;
+ cJSON *n = NULL;
+ cJSON *p = NULL;
+ cJSON *a = NULL;
+
+ if ((count < 0) || (numbers == NULL))
+ {
+ return NULL;
+ }
+
+ a = cJSON_CreateArray();
+ for(i = 0; a && (i < (size_t)count); i++)
+ {
+ n = cJSON_CreateNumber(numbers[i]);
+ if (!n)
+ {
+ cJSON_Delete(a);
+ return NULL;
+ }
+ if(!i)
+ {
+ a->child = n;
+ }
+ else
+ {
+ suffix_object(p, n);
+ }
+ p = n;
+ }
+ a->child->prev = n;
+
+ return a;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count)
+{
+ size_t i = 0;
+ cJSON *n = NULL;
+ cJSON *p = NULL;
+ cJSON *a = NULL;
+
+ if ((count < 0) || (numbers == NULL))
+ {
+ return NULL;
+ }
+
+ a = cJSON_CreateArray();
+
+ for(i = 0; a && (i < (size_t)count); i++)
+ {
+ n = cJSON_CreateNumber((double)numbers[i]);
+ if(!n)
+ {
+ cJSON_Delete(a);
+ return NULL;
+ }
+ if(!i)
+ {
+ a->child = n;
+ }
+ else
+ {
+ suffix_object(p, n);
+ }
+ p = n;
+ }
+ a->child->prev = n;
+
+ return a;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count)
+{
+ size_t i = 0;
+ cJSON *n = NULL;
+ cJSON *p = NULL;
+ cJSON *a = NULL;
+
+ if ((count < 0) || (numbers == NULL))
+ {
+ return NULL;
+ }
+
+ a = cJSON_CreateArray();
+
+ for(i = 0;a && (i < (size_t)count); i++)
+ {
+ n = cJSON_CreateNumber(numbers[i]);
+ if(!n)
+ {
+ cJSON_Delete(a);
+ return NULL;
+ }
+ if(!i)
+ {
+ a->child = n;
+ }
+ else
+ {
+ suffix_object(p, n);
+ }
+ p = n;
+ }
+ a->child->prev = n;
+
+ return a;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count)
+{
+ size_t i = 0;
+ cJSON *n = NULL;
+ cJSON *p = NULL;
+ cJSON *a = NULL;
+
+ if ((count < 0) || (strings == NULL))
+ {
+ return NULL;
+ }
+
+ a = cJSON_CreateArray();
+
+ for (i = 0; a && (i < (size_t)count); i++)
+ {
+ n = cJSON_CreateString(strings[i]);
+ if(!n)
+ {
+ cJSON_Delete(a);
+ return NULL;
+ }
+ if(!i)
+ {
+ a->child = n;
+ }
+ else
+ {
+ suffix_object(p,n);
+ }
+ p = n;
+ }
+ a->child->prev = n;
+
+ return a;
+}
+
+/* Duplication */
+CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse)
+{
+ cJSON *newitem = NULL;
+ cJSON *child = NULL;
+ cJSON *next = NULL;
+ cJSON *newchild = NULL;
+
+ /* Bail on bad ptr */
+ if (!item)
+ {
+ goto fail;
+ }
+ /* Create new item */
+ newitem = cJSON_New_Item(&global_hooks);
+ if (!newitem)
+ {
+ goto fail;
+ }
+ /* Copy over all vars */
+ newitem->type = item->type & (~cJSON_IsReference);
+ newitem->valueint = item->valueint;
+ newitem->valuedouble = item->valuedouble;
+ if (item->valuestring)
+ {
+ newitem->valuestring = (char*)cJSON_strdup((unsigned char*)item->valuestring, &global_hooks);
+ if (!newitem->valuestring)
+ {
+ goto fail;
+ }
+ }
+ if (item->string)
+ {
+ newitem->string = (item->type&cJSON_StringIsConst) ? item->string : (char*)cJSON_strdup((unsigned char*)item->string, &global_hooks);
+ if (!newitem->string)
+ {
+ goto fail;
+ }
+ }
+ /* If non-recursive, then we're done! */
+ if (!recurse)
+ {
+ return newitem;
+ }
+ /* Walk the ->next chain for the child. */
+ child = item->child;
+ while (child != NULL)
+ {
+ newchild = cJSON_Duplicate(child, true); /* Duplicate (with recurse) each item in the ->next chain */
+ if (!newchild)
+ {
+ goto fail;
+ }
+ if (next != NULL)
+ {
+ /* If newitem->child already set, then crosswire ->prev and ->next and move on */
+ next->next = newchild;
+ newchild->prev = next;
+ next = newchild;
+ }
+ else
+ {
+ /* Set newitem->child and move to it */
+ newitem->child = newchild;
+ next = newchild;
+ }
+ child = child->next;
+ }
+ if (newitem && newitem->child)
+ {
+ newitem->child->prev = newchild;
+ }
+
+ return newitem;
+
+fail:
+ if (newitem != NULL)
+ {
+ cJSON_Delete(newitem);
+ }
+
+ return NULL;
+}
+
+static void skip_oneline_comment(char **input)
+{
+ *input += static_strlen("//");
+
+ for (; (*input)[0] != '\0'; ++(*input))
+ {
+ if ((*input)[0] == '\n') {
+ *input += static_strlen("\n");
+ return;
+ }
+ }
+}
+
+static void skip_multiline_comment(char **input)
+{
+ *input += static_strlen("/*");
+
+ for (; (*input)[0] != '\0'; ++(*input))
+ {
+ if (((*input)[0] == '*') && ((*input)[1] == '/'))
+ {
+ *input += static_strlen("*/");
+ return;
+ }
+ }
+}
+
+static void minify_string(char **input, char **output) {
+ (*output)[0] = (*input)[0];
+ *input += static_strlen("\"");
+ *output += static_strlen("\"");
+
+
+ for (; (*input)[0] != '\0'; (void)++(*input), ++(*output)) {
+ (*output)[0] = (*input)[0];
+
+ if ((*input)[0] == '\"') {
+ (*output)[0] = '\"';
+ *input += static_strlen("\"");
+ *output += static_strlen("\"");
+ return;
+ } else if (((*input)[0] == '\\') && ((*input)[1] == '\"')) {
+ (*output)[1] = (*input)[1];
+ *input += static_strlen("\"");
+ *output += static_strlen("\"");
+ }
+ }
+}
+
+CJSON_PUBLIC(void) cJSON_Minify(char *json)
+{
+ char *into = json;
+
+ if (json == NULL)
+ {
+ return;
+ }
+
+ while (json[0] != '\0')
+ {
+ switch (json[0])
+ {
+ case ' ':
+ case '\t':
+ case '\r':
+ case '\n':
+ json++;
+ break;
+
+ case '/':
+ if (json[1] == '/')
+ {
+ skip_oneline_comment(&json);
+ }
+ else if (json[1] == '*')
+ {
+ skip_multiline_comment(&json);
+ } else {
+ json++;
+ }
+ break;
+
+ case '\"':
+ minify_string(&json, (char**)&into);
+ break;
+
+ default:
+ into[0] = json[0];
+ json++;
+ into++;
+ }
+ }
+
+ /* and null-terminate. */
+ *into = '\0';
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item)
+{
+ if (item == NULL)
+ {
+ return false;
+ }
+
+ return (item->type & 0xFF) == cJSON_Invalid;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item)
+{
+ if (item == NULL)
+ {
+ return false;
+ }
+
+ return (item->type & 0xFF) == cJSON_False;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item)
+{
+ if (item == NULL)
+ {
+ return false;
+ }
+
+ return (item->type & 0xff) == cJSON_True;
+}
+
+
+CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item)
+{
+ if (item == NULL)
+ {
+ return false;
+ }
+
+ return (item->type & (cJSON_True | cJSON_False)) != 0;
+}
+CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item)
+{
+ if (item == NULL)
+ {
+ return false;
+ }
+
+ return (item->type & 0xFF) == cJSON_NULL;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item)
+{
+ if (item == NULL)
+ {
+ return false;
+ }
+
+ return (item->type & 0xFF) == cJSON_Number;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item)
+{
+ if (item == NULL)
+ {
+ return false;
+ }
+
+ return (item->type & 0xFF) == cJSON_String;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item)
+{
+ if (item == NULL)
+ {
+ return false;
+ }
+
+ return (item->type & 0xFF) == cJSON_Array;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item)
+{
+ if (item == NULL)
+ {
+ return false;
+ }
+
+ return (item->type & 0xFF) == cJSON_Object;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item)
+{
+ if (item == NULL)
+ {
+ return false;
+ }
+
+ return (item->type & 0xFF) == cJSON_Raw;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive)
+{
+ if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF)) || cJSON_IsInvalid(a))
+ {
+ return false;
+ }
+
+ /* check if type is valid */
+ switch (a->type & 0xFF)
+ {
+ case cJSON_False:
+ case cJSON_True:
+ case cJSON_NULL:
+ case cJSON_Number:
+ case cJSON_String:
+ case cJSON_Raw:
+ case cJSON_Array:
+ case cJSON_Object:
+ break;
+
+ default:
+ return false;
+ }
+
+ /* identical objects are equal */
+ if (a == b)
+ {
+ return true;
+ }
+
+ switch (a->type & 0xFF)
+ {
+ /* in these cases and equal type is enough */
+ case cJSON_False:
+ case cJSON_True:
+ case cJSON_NULL:
+ return true;
+
+ case cJSON_Number:
+ if (compare_double(a->valuedouble, b->valuedouble))
+ {
+ return true;
+ }
+ return false;
+
+ case cJSON_String:
+ case cJSON_Raw:
+ if ((a->valuestring == NULL) || (b->valuestring == NULL))
+ {
+ return false;
+ }
+ if (strcmp(a->valuestring, b->valuestring) == 0)
+ {
+ return true;
+ }
+
+ return false;
+
+ case cJSON_Array:
+ {
+ cJSON *a_element = a->child;
+ cJSON *b_element = b->child;
+
+ for (; (a_element != NULL) && (b_element != NULL);)
+ {
+ if (!cJSON_Compare(a_element, b_element, case_sensitive))
+ {
+ return false;
+ }
+
+ a_element = a_element->next;
+ b_element = b_element->next;
+ }
+
+ /* one of the arrays is longer than the other */
+ if (a_element != b_element) {
+ return false;
+ }
+
+ return true;
+ }
+
+ case cJSON_Object:
+ {
+ cJSON *a_element = NULL;
+ cJSON *b_element = NULL;
+ cJSON_ArrayForEach(a_element, a)
+ {
+ /* TODO This has O(n^2) runtime, which is horrible! */
+ b_element = get_object_item(b, a_element->string, case_sensitive);
+ if (b_element == NULL)
+ {
+ return false;
+ }
+
+ if (!cJSON_Compare(a_element, b_element, case_sensitive))
+ {
+ return false;
+ }
+ }
+
+ /* doing this twice, once on a and b to prevent true comparison if a subset of b
+ * TODO: Do this the proper way, this is just a fix for now */
+ cJSON_ArrayForEach(b_element, b)
+ {
+ a_element = get_object_item(a, b_element->string, case_sensitive);
+ if (a_element == NULL)
+ {
+ return false;
+ }
+
+ if (!cJSON_Compare(b_element, a_element, case_sensitive))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ default:
+ return false;
+ }
+}
+
+CJSON_PUBLIC(void *) cJSON_malloc(size_t size)
+{
+ return global_hooks.allocate(size);
+}
+
+CJSON_PUBLIC(void) cJSON_free(void *object)
+{
+ global_hooks.deallocate(object);
+}
+
+}
diff --git a/contrib/restricted/aws/aws-crt-cpp/source/http/HttpConnection.cpp b/contrib/restricted/aws/aws-crt-cpp/source/http/HttpConnection.cpp
new file mode 100644
index 0000000000..f8ed94cefc
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/source/http/HttpConnection.cpp
@@ -0,0 +1,400 @@
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+#include <aws/crt/Api.h>
+#include <aws/crt/http/HttpConnection.h>
+#include <aws/crt/http/HttpProxyStrategy.h>
+#include <aws/crt/http/HttpRequestResponse.h>
+#include <aws/crt/io/Bootstrap.h>
+
+namespace Aws
+{
+ namespace Crt
+ {
+ namespace Http
+ {
+ /* This exists to handle aws_http_connection's shutdown callback, which might fire after
+ * HttpClientConnection has been destroyed. */
+ struct ConnectionCallbackData
+ {
+ explicit ConnectionCallbackData(Allocator *allocator) : allocator(allocator) {}
+ std::weak_ptr<HttpClientConnection> connection;
+ Allocator *allocator;
+ OnConnectionSetup onConnectionSetup;
+ OnConnectionShutdown onConnectionShutdown;
+ };
+
+ class UnmanagedConnection final : public HttpClientConnection
+ {
+ public:
+ UnmanagedConnection(aws_http_connection *connection, Aws::Crt::Allocator *allocator)
+ : HttpClientConnection(connection, allocator)
+ {
+ }
+
+ ~UnmanagedConnection() override
+ {
+ if (m_connection)
+ {
+ aws_http_connection_release(m_connection);
+ m_connection = nullptr;
+ }
+ }
+ };
+
+ void HttpClientConnection::s_onClientConnectionSetup(
+ struct aws_http_connection *connection,
+ int errorCode,
+ void *user_data) noexcept
+ {
+ /**
+ * Allocate an HttpClientConnection and seat it to `ConnectionCallbackData`'s shared_ptr.
+ */
+ auto *callbackData = static_cast<ConnectionCallbackData *>(user_data);
+ if (!errorCode)
+ {
+ auto connectionObj = std::allocate_shared<UnmanagedConnection>(
+ Aws::Crt::StlAllocator<UnmanagedConnection>(), connection, callbackData->allocator);
+
+ if (connectionObj)
+ {
+ callbackData->connection = connectionObj;
+ callbackData->onConnectionSetup(std::move(connectionObj), errorCode);
+ return;
+ }
+
+ aws_http_connection_release(connection);
+ errorCode = aws_last_error();
+ }
+
+ callbackData->onConnectionSetup(nullptr, errorCode);
+ Delete(callbackData, callbackData->allocator);
+ }
+
+ void HttpClientConnection::s_onClientConnectionShutdown(
+ struct aws_http_connection *connection,
+ int errorCode,
+ void *user_data) noexcept
+ {
+ (void)connection;
+ auto *callbackData = static_cast<ConnectionCallbackData *>(user_data);
+
+ /* Don't invoke callback if the connection object has expired. */
+ if (auto connectionPtr = callbackData->connection.lock())
+ {
+ callbackData->onConnectionShutdown(*connectionPtr, errorCode);
+ }
+
+ Delete(callbackData, callbackData->allocator);
+ }
+
+ bool HttpClientConnection::CreateConnection(
+ const HttpClientConnectionOptions &connectionOptions,
+ Allocator *allocator) noexcept
+ {
+ AWS_FATAL_ASSERT(connectionOptions.OnConnectionSetupCallback);
+ AWS_FATAL_ASSERT(connectionOptions.OnConnectionShutdownCallback);
+
+ if (connectionOptions.TlsOptions && !(*connectionOptions.TlsOptions))
+ {
+ AWS_LOGF_ERROR(
+ AWS_LS_HTTP_GENERAL,
+ "Cannot create HttpClientConnection: connectionOptions contains invalid TlsOptions.");
+ aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
+ return false;
+ }
+
+ if (connectionOptions.ProxyOptions)
+ {
+ const auto &proxyOpts = connectionOptions.ProxyOptions.value();
+
+ if (proxyOpts.TlsOptions && !(*proxyOpts.TlsOptions))
+ {
+ AWS_LOGF_ERROR(
+ AWS_LS_HTTP_GENERAL,
+ "Cannot create HttpClientConnection: connectionOptions has ProxyOptions that contain "
+ "invalid TlsOptions.");
+ aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
+ return false;
+ }
+ }
+
+ auto *callbackData = New<ConnectionCallbackData>(allocator, allocator);
+
+ if (!callbackData)
+ {
+ return false;
+ }
+ callbackData->onConnectionShutdown = connectionOptions.OnConnectionShutdownCallback;
+ callbackData->onConnectionSetup = connectionOptions.OnConnectionSetupCallback;
+
+ aws_http_client_connection_options options;
+ AWS_ZERO_STRUCT(options);
+ options.self_size = sizeof(aws_http_client_connection_options);
+
+ if (options.bootstrap != nullptr)
+ {
+ options.bootstrap = connectionOptions.Bootstrap->GetUnderlyingHandle();
+ }
+ else
+ {
+ options.bootstrap = ApiHandle::GetOrCreateStaticDefaultClientBootstrap()->GetUnderlyingHandle();
+ }
+
+ if (connectionOptions.TlsOptions)
+ {
+ /* This is verified earlier in this function. */
+ AWS_FATAL_ASSERT(*connectionOptions.TlsOptions);
+
+ options.tls_options =
+ const_cast<aws_tls_connection_options *>(connectionOptions.TlsOptions->GetUnderlyingHandle());
+ }
+ options.allocator = allocator;
+ options.user_data = callbackData;
+ options.host_name = aws_byte_cursor_from_c_str(connectionOptions.HostName.c_str());
+ options.port = connectionOptions.Port;
+ options.initial_window_size = connectionOptions.InitialWindowSize;
+ options.socket_options = &connectionOptions.SocketOptions.GetImpl();
+ options.on_setup = HttpClientConnection::s_onClientConnectionSetup;
+ options.on_shutdown = HttpClientConnection::s_onClientConnectionShutdown;
+ options.manual_window_management = connectionOptions.ManualWindowManagement;
+
+ aws_http_proxy_options proxyOptions;
+ AWS_ZERO_STRUCT(proxyOptions);
+ if (connectionOptions.ProxyOptions)
+ {
+ const auto &proxyOpts = connectionOptions.ProxyOptions.value();
+
+ /* This is verified earlier in this function. */
+ AWS_FATAL_ASSERT(!proxyOpts.TlsOptions || *proxyOpts.TlsOptions);
+
+ proxyOpts.InitializeRawProxyOptions(proxyOptions);
+
+ options.proxy_options = &proxyOptions;
+ }
+
+ if (aws_http_client_connect(&options))
+ {
+ Delete(callbackData, allocator);
+ return false;
+ }
+
+ return true;
+ }
+
+ HttpClientConnection::HttpClientConnection(aws_http_connection *connection, Allocator *allocator) noexcept
+ : m_connection(connection), m_allocator(allocator), m_lastError(AWS_ERROR_SUCCESS)
+ {
+ }
+
+ std::shared_ptr<HttpClientStream> HttpClientConnection::NewClientStream(
+ const HttpRequestOptions &requestOptions) noexcept
+ {
+ AWS_ASSERT(requestOptions.onIncomingHeaders);
+ AWS_ASSERT(requestOptions.onStreamComplete);
+
+ aws_http_make_request_options options;
+ AWS_ZERO_STRUCT(options);
+ options.self_size = sizeof(aws_http_make_request_options);
+ options.request = requestOptions.request->GetUnderlyingMessage();
+ options.on_response_body = HttpStream::s_onIncomingBody;
+ options.on_response_headers = HttpStream::s_onIncomingHeaders;
+ options.on_response_header_block_done = HttpStream::s_onIncomingHeaderBlockDone;
+ options.on_complete = HttpStream::s_onStreamComplete;
+
+ /* Do the same ref counting trick we did with HttpClientConnection. We need to maintain a reference
+ * internally (regardless of what the user does), until the Stream shuts down. */
+ auto *toSeat = static_cast<HttpClientStream *>(aws_mem_acquire(m_allocator, sizeof(HttpClientStream)));
+
+ if (toSeat)
+ {
+ toSeat = new (toSeat) HttpClientStream(this->shared_from_this());
+
+ Allocator *captureAllocator = m_allocator;
+ std::shared_ptr<HttpClientStream> stream(
+ toSeat,
+ [captureAllocator](HttpStream *stream) { Delete(stream, captureAllocator); },
+ StlAllocator<HttpClientStream>(captureAllocator));
+
+ stream->m_onIncomingBody = requestOptions.onIncomingBody;
+ stream->m_onIncomingHeaders = requestOptions.onIncomingHeaders;
+ stream->m_onIncomingHeadersBlockDone = requestOptions.onIncomingHeadersBlockDone;
+ stream->m_onStreamComplete = requestOptions.onStreamComplete;
+ stream->m_callbackData.allocator = m_allocator;
+
+ // we purposefully do not set m_callbackData::stream because we don't want the reference count
+ // incremented until the request is kicked off via HttpClientStream::Activate(). Activate()
+ // increments the ref count.
+ options.user_data = &stream->m_callbackData;
+ stream->m_stream = aws_http_connection_make_request(m_connection, &options);
+
+ if (!stream->m_stream)
+ {
+ stream = nullptr;
+ m_lastError = aws_last_error();
+ return nullptr;
+ }
+
+ return stream;
+ }
+
+ m_lastError = aws_last_error();
+ return nullptr;
+ }
+
+ bool HttpClientConnection::IsOpen() const noexcept { return aws_http_connection_is_open(m_connection); }
+
+ void HttpClientConnection::Close() noexcept { aws_http_connection_close(m_connection); }
+
+ HttpVersion HttpClientConnection::GetVersion() noexcept
+ {
+ return (HttpVersion)aws_http_connection_get_version(m_connection);
+ }
+
+ int HttpStream::s_onIncomingHeaders(
+ struct aws_http_stream *,
+ enum aws_http_header_block headerBlock,
+ const struct aws_http_header *headerArray,
+ size_t numHeaders,
+ void *userData) noexcept
+ {
+ auto callbackData = static_cast<ClientStreamCallbackData *>(userData);
+ callbackData->stream->m_onIncomingHeaders(*callbackData->stream, headerBlock, headerArray, numHeaders);
+
+ return AWS_OP_SUCCESS;
+ }
+
+ int HttpStream::s_onIncomingHeaderBlockDone(
+ struct aws_http_stream *,
+ enum aws_http_header_block headerBlock,
+ void *userData) noexcept
+ {
+ auto callbackData = static_cast<ClientStreamCallbackData *>(userData);
+
+ if (callbackData->stream->m_onIncomingHeadersBlockDone)
+ {
+ callbackData->stream->m_onIncomingHeadersBlockDone(*callbackData->stream, headerBlock);
+ }
+
+ return AWS_OP_SUCCESS;
+ }
+
+ int HttpStream::s_onIncomingBody(
+ struct aws_http_stream *,
+ const struct aws_byte_cursor *data,
+ void *userData) noexcept
+ {
+ auto callbackData = static_cast<ClientStreamCallbackData *>(userData);
+
+ if (callbackData->stream->m_onIncomingBody)
+ {
+ callbackData->stream->m_onIncomingBody(*callbackData->stream, *data);
+ }
+
+ return AWS_OP_SUCCESS;
+ }
+
+ void HttpStream::s_onStreamComplete(struct aws_http_stream *, int errorCode, void *userData) noexcept
+ {
+ auto callbackData = static_cast<ClientStreamCallbackData *>(userData);
+ callbackData->stream->m_onStreamComplete(*callbackData->stream, errorCode);
+ callbackData->stream = nullptr;
+ }
+
+ HttpStream::HttpStream(const std::shared_ptr<HttpClientConnection> &connection) noexcept
+ : m_stream(nullptr), m_connection(connection)
+ {
+ }
+
+ HttpStream::~HttpStream()
+ {
+ if (m_stream)
+ {
+ aws_http_stream_release(m_stream);
+ }
+
+ if (m_connection)
+ {
+ m_connection = nullptr;
+ }
+ }
+
+ HttpClientConnection &HttpStream::GetConnection() const noexcept { return *m_connection; }
+
+ HttpClientStream::HttpClientStream(const std::shared_ptr<HttpClientConnection> &connection) noexcept
+ : HttpStream(connection)
+ {
+ }
+
+ HttpClientStream::~HttpClientStream() {}
+
+ int HttpClientStream::GetResponseStatusCode() const noexcept
+ {
+ int status = 0;
+ if (!aws_http_stream_get_incoming_response_status(m_stream, &status))
+ {
+ return status;
+ }
+
+ return -1;
+ }
+
+ bool HttpClientStream::Activate() noexcept
+ {
+ m_callbackData.stream = shared_from_this();
+ if (aws_http_stream_activate(m_stream))
+ {
+ m_callbackData.stream = nullptr;
+ return false;
+ }
+
+ return true;
+ }
+
+ void HttpStream::UpdateWindow(std::size_t incrementSize) noexcept
+ {
+ aws_http_stream_update_window(m_stream, incrementSize);
+ }
+
+ HttpClientConnectionProxyOptions::HttpClientConnectionProxyOptions()
+ : HostName(), Port(0), TlsOptions(), ProxyConnectionType(AwsHttpProxyConnectionType::Legacy),
+ ProxyStrategy(), AuthType(AwsHttpProxyAuthenticationType::None)
+ {
+ }
+
+ void HttpClientConnectionProxyOptions::InitializeRawProxyOptions(
+ struct aws_http_proxy_options &rawOptions) const
+ {
+ AWS_ZERO_STRUCT(rawOptions);
+ rawOptions.connection_type = (enum aws_http_proxy_connection_type)ProxyConnectionType;
+ rawOptions.host = aws_byte_cursor_from_c_str(HostName.c_str());
+ rawOptions.port = Port;
+
+ if (TlsOptions.has_value())
+ {
+ rawOptions.tls_options = TlsOptions->GetUnderlyingHandle();
+ }
+
+ if (ProxyStrategy)
+ {
+ rawOptions.proxy_strategy = ProxyStrategy->GetUnderlyingHandle();
+ }
+
+ if (AuthType == AwsHttpProxyAuthenticationType::Basic)
+ {
+ rawOptions.auth_type = AWS_HPAT_BASIC;
+ rawOptions.auth_username = ByteCursorFromCString(BasicAuthUsername.c_str());
+ rawOptions.auth_password = ByteCursorFromCString(BasicAuthPassword.c_str());
+ }
+ }
+
+ HttpClientConnectionOptions::HttpClientConnectionOptions()
+ : Bootstrap(nullptr), InitialWindowSize(SIZE_MAX), OnConnectionSetupCallback(),
+ OnConnectionShutdownCallback(), HostName(), Port(0), SocketOptions(), TlsOptions(), ProxyOptions(),
+ ManualWindowManagement(false)
+ {
+ }
+ } // namespace Http
+ } // namespace Crt
+} // namespace Aws
diff --git a/contrib/restricted/aws/aws-crt-cpp/source/http/HttpConnectionManager.cpp b/contrib/restricted/aws/aws-crt-cpp/source/http/HttpConnectionManager.cpp
new file mode 100644
index 0000000000..7a13a2bdb1
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/source/http/HttpConnectionManager.cpp
@@ -0,0 +1,236 @@
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+#include <aws/crt/Api.h>
+#include <aws/crt/http/HttpConnectionManager.h>
+#include <aws/crt/http/HttpProxyStrategy.h>
+
+#include <algorithm>
+#include <aws/http/connection_manager.h>
+
+namespace Aws
+{
+ namespace Crt
+ {
+ namespace Http
+ {
+ struct ConnectionManagerCallbackArgs
+ {
+ ConnectionManagerCallbackArgs() = default;
+ OnClientConnectionAvailable m_onClientConnectionAvailable;
+ std::shared_ptr<HttpClientConnectionManager> m_connectionManager;
+ };
+
+ void HttpClientConnectionManager::s_shutdownCompleted(void *userData) noexcept
+ {
+ HttpClientConnectionManager *connectionManager =
+ reinterpret_cast<HttpClientConnectionManager *>(userData);
+ connectionManager->m_shutdownPromise.set_value();
+ }
+
+ HttpClientConnectionManagerOptions::HttpClientConnectionManagerOptions() noexcept
+ : ConnectionOptions(), MaxConnections(1), EnableBlockingShutdown(false)
+ {
+ }
+
+ std::shared_ptr<HttpClientConnectionManager> HttpClientConnectionManager::NewClientConnectionManager(
+ const HttpClientConnectionManagerOptions &connectionManagerOptions,
+ Allocator *allocator) noexcept
+ {
+ const Optional<Io::TlsConnectionOptions> &tlsOptions =
+ connectionManagerOptions.ConnectionOptions.TlsOptions;
+
+ if (tlsOptions && !(*tlsOptions))
+ {
+ AWS_LOGF_ERROR(
+ AWS_LS_HTTP_GENERAL,
+ "Cannot create HttpClientConnectionManager: ConnectionOptions contain invalid TLSOptions.");
+ aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
+ return nullptr;
+ }
+
+ const Crt::Optional<Crt::Http::HttpClientConnectionProxyOptions> &proxyOptions =
+ connectionManagerOptions.ConnectionOptions.ProxyOptions;
+
+ if (proxyOptions && proxyOptions->TlsOptions && !(*proxyOptions->TlsOptions))
+ {
+ AWS_LOGF_ERROR(
+ AWS_LS_HTTP_GENERAL,
+ "Cannot create HttpClientConnectionManager: ProxyOptions has ConnectionOptions that contain "
+ "invalid TLSOptions.");
+ aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
+ return nullptr;
+ }
+
+ auto *toSeat = static_cast<HttpClientConnectionManager *>(
+ aws_mem_acquire(allocator, sizeof(HttpClientConnectionManager)));
+ if (toSeat)
+ {
+ toSeat = new (toSeat) HttpClientConnectionManager(connectionManagerOptions, allocator);
+ return std::shared_ptr<HttpClientConnectionManager>(
+ toSeat, [allocator](HttpClientConnectionManager *manager) { Delete(manager, allocator); });
+ }
+
+ return nullptr;
+ }
+
+ HttpClientConnectionManager::HttpClientConnectionManager(
+ const HttpClientConnectionManagerOptions &options,
+ Allocator *allocator) noexcept
+ : m_allocator(allocator), m_connectionManager(nullptr), m_options(options), m_releaseInvoked(false)
+ {
+ const auto &connectionOptions = m_options.ConnectionOptions;
+ AWS_FATAL_ASSERT(connectionOptions.HostName.size() > 0);
+ AWS_FATAL_ASSERT(connectionOptions.Port > 0);
+
+ aws_http_connection_manager_options managerOptions;
+ AWS_ZERO_STRUCT(managerOptions);
+
+ if (connectionOptions.Bootstrap != nullptr)
+ {
+ managerOptions.bootstrap = connectionOptions.Bootstrap->GetUnderlyingHandle();
+ }
+ else
+ {
+ managerOptions.bootstrap =
+ ApiHandle::GetOrCreateStaticDefaultClientBootstrap()->GetUnderlyingHandle();
+ }
+
+ managerOptions.port = connectionOptions.Port;
+ managerOptions.max_connections = m_options.MaxConnections;
+ managerOptions.socket_options = &connectionOptions.SocketOptions.GetImpl();
+ managerOptions.initial_window_size = connectionOptions.InitialWindowSize;
+
+ if (options.EnableBlockingShutdown)
+ {
+ managerOptions.shutdown_complete_callback = s_shutdownCompleted;
+ managerOptions.shutdown_complete_user_data = this;
+ }
+ else
+ {
+ m_shutdownPromise.set_value();
+ }
+
+ aws_http_proxy_options proxyOptions;
+ AWS_ZERO_STRUCT(proxyOptions);
+ if (connectionOptions.ProxyOptions)
+ {
+ /* This is verified by HttpClientConnectionManager::NewClientConnectionManager */
+ AWS_FATAL_ASSERT(
+ !connectionOptions.ProxyOptions->TlsOptions || *connectionOptions.ProxyOptions->TlsOptions);
+
+ const auto &proxyOpts = connectionOptions.ProxyOptions.value();
+ proxyOpts.InitializeRawProxyOptions(proxyOptions);
+
+ managerOptions.proxy_options = &proxyOptions;
+ }
+
+ if (connectionOptions.TlsOptions)
+ {
+ /* This is verified by HttpClientConnectionManager::NewClientConnectionManager */
+ AWS_FATAL_ASSERT(*connectionOptions.TlsOptions);
+
+ managerOptions.tls_connection_options =
+ const_cast<aws_tls_connection_options *>(connectionOptions.TlsOptions->GetUnderlyingHandle());
+ }
+ managerOptions.host = aws_byte_cursor_from_c_str(connectionOptions.HostName.c_str());
+
+ m_connectionManager = aws_http_connection_manager_new(allocator, &managerOptions);
+ }
+
+ HttpClientConnectionManager::~HttpClientConnectionManager()
+ {
+ if (!m_releaseInvoked)
+ {
+ aws_http_connection_manager_release(m_connectionManager);
+ m_shutdownPromise.get_future().get();
+ }
+ m_connectionManager = nullptr;
+ }
+
+ bool HttpClientConnectionManager::AcquireConnection(
+ const OnClientConnectionAvailable &onClientConnectionAvailable) noexcept
+ {
+ auto connectionManagerCallbackArgs = Aws::Crt::New<ConnectionManagerCallbackArgs>(m_allocator);
+ if (!connectionManagerCallbackArgs)
+ {
+ return false;
+ }
+
+ connectionManagerCallbackArgs->m_connectionManager = shared_from_this();
+ connectionManagerCallbackArgs->m_onClientConnectionAvailable = onClientConnectionAvailable;
+
+ aws_http_connection_manager_acquire_connection(
+ m_connectionManager, s_onConnectionSetup, connectionManagerCallbackArgs);
+ return true;
+ }
+
+ std::future<void> HttpClientConnectionManager::InitiateShutdown() noexcept
+ {
+ m_releaseInvoked = true;
+ aws_http_connection_manager_release(m_connectionManager);
+ return m_shutdownPromise.get_future();
+ }
+
+ class ManagedConnection final : public HttpClientConnection
+ {
+ public:
+ ManagedConnection(
+ aws_http_connection *connection,
+ std::shared_ptr<HttpClientConnectionManager> connectionManager)
+ : HttpClientConnection(connection, connectionManager->m_allocator),
+ m_connectionManager(std::move(connectionManager))
+ {
+ }
+
+ ~ManagedConnection() override
+ {
+ if (m_connection)
+ {
+ aws_http_connection_manager_release_connection(
+ m_connectionManager->m_connectionManager, m_connection);
+ m_connection = nullptr;
+ }
+ }
+
+ private:
+ std::shared_ptr<HttpClientConnectionManager> m_connectionManager;
+ };
+
+ void HttpClientConnectionManager::s_onConnectionSetup(
+ aws_http_connection *connection,
+ int errorCode,
+ void *userData) noexcept
+ {
+ auto callbackArgs = static_cast<ConnectionManagerCallbackArgs *>(userData);
+ std::shared_ptr<HttpClientConnectionManager> manager = callbackArgs->m_connectionManager;
+ auto callback = std::move(callbackArgs->m_onClientConnectionAvailable);
+
+ Delete(callbackArgs, manager->m_allocator);
+
+ if (errorCode)
+ {
+ callback(nullptr, errorCode);
+ return;
+ }
+
+ auto allocator = manager->m_allocator;
+ auto connectionRawObj = Aws::Crt::New<ManagedConnection>(manager->m_allocator, connection, manager);
+
+ if (!connectionRawObj)
+ {
+ aws_http_connection_manager_release_connection(manager->m_connectionManager, connection);
+ callback(nullptr, AWS_ERROR_OOM);
+ return;
+ }
+ auto connectionObj = std::shared_ptr<ManagedConnection>(
+ connectionRawObj,
+ [allocator](ManagedConnection *managedConnection) { Delete(managedConnection, allocator); });
+
+ callback(connectionObj, AWS_OP_SUCCESS);
+ }
+
+ } // namespace Http
+ } // namespace Crt
+} // namespace Aws
diff --git a/contrib/restricted/aws/aws-crt-cpp/source/http/HttpProxyStrategy.cpp b/contrib/restricted/aws/aws-crt-cpp/source/http/HttpProxyStrategy.cpp
new file mode 100644
index 0000000000..7b9ef2c3f9
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/source/http/HttpProxyStrategy.cpp
@@ -0,0 +1,196 @@
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+#include <aws/crt/http/HttpProxyStrategy.h>
+
+#include <aws/common/string.h>
+#include <aws/crt/http/HttpConnection.h>
+#include <aws/http/proxy.h>
+
+namespace Aws
+{
+ namespace Crt
+ {
+ namespace Http
+ {
+ HttpProxyStrategy::HttpProxyStrategy(struct aws_http_proxy_strategy *strategy) : m_strategy(strategy) {}
+
+ HttpProxyStrategy::~HttpProxyStrategy() { aws_http_proxy_strategy_release(m_strategy); }
+
+ HttpProxyStrategyBasicAuthConfig::HttpProxyStrategyBasicAuthConfig()
+ : ConnectionType(AwsHttpProxyConnectionType::Legacy), Username(), Password()
+ {
+ }
+
+ std::shared_ptr<HttpProxyStrategy> HttpProxyStrategy::CreateBasicHttpProxyStrategy(
+ const HttpProxyStrategyBasicAuthConfig &config,
+ Allocator *allocator)
+ {
+ struct aws_http_proxy_strategy_basic_auth_options basicConfig;
+ AWS_ZERO_STRUCT(basicConfig);
+ basicConfig.proxy_connection_type = (enum aws_http_proxy_connection_type)config.ConnectionType;
+ basicConfig.user_name = aws_byte_cursor_from_c_str(config.Username.c_str());
+ basicConfig.password = aws_byte_cursor_from_c_str(config.Password.c_str());
+
+ struct aws_http_proxy_strategy *strategy =
+ aws_http_proxy_strategy_new_basic_auth(allocator, &basicConfig);
+ if (strategy == NULL)
+ {
+ return NULL;
+ }
+
+ return Aws::Crt::MakeShared<HttpProxyStrategy>(allocator, strategy);
+ }
+
+ class AdaptiveHttpProxyStrategy : public HttpProxyStrategy
+ {
+ public:
+ AdaptiveHttpProxyStrategy(
+ Allocator *allocator,
+ const KerberosGetTokenFunction &kerberosGetToken,
+ const KerberosGetTokenFunction &ntlmGetCredential,
+ const NtlmGetTokenFunction &ntlmGetToken)
+ : HttpProxyStrategy(nullptr), m_Allocator(allocator), m_KerberosGetToken(kerberosGetToken),
+ m_NtlmGetCredential(ntlmGetCredential), m_NtlmGetToken(ntlmGetToken)
+ {
+ }
+
+ void SetStrategy(struct aws_http_proxy_strategy *strategy)
+ {
+ aws_http_proxy_strategy_release(m_strategy);
+ m_strategy = strategy;
+ }
+
+ static struct aws_string *NtlmGetCredential(void *user_data, int *error_code)
+ {
+ AdaptiveHttpProxyStrategy *strategy = reinterpret_cast<AdaptiveHttpProxyStrategy *>(user_data);
+
+ String ntlmCredential;
+ if (strategy->m_NtlmGetCredential(ntlmCredential))
+ {
+ struct aws_string *token =
+ aws_string_new_from_c_str(strategy->m_Allocator, ntlmCredential.c_str());
+
+ if (token != NULL)
+ {
+ return token;
+ }
+
+ *error_code = aws_last_error();
+ }
+ else
+ {
+ *error_code = AWS_ERROR_HTTP_PROXY_STRATEGY_TOKEN_RETRIEVAL_FAILURE;
+ }
+
+ return NULL;
+ }
+
+ static struct aws_string *KerberosGetToken(void *user_data, int *error_code)
+ {
+ AdaptiveHttpProxyStrategy *strategy = reinterpret_cast<AdaptiveHttpProxyStrategy *>(user_data);
+
+ String kerberosToken;
+ if (strategy->m_KerberosGetToken(kerberosToken))
+ {
+ struct aws_string *token =
+ aws_string_new_from_c_str(strategy->m_Allocator, kerberosToken.c_str());
+
+ if (token != NULL)
+ {
+ return token;
+ }
+
+ *error_code = aws_last_error();
+ }
+ else
+ {
+ *error_code = AWS_ERROR_HTTP_PROXY_STRATEGY_TOKEN_RETRIEVAL_FAILURE;
+ }
+
+ return NULL;
+ }
+
+ static struct aws_string *NtlmGetToken(
+ void *user_data,
+ const struct aws_byte_cursor *challenge_cursor,
+ int *error_code)
+ {
+ AdaptiveHttpProxyStrategy *strategy = reinterpret_cast<AdaptiveHttpProxyStrategy *>(user_data);
+
+ String ntlmToken;
+ String challengeToken((const char *)challenge_cursor->ptr, challenge_cursor->len);
+ if (strategy->m_NtlmGetToken(challengeToken, ntlmToken))
+ {
+ struct aws_string *token = aws_string_new_from_c_str(strategy->m_Allocator, ntlmToken.c_str());
+
+ if (token != NULL)
+ {
+ return token;
+ }
+
+ *error_code = aws_last_error();
+ }
+ else
+ {
+ *error_code = AWS_ERROR_HTTP_PROXY_STRATEGY_TOKEN_RETRIEVAL_FAILURE;
+ }
+
+ return NULL;
+ }
+
+ private:
+ Allocator *m_Allocator;
+
+ KerberosGetTokenFunction m_KerberosGetToken;
+ KerberosGetTokenFunction m_NtlmGetCredential;
+ NtlmGetTokenFunction m_NtlmGetToken;
+ };
+
+ std::shared_ptr<HttpProxyStrategy> HttpProxyStrategy::CreateAdaptiveHttpProxyStrategy(
+ const HttpProxyStrategyAdaptiveConfig &config,
+ Allocator *allocator)
+ {
+ std::shared_ptr<AdaptiveHttpProxyStrategy> adaptiveStrategy =
+ Aws::Crt::MakeShared<AdaptiveHttpProxyStrategy>(
+ allocator, allocator, config.KerberosGetToken, config.NtlmGetCredential, config.NtlmGetToken);
+
+ struct aws_http_proxy_strategy_tunneling_kerberos_options kerberosConfig;
+ AWS_ZERO_STRUCT(kerberosConfig);
+ kerberosConfig.get_token = AdaptiveHttpProxyStrategy::KerberosGetToken;
+ kerberosConfig.get_token_user_data = adaptiveStrategy.get();
+
+ struct aws_http_proxy_strategy_tunneling_ntlm_options ntlmConfig;
+ AWS_ZERO_STRUCT(ntlmConfig);
+ ntlmConfig.get_challenge_token = AdaptiveHttpProxyStrategy::NtlmGetToken;
+ ntlmConfig.get_token = AdaptiveHttpProxyStrategy::NtlmGetCredential;
+ ntlmConfig.get_challenge_token_user_data = adaptiveStrategy.get();
+
+ struct aws_http_proxy_strategy_tunneling_adaptive_options adaptiveConfig;
+ AWS_ZERO_STRUCT(adaptiveConfig);
+
+ if (config.KerberosGetToken)
+ {
+ adaptiveConfig.kerberos_options = &kerberosConfig;
+ }
+
+ if (config.NtlmGetToken)
+ {
+ adaptiveConfig.ntlm_options = &ntlmConfig;
+ }
+
+ struct aws_http_proxy_strategy *strategy =
+ aws_http_proxy_strategy_new_tunneling_adaptive(allocator, &adaptiveConfig);
+ if (strategy == NULL)
+ {
+ return NULL;
+ }
+
+ adaptiveStrategy->SetStrategy(strategy);
+
+ return adaptiveStrategy;
+ }
+ } // namespace Http
+ } // namespace Crt
+} // namespace Aws
diff --git a/contrib/restricted/aws/aws-crt-cpp/source/http/HttpRequestResponse.cpp b/contrib/restricted/aws/aws-crt-cpp/source/http/HttpRequestResponse.cpp
new file mode 100644
index 0000000000..a80a582ac8
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/source/http/HttpRequestResponse.cpp
@@ -0,0 +1,151 @@
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+
+#include <aws/crt/http/HttpRequestResponse.h>
+
+#include <aws/crt/io/Stream.h>
+#include <aws/http/request_response.h>
+#include <aws/io/stream.h>
+
+namespace Aws
+{
+ namespace Crt
+ {
+ namespace Http
+ {
+
+ HttpMessage::HttpMessage(Allocator *allocator, struct aws_http_message *message) noexcept
+ : m_allocator(allocator), m_message(message), m_bodyStream(nullptr)
+ {
+ if (message)
+ {
+ // Acquire a refcount to keep the message alive until this object dies.
+ aws_http_message_acquire(this->m_message);
+ }
+ }
+
+ HttpMessage::~HttpMessage() { m_message = aws_http_message_release(m_message); }
+
+ std::shared_ptr<Aws::Crt::Io::InputStream> HttpMessage::GetBody() const noexcept { return m_bodyStream; }
+
+ bool HttpMessage::SetBody(const std::shared_ptr<Aws::Crt::Io::IStream> &body) noexcept
+ {
+ aws_http_message_set_body_stream(m_message, nullptr);
+ m_bodyStream = nullptr;
+
+ if (body != nullptr)
+ {
+ m_bodyStream = MakeShared<Io::StdIOStreamInputStream>(m_allocator, body, m_allocator);
+ if (m_bodyStream == nullptr || !m_bodyStream)
+ {
+ return false;
+ }
+ aws_http_message_set_body_stream(m_message, m_bodyStream->GetUnderlyingStream());
+ }
+
+ return true;
+ }
+
+ bool HttpMessage::SetBody(const std::shared_ptr<Aws::Crt::Io::InputStream> &body) noexcept
+ {
+ m_bodyStream = body;
+ aws_http_message_set_body_stream(
+ m_message, m_bodyStream && *m_bodyStream ? m_bodyStream->GetUnderlyingStream() : nullptr);
+
+ return true;
+ }
+
+ size_t HttpMessage::GetHeaderCount() const noexcept { return aws_http_message_get_header_count(m_message); }
+
+ Optional<HttpHeader> HttpMessage::GetHeader(size_t index) const noexcept
+ {
+ HttpHeader header;
+ if (aws_http_message_get_header(m_message, &header, index) != AWS_OP_SUCCESS)
+ {
+ return Optional<HttpHeader>();
+ }
+
+ return Optional<HttpHeader>(header);
+ }
+
+ bool HttpMessage::AddHeader(const HttpHeader &header) noexcept
+ {
+ return aws_http_message_add_header(m_message, header) == AWS_OP_SUCCESS;
+ }
+
+ bool HttpMessage::EraseHeader(size_t index) noexcept
+ {
+ return aws_http_message_erase_header(m_message, index) == AWS_OP_SUCCESS;
+ }
+
+ HttpRequest::HttpRequest(Allocator *allocator)
+ : HttpMessage(allocator, aws_http_message_new_request(allocator))
+ {
+ // Releas the refcount as it created, since HttpMessage is taking the ownership
+ aws_http_message_release(this->m_message);
+ }
+
+ HttpRequest::HttpRequest(Allocator *allocator, struct aws_http_message *message)
+ : HttpMessage(allocator, message)
+ {
+ }
+
+ Optional<ByteCursor> HttpRequest::GetMethod() const noexcept
+ {
+ ByteCursor method;
+ if (aws_http_message_get_request_method(m_message, &method) != AWS_OP_SUCCESS)
+ {
+ return Optional<ByteCursor>();
+ }
+
+ return Optional<ByteCursor>(method);
+ }
+
+ bool HttpRequest::SetMethod(ByteCursor method) noexcept
+ {
+ return aws_http_message_set_request_method(m_message, method) == AWS_OP_SUCCESS;
+ }
+
+ Optional<ByteCursor> HttpRequest::GetPath() const noexcept
+ {
+ ByteCursor path;
+ if (aws_http_message_get_request_path(m_message, &path) != AWS_OP_SUCCESS)
+ {
+ return Optional<ByteCursor>();
+ }
+
+ return Optional<ByteCursor>(path);
+ }
+
+ bool HttpRequest::SetPath(ByteCursor path) noexcept
+ {
+ return aws_http_message_set_request_path(m_message, path) == AWS_OP_SUCCESS;
+ }
+
+ HttpResponse::HttpResponse(Allocator *allocator)
+ : HttpMessage(allocator, aws_http_message_new_response(allocator))
+ {
+ // Releas the refcount as it created, since HttpMessage is taking the ownership
+ aws_http_message_release(this->m_message);
+ }
+
+ Optional<int> HttpResponse::GetResponseCode() const noexcept
+ {
+ int response = 0;
+ if (aws_http_message_get_response_status(m_message, &response) != AWS_OP_SUCCESS)
+ {
+ return Optional<int>();
+ }
+
+ return response;
+ }
+
+ bool HttpResponse::SetResponseCode(int response) noexcept
+ {
+ return aws_http_message_set_response_status(m_message, response) == AWS_OP_SUCCESS;
+ }
+ } // namespace Http
+ } // namespace Crt
+} // namespace Aws
diff --git a/contrib/restricted/aws/aws-crt-cpp/source/io/Bootstrap.cpp b/contrib/restricted/aws/aws-crt-cpp/source/io/Bootstrap.cpp
new file mode 100644
index 0000000000..84005a41dc
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/source/io/Bootstrap.cpp
@@ -0,0 +1,122 @@
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+#include <aws/crt/Api.h>
+#include <aws/crt/io/Bootstrap.h>
+
+namespace Aws
+{
+ namespace Crt
+ {
+ namespace Io
+ {
+
+ /**
+ * @private
+ * Holds the bootstrap's shutdown promise.
+ * Lives until the bootstrap's shutdown-complete callback fires.
+ */
+ class ClientBootstrapCallbackData
+ {
+ private:
+ Allocator *m_allocator;
+
+ public:
+ ClientBootstrapCallbackData(Allocator *allocator) : m_allocator(allocator) {}
+ /**
+ * Promise for bootstrap's shutdown.
+ */
+ std::promise<void> ShutdownPromise;
+ /**
+ * User callback of bootstrap's shutdown-complete.
+ */
+ OnClientBootstrapShutdownComplete ShutdownCallback;
+
+ /**
+ * Internal callback of bootstrap's shutdown-complete
+ */
+ static void OnShutdownComplete(void *userData)
+ {
+ auto callbackData = static_cast<ClientBootstrapCallbackData *>(userData);
+
+ callbackData->ShutdownPromise.set_value();
+ if (callbackData->ShutdownCallback)
+ {
+ callbackData->ShutdownCallback();
+ }
+
+ Crt::Delete(callbackData, callbackData->m_allocator);
+ }
+ };
+
+ ClientBootstrap::ClientBootstrap(
+ EventLoopGroup &elGroup,
+ HostResolver &resolver,
+ Allocator *allocator) noexcept
+ : m_bootstrap(nullptr), m_lastError(AWS_ERROR_SUCCESS),
+ m_callbackData(Crt::New<ClientBootstrapCallbackData>(allocator, allocator)),
+ m_enableBlockingShutdown(false)
+ {
+ m_shutdownFuture = m_callbackData->ShutdownPromise.get_future();
+
+ aws_client_bootstrap_options options;
+ options.event_loop_group = elGroup.GetUnderlyingHandle();
+ options.host_resolution_config = resolver.GetConfig();
+ options.host_resolver = resolver.GetUnderlyingHandle();
+ options.on_shutdown_complete = ClientBootstrapCallbackData::OnShutdownComplete;
+ options.user_data = m_callbackData.get();
+ m_bootstrap = aws_client_bootstrap_new(allocator, &options);
+ if (!m_bootstrap)
+ {
+ m_lastError = aws_last_error();
+ }
+ }
+
+ ClientBootstrap::ClientBootstrap(Allocator *allocator) noexcept
+ : ClientBootstrap(
+ *Crt::ApiHandle::GetOrCreateStaticDefaultEventLoopGroup(),
+ *Crt::ApiHandle::GetOrCreateStaticDefaultHostResolver(),
+ allocator)
+ {
+ }
+
+ ClientBootstrap::~ClientBootstrap()
+ {
+ if (m_bootstrap)
+ {
+ // Release m_callbackData, it destroys itself when shutdown completes.
+ m_callbackData.release();
+
+ aws_client_bootstrap_release(m_bootstrap);
+ if (m_enableBlockingShutdown)
+ {
+ // If your program is stuck here, stop using EnableBlockingShutdown()
+ m_shutdownFuture.wait();
+ }
+ }
+ }
+
+ ClientBootstrap::operator bool() const noexcept { return m_lastError == AWS_ERROR_SUCCESS; }
+
+ int ClientBootstrap::LastError() const noexcept { return m_lastError; }
+
+ void ClientBootstrap::SetShutdownCompleteCallback(OnClientBootstrapShutdownComplete callback)
+ {
+ m_callbackData->ShutdownCallback = std::move(callback);
+ }
+
+ void ClientBootstrap::EnableBlockingShutdown() noexcept { m_enableBlockingShutdown = true; }
+
+ aws_client_bootstrap *ClientBootstrap::GetUnderlyingHandle() const noexcept
+ {
+ if (*this)
+ {
+ return m_bootstrap;
+ }
+
+ return nullptr;
+ }
+ } // namespace Io
+ } // namespace Crt
+} // namespace Aws
diff --git a/contrib/restricted/aws/aws-crt-cpp/source/io/ChannelHandler.cpp b/contrib/restricted/aws/aws-crt-cpp/source/io/ChannelHandler.cpp
new file mode 100644
index 0000000000..fcbc443170
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/source/io/ChannelHandler.cpp
@@ -0,0 +1,217 @@
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+#include <aws/crt/io/ChannelHandler.h>
+
+#include <chrono>
+
+namespace Aws
+{
+ namespace Crt
+ {
+ namespace Io
+ {
+ int ChannelHandler::s_ProcessReadMessage(
+ struct aws_channel_handler *handler,
+ struct aws_channel_slot *,
+ struct aws_io_message *message)
+ {
+ auto *channelHandler = reinterpret_cast<ChannelHandler *>(handler->impl);
+
+ return channelHandler->ProcessReadMessage(message);
+ }
+
+ int ChannelHandler::s_ProcessWriteMessage(
+ struct aws_channel_handler *handler,
+ struct aws_channel_slot *,
+ struct aws_io_message *message)
+ {
+ auto *channelHandler = reinterpret_cast<ChannelHandler *>(handler->impl);
+
+ return channelHandler->ProcessWriteMessage(message);
+ }
+
+ int ChannelHandler::s_IncrementReadWindow(
+ struct aws_channel_handler *handler,
+ struct aws_channel_slot *,
+ size_t size)
+ {
+ auto *channelHandler = reinterpret_cast<ChannelHandler *>(handler->impl);
+
+ return channelHandler->IncrementReadWindow(size);
+ }
+
+ int ChannelHandler::s_ProcessShutdown(
+ struct aws_channel_handler *handler,
+ struct aws_channel_slot *,
+ enum aws_channel_direction dir,
+ int errorCode,
+ bool freeScarceResourcesImmediately)
+ {
+ auto *channelHandler = reinterpret_cast<ChannelHandler *>(handler->impl);
+
+ channelHandler->ProcessShutdown(
+ static_cast<ChannelDirection>(dir), errorCode, freeScarceResourcesImmediately);
+ return AWS_OP_SUCCESS;
+ }
+
+ size_t ChannelHandler::s_InitialWindowSize(struct aws_channel_handler *handler)
+ {
+ auto *channelHandler = reinterpret_cast<ChannelHandler *>(handler->impl);
+ return channelHandler->InitialWindowSize();
+ }
+
+ size_t ChannelHandler::s_MessageOverhead(struct aws_channel_handler *handler)
+ {
+ auto *channelHandler = reinterpret_cast<ChannelHandler *>(handler->impl);
+ return channelHandler->MessageOverhead();
+ }
+
+ void ChannelHandler::s_ResetStatistics(struct aws_channel_handler *handler)
+ {
+ auto *channelHandler = reinterpret_cast<ChannelHandler *>(handler->impl);
+ channelHandler->ResetStatistics();
+ }
+
+ void ChannelHandler::s_GatherStatistics(
+ struct aws_channel_handler *handler,
+ struct aws_array_list *statsList)
+ {
+ auto *channelHandler = reinterpret_cast<ChannelHandler *>(handler->impl);
+ channelHandler->GatherStatistics(statsList);
+ }
+
+ void ChannelHandler::s_Destroy(struct aws_channel_handler *handler)
+ {
+ auto *channelHandler = reinterpret_cast<ChannelHandler *>(handler->impl);
+ channelHandler->m_selfReference = nullptr;
+ }
+
+ struct aws_channel_handler_vtable ChannelHandler::s_vtable = {
+ s_ProcessReadMessage,
+ s_ProcessWriteMessage,
+ s_IncrementReadWindow,
+ s_ProcessShutdown,
+ s_InitialWindowSize,
+ s_MessageOverhead,
+ ChannelHandler::s_Destroy,
+ s_ResetStatistics,
+ s_GatherStatistics,
+ };
+
+ ChannelHandler::ChannelHandler(Allocator *allocator) : m_allocator(allocator)
+ {
+ AWS_ZERO_STRUCT(m_handler);
+ m_handler.alloc = allocator;
+ m_handler.impl = reinterpret_cast<void *>(this);
+ m_handler.vtable = &ChannelHandler::s_vtable;
+ }
+
+ struct aws_channel_handler *ChannelHandler::SeatForCInterop(const std::shared_ptr<ChannelHandler> &selfRef)
+ {
+ AWS_FATAL_ASSERT(this == selfRef.get());
+ m_selfReference = selfRef;
+ return &m_handler;
+ }
+
+ struct aws_io_message *ChannelHandler::AcquireMessageFromPool(MessageType messageType, size_t sizeHint)
+ {
+ return aws_channel_acquire_message_from_pool(
+ GetSlot()->channel, static_cast<aws_io_message_type>(messageType), sizeHint);
+ }
+
+ struct aws_io_message *ChannelHandler::AcquireMaxSizeMessageForWrite()
+ {
+ return aws_channel_slot_acquire_max_message_for_write(GetSlot());
+ }
+
+ void ChannelHandler::ShutDownChannel(int errorCode) { aws_channel_shutdown(GetSlot()->channel, errorCode); }
+
+ bool ChannelHandler::ChannelsThreadIsCallersThread() const
+ {
+ return aws_channel_thread_is_callers_thread(GetSlot()->channel);
+ }
+
+ bool ChannelHandler::SendMessage(struct aws_io_message *message, ChannelDirection direction)
+ {
+ return aws_channel_slot_send_message(
+ GetSlot(), message, static_cast<aws_channel_direction>(direction)) == AWS_OP_SUCCESS;
+ }
+
+ bool ChannelHandler::IncrementUpstreamReadWindow(size_t windowUpdateSize)
+ {
+ return aws_channel_slot_increment_read_window(GetSlot(), windowUpdateSize) == AWS_OP_SUCCESS;
+ }
+
+ void ChannelHandler::OnShutdownComplete(
+ ChannelDirection direction,
+ int errorCode,
+ bool freeScarceResourcesImmediately)
+ {
+ aws_channel_slot_on_handler_shutdown_complete(
+ GetSlot(),
+ static_cast<aws_channel_direction>(direction),
+ errorCode,
+ freeScarceResourcesImmediately);
+ }
+
+ size_t ChannelHandler::DownstreamReadWindow() const
+ {
+ if (!GetSlot()->adj_right)
+ {
+ return 0;
+ }
+ return aws_channel_slot_downstream_read_window(GetSlot());
+ }
+
+ size_t ChannelHandler::UpstreamMessageOverhead() const
+ {
+ return aws_channel_slot_upstream_message_overhead(GetSlot());
+ }
+
+ struct aws_channel_slot *ChannelHandler::GetSlot() const { return m_handler.slot; }
+
+ struct TaskWrapper
+ {
+ struct aws_channel_task task
+ {
+ };
+ Allocator *allocator{};
+ std::function<void(TaskStatus)> wrappingFn;
+ };
+
+ static void s_ChannelTaskCallback(struct aws_channel_task *, void *arg, enum aws_task_status status)
+ {
+ auto *taskWrapper = reinterpret_cast<TaskWrapper *>(arg);
+ taskWrapper->wrappingFn(static_cast<TaskStatus>(status));
+ Delete(taskWrapper, taskWrapper->allocator);
+ }
+
+ void ChannelHandler::ScheduleTask(std::function<void(TaskStatus)> &&task, std::chrono::nanoseconds run_in)
+ {
+ auto *wrapper = New<TaskWrapper>(m_allocator);
+ wrapper->wrappingFn = std::move(task);
+ wrapper->allocator = m_allocator;
+ aws_channel_task_init(
+ &wrapper->task, s_ChannelTaskCallback, wrapper, "cpp-crt-custom-channel-handler-task");
+
+ uint64_t currentTimestamp = 0;
+ aws_channel_current_clock_time(GetSlot()->channel, &currentTimestamp);
+ aws_channel_schedule_task_future(GetSlot()->channel, &wrapper->task, currentTimestamp + run_in.count());
+ }
+
+ void ChannelHandler::ScheduleTask(std::function<void(TaskStatus)> &&task)
+ {
+ auto *wrapper = New<TaskWrapper>(m_allocator);
+ wrapper->wrappingFn = std::move(task);
+ wrapper->allocator = m_allocator;
+ aws_channel_task_init(
+ &wrapper->task, s_ChannelTaskCallback, wrapper, "cpp-crt-custom-channel-handler-task");
+
+ aws_channel_schedule_task_now(GetSlot()->channel, &wrapper->task);
+ }
+
+ } // namespace Io
+ } // namespace Crt
+} // namespace Aws
diff --git a/contrib/restricted/aws/aws-crt-cpp/source/io/EventLoopGroup.cpp b/contrib/restricted/aws/aws-crt-cpp/source/io/EventLoopGroup.cpp
new file mode 100644
index 0000000000..000c08513b
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/source/io/EventLoopGroup.cpp
@@ -0,0 +1,71 @@
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+#include <aws/crt/io/EventLoopGroup.h>
+#include <iostream>
+
+namespace Aws
+{
+ namespace Crt
+ {
+ namespace Io
+ {
+ EventLoopGroup::EventLoopGroup(uint16_t threadCount, Allocator *allocator) noexcept
+ : m_eventLoopGroup(nullptr), m_lastError(AWS_ERROR_SUCCESS)
+ {
+ m_eventLoopGroup = aws_event_loop_group_new_default(allocator, threadCount, NULL);
+ if (m_eventLoopGroup == nullptr)
+ {
+ m_lastError = aws_last_error();
+ }
+ }
+
+ EventLoopGroup::EventLoopGroup(uint16_t cpuGroup, uint16_t threadCount, Allocator *allocator) noexcept
+ : m_eventLoopGroup(nullptr), m_lastError(AWS_ERROR_SUCCESS)
+ {
+ m_eventLoopGroup =
+ aws_event_loop_group_new_default_pinned_to_cpu_group(allocator, threadCount, cpuGroup, NULL);
+ if (m_eventLoopGroup == nullptr)
+ {
+ m_lastError = aws_last_error();
+ }
+ }
+
+ EventLoopGroup::~EventLoopGroup() { aws_event_loop_group_release(m_eventLoopGroup); }
+
+ EventLoopGroup::EventLoopGroup(EventLoopGroup &&toMove) noexcept
+ : m_eventLoopGroup(toMove.m_eventLoopGroup), m_lastError(toMove.m_lastError)
+ {
+ toMove.m_lastError = AWS_ERROR_UNKNOWN;
+ toMove.m_eventLoopGroup = nullptr;
+ }
+
+ EventLoopGroup &EventLoopGroup::operator=(EventLoopGroup &&toMove) noexcept
+ {
+ m_eventLoopGroup = toMove.m_eventLoopGroup;
+ m_lastError = toMove.m_lastError;
+ toMove.m_lastError = AWS_ERROR_UNKNOWN;
+ toMove.m_eventLoopGroup = nullptr;
+
+ return *this;
+ }
+
+ int EventLoopGroup::LastError() const { return m_lastError; }
+
+ EventLoopGroup::operator bool() const { return m_lastError == AWS_ERROR_SUCCESS; }
+
+ aws_event_loop_group *EventLoopGroup::GetUnderlyingHandle() noexcept
+ {
+ if (*this)
+ {
+ return m_eventLoopGroup;
+ }
+
+ return nullptr;
+ }
+
+ } // namespace Io
+
+ } // namespace Crt
+} // namespace Aws
diff --git a/contrib/restricted/aws/aws-crt-cpp/source/io/HostResolver.cpp b/contrib/restricted/aws/aws-crt-cpp/source/io/HostResolver.cpp
new file mode 100644
index 0000000000..18173fc413
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/source/io/HostResolver.cpp
@@ -0,0 +1,121 @@
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+#include <aws/crt/io/HostResolver.h>
+
+#include <aws/crt/io/EventLoopGroup.h>
+
+#include <aws/common/string.h>
+#include <aws/crt/Api.h>
+
+namespace Aws
+{
+ namespace Crt
+ {
+ namespace Io
+ {
+ HostResolver::~HostResolver() {}
+
+ DefaultHostResolver::DefaultHostResolver(
+ EventLoopGroup &elGroup,
+ size_t maxHosts,
+ size_t maxTTL,
+ Allocator *allocator) noexcept
+ : m_resolver(nullptr), m_allocator(allocator), m_initialized(false)
+ {
+ AWS_ZERO_STRUCT(m_config);
+
+ struct aws_host_resolver_default_options resolver_options;
+ AWS_ZERO_STRUCT(resolver_options);
+ resolver_options.max_entries = maxHosts;
+ resolver_options.el_group = elGroup.GetUnderlyingHandle();
+
+ m_resolver = aws_host_resolver_new_default(allocator, &resolver_options);
+ if (m_resolver != nullptr)
+ {
+ m_initialized = true;
+ }
+
+ m_config.impl = aws_default_dns_resolve;
+ m_config.impl_data = nullptr;
+ m_config.max_ttl = maxTTL;
+ }
+
+ DefaultHostResolver::DefaultHostResolver(size_t maxHosts, size_t maxTTL, Allocator *allocator) noexcept
+ : DefaultHostResolver(
+ *Crt::ApiHandle::GetOrCreateStaticDefaultEventLoopGroup(),
+ maxHosts,
+ maxTTL,
+ allocator)
+ {
+ }
+
+ DefaultHostResolver::~DefaultHostResolver()
+ {
+ aws_host_resolver_release(m_resolver);
+ m_initialized = false;
+ }
+
+ /**
+ * @private
+ */
+ struct DefaultHostResolveArgs
+ {
+ Allocator *allocator;
+ HostResolver *resolver;
+ OnHostResolved onResolved;
+ aws_string *host;
+ };
+
+ void DefaultHostResolver::s_onHostResolved(
+ struct aws_host_resolver *,
+ const struct aws_string *hostName,
+ int errCode,
+ const struct aws_array_list *hostAddresses,
+ void *userData)
+ {
+ DefaultHostResolveArgs *args = static_cast<DefaultHostResolveArgs *>(userData);
+
+ size_t len = aws_array_list_length(hostAddresses);
+ Vector<HostAddress> addresses;
+
+ for (size_t i = 0; i < len; ++i)
+ {
+ HostAddress *address_ptr = NULL;
+ aws_array_list_get_at_ptr(hostAddresses, reinterpret_cast<void **>(&address_ptr), i);
+ addresses.push_back(*address_ptr);
+ }
+
+ String host(aws_string_c_str(hostName), hostName->len);
+ args->onResolved(*args->resolver, addresses, errCode);
+ aws_string_destroy(args->host);
+ Delete(args, args->allocator);
+ }
+
+ bool DefaultHostResolver::ResolveHost(const String &host, const OnHostResolved &onResolved) noexcept
+ {
+ DefaultHostResolveArgs *args = New<DefaultHostResolveArgs>(m_allocator);
+ if (!args)
+ {
+ return false;
+ }
+
+ args->host = aws_string_new_from_array(
+ m_allocator, reinterpret_cast<const uint8_t *>(host.data()), host.length());
+ args->onResolved = onResolved;
+ args->resolver = this;
+ args->allocator = m_allocator;
+
+ if (!args->host ||
+ aws_host_resolver_resolve_host(m_resolver, args->host, s_onHostResolved, &m_config, args))
+ {
+ Delete(args, m_allocator);
+ return false;
+ }
+
+ return true;
+ }
+ } // namespace Io
+ } // namespace Crt
+} // namespace Aws
diff --git a/contrib/restricted/aws/aws-crt-cpp/source/io/Pkcs11.cpp b/contrib/restricted/aws/aws-crt-cpp/source/io/Pkcs11.cpp
new file mode 100644
index 0000000000..6e71287387
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/source/io/Pkcs11.cpp
@@ -0,0 +1,69 @@
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+#include <aws/crt/io/Pkcs11.h>
+
+#include <aws/io/logging.h>
+#include <aws/io/pkcs11.h>
+
+namespace Aws
+{
+ namespace Crt
+ {
+ namespace Io
+ {
+ std::shared_ptr<Pkcs11Lib> Pkcs11Lib::Create(const String &filename, Allocator *allocator)
+ {
+ return Create(filename, InitializeFinalizeBehavior::Default, allocator);
+ }
+
+ std::shared_ptr<Pkcs11Lib> Pkcs11Lib::Create(
+ const String &filename,
+ InitializeFinalizeBehavior initializeFinalizeBehavior,
+ Allocator *allocator)
+ {
+ aws_pkcs11_lib_options options;
+ AWS_ZERO_STRUCT(options);
+
+ if (!filename.empty())
+ {
+ options.filename = ByteCursorFromString(filename);
+ }
+
+ switch (initializeFinalizeBehavior)
+ {
+ case InitializeFinalizeBehavior::Default:
+ options.initialize_finalize_behavior = AWS_PKCS11_LIB_DEFAULT_BEHAVIOR;
+ break;
+ case InitializeFinalizeBehavior::Omit:
+ options.initialize_finalize_behavior = AWS_PKCS11_LIB_OMIT_INITIALIZE;
+ break;
+ case InitializeFinalizeBehavior::Strict:
+ options.initialize_finalize_behavior = AWS_PKCS11_LIB_STRICT_INITIALIZE_FINALIZE;
+ break;
+ default:
+ AWS_LOGF_ERROR(
+ AWS_LS_IO_PKCS11,
+ "Cannot create Pkcs11Lib. Invalid InitializeFinalizeBehavior %d",
+ (int)initializeFinalizeBehavior);
+ aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
+ return nullptr;
+ }
+
+ struct aws_pkcs11_lib *impl = aws_pkcs11_lib_new(allocator, &options);
+ if (impl == nullptr)
+ {
+ return nullptr;
+ }
+
+ return MakeShared<Pkcs11Lib>(allocator, *impl);
+ }
+
+ Pkcs11Lib::Pkcs11Lib(aws_pkcs11_lib &impl) : impl(&impl) {}
+
+ Pkcs11Lib::~Pkcs11Lib() { aws_pkcs11_lib_release(impl); }
+
+ } // namespace Io
+ } // namespace Crt
+} // namespace Aws
diff --git a/contrib/restricted/aws/aws-crt-cpp/source/io/SocketOptions.cpp b/contrib/restricted/aws/aws-crt-cpp/source/io/SocketOptions.cpp
new file mode 100644
index 0000000000..339b81c087
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/source/io/SocketOptions.cpp
@@ -0,0 +1,28 @@
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+#include <aws/crt/io/SocketOptions.h>
+
+namespace Aws
+{
+ namespace Crt
+ {
+ namespace Io
+ {
+
+ static const uint32_t DEFAULT_SOCKET_TIME_MSEC = 3000;
+
+ SocketOptions::SocketOptions()
+ {
+ options.type = AWS_SOCKET_STREAM;
+ options.domain = AWS_SOCKET_IPV4;
+ options.connect_timeout_ms = DEFAULT_SOCKET_TIME_MSEC;
+ options.keep_alive_max_failed_probes = 0;
+ options.keep_alive_timeout_sec = 0;
+ options.keep_alive_interval_sec = 0;
+ options.keepalive = false;
+ }
+ } // namespace Io
+ } // namespace Crt
+} // namespace Aws
diff --git a/contrib/restricted/aws/aws-crt-cpp/source/io/Stream.cpp b/contrib/restricted/aws/aws-crt-cpp/source/io/Stream.cpp
new file mode 100644
index 0000000000..cf3d6d1cf6
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/source/io/Stream.cpp
@@ -0,0 +1,211 @@
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+
+#include <aws/crt/StlAllocator.h>
+#include <aws/crt/io/Stream.h>
+
+#include <aws/io/stream.h>
+
+namespace Aws
+{
+ namespace Crt
+ {
+ namespace Io
+ {
+ InputStream::~InputStream()
+ {
+ // DO NOTHING: for now. But keep this here because it has to be virtual, and we may have
+ // resources to clean up in the future.
+ }
+
+ int InputStream::s_Seek(aws_input_stream *stream, int64_t offset, enum aws_stream_seek_basis basis)
+ {
+ auto impl = static_cast<InputStream *>(stream->impl);
+
+ // Detect whether implementation raises an error when reporting failure.
+ // Docs for C++ SeekImpl API say you "SHOULD" raise an error,
+ // but the C API does in fact require an error to be raised.
+ aws_reset_error();
+
+ if (impl->SeekImpl(offset, static_cast<StreamSeekBasis>(basis)))
+ {
+ return AWS_OP_SUCCESS;
+ }
+
+ if (aws_last_error() == 0)
+ {
+ aws_raise_error(AWS_IO_STREAM_SEEK_FAILED);
+ }
+
+ return AWS_OP_ERR;
+ }
+
+ int InputStream::s_Read(aws_input_stream *stream, aws_byte_buf *dest)
+ {
+ auto impl = static_cast<InputStream *>(stream->impl);
+
+ // Detect whether implementation raises an error when reporting failure.
+ // Docs for C++ ReadImpl API say you "SHOULD" raise an error,
+ // but the C API does in fact require an error to be raised.
+ aws_reset_error();
+
+ if (impl->ReadImpl(*dest))
+ {
+ return AWS_OP_SUCCESS;
+ }
+
+ if (aws_last_error() == 0)
+ {
+ aws_raise_error(AWS_IO_STREAM_READ_FAILED);
+ }
+
+ return AWS_OP_ERR;
+ }
+
+ int InputStream::s_GetStatus(aws_input_stream *stream, aws_stream_status *status)
+ {
+ auto impl = static_cast<InputStream *>(stream->impl);
+
+ *status = impl->GetStatusImpl();
+ return AWS_OP_SUCCESS;
+ }
+
+ int InputStream::s_GetLength(struct aws_input_stream *stream, int64_t *out_length)
+ {
+ auto impl = static_cast<InputStream *>(stream->impl);
+
+ int64_t length = impl->GetLengthImpl();
+
+ if (length >= 0)
+ {
+ *out_length = length;
+ return AWS_OP_SUCCESS;
+ }
+
+ aws_raise_error(AWS_IO_STREAM_READ_FAILED);
+ return AWS_OP_ERR;
+ }
+
+ void InputStream::s_Acquire(aws_input_stream *stream)
+ {
+ auto impl = static_cast<InputStream *>(stream->impl);
+ impl->AcquireRef();
+ }
+
+ void InputStream::s_Release(aws_input_stream *stream)
+ {
+ auto impl = static_cast<InputStream *>(stream->impl);
+ impl->ReleaseRef();
+ }
+
+ aws_input_stream_vtable InputStream::s_vtable = {
+ InputStream::s_Seek,
+ InputStream::s_Read,
+ InputStream::s_GetStatus,
+ InputStream::s_GetLength,
+ InputStream::s_Acquire,
+ InputStream::s_Release,
+ };
+
+ InputStream::InputStream(Aws::Crt::Allocator *allocator)
+ {
+ m_allocator = allocator;
+ AWS_ZERO_STRUCT(m_underlying_stream);
+
+ m_underlying_stream.impl = this;
+ m_underlying_stream.vtable = &s_vtable;
+ }
+
+ StdIOStreamInputStream::StdIOStreamInputStream(
+ std::shared_ptr<Aws::Crt::Io::IStream> stream,
+ Aws::Crt::Allocator *allocator) noexcept
+ : InputStream(allocator), m_stream(std::move(stream))
+ {
+ }
+
+ bool StdIOStreamInputStream::IsValid() const noexcept
+ {
+ auto status = GetStatusImpl();
+ return status.is_valid;
+ }
+
+ bool StdIOStreamInputStream::ReadImpl(ByteBuf &buffer) noexcept
+ {
+ // so this blocks, but readsome() doesn't work at all, so this is the best we've got.
+ // if you don't like this, don't use std::input_stream and implement your own version
+ // of Aws::Crt::Io::InputStream.
+ m_stream->read(reinterpret_cast<char *>(buffer.buffer + buffer.len), buffer.capacity - buffer.len);
+ auto read = m_stream->gcount();
+ buffer.len += static_cast<size_t>(read);
+
+ if (read > 0 || (read == 0 && m_stream->eof()))
+ {
+ return true;
+ }
+
+ auto status = GetStatusImpl();
+
+ return status.is_valid && !status.is_end_of_stream;
+ }
+
+ StreamStatus StdIOStreamInputStream::GetStatusImpl() const noexcept
+ {
+ StreamStatus status;
+ status.is_end_of_stream = m_stream->eof();
+ status.is_valid = static_cast<bool>(*m_stream);
+
+ return status;
+ }
+
+ int64_t StdIOStreamInputStream::GetLengthImpl() const noexcept
+ {
+ auto currentPosition = m_stream->tellg();
+
+ m_stream->seekg(0, std::ios_base::end);
+ int64_t retVal = -1;
+
+ if (*m_stream)
+ {
+ retVal = static_cast<int64_t>(m_stream->tellg());
+ }
+
+ m_stream->seekg(currentPosition);
+
+ return retVal;
+ }
+
+ bool StdIOStreamInputStream::SeekImpl(int64_t offset, StreamSeekBasis seekBasis) noexcept
+ {
+ // very important, otherwise the stream can't be reused after reading the entire stream the first time.
+ m_stream->clear();
+
+ auto seekDir = std::ios_base::beg;
+ switch (seekBasis)
+ {
+ case StreamSeekBasis::Begin:
+ seekDir = std::ios_base::beg;
+ break;
+ case StreamSeekBasis::End:
+ seekDir = std::ios_base::end;
+ break;
+ default:
+ aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
+ return false;
+ }
+
+ using stdOffType = Aws::Crt::Io::IStream::off_type;
+ if (offset < std::numeric_limits<stdOffType>::min() || offset > std::numeric_limits<stdOffType>::max())
+ {
+ aws_raise_error(AWS_IO_STREAM_INVALID_SEEK_POSITION);
+ return false;
+ }
+
+ m_stream->seekg(static_cast<stdOffType>(offset), seekDir);
+
+ return true;
+ }
+ } // namespace Io
+ } // namespace Crt
+} // namespace Aws
diff --git a/contrib/restricted/aws/aws-crt-cpp/source/io/TlsOptions.cpp b/contrib/restricted/aws/aws-crt-cpp/source/io/TlsOptions.cpp
new file mode 100644
index 0000000000..6077912c9a
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/source/io/TlsOptions.cpp
@@ -0,0 +1,520 @@
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+#include <aws/crt/io/TlsOptions.h>
+
+#include <aws/crt/io/Pkcs11.h>
+
+#include <aws/crt/Api.h>
+#include <aws/io/logging.h>
+#include <aws/io/tls_channel_handler.h>
+
+namespace Aws
+{
+ namespace Crt
+ {
+ namespace Io
+ {
+ TlsContextOptions::~TlsContextOptions()
+ {
+ if (m_isInit)
+ {
+ aws_tls_ctx_options_clean_up(&m_options);
+ }
+ }
+
+ TlsContextOptions::TlsContextOptions() noexcept : m_isInit(false) { AWS_ZERO_STRUCT(m_options); }
+
+ TlsContextOptions::TlsContextOptions(TlsContextOptions &&other) noexcept
+ {
+ m_options = other.m_options;
+ m_isInit = other.m_isInit;
+ AWS_ZERO_STRUCT(other.m_options);
+ other.m_isInit = false;
+ }
+
+ TlsContextOptions &TlsContextOptions::operator=(TlsContextOptions &&other) noexcept
+ {
+ if (&other != this)
+ {
+ if (m_isInit)
+ {
+ aws_tls_ctx_options_clean_up(&m_options);
+ }
+
+ m_options = other.m_options;
+ m_isInit = other.m_isInit;
+ AWS_ZERO_STRUCT(other.m_options);
+ other.m_isInit = false;
+ }
+
+ return *this;
+ }
+
+ TlsContextOptions TlsContextOptions::InitDefaultClient(Allocator *allocator) noexcept
+ {
+ TlsContextOptions ctxOptions;
+ aws_tls_ctx_options_init_default_client(&ctxOptions.m_options, allocator);
+ ctxOptions.m_isInit = true;
+ return ctxOptions;
+ }
+
+ TlsContextOptions TlsContextOptions::InitClientWithMtls(
+ const char *certPath,
+ const char *pKeyPath,
+ Allocator *allocator) noexcept
+ {
+ TlsContextOptions ctxOptions;
+ if (!aws_tls_ctx_options_init_client_mtls_from_path(
+ &ctxOptions.m_options, allocator, certPath, pKeyPath))
+ {
+ ctxOptions.m_isInit = true;
+ }
+ return ctxOptions;
+ }
+
+ TlsContextOptions TlsContextOptions::InitClientWithMtls(
+ const ByteCursor &cert,
+ const ByteCursor &pkey,
+ Allocator *allocator) noexcept
+ {
+ TlsContextOptions ctxOptions;
+ if (!aws_tls_ctx_options_init_client_mtls(
+ &ctxOptions.m_options,
+ allocator,
+ const_cast<ByteCursor *>(&cert),
+ const_cast<ByteCursor *>(&pkey)))
+ {
+ ctxOptions.m_isInit = true;
+ }
+ return ctxOptions;
+ }
+
+ TlsContextOptions TlsContextOptions::InitClientWithMtlsPkcs11(
+ const TlsContextPkcs11Options &pkcs11Options,
+ Allocator *allocator) noexcept
+ {
+ TlsContextOptions ctxOptions;
+ aws_tls_ctx_pkcs11_options nativePkcs11Options = pkcs11Options.GetUnderlyingHandle();
+ if (!aws_tls_ctx_options_init_client_mtls_with_pkcs11(
+ &ctxOptions.m_options, allocator, &nativePkcs11Options))
+ {
+ ctxOptions.m_isInit = true;
+ }
+ return ctxOptions;
+ }
+
+ TlsContextOptions TlsContextOptions::InitClientWithMtlsPkcs12(
+ const char *pkcs12Path,
+ const char *pkcs12Pwd,
+ Allocator *allocator) noexcept
+ {
+ TlsContextOptions ctxOptions;
+ struct aws_byte_cursor password = aws_byte_cursor_from_c_str(pkcs12Pwd);
+ if (!aws_tls_ctx_options_init_client_mtls_pkcs12_from_path(
+ &ctxOptions.m_options, allocator, pkcs12Path, &password))
+ {
+ ctxOptions.m_isInit = true;
+ }
+ return ctxOptions;
+ }
+
+ bool TlsContextOptions::SetKeychainPath(ByteCursor &keychain_path) noexcept
+ {
+ AWS_ASSERT(m_isInit);
+ return aws_tls_ctx_options_set_keychain_path(&m_options, &keychain_path) == 0;
+ }
+
+ TlsContextOptions TlsContextOptions::InitClientWithMtlsSystemPath(
+ const char *windowsCertStorePath,
+ Allocator *allocator) noexcept
+ {
+ TlsContextOptions ctxOptions;
+ if (!aws_tls_ctx_options_init_client_mtls_from_system_path(
+ &ctxOptions.m_options, allocator, windowsCertStorePath))
+ {
+ ctxOptions.m_isInit = true;
+ }
+ return ctxOptions;
+ }
+
+ int TlsContextOptions::LastError() const noexcept { return LastErrorOrUnknown(); }
+
+ bool TlsContextOptions::IsAlpnSupported() noexcept { return aws_tls_is_alpn_available(); }
+
+ bool TlsContextOptions::SetAlpnList(const char *alpn_list) noexcept
+ {
+ AWS_ASSERT(m_isInit);
+ return aws_tls_ctx_options_set_alpn_list(&m_options, alpn_list) == 0;
+ }
+
+ void TlsContextOptions::SetVerifyPeer(bool verify_peer) noexcept
+ {
+ AWS_ASSERT(m_isInit);
+ aws_tls_ctx_options_set_verify_peer(&m_options, verify_peer);
+ }
+
+ void TlsContextOptions::SetMinimumTlsVersion(aws_tls_versions minimumTlsVersion)
+ {
+ AWS_ASSERT(m_isInit);
+ aws_tls_ctx_options_set_minimum_tls_version(&m_options, minimumTlsVersion);
+ }
+
+ void TlsContextOptions::SetTlsCipherPreference(aws_tls_cipher_pref cipher_pref)
+ {
+ AWS_ASSERT(m_isInit);
+ aws_tls_ctx_options_set_tls_cipher_preference(&m_options, cipher_pref);
+ }
+
+ bool TlsContextOptions::OverrideDefaultTrustStore(const char *caPath, const char *caFile) noexcept
+ {
+ AWS_ASSERT(m_isInit);
+ return aws_tls_ctx_options_override_default_trust_store_from_path(&m_options, caPath, caFile) == 0;
+ }
+
+ bool TlsContextOptions::OverrideDefaultTrustStore(const ByteCursor &ca) noexcept
+ {
+ AWS_ASSERT(m_isInit);
+ return aws_tls_ctx_options_override_default_trust_store(&m_options, const_cast<ByteCursor *>(&ca)) == 0;
+ }
+
+ TlsContextPkcs11Options::TlsContextPkcs11Options(
+ const std::shared_ptr<Pkcs11Lib> &pkcs11Lib,
+ Allocator *) noexcept
+ : m_pkcs11Lib{pkcs11Lib}
+ {
+ }
+
+ void TlsContextPkcs11Options::SetUserPin(const String &pin) noexcept { m_userPin = pin; }
+
+ void TlsContextPkcs11Options::SetSlotId(const uint64_t id) noexcept { m_slotId = id; }
+
+ void TlsContextPkcs11Options::SetTokenLabel(const String &label) noexcept { m_tokenLabel = label; }
+
+ void TlsContextPkcs11Options::SetPrivateKeyObjectLabel(const String &label) noexcept
+ {
+ m_privateKeyObjectLabel = label;
+ }
+
+ void TlsContextPkcs11Options::SetCertificateFilePath(const String &path) noexcept
+ {
+ m_certificateFilePath = path;
+ }
+
+ void TlsContextPkcs11Options::SetCertificateFileContents(const String &contents) noexcept
+ {
+ m_certificateFileContents = contents;
+ }
+
+ aws_tls_ctx_pkcs11_options TlsContextPkcs11Options::GetUnderlyingHandle() const noexcept
+ {
+ aws_tls_ctx_pkcs11_options options;
+ AWS_ZERO_STRUCT(options);
+
+ if (m_pkcs11Lib)
+ {
+ options.pkcs11_lib = m_pkcs11Lib->GetNativeHandle();
+ }
+
+ if (m_slotId)
+ {
+ options.slot_id = &(*m_slotId);
+ }
+
+ if (m_userPin)
+ {
+ options.user_pin = ByteCursorFromString(*m_userPin);
+ }
+
+ if (m_tokenLabel)
+ {
+ options.token_label = ByteCursorFromString(*m_tokenLabel);
+ }
+
+ if (m_privateKeyObjectLabel)
+ {
+ options.private_key_object_label = ByteCursorFromString(*m_privateKeyObjectLabel);
+ }
+
+ if (m_certificateFilePath)
+ {
+ options.cert_file_path = ByteCursorFromString(*m_certificateFilePath);
+ }
+
+ if (m_certificateFileContents)
+ {
+ options.cert_file_contents = ByteCursorFromString(*m_certificateFileContents);
+ }
+
+ return options;
+ }
+
+ TlsConnectionOptions::TlsConnectionOptions() noexcept : m_lastError(AWS_ERROR_SUCCESS), m_isInit(false) {}
+
+ TlsConnectionOptions::TlsConnectionOptions(aws_tls_ctx *ctx, Allocator *allocator) noexcept
+ : m_allocator(allocator), m_lastError(AWS_ERROR_SUCCESS), m_isInit(true)
+ {
+ aws_tls_connection_options_init_from_ctx(&m_tls_connection_options, ctx);
+ }
+
+ TlsConnectionOptions::~TlsConnectionOptions()
+ {
+ if (m_isInit)
+ {
+ aws_tls_connection_options_clean_up(&m_tls_connection_options);
+ m_isInit = false;
+ }
+ }
+
+ TlsConnectionOptions::TlsConnectionOptions(const TlsConnectionOptions &options) noexcept
+ {
+ m_isInit = false;
+ AWS_ZERO_STRUCT(m_tls_connection_options);
+
+ if (options.m_isInit)
+ {
+ m_allocator = options.m_allocator;
+
+ if (!aws_tls_connection_options_copy(&m_tls_connection_options, &options.m_tls_connection_options))
+ {
+ m_isInit = true;
+ }
+ else
+ {
+ m_lastError = LastErrorOrUnknown();
+ }
+ }
+ }
+
+ TlsConnectionOptions &TlsConnectionOptions::operator=(const TlsConnectionOptions &options) noexcept
+ {
+ if (this != &options)
+ {
+ if (m_isInit)
+ {
+ aws_tls_connection_options_clean_up(&m_tls_connection_options);
+ }
+
+ m_isInit = false;
+ AWS_ZERO_STRUCT(m_tls_connection_options);
+
+ if (options.m_isInit)
+ {
+ m_allocator = options.m_allocator;
+ if (!aws_tls_connection_options_copy(
+ &m_tls_connection_options, &options.m_tls_connection_options))
+ {
+ m_isInit = true;
+ }
+ else
+ {
+ m_lastError = LastErrorOrUnknown();
+ }
+ }
+ }
+
+ return *this;
+ }
+
+ TlsConnectionOptions::TlsConnectionOptions(TlsConnectionOptions &&options) noexcept
+ : m_isInit(options.m_isInit)
+ {
+ if (options.m_isInit)
+ {
+ m_tls_connection_options = options.m_tls_connection_options;
+ m_allocator = options.m_allocator;
+ AWS_ZERO_STRUCT(options.m_tls_connection_options);
+ options.m_isInit = false;
+ }
+ }
+
+ TlsConnectionOptions &TlsConnectionOptions::operator=(TlsConnectionOptions &&options) noexcept
+ {
+ if (this != &options)
+ {
+ if (m_isInit)
+ {
+ aws_tls_connection_options_clean_up(&m_tls_connection_options);
+ }
+
+ m_isInit = false;
+
+ if (options.m_isInit)
+ {
+ m_tls_connection_options = options.m_tls_connection_options;
+ AWS_ZERO_STRUCT(options.m_tls_connection_options);
+ options.m_isInit = false;
+ m_isInit = true;
+ m_allocator = options.m_allocator;
+ }
+ }
+
+ return *this;
+ }
+
+ bool TlsConnectionOptions::SetServerName(ByteCursor &serverName) noexcept
+ {
+ if (!isValid())
+ {
+ m_lastError = LastErrorOrUnknown();
+ return false;
+ }
+
+ if (aws_tls_connection_options_set_server_name(&m_tls_connection_options, m_allocator, &serverName))
+ {
+ m_lastError = LastErrorOrUnknown();
+ return false;
+ }
+
+ return true;
+ }
+
+ bool TlsConnectionOptions::SetAlpnList(const char *alpnList) noexcept
+ {
+ if (!isValid())
+ {
+ m_lastError = LastErrorOrUnknown();
+ return false;
+ }
+
+ if (aws_tls_connection_options_set_alpn_list(&m_tls_connection_options, m_allocator, alpnList))
+ {
+ m_lastError = LastErrorOrUnknown();
+ return false;
+ }
+
+ return true;
+ }
+
+ TlsContext::TlsContext() noexcept : m_ctx(nullptr), m_initializationError(AWS_ERROR_SUCCESS) {}
+
+ TlsContext::TlsContext(TlsContextOptions &options, TlsMode mode, Allocator *allocator) noexcept
+ : m_ctx(nullptr), m_initializationError(AWS_ERROR_SUCCESS)
+ {
+#if BYO_CRYPTO
+ if (!ApiHandle::GetBYOCryptoNewTlsContextImplCallback() ||
+ !ApiHandle::GetBYOCryptoDeleteTlsContextImplCallback())
+ {
+ AWS_LOGF_ERROR(
+ AWS_LS_IO_TLS,
+ "Must call ApiHandle::SetBYOCryptoTlsContextCallbacks() before TlsContext can be created");
+ m_initializationError = AWS_IO_TLS_CTX_ERROR;
+ return;
+ }
+
+ void *impl = ApiHandle::GetBYOCryptoNewTlsContextImplCallback()(options, mode, allocator);
+ if (!impl)
+ {
+ AWS_LOGF_ERROR(
+ AWS_LS_IO_TLS, "Creation callback from ApiHandle::SetBYOCryptoTlsContextCallbacks() failed");
+ m_initializationError = AWS_IO_TLS_CTX_ERROR;
+ return;
+ }
+
+ auto underlying_tls_ctx = static_cast<aws_tls_ctx *>(aws_mem_calloc(allocator, 1, sizeof(aws_tls_ctx)));
+ underlying_tls_ctx->alloc = allocator;
+ underlying_tls_ctx->impl = impl;
+
+ aws_ref_count_init(&underlying_tls_ctx->ref_count, underlying_tls_ctx, [](void *userdata) {
+ auto dying_ctx = static_cast<aws_tls_ctx *>(userdata);
+ ApiHandle::GetBYOCryptoDeleteTlsContextImplCallback()(dying_ctx->impl);
+ aws_mem_release(dying_ctx->alloc, dying_ctx);
+ });
+
+ m_ctx.reset(underlying_tls_ctx, aws_tls_ctx_release);
+#else
+ if (mode == TlsMode::CLIENT)
+ {
+ aws_tls_ctx *underlying_tls_ctx = aws_tls_client_ctx_new(allocator, &options.m_options);
+ if (underlying_tls_ctx != nullptr)
+ {
+ m_ctx.reset(underlying_tls_ctx, aws_tls_ctx_release);
+ }
+ }
+ else
+ {
+ aws_tls_ctx *underlying_tls_ctx = aws_tls_server_ctx_new(allocator, &options.m_options);
+ if (underlying_tls_ctx != nullptr)
+ {
+ m_ctx.reset(underlying_tls_ctx, aws_tls_ctx_release);
+ }
+ }
+ if (!m_ctx)
+ {
+ m_initializationError = Aws::Crt::LastErrorOrUnknown();
+ }
+#endif // BYO_CRYPTO
+ }
+
+ TlsConnectionOptions TlsContext::NewConnectionOptions() const noexcept
+ {
+ if (!isValid())
+ {
+ AWS_LOGF_ERROR(
+ AWS_LS_IO_TLS, "Trying to call TlsContext::NewConnectionOptions from an invalid TlsContext.");
+ return TlsConnectionOptions();
+ }
+
+ return TlsConnectionOptions(m_ctx.get(), m_ctx->alloc);
+ }
+
+ TlsChannelHandler::TlsChannelHandler(
+ struct aws_channel_slot *,
+ const struct aws_tls_connection_options &options,
+ Allocator *allocator)
+ : ChannelHandler(allocator)
+ {
+ m_OnNegotiationResult = options.on_negotiation_result;
+ m_userData = options.user_data;
+ aws_byte_buf_init(&m_protocolByteBuf, allocator, 16);
+ }
+
+ TlsChannelHandler::~TlsChannelHandler() { aws_byte_buf_clean_up(&m_protocolByteBuf); }
+
+ void TlsChannelHandler::CompleteTlsNegotiation(int errorCode)
+ {
+ m_OnNegotiationResult(&this->m_handler, GetSlot(), errorCode, m_userData);
+ }
+
+ ClientTlsChannelHandler::ClientTlsChannelHandler(
+ struct aws_channel_slot *slot,
+ const struct aws_tls_connection_options &options,
+ Allocator *allocator)
+ : TlsChannelHandler(slot, options, allocator)
+ {
+ }
+
+ } // namespace Io
+ } // namespace Crt
+} // namespace Aws
+
+#if BYO_CRYPTO
+AWS_EXTERN_C_BEGIN
+
+bool aws_tls_is_alpn_available(void)
+{
+ const auto &callback = Aws::Crt::ApiHandle::GetBYOCryptoIsTlsAlpnSupportedCallback();
+ if (!callback)
+ {
+ AWS_LOGF_ERROR(
+ AWS_LS_IO_TLS, "Must call ApiHandle::SetBYOCryptoTlsContextCallbacks() before ALPN can be queried");
+ return false;
+ }
+ return callback();
+}
+
+struct aws_byte_buf aws_tls_handler_protocol(struct aws_channel_handler *handler)
+{
+ auto *channelHandler = reinterpret_cast<Aws::Crt::Io::ChannelHandler *>(handler->impl);
+ auto *tlsHandler = static_cast<Aws::Crt::Io::TlsChannelHandler *>(channelHandler);
+ Aws::Crt::String protocolString = const_cast<const Aws::Crt::Io::TlsChannelHandler *>(tlsHandler)->GetProtocol();
+
+ tlsHandler->m_protocolByteBuf.len = 0;
+ aws_byte_cursor protocolCursor = Aws::Crt::ByteCursorFromString(protocolString);
+ aws_byte_buf_append_dynamic(&tlsHandler->m_protocolByteBuf, &protocolCursor);
+ return tlsHandler->m_protocolByteBuf;
+}
+
+AWS_EXTERN_C_END
+#endif /* BYO_CRYPTO */
diff --git a/contrib/restricted/aws/aws-crt-cpp/source/io/Uri.cpp b/contrib/restricted/aws/aws-crt-cpp/source/io/Uri.cpp
new file mode 100644
index 0000000000..dd43f3249e
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/source/io/Uri.cpp
@@ -0,0 +1,145 @@
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+#include <aws/crt/io/Uri.h>
+
+namespace Aws
+{
+ namespace Crt
+ {
+ namespace Io
+ {
+ Uri::Uri() noexcept : m_lastError(AWS_ERROR_SUCCESS), m_isInit(false) { AWS_ZERO_STRUCT(m_uri); }
+
+ Uri::~Uri()
+ {
+ if (m_isInit)
+ {
+ aws_uri_clean_up(&m_uri);
+ m_isInit = false;
+ }
+ }
+
+ Uri::Uri(const ByteCursor &cursor, Allocator *allocator) noexcept
+ : m_lastError(AWS_ERROR_SUCCESS), m_isInit(false)
+ {
+ if (!aws_uri_init_parse(&m_uri, allocator, &cursor))
+ {
+ m_isInit = true;
+ }
+ else
+ {
+ m_lastError = aws_last_error();
+ }
+ }
+
+ Uri::Uri(aws_uri_builder_options &builderOptions, Allocator *allocator) noexcept
+ : m_lastError(AWS_ERROR_SUCCESS), m_isInit(false)
+ {
+ if (!aws_uri_init_from_builder_options(&m_uri, allocator, &builderOptions))
+ {
+ m_isInit = true;
+ }
+ else
+ {
+ m_lastError = aws_last_error();
+ }
+ }
+
+ Uri::Uri(const Uri &other) : m_lastError(AWS_ERROR_SUCCESS), m_isInit(false)
+ {
+ if (other.m_isInit)
+ {
+ ByteCursor uriCursor = other.GetFullUri();
+
+ if (!aws_uri_init_parse(&m_uri, other.m_uri.allocator, &uriCursor))
+ {
+ m_isInit = true;
+ }
+ else
+ {
+ m_lastError = aws_last_error();
+ }
+ }
+ }
+
+ Uri &Uri::operator=(const Uri &other)
+ {
+ if (this != &other)
+ {
+ m_isInit = false;
+ m_lastError = AWS_ERROR_SUCCESS;
+
+ if (other.m_isInit)
+ {
+ ByteCursor uriCursor = other.GetFullUri();
+
+ if (!aws_uri_init_parse(&m_uri, other.m_uri.allocator, &uriCursor))
+ {
+ m_isInit = true;
+ }
+ else
+ {
+ m_lastError = aws_last_error();
+ }
+ }
+ }
+
+ return *this;
+ }
+
+ Uri::Uri(Uri &&uri) noexcept : m_lastError(AWS_ERROR_SUCCESS), m_isInit(uri.m_isInit)
+ {
+ if (uri.m_isInit)
+ {
+ m_uri = uri.m_uri;
+ AWS_ZERO_STRUCT(uri.m_uri);
+ uri.m_isInit = false;
+ }
+ }
+
+ Uri &Uri::operator=(Uri &&uri) noexcept
+ {
+ if (this != &uri)
+ {
+ if (m_isInit)
+ {
+ aws_uri_clean_up(&m_uri);
+ }
+
+ if (uri.m_isInit)
+ {
+ m_uri = uri.m_uri;
+ AWS_ZERO_STRUCT(uri.m_uri);
+ uri.m_isInit = false;
+ m_isInit = true;
+ m_lastError = AWS_ERROR_SUCCESS;
+ }
+ else
+ {
+ m_lastError = uri.m_lastError;
+ }
+ }
+
+ return *this;
+ }
+
+ ByteCursor Uri::GetScheme() const noexcept { return m_uri.scheme; }
+
+ ByteCursor Uri::GetAuthority() const noexcept { return m_uri.authority; }
+
+ ByteCursor Uri::GetPath() const noexcept { return m_uri.path; }
+
+ ByteCursor Uri::GetQueryString() const noexcept { return m_uri.query_string; }
+
+ ByteCursor Uri::GetHostName() const noexcept { return m_uri.host_name; }
+
+ uint16_t Uri::GetPort() const noexcept { return m_uri.port; }
+
+ ByteCursor Uri::GetPathAndQuery() const noexcept { return m_uri.path_and_query; }
+
+ ByteCursor Uri::GetFullUri() const noexcept { return ByteCursorFromByteBuf(m_uri.uri_str); }
+ } // namespace Io
+ } // namespace Crt
+} // namespace Aws
diff --git a/contrib/restricted/aws/aws-crt-cpp/source/iot/Mqtt5Client.cpp b/contrib/restricted/aws/aws-crt-cpp/source/iot/Mqtt5Client.cpp
new file mode 100644
index 0000000000..1c69203a40
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/source/iot/Mqtt5Client.cpp
@@ -0,0 +1,641 @@
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+
+#include <aws/crt/Api.h>
+#include <aws/crt/auth/Credentials.h>
+#include <aws/crt/auth/Sigv4Signing.h>
+#include <aws/crt/http/HttpRequestResponse.h>
+#include <aws/crt/mqtt/Mqtt5Packets.h>
+
+#include <aws/iot/Mqtt5Client.h>
+
+#if !BYO_CRYPTO
+
+namespace Aws
+{
+ namespace Iot
+ {
+ static Crt::String AddToUsernameParameter(
+ Crt::String currentUsername,
+ Crt::String parameterValue,
+ Crt::String parameterPreText)
+ {
+ Crt::String return_string = currentUsername;
+ if (return_string.find("?") != Crt::String::npos)
+ {
+ return_string += "&";
+ }
+ else
+ {
+ return_string += "?";
+ }
+
+ if (parameterValue.find(parameterPreText) != Crt::String::npos)
+ {
+ return return_string + parameterValue;
+ }
+ else
+ {
+ return return_string + parameterPreText + parameterValue;
+ }
+ }
+
+ static bool buildMqtt5FinalUsername(
+ Crt::Optional<Mqtt5CustomAuthConfig> customAuthConfig,
+ Crt::String &username)
+ {
+ if (customAuthConfig.has_value())
+ {
+ /* If we're using token-signing authentication, then all token properties must be set */
+ bool usingSigning = false;
+ if (customAuthConfig->GetTokenValue().has_value() || customAuthConfig->GetTokenKeyName().has_value() ||
+ customAuthConfig->GetTokenSignature().has_value())
+ {
+ usingSigning = true;
+ if (!customAuthConfig->GetTokenValue().has_value() ||
+ !customAuthConfig->GetTokenKeyName().has_value() ||
+ !customAuthConfig->GetTokenSignature().has_value())
+ {
+ return false;
+ }
+ }
+ Crt::String usernameString = "";
+
+ if (!customAuthConfig->GetUsername().has_value())
+ {
+ if (!username.empty())
+ {
+ usernameString += username;
+ }
+ }
+ else
+ {
+ usernameString += customAuthConfig->GetUsername().value();
+ }
+
+ if (customAuthConfig->GetAuthorizerName().has_value())
+ {
+ usernameString = AddToUsernameParameter(
+ usernameString, customAuthConfig->GetAuthorizerName().value(), "x-amz-customauthorizer-name=");
+ }
+ if (usingSigning)
+ {
+ usernameString = AddToUsernameParameter(
+ usernameString,
+ customAuthConfig->GetTokenValue().value(),
+ customAuthConfig->GetTokenKeyName().value() + "=");
+ usernameString = AddToUsernameParameter(
+ usernameString,
+ customAuthConfig->GetTokenSignature().value(),
+ "x-amz-customauthorizer-signature=");
+ }
+
+ username = usernameString;
+ }
+ return true;
+ }
+
+ /*****************************************************
+ *
+ * Mqtt5ClientOptionsBuilder
+ *
+ *****************************************************/
+
+ Mqtt5ClientBuilder::Mqtt5ClientBuilder(Crt::Allocator *allocator) noexcept
+ : m_allocator(allocator), m_port(0), m_lastError(0), m_enableMetricsCollection(true)
+ {
+ m_options = new Crt::Mqtt5::Mqtt5ClientOptions(allocator);
+ }
+
+ Mqtt5ClientBuilder::Mqtt5ClientBuilder(int error, Crt::Allocator *allocator) noexcept
+ : m_allocator(allocator), m_options(nullptr), m_lastError(error)
+ {
+ }
+
+ Mqtt5ClientBuilder *Mqtt5ClientBuilder::NewMqtt5ClientBuilderWithMtlsFromPath(
+ const Crt::String hostName,
+ const char *certPath,
+ const char *pkeyPath,
+ Crt::Allocator *allocator) noexcept
+ {
+ Mqtt5ClientBuilder *result = new Mqtt5ClientBuilder(allocator);
+ result->m_tlsConnectionOptions =
+ Crt::Io::TlsContextOptions::InitClientWithMtls(certPath, pkeyPath, allocator);
+ if (!result->m_tlsConnectionOptions.value())
+ {
+ result->m_lastError = result->m_tlsConnectionOptions->LastError();
+ return result;
+ }
+ result->withHostName(hostName);
+ return result;
+ }
+
+ Mqtt5ClientBuilder *Mqtt5ClientBuilder::NewMqtt5ClientBuilderWithMtlsFromMemory(
+ const Crt::String hostName,
+ const Crt::ByteCursor &cert,
+ const Crt::ByteCursor &pkey,
+ Crt::Allocator *allocator) noexcept
+ {
+ Mqtt5ClientBuilder *result = new Mqtt5ClientBuilder(allocator);
+ result->m_tlsConnectionOptions = Crt::Io::TlsContextOptions::InitClientWithMtls(cert, pkey, allocator);
+ if (!result->m_tlsConnectionOptions.value())
+ {
+ result->m_lastError = result->m_tlsConnectionOptions->LastError();
+ return result;
+ }
+ result->withHostName(hostName);
+ return result;
+ }
+
+ Mqtt5ClientBuilder *Mqtt5ClientBuilder::NewMqtt5ClientBuilderWithMtlsPkcs11(
+ const Crt::String hostName,
+ const Crt::Io::TlsContextPkcs11Options &pkcs11Options,
+ Crt::Allocator *allocator) noexcept
+ {
+ Mqtt5ClientBuilder *result = new Mqtt5ClientBuilder(allocator);
+ result->m_tlsConnectionOptions =
+ Crt::Io::TlsContextOptions::InitClientWithMtlsPkcs11(pkcs11Options, allocator);
+ if (!result->m_tlsConnectionOptions.value())
+ {
+ result->m_lastError = result->m_tlsConnectionOptions->LastError();
+ return result;
+ }
+ result->withHostName(hostName);
+ return result;
+ }
+
+ Mqtt5ClientBuilder *Mqtt5ClientBuilder::NewMqtt5ClientBuilderWithWindowsCertStorePath(
+ const Crt::String hostName,
+ const char *windowsCertStorePath,
+ Crt::Allocator *allocator) noexcept
+ {
+ Mqtt5ClientBuilder *result = new Mqtt5ClientBuilder(allocator);
+ result->m_tlsConnectionOptions =
+ Crt::Io::TlsContextOptions::InitClientWithMtlsSystemPath(windowsCertStorePath, allocator);
+ if (!result->m_tlsConnectionOptions.value())
+ {
+ result->m_lastError = result->m_tlsConnectionOptions->LastError();
+ return result;
+ }
+ result->withHostName(hostName);
+ return result;
+ }
+
+ Mqtt5ClientBuilder *Mqtt5ClientBuilder::NewMqtt5ClientBuilderWithWebsocket(
+ const Crt::String hostName,
+ const WebsocketConfig &config,
+ Crt::Allocator *allocator) noexcept
+ {
+ Mqtt5ClientBuilder *result = new Mqtt5ClientBuilder(allocator);
+ result->m_tlsConnectionOptions = Crt::Io::TlsContextOptions::InitDefaultClient();
+ result->withHostName(hostName);
+ result->m_websocketConfig = config;
+ return result;
+ }
+
+ Mqtt5ClientBuilder *Mqtt5ClientBuilder::NewMqtt5ClientBuilderWithCustomAuthorizer(
+ const Crt::String hostName,
+ const Mqtt5CustomAuthConfig &customAuthConfig,
+ Crt::Allocator *allocator) noexcept
+ {
+ Mqtt5ClientBuilder *result = new Mqtt5ClientBuilder(allocator);
+ result->m_tlsConnectionOptions = Crt::Io::TlsContextOptions::InitDefaultClient();
+ result->withHostName(hostName);
+ result->WithCustomAuthorizer(customAuthConfig);
+ return result;
+ }
+
+ Mqtt5ClientBuilder *Mqtt5ClientBuilder::NewMqtt5ClientBuilderWithCustomAuthorizerWebsocket(
+ const Crt::String hostName,
+ const Mqtt5CustomAuthConfig &customAuthConfig,
+ const WebsocketConfig &config,
+ Crt::Allocator *allocator) noexcept
+ {
+ Mqtt5ClientBuilder *result = new Mqtt5ClientBuilder(allocator);
+ result->m_tlsConnectionOptions = Crt::Io::TlsContextOptions::InitDefaultClient();
+ result->withHostName(hostName);
+ result->m_websocketConfig = config;
+ result->WithCustomAuthorizer(customAuthConfig);
+ return result;
+ }
+
+ Mqtt5ClientBuilder &Mqtt5ClientBuilder::withHostName(const Crt::String hostName)
+ {
+ m_options->withHostName(hostName);
+ return *this;
+ }
+
+ Mqtt5ClientBuilder &Mqtt5ClientBuilder::withPort(uint16_t port) noexcept
+ {
+ m_port = port;
+ return *this;
+ }
+
+ Mqtt5ClientBuilder &Mqtt5ClientBuilder::WithCertificateAuthority(const char *caPath) noexcept
+ {
+ if (m_tlsConnectionOptions)
+ {
+ if (!m_tlsConnectionOptions->OverrideDefaultTrustStore(nullptr, caPath))
+ {
+ m_lastError = m_tlsConnectionOptions->LastError();
+ }
+ }
+ return *this;
+ }
+
+ Mqtt5ClientBuilder &Mqtt5ClientBuilder::WithCertificateAuthority(const Crt::ByteCursor &cert) noexcept
+ {
+ if (m_tlsConnectionOptions)
+ {
+ if (!m_tlsConnectionOptions->OverrideDefaultTrustStore(cert))
+ {
+ m_lastError = m_tlsConnectionOptions->LastError();
+ }
+ }
+ return *this;
+ }
+
+ Mqtt5ClientBuilder &Mqtt5ClientBuilder::withHttpProxyOptions(
+ const Crt::Http::HttpClientConnectionProxyOptions &proxyOptions) noexcept
+ {
+ m_proxyOptions = proxyOptions;
+ return *this;
+ }
+
+ Mqtt5ClientBuilder &Mqtt5ClientBuilder::WithCustomAuthorizer(const Iot::Mqtt5CustomAuthConfig &config) noexcept
+ {
+ m_customAuthConfig = config;
+ return *this;
+ }
+
+ Mqtt5ClientBuilder &Mqtt5ClientBuilder::withConnectOptions(
+ std::shared_ptr<ConnectPacket> packetConnect) noexcept
+ {
+ m_connectOptions = packetConnect;
+ return *this;
+ }
+
+ Mqtt5ClientBuilder &Mqtt5ClientBuilder::withSessionBehavior(ClientSessionBehaviorType sessionBehavior) noexcept
+ {
+ m_options->withSessionBehavior(sessionBehavior);
+ return *this;
+ }
+
+ Mqtt5ClientBuilder &Mqtt5ClientBuilder::withClientExtendedValidationAndFlowControl(
+ ClientExtendedValidationAndFlowControl clientExtendedValidationAndFlowControl) noexcept
+ {
+ m_options->withClientExtendedValidationAndFlowControl(clientExtendedValidationAndFlowControl);
+ return *this;
+ }
+
+ Mqtt5ClientBuilder &Mqtt5ClientBuilder::withOfflineQueueBehavior(
+ ClientOperationQueueBehaviorType operationQueueBehavior) noexcept
+ {
+ m_options->withAckTimeoutSeconds(operationQueueBehavior);
+ return *this;
+ }
+
+ Mqtt5ClientBuilder &Mqtt5ClientBuilder::withReconnectOptions(ReconnectOptions reconnectOptions) noexcept
+ {
+ m_options->withReconnectOptions(reconnectOptions);
+ return *this;
+ }
+
+ Mqtt5ClientBuilder &Mqtt5ClientBuilder::withPingTimeoutMs(uint32_t pingTimeoutMs) noexcept
+ {
+ m_options->withPingTimeoutMs(pingTimeoutMs);
+ return *this;
+ }
+
+ Mqtt5ClientBuilder &Mqtt5ClientBuilder::withConnackTimeoutMs(uint32_t connackTimeoutMs) noexcept
+ {
+ m_options->withConnackTimeoutMs(connackTimeoutMs);
+ return *this;
+ }
+
+ Mqtt5ClientBuilder &Mqtt5ClientBuilder::withAckTimeoutSeconds(uint32_t ackTimeoutSeconds) noexcept
+ {
+ m_options->withAckTimeoutSeconds(ackTimeoutSeconds);
+ return *this;
+ }
+
+ Mqtt5ClientBuilder &Mqtt5ClientBuilder::WithSdkName(const Crt::String &sdkName)
+ {
+ m_sdkName = sdkName;
+ return *this;
+ }
+
+ Mqtt5ClientBuilder &Mqtt5ClientBuilder::WithSdkVersion(const Crt::String &sdkVersion)
+ {
+ m_sdkVersion = sdkVersion;
+ return *this;
+ }
+
+ Mqtt5ClientBuilder &Mqtt5ClientBuilder::withClientConnectionSuccessCallback(
+ OnConnectionSuccessHandler callback) noexcept
+ {
+ m_options->withClientConnectionSuccessCallback(std::move(callback));
+ return *this;
+ }
+
+ Mqtt5ClientBuilder &Mqtt5ClientBuilder::withClientConnectionFailureCallback(
+ OnConnectionFailureHandler callback) noexcept
+ {
+ m_options->withClientConnectionFailureCallback(std::move(callback));
+ return *this;
+ }
+
+ Mqtt5ClientBuilder &Mqtt5ClientBuilder::withClientDisconnectionCallback(
+ OnDisconnectionHandler callback) noexcept
+ {
+ m_options->withClientDisconnectionCallback(std::move(callback));
+ return *this;
+ }
+
+ Mqtt5ClientBuilder &Mqtt5ClientBuilder::withClientStoppedCallback(OnStoppedHandler callback) noexcept
+ {
+ m_options->withClientStoppedCallback(std::move(callback));
+ return *this;
+ }
+
+ Mqtt5ClientBuilder &Mqtt5ClientBuilder::withClientAttemptingConnectCallback(
+ OnAttemptingConnectHandler callback) noexcept
+ {
+ m_options->withClientAttemptingConnectCallback(std::move(callback));
+ return *this;
+ }
+
+ Mqtt5ClientBuilder &Mqtt5ClientBuilder::withPublishReceivedCallback(OnPublishReceivedHandler callback) noexcept
+ {
+ m_options->withPublishReceivedCallback(std::move(callback));
+ return *this;
+ }
+
+ std::shared_ptr<Mqtt5Client> Mqtt5ClientBuilder::Build() noexcept
+ {
+ if (m_lastError != 0)
+ {
+ return nullptr;
+ }
+
+ uint16_t port = m_port;
+
+ if (!port) // port is default to 0
+ {
+ if (m_websocketConfig || Crt::Io::TlsContextOptions::IsAlpnSupported())
+ {
+ port = 443;
+ }
+ else
+ {
+ port = 8883;
+ }
+ }
+
+ if (port == 443 && !m_websocketConfig && Crt::Io::TlsContextOptions::IsAlpnSupported() &&
+ !m_customAuthConfig.has_value())
+ {
+ if (!m_tlsConnectionOptions->SetAlpnList("x-amzn-mqtt-ca"))
+ {
+ return nullptr;
+ }
+ }
+
+ if (m_customAuthConfig.has_value())
+ {
+ if (port != 443)
+ {
+ AWS_LOGF_WARN(
+ AWS_LS_MQTT_GENERAL,
+ "Attempting to connect to authorizer with unsupported port. Port is not 443...");
+ }
+ if (!m_websocketConfig)
+ {
+ if (!m_tlsConnectionOptions->SetAlpnList("mqtt"))
+ {
+ return nullptr;
+ }
+ }
+ }
+
+ // add metrics string to username (if metrics enabled)
+ if (m_enableMetricsCollection || m_customAuthConfig.has_value())
+ {
+ Crt::String username = "";
+ if (m_connectOptions != nullptr)
+ {
+ if (m_connectOptions->getUsername().has_value())
+ username = m_connectOptions->getUsername().value();
+ }
+ else
+ {
+ m_connectOptions = std::make_shared<ConnectPacket>(m_allocator);
+ }
+
+ if (m_customAuthConfig.has_value())
+ {
+ if (!buildMqtt5FinalUsername(m_customAuthConfig, username))
+ {
+ AWS_LOGF_ERROR(
+ AWS_LS_MQTT5_CLIENT,
+ "Failed to setup CustomAuthorizerConfig, please check if the parameters are set "
+ "correctly.");
+ return nullptr;
+ }
+ if (m_customAuthConfig->GetPassword().has_value())
+ {
+ m_connectOptions->withPassword(m_customAuthConfig->GetPassword().value());
+ }
+ }
+
+ if (m_enableMetricsCollection)
+ {
+ username = AddToUsernameParameter(username, "SDK", m_sdkName);
+ username = AddToUsernameParameter(username, "Version", m_sdkName);
+ }
+ m_connectOptions->withUserName(username);
+ }
+
+ auto tlsContext =
+ Crt::Io::TlsContext(m_tlsConnectionOptions.value(), Crt::Io::TlsMode::CLIENT, m_allocator);
+ if (!tlsContext)
+ {
+ return nullptr;
+ }
+
+ m_options->withPort(port).withTlsConnectionOptions(tlsContext.NewConnectionOptions());
+
+ if (m_connectOptions != nullptr)
+ {
+ m_options->withConnectOptions(m_connectOptions);
+ }
+
+ if (m_websocketConfig.has_value())
+ {
+ auto websocketConfig = m_websocketConfig.value();
+ auto signerTransform = [websocketConfig](
+ std::shared_ptr<Crt::Http::HttpRequest> req,
+ const Crt::Mqtt::OnWebSocketHandshakeInterceptComplete &onComplete) {
+ // it is only a very happy coincidence that these function signatures match. This is the callback
+ // for signing to be complete. It invokes the callback for websocket handshake to be complete.
+ auto signingComplete =
+ [onComplete](const std::shared_ptr<Aws::Crt::Http::HttpRequest> &req1, int errorCode) {
+ onComplete(req1, errorCode);
+ };
+
+ auto signerConfig = websocketConfig.CreateSigningConfigCb();
+
+ websocketConfig.Signer->SignRequest(req, *signerConfig, signingComplete);
+ };
+
+ m_options->withWebsocketHandshakeTransformCallback(signerTransform);
+ bool useWebsocketProxyOptions =
+ m_websocketConfig->ProxyOptions.has_value() && !m_proxyOptions.has_value();
+ if (useWebsocketProxyOptions)
+ {
+ m_options->withHttpProxyOptions(m_websocketConfig->ProxyOptions.value());
+ }
+ else if (m_proxyOptions.has_value())
+ {
+ m_options->withHttpProxyOptions(m_proxyOptions.value());
+ }
+ }
+
+ return Crt::Mqtt5::Mqtt5Client::NewMqtt5Client(*m_options, m_allocator);
+ }
+
+ Aws::Iot::Mqtt5CustomAuthConfig::Mqtt5CustomAuthConfig(Crt::Allocator *allocator) noexcept
+ : m_allocator(allocator)
+ {
+ AWS_ZERO_STRUCT(m_passwordStorage);
+ }
+
+ Aws::Iot::Mqtt5CustomAuthConfig::~Mqtt5CustomAuthConfig() { aws_byte_buf_clean_up(&m_passwordStorage); }
+
+ Aws::Iot::Mqtt5CustomAuthConfig::Mqtt5CustomAuthConfig(const Mqtt5CustomAuthConfig &rhs)
+ {
+ if (&rhs != this)
+ {
+ m_allocator = rhs.m_allocator;
+ if (rhs.m_authorizerName.has_value())
+ {
+ m_authorizerName = rhs.m_authorizerName.value();
+ }
+ if (rhs.m_tokenKeyName.has_value())
+ {
+ m_tokenKeyName = rhs.m_tokenKeyName.value();
+ }
+ if (rhs.m_tokenSignature.has_value())
+ {
+ m_tokenSignature = rhs.m_tokenSignature.value();
+ }
+ if (rhs.m_tokenValue.has_value())
+ {
+ m_tokenValue = rhs.m_tokenValue.value();
+ }
+ if (rhs.m_username.has_value())
+ {
+ m_username = rhs.m_username.value();
+ }
+ if (rhs.m_password.has_value())
+ {
+ AWS_ZERO_STRUCT(m_passwordStorage);
+ aws_byte_buf_init_copy_from_cursor(&m_passwordStorage, m_allocator, rhs.m_password.value());
+ m_password = aws_byte_cursor_from_buf(&m_passwordStorage);
+ }
+ }
+ }
+
+ Mqtt5CustomAuthConfig &Aws::Iot::Mqtt5CustomAuthConfig::operator=(const Mqtt5CustomAuthConfig &rhs)
+ {
+ if (&rhs != this)
+ {
+ m_allocator = rhs.m_allocator;
+ if (rhs.m_authorizerName.has_value())
+ {
+ m_authorizerName = rhs.m_authorizerName.value();
+ }
+ if (rhs.m_tokenKeyName.has_value())
+ {
+ m_tokenKeyName = rhs.m_tokenKeyName.value();
+ }
+ if (rhs.m_tokenSignature.has_value())
+ {
+ m_tokenSignature = rhs.m_tokenSignature.value();
+ }
+ if (rhs.m_tokenValue.has_value())
+ {
+ m_tokenValue = rhs.m_tokenValue.value();
+ }
+ if (rhs.m_username.has_value())
+ {
+ m_username = rhs.m_username.value();
+ }
+ if (rhs.m_password.has_value())
+ {
+ aws_byte_buf_clean_up(&m_passwordStorage);
+ AWS_ZERO_STRUCT(m_passwordStorage);
+ aws_byte_buf_init_copy_from_cursor(&m_passwordStorage, m_allocator, rhs.m_password.value());
+ m_password = aws_byte_cursor_from_buf(&m_passwordStorage);
+ }
+ }
+ return *this;
+ }
+
+ const Crt::Optional<Crt::String> &Mqtt5CustomAuthConfig::GetAuthorizerName() { return m_authorizerName; }
+
+ const Crt::Optional<Crt::String> &Mqtt5CustomAuthConfig::GetUsername() { return m_username; }
+
+ const Crt::Optional<Crt::ByteCursor> &Mqtt5CustomAuthConfig::GetPassword() { return m_password; }
+
+ const Crt::Optional<Crt::String> &Mqtt5CustomAuthConfig::GetTokenKeyName() { return m_tokenKeyName; }
+
+ const Crt::Optional<Crt::String> &Mqtt5CustomAuthConfig::GetTokenValue() { return m_tokenValue; }
+
+ const Crt::Optional<Crt::String> &Mqtt5CustomAuthConfig::GetTokenSignature() { return m_tokenSignature; }
+
+ Mqtt5CustomAuthConfig &Aws::Iot::Mqtt5CustomAuthConfig::WithAuthorizerName(Crt::String authName)
+ {
+ m_authorizerName = std::move(authName);
+ return *this;
+ }
+
+ Mqtt5CustomAuthConfig &Aws::Iot::Mqtt5CustomAuthConfig::WithUsername(Crt::String username)
+ {
+ m_username = std::move(username);
+ return *this;
+ }
+
+ Mqtt5CustomAuthConfig &Aws::Iot::Mqtt5CustomAuthConfig::WithPassword(Crt::ByteCursor password)
+ {
+ aws_byte_buf_clean_up(&m_passwordStorage);
+ AWS_ZERO_STRUCT(m_passwordStorage);
+ aws_byte_buf_init_copy_from_cursor(&m_passwordStorage, m_allocator, password);
+ m_password = aws_byte_cursor_from_buf(&m_passwordStorage);
+ return *this;
+ }
+
+ Mqtt5CustomAuthConfig &Aws::Iot::Mqtt5CustomAuthConfig::WithTokenKeyName(Crt::String tokenKeyName)
+ {
+ m_tokenKeyName = std::move(tokenKeyName);
+ return *this;
+ }
+
+ Mqtt5CustomAuthConfig &Aws::Iot::Mqtt5CustomAuthConfig::WithTokenValue(Crt::String tokenValue)
+ {
+ m_tokenValue = std::move(tokenValue);
+ return *this;
+ }
+
+ Mqtt5CustomAuthConfig &Aws::Iot::Mqtt5CustomAuthConfig::WithTokenSignature(Crt::String tokenSignature)
+ {
+ m_tokenSignature = std::move(tokenSignature);
+ return *this;
+ }
+
+ } // namespace Iot
+} // namespace Aws
+
+#endif // !BYO_CRYPTO
diff --git a/contrib/restricted/aws/aws-crt-cpp/source/iot/MqttClient.cpp b/contrib/restricted/aws/aws-crt-cpp/source/iot/MqttClient.cpp
new file mode 100644
index 0000000000..3f80782b3f
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/source/iot/MqttClient.cpp
@@ -0,0 +1,541 @@
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+#include <aws/iot/MqttClient.h>
+
+#include <aws/crt/Api.h>
+#include <aws/crt/auth/Credentials.h>
+#include <aws/crt/auth/Sigv4Signing.h>
+#include <aws/crt/http/HttpRequestResponse.h>
+
+#if !BYO_CRYPTO
+
+namespace Aws
+{
+ namespace Iot
+ {
+
+ MqttClientConnectionConfig::MqttClientConnectionConfig(int lastError) noexcept
+ : m_port(0), m_lastError(lastError)
+ {
+ }
+
+ MqttClientConnectionConfig MqttClientConnectionConfig::CreateInvalid(int lastError) noexcept
+ {
+ return MqttClientConnectionConfig(lastError);
+ }
+
+ MqttClientConnectionConfig::MqttClientConnectionConfig(
+ const Crt::String &endpoint,
+ uint16_t port,
+ const Crt::Io::SocketOptions &socketOptions,
+ Crt::Io::TlsContext &&tlsContext)
+ : m_endpoint(endpoint), m_port(port), m_context(std::move(tlsContext)), m_socketOptions(socketOptions),
+ m_lastError(0)
+ {
+ }
+
+ MqttClientConnectionConfig::MqttClientConnectionConfig(
+ const Crt::String &endpoint,
+ uint16_t port,
+ const Crt::Io::SocketOptions &socketOptions,
+ Crt::Io::TlsContext &&tlsContext,
+ Crt::Mqtt::OnWebSocketHandshakeIntercept &&interceptor,
+ const Crt::Optional<Crt::Http::HttpClientConnectionProxyOptions> &proxyOptions)
+ : m_endpoint(endpoint), m_port(port), m_context(std::move(tlsContext)), m_socketOptions(socketOptions),
+ m_webSocketInterceptor(std::move(interceptor)), m_proxyOptions(proxyOptions), m_lastError(0)
+ {
+ }
+
+ MqttClientConnectionConfig::MqttClientConnectionConfig(
+ const Crt::String &endpoint,
+ uint16_t port,
+ const Crt::Io::SocketOptions &socketOptions,
+ Crt::Io::TlsContext &&tlsContext,
+ const Crt::Optional<Crt::Http::HttpClientConnectionProxyOptions> &proxyOptions)
+ : m_endpoint(endpoint), m_port(port), m_context(std::move(tlsContext)), m_socketOptions(socketOptions),
+ m_proxyOptions(proxyOptions), m_lastError(0)
+ {
+ }
+
+ MqttClientConnectionConfigBuilder::MqttClientConnectionConfigBuilder()
+ : MqttClientConnectionConfigBuilder(Crt::ApiAllocator())
+ {
+ m_lastError = AWS_ERROR_INVALID_STATE;
+ }
+
+ // Common setup shared by all valid constructors
+ MqttClientConnectionConfigBuilder::MqttClientConnectionConfigBuilder(Crt::Allocator *allocator) noexcept
+ : m_allocator(allocator), m_portOverride(0),
+# ifdef AWS_IOT_SDK_VERSION
+ m_sdkVersion(AWS_IOT_SDK_VERSION),
+# else
+ m_sdkVersion(AWS_CRT_CPP_VERSION),
+# endif
+ m_lastError(0)
+ {
+ m_socketOptions.SetConnectTimeoutMs(3000);
+ }
+
+ MqttClientConnectionConfigBuilder::MqttClientConnectionConfigBuilder(
+ const char *certPath,
+ const char *pkeyPath,
+ Crt::Allocator *allocator) noexcept
+ : MqttClientConnectionConfigBuilder(allocator)
+ {
+ m_contextOptions = Crt::Io::TlsContextOptions::InitClientWithMtls(certPath, pkeyPath, allocator);
+ if (!m_contextOptions)
+ {
+ m_lastError = m_contextOptions.LastError();
+ return;
+ }
+ }
+
+ MqttClientConnectionConfigBuilder::MqttClientConnectionConfigBuilder(
+ const Crt::ByteCursor &cert,
+ const Crt::ByteCursor &pkey,
+ Crt::Allocator *allocator) noexcept
+ : MqttClientConnectionConfigBuilder(allocator)
+ {
+ m_contextOptions = Crt::Io::TlsContextOptions::InitClientWithMtls(cert, pkey, allocator);
+ if (!m_contextOptions)
+ {
+ m_lastError = m_contextOptions.LastError();
+ return;
+ }
+ }
+
+ MqttClientConnectionConfigBuilder::MqttClientConnectionConfigBuilder(
+ const Crt::Io::TlsContextPkcs11Options &pkcs11Options,
+ Crt::Allocator *allocator) noexcept
+ : MqttClientConnectionConfigBuilder(allocator)
+ {
+ m_contextOptions = Crt::Io::TlsContextOptions::InitClientWithMtlsPkcs11(pkcs11Options, allocator);
+ if (!m_contextOptions)
+ {
+ m_lastError = m_contextOptions.LastError();
+ return;
+ }
+ }
+
+ MqttClientConnectionConfigBuilder::MqttClientConnectionConfigBuilder(
+ const char *windowsCertStorePath,
+ Crt::Allocator *allocator) noexcept
+ : MqttClientConnectionConfigBuilder(allocator)
+ {
+ m_contextOptions =
+ Crt::Io::TlsContextOptions::InitClientWithMtlsSystemPath(windowsCertStorePath, allocator);
+ if (!m_contextOptions)
+ {
+ m_lastError = m_contextOptions.LastError();
+ return;
+ }
+ }
+
+ MqttClientConnectionConfigBuilder::MqttClientConnectionConfigBuilder(
+ const WebsocketConfig &config,
+ Crt::Allocator *allocator) noexcept
+ : MqttClientConnectionConfigBuilder(allocator)
+ {
+ m_contextOptions = Crt::Io::TlsContextOptions::InitDefaultClient(allocator);
+ if (!m_contextOptions)
+ {
+ m_lastError = m_contextOptions.LastError();
+ return;
+ }
+
+ m_websocketConfig = config;
+ }
+
+ MqttClientConnectionConfigBuilder MqttClientConnectionConfigBuilder::NewDefaultBuilder() noexcept
+ {
+ MqttClientConnectionConfigBuilder return_value =
+ MqttClientConnectionConfigBuilder(Aws::Crt::ApiAllocator());
+ return_value.m_contextOptions = Crt::Io::TlsContextOptions::InitDefaultClient();
+ return return_value;
+ }
+
+ MqttClientConnectionConfigBuilder &MqttClientConnectionConfigBuilder::WithEndpoint(const Crt::String &endpoint)
+ {
+ m_endpoint = endpoint;
+ return *this;
+ }
+
+ MqttClientConnectionConfigBuilder &MqttClientConnectionConfigBuilder::WithEndpoint(Crt::String &&endpoint)
+ {
+ m_endpoint = std::move(endpoint);
+ return *this;
+ }
+
+ MqttClientConnectionConfigBuilder &MqttClientConnectionConfigBuilder::WithMetricsCollection(bool enabled)
+ {
+ m_enableMetricsCollection = enabled;
+ return *this;
+ }
+
+ MqttClientConnectionConfigBuilder &MqttClientConnectionConfigBuilder::WithSdkName(const Crt::String &sdkName)
+ {
+ m_sdkName = sdkName;
+ return *this;
+ }
+
+ MqttClientConnectionConfigBuilder &MqttClientConnectionConfigBuilder::WithSdkVersion(
+ const Crt::String &sdkVersion)
+ {
+ m_sdkVersion = sdkVersion;
+ return *this;
+ }
+
+ MqttClientConnectionConfigBuilder &MqttClientConnectionConfigBuilder::WithPortOverride(uint16_t port) noexcept
+ {
+ m_portOverride = port;
+ return *this;
+ }
+
+ MqttClientConnectionConfigBuilder &MqttClientConnectionConfigBuilder::WithCertificateAuthority(
+ const char *caPath) noexcept
+ {
+ if (m_contextOptions)
+ {
+ if (!m_contextOptions.OverrideDefaultTrustStore(nullptr, caPath))
+ {
+ m_lastError = m_contextOptions.LastError();
+ }
+ }
+ return *this;
+ }
+
+ MqttClientConnectionConfigBuilder &MqttClientConnectionConfigBuilder::WithCertificateAuthority(
+ const Crt::ByteCursor &cert) noexcept
+ {
+ if (m_contextOptions)
+ {
+ if (!m_contextOptions.OverrideDefaultTrustStore(cert))
+ {
+ m_lastError = m_contextOptions.LastError();
+ }
+ }
+ return *this;
+ }
+
+ MqttClientConnectionConfigBuilder &MqttClientConnectionConfigBuilder::WithTcpKeepAlive() noexcept
+ {
+ m_socketOptions.SetKeepAlive(true);
+ return *this;
+ }
+ MqttClientConnectionConfigBuilder &MqttClientConnectionConfigBuilder::WithTcpConnectTimeout(
+ uint32_t connectTimeoutMs) noexcept
+ {
+ m_socketOptions.SetConnectTimeoutMs(connectTimeoutMs);
+ return *this;
+ }
+
+ MqttClientConnectionConfigBuilder &MqttClientConnectionConfigBuilder::WithTcpKeepAliveTimeout(
+ uint16_t keepAliveTimeoutSecs) noexcept
+ {
+ m_socketOptions.SetKeepAliveTimeoutSec(keepAliveTimeoutSecs);
+ return *this;
+ }
+
+ MqttClientConnectionConfigBuilder &MqttClientConnectionConfigBuilder::WithTcpKeepAliveInterval(
+ uint16_t keepAliveIntervalSecs) noexcept
+ {
+ m_socketOptions.SetKeepAliveIntervalSec(keepAliveIntervalSecs);
+ return *this;
+ }
+
+ MqttClientConnectionConfigBuilder &MqttClientConnectionConfigBuilder::WithTcpKeepAliveMaxProbes(
+ uint16_t maxProbes) noexcept
+ {
+ m_socketOptions.SetKeepAliveMaxFailedProbes(maxProbes);
+ return *this;
+ }
+
+ MqttClientConnectionConfigBuilder &MqttClientConnectionConfigBuilder::WithMinimumTlsVersion(
+ aws_tls_versions minimumTlsVersion) noexcept
+ {
+ m_contextOptions.SetMinimumTlsVersion(minimumTlsVersion);
+ return *this;
+ }
+
+ MqttClientConnectionConfigBuilder &MqttClientConnectionConfigBuilder::WithHttpProxyOptions(
+ const Crt::Http::HttpClientConnectionProxyOptions &proxyOptions) noexcept
+ {
+ m_proxyOptions = proxyOptions;
+ return *this;
+ }
+
+ Crt::String MqttClientConnectionConfigBuilder::AddToUsernameParameter(
+ Crt::String currentUsername,
+ Crt::String parameterValue,
+ Crt::String parameterPreText)
+ {
+ Crt::String return_string = currentUsername;
+ if (return_string.find("?") != Crt::String::npos)
+ {
+ return_string += "&";
+ }
+ else
+ {
+ return_string += "?";
+ }
+
+ if (parameterValue.find(parameterPreText) != Crt::String::npos)
+ {
+ return return_string + parameterValue;
+ }
+ else
+ {
+ return return_string + parameterPreText + parameterValue;
+ }
+ }
+
+ MqttClientConnectionConfigBuilder &MqttClientConnectionConfigBuilder::WithCustomAuthorizer(
+ const Crt::String &username,
+ const Crt::String &authorizerName,
+ const Crt::String &authorizerSignature,
+ const Crt::String &password) noexcept
+ {
+ if (!m_contextOptions.IsAlpnSupported())
+ {
+ m_lastError = AWS_ERROR_INVALID_STATE;
+ return *this;
+ }
+
+ m_isUsingCustomAuthorizer = true;
+ Crt::String usernameString = "";
+
+ if (username.empty())
+ {
+ if (!m_username.empty())
+ {
+ usernameString += m_username;
+ }
+ }
+ else
+ {
+ usernameString += username;
+ }
+
+ if (!authorizerName.empty())
+ {
+ usernameString = AddToUsernameParameter(usernameString, authorizerName, "x-amz-customauthorizer-name=");
+ }
+ if (!authorizerSignature.empty())
+ {
+ usernameString =
+ AddToUsernameParameter(usernameString, authorizerSignature, "x-amz-customauthorizer-signature=");
+ }
+
+ m_username = usernameString;
+ m_password = password;
+
+ if (!m_websocketConfig)
+ {
+ if (!m_contextOptions.SetAlpnList("mqtt"))
+ {
+ m_lastError = m_contextOptions.LastError();
+ }
+ m_portOverride = 443;
+ }
+ return *this;
+ }
+
+ MqttClientConnectionConfigBuilder &MqttClientConnectionConfigBuilder::WithUsername(
+ const Crt::String &username) noexcept
+ {
+ m_username = username;
+ return *this;
+ }
+
+ MqttClientConnectionConfigBuilder &MqttClientConnectionConfigBuilder::WithPassword(
+ const Crt::String &password) noexcept
+ {
+ m_password = password;
+ return *this;
+ }
+
+ MqttClientConnectionConfig MqttClientConnectionConfigBuilder::Build() noexcept
+ {
+ if (m_lastError != 0)
+ {
+ return MqttClientConnectionConfig::CreateInvalid(m_lastError);
+ }
+
+ uint16_t port = m_portOverride;
+
+ if (!m_portOverride)
+ {
+ if (m_websocketConfig || Crt::Io::TlsContextOptions::IsAlpnSupported())
+ {
+ port = 443;
+ }
+ else
+ {
+ port = 8883;
+ }
+ }
+
+ Crt::String username = m_username;
+ Crt::String password = m_password;
+
+ // Check to see if a custom authorizer is being used but not through the builder
+ if (!m_isUsingCustomAuthorizer)
+ {
+ if (!m_username.empty())
+ {
+ if (m_username.find_first_of("x-amz-customauthorizer-name=") != Crt::String::npos ||
+ m_username.find_first_of("x-amz-customauthorizer-signature=") != Crt::String::npos)
+ {
+ m_isUsingCustomAuthorizer = true;
+ }
+ }
+ }
+
+ if (port == 443 && !m_websocketConfig && Crt::Io::TlsContextOptions::IsAlpnSupported() &&
+ !m_isUsingCustomAuthorizer)
+ {
+ if (!m_contextOptions.SetAlpnList("x-amzn-mqtt-ca"))
+ {
+ return MqttClientConnectionConfig::CreateInvalid(m_contextOptions.LastError());
+ }
+ }
+
+ // Is the user trying to connect using a custom authorizer?
+ if (m_isUsingCustomAuthorizer)
+ {
+ if (port != 443)
+ {
+ AWS_LOGF_WARN(
+ AWS_LS_MQTT_GENERAL,
+ "Attempting to connect to authorizer with unsupported port. Port is not 443...");
+ }
+ }
+
+ // add metrics string to username (if metrics enabled)
+ if (m_enableMetricsCollection)
+ {
+ if (username.find('?') != Crt::String::npos)
+ {
+ username += "&";
+ }
+ else
+ {
+ username += "?";
+ }
+ username += "SDK=";
+ username += m_sdkName;
+ username += "&Version=";
+ username += m_sdkVersion;
+ }
+
+ auto tlsContext = Crt::Io::TlsContext(m_contextOptions, Crt::Io::TlsMode::CLIENT, m_allocator);
+ if (!tlsContext)
+ {
+ return MqttClientConnectionConfig::CreateInvalid(tlsContext.GetInitializationError());
+ }
+
+ if (!m_websocketConfig)
+ {
+ auto config = MqttClientConnectionConfig(
+ m_endpoint, port, m_socketOptions, std::move(tlsContext), m_proxyOptions);
+ config.m_username = username;
+ config.m_password = password;
+ return config;
+ }
+
+ auto websocketConfig = m_websocketConfig.value();
+ auto signerTransform = [websocketConfig](
+ std::shared_ptr<Crt::Http::HttpRequest> req,
+ const Crt::Mqtt::OnWebSocketHandshakeInterceptComplete &onComplete) {
+ // it is only a very happy coincidence that these function signatures match. This is the callback
+ // for signing to be complete. It invokes the callback for websocket handshake to be complete.
+ auto signingComplete =
+ [onComplete](const std::shared_ptr<Aws::Crt::Http::HttpRequest> &req1, int errorCode) {
+ onComplete(req1, errorCode);
+ };
+
+ auto signerConfig = websocketConfig.CreateSigningConfigCb();
+
+ websocketConfig.Signer->SignRequest(req, *signerConfig, signingComplete);
+ };
+
+ bool useWebsocketProxyOptions = m_websocketConfig->ProxyOptions.has_value() && !m_proxyOptions.has_value();
+
+ auto config = MqttClientConnectionConfig(
+ m_endpoint,
+ port,
+ m_socketOptions,
+ std::move(tlsContext),
+ signerTransform,
+ useWebsocketProxyOptions ? m_websocketConfig->ProxyOptions : m_proxyOptions);
+ config.m_username = username;
+ config.m_password = password;
+ return config;
+ }
+
+ MqttClient::MqttClient(Crt::Io::ClientBootstrap &bootstrap, Crt::Allocator *allocator) noexcept
+ : m_client(bootstrap, allocator), m_lastError(0)
+ {
+ if (!m_client)
+ {
+ m_lastError = m_client.LastError();
+ }
+ }
+
+ MqttClient::MqttClient(Crt::Allocator *allocator) noexcept
+ : MqttClient(*Crt::ApiHandle::GetOrCreateStaticDefaultClientBootstrap(), allocator)
+ {
+ }
+
+ std::shared_ptr<Crt::Mqtt::MqttConnection> MqttClient::NewConnection(
+ const MqttClientConnectionConfig &config) noexcept
+ {
+ if (!config)
+ {
+ m_lastError = config.LastError();
+ return nullptr;
+ }
+
+ bool useWebsocket = config.m_webSocketInterceptor.operator bool();
+ auto newConnection = m_client.NewConnection(
+ config.m_endpoint.c_str(), config.m_port, config.m_socketOptions, config.m_context, useWebsocket);
+
+ if (!newConnection)
+ {
+ m_lastError = m_client.LastError();
+ return nullptr;
+ }
+
+ if (!(*newConnection))
+ {
+ m_lastError = newConnection->LastError();
+ return nullptr;
+ }
+
+ if (!config.m_username.empty() || !config.m_password.empty())
+ {
+ if (!newConnection->SetLogin(config.m_username.c_str(), config.m_password.c_str()))
+ {
+ m_lastError = newConnection->LastError();
+ return nullptr;
+ }
+ }
+
+ if (useWebsocket)
+ {
+ newConnection->WebsocketInterceptor = config.m_webSocketInterceptor;
+ }
+
+ if (config.m_proxyOptions)
+ {
+ newConnection->SetHttpProxyOptions(config.m_proxyOptions.value());
+ }
+
+ return newConnection;
+ }
+ } // namespace Iot
+} // namespace Aws
+
+#endif // !BYO_CRYPTO
diff --git a/contrib/restricted/aws/aws-crt-cpp/source/iot/MqttCommon.cpp b/contrib/restricted/aws/aws-crt-cpp/source/iot/MqttCommon.cpp
new file mode 100644
index 0000000000..e96c7b5e79
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/source/iot/MqttCommon.cpp
@@ -0,0 +1,88 @@
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+#include <aws/iot/MqttClient.h>
+
+#include <aws/crt/Api.h>
+#include <aws/crt/auth/Credentials.h>
+#include <aws/crt/auth/Sigv4Signing.h>
+#include <aws/crt/http/HttpRequestResponse.h>
+
+#if !BYO_CRYPTO
+
+namespace Aws
+{
+ namespace Iot
+ {
+ WebsocketConfig::WebsocketConfig(
+ const Crt::String &signingRegion,
+ Crt::Io::ClientBootstrap *bootstrap,
+ Crt::Allocator *allocator) noexcept
+ : SigningRegion(signingRegion), ServiceName("iotdevicegateway")
+ {
+ Crt::Auth::CredentialsProviderChainDefaultConfig config;
+ config.Bootstrap = bootstrap;
+
+ CredentialsProvider =
+ Crt::Auth::CredentialsProvider::CreateCredentialsProviderChainDefault(config, allocator);
+
+ Signer = Aws::Crt::MakeShared<Crt::Auth::Sigv4HttpRequestSigner>(allocator, allocator);
+
+ auto credsProviderRef = CredentialsProvider;
+ auto signingRegionCopy = SigningRegion;
+ auto serviceNameCopy = ServiceName;
+ CreateSigningConfigCb = [allocator, credsProviderRef, signingRegionCopy, serviceNameCopy]() {
+ auto signerConfig = Aws::Crt::MakeShared<Crt::Auth::AwsSigningConfig>(allocator);
+ signerConfig->SetRegion(signingRegionCopy);
+ signerConfig->SetService(serviceNameCopy);
+ signerConfig->SetSigningAlgorithm(Crt::Auth::SigningAlgorithm::SigV4);
+ signerConfig->SetSignatureType(Crt::Auth::SignatureType::HttpRequestViaQueryParams);
+ signerConfig->SetOmitSessionToken(true);
+ signerConfig->SetCredentialsProvider(credsProviderRef);
+
+ return signerConfig;
+ };
+ }
+
+ WebsocketConfig::WebsocketConfig(const Crt::String &signingRegion, Crt::Allocator *allocator) noexcept
+ : WebsocketConfig(signingRegion, Crt::ApiHandle::GetOrCreateStaticDefaultClientBootstrap(), allocator)
+ {
+ }
+
+ WebsocketConfig::WebsocketConfig(
+ const Crt::String &signingRegion,
+ const std::shared_ptr<Crt::Auth::ICredentialsProvider> &credentialsProvider,
+ Crt::Allocator *allocator) noexcept
+ : CredentialsProvider(credentialsProvider),
+ Signer(Aws::Crt::MakeShared<Crt::Auth::Sigv4HttpRequestSigner>(allocator, allocator)),
+ SigningRegion(signingRegion), ServiceName("iotdevicegateway")
+ {
+ auto credsProviderRef = CredentialsProvider;
+ auto signingRegionCopy = SigningRegion;
+ auto serviceNameCopy = ServiceName;
+ CreateSigningConfigCb = [allocator, credsProviderRef, signingRegionCopy, serviceNameCopy]() {
+ auto signerConfig = Aws::Crt::MakeShared<Crt::Auth::AwsSigningConfig>(allocator);
+ signerConfig->SetRegion(signingRegionCopy);
+ signerConfig->SetService(serviceNameCopy);
+ signerConfig->SetSigningAlgorithm(Crt::Auth::SigningAlgorithm::SigV4);
+ signerConfig->SetSignatureType(Crt::Auth::SignatureType::HttpRequestViaQueryParams);
+ signerConfig->SetOmitSessionToken(true);
+ signerConfig->SetCredentialsProvider(credsProviderRef);
+
+ return signerConfig;
+ };
+ }
+
+ WebsocketConfig::WebsocketConfig(
+ const std::shared_ptr<Crt::Auth::ICredentialsProvider> &credentialsProvider,
+ const std::shared_ptr<Crt::Auth::IHttpRequestSigner> &signer,
+ Iot::CreateSigningConfig createSigningConfig) noexcept
+ : CredentialsProvider(credentialsProvider), Signer(signer),
+ CreateSigningConfigCb(std::move(createSigningConfig)), ServiceName("iotdevicegateway")
+ {
+ }
+ } // namespace Iot
+} // namespace Aws
+
+#endif // !BYO_CRYPTO
diff --git a/contrib/restricted/aws/aws-crt-cpp/source/mqtt/Mqtt5Client.cpp b/contrib/restricted/aws/aws-crt-cpp/source/mqtt/Mqtt5Client.cpp
new file mode 100644
index 0000000000..b8e1217d73
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/source/mqtt/Mqtt5Client.cpp
@@ -0,0 +1,743 @@
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+#include <aws/crt/mqtt/Mqtt5Client.h>
+#include <aws/crt/mqtt/Mqtt5Packets.h>
+
+#include <aws/crt/Api.h>
+#include <aws/crt/StlAllocator.h>
+#include <aws/crt/http/HttpProxyStrategy.h>
+#include <aws/crt/http/HttpRequestResponse.h>
+#include <aws/crt/io/Bootstrap.h>
+#include <aws/iot/MqttClient.h>
+
+#include <utility>
+
+namespace Aws
+{
+ namespace Crt
+ {
+ namespace Mqtt5
+ {
+ struct PubAckCallbackData : public std::enable_shared_from_this<PubAckCallbackData>
+ {
+ PubAckCallbackData(Allocator *alloc = ApiAllocator()) : client(nullptr), allocator(alloc) {}
+
+ std::shared_ptr<Mqtt5Client> client;
+ OnPublishCompletionHandler onPublishCompletion;
+ Allocator *allocator;
+ };
+
+ struct SubAckCallbackData
+ {
+ SubAckCallbackData(Allocator *alloc = ApiAllocator()) : client(nullptr), allocator(alloc) {}
+
+ std::shared_ptr<Mqtt5Client> client;
+ OnSubscribeCompletionHandler onSubscribeCompletion;
+ Allocator *allocator;
+ };
+
+ struct UnSubAckCallbackData
+ {
+ UnSubAckCallbackData(Allocator *alloc = ApiAllocator()) : client(nullptr), allocator(alloc) {}
+
+ std::shared_ptr<Mqtt5Client> client;
+ OnUnsubscribeCompletionHandler onUnsubscribeCompletion;
+ Allocator *allocator;
+ };
+
+ void Mqtt5Client::s_lifeCycleEventCallback(const struct aws_mqtt5_client_lifecycle_event *event)
+ {
+ Mqtt5Client *client = reinterpret_cast<Mqtt5Client *>(event->user_data);
+ switch (event->event_type)
+ {
+ case AWS_MQTT5_CLET_STOPPED:
+ AWS_LOGF_INFO(AWS_LS_MQTT5_CLIENT, "Lifecycle event: Client Stopped!");
+ if (client->onStopped)
+ {
+ OnStoppedEventData eventData;
+ client->onStopped(*client, eventData);
+ }
+ break;
+
+ case AWS_MQTT5_CLET_ATTEMPTING_CONNECT:
+ AWS_LOGF_INFO(AWS_LS_MQTT5_CLIENT, "Lifecycle event: Attempting Connect!");
+ if (client->onAttemptingConnect)
+ {
+ OnAttemptingConnectEventData eventData;
+ client->onAttemptingConnect(*client, eventData);
+ }
+ break;
+
+ case AWS_MQTT5_CLET_CONNECTION_FAILURE:
+ AWS_LOGF_INFO(AWS_LS_MQTT5_CLIENT, "Lifecycle event: Connection Failure!");
+ AWS_LOGF_INFO(
+ AWS_LS_MQTT5_CLIENT,
+ " Error Code: %d(%s)",
+ event->error_code,
+ aws_error_debug_str(event->error_code));
+ if (client->onConnectionFailure)
+ {
+ OnConnectionFailureEventData eventData;
+ eventData.errorCode = event->error_code;
+ std::shared_ptr<ConnAckPacket> packet = nullptr;
+ if (event->connack_data != NULL)
+ {
+ packet = Aws::Crt::MakeShared<ConnAckPacket>(
+ client->m_allocator, *event->connack_data, client->m_allocator);
+ eventData.connAckPacket = packet;
+ }
+ client->onConnectionFailure(*client, eventData);
+ }
+ break;
+
+ case AWS_MQTT5_CLET_CONNECTION_SUCCESS:
+ AWS_LOGF_INFO(AWS_LS_MQTT5_CLIENT, "Lifecycle event: Connection Success!");
+ if (client->onConnectionSuccess)
+ {
+ OnConnectionSuccessEventData eventData;
+
+ std::shared_ptr<ConnAckPacket> packet = nullptr;
+ if (event->connack_data != NULL)
+ {
+ packet = Aws::Crt::MakeShared<ConnAckPacket>(ApiAllocator(), *event->connack_data);
+ }
+
+ std::shared_ptr<NegotiatedSettings> neg_settings = nullptr;
+ if (event->settings != NULL)
+ {
+ neg_settings =
+ Aws::Crt::MakeShared<NegotiatedSettings>(ApiAllocator(), *event->settings);
+ }
+
+ eventData.connAckPacket = packet;
+ eventData.negotiatedSettings = neg_settings;
+ client->onConnectionSuccess(*client, eventData);
+ }
+ break;
+
+ case AWS_MQTT5_CLET_DISCONNECTION:
+ AWS_LOGF_INFO(
+ AWS_LS_MQTT5_CLIENT,
+ " Error Code: %d(%s)",
+ event->error_code,
+ aws_error_debug_str(event->error_code));
+ if (client->onDisconnection)
+ {
+ OnDisconnectionEventData eventData;
+ std::shared_ptr<DisconnectPacket> disconnection = nullptr;
+ if (event->disconnect_data != nullptr)
+ {
+ disconnection = Aws::Crt::MakeShared<DisconnectPacket>(
+ client->m_allocator, *event->disconnect_data, client->m_allocator);
+ }
+ eventData.errorCode = event->error_code;
+ eventData.disconnectPacket = disconnection;
+ client->onDisconnection(*client, eventData);
+ }
+ break;
+ }
+ }
+
+ void Mqtt5Client::s_publishReceivedCallback(
+ const struct aws_mqtt5_packet_publish_view *publish,
+ void *user_data)
+ {
+ AWS_LOGF_INFO(AWS_LS_MQTT5_CLIENT, "on publish recieved callback");
+ Mqtt5Client *client = reinterpret_cast<Mqtt5Client *>(user_data);
+ if (client != nullptr && client->onPublishReceived != nullptr)
+ {
+ if (publish != NULL)
+ {
+ std::shared_ptr<PublishPacket> packet =
+ std::make_shared<PublishPacket>(*publish, client->m_allocator);
+ PublishReceivedEventData eventData;
+ eventData.publishPacket = packet;
+ client->onPublishReceived(*client, eventData);
+ }
+ else
+ {
+ AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "Failed to access Publish packet view.");
+ }
+ }
+ }
+
+ void Mqtt5Client::s_publishCompletionCallback(
+ enum aws_mqtt5_packet_type packet_type,
+ const void *publshCompletionPacket,
+ int error_code,
+ void *complete_ctx)
+ {
+ AWS_LOGF_INFO(AWS_LS_MQTT5_CLIENT, "Publish completion callback triggered.");
+ auto callbackData = reinterpret_cast<PubAckCallbackData *>(complete_ctx);
+
+ if (callbackData)
+ {
+ std::shared_ptr<PublishResult> publish = nullptr;
+ switch (packet_type)
+ {
+ case aws_mqtt5_packet_type::AWS_MQTT5_PT_PUBACK:
+ {
+ if (publshCompletionPacket != NULL)
+ {
+ std::shared_ptr<PubAckPacket> packet = std::make_shared<PubAckPacket>(
+ *(aws_mqtt5_packet_puback_view *)publshCompletionPacket, callbackData->allocator);
+ publish = std::make_shared<PublishResult>(std::move(packet));
+ }
+ else // This should never happened.
+ {
+ AWS_LOGF_INFO(AWS_LS_MQTT5_CLIENT, "The PubAck Packet is invalid.");
+ publish = std::make_shared<PublishResult>(AWS_ERROR_INVALID_ARGUMENT);
+ }
+ break;
+ }
+ case aws_mqtt5_packet_type::AWS_MQTT5_PT_NONE:
+ {
+ publish = std::make_shared<PublishResult>(error_code);
+ break;
+ }
+ default: // Invalid packet type
+ {
+ AWS_LOGF_INFO(AWS_LS_MQTT5_CLIENT, "Invalid Packet Type.");
+ publish = std::make_shared<PublishResult>(AWS_ERROR_INVALID_ARGUMENT);
+ break;
+ }
+ }
+ if (callbackData->onPublishCompletion != NULL)
+ {
+ callbackData->onPublishCompletion(callbackData->client, error_code, publish);
+ }
+
+ Crt::Delete(callbackData, callbackData->allocator);
+ }
+ }
+
+ void Mqtt5Client::s_onWebsocketHandshake(
+ struct aws_http_message *rawRequest,
+ void *user_data,
+ aws_mqtt5_transform_websocket_handshake_complete_fn *complete_fn,
+ void *complete_ctx)
+ {
+ auto client = reinterpret_cast<Mqtt5Client *>(user_data);
+
+ Allocator *allocator = client->m_allocator;
+ // we have to do this because of private constructors.
+ auto toSeat =
+ reinterpret_cast<Http::HttpRequest *>(aws_mem_acquire(allocator, sizeof(Http::HttpRequest)));
+ toSeat = new (toSeat) Http::HttpRequest(allocator, rawRequest);
+
+ std::shared_ptr<Http::HttpRequest> request = std::shared_ptr<Http::HttpRequest>(
+ toSeat, [allocator](Http::HttpRequest *ptr) { Crt::Delete(ptr, allocator); });
+
+ auto onInterceptComplete =
+ [complete_fn,
+ complete_ctx](const std::shared_ptr<Http::HttpRequest> &transformedRequest, int errorCode) {
+ complete_fn(transformedRequest->GetUnderlyingMessage(), errorCode, complete_ctx);
+ };
+
+ client->websocketInterceptor(request, onInterceptComplete);
+ }
+
+ void Mqtt5Client::s_clientTerminationCompletion(void *complete_ctx)
+ {
+ Mqtt5Client *client = reinterpret_cast<Mqtt5Client *>(complete_ctx);
+ std::unique_lock<std::mutex> lock(client->m_terminationMutex);
+ client->m_terminationPredicate = true;
+ client->m_terminationCondition.notify_all();
+ }
+
+ void Mqtt5Client::s_subscribeCompletionCallback(
+ const aws_mqtt5_packet_suback_view *suback,
+ int error_code,
+ void *complete_ctx)
+ {
+ SubAckCallbackData *callbackData = reinterpret_cast<SubAckCallbackData *>(complete_ctx);
+ AWS_ASSERT(callbackData != nullptr);
+
+ std::shared_ptr<SubAckPacket> packet = nullptr;
+ if (suback != nullptr)
+ {
+ packet = std::make_shared<SubAckPacket>(*suback, callbackData->allocator);
+ }
+
+ if (error_code != 0)
+ {
+ AWS_LOGF_INFO(
+ AWS_LS_MQTT5_CLIENT,
+ "SubscribeCompletion Failed with Error Code: %d(%s)",
+ error_code,
+ aws_error_debug_str(error_code));
+ }
+
+ if (callbackData->onSubscribeCompletion)
+ {
+ callbackData->onSubscribeCompletion(callbackData->client, error_code, packet);
+ }
+ Crt::Delete(callbackData, callbackData->allocator);
+ }
+
+ void Mqtt5Client::s_unsubscribeCompletionCallback(
+ const aws_mqtt5_packet_unsuback_view *unsuback,
+ int error_code,
+ void *complete_ctx)
+ {
+ UnSubAckCallbackData *callbackData = reinterpret_cast<UnSubAckCallbackData *>(complete_ctx);
+ AWS_ASSERT(callbackData != nullptr);
+
+ std::shared_ptr<UnSubAckPacket> packet = nullptr;
+ if (unsuback != nullptr)
+ {
+ packet = std::make_shared<UnSubAckPacket>(*unsuback, callbackData->allocator);
+ }
+
+ if (error_code != 0)
+ {
+ AWS_LOGF_INFO(
+ AWS_LS_MQTT5_CLIENT,
+ "UnsubscribeCompletion Failed with Error Code: %d(%s)",
+ error_code,
+ aws_error_debug_str(error_code));
+ }
+
+ if (callbackData->onUnsubscribeCompletion != NULL)
+ {
+ callbackData->onUnsubscribeCompletion(callbackData->client, error_code, packet);
+ }
+
+ Crt::Delete(callbackData, callbackData->allocator);
+ }
+
+ Mqtt5Client::Mqtt5Client(const Mqtt5ClientOptions &options, Allocator *allocator) noexcept
+ : m_client(nullptr), m_allocator(allocator)
+ {
+ aws_mqtt5_client_options clientOptions;
+
+ options.initializeRawOptions(clientOptions);
+
+ /* Setup Callbacks */
+ if (options.websocketHandshakeTransform)
+ {
+ this->websocketInterceptor = options.websocketHandshakeTransform;
+ clientOptions.websocket_handshake_transform = &Mqtt5Client::s_onWebsocketHandshake;
+ clientOptions.websocket_handshake_transform_user_data = this;
+ }
+
+ if (options.onConnectionFailure)
+ {
+ this->onConnectionFailure = options.onConnectionFailure;
+ }
+
+ if (options.onConnectionSuccess)
+ {
+ this->onConnectionSuccess = options.onConnectionSuccess;
+ }
+
+ if (options.onDisconnection)
+ {
+ this->onDisconnection = options.onDisconnection;
+ }
+
+ if (options.onPublishReceived)
+ {
+ this->onPublishReceived = options.onPublishReceived;
+ }
+
+ if (options.onStopped)
+ {
+ this->onStopped = options.onStopped;
+ }
+
+ if (options.onAttemptingConnect)
+ {
+ this->onAttemptingConnect = options.onAttemptingConnect;
+ }
+
+ clientOptions.publish_received_handler_user_data = this;
+ clientOptions.publish_received_handler = &Mqtt5Client::s_publishReceivedCallback;
+
+ clientOptions.lifecycle_event_handler = &Mqtt5Client::s_lifeCycleEventCallback;
+ clientOptions.lifecycle_event_handler_user_data = this;
+
+ clientOptions.client_termination_handler = &Mqtt5Client::s_clientTerminationCompletion;
+ clientOptions.client_termination_handler_user_data = this;
+
+ m_client = aws_mqtt5_client_new(allocator, &clientOptions);
+ }
+
+ Mqtt5Client::~Mqtt5Client()
+ {
+ if (m_client != nullptr)
+ {
+ aws_mqtt5_client_release(m_client);
+ std::unique_lock<std::mutex> lock(m_terminationMutex);
+ m_terminationCondition.wait(lock, [this] { return m_terminationPredicate == true; });
+ m_client = nullptr;
+ }
+ }
+
+ std::shared_ptr<Mqtt5Client> Mqtt5Client::NewMqtt5Client(
+ const Mqtt5ClientOptions &options,
+ Allocator *allocator) noexcept
+ {
+ /* Copied from MqttClient.cpp:ln754 */
+ // As the constructor is private, make share would not work here. We do make_share manually.
+ Mqtt5Client *toSeat = reinterpret_cast<Mqtt5Client *>(aws_mem_acquire(allocator, sizeof(Mqtt5Client)));
+ if (!toSeat)
+ {
+ return nullptr;
+ }
+
+ toSeat = new (toSeat) Mqtt5Client(options, allocator);
+ return std::shared_ptr<Mqtt5Client>(
+ toSeat, [allocator](Mqtt5Client *client) { Crt::Delete(client, allocator); });
+ }
+
+ Mqtt5Client::operator bool() const noexcept { return m_client != nullptr; }
+
+ int Mqtt5Client::LastError() const noexcept { return aws_last_error(); }
+
+ bool Mqtt5Client::Start() const noexcept { return aws_mqtt5_client_start(m_client) == AWS_OP_SUCCESS; }
+
+ bool Mqtt5Client::Stop() noexcept { return aws_mqtt5_client_stop(m_client, NULL, NULL) == AWS_OP_SUCCESS; }
+
+ bool Mqtt5Client::Stop(std::shared_ptr<DisconnectPacket> disconnectOptions) noexcept
+ {
+ if (disconnectOptions == nullptr)
+ {
+ return Stop();
+ }
+
+ aws_mqtt5_packet_disconnect_view disconnect_packet;
+ AWS_ZERO_STRUCT(disconnect_packet);
+ if (disconnectOptions->initializeRawOptions(disconnect_packet) == false)
+ {
+ return false;
+ }
+ return aws_mqtt5_client_stop(m_client, &disconnect_packet, NULL) == AWS_OP_SUCCESS;
+ }
+
+ bool Mqtt5Client::Publish(
+ std::shared_ptr<PublishPacket> publishOptions,
+ OnPublishCompletionHandler onPublishCmpletionCallback) noexcept
+ {
+ if (publishOptions == nullptr)
+ {
+ return false;
+ }
+
+ aws_mqtt5_packet_publish_view publish;
+ publishOptions->initializeRawOptions(publish);
+
+ PubAckCallbackData *pubCallbackData = Aws::Crt::New<PubAckCallbackData>(m_allocator);
+
+ pubCallbackData->client = this->getptr();
+ pubCallbackData->allocator = m_allocator;
+ pubCallbackData->onPublishCompletion = onPublishCmpletionCallback;
+
+ aws_mqtt5_publish_completion_options options;
+
+ options.completion_callback = Mqtt5Client::s_publishCompletionCallback;
+ options.completion_user_data = pubCallbackData;
+
+ int result = aws_mqtt5_client_publish(m_client, &publish, &options);
+ if (result != AWS_OP_SUCCESS)
+ {
+ Crt::Delete(pubCallbackData, pubCallbackData->allocator);
+ return false;
+ }
+ return true;
+ }
+
+ bool Mqtt5Client::Subscribe(
+ std::shared_ptr<SubscribePacket> subscribeOptions,
+ OnSubscribeCompletionHandler onSubscribeCompletionCallback) noexcept
+ {
+ if (subscribeOptions == nullptr)
+ {
+ return false;
+ }
+ /* Setup packet_subscribe */
+ aws_mqtt5_packet_subscribe_view subscribe;
+
+ subscribeOptions->initializeRawOptions(subscribe);
+
+ /* Setup subscription Completion callback*/
+ SubAckCallbackData *subCallbackData = Aws::Crt::New<SubAckCallbackData>(m_allocator);
+
+ subCallbackData->client = this->getptr();
+ subCallbackData->allocator = m_allocator;
+ subCallbackData->onSubscribeCompletion = onSubscribeCompletionCallback;
+
+ aws_mqtt5_subscribe_completion_options options;
+
+ options.completion_callback = Mqtt5Client::s_subscribeCompletionCallback;
+ options.completion_user_data = subCallbackData;
+
+ /* Subscribe to topic */
+ int result = aws_mqtt5_client_subscribe(m_client, &subscribe, &options);
+ if (result != AWS_OP_SUCCESS)
+ {
+ Crt::Delete(subCallbackData, subCallbackData->allocator);
+ return false;
+ }
+ return result == AWS_OP_SUCCESS;
+ }
+
+ bool Mqtt5Client::Unsubscribe(
+ std::shared_ptr<UnsubscribePacket> unsubscribeOptions,
+ OnUnsubscribeCompletionHandler onUnsubscribeCompletionCallback) noexcept
+ {
+ if (unsubscribeOptions == nullptr)
+ {
+ return false;
+ }
+
+ aws_mqtt5_packet_unsubscribe_view unsubscribe;
+ unsubscribeOptions->initializeRawOptions(unsubscribe);
+
+ UnSubAckCallbackData *unSubCallbackData = Aws::Crt::New<UnSubAckCallbackData>(m_allocator);
+
+ unSubCallbackData->client = this->getptr();
+ unSubCallbackData->allocator = m_allocator;
+ unSubCallbackData->onUnsubscribeCompletion = onUnsubscribeCompletionCallback;
+
+ aws_mqtt5_unsubscribe_completion_options options;
+
+ options.completion_callback = Mqtt5Client::s_unsubscribeCompletionCallback;
+ options.completion_user_data = unSubCallbackData;
+
+ int result = aws_mqtt5_client_unsubscribe(m_client, &unsubscribe, &options);
+ if (result != AWS_OP_SUCCESS)
+ {
+ Crt::Delete(unSubCallbackData, unSubCallbackData->allocator);
+ return false;
+ }
+ return result == AWS_OP_SUCCESS;
+ }
+
+ const Mqtt5ClientOperationStatistics &Mqtt5Client::GetOperationStatistics() noexcept
+ {
+ aws_mqtt5_client_operation_statistics m_operationStatisticsNative = {0, 0, 0, 0};
+ if (m_client != nullptr)
+ {
+ aws_mqtt5_client_get_stats(m_client, &m_operationStatisticsNative);
+ m_operationStatistics.incompleteOperationCount =
+ m_operationStatisticsNative.incomplete_operation_count;
+ m_operationStatistics.incompleteOperationSize =
+ m_operationStatisticsNative.incomplete_operation_size;
+ m_operationStatistics.unackedOperationCount = m_operationStatisticsNative.unacked_operation_count;
+ m_operationStatistics.unackedOperationSize = m_operationStatisticsNative.unacked_operation_size;
+ }
+ return m_operationStatistics;
+ }
+
+ /*****************************************************
+ *
+ * Mqtt5ClientOptions
+ *
+ *****************************************************/
+
+ /**
+ * Mqtt5ClientOptions
+ */
+ Mqtt5ClientOptions::Mqtt5ClientOptions(Crt::Allocator *allocator) noexcept
+ : m_bootstrap(nullptr), m_sessionBehavior(ClientSessionBehaviorType::AWS_MQTT5_CSBT_DEFAULT),
+ m_extendedValidationAndFlowControlOptions(AWS_MQTT5_EVAFCO_AWS_IOT_CORE_DEFAULTS),
+ m_offlineQueueBehavior(AWS_MQTT5_COQBT_DEFAULT),
+ m_reconnectionOptions({AWS_EXPONENTIAL_BACKOFF_JITTER_DEFAULT, 0, 0, 0}), m_pingTimeoutMs(0),
+ m_connackTimeoutMs(0), m_ackTimeoutSec(0), m_allocator(allocator)
+ {
+ m_socketOptions.SetSocketType(Io::SocketType::Stream);
+ AWS_ZERO_STRUCT(m_packetConnectViewStorage);
+ AWS_ZERO_STRUCT(m_httpProxyOptionsStorage);
+ }
+
+ bool Mqtt5ClientOptions::initializeRawOptions(aws_mqtt5_client_options &raw_options) const noexcept
+ {
+ AWS_ZERO_STRUCT(raw_options);
+
+ raw_options.host_name = ByteCursorFromString(m_hostName);
+ raw_options.port = m_port;
+
+ if (m_bootstrap == nullptr)
+ {
+ raw_options.bootstrap = ApiHandle::GetOrCreateStaticDefaultClientBootstrap()->GetUnderlyingHandle();
+ }
+ else
+ {
+ raw_options.bootstrap = m_bootstrap->GetUnderlyingHandle();
+ }
+ raw_options.socket_options = &m_socketOptions.GetImpl();
+ if (m_tlsConnectionOptions.has_value())
+ {
+ raw_options.tls_options = m_tlsConnectionOptions.value().GetUnderlyingHandle();
+ }
+
+ if (m_proxyOptions.has_value())
+ {
+ raw_options.http_proxy_options = &m_httpProxyOptionsStorage;
+ }
+
+ raw_options.connect_options = &m_packetConnectViewStorage;
+ raw_options.session_behavior = m_sessionBehavior;
+ raw_options.extended_validation_and_flow_control_options = m_extendedValidationAndFlowControlOptions;
+ raw_options.offline_queue_behavior = m_offlineQueueBehavior;
+ raw_options.retry_jitter_mode = m_reconnectionOptions.m_reconnectMode;
+ raw_options.max_reconnect_delay_ms = m_reconnectionOptions.m_maxReconnectDelayMs;
+ raw_options.min_reconnect_delay_ms = m_reconnectionOptions.m_minReconnectDelayMs;
+ raw_options.min_connected_time_to_reset_reconnect_delay_ms =
+ m_reconnectionOptions.m_minConnectedTimeToResetReconnectDelayMs;
+ raw_options.ping_timeout_ms = m_pingTimeoutMs;
+ raw_options.connack_timeout_ms = m_connackTimeoutMs;
+ raw_options.ack_timeout_seconds = m_ackTimeoutSec;
+
+ return true;
+ }
+
+ Mqtt5ClientOptions::~Mqtt5ClientOptions() {}
+
+ Mqtt5ClientOptions &Mqtt5ClientOptions::withHostName(Crt::String hostname)
+ {
+ m_hostName = std::move(hostname);
+ return *this;
+ }
+
+ Mqtt5ClientOptions &Mqtt5ClientOptions::withPort(uint16_t port) noexcept
+ {
+ m_port = port;
+ return *this;
+ }
+
+ Mqtt5ClientOptions &Mqtt5ClientOptions::withBootstrap(Io::ClientBootstrap *bootStrap) noexcept
+ {
+ m_bootstrap = bootStrap;
+ return *this;
+ }
+
+ Mqtt5ClientOptions &Mqtt5ClientOptions::withSocketOptions(Io::SocketOptions socketOptions) noexcept
+ {
+ m_socketOptions = std::move(socketOptions);
+ return *this;
+ }
+
+ Mqtt5ClientOptions &Mqtt5ClientOptions::withTlsConnectionOptions(
+ const Io::TlsConnectionOptions &tslOptions) noexcept
+ {
+ m_tlsConnectionOptions = tslOptions;
+ return *this;
+ }
+
+ Mqtt5ClientOptions &Mqtt5ClientOptions::withHttpProxyOptions(
+ const Crt::Http::HttpClientConnectionProxyOptions &proxyOptions) noexcept
+ {
+ m_proxyOptions = proxyOptions;
+ m_proxyOptions->InitializeRawProxyOptions(m_httpProxyOptionsStorage);
+ return *this;
+ }
+
+ Mqtt5ClientOptions &Mqtt5ClientOptions::withConnectOptions(
+ std::shared_ptr<ConnectPacket> packetConnect) noexcept
+ {
+ m_connectOptions = packetConnect;
+ m_connectOptions->initializeRawOptions(m_packetConnectViewStorage, m_allocator);
+ return *this;
+ }
+
+ Mqtt5ClientOptions &Mqtt5ClientOptions::withSessionBehavior(
+ ClientSessionBehaviorType sessionBehavior) noexcept
+ {
+ m_sessionBehavior = sessionBehavior;
+ return *this;
+ }
+
+ Mqtt5ClientOptions &Mqtt5ClientOptions::withClientExtendedValidationAndFlowControl(
+ ClientExtendedValidationAndFlowControl clientExtendedValidationAndFlowControl) noexcept
+ {
+ m_extendedValidationAndFlowControlOptions = clientExtendedValidationAndFlowControl;
+ return *this;
+ }
+
+ Mqtt5ClientOptions &Mqtt5ClientOptions::withOfflineQueueBehavior(
+ ClientOperationQueueBehaviorType offlineQueueBehavior) noexcept
+ {
+ m_offlineQueueBehavior = offlineQueueBehavior;
+ return *this;
+ }
+
+ Mqtt5ClientOptions &Mqtt5ClientOptions::withReconnectOptions(ReconnectOptions reconnectOptions) noexcept
+ {
+ m_reconnectionOptions = reconnectOptions;
+
+ return *this;
+ }
+
+ Mqtt5ClientOptions &Mqtt5ClientOptions::withPingTimeoutMs(uint32_t pingTimeoutMs) noexcept
+ {
+ m_pingTimeoutMs = pingTimeoutMs;
+ return *this;
+ }
+
+ Mqtt5ClientOptions &Mqtt5ClientOptions::withConnackTimeoutMs(uint32_t connackTimeoutMs) noexcept
+ {
+ m_connackTimeoutMs = connackTimeoutMs;
+ return *this;
+ }
+
+ Mqtt5ClientOptions &Mqtt5ClientOptions::withAckTimeoutSeconds(uint32_t ackTimeoutSeconds) noexcept
+ {
+ m_ackTimeoutSec = ackTimeoutSeconds;
+ return *this;
+ }
+
+ Mqtt5ClientOptions &Mqtt5ClientOptions::withWebsocketHandshakeTransformCallback(
+ OnWebSocketHandshakeIntercept callback) noexcept
+ {
+ websocketHandshakeTransform = std::move(callback);
+ return *this;
+ }
+
+ Mqtt5ClientOptions &Mqtt5ClientOptions::withClientConnectionSuccessCallback(
+ OnConnectionSuccessHandler callback) noexcept
+ {
+ onConnectionSuccess = std::move(callback);
+ return *this;
+ }
+
+ Mqtt5ClientOptions &Mqtt5ClientOptions::withClientConnectionFailureCallback(
+ OnConnectionFailureHandler callback) noexcept
+ {
+ onConnectionFailure = std::move(callback);
+ return *this;
+ }
+
+ Mqtt5ClientOptions &Mqtt5ClientOptions::withClientDisconnectionCallback(
+ OnDisconnectionHandler callback) noexcept
+ {
+ onDisconnection = std::move(callback);
+ return *this;
+ }
+
+ Mqtt5ClientOptions &Mqtt5ClientOptions::withClientStoppedCallback(OnStoppedHandler callback) noexcept
+ {
+ onStopped = std::move(callback);
+ return *this;
+ }
+
+ Mqtt5ClientOptions &Mqtt5ClientOptions::withClientAttemptingConnectCallback(
+ OnAttemptingConnectHandler callback) noexcept
+ {
+ onAttemptingConnect = std::move(callback);
+ return *this;
+ }
+
+ Mqtt5ClientOptions &Mqtt5ClientOptions::withPublishReceivedCallback(
+ OnPublishReceivedHandler callback) noexcept
+ {
+ onPublishReceived = std::move(callback);
+ return *this;
+ }
+
+ } // namespace Mqtt5
+ } // namespace Crt
+} // namespace Aws
diff --git a/contrib/restricted/aws/aws-crt-cpp/source/mqtt/Mqtt5Packets.cpp b/contrib/restricted/aws/aws-crt-cpp/source/mqtt/Mqtt5Packets.cpp
new file mode 100644
index 0000000000..a59bebb635
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/source/mqtt/Mqtt5Packets.cpp
@@ -0,0 +1,1236 @@
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+#include <aws/crt/mqtt/Mqtt5Client.h>
+#include <aws/crt/mqtt/Mqtt5Packets.h>
+
+namespace Aws
+{
+ namespace Crt
+ {
+ namespace Mqtt5
+ {
+ template <typename T> void setPacketVector(Vector<T> &vector, const T *values, size_t length)
+ {
+ vector.clear();
+ for (size_t i = 0; i < length; ++i)
+ {
+ vector.push_back(values[i]);
+ }
+ }
+ template <typename T> void setPacketOptional(Optional<T> &optional, const T *value)
+ {
+ if (value != nullptr)
+ {
+ optional = *value;
+ }
+ else
+ {
+ optional.reset();
+ }
+ }
+
+ void setPacketStringOptional(
+ Optional<aws_byte_cursor> &optional,
+ Crt::String &optionalStorage,
+ const aws_byte_cursor *value)
+ {
+ if (value != nullptr)
+ {
+ optionalStorage = Crt::String((const char *)value->ptr, value->len);
+ struct aws_byte_cursor optional_cursor;
+ optional_cursor.ptr = (uint8_t *)optionalStorage.c_str();
+ optional_cursor.len = optionalStorage.size();
+ optional = optional_cursor;
+ }
+ }
+
+ void setPacketStringOptional(Optional<Crt::String> &optional, const aws_byte_cursor *value)
+ {
+ if (value != nullptr)
+ {
+ optional = Crt::String((const char *)value->ptr, value->len);
+ }
+ else
+ {
+ optional.reset();
+ }
+ }
+
+ void setPacketStringOptional(Optional<Crt::String> &optional, Crt::String &&toMove)
+ {
+ if (!toMove.empty())
+ {
+ optional = std::move(toMove);
+ }
+ else
+ {
+ optional.reset();
+ }
+ }
+
+ void setPacketByteBufOptional(
+ Optional<aws_byte_cursor> &optional,
+ ByteBuf &optionalStorage,
+ Allocator *allocator,
+ const aws_byte_cursor *value)
+ {
+ aws_byte_buf_clean_up(&optionalStorage);
+ AWS_ZERO_STRUCT(optionalStorage);
+ if (value != nullptr)
+ {
+ aws_byte_buf_init_copy_from_cursor(&optionalStorage, allocator, *value);
+ optional = aws_byte_cursor_from_buf(&optionalStorage);
+ }
+ else
+ {
+ optional.reset();
+ }
+ }
+ void setUserProperties(
+ Vector<UserProperty> &userProperties,
+ const struct aws_mqtt5_user_property *properties,
+ size_t propertyCount)
+ {
+ for (size_t i = 0; i < propertyCount; ++i)
+ {
+ userProperties.push_back(UserProperty(
+ Aws::Crt::String((const char *)properties[i].name.ptr, properties[i].name.len),
+ Aws::Crt::String((const char *)properties[i].value.ptr, properties[i].value.len)));
+ }
+ }
+ template <typename T> void setNullableFromOptional(const T *&nullable, const Optional<T> &optional)
+ {
+ if (optional.has_value())
+ {
+ nullable = &optional.value();
+ }
+ }
+
+ void s_AllocateUnderlyingUserProperties(
+ aws_mqtt5_user_property *&dst,
+ const Crt::Vector<UserProperty> &userProperties,
+ Allocator *allocator)
+ {
+ if (dst != nullptr)
+ {
+ aws_mem_release(allocator, (void *)dst);
+ dst = nullptr;
+ }
+ if (userProperties.size() > 0)
+ {
+ dst = reinterpret_cast<struct aws_mqtt5_user_property *>(
+ aws_mem_calloc(allocator, userProperties.size(), sizeof(aws_mqtt5_user_property)));
+ AWS_ZERO_STRUCT(*dst);
+ for (size_t index = 0; index < userProperties.size(); ++index)
+ {
+ (dst + index)->name = aws_byte_cursor_from_array(
+ userProperties[index].getName().c_str(), userProperties[index].getName().length());
+ (dst + index)->value = aws_byte_cursor_from_array(
+ userProperties[index].getValue().c_str(), userProperties[index].getValue().length());
+ }
+ }
+ }
+
+ void s_AllocateStringVector(
+ aws_array_list &dst,
+ const Crt::Vector<String> &stringVector,
+ Allocator *allocator)
+ {
+ AWS_ZERO_STRUCT(dst);
+
+ if (aws_array_list_init_dynamic(&dst, allocator, stringVector.size(), sizeof(aws_byte_cursor)) !=
+ AWS_OP_SUCCESS)
+ {
+ return;
+ }
+
+ for (auto &topic : stringVector)
+ {
+ ByteCursor topicCursor = ByteCursorFromString(topic);
+ aws_array_list_push_back(&dst, reinterpret_cast<const void *>(&topicCursor));
+ }
+ }
+
+ void s_AllocateUnderlyingSubscription(
+ aws_mqtt5_subscription_view *&dst,
+ const Crt::Vector<Subscription> &subscriptions,
+ Allocator *allocator)
+ {
+ if (dst != nullptr)
+ {
+ aws_mem_release(allocator, dst);
+ dst = nullptr;
+ }
+
+ aws_array_list subscription_list;
+ AWS_ZERO_STRUCT(subscription_list);
+
+ if (aws_array_list_init_dynamic(
+ &subscription_list, allocator, subscriptions.size(), sizeof(aws_mqtt5_subscription_view)) !=
+ AWS_OP_SUCCESS)
+ {
+ return;
+ }
+
+ for (auto &subscription : subscriptions)
+ {
+
+ aws_mqtt5_subscription_view underlying_subscription;
+ if (subscription.initializeRawOptions(underlying_subscription) != true)
+ {
+ goto clean_up;
+ }
+
+ aws_array_list_push_back(
+ &subscription_list, reinterpret_cast<const void *>(&underlying_subscription));
+ }
+ dst = static_cast<aws_mqtt5_subscription_view *>(subscription_list.data);
+ return;
+
+ clean_up:
+ aws_array_list_clean_up(&subscription_list);
+ }
+
+ ConnectPacket::ConnectPacket(Allocator *allocator) noexcept
+ : m_allocator(allocator), m_keepAliveIntervalSec(1200), m_userPropertiesStorage(nullptr)
+ {
+ // m_clientId.clear();
+ AWS_ZERO_STRUCT(m_usernameCursor);
+ AWS_ZERO_STRUCT(m_passowrdStorage);
+ AWS_ZERO_STRUCT(m_willStorage);
+ }
+
+ ConnectPacket &ConnectPacket::withKeepAliveIntervalSec(uint16_t second) noexcept
+ {
+ m_keepAliveIntervalSec = second;
+ return *this;
+ }
+
+ ConnectPacket &ConnectPacket::withClientId(Crt::String client_id) noexcept
+ {
+ m_clientId = std::move(client_id);
+ return *this;
+ }
+
+ ConnectPacket &ConnectPacket::withUserName(Crt::String username) noexcept
+ {
+ m_username = std::move(username);
+ m_usernameCursor = ByteCursorFromString(m_username.value());
+ return *this;
+ }
+
+ ConnectPacket &ConnectPacket::withPassword(Crt::ByteCursor password) noexcept
+ {
+ setPacketByteBufOptional(m_password, m_passowrdStorage, m_allocator, &password);
+ return *this;
+ }
+
+ ConnectPacket &ConnectPacket::withSessionExpiryIntervalSec(uint32_t sessionExpiryIntervalSec) noexcept
+ {
+ m_sessionExpiryIntervalSec = sessionExpiryIntervalSec;
+ return *this;
+ }
+
+ ConnectPacket &ConnectPacket::withRequestResponseInformation(bool requestResponseInformation) noexcept
+ {
+ m_requestResponseInformation = requestResponseInformation;
+ return *this;
+ }
+
+ ConnectPacket &ConnectPacket::withRequestProblemInformation(bool requestProblemInformation) noexcept
+ {
+ m_requestProblemInformation = requestProblemInformation;
+ return *this;
+ }
+
+ ConnectPacket &ConnectPacket::withReceiveMaximum(uint16_t receiveMaximum) noexcept
+ {
+ m_receiveMaximum = receiveMaximum;
+ return *this;
+ }
+
+ ConnectPacket &ConnectPacket::withMaximumPacketSizeBytes(uint32_t maximumPacketSizeBytes) noexcept
+ {
+ m_maximumPacketSizeBytes = maximumPacketSizeBytes;
+ return *this;
+ }
+
+ ConnectPacket &ConnectPacket::withWillDelayIntervalSec(uint32_t willDelayIntervalSec) noexcept
+ {
+ m_willDelayIntervalSeconds = willDelayIntervalSec;
+ return *this;
+ }
+
+ ConnectPacket &ConnectPacket::withWill(std::shared_ptr<PublishPacket> will) noexcept
+ {
+ m_will = will;
+ m_will.value()->initializeRawOptions(m_willStorage);
+ return *this;
+ }
+
+ ConnectPacket &ConnectPacket::withUserProperties(const Vector<UserProperty> &userProperties) noexcept
+ {
+ m_userProperties = userProperties;
+ return *this;
+ }
+
+ ConnectPacket &ConnectPacket::withUserProperties(Vector<UserProperty> &&userProperties) noexcept
+ {
+ m_userProperties = userProperties;
+ return *this;
+ }
+
+ ConnectPacket &ConnectPacket::withUserProperty(UserProperty &&property) noexcept
+ {
+ m_userProperties.push_back(std::move(property));
+ return *this;
+ }
+
+ bool ConnectPacket::initializeRawOptions(
+ aws_mqtt5_packet_connect_view &raw_options,
+ Allocator * /*allocator*/) noexcept
+ {
+ AWS_ZERO_STRUCT(raw_options);
+
+ raw_options.keep_alive_interval_seconds = m_keepAliveIntervalSec;
+ raw_options.client_id = ByteCursorFromString(m_clientId);
+
+ if (m_username.has_value())
+ {
+ raw_options.username = &m_usernameCursor;
+ }
+
+ if (m_password.has_value())
+ {
+ raw_options.password = &m_password.value();
+ }
+
+ if (m_sessionExpiryIntervalSec.has_value())
+ {
+ raw_options.session_expiry_interval_seconds = &m_sessionExpiryIntervalSec.value();
+ }
+
+ if (m_requestProblemInformation.has_value())
+ {
+ m_requestResponseInformationStorage = m_requestResponseInformation.value() ? 1 : 0;
+ raw_options.request_response_information = &m_requestResponseInformationStorage;
+ }
+
+ if (m_requestProblemInformation.has_value())
+ {
+ m_requestProblemInformationStorage = m_requestProblemInformation.value() ? 1 : 0;
+ raw_options.request_problem_information = &m_requestProblemInformationStorage;
+ }
+
+ if (m_receiveMaximum.has_value())
+ {
+ raw_options.receive_maximum = &m_receiveMaximum.value();
+ }
+
+ if (m_maximumPacketSizeBytes.has_value())
+ {
+ raw_options.maximum_packet_size_bytes = &m_maximumPacketSizeBytes.value();
+ }
+
+ if (m_willDelayIntervalSeconds.has_value())
+ {
+ raw_options.will_delay_interval_seconds = &m_willDelayIntervalSeconds.value();
+ }
+
+ if (m_will.has_value())
+ {
+ raw_options.will = &m_willStorage;
+ }
+
+ s_AllocateUnderlyingUserProperties(m_userPropertiesStorage, m_userProperties, m_allocator);
+ raw_options.user_properties = m_userPropertiesStorage;
+ raw_options.user_property_count = m_userProperties.size();
+
+ return true;
+ }
+
+ ConnectPacket::~ConnectPacket()
+ {
+ if (m_userPropertiesStorage != nullptr)
+ {
+ aws_mem_release(m_allocator, m_userPropertiesStorage);
+ m_userProperties.clear();
+ }
+ aws_byte_buf_clean_up(&m_passowrdStorage);
+ }
+
+ uint16_t ConnectPacket::getKeepAliveIntervalSec() const noexcept { return m_keepAliveIntervalSec; }
+
+ const Crt::String &ConnectPacket::getClientId() const noexcept { return m_clientId; }
+
+ const Crt::Optional<Crt::String> &ConnectPacket::getUsername() const noexcept { return m_username; }
+
+ const Crt::Optional<Crt::ByteCursor> &ConnectPacket::getPassword() const noexcept { return m_password; }
+
+ const Crt::Optional<uint32_t> &ConnectPacket::getSessionExpiryIntervalSec() const noexcept
+ {
+ return m_sessionExpiryIntervalSec;
+ }
+
+ const Crt::Optional<bool> &ConnectPacket::getRequestResponseInformation() const noexcept
+ {
+ return m_requestResponseInformation;
+ }
+
+ const Crt::Optional<bool> &ConnectPacket::getRequestProblemInformation() const noexcept
+ {
+ return m_requestProblemInformation;
+ }
+
+ const Crt::Optional<uint16_t> &ConnectPacket::getReceiveMaximum() const noexcept
+ {
+ return m_receiveMaximum;
+ }
+
+ const Crt::Optional<uint32_t> &ConnectPacket::getMaximumPacketSizeBytes() const noexcept
+ {
+ return m_maximumPacketSizeBytes;
+ }
+
+ const Crt::Optional<uint32_t> &ConnectPacket::getWillDelayIntervalSec() const noexcept
+ {
+ return m_willDelayIntervalSeconds;
+ }
+
+ const Crt::Optional<std::shared_ptr<PublishPacket>> &ConnectPacket::getWill() const noexcept
+ {
+ return m_will;
+ }
+
+ const Crt::Vector<UserProperty> &ConnectPacket::getUserProperties() const noexcept
+ {
+ return m_userProperties;
+ }
+
+ UserProperty::UserProperty(Crt::String name, Crt::String value) noexcept
+ : m_name(std::move(name)), m_value(std::move(value))
+ {
+ }
+
+ UserProperty::~UserProperty() noexcept {}
+
+ UserProperty::UserProperty(const UserProperty &toCopy) noexcept
+ : m_name(toCopy.getName()), m_value(toCopy.getValue())
+ {
+ }
+
+ UserProperty::UserProperty(UserProperty &&toMove) noexcept
+ : m_name(std::move(toMove.m_name)), m_value(std::move(toMove.m_value))
+ {
+ }
+
+ UserProperty &UserProperty::operator=(const UserProperty &toCopy) noexcept
+ {
+ if (&toCopy != this)
+ {
+ m_name = toCopy.getName();
+ m_value = toCopy.getValue();
+ }
+ return *this;
+ }
+
+ UserProperty &UserProperty::operator=(UserProperty &&toMove) noexcept
+ {
+ if (&toMove != this)
+ {
+ m_name = std::move(toMove.m_name);
+ m_value = std::move(toMove.m_value);
+ }
+ return *this;
+ }
+
+ PublishPacket::PublishPacket(const aws_mqtt5_packet_publish_view &packet, Allocator *allocator) noexcept
+ : m_allocator(allocator), m_qos(packet.qos), m_retain(packet.retain),
+ m_topicName((const char *)packet.topic.ptr, packet.topic.len), m_userPropertiesStorage(nullptr)
+ {
+ AWS_ZERO_STRUCT(m_payloadStorage);
+ AWS_ZERO_STRUCT(m_contentTypeStorage);
+ AWS_ZERO_STRUCT(m_correlationDataStorage);
+ AWS_ZERO_STRUCT(m_payload);
+
+ withPayload(packet.payload);
+
+ setPacketOptional(m_payloadFormatIndicator, packet.payload_format);
+ setPacketOptional(m_messageExpiryIntervalSec, packet.message_expiry_interval_seconds);
+ setPacketStringOptional(m_responseTopic, m_responseTopicString, packet.response_topic);
+ setPacketByteBufOptional(
+ m_correlationData, m_correlationDataStorage, allocator, packet.correlation_data);
+ setPacketByteBufOptional(m_contentType, m_contentTypeStorage, allocator, packet.content_type);
+ setPacketVector(
+ m_subscriptionIdentifiers, packet.subscription_identifiers, packet.subscription_identifier_count);
+ setUserProperties(m_userProperties, packet.user_properties, packet.user_property_count);
+ }
+
+ /* Default constructor */
+ PublishPacket::PublishPacket(Allocator *allocator) noexcept
+ : m_allocator(allocator), m_qos(QOS::AWS_MQTT5_QOS_AT_MOST_ONCE), m_retain(false), m_topicName(""),
+ m_userPropertiesStorage(nullptr)
+ {
+ AWS_ZERO_STRUCT(m_payloadStorage);
+ AWS_ZERO_STRUCT(m_contentTypeStorage);
+ AWS_ZERO_STRUCT(m_correlationDataStorage);
+ AWS_ZERO_STRUCT(m_payload);
+ }
+
+ PublishPacket::PublishPacket(
+ Crt::String topic,
+ ByteCursor payload,
+ Mqtt5::QOS qos,
+ Allocator *allocator) noexcept
+ : m_allocator(allocator), m_qos(qos), m_retain(false), m_topicName(std::move(topic)),
+ m_userPropertiesStorage(nullptr)
+ {
+ AWS_ZERO_STRUCT(m_payloadStorage);
+ AWS_ZERO_STRUCT(m_contentTypeStorage);
+ AWS_ZERO_STRUCT(m_correlationDataStorage);
+ AWS_ZERO_STRUCT(m_payload);
+
+ // Setup message payload, sync with PublishPacket::withPayload
+ aws_byte_buf_clean_up(&m_payloadStorage);
+ aws_byte_buf_init_copy_from_cursor(&m_payloadStorage, m_allocator, payload);
+ m_payload = aws_byte_cursor_from_buf(&m_payloadStorage);
+ }
+
+ PublishPacket &PublishPacket::withPayload(ByteCursor payload) noexcept
+ {
+ aws_byte_buf_clean_up(&m_payloadStorage);
+ aws_byte_buf_init_copy_from_cursor(&m_payloadStorage, m_allocator, payload);
+ m_payload = aws_byte_cursor_from_buf(&m_payloadStorage);
+ return *this;
+ }
+
+ PublishPacket &PublishPacket::withQOS(Mqtt5::QOS qos) noexcept
+ {
+ m_qos = qos;
+ return *this;
+ }
+
+ PublishPacket &PublishPacket::withRetain(bool retain) noexcept
+ {
+ m_retain = retain;
+ return *this;
+ }
+
+ PublishPacket &PublishPacket::withTopic(Crt::String topic) noexcept
+ {
+ m_topicName = std::move(topic);
+ return *this;
+ }
+
+ PublishPacket &PublishPacket::withPayloadFormatIndicator(PayloadFormatIndicator format) noexcept
+ {
+ m_payloadFormatIndicator = format;
+ return *this;
+ }
+
+ PublishPacket &PublishPacket::withMessageExpiryIntervalSec(uint32_t second) noexcept
+ {
+ m_messageExpiryIntervalSec = second;
+ return *this;
+ }
+
+ PublishPacket &PublishPacket::withResponseTopic(ByteCursor responseTopic) noexcept
+ {
+ setPacketStringOptional(m_responseTopic, m_responseTopicString, &responseTopic);
+ return *this;
+ }
+
+ PublishPacket &PublishPacket::withCorrelationData(ByteCursor correlationData) noexcept
+ {
+ setPacketByteBufOptional(m_correlationData, m_correlationDataStorage, m_allocator, &correlationData);
+ return *this;
+ }
+
+ PublishPacket &PublishPacket::withUserProperties(const Vector<UserProperty> &userProperties) noexcept
+ {
+ m_userProperties = userProperties;
+ return *this;
+ }
+
+ PublishPacket &PublishPacket::withUserProperties(Vector<UserProperty> &&userProperties) noexcept
+ {
+ m_userProperties = userProperties;
+ return *this;
+ }
+
+ PublishPacket &PublishPacket::withUserProperty(UserProperty &&property) noexcept
+ {
+ m_userProperties.push_back(std::move(property));
+ return *this;
+ }
+
+ bool PublishPacket::initializeRawOptions(aws_mqtt5_packet_publish_view &raw_options) noexcept
+ {
+ AWS_ZERO_STRUCT(raw_options);
+ raw_options.payload = m_payload;
+ raw_options.qos = m_qos;
+ raw_options.retain = m_retain;
+ raw_options.topic = ByteCursorFromString(m_topicName);
+
+ if (m_payloadFormatIndicator.has_value())
+ {
+ raw_options.payload_format =
+ (aws_mqtt5_payload_format_indicator *)&m_payloadFormatIndicator.value();
+ }
+ if (m_messageExpiryIntervalSec.has_value())
+ {
+ raw_options.message_expiry_interval_seconds = &m_messageExpiryIntervalSec.value();
+ }
+ if (m_responseTopic.has_value())
+ {
+ raw_options.response_topic = &m_responseTopic.value();
+ }
+ if (m_correlationData.has_value())
+ {
+ raw_options.correlation_data = &m_correlationData.value();
+ }
+
+ s_AllocateUnderlyingUserProperties(m_userPropertiesStorage, m_userProperties, m_allocator);
+ raw_options.user_properties = m_userPropertiesStorage;
+ raw_options.user_property_count = m_userProperties.size();
+
+ return true;
+ }
+
+ const ByteCursor &PublishPacket::getPayload() const noexcept { return m_payload; }
+
+ Mqtt5::QOS PublishPacket::getQOS() const noexcept { return m_qos; }
+
+ bool PublishPacket::getRetain() const noexcept { return m_retain; }
+
+ const Crt::String &PublishPacket::getTopic() const noexcept { return m_topicName; }
+
+ const Crt::Optional<PayloadFormatIndicator> &PublishPacket::getPayloadFormatIndicator() const noexcept
+ {
+ return m_payloadFormatIndicator;
+ }
+
+ const Crt::Optional<uint32_t> &PublishPacket::getMessageExpiryIntervalSec() const noexcept
+ {
+ return m_messageExpiryIntervalSec;
+ }
+
+ const Crt::Optional<ByteCursor> &PublishPacket::getResponseTopic() const noexcept
+ {
+ return m_responseTopic;
+ }
+
+ const Crt::Optional<ByteCursor> &PublishPacket::getCorrelationData() const noexcept
+ {
+ return m_correlationData;
+ }
+
+ const Crt::Vector<uint32_t> &PublishPacket::getSubscriptionIdentifiers() const noexcept
+ {
+ return m_subscriptionIdentifiers;
+ }
+
+ const Crt::Optional<ByteCursor> &PublishPacket::getContentType() const noexcept { return m_contentType; }
+
+ const Crt::Vector<UserProperty> &PublishPacket::getUserProperties() const noexcept
+ {
+ return m_userProperties;
+ }
+
+ PublishPacket::~PublishPacket()
+ {
+ aws_byte_buf_clean_up(&m_payloadStorage);
+ aws_byte_buf_clean_up(&m_correlationDataStorage);
+ aws_byte_buf_clean_up(&m_contentTypeStorage);
+
+ if (m_userProperties.size() > 0)
+ {
+ aws_mem_release(m_allocator, m_userPropertiesStorage);
+ m_userProperties.clear();
+ }
+ }
+
+ DisconnectPacket::DisconnectPacket(Allocator *allocator) noexcept
+ : m_allocator(allocator), m_reasonCode(AWS_MQTT5_DRC_NORMAL_DISCONNECTION),
+ m_userPropertiesStorage(nullptr)
+ {
+ }
+
+ bool DisconnectPacket::initializeRawOptions(aws_mqtt5_packet_disconnect_view &raw_options) noexcept
+ {
+ AWS_ZERO_STRUCT(raw_options);
+
+ raw_options.reason_code = m_reasonCode;
+
+ if (m_sessionExpiryIntervalSec.has_value())
+ {
+ raw_options.session_expiry_interval_seconds = &m_sessionExpiryIntervalSec.value();
+ }
+
+ if (m_reasonString.has_value())
+ {
+ m_reasonStringCursor = ByteCursorFromString(m_reasonString.value());
+ raw_options.reason_string = &m_reasonStringCursor;
+ }
+
+ if (m_serverReference.has_value())
+ {
+ m_serverReferenceCursor = ByteCursorFromString(m_serverReference.value());
+ raw_options.server_reference = &m_serverReferenceCursor;
+ }
+
+ s_AllocateUnderlyingUserProperties(m_userPropertiesStorage, m_userProperties, m_allocator);
+ raw_options.user_properties = m_userPropertiesStorage;
+ raw_options.user_property_count = m_userProperties.size();
+
+ return true;
+ }
+
+ DisconnectPacket &DisconnectPacket::withReasonCode(const DisconnectReasonCode code) noexcept
+ {
+ m_reasonCode = code;
+ return *this;
+ }
+
+ DisconnectPacket &DisconnectPacket::withSessionExpiryIntervalSec(const uint32_t second) noexcept
+ {
+ m_sessionExpiryIntervalSec = second;
+ return *this;
+ }
+
+ DisconnectPacket &DisconnectPacket::withReasonString(Crt::String reason) noexcept
+ {
+ m_reasonString = std::move(reason);
+ return *this;
+ }
+
+ DisconnectPacket &DisconnectPacket::withServerReference(Crt::String server_reference) noexcept
+ {
+ m_serverReference = std::move(server_reference);
+ return *this;
+ }
+
+ DisconnectPacket &DisconnectPacket::withUserProperties(const Vector<UserProperty> &userProperties) noexcept
+ {
+ m_userProperties = userProperties;
+ return *this;
+ }
+
+ DisconnectPacket &DisconnectPacket::withUserProperties(Vector<UserProperty> &&userProperties) noexcept
+ {
+ m_userProperties = userProperties;
+ return *this;
+ }
+
+ DisconnectPacket &DisconnectPacket::withUserProperty(UserProperty &&property) noexcept
+ {
+ m_userProperties.push_back(std::move(property));
+ return *this;
+ }
+
+ DisconnectReasonCode DisconnectPacket::getReasonCode() const noexcept { return m_reasonCode; }
+
+ const Crt::Optional<uint32_t> &DisconnectPacket::getSessionExpiryIntervalSec() const noexcept
+ {
+ return m_sessionExpiryIntervalSec;
+ }
+
+ const Crt::Optional<Crt::String> &DisconnectPacket::getReasonString() const noexcept
+ {
+ return m_reasonString;
+ }
+
+ const Crt::Optional<Crt::String> &DisconnectPacket::getServerReference() const noexcept
+ {
+ return m_serverReference;
+ }
+
+ const Crt::Vector<UserProperty> &DisconnectPacket::getUserProperties() const noexcept
+ {
+ return m_userProperties;
+ }
+
+ DisconnectPacket::DisconnectPacket(
+ const aws_mqtt5_packet_disconnect_view &packet,
+ Allocator *allocator) noexcept
+ : m_allocator(allocator), m_userPropertiesStorage(nullptr)
+ {
+ m_reasonCode = packet.reason_code;
+
+ setPacketOptional(m_sessionExpiryIntervalSec, packet.session_expiry_interval_seconds);
+ setPacketStringOptional(m_reasonString, packet.reason_string);
+ setPacketStringOptional(m_serverReference, packet.server_reference);
+ setUserProperties(m_userProperties, packet.user_properties, packet.user_property_count);
+ }
+
+ DisconnectPacket::~DisconnectPacket()
+ {
+ if (m_userPropertiesStorage != nullptr)
+ {
+ aws_mem_release(m_allocator, m_userPropertiesStorage);
+ }
+ }
+
+ PubAckPacket::PubAckPacket(const aws_mqtt5_packet_puback_view &packet, Allocator * /*allocator*/) noexcept
+ {
+ m_reasonCode = packet.reason_code;
+ setPacketStringOptional(m_reasonString, packet.reason_string);
+ setUserProperties(m_userProperties, packet.user_properties, packet.user_property_count);
+ }
+
+ PubAckReasonCode PubAckPacket::getReasonCode() const noexcept { return m_reasonCode; }
+
+ const Crt::Optional<Crt::String> &PubAckPacket::getReasonString() const noexcept { return m_reasonString; }
+
+ const Crt::Vector<UserProperty> &PubAckPacket::getUserProperties() const noexcept
+ {
+ return m_userProperties;
+ }
+
+ ConnAckPacket::ConnAckPacket(
+ const aws_mqtt5_packet_connack_view &packet,
+ Allocator * /*allocator*/) noexcept
+ {
+ m_sessionPresent = packet.session_present;
+ m_reasonCode = packet.reason_code;
+ setPacketOptional(m_sessionExpiryInterval, packet.session_expiry_interval);
+ setPacketOptional(m_receiveMaximum, packet.receive_maximum);
+ setPacketOptional(m_maximumQOS, packet.maximum_qos);
+ setPacketOptional(m_retainAvailable, packet.retain_available);
+ setPacketOptional(m_maximumPacketSize, packet.maximum_packet_size);
+ setPacketStringOptional(m_assignedClientIdentifier, packet.assigned_client_identifier);
+ setPacketOptional(m_topicAliasMaximum, packet.topic_alias_maximum);
+ setPacketStringOptional(m_reasonString, packet.reason_string);
+ setUserProperties(m_userProperties, packet.user_properties, packet.user_property_count);
+ setPacketOptional(m_wildcardSubscriptionsAvaliable, packet.wildcard_subscriptions_available);
+ setPacketOptional(m_subscriptionIdentifiersAvaliable, packet.subscription_identifiers_available);
+ setPacketOptional(m_sharedSubscriptionsAvaliable, packet.shared_subscriptions_available);
+ setPacketOptional(m_serverKeepAlive, packet.server_keep_alive);
+ setPacketStringOptional(m_responseInformation, packet.response_information);
+ setPacketStringOptional(m_serverReference, packet.server_reference);
+ }
+
+ bool ConnAckPacket::getSessionPresent() const noexcept { return m_sessionPresent; }
+
+ ConnectReasonCode ConnAckPacket::getReasonCode() const noexcept { return m_reasonCode; }
+
+ const Crt::Optional<uint32_t> &ConnAckPacket::getSessionExpiryInterval() const noexcept
+ {
+ return m_sessionExpiryInterval;
+ }
+
+ const Crt::Optional<uint16_t> &ConnAckPacket::getReceiveMaximum() const noexcept
+ {
+ return m_receiveMaximum;
+ }
+
+ const Crt::Optional<QOS> &ConnAckPacket::getMaximumQOS() const noexcept { return m_maximumQOS; }
+
+ const Crt::Optional<bool> &ConnAckPacket::getRetainAvailable() const noexcept { return m_retainAvailable; }
+
+ const Crt::Optional<uint32_t> &ConnAckPacket::getMaximumPacketSize() const noexcept
+ {
+ return m_maximumPacketSize;
+ }
+
+ const Crt::Optional<String> &ConnAckPacket::getAssignedClientIdentifier() const noexcept
+ {
+ return m_assignedClientIdentifier;
+ }
+
+ const Crt::Optional<uint16_t> ConnAckPacket::getTopicAliasMaximum() const noexcept
+ {
+ return m_topicAliasMaximum;
+ }
+
+ const Crt::Optional<String> &ConnAckPacket::getReasonString() const noexcept { return m_reasonString; }
+
+ const Vector<UserProperty> &ConnAckPacket::getUserProperty() const noexcept { return m_userProperties; }
+
+ const Crt::Optional<bool> &ConnAckPacket::getWildcardSubscriptionsAvaliable() const noexcept
+ {
+ return m_wildcardSubscriptionsAvaliable;
+ }
+
+ const Crt::Optional<bool> &ConnAckPacket::getSubscriptionIdentifiersAvaliable() const noexcept
+ {
+ return m_subscriptionIdentifiersAvaliable;
+ }
+
+ const Crt::Optional<bool> &ConnAckPacket::getSharedSubscriptionsAvaliable() const noexcept
+ {
+ return m_sharedSubscriptionsAvaliable;
+ }
+
+ const Crt::Optional<uint16_t> &ConnAckPacket::getServerKeepAlive() const noexcept
+ {
+ return m_serverKeepAlive;
+ }
+
+ const Crt::Optional<String> &ConnAckPacket::getResponseInformation() const noexcept
+ {
+ return m_responseInformation;
+ }
+
+ const Crt::Optional<String> &ConnAckPacket::getServerReference() const noexcept
+ {
+ return m_serverReference;
+ }
+
+ Subscription::Subscription(Allocator *allocator)
+ : m_allocator(allocator), m_topicFilter(""), m_qos(QOS::AWS_MQTT5_QOS_AT_MOST_ONCE), m_noLocal(false),
+ m_retain(false), m_retainHnadlingType(AWS_MQTT5_RHT_SEND_ON_SUBSCRIBE)
+
+ {
+ }
+
+ Subscription::Subscription(Crt::String topicFilter, Mqtt5::QOS qos, Allocator *allocator)
+ : m_allocator(allocator), m_topicFilter(std::move(topicFilter)), m_qos(qos), m_noLocal(false),
+ m_retain(false), m_retainHnadlingType(AWS_MQTT5_RHT_SEND_ON_SUBSCRIBE)
+ {
+ }
+
+ Subscription &Subscription::withTopicFilter(Crt::String topicFilter) noexcept
+ {
+ m_topicFilter = std::move(topicFilter);
+ return *this;
+ }
+
+ Subscription &Subscription::withQOS(Mqtt5::QOS qos) noexcept
+ {
+ m_qos = qos;
+ return *this;
+ }
+ Subscription &Subscription::withNoLocal(bool noLocal) noexcept
+ {
+ m_noLocal = noLocal;
+ return *this;
+ }
+ Subscription &Subscription::withRetain(bool retain) noexcept
+ {
+ m_retain = retain;
+ return *this;
+ }
+ Subscription &Subscription::withRetainHandlingType(RetainHandlingType retainHandlingType) noexcept
+ {
+ m_retainHnadlingType = retainHandlingType;
+ return *this;
+ }
+
+ bool Subscription::initializeRawOptions(aws_mqtt5_subscription_view &raw_options) const noexcept
+ {
+ AWS_ZERO_STRUCT(raw_options);
+ raw_options.topic_filter = ByteCursorFromString(m_topicFilter);
+ raw_options.no_local = m_noLocal;
+ raw_options.qos = m_qos;
+ raw_options.retain_as_published = m_retain;
+ raw_options.retain_handling_type = m_retainHnadlingType;
+ return true;
+ }
+
+ Subscription::Subscription(const Subscription &toCopy) noexcept
+ : m_allocator(toCopy.m_allocator), m_topicFilter(toCopy.m_topicFilter), m_qos(toCopy.m_qos),
+ m_noLocal(toCopy.m_noLocal), m_retain(toCopy.m_retain),
+ m_retainHnadlingType(toCopy.m_retainHnadlingType)
+ {
+ }
+
+ Subscription::Subscription(Subscription &&toMove) noexcept
+ : m_allocator(toMove.m_allocator), m_topicFilter(std::move(toMove.m_topicFilter)), m_qos(toMove.m_qos),
+ m_noLocal(toMove.m_noLocal), m_retain(toMove.m_retain),
+ m_retainHnadlingType(toMove.m_retainHnadlingType)
+ {
+ }
+
+ Subscription &Subscription::operator=(const Subscription &toCopy) noexcept
+ {
+ if (&toCopy != this)
+ {
+ m_allocator = toCopy.m_allocator;
+ m_qos = toCopy.m_qos;
+ m_topicFilter = toCopy.m_topicFilter;
+ m_noLocal = toCopy.m_noLocal;
+ m_retain = toCopy.m_retain;
+ m_retainHnadlingType = toCopy.m_retainHnadlingType;
+ }
+ return *this;
+ }
+
+ Subscription &Subscription::operator=(Subscription &&toMove) noexcept
+ {
+ if (&toMove != this)
+ {
+ m_allocator = toMove.m_allocator;
+ m_qos = toMove.m_qos;
+ m_topicFilter = std::move(toMove.m_topicFilter);
+ m_noLocal = toMove.m_noLocal;
+ m_retain = toMove.m_retain;
+ m_retainHnadlingType = toMove.m_retainHnadlingType;
+ }
+ return *this;
+ }
+
+ SubscribePacket::SubscribePacket(Allocator *allocator) noexcept
+ : m_allocator(allocator), m_subscriptionViewStorage(nullptr), m_userPropertiesStorage(nullptr)
+ {
+ }
+
+ SubscribePacket &SubscribePacket::withUserProperties(const Vector<UserProperty> &userProperties) noexcept
+ {
+ m_userProperties = userProperties;
+ return *this;
+ }
+
+ SubscribePacket &SubscribePacket::withUserProperties(Vector<UserProperty> &&userProperties) noexcept
+ {
+ m_userProperties = userProperties;
+ return *this;
+ }
+
+ SubscribePacket &SubscribePacket::withUserProperty(UserProperty &&property) noexcept
+ {
+ m_userProperties.push_back(std::move(property));
+ return *this;
+ }
+
+ SubscribePacket &SubscribePacket::withSubscriptionIdentifier(uint32_t identifier) noexcept
+ {
+ m_subscriptionIdentifier = identifier;
+ return *this;
+ }
+
+ SubscribePacket &SubscribePacket::withSubscriptions(const Crt::Vector<Subscription> &subscriptions) noexcept
+ {
+ m_subscriptions = subscriptions;
+
+ return *this;
+ }
+
+ SubscribePacket &SubscribePacket::withSubscriptions(Vector<Subscription> &&subscriptions) noexcept
+ {
+ m_subscriptions = subscriptions;
+ return *this;
+ }
+
+ SubscribePacket &SubscribePacket::withSubscription(Subscription &&subscription) noexcept
+ {
+ m_subscriptions.push_back(subscription);
+ return *this;
+ }
+
+ bool SubscribePacket::initializeRawOptions(aws_mqtt5_packet_subscribe_view &raw_options) noexcept
+ {
+ AWS_ZERO_STRUCT(raw_options);
+
+ s_AllocateUnderlyingSubscription(m_subscriptionViewStorage, m_subscriptions, m_allocator);
+ raw_options.subscription_count = m_subscriptions.size();
+ raw_options.subscriptions = m_subscriptionViewStorage;
+
+ s_AllocateUnderlyingUserProperties(m_userPropertiesStorage, m_userProperties, m_allocator);
+ raw_options.user_properties = m_userPropertiesStorage;
+ raw_options.user_property_count = m_userProperties.size();
+
+ return true;
+ }
+
+ SubscribePacket::~SubscribePacket()
+ {
+ if (m_userPropertiesStorage != nullptr)
+ {
+ aws_mem_release(m_allocator, m_userPropertiesStorage);
+ m_userPropertiesStorage = nullptr;
+ }
+
+ if (m_subscriptionViewStorage != nullptr)
+ {
+ aws_mem_release(m_allocator, m_subscriptionViewStorage);
+ m_subscriptionViewStorage = nullptr;
+ }
+ }
+
+ SubAckPacket::SubAckPacket(const aws_mqtt5_packet_suback_view &packet, Allocator * /*allocator*/) noexcept
+ {
+ setPacketStringOptional(m_reasonString, packet.reason_string);
+ setUserProperties(m_userProperties, packet.user_properties, packet.user_property_count);
+ for (size_t i = 0; i < packet.reason_code_count; i++)
+ {
+ m_reasonCodes.push_back(*(packet.reason_codes + i));
+ }
+ }
+
+ const Crt::Optional<Crt::String> &SubAckPacket::getReasonString() const noexcept { return m_reasonString; }
+
+ const Crt::Vector<UserProperty> &SubAckPacket::getUserProperties() const noexcept
+ {
+ return m_userProperties;
+ }
+
+ const Crt::Vector<SubAckReasonCode> &SubAckPacket::getReasonCodes() const noexcept { return m_reasonCodes; }
+
+ UnsubscribePacket::UnsubscribePacket(Allocator *allocator) noexcept
+ : m_allocator(allocator), m_userPropertiesStorage(nullptr)
+ {
+ AWS_ZERO_STRUCT(m_topicFiltersList);
+ }
+
+ UnsubscribePacket &UnsubscribePacket::withTopicFilter(Crt::String topicFilter) noexcept
+ {
+ m_topicFilters.push_back(std::move(topicFilter));
+ return *this;
+ }
+
+ UnsubscribePacket &UnsubscribePacket::withTopicFilters(Crt::Vector<String> topicFilters) noexcept
+ {
+ m_topicFilters = std::move(topicFilters);
+
+ return *this;
+ }
+
+ UnsubscribePacket &UnsubscribePacket::withUserProperties(
+ const Vector<UserProperty> &userProperties) noexcept
+ {
+ m_userProperties = userProperties;
+ return *this;
+ }
+
+ UnsubscribePacket &UnsubscribePacket::withUserProperties(Vector<UserProperty> &&userProperties) noexcept
+ {
+ m_userProperties = userProperties;
+ return *this;
+ }
+
+ UnsubscribePacket &UnsubscribePacket::withUserProperty(UserProperty &&property) noexcept
+ {
+ m_userProperties.push_back(std::move(property));
+ return *this;
+ }
+
+ bool UnsubscribePacket::initializeRawOptions(aws_mqtt5_packet_unsubscribe_view &raw_options) noexcept
+ {
+ AWS_ZERO_STRUCT(raw_options);
+
+ s_AllocateStringVector(m_topicFiltersList, m_topicFilters, m_allocator);
+ raw_options.topic_filters = static_cast<aws_byte_cursor *>(m_topicFiltersList.data);
+ raw_options.topic_filter_count = m_topicFilters.size();
+
+ s_AllocateUnderlyingUserProperties(m_userPropertiesStorage, m_userProperties, m_allocator);
+ raw_options.user_properties = m_userPropertiesStorage;
+ raw_options.user_property_count = m_userProperties.size();
+
+ return true;
+ }
+
+ UnsubscribePacket::~UnsubscribePacket()
+ {
+ aws_array_list_clean_up(&m_topicFiltersList);
+ AWS_ZERO_STRUCT(m_topicFiltersList);
+
+ if (m_userPropertiesStorage != nullptr)
+ {
+ aws_mem_release(m_allocator, m_userPropertiesStorage);
+ m_userPropertiesStorage = nullptr;
+ }
+ }
+
+ UnSubAckPacket::UnSubAckPacket(const aws_mqtt5_packet_unsuback_view &packet, Allocator *allocator) noexcept
+ {
+ (void)allocator;
+
+ setPacketStringOptional(m_reasonString, packet.reason_string);
+
+ for (size_t i = 0; i < packet.reason_code_count; i++)
+ {
+ m_reasonCodes.push_back(*(packet.reason_codes + i));
+ }
+ setUserProperties(m_userProperties, packet.user_properties, packet.user_property_count);
+ }
+
+ const Crt::Optional<Crt::String> &UnSubAckPacket::getReasonString() const noexcept
+ {
+ return m_reasonString;
+ }
+
+ const Crt::Vector<UserProperty> &UnSubAckPacket::getUserProperties() const noexcept
+ {
+ return m_userProperties;
+ }
+
+ const Crt::Vector<UnSubAckReasonCode> &UnSubAckPacket::getReasonCodes() const noexcept
+ {
+ return m_reasonCodes;
+ }
+
+ NegotiatedSettings::NegotiatedSettings(
+ const aws_mqtt5_negotiated_settings &negotiated_settings,
+ Allocator *allocator) noexcept
+ {
+ (void)allocator;
+
+ m_maximumQOS = negotiated_settings.maximum_qos;
+ m_sessionExpiryIntervalSec = negotiated_settings.session_expiry_interval;
+ m_receiveMaximumFromServer = negotiated_settings.receive_maximum_from_server;
+
+ m_maximumPacketSizeBytes = negotiated_settings.maximum_packet_size_to_server;
+ m_serverKeepAliveSec = negotiated_settings.server_keep_alive;
+
+ m_retainAvailable = negotiated_settings.retain_available;
+ m_wildcardSubscriptionsAvaliable = negotiated_settings.wildcard_subscriptions_available;
+ m_subscriptionIdentifiersAvaliable = negotiated_settings.subscription_identifiers_available;
+ m_sharedSubscriptionsAvaliable = negotiated_settings.shared_subscriptions_available;
+ m_rejoinedSession = negotiated_settings.rejoined_session;
+
+ m_clientId = Crt::String(
+ (const char *)negotiated_settings.client_id_storage.buffer,
+ negotiated_settings.client_id_storage.len);
+ }
+
+ Mqtt5::QOS NegotiatedSettings::getMaximumQOS() const noexcept { return m_maximumQOS; }
+
+ uint32_t NegotiatedSettings::getSessionExpiryIntervalSec() const noexcept
+ {
+ return m_sessionExpiryIntervalSec;
+ }
+
+ uint16_t NegotiatedSettings::getReceiveMaximumFromServer() const noexcept
+ {
+ return m_receiveMaximumFromServer;
+ }
+
+ uint32_t NegotiatedSettings::getMaximumPacketSizeBytes() const noexcept { return m_maximumPacketSizeBytes; }
+
+ uint16_t NegotiatedSettings::getServerKeepAlive() const noexcept { return m_serverKeepAliveSec; }
+
+ bool NegotiatedSettings::getRetainAvailable() const noexcept { return m_retainAvailable; }
+
+ bool NegotiatedSettings::getWildcardSubscriptionsAvaliable() const noexcept
+ {
+ return m_wildcardSubscriptionsAvaliable;
+ }
+
+ bool NegotiatedSettings::getSubscriptionIdentifiersAvaliable() const noexcept
+ {
+ return m_subscriptionIdentifiersAvaliable;
+ }
+
+ bool NegotiatedSettings::getSharedSubscriptionsAvaliable() const noexcept
+ {
+ return m_sharedSubscriptionsAvaliable;
+ }
+
+ bool NegotiatedSettings::getRejoinedSession() const noexcept { return m_rejoinedSession; }
+
+ const Crt::String &NegotiatedSettings::getClientId() const noexcept { return m_clientId; }
+
+ PublishResult::PublishResult() : m_ack(nullptr), m_errorCode(0) {}
+
+ PublishResult::PublishResult(std::shared_ptr<PubAckPacket> puback) : m_errorCode(0) { m_ack = puback; }
+
+ PublishResult::PublishResult(int error) : m_ack(nullptr), m_errorCode(error) {}
+
+ PublishResult::~PublishResult() noexcept { m_ack.reset(); }
+
+ } // namespace Mqtt5
+ } // namespace Crt
+} // namespace Aws
diff --git a/contrib/restricted/aws/aws-crt-cpp/source/mqtt/MqttClient.cpp b/contrib/restricted/aws/aws-crt-cpp/source/mqtt/MqttClient.cpp
new file mode 100644
index 0000000000..e36c591237
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/source/mqtt/MqttClient.cpp
@@ -0,0 +1,816 @@
+/**
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+#include <aws/crt/mqtt/MqttClient.h>
+
+#include <aws/crt/Api.h>
+#include <aws/crt/StlAllocator.h>
+#include <aws/crt/http/HttpProxyStrategy.h>
+#include <aws/crt/http/HttpRequestResponse.h>
+#include <aws/crt/io/Bootstrap.h>
+
+#include <utility>
+
+#define AWS_MQTT_MAX_TOPIC_LENGTH 65535
+
+namespace Aws
+{
+ namespace Crt
+ {
+ namespace Mqtt
+ {
+ void MqttConnection::s_onConnectionInterrupted(aws_mqtt_client_connection *, int errorCode, void *userData)
+ {
+ auto connWrapper = reinterpret_cast<MqttConnection *>(userData);
+ if (connWrapper->OnConnectionInterrupted)
+ {
+ connWrapper->OnConnectionInterrupted(*connWrapper, errorCode);
+ }
+ }
+
+ void MqttConnection::s_onConnectionResumed(
+ aws_mqtt_client_connection *,
+ ReturnCode returnCode,
+ bool sessionPresent,
+ void *userData)
+ {
+ auto connWrapper = reinterpret_cast<MqttConnection *>(userData);
+ if (connWrapper->OnConnectionResumed)
+ {
+ connWrapper->OnConnectionResumed(*connWrapper, returnCode, sessionPresent);
+ }
+ }
+
+ void MqttConnection::s_onConnectionCompleted(
+ aws_mqtt_client_connection *,
+ int errorCode,
+ enum aws_mqtt_connect_return_code returnCode,
+ bool sessionPresent,
+ void *userData)
+ {
+ auto connWrapper = reinterpret_cast<MqttConnection *>(userData);
+ if (connWrapper->OnConnectionCompleted)
+ {
+ connWrapper->OnConnectionCompleted(*connWrapper, errorCode, returnCode, sessionPresent);
+ }
+ }
+
+ void MqttConnection::s_onDisconnect(aws_mqtt_client_connection *, void *userData)
+ {
+ auto connWrapper = reinterpret_cast<MqttConnection *>(userData);
+ if (connWrapper->OnDisconnect)
+ {
+ connWrapper->OnDisconnect(*connWrapper);
+ }
+ }
+
+ struct PubCallbackData
+ {
+ PubCallbackData() : connection(nullptr), allocator(nullptr) {}
+
+ MqttConnection *connection;
+ OnMessageReceivedHandler onMessageReceived;
+ Allocator *allocator;
+ };
+
+ static void s_cleanUpOnPublishData(void *userData)
+ {
+ auto callbackData = reinterpret_cast<PubCallbackData *>(userData);
+ Crt::Delete(callbackData, callbackData->allocator);
+ }
+
+ void MqttConnection::s_onPublish(
+ aws_mqtt_client_connection *,
+ const aws_byte_cursor *topic,
+ const aws_byte_cursor *payload,
+ bool dup,
+ enum aws_mqtt_qos qos,
+ bool retain,
+ void *userData)
+ {
+ auto callbackData = reinterpret_cast<PubCallbackData *>(userData);
+
+ if (callbackData->onMessageReceived)
+ {
+ String topicStr(reinterpret_cast<char *>(topic->ptr), topic->len);
+ ByteBuf payloadBuf = aws_byte_buf_from_array(payload->ptr, payload->len);
+ callbackData->onMessageReceived(
+ *(callbackData->connection), topicStr, payloadBuf, dup, qos, retain);
+ }
+ }
+
+ struct OpCompleteCallbackData
+ {
+ OpCompleteCallbackData() : connection(nullptr), topic(nullptr), allocator(nullptr) {}
+
+ MqttConnection *connection;
+ OnOperationCompleteHandler onOperationComplete;
+ const char *topic;
+ Allocator *allocator;
+ };
+
+ void MqttConnection::s_onOpComplete(
+ aws_mqtt_client_connection *,
+ uint16_t packetId,
+ int errorCode,
+ void *userData)
+ {
+ auto callbackData = reinterpret_cast<OpCompleteCallbackData *>(userData);
+
+ if (callbackData->onOperationComplete)
+ {
+ callbackData->onOperationComplete(*callbackData->connection, packetId, errorCode);
+ }
+
+ if (callbackData->topic)
+ {
+ aws_mem_release(
+ callbackData->allocator, reinterpret_cast<void *>(const_cast<char *>(callbackData->topic)));
+ }
+
+ Crt::Delete(callbackData, callbackData->allocator);
+ }
+
+ struct SubAckCallbackData
+ {
+ SubAckCallbackData() : connection(nullptr), topic(nullptr), allocator(nullptr) {}
+
+ MqttConnection *connection;
+ OnSubAckHandler onSubAck;
+ const char *topic;
+ Allocator *allocator;
+ };
+
+ void MqttConnection::s_onSubAck(
+ aws_mqtt_client_connection *,
+ uint16_t packetId,
+ const struct aws_byte_cursor *topic,
+ enum aws_mqtt_qos qos,
+ int errorCode,
+ void *userData)
+ {
+ auto callbackData = reinterpret_cast<SubAckCallbackData *>(userData);
+
+ if (callbackData->onSubAck)
+ {
+ String topicStr(reinterpret_cast<char *>(topic->ptr), topic->len);
+ callbackData->onSubAck(*callbackData->connection, packetId, topicStr, qos, errorCode);
+ }
+
+ if (callbackData->topic)
+ {
+ aws_mem_release(
+ callbackData->allocator, reinterpret_cast<void *>(const_cast<char *>(callbackData->topic)));
+ }
+
+ Crt::Delete(callbackData, callbackData->allocator);
+ }
+
+ struct MultiSubAckCallbackData
+ {
+ MultiSubAckCallbackData() : connection(nullptr), topic(nullptr), allocator(nullptr) {}
+
+ MqttConnection *connection;
+ OnMultiSubAckHandler onSubAck;
+ const char *topic;
+ Allocator *allocator;
+ };
+
+ void MqttConnection::s_onMultiSubAck(
+ aws_mqtt_client_connection *,
+ uint16_t packetId,
+ const struct aws_array_list *topicSubacks,
+ int errorCode,
+ void *userData)
+ {
+ auto callbackData = reinterpret_cast<MultiSubAckCallbackData *>(userData);
+
+ if (callbackData->onSubAck)
+ {
+ size_t length = aws_array_list_length(topicSubacks);
+ Vector<String> topics;
+ topics.reserve(length);
+ QOS qos = AWS_MQTT_QOS_AT_MOST_ONCE;
+ for (size_t i = 0; i < length; ++i)
+ {
+ aws_mqtt_topic_subscription *subscription = NULL;
+ aws_array_list_get_at(topicSubacks, &subscription, i);
+ topics.push_back(
+ String(reinterpret_cast<char *>(subscription->topic.ptr), subscription->topic.len));
+ qos = subscription->qos;
+ }
+
+ callbackData->onSubAck(*callbackData->connection, packetId, topics, qos, errorCode);
+ }
+
+ if (callbackData->topic)
+ {
+ aws_mem_release(
+ callbackData->allocator, reinterpret_cast<void *>(const_cast<char *>(callbackData->topic)));
+ }
+
+ Crt::Delete(callbackData, callbackData->allocator);
+ }
+
+ void MqttConnection::s_connectionInit(
+ MqttConnection *self,
+ const char *hostName,
+ uint16_t port,
+ const Io::SocketOptions &socketOptions)
+ {
+
+ self->m_hostName = String(hostName);
+ self->m_port = port;
+ self->m_socketOptions = socketOptions;
+
+ self->m_underlyingConnection = aws_mqtt_client_connection_new(self->m_owningClient);
+
+ if (self->m_underlyingConnection)
+ {
+ aws_mqtt_client_connection_set_connection_interruption_handlers(
+ self->m_underlyingConnection,
+ MqttConnection::s_onConnectionInterrupted,
+ self,
+ MqttConnection::s_onConnectionResumed,
+ self);
+ }
+ }
+
+ void MqttConnection::s_onWebsocketHandshake(
+ struct aws_http_message *rawRequest,
+ void *user_data,
+ aws_mqtt_transform_websocket_handshake_complete_fn *complete_fn,
+ void *complete_ctx)
+ {
+ auto connection = reinterpret_cast<MqttConnection *>(user_data);
+
+ Allocator *allocator = connection->m_owningClient->allocator;
+ // we have to do this because of private constructors.
+ auto toSeat =
+ reinterpret_cast<Http::HttpRequest *>(aws_mem_acquire(allocator, sizeof(Http::HttpRequest)));
+ toSeat = new (toSeat) Http::HttpRequest(allocator, rawRequest);
+
+ std::shared_ptr<Http::HttpRequest> request = std::shared_ptr<Http::HttpRequest>(
+ toSeat, [allocator](Http::HttpRequest *ptr) { Crt::Delete(ptr, allocator); });
+
+ auto onInterceptComplete =
+ [complete_fn,
+ complete_ctx](const std::shared_ptr<Http::HttpRequest> &transformedRequest, int errorCode) {
+ complete_fn(transformedRequest->GetUnderlyingMessage(), errorCode, complete_ctx);
+ };
+
+ connection->WebsocketInterceptor(request, onInterceptComplete);
+ }
+
+ MqttConnection::MqttConnection(
+ aws_mqtt_client *client,
+ const char *hostName,
+ uint16_t port,
+ const Io::SocketOptions &socketOptions,
+ const Crt::Io::TlsContext &tlsContext,
+ bool useWebsocket) noexcept
+ : m_owningClient(client), m_tlsContext(tlsContext), m_tlsOptions(tlsContext.NewConnectionOptions()),
+ m_onAnyCbData(nullptr), m_useTls(true), m_useWebsocket(useWebsocket)
+ {
+ s_connectionInit(this, hostName, port, socketOptions);
+ }
+
+ MqttConnection::MqttConnection(
+ aws_mqtt_client *client,
+ const char *hostName,
+ uint16_t port,
+ const Io::SocketOptions &socketOptions,
+ bool useWebsocket) noexcept
+ : m_owningClient(client), m_onAnyCbData(nullptr), m_useTls(false), m_useWebsocket(useWebsocket)
+ {
+ s_connectionInit(this, hostName, port, socketOptions);
+ }
+
+ MqttConnection::~MqttConnection()
+ {
+ if (*this)
+ {
+ aws_mqtt_client_connection_release(m_underlyingConnection);
+
+ if (m_onAnyCbData)
+ {
+ auto pubCallbackData = reinterpret_cast<PubCallbackData *>(m_onAnyCbData);
+ Crt::Delete(pubCallbackData, pubCallbackData->allocator);
+ }
+ }
+ }
+
+ MqttConnection::operator bool() const noexcept { return m_underlyingConnection != nullptr; }
+
+ int MqttConnection::LastError() const noexcept { return aws_last_error(); }
+
+ bool MqttConnection::SetWill(const char *topic, QOS qos, bool retain, const ByteBuf &payload) noexcept
+ {
+ ByteBuf topicBuf = aws_byte_buf_from_c_str(topic);
+ ByteCursor topicCur = aws_byte_cursor_from_buf(&topicBuf);
+ ByteCursor payloadCur = aws_byte_cursor_from_buf(&payload);
+
+ return aws_mqtt_client_connection_set_will(
+ m_underlyingConnection, &topicCur, qos, retain, &payloadCur) == 0;
+ }
+
+ bool MqttConnection::SetLogin(const char *userName, const char *password) noexcept
+ {
+ ByteBuf userNameBuf = aws_byte_buf_from_c_str(userName);
+ ByteCursor userNameCur = aws_byte_cursor_from_buf(&userNameBuf);
+
+ ByteCursor *pwdCurPtr = nullptr;
+ ByteCursor pwdCur;
+
+ if (password)
+ {
+ pwdCur = ByteCursorFromCString(password);
+ pwdCurPtr = &pwdCur;
+ }
+ return aws_mqtt_client_connection_set_login(m_underlyingConnection, &userNameCur, pwdCurPtr) == 0;
+ }
+
+ bool MqttConnection::SetWebsocketProxyOptions(
+ const Http::HttpClientConnectionProxyOptions &proxyOptions) noexcept
+ {
+ m_proxyOptions = proxyOptions;
+ return true;
+ }
+
+ bool MqttConnection::SetHttpProxyOptions(
+ const Http::HttpClientConnectionProxyOptions &proxyOptions) noexcept
+ {
+ m_proxyOptions = proxyOptions;
+ return true;
+ }
+
+ bool MqttConnection::SetReconnectTimeout(uint64_t min_seconds, uint64_t max_seconds) noexcept
+ {
+ return aws_mqtt_client_connection_set_reconnect_timeout(
+ m_underlyingConnection, min_seconds, max_seconds) == 0;
+ }
+
+ bool MqttConnection::Connect(
+ const char *clientId,
+ bool cleanSession,
+ uint16_t keepAliveTime,
+ uint32_t pingTimeoutMs,
+ uint32_t protocolOperationTimeoutMs) noexcept
+ {
+ aws_mqtt_connection_options options;
+ AWS_ZERO_STRUCT(options);
+ options.client_id = aws_byte_cursor_from_c_str(clientId);
+ options.host_name = aws_byte_cursor_from_array(
+ reinterpret_cast<const uint8_t *>(m_hostName.data()), m_hostName.length());
+ options.tls_options =
+ m_useTls ? const_cast<aws_tls_connection_options *>(m_tlsOptions.GetUnderlyingHandle()) : nullptr;
+ options.port = m_port;
+ options.socket_options = &m_socketOptions.GetImpl();
+ options.clean_session = cleanSession;
+ options.keep_alive_time_secs = keepAliveTime;
+ options.ping_timeout_ms = pingTimeoutMs;
+ options.protocol_operation_timeout_ms = protocolOperationTimeoutMs;
+ options.on_connection_complete = MqttConnection::s_onConnectionCompleted;
+ options.user_data = this;
+
+ if (m_useWebsocket)
+ {
+ if (WebsocketInterceptor)
+ {
+ if (aws_mqtt_client_connection_use_websockets(
+ m_underlyingConnection, MqttConnection::s_onWebsocketHandshake, this, nullptr, nullptr))
+ {
+ return false;
+ }
+ }
+ else
+ {
+ if (aws_mqtt_client_connection_use_websockets(
+ m_underlyingConnection, nullptr, nullptr, nullptr, nullptr))
+ {
+ return false;
+ }
+ }
+ }
+
+ if (m_proxyOptions)
+ {
+ struct aws_http_proxy_options proxyOptions;
+ m_proxyOptions->InitializeRawProxyOptions(proxyOptions);
+
+ if (aws_mqtt_client_connection_set_http_proxy_options(m_underlyingConnection, &proxyOptions))
+ {
+ return false;
+ }
+ }
+
+ return aws_mqtt_client_connection_connect(m_underlyingConnection, &options) == AWS_OP_SUCCESS;
+ }
+
+ bool MqttConnection::Disconnect() noexcept
+ {
+ return aws_mqtt_client_connection_disconnect(
+ m_underlyingConnection, MqttConnection::s_onDisconnect, this) == AWS_OP_SUCCESS;
+ }
+
+ aws_mqtt_client_connection *MqttConnection::GetUnderlyingConnection() noexcept
+ {
+ return m_underlyingConnection;
+ }
+
+ bool MqttConnection::SetOnMessageHandler(OnPublishReceivedHandler &&onPublish) noexcept
+ {
+ return SetOnMessageHandler(
+ [onPublish](
+ MqttConnection &connection, const String &topic, const ByteBuf &payload, bool, QOS, bool) {
+ onPublish(connection, topic, payload);
+ });
+ }
+
+ bool MqttConnection::SetOnMessageHandler(OnMessageReceivedHandler &&onMessage) noexcept
+ {
+ auto pubCallbackData = Aws::Crt::New<PubCallbackData>(m_owningClient->allocator);
+
+ if (!pubCallbackData)
+ {
+ return false;
+ }
+
+ pubCallbackData->connection = this;
+ pubCallbackData->onMessageReceived = std::move(onMessage);
+ pubCallbackData->allocator = m_owningClient->allocator;
+
+ if (!aws_mqtt_client_connection_set_on_any_publish_handler(
+ m_underlyingConnection, s_onPublish, pubCallbackData))
+ {
+ m_onAnyCbData = reinterpret_cast<void *>(pubCallbackData);
+ return true;
+ }
+
+ Aws::Crt::Delete(pubCallbackData, pubCallbackData->allocator);
+ return false;
+ }
+
+ uint16_t MqttConnection::Subscribe(
+ const char *topicFilter,
+ QOS qos,
+ OnPublishReceivedHandler &&onPublish,
+ OnSubAckHandler &&onSubAck) noexcept
+ {
+ return Subscribe(
+ topicFilter,
+ qos,
+ [onPublish](
+ MqttConnection &connection, const String &topic, const ByteBuf &payload, bool, QOS, bool) {
+ onPublish(connection, topic, payload);
+ },
+ std::move(onSubAck));
+ }
+
+ uint16_t MqttConnection::Subscribe(
+ const char *topicFilter,
+ QOS qos,
+ OnMessageReceivedHandler &&onMessage,
+ OnSubAckHandler &&onSubAck) noexcept
+ {
+ auto pubCallbackData = Crt::New<PubCallbackData>(m_owningClient->allocator);
+
+ if (!pubCallbackData)
+ {
+ return 0;
+ }
+
+ pubCallbackData->connection = this;
+ pubCallbackData->onMessageReceived = std::move(onMessage);
+ pubCallbackData->allocator = m_owningClient->allocator;
+
+ auto subAckCallbackData = Crt::New<SubAckCallbackData>(m_owningClient->allocator);
+
+ if (!subAckCallbackData)
+ {
+ Crt::Delete(pubCallbackData, m_owningClient->allocator);
+ return 0;
+ }
+
+ subAckCallbackData->connection = this;
+ subAckCallbackData->allocator = m_owningClient->allocator;
+ subAckCallbackData->onSubAck = std::move(onSubAck);
+ subAckCallbackData->topic = nullptr;
+ subAckCallbackData->allocator = m_owningClient->allocator;
+
+ ByteBuf topicFilterBuf = aws_byte_buf_from_c_str(topicFilter);
+ ByteCursor topicFilterCur = aws_byte_cursor_from_buf(&topicFilterBuf);
+
+ uint16_t packetId = aws_mqtt_client_connection_subscribe(
+ m_underlyingConnection,
+ &topicFilterCur,
+ qos,
+ s_onPublish,
+ pubCallbackData,
+ s_cleanUpOnPublishData,
+ s_onSubAck,
+ subAckCallbackData);
+
+ if (!packetId)
+ {
+ Crt::Delete(pubCallbackData, pubCallbackData->allocator);
+ Crt::Delete(subAckCallbackData, subAckCallbackData->allocator);
+ }
+
+ return packetId;
+ }
+
+ uint16_t MqttConnection::Subscribe(
+ const Vector<std::pair<const char *, OnPublishReceivedHandler>> &topicFilters,
+ QOS qos,
+ OnMultiSubAckHandler &&onSubAck) noexcept
+ {
+ Vector<std::pair<const char *, OnMessageReceivedHandler>> newTopicFilters;
+ newTopicFilters.reserve(topicFilters.size());
+ for (const auto &pair : topicFilters)
+ {
+ const OnPublishReceivedHandler &pubHandler = pair.second;
+ newTopicFilters.emplace_back(
+ pair.first,
+ [pubHandler](
+ MqttConnection &connection, const String &topic, const ByteBuf &payload, bool, QOS, bool) {
+ pubHandler(connection, topic, payload);
+ });
+ }
+ return Subscribe(newTopicFilters, qos, std::move(onSubAck));
+ }
+
+ uint16_t MqttConnection::Subscribe(
+ const Vector<std::pair<const char *, OnMessageReceivedHandler>> &topicFilters,
+ QOS qos,
+ OnMultiSubAckHandler &&onSubAck) noexcept
+ {
+ uint16_t packetId = 0;
+ auto subAckCallbackData = Crt::New<MultiSubAckCallbackData>(m_owningClient->allocator);
+
+ if (!subAckCallbackData)
+ {
+ return 0;
+ }
+
+ aws_array_list multiPub;
+ AWS_ZERO_STRUCT(multiPub);
+
+ if (aws_array_list_init_dynamic(
+ &multiPub, m_owningClient->allocator, topicFilters.size(), sizeof(aws_mqtt_topic_subscription)))
+ {
+ Crt::Delete(subAckCallbackData, m_owningClient->allocator);
+ return 0;
+ }
+
+ for (auto &topicFilter : topicFilters)
+ {
+ auto pubCallbackData = Crt::New<PubCallbackData>(m_owningClient->allocator);
+
+ if (!pubCallbackData)
+ {
+ goto clean_up;
+ }
+
+ pubCallbackData->connection = this;
+ pubCallbackData->onMessageReceived = topicFilter.second;
+ pubCallbackData->allocator = m_owningClient->allocator;
+
+ ByteBuf topicFilterBuf = aws_byte_buf_from_c_str(topicFilter.first);
+ ByteCursor topicFilterCur = aws_byte_cursor_from_buf(&topicFilterBuf);
+
+ aws_mqtt_topic_subscription subscription;
+ subscription.on_cleanup = s_cleanUpOnPublishData;
+ subscription.on_publish = s_onPublish;
+ subscription.on_publish_ud = pubCallbackData;
+ subscription.qos = qos;
+ subscription.topic = topicFilterCur;
+
+ aws_array_list_push_back(&multiPub, reinterpret_cast<const void *>(&subscription));
+ }
+
+ subAckCallbackData->connection = this;
+ subAckCallbackData->allocator = m_owningClient->allocator;
+ subAckCallbackData->onSubAck = std::move(onSubAck);
+ subAckCallbackData->topic = nullptr;
+ subAckCallbackData->allocator = m_owningClient->allocator;
+
+ packetId = aws_mqtt_client_connection_subscribe_multiple(
+ m_underlyingConnection, &multiPub, s_onMultiSubAck, subAckCallbackData);
+
+ clean_up:
+ if (!packetId)
+ {
+ size_t length = aws_array_list_length(&multiPub);
+ for (size_t i = 0; i < length; ++i)
+ {
+ aws_mqtt_topic_subscription *subscription = NULL;
+ aws_array_list_get_at_ptr(&multiPub, reinterpret_cast<void **>(&subscription), i);
+ auto pubCallbackData = reinterpret_cast<PubCallbackData *>(subscription->on_publish_ud);
+ Crt::Delete(pubCallbackData, m_owningClient->allocator);
+ }
+
+ Crt::Delete(subAckCallbackData, m_owningClient->allocator);
+ }
+
+ aws_array_list_clean_up(&multiPub);
+
+ return packetId;
+ }
+
+ uint16_t MqttConnection::Unsubscribe(
+ const char *topicFilter,
+ OnOperationCompleteHandler &&onOpComplete) noexcept
+ {
+ auto opCompleteCallbackData = Crt::New<OpCompleteCallbackData>(m_owningClient->allocator);
+
+ if (!opCompleteCallbackData)
+ {
+ return 0;
+ }
+
+ opCompleteCallbackData->connection = this;
+ opCompleteCallbackData->allocator = m_owningClient->allocator;
+ opCompleteCallbackData->onOperationComplete = std::move(onOpComplete);
+ opCompleteCallbackData->topic = nullptr;
+ ByteBuf topicFilterBuf = aws_byte_buf_from_c_str(topicFilter);
+ ByteCursor topicFilterCur = aws_byte_cursor_from_buf(&topicFilterBuf);
+
+ uint16_t packetId = aws_mqtt_client_connection_unsubscribe(
+ m_underlyingConnection, &topicFilterCur, s_onOpComplete, opCompleteCallbackData);
+
+ if (!packetId)
+ {
+ Crt::Delete(opCompleteCallbackData, m_owningClient->allocator);
+ }
+
+ return packetId;
+ }
+
+ uint16_t MqttConnection::Publish(
+ const char *topic,
+ QOS qos,
+ bool retain,
+ const ByteBuf &payload,
+ OnOperationCompleteHandler &&onOpComplete) noexcept
+ {
+
+ auto opCompleteCallbackData = Crt::New<OpCompleteCallbackData>(m_owningClient->allocator);
+ if (!opCompleteCallbackData)
+ {
+ return 0;
+ }
+
+ size_t topicLen = strnlen(topic, AWS_MQTT_MAX_TOPIC_LENGTH) + 1;
+ char *topicCpy =
+ reinterpret_cast<char *>(aws_mem_calloc(m_owningClient->allocator, topicLen, sizeof(char)));
+
+ if (!topicCpy)
+ {
+ Crt::Delete(opCompleteCallbackData, m_owningClient->allocator);
+ }
+
+ memcpy(topicCpy, topic, topicLen);
+
+ opCompleteCallbackData->connection = this;
+ opCompleteCallbackData->allocator = m_owningClient->allocator;
+ opCompleteCallbackData->onOperationComplete = std::move(onOpComplete);
+ opCompleteCallbackData->topic = topicCpy;
+ ByteCursor topicCur = aws_byte_cursor_from_array(topicCpy, topicLen - 1);
+
+ ByteCursor payloadCur = aws_byte_cursor_from_buf(&payload);
+ uint16_t packetId = aws_mqtt_client_connection_publish(
+ m_underlyingConnection,
+ &topicCur,
+ qos,
+ retain,
+ &payloadCur,
+ s_onOpComplete,
+ opCompleteCallbackData);
+
+ if (!packetId)
+ {
+ aws_mem_release(m_owningClient->allocator, reinterpret_cast<void *>(topicCpy));
+ Crt::Delete(opCompleteCallbackData, m_owningClient->allocator);
+ }
+
+ return packetId;
+ }
+
+ const MqttConnectionOperationStatistics &MqttConnection::GetOperationStatistics() noexcept
+ {
+ aws_mqtt_connection_operation_statistics m_operationStatisticsNative = {0, 0, 0, 0};
+ if (m_underlyingConnection != nullptr)
+ {
+ aws_mqtt_client_connection_get_stats(m_underlyingConnection, &m_operationStatisticsNative);
+ m_operationStatistics.incompleteOperationCount =
+ m_operationStatisticsNative.incomplete_operation_count;
+ m_operationStatistics.incompleteOperationSize =
+ m_operationStatisticsNative.incomplete_operation_size;
+ m_operationStatistics.unackedOperationCount = m_operationStatisticsNative.unacked_operation_count;
+ m_operationStatistics.unackedOperationSize = m_operationStatisticsNative.unacked_operation_size;
+ }
+ return m_operationStatistics;
+ }
+
+ MqttClient::MqttClient(Io::ClientBootstrap &bootstrap, Allocator *allocator) noexcept
+ : m_client(aws_mqtt_client_new(allocator, bootstrap.GetUnderlyingHandle()))
+ {
+ }
+
+ MqttClient::MqttClient(Allocator *allocator) noexcept
+ : m_client(aws_mqtt_client_new(
+ allocator,
+ Crt::ApiHandle::GetOrCreateStaticDefaultClientBootstrap()->GetUnderlyingHandle()))
+ {
+ }
+
+ MqttClient::~MqttClient()
+ {
+ aws_mqtt_client_release(m_client);
+ m_client = nullptr;
+ }
+
+ MqttClient::MqttClient(MqttClient &&toMove) noexcept : m_client(toMove.m_client)
+ {
+ toMove.m_client = nullptr;
+ }
+
+ MqttClient &MqttClient::operator=(MqttClient &&toMove) noexcept
+ {
+ if (&toMove != this)
+ {
+ m_client = toMove.m_client;
+ toMove.m_client = nullptr;
+ }
+
+ return *this;
+ }
+
+ MqttClient::operator bool() const noexcept { return m_client != nullptr; }
+
+ int MqttClient::LastError() const noexcept { return aws_last_error(); }
+
+ std::shared_ptr<MqttConnection> MqttClient::NewConnection(
+ const char *hostName,
+ uint16_t port,
+ const Io::SocketOptions &socketOptions,
+ const Crt::Io::TlsContext &tlsContext,
+ bool useWebsocket) noexcept
+ {
+ if (!tlsContext)
+ {
+ AWS_LOGF_ERROR(
+ AWS_LS_MQTT_CLIENT,
+ "id=%p Trying to call MqttClient::NewConnection using an invalid TlsContext.",
+ (void *)m_client);
+ aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
+ return nullptr;
+ }
+
+ // If you're reading this and asking.... why is this so complicated? Why not use make_shared
+ // or allocate_shared? Well, MqttConnection constructors are private and stl is dumb like that.
+ // so, we do it manually.
+ Allocator *allocator = m_client->allocator;
+ MqttConnection *toSeat =
+ reinterpret_cast<MqttConnection *>(aws_mem_acquire(allocator, sizeof(MqttConnection)));
+ if (!toSeat)
+ {
+ return nullptr;
+ }
+
+ toSeat = new (toSeat) MqttConnection(m_client, hostName, port, socketOptions, tlsContext, useWebsocket);
+ return std::shared_ptr<MqttConnection>(toSeat, [allocator](MqttConnection *connection) {
+ connection->~MqttConnection();
+ aws_mem_release(allocator, reinterpret_cast<void *>(connection));
+ });
+ }
+
+ std::shared_ptr<MqttConnection> MqttClient::NewConnection(
+ const char *hostName,
+ uint16_t port,
+ const Io::SocketOptions &socketOptions,
+ bool useWebsocket) noexcept
+
+ {
+ // If you're reading this and asking.... why is this so complicated? Why not use make_shared
+ // or allocate_shared? Well, MqttConnection constructors are private and stl is dumb like that.
+ // so, we do it manually.
+ Allocator *allocator = m_client->allocator;
+ MqttConnection *toSeat =
+ reinterpret_cast<MqttConnection *>(aws_mem_acquire(m_client->allocator, sizeof(MqttConnection)));
+ if (!toSeat)
+ {
+ return nullptr;
+ }
+
+ toSeat = new (toSeat) MqttConnection(m_client, hostName, port, socketOptions, useWebsocket);
+ return std::shared_ptr<MqttConnection>(toSeat, [allocator](MqttConnection *connection) {
+ connection->~MqttConnection();
+ aws_mem_release(allocator, reinterpret_cast<void *>(connection));
+ });
+ }
+ } // namespace Mqtt
+ } // namespace Crt
+} // namespace Aws
diff --git a/contrib/restricted/aws/aws-crt-cpp/ya.make b/contrib/restricted/aws/aws-crt-cpp/ya.make
new file mode 100644
index 0000000000..962f99ecb7
--- /dev/null
+++ b/contrib/restricted/aws/aws-crt-cpp/ya.make
@@ -0,0 +1,102 @@
+# Generated by devtools/yamaker from nixpkgs 23.05.
+
+LIBRARY()
+
+LICENSE(
+ Apache-2.0 AND
+ MIT
+)
+
+LICENSE_TEXTS(.yandex_meta/licenses.list.txt)
+
+VERSION(0.19.8)
+
+ORIGINAL_SOURCE(https://github.com/awslabs/aws-crt-cpp/archive/v0.19.8.tar.gz)
+
+PEERDIR(
+ contrib/restricted/aws/aws-c-auth
+ contrib/restricted/aws/aws-c-cal
+ contrib/restricted/aws/aws-c-common
+ contrib/restricted/aws/aws-c-event-stream
+ contrib/restricted/aws/aws-c-http
+ contrib/restricted/aws/aws-c-io
+ contrib/restricted/aws/aws-c-mqtt
+ contrib/restricted/aws/aws-c-s3
+ contrib/restricted/aws/aws-c-sdkutils
+)
+
+ADDINCL(
+ GLOBAL contrib/restricted/aws/aws-crt-cpp/include
+)
+
+NO_COMPILER_WARNINGS()
+
+NO_UTIL()
+
+CFLAGS(
+ -DAWS_AUTH_USE_IMPORT_EXPORT
+ -DAWS_CAL_USE_IMPORT_EXPORT
+ -DAWS_CHECKSUMS_USE_IMPORT_EXPORT
+ -DAWS_COMMON_USE_IMPORT_EXPORT
+ -DAWS_COMPRESSION_USE_IMPORT_EXPORT
+ -DAWS_CRT_CPP_USE_IMPORT_EXPORT
+ -DAWS_EVENT_STREAM_USE_IMPORT_EXPORT
+ -DAWS_HTTP_USE_IMPORT_EXPORT
+ -DAWS_IO_USE_IMPORT_EXPORT
+ -DAWS_MQTT_USE_IMPORT_EXPORT
+ -DAWS_MQTT_WITH_WEBSOCKETS
+ -DAWS_S3_USE_IMPORT_EXPORT
+ -DAWS_SDKUTILS_USE_IMPORT_EXPORT
+ -DAWS_USE_EPOLL
+ -DCJSON_HIDE_SYMBOLS
+ -DS2N_CLONE_SUPPORTED
+ -DS2N_CPUID_AVAILABLE
+ -DS2N_FALL_THROUGH_SUPPORTED
+ -DS2N_FEATURES_AVAILABLE
+ -DS2N_KYBER512R3_AVX2_BMI2
+ -DS2N_LIBCRYPTO_SUPPORTS_EVP_MD5_SHA1_HASH
+ -DS2N_LIBCRYPTO_SUPPORTS_EVP_MD_CTX_SET_PKEY_CTX
+ -DS2N_LIBCRYPTO_SUPPORTS_EVP_RC4
+ -DS2N_MADVISE_SUPPORTED
+ -DS2N_PLATFORM_SUPPORTS_KTLS
+ -DS2N_STACKTRACE
+ -DS2N___RESTRICT__SUPPORTED
+)
+
+SRCS(
+ source/Allocator.cpp
+ source/Api.cpp
+ source/DateTime.cpp
+ source/ImdsClient.cpp
+ source/JsonObject.cpp
+ source/StringUtils.cpp
+ source/Types.cpp
+ source/UUID.cpp
+ source/auth/Credentials.cpp
+ source/auth/Sigv4Signing.cpp
+ source/crypto/HMAC.cpp
+ source/crypto/Hash.cpp
+ source/endpoints/RuleEngine.cpp
+ source/external/cJSON.cpp
+ source/http/HttpConnection.cpp
+ source/http/HttpConnectionManager.cpp
+ source/http/HttpProxyStrategy.cpp
+ source/http/HttpRequestResponse.cpp
+ source/io/Bootstrap.cpp
+ source/io/ChannelHandler.cpp
+ source/io/EventLoopGroup.cpp
+ source/io/HostResolver.cpp
+ source/io/Pkcs11.cpp
+ source/io/SocketOptions.cpp
+ source/io/Stream.cpp
+ source/io/TlsOptions.cpp
+ source/io/Uri.cpp
+ source/iot/Mqtt5Client.cpp
+ source/iot/MqttClient.cpp
+ source/iot/MqttCommon.cpp
+ source/mqtt/Mqtt5Client.cpp
+ source/mqtt/Mqtt5Packets.cpp
+ source/mqtt/MqttClient.cpp
+)
+
+END()