Lesson 35 - Get Compute Auth Token Working

This commit is contained in:
Norman Lansing
2026-02-28 12:32:28 -05:00
parent 1d477ee42a
commit 4fde462bce
7743 changed files with 1397833 additions and 18 deletions

View File

@@ -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

View File

@@ -0,0 +1,240 @@
#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 SHA1 hashes.
* If using BYO_CRYPTO, you must call this.
*/
void SetBYOCryptoNewSHA1Callback(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();
#pragma pack(push, 1)
struct Version
{
uint16_t major;
uint16_t minor;
uint16_t patch;
};
#pragma pack(pop)
/**
* Gets the version of the AWS-CRT-CPP library
* @return Version representing the library version
*/
Version GetCrtVersion() const;
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();
Version m_version = {0, 0, 0};
};
/**
* 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

View File

@@ -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.29.3"
#define AWS_CRT_CPP_VERSION_MAJOR 0
#define AWS_CRT_CPP_VERSION_MINOR 29
#define AWS_CRT_CPP_VERSION_PATCH 3
#define AWS_CRT_CPP_GIT_HASH "281a7caff7e10f68a5422d8fca8acf0b48e4215f"

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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/StlAllocator.h>
#include <aws/crt/Types.h>
struct aws_json_value;
namespace Aws
{
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.
* Call WasParseSuccessful() on new object to determine if parse was successful.
*/
JsonObject(const String &stringToParse);
/**
* Construct a deep copy.
* Prefer using a @ref JsonView if copying is not needed.
*/
JsonObject(const JsonObject &other);
/**
* Move constructor.
* No copying is performed.
*/
JsonObject(JsonObject &&other) noexcept;
~JsonObject();
/**
* Performs a deep copy.
*/
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 a number value at key at the top level of this node.
* Precision may be lost.
*/
JsonObject &WithInteger(const String &key, int value);
JsonObject &WithInteger(const char *key, int value);
/**
* Converts the current JSON node to a number.
* Precision may be lost.
*/
JsonObject &AsInteger(int value);
/**
* Adds a number value at key to the top level of this node.
* Precision may be lost.
*/
JsonObject &WithInt64(const String &key, int64_t value);
JsonObject &WithInt64(const char *key, int64_t value);
/**
* Converts the current JSON node to a number.
* Precision may be lost.
*/
JsonObject &AsInt64(int64_t value);
/**
* Adds a number 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 number.
*/
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.
*/
inline bool WasParseSuccessful() const { return m_value != nullptr; }
/**
* @deprecated
*/
const String &GetErrorMessage() const;
/**
* Creates a view of this JSON node.
*/
JsonView View() const;
private:
/**
* Construct a duplicate of this JSON value.
*/
JsonObject(const aws_json_value *valueToCopy);
/**
* Helper for all AsXYZ() functions.
* Destroys any pre-existing value and takes ownership of new value.
*/
JsonObject &AsNewValue(aws_json_value *valueToOwn);
/**
* Helper for all WithXZY() functions.
* Take ownership of new value and add at key, replacing any previous value.
* Converts this node to JSON object if necessary.
*/
JsonObject &WithNewKeyValue(const char *key, aws_json_value *valueToOwn);
/**
* Return new aws_json_value, an array containing duplicates of everything in objectsToCopy.
*/
static aws_json_value *NewArray(const Vector<JsonObject> &objectsToCopy);
/**
* Return new aws_json_value, an array which has taken ownership of everything in objectsToMove
*/
static aws_json_value *NewArray(Vector<JsonObject> &&objectsToMove);
aws_json_value *m_value;
/* Once upon a time each class instance had an m_errorMessage string member,
* and if parse failed the string would explain why.
* When we switched json implementations, there was no longer a unique string
* explaining why parse failed so we dropped that member from the class.
* To avoid breaking the GetErrorMessage() API, which returns the string by REFERENCE,
* we now use singletons that are created/destroyed along with library init/cleanup. */
static std::unique_ptr<String> s_errorMessage;
static std::unique_ptr<String> s_okMessage;
static void OnLibraryInit();
static void OnLibraryCleanup();
friend class JsonView;
friend class ApiHandle;
};
/**
* 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 a number.
*/
bool IsNumber() const;
/**
* Tests whether the current value is a number that can convert to an int64_t without losing precision.
*/
bool IsIntegerType() const;
/**
* Tests whether the current value is a number that will lose precision if converted to an int64_t.
*/
bool IsFloatingPointType() const;
/**
* Tests whether the current value is a JSON array.
*/
bool IsListType() const;
/**
* Tests whether the current value is a JSON 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(const aws_json_value *val);
String Write(bool treatAsObject, bool readable) const;
const aws_json_value *m_value;
};
} // namespace Crt
} // namespace Aws

View File

@@ -0,0 +1,220 @@
#pragma once
/**
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/
#include <aws/crt/Utility.h>
#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;
}
}
template <typename... Args> explicit Optional(Aws::Crt::InPlaceT, Args &&...args)
{
new (m_storage) T(std::forward<Args>(args)...);
m_value = reinterpret_cast<T *>(m_storage);
}
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;
}
template <typename... Args> T &emplace(Args &&...args)
{
reset();
new (m_storage) T(std::forward<Args>(args)...);
m_value = reinterpret_cast<T *>(m_storage);
return *m_value;
}
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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -0,0 +1,865 @@
#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 <string>
#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

View File

@@ -0,0 +1,166 @@
#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 ByteBuf ByteBufInit(Allocator *alloc, 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) noexcept;
AWS_CRT_CPP_API String Base64Encode(const Vector<uint8_t> &encode) noexcept;
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

View File

@@ -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

View File

@@ -0,0 +1,31 @@
#pragma once
/**
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/
namespace Aws
{
namespace Crt
{
/**
* Custom implementation of an in_place type tag for constructor parameter list
*/
struct InPlaceT
{
explicit InPlaceT() = default;
};
static constexpr InPlaceT InPlace{};
template <typename T> struct InPlaceTypeT
{
explicit InPlaceTypeT() = default;
};
/** Variable templates are only available since C++14
* Use a dummy object "Aws::Crt::InPlaceTypeT<T>() in-place instead in C++11"*/
#if defined(__cplusplus) && __cplusplus > 201103L //
template <class T> static constexpr InPlaceTypeT<T> InPlaceType{};
#endif
} // namespace Crt
} // namespace Aws

View File

