Skip to content

H1b #56

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 15 commits into from
Aug 28, 2019
Merged
2 changes: 1 addition & 1 deletion aws-common-runtime/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,5 @@ set(AWS_DEPS_DOWNLOAD_DIR "${AWS_DEPS_BUILD_DIR}/downloads" CACHE PATH "Dependen
message("install dir ${AWS_DEPS_INSTALL_DIR}")

set(AWS_CRT_CPP_URL "https://github.com/awslabs/aws-crt-cpp.git")
set(AWS_CRT_CPP_SHA "v0.4.6")
set(AWS_CRT_CPP_SHA "v0.5.2")
include(BuildAwsCrtCpp)
2 changes: 1 addition & 1 deletion codebuild/common-posix.sh
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ fi

# build aws-crt-cpp
pushd $BUILD_PATH
git clone --branch v0.4.6 https://github.com/awslabs/aws-crt-cpp.git
git clone --branch v0.5.2 https://github.com/awslabs/aws-crt-cpp.git
cd aws-crt-cpp
cmake $CMAKE_ARGS -DBUILD_DEPS=ON ./
cmake --build . --target install
Expand Down
2 changes: 1 addition & 1 deletion codebuild/common-windows.bat
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ mkdir %INSTALL_DIR%
@rem build aws-crt-cpp
mkdir %BUILDS_DIR%\aws-crt-cpp-build
cd %BUILDS_DIR%\aws-crt-cpp-build
git clone --branch v0.4.6 https://github.com/awslabs/aws-crt-cpp.git
git clone --branch v0.5.2 https://github.com/awslabs/aws-crt-cpp.git
cmake %CMAKE_ARGS% -DCMAKE_INSTALL_PREFIX="%INSTALL_DIR%" -DCMAKE_PREFIX_PATH="%INSTALL_DIR%" -DCMAKE_BUILD_TYPE="Release" -DBUILD_DEPS=ON aws-crt-cpp || goto error
cmake --build . --target install || goto error

Expand Down
107 changes: 96 additions & 11 deletions discovery/include/aws/discovery/DiscoveryClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,26 +22,111 @@ namespace Aws
{
using OnDiscoverResponse = std::function<void(DiscoverResponse *, int errorCode, int httpResponseCode)>;

struct DiscoveryClientConfig
class AWS_DISCOVERY_API DiscoveryClientConfig
{
public:
DiscoveryClientConfig() noexcept;
Crt::Allocator *allocator;
Crt::Io::ClientBootstrap *bootstrap;
Crt::Io::TlsContext *tlsContext;
Crt::Io::SocketOptions *socketOptions;
Crt::String region;
size_t maxConnections;
// TODO: when supported add proxy configuration.
DiscoveryClientConfig(const DiscoveryClientConfig &rhs) = default;
DiscoveryClientConfig(DiscoveryClientConfig &&rhs) = default;

DiscoveryClientConfig &operator=(const DiscoveryClientConfig &rhs) = default;
DiscoveryClientConfig &operator=(DiscoveryClientConfig &&rhs) = default;

~DiscoveryClientConfig() = default;

/**
* Sets the client bootstrap to use for setting up and tearing down connections.
* This value must be set.
*/
void SetBootstrap(Crt::Io::ClientBootstrap *bootstrap) noexcept { m_bootstrap = bootstrap; }

/**
* Gets the client bootstrap to use for setting up and tearing down connections.
*/
Crt::Io::ClientBootstrap *GetBootstrap() const noexcept { return m_bootstrap; }

/**
* Sets the TLS options for all http connections made by this client
*/
void SetTlsContext(const Crt::Io::TlsContext &context) noexcept { m_tlsContext = context; }

/**
* Gets the TLS options for all http connections made by this client
*/
const Crt::Io::TlsContext *GetTlsContext() const noexcept
{
return m_tlsContext.has_value() ? &m_tlsContext.value() : nullptr;
}

/**
* Sets the socket options of the connections made by the client.
* This value must be set.
*/
void SetSocketOptions(const Crt::Io::SocketOptions &options) noexcept { m_socketOptions = options; }

/**
* Gets the socket options of the connections made by the client
*/
const Crt::Io::SocketOptions &GetSocketOptions() const noexcept { return m_socketOptions; }

/**
* Sets the value of the Aws region to connect to.
* This value must be set.
*/
void SetRegion(const Crt::String &region) noexcept { m_region = region; }

/**
* Gets the value of the Aws region to connect to.
*/
const Crt::String &GetRegion() const noexcept { return m_region; }

/**
* Sets the maximum number of concurrent connections allowed
*/
void SetMaxConnections(size_t maxConnections) noexcept { m_maxConnections = maxConnections; }

/**
* Gets the maximum number of concurrent connections allowed
*/
size_t GetMaxConnections() const noexcept { return m_maxConnections; }

/**
* Sets the proxy options for all http connections made by this client
*/
void SetProxyOptions(const Crt::Http::HttpClientConnectionProxyOptions &options) noexcept
{
m_proxyOptions = options;
}

/**
* Gets the proxy options for all http connections made by this client
*/
const Crt::Http::HttpClientConnectionProxyOptions *GetProxyOptions() const noexcept
{
return m_proxyOptions.has_value() ? &m_proxyOptions.value() : nullptr;
}

private:
Crt::Io::ClientBootstrap *m_bootstrap;
Crt::Optional<Crt::Io::TlsContext> m_tlsContext;
Crt::Io::SocketOptions m_socketOptions;
Crt::String m_region;
size_t m_maxConnections;
Crt::Optional<Crt::Http::HttpClientConnectionProxyOptions> m_proxyOptions;
};

class DiscoveryClient final
class AWS_DISCOVERY_API DiscoveryClient final
{
public:
DiscoveryClient(const DiscoveryClientConfig &) noexcept;

bool Discover(const Crt::String &thingName, const OnDiscoverResponse &onDiscoverResponse) noexcept;

static std::shared_ptr<DiscoveryClient> CreateClient(
const DiscoveryClientConfig &config,
Crt::Allocator *allocator = Crt::DefaultAllocator());

private:
DiscoveryClient(const DiscoveryClientConfig &config, Crt::Allocator *allocator) noexcept;

std::shared_ptr<Crt::Http::HttpClientConnectionManager> m_connectionManager;
Crt::String m_hostName;
Crt::Allocator *m_allocator;
Expand Down
182 changes: 109 additions & 73 deletions discovery/source/DiscoveryClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
*/
#include <aws/discovery/DiscoveryClient.h>

#include <aws/crt/Api.h>
#include <aws/crt/Types.h>
#include <aws/crt/http/HttpRequestResponse.h>
#include <aws/crt/io/TlsOptions.h>
#include <aws/crt/io/Uri.h>

Expand All @@ -22,23 +24,24 @@ namespace Aws
namespace Discovery
{
DiscoveryClientConfig::DiscoveryClientConfig() noexcept
: allocator(Crt::DefaultAllocator()), bootstrap(nullptr), tlsContext(nullptr), socketOptions(nullptr),
region("us-east-1"), maxConnections(2)
: m_bootstrap(nullptr), m_tlsContext(), m_socketOptions(), m_region(),
m_maxConnections(2), m_proxyOptions()
{
}

DiscoveryClient::DiscoveryClient(const Aws::Discovery::DiscoveryClientConfig &clientConfig) noexcept
DiscoveryClient::DiscoveryClient(
const Aws::Discovery::DiscoveryClientConfig &clientConfig,
Crt::Allocator *allocator) noexcept
{
AWS_ASSERT(clientConfig.tlsContext);
AWS_ASSERT(clientConfig.bootstrap);
AWS_ASSERT(clientConfig.socketOptions);
AWS_ASSERT(clientConfig.GetTlsContext());
AWS_ASSERT(clientConfig.GetBootstrap());

m_allocator = clientConfig.allocator;
m_allocator = allocator;

Crt::StringStream ss;
ss << "greengrass-ats.iot." << clientConfig.region << ".amazonaws.com";
ss << "greengrass-ats.iot." << clientConfig.GetRegion() << ".amazonaws.com";

Crt::Io::TlsConnectionOptions tlsConnectionOptions = clientConfig.tlsContext->NewConnectionOptions();
Crt::Io::TlsConnectionOptions tlsConnectionOptions = clientConfig.GetTlsContext()->NewConnectionOptions();
uint16_t port = 443;

if (Crt::Io::TlsContextOptions::IsAlpnSupported())
Expand All @@ -54,17 +57,39 @@ namespace Aws
Crt::ByteCursor serverName = Crt::ByteCursorFromCString(m_hostName.c_str());
tlsConnectionOptions.SetServerName(serverName);

Crt::Http::HttpClientConnectionOptions connectionOptions;
connectionOptions.SetSocketOptions(clientConfig.GetSocketOptions());
connectionOptions.SetBootstrap(clientConfig.GetBootstrap());
connectionOptions.SetTlsOptions(tlsConnectionOptions);
connectionOptions.SetInitialWindowSize(SIZE_MAX);
connectionOptions.SetHostName(Crt::String((const char *)serverName.ptr, serverName.len));
connectionOptions.SetPort(port);
if (clientConfig.GetProxyOptions())
{
connectionOptions.SetProxyOptions(*clientConfig.GetProxyOptions());
}

Crt::Http::HttpClientConnectionManagerOptions connectionManagerOptions;
connectionManagerOptions.socketOptions = clientConfig.socketOptions;
connectionManagerOptions.bootstrap = clientConfig.bootstrap;
connectionManagerOptions.tlsConnectionOptions = &tlsConnectionOptions;
connectionManagerOptions.maxConnections = clientConfig.maxConnections;
connectionManagerOptions.initialWindowSize = SIZE_MAX;
connectionManagerOptions.hostName = serverName;
connectionManagerOptions.port = port;

m_connectionManager = Crt::Http::HttpClientConnectionManager::NewClientConnectionManager(
connectionManagerOptions, clientConfig.allocator);
connectionManagerOptions.SetConnectionOptions(connectionOptions);
connectionManagerOptions.SetMaxConnections(clientConfig.GetMaxConnections());

m_connectionManager =
Crt::Http::HttpClientConnectionManager::NewClientConnectionManager(connectionManagerOptions, allocator);
}

std::shared_ptr<DiscoveryClient> DiscoveryClient::CreateClient(
const Aws::Discovery::DiscoveryClientConfig &clientConfig,
Crt::Allocator *allocator)
{
auto *toSeat = static_cast<DiscoveryClient *>(aws_mem_acquire(allocator, sizeof(DiscoveryClient)));
if (toSeat)
{
toSeat = new (toSeat) DiscoveryClient(clientConfig, allocator);
return std::shared_ptr<DiscoveryClient>(
toSeat, [allocator](DiscoveryClient *client) { Crt::Delete(client, allocator); });
}

return nullptr;
}

struct ClientCallbackContext
Expand All @@ -77,8 +102,7 @@ namespace Aws
const Crt::String &thingName,
const OnDiscoverResponse &onDiscoverResponse) noexcept
{

auto *callbackContext = Crt::New<ClientCallbackContext>(m_allocator);
auto callbackContext = Crt::MakeShared<ClientCallbackContext>(m_allocator);
if (!callbackContext)
{
return false;
Expand All @@ -89,69 +113,81 @@ namespace Aws
bool res = m_connectionManager->AcquireConnection(
[this, callbackContext, thingName, onDiscoverResponse](
std::shared_ptr<Crt::Http::HttpClientConnection> connection, int errorCode) {
if (!errorCode)
if (errorCode)
{
Crt::StringStream ss;
ss << "/greengrass/discover/thing/" << thingName;
Crt::String uriStr = ss.str();
Crt::Http::HttpRequestOptions requestOptions;
requestOptions.uri = Crt::ByteCursorFromCString(uriStr.c_str());
requestOptions.method = Crt::ByteCursorFromCString("GET");

Crt::Http::HttpHeader hostNameHeader;
hostNameHeader.name = Crt::ByteCursorFromCString("host");
hostNameHeader.value = Crt::ByteCursorFromCString(m_hostName.c_str());

requestOptions.headerArray = &hostNameHeader;
requestOptions.headerArrayLength = 1;

requestOptions.onStreamOutgoingBody = nullptr;
requestOptions.onIncomingHeaders =
[](Crt::Http::HttpStream &, const Crt::Http::HttpHeader *, std::size_t) {};
requestOptions.onIncomingHeadersBlockDone =
[callbackContext](Crt::Http::HttpStream &stream, bool) {
callbackContext->responseCode = stream.GetResponseStatusCode();
};
requestOptions.onIncomingBody =
[callbackContext](Crt::Http::HttpStream &, const Crt::ByteCursor &data, std::size_t &) {
callbackContext->ss.write(reinterpret_cast<const char *>(data.ptr), data.len);
};
requestOptions.onStreamComplete = [this, connection, callbackContext, onDiscoverResponse](
Crt::Http::HttpStream &stream, int errorCode) {
if (!errorCode && callbackContext->responseCode == 200)
{
Crt::JsonObject jsonObject(callbackContext->ss.str());
DiscoverResponse response(jsonObject.View());
onDiscoverResponse(&response, AWS_ERROR_SUCCESS, callbackContext->responseCode);
}
else
{
if (!errorCode)
{
errorCode = AWS_ERROR_UNKNOWN;
}
onDiscoverResponse(nullptr, errorCode, callbackContext->responseCode);
}
onDiscoverResponse(nullptr, errorCode, 0);
return;
}

Crt::Delete(callbackContext, m_allocator);
};
auto request = Aws::Crt::MakeShared<Crt::Http::HttpRequest>(m_allocator, m_allocator);
if (request == nullptr)
{
onDiscoverResponse(nullptr, Crt::LastErrorOrUnknown(), 0);
return;
}

if (!connection->NewClientStream(requestOptions))
{
onDiscoverResponse(nullptr, aws_last_error(), 0);
Crt::Delete(callbackContext, m_allocator);
}
Crt::StringStream ss;
ss << "/greengrass/discover/thing/" << thingName;
Crt::String uriStr = ss.str();
if (!request->SetMethod(Crt::ByteCursorFromCString("GET")))
{
onDiscoverResponse(nullptr, Crt::LastErrorOrUnknown(), 0);
return;
}

if (!request->SetPath(Crt::ByteCursorFromCString(uriStr.c_str())))
{
onDiscoverResponse(nullptr, Crt::LastErrorOrUnknown(), 0);
return;
}

Crt::Http::HttpHeader hostNameHeader;
hostNameHeader.name = Crt::ByteCursorFromCString("host");
hostNameHeader.value = Crt::ByteCursorFromCString(m_hostName.c_str());

if (!request->AddHeader(hostNameHeader))
{
onDiscoverResponse(nullptr, Crt::LastErrorOrUnknown(), 0);
return;
}

onDiscoverResponse(nullptr, errorCode, 0);
Crt::Delete(callbackContext, m_allocator);
Crt::Http::HttpRequestOptions requestOptions;
requestOptions.request = request.get();
requestOptions.onIncomingHeaders =
[](Crt::Http::HttpStream &, const Crt::Http::HttpHeader *, std::size_t) {};
requestOptions.onIncomingHeadersBlockDone = [callbackContext](Crt::Http::HttpStream &stream, bool) {
callbackContext->responseCode = stream.GetResponseStatusCode();
};
requestOptions.onIncomingBody =
[callbackContext](Crt::Http::HttpStream &, const Crt::ByteCursor &data) {
callbackContext->ss.write(reinterpret_cast<const char *>(data.ptr), data.len);
};
requestOptions.onStreamComplete = [request, connection, callbackContext, onDiscoverResponse](
Crt::Http::HttpStream &, int errorCode) {
if (!errorCode && callbackContext->responseCode == 200)
{
Crt::JsonObject jsonObject(callbackContext->ss.str());
DiscoverResponse response(jsonObject.View());
onDiscoverResponse(&response, AWS_ERROR_SUCCESS, callbackContext->responseCode);
}
else
{
if (!errorCode)
{
errorCode = AWS_ERROR_UNKNOWN;
}
onDiscoverResponse(nullptr, errorCode, callbackContext->responseCode);
}
};

if (!connection->NewClientStream(requestOptions))
{
onDiscoverResponse(nullptr, Crt::LastErrorOrUnknown(), 0);
}
});

if (!res)
{
Crt::Delete(callbackContext, m_allocator);
return false;
}

Expand Down
Loading