diff --git a/CHANGELOG.md b/CHANGELOG.md
index 03e9184b..0f029729 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,7 @@
Version 213:
* Fix posix_file::close handling of EINTR
+* basic_stream subsumes stranded_stream:
--------------------------------------------------------------------------------
diff --git a/doc/qbk/03_core/3_layers.qbk b/doc/qbk/03_core/3_layers.qbk
index 7bac24f8..67922c01 100644
--- a/doc/qbk/03_core/3_layers.qbk
+++ b/doc/qbk/03_core/3_layers.qbk
@@ -46,12 +46,15 @@ facilities for authoring and working with layered streams:
[table Layered Stream Algorithms and Types
[[Name][Description]]
[[
- [link beast.ref.boost__beast__timeout_stream `timeout_stream`]
- [link beast.ref.boost__beast__basic_timeout_stream `basic_timeout_stream`]
+ [link beast.ref.boost__beast__basic_stream `basic_stream`]
+ [link beast.ref.boost__beast__tcp_stream `tcp_stream`]
][
- A timeout stream meets the requirements for synchronous and asynchronous
- read and write streams, and additionally provides configurable timeouts
- for logical operations that include reading, writing, and/or connecting.
+ This stream can be used for synchronous and asynchronous reading
+ and writing. It allows timeouts to be set on logical operations,
+ and can have an executor associated with the stream which is
+ used to invoke completion handlers. This lets you set a strand
+ on the stream once, which is then used for all asynchronous
+ operations automatically.
]]
[[
[link beast.ref.boost__beast__buffered_read_stream `buffered_read_stream`]
@@ -109,16 +112,6 @@ facilities for authoring and working with layered streams:
allows for move-construction and move-assignment, and also implements
a work-around for a performance limitation in the original SSL stream.
]]
-[[
- [link beast.ref.boost__beast__stranded_socket `stranded_socket`]
-][
- A timeout stream meets the requirements for synchronous and asynchronous
- read and write streams by passing I/O through to an underlying
- `net::basic_stream_socket`, and additionally supports
- [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1322r0.html [P1322R0] "Networking TS enhancement to enable custom I/O executors"],
- allowing a custom executor (such a strand) to be used for all
- asynchronous operations.
-]]
]
[heading Example]
diff --git a/doc/qbk/quickref.xml b/doc/qbk/quickref.xml
index 88d63bf4..4b963b3e 100644
--- a/doc/qbk/quickref.xml
+++ b/doc/qbk/quickref.xml
@@ -24,7 +24,7 @@
Classes (1 of 2)async_op_base 🞲
- basic_timeout_stream 🞲
+ basic_stream 🞲filefile_modefile_posix
@@ -46,10 +46,9 @@
spanstatic_stringstable_async_op_base 🞲
- stranded_socket 🞲string_paramstring_view
- timeout_stream 🞲
+ tcp_stream 🞲Constants
diff --git a/doc/qbk/release_notes.qbk b/doc/qbk/release_notes.qbk
index 4bdcbbad..1a9910d0 100644
--- a/doc/qbk/release_notes.qbk
+++ b/doc/qbk/release_notes.qbk
@@ -14,14 +14,19 @@
[heading Boost 1.70]
[/ includes up to version 209]
[/
+* Use `beast::tcp_socket` instead of `boost::asio::ip::tcp::socket`!
+* subscribe to this GitHub issue to be informed!
+* we need testers!
+* star the repo!
+
Exposition:
Enlarged scope
-New quality of life features:
- timed stream
+- `net` is a namespace alias for `boost::asio`
+- New quality of life features:
+ tcp_socket
async_op_base, stable_async_op_base
-New Networking refresher
-New websocket-chat-multi example
-* `net` is a namespace alias for `boost::asio`
+- New Networking refresher
+- New websocket-chat-multi example
]
[tip
diff --git a/include/boost/beast/core.hpp b/include/boost/beast/core.hpp
index f24800cb..e286690a 100644
--- a/include/boost/beast/core.hpp
+++ b/include/boost/beast/core.hpp
@@ -12,7 +12,7 @@
#include
-#include
+#include
#include
#include
#include
@@ -41,10 +41,9 @@
#include
#include
#include
-#include
#include
#include
#include
-#include
+#include
#endif
diff --git a/include/boost/beast/core/basic_stream.hpp b/include/boost/beast/core/basic_stream.hpp
new file mode 100644
index 00000000..03019be9
--- /dev/null
+++ b/include/boost/beast/core/basic_stream.hpp
@@ -0,0 +1,1464 @@
+//
+// 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_HPP
+#define BOOST_BEAST_CORE_BASIC_STREAM_HPP
+
+#include
+#include
+#include
+#include // VFALCO This is unfortunate
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace boost {
+namespace asio {
+namespace ssl {
+template class stream;
+} // ssl
+} // asio
+} // boost
+
+namespace boost {
+namespace beast {
+
+//------------------------------------------------------------------------------
+
+/** A stream socket wrapper with timeouts and associated executor.
+
+ This stream wraps a `net::basic_stream_socket` to provide
+ the following additional features:
+
+ @li Optional timeouts may be specified for each logical asynchronous
+ operation performing any reading, writing, or connecting.
+
+ @li An Executor may be associated with the stream, which will
+ be used to invoke any completion handlers which do not already have
+ an associated executor. This achieves partial support for
+ [P1322R0] Networking TS enhancement to enable custom I/O executors.
+
+ Although the stream supports multiple concurrent outstanding asynchronous
+ operations, the stream object 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, are
+ accessed by the networking implementation. To meet this thread safety
+ requirement, all asynchronous operations must be performed by the stream
+ within the same implicit strand (only one thread `net::io_context::run`)
+ or within the same explicit strand, such as an instance of `net::strand`.
+
+ Completion handlers with explicit associated executors (such as those
+ arising from use of `net::bind_executor`) will be invoked by the stream
+ using the associated executor. Otherwise, the completion handler will
+ be invoked by the executor associated with the stream upon construction.
+ The type of executor used with this stream must meet the following
+ requirements:
+
+ @li 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.
+
+ Unlike other stream wrappers, the underlying socket is accessed
+ through the @ref socket member function instead of `next_layer`.
+ This causes the @ref basic_stream to be returned in calls
+ to @ref get_lowest_layer.
+
+ @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 asynchronous read, asynchronous write, or asynchronous 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 (tcp_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 (tcp_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
+
+ @par Blocking I/O
+
+ Synchronous functions behave identically as that of the wrapped
+ `net::basic_stream_socket`. Timeouts are not available when performing
+ blocking calls.
+
+ @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.
+
+ @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
+
+ @li @ref beast::connect, @ref beast::async_connect
+
+ @li [P1322R0] Networking TS enhancement to enable custom I/O executors.
+*/
+template
+class basic_stream
+#if ! BOOST_BEAST_DOXYGEN
+ : private detail::stream_base
+#endif
+{
+// 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
+ , boost::empty_value
+ {
+ op_state read;
+ op_state write;
+
+ net::basic_stream_socket socket;
+
+ impl_type(impl_type&&) = default;
+
+ template
+ explicit
+ impl_type(Executor const&, Args&&...);
+
+ template
+ impl_type(net::basic_stream_socket&& socket_,
+ std::true_type);
+
+ template
+ impl_type(net::basic_stream_socket&& socket_,
+ std::false_type);
+
+ impl_type& operator=(impl_type&&) = delete;
+
+ Executor const&
+ ex() const noexcept
+ {
+ return this->get();
+ }
+
+ 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 a 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::basic_stream_connect_op;
+
+ template
+ friend class basic_stream;
+
+ struct timeout_handler;
+
+#if ! BOOST_BEAST_DOXYGEN
+ // boost::asio::ssl::stream needs these
+ // DEPRECATED
+ template
+ friend class boost::asio::ssl::stream;
+ // DEPRECATED
+ using lowest_layer_type = net::basic_stream_socket;
+ // DEPRECATED
+ net::basic_stream_socket&
+ lowest_layer() noexcept
+ {
+ return impl_->socket;
+ }
+ // DEPRECATED
+ net::basic_stream_socket const&
+ lowest_layer() const noexcept
+ {
+ return impl_->socket;
+ }
+#endif
+
+public:
+ /** The type of the executor associated with the stream.
+
+ This will be the type of executor used to invoke completion
+ handlers which do not have an explicit associated executor.
+ */
+ using executor_type = Executor;
+
+ /// The type of the underlying socket.
+ using socket_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 stream, cancelling any outstanding
+ asynchronous operations associated with the socket as if by
+ calling cancel.
+ */
+ ~basic_stream();
+
+ /** Construct the stream from an execution context.
+
+ This constructor creates the stream from an execution context.
+ The underlying socket needs to be open and 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 that do not have an explicit associated executor.
+ Currently, the only supported type for `ctx` is `net::io_context`.
+
+ @param args A list of parameters forwarded to the constructor of
+ the underlying socket.
+
+ @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 [P1322R0] Networking TS enhancement to enable custom I/O executors
+ */
+ template<
+ class ExecutionContext,
+ class... Args
+ #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(ExecutionContext& ctx, Args&&... args);
+
+ /** Construct the stream from an executor.
+
+ This constructor creates the stream from an executor.
+ The underlying socket needs to be open and connected or accepted
+ before data can be sent or received on it.
+
+ @param ex The executor to use when dispatching handlers that do
+ not have an explicit associated executor.
+ Currently, only executors that return a `net::io_context&` from
+ `ex.context()` are supported.
+
+ @param args A list of parameters forwarded to the constructor of
+ the underlying socket.
+
+ @see [P1322R0] Networking TS enhancement to enable custom I/O executors
+ */
+ template
+ explicit
+ basic_stream(
+ executor_type const& ex, Args&&... args);
+
+ /** Construct the stream from an existing socket.
+
+ This constructor creates the stream from an existing socket.
+ The underlying socket needs to be open and connected or accepted
+ before data can be sent or received on it.
+
+ @param socket The socket to construct from. Ownership of the
+ socket will be transferred by move-construction.
+
+ @param args A list of parameters forwarded to the constructor of
+ the underlying socket.
+
+ @note This function does not participate in overload resolution unless:
+
+ @li `OtherProtocol` is convertible to `Protocol`, and one of:
+
+ @li `executor_type` of the stream is constructible from the type of
+ context returned by calling `socket.get_executor().context()`, or
+
+ @li `executor_type` of the stream is constructible from the type of
+ executor returned by calling `socket.get_executor()`.
+ */
+ template<
+ class OtherProtocol
+#if ! BOOST_BEAST_DOXYGEN
+ ,class = typename std::enable_if<
+ std::is_convertible::value && (
+ std::is_constructible&>().get_executor().context())>::value ||
+ std::is_constructible&>().get_executor())>::value)
+ >::type
+#endif
+ >
+ explicit
+ basic_stream(net::basic_stream_socket&& socket);
+
+ /** Move constructor.
+
+ @param other The other object from which the move will occur.
+
+ @note Following the move, the moved-from object is in the
+ same state as if newly constructed.
+ */
+ basic_stream(basic_stream&& other);
+
+ /// Move assignment (deleted).
+ basic_stream& operator=(basic_stream&&) = delete;
+
+ /// Return a reference to the underlying socket
+ socket_type&
+ socket() noexcept
+ {
+ return impl_->socket;
+ }
+
+ /// Return a reference to the underlying socket
+ socket_type const&
+ socket() const noexcept
+ {
+ return impl_->socket;
+ }
+
+ /** Release ownership of the underlying socket.
+
+ This function causes all outstanding asynchronous connect,
+ read, and write operations to be canceled as if by a call
+ to @ref cancel. Ownership of the underlying socket is then
+ transferred to the caller.
+ */
+ socket_type
+ release_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.
+
+ This function causes all outstanding asynchronous connect,
+ read, and write operations to finish immediately. Completion
+ handlers for cancelled operations will receive the error
+ `net::error::operation_aborted`. Completion handlers not
+ yet invoked whose operations have completed, will receive
+ the error corresponding to the result of the operation (which
+ may indicate success).
+ */
+ void
+ cancel();
+
+ /** Close the timed stream.
+
+ This cancels all of the outstanding asynchronous operations
+ as if by calling @ref cancel, and closes the file
+ */
+ void
+ close();
+
+ //--------------------------------------------------------------------------
+
+ /** Get the executor associated with the object.
+
+ This function may be used to obtain the executor object that the
+ stream uses to dispatch completion handlers without an assocaited
+ executor.
+
+ @return A copy of the executor that stream will use to dispatch handlers.
+ */
+ executor_type
+ get_executor() const noexcept
+ {
+ return impl_->ex();
+ }
+
+ /** Connect the stream to the specified endpoint.
+
+ This function is used to connect the underlying socket to the
+ specified remote endpoint. The function call will block until
+ the connection is successfully made or an error occurs.
+
+ The underlying socket is automatically opened if needed.
+ An automatically opened socket is not returned to the
+ closed state upon failure.
+
+ @param ep The remote endpoint to connect to.
+
+ @throws system_error Thrown on failure.
+
+ @see @ref connect
+ */
+ void
+ connect(endpoint_type const& ep)
+ {
+ impl_->socket.connect(ep);
+ }
+
+ /** Connect the stream to the specified endpoint.
+
+ This function is used to connect the underlying socket to the
+ specified remote endpoint. The function call will block until
+ the connection is successfully made or an error occurs.
+
+ The underlying socket is automatically opened if needed.
+ An automatically opened socket is not returned to the
+ closed state upon failure.
+
+ @param ep The remote endpoint to connect to.
+
+ @param ec Set to indicate what error occurred, if any.
+
+ @see @ref connect
+ */
+ void
+ connect(endpoint_type const& ep, error_code& ec)
+ {
+ impl_->socket.connect(ep, ec);
+ }
+
+ /** Connect the stream to the specified endpoint asynchronously.
+
+ This function is used to asynchronously connect the underlying
+ socket to the specified remote endpoint. The function call always
+ returns immediately.
+
+ The underlying socket is automatically opened if needed.
+ An automatically opened socket is not returned to the
+ closed state upon failure.
+
+ If the timeout timer expires while the operation is outstanding,
+ the operation will be canceled and the completion handler will be
+ invoked with the error @ref error::timeout.
+
+ @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 Invoked when the operation completes. Ownership
+ of the handler will be transferred by move-construction as needed.
+ The equivalent function signature of the handler must be:
+ @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`.
+
+ @see @ref async_connect
+ */
+ template
+ BOOST_ASIO_INITFN_RESULT_TYPE(ConnectHandler,
+ void(error_code))
+ async_connect(
+ endpoint_type const& ep,
+ ConnectHandler&& handler);
+
+ //--------------------------------------------------------------------------
+
+ /** Read some data.
+
+ This function is used to read some data from the stream.
+
+ The call blocks until one of the following is true:
+
+ @li One or more bytes are read from the stream.
+
+ @li An error occurs.
+
+ @param buffers The buffers into which the data will be read. If the
+ size of the buffers is zero bytes, the call always returns
+ immediately with no error.
+
+ @returns The number of bytes read.
+
+ @throws system_error Thrown on failure.
+
+ @note The `read_some` operation may not receive all of the requested
+ number of bytes. Consider using the function `net::read` if you need
+ to ensure that the requested amount of data is read before the
+ blocking operation completes.
+ */
+ template
+ std::size_t
+ read_some(MutableBufferSequence const& buffers)
+ {
+ return impl_->socket.read_some(buffers);
+ }
+
+ /** Read some data.
+
+ This function is used to read some data from the underlying socket.
+
+ The call blocks until one of the following is true:
+
+ @li One or more bytes are read from the stream.
+
+ @li An error occurs.
+
+ @param buffers The buffers into which the data will be read. If the
+ size of the buffers is zero bytes, the call always returns
+ immediately with no error.
+
+ @param ec Set to indicate what error occurred, if any.
+
+ @returns The number of bytes read.
+
+ @note The `read_some` operation may not receive all of the requested
+ number of bytes. Consider using the function `net::read` if you need
+ to ensure that the requested amount of data is read before the
+ blocking operation completes.
+ */
+ template
+ std::size_t
+ read_some(
+ MutableBufferSequence const& buffers,
+ error_code& ec)
+ {
+ return impl_->socket.read_some(buffers, ec);
+ }
+
+ /** Read some data asynchronously.
+
+ This function is used to asynchronously read data from the stream.
+
+ This call always returns immediately. The asynchronous operation
+ will continue until one of the following conditions is true:
+
+ @li One or more bytes are read from the stream.
+
+ @li An error occurs.
+
+ The algorithm, known as a composed asynchronous operation,
+ is implemented in terms of calls to the next layer's `async_read_some`
+ function. The program must ensure that no other calls to @ref read_some
+ or @ref async_read_some are performed until this operation completes.
+
+ If the timeout timer expires while the operation is outstanding,
+ the operation will be canceled and the completion handler will be
+ invoked with the error @ref error::timeout.
+
+ @param buffers The buffers into which the data will be read. If the size
+ of the buffers is zero bytes, the operation always completes immediately
+ with no error.
+ 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`.
+
+ @note The `async_read_some` operation may not receive all of the requested
+ number of bytes. Consider using the function `net::async_read` if you need
+ to ensure that the requested amount of data is read before the asynchronous
+ operation completes.
+ */
+ template
+ BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
+ void(error_code, std::size_t))
+ async_read_some(
+ MutableBufferSequence const& buffers,
+ ReadHandler&& handler);
+
+ /** Write some data.
+
+ This function is used to write some data to the stream.
+
+ The call blocks until one of the following is true:
+
+ @li One or more bytes are written to the stream.
+
+ @li An error occurs.
+
+ @param buffers The buffers from which the data will be written. If the
+ size of the buffers is zero bytes, the call always returns immediately
+ with no error.
+
+ @returns The number of bytes written.
+
+ @throws system_error Thrown on failure.
+
+ @note The `write_some` operation may not transmit all of the requested
+ number of bytes. Consider using the function `net::write` if you need
+ to ensure that the requested amount of data is written before the
+ blocking operation completes.
+ */
+ template
+ std::size_t
+ write_some(ConstBufferSequence const& buffers)
+ {
+ return impl_->socket.write_some(buffers);
+ }
+
+ /** Write some data.
+
+ This function is used to write some data to the stream.
+
+ The call blocks until one of the following is true:
+
+ @li One or more bytes are written to the stream.
+
+ @li An error occurs.
+
+ @param buffers The buffers from which the data will be written. If the
+ size of the buffers is zero bytes, the call always returns immediately
+ with no error.
+
+ @param ec Set to indicate what error occurred, if any.
+
+ @returns The number of bytes written.
+
+ @throws system_error Thrown on failure.
+
+ @note The `write_some` operation may not transmit all of the requested
+ number of bytes. Consider using the function `net::write` if you need
+ to ensure that the requested amount of data is written before the
+ blocking operation completes.
+ */
+ template
+ std::size_t
+ write_some(
+ ConstBufferSequence const& buffers,
+ error_code& ec)
+ {
+ return impl_->socket.write_some(buffers, ec);
+ }
+
+ /** Write some data asynchronously.
+
+ This function is used to asynchronously write data to the underlying socket.
+
+ This call always returns immediately. The asynchronous operation
+ will continue until one of the following conditions is true:
+
+ @li One or more bytes are written to the stream.
+
+ @li An error occurs.
+
+ The algorithm, known as a composed asynchronous operation,
+ is implemented in terms of calls to the next layer's `async_write_some`
+ function. The program must ensure that no other calls to @ref async_write_some
+ are performed until this operation completes.
+
+ If the timeout timer expires while the operation is outstanding,
+ the operation will be canceled and the completion handler will be
+ invoked with the error @ref error::timeout.
+
+ @param buffers The buffers from which the data will be written. If the
+ size of the buffers is zero bytes, the operation always completes
+ immediately with no error.
+ 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`.
+
+ @note The `async_write_some` operation may not transmit all of the requested
+ number of bytes. Consider using the function `net::async_write` if you need
+ to ensure that the requested amount of data is sent before the asynchronous
+ operation completes.
+ */
+ template
+ BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler,
+ void(error_code, std::size_t))
+ async_write_some(
+ ConstBufferSequence const& buffers,
+ WriteHandler&& handler);
+};
+
+//------------------------------------------------------------------------------
+
+/** Establishes a connection by trying each endpoint in a sequence.
+
+ This function attempts to connect the stream to one of a sequence of
+ endpoints by trying each endpoint until a connection is successfully
+ established.
+
+ The algorithm, known as a composed operation, is implemented
+ in terms of calls to the underlying socket's `connect` function.
+
+ @param stream The stream to be connected.
+ If the underlying socket is already open, it will be closed.
+
+ @param endpoints A sequence of endpoints.
+
+ @returns The successfully connected endpoint.
+
+ @throws system_error Thrown on failure. If the sequence is
+ empty, the associated error code is `net::error::not_found`.
+ Otherwise, contains the error from the last connection attempt.
+*/
+template<
+ class Protocol, class Executor,
+ class EndpointSequence
+#if ! BOOST_BEAST_DOXYGEN
+ ,class = typename std::enable_if<
+ net::is_endpoint_sequence<
+ EndpointSequence>::value>::type
+#endif
+>
+typename Protocol::endpoint
+connect(
+ basic_stream& stream,
+ EndpointSequence const& endpoints
+)
+{
+ return net::connect(stream.socket(), endpoints);
+}
+
+/** Establishes a connection by trying each endpoint in a sequence.
+
+ This function attempts to connect the stream to one of a sequence of
+ endpoints by trying each endpoint until a connection is successfully
+ established.
+
+ The algorithm, known as a composed operation, is implemented
+ in terms of calls to the underlying socket's `connect` function.
+
+ @param stream The stream to be connected.
+ If the underlying socket is already open, it will be closed.
+
+ @param endpoints A sequence of endpoints.
+
+ @param ec Set to indicate what error occurred, if any. If the sequence is
+ empty, set to `net::error::not_found`. Otherwise, contains the error
+ from the last connection attempt.
+
+ @returns On success, the successfully connected endpoint. Otherwise, a
+ default-constructed endpoint.
+*/
+template<
+ class Protocol, class Executor,
+ class EndpointSequence
+#if ! BOOST_BEAST_DOXYGEN
+ ,class = typename std::enable_if<
+ net::is_endpoint_sequence<
+ EndpointSequence>::value>::type
+#endif
+>
+typename Protocol::endpoint
+connect(
+ basic_stream& stream,
+ EndpointSequence const& endpoints,
+ error_code& ec
+)
+{
+ return net::connect(stream.socket(), endpoints, ec);
+}
+
+/** Establishes a connection by trying each endpoint in a sequence.
+
+ This function attempts to connect the stream to one of a sequence of
+ endpoints by trying each endpoint until a connection is successfully
+ established.
+
+ The algorithm, known as a composed operation, is implemented
+ in terms of calls to the underlying socket's `connect` function.
+
+ @param stream The 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.
+
+ @returns An iterator denoting the successfully connected endpoint.
+
+ @throws system_error Thrown on failure. If the sequence is
+ empty, the associated error code is `net::error::not_found`.
+ Otherwise, contains the error from the last connection attempt.
+*/
+template<
+ class Protocol, class Executor,
+ class Iterator>
+Iterator
+connect(
+ basic_stream& stream,
+ Iterator begin, Iterator end)
+{
+ return net::connect(stream.socket(), begin, end);
+}
+
+/** Establishes a connection by trying each endpoint in a sequence.
+
+ This function attempts to connect the stream to one of a sequence of
+ endpoints by trying each endpoint until a connection is successfully
+ established.
+
+ The algorithm, known as a composed operation, is implemented
+ in terms of calls to the underlying socket's `connect` function.
+
+ @param stream The 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 ec Set to indicate what error occurred, if any. If the sequence is
+ empty, set to boost::asio::error::not_found. Otherwise, contains the error
+ from the last connection attempt.
+
+ @returns On success, an iterator denoting the successfully connected
+ endpoint. Otherwise, the end iterator.
+*/
+template<
+ class Protocol, class Executor,
+ class Iterator>
+Iterator
+connect(
+ basic_stream& stream,
+ Iterator begin, Iterator end,
+ error_code& ec)
+{
+ return net::connect(stream.socket(), begin, end, ec);
+}
+
+/** Establishes a connection by trying each endpoint in a sequence.
+
+ This function attempts to connect the stream to one of a sequence of
+ endpoints by trying each endpoint until a connection is successfully
+ established.
+
+ The algorithm, known as a composed operation, is implemented
+ in terms of calls to the underlying socket's `connect` function.
+
+ @param stream The stream to be connected.
+ If the underlying 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.
+
+ @returns The successfully connected endpoint.
+
+ @throws boost::system::system_error Thrown on failure. If the sequence is
+ empty, the associated error code is `net::error::not_found`.
+ Otherwise, contains the error from the last connection attempt.
+*/
+template<
+ class Protocol, class Executor,
+ class EndpointSequence, class ConnectCondition
+#if ! BOOST_BEAST_DOXYGEN
+ ,class = typename std::enable_if<
+ net::is_endpoint_sequence<
+ EndpointSequence>::value>::type
+#endif
+>
+typename Protocol::endpoint
+connect(
+ basic_stream& stream,
+ EndpointSequence const& endpoints,
+ ConnectCondition connect_condition
+)
+{
+ return net::connect(stream.socket(), endpoints, connect_condition);
+}
+
+/** Establishes a connection by trying each endpoint in a sequence.
+
+ This function attempts to connect the stream to one of a sequence of
+ endpoints by trying each endpoint until a connection is successfully
+ established.
+
+ The algorithm, known as a composed operation, is implemented
+ in terms of calls to the underlying socket's `connect` function.
+
+ @param stream The stream to be connected.
+ If the underlying 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 ec Set to indicate what error occurred, if any. If the sequence is
+ empty, set to `net::error::not_found`. Otherwise, contains the error
+ from the last connection attempt.
+
+ @returns On success, the successfully connected endpoint. Otherwise, a
+ default-constructed endpoint.
+*/
+template<
+ class Protocol, class Executor,
+ class EndpointSequence, class ConnectCondition
+#if ! BOOST_BEAST_DOXYGEN
+ ,class = typename std::enable_if<
+ net::is_endpoint_sequence<
+ EndpointSequence>::value>::type
+#endif
+>
+typename Protocol::endpoint
+connect(
+ basic_stream& stream,
+ EndpointSequence const& endpoints,
+ ConnectCondition connect_condition,
+ error_code& ec)
+{
+ return net::connect(stream.socket(), endpoints, connect_condition, ec);
+}
+
+/** Establishes a connection by trying each endpoint in a sequence.
+
+ This function attempts to connect the stream to one of a sequence of
+ endpoints by trying each endpoint until a connection is successfully
+ established.
+
+ The algorithm, known as a composed operation, is implemented
+ in terms of calls to the underlying socket's `connect` function.
+
+ @param stream The 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,
+ 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.
+
+ @returns An iterator denoting the successfully connected endpoint.
+
+ @throws boost::system::system_error Thrown on failure. If the sequence is
+ empty, the associated @c error_code is `net::error::not_found`.
+ Otherwise, contains the error from the last connection attempt.
+*/
+template<
+ class Protocol, class Executor,
+ class Iterator, class ConnectCondition>
+Iterator
+connect(
+ basic_stream& stream,
+ Iterator begin, Iterator end,
+ ConnectCondition connect_condition)
+{
+ return net::connect(stream.socket(), begin, end, connect_condition);
+}
+
+/** Establishes a connection by trying each endpoint in a sequence.
+
+ This function attempts to connect the stream to one of a sequence of
+ endpoints by trying each endpoint until a connection is successfully
+ established.
+
+ The algorithm, known as a composed operation, is implemented
+ in terms of calls to the underlying socket's `connect` function.
+
+ @param stream The 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,
+ 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 ec Set to indicate what error occurred, if any. If the sequence is
+ empty, set to `net::error::not_found`. Otherwise, contains the error
+ from the last connection attempt.
+
+ @returns On success, an iterator denoting the successfully connected
+ endpoint. Otherwise, the end iterator.
+*/
+template<
+ class Protocol, class Executor,
+ class Iterator, class ConnectCondition>
+Iterator
+connect(
+ basic_stream& stream,
+ Iterator begin, Iterator end,
+ ConnectCondition connect_condition,
+ error_code& ec)
+{
+ return net::connect(stream.socket(), begin, end, connect_condition, ec);
+}
+
+/** Establishes a connection by trying each endpoint in a sequence asynchronously.
+
+ This function attempts to connect the stream to one of a sequence of
+ endpoints by trying each endpoint until a connection is successfully
+ established.
+
+ The algorithm, known as a composed asynchronous operation, is
+ implemented in terms of calls to the underlying socket's `async_connect`
+ function.
+
+ If the timeout timer expires while the operation is outstanding,
+ the current connection attempt will be canceled and the completion
+ handler will be invoked with the error @ref error::timeout.
+
+ @param stream The 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::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_stream& stream,
+ EndpointSequence const& endpoints,
+ RangeConnectHandler&& handler);
+
+/** Establishes a connection by trying each endpoint in a sequence asynchronously.
+
+ This function attempts to connect the stream to one of a sequence of
+ endpoints by trying each endpoint until a connection is successfully
+ established.
+
+ The algorithm, known as a composed asynchronous operation, is
+ implemented in terms of calls to the underlying socket's `async_connect`
+ function.
+
+ If the timeout timer expires while the operation is outstanding,
+ the current connection attempt will be canceled and the completion
+ handler will be invoked with the error @ref error::timeout.
+
+ @param stream The 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::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_stream& stream,
+ EndpointSequence const& endpoints,
+ ConnectCondition connect_condition,
+ RangeConnectHandler&& handler);
+
+/** Establishes a connection by trying each endpoint in a sequence asynchronously.
+
+ This function attempts to connect the stream to one of a sequence of
+ endpoints by trying each endpoint until a connection is successfully
+ established.
+
+ The algorithm, known as a composed asynchronous operation, is
+ implemented in terms of calls to the underlying socket's `async_connect`
+ function.
+
+ If the timeout timer expires while the operation is outstanding,
+ the current connection attempt will be canceled and the completion
+ handler will be invoked with the error @ref error::timeout.
+
+ @param stream The 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::post`.
+*/
+template<
+ class Protocol, class Executor,
+ class Iterator,
+ class IteratorConnectHandler>
+BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler,
+ void (error_code, Iterator))
+async_connect(
+ basic_stream& stream,
+ Iterator begin, Iterator end,
+ IteratorConnectHandler&& handler);
+
+/** Establishes a connection by trying each endpoint in a sequence asynchronously.
+
+ This function attempts to connect the stream to one of a sequence of
+ endpoints by trying each endpoint until a connection is successfully
+ established.
+
+ The algorithm, known as a composed asynchronous operation, is
+ implemented in terms of calls to the underlying socket's `async_connect`
+ function.
+
+ If the timeout timer expires while the operation is outstanding,
+ the current connection attempt will be canceled and the completion
+ handler will be invoked with the error @ref error::timeout.
+
+ @param stream The 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::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_stream& stream,
+ 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
deleted file mode 100644
index ab6d8e91..00000000
--- a/include/boost/beast/core/basic_timeout_stream.hpp
+++ /dev/null
@@ -1,847 +0,0 @@
-//
-// Copyright (c) 2018 Vinnie Falco (vinnie dot falco at gmail dot com)
-//
-// Distributed under the Boost Software License, Version 1.0. (See accompanying
-// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
-//
-// Official repository: https://github.com/boostorg/beast
-//
-
-#ifndef BOOST_BEAST_CORE_BASIC_TIMEOUT_SOCKET_HPP
-#define BOOST_BEAST_CORE_BASIC_TIMEOUT_SOCKET_HPP
-
-#include
-#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)();
-
- using tick_type = std::uint64_t;
-
- struct op_state
- {
- net::steady_timer timer; // for timing out
- tick_type tick = 0; // counts waits
- bool pending = false; // if op is pending
- bool timeout = false; // if timed out
-
- explicit
- op_state(net::io_context& ioc)
- : timer(ioc)
- {
- }
- };
-
-// friend class template declaration in a class template is ignored
-// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88672
-#if BOOST_WORKAROUND(BOOST_GCC, > 0)
-public:
-#endif
- struct impl_type
- : std::enable_shared_from_this
- {
- 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/buffer_size.hpp b/include/boost/beast/core/buffer_size.hpp
index ffaa6910..34525a89 100644
--- a/include/boost/beast/core/buffer_size.hpp
+++ b/include/boost/beast/core/buffer_size.hpp
@@ -78,6 +78,25 @@ struct buffer_size_impl
}
};
+/** Return `true` if a buffer sequence is empty
+
+ This is sometimes faster than using @ref buffer_size
+*/
+template
+bool
+buffers_empty(ConstBufferSequence const& buffers)
+{
+ auto it = net::buffer_sequence_begin(buffers);
+ auto end = net::buffer_sequence_end(buffers);
+ while(it != end)
+ {
+ if(net::const_buffer(*it).size() > 0)
+ return false;
+ ++it;
+ }
+ return true;
+}
+
} // detail
/** Return the total number of bytes in a buffer or buffer sequence
diff --git a/include/boost/beast/core/detail/stranded_socket.hpp b/include/boost/beast/core/detail/stranded_socket.hpp
deleted file mode 100644
index ce2d401a..00000000
--- a/include/boost/beast/core/detail/stranded_socket.hpp
+++ /dev/null
@@ -1,42 +0,0 @@
-//
-// Copyright (c) 2018 Vinnie Falco (vinnie dot falco at gmail dot com)
-//
-// Distributed under the Boost Software License, Version 1.0. (See accompanying
-// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
-//
-// Official repository: https://github.com/boostorg/beast
-//
-
-#ifndef BOOST_BEAST_CORE_DETAIL_STRANDED_SOCKET_HPP
-#define BOOST_BEAST_CORE_DETAIL_STRANDED_SOCKET_HPP
-
-#include
-#include
-#include
-
-namespace boost {
-namespace beast {
-namespace detail {
-
-template
-class stranded_socket_base
-{
-protected:
- net::basic_stream_socket socket_;
-
- template
- explicit
- stranded_socket_base(Args&&... args)
- : socket_(std::forward(args)...)
- {
- }
-
- stranded_socket_base(stranded_socket_base&&) = default;
- stranded_socket_base& operator=(stranded_socket_base&&) = delete;
-};
-
-} // detail
-} // beast
-} // boost
-
-#endif
diff --git a/include/boost/beast/core/detail/timeout_stream_base.hpp b/include/boost/beast/core/detail/stream_base.hpp
similarity index 59%
rename from include/boost/beast/core/detail/timeout_stream_base.hpp
rename to include/boost/beast/core/detail/stream_base.hpp
index 9e2b22d2..140a0d16 100644
--- a/include/boost/beast/core/detail/timeout_stream_base.hpp
+++ b/include/boost/beast/core/detail/stream_base.hpp
@@ -7,18 +7,21 @@
// Official repository: https://github.com/boostorg/beast
//
-#ifndef BOOST_BEAST_CORE_DETAIL_TIMEOUT_STREAM_BASE_HPP
-#define BOOST_BEAST_CORE_DETAIL_TIMEOUT_STREAM_BASE_HPP
+#ifndef BOOST_BEAST_CORE_DETAIL_STREAM_BASE_HPP
+#define BOOST_BEAST_CORE_DETAIL_STREAM_BASE_HPP
+#include
#include
#include
+#include
+#include
namespace boost {
namespace beast {
namespace detail {
template
-class timeout_stream_connect_op;
+class basic_stream_connect_op;
struct any_endpoint
{
@@ -31,9 +34,27 @@ struct any_endpoint
}
};
-class timeout_stream_base
+struct stream_base
{
-protected:
+ using clock_type = std::chrono::steady_clock;
+ using time_point = typename
+ std::chrono::steady_clock::time_point;
+ using tick_type = std::uint64_t;
+
+ struct op_state
+ {
+ net::steady_timer timer; // for timing out
+ tick_type tick = 0; // counts waits
+ bool pending = false; // if op is pending
+ bool timeout = false; // if timed out
+
+ explicit
+ op_state(net::io_context& ioc)
+ : timer(ioc)
+ {
+ }
+ };
+
class pending_guard
{
bool& b_;
@@ -70,6 +91,14 @@ protected:
clear_ = false;
}
};
+
+ static constexpr time_point never()
+ {
+ return (time_point::max)();
+ }
+
+ static std::size_t constexpr no_limit =
+ (std::numeric_limits::max)();
};
} // detail
diff --git a/include/boost/beast/core/impl/basic_timeout_stream.hpp b/include/boost/beast/core/impl/basic_stream.hpp
similarity index 68%
rename from include/boost/beast/core/impl/basic_timeout_stream.hpp
rename to include/boost/beast/core/impl/basic_stream.hpp
index 53b4b4e6..2958e2e5 100644
--- a/include/boost/beast/core/impl/basic_timeout_stream.hpp
+++ b/include/boost/beast/core/impl/basic_stream.hpp
@@ -7,11 +7,13 @@
// Official repository: https://github.com/boostorg/beast
//
-#ifndef BOOST_BEAST_CORE_IMPL_BASIC_TIMEOUT_STREAM_HPP
-#define BOOST_BEAST_CORE_IMPL_BASIC_TIMEOUT_STREAM_HPP
+#ifndef BOOST_BEAST_CORE_IMPL_BASIC_STREAM_HPP
+#define BOOST_BEAST_CORE_IMPL_BASIC_STREAM_HPP
#include
-#include
+#include
+#include
+#include
#include
#include
#include
@@ -23,8 +25,96 @@
namespace boost {
namespace beast {
+//------------------------------------------------------------------------------
+
template
-struct basic_timeout_stream<
+template
+basic_stream::
+impl_type::
+impl_type(
+ Executor const& ex_,
+ Args&&... args)
+ : boost::empty_value(
+ boost::empty_init_t{}, ex_)
+ , read(ex().context())
+ , write(ex().context())
+ , socket(std::forward(args)...)
+{
+ reset();
+}
+
+template
+template
+basic_stream::
+impl_type::
+impl_type(net::basic_stream_socket&& socket_,
+ std::true_type)
+ : boost::empty_value(
+ boost::empty_init_t{}, socket_.get_executor())
+ , read(ex().context())
+ , write(ex().context())
+ , socket(std::move(socket_))
+{
+ reset();
+}
+
+template
+template
+basic_stream::
+impl_type::
+impl_type(net::basic_stream_socket&& socket_,
+ std::false_type)
+ : boost::empty_value(boost::empty_init_t{},
+ socket_.get_executor().context())
+ , read(ex().context())
+ , write(ex().context())
+ , socket(std::move(socket_))
+{
+ reset();
+}
+
+template
+void
+basic_stream::
+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::
+impl_type::
+close()
+{
+ socket.close();
+
+ // have to let the read/write ops cancel the timer,
+ // otherwise we will get error::timeout on close when
+ // we actually want net::error::operation_aborted.
+ //
+ //read.timer.cancel();
+ //write.timer.cancel();
+}
+
+//------------------------------------------------------------------------------
+
+template
+struct basic_stream<
Protocol, Executor>::timeout_handler
{
op_state& state;
@@ -50,14 +140,8 @@ struct basic_timeout_stream<
return;
BOOST_ASSERT(tick == state.tick);
- // late completion
- if(state.timeout)
- {
- state.timeout = false;
- return;
- }
-
// timeout
+ BOOST_ASSERT(! state.timeout);
sp->close();
state.timeout = true;
}
@@ -75,7 +159,7 @@ struct basic_timeout_stream<
template
template
-class basic_timeout_stream::async_op
+class basic_stream::async_op
: public async_op_base
, public boost::asio::coroutine
{
@@ -119,7 +203,7 @@ class basic_timeout_stream::async_op
public:
template
async_op(
- basic_timeout_stream& s,
+ basic_stream& s,
Buffers const& b,
Handler_&& h)
: async_op_base(
@@ -138,44 +222,55 @@ public:
{
BOOST_ASIO_CORO_REENTER(*this)
{
- // VFALCO TODO handle buffer size == 0
+ if(detail::buffers_empty(b_))
+ {
+ BOOST_ASIO_CORO_YIELD
+ async_perform(
+ std::integral_constant{});
+ if(state().timer.expiry() <= clock_type::now())
+ ec = beast::error::timeout;
+ goto upcall;
+ }
- state().timer.async_wait(
- net::bind_executor(
- this->get_executor(),
- timeout_handler{
- state(),
- impl_,
- state().tick
- }));
+ if(state().timer.expiry() != never())
+ state().timer.async_wait(
+ net::bind_executor(
+ this->get_executor(),
+ timeout_handler{
+ state(),
+ impl_,
+ state().tick
+ }));
BOOST_ASIO_CORO_YIELD
async_perform(
std::integral_constant{});
- ++state().tick;
- // try cancelling timer
- auto const n =
- state().timer.cancel();
- if(n == 0)
+ if(state().timer.expiry() != never())
{
- if(state().timeout)
+ ++state().tick;
+
+ // try cancelling timer
+ auto const n =
+ state().timer.cancel();
+ if(n == 0)
{
- // timeout handler invoked
- ec = beast::error::timeout;
- state().timeout = false;
+ // timeout handler invoked?
+ if(state().timeout)
+ {
+ // yes, socket already closed
+ ec = beast::error::timeout;
+ state().timeout = false;
+ }
}
else
{
- // timeout handler queued, stale
+ BOOST_ASSERT(n == 1);
+ BOOST_ASSERT(! state().timeout);
}
}
- else
- {
- BOOST_ASSERT(n == 1);
- BOOST_ASSERT(! state().timeout);
- }
+ upcall:
pg_.reset();
this->invoke(ec, bytes_transferred);
}
@@ -188,17 +283,17 @@ namespace detail {
template<
class Protocol, class Executor, class Handler>
-class timeout_stream_connect_op
+class basic_stream_connect_op
: public async_op_base
{
using stream_type =
- beast::basic_timeout_stream;
+ beast::basic_stream;
using timeout_handler =
typename stream_type::timeout_handler;
- std::shared_ptr::impl_type> impl_;
+ std::shared_ptr impl_;
typename stream_type::pending_guard pg0_;
typename stream_type::pending_guard pg1_;
@@ -209,64 +304,8 @@ class timeout_stream_connect_op
}
public:
- template<
- class Endpoints, class Condition,
- class Handler_>
- timeout_stream_connect_op(
- stream_type& s,
- Endpoints const& eps,
- Condition cond,
- Handler_&& h)
- : async_op_base(
- 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{
- state(),
- impl_,
- state().tick}));
-
- net::async_connect(impl_->socket,
- eps, cond, std::move(*this));
- // *this is now moved-from
- }
-
- template<
- class Iterator, class Condition,
- class Handler_>
- timeout_stream_connect_op(
- stream_type& s,
- Iterator begin, Iterator end,
- Condition cond,
- Handler_&& h)
- : async_op_base(
- 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{
- state(),
- impl_,
- state().tick}));
-
- net::async_connect(impl_->socket,
- begin, end, cond, std::move(*this));
- // *this is now moved-from
- }
-
template
- timeout_stream_connect_op(
+ basic_stream_connect_op(
stream_type& s,
typename stream_type::endpoint_type ep,
Handler_&& h)
@@ -276,48 +315,104 @@ public:
, pg0_(impl_->read.pending)
, pg1_(impl_->write.pending)
{
- // must come first
- impl_->write.timer.async_wait(
- net::bind_executor(
- this->get_executor(),
- timeout_handler{
- state(),
- impl_,
- state().tick}));
+ if(state().timer.expiry() != stream_base::never())
+ impl_->write.timer.async_wait(
+ net::bind_executor(
+ this->get_executor(),
+ timeout_handler{
+ state(),
+ impl_,
+ state().tick}));
impl_->socket.async_connect(
ep, std::move(*this));
// *this is now moved-from
}
+ template<
+ class Endpoints, class Condition,
+ class Handler_>
+ basic_stream_connect_op(
+ stream_type& s,
+ Endpoints const& eps,
+ Condition const& cond,
+ Handler_&& h)
+ : async_op_base(
+ std::forward(h), s.get_executor())
+ , impl_(s.impl_)
+ , pg0_(impl_->read.pending)
+ , pg1_(impl_->write.pending)
+ {
+ if(state().timer.expiry() != stream_base::never())
+ impl_->write.timer.async_wait(
+ net::bind_executor(
+ this->get_executor(),
+ timeout_handler{
+ state(),
+ impl_,
+ state().tick}));
+
+ net::async_connect(impl_->socket,
+ eps, cond, std::move(*this));
+ // *this is now moved-from
+ }
+
+ template<
+ class Iterator, class Condition,
+ class Handler_>
+ basic_stream_connect_op(
+ stream_type& s,
+ Iterator begin, Iterator end,
+ Condition const& cond,
+ Handler_&& h)
+ : async_op_base(
+ std::forward(h), s.get_executor())
+ , impl_(s.impl_)
+ , pg0_(impl_->read.pending)
+ , pg1_(impl_->write.pending)
+ {
+ if(state().timer.expiry() != stream_base::never())
+ impl_->write.timer.async_wait(
+ net::bind_executor(
+ this->get_executor(),
+ timeout_handler{
+ state(),
+ impl_,
+ state().tick}));
+
+ net::async_connect(impl_->socket,
+ begin, end, cond, std::move(*this));
+ // *this is now moved-from
+ }
+
template
void
operator()(error_code ec, Args&&... args)
{
- ++state().tick;
-
- // try cancelling timer
- auto const n =
- impl_->write.timer.cancel();
- if(n == 0)
+ if(state().timer.expiry() != stream_base::never())
{
- if(state().timeout)
+ ++state().tick;
+
+ // try cancelling timer
+ auto const n =
+ impl_->write.timer.cancel();
+ if(n == 0)
{
- // timeout handler invoked
- ec = beast::error::timeout;
- state().timeout = false;
+ // timeout handler invoked?
+ if(state().timeout)
+ {
+ // yes, socket already closed
+ ec = beast::error::timeout;
+ state().timeout = false;
+ }
}
else
{
- // timeout handler queued, stale
+ BOOST_ASSERT(n == 1);
+ BOOST_ASSERT(! state().timeout);
}
}
- else
- {
- BOOST_ASSERT(n == 1);
- BOOST_ASSERT(! state().timeout);
- }
-
+
pg0_.reset();
pg1_.reset();
this->invoke(ec, std::forward(args)...);
@@ -329,82 +424,8 @@ public:
//------------------------------------------------------------------------------
template
-template
-basic_timeout_stream::
-impl_type::
-impl_type(
- Executor const& ex_,
- Args&&... args)
- : ex(ex_)
- , read(ex_.context())
- , write(ex_.context())
- , socket(std::forward(args)...)
-{
- reset();
-}
-
-template
-auto
-basic_timeout_stream::
-impl_type::
-operator=(impl_type&& other) -> impl_type&
-{
- // VFALCO This hack is because legacy io_context::strand
- // doesn't support operator=. Don't worry, constructing
- // an executor cannot throw.
- ex.~Executor();
- ::new(&ex) Executor(other.ex);
-
- socket = std::move(other.socket);
- read = std::move(other.read);
- write = std::move(other.write);
-
- return *this;
-}
-
-template
-void
-basic_timeout_stream::
-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_timeout_stream::
-impl_type::
-close()
-{
- socket.close();
-
- // have to let the read/write ops cancel the timer,
- // otherwise we will get error::timeout on close when
- // we actually want net::error::operation_aborted.
- //
- //read.timer.cancel();
- //write.timer.cancel();
-}
-
-//------------------------------------------------------------------------------
-
-template
-basic_timeout_stream::
-~basic_timeout_stream()
+basic_stream::
+~basic_stream()
{
// the shared object can outlive *this,
// cancel any operations so the shared
@@ -413,12 +434,12 @@ basic_timeout_stream::
}
template
-template
-basic_timeout_stream::
-basic_timeout_stream(ExecutionContext& ctx)
+template
+basic_stream::
+basic_stream(ExecutionContext& ctx, Args&&... args)
: impl_(std::make_shared(
ctx.get_executor(),
- ctx))
+ ctx, std::forward(args)...))
{
// Restriction is necessary until Asio fully supports P1322R0
static_assert(
@@ -427,67 +448,52 @@ basic_timeout_stream(ExecutionContext& ctx)
}
template
-basic_timeout_stream::
-basic_timeout_stream(executor_type const& ex)
+template
+basic_stream::
+basic_stream(
+ executor_type const& ex, Args&&... args)
: impl_(std::make_shared(
- ex, ex.context()))
+ ex,
+ ex.context(), std::forward(args)...))
{
}
template
-basic_timeout_stream::
-basic_timeout_stream(
- net::basic_stream_socket&& socket)
+template
+basic_stream::
+basic_stream(net::basic_stream_socket&& socket)
: impl_(std::make_shared(
- socket.get_executor(), std::move(socket)))
+ std::move(socket),
+ std::is_constructible&>().get_executor())>{}))
{
}
template
-basic_timeout_stream::
-basic_timeout_stream(
- executor_type const& ex,
- net::basic_stream_socket&& socket)
- : impl_(std::make_shared(
- ex, std::move(socket)))
-{
- // Restriction is necessary until Asio fully supports P1322R0
- if(ex.context().get_executor() != socket.get_executor())
- throw std::invalid_argument(
- "basic_timeout_stream currently requires ctx.get_executor() == socket.get_executor()");
-}
-
-template
-basic_timeout_stream::
-basic_timeout_stream(basic_timeout_stream&& other)
+basic_stream::
+basic_stream(basic_stream&& 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_timeout_stream::
-operator=(basic_timeout_stream&& other) ->
- basic_timeout_stream&
-{
- // Can't move while operations are pending!
- BOOST_ASSERT(! impl_->read.pending);
- BOOST_ASSERT(! impl_->write.pending);
- BOOST_ASSERT(! other.impl_->read.pending);
- BOOST_ASSERT(! other.impl_->write.pending);
- *impl_ = std::move(*other.impl_);
- return *this;
+ // VFALCO I'm not sure this implementation is correct...
}
//------------------------------------------------------------------------------
+template
+auto
+basic_stream::
+release_socket() ->
+ socket_type
+{
+ this->cancel();
+ return std::move(impl_->socket);
+}
+
template
void
-basic_timeout_stream::
+basic_stream::
expires_after(std::chrono::nanoseconds expiry_time)
{
// If assert goes off, it means that there are
@@ -512,7 +518,7 @@ expires_after(std::chrono::nanoseconds expiry_time)
template
void
-basic_timeout_stream::
+basic_stream::
expires_at(
net::steady_timer::time_point expiry_time)
{
@@ -538,7 +544,7 @@ expires_at(
template
void
-basic_timeout_stream::
+basic_stream::
expires_never()
{
impl_->reset();
@@ -546,7 +552,7 @@ expires_never()
template
void
-basic_timeout_stream::
+basic_stream::
cancel()
{
error_code ec;
@@ -555,7 +561,7 @@ cancel()
template
void
-basic_timeout_stream::
+basic_stream::
close()
{
impl_->close();
@@ -565,14 +571,14 @@ template