Skip to content

Commit

Permalink
Connection manager (#18)
Browse files Browse the repository at this point in the history
* HttpClientConnection manager and unit tests.

* Updated Http tag.

* Updated common version.

* Updated aws-c-io tag.

* HttpConnection can clean itself up


* Added host resolver, updates to handle io changes, added test for host resolver.
  • Loading branch information
JonathanHenson authored Apr 10, 2019
1 parent 30f4fb0 commit be7daab
Show file tree
Hide file tree
Showing 22 changed files with 1,172 additions and 4,284 deletions.
10 changes: 5 additions & 5 deletions aws-common-runtime/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,25 +17,25 @@ set(AWS_DEPS_DOWNLOAD_DIR "${AWS_DEPS_BUILD_DIR}/downloads" CACHE PATH "Dependen

message("install dir ${AWS_DEPS_INSTALL_DIR}")
set(AWS_C_COMMON_URL "https://github.com/awslabs/aws-c-common.git")
set(AWS_C_COMMON_SHA "v0.3.4")
set(AWS_C_COMMON_SHA "v0.3.6")
include(BuildAwsCCommon)

if (UNIX AND NOT APPLE)
set(S2N_URL "https://github.com/awslabs/s2n.git")
set(S2N_SHA "ff1a8b2187ded17ee5570fd54f15c58f2175ce51")
set(S2N_SHA "db4fe111c6e64a206662524da31a5aba6b0932a8")
include(BuildS2N)
endif()

set(AWS_C_IO_URL "https://github.com/awslabs/aws-c-io.git")
set(AWS_C_IO_SHA "v0.2.5")
set(AWS_C_IO_SHA "v0.3.0")
include(BuildAwsCIO)

set(AWS_C_HTTP_URL "https://github.com/awslabs/aws-c-http.git")
set(AWS_C_HTTP_SHA "v0.1.0")
set(AWS_C_HTTP_SHA "v0.2.1")
include(BuildAwsCHttp)

set(AWS_C_MQTT_URL "https://github.com/awslabs/aws-c-mqtt.git")
set(AWS_C_MQTT_SHA "v0.3.3")
set(AWS_C_MQTT_SHA "v0.3.4")
include(BuildAwsCMqtt)

set(AWS_C_CAL_URL "https://github.com/awslabs/aws-c-cal.git")
Expand Down
5 changes: 4 additions & 1 deletion aws-common-runtime/cmake/BuildS2N.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@ if("${TARGET_ARCH}" STREQUAL ANDROID)
-DANDROID_TOOLCHAIN_NAME=${ANDROID_TOOLCHAIN_NAME}
-DANDROID_STANDALONE_TOOLCHAIN=${ANDROID_STANDALONE_TOOLCHAIN}
-DANDROID_STL=${ANDROID_STL}
-DENABLE_HW_OPTIMIZATION=OFF
-DCMAKE_C_FLAGS=${CMAKE_C_FLAGS}
-DBUILD_TESTING=OFF
-DUSE_S2N_PQ_CRYPTO=OFF
)
else()
ExternalProject_Add(S2N
Expand All @@ -37,5 +38,7 @@ else()
-DBUILD_SHARED_LIBS=${BUILD_SHARED_LIBS}
-DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}
-DCMAKE_C_FLAGS=${CMAKE_C_FLAGS}
-DBUILD_TESTING=OFF
-DUSE_S2N_PQ_CRYPTO=OFF
)
endif()
2 changes: 2 additions & 0 deletions include/aws/crt/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <aws/io/socket.h>
#include <aws/mqtt/mqtt.h>

#include <list>
#include <map>
#include <sstream>
#include <string>
Expand Down Expand Up @@ -62,6 +63,7 @@ namespace Aws
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 Allocator *DefaultAllocator() noexcept;
AWS_CRT_CPP_API ByteBuf ByteBufFromCString(const char *str) noexcept;
Expand Down
11 changes: 7 additions & 4 deletions include/aws/crt/http/HttpConnection.h
Original file line number Diff line number Diff line change
Expand Up @@ -324,14 +324,19 @@ namespace Aws
*/
std::shared_ptr<HttpClientStream> NewClientStream(const HttpRequestOptions &requestOptions) noexcept;

