mirror of
https://github.com/boostorg/beast.git
synced 2025-07-31 05:17:26 +02:00
Add stranded_stream
This commit is contained in:
@ -2,6 +2,7 @@ Version 211:
|
|||||||
|
|
||||||
* close_socket is in stream_traits.hpp
|
* close_socket is in stream_traits.hpp
|
||||||
* Improvements to test::stream
|
* Improvements to test::stream
|
||||||
|
* Add stranded_stream
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -109,6 +109,16 @@ facilities for authoring and working with layered streams:
|
|||||||
allows for move-construction and move-assignment, and also implements
|
allows for move-construction and move-assignment, and also implements
|
||||||
a work-around for a performance limitation in the original SSL stream.
|
a work-around for a performance limitation in the original SSL stream.
|
||||||
]]
|
]]
|
||||||
|
[[
|
||||||
|
[link beast.ref.boost__beast__stranded_stream `stranded_stream`]
|
||||||
|
][
|
||||||
|
A timeout stream meets the requirements for synchronous and asynchronous
|
||||||
|
read and write streams by passing I/O through to an underlying
|
||||||
|
`net::basic_stream_socket`, and additionally supports
|
||||||
|
[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1322r0.html [P1322R0] "Networking TS enhancement to enable custom I/O executors"],
|
||||||
|
allowing a custom executor (such a strand) to be used for all
|
||||||
|
asynchronous operations.
|
||||||
|
]]
|
||||||
]
|
]
|
||||||
|
|
||||||
[heading Example]
|
[heading Example]
|
||||||
|
@ -45,6 +45,7 @@
|
|||||||
<member><link linkend="beast.ref.boost__beast__span">span</link></member>
|
<member><link linkend="beast.ref.boost__beast__span">span</link></member>
|
||||||
<member><link linkend="beast.ref.boost__beast__static_string">static_string</link></member>
|
<member><link linkend="beast.ref.boost__beast__static_string">static_string</link></member>
|
||||||
<member><link linkend="beast.ref.boost__beast__stable_async_op_base">stable_async_op_base</link> <emphasis role="green">🞲</emphasis></member>
|
<member><link linkend="beast.ref.boost__beast__stable_async_op_base">stable_async_op_base</link> <emphasis role="green">🞲</emphasis></member>
|
||||||
|
<member><link linkend="beast.ref.boost__beast__stranded_stream">stranded_stream</link> <emphasis role="green">🞲</emphasis></member>
|
||||||
<member><link linkend="beast.ref.boost__beast__string_param">string_param</link></member>
|
<member><link linkend="beast.ref.boost__beast__string_param">string_param</link></member>
|
||||||
<member><link linkend="beast.ref.boost__beast__string_view">string_view</link></member>
|
<member><link linkend="beast.ref.boost__beast__string_view">string_view</link></member>
|
||||||
<member><link linkend="beast.ref.boost__beast__timeout_stream">timeout_stream</link> <emphasis role="green">🞲</emphasis></member>
|
<member><link linkend="beast.ref.boost__beast__timeout_stream">timeout_stream</link> <emphasis role="green">🞲</emphasis></member>
|
||||||
|
@ -40,6 +40,7 @@
|
|||||||
#include <boost/beast/core/span.hpp>
|
#include <boost/beast/core/span.hpp>
|
||||||
#include <boost/beast/core/static_buffer.hpp>
|
#include <boost/beast/core/static_buffer.hpp>
|
||||||
#include <boost/beast/core/static_string.hpp>
|
#include <boost/beast/core/static_string.hpp>
|
||||||
|
#include <boost/beast/core/stranded_stream.hpp>
|
||||||
#include <boost/beast/core/stream_traits.hpp>
|
#include <boost/beast/core/stream_traits.hpp>
|
||||||
#include <boost/beast/core/string.hpp>
|
#include <boost/beast/core/string.hpp>
|
||||||
#include <boost/beast/core/string_param.hpp>
|
#include <boost/beast/core/string_param.hpp>
|
||||||
|
123
include/boost/beast/core/detail/bind_default_executor.hpp
Normal file
123
include/boost/beast/core/detail/bind_default_executor.hpp
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
//
|
||||||
|
// 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_BIND_DEFAULT_EXECUTOR_HPP
|
||||||
|
#define BOOST_BEAST_CORE_DETAIL_BIND_DEFAULT_EXECUTOR_HPP
|
||||||
|
|
||||||
|
#include <boost/asio/associated_allocator.hpp>
|
||||||
|
#include <boost/asio/associated_executor.hpp>
|
||||||
|
#include <boost/asio/dispatch.hpp>
|
||||||
|
#include <boost/asio/executor.hpp>
|
||||||
|
#include <boost/asio/handler_alloc_hook.hpp>
|
||||||
|
#include <boost/asio/handler_continuation_hook.hpp>
|
||||||
|
#include <boost/asio/handler_invoke_hook.hpp>
|
||||||
|
#include <boost/core/empty_value.hpp>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
namespace beast {
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template<class Handler, class Executor>
|
||||||
|
class bind_default_executor_wrapper
|
||||||
|
: private boost::empty_value<Executor>
|
||||||
|
{
|
||||||
|
Handler h_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
template<class Handler_>
|
||||||
|
bind_default_executor_wrapper(
|
||||||
|
Handler_&& h,
|
||||||
|
Executor const& ex)
|
||||||
|
: boost::empty_value<Executor>(
|
||||||
|
boost::empty_init_t{}, ex)
|
||||||
|
, h_(std::forward<Handler_>(h))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class... Args>
|
||||||
|
void
|
||||||
|
operator()(Args&&... args)
|
||||||
|
{
|
||||||
|
h_(std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
using allocator_type =
|
||||||
|
net::associated_allocator_t<Handler>;
|
||||||
|
|
||||||
|
allocator_type
|
||||||
|
get_allocator() const noexcept
|
||||||
|
{
|
||||||
|
return net::get_associated_allocator(h_);
|
||||||
|
}
|
||||||
|
|
||||||
|
using executor_type =
|
||||||
|
net::associated_executor_t<Handler, Executor>;
|
||||||
|
|
||||||
|
executor_type
|
||||||
|
get_executor() const noexcept
|
||||||
|
{
|
||||||
|
return net::get_associated_executor(
|
||||||
|
h_, this->get());
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Function>
|
||||||
|
void
|
||||||
|
asio_handler_invoke(Function&& f,
|
||||||
|
bind_default_executor_wrapper* p)
|
||||||
|
{
|
||||||
|
net::dispatch(p->get_executor(), std::move(f));
|
||||||
|
}
|
||||||
|
|
||||||
|
friend
|
||||||
|
void* asio_handler_allocate(
|
||||||
|
std::size_t size, bind_default_executor_wrapper* p)
|
||||||
|
{
|
||||||
|
using net::asio_handler_allocate;
|
||||||
|
return asio_handler_allocate(
|
||||||
|
size, std::addressof(p->h_));
|
||||||
|
}
|
||||||
|
|
||||||
|
friend
|
||||||
|
void asio_handler_deallocate(
|
||||||
|
void* mem, std::size_t size,
|
||||||
|
bind_default_executor_wrapper* p)
|
||||||
|
{
|
||||||
|
using net::asio_handler_deallocate;
|
||||||
|
asio_handler_deallocate(mem, size,
|
||||||
|
std::addressof(p->h_));
|
||||||
|
}
|
||||||
|
|
||||||
|
friend
|
||||||
|
bool asio_handler_is_continuation(
|
||||||
|
bind_default_executor_wrapper* p)
|
||||||
|
{
|
||||||
|
using net::asio_handler_is_continuation;
|
||||||
|
return asio_handler_is_continuation(
|
||||||
|
std::addressof(p->h_));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class Executor, class Handler>
|
||||||
|
auto
|
||||||
|
bind_default_executor(Executor const& ex, Handler&& h) ->
|
||||||
|
bind_default_executor_wrapper<
|
||||||
|
typename std::decay<Handler>::type,
|
||||||
|
Executor>
|
||||||
|
{
|
||||||
|
return bind_default_executor_wrapper<
|
||||||
|
typename std::decay<Handler>::type,
|
||||||
|
Executor>(std::forward<Handler>(h), ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // detail
|
||||||
|
} // beast
|
||||||
|
} // boost
|
||||||
|
|
||||||
|
#endif
|
42
include/boost/beast/core/detail/stranded_stream.hpp
Normal file
42
include/boost/beast/core/detail/stranded_stream.hpp
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
//
|
||||||
|
// 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_STREAM_HPP
|
||||||
|
#define BOOST_BEAST_CORE_DETAIL_STRANDED_STREAM_HPP
|
||||||
|
|
||||||
|
#include <boost/beast/core/detail/bind_default_executor.hpp>
|
||||||
|
#include <boost/asio/basic_stream_socket.hpp>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
namespace beast {
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template<class Protocol>
|
||||||
|
class stranded_stream_base
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
net::basic_stream_socket<Protocol> socket_;
|
||||||
|
|
||||||
|
template<class... Args>
|
||||||
|
explicit
|
||||||
|
stranded_stream_base(Args&&... args)
|
||||||
|
: socket_(std::forward<Args>(args)...)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
stranded_stream_base(stranded_stream_base&&) = default;
|
||||||
|
stranded_stream_base& operator=(stranded_stream_base&&) = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // detail
|
||||||
|
} // beast
|
||||||
|
} // boost
|
||||||
|
|
||||||
|
#endif
|
433
include/boost/beast/core/stranded_stream.hpp
Normal file
433
include/boost/beast/core/stranded_stream.hpp
Normal file
@ -0,0 +1,433 @@
|
|||||||
|
//
|
||||||
|
// 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 <boost/beast/core/detail/config.hpp>
|
||||||
|
#include <boost/beast/core/stream_traits.hpp>
|
||||||
|
#include <boost/beast/core/detail/stranded_stream.hpp>
|
||||||
|
#include <boost/beast/core/detail/type_traits.hpp>
|
||||||
|
#include <boost/asio/async_result.hpp>
|
||||||
|
#include <boost/asio/basic_stream_socket.hpp>
|
||||||
|
#include <boost/asio/connect.hpp>
|
||||||
|
#include <boost/asio/executor.hpp>
|
||||||
|
#include <boost/core/empty_value.hpp>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
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 <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1322r0.html">[P1322R0]</a>
|
||||||
|
<em>Networking TS enhancement to enable custom I/O executors</em>
|
||||||
|
*/
|
||||||
|
template<
|
||||||
|
class Protocol,
|
||||||
|
class Executor = beast::executor_type<net::basic_stream_socket<Protocol>>
|
||||||
|
>
|
||||||
|
class stranded_stream
|
||||||
|
#ifndef BOOST_BEAST_DOXYGEN
|
||||||
|
: private detail::stranded_stream_base<Protocol>
|
||||||
|
, private boost::empty_value<Executor>
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
// Restricted until P1322R0 is incorporated into Boost.Asio.
|
||||||
|
static_assert(
|
||||||
|
std::is_convertible<decltype(
|
||||||
|
std::declval<Executor const&>().context()),
|
||||||
|
net::io_context&>::value,
|
||||||
|
"Only net::io_context is currently supported for executor_type::context()");
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// The type of the executor associated with the object.
|
||||||
|
using executor_type = Executor;
|
||||||
|
|
||||||
|
/// The type of the next layer.
|
||||||
|
using next_layer_type = net::basic_stream_socket<Protocol>;
|
||||||
|
|
||||||
|
/// The protocol type.
|
||||||
|
using protocol_type = Protocol;
|
||||||
|
|
||||||
|
/// The endpoint type.
|
||||||
|
using endpoint_type = typename Protocol::endpoint;
|
||||||
|
|
||||||
|
/** 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
|
||||||
|
<em>ExecutionContext</em>, which the stream will use to dispatch
|
||||||
|
handlers for any asynchronous operations performed on the socket.
|
||||||
|
Currently, the only supported type for `ctx` is `net::io_context`.
|
||||||
|
|
||||||
|
@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<ExecutionContext&, net::execution_context&>::value` is `true`, and
|
||||||
|
@li `std::is_constructible<executor_type, typename ExecutionContext::executor_type>::value` is `true`.
|
||||||
|
|
||||||
|
@see http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1322r0.html
|
||||||
|
*/
|
||||||
|
template<
|
||||||
|
class ExecutionContext,
|
||||||
|
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<Protocol>(
|
||||||
|
ctx, std::forward<Args>(args)...)
|
||||||
|
, boost::empty_value<Executor>(
|
||||||
|
boost::empty_init_t{}, ctx.get_executor())
|
||||||
|
{
|
||||||
|
// Restriction is necessary until Asio fully supports P1322R0
|
||||||
|
static_assert(
|
||||||
|
std::is_same<ExecutionContext, net::io_context>::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<class... Args>
|
||||||
|
explicit
|
||||||
|
stranded_stream(executor_type const& ex, Args&&... args)
|
||||||
|
: detail::stranded_stream_base<Protocol>(
|
||||||
|
ex.context(), std::forward<Args>(args)...)
|
||||||
|
, boost::empty_value<Executor>(
|
||||||
|
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<class ConnectHandler>
|
||||||
|
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<class MutableBufferSequence>
|
||||||
|
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<class MutableBufferSequence>
|
||||||
|
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<class MutableBufferSequence, class ReadHandler>
|
||||||
|
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<class ConstBufferSequence>
|
||||||
|
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<class ConstBufferSequence>
|
||||||
|
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<class ConstBufferSequence, class WriteHandler>
|
||||||
|
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
|
@ -60,6 +60,7 @@ add_executable (tests-beast-core
|
|||||||
span.cpp
|
span.cpp
|
||||||
static_buffer.cpp
|
static_buffer.cpp
|
||||||
static_string.cpp
|
static_string.cpp
|
||||||
|
stranded_stream.cpp
|
||||||
stream_traits.cpp
|
stream_traits.cpp
|
||||||
string.cpp
|
string.cpp
|
||||||
string_param.cpp
|
string_param.cpp
|
||||||
|
@ -48,6 +48,7 @@ local SOURCES =
|
|||||||
span.cpp
|
span.cpp
|
||||||
static_buffer.cpp
|
static_buffer.cpp
|
||||||
static_string.cpp
|
static_string.cpp
|
||||||
|
stranded_stream.cpp
|
||||||
stream_traits.cpp
|
stream_traits.cpp
|
||||||
string.cpp
|
string.cpp
|
||||||
string_param.cpp
|
string_param.cpp
|
||||||
|
81
test/beast/core/stranded_stream.cpp
Normal file
81
test/beast/core/stranded_stream.cpp
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) 2018 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||||
|
//
|
||||||
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
//
|
||||||
|
// Official repository: https://github.com/boostorg/beast
|
||||||
|
//
|
||||||
|
|
||||||
|
// Test that header file is self-contained.
|
||||||
|
#include <boost/beast/core/stranded_stream.hpp>
|
||||||
|
|
||||||
|
#include "stream_tests.hpp"
|
||||||
|
|
||||||
|
#include <boost/beast/_experimental/unit_test/suite.hpp>
|
||||||
|
#include <boost/asio/ip/tcp.hpp>
|
||||||
|
|
||||||
|
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<tcp, ex_t> s1(ioc);
|
||||||
|
stranded_stream<tcp, ex_t> s2(ex);
|
||||||
|
stranded_stream<tcp, ex_t> s3(ioc, tcp::v4());
|
||||||
|
stranded_stream<tcp, ex_t> 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<tcp, ex_t> s1(ex);
|
||||||
|
stranded_stream<tcp, ex_t> s2(ex, tcp::v4());
|
||||||
|
stranded_stream<tcp, ex_t> 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<stranded_stream<tcp, ex_t>>();
|
||||||
|
test_async_stream<stranded_stream<tcp, ex_t>>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
testJavadocs()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void
|
||||||
|
run()
|
||||||
|
{
|
||||||
|
testStream();
|
||||||
|
testJavadocs();
|
||||||
|
pass();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
BEAST_DEFINE_TESTSUITE(beast,core,stranded_stream);
|
||||||
|
|
||||||
|
} // beast
|
||||||
|
} // boost
|
@ -20,6 +20,40 @@
|
|||||||
namespace boost {
|
namespace boost {
|
||||||
namespace beast {
|
namespace beast {
|
||||||
|
|
||||||
|
template<class SyncReadStream>
|
||||||
|
void
|
||||||
|
test_sync_read_stream()
|
||||||
|
{
|
||||||
|
BOOST_ASSERT(is_sync_read_stream<SyncReadStream>::value);
|
||||||
|
BEAST_EXPECT(static_cast<
|
||||||
|
std::size_t(SyncReadStream::*)(net::mutable_buffer const&)>(
|
||||||
|
&SyncReadStream::template read_some<net::mutable_buffer>));
|
||||||
|
BEAST_EXPECT(static_cast<
|
||||||
|
std::size_t(SyncReadStream::*)(net::mutable_buffer const&, error_code&)>(
|
||||||
|
&SyncReadStream::template read_some<net::mutable_buffer>));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class SyncWriteStream>
|
||||||
|
void
|
||||||
|
test_sync_write_stream()
|
||||||
|
{
|
||||||
|
BOOST_ASSERT(is_sync_write_stream<SyncWriteStream>::value);
|
||||||
|
BEAST_EXPECT(static_cast<
|
||||||
|
std::size_t(SyncWriteStream::*)(net::const_buffer const&)>(
|
||||||
|
&SyncWriteStream::template write_some<net::const_buffer>));
|
||||||
|
BEAST_EXPECT(static_cast<
|
||||||
|
std::size_t(SyncWriteStream::*)(net::const_buffer const&, error_code&)>(
|
||||||
|
&SyncWriteStream::template write_some<net::const_buffer>));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class SyncReadStream>
|
||||||
|
void
|
||||||
|
test_sync_stream()
|
||||||
|
{
|
||||||
|
test_sync_read_stream<SyncReadStream>();
|
||||||
|
test_sync_write_stream<SyncReadStream>();
|
||||||
|
}
|
||||||
|
|
||||||
template<class AsyncReadStream>
|
template<class AsyncReadStream>
|
||||||
void
|
void
|
||||||
test_async_read_stream()
|
test_async_read_stream()
|
||||||
|
Reference in New Issue
Block a user