@@ -0,0 +1,591 @@
#pragma once
/**
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/
#include <aws/common/assert.h>
#include <aws/crt/Utility.h>
#include <algorithm>
#include <type_traits>
#include <utility>
namespace Aws
{
namespace Crt
{
namespace VariantDetail
{
template <typename T> constexpr const T &ConstExprMax(const T &a, const T &b)
{
return (a < b) ? b : a;
}
namespace ParameterPackSize
{
// Returns a max of sizeof(T) over all T in a template parameter pack
template <typename Last> constexpr std::size_t GetMaxSizeOf(std::size_t curMax = 0)
{
return ConstExprMax(curMax, sizeof(Last));
}
template <typename First, typename Second, typename... Rest>
constexpr std::size_t GetMaxSizeOf(std::size_t curMax = 0)
{
return ConstExprMax(curMax, GetMaxSizeOf<Second, Rest...>(ConstExprMax(curMax, sizeof(First))));
}
// some old gcc versions does not work with alignas(Ts..)
template <typename Last> constexpr std::size_t AlignAsPack(std::size_t curMax = 0)
{
return ConstExprMax(curMax, alignof(Last));
}
template <typename First, typename Second, typename... Rest>
constexpr std::size_t AlignAsPack(std::size_t curMax = 0)
{
return ConstExprMax(curMax, AlignAsPack<Second, Rest...>(ConstExprMax(curMax, alignof(First))));
}
} // namespace ParameterPackSize
namespace Index
{
using VariantIndex = short;
template <typename T, typename Last> constexpr VariantIndex GetIndexOf(VariantIndex curIndex = 0)
{
return std::is_same<T, Last>::value ? curIndex : -1;
}
template <typename T, typename First, typename Second, typename... Rest>
constexpr VariantIndex GetIndexOf(VariantIndex curIndex = 0)
{
return std::is_same<T, First>::value ? curIndex : GetIndexOf<T, Second, Rest...>(++curIndex);
}
} // namespace Index
namespace Checker
{
// Returns True if the template parameter pack Ts has a type T, i.e. ContainsType<T, Ts>() == true if T
// is in the list of Ts
template <typename T, typename Last> constexpr bool ContainsType()
{
return std::is_same<T, Last>::value;
}
template <typename T, typename First, typename Second, typename... Rest> constexpr bool ContainsType()
{
return std::is_same<T, First>::value || ContainsType<T, Second, Rest...>();
}
// a case when the template parameter pack is empty (i.e. Variant<>)
template <typename T> constexpr bool ContainsType()
{
return false;
}
template <typename T, typename... Ts> struct HasType
{
static const bool value = ContainsType<T, Ts...>();
};
} // namespace Checker
#if defined(AWS_CRT_ENABLE_VARIANT_DEBUG)
namespace VariantDebug
{
template <typename... Ts> class VariantDebugBrowser
{
public:
VariantDebugBrowser(char *storage) { InitTuple<0, Ts...>(storage); }
std::tuple<typename std::add_pointer<Ts>::type...> as_tuple;
private:
template <IndexT Index, typename First, typename Second, typename... Rest>
void InitTuple(char *storage)
{
First *value = reinterpret_cast<First *>(storage);
std::get<Index>(as_tuple) = value;
InitTuple<Index + 1, Second, Rest...>(storage);
}
template <IndexT Index, typename Last> void InitTuple(char *storage)
{
Last *value = reinterpret_cast<Last *>(storage);
std::get<Index>(as_tuple) = value;
}
};
} // namespace VariantDebug
#endif /* defined(AWS_CRT_ENABLE_VARIANT_DEBUG) */
} // namespace VariantDetail
template <std::size_t Index, typename... Ts> class VariantAlternative;
/**
* Custom implementation of a Variant type. std::variant requires C++17
* @tparam Ts types of the variant value
*/
template <typename... Ts> class Variant
{
private:
template <std::size_t Index> using ThisVariantAlternative = VariantAlternative<Index, Ts...>;
template <typename OtherT>
using EnableIfOtherIsThisVariantAlternative = typename std::
enable_if<VariantDetail::Checker::HasType<typename std::decay<OtherT>::type, Ts...>::value, int>::type;
public:
using IndexT = VariantDetail::Index::VariantIndex;
static constexpr std::size_t AlternativeCount = sizeof...(Ts);
Variant()
{
using FirstAlternative = typename ThisVariantAlternative<0>::type;
new (m_storage) FirstAlternative();
m_index = 0;
}
Variant(const Variant &other)
{
AWS_FATAL_ASSERT(other.m_index != -1);
m_index = other.m_index;
VisitorUtil<0, Ts...>::VisitBinary(this, other, CopyMoveConstructor());
}
Variant(Variant &&other)
{
AWS_FATAL_ASSERT(other.m_index != -1);
m_index = other.m_index;
VisitorUtil<0, Ts...>::VisitBinary(this, std::move(other), CopyMoveConstructor());
}
template <typename T, EnableIfOtherIsThisVariantAlternative<T> = 1> Variant(const T &val)
{
static_assert(
VariantDetail::Checker::HasType<typename std::decay<T>::type, Ts...>::value,
"This variant does not have such alternative T.");
static_assert(
sizeof(T) <= STORAGE_SIZE,
"Attempting to instantiate a Variant with a type bigger than all alternatives.");
using PlainT = typename std::decay<T>::type;
new (m_storage) PlainT(val);
m_index = VariantDetail::Index::GetIndexOf<PlainT, Ts...>();
AWS_ASSERT(m_index != -1);
}
template <typename T, EnableIfOtherIsThisVariantAlternative<T> = 1> Variant(T &&val)
{
static_assert(
VariantDetail::Checker::HasType<typename std::decay<T>::type, Ts...>::value,
"This variant does not have such alternative T.");
static_assert(
sizeof(T) <= STORAGE_SIZE,
"Attempting to instantiate a Variant with a type bigger than all alternatives.");
using PlainT = typename std::decay<T>::type;
new (m_storage) PlainT(std::forward<T>(val));
m_index = VariantDetail::Index::GetIndexOf<PlainT, Ts...>();
AWS_ASSERT(m_index != -1);
}
// An overload to initialize with an Alternative T in-place
template <typename T, typename... Args> explicit Variant(Aws::Crt::InPlaceTypeT<T>, Args &&...args)
{
static_assert(
VariantDetail::Checker::HasType<typename std::decay<T>::type, Ts...>::value,
"This variant does not have such alternative T.");
static_assert(
sizeof(T) <= STORAGE_SIZE,
"Attempting to instantiate a Variant with a type bigger than all alternatives.");
using PlainT = typename std::decay<T>::type;
new (m_storage) PlainT(std::forward<Args>(args)...);
m_index = VariantDetail::Index::GetIndexOf<PlainT, Ts...>();
AWS_ASSERT(m_index != -1);
}
Variant &operator=(const Variant &other)
{
if (this != &other)
{
AWS_FATAL_ASSERT(other.m_index != -1);
if (m_index != other.m_index)
{
Destroy();
m_index = other.m_index;
VisitorUtil<0, Ts...>::VisitBinary(this, other, CopyMoveConstructor());
}
else
{
VisitorUtil<0, Ts...>::VisitBinary(this, other, CopyMoveAssigner());
}
}
return *this;
}
Variant &operator=(Variant &&other)
{
if (this != &other)
{
AWS_FATAL_ASSERT(other.m_index != -1);
if (m_index != other.m_index)
{
Destroy();
m_index = other.m_index;
VisitorUtil<0, Ts...>::VisitBinary(this, std::move(other), CopyMoveConstructor());
}
else
{
VisitorUtil<0, Ts...>::VisitBinary(this, std::move(other), CopyMoveAssigner());
};
}
return *this;
}
/* emplace */
template <typename T, typename... Args, EnableIfOtherIsThisVariantAlternative<T> = 1>
T &emplace(Args &&...args)
{
static_assert(
VariantDetail::Checker::HasType<typename std::decay<T>::type, Ts...>::value,
"This variant does not have such alternative T.");
static_assert(
sizeof(T) <= STORAGE_SIZE,
"Attempting to instantiate a Variant with a type bigger than all alternatives.");
Destroy();
using PlainT = typename std::decay<T>::type;
new (m_storage) PlainT(std::forward<Args>(args)...);
m_index = VariantDetail::Index::GetIndexOf<PlainT, Ts...>();
AWS_ASSERT(m_index != -1);
T *value = reinterpret_cast<T *>(m_storage);
return *value;
}
template <std::size_t Index, typename... Args>
auto emplace(Args &&...args) -> typename ThisVariantAlternative<Index>::type &
{
static_assert(Index < AlternativeCount, "Unknown alternative index to emplace");
using AlternativeT = typename ThisVariantAlternative<Index>::type;
return emplace<AlternativeT, Args...>(std::forward<Args>(args)...);
}
template <typename T, EnableIfOtherIsThisVariantAlternative<T> = 1> bool holds_alternative() const
{
AWS_ASSERT(m_index != -1);
return m_index == VariantDetail::Index::GetIndexOf<T, Ts...>();
}
/* non-const get */
template <typename T, EnableIfOtherIsThisVariantAlternative<T> = 1> T &get()
{
AWS_FATAL_ASSERT(holds_alternative<T>());
T *value = reinterpret_cast<T *>(m_storage);
return *value;
}
template <typename T, EnableIfOtherIsThisVariantAlternative<T> = 1> T *get_if()
{
if (holds_alternative<T>())
{
T *value = reinterpret_cast<T *>(m_storage);
return value;
}
else
{
return nullptr;
}
}
template <std::size_t Index> auto get() -> typename ThisVariantAlternative<Index>::type &
{
static_assert(Index < AlternativeCount, "Unknown alternative index to get");
AWS_FATAL_ASSERT(holds_alternative<Index>());
using AlternativeT = typename ThisVariantAlternative<Index>::type;
AlternativeT *ret = reinterpret_cast<AlternativeT *>(m_storage);
return *ret;
}
/* const get */
template <typename T, EnableIfOtherIsThisVariantAlternative<T> = 1> const T &get() const
{
AWS_FATAL_ASSERT(holds_alternative<T>());
const T *value = reinterpret_cast<const T *>(m_storage);
return *value;
}
template <typename T, EnableIfOtherIsThisVariantAlternative<T> = 1> const T *get_if() const
{
if (holds_alternative<T>())
{
T *value = reinterpret_cast<T *>(m_storage);
return value;
}
else
{
return nullptr;
}
}
template <std::size_t Index> auto get() const -> const typename ThisVariantAlternative<Index>::type &
{
static_assert(Index < AlternativeCount, "Unknown alternative index to get");
AWS_ASSERT(Index == m_index);
using AlternativeT = typename ThisVariantAlternative<Index>::type;
const AlternativeT *ret = reinterpret_cast<const AlternativeT *>(m_storage);
return *ret;
}
/* This is just a templated way to say
* "int*" for
* a VariantAlternative<0, Variant<int, char, long>()>*/
template <std::size_t Index>
using RawAlternativePointerT =
typename std::add_pointer<typename ThisVariantAlternative<Index>::type>::type;
template <std::size_t Index> auto get_if() -> RawAlternativePointerT<Index>
{
static_assert(Index < AlternativeCount, "Unknown alternative index to get");
if (holds_alternative<Index>())
{
using AlternativePtrT = RawAlternativePointerT<Index>;
AlternativePtrT value = reinterpret_cast<AlternativePtrT>(m_storage);
return value;
}
else
{
return nullptr;
}
}
template <std::size_t Index>
using ConstRawAlternativePointerT = typename std::add_pointer<
typename std::add_const<typename ThisVariantAlternative<Index>::type>::type>::type;
template <std::size_t Index> auto get_if() const -> ConstRawAlternativePointerT<Index>
{
static_assert(Index < AlternativeCount, "Unknown alternative index to get");
if (holds_alternative<Index>())
{
using AlternativePtrT = ConstRawAlternativePointerT<Index>;
AlternativePtrT value = reinterpret_cast<AlternativePtrT>(m_storage);
return value;
}
else
{
return nullptr;
}
}
std::size_t index() const { return m_index; }
~Variant() { Destroy(); }
template <typename VisitorT> void Visit(VisitorT &&visitor)
{
return VisitorUtil<0, Ts...>::Visit(this, std::forward<VisitorT>(visitor));
}
private:
static constexpr std::size_t STORAGE_SIZE = VariantDetail::ParameterPackSize::GetMaxSizeOf<Ts...>();
alignas(VariantDetail::ParameterPackSize::AlignAsPack<Ts...>()) char m_storage[STORAGE_SIZE];
IndexT m_index = -1;
#if defined(AWS_CRT_ENABLE_VARIANT_DEBUG)
VariantDetail::VariantDebug::VariantDebugBrowser<Ts...> browser = m_storage;
#endif /* defined(AWS_CRT_ENABLE_VARIANT_DEBUG) */
template <size_t Index> constexpr bool holds_alternative() const { return Index == m_index; }
struct Destroyer
{
template <typename AlternativeT> void operator()(AlternativeT &&value) const
{
using PlaintT = typename std::remove_reference<AlternativeT>::type;
value.~PlaintT();
}
};
void Destroy()
{
AWS_FATAL_ASSERT(m_index != -1);
Visit(Destroyer());
m_index = -1;
}
struct CopyMoveConstructor
{
template <typename AlternativeT> void operator()(AlternativeT &&value, AlternativeT &&other) const
{
using PlaintT = typename std::remove_reference<AlternativeT>::type;
new (&value) PlaintT(std::move<AlternativeT>(other));
}
template <typename AlternativeT, typename ConstAlternativeT>
void operator()(AlternativeT &&value, ConstAlternativeT &other) const
{
using PlaintT = typename std::remove_reference<AlternativeT>::type;
using PlaintOtherT =
typename std::remove_const<typename std::remove_reference<AlternativeT>::type>::type;
static_assert(std::is_same<PlaintT, PlaintOtherT>::value, "Incompatible types");
new (&value) PlaintT(other);
}
};
struct CopyMoveAssigner
{
template <typename AlternativeT> void operator()(AlternativeT &&value, AlternativeT &&other) const
{
value = std::move(other);
}
template <typename AlternativeT, typename ConstAlternativeT>
void operator()(AlternativeT &&value, ConstAlternativeT &other) const
{
using PlaintT = typename std::remove_reference<AlternativeT>::type;
using PlaintOtherT =
typename std::remove_const<typename std::remove_reference<AlternativeT>::type>::type;
static_assert(std::is_same<PlaintT, PlaintOtherT>::value, "Incompatible types");
value = other;
}
};
template <IndexT Index, typename... Args> struct VisitorUtil;
template <IndexT Index, typename First, typename Second, typename... Rest>
struct VisitorUtil<Index, First, Second, Rest...>
{
template <typename VisitorStruct> static void Visit(Variant *pThis, VisitorStruct &&visitor)
{
static_assert(Index < AlternativeCount, "Attempting to visit unknown Index Type");
if (Index == pThis->m_index)
{
using AlternativeT = typename ThisVariantAlternative<Index>::type;
AlternativeT *value = reinterpret_cast<AlternativeT *>(pThis->m_storage);
visitor(*value);
}
else
{
VisitorUtil<static_cast<IndexT>(Index + 1), Second, Rest...>::Visit(
pThis, std::forward<VisitorStruct>(visitor));
}
}
template <typename VisitorStruct>
static void VisitBinary(Variant<Ts...> *pThis, Variant<Ts...> &&other, VisitorStruct &&visitor)
{
static_assert(Index < AlternativeCount, "Attempting to visit unknown Index Type");
if (Index == pThis->m_index)
{
using AlternativeT = typename ThisVariantAlternative<Index>::type;
AlternativeT *value = reinterpret_cast<AlternativeT *>(pThis->m_storage);
visitor(*value, other.get<AlternativeT>());
}
else
{
VisitorUtil<static_cast<IndexT>(Index + 1), Second, Rest...>::VisitBinary(
pThis, std::forward<Variant<Ts...>>(other), std::forward<VisitorStruct>(visitor));
}
}
template <typename VisitorStruct>
static void VisitBinary(Variant<Ts...> *pThis, const Variant<Ts...> &other, VisitorStruct &&visitor)
{
static_assert(Index < AlternativeCount, "Attempting to visit unknown Index Type");
if (Index == pThis->m_index)
{
using AlternativeT = typename ThisVariantAlternative<Index>::type;
AlternativeT *value = reinterpret_cast<AlternativeT *>(pThis->m_storage);
const AlternativeT &otherValue = other.get<AlternativeT>();
visitor(*value, otherValue);
}
else
{
VisitorUtil<static_cast<IndexT>(Index + 1), Second, Rest...>::VisitBinary(
pThis, other, std::forward<VisitorStruct>(visitor));
}
}
};
template <IndexT Index, typename Last> struct VisitorUtil<Index, Last>
{
template <typename VisitorStruct> static void Visit(Variant *pThis, VisitorStruct &&visitor)
{
static_assert(Index < AlternativeCount, "Attempting to visit unknown Index Type");
if (Index == pThis->m_index)
{
using AlternativeT = typename ThisVariantAlternative<Index>::type;
AlternativeT *value = reinterpret_cast<AlternativeT *>(pThis->m_storage);
visitor(*value);
}
else
{
AWS_FATAL_ASSERT(!"Unknown variant alternative to visit!");
}
}
template <typename VisitorStruct>
static void VisitBinary(Variant<Ts...> *pThis, Variant<Ts...> &&other, VisitorStruct &&visitor)
{
static_assert(Index < AlternativeCount, "Attempting to visit unknown Index Type");
if (Index == pThis->m_index)
{
using AlternativeT = typename ThisVariantAlternative<Index>::type;
AlternativeT *value = reinterpret_cast<AlternativeT *>(pThis->m_storage);
visitor(*value, other.get<AlternativeT>());
}
else
{
AWS_FATAL_ASSERT(!"Unknown variant alternative to visit!");
}
}
template <typename VisitorStruct>
static void VisitBinary(Variant<Ts...> *pThis, const Variant<Ts...> &other, VisitorStruct &&visitor)
{
static_assert(Index < AlternativeCount, "Attempting to visit unknown Index Type");
if (Index == pThis->m_index)
{
using AlternativeT = typename ThisVariantAlternative<Index>::type;
AlternativeT *value = reinterpret_cast<AlternativeT *>(pThis->m_storage);
const AlternativeT &otherValue = other.get<AlternativeT>();
visitor(*value, otherValue);
}
else
{
AWS_FATAL_ASSERT(!"Unknown variant alternative to visit!");
}
}
};
};
/* Helper template to get an actual type from an Index */
template <std::size_t Index, typename... Ts> class VariantAlternative
{
public:
// uses std::tuple as a helper struct to provide index-based access of a parameter pack
using type = typename std::tuple_element<Index, std::tuple<Ts...>>::type;
VariantAlternative(const Variant<Ts...> &) {}
VariantAlternative(const Variant<Ts...> *) {}
};
template <typename T> class VariantSize
{
constexpr static const std::size_t Value = T::AlternativeCount;
};
} // namespace Crt
} // namespace Aws

