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: Version 124:
* Fix for a test matrix compiler * Fix for a test matrix compiler

View File

@ -21,7 +21,6 @@ if (MSVC)
add_definitions (-D_WIN32_WINNT=0x0601) add_definitions (-D_WIN32_WINNT=0x0601)
add_definitions (-D_SCL_SECURE_NO_WARNINGS=1) add_definitions (-D_SCL_SECURE_NO_WARNINGS=1)
add_definitions (-D_CRT_SECURE_NO_WARNINGS=1) add_definitions (-D_CRT_SECURE_NO_WARNINGS=1)
add_definitions (-DBOOST_ASIO_NO_DEPRECATED=1)
add_compile_options( add_compile_options(
/bigobj # large object file format /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 # VFALCO I want static but "b2 stage" builds a minimal set which excludes static
add_definitions (-DBOOST_ALL_STATIC_LINK=1) 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_ARRAY=1)
add_definitions (-DBOOST_ASIO_DISABLE_BOOST_BIND=1) add_definitions (-DBOOST_ASIO_DISABLE_BOOST_BIND=1)
add_definitions (-DBOOST_ASIO_DISABLE_BOOST_DATE_TIME=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_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 __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 __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 __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`]] [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 [table Global Variables
[[Name][Description]] [[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 A variable of type
[@http://www.boost.org/doc/html/boost_asio/reference/io_service.html `boost::asio::io_service`] [@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 a which is running on one separate thread, and upon which an
[@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/executor_work.html `boost::asio::executor_work`]
object has been constructed. 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`. 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, Determine if the `get_executor` member function is present.
and returns an __io_service__.
]] ]]
[[ [[
[link beast.ref.boost__beast__is_async_read_stream `is_async_read_stream`] [link beast.ref.boost__beast__is_async_read_stream `is_async_read_stream`]

View File

@ -9,36 +9,71 @@
[section Buffer Types] [section Buffer Types]
__Asio__ provides the __ConstBufferSequence__ and __MutableBufferSequence__ To facilitate working with instances of the __ConstBufferSequence__ and
concepts, whose models provide ranges of buffers, as well as the __streambuf__ __MutableBufferSequence__ concepts introduced in __Asio__, Beast treats
class which encapsulates memory storage that may be automatically resized as those sequences as a special type of range. The following algorithms and
required, where the memory is divided into an input sequence followed by an wrappers are provided which transform these ranges efficiently using lazy
output sequence. The Networking TS (__N4588__) generalizes this `streambuf` evaluation. No memory allocations are used in the transformations; instead,
interface into the __DynamicBuffer__ concept. Beast algorithms which require they create lightweight iterators over the existing, unmodified memory
resizable buffers accept dynamic buffer objects as templated parameters. buffers. Control of buffers is retained by the caller; ownership is not
These metafunctions check if types match the buffer concepts: transferred.
[table Buffer Type Checks [table Buffer Algorithms and Types
[[Name][Description]] [[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 The __DynamicBuffer__ concept introduced in __Asio__ models a buffer
of scenarios: sequence which supports an owning, resizable range. Beast provides this
set of additional implementations of the dynamic buffer concept:
[table Dynamic Buffer Implementations [table Dynamic Buffer Implementations
[[Name][Description]] [[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 These two functions facilitate buffer interoperability with standard
output streams. output streams.

View File

@ -38,23 +38,6 @@ composed operations:
[table Asynchronous Helpers [table Asynchronous Helpers
[[Name][Description]] [[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`] [link beast.ref.boost__beast__bind_handler `bind_handler`]
][ ][
@ -66,15 +49,6 @@ composed operations:
`asio_handler_invoke` associated with the original completion handler. `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`] [link beast.ref.boost__beast__handler_ptr `handler_ptr`]
][ ][
@ -87,14 +61,6 @@ composed operations:
associated allocator, benefiting from all handler memory management associated allocator, benefiting from all handler memory management
optimizations transparently. 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. * 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 * Forgetting to include a return statement after calling an
initiating function. initiating function.
* Calling a synchronous function by accident. In general composed * Calling a synchronous function by accident. In general composed
operations should not block for long periods of time, since this 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 * Forgetting to provide `executor_type` and `get_executor` for the
operation. This will cause undefined behavior if someone calls composed operation. This will cause undefined behavior. For example,
the initiating function with a strand-wrapped function object, if someone calls the initiating function with a strand-wrapped
and there is more than thread running on the `io_service`. 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 * 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 to invoke the final handler. This breaks the following initiating
function guarantee: ['Regardless of whether the asynchronous operation function guarantee: ['Regardless of whether the asynchronous operation
completes immediately or not, the handler will not be invoked from completes immediately or not, the handler will not be invoked from
within this function. Invocation of the handler will be performed 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 The function
[link beast.ref.boost__beast__bind_handler `bind_handler`] [link beast.ref.boost__beast__bind_handler `bind_handler`]
is provided for this purpose. 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 If a read stream algorithm cannot complete its operation without exceeding
the maximum specified size of the dynamic buffer provided, the error the maximum specified size of the dynamic buffer provided, the error
[link beast.ref.boost__beast__http__error `buffer_overflow`] [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 is returned. This is one technique which may be used to impose a limit on
HTTP message header for protection from buffer overflow attacks. The the maximum size of an HTTP message header for protection from buffer
following code will print the error message: overflow attacks. The following code will print the error message:
[http_snippet_6] [http_snippet_6]

View File

@ -31,7 +31,7 @@ field value.
[heading Serializing Chunks] [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 when a message returns `true` from
[link beast.ref.boost__beast__http__message.chunked.overload1 `message::chunked`]. [link beast.ref.boost__beast__http__message.chunked.overload1 `message::chunked`].
The boundaries between chunks emitted by the serializer are implementation 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. the stream wrapper are passed to next layer's constructor.
Here we declare a websocket stream over a TCP/IP socket with ownership 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: socket's constructor:
[ws_snippet_2] [ws_snippet_2]
@ -27,7 +27,7 @@ socket's constructor:
[heading Using SSL] [heading Using SSL]
To use WebSockets over SSL, use an instance of the `boost::asio::ssl::stream` 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: and `ssl::context` arguments are forwarded to the wrapped stream's constructor:
[wss_snippet_1] [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 on the received HTTP response message. For example, to check that the
response to a basic authentication challenge is valid. To achieve this, response to a basic authentication challenge is valid. To achieve this,
overloads of the handshake member function allow the caller to store the 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`] [link beast.ref.boost__beast__websocket__response_type `response_type`]
as follows: as follows:

View File

@ -31,9 +31,12 @@ handlers, stackful or stackless coroutines, and even futures:
[ws_snippet_21] [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 underlying stream is left to the callers, permitting any implementation
strategy including one that does not require threads for environments strategy including one that does not require threads for environments
where threads are unavailable. Beast WebSocket itself does not use 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`] [link beast.ref.boost__beast__websocket__stream `stream`]
is not thread safe. Callers are responsible for synchronizing operations on 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 socket using an implicit or explicit strand, as per the Asio documentation.
The asynchronous interface supports one of each of the following operations The websocket stream asynchronous interface supports one of each of the
to be active at the same time: 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_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`] * [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] [heading Associated Types]
* [link beast.ref.boost__beast__is_dynamic_buffer `is_dynamic_buffer`] * `boost::asio::is_dynamic_buffer`
* __ConstBufferSequence__ * __ConstBufferSequence__
* __MutableBufferSequence__ * __MutableBufferSequence__

View File

@ -190,7 +190,7 @@ In this table:
[ [
If `(v < 11 && b)`, then all "close" tokens present in the If `(v < 11 && b)`, then all "close" tokens present in the
value are removed, and the "keep-alive" token is added to 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" If `(v < 11 && ! b)`, then all "close" and "keep-alive"
tokens present in the value are removed. 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 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 be optimal for interacting with Asio, and for other tasks such as incremental
parsing of data in buffers (for example, parsing websocket frames stored 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 During the development of Beast the authors have studied other software
packages and in particular the comments left during the Boost Review process 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 The start-line data members are replaced by traditional accessors
non-owning references to string buffers. The method is stored using using non-owning references to string buffers. The method is stored
a simple integer instead of the entire string, for the case where using a simple integer instead of the entire string, for the case
the method is recognized from the set of known verb strings. where the method is recognized from the set of known verb strings.
Now we add a requirement to the fields type: management of the Now we add a requirement to the fields type: management of the
corresponding string is delegated to the [*Fields] container, which can 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 The only requirement in Beast is that calls to asynchronous initiation
functions are made from the same implicit or explicit strand. For 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 is single threaded, this counts as an implicit strand and no performance
costs associated with mutexes are incurred. costs associated with mutexes are incurred.

View File

@ -174,9 +174,6 @@
<entry valign="top"> <entry valign="top">
<bridgehead renderas="sect3">Classes</bridgehead> <bridgehead renderas="sect3">Classes</bridgehead>
<simplelist type="vert" columns="1"> <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_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__basic_multi_buffer">basic_multi_buffer</link></member>
<member><link linkend="beast.ref.boost__beast__buffered_read_stream">buffered_read_stream</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_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">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__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_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__iequal">iequal</link></member>
<member><link linkend="beast.ref.boost__beast__iless">iless</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> <member><link linkend="beast.ref.boost__beast__multi_buffer">multi_buffer</link></member>
@ -236,15 +231,12 @@
<bridgehead renderas="sect3">Type Traits</bridgehead> <bridgehead renderas="sect3">Type Traits</bridgehead>
<simplelist type="vert" columns="1"> <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__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_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_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_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_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_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_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_stream">is_sync_stream</link></member>
<member><link linkend="beast.ref.boost__beast__is_sync_write_stream">is_sync_write_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 = \ PREDEFINED = \
BOOST_BEAST_DOXYGEN \ BOOST_BEAST_DOXYGEN \
BOOST_BEAST_USE_POSIX_FILE=1 \ 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 = EXPAND_AS_DEFINED =
SKIP_FUNCTION_MACROS = YES SKIP_FUNCTION_MACROS = YES

View File

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

View File

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

View File

@ -61,7 +61,8 @@ is_ssl_handshake(
ConstBufferSequence const& buffers) ConstBufferSequence const& buffers)
{ {
// Make sure buffers meets the requirements // 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"); "ConstBufferSequence requirements not met");
// We need at least one byte to really do anything // We need at least one byte to really do anything
@ -135,7 +136,8 @@ detect_ssl(
// Make sure arguments meet the requirements // Make sure arguments meet the requirements
static_assert(beast::is_sync_read_stream<SyncReadStream>::value, static_assert(beast::is_sync_read_stream<SyncReadStream>::value,
"SyncReadStream requirements not met"); "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"); "DynamicBuffer requirements not met");
// Loop until an error occurs or we get a definitive answer // Loop until an error occurs or we get a definitive answer
@ -219,15 +221,15 @@ detect_ssl(
Regardless of whether the asynchronous operation completes Regardless of whether the asynchronous operation completes
immediately or not, the handler will not be invoked from within immediately or not, the handler will not be invoked from within
this function. Invocation of the handler will be performed in a 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< template<
class AsyncReadStream, class AsyncReadStream,
class DynamicBuffer, class DynamicBuffer,
class CompletionToken> 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, 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( async_detect_ssl(
AsyncReadStream& stream, AsyncReadStream& stream,
DynamicBuffer& buffer, DynamicBuffer& buffer,
@ -249,9 +251,9 @@ template<
class AsyncReadStream, class AsyncReadStream,
class DynamicBuffer, class DynamicBuffer,
class CompletionToken> class CompletionToken>
boost::beast::async_return_type< BOOST_ASIO_INITFN_RESULT_TYPE(
CompletionToken, CompletionToken,
void(boost::beast::error_code, boost::tribool)> void(boost::beast::error_code, boost::tribool))
async_detect_ssl( async_detect_ssl(
AsyncReadStream& stream, AsyncReadStream& stream,
DynamicBuffer& buffer, DynamicBuffer& buffer,
@ -262,26 +264,29 @@ async_detect_ssl(
// Make sure arguments meet the requirements // Make sure arguments meet the requirements
static_assert(beast::is_async_read_stream<AsyncReadStream>::value, static_assert(beast::is_async_read_stream<AsyncReadStream>::value,
"SyncReadStream requirements not met"); "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"); "DynamicBuffer requirements not met");
// This helper manages some of the handler's lifetime and // This helper manages some of the handler's lifetime and
// uses the result and handler specializations associated with // uses the result and handler specializations associated with
// the completion token to help customize the return value. // 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}; CompletionToken, void(beast::error_code, boost::tribool)> init{token};
// Create the composed operation and launch it. This is a constructor // 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, // to convert the completion token into the correct handler type,
// allowing user defined specializations of the async result template // allowing user defined specializations of the async result template
// to take effect. // to take effect.
// //
detect_ssl_op<AsyncReadStream, DynamicBuffer, beast::handler_type< detect_ssl_op<
CompletionToken, void(beast::error_code, boost::tribool)>>{ AsyncReadStream,
stream, buffer, init.completion_handler}( DynamicBuffer,
beast::error_code{}, 0); 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. // This hook lets the caller see a return value when appropriate.
// For example this might return std::future<error_code, boost::tribool> if // 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 // Determines if the next asynchronous operation represents a
// continuation of the asynchronous flow of control associated // continuation of the asynchronous flow of control associated
// with the final handler. If we are past step two, it means // 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_)); 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 // Our main entry point. This will get called as our
// intermediate operations complete. Definition below. // 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 // We need to invoke the handler, but the guarantee
// is that the handler will not be called before the // is that the handler will not be called before the
// call to async_detect_ssl returns, so we must post // 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 // `bind_handler` lets us bind arguments in a safe way
// that preserves the type customization hooks of the // that preserves the type customization hooks of the
// original handler. // original handler.
step_ = 1; step_ = 1;
return stream_.get_io_service().post( return boost::asio::post(
stream_.get_executor(),
beast::bind_handler(std::move(*this), ec, 0)); beast::bind_handler(std::move(*this), ec, 0));
} }

View File

@ -10,21 +10,21 @@
#ifndef BOOST_BEAST_EXAMPLE_COMMON_SESSION_ALLOC_HPP #ifndef BOOST_BEAST_EXAMPLE_COMMON_SESSION_ALLOC_HPP
#define 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_continuation_hook.hpp>
#include <boost/asio/handler_invoke_hook.hpp>
#include <boost/assert.hpp> #include <boost/assert.hpp>
#include <boost/intrusive/list.hpp> #include <boost/intrusive/list.hpp>
#include <algorithm> #include <algorithm>
#include <cstddef> #include <cstddef>
#include <utility> #include <utility>
namespace detail {
template<class Context> template<class Context>
class session_alloc_base class session_alloc_base
{ {
template<class Handler> protected:
class wrapped_handler;
class pool_t class pool_t
{ {
using hook_type = using hook_type =
@ -78,23 +78,18 @@ class session_alloc_base
boost::intrusive::constant_time_size< boost::intrusive::constant_time_size<
true>>::type; true>>::type;
Context* ctx_;
std::size_t refs_ = 1; // shared count std::size_t refs_ = 1; // shared count
std::size_t high_ = 0; // highest used std::size_t high_ = 0; // highest used
std::size_t size_ = 0; // size of buf_ std::size_t size_ = 0; // size of buf_
char* buf_ = nullptr; // a large block char* buf_ = nullptr; // a large block
list_type list_; // list of allocations list_type list_; // list of allocations
explicit pool_t() = default;
pool_t(Context* ctx)
: ctx_(ctx)
{
}
public: public:
static static
pool_t& pool_t&
construct(Context* ctx); construct();
~pool_t(); ~pool_t();
@ -110,73 +105,178 @@ class session_alloc_base
void void
dealloc(void* pv, std::size_t n); 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> template<class T>
class session_alloc : public session_alloc_base<Context> class session_alloc
: private detail::session_alloc_base<void>
{ {
template<class U, class C> template<class U>
friend class session_alloc; 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: public:
using value_type = T; using value_type = T;
using is_always_equal = std::false_type; using is_always_equal = std::false_type;
@ -193,21 +293,32 @@ public:
using other = session_alloc<U>; using other = session_alloc<U>;
}; };
session_alloc() = default; session_alloc& operator=(session_alloc const&) = delete;
session_alloc(session_alloc const&) = default;
~session_alloc()
{
pool_.release();
}
session_alloc()
: pool_(pool_t::construct())
{
}
session_alloc(session_alloc const& other) noexcept
: pool_(other.pool_.addref())
{
}
template<class U> template<class U>
session_alloc(session_alloc<U> const& other) session_alloc(session_alloc<U> const& other) noexcept
: session_alloc_base<Context>(static_cast< : pool_(other.pool_)
session_alloc_base<Context> const&>(other))
{ {
} }
explicit template<class Handler>
session_alloc(Context& ctx) wrapped_handler<typename std::decay<Handler>::type>
: session_alloc_base<Context>(ctx) wrap(Handler&& handler);
{
}
value_type* value_type*
allocate(size_type n) allocate(size_type n)
@ -257,209 +368,67 @@ public:
{ {
return ! (lhs == rhs); 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> 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_; return alloc_;
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_));
}
};
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
template<class Context> template<class T>
template<class Handler>
auto auto
session_alloc_base<Context>:: session_alloc<T>::
pool_t:: wrap(Handler&& handler) ->
construct(Context* ctx) -> wrapped_handler<typename std::decay<Handler>::type>
pool_t&
{ {
using boost::asio::asio_handler_allocate; return wrapped_handler<
return *new(asio_handler_allocate( typename std::decay<Handler>::type>(
sizeof(pool_t), ctx)) pool_t{ctx}; std::forward<Handler>(handler), *this);
} }
template<class Context> namespace boost {
session_alloc_base<Context>:: namespace asio {
pool_t:: template<class T, class Handler, class Executor>
~pool_t() struct associated_executor<
session_alloc<T>::wrapped_handler<Handler>, Executor>
{ {
BOOST_ASSERT(list_.size() == 0); using type = typename
if(buf_) 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; return associated_executor<
asio_handler_deallocate(buf_, size_, ctx_); Handler, Executor>::get(h.h_, ex);
} }
} };
} // asio
template<class Context> } // boost
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();
}
#endif #endif

View File

@ -52,9 +52,6 @@ public:
/// Structure for use with deprecated impl_type. /// Structure for use with deprecated impl_type.
using impl_struct = typename stream_type::impl_struct; 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. /// The type of the next layer.
using next_layer_type = typename stream_type::next_layer_type; using next_layer_type = typename stream_type::next_layer_type;
@ -64,14 +61,16 @@ public:
ssl_stream( ssl_stream(
boost::asio::ip::tcp::socket socket, boost::asio::ip::tcp::socket socket,
boost::asio::ssl::context& ctx) 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) , ctx_(&ctx)
{ {
p_->next_layer() = std::move(socket); p_->next_layer() = std::move(socket);
} }
ssl_stream(ssl_stream&& other) 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_) , ctx_(other.ctx_)
{ {
using std::swap; using std::swap;
@ -80,8 +79,8 @@ public:
ssl_stream& operator=(ssl_stream&& other) ssl_stream& operator=(ssl_stream&& other)
{ {
std::unique_ptr<stream_type> p( std::unique_ptr<stream_type> p(new stream_type{
new stream_type{other.get_io_service(), other.ctx_}); other.get_executor().context(), other.ctx_});
using std::swap; using std::swap;
swap(p_, p); swap(p_, p);
swap(p_, other.p_); swap(p_, other.p_);
@ -89,10 +88,10 @@ public:
return *this; return *this;
} }
boost::asio::io_service& decltype(p_->get_executor())
get_io_service() get_executor() noexcept
{ {
return p_->get_io_service(); return p_->get_executor();
} }
native_handle_type native_handle_type
@ -101,12 +100,6 @@ public:
return p_->native_handle(); return p_->native_handle();
} }
impl_type
impl()
{
return p_->impl();
}
next_layer_type const& next_layer_type const&
next_layer() 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, static_assert(is_sync_stream<SyncStream>::value,
"SyncStream requirements not met"); "SyncStream requirements not met");
static_assert(is_dynamic_buffer<DynamicBuffer>::value, static_assert(
boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
"DynamicBuffer requirements not met"); "DynamicBuffer requirements not met");
// Insert or replace the Expect field // Insert or replace the Expect field
@ -123,7 +124,8 @@ receive_expect_100_continue(
static_assert(is_sync_stream<SyncStream>::value, static_assert(is_sync_stream<SyncStream>::value,
"SyncStream requirements not met"); "SyncStream requirements not met");
static_assert(is_dynamic_buffer<DynamicBuffer>::value, static_assert(
boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
"DynamicBuffer requirements not met"); "DynamicBuffer requirements not met");
// Declare a parser for a request with a string body // 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, static_assert(is_sync_write_stream<SyncWriteStream>::value,
"SyncWriteStream requirements not met"); "SyncWriteStream requirements not met");
using boost::asio::buffer_cast;
using boost::asio::buffer_size;
// Set up the response. We use the buffer_body type, // Set up the response. We use the buffer_body type,
// allowing serialization to use manually provided buffers. // allowing serialization to use manually provided buffers.
response<buffer_body> res; response<buffer_body> res;
@ -293,7 +292,8 @@ void do_server_head(
{ {
static_assert(is_sync_stream<SyncStream>::value, static_assert(is_sync_stream<SyncStream>::value,
"SyncStream requirements not met"); "SyncStream requirements not met");
static_assert(is_dynamic_buffer<DynamicBuffer>::value, static_assert(
boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
"DynamicBuffer requirments not met"); "DynamicBuffer requirments not met");
// We deliver this payload for all GET requests // We deliver this payload for all GET requests
@ -386,7 +386,8 @@ do_head_request(
// Do some type checking to be a good citizen // Do some type checking to be a good citizen
static_assert(is_sync_stream<SyncStream>::value, static_assert(is_sync_stream<SyncStream>::value,
"SyncStream requirements not met"); "SyncStream requirements not met");
static_assert(is_dynamic_buffer<DynamicBuffer>::value, static_assert(
boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
"DynamicBuffer requirments not met"); "DynamicBuffer requirments not met");
// The interfaces we are using are low level and do not // The interfaces we are using are low level and do not
@ -589,10 +590,6 @@ public:
void void
operator()(error_code& ec, ConstBufferSequence const& buffers) const 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 // Error codes must be cleared on success
ec = {}; ec = {};
@ -600,15 +597,16 @@ public:
std::size_t bytes_transferred = 0; std::size_t bytes_transferred = 0;
// Loop over the buffer sequence // 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 // This is the next buffer in the sequence
boost::asio::const_buffer const buffer = *it; boost::asio::const_buffer const buffer = *it;
// Write it to the std::ostream // Write it to the std::ostream
os_.write( os_.write(
buffer_cast<char const*>(buffer), reinterpret_cast<char const*>(buffer.data()),
buffer_size(buffer)); buffer.size());
// If the std::ostream fails, convert it to an error code // If the std::ostream fails, convert it to an error code
if(os_.fail()) if(os_.fail())
@ -714,13 +712,12 @@ read_istream(
if(is.rdbuf()->in_avail() > 0) if(is.rdbuf()->in_avail() > 0)
{ {
// Get a mutable buffer sequence for writing // 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())); static_cast<std::size_t>(is.rdbuf()->in_avail()));
// Now get everything we can from the istream // Now get everything we can from the istream
buffer.commit(static_cast<std::size_t>(is.readsome( buffer.commit(static_cast<std::size_t>(is.readsome(
boost::asio::buffer_cast<char*>(mb), reinterpret_cast<char*>(b.data()), b.size())));
boost::asio::buffer_size(mb))));
} }
else if(buffer.size() == 0) else if(buffer.size() == 0)
{ {
@ -729,12 +726,10 @@ read_istream(
if(! is.eof()) if(! is.eof())
{ {
// Get a mutable buffer sequence for writing // 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. // Try to get more from the istream. This might block.
is.read( is.read(reinterpret_cast<char*>(b.data()), b.size());
boost::asio::buffer_cast<char*>(mb),
boost::asio::buffer_size(mb));
// If an error occurs on the istream then return it to the caller. // If an error occurs on the istream then return it to the caller.
if(is.fail() && ! is.eof()) if(is.fail() && ! is.eof())

View File

@ -23,7 +23,7 @@ auto
async_echo(AsyncStream& stream, CompletionToken&& token) 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 //[example_core_echo_op_2
@ -61,14 +61,14 @@ async_echo(AsyncStream& stream, CompletionToken&& token)
Regardless of whether the asynchronous operation completes Regardless of whether the asynchronous operation completes
immediately or not, the handler will not be invoked from within immediately or not, the handler will not be invoked from within
this function. Invocation of the handler will be performed in a 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< template<
class AsyncStream, class AsyncStream,
class CompletionToken> 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, 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( async_echo(
AsyncStream& stream, AsyncStream& stream,
CompletionToken&& token); CompletionToken&& token);
@ -95,11 +95,13 @@ class echo_op
// The buffer used to hold the input and output data. // The buffer used to hold the input and output data.
// //
// We use a custom allocator for performance, this allows // 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 // re-use of memory allocated by composed operations during
// a continuation. // 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 // handler_ptr requires that the first parameter to the
// contained object constructor is a reference to the // contained object constructor is a reference to the
@ -108,7 +110,7 @@ class echo_op
explicit state(Handler& handler, AsyncStream& stream_) explicit state(Handler& handler, AsyncStream& stream_)
: stream(stream_) : stream(stream_)
, buffer((std::numeric_limits<std::size_t>::max)(), , 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 // The operation's data is kept in a cheap-to-copy smart
// pointer container called `handler_ptr`. This efficiently // pointer container called `handler_ptr`. This efficiently
// satisfies the CopyConstructible requirements of completion // satisfies the CopyConstructible requirements of completion
// handlers. // handlers with expensive-to-copy state.
// //
// `handler_ptr` uses these memory allocation hooks associated // `handler_ptr` uses the allocator associated with the final
// with the final completion handler, in order to allocate the // completion handler, in order to allocate the storage for `state`.
// storage for `state`:
//
// asio_handler_allocate
// asio_handler_deallocate
// //
boost::beast::handler_ptr<state, Handler> p_; 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 // The entry point for this handler. This will get called
// as our intermediate operations complete. Definition below. // as our intermediate operations complete. Definition below.
// //
void operator()(boost::beast::error_code ec, std::size_t bytes_transferred); 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 //[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 // Determines if the next asynchronous operation represents a
// continuation of the asynchronous flow of control associated // continuation of the asynchronous flow of control associated
// with the final handler. If we are past step one, it means // 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 // Read a line and echo it back
// //
template<class AsyncStream, class CompletionToken> 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) async_echo(AsyncStream& stream, CompletionToken&& token)
{ {
// Make sure stream meets the requirements. We use static_assert // 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 // uses the result and handler specializations associated with
// the completion token to help customize the return value. // 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 // 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, // to convert the completion token into the correct handler type,
// allowing user-defined specializations of the async_result template // allowing user-defined specializations of the async_result template
// to be used. // to be used.
// //
echo_op<AsyncStream, boost::beast::handler_type<CompletionToken, void(boost::beast::error_code)>>{ echo_op<
stream, init.completion_handler}(boost::beast::error_code{}, 0); 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. // This hook lets the caller see a return value when appropriate.
// For example this might return std::future<error_code> if // 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) int main(int, char** argv)
{ {
using address_type = boost::asio::ip::address;
using socket_type = boost::asio::ip::tcp::socket; using socket_type = boost::asio::ip::tcp::socket;
using endpoint_type = boost::asio::ip::tcp::endpoint; using endpoint_type = boost::asio::ip::tcp::endpoint;
// Create a listening socket, accept a connection, perform // Create a listening socket, accept a connection, perform
// the echo, and then shut everything down and exit. // the echo, and then shut everything down and exit.
boost::asio::io_service ios; boost::asio::io_context ioc;
socket_type sock{ios}; socket_type sock{ioc};
boost::asio::ip::tcp::acceptor acceptor{ios}; boost::asio::ip::tcp::acceptor acceptor{ioc};
endpoint_type ep{address_type::from_string("0.0.0.0"), 0}; endpoint_type ep{boost::asio::ip::make_address("0.0.0.0"), 0};
acceptor.open(ep.protocol()); acceptor.open(ep.protocol());
acceptor.bind(ep); acceptor.bind(ep);
acceptor.listen(); acceptor.listen();
@ -353,6 +331,6 @@ int main(int, char** argv)
if(ec) if(ec)
std::cerr << argv[0] << ": " << ec.message() << std::endl; std::cerr << argv[0] << ": " << ec.message() << std::endl;
}); });
ios.run(); ioc.run();
return 0; return 0;
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -75,7 +75,7 @@ private:
// The timer for putting a deadline on connection processing. // The timer for putting a deadline on connection processing.
boost::asio::basic_waitable_timer<std::chrono::steady_clock> deadline_{ 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. // Asynchronously receive a complete request message.
void void
@ -231,16 +231,16 @@ main(int argc, char* argv[])
return EXIT_FAILURE; 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])); 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::acceptor acceptor{ioc, {address, port}};
tcp::socket socket{ios}; tcp::socket socket{ioc};
http_server(acceptor, socket); http_server(acceptor, socket);
ios.run(); ioc.run();
} }
catch(std::exception const& e) catch(std::exception const& e)
{ {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -47,8 +47,8 @@ int main(int argc, char** argv)
auto const port = argv[2]; auto const port = argv[2];
auto const text = argv[3]; auto const text = argv[3];
// The io_service is required for all I/O // The io_context is required for all I/O
boost::asio::io_service ios; boost::asio::io_context ioc;
// The SSL context is required, and holds certificates // The SSL context is required, and holds certificates
ssl::context ctx{ssl::context::sslv23_client}; ssl::context ctx{ssl::context::sslv23_client};
@ -57,14 +57,14 @@ int main(int argc, char** argv)
load_root_certificates(ctx); load_root_certificates(ctx);
// These objects perform our I/O // These objects perform our I/O
tcp::resolver resolver{ios}; tcp::resolver resolver{ioc};
websocket::stream<ssl::stream<tcp::socket>> ws{ios, ctx}; websocket::stream<ssl::stream<tcp::socket>> ws{ioc, ctx};
// Look up the domain name // 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 // 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 // Perform the SSL handshake
ws.next_layer().handshake(ssl::stream_base::client); 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 port = argv[2];
auto const text = argv[3]; auto const text = argv[3];
// The io_service is required for all I/O // The io_context is required for all I/O
boost::asio::io_service ios; boost::asio::io_context ioc;
// These objects perform our I/O // These objects perform our I/O
tcp::resolver resolver{ios}; tcp::resolver resolver{ioc};
websocket::stream<tcp::socket> ws{ios}; websocket::stream<tcp::socket> ws{ioc};
// Look up the domain name // 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 // 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 // Perform the websocket handshake
ws.handshake(host, "/"); ws.handshake(host, "/");

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -12,7 +12,6 @@
#include <boost/beast/core/detail/config.hpp> #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/bind_handler.hpp>
#include <boost/beast/core/buffered_read_stream.hpp> #include <boost/beast/core/buffered_read_stream.hpp>
#include <boost/beast/core/buffers_adapter.hpp> #include <boost/beast/core/buffers_adapter.hpp>
@ -28,7 +27,6 @@
#include <boost/beast/core/file_win32.hpp> #include <boost/beast/core/file_win32.hpp>
#include <boost/beast/core/flat_buffer.hpp> #include <boost/beast/core/flat_buffer.hpp>
#include <boost/beast/core/flat_static_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/handler_ptr.hpp>
#include <boost/beast/core/multi_buffer.hpp> #include <boost/beast/core/multi_buffer.hpp>
#include <boost/beast/core/ostream.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 placeholders present in the list of bound arguments. Parameters
which are not matched to placeholders are silently discarded. which are not matched to placeholders are silently discarded.
The passed handler and arguments are forwarded into the returned 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. as the original handler.
Unlike `boost::asio::io_service::wrap`, the returned handler can Unlike `boost::asio::io_context::wrap`, the returned handler can
be used in a subsequent call to `boost::asio::io_service::post` be used in a subsequent call to `boost::asio::io_context::post`
instead of `boost::asio::io_service::dispatch`, to ensure that instead of `boost::asio::io_context::dispatch`, to ensure that
the handler will not be invoked immediately by the calling the handler will not be invoked immediately by the calling
function. function.
@ -43,7 +43,8 @@ namespace beast {
void void
signal_aborted(AsyncReadStream& stream, ReadHandler&& handler) signal_aborted(AsyncReadStream& stream, ReadHandler&& handler)
{ {
stream.get_io_service().post( boost::asio::post(
stream.get_executor(),
bind_handler(std::forward<ReadHandler>(handler), bind_handler(std::forward<ReadHandler>(handler),
boost::asio::error::operation_aborted, 0)); boost::asio::error::operation_aborted, 0));
} }

View File

@ -11,12 +11,12 @@
#define BOOST_BEAST_BUFFERED_READ_STREAM_HPP #define BOOST_BEAST_BUFFERED_READ_STREAM_HPP
#include <boost/beast/core/detail/config.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/error.hpp>
#include <boost/beast/core/multi_buffer.hpp> #include <boost/beast/core/multi_buffer.hpp>
#include <boost/beast/core/type_traits.hpp> #include <boost/beast/core/type_traits.hpp>
#include <boost/asio/async_result.hpp>
#include <boost/asio/buffer.hpp> #include <boost/asio/buffer.hpp>
#include <boost/asio/io_service.hpp> #include <boost/asio/io_context.hpp>
#include <cstdint> #include <cstdint>
#include <utility> #include <utility>
@ -91,7 +91,8 @@ namespace beast {
template<class Stream, class DynamicBuffer> template<class Stream, class DynamicBuffer>
class buffered_read_stream class buffered_read_stream
{ {
static_assert(is_dynamic_buffer<DynamicBuffer>::value, static_assert(
boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
"DynamicBuffer requirements not met"); "DynamicBuffer requirements not met");
template<class Buffers, class Handler> template<class Buffers, class Handler>
@ -163,11 +164,29 @@ public:
return next_layer_.lowest_layer(); return next_layer_.lowest_layer();
} }
/// Get the io_service associated with the object. /** Get the executor associated with the object.
boost::asio::io_service&
get_io_service() 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. /** Access the internal buffer.
@ -265,14 +284,11 @@ public:
Regardless of whether the asynchronous operation completes Regardless of whether the asynchronous operation completes
immediately or not, the handler will not be invoked from within immediately or not, the handler will not be invoked from within
this function. Invocation of the handler will be performed in a 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> template<class MutableBufferSequence, class ReadHandler>
#if BOOST_BEAST_DOXYGEN BOOST_ASIO_INITFN_RESULT_TYPE(
void_or_deduced ReadHandler, void(error_code))
#else
async_return_type<ReadHandler, void(error_code)>
#endif
async_read_some(MutableBufferSequence const& buffers, async_read_some(MutableBufferSequence const& buffers,
ReadHandler&& handler); ReadHandler&& handler);
@ -340,14 +356,11 @@ public:
Regardless of whether the asynchronous operation completes Regardless of whether the asynchronous operation completes
immediately or not, the handler will not be invoked from within immediately or not, the handler will not be invoked from within
this function. Invocation of the handler will be performed in a 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> template<class ConstBufferSequence, class WriteHandler>
#if BOOST_BEAST_DOXYGEN BOOST_ASIO_INITFN_RESULT_TYPE(
void_or_deduced WriteHandler, void(error_code))
#else
async_return_type<WriteHandler, void(error_code)>
#endif
async_write_some(ConstBufferSequence const& buffers, async_write_some(ConstBufferSequence const& buffers,
WriteHandler&& handler); WriteHandler&& handler);
}; };

View File

@ -35,10 +35,12 @@ namespace beast {
template<class MutableBufferSequence> template<class MutableBufferSequence>
class buffers_adapter 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"); "MutableBufferSequence requirements not met");
using iter_type = typename MutableBufferSequence::const_iterator; using iter_type = typename
detail::buffer_sequence_iterator<
MutableBufferSequence>::type;
MutableBufferSequence bs_; MutableBufferSequence bs_;
iter_type begin_; iter_type begin_;

View File

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

View File

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

View File

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

View File

@ -11,9 +11,9 @@
#define BOOST_BEAST_DETAIL_BIND_HANDLER_HPP #define BOOST_BEAST_DETAIL_BIND_HANDLER_HPP
#include <boost/beast/core/detail/integer_sequence.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_continuation_hook.hpp>
#include <boost/asio/handler_invoke_hook.hpp>
#include <boost/core/ignore_unused.hpp> #include <boost/core/ignore_unused.hpp>
#include <functional> #include <functional>
#include <utility> #include <utility>
@ -24,13 +24,17 @@ namespace detail {
/* Nullary handler that calls Handler with bound arguments. /* 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. guarantees as the original handler.
*/ */
template<class Handler, class... Args> template<class Handler, class... Args>
class bound_handler 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< using args_type = std::tuple<
typename std::decay<Args>::type...>; typename std::decay<Args>::type...>;
@ -101,6 +105,9 @@ private:
public: public:
using result_type = void; using result_type = void;
using allocator_type =
boost::asio::associated_allocator_t<Handler>;
bound_handler(bound_handler&&) = default; bound_handler(bound_handler&&) = default;
bound_handler(bound_handler const&) = 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> template<class... Values>
void void
operator()(Values&&... values) operator()(Values&&... values)
@ -132,48 +153,30 @@ public:
std::forward<Values>(values)...), std::forward<Values>(values)...),
index_sequence_for<Args...>()); 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 } // detail
} // beast } // 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 } // boost
namespace std { namespace std {

View File

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

View File

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

View File

@ -12,38 +12,12 @@
#include <boost/beast/core/error.hpp> #include <boost/beast/core/error.hpp>
#include <boost/asio/buffer.hpp> #include <boost/asio/buffer.hpp>
#include <boost/asio/io_service.hpp>
#include <iterator> #include <iterator>
#include <tuple> #include <tuple>
#include <type_traits> #include <type_traits>
#include <string> #include <string>
#include <utility> #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 boost {
namespace beast { namespace beast {
namespace detail { namespace detail {
@ -281,57 +255,17 @@ using ConstBufferSequence =
using MutableBufferSequence = using MutableBufferSequence =
BufferSequence<boost::asio::mutable_buffer>; 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> template<class B1, class... Bn>
struct is_all_const_buffer_sequence struct is_all_const_buffer_sequence
: std::integral_constant<bool, : 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> is_all_const_buffer_sequence<Bn...>::value>
{ {
}; };
template<class B1> template<class B>
struct is_all_const_buffer_sequence<B1> struct is_all_const_buffer_sequence<B>
: is_buffer_sequence<B1, boost::asio::const_buffer> : boost::asio::is_const_buffer_sequence<B>
{ {
}; };
@ -346,6 +280,14 @@ struct common_buffers_type
boost::asio::const_buffer>::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, // Types that meet the requirements,
// for use with std::declval only. // for use with std::declval only.
struct StreamHandler struct StreamHandler
@ -356,6 +298,54 @@ struct StreamHandler
using ReadHandler = StreamHandler; using ReadHandler = StreamHandler;
using WriteHandler = 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 } // detail
} // beast } // beast
} // boost } // boost

View File

@ -84,10 +84,10 @@ public:
using allocator_type = Allocator; using allocator_type = Allocator;
/// The type used to represent the input sequence as a list of buffers. /// 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. /// 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 /// Destructor
~basic_flat_buffer(); ~basic_flat_buffer();

View File

@ -52,13 +52,13 @@ public:
This buffer sequence is guaranteed to have length 1. 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. /** The type used to represent the output sequence as a list of buffers.
This buffer sequence is guaranteed to have length 1. 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 /** 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/read_size.hpp>
#include <boost/beast/core/type_traits.hpp> #include <boost/beast/core/type_traits.hpp>
#include <boost/beast/core/detail/config.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_continuation_hook.hpp>
#include <boost/asio/handler_invoke_hook.hpp> #include <boost/asio/post.hpp>
#include <boost/throw_exception.hpp> #include <boost/throw_exception.hpp>
namespace boost { 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 void
operator()(error_code const& ec, operator()(error_code const& ec,
std::size_t bytes_transferred); 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 friend
bool asio_handler_is_continuation(read_some_op* op) bool asio_handler_is_continuation(read_some_op* op)
{ {
@ -77,14 +78,6 @@ public:
return asio_handler_is_continuation( return asio_handler_is_continuation(
std::addressof(op->h_)); 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> template<class Stream, class DynamicBuffer>
@ -116,9 +109,9 @@ read_some_op<MutableBufferSequence, Handler>::operator()(
} }
step_ = 3; step_ = 3;
s_.get_io_service().post( return boost::asio::post(
s_.get_executor(),
bind_handler(std::move(*this), ec, 0)); bind_handler(std::move(*this), ec, 0));
return;
case 1: case 1:
// upcall // upcall
@ -153,11 +146,11 @@ auto
buffered_read_stream<Stream, DynamicBuffer>:: buffered_read_stream<Stream, DynamicBuffer>::
async_write_some(ConstBufferSequence const& buffers, async_write_some(ConstBufferSequence const& buffers,
WriteHandler&& handler) -> 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, static_assert(is_async_write_stream<next_layer_type>::value,
"AsyncWriteStream requirements not met"); "AsyncWriteStream requirements not met");
static_assert(is_const_buffer_sequence< static_assert(boost::asio::is_const_buffer_sequence<
ConstBufferSequence>::value, ConstBufferSequence>::value,
"ConstBufferSequence requirements not met"); "ConstBufferSequence requirements not met");
static_assert(is_completion_handler<WriteHandler, static_assert(is_completion_handler<WriteHandler,
@ -176,7 +169,7 @@ read_some(
{ {
static_assert(is_sync_read_stream<next_layer_type>::value, static_assert(is_sync_read_stream<next_layer_type>::value,
"SyncReadStream requirements not met"); "SyncReadStream requirements not met");
static_assert(is_mutable_buffer_sequence< static_assert(boost::asio::is_mutable_buffer_sequence<
MutableBufferSequence>::value, MutableBufferSequence>::value,
"MutableBufferSequence requirements not met"); "MutableBufferSequence requirements not met");
error_code ec; error_code ec;
@ -195,7 +188,7 @@ read_some(MutableBufferSequence const& buffers,
{ {
static_assert(is_sync_read_stream<next_layer_type>::value, static_assert(is_sync_read_stream<next_layer_type>::value,
"SyncReadStream requirements not met"); "SyncReadStream requirements not met");
static_assert(is_mutable_buffer_sequence< static_assert(boost::asio::is_mutable_buffer_sequence<
MutableBufferSequence>::value, MutableBufferSequence>::value,
"MutableBufferSequence requirements not met"); "MutableBufferSequence requirements not met");
using boost::asio::buffer_size; using boost::asio::buffer_size;
@ -226,20 +219,20 @@ auto
buffered_read_stream<Stream, DynamicBuffer>:: buffered_read_stream<Stream, DynamicBuffer>::
async_read_some(MutableBufferSequence const& buffers, async_read_some(MutableBufferSequence const& buffers,
ReadHandler&& handler) -> 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, static_assert(is_async_read_stream<next_layer_type>::value,
"Stream requirements not met"); "AsyncReadStream requirements not met");
static_assert(is_mutable_buffer_sequence< static_assert(boost::asio::is_mutable_buffer_sequence<
MutableBufferSequence>::value, MutableBufferSequence>::value,
"MutableBufferSequence requirements not met"); "MutableBufferSequence requirements not met");
if(buffer_.size() == 0 && capacity_ == 0) if(buffer_.size() == 0 && capacity_ == 0)
return next_layer_.async_read_some(buffers, return next_layer_.async_read_some(buffers,
std::forward<ReadHandler>(handler)); std::forward<ReadHandler>(handler));
async_completion<ReadHandler, boost::asio::async_completion<ReadHandler,
void(error_code, std::size_t)> init{handler}; void(error_code, std::size_t)> init{handler};
read_some_op<MutableBufferSequence, handler_type< read_some_op<MutableBufferSequence, BOOST_ASIO_HANDLER_TYPE(
ReadHandler, void(error_code, std::size_t)>>{ ReadHandler, void(error_code, std::size_t))>{
init.completion_handler, *this, buffers}( init.completion_handler, *this, buffers}(
error_code{}, 0); error_code{}, 0);
return init.result.get(); return init.result.get();

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -38,7 +38,8 @@ std::size_t
read_size(DynamicBuffer& buffer, read_size(DynamicBuffer& buffer,
std::size_t max_size, std::false_type) 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"); "DynamicBuffer requirements not met");
BOOST_ASSERT(max_size >= 1); BOOST_ASSERT(max_size >= 1);
auto const size = buffer.size(); auto const size = buffer.size();

View File

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

View File

@ -19,153 +19,6 @@
namespace boost { namespace boost {
namespace beast { 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 // 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 Metafunctions are used to perform compile time checking of template
types. This type will be `std::true_type` if `T` has the member 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> template<class T>
void maybe_hello(T& t, std::true_type) 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> template<class T>
void maybe_hello(T&, std::false_type) void maybe_hello(T&, std::false_type)
{ {
// T does not have get_io_service // T does not have get_executor
} }
template<class T> template<class T>
void maybe_hello(T& t) void maybe_hello(T& t)
{ {
maybe_hello(t, has_get_io_service<T>{}); maybe_hello(t, has_get_executor<T>{});
} }
@endcode @endcode
@ -244,24 +102,23 @@ using is_completion_handler = std::integral_constant<bool,
@code @code
struct stream 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, static_assert(has_get_executor<stream>::value, "Missing get_executor member");
"Missing get_io_service member");
@endcode @endcode
*/ */
#if BOOST_BEAST_DOXYGEN #if BOOST_BEAST_DOXYGEN
template<class T> template<class T>
struct has_get_io_service : std::integral_constant<bool, ...>{}; struct has_get_executor : std::integral_constant<bool, ...>{};
#else #else
template<class T, class = void> template<class T, class = void>
struct has_get_io_service : std::false_type {}; struct has_get_executor : std::false_type {};
template<class T> template<class T>
struct has_get_io_service<T, beast::detail::void_t<decltype( struct has_get_executor<T, beast::detail::void_t<decltype(
detail::accept_rv<boost::asio::io_service&>( std::declval<T&>().get_executor(),
std::declval<T&>().get_io_service()),
(void)0)>> : std::true_type {}; (void)0)>> : std::true_type {};
#endif #endif
@ -350,7 +207,7 @@ struct is_async_read_stream<T, detail::void_t<decltype(
std::declval<detail::MutableBufferSequence>(), std::declval<detail::MutableBufferSequence>(),
std::declval<detail::ReadHandler>()), std::declval<detail::ReadHandler>()),
(void)0)>> : std::integral_constant<bool, (void)0)>> : std::integral_constant<bool,
has_get_io_service<T>::value has_get_executor<T>::value
> {}; > {};
#endif #endif
@ -394,7 +251,7 @@ struct is_async_write_stream<T, detail::void_t<decltype(
std::declval<detail::ConstBufferSequence>(), std::declval<detail::ConstBufferSequence>(),
std::declval<detail::WriteHandler>()), std::declval<detail::WriteHandler>()),
(void)0)>> : std::integral_constant<bool, (void)0)>> : std::integral_constant<bool,
has_get_io_service<T>::value has_get_executor<T>::value
> {}; > {};
#endif #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<std::size_t&>() = std::declval<T>().read_some(
std::declval<detail::MutableBufferSequence>(), std::declval<detail::MutableBufferSequence>(),
std::declval<boost::system::error_code&>()), std::declval<boost::system::error_code&>()),
(void)0)>> : std::integral_constant<bool, (void)0)>> : std::true_type {};
has_get_io_service<T>::value
> {};
#endif #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 Metafunctions are used to perform compile time checking of template
types. This type will be `std::true_type` if `T` meets the requirements, 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<std::size_t&>() = std::declval<T&>().write_some(
std::declval<detail::ConstBufferSequence>(), std::declval<detail::ConstBufferSequence>(),
std::declval<boost::system::error_code&>()), std::declval<boost::system::error_code&>()),
(void)0)>> : std::integral_constant<bool, (void)0)>> : std::true_type {};
has_get_io_service<T>::value
> {};
#endif #endif
/** Determine if `T` meets the requirements of @b AsyncStream. /** Determine if `T` meets the requirements of @b AsyncStream.

View File

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

View File

@ -143,7 +143,13 @@ public:
/** Set the open file /** 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 void
reset(File&& file, error_code& ec); reset(File&& file, error_code& ec);
@ -229,7 +235,7 @@ public:
// The type of buffer sequence returned by `get`. // The type of buffer sequence returned by `get`.
// //
using const_buffers_type = using const_buffers_type =
boost::asio::const_buffers_1; boost::asio::const_buffer;
// Constructor. // Constructor.
// //
@ -485,13 +491,13 @@ put(ConstBufferSequence const& buffers, error_code& ec)
// Loop over all the buffers in the sequence, // Loop over all the buffers in the sequence,
// and write each one to the file. // 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 // Write this buffer to the file
boost::asio::const_buffer buffer = *it;
nwritten += body_.file_.write( nwritten += body_.file_.write(
boost::asio::buffer_cast<void const*>(buffer), buffer.data(), buffer.size(), ec);
boost::asio::buffer_size(buffer),
ec);
if(ec) if(ec)
return nwritten; return nwritten;
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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