/**
* Returns 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. It is safe to release your reference to this object after calling this function.
* call.
*/
bool Close() noexcept;
void Close() noexcept;

int LastError() const noexcept { return m_lastError; }

Expand Down Expand Up @@ -359,8 +364,6 @@ namespace Aws
struct aws_http_connection *connection,
int error_code,
void *user_data) noexcept;

friend class HttpClient;
};

} // namespace Http
Expand Down
103 changes: 103 additions & 0 deletions include/aws/crt/http/HttpConnectionManager.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
#pragma once
/*
* Copyright 2010-2019 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.
*/
#include <aws/crt/http/HttpConnection.h>
#include <condition_variable>
#include <mutex>

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. It is your responsibility to release the connection when you are finished with it.
*/
using OnClientConnectionAvailable =
std::function<void(std::shared_ptr<HttpClientConnection> connection, int errorCode)>;

struct HttpClientConnectionManagerOptions
{
HttpClientConnectionManagerOptions();
Io::ClientBootstrap *bootstrap;
size_t initialWindowSize;
Io::SocketOptions *socketOptions;
Io::TlsConnectionOptions *tlsConnectionOptions;
ByteCursor hostName;
uint16_t port;
size_t maxConnections;
};

/**
* Manages a pool of connections to a specific endpoint using the same socket and tls options.
*/
class 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 pooled, returns false if it
* failed. On failure, onClientConnectionAvailable will not be invoked. After receiving a connection,
* you must invoke ReleaseConnection().
*/
bool AcquireConnection(const OnClientConnectionAvailable &onClientConnectionAvailable) noexcept;

/**
* Releases a connection back to the pool. This will cause queued consumers to be serviced, or the
* connection will be pooled waiting on another call to AcquireConnection
*/
void ReleaseConnection(std::shared_ptr<HttpClientConnection> connection) noexcept;

int LastError() const noexcept { return m_lastError; }
explicit operator bool() const noexcept { return m_good; }

static std::shared_ptr<HttpClientConnectionManager> NewClientConnectionManager(
const HttpClientConnectionManagerOptions &connectionManagerOptions,
Allocator *allocator = DefaultAllocator()) noexcept;

private:
HttpClientConnectionManager(
const HttpClientConnectionManagerOptions &connectionManagerOptions,
Allocator *allocator = DefaultAllocator()) noexcept;

Vector<std::shared_ptr<HttpClientConnection>> m_connections;
List<OnClientConnectionAvailable> m_pendingConnectionRequests;
Allocator *m_allocator;
Io::ClientBootstrap *m_bootstrap;
size_t m_initialWindowSize;
Io::SocketOptions m_socketOptions;
Io::TlsConnectionOptions m_tlsConnOptions;
String m_hostName;
uint16_t m_port;
bool m_good;
int m_lastError;
size_t m_maxSize;
size_t m_outstandingVendedConnections;
size_t m_pendingConnections;
std::mutex m_connectionsLock;

void onConnectionSetup(const std::shared_ptr<HttpClientConnection> &connection, int errorCode) noexcept;
void onConnectionShutdown(HttpClientConnection &connection, int errorCode) noexcept;
bool createConnection() noexcept;
void poolOrVendConnection(std::shared_ptr<HttpClientConnection> connection, bool isRelease) noexcept;
};
} // namespace Http
} // namespace Crt
} // namespace Aws
13 changes: 9 additions & 4 deletions include/aws/crt/io/Bootstrap.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@
#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>