View File

@@ -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

View File

@@ -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
* if 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

View File

@@ -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

View File

@@ -0,0 +1,367 @@
#pragma once
/**
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/
#include <aws/common/cbor.h>
#include <aws/crt/Types.h>
namespace Aws
{
namespace Crt
{
namespace Cbor
{
/**
* The types used by APIs, not 1:1 with major types.
* It's an extension for CBOR major type in RFC8949 section 3.1.
* Major type 0 - UInt
* Major type 1 - NegInt
* Major type 2 - Bytes / IndefBytesStart
* Major type 3 - Text / IndefTextStart
* Major type 4 - ArrayStart / IndefArrayStart
* Major type 5 - MapStart / IndefMapStart
* Major type 6 - Tag
* Major type 7:
* - 20/21 - Bool
* - 22 - Null
* - 23 - Undefined
* - 25/26/27 - Float
* - 31 - Break
* - Rest of the values are not supported.
*/
enum class CborType
{
Unknown = AWS_CBOR_TYPE_UNKNOWN,
UInt = AWS_CBOR_TYPE_UINT,
NegInt = AWS_CBOR_TYPE_NEGINT,
Float = AWS_CBOR_TYPE_FLOAT,
Bytes = AWS_CBOR_TYPE_BYTES,
Text = AWS_CBOR_TYPE_TEXT,
ArrayStart = AWS_CBOR_TYPE_ARRAY_START,
MapStart = AWS_CBOR_TYPE_MAP_START,
Tag = AWS_CBOR_TYPE_TAG,
Bool = AWS_CBOR_TYPE_BOOL,
Null = AWS_CBOR_TYPE_NULL,
Undefined = AWS_CBOR_TYPE_UNDEFINED,
Break = AWS_CBOR_TYPE_BREAK,
IndefBytesStart = AWS_CBOR_TYPE_INDEF_BYTES_START,
IndefTextStart = AWS_CBOR_TYPE_INDEF_TEXT_START,
IndefArrayStart = AWS_CBOR_TYPE_INDEF_ARRAY_START,
IndefMapStart = AWS_CBOR_TYPE_INDEF_MAP_START,
};
class AWS_CRT_CPP_API CborEncoder final
{
public:
CborEncoder(const CborEncoder &) = delete;
CborEncoder(CborEncoder &&) = delete;
CborEncoder &operator=(const CborEncoder &) = delete;
CborEncoder &operator=(CborEncoder &&) = delete;
CborEncoder(Allocator *allocator = ApiAllocator()) noexcept;
~CborEncoder() noexcept;
/**
* Get the current encoded data from encoder. The encoded data has the same lifetime as the encoder,
* and once any other function call invoked for the encoder, the encoded data is no longer valid.
*
* @return the current encoded data
*/
ByteCursor GetEncodedData() noexcept;
/**
* Clear the current encoded buffer from encoder.
*/
void Reset() noexcept;
/**
* Encode a AWS_CBOR_TYPE_UINT value to "smallest possible" in encoder's buffer.
* Referring to RFC8949 section 4.2.1
*
* @param value value to encode.
*/
void WriteUInt(uint64_t value) noexcept;
/**
* Encode a AWS_CBOR_TYPE_NEGINT value to "smallest possible" in encoder's buffer.
* It represents (-1 - value).
* Referring to RFC8949 section 4.2.1
*
* @param value value to encode, which is (-1 - represented value)
*/
void WriteNegInt(uint64_t value) noexcept;
/**
* Encode a AWS_CBOR_TYPE_FLOAT value to "smallest possible", but will not be encoded into
* half-precision float, as it's not well supported cross languages.
*
* To be more specific, it will be encoded into integer/negative/float
* (Order with priority) when the conversion will not cause precision loss.
*
* @param value value to encode.
*/
void WriteFloat(double value) noexcept;
/**
* Encode a Bytes value to "smallest possible" in encoder's buffer.
* Referring to RFC8949 section 4.2.1, the length of "value" will be encoded first and then the value of
* "value" will be followed.
*
* @param value value to encode.
*/
void WriteBytes(ByteCursor value) noexcept;
/**
* Encode a Text value to "smallest possible" in encoder's buffer.
* Referring to RFC8949 section 4.2.1, the length of "value" will be encoded first and then the value of
* "value" will be followed.
*
* @param value value to encode.
*/
void WriteText(ByteCursor value) noexcept;
/**
* Encode an ArrayStart value to "smallest possible" in encoder's buffer.
* Referring to RFC8949 section 4.2.1
* Notes: it's user's responsibility to keep the integrity of the array to be encoded.
*
* @param number_entries the number of CBOR data items to be followed as the content of the array.
*/
void WriteArrayStart(size_t number_entries) noexcept;
/**
* Encode a MapStart value to "smallest possible" in encoder's buffer.
* Referring to RFC8949 section 4.2.1
*
* Notes: it's user's responsibility to keep the integrity of the map to be encoded.
*
* @param number_entries the number of pair of CBOR data items as key and value to be followed as
* the content of the map.
*/
void WriteMapStart(size_t number_entries) noexcept;
/**
* Encode a Tag value to "smallest possible" in encoder's buffer.
* Referring to RFC8949 section 4.2.1
* The following CBOR data item will be the content of the tagged value.
* Notes: it's user's responsibility to keep the integrity of the tagged value to follow the RFC8949
* section 3.4
*
* @param tag_number The tag value to encode.
*/
void WriteTag(uint64_t tag_number) noexcept;
/**
* Encode a simple value Null
*/
void WriteNull() noexcept;
/**
* Encode a simple value Undefined
*/
void WriteUndefined() noexcept;
/**
* Encode a simple value Bool
*/
void WriteBool(bool value) noexcept;
/**
* Encode a simple value Break
* Notes: no error checking, it's user's responsibility to track the break to close the corresponding
* indef_start
*/
void WriteBreak() noexcept;
/**
* Encode an IndefBytesStart
* Notes: no error checking, it's user's responsibility to add corresponding data and the break to close
* the indef_start
*/
void WriteIndefBytesStart() noexcept;
/**
* Encode an IndefTextStart
* Notes: no error checking, it's user's responsibility to add corresponding data and the break to close
* the indef_start
*/
void WriteIndefTextStart() noexcept;
/**
* Encode an IndefArrayStart
* Notes: no error checking, it's user's responsibility to add corresponding data and the break to close
* the indef_start
*/
void WriteIndefArrayStart() noexcept;
/**
* Encode an IndefMapStart
* Notes: no error checking, it's user's responsibility to add corresponding data and the break to close
* the indef_start
*/
void WriteIndefMapStart() noexcept;
private:
struct aws_cbor_encoder *m_encoder;
};
class AWS_CRT_CPP_API CborDecoder final
{
public:
CborDecoder(const CborDecoder &) = delete;
CborDecoder(CborDecoder &&) = delete;
CborDecoder &operator=(const CborDecoder &) = delete;
CborDecoder &operator=(CborDecoder &&) = delete;
/**
* Construct a new Cbor Decoder object
*
* @param allocator
* @param src The src data to decode from.
*/
CborDecoder(ByteCursor src, Allocator *allocator = ApiAllocator()) noexcept;
~CborDecoder() noexcept;
/**
* Get the length of the remaining bytes of the source. Once the source was decoded, it will be
* consumed, and result in decrease of the remaining length of bytes.
*
* @return The length of bytes remaining of the decoder source.
*/
size_t GetRemainingLength() noexcept;
/**
* Decode the next element and store it in the decoder cache if there was no element cached.
* If there was an element cached, just return the type of the cached element.
*
* @return If successful, return the type of next element
* If not, return will be none and LastError() can be
* used to retrieve CRT error code.
*/
Optional<CborType> PeekType() noexcept;
/**
* Consume the next data item, includes all the content within the data item.
*
* As an example for the following CBOR, this function will consume all the data
* as it's only one CBOR data item, an indefinite map with 2 key, value pair:
* 0xbf6346756ef563416d7421ff
* BF -- Start indefinite-length map
* 63 -- First key, UTF-8 string length 3
* 46756e -- "Fun"
* F5 -- First value, true
* 63 -- Second key, UTF-8 string length 3
* 416d74 -- "Amt"
* 21 -- Second value, -2
* FF -- "break"
*
* Notes: this function will not ensure the data item is well-formed.
*
* @return true if the operation succeed, false otherwise and LastError() will contain the errorCode.
*/
bool ConsumeNextWholeDataItem() noexcept;
/**
* Consume the next single element, without the content followed by the element.
*
* As an example for the following CBOR, this function will only consume the
* 0xBF, "Start indefinite-length map", not any content of the map represented.
* The next element to decode will start from 0x63.
* 0xbf6346756ef563416d7421ff
* BF -- Start indefinite-length map
* 63 -- First key, UTF-8 string length 3
* 46756e -- "Fun"
* F5 -- First value, true
* 63 -- Second key, UTF-8 string length 3
* 416d74 -- "Amt"
* 21 -- Second value, -2
* FF -- "break"
*
* @return true if the operation succeed, false otherwise and LastError() will contain the errorCode.
*/
bool ConsumeNextSingleElement() noexcept;
/**
* Get the next element based on the type. If the next element doesn't match the expected type, an error
* will be raised. If the next element has already been cached, it will consume the cached item when no
* error was returned. Specifically:
* - UInt - PopNextUnsignedIntVal
* - NegInt - PopNextNegativeIntVal, it represents (-1 - &out)
* - Float - PopNextFloatVal
* - Bytes - PopNextBytesVal
* - Text - PopNextTextVal
*
* @return If successful, return the next element
* If not, return will be none and LastError() can be
* used to retrieve CRT error code.
*/
Optional<uint64_t> PopNextUnsignedIntVal() noexcept;
Optional<uint64_t> PopNextNegativeIntVal() noexcept;
Optional<double> PopNextFloatVal() noexcept;
Optional<bool> PopNextBooleanVal() noexcept;
Optional<ByteCursor> PopNextBytesVal() noexcept;
Optional<ByteCursor> PopNextTextVal() noexcept;
/**
* Get the next ArrayStart element. Only consume the ArrayStart element and set the size of array to
* &out_size, not the content of the array. The next &out_size CBOR data items will be the content of
* the array for a valid CBOR data.
*
* Notes: For indefinite-length, this function will fail with "AWS_ERROR_CBOR_UNEXPECTED_TYPE". The
* designed way to handle indefinite-length is:
* - Get IndefArrayStart from PeekType
* - Call ConsumeNextSingleElement to pop the indefinite-length start.
* - Decode the next data item until Break is read.
*
* @return If successful, return the size of array
* If not, return will be none and LastError() can be
* used to retrieve CRT error code.
*/
Optional<uint64_t> PopNextArrayStart() noexcept;
/**
* Get the next MapStart element. Only consume the MapStart element and set the size of array to
* &out_size, not the content of the map. The next &out_size pair of CBOR data items as key and value
* will be the content of the array for a valid CBOR data.
*
* Notes: For indefinite-length, this function will fail with "AWS_ERROR_CBOR_UNEXPECTED_TYPE". The
* designed way to handle indefinite-length is:
* - Get IndefMapStart from PeekType
* - Call ConsumeNextSingleElement to pop the indefinite-length start.
* - Decode the next data item until Break is read.
*
* @return If successful, return the size of map
* If not, return will be none and LastError() can be
* used to retrieve CRT error code.
*/
Optional<uint64_t> PopNextMapStart() noexcept;
/**
* Get the next Tag element. Only consume the Tag element and set the tag value to out_tag_val,
* not the content of the tagged value. The next CBOR data item will be the content of the tagged value
* for a valid CBOR data.
*
* @return If successful, return the tag value
* If not, return will be none and LastError() can be
* used to retrieve CRT error code.
*/
Optional<uint64_t> PopNextTagVal() noexcept;
/**
* @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:
struct aws_cbor_decoder *m_decoder;
/* Error */
int m_lastError;
};
} // namespace Cbor
} // namespace Crt
} // namespace Aws

