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:
|
Version 213:
|
||||||
|
|
||||||
* Fix posix_file::close handling of EINTR
|
* 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
|
[table Layered Stream Algorithms and Types
|
||||||
[[Name][Description]]
|
[[Name][Description]]
|
||||||
[[
|
[[
|
||||||
[link beast.ref.boost__beast__timeout_stream `timeout_stream`]
|
[link beast.ref.boost__beast__basic_stream `basic_stream`]
|
||||||
[link beast.ref.boost__beast__basic_timeout_stream `basic_timeout_stream`]
|
[link beast.ref.boost__beast__tcp_stream `tcp_stream`]
|
||||||
][
|
][
|
||||||
A timeout stream meets the requirements for synchronous and asynchronous
|
This stream can be used for synchronous and asynchronous reading
|
||||||
read and write streams, and additionally provides configurable timeouts
|
and writing. It allows timeouts to be set on logical operations,
|
||||||
for logical operations that include reading, writing, and/or connecting.
|
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`]
|
[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
|
allows for move-construction and move-assignment, and also implements
|
||||||
a work-around for a performance limitation in the original SSL stream.
|
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]
|
[heading Example]
|
||||||
|
@@ -24,7 +24,7 @@
|
|||||||
<bridgehead renderas="sect3">Classes <emphasis role="normal">(1 of 2)</emphasis></bridgehead>
|
<bridgehead renderas="sect3">Classes <emphasis role="normal">(1 of 2)</emphasis></bridgehead>
|
||||||
<simplelist type="vert" columns="1">
|
<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__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">file</link></member>
|
||||||
<member><link linkend="beast.ref.boost__beast__file_mode">file_mode</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>
|
<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__span">span</link></member>
|
||||||
<member><link linkend="beast.ref.boost__beast__static_string">static_string</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__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_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__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>
|
</simplelist>
|
||||||
<bridgehead renderas="sect3">Constants</bridgehead>
|
<bridgehead renderas="sect3">Constants</bridgehead>
|
||||||
<simplelist type="vert" columns="1">
|
<simplelist type="vert" columns="1">
|
||||||
|
@@ -14,14 +14,19 @@
|
|||||||
[heading Boost 1.70]
|
[heading Boost 1.70]
|
||||||
[/ includes up to version 209]
|
[/ 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:
|
Exposition:
|
||||||
Enlarged scope
|
Enlarged scope
|
||||||
New quality of life features:
|
- `net` is a namespace alias for `boost::asio`
|
||||||
timed stream
|
- New quality of life features:
|
||||||
|
tcp_socket
|
||||||
async_op_base, stable_async_op_base
|
async_op_base, stable_async_op_base
|
||||||
New Networking refresher
|
- New Networking refresher
|
||||||
New websocket-chat-multi example
|
- New websocket-chat-multi example
|
||||||
* `net` is a namespace alias for `boost::asio`
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[tip
|
[tip
|
||||||
|
@@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
#include <boost/beast/core/detail/config.hpp>
|
#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/bind_handler.hpp>
|
||||||
#include <boost/beast/core/buffer_size.hpp>
|
#include <boost/beast/core/buffer_size.hpp>
|
||||||
#include <boost/beast/core/buffer_traits.hpp>
|
#include <boost/beast/core/buffer_traits.hpp>
|
||||||
@@ -41,10 +41,9 @@
|
|||||||
#include <boost/beast/core/span.hpp>
|
#include <boost/beast/core/span.hpp>
|
||||||
#include <boost/beast/core/static_buffer.hpp>
|
#include <boost/beast/core/static_buffer.hpp>
|
||||||
#include <boost/beast/core/static_string.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/stream_traits.hpp>
|
||||||
#include <boost/beast/core/string.hpp>
|
#include <boost/beast/core/string.hpp>
|
||||||
#include <boost/beast/core/string_param.hpp>
|
#include <boost/beast/core/string_param.hpp>
|
||||||
#include <boost/beast/core/timeout_stream.hpp>
|
#include <boost/beast/core/tcp_stream.hpp>
|
||||||
|
|
||||||
#endif
|
#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
|
} // detail
|
||||||
|
|
||||||
/** Return the total number of bytes in a buffer or buffer sequence
|
/** 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
|
// Official repository: https://github.com/boostorg/beast
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifndef BOOST_BEAST_CORE_DETAIL_TIMEOUT_STREAM_BASE_HPP
|
#ifndef BOOST_BEAST_CORE_DETAIL_STREAM_BASE_HPP
|
||||||
#define BOOST_BEAST_CORE_DETAIL_TIMEOUT_STREAM_BASE_HPP
|
#define BOOST_BEAST_CORE_DETAIL_STREAM_BASE_HPP
|
||||||
|
|
||||||
|
#include <boost/asio/steady_timer.hpp>
|
||||||
#include <boost/assert.hpp>
|
#include <boost/assert.hpp>
|
||||||
#include <boost/core/exchange.hpp>
|
#include <boost/core/exchange.hpp>
|
||||||
|
#include <chrono>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
namespace boost {
|
namespace boost {
|
||||||
namespace beast {
|
namespace beast {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
template<class, class, class>
|
template<class, class, class>
|
||||||
class timeout_stream_connect_op;
|
class basic_stream_connect_op;
|
||||||
|
|
||||||
struct any_endpoint
|
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
|
class pending_guard
|
||||||
{
|
{
|
||||||
bool& b_;
|
bool& b_;
|
||||||
@@ -70,6 +91,14 @@ protected:
|
|||||||
clear_ = false;
|
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
|
} // detail
|
@@ -7,11 +7,13 @@
|
|||||||
// Official repository: https://github.com/boostorg/beast
|
// Official repository: https://github.com/boostorg/beast
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifndef BOOST_BEAST_CORE_IMPL_BASIC_TIMEOUT_STREAM_HPP
|
#ifndef BOOST_BEAST_CORE_IMPL_BASIC_STREAM_HPP
|
||||||
#define BOOST_BEAST_CORE_IMPL_BASIC_TIMEOUT_STREAM_HPP
|
#define BOOST_BEAST_CORE_IMPL_BASIC_STREAM_HPP
|
||||||
|
|
||||||
#include <boost/beast/core/async_op_base.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/bind_executor.hpp>
|
||||||
#include <boost/asio/coroutine.hpp>
|
#include <boost/asio/coroutine.hpp>
|
||||||
#include <boost/assert.hpp>
|
#include <boost/assert.hpp>
|
||||||
@@ -23,8 +25,96 @@
|
|||||||
namespace boost {
|
namespace boost {
|
||||||
namespace beast {
|
namespace beast {
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
template<class Protocol, class Executor>
|
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
|
Protocol, Executor>::timeout_handler
|
||||||
{
|
{
|
||||||
op_state& state;
|
op_state& state;
|
||||||
@@ -50,14 +140,8 @@ struct basic_timeout_stream<
|
|||||||
return;
|
return;
|
||||||
BOOST_ASSERT(tick == state.tick);
|
BOOST_ASSERT(tick == state.tick);
|
||||||
|
|
||||||
// late completion
|
|
||||||
if(state.timeout)
|
|
||||||
{
|
|
||||||
state.timeout = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// timeout
|
// timeout
|
||||||
|
BOOST_ASSERT(! state.timeout);
|
||||||
sp->close();
|
sp->close();
|
||||||
state.timeout = true;
|
state.timeout = true;
|
||||||
}
|
}
|
||||||
@@ -75,7 +159,7 @@ struct basic_timeout_stream<
|
|||||||
|
|
||||||
template<class Protocol, class Executor>
|
template<class Protocol, class Executor>
|
||||||
template<bool isRead, class Buffers, class Handler>
|
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 async_op_base<Handler, Executor>
|
||||||
, public boost::asio::coroutine
|
, public boost::asio::coroutine
|
||||||
{
|
{
|
||||||
@@ -119,7 +203,7 @@ class basic_timeout_stream<Protocol, Executor>::async_op
|
|||||||
public:
|
public:
|
||||||
template<class Handler_>
|
template<class Handler_>
|
||||||
async_op(
|
async_op(
|
||||||
basic_timeout_stream& s,
|
basic_stream& s,
|
||||||
Buffers const& b,
|
Buffers const& b,
|
||||||
Handler_&& h)
|
Handler_&& h)
|
||||||
: async_op_base<Handler, Executor>(
|
: async_op_base<Handler, Executor>(
|
||||||
@@ -138,44 +222,55 @@ public:
|
|||||||
{
|
{
|
||||||
BOOST_ASIO_CORO_REENTER(*this)
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
state().timer.async_wait(
|
if(state().timer.expiry() != never())
|
||||||
net::bind_executor(
|
state().timer.async_wait(
|
||||||
this->get_executor(),
|
net::bind_executor(
|
||||||
timeout_handler{
|
this->get_executor(),
|
||||||
state(),
|
timeout_handler{
|
||||||
impl_,
|
state(),
|
||||||
state().tick
|
impl_,
|
||||||
}));
|
state().tick
|
||||||
|
}));
|
||||||
|
|
||||||
BOOST_ASIO_CORO_YIELD
|
BOOST_ASIO_CORO_YIELD
|
||||||
async_perform(
|
async_perform(
|
||||||
std::integral_constant<bool, isRead>{});
|
std::integral_constant<bool, isRead>{});
|
||||||
++state().tick;
|
|
||||||
|
|
||||||
// try cancelling timer
|
if(state().timer.expiry() != never())
|
||||||
auto const n =
|
|
||||||
state().timer.cancel();
|
|
||||||
if(n == 0)
|
|
||||||
{
|
{
|
||||||
if(state().timeout)
|
++state().tick;
|
||||||
|
|
||||||
|
// try cancelling timer
|
||||||
|
auto const n =
|
||||||
|
state().timer.cancel();
|
||||||
|
if(n == 0)
|
||||||
{
|
{
|
||||||
// timeout handler invoked
|
// timeout handler invoked?
|
||||||
ec = beast::error::timeout;
|
if(state().timeout)
|
||||||
state().timeout = false;
|
{
|
||||||
|
// yes, socket already closed
|
||||||
|
ec = beast::error::timeout;
|
||||||
|
state().timeout = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// timeout handler queued, stale
|
BOOST_ASSERT(n == 1);
|
||||||
|
BOOST_ASSERT(! state().timeout);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
BOOST_ASSERT(n == 1);
|
|
||||||
BOOST_ASSERT(! state().timeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
upcall:
|
||||||
pg_.reset();
|
pg_.reset();
|
||||||
this->invoke(ec, bytes_transferred);
|
this->invoke(ec, bytes_transferred);
|
||||||
}
|
}
|
||||||
@@ -188,17 +283,17 @@ namespace detail {
|
|||||||
|
|
||||||
template<
|
template<
|
||||||
class Protocol, class Executor, class Handler>
|
class Protocol, class Executor, class Handler>
|
||||||
class timeout_stream_connect_op
|
class basic_stream_connect_op
|
||||||
: public async_op_base<Handler, Executor>
|
: public async_op_base<Handler, Executor>
|
||||||
{
|
{
|
||||||
using stream_type =
|
using stream_type =
|
||||||
beast::basic_timeout_stream<Protocol, Executor>;
|
beast::basic_stream<Protocol, Executor>;
|
||||||
|
|
||||||
using timeout_handler =
|
using timeout_handler =
|
||||||
typename stream_type::timeout_handler;
|
typename stream_type::timeout_handler;
|
||||||
|
|
||||||
std::shared_ptr<typename basic_timeout_stream<
|
std::shared_ptr<typename
|
||||||
Protocol, Executor>::impl_type> impl_;
|
stream_type::impl_type> impl_;
|
||||||
typename stream_type::pending_guard pg0_;
|
typename stream_type::pending_guard pg0_;
|
||||||
typename stream_type::pending_guard pg1_;
|
typename stream_type::pending_guard pg1_;
|
||||||
|
|
||||||
@@ -209,64 +304,8 @@ class timeout_stream_connect_op
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
template<
|
|
||||||
class Endpoints, class Condition,
|
|
||||||
class Handler_>
|
|
||||||
timeout_stream_connect_op(
|
|
||||||
stream_type& s,
|
|
||||||
Endpoints const& eps,
|
|
||||||
Condition 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)
|
|
||||||
{
|
|
||||||
// must come first
|
|
||||||
impl_->write.timer.async_wait(
|
|
||||||
net::bind_executor(
|
|
||||||
this->get_executor(),
|
|
||||||
timeout_handler{
|
|
||||||
state(),
|
|
||||||
impl_,
|
|
||||||
state().tick}));
|
|
||||||
|
|
||||||
net::async_connect(impl_->socket,
|
|
||||||
eps, cond, std::move(*this));
|
|
||||||
// *this is now moved-from
|
|
||||||
}
|
|
||||||
|
|
||||||
template<
|
|
||||||
class Iterator, class Condition,
|
|
||||||
class Handler_>
|
|
||||||
timeout_stream_connect_op(
|
|
||||||
stream_type& s,
|
|
||||||
Iterator begin, Iterator end,
|
|
||||||
Condition 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)
|
|
||||||
{
|
|
||||||
// must come first
|
|
||||||
impl_->write.timer.async_wait(
|
|
||||||
net::bind_executor(
|
|
||||||
this->get_executor(),
|
|
||||||
timeout_handler{
|
|
||||||
state(),
|
|
||||||
impl_,
|
|
||||||
state().tick}));
|
|
||||||
|
|
||||||
net::async_connect(impl_->socket,
|
|
||||||
begin, end, cond, std::move(*this));
|
|
||||||
// *this is now moved-from
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Handler_>
|
template<class Handler_>
|
||||||
timeout_stream_connect_op(
|
basic_stream_connect_op(
|
||||||
stream_type& s,
|
stream_type& s,
|
||||||
typename stream_type::endpoint_type ep,
|
typename stream_type::endpoint_type ep,
|
||||||
Handler_&& h)
|
Handler_&& h)
|
||||||
@@ -276,48 +315,104 @@ public:
|
|||||||
, pg0_(impl_->read.pending)
|
, pg0_(impl_->read.pending)
|
||||||
, pg1_(impl_->write.pending)
|
, pg1_(impl_->write.pending)
|
||||||
{
|
{
|
||||||
// must come first
|
if(state().timer.expiry() != stream_base::never())
|
||||||
impl_->write.timer.async_wait(
|
impl_->write.timer.async_wait(
|
||||||
net::bind_executor(
|
net::bind_executor(
|
||||||
this->get_executor(),
|
this->get_executor(),
|
||||||
timeout_handler{
|
timeout_handler{
|
||||||
state(),
|
state(),
|
||||||
impl_,
|
impl_,
|
||||||
state().tick}));
|
state().tick}));
|
||||||
|
|
||||||
impl_->socket.async_connect(
|
impl_->socket.async_connect(
|
||||||
ep, std::move(*this));
|
ep, std::move(*this));
|
||||||
// *this is now moved-from
|
// *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(),
|
||||||
|
timeout_handler{
|
||||||
|
state(),
|
||||||
|
impl_,
|
||||||
|
state().tick}));
|
||||||
|
|
||||||
|
net::async_connect(impl_->socket,
|
||||||
|
eps, cond, std::move(*this));
|
||||||
|
// *this is now moved-from
|
||||||
|
}
|
||||||
|
|
||||||
|
template<
|
||||||
|
class Iterator, class Condition,
|
||||||
|
class Handler_>
|
||||||
|
basic_stream_connect_op(
|
||||||
|
stream_type& s,
|
||||||
|
Iterator begin, Iterator end,
|
||||||
|
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(),
|
||||||
|
timeout_handler{
|
||||||
|
state(),
|
||||||
|
impl_,
|
||||||
|
state().tick}));
|
||||||
|
|
||||||
|
net::async_connect(impl_->socket,
|
||||||
|
begin, end, cond, std::move(*this));
|
||||||
|
// *this is now moved-from
|
||||||
|
}
|
||||||
|
|
||||||
template<class... Args>
|
template<class... Args>
|
||||||
void
|
void
|
||||||
operator()(error_code ec, Args&&... args)
|
operator()(error_code ec, Args&&... args)
|
||||||
{
|
{
|
||||||
++state().tick;
|
if(state().timer.expiry() != stream_base::never())
|
||||||
|
|
||||||
// try cancelling timer
|
|
||||||
auto const n =
|
|
||||||
impl_->write.timer.cancel();
|
|
||||||
if(n == 0)
|
|
||||||
{
|
{
|
||||||
if(state().timeout)
|
++state().tick;
|
||||||
|
|
||||||
|
// try cancelling timer
|
||||||
|
auto const n =
|
||||||
|
impl_->write.timer.cancel();
|
||||||
|
if(n == 0)
|
||||||
{
|
{
|
||||||
// timeout handler invoked
|
// timeout handler invoked?
|
||||||
ec = beast::error::timeout;
|
if(state().timeout)
|
||||||
state().timeout = false;
|
{
|
||||||
|
// yes, socket already closed
|
||||||
|
ec = beast::error::timeout;
|
||||||
|
state().timeout = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// timeout handler queued, stale
|
BOOST_ASSERT(n == 1);
|
||||||
|
BOOST_ASSERT(! state().timeout);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
BOOST_ASSERT(n == 1);
|
|
||||||
BOOST_ASSERT(! state().timeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
pg0_.reset();
|
pg0_.reset();
|
||||||
pg1_.reset();
|
pg1_.reset();
|
||||||
this->invoke(ec, std::forward<Args>(args)...);
|
this->invoke(ec, std::forward<Args>(args)...);
|
||||||
@@ -329,82 +424,8 @@ public:
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
template<class Protocol, class Executor>
|
template<class Protocol, class Executor>
|
||||||
template<class... Args>
|
basic_stream<Protocol, Executor>::
|
||||||
basic_timeout_stream<Protocol, Executor>::
|
~basic_stream()
|
||||||
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()
|
|
||||||
{
|
{
|
||||||
// the shared object can outlive *this,
|
// the shared object can outlive *this,
|
||||||
// cancel any operations so the shared
|
// cancel any operations so the shared
|
||||||
@@ -413,12 +434,12 @@ basic_timeout_stream<Protocol, Executor>::
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<class Protocol, class Executor>
|
template<class Protocol, class Executor>
|
||||||
template<class ExecutionContext, class>
|
template<class ExecutionContext, class... Args, class>
|
||||||
basic_timeout_stream<Protocol, Executor>::
|
basic_stream<Protocol, Executor>::
|
||||||
basic_timeout_stream(ExecutionContext& ctx)
|
basic_stream(ExecutionContext& ctx, Args&&... args)
|
||||||
: impl_(std::make_shared<impl_type>(
|
: impl_(std::make_shared<impl_type>(
|
||||||
ctx.get_executor(),
|
ctx.get_executor(),
|
||||||
ctx))
|
ctx, std::forward<Args>(args)...))
|
||||||
{
|
{
|
||||||
// Restriction is necessary until Asio fully supports P1322R0
|
// Restriction is necessary until Asio fully supports P1322R0
|
||||||
static_assert(
|
static_assert(
|
||||||
@@ -427,67 +448,52 @@ basic_timeout_stream(ExecutionContext& ctx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<class Protocol, class Executor>
|
template<class Protocol, class Executor>
|
||||||
basic_timeout_stream<Protocol, Executor>::
|
template<class... Args>
|
||||||
basic_timeout_stream(executor_type const& ex)
|
basic_stream<Protocol, Executor>::
|
||||||
|
basic_stream(
|
||||||
|
executor_type const& ex, Args&&... args)
|
||||||
: impl_(std::make_shared<impl_type>(
|
: impl_(std::make_shared<impl_type>(
|
||||||
ex, ex.context()))
|
ex,
|
||||||
|
ex.context(), std::forward<Args>(args)...))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Protocol, class Executor>
|
template<class Protocol, class Executor>
|
||||||
basic_timeout_stream<Protocol, Executor>::
|
template<class OtherProtocol, class>
|
||||||
basic_timeout_stream(
|
basic_stream<Protocol, Executor>::
|
||||||
net::basic_stream_socket<Protocol>&& socket)
|
basic_stream(net::basic_stream_socket<OtherProtocol>&& socket)
|
||||||
: impl_(std::make_shared<impl_type>(
|
: 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>
|
template<class Protocol, class Executor>
|
||||||
basic_timeout_stream<Protocol, Executor>::
|
basic_stream<Protocol, Executor>::
|
||||||
basic_timeout_stream(
|
basic_stream(basic_stream&& other)
|
||||||
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)
|
|
||||||
: impl_(std::make_shared<impl_type>(
|
: impl_(std::make_shared<impl_type>(
|
||||||
std::move(*other.impl_)))
|
std::move(*other.impl_)))
|
||||||
{
|
{
|
||||||
// Can't move while operations are pending!
|
// VFALCO I'm not sure this implementation is correct...
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
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>
|
template<class Protocol, class Executor>
|
||||||
void
|
void
|
||||||
basic_timeout_stream<Protocol, Executor>::
|
basic_stream<Protocol, Executor>::
|
||||||
expires_after(std::chrono::nanoseconds expiry_time)
|
expires_after(std::chrono::nanoseconds expiry_time)
|
||||||
{
|
{
|
||||||
// If assert goes off, it means that there are
|
// 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>
|
template<class Protocol, class Executor>
|
||||||
void
|
void
|
||||||
basic_timeout_stream<Protocol, Executor>::
|
basic_stream<Protocol, Executor>::
|
||||||
expires_at(
|
expires_at(
|
||||||
net::steady_timer::time_point expiry_time)
|
net::steady_timer::time_point expiry_time)
|
||||||
{
|
{
|
||||||
@@ -538,7 +544,7 @@ expires_at(
|
|||||||
|
|
||||||
template<class Protocol, class Executor>
|
template<class Protocol, class Executor>
|
||||||
void
|
void
|
||||||
basic_timeout_stream<Protocol, Executor>::
|
basic_stream<Protocol, Executor>::
|
||||||
expires_never()
|
expires_never()
|
||||||
{
|
{
|
||||||
impl_->reset();
|
impl_->reset();
|
||||||
@@ -546,7 +552,7 @@ expires_never()
|
|||||||
|
|
||||||
template<class Protocol, class Executor>
|
template<class Protocol, class Executor>
|
||||||
void
|
void
|
||||||
basic_timeout_stream<Protocol, Executor>::
|
basic_stream<Protocol, Executor>::
|
||||||
cancel()
|
cancel()
|
||||||
{
|
{
|
||||||
error_code ec;
|
error_code ec;
|
||||||
@@ -555,7 +561,7 @@ cancel()
|
|||||||
|
|
||||||
template<class Protocol, class Executor>
|
template<class Protocol, class Executor>
|
||||||
void
|
void
|
||||||
basic_timeout_stream<Protocol, Executor>::
|
basic_stream<Protocol, Executor>::
|
||||||
close()
|
close()
|
||||||
{
|
{
|
||||||
impl_->close();
|
impl_->close();
|
||||||
@@ -565,14 +571,14 @@ template<class Protocol, class Executor>
|
|||||||
template<class ConnectHandler>
|
template<class ConnectHandler>
|
||||||
BOOST_ASIO_INITFN_RESULT_TYPE(ConnectHandler,
|
BOOST_ASIO_INITFN_RESULT_TYPE(ConnectHandler,
|
||||||
void(error_code))
|
void(error_code))
|
||||||
basic_timeout_stream<Protocol, Executor>::
|
basic_stream<Protocol, Executor>::
|
||||||
async_connect(
|
async_connect(
|
||||||
endpoint_type ep,
|
endpoint_type const& ep,
|
||||||
ConnectHandler&& handler)
|
ConnectHandler&& handler)
|
||||||
{
|
{
|
||||||
BOOST_BEAST_HANDLER_INIT(
|
BOOST_BEAST_HANDLER_INIT(
|
||||||
ConnectHandler, void(error_code));
|
ConnectHandler, void(error_code));
|
||||||
detail::timeout_stream_connect_op<
|
detail::basic_stream_connect_op<
|
||||||
Protocol, Executor, BOOST_ASIO_HANDLER_TYPE(
|
Protocol, Executor, BOOST_ASIO_HANDLER_TYPE(
|
||||||
ConnectHandler, void(error_code))>(*this,
|
ConnectHandler, void(error_code))>(*this,
|
||||||
ep, std::forward<ConnectHandler>(handler));
|
ep, std::forward<ConnectHandler>(handler));
|
||||||
@@ -583,7 +589,7 @@ template<class Protocol, class Executor>
|
|||||||
template<class MutableBufferSequence, class ReadHandler>
|
template<class MutableBufferSequence, class ReadHandler>
|
||||||
BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
|
BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
|
||||||
void(error_code, std::size_t))
|
void(error_code, std::size_t))
|
||||||
basic_timeout_stream<Protocol, Executor>::
|
basic_stream<Protocol, Executor>::
|
||||||
async_read_some(
|
async_read_some(
|
||||||
MutableBufferSequence const& buffers,
|
MutableBufferSequence const& buffers,
|
||||||
ReadHandler&& handler)
|
ReadHandler&& handler)
|
||||||
@@ -603,7 +609,7 @@ template<class Protocol, class Executor>
|
|||||||
template<class ConstBufferSequence, class WriteHandler>
|
template<class ConstBufferSequence, class WriteHandler>
|
||||||
BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler,
|
BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler,
|
||||||
void(error_code, std::size_t))
|
void(error_code, std::size_t))
|
||||||
basic_timeout_stream<Protocol, Executor>::
|
basic_stream<Protocol, Executor>::
|
||||||
async_write_some(
|
async_write_some(
|
||||||
ConstBufferSequence const& buffers,
|
ConstBufferSequence const& buffers,
|
||||||
WriteHandler&& handler)
|
WriteHandler&& handler)
|
||||||
@@ -629,13 +635,13 @@ template<
|
|||||||
BOOST_ASIO_INITFN_RESULT_TYPE(RangeConnectHandler,
|
BOOST_ASIO_INITFN_RESULT_TYPE(RangeConnectHandler,
|
||||||
void(error_code, typename Protocol::endpoint))
|
void(error_code, typename Protocol::endpoint))
|
||||||
async_connect(
|
async_connect(
|
||||||
basic_timeout_stream<Protocol, Executor>& stream,
|
basic_stream<Protocol, Executor>& stream,
|
||||||
EndpointSequence const& endpoints,
|
EndpointSequence const& endpoints,
|
||||||
RangeConnectHandler&& handler)
|
RangeConnectHandler&& handler)
|
||||||
{
|
{
|
||||||
BOOST_BEAST_HANDLER_INIT(RangeConnectHandler,
|
BOOST_BEAST_HANDLER_INIT(RangeConnectHandler,
|
||||||
void(error_code, typename Protocol::endpoint));
|
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,
|
BOOST_ASIO_HANDLER_TYPE(RangeConnectHandler,
|
||||||
void(error_code, typename Protocol::endpoint))>(
|
void(error_code, typename Protocol::endpoint))>(
|
||||||
stream, endpoints, detail::any_endpoint{},
|
stream, endpoints, detail::any_endpoint{},
|
||||||
@@ -652,14 +658,14 @@ template<
|
|||||||
BOOST_ASIO_INITFN_RESULT_TYPE(RangeConnectHandler,
|
BOOST_ASIO_INITFN_RESULT_TYPE(RangeConnectHandler,
|
||||||
void (error_code, typename Protocol::endpoint))
|
void (error_code, typename Protocol::endpoint))
|
||||||
async_connect(
|
async_connect(
|
||||||
basic_timeout_stream<Protocol, Executor>& stream,
|
basic_stream<Protocol, Executor>& stream,
|
||||||
EndpointSequence const& endpoints,
|
EndpointSequence const& endpoints,
|
||||||
ConnectCondition connect_condition,
|
ConnectCondition connect_condition,
|
||||||
RangeConnectHandler&& handler)
|
RangeConnectHandler&& handler)
|
||||||
{
|
{
|
||||||
BOOST_BEAST_HANDLER_INIT(RangeConnectHandler,
|
BOOST_BEAST_HANDLER_INIT(RangeConnectHandler,
|
||||||
void(error_code, typename Protocol::endpoint));
|
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,
|
BOOST_ASIO_HANDLER_TYPE(RangeConnectHandler,
|
||||||
void(error_code, typename Protocol::endpoint))>(
|
void(error_code, typename Protocol::endpoint))>(
|
||||||
stream, endpoints, connect_condition,
|
stream, endpoints, connect_condition,
|
||||||
@@ -674,13 +680,13 @@ template<
|
|||||||
BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler,
|
BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler,
|
||||||
void (error_code, Iterator))
|
void (error_code, Iterator))
|
||||||
async_connect(
|
async_connect(
|
||||||
basic_timeout_stream<Protocol, Executor>& stream,
|
basic_stream<Protocol, Executor>& stream,
|
||||||
Iterator begin, Iterator end,
|
Iterator begin, Iterator end,
|
||||||
IteratorConnectHandler&& handler)
|
IteratorConnectHandler&& handler)
|
||||||
{
|
{
|
||||||
BOOST_BEAST_HANDLER_INIT(IteratorConnectHandler,
|
BOOST_BEAST_HANDLER_INIT(IteratorConnectHandler,
|
||||||
void(error_code, Iterator));
|
void(error_code, Iterator));
|
||||||
detail::timeout_stream_connect_op<Protocol, Executor,
|
detail::basic_stream_connect_op<Protocol, Executor,
|
||||||
BOOST_ASIO_HANDLER_TYPE(IteratorConnectHandler,
|
BOOST_ASIO_HANDLER_TYPE(IteratorConnectHandler,
|
||||||
void(error_code, Iterator))>(
|
void(error_code, Iterator))>(
|
||||||
stream, begin, end, detail::any_endpoint{},
|
stream, begin, end, detail::any_endpoint{},
|
||||||
@@ -696,14 +702,14 @@ template<
|
|||||||
BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler,
|
BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler,
|
||||||
void (error_code, Iterator))
|
void (error_code, Iterator))
|
||||||
async_connect(
|
async_connect(
|
||||||
basic_timeout_stream<Protocol, Executor>& stream,
|
basic_stream<Protocol, Executor>& stream,
|
||||||
Iterator begin, Iterator end,
|
Iterator begin, Iterator end,
|
||||||
ConnectCondition connect_condition,
|
ConnectCondition connect_condition,
|
||||||
IteratorConnectHandler&& handler)
|
IteratorConnectHandler&& handler)
|
||||||
{
|
{
|
||||||
BOOST_BEAST_HANDLER_INIT(IteratorConnectHandler,
|
BOOST_BEAST_HANDLER_INIT(IteratorConnectHandler,
|
||||||
void(error_code, Iterator));
|
void(error_code, Iterator));
|
||||||
detail::timeout_stream_connect_op<Protocol, Executor,
|
detail::basic_stream_connect_op<Protocol, Executor,
|
||||||
BOOST_ASIO_HANDLER_TYPE(IteratorConnectHandler,
|
BOOST_ASIO_HANDLER_TYPE(IteratorConnectHandler,
|
||||||
void(error_code, Iterator))>(
|
void(error_code, Iterator))>(
|
||||||
stream, begin, end, connect_condition,
|
stream, begin, end, connect_condition,
|
||||||
@@ -711,6 +717,46 @@ async_connect(
|
|||||||
return init.result.get();
|
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
|
} // beast
|
||||||
} // boost
|
} // boost
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
@@ -7,22 +7,25 @@
|
|||||||
// Official repository: https://github.com/boostorg/beast
|
// Official repository: https://github.com/boostorg/beast
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifndef BOOST_BEAST_CORE_TIMEOUT_STREAM_HPP
|
#ifndef BOOST_BEAST_CORE_TCP_STREAM_HPP
|
||||||
#define BOOST_BEAST_CORE_TIMEOUT_STREAM_HPP
|
#define BOOST_BEAST_CORE_TCP_STREAM_HPP
|
||||||
|
|
||||||
#include <boost/beast/core/detail/config.hpp>
|
#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/error.hpp>
|
|
||||||
#include <boost/asio/ip/tcp.hpp>
|
#include <boost/asio/ip/tcp.hpp>
|
||||||
|
|
||||||
namespace boost {
|
namespace boost {
|
||||||
namespace beast {
|
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<
|
template<class Executor>
|
||||||
net::ip::tcp,
|
using tcp_stream = basic_stream<net::ip::tcp, Executor>;
|
||||||
net::io_context::executor_type>;
|
|
||||||
|
|
||||||
} // beast
|
} // beast
|
||||||
} // boost
|
} // boost
|
@@ -599,7 +599,7 @@ public:
|
|||||||
|
|
||||||
@li An error occurs.
|
@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`
|
in terms of calls to the next layer's `read_some` and `write_some`
|
||||||
functions.
|
functions.
|
||||||
|
|
||||||
@@ -646,7 +646,7 @@ public:
|
|||||||
|
|
||||||
@li An error occurs.
|
@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`
|
in terms of calls to the next layer's `read_some` and `write_some`
|
||||||
functions.
|
functions.
|
||||||
|
|
||||||
@@ -700,7 +700,7 @@ public:
|
|||||||
|
|
||||||
@li An error occurs.
|
@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`
|
in terms of calls to the next layer's `read_some` and `write_some`
|
||||||
functions.
|
functions.
|
||||||
|
|
||||||
@@ -764,7 +764,7 @@ public:
|
|||||||
|
|
||||||
@li An error occurs.
|
@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`
|
in terms of calls to the next layer's `read_some` and `write_some`
|
||||||
functions.
|
functions.
|
||||||
|
|
||||||
@@ -835,7 +835,7 @@ public:
|
|||||||
|
|
||||||
@li An error occurs.
|
@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`
|
in terms of calls to the next layer's `read_some` and `write_some`
|
||||||
functions.
|
functions.
|
||||||
|
|
||||||
@@ -884,7 +884,7 @@ public:
|
|||||||
|
|
||||||
@li An error occurs.
|
@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`
|
in terms of calls to the next layer's `read_some` and `write_some`
|
||||||
functions.
|
functions.
|
||||||
|
|
||||||
@@ -941,7 +941,7 @@ public:
|
|||||||
|
|
||||||
@li An error occurs.
|
@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`
|
in terms of calls to the next layer's `read_some` and `write_some`
|
||||||
functions.
|
functions.
|
||||||
|
|
||||||
@@ -1008,7 +1008,7 @@ public:
|
|||||||
|
|
||||||
@li An error occurs.
|
@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`
|
in terms of calls to the next layer's `read_some` and `write_some`
|
||||||
functions.
|
functions.
|
||||||
|
|
||||||
@@ -1428,7 +1428,7 @@ public:
|
|||||||
|
|
||||||
@li An error occurs.
|
@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`
|
in terms of calls to the next layer's `read_some` and `write_some`
|
||||||
functions.
|
functions.
|
||||||
|
|
||||||
@@ -1467,7 +1467,7 @@ public:
|
|||||||
|
|
||||||
@li An error occurs.
|
@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`
|
in terms of calls to the next layer's `read_some` and `write_some`
|
||||||
functions.
|
functions.
|
||||||
|
|
||||||
@@ -1518,7 +1518,7 @@ public:
|
|||||||
|
|
||||||
@li An error occurs.
|
@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`
|
in terms of calls to the next layer's `read_some` and `write_some`
|
||||||
functions.
|
functions.
|
||||||
|
|
||||||
@@ -1557,7 +1557,7 @@ public:
|
|||||||
|
|
||||||
@li An error occurs.
|
@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`
|
in terms of calls to the next layer's `read_some` and `write_some`
|
||||||
functions.
|
functions.
|
||||||
|
|
||||||
@@ -1610,7 +1610,7 @@ public:
|
|||||||
|
|
||||||
@li An error occurs.
|
@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`
|
in terms of calls to the next layer's `read_some` and `write_some`
|
||||||
functions.
|
functions.
|
||||||
|
|
||||||
@@ -1659,7 +1659,7 @@ public:
|
|||||||
|
|
||||||
@li An error occurs.
|
@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`
|
in terms of calls to the next layer's `read_some` and `write_some`
|
||||||
functions.
|
functions.
|
||||||
|
|
||||||
@@ -1722,7 +1722,7 @@ public:
|
|||||||
|
|
||||||
@li An error occurs.
|
@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`
|
in terms of calls to the next layer's `read_some` and `write_some`
|
||||||
functions.
|
functions.
|
||||||
|
|
||||||
@@ -1773,7 +1773,7 @@ public:
|
|||||||
|
|
||||||
@li An error occurs.
|
@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`
|
in terms of calls to the next layer's `read_some` and `write_some`
|
||||||
functions.
|
functions.
|
||||||
|
|
||||||
@@ -1836,7 +1836,7 @@ public:
|
|||||||
|
|
||||||
@li An error occurs.
|
@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`
|
in terms of calls to the next layer's `read_some` and `write_some`
|
||||||
functions.
|
functions.
|
||||||
|
|
||||||
@@ -1874,7 +1874,7 @@ public:
|
|||||||
|
|
||||||
@li An error occurs.
|
@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`
|
in terms of calls to the next layer's `read_some` and `write_some`
|
||||||
functions.
|
functions.
|
||||||
|
|
||||||
@@ -1925,7 +1925,7 @@ public:
|
|||||||
|
|
||||||
@li An error occurs.
|
@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`
|
in terms of calls to the next layer's `read_some` and `write_some`
|
||||||
functions.
|
functions.
|
||||||
|
|
||||||
@@ -1964,7 +1964,7 @@ public:
|
|||||||
|
|
||||||
@li An error occurs.
|
@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`
|
in terms of calls to the next layer's `read_some` and `write_some`
|
||||||
functions.
|
functions.
|
||||||
|
|
||||||
@@ -2424,7 +2424,7 @@ public:
|
|||||||
|
|
||||||
@li An error occurs.
|
@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.
|
in terms of calls to the next layer's `write_some` function.
|
||||||
|
|
||||||
After beginning the closing handshake, the program should not write
|
After beginning the closing handshake, the program should not write
|
||||||
@@ -2459,7 +2459,7 @@ public:
|
|||||||
|
|
||||||
@li An error occurs.
|
@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.
|
in terms of calls to the next layer's `write_some` function.
|
||||||
|
|
||||||
After beginning the closing handshake, the program should not write
|
After beginning the closing handshake, the program should not write
|
||||||
@@ -2551,7 +2551,7 @@ public:
|
|||||||
|
|
||||||
@li An error occurs.
|
@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.
|
in terms of calls to the next layer's `write_some` function.
|
||||||
|
|
||||||
@param payload The payload of the ping message, which may be empty.
|
@param payload The payload of the ping message, which may be empty.
|
||||||
@@ -2574,7 +2574,7 @@ public:
|
|||||||
|
|
||||||
@li An error occurs.
|
@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.
|
in terms of calls to the next layer's `write_some` function.
|
||||||
|
|
||||||
@param payload The payload of the ping message, which may be empty.
|
@param payload The payload of the ping message, which may be empty.
|
||||||
@@ -2640,7 +2640,7 @@ public:
|
|||||||
|
|
||||||
@li An error occurs.
|
@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.
|
in terms of calls to the next layer's `write_some` function.
|
||||||
|
|
||||||
WebSocket allows pong frames to be sent at any time, without first
|
WebSocket allows pong frames to be sent at any time, without first
|
||||||
@@ -2667,7 +2667,7 @@ public:
|
|||||||
|
|
||||||
@li An error occurs.
|
@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.
|
in terms of calls to the next layer's `write_some` function.
|
||||||
|
|
||||||
WebSocket allows pong frames to be sent at any time, without first
|
WebSocket allows pong frames to be sent at any time, without first
|
||||||
@@ -2747,7 +2747,7 @@ public:
|
|||||||
|
|
||||||
@li An error occurs.
|
@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`
|
in terms of calls to the next layer's `read_some` and `write_some`
|
||||||
functions.
|
functions.
|
||||||
|
|
||||||
@@ -2790,7 +2790,7 @@ public:
|
|||||||
|
|
||||||
@li An error occurs.
|
@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`
|
in terms of calls to the next layer's `read_some` and `write_some`
|
||||||
functions.
|
functions.
|
||||||
|
|
||||||
@@ -2899,7 +2899,7 @@ public:
|
|||||||
|
|
||||||
@li An error occurs.
|
@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`
|
in terms of calls to the next layer's `read_some` and `write_some`
|
||||||
functions.
|
functions.
|
||||||
|
|
||||||
@@ -2950,7 +2950,7 @@ public:
|
|||||||
|
|
||||||
@li An error occurs.
|
@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`
|
in terms of calls to the next layer's `read_some` and `write_some`
|
||||||
functions.
|
functions.
|
||||||
|
|
||||||
@@ -3032,6 +3032,10 @@ public:
|
|||||||
|
|
||||||
@param buffer A dynamic buffer to append message data to.
|
@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
|
@param handler Invoked when the operation completes. Ownership
|
||||||
of the handler will be transferred by move-construction as needed.
|
of the handler will be transferred by move-construction as needed.
|
||||||
The equivalent function signature of the handler must be:
|
The equivalent function signature of the handler must be:
|
||||||
@@ -3069,7 +3073,7 @@ public:
|
|||||||
|
|
||||||
@li An error occurs.
|
@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`
|
in terms of calls to the next layer's `read_some` and `write_some`
|
||||||
functions.
|
functions.
|
||||||
|
|
||||||
@@ -3096,10 +3100,6 @@ public:
|
|||||||
The previous contents of the buffers will be overwritten, starting
|
The previous contents of the buffers will be overwritten, starting
|
||||||
from the beginning.
|
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.
|
@throws system_error Thrown on failure.
|
||||||
*/
|
*/
|
||||||
template<class MutableBufferSequence>
|
template<class MutableBufferSequence>
|
||||||
@@ -3120,7 +3120,7 @@ public:
|
|||||||
|
|
||||||
@li An error occurs.
|
@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`
|
in terms of calls to the next layer's `read_some` and `write_some`
|
||||||
functions.
|
functions.
|
||||||
|
|
||||||
@@ -3147,10 +3147,6 @@ public:
|
|||||||
The previous contents of the buffers will be overwritten, starting
|
The previous contents of the buffers will be overwritten, starting
|
||||||
from the beginning.
|
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.
|
@param ec Set to indicate what error occurred, if any.
|
||||||
*/
|
*/
|
||||||
template<class MutableBufferSequence>
|
template<class MutableBufferSequence>
|
||||||
@@ -3246,7 +3242,7 @@ public:
|
|||||||
|
|
||||||
@li An error occurs.
|
@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.
|
in terms of calls to the next layer's `write_some` function.
|
||||||
|
|
||||||
The current setting of the @ref binary option controls
|
The current setting of the @ref binary option controls
|
||||||
@@ -3275,7 +3271,7 @@ public:
|
|||||||
|
|
||||||
@li An error occurs.
|
@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.
|
in terms of calls to the next layer's `write_some` function.
|
||||||
|
|
||||||
The current setting of the @ref binary option controls
|
The current setting of the @ref binary option controls
|
||||||
@@ -3359,7 +3355,7 @@ public:
|
|||||||
|
|
||||||
@li An error occurs.
|
@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.
|
in terms of calls to the next layer's `write_some` function.
|
||||||
|
|
||||||
If this is the beginning of a new message, the message opcode
|
If this is the beginning of a new message, the message opcode
|
||||||
@@ -3389,7 +3385,7 @@ public:
|
|||||||
|
|
||||||
@li An error occurs.
|
@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.
|
in terms of calls to the next layer's `write_some` function.
|
||||||
|
|
||||||
If this is the beginning of a new message, the message opcode
|
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 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 sent from the buffers.
|
||||||
|
|
||||||
@return The number of bytes consumed in the input buffers.
|
@return The number of bytes consumed in the input buffers.
|
||||||
|
@@ -30,7 +30,7 @@ add_executable (tests-beast-core
|
|||||||
_detail_variant.cpp
|
_detail_variant.cpp
|
||||||
_detail_varint.cpp
|
_detail_varint.cpp
|
||||||
async_op_base.cpp
|
async_op_base.cpp
|
||||||
basic_timeout_stream.cpp
|
basic_stream.cpp
|
||||||
bind_handler.cpp
|
bind_handler.cpp
|
||||||
buffer_size.cpp
|
buffer_size.cpp
|
||||||
buffer_traits.cpp
|
buffer_traits.cpp
|
||||||
@@ -61,11 +61,10 @@ add_executable (tests-beast-core
|
|||||||
span.cpp
|
span.cpp
|
||||||
static_buffer.cpp
|
static_buffer.cpp
|
||||||
static_string.cpp
|
static_string.cpp
|
||||||
stranded_socket.cpp
|
|
||||||
stream_traits.cpp
|
stream_traits.cpp
|
||||||
string.cpp
|
string.cpp
|
||||||
string_param.cpp
|
string_param.cpp
|
||||||
timeout_stream.cpp
|
tcp_stream.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
set_property(TARGET tests-beast-core PROPERTY FOLDER "tests")
|
set_property(TARGET tests-beast-core PROPERTY FOLDER "tests")
|
||||||
|
@@ -18,7 +18,7 @@ local SOURCES =
|
|||||||
_detail_variant.cpp
|
_detail_variant.cpp
|
||||||
_detail_varint.cpp
|
_detail_varint.cpp
|
||||||
async_op_base.cpp
|
async_op_base.cpp
|
||||||
basic_timeout_stream.cpp
|
basic_stream.cpp
|
||||||
bind_handler.cpp
|
bind_handler.cpp
|
||||||
buffer_size.cpp
|
buffer_size.cpp
|
||||||
buffer_traits.cpp
|
buffer_traits.cpp
|
||||||
@@ -49,11 +49,10 @@ local SOURCES =
|
|||||||
span.cpp
|
span.cpp
|
||||||
static_buffer.cpp
|
static_buffer.cpp
|
||||||
static_string.cpp
|
static_string.cpp
|
||||||
stranded_socket.cpp
|
|
||||||
stream_traits.cpp
|
stream_traits.cpp
|
||||||
string.cpp
|
string.cpp
|
||||||
string_param.cpp
|
string_param.cpp
|
||||||
timeout_stream.cpp
|
tcp_stream.cpp
|
||||||
;
|
;
|
||||||
|
|
||||||
local RUN_TESTS ;
|
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.
|
// 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