diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6ed00ba4..7abfe78c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,9 @@
+Version 204
+
+* Add basic_timeout_stream
+
+--------------------------------------------------------------------------------
+
Version 203
* Update networking refresher doc
diff --git a/doc/qbk/00_main.qbk b/doc/qbk/00_main.qbk
index eba055ff..3fabfb9a 100644
--- a/doc/qbk/00_main.qbk
+++ b/doc/qbk/00_main.qbk
@@ -41,6 +41,7 @@
[def __asio_handler_allocate__ [@boost:/doc/html/boost_asio/reference/asio_handler_allocate.html `asio_handler_allocate`]]
[def __asio_handler_invoke__ [@boost:/doc/html/boost_asio/reference/asio_handler_invoke.html `asio_handler_invoke`]]
+[def __basic_stream_socket__ [@boost:/doc/html/boost_asio/reference/basic_stream_socket.html `basic_stream_socket`]]
[def __const_buffer__ [@boost:/doc/html/boost_asio/reference/const_buffer.html `const_buffer`]]
[def __deduced__ [@boost:/doc/html/boost_asio/reference/asynchronous_operations.html#boost_asio.reference.asynchronous_operations.automatic_deduction_of_initiating_function_return_type ['DEDUCED]]]
[def __executor_work_guard__ [@boost:/doc/html/boost_asio/reference/executor_work_guard.html `net::executor_work_guard`]]
@@ -64,6 +65,7 @@
[def __CompletionHandler__ [@boost:/doc/html/boost_asio/reference/CompletionHandler.html ['CompletionHandler]]]
[def __CompletionCondition__ [@boost:/doc/html/boost_asio/reference/CompletionCondition.html ['CompletionCondition]]]
[def __ConnectCondition__ [@boost:/doc/html/boost_asio/reference/ConnectCondition.html ['ConnectCondition]]]
+[def __ConnectHandler__ [@boost:/doc/html/boost_asio/reference/ConnectHandler.html ['ConnectHandler]]]
[def __ConstBufferSequence__ [@boost:/doc/html/boost_asio/reference/ConstBufferSequence.html ['ConstBufferSequence]]]
[def __EndpointSequence__ [@boost:/doc/html/boost_asio/reference/EndpointSequence.html ['EndpointSequence]]]
[def __Executor__ [@boost:/doc/html/boost_asio/reference/Executor1.html ['Executor]]]
diff --git a/doc/qbk/quickref.xml b/doc/qbk/quickref.xml
index c6119a11..e6f110ae 100644
--- a/doc/qbk/quickref.xml
+++ b/doc/qbk/quickref.xml
@@ -6,7 +6,7 @@
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
-->
@@ -180,7 +180,7 @@
async_op_basebasic_flat_bufferbasic_multi_buffer
- basic_stream_socket
+ basic_timeout_streambuffered_read_streambuffers_adaptorbuffers_cat_view
@@ -209,9 +209,9 @@
static_buffer_basestatic_stringstable_async_op_base
- stream_socketstring_paramstring_view
+ timeout_streamConstants
diff --git a/doc/xsl/class_detail.xsl b/doc/xsl/class_detail.xsl
index dab37942..d2562cfc 100644
--- a/doc/xsl/class_detail.xsl
+++ b/doc/xsl/class_detail.xsl
@@ -27,6 +27,9 @@
class __ConnectCondition__
+
+ class __ConnectHandler__
+ class __ConstBufferSequence__
diff --git a/include/boost/beast/core.hpp b/include/boost/beast/core.hpp
index a932b997..21b4134a 100644
--- a/include/boost/beast/core.hpp
+++ b/include/boost/beast/core.hpp
@@ -12,7 +12,7 @@
#include
-#include
+#include
#include
#include
#include
@@ -38,9 +38,9 @@
#include
#include
#include
-#include
#include
#include
+#include
#include
#endif
diff --git a/include/boost/beast/core/basic_stream_socket.hpp b/include/boost/beast/core/basic_stream_socket.hpp
deleted file mode 100644
index 4b2cb63b..00000000
--- a/include/boost/beast/core/basic_stream_socket.hpp
+++ /dev/null
@@ -1,1175 +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_STREAM_SOCKET_HPP
-#define BOOST_BEAST_CORE_BASIC_STREAM_SOCKET_HPP
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-namespace boost {
-namespace beast {
-
-/** A stream socket with integrated timeout and bandwidth management.
-
- This stream socket adapts a `net::basic_stream_socket` to provide
- the following additional features:
-
- @li The class template is parameterized on a user-defined executor
- used for asynchronous operations. This achieves partial support for
- "Networking TS enhancement to enable custom I/O executors"
- (P1322R0).
-
- @li Optional timeouts may be specified for logical operations which
- perform asynchronous reads, writes, and connects.
-
- @li Optional bytes-per-second rate limits may be set independently
- on asynchronous reads and writes.
-
- @par Usage
-
- Objects of this type are designed to be used in places where a
- regular networking TCP/IP socket is being used. In particular this
- class template replaces `net::basic_stream_socket`. The constructors
- used here are similar to those of networking sockets, but with the
- ability to use either an executor or an execution context when
- constructing the socket.
-
- The caller is responsible for ensuring that all stream operations,
- including the internal timer operations, are running from the same
- implicit or explicit strand. When there are multiple threads calling
- `net::io_context::run`, the `Executor` template parameter, and the
- instance of that executor type passed to the constructor must provide
- the following guarantees:
-
- @li Serial Execution:
- Function objects submitted to the executor shall never run
- concurrently.
-
- @li Ordering:
- Function objects submitted to the executor from the same thread shall
- execute in the order they were submitted.
-
- If only one thread is calling `net::io_context::run`, the executor
- may be the executor used by the I/O context (`net::io_context::executor_type`).
- Otherwise, a `net::strand` may be used to meet the requirements.
- Note that when using a strand to instantiate the socket, it is not
- necessary to also bind each submitted completion handler used in
- subsequent operations to the strand, this is taken care of automatically.
-
- @par Associated Executor
-
-
- @par Using Timeouts
-
- 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 defined as one of the following:
-
- @li A call to @ref beast::async_connect where the stream is passed
- as the first argument.
-
- @li One or more calls to either one or both of the stream's
- @ref async_read_some and @ref async_write_some member functions.
- This also includes indirect calls, for example when passing the
- stream as the first argument to an initiating function such as
- `net::async_read_until`.
-
- Each logical operation can be considered as peforming just reads,
- just writes, or both reads and writes. Calls to @ref beast::async_connect
- count as both a read and a write, although no actual reads or writes
- are performed. While logical operations can include both reading
- and writing, the usual restriction on having at most one read and
- one write outstanding simultaneously applies.
-
- The implementation maintains two timers: one timer for reads, and
- another timer for writes. When the expiration time is adjusted
- (by calling @ref expires_after or @ref expires_at), the indiviudal
- timer is only set if there is not currently an operation of that
- type (read or write) outstanding. It is undefined behavior to set
- an expiration when there is both a read and a write pending, since
- there would be no available timer to apply the expiration to.
-
- @par Example
- This code sets a timeout, and uses a generic networking stream algorithm
- to read data from a timed stream until a particular delimiter is found
- or until the stream times out:
- @code
- template
- void async_read_line (
- basic_stream_socket& stream,
- net::streambuf& buffer, ReadHandler&& handler)
- {
- stream.expires_after (std::chrono::seconds(30));
-
- net::async_read_until (stream, buffer, "\r\n", std::forward(handler));
- }
- @endcode
-
- 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 Using Rate Limits
-
- @tparam Protocol A type meeting the requirements of Protocol
- 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 Executor to
- be used for submitting all completion handlers which do not already have an
- associated executor.
-
- @note A multi-stream object must not be moved or destroyed while there
- are oustanding asynchronous operations associated with it. Objects of this
- type meet the requirements of @b AsyncReadStream and @b AsyncWriteStream.
-
- @par Thread Safety
- Distinct objects: Safe.@n
- Shared objects: Unsafe. The application must also ensure
- that all asynchronous operations are performed within the same
- implicit or explicit strand.
-
- @see "Networking TS enhancement to enable custom I/O executors"
- (P1322R0).
-*/
-template
-class basic_stream_socket
- : private detail::stream_socket_base
-{
- using time_point = typename
- std::chrono::steady_clock::time_point;
-
- // the number of seconds in each time slice
- // for applying bandwidth rate limiting.
- enum : std::size_t
- {
- rate_seconds = 3
- };
-
- static constexpr time_point never()
- {
- return (time_point::max)();
- }
-
- static std::size_t constexpr no_limit =
- (std::numeric_limits::max)();
-
-// 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
- {
- Executor ex; // must come first
- net::basic_stream_socket<
- Protocol> socket;
- net::steady_timer rate_timer; // rate-limit interval timer
- net::steady_timer read_timer; // for read timeout
- net::steady_timer write_timer; // for write/connect timeout
-
- // VFALCO these could be 32-bit unsigneds
- std::size_t read_limit = no_limit; // read budget
- std::size_t read_remain = no_limit; // read balance
- std::size_t write_limit = no_limit; // write budget
- std::size_t write_remain = no_limit;// write balance
-
- char waiting = 0; // number of waiters on rate timer
- bool read_pending = false; // if read (or connect) is pending
- bool read_closed = false; // if read timed out
- bool write_pending = false; // if write (or connect) is pending
- bool write_closed = false; // if write (or connect) timed out
-
- template
- 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
- void maybe_kick(); // kick the rate timer if needed
- void on_timer(); // rate timer completion
-
- using executor_type = Executor;
- Executor
- get_executor() const noexcept
- {
- return ex;
- }
- };
-#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_;
-
- // Restricted until P1322R0 is incorporated into Boost.Asio.
- static_assert(
- std::is_convertible<
- decltype(std::declval().context()),
- net::io_context&>::value,
- "Only net::io_context is currently supported for executor_type::context()");
-
- template class read_op;
- template class write_op;
-
- template
- friend class detail::stream_socket_connect_op;
-
- template
- friend class basic_stream_socket;
-
- struct read_timeout_handler;
- struct write_timeout_handler;
-
-public:
- /// The type of the next layer.
- using next_layer_type = net::basic_stream_socket;
-
- /// The type of the lowest layer.
- using lowest_layer_type = get_lowest_layer;
-
- /// The type of the executor associated with the object.
- using executor_type = Executor;
-
- /// The protocol type.
- using protocol_type = Protocol;
-
- /// The endpoint type.
- using endpoint_type = typename Protocol::endpoint;
-
- /** Destructor
-
- This function destroys the socket.
-
- @note The behavior of destruction while asynchronous
- operations are outstanding is undefined.
- */
- ~basic_stream_socket();
-
- /** Construct a basic_stream_socket without opening it.
-
- This constructor creates a stream socket without opening it. The
- 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
- ExecutionContext, which the stream socket will use
- to dispatch handlers for any asynchronous operations performed
- on the socket. Currently, the only supported execution context
- which may be passed here is `net::io_context`.
-
- @note This function does not participate in overload resolution unless:
- @li `std::is_convertible::value` is `true`, and
- @li `std::is_constructible::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_stream_socket(ExecutionContext& ctx);
-
- /** Construct a basic_stream_socket without opening it.
-
- This constructor creates a stream socket without opening it. The
- socket needs to be opened and then connected or accepted before
- data can be sent or received on it.
-
- @param ex The executor which the stream socket will use to dispatch
- handlers for any asynchronous operations performed on the socket.
- Currently, only executors that return `net::io_context&` from
- `ex.context()` are supported.
-
- @see http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1322r0.html
- */
- explicit
- basic_stream_socket(executor_type const& ex);
-
- /** Construct and open a basic_stream_socket.
-
- This constructor creates and opens a stream socket. The socket
- needs to be connected or accepted before data can be sent or
- received on it.
-
- @param ctx An object whose type meets the requirements of
- ExecutionContext, which the stream socket will use
- to dispatch handlers for any asynchronous operations performed
- on the socket. Currently, the only supported execution context
- which may be passed here is `net::io_context`.
-
- @param protocol An object specifying protocol parameters to be
- used.
-
- @note This function does not participate in overload resolution unless:
- @li `std::is_convertible::value` is `true`, and
- @li `std::is_constructible::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
- >
- basic_stream_socket(
- ExecutionContext& ctx,
- protocol_type const& protocol);
-
- /** Construct and open a basic_stream_socket.
-
- This constructor creates and opens a stream socket. The socket
- needs to be connected or accepted before data can be sent or
- received on it.
-
- @param ex The executor which the stream socket will use to dispatch
- handlers for any asynchronous operations performed on the socket.
- Currently, only executors that return `net::io_context&` from
- `ex.context()` are supported.
-
- @param protocol An object specifying protocol parameters to be
- used.
-
- @note This function does not participate in overload resolution unless:
- @li `std::is_convertible::value` is `true`, and
- @li `std::is_constructible::value` is `true`.
-
- @see http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1322r0.html
- */
- basic_stream_socket(
- executor_type const& ex,
- protocol_type const& protocol);
-
- /** Construct a basic_stream_socket, opening and binding it to the given local endpoint.
-
- This constructor creates a stream socket and automatically
- opens it bound to the specified endpoint on the local machine.
- The protocol used is the protocol associated with the given
- endpoint.
-
- @param ctx An object whose type meets the requirements of
- ExecutionContext, which the stream socket will use
- to dispatch handlers for any asynchronous operations performed
- on the socket. Currently, the only supported execution context
- which may be passed here is `net::io_context`.
-
- @param endpoint An endpoint on the local machine to which the
- stream socket will be bound.
-
- @note This function does not participate in overload resolution unless:
- @li `std::is_convertible::value` is `true`, and
- @li `std::is_constructible::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
- >
- basic_stream_socket(
- ExecutionContext& ctx,
- endpoint_type const& endpoint);
-
- /** Construct a basic_stream_socket, opening and binding it to the given local endpoint.
-
- This constructor creates a stream socket and automatically
- opens it bound to the specified endpoint on the local machine.
- The protocol used is the protocol associated with the given
- endpoint.
-
- @param ex The executor which the stream socket will use to dispatch
- handlers for any asynchronous operations performed on the socket.
- Currently, only executors that return `net::io_context&` from
- `ex.context()` are supported.
-
- @param endpoint An endpoint on the local machine to which the
- stream socket will be bound.
-
- @note This function does not participate in overload resolution unless:
- @li `std::is_convertible::value` is `true`, and
- @li `std::is_constructible::value` is `true`.
-
- @see http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1322r0.html
- */
- basic_stream_socket(
- executor_type const& ex,
- endpoint_type const& endpoint);
-
- /** Construct a basic_stream_socket, opening and binding it to the given local endpoint.
-
- This constructor creates a stream socket object to from an existing
- next layer object.
-
- @param ctx An object whose type meets the requirements of
- ExecutionContext, which the stream socket will use
- to dispatch handlers for any asynchronous operations performed
- on the socket. Currently, the only supported execution context
- which may be passed here is `net::io_context`.
-
- @param socket The socket object to construct with. Ownership of
- this object is transferred by move.
-
- @note This function does not participate in overload resolution unless:
- @li `std::is_convertible::value` is `true`, and
- @li `std::is_constructible::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
- >
- basic_stream_socket(
- ExecutionContext& ctx,
- next_layer_type&& socket);
-
- /** Construct a basic_stream_socket, opening and binding it to the given local endpoint.
-
- This constructor creates a stream socket object to from an existing
- next layer object.
-
- @param ex The executor which the stream socket will use to dispatch
- handlers for any asynchronous operations performed on the socket.
- Currently, only executors that return `net::io_context&` from
- `ex.context()` are supported.
-
- @param socket The socket object to construct with. Ownership of
- this object is transferred by move.
-
- @note This function does not participate in overload resolution unless:
- @li `std::is_convertible::value` is `true`, and
- @li `std::is_constructible::value` is `true`.
-
- @see http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1322r0.html
- */
- basic_stream_socket(
- executor_type const& ex,
- next_layer_type&& socket);
-
- /** Move-construct a basic_stream_socket from another
-
- This constructor moves a stream socket from one object to another.
-
- The behavior of moving a stream socket while asynchronous operations
- are outstanding is undefined.
-
- @param other The other basic_stream_socket object from which the
- move will occur.
-
- @note Following the move, the moved-from object is in the same state
- as if constructed using the @c basic_stream_socket(ExecutionContext&)
- constructor.
- */
- basic_stream_socket(basic_stream_socket&& other);
-
- /** Move-assign a basic_stream_socket from another.
-
- 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_stream_socket object from which the
- move will occur.
-
- @note Following the move, the moved-from object is in the same state
- as if constructed using the @c basic_stream_socket(ExecutionContext&)
- constructor.
- */
- basic_stream_socket& operator=(basic_stream_socket&& other);
-
- /** Move-construct a basic_stream_socket from a socket of another protocol and executor type.
-
- This constructor moves a stream socket from one object to another.
-
- The behavior of moving a stream socket while asynchronous operations
- are outstanding is undefined.
-
- @param other The other basic_stream_socket object from which the
- move will occur.
-
- @note This constructor does not participate in overload resolution unless:
- @li `std::is_convertible::value` is `true`, and
- @li `std::is_convertible::value` is `true`.
- */
- template<
- class OtherProtocol,
- class OtherExecutor
- #if ! BOOST_BEAST_DOXYGEN
- ,class = typename std::enable_if<
- std::is_convertible<
- OtherProtocol, protocol_type>::value &&
- std::is_convertible<
- OtherExecutor, executor_type>::value>::type
- #endif
- >
- basic_stream_socket(
- basic_stream_socket&& other);
-
- /** Move-assign a basic_stream_socket from a socket of another protocol and executor type.
-
- This assignment operator a stream socket from one object to another.
-
- The behavior of moving a stream socket while asynchronous operations
- are outstanding is undefined.
-
- @param other The other basic_stream_socket object from which the
- move will occur.
-
- @note This constructor does not participate in overload resolution unless:
- @li `std::is_convertible::value` is `true`, and
- @li `std::is_convertible::value` is `true`.
- */
- template<
- class OtherProtocol,
- class OtherExecutor
- #if ! BOOST_BEAST_DOXYGEN
- ,class = typename std::enable_if<
- std::is_convertible<
- OtherProtocol, protocol_type>::value &&
- std::is_convertible<
- OtherExecutor, executor_type>::value>::type
- #endif
- >
- basic_stream_socket& operator=(basic_stream_socket<
- OtherProtocol, OtherExecutor>&& 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 next layer
-
- 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 next layer
-
- 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;
- }
-
- /** Get a reference to the lowest layer
-
- This function returns a reference to the lowest layer
- in a stack of stream layers.
-
- @return A reference to the lowest layer in the stack of
- stream layers.
- */
- lowest_layer_type&
- lowest_layer() noexcept
- {
- return impl_->socket.lowest_layer();
- }
-
- /** Get a reference to the lowest layer
-
- This function returns a reference to the lowest layer
- in a stack of stream layers.
-
- @return A reference to the lowest layer in the stack of
- stream layers. Ownership is not transferred to the caller.
- */
- lowest_layer_type const&
- lowest_layer() const noexcept
- {
- return impl_->socket.lowest_layer();
- }
-
- /** Set the number of bytes allowed to be read per second.
-
- The limit will take effect in the next measured time
- interval (currently set to 3 seconds).
-
- @param bytes_per_second The maximum number of bytes the
- implementation should attempt to read per second. A value
- of zero indicates no limit.
- */
- void
- read_limit(std::size_t bytes_per_second);
-
- /** Set the number of bytes allowed to be written per second.
-
- The limit will take effect in the next measured time
- interval (currently set to 3 seconds).
-
- @param bytes_per_second The maximum number of bytes the
- implementation should attempt to write per second. A value
- of zero indicates no limit.
- */
- void
- write_limit(std::size_t bytes_per_second);
-
- /** 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();
-
- /** 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()
- {
- impl_->close();
- }
-
- //--------------------------------------------------------------------------
-
- /** Start an asynchronous read.
-
- This function is used to asynchronously read data from the stream socket.
- The function call always returns immediately.
-
- @param buffers One or more buffers into which the data will be read.
- 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 read operation completes.
- Copies will be made of the handler as required. The function signature of
- the handler must be:
- @code
- void handler(
- error_code const & 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::io_context::post()`.
- */
- template
- 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 socket.
- The function call always returns immediately.
-
- @param buffers One or more data buffers to be written to the socket.
- 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 write operation completes.
- Copies will be made of the handler as required. The function signature of
- the handler must be:
- @code
- void handler(
- error_code const & 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::io_context::post()`.
- */
- template
- BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler,
- void(error_code, std::size_t))
- async_write_some(
- ConstBufferSequence const& buffers,
- WriteHandler&& handler);
-};
-
-//------------------------------------------------------------------------------
-
-/**
- @defgroup async_connect boost::beast::async_connect
- @brief Asynchronously establishes a socket connection by trying each
- endpoint in a sequence, and terminating if a timeout occurs.
-*/
-/* @{ */
-/** 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 s The @ref beast::basic_stream_socket to be connected. If the socket
- is already open, it will be closed.
-
- @param endpoints 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, 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
- @code
- net::tcp::resolver r(ioc);
- net::tcp::resolver::query q("host", "service");
- timed_stream s(ioc.get_executor());
-
- // ...
- r.async_resolve(q, resolve_handler);
-
- // ...
-
- void resolve_handler(
- error_code const& ec,
- tcp::resolver::results_type results)
- {
- if (!ec)
- {
- async_connect(s, results, connect_handler);
- }
- }
-
- // ...
- void connect_handler(
- error_code const& ec,
- tcp::endpoint const& endpoint)
- {
- // ...
- }
- @endcode
-*/
-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_stream_socket& s,
- 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 s The @ref beast::basic_stream_socket to be connected. If the socket
- is already open, it will be closed.
-
- @param endpoints 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,
- 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
- It would be used with the @ref boost::beast::async_connect
- function as follows:
- @code
- net::tcp::resolver r(ioc);
- net::tcp::resolver::query q("host", "service");
- timed_stream s(ioc.get_executor());
-
- // ...
- r.async_resolve(q, resolve_handler);
-
- // ...
-
- void resolve_handler(
- error_code const& ec,
- tcp::resolver::results_type results)
- {
- if (!ec)
- {
- async_connect(s, results, my_connect_condition{}, connect_handler);
- }
- }
-
- // ...
- void connect_handler(
- error_code const& ec,
- tcp::endpoint const& endpoint)
- {
- // ...
- }
- @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_stream_socket& s,
- 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 s The @ref beast::basic_stream_socket to be connected. If the 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()`.
-
- @par Example
- @code
- std::vector endpoints = ...;
- timed_stream s(ioc.get_executor());
-
- async_connect(s,
- endpoints.begin(), endpoints.end(),
- connect_handler);
- void connect_handler(
- error_code const& ec,
- std::vector::iterator)
- {
- // ...
- }
- @endcode
-*/
-template<
- class Protocol, class Executor,
- class Iterator,
- class IteratorConnectHandler>
-BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler,
- void (error_code, Iterator))
-async_connect(
- basic_stream_socket& s,
- 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 s The @ref beast::basic_stream_socket to be connected. If the 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()`.
-
- @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
- It would be used with the @ref boost::beast::async_connect
- function as follows:
- @code
- std::vector endpoints = ...;
- timed_stream s(ioc.get_executor());
-
- async_connect(s, endpoints.begin(), endpoints.end(),
- my_connect_condition{}, connect_handler);
- void connect_handler(
- error_code const& ec,
- std::vector::iterator)
- {
- // ...
- }
- @endcode
-*/
-template<
- class Protocol, class Executor,
- class Iterator,
- class ConnectCondition,
- class IteratorConnectHandler>
-BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler,
- void (error_code, Iterator))
-async_connect(
- basic_stream_socket& s,
- Iterator begin, Iterator end,
- ConnectCondition connect_condition,
- IteratorConnectHandler&& handler);
-/* @} */
-
-} // beast
-} // boost
-
-#include
-
-#endif
diff --git a/include/boost/beast/core/basic_timeout_stream.hpp b/include/boost/beast/core/basic_timeout_stream.hpp
new file mode 100644
index 00000000..6084eafb
--- /dev/null
+++ b/include/boost/beast/core/basic_timeout_stream.hpp
@@ -0,0 +1,844 @@
+//
+// 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
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+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
+ "Networking TS enhancement to enable custom I/O executors"
+ (P1322R0).
+
+ 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 DefaultConstructible).
+ Regardless of the method chosen, the executor used with the stream must
+ provide the following guarantees:
+
+ @li Ordering:
+ Function objects submitted to the executor from the same thread shall
+ execute in the order they were submitted.
+
+ @li Concurrency:
+ 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 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 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 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 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& 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 Protocol
+ 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 Executor 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
+ Distinct objects: Safe.@n
+ Shared objects: Unsafe. The application must also ensure
+ that all asynchronous operations are performed within the same
+ implicit or explicit strand.
+
+ @see "Networking TS enhancement to enable custom I/O executors"
+ (P1322R0).
+*/
+template<
+ class Protocol,
+ class Executor = typename
+ net::basic_stream_socket::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::max)();
+
+ struct op_state
+ {
+ net::steady_timer timer; // for timing out
+ bool pending = false; // if op is pending
+ bool closed = 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
+ {
+ Executor ex; // must come first
+ op_state read;
+ op_state write;
+
+ net::basic_stream_socket socket;
+
+ template
+ 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_;
+
+ // Restricted until P1322R0 is incorporated into Boost.Asio.
+ static_assert(
+ std::is_convertible<
+ decltype(std::declval().context()),
+ net::io_context&>::value,
+ "Only net::io_context is currently supported for executor_type::context()");
+
+ template class async_op;
+
+ template
+ friend class detail::timeout_stream_connect_op;
+
+ template
+ 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;
+
+ /// 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
+ ExecutionContext, 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::value` is `true`, and
+ @li `std::is_constructible::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&& 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&& 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
+ 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
+ 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
+ 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 EndpointSequence.
+
+ @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& 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 EndpointSequence.
+
+ @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& 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& 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& stream,
+ Iterator begin, Iterator end,
+ ConnectCondition connect_condition,
+ IteratorConnectHandler&& handler);
+
+} // beast
+} // boost
+
+#include
+
+#endif
diff --git a/include/boost/beast/core/detail/stream_socket_base.hpp b/include/boost/beast/core/detail/timeout_stream_base.hpp
similarity index 67%
rename from include/boost/beast/core/detail/stream_socket_base.hpp
rename to include/boost/beast/core/detail/timeout_stream_base.hpp
index 5ee9df2f..9e2b22d2 100644
--- a/include/boost/beast/core/detail/stream_socket_base.hpp
+++ b/include/boost/beast/core/detail/timeout_stream_base.hpp
@@ -7,8 +7,8 @@
// Official repository: https://github.com/boostorg/beast
//
-#ifndef BOOST_BEAST_CORE_DETAIL_STREAM_SOCKET_BASE_HPP
-#define BOOST_BEAST_CORE_DETAIL_STREAM_SOCKET_BASE_HPP
+#ifndef BOOST_BEAST_CORE_DETAIL_TIMEOUT_STREAM_BASE_HPP
+#define BOOST_BEAST_CORE_DETAIL_TIMEOUT_STREAM_BASE_HPP
#include
#include
@@ -18,9 +18,20 @@ namespace beast {
namespace detail {
template
-class stream_socket_connect_op;
+class timeout_stream_connect_op;
-class stream_socket_base
+struct any_endpoint
+{
+ template
+ bool
+ operator()(
+ Error const&, Endpoint const&) const noexcept
+ {
+ return true;
+ }
+};
+
+class timeout_stream_base
{
protected:
class pending_guard
@@ -43,9 +54,11 @@ protected:
b_ = true;
}
- pending_guard(pending_guard&& other) noexcept
+ pending_guard(
+ pending_guard&& other) noexcept
: b_(other.b_)
- , clear_(boost::exchange(other.clear_, false))
+ , clear_(boost::exchange(
+ other.clear_, false))
{
}
diff --git a/include/boost/beast/core/impl/basic_stream_socket.hpp b/include/boost/beast/core/impl/basic_stream_socket.hpp
deleted file mode 100644
index 806de4bd..00000000
--- a/include/boost/beast/core/impl/basic_stream_socket.hpp
+++ /dev/null
@@ -1,1024 +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_IMPL_BASIC_STREAM_SOCKET_HPP
-#define BOOST_BEAST_CORE_IMPL_BASIC_STREAM_SOCKET_HPP
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-namespace boost {
-namespace beast {
-
-template
-struct basic_stream_socket<
- Protocol, Executor>::read_timeout_handler
-{
- std::shared_ptr impl;
-
- void
- operator()(error_code ec)
- {
- // timer canceled
- if(ec == net::error::operation_aborted)
- return;
-
- BOOST_ASSERT(! ec);
-
- if(! impl->read_closed)
- {
- // timeout
- impl->close();
- impl->read_closed = true;
- }
- else
- {
- // late completion
- impl->read_closed = false;
- }
- }
-};
-
-template
-struct basic_stream_socket<
- Protocol, Executor>::write_timeout_handler
-{
- std::shared_ptr impl;
-
- void
- operator()(error_code ec)
- {
- // timer canceled
- if(ec == net::error::operation_aborted)
- return;
-
- BOOST_ASSERT(! ec);
-
- if(! impl->write_closed)
- {
- // timeout
- impl->close();
- impl->write_closed = true;
- }
- else
- {
- // late completion
- impl->write_closed = false;
- }
- }
-};
-
-/*
- The algorithm for implementing the timeout depends
- on the executor providing ordered execution guarantee.
- `net::strand` automatically provides this, and we assume
- that an implicit strand (one thread calling io_context::run)
- also provides this.
-*/
-
-template
-template
-class basic_stream_socket::read_op
- : public async_op_base
- , public boost::asio::coroutine
-{
- typename basic_stream_socket<
- Protocol, Executor>::impl_type& impl_;
- pending_guard pg_;
- Buffers b_;
-
-public:
- template
- read_op(
- basic_stream_socket& s,
- Buffers const& b,
- Handler_&& h)
- : async_op_base(
- std::forward(h), s.get_executor())
- , impl_(*s.impl_)
- , pg_(impl_.read_pending)
- , b_(b)
- {
- (*this)({});
- }
-
- void
- operator()(
- error_code ec,
- std::size_t bytes_transferred = 0)
- {
- BOOST_ASIO_CORO_REENTER(*this)
- {
- // must come first
- // VFALCO TODO what about the handler's allocator?
- impl_.read_timer.async_wait(
- net::bind_executor(
- this->get_executor(),
- read_timeout_handler{
- impl_.shared_from_this()}));
-
- impl_.maybe_kick();
-
- // check if the balance is zero
- if(impl_.read_remain == 0)
- {
- // wait until the next time slice
- ++impl_.waiting;
- BOOST_ASIO_CORO_YIELD
- impl_.rate_timer.async_wait(std::move(*this));
-
- if(ec)
- {
- // caused by impl::close on timeout
- BOOST_ASSERT(
- ec == net::error::operation_aborted);
- goto upcall;
- }
-
- // must call this
- impl_.on_timer();
- BOOST_ASSERT(impl_.read_remain > 0);
- }
-
- // we always use buffers_prefix,
- // to reduce template instantiations.
- BOOST_ASSERT(impl_.read_remain > 0);
- BOOST_ASIO_CORO_YIELD
- impl_.socket.async_read_some(
- beast::buffers_prefix(
- impl_.read_remain, b_),
- std::move(*this));
-
- if(impl_.read_remain != no_limit)
- {
- // adjust balance
- BOOST_ASSERT(
- bytes_transferred <= impl_.read_remain);
- impl_.read_remain -= bytes_transferred;
- }
-
- {
- // try cancelling timer
- auto const n =
- impl_.read_timer.cancel();
-
- if(impl_.read_closed)
- {
- // timeout handler already invoked
- BOOST_ASSERT(n == 0);
- ec = beast::error::timeout;
- impl_.read_closed = false;
- }
- else if(n == 0)
- {
- // timeout handler already queued
- ec = beast::error::timeout;
-
- impl_.close();
- impl_.read_closed = true;
- }
- else
- {
- // timeout was canceled
- BOOST_ASSERT(n == 1);
- }
- }
-
- upcall:
- pg_.reset();
- this->invoke(ec, bytes_transferred);
- }
- }
-};
-
-//------------------------------------------------------------------------------
-
-template
-template
-class basic_stream_socket::write_op
- : public async_op_base
- , public boost::asio::coroutine
-{
- typename basic_stream_socket<
- Protocol, Executor>::impl_type& impl_;
- pending_guard pg_;
- Buffers b_;
-
-public:
- template
- write_op(
- basic_stream_socket& s,
- Buffers const& b,
- Handler_&& h)
- : async_op_base(
- std::forward(h), s.get_executor())
- , impl_(*s.impl_)
- , pg_(impl_.write_pending)
- , b_(b)
- {
- (*this)();
- }
-
- void
- operator()(
- error_code ec = {},
- std::size_t bytes_transferred = 0)
- {
- BOOST_ASIO_CORO_REENTER(*this)
- {
- // must come first
- // VFALCO TODO what about the handler's allocator?
- impl_.write_timer.async_wait(
- net::bind_executor(
- this->get_executor(),
- write_timeout_handler{
- impl_.shared_from_this()}));
-
- impl_.maybe_kick();
-
- // check if the balance is zero
- if(impl_.write_remain == 0)
- {
- // wait until the next time slice
- ++impl_.waiting;
- BOOST_ASIO_CORO_YIELD
- impl_.rate_timer.async_wait(std::move(*this));
-
- if(ec)
- {
- // caused by impl::close on timeout
- BOOST_ASSERT(
- ec == net::error::operation_aborted);
- goto upcall;
- }
-
- // must call this
- impl_.on_timer();
- BOOST_ASSERT(impl_.write_remain > 0);
- }
-
- // we always use buffers_prefix,
- // to reduce template instantiations.
- BOOST_ASSERT(impl_.write_remain > 0);
- BOOST_ASIO_CORO_YIELD
- impl_.socket.async_write_some(
- beast::buffers_prefix(
- impl_.write_remain, b_),
- std::move(*this));
-
- if(impl_.write_remain != no_limit)
- {
- // adjust balance
- BOOST_ASSERT(
- bytes_transferred <= impl_.write_remain);
- impl_.write_remain -= bytes_transferred;
- }
-
- {
- // try cancelling timer
- auto const n =
- impl_.write_timer.cancel();
-
- if(impl_.write_closed)
- {
- // timeout handler already invoked
- BOOST_ASSERT(n == 0);
- ec = beast::error::timeout;
- impl_.write_closed = false;
- }
- else if(n == 0)
- {
- // timeout handler already queued
- ec = beast::error::timeout;
-
- impl_.close();
- impl_.write_closed = true;
- }
- else
- {
- // timeout was canceled
- BOOST_ASSERT(n == 1);
- }
- }
-
- upcall:
- pg_.reset();
- this->invoke(ec, bytes_transferred);
- }
- }
-};
-
-//------------------------------------------------------------------------------
-
-namespace detail {
-
-template<
- class Protocol, class Executor, class Handler>
-class stream_socket_connect_op
- : public async_op_base
-{
- using stream_type =
- beast::basic_stream_socket;
- using timeout_handler =
- typename stream_type::write_timeout_handler;
-
- typename basic_stream_socket<
- Protocol, Executor>::impl_type& impl_;
- typename stream_type::pending_guard pg0_;
- typename stream_type::pending_guard pg1_;
-
-public:
- template<
- class Endpoints, class Condition,
- class Handler_>
- stream_socket_connect_op(
- stream_type& s,
- Endpoints const& eps,
- Condition cond,
- Handler_&& h)
- : async_op_base(
- std::forward(h), s.get_executor())
- , impl_(*s.impl_)
- , pg0_(impl_.read_pending)
- , pg1_(impl_.write_pending)
- {
- // must come first
- // VFALCO TODO what about the handler's allocator?
- impl_.write_timer.async_wait(
- net::bind_executor(
- this->get_executor(),
- timeout_handler{
- impl_.shared_from_this()}));
-
- net::async_connect(impl_.socket,
- eps, cond, std::move(*this));
- // *this is now moved-from
- }
-
- template<
- class Iterator, class Condition,
- class Handler_>
- stream_socket_connect_op(
- stream_type& s,
- Iterator begin, Iterator end,
- Condition cond,
- Handler_&& h)
- : async_op_base(
- std::forward(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{
- impl_.shared_from_this()}));
-
- net::async_connect(impl_.socket,
- begin, end, cond, std::move(*this));
- // *this is now moved-from
- }
-
- template
- void
- operator()(error_code ec, Arg&& arg)
- {
- // try to cancel the timer
- auto const n =
- impl_.write_timer.cancel();
-
- if(impl_.write_closed)
- {
- // timeout handler already invoked
- BOOST_ASSERT(n == 0);
- ec = beast::error::timeout;
- impl_.write_closed = false;
- }
- else if(n == 0)
- {
- // timeout handler already queued
- ec = beast::error::timeout;
-
- impl_.close();
- impl_.write_closed = true;
- }
- else
- {
- // timeout was canceled
- BOOST_ASSERT(n == 1);
- }
-
- pg0_.reset();
- pg1_.reset();
- this->invoke(ec, std::forward(arg));
- }
-};
-
-} // detail
-
-//------------------------------------------------------------------------------
-
-template
-template
-basic_stream_socket::
-impl_type::
-impl_type(
- Executor const& ex_,
- Args&&... args)
- : ex(ex_)
- , socket(std::forward(args)...)
- , rate_timer(ex.context())
- , read_timer(ex.context())
- , write_timer(ex.context())
-{
- reset();
-}
-
-template
-auto
-basic_stream_socket::
-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);
- rate_timer = std::move(other.rate_timer);
- read_timer = std::move(other.read_timer);
- write_timer = std::move(other.write_timer);
-
- read_limit = other.read_limit;
- read_remain = other.read_remain;
- write_limit = other.write_limit;
- write_remain = other.write_remain;
-
- waiting = other.waiting;
- read_pending = other.read_pending;
- read_closed = other.read_closed;
- write_pending = other.write_pending;
- write_closed = other.write_closed;
-
- return *this;
-}
-
-template
-void
-basic_stream_socket::
-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
-void
-basic_stream_socket::
-impl_type::
-close()
-{
- socket.close();
- rate_timer.cancel();
- read_timer.cancel();
- write_timer.cancel();
-}
-
-template
-void
-basic_stream_socket::
-impl_type::
-maybe_kick()
-{
- // see if the timer needs a kick
- if(waiting > 0)
- {
- BOOST_ASSERT(
- rate_timer.expiry() != never());
- return;
- }
-
- // are both limits disabled?
- if( read_limit == no_limit &&
- write_limit == no_limit)
- return;
-
- BOOST_ASSERT(
- read_pending || write_pending);
-
- // update budget
- read_remain = read_limit;
- write_remain = write_limit;
-
- // start the clock
- ++waiting;
- on_timer();
-}
-
-template
-void
-basic_stream_socket::
-impl_type::
-on_timer()
-{
- BOOST_ASSERT(waiting > 0);
-
- // the last waiter starts the new slice
- if(--waiting > 0)
- return;
-
- // update the expiration time
- BOOST_VERIFY(rate_timer.expires_after(
- std::chrono::seconds(rate_seconds)) == 0);
-
- // update budget
- read_remain = read_limit;
- write_remain = write_limit;
-
- // wait again
- ++waiting;
- auto const this_ = this->shared_from_this();
- rate_timer.async_wait(
- net::bind_executor(ex,
- [this_](error_code ec)
- {
- if(ec == net::error::operation_aborted)
- return;
- BOOST_ASSERT(! ec);
- if(ec)
- return;
- this_->on_timer();
- }
- ));
-}
-
-//------------------------------------------------------------------------------
-
-template
-basic_stream_socket::
-~basic_stream_socket()
-{
- // the shared object can outlive *this,
- // cancel any operations so the shared
- // object is destroyed as soon as possible.
- impl_->close();
-}
-
-template
-template
-basic_stream_socket::
-basic_stream_socket(ExecutionContext& ctx)
- : impl_(std::make_shared(
- ctx.get_executor(),
- ctx))
-{
- static_assert(
- std::is_same::value,
- "Only net::io_context is currently supported for ExecutionContext");
-}
-
-template
-basic_stream_socket::
-basic_stream_socket(executor_type const& ex)
- : impl_(std::make_shared(
- ex,
- ex.context()))
-{
-}
-
-template
-template
-basic_stream_socket::
-basic_stream_socket(
- ExecutionContext& ctx,
- protocol_type const& protocol)
- : impl_(std::make_shared(
- ctx.get_executor(),
- ctx,
- protocol))
-{
- static_assert(
- std::is_same::value,
- "Only net::io_context is currently supported for ExecutionContext");
-}
-
-template
-basic_stream_socket::
-basic_stream_socket(
- executor_type const& ex,
- protocol_type const& protocol)
- : impl_(std::make_shared(
- ex,
- ex.context(),
- protocol))
-{
-}
-
-template
-template
-basic_stream_socket::
-basic_stream_socket(
- ExecutionContext& ctx,
- endpoint_type const& endpoint)
- : impl_(std::make_shared(
- ctx.get_executor(),
- ctx,
- endpoint))
-{
- static_assert(
- std::is_same::value,
- "Only net::io_context is currently supported for ExecutionContext");
-}
-
-template
-basic_stream_socket::
-basic_stream_socket(
- executor_type const& ex,
- endpoint_type const& endpoint)
- : impl_(std::make_shared(
- ex,
- ex.context(),
- endpoint))
-{
-}
-
-template
-template
-basic_stream_socket::
-basic_stream_socket(
- ExecutionContext& ctx,
- next_layer_type&& socket)
- : impl_(std::make_shared(
- ctx.get_executor(),
- std::move(socket)))
-{
- static_assert(
- std::is_same::value,
- "Only net::io_context is currently supported for ExecutionContext");
-}
-
-template
-basic_stream_socket::
-basic_stream_socket(
- executor_type const& ex,
- next_layer_type&& socket)
- : impl_(std::make_shared(
- ex,
- std::move(socket)))
-{
-}
-
-template
-basic_stream_socket::
-basic_stream_socket(basic_stream_socket&& other)
- : impl_(std::make_shared(
- std::move(*other.impl_)))
-{
- // Can't move while operations are pending!
- BOOST_ASSERT(! impl_->read_pending);
- BOOST_ASSERT(! impl_->write_pending);
-}
-
-template
-auto
-basic_stream_socket::
-operator=(basic_stream_socket&& other) ->
- basic_stream_socket&
-{
- // 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
-template
-basic_stream_socket::
-basic_stream_socket(
- basic_stream_socket&& other)
- : impl_(std::make_shared(
- other.get_executor(),
- std::move(other.impl_->socket)))
-{
- static_assert(std::is_same<
- net::io_context,
- typename std::decay::type>::value,
- "Only net::io_context& is currently supported for other.get_executor().context()");
-}
-
-template
-template
-auto
-basic_stream_socket::
-operator=(
- basic_stream_socket&& other) ->
- basic_stream_socket&
-{
- static_assert(std::is_same<
- net::io_context,
- typename std::decay::type>::value,
- "Only net::io_context& is currently supported for other.get_executor().context()");
-
- // 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::make_shared(
- other.get_executor(),
- std::move(other.impl_->socket));
- return *this;
-}
-
-//------------------------------------------------------------------------------
-
-template
-void
-basic_stream_socket::
-read_limit(std::size_t bytes_per_second)
-{
- if(bytes_per_second == 0)
- {
- impl_->read_limit = no_limit;
- }
- else if(bytes_per_second < no_limit)
- {
- impl_->read_limit =
- bytes_per_second * rate_seconds;
- }
- else
- {
- impl_->read_limit = no_limit - 1;
- }
- BOOST_ASSERT(impl_->read_limit > 0);
-}
-
-template
-void
-basic_stream_socket::
-write_limit(std::size_t bytes_per_second)
-{
- if(bytes_per_second == 0)
- {
- impl_->write_limit = no_limit;
- }
- else if(bytes_per_second < no_limit)
- {
- impl_->write_limit =
- bytes_per_second * rate_seconds;
- }
- else
- {
- impl_->write_limit = no_limit - 1;
- }
- BOOST_ASSERT(impl_->write_limit > 0);
-}
-
-template
-void
-basic_stream_socket::
-expires_after(std::chrono::nanoseconds expiry_time)
-{
- // 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(
- ! impl_->read_pending ||
- ! impl_->write_pending);
-
- if(! impl_->read_pending)
- BOOST_VERIFY(
- impl_->read_timer.expires_after(
- expiry_time) == 0);
-
- if(! impl_->write_pending)
- BOOST_VERIFY(
- impl_->write_timer.expires_after(
- expiry_time) == 0);
-}
-
-template
-void
-basic_stream_socket::
-expires_at(
- net::steady_timer::time_point expiry_time)
-{
- // 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(
- ! impl_->read_pending ||
- ! impl_->write_pending);
-
- if(! impl_->read_pending)
- BOOST_VERIFY(
- impl_->read_timer.expires_at(
- expiry_time) == 0);
-
- if(! impl_->write_pending)
- BOOST_VERIFY(
- impl_->write_timer.expires_at(
- expiry_time) == 0);
-}
-
-template
-void
-basic_stream_socket::
-expires_never()
-{
- impl_->reset();
-}
-
-template
-template
-BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
- void(error_code, std::size_t))
-basic_stream_socket::
-async_read_some(
- MutableBufferSequence const& buffers,
- ReadHandler&& handler)
-{
- static_assert(net::is_mutable_buffer_sequence<
- MutableBufferSequence>::value,
- "MutableBufferSequence requirements not met");
- BOOST_BEAST_HANDLER_INIT(
- ReadHandler, void(error_code, std::size_t));
- read_op(
- *this, buffers, std::forward(handler));
- return init.result.get();
-}
-
-template
-template
-BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler,
- void(error_code, std::size_t))
-basic_stream_socket::
-async_write_some(
- ConstBufferSequence const& buffers,
- WriteHandler&& handler)
-{
- static_assert(net::is_const_buffer_sequence<
- ConstBufferSequence>::value,
- "ConstBufferSequence requirements not met");
- BOOST_BEAST_HANDLER_INIT(
- WriteHandler, void(error_code, std::size_t));
- write_op(
- *this, buffers, std::forward(handler));
- return init.result.get();
-}
-
-//------------------------------------------------------------------------------
-
-namespace detail {
-
-struct any_endpoint
-{
- template
- bool
- operator()(
- Error const&, Endpoint const&) const noexcept
- {
- return true;
- }
-};
-
-} // detail
-
-template<
- class Protocol, class Executor,
- class EndpointSequence,
- class RangeConnectHandler,
- class>
-BOOST_ASIO_INITFN_RESULT_TYPE(RangeConnectHandler,
- void(error_code, typename Protocol::endpoint))
-async_connect(
- basic_stream_socket& s,
- EndpointSequence const& endpoints,
- RangeConnectHandler&& handler)
-{
- BOOST_BEAST_HANDLER_INIT(RangeConnectHandler,
- void(error_code, typename Protocol::endpoint));
- detail::stream_socket_connect_op(
- s, endpoints, detail::any_endpoint{},
- std::forward(handler));
- return init.result.get();
-}
-
-template<
- class Protocol, class Executor,
- class EndpointSequence,
- class ConnectCondition,
- class RangeConnectHandler,
- class>
-BOOST_ASIO_INITFN_RESULT_TYPE(RangeConnectHandler,
- void (error_code, typename Protocol::endpoint))
-async_connect(
- basic_stream_socket& s,
- EndpointSequence const& endpoints,
- ConnectCondition connect_condition,
- RangeConnectHandler&& handler)
-{
- BOOST_BEAST_HANDLER_INIT(RangeConnectHandler,
- void(error_code, typename Protocol::endpoint));
- detail::stream_socket_connect_op(
- s, endpoints, connect_condition,
- std::forward(handler));
- return init.result.get();
-}
-
-template<
- class Protocol, class Executor,
- class Iterator,
- class IteratorConnectHandler>
-BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler,
- void (error_code, Iterator))
-async_connect(
- basic_stream_socket& s,
- Iterator begin, Iterator end,
- IteratorConnectHandler&& handler)
-{
- BOOST_BEAST_HANDLER_INIT(IteratorConnectHandler,
- void(error_code, Iterator));
- detail::stream_socket_connect_op(
- s, begin, end, detail::any_endpoint{},
- std::forward(handler));
- return init.result.get();
-}
-
-template<
- class Protocol, class Executor,
- class Iterator,
- class ConnectCondition,
- class IteratorConnectHandler>
-BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler,
- void (error_code, Iterator))
-async_connect(
- basic_stream_socket& s,
- Iterator begin, Iterator end,
- ConnectCondition connect_condition,
- IteratorConnectHandler&& handler)
-{
- BOOST_BEAST_HANDLER_INIT(IteratorConnectHandler,
- void(error_code, Iterator));
- detail::stream_socket_connect_op(
- s, begin, end, connect_condition,
- std::forward(handler));
- return init.result.get();
-}
-
-} // beast
-} // boost
-
-#endif
diff --git a/include/boost/beast/core/impl/basic_timeout_stream.hpp b/include/boost/beast/core/impl/basic_timeout_stream.hpp
new file mode 100644
index 00000000..e7028b92
--- /dev/null
+++ b/include/boost/beast/core/impl/basic_timeout_stream.hpp
@@ -0,0 +1,699 @@
+//
+// 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_IMPL_BASIC_TIMEOUT_STREAM_HPP
+#define BOOST_BEAST_CORE_IMPL_BASIC_TIMEOUT_STREAM_HPP
+
+#include
+#include
+#include
+#include