View File

@@ -0,0 +1,39 @@
#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>
namespace Aws
{
namespace Crt
{
namespace Checksum
{
/**
* The entry point function to perform a CRC32 (Ethernet, gzip) computation.
* Selects a suitable implementation based on hardware capabilities.
* Pass previousCRC32 if updating a running checksum.
*/
uint32_t AWS_CRT_CPP_API ComputeCRC32(ByteCursor input, uint32_t previousCRC32 = 0) noexcept;
/**
* The entry point function to perform a Castagnoli CRC32c (iSCSI) computation.
* Selects a suitable implementation based on hardware capabilities.
* Pass previousCRC32C if updating a running checksum.
*/
uint32_t AWS_CRT_CPP_API ComputeCRC32C(ByteCursor input, uint32_t previousCRC32C = 0) noexcept;
/**
* The entry point function to perform a CRC64-NVME (a.k.a. CRC64-Rocksoft) computation.
* Selects a suitable implementation based on hardware capabilities.
* Pass previousCRC64NVME if updating a running checksum.
* There are many variants of CRC64 algorithms. This CRC64 variant is bit-reflected (based on
* the non bit-reflected polynomial 0xad93d23594c93659) and inverts the CRC input and output bits.
*/
uint64_t AWS_CRT_CPP_API ComputeCRC64NVME(ByteCursor input, uint64_t previousCRC64NVME = 0) noexcept;
} // namespace Checksum
} // namespace Crt
} // namespace Aws

View File

