mirror of
https://github.com/boostorg/beast.git
synced 2025-08-03 23:04:35 +02:00
Add experimental timeout_socket:
This is a socket wrapper which has a built-in timeout feature on reads and writes.
This commit is contained in:
@@ -1,3 +1,9 @@
|
|||||||
|
Version 187:
|
||||||
|
|
||||||
|
* Add experimental timeout_socket
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
Version 186:
|
Version 186:
|
||||||
|
|
||||||
* basic_fields uses intrusive base hooks
|
* basic_fields uses intrusive base hooks
|
||||||
|
@@ -27,12 +27,16 @@
|
|||||||
|
|
||||||
* ([issue 1091]) Fix timer on websocket upgrade in examples
|
* ([issue 1091]) Fix timer on websocket upgrade in examples
|
||||||
|
|
||||||
* ([issue 1270]) `basic_fields` uses intrusive base hooks
|
* ([issue 1270]) [link beast.ref.boost__beast__http__basic_fields `basic_fields`] uses intrusive base hooks
|
||||||
|
|
||||||
* ([issue 1267]) Fix parsing of out-of-bounds hex values
|
* ([issue 1267]) Fix parsing of out-of-bounds hex values
|
||||||
|
|
||||||
* Workaround for http-server-fast and libstdc++
|
* Workaround for http-server-fast and libstdc++
|
||||||
|
|
||||||
|
[*Experimental]
|
||||||
|
|
||||||
|
* Add [link beast.ref.boost__beast__timeout_socket `timeout_socket`]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@@ -302,16 +302,19 @@
|
|||||||
<entry valign="top">
|
<entry valign="top">
|
||||||
<bridgehead renderas="sect3">Classes</bridgehead>
|
<bridgehead renderas="sect3">Classes</bridgehead>
|
||||||
<simplelist type="vert" columns="1">
|
<simplelist type="vert" columns="1">
|
||||||
|
<member><link linkend="beast.ref.boost__beast__basic_timeout_socket">basic_timeout_socket</link></member>
|
||||||
<member><link linkend="beast.ref.boost__beast__flat_stream">flat_stream</link></member>
|
<member><link linkend="beast.ref.boost__beast__flat_stream">flat_stream</link></member>
|
||||||
<member><link linkend="beast.ref.boost__beast__ssl_stream">ssl_stream</link></member>
|
<member><link linkend="beast.ref.boost__beast__ssl_stream">ssl_stream</link></member>
|
||||||
<member><link linkend="beast.ref.boost__beast__http__icy_stream">http::icy_stream</link></member>
|
<member><link linkend="beast.ref.boost__beast__http__icy_stream">http::icy_stream</link></member>
|
||||||
<member><link linkend="beast.ref.boost__beast__test__fail_count">test::fail_count</link></member>
|
<member><link linkend="beast.ref.boost__beast__test__fail_count">test::fail_count</link></member>
|
||||||
<member><link linkend="beast.ref.boost__beast__test__stream">test::stream</link></member>
|
<member><link linkend="beast.ref.boost__beast__test__stream">test::stream</link></member>
|
||||||
|
<member><link linkend="beast.ref.boost__beast__timeout_socket">timeout_socket</link></member>
|
||||||
</simplelist>
|
</simplelist>
|
||||||
</entry>
|
</entry>
|
||||||
<entry valign="top">
|
<entry valign="top">
|
||||||
<bridgehead renderas="sect3">Functions</bridgehead>
|
<bridgehead renderas="sect3">Functions</bridgehead>
|
||||||
<simplelist type="vert" columns="1">
|
<simplelist type="vert" columns="1">
|
||||||
|
<member><link linkend="beast.ref.boost__beast__set_timeout_service_options">set_timeout_service_options</link></member>
|
||||||
<member><link linkend="beast.ref.boost__beast__test__connect">test::connect</link></member>
|
<member><link linkend="beast.ref.boost__beast__test__connect">test::connect</link></member>
|
||||||
</simplelist>
|
</simplelist>
|
||||||
</entry>
|
</entry>
|
||||||
|
@@ -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
|
@@ -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
|
124
include/boost/beast/experimental/core/detail/timeout_service.hpp
Normal file
124
include/boost/beast/experimental/core/detail/timeout_service.hpp
Normal file
@@ -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
|
@@ -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
|
@@ -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
|
207
include/boost/beast/experimental/core/impl/timeout_socket.hpp
Normal file
207
include/boost/beast/experimental/core/impl/timeout_socket.hpp
Normal file
@@ -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
|
40
include/boost/beast/experimental/core/timeout_service.hpp
Normal file
40
include/boost/beast/experimental/core/timeout_service.hpp
Normal file
@@ -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
|
240
include/boost/beast/experimental/core/timeout_socket.hpp
Normal file
240
include/boost/beast/experimental/core/timeout_socket.hpp
Normal file
@@ -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
|
@@ -22,6 +22,9 @@ add_executable (tests-beast-experimental
|
|||||||
icy_stream.cpp
|
icy_stream.cpp
|
||||||
ssl_stream.cpp
|
ssl_stream.cpp
|
||||||
stream.cpp
|
stream.cpp
|
||||||
|
timeout_socket.cpp
|
||||||
|
timeout_service.cpp
|
||||||
|
timeout_work_guard.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
set_property(TARGET tests-beast-experimental PROPERTY FOLDER "tests")
|
set_property(TARGET tests-beast-experimental PROPERTY FOLDER "tests")
|
||||||
|
@@ -13,6 +13,9 @@ local SOURCES =
|
|||||||
icy_stream.cpp
|
icy_stream.cpp
|
||||||
ssl_stream.cpp
|
ssl_stream.cpp
|
||||||
stream.cpp
|
stream.cpp
|
||||||
|
timeout_socket.cpp
|
||||||
|
timeout_service.cpp
|
||||||
|
timeout_work_guard.cpp
|
||||||
;
|
;
|
||||||
|
|
||||||
local RUN_TESTS ;
|
local RUN_TESTS ;
|
||||||
|
35
test/beast/experimental/timeout_service.cpp
Normal file
35
test/beast/experimental/timeout_service.cpp
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) 2016-2017 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/experimental/core/timeout_service.hpp>
|
||||||
|
|
||||||
|
#include <boost/beast/unit_test/suite.hpp>
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
namespace beast {
|
||||||
|
|
||||||
|
class timeout_service_test
|
||||||
|
: public beast::unit_test::suite
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void
|
||||||
|
run() override
|
||||||
|
{
|
||||||
|
boost::asio::io_context ctx;
|
||||||
|
set_timeout_service_options(ctx,
|
||||||
|
std::chrono::seconds(1));
|
||||||
|
pass();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
BEAST_DEFINE_TESTSUITE(beast,core,timeout_service);
|
||||||
|
|
||||||
|
} // beast
|
||||||
|
} // boost
|
181
test/beast/experimental/timeout_socket.cpp
Normal file
181
test/beast/experimental/timeout_socket.cpp
Normal file
@@ -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
|
||||||
|
//
|
||||||
|
|
||||||
|
// Test that header file is self-contained.
|
||||||
|
#include <boost/beast/experimental/core/timeout_socket.hpp>
|
||||||
|
|
||||||
|
#include <boost/beast/experimental/core/timeout_service.hpp>
|
||||||
|
|
||||||
|
#include <boost/beast/test/yield_to.hpp>
|
||||||
|
#include <boost/beast/unit_test/suite.hpp>
|
||||||
|
#include <boost/asio/ip/tcp.hpp>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
namespace beast {
|
||||||
|
|
||||||
|
class timeout_socket_test
|
||||||
|
: public beast::unit_test::suite
|
||||||
|
, public test::enable_yield_to
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
class server
|
||||||
|
{
|
||||||
|
std::ostream& log_;
|
||||||
|
boost::asio::io_context ioc_;
|
||||||
|
boost::asio::ip::tcp::acceptor acceptor_;
|
||||||
|
boost::asio::ip::tcp::socket socket_;
|
||||||
|
std::thread t_;
|
||||||
|
|
||||||
|
void
|
||||||
|
fail(error_code ec, string_view what)
|
||||||
|
{
|
||||||
|
if(ec != boost::asio::error::operation_aborted)
|
||||||
|
log_ << what << ": " << ec.message() << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
server(
|
||||||
|
boost::asio::ip::tcp::endpoint ep,
|
||||||
|
std::ostream& log)
|
||||||
|
: log_(log)
|
||||||
|
, ioc_(1)
|
||||||
|
, acceptor_(ioc_)
|
||||||
|
, socket_(ioc_)
|
||||||
|
{
|
||||||
|
boost::system::error_code ec;
|
||||||
|
|
||||||
|
acceptor_.open(ep.protocol(), ec);
|
||||||
|
if(ec)
|
||||||
|
{
|
||||||
|
fail(ec, "open");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
acceptor_.set_option(
|
||||||
|
boost::asio::socket_base::reuse_address(true), ec);
|
||||||
|
if(ec)
|
||||||
|
{
|
||||||
|
fail(ec, "set_option");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
acceptor_.bind(ep, ec);
|
||||||
|
if(ec)
|
||||||
|
{
|
||||||
|
fail(ec, "bind");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
acceptor_.listen(
|
||||||
|
boost::asio::socket_base::max_listen_connections, ec);
|
||||||
|
if(ec)
|
||||||
|
{
|
||||||
|
fail(ec, "listen");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
acceptor_.async_accept(socket_,
|
||||||
|
[this](error_code ec){ this->on_accept(ec); });
|
||||||
|
|
||||||
|
t_ = std::thread([this]{ ioc_.run(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
~server()
|
||||||
|
{
|
||||||
|
ioc_.stop();
|
||||||
|
t_.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
class session
|
||||||
|
: public std::enable_shared_from_this<session>
|
||||||
|
{
|
||||||
|
boost::asio::ip::tcp::socket socket_;
|
||||||
|
std::ostream& log_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
session(
|
||||||
|
boost::asio::ip::tcp::socket sock,
|
||||||
|
std::ostream& log)
|
||||||
|
: socket_(std::move(sock))
|
||||||
|
, log_(log)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
run()
|
||||||
|
{
|
||||||
|
socket_.async_wait(
|
||||||
|
boost::asio::socket_base::wait_read,
|
||||||
|
std::bind(
|
||||||
|
&session::on_read,
|
||||||
|
shared_from_this(),
|
||||||
|
std::placeholders::_1));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void
|
||||||
|
on_read(error_code ec)
|
||||||
|
{
|
||||||
|
boost::ignore_unused(ec);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
on_accept(error_code ec)
|
||||||
|
{
|
||||||
|
if(! acceptor_.is_open())
|
||||||
|
return;
|
||||||
|
if(ec)
|
||||||
|
fail(ec, "accept");
|
||||||
|
else
|
||||||
|
std::make_shared<session>(
|
||||||
|
std::move(socket_), log_)->run();
|
||||||
|
acceptor_.async_accept(socket_,
|
||||||
|
[this](error_code ec){ this->on_accept(ec); });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
testAsync()
|
||||||
|
{
|
||||||
|
boost::asio::ip::tcp::endpoint ep(
|
||||||
|
boost::asio::ip::make_address("127.0.0.1"), 8080);
|
||||||
|
server srv(ep, log);
|
||||||
|
{
|
||||||
|
boost::asio::io_context ioc;
|
||||||
|
set_timeout_service_options(
|
||||||
|
ioc, std::chrono::seconds(1));
|
||||||
|
timeout_socket s(ioc);
|
||||||
|
s.next_layer().connect(ep);
|
||||||
|
char buf[32];
|
||||||
|
s.async_read_some(boost::asio::buffer(buf),
|
||||||
|
[&](error_code ec, std::size_t n)
|
||||||
|
{
|
||||||
|
log << "read_some: " << ec.message() << "\n";
|
||||||
|
boost::ignore_unused(ec, n);
|
||||||
|
});
|
||||||
|
ioc.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
run()
|
||||||
|
{
|
||||||
|
testAsync();
|
||||||
|
|
||||||
|
pass();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
BEAST_DEFINE_TESTSUITE(beast,core,timeout_socket);
|
||||||
|
|
||||||
|
} // beast
|
||||||
|
} // boost
|
11
test/beast/experimental/timeout_work_guard.cpp
Normal file
11
test/beast/experimental/timeout_work_guard.cpp
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) 2016-2017 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/experimental/core/detail/timeout_work_guard.hpp>
|
Reference in New Issue
Block a user