mirror of
https://github.com/boostorg/beast.git
synced 2025-07-30 21:07:26 +02:00
New stream_socket:
This I/O object wraps an ordinary socket and provides a built-in timeout and optional bandwidth rate-limiting facility. Added class template basic_stream_socket * Meets the requirements of AsyncReadStream and AsyncWriteStream * Partially supports P1322R0: "Networking TS enhancement to enable custom I/O executors" http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1322r0.html A strand or other io_context-compatible executor may be chosen to use for all asynchronous stream operations. * Supports independent timeouts on logical operations: connect, read, write, or both read and write. * Provides an option for a configurable rate limit limit on the maximum rates of reading or writing. * The previous experimental implementation, `timeout_socket` and related types, is removed. * stream_socket is an alias for basic_stream_socket which uses `net::ip::tcp` as its protocol.
This commit is contained in:
@ -4,6 +4,7 @@ Version 201
|
||||
* Add bind_back_handler
|
||||
* Tidy up default-constructed iterators
|
||||
* Add core errors and conditions
|
||||
* New basic_stream_socket
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
@ -54,7 +54,7 @@
|
||||
|
||||
[*Experimental]
|
||||
|
||||
* Add [link beast.ref.boost__beast__timeout_socket `timeout_socket`]
|
||||
* Add `timeout_socket`
|
||||
|
||||
|
||||
|
||||
|
@ -179,6 +179,7 @@
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="beast.ref.boost__beast__basic_flat_buffer">basic_flat_buffer</link></member>
|
||||
<member><link linkend="beast.ref.boost__beast__basic_multi_buffer">basic_multi_buffer</link></member>
|
||||
<member><link linkend="beast.ref.boost__beast__basic_stream_socket">basic_stream_socket</link></member>
|
||||
<member><link linkend="beast.ref.boost__beast__buffered_read_stream">buffered_read_stream</link></member>
|
||||
<member><link linkend="beast.ref.boost__beast__buffers_adaptor">buffers_adaptor</link></member>
|
||||
<member><link linkend="beast.ref.boost__beast__buffers_cat_view">buffers_cat_view</link></member>
|
||||
@ -189,14 +190,14 @@
|
||||
<member><link linkend="beast.ref.boost__beast__file_posix">file_posix</link></member>
|
||||
<member><link linkend="beast.ref.boost__beast__file_stdio">file_stdio</link></member>
|
||||
<member><link linkend="beast.ref.boost__beast__file_win32">file_win32</link></member>
|
||||
<member><link linkend="beast.ref.boost__beast__flat_buffer">flat_buffer</link></member>
|
||||
<member><link linkend="beast.ref.boost__beast__flat_static_buffer">flat_static_buffer</link></member>
|
||||
<member><link linkend="beast.ref.boost__beast__flat_static_buffer_base">flat_static_buffer_base</link></member>
|
||||
</simplelist>
|
||||
</entry>
|
||||
<entry valign="top">
|
||||
<bridgehead renderas="sect3"> </bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="beast.ref.boost__beast__flat_buffer">flat_buffer</link></member>
|
||||
<member><link linkend="beast.ref.boost__beast__flat_static_buffer">flat_static_buffer</link></member>
|
||||
<member><link linkend="beast.ref.boost__beast__flat_static_buffer_base">flat_static_buffer_base</link></member>
|
||||
<member><link linkend="beast.ref.boost__beast__handler_ptr">handler_ptr</link></member>
|
||||
<member><link linkend="beast.ref.boost__beast__iequal">iequal</link></member>
|
||||
<member><link linkend="beast.ref.boost__beast__iless">iless</link></member>
|
||||
@ -205,17 +206,24 @@
|
||||
<member><link linkend="beast.ref.boost__beast__static_buffer">static_buffer</link></member>
|
||||
<member><link linkend="beast.ref.boost__beast__static_buffer_base">static_buffer_base</link></member>
|
||||
<member><link linkend="beast.ref.boost__beast__static_string">static_string</link></member>
|
||||
<member><link linkend="beast.ref.boost__beast__stream_socket">stream_socket</link></member>
|
||||
<member><link linkend="beast.ref.boost__beast__string_param">string_param</link></member>
|
||||
<member><link linkend="beast.ref.boost__beast__string_view">string_view</link></member>
|
||||
</simplelist>
|
||||
<bridgehead renderas="sect3">Constants</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="beast.ref.boost__beast__condition">condition</link></member>
|
||||
<member><link linkend="beast.ref.boost__beast__error">error</link></member>
|
||||
<member><link linkend="beast.ref.boost__beast__file_mode">file_mode</link></member>
|
||||
</simplelist>
|
||||
</entry>
|
||||
<entry valign="top">
|
||||
<bridgehead renderas="sect3">Functions</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="beast.ref.boost__beast__async_connect">async_connect</link></member>
|
||||
<member><link linkend="beast.ref.boost__beast__bind_back_handler">bind_back_handler</link></member>
|
||||
<member><link linkend="beast.ref.boost__beast__bind_front_handler">bind_front_handler</link></member>
|
||||
<member><link linkend="beast.ref.boost__beast__bind_handler">bind_handler</link></member>
|
||||
<member><link linkend="beast.ref.boost__beast__make_printable">make_printable</link></member>
|
||||
<member><link linkend="beast.ref.boost__beast__buffers_cat">buffers_cat</link></member>
|
||||
<member><link linkend="beast.ref.boost__beast__buffers_front">buffers_front</link></member>
|
||||
<member><link linkend="beast.ref.boost__beast__buffers_prefix">buffers_prefix</link></member>
|
||||
@ -224,17 +232,12 @@
|
||||
<member><link linkend="beast.ref.boost__beast__buffers_to_string">buffers_to_string</link></member>
|
||||
<member><link linkend="beast.ref.boost__beast__generic_category">generic_category</link></member>
|
||||
<member><link linkend="beast.ref.boost__beast__iequals">iequals</link></member>
|
||||
<member><link linkend="beast.ref.boost__beast__make_printable">make_printable</link></member>
|
||||
<member><link linkend="beast.ref.boost__beast__ostream">ostream</link></member>
|
||||
<member><link linkend="beast.ref.boost__beast__read_size">read_size</link></member>
|
||||
<member><link linkend="beast.ref.boost__beast__read_size_or_throw">read_size_or_throw</link></member>
|
||||
<member><link linkend="beast.ref.boost__beast__to_static_string">to_static_string</link></member>
|
||||
</simplelist>
|
||||
<bridgehead renderas="sect3">Constants</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="beast.ref.boost__beast__condition">condition</link></member>
|
||||
<member><link linkend="beast.ref.boost__beast__error">error</link></member>
|
||||
<member><link linkend="beast.ref.boost__beast__file_mode">file_mode</link></member>
|
||||
</simplelist>
|
||||
</entry>
|
||||
<entry valign="top">
|
||||
<bridgehead renderas="sect3">Type Traits</bridgehead>
|
||||
@ -312,22 +315,16 @@
|
||||
<entry valign="top">
|
||||
<bridgehead renderas="sect3">Classes</bridgehead>
|
||||
<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__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__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__timeout_handle">timeout_handle</link></member>
|
||||
<member><link linkend="beast.ref.boost__beast__timeout_socket">timeout_socket</link></member>
|
||||
<member><link linkend="beast.ref.boost__beast__timeout_work_guard">timeout_work_guard</link></member>
|
||||
</simplelist>
|
||||
</entry>
|
||||
<entry valign="top">
|
||||
<bridgehead renderas="sect3">Functions</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="beast.ref.boost__beast__async_connect">async_connect</link></member>
|
||||
<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>
|
||||
</simplelist>
|
||||
</entry>
|
||||
|
@ -1,326 +0,0 @@
|
||||
//
|
||||
// Copyright (c) 2018 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/beast
|
||||
//
|
||||
|
||||
#ifndef BOOST_BEAST_CORE_DETAIL_IMPL_TIMEOUT_SERVICE_HPP
|
||||
#define BOOST_BEAST_CORE_DETAIL_IMPL_TIMEOUT_SERVICE_HPP
|
||||
|
||||
namespace boost {
|
||||
namespace beast {
|
||||
namespace detail {
|
||||
|
||||
timeout_service::
|
||||
timeout_service(net::io_context& ctx)
|
||||
: service_base(ctx)
|
||||
, thunks_(1) // element [0] reserved for "null"
|
||||
, timer_(ctx)
|
||||
{
|
||||
}
|
||||
|
||||
timeout_handle
|
||||
timeout_service::
|
||||
make_handle()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_);
|
||||
if(free_thunk_ != 0)
|
||||
{
|
||||
auto const n = free_thunk_;
|
||||
auto& t = thunks_[n];
|
||||
free_thunk_ = t.pos; // next in free list
|
||||
t = {};
|
||||
return timeout_handle(n, *this);
|
||||
}
|
||||
auto const n = thunks_.size();
|
||||
thunks_.emplace_back();
|
||||
return timeout_handle(n, *this);
|
||||
}
|
||||
|
||||
void
|
||||
timeout_service::
|
||||
set_option(std::chrono::seconds n)
|
||||
{
|
||||
interval_ = n;
|
||||
}
|
||||
|
||||
template<class Executor, class CancelHandler>
|
||||
void
|
||||
timeout_service::
|
||||
set_callback(
|
||||
timeout_handle h,
|
||||
Executor const& ex,
|
||||
CancelHandler&& handler)
|
||||
{
|
||||
thunks_[h.id_].callback.emplace(
|
||||
callback<
|
||||
Executor,
|
||||
typename std::decay<CancelHandler>::type>{
|
||||
h, ex,
|
||||
std::forward<CancelHandler>(handler)});
|
||||
}
|
||||
|
||||
void
|
||||
timeout_service::
|
||||
on_work_started(timeout_handle h)
|
||||
{
|
||||
BOOST_ASSERT(h.id_ != 0);
|
||||
if( [this, h]
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_);
|
||||
auto& t = thunks_[h.id_];
|
||||
insert(t, *fresh_);
|
||||
return ++pending_ == 1;
|
||||
}())
|
||||
{
|
||||
do_async_wait();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
timeout_service::
|
||||
on_work_stopped(timeout_handle h)
|
||||
{
|
||||
BOOST_ASSERT(h.id_ != 0);
|
||||
std::lock_guard<std::mutex> lock(m_);
|
||||
auto& t = thunks_[h.id_];
|
||||
if(t.list != nullptr)
|
||||
{
|
||||
BOOST_ASSERT(! t.expired);
|
||||
remove(t);
|
||||
}
|
||||
if(--pending_ == 0)
|
||||
timer_.cancel();
|
||||
BOOST_ASSERT(pending_ >= 0);
|
||||
}
|
||||
|
||||
/*
|
||||
Synchronization points
|
||||
|
||||
(A) async_op invoke
|
||||
(B) timeout handler invoke expired=true
|
||||
(C) posted handler invoked canceled=true
|
||||
|
||||
----------------------------------------------
|
||||
|
||||
Linearized paths (for async_read)
|
||||
|
||||
----------------------------------------------
|
||||
|
||||
1. async_read
|
||||
2. async_read complete, async_op posted
|
||||
(A) 3. async_op invoked
|
||||
- work_.try_complete() returns true
|
||||
+ expired==false
|
||||
+ thunk is removed from list
|
||||
|
||||
----------------------------------------------
|
||||
|
||||
1. async_read
|
||||
2. async_read complete, async_op posted
|
||||
(B) 3. timeout, cancel posted
|
||||
- expired=true
|
||||
- thunk is removed from list
|
||||
(A) 4. async_op invoked
|
||||
- work_.try_complete() returns false
|
||||
+ completed=true
|
||||
- handler is saved
|
||||
(C) 5. cancel invoked
|
||||
- saved handler is invoked
|
||||
+ expired==true, canceled==false, completed==true
|
||||
+ work_.try_complete() returns true
|
||||
|
||||
----------------------------------------------
|
||||
|
||||
The following two paths are not distinguishable:
|
||||
|
||||
1. async_read
|
||||
(B) 2. timeout, cancel posted
|
||||
- expired=true
|
||||
- thunk is removed from list
|
||||
3. async_read complete, async_op posted
|
||||
(C) 4. cancel invoked
|
||||
- socket::cancel called (what does this do?)
|
||||
- canceled=true
|
||||
(A) 5. async_op invoked
|
||||
- expired==true, canceled==true, completed==false
|
||||
- work_.try_complete() returns `true`
|
||||
|
||||
1. async_read
|
||||
(B) 2. timeout, `cancel` posted
|
||||
- expired=true
|
||||
- thunk is removed from list
|
||||
(C) 3. cancel invoked, async_read canceled
|
||||
- socket::cancel called
|
||||
- canceled=true
|
||||
(A) 4. async_op invoked, ec==operation_aborted
|
||||
- expired==true, canceled==true, completed=false
|
||||
- work_.try_complete()` returns true
|
||||
*/
|
||||
bool
|
||||
timeout_service::
|
||||
on_try_work_complete(timeout_handle h)
|
||||
{
|
||||
BOOST_ASSERT(h.id_ != 0);
|
||||
std::lock_guard<std::mutex> lock(m_);
|
||||
auto& t = thunks_[h.id_];
|
||||
if(! t.expired)
|
||||
{
|
||||
// hot path: operation complete
|
||||
BOOST_ASSERT(t.list != nullptr);
|
||||
BOOST_ASSERT(! t.canceled);
|
||||
BOOST_ASSERT(! t.completed);
|
||||
remove(t);
|
||||
return true;
|
||||
}
|
||||
BOOST_ASSERT(t.list == nullptr);
|
||||
if(! t.canceled)
|
||||
{
|
||||
// happens when operation completes before
|
||||
// posted cancel handler is invoked.
|
||||
t.completed = true;
|
||||
return false;
|
||||
}
|
||||
if(t.completed)
|
||||
{
|
||||
// happens when the saved handler is
|
||||
// invoked from the posted callback
|
||||
t.expired = false;
|
||||
t.canceled = false;
|
||||
t.completed = false;
|
||||
return true;
|
||||
}
|
||||
// happens when operation_aborted is delivered
|
||||
t.expired = false;
|
||||
t.canceled = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
timeout_service::
|
||||
on_cancel(timeout_handle h)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_);
|
||||
auto& t = thunks_[h.id_];
|
||||
BOOST_ASSERT(t.expired);
|
||||
t.canceled = true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void
|
||||
timeout_service::
|
||||
destroy(timeout_handle h)
|
||||
{
|
||||
BOOST_ASSERT(h.id_ != 0);
|
||||
std::lock_guard<std::mutex> lock(m_);
|
||||
thunks_[h.id_].pos = free_thunk_;
|
||||
free_thunk_ = h.id_;
|
||||
}
|
||||
|
||||
// Precondition: caller holds the mutex
|
||||
void
|
||||
timeout_service::
|
||||
insert(
|
||||
thunk& t,
|
||||
thunk::list_type& list)
|
||||
{
|
||||
BOOST_ASSERT(t.list == nullptr);
|
||||
list.emplace_back(&t); // can throw
|
||||
t.list = &list;
|
||||
t.pos = list.size();
|
||||
}
|
||||
|
||||
// Precondition: caller holds the mutex
|
||||
void
|
||||
timeout_service::
|
||||
remove(thunk& t)
|
||||
{
|
||||
BOOST_ASSERT(t.list != nullptr);
|
||||
BOOST_ASSERT(
|
||||
t.list == stale_ ||
|
||||
t.list == fresh_);
|
||||
BOOST_ASSERT(t.list->size() > 0);
|
||||
auto& list = *t.list;
|
||||
auto const n = list.size() - 1;
|
||||
if(t.pos != n)
|
||||
{
|
||||
// move back element to t.pos
|
||||
list[t.pos] = list[n];
|
||||
list[t.pos]->pos = t.pos;
|
||||
}
|
||||
t.list = nullptr;
|
||||
list.resize(n);
|
||||
}
|
||||
|
||||
void
|
||||
timeout_service::
|
||||
do_async_wait()
|
||||
{
|
||||
timer_.expires_after(interval_);
|
||||
timer_.async_wait(
|
||||
[this](error_code ec)
|
||||
{
|
||||
this->on_timer(ec);
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
timeout_service::
|
||||
on_timer(error_code ec)
|
||||
{
|
||||
if(ec == net::error::operation_aborted)
|
||||
{
|
||||
BOOST_ASSERT(fresh_->empty());
|
||||
BOOST_ASSERT(stale_->empty());
|
||||
return;
|
||||
}
|
||||
std::vector<thunk*> expired;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_);
|
||||
if(! stale_->empty())
|
||||
{
|
||||
for(auto t : *stale_)
|
||||
{
|
||||
// remove from list
|
||||
t->list = nullptr;
|
||||
t->expired = true;
|
||||
}
|
||||
std::swap(expired, *stale_);
|
||||
stale_->reserve(expired.size() / 2);
|
||||
}
|
||||
std::swap(fresh_, stale_);
|
||||
}
|
||||
for(auto p : expired)
|
||||
p->callback();
|
||||
if( [this]
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_);
|
||||
BOOST_ASSERT(pending_);
|
||||
pending_ =
|
||||
! stale_->empty() ||
|
||||
! fresh_->empty();
|
||||
return pending_;
|
||||
}())
|
||||
{
|
||||
do_async_wait();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
timeout_service::
|
||||
shutdown() noexcept
|
||||
{
|
||||
// The ExecutionContext is already in a stopped
|
||||
// state, so no synchronization is required.
|
||||
timer_.cancel();
|
||||
}
|
||||
|
||||
} // detail
|
||||
} // beast
|
||||
} // boost
|
||||
|
||||
#endif
|
@ -59,11 +59,10 @@ public:
|
||||
std::forward<Handler>(h)));
|
||||
}
|
||||
|
||||
template<class Handler,
|
||||
class T0, class... TN>
|
||||
template<
|
||||
class Handler, class T0, class... TN>
|
||||
void
|
||||
emplace(Handler&& h,
|
||||
T0&& t0, TN&... tn)
|
||||
emplace(Handler&& h, T0&& t0, TN&&... tn)
|
||||
{
|
||||
using type = decltype(
|
||||
beast::bind_front_handler(
|
||||
|
@ -1,133 +0,0 @@
|
||||
//
|
||||
// Copyright (c) 2018 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/beast
|
||||
//
|
||||
|
||||
#ifndef BOOST_BEAST_CORE_DETAIL_TIMEOUT_SERVICE_HPP
|
||||
#define BOOST_BEAST_CORE_DETAIL_TIMEOUT_SERVICE_HPP
|
||||
|
||||
#include <boost/beast/_experimental/core/detail/service_base.hpp>
|
||||
#include <boost/beast/_experimental/core/detail/timeout_service_base.hpp>
|
||||
#include <boost/beast/core/bind_handler.hpp>
|
||||
#include <boost/beast/core/error.hpp>
|
||||
#include <boost/asio/executor.hpp>
|
||||
#include <boost/asio/io_context.hpp> // #include <boost/asio/execution_context.hpp>
|
||||
#include <boost/asio/post.hpp>
|
||||
#include <boost/asio/steady_timer.hpp>
|
||||
#include <chrono>
|
||||
#include <cstdlib>
|
||||
#include <deque>
|
||||
#include <mutex>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace boost {
|
||||
namespace beast {
|
||||
|
||||
class timeout_handle;
|
||||
|
||||
namespace detail {
|
||||
|
||||
class timeout_service
|
||||
: public service_base<timeout_service>
|
||||
{
|
||||
template<class Executor, class Handler>
|
||||
struct callback
|
||||
{
|
||||
timeout_handle th;
|
||||
Executor ex;
|
||||
Handler h;
|
||||
|
||||
void
|
||||
operator()()
|
||||
{
|
||||
net::post(ex,
|
||||
beast::bind_front_handler(
|
||||
std::move(*this), 0));
|
||||
}
|
||||
|
||||
void
|
||||
operator()(int)
|
||||
{
|
||||
th.service().on_cancel(th);
|
||||
h();
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
using key_type = timeout_service;
|
||||
|
||||
// VFALCO Should be execution_context
|
||||
BOOST_BEAST_DECL
|
||||
explicit
|
||||
timeout_service(net::io_context& ctx);
|
||||
|
||||
BOOST_BEAST_DECL
|
||||
timeout_handle
|
||||
make_handle();
|
||||
|
||||
BOOST_BEAST_DECL
|
||||
void set_option(std::chrono::seconds n);
|
||||
|
||||
// Undefined if work is active
|
||||
template<class Executor, class CancelHandler>
|
||||
void set_callback(
|
||||
timeout_handle h,
|
||||
Executor const& ex,
|
||||
CancelHandler&& handler);
|
||||
|
||||
BOOST_BEAST_DECL
|
||||
void on_work_started(timeout_handle h);
|
||||
|
||||
BOOST_BEAST_DECL
|
||||
void on_work_stopped(timeout_handle h);
|
||||
|
||||
BOOST_BEAST_DECL
|
||||
bool on_try_work_complete(timeout_handle h);
|
||||
|
||||
private:
|
||||
friend class beast::timeout_handle;
|
||||
|
||||
BOOST_BEAST_DECL
|
||||
void destroy(timeout_handle h);
|
||||
|
||||
BOOST_BEAST_DECL
|
||||
void insert(thunk& t, thunk::list_type& list);
|
||||
|
||||
BOOST_BEAST_DECL
|
||||
void remove(thunk& t);
|
||||
|
||||
BOOST_BEAST_DECL
|
||||
void do_async_wait();
|
||||
|
||||
BOOST_BEAST_DECL
|
||||
void on_cancel(timeout_handle h);
|
||||
|
||||
BOOST_BEAST_DECL
|
||||
void on_timer(error_code ec);
|
||||
|
||||
BOOST_BEAST_DECL
|
||||
virtual void shutdown() noexcept override;
|
||||
|
||||
std::mutex m_;
|
||||
thunk::list_type list_[2];
|
||||
thunk::list_type* fresh_ = &list_[0];
|
||||
thunk::list_type* stale_ = &list_[1];
|
||||
std::deque<thunk> thunks_;
|
||||
std::size_t free_thunk_ = 0;
|
||||
net::steady_timer timer_;
|
||||
std::chrono::seconds interval_{30ul};
|
||||
long pending_ = 0;
|
||||
};
|
||||
|
||||
} // detail
|
||||
} // beast
|
||||
} // boost
|
||||
|
||||
#include <boost/beast/_experimental/core/detail/impl/timeout_service.hpp>
|
||||
|
||||
#endif
|
@ -1,38 +0,0 @@
|
||||
//
|
||||
// Copyright (c) 2018 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/beast
|
||||
//
|
||||
|
||||
#ifndef BOOST_BEAST_CORE_DETAIL_TIMEOUT_SERVICE_BASE_HPP
|
||||
#define BOOST_BEAST_CORE_DETAIL_TIMEOUT_SERVICE_BASE_HPP
|
||||
|
||||
#include <boost/beast/_experimental/core/detail/saved_handler.hpp>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace boost {
|
||||
namespace beast {
|
||||
namespace detail {
|
||||
|
||||
struct thunk
|
||||
{
|
||||
using list_type =
|
||||
std::vector<thunk*>;
|
||||
|
||||
saved_handler callback;
|
||||
list_type* list = nullptr;
|
||||
std::size_t pos = 0; // also: next in free list
|
||||
bool expired = false;
|
||||
bool canceled = false;
|
||||
bool completed = false;
|
||||
};
|
||||
|
||||
} // detail
|
||||
} // beast
|
||||
} // boost
|
||||
|
||||
#endif
|
@ -1,64 +0,0 @@
|
||||
//
|
||||
// Copyright (c) 2018 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/beast
|
||||
//
|
||||
|
||||
#ifndef BOOST_BEAST_CORE_IMPL_TIMEOUT_SERVICE_HPP
|
||||
#define BOOST_BEAST_CORE_IMPL_TIMEOUT_SERVICE_HPP
|
||||
|
||||
#include <boost/beast/_experimental/core/detail/timeout_service.hpp>
|
||||
#include <boost/asio/execution_context.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace beast {
|
||||
|
||||
timeout_handle::
|
||||
timeout_handle(net::io_context& ioc)
|
||||
: timeout_handle(
|
||||
net::use_service<
|
||||
detail::timeout_service>(
|
||||
ioc).make_handle())
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
timeout_handle::
|
||||
destroy()
|
||||
{
|
||||
BOOST_ASSERT(svc_ != nullptr);
|
||||
svc_->destroy(*this);
|
||||
id_ = 0;
|
||||
svc_ = nullptr;
|
||||
}
|
||||
|
||||
template<class Executor, class CancelHandler>
|
||||
void
|
||||
timeout_handle::
|
||||
set_callback(
|
||||
Executor const& ex, CancelHandler&& handler)
|
||||
{
|
||||
svc_->set_callback(*this, ex,
|
||||
std::forward<CancelHandler>(handler));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void
|
||||
set_timeout_service_options(
|
||||
net::io_context& ioc,
|
||||
std::chrono::seconds interval)
|
||||
{
|
||||
net::use_service<
|
||||
detail::timeout_service>(
|
||||
ioc).set_option(interval);
|
||||
}
|
||||
|
||||
} // beast
|
||||
} // boost
|
||||
|
||||
#endif
|
@ -1,478 +0,0 @@
|
||||
//
|
||||
// Copyright (c) 2018 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/beast
|
||||
//
|
||||
|
||||
#ifndef BOOST_BEAST_CORE_IMPL_TIMEOUT_SOCKET_HPP
|
||||
#define BOOST_BEAST_CORE_IMPL_TIMEOUT_SOCKET_HPP
|
||||
|
||||
#include <boost/beast/core/detail/stream_algorithm.hpp>
|
||||
#include <boost/beast/_experimental/core/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
|
||||
{
|
||||
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_)
|
||||
, wg0_(s_.get_executor())
|
||||
, wg1_(get_executor())
|
||||
, saved_(s_.rd_op_)
|
||||
|
||||
{
|
||||
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_)
|
||||
, wg0_(s_.get_executor())
|
||||
, wg1_(get_executor())
|
||||
, saved_(s_.wr_op_)
|
||||
{
|
||||
s_.sock_.async_write_some(b, std::move(*this));
|
||||
}
|
||||
|
||||
void
|
||||
operator()(error_code ec, std::size_t bytes_transferred)
|
||||
{
|
||||
if(! work_.try_complete())
|
||||
{
|
||||
saved_.emplace(
|
||||
std::move(*this),
|
||||
ec,
|
||||
bytes_transferred);
|
||||
return;
|
||||
}
|
||||
h_(ec, bytes_transferred);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
using allocator_type =
|
||||
net::associated_allocator_t<Handler>;
|
||||
|
||||
using executor_type =
|
||||
net::associated_executor_t<Handler,
|
||||
decltype(std::declval<basic_timeout_socket<
|
||||
Protocol, Executor>&>().get_executor())>;
|
||||
|
||||
allocator_type
|
||||
get_allocator() const noexcept
|
||||
{
|
||||
return net::get_associated_allocator(h_);
|
||||
}
|
||||
|
||||
executor_type
|
||||
get_executor() const noexcept
|
||||
{
|
||||
return net::get_associated_executor(
|
||||
h_, s_.get_executor());
|
||||
}
|
||||
|
||||
template<class Function>
|
||||
friend
|
||||
void asio_handler_invoke(Function&& f, async_op* op)
|
||||
{
|
||||
using net::asio_handler_invoke;
|
||||
asio_handler_invoke(f, std::addressof(op->h_));
|
||||
}
|
||||
|
||||
friend
|
||||
void* asio_handler_allocate(
|
||||
std::size_t size, async_op* op)
|
||||
{
|
||||
using net::asio_handler_allocate;
|
||||
return asio_handler_allocate(
|
||||
size, std::addressof(op->h_));
|
||||
}
|
||||
|
||||
friend
|
||||
void asio_handler_deallocate(
|
||||
void* p, std::size_t size, async_op* op)
|
||||
{
|
||||
using net::asio_handler_deallocate;
|
||||
asio_handler_deallocate(
|
||||
p, size, std::addressof(op->h_));
|
||||
}
|
||||
|
||||
friend
|
||||
bool asio_handler_is_continuation(async_op* op)
|
||||
{
|
||||
using net::asio_handler_is_continuation;
|
||||
return asio_handler_is_continuation(
|
||||
std::addressof(op->h_));
|
||||
}
|
||||
|
||||
private:
|
||||
Handler h_;
|
||||
basic_timeout_socket& s_;
|
||||
timeout_work_guard work_;
|
||||
net::executor_work_guard<Executor> wg0_;
|
||||
net::executor_work_guard<executor_type> wg1_;
|
||||
detail::saved_handler& saved_;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
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_(ctx)
|
||||
, wr_timer_(ctx)
|
||||
, cn_timer_(ctx)
|
||||
, sock_(ctx)
|
||||
{
|
||||
rd_timer_.set_callback(ex_,
|
||||
[this]
|
||||
{
|
||||
if(rd_op_.empty())
|
||||
sock_.cancel();
|
||||
else
|
||||
rd_op_();
|
||||
});
|
||||
|
||||
wr_timer_.set_callback(ex_,
|
||||
[this]
|
||||
{
|
||||
if(wr_op_.empty())
|
||||
sock_.cancel();
|
||||
else
|
||||
wr_op_();
|
||||
});
|
||||
|
||||
cn_timer_.set_callback(ex_,
|
||||
[this]
|
||||
{
|
||||
if(cn_op_.empty())
|
||||
sock_.cancel();
|
||||
else
|
||||
cn_op_();
|
||||
});
|
||||
}
|
||||
|
||||
template<class Protocol, class Executor>
|
||||
basic_timeout_socket<Protocol, Executor>::
|
||||
~basic_timeout_socket()
|
||||
{
|
||||
rd_timer_.destroy();
|
||||
wr_timer_.destroy();
|
||||
}
|
||||
|
||||
template<class Protocol, class Executor>
|
||||
template<class MutableBufferSequence, class ReadHandler>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
|
||||
void(error_code, std::size_t))
|
||||
basic_timeout_socket<Protocol, Executor>::
|
||||
async_read_some(
|
||||
MutableBufferSequence const& buffers,
|
||||
ReadHandler&& handler)
|
||||
{
|
||||
static_assert(net::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(error_code, std::size_t))
|
||||
basic_timeout_socket<Protocol, Executor>::
|
||||
async_write_some(
|
||||
ConstBufferSequence const& buffers,
|
||||
WriteHandler&& handler)
|
||||
{
|
||||
static_assert(net::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();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<
|
||||
class Protocol, class Executor,
|
||||
class Handler>
|
||||
class connect_op
|
||||
{
|
||||
public:
|
||||
template<
|
||||
class Endpoints,
|
||||
class Condition,
|
||||
class DeducedHandler>
|
||||
connect_op(
|
||||
basic_timeout_socket<Protocol, Executor>& s,
|
||||
Endpoints const& eps,
|
||||
Condition cond,
|
||||
DeducedHandler&& h)
|
||||
: h_(std::forward<DeducedHandler>(h))
|
||||
, work_(s.cnd_timer_)
|
||||
, s_(s)
|
||||
, wg0_(s_.get_executor())
|
||||
, wg1_(get_executor())
|
||||
{
|
||||
net::async_connect(
|
||||
s_.next_layer(), eps, cond,
|
||||
std::move(*this));
|
||||
}
|
||||
|
||||
template<class Arg>
|
||||
void
|
||||
operator()(error_code ec, Arg&& arg)
|
||||
{
|
||||
if(! work_.try_complete())
|
||||
{
|
||||
s_.cn_op_.emplace(
|
||||
std::move(*this),
|
||||
ec,
|
||||
std::forward<Arg>(arg));
|
||||
return;
|
||||
}
|
||||
h_(ec, std::forward<Arg>(arg));
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
using allocator_type =
|
||||
net::associated_allocator_t<Handler>;
|
||||
|
||||
using executor_type =
|
||||
net::associated_executor_t<Handler,
|
||||
decltype(std::declval<basic_timeout_socket<
|
||||
Protocol, Executor>&>().get_executor())>;
|
||||
|
||||
allocator_type
|
||||
get_allocator() const noexcept
|
||||
{
|
||||
return net::get_associated_allocator(h_);
|
||||
}
|
||||
|
||||
executor_type
|
||||
get_executor() const noexcept
|
||||
{
|
||||
return net::get_associated_executor(
|
||||
h_, s_.get_executor());
|
||||
}
|
||||
|
||||
template<class Function>
|
||||
friend
|
||||
void asio_handler_invoke(
|
||||
Function&& f, connect_op* op)
|
||||
{
|
||||
using net::asio_handler_invoke;
|
||||
asio_handler_invoke(
|
||||
f, std::addressof(op->h_));
|
||||
}
|
||||
|
||||
friend
|
||||
void* asio_handler_allocate(
|
||||
std::size_t size, connect_op* op)
|
||||
{
|
||||
using net::asio_handler_allocate;
|
||||
return asio_handler_allocate(
|
||||
size, std::addressof(op->h_));
|
||||
}
|
||||
|
||||
friend
|
||||
void asio_handler_deallocate(
|
||||
void* p, std::size_t size, connect_op* op)
|
||||
{
|
||||
using net::asio_handler_deallocate;
|
||||
asio_handler_deallocate(
|
||||
p, size, std::addressof(op->h_));
|
||||
}
|
||||
|
||||
friend
|
||||
bool asio_handler_is_continuation(connect_op* op)
|
||||
{
|
||||
using net::asio_handler_is_continuation;
|
||||
return asio_handler_is_continuation(
|
||||
std::addressof(op->h_));
|
||||
}
|
||||
|
||||
private:
|
||||
Handler h_;
|
||||
timeout_work_guard work_;
|
||||
basic_timeout_socket<Protocol, Executor>& s_;
|
||||
net::executor_work_guard<Executor> wg0_;
|
||||
net::executor_work_guard<executor_type> wg1_;
|
||||
};
|
||||
|
||||
struct any_endpoint
|
||||
{
|
||||
template<class Error, class Endpoint>
|
||||
bool
|
||||
operator()(
|
||||
Error const&, Endpoint const&) const noexcept
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template<class Iterator>
|
||||
struct endpoint_range_type
|
||||
{
|
||||
using const_iterator = Iterator;
|
||||
|
||||
Iterator begin_;
|
||||
Iterator end_;
|
||||
|
||||
Iterator begin() const noexcept
|
||||
{
|
||||
return begin_;
|
||||
}
|
||||
|
||||
Iterator end() const noexcept
|
||||
{
|
||||
return end_;
|
||||
}
|
||||
};
|
||||
|
||||
template<class Iterator>
|
||||
endpoint_range_type<Iterator>
|
||||
endpoint_range(Iterator first, Iterator last)
|
||||
{
|
||||
return endpoint_range_type<
|
||||
Iterator>(first, last);
|
||||
}
|
||||
|
||||
} // detail
|
||||
|
||||
template<
|
||||
class Protocol, class Executor,
|
||||
class EndpointSequence,
|
||||
class RangeConnectHandler, class>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(RangeConnectHandler,
|
||||
void(error_code, typename Protocol::endpoint))
|
||||
async_connect(
|
||||
basic_timeout_socket<Protocol, Executor>& s,
|
||||
EndpointSequence const& endpoints,
|
||||
RangeConnectHandler&& handler)
|
||||
{
|
||||
BOOST_BEAST_HANDLER_INIT(RangeConnectHandler,
|
||||
void(error_code, typename Protocol::endpoint));
|
||||
detail::connect_op<Protocol, Executor,
|
||||
BOOST_ASIO_HANDLER_TYPE(RangeConnectHandler,
|
||||
void(error_code,
|
||||
typename Protocol::endpoint))>(
|
||||
s, endpoints, detail::any_endpoint{},
|
||||
std::forward<RangeConnectHandler>(handler));
|
||||
return init.result.get();
|
||||
}
|
||||
|
||||
template<
|
||||
class Protocol, class Executor,
|
||||
class EndpointSequence,
|
||||
class ConnectCondition,
|
||||
class RangeConnectHandler, class>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(RangeConnectHandler,
|
||||
void (error_code, typename Protocol::endpoint))
|
||||
async_connect(
|
||||
basic_timeout_socket<Protocol, Executor>& s,
|
||||
EndpointSequence const& endpoints,
|
||||
ConnectCondition connect_condition,
|
||||
RangeConnectHandler&& handler)
|
||||
{
|
||||
BOOST_BEAST_HANDLER_INIT(RangeConnectHandler,
|
||||
void(error_code, typename Protocol::endpoint));
|
||||
detail::connect_op<Protocol, Executor,
|
||||
BOOST_ASIO_HANDLER_TYPE(RangeConnectHandler,
|
||||
void(error_code,
|
||||
typename Protocol::endpoint))>(
|
||||
s, endpoints, connect_condition,
|
||||
std::forward<RangeConnectHandler>(handler));
|
||||
return init.result.get();
|
||||
}
|
||||
|
||||
template<
|
||||
class Protocol, class Executor,
|
||||
class Iterator,
|
||||
class IteratorConnectHandler, class>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler,
|
||||
void (error_code, Iterator))
|
||||
async_connect(
|
||||
basic_timeout_socket<Protocol, Executor>& s,
|
||||
Iterator begin, Iterator end,
|
||||
IteratorConnectHandler&& handler)
|
||||
{
|
||||
BOOST_BEAST_HANDLER_INIT(IteratorConnectHandler,
|
||||
void(error_code, Iterator));
|
||||
detail::connect_op<Protocol, Executor,
|
||||
BOOST_ASIO_HANDLER_TYPE(IteratorConnectHandler,
|
||||
void(error_code, Iterator))>(
|
||||
s, detail::endpoint_range(begin, end), detail::any_endpoint{},
|
||||
std::forward<IteratorConnectHandler>(handler));
|
||||
return init.result.get();
|
||||
}
|
||||
|
||||
template<
|
||||
class Protocol, class Executor,
|
||||
class Iterator,
|
||||
class ConnectCondition,
|
||||
class IteratorConnectHandler, class>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler,
|
||||
void (error_code, Iterator))
|
||||
async_connect(
|
||||
basic_timeout_socket<Protocol, Executor>& s,
|
||||
Iterator begin, Iterator end,
|
||||
ConnectCondition connect_condition,
|
||||
IteratorConnectHandler&& handler)
|
||||
{
|
||||
BOOST_BEAST_HANDLER_INIT(IteratorConnectHandler,
|
||||
void(error_code, Iterator));
|
||||
detail::connect_op<Protocol, Executor,
|
||||
BOOST_ASIO_HANDLER_TYPE(IteratorConnectHandler,
|
||||
void(error_code, Iterator))>(
|
||||
s, detail::endpoint_range(begin, end), connect_condition,
|
||||
std::forward<IteratorConnectHandler>(handler));
|
||||
return init.result.get();
|
||||
}
|
||||
|
||||
} // beast
|
||||
} // boost
|
||||
|
||||
#endif
|
@ -1,135 +0,0 @@
|
||||
//
|
||||
// Copyright (c) 2018 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/beast
|
||||
//
|
||||
|
||||
#ifndef BOOST_BEAST_CORE_TIMEOUT_SERVICE_HPP
|
||||
#define BOOST_BEAST_CORE_TIMEOUT_SERVICE_HPP
|
||||
|
||||
#include <boost/beast/core/detail/config.hpp>
|
||||
#include <boost/asio/io_context.hpp> // #include <boost/asio/execution_context.hpp>
|
||||
#include <cstddef>
|
||||
|
||||
namespace boost {
|
||||
namespace beast {
|
||||
|
||||
namespace detail {
|
||||
class timeout_service;
|
||||
} // detail
|
||||
|
||||
class timeout_work_guard;
|
||||
|
||||
class timeout_handle
|
||||
{
|
||||
std::size_t id_ = 0;
|
||||
detail::timeout_service* svc_ = nullptr;
|
||||
|
||||
timeout_handle(
|
||||
std::size_t id,
|
||||
detail::timeout_service& svc)
|
||||
: id_(id)
|
||||
, svc_(&svc)
|
||||
{
|
||||
}
|
||||
|
||||
detail::timeout_service&
|
||||
service() const
|
||||
{
|
||||
return *svc_;
|
||||
}
|
||||
|
||||
friend class detail::timeout_service;
|
||||
friend class timeout_work_guard;
|
||||
|
||||
public:
|
||||
timeout_handle() = default;
|
||||
timeout_handle(timeout_handle const&) = default;
|
||||
timeout_handle& operator=(timeout_handle const&) = default;
|
||||
|
||||
timeout_handle(std::nullptr_t)
|
||||
{
|
||||
}
|
||||
|
||||
timeout_handle&
|
||||
operator=(std::nullptr_t)
|
||||
{
|
||||
id_ = 0;
|
||||
svc_ = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// VFALCO should be execution_context
|
||||
BOOST_BEAST_DECL
|
||||
explicit
|
||||
timeout_handle(net::io_context& ioc);
|
||||
|
||||
BOOST_BEAST_DECL
|
||||
void
|
||||
destroy();
|
||||
|
||||
template<class Executor, class CancelHandler>
|
||||
void
|
||||
set_callback(
|
||||
Executor const& ex, CancelHandler&& handler);
|
||||
|
||||
explicit
|
||||
operator bool() const noexcept
|
||||
{
|
||||
return svc_ != nullptr;
|
||||
}
|
||||
|
||||
friend bool operator==(
|
||||
timeout_handle const& lhs,
|
||||
std::nullptr_t) noexcept
|
||||
{
|
||||
return lhs.svc_ == nullptr;
|
||||
}
|
||||
|
||||
friend bool operator==(
|
||||
std::nullptr_t,
|
||||
timeout_handle const& rhs) noexcept
|
||||
{
|
||||
return rhs.svc_ == nullptr;
|
||||
}
|
||||
|
||||
friend bool operator!=(
|
||||
timeout_handle const& lhs,
|
||||
std::nullptr_t) noexcept
|
||||
{
|
||||
return lhs.svc_ != nullptr;
|
||||
}
|
||||
|
||||
friend bool operator!=(
|
||||
std::nullptr_t,
|
||||
timeout_handle const& rhs) noexcept
|
||||
{
|
||||
return rhs.svc_ != nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
/** 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.
|
||||
*/
|
||||
BOOST_BEAST_DECL
|
||||
void
|
||||
set_timeout_service_options(
|
||||
net::io_context& ctx, // VFALCO should be execution_context
|
||||
std::chrono::seconds interval);
|
||||
|
||||
} // beast
|
||||
} // boost
|
||||
|
||||
#include <boost/beast/_experimental/core/impl/timeout_service.hpp>
|
||||
|
||||
#endif
|
@ -1,632 +0,0 @@
|
||||
//
|
||||
// Copyright (c) 2018 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/beast
|
||||
//
|
||||
|
||||
#ifndef BOOST_BEAST_CORE_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/timeout_service.hpp>
|
||||
#include <boost/beast/_experimental/core/detail/saved_handler.hpp>
|
||||
#include <boost/asio/async_result.hpp>
|
||||
#include <boost/asio/basic_stream_socket.hpp>
|
||||
#include <boost/asio/connect.hpp>
|
||||
#include <boost/asio/executor.hpp>
|
||||
#include <chrono>
|
||||
|
||||
namespace boost {
|
||||
namespace asio {
|
||||
namespace ip {
|
||||
class tcp;
|
||||
} // ip
|
||||
} // asio
|
||||
} // boost
|
||||
|
||||
namespace boost {
|
||||
namespace beast {
|
||||
|
||||
namespace detail {
|
||||
template<class, class, class>
|
||||
class connect_op;
|
||||
} // detail
|
||||
|
||||
/** 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 = net::executor
|
||||
>
|
||||
class basic_timeout_socket
|
||||
{
|
||||
template<class> class async_op;
|
||||
template<class, class, class>
|
||||
friend class detail::connect_op;
|
||||
|
||||
Executor ex_; // must come first
|
||||
timeout_handle rd_timer_;
|
||||
timeout_handle wr_timer_;
|
||||
timeout_handle cn_timer_;
|
||||
detail::saved_handler rd_op_;
|
||||
detail::saved_handler wr_op_;
|
||||
detail::saved_handler cn_op_;
|
||||
net::basic_stream_socket<Protocol> sock_;
|
||||
|
||||
public:
|
||||
/// The type of the next layer.
|
||||
using next_layer_type = net::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;
|
||||
|
||||
/** Destructor
|
||||
|
||||
The behavior of destruction while asynchronous operations
|
||||
are pending is undefined.
|
||||
*/
|
||||
~basic_timeout_socket();
|
||||
|
||||
// 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&,
|
||||
net::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() noexcept
|
||||
{
|
||||
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 noexcept
|
||||
{
|
||||
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() noexcept
|
||||
{
|
||||
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 noexcept
|
||||
{
|
||||
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
|
||||
net::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
|
||||
net::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<
|
||||
net::ip::tcp,
|
||||
net::io_context::executor_type>;
|
||||
|
||||
/**
|
||||
@defgroup async_connect boost::beast::async_connect
|
||||
|
||||
@brief Asynchronously establishes a socket connection by trying each
|
||||
endpoint in a sequence, and terminating if a timeout occurs.
|
||||
*/
|
||||
/* @{ */
|
||||
/** Asynchronously establishes a socket connection by trying each endpoint in a sequence.
|
||||
|
||||
This function attempts to connect a socket to one of a sequence of
|
||||
endpoints. It does this by repeated calls to the underlying socket's
|
||||
@c async_connect member function, once for each endpoint in the sequence,
|
||||
until a connection is successfully established or a timeout occurs.
|
||||
|
||||
@param s The @ref basic_timeout_socket to be connected. If the socket
|
||||
is already open, it will be closed.
|
||||
|
||||
@param endpoints A sequence of endpoints.
|
||||
|
||||
@param handler The handler to be called when the connect operation
|
||||
completes. Ownership of the handler may be transferred. The function
|
||||
signature of the handler must be:
|
||||
@code
|
||||
void handler(
|
||||
// Result of operation. if the sequence is empty, set to
|
||||
// net::error::not_found. Otherwise, contains the
|
||||
// error from the last connection attempt.
|
||||
error_code const& error,
|
||||
|
||||
// On success, the successfully connected endpoint.
|
||||
// Otherwise, a default-constructed endpoint.
|
||||
typename Protocol::endpoint const& endpoint
|
||||
);
|
||||
@endcode
|
||||
|
||||
Regardless of whether the asynchronous operation completes immediately or
|
||||
not, the handler will not be invoked from within this function. Invocation
|
||||
of the handler will be performed in a manner equivalent to using
|
||||
`net::io_context::post()`.
|
||||
|
||||
@par Example
|
||||
|
||||
@code
|
||||
net::tcp::resolver r(ioc);
|
||||
net::tcp::resolver::query q("host", "service");
|
||||
timeout_socket s(ioc.get_executor());
|
||||
|
||||
// ...
|
||||
|
||||
r.async_resolve(q, resolve_handler);
|
||||
|
||||
// ...
|
||||
|
||||
void resolve_handler(
|
||||
boost::system::error_code const& ec,
|
||||
tcp::resolver::results_type results)
|
||||
{
|
||||
if (!ec)
|
||||
{
|
||||
async_connect(s, results, connect_handler);
|
||||
}
|
||||
}
|
||||
|
||||
// ...
|
||||
|
||||
void connect_handler(
|
||||
boost::system::error_code const& ec,
|
||||
tcp::endpoint const& endpoint)
|
||||
{
|
||||
// ...
|
||||
}
|
||||
@endcode
|
||||
*/
|
||||
template<
|
||||
class Protocol, class Executor,
|
||||
class EndpointSequence,
|
||||
class RangeConnectHandler
|
||||
#if ! BOOST_BEAST_DOXYGEN
|
||||
,class = typename std::enable_if<
|
||||
net::is_endpoint_sequence<
|
||||
EndpointSequence>::value>::type
|
||||
#endif
|
||||
>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(RangeConnectHandler,
|
||||
void (boost::system::error_code, class Protocol::endpoint))
|
||||
async_connect(
|
||||
basic_timeout_socket<Protocol, Executor>& s,
|
||||
EndpointSequence const& endpoints,
|
||||
RangeConnectHandler&& handler);
|
||||
|
||||
/** Asynchronously establishes a socket connection by trying each endpoint in a sequence.
|
||||
|
||||
This function attempts to connect a socket to one of a sequence of
|
||||
endpoints. It does this by repeated calls to the underlying socket's
|
||||
@c async_connect member function, once for each endpoint in the sequence,
|
||||
until a connection is successfully established or a timeout occurs.
|
||||
|
||||
@param s The @ref basic_timeout_socket to be connected. If the socket
|
||||
is already open, it will be closed.
|
||||
|
||||
@param endpoints A sequence of endpoints.
|
||||
|
||||
@param connect_condition A function object that is called prior to each
|
||||
connection attempt. The signature of the function object must be:
|
||||
|
||||
@code
|
||||
bool connect_condition(
|
||||
boost::system::error_code const& ec,
|
||||
typename Protocol::endpoint const& next);
|
||||
@endcode
|
||||
|
||||
The @c ec parameter contains the result from the most recent connect
|
||||
operation. Before the first connection attempt, @c ec is always set to
|
||||
indicate success. The @c next parameter is the next endpoint to be tried.
|
||||
The function object should return true if the next endpoint should be tried,
|
||||
and false if it should be skipped.
|
||||
|
||||
@param handler The handler to be called when the connect operation
|
||||
completes. Ownership of the handler may be transferred. The function
|
||||
signature of the handler must be:
|
||||
@code
|
||||
void handler(
|
||||
// Result of operation. if the sequence is empty, set to
|
||||
// net::error::not_found. Otherwise, contains the
|
||||
// error from the last connection attempt.
|
||||
error_code const& error,
|
||||
|
||||
// On success, the successfully connected endpoint.
|
||||
// Otherwise, a default-constructed endpoint.
|
||||
typename Protocol::endpoint const& endpoint
|
||||
);
|
||||
@endcode
|
||||
|
||||
Regardless of whether the asynchronous operation completes immediately or
|
||||
not, the handler will not be invoked from within this function. Invocation
|
||||
of the handler will be performed in a manner equivalent to using
|
||||
`net::io_context::post()`.
|
||||
|
||||
@par Example
|
||||
|
||||
The following connect condition function object can be used to output
|
||||
information about the individual connection attempts:
|
||||
|
||||
@code
|
||||
struct my_connect_condition
|
||||
{
|
||||
bool operator()(
|
||||
boost::system::error_code const& ec,
|
||||
net::ip::tcp::endpoint const& next)
|
||||
{
|
||||
if (ec) std::cout << "Error: " << ec.message() << std::endl;
|
||||
std::cout << "Trying: " << next << std::endl;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
@endcode
|
||||
|
||||
It would be used with the @ref boost::beast::async_connect
|
||||
function as follows:
|
||||
|
||||
@code
|
||||
net::tcp::resolver r(ioc);
|
||||
net::tcp::resolver::query q("host", "service");
|
||||
timeout_socket s(ioc.get_executor());
|
||||
|
||||
// ...
|
||||
|
||||
r.async_resolve(q, resolve_handler);
|
||||
|
||||
// ...
|
||||
|
||||
void resolve_handler(
|
||||
boost::system::error_code const& ec,
|
||||
tcp::resolver::results_type results)
|
||||
{
|
||||
if (!ec)
|
||||
{
|
||||
async_connect(s, results, my_connect_condition{}, connect_handler);
|
||||
}
|
||||
}
|
||||
|
||||
// ...
|
||||
|
||||
void connect_handler(
|
||||
boost::system::error_code const& ec,
|
||||
tcp::endpoint const& endpoint)
|
||||
{
|
||||
// ...
|
||||
}
|
||||
@endcode
|
||||
*/
|
||||
template<
|
||||
class Protocol, class Executor,
|
||||
class EndpointSequence,
|
||||
class ConnectCondition,
|
||||
class RangeConnectHandler
|
||||
#if ! BOOST_BEAST_DOXYGEN
|
||||
,class = typename std::enable_if<
|
||||
net::is_endpoint_sequence<
|
||||
EndpointSequence>::value>::type
|
||||
#endif
|
||||
>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(RangeConnectHandler,
|
||||
void (boost::system::error_code, class Protocol::endpoint))
|
||||
async_connect(
|
||||
basic_timeout_socket<Protocol, Executor>& s,
|
||||
EndpointSequence const& endpoints,
|
||||
ConnectCondition connect_condition,
|
||||
RangeConnectHandler&& handler);
|
||||
|
||||
/** Asynchronously establishes a socket connection by trying each endpoint in a sequence.
|
||||
|
||||
This function attempts to connect a socket to one of a sequence of
|
||||
endpoints. It does this by repeated calls to the underlying socket's
|
||||
@c async_connect member function, once for each endpoint in the sequence,
|
||||
until a connection is successfully established or a timeout occurs.
|
||||
|
||||
@param s The @ref timeout_socket to be connected. If the socket
|
||||
is already open, it will be closed.
|
||||
|
||||
@param begin An iterator pointing to the start of a sequence of endpoints.
|
||||
|
||||
@param end An iterator pointing to the end of a sequence of endpoints.
|
||||
|
||||
@param handler The handler to be called when the connect operation
|
||||
completes. Ownership of the handler may be transferred. The function
|
||||
signature of the handler must be:
|
||||
@code
|
||||
void handler(
|
||||
// Result of operation. if the sequence is empty, set to
|
||||
// net::error::not_found. Otherwise, contains the
|
||||
// error from the last connection attempt.
|
||||
error_code const& error,
|
||||
|
||||
// On success, an iterator denoting the successfully
|
||||
// connected endpoint. Otherwise, the end iterator.
|
||||
Iterator iterator
|
||||
);
|
||||
@endcode
|
||||
|
||||
Regardless of whether the asynchronous operation completes immediately or
|
||||
not, the handler will not be invoked from within this function. Invocation
|
||||
of the handler will be performed in a manner equivalent to using
|
||||
`net::io_context::post()`.
|
||||
|
||||
@par Example
|
||||
|
||||
@code
|
||||
std::vector<tcp::endpoint> endpoints = ...;
|
||||
timeout_socket s(ioc.get_executor());
|
||||
|
||||
async_connect(s,
|
||||
endpoints.begin(), endpoints.end(),
|
||||
connect_handler);
|
||||
|
||||
void connect_handler(
|
||||
boost::system::error_code const& ec,
|
||||
std::vector<tcp::endpoint>::iterator)
|
||||
{
|
||||
// ...
|
||||
}
|
||||
@endcode
|
||||
*/
|
||||
template<
|
||||
class Protocol, class Executor,
|
||||
class Iterator,
|
||||
class IteratorConnectHandler
|
||||
#if ! BOOST_BEAST_DOXYGEN
|
||||
,class = typename std::enable_if<
|
||||
! net::is_endpoint_sequence<
|
||||
Iterator>::value>::type
|
||||
#endif
|
||||
>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler,
|
||||
void (boost::system::error_code, Iterator))
|
||||
async_connect(
|
||||
basic_timeout_socket<Protocol, Executor>& s,
|
||||
Iterator begin, Iterator end,
|
||||
IteratorConnectHandler&& handler);
|
||||
|
||||
/** Asynchronously establishes a socket connection by trying each endpoint in a sequence.
|
||||
|
||||
This function attempts to connect a socket to one of a sequence of
|
||||
endpoints. It does this by repeated calls to the underlying socket's
|
||||
@c async_connect member function, once for each endpoint in the sequence,
|
||||
until a connection is successfully established or a timeout occurs.
|
||||
|
||||
@param s The @ref basic_timeout_socket to be connected. If the socket
|
||||
is already open, it will be closed.
|
||||
|
||||
@param begin An iterator pointing to the start of a sequence of endpoints.
|
||||
|
||||
@param end An iterator pointing to the end of a sequence of endpoints.
|
||||
|
||||
@param connect_condition A function object that is called prior to each
|
||||
connection attempt. The signature of the function object must be:
|
||||
|
||||
@code
|
||||
bool connect_condition(
|
||||
boost::system::error_code const& ec,
|
||||
Iterator next);
|
||||
@endcode
|
||||
|
||||
@param handler The handler to be called when the connect operation
|
||||
completes. Ownership of the handler may be transferred. The function
|
||||
signature of the handler must be:
|
||||
@code
|
||||
void handler(
|
||||
// Result of operation. if the sequence is empty, set to
|
||||
// net::error::not_found. Otherwise, contains the
|
||||
// error from the last connection attempt.
|
||||
error_code const& error,
|
||||
|
||||
// On success, an iterator denoting the successfully
|
||||
// connected endpoint. Otherwise, the end iterator.
|
||||
Iterator iterator
|
||||
);
|
||||
@endcode
|
||||
|
||||
Regardless of whether the asynchronous operation completes immediately or
|
||||
not, the handler will not be invoked from within this function. Invocation
|
||||
of the handler will be performed in a manner equivalent to using
|
||||
`net::io_context::post()`.
|
||||
|
||||
@par Example
|
||||
|
||||
The following connect condition function object can be used to output
|
||||
information about the individual connection attempts:
|
||||
|
||||
@code
|
||||
struct my_connect_condition
|
||||
{
|
||||
bool operator()(
|
||||
boost::system::error_code const& ec,
|
||||
net::ip::tcp::endpoint const& next)
|
||||
{
|
||||
if (ec) std::cout << "Error: " << ec.message() << std::endl;
|
||||
std::cout << "Trying: " << next << std::endl;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
@endcode
|
||||
|
||||
It would be used with the @ref boost::beast::async_connect
|
||||
function as follows:
|
||||
|
||||
@code
|
||||
std::vector<tcp::endpoint> endpoints = ...;
|
||||
timeout_socket s(ioc.get_executor());
|
||||
|
||||
async_connect(s, endpoints.begin(), endpoints.end(),
|
||||
my_connect_condition{}, connect_handler);
|
||||
|
||||
void connect_handler(
|
||||
boost::system::error_code const& ec,
|
||||
std::vector<tcp::endpoint>::iterator)
|
||||
{
|
||||
// ...
|
||||
}
|
||||
@endcode
|
||||
*/
|
||||
template<
|
||||
class Protocol, class Executor,
|
||||
class Iterator,
|
||||
class ConnectCondition,
|
||||
class IteratorConnectHandler
|
||||
#if ! BOOST_BEAST_DOXYGEN
|
||||
,class = typename std::enable_if<
|
||||
! net::is_endpoint_sequence<
|
||||
Iterator>::value>::type
|
||||
#endif
|
||||
>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler,
|
||||
void (boost::system::error_code, Iterator))
|
||||
async_connect(
|
||||
basic_timeout_socket<Protocol, Executor>& s,
|
||||
Iterator begin, Iterator end,
|
||||
ConnectCondition connect_condition,
|
||||
IteratorConnectHandler&& handler);
|
||||
/* @} */
|
||||
|
||||
} // beast
|
||||
} // boost
|
||||
|
||||
#include <boost/beast/_experimental/core/impl/timeout_socket.hpp>
|
||||
|
||||
#endif
|
@ -1,73 +0,0 @@
|
||||
//
|
||||
// Copyright (c) 2018 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/beast
|
||||
//
|
||||
|
||||
#ifndef BOOST_BEAST_CORE_TIMEOUT_WORK_GUARD_HPP
|
||||
#define BOOST_BEAST_CORE_TIMEOUT_WORK_GUARD_HPP
|
||||
|
||||
#include <boost/beast/core/detail/config.hpp>
|
||||
#include <boost/beast/_experimental/core/timeout_service.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace beast {
|
||||
|
||||
class timeout_work_guard
|
||||
{
|
||||
timeout_handle h_;
|
||||
|
||||
public:
|
||||
timeout_work_guard(timeout_work_guard const&) = delete;
|
||||
timeout_work_guard& operator=(timeout_work_guard const&) = delete;
|
||||
|
||||
~timeout_work_guard()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
timeout_work_guard(timeout_work_guard&& other)
|
||||
: h_(other.h_)
|
||||
{
|
||||
other.h_ = nullptr;
|
||||
}
|
||||
|
||||
explicit
|
||||
timeout_work_guard(timeout_handle h)
|
||||
: h_(h)
|
||||
{
|
||||
h_.service().on_work_started(h_);
|
||||
}
|
||||
|
||||
bool
|
||||
owns_work() const
|
||||
{
|
||||
return h_ != nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
reset()
|
||||
{
|
||||
if(h_)
|
||||
h_.service().on_work_stopped(h_);
|
||||
}
|
||||
|
||||
bool
|
||||
try_complete()
|
||||
{
|
||||
BOOST_ASSERT(h_ != nullptr);
|
||||
auto result =
|
||||
h_.service().on_try_work_complete(h_);
|
||||
h_ = nullptr;
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
} // beast
|
||||
} // boost
|
||||
|
||||
#endif
|
@ -12,6 +12,7 @@
|
||||
|
||||
#include <boost/beast/core/detail/config.hpp>
|
||||
|
||||
#include <boost/beast/core/basic_stream_socket.hpp>
|
||||
#include <boost/beast/core/bind_handler.hpp>
|
||||
#include <boost/beast/core/buffer_traits.hpp>
|
||||
#include <boost/beast/core/buffered_read_stream.hpp>
|
||||
@ -37,6 +38,7 @@
|
||||
#include <boost/beast/core/span.hpp>
|
||||
#include <boost/beast/core/static_buffer.hpp>
|
||||
#include <boost/beast/core/static_string.hpp>
|
||||
#include <boost/beast/core/stream_socket.hpp>
|
||||
#include <boost/beast/core/string.hpp>
|
||||
#include <boost/beast/core/string_param.hpp>
|
||||
#include <boost/beast/core/type_traits.hpp>
|
||||
|
1131
include/boost/beast/core/basic_stream_socket.hpp
Normal file
1131
include/boost/beast/core/basic_stream_socket.hpp
Normal file
File diff suppressed because it is too large
Load Diff
241
include/boost/beast/core/detail/operation_base.hpp
Normal file
241
include/boost/beast/core/detail/operation_base.hpp
Normal file
@ -0,0 +1,241 @@
|
||||
//
|
||||
// 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_OPERATION_BASE_HPP
|
||||
#define BOOST_BEAST_CORE_DETAIL_OPERATION_BASE_HPP
|
||||
|
||||
#include <boost/beast/core/detail/config.hpp>
|
||||
#include <boost/asio/associated_allocator.hpp>
|
||||
#include <boost/asio/associated_executor.hpp>
|
||||
#include <boost/asio/handler_alloc_hook.hpp>
|
||||
#include <boost/asio/handler_continuation_hook.hpp>
|
||||
#include <boost/asio/handler_invoke_hook.hpp>
|
||||
#include <boost/asio/system_executor.hpp>
|
||||
#include <boost/core/empty_value.hpp>
|
||||
#include <utility>
|
||||
|
||||
namespace boost {
|
||||
namespace beast {
|
||||
namespace detail {
|
||||
|
||||
/** Base class which stores a handler and forwards handler associations.
|
||||
|
||||
This mix-in assists bind wrappers, intermediate handlers, composed
|
||||
operations, and similar types which store a handler, by acting as
|
||||
a base class which holds the handler. Any networking customizations
|
||||
on the handler will be propagated to the derived class. Specifically:
|
||||
|
||||
@li Any allocator associated with the handler will be propagated to
|
||||
this object. Otherwise, the allocator associated with this
|
||||
object will be a default allocator which the caller may specify
|
||||
through a template parameter and constructor parameter.
|
||||
|
||||
@li Any executor associated with the handler will be propagated to
|
||||
this object. Otherwise, the executor associated with this
|
||||
object will be a default executor which the caller may specify
|
||||
through a template parameter and constructor parameter.
|
||||
|
||||
@li The legacy customization points
|
||||
`asio_handler_invoke`,
|
||||
`asio_handler_allocate`,
|
||||
`asio_handler_deallocate`, and
|
||||
`asio_handler_is_continuation`,
|
||||
which use argument-dependent lookup, will be forwarded to the
|
||||
legacy customization points associated with the handler.
|
||||
|
||||
@par Example
|
||||
|
||||
The following declaration produces a class which wraps a
|
||||
handler and inherits all of the networking customizations
|
||||
associated with that handler:
|
||||
|
||||
@code
|
||||
template <class Handler>
|
||||
struct wrapped_handler : operation_base<
|
||||
Handler, net::associated_executor_t<Handler>>
|
||||
{
|
||||
template <class Handler_>
|
||||
explicit wrapped_handler (Handler_&& handler)
|
||||
: operation_base<Handler, net::associated_executor_t <Handler>>(
|
||||
std::forward<Handler_>(handler), net::get_associated_executor(handler))
|
||||
{
|
||||
}
|
||||
|
||||
template <class... Args>
|
||||
void operator()(Args&&... args)
|
||||
{
|
||||
this->handler_(std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
@endcode
|
||||
|
||||
@tparam Handler The type of the completion handler to store.
|
||||
This type must meet the requirements of <em>CompletionHandler</em>.
|
||||
|
||||
@tparam Executor The executor type to use if the handler does not
|
||||
have an associated executor.
|
||||
|
||||
@tparam Allocator The allocator type to use if the handler does not
|
||||
have an associated allocator. If this parameter is omitted, then
|
||||
`std::allocator<void>` will be used.
|
||||
*/
|
||||
template<
|
||||
class Handler,
|
||||
class Executor,
|
||||
class Allocator = std::allocator<void>
|
||||
>
|
||||
class operation_base
|
||||
#if ! BOOST_BEAST_DOXYGEN
|
||||
: private boost::empty_value<
|
||||
net::associated_allocator_t<
|
||||
Handler, Allocator>, 0>
|
||||
, private boost::empty_value<
|
||||
net::associated_executor_t<
|
||||
Handler, Executor>, 1>
|
||||
#endif
|
||||
{
|
||||
public:
|
||||
/** The type of allocator associated with this object.
|
||||
|
||||
If a class derived from @ref operation_base is a completion
|
||||
handler, then the associated allocator of the derived class will
|
||||
be this type.
|
||||
*/
|
||||
using allocator_type =
|
||||
net::associated_allocator_t<
|
||||
Handler, Allocator>;
|
||||
|
||||
/** The type of executor associated with this object.
|
||||
|
||||
If a class derived from @ref operation_base is a completion
|
||||
handler, then the associated executor of the derived class will
|
||||
be this type.
|
||||
*/
|
||||
using executor_type =
|
||||
net::associated_executor_t<
|
||||
Handler, Executor>;
|
||||
|
||||
/** Returns the allocator associated with this object.
|
||||
|
||||
If a class derived from @ref operation_base is a completion
|
||||
handler, then the object returned from this function will be used
|
||||
as the associated allocator of the derived class.
|
||||
*/
|
||||
allocator_type
|
||||
get_allocator() const noexcept
|
||||
{
|
||||
return boost::empty_value<
|
||||
allocator_type, 0>::get();
|
||||
}
|
||||
|
||||
/** Returns the allocator associated with this object.
|
||||
|
||||
If a class derived from @ref operation_base is a completion
|
||||
handler, then the object returned from this function will be used
|
||||
as the associated allocator of the derived class.
|
||||
*/
|
||||
executor_type
|
||||
get_executor() const noexcept
|
||||
{
|
||||
return boost::empty_value<
|
||||
executor_type, 1>::get();
|
||||
}
|
||||
|
||||
protected:
|
||||
Handler handler_;
|
||||
|
||||
template<
|
||||
class DeducedHandler
|
||||
#if BOOST_BEAST_DOXYGEN
|
||||
,class = typename std::enable_if<
|
||||
! std::is_same<typename
|
||||
std::decay<Handler_>::type,
|
||||
operation_base
|
||||
>::value>::type
|
||||
#endif
|
||||
>
|
||||
operation_base(
|
||||
DeducedHandler&& handler,
|
||||
executor_type ex = executor_type{},
|
||||
allocator_type alloc = allocator_type{})
|
||||
: boost::empty_value<allocator_type, 0>(
|
||||
boost::empty_init_t{}, alloc)
|
||||
, boost::empty_value<executor_type, 1>(
|
||||
boost::empty_init_t{}, ex)
|
||||
, handler_(std::forward<DeducedHandler>(handler))
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
#if ! BOOST_BEAST_DOXYGEN
|
||||
template<
|
||||
class Handler_,
|
||||
class Executor_,
|
||||
class Allocator_,
|
||||
class Function>
|
||||
friend
|
||||
void asio_handler_invoke(
|
||||
Function&& f,
|
||||
operation_base<
|
||||
Handler_, Executor_, Allocator_>* p);
|
||||
|
||||
friend
|
||||
void* asio_handler_allocate(
|
||||
std::size_t size, operation_base* p)
|
||||
{
|
||||
using net::asio_handler_allocate;
|
||||
return asio_handler_allocate(
|
||||
size, std::addressof(p->handler_));
|
||||
}
|
||||
|
||||
friend
|
||||
void asio_handler_deallocate(
|
||||
void* mem, std::size_t size,
|
||||
operation_base* p)
|
||||
{
|
||||
using net::asio_handler_deallocate;
|
||||
asio_handler_deallocate(mem, size,
|
||||
std::addressof(p->handler_));
|
||||
}
|
||||
|
||||
friend
|
||||
bool asio_handler_is_continuation(
|
||||
operation_base* p)
|
||||
{
|
||||
using net::asio_handler_is_continuation;
|
||||
return asio_handler_is_continuation(
|
||||
std::addressof(p->handler_));
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
#if ! BOOST_BEAST_DOXYGEN
|
||||
|
||||
template<
|
||||
class Handler,
|
||||
class Executor,
|
||||
class Allocator,
|
||||
class Function>
|
||||
void asio_handler_invoke(
|
||||
Function&& f,
|
||||
operation_base<
|
||||
Handler, Executor, Allocator>* p)
|
||||
{
|
||||
using net::asio_handler_invoke;
|
||||
asio_handler_invoke(
|
||||
f, std::addressof(p->handler_));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // detail
|
||||
} // beast
|
||||
} // boost
|
||||
|
||||
#endif
|
66
include/boost/beast/core/detail/stream_socket_base.hpp
Normal file
66
include/boost/beast/core/detail/stream_socket_base.hpp
Normal file
@ -0,0 +1,66 @@
|
||||
//
|
||||
// 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_STREAM_SOCKET_BASE_HPP
|
||||
#define BOOST_BEAST_CORE_DETAIL_STREAM_SOCKET_BASE_HPP
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/core/exchange.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace beast {
|
||||
namespace detail {
|
||||
|
||||
template<class, class, class>
|
||||
class stream_socket_connect_op;
|
||||
|
||||
class stream_socket_base
|
||||
{
|
||||
protected:
|
||||
class pending_guard
|
||||
{
|
||||
bool& b_;
|
||||
bool clear_ = true;
|
||||
|
||||
public:
|
||||
~pending_guard()
|
||||
{
|
||||
if(clear_)
|
||||
b_ = false;
|
||||
}
|
||||
|
||||
explicit
|
||||
pending_guard(bool& b)
|
||||
: b_(b)
|
||||
{
|
||||
BOOST_ASSERT(! b_);
|
||||
b_ = true;
|
||||
}
|
||||
|
||||
pending_guard(pending_guard&& other) noexcept
|
||||
: b_(other.b_)
|
||||
, clear_(boost::exchange(other.clear_, false))
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
reset()
|
||||
{
|
||||
BOOST_ASSERT(clear_);
|
||||
b_ = false;
|
||||
clear_ = false;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
} // detail
|
||||
} // beast
|
||||
} // boost
|
||||
|
||||
#endif
|
1073
include/boost/beast/core/impl/basic_stream_socket.hpp
Normal file
1073
include/boost/beast/core/impl/basic_stream_socket.hpp
Normal file
File diff suppressed because it is too large
Load Diff
30
include/boost/beast/core/stream_socket.hpp
Normal file
30
include/boost/beast/core/stream_socket.hpp
Normal file
@ -0,0 +1,30 @@
|
||||
//
|
||||
// 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_STREAM_SOCKET_HPP
|
||||
#define BOOST_BEAST_CORE_STREAM_SOCKET_HPP
|
||||
|
||||
#include <boost/beast/core/detail/config.hpp>
|
||||
#include <boost/beast/core/basic_stream_socket.hpp>
|
||||
#include <boost/beast/core/error.hpp>
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace beast {
|
||||
|
||||
/** A TCP/IP stream socket which supports timeouts and rate limits
|
||||
*/
|
||||
using stream_socket = basic_stream_socket<
|
||||
net::ip::tcp,
|
||||
net::io_context::executor_type>;
|
||||
|
||||
} // beast
|
||||
} // boost
|
||||
|
||||
#endif
|
@ -42,7 +42,7 @@ class saved_handler
|
||||
};
|
||||
|
||||
template<class Handler>
|
||||
class impl : public base
|
||||
class impl final : public base
|
||||
{
|
||||
Handler h_;
|
||||
net::executor_work_guard<
|
||||
|
@ -16,16 +16,18 @@ add_executable (tests-beast-core
|
||||
${EXTRAS_FILES}
|
||||
${TEST_MAIN}
|
||||
Jamfile
|
||||
buffer_test.hpp
|
||||
file_test.hpp
|
||||
_detail_base64.cpp
|
||||
_detail_buffer.cpp
|
||||
_detail_clamp.cpp
|
||||
_detail_operation_base.cpp
|
||||
_detail_read.cpp
|
||||
_detail_sha1.cpp
|
||||
_detail_tuple.cpp
|
||||
_detail_variant.cpp
|
||||
_detail_varint.cpp
|
||||
buffer_test.hpp
|
||||
file_test.hpp
|
||||
basic_stream_socket.cpp
|
||||
bind_handler.cpp
|
||||
buffer_traits.cpp
|
||||
buffered_read_stream.cpp
|
||||
@ -51,6 +53,7 @@ add_executable (tests-beast-core
|
||||
span.cpp
|
||||
static_buffer.cpp
|
||||
static_string.cpp
|
||||
stream_socket.cpp
|
||||
string.cpp
|
||||
string_param.cpp
|
||||
type_traits.cpp
|
||||
|
@ -11,11 +11,13 @@ local SOURCES =
|
||||
_detail_base64.cpp
|
||||
_detail_buffer.cpp
|
||||
_detail_clamp.cpp
|
||||
_detail_operation_base.cpp
|
||||
_detail_read.cpp
|
||||
_detail_sha1.cpp
|
||||
_detail_tuple.cpp
|
||||
_detail_variant.cpp
|
||||
_detail_varint.cpp
|
||||
basic_stream_socket.cpp
|
||||
bind_handler.cpp
|
||||
buffer_traits.cpp
|
||||
buffered_read_stream.cpp
|
||||
@ -41,6 +43,7 @@ local SOURCES =
|
||||
span.cpp
|
||||
static_buffer.cpp
|
||||
static_string.cpp
|
||||
stream_socket.cpp
|
||||
string.cpp
|
||||
string_param.cpp
|
||||
type_traits.cpp
|
||||
|
500
test/beast/core/_detail_operation_base.cpp
Normal file
500
test/beast/core/_detail_operation_base.cpp
Normal file
@ -0,0 +1,500 @@
|
||||
//
|
||||
// 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/core/detail/operation_base.hpp>
|
||||
|
||||
#include <boost/beast/_experimental/unit_test/suite.hpp>
|
||||
#include <boost/core/ignore_unused.hpp>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace boost {
|
||||
namespace beast {
|
||||
namespace detail {
|
||||
|
||||
namespace {
|
||||
|
||||
struct specialized_handler
|
||||
{
|
||||
bool invoked = false;
|
||||
struct executor
|
||||
{
|
||||
void* context() { return nullptr; }
|
||||
void on_work_started() {}
|
||||
void on_work_finished() {}
|
||||
template<class F> void dispatch(F&&) {}
|
||||
template<class F> void post(F&&) {}
|
||||
template<class F> void defer(F&&) {}
|
||||
};
|
||||
};
|
||||
|
||||
template<class Function>
|
||||
static
|
||||
void
|
||||
asio_handler_invoke(
|
||||
Function&& f,
|
||||
specialized_handler* p)
|
||||
{
|
||||
p->invoked = true;
|
||||
f();
|
||||
}
|
||||
|
||||
static
|
||||
void*
|
||||
asio_handler_allocate(
|
||||
std::size_t,
|
||||
specialized_handler* p)
|
||||
{
|
||||
p->invoked = true;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
asio_handler_deallocate(
|
||||
void*, std::size_t,
|
||||
specialized_handler* p)
|
||||
{
|
||||
p->invoked = true;
|
||||
}
|
||||
|
||||
static bool
|
||||
asio_handler_is_continuation(
|
||||
specialized_handler* p)
|
||||
{
|
||||
p->invoked = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
} // <anonymous>
|
||||
|
||||
} // detail
|
||||
} // beast
|
||||
} // boost
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace boost {
|
||||
namespace asio {
|
||||
|
||||
template<class Allocator>
|
||||
struct associated_allocator<
|
||||
boost::beast::detail::specialized_handler, Allocator>
|
||||
{
|
||||
using type = std::allocator<int>;
|
||||
|
||||
static type get(
|
||||
boost::beast::detail::specialized_handler const& h,
|
||||
Allocator const& a = Allocator()) noexcept
|
||||
{
|
||||
return type{};
|
||||
}
|
||||
};
|
||||
|
||||
template<class Executor>
|
||||
struct associated_executor<
|
||||
boost::beast::detail::specialized_handler, Executor>
|
||||
{
|
||||
using type = typename
|
||||
boost::beast::detail::specialized_handler::executor;
|
||||
|
||||
static type get(
|
||||
boost::beast::detail::specialized_handler const& h,
|
||||
Executor const& ex = Executor()) noexcept
|
||||
{
|
||||
return type{};
|
||||
}
|
||||
};
|
||||
|
||||
} // asio
|
||||
} // boost
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace boost {
|
||||
namespace beast {
|
||||
namespace detail {
|
||||
|
||||
class operation_base_test : public beast::unit_test::suite
|
||||
{
|
||||
public:
|
||||
using default_alloc = std::allocator<void>;
|
||||
using default_exec = net::system_executor;
|
||||
|
||||
struct U {};
|
||||
struct V {};
|
||||
|
||||
template<class E>
|
||||
struct executor
|
||||
{
|
||||
void* context() { return nullptr; }
|
||||
void on_work_started() {}
|
||||
void on_work_finished() {}
|
||||
template<class F> void dispatch(F&&) {}
|
||||
template<class F> void post(F&&) {}
|
||||
template<class F> void defer(F&&) {}
|
||||
};
|
||||
|
||||
struct none
|
||||
{
|
||||
void operator()() const
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct with_alloc
|
||||
{
|
||||
using allocator_type = std::allocator<U>;
|
||||
};
|
||||
|
||||
struct with_exec
|
||||
{
|
||||
using executor_type = executor<U>;
|
||||
};
|
||||
|
||||
struct move_only
|
||||
{
|
||||
move_only() = default;
|
||||
move_only(move_only&&) = default;
|
||||
move_only(move_only const&) = delete;
|
||||
void operator()() const{};
|
||||
};
|
||||
|
||||
template<
|
||||
class H,
|
||||
class E = default_exec,
|
||||
class A = default_alloc>
|
||||
using tested_base =
|
||||
operation_base<H, E, A>;
|
||||
|
||||
struct movable_handler : tested_base<move_only>
|
||||
{
|
||||
movable_handler()
|
||||
: tested_base<move_only>(move_only{})
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct test_handler :
|
||||
tested_base<specialized_handler>
|
||||
{
|
||||
test_handler()
|
||||
: tested_base<
|
||||
specialized_handler>(
|
||||
specialized_handler{})
|
||||
{
|
||||
}
|
||||
|
||||
bool invoked() const noexcept
|
||||
{
|
||||
return this->handler_.invoked;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// no nested allocator type
|
||||
|
||||
BOOST_STATIC_ASSERT(
|
||||
std::is_same<
|
||||
default_alloc,
|
||||
net::associated_allocator_t<
|
||||
tested_base<none>
|
||||
>>::value);
|
||||
|
||||
BOOST_STATIC_ASSERT(
|
||||
std::is_same<
|
||||
default_alloc,
|
||||
decltype(net::get_associated_allocator(
|
||||
std::declval<tested_base<none>>()
|
||||
))>::value);
|
||||
|
||||
BOOST_STATIC_ASSERT(
|
||||
std::is_same<
|
||||
default_alloc,
|
||||
decltype(net::get_associated_allocator(
|
||||
std::declval<tested_base<none>>()
|
||||
))>::value);
|
||||
|
||||
BOOST_STATIC_ASSERT(
|
||||
std::is_same<
|
||||
std::allocator<U>,
|
||||
decltype(net::get_associated_allocator(std::declval<
|
||||
tested_base<none, default_exec, std::allocator<U>>>()
|
||||
))>::value);
|
||||
|
||||
// shouldn't work due to net.ts limitations
|
||||
BOOST_STATIC_ASSERT(
|
||||
! std::is_same<
|
||||
std::allocator<U>,
|
||||
decltype(net::get_associated_allocator(
|
||||
std::declval<tested_base<none>>(),
|
||||
std::declval<std::allocator<U>>()
|
||||
))>::value);
|
||||
BOOST_STATIC_ASSERT(
|
||||
std::is_same<
|
||||
default_alloc,
|
||||
decltype(net::get_associated_allocator(
|
||||
std::declval<tested_base<none>>(),
|
||||
std::declval<std::allocator<U>>()
|
||||
))>::value);
|
||||
|
||||
// nested allocator_type
|
||||
|
||||
BOOST_STATIC_ASSERT(
|
||||
std::is_same<
|
||||
std::allocator<U>,
|
||||
net::associated_allocator_t<
|
||||
tested_base<with_alloc>
|
||||
>>::value);
|
||||
|
||||
BOOST_STATIC_ASSERT(
|
||||
std::is_same<
|
||||
std::allocator<U>,
|
||||
decltype(net::get_associated_allocator(
|
||||
std::declval<tested_base<with_alloc>>()
|
||||
))>::value);
|
||||
|
||||
BOOST_STATIC_ASSERT(
|
||||
std::is_same<
|
||||
std::allocator<U>,
|
||||
decltype(net::get_associated_allocator(
|
||||
std::declval<tested_base<with_alloc>>(),
|
||||
std::declval<std::allocator<V>>()
|
||||
))>::value);
|
||||
|
||||
// specialization of associated_allocator
|
||||
|
||||
BOOST_STATIC_ASSERT(
|
||||
std::is_same<
|
||||
std::allocator<int>,
|
||||
net::associated_allocator_t<
|
||||
tested_base<
|
||||
specialized_handler>
|
||||
>>::value);
|
||||
|
||||
BOOST_STATIC_ASSERT(
|
||||
std::is_same<
|
||||
std::allocator<int>,
|
||||
decltype(net::get_associated_allocator(
|
||||
std::declval<tested_base<
|
||||
specialized_handler>>()
|
||||
))>::value);
|
||||
|
||||
BOOST_STATIC_ASSERT(
|
||||
std::is_same<
|
||||
std::allocator<int>,
|
||||
decltype(net::get_associated_allocator(
|
||||
std::declval<tested_base<
|
||||
specialized_handler>>(),
|
||||
std::declval<std::allocator<V>>()
|
||||
))>::value);
|
||||
|
||||
// no nested executor type
|
||||
|
||||
BOOST_STATIC_ASSERT(
|
||||
std::is_same<
|
||||
default_exec,
|
||||
net::associated_executor_t<
|
||||
tested_base<none>
|
||||
>>::value);
|
||||
|
||||
BOOST_STATIC_ASSERT(
|
||||
std::is_same<
|
||||
executor<U>,
|
||||
net::associated_executor_t<
|
||||
tested_base<none, executor<U>>
|
||||
>>::value);
|
||||
|
||||
BOOST_STATIC_ASSERT(
|
||||
std::is_same<
|
||||
default_exec,
|
||||
decltype(net::get_associated_executor(
|
||||
std::declval<tested_base<none>>()
|
||||
))>::value);
|
||||
|
||||
BOOST_STATIC_ASSERT(
|
||||
std::is_same<
|
||||
executor<U>,
|
||||
decltype(net::get_associated_executor(std::declval<
|
||||
tested_base<none, executor<U>>>()
|
||||
))>::value);
|
||||
|
||||
// shouldn't work due to net.ts limitations
|
||||
BOOST_STATIC_ASSERT(
|
||||
! std::is_same<
|
||||
executor<U>,
|
||||
decltype(net::get_associated_executor(
|
||||
std::declval<tested_base<none>>(),
|
||||
std::declval<executor<U>>()
|
||||
))>::value);
|
||||
BOOST_STATIC_ASSERT(
|
||||
std::is_same<
|
||||
default_exec,
|
||||
decltype(net::get_associated_executor(
|
||||
std::declval<tested_base<none>>(),
|
||||
std::declval<executor<U>>()
|
||||
))>::value);
|
||||
|
||||
// nested executor_type
|
||||
|
||||
BOOST_STATIC_ASSERT(
|
||||
std::is_same<
|
||||
executor<U>,
|
||||
net::associated_executor_t<
|
||||
tested_base<with_exec>
|
||||
>>::value);
|
||||
|
||||
BOOST_STATIC_ASSERT(
|
||||
std::is_same<
|
||||
executor<U>,
|
||||
decltype(net::get_associated_executor(
|
||||
std::declval<tested_base<with_exec>>()
|
||||
))>::value);
|
||||
|
||||
BOOST_STATIC_ASSERT(
|
||||
std::is_same<
|
||||
executor<U>,
|
||||
decltype(net::get_associated_executor(
|
||||
std::declval<tested_base<with_exec>>(),
|
||||
std::declval<executor<V>>()
|
||||
))>::value);
|
||||
|
||||
// specialization of associated_executor
|
||||
|
||||
BOOST_STATIC_ASSERT(
|
||||
std::is_same<
|
||||
specialized_handler::executor,
|
||||
net::associated_executor_t<
|
||||
tested_base<
|
||||
specialized_handler>
|
||||
>>::value);
|
||||
|
||||
BOOST_STATIC_ASSERT(
|
||||
std::is_same<
|
||||
specialized_handler::executor,
|
||||
decltype(net::get_associated_executor(std::declval<
|
||||
tested_base<
|
||||
specialized_handler>>()
|
||||
))>::value);
|
||||
|
||||
BOOST_STATIC_ASSERT(
|
||||
std::is_same<
|
||||
specialized_handler::executor,
|
||||
decltype(net::get_associated_executor(std::declval<
|
||||
tested_base<
|
||||
specialized_handler>>(),
|
||||
std::declval<executor<V>>()
|
||||
))>::value);
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
template <class Handler>
|
||||
struct wrapped_handler : operation_base<
|
||||
Handler, net::associated_executor_t<Handler>>
|
||||
{
|
||||
template <class Handler_>
|
||||
explicit wrapped_handler (Handler_&& handler)
|
||||
: operation_base<Handler, net::associated_executor_t <Handler>>(
|
||||
std::forward<Handler_>(handler), net::get_associated_executor(handler))
|
||||
{
|
||||
}
|
||||
|
||||
template <class... Args>
|
||||
void operator()(Args&&... args)
|
||||
{
|
||||
this->handler_(std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
void
|
||||
testJavadocs()
|
||||
{
|
||||
wrapped_handler<none>{none{}}();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
void
|
||||
testLegacyHooks()
|
||||
{
|
||||
// asio_handler_invoke
|
||||
{
|
||||
test_handler h;
|
||||
BEAST_EXPECT(! h.invoked());
|
||||
bool invoked = false;
|
||||
using net::asio_handler_invoke;
|
||||
asio_handler_invoke(
|
||||
[&invoked]
|
||||
{
|
||||
invoked =true;
|
||||
}, &h);
|
||||
BEAST_EXPECT(invoked);
|
||||
BEAST_EXPECT(h.invoked());
|
||||
}
|
||||
|
||||
// asio_handler_allocate
|
||||
{
|
||||
test_handler h;
|
||||
BEAST_EXPECT(! h.invoked());
|
||||
using net::asio_handler_allocate;
|
||||
asio_handler_allocate(0, &h);
|
||||
BEAST_EXPECT(h.invoked());
|
||||
}
|
||||
|
||||
// asio_handler_deallocate
|
||||
{
|
||||
test_handler h;
|
||||
BEAST_EXPECT(! h.invoked());
|
||||
using net::asio_handler_deallocate;
|
||||
asio_handler_deallocate(nullptr, 0, &h);
|
||||
BEAST_EXPECT(h.invoked());
|
||||
}
|
||||
|
||||
// asio_handler_deallocate
|
||||
{
|
||||
test_handler h;
|
||||
BEAST_EXPECT(! h.invoked());
|
||||
using net::asio_handler_is_continuation;
|
||||
asio_handler_is_continuation(&h);
|
||||
BEAST_EXPECT(h.invoked());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testSpecialMembers()
|
||||
{
|
||||
{
|
||||
test_handler h1;
|
||||
test_handler h2(std::move(h1));
|
||||
test_handler h3(h2);
|
||||
boost::ignore_unused(h3);
|
||||
}
|
||||
|
||||
{
|
||||
movable_handler h1;
|
||||
movable_handler h2(std::move(h1));
|
||||
boost::ignore_unused(h2);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
run() override
|
||||
{
|
||||
testJavadocs();
|
||||
testLegacyHooks();
|
||||
testSpecialMembers();
|
||||
}
|
||||
};
|
||||
|
||||
BEAST_DEFINE_TESTSUITE(beast,core,operation_base);
|
||||
|
||||
} // detail
|
||||
} // beast
|
||||
} // boost
|
132
test/beast/core/basic_stream_socket.cpp
Normal file
132
test/beast/core/basic_stream_socket.cpp
Normal file
@ -0,0 +1,132 @@
|
||||
//
|
||||
// Copyright (c) 2018 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/beast
|
||||
//
|
||||
|
||||
// Test that header file is self-contained.
|
||||
#include <boost/beast/core/basic_stream_socket.hpp>
|
||||
|
||||
#include <boost/beast/_experimental/unit_test/suite.hpp>
|
||||
#include <boost/beast/core/stream_socket.hpp>
|
||||
#include <boost/asio/read_until.hpp>
|
||||
#include <boost/asio/streambuf.hpp>
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
#include <boost/asio/ip/udp.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace beast {
|
||||
|
||||
class basic_stream_socket_test
|
||||
: public beast::unit_test::suite
|
||||
{
|
||||
public:
|
||||
struct read_handler
|
||||
{
|
||||
template<class... Args>
|
||||
void operator()(Args&&...)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
template <class Protocol, class Executor, class ReadHandler>
|
||||
void async_read_line (
|
||||
basic_stream_socket<Protocol, Executor>& stream,
|
||||
net::streambuf& buffer, ReadHandler&& handler)
|
||||
{
|
||||
stream.expires_after(std::chrono::seconds(30));
|
||||
|
||||
net::async_read_until(stream, buffer, "\r\n", std::forward<ReadHandler>(handler));
|
||||
}
|
||||
|
||||
void
|
||||
testJavadocs()
|
||||
{
|
||||
BEAST_EXPECT((&basic_stream_socket_test::async_read_line<
|
||||
net::ip::tcp, net::io_context::executor_type, read_handler>));
|
||||
}
|
||||
|
||||
struct other_t
|
||||
{
|
||||
};
|
||||
|
||||
void
|
||||
testMembers()
|
||||
{
|
||||
using tcp = net::ip::tcp;
|
||||
using ep_t = tcp::endpoint;
|
||||
using ioc_t = net::io_context;
|
||||
using ex_t = ioc_t::executor_type;
|
||||
using stream_t = basic_stream_socket<tcp, ex_t>;
|
||||
|
||||
net::io_context ioc;
|
||||
auto ex = ioc.get_executor();
|
||||
|
||||
// construction
|
||||
|
||||
{
|
||||
stream_t{ioc};
|
||||
stream_t{ex};
|
||||
BOOST_STATIC_ASSERT(! std::is_constructible<
|
||||
stream_t, other_t>::value);
|
||||
}
|
||||
{
|
||||
stream_t{ioc, tcp::v4()};
|
||||
stream_t{ex, tcp::v4()};
|
||||
BOOST_STATIC_ASSERT(! std::is_constructible<
|
||||
stream_t, other_t, tcp>::value);
|
||||
}
|
||||
{
|
||||
stream_t{ioc, ep_t{}};
|
||||
stream_t{ex, ep_t{}};
|
||||
BOOST_STATIC_ASSERT(! std::is_constructible<
|
||||
stream_t, other_t, ep_t>::value);
|
||||
}
|
||||
{
|
||||
tcp::socket sock(ioc);
|
||||
stream_t{ioc, std::move(sock)};
|
||||
stream_t{ex, std::move(sock)};
|
||||
BOOST_STATIC_ASSERT(! std::is_constructible<
|
||||
stream_t, other_t, tcp::socket>::value);
|
||||
}
|
||||
|
||||
// move
|
||||
|
||||
{
|
||||
stream_t s1(ioc);
|
||||
stream_t s2(std::move(s1));
|
||||
}
|
||||
{
|
||||
stream_t s1(ioc);
|
||||
stream_t s2(ioc);
|
||||
s2 = std::move(s1);
|
||||
}
|
||||
|
||||
// converting move
|
||||
|
||||
{
|
||||
// We don't have any convertible protocol types
|
||||
#if 0
|
||||
basic_stream_socket<net::ip::udp, ex_t> s1(ioc);
|
||||
stream_t s2(std::move(s1));
|
||||
|
||||
stream_t s3 = std::move(s1);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
run()
|
||||
{
|
||||
testJavadocs();
|
||||
testMembers();
|
||||
}
|
||||
};
|
||||
|
||||
BEAST_DEFINE_TESTSUITE(beast,core,basic_stream_socket);
|
||||
|
||||
} // beast
|
||||
} // boost
|
@ -8,19 +8,18 @@
|
||||
//
|
||||
|
||||
// Test that header file is self-contained.
|
||||
#include <boost/beast/_experimental/core/timeout_socket.hpp>
|
||||
#include <boost/beast/core/stream_socket.hpp>
|
||||
|
||||
#include <boost/beast/_experimental/core/timeout_service.hpp>
|
||||
|
||||
#include <boost/beast/test/yield_to.hpp>
|
||||
#include <boost/beast/_experimental/unit_test/suite.hpp>
|
||||
#include <boost/beast/test/yield_to.hpp>
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
#include <array>
|
||||
#include <thread>
|
||||
|
||||
namespace boost {
|
||||
namespace beast {
|
||||
|
||||
class timeout_socket_test
|
||||
class stream_socket_test
|
||||
: public beast::unit_test::suite
|
||||
, public test::enable_yield_to
|
||||
{
|
||||
@ -152,18 +151,117 @@ public:
|
||||
server srv(ep, log);
|
||||
{
|
||||
net::io_context ioc;
|
||||
set_timeout_service_options(
|
||||
ioc, std::chrono::seconds(1));
|
||||
timeout_socket s(ioc);
|
||||
stream_socket s(ioc);
|
||||
s.next_layer().connect(ep);
|
||||
char buf[32];
|
||||
error_code ec;
|
||||
s.expires_after(std::chrono::seconds(1));
|
||||
s.async_read_some(net::buffer(buf),
|
||||
[&](error_code ec, std::size_t n)
|
||||
[&ec](error_code ec_, std::size_t)
|
||||
{
|
||||
log << "read_some: " << ec.message() << "\n";
|
||||
boost::ignore_unused(ec, n);
|
||||
ec = ec_;
|
||||
});
|
||||
ioc.run();
|
||||
BEAST_EXPECTS(
|
||||
ec == error::timeout, ec.message());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testConnect()
|
||||
{
|
||||
using es_t =
|
||||
std::array<net::ip::tcp::endpoint, 2>;
|
||||
{
|
||||
net::io_context ioc;
|
||||
stream_socket s(ioc);
|
||||
beast::async_connect(s, es_t{},
|
||||
[](error_code, es_t::value_type)
|
||||
{
|
||||
});
|
||||
}
|
||||
{
|
||||
net::io_context ioc;
|
||||
stream_socket s(ioc);
|
||||
beast::async_connect(s, es_t{},
|
||||
[](error_code, es_t::value_type)
|
||||
{
|
||||
return true;
|
||||
},
|
||||
[](error_code, es_t::value_type)
|
||||
{
|
||||
});
|
||||
}
|
||||
{
|
||||
es_t es;
|
||||
net::io_context ioc;
|
||||
stream_socket s(ioc);
|
||||
beast::async_connect(s, es.begin(), es.end(),
|
||||
[](error_code, es_t::iterator)
|
||||
{
|
||||
});
|
||||
}
|
||||
{
|
||||
es_t es;
|
||||
net::io_context ioc;
|
||||
stream_socket s(ioc);
|
||||
beast::async_connect(s, es.begin(), es.end(),
|
||||
[](error_code, es_t::value_type)
|
||||
{
|
||||
return true;
|
||||
},
|
||||
[](error_code, es_t::iterator)
|
||||
{
|
||||
});
|
||||
}
|
||||
pass();
|
||||
}
|
||||
|
||||
void callConnects()
|
||||
{
|
||||
using es_t =
|
||||
std::array<net::ip::tcp::endpoint, 2>;
|
||||
{
|
||||
net::io_context ioc;
|
||||
stream_socket s(ioc);
|
||||
async_connect(s, es_t{},
|
||||
[](error_code, es_t::value_type)
|
||||
{
|
||||
});
|
||||
}
|
||||
{
|
||||
net::io_context ioc;
|
||||
stream_socket s(ioc);
|
||||
async_connect(s, es_t{},
|
||||
[](error_code, es_t::value_type)
|
||||
{
|
||||
return true;
|
||||
},
|
||||
[](error_code, es_t::value_type)
|
||||
{
|
||||
});
|
||||
}
|
||||
{
|
||||
es_t es;
|
||||
net::io_context ioc;
|
||||
stream_socket s(ioc);
|
||||
async_connect(s, es.begin(), es.end(),
|
||||
[](error_code, es_t::iterator)
|
||||
{
|
||||
});
|
||||
}
|
||||
{
|
||||
es_t es;
|
||||
net::io_context ioc;
|
||||
stream_socket s(ioc);
|
||||
async_connect(s, es.begin(), es.end(),
|
||||
[](error_code, es_t::value_type)
|
||||
{
|
||||
return true;
|
||||
},
|
||||
[](error_code, es_t::iterator)
|
||||
{
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -171,12 +269,11 @@ public:
|
||||
run()
|
||||
{
|
||||
testAsync();
|
||||
|
||||
pass();
|
||||
testConnect();
|
||||
}
|
||||
};
|
||||
|
||||
BEAST_DEFINE_TESTSUITE(beast,core,timeout_socket);
|
||||
BEAST_DEFINE_TESTSUITE(beast,core,stream_socket);
|
||||
|
||||
} // beast
|
||||
} // boost
|
@ -21,9 +21,6 @@ add_executable (tests-beast-experimental
|
||||
icy_stream.cpp
|
||||
ssl_stream.cpp
|
||||
stream.cpp
|
||||
timeout_socket.cpp
|
||||
timeout_service.cpp
|
||||
timeout_work_guard.cpp
|
||||
)
|
||||
|
||||
set_property(TARGET tests-beast-experimental PROPERTY FOLDER "tests")
|
||||
|
@ -13,9 +13,6 @@ local SOURCES =
|
||||
icy_stream.cpp
|
||||
ssl_stream.cpp
|
||||
stream.cpp
|
||||
timeout_socket.cpp
|
||||
timeout_service.cpp
|
||||
timeout_work_guard.cpp
|
||||
;
|
||||
|
||||
local RUN_TESTS ;
|
||||
|
@ -1,35 +0,0 @@
|
||||
//
|
||||
// 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/_experimental/unit_test/suite.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace beast {
|
||||
|
||||
class timeout_service_test
|
||||
: public beast::unit_test::suite
|
||||
{
|
||||
public:
|
||||
void
|
||||
run() override
|
||||
{
|
||||
net::io_context ctx;
|
||||
set_timeout_service_options(ctx,
|
||||
std::chrono::seconds(1));
|
||||
pass();
|
||||
}
|
||||
};
|
||||
|
||||
BEAST_DEFINE_TESTSUITE(beast,core,timeout_service);
|
||||
|
||||
} // beast
|
||||
} // boost
|
@ -1,11 +0,0 @@
|
||||
//
|
||||
// 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_work_guard.hpp>
|
Reference in New Issue
Block a user