@@ -0,0 +1,168 @@
#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;
/**
* Returns the size of the digest for this hmac algorithm. If this object is not valid, it will
* return 0 instead.
*/
size_t DigestSize() const noexcept;
/**
* Computes the running HMAC and 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 HMAC digest. Returns true on success. Call LastError() for the reason this call failed.
*
* This is an API a user would use for smaller size inputs. For larger, streaming inputs, use
* multiple calls to Update() for each buffer, followed by a single call to Digest().
*/
bool ComputeOneShot(const ByteCursor &input, 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

View File

@@ -0,0 +1,212 @@
#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 SHA1_DIGEST_SIZE = AWS_SHA1_LEN;
static const size_t SHA256_DIGEST_SIZE = AWS_SHA256_LEN;
static const size_t MD5_DIGEST_SIZE = AWS_MD5_LEN;
/**
* 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;
/**
* Computes a SHA1 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 ComputeSHA1(
Allocator *allocator,
const ByteCursor &input,
ByteBuf &output,
size_t truncateTo = 0) noexcept;
/**
* Computes a SHA1 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 SHA1_DIGEST_SIZE.
*/
bool AWS_CRT_CPP_API ComputeSHA1(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.
*/
operator bool() const noexcept;
/**
* 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 Stream SHA1 Hash.
*/
static Hash CreateSHA1(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: SHA1_DIGEST_SIZE, 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;
/**
* Computes the hash of input and writes the digest into output. The available capacity of
* output must be large enough for the digest. See: SHA1_DIGEST_SIZE, 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.
*
* This is an API a user would use for smaller size inputs. For larger, streaming inputs, use
* multiple calls to Update() for each buffer, followed by a single call to Digest().
*/
bool ComputeOneShot(const ByteCursor &input, ByteBuf &output, size_t truncateTo = 0) noexcept;
/**
* Returns the size of the digest for this hash algorithm. If this object is not valid, it will
* return 0 instead.
*/
size_t DigestSize() const noexcept;
private:
Hash(aws_hash *hash) noexcept;
Hash() = delete;
aws_hash *m_hash;
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 cannot 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

View File

@@ -0,0 +1,18 @@
#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>
namespace Aws
{
namespace Crt
{
namespace Crypto
{
bool AWS_CRT_CPP_API GenerateRandomBytes(ByteBuf &output, size_t lengthToGenerate);
}
} // namespace Crt
} // namespace Aws

View File

@@ -0,0 +1,166 @@
#pragma once
/**
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/
#include <aws/cal/symmetric_cipher.h>
#include <aws/crt/Exports.h>
#include <aws/crt/Types.h>
struct aws_symmetric_cipher;
namespace Aws
{
namespace Crt
{
namespace Crypto
{
static const size_t AES_256_CIPHER_BLOCK_SIZE = 16u;
static const size_t AES_256_KEY_SIZE_BYTES = 32u;
enum class SymmetricCipherState
{
Ready = AWS_SYMMETRIC_CIPHER_READY,
Finalized = AWS_SYMMETRIC_CIPHER_FINALIZED,
Error = AWS_SYMMETRIC_CIPHER_ERROR,
};
class AWS_CRT_CPP_API SymmetricCipher final
{
public:
SymmetricCipher(const SymmetricCipher &) = delete;
SymmetricCipher &operator=(const SymmetricCipher &) = delete;
SymmetricCipher(SymmetricCipher &&) noexcept = default;
SymmetricCipher &operator=(SymmetricCipher &&) noexcept = default;
/**
* Creates an AES 256 CBC mode cipher using a provided key and iv.
* Key must be 32 bytes. If key or iv are not provided, they will be generated.
*/
static SymmetricCipher CreateAES_256_CBC_Cipher(
const Optional<ByteCursor> &key = Optional<ByteCursor>(),
const Optional<ByteCursor> &iv = Optional<ByteCursor>(),
Allocator *allocator = ApiAllocator()) noexcept;
/**
* Creates an AES 256 CTR mode cipher using a provided key and iv.
* If key and iv are not provided, they will be generated.
*/
static SymmetricCipher CreateAES_256_CTR_Cipher(
const Optional<ByteCursor> &key = Optional<ByteCursor>(),
const Optional<ByteCursor> &iv = Optional<ByteCursor>(),
Allocator *allocator = ApiAllocator()) noexcept;
/**
* Creates an AES 256 GCM mode cipher using a provided key, iv, tag, and aad if provided.
* Key and iv will be generated if not provided.
* AAD values are not generated.
* Provide AAD if you need to provide additional auth info.
*/
static SymmetricCipher CreateAES_256_GCM_Cipher(
const Optional<ByteCursor> &key = Optional<ByteCursor>(),
const Optional<ByteCursor> &iv = Optional<ByteCursor>(),
const Optional<ByteCursor> &aad = Optional<ByteCursor>(),
Allocator *allocator = ApiAllocator()) noexcept;
/**
* Creates an AES 256 Keywrap mode cipher using key if provided.
* If a key is not provided, one will be generated.
*/
static SymmetricCipher CreateAES_256_KeyWrap_Cipher(
const Optional<ByteCursor> &key = Optional<ByteCursor>(),
Allocator *allocator = ApiAllocator()) noexcept;
/**
* Returns true if the instance is in a valid state, false otherwise.
*/
operator bool() const noexcept;
/**
* Returns current state of the cipher instance. ready to be used, finalized, or in a error state.
* If the cipher is in a finalized or error state it may not be used anymore
**/
SymmetricCipherState GetState() const noexcept;
/**
* Returns the value of the last aws error encountered by operations on this instance.
*/
inline int LastError() const noexcept { return m_lastError; }
/**
* Encrypts the value in toEncrypt and stores any immediate results in out. Out can be dynamically
* re-sized if out is a dynamic byte buf. Otherwise, make sure the size of out is at least 2 blocks
* larger than the input to allow for padding.
*
* Returns true on success. Call
* LastError() for the reason this call failed.
*/
bool Encrypt(const ByteCursor &toEncrypt, ByteBuf &out) noexcept;
/**
* Encrypts any remaining data on the cipher and stores the output in out. Out can be dynamically
* re-sized if out is a dynamic byte buf. Otherwise, make sure the size of out is at least 2 blocks
* for CBC, CTR, and GCM modes and 40 bytes for KeyWrap.
*
* Returns true on success. Call
* LastError() for the reason this call failed.
*/
bool FinalizeEncryption(ByteBuf &out) noexcept;
/**
* Decrypts the value in toEncrypt and stores any immediate results in out. Out can be dynamically
* re-sized if out is a dynamic byte buf. Otherwise, make sure the size of out is at least 1 block
* larger than the input to allow for padding. Returns true on success. Call LastError() for the reason
* this call failed.
*/
bool Decrypt(const ByteCursor &toDecrypt, ByteBuf &out) noexcept;
/**
* Decrypts any remaining data on the cipher and stores the output in out. Out can be dynamically
* re-sized if out is a dynamic byte buf. Otherwise, make sure the size of out is at least 2 blocks
* for CBC, CTR, GCM, and Keywrap modes.
*
* Returns true on success. Call
* LastError() for the reason this call failed.
*/
bool FinalizeDecryption(ByteBuf &out) noexcept;
/**
* Reset to cipher to new state.
*/
bool Reset() noexcept;
/**
* Returns the key used for this cipher. This key is not copied from the cipher so do not mutate this
* data. Copy if you need to pass it around anywhere.
*/
ByteCursor GetKey() const noexcept;
/**
* Returns the initialization vector used for this cipher.
* This IV is not copied from the cipher so do not mutate this
* data. Copy if you need to pass it around anywhere.
*/
ByteCursor GetIV() const noexcept;
/**
* Returns the encryption tag generated during encryption operations for this cipher in GCM mode.
* This tag is not copied from the cipher so do not mutate this
* data. Copy if you need to pass it around anywhere.
*/
ByteCursor GetTag() const noexcept;
/**
* Sets the tag used during decryption operations for this cipher in GCM mode.
* No-op outside of GCM mode. In GCM mode, encrypt operation overrides the value of the tag.
*/
void SetTag(ByteCursor tag) const noexcept;
private:
SymmetricCipher(aws_symmetric_cipher *cipher) noexcept;
ScopedResource<struct aws_symmetric_cipher> m_cipher;
int m_lastError;
};
} // namespace Crypto
} // namespace Crt
} // namespace Aws

View File

@@ -0,0 +1,162 @@
#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);
/*
* Add string array parameter.
* True if added successfully and false if failed.
* Aws::Crt::LastError() can be used to retrieve failure error code.
*/
bool AddStringArray(const ByteCursor &name, const Vector<ByteCursor> &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

View File

@@ -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.
*/
uint32_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.
*/
uint32_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

View File

@@ -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

View File

@@ -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

View File

@@ -0,0 +1,161 @@
#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;
class MqttConnectionCore;
} // namespace Mqtt
namespace Mqtt5
{
class Mqtt5ClientCore;
}
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::MqttConnectionCore;
friend class Mqtt5::Mqtt5ClientCore;
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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -0,0 +1,197 @@
#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;
/***
* Read up-to buffer::capacity - buffer::len immediately available bytes 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 ReadSomeImpl(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;
/**
* Peeks the stream
*
* Essentially calls peek on the underlying istream
*
* @return return value of the underlying istream::peek
*/
virtual int64_t PeekImpl() const 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;
bool ReadSomeImpl(ByteBuf &buffer) noexcept override;
StreamStatus GetStatusImpl() const noexcept override;
int64_t GetLengthImpl() const noexcept override;
bool SeekImpl(OffsetType offsetType, StreamSeekBasis seekBasis) noexcept override;
int64_t PeekImpl() const noexcept override;
private:
std::shared_ptr<Aws::Crt::Io::IStream> m_stream;
};
} // namespace Io
} // namespace Crt
} // namespace Aws

View File

@@ -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

View File

@@ -0,0 +1,105 @@
#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.
*/
uint32_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;
};
AWS_CRT_CPP_API Aws::Crt::String EncodeQueryParameterValue(ByteCursor paramValue);
} // namespace Io
} // namespace Crt
} // namespace Aws

View File

