diff options
Diffstat (limited to 'boost/beast/experimental')
8 files changed, 946 insertions, 0 deletions
diff --git a/boost/beast/experimental/core/detail/impl/timeout_service.ipp b/boost/beast/experimental/core/detail/impl/timeout_service.ipp new file mode 100644 index 0000000000..fd1427bda7 --- /dev/null +++ b/boost/beast/experimental/core/detail/impl/timeout_service.ipp @@ -0,0 +1,181 @@ +// +// 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_IMPL_TIMEOUT_SERVICE_IPP +#define BOOST_BEAST_CORE_DETAIL_IMPL_TIMEOUT_SERVICE_IPP + +namespace boost { +namespace beast { +namespace detail { + +//------------------------------------------------------------------------------ + +inline +timeout_object:: +timeout_object(boost::asio::io_context& ioc) + : svc_(boost::asio::use_service<timeout_service>(ioc)) +{ +} + +//------------------------------------------------------------------------------ + +inline +timeout_service:: +timeout_service(boost::asio::io_context& ctx) + : service_base(ctx) + , strand_(ctx.get_executor()) + , timer_(ctx) +{ +} + +inline +void +timeout_service:: +on_work_started(timeout_object& obj) +{ + std::lock_guard<std::mutex> lock(m_); + BOOST_VERIFY(++obj.outstanding_work_ == 1); + insert(obj, *fresh_); + if(++count_ == 1) + do_async_wait(); +} + +inline +void +timeout_service:: +on_work_complete(timeout_object& obj) +{ + std::lock_guard<std::mutex> lock(m_); + remove(obj); +} + +inline +void +timeout_service:: +on_work_stopped(timeout_object& obj) +{ + std::lock_guard<std::mutex> lock(m_); + BOOST_ASSERT(count_ > 0); + BOOST_VERIFY(--obj.outstanding_work_ == 0); + if(obj.list_ != nullptr) + remove(obj); + if(--count_ == 0) + timer_.cancel(); +} + +inline +void +timeout_service:: +set_option(std::chrono::seconds n) +{ + interval_ = n; +} + +//------------------------------------------------------------------------------ + +// Precondition: caller holds the mutex +inline +void +timeout_service:: +insert(timeout_object& obj, list_type& list) +{ + BOOST_ASSERT(obj.list_ == nullptr); + list.push_back(&obj); // can throw + obj.list_ = &list; + obj.pos_ = list.size(); +} + +// Precondition: caller holds the mutex +inline +void +timeout_service:: +remove(timeout_object& obj) +{ + BOOST_ASSERT(obj.list_ != nullptr); + BOOST_ASSERT( + obj.list_ == stale_ || + obj.list_ == fresh_); + BOOST_ASSERT(obj.list_->size() > 0); + auto& list = *obj.list_; + auto const n = list.size() - 1; + if(obj.pos_ != n) + { + auto other = list[n]; + list[obj.pos_] = other; + other->pos_ = obj.pos_; + } + obj.list_ = nullptr; + list.resize(n); +} + +inline +void +timeout_service:: +do_async_wait() +{ + timer_.expires_after(interval_); + timer_.async_wait( + boost::asio::bind_executor( + strand_, + [this](error_code ec) + { + this->on_timer(ec); + })); +} + +inline +void +timeout_service:: +on_timer(error_code ec) +{ + if(ec == boost::asio::error::operation_aborted) + { + BOOST_ASSERT(fresh_->empty()); + BOOST_ASSERT(stale_->empty()); + return; + } + + { + std::lock_guard<std::mutex> lock(m_); + if(! stale_->empty()) + { + for(auto obj : *stale_) + { + obj->list_ = nullptr; + obj->on_timeout(); + } + stale_->clear(); + } + std::swap(fresh_, stale_); + } + + do_async_wait(); +} + +//------------------------------------------------------------------------------ + +inline +void +timeout_service:: +shutdown() noexcept +{ + boost::asio::post( + boost::asio::bind_executor( + strand_, + [this]() + { + timer_.cancel(); + })); +} + +} // detail +} // beast +} // boost + +#endif diff --git a/boost/beast/experimental/core/detail/service_base.hpp b/boost/beast/experimental/core/detail/service_base.hpp new file mode 100644 index 0000000000..278db3f71d --- /dev/null +++ b/boost/beast/experimental/core/detail/service_base.hpp @@ -0,0 +1,50 @@ +// +// 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_SERVICE_BASE_HPP +#define BOOST_BEAST_CORE_DETAIL_SERVICE_BASE_HPP + +#include <boost/asio/execution_context.hpp> + +namespace boost { +namespace beast { +namespace detail { + +template<class T> +class service_id : public boost::asio::execution_context::id +{ +}; + +template<class T> +class service_base + : public boost::asio::execution_context::service +{ +protected: + boost::asio::execution_context& ctx_; + +public: + static service_id<T> id; + + explicit + service_base(boost::asio::execution_context& ctx) + : boost::asio::execution_context::service(ctx) + , ctx_(ctx) + { + } +}; + +template<class T> +service_id<T> +service_base<T>::id; + +} // detail +} // beast +} // boost + +#endif diff --git a/boost/beast/experimental/core/detail/timeout_service.hpp b/boost/beast/experimental/core/detail/timeout_service.hpp new file mode 100644 index 0000000000..b32cedda00 --- /dev/null +++ b/boost/beast/experimental/core/detail/timeout_service.hpp @@ -0,0 +1,124 @@ +// +// 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_TIMEOUT_SERVICE_HPP +#define BOOST_BEAST_CORE_DETAIL_TIMEOUT_SERVICE_HPP + +#include <boost/beast/core/error.hpp> +#include <boost/beast/experimental/core/detail/service_base.hpp> +#include <boost/assert.hpp> +#include <boost/core/ignore_unused.hpp> +#include <boost/asio/bind_executor.hpp> +#include <boost/asio/executor.hpp> +#include <boost/asio/io_context.hpp> +#include <boost/asio/post.hpp> +#include <boost/asio/steady_timer.hpp> +#include <boost/asio/strand.hpp> +#include <chrono> +#include <cstdlib> +#include <mutex> +#include <utility> +#include <vector> + +namespace boost { +namespace beast { +namespace detail { + +//------------------------------------------------------------------------------ + +class timeout_service; + +class timeout_object +{ + friend class timeout_service; + + using list_type = std::vector<timeout_object*>; + + timeout_service& svc_; + std::size_t pos_; + list_type* list_ = nullptr; + char outstanding_work_ = 0; + +public: + timeout_object() = delete; + timeout_object(timeout_object&&) = delete; + timeout_object(timeout_object const&) = delete; + timeout_object& operator=(timeout_object&&) = delete; + timeout_object& operator=(timeout_object const&) = delete; + + // VFALCO should be execution_context + explicit + timeout_object(boost::asio::io_context& ioc); + + timeout_service& + service() const + { + return svc_; + } + + virtual void on_timeout() = 0; +}; + +//------------------------------------------------------------------------------ + +class timeout_service + : public service_base<timeout_service> +{ +public: + using key_type = timeout_service; + + // VFALCO Should be execution_context + explicit + timeout_service(boost::asio::io_context& ctx); + + void + on_work_started(timeout_object& obj); + + void + on_work_complete(timeout_object& obj); + + void + on_work_stopped(timeout_object& obj); + + void + set_option(std::chrono::seconds n); + +private: + friend class timeout_object; + + using list_type = std::vector<timeout_object*>; + + void insert(timeout_object& obj, list_type& list); + void remove(timeout_object& obj); + void do_async_wait(); + void on_timer(error_code ec); + + virtual void shutdown() noexcept override; + + boost::asio::strand< + boost::asio::io_context::executor_type> strand_; + + std::mutex m_; + list_type list_[2]; + list_type* fresh_ = &list_[0]; + list_type* stale_ = &list_[1]; + std::size_t count_ = 0; + boost::asio::steady_timer timer_; + std::chrono::seconds interval_{30ul}; +}; + +//------------------------------------------------------------------------------ + +} // detail +} // beast +} // boost + +#include <boost/beast/experimental/core/detail/impl/timeout_service.ipp> + +#endif diff --git a/boost/beast/experimental/core/detail/timeout_work_guard.hpp b/boost/beast/experimental/core/detail/timeout_work_guard.hpp new file mode 100644 index 0000000000..463567ae78 --- /dev/null +++ b/boost/beast/experimental/core/detail/timeout_work_guard.hpp @@ -0,0 +1,73 @@ +// +// 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_TIMEOUT_WORK_GUARD_HPP +#define BOOST_BEAST_CORE_DETAIL_TIMEOUT_WORK_GUARD_HPP + +#include <boost/beast/experimental/core/detail/timeout_service.hpp> +#include <boost/assert.hpp> +#include <boost/core/exchange.hpp> + +namespace boost { +namespace beast { +namespace detail { + +class timeout_work_guard +{ + timeout_object* obj_; + +public: + timeout_work_guard(timeout_work_guard const&) = delete; + timeout_work_guard& operator=(timeout_work_guard&&) = delete; + timeout_work_guard& operator=(timeout_work_guard const&) = delete; + + ~timeout_work_guard() + { + reset(); + } + + timeout_work_guard(timeout_work_guard&& other) + : obj_(boost::exchange(other.obj_, nullptr)) + { + } + + explicit + timeout_work_guard(timeout_object& obj) + : obj_(&obj) + { + obj_->service().on_work_started(*obj_); + } + + bool + owns_work() const + { + return obj_ != nullptr; + } + + void + reset() + { + if(obj_) + obj_->service().on_work_stopped(*obj_); + } + + void + complete() + { + BOOST_ASSERT(obj_ != nullptr); + obj_->service().on_work_complete(*obj_); + obj_ = nullptr; + } +}; + +} // detail +} // beast +} // boost + +#endif diff --git a/boost/beast/experimental/core/impl/timeout_service.ipp b/boost/beast/experimental/core/impl/timeout_service.ipp new file mode 100644 index 0000000000..4da0eed115 --- /dev/null +++ b/boost/beast/experimental/core/impl/timeout_service.ipp @@ -0,0 +1,31 @@ +// +// Copyright (c) 2018 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/boostorg/beast +// + +#ifndef BOOST_BEAST_CORE_IMPL_TIMEOUT_SERVICE_HPP +#define BOOST_BEAST_CORE_IMPL_TIMEOUT_SERVICE_HPP + +#include <boost/beast/experimental/core/detail/timeout_service.hpp> + +namespace boost { +namespace beast { + +inline +void +set_timeout_service_options( + boost::asio::io_context& ioc, + std::chrono::seconds interval) +{ + boost::asio::use_service< + detail::timeout_service>(ioc).set_option(interval); +} + +} // beast +} // boost + +#endif diff --git a/boost/beast/experimental/core/impl/timeout_socket.hpp b/boost/beast/experimental/core/impl/timeout_socket.hpp new file mode 100644 index 0000000000..8c5a7d7427 --- /dev/null +++ b/boost/beast/experimental/core/impl/timeout_socket.hpp @@ -0,0 +1,207 @@ +// +// Copyright (c) 2018 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/boostorg/beast +// + +#ifndef BOOST_BEAST_CORE_IMPL_TIMOUT_SOCKET_HPP +#define BOOST_BEAST_CORE_IMPL_TIMOUT_SOCKET_HPP + +#include <boost/beast/core/bind_handler.hpp> +#include <boost/beast/core/type_traits.hpp> +#include <boost/beast/experimental/core/detail/timeout_work_guard.hpp> +#include <boost/asio/executor_work_guard.hpp> +#include <memory> +#include <utility> + +namespace boost { +namespace beast { + +template<class Protocol, class Executor> +template<class Handler> +class basic_timeout_socket<Protocol, Executor>::async_op +{ + Handler h_; + basic_timeout_socket& s_; + detail::timeout_work_guard work_; + +public: + async_op(async_op&&) = default; + async_op(async_op const&) = delete; + + template<class Buffers, class DeducedHandler> + async_op( + Buffers const& b, + DeducedHandler&& h, + basic_timeout_socket& s, + std::true_type) + : h_(std::forward<DeducedHandler>(h)) + , s_(s) + , work_(s.rd_timer_) + { + s_.sock_.async_read_some(b, std::move(*this)); + } + + template<class Buffers, class DeducedHandler> + async_op( + Buffers const& b, + DeducedHandler&& h, + basic_timeout_socket& s, + std::false_type) + : h_(std::forward<DeducedHandler>(h)) + , s_(s) + , work_(s.wr_timer_) + { + s_.sock_.async_write_some(b, std::move(*this)); + } + + using allocator_type = + boost::asio::associated_allocator_t<Handler>; + + allocator_type + get_allocator() const noexcept + { + return (boost::asio::get_associated_allocator)(h_); + } + + using executor_type = + boost::asio::associated_executor_t<Handler, decltype( + std::declval<basic_timeout_socket<Protocol>&>().get_executor())>; + + executor_type + get_executor() const noexcept + { + return (boost::asio::get_associated_executor)( + h_, s_.get_executor()); + } + + friend + bool asio_handler_is_continuation(async_op* op) + { + using boost::asio::asio_handler_is_continuation; + return asio_handler_is_continuation( + std::addressof(op->h_)); + } + + template<class Function> + friend + void asio_handler_invoke(Function&& f, async_op* op) + { + using boost::asio::asio_handler_invoke; + asio_handler_invoke(f, std::addressof(op->h_)); + } + + void + operator()(error_code ec, std::size_t bytes_transferred) + { + if(s_.expired_) + { + BOOST_ASSERT(ec == boost::asio::error::operation_aborted); + ec = boost::asio::error::timed_out; + } + else + { + work_.complete(); + } + h_(ec, bytes_transferred); + } +}; + +//------------------------------------------------------------------------------ + +template<class Protocol, class Executor> +basic_timeout_socket<Protocol, Executor>:: +timer:: +timer(basic_timeout_socket& s) + : detail::timeout_object(s.ex_.context()) + , s_(s) +{ +} + +template<class Protocol, class Executor> +auto +basic_timeout_socket<Protocol, Executor>:: +timer:: +operator=(timer&&) + -> timer& +{ + return *this; +} + +template<class Protocol, class Executor> +void +basic_timeout_socket<Protocol, Executor>:: +timer:: +on_timeout() +{ + boost::asio::post( + s_.ex_, + [this]() + { + s_.expired_ = true; + s_.sock_.cancel(); + }); +} + +//------------------------------------------------------------------------------ + +template<class Protocol, class Executor> +template<class ExecutionContext, class> +basic_timeout_socket<Protocol, Executor>:: +basic_timeout_socket(ExecutionContext& ctx) + : ex_(ctx.get_executor()) + , rd_timer_(*this) + , wr_timer_(*this) + , sock_(ctx) +{ +} + +template<class Protocol, class Executor> +template<class MutableBufferSequence, class ReadHandler> +BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void(boost::system::error_code, std::size_t)) +basic_timeout_socket<Protocol, Executor>:: +async_read_some( + MutableBufferSequence const& buffers, + ReadHandler&& handler) +{ + static_assert(boost::asio::is_mutable_buffer_sequence< + MutableBufferSequence>::value, + "MutableBufferSequence requirements not met"); + BOOST_BEAST_HANDLER_INIT( + ReadHandler, void(error_code, std::size_t)); + async_op<BOOST_ASIO_HANDLER_TYPE(ReadHandler, + void(error_code, std::size_t))>(buffers, + std::forward<ReadHandler>(handler), *this, + std::true_type{}); + return init.result.get(); +} + +template<class Protocol, class Executor> +template<class ConstBufferSequence, class WriteHandler> +BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + void(boost::system::error_code, std::size_t)) +basic_timeout_socket<Protocol, Executor>:: +async_write_some( + ConstBufferSequence const& buffers, + WriteHandler&& handler) +{ + static_assert(boost::asio::is_const_buffer_sequence< + ConstBufferSequence>::value, + "ConstBufferSequence requirements not met"); + BOOST_BEAST_HANDLER_INIT( + WriteHandler, void(error_code, std::size_t)); + async_op<BOOST_ASIO_HANDLER_TYPE(WriteHandler, + void(error_code, std::size_t))>(buffers, + std::forward<WriteHandler>(handler), *this, + std::false_type{}); + return init.result.get(); +} + +} // beast +} // boost + +#endif diff --git a/boost/beast/experimental/core/timeout_service.hpp b/boost/beast/experimental/core/timeout_service.hpp new file mode 100644 index 0000000000..2a5da2b887 --- /dev/null +++ b/boost/beast/experimental/core/timeout_service.hpp @@ -0,0 +1,40 @@ +// +// 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_TIMEOUT_SERVICE_HPP +#define BOOST_BEAST_CORE_TIMEOUT_SERVICE_HPP + +//#include <boost/asio/execution_context.hpp> +#include <boost/asio/io_context.hpp> +#include <chrono> + +namespace boost { +namespace beast { + +/** Set timeout service options in an execution context. + + This changes the time interval for all timeouts associated + with the execution context. The option must be set before any + timeout objects are constructed. + + @param ctx The execution context. + + @param interval The approximate amount of time until a timeout occurs. +*/ +void +set_timeout_service_options( + boost::asio::io_context& ctx, // VFALCO should be execution_context + std::chrono::seconds interval); + +} // beast +} // boost + +#include <boost/beast/experimental/core/impl/timeout_service.ipp> + +#endif diff --git a/boost/beast/experimental/core/timeout_socket.hpp b/boost/beast/experimental/core/timeout_socket.hpp new file mode 100644 index 0000000000..b2c2a22ea5 --- /dev/null +++ b/boost/beast/experimental/core/timeout_socket.hpp @@ -0,0 +1,240 @@ +// +// 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_TIMEOUT_SOCKET_HPP +#define BOOST_BEAST_CORE_TIMEOUT_SOCKET_HPP + +#include <boost/beast/core/detail/config.hpp> +#include <boost/beast/core/error.hpp> +#include <boost/beast/core/type_traits.hpp> +#include <boost/beast/experimental/core/detail/timeout_service.hpp> +#include <boost/asio/async_result.hpp> +#include <boost/asio/basic_stream_socket.hpp> +#include <boost/asio/executor.hpp> +#include <chrono> + +namespace boost { +namespace asio { +namespace ip { +class tcp; +} // ip +} // asio +} // boost + +namespace boost { +namespace beast { + +/** A socket wrapper which automatically times out on asynchronous reads. + + This wraps a normal stream socket and implements a simple and efficient + timeout for asynchronous read operations. + + @note Meets the requirements of @b AsyncReadStream and @b AsyncWriteStream +*/ +template< + class Protocol, + class Executor = boost::asio::executor +> +class basic_timeout_socket +{ + template<class> class async_op; + + class timer : public detail::timeout_object + { + basic_timeout_socket& s_; + + public: + explicit timer(basic_timeout_socket& s); + timer& operator=(timer&& other); + void on_timeout() override; + }; + + Executor ex_; // must come first + timer rd_timer_; + timer wr_timer_; + boost::asio::basic_stream_socket<Protocol> sock_; + bool expired_ = false; + +public: + /// The type of the next layer. + using next_layer_type = boost::asio::basic_stream_socket<Protocol>; + + /// The type of the lowest layer. + using lowest_layer_type = get_lowest_layer<next_layer_type>; + + /// The protocol used by the stream. + using protocol_type = Protocol; + + /// The type of the executor associated with the object. + using executor_type = Executor; + + // VFALCO we only support default-construction + // of the contained socket for now. + // This constructor needs a protocol parameter. + // + /** Constructor + */ + template<class ExecutionContext +#if ! BOOST_BEAST_DOXYGEN + , class = typename std::enable_if< + std::is_convertible< + ExecutionContext&, + boost::asio::execution_context&>::value && + std::is_constructible< + executor_type, + typename ExecutionContext::executor_type>::value + >::type +#endif + > + explicit + basic_timeout_socket(ExecutionContext& ctx); + + //-------------------------------------------------------------------------- + + /** Get the executor associated with the object. + + This function may be used to obtain the executor object that the + stream uses to dispatch handlers for asynchronous operations. + + @return A copy of the executor that stream will use to dispatch handlers. + */ + executor_type + get_executor() const noexcept + { + return ex_; + } + + /** Get a reference to the next layer + + This function returns a reference to the next layer + in a stack of stream layers. + + @return A reference to the next layer in the stack of + stream layers. + */ + next_layer_type& + next_layer() + { + return sock_; + } + + /** Get a reference to the next layer + + This function returns a reference to the next layer in a + stack of stream layers. + + @return A reference to the next layer in the stack of + stream layers. + */ + next_layer_type const& + next_layer() const + { + return sock_; + } + + /** Get a reference to the lowest layer + + This function returns a reference to the lowest layer + in a stack of stream layers. + + @return A reference to the lowest layer in the stack of + stream layers. + */ + lowest_layer_type& + lowest_layer() + { + return sock_.lowest_layer(); + } + + /** Get a reference to the lowest layer + + This function returns a reference to the lowest layer + in a stack of stream layers. + + @return A reference to the lowest layer in the stack of + stream layers. Ownership is not transferred to the caller. + */ + lowest_layer_type const& + lowest_layer() const + { + return sock_.lowest_layer(); + } + + //-------------------------------------------------------------------------- + + /** Start an asynchronous read. + + This function is used to asynchronously read data from the stream socket. + The function call always returns immediately. + + @param buffers One or more buffers into which the data will be read. + Although the buffers object may be copied as necessary, ownership of the + underlying memory blocks is retained by the caller, which must guarantee + that they remain valid until the handler is called. + + @param handler The handler to be called when the read operation completes. + Copies will be made of the handler as required. The function signature of + the handler must be: + @code void handler( + const boost::system::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 + boost::asio::io_context::post(). + */ + template<class MutableBufferSequence, class ReadHandler> + BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void(boost::system::error_code, std::size_t)) + async_read_some( + MutableBufferSequence const& buffers, + ReadHandler&& handler); + + /** Start an asynchronous write. + + This function is used to asynchronously write data to the stream socket. + The function call always returns immediately. + + @param buffers One or more data buffers to be written to the socket. + Although the buffers object may be copied as necessary, ownership of the + underlying memory blocks is retained by the caller, which must guarantee + that they remain valid until the handler is called. + + @param handler The handler to be called when the write operation completes. + Copies will be made of the handler as required. The function signature of + the handler must be: + @code void handler( + const boost::system::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 + boost::asio::io_context::post(). + */ + template<class ConstBufferSequence, class WriteHandler> + BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + void(boost::system::error_code, std::size_t)) + async_write_some( + ConstBufferSequence const& buffers, + WriteHandler&& handler); +}; + +/// A TCP/IP socket wrapper which has a built-in asynchronous timeout +using timeout_socket = basic_timeout_socket< + boost::asio::ip::tcp, + boost::asio::io_context::executor_type>; + +} // beast +} // boost + +#include <boost/beast/experimental/core/impl/timeout_socket.hpp> + +#endif |