Add RatePolicy to basic_stream

This commit is contained in:
Vinnie Falco
2019-02-10 12:27:28 -08:00
parent 6baa607295
commit 23a7bcc67e
10 changed files with 546 additions and 82 deletions

View File

@ -4,6 +4,7 @@ Version 216:
* Add websocket::stream timeouts
* Use suggested timeouts in Websocket examples
* Add make_strand
* Add RatePolicy to basic_stream
--------------------------------------------------------------------------------

View File

@ -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>&nbsp;<emphasis role="green">&#128946;</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>&nbsp;<emphasis role="green">&#128946;</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>&nbsp;<emphasis role="green">&#128946;</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>&nbsp;<emphasis role="green">&#128946;</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>&nbsp;<emphasis role="green">&#128946;</emphasis></member>
<member><link linkend="beast.ref.boost__beast__unlimited_rate_policy">unlimited_rate_policy</link>&nbsp;<emphasis role="green">&#128946;</emphasis></member>
</simplelist>
<bridgehead renderas="sect3">Constants</bridgehead>
<simplelist type="vert" columns="1">

View File

@ -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);

View File

@ -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

View File

@ -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;

View 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

View File

@ -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

View File

@ -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

View File

@ -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>

View 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