diff --git a/CHANGELOG.md b/CHANGELOG.md
index c6e87f67..7ead8398 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,7 @@ Version 212:
* dynamic_buffer_ref tests and tidy
* flat_stream tests and tidy
+* stranded_socket tests and tidy
--------------------------------------------------------------------------------
diff --git a/doc/qbk/03_core/2_streams.qbk b/doc/qbk/03_core/2_streams.qbk
index 6221b4af..fc489178 100644
--- a/doc/qbk/03_core/2_streams.qbk
+++ b/doc/qbk/03_core/2_streams.qbk
@@ -113,30 +113,4 @@ synchronous stream may check its argument:
[snippet_core_3]
-
-
-[heading Stream Interfaces]
-
-To facilitiate stream algorithms, these types provide enhanced functionality
-above what is offered by networking:
-
-[table Stream Interfaces
-[[Name][Description]]
-[[
- [link beast.ref.boost__beast__basic_timeout_stream `basic_timeout_stream`]
- [link beast.ref.boost__beast__timeout_stream `timeout_stream`]
-][
- Objects of this type are designed to act as a replacement for the
- traditional networking socket. They
-]]
-[[
- [link beast.ref.boost__beast__flat_stream `flat_stream`]
-][
- This stream wrapper improves performance by working around a limitation
- of networking's `ssl::stream` to improve performance.
-]]
-]
-
-
-
[endsect]
diff --git a/doc/qbk/03_core/3_layers.qbk b/doc/qbk/03_core/3_layers.qbk
index d90669b6..7bac24f8 100644
--- a/doc/qbk/03_core/3_layers.qbk
+++ b/doc/qbk/03_core/3_layers.qbk
@@ -110,7 +110,7 @@ facilities for authoring and working with layered streams:
a work-around for a performance limitation in the original SSL stream.
]]
[[
- [link beast.ref.boost__beast__stranded_stream `stranded_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
@@ -131,4 +131,3 @@ streams:
[code_core_3_layers_5]
[endsect]
-
diff --git a/doc/qbk/quickref.xml b/doc/qbk/quickref.xml
index 0548c6bd..88d63bf4 100644
--- a/doc/qbk/quickref.xml
+++ b/doc/qbk/quickref.xml
@@ -46,7 +46,7 @@
spanstatic_stringstable_async_op_base 🞲
- stranded_stream 🞲
+ stranded_socket 🞲string_paramstring_viewtimeout_stream 🞲
@@ -69,6 +69,7 @@
bind_handlerbuffer_size 🞲close_socket 🞲
+ connect 🞲generic_categoryget_lowest_layer 🞲iequals
diff --git a/doc/xsl/class_detail.xsl b/doc/xsl/class_detail.xsl
index d2562cfc..70cff029 100644
--- a/doc/xsl/class_detail.xsl
+++ b/doc/xsl/class_detail.xsl
@@ -39,6 +39,9 @@
class __EndpointSequence__
+
+ class __ExecutionContext__
+ class __Executor__
diff --git a/include/boost/beast/core.hpp b/include/boost/beast/core.hpp
index 5bf8d46c..f24800cb 100644
--- a/include/boost/beast/core.hpp
+++ b/include/boost/beast/core.hpp
@@ -41,7 +41,7 @@
#include
#include
#include
-#include
+#include
#include
#include
#include
diff --git a/include/boost/beast/core/basic_timeout_stream.hpp b/include/boost/beast/core/basic_timeout_stream.hpp
index fc03141b..ab6d8e91 100644
--- a/include/boost/beast/core/basic_timeout_stream.hpp
+++ b/include/boost/beast/core/basic_timeout_stream.hpp
@@ -682,6 +682,7 @@ async_connect(
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:
@@ -701,7 +702,7 @@ async_connect(
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:
diff --git a/include/boost/beast/core/detail/stranded_stream.hpp b/include/boost/beast/core/detail/stranded_socket.hpp
similarity index 70%
rename from include/boost/beast/core/detail/stranded_stream.hpp
rename to include/boost/beast/core/detail/stranded_socket.hpp
index f8448b00..ce2d401a 100644
--- a/include/boost/beast/core/detail/stranded_stream.hpp
+++ b/include/boost/beast/core/detail/stranded_socket.hpp
@@ -7,8 +7,8 @@
// Official repository: https://github.com/boostorg/beast
//
-#ifndef BOOST_BEAST_CORE_DETAIL_STRANDED_STREAM_HPP
-#define BOOST_BEAST_CORE_DETAIL_STRANDED_STREAM_HPP
+#ifndef BOOST_BEAST_CORE_DETAIL_STRANDED_SOCKET_HPP
+#define BOOST_BEAST_CORE_DETAIL_STRANDED_SOCKET_HPP
#include
#include
@@ -19,20 +19,20 @@ namespace beast {
namespace detail {
template
-class stranded_stream_base
+class stranded_socket_base
{
protected:
net::basic_stream_socket socket_;
template
explicit
- stranded_stream_base(Args&&... args)
+ stranded_socket_base(Args&&... args)
: socket_(std::forward(args)...)
{
}
- stranded_stream_base(stranded_stream_base&&) = default;
- stranded_stream_base& operator=(stranded_stream_base&&) = default;
+ stranded_socket_base(stranded_socket_base&&) = default;
+ stranded_socket_base& operator=(stranded_socket_base&&) = delete;
};
} // detail
diff --git a/include/boost/beast/core/stranded_socket.hpp b/include/boost/beast/core/stranded_socket.hpp
new file mode 100644
index 00000000..09c5c6d4
--- /dev/null
+++ b/include/boost/beast/core/stranded_socket.hpp
@@ -0,0 +1,1102 @@
+//
+// 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_STRANDED_SOCKET_HPP
+#define BOOST_BEAST_CORE_STRANDED_SOCKET_HPP
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace boost {
+namespace beast {
+
+//------------------------------------------------------------------------------
+
+/** A stream-oriented socket using a custom executor, defaulting to a strand
+
+ This class template provides asynchronous and blocking stream-oriented
+ socket functionality. It is designed as a replacement for
+ `net::basic_stream_socket`.
+
+ This class template is parameterized on the executor type to be
+ used for all asynchronous operations. This achieves partial support for
+ [P1322]. The default template parameter uses a strand for the next
+ layer's executor.
+
+ Unlike other stream wrappers, the underlying socket is accessed
+ through the @ref socket member function instead of `next_layer`.
+ This causes @ref stranded_socket to be returned in calls to
+ @ref get_lowest_layer.
+
+ @tparam Protocol The protocol to use.
+
+ @tparam Executor The executor to use.
+
+ @par Thread Safety
+ @e Distinct @e objects: Safe.@n
+ @e Shared @e objects: Unsafe.
+
+ @par Concepts:
+ @li SyncReadStream, SyncWriteStream
+ @li AsyncReadStream, AsyncWriteStream,
+ @li Protocol
+ @li Executor
+
+ @see [P1322R0]
+ Networking TS enhancement to enable custom I/O executors
+*/
+template<
+ class Protocol,
+ class Executor = net::io_context::strand
+>
+class stranded_socket
+#ifndef BOOST_BEAST_DOXYGEN
+ : private detail::stranded_socket_base
+ , private boost::empty_value
+#endif
+{
+ // Restricted until P1322R0 is incorporated into Boost.Asio.
+ static_assert(
+ std::is_convertible().context()),
+ net::io_context&>::value,
+ "Only net::io_context is currently supported for executor_type::context()");
+
+public:
+ /// The type of the executor associated with the object.
+ 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;
+
+ /** Construct the stream without opening it.
+
+ This constructor creates a 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`.
+
+ @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 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1322r0.html
+ */
+ 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
+ stranded_socket(ExecutionContext& ctx, Args&&... args)
+ : detail::stranded_socket_base(
+ ctx, std::forward(args)...)
+ , boost::empty_value(
+ boost::empty_init_t{}, ctx.get_executor())
+ {
+ // Restriction is necessary until Asio fully supports P1322R0
+ static_assert(
+ std::is_same::value,
+ "Only net::io_context is currently supported for ExecutionContext");
+ }
+
+ /** Construct the stream without opening it.
+
+ This constructor creates a 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.
+
+ @param args A list of parameters forwarded to the constructor of
+ the underlying socket.
+
+ @see http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1322r0.html
+ */
+ template
+ explicit
+ stranded_socket(executor_type const& ex, Args&&... args)
+ : detail::stranded_socket_base(
+ ex.context(), std::forward(args)...)
+ , boost::empty_value(
+ boost::empty_init_t{}, ex)
+ {
+ }
+
+ /** 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.
+ */
+ stranded_socket(stranded_socket&& other) = default;
+
+ /// Move assignment (deleted)
+ stranded_socket&
+ operator=(stranded_socket&& other) = delete;
+
+ /** Get a reference to the underlying socket.
+
+ This function returns a reference to the underlying
+ socket used by the stream.
+ */
+ socket_type&
+ socket() noexcept
+ {
+ return this->socket_;
+ }
+
+ /** Get a reference to the underlying socket.
+
+ This function returns a reference to the underlying
+ socket used by the stream.
+ */
+ socket_type const&
+ socket() const noexcept
+ {
+ return this->socket_;
+ }
+
+ //--------------------------------------------------------------------------
+
+ /** Return the executor associated with the object.
+
+ @return A copy of the executor that stream will use to dispatch handlers.
+ */
+ executor_type
+ get_executor() const noexcept
+ {
+ return this->get();
+ }
+
+ /** Connect the socket to the specified endpoint.
+
+ This function is used to connect a socket to the specified remote endpoint.
+ The function call will block until the connection is successfully made or
+ an error occurs.
+
+ The 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 socket will be
+ connected.
+
+ @throws system_error Thrown on failure.
+ */
+ void
+ connect(endpoint_type const& ep)
+ {
+ this->socket_.connect(ep);
+ }
+
+ /** Connect the socket to the specified endpoint.
+
+ This function is used to connect a socket to the specified remote endpoint.
+ The function call will block until the connection is successfully made or
+ an error occurs.
+
+ The 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 socket will be
+ connected.
+
+ @param ec Set to indicate what error occurred, if any.
+ */
+ void
+ connect(endpoint_type const& ep, error_code& ec)
+ {
+ this->socket_.connect(ep, ec);
+ }
+
+ /** 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 const& ep,
+ ConnectHandler&& handler)
+ {
+ BOOST_BEAST_HANDLER_INIT(ConnectHandler,
+ void(error_code));
+ this->socket_.async_connect(
+ ep,
+ detail::bind_default_executor(
+ this->get(),
+ std::move(init.completion_handler)));
+ return init.result.get();
+ }
+
+ /** Read some data from the stream.
+
+ This function is used to read data from the stream. The function call will
+ block until one or more bytes of data has been read successfully, or until
+ an error occurs.
+
+ @param buffers The buffers into which the data will be read.
+
+ @returns The number of bytes read.
+
+ @throws boost::system::system_error Thrown on failure.
+
+ @note The `read_some` operation may not read 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 this->socket_.read_some(buffers);
+ }
+
+ /** Read some data from the stream.
+
+ This function is used to read data from the stream. The function call will
+ block until one or more bytes of data has been read successfully, or until
+ an error occurs.
+
+ @param buffers The buffers into which the data will be read.
+
+ @param ec Set to indicate what error occurred, if any.
+
+ @returns The number of bytes read.
+
+ @note The `read_some` operation may not read 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 this->socket_.read_some(buffers, ec);
+ }
+
+ /** 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)
+ {
+ BOOST_BEAST_HANDLER_INIT(ReadHandler,
+ void(error_code, std::size_t));
+ this->socket_.async_read_some(
+ buffers,
+ detail::bind_default_executor(
+ this->get(),
+ std::move(init.completion_handler)));
+ return init.result.get();
+ }
+
+ /** Write some data to the stream.
+
+ This function is used to write data on the stream. The function call will
+ block until one or more bytes of data has been written successfully, or
+ until an error occurs.
+
+ @param buffers The data to be written.
+
+ @returns The number of bytes written.
+
+ @throws boost::system::system_error Thrown on failure.
+
+ @note The `write_some` operation may not transmit all of the data to the
+ peer. Consider using the function `net::write` if you need to
+ ensure that all data is written before the blocking operation completes.
+ */
+ template
+ std::size_t
+ write_some(ConstBufferSequence const& buffers)
+ {
+ return this->socket_.write_some(buffers);
+ }
+
+ /** Write some data to the stream.
+
+ This function is used to write data on the stream. The function call will
+ block until one or more bytes of data has been written successfully, or
+ until an error occurs.
+
+ @param buffers The data to be written.
+
+ @param ec Set to indicate what error occurred, if any.
+
+ @returns The number of bytes written.
+
+ @note The `write_some` operation may not transmit all of the data to the
+ peer. Consider using the function `net::write` if you need to
+ ensure that all data is written before the blocking operation completes.
+ */
+ template
+ std::size_t
+ write_some(
+ ConstBufferSequence const& buffers,
+ error_code& ec)
+ {
+ return this->socket_.write_some(buffers, ec);
+ }
+
+ /** 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)
+ {
+ BOOST_BEAST_HANDLER_INIT(WriteHandler,
+ void(error_code, std::size_t));
+ this->socket_.async_write_some(
+ buffers,
+ detail::bind_default_executor(
+ this->get(),
+ std::move(init.completion_handler)));
+ return init.result.get();
+ }
+};
+
+//------------------------------------------------------------------------------
+
+/** Establishes a socket connection by trying each endpoint in a sequence.
+
+ This function attempts to connect a socket to one of a sequence of
+ endpoints. It does this by repeated calls to the socket's @c connect member
+ function, once for each endpoint in the sequence, until a connection is
+ successfully established.
+
+ @param socket The socket 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(
+ stranded_socket& socket,
+ EndpointSequence const & endpoints
+)
+{
+ return net::connect(socket.socket(), endpoints);
+}
+
+/** Establishes a socket connection by trying each endpoint in a sequence.
+
+ This function attempts to connect a socket to one of a sequence of
+ endpoints. It does this by repeated calls to the socket's @c connect member
+ function, once for each endpoint in the sequence, until a connection is
+ successfully established.
+
+ @param socket The socket 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(
+ stranded_socket& socket,
+ EndpointSequence const& endpoints,
+ error_code& ec
+)
+{
+ return net::connect(socket.socket(), endpoints, ec);
+}
+
+/** Establishes a socket connection by trying each endpoint in a sequence.
+
+ This function attempts to connect a socket to one of a sequence of
+ endpoints. It does this by repeated calls to the socket's @c connect member
+ function, once for each endpoint in the sequence, until a connection is
+ successfully established.
+
+ @param socket The socket 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(
+ stranded_socket& socket,
+ Iterator begin, Iterator end)
+{
+ return net::connect(socket.socket(), begin, end);
+}
+
+/** Establishes a socket connection by trying each endpoint in a sequence.
+
+ This function attempts to connect a socket to one of a sequence of
+ endpoints. It does this by repeated calls to the socket's @c connect member
+ function, once for each endpoint in the sequence, until a connection is
+ successfully established.
+
+ @param socket The socket 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(
+ stranded_socket& socket,
+ Iterator begin, Iterator end,
+ error_code& ec)
+{
+ return net::connect(socket.socket(), begin, end, ec);
+}
+
+/** Establishes a socket connection by trying each endpoint in a sequence.
+
+ This function attempts to connect a socket to one of a sequence of
+ endpoints. It does this by repeated calls to the socket's @c connect member
+ function, once for each endpoint in the sequence, until a connection is
+ successfully established.
+
+ @param socket The socket 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(
+ stranded_socket& socket,
+ EndpointSequence const& endpoints,
+ ConnectCondition connect_condition
+)
+{
+ return net::connect(socket.socket(), endpoints, connect_condition);
+}
+
+/** Establishes a socket connection by trying each endpoint in a sequence.
+
+ This function attempts to connect a socket to one of a sequence of
+ endpoints. It does this by repeated calls to the socket's @c connect member
+ function, once for each endpoint in the sequence, until a connection is
+ successfully established.
+
+ @param socket The socket 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(
+ stranded_socket& socket,
+ EndpointSequence const& endpoints,
+ ConnectCondition connect_condition,
+ error_code& ec)
+{
+ return net::connect(socket.socket(), endpoints, connect_condition, ec);
+}
+
+/** Establishes a socket connection by trying each endpoint in a sequence.
+
+ This function attempts to connect a socket to one of a sequence of
+ endpoints. It does this by repeated calls to the socket's @c connect member
+ function, once for each endpoint in the sequence, until a connection is
+ successfully established.
+
+ @param socket The socket 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(
+ stranded_socket& socket,
+ Iterator begin, Iterator end,
+ ConnectCondition connect_condition)
+{
+ return net::connect(socket.socket(), begin, end, connect_condition);
+}
+
+/** Establishes a socket connection by trying each endpoint in a sequence.
+
+ This function attempts to connect a socket to one of a sequence of
+ endpoints. It does this by repeated calls to the socket's @c connect member
+ function, once for each endpoint in the sequence, until a connection is
+ successfully established.
+
+ @param socket The socket 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(
+ stranded_socket& socket,
+ Iterator begin, Iterator end,
+ ConnectCondition connect_condition,
+ error_code& ec)
+{
+ return net::connect(socket.socket(), begin, end, connect_condition, ec);
+}
+
+/** 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 socket The socket 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(
+ stranded_socket& socket,
+ EndpointSequence const& endpoints,
+ RangeConnectHandler&& handler)
+{
+ BOOST_BEAST_HANDLER_INIT(RangeConnectHandler,
+ void(error_code, typename Protocol::endpoint));
+ net::async_connect(socket.socket(),
+ endpoints,
+ detail::bind_default_executor(
+ socket.get_executor(),
+ std::move(init.completion_handler)));
+ return init.result.get();
+}
+
+/** 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 socket The socket 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(
+ stranded_socket& socket,
+ EndpointSequence const& endpoints,
+ ConnectCondition connect_condition,
+ RangeConnectHandler&& handler)
+{
+ BOOST_BEAST_HANDLER_INIT(RangeConnectHandler,
+ void(error_code, typename Protocol::endpoint));
+ net::async_connect(socket.socket(),
+ endpoints,
+ connect_condition,
+ detail::bind_default_executor(
+ socket.get_executor(),
+ std::move(init.completion_handler)));
+ return init.result.get();
+}
+
+/** 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 socket The socket 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(
+ stranded_socket& socket,
+ Iterator begin, Iterator end,
+ IteratorConnectHandler&& handler)
+{
+ BOOST_BEAST_HANDLER_INIT(IteratorConnectHandler,
+ void(error_code, Iterator));
+ net::async_connect(socket.socket(),
+ begin, end,
+ detail::bind_default_executor(
+ socket.get_executor(),
+ std::move(init.completion_handler)));
+ return init.result.get();
+}
+
+/** 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 socket The socket 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 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(
+ stranded_socket& socket,
+ Iterator begin, Iterator end,
+ ConnectCondition connect_condition,
+ IteratorConnectHandler&& handler)
+{
+ BOOST_BEAST_HANDLER_INIT(IteratorConnectHandler,
+ void(error_code, Iterator));
+ net::async_connect(socket.socket(),
+ begin, end,
+ connect_condition,
+ detail::bind_default_executor(
+ socket.get_executor(),
+ std::move(init.completion_handler)));
+ return init.result.get();
+}
+
+} // beast
+} // boost
+
+#endif
diff --git a/include/boost/beast/core/stranded_stream.hpp b/include/boost/beast/core/stranded_stream.hpp
deleted file mode 100644
index 583fba2e..00000000
--- a/include/boost/beast/core/stranded_stream.hpp
+++ /dev/null
@@ -1,433 +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_STRANDED_STREAM_HPP
-#define BOOST_BEAST_CORE_STRANDED_STREAM_HPP
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-namespace boost {
-namespace beast {
-
-//------------------------------------------------------------------------------
-
-/** A stream socket using a custom executor, defaulting to a strand
-
- This class template is parameterized on the executor type to be
- used for all asynchronous operations. This achieves partial support for
- [P1322]. The default template parameter uses a strand for the next
- layer's executor.
-
- @see [P1322R0]
- Networking TS enhancement to enable custom I/O executors
-*/
-template<
- class Protocol,
- class Executor = beast::executor_type>
->
-class stranded_stream
-#ifndef BOOST_BEAST_DOXYGEN
- : private detail::stranded_stream_base
- , private boost::empty_value
-#endif
-{
- // Restricted until P1322R0 is incorporated into Boost.Asio.
- static_assert(
- std::is_convertible().context()),
- net::io_context&>::value,
- "Only net::io_context is currently supported for executor_type::context()");
-
-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;
-
- /** Construct the stream without opening it.
-
- This constructor creates a 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`.
-
- @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 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1322r0.html
- */
- 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
- stranded_stream(ExecutionContext& ctx, Args&&... args)
- : detail::stranded_stream_base(
- ctx, std::forward(args)...)
- , boost::empty_value(
- boost::empty_init_t{}, ctx.get_executor())
- {
- // Restriction is necessary until Asio fully supports P1322R0
- static_assert(
- std::is_same::value,
- "Only net::io_context is currently supported for ExecutionContext");
- }
-
- /** Construct the stream without opening it.
-
- This constructor creates a 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.
-
- @param args A list of parameters forwarded to the constructor of
- the underlying socket.
-
- @see http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1322r0.html
- */
- template
- explicit
- stranded_stream(executor_type const& ex, Args&&... args)
- : detail::stranded_stream_base(
- ex.context(), std::forward(args)...)
- , boost::empty_value(
- boost::empty_init_t{}, ex)
- {
- // Restriction is necessary until Asio fully supports P1322R0
- if(ex.context().get_executor() != this->socket_.get_executor())
- throw std::invalid_argument(
- "ctx.get_executor() != socket.get_executor()");
- }
-
- /** 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.
- */
- stranded_stream(stranded_stream&& other) = default;
-
- /** 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.
- */
- stranded_stream&
- operator=(stranded_stream&& other) = default;
-
- //--------------------------------------------------------------------------
-
- /** Return the executor associated with the object.
-
- @return A copy of the executor that stream will use to dispatch handlers.
- */
- executor_type
- get_executor() const noexcept
- {
- return this->get();
- }
-
- /** 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 this->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 this->socket_;
- }
-
- /** 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);
-
- /** Read some data from the stream.
-
- This function is used to read data from the stream. The function call will
- block until one or more bytes of data has been read successfully, or until
- an error occurs.
-
- @param buffers The buffers into which the data will be read.
-
- @returns The number of bytes read.
-
- @throws boost::system::system_error Thrown on failure.
-
- @note The `read_some` operation may not read 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 this->socket_.read_some(buffers);
- }
-
- /** Read some data from the stream.
-
- This function is used to read data from the stream. The function call will
- block until one or more bytes of data has been read successfully, or until
- an error occurs.
-
- @param buffers The buffers into which the data will be read.
-
- @param ec Set to indicate what error occurred, if any.
-
- @returns The number of bytes read.
-
- @note The `read_some` operation may not read 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 this->socket_.read_some(buffers, ec);
- }
-
- /** 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)
- {
- BOOST_BEAST_HANDLER_INIT(ReadHandler,
- void(error_code, std::size_t));
- this->socket_.async_read_some(
- buffers,
- detail::bind_default_executor(
- this->get(),
- std::move(init.completion_handler)));
- return init.result.get();
- }
-
- /** Write some data to the stream.
-
- This function is used to write data on the stream. The function call will
- block until one or more bytes of data has been written successfully, or
- until an error occurs.
-
- @param buffers The data to be written.
-
- @returns The number of bytes written.
-
- @throws boost::system::system_error Thrown on failure.
-
- @note The `write_some` operation may not transmit all of the data to the
- peer. Consider using the function `net::write` if you need to
- ensure that all data is written before the blocking operation completes.
- */
- template
- std::size_t
- write_some(ConstBufferSequence const& buffers)
- {
- return this->socket_.write_some(buffers);
- }
-
- /** Write some data to the stream.
-
- This function is used to write data on the stream. The function call will
- block until one or more bytes of data has been written successfully, or
- until an error occurs.
-
- @param buffers The data to be written.
-
- @param ec Set to indicate what error occurred, if any.
-
- @returns The number of bytes written.
-
- @note The `write_some` operation may not transmit all of the data to the
- peer. Consider using the function `net::write` if you need to
- ensure that all data is written before the blocking operation completes.
- */
- template
- std::size_t
- write_some(
- ConstBufferSequence const& buffers,
- error_code& ec)
- {
- return this->socket_.write_some(buffers, ec);
- }
-
- /** 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)
- {
- BOOST_BEAST_HANDLER_INIT(WriteHandler,
- void(error_code, std::size_t));
- this->socket_.async_write_some(
- buffers,
- detail::bind_default_executor(
- this->get(),
- std::move(init.completion_handler)));
- return init.result.get();
- }
-};
-
-} // beast
-} // boost
-
-#endif
diff --git a/test/beast/core/CMakeLists.txt b/test/beast/core/CMakeLists.txt
index bc43c50d..34dfadcd 100644
--- a/test/beast/core/CMakeLists.txt
+++ b/test/beast/core/CMakeLists.txt
@@ -61,7 +61,7 @@ add_executable (tests-beast-core
span.cpp
static_buffer.cpp
static_string.cpp
- stranded_stream.cpp
+ stranded_socket.cpp
stream_traits.cpp
string.cpp
string_param.cpp
diff --git a/test/beast/core/Jamfile b/test/beast/core/Jamfile
index c63b3ff8..073cc723 100644
--- a/test/beast/core/Jamfile
+++ b/test/beast/core/Jamfile
@@ -49,7 +49,7 @@ local SOURCES =
span.cpp
static_buffer.cpp
static_string.cpp
- stranded_stream.cpp
+ stranded_socket.cpp
stream_traits.cpp
string.cpp
string_param.cpp
diff --git a/test/beast/core/bind_handler.cpp b/test/beast/core/bind_handler.cpp
index 7af2e6dd..ac9e934e 100644
--- a/test/beast/core/bind_handler.cpp
+++ b/test/beast/core/bind_handler.cpp
@@ -134,7 +134,7 @@ public:
{
// shouldn't be called since the enclosing
// networking wrapper only uses dispatch
- s_.fail("unexpected post", __FILE__, __LINE__);
+ BEAST_FAIL();
}
template
@@ -142,7 +142,7 @@ public:
{
// shouldn't be called since the enclosing
// networking wrapper only uses dispatch
- s_.fail("unexpected defer", __FILE__, __LINE__);
+ BEAST_FAIL();
}
};
diff --git a/test/beast/core/stranded_socket.cpp b/test/beast/core/stranded_socket.cpp
new file mode 100644
index 00000000..f9ab9a9b
--- /dev/null
+++ b/test/beast/core/stranded_socket.cpp
@@ -0,0 +1,519 @@
+//
+// Copyright (c) 2018 Vinnie Falco (vinnie dot falco at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+// Official repository: https://github.com/boostorg/beast
+//
+
+// Test that header file is self-contained.
+#include
+
+#include "stream_tests.hpp"
+
+#include
+#include
+
+#include
+
+namespace boost {
+namespace beast {
+
+namespace {
+
+template
+class test_executor
+{
+public:
+ // VFALCO These need to be atomic or something
+ struct info
+ {
+ int dispatch = 0;
+ int post = 0;
+ int defer = 0;
+ int work = 0;
+ int total = 0;
+ };
+
+private:
+ struct state
+ {
+ Executor ex;
+ info info_;
+
+ state(Executor const& ex_)
+ : ex(ex_)
+ {
+ }
+ };
+
+ std::shared_ptr sp_;
+
+public:
+ test_executor(test_executor const&) = default;
+ test_executor& operator=(test_executor const&) = default;
+
+ explicit
+ test_executor(Executor const& ex)
+ : sp_(std::make_shared(ex))
+ {
+ }
+
+ decltype(sp_->ex.context())
+ context() const noexcept
+ {
+ return sp_->ex.context();
+ }
+
+ info&
+ operator*() noexcept
+ {
+ return sp_->info_;
+ }
+
+ info*
+ operator->() noexcept
+ {
+ return &sp_->info_;
+ }
+
+ void
+ on_work_started() const noexcept
+ {
+ ++sp_->info_.work;
+ }
+
+ void
+ on_work_finished() const noexcept
+ {
+ }
+
+ template
+ void
+ dispatch(F&& f, A const& a)
+ {
+ ++sp_->info_.dispatch;
+ ++sp_->info_.total;
+ sp_->ex.dispatch(
+ std::forward(f), a);
+ }
+
+ template
+ void
+ post(F&& f, A const& a)
+ {
+ ++sp_->info_.post;
+ ++sp_->info_.total;
+ sp_->ex.post(
+ std::forward(f), a);
+ }
+
+ template
+ void
+ defer(F&& f, A const& a)
+ {
+ ++sp_->info_.defer;
+ ++sp_->info_.total;
+ sp_->ex.defer(
+ std::forward(f), a);
+ }
+};
+
+struct test_handler
+{
+ int& flags;
+
+ void
+ operator()()
+ {
+ flags |= 1;
+ }
+
+ template
+ friend
+ void
+ asio_handler_invoke(F&& f, test_handler* p)
+ {
+ p->flags |= 2;
+ std::move(f)();
+ }
+};
+
+struct test_acceptor
+{
+ net::io_context ioc;
+ net::ip::tcp::acceptor a;
+ net::ip::tcp::endpoint ep;
+
+ test_acceptor()
+ : a(ioc)
+ , ep(net::ip::make_address_v4("127.0.0.1"), 0)
+ {
+ a.open(ep.protocol());
+ a.set_option(
+ net::socket_base::reuse_address(true));
+ a.bind(ep);
+ a.listen(1);
+ ep = a.local_endpoint();
+ a.async_accept(
+ [](error_code, net::ip::tcp::socket)
+ {
+ });
+ }
+};
+
+} // (anon)
+
+//------------------------------------------------------------------------------
+
+class stranded_socket_test
+ : public beast::unit_test::suite
+{
+public:
+ using tcp = net::ip::tcp;
+ using strand = net::io_context::strand;
+ using executor = net::io_context::executor_type;
+
+ void
+ testStream()
+ {
+ net::io_context ioc;
+
+ // default Executor
+
+ {
+ stranded_socket s1{strand(ioc)};
+ stranded_socket s2{strand{ioc}};
+ //stranded_socket s3{strand{ioc}}; // ambiguous parse
+ }
+
+ // explicit Executor
+
+ {
+ auto ex = ioc.get_executor();
+ stranded_socket s1(ioc);
+ stranded_socket s2(ex);
+ stranded_socket s3(ioc, tcp::v4());
+ stranded_socket s4(std::move(s1));
+ s2.socket() = tcp::socket(ioc);
+ BEAST_EXPECT(s1.get_executor() == ex);
+ BEAST_EXPECT(s2.get_executor() == ex);
+ BEAST_EXPECT(s3.get_executor() == ex);
+ BEAST_EXPECT(s4.get_executor() == ex);
+
+ BEAST_EXPECT((! static_cast<
+ stranded_socket const&>(
+ s2).socket().is_open()));
+ }
+
+ {
+ auto ex = strand{ioc};
+ stranded_socket s1(ex);
+ stranded_socket s2(ex, tcp::v4());
+ stranded_socket s3(std::move(s1));
+ s2.socket() = tcp::socket(ioc);
+ BEAST_EXPECT(s1.get_executor() == ex);
+ BEAST_EXPECT(s2.get_executor() == ex);
+ BEAST_EXPECT(s3.get_executor() == ex);
+
+ BEAST_EXPECT((! static_cast<
+ stranded_socket const&>(
+ s2).socket().is_open()));
+ }
+
+ {
+ test_sync_stream>();
+ test_async_stream>();
+ test_sync_stream>();
+ test_async_stream>();
+ }
+ }
+
+ void
+ testMembers()
+ {
+ net::io_context ioc;
+
+ // connect (member)
+
+ auto const cond =
+ [](error_code, tcp::endpoint)
+ {
+ return true;
+ };
+
+ {
+ stranded_socket s(ioc);
+ error_code ec;
+ test_acceptor a;
+ try
+ {
+ s.connect(a.ep);
+ BEAST_PASS();
+ }
+ catch(std::exception const&)
+ {
+ BEAST_FAIL();
+ }
+ }
+
+ {
+ stranded_socket s(ioc);
+ error_code ec;
+ test_acceptor a;
+ s.connect(a.ep, ec);
+ BEAST_EXPECT(! ec);
+ }
+
+ // connect
+
+ {
+ test_acceptor a;
+ std::array epa;
+ epa[0] = a.ep;
+ stranded_socket s(ioc);
+ error_code ec;
+ connect(s, epa);
+ connect(s, epa, ec);
+ }
+
+ {
+ test_acceptor a;
+ std::array epa;
+ epa[0] = a.ep;
+ stranded_socket s(ioc);
+ error_code ec;
+ connect(s, epa, cond);
+ connect(s, epa, cond, ec);
+ }
+
+ {
+ test_acceptor a;
+ std::array epa;
+ epa[0] = a.ep;
+ stranded_socket s(ioc);
+ error_code ec;
+ connect(s, epa.begin(), epa.end());
+ connect(s, epa.begin(), epa.end(), ec);
+ }
+
+ {
+ test_acceptor a;
+ std::array epa;
+ epa[0] = a.ep;
+ stranded_socket s(ioc);
+ error_code ec;
+ connect(s, epa.begin(), epa.end(), cond);
+ connect(s, epa.begin(), epa.end(), cond, ec);
+ }
+
+ // async_connect
+
+ {
+ stranded_socket s(ioc);
+ test_acceptor a;
+ error_code ec;
+ s.async_connect(a. ep,
+ [](error_code ec)
+ {
+ BEAST_EXPECT(! ec);
+ });
+ ioc.run();
+ ioc.restart();
+ }
+
+ {
+ std::array epa;
+ epa[0] = tcp::endpoint(
+ net::ip::make_address_v4("127.0.0.1"), 0);
+ stranded_socket s(ioc);
+ async_connect(s, epa,
+ [](error_code, tcp::endpoint)
+ {
+ });
+ }
+
+ {
+ std::array epa;
+ epa[0] = tcp::endpoint(
+ net::ip::make_address_v4("127.0.0.1"), 0);
+ stranded_socket s(ioc);
+ async_connect(s, epa, cond,
+ [](error_code, tcp::endpoint)
+ {
+ });
+ }
+
+ {
+ std::array epa;
+ epa[0] = tcp::endpoint(
+ net::ip::make_address_v4("127.0.0.1"), 0);
+ using iter_type = decltype(epa)::const_iterator;
+ stranded_socket s(ioc);
+ async_connect(s, epa.begin(), epa.end(),
+ [](error_code, iter_type)
+ {
+ });
+ }
+
+ {
+ std::array epa;
+ epa[0] = tcp::endpoint(
+ net::ip::make_address_v4("127.0.0.1"), 0);
+ using iter_type = decltype(epa)::const_iterator;
+ stranded_socket s(ioc);
+ async_connect(s, epa.begin(), epa.end(), cond,
+ [](error_code, iter_type)
+ {
+ });
+ }
+
+ // read/write
+
+ {
+ error_code ec;
+ stranded_socket s(ioc, tcp::v4());
+
+ BEAST_EXPECT(s.read_some(net::mutable_buffer{}) == 0);
+ BEAST_EXPECT(s.read_some(net::mutable_buffer{}, ec) == 0);
+ BEAST_EXPECTS(! ec, ec.message());
+
+ BEAST_EXPECT(s.write_some(net::const_buffer{}) == 0);
+ BEAST_EXPECT(s.write_some(net::const_buffer{}, ec) == 0);
+ BEAST_EXPECTS(! ec, ec.message());
+
+ bool invoked;
+
+ invoked = false;
+ s.async_read_some(net::mutable_buffer{},
+ [&](error_code ec, std::size_t)
+ {
+ invoked = true;
+ BEAST_EXPECTS(! ec, ec.message());
+ });
+ ioc.run();
+ ioc.restart();
+ BEAST_EXPECT(invoked);
+
+ invoked = false;
+ s.async_write_some(net::const_buffer{},
+ [&](error_code ec, std::size_t)
+ {
+ invoked = true;
+ BEAST_EXPECTS(! ec, ec.message());
+ });
+ ioc.run();
+ ioc.restart();
+ BEAST_EXPECT(invoked);
+ }
+
+ // stranded
+
+ {
+ error_code ec;
+ stranded_socket s(strand(ioc), tcp::v4());
+
+ bool invoked;
+
+ invoked = false;
+ s.async_read_some(net::mutable_buffer{},
+ [&](error_code ec, std::size_t)
+ {
+ invoked = true;
+ BEAST_EXPECTS(! ec, ec.message());
+ });
+ ioc.run();
+ ioc.restart();
+ BEAST_EXPECT(invoked);
+
+ invoked = false;
+ s.async_write_some(net::const_buffer{},
+ [&](error_code ec, std::size_t)
+ {
+ invoked = true;
+ BEAST_EXPECTS(! ec, ec.message());
+ });
+ ioc.run();
+ ioc.restart();
+ BEAST_EXPECT(invoked);
+ }
+
+ // test_executor
+
+ {
+ error_code ec;
+ stranded_socket> s(
+ test_executor<>(ioc.get_executor()), tcp::v4());
+
+ bool invoked;
+
+ invoked = false;
+ s.async_read_some(net::mutable_buffer{},
+ [&](error_code ec, std::size_t)
+ {
+ invoked = true;
+ BEAST_EXPECTS(! ec, ec.message());
+ });
+ ioc.run();
+ ioc.restart();
+ BEAST_EXPECT(invoked);
+ BEAST_EXPECT(s.get_executor()->total > 0);
+ s.get_executor()->total = 0;
+
+ invoked = false;
+ s.async_write_some(net::const_buffer{},
+ [&](error_code ec, std::size_t)
+ {
+ invoked = true;
+ BEAST_EXPECTS(! ec, ec.message());
+ });
+ ioc.run();
+ ioc.restart();
+ BEAST_EXPECT(invoked);
+ BEAST_EXPECT(s.get_executor()->total > 0);
+ s.get_executor()->total = 0;
+ }
+
+ // bind_default_executor::asio_handler_invoke
+
+#if 0
+ // VFALCO This test fails, because it is unclear how
+ // asio_handler_invoke interacts with the wrapper.
+ // Need to ask Chris Kohlhoff about this one.
+ {
+ int flags = 0;
+ net::post(
+ ioc,
+ detail::bind_default_executor(
+ strand(ioc),
+ test_handler{flags}));
+ ioc.run();
+ ioc.restart();
+ BEAST_EXPECT(flags == 3);
+ }
+#endif
+ }
+
+ //--------------------------------------------------------------------------
+
+ void
+ testJavadocs()
+ {
+ }
+
+ //--------------------------------------------------------------------------
+
+ void
+ run()
+ {
+ testStream();
+ testJavadocs();
+ testMembers();
+ }
+};
+
+BEAST_DEFINE_TESTSUITE(beast,core,stranded_socket);
+
+} // beast
+} // boost
diff --git a/test/beast/core/stranded_stream.cpp b/test/beast/core/stranded_stream.cpp
deleted file mode 100644
index b282bcec..00000000
--- a/test/beast/core/stranded_stream.cpp
+++ /dev/null
@@ -1,81 +0,0 @@
-//
-// Copyright (c) 2018 Vinnie Falco (vinnie dot falco at gmail dot com)
-//
-// Distributed under the Boost Software License, Version 1.0. (See accompanying
-// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
-//
-// Official repository: https://github.com/boostorg/beast
-//
-
-// Test that header file is self-contained.
-#include
-
-#include "stream_tests.hpp"
-
-#include
-#include
-
-namespace boost {
-namespace beast {
-
-class stranded_stream_test
- : public beast::unit_test::suite
-{
-public:
- using tcp = net::ip::tcp;
-
- void
- testStream()
- {
- net::io_context ioc;
- {
- using ex_t = net::io_context::executor_type;
- auto ex = ioc.get_executor();
- stranded_stream s1(ioc);
- stranded_stream s2(ex);
- stranded_stream s3(ioc, tcp::v4());
- stranded_stream s4(std::move(s1));
- s2.next_layer() = tcp::socket(ioc);
- BEAST_EXPECT(s1.get_executor() == ex);
- BEAST_EXPECT(s2.get_executor() == ex);
- BEAST_EXPECT(s3.get_executor() == ex);
- BEAST_EXPECT(s4.get_executor() == ex);
- }
- {
- using ex_t = net::io_context::strand;
- auto ex = ex_t{ioc};
- stranded_stream s1(ex);
- stranded_stream s2(ex, tcp::v4());
- stranded_stream s3(std::move(s1));
- s2.next_layer() = tcp::socket(ioc);
- BEAST_EXPECT(s1.get_executor() == ex);
- BEAST_EXPECT(s2.get_executor() == ex);
- BEAST_EXPECT(s3.get_executor() == ex);
- }
- {
- using ex_t = net::io_context::executor_type;
- test_sync_stream>();
- test_async_stream>();
- }
- }
-
- void
- testJavadocs()
- {
- }
-
- //--------------------------------------------------------------------------
-
- void
- run()
- {
- testStream();
- testJavadocs();
- pass();
- }
-};
-
-BEAST_DEFINE_TESTSUITE(beast,core,stranded_stream);
-
-} // beast
-} // boost