summaryrefslogtreecommitdiff
path: root/boost/beast/experimental
diff options
context:
space:
mode:
Diffstat (limited to 'boost/beast/experimental')
-rw-r--r--boost/beast/experimental/core/detail/impl/timeout_service.ipp181
-rw-r--r--boost/beast/experimental/core/detail/service_base.hpp50
-rw-r--r--boost/beast/experimental/core/detail/timeout_service.hpp124
-rw-r--r--boost/beast/experimental/core/detail/timeout_work_guard.hpp73
-rw-r--r--boost/beast/experimental/core/impl/timeout_service.ipp31
-rw-r--r--boost/beast/experimental/core/impl/timeout_socket.hpp207
-rw-r--r--boost/beast/experimental/core/timeout_service.hpp40
-rw-r--r--boost/beast/experimental/core/timeout_socket.hpp240
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