forked from boostorg/beast
beast support per-op cancellation
- websocket supports cancellation. - Iterating test for ws cancellation. - Only terminal cancellation is forwarded by default. - basic_stream supports cancellation. - supported cancellation is documented. - http cancellation additions. - Added cancellation_slot tests to http, utils and saved_handler. - Added post to write.cpp, to avoid SIGSEV in test. - Refresher describes cancellation in more detail.
This commit is contained in:
committed by
Klemens Morgenstern
parent
0bf3d971a0
commit
3ebff60b1a
@@ -77,6 +77,16 @@ class basic_stream<Executor>::read_op : public detail::stream_read_op_base
|
||||
return net::get_associated_allocator(h_);
|
||||
}
|
||||
|
||||
using cancellation_slot_type =
|
||||
net::associated_cancellation_slot_t<Handler>;
|
||||
|
||||
cancellation_slot_type
|
||||
get_cancellation_slot() const noexcept
|
||||
{
|
||||
return net::get_associated_cancellation_slot(h_,
|
||||
net::cancellation_slot());
|
||||
}
|
||||
|
||||
void
|
||||
operator()(error_code ec)
|
||||
{
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <boost/beast/core/bind_handler.hpp>
|
||||
#include <boost/beast/core/detail/allocator.hpp>
|
||||
#include <boost/beast/core/detail/async_base.hpp>
|
||||
#include <boost/beast/core/detail/filtering_cancellation_slot.hpp>
|
||||
#include <boost/beast/core/detail/work_guard.hpp>
|
||||
#include <boost/asio/associated_allocator.hpp>
|
||||
#include <boost/asio/associated_executor.hpp>
|
||||
@@ -187,7 +188,7 @@ class async_base
|
||||
|
||||
Handler h_;
|
||||
detail::select_work_guard_t<Executor1> wg1_;
|
||||
|
||||
net::cancellation_type act_{net::cancellation_type::terminal};
|
||||
public:
|
||||
/** The type of executor associated with this object.
|
||||
|
||||
@@ -308,6 +309,38 @@ public:
|
||||
h_, wg1_.get_executor());
|
||||
}
|
||||
|
||||
/** The type of cancellation_slot associated with this object.
|
||||
|
||||
If a class derived from @ref async_base is a completion
|
||||
handler, then the associated cancellation_slot of the
|
||||
derived class will be this type.
|
||||
|
||||
The default type is a filtering cancellation slot,
|
||||
that only allows terminal cancellation.
|
||||
*/
|
||||
using cancellation_slot_type =
|
||||
beast::detail::filtering_cancellation_slot<net::associated_cancellation_slot_t<Handler>>;
|
||||
|
||||
/** Returns the cancellation_slot associated with this object.
|
||||
|
||||
If a class derived from @ref async_base is a completion
|
||||
handler, then the object returned from this function will be used
|
||||
as the associated cancellation_slot of the derived class.
|
||||
*/
|
||||
cancellation_slot_type
|
||||
get_cancellation_slot() const noexcept
|
||||
{
|
||||
return cancellation_slot_type(act_, net::get_associated_cancellation_slot(h_,
|
||||
net::cancellation_slot()));
|
||||
}
|
||||
|
||||
/// Set the allowed cancellation types, default is `terminal`.
|
||||
void set_allowed_cancellation(
|
||||
net::cancellation_type allowed_cancellation_types = net::cancellation_type::terminal)
|
||||
{
|
||||
act_ = allowed_cancellation_types;
|
||||
}
|
||||
|
||||
/// Returns the handler associated with this object
|
||||
Handler const&
|
||||
handler() const noexcept
|
||||
|
||||
@@ -919,6 +919,17 @@ public:
|
||||
this function. Invocation of the handler will be performed in a
|
||||
manner equivalent to using `net::post`.
|
||||
|
||||
@par Per-Operation Cancellation
|
||||
|
||||
This asynchronous operation supports cancellation for the following
|
||||
net::cancellation_type values:
|
||||
|
||||
@li @c net::cancellation_type::terminal
|
||||
@li @c net::cancellation_type::partial
|
||||
@li @c net::cancellation_type::total
|
||||
|
||||
if they are also supported by the socket's @c async_connect operation.
|
||||
|
||||
@see async_connect
|
||||
*/
|
||||
template<
|
||||
@@ -972,6 +983,18 @@ public:
|
||||
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::post`.
|
||||
|
||||
@par Per-Operation Cancellation
|
||||
|
||||
This asynchronous operation supports cancellation for the following
|
||||
net::cancellation_type values:
|
||||
|
||||
@li @c net::cancellation_type::terminal
|
||||
@li @c net::cancellation_type::partial
|
||||
@li @c net::cancellation_type::total
|
||||
|
||||
if they are also supported by the socket's @c async_connect operation.
|
||||
|
||||
*/
|
||||
template<
|
||||
class EndpointSequence,
|
||||
@@ -1064,6 +1087,17 @@ public:
|
||||
}
|
||||
};
|
||||
@endcode
|
||||
|
||||
@par Per-Operation Cancellation
|
||||
|
||||
This asynchronous operation supports cancellation for the following
|
||||
net::cancellation_type values:
|
||||
|
||||
@li @c net::cancellation_type::terminal
|
||||
@li @c net::cancellation_type::partial
|
||||
@li @c net::cancellation_type::total
|
||||
|
||||
if they are also supported by the socket's @c async_connect operation.
|
||||
*/
|
||||
template<
|
||||
class EndpointSequence,
|
||||
@@ -1129,6 +1163,17 @@ public:
|
||||
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::post`.
|
||||
|
||||
@par Per-Operation Cancellation
|
||||
|
||||
This asynchronous operation supports cancellation for the following
|
||||
net::cancellation_type values:
|
||||
|
||||
@li @c net::cancellation_type::terminal
|
||||
@li @c net::cancellation_type::partial
|
||||
@li @c net::cancellation_type::total
|
||||
|
||||
if they are also supported by the socket's @c async_connect operation.
|
||||
*/
|
||||
template<
|
||||
class Iterator,
|
||||
@@ -1189,6 +1234,17 @@ public:
|
||||
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::post`.
|
||||
|
||||
@par Per-Operation Cancellation
|
||||
|
||||
This asynchronous operation supports cancellation for the following
|
||||
net::cancellation_type values:
|
||||
|
||||
@li @c net::cancellation_type::terminal
|
||||
@li @c net::cancellation_type::partial
|
||||
@li @c net::cancellation_type::total
|
||||
|
||||
if they are also supported by the socket's @c async_connect operation.
|
||||
*/
|
||||
template<
|
||||
class Iterator,
|
||||
@@ -1316,6 +1372,17 @@ public:
|
||||
number of bytes. Consider using the function `net::async_read` if you need
|
||||
to ensure that the requested amount of data is read before the asynchronous
|
||||
operation completes.
|
||||
|
||||
@par Per-Operation Cancellation
|
||||
|
||||
This asynchronous operation supports cancellation for the following
|
||||
net::cancellation_type values:
|
||||
|
||||
@li @c net::cancellation_type::terminal
|
||||
@li @c net::cancellation_type::partial
|
||||
@li @c net::cancellation_type::total
|
||||
|
||||
if they are also supported by the socket's @c async_read_some operation.
|
||||
*/
|
||||
template<
|
||||
class MutableBufferSequence,
|
||||
@@ -1439,6 +1506,17 @@ public:
|
||||
number of bytes. Consider using the function `net::async_write` if you need
|
||||
to ensure that the requested amount of data is sent before the asynchronous
|
||||
operation completes.
|
||||
|
||||
@par Per-Operation Cancellation
|
||||
|
||||
This asynchronous operation supports cancellation for the following
|
||||
net::cancellation_type values:
|
||||
|
||||
@li @c net::cancellation_type::terminal
|
||||
@li @c net::cancellation_type::partial
|
||||
@li @c net::cancellation_type::total
|
||||
|
||||
if they are also supported by the socket's @c async_write_some operation.
|
||||
*/
|
||||
template<
|
||||
class ConstBufferSequence,
|
||||
|
||||
@@ -67,6 +67,16 @@ public:
|
||||
h_, this->get());
|
||||
}
|
||||
|
||||
using cancellation_slot_type =
|
||||
net::associated_cancellation_slot_t<Handler>;
|
||||
|
||||
cancellation_slot_type
|
||||
get_cancellation_slot() const noexcept
|
||||
{
|
||||
return net::get_associated_cancellation_slot(h_,
|
||||
net::cancellation_slot());
|
||||
}
|
||||
|
||||
// The allocation hooks are still defined because they trivially forward to
|
||||
// user hooks. Forward here ensures that the user will get a compile error
|
||||
// if they build their code with BOOST_ASIO_NO_DEPRECATED.
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <boost/beast/core/error.hpp>
|
||||
#include <boost/beast/core/detail/tuple.hpp>
|
||||
#include <boost/asio/associated_allocator.hpp>
|
||||
#include <boost/asio/associated_cancellation_slot.hpp>
|
||||
#include <boost/asio/associated_executor.hpp>
|
||||
#include <boost/asio/handler_alloc_hook.hpp>
|
||||
#include <boost/asio/handler_continuation_hook.hpp>
|
||||
@@ -48,6 +49,9 @@ class bind_wrapper
|
||||
template<class T, class Allocator>
|
||||
friend struct net::associated_allocator;
|
||||
|
||||
template<class T, class CancellationSlot>
|
||||
friend struct net::associated_cancellation_slot;
|
||||
|
||||
template<class Arg, class Vals>
|
||||
static
|
||||
typename std::enable_if<
|
||||
@@ -217,6 +221,10 @@ class bind_front_wrapper
|
||||
template<class T, class Allocator>
|
||||
friend struct net::associated_allocator;
|
||||
|
||||
template<class T, class CancellationSlot>
|
||||
friend struct net::associated_cancellation_slot;
|
||||
|
||||
|
||||
template<std::size_t... I, class... Ts>
|
||||
void
|
||||
invoke(
|
||||
@@ -385,6 +393,42 @@ struct associated_allocator<
|
||||
}
|
||||
};
|
||||
|
||||
template<class Handler, class... Args, class CancellationSlot>
|
||||
struct associated_cancellation_slot<
|
||||
beast::detail::bind_wrapper<Handler, Args...>, CancellationSlot>
|
||||
{
|
||||
using type = typename
|
||||
associated_cancellation_slot<Handler>::type;
|
||||
|
||||
static
|
||||
type
|
||||
get(beast::detail::bind_wrapper<Handler, Args...> const& op,
|
||||
CancellationSlot const& slot = CancellationSlot{}) noexcept
|
||||
{
|
||||
return associated_cancellation_slot<
|
||||
Handler, CancellationSlot>::get(op.h_, slot);
|
||||
}
|
||||
};
|
||||
|
||||
template<class Handler, class... Args, class CancellationSlot>
|
||||
struct associated_cancellation_slot<
|
||||
beast::detail::bind_front_wrapper<Handler, Args...>, CancellationSlot>
|
||||
{
|
||||
using type = typename
|
||||
associated_cancellation_slot<Handler>::type;
|
||||
|
||||
static
|
||||
type
|
||||
get(beast::detail::bind_front_wrapper<Handler, Args...> const& op,
|
||||
CancellationSlot const& slot = CancellationSlot{}) noexcept
|
||||
{
|
||||
return associated_cancellation_slot<
|
||||
Handler, CancellationSlot>::get(op.h_, slot);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // asio
|
||||
} // boost
|
||||
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
//
|
||||
// Copyright (c) 2022 Klemens Morgenstern (klemens.morgenstern@gmx.net)
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
|
||||
#ifndef BOOST_BEAST_CORE_DETAIL_FILTERING_CANCELLATION_SLOT_HPP
|
||||
#define BOOST_BEAST_CORE_DETAIL_FILTERING_CANCELLATION_SLOT_HPP
|
||||
|
||||
#include <boost/beast/core/detail/config.hpp>
|
||||
#include <boost/asio/cancellation_signal.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace beast {
|
||||
namespace detail {
|
||||
|
||||
template<typename CancellationSlot = net::cancellation_slot>
|
||||
struct filtering_cancellation_slot : CancellationSlot
|
||||
{
|
||||
template<typename ... Args>
|
||||
filtering_cancellation_slot(net::cancellation_type type, Args && ... args)
|
||||
: CancellationSlot(std::forward<Args>(args)...), type(type) {}
|
||||
|
||||
net::cancellation_type type = net::cancellation_type::terminal;
|
||||
|
||||
using CancellationSlot::operator=;
|
||||
|
||||
template<typename Handler>
|
||||
struct handler_wrapper
|
||||
{
|
||||
Handler handler;
|
||||
const net::cancellation_type type;
|
||||
|
||||
template<typename ... Args>
|
||||
handler_wrapper(net::cancellation_type type, Args && ... args)
|
||||
: handler(std::forward<Args>(args)...),
|
||||
type(type) {}
|
||||
|
||||
void operator()(net::cancellation_type tp)
|
||||
{
|
||||
if ((tp & type) != net::cancellation_type::none)
|
||||
handler(tp);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename CancellationHandler, typename ... Args>
|
||||
CancellationHandler& emplace(Args && ... args)
|
||||
{
|
||||
return CancellationSlot::template emplace<handler_wrapper<CancellationHandler>>(
|
||||
type, std::forward<Args>(args)...).handler;
|
||||
}
|
||||
|
||||
template <typename CancellationHandler>
|
||||
CancellationHandler& assign(CancellationHandler && ch)
|
||||
{
|
||||
return CancellationSlot::template emplace<handler_wrapper<CancellationHandler>>(
|
||||
type, std::forward<CancellationHandler>(ch)).handler;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif //BOOST_BEAST_CORE_DETAIL_FILTERING_CANCELLATION_SLOT_HPP
|
||||
@@ -283,6 +283,7 @@ public:
|
||||
, pg_()
|
||||
, b_(b)
|
||||
{
|
||||
this->set_allowed_cancellation(net::cancellation_type::all);
|
||||
if (buffer_bytes(b_) == 0 && state().pending)
|
||||
{
|
||||
// Workaround:
|
||||
@@ -452,6 +453,7 @@ public:
|
||||
, pg0_(impl_->read.pending)
|
||||
, pg1_(impl_->write.pending)
|
||||
{
|
||||
this->set_allowed_cancellation(net::cancellation_type::all);
|
||||
if(state().timer.expiry() != stream_base::never())
|
||||
{
|
||||
BOOST_ASIO_HANDLER_LOCATION((
|
||||
@@ -489,6 +491,7 @@ public:
|
||||
, pg0_(impl_->read.pending)
|
||||
, pg1_(impl_->write.pending)
|
||||
{
|
||||
this->set_allowed_cancellation(net::cancellation_type::all);
|
||||
if(state().timer.expiry() != stream_base::never())
|
||||
{
|
||||
BOOST_ASIO_HANDLER_LOCATION((
|
||||
@@ -526,6 +529,7 @@ public:
|
||||
, pg0_(impl_->read.pending)
|
||||
, pg1_(impl_->write.pending)
|
||||
{
|
||||
this->set_allowed_cancellation(net::cancellation_type::all);
|
||||
if(state().timer.expiry() != stream_base::never())
|
||||
{
|
||||
BOOST_ASIO_HANDLER_LOCATION((
|
||||
|
||||
@@ -12,7 +12,9 @@
|
||||
|
||||
#include <boost/beast/core/detail/allocator.hpp>
|
||||
#include <boost/asio/associated_allocator.hpp>
|
||||
#include <boost/asio/associated_cancellation_slot.hpp>
|
||||
#include <boost/asio/associated_executor.hpp>
|
||||
#include <boost/asio/error.hpp>
|
||||
#include <boost/asio/executor_work_guard.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/core/empty_value.hpp>
|
||||
@@ -28,9 +30,10 @@ class saved_handler::base
|
||||
{
|
||||
protected:
|
||||
~base() = default;
|
||||
|
||||
saved_handler * owner_;
|
||||
public:
|
||||
base() = default;
|
||||
base(saved_handler * owner) : owner_(owner){}
|
||||
void set_owner(saved_handler * new_owner) { owner_ = new_owner;}
|
||||
virtual void destroy() = 0;
|
||||
virtual void invoke() = 0;
|
||||
};
|
||||
@@ -72,11 +75,12 @@ class saved_handler::impl final : public base
|
||||
net::executor_work_guard<
|
||||
net::associated_executor_t<Handler>> wg2_;
|
||||
#endif // defined(BOOST_ASIO_NO_TS_EXECUTORS)
|
||||
|
||||
net::cancellation_slot slot_{net::get_associated_cancellation_slot(v_.h)};
|
||||
public:
|
||||
template<class Handler_>
|
||||
impl(alloc_type const& a, Handler_&& h)
|
||||
: v_(a, std::forward<Handler_>(h))
|
||||
impl(alloc_type const& a, Handler_&& h,
|
||||
saved_handler * owner)
|
||||
: base(owner), v_(a, std::forward<Handler_>(h))
|
||||
#if defined(BOOST_ASIO_NO_TS_EXECUTORS)
|
||||
, wg2_(net::prefer(
|
||||
net::get_associated_executor(v_.h),
|
||||
@@ -87,10 +91,15 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
~impl()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
destroy() override
|
||||
{
|
||||
auto v = std::move(v_);
|
||||
slot_.clear();
|
||||
alloc_traits::destroy(v.get(), this);
|
||||
alloc_traits::deallocate(v.get(), this, 1);
|
||||
}
|
||||
@@ -98,11 +107,22 @@ public:
|
||||
void
|
||||
invoke() override
|
||||
{
|
||||
slot_.clear();
|
||||
auto v = std::move(v_);
|
||||
alloc_traits::destroy(v.get(), this);
|
||||
alloc_traits::deallocate(v.get(), this, 1);
|
||||
v.h();
|
||||
}
|
||||
|
||||
void self_complete()
|
||||
{
|
||||
slot_.clear();
|
||||
owner_->p_ = nullptr;
|
||||
auto v = std::move(v_);
|
||||
alloc_traits::destroy(v.get(), this);
|
||||
alloc_traits::deallocate(v.get(), this, 1);
|
||||
v.h(net::error::operation_aborted);
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -110,7 +130,8 @@ public:
|
||||
template<class Handler, class Allocator>
|
||||
void
|
||||
saved_handler::
|
||||
emplace(Handler&& handler, Allocator const& alloc)
|
||||
emplace(Handler&& handler, Allocator const& alloc,
|
||||
net::cancellation_type cancel_type)
|
||||
{
|
||||
// Can't delete a handler before invoking
|
||||
BOOST_ASSERT(! has_value());
|
||||
@@ -140,22 +161,47 @@ emplace(Handler&& handler, Allocator const& alloc)
|
||||
alloc_traits::deallocate(a, p, 1);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
auto cancel_slot = net::get_associated_cancellation_slot(handler);
|
||||
storage s(alloc);
|
||||
alloc_traits::construct(s.a, s.p,
|
||||
s.a, std::forward<Handler>(handler));
|
||||
p_ = boost::exchange(s.p, nullptr);
|
||||
s.a, std::forward<Handler>(handler), this);
|
||||
|
||||
auto tmp = boost::exchange(s.p, nullptr);
|
||||
p_ = tmp;
|
||||
|
||||
if (cancel_slot.is_connected())
|
||||
{
|
||||
struct cancel_op
|
||||
{
|
||||
impl<Handler, Allocator>* p;
|
||||
net::cancellation_type accepted_ct;
|
||||
cancel_op(impl<Handler, Allocator>* p,
|
||||
net::cancellation_type accepted_ct)
|
||||
: p(p), accepted_ct(accepted_ct) {}
|
||||
|
||||
void operator()(net::cancellation_type ct)
|
||||
{
|
||||
if ((ct & accepted_ct) != net::cancellation_type::none)
|
||||
p->self_complete();
|
||||
}
|
||||
};
|
||||
cancel_slot.template emplace<cancel_op>(tmp, cancel_type);
|
||||
}
|
||||
}
|
||||
|
||||
template<class Handler>
|
||||
void
|
||||
saved_handler::
|
||||
emplace(Handler&& handler)
|
||||
emplace(Handler&& handler, net::cancellation_type cancel_type)
|
||||
{
|
||||
// Can't delete a handler before invoking
|
||||
BOOST_ASSERT(! has_value());
|
||||
emplace(
|
||||
std::forward<Handler>(handler),
|
||||
net::get_associated_allocator(handler));
|
||||
net::get_associated_allocator(handler),
|
||||
cancel_type);
|
||||
}
|
||||
|
||||
} // beast
|
||||
|
||||
@@ -27,6 +27,7 @@ saved_handler::
|
||||
saved_handler(saved_handler&& other) noexcept
|
||||
: p_(boost::exchange(other.p_, nullptr))
|
||||
{
|
||||
p_->set_owner(this);
|
||||
}
|
||||
|
||||
saved_handler&
|
||||
@@ -36,6 +37,7 @@ operator=(saved_handler&& other) noexcept
|
||||
// Can't delete a handler before invoking
|
||||
BOOST_ASSERT(! has_value());
|
||||
p_ = boost::exchange(other.p_, nullptr);
|
||||
p_->set_owner(this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#define BOOST_BEAST_CORE_SAVED_HANDLER_HPP
|
||||
|
||||
#include <boost/beast/core/detail/config.hpp>
|
||||
#include <boost/asio/cancellation_type.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace beast {
|
||||
@@ -72,10 +73,13 @@ public:
|
||||
The implementation takes ownership of the handler by performing a decay-copy.
|
||||
|
||||
@param alloc The allocator to use.
|
||||
|
||||
@param cancel_type The type of cancellation allowed to complete this op.
|
||||
*/
|
||||
template<class Handler, class Allocator>
|
||||
void
|
||||
emplace(Handler&& handler, Allocator const& alloc);
|
||||
emplace(Handler&& handler, Allocator const& alloc,
|
||||
net::cancellation_type cancel_type = net::cancellation_type::terminal);
|
||||
|
||||
/** Store a completion handler in the container.
|
||||
|
||||
@@ -85,10 +89,13 @@ public:
|
||||
|
||||
@param handler The completion handler to store.
|
||||
The implementation takes ownership of the handler by performing a decay-copy.
|
||||
|
||||
@param cancel_type The type of cancellation allowed to complete this op.
|
||||
*/
|
||||
template<class Handler>
|
||||
void
|
||||
emplace(Handler&& handler);
|
||||
emplace(Handler&& handler,
|
||||
net::cancellation_type cancel_type = net::cancellation_type::terminal);
|
||||
|
||||
/** Discard the saved handler, if one exists.
|
||||
|
||||
|
||||
@@ -178,8 +178,18 @@ class write_op
|
||||
Stream& s_;
|
||||
serializer<isRequest, Body, Fields>& sr_;
|
||||
std::size_t bytes_transferred_ = 0;
|
||||
net::cancellation_state st_{this->
|
||||
beast::async_base<Handler, beast::executor_type<Stream>>
|
||||
::get_cancellation_slot()};
|
||||
|
||||
public:
|
||||
using cancellation_slot_type = net::cancellation_slot;
|
||||
cancellation_slot_type get_cancellation_slot() const noexcept
|
||||
{
|
||||
return st_.slot();
|
||||
}
|
||||
|
||||
|
||||
template<class Handler_>
|
||||
write_op(
|
||||
Handler_&& h,
|
||||
@@ -227,6 +237,8 @@ public:
|
||||
s_, sr_, std::move(*this));
|
||||
}
|
||||
bytes_transferred_ += bytes_transferred;
|
||||
if (!ec && st_.cancelled() != net::cancellation_type::none)
|
||||
ec = net::error::operation_aborted;
|
||||
if(ec)
|
||||
goto upcall;
|
||||
if(Predicate{}(sr_))
|
||||
|
||||
@@ -200,6 +200,19 @@ read_some(
|
||||
@note The completion handler will receive as a parameter the total number
|
||||
of bytes transferred from the stream. This may be zero for the case where
|
||||
there is sufficient pre-existing message data in the dynamic buffer.
|
||||
|
||||
@par Per-Operation Cancellation
|
||||
|
||||
This asynchronous operation supports cancellation for the following
|
||||
net::cancellation_type values:
|
||||
|
||||
@li @c net::cancellation_type::terminal
|
||||
|
||||
if the `stream` also supports terminal cancellation.
|
||||
|
||||
`terminal` cancellation leaves the stream in an undefined state,
|
||||
so that only closing it is guaranteed to succeed.
|
||||
|
||||
*/
|
||||
template<
|
||||
class AsyncReadStream,
|
||||
@@ -397,6 +410,19 @@ read_header(
|
||||
there is sufficient pre-existing message data in the dynamic buffer. The
|
||||
implementation will call @ref basic_parser::eager with the value `false`
|
||||
on the parser passed in.
|
||||
|
||||
@par Per-Operation Cancellation
|
||||
|
||||
This asynchronous operation supports cancellation for the following
|
||||
net::cancellation_type values:
|
||||
|
||||
@li @c net::cancellation_type::terminal
|
||||
|
||||
if the `stream` also supports terminal cancellation.
|
||||
|
||||
`terminal` cancellation leaves the stream in an undefined state,
|
||||
so that only closing it is guaranteed to succeed.
|
||||
|
||||
*/
|
||||
template<
|
||||
class AsyncReadStream,
|
||||
@@ -594,6 +620,19 @@ read(
|
||||
there is sufficient pre-existing message data in the dynamic buffer. The
|
||||
implementation will call @ref basic_parser::eager with the value `true`
|
||||
on the parser passed in.
|
||||
|
||||
@par Per-Operation Cancellation
|
||||
|
||||
This asynchronous operation supports cancellation for the following
|
||||
net::cancellation_type values:
|
||||
|
||||
@li @c net::cancellation_type::terminal
|
||||
|
||||
if the `stream` also supports terminal cancellation.
|
||||
|
||||
`terminal` cancellation leaves the stream in an undefined state,
|
||||
so that only closing it is guaranteed to succeed.
|
||||
|
||||
*/
|
||||
template<
|
||||
class AsyncReadStream,
|
||||
@@ -800,6 +839,19 @@ read(
|
||||
there is sufficient pre-existing message data in the dynamic buffer. The
|
||||
implementation will call @ref basic_parser::eager with the value `true`
|
||||
on the parser passed in.
|
||||
|
||||
@par Per-Operation Cancellation
|
||||
|
||||
This asynchronous operation supports cancellation for the following
|
||||
net::cancellation_type values:
|
||||
|
||||
@li @c net::cancellation_type::terminal
|
||||
|
||||
if the `stream` also supports terminal cancellation.
|
||||
|
||||
`terminal` cancellation leaves the stream in an undefined state,
|
||||
so that only closing it is guaranteed to succeed.
|
||||
|
||||
*/
|
||||
template<
|
||||
class AsyncReadStream,
|
||||
|
||||
@@ -161,6 +161,18 @@ write_some(
|
||||
this function. Invocation of the handler will be performed in a
|
||||
manner equivalent to using `net::post`.
|
||||
|
||||
@par Per-Operation Cancellation
|
||||
|
||||
This asynchronous operation supports cancellation for the following
|
||||
net::cancellation_type values:
|
||||
|
||||
@li @c net::cancellation_type::terminal
|
||||
|
||||
if the `stream` also supports terminal cancellation.
|
||||
|
||||
`terminal` cancellation leaves the stream in an undefined state,
|
||||
so that only closing it is guaranteed to succeed.
|
||||
|
||||
@see serializer
|
||||
*/
|
||||
template<
|
||||
@@ -291,6 +303,18 @@ write_header(
|
||||
@note The implementation will call @ref serializer::split with
|
||||
the value `true` on the serializer passed in.
|
||||
|
||||
@par Per-Operation Cancellation
|
||||
|
||||
This asynchronous operation supports cancellation for the following
|
||||
net::cancellation_type values:
|
||||
|
||||
@li @c net::cancellation_type::terminal
|
||||
|
||||
if the `stream` also supports terminal cancellation.
|
||||
|
||||
`terminal` cancellation leaves the stream in an undefined state,
|
||||
so that only closing it is guaranteed to succeed.
|
||||
|
||||
@see serializer
|
||||
*/
|
||||
template<
|
||||
@@ -412,6 +436,18 @@ write(
|
||||
this function. Invocation of the handler will be performed in a
|
||||
manner equivalent to using `net::post`.
|
||||
|
||||
@par Per-Operation Cancellation
|
||||
|
||||
This asynchronous operation supports cancellation for the following
|
||||
net::cancellation_type values:
|
||||
|
||||
@li @c net::cancellation_type::terminal
|
||||
|
||||
if the `stream` also supports terminal cancellation.
|
||||
|
||||
`terminal` cancellation leaves the stream in an undefined state,
|
||||
so that only closing it is guaranteed to succeed.
|
||||
|
||||
@see serializer
|
||||
*/
|
||||
template<
|
||||
@@ -637,6 +673,18 @@ write(
|
||||
this function. Invocation of the handler will be performed in a
|
||||
manner equivalent to using `net::post`.
|
||||
|
||||
@par Per-Operation Cancellation
|
||||
|
||||
This asynchronous operation supports cancellation for the following
|
||||
net::cancellation_type values:
|
||||
|
||||
@li @c net::cancellation_type::terminal
|
||||
|
||||
if the `stream` also supports terminal cancellation.
|
||||
|
||||
`terminal` cancellation leaves the stream in an undefined state,
|
||||
so that only closing it is guaranteed to succeed.
|
||||
|
||||
@see message
|
||||
*/
|
||||
template<
|
||||
@@ -699,6 +747,18 @@ async_write(
|
||||
this function. Invocation of the handler will be performed in a
|
||||
manner equivalent to using `net::post`.
|
||||
|
||||
@par Per-Operation Cancellation
|
||||
|
||||
This asynchronous operation supports cancellation for the following
|
||||
net::cancellation_type values:
|
||||
|
||||
@li @c net::cancellation_type::terminal
|
||||
|
||||
if the `stream` also supports terminal cancellation.
|
||||
|
||||
`terminal` cancellation leaves the stream in an undefined state,
|
||||
so that only closing it is guaranteed to succeed.
|
||||
|
||||
@see message
|
||||
*/
|
||||
template<
|
||||
|
||||
@@ -266,6 +266,9 @@ public:
|
||||
|
||||
// read and respond to an upgrade request
|
||||
//
|
||||
// Cancellation: the async_accept cancellation can be terminal
|
||||
// because it will just interrupt the reading of the header.
|
||||
//
|
||||
template<class NextLayer, bool deflateSupported>
|
||||
template<class Handler, class Decorator>
|
||||
class stream<NextLayer, deflateSupported>::accept_op
|
||||
|
||||
@@ -90,9 +90,15 @@ public:
|
||||
BOOST_ASIO_HANDLER_LOCATION((
|
||||
__FILE__, __LINE__,
|
||||
"websocket::async_close"));
|
||||
|
||||
impl.op_close.emplace(std::move(*this));
|
||||
this->set_allowed_cancellation(net::cancellation_type::all);
|
||||
impl.op_close.emplace(std::move(*this),
|
||||
net::cancellation_type::all);
|
||||
}
|
||||
// cancel fired before we could do anything.
|
||||
if (ec == net::error::operation_aborted)
|
||||
return this->complete(cont, ec);
|
||||
this->set_allowed_cancellation(net::cancellation_type::terminal);
|
||||
|
||||
impl.wr_block.lock(this);
|
||||
BOOST_ASIO_CORO_YIELD
|
||||
{
|
||||
@@ -143,9 +149,17 @@ public:
|
||||
BOOST_ASIO_HANDLER_LOCATION((
|
||||
__FILE__, __LINE__,
|
||||
"websocket::async_close"));
|
||||
|
||||
// terminal only, that's the default
|
||||
impl.op_r_close.emplace(std::move(*this));
|
||||
}
|
||||
if (ec == net::error::operation_aborted)
|
||||
{
|
||||
// if a cancellation fires here, we do a dirty shutdown
|
||||
impl.change_status(status::closed);
|
||||
close_socket(get_lowest_layer(impl.stream()));
|
||||
return this->complete(cont, ec);
|
||||
}
|
||||
|
||||
impl.rd_block.lock(this);
|
||||
BOOST_ASIO_CORO_YIELD
|
||||
{
|
||||
@@ -185,7 +199,7 @@ public:
|
||||
beast::detail::bind_continuation(std::move(*this)));
|
||||
}
|
||||
impl.rd_buf.commit(bytes_transferred);
|
||||
if(impl.check_stop_now(ec))
|
||||
if(impl.check_stop_now(ec)) //< this catches cancellation
|
||||
goto upcall;
|
||||
}
|
||||
if(detail::is_control(impl.rd_fh.op))
|
||||
|
||||
@@ -86,9 +86,12 @@ public:
|
||||
BOOST_ASIO_HANDLER_LOCATION((
|
||||
__FILE__, __LINE__,
|
||||
"websocket::async_ping"));
|
||||
|
||||
impl.op_ping.emplace(std::move(*this));
|
||||
this->set_allowed_cancellation(net::cancellation_type::all);
|
||||
impl.op_ping.emplace(std::move(*this), net::cancellation_type::all);
|
||||
}
|
||||
if (ec)
|
||||
return this->complete(cont, ec);
|
||||
this->set_allowed_cancellation(net::cancellation_type::terminal);
|
||||
impl.wr_block.lock(this);
|
||||
BOOST_ASIO_CORO_YIELD
|
||||
{
|
||||
|
||||
@@ -107,8 +107,14 @@ public:
|
||||
__FILE__, __LINE__,
|
||||
"websocket::async_read_some"));
|
||||
|
||||
impl.op_r_rd.emplace(std::move(*this));
|
||||
this->set_allowed_cancellation(net::cancellation_type::all);
|
||||
impl.op_r_rd.emplace(std::move(*this), net::cancellation_type::all);
|
||||
}
|
||||
if (ec)
|
||||
return this->complete(cont, ec, bytes_written_);
|
||||
|
||||
this->set_allowed_cancellation(net::cancellation_type::terminal);
|
||||
|
||||
impl.rd_block.lock(this);
|
||||
BOOST_ASIO_CORO_YIELD
|
||||
{
|
||||
@@ -275,6 +281,9 @@ public:
|
||||
|
||||
impl.op_rd.emplace(std::move(*this));
|
||||
}
|
||||
if (ec)
|
||||
return this->complete(cont, ec, bytes_written_);
|
||||
|
||||
impl.wr_block.lock(this);
|
||||
BOOST_ASIO_CORO_YIELD
|
||||
{
|
||||
@@ -629,6 +638,9 @@ public:
|
||||
|
||||
impl.op_rd.emplace(std::move(*this));
|
||||
}
|
||||
if (ec)
|
||||
return this->complete(cont, ec, bytes_written_);
|
||||
|
||||
impl.wr_block.lock(this);
|
||||
BOOST_ASIO_CORO_YIELD
|
||||
{
|
||||
|
||||
@@ -66,6 +66,8 @@ struct ssl_shutdown_op
|
||||
{
|
||||
BOOST_ASIO_CORO_REENTER(*this)
|
||||
{
|
||||
self.reset_cancellation_state(net::enable_total_cancellation());
|
||||
|
||||
BOOST_ASIO_CORO_YIELD
|
||||
s_.async_shutdown(std::move(self));
|
||||
ec_ = ec;
|
||||
|
||||
@@ -59,6 +59,7 @@ public:
|
||||
, nb_(false)
|
||||
{
|
||||
(*this)({}, 0, false);
|
||||
this->set_allowed_cancellation(net::cancellation_type::all);
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -181,9 +181,14 @@ operator()(
|
||||
"websocket::async_write" :
|
||||
"websocket::async_write_some"
|
||||
));
|
||||
|
||||
impl.op_wr.emplace(std::move(*this));
|
||||
this->set_allowed_cancellation(net::cancellation_type::all);
|
||||
impl.op_wr.emplace(std::move(*this),
|
||||
net::cancellation_type::all);
|
||||
}
|
||||
if (ec)
|
||||
return this->complete(cont, ec, bytes_transferred_);
|
||||
|
||||
this->set_allowed_cancellation(net::cancellation_type::terminal);
|
||||
impl.wr_block.lock(this);
|
||||
BOOST_ASIO_CORO_YIELD
|
||||
{
|
||||
|
||||
@@ -68,6 +68,18 @@ teardown(
|
||||
this function. Invocation of the handler will be performed in a
|
||||
manner equivalent to using `net::post`.
|
||||
|
||||
@par Per-Operation Cancellation
|
||||
|
||||
This asynchronous operation supports cancellation for the following
|
||||
net::cancellation_type values:
|
||||
|
||||
@li @c net::cancellation_type::terminal
|
||||
@li @c net::cancellation_type::partial
|
||||
@li @c net::cancellation_type::total
|
||||
|
||||
if they are also supported by the socket's @c async_teardown
|
||||
and @c async_shutdown operation.
|
||||
|
||||
*/
|
||||
template<class AsyncStream, class TeardownHandler>
|
||||
void
|
||||
|
||||
@@ -1602,6 +1602,20 @@ public:
|
||||
this function. Invocation of the handler will be performed in a
|
||||
manner equivalent to using `net::post`.
|
||||
|
||||
@par Per-Operation Cancellation
|
||||
|
||||
This asynchronous operation supports cancellation for the following
|
||||
net::cancellation_type values:
|
||||
|
||||
@li @c net::cancellation_type::terminal
|
||||
@li @c net::cancellation_type::total
|
||||
|
||||
`total` cancellation succeeds if the operation is suspended due to ongoing
|
||||
control operations such as a ping/pong.
|
||||
`terminal` cancellation succeeds when supported by the underlying stream.
|
||||
|
||||
@note `terminal` cancellation will may close the underlying socket.
|
||||
|
||||
@see
|
||||
@li <a href="https://tools.ietf.org/html/rfc6455#section-7.1.2">Websocket Closing Handshake (RFC6455)</a>
|
||||
*/
|
||||
@@ -1706,6 +1720,21 @@ public:
|
||||
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::post`.
|
||||
|
||||
@par Per-Operation Cancellation
|
||||
|
||||
This asynchronous operation supports cancellation for the following
|
||||
net::cancellation_type values:
|
||||
|
||||
@li @c net::cancellation_type::terminal
|
||||
@li @c net::cancellation_type::total
|
||||
|
||||
`total` cancellation succeeds if the operation is suspended due to ongoing
|
||||
control operations such as a ping/pong.
|
||||
`terminal` cancellation succeeds when supported by the underlying stream.
|
||||
|
||||
`terminal` cancellation leaves the stream in an undefined state,
|
||||
so that only closing it is guaranteed to succeed.
|
||||
*/
|
||||
template<
|
||||
BOOST_BEAST_ASYNC_TPARAM1 WriteHandler =
|
||||
@@ -1814,6 +1843,21 @@ public:
|
||||
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::post`.
|
||||
|
||||
@par Per-Operation Cancellation
|
||||
|
||||
This asynchronous operation supports cancellation for the following
|
||||
net::cancellation_type values:
|
||||
|
||||
@li @c net::cancellation_type::terminal
|
||||
@li @c net::cancellation_type::total
|
||||
|
||||
`total` cancellation succeeds if the operation is suspended due to ongoing
|
||||
control operations such as a ping/pong.
|
||||
`terminal` cancellation succeeds when supported by the underlying stream.
|
||||
|
||||
`terminal` cancellation leaves the stream in an undefined state,
|
||||
so that only closing it is guaranteed to succeed.
|
||||
*/
|
||||
template<
|
||||
BOOST_BEAST_ASYNC_TPARAM1 WriteHandler =
|
||||
@@ -1975,6 +2019,21 @@ public:
|
||||
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::post`.
|
||||
|
||||
@par Per-Operation Cancellation
|
||||
|
||||
This asynchronous operation supports cancellation for the following
|
||||
net::cancellation_type values:
|
||||
|
||||
@li @c net::cancellation_type::terminal
|
||||
@li @c net::cancellation_type::total
|
||||
|
||||
`total` cancellation succeeds if the operation is suspended due to ongoing
|
||||
control operations such as a ping/pong.
|
||||
`terminal` cancellation succeeds when supported by the underlying stream.
|
||||
|
||||
`terminal` cancellation leaves the stream in an undefined state,
|
||||
so that only closing it is guaranteed to succeed.
|
||||
*/
|
||||
template<
|
||||
class DynamicBuffer,
|
||||
@@ -2154,6 +2213,21 @@ public:
|
||||
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::post`.
|
||||
|
||||
@par Per-Operation Cancellation
|
||||
|
||||
This asynchronous operation supports cancellation for the following
|
||||
net::cancellation_type values:
|
||||
|
||||
@li @c net::cancellation_type::terminal
|
||||
@li @c net::cancellation_type::total
|
||||
|
||||
`total` cancellation succeeds if the operation is suspended due to ongoing
|
||||
control operations such as a ping/pong.
|
||||
`terminal` cancellation succeeds when supported by the underlying stream.
|
||||
|
||||
`terminal` cancellation leaves the stream in an undefined state,
|
||||
so that only closing it is guaranteed to succeed.
|
||||
*/
|
||||
template<
|
||||
class DynamicBuffer,
|
||||
@@ -2258,6 +2332,21 @@ public:
|
||||
from the beginning.
|
||||
|
||||
@param ec Set to indicate what error occurred, if any.
|
||||
|
||||
@par Per-Operation Cancellation
|
||||
|
||||
This asynchronous operation supports cancellation for the following
|
||||
net::cancellation_type values:
|
||||
|
||||
@li @c net::cancellation_type::terminal
|
||||
@li @c net::cancellation_type::total
|
||||
|
||||
`total` cancellation succeeds if the operation is suspended due to ongoing
|
||||
control operations such as a ping/pong.
|
||||
`terminal` cancellation succeeds when supported by the underlying stream.
|
||||
|
||||
`terminal` cancellation leaves the stream in an undefined state,
|
||||
so that only closing it is guaranteed to succeed.
|
||||
*/
|
||||
template<class MutableBufferSequence>
|
||||
std::size_t
|
||||
@@ -2329,6 +2418,22 @@ public:
|
||||
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::post`.
|
||||
|
||||
|
||||
@par Per-Operation Cancellation
|
||||
|
||||
This asynchronous operation supports cancellation for the following
|
||||
net::cancellation_type values:
|
||||
|
||||
@li @c net::cancellation_type::terminal
|
||||
@li @c net::cancellation_type::total
|
||||
|
||||
`total` cancellation succeeds if the operation is suspended due to ongoing
|
||||
control operations such as a ping/pong.
|
||||
`terminal` cancellation succeeds when supported by the underlying stream.
|
||||
|
||||
`terminal` cancellation leaves the stream in an undefined state,
|
||||
so that only closing it is guaranteed to succeed.
|
||||
*/
|
||||
template<
|
||||
class MutableBufferSequence,
|
||||
@@ -2452,6 +2557,21 @@ public:
|
||||
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::post`.
|
||||
|
||||
@par Per-Operation Cancellation
|
||||
|
||||
This asynchronous operation supports cancellation for the following
|
||||
net::cancellation_type values:
|
||||
|
||||
@li @c net::cancellation_type::terminal
|
||||
@li @c net::cancellation_type::total
|
||||
|
||||
`total` cancellation succeeds if the operation is suspended due to ongoing
|
||||
control operations such as a ping/pong.
|
||||
`terminal` cancellation succeeds when supported by the underlying stream.
|
||||
|
||||
`terminal` cancellation leaves the stream in an undefined state,
|
||||
so that only closing it is guaranteed to succeed.
|
||||
*/
|
||||
template<
|
||||
class ConstBufferSequence,
|
||||
@@ -2490,6 +2610,7 @@ public:
|
||||
@return The number of bytes sent from the buffers.
|
||||
|
||||
@throws system_error Thrown on failure.
|
||||
|
||||
*/
|
||||
template<class ConstBufferSequence>
|
||||
std::size_t
|
||||
@@ -2575,6 +2696,21 @@ public:
|
||||
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::post`.
|
||||
|
||||
@par Per-Operation Cancellation
|
||||
|
||||
This asynchronous operation supports cancellation for the following
|
||||
net::cancellation_type values:
|
||||
|
||||
@li @c net::cancellation_type::terminal
|
||||
@li @c net::cancellation_type::total
|
||||
|
||||
`total` cancellation succeeds if the operation is suspended due to ongoing
|
||||
control operations such as a ping/pong.
|
||||
`terminal` cancellation succeeds when supported by the underlying stream.
|
||||
|
||||
`terminal` cancellation leaves the stream in an undefined state,
|
||||
so that only closing it is guaranteed to succeed.
|
||||
*/
|
||||
template<
|
||||
class ConstBufferSequence,
|
||||
|
||||
@@ -163,6 +163,17 @@ teardown(
|
||||
this function. Invocation of the handler will be performed in a
|
||||
manner equivalent to using `net::post`.
|
||||
|
||||
@par Per-Operation Cancellation
|
||||
|
||||
This asynchronous operation supports cancellation for the following
|
||||
net::cancellation_type values:
|
||||
|
||||
@li @c net::cancellation_type::terminal
|
||||
@li @c net::cancellation_type::partial
|
||||
@li @c net::cancellation_type::total
|
||||
|
||||
if they are also supported by the socket's @c async_wait operation.
|
||||
|
||||
*/
|
||||
template<
|
||||
class Protocol, class Executor,
|
||||
|
||||
Reference in New Issue
Block a user