@@ -0,0 +1,842 @@
#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>
#include <aws/crt/mqtt/MqttClient.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;
class Mqtt5ClientCore;
class Mqtt5to3AdapterOptions;
/**
* An enumeration that controls how the client applies topic aliasing to outbound publish packets.
*
* Topic alias behavior is described in
* https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901113
*/
enum class OutboundTopicAliasBehaviorType
{
/**
* Maps to Disabled. This keeps the client from being broken (by default) if the broker
* topic aliasing implementation has a problem.
*/
Default = AWS_MQTT5_COTABT_DEFAULT,
/**
* Outbound aliasing is the user's responsibility. Client will cache and use
* previously-established aliases if they fall within the negotiated limits of the connection.
*
* The user must still always submit a full topic in their publishes because disconnections disrupt
* topic alias mappings unpredictably. The client will properly use a requested alias when the
* most-recently-seen binding for a topic alias value matches the alias and topic in the publish packet.
*/
Manual = AWS_MQTT5_COTABT_MANUAL,
/**
* (Recommended) The client will ignore any user-specified topic aliasing and instead use an LRU cache
* to drive alias usage.
*/
LRU = AWS_MQTT5_COTABT_LRU,
/**
* Completely disable outbound topic aliasing.
*/
Disabled = AWS_MQTT5_COTABT_DISABLED,
};
/**
* An enumeration that controls whether or not the client allows the broker to send publishes that use topic
* aliasing.
*
* Topic alias behavior is described in
* https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901113
*/
enum class InboundTopicAliasBehaviorType
{
/**
* Maps to Disabled. This keeps the client from being broken (by default) if the broker
* topic aliasing implementation has a problem.
*/
Default = AWS_MQTT5_CITABT_DEFAULT,
/**
* Allow the server to send PUBLISH packets to the client that use topic aliasing
*/
Enabled = AWS_MQTT5_CITABT_ENABLED,
/**
* Forbid the server from sending PUBLISH packets to the client that use topic aliasing
*/
Disabled = AWS_MQTT5_CITABT_DISABLED,
};
/**
* Configuration for all client topic aliasing behavior.
*/
struct AWS_CRT_CPP_API TopicAliasingOptions
{
/**
* Controls what kind of outbound topic aliasing behavior the client should attempt to use.
*
* If topic aliasing is not supported by the server, this setting has no effect and any attempts to
* directly manipulate the topic alias id in outbound publishes will be ignored.
*
* If left undefined, then outbound topic aliasing is disabled.
*/
Crt::Optional<OutboundTopicAliasBehaviorType> m_outboundBehavior;
/**
* If outbound topic aliasing is set to LRU, this controls the maximum size of the cache. If outbound
* topic aliasing is set to LRU and this is zero or undefined, a sensible default is used (25). If
* outbound topic aliasing is not set to LRU, then this setting has no effect.
*
* The final size of the cache is determined by the minimum of this setting and the value of the
* topic_alias_maximum property of the received CONNACK. If the received CONNACK does not have an
* explicit positive value for that field, outbound topic aliasing is disabled for the duration of that
* connection.
*/
Crt::Optional<uint16_t> m_outboundCacheMaxSize;
/**
* Controls whether or not the client allows the broker to use topic aliasing when sending publishes.
* Even if inbound topic aliasing is enabled, it is up to the server to choose whether or not to use it.
*
* If left undefined, then inbound topic aliasing is disabled.
*/
Crt::Optional<InboundTopicAliasBehaviorType> m_inboundBehavior;
/**
* If inbound topic aliasing is enabled, this will control the size of the inbound alias cache. If
* inbound aliases are enabled and this is zero or undefined, then a sensible default will be used (25).
* If inbound aliases are disabled, this setting has no effect.
*
* Behaviorally, this value overrides anything present in the topic_alias_maximum field of
* the CONNECT packet options.
*/
Crt::Optional<uint16_t> m_inboundCacheMaxSize;
};
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.
*/
ExponentialBackoffJitterMode 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(const OnConnectionSuccessEventData &)>;
/**
* Type signature of the callback invoked when connection failed
*/
using OnConnectionFailureHandler = std::function<void(const OnConnectionFailureEventData &)>;
/**
* Type signature of the callback invoked when the internal connection is shutdown
*/
using OnDisconnectionHandler = std::function<void(const OnDisconnectionEventData &)>;
/**
* Type signature of the callback invoked when attempting connect to client
* Mandatory event fields: client
*/
using OnAttemptingConnectHandler = std::function<void(const OnAttemptingConnectEventData &)>;
/**
* Type signature of the callback invoked when client connection stopped
* Mandatory event fields: client
*/
using OnStoppedHandler = std::function<void(const OnStoppedEventData &)>;
/**
* Type signature of the callback invoked when a Publish Complete
*/
using OnPublishCompletionHandler = std::function<void(int, std::shared_ptr<PublishResult>)>;
/**
* Type signature of the callback invoked when a Subscribe Complete
*/
using OnSubscribeCompletionHandler = std::function<void(int, std::shared_ptr<SubAckPacket>)>;
/**
* Type signature of the callback invoked when a Unsubscribe Complete
*/
using OnUnsubscribeCompletionHandler = std::function<void(int, std::shared_ptr<UnSubAckPacket>)>;
/**
* Type signature of the callback invoked when a PacketPublish message received (OnMessageHandler)
*/
using OnPublishReceivedHandler = std::function<void(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>
{
friend class Mqtt::MqttConnection;
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 disconnectPacket (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> disconnectPacket) noexcept;
/**
* Tells the client to attempt to send a PUBLISH packet
*
* @param publishPacket: 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> publishPacket,
OnPublishCompletionHandler onPublishCompletionCallback = NULL) noexcept;
/**
* Tells the client to attempt to subscribe to one or more topic filters.
*
* @param subscribePacket: 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> subscribePacket,
OnSubscribeCompletionHandler onSubscribeCompletionCallback = NULL) noexcept;
/**
* Tells the client to attempt to unsubscribe to one or more topic filters.
*
* @param unsubscribePacket: 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> unsubscribePacket,
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;
/* The client core to handle the user callbacks and c client termination */
std::shared_ptr<Mqtt5ClientCore> m_client_core;
Mqtt5ClientOperationStatistics m_operationStatistics;
};
/**
* Configuration interface for mqtt5 clients
*/
class AWS_CRT_CPP_API Mqtt5ClientOptions final
{
friend class Mqtt5ClientCore;
friend class Mqtt5to3AdapterOptions;
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(uint32_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 connectPacket package connection options
*
* @return this option object
*/
Mqtt5ClientOptions &WithConnectOptions(std::shared_ptr<ConnectPacket> connectPacket) 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 the topic aliasing behavior for the client.
*
* @param topicAliasingOptions topic aliasing behavior options to use
* @return this options object
*/
Mqtt5ClientOptions &WithTopicAliasingOptions(TopicAliasingOptions topicAliasingOptions) 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;
/**
* @deprecated The function is deprecated, please use `Mqtt5ClientOptions::WithAckTimeoutSec(uint32_t)`
*
* 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 ackTimeoutSec
*
* @return this option object
*/
Mqtt5ClientOptions &WithAckTimeoutSeconds(uint32_t ackTimeoutSec) 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 ackTimeoutSec
*
* @return this option object
*/
Mqtt5ClientOptions &WithAckTimeoutSec(uint32_t ackTimeoutSec) 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.
*/
uint32_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, 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;
/**
* Controls client topic aliasing behavior
*/
aws_mqtt5_client_topic_alias_options m_topicAliasingOptions;
/**
* 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

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,313 @@
#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.
*
* <TABLE>
* <TR><TH colspan="2">Enumerator</TH>
* <TR><TD>AWS_MQTT5_QOS_AT_MOST_ONCE</TD><TD>https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901235</TD>
* <TR><TD>AWS_MQTT5_QOS_AT_LEAST_ONCE</TD><TD>https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901236</TD>
* <TR><TD>AWS_MQTT5_QOS_EXACTLY_ONCE</TD><TD>https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901237</TD>
* </TABLE>
*
*/
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.
*
* <TABLE>
* <TR><TH colspan="2">Enumerator</TH>
* <TR><TD>AWS_MQTT5_CRC_SUCCESS</TD><TD>0</TD>
* <TR><TD>AWS_MQTT5_CRC_UNSPECIFIED_ERROR</TD><TD>128</TD>
* <TR><TD>AWS_MQTT5_CRC_MALFORMED_PACKET</TD><TD>129</TD>
* <TR><TD>AWS_MQTT5_CRC_PROTOCOL_ERROR</TD><TD>130</TD>
* <TR><TD>AWS_MQTT5_CRC_IMPLEMENTATION_SPECIFIC_ERROR</TD><TD>131</TD>
* <TR><TD>AWS_MQTT5_CRC_UNSUPPORTED_PROTOCOL_VERSION</TD><TD>132</TD>
* <TR><TD>AWS_MQTT5_CRC_CLIENT_IDENTIFIER_NOT_VALID</TD><TD>133</TD>
* <TR><TD>AWS_MQTT5_CRC_BAD_USERNAME_OR_PASSWORD</TD><TD>134</TD>
* <TR><TD>AWS_MQTT5_CRC_NOT_AUTHORIZED</TD><TD>135</TD>
* <TR><TD>AWS_MQTT5_CRC_SERVER_UNAVAILABLE</TD><TD>136</TD>
* <TR><TD>AWS_MQTT5_CRC_SERVER_BUSY</TD><TD>137</TD>
* <TR><TD>AWS_MQTT5_CRC_BANNED</TD><TD>138</TD>
* <TR><TD>AWS_MQTT5_CRC_BAD_AUTHENTICATION_METHOD</TD><TD>140</TD>
* <TR><TD>AWS_MQTT5_CRC_TOPIC_NAME_INVALID</TD><TD>144</TD>
* <TR><TD>AWS_MQTT5_CRC_PACKET_TOO_LARGE</TD><TD>149</TD>
* <TR><TD>AWS_MQTT5_CRC_QUOTA_EXCEEDED</TD><TD>151</TD>
* <TR><TD>AWS_MQTT5_CRC_PAYLOAD_FORMAT_INVALID</TD><TD>153</TD>
* <TR><TD>AWS_MQTT5_CRC_RETAIN_NOT_SUPPORTED</TD><TD>154</TD>
* <TR><TD>AWS_MQTT5_CRC_QOS_NOT_SUPPORTED</TD><TD>155</TD>
* <TR><TD>AWS_MQTT5_CRC_USE_ANOTHER_SERVER</TD><TD>156</TD>
* <TR><TD>AWS_MQTT5_CRC_SERVER_MOVED</TD><TD>157</TD>
* <TR><TD>AWS_MQTT5_CRC_CONNECTION_RATE_EXCEEDED</TD><TD>159</TD>
* </TABLE>
*
*
*/
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.
*
* <TABLE>
* <TR><TH colspan="2">Enumerator</TH>
* <TR><TD>AWS_MQTT5_DRC_NORMAL_DISCONNECTION</TD><TD>0</TD>
* <TR><TD>AWS_MQTT5_DRC_DISCONNECT_WITH_WILL_MESSAGE</TD><TD>4</TD>
* <TR><TD>AWS_MQTT5_DRC_UNSPECIFIED_ERROR</TD><TD>128</TD>
* <TR><TD>AWS_MQTT5_DRC_MALFORMED_PACKET</TD><TD>129</TD>
* <TR><TD>AWS_MQTT5_DRC_PROTOCOL_ERROR</TD><TD>130</TD>
* <TR><TD>AWS_MQTT5_DRC_IMPLEMENTATION_SPECIFIC_ERROR</TD><TD>131</TD>
* <TR><TD>AWS_MQTT5_DRC_NOT_AUTHORIZED</TD><TD>135</TD>
* <TR><TD>AWS_MQTT5_DRC_SERVER_BUSY</TD><TD>137</TD>
* <TR><TD>AWS_MQTT5_DRC_SERVER_SHUTTING_DOWN</TD><TD>139</TD>
* <TR><TD>AWS_MQTT5_DRC_KEEP_ALIVE_TIMEOUT</TD><TD>141</TD>
* <TR><TD>AWS_MQTT5_DRC_SESSION_TAKEN_OVER</TD><TD>142</TD>
* <TR><TD>AWS_MQTT5_DRC_TOPIC_FILTER_INVALID</TD><TD>143</TD>
* <TR><TD>AWS_MQTT5_DRC_TOPIC_NAME_INVALID</TD><TD>144</TD>
* <TR><TD>AWS_MQTT5_DRC_RECEIVE_MAXIMUM_EXCEEDED</TD><TD>147</TD>
* <TR><TD>AWS_MQTT5_DRC_TOPIC_ALIAS_INVALID</TD><TD>148</TD>
* <TR><TD>AWS_MQTT5_DRC_PACKET_TOO_LARGE</TD><TD>149</TD>
* <TR><TD>AWS_MQTT5_DRC_MESSAGE_RATE_TOO_HIGH</TD><TD>150</TD>
* <TR><TD>AWS_MQTT5_DRC_QUOTA_EXCEEDED</TD><TD>151</TD>
* <TR><TD>AWS_MQTT5_DRC_ADMINISTRATIVE_ACTION</TD><TD>152</TD>
* <TR><TD>AWS_MQTT5_DRC_PAYLOAD_FORMAT_INVALID</TD><TD>153</TD>
* <TR><TD>AWS_MQTT5_DRC_RETAIN_NOT_SUPPORTED</TD><TD>154</TD>
* <TR><TD>AWS_MQTT5_DRC_QOS_NOT_SUPPORTED</TD><TD>155</TD>
* <TR><TD>AWS_MQTT5_DRC_USE_ANOTHER_SERVER</TD><TD>156</TD>
* <TR><TD>AWS_MQTT5_DRC_SERVER_MOVED</TD><TD>157</TD>
* <TR><TD>AWS_MQTT5_DRC_SHARED_SUBSCRIPTIONS_NOT_SUPPORTED</TD><TD>158</TD>
* <TR><TD>AWS_MQTT5_DRC_CONNECTION_RATE_EXCEEDED</TD><TD>159</TD>
* <TR><TD>AWS_MQTT5_DRC_MAXIMUM_CONNECT_TIME</TD><TD>160</TD>
* <TR><TD>AWS_MQTT5_DRC_SUBSCRIPTION_IDENTIFIERS_NOT_SUPPORTED</TD><TD>161</TD>
* <TR><TD>AWS_MQTT5_DRC_WILDCARD_SUBSCRIPTIONS_NOT_SUPPORTED</TD><TD>162</TD>
* </TABLE>
*
*/
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
* <TABLE>
* <TR><TH colspan="2">Enumerator</TH>
* <TR><TD>AWS_MQTT5_PARC_SUCCESS</TD><TD>0</TD>
* <TR><TD>AWS_MQTT5_PARC_NO_MATCHING_SUBSCRIBERS</TD><TD>16</TD>
* <TR><TD>AWS_MQTT5_PARC_UNSPECIFIED_ERROR</TD><TD>128</TD>
* <TR><TD>AWS_MQTT5_PARC_IMPLEMENTATION_SPECIFIC_ERROR</TD><TD>131</TD>
* <TR><TD>AWS_MQTT5_PARC_NOT_AUTHORIZED</TD><TD>135</TD>
* <TR><TD>AWS_MQTT5_PARC_TOPIC_NAME_INVALID</TD><TD>144</TD>
* <TR><TD>AWS_MQTT5_PARC_PACKET_IDENTIFIER_IN_USE</TD><TD>145</TD>
* <TR><TD>AWS_MQTT5_PARC_QUOTA_EXCEEDED</TD><TD>151</TD>
* <TR><TD>AWS_MQTT5_PARC_PAYLOAD_FORMAT_INVALID</TD><TD>153</TD>
* </TABLE>
*/
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.
*
* <TABLE>
* <TR><TH colspan="2">Enumerator</TH>
* <TR><TD>AWS_MQTT5_PARC_SUCCESS</TD><TD>0</TD>
* <TR><TD>AWS_MQTT5_PARC_NO_MATCHING_SUBSCRIBERS</TD><TD>16</TD>
* <TR><TD>AWS_MQTT5_PARC_UNSPECIFIED_ERROR</TD><TD>128</TD>
* <TR><TD>AWS_MQTT5_PARC_IMPLEMENTATION_SPECIFIC_ERROR</TD><TD>131</TD>
* <TR><TD>AWS_MQTT5_PARC_NOT_AUTHORIZED</TD><TD>135</TD>
* <TR><TD>AWS_MQTT5_PARC_TOPIC_NAME_INVALID</TD><TD>144</TD>
* <TR><TD>AWS_MQTT5_PARC_PACKET_IDENTIFIER_IN_USE</TD><TD>145</TD>
* <TR><TD>AWS_MQTT5_PARC_QUOTA_EXCEEDED</TD><TD>151</TD>
* <TR><TD>AWS_MQTT5_PARC_PAYLOAD_FORMAT_INVALID</TD><TD>153</TD>
* </TABLE>
*/
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.
*
* <TABLE>
* <TR><TH colspan="2">Enumerator</TH>
* <TR><TD>AWS_MQTT5_UARC_SUCCESS</TD><TD>0</TD>
* <TR><TD>AWS_MQTT5_UARC_NO_SUBSCRIPTION_EXISTED</TD><TD>17</TD>
* <TR><TD>AWS_MQTT5_UARC_UNSPECIFIED_ERROR</TD><TD>128</TD>
* <TR><TD>AWS_MQTT5_UARC_IMPLEMENTATION_SPECIFIC_ERROR</TD><TD>131</TD>
* <TR><TD>AWS_MQTT5_UARC_NOT_AUTHORIZED</TD><TD>135</TD>
* <TR><TD>AWS_MQTT5_UARC_TOPIC_FILTER_INVALID</TD><TD>143</TD>
* <TR><TD>AWS_MQTT5_UARC_PACKET_IDENTIFIER_IN_USE</TD><TD>145</TD>
* </TABLE>
*
*/
using UnSubAckReasonCode = aws_mqtt5_unsuback_reason_code;
/**
* Controls how the MQTT5 client should behave with respect to MQTT sessions.
*
* <TABLE>
* <TR><TH colspan="2">Enumerator</TH>
* <TR><TD>AWS_MQTT5_CSBT_DEFAULT</TD><TD>Maps to AWS_MQTT5_CSBT_CLEAN</TD></TR>
* <TR><TD>AWS_MQTT5_CSBT_CLEAN</TD><TD>Always join a new, clean session</TD></TR>
* <TR><TD>AWS_MQTT5_CSBT_REJOIN_POST_SUCCESS</TD><TD>Always attempt to rejoin an existing session after an
* initial connection success.</TD></TR> <TR><TD>AWS_MQTT5_CSBT_REJOIN_ALWAYS</TD><TD>Always attempt to
* rejoin an existing session. Since the client does not support durable session persistence, this option is
* not guaranteed to be spec compliant because any unacknowledged qos1 publishes (which are part of the
* client session state) will not be present on the initial connection. Until we support durable session
* resumption, this option is technically spec-breaking, but useful.</TD></TR>
* </TABLE>
*/
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.
* <TABLE>
* <TR><TH colspan="2">Enumerator</TH>
* <TR><TD>AWS_MQTT5_EVAFCO_NONE</TD><TD>Do not do any additional validation or flow control outside of the
* MQTT5 spec</TD></TR> <TR><TD>AWS_MQTT5_EVAFCO_AWS_IOT_CORE_DEFAULTS</TD><TD>Apply additional client-side
* operational flow control that respects the default AWS IoT Core limits. Applies the following flow
* control: (1) Outbound throughput throttled to 512KB/s (2) Outbound publish TPS throttled to 100</TD></TR>
* </TABLE>
*
*/
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.
*
* <TABLE>
* <TR><TH colspan="2">Enumerator</TH>
* <TR><TD>AWS_MQTT5_COQBT_DEFAULT</TD><TD>Maps to AWS_MQTT5_COQBT_FAIL_QOS0_PUBLISH_ON_DISCONNECT</TD></TR>
* <TR><TD>AWS_MQTT5_COQBT_FAIL_NON_QOS1_PUBLISH_ON_DISCONNECT</TD><TD>Requeues QoS 1+ publishes on
* disconnect; unacked publishes go to the front, unprocessed publishes stay in place. All other operations
* (QoS 0 publishes, subscribe, unsubscribe) are failed.</TD></TR>
* <TR><TD>AWS_MQTT5_COQBT_FAIL_QOS0_PUBLISH_ON_DISCONNECT</TD><TD>Qos 0 publishes that are not complete at
* the time of disconnection are failed. Unacked QoS 1+ publishes are requeued at the head of the line for
* immediate retransmission on a session resumption. All other operations are requeued in the original order
* behind any retransmissions.</TD></TR> <TR><TD>AWS_MQTT5_COQBT_FAIL_ALL_ON_DISCONNECT</TD><TD>All
* operations that are not complete at the time of disconnection are failed, except those operations that
* the MQTT 5 spec requires to be retransmitted (unacked QoS 1+ publishes).</TD></TR>
* </TABLE>
*
*/
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/)
*
* <TABLE>
* <TR><TH colspan="2">Enumerator</TH>
* <TR><TD>AWS_EXPONENTIAL_BACKOFF_JITTER_DEFAULT</TD><TD>Uses AWS_EXPONENTIAL_BACKOFF_JITTER_FULL</TD></TR>
* <TR><TD>AWS_EXPONENTIAL_BACKOFF_JITTER_NONE</TD><TD>No jitter is applied to the exponential
* backoff</TD></TR> <TR><TD>AWS_EXPONENTIAL_BACKOFF_JITTER_FULL</TD><TD>Full jitter is applied to the
* exponential backoff</TD></TR> <TR><TD>AWS_EXPONENTIAL_BACKOFF_JITTER_DECORRELATED</TD><TD>Jitter is
* decorrelated from the backoff sequence</TD></TR>
* </TABLE>
*
*/
using ExponentialBackoffJitterMode = aws_exponential_backoff_jitter_mode;
/** @deprecated JitterMode is deprecated, please use Aws::Crt::Mqtt5::ExponentialBackoffJitterMode */
using JitterMode = ExponentialBackoffJitterMode;
/**
* 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.
*
* <TABLE>
* <TR><TH colspan="2">Enumerator</TH>
* <TR><TD>AWS_MQTT5_PFI_BYTES</TD><TD>Bytes format.</TD></TR>
* <TR><TD>AWS_MQTT5_PFI_UTF8</TD><TD>UTF-8 format.</TD></TR>
* </TABLE>
*/
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.
*
* <TABLE>
* <TR><TH colspan="2">Enumerator</TH>
* <TR><TD>AWS_MQTT5_RHT_SEND_ON_SUBSCRIBE</TD><TD>Server should send all retained messages on topics that
* match the subscription's filter.</TD></TR> <TR><TD>AWS_MQTT5_RHT_SEND_ON_SUBSCRIBE_IF_NEW</TD><TD>Server
* should send all retained messages on topics that match the subscription's filter, where this is the first
* (relative to connection) subscription filter that matches the topic with a retained message.</TD></TR>
* <TR><TD>AWS_MQTT5_RHT_DONT_SEND</TD><TD>Subscribe must not trigger any retained message publishes from
* the server.</TD></TR>
* </TABLE>
*/
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
*
* <TABLE>
* <TR><TH colspan="2">Enumerator</TH>
* <TR><TD>AWS_MQTT5_PT_NONE</TD><TD>Internal indicator that the associated packet is null.</TD></TR>
* <TR><TD>AWS_MQTT5_PT_RESERVED</TD><TD>Reserved.</TD></TR>
* <TR><TD>AWS_MQTT5_PT_CONNECT</TD><TD>CONNECT packet.</TD></TR>
* <TR><TD>AWS_MQTT5_PT_CONNACK</TD><TD>CONNACK packet.</TD></TR>
* <TR><TD>AWS_MQTT5_PT_PUBLISH</TD><TD>PUBLISH packet.</TD></TR>
* <TR><TD>AWS_MQTT5_PT_PUBACK</TD><TD>PUBACK packet.</TD></TR>
* <TR><TD>AWS_MQTT5_PT_PUBREC</TD><TD>PUBREC packet.</TD></TR>
* <TR><TD>AWS_MQTT5_PT_PUBREL</TD><TD>PUBREL packet.</TD></TR>
* <TR><TD>AWS_MQTT5_PT_PUBCOMP</TD><TD>PUBCOMP packet.</TD></TR>
* <TR><TD>AWS_MQTT5_PT_SUBSCRIBE</TD><TD>SUBSCRIBE packet.</TD></TR>
* <TR><TD>AWS_MQTT5_PT_SUBACK</TD><TD>SUBACK packet.</TD></TR>
* <TR><TD>AWS_MQTT5_PT_UNSUBSCRIBE</TD><TD>UNSUBSCRIBE packet.</TD></TR>
* <TR><TD>AWS_MQTT5_PT_UNSUBACK</TD><TD>UNSUBACK packet.</TD></TR>
* <TR><TD>AWS_MQTT5_PT_PINGREQ</TD><TD>PINGREQ packet.</TD></TR>
* <TR><TD>AWS_MQTT5_PT_PINGRESP</TD><TD>PINGRESP packet.</TD></TR>
* <TR><TD>AWS_MQTT5_PT_DISCONNECT</TD><TD>DISCONNECT packet.</TD></TR>
* <TR><TD>AWS_MQTT5_PT_AUTH</TD><TD>AUTH packet.</TD></TR>
* </TABLE>
*
*/
using PacketType = aws_mqtt5_packet_type;
} // namespace Mqtt5
} // namespace Crt
} // namespace Aws