namespace Aws
{
Expand All @@ -29,12 +31,15 @@ namespace Aws
class AWS_CRT_CPP_API ClientBootstrap final
{
public:
ClientBootstrap(EventLoopGroup &elGroup, Allocator *allocator = DefaultAllocator()) noexcept;
ClientBootstrap(
EventLoopGroup &elGroup,
HostResolver &resolver,
Allocator *allocator = DefaultAllocator()) noexcept;
~ClientBootstrap();
ClientBootstrap(const ClientBootstrap &) = delete;
ClientBootstrap &operator=(const ClientBootstrap &) = delete;
ClientBootstrap(ClientBootstrap &&) noexcept;
ClientBootstrap &operator=(ClientBootstrap &&) noexcept;
ClientBootstrap(ClientBootstrap &&) = delete;
ClientBootstrap &operator=(ClientBootstrap &&) = delete;

operator bool() const noexcept;
int LastError() const noexcept;
Expand All @@ -47,4 +52,4 @@ namespace Aws
};
} // namespace Io
} // namespace Crt
} // namespace Aws
} // namespace Aws
94 changes: 94 additions & 0 deletions include/aws/crt/io/HostResolver.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
#pragma once
/*
* Copyright 2010-2019 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.
*/
#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)>;

class HostResolver
{
public:
virtual ~HostResolver();
virtual bool ResolveHost(const String &host, const OnHostResolved &onResolved) noexcept = 0;
virtual aws_host_resolver *GetUnderlyingHandle() noexcept = 0;
virtual aws_host_resolution_config *GetConfig() noexcept = 0;
};

class DefaultHostResolver final : public HostResolver
{
public:
/**
* Resolves DNS addresses. maxHosts is the number of unique hosts to maintain in the cache. maxTTL is
* how long to keep an address in the cache before evicting it.
*/
DefaultHostResolver(
EventLoopGroup &elGroup,
size_t maxHosts,
size_t maxTTL,
Allocator *allocator = DefaultAllocator()) noexcept;
~DefaultHostResolver();
DefaultHostResolver(const DefaultHostResolver &) = delete;
DefaultHostResolver &operator=(const DefaultHostResolver &) = delete;
DefaultHostResolver(DefaultHostResolver &&) = delete;
DefaultHostResolver &operator=(DefaultHostResolver &&) = delete;

operator bool() const noexcept { return m_initialized; }

/**
* Kicks off an asynchronous resolution of host. onResolved will be invoked upon completion of the
* resolution. If this returns false, the resolution was not attempted. On true, onResolved will be
* called with the result.
*/
bool ResolveHost(const String &host, const OnHostResolved &onResolved) noexcept override;
aws_host_resolver *GetUnderlyingHandle() noexcept override { return &m_resolver; }
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
3 changes: 2 additions & 1 deletion samples/mqtt_pub_sub/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,8 @@ int main(int argc, char *argv[])
socketOptions.keep_alive_max_failed_probes = 1;
socketOptions.keepalive = true;

Io::ClientBootstrap bootstrap(eventLoopGroup);
Aws::Crt::Io::DefaultHostResolver defaultHostResolver(eventLoopGroup, 1, 5);
Io::ClientBootstrap bootstrap(eventLoopGroup, defaultHostResolver);

if (!bootstrap)
{
Expand Down
4 changes: 4 additions & 0 deletions source/Api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
#include <aws/crt/external/cJSON.h>
#include <aws/crt/io/TlsOptions.h>

#include <aws/http/http.h>

namespace Aws
{
namespace Crt
Expand All @@ -32,6 +34,7 @@ namespace Aws
// sets up the StlAllocator for use.
g_allocator = allocator;
Io::InitTlsStaticState(allocator);
aws_http_library_init(allocator);

cJSON_Hooks hooks;
hooks.malloc_fn = s_cJSONAlloc;
Expand All @@ -42,6 +45,7 @@ namespace Aws
static void s_cleanUpApi()
{
g_allocator = nullptr;
aws_http_library_clean_up();
Io::CleanUpTlsStaticState();
}

Expand Down
Loading

0 comments on commit be7daab

Please sign in to comment.