mirror of
https://github.com/boostorg/beast.git
synced 2025-07-31 21:34:46 +02:00
basic_stream subsumes stranded_stream:
* All functionality of stranded_stream is folded into basic_stream * tcp_stream is an alias for basic_stream with tcp * The tests are expanded to produce full coverage * Timeout implementation is simplified
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
Version 213:
|
||||
|
||||
* Fix posix_file::close handling of EINTR
|
||||
* basic_stream subsumes stranded_stream:
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
@@ -46,12 +46,15 @@ facilities for authoring and working with layered streams:
|
||||
[table Layered Stream Algorithms and Types
|
||||
[[Name][Description]]
|
||||
[[
|
||||
[link beast.ref.boost__beast__timeout_stream `timeout_stream`]
|
||||
[link beast.ref.boost__beast__basic_timeout_stream `basic_timeout_stream`]
|
||||
[link beast.ref.boost__beast__basic_stream `basic_stream`]
|
||||
[link beast.ref.boost__beast__tcp_stream `tcp_stream`]
|
||||
][
|
||||
A timeout stream meets the requirements for synchronous and asynchronous
|
||||
read and write streams, and additionally provides configurable timeouts
|
||||
for logical operations that include reading, writing, and/or connecting.
|
||||
This stream can be used for synchronous and asynchronous reading
|
||||
and writing. It allows timeouts to be set on logical operations,
|
||||
and can have an executor associated with the stream which is
|
||||
used to invoke completion handlers. This lets you set a strand
|
||||
on the stream once, which is then used for all asynchronous
|
||||
operations automatically.
|
||||
]]
|
||||
[[
|
||||
[link beast.ref.boost__beast__buffered_read_stream `buffered_read_stream`]
|
||||
@@ -109,16 +112,6 @@ facilities for authoring and working with layered streams:
|
||||
allows for move-construction and move-assignment, and also implements
|
||||
a work-around for a performance limitation in the original SSL stream.
|
||||
]]
|
||||
[[
|
||||
[link beast.ref.boost__beast__stranded_socket `stranded_socket`]
|
||||
][
|
||||
A timeout stream meets the requirements for synchronous and asynchronous
|
||||
read and write streams by passing I/O through to an underlying
|
||||
`net::basic_stream_socket`, and additionally supports
|
||||
[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1322r0.html [P1322R0] "Networking TS enhancement to enable custom I/O executors"],
|
||||
allowing a custom executor (such a strand) to be used for all
|
||||
asynchronous operations.
|
||||
]]
|
||||
]
|
||||
|
||||
[heading Example]
|
||||
|
@@ -24,7 +24,7 @@
|
||||
<bridgehead renderas="sect3">Classes <emphasis role="normal">(1 of 2)</emphasis></bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="beast.ref.boost__beast__async_op_base">async_op_base</link> <emphasis role="green">🞲</emphasis></member>
|
||||
<member><link linkend="beast.ref.boost__beast__basic_timeout_stream">basic_timeout_stream</link> <emphasis role="green">🞲</emphasis></member>
|
||||
<member><link linkend="beast.ref.boost__beast__basic_stream">basic_stream</link> <emphasis role="green">🞲</emphasis></member>
|
||||
<member><link linkend="beast.ref.boost__beast__file">file</link></member>
|
||||
<member><link linkend="beast.ref.boost__beast__file_mode">file_mode</link></member>
|
||||
<member><link linkend="beast.ref.boost__beast__file_posix">file_posix</link></member>
|
||||
@@ -46,10 +46,9 @@
|
||||
<member><link linkend="beast.ref.boost__beast__span">span</link></member>
|
||||
<member><link linkend="beast.ref.boost__beast__static_string">static_string</link></member>
|
||||
<member><link linkend="beast.ref.boost__beast__stable_async_op_base">stable_async_op_base</link> <emphasis role="green">🞲</emphasis></member>
|
||||
<member><link linkend="beast.ref.boost__beast__stranded_socket">stranded_socket</link> <emphasis role="green">🞲</emphasis></member>
|
||||
<member><link linkend="beast.ref.boost__beast__string_param">string_param</link></member>
|
||||
<member><link linkend="beast.ref.boost__beast__string_view">string_view</link></member>
|
||||
<member><link linkend="beast.ref.boost__beast__timeout_stream">timeout_stream</link> <emphasis role="green">🞲</emphasis></member>
|
||||
<member><link linkend="beast.ref.boost__beast__tcp_stream">tcp_stream</link> <emphasis role="green">🞲</emphasis></member>
|
||||
</simplelist>
|
||||
<bridgehead renderas="sect3">Constants</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
|
@@ -14,14 +14,19 @@
|
||||
[heading Boost 1.70]
|
||||
[/ includes up to version 209]
|
||||
[/
|
||||
* Use `beast::tcp_socket` instead of `boost::asio::ip::tcp::socket`!
|
||||
* subscribe to this GitHub issue to be informed!
|
||||
* we need testers!
|
||||
* star the repo!
|
||||
|
||||
Exposition:
|
||||
Enlarged scope
|
||||
New quality of life features:
|
||||
timed stream
|
||||
- `net` is a namespace alias for `boost::asio`
|
||||
- New quality of life features:
|
||||
tcp_socket
|
||||
async_op_base, stable_async_op_base
|
||||
New Networking refresher
|
||||
New websocket-chat-multi example
|
||||
* `net` is a namespace alias for `boost::asio`
|
||||
- New Networking refresher
|
||||
- New websocket-chat-multi example
|
||||
]
|
||||
|
||||
[tip
|
||||
|
@@ -12,7 +12,7 @@
|
||||
|
||||
#include <boost/beast/core/detail/config.hpp>
|
||||
|
||||
#include <boost/beast/core/basic_timeout_stream.hpp>
|
||||
#include <boost/beast/core/basic_stream.hpp>
|
||||
#include <boost/beast/core/bind_handler.hpp>
|
||||
#include <boost/beast/core/buffer_size.hpp>
|
||||
#include <boost/beast/core/buffer_traits.hpp>
|
||||
@@ -41,10 +41,9 @@
|
||||
#include <boost/beast/core/span.hpp>
|
||||
#include <boost/beast/core/static_buffer.hpp>
|
||||
#include <boost/beast/core/static_string.hpp>
|
||||
#include <boost/beast/core/stranded_socket.hpp>
|
||||
#include <boost/beast/core/stream_traits.hpp>
|
||||
#include <boost/beast/core/string.hpp>
|
||||
#include <boost/beast/core/string_param.hpp>
|
||||
#include <boost/beast/core/timeout_stream.hpp>
|
||||
#include <boost/beast/core/tcp_stream.hpp>
|
||||
|
||||
#endif
|
||||
|
1464
include/boost/beast/core/basic_stream.hpp
Normal file
1464
include/boost/beast/core/basic_stream.hpp
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,847 +0,0 @@
|
||||
//
|
||||
// Copyright (c) 2018 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_CORE_BASIC_TIMEOUT_SOCKET_HPP
|
||||
#define BOOST_BEAST_CORE_BASIC_TIMEOUT_SOCKET_HPP
|
||||
|
||||
#include <boost/beast/core/detail/config.hpp>
|
||||
#include <boost/beast/core/detail/timeout_stream_base.hpp>
|
||||
#include <boost/beast/core/error.hpp>
|
||||
#include <boost/asio/async_result.hpp>
|
||||
#include <boost/asio/basic_stream_socket.hpp>
|
||||
#include <boost/asio/connect.hpp>
|
||||
#include <boost/asio/executor.hpp>
|
||||
#include <boost/asio/steady_timer.hpp>
|
||||
#include <boost/config/workaround.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
|
||||
namespace boost {
|
||||
namespace beast {
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** A stream socket with an integrated timeout on reading, writing, and connecting.
|
||||
|
||||
This layered stream wrapper manages a contained `net::basic_stream_socket`
|
||||
object to provide the following additional features:
|
||||
|
||||
@li A timeout may be specified for each logical asynchronous
|
||||
operation that performs reading, writing, and/or connecting.
|
||||
|
||||
@li The class template is parameterized on the executor type to be
|
||||
used for all asynchronous operations. This achieves partial support for
|
||||
<em>"Networking TS enhancement to enable custom I/O executors"</em>
|
||||
(<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1322r0.html">P1322R0</a>).
|
||||
|
||||
Objects of this type are used in place of a regular networking socket,
|
||||
where timeouts on operations are desired. In particular this class
|
||||
template is designed to be used in place of `net::basic_stream_socket`
|
||||
or more typically, `net:ip::tcp::socket`. Constructors are provided to
|
||||
use a particular execution context or executor, subject to temporary
|
||||
restrictions based on the current implementation of networking. Additional
|
||||
constructors allow the timeout stream to be constructed from a networking
|
||||
socket that already exists.
|
||||
|
||||
Although the stream supports multiple concurrent outstanding asynchronous
|
||||
operations, the stream object itself is not thread-safe. The caller is
|
||||
responsible for ensuring that the stream is accessed from only one thread
|
||||
at a time. This includes the times when the stream, and its underlying
|
||||
socket, is accessed by the networking implementation. To meet these
|
||||
thread safety requirements, all asynchronous operations must be performed
|
||||
by the stream within the same implicit strand (only one thread calling `run()`
|
||||
on the corresponding `net::io_context`) or within the same explicit strand
|
||||
such as an instance of `net::strand`.
|
||||
|
||||
When using explicit strands, calls to initiating functions may use
|
||||
`net::bind_handler` with a suitable executor on the completion handler.
|
||||
Alternatively, the executor may be specified once by passing it as a stream
|
||||
class template parameter, and providing an instance of the executor upon
|
||||
construction (if the executor type is not <em>DefaultConstructible</em>).
|
||||
Regardless of the method chosen, the executor used with the stream must
|
||||
provide the following guarantees:
|
||||
|
||||
@li <b>Ordering:</b>
|
||||
Function objects submitted to the executor from the same thread shall
|
||||
execute in the order they were submitted.
|
||||
|
||||
@li <b>Concurrency:</b>
|
||||
Function objects submitted to the executor shall never run concurrently
|
||||
with each other.
|
||||
|
||||
The executor type `net::strand` meets these requirements. Use of a
|
||||
strand as the executor in the stream class template offers an additional
|
||||
notational convenience: the strand does not need to be specified in
|
||||
each individual initiating function call.
|
||||
|
||||
@par Usage
|
||||
|
||||
To use this stream declare an instance of the class. Then, before
|
||||
each logical operation for which a timeout is desired, call
|
||||
@ref expires_after with a duration, or call @ref expires_at with a
|
||||
time point. Alternatively, call @ref expires_never to disable the
|
||||
timeout for subsequent logical operations. A logical operation
|
||||
is any series of one or more direct or indirect calls to the timeout
|
||||
stream's read, write, or connect functions.
|
||||
|
||||
When a timeout is set and a mixed operation is performed (one that
|
||||
includes both reads and writes, for example) the timeout applies
|
||||
to all of the intermediate asynchronous operations used in the
|
||||
enclosing operation. This allows timeouts to be applied to stream
|
||||
algorithms which were not written specifically to allow for timeouts,
|
||||
when those algorithms are passed a timeout stream with a timeout set.
|
||||
|
||||
When a timeout occurs the socket will be closed, canceling any
|
||||
pending I/O operations. The completion handlers for these canceled
|
||||
operations will be invoked with the error @ref beast::error::timeout.
|
||||
|
||||
@par Examples
|
||||
|
||||
This function reads an HTTP request with a timeout, then sends the
|
||||
HTTP response with a different timeout.
|
||||
|
||||
@code
|
||||
void process_http_1 (timeout_stream& stream, net::yield_context yield)
|
||||
{
|
||||
flat_buffer buffer;
|
||||
http::request<http::empty_body> req;
|
||||
|
||||
// Read the request, with a 15 second timeout
|
||||
stream.expires_after(std::chrono::seconds(15));
|
||||
http::async_read(stream, buffer, req, yield);
|
||||
|
||||
// Calculate the response
|
||||
http::response<http::string_body> res = make_response(req);
|
||||
|
||||
// Send the response, with a 30 second timeout.
|
||||
stream.expires_after (std::chrono::seconds(30));
|
||||
http::async_write (stream, res, yield);
|
||||
}
|
||||
@endcode
|
||||
|
||||
The example above could be expressed using a single timeout with a
|
||||
simple modification. The function that follows first reads an HTTP
|
||||
request then sends the HTTP response, with a single timeout that
|
||||
applies to the entire combined operation of reading and writing:
|
||||
|
||||
@code
|
||||
void process_http_2 (timeout_stream& stream, net::yield_context yield)
|
||||
{
|
||||
flat_buffer buffer;
|
||||
http::request<http::empty_body> req;
|
||||
|
||||
// Require that the read and write combined take no longer than 30 seconds
|
||||
stream.expires_after(std::chrono::seconds(30));
|
||||
|
||||
http::async_read(stream, buffer, req, yield);
|
||||
|
||||
http::response<http::string_body> res = make_response(req);
|
||||
http::async_write (stream, res, yield);
|
||||
}
|
||||
@endcode
|
||||
|
||||
Some stream algorithms, such as `ssl::stream::async_handshake` perform
|
||||
both reads and writes. A timeout set before calling the initiating function
|
||||
of such composite stream algorithms will apply to the entire composite
|
||||
operation. For example, a timeout may be set on performing the SSL handshake
|
||||
thusly:
|
||||
|
||||
@code
|
||||
void do_ssl_handshake (net::ssl::stream<timeout_stream>& stream, net::yield_context yield)
|
||||
{
|
||||
// Require that the SSL handshake take no longer than 10 seconds
|
||||
stream.expires_after(std::chrono::seconds(10));
|
||||
|
||||
stream.async_handshake(net::ssl::stream_base::client, yield);
|
||||
}
|
||||
@endcode
|
||||
|
||||
@tparam Protocol A type meeting the requirements of <em>Protocol</em>
|
||||
representing the protocol the protocol to use for the basic stream socket.
|
||||
A common choice is `net::ip::tcp`.
|
||||
|
||||
@tparam Executor A type meeting the requirements of <em>Executor</em> to
|
||||
be used for submitting all completion handlers which do not already have an
|
||||
associated executor. This type defaults to `net::io_context::executor_type`.
|
||||
|
||||
@par Thread Safety
|
||||
<em>Distinct objects</em>: Safe.@n
|
||||
<em>Shared objects</em>: Unsafe. The application must also ensure
|
||||
that all asynchronous operations are performed within the same
|
||||
implicit or explicit strand.
|
||||
|
||||
@see <em>"Networking TS enhancement to enable custom I/O executors"</em>
|
||||
(<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1322r0.html">P1322R0</a>).
|
||||
*/
|
||||
template<
|
||||
class Protocol,
|
||||
class Executor = typename
|
||||
net::basic_stream_socket<Protocol>::executor_type>
|
||||
class basic_timeout_stream
|
||||
#if ! BOOST_BEAST_DOXYGEN
|
||||
: private detail::timeout_stream_base
|
||||
#endif
|
||||
{
|
||||
using time_point = typename
|
||||
std::chrono::steady_clock::time_point;
|
||||
|
||||
static constexpr time_point never()
|
||||
{
|
||||
return (time_point::max)();
|
||||
}
|
||||
|
||||
static std::size_t constexpr no_limit =
|
||||
(std::numeric_limits<std::size_t>::max)();
|
||||
|
||||
using tick_type = std::uint64_t;
|
||||
|
||||
struct op_state
|
||||
{
|
||||
net::steady_timer timer; // for timing out
|
||||
tick_type tick = 0; // counts waits
|
||||
bool pending = false; // if op is pending
|
||||
bool timeout = false; // if timed out
|
||||
|
||||
explicit
|
||||
op_state(net::io_context& ioc)
|
||||
: timer(ioc)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// friend class template declaration in a class template is ignored
|
||||
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88672
|
||||
#if BOOST_WORKAROUND(BOOST_GCC, > 0)
|
||||
public:
|
||||
#endif
|
||||
struct impl_type
|
||||
: std::enable_shared_from_this<impl_type>
|
||||
{
|
||||
Executor ex; // must come first
|
||||
op_state read;
|
||||
op_state write;
|
||||
|
||||
net::basic_stream_socket<Protocol> socket;
|
||||
|
||||
template<class... Args>
|
||||
explicit
|
||||
impl_type(Executor const&, Args&&...);
|
||||
|
||||
impl_type(impl_type&&) = default;
|
||||
impl_type& operator=(impl_type&&);
|
||||
|
||||
void reset(); // set timeouts to never
|
||||
void close(); // cancel everything
|
||||
};
|
||||
#if BOOST_WORKAROUND(BOOST_GCC, > 0)
|
||||
private:
|
||||
#endif
|
||||
|
||||
// We use shared ownership for the state so it can
|
||||
// outlive the destruction of the stream_socket object,
|
||||
// in the case where there is no outstanding read or
|
||||
// write but the implementation is still waiting on
|
||||
// the rate timer.
|
||||
std::shared_ptr<impl_type> impl_;
|
||||
|
||||
// Restricted until P1322R0 is incorporated into Boost.Asio.
|
||||
static_assert(
|
||||
std::is_convertible<
|
||||
decltype(std::declval<Executor const&>().context()),
|
||||
net::io_context&>::value,
|
||||
"Only net::io_context is currently supported for executor_type::context()");
|
||||
|
||||
template<bool, class, class> class async_op;
|
||||
|
||||
template<class, class, class>
|
||||
friend class detail::timeout_stream_connect_op;
|
||||
|
||||
template<class, class>
|
||||
friend class basic_timeout_stream;
|
||||
|
||||
struct timeout_handler;
|
||||
|
||||
public:
|
||||
/// The type of the executor associated with the object.
|
||||
using executor_type = Executor;
|
||||
|
||||
/// The type of the next layer.
|
||||
using next_layer_type = net::basic_stream_socket<Protocol>;
|
||||
|
||||
/// The protocol type.
|
||||
using protocol_type = Protocol;
|
||||
|
||||
/// The endpoint type.
|
||||
using endpoint_type = typename Protocol::endpoint;
|
||||
|
||||
/** Destructor
|
||||
|
||||
This function destroys the socket, cancelling any outstanding
|
||||
asynchronous operations associated with the socket as if by
|
||||
calling cancel.
|
||||
*/
|
||||
~basic_timeout_stream();
|
||||
|
||||
/** Construct the stream without opening it.
|
||||
|
||||
This constructor creates a timeout stream. The underlying socket needs
|
||||
to be opened and then connected or accepted before data can be sent or
|
||||
received on it.
|
||||
|
||||
@param ctx An object whose type meets the requirements of
|
||||
<em>ExecutionContext</em>, which the stream will use to dispatch
|
||||
handlers for any asynchronous operations performed on the socket.
|
||||
Currently, the only supported type for `ctx` is `net::io_context`.
|
||||
|
||||
@note This function does not participate in overload resolution unless:
|
||||
@li `std::is_convertible<ExecutionContext&, net::execution_context&>::value` is `true`, and
|
||||
@li `std::is_constructible<executor_type, typename ExecutionContext::executor_type>::value` is `true`.
|
||||
|
||||
@see http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1322r0.html
|
||||
*/
|
||||
template<
|
||||
class ExecutionContext
|
||||
#if ! BOOST_BEAST_DOXYGEN
|
||||
, class = typename std::enable_if<
|
||||
std::is_convertible<
|
||||
ExecutionContext&,
|
||||
net::execution_context&>::value &&
|
||||
std::is_constructible<
|
||||
executor_type,
|
||||
typename ExecutionContext::executor_type>::value
|
||||
>::type
|
||||
#endif
|
||||
>
|
||||
explicit
|
||||
basic_timeout_stream(ExecutionContext& ctx);
|
||||
|
||||
/** Construct the stream without opening it.
|
||||
|
||||
This constructor creates a timeout stream. The underlying socket needs
|
||||
to be opened and then connected or accepted before data can be sent or
|
||||
received on it.
|
||||
|
||||
@param ex The executor which stream will use to dispatch handlers for
|
||||
any asynchronous operations performed on the underlying socket.
|
||||
Currently, only executors that return a `net::io_context&` from
|
||||
`ex.context()` are supported.
|
||||
|
||||
@see http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1322r0.html
|
||||
*/
|
||||
explicit
|
||||
basic_timeout_stream(executor_type const& ex);
|
||||
|
||||
/** Construct the stream with an existing socket.
|
||||
|
||||
This constructor creates a timeout stream by taking ownership of an
|
||||
already existing socket. The executor will be the same as the executor
|
||||
of the provided socket.
|
||||
|
||||
@param socket The socket object to construct with, which becomes the
|
||||
next layer of the timeout stream. Ownership of this socket is
|
||||
transferred by move.
|
||||
|
||||
@see http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1322r0.html
|
||||
*/
|
||||
explicit
|
||||
basic_timeout_stream(
|
||||
net::basic_stream_socket<Protocol>&& socket);
|
||||
|
||||
/** Construct the stream with an executor and existing socket.
|
||||
|
||||
This constructor creates a timeout stream by taking ownership of an
|
||||
already existing socket.
|
||||
|
||||
@param ex The executor which stream will use to dispatch handlers for
|
||||
any asynchronous operations performed on the underlying socket.
|
||||
Currently, only executors that return a `net::io_context&` from
|
||||
`ex.context()` are supported.
|
||||
|
||||
@param socket The socket object to construct with, which becomes the
|
||||
next layer of the timeout stream. Ownership of this socket is
|
||||
transferred by move.
|
||||
|
||||
@see http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1322r0.html
|
||||
*/
|
||||
basic_timeout_stream(
|
||||
executor_type const& ex,
|
||||
net::basic_stream_socket<Protocol>&& socket);
|
||||
|
||||
/** Move-construct a stream from another stream
|
||||
|
||||
This constructor moves a stream from one object to another.
|
||||
|
||||
The behavior of moving a stream while asynchronous operations
|
||||
are outstanding is undefined.
|
||||
|
||||
@param other The other object from which the move will occur.
|
||||
|
||||
@note Following the move, the moved-from object is in a newly
|
||||
constructed state.
|
||||
*/
|
||||
basic_timeout_stream(basic_timeout_stream&& other);
|
||||
|
||||
/** Move-assign a stream from another stream
|
||||
|
||||
This assignment operator moves a stream socket from one object
|
||||
to another.
|
||||
|
||||
The behavior of move assignment while asynchronous operations
|
||||
are pending is undefined.
|
||||
|
||||
@param other The other basic_timeout_stream object from which the
|
||||
move will occur.
|
||||
|
||||
@note Following the move, the moved-from object is a newly
|
||||
constructed state.
|
||||
*/
|
||||
basic_timeout_stream& operator=(basic_timeout_stream&& other);
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/** Get the executor associated with the object.
|
||||
|
||||
This function may be used to obtain the executor object that the
|
||||
stream uses to dispatch handlers for asynchronous operations.
|
||||
|
||||
@return A copy of the executor that stream will use to dispatch handlers.
|
||||
*/
|
||||
executor_type
|
||||
get_executor() const noexcept
|
||||
{
|
||||
return impl_->ex;
|
||||
}
|
||||
|
||||
/** Get a reference to the underlying socket.
|
||||
|
||||
This function returns a reference to the next layer
|
||||
in a stack of stream layers.
|
||||
|
||||
@return A reference to the next layer in the stack of
|
||||
stream layers.
|
||||
*/
|
||||
next_layer_type&
|
||||
next_layer() noexcept
|
||||
{
|
||||
return impl_->socket;
|
||||
}
|
||||
|
||||
/** Get a reference to the underlying socket.
|
||||
|
||||
This function returns a reference to the next layer in a
|
||||
stack of stream layers.
|
||||
|
||||
@return A reference to the next layer in the stack of
|
||||
stream layers.
|
||||
*/
|
||||
next_layer_type const&
|
||||
next_layer() const noexcept
|
||||
{
|
||||
return impl_->socket;
|
||||
}
|
||||
|
||||
/** Set the timeout for the next logical operation.
|
||||
|
||||
This sets either the read timer, the write timer, or
|
||||
both timers to expire after the specified amount of time
|
||||
has elapsed. If a timer expires when the corresponding
|
||||
asynchronous operation is outstanding, the stream will be
|
||||
closed and any outstanding operations will complete with the
|
||||
error @ref beast::error::timeout. Otherwise, if the timer
|
||||
expires while no operations are outstanding, and the expiraton
|
||||
is not set again, the next operation will time out immediately.
|
||||
|
||||
The timer applies collectively to any asynchronous reads
|
||||
or writes initiated after the expiration is set, until the
|
||||
expiration is set again. A call to @ref beast::async_connect
|
||||
counts as both a read and a write.
|
||||
|
||||
@param expiry_time The amount of time after which a logical
|
||||
operation should be considered timed out.
|
||||
*/
|
||||
void
|
||||
expires_after(
|
||||
std::chrono::nanoseconds expiry_time);
|
||||
|
||||
/** Set the timeout for the next logical operation.
|
||||
|
||||
This sets either the read timer, the write timer, or both
|
||||
timers to expire at the specified time point. If a timer
|
||||
expires when the corresponding asynchronous operation is
|
||||
outstanding, the stream will be closed and any outstanding
|
||||
operations will complete with the error @ref beast::error::timeout.
|
||||
Otherwise, if the timer expires while no operations are outstanding,
|
||||
and the expiraton is not set again, the next operation will time out
|
||||
immediately.
|
||||
|
||||
The timer applies collectively to any asynchronous reads
|
||||
or writes initiated after the expiration is set, until the
|
||||
expiration is set again. A call to @ref beast::async_connect
|
||||
counts as both a read and a write.
|
||||
|
||||
@param expiry_time The time point after which a logical
|
||||
operation should be considered timed out.
|
||||
*/
|
||||
void
|
||||
expires_at(net::steady_timer::time_point expiry_time);
|
||||
|
||||
/// Disable the timeout for the next logical operation.
|
||||
void
|
||||
expires_never();
|
||||
|
||||
/// Cancel all asynchronous operations associated with the socket.
|
||||
void
|
||||
cancel();
|
||||
|
||||
/** Close the timed stream.
|
||||
|
||||
This cancels all timers and pending I/O. The completion handlers
|
||||
for any pending I/O will see an error code.
|
||||
*/
|
||||
void
|
||||
close();
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/** Start an asynchronous connect.
|
||||
|
||||
This function is used to asynchronously connect a socket to the
|
||||
specified remote endpoint. The function call always returns immediately.
|
||||
|
||||
The underlying socket is automatically opened if it is not already open.
|
||||
If the connect fails, and the socket was automatically opened, the socket
|
||||
is not returned to the closed state.
|
||||
|
||||
@param ep The remote endpoint to which the underlying socket will be
|
||||
connected. Copies will be made of the endpoint object as required.
|
||||
|
||||
@param handler The handler to be called when the operation completes.
|
||||
The implementation will take ownership of the handler by move construction.
|
||||
The handler must be invocable with this signature:
|
||||
@code
|
||||
void handler(
|
||||
error_code ec // 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
|
||||
`net::post()`.
|
||||
*/
|
||||
template<class ConnectHandler>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(ConnectHandler,
|
||||
void(error_code))
|
||||
async_connect(
|
||||
endpoint_type ep,
|
||||
ConnectHandler&& handler);
|
||||
|
||||
/** Start an asynchronous read.
|
||||
|
||||
This function is used to asynchronously read data from the stream.
|
||||
The function call always returns immediately.
|
||||
|
||||
@param buffers A range of zero or more buffers to read stream data into.
|
||||
Although the buffers object may be copied as necessary, ownership of the
|
||||
underlying memory blocks is retained by the caller, which must guarantee
|
||||
that they remain valid until the handler is called.
|
||||
|
||||
@param handler The handler to be called when the operation completes.
|
||||
The implementation will take ownership of the handler by move construction.
|
||||
The handler must be invocable with this signature:
|
||||
@code
|
||||
void handler(
|
||||
error_code error, // Result of operation.
|
||||
std::size_t bytes_transferred // Number of bytes read.
|
||||
);
|
||||
@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
|
||||
`net::post()`.
|
||||
*/
|
||||
template<class MutableBufferSequence, class ReadHandler>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
|
||||
void(error_code, std::size_t))
|
||||
async_read_some(
|
||||
MutableBufferSequence const& buffers,
|
||||
ReadHandler&& handler);
|
||||
|
||||
/** Start an asynchronous write.
|
||||
|
||||
This function is used to asynchronously write data to the stream.
|
||||
The function call always returns immediately.
|
||||
|
||||
@param buffers A range of zero or more buffers to be written to the stream.
|
||||
Although the buffers object may be copied as necessary, ownership of the
|
||||
underlying memory blocks is retained by the caller, which must guarantee
|
||||
that they remain valid until the handler is called.
|
||||
|
||||
@param handler The handler to be called when the operation completes.
|
||||
The implementation will take ownership of the handler by move construction.
|
||||
The handler must be invocable with this signature:
|
||||
@code
|
||||
void handler(
|
||||
error_code error, // Result of operation.
|
||||
std::size_t bytes_transferred // Number of bytes written.
|
||||
);
|
||||
@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
|
||||
`net::post()`.
|
||||
*/
|
||||
template<class ConstBufferSequence, class WriteHandler>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler,
|
||||
void(error_code, std::size_t))
|
||||
async_write_some(
|
||||
ConstBufferSequence const& buffers,
|
||||
WriteHandler&& handler);
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** Asynchronously establishes a socket connection by trying each endpoint in a sequence, and terminating if a timeout occurs.
|
||||
|
||||
This function attempts to connect a socket to one of a sequence of
|
||||
endpoints. It does this by repeated calls to the underlying socket's
|
||||
@c async_connect member function, once for each endpoint in the sequence,
|
||||
until a connection is successfully established or a timeout occurs.
|
||||
|
||||
@param stream The @ref beast::basic_timeout_stream to be connected. If the
|
||||
underlying socket is already open, it will be closed.
|
||||
|
||||
@param endpoints A sequence of endpoints. This this object must meet
|
||||
the requirements of <em>EndpointSequence</em>.
|
||||
|
||||
@param handler The handler to be called when the connect operation
|
||||
completes. Ownership of the handler may be transferred. The function
|
||||
signature of the handler must be:
|
||||
@code
|
||||
void handler(
|
||||
// Result of operation. if the sequence is empty, set to
|
||||
// net::error::not_found. Otherwise, contains the
|
||||
// error from the last connection attempt.
|
||||
error_code const& error,
|
||||
|
||||
// On success, the successfully connected endpoint.
|
||||
// Otherwise, a default-constructed endpoint.
|
||||
typename Protocol::endpoint const& endpoint
|
||||
);
|
||||
@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
|
||||
`net::io_context::post()`.
|
||||
*/
|
||||
template<
|
||||
class Protocol, class Executor,
|
||||
class EndpointSequence,
|
||||
class RangeConnectHandler
|
||||
#if ! BOOST_BEAST_DOXYGEN
|
||||
,class = typename std::enable_if<
|
||||
net::is_endpoint_sequence<
|
||||
EndpointSequence>::value>::type
|
||||
#endif
|
||||
>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(RangeConnectHandler,
|
||||
void (error_code, typename Protocol::endpoint))
|
||||
async_connect(
|
||||
basic_timeout_stream<Protocol, Executor>& stream,
|
||||
EndpointSequence const& endpoints,
|
||||
RangeConnectHandler&& handler);
|
||||
|
||||
/** Asynchronously establishes a socket connection by trying each endpoint in a sequence, and terminating if a timeout occurs.
|
||||
|
||||
This function attempts to connect a socket to one of a sequence of
|
||||
endpoints. It does this by repeated calls to the underlying socket's
|
||||
@c async_connect member function, once for each endpoint in the sequence,
|
||||
until a connection is successfully established or a timeout occurs.
|
||||
|
||||
@param stream The @ref beast::basic_timeout_stream to be connected. If the
|
||||
underlying socket is already open, it will be closed.
|
||||
|
||||
@param endpoints A sequence of endpoints. This this object must meet
|
||||
the requirements of <em>EndpointSequence</em>.
|
||||
|
||||
@param connect_condition A function object that is called prior to each
|
||||
connection attempt. The signature of the function object must be:
|
||||
@code
|
||||
bool connect_condition(
|
||||
error_code const& ec,
|
||||
typename Protocol::endpoint const& next);
|
||||
@endcode
|
||||
The @c ec parameter contains the result from the most recent connect
|
||||
operation. Before the first connection attempt, @c ec is always set to
|
||||
indicate success. The @c next parameter is the next endpoint to be tried.
|
||||
The function object should return true if the next endpoint should be tried,
|
||||
and false if it should be skipped.
|
||||
|
||||
@param handler The handler to be called when the connect operation
|
||||
completes. Ownership of the handler may be transferred. The function
|
||||
signature of the handler must be:
|
||||
@code
|
||||
void handler(
|
||||
// Result of operation. if the sequence is empty, set to
|
||||
// net::error::not_found. Otherwise, contains the
|
||||
// error from the last connection attempt.
|
||||
error_code const& error,
|
||||
|
||||
// On success, the successfully connected endpoint.
|
||||
// Otherwise, a default-constructed endpoint.
|
||||
typename Protocol::endpoint const& endpoint
|
||||
);
|
||||
@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
|
||||
`net::io_context::post()`.
|
||||
|
||||
@par Example
|
||||
The following connect condition function object can be used to output
|
||||
information about the individual connection attempts:
|
||||
@code
|
||||
struct my_connect_condition
|
||||
{
|
||||
bool operator()(
|
||||
error_code const& ec,
|
||||
net::ip::tcp::endpoint const& next)
|
||||
{
|
||||
if (ec)
|
||||
std::cout << "Error: " << ec.message() << std::endl;
|
||||
std::cout << "Trying: " << next << std::endl;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
@endcode
|
||||
*/
|
||||
template<
|
||||
class Protocol, class Executor,
|
||||
class EndpointSequence,
|
||||
class ConnectCondition,
|
||||
class RangeConnectHandler
|
||||
#if ! BOOST_BEAST_DOXYGEN
|
||||
,class = typename std::enable_if<
|
||||
net::is_endpoint_sequence<
|
||||
EndpointSequence>::value>::type
|
||||
#endif
|
||||
>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(RangeConnectHandler,
|
||||
void (error_code, typename Protocol::endpoint))
|
||||
async_connect(
|
||||
basic_timeout_stream<Protocol, Executor>& stream,
|
||||
EndpointSequence const& endpoints,
|
||||
ConnectCondition connect_condition,
|
||||
RangeConnectHandler&& handler);
|
||||
|
||||
/** Asynchronously establishes a socket connection by trying each endpoint in a sequence, and terminating if a timeout occurs.
|
||||
|
||||
This function attempts to connect a socket to one of a sequence of
|
||||
endpoints. It does this by repeated calls to the underlying socket's
|
||||
@c async_connect member function, once for each endpoint in the sequence,
|
||||
until a connection is successfully established or a timeout occurs.
|
||||
|
||||
@param stream The @ref beast::basic_timeout_stream to be connected. If the
|
||||
underlying socket is already open, it will be closed.
|
||||
|
||||
@param begin An iterator pointing to the start of a sequence of endpoints.
|
||||
|
||||
@param end An iterator pointing to the end of a sequence of endpoints.
|
||||
|
||||
@param handler The handler to be called when the connect operation
|
||||
completes. Ownership of the handler may be transferred. The function
|
||||
signature of the handler must be:
|
||||
@code
|
||||
void handler(
|
||||
// Result of operation. if the sequence is empty, set to
|
||||
// net::error::not_found. Otherwise, contains the
|
||||
// error from the last connection attempt.
|
||||
error_code const& error,
|
||||
|
||||
// On success, an iterator denoting the successfully
|
||||
// connected endpoint. Otherwise, the end iterator.
|
||||
Iterator iterator
|
||||
);
|
||||
@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
|
||||
`net::io_context::post()`.
|
||||
*/
|
||||
template<
|
||||
class Protocol, class Executor,
|
||||
class Iterator,
|
||||
class IteratorConnectHandler>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler,
|
||||
void (error_code, Iterator))
|
||||
async_connect(
|
||||
basic_timeout_stream<Protocol, Executor>& stream,
|
||||
Iterator begin, Iterator end,
|
||||
IteratorConnectHandler&& handler);
|
||||
|
||||
/** Asynchronously establishes a socket connection by trying each endpoint in a sequence, and terminating if a timeout occurs.
|
||||
|
||||
This function attempts to connect a socket to one of a sequence of
|
||||
endpoints. It does this by repeated calls to the underlying socket's
|
||||
@c async_connect member function, once for each endpoint in the sequence,
|
||||
until a connection is successfully established or a timeout occurs.
|
||||
|
||||
@param stream The @ref beast::basic_timeout_stream to be connected. If the
|
||||
underlying socket is already open, it will be closed.
|
||||
|
||||
@param begin An iterator pointing to the start of a sequence of endpoints.
|
||||
|
||||
@param end An iterator pointing to the end of a sequence of endpoints.
|
||||
|
||||
@param connect_condition A function object that is called prior to each
|
||||
connection attempt. The signature of the function object must be:
|
||||
@code
|
||||
bool connect_condition(
|
||||
error_code const& ec,
|
||||
Iterator next);
|
||||
@endcode
|
||||
@param handler The handler to be called when the connect operation
|
||||
completes. Ownership of the handler may be transferred. The function
|
||||
signature of the handler must be:
|
||||
@code
|
||||
void handler(
|
||||
// Result of operation. if the sequence is empty, set to
|
||||
// net::error::not_found. Otherwise, contains the
|
||||
// error from the last connection attempt.
|
||||
error_code const& error,
|
||||
|
||||
// On success, an iterator denoting the successfully
|
||||
// connected endpoint. Otherwise, the end iterator.
|
||||
Iterator iterator
|
||||
);
|
||||
@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
|
||||
`net::io_context::post()`.
|
||||
*/
|
||||
template<
|
||||
class Protocol, class Executor,
|
||||
class Iterator,
|
||||
class ConnectCondition,
|
||||
class IteratorConnectHandler>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler,
|
||||
void (error_code, Iterator))
|
||||
async_connect(
|
||||
basic_timeout_stream<Protocol, Executor>& stream,
|
||||
Iterator begin, Iterator end,
|
||||
ConnectCondition connect_condition,
|
||||
IteratorConnectHandler&& handler);
|
||||
|
||||
} // beast
|
||||
} // boost
|
||||
|
||||
#include <boost/beast/core/impl/basic_timeout_stream.hpp>
|
||||
|
||||
#endif
|
@@ -78,6 +78,25 @@ struct buffer_size_impl
|
||||
}
|
||||
};
|
||||
|
||||
/** Return `true` if a buffer sequence is empty
|
||||
|
||||
This is sometimes faster than using @ref buffer_size
|
||||
*/
|
||||
template<class ConstBufferSequence>
|
||||
bool
|
||||
buffers_empty(ConstBufferSequence const& buffers)
|
||||
{
|
||||
auto it = net::buffer_sequence_begin(buffers);
|
||||
auto end = net::buffer_sequence_end(buffers);
|
||||
while(it != end)
|
||||
{
|
||||
if(net::const_buffer(*it).size() > 0)
|
||||
return false;
|
||||
++it;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // detail
|
||||
|
||||
/** Return the total number of bytes in a buffer or buffer sequence
|
||||
|
@@ -1,42 +0,0 @@
|
||||
//
|
||||
// Copyright (c) 2018 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_CORE_DETAIL_STRANDED_SOCKET_HPP
|
||||
#define BOOST_BEAST_CORE_DETAIL_STRANDED_SOCKET_HPP
|
||||
|
||||
#include <boost/beast/core/detail/bind_default_executor.hpp>
|
||||
#include <boost/asio/basic_stream_socket.hpp>
|
||||
#include <utility>
|
||||
|
||||
namespace boost {
|
||||
namespace beast {
|
||||
namespace detail {
|
||||
|
||||
template<class Protocol>
|
||||
class stranded_socket_base
|
||||
{
|
||||
protected:
|
||||
net::basic_stream_socket<Protocol> socket_;
|
||||
|
||||
template<class... Args>
|
||||
explicit
|
||||
stranded_socket_base(Args&&... args)
|
||||
: socket_(std::forward<Args>(args)...)
|
||||
{
|
||||
}
|
||||
|
||||
stranded_socket_base(stranded_socket_base&&) = default;
|
||||
stranded_socket_base& operator=(stranded_socket_base&&) = delete;
|
||||
};
|
||||
|
||||
} // detail
|
||||
} // beast
|
||||
} // boost
|
||||
|
||||
#endif
|
@@ -7,18 +7,21 @@
|
||||
// Official repository: https://github.com/boostorg/beast
|
||||
//
|
||||
|
||||
#ifndef BOOST_BEAST_CORE_DETAIL_TIMEOUT_STREAM_BASE_HPP
|
||||
#define BOOST_BEAST_CORE_DETAIL_TIMEOUT_STREAM_BASE_HPP
|
||||
#ifndef BOOST_BEAST_CORE_DETAIL_STREAM_BASE_HPP
|
||||
#define BOOST_BEAST_CORE_DETAIL_STREAM_BASE_HPP
|
||||
|
||||
#include <boost/asio/steady_timer.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/core/exchange.hpp>
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
|
||||
namespace boost {
|
||||
namespace beast {
|
||||
namespace detail {
|
||||
|
||||
template<class, class, class>
|
||||
class timeout_stream_connect_op;
|
||||
class basic_stream_connect_op;
|
||||
|
||||
struct any_endpoint
|
||||
{
|
||||
@@ -31,9 +34,27 @@ struct any_endpoint
|
||||
}
|
||||
};
|
||||
|
||||
class timeout_stream_base
|
||||
struct stream_base
|
||||
{
|
||||
protected:
|
||||
using clock_type = std::chrono::steady_clock;
|
||||
using time_point = typename
|
||||
std::chrono::steady_clock::time_point;
|
||||
using tick_type = std::uint64_t;
|
||||
|
||||
struct op_state
|
||||
{
|
||||
net::steady_timer timer; // for timing out
|
||||
tick_type tick = 0; // counts waits
|
||||
bool pending = false; // if op is pending
|
||||
bool timeout = false; // if timed out
|
||||
|
||||
explicit
|
||||
op_state(net::io_context& ioc)
|
||||
: timer(ioc)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class pending_guard
|
||||
{
|
||||
bool& b_;
|
||||
@@ -70,6 +91,14 @@ protected:
|
||||
clear_ = false;
|
||||
}
|
||||
};
|
||||
|
||||
static constexpr time_point never()
|
||||
{
|
||||
return (time_point::max)();
|
||||
}
|
||||
|
||||
static std::size_t constexpr no_limit =
|
||||
(std::numeric_limits<std::size_t>::max)();
|
||||
};
|
||||
|
||||
} // detail
|
@@ -7,11 +7,13 @@
|
||||
// Official repository: https://github.com/boostorg/beast
|
||||
//
|
||||
|
||||
#ifndef BOOST_BEAST_CORE_IMPL_BASIC_TIMEOUT_STREAM_HPP
|
||||
#define BOOST_BEAST_CORE_IMPL_BASIC_TIMEOUT_STREAM_HPP
|
||||
#ifndef BOOST_BEAST_CORE_IMPL_BASIC_STREAM_HPP
|
||||
#define BOOST_BEAST_CORE_IMPL_BASIC_STREAM_HPP
|
||||
|
||||
#include <boost/beast/core/async_op_base.hpp>
|
||||
#include <boost/beast/core/buffers_prefix.hpp>
|
||||
#include <boost/beast/core/buffer_size.hpp>
|
||||
#include <boost/beast/core/detail/type_traits.hpp>
|
||||
#include <boost/beast/websocket/teardown.hpp>
|
||||
#include <boost/asio/bind_executor.hpp>
|
||||
#include <boost/asio/coroutine.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
@@ -23,8 +25,96 @@
|
||||
namespace boost {
|
||||
namespace beast {
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<class Protocol, class Executor>
|
||||
struct basic_timeout_stream<
|
||||
template<class... Args>
|
||||
basic_stream<Protocol, Executor>::
|
||||
impl_type::
|
||||
impl_type(
|
||||
Executor const& ex_,
|
||||
Args&&... args)
|
||||
: boost::empty_value<Executor>(
|
||||
boost::empty_init_t{}, ex_)
|
||||
, read(ex().context())
|
||||
, write(ex().context())
|
||||
, socket(std::forward<Args>(args)...)
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
template<class Protocol, class Executor>
|
||||
template<class OtherProtocol>
|
||||
basic_stream<Protocol, Executor>::
|
||||
impl_type::
|
||||
impl_type(net::basic_stream_socket<OtherProtocol>&& socket_,
|
||||
std::true_type)
|
||||
: boost::empty_value<Executor>(
|
||||
boost::empty_init_t{}, socket_.get_executor())
|
||||
, read(ex().context())
|
||||
, write(ex().context())
|
||||
, socket(std::move(socket_))
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
template<class Protocol, class Executor>
|
||||
template<class OtherProtocol>
|
||||
basic_stream<Protocol, Executor>::
|
||||
impl_type::
|
||||
impl_type(net::basic_stream_socket<OtherProtocol>&& socket_,
|
||||
std::false_type)
|
||||
: boost::empty_value<Executor>(boost::empty_init_t{},
|
||||
socket_.get_executor().context())
|
||||
, read(ex().context())
|
||||
, write(ex().context())
|
||||
, socket(std::move(socket_))
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
template<class Protocol, class Executor>
|
||||
void
|
||||
basic_stream<Protocol, Executor>::
|
||||
impl_type::
|
||||
reset()
|
||||
{
|
||||
// If assert goes off, it means that there are
|
||||
// already read or write (or connect) operations
|
||||
// outstanding, so there is nothing to apply
|
||||
// the expiration time to!
|
||||
//
|
||||
BOOST_ASSERT(! read.pending || ! write.pending);
|
||||
|
||||
if(! read.pending)
|
||||
BOOST_VERIFY(
|
||||
read.timer.expires_at(never()) == 0);
|
||||
|
||||
if(! write.pending)
|
||||
BOOST_VERIFY(
|
||||
write.timer.expires_at(never()) == 0);
|
||||
}
|
||||
|
||||
template<class Protocol, class Executor>
|
||||
void
|
||||
basic_stream<Protocol, Executor>::
|
||||
impl_type::
|
||||
close()
|
||||
{
|
||||
socket.close();
|
||||
|
||||
// have to let the read/write ops cancel the timer,
|
||||
// otherwise we will get error::timeout on close when
|
||||
// we actually want net::error::operation_aborted.
|
||||
//
|
||||
//read.timer.cancel();
|
||||
//write.timer.cancel();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<class Protocol, class Executor>
|
||||
struct basic_stream<
|
||||
Protocol, Executor>::timeout_handler
|
||||
{
|
||||
op_state& state;
|
||||
@@ -50,14 +140,8 @@ struct basic_timeout_stream<
|
||||
return;
|
||||
BOOST_ASSERT(tick == state.tick);
|
||||
|
||||
// late completion
|
||||
if(state.timeout)
|
||||
{
|
||||
state.timeout = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// timeout
|
||||
BOOST_ASSERT(! state.timeout);
|
||||
sp->close();
|
||||
state.timeout = true;
|
||||
}
|
||||
@@ -75,7 +159,7 @@ struct basic_timeout_stream<
|
||||
|
||||
template<class Protocol, class Executor>
|
||||
template<bool isRead, class Buffers, class Handler>
|
||||
class basic_timeout_stream<Protocol, Executor>::async_op
|
||||
class basic_stream<Protocol, Executor>::async_op
|
||||
: public async_op_base<Handler, Executor>
|
||||
, public boost::asio::coroutine
|
||||
{
|
||||
@@ -119,7 +203,7 @@ class basic_timeout_stream<Protocol, Executor>::async_op
|
||||
public:
|
||||
template<class Handler_>
|
||||
async_op(
|
||||
basic_timeout_stream& s,
|
||||
basic_stream& s,
|
||||
Buffers const& b,
|
||||
Handler_&& h)
|
||||
: async_op_base<Handler, Executor>(
|
||||
@@ -138,8 +222,17 @@ public:
|
||||
{
|
||||
BOOST_ASIO_CORO_REENTER(*this)
|
||||
{
|
||||
// VFALCO TODO handle buffer size == 0
|
||||
if(detail::buffers_empty(b_))
|
||||
{
|
||||
BOOST_ASIO_CORO_YIELD
|
||||
async_perform(
|
||||
std::integral_constant<bool, isRead>{});
|
||||
if(state().timer.expiry() <= clock_type::now())
|
||||
ec = beast::error::timeout;
|
||||
goto upcall;
|
||||
}
|
||||
|
||||
if(state().timer.expiry() != never())
|
||||
state().timer.async_wait(
|
||||
net::bind_executor(
|
||||
this->get_executor(),
|
||||
@@ -152,6 +245,9 @@ public:
|
||||
BOOST_ASIO_CORO_YIELD
|
||||
async_perform(
|
||||
std::integral_constant<bool, isRead>{});
|
||||
|
||||
if(state().timer.expiry() != never())
|
||||
{
|
||||
++state().tick;
|
||||
|
||||
// try cancelling timer
|
||||
@@ -159,23 +255,22 @@ public:
|
||||
state().timer.cancel();
|
||||
if(n == 0)
|
||||
{
|
||||
// timeout handler invoked?
|
||||
if(state().timeout)
|
||||
{
|
||||
// timeout handler invoked
|
||||
// yes, socket already closed
|
||||
ec = beast::error::timeout;
|
||||
state().timeout = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// timeout handler queued, stale
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(n == 1);
|
||||
BOOST_ASSERT(! state().timeout);
|
||||
}
|
||||
}
|
||||
|
||||
upcall:
|
||||
pg_.reset();
|
||||
this->invoke(ec, bytes_transferred);
|
||||
}
|
||||
@@ -188,17 +283,17 @@ namespace detail {
|
||||
|
||||
template<
|
||||
class Protocol, class Executor, class Handler>
|
||||
class timeout_stream_connect_op
|
||||
class basic_stream_connect_op
|
||||
: public async_op_base<Handler, Executor>
|
||||
{
|
||||
using stream_type =
|
||||
beast::basic_timeout_stream<Protocol, Executor>;
|
||||
beast::basic_stream<Protocol, Executor>;
|
||||
|
||||
using timeout_handler =
|
||||
typename stream_type::timeout_handler;
|
||||
|
||||
std::shared_ptr<typename basic_timeout_stream<
|
||||
Protocol, Executor>::impl_type> impl_;
|
||||
std::shared_ptr<typename
|
||||
stream_type::impl_type> impl_;
|
||||
typename stream_type::pending_guard pg0_;
|
||||
typename stream_type::pending_guard pg1_;
|
||||
|
||||
@@ -209,13 +304,10 @@ class timeout_stream_connect_op
|
||||
}
|
||||
|
||||
public:
|
||||
template<
|
||||
class Endpoints, class Condition,
|
||||
class Handler_>
|
||||
timeout_stream_connect_op(
|
||||
template<class Handler_>
|
||||
basic_stream_connect_op(
|
||||
stream_type& s,
|
||||
Endpoints const& eps,
|
||||
Condition cond,
|
||||
typename stream_type::endpoint_type ep,
|
||||
Handler_&& h)
|
||||
: async_op_base<Handler, Executor>(
|
||||
std::forward<Handler_>(h), s.get_executor())
|
||||
@@ -223,7 +315,35 @@ public:
|
||||
, pg0_(impl_->read.pending)
|
||||
, pg1_(impl_->write.pending)
|
||||
{
|
||||
// must come first
|
||||
if(state().timer.expiry() != stream_base::never())
|
||||
impl_->write.timer.async_wait(
|
||||
net::bind_executor(
|
||||
this->get_executor(),
|
||||
timeout_handler{
|
||||
state(),
|
||||
impl_,
|
||||
state().tick}));
|
||||
|
||||
impl_->socket.async_connect(
|
||||
ep, std::move(*this));
|
||||
// *this is now moved-from
|
||||
}
|
||||
|
||||
template<
|
||||
class Endpoints, class Condition,
|
||||
class Handler_>
|
||||
basic_stream_connect_op(
|
||||
stream_type& s,
|
||||
Endpoints const& eps,
|
||||
Condition const& cond,
|
||||
Handler_&& h)
|
||||
: async_op_base<Handler, Executor>(
|
||||
std::forward<Handler_>(h), s.get_executor())
|
||||
, impl_(s.impl_)
|
||||
, pg0_(impl_->read.pending)
|
||||
, pg1_(impl_->write.pending)
|
||||
{
|
||||
if(state().timer.expiry() != stream_base::never())
|
||||
impl_->write.timer.async_wait(
|
||||
net::bind_executor(
|
||||
this->get_executor(),
|
||||
@@ -240,10 +360,10 @@ public:
|
||||
template<
|
||||
class Iterator, class Condition,
|
||||
class Handler_>
|
||||
timeout_stream_connect_op(
|
||||
basic_stream_connect_op(
|
||||
stream_type& s,
|
||||
Iterator begin, Iterator end,
|
||||
Condition cond,
|
||||
Condition const& cond,
|
||||
Handler_&& h)
|
||||
: async_op_base<Handler, Executor>(
|
||||
std::forward<Handler_>(h), s.get_executor())
|
||||
@@ -251,7 +371,7 @@ public:
|
||||
, pg0_(impl_->read.pending)
|
||||
, pg1_(impl_->write.pending)
|
||||
{
|
||||
// must come first
|
||||
if(state().timer.expiry() != stream_base::never())
|
||||
impl_->write.timer.async_wait(
|
||||
net::bind_executor(
|
||||
this->get_executor(),
|
||||
@@ -265,34 +385,11 @@ public:
|
||||
// *this is now moved-from
|
||||
}
|
||||
|
||||
template<class Handler_>
|
||||
timeout_stream_connect_op(
|
||||
stream_type& s,
|
||||
typename stream_type::endpoint_type ep,
|
||||
Handler_&& h)
|
||||
: async_op_base<Handler, Executor>(
|
||||
std::forward<Handler_>(h), s.get_executor())
|
||||
, impl_(s.impl_)
|
||||
, pg0_(impl_->read.pending)
|
||||
, pg1_(impl_->write.pending)
|
||||
{
|
||||
// must come first
|
||||
impl_->write.timer.async_wait(
|
||||
net::bind_executor(
|
||||
this->get_executor(),
|
||||
timeout_handler{
|
||||
state(),
|
||||
impl_,
|
||||
state().tick}));
|
||||
|
||||
impl_->socket.async_connect(
|
||||
ep, std::move(*this));
|
||||
// *this is now moved-from
|
||||
}
|
||||
|
||||
template<class... Args>
|
||||
void
|
||||
operator()(error_code ec, Args&&... args)
|
||||
{
|
||||
if(state().timer.expiry() != stream_base::never())
|
||||
{
|
||||
++state().tick;
|
||||
|
||||
@@ -301,22 +398,20 @@ public:
|
||||
impl_->write.timer.cancel();
|
||||
if(n == 0)
|
||||
{
|
||||
// timeout handler invoked?
|
||||
if(state().timeout)
|
||||
{
|
||||
// timeout handler invoked
|
||||
// yes, socket already closed
|
||||
ec = beast::error::timeout;
|
||||
state().timeout = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// timeout handler queued, stale
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(n == 1);
|
||||
BOOST_ASSERT(! state().timeout);
|
||||
}
|
||||
}
|
||||
|
||||
pg0_.reset();
|
||||
pg1_.reset();
|
||||
@@ -329,82 +424,8 @@ public:
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<class Protocol, class Executor>
|
||||
template<class... Args>
|
||||
basic_timeout_stream<Protocol, Executor>::
|
||||
impl_type::
|
||||
impl_type(
|
||||
Executor const& ex_,
|
||||
Args&&... args)
|
||||
: ex(ex_)
|
||||
, read(ex_.context())
|
||||
, write(ex_.context())
|
||||
, socket(std::forward<Args>(args)...)
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
template<class Protocol, class Executor>
|
||||
auto
|
||||
basic_timeout_stream<Protocol, Executor>::
|
||||
impl_type::
|
||||
operator=(impl_type&& other) -> impl_type&
|
||||
{
|
||||
// VFALCO This hack is because legacy io_context::strand
|
||||
// doesn't support operator=. Don't worry, constructing
|
||||
// an executor cannot throw.
|
||||
ex.~Executor();
|
||||
::new(&ex) Executor(other.ex);
|
||||
|
||||
socket = std::move(other.socket);
|
||||
read = std::move(other.read);
|
||||
write = std::move(other.write);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class Protocol, class Executor>
|
||||
void
|
||||
basic_timeout_stream<Protocol, Executor>::
|
||||
impl_type::
|
||||
reset()
|
||||
{
|
||||
// If assert goes off, it means that there are
|
||||
// already read or write (or connect) operations
|
||||
// outstanding, so there is nothing to apply
|
||||
// the expiration time to!
|
||||
//
|
||||
BOOST_ASSERT(! read.pending || ! write.pending);
|
||||
|
||||
if(! read.pending)
|
||||
BOOST_VERIFY(
|
||||
read.timer.expires_at(never()) == 0);
|
||||
|
||||
if(! write.pending)
|
||||
BOOST_VERIFY(
|
||||
write.timer.expires_at(never()) == 0);
|
||||
}
|
||||
|
||||
template<class Protocol, class Executor>
|
||||
void
|
||||
basic_timeout_stream<Protocol, Executor>::
|
||||
impl_type::
|
||||
close()
|
||||
{
|
||||
socket.close();
|
||||
|
||||
// have to let the read/write ops cancel the timer,
|
||||
// otherwise we will get error::timeout on close when
|
||||
// we actually want net::error::operation_aborted.
|
||||
//
|
||||
//read.timer.cancel();
|
||||
//write.timer.cancel();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<class Protocol, class Executor>
|
||||
basic_timeout_stream<Protocol, Executor>::
|
||||
~basic_timeout_stream()
|
||||
basic_stream<Protocol, Executor>::
|
||||
~basic_stream()
|
||||
{
|
||||
// the shared object can outlive *this,
|
||||
// cancel any operations so the shared
|
||||
@@ -413,12 +434,12 @@ basic_timeout_stream<Protocol, Executor>::
|
||||
}
|
||||
|
||||
template<class Protocol, class Executor>
|
||||
template<class ExecutionContext, class>
|
||||
basic_timeout_stream<Protocol, Executor>::
|
||||
basic_timeout_stream(ExecutionContext& ctx)
|
||||
template<class ExecutionContext, class... Args, class>
|
||||
basic_stream<Protocol, Executor>::
|
||||
basic_stream(ExecutionContext& ctx, Args&&... args)
|
||||
: impl_(std::make_shared<impl_type>(
|
||||
ctx.get_executor(),
|
||||
ctx))
|
||||
ctx, std::forward<Args>(args)...))
|
||||
{
|
||||
// Restriction is necessary until Asio fully supports P1322R0
|
||||
static_assert(
|
||||
@@ -427,67 +448,52 @@ basic_timeout_stream(ExecutionContext& ctx)
|
||||
}
|
||||
|
||||
template<class Protocol, class Executor>
|
||||
basic_timeout_stream<Protocol, Executor>::
|
||||
basic_timeout_stream(executor_type const& ex)
|
||||
template<class... Args>
|
||||
basic_stream<Protocol, Executor>::
|
||||
basic_stream(
|
||||
executor_type const& ex, Args&&... args)
|
||||
: impl_(std::make_shared<impl_type>(
|
||||
ex, ex.context()))
|
||||
ex,
|
||||
ex.context(), std::forward<Args>(args)...))
|
||||
{
|
||||
}
|
||||
|
||||
template<class Protocol, class Executor>
|
||||
basic_timeout_stream<Protocol, Executor>::
|
||||
basic_timeout_stream(
|
||||
net::basic_stream_socket<Protocol>&& socket)
|
||||
template<class OtherProtocol, class>
|
||||
basic_stream<Protocol, Executor>::
|
||||
basic_stream(net::basic_stream_socket<OtherProtocol>&& socket)
|
||||
: impl_(std::make_shared<impl_type>(
|
||||
socket.get_executor(), std::move(socket)))
|
||||
std::move(socket),
|
||||
std::is_constructible<Executor,
|
||||
decltype(std::declval<net::basic_stream_socket<
|
||||
Protocol>&>().get_executor())>{}))
|
||||
{
|
||||
}
|
||||
|
||||
template<class Protocol, class Executor>
|
||||
basic_timeout_stream<Protocol, Executor>::
|
||||
basic_timeout_stream(
|
||||
executor_type const& ex,
|
||||
net::basic_stream_socket<Protocol>&& socket)
|
||||
: impl_(std::make_shared<impl_type>(
|
||||
ex, std::move(socket)))
|
||||
{
|
||||
// Restriction is necessary until Asio fully supports P1322R0
|
||||
if(ex.context().get_executor() != socket.get_executor())
|
||||
throw std::invalid_argument(
|
||||
"basic_timeout_stream currently requires ctx.get_executor() == socket.get_executor()");
|
||||
}
|
||||
|
||||
template<class Protocol, class Executor>
|
||||
basic_timeout_stream<Protocol, Executor>::
|
||||
basic_timeout_stream(basic_timeout_stream&& other)
|
||||
basic_stream<Protocol, Executor>::
|
||||
basic_stream(basic_stream&& other)
|
||||
: impl_(std::make_shared<impl_type>(
|
||||
std::move(*other.impl_)))
|
||||
{
|
||||
// Can't move while operations are pending!
|
||||
BOOST_ASSERT(! impl_->read.pending);
|
||||
BOOST_ASSERT(! impl_->write.pending);
|
||||
}
|
||||
|
||||
template<class Protocol, class Executor>
|
||||
auto
|
||||
basic_timeout_stream<Protocol, Executor>::
|
||||
operator=(basic_timeout_stream&& other) ->
|
||||
basic_timeout_stream&
|
||||
{
|
||||
// Can't move while operations are pending!
|
||||
BOOST_ASSERT(! impl_->read.pending);
|
||||
BOOST_ASSERT(! impl_->write.pending);
|
||||
BOOST_ASSERT(! other.impl_->read.pending);
|
||||
BOOST_ASSERT(! other.impl_->write.pending);
|
||||
*impl_ = std::move(*other.impl_);
|
||||
return *this;
|
||||
// VFALCO I'm not sure this implementation is correct...
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<class Protocol, class Executor>
|
||||
auto
|
||||
basic_stream<Protocol, Executor>::
|
||||
release_socket() ->
|
||||
socket_type
|
||||
{
|
||||
this->cancel();
|
||||
return std::move(impl_->socket);
|
||||
}
|
||||
|
||||
template<class Protocol, class Executor>
|
||||
void
|
||||
basic_timeout_stream<Protocol, Executor>::
|
||||
basic_stream<Protocol, Executor>::
|
||||
expires_after(std::chrono::nanoseconds expiry_time)
|
||||
{
|
||||
// If assert goes off, it means that there are
|
||||
@@ -512,7 +518,7 @@ expires_after(std::chrono::nanoseconds expiry_time)
|
||||
|
||||
template<class Protocol, class Executor>
|
||||
void
|
||||
basic_timeout_stream<Protocol, Executor>::
|
||||
basic_stream<Protocol, Executor>::
|
||||
expires_at(
|
||||
net::steady_timer::time_point expiry_time)
|
||||
{
|
||||
@@ -538,7 +544,7 @@ expires_at(
|
||||
|
||||
template<class Protocol, class Executor>
|
||||
void
|
||||
basic_timeout_stream<Protocol, Executor>::
|
||||
basic_stream<Protocol, Executor>::
|
||||
expires_never()
|
||||
{
|
||||
impl_->reset();
|
||||
@@ -546,7 +552,7 @@ expires_never()
|
||||
|
||||
template<class Protocol, class Executor>
|
||||
void
|
||||
basic_timeout_stream<Protocol, Executor>::
|
||||
basic_stream<Protocol, Executor>::
|
||||
cancel()
|
||||
{
|
||||
error_code ec;
|
||||
@@ -555,7 +561,7 @@ cancel()
|
||||
|
||||
template<class Protocol, class Executor>
|
||||
void
|
||||
basic_timeout_stream<Protocol, Executor>::
|
||||
basic_stream<Protocol, Executor>::
|
||||
close()
|
||||
{
|
||||
impl_->close();
|
||||
@@ -565,14 +571,14 @@ template<class Protocol, class Executor>
|
||||
template<class ConnectHandler>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(ConnectHandler,
|
||||
void(error_code))
|
||||
basic_timeout_stream<Protocol, Executor>::
|
||||
basic_stream<Protocol, Executor>::
|
||||
async_connect(
|
||||
endpoint_type ep,
|
||||
endpoint_type const& ep,
|
||||
ConnectHandler&& handler)
|
||||
{
|
||||
BOOST_BEAST_HANDLER_INIT(
|
||||
ConnectHandler, void(error_code));
|
||||
detail::timeout_stream_connect_op<
|
||||
detail::basic_stream_connect_op<
|
||||
Protocol, Executor, BOOST_ASIO_HANDLER_TYPE(
|
||||
ConnectHandler, void(error_code))>(*this,
|
||||
ep, std::forward<ConnectHandler>(handler));
|
||||
@@ -583,7 +589,7 @@ template<class Protocol, class Executor>
|
||||
template<class MutableBufferSequence, class ReadHandler>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
|
||||
void(error_code, std::size_t))
|
||||
basic_timeout_stream<Protocol, Executor>::
|
||||
basic_stream<Protocol, Executor>::
|
||||
async_read_some(
|
||||
MutableBufferSequence const& buffers,
|
||||
ReadHandler&& handler)
|
||||
@@ -603,7 +609,7 @@ template<class Protocol, class Executor>
|
||||
template<class ConstBufferSequence, class WriteHandler>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler,
|
||||
void(error_code, std::size_t))
|
||||
basic_timeout_stream<Protocol, Executor>::
|
||||
basic_stream<Protocol, Executor>::
|
||||
async_write_some(
|
||||
ConstBufferSequence const& buffers,
|
||||
WriteHandler&& handler)
|
||||
@@ -629,13 +635,13 @@ template<
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(RangeConnectHandler,
|
||||
void(error_code, typename Protocol::endpoint))
|
||||
async_connect(
|
||||
basic_timeout_stream<Protocol, Executor>& stream,
|
||||
basic_stream<Protocol, Executor>& stream,
|
||||
EndpointSequence const& endpoints,
|
||||
RangeConnectHandler&& handler)
|
||||
{
|
||||
BOOST_BEAST_HANDLER_INIT(RangeConnectHandler,
|
||||
void(error_code, typename Protocol::endpoint));
|
||||
detail::timeout_stream_connect_op<Protocol, Executor,
|
||||
detail::basic_stream_connect_op<Protocol, Executor,
|
||||
BOOST_ASIO_HANDLER_TYPE(RangeConnectHandler,
|
||||
void(error_code, typename Protocol::endpoint))>(
|
||||
stream, endpoints, detail::any_endpoint{},
|
||||
@@ -652,14 +658,14 @@ template<
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(RangeConnectHandler,
|
||||
void (error_code, typename Protocol::endpoint))
|
||||
async_connect(
|
||||
basic_timeout_stream<Protocol, Executor>& stream,
|
||||
basic_stream<Protocol, Executor>& stream,
|
||||
EndpointSequence const& endpoints,
|
||||
ConnectCondition connect_condition,
|
||||
RangeConnectHandler&& handler)
|
||||
{
|
||||
BOOST_BEAST_HANDLER_INIT(RangeConnectHandler,
|
||||
void(error_code, typename Protocol::endpoint));
|
||||
detail::timeout_stream_connect_op<Protocol, Executor,
|
||||
detail::basic_stream_connect_op<Protocol, Executor,
|
||||
BOOST_ASIO_HANDLER_TYPE(RangeConnectHandler,
|
||||
void(error_code, typename Protocol::endpoint))>(
|
||||
stream, endpoints, connect_condition,
|
||||
@@ -674,13 +680,13 @@ template<
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler,
|
||||
void (error_code, Iterator))
|
||||
async_connect(
|
||||
basic_timeout_stream<Protocol, Executor>& stream,
|
||||
basic_stream<Protocol, Executor>& stream,
|
||||
Iterator begin, Iterator end,
|
||||
IteratorConnectHandler&& handler)
|
||||
{
|
||||
BOOST_BEAST_HANDLER_INIT(IteratorConnectHandler,
|
||||
void(error_code, Iterator));
|
||||
detail::timeout_stream_connect_op<Protocol, Executor,
|
||||
detail::basic_stream_connect_op<Protocol, Executor,
|
||||
BOOST_ASIO_HANDLER_TYPE(IteratorConnectHandler,
|
||||
void(error_code, Iterator))>(
|
||||
stream, begin, end, detail::any_endpoint{},
|
||||
@@ -696,14 +702,14 @@ template<
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler,
|
||||
void (error_code, Iterator))
|
||||
async_connect(
|
||||
basic_timeout_stream<Protocol, Executor>& stream,
|
||||
basic_stream<Protocol, Executor>& stream,
|
||||
Iterator begin, Iterator end,
|
||||
ConnectCondition connect_condition,
|
||||
IteratorConnectHandler&& handler)
|
||||
{
|
||||
BOOST_BEAST_HANDLER_INIT(IteratorConnectHandler,
|
||||
void(error_code, Iterator));
|
||||
detail::timeout_stream_connect_op<Protocol, Executor,
|
||||
detail::basic_stream_connect_op<Protocol, Executor,
|
||||
BOOST_ASIO_HANDLER_TYPE(IteratorConnectHandler,
|
||||
void(error_code, Iterator))>(
|
||||
stream, begin, end, connect_condition,
|
||||
@@ -711,6 +717,46 @@ async_connect(
|
||||
return init.result.get();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#if ! BOOST_BEAST_DOXYGEN
|
||||
|
||||
template<class Protocol, class Executor>
|
||||
void
|
||||
beast_close_socket(
|
||||
basic_stream<Protocol, Executor>& stream)
|
||||
{
|
||||
error_code ec;
|
||||
stream.socket().close(ec);
|
||||
}
|
||||
|
||||
template<class Protocol, class Executor>
|
||||
void
|
||||
teardown(
|
||||
websocket::role_type role,
|
||||
basic_stream<Protocol, Executor>& stream,
|
||||
error_code& ec)
|
||||
{
|
||||
using beast::websocket::teardown;
|
||||
teardown(role, stream.socket(), ec);
|
||||
}
|
||||
|
||||
template<
|
||||
class Protocol, class Executor,
|
||||
class TeardownHandler>
|
||||
void
|
||||
async_teardown(
|
||||
websocket::role_type role,
|
||||
basic_stream<Protocol, Executor>& stream,
|
||||
TeardownHandler&& handler)
|
||||
{
|
||||
using beast::websocket::async_teardown;
|
||||
async_teardown(role, stream.socket(),
|
||||
std::forward<TeardownHandler>(handler));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // beast
|
||||
} // boost
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -7,22 +7,25 @@
|
||||
// Official repository: https://github.com/boostorg/beast
|
||||
//
|
||||
|
||||
#ifndef BOOST_BEAST_CORE_TIMEOUT_STREAM_HPP
|
||||
#define BOOST_BEAST_CORE_TIMEOUT_STREAM_HPP
|
||||
#ifndef BOOST_BEAST_CORE_TCP_STREAM_HPP
|
||||
#define BOOST_BEAST_CORE_TCP_STREAM_HPP
|
||||
|
||||
#include <boost/beast/core/detail/config.hpp>
|
||||
#include <boost/beast/core/basic_timeout_stream.hpp>
|
||||
#include <boost/beast/core/error.hpp>
|
||||
#include <boost/beast/core/basic_stream.hpp>
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace beast {
|
||||
|
||||
/** A TCP/IP stream socket which supports timeouts and rate limits
|
||||
/** A TCP/IP stream socket with timeouts, rate limits, and executor.
|
||||
|
||||
@tparam Executor The type of executor to use for all completion
|
||||
handlers which do not already have an associated executor.
|
||||
|
||||
@see basic_stream
|
||||
*/
|
||||
using timeout_stream = basic_timeout_stream<
|
||||
net::ip::tcp,
|
||||
net::io_context::executor_type>;
|
||||
template<class Executor>
|
||||
using tcp_stream = basic_stream<net::ip::tcp, Executor>;
|
||||
|
||||
} // beast
|
||||
} // boost
|
@@ -599,7 +599,7 @@ public:
|
||||
|
||||
@li An error occurs.
|
||||
|
||||
The algorithm, known as a <em>composed operation</em> is implemented
|
||||
The algorithm, known as a <em>composed operation</em>, is implemented
|
||||
in terms of calls to the next layer's `read_some` and `write_some`
|
||||
functions.
|
||||
|
||||
@@ -646,7 +646,7 @@ public:
|
||||
|
||||
@li An error occurs.
|
||||
|
||||
The algorithm, known as a <em>composed operation</em> is implemented
|
||||
The algorithm, known as a <em>composed operation</em>, is implemented
|
||||
in terms of calls to the next layer's `read_some` and `write_some`
|
||||
functions.
|
||||
|
||||
@@ -700,7 +700,7 @@ public:
|
||||
|
||||
@li An error occurs.
|
||||
|
||||
The algorithm, known as a <em>composed operation</em> is implemented
|
||||
The algorithm, known as a <em>composed operation</em>, is implemented
|
||||
in terms of calls to the next layer's `read_some` and `write_some`
|
||||
functions.
|
||||
|
||||
@@ -764,7 +764,7 @@ public:
|
||||
|
||||
@li An error occurs.
|
||||
|
||||
The algorithm, known as a <em>composed operation</em> is implemented
|
||||
The algorithm, known as a <em>composed operation</em>, is implemented
|
||||
in terms of calls to the next layer's `read_some` and `write_some`
|
||||
functions.
|
||||
|
||||
@@ -835,7 +835,7 @@ public:
|
||||
|
||||
@li An error occurs.
|
||||
|
||||
The algorithm, known as a <em>composed operation</em> is implemented
|
||||
The algorithm, known as a <em>composed operation</em>, is implemented
|
||||
in terms of calls to the next layer's `read_some` and `write_some`
|
||||
functions.
|
||||
|
||||
@@ -884,7 +884,7 @@ public:
|
||||
|
||||
@li An error occurs.
|
||||
|
||||
The algorithm, known as a <em>composed operation</em> is implemented
|
||||
The algorithm, known as a <em>composed operation</em>, is implemented
|
||||
in terms of calls to the next layer's `read_some` and `write_some`
|
||||
functions.
|
||||
|
||||
@@ -941,7 +941,7 @@ public:
|
||||
|
||||
@li An error occurs.
|
||||
|
||||
The algorithm, known as a <em>composed operation</em> is implemented
|
||||
The algorithm, known as a <em>composed operation</em>, is implemented
|
||||
in terms of calls to the next layer's `read_some` and `write_some`
|
||||
functions.
|
||||
|
||||
@@ -1008,7 +1008,7 @@ public:
|
||||
|
||||
@li An error occurs.
|
||||
|
||||
The algorithm, known as a <em>composed operation</em> is implemented
|
||||
The algorithm, known as a <em>composed operation</em>, is implemented
|
||||
in terms of calls to the next layer's `read_some` and `write_some`
|
||||
functions.
|
||||
|
||||
@@ -1428,7 +1428,7 @@ public:
|
||||
|
||||
@li An error occurs.
|
||||
|
||||
The algorithm, known as a <em>composed operation</em> is implemented
|
||||
The algorithm, known as a <em>composed operation</em>, is implemented
|
||||
in terms of calls to the next layer's `read_some` and `write_some`
|
||||
functions.
|
||||
|
||||
@@ -1467,7 +1467,7 @@ public:
|
||||
|
||||
@li An error occurs.
|
||||
|
||||
The algorithm, known as a <em>composed operation</em> is implemented
|
||||
The algorithm, known as a <em>composed operation</em>, is implemented
|
||||
in terms of calls to the next layer's `read_some` and `write_some`
|
||||
functions.
|
||||
|
||||
@@ -1518,7 +1518,7 @@ public:
|
||||
|
||||
@li An error occurs.
|
||||
|
||||
The algorithm, known as a <em>composed operation</em> is implemented
|
||||
The algorithm, known as a <em>composed operation</em>, is implemented
|
||||
in terms of calls to the next layer's `read_some` and `write_some`
|
||||
functions.
|
||||
|
||||
@@ -1557,7 +1557,7 @@ public:
|
||||
|
||||
@li An error occurs.
|
||||
|
||||
The algorithm, known as a <em>composed operation</em> is implemented
|
||||
The algorithm, known as a <em>composed operation</em>, is implemented
|
||||
in terms of calls to the next layer's `read_some` and `write_some`
|
||||
functions.
|
||||
|
||||
@@ -1610,7 +1610,7 @@ public:
|
||||
|
||||
@li An error occurs.
|
||||
|
||||
The algorithm, known as a <em>composed operation</em> is implemented
|
||||
The algorithm, known as a <em>composed operation</em>, is implemented
|
||||
in terms of calls to the next layer's `read_some` and `write_some`
|
||||
functions.
|
||||
|
||||
@@ -1659,7 +1659,7 @@ public:
|
||||
|
||||
@li An error occurs.
|
||||
|
||||
The algorithm, known as a <em>composed operation</em> is implemented
|
||||
The algorithm, known as a <em>composed operation</em>, is implemented
|
||||
in terms of calls to the next layer's `read_some` and `write_some`
|
||||
functions.
|
||||
|
||||
@@ -1722,7 +1722,7 @@ public:
|
||||
|
||||
@li An error occurs.
|
||||
|
||||
The algorithm, known as a <em>composed operation</em> is implemented
|
||||
The algorithm, known as a <em>composed operation</em>, is implemented
|
||||
in terms of calls to the next layer's `read_some` and `write_some`
|
||||
functions.
|
||||
|
||||
@@ -1773,7 +1773,7 @@ public:
|
||||
|
||||
@li An error occurs.
|
||||
|
||||
The algorithm, known as a <em>composed operation</em> is implemented
|
||||
The algorithm, known as a <em>composed operation</em>, is implemented
|
||||
in terms of calls to the next layer's `read_some` and `write_some`
|
||||
functions.
|
||||
|
||||
@@ -1836,7 +1836,7 @@ public:
|
||||
|
||||
@li An error occurs.
|
||||
|
||||
The algorithm, known as a <em>composed operation</em> is implemented
|
||||
The algorithm, known as a <em>composed operation</em>, is implemented
|
||||
in terms of calls to the next layer's `read_some` and `write_some`
|
||||
functions.
|
||||
|
||||
@@ -1874,7 +1874,7 @@ public:
|
||||
|
||||
@li An error occurs.
|
||||
|
||||
The algorithm, known as a <em>composed operation</em> is implemented
|
||||
The algorithm, known as a <em>composed operation</em>, is implemented
|
||||
in terms of calls to the next layer's `read_some` and `write_some`
|
||||
functions.
|
||||
|
||||
@@ -1925,7 +1925,7 @@ public:
|
||||
|
||||
@li An error occurs.
|
||||
|
||||
The algorithm, known as a <em>composed operation</em> is implemented
|
||||
The algorithm, known as a <em>composed operation</em>, is implemented
|
||||
in terms of calls to the next layer's `read_some` and `write_some`
|
||||
functions.
|
||||
|
||||
@@ -1964,7 +1964,7 @@ public:
|
||||
|
||||
@li An error occurs.
|
||||
|
||||
The algorithm, known as a <em>composed operation</em> is implemented
|
||||
The algorithm, known as a <em>composed operation</em>, is implemented
|
||||
in terms of calls to the next layer's `read_some` and `write_some`
|
||||
functions.
|
||||
|
||||
@@ -2424,7 +2424,7 @@ public:
|
||||
|
||||
@li An error occurs.
|
||||
|
||||
The algorithm, known as a <em>composed operation</em> is implemented
|
||||
The algorithm, known as a <em>composed operation</em>, is implemented
|
||||
in terms of calls to the next layer's `write_some` function.
|
||||
|
||||
After beginning the closing handshake, the program should not write
|
||||
@@ -2459,7 +2459,7 @@ public:
|
||||
|
||||
@li An error occurs.
|
||||
|
||||
The algorithm, known as a <em>composed operation</em> is implemented
|
||||
The algorithm, known as a <em>composed operation</em>, is implemented
|
||||
in terms of calls to the next layer's `write_some` function.
|
||||
|
||||
After beginning the closing handshake, the program should not write
|
||||
@@ -2551,7 +2551,7 @@ public:
|
||||
|
||||
@li An error occurs.
|
||||
|
||||
The algorithm, known as a <em>composed operation</em> is implemented
|
||||
The algorithm, known as a <em>composed operation</em>, is implemented
|
||||
in terms of calls to the next layer's `write_some` function.
|
||||
|
||||
@param payload The payload of the ping message, which may be empty.
|
||||
@@ -2574,7 +2574,7 @@ public:
|
||||
|
||||
@li An error occurs.
|
||||
|
||||
The algorithm, known as a <em>composed operation</em> is implemented
|
||||
The algorithm, known as a <em>composed operation</em>, is implemented
|
||||
in terms of calls to the next layer's `write_some` function.
|
||||
|
||||
@param payload The payload of the ping message, which may be empty.
|
||||
@@ -2640,7 +2640,7 @@ public:
|
||||
|
||||
@li An error occurs.
|
||||
|
||||
The algorithm, known as a <em>composed operation</em> is implemented
|
||||
The algorithm, known as a <em>composed operation</em>, is implemented
|
||||
in terms of calls to the next layer's `write_some` function.
|
||||
|
||||
WebSocket allows pong frames to be sent at any time, without first
|
||||
@@ -2667,7 +2667,7 @@ public:
|
||||
|
||||
@li An error occurs.
|
||||
|
||||
The algorithm, known as a <em>composed operation</em> is implemented
|
||||
The algorithm, known as a <em>composed operation</em>, is implemented
|
||||
in terms of calls to the next layer's `write_some` function.
|
||||
|
||||
WebSocket allows pong frames to be sent at any time, without first
|
||||
@@ -2747,7 +2747,7 @@ public:
|
||||
|
||||
@li An error occurs.
|
||||
|
||||
The algorithm, known as a <em>composed operation</em> is implemented
|
||||
The algorithm, known as a <em>composed operation</em>, is implemented
|
||||
in terms of calls to the next layer's `read_some` and `write_some`
|
||||
functions.
|
||||
|
||||
@@ -2790,7 +2790,7 @@ public:
|
||||
|
||||
@li An error occurs.
|
||||
|
||||
The algorithm, known as a <em>composed operation</em> is implemented
|
||||
The algorithm, known as a <em>composed operation</em>, is implemented
|
||||
in terms of calls to the next layer's `read_some` and `write_some`
|
||||
functions.
|
||||
|
||||
@@ -2899,7 +2899,7 @@ public:
|
||||
|
||||
@li An error occurs.
|
||||
|
||||
The algorithm, known as a <em>composed operation</em> is implemented
|
||||
The algorithm, known as a <em>composed operation</em>, is implemented
|
||||
in terms of calls to the next layer's `read_some` and `write_some`
|
||||
functions.
|
||||
|
||||
@@ -2950,7 +2950,7 @@ public:
|
||||
|
||||
@li An error occurs.
|
||||
|
||||
The algorithm, known as a <em>composed operation</em> is implemented
|
||||
The algorithm, known as a <em>composed operation</em>, is implemented
|
||||
in terms of calls to the next layer's `read_some` and `write_some`
|
||||
functions.
|
||||
|
||||
@@ -3032,6 +3032,10 @@ public:
|
||||
|
||||
@param buffer A dynamic buffer to append message data to.
|
||||
|
||||
@param limit An upper limit on the number of bytes this function
|
||||
will append into the buffer. If this value is zero, then a reasonable
|
||||
size will be chosen automatically.
|
||||
|
||||
@param handler Invoked when the operation completes. Ownership
|
||||
of the handler will be transferred by move-construction as needed.
|
||||
The equivalent function signature of the handler must be:
|
||||
@@ -3069,7 +3073,7 @@ public:
|
||||
|
||||
@li An error occurs.
|
||||
|
||||
The algorithm, known as a <em>composed operation</em> is implemented
|
||||
The algorithm, known as a <em>composed operation</em>, is implemented
|
||||
in terms of calls to the next layer's `read_some` and `write_some`
|
||||
functions.
|
||||
|
||||
@@ -3096,10 +3100,6 @@ public:
|
||||
The previous contents of the buffers will be overwritten, starting
|
||||
from the beginning.
|
||||
|
||||
@param limit An upper limit on the number of bytes this function
|
||||
will append into the buffer. If this value is zero, then a reasonable
|
||||
size will be chosen automatically.
|
||||
|
||||
@throws system_error Thrown on failure.
|
||||
*/
|
||||
template<class MutableBufferSequence>
|
||||
@@ -3120,7 +3120,7 @@ public:
|
||||
|
||||
@li An error occurs.
|
||||
|
||||
The algorithm, known as a <em>composed operation</em> is implemented
|
||||
The algorithm, known as a <em>composed operation</em>, is implemented
|
||||
in terms of calls to the next layer's `read_some` and `write_some`
|
||||
functions.
|
||||
|
||||
@@ -3147,10 +3147,6 @@ public:
|
||||
The previous contents of the buffers will be overwritten, starting
|
||||
from the beginning.
|
||||
|
||||
@param limit An upper limit on the number of bytes this function
|
||||
will append into the buffer. If this value is zero, then a reasonable
|
||||
size will be chosen automatically.
|
||||
|
||||
@param ec Set to indicate what error occurred, if any.
|
||||
*/
|
||||
template<class MutableBufferSequence>
|
||||
@@ -3246,7 +3242,7 @@ public:
|
||||
|
||||
@li An error occurs.
|
||||
|
||||
The algorithm, known as a <em>composed operation</em> is implemented
|
||||
The algorithm, known as a <em>composed operation</em>, is implemented
|
||||
in terms of calls to the next layer's `write_some` function.
|
||||
|
||||
The current setting of the @ref binary option controls
|
||||
@@ -3275,7 +3271,7 @@ public:
|
||||
|
||||
@li An error occurs.
|
||||
|
||||
The algorithm, known as a <em>composed operation</em> is implemented
|
||||
The algorithm, known as a <em>composed operation</em>, is implemented
|
||||
in terms of calls to the next layer's `write_some` function.
|
||||
|
||||
The current setting of the @ref binary option controls
|
||||
@@ -3359,7 +3355,7 @@ public:
|
||||
|
||||
@li An error occurs.
|
||||
|
||||
The algorithm, known as a <em>composed operation</em> is implemented
|
||||
The algorithm, known as a <em>composed operation</em>, is implemented
|
||||
in terms of calls to the next layer's `write_some` function.
|
||||
|
||||
If this is the beginning of a new message, the message opcode
|
||||
@@ -3389,7 +3385,7 @@ public:
|
||||
|
||||
@li An error occurs.
|
||||
|
||||
The algorithm, known as a <em>composed operation</em> is implemented
|
||||
The algorithm, known as a <em>composed operation</em>, is implemented
|
||||
in terms of calls to the next layer's `write_some` function.
|
||||
|
||||
If this is the beginning of a new message, the message opcode
|
||||
@@ -3401,6 +3397,8 @@ public:
|
||||
|
||||
@param buffers The buffers containing the message part to send.
|
||||
|
||||
@param ec Set to indicate what error occurred, if any.
|
||||
|
||||
@return The number of bytes sent from the buffers.
|
||||
|
||||
@return The number of bytes consumed in the input buffers.
|
||||
|
@@ -30,7 +30,7 @@ add_executable (tests-beast-core
|
||||
_detail_variant.cpp
|
||||
_detail_varint.cpp
|
||||
async_op_base.cpp
|
||||
basic_timeout_stream.cpp
|
||||
basic_stream.cpp
|
||||
bind_handler.cpp
|
||||
buffer_size.cpp
|
||||
buffer_traits.cpp
|
||||
@@ -61,11 +61,10 @@ add_executable (tests-beast-core
|
||||
span.cpp
|
||||
static_buffer.cpp
|
||||
static_string.cpp
|
||||
stranded_socket.cpp
|
||||
stream_traits.cpp
|
||||
string.cpp
|
||||
string_param.cpp
|
||||
timeout_stream.cpp
|
||||
tcp_stream.cpp
|
||||
)
|
||||
|
||||
set_property(TARGET tests-beast-core PROPERTY FOLDER "tests")
|
||||
|
@@ -18,7 +18,7 @@ local SOURCES =
|
||||
_detail_variant.cpp
|
||||
_detail_varint.cpp
|
||||
async_op_base.cpp
|
||||
basic_timeout_stream.cpp
|
||||
basic_stream.cpp
|
||||
bind_handler.cpp
|
||||
buffer_size.cpp
|
||||
buffer_traits.cpp
|
||||
@@ -49,11 +49,10 @@ local SOURCES =
|
||||
span.cpp
|
||||
static_buffer.cpp
|
||||
static_string.cpp
|
||||
stranded_socket.cpp
|
||||
stream_traits.cpp
|
||||
string.cpp
|
||||
string_param.cpp
|
||||
timeout_stream.cpp
|
||||
tcp_stream.cpp
|
||||
;
|
||||
|
||||
local RUN_TESTS ;
|
||||
|
1245
test/beast/core/basic_stream.cpp
Normal file
1245
test/beast/core/basic_stream.cpp
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,519 +0,0 @@
|
||||
//
|
||||
// Copyright (c) 2018 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
|
||||
//
|
||||
|
||||
// Test that header file is self-contained.
|
||||
#include <boost/beast/core/stranded_socket.hpp>
|
||||
|
||||
#include "stream_tests.hpp"
|
||||
|
||||
#include <boost/beast/_experimental/unit_test/suite.hpp>
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace boost {
|
||||
namespace beast {
|
||||
|
||||
namespace {
|
||||
|
||||
template<class Executor = net::io_context::executor_type>
|
||||
class test_executor
|
||||
{
|
||||
public:
|
||||
// VFALCO These need to be atomic or something
|
||||
struct info
|
||||
{
|
||||
int dispatch = 0;
|
||||
int post = 0;
|
||||
int defer = 0;
|
||||
int work = 0;
|
||||
int total = 0;
|
||||
};
|
||||
|
||||
private:
|
||||
struct state
|
||||
{
|
||||
Executor ex;
|
||||
info info_;
|
||||
|
||||
state(Executor const& ex_)
|
||||
: ex(ex_)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
std::shared_ptr<state> sp_;
|
||||
|
||||
public:
|
||||
test_executor(test_executor const&) = default;
|
||||
test_executor& operator=(test_executor const&) = default;
|
||||
|
||||
explicit
|
||||
test_executor(Executor const& ex)
|
||||
: sp_(std::make_shared<state>(ex))
|
||||
{
|
||||
}
|
||||
|
||||
decltype(sp_->ex.context())
|
||||
context() const noexcept
|
||||
{
|
||||
return sp_->ex.context();
|
||||
}
|
||||
|
||||
info&
|
||||
operator*() noexcept
|
||||
{
|
||||
return sp_->info_;
|
||||
}
|
||||
|
||||
info*
|
||||
operator->() noexcept
|
||||
{
|
||||
return &sp_->info_;
|
||||
}
|
||||
|
||||
void
|
||||
on_work_started() const noexcept
|
||||
{
|
||||
++sp_->info_.work;
|
||||
}
|
||||
|
||||
void
|
||||
on_work_finished() const noexcept
|
||||
{
|
||||
}
|
||||
|
||||
template<class F, class A>
|
||||
void
|
||||
dispatch(F&& f, A const& a)
|
||||
{
|
||||
++sp_->info_.dispatch;
|
||||
++sp_->info_.total;
|
||||
sp_->ex.dispatch(
|
||||
std::forward<F>(f), a);
|
||||
}
|
||||
|
||||
template<class F, class A>
|
||||
void
|
||||
post(F&& f, A const& a)
|
||||
{
|
||||
++sp_->info_.post;
|
||||
++sp_->info_.total;
|
||||
sp_->ex.post(
|
||||
std::forward<F>(f), a);
|
||||
}
|
||||
|
||||
template<class F, class A>
|
||||
void
|
||||
defer(F&& f, A const& a)
|
||||
{
|
||||
++sp_->info_.defer;
|
||||
++sp_->info_.total;
|
||||
sp_->ex.defer(
|
||||
std::forward<F>(f), a);
|
||||
}
|
||||
};
|
||||
|
||||
struct test_handler
|
||||
{
|
||||
int& flags;
|
||||
|
||||
void
|
||||
operator()()
|
||||
{
|
||||
flags |= 1;
|
||||
}
|
||||
|
||||
template<class F>
|
||||
friend
|
||||
void
|
||||
asio_handler_invoke(F&& f, test_handler* p)
|
||||
{
|
||||
p->flags |= 2;
|
||||
std::move(f)();
|
||||
}
|
||||
};
|
||||
|
||||
struct test_acceptor
|
||||
{
|
||||
net::io_context ioc;
|
||||
net::ip::tcp::acceptor a;
|
||||
net::ip::tcp::endpoint ep;
|
||||
|
||||
test_acceptor()
|
||||
: a(ioc)
|
||||
, ep(net::ip::make_address_v4("127.0.0.1"), 0)
|
||||
{
|
||||
a.open(ep.protocol());
|
||||
a.set_option(
|
||||
net::socket_base::reuse_address(true));
|
||||
a.bind(ep);
|
||||
a.listen(1);
|
||||
ep = a.local_endpoint();
|
||||
a.async_accept(
|
||||
[](error_code, net::ip::tcp::socket)
|
||||
{
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
} // (anon)
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class stranded_socket_test
|
||||
: public beast::unit_test::suite
|
||||
{
|
||||
public:
|
||||
using tcp = net::ip::tcp;
|
||||
using strand = net::io_context::strand;
|
||||
using executor = net::io_context::executor_type;
|
||||
|
||||
void
|
||||
testStream()
|
||||
{
|
||||
net::io_context ioc;
|
||||
|
||||
// default Executor
|
||||
|
||||
{
|
||||
stranded_socket<tcp> s1{strand(ioc)};
|
||||
stranded_socket<tcp> s2{strand{ioc}};
|
||||
//stranded_socket<tcp> s3{strand{ioc}}; // ambiguous parse
|
||||
}
|
||||
|
||||
// explicit Executor
|
||||
|
||||
{
|
||||
auto ex = ioc.get_executor();
|
||||
stranded_socket<tcp, executor> s1(ioc);
|
||||
stranded_socket<tcp, executor> s2(ex);
|
||||
stranded_socket<tcp, executor> s3(ioc, tcp::v4());
|
||||
stranded_socket<tcp, executor> s4(std::move(s1));
|
||||
s2.socket() = tcp::socket(ioc);
|
||||
BEAST_EXPECT(s1.get_executor() == ex);
|
||||
BEAST_EXPECT(s2.get_executor() == ex);
|
||||
BEAST_EXPECT(s3.get_executor() == ex);
|
||||
BEAST_EXPECT(s4.get_executor() == ex);
|
||||
|
||||
BEAST_EXPECT((! static_cast<
|
||||
stranded_socket<tcp, executor> const&>(
|
||||
s2).socket().is_open()));
|
||||
}
|
||||
|
||||
{
|
||||
auto ex = strand{ioc};
|
||||
stranded_socket<tcp, strand> s1(ex);
|
||||
stranded_socket<tcp, strand> s2(ex, tcp::v4());
|
||||
stranded_socket<tcp, strand> s3(std::move(s1));
|
||||
s2.socket() = tcp::socket(ioc);
|
||||
BEAST_EXPECT(s1.get_executor() == ex);
|
||||
BEAST_EXPECT(s2.get_executor() == ex);
|
||||
BEAST_EXPECT(s3.get_executor() == ex);
|
||||
|
||||
BEAST_EXPECT((! static_cast<
|
||||
stranded_socket<tcp, strand> const&>(
|
||||
s2).socket().is_open()));
|
||||
}
|
||||
|
||||
{
|
||||
test_sync_stream<stranded_socket<tcp, executor>>();
|
||||
test_async_stream<stranded_socket<tcp, executor>>();
|
||||
test_sync_stream<stranded_socket<tcp, strand>>();
|
||||
test_async_stream<stranded_socket<tcp, strand>>();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testMembers()
|
||||
{
|
||||
net::io_context ioc;
|
||||
|
||||
// connect (member)
|
||||
|
||||
auto const cond =
|
||||
[](error_code, tcp::endpoint)
|
||||
{
|
||||
return true;
|
||||
};
|
||||
|
||||
{
|
||||
stranded_socket<tcp, executor> s(ioc);
|
||||
error_code ec;
|
||||
test_acceptor a;
|
||||
try
|
||||
{
|
||||
s.connect(a.ep);
|
||||
BEAST_PASS();
|
||||
}
|
||||
catch(std::exception const&)
|
||||
{
|
||||
BEAST_FAIL();
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
stranded_socket<tcp, executor> s(ioc);
|
||||
error_code ec;
|
||||
test_acceptor a;
|
||||
s.connect(a.ep, ec);
|
||||
BEAST_EXPECT(! ec);
|
||||
}
|
||||
|
||||
// connect
|
||||
|
||||
{
|
||||
test_acceptor a;
|
||||
std::array<tcp::endpoint, 1> epa;
|
||||
epa[0] = a.ep;
|
||||
stranded_socket<tcp, executor> s(ioc);
|
||||
error_code ec;
|
||||
connect(s, epa);
|
||||
connect(s, epa, ec);
|
||||
}
|
||||
|
||||
{
|
||||
test_acceptor a;
|
||||
std::array<tcp::endpoint, 1> epa;
|
||||
epa[0] = a.ep;
|
||||
stranded_socket<tcp, executor> s(ioc);
|
||||
error_code ec;
|
||||
connect(s, epa, cond);
|
||||
connect(s, epa, cond, ec);
|
||||
}
|
||||
|
||||
{
|
||||
test_acceptor a;
|
||||
std::array<tcp::endpoint, 1> epa;
|
||||
epa[0] = a.ep;
|
||||
stranded_socket<tcp, executor> s(ioc);
|
||||
error_code ec;
|
||||
connect(s, epa.begin(), epa.end());
|
||||
connect(s, epa.begin(), epa.end(), ec);
|
||||
}
|
||||
|
||||
{
|
||||
test_acceptor a;
|
||||
std::array<tcp::endpoint, 1> epa;
|
||||
epa[0] = a.ep;
|
||||
stranded_socket<tcp, executor> s(ioc);
|
||||
error_code ec;
|
||||
connect(s, epa.begin(), epa.end(), cond);
|
||||
connect(s, epa.begin(), epa.end(), cond, ec);
|
||||
}
|
||||
|
||||
// async_connect
|
||||
|
||||
{
|
||||
stranded_socket<tcp, executor> s(ioc);
|
||||
test_acceptor a;
|
||||
error_code ec;
|
||||
s.async_connect(a. ep,
|
||||
[](error_code ec)
|
||||
{
|
||||
BEAST_EXPECT(! ec);
|
||||
});
|
||||
ioc.run();
|
||||
ioc.restart();
|
||||
}
|
||||
|
||||
{
|
||||
std::array<tcp::endpoint, 1> epa;
|
||||
epa[0] = tcp::endpoint(
|
||||
net::ip::make_address_v4("127.0.0.1"), 0);
|
||||
stranded_socket<tcp, executor> s(ioc);
|
||||
async_connect(s, epa,
|
||||
[](error_code, tcp::endpoint)
|
||||
{
|
||||
});
|
||||
}
|
||||
|
||||
{
|
||||
std::array<tcp::endpoint, 1> epa;
|
||||
epa[0] = tcp::endpoint(
|
||||
net::ip::make_address_v4("127.0.0.1"), 0);
|
||||
stranded_socket<tcp, executor> s(ioc);
|
||||
async_connect(s, epa, cond,
|
||||
[](error_code, tcp::endpoint)
|
||||
{
|
||||
});
|
||||
}
|
||||
|
||||
{
|
||||
std::array<tcp::endpoint, 1> epa;
|
||||
epa[0] = tcp::endpoint(
|
||||
net::ip::make_address_v4("127.0.0.1"), 0);
|
||||
using iter_type = decltype(epa)::const_iterator;
|
||||
stranded_socket<tcp, executor> s(ioc);
|
||||
async_connect(s, epa.begin(), epa.end(),
|
||||
[](error_code, iter_type)
|
||||
{
|
||||
});
|
||||
}
|
||||
|
||||
{
|
||||
std::array<tcp::endpoint, 1> epa;
|
||||
epa[0] = tcp::endpoint(
|
||||
net::ip::make_address_v4("127.0.0.1"), 0);
|
||||
using iter_type = decltype(epa)::const_iterator;
|
||||
stranded_socket<tcp, executor> s(ioc);
|
||||
async_connect(s, epa.begin(), epa.end(), cond,
|
||||
[](error_code, iter_type)
|
||||
{
|
||||
});
|
||||
}
|
||||
|
||||
// read/write
|
||||
|
||||
{
|
||||
error_code ec;
|
||||
stranded_socket<tcp, executor> s(ioc, tcp::v4());
|
||||
|
||||
BEAST_EXPECT(s.read_some(net::mutable_buffer{}) == 0);
|
||||
BEAST_EXPECT(s.read_some(net::mutable_buffer{}, ec) == 0);
|
||||
BEAST_EXPECTS(! ec, ec.message());
|
||||
|
||||
BEAST_EXPECT(s.write_some(net::const_buffer{}) == 0);
|
||||
BEAST_EXPECT(s.write_some(net::const_buffer{}, ec) == 0);
|
||||
BEAST_EXPECTS(! ec, ec.message());
|
||||
|
||||
bool invoked;
|
||||
|
||||
invoked = false;
|
||||
s.async_read_some(net::mutable_buffer{},
|
||||
[&](error_code ec, std::size_t)
|
||||
{
|
||||
invoked = true;
|
||||
BEAST_EXPECTS(! ec, ec.message());
|
||||
});
|
||||
ioc.run();
|
||||
ioc.restart();
|
||||
BEAST_EXPECT(invoked);
|
||||
|
||||
invoked = false;
|
||||
s.async_write_some(net::const_buffer{},
|
||||
[&](error_code ec, std::size_t)
|
||||
{
|
||||
invoked = true;
|
||||
BEAST_EXPECTS(! ec, ec.message());
|
||||
});
|
||||
ioc.run();
|
||||
ioc.restart();
|
||||
BEAST_EXPECT(invoked);
|
||||
}
|
||||
|
||||
// stranded
|
||||
|
||||
{
|
||||
error_code ec;
|
||||
stranded_socket<tcp, strand> s(strand(ioc), tcp::v4());
|
||||
|
||||
bool invoked;
|
||||
|
||||
invoked = false;
|
||||
s.async_read_some(net::mutable_buffer{},
|
||||
[&](error_code ec, std::size_t)
|
||||
{
|
||||
invoked = true;
|
||||
BEAST_EXPECTS(! ec, ec.message());
|
||||
});
|
||||
ioc.run();
|
||||
ioc.restart();
|
||||
BEAST_EXPECT(invoked);
|
||||
|
||||
invoked = false;
|
||||
s.async_write_some(net::const_buffer{},
|
||||
[&](error_code ec, std::size_t)
|
||||
{
|
||||
invoked = true;
|
||||
BEAST_EXPECTS(! ec, ec.message());
|
||||
});
|
||||
ioc.run();
|
||||
ioc.restart();
|
||||
BEAST_EXPECT(invoked);
|
||||
}
|
||||
|
||||
// test_executor
|
||||
|
||||
{
|
||||
error_code ec;
|
||||
stranded_socket<tcp, test_executor<>> s(
|
||||
test_executor<>(ioc.get_executor()), tcp::v4());
|
||||
|
||||
bool invoked;
|
||||
|
||||
invoked = false;
|
||||
s.async_read_some(net::mutable_buffer{},
|
||||
[&](error_code ec, std::size_t)
|
||||
{
|
||||
invoked = true;
|
||||
BEAST_EXPECTS(! ec, ec.message());
|
||||
});
|
||||
ioc.run();
|
||||
ioc.restart();
|
||||
BEAST_EXPECT(invoked);
|
||||
BEAST_EXPECT(s.get_executor()->total > 0);
|
||||
s.get_executor()->total = 0;
|
||||
|
||||
invoked = false;
|
||||
s.async_write_some(net::const_buffer{},
|
||||
[&](error_code ec, std::size_t)
|
||||
{
|
||||
invoked = true;
|
||||
BEAST_EXPECTS(! ec, ec.message());
|
||||
});
|
||||
ioc.run();
|
||||
ioc.restart();
|
||||
BEAST_EXPECT(invoked);
|
||||
BEAST_EXPECT(s.get_executor()->total > 0);
|
||||
s.get_executor()->total = 0;
|
||||
}
|
||||
|
||||
// bind_default_executor::asio_handler_invoke
|
||||
|
||||
#if 0
|
||||
// VFALCO This test fails, because it is unclear how
|
||||
// asio_handler_invoke interacts with the wrapper.
|
||||
// Need to ask Chris Kohlhoff about this one.
|
||||
{
|
||||
int flags = 0;
|
||||
net::post(
|
||||
ioc,
|
||||
detail::bind_default_executor(
|
||||
strand(ioc),
|
||||
test_handler{flags}));
|
||||
ioc.run();
|
||||
ioc.restart();
|
||||
BEAST_EXPECT(flags == 3);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
void
|
||||
testJavadocs()
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
void
|
||||
run()
|
||||
{
|
||||
testStream();
|
||||
testJavadocs();
|
||||
testMembers();
|
||||
}
|
||||
};
|
||||
|
||||
BEAST_DEFINE_TESTSUITE(beast,core,stranded_socket);
|
||||
|
||||
} // beast
|
||||
} // boost
|
@@ -8,4 +8,4 @@
|
||||
//
|
||||
|
||||
// Test that header file is self-contained.
|
||||
#include <boost/beast/core/timeout_stream.hpp>
|
||||
#include <boost/beast/core/tcp_stream.hpp>
|
Reference in New Issue
Block a user