View File

@@ -0,0 +1,121 @@
#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/crt/mqtt/MqttConnection.h>
#include <aws/mqtt/client.h>
#include <aws/mqtt/v5/mqtt5_client.h>
#include <atomic>
#include <functional>
#include <memory>
namespace Aws
{
namespace Crt
{
namespace Io
{
class ClientBootstrap;
}
namespace Http
{
class HttpRequest;
}
namespace Mqtt5
{
class Mqtt5ClientCore;
}
namespace Mqtt
{
/**
* 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,
uint32_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,
uint32_t port,
const Io::SocketOptions &socketOptions,
bool useWebsocket = false) noexcept;
private:
aws_mqtt_client *m_client;
};
} // namespace Mqtt
} // namespace Crt
} // namespace Aws

View File

@@ -0,0 +1,462 @@
#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/crt/mqtt/MqttTypes.h>
#include <aws/mqtt/client.h>
#include <aws/mqtt/v5/mqtt5_client.h>
#include <functional>
#include <memory>
namespace Aws
{
namespace Crt
{
namespace Http
{
class HttpRequest;
}
namespace Mqtt5
{
class Mqtt5Client;
class Mqtt5ClientCore;
} // namespace Mqtt5
namespace Mqtt
{
class MqttClient;
class MqttConnectionCore;
class MqttConnection;
/**
* The data returned when the connection closed callback is invoked in a connection.
* Note: This class is currently empty, but this may contain data in the future.
*/
struct OnConnectionClosedData
{
};
/**
* The data returned when the connection success callback is invoked in a connection.
*/
struct OnConnectionSuccessData
{
/**
* The Connect return code received from the server.
*/
ReturnCode returnCode;
/**
* Returns whether a session was present and resumed for this successful connection.
* Will be set to true if the connection resumed an already present MQTT connection session.
*/
bool sessionPresent;
};
/**
* The data returned when the connection failure callback is invoked in a connection.
*/
struct OnConnectionFailureData
{
/**
* The AWS CRT error code for the connection failure.
* Use Aws::Crt::ErrorDebugString to get a human readable string from the error code.
*/
int error;
};
/**
* 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 connection is disconnected and shutdown successfully.
*
* Note: Currently callbackData will always be nullptr, but this may change in the future to send additional
* data.
*/
using OnConnectionClosedHandler =
std::function<void(MqttConnection &connection, OnConnectionClosedData *callbackData)>;
/**
* Invoked whenever the connection successfully connects.
*
* This callback is invoked for every successful connect and every successful reconnect.
*/
using OnConnectionSuccessHandler =
std::function<void(MqttConnection &connection, OnConnectionSuccessData *callbackData)>;
/**
* Invoked whenever the connection fails to connect.
*
* This callback is invoked for every failed connect and every failed reconnect.
*/
using OnConnectionFailureHandler =
std::function<void(MqttConnection &connection, OnConnectionFailureData *callbackData)>;
/**
* Invoked when a disconnect message has been sent.
*/
using OnDisconnectHandler = std::function<void(MqttConnection &connection)>;
/**
* @deprecated Use OnMessageReceivedHandler
*/
using OnPublishReceivedHandler =
std::function<void(MqttConnection &connection, const String &topic, const ByteBuf &payload)>;
/**
* 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)>;
/**
* Represents a persistent Mqtt Connection. The memory is owned by MqttClient or Mqtt5Client.
*
* To get a new instance of this class, use MqttClient::NewConnection or Mqtt5Client::NewConnection. Unless
* specified all function arguments need only to live through the duration of the function call.
*
* @sa MqttClient::NewConnection
* @sa Mqtt5Client::NewConnection
*/
class AWS_CRT_CPP_API MqttConnection final : public std::enable_shared_from_this<MqttConnection>
{
friend class MqttClient;
friend class Mqtt5::Mqtt5ClientCore;
public:
~MqttConnection();
MqttConnection(const MqttConnection &) = delete;
MqttConnection(MqttConnection &&) = delete;
MqttConnection &operator=(const MqttConnection &) = delete;
MqttConnection &operator=(MqttConnection &&) = delete;
/**
* Create a new MqttConnection object from the Mqtt5Client.
* @param mqtt5client The shared ptr of Mqtt5Client
*
* @return std::shared_ptr<Crt::Mqtt::MqttConnection>
*/
static std::shared_ptr<Crt::Mqtt::MqttConnection> NewConnectionFromMqtt5Client(
std::shared_ptr<Mqtt5::Mqtt5Client> mqtt5client) 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;
/**
* 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;
/**
* A callback invoked every time the connections is interrupted.
*/
OnConnectionInterruptedHandler OnConnectionInterrupted;
/**
* A callback invoked every time the connection is resumed.
*/
OnConnectionResumedHandler OnConnectionResumed;
/**
* Invoked when a connack message is received, or an error occurred.
*/
OnConnectionCompletedHandler OnConnectionCompleted;
/**
* A callback invoked on disconnect.
*/
OnDisconnectHandler OnDisconnect;
/**
* 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.
*/
OnWebSocketHandshakeIntercept WebsocketInterceptor;
/**
* Invoked when a connection is disconnected and shutdown successfully.
*
* @note Currently callbackData will always be nullptr, but this may change in the future to send
* additional data.
* @note From the user perspective, this callback is indistinguishable from OnDisconnect.
*/
OnConnectionClosedHandler OnConnectionClosed;
/**
* Invoked whenever the connection successfully connects.
*
* This callback is invoked for every successful connect and every successful reconnect.
*/
OnConnectionSuccessHandler OnConnectionSuccess;
/**
* Invoked whenever the connection fails to connect.
*
* This callback is invoked for every failed connect and every failed reconnect.
*/
OnConnectionFailureHandler OnConnectionFailure;
private:
/**
* Constructor.
*
* Make private to restrict ability to create MqttConnections objects to certain classes.
*/
MqttConnection() = default;
/**
* @internal
* Factory method for creating MqttConnection.
*
* @param client MQTT3 client.
* @param options Options required for MqttConnection creation.
* @return New instance of MqttConnection.
*/
static std::shared_ptr<MqttConnection> s_CreateMqttConnection(
aws_mqtt_client *client,
MqttConnectionOptions options) noexcept;
/**
* @internal
* Factory method for creating MqttConnection.
*
* @param mqtt5Client MQTT5 client.
* @param options Options required for MqttConnection creation.
* @return New instance of MqttConnection.
*/
static std::shared_ptr<MqttConnection> s_CreateMqttConnection(
aws_mqtt5_client *mqtt5Client,
MqttConnectionOptions options) noexcept;
/**
* @internal
* Internal handler for the underlying connection.
*/
std::shared_ptr<MqttConnectionCore> m_connectionCore;
};
} // namespace Mqtt
} // namespace Crt
} // namespace Aws

