forked from boostorg/beast
Update for Net-TS Asio (API Change):
fix #769 The following classes are removed: * handler_type * async_result * async_completion * is_dynamic_buffer * is_const_buffer_sequence * is_mutable_buffer_sequence * handler_alloc Actions Required: * Use BOOST_ASIO_HANDLER_TYPE instead of handler_type * Use BOOST_ASIO_INITFN_RESULT_TYPE instead of async_result * Use boost::asio::async_completion * Use boost::asio::is_dynamic_buffer * Use boost::asio::is_const_buffer_sequence * Use boost::asio::is_mutable_buffer_sequence * boost::asio::associated_allocator_t replaces handler_alloc
This commit is contained in:
@@ -61,7 +61,8 @@ is_ssl_handshake(
|
||||
ConstBufferSequence const& buffers)
|
||||
{
|
||||
// Make sure buffers meets the requirements
|
||||
static_assert(boost::beast::is_const_buffer_sequence<ConstBufferSequence>::value,
|
||||
static_assert(
|
||||
boost::asio::is_const_buffer_sequence<ConstBufferSequence>::value,
|
||||
"ConstBufferSequence requirements not met");
|
||||
|
||||
// We need at least one byte to really do anything
|
||||
@@ -135,7 +136,8 @@ detect_ssl(
|
||||
// Make sure arguments meet the requirements
|
||||
static_assert(beast::is_sync_read_stream<SyncReadStream>::value,
|
||||
"SyncReadStream requirements not met");
|
||||
static_assert(beast::is_dynamic_buffer<DynamicBuffer>::value,
|
||||
static_assert(
|
||||
boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
|
||||
"DynamicBuffer requirements not met");
|
||||
|
||||
// Loop until an error occurs or we get a definitive answer
|
||||
@@ -219,15 +221,15 @@ detect_ssl(
|
||||
Regardless of whether the asynchronous operation completes
|
||||
immediately or not, the handler will not be invoked from within
|
||||
this function. Invocation of the handler will be performed in a
|
||||
manner equivalent to using `boost::asio::io_service::post`.
|
||||
manner equivalent to using `boost::asio::io_context::post`.
|
||||
*/
|
||||
template<
|
||||
class AsyncReadStream,
|
||||
class DynamicBuffer,
|
||||
class CompletionToken>
|
||||
boost::beast::async_return_type< /*< The [link beast.ref.boost__beast__async_return_type `async_return_type`] customizes the return value based on the completion token >*/
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE( /*< `BOOST_ASIO_INITFN_RESULT_TYPE` customizes the return value based on the completion token >*/
|
||||
CompletionToken,
|
||||
void(boost::beast::error_code, boost::tribool)> /*< This is the signature for the completion handler >*/
|
||||
void(boost::beast::error_code, boost::tribool)) /*< This is the signature for the completion handler >*/
|
||||
async_detect_ssl(
|
||||
AsyncReadStream& stream,
|
||||
DynamicBuffer& buffer,
|
||||
@@ -249,9 +251,9 @@ template<
|
||||
class AsyncReadStream,
|
||||
class DynamicBuffer,
|
||||
class CompletionToken>
|
||||
boost::beast::async_return_type<
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(
|
||||
CompletionToken,
|
||||
void(boost::beast::error_code, boost::tribool)>
|
||||
void(boost::beast::error_code, boost::tribool))
|
||||
async_detect_ssl(
|
||||
AsyncReadStream& stream,
|
||||
DynamicBuffer& buffer,
|
||||
@@ -262,26 +264,29 @@ async_detect_ssl(
|
||||
// Make sure arguments meet the requirements
|
||||
static_assert(beast::is_async_read_stream<AsyncReadStream>::value,
|
||||
"SyncReadStream requirements not met");
|
||||
static_assert(beast::is_dynamic_buffer<DynamicBuffer>::value,
|
||||
static_assert(
|
||||
boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
|
||||
"DynamicBuffer requirements not met");
|
||||
|
||||
// This helper manages some of the handler's lifetime and
|
||||
// uses the result and handler specializations associated with
|
||||
// the completion token to help customize the return value.
|
||||
//
|
||||
beast::async_completion<
|
||||
boost::asio::async_completion<
|
||||
CompletionToken, void(beast::error_code, boost::tribool)> init{token};
|
||||
|
||||
// Create the composed operation and launch it. This is a constructor
|
||||
// call followed by invocation of operator(). We use handler_type
|
||||
// call followed by invocation of operator(). We use BOOST_ASIO_HANDLER_TYPE
|
||||
// to convert the completion token into the correct handler type,
|
||||
// allowing user defined specializations of the async result template
|
||||
// to take effect.
|
||||
//
|
||||
detect_ssl_op<AsyncReadStream, DynamicBuffer, beast::handler_type<
|
||||
CompletionToken, void(beast::error_code, boost::tribool)>>{
|
||||
stream, buffer, init.completion_handler}(
|
||||
beast::error_code{}, 0);
|
||||
detect_ssl_op<
|
||||
AsyncReadStream,
|
||||
DynamicBuffer,
|
||||
BOOST_ASIO_HANDLER_TYPE(
|
||||
CompletionToken, void(beast::error_code, boost::tribool))>{
|
||||
stream, buffer, init.completion_handler}(beast::error_code{}, 0);
|
||||
|
||||
// This hook lets the caller see a return value when appropriate.
|
||||
// For example this might return std::future<error_code, boost::tribool> if
|
||||
@@ -336,6 +341,35 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
// Associated allocator support. This is Asio's system for
|
||||
// allowing the final completion handler to customize the
|
||||
// memory allocation strategy used for composed operation
|
||||
// states. A composed operation needs to use the same allocator
|
||||
// as the final handler. These declarations achieve that.
|
||||
|
||||
using allocator_type =
|
||||
boost::asio::associated_allocator_t<Handler>;
|
||||
|
||||
allocator_type
|
||||
get_allocator() const noexcept
|
||||
{
|
||||
return boost::asio::get_associated_allocator(handler_);
|
||||
}
|
||||
|
||||
// Executor hook. This is Asio's system for customizing the
|
||||
// manner in which asynchronous completion handlers are invoked.
|
||||
// A composed operation needs to use the same executor to invoke
|
||||
// intermediate completion handlers as that used to invoke the
|
||||
// final handler.
|
||||
|
||||
using executor_type = boost::asio::associated_executor_t<
|
||||
Handler, decltype(stream_.get_executor())>;
|
||||
|
||||
executor_type get_executor() const noexcept
|
||||
{
|
||||
return boost::asio::get_associated_executor(handler_, stream_.get_executor());
|
||||
}
|
||||
|
||||
// Determines if the next asynchronous operation represents a
|
||||
// continuation of the asynchronous flow of control associated
|
||||
// with the final handler. If we are past step two, it means
|
||||
@@ -358,34 +392,6 @@ public:
|
||||
asio_handler_is_continuation(std::addressof(op->handler_));
|
||||
}
|
||||
|
||||
// Handler hook forwarding. These free functions invoke the hooks
|
||||
// associated with the final completion handler. In effect, they
|
||||
// make the Asio implementation treat our composed operation the
|
||||
// same way it would treat the final completion handler for the
|
||||
// purpose of memory allocation and invocation.
|
||||
//
|
||||
// Our implementation just passes through the call to the hook
|
||||
// associated with the final handler.
|
||||
|
||||
friend void* asio_handler_allocate(std::size_t size, detect_ssl_op* op)
|
||||
{
|
||||
using boost::asio::asio_handler_allocate;
|
||||
return asio_handler_allocate(size, std::addressof(op->handler_));
|
||||
}
|
||||
|
||||
friend void asio_handler_deallocate(void* p, std::size_t size, detect_ssl_op* op)
|
||||
{
|
||||
using boost::asio::asio_handler_deallocate;
|
||||
return asio_handler_deallocate(p, size, std::addressof(op->handler_));
|
||||
}
|
||||
|
||||
template<class Function>
|
||||
friend void asio_handler_invoke(Function&& f, detect_ssl_op* op)
|
||||
{
|
||||
using boost::asio::asio_handler_invoke;
|
||||
return asio_handler_invoke(f, std::addressof(op->handler_));
|
||||
}
|
||||
|
||||
// Our main entry point. This will get called as our
|
||||
// intermediate operations complete. Definition below.
|
||||
//
|
||||
@@ -424,12 +430,13 @@ operator()(boost::beast::error_code ec, std::size_t bytes_transferred)
|
||||
// We need to invoke the handler, but the guarantee
|
||||
// is that the handler will not be called before the
|
||||
// call to async_detect_ssl returns, so we must post
|
||||
// the operation to the io_service. The helper function
|
||||
// the operation to the executor. The helper function
|
||||
// `bind_handler` lets us bind arguments in a safe way
|
||||
// that preserves the type customization hooks of the
|
||||
// original handler.
|
||||
step_ = 1;
|
||||
return stream_.get_io_service().post(
|
||||
return boost::asio::post(
|
||||
stream_.get_executor(),
|
||||
beast::bind_handler(std::move(*this), ec, 0));
|
||||
}
|
||||
|
||||
|
||||
+239
-270
@@ -10,21 +10,21 @@
|
||||
#ifndef BOOST_BEAST_EXAMPLE_COMMON_SESSION_ALLOC_HPP
|
||||
#define BOOST_BEAST_EXAMPLE_COMMON_SESSION_ALLOC_HPP
|
||||
|
||||
#include <boost/asio/handler_alloc_hook.hpp>
|
||||
#include <boost/asio/associated_allocator.hpp>
|
||||
#include <boost/asio/associated_executor.hpp>
|
||||
#include <boost/asio/handler_continuation_hook.hpp>
|
||||
#include <boost/asio/handler_invoke_hook.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/intrusive/list.hpp>
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<class Context>
|
||||
class session_alloc_base
|
||||
{
|
||||
template<class Handler>
|
||||
class wrapped_handler;
|
||||
|
||||
protected:
|
||||
class pool_t
|
||||
{
|
||||
using hook_type =
|
||||
@@ -78,23 +78,18 @@ class session_alloc_base
|
||||
boost::intrusive::constant_time_size<
|
||||
true>>::type;
|
||||
|
||||
Context* ctx_;
|
||||
std::size_t refs_ = 1; // shared count
|
||||
std::size_t high_ = 0; // highest used
|
||||
std::size_t size_ = 0; // size of buf_
|
||||
char* buf_ = nullptr; // a large block
|
||||
list_type list_; // list of allocations
|
||||
|
||||
explicit
|
||||
pool_t(Context* ctx)
|
||||
: ctx_(ctx)
|
||||
{
|
||||
}
|
||||
pool_t() = default;
|
||||
|
||||
public:
|
||||
static
|
||||
pool_t&
|
||||
construct(Context* ctx);
|
||||
construct();
|
||||
|
||||
~pool_t();
|
||||
|
||||
@@ -110,73 +105,178 @@ class session_alloc_base
|
||||
void
|
||||
dealloc(void* pv, std::size_t n);
|
||||
};
|
||||
|
||||
pool_t& pool_;
|
||||
|
||||
public:
|
||||
session_alloc_base& operator=(session_alloc_base const&) = delete;
|
||||
|
||||
~session_alloc_base()
|
||||
{
|
||||
pool_.release();
|
||||
}
|
||||
|
||||
session_alloc_base()
|
||||
: pool_(pool_t::construct(nullptr))
|
||||
{
|
||||
static_assert(std::is_same<Context, std::nullptr_t>::value,
|
||||
"Context requirements not met");
|
||||
}
|
||||
|
||||
session_alloc_base(session_alloc_base const& other)
|
||||
: pool_(other.pool_.addref())
|
||||
{
|
||||
}
|
||||
|
||||
template<class DeducedContext, class = typename
|
||||
std::enable_if<! std::is_same<
|
||||
session_alloc_base<Context>,
|
||||
typename std::decay<DeducedContext>::type
|
||||
>::value>::type>
|
||||
explicit
|
||||
session_alloc_base(DeducedContext& ctx)
|
||||
: pool_(pool_t::construct(std::addressof(ctx)))
|
||||
{
|
||||
static_assert(! std::is_same<Context, std::nullptr_t>::value,
|
||||
"Context requirements not met");
|
||||
}
|
||||
|
||||
template<class Handler>
|
||||
wrapped_handler<typename std::decay<Handler>::type>
|
||||
wrap(Handler&& handler)
|
||||
{
|
||||
return wrapped_handler<
|
||||
typename std::decay<Handler>::type>(
|
||||
std::forward<Handler>(handler), *this);
|
||||
}
|
||||
|
||||
protected:
|
||||
void*
|
||||
alloc(std::size_t n)
|
||||
{
|
||||
return pool_.alloc(n);
|
||||
}
|
||||
|
||||
void
|
||||
dealloc(void* p, std::size_t n)
|
||||
{
|
||||
pool_.dealloc(p, n);
|
||||
}
|
||||
};
|
||||
|
||||
template<class Context>
|
||||
auto
|
||||
session_alloc_base<Context>::
|
||||
pool_t::
|
||||
construct() ->
|
||||
pool_t&
|
||||
{
|
||||
return *(new pool_t);
|
||||
}
|
||||
|
||||
template<class Context>
|
||||
session_alloc_base<Context>::
|
||||
pool_t::
|
||||
~pool_t()
|
||||
{
|
||||
BOOST_ASSERT(list_.size() == 0);
|
||||
if(buf_)
|
||||
delete[] buf_;
|
||||
}
|
||||
|
||||
template<class Context>
|
||||
auto
|
||||
session_alloc_base<Context>::
|
||||
pool_t::
|
||||
addref() ->
|
||||
pool_t&
|
||||
{
|
||||
++refs_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class Context>
|
||||
void
|
||||
session_alloc_base<Context>::
|
||||
pool_t::
|
||||
release()
|
||||
{
|
||||
if(--refs_)
|
||||
return;
|
||||
delete this;
|
||||
}
|
||||
|
||||
template<class Context>
|
||||
void*
|
||||
session_alloc_base<Context>::
|
||||
pool_t::
|
||||
alloc(std::size_t n)
|
||||
{
|
||||
if(list_.empty() && size_ < high_)
|
||||
{
|
||||
if(buf_)
|
||||
delete[] buf_;
|
||||
buf_ = new char[high_];
|
||||
size_ = high_;
|
||||
}
|
||||
if(buf_)
|
||||
{
|
||||
char* end;
|
||||
std::size_t used;
|
||||
if(list_.empty())
|
||||
{
|
||||
end = buf_;
|
||||
used = sizeof(element) + n;
|
||||
}
|
||||
else
|
||||
{
|
||||
end = list_.back().end();
|
||||
used = list_.back().used() +
|
||||
sizeof(element) + n;
|
||||
}
|
||||
if(end >= buf_ && end +
|
||||
sizeof(element) + n <= buf_ + size_)
|
||||
{
|
||||
auto& e = *new(end) element{n, used};
|
||||
list_.push_back(e);
|
||||
high_ = (std::max)(high_, used);
|
||||
return e.data();
|
||||
}
|
||||
}
|
||||
std::size_t const used =
|
||||
sizeof(element) + n + (
|
||||
buf_ && ! list_.empty() ?
|
||||
list_.back().used() : 0);
|
||||
auto& e = *new(new char[sizeof(element) + n]) element{n, used};
|
||||
list_.push_back(e);
|
||||
high_ = (std::max)(high_, used);
|
||||
return e.data();
|
||||
}
|
||||
|
||||
template<class Context>
|
||||
void
|
||||
session_alloc_base<Context>::
|
||||
pool_t::
|
||||
dealloc(void* pv, std::size_t n)
|
||||
{
|
||||
auto& e = *(reinterpret_cast<element*>(pv) - 1);
|
||||
BOOST_ASSERT(e.size() == n);
|
||||
if( (e.end() > buf_ + size_) ||
|
||||
reinterpret_cast<char*>(&e) < buf_)
|
||||
{
|
||||
list_.erase(list_.iterator_to(e));
|
||||
e.~element();
|
||||
delete[] reinterpret_cast<char*>(&e);
|
||||
return;
|
||||
}
|
||||
list_.erase(list_.iterator_to(e));
|
||||
e.~element();
|
||||
}
|
||||
|
||||
} // detail
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<class T, class Context = std::nullptr_t>
|
||||
class session_alloc : public session_alloc_base<Context>
|
||||
template<class T>
|
||||
class session_alloc
|
||||
: private detail::session_alloc_base<void>
|
||||
{
|
||||
template<class U, class C>
|
||||
template<class U>
|
||||
friend class session_alloc;
|
||||
|
||||
template<class Handler>
|
||||
class wrapped_handler
|
||||
{
|
||||
// Can't friend partial specializations,
|
||||
// so we just friend the whole thing.
|
||||
template<class T, class Executor>
|
||||
friend struct boost::asio::associated_executor;
|
||||
|
||||
Handler h_;
|
||||
session_alloc<char> alloc_;
|
||||
|
||||
public:
|
||||
wrapped_handler(wrapped_handler&&) = default;
|
||||
wrapped_handler(wrapped_handler const&) = default;
|
||||
|
||||
template<class DeducedHandler>
|
||||
wrapped_handler(
|
||||
DeducedHandler&& h,
|
||||
session_alloc const& alloc)
|
||||
: h_(std::forward<DeducedHandler>(h))
|
||||
, alloc_(alloc)
|
||||
{
|
||||
}
|
||||
|
||||
using allocator_type = session_alloc<char>;
|
||||
|
||||
allocator_type
|
||||
get_allocator() const noexcept;
|
||||
|
||||
template<class... Args>
|
||||
void
|
||||
operator()(Args&&... args) const
|
||||
{
|
||||
h_(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
friend
|
||||
bool
|
||||
asio_handler_is_continuation(wrapped_handler* w)
|
||||
{
|
||||
using boost::asio::asio_handler_is_continuation;
|
||||
return asio_handler_is_continuation(std::addressof(w->h_));
|
||||
}
|
||||
};
|
||||
|
||||
using pool_t = typename
|
||||
detail::session_alloc_base<void>::pool_t;
|
||||
|
||||
pool_t& pool_;
|
||||
|
||||
public:
|
||||
using value_type = T;
|
||||
using is_always_equal = std::false_type;
|
||||
@@ -193,21 +293,32 @@ public:
|
||||
using other = session_alloc<U>;
|
||||
};
|
||||
|
||||
session_alloc() = default;
|
||||
session_alloc(session_alloc const&) = default;
|
||||
session_alloc& operator=(session_alloc const&) = delete;
|
||||
|
||||
~session_alloc()
|
||||
{
|
||||
pool_.release();
|
||||
}
|
||||
|
||||
session_alloc()
|
||||
: pool_(pool_t::construct())
|
||||
{
|
||||
}
|
||||
|
||||
session_alloc(session_alloc const& other) noexcept
|
||||
: pool_(other.pool_.addref())
|
||||
{
|
||||
}
|
||||
|
||||
template<class U>
|
||||
session_alloc(session_alloc<U> const& other)
|
||||
: session_alloc_base<Context>(static_cast<
|
||||
session_alloc_base<Context> const&>(other))
|
||||
session_alloc(session_alloc<U> const& other) noexcept
|
||||
: pool_(other.pool_)
|
||||
{
|
||||
}
|
||||
|
||||
explicit
|
||||
session_alloc(Context& ctx)
|
||||
: session_alloc_base<Context>(ctx)
|
||||
{
|
||||
}
|
||||
template<class Handler>
|
||||
wrapped_handler<typename std::decay<Handler>::type>
|
||||
wrap(Handler&& handler);
|
||||
|
||||
value_type*
|
||||
allocate(size_type n)
|
||||
@@ -257,209 +368,67 @@ public:
|
||||
{
|
||||
return ! (lhs == rhs);
|
||||
}
|
||||
|
||||
protected:
|
||||
void*
|
||||
alloc(std::size_t n)
|
||||
{
|
||||
return pool_.alloc(n);
|
||||
}
|
||||
|
||||
void
|
||||
dealloc(void* p, std::size_t n)
|
||||
{
|
||||
pool_.dealloc(p, n);
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<class Context>
|
||||
template<class T>
|
||||
template<class Handler>
|
||||
class session_alloc_base<Context>::wrapped_handler
|
||||
auto
|
||||
session_alloc<T>::
|
||||
wrapped_handler<Handler>::
|
||||
get_allocator() const noexcept ->
|
||||
allocator_type
|
||||
{
|
||||
Handler h_;
|
||||
session_alloc_base alloc_;
|
||||
|
||||
void*
|
||||
alloc(std::size_t size)
|
||||
{
|
||||
return alloc_.alloc(size);
|
||||
}
|
||||
|
||||
void
|
||||
dealloc(void* p, std::size_t size)
|
||||
{
|
||||
alloc_.dealloc(p, size);
|
||||
}
|
||||
|
||||
public:
|
||||
wrapped_handler(wrapped_handler&&) = default;
|
||||
wrapped_handler(wrapped_handler const&) = default;
|
||||
|
||||
template<class DeducedHandler>
|
||||
explicit
|
||||
wrapped_handler(DeducedHandler&& h,
|
||||
session_alloc_base const& alloc)
|
||||
: h_(std::forward<DeducedHandler>(h))
|
||||
, alloc_(alloc)
|
||||
{
|
||||
}
|
||||
|
||||
template<class... Args>
|
||||
void
|
||||
operator()(Args&&... args) const
|
||||
{
|
||||
h_(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
friend
|
||||
void*
|
||||
asio_handler_allocate(
|
||||
std::size_t size, wrapped_handler* w)
|
||||
{
|
||||
return w->alloc(size);
|
||||
}
|
||||
|
||||
friend
|
||||
void
|
||||
asio_handler_deallocate(
|
||||
void* p, std::size_t size, wrapped_handler* w)
|
||||
{
|
||||
w->dealloc(p, size);
|
||||
}
|
||||
|
||||
friend
|
||||
bool
|
||||
asio_handler_is_continuation(wrapped_handler* w)
|
||||
{
|
||||
using boost::asio::asio_handler_is_continuation;
|
||||
return asio_handler_is_continuation(std::addressof(w->h_));
|
||||
}
|
||||
|
||||
template<class F>
|
||||
friend
|
||||
void
|
||||
asio_handler_invoke(F&& f, wrapped_handler* w)
|
||||
{
|
||||
using boost::asio::asio_handler_invoke;
|
||||
asio_handler_invoke(
|
||||
f, std::addressof(w->h_));
|
||||
}
|
||||
};
|
||||
return alloc_;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<class Context>
|
||||
template<class T>
|
||||
template<class Handler>
|
||||
auto
|
||||
session_alloc_base<Context>::
|
||||
pool_t::
|
||||
construct(Context* ctx) ->
|
||||
pool_t&
|
||||
session_alloc<T>::
|
||||
wrap(Handler&& handler) ->
|
||||
wrapped_handler<typename std::decay<Handler>::type>
|
||||
{
|
||||
using boost::asio::asio_handler_allocate;
|
||||
return *new(asio_handler_allocate(
|
||||
sizeof(pool_t), ctx)) pool_t{ctx};
|
||||
return wrapped_handler<
|
||||
typename std::decay<Handler>::type>(
|
||||
std::forward<Handler>(handler), *this);
|
||||
}
|
||||
|
||||
template<class Context>
|
||||
session_alloc_base<Context>::
|
||||
pool_t::
|
||||
~pool_t()
|
||||
namespace boost {
|
||||
namespace asio {
|
||||
template<class T, class Handler, class Executor>
|
||||
struct associated_executor<
|
||||
session_alloc<T>::wrapped_handler<Handler>, Executor>
|
||||
{
|
||||
BOOST_ASSERT(list_.size() == 0);
|
||||
if(buf_)
|
||||
using type = typename
|
||||
associated_executor<Handler, Executor>::type;
|
||||
|
||||
static
|
||||
type
|
||||
get(session_alloc<T>::wrapped_handler<Handler> const& h,
|
||||
Executor const& ex = Executor()) noexcept
|
||||
{
|
||||
using boost::asio::asio_handler_deallocate;
|
||||
asio_handler_deallocate(buf_, size_, ctx_);
|
||||
return associated_executor<
|
||||
Handler, Executor>::get(h.h_, ex);
|
||||
}
|
||||
}
|
||||
|
||||
template<class Context>
|
||||
auto
|
||||
session_alloc_base<Context>::
|
||||
pool_t::
|
||||
addref() ->
|
||||
pool_t&
|
||||
{
|
||||
++refs_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class Context>
|
||||
void
|
||||
session_alloc_base<Context>::
|
||||
pool_t::
|
||||
release()
|
||||
{
|
||||
if(--refs_)
|
||||
return;
|
||||
this->~pool_t();
|
||||
using boost::asio::asio_handler_deallocate;
|
||||
asio_handler_deallocate(this, sizeof(*this), ctx_);
|
||||
}
|
||||
|
||||
template<class Context>
|
||||
void*
|
||||
session_alloc_base<Context>::
|
||||
pool_t::
|
||||
alloc(std::size_t n)
|
||||
{
|
||||
if(list_.empty() && size_ < high_)
|
||||
{
|
||||
if(buf_)
|
||||
{
|
||||
using boost::asio::asio_handler_deallocate;
|
||||
asio_handler_deallocate(buf_, size_, ctx_);
|
||||
}
|
||||
using boost::asio::asio_handler_allocate;
|
||||
buf_ = reinterpret_cast<char*>(
|
||||
asio_handler_allocate(high_, ctx_));
|
||||
size_ = high_;
|
||||
}
|
||||
if(buf_)
|
||||
{
|
||||
char* end;
|
||||
std::size_t used;
|
||||
if(list_.empty())
|
||||
{
|
||||
end = buf_;
|
||||
used = sizeof(element) + n;
|
||||
}
|
||||
else
|
||||
{
|
||||
end = list_.back().end();
|
||||
used = list_.back().used() +
|
||||
sizeof(element) + n;
|
||||
}
|
||||
if(end >= buf_ && end +
|
||||
sizeof(element) + n <= buf_ + size_)
|
||||
{
|
||||
auto& e = *new(end) element{n, used};
|
||||
list_.push_back(e);
|
||||
high_ = (std::max)(high_, used);
|
||||
return e.data();
|
||||
}
|
||||
}
|
||||
std::size_t const used =
|
||||
sizeof(element) + n + (
|
||||
buf_ && ! list_.empty() ?
|
||||
list_.back().used() : 0);
|
||||
using boost::asio::asio_handler_allocate;
|
||||
auto& e = *new(asio_handler_allocate(
|
||||
sizeof(element) + n, ctx_)) element{n, used};
|
||||
list_.push_back(e);
|
||||
high_ = (std::max)(high_, used);
|
||||
return e.data();
|
||||
}
|
||||
|
||||
template<class Context>
|
||||
void
|
||||
session_alloc_base<Context>::
|
||||
pool_t::
|
||||
dealloc(void* pv, std::size_t n)
|
||||
{
|
||||
auto& e = *(reinterpret_cast<element*>(pv) - 1);
|
||||
BOOST_ASSERT(e.size() == n);
|
||||
if( (e.end() > buf_ + size_) ||
|
||||
reinterpret_cast<char*>(&e) < buf_)
|
||||
{
|
||||
list_.erase(list_.iterator_to(e));
|
||||
e.~element();
|
||||
using boost::asio::asio_handler_deallocate;
|
||||
asio_handler_deallocate(
|
||||
&e, sizeof(e) + n, ctx_);
|
||||
return;
|
||||
}
|
||||
list_.erase(list_.iterator_to(e));
|
||||
e.~element();
|
||||
}
|
||||
};
|
||||
} // asio
|
||||
} // boost
|
||||
|
||||
#endif
|
||||
|
||||
@@ -52,9 +52,6 @@ public:
|
||||
/// Structure for use with deprecated impl_type.
|
||||
using impl_struct = typename stream_type::impl_struct;
|
||||
|
||||
/// (Deprecated: Use native_handle_type.) The underlying implementation type.
|
||||
using impl_type = typename stream_type::impl_type;
|
||||
|
||||
/// The type of the next layer.
|
||||
using next_layer_type = typename stream_type::next_layer_type;
|
||||
|
||||
@@ -64,14 +61,16 @@ public:
|
||||
ssl_stream(
|
||||
boost::asio::ip::tcp::socket socket,
|
||||
boost::asio::ssl::context& ctx)
|
||||
: p_(new stream_type{socket.get_io_service(), ctx})
|
||||
: p_(new stream_type{
|
||||
socket.get_executor().context(), ctx})
|
||||
, ctx_(&ctx)
|
||||
{
|
||||
p_->next_layer() = std::move(socket);
|
||||
}
|
||||
|
||||
ssl_stream(ssl_stream&& other)
|
||||
: p_(new stream_type(other.get_io_service(), *other.ctx_))
|
||||
: p_(new stream_type(
|
||||
other.get_executor().context(), *other.ctx_))
|
||||
, ctx_(other.ctx_)
|
||||
{
|
||||
using std::swap;
|
||||
@@ -80,8 +79,8 @@ public:
|
||||
|
||||
ssl_stream& operator=(ssl_stream&& other)
|
||||
{
|
||||
std::unique_ptr<stream_type> p(
|
||||
new stream_type{other.get_io_service(), other.ctx_});
|
||||
std::unique_ptr<stream_type> p(new stream_type{
|
||||
other.get_executor().context(), other.ctx_});
|
||||
using std::swap;
|
||||
swap(p_, p);
|
||||
swap(p_, other.p_);
|
||||
@@ -89,10 +88,10 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
boost::asio::io_service&
|
||||
get_io_service()
|
||||
decltype(p_->get_executor())
|
||||
get_executor() noexcept
|
||||
{
|
||||
return p_->get_io_service();
|
||||
return p_->get_executor();
|
||||
}
|
||||
|
||||
native_handle_type
|
||||
@@ -101,12 +100,6 @@ public:
|
||||
return p_->native_handle();
|
||||
}
|
||||
|
||||
impl_type
|
||||
impl()
|
||||
{
|
||||
return p_->impl();
|
||||
}
|
||||
|
||||
next_layer_type const&
|
||||
next_layer() const
|
||||
{
|
||||
|
||||
@@ -1,230 +0,0 @@
|
||||
//
|
||||
// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/beast
|
||||
//
|
||||
|
||||
#ifndef BOOST_BEAST_EXAMPLE_COMMON_WRITE_MSG_HPP
|
||||
#define BOOST_BEAST_EXAMPLE_COMMON_WRITE_MSG_HPP
|
||||
|
||||
#include <boost/beast/core/async_result.hpp>
|
||||
#include <boost/beast/core/handler_ptr.hpp>
|
||||
#include <boost/beast/core/type_traits.hpp>
|
||||
#include <boost/beast/http/message.hpp>
|
||||
#include <boost/beast/http/write.hpp>
|
||||
#include <boost/beast/http/type_traits.hpp>
|
||||
#include <boost/asio/handler_alloc_hook.hpp>
|
||||
#include <boost/asio/handler_continuation_hook.hpp>
|
||||
#include <boost/asio/handler_invoke_hook.hpp>
|
||||
|
||||
namespace detail {
|
||||
|
||||
/** Composed operation to send an HTTP message
|
||||
|
||||
This implements the composed operation needed for the
|
||||
@ref async_write_msg function.
|
||||
*/
|
||||
template<
|
||||
class AsyncWriteStream,
|
||||
class Handler,
|
||||
bool isRequest, class Body, class Fields>
|
||||
class write_msg_op
|
||||
{
|
||||
// This composed operation has a state which is not trivial
|
||||
// to copy (msg) so we need to store the state in an allocated
|
||||
// object.
|
||||
//
|
||||
struct data
|
||||
{
|
||||
// The stream we are writing to
|
||||
AsyncWriteStream& stream;
|
||||
|
||||
// The message we are sending. Note that this composed
|
||||
// operation takes ownership of the message and destroys
|
||||
// it when it is done.
|
||||
//
|
||||
boost::beast::http::message<isRequest, Body, Fields> msg;
|
||||
|
||||
// Serializer for the message
|
||||
boost::beast::http::serializer<isRequest, Body, Fields> sr;
|
||||
|
||||
data(
|
||||
Handler& handler,
|
||||
AsyncWriteStream& stream_,
|
||||
boost::beast::http::message<isRequest, Body, Fields>&& msg_)
|
||||
: stream(stream_)
|
||||
, msg(std::move(msg_))
|
||||
, sr(msg)
|
||||
{
|
||||
boost::ignore_unused(handler);
|
||||
}
|
||||
};
|
||||
|
||||
// `handler_ptr` is a utility which helps to manage a composed
|
||||
// operation's state. It is similar to a shared pointer, but
|
||||
// it uses handler allocation hooks to allocate and free memory,
|
||||
// and it also helps to meet Asio's deallocate-before-invocation
|
||||
// guarantee.
|
||||
//
|
||||
boost::beast::handler_ptr<data, Handler> d_;
|
||||
|
||||
public:
|
||||
// Asio can move and copy the handler, we support both
|
||||
write_msg_op(write_msg_op&&) = default;
|
||||
write_msg_op(write_msg_op const&) = default;
|
||||
|
||||
// Constructor
|
||||
//
|
||||
// We take the handler as a template type to
|
||||
// support both const and rvalue references.
|
||||
//
|
||||
template<
|
||||
class DeducedHandler,
|
||||
class... Args>
|
||||
write_msg_op(
|
||||
DeducedHandler&& h,
|
||||
AsyncWriteStream& s,
|
||||
Args&&... args)
|
||||
: d_(std::forward<DeducedHandler>(h),
|
||||
s, std::forward<Args>(args)...)
|
||||
{
|
||||
}
|
||||
|
||||
// Entry point
|
||||
//
|
||||
// The initiation function calls this to start the operation
|
||||
//
|
||||
void
|
||||
operator()()
|
||||
{
|
||||
auto& d = *d_;
|
||||
boost::beast::http::async_write(
|
||||
d.stream, d.sr, std::move(*this));
|
||||
}
|
||||
|
||||
// Completion handler
|
||||
//
|
||||
// This gets called when boost::beast::http::async_write completes
|
||||
//
|
||||
void
|
||||
operator()(boost::beast::error_code ec)
|
||||
{
|
||||
d_.invoke(ec);
|
||||
}
|
||||
|
||||
//
|
||||
// These hooks are necessary for Asio
|
||||
//
|
||||
// The meaning is explained in the Beast documentation
|
||||
//
|
||||
|
||||
friend
|
||||
void* asio_handler_allocate(
|
||||
std::size_t size, write_msg_op* op)
|
||||
{
|
||||
using boost::asio::asio_handler_allocate;
|
||||
return asio_handler_allocate(
|
||||
size, std::addressof(op->d_.handler()));
|
||||
}
|
||||
|
||||
friend
|
||||
void asio_handler_deallocate(
|
||||
void* p, std::size_t size, write_msg_op* op)
|
||||
{
|
||||
using boost::asio::asio_handler_deallocate;
|
||||
asio_handler_deallocate(
|
||||
p, size, std::addressof(op->d_.handler()));
|
||||
}
|
||||
|
||||
friend
|
||||
bool asio_handler_is_continuation(write_msg_op* op)
|
||||
{
|
||||
using boost::asio::asio_handler_is_continuation;
|
||||
return asio_handler_is_continuation(std::addressof(op->d_.handler()));
|
||||
}
|
||||
|
||||
template<class Function>
|
||||
friend
|
||||
void asio_handler_invoke(Function&& f, write_msg_op* op)
|
||||
{
|
||||
using boost::asio::asio_handler_invoke;
|
||||
asio_handler_invoke(
|
||||
f, std::addressof(op->d_.handler()));
|
||||
}
|
||||
};
|
||||
|
||||
} // detail
|
||||
|
||||
/** Write an HTTP message to a stream asynchronously
|
||||
|
||||
This function is used to write a complete message to a stream asynchronously
|
||||
using HTTP/1. The function call always returns immediately. The asynchronous
|
||||
operation will continue until one of the following conditions is true:
|
||||
|
||||
@li The entire message is written.
|
||||
|
||||
@li An error occurs.
|
||||
|
||||
This operation is implemented in terms of zero or more calls to the stream's
|
||||
`async_write_some` function, and is known as a <em>composed operation</em>.
|
||||
The program must ensure that the stream performs no other write operations
|
||||
until this operation completes. The algorithm will use a temporary
|
||||
@ref serializer to produce buffers. If the semantics of the message
|
||||
indicate that the connection should be closed after the message is sent,
|
||||
the error delivered by this function
|
||||
will be @ref error::end_of_stream
|
||||
|
||||
@param stream The stream to which the data is to be written.
|
||||
The type must support the @b AsyncWriteStream concept.
|
||||
|
||||
@param msg The message to write. The function will take ownership
|
||||
of the object as if by move constrction.
|
||||
|
||||
@param handler The handler to be called when the operation
|
||||
completes. Copies will be made of the handler as required.
|
||||
The equivalent function signature of the handler must be:
|
||||
@code void handler(
|
||||
error_code const& error // result of operation
|
||||
); @endcode
|
||||
Regardless of whether the asynchronous operation completes
|
||||
immediately or not, the handler will not be invoked from within
|
||||
this function. Invocation of the handler will be performed in a
|
||||
manner equivalent to using `boost::asio::io_service::post`.
|
||||
*/
|
||||
template<
|
||||
class AsyncWriteStream,
|
||||
bool isRequest, class Body, class Fields,
|
||||
class WriteHandler>
|
||||
boost::beast::async_return_type<WriteHandler, void(boost::beast::error_code)>
|
||||
async_write_msg(
|
||||
AsyncWriteStream& stream,
|
||||
boost::beast::http::message<isRequest, Body, Fields>&& msg,
|
||||
WriteHandler&& handler)
|
||||
{
|
||||
static_assert(
|
||||
boost::beast::is_async_write_stream<AsyncWriteStream>::value,
|
||||
"AsyncWriteStream requirements not met");
|
||||
|
||||
static_assert(boost::beast::http::is_body<Body>::value,
|
||||
"Body requirements not met");
|
||||
|
||||
static_assert(boost::beast::http::is_body_reader<Body>::value,
|
||||
"BodyReader requirements not met");
|
||||
|
||||
boost::beast::async_completion<WriteHandler, void(boost::beast::error_code)> init{handler};
|
||||
|
||||
::detail::write_msg_op<
|
||||
AsyncWriteStream,
|
||||
boost::beast::handler_type<WriteHandler, void(boost::beast::error_code)>,
|
||||
isRequest, Body, Fields>{
|
||||
init.completion_handler,
|
||||
stream,
|
||||
std::move(msg)}();
|
||||
|
||||
return init.result.get();
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user