mirror of
https://github.com/boostorg/beast.git
synced 2025-07-29 20:37:31 +02:00
Add RatePolicy to basic_stream
This commit is contained in:
@ -4,6 +4,7 @@ Version 216:
|
||||
* Add websocket::stream timeouts
|
||||
* Use suggested timeouts in Websocket examples
|
||||
* Add make_strand
|
||||
* Add RatePolicy to basic_stream
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
@ -37,6 +37,7 @@
|
||||
<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>
|
||||
<member><link linkend="beast.ref.boost__beast__rate_policy_access">rate_policy_access</link> <emphasis role="green">🞲</emphasis></member>
|
||||
</simplelist>
|
||||
</entry>
|
||||
<entry valign="top">
|
||||
@ -44,11 +45,13 @@
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="beast.ref.boost__beast__saved_handler">saved_handler</link> <emphasis role="green">🞲</emphasis></member>
|
||||
<member><link linkend="beast.ref.boost__beast__span">span</link></member>
|
||||
<member><link linkend="beast.ref.boost__beast__simple_rate_policy">simple_rate_policy</link> <emphasis role="green">🞲</emphasis></member>
|
||||
<member><link linkend="beast.ref.boost__beast__static_string">static_string</link></member>
|
||||
<member><link linkend="beast.ref.boost__beast__stable_async_op_base">stable_async_op_base</link> <emphasis role="green">🞲</emphasis></member>
|
||||
<member><link linkend="beast.ref.boost__beast__string_param">string_param</link></member>
|
||||
<member><link linkend="beast.ref.boost__beast__string_view">string_view</link></member>
|
||||
<member><link linkend="beast.ref.boost__beast__tcp_stream">tcp_stream</link> <emphasis role="green">🞲</emphasis></member>
|
||||
<member><link linkend="beast.ref.boost__beast__unlimited_rate_policy">unlimited_rate_policy</link> <emphasis role="green">🞲</emphasis></member>
|
||||
</simplelist>
|
||||
<bridgehead renderas="sect3">Constants</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include <boost/beast/core/detail/config.hpp>
|
||||
#include <boost/beast/core/detail/stream_base.hpp>
|
||||
#include <boost/beast/core/error.hpp>
|
||||
#include <boost/beast/core/rate_policy.hpp>
|
||||
#include <boost/beast/core/stream_traits.hpp>
|
||||
#include <boost/beast/websocket/role.hpp> // VFALCO This is unfortunate
|
||||
#include <boost/asio/async_result.hpp>
|
||||
@ -25,6 +26,8 @@
|
||||
#include <boost/enable_shared_from_this.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <chrono>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
|
||||
namespace boost {
|
||||
namespace asio {
|
||||
@ -37,9 +40,7 @@ template<typename> class stream;
|
||||
namespace boost {
|
||||
namespace beast {
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** A stream socket wrapper with timeouts and associated executor.
|
||||
/** A stream socket wrapper with timeouts, bandwidth limits, and associated executor.
|
||||
|
||||
This stream wraps a `net::basic_stream_socket` to provide
|
||||
the following features:
|
||||
@ -193,7 +194,9 @@ namespace beast {
|
||||
*/
|
||||
template<
|
||||
class Protocol,
|
||||
class Executor = net::executor>
|
||||
class Executor = net::executor,
|
||||
class RatePolicy = unlimited_rate_policy
|
||||
>
|
||||
class basic_stream
|
||||
#if ! BOOST_BEAST_DOXYGEN
|
||||
: private detail::stream_base
|
||||
@ -228,6 +231,7 @@ public:
|
||||
#endif
|
||||
struct impl_type
|
||||
: boost::enable_shared_from_this<impl_type>
|
||||
, boost::empty_value<RatePolicy>
|
||||
{
|
||||
// must come first
|
||||
net::basic_stream_socket<
|
||||
@ -235,6 +239,8 @@ public:
|
||||
|
||||
op_state read;
|
||||
op_state write;
|
||||
net::steady_timer timer; // rate timer
|
||||
int waiting = 0;
|
||||
|
||||
impl_type(impl_type&&) = default;
|
||||
|
||||
@ -250,6 +256,21 @@ public:
|
||||
return this->socket.get_executor();
|
||||
}
|
||||
|
||||
RatePolicy&
|
||||
policy() noexcept
|
||||
{
|
||||
return this->boost::empty_value<RatePolicy>::get();
|
||||
}
|
||||
|
||||
RatePolicy const&
|
||||
policy() const noexcept
|
||||
{
|
||||
return this->boost::empty_value<RatePolicy>::get();
|
||||
}
|
||||
|
||||
template<class Executor2>
|
||||
void on_timer(Executor2 const& ex2);
|
||||
|
||||
void reset(); // set timeouts to never
|
||||
void close(); // cancel everything
|
||||
};
|
||||
@ -265,10 +286,10 @@ private:
|
||||
|
||||
template<bool, class, class> class async_op;
|
||||
|
||||
template<class, class, class>
|
||||
template<class, class, class, class>
|
||||
friend class detail::basic_stream_connect_op;
|
||||
|
||||
template<class, class>
|
||||
template<class, class, class>
|
||||
friend class basic_stream;
|
||||
|
||||
struct timeout_handler;
|
||||
@ -354,6 +375,20 @@ public:
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/// Returns the rate policy associated with the object
|
||||
RatePolicy&
|
||||
rate_policy() noexcept
|
||||
{
|
||||
return impl_->policy();
|
||||
}
|
||||
|
||||
/// Returns the rate policy associated with the object
|
||||
RatePolicy const&
|
||||
rate_policy() const noexcept
|
||||
{
|
||||
return impl_->policy();
|
||||
}
|
||||
|
||||
/** Set the timeout for the next logical operation.
|
||||
|
||||
This sets either the read timer, the write timer, or
|
||||
@ -1148,7 +1183,7 @@ connect(
|
||||
to using `net::post`.
|
||||
*/
|
||||
template<
|
||||
class Protocol, class Executor,
|
||||
class Protocol, class Executor, class RatePolicy,
|
||||
class EndpointSequence,
|
||||
class RangeConnectHandler
|
||||
#if ! BOOST_BEAST_DOXYGEN
|
||||
@ -1160,7 +1195,7 @@ template<
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(RangeConnectHandler,
|
||||
void (error_code, typename Protocol::endpoint))
|
||||
async_connect(
|
||||
basic_stream<Protocol, Executor>& stream,
|
||||
basic_stream<Protocol, Executor, RatePolicy>& stream,
|
||||
EndpointSequence const& endpoints,
|
||||
RangeConnectHandler&& handler);
|
||||
|
||||
@ -1236,7 +1271,7 @@ async_connect(
|
||||
@endcode
|
||||
*/
|
||||
template<
|
||||
class Protocol, class Executor,
|
||||
class Protocol, class Executor, class RatePolicy,
|
||||
class EndpointSequence,
|
||||
class ConnectCondition,
|
||||
class RangeConnectHandler
|
||||
@ -1249,7 +1284,7 @@ template<
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(RangeConnectHandler,
|
||||
void (error_code, typename Protocol::endpoint))
|
||||
async_connect(
|
||||
basic_stream<Protocol, Executor>& stream,
|
||||
basic_stream<Protocol, Executor, RatePolicy>& stream,
|
||||
EndpointSequence const& endpoints,
|
||||
ConnectCondition connect_condition,
|
||||
RangeConnectHandler&& handler);
|
||||
@ -1296,13 +1331,13 @@ async_connect(
|
||||
to using `net::post`.
|
||||
*/
|
||||
template<
|
||||
class Protocol, class Executor,
|
||||
class Protocol, class Executor, class RatePolicy,
|
||||
class Iterator,
|
||||
class IteratorConnectHandler>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler,
|
||||
void (error_code, Iterator))
|
||||
async_connect(
|
||||
basic_stream<Protocol, Executor>& stream,
|
||||
basic_stream<Protocol, Executor, RatePolicy>& stream,
|
||||
Iterator begin, Iterator end,
|
||||
IteratorConnectHandler&& handler);
|
||||
|
||||
@ -1355,14 +1390,14 @@ async_connect(
|
||||
to using `net::post`.
|
||||
*/
|
||||
template<
|
||||
class Protocol, class Executor,
|
||||
class Protocol, class Executor, class RatePolicy,
|
||||
class Iterator,
|
||||
class ConnectCondition,
|
||||
class IteratorConnectHandler>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler,
|
||||
void (error_code, Iterator))
|
||||
async_connect(
|
||||
basic_stream<Protocol, Executor>& stream,
|
||||
basic_stream<Protocol, Executor, RatePolicy>& stream,
|
||||
Iterator begin, Iterator end,
|
||||
ConnectCondition connect_condition,
|
||||
IteratorConnectHandler&& handler);
|
||||
|
@ -21,7 +21,7 @@ namespace boost {
|
||||
namespace beast {
|
||||
namespace detail {
|
||||
|
||||
template<class, class, class>
|
||||
template<class, class, class, class>
|
||||
class basic_stream_connect_op;
|
||||
|
||||
struct any_endpoint
|
||||
|
@ -12,6 +12,7 @@
|
||||
|
||||
#include <boost/beast/core/async_op_base.hpp>
|
||||
#include <boost/beast/core/buffer_size.hpp>
|
||||
#include <boost/beast/core/buffers_prefix.hpp>
|
||||
#include <boost/beast/core/detail/type_traits.hpp>
|
||||
#include <boost/beast/websocket/teardown.hpp>
|
||||
#include <boost/asio/bind_executor.hpp>
|
||||
@ -28,21 +29,82 @@ namespace beast {
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<class Protocol, class Executor>
|
||||
template<class Protocol, class Executor, class RatePolicy>
|
||||
template<class... Args>
|
||||
basic_stream<Protocol, Executor>::
|
||||
basic_stream<Protocol, Executor, RatePolicy>::
|
||||
impl_type::
|
||||
impl_type(Args&&... args)
|
||||
: socket(std::forward<Args>(args)...)
|
||||
, read(ex())
|
||||
, write(ex())
|
||||
, timer(ex())
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
template<class Protocol, class Executor>
|
||||
template<class Protocol, class Executor, class RatePolicy>
|
||||
template<class Executor2>
|
||||
void
|
||||
basic_stream<Protocol, Executor>::
|
||||
basic_stream<Protocol, Executor, RatePolicy>::
|
||||
impl_type::
|
||||
on_timer(Executor2 const& ex2)
|
||||
{
|
||||
BOOST_ASSERT(waiting > 0);
|
||||
|
||||
// the last waiter starts the new slice
|
||||
if(--waiting > 0)
|
||||
return;
|
||||
|
||||
// update the expiration time
|
||||
BOOST_VERIFY(timer.expires_after(
|
||||
std::chrono::seconds(1)) == 0);
|
||||
|
||||
rate_policy_access::on_timer(policy());
|
||||
|
||||
struct handler : boost::empty_value<Executor2>
|
||||
{
|
||||
boost::weak_ptr<impl_type> wp;
|
||||
|
||||
using executor_type = Executor2;
|
||||
|
||||
executor_type
|
||||
get_executor() const noexcept
|
||||
{
|
||||
return this->get();
|
||||
}
|
||||
|
||||
handler(
|
||||
Executor2 const& ex2,
|
||||
boost::shared_ptr<impl_type> const& sp)
|
||||
: boost::empty_value<Executor2>(
|
||||
boost::empty_init_t{}, ex2)
|
||||
, wp(sp)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
operator()(error_code ec)
|
||||
{
|
||||
auto sp = wp.lock();
|
||||
if(! sp)
|
||||
return;
|
||||
if(ec == net::error::operation_aborted)
|
||||
return;
|
||||
BOOST_ASSERT(! ec);
|
||||
if(ec)
|
||||
return;
|
||||
sp->on_timer(this->get());
|
||||
}
|
||||
};
|
||||
|
||||
// wait on the timer again
|
||||
++waiting;
|
||||
timer.async_wait(handler(ex2, this->shared_from_this()));
|
||||
}
|
||||
|
||||
template<class Protocol, class Executor, class RatePolicy>
|
||||
void
|
||||
basic_stream<Protocol, Executor, RatePolicy>::
|
||||
impl_type::
|
||||
reset()
|
||||
{
|
||||
@ -62,13 +124,14 @@ reset()
|
||||
write.timer.expires_at(never()) == 0);
|
||||
}
|
||||
|
||||
template<class Protocol, class Executor>
|
||||
template<class Protocol, class Executor, class RatePolicy>
|
||||
void
|
||||
basic_stream<Protocol, Executor>::
|
||||
basic_stream<Protocol, Executor, RatePolicy>::
|
||||
impl_type::
|
||||
close()
|
||||
{
|
||||
socket.close();
|
||||
timer.cancel();
|
||||
|
||||
// have to let the read/write ops cancel the timer,
|
||||
// otherwise we will get error::timeout on close when
|
||||
@ -80,9 +143,9 @@ close()
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<class Protocol, class Executor>
|
||||
struct basic_stream<
|
||||
Protocol, Executor>::timeout_handler
|
||||
template<class Protocol, class Executor, class RatePolicy>
|
||||
struct basic_stream<Protocol, Executor, RatePolicy>::
|
||||
timeout_handler
|
||||
{
|
||||
op_state& state;
|
||||
boost::weak_ptr<impl_type> wp;
|
||||
@ -124,9 +187,9 @@ struct basic_stream<
|
||||
also provides this.
|
||||
*/
|
||||
|
||||
template<class Protocol, class Executor>
|
||||
template<class Protocol, class Executor, class RatePolicy>
|
||||
template<bool isRead, class Buffers, class Handler>
|
||||
class basic_stream<Protocol, Executor>::async_op
|
||||
class basic_stream<Protocol, Executor, RatePolicy>::async_op
|
||||
: public async_op_base<Handler, Executor>
|
||||
, public boost::asio::coroutine
|
||||
{
|
||||
@ -134,6 +197,8 @@ class basic_stream<Protocol, Executor>::async_op
|
||||
pending_guard pg_;
|
||||
Buffers b_;
|
||||
|
||||
using is_read = std::integral_constant<bool, isRead>;
|
||||
|
||||
op_state&
|
||||
state(std::true_type)
|
||||
{
|
||||
@ -153,18 +218,62 @@ class basic_stream<Protocol, Executor>::async_op
|
||||
std::integral_constant<bool, isRead>{});
|
||||
}
|
||||
|
||||
void
|
||||
async_perform(std::true_type)
|
||||
std::size_t
|
||||
available_bytes(std::true_type)
|
||||
{
|
||||
impl_->socket.async_read_some(
|
||||
b_, std::move(*this));
|
||||
return rate_policy_access::
|
||||
available_read_bytes(impl_->policy());
|
||||
}
|
||||
|
||||
std::size_t
|
||||
available_bytes(std::false_type)
|
||||
{
|
||||
return rate_policy_access::
|
||||
available_write_bytes(impl_->policy());
|
||||
}
|
||||
|
||||
std::size_t
|
||||
available_bytes()
|
||||
{
|
||||
return available_bytes(is_read{});
|
||||
}
|
||||
|
||||
void
|
||||
async_perform(std::false_type)
|
||||
transfer_bytes(std::size_t n, std::true_type)
|
||||
{
|
||||
rate_policy_access::
|
||||
transfer_read_bytes(impl_->policy(), n);
|
||||
}
|
||||
|
||||
void
|
||||
transfer_bytes(std::size_t n, std::false_type)
|
||||
{
|
||||
rate_policy_access::
|
||||
transfer_write_bytes(impl_->policy(), n);
|
||||
}
|
||||
|
||||
void
|
||||
transfer_bytes(std::size_t n)
|
||||
{
|
||||
transfer_bytes(n, is_read{});
|
||||
}
|
||||
|
||||
void
|
||||
async_perform(
|
||||
std::size_t amount, std::true_type)
|
||||
{
|
||||
impl_->socket.async_read_some(
|
||||
beast::buffers_prefix(amount, b_),
|
||||
std::move(*this));
|
||||
}
|
||||
|
||||
void
|
||||
async_perform(
|
||||
std::size_t amount, std::false_type)
|
||||
{
|
||||
impl_->socket.async_write_some(
|
||||
b_, std::move(*this));
|
||||
beast::buffers_prefix(amount, b_),
|
||||
std::move(*this));
|
||||
}
|
||||
|
||||
public:
|
||||
@ -189,16 +298,23 @@ public:
|
||||
{
|
||||
BOOST_ASIO_CORO_REENTER(*this)
|
||||
{
|
||||
// handle empty buffers
|
||||
if(detail::buffers_empty(b_))
|
||||
{
|
||||
// make sure we perform the no-op
|
||||
BOOST_ASIO_CORO_YIELD
|
||||
async_perform(
|
||||
std::integral_constant<bool, isRead>{});
|
||||
async_perform(0, is_read{});
|
||||
// apply the timeout manually, otherwise
|
||||
// behavior varies across platforms.
|
||||
if(state().timer.expiry() <= clock_type::now())
|
||||
{
|
||||
impl_->close();
|
||||
ec = beast::error::timeout;
|
||||
}
|
||||
goto upcall;
|
||||
}
|
||||
|
||||
// if a timeout is active, wait on the timer
|
||||
if(state().timer.expiry() != never())
|
||||
state().timer.async_wait(
|
||||
net::bind_executor(
|
||||
@ -209,9 +325,38 @@ public:
|
||||
state().tick
|
||||
}));
|
||||
|
||||
// check rate limit, maybe wait
|
||||
std::size_t amount;
|
||||
amount = available_bytes();
|
||||
if(amount == 0)
|
||||
{
|
||||
++impl_->waiting;
|
||||
BOOST_ASIO_CORO_YIELD
|
||||
impl_->timer.async_wait(std::move(*this));
|
||||
if(ec)
|
||||
{
|
||||
// socket was closed, or a timeout
|
||||
BOOST_ASSERT(ec ==
|
||||
net::error::operation_aborted);
|
||||
// timeout handler invoked?
|
||||
if(state().timeout)
|
||||
{
|
||||
// yes, socket already closed
|
||||
ec = beast::error::timeout;
|
||||
state().timeout = false;
|
||||
}
|
||||
goto upcall;
|
||||
}
|
||||
impl_->on_timer(this->get_executor());
|
||||
|
||||
// Allow at least one byte, otherwise
|
||||
// bytes_transferred could be 0.
|
||||
amount = std::max<std::size_t>(
|
||||
available_bytes(), 1);
|
||||
}
|
||||
|
||||
BOOST_ASIO_CORO_YIELD
|
||||
async_perform(
|
||||
std::integral_constant<bool, isRead>{});
|
||||
async_perform(amount, is_read{});
|
||||
|
||||
if(state().timer.expiry() != never())
|
||||
{
|
||||
@ -239,6 +384,7 @@ public:
|
||||
|
||||
upcall:
|
||||
pg_.reset();
|
||||
transfer_bytes(bytes_transferred);
|
||||
this->invoke_now(ec, bytes_transferred);
|
||||
}
|
||||
}
|
||||
@ -249,12 +395,13 @@ public:
|
||||
namespace detail {
|
||||
|
||||
template<
|
||||
class Protocol, class Executor, class Handler>
|
||||
class Protocol, class Executor, class RatePolicy,
|
||||
class Handler>
|
||||
class basic_stream_connect_op
|
||||
: public async_op_base<Handler, Executor>
|
||||
{
|
||||
using stream_type =
|
||||
beast::basic_stream<Protocol, Executor>;
|
||||
using stream_type = beast::basic_stream<
|
||||
Protocol, Executor, RatePolicy>;
|
||||
|
||||
using timeout_handler =
|
||||
typename stream_type::timeout_handler;
|
||||
@ -390,8 +537,8 @@ public:
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<class Protocol, class Executor>
|
||||
basic_stream<Protocol, Executor>::
|
||||
template<class Protocol, class Executor, class RatePolicy>
|
||||
basic_stream<Protocol, Executor, RatePolicy>::
|
||||
~basic_stream()
|
||||
{
|
||||
// the shared object can outlive *this,
|
||||
@ -400,17 +547,17 @@ basic_stream<Protocol, Executor>::
|
||||
impl_->close();
|
||||
}
|
||||
|
||||
template<class Protocol, class Executor>
|
||||
template<class Protocol, class Executor, class RatePolicy>
|
||||
template<class... Args>
|
||||
basic_stream<Protocol, Executor>::
|
||||
basic_stream<Protocol, Executor, RatePolicy>::
|
||||
basic_stream(Args&&... args)
|
||||
: impl_(boost::make_shared<impl_type>(
|
||||
std::forward<Args>(args)...))
|
||||
{
|
||||
}
|
||||
|
||||
template<class Protocol, class Executor>
|
||||
basic_stream<Protocol, Executor>::
|
||||
template<class Protocol, class Executor, class RatePolicy>
|
||||
basic_stream<Protocol, Executor, RatePolicy>::
|
||||
basic_stream(basic_stream&& other)
|
||||
: impl_(boost::make_shared<impl_type>(
|
||||
std::move(*other.impl_)))
|
||||
@ -420,9 +567,9 @@ basic_stream(basic_stream&& other)
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<class Protocol, class Executor>
|
||||
template<class Protocol, class Executor, class RatePolicy>
|
||||
auto
|
||||
basic_stream<Protocol, Executor>::
|
||||
basic_stream<Protocol, Executor, RatePolicy>::
|
||||
release_socket() ->
|
||||
socket_type
|
||||
{
|
||||
@ -430,9 +577,9 @@ release_socket() ->
|
||||
return std::move(impl_->socket);
|
||||
}
|
||||
|
||||
template<class Protocol, class Executor>
|
||||
template<class Protocol, class Executor, class RatePolicy>
|
||||
void
|
||||
basic_stream<Protocol, Executor>::
|
||||
basic_stream<Protocol, Executor, RatePolicy>::
|
||||
expires_after(std::chrono::nanoseconds expiry_time)
|
||||
{
|
||||
// If assert goes off, it means that there are
|
||||
@ -455,9 +602,9 @@ expires_after(std::chrono::nanoseconds expiry_time)
|
||||
expiry_time) == 0);
|
||||
}
|
||||
|
||||
template<class Protocol, class Executor>
|
||||
template<class Protocol, class Executor, class RatePolicy>
|
||||
void
|
||||
basic_stream<Protocol, Executor>::
|
||||
basic_stream<Protocol, Executor, RatePolicy>::
|
||||
expires_at(
|
||||
net::steady_timer::time_point expiry_time)
|
||||
{
|
||||
@ -481,36 +628,37 @@ expires_at(
|
||||
expiry_time) == 0);
|
||||
}
|
||||
|
||||
template<class Protocol, class Executor>
|
||||
template<class Protocol, class Executor, class RatePolicy>
|
||||
void
|
||||
basic_stream<Protocol, Executor>::
|
||||
basic_stream<Protocol, Executor, RatePolicy>::
|
||||
expires_never()
|
||||
{
|
||||
impl_->reset();
|
||||
}
|
||||
|
||||
template<class Protocol, class Executor>
|
||||
template<class Protocol, class Executor, class RatePolicy>
|
||||
void
|
||||
basic_stream<Protocol, Executor>::
|
||||
basic_stream<Protocol, Executor, RatePolicy>::
|
||||
cancel()
|
||||
{
|
||||
error_code ec;
|
||||
impl_->socket.cancel(ec);
|
||||
impl_->timer.cancel();
|
||||
}
|
||||
|
||||
template<class Protocol, class Executor>
|
||||
template<class Protocol, class Executor, class RatePolicy>
|
||||
void
|
||||
basic_stream<Protocol, Executor>::
|
||||
basic_stream<Protocol, Executor, RatePolicy>::
|
||||
close()
|
||||
{
|
||||
impl_->close();
|
||||
}
|
||||
|
||||
template<class Protocol, class Executor>
|
||||
template<class Protocol, class Executor, class RatePolicy>
|
||||
template<class ConnectHandler>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(ConnectHandler,
|
||||
void(error_code))
|
||||
basic_stream<Protocol, Executor>::
|
||||
basic_stream<Protocol, Executor, RatePolicy>::
|
||||
async_connect(
|
||||
endpoint_type const& ep,
|
||||
ConnectHandler&& handler)
|
||||
@ -518,17 +666,18 @@ async_connect(
|
||||
BOOST_BEAST_HANDLER_INIT(
|
||||
ConnectHandler, void(error_code));
|
||||
detail::basic_stream_connect_op<
|
||||
Protocol, Executor, BOOST_ASIO_HANDLER_TYPE(
|
||||
Protocol, Executor, RatePolicy,
|
||||
BOOST_ASIO_HANDLER_TYPE(
|
||||
ConnectHandler, void(error_code))>(*this,
|
||||
ep, std::forward<ConnectHandler>(handler));
|
||||
return init.result.get();
|
||||
}
|
||||
|
||||
template<class Protocol, class Executor>
|
||||
template<class Protocol, class Executor, class RatePolicy>
|
||||
template<class MutableBufferSequence, class ReadHandler>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
|
||||
void(error_code, std::size_t))
|
||||
basic_stream<Protocol, Executor>::
|
||||
basic_stream<Protocol, Executor, RatePolicy>::
|
||||
async_read_some(
|
||||
MutableBufferSequence const& buffers,
|
||||
ReadHandler&& handler)
|
||||
@ -544,11 +693,11 @@ async_read_some(
|
||||
return init.result.get();
|
||||
}
|
||||
|
||||
template<class Protocol, class Executor>
|
||||
template<class Protocol, class Executor, class RatePolicy>
|
||||
template<class ConstBufferSequence, class WriteHandler>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler,
|
||||
void(error_code, std::size_t))
|
||||
basic_stream<Protocol, Executor>::
|
||||
basic_stream<Protocol, Executor, RatePolicy>::
|
||||
async_write_some(
|
||||
ConstBufferSequence const& buffers,
|
||||
WriteHandler&& handler)
|
||||
@ -567,20 +716,21 @@ async_write_some(
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<
|
||||
class Protocol, class Executor,
|
||||
class Protocol, class Executor, class RatePolicy,
|
||||
class EndpointSequence,
|
||||
class RangeConnectHandler,
|
||||
class>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(RangeConnectHandler,
|
||||
void(error_code, typename Protocol::endpoint))
|
||||
async_connect(
|
||||
basic_stream<Protocol, Executor>& stream,
|
||||
basic_stream<Protocol, Executor, RatePolicy>& stream,
|
||||
EndpointSequence const& endpoints,
|
||||
RangeConnectHandler&& handler)
|
||||
{
|
||||
BOOST_BEAST_HANDLER_INIT(RangeConnectHandler,
|
||||
void(error_code, typename Protocol::endpoint));
|
||||
detail::basic_stream_connect_op<Protocol, Executor,
|
||||
detail::basic_stream_connect_op<
|
||||
Protocol, Executor, RatePolicy,
|
||||
BOOST_ASIO_HANDLER_TYPE(RangeConnectHandler,
|
||||
void(error_code, typename Protocol::endpoint))>(
|
||||
stream, endpoints, detail::any_endpoint{},
|
||||
@ -589,7 +739,7 @@ async_connect(
|
||||
}
|
||||
|
||||
template<
|
||||
class Protocol, class Executor,
|
||||
class Protocol, class Executor, class RatePolicy,
|
||||
class EndpointSequence,
|
||||
class ConnectCondition,
|
||||
class RangeConnectHandler,
|
||||
@ -597,14 +747,15 @@ template<
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(RangeConnectHandler,
|
||||
void (error_code, typename Protocol::endpoint))
|
||||
async_connect(
|
||||
basic_stream<Protocol, Executor>& stream,
|
||||
basic_stream<Protocol, Executor, RatePolicy>& stream,
|
||||
EndpointSequence const& endpoints,
|
||||
ConnectCondition connect_condition,
|
||||
RangeConnectHandler&& handler)
|
||||
{
|
||||
BOOST_BEAST_HANDLER_INIT(RangeConnectHandler,
|
||||
void(error_code, typename Protocol::endpoint));
|
||||
detail::basic_stream_connect_op<Protocol, Executor,
|
||||
detail::basic_stream_connect_op<
|
||||
Protocol, Executor, RatePolicy,
|
||||
BOOST_ASIO_HANDLER_TYPE(RangeConnectHandler,
|
||||
void(error_code, typename Protocol::endpoint))>(
|
||||
stream, endpoints, connect_condition,
|
||||
@ -613,19 +764,20 @@ async_connect(
|
||||
}
|
||||
|
||||
template<
|
||||
class Protocol, class Executor,
|
||||
class Protocol, class Executor, class RatePolicy,
|
||||
class Iterator,
|
||||
class IteratorConnectHandler>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler,
|
||||
void (error_code, Iterator))
|
||||
async_connect(
|
||||
basic_stream<Protocol, Executor>& stream,
|
||||
basic_stream<Protocol, Executor, RatePolicy>& stream,
|
||||
Iterator begin, Iterator end,
|
||||
IteratorConnectHandler&& handler)
|
||||
{
|
||||
BOOST_BEAST_HANDLER_INIT(IteratorConnectHandler,
|
||||
void(error_code, Iterator));
|
||||
detail::basic_stream_connect_op<Protocol, Executor,
|
||||
detail::basic_stream_connect_op<
|
||||
Protocol, Executor, RatePolicy,
|
||||
BOOST_ASIO_HANDLER_TYPE(IteratorConnectHandler,
|
||||
void(error_code, Iterator))>(
|
||||
stream, begin, end, detail::any_endpoint{},
|
||||
@ -634,21 +786,22 @@ async_connect(
|
||||
}
|
||||
|
||||
template<
|
||||
class Protocol, class Executor,
|
||||
class Protocol, class Executor, class RatePolicy,
|
||||
class Iterator,
|
||||
class ConnectCondition,
|
||||
class IteratorConnectHandler>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler,
|
||||
void (error_code, Iterator))
|
||||
async_connect(
|
||||
basic_stream<Protocol, Executor>& stream,
|
||||
basic_stream<Protocol, Executor, RatePolicy>& stream,
|
||||
Iterator begin, Iterator end,
|
||||
ConnectCondition connect_condition,
|
||||
IteratorConnectHandler&& handler)
|
||||
{
|
||||
BOOST_BEAST_HANDLER_INIT(IteratorConnectHandler,
|
||||
void(error_code, Iterator));
|
||||
detail::basic_stream_connect_op<Protocol, Executor,
|
||||
detail::basic_stream_connect_op<
|
||||
Protocol, Executor, RatePolicy,
|
||||
BOOST_ASIO_HANDLER_TYPE(IteratorConnectHandler,
|
||||
void(error_code, Iterator))>(
|
||||
stream, begin, end, connect_condition,
|
||||
@ -663,20 +816,22 @@ async_connect(
|
||||
|
||||
#if ! BOOST_BEAST_DOXYGEN
|
||||
|
||||
template<class Protocol, class Executor>
|
||||
template<
|
||||
class Protocol, class Executor, class RatePolicy>
|
||||
void
|
||||
beast_close_socket(
|
||||
basic_stream<Protocol, Executor>& stream)
|
||||
basic_stream<Protocol, Executor, RatePolicy>& stream)
|
||||
{
|
||||
error_code ec;
|
||||
stream.socket().close(ec);
|
||||
}
|
||||
|
||||
template<class Protocol, class Executor>
|
||||
template<
|
||||
class Protocol, class Executor, class RatePolicy>
|
||||
void
|
||||
teardown(
|
||||
websocket::role_type role,
|
||||
basic_stream<Protocol, Executor>& stream,
|
||||
basic_stream<Protocol, Executor, RatePolicy>& stream,
|
||||
error_code& ec)
|
||||
{
|
||||
using beast::websocket::teardown;
|
||||
@ -684,12 +839,12 @@ teardown(
|
||||
}
|
||||
|
||||
template<
|
||||
class Protocol, class Executor,
|
||||
class Protocol, class Executor, class RatePolicy,
|
||||
class TeardownHandler>
|
||||
void
|
||||
async_teardown(
|
||||
websocket::role_type role,
|
||||
basic_stream<Protocol, Executor>& stream,
|
||||
basic_stream<Protocol, Executor, RatePolicy>& stream,
|
||||
TeardownHandler&& handler)
|
||||
{
|
||||
using beast::websocket::async_teardown;
|
||||
|
222
include/boost/beast/core/rate_policy.hpp
Normal file
222
include/boost/beast/core/rate_policy.hpp
Normal file
@ -0,0 +1,222 @@
|
||||
//
|
||||
// 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_RATE_POLICY_HPP
|
||||
#define BOOST_BEAST_CORE_RATE_POLICY_HPP
|
||||
|
||||
#include <boost/beast/core/detail/config.hpp>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
|
||||
namespace boost {
|
||||
namespace beast {
|
||||
|
||||
/** Helper class to assist implementing a RatePolicy.
|
||||
|
||||
This class is used by the implementation to gain access to the
|
||||
private members of a user-defined object meeting the requirements
|
||||
of <em>RatePolicy</em>. To use it, simply declare it as a friend
|
||||
in your class:
|
||||
|
||||
@par Example
|
||||
@code
|
||||
class custom_rate_policy
|
||||
{
|
||||
friend class beast::rate_policy_access;
|
||||
...
|
||||
@endcode
|
||||
|
||||
@par Concepts
|
||||
|
||||
@li <em>RatePolicy</em>
|
||||
|
||||
@see @ref beast::basic_stream
|
||||
*/
|
||||
class rate_policy_access
|
||||
{
|
||||
private:
|
||||
template<class, class, class>
|
||||
friend class basic_stream;
|
||||
|
||||
template<class Policy>
|
||||
static
|
||||
std::size_t
|
||||
available_read_bytes(Policy& policy)
|
||||
{
|
||||
return policy.available_read_bytes();
|
||||
}
|
||||
|
||||
template<class Policy>
|
||||
static
|
||||
std::size_t
|
||||
available_write_bytes(Policy& policy)
|
||||
{
|
||||
return policy.available_write_bytes();
|
||||
}
|
||||
|
||||
template<class Policy>
|
||||
static
|
||||
void
|
||||
transfer_read_bytes(
|
||||
Policy& policy, std::size_t n)
|
||||
{
|
||||
return policy.transfer_read_bytes(n);
|
||||
}
|
||||
|
||||
template<class Policy>
|
||||
static
|
||||
void
|
||||
transfer_write_bytes(
|
||||
Policy& policy, std::size_t n)
|
||||
{
|
||||
return policy.transfer_write_bytes(n);
|
||||
}
|
||||
|
||||
template<class Policy>
|
||||
static
|
||||
void
|
||||
on_timer(Policy& policy)
|
||||
{
|
||||
return policy.on_timer();
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** A rate policy with unlimited throughput.
|
||||
|
||||
This rate policy places no restrictions on read and write
|
||||
bandwidth utilization.
|
||||
|
||||
@par Concepts
|
||||
|
||||
@li <em>RatePolicy</em>
|
||||
|
||||
@see @ref beast::basic_stream
|
||||
*/
|
||||
class unlimited_rate_policy
|
||||
{
|
||||
static std::size_t constexpr all =
|
||||
(std::numeric_limits<std::size_t>::max)();
|
||||
|
||||
private:
|
||||
friend class rate_policy_access;
|
||||
|
||||
std::size_t
|
||||
available_read_bytes()
|
||||
{
|
||||
return all;
|
||||
}
|
||||
|
||||
std::size_t
|
||||
available_write_bytes()
|
||||
{
|
||||
return all;
|
||||
}
|
||||
|
||||
void
|
||||
transfer_read_bytes(std::size_t)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
transfer_write_bytes(std::size_t)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
on_timer()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** A rate policy with simple, configurable limits on read and write throughput.
|
||||
|
||||
This rate policy allows for simple individual limits on the amount
|
||||
of bytes per second allowed for reads and writes.
|
||||
|
||||
@par Concepts
|
||||
|
||||
@li <em>RatePolicy</em>
|
||||
|
||||
@see @ref beast::basic_stream
|
||||
*/
|
||||
class simple_rate_policy
|
||||
{
|
||||
friend class rate_policy_access;
|
||||
|
||||
static std::size_t constexpr all =
|
||||
std::numeric_limits<std::size_t>::max();
|
||||
|
||||
std::size_t rd_remain_ = all;
|
||||
std::size_t wr_remain_ = all;
|
||||
std::size_t rd_limit_ = all;
|
||||
std::size_t wr_limit_ = all;
|
||||
|
||||
std::size_t
|
||||
available_read_bytes()
|
||||
{
|
||||
return rd_remain_;
|
||||
}
|
||||
|
||||
std::size_t
|
||||
available_write_bytes()
|
||||
{
|
||||
return wr_remain_;
|
||||
}
|
||||
|
||||
void
|
||||
transfer_read_bytes(std::size_t n)
|
||||
{
|
||||
if( rd_remain_ != all)
|
||||
rd_remain_ =
|
||||
(n < rd_remain_) ? rd_remain_ - n : 0;
|
||||
}
|
||||
|
||||
void
|
||||
transfer_write_bytes(std::size_t n)
|
||||
{
|
||||
if( wr_remain_ != all)
|
||||
wr_remain_ =
|
||||
(n < wr_remain_) ? wr_remain_ - n : 0;
|
||||
}
|
||||
|
||||
void
|
||||
on_timer()
|
||||
{
|
||||
rd_remain_ = rd_limit_;
|
||||
wr_remain_ = wr_limit_;
|
||||
}
|
||||
|
||||
public:
|
||||
/// Set the limit of bytes per second to read
|
||||
void
|
||||
read_limit(std::size_t bytes_per_second)
|
||||
{
|
||||
rd_limit_ = bytes_per_second;
|
||||
if( rd_remain_ > bytes_per_second)
|
||||
rd_remain_ = bytes_per_second;
|
||||
}
|
||||
|
||||
/// Set the limit of bytes per second to write
|
||||
void
|
||||
write_limit(std::size_t bytes_per_second)
|
||||
{
|
||||
wr_limit_ = bytes_per_second;
|
||||
if( wr_remain_ > bytes_per_second)
|
||||
wr_remain_ = bytes_per_second;
|
||||
}
|
||||
};
|
||||
|
||||
} // beast
|
||||
} // boost
|
||||
|
||||
#endif
|
@ -59,6 +59,7 @@ add_executable (tests-beast-core
|
||||
make_strand.cpp
|
||||
multi_buffer.cpp
|
||||
ostream.cpp
|
||||
rate_policy.cpp
|
||||
read_size.cpp
|
||||
saved_handler.cpp
|
||||
span.cpp
|
||||
|
@ -47,6 +47,7 @@ local SOURCES =
|
||||
make_strand.cpp
|
||||
multi_buffer.cpp
|
||||
ostream.cpp
|
||||
rate_policy.cpp
|
||||
read_size.cpp
|
||||
saved_handler.cpp
|
||||
span.cpp
|
||||
|
@ -31,6 +31,18 @@
|
||||
namespace boost {
|
||||
namespace beast {
|
||||
|
||||
#if 0
|
||||
template class basic_stream<
|
||||
net::ip::tcp,
|
||||
net::executor,
|
||||
unlimited_rate_policy>;
|
||||
|
||||
template class basic_stream<
|
||||
net::ip::tcp,
|
||||
net::executor,
|
||||
simple_rate_policy>;
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
|
||||
template<class Executor = net::io_context::executor_type>
|
||||
|
34
test/beast/core/rate_policy.cpp
Normal file
34
test/beast/core/rate_policy.cpp
Normal file
@ -0,0 +1,34 @@
|
||||
//
|
||||
// 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/rate_policy.hpp>
|
||||
|
||||
#include <boost/beast/_experimental/unit_test/suite.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace beast {
|
||||
|
||||
class rate_policy_test : public unit_test::suite
|
||||
{
|
||||
public:
|
||||
void
|
||||
run() override
|
||||
{
|
||||
unlimited_rate_policy{};
|
||||
simple_rate_policy{};
|
||||
|
||||
pass();
|
||||
}
|
||||
};
|
||||
|
||||
BEAST_DEFINE_TESTSUITE(beast,core,rate_policy);
|
||||
|
||||
} // beast
|
||||
} // boost
|
Reference in New Issue
Block a user