View File

@@ -0,0 +1,130 @@
#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/SocketOptions.h>
#include <aws/crt/io/TlsOptions.h>
#include <aws/mqtt/client.h>
#include <aws/mqtt/v5/mqtt5_client.h>
#include <functional>
namespace Aws
{
namespace Crt
{
namespace Mqtt
{
class MqttConnection;
/**
* Options required to create an MqttConnection.
*/
struct MqttConnectionOptions
{
const char *hostName = nullptr;
uint32_t port = 0;
Io::SocketOptions socketOptions;
Crt::Io::TlsContext tlsContext;
Crt::Io::TlsConnectionOptions tlsConnectionOptions;
bool useWebsocket = false;
bool useTls = false;
Allocator *allocator = nullptr;
};
/**
* 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)>;
/**
* Invoked when a suback message is received.
*
* @param connection The connection object.
* @param packetId Packet ID of the corresponding subscribe request.
* @param topic The information channel to which the payload data was published.
* @param qos Quality of Service used to deliver the message.
* @param errorCode Indicating if an error occurred.
*/
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.
*
* @param connection The connection object.
* @param packetId Packet ID of the corresponding subscribe request.
* @param topics The information channels to which the payload data was published.
* @param qos Quality of Service used to deliver the message.
* @param errorCode Indicating if an error occurred.
*/
using OnMultiSubAckHandler = std::function<void(
MqttConnection &connection,
uint16_t packetId,
const Vector<String> &topics,
QOS qos,
int errorCode)>;
/**
* 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.
*
* @param connection The connection object.
* @param packetId Packet ID of the corresponding subscribe request.
* @param errorCode Indicating if an error occurred.
*/
using OnOperationCompleteHandler =
std::function<void(MqttConnection &connection, uint16_t packetId, int errorCode)>;
/**
* 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;
};
} // namespace Mqtt
} // namespace Crt
} // namespace Aws