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:
Vinnie Falco
2017-09-07 07:39:52 -07:00
parent 9dc9ca13b9
commit 3a28e999af
173 changed files with 3214 additions and 4138 deletions

View File

@ -1,3 +1,21 @@
Version 125:
API Changes:
* Update for Net-TS Asio
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
--------------------------------------------------------------------------------
Version 124:
* Fix for a test matrix compiler

View File

@ -21,7 +21,6 @@ if (MSVC)
add_definitions (-D_WIN32_WINNT=0x0601)
add_definitions (-D_SCL_SECURE_NO_WARNINGS=1)
add_definitions (-D_CRT_SECURE_NO_WARNINGS=1)
add_definitions (-DBOOST_ASIO_NO_DEPRECATED=1)
add_compile_options(
/bigobj # large object file format
@ -75,6 +74,7 @@ get_filename_component (BOOST_ROOT ../../ ABSOLUTE)
# VFALCO I want static but "b2 stage" builds a minimal set which excludes static
add_definitions (-DBOOST_ALL_STATIC_LINK=1)
add_definitions (-DBOOST_ASIO_NO_DEPRECATED=1)
add_definitions (-DBOOST_ASIO_DISABLE_BOOST_ARRAY=1)
add_definitions (-DBOOST_ASIO_DISABLE_BOOST_BIND=1)
add_definitions (-DBOOST_ASIO_DISABLE_BOOST_DATE_TIME=1)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 43 KiB

View File

@ -38,7 +38,7 @@
[def __asio_handler_invoke__ [@http://www.boost.org/doc/html/boost_asio/reference/asio_handler_invoke.html `asio_handler_invoke`]]
[def __asio_handler_allocate__ [@http://www.boost.org/doc/html/boost_asio/reference/asio_handler_allocate.html `asio_handler_allocate`]]
[def __io_service__ [@http://www.boost.org/doc/html/boost_asio/reference/io_service.html `io_service`]]
[def __io_context__ [@http://www.boost.org/doc/html/boost_asio/reference/io_context.html `io_context`]]
[def __socket__ [@http://www.boost.org/doc/html/boost_asio/reference/ip__tcp/socket.html `boost::asio::ip::tcp::socket`]]
[def __ssl_stream__ [@http://www.boost.org/doc/html/boost_asio/reference/ssl__stream.html `boost::asio::ssl::stream`]]
[def __streambuf__ [@http://www.boost.org/doc/html/boost_asio/reference/streambuf.html `boost::asio::streambuf`]]

View File

@ -30,12 +30,12 @@ special meaning:
[table Global Variables
[[Name][Description]]
[[
[@http://www.boost.org/doc/html/boost_asio/reference/io_service.html [*`ios`]]
[@http://www.boost.org/doc/html/boost_asio/reference/io_context.html [*`ioc`]]
][
A variable of type
[@http://www.boost.org/doc/html/boost_asio/reference/io_service.html `boost::asio::io_service`]
which is running on one separate thread, and upon which a
[@http://www.boost.org/doc/html/boost_asio/reference/io_service__work.html `boost::asio::io_service::work`]
[@http://www.boost.org/doc/html/boost_asio/reference/io_context.html `boost::asio::io_context`]
which is running on one separate thread, and upon which an
[@http://www.boost.org/doc/html/boost_asio/reference/executor_work.html `boost::asio::executor_work`]
object has been constructed.
]]
[[

View File

@ -67,10 +67,9 @@ checks helps provide more concise errors during compilation:
Returns `T::lowest_layer_type` if it exists, else returns `T`.
]]
[[
[link beast.ref.boost__beast__has_get_io_service `has_get_io_service`]
[link beast.ref.boost__beast__has_get_executor `has_get_executor`]
][
Determine if the `get_io_service` member function is present,
and returns an __io_service__.
Determine if the `get_executor` member function is present.
]]
[[
[link beast.ref.boost__beast__is_async_read_stream `is_async_read_stream`]

View File

@ -9,36 +9,71 @@
[section Buffer Types]
__Asio__ provides the __ConstBufferSequence__ and __MutableBufferSequence__
concepts, whose models provide ranges of buffers, as well as the __streambuf__
class which encapsulates memory storage that may be automatically resized as
required, where the memory is divided into an input sequence followed by an
output sequence. The Networking TS (__N4588__) generalizes this `streambuf`
interface into the __DynamicBuffer__ concept. Beast algorithms which require
resizable buffers accept dynamic buffer objects as templated parameters.
These metafunctions check if types match the buffer concepts:
To facilitate working with instances of the __ConstBufferSequence__ and
__MutableBufferSequence__ concepts introduced in __Asio__, Beast treats
those sequences as a special type of range. The following algorithms and
wrappers are provided which transform these ranges efficiently using lazy
evaluation. No memory allocations are used in the transformations; instead,
they create lightweight iterators over the existing, unmodified memory
buffers. Control of buffers is retained by the caller; ownership is not
transferred.
[table Buffer Type Checks
[table Buffer Algorithms and Types
[[Name][Description]]
[[
[link beast.ref.boost__beast__is_dynamic_buffer `is_dynamic_buffer`]
[link beast.ref.boost__beast__buffers_cat `buffers_cat`]
][
Determine if a type meets the requirements of __DynamicBuffer__.
This functions returns a new buffer sequence which, when iterated,
traverses the sequence which would be formed if all of the input buffer
sequences were concatenated. With this routine, multiple calls to a
stream's `write_some` function may be combined into one, eliminating
expensive system calls.
]]
[[
[link beast.ref.boost__beast__is_const_buffer_sequence `is_const_buffer_sequence`]
[link beast.ref.boost__beast__buffers_cat_view `buffers_cat_view`]
][
Determine if a type meets the requirements of __ConstBufferSequence__.
This class represents the buffer sequence formed by concatenating
two or more buffer sequences. This is type of object returned by
[link beast.ref.boost__beast__buffers_cat `buffers_cat`].
]]
[[
[link beast.ref.boost__beast__is_mutable_buffer_sequence `is_mutable_buffer_sequence`]
[link beast.ref.boost__beast__buffers_front `buffers_front`]
][
Determine if a type meets the requirements of __MutableBufferSequence__.
This function returns the first buffer in a buffer sequence,
or a buffer of size zero if the buffer sequence has no elements.
]]
[[
[link beast.ref.boost__beast__buffers_prefix `buffers_prefix`]
][
This function returns a new buffer or buffer sequence which represents
a prefix of the original buffers.
]]
[[
[link beast.ref.boost__beast__buffers_prefix_view `buffers_prefix_view`]
][
This class represents the buffer sequence formed from a prefix of
an existing buffer sequence. This is the type of buffer returned by
[link beast.ref.boost__beast__buffers_prefix.overload3 `buffers_prefix`].
]]
[[
[link beast.ref.boost__beast__buffers_suffix `buffers_suffix`]
][
This class wraps the underlying memory of an existing buffer sequence
and presents a suffix of the original sequence. The length of the suffix
may be progressively shortened. This lets callers work with sequential
increments of a buffer sequence.
]]
[[
[link beast.ref.boost__beast__buffers_to_string `buffers_to_string`]
][
This function converts a buffer sequence to a `std::string`. It can
be used for diagnostic purposes and tests.
]]
]
Beast provides several dynamic buffer implementations for a variety
of scenarios:
The __DynamicBuffer__ concept introduced in __Asio__ models a buffer
sequence which supports an owning, resizable range. Beast provides this
set of additional implementations of the dynamic buffer concept:
[table Dynamic Buffer Implementations
[[Name][Description]]
@ -95,68 +130,6 @@ of scenarios:
]]
]
Network applications frequently need to manipulate buffer sequences. To
facilitate working with buffers the library treats these sequences as
a special type of range. Algorithms and wrappers are provided which
transform these ranges efficiently using lazy evaluation. No memory
allocations are used in the transformations; instead, they create
lightweight iterators over the existing, unmodified memory buffers.
Control of buffers is retained by the caller; ownership is not
transferred.
[table Buffer Algorithms and Types
[[Name][Description]]
[[
[link beast.ref.boost__beast__buffers_cat `buffers_cat`]
][
This functions returns a new buffer sequence which, when iterated,
traverses the sequence which would be formed if all of the input buffer
sequences were concatenated. With this routine, multiple calls to a
stream's `write_some` function may be combined into one, eliminating
expensive system calls.
]]
[[
[link beast.ref.boost__beast__buffers_cat_view `buffers_cat_view`]
][
This class represents the buffer sequence formed by concatenating
two or more buffer sequences. This is type of object returned by
[link beast.ref.boost__beast__buffers_cat `buffers_cat`].
]]
[[
[link beast.ref.boost__beast__buffers_front `buffers_front`]
][
This function returns the first buffer in a buffer sequence,
or a buffer of size zero if the buffer sequence has no elements.
]]
[[
[link beast.ref.boost__beast__buffers_prefix `buffers_prefix`]
][
This function returns a new buffer or buffer sequence which represents
a prefix of the original buffers.
]]
[[
[link beast.ref.boost__beast__buffers_prefix_view `buffers_prefix_view`]
][
This class represents the buffer sequence formed from a prefix of
an existing buffer sequence. This is the type of buffer returned by
[link beast.ref.boost__beast__buffers_prefix.overload3 `buffers_prefix`].
]]
[[
[link beast.ref.boost__beast__buffers_suffix `buffers_suffix`]
][
This class wraps the underlying memory of an existing buffer sequence
and presents a suffix of the original sequence. The length of the suffix
may be progressively shortened. This lets callers work with sequential
increments of a buffer sequence.
]]
[[
[link beast.ref.boost__beast__buffers_to_string `buffers_to_string`]
][
This function converts a buffer sequence to a `std::string`. It can
be used for diagnostic purposes and tests.
]]
]
These two functions facilitate buffer interoperability with standard
output streams.

View File

@ -38,23 +38,6 @@ composed operations:
[table Asynchronous Helpers
[[Name][Description]]
[[
[link beast.ref.boost__beast__async_completion `async_completion`]
][
This class aggregates the completion handler customization point and
the asynchronous initiation function return value customization point
into a single object which exposes the appropriate output types for the
given input types, and also contains boilerplate that is necessary to
implement an initiation function using the Extensible Model.
]]
[[
[link beast.ref.boost__beast__async_return_type `async_return_type`]
][
This template alias determines the return value of an asynchronous
initiation function given the completion token and signature. It is used
by asynchronous initiation functions to meet the requirements of the
Extensible Asynchronous Model.
]]
[[
[link beast.ref.boost__beast__bind_handler `bind_handler`]
][
@ -66,15 +49,6 @@ composed operations:
`asio_handler_invoke` associated with the original completion handler.
]]
[[
[link beast.ref.boost__beast__handler_alloc `handler_alloc`]
][
This class meets the requirements of [*Allocator], and uses any custom
memory allocation and deallocation hooks associated with a given handler.
It is useful for when a composed operation requires temporary dynamic
allocations to achieve its result. Memory allocated using this allocator
must be freed before the final completion handler is invoked.
]]
[[
[link beast.ref.boost__beast__handler_ptr `handler_ptr`]
][
@ -87,14 +61,6 @@ composed operations:
associated allocator, benefiting from all handler memory management
optimizations transparently.
]]
[[
[link beast.ref.boost__beast__handler_type `handler_type`]
][
This template alias converts a completion token and signature to the
correct completion handler type. It is used in the implementation of
asynchronous initiation functions to meet the requirements of the
Extensible Asynchronous Model.
]]
]
@ -203,27 +169,28 @@ composed operations:
* Type erasing the final handler. This will cause undefined behavior.
* Not using `std::addressof` to get the address of the handler.
* Forgetting to include a return statement after calling an
initiating function.
* Calling a synchronous function by accident. In general composed
operations should not block for long periods of time, since this
ties up a thread running on the __io_service__.
ties up a thread running on the __io_context__.
* Forgetting to overload `asio_handler_invoke` for the composed
operation. This will cause undefined behavior if someone calls
the initiating function with a strand-wrapped function object,
and there is more than thread running on the `io_service`.
* Forgetting to provide `executor_type` and `get_executor` for the
composed operation. This will cause undefined behavior. For example,
if someone calls the initiating function with a strand-wrapped
function object, and there is more than thread running on the
`io_context`, the underlying stream may be accessed in a fashion
that violates safety guarantees.
* For operations which complete immediately (i.e. without calling an
intermediate initiating function), forgetting to use `io_service::post`
intermediate initiating function), forgetting to use
[@http://www.boost.org/doc/html/boost_asio/reference/post.html `boost::asio::post`]
to invoke the final handler. This breaks the following initiating
function guarantee: ['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`].
in a manner equivalent to using `boost::asio::post`].
The function
[link beast.ref.boost__beast__bind_handler `bind_handler`]
is provided for this purpose.

View File

@ -83,9 +83,9 @@ as this example shows.
If a read stream algorithm cannot complete its operation without exceeding
the maximum specified size of the dynamic buffer provided, the error
[link beast.ref.boost__beast__http__error `buffer_overflow`]
is returned. This may be used to impose a limit on the maximum size of an
HTTP message header for protection from buffer overflow attacks. The
following code will print the error message:
is returned. This is one technique which may be used to impose a limit on
the maximum size of an HTTP message header for protection from buffer
overflow attacks. The following code will print the error message:
[http_snippet_6]

View File

@ -31,7 +31,7 @@ field value.
[heading Serializing Chunks]
The __serializer__ automatically applies the chunked tranfer encoding
The __serializer__ automatically applies the chunked transfer encoding
when a message returns `true` from
[link beast.ref.boost__beast__http__message.chunked.overload1 `message::chunked`].
The boundaries between chunks emitted by the serializer are implementation

View File

@ -19,7 +19,7 @@ are performed, or both. Any arguments supplied during construction of
the stream wrapper are passed to next layer's constructor.
Here we declare a websocket stream over a TCP/IP socket with ownership
of the socket. The `io_service` argument is forwarded to the wrapped
of the socket. The `io_context` argument is forwarded to the wrapped
socket's constructor:
[ws_snippet_2]
@ -27,7 +27,7 @@ socket's constructor:
[heading Using SSL]
To use WebSockets over SSL, use an instance of the `boost::asio::ssl::stream`
class template as the template type for the stream. The required `io_service`
class template as the template type for the stream. The required `io_context`
and `ssl::context` arguments are forwarded to the wrapped stream's constructor:
[wss_snippet_1]

View File

@ -88,7 +88,7 @@ a successful upgrade, the caller may wish to perform additional validation
on the received HTTP response message. For example, to check that the
response to a basic authentication challenge is valid. To achieve this,
overloads of the handshake member function allow the caller to store the
received HTTP message in an output reference argument as
received HTTP message in an output reference argument of type
[link beast.ref.boost__beast__websocket__response_type `response_type`]
as follows:

View File

@ -31,9 +31,12 @@ handlers, stackful or stackless coroutines, and even futures:
[ws_snippet_21]
[heading The io_service]
The example programs that come with the library demonstrate the usage of
websocket stream operations with all asynchronous varieties.
The creation and operation of the __io_service__ associated with the
[heading The io_context]
The creation and operation of the __io_context__ associated with the
underlying stream is left to the callers, permitting any implementation
strategy including one that does not require threads for environments
where threads are unavailable. Beast WebSocket itself does not use
@ -45,8 +48,8 @@ Like a regular __Asio__ socket, a
[link beast.ref.boost__beast__websocket__stream `stream`]
is not thread safe. Callers are responsible for synchronizing operations on
the socket using an implicit or explicit strand, as per the Asio documentation.
The asynchronous interface supports one of each of the following operations
to be active at the same time:
The websocket stream asynchronous interface supports one of each of the
following operations to be active at the same time:
* [link beast.ref.boost__beast__websocket__stream.async_read `async_read`] or [link beast.ref.boost__beast__websocket__stream.async_read_some `async_read_some`]
* [link beast.ref.boost__beast__websocket__stream.async_write `async_write`] or [link beast.ref.boost__beast__websocket__stream.async_write_some `async_write_some`]

View File

@ -35,7 +35,7 @@ implementation strategies:
[heading Associated Types]
* [link beast.ref.boost__beast__is_dynamic_buffer `is_dynamic_buffer`]
* `boost::asio::is_dynamic_buffer`
* __ConstBufferSequence__
* __MutableBufferSequence__

View File

@ -190,7 +190,7 @@ In this table:
[
If `(v < 11 && b)`, then all "close" tokens present in the
value are removed, and the "keep-alive" token is added to
the valueif it is not already present.
the value if it is not already present.
][
If `(v < 11 && ! b)`, then all "close" and "keep-alive"
tokens present in the value are removed.

View File

@ -32,7 +32,7 @@ __MutableBufferSequence__ concepts for passing buffers to functions.
The authors have found the dynamic buffer and buffer sequence interfaces to
be optimal for interacting with Asio, and for other tasks such as incremental
parsing of data in buffers (for example, parsing websocket frames stored
in a [link beast.ref.boost__beast__flat_static_buffer `flat_static_buffer`]).
in a [link beast.ref.boost__beast__static_buffer `static_buffer`]).
During the development of Beast the authors have studied other software
packages and in particular the comments left during the Boost Review process

View File

@ -260,10 +260,10 @@ struct header<false, Fields> : Fields
};
```
The start-line data members are replaced traditional accessors using
non-owning references to string buffers. The method is stored using
a simple integer instead of the entire string, for the case where
the method is recognized from the set of known verb strings.
The start-line data members are replaced by traditional accessors
using non-owning references to string buffers. The method is stored
using a simple integer instead of the entire string, for the case
where the method is recognized from the set of known verb strings.
Now we add a requirement to the fields type: management of the
corresponding string is delegated to the [*Fields] container, which can

View File

@ -122,7 +122,7 @@ through the __asio_handler_invoke__ mechanism.
The only requirement in Beast is that calls to asynchronous initiation
functions are made from the same implicit or explicit strand. For
example, if the `io_service` associated with a `beast::websocket::stream`
example, if the `io_context` associated with a `beast::websocket::stream`
is single threaded, this counts as an implicit strand and no performance
costs associated with mutexes are incurred.

View File

@ -174,9 +174,6 @@
<entry valign="top">
<bridgehead renderas="sect3">Classes</bridgehead>
<simplelist type="vert" columns="1">
<member><link linkend="beast.ref.boost__beast__async_completion">async_completion</link></member>
<member><link linkend="beast.ref.boost__beast__async_result">async_result</link></member>
<member><link linkend="beast.ref.boost__beast__async_return_type">async_return_type</link></member>
<member><link linkend="beast.ref.boost__beast__basic_flat_buffer">basic_flat_buffer</link></member>
<member><link linkend="beast.ref.boost__beast__basic_multi_buffer">basic_multi_buffer</link></member>
<member><link linkend="beast.ref.boost__beast__buffered_read_stream">buffered_read_stream</link></member>
@ -197,9 +194,7 @@
<member><link linkend="beast.ref.boost__beast__flat_buffer">flat_buffer</link></member>
<member><link linkend="beast.ref.boost__beast__flat_static_buffer">flat_static_buffer</link></member>
<member><link linkend="beast.ref.boost__beast__flat_static_buffer_base">flat_static_buffer_base</link></member>
<member><link linkend="beast.ref.boost__beast__handler_alloc">handler_alloc</link></member>
<member><link linkend="beast.ref.boost__beast__handler_ptr">handler_ptr</link></member>
<member><link linkend="beast.ref.boost__beast__handler_type">handler_type</link></member>
<member><link linkend="beast.ref.boost__beast__iequal">iequal</link></member>
<member><link linkend="beast.ref.boost__beast__iless">iless</link></member>
<member><link linkend="beast.ref.boost__beast__multi_buffer">multi_buffer</link></member>
@ -236,15 +231,12 @@
<bridgehead renderas="sect3">Type Traits</bridgehead>
<simplelist type="vert" columns="1">
<member><link linkend="beast.ref.boost__beast__get_lowest_layer">get_lowest_layer</link></member>
<member><link linkend="beast.ref.boost__beast__has_get_io_service">has_get_io_service</link></member>
<member><link linkend="beast.ref.boost__beast__has_get_executor">has_get_executor</link></member>
<member><link linkend="beast.ref.boost__beast__is_async_read_stream">is_async_read_stream</link></member>
<member><link linkend="beast.ref.boost__beast__is_async_write_stream">is_async_write_stream</link></member>
<member><link linkend="beast.ref.boost__beast__is_async_stream">is_async_stream</link></member>
<member><link linkend="beast.ref.boost__beast__is_completion_handler">is_completion_handler</link></member>
<member><link linkend="beast.ref.boost__beast__is_const_buffer_sequence">is_const_buffer_sequence</link></member>
<member><link linkend="beast.ref.boost__beast__is_dynamic_buffer">is_dynamic_buffer</link></member>
<member><link linkend="beast.ref.boost__beast__is_file">is_file</link></member>
<member><link linkend="beast.ref.boost__beast__is_mutable_buffer_sequence">is_mutable_buffer_sequence</link></member>
<member><link linkend="beast.ref.boost__beast__is_sync_read_stream">is_sync_read_stream</link></member>
<member><link linkend="beast.ref.boost__beast__is_sync_stream">is_sync_stream</link></member>
<member><link linkend="beast.ref.boost__beast__is_sync_write_stream">is_sync_write_stream</link></member>

View File

@ -285,7 +285,9 @@ INCLUDE_FILE_PATTERNS =
PREDEFINED = \
BOOST_BEAST_DOXYGEN \
BOOST_BEAST_USE_POSIX_FILE=1 \
BOOST_BEAST_USE_WIN32_FILE=1
BOOST_BEAST_USE_WIN32_FILE=1 \
BOOST_ASIO_INITFN_RESULT_TYPE(t,a)=void_or_deduced \
GENERATING_DOCUMENTATION
EXPAND_AS_DEFINED =
SKIP_FUNCTION_MACROS = YES

View File

@ -21,6 +21,7 @@
#include <boost/beast/http.hpp>
#include <boost/beast/websocket.hpp>
#include <boost/beast/version.hpp>
#include <boost/asio/bind_executor.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/ssl/stream.hpp>
#include <boost/asio/strand.hpp>
@ -235,15 +236,16 @@ class websocket_session
boost::beast::multi_buffer buffer_;
protected:
boost::asio::io_service::strand strand_;
boost::asio::strand<
boost::asio::io_context::executor_type> strand_;
boost::asio::steady_timer timer_;
public:
// Construct the session
explicit
websocket_session(boost::asio::io_service& ios)
: strand_(ios)
, timer_(ios,
websocket_session(boost::asio::io_context& ioc)
: strand_(ioc.get_executor())
, timer_(ioc,
(std::chrono::steady_clock::time_point::max)())
{
}
@ -254,15 +256,17 @@ public:
do_accept(http::request<Body, http::basic_fields<Allocator>> req)
{
// Set the timer
timer_.expires_from_now(std::chrono::seconds(15));
timer_.expires_after(std::chrono::seconds(15));
// Accept the websocket handshake
derived().ws().async_accept(
req,
strand_.wrap(std::bind(
&websocket_session::on_accept,
derived().shared_from_this(),
std::placeholders::_1)));
boost::asio::bind_executor(
strand_,
std::bind(
&websocket_session::on_accept,
derived().shared_from_this(),
std::placeholders::_1)));
}
// Called when the timer expires.
@ -273,15 +277,17 @@ public:
return fail(ec, "timer");
// Verify that the timer really expired since the deadline may have moved.
if(timer_.expires_at() <= std::chrono::steady_clock::now())
if(timer_.expiry() <= std::chrono::steady_clock::now())
derived().do_timeout();
// Wait on the timer
timer_.async_wait(
strand_.wrap(std::bind(
&websocket_session::on_timer,
derived().shared_from_this(),
std::placeholders::_1)));
boost::asio::bind_executor(
strand_,
std::bind(
&websocket_session::on_timer,
derived().shared_from_this(),
std::placeholders::_1)));
}
void
@ -302,16 +308,18 @@ public:
do_read()
{
// Set the timer
timer_.expires_from_now(std::chrono::seconds(15));
timer_.expires_after(std::chrono::seconds(15));
// Read a message into our buffer
derived().ws().async_read(
buffer_,
strand_.wrap(std::bind(
&websocket_session::on_read,
derived().shared_from_this(),
std::placeholders::_1,
std::placeholders::_2)));
boost::asio::bind_executor(
strand_,
std::bind(
&websocket_session::on_read,
derived().shared_from_this(),
std::placeholders::_1,
std::placeholders::_2)));
}
void
@ -336,11 +344,13 @@ public:
derived().ws().text(derived().ws().got_text());
derived().ws().async_write(
buffer_.data(),
strand_.wrap(std::bind(
&websocket_session::on_write,
derived().shared_from_this(),
std::placeholders::_1,
std::placeholders::_2)));
boost::asio::bind_executor(
strand_,
std::bind(
&websocket_session::on_write,
derived().shared_from_this(),
std::placeholders::_1,
std::placeholders::_2)));
}
void
@ -378,7 +388,7 @@ public:
explicit
plain_websocket_session(tcp::socket socket)
: websocket_session<plain_websocket_session>(
socket.get_io_service())
socket.get_executor().context())
, ws_(std::move(socket))
{
}
@ -412,15 +422,17 @@ public:
close_ = true;
// Set the timer
timer_.expires_from_now(std::chrono::seconds(15));
timer_.expires_after(std::chrono::seconds(15));
// Close the WebSocket Connection
ws_.async_close(
websocket::close_code::normal,
strand_.wrap(std::bind(
&plain_websocket_session::on_close,
shared_from_this(),
std::placeholders::_1)));
boost::asio::bind_executor(
strand_,
std::bind(
&plain_websocket_session::on_close,
shared_from_this(),
std::placeholders::_1)));
}
void
@ -443,7 +455,8 @@ class ssl_websocket_session
, public std::enable_shared_from_this<ssl_websocket_session>
{
websocket::stream<ssl_stream<tcp::socket>> ws_;
boost::asio::io_service::strand strand_;
boost::asio::strand<
boost::asio::io_context::executor_type> strand_;
bool eof_ = false;
public:
@ -451,9 +464,9 @@ public:
explicit
ssl_websocket_session(ssl_stream<tcp::socket> stream)
: websocket_session<ssl_websocket_session>(
stream.get_io_service())
stream.get_executor().context())
, ws_(std::move(stream))
, strand_(ws_.get_io_service())
, strand_(ws_.get_executor())
{
}
@ -483,14 +496,16 @@ public:
eof_ = true;
// Set the timer
timer_.expires_from_now(std::chrono::seconds(15));
timer_.expires_after(std::chrono::seconds(15));
// Perform the SSL shutdown
ws_.next_layer().async_shutdown(
strand_.wrap(std::bind(
&ssl_websocket_session::on_shutdown,
shared_from_this(),
std::placeholders::_1)));
boost::asio::bind_executor(
strand_,
std::bind(
&ssl_websocket_session::on_shutdown,
shared_from_this(),
std::placeholders::_1)));
}
void
@ -630,10 +645,12 @@ class http_session
http::async_write(
self_.derived().stream(),
msg_,
self_.strand_.wrap(std::bind(
&http_session::on_write,
self_.derived().shared_from_this(),
std::placeholders::_1)));
boost::asio::bind_executor(
self_.strand_,
std::bind(
&http_session::on_write,
self_.derived().shared_from_this(),
std::placeholders::_1)));
}
};
@ -652,20 +669,21 @@ class http_session
protected:
boost::asio::steady_timer timer_;
boost::asio::io_service::strand strand_;
boost::asio::strand<
boost::asio::io_context::executor_type> strand_;
boost::beast::flat_buffer buffer_;
public:
// Construct the session
http_session(
boost::asio::io_service& ios,
boost::asio::io_context& ioc,
boost::beast::flat_buffer buffer,
std::string const& doc_root)
: doc_root_(doc_root)
, queue_(*this)
, timer_(ios,
, timer_(ioc,
(std::chrono::steady_clock::time_point::max)())
, strand_(ios)
, strand_(ioc.get_executor())
, buffer_(std::move(buffer))
{
}
@ -674,17 +692,19 @@ public:
do_read()
{
// Set the timer
timer_.expires_from_now(std::chrono::seconds(15));
timer_.expires_after(std::chrono::seconds(15));
// Read a request
http::async_read(
derived().stream(),
buffer_,
req_,
strand_.wrap(std::bind(
&http_session::on_read,
derived().shared_from_this(),
std::placeholders::_1)));
boost::asio::bind_executor(
strand_,
std::bind(
&http_session::on_read,
derived().shared_from_this(),
std::placeholders::_1)));
}
// Called when the timer expires.
@ -695,15 +715,17 @@ public:
return fail(ec, "timer");
// Verify that the timer really expired since the deadline may have moved.
if(timer_.expires_at() <= std::chrono::steady_clock::now())
if(timer_.expiry() <= std::chrono::steady_clock::now())
return derived().do_timeout();
// Wait on the timer
timer_.async_wait(
strand_.wrap(std::bind(
&http_session::on_timer,
derived().shared_from_this(),
std::placeholders::_1)));
boost::asio::bind_executor(
strand_,
std::bind(
&http_session::on_timer,
derived().shared_from_this(),
std::placeholders::_1)));
}
void
@ -769,7 +791,8 @@ class plain_http_session
, public std::enable_shared_from_this<plain_http_session>
{
tcp::socket socket_;
boost::asio::io_service::strand strand_;
boost::asio::strand<
boost::asio::io_context::executor_type> strand_;
public:
// Create the http_session
@ -778,11 +801,11 @@ public:
boost::beast::flat_buffer buffer,
std::string const& doc_root)
: http_session<plain_http_session>(
socket.get_io_service(),
socket.get_executor().context(),
std::move(buffer),
doc_root)
, socket_(std::move(socket))
, strand_(socket_.get_io_service())
, strand_(socket_.get_executor())
{
}
@ -838,7 +861,8 @@ class ssl_http_session
, public std::enable_shared_from_this<ssl_http_session>
{
ssl_stream<tcp::socket> stream_;
boost::asio::io_service::strand strand_;
boost::asio::strand<
boost::asio::io_context::executor_type> strand_;
bool eof_ = false;
public:
@ -849,11 +873,11 @@ public:
boost::beast::flat_buffer buffer,
std::string const& doc_root)
: http_session<ssl_http_session>(
socket.get_io_service(),
socket.get_executor().context(),
std::move(buffer),
doc_root)
, stream_(std::move(socket), ctx)
, strand_(stream_.get_io_service())
, strand_(stream_.get_executor())
{
}
@ -880,18 +904,20 @@ public:
on_timer({});
// Set the timer
timer_.expires_from_now(std::chrono::seconds(15));
timer_.expires_after(std::chrono::seconds(15));
// Perform the SSL handshake
// Note, this is the buffered version of the handshake.
stream_.async_handshake(
ssl::stream_base::server,
buffer_.data(),
strand_.wrap(std::bind(
&ssl_http_session::on_handshake,
shared_from_this(),
std::placeholders::_1,
std::placeholders::_2)));
boost::asio::bind_executor(
strand_,
std::bind(
&ssl_http_session::on_handshake,
shared_from_this(),
std::placeholders::_1,
std::placeholders::_2)));
}
void
on_handshake(
@ -917,14 +943,16 @@ public:
eof_ = true;
// Set the timer
timer_.expires_from_now(std::chrono::seconds(15));
timer_.expires_after(std::chrono::seconds(15));
// Perform the SSL shutdown
stream_.async_shutdown(
strand_.wrap(std::bind(
&ssl_http_session::on_shutdown,
shared_from_this(),
std::placeholders::_1)));
boost::asio::bind_executor(
strand_,
std::bind(
&ssl_http_session::on_shutdown,
shared_from_this(),
std::placeholders::_1)));
}
void
@ -962,7 +990,8 @@ class detect_session : public std::enable_shared_from_this<detect_session>
{
tcp::socket socket_;
ssl::context& ctx_;
boost::asio::io_service::strand strand_;
boost::asio::strand<
boost::asio::io_context::executor_type> strand_;
std::string const& doc_root_;
boost::beast::flat_buffer buffer_;
@ -974,7 +1003,7 @@ public:
std::string const& doc_root)
: socket_(std::move(socket))
, ctx_(ctx)
, strand_(socket_.get_io_service())
, strand_(socket_.get_executor())
, doc_root_(doc_root)
{
}
@ -986,11 +1015,13 @@ public:
async_detect_ssl(
socket_,
buffer_,
strand_.wrap(std::bind(
&detect_session::on_detect,
shared_from_this(),
std::placeholders::_1,
std::placeholders::_2)));
boost::asio::bind_executor(
strand_,
std::bind(
&detect_session::on_detect,
shared_from_this(),
std::placeholders::_1,
std::placeholders::_2)));
}
@ -1029,13 +1060,13 @@ class listener : public std::enable_shared_from_this<listener>
public:
listener(
boost::asio::io_service& ios,
boost::asio::io_context& ioc,
ssl::context& ctx,
tcp::endpoint endpoint,
std::string const& doc_root)
: ctx_(ctx)
, acceptor_(ios)
, socket_(ios)
, acceptor_(ioc)
, socket_(ioc)
, doc_root_(doc_root)
{
boost::system::error_code ec;
@ -1058,7 +1089,7 @@ public:
// Start listening for connections
acceptor_.listen(
boost::asio::socket_base::max_connections, ec);
boost::asio::socket_base::max_listen_connections, ec);
if(ec)
{
fail(ec, "listen");
@ -1120,13 +1151,13 @@ int main(int argc, char* argv[])
" advanced-server-flex 0.0.0.0 8080 . 1\n";
return EXIT_FAILURE;
}
auto const address = boost::asio::ip::address::from_string(argv[1]);
auto const address = boost::asio::ip::make_address(argv[1]);
auto const port = static_cast<unsigned short>(std::atoi(argv[2]));
std::string const doc_root = argv[3];
auto const threads = std::max<std::size_t>(1, std::atoi(argv[4]));
auto const threads = std::max<int>(1, std::atoi(argv[4]));
// The io_service is required for all I/O
boost::asio::io_service ios{threads};
// The io_context is required for all I/O
boost::asio::io_context ioc{threads};
// The SSL context is required, and holds certificates
ssl::context ctx{ssl::context::sslv23};
@ -1136,7 +1167,7 @@ int main(int argc, char* argv[])
// Create and launch a listening port
std::make_shared<listener>(
ios,
ioc,
ctx,
tcp::endpoint{address, port},
doc_root)->run();
@ -1146,11 +1177,11 @@ int main(int argc, char* argv[])
v.reserve(threads - 1);
for(auto i = threads - 1; i > 0; --i)
v.emplace_back(
[&ios]
[&ioc]
{
ios.run();
ioc.run();
});
ios.run();
ioc.run();
return EXIT_SUCCESS;
}

View File

@ -17,6 +17,7 @@
#include <boost/beast/http.hpp>
#include <boost/beast/websocket.hpp>
#include <boost/beast/version.hpp>
#include <boost/asio/bind_executor.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/strand.hpp>
#include <boost/asio/steady_timer.hpp>
@ -214,7 +215,8 @@ fail(boost::system::error_code ec, char const* what)
class websocket_session : public std::enable_shared_from_this<websocket_session>
{
websocket::stream<tcp::socket> ws_;
boost::asio::io_service::strand strand_;
boost::asio::strand<
boost::asio::io_context::executor_type> strand_;
boost::asio::steady_timer timer_;
boost::beast::multi_buffer buffer_;
@ -223,8 +225,8 @@ public:
explicit
websocket_session(tcp::socket socket)
: ws_(std::move(socket))
, strand_(ws_.get_io_service())
, timer_(ws_.get_io_service(),
, strand_(ws_.get_executor())
, timer_(ws_.get_executor().context(),
(std::chrono::steady_clock::time_point::max)())
{
}
@ -239,15 +241,17 @@ public:
on_timer({});
// Set the timer
timer_.expires_from_now(std::chrono::seconds(15));
timer_.expires_after(std::chrono::seconds(15));
// Accept the websocket handshake
ws_.async_accept(
req,
strand_.wrap(std::bind(
&websocket_session::on_accept,
shared_from_this(),
std::placeholders::_1)));
boost::asio::bind_executor(
strand_,
std::bind(
&websocket_session::on_accept,
shared_from_this(),
std::placeholders::_1)));
}
// Called when the timer expires.
@ -258,7 +262,7 @@ public:
return fail(ec, "timer");
// Verify that the timer really expired since the deadline may have moved.
if(timer_.expires_at() <= std::chrono::steady_clock::now())
if(timer_.expiry() <= std::chrono::steady_clock::now())
{
// Closing the socket cancels all outstanding operations. They
// will complete with boost::asio::error::operation_aborted
@ -269,10 +273,12 @@ public:
// Wait on the timer
timer_.async_wait(
strand_.wrap(std::bind(
&websocket_session::on_timer,
shared_from_this(),
std::placeholders::_1)));
boost::asio::bind_executor(
strand_,
std::bind(
&websocket_session::on_timer,
shared_from_this(),
std::placeholders::_1)));
}
void
@ -293,16 +299,18 @@ public:
do_read()
{
// Set the timer
timer_.expires_from_now(std::chrono::seconds(15));
timer_.expires_after(std::chrono::seconds(15));
// Read a message into our buffer
ws_.async_read(
buffer_,
strand_.wrap(std::bind(
&websocket_session::on_read,
shared_from_this(),
std::placeholders::_1,
std::placeholders::_2)));
boost::asio::bind_executor(
strand_,
std::bind(
&websocket_session::on_read,
shared_from_this(),
std::placeholders::_1,
std::placeholders::_2)));
}
void
@ -327,11 +335,13 @@ public:
ws_.text(ws_.got_text());
ws_.async_write(
buffer_.data(),
strand_.wrap(std::bind(
&websocket_session::on_write,
shared_from_this(),
std::placeholders::_1,
std::placeholders::_2)));
boost::asio::bind_executor(
strand_,
std::bind(
&websocket_session::on_write,
shared_from_this(),
std::placeholders::_1,
std::placeholders::_2)));
}
void
@ -432,10 +442,12 @@ class http_session : public std::enable_shared_from_this<http_session>
http::async_write(
self_.socket_,
msg_,
self_.strand_.wrap(std::bind(
&http_session::on_write,
self_.shared_from_this(),
std::placeholders::_1)));
boost::asio::bind_executor(
self_.strand_,
std::bind(
&http_session::on_write,
self_.shared_from_this(),
std::placeholders::_1)));
}
};
@ -449,7 +461,8 @@ class http_session : public std::enable_shared_from_this<http_session>
};
tcp::socket socket_;
boost::asio::io_service::strand strand_;
boost::asio::strand<
boost::asio::io_context::executor_type> strand_;
boost::asio::steady_timer timer_;
boost::beast::flat_buffer buffer_;
std::string const& doc_root_;
@ -463,8 +476,8 @@ public:
tcp::socket socket,
std::string const& doc_root)
: socket_(std::move(socket))
, strand_(socket_.get_io_service())
, timer_(socket_.get_io_service(),
, strand_(socket_.get_executor())
, timer_(socket_.get_executor().context(),
(std::chrono::steady_clock::time_point::max)())
, doc_root_(doc_root)
, queue_(*this)
@ -486,14 +499,16 @@ public:
do_read()
{
// Set the timer
timer_.expires_from_now(std::chrono::seconds(15));
timer_.expires_after(std::chrono::seconds(15));
// Read a request
http::async_read(socket_, buffer_, req_,
strand_.wrap(std::bind(
&http_session::on_read,
shared_from_this(),
std::placeholders::_1)));
boost::asio::bind_executor(
strand_,
std::bind(
&http_session::on_read,
shared_from_this(),
std::placeholders::_1)));
}
// Called when the timer expires.
@ -504,7 +519,7 @@ public:
return fail(ec, "timer");
// Verify that the timer really expired since the deadline may have moved.
if(timer_.expires_at() <= std::chrono::steady_clock::now())
if(timer_.expiry() <= std::chrono::steady_clock::now())
{
// Closing the socket cancels all outstanding operations. They
// will complete with boost::asio::error::operation_aborted
@ -515,10 +530,12 @@ public:
// Wait on the timer
timer_.async_wait(
strand_.wrap(std::bind(
&http_session::on_timer,
shared_from_this(),
std::placeholders::_1)));
boost::asio::bind_executor(
strand_,
std::bind(
&http_session::on_timer,
shared_from_this(),
std::placeholders::_1)));
}
void
@ -599,11 +616,11 @@ class listener : public std::enable_shared_from_this<listener>
public:
listener(
boost::asio::io_service& ios,
boost::asio::io_context& ioc,
tcp::endpoint endpoint,
std::string const& doc_root)
: acceptor_(ios)
, socket_(ios)
: acceptor_(ioc)
, socket_(ioc)
, doc_root_(doc_root)
{
boost::system::error_code ec;
@ -626,7 +643,7 @@ public:
// Start listening for connections
acceptor_.listen(
boost::asio::socket_base::max_connections, ec);
boost::asio::socket_base::max_listen_connections, ec);
if(ec)
{
fail(ec, "listen");
@ -687,17 +704,17 @@ int main(int argc, char* argv[])
" advanced-server 0.0.0.0 8080 . 1\n";
return EXIT_FAILURE;
}
auto const address = boost::asio::ip::address::from_string(argv[1]);
auto const address = boost::asio::ip::make_address(argv[1]);
auto const port = static_cast<unsigned short>(std::atoi(argv[2]));
std::string const doc_root = argv[3];
auto const threads = std::max<std::size_t>(1, std::atoi(argv[4]));
auto const threads = std::max<int>(1, std::atoi(argv[4]));
// The io_service is required for all I/O
boost::asio::io_service ios{threads};
// The io_context is required for all I/O
boost::asio::io_context ioc{threads};
// Create and launch a listening port
std::make_shared<listener>(
ios,
ioc,
tcp::endpoint{address, port},
doc_root)->run();
@ -706,11 +723,11 @@ int main(int argc, char* argv[])
v.reserve(threads - 1);
for(auto i = threads - 1; i > 0; --i)
v.emplace_back(
[&ios]
[&ioc]
{
ios.run();
ioc.run();
});
ios.run();
ioc.run();
return EXIT_SUCCESS;
}

View File

@ -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));
}

View File

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

View File

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

View File

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

View File

@ -62,7 +62,8 @@ send_expect_100_continue(
static_assert(is_sync_stream<SyncStream>::value,
"SyncStream requirements not met");
static_assert(is_dynamic_buffer<DynamicBuffer>::value,
static_assert(
boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
"DynamicBuffer requirements not met");
// Insert or replace the Expect field
@ -123,7 +124,8 @@ receive_expect_100_continue(
static_assert(is_sync_stream<SyncStream>::value,
"SyncStream requirements not met");
static_assert(is_dynamic_buffer<DynamicBuffer>::value,
static_assert(
boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
"DynamicBuffer requirements not met");
// Declare a parser for a request with a string body
@ -194,9 +196,6 @@ send_cgi_response(
static_assert(is_sync_write_stream<SyncWriteStream>::value,
"SyncWriteStream requirements not met");
using boost::asio::buffer_cast;
using boost::asio::buffer_size;
// Set up the response. We use the buffer_body type,
// allowing serialization to use manually provided buffers.
response<buffer_body> res;
@ -293,7 +292,8 @@ void do_server_head(
{
static_assert(is_sync_stream<SyncStream>::value,
"SyncStream requirements not met");
static_assert(is_dynamic_buffer<DynamicBuffer>::value,
static_assert(
boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
"DynamicBuffer requirments not met");
// We deliver this payload for all GET requests
@ -386,7 +386,8 @@ do_head_request(
// Do some type checking to be a good citizen
static_assert(is_sync_stream<SyncStream>::value,
"SyncStream requirements not met");
static_assert(is_dynamic_buffer<DynamicBuffer>::value,
static_assert(
boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
"DynamicBuffer requirments not met");
// The interfaces we are using are low level and do not
@ -589,10 +590,6 @@ public:
void
operator()(error_code& ec, ConstBufferSequence const& buffers) const
{
// These asio functions are needed to access a buffer's contents
using boost::asio::buffer_cast;
using boost::asio::buffer_size;
// Error codes must be cleared on success
ec = {};
@ -600,15 +597,16 @@ public:
std::size_t bytes_transferred = 0;
// Loop over the buffer sequence
for(auto it = buffers.begin(); it != buffers.end(); ++ it)
for(auto it = boost::asio::buffer_sequence_begin(buffers);
it != boost::asio::buffer_sequence_end(buffers); ++it)
{
// This is the next buffer in the sequence
boost::asio::const_buffer const buffer = *it;
// Write it to the std::ostream
os_.write(
buffer_cast<char const*>(buffer),
buffer_size(buffer));
reinterpret_cast<char const*>(buffer.data()),
buffer.size());
// If the std::ostream fails, convert it to an error code
if(os_.fail())
@ -714,13 +712,12 @@ read_istream(
if(is.rdbuf()->in_avail() > 0)
{
// Get a mutable buffer sequence for writing
auto const mb = buffer.prepare(
auto const b = buffer.prepare(
static_cast<std::size_t>(is.rdbuf()->in_avail()));
// Now get everything we can from the istream
buffer.commit(static_cast<std::size_t>(is.readsome(
boost::asio::buffer_cast<char*>(mb),
boost::asio::buffer_size(mb))));
reinterpret_cast<char*>(b.data()), b.size())));
}
else if(buffer.size() == 0)
{
@ -729,12 +726,10 @@ read_istream(
if(! is.eof())
{
// Get a mutable buffer sequence for writing
auto const mb = buffer.prepare(1024);
auto const b = buffer.prepare(1024);
// Try to get more from the istream. This might block.
is.read(
boost::asio::buffer_cast<char*>(mb),
boost::asio::buffer_size(mb));
is.read(reinterpret_cast<char*>(b.data()), b.size());
// If an error occurs on the istream then return it to the caller.
if(is.fail() && ! is.eof())

View File

@ -23,7 +23,7 @@ auto
async_echo(AsyncStream& stream, CompletionToken&& token)
//]
-> boost::beast::async_return_type<CompletionToken, void(boost::beast::error_code)>;
-> BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void(boost::beast::error_code));
//[example_core_echo_op_2
@ -61,14 +61,14 @@ async_echo(AsyncStream& stream, CompletionToken&& token)
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 AsyncStream,
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)> /*< This is the signature for the completion handler >*/
void(boost::beast::error_code)) /*< This is the signature for the completion handler >*/
async_echo(
AsyncStream& stream,
CompletionToken&& token);
@ -95,11 +95,13 @@ class echo_op
// The buffer used to hold the input and output data.
//
// We use a custom allocator for performance, this allows
// the implementation of the io_service to make efficient
// the implementation of the io_context to make efficient
// re-use of memory allocated by composed operations during
// a continuation.
//
boost::asio::basic_streambuf<boost::beast::handler_alloc<char, Handler>> buffer;
boost::asio::basic_streambuf<typename std::allocator_traits<
boost::asio::associated_allocator_t<Handler> >::
template rebind_alloc<char> > buffer;
// handler_ptr requires that the first parameter to the
// contained object constructor is a reference to the
@ -108,7 +110,7 @@ class echo_op
explicit state(Handler& handler, AsyncStream& stream_)
: stream(stream_)
, buffer((std::numeric_limits<std::size_t>::max)(),
boost::beast::handler_alloc<char, Handler>{handler})
boost::asio::get_associated_allocator(handler))
{
}
};
@ -116,14 +118,10 @@ class echo_op
// The operation's data is kept in a cheap-to-copy smart
// pointer container called `handler_ptr`. This efficiently
// satisfies the CopyConstructible requirements of completion
// handlers.
// handlers with expensive-to-copy state.
//
// `handler_ptr` uses these memory allocation hooks associated
// with the final completion handler, in order to allocate the
// storage for `state`:
//
// asio_handler_allocate
// asio_handler_deallocate
// `handler_ptr` uses the allocator associated with the final
// completion handler, in order to allocate the storage for `state`.
//
boost::beast::handler_ptr<state, Handler> p_;
@ -144,30 +142,45 @@ 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(p_.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(p_->stream.get_executor())>;
executor_type get_executor() const noexcept
{
return boost::asio::get_associated_executor(
p_.handler(), p_->stream.get_executor());
}
// (DEPRECATED)
template<class AsyncStream_, class Handler_>
friend bool asio_handler_is_continuation(
echo_op<AsyncStream_, Handler_>* op);
// The entry point for this handler. This will get called
// as our intermediate operations complete. Definition below.
//
void operator()(boost::beast::error_code ec, std::size_t bytes_transferred);
// The next four functions are required for our class
// to meet the requirements for composed operations.
// Definitions and exposition will follow.
template<class AsyncStream_, class Handler_, class Function>
friend void asio_handler_invoke(
Function&& f, echo_op<AsyncStream_, Handler_>* op);
template<class AsyncStream_, class Handler_>
friend void* asio_handler_allocate(
std::size_t size, echo_op<AsyncStream_, Handler_>* op);
template<class AsyncStream_, class Handler_>
friend void asio_handler_deallocate(
void* p, std::size_t size, echo_op<AsyncStream_, Handler_>* op);
template<class AsyncStream_, class Handler_>
friend bool asio_handler_is_continuation(
echo_op<AsyncStream_, Handler_>* op);
};
//]
@ -226,44 +239,6 @@ operator()(boost::beast::error_code ec, std::size_t bytes_transferred)
//[example_core_echo_op_6
// 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 the call through to the hook
// associated with the final handler. The "using" statements are
// structured to permit argument dependent lookup. Always use
// `std::addressof` or its equivalent to pass the pointer to the
// handler, otherwise an unwanted overload of `operator&` may be
// called instead.
template<class AsyncStream, class Handler, class Function>
void asio_handler_invoke(
Function&& f, echo_op<AsyncStream, Handler>* op)
{
using boost::asio::asio_handler_invoke;
return asio_handler_invoke(f, std::addressof(op->p_.handler()));
}
template<class AsyncStream, class Handler>
void* asio_handler_allocate(
std::size_t size, echo_op<AsyncStream, Handler>* op)
{
using boost::asio::asio_handler_allocate;
return asio_handler_allocate(size, std::addressof(op->p_.handler()));
}
template<class AsyncStream, class Handler>
void asio_handler_deallocate(
void* p, std::size_t size, echo_op<AsyncStream, Handler>* op)
{
using boost::asio::asio_handler_deallocate;
return asio_handler_deallocate(p, size,
std::addressof(op->p_.handler()));
}
// 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 one, it means
@ -297,7 +272,7 @@ class echo_op;
// Read a line and echo it back
//
template<class AsyncStream, class CompletionToken>
boost::beast::async_return_type<CompletionToken, void(boost::beast::error_code)>
BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void(boost::beast::error_code))
async_echo(AsyncStream& stream, CompletionToken&& token)
{
// Make sure stream meets the requirements. We use static_assert
@ -310,16 +285,20 @@ async_echo(AsyncStream& stream, CompletionToken&& token)
// uses the result and handler specializations associated with
// the completion token to help customize the return value.
//
boost::beast::async_completion<CompletionToken, void(boost::beast::error_code)> init{token};
boost::asio::async_completion<CompletionToken, void(boost::beast::error_code)> 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 be used.
//
echo_op<AsyncStream, boost::beast::handler_type<CompletionToken, void(boost::beast::error_code)>>{
stream, init.completion_handler}(boost::beast::error_code{}, 0);
echo_op<
AsyncStream,
BOOST_ASIO_HANDLER_TYPE(
CompletionToken, void(boost::beast::error_code))>{
stream,
init.completion_handler}(boost::beast::error_code{}, 0);
// This hook lets the caller see a return value when appropriate.
// For example this might return std::future<error_code> if
@ -333,16 +312,15 @@ async_echo(AsyncStream& stream, CompletionToken&& token)
int main(int, char** argv)
{
using address_type = boost::asio::ip::address;
using socket_type = boost::asio::ip::tcp::socket;
using endpoint_type = boost::asio::ip::tcp::endpoint;
// Create a listening socket, accept a connection, perform
// the echo, and then shut everything down and exit.
boost::asio::io_service ios;
socket_type sock{ios};
boost::asio::ip::tcp::acceptor acceptor{ios};
endpoint_type ep{address_type::from_string("0.0.0.0"), 0};
boost::asio::io_context ioc;
socket_type sock{ioc};
boost::asio::ip::tcp::acceptor acceptor{ioc};
endpoint_type ep{boost::asio::ip::make_address("0.0.0.0"), 0};
acceptor.open(ep.protocol());
acceptor.bind(ep);
acceptor.listen();
@ -353,6 +331,6 @@ int main(int, char** argv)
if(ec)
std::cerr << argv[0] << ": " << ec.message() << std::endl;
});
ios.run();
ioc.run();
return 0;
}

View File

@ -50,11 +50,11 @@ class session : public std::enable_shared_from_this<session>
http::response<http::string_body> res_;
public:
// Resolver and stream require an io_service
// Resolver and stream require an io_context
explicit
session(boost::asio::io_service& ios, ssl::context& ctx)
: resolver_(ios)
, stream_(ios, ctx)
session(boost::asio::io_context& ioc, ssl::context& ctx)
: resolver_(ioc)
, stream_(ioc, ctx)
{
}
@ -73,7 +73,9 @@ public:
req_.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING);
// Look up the domain name
resolver_.async_resolve({host, port},
resolver_.async_resolve(
host,
port,
std::bind(
&session::on_resolve,
shared_from_this(),
@ -84,7 +86,7 @@ public:
void
on_resolve(
boost::system::error_code ec,
tcp::resolver::iterator result)
tcp::resolver::results_type results)
{
if(ec)
return fail(ec, "resolve");
@ -92,7 +94,8 @@ public:
// Make the connection on the IP address we get from a lookup
boost::asio::async_connect(
stream_.next_layer(),
result,
results.begin(),
results.end(),
std::bind(
&session::on_connect,
shared_from_this(),
@ -202,8 +205,8 @@ int main(int argc, char** argv)
auto const port = argv[2];
auto const target = argv[3];
// The io_service is required for all I/O
boost::asio::io_service ios;
// The io_context is required for all I/O
boost::asio::io_context ioc;
// The SSL context is required, and holds certificates
ssl::context ctx{ssl::context::sslv23_client};
@ -212,11 +215,11 @@ int main(int argc, char** argv)
load_root_certificates(ctx);
// Launch the asynchronous operation
std::make_shared<session>(ios, ctx)->run(host, port, target);
std::make_shared<session>(ioc, ctx)->run(host, port, target);
// Run the I/O service. The call will return when
// the get operation is complete.
ios.run();
ioc.run();
return EXIT_SUCCESS;
}

View File

@ -46,11 +46,11 @@ class session : public std::enable_shared_from_this<session>
http::response<http::string_body> res_;
public:
// Resolver and socket require an io_service
// Resolver and socket require an io_context
explicit
session(boost::asio::io_service& ios)
: resolver_(ios)
, socket_(ios)
session(boost::asio::io_context& ioc)
: resolver_(ioc)
, socket_(ioc)
{
}
@ -69,7 +69,9 @@ public:
req_.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING);
// Look up the domain name
resolver_.async_resolve({host, port},
resolver_.async_resolve(
host,
port,
std::bind(
&session::on_resolve,
shared_from_this(),
@ -80,13 +82,16 @@ public:
void
on_resolve(
boost::system::error_code ec,
tcp::resolver::iterator result)
tcp::resolver::results_type results)
{
if(ec)
return fail(ec, "resolve");
// Make the connection on the IP address we get from a lookup
boost::asio::async_connect(socket_, result,
boost::asio::async_connect(
socket_,
results.begin(),
results.end(),
std::bind(
&session::on_connect,
shared_from_this(),
@ -168,15 +173,15 @@ int main(int argc, char** argv)
auto const port = argv[2];
auto const target = argv[3];
// The io_service is required for all I/O
boost::asio::io_service ios;
// The io_context is required for all I/O
boost::asio::io_context ioc;
// Launch the asynchronous operation
std::make_shared<session>(ios)->run(host, port, target);
std::make_shared<session>(ioc)->run(host, port, target);
// Run the I/O service. The call will return when
// the get operation is complete.
ios.run();
ioc.run();
return EXIT_SUCCESS;
}

View File

@ -46,23 +46,23 @@ do_session(
std::string const& host,
std::string const& port,
std::string const& target,
boost::asio::io_service& ios,
boost::asio::io_context& ioc,
ssl::context& ctx,
boost::asio::yield_context yield)
{
boost::system::error_code ec;
// These objects perform our I/O
tcp::resolver resolver{ios};
ssl::stream<tcp::socket> stream{ios, ctx};
tcp::resolver resolver{ioc};
ssl::stream<tcp::socket> stream{ioc, ctx};
// Look up the domain name
auto const lookup = resolver.async_resolve({host, port}, yield[ec]);
auto const results = resolver.async_resolve(host, port, yield[ec]);
if(ec)
return fail(ec, "resolve");
// Make the connection on the IP address we get from a lookup
boost::asio::async_connect(stream.next_layer(), lookup, yield[ec]);
boost::asio::async_connect(stream.next_layer(), results.begin(), results.end(), yield[ec]);
if(ec)
return fail(ec, "connect");
@ -126,8 +126,8 @@ int main(int argc, char** argv)
auto const port = argv[2];
auto const target = argv[3];
// The io_service is required for all I/O
boost::asio::io_service ios;
// The io_context is required for all I/O
boost::asio::io_context ioc;
// The SSL context is required, and holds certificates
ssl::context ctx{ssl::context::sslv23_client};
@ -136,18 +136,18 @@ int main(int argc, char** argv)
load_root_certificates(ctx);
// Launch the asynchronous operation
boost::asio::spawn(ios, std::bind(
boost::asio::spawn(ioc, std::bind(
&do_session,
std::string(host),
std::string(port),
std::string(target),
std::ref(ios),
std::ref(ioc),
std::ref(ctx),
std::placeholders::_1));
// Run the I/O service. The call will return when
// the get operation is complete.
ios.run();
ioc.run();
return EXIT_SUCCESS;
}

View File

@ -42,22 +42,22 @@ do_session(
std::string const& host,
std::string const& port,
std::string const& target,
boost::asio::io_service& ios,
boost::asio::io_context& ioc,
boost::asio::yield_context yield)
{
boost::system::error_code ec;
// These objects perform our I/O
tcp::resolver resolver{ios};
tcp::socket socket{ios};
tcp::resolver resolver{ioc};
tcp::socket socket{ioc};
// Look up the domain name
auto const lookup = resolver.async_resolve({host, port}, yield[ec]);
auto const results = resolver.async_resolve(host, port, yield[ec]);
if(ec)
return fail(ec, "resolve");
// Make the connection on the IP address we get from a lookup
boost::asio::async_connect(socket, lookup, yield[ec]);
boost::asio::async_connect(socket, results.begin(), results.end(), yield[ec]);
if(ec)
return fail(ec, "connect");
@ -114,21 +114,21 @@ int main(int argc, char** argv)
auto const port = argv[2];
auto const target = argv[3];
// The io_service is required for all I/O
boost::asio::io_service ios;
// The io_context is required for all I/O
boost::asio::io_context ioc;
// Launch the asynchronous operation
boost::asio::spawn(ios, std::bind(
boost::asio::spawn(ioc, std::bind(
&do_session,
std::string(host),
std::string(port),
std::string(target),
std::ref(ios),
std::ref(ioc),
std::placeholders::_1));
// Run the I/O service. The call will return when
// the get operation is complete.
ios.run();
ioc.run();
return EXIT_SUCCESS;
}

View File

@ -18,10 +18,11 @@
#include <boost/beast/core.hpp>
#include <boost/beast/http.hpp>
#include <boost/beast/version.hpp>
#include <boost/asio/bind_executor.hpp>
#include <boost/asio/connect.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/post.hpp>
#include <boost/asio/strand.hpp>
#include <boost/optional.hpp>
#include <atomic>
#include <chrono>
#include <cstdlib>
@ -43,16 +44,17 @@ namespace chrono = std::chrono; // from <chrono>
// This structure aggregates statistics on all the sites
class crawl_report
{
boost::asio::io_service& ios_;
boost::asio::io_service::strand strand_;
boost::asio::io_context& ioc_;
boost::asio::strand<
boost::asio::io_context::executor_type> strand_;
std::atomic<std::size_t> index_;
std::vector<char const*> const& hosts_;
std::size_t count_ = 0;
public:
crawl_report(boost::asio::io_service& ios)
: ios_(ios)
, strand_(ios_)
crawl_report(boost::asio::io_context& ioc)
: ioc_(ioc)
, strand_(ioc_.get_executor())
, index_(0)
, hosts_(urls_large_data())
{
@ -64,18 +66,19 @@ public:
void
aggregate(F const& f)
{
ios_.post(strand_.wrap(
[&, f]
{
f(*this);
if(count_ % 100 == 0)
boost::asio::post(
strand_,
[&, f]
{
std::cerr <<
"Progress: " << count_ << " of " << hosts_.size() << "\n";
//std::cerr << *this;
}
++count_;
}));
f(*this);
if(count_ % 100 == 0)
{
std::cerr <<
"Progress: " << count_ << " of " << hosts_.size() << "\n";
//std::cerr << *this;
}
++count_;
});
}
// Returns the next host to check
@ -148,7 +151,8 @@ class worker : public std::enable_shared_from_this<worker>
tcp::resolver resolver_;
tcp::socket socket_;
boost::asio::steady_timer timer_;
boost::asio::io_service::strand strand_;
boost::asio::strand<
boost::asio::io_context::executor_type> strand_;
boost::beast::flat_buffer buffer_; // (Must persist between reads)
http::request<http::empty_body> req_;
http::response<http::string_body> res_;
@ -156,16 +160,16 @@ class worker : public std::enable_shared_from_this<worker>
public:
worker(worker&&) = default;
// Resolver and socket require an io_service
// Resolver and socket require an io_context
worker(
crawl_report& report,
boost::asio::io_service& ios)
boost::asio::io_context& ioc)
: report_(report)
, resolver_(ios)
, socket_(ios)
, timer_(ios,
, resolver_(ioc)
, socket_(ioc)
, timer_(ioc,
(chrono::steady_clock::time_point::max)())
, strand_(ios)
, strand_(ioc.get_executor())
{
// Set up the common fields of the request
req_.version(11);
@ -200,7 +204,7 @@ public:
}
// Verify that the timer really expired since the deadline may have moved.
if(timer_.expires_at() <= chrono::steady_clock::now())
if(timer_.expiry() <= chrono::steady_clock::now())
{
socket_.shutdown(tcp::socket::shutdown_both, ec);
socket_.close(ec);
@ -209,10 +213,12 @@ public:
// Wait on the timer
timer_.async_wait(
strand_.wrap(std::bind(
&worker::on_timer,
shared_from_this(),
std::placeholders::_1)));
boost::asio::bind_executor(
strand_,
std::bind(
&worker::on_timer,
shared_from_this(),
std::placeholders::_1)));
}
void
@ -224,8 +230,7 @@ public:
// nullptr means no more work
if(! host)
{
boost::system::error_code ec;
timer_.cancel(ec);
timer_.cancel_one();
return;
}
@ -233,23 +238,26 @@ public:
req_.set(http::field::host, host);
// Set the timer
timer_.expires_from_now(chrono::seconds(timeout));
timer_.expires_after(chrono::seconds(timeout));
// Set up an HTTP GET request message
// Look up the domain name
resolver_.async_resolve(
tcp::resolver::query{host, "http"},
strand_.wrap(std::bind(
&worker::on_resolve,
shared_from_this(),
std::placeholders::_1,
std::placeholders::_2)));
host,
"http",
boost::asio::bind_executor(
strand_,
std::bind(
&worker::on_resolve,
shared_from_this(),
std::placeholders::_1,
std::placeholders::_2)));
}
void
on_resolve(
boost::system::error_code ec,
tcp::resolver::iterator result)
tcp::resolver::results_type results)
{
if(ec)
{
@ -262,16 +270,19 @@ public:
}
// Set the timer
timer_.expires_from_now(chrono::seconds(timeout));
timer_.expires_after(chrono::seconds(timeout));
// Make the connection on the IP address we get from a lookup
boost::asio::async_connect(
socket_,
result,
strand_.wrap(std::bind(
&worker::on_connect,
shared_from_this(),
std::placeholders::_1)));
results.begin(),
results.end(),
boost::asio::bind_executor(
strand_,
std::bind(
&worker::on_connect,
shared_from_this(),
std::placeholders::_1)));
}
void
@ -288,17 +299,19 @@ public:
}
// Set the timer
timer_.expires_from_now(chrono::seconds(timeout));
timer_.expires_after(chrono::seconds(timeout));
// Send the HTTP request to the remote host
http::async_write(
socket_,
req_,
strand_.wrap(std::bind(
&worker::on_write,
shared_from_this(),
std::placeholders::_1,
std::placeholders::_2)));
boost::asio::bind_executor(
strand_,
std::bind(
&worker::on_write,
shared_from_this(),
std::placeholders::_1,
std::placeholders::_2)));
}
void
@ -319,18 +332,20 @@ public:
}
// Set the timer
timer_.expires_from_now(chrono::seconds(timeout));
timer_.expires_after(chrono::seconds(timeout));
// Receive the HTTP response
http::async_read(
socket_,
buffer_,
res_,
strand_.wrap(std::bind(
&worker::on_read,
shared_from_this(),
std::placeholders::_1,
std::placeholders::_2)));
boost::asio::bind_executor(
strand_,
std::bind(
&worker::on_read,
shared_from_this(),
std::placeholders::_1,
std::placeholders::_2)));
}
void
@ -400,41 +415,41 @@ int main(int argc, char* argv[])
" http-crawl 100 1\n";
return EXIT_FAILURE;
}
auto const threads = std::max<std::size_t>(1, std::atoi(argv[1]));
auto const threads = std::max<int>(1, std::atoi(argv[1]));
// The io_service is required for all I/O
boost::asio::io_service ios{1};
// The io_context is required for all I/O
boost::asio::io_context ioc{1};
// The work keeps io_service::run from returning
boost::optional<boost::asio::io_service::work> work{ios};
// The work keeps io_context::run from returning
auto work = boost::asio::make_work_guard(ioc);
// The report holds the aggregated statistics
crawl_report report{ios};
crawl_report report{ioc};
timer t;
// Create and launch the worker threads.
std::vector<std::thread> workers;
workers.reserve(threads + 1);
for(std::size_t i = 0; i < threads; ++i)
for(int i = 0; i < threads; ++i)
workers.emplace_back(
[&report]
{
// We use a separate io_service for each worker because
// We use a separate io_context for each worker because
// the asio resolver simulates asynchronous operation using
// a dedicated worker thread per io_service, and we want to
// a dedicated worker thread per io_context, and we want to
// do a lot of name resolutions in parallel.
boost::asio::io_service ios{1};
std::make_shared<worker>(report, ios)->run();
ios.run();
boost::asio::io_context ioc{1};
std::make_shared<worker>(report, ioc)->run();
ioc.run();
});
// Add another thread to run the main io_service which
// Add another thread to run the main io_context which
// is used to aggregate the statistics
workers.emplace_back(
[&ios]
[&ioc]
{
ios.run();
ioc.run();
});
// Now block until all threads exit
@ -442,11 +457,10 @@ int main(int argc, char* argv[])
{
auto& thread = workers[i];
// If this is the last thread, destroy the
// If this is the last thread, reset the
// work object so that it can return from run.
//if(&thread == &workers.back())
if(i == workers.size() - 1)
work = boost::none;
work.reset();
// Wait for the thread to exit
thread.join();

View File

@ -47,8 +47,8 @@ int main(int argc, char** argv)
auto const port = argv[2];
auto const target = argv[3];
// The io_service is required for all I/O
boost::asio::io_service ios;
// The io_context is required for all I/O
boost::asio::io_context ioc;
// The SSL context is required, and holds certificates
ssl::context ctx{ssl::context::sslv23_client};
@ -57,14 +57,14 @@ int main(int argc, char** argv)
load_root_certificates(ctx);
// These objects perform our I/O
tcp::resolver resolver{ios};
ssl::stream<tcp::socket> stream{ios, ctx};
tcp::resolver resolver{ioc};
ssl::stream<tcp::socket> stream{ioc, ctx};
// Look up the domain name
auto const lookup = resolver.resolve({host, port});
auto const results = resolver.resolve(host, port);
// Make the connection on the IP address we get from a lookup
boost::asio::connect(stream.next_layer(), lookup);
boost::asio::connect(stream.next_layer(), results.begin(), results.end());
// Perform the SSL handshake
stream.handshake(ssl::stream_base::client);

View File

@ -45,18 +45,18 @@ int main(int argc, char** argv)
auto const port = argv[2];
auto const target = argv[3];
// The io_service is required for all I/O
boost::asio::io_service ios;
// The io_context is required for all I/O
boost::asio::io_context ioc;
// These objects perform our I/O
tcp::resolver resolver{ios};
tcp::socket socket{ios};
tcp::resolver resolver{ioc};
tcp::socket socket{ioc};
// Look up the domain name
auto const lookup = resolver.resolve({host, port});
auto const results = resolver.resolve(host, port);
// Make the connection on the IP address we get from a lookup
boost::asio::connect(socket, lookup);
boost::asio::connect(socket, results.begin(), results.end());
// Set up an HTTP GET request message
http::request<http::string_body> req{http::verb::get, target, 11};

View File

@ -18,6 +18,7 @@
#include <boost/beast/core.hpp>
#include <boost/beast/http.hpp>
#include <boost/beast/version.hpp>
#include <boost/asio/bind_executor.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/ssl/stream.hpp>
#include <boost/asio/strand.hpp>
@ -244,18 +245,21 @@ class session : public std::enable_shared_from_this<session>
http::async_write(
self_.stream_,
*sp,
self_.strand_.wrap(std::bind(
&session::on_write,
self_.shared_from_this(),
std::placeholders::_1,
std::placeholders::_2,
! sp->keep_alive())));
boost::asio::bind_executor(
self_.strand_,
std::bind(
&session::on_write,
self_.shared_from_this(),
std::placeholders::_1,
std::placeholders::_2,
! sp->keep_alive())));
}
};
tcp::socket socket_;
ssl::stream<tcp::socket&> stream_;
boost::asio::io_service::strand strand_;
boost::asio::strand<
boost::asio::io_context::executor_type> strand_;
boost::beast::flat_buffer buffer_;
std::string const& doc_root_;
http::request<http::string_body> req_;
@ -271,7 +275,7 @@ public:
std::string const& doc_root)
: socket_(std::move(socket))
, stream_(socket_, ctx)
, strand_(socket_.get_io_service())
, strand_(socket_.get_executor())
, doc_root_(doc_root)
, lambda_(*this)
{
@ -284,10 +288,12 @@ public:
// Perform the SSL handshake
stream_.async_handshake(
ssl::stream_base::server,
strand_.wrap(std::bind(
&session::on_handshake,
shared_from_this(),
std::placeholders::_1)));
boost::asio::bind_executor(
strand_,
std::bind(
&session::on_handshake,
shared_from_this(),
std::placeholders::_1)));
}
void
@ -304,11 +310,13 @@ public:
{
// Read a request
http::async_read(stream_, buffer_, req_,
strand_.wrap(std::bind(
&session::on_read,
shared_from_this(),
std::placeholders::_1,
std::placeholders::_2)));
boost::asio::bind_executor(
strand_,
std::bind(
&session::on_read,
shared_from_this(),
std::placeholders::_1,
std::placeholders::_2)));
}
void
@ -359,10 +367,12 @@ public:
{
// Perform the SSL shutdown
stream_.async_shutdown(
strand_.wrap(std::bind(
&session::on_shutdown,
shared_from_this(),
std::placeholders::_1)));
boost::asio::bind_executor(
strand_,
std::bind(
&session::on_shutdown,
shared_from_this(),
std::placeholders::_1)));
}
void
@ -387,13 +397,13 @@ class listener : public std::enable_shared_from_this<listener>
public:
listener(
boost::asio::io_service& ios,
boost::asio::io_context& ioc,
ssl::context& ctx,
tcp::endpoint endpoint,
std::string const& doc_root)
: ctx_(ctx)
, acceptor_(ios)
, socket_(ios)
, acceptor_(ioc)
, socket_(ioc)
, doc_root_(doc_root)
{
boost::system::error_code ec;
@ -416,7 +426,7 @@ public:
// Start listening for connections
acceptor_.listen(
boost::asio::socket_base::max_connections, ec);
boost::asio::socket_base::max_listen_connections, ec);
if(ec)
{
fail(ec, "listen");
@ -478,13 +488,13 @@ int main(int argc, char* argv[])
" http-server-async-ssl 0.0.0.0 8080 . 1\n";
return EXIT_FAILURE;
}
auto const address = boost::asio::ip::address::from_string(argv[1]);
auto const address = boost::asio::ip::make_address(argv[1]);
auto const port = static_cast<unsigned short>(std::atoi(argv[2]));
std::string const doc_root = argv[3];
auto const threads = std::max<std::size_t>(1, std::atoi(argv[4]));
auto const threads = std::max<int>(1, std::atoi(argv[4]));
// The io_service is required for all I/O
boost::asio::io_service ios{threads};
// The io_context is required for all I/O
boost::asio::io_context ioc{threads};
// The SSL context is required, and holds certificates
ssl::context ctx{ssl::context::sslv23};
@ -494,7 +504,7 @@ int main(int argc, char* argv[])
// Create and launch a listening port
std::make_shared<listener>(
ios,
ioc,
ctx,
tcp::endpoint{address, port},
doc_root)->run();
@ -504,11 +514,11 @@ int main(int argc, char* argv[])
v.reserve(threads - 1);
for(auto i = threads - 1; i > 0; --i)
v.emplace_back(
[&ios]
[&ioc]
{
ios.run();
ioc.run();
});
ios.run();
ioc.run();
return EXIT_SUCCESS;
}

View File

@ -16,6 +16,7 @@
#include <boost/beast/core.hpp>
#include <boost/beast/http.hpp>
#include <boost/beast/version.hpp>
#include <boost/asio/bind_executor.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/strand.hpp>
#include <boost/config.hpp>
@ -240,17 +241,20 @@ class session : public std::enable_shared_from_this<session>
http::async_write(
self_.socket_,
*sp,
self_.strand_.wrap(std::bind(
&session::on_write,
self_.shared_from_this(),
std::placeholders::_1,
std::placeholders::_2,
! sp->keep_alive())));
boost::asio::bind_executor(
self_.strand_,
std::bind(
&session::on_write,
self_.shared_from_this(),
std::placeholders::_1,
std::placeholders::_2,
! sp->keep_alive())));
}
};
tcp::socket socket_;
boost::asio::io_service::strand strand_;
boost::asio::strand<
boost::asio::io_context::executor_type> strand_;
boost::beast::flat_buffer buffer_;
std::string const& doc_root_;
http::request<http::string_body> req_;
@ -264,7 +268,7 @@ public:
tcp::socket socket,
std::string const& doc_root)
: socket_(std::move(socket))
, strand_(socket_.get_io_service())
, strand_(socket_.get_executor())
, doc_root_(doc_root)
, lambda_(*this)
{
@ -282,11 +286,13 @@ public:
{
// Read a request
http::async_read(socket_, buffer_, req_,
strand_.wrap(std::bind(
&session::on_read,
shared_from_this(),
std::placeholders::_1,
std::placeholders::_2)));
boost::asio::bind_executor(
strand_,
std::bind(
&session::on_read,
shared_from_this(),
std::placeholders::_1,
std::placeholders::_2)));
}
void
@ -354,11 +360,11 @@ class listener : public std::enable_shared_from_this<listener>
public:
listener(
boost::asio::io_service& ios,
boost::asio::io_context& ioc,
tcp::endpoint endpoint,
std::string const& doc_root)
: acceptor_(ios)
, socket_(ios)
: acceptor_(ioc)
, socket_(ioc)
, doc_root_(doc_root)
{
boost::system::error_code ec;
@ -381,7 +387,7 @@ public:
// Start listening for connections
acceptor_.listen(
boost::asio::socket_base::max_connections, ec);
boost::asio::socket_base::max_listen_connections, ec);
if(ec)
{
fail(ec, "listen");
@ -442,17 +448,17 @@ int main(int argc, char* argv[])
" http-server-async 0.0.0.0 8080 . 1\n";
return EXIT_FAILURE;
}
auto const address = boost::asio::ip::address::from_string(argv[1]);
auto const address = boost::asio::ip::make_address(argv[1]);
auto const port = static_cast<unsigned short>(std::atoi(argv[2]));
std::string const doc_root = argv[3];
auto const threads = std::max<std::size_t>(1, std::atoi(argv[4]));
auto const threads = std::max<int>(1, std::atoi(argv[4]));
// The io_service is required for all I/O
boost::asio::io_service ios{threads};
// The io_context is required for all I/O
boost::asio::io_context ioc{threads};
// Create and launch a listening port
std::make_shared<listener>(
ios,
ioc,
tcp::endpoint{address, port},
doc_root)->run();
@ -461,11 +467,11 @@ int main(int argc, char* argv[])
v.reserve(threads - 1);
for(auto i = threads - 1; i > 0; --i)
v.emplace_back(
[&ios]
[&ioc]
{
ios.run();
ioc.run();
});
ios.run();
ioc.run();
return EXIT_SUCCESS;
}

View File

@ -308,7 +308,7 @@ do_session(
// Accepts incoming connections and launches the sessions
void
do_listen(
boost::asio::io_service& ios,
boost::asio::io_context& ioc,
ssl::context& ctx,
tcp::endpoint endpoint,
std::string const& doc_root,
@ -317,7 +317,7 @@ do_listen(
boost::system::error_code ec;
// Open the acceptor
tcp::acceptor acceptor(ios);
tcp::acceptor acceptor(ioc);
acceptor.open(endpoint.protocol(), ec);
if(ec)
return fail(ec, "open");
@ -328,19 +328,19 @@ do_listen(
return fail(ec, "bind");
// Start listening for connections
acceptor.listen(boost::asio::socket_base::max_connections, ec);
acceptor.listen(boost::asio::socket_base::max_listen_connections, ec);
if(ec)
return fail(ec, "listen");
for(;;)
{
tcp::socket socket(ios);
tcp::socket socket(ioc);
acceptor.async_accept(socket, yield[ec]);
if(ec)
fail(ec, "accept");
else
boost::asio::spawn(
acceptor.get_io_service(),
acceptor.get_executor().context(),
std::bind(
&do_session,
std::move(socket),
@ -361,13 +361,13 @@ int main(int argc, char* argv[])
" http-server-coro-ssl 0.0.0.0 8080 . 1\n";
return EXIT_FAILURE;
}
auto const address = boost::asio::ip::address::from_string(argv[1]);
auto const address = boost::asio::ip::make_address(argv[1]);
auto const port = static_cast<unsigned short>(std::atoi(argv[2]));
std::string const doc_root = argv[3];
auto const threads = std::max<std::size_t>(1, std::atoi(argv[4]));
auto const threads = std::max<int>(1, std::atoi(argv[4]));
// The io_service is required for all I/O
boost::asio::io_service ios{threads};
// The io_context is required for all I/O
boost::asio::io_context ioc{threads};
// The SSL context is required, and holds certificates
ssl::context ctx{ssl::context::sslv23};
@ -376,10 +376,10 @@ int main(int argc, char* argv[])
load_server_certificate(ctx);
// Spawn a listening port
boost::asio::spawn(ios,
boost::asio::spawn(ioc,
std::bind(
&do_listen,
std::ref(ios),
std::ref(ioc),
std::ref(ctx),
tcp::endpoint{address, port},
doc_root,
@ -390,11 +390,11 @@ int main(int argc, char* argv[])
v.reserve(threads - 1);
for(auto i = threads - 1; i > 0; --i)
v.emplace_back(
[&ios]
[&ioc]
{
ios.run();
ioc.run();
});
ios.run();
ioc.run();
return EXIT_SUCCESS;
}

View File

@ -293,7 +293,7 @@ do_session(
// Accepts incoming connections and launches the sessions
void
do_listen(
boost::asio::io_service& ios,
boost::asio::io_context& ioc,
tcp::endpoint endpoint,
std::string const& doc_root,
boost::asio::yield_context yield)
@ -301,7 +301,7 @@ do_listen(
boost::system::error_code ec;
// Open the acceptor
tcp::acceptor acceptor(ios);
tcp::acceptor acceptor(ioc);
acceptor.open(endpoint.protocol(), ec);
if(ec)
return fail(ec, "open");
@ -312,19 +312,19 @@ do_listen(
return fail(ec, "bind");
// Start listening for connections
acceptor.listen(boost::asio::socket_base::max_connections, ec);
acceptor.listen(boost::asio::socket_base::max_listen_connections, ec);
if(ec)
return fail(ec, "listen");
for(;;)
{
tcp::socket socket(ios);
tcp::socket socket(ioc);
acceptor.async_accept(socket, yield[ec]);
if(ec)
fail(ec, "accept");
else
boost::asio::spawn(
acceptor.get_io_service(),
acceptor.get_executor().context(),
std::bind(
&do_session,
std::move(socket),
@ -344,19 +344,19 @@ int main(int argc, char* argv[])
" http-server-coro 0.0.0.0 8080 . 1\n";
return EXIT_FAILURE;
}
auto const address = boost::asio::ip::address::from_string(argv[1]);
auto const address = boost::asio::ip::make_address(argv[1]);
auto const port = static_cast<unsigned short>(std::atoi(argv[2]));
std::string const doc_root = argv[3];
auto const threads = std::max<std::size_t>(1, std::atoi(argv[4]));
auto const threads = std::max<int>(1, std::atoi(argv[4]));
// The io_service is required for all I/O
boost::asio::io_service ios{threads};
// The io_context is required for all I/O
boost::asio::io_context ioc{threads};
// Spawn a listening port
boost::asio::spawn(ios,
boost::asio::spawn(ioc,
std::bind(
&do_listen,
std::ref(ios),
std::ref(ioc),
tcp::endpoint{address, port},
doc_root,
std::placeholders::_1));
@ -366,11 +366,11 @@ int main(int argc, char* argv[])
v.reserve(threads - 1);
for(auto i = threads - 1; i > 0; --i)
v.emplace_back(
[&ios]
[&ioc]
{
ios.run();
ioc.run();
});
ios.run();
ioc.run();
return EXIT_SUCCESS;
}

View File

@ -97,7 +97,7 @@ private:
std::string doc_root_;
// The socket for the currently connected client.
tcp::socket socket_{acceptor_.get_io_service()};
tcp::socket socket_{acceptor_.get_executor().context()};
// The buffer for performing reads
boost::beast::flat_static_buffer<8192> buffer_;
@ -110,7 +110,7 @@ private:
// The timer putting a time limit on requests.
boost::asio::basic_waitable_timer<std::chrono::steady_clock> request_deadline_{
acceptor_.get_io_service(), (std::chrono::steady_clock::time_point::max)()};
acceptor_.get_executor().context(), (std::chrono::steady_clock::time_point::max)()};
// The string-based response message.
boost::optional<http::response<http::string_body, http::basic_fields<alloc_t>>> string_response_;
@ -142,7 +142,7 @@ private:
else
{
// Request must be fully processed within 60 seconds.
request_deadline_.expires_from_now(
request_deadline_.expires_after(
std::chrono::seconds(60));
read_request();
@ -288,7 +288,7 @@ private:
void check_deadline()
{
// The deadline may have moved, so check it has really passed.
if (request_deadline_.expires_at() <= std::chrono::steady_clock::now())
if (request_deadline_.expiry() <= std::chrono::steady_clock::now())
{
// Close socket to cancel any outstanding operation.
boost::beast::error_code ec;
@ -322,14 +322,14 @@ int main(int argc, char* argv[])
return EXIT_FAILURE;
}
auto address = ip::address::from_string(argv[1]);
auto const address = boost::asio::ip::make_address(argv[1]);
unsigned short port = static_cast<unsigned short>(std::atoi(argv[2]));
std::string doc_root = argv[3];
int num_workers = std::atoi(argv[4]);
bool spin = (std::strcmp(argv[5], "spin") == 0);
boost::asio::io_service ios{1};
tcp::acceptor acceptor{ios, {address, port}};
boost::asio::io_context ioc{1};
tcp::acceptor acceptor{ioc, {address, port}};
std::list<http_worker> workers;
for (int i = 0; i < num_workers; ++i)
@ -339,9 +339,9 @@ int main(int argc, char* argv[])
}
if (spin)
for (;;) ios.poll();
for (;;) ioc.poll();
else
ios.run();
ioc.run();
}
catch (const std::exception& e)
{

View File

@ -19,6 +19,7 @@
#include <boost/beast/core.hpp>
#include <boost/beast/http.hpp>
#include <boost/beast/version.hpp>
#include <boost/asio/bind_executor.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/ssl/stream.hpp>
#include <boost/asio/strand.hpp>
@ -255,12 +256,14 @@ class session
http::async_write(
self_.derived().stream(),
*sp,
self_.strand_.wrap(std::bind(
&session::on_write,
self_.derived().shared_from_this(),
std::placeholders::_1,
std::placeholders::_2,
! sp->keep_alive())));
boost::asio::bind_executor(
self_.strand_,
std::bind(
&session::on_write,
self_.derived().shared_from_this(),
std::placeholders::_1,
std::placeholders::_2,
! sp->keep_alive())));
}
};
@ -270,19 +273,20 @@ class session
send_lambda lambda_;
protected:
boost::asio::io_service::strand strand_;
boost::asio::strand<
boost::asio::io_context::executor_type> strand_;
boost::beast::flat_buffer buffer_;
public:
// Take ownership of the buffer
explicit
session(
boost::asio::io_service& ios,
boost::asio::io_context& ioc,
boost::beast::flat_buffer buffer,
std::string const& doc_root)
: doc_root_(doc_root)
, lambda_(*this)
, strand_(ios)
, strand_(ioc.get_executor())
, buffer_(std::move(buffer))
{
}
@ -295,11 +299,13 @@ public:
derived().stream(),
buffer_,
req_,
strand_.wrap(std::bind(
&session::on_read,
derived().shared_from_this(),
std::placeholders::_1,
std::placeholders::_2)));
boost::asio::bind_executor(
strand_,
std::bind(
&session::on_read,
derived().shared_from_this(),
std::placeholders::_1,
std::placeholders::_2)));
}
void
@ -352,7 +358,8 @@ class plain_session
, public std::enable_shared_from_this<plain_session>
{
tcp::socket socket_;
boost::asio::io_service::strand strand_;
boost::asio::strand<
boost::asio::io_context::executor_type> strand_;
public:
// Create the session
@ -361,11 +368,11 @@ public:
boost::beast::flat_buffer buffer,
std::string const& doc_root)
: session<plain_session>(
socket.get_io_service(),
socket.get_executor().context(),
std::move(buffer),
doc_root)
, socket_(std::move(socket))
, strand_(socket_.get_io_service())
, strand_(socket_.get_executor())
{
}
@ -401,7 +408,8 @@ class ssl_session
{
tcp::socket socket_;
ssl::stream<tcp::socket&> stream_;
boost::asio::io_service::strand strand_;
boost::asio::strand<
boost::asio::io_context::executor_type> strand_;
public:
// Create the session
@ -411,12 +419,12 @@ public:
boost::beast::flat_buffer buffer,
std::string const& doc_root)
: session<ssl_session>(
socket.get_io_service(),
socket.get_executor().context(),
std::move(buffer),
doc_root)
, socket_(std::move(socket))
, stream_(socket_, ctx)
, strand_(stream_.get_io_service())
, strand_(stream_.get_executor())
{
}
@ -436,11 +444,13 @@ public:
stream_.async_handshake(
ssl::stream_base::server,
buffer_.data(),
strand_.wrap(std::bind(
&ssl_session::on_handshake,
shared_from_this(),
std::placeholders::_1,
std::placeholders::_2)));
boost::asio::bind_executor(
strand_,
std::bind(
&ssl_session::on_handshake,
shared_from_this(),
std::placeholders::_1,
std::placeholders::_2)));
}
void
on_handshake(
@ -461,10 +471,12 @@ public:
{
// Perform the SSL shutdown
stream_.async_shutdown(
strand_.wrap(std::bind(
&ssl_session::on_shutdown,
shared_from_this(),
std::placeholders::_1)));
boost::asio::bind_executor(
strand_,
std::bind(
&ssl_session::on_shutdown,
shared_from_this(),
std::placeholders::_1)));
}
void
@ -484,7 +496,8 @@ class detect_session : public std::enable_shared_from_this<detect_session>
{
tcp::socket socket_;
ssl::context& ctx_;
boost::asio::io_service::strand strand_;
boost::asio::strand<
boost::asio::io_context::executor_type> strand_;
std::string const& doc_root_;
boost::beast::flat_buffer buffer_;
@ -496,7 +509,7 @@ public:
std::string const& doc_root)
: socket_(std::move(socket))
, ctx_(ctx)
, strand_(socket_.get_io_service())
, strand_(socket_.get_executor())
, doc_root_(doc_root)
{
}
@ -508,11 +521,13 @@ public:
async_detect_ssl(
socket_,
buffer_,
strand_.wrap(std::bind(
&detect_session::on_detect,
shared_from_this(),
std::placeholders::_1,
std::placeholders::_2)));
boost::asio::bind_executor(
strand_,
std::bind(
&detect_session::on_detect,
shared_from_this(),
std::placeholders::_1,
std::placeholders::_2)));
}
@ -545,21 +560,22 @@ public:
class listener : public std::enable_shared_from_this<listener>
{
ssl::context& ctx_;
boost::asio::io_service::strand strand_;
boost::asio::strand<
boost::asio::io_context::executor_type> strand_;
tcp::acceptor acceptor_;
tcp::socket socket_;
std::string const& doc_root_;
public:
listener(
boost::asio::io_service& ios,
boost::asio::io_context& ioc,
ssl::context& ctx,
tcp::endpoint endpoint,
std::string const& doc_root)
: ctx_(ctx)
, strand_(ios)
, acceptor_(ios)
, socket_(ios)
, strand_(ioc.get_executor())
, acceptor_(ioc)
, socket_(ioc)
, doc_root_(doc_root)
{
boost::system::error_code ec;
@ -582,7 +598,7 @@ public:
// Start listening for connections
acceptor_.listen(
boost::asio::socket_base::max_connections, ec);
boost::asio::socket_base::max_listen_connections, ec);
if(ec)
{
fail(ec, "listen");
@ -644,13 +660,13 @@ int main(int argc, char* argv[])
" http-server-sync 0.0.0.0 8080 .\n";
return EXIT_FAILURE;
}
auto const address = boost::asio::ip::address::from_string(argv[1]);
auto const address = boost::asio::ip::make_address(argv[1]);
auto const port = static_cast<unsigned short>(std::atoi(argv[2]));
std::string const doc_root = argv[3];
auto const threads = std::max<std::size_t>(1, std::atoi(argv[4]));
auto const threads = std::max<int>(1, std::atoi(argv[4]));
// The io_service is required for all I/O
boost::asio::io_service ios{threads};
// The io_context is required for all I/O
boost::asio::io_context ioc{threads};
// The SSL context is required, and holds certificates
ssl::context ctx{ssl::context::sslv23};
@ -660,7 +676,7 @@ int main(int argc, char* argv[])
// Create and launch a listening port
std::make_shared<listener>(
ios,
ioc,
ctx,
tcp::endpoint{address, port},
doc_root)->run();
@ -670,11 +686,11 @@ int main(int argc, char* argv[])
v.reserve(threads - 1);
for(auto i = threads - 1; i > 0; --i)
v.emplace_back(
[&ios]
[&ioc]
{
ios.run();
ioc.run();
});
ios.run();
ioc.run();
return EXIT_SUCCESS;
}

View File

@ -75,7 +75,7 @@ private:
// The timer for putting a deadline on connection processing.
boost::asio::basic_waitable_timer<std::chrono::steady_clock> deadline_{
socket_.get_io_service(), std::chrono::seconds(60)};
socket_.get_executor().context(), std::chrono::seconds(60)};
// Asynchronously receive a complete request message.
void
@ -231,16 +231,16 @@ main(int argc, char* argv[])
return EXIT_FAILURE;
}
auto address = ip::address::from_string(argv[1]);
auto const address = boost::asio::ip::make_address(argv[1]);
unsigned short port = static_cast<unsigned short>(std::atoi(argv[2]));
boost::asio::io_service ios{1};
boost::asio::io_context ioc{1};
tcp::acceptor acceptor{ios, {address, port}};
tcp::socket socket{ios};
tcp::acceptor acceptor{ioc, {address, port}};
tcp::socket socket{ioc};
http_server(acceptor, socket);
ios.run();
ioc.run();
}
catch(std::exception const& e)
{

View File

@ -18,6 +18,7 @@
#include <boost/beast/core.hpp>
#include <boost/beast/http.hpp>
#include <boost/beast/version.hpp>
#include <boost/asio/bind_executor.hpp>
#include <boost/asio/coroutine.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/ssl/stream.hpp>
@ -247,18 +248,21 @@ class session
http::async_write(
self_.socket_,
*sp,
self_.strand_.wrap(std::bind(
&session::loop,
self_.shared_from_this(),
std::placeholders::_1,
std::placeholders::_2,
! sp->keep_alive())));
boost::asio::bind_executor(
self_.strand_,
std::bind(
&session::loop,
self_.shared_from_this(),
std::placeholders::_1,
std::placeholders::_2,
! sp->keep_alive())));
}
};
tcp::socket socket_;
ssl::stream<tcp::socket&> stream_;
boost::asio::io_service::strand strand_;
boost::asio::strand<
boost::asio::io_context::executor_type> strand_;
boost::beast::flat_buffer buffer_;
std::string const& doc_root_;
http::request<http::string_body> req_;
@ -274,7 +278,7 @@ public:
std::string const& doc_root)
: socket_(std::move(socket))
, stream_(socket_, ctx)
, strand_(socket_.get_io_service())
, strand_(socket_.get_executor())
, doc_root_(doc_root)
, lambda_(*this)
{
@ -300,12 +304,14 @@ public:
// Perform the SSL handshake
yield stream_.async_handshake(
ssl::stream_base::server,
strand_.wrap(std::bind(
&session::loop,
shared_from_this(),
std::placeholders::_1,
0,
false)));
boost::asio::bind_executor(
strand_,
std::bind(
&session::loop,
shared_from_this(),
std::placeholders::_1,
0,
false)));
if(ec)
return fail(ec, "handshake");
@ -313,12 +319,14 @@ public:
{
// Read a request
yield http::async_read(stream_, buffer_, req_,
strand_.wrap(std::bind(
&session::loop,
shared_from_this(),
std::placeholders::_1,
std::placeholders::_2,
false)));
boost::asio::bind_executor(
strand_,
std::bind(
&session::loop,
shared_from_this(),
std::placeholders::_1,
std::placeholders::_2,
false)));
if(ec == http::error::end_of_stream)
{
// The remote host closed the connection
@ -344,12 +352,14 @@ public:
// Perform the SSL shutdown
yield stream_.async_shutdown(
strand_.wrap(std::bind(
&session::loop,
shared_from_this(),
std::placeholders::_1,
0,
false)));
boost::asio::bind_executor(
strand_,
std::bind(
&session::loop,
shared_from_this(),
std::placeholders::_1,
0,
false)));
if(ec)
return fail(ec, "shutdown");
@ -373,13 +383,13 @@ class listener
public:
listener(
boost::asio::io_service& ios,
boost::asio::io_context& ioc,
ssl::context& ctx,
tcp::endpoint endpoint,
std::string const& doc_root)
: ctx_(ctx)
, acceptor_(ios)
, socket_(ios)
, acceptor_(ioc)
, socket_(ioc)
, doc_root_(doc_root)
{
boost::system::error_code ec;
@ -402,7 +412,7 @@ public:
// Start listening for connections
acceptor_.listen(
boost::asio::socket_base::max_connections, ec);
boost::asio::socket_base::max_listen_connections, ec);
if(ec)
{
fail(ec, "listen");
@ -464,13 +474,13 @@ int main(int argc, char* argv[])
" http-server-stackless-ssl 0.0.0.0 8080 . 1\n";
return EXIT_FAILURE;
}
auto const address = boost::asio::ip::address::from_string(argv[1]);
auto const address = boost::asio::ip::make_address(argv[1]);
auto const port = static_cast<unsigned short>(std::atoi(argv[2]));
std::string const doc_root = argv[3];
auto const threads = std::max<std::size_t>(1, std::atoi(argv[4]));
auto const threads = std::max<int>(1, std::atoi(argv[4]));
// The io_service is required for all I/O
boost::asio::io_service ios{threads};
// The io_context is required for all I/O
boost::asio::io_context ioc{threads};
// The SSL context is required, and holds certificates
ssl::context ctx{ssl::context::sslv23};
@ -480,7 +490,7 @@ int main(int argc, char* argv[])
// Create and launch a listening port
std::make_shared<listener>(
ios,
ioc,
ctx,
tcp::endpoint{address, port},
doc_root)->run();
@ -490,11 +500,11 @@ int main(int argc, char* argv[])
v.reserve(threads - 1);
for(auto i = threads - 1; i > 0; --i)
v.emplace_back(
[&ios]
[&ioc]
{
ios.run();
ioc.run();
});
ios.run();
ioc.run();
return EXIT_SUCCESS;
}

View File

@ -16,6 +16,7 @@
#include <boost/beast/core.hpp>
#include <boost/beast/http.hpp>
#include <boost/beast/version.hpp>
#include <boost/asio/bind_executor.hpp>
#include <boost/asio/coroutine.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/strand.hpp>
@ -244,17 +245,20 @@ class session
http::async_write(
self_.socket_,
*sp,
self_.strand_.wrap(std::bind(
&session::loop,
self_.shared_from_this(),
std::placeholders::_1,
std::placeholders::_2,
! sp->keep_alive())));
boost::asio::bind_executor(
self_.strand_,
std::bind(
&session::loop,
self_.shared_from_this(),
std::placeholders::_1,
std::placeholders::_2,
! sp->keep_alive())));
}
};
tcp::socket socket_;
boost::asio::io_service::strand strand_;
boost::asio::strand<
boost::asio::io_context::executor_type> strand_;
boost::beast::flat_buffer buffer_;
std::string const& doc_root_;
http::request<http::string_body> req_;
@ -268,7 +272,7 @@ public:
tcp::socket socket,
std::string const& doc_root)
: socket_(std::move(socket))
, strand_(socket_.get_io_service())
, strand_(socket_.get_executor())
, doc_root_(doc_root)
, lambda_(*this)
{
@ -295,12 +299,14 @@ public:
{
// Read a request
yield http::async_read(socket_, buffer_, req_,
strand_.wrap(std::bind(
&session::loop,
shared_from_this(),
std::placeholders::_1,
std::placeholders::_2,
false)));
boost::asio::bind_executor(
strand_,
std::bind(
&session::loop,
shared_from_this(),
std::placeholders::_1,
std::placeholders::_2,
false)));
if(ec == http::error::end_of_stream)
{
// The remote host closed the connection
@ -346,11 +352,11 @@ class listener
public:
listener(
boost::asio::io_service& ios,
boost::asio::io_context& ioc,
tcp::endpoint endpoint,
std::string const& doc_root)
: acceptor_(ios)
, socket_(ios)
: acceptor_(ioc)
, socket_(ioc)
, doc_root_(doc_root)
{
boost::system::error_code ec;
@ -372,7 +378,7 @@ public:
}
// Start listening for connections
acceptor_.listen(boost::asio::socket_base::max_connections, ec);
acceptor_.listen(boost::asio::socket_base::max_listen_connections, ec);
if(ec)
{
fail(ec, "listen");
@ -433,17 +439,17 @@ int main(int argc, char* argv[])
" http-server-stackless 0.0.0.0 8080 . 1\n";
return EXIT_FAILURE;
}
auto const address = boost::asio::ip::address::from_string(argv[1]);
auto const address = boost::asio::ip::make_address(argv[1]);
auto const port = static_cast<unsigned short>(std::atoi(argv[2]));
std::string const doc_root = argv[3];
auto const threads = std::max<std::size_t>(1, std::atoi(argv[4]));
auto const threads = std::max<int>(1, std::atoi(argv[4]));
// The io_service is required for all I/O
boost::asio::io_service ios{threads};
// The io_context is required for all I/O
boost::asio::io_context ioc{threads};
// Create and launch a listening port
std::make_shared<listener>(
ios,
ioc,
tcp::endpoint{address, port},
doc_root)->run();
@ -452,11 +458,11 @@ int main(int argc, char* argv[])
v.reserve(threads - 1);
for(auto i = threads - 1; i > 0; --i)
v.emplace_back(
[&ios]
[&ioc]
{
ios.run();
ioc.run();
});
ios.run();
ioc.run();
return EXIT_SUCCESS;
}

View File

@ -311,12 +311,12 @@ int main(int argc, char* argv[])
" http-server-sync-ssl 0.0.0.0 8080 .\n";
return EXIT_FAILURE;
}
auto const address = boost::asio::ip::address::from_string(argv[1]);
auto const address = boost::asio::ip::make_address(argv[1]);
auto const port = static_cast<unsigned short>(std::atoi(argv[2]));
std::string const doc_root = argv[3];
// The io_service is required for all I/O
boost::asio::io_service ios{1};
// The io_context is required for all I/O
boost::asio::io_context ioc{1};
// The SSL context is required, and holds certificates
ssl::context ctx{ssl::context::sslv23};
@ -325,11 +325,11 @@ int main(int argc, char* argv[])
load_server_certificate(ctx);
// The acceptor receives incoming connections
tcp::acceptor acceptor{ios, {address, port}};
tcp::acceptor acceptor{ioc, {address, port}};
for(;;)
{
// This will receive the new connection
tcp::socket socket{ios};
tcp::socket socket{ioc};
// Block until we get a connection
acceptor.accept(socket);

View File

@ -298,19 +298,19 @@ int main(int argc, char* argv[])
" http-server-sync 0.0.0.0 8080 .\n";
return EXIT_FAILURE;
}
auto const address = boost::asio::ip::address::from_string(argv[1]);
auto const address = boost::asio::ip::make_address(argv[1]);
auto const port = static_cast<unsigned short>(std::atoi(argv[2]));
std::string const doc_root = argv[3];
// The io_service is required for all I/O
boost::asio::io_service ios{1};
// The io_context is required for all I/O
boost::asio::io_context ioc{1};
// The acceptor receives incoming connections
tcp::acceptor acceptor{ios, {address, port}};
tcp::acceptor acceptor{ioc, {address, port}};
for(;;)
{
// This will receive the new connection
tcp::socket socket{ios};
tcp::socket socket{ioc};
// Block until we get a connection
acceptor.accept(socket);

View File

@ -50,11 +50,11 @@ class session : public std::enable_shared_from_this<session>
std::string text_;
public:
// Resolver and socket require an io_service
// Resolver and socket require an io_context
explicit
session(boost::asio::io_service& ios, ssl::context& ctx)
: resolver_(ios)
, ws_(ios, ctx)
session(boost::asio::io_context& ioc, ssl::context& ctx)
: resolver_(ioc)
, ws_(ioc, ctx)
{
}
@ -70,7 +70,9 @@ public:
text_ = text;
// Look up the domain name
resolver_.async_resolve({host, port},
resolver_.async_resolve(
host,
port,
std::bind(
&session::on_resolve,
shared_from_this(),
@ -81,7 +83,7 @@ public:
void
on_resolve(
boost::system::error_code ec,
tcp::resolver::iterator result)
tcp::resolver::results_type results)
{
if(ec)
return fail(ec, "resolve");
@ -89,7 +91,8 @@ public:
// Make the connection on the IP address we get from a lookup
boost::asio::async_connect(
ws_.next_layer().next_layer(),
result,
results.begin(),
results.end(),
std::bind(
&session::on_connect,
shared_from_this(),
@ -209,8 +212,8 @@ int main(int argc, char** argv)
auto const port = argv[2];
auto const text = argv[3];
// The io_service is required for all I/O
boost::asio::io_service ios;
// The io_context is required for all I/O
boost::asio::io_context ioc;
// The SSL context is required, and holds certificates
ssl::context ctx{ssl::context::sslv23_client};
@ -219,11 +222,11 @@ int main(int argc, char** argv)
load_root_certificates(ctx);
// Launch the asynchronous operation
std::make_shared<session>(ios, ctx)->run(host, port, text);
std::make_shared<session>(ioc, ctx)->run(host, port, text);
// Run the I/O service. The call will return when
// the get operation is complete.
ios.run();
ioc.run();
return EXIT_SUCCESS;
}

View File

@ -45,11 +45,11 @@ class session : public std::enable_shared_from_this<session>
std::string text_;
public:
// Resolver and socket require an io_service
// Resolver and socket require an io_context
explicit
session(boost::asio::io_service& ios)
: resolver_(ios)
, ws_(ios)
session(boost::asio::io_context& ioc)
: resolver_(ioc)
, ws_(ioc)
{
}
@ -65,7 +65,9 @@ public:
text_ = text;
// Look up the domain name
resolver_.async_resolve({host, port},
resolver_.async_resolve(
host,
port,
std::bind(
&session::on_resolve,
shared_from_this(),
@ -76,7 +78,7 @@ public:
void
on_resolve(
boost::system::error_code ec,
tcp::resolver::iterator result)
tcp::resolver::results_type results)
{
if(ec)
return fail(ec, "resolve");
@ -84,7 +86,8 @@ public:
// Make the connection on the IP address we get from a lookup
boost::asio::async_connect(
ws_.next_layer(),
result,
results.begin(),
results.end(),
std::bind(
&session::on_connect,
shared_from_this(),
@ -189,15 +192,15 @@ int main(int argc, char** argv)
auto const port = argv[2];
auto const text = argv[3];
// The io_service is required for all I/O
boost::asio::io_service ios;
// The io_context is required for all I/O
boost::asio::io_context ioc;
// Launch the asynchronous operation
std::make_shared<session>(ios)->run(host, port, text);
std::make_shared<session>(ioc)->run(host, port, text);
// Run the I/O service. The call will return when
// the get operation is complete.
ios.run();
ioc.run();
return EXIT_SUCCESS;
}

View File

@ -46,23 +46,23 @@ do_session(
std::string const& host,
std::string const& port,
std::string const& text,
boost::asio::io_service& ios,
boost::asio::io_context& ioc,
ssl::context& ctx,
boost::asio::yield_context yield)
{
boost::system::error_code ec;
// These objects perform our I/O
tcp::resolver resolver{ios};
websocket::stream<ssl::stream<tcp::socket>> ws{ios, ctx};
tcp::resolver resolver{ioc};
websocket::stream<ssl::stream<tcp::socket>> ws{ioc, ctx};
// Look up the domain name
auto const lookup = resolver.async_resolve({host, port}, yield[ec]);
auto const results = resolver.async_resolve(host, port, yield[ec]);
if(ec)
return fail(ec, "resolve");
// Make the connection on the IP address we get from a lookup
boost::asio::async_connect(ws.next_layer().next_layer(), lookup, yield[ec]);
boost::asio::async_connect(ws.next_layer().next_layer(), results.begin(), results.end(), yield[ec]);
if(ec)
return fail(ec, "connect");
@ -117,8 +117,8 @@ int main(int argc, char** argv)
auto const port = argv[2];
auto const text = argv[3];
// The io_service is required for all I/O
boost::asio::io_service ios;
// The io_context is required for all I/O
boost::asio::io_context ioc;
// The SSL context is required, and holds certificates
ssl::context ctx{ssl::context::sslv23_client};
@ -127,18 +127,18 @@ int main(int argc, char** argv)
load_root_certificates(ctx);
// Launch the asynchronous operation
boost::asio::spawn(ios, std::bind(
boost::asio::spawn(ioc, std::bind(
&do_session,
std::string(host),
std::string(port),
std::string(text),
std::ref(ios),
std::ref(ioc),
std::ref(ctx),
std::placeholders::_1));
// Run the I/O service. The call will return when
// the get operation is complete.
ios.run();
ioc.run();
return EXIT_SUCCESS;
}

View File

@ -41,22 +41,22 @@ do_session(
std::string const& host,
std::string const& port,
std::string const& text,
boost::asio::io_service& ios,
boost::asio::io_context& ioc,
boost::asio::yield_context yield)
{
boost::system::error_code ec;
// These objects perform our I/O
tcp::resolver resolver{ios};
websocket::stream<tcp::socket> ws{ios};
tcp::resolver resolver{ioc};
websocket::stream<tcp::socket> ws{ioc};
// Look up the domain name
auto const lookup = resolver.async_resolve({host, port}, yield[ec]);
auto const results = resolver.async_resolve(host, port, yield[ec]);
if(ec)
return fail(ec, "resolve");
// Make the connection on the IP address we get from a lookup
boost::asio::async_connect(ws.next_layer(), lookup, yield[ec]);
boost::asio::async_connect(ws.next_layer(), results.begin(), results.end(), yield[ec]);
if(ec)
return fail(ec, "connect");
@ -106,21 +106,21 @@ int main(int argc, char** argv)
auto const port = argv[2];
auto const text = argv[3];
// The io_service is required for all I/O
boost::asio::io_service ios;
// The io_context is required for all I/O
boost::asio::io_context ioc;
// Launch the asynchronous operation
boost::asio::spawn(ios, std::bind(
boost::asio::spawn(ioc, std::bind(
&do_session,
std::string(host),
std::string(port),
std::string(text),
std::ref(ios),
std::ref(ioc),
std::placeholders::_1));
// Run the I/O service. The call will return when
// the get operation is complete.
ios.run();
ioc.run();
return EXIT_SUCCESS;
}

View File

@ -47,8 +47,8 @@ int main(int argc, char** argv)
auto const port = argv[2];
auto const text = argv[3];
// The io_service is required for all I/O
boost::asio::io_service ios;
// The io_context is required for all I/O
boost::asio::io_context ioc;
// The SSL context is required, and holds certificates
ssl::context ctx{ssl::context::sslv23_client};
@ -57,14 +57,14 @@ int main(int argc, char** argv)
load_root_certificates(ctx);
// These objects perform our I/O
tcp::resolver resolver{ios};
websocket::stream<ssl::stream<tcp::socket>> ws{ios, ctx};
tcp::resolver resolver{ioc};
websocket::stream<ssl::stream<tcp::socket>> ws{ioc, ctx};
// Look up the domain name
auto const lookup = resolver.resolve({host, port});
auto const results = resolver.resolve(host, port);
// Make the connection on the IP address we get from a lookup
boost::asio::connect(ws.next_layer().next_layer(), lookup);
boost::asio::connect(ws.next_layer().next_layer(), results.begin(), results.end());
// Perform the SSL handshake
ws.next_layer().handshake(ssl::stream_base::client);

View File

@ -44,18 +44,18 @@ int main(int argc, char** argv)
auto const port = argv[2];
auto const text = argv[3];
// The io_service is required for all I/O
boost::asio::io_service ios;
// The io_context is required for all I/O
boost::asio::io_context ioc;
// These objects perform our I/O
tcp::resolver resolver{ios};
websocket::stream<tcp::socket> ws{ios};
tcp::resolver resolver{ioc};
websocket::stream<tcp::socket> ws{ioc};
// Look up the domain name
auto const lookup = resolver.resolve({host, port});
auto const results = resolver.resolve(host, port);
// Make the connection on the IP address we get from a lookup
boost::asio::connect(ws.next_layer(), lookup);
boost::asio::connect(ws.next_layer(), results.begin(), results.end());
// Perform the websocket handshake
ws.handshake(host, "/");

View File

@ -18,6 +18,7 @@
#include <boost/beast/core.hpp>
#include <boost/beast/websocket.hpp>
#include <boost/beast/websocket/ssl.hpp>
#include <boost/asio/bind_executor.hpp>
#include <boost/asio/strand.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/ssl/stream.hpp>
@ -48,7 +49,8 @@ class session : public std::enable_shared_from_this<session>
{
tcp::socket socket_;
websocket::stream<ssl::stream<tcp::socket&>> ws_;
boost::asio::io_service::strand strand_;
boost::asio::strand<
boost::asio::io_context::executor_type> strand_;
boost::beast::multi_buffer buffer_;
public:
@ -56,7 +58,7 @@ public:
session(tcp::socket socket, ssl::context& ctx)
: socket_(std::move(socket))
, ws_(socket_, ctx)
, strand_(ws_.get_io_service())
, strand_(ws_.get_executor())
{
}
@ -67,10 +69,12 @@ public:
// Perform the SSL handshake
ws_.next_layer().async_handshake(
ssl::stream_base::server,
strand_.wrap(std::bind(
&session::on_handshake,
shared_from_this(),
std::placeholders::_1)));
boost::asio::bind_executor(
strand_,
std::bind(
&session::on_handshake,
shared_from_this(),
std::placeholders::_1)));
}
void
@ -81,10 +85,12 @@ public:
// Accept the websocket handshake
ws_.async_accept(
strand_.wrap(std::bind(
&session::on_accept,
shared_from_this(),
std::placeholders::_1)));
boost::asio::bind_executor(
strand_,
std::bind(
&session::on_accept,
shared_from_this(),
std::placeholders::_1)));
}
void
@ -103,11 +109,13 @@ public:
// Read a message into our buffer
ws_.async_read(
buffer_,
strand_.wrap(std::bind(
&session::on_read,
shared_from_this(),
std::placeholders::_1,
std::placeholders::_2)));
boost::asio::bind_executor(
strand_,
std::bind(
&session::on_read,
shared_from_this(),
std::placeholders::_1,
std::placeholders::_2)));
}
void
@ -128,11 +136,13 @@ public:
ws_.text(ws_.got_text());
ws_.async_write(
buffer_.data(),
strand_.wrap(std::bind(
&session::on_write,
shared_from_this(),
std::placeholders::_1,
std::placeholders::_2)));
boost::asio::bind_executor(
strand_,
std::bind(
&session::on_write,
shared_from_this(),
std::placeholders::_1,
std::placeholders::_2)));
}
void
@ -164,12 +174,12 @@ class listener : public std::enable_shared_from_this<listener>
public:
listener(
boost::asio::io_service& ios,
boost::asio::io_context& ioc,
ssl::context& ctx,
tcp::endpoint endpoint)
: ctx_(ctx)
, acceptor_(ios)
, socket_(ios)
, acceptor_(ioc)
, socket_(ioc)
{
boost::system::error_code ec;
@ -191,7 +201,7 @@ public:
// Start listening for connections
acceptor_.listen(
boost::asio::socket_base::max_connections, ec);
boost::asio::socket_base::max_listen_connections, ec);
if(ec)
{
fail(ec, "listen");
@ -250,12 +260,12 @@ int main(int argc, char* argv[])
" websocket-server-async-ssl 0.0.0.0 8080 1\n";
return EXIT_FAILURE;
}
auto const address = boost::asio::ip::address::from_string(argv[1]);
auto const address = boost::asio::ip::make_address(argv[1]);
auto const port = static_cast<unsigned short>(std::atoi(argv[2]));
auto const threads = std::max<std::size_t>(1, std::atoi(argv[3]));
auto const threads = std::max<int>(1, std::atoi(argv[3]));
// The io_service is required for all I/O
boost::asio::io_service ios{threads};
// The io_context is required for all I/O
boost::asio::io_context ioc{threads};
// The SSL context is required, and holds certificates
ssl::context ctx{ssl::context::sslv23};
@ -264,18 +274,18 @@ int main(int argc, char* argv[])
load_server_certificate(ctx);
// Create and launch a listening port
std::make_shared<listener>(ios, ctx, tcp::endpoint{address, port})->run();
std::make_shared<listener>(ioc, ctx, tcp::endpoint{address, port})->run();
// Run the I/O service on the requested number of threads
std::vector<std::thread> v;
v.reserve(threads - 1);
for(auto i = threads - 1; i > 0; --i)
v.emplace_back(
[&ios]
[&ioc]
{
ios.run();
ioc.run();
});
ios.run();
ioc.run();
return EXIT_SUCCESS;
}

View File

@ -15,6 +15,7 @@
#include <boost/beast/core.hpp>
#include <boost/beast/websocket.hpp>
#include <boost/asio/bind_executor.hpp>
#include <boost/asio/strand.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <algorithm>
@ -42,7 +43,8 @@ fail(boost::system::error_code ec, char const* what)
class session : public std::enable_shared_from_this<session>
{
websocket::stream<tcp::socket> ws_;
boost::asio::io_service::strand strand_;
boost::asio::strand<
boost::asio::io_context::executor_type> strand_;
boost::beast::multi_buffer buffer_;
public:
@ -50,7 +52,7 @@ public:
explicit
session(tcp::socket socket)
: ws_(std::move(socket))
, strand_(ws_.get_io_service())
, strand_(ws_.get_executor())
{
}
@ -60,10 +62,12 @@ public:
{
// Accept the websocket handshake
ws_.async_accept(
strand_.wrap(std::bind(
&session::on_accept,
shared_from_this(),
std::placeholders::_1)));
boost::asio::bind_executor(
strand_,
std::bind(
&session::on_accept,
shared_from_this(),
std::placeholders::_1)));
}
void
@ -82,11 +86,13 @@ public:
// Read a message into our buffer
ws_.async_read(
buffer_,
strand_.wrap(std::bind(
&session::on_read,
shared_from_this(),
std::placeholders::_1,
std::placeholders::_2)));
boost::asio::bind_executor(
strand_,
std::bind(
&session::on_read,
shared_from_this(),
std::placeholders::_1,
std::placeholders::_2)));
}
void
@ -107,11 +113,13 @@ public:
ws_.text(ws_.got_text());
ws_.async_write(
buffer_.data(),
strand_.wrap(std::bind(
&session::on_write,
shared_from_this(),
std::placeholders::_1,
std::placeholders::_2)));
boost::asio::bind_executor(
strand_,
std::bind(
&session::on_write,
shared_from_this(),
std::placeholders::_1,
std::placeholders::_2)));
}
void
@ -142,10 +150,10 @@ class listener : public std::enable_shared_from_this<listener>
public:
listener(
boost::asio::io_service& ios,
boost::asio::io_context& ioc,
tcp::endpoint endpoint)
: acceptor_(ios)
, socket_(ios)
: acceptor_(ioc)
, socket_(ioc)
{
boost::system::error_code ec;
@ -167,7 +175,7 @@ public:
// Start listening for connections
acceptor_.listen(
boost::asio::socket_base::max_connections, ec);
boost::asio::socket_base::max_listen_connections, ec);
if(ec)
{
fail(ec, "listen");
@ -226,26 +234,26 @@ int main(int argc, char* argv[])
" websocket-server-async 0.0.0.0 8080 1\n";
return EXIT_FAILURE;
}
auto const address = boost::asio::ip::address::from_string(argv[1]);
auto const address = boost::asio::ip::make_address(argv[1]);
auto const port = static_cast<unsigned short>(std::atoi(argv[2]));
auto const threads = std::max<std::size_t>(1, std::atoi(argv[3]));
auto const threads = std::max<int>(1, std::atoi(argv[3]));
// The io_service is required for all I/O
boost::asio::io_service ios{threads};
// The io_context is required for all I/O
boost::asio::io_context ioc{threads};
// Create and launch a listening port
std::make_shared<listener>(ios, tcp::endpoint{address, port})->run();
std::make_shared<listener>(ioc, tcp::endpoint{address, port})->run();
// Run the I/O service on the requested number of threads
std::vector<std::thread> v;
v.reserve(threads - 1);
for(auto i = threads - 1; i > 0; --i)
v.emplace_back(
[&ios]
[&ioc]
{
ios.run();
ioc.run();
});
ios.run();
ioc.run();
return EXIT_SUCCESS;
}

View File

@ -93,7 +93,7 @@ do_session(
// Accepts incoming connections and launches the sessions
void
do_listen(
boost::asio::io_service& ios,
boost::asio::io_context& ioc,
ssl::context& ctx,
tcp::endpoint endpoint,
boost::asio::yield_context yield)
@ -101,7 +101,7 @@ do_listen(
boost::system::error_code ec;
// Open the acceptor
tcp::acceptor acceptor(ios);
tcp::acceptor acceptor(ioc);
acceptor.open(endpoint.protocol(), ec);
if(ec)
return fail(ec, "open");
@ -112,19 +112,19 @@ do_listen(
return fail(ec, "bind");
// Start listening for connections
acceptor.listen(boost::asio::socket_base::max_connections, ec);
acceptor.listen(boost::asio::socket_base::max_listen_connections, ec);
if(ec)
return fail(ec, "listen");
for(;;)
{
tcp::socket socket(ios);
tcp::socket socket(ioc);
acceptor.async_accept(socket, yield[ec]);
if(ec)
fail(ec, "accept");
else
boost::asio::spawn(
acceptor.get_io_service(),
acceptor.get_executor().context(),
std::bind(
&do_session,
std::move(socket),
@ -144,12 +144,12 @@ int main(int argc, char* argv[])
" websocket-server-coro-ssl 0.0.0.0 8080 1\n";
return EXIT_FAILURE;
}
auto const address = boost::asio::ip::address::from_string(argv[1]);
auto const address = boost::asio::ip::make_address(argv[1]);
auto const port = static_cast<unsigned short>(std::atoi(argv[2]));
auto const threads = std::max<std::size_t>(1, std::atoi(argv[3]));
auto const threads = std::max<int>(1, std::atoi(argv[3]));
// The io_service is required for all I/O
boost::asio::io_service ios{threads};
// The io_context is required for all I/O
boost::asio::io_context ioc{threads};
// The SSL context is required, and holds certificates
ssl::context ctx{ssl::context::sslv23};
@ -158,10 +158,10 @@ int main(int argc, char* argv[])
load_server_certificate(ctx);
// Spawn a listening port
boost::asio::spawn(ios,
boost::asio::spawn(ioc,
std::bind(
&do_listen,
std::ref(ios),
std::ref(ioc),
std::ref(ctx),
tcp::endpoint{address, port},
std::placeholders::_1));
@ -171,11 +171,11 @@ int main(int argc, char* argv[])
v.reserve(threads - 1);
for(auto i = threads - 1; i > 0; --i)
v.emplace_back(
[&ios]
[&ioc]
{
ios.run();
ioc.run();
});
ios.run();
ioc.run();
return EXIT_SUCCESS;
}

View File

@ -80,14 +80,14 @@ do_session(tcp::socket& socket, boost::asio::yield_context yield)
// Accepts incoming connections and launches the sessions
void
do_listen(
boost::asio::io_service& ios,
boost::asio::io_context& ioc,
tcp::endpoint endpoint,
boost::asio::yield_context yield)
{
boost::system::error_code ec;
// Open the acceptor
tcp::acceptor acceptor(ios);
tcp::acceptor acceptor(ioc);
acceptor.open(endpoint.protocol(), ec);
if(ec)
return fail(ec, "open");
@ -98,19 +98,19 @@ do_listen(
return fail(ec, "bind");
// Start listening for connections
acceptor.listen(boost::asio::socket_base::max_connections, ec);
acceptor.listen(boost::asio::socket_base::max_listen_connections, ec);
if(ec)
return fail(ec, "listen");
for(;;)
{
tcp::socket socket(ios);
tcp::socket socket(ioc);
acceptor.async_accept(socket, yield[ec]);
if(ec)
fail(ec, "accept");
else
boost::asio::spawn(
acceptor.get_io_service(),
acceptor.get_executor().context(),
std::bind(
&do_session,
std::move(socket),
@ -129,18 +129,18 @@ int main(int argc, char* argv[])
" websocket-server-coro 0.0.0.0 8080 1\n";
return EXIT_FAILURE;
}
auto const address = boost::asio::ip::address::from_string(argv[1]);
auto const address = boost::asio::ip::make_address(argv[1]);
auto const port = static_cast<unsigned short>(std::atoi(argv[2]));
auto const threads = std::max<std::size_t>(1, std::atoi(argv[3]));
auto const threads = std::max<int>(1, std::atoi(argv[3]));
// The io_service is required for all I/O
boost::asio::io_service ios{threads};
// The io_context is required for all I/O
boost::asio::io_context ioc{threads};
// Spawn a listening port
boost::asio::spawn(ios,
boost::asio::spawn(ioc,
std::bind(
&do_listen,
std::ref(ios),
std::ref(ioc),
tcp::endpoint{address, port},
std::placeholders::_1));
@ -149,11 +149,11 @@ int main(int argc, char* argv[])
v.reserve(threads - 1);
for(auto i = threads - 1; i > 0; --i)
v.emplace_back(
[&ios]
[&ioc]
{
ios.run();
ioc.run();
});
ios.run();
ioc.run();
return EXIT_SUCCESS;
}

View File

@ -30,6 +30,7 @@
#include <boost/beast/http.hpp>
#include <boost/beast/version.hpp>
#include <boost/beast/websocket.hpp>
#include <boost/asio/bind_executor.hpp>
#include <boost/asio/spawn.hpp>
#include <boost/asio/strand.hpp>
#include <boost/asio/ip/tcp.hpp>
@ -113,14 +114,14 @@ do_sync_session(tcp::socket& socket)
void
do_sync_listen(
boost::asio::io_service& ios,
boost::asio::io_context& ioc,
tcp::endpoint endpoint)
{
boost::system::error_code ec;
tcp::acceptor acceptor{ios, endpoint};
tcp::acceptor acceptor{ioc, endpoint};
for(;;)
{
tcp::socket socket{ios};
tcp::socket socket{ioc};
acceptor.accept(socket, ec);
if(ec)
@ -138,7 +139,8 @@ do_sync_listen(
class async_session : public std::enable_shared_from_this<async_session>
{
websocket::stream<tcp::socket> ws_;
boost::asio::io_service::strand strand_;
boost::asio::strand<
boost::asio::io_context::executor_type> strand_;
boost::beast::multi_buffer buffer_;
public:
@ -146,7 +148,7 @@ public:
explicit
async_session(tcp::socket socket)
: ws_(std::move(socket))
, strand_(ws_.get_io_service())
, strand_(ws_.get_executor())
{
setup_stream(ws_);
}
@ -162,10 +164,12 @@ public:
res.set(http::field::server,
"Boost.Beast.async/" + std::to_string(BOOST_BEAST_VERSION));
},
strand_.wrap(std::bind(
&async_session::on_accept,
shared_from_this(),
std::placeholders::_1)));
boost::asio::bind_executor(
strand_,
std::bind(
&async_session::on_accept,
shared_from_this(),
std::placeholders::_1)));
}
void
@ -184,11 +188,13 @@ public:
// Read a message into our buffer
ws_.async_read(
buffer_,
strand_.wrap(std::bind(
&async_session::on_read,
shared_from_this(),
std::placeholders::_1,
std::placeholders::_2)));
boost::asio::bind_executor(
strand_,
std::bind(
&async_session::on_read,
shared_from_this(),
std::placeholders::_1,
std::placeholders::_2)));
}
void
@ -209,11 +215,13 @@ public:
ws_.text(ws_.got_text());
ws_.async_write(
buffer_.data(),
strand_.wrap(std::bind(
&async_session::on_write,
shared_from_this(),
std::placeholders::_1,
std::placeholders::_2)));
boost::asio::bind_executor(
strand_,
std::bind(
&async_session::on_write,
shared_from_this(),
std::placeholders::_1,
std::placeholders::_2)));
}
void
@ -237,17 +245,18 @@ public:
// Accepts incoming connections and launches the sessions
class async_listener : public std::enable_shared_from_this<async_listener>
{
boost::asio::io_service::strand strand_;
boost::asio::strand<
boost::asio::io_context::executor_type> strand_;
tcp::acceptor acceptor_;
tcp::socket socket_;
public:
async_listener(
boost::asio::io_service& ios,
boost::asio::io_context& ioc,
tcp::endpoint endpoint)
: strand_(ios)
, acceptor_(ios)
, socket_(ios)
: strand_(ioc.get_executor())
, acceptor_(ioc)
, socket_(ioc)
{
boost::system::error_code ec;
@ -269,7 +278,7 @@ public:
// Start listening for connections
acceptor_.listen(
boost::asio::socket_base::max_connections, ec);
boost::asio::socket_base::max_listen_connections, ec);
if(ec)
{
fail(ec, "listen");
@ -291,10 +300,12 @@ public:
{
acceptor_.async_accept(
socket_,
strand_.wrap(std::bind(
&async_listener::on_accept,
shared_from_this(),
std::placeholders::_1)));
boost::asio::bind_executor(
strand_,
std::bind(
&async_listener::on_accept,
shared_from_this(),
std::placeholders::_1)));
}
void
@ -354,13 +365,13 @@ do_coro_session(tcp::socket& socket, boost::asio::yield_context yield)
void
do_coro_listen(
boost::asio::io_service& ios,
boost::asio::io_context& ioc,
tcp::endpoint endpoint,
boost::asio::yield_context yield)
{
boost::system::error_code ec;
tcp::acceptor acceptor(ios);
tcp::acceptor acceptor(ioc);
acceptor.open(endpoint.protocol(), ec);
if(ec)
return fail(ec, "open");
@ -369,13 +380,13 @@ do_coro_listen(
if(ec)
return fail(ec, "bind");
acceptor.listen(boost::asio::socket_base::max_connections, ec);
acceptor.listen(boost::asio::socket_base::max_listen_connections, ec);
if(ec)
return fail(ec, "listen");
for(;;)
{
tcp::socket socket(ios);
tcp::socket socket(ioc);
acceptor.async_accept(socket, yield[ec]);
if(ec)
@ -385,7 +396,7 @@ do_coro_listen(
}
boost::asio::spawn(
acceptor.get_io_service(),
acceptor.get_executor().context(),
std::bind(
&do_coro_session,
std::move(socket),
@ -410,17 +421,17 @@ int main(int argc, char* argv[])
" starting-port+2 for coroutine.\n";
return EXIT_FAILURE;
}
auto const address = boost::asio::ip::address::from_string(argv[1]);
auto const address = boost::asio::ip::make_address(argv[1]);
auto const port = static_cast<unsigned short>(std::atoi(argv[2]));
auto const threads = std::max<std::size_t>(1, std::atoi(argv[3]));
auto const threads = std::max<int>(1, std::atoi(argv[3]));
// The io_service is required for all I/O
boost::asio::io_service ios{threads};
// The io_context is required for all I/O
boost::asio::io_context ioc{threads};
// Create sync port
std::thread(std::bind(
&do_sync_listen,
std::ref(ios),
std::ref(ioc),
tcp::endpoint{
address,
static_cast<unsigned short>(port + 0u)}
@ -428,16 +439,16 @@ int main(int argc, char* argv[])
// Create async port
std::make_shared<async_listener>(
ios,
ioc,
tcp::endpoint{
address,
static_cast<unsigned short>(port + 1u)})->run();
// Create coro port
boost::asio::spawn(ios,
boost::asio::spawn(ioc,
std::bind(
&do_coro_listen,
std::ref(ios),
std::ref(ioc),
tcp::endpoint{
address,
static_cast<unsigned short>(port + 2u)},
@ -448,11 +459,11 @@ int main(int argc, char* argv[])
v.reserve(threads - 1);
for(auto i = threads - 1; i > 0; --i)
v.emplace_back(
[&ios]
[&ioc]
{
ios.run();
ioc.run();
});
ios.run();
ioc.run();
return EXIT_SUCCESS;
}

View File

@ -18,6 +18,7 @@
#include <boost/beast/core.hpp>
#include <boost/beast/websocket.hpp>
#include <boost/beast/websocket/ssl.hpp>
#include <boost/asio/bind_executor.hpp>
#include <boost/asio/coroutine.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/ssl/stream.hpp>
@ -51,7 +52,8 @@ class session
{
tcp::socket socket_;
websocket::stream<ssl::stream<tcp::socket&>> ws_;
boost::asio::io_service::strand strand_;
boost::asio::strand<
boost::asio::io_context::executor_type> strand_;
boost::beast::multi_buffer buffer_;
public:
@ -59,7 +61,7 @@ public:
session(tcp::socket socket, ssl::context& ctx)
: socket_(std::move(socket))
, ws_(socket_, ctx)
, strand_(ws_.get_io_service())
, strand_(ws_.get_executor())
{
}
@ -83,21 +85,25 @@ public:
// Perform the SSL handshake
yield ws_.next_layer().async_handshake(
ssl::stream_base::server,
strand_.wrap(std::bind(
&session::loop,
shared_from_this(),
std::placeholders::_1,
0)));
boost::asio::bind_executor(
strand_,
std::bind(
&session::loop,
shared_from_this(),
std::placeholders::_1,
0)));
if(ec)
return fail(ec, "handshake");
// Accept the websocket handshake
yield ws_.async_accept(
strand_.wrap(std::bind(
&session::loop,
shared_from_this(),
std::placeholders::_1,
0)));
boost::asio::bind_executor(
strand_,
std::bind(
&session::loop,
shared_from_this(),
std::placeholders::_1,
0)));
if(ec)
return fail(ec, "accept");
@ -106,11 +112,13 @@ public:
// Read a message into our buffer
yield ws_.async_read(
buffer_,
strand_.wrap(std::bind(
&session::loop,
shared_from_this(),
std::placeholders::_1,
std::placeholders::_2)));
boost::asio::bind_executor(
strand_,
std::bind(
&session::loop,
shared_from_this(),
std::placeholders::_1,
std::placeholders::_2)));
if(ec == websocket::error::closed)
{
// This indicates that the session was closed
@ -123,11 +131,13 @@ public:
ws_.text(ws_.got_text());
yield ws_.async_write(
buffer_.data(),
strand_.wrap(std::bind(
&session::loop,
shared_from_this(),
std::placeholders::_1,
std::placeholders::_2)));
boost::asio::bind_executor(
strand_,
std::bind(
&session::loop,
shared_from_this(),
std::placeholders::_1,
std::placeholders::_2)));
if(ec)
return fail(ec, "write");
@ -152,12 +162,12 @@ class listener
public:
listener(
boost::asio::io_service& ios,
boost::asio::io_context& ioc,
ssl::context& ctx,
tcp::endpoint endpoint)
: ctx_(ctx)
, acceptor_(ios)
, socket_(ios)
, acceptor_(ioc)
, socket_(ioc)
{
boost::system::error_code ec;
@ -179,7 +189,7 @@ public:
// Start listening for connections
acceptor_.listen(
boost::asio::socket_base::max_connections, ec);
boost::asio::socket_base::max_listen_connections, ec);
if(ec)
{
fail(ec, "listen");
@ -238,12 +248,12 @@ int main(int argc, char* argv[])
" websocket-server-async-ssl 0.0.0.0 8080 1\n";
return EXIT_FAILURE;
}
auto const address = boost::asio::ip::address::from_string(argv[1]);
auto const address = boost::asio::ip::make_address(argv[1]);
auto const port = static_cast<unsigned short>(std::atoi(argv[2]));
auto const threads = std::max<std::size_t>(1, std::atoi(argv[3]));
auto const threads = std::max<int>(1, std::atoi(argv[3]));
// The io_service is required for all I/O
boost::asio::io_service ios{threads};
// The io_context is required for all I/O
boost::asio::io_context ioc{threads};
// The SSL context is required, and holds certificates
ssl::context ctx{ssl::context::sslv23};
@ -252,18 +262,18 @@ int main(int argc, char* argv[])
load_server_certificate(ctx);
// Create and launch a listening port
std::make_shared<listener>(ios, ctx, tcp::endpoint{address, port})->run();
std::make_shared<listener>(ioc, ctx, tcp::endpoint{address, port})->run();
// Run the I/O service on the requested number of threads
std::vector<std::thread> v;
v.reserve(threads - 1);
for(auto i = threads - 1; i > 0; --i)
v.emplace_back(
[&ios]
[&ioc]
{
ios.run();
ioc.run();
});
ios.run();
ioc.run();
return EXIT_SUCCESS;
}

View File

@ -15,6 +15,7 @@
#include <boost/beast/core.hpp>
#include <boost/beast/websocket.hpp>
#include <boost/asio/bind_executor.hpp>
#include <boost/asio/coroutine.hpp>
#include <boost/asio/strand.hpp>
#include <boost/asio/ip/tcp.hpp>
@ -45,7 +46,8 @@ class session
, public std::enable_shared_from_this<session>
{
websocket::stream<tcp::socket> ws_;
boost::asio::io_service::strand strand_;
boost::asio::strand<
boost::asio::io_context::executor_type> strand_;
boost::beast::multi_buffer buffer_;
public:
@ -53,7 +55,7 @@ public:
explicit
session(tcp::socket socket)
: ws_(std::move(socket))
, strand_(ws_.get_io_service())
, strand_(ws_.get_executor())
{
}
@ -75,11 +77,13 @@ public:
{
// Accept the websocket handshake
yield ws_.async_accept(
strand_.wrap(std::bind(
&session::loop,
shared_from_this(),
std::placeholders::_1,
0)));
boost::asio::bind_executor(
strand_,
std::bind(
&session::loop,
shared_from_this(),
std::placeholders::_1,
0)));
if(ec)
return fail(ec, "accept");
@ -88,11 +92,13 @@ public:
// Read a message into our buffer
yield ws_.async_read(
buffer_,
strand_.wrap(std::bind(
&session::loop,
shared_from_this(),
std::placeholders::_1,
std::placeholders::_2)));
boost::asio::bind_executor(
strand_,
std::bind(
&session::loop,
shared_from_this(),
std::placeholders::_1,
std::placeholders::_2)));
if(ec == websocket::error::closed)
{
// This indicates that the session was closed
@ -105,11 +111,13 @@ public:
ws_.text(ws_.got_text());
yield ws_.async_write(
buffer_.data(),
strand_.wrap(std::bind(
&session::loop,
shared_from_this(),
std::placeholders::_1,
std::placeholders::_2)));
boost::asio::bind_executor(
strand_,
std::bind(
&session::loop,
shared_from_this(),
std::placeholders::_1,
std::placeholders::_2)));
if(ec)
return fail(ec, "write");
@ -133,10 +141,10 @@ class listener
public:
listener(
boost::asio::io_service& ios,
boost::asio::io_context& ioc,
tcp::endpoint endpoint)
: acceptor_(ios)
, socket_(ios)
: acceptor_(ioc)
, socket_(ioc)
{
boost::system::error_code ec;
@ -158,7 +166,7 @@ public:
// Start listening for connections
acceptor_.listen(
boost::asio::socket_base::max_connections, ec);
boost::asio::socket_base::max_listen_connections, ec);
if(ec)
{
fail(ec, "listen");
@ -217,26 +225,26 @@ int main(int argc, char* argv[])
" websocket-server-stackless 0.0.0.0 8080 1\n";
return EXIT_FAILURE;
}
auto const address = boost::asio::ip::address::from_string(argv[1]);
auto const address = boost::asio::ip::make_address(argv[1]);
auto const port = static_cast<unsigned short>(std::atoi(argv[2]));
auto const threads = std::max<std::size_t>(1, std::atoi(argv[3]));
auto const threads = std::max<int>(1, std::atoi(argv[3]));
// The io_service is required for all I/O
boost::asio::io_service ios{threads};
// The io_context is required for all I/O
boost::asio::io_context ioc{threads};
// Create and launch a listening port
std::make_shared<listener>(ios, tcp::endpoint{address, port})->run();
std::make_shared<listener>(ioc, tcp::endpoint{address, port})->run();
// Run the I/O service on the requested number of threads
std::vector<std::thread> v;
v.reserve(threads - 1);
for(auto i = threads - 1; i > 0; --i)
v.emplace_back(
[&ios]
[&ioc]
{
ios.run();
ioc.run();
});
ios.run();
ioc.run();
return EXIT_SUCCESS;
}

View File

@ -87,11 +87,11 @@ int main(int argc, char* argv[])
" websocket-server-sync-ssl 0.0.0.0 8080\n";
return EXIT_FAILURE;
}
auto const address = boost::asio::ip::address::from_string(argv[1]);
auto const address = boost::asio::ip::make_address(argv[1]);
auto const port = static_cast<unsigned short>(std::atoi(argv[2]));
// The io_service is required for all I/O
boost::asio::io_service ios{1};
// The io_context is required for all I/O
boost::asio::io_context ioc{1};
// The SSL context is required, and holds certificates
ssl::context ctx{ssl::context::sslv23};
@ -100,11 +100,11 @@ int main(int argc, char* argv[])
load_server_certificate(ctx);
// The acceptor receives incoming connections
tcp::acceptor acceptor{ios, {address, port}};
tcp::acceptor acceptor{ioc, {address, port}};
for(;;)
{
// This will receive the new connection
tcp::socket socket{ios};
tcp::socket socket{ioc};
// Block until we get a connection
acceptor.accept(socket);

View File

@ -79,18 +79,18 @@ int main(int argc, char* argv[])
" websocket-server-sync 0.0.0.0 8080\n";
return EXIT_FAILURE;
}
auto const address = boost::asio::ip::address::from_string(argv[1]);
auto const address = boost::asio::ip::make_address(argv[1]);
auto const port = static_cast<unsigned short>(std::atoi(argv[2]));
// The io_service is required for all I/O
boost::asio::io_service ios{1};
// The io_context is required for all I/O
boost::asio::io_context ioc{1};
// The acceptor receives incoming connections
tcp::acceptor acceptor{ios, {address, port}};
tcp::acceptor acceptor{ioc, {address, port}};
for(;;)
{
// This will receive the new connection
tcp::socket socket{ios};
tcp::socket socket{ioc};
// Block until we get a connection
acceptor.accept(socket);

View File

@ -12,7 +12,6 @@
#include <boost/beast/core/detail/config.hpp>
#include <boost/beast/core/async_result.hpp>
#include <boost/beast/core/bind_handler.hpp>
#include <boost/beast/core/buffered_read_stream.hpp>
#include <boost/beast/core/buffers_adapter.hpp>
@ -28,7 +27,6 @@
#include <boost/beast/core/file_win32.hpp>
#include <boost/beast/core/flat_buffer.hpp>
#include <boost/beast/core/flat_static_buffer.hpp>
#include <boost/beast/core/handler_alloc.hpp>
#include <boost/beast/core/handler_ptr.hpp>
#include <boost/beast/core/multi_buffer.hpp>
#include <boost/beast/core/ostream.hpp>

View File

@ -1,209 +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_ASYNC_COMPLETION_HPP
#define BOOST_BEAST_ASYNC_COMPLETION_HPP
#include <boost/beast/core/detail/config.hpp>
#include <boost/beast/core/type_traits.hpp>
#include <boost/asio/async_result.hpp>
#include <boost/asio/handler_type.hpp>
#include <type_traits>
#include <utility>
namespace boost {
namespace beast {
/** An interface for customising the behaviour of an asynchronous initiation function.
This class is used for determining:
@li The concrete completion handler type to be called at the end of the
asynchronous operation;
@li the initiating function return type; and
@li how the return value of the initiating function is obtained.
The trait allows the handler and return types to be determined at the point
where the specific completion handler signature is known.
This template takes advantage of specializations of both
`boost::asio::async_result` and `boost::asio::handler_type` for user-defined
completion token types. The primary template assumes that the
@b CompletionToken is the completion handler.
@par Example
The example shows how to define an asynchronous initiation function
whose completion handler receives an error code:
@code
template<
class AsyncStream, // A stream supporting asynchronous read and write
class Handler // The handler to call with signature void(error_code)
>
async_return_type< // This provides the return type customization
Handler, void(error_code)>
do_async(
AsyncStream& stream, // The stream to work on
Handler&& handler) // Could be an rvalue or const reference
{
// Make sure we have an async stream
static_assert(is_async_stream<AsyncWriteStream>::value,
"AsyncStream requirements not met");
// This helper converts the handler into the real handler type
async_completion<WriteHandler, void(error_code)> init{handler};
... // Create and invoke the composed operation
// This provides the return value and executor customization
return init.result.get();
}
@endcode
@see @ref async_completion, @ref async_return_type, @ref handler_type
*/
template<class CompletionToken, class Signature>
class async_result
{
BOOST_STATIC_ASSERT(
! std::is_reference<CompletionToken>::value);
boost::asio::async_result<typename
boost::asio::handler_type<CompletionToken,
Signature>::type> impl_;
async_result(async_result const&) = delete;
async_result& operator=(async_result const&) = delete;
public:
/// The concrete completion handler type for the specific signature.
using completion_handler_type =
typename boost::asio::handler_type<
CompletionToken, Signature>::type;
/// The return type of the initiating function.
using return_type =
typename boost::asio::async_result<
completion_handler_type>::type;
/** Construct an async result from a given handler.
When using a specalised async_result, the constructor has
an opportunity to initialise some state associated with the
completion handler, which is then returned from the initiating
function.
*/
explicit
async_result(completion_handler_type& h)
: impl_(h)
{
}
/// Obtain the value to be returned from the initiating function.
return_type
get()
{
return impl_.get();
}
};
/** Helper for customizing the return type of asynchronous initiation functions.
This class template is used to transform caller-provided completion
handlers in calls to asynchronous initiation functions. The transformation
allows customization of the return type of the initiating function, and the
function signature of the final handler.
Example:
@code
...
template<class CompletionToken>
typename async_completion<CompletionToken, void(error_code)>::result_type
async_initfn(..., CompletionToken&& handler)
{
async_completion<CompletionToken, void(error_code)> completion{handler};
...
return completion.result.get();
}
@endcode
@tparam CompletionToken Specifies the model used to obtain the result of
the asynchronous operation.
@tparam Signature The call signature for the completion handler type invoked
on completion of the asynchronous operation.
@note See <a href="http://cplusplus.github.io/networking-ts/draft.pdf">
Working Draft, C++ Extensions for Networking</a>
@see @ref async_return_type, @ref handler_type
*/
template<class CompletionToken, class Signature>
struct async_completion
{
/** The type of the final handler called by the asynchronous initiation function.
Objects of this type will be callable with the specified signature.
*/
using completion_handler_type = typename async_result<
typename std::decay<CompletionToken>::type,
Signature>::completion_handler_type;
/** Constructor
The constructor creates the concrete completion handler and
makes the link between the handler and the asynchronous
result.
@param token The completion token. If this is a regular completion
handler, copies may be made as needed. If the handler is movable,
it may also be moved.
*/
explicit
async_completion(CompletionToken& token)
: completion_handler(static_cast<typename std::conditional<
std::is_same<CompletionToken, completion_handler_type>::value,
completion_handler_type&, CompletionToken&&>::type>(token))
, result(completion_handler)
{
// CompletionToken is not invokable with the given signature
static_assert(is_completion_handler<
completion_handler_type, Signature>::value,
"CompletionToken requirements not met: signature mismatch");
}
/// The final completion handler, callable with the specified signature.
typename std::conditional<std::is_same<
CompletionToken, completion_handler_type>::value,
completion_handler_type&,
completion_handler_type
>::type completion_handler;
/// The return value of the asynchronous initiation function.
async_result<typename std::decay<
CompletionToken>::type, Signature> result;
};
template<class CompletionToken, typename Signature>
using handler_type = typename beast::async_result<
typename std::decay<CompletionToken>::type,
Signature>::completion_handler_type;
template<class CompletionToken, typename Signature>
using async_return_type = typename beast::async_result<
typename std::decay<CompletionToken>::type,
Signature>::return_type;
} // beast
} // boost
#endif

View File

@ -27,12 +27,12 @@ namespace beast {
placeholders present in the list of bound arguments. Parameters
which are not matched to placeholders are silently discarded.
The passed handler and arguments are forwarded into the returned
handler, which provides the same `io_service` execution guarantees
handler, which provides the same `io_context` execution guarantees
as the original handler.
Unlike `boost::asio::io_service::wrap`, the returned handler can
be used in a subsequent call to `boost::asio::io_service::post`
instead of `boost::asio::io_service::dispatch`, to ensure that
Unlike `boost::asio::io_context::wrap`, the returned handler can
be used in a subsequent call to `boost::asio::io_context::post`
instead of `boost::asio::io_context::dispatch`, to ensure that
the handler will not be invoked immediately by the calling
function.
@ -43,7 +43,8 @@ namespace beast {
void
signal_aborted(AsyncReadStream& stream, ReadHandler&& handler)
{
stream.get_io_service().post(
boost::asio::post(
stream.get_executor(),
bind_handler(std::forward<ReadHandler>(handler),
boost::asio::error::operation_aborted, 0));
}

View File

@ -11,12 +11,12 @@
#define BOOST_BEAST_BUFFERED_READ_STREAM_HPP
#include <boost/beast/core/detail/config.hpp>
#include <boost/beast/core/async_result.hpp>
#include <boost/beast/core/error.hpp>
#include <boost/beast/core/multi_buffer.hpp>
#include <boost/beast/core/type_traits.hpp>
#include <boost/asio/async_result.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/asio/io_context.hpp>
#include <cstdint>
#include <utility>
@ -91,7 +91,8 @@ namespace beast {
template<class Stream, class DynamicBuffer>
class buffered_read_stream
{
static_assert(is_dynamic_buffer<DynamicBuffer>::value,
static_assert(
boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
"DynamicBuffer requirements not met");
template<class Buffers, class Handler>
@ -163,11 +164,29 @@ public:
return next_layer_.lowest_layer();
}
/// Get the io_service associated with the object.
boost::asio::io_service&
get_io_service()
/** Get the executor associated with the object.
This function may be used to obtain the executor object that the stream
uses to dispatch handlers for asynchronous operations.
@return A copy of the executor that stream will use to dispatch handlers.
@note This function participates in overload resolution only if
`NextLayer` has a member function named `get_executor`.
*/
#if BOOST_BEAST_DOXYGEN
implementation_defined
#else
template<
class T = next_layer_type,
class = typename std::enable_if<
has_get_executor<next_layer_type>::value>::type>
auto
#endif
get_executor() noexcept ->
decltype(std::declval<T&>().get_executor())
{
return next_layer_.get_io_service();
return next_layer_.get_executor();
}
/** Access the internal buffer.
@ -265,14 +284,11 @@ public:
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 MutableBufferSequence, class ReadHandler>
#if BOOST_BEAST_DOXYGEN
void_or_deduced
#else
async_return_type<ReadHandler, void(error_code)>
#endif
BOOST_ASIO_INITFN_RESULT_TYPE(
ReadHandler, void(error_code))
async_read_some(MutableBufferSequence const& buffers,
ReadHandler&& handler);
@ -340,14 +356,11 @@ public:
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 ConstBufferSequence, class WriteHandler>
#if BOOST_BEAST_DOXYGEN
void_or_deduced
#else
async_return_type<WriteHandler, void(error_code)>
#endif
BOOST_ASIO_INITFN_RESULT_TYPE(
WriteHandler, void(error_code))
async_write_some(ConstBufferSequence const& buffers,
WriteHandler&& handler);
};

View File

@ -35,10 +35,12 @@ namespace beast {
template<class MutableBufferSequence>
class buffers_adapter
{
static_assert(is_mutable_buffer_sequence<MutableBufferSequence>::value,
static_assert(boost::asio::is_mutable_buffer_sequence<MutableBufferSequence>::value,
"MutableBufferSequence requirements not met");
using iter_type = typename MutableBufferSequence::const_iterator;
using iter_type = typename
detail::buffer_sequence_iterator<
MutableBufferSequence>::type;
MutableBufferSequence bs_;
iter_type begin_;

View File

@ -34,8 +34,8 @@ class buffers_prefix_view
using buffers_type = typename
std::decay<BufferSequence>::type;
using iter_type =
typename buffers_type::const_iterator;
using iter_type = typename
detail::buffer_sequence_iterator<buffers_type>::type;
BufferSequence bs_;
std::size_t size_;
@ -141,10 +141,8 @@ boost::asio::const_buffer
buffers_prefix(std::size_t size,
boost::asio::const_buffer buffer)
{
using boost::asio::buffer_cast;
using boost::asio::buffer_size;
return { buffer_cast<void const*>(buffer),
(std::min)(size, buffer_size(buffer)) };
return {buffer.data(),
(std::min)(size, buffer.size())};
}
/** Returns a prefix of a mutable buffer.
@ -166,10 +164,8 @@ boost::asio::mutable_buffer
buffers_prefix(std::size_t size,
boost::asio::mutable_buffer buffer)
{
using boost::asio::buffer_cast;
using boost::asio::buffer_size;
return {buffer_cast<void*>(buffer),
(std::min)(size, buffer_size(buffer))};
return {buffer.data(),
(std::min)(size, buffer.size())};
}
/** Returns a prefix of a buffer sequence.
@ -203,8 +199,8 @@ typename std::enable_if<
buffers_prefix(std::size_t size, BufferSequence const& buffers)
{
static_assert(
is_const_buffer_sequence<BufferSequence>::value ||
is_mutable_buffer_sequence<BufferSequence>::value,
boost::asio::is_const_buffer_sequence<BufferSequence>::value ||
boost::asio::is_mutable_buffer_sequence<BufferSequence>::value,
"BufferSequence requirements not met");
return buffers_prefix_view<BufferSequence>(size, buffers);
}
@ -221,13 +217,14 @@ buffers_prefix(std::size_t size, BufferSequence const& buffers)
*/
template<class BufferSequence>
typename std::conditional<
is_mutable_buffer_sequence<BufferSequence>::value,
boost::asio::is_mutable_buffer_sequence<BufferSequence>::value,
boost::asio::mutable_buffer,
boost::asio::const_buffer>::type
buffers_front(BufferSequence const& buffers)
{
auto const first = buffers.begin();
if(first == buffers.end())
auto const first =
boost::asio::buffer_sequence_begin(buffers);
if(first == boost::asio::buffer_sequence_end(buffers))
return {};
return *first;
}

View File

@ -12,11 +12,11 @@
#include <boost/beast/core/detail/config.hpp>
#include <boost/beast/core/detail/in_place_init.hpp>
#include <boost/beast/core/detail/type_traits.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/optional.hpp>
#include <cstdint>
#include <iterator>
#include <type_traits>
#include <utility>
namespace boost {
@ -57,8 +57,8 @@ class buffers_suffix
using buffers_type =
typename std::decay<BufferSequence>::type;
using iter_type =
typename buffers_type::const_iterator;
using iter_type = typename
detail::buffer_sequence_iterator<buffers_type>::type;
BufferSequence bs_;
iter_type begin_;
@ -67,7 +67,9 @@ class buffers_suffix
template<class Deduced>
buffers_suffix(Deduced&& other, std::size_t dist)
: bs_(std::forward<Deduced>(other).bs_)
, begin_(std::next(bs_.begin(), dist))
, begin_(std::next(
boost::asio::buffer_sequence_begin(bs_),
dist))
, skip_(other.skip_)
{
}

View File

@ -11,6 +11,7 @@
#define BOOST_BEAST_BUFFERS_TO_STRING_HPP
#include <boost/beast/core/detail/config.hpp>
#include <boost/beast/core/detail/type_traits.hpp>
#include <boost/asio/buffer.hpp>
#include <string>
@ -45,10 +46,10 @@ buffers_to_string(ConstBufferSequence const& buffers)
{
std::string result;
result.reserve(boost::asio::buffer_size(buffers));
for(boost::asio::const_buffer buffer : buffers)
result.append(
boost::asio::buffer_cast<char const*>(buffer),
boost::asio::buffer_size(buffer));
for(boost::asio::const_buffer buffer :
detail::buffers_range(buffers))
result.append(reinterpret_cast<
char const*>(buffer.data()), buffer.size());
return result;
}

View File

@ -11,9 +11,9 @@
#define BOOST_BEAST_DETAIL_BIND_HANDLER_HPP
#include <boost/beast/core/detail/integer_sequence.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/core/ignore_unused.hpp>
#include <functional>
#include <utility>
@ -24,13 +24,17 @@ namespace detail {
/* Nullary handler that calls Handler with bound arguments.
The bound handler provides the same io_service execution
The bound handler provides the same io_context execution
guarantees as the original handler.
*/
template<class Handler, class... Args>
class bound_handler
{
private:
// Can't friend partial specializations,
// so we just friend the whole thing.
template<class T, class Executor>
friend struct boost::asio::associated_executor;
using args_type = std::tuple<
typename std::decay<Args>::type...>;
@ -101,6 +105,9 @@ private:
public:
using result_type = void;
using allocator_type =
boost::asio::associated_allocator_t<Handler>;
bound_handler(bound_handler&&) = default;
bound_handler(bound_handler const&) = default;
@ -113,6 +120,20 @@ public:
{
}
allocator_type
get_allocator() const noexcept
{
return boost::asio::get_associated_allocator(h_);
}
friend
bool
asio_handler_is_continuation(bound_handler* h)
{
using boost::asio::asio_handler_is_continuation;
return asio_handler_is_continuation(std::addressof(h->h_));
}
template<class... Values>
void
operator()(Values&&... values)
@ -132,48 +153,30 @@ public:
std::forward<Values>(values)...),
index_sequence_for<Args...>());
}
friend
void*
asio_handler_allocate(
std::size_t size, bound_handler* h)
{
using boost::asio::asio_handler_allocate;
return asio_handler_allocate(
size, std::addressof(h->h_));
}
friend
void
asio_handler_deallocate(
void* p, std::size_t size, bound_handler* h)
{
using boost::asio::asio_handler_deallocate;
asio_handler_deallocate(
p, size, std::addressof(h->h_));
}
friend
bool
asio_handler_is_continuation(bound_handler* h)
{
using boost::asio::asio_handler_is_continuation;
return asio_handler_is_continuation(std::addressof(h->h_));
}
template<class F>
friend
void
asio_handler_invoke(F&& f, bound_handler* h)
{
using boost::asio::asio_handler_invoke;
asio_handler_invoke(
f, std::addressof(h->h_));
}
};
} // detail
} // beast
namespace asio {
template<class Handler, class... Args, class Executor>
struct associated_executor<
beast::detail::bound_handler<Handler, Args...>, Executor>
{
using type = typename
associated_executor<Handler, Executor>::type;
static
type
get(beast::detail::bound_handler<Handler, Args...> const& h,
Executor const& ex = Executor()) noexcept
{
return associated_executor<
Handler, Executor>::get(h.h_, ex);
}
};
} // asio
} // boost
namespace std {

View File

@ -11,6 +11,7 @@
#define BOOST_BEAST_DETAIL_BUFFERS_REF_HPP
#include <boost/beast/core/type_traits.hpp>
#include <iterator>
namespace boost {
namespace beast {
@ -23,11 +24,11 @@ class buffers_ref
BufferSequence const* buffers_;
public:
using value_type =
typename BufferSequence::value_type;
using const_iterator = typename
buffer_sequence_iterator<BufferSequence>::type;
using const_iterator =
typename BufferSequence::const_iterator;
using value_type = typename std::iterator_traits<
const_iterator>::value_type;
buffers_ref(buffers_ref const&) = default;
buffers_ref& operator=(buffers_ref const&) = default;
@ -41,13 +42,13 @@ public:
const_iterator
begin() const
{
return buffers_->begin();
return boost::asio::buffer_sequence_begin(*buffers_);
}
const_iterator
end() const
{
return buffers_->end();
return boost::asio::buffer_sequence_end(*buffers_);
}
};

View File

@ -10,8 +10,10 @@
#ifndef BOOST_BEAST_DETAIL_OSTREAM_HPP
#define BOOST_BEAST_DETAIL_OSTREAM_HPP
#include <boost/asio/buffer.hpp>
#include <boost/beast/core/buffers_prefix.hpp>
#include <boost/beast/core/read_size.hpp>
#include <boost/beast/core/detail/type_traits.hpp>
#include <boost/asio/buffer.hpp>
#include <memory>
#include <iosfwd>
#include <streambuf>
@ -46,11 +48,10 @@ std::ostream&
operator<<(std::ostream& os,
buffers_helper<Buffers> const& v)
{
using boost::asio::buffer_cast;
using boost::asio::buffer_size;
for(boost::asio::const_buffer b : v.b_)
os.write(buffer_cast<char const*>(b),
buffer_size(b));
for(auto b : buffers_range(v.b_))
os.write(
reinterpret_cast<char const*>(b.data()),
b.size());
return os;
}
@ -130,14 +131,12 @@ private:
void
prepare()
{
using boost::asio::buffer_cast;
using boost::asio::buffer_size;
auto mbs = buf_.prepare(
auto bs = buf_.prepare(
read_size_or_throw(buf_, max_size));
auto const mb = *mbs.begin();
auto const p = buffer_cast<CharT*>(mb);
auto const b = buffers_front(bs);
auto const p = reinterpret_cast<CharT*>(b.data());
this->setp(p,
p + buffer_size(mb) / sizeof(CharT) - 1);
p + b.size() / sizeof(CharT) - 1);
}
void
@ -211,14 +210,12 @@ private:
void
prepare()
{
using boost::asio::buffer_cast;
using boost::asio::buffer_size;
auto mbs = buf_.prepare(
auto bs = buf_.prepare(
read_size_or_throw(buf_, max_size));
auto const mb = *mbs.begin();
auto const p = buffer_cast<CharT*>(mb);
auto const b = buffers_front(bs);
auto const p = reinterpret_cast<CharT*>(b.data());
this->setp(p,
p + buffer_size(mb) / sizeof(CharT) - 1);
p + b.size() / sizeof(CharT) - 1);
}
void

View File

@ -12,38 +12,12 @@
#include <boost/beast/core/error.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/asio/io_service.hpp>
#include <iterator>
#include <tuple>
#include <type_traits>
#include <string>
#include <utility>
// A few workarounds to keep things working
namespace boost {
namespace asio {
// for has_get_io_service
class io_service;
// for is_dynamic_buffer
template<class Allocator>
class basic_streambuf;
namespace detail {
// for is_buffer_sequence
template<class Buffer, class Buffers>
class consuming_buffers;
} // detail
} // asio
} // boost
//------------------------------------------------------------------------------
namespace boost {
namespace beast {
namespace detail {
@ -281,57 +255,17 @@ using ConstBufferSequence =
using MutableBufferSequence =
BufferSequence<boost::asio::mutable_buffer>;
template<class T, class B, class = void>
struct is_buffer_sequence : std::false_type {};
template<class T, class B>
struct is_buffer_sequence<T, B, void_t<decltype(
std::declval<typename T::value_type>(),
std::declval<typename T::const_iterator&>() =
std::declval<T const&>().begin(),
std::declval<typename T::const_iterator&>() =
std::declval<T const&>().end(),
(void)0)>> : std::integral_constant<bool,
std::is_convertible<typename T::value_type, B>::value &&
#if 0
std::is_base_of<std::bidirectional_iterator_tag,
typename std::iterator_traits<
typename T::const_iterator>::iterator_category>::value
#else
// workaround:
// boost::asio::detail::consuming_buffers::const_iterator
// is not bidirectional
std::is_base_of<std::forward_iterator_tag,
typename std::iterator_traits<
typename T::const_iterator>::iterator_category>::value
#endif
>
{
};
#if 0
// workaround:
// boost::asio::detail::consuming_buffers::const_iterator
// is not bidirectional
template<class Buffer, class Buffers, class B>
struct is_buffer_sequence<
boost::asio::detail::consuming_buffers<Buffer, Buffers>>
: std::true_type
{
};
#endif
template<class B1, class... Bn>
struct is_all_const_buffer_sequence
: std::integral_constant<bool,
is_buffer_sequence<B1, boost::asio::const_buffer>::value &&
boost::asio::is_const_buffer_sequence<B1>::value &&
is_all_const_buffer_sequence<Bn...>::value>
{
};
template<class B1>
struct is_all_const_buffer_sequence<B1>
: is_buffer_sequence<B1, boost::asio::const_buffer>
template<class B>
struct is_all_const_buffer_sequence<B>
: boost::asio::is_const_buffer_sequence<B>
{
};
@ -346,6 +280,14 @@ struct common_buffers_type
boost::asio::const_buffer>::type;
};
template<class B>
struct buffer_sequence_iterator
{
using type = decltype(
boost::asio::buffer_sequence_begin(
std::declval<B const&>()));
};
// Types that meet the requirements,
// for use with std::declval only.
struct StreamHandler
@ -356,6 +298,54 @@ struct StreamHandler
using ReadHandler = StreamHandler;
using WriteHandler = StreamHandler;
template<class Buffers>
class buffers_range_adapter
{
Buffers const& b_;
public:
using value_type = typename std::conditional<
std::is_convertible<typename std::iterator_traits<
typename buffer_sequence_iterator<Buffers>::type>::value_type,
boost::asio::const_buffer>::value,
boost::asio::const_buffer,
boost::asio::mutable_buffer>::type;
/* VFALCO This isn't right, because range-for will pick up the iterator's
value_type which might not be const_buffer or mutable_buffer. We
need to declare our own iterator wrapper that converts the underlying
iterator's value_type to const_buffer or mutable_buffer so that
range-for sees one of those types.
*/
using const_iterator = typename
buffer_sequence_iterator<Buffers>::type;
explicit
buffers_range_adapter(Buffers const& b)
: b_(b)
{
}
const_iterator
begin() const noexcept
{
return boost::asio::buffer_sequence_begin(b_);
}
const_iterator
end() const noexcept
{
return boost::asio::buffer_sequence_end(b_);
}
};
template<class Buffers>
buffers_range_adapter<Buffers>
buffers_range(Buffers const& buffers)
{
return buffers_range_adapter<Buffers>{buffers};
}
} // detail
} // beast
} // boost

View File

@ -84,10 +84,10 @@ public:
using allocator_type = Allocator;
/// The type used to represent the input sequence as a list of buffers.
using const_buffers_type = boost::asio::mutable_buffers_1;
using const_buffers_type = boost::asio::mutable_buffer;
/// The type used to represent the output sequence as a list of buffers.
using mutable_buffers_type = boost::asio::mutable_buffers_1;
using mutable_buffers_type = boost::asio::mutable_buffer;
/// Destructor
~basic_flat_buffer();

View File

@ -52,13 +52,13 @@ public:
This buffer sequence is guaranteed to have length 1.
*/
using const_buffers_type = boost::asio::mutable_buffers_1;
using const_buffers_type = boost::asio::mutable_buffer;
/** The type used to represent the output sequence as a list of buffers.
This buffer sequence is guaranteed to have length 1.
*/
using mutable_buffers_type = boost::asio::mutable_buffers_1;
using mutable_buffers_type = boost::asio::mutable_buffer;
/** Constructor

View File

@ -1,162 +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_HANDLER_ALLOC_HPP
#define BOOST_BEAST_HANDLER_ALLOC_HPP
#include <boost/beast/core/detail/config.hpp>
#include <boost/asio/handler_alloc_hook.hpp>
#include <boost/config.hpp>
#include <cstddef>
#include <cstdlib>
#include <memory>
#include <type_traits>
#include <utility>
namespace boost {
namespace beast {
// Guidance from
// http://howardhinnant.github.io/allocator_boilerplate.html
/** An allocator that uses handler customizations.
This allocator uses the handler customizations `asio_handler_allocate`
and `asio_handler_deallocate` to manage memory. It meets the requirements
of @b Allocator and can be used anywhere a `std::allocator` is
accepted.
@tparam T The type of objects allocated by the allocator.
@tparam Handler The type of handler.
@note Memory allocated by this allocator must be freed before
the handler is invoked or undefined behavior results. This behavior
is described as the "deallocate before invocation" Asio guarantee.
*/
#if BOOST_BEAST_DOXYGEN
template<class T, class Handler>
class handler_alloc;
#else
template<class T, class Handler>
class handler_alloc
{
private:
// We want a partial template specialization as a friend
// but that isn't allowed so we friend all versions. This
// should produce a compile error if Handler is not
// constructible from H.
//
template<class U, class H>
friend class handler_alloc;
Handler& h_;
public:
using value_type = T;
using is_always_equal = std::true_type;
using pointer = T*;
using reference = T&;
using const_pointer = T const*;
using const_reference = T const&;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
template<class U>
struct rebind
{
using other = handler_alloc<U, Handler>;
};
handler_alloc() = delete;
handler_alloc(handler_alloc&&) = default;
handler_alloc(handler_alloc const&) = default;
handler_alloc& operator=(handler_alloc&&) = default;
handler_alloc& operator=(handler_alloc const&) = default;
/** Construct the allocator.
A reference of the handler is stored. The handler must
remain valid for at least the lifetime of the allocator.
*/
explicit
handler_alloc(Handler& h)
: h_(h)
{
}
/// Copy constructor
template<class U>
handler_alloc(
handler_alloc<U, Handler> const& other)
: h_(other.h_)
{
}
value_type*
allocate(size_type n)
{
auto const size = n * sizeof(T);
using boost::asio::asio_handler_allocate;
return static_cast<value_type*>(
asio_handler_allocate(size, std::addressof(h_)));
}
void
deallocate(value_type* p, size_type n)
{
auto const size = n * sizeof(T);
using boost::asio::asio_handler_deallocate;
asio_handler_deallocate(p, size, std::addressof(h_));
}
//#if BOOST_WORKAROUND(BOOST_GCC, < 60000) // Works, but too coarse
#if defined(BOOST_LIBSTDCXX_VERSION) && BOOST_LIBSTDCXX_VERSION < 60000
template<class U, class... Args>
void
construct(U* ptr, Args&&... args)
{
::new((void*)ptr) U(std::forward<Args>(args)...);
}
template<class U>
void
destroy(U* ptr)
{
ptr->~U();
}
#endif
template<class U>
friend
bool
operator==(
handler_alloc const&,
handler_alloc<U, Handler> const&)
{
return true;
}
template<class U>
friend
bool
operator!=(
handler_alloc const& lhs,
handler_alloc<U, Handler> const& rhs)
{
return ! (lhs == rhs);
}
};
#endif
} // beast
} // boost
#endif

View File

@ -16,9 +16,10 @@
#include <boost/beast/core/read_size.hpp>
#include <boost/beast/core/type_traits.hpp>
#include <boost/beast/core/detail/config.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/asio/post.hpp>
#include <boost/throw_exception.hpp>
namespace boost {
@ -48,28 +49,28 @@ public:
{
}
using allocator_type =
boost::asio::associated_allocator_t<Handler>;
allocator_type
get_allocator() const noexcept
{
return boost::asio::get_associated_allocator(h_);
}
using executor_type = boost::asio::associated_executor_t<
Handler, decltype(s_.get_executor())>;
executor_type get_executor() const noexcept
{
return boost::asio::get_associated_executor(
h_, s_.get_executor());
}
void
operator()(error_code const& ec,
std::size_t bytes_transferred);
friend
void* asio_handler_allocate(
std::size_t size, read_some_op* op)
{
using boost::asio::asio_handler_allocate;
return asio_handler_allocate(
size, std::addressof(op->h_));
}
friend
void asio_handler_deallocate(
void* p, std::size_t size, read_some_op* op)
{
using boost::asio::asio_handler_deallocate;
asio_handler_deallocate(
p, size, std::addressof(op->h_));
}
friend
bool asio_handler_is_continuation(read_some_op* op)
{
@ -77,14 +78,6 @@ public:
return asio_handler_is_continuation(
std::addressof(op->h_));
}
template<class Function>
friend
void asio_handler_invoke(Function&& f, read_some_op* op)
{
using boost::asio::asio_handler_invoke;
asio_handler_invoke(f, std::addressof(op->h_));
}
};
template<class Stream, class DynamicBuffer>
@ -116,9 +109,9 @@ read_some_op<MutableBufferSequence, Handler>::operator()(
}
step_ = 3;
s_.get_io_service().post(
return boost::asio::post(
s_.get_executor(),
bind_handler(std::move(*this), ec, 0));
return;
case 1:
// upcall
@ -153,11 +146,11 @@ auto
buffered_read_stream<Stream, DynamicBuffer>::
async_write_some(ConstBufferSequence const& buffers,
WriteHandler&& handler) ->
async_return_type<WriteHandler, void(error_code)>
BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, void(error_code))
{
static_assert(is_async_write_stream<next_layer_type>::value,
"AsyncWriteStream requirements not met");
static_assert(is_const_buffer_sequence<
static_assert(boost::asio::is_const_buffer_sequence<
ConstBufferSequence>::value,
"ConstBufferSequence requirements not met");
static_assert(is_completion_handler<WriteHandler,
@ -176,7 +169,7 @@ read_some(
{
static_assert(is_sync_read_stream<next_layer_type>::value,
"SyncReadStream requirements not met");
static_assert(is_mutable_buffer_sequence<
static_assert(boost::asio::is_mutable_buffer_sequence<
MutableBufferSequence>::value,
"MutableBufferSequence requirements not met");
error_code ec;
@ -195,7 +188,7 @@ read_some(MutableBufferSequence const& buffers,
{
static_assert(is_sync_read_stream<next_layer_type>::value,
"SyncReadStream requirements not met");
static_assert(is_mutable_buffer_sequence<
static_assert(boost::asio::is_mutable_buffer_sequence<
MutableBufferSequence>::value,
"MutableBufferSequence requirements not met");
using boost::asio::buffer_size;
@ -226,20 +219,20 @@ auto
buffered_read_stream<Stream, DynamicBuffer>::
async_read_some(MutableBufferSequence const& buffers,
ReadHandler&& handler) ->
async_return_type<ReadHandler, void(error_code)>
BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, void(error_code))
{
static_assert(is_async_read_stream<next_layer_type>::value,
"Stream requirements not met");
static_assert(is_mutable_buffer_sequence<
"AsyncReadStream requirements not met");
static_assert(boost::asio::is_mutable_buffer_sequence<
MutableBufferSequence>::value,
"MutableBufferSequence requirements not met");
if(buffer_.size() == 0 && capacity_ == 0)
return next_layer_.async_read_some(buffers,
std::forward<ReadHandler>(handler));
async_completion<ReadHandler,
boost::asio::async_completion<ReadHandler,
void(error_code, std::size_t)> init{handler};
read_some_op<MutableBufferSequence, handler_type<
ReadHandler, void(error_code, std::size_t)>>{
read_some_op<MutableBufferSequence, BOOST_ASIO_HANDLER_TYPE(
ReadHandler, void(error_code, std::size_t))>{
init.completion_handler, *this, buffers}(
error_code{}, 0);
return init.result.get();

View File

@ -90,11 +90,10 @@ public:
reference
operator*() const
{
using boost::asio::buffer_cast;
using boost::asio::buffer_size;
return value_type{buffer_cast<void const*>(*it_),
(ba_->out_ == ba_->bs_.end() ||
it_ != ba_->out_) ? buffer_size(*it_) : ba_->out_pos_} +
value_type const b = *it_;
return value_type{b.data(),
(ba_->out_ == boost::asio::buffer_sequence_end(ba_->bs_) ||
it_ != ba_->out_) ? b.size() : ba_->out_pos_} +
(it_ == ba_->begin_ ? ba_->in_pos_ : 0);
}
@ -233,11 +232,10 @@ public:
reference
operator*() const
{
using boost::asio::buffer_cast;
using boost::asio::buffer_size;
return value_type{buffer_cast<void*>(*it_),
value_type const b = *it_;
return value_type{b.data(),
it_ == std::prev(ba_->end_) ?
ba_->out_end_ : buffer_size(*it_)} +
ba_->out_end_ : b.size()} +
(it_ == ba_->out_ ? ba_->out_pos_ : 0);
}
@ -288,7 +286,9 @@ private:
template<class MutableBufferSequence>
inline
auto
buffers_adapter<MutableBufferSequence>::mutable_buffers_type::begin() const ->
buffers_adapter<MutableBufferSequence>::
mutable_buffers_type::
begin() const ->
const_iterator
{
return const_iterator{*ba_, ba_->out_};
@ -297,7 +297,9 @@ buffers_adapter<MutableBufferSequence>::mutable_buffers_type::begin() const ->
template<class MutableBufferSequence>
inline
auto
buffers_adapter<MutableBufferSequence>::mutable_buffers_type::end() const ->
buffers_adapter<MutableBufferSequence>::
mutable_buffers_type::
end() const ->
const_iterator
{
return const_iterator{*ba_, ba_->end_};
@ -309,9 +311,9 @@ template<class MutableBufferSequence>
buffers_adapter<MutableBufferSequence>::buffers_adapter(
buffers_adapter&& other)
: buffers_adapter(std::move(other),
std::distance<iter_type>(other.bs_.begin(), other.begin_),
std::distance<iter_type>(other.bs_.begin(), other.out_),
std::distance<iter_type>(other.bs_.begin(), other.end_))
std::distance<iter_type>(boost::asio::buffer_sequence_begin(other.bs_), other.begin_),
std::distance<iter_type>(boost::asio::buffer_sequence_begin(other.bs_), other.out_),
std::distance<iter_type>(boost::asio::buffer_sequence_begin(other.bs_), other.end_))
{
}
@ -319,9 +321,9 @@ template<class MutableBufferSequence>
buffers_adapter<MutableBufferSequence>::buffers_adapter(
buffers_adapter const& other)
: buffers_adapter(other,
std::distance<iter_type>(other.bs_.begin(), other.begin_),
std::distance<iter_type>(other.bs_.begin(), other.out_),
std::distance<iter_type>(other.bs_.begin(), other.end_))
std::distance<iter_type>(boost::asio::buffer_sequence_begin(other.bs_), other.begin_),
std::distance<iter_type>(boost::asio::buffer_sequence_begin(other.bs_), other.out_),
std::distance<iter_type>(boost::asio::buffer_sequence_begin(other.bs_), other.end_))
{
}
@ -331,15 +333,18 @@ buffers_adapter<MutableBufferSequence>::operator=(
buffers_adapter&& other) -> buffers_adapter&
{
auto const nbegin = std::distance<iter_type>(
other.bs_.begin(), other.begin_);
boost::asio::buffer_sequence_begin(other.bs_),
other.begin_);
auto const nout = std::distance<iter_type>(
other.bs_.begin(), other.out_);
boost::asio::buffer_sequence_begin(other.bs_),
other.out_);
auto const nend = std::distance<iter_type>(
other.bs_.begin(), other.end_);
boost::asio::buffer_sequence_begin(other.bs_),
other.end_);
bs_ = std::move(other.bs_);
begin_ = std::next(bs_.begin(), nbegin);
out_ = std::next(bs_.begin(), nout);
end_ = std::next(bs_.begin(), nend);
begin_ = std::next(boost::asio::buffer_sequence_begin(bs_), nbegin);
out_ = std::next(boost::asio::buffer_sequence_begin(bs_), nout);
end_ = std::next(boost::asio::buffer_sequence_begin(bs_), nend);
max_size_ = other.max_size_;
in_pos_ = other.in_pos_;
in_size_ = other.in_size_;
@ -354,15 +359,18 @@ buffers_adapter<MutableBufferSequence>::operator=(
buffers_adapter const& other) -> buffers_adapter&
{
auto const nbegin = std::distance<iter_type>(
other.bs_.begin(), other.begin_);
boost::asio::buffer_sequence_begin(other.bs_),
other.begin_);
auto const nout = std::distance<iter_type>(
other.bs_.begin(), other.out_);
boost::asio::buffer_sequence_begin(other.bs_),
other.out_);
auto const nend = std::distance<iter_type>(
other.bs_.begin(), other.end_);
boost::asio::buffer_sequence_begin(other.bs_),
other.end_);
bs_ = other.bs_;
begin_ = std::next(bs_.begin(), nbegin);
out_ = std::next(bs_.begin(), nout);
end_ = std::next(bs_.begin(), nend);
begin_ = std::next(boost::asio::buffer_sequence_begin(bs_), nbegin);
out_ = std::next(boost::asio::buffer_sequence_begin(bs_), nout);
end_ = std::next(boost::asio::buffer_sequence_begin(bs_), nend);
max_size_ = other.max_size_;
in_pos_ = other.in_pos_;
in_size_ = other.in_size_;
@ -375,9 +383,9 @@ template<class MutableBufferSequence>
buffers_adapter<MutableBufferSequence>::buffers_adapter(
MutableBufferSequence const& bs)
: bs_(bs)
, begin_(bs_.begin())
, out_(bs_.begin())
, end_(bs_.begin())
, begin_(boost::asio::buffer_sequence_begin(bs_))
, out_ (boost::asio::buffer_sequence_begin(bs_))
, end_ (boost::asio::buffer_sequence_begin(bs_))
, max_size_(boost::asio::buffer_size(bs_))
{
}
@ -389,13 +397,14 @@ buffers_adapter<MutableBufferSequence>::prepare(std::size_t n) ->
{
using boost::asio::buffer_size;
end_ = out_;
if(end_ != bs_.end())
if(end_ != boost::asio::buffer_sequence_end(bs_))
{
auto size = buffer_size(*end_) - out_pos_;
if(n > size)
{
n -= size;
while(++end_ != bs_.end())
while(++end_ !=
boost::asio::buffer_sequence_end(bs_))
{
size = buffer_size(*end_);
if(n < size)

View File

@ -30,7 +30,7 @@ class buffers_cat_view<Bn...>::const_iterator
std::size_t n_;
std::tuple<Bn...> const* bn_;
std::array<char, detail::max_sizeof<
typename Bn::const_iterator...>()> buf_;
typename detail::buffer_sequence_iterator<Bn>::type...>()> buf_;
friend class buffers_cat_view<Bn...>;
@ -38,8 +38,8 @@ class buffers_cat_view<Bn...>::const_iterator
using C = std::integral_constant<std::size_t, I>;
template<std::size_t I>
using iter_t = typename std::tuple_element<
I, std::tuple<Bn...>>::type::const_iterator;
using iter_t = typename detail::buffer_sequence_iterator<
typename std::tuple_element<I, std::tuple<Bn...>>::type>::type;
template<std::size_t I>
iter_t<I>&
@ -123,7 +123,8 @@ private:
{
n_ = I;
new(&buf_[0]) iter_t<I>{
std::get<I>(*bn_).begin()};
boost::asio::buffer_sequence_begin(
std::get<I>(*bn_))};
return;
}
construct(C<I+1>{});
@ -138,7 +139,8 @@ private:
{
n_ = I;
new(&buf_[0]) iter_t<I>{
std::get<I>(*bn_).end()};
boost::asio::buffer_sequence_end(
std::get<I>(*bn_))};
return;
}
BOOST_THROW_EXCEPTION(std::logic_error{
@ -154,7 +156,8 @@ private:
{
n_ = I;
new(&buf_[0]) iter_t<I>{
std::get<I>(*bn_).end()};
boost::asio::buffer_sequence_end(
std::get<I>(*bn_))};
return;
}
rconstruct(C<I-1>{});
@ -268,7 +271,8 @@ private:
if(n_ == I)
{
if(++iter<I>() !=
std::get<I>(*bn_).end())
boost::asio::buffer_sequence_end(
std::get<I>(*bn_)))
return;
using Iter = iter_t<I>;
iter<I>().~Iter();
@ -292,7 +296,9 @@ private:
{
if(n_ == I)
{
if(iter<I>() != std::get<I>(*bn_).begin())
if(iter<I>() !=
boost::asio::buffer_sequence_begin(
std::get<I>(*bn_)))
{
--iter<I>();
return;
@ -309,7 +315,9 @@ private:
decrement(C<0> const&)
{
auto constexpr I = 0;
if(iter<I>() != std::get<I>(*bn_).begin())
if(iter<I>() !=
boost::asio::buffer_sequence_begin(
std::get<I>(*bn_)))
{
--iter<I>();
return;

View File

@ -27,10 +27,8 @@ boost::asio::const_buffer
buffers_prefix(std::size_t size,
boost::asio::const_buffer buffer)
{
using boost::asio::buffer_cast;
using boost::asio::buffer_size;
return {buffer_cast<void const*>(buffer),
(std::min)(size, buffer_size(buffer))};
return {buffer.data(),
(std::min)(size, buffer.size())};
}
inline
@ -38,10 +36,8 @@ boost::asio::mutable_buffer
buffers_prefix(std::size_t size,
boost::asio::mutable_buffer buffer)
{
using boost::asio::buffer_cast;
using boost::asio::buffer_size;
return {buffer_cast<void*>(buffer),
(std::min)(size, buffer_size(buffer))};
return {buffer.data(),
(std::min)(size, buffer.size())};
}
} // detail
@ -138,7 +134,7 @@ private:
std::false_type)
: b_(&b)
, remain_(b_->size_)
, it_(b_->bs_.begin())
, it_(boost::asio::buffer_sequence_begin(b_->bs_))
{
}
};
@ -149,7 +145,7 @@ buffers_prefix_view<BufferSequence>::
setup(std::size_t size)
{
size_ = 0;
end_ = bs_.begin();
end_ = boost::asio::buffer_sequence_begin(bs_);
auto const last = bs_.end();
while(end_ != last)
{
@ -170,7 +166,8 @@ buffers_prefix_view<BufferSequence>::
buffers_prefix_view(buffers_prefix_view&& other)
: buffers_prefix_view(std::move(other),
std::distance<iter_type>(
other.bs_.begin(), other.end_))
boost::asio::buffer_sequence_begin(other.bs_),
other.end_))
{
}
@ -179,7 +176,8 @@ buffers_prefix_view<BufferSequence>::
buffers_prefix_view(buffers_prefix_view const& other)
: buffers_prefix_view(other,
std::distance<iter_type>(
other.bs_.begin(), other.end_))
boost::asio::buffer_sequence_begin(other.bs_),
other.end_))
{
}
@ -190,10 +188,13 @@ operator=(buffers_prefix_view&& other) ->
buffers_prefix_view&
{
auto const dist = std::distance<iter_type>(
other.bs_.begin(), other.end_);
boost::asio::buffer_sequence_begin(other.bs_),
other.end_);
bs_ = std::move(other.bs_);
size_ = other.size_;
end_ = std::next(bs_.begin(), dist);
end_ = std::next(
boost::asio::buffer_sequence_begin(bs_),
dist);
return *this;
}
@ -204,10 +205,13 @@ operator=(buffers_prefix_view const& other) ->
buffers_prefix_view&
{
auto const dist = std::distance<iter_type>(
other.bs_.begin(), other.end_);
boost::asio::buffer_sequence_begin(other.bs_),
other.end_);
bs_ = other.bs_;
size_ = other.size_;
end_ = std::next(bs_.begin(), dist);
end_ = std::next(
boost::asio::buffer_sequence_begin(bs_),
dist);
return *this;
}

View File

@ -25,8 +25,8 @@ class buffers_suffix<Buffers>::const_iterator
{
friend class buffers_suffix<Buffers>;
using iter_type =
typename Buffers::const_iterator;
using iter_type = typename
detail::buffer_sequence_iterator<Buffers>::type;
iter_type it_;
buffers_suffix const* b_ = nullptr;
@ -117,7 +117,7 @@ private:
template<class Buffers>
buffers_suffix<Buffers>::
buffers_suffix()
: begin_(bs_.begin())
: begin_(boost::asio::buffer_sequence_begin(bs_))
{
}
@ -126,7 +126,8 @@ buffers_suffix<Buffers>::
buffers_suffix(buffers_suffix&& other)
: buffers_suffix(std::move(other),
std::distance<iter_type>(
other.bs_.begin(), other.begin_))
boost::asio::buffer_sequence_begin(
other.bs_), other.begin_))
{
}
@ -135,7 +136,8 @@ buffers_suffix<Buffers>::
buffers_suffix(buffers_suffix const& other)
: buffers_suffix(other,
std::distance<iter_type>(
other.bs_.begin(), other.begin_))
boost::asio::buffer_sequence_begin(
other.bs_), other.begin_))
{
}
@ -143,11 +145,11 @@ template<class Buffers>
buffers_suffix<Buffers>::
buffers_suffix(Buffers const& bs)
: bs_(bs)
, begin_(bs_.begin())
, begin_(boost::asio::buffer_sequence_begin(bs_))
{
static_assert(
is_const_buffer_sequence<Buffers>::value||
is_mutable_buffer_sequence<Buffers>::value,
boost::asio::is_const_buffer_sequence<Buffers>::value||
boost::asio::is_mutable_buffer_sequence<Buffers>::value,
"BufferSequence requirements not met");
}
@ -156,7 +158,7 @@ template<class... Args>
buffers_suffix<Buffers>::
buffers_suffix(boost::in_place_init_t, Args&&... args)
: bs_(std::forward<Args>(args)...)
, begin_(bs_.begin())
, begin_(boost::asio::buffer_sequence_begin(bs_))
{
static_assert(sizeof...(Args) > 0,
"Missing constructor arguments");
@ -172,9 +174,12 @@ operator=(buffers_suffix&& other) ->
buffers_suffix&
{
auto const dist = std::distance<iter_type>(
other.bs_.begin(), other.begin_);
boost::asio::buffer_sequence_begin(other.bs_),
other.begin_);
bs_ = std::move(other.bs_);
begin_ = std::next(bs_.begin(), dist);
begin_ = std::next(
boost::asio::buffer_sequence_begin(bs_),
dist);
skip_ = other.skip_;
return *this;
}
@ -186,9 +191,11 @@ operator=(buffers_suffix const& other) ->
buffers_suffix&
{
auto const dist = std::distance<iter_type>(
other.bs_.begin(), other.begin_);
boost::asio::buffer_sequence_begin(other.bs_),
other.begin_);
bs_ = other.bs_;
begin_ = std::next(bs_.begin(), dist);
begin_ = std::next(
boost::asio::buffer_sequence_begin(bs_), dist);
skip_ = other.skip_;
return *this;
}
@ -210,7 +217,8 @@ buffers_suffix<Buffers>::
end() const ->
const_iterator
{
return const_iterator{*this, bs_.end()};
return const_iterator{*this,
boost::asio::buffer_sequence_end(bs_)};
}
template<class Buffers>
@ -219,7 +227,9 @@ buffers_suffix<Buffers>::
consume(std::size_t amount)
{
using boost::asio::buffer_size;
for(;amount > 0 && begin_ != bs_.end(); ++begin_)
auto const end =
boost::asio::buffer_sequence_end(bs_);
for(;amount > 0 && begin_ != end; ++begin_)
{
auto const len =
buffer_size(*begin_) - skip_;

View File

@ -10,9 +10,7 @@
#ifndef BOOST_BEAST_IMPL_HANDLER_PTR_HPP
#define BOOST_BEAST_IMPL_HANDLER_PTR_HPP
#include <boost/asio/handler_alloc_hook.hpp>
#include <boost/asio/handler_continuation_hook.hpp>
#include <boost/asio/handler_invoke_hook.hpp>
#include <boost/asio/associated_allocator.hpp>
#include <boost/assert.hpp>
#include <memory>
@ -27,10 +25,11 @@ P(DeducedHandler&& h, Args&&... args)
: n(1)
, handler(std::forward<DeducedHandler>(h))
{
using boost::asio::asio_handler_allocate;
t = reinterpret_cast<T*>(
asio_handler_allocate(
sizeof(T), std::addressof(handler)));
typename std::allocator_traits<
boost::asio::associated_allocator_t<Handler>>::
template rebind_alloc<T> alloc{
boost::asio::get_associated_allocator(handler)};
t = std::allocator_traits<decltype(alloc)>::allocate(alloc, 1);
try
{
t = new(t) T{handler,
@ -38,9 +37,8 @@ P(DeducedHandler&& h, Args&&... args)
}
catch(...)
{
using boost::asio::asio_handler_deallocate;
asio_handler_deallocate(
t, sizeof(T), std::addressof(handler));
std::allocator_traits<
decltype(alloc)>::deallocate(alloc, t, 1);
throw;
}
}
@ -56,9 +54,13 @@ handler_ptr<T, Handler>::
if(p_->t)
{
p_->t->~T();
using boost::asio::asio_handler_deallocate;
asio_handler_deallocate(
p_->t, sizeof(T), std::addressof(p_->handler));
typename std::allocator_traits<
boost::asio::associated_allocator_t<Handler>>::
template rebind_alloc<T> alloc{
boost::asio::get_associated_allocator(
p_->handler)};
std::allocator_traits<
decltype(alloc)>::deallocate(alloc, p_->t, 1);
}
delete p_;
}
@ -108,9 +110,13 @@ release_handler() ->
BOOST_ASSERT(p_);
BOOST_ASSERT(p_->t);
p_->t->~T();
using boost::asio::asio_handler_deallocate;
asio_handler_deallocate(
p_->t, sizeof(T), std::addressof(p_->handler));
typename std::allocator_traits<
boost::asio::associated_allocator_t<Handler>>::
template rebind_alloc<T> alloc{
boost::asio::get_associated_allocator(
p_->handler)};
std::allocator_traits<
decltype(alloc)>::deallocate(alloc, p_->t, 1);
p_->t = nullptr;
return std::move(p_->handler);
}
@ -124,9 +130,13 @@ invoke(Args&&... args)
BOOST_ASSERT(p_);
BOOST_ASSERT(p_->t);
p_->t->~T();
using boost::asio::asio_handler_deallocate;
asio_handler_deallocate(
p_->t, sizeof(T), std::addressof(p_->handler));
typename std::allocator_traits<
boost::asio::associated_allocator_t<Handler>>::
template rebind_alloc<T> alloc{
boost::asio::get_associated_allocator(
p_->handler)};
std::allocator_traits<
decltype(alloc)>::deallocate(alloc, p_->t, 1);
p_->t = nullptr;
p_->handler(std::forward<Args>(args)...);
}

View File

@ -38,7 +38,8 @@ std::size_t
read_size(DynamicBuffer& buffer,
std::size_t max_size, std::false_type)
{
static_assert(is_dynamic_buffer<DynamicBuffer>::value,
static_assert(
boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
"DynamicBuffer requirements not met");
BOOST_ASSERT(max_size >= 1);
auto const size = buffer.size();

View File

@ -49,7 +49,7 @@ detail::buffers_helper<ConstBufferSequence>
#endif
buffers(ConstBufferSequence const& b)
{
static_assert(is_const_buffer_sequence<
static_assert(boost::asio::is_const_buffer_sequence<
ConstBufferSequence>::value,
"ConstBufferSequence requirements not met");
return detail::buffers_helper<
@ -90,7 +90,8 @@ detail::ostream_helper<
#endif
ostream(DynamicBuffer& buffer)
{
static_assert(is_dynamic_buffer<DynamicBuffer>::value,
static_assert(
boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
"DynamicBuffer requirements not met");
return detail::ostream_helper<
DynamicBuffer, char, std::char_traits<char>,

View File

@ -19,153 +19,6 @@
namespace boost {
namespace beast {
//------------------------------------------------------------------------------
//
// Buffer concepts
//
//------------------------------------------------------------------------------
/** Determine if `T` meets the requirements of @b ConstBufferSequence.
Metafunctions are used to perform compile time checking of template
types. This type will be `std::true_type` if `T` meets the requirements,
else the type will be `std::false_type`.
@par Example
Use with `static_assert`:
@code
template<class ConstBufferSequence>
void f(ConstBufferSequence const& buffers)
{
static_assert(is_const_buffer_sequence<ConstBufferSequence>::value,
"ConstBufferSequence requirements not met");
...
@endcode
Use with `std::enable_if` (SFINAE):
@code
template<class ConstBufferSequence>
typename std::enable_if<is_const_buffer_sequence<ConstBufferSequence>::value>::type
f(ConstBufferSequence const& buffers);
@endcode
*/
template<class T>
#if BOOST_BEAST_DOXYGEN
struct is_const_buffer_sequence : std::integral_constant<bool, ...>
#else
struct is_const_buffer_sequence :
detail::is_buffer_sequence<T, boost::asio::const_buffer>
#endif
{
};
/** Determine if `T` meets the requirements of @b MutableBufferSequence.
Metafunctions are used to perform compile time checking of template
types. This type will be `std::true_type` if `T` meets the requirements,
else the type will be `std::false_type`.
@par Example
Use with `static_assert`:
@code
template<class MutableBufferSequence>
void f(MutableBufferSequence const& buffers)
{
static_assert(is_const_buffer_sequence<MutableBufferSequence>::value,
"MutableBufferSequence requirements not met");
...
@endcode
Use with `std::enable_if` (SFINAE):
@code
template<class MutableBufferSequence>
typename std::enable_if<is_mutable_buffer_sequence<MutableBufferSequence>::value>::type
f(MutableBufferSequence const& buffers);
@endcode
*/
template<class T>
#if BOOST_BEAST_DOXYGEN
struct is_mutable_buffer_sequence : std::integral_constant<bool, ...>
#else
struct is_mutable_buffer_sequence :
detail::is_buffer_sequence<T, boost::asio::mutable_buffer>
#endif
{
};
/** Determine if `T` meets the requirements of @b DynamicBuffer.
Metafunctions are used to perform compile time checking of template
types. This type will be `std::true_type` if `T` meets the requirements,
else the type will be `std::false_type`.
@par Example
Use with `static_assert`:
@code
template<class DynamicBuffer>
void f(DynamicBuffer& buffer)
{
static_assert(is_dynamic_buffer<DynamicBuffer>::value,
"DynamicBuffer requirements not met");
...
@endcode
Use with `std::enable_if` (SFINAE):
@code
template<class DynamicBuffer>
typename std::enable_if<is_dynamic_buffer<DynamicBuffer>::value>::type
f(DynamicBuffer const& buffer);
@endcode
*/
#if BOOST_BEAST_DOXYGEN
template<class T>
struct is_dynamic_buffer : std::integral_constant<bool, ...> {};
#else
template<class T, class = void>
struct is_dynamic_buffer : std::false_type {};
template<class T>
struct is_dynamic_buffer<T, detail::void_t<decltype(
std::declval<std::size_t&>() =
std::declval<T const&>().size(),
std::declval<std::size_t&>() =
std::declval<T const&>().max_size(),
std::declval<std::size_t&>() =
std::declval<T const&>().capacity(),
std::declval<T&>().commit(std::declval<std::size_t>()),
std::declval<T&>().consume(std::declval<std::size_t>()),
(void)0)> > : std::integral_constant<bool,
is_const_buffer_sequence<
typename T::const_buffers_type>::value &&
is_mutable_buffer_sequence<
typename T::mutable_buffers_type>::value &&
std::is_same<typename T::const_buffers_type,
decltype(std::declval<T const&>().data())>::value &&
std::is_same<typename T::mutable_buffers_type,
decltype(std::declval<T&>().prepare(
std::declval<std::size_t>()))>::value
>
{
};
// Special case for Boost.Asio which doesn't adhere to
// net-ts but still provides a read_size_helper so things work
template<class Allocator>
struct is_dynamic_buffer<
boost::asio::basic_streambuf<Allocator>> : std::true_type
{
};
#endif
//------------------------------------------------------------------------------
//
// Handler concepts
@ -209,7 +62,7 @@ using is_completion_handler = std::integral_constant<bool,
//
//------------------------------------------------------------------------------
/** Determine if `T` has the `get_io_service` member.
/** Determine if `T` has the `get_executor` member function.
Metafunctions are used to perform compile time checking of template
types. This type will be `std::true_type` if `T` has the member
@ -223,19 +76,24 @@ using is_completion_handler = std::integral_constant<bool,
template<class T>
void maybe_hello(T& t, std::true_type)
{
t.get_io_service().post([]{ std::cout << "Hello, world!" << std::endl; });
boost::asio::post(
t.get_executor(),
[]
{
std::cout << "Hello, world!" << std::endl;
});
}
template<class T>
void maybe_hello(T&, std::false_type)
{
// T does not have get_io_service
// T does not have get_executor
}
template<class T>
void maybe_hello(T& t)
{
maybe_hello(t, has_get_io_service<T>{});
maybe_hello(t, has_get_executor<T>{});
}
@endcode
@ -244,24 +102,23 @@ using is_completion_handler = std::integral_constant<bool,
@code
struct stream
{
boost::asio::io_service& get_io_service();
using executor_type = boost::asio::io_context::executor_type;
executor_type get_executor() noexcept;
};
static_assert(has_get_io_service<stream>::value,
"Missing get_io_service member");
static_assert(has_get_executor<stream>::value, "Missing get_executor member");
@endcode
*/
#if BOOST_BEAST_DOXYGEN
template<class T>
struct has_get_io_service : std::integral_constant<bool, ...>{};
struct has_get_executor : std::integral_constant<bool, ...>{};
#else
template<class T, class = void>
struct has_get_io_service : std::false_type {};
struct has_get_executor : std::false_type {};
template<class T>
struct has_get_io_service<T, beast::detail::void_t<decltype(
detail::accept_rv<boost::asio::io_service&>(
std::declval<T&>().get_io_service()),
struct has_get_executor<T, beast::detail::void_t<decltype(
std::declval<T&>().get_executor(),
(void)0)>> : std::true_type {};
#endif
@ -350,7 +207,7 @@ struct is_async_read_stream<T, detail::void_t<decltype(
std::declval<detail::MutableBufferSequence>(),
std::declval<detail::ReadHandler>()),
(void)0)>> : std::integral_constant<bool,
has_get_io_service<T>::value
has_get_executor<T>::value
> {};
#endif
@ -394,7 +251,7 @@ struct is_async_write_stream<T, detail::void_t<decltype(
std::declval<detail::ConstBufferSequence>(),
std::declval<detail::WriteHandler>()),
(void)0)>> : std::integral_constant<bool,
has_get_io_service<T>::value
has_get_executor<T>::value
> {};
#endif
@ -439,12 +296,10 @@ struct is_sync_read_stream<T, detail::void_t<decltype(
std::declval<std::size_t&>() = std::declval<T>().read_some(
std::declval<detail::MutableBufferSequence>(),
std::declval<boost::system::error_code&>()),
(void)0)>> : std::integral_constant<bool,
has_get_io_service<T>::value
> {};
(void)0)>> : std::true_type {};
#endif
/** Determine if `T` meets the requirements of @b SyncWriterStream.
/** Determine if `T` meets the requirements of @b SyncWriteStream.
Metafunctions are used to perform compile time checking of template
types. This type will be `std::true_type` if `T` meets the requirements,
@ -485,9 +340,7 @@ struct is_sync_write_stream<T, detail::void_t<decltype(
std::declval<std::size_t&>() = std::declval<T&>().write_some(
std::declval<detail::ConstBufferSequence>(),
std::declval<boost::system::error_code&>()),
(void)0)>> : std::integral_constant<bool,
has_get_io_service<T>::value
> {};
(void)0)>> : std::true_type {};
#endif
/** Determine if `T` meets the requirements of @b AsyncStream.

View File

@ -32,7 +32,8 @@ namespace http {
template<class DynamicBuffer>
struct basic_dynamic_body
{
static_assert(is_dynamic_buffer<DynamicBuffer>::value,
static_assert(
boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
"DynamicBuffer requirements not met");
/** The type of container used for the body

View File

@ -143,7 +143,13 @@ public:
/** Set the open file
This function is used to set the open
This function is used to set the open file. Any previously
set file will be closed.
@param file The file to set. The file must be open or else
an error occurs
@param ec Set to the error, if any occurred
*/
void
reset(File&& file, error_code& ec);
@ -229,7 +235,7 @@ public:
// The type of buffer sequence returned by `get`.
//
using const_buffers_type =
boost::asio::const_buffers_1;
boost::asio::const_buffer;
// Constructor.
//
@ -485,13 +491,13 @@ put(ConstBufferSequence const& buffers, error_code& ec)
// Loop over all the buffers in the sequence,
// and write each one to the file.
for(boost::asio::const_buffer buffer : buffers)
for(auto it = boost::asio::buffer_sequence_begin(buffers);
it != boost::asio::buffer_sequence_end(buffers); ++it)
{
// Write this buffer to the file
boost::asio::const_buffer buffer = *it;
nwritten += body_.file_.write(
boost::asio::buffer_cast<void const*>(buffer),
boost::asio::buffer_size(buffer),
ec);
buffer.data(), buffer.size(), ec);
if(ec)
return nwritten;
}

View File

@ -515,7 +515,7 @@ public:
#if ! BOOST_BEAST_DOXYGEN
std::size_t
put(boost::asio::const_buffers_1 const& buffer,
put(boost::asio::const_buffer const& buffer,
error_code& ec);
#endif

View File

@ -105,7 +105,7 @@ struct buffer_body
public:
using const_buffers_type =
boost::asio::const_buffers_1;
boost::asio::const_buffer;
template<bool isRequest, class Fields>
explicit

View File

@ -106,7 +106,7 @@ class chunk_header
{
using view_type = buffers_cat_view<
detail::chunk_size, // chunk-size
boost::asio::const_buffers_1, // chunk-extensions
boost::asio::const_buffer, // chunk-extensions
chunk_crlf>; // CRLF
std::shared_ptr<
@ -285,7 +285,7 @@ class chunk_body
{
using view_type = buffers_cat_view<
detail::chunk_size, // chunk-size
boost::asio::const_buffers_1, // chunk-extensions
boost::asio::const_buffer, // chunk-extensions
chunk_crlf, // CRLF
ConstBufferSequence, // chunk-body
chunk_crlf>; // CRLF
@ -459,7 +459,7 @@ class chunk_last
{
static_assert(
is_fields<Trailer>::value ||
is_const_buffer_sequence<Trailer>::value,
boost::asio::is_const_buffer_sequence<Trailer>::value,
"Trailer requirements not met");
using buffers_type = typename

View File

@ -25,7 +25,7 @@ namespace detail {
struct chunk_extensions
{
virtual ~chunk_extensions() = default;
virtual boost::asio::const_buffers_1 str() = 0;
virtual boost::asio::const_buffer str() = 0;
};
template<class ChunkExtensions>
@ -43,7 +43,7 @@ struct chunk_extensions_impl : chunk_extensions
{
}
boost::asio::const_buffers_1
boost::asio::const_buffer
str() override
{
auto const s = ext_.str();
@ -151,7 +151,7 @@ prepare(std::size_t n)
/// Returns a buffer sequence holding a CRLF for chunk encoding
inline
boost::asio::const_buffers_1
boost::asio::const_buffer
chunk_crlf()
{
return {"\r\n", 2};
@ -159,7 +159,7 @@ chunk_crlf()
/// Returns a buffer sequence holding a final chunk header
inline
boost::asio::const_buffers_1
boost::asio::const_buffer
chunk_last()
{
return {"0\r\n", 3};

View File

@ -103,14 +103,13 @@ basic_parser<isRequest, Derived>::
put(ConstBufferSequence const& buffers,
error_code& ec)
{
static_assert(is_const_buffer_sequence<
static_assert(boost::asio::is_const_buffer_sequence<
ConstBufferSequence>::value,
"ConstBufferSequence requirements not met");
using boost::asio::buffer_cast;
using boost::asio::buffer_copy;
using boost::asio::buffer_size;
auto const p = buffers.begin();
auto const last = buffers.end();
auto const p = boost::asio::buffer_sequence_begin(buffers);
auto const last = boost::asio::buffer_sequence_end(buffers);
if(p == last)
{
ec.assign(0, ec.category());
@ -119,10 +118,7 @@ put(ConstBufferSequence const& buffers,
if(std::next(p) == last)
{
// single buffer
auto const b = *p;
return put(boost::asio::const_buffers_1{
buffer_cast<char const*>(b),
buffer_size(b)}, ec);
return put(boost::asio::const_buffer(*p), ec);
}
auto const size = buffer_size(buffers);
if(size <= max_stack_buffer)
@ -136,21 +132,21 @@ put(ConstBufferSequence const& buffers,
// flatten
buffer_copy(boost::asio::buffer(
buf_.get(), buf_len_), buffers);
return put(boost::asio::const_buffers_1{
return put(boost::asio::const_buffer{
buf_.get(), buf_len_}, ec);
}
template<bool isRequest, class Derived>
std::size_t
basic_parser<isRequest, Derived>::
put(boost::asio::const_buffers_1 const& buffer,
put(boost::asio::const_buffer const& buffer,
error_code& ec)
{
BOOST_ASSERT(state_ != state::complete);
using boost::asio::buffer_size;
auto p = boost::asio::buffer_cast<
char const*>(*buffer.begin());
auto n = buffer_size(*buffer.begin());
auto p = reinterpret_cast<
char const*>(buffer.data());
auto n = buffer.size();
auto const p0 = p;
auto const p1 = p0 + n;
ec.assign(0, ec.category());
@ -324,7 +320,7 @@ put_from_stack(std::size_t size,
using boost::asio::buffer;
using boost::asio::buffer_copy;
buffer_copy(buffer(buf, sizeof(buf)), buffers);
return put(boost::asio::const_buffers_1{
return put(boost::asio::const_buffer{
buf, size}, ec);
}

View File

@ -24,7 +24,7 @@ chunk_header::
chunk_header(std::size_t size)
: view_(
size,
boost::asio::const_buffers_1{nullptr, 0},
boost::asio::const_buffer{nullptr, 0},
chunk_crlf{})
{
BOOST_ASSERT(size > 0);
@ -37,7 +37,7 @@ chunk_header(
string_view extensions)
: view_(
size,
boost::asio::const_buffers_1{
boost::asio::const_buffer{
extensions.data(), extensions.size()},
chunk_crlf{})
{
@ -90,7 +90,7 @@ chunk_body<ConstBufferSequence>::
chunk_body(ConstBufferSequence const& buffers)
: view_(
boost::asio::buffer_size(buffers),
boost::asio::const_buffers_1{nullptr, 0},
boost::asio::const_buffer{nullptr, 0},
chunk_crlf{},
buffers,
chunk_crlf{})
@ -104,7 +104,7 @@ chunk_body(
string_view extensions)
: view_(
boost::asio::buffer_size(buffers),
boost::asio::const_buffers_1{
boost::asio::const_buffer{
extensions.data(), extensions.size()},
chunk_crlf{},
buffers,

View File

@ -143,9 +143,9 @@ public:
};
using view_type = buffers_cat_view<
boost::asio::const_buffers_1,
boost::asio::const_buffers_1,
boost::asio::const_buffers_1,
boost::asio::const_buffer,
boost::asio::const_buffer,
boost::asio::const_buffer,
field_range,
chunk_crlf>;
@ -178,9 +178,9 @@ reader(basic_fields const& f)
: f_(f)
{
view_.emplace(
boost::asio::const_buffers_1{nullptr, 0},
boost::asio::const_buffers_1{nullptr, 0},
boost::asio::const_buffers_1{nullptr, 0},
boost::asio::const_buffer{nullptr, 0},
boost::asio::const_buffer{nullptr, 0},
boost::asio::const_buffer{nullptr, 0},
field_range(f_.list_.begin(), f_.list_.end()),
chunk_crlf());
}
@ -218,11 +218,11 @@ reader(basic_fields const& f,
buf_[10]= '\n';
view_.emplace(
boost::asio::const_buffers_1{sv.data(), sv.size()},
boost::asio::const_buffers_1{
boost::asio::const_buffer{sv.data(), sv.size()},
boost::asio::const_buffer{
f_.target_or_reason_.data(),
f_.target_or_reason_.size()},
boost::asio::const_buffers_1{buf_, 11},
boost::asio::const_buffer{buf_, 11},
field_range(f_.list_.begin(), f_.list_.end()),
chunk_crlf());
}
@ -260,9 +260,9 @@ reader(basic_fields const& f,
sv = obsolete_reason(static_cast<status>(code));
view_.emplace(
boost::asio::const_buffers_1{buf_, 13},
boost::asio::const_buffers_1{sv.data(), sv.size()},
boost::asio::const_buffers_1{"\r\n", 2},
boost::asio::const_buffer{buf_, 13},
boost::asio::const_buffer{sv.data(), sv.size()},
boost::asio::const_buffer{"\r\n", 2},
field_range(f_.list_.begin(), f_.list_.end()),
chunk_crlf{});
}

View File

@ -12,15 +12,15 @@
#if BOOST_BEAST_USE_WIN32_FILE
#include <boost/beast/core/async_result.hpp>
#include <boost/beast/core/bind_handler.hpp>
#include <boost/beast/core/type_traits.hpp>
#include <boost/beast/core/detail/clamp.hpp>
#include <boost/beast/http/serializer.hpp>
#include <boost/asio/associated_allocator.hpp>
#include <boost/asio/associated_executor.hpp>
#include <boost/asio/async_result.hpp>
#include <boost/asio/basic_stream_socket.hpp>
#include <boost/asio/handler_alloc_hook.hpp>
#include <boost/asio/handler_continuation_hook.hpp>
#include <boost/asio/handler_invoke_hook.hpp>
#include <boost/asio/windows/overlapped_ptr.hpp>
#include <boost/make_unique.hpp>
#include <boost/smart_ptr/make_shared_array.hpp>
@ -120,7 +120,7 @@ struct basic_file_body<file_win32>
public:
using const_buffers_type =
boost::asio::const_buffers_1;
boost::asio::const_buffer;
template<bool isRequest, class Fields>
reader(message<isRequest,
@ -189,12 +189,10 @@ struct basic_file_body<file_win32>
error_code& ec)
{
std::size_t nwritten = 0;
for(boost::asio::const_buffer buffer : buffers)
for(auto buffer : beast::detail::buffers_range(buffers))
{
nwritten += body_.file_.write(
boost::asio::buffer_cast<void const*>(buffer),
boost::asio::buffer_size(buffer),
ec);
buffer.data(), buffer.size(), ec);
if(ec)
return nwritten;
}
@ -360,6 +358,24 @@ public:
{
}
using allocator_type =
boost::asio::associated_allocator_t<Handler>;
allocator_type
get_allocator() const noexcept
{
return boost::asio::get_associated_allocator(h_);
}
using executor_type = boost::asio::associated_executor_t<
Handler, decltype(sock_.get_executor())>;
executor_type get_executor() const noexcept
{
return boost::asio::get_associated_executor(
h_, sock_.get_executor());
}
void
operator()();
@ -368,24 +384,6 @@ public:
error_code ec,
std::size_t bytes_transferred = 0);
friend
void* asio_handler_allocate(
std::size_t size, write_some_win32_op* op)
{
using boost::asio::asio_handler_allocate;
return asio_handler_allocate(
size, std::addressof(op->h_));
}
friend
void asio_handler_deallocate(
void* p, std::size_t size, write_some_win32_op* op)
{
using boost::asio::asio_handler_deallocate;
asio_handler_deallocate(
p, size, std::addressof(op->h_));
}
friend
bool asio_handler_is_continuation(write_some_win32_op* op)
{
@ -393,15 +391,6 @@ public:
return asio_handler_is_continuation(
std::addressof(op->h_));
}
template<class Function>
friend
void asio_handler_invoke(Function&& f, write_some_win32_op* op)
{
using boost::asio::asio_handler_invoke;
asio_handler_invoke(
f, std::addressof(op->h_));
}
};
template<
@ -431,7 +420,7 @@ operator()()
r.body_.last_ - r.pos_, sr_.limit())),
2147483646);
boost::asio::windows::overlapped_ptr overlapped{
sock_.get_io_service(), *this};
sock_.get_executor().context(), *this};
auto& ov = *overlapped.get();
ov.Offset = lowPart(r.pos_);
ov.OffsetHigh = highPart(r.pos_);
@ -567,21 +556,20 @@ template<
class Protocol,
bool isRequest, class Fields,
class WriteHandler>
async_return_type<
WriteHandler,
void(error_code, std::size_t)>
BOOST_ASIO_INITFN_RESULT_TYPE(
WriteHandler, void(error_code, std::size_t))
async_write_some(
boost::asio::basic_stream_socket<Protocol>& sock,
serializer<isRequest,
basic_file_body<file_win32>, Fields>& sr,
WriteHandler&& handler)
{
async_completion<WriteHandler,
boost::asio::async_completion<WriteHandler,
void(error_code)> init{handler};
detail::write_some_win32_op<
Protocol,
handler_type<WriteHandler,
void(error_code, std::size_t)>,
BOOST_ASIO_HANDLER_TYPE(WriteHandler,
void(error_code, std::size_t)),
isRequest, Fields>{
init.completion_handler, sock, sr}();
return init.result.get();

View File

@ -18,9 +18,10 @@
#include <boost/beast/core/handler_ptr.hpp>
#include <boost/beast/core/read_size.hpp>
#include <boost/beast/core/type_traits.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/asio/post.hpp>
#include <boost/assert.hpp>
#include <boost/config.hpp>
#include <boost/optional.hpp>
@ -61,29 +62,29 @@ public:
{
}
using allocator_type =
boost::asio::associated_allocator_t<Handler>;
allocator_type
get_allocator() const noexcept
{
return boost::asio::get_associated_allocator(h_);
}
using executor_type = boost::asio::associated_executor_t<
Handler, decltype(s_.get_executor())>;
executor_type get_executor() const noexcept
{
return boost::asio::get_associated_executor(
h_, s_.get_executor());
}
void
operator()(
error_code ec = {},
std::size_t bytes_transferred = 0);
friend
void* asio_handler_allocate(
std::size_t size, read_some_op* op)
{
using boost::asio::asio_handler_allocate;
return asio_handler_allocate(
size, std::addressof(op->h_));
}
friend
void asio_handler_deallocate(
void* p, std::size_t size, read_some_op* op)
{
using boost::asio::asio_handler_deallocate;
asio_handler_deallocate(
p, size, std::addressof(op->h_));
}
friend
bool asio_handler_is_continuation(read_some_op* op)
{
@ -92,15 +93,6 @@ public:
asio_handler_is_continuation(
std::addressof(op->h_));
}
template<class Function>
friend
void asio_handler_invoke(Function&& f, read_some_op* op)
{
using boost::asio::asio_handler_invoke;
asio_handler_invoke(
f, std::addressof(op->h_));
}
};
template<class Stream, class DynamicBuffer,
@ -170,7 +162,8 @@ operator()(
if(state_ >= 2)
goto upcall;
state_ = 3;
return s_.get_io_service().post(
return boost::asio::post(
s_.get_executor(),
bind_handler(std::move(*this), ec, 0));
case 3:
@ -231,29 +224,29 @@ public:
{
}
using allocator_type =
boost::asio::associated_allocator_t<Handler>;
allocator_type
get_allocator() const noexcept
{
return boost::asio::get_associated_allocator(h_);
}
using executor_type = boost::asio::associated_executor_t<
Handler, decltype(s_.get_executor())>;
executor_type get_executor() const noexcept
{
return boost::asio::get_associated_executor(
h_, s_.get_executor());
}
void
operator()(
error_code ec = {},
std::size_t bytes_transferred = 0);
friend
void* asio_handler_allocate(
std::size_t size, read_op* op)
{
using boost::asio::asio_handler_allocate;
return asio_handler_allocate(
size, std::addressof(op->h_));
}
friend
void asio_handler_deallocate(
void* p, std::size_t size, read_op* op)
{
using boost::asio::asio_handler_deallocate;
asio_handler_deallocate(
p, size, std::addressof(op->h_));
}
friend
bool asio_handler_is_continuation(read_op* op)
{
@ -262,15 +255,6 @@ public:
asio_handler_is_continuation(
std::addressof(op->h_));
}
template<class Function>
friend
void asio_handler_invoke(Function&& f, read_op* op)
{
using boost::asio::asio_handler_invoke;
asio_handler_invoke(
f, std::addressof(op->h_));
}
};
template<class Stream, class DynamicBuffer,
@ -289,7 +273,8 @@ operator()(
if(Condition{}(p_))
{
state_ = 1;
return s_.get_io_service().post(
return boost::asio::post(
s_.get_executor(),
bind_handler(std::move(*this), ec));
}
state_ = 2;
@ -361,29 +346,29 @@ public:
{
}
using allocator_type =
boost::asio::associated_allocator_t<Handler>;
allocator_type
get_allocator() const noexcept
{
return boost::asio::get_associated_allocator(d_.handler());
}
using executor_type = boost::asio::associated_executor_t<
Handler, decltype(d_->s.get_executor())>;
executor_type get_executor() const noexcept
{
return boost::asio::get_associated_executor(
d_.handler(), d_->s.get_executor());
}
void
operator()(
error_code ec = {},
std::size_t bytes_transferred = 0);
friend
void* asio_handler_allocate(
std::size_t size, read_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, read_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(read_msg_op* op)
{
@ -392,15 +377,6 @@ public:
asio_handler_is_continuation(
std::addressof(op->d_.handler()));
}
template<class Function>
friend
void asio_handler_invoke(Function&& f, read_msg_op* op)
{
using boost::asio::asio_handler_invoke;
asio_handler_invoke(
f, std::addressof(op->d_.handler()));
}
};
template<class Stream, class DynamicBuffer,
@ -458,7 +434,8 @@ read_some(
{
static_assert(is_sync_read_stream<SyncReadStream>::value,
"SyncReadStream requirements not met");
static_assert(is_dynamic_buffer<DynamicBuffer>::value,
static_assert(
boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
"DynamicBuffer requirements not met");
BOOST_ASSERT(! parser.is_done());
error_code ec;
@ -482,7 +459,8 @@ read_some(
{
static_assert(is_sync_read_stream<SyncReadStream>::value,
"SyncReadStream requirements not met");
static_assert(is_dynamic_buffer<DynamicBuffer>::value,
static_assert(
boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
"DynamicBuffer requirements not met");
BOOST_ASSERT(! parser.is_done());
std::size_t bytes_transferred = 0;
@ -541,8 +519,8 @@ template<
class DynamicBuffer,
bool isRequest, class Derived,
class ReadHandler>
async_return_type<
ReadHandler, void(error_code, std::size_t)>
BOOST_ASIO_INITFN_RESULT_TYPE(
ReadHandler, void(error_code, std::size_t))
async_read_some(
AsyncReadStream& stream,
DynamicBuffer& buffer,
@ -551,13 +529,14 @@ async_read_some(
{
static_assert(is_async_read_stream<AsyncReadStream>::value,
"AsyncReadStream requirements not met");
static_assert(is_dynamic_buffer<DynamicBuffer>::value,
static_assert(
boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
"DynamicBuffer requirements not met");
BOOST_ASSERT(! parser.is_done());
async_completion<ReadHandler, void(error_code)> init{handler};
boost::asio::async_completion<ReadHandler, void(error_code)> init{handler};
detail::read_some_op<AsyncReadStream,
DynamicBuffer, isRequest, Derived, handler_type<
ReadHandler, void(error_code, std::size_t)>>{
DynamicBuffer, isRequest, Derived, BOOST_ASIO_HANDLER_TYPE(
ReadHandler, void(error_code, std::size_t))>{
init.completion_handler, stream, buffer, parser}();
return init.result.get();
}
@ -576,7 +555,8 @@ read_header(
{
static_assert(is_sync_read_stream<SyncReadStream>::value,
"SyncReadStream requirements not met");
static_assert(is_dynamic_buffer<DynamicBuffer>::value,
static_assert(
boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
"DynamicBuffer requirements not met");
error_code ec;
auto const bytes_transferred =
@ -599,7 +579,8 @@ read_header(
{
static_assert(is_sync_read_stream<SyncReadStream>::value,
"SyncReadStream requirements not met");
static_assert(is_dynamic_buffer<DynamicBuffer>::value,
static_assert(
boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
"DynamicBuffer requirements not met");
parser.eager(false);
if(parser.is_header_done())
@ -624,9 +605,8 @@ template<
class DynamicBuffer,
bool isRequest, class Derived,
class ReadHandler>
async_return_type<
ReadHandler,
void(error_code, std::size_t)>
BOOST_ASIO_INITFN_RESULT_TYPE(
ReadHandler, void(error_code, std::size_t))
async_read_header(
AsyncReadStream& stream,
DynamicBuffer& buffer,
@ -635,14 +615,15 @@ async_read_header(
{
static_assert(is_async_read_stream<AsyncReadStream>::value,
"AsyncReadStream requirements not met");
static_assert(is_dynamic_buffer<DynamicBuffer>::value,
static_assert(
boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
"DynamicBuffer requirements not met");
parser.eager(false);
async_completion<ReadHandler,
boost::asio::async_completion<ReadHandler,
void(error_code, std::size_t)> init{handler};
detail::read_op<AsyncReadStream, DynamicBuffer,
isRequest, Derived, detail::parser_is_header_done,
handler_type<ReadHandler, void(error_code, std::size_t)>>{
BOOST_ASIO_HANDLER_TYPE(ReadHandler, void(error_code, std::size_t))>{
init.completion_handler, stream, buffer, parser}();
return init.result.get();
}
@ -661,7 +642,8 @@ read(
{
static_assert(is_sync_read_stream<SyncReadStream>::value,
"SyncReadStream requirements not met");
static_assert(is_dynamic_buffer<DynamicBuffer>::value,
static_assert(
boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
"DynamicBuffer requirements not met");
error_code ec;
auto const bytes_transferred =
@ -684,7 +666,8 @@ read(
{
static_assert(is_sync_read_stream<SyncReadStream>::value,
"SyncReadStream requirements not met");
static_assert(is_dynamic_buffer<DynamicBuffer>::value,
static_assert(
boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
"DynamicBuffer requirements not met");
parser.eager(true);
if(parser.is_done())
@ -709,9 +692,8 @@ template<
class DynamicBuffer,
bool isRequest, class Derived,
class ReadHandler>
async_return_type<
ReadHandler,
void(error_code, std::size_t)>
BOOST_ASIO_INITFN_RESULT_TYPE(
ReadHandler, void(error_code, std::size_t))
async_read(
AsyncReadStream& stream,
DynamicBuffer& buffer,
@ -720,15 +702,16 @@ async_read(
{
static_assert(is_async_read_stream<AsyncReadStream>::value,
"AsyncReadStream requirements not met");
static_assert(is_dynamic_buffer<DynamicBuffer>::value,
static_assert(
boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
"DynamicBuffer requirements not met");
parser.eager(true);
async_completion<
boost::asio::async_completion<
ReadHandler,
void(error_code, std::size_t)> init{handler};
detail::read_op<AsyncReadStream, DynamicBuffer,
isRequest, Derived, detail::parser_is_done,
handler_type<ReadHandler, void(error_code, std::size_t)>>{
BOOST_ASIO_HANDLER_TYPE(ReadHandler, void(error_code, std::size_t))>{
init.completion_handler, stream, buffer, parser}();
return init.result.get();
}
@ -747,7 +730,8 @@ read(
{
static_assert(is_sync_read_stream<SyncReadStream>::value,
"SyncReadStream requirements not met");
static_assert(is_dynamic_buffer<DynamicBuffer>::value,
static_assert(
boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
"DynamicBuffer requirements not met");
static_assert(is_body<Body>::value,
"Body requirements not met");
@ -774,7 +758,8 @@ read(
{
static_assert(is_sync_read_stream<SyncReadStream>::value,
"SyncReadStream requirements not met");
static_assert(is_dynamic_buffer<DynamicBuffer>::value,
static_assert(
boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
"DynamicBuffer requirements not met");
static_assert(is_body<Body>::value,
"Body requirements not met");
@ -795,9 +780,8 @@ template<
class DynamicBuffer,
bool isRequest, class Body, class Allocator,
class ReadHandler>
async_return_type<
ReadHandler,
void(error_code, std::size_t)>
BOOST_ASIO_INITFN_RESULT_TYPE(
ReadHandler, void(error_code, std::size_t))
async_read(
AsyncReadStream& stream,
DynamicBuffer& buffer,
@ -806,21 +790,22 @@ async_read(
{
static_assert(is_async_read_stream<AsyncReadStream>::value,
"AsyncReadStream requirements not met");
static_assert(is_dynamic_buffer<DynamicBuffer>::value,
static_assert(
boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
"DynamicBuffer requirements not met");
static_assert(is_body<Body>::value,
"Body requirements not met");
static_assert(is_body_writer<Body>::value,
"BodyWriter requirements not met");
async_completion<
boost::asio::async_completion<
ReadHandler,
void(error_code, std::size_t)> init{handler};
detail::read_msg_op<
AsyncReadStream,
DynamicBuffer,
isRequest, Body, Allocator,
handler_type<ReadHandler,
void(error_code, std::size_t)>>{
BOOST_ASIO_HANDLER_TYPE(
ReadHandler, void(error_code, std::size_t))>{
init.completion_handler, stream, buffer, msg}();
return init.result.get();
}

View File

@ -166,12 +166,12 @@ next(error_code& ec, Visit&& visit)
boost::in_place_init,
frd_->get(),
buffer_size(result->first),
boost::asio::const_buffers_1{nullptr, 0},
boost::asio::const_buffer{nullptr, 0},
chunk_crlf{},
result->first,
chunk_crlf{},
detail::chunk_last(),
boost::asio::const_buffers_1{nullptr, 0},
boost::asio::const_buffer{nullptr, 0},
chunk_crlf{});
goto go_all_c;
}
@ -179,7 +179,7 @@ next(error_code& ec, Visit&& visit)
boost::in_place_init,
frd_->get(),
buffer_size(result->first),
boost::asio::const_buffers_1{nullptr, 0},
boost::asio::const_buffer{nullptr, 0},
chunk_crlf{},
result->first,
chunk_crlf{});
@ -216,19 +216,19 @@ next(error_code& ec, Visit&& visit)
v_.template emplace<6>(
boost::in_place_init,
buffer_size(result->first),
boost::asio::const_buffers_1{nullptr, 0},
boost::asio::const_buffer{nullptr, 0},
chunk_crlf{},
result->first,
chunk_crlf{},
detail::chunk_last(),
boost::asio::const_buffers_1{nullptr, 0},
boost::asio::const_buffer{nullptr, 0},
chunk_crlf{});
goto go_body_final_c;
}
v_.template emplace<5>(
boost::in_place_init,
buffer_size(result->first),
boost::asio::const_buffers_1{nullptr, 0},
boost::asio::const_buffer{nullptr, 0},
chunk_crlf{},
result->first,
chunk_crlf{});
@ -257,7 +257,7 @@ next(error_code& ec, Visit&& visit)
v_.template emplace<8>(
boost::in_place_init,
detail::chunk_last(),
boost::asio::const_buffers_1{nullptr, 0},
boost::asio::const_buffer{nullptr, 0},
chunk_crlf{});
s_ = do_final_c + 1;
BOOST_BEAST_FALLTHROUGH;

View File

@ -16,9 +16,10 @@
#include <boost/beast/core/handler_ptr.hpp>
#include <boost/beast/core/type_traits.hpp>
#include <boost/beast/core/detail/config.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/asio/post.hpp>
#include <boost/asio/write.hpp>
#include <boost/optional.hpp>
#include <boost/throw_exception.hpp>
@ -77,6 +78,24 @@ public:
{
}
using allocator_type =
boost::asio::associated_allocator_t<Handler>;
allocator_type
get_allocator() const noexcept
{
return boost::asio::get_associated_allocator(h_);
}
using executor_type = boost::asio::associated_executor_t<
Handler, decltype(s_.get_executor())>;
executor_type get_executor() const noexcept
{
return boost::asio::get_associated_executor(
h_, s_.get_executor());
}
void
operator()();
@ -85,24 +104,6 @@ public:
error_code ec,
std::size_t bytes_transferred);
friend
void* asio_handler_allocate(
std::size_t size, write_some_op* op)
{
using boost::asio::asio_handler_allocate;
return asio_handler_allocate(
size, std::addressof(op->h_));
}
friend
void asio_handler_deallocate(
void* p, std::size_t size, write_some_op* op)
{
using boost::asio::asio_handler_deallocate;
asio_handler_deallocate(
p, size, std::addressof(op->h_));
}
friend
bool asio_handler_is_continuation(write_some_op* op)
{
@ -110,14 +111,6 @@ public:
return asio_handler_is_continuation(
std::addressof(op->h_));
}
template<class Function>
friend
void asio_handler_invoke(Function&& f, write_some_op* op)
{
using boost::asio::asio_handler_invoke;
asio_handler_invoke(f, std::addressof(op->h_));
}
};
template<
@ -136,7 +129,8 @@ operator()()
if(ec)
{
BOOST_ASSERT(! f.invoked);
return s_.get_io_service().post(
return boost::asio::post(
s_.get_executor(),
bind_handler(std::move(*this), ec, 0));
}
if(f.invoked)
@ -148,7 +142,8 @@ operator()()
// What else could it be?
BOOST_ASSERT(sr_.is_done());
}
return s_.get_io_service().post(
return boost::asio::post(
s_.get_executor(),
bind_handler(std::move(*this), ec, 0));
}
@ -218,29 +213,29 @@ public:
{
}
using allocator_type =
boost::asio::associated_allocator_t<Handler>;
allocator_type
get_allocator() const noexcept
{
return boost::asio::get_associated_allocator(h_);
}
using executor_type = boost::asio::associated_executor_t<
Handler, decltype(s_.get_executor())>;
executor_type get_executor() const noexcept
{
return boost::asio::get_associated_executor(
h_, s_.get_executor());
}
void
operator()(
error_code ec = {},
std::size_t bytes_transferred = 0);
friend
void* asio_handler_allocate(
std::size_t size, write_op* op)
{
using boost::asio::asio_handler_allocate;
return asio_handler_allocate(
size, std::addressof(op->h_));
}
friend
void asio_handler_deallocate(
void* p, std::size_t size, write_op* op)
{
using boost::asio::asio_handler_deallocate;
asio_handler_deallocate(
p, size, std::addressof(op->h_));
}
friend
bool asio_handler_is_continuation(write_op* op)
{
@ -249,15 +244,6 @@ public:
asio_handler_is_continuation(
std::addressof(op->h_));
}
template<class Function>
friend
void asio_handler_invoke(Function&& f, write_op* op)
{
using boost::asio::asio_handler_invoke;
asio_handler_invoke(
f, std::addressof(op->h_));
}
};
template<
@ -278,7 +264,8 @@ operator()(
if(Predicate{}(sr_))
{
state_ = 1;
return s_.get_io_service().post(
return boost::asio::post(
s_.get_executor(),
bind_handler(std::move(*this), ec, 0));
}
state_ = 2;
@ -338,6 +325,24 @@ public:
{
}
using allocator_type =
boost::asio::associated_allocator_t<Handler>;
allocator_type
get_allocator() const noexcept
{
return boost::asio::get_associated_allocator(d_.handler());
}
using executor_type = boost::asio::associated_executor_t<
Handler, decltype(d_->s.get_executor())>;
executor_type get_executor() const noexcept
{
return boost::asio::get_associated_executor(
d_.handler(), d_->s.get_executor());
}
void
operator()();
@ -345,24 +350,6 @@ public:
operator()(
error_code ec, std::size_t bytes_transferred);
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)
{
@ -370,15 +357,6 @@ public:
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()));
}
};
template<class Stream, class Handler,
@ -483,21 +461,20 @@ template<
class AsyncWriteStream,
bool isRequest, class Body, class Fields,
class WriteHandler>
async_return_type<
WriteHandler,
void(error_code, std::size_t)>
BOOST_ASIO_INITFN_RESULT_TYPE(
WriteHandler, void(error_code, std::size_t))
async_write_some(
AsyncWriteStream& stream,
serializer<isRequest, Body, Fields>& sr,
WriteHandler&& handler)
{
async_completion<
boost::asio::async_completion<
WriteHandler,
void(error_code, std::size_t)> init{handler};
detail::write_some_op<
AsyncWriteStream,
handler_type<WriteHandler,
void(error_code, std::size_t)>,
BOOST_ASIO_HANDLER_TYPE(WriteHandler,
void(error_code, std::size_t)),
isRequest, Body, Fields>{
init.completion_handler, stream, sr}();
return init.result.get();
@ -551,9 +528,8 @@ template<
class AsyncWriteStream,
bool isRequest, class Body, class Fields,
class WriteHandler>
async_return_type<
WriteHandler,
void(error_code, std::size_t)>
BOOST_ASIO_INITFN_RESULT_TYPE(
WriteHandler, void(error_code, std::size_t))
async_write_some(
AsyncWriteStream& stream,
serializer<isRequest, Body, Fields>& sr,
@ -635,9 +611,8 @@ template<
class AsyncWriteStream,
bool isRequest, class Body, class Fields,
class WriteHandler>
async_return_type<
WriteHandler,
void(error_code, std::size_t)>
BOOST_ASIO_INITFN_RESULT_TYPE(
WriteHandler, void(error_code, std::size_t))
async_write_header(
AsyncWriteStream& stream,
serializer<isRequest, Body, Fields>& sr,
@ -651,13 +626,13 @@ async_write_header(
static_assert(is_body_reader<Body>::value,
"BodyReader requirements not met");
sr.split(true);
async_completion<
boost::asio::async_completion<
WriteHandler,
void(error_code, std::size_t)> init{handler};
detail::write_op<
AsyncWriteStream,
handler_type<WriteHandler,
void(error_code, std::size_t)>,
BOOST_ASIO_HANDLER_TYPE(WriteHandler,
void(error_code, std::size_t)),
detail::serializer_is_header_done,
isRequest, Body, Fields>{
init.completion_handler, stream, sr}();
@ -713,9 +688,8 @@ template<
class AsyncWriteStream,
bool isRequest, class Body, class Fields,
class WriteHandler>
async_return_type<
WriteHandler,
void(error_code, std::size_t)>
BOOST_ASIO_INITFN_RESULT_TYPE(
WriteHandler, void(error_code, std::size_t))
async_write(
AsyncWriteStream& stream,
serializer<isRequest, Body, Fields>& sr,
@ -729,13 +703,13 @@ async_write(
static_assert(is_body_reader<Body>::value,
"BodyReader requirements not met");
sr.split(false);
async_completion<
boost::asio::async_completion<
WriteHandler,
void(error_code, std::size_t)> init{handler};
detail::write_op<
AsyncWriteStream,
handler_type<WriteHandler,
void(error_code, std::size_t)>,
BOOST_ASIO_HANDLER_TYPE(WriteHandler,
void(error_code, std::size_t)),
detail::serializer_is_done,
isRequest, Body, Fields>{
init.completion_handler, stream, sr}();
@ -789,9 +763,8 @@ template<
class AsyncWriteStream,
bool isRequest, class Body, class Fields,
class WriteHandler>
async_return_type<
WriteHandler,
void(error_code, std::size_t)>
BOOST_ASIO_INITFN_RESULT_TYPE(
WriteHandler, void(error_code, std::size_t))
async_write(
AsyncWriteStream& stream,
message<isRequest, Body, Fields>& msg,
@ -804,13 +777,13 @@ async_write(
"Body requirements not met");
static_assert(is_body_reader<Body>::value,
"BodyReader requirements not met");
async_completion<
boost::asio::async_completion<
WriteHandler,
void(error_code, std::size_t)> init{handler};
detail::write_msg_op<
AsyncWriteStream,
handler_type<WriteHandler,
void(error_code, std::size_t)>,
BOOST_ASIO_HANDLER_TYPE(WriteHandler,
void(error_code, std::size_t)),
isRequest, Body, Fields>{
init.completion_handler, stream, msg}();
return init.result.get();
@ -843,17 +816,13 @@ public:
if(os_.fail())
return;
std::size_t bytes_transferred = 0;
using boost::asio::buffer_cast;
using boost::asio::buffer_size;
for(auto it = buffers.begin();
it != buffers.end(); ++it)
for(auto b : buffers_range(buffers))
{
boost::asio::const_buffer b = *it;
auto const n = buffer_size(b);
os_.write(buffer_cast<char const*>(b), n);
os_.write(reinterpret_cast<char const*>(
b.data()), b.size());
if(os_.fail())
return;
bytes_transferred += n;
bytes_transferred += b.size();
}
sr_.consume(bytes_transferred);
}

View File

@ -11,10 +11,10 @@
#define BOOST_BEAST_HTTP_READ_HPP
#include <boost/beast/core/detail/config.hpp>
#include <boost/beast/core/async_result.hpp>
#include <boost/beast/core/error.hpp>
#include <boost/beast/http/basic_parser.hpp>
#include <boost/beast/http/message.hpp>
#include <boost/asio/async_result.hpp>
namespace boost {
namespace beast {
@ -185,7 +185,7 @@ read_some(
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`.
The completion handler will receive as a parameter the number
of octets processed from the dynamic buffer. The octets should
@ -197,12 +197,8 @@ template<
class DynamicBuffer,
bool isRequest, class Derived,
class ReadHandler>
#if BOOST_BEAST_DOXYGEN
void_or_deduced
#else
async_return_type<
ReadHandler, void(error_code, std::size_t)>
#endif
BOOST_ASIO_INITFN_RESULT_TYPE(
ReadHandler, void(error_code, std::size_t))
async_read_some(
AsyncReadStream& stream,
DynamicBuffer& buffer,
@ -375,7 +371,7 @@ read_header(
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`.
@note The implementation will call @ref basic_parser::eager
with the value `false` on the parser passed in.
@ -385,12 +381,8 @@ template<
class DynamicBuffer,
bool isRequest, class Derived,
class ReadHandler>
#if BOOST_BEAST_DOXYGEN
void_or_deduced
#else
async_return_type<
ReadHandler, void(error_code, std::size_t)>
#endif
BOOST_ASIO_INITFN_RESULT_TYPE(
ReadHandler, void(error_code, std::size_t))
async_read_header(
AsyncReadStream& stream,
DynamicBuffer& buffer,
@ -563,7 +555,7 @@ read(
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`.
@note The implementation will call @ref basic_parser::eager
with the value `true` on the parser passed in.
@ -573,13 +565,8 @@ template<
class DynamicBuffer,
bool isRequest, class Derived,
class ReadHandler>
#if BOOST_BEAST_DOXYGEN
void_or_deduced
#else
async_return_type<
ReadHandler,
void(error_code, std::size_t)>
#endif
BOOST_ASIO_INITFN_RESULT_TYPE(
ReadHandler, void(error_code, std::size_t))
async_read(
AsyncReadStream& stream,
DynamicBuffer& buffer,
@ -754,20 +741,15 @@ read(
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,
bool isRequest, class Body, class Allocator,
class ReadHandler>
#if BOOST_BEAST_DOXYGEN
void_or_deduced
#else
async_return_type<
ReadHandler,
void(error_code, std::size_t)>
#endif
BOOST_ASIO_INITFN_RESULT_TYPE(
ReadHandler, void(error_code, std::size_t))
async_read(
AsyncReadStream& stream,
DynamicBuffer& buffer,

View File

@ -132,7 +132,7 @@ private:
using cb4_t = buffers_suffix<buffers_cat_view<
typename Fields::reader::const_buffers_type,// header
detail::chunk_size, // chunk-size
boost::asio::const_buffers_1, // chunk-ext
boost::asio::const_buffer, // chunk-ext
chunk_crlf, // crlf
typename reader::const_buffers_type, // body
chunk_crlf>>; // crlf
@ -140,7 +140,7 @@ private:
using cb5_t = buffers_suffix<buffers_cat_view<
detail::chunk_size, // chunk-header
boost::asio::const_buffers_1, // chunk-ext
boost::asio::const_buffer, // chunk-ext
chunk_crlf, // crlf
typename reader::const_buffers_type, // body
chunk_crlf>>; // crlf
@ -148,30 +148,30 @@ private:
using cb6_t = buffers_suffix<buffers_cat_view<
detail::chunk_size, // chunk-header
boost::asio::const_buffers_1, // chunk-size
boost::asio::const_buffer, // chunk-size
chunk_crlf, // crlf
typename reader::const_buffers_type, // body
chunk_crlf, // crlf
boost::asio::const_buffers_1, // chunk-final
boost::asio::const_buffers_1, // trailers
boost::asio::const_buffer, // chunk-final
boost::asio::const_buffer, // trailers
chunk_crlf>>; // crlf
using pcb6_t = buffers_prefix_view<cb6_t const&>;
using cb7_t = buffers_suffix<buffers_cat_view<
typename Fields::reader::const_buffers_type,// header
detail::chunk_size, // chunk-size
boost::asio::const_buffers_1, // chunk-ext
boost::asio::const_buffer, // chunk-ext
chunk_crlf, // crlf
typename reader::const_buffers_type, // body
chunk_crlf, // crlf
boost::asio::const_buffers_1, // chunk-final
boost::asio::const_buffers_1, // trailers
boost::asio::const_buffer, // chunk-final
boost::asio::const_buffer, // trailers
chunk_crlf>>; // crlf
using pcb7_t = buffers_prefix_view<cb7_t const&>;
using cb8_t = buffers_suffix<buffers_cat_view<
boost::asio::const_buffers_1, // chunk-final
boost::asio::const_buffers_1, // trailers
boost::asio::const_buffer, // chunk-final
boost::asio::const_buffer, // trailers
chunk_crlf>>; // crlf
using pcb8_t = buffers_prefix_view<cb8_t const&>;

Some files were not shown because too many files have changed in this diff Show More