summaryrefslogtreecommitdiff
path: root/boost/beast/websocket
diff options
context:
space:
mode:
Diffstat (limited to 'boost/beast/websocket')
-rw-r--r--boost/beast/websocket/detail/error.hpp4
-rw-r--r--boost/beast/websocket/detail/frame.hpp8
-rw-r--r--boost/beast/websocket/detail/hybi13.hpp8
-rw-r--r--boost/beast/websocket/detail/mask.hpp62
-rw-r--r--boost/beast/websocket/detail/stream_base.hpp200
-rw-r--r--boost/beast/websocket/detail/utf8_checker.hpp6
-rw-r--r--boost/beast/websocket/impl/accept.ipp18
-rw-r--r--boost/beast/websocket/impl/close.ipp35
-rw-r--r--boost/beast/websocket/impl/handshake.ipp9
-rw-r--r--boost/beast/websocket/impl/ping.ipp9
-rw-r--r--boost/beast/websocket/impl/read.ipp24
-rw-r--r--boost/beast/websocket/impl/stream.ipp6
-rw-r--r--boost/beast/websocket/impl/teardown.ipp4
-rw-r--r--boost/beast/websocket/impl/write.ipp25
-rw-r--r--boost/beast/websocket/stream.hpp72
15 files changed, 365 insertions, 125 deletions
diff --git a/boost/beast/websocket/detail/error.hpp b/boost/beast/websocket/detail/error.hpp
index 57b837bd4c..1cf63fc68a 100644
--- a/boost/beast/websocket/detail/error.hpp
+++ b/boost/beast/websocket/detail/error.hpp
@@ -7,8 +7,8 @@
// Official repository: https://github.com/boostorg/beast
//
-#ifndef BOOST_BEAST_WEBSOCKET_DETAIL_ERROR_IPP
-#define BOOST_BEAST_WEBSOCKET_DETAIL_ERROR_IPP
+#ifndef BOOST_BEAST_WEBSOCKET_DETAIL_ERROR_HPP
+#define BOOST_BEAST_WEBSOCKET_DETAIL_ERROR_HPP
#include <boost/beast/core/error.hpp>
#include <boost/beast/core/string.hpp>
diff --git a/boost/beast/websocket/detail/frame.hpp b/boost/beast/websocket/detail/frame.hpp
index c3bd1690a9..be79a8af39 100644
--- a/boost/beast/websocket/detail/frame.hpp
+++ b/boost/beast/websocket/detail/frame.hpp
@@ -30,7 +30,7 @@ inline
std::uint16_t
big_uint16_to_native(void const* buf)
{
- auto const p = reinterpret_cast<
+ auto const p = static_cast<
std::uint8_t const*>(buf);
return (p[0]<<8) + p[1];
}
@@ -39,7 +39,7 @@ inline
std::uint64_t
big_uint64_to_native(void const* buf)
{
- auto const p = reinterpret_cast<
+ auto const p = static_cast<
std::uint8_t const*>(buf);
return
(static_cast<std::uint64_t>(p[0])<<56) +
@@ -56,7 +56,7 @@ inline
std::uint32_t
little_uint32_to_native(void const* buf)
{
- auto const p = reinterpret_cast<
+ auto const p = static_cast<
std::uint8_t const*>(buf);
return
p[0] +
@@ -69,7 +69,7 @@ inline
void
native_to_little_uint32(std::uint32_t v, void* buf)
{
- auto p = reinterpret_cast<std::uint8_t*>(buf);
+ auto p = static_cast<std::uint8_t*>(buf);
p[0] = v & 0xff;
p[1] = (v >> 8) & 0xff;
p[2] = (v >> 16) & 0xff;
diff --git a/boost/beast/websocket/detail/hybi13.hpp b/boost/beast/websocket/detail/hybi13.hpp
index b9c67b8200..424a9cc9e5 100644
--- a/boost/beast/websocket/detail/hybi13.hpp
+++ b/boost/beast/websocket/detail/hybi13.hpp
@@ -14,6 +14,7 @@
#include <boost/beast/core/string.hpp>
#include <boost/beast/core/detail/base64.hpp>
#include <boost/beast/core/detail/sha1.hpp>
+#include <boost/beast/websocket/detail/stream_base.hpp>
#include <boost/assert.hpp>
#include <array>
#include <cstdint>
@@ -31,14 +32,15 @@ using sec_ws_key_type = static_string<
using sec_ws_accept_type = static_string<
beast::detail::base64::encoded_size(20)>;
-template<class Gen>
+inline
void
-make_sec_ws_key(sec_ws_key_type& key, Gen& g)
+make_sec_ws_key(sec_ws_key_type& key)
{
+ auto p = stream_prng::prng();
char a[16];
for(int i = 0; i < 16; i += 4)
{
- auto const v = g();
+ auto const v = p->secure();
a[i ] = v & 0xff;
a[i+1] = (v >> 8) & 0xff;
a[i+2] = (v >> 16) & 0xff;
diff --git a/boost/beast/websocket/detail/mask.hpp b/boost/beast/websocket/detail/mask.hpp
index 8958d793b8..9f43a5782b 100644
--- a/boost/beast/websocket/detail/mask.hpp
+++ b/boost/beast/websocket/detail/mask.hpp
@@ -24,66 +24,6 @@ namespace beast {
namespace websocket {
namespace detail {
-// Pseudo-random source of mask keys
-//
-template<class Generator>
-class maskgen_t
-{
- Generator g_;
-
-public:
- using result_type =
- typename Generator::result_type;
-
- maskgen_t();
-
- result_type
- operator()() noexcept;
-
- void
- rekey();
-};
-
-template<class Generator>
-maskgen_t<Generator>::maskgen_t()
-{
- rekey();
-}
-
-template<class Generator>
-auto
-maskgen_t<Generator>::operator()() noexcept ->
- result_type
-{
- for(;;)
- if(auto key = g_())
- return key;
-}
-
-template<class _>
-void
-maskgen_t<_>::rekey()
-{
- std::random_device rng;
-#if 0
- std::array<std::uint32_t, 32> e;
- for(auto& i : e)
- i = rng();
- // VFALCO This constructor causes
- // address sanitizer to fail, no idea why.
- std::seed_seq ss(e.begin(), e.end());
- g_.seed(ss);
-#else
- g_.seed(rng());
-#endif
-}
-
-// VFALCO NOTE This generator has 5KB of state!
-//using maskgen = maskgen_t<std::mt19937>;
-using maskgen = maskgen_t<std::minstd_rand>;
-
-//------------------------------------------------------------------------------
-
using prepared_key = std::array<unsigned char, 4>;
inline
@@ -113,7 +53,7 @@ mask_inplace(boost::asio::mutable_buffer& b, prepared_key& key)
{
auto n = b.size();
auto mask = key; // avoid aliasing
- auto p = reinterpret_cast<unsigned char*>(b.data());
+ auto p = static_cast<unsigned char*>(b.data());
while(n >= 4)
{
for(int i = 0; i < 4; ++i)
diff --git a/boost/beast/websocket/detail/stream_base.hpp b/boost/beast/websocket/detail/stream_base.hpp
index 2e93cce3d4..4da5747e0b 100644
--- a/boost/beast/websocket/detail/stream_base.hpp
+++ b/boost/beast/websocket/detail/stream_base.hpp
@@ -16,9 +16,24 @@
#include <boost/beast/zlib/inflate_stream.hpp>
#include <boost/beast/core/buffers_suffix.hpp>
#include <boost/beast/core/error.hpp>
+#include <boost/beast/core/detail/chacha.hpp>
+#include <boost/beast/core/detail/integer_sequence.hpp>
+#include <boost/align/aligned_alloc.hpp>
#include <boost/asio/buffer.hpp>
+#include <boost/core/exchange.hpp>
+#include <atomic>
#include <cstdint>
#include <memory>
+#include <new>
+#include <random>
+
+// Turn this on to avoid using thread_local
+//#define BOOST_BEAST_NO_THREAD_LOCAL 1
+
+#ifdef BOOST_BEAST_NO_THREAD_LOCAL
+#include <atomic>
+#include <mutex>
+#endif
namespace boost {
namespace beast {
@@ -36,9 +51,8 @@ public:
soft_mutex& operator=(soft_mutex const&) = delete;
soft_mutex(soft_mutex&& other) noexcept
- : id_(other.id_)
+ : id_(boost::exchange(other.id_, 0))
{
- other.id_ = 0;
}
soft_mutex& operator=(soft_mutex&& other) noexcept
@@ -105,8 +119,186 @@ public:
}
};
+//------------------------------------------------------------------------------
+
+struct stream_prng
+{
+ bool secure_prng_ = true;
+
+ struct prng_type
+ {
+ std::minstd_rand fast;
+ beast::detail::chacha<20> secure;
+
+#if BOOST_BEAST_NO_THREAD_LOCAL
+ prng_type* next = nullptr;
+#endif
+
+ prng_type(std::uint32_t const* v, std::uint64_t stream)
+ : fast(static_cast<typename decltype(fast)::result_type>(
+ v[0] + v[1] + v[2] + v[3] + v[4] + v[5] + v[6] + v[7] + stream))
+ , secure(v, stream)
+ {
+ }
+ };
+
+ class prng_ref
+ {
+ prng_type* p_;
+
+ public:
+ prng_ref& operator=(prng_ref&&) = delete;
+
+ explicit
+ prng_ref(prng_type& p)
+ : p_(&p)
+ {
+ }
+
+ prng_ref(prng_ref&& other)
+ : p_(boost::exchange(other.p_, nullptr))
+ {
+ }
+
+#ifdef BOOST_BEAST_NO_THREAD_LOCAL
+ ~prng_ref()
+ {
+ if(p_)
+ pool::impl().release(*p_);
+ }
+#endif
+
+ prng_type*
+ operator->() const
+ {
+ return p_;
+ }
+ };
+
+#ifndef BOOST_BEAST_NO_THREAD_LOCAL
+ static
+ prng_ref
+ prng()
+ {
+ static std::atomic<std::uint64_t> stream{0};
+ thread_local prng_type p{seed(), stream++};
+ return prng_ref(p);
+ }
+
+#else
+ static
+ prng_ref
+ prng()
+ {
+ return prng_ref(pool::impl().acquire());
+ }
+
+#endif
+
+ static
+ std::uint32_t const*
+ seed(std::seed_seq* ss = nullptr)
+ {
+ static seed_data d(ss);
+ return d.v;
+ }
+
+ std::uint32_t
+ create_mask()
+ {
+ auto p = prng();
+ if(secure_prng_)
+ for(;;)
+ if(auto key = p->secure())
+ return key;
+ for(;;)
+ if(auto key = p->fast())
+ return key;
+ }
+
+private:
+ struct seed_data
+ {
+ std::uint32_t v[8];
+
+ explicit
+ seed_data(std::seed_seq* pss)
+ {
+ if(! pss)
+ {
+ std::random_device g;
+ std::seed_seq ss{
+ g(), g(), g(), g(), g(), g(), g(), g()};
+ ss.generate(v, v+8);
+ }
+ else
+ {
+ pss->generate(v, v+8);
+ }
+ }
+ };
+
+#ifdef BOOST_BEAST_NO_THREAD_LOCAL
+ class pool
+ {
+ prng_type* head_ = nullptr;
+ std::atomic<std::uint64_t> n_{0};
+ std::mutex m_;
+
+ public:
+ ~pool()
+ {
+ for(auto p = head_; p;)
+ {
+ auto next = p->next;
+ p->~prng_type();
+ boost::alignment::aligned_free(p);
+ p = next;
+ }
+ }
+
+ prng_type&
+ acquire()
+ {
+ for(;;)
+ {
+ std::lock_guard<std::mutex> lock(m_);
+ if(! head_)
+ break;
+ auto p = head_;
+ head_ = head_->next;
+ return *p;
+ }
+ auto p = boost::alignment::aligned_alloc(
+ 16, sizeof(prng_type));
+ if(! p)
+ BOOST_THROW_EXCEPTION(std::bad_alloc{});
+ return *(new(p) prng_type(seed(), n_++));
+ }
+
+ void
+ release(prng_type& p)
+ {
+ std::lock_guard<std::mutex> lock(m_);
+ p.next = head_;
+ head_ = &p;
+ }
+
+ static
+ pool&
+ impl()
+ {
+ static pool instance;
+ return instance;
+ }
+ };
+#endif
+};
+
+//------------------------------------------------------------------------------
+
template<bool deflateSupported>
-struct stream_base
+struct stream_base : stream_prng
{
// State information for the permessage-deflate extension
struct pmd_type
@@ -165,7 +357,7 @@ struct stream_base
};
template<>
-struct stream_base<false>
+struct stream_base<false> : stream_prng
{
// These stubs are for avoiding linking in the zlib
// code when permessage-deflate is not enabled.
diff --git a/boost/beast/websocket/detail/utf8_checker.hpp b/boost/beast/websocket/detail/utf8_checker.hpp
index 61c241bc19..63687587ce 100644
--- a/boost/beast/websocket/detail/utf8_checker.hpp
+++ b/boost/beast/websocket/detail/utf8_checker.hpp
@@ -89,7 +89,7 @@ write(ConstBufferSequence const& bs)
static_assert(boost::asio::is_const_buffer_sequence<ConstBufferSequence>::value,
"ConstBufferSequence requirements not met");
for(auto b : beast::detail::buffers_range(bs))
- if(! write(reinterpret_cast<
+ if(! write(static_cast<
std::uint8_t const*>(b.data()),
b.size()))
return false;
@@ -194,7 +194,7 @@ write(std::uint8_t const* in, std::size_t size)
// Add characters to the code point
while(n--)
*p_++ = *in++;
- BOOST_ASSERT(p_ <= cp_ + 5);
+ BOOST_ASSERT(p_ <= cp_ + 4);
// Still incomplete?
if(need_ > 0)
@@ -313,7 +313,7 @@ tail:
while(n--)
*p_++ = *in++;
BOOST_ASSERT(in == end);
- BOOST_ASSERT(p_ <= cp_ + 5);
+ BOOST_ASSERT(p_ <= cp_ + 4);
// Do partial validation on the incomplete
// code point, this is called "Fail fast"
diff --git a/boost/beast/websocket/impl/accept.ipp b/boost/beast/websocket/impl/accept.ipp
index 9daf7b311b..c93e933b18 100644
--- a/boost/beast/websocket/impl/accept.ipp
+++ b/boost/beast/websocket/impl/accept.ipp
@@ -22,6 +22,7 @@
#include <boost/asio/coroutine.hpp>
#include <boost/asio/associated_allocator.hpp>
#include <boost/asio/associated_executor.hpp>
+#include <boost/asio/executor_work_guard.hpp>
#include <boost/asio/handler_continuation_hook.hpp>
#include <boost/asio/handler_invoke_hook.hpp>
#include <boost/asio/post.hpp>
@@ -43,6 +44,8 @@ class stream<NextLayer, deflateSupported>::response_op
struct data
{
stream<NextLayer, deflateSupported>& ws;
+ boost::asio::executor_work_guard<decltype(std::declval<
+ stream<NextLayer, deflateSupported>&>().get_executor())> wg;
error_code result;
response_type res;
@@ -54,6 +57,7 @@ class stream<NextLayer, deflateSupported>::response_op
http::basic_fields<Allocator>> const& req,
Decorator const& decorator)
: ws(ws_)
+ , wg(ws.get_executor())
, res(ws_.build_response(req, decorator, result))
{
}
@@ -137,7 +141,10 @@ operator()(
d.ws.do_pmd_config(d.res, is_deflate_supported{});
d.ws.open(role_type::server);
}
- d_.invoke(ec);
+ {
+ auto wg = std::move(d.wg);
+ d_.invoke(ec);
+ }
}
}
@@ -153,6 +160,8 @@ class stream<NextLayer, deflateSupported>::accept_op
struct data
{
stream<NextLayer, deflateSupported>& ws;
+ boost::asio::executor_work_guard<decltype(std::declval<
+ stream<NextLayer, deflateSupported>&>().get_executor())> wg;
Decorator decorator;
http::request_parser<http::empty_body> p;
data(
@@ -160,6 +169,7 @@ class stream<NextLayer, deflateSupported>::accept_op
stream<NextLayer, deflateSupported>& ws_,
Decorator const& decorator_)
: ws(ws_)
+ , wg(ws.get_executor())
, decorator(decorator_)
{
}
@@ -284,6 +294,7 @@ operator()(error_code ec, std::size_t)
auto& ws = d.ws;
auto const req = d.p.release();
auto const decorator = d.decorator;
+ auto wg = std::move(d.wg);
#if 1
return response_op<Handler>{
d_.release_handler(),
@@ -297,7 +308,10 @@ operator()(error_code ec, std::size_t)
#endif
}
}
- d_.invoke(ec);
+ {
+ auto wg = std::move(d.wg);
+ d_.invoke(ec);
+ }
}
}
diff --git a/boost/beast/websocket/impl/close.ipp b/boost/beast/websocket/impl/close.ipp
index 7b0e1ff648..62ddffa23d 100644
--- a/boost/beast/websocket/impl/close.ipp
+++ b/boost/beast/websocket/impl/close.ipp
@@ -18,6 +18,7 @@
#include <boost/asio/associated_allocator.hpp>
#include <boost/asio/associated_executor.hpp>
#include <boost/asio/coroutine.hpp>
+#include <boost/asio/executor_work_guard.hpp>
#include <boost/asio/handler_continuation_hook.hpp>
#include <boost/asio/handler_invoke_hook.hpp>
#include <boost/asio/post.hpp>
@@ -43,6 +44,8 @@ class stream<NextLayer, deflateSupported>::close_op
struct state
{
stream<NextLayer, deflateSupported>& ws;
+ boost::asio::executor_work_guard<decltype(std::declval<
+ stream<NextLayer, deflateSupported>&>().get_executor())> wg;
detail::frame_buffer fb;
error_code ev;
bool cont = false;
@@ -52,6 +55,7 @@ class stream<NextLayer, deflateSupported>::close_op
stream<NextLayer, deflateSupported>& ws_,
close_reason const& cr)
: ws(ws_)
+ , wg(ws.get_executor())
{
// Serialize the close frame
ws.template write_close<
@@ -134,14 +138,8 @@ operator()(
d.cont = cont;
BOOST_ASIO_CORO_REENTER(*this)
{
- // Maybe suspend
- if(d.ws.wr_block_.try_lock(this))
- {
- // Make sure the stream is open
- if(! d.ws.check_open(ec))
- goto upcall;
- }
- else
+ // Attempt to acquire write block
+ if(! d.ws.wr_block_.try_lock(this))
{
// Suspend
BOOST_ASIO_CORO_YIELD
@@ -155,12 +153,12 @@ operator()(
boost::asio::post(
d.ws.get_executor(), std::move(*this));
BOOST_ASSERT(d.ws.wr_block_.is_locked(this));
-
- // Make sure the stream is open
- if(! d.ws.check_open(ec))
- goto upcall;
}
+ // Make sure the stream is open
+ if(! d.ws.check_open(ec))
+ goto upcall;
+
// Can't call close twice
BOOST_ASSERT(! d.ws.wr_close_);
@@ -303,12 +301,15 @@ operator()(
d.ws.paused_wr_.maybe_invoke();
if(! d.cont)
{
- auto& ws = d.ws;
- return boost::asio::post(
- ws.stream_.get_executor(),
- bind_handler(d_.release_handler(), ec));
+ BOOST_ASIO_CORO_YIELD
+ boost::asio::post(
+ d.ws.get_executor(),
+ bind_handler(std::move(*this), ec));
+ }
+ {
+ auto wg = std::move(d.wg);
+ d_.invoke(ec);
}
- d_.invoke(ec);
}
}
diff --git a/boost/beast/websocket/impl/handshake.ipp b/boost/beast/websocket/impl/handshake.ipp
index 8e33e1a890..a1a826be8a 100644
--- a/boost/beast/websocket/impl/handshake.ipp
+++ b/boost/beast/websocket/impl/handshake.ipp
@@ -20,6 +20,7 @@
#include <boost/asio/associated_allocator.hpp>
#include <boost/asio/associated_executor.hpp>
#include <boost/asio/coroutine.hpp>
+#include <boost/asio/executor_work_guard.hpp>
#include <boost/asio/handler_continuation_hook.hpp>
#include <boost/asio/handler_invoke_hook.hpp>
#include <boost/assert.hpp>
@@ -42,6 +43,8 @@ class stream<NextLayer, deflateSupported>::handshake_op
struct data
{
stream<NextLayer, deflateSupported>& ws;
+ boost::asio::executor_work_guard<decltype(std::declval<
+ stream<NextLayer, deflateSupported>&>().get_executor())> wg;
response_type* res_p;
detail::sec_ws_key_type key;
http::request<http::empty_body> req;
@@ -56,6 +59,7 @@ class stream<NextLayer, deflateSupported>::handshake_op
string_view target,
Decorator const& decorator)
: ws(ws_)
+ , wg(ws.get_executor())
, res_p(res_p_)
, req(ws.build_request(key,
host, target, decorator))
@@ -155,7 +159,10 @@ operator()(error_code ec, std::size_t)
if(d.res_p)
swap(d.res, *d.res_p);
upcall:
- d_.invoke(ec);
+ {
+ auto wg = std::move(d.wg);
+ d_.invoke(ec);
+ }
}
}
diff --git a/boost/beast/websocket/impl/ping.ipp b/boost/beast/websocket/impl/ping.ipp
index c7deb9c37c..6ceaaeabae 100644
--- a/boost/beast/websocket/impl/ping.ipp
+++ b/boost/beast/websocket/impl/ping.ipp
@@ -18,6 +18,7 @@
#include <boost/asio/associated_allocator.hpp>
#include <boost/asio/associated_executor.hpp>
#include <boost/asio/coroutine.hpp>
+#include <boost/asio/executor_work_guard.hpp>
#include <boost/asio/handler_continuation_hook.hpp>
#include <boost/asio/handler_invoke_hook.hpp>
#include <boost/asio/post.hpp>
@@ -41,6 +42,8 @@ class stream<NextLayer, deflateSupported>::ping_op
struct state
{
stream<NextLayer, deflateSupported>& ws;
+ boost::asio::executor_work_guard<decltype(std::declval<
+ stream<NextLayer, deflateSupported>&>().get_executor())> wg;
detail::frame_buffer fb;
state(
@@ -49,6 +52,7 @@ class stream<NextLayer, deflateSupported>::ping_op
detail::opcode op,
ping_data const& payload)
: ws(ws_)
+ , wg(ws.get_executor())
{
// Serialize the control frame
ws.template write_ping<
@@ -172,7 +176,10 @@ operator()(error_code ec, std::size_t)
d.ws.paused_close_.maybe_invoke() ||
d.ws.paused_rd_.maybe_invoke() ||
d.ws.paused_wr_.maybe_invoke();
- d_.invoke(ec);
+ {
+ auto wg = std::move(d.wg);
+ d_.invoke(ec);
+ }
}
}
diff --git a/boost/beast/websocket/impl/read.ipp b/boost/beast/websocket/impl/read.ipp
index 1dfbd01e72..9e8e0c4740 100644
--- a/boost/beast/websocket/impl/read.ipp
+++ b/boost/beast/websocket/impl/read.ipp
@@ -21,6 +21,7 @@
#include <boost/asio/associated_allocator.hpp>
#include <boost/asio/associated_executor.hpp>
#include <boost/asio/coroutine.hpp>
+#include <boost/asio/executor_work_guard.hpp>
#include <boost/asio/handler_continuation_hook.hpp>
#include <boost/asio/handler_invoke_hook.hpp>
#include <boost/asio/post.hpp>
@@ -82,6 +83,8 @@ class stream<NextLayer, deflateSupported>::read_some_op
{
Handler h_;
stream<NextLayer, deflateSupported>& ws_;
+ boost::asio::executor_work_guard<decltype(std::declval<
+ stream<NextLayer, deflateSupported>&>().get_executor())> wg_;
MutableBufferSequence bs_;
buffers_suffix<MutableBufferSequence> cb_;
std::size_t bytes_written_ = 0;
@@ -103,6 +106,7 @@ public:
MutableBufferSequence const& bs)
: h_(std::forward<DeducedHandler>(h))
, ws_(ws)
+ , wg_(ws_.get_executor())
, bs_(bs)
, cb_(bs)
, code_(close_code::none)
@@ -622,12 +626,8 @@ operator()(
goto upcall;
close:
- if(ws_.wr_block_.try_lock(this))
- {
- // Make sure the stream is open
- BOOST_ASSERT(ws_.status_ == status::open);
- }
- else
+ // Try to acquire the write block
+ if(! ws_.wr_block_.try_lock(this))
{
// Suspend
BOOST_ASIO_CORO_YIELD
@@ -700,10 +700,13 @@ operator()(
ws_.paused_ping_.maybe_invoke() ||
ws_.paused_wr_.maybe_invoke();
if(! cont_)
- return boost::asio::post(
- ws_.stream_.get_executor(),
- bind_handler(std::move(h_),
+ {
+ BOOST_ASIO_CORO_YIELD
+ boost::asio::post(
+ ws_.get_executor(),
+ bind_handler(std::move(*this),
ec, bytes_written_));
+ }
h_(ec, bytes_written_);
}
}
@@ -719,6 +722,8 @@ class stream<NextLayer, deflateSupported>::read_op
{
Handler h_;
stream<NextLayer, deflateSupported>& ws_;
+ boost::asio::executor_work_guard<decltype(std::declval<
+ stream<NextLayer, deflateSupported>&>().get_executor())> wg_;
DynamicBuffer& b_;
std::size_t limit_;
std::size_t bytes_written_ = 0;
@@ -740,6 +745,7 @@ public:
bool some)
: h_(std::forward<DeducedHandler>(h))
, ws_(ws)
+ , wg_(ws_.get_executor())
, b_(b)
, limit_(limit ? limit : (
std::numeric_limits<std::size_t>::max)())
diff --git a/boost/beast/websocket/impl/stream.ipp b/boost/beast/websocket/impl/stream.ipp
index cf747c230d..4aa729956b 100644
--- a/boost/beast/websocket/impl/stream.ipp
+++ b/boost/beast/websocket/impl/stream.ipp
@@ -556,7 +556,7 @@ write_close(DynamicBuffer& db, close_reason const& cr)
if(role_ == role_type::client)
{
fh.mask = true;
- fh.key = wr_gen_();
+ fh.key = this->create_mask();
}
else
{
@@ -608,7 +608,7 @@ write_ping(DynamicBuffer& db,
fh.len = data.size();
fh.mask = role_ == role_type::client;
if(fh.mask)
- fh.key = wr_gen_();
+ fh.key = this->create_mask();
detail::write(db, fh);
if(data.empty())
return;
@@ -641,7 +641,7 @@ build_request(detail::sec_ws_key_type& key,
req.set(http::field::host, host);
req.set(http::field::upgrade, "websocket");
req.set(http::field::connection, "upgrade");
- detail::make_sec_ws_key(key, wr_gen_);
+ detail::make_sec_ws_key(key);
req.set(http::field::sec_websocket_key, key);
req.set(http::field::sec_websocket_version, "13");
build_request_pmd(req, is_deflate_supported{});
diff --git a/boost/beast/websocket/impl/teardown.ipp b/boost/beast/websocket/impl/teardown.ipp
index add6b2773d..fe94d55274 100644
--- a/boost/beast/websocket/impl/teardown.ipp
+++ b/boost/beast/websocket/impl/teardown.ipp
@@ -15,6 +15,7 @@
#include <boost/asio/associated_allocator.hpp>
#include <boost/asio/associated_executor.hpp>
#include <boost/asio/coroutine.hpp>
+#include <boost/asio/executor_work_guard.hpp>
#include <boost/asio/handler_continuation_hook.hpp>
#include <boost/asio/handler_invoke_hook.hpp>
#include <boost/asio/post.hpp>
@@ -34,6 +35,8 @@ class teardown_tcp_op : public boost::asio::coroutine
Handler h_;
socket_type& s_;
+ boost::asio::executor_work_guard<decltype(std::declval<
+ socket_type&>().get_executor())> wg_;
role_type role_;
bool nb_;
@@ -48,6 +51,7 @@ public:
role_type role)
: h_(std::forward<DeducedHandler>(h))
, s_(s)
+ , wg_(s_.get_executor())
, role_(role)
{
}
diff --git a/boost/beast/websocket/impl/write.ipp b/boost/beast/websocket/impl/write.ipp
index d12f2f9e12..edaca7989f 100644
--- a/boost/beast/websocket/impl/write.ipp
+++ b/boost/beast/websocket/impl/write.ipp
@@ -22,6 +22,7 @@
#include <boost/asio/associated_allocator.hpp>
#include <boost/asio/associated_executor.hpp>
#include <boost/asio/coroutine.hpp>
+#include <boost/asio/executor_work_guard.hpp>
#include <boost/asio/handler_continuation_hook.hpp>
#include <boost/asio/handler_invoke_hook.hpp>
#include <boost/assert.hpp>
@@ -141,6 +142,8 @@ class stream<NextLayer, deflateSupported>::write_some_op
{
Handler h_;
stream<NextLayer, deflateSupported>& ws_;
+ boost::asio::executor_work_guard<decltype(std::declval<
+ stream<NextLayer, deflateSupported>&>().get_executor())> wg_;
buffers_suffix<Buffers> cb_;
detail::frame_header fh_;
detail::prepared_key key_;
@@ -166,6 +169,7 @@ public:
Buffers const& bs)
: h_(std::forward<DeducedHandler>(h))
, ws_(ws)
+ , wg_(ws_.get_executor())
, cb_(bs)
, fin_(fin)
{
@@ -402,7 +406,7 @@ operator()(
remain_ = buffer_size(cb_);
fh_.fin = fin_;
fh_.len = remain_;
- fh_.key = ws_.wr_gen_();
+ fh_.key = ws_.create_mask();
detail::prepare_key(key_, fh_.key);
ws_.wr_fb_.reset();
detail::write<flat_static_buffer_base>(
@@ -454,7 +458,7 @@ operator()(
n = clamp(remain_, ws_.wr_buf_size_);
remain_ -= n;
fh_.len = n;
- fh_.key = ws_.wr_gen_();
+ fh_.key = ws_.create_mask();
fh_.fin = fin_ ? remain_ == 0 : false;
detail::prepare_key(key_, fh_.key);
buffer_copy(buffer(
@@ -517,7 +521,7 @@ operator()(
}
if(fh_.mask)
{
- fh_.key = ws_.wr_gen_();
+ fh_.key = ws_.create_mask();
detail::prepared_key key;
detail::prepare_key(key, fh_.key);
detail::mask_inplace(b, key);
@@ -569,9 +573,12 @@ operator()(
ws_.paused_rd_.maybe_invoke() ||
ws_.paused_ping_.maybe_invoke();
if(! cont_)
- return boost::asio::post(
- ws_.stream_.get_executor(),
- bind_handler(std::move(h_), ec, bytes_transferred_));
+ {
+ BOOST_ASIO_CORO_YIELD
+ boost::asio::post(
+ ws_.get_executor(),
+ bind_handler(std::move(*this), ec, bytes_transferred_));
+ }
h_(ec, bytes_transferred_);
}
}
@@ -659,7 +666,7 @@ write_some(bool fin,
}
if(fh.mask)
{
- fh.key = wr_gen_();
+ fh.key = this->create_mask();
detail::prepared_key key;
detail::prepare_key(key, fh.key);
detail::mask_inplace(b, key);
@@ -733,7 +740,7 @@ write_some(bool fin,
// mask, no autofrag
fh.fin = fin;
fh.len = remain;
- fh.key = wr_gen_();
+ fh.key = this->create_mask();
detail::prepared_key key;
detail::prepare_key(key, fh.key);
detail::fh_buffer fh_buf;
@@ -777,7 +784,7 @@ write_some(bool fin,
ConstBufferSequence> cb{buffers};
for(;;)
{
- fh.key = wr_gen_();
+ fh.key = this->create_mask();
detail::prepared_key key;
detail::prepare_key(key, fh.key);
auto const n = clamp(remain, wr_buf_size_);
diff --git a/boost/beast/websocket/stream.hpp b/boost/beast/websocket/stream.hpp
index 90cb753294..315a23d69b 100644
--- a/boost/beast/websocket/stream.hpp
+++ b/boost/beast/websocket/stream.hpp
@@ -125,7 +125,7 @@ template<
class NextLayer,
bool deflateSupported>
class stream
-#ifndef BOOST_BEAST_DOXYGEN
+#if ! BOOST_BEAST_DOXYGEN
: private detail::stream_base<deflateSupported>
#endif
{
@@ -206,7 +206,6 @@ class stream
std::size_t wr_buf_opt_ // write buffer size option setting
= 4096;
detail::fh_buffer wr_fb_; // header buffer used for writes
- detail::maskgen wr_gen_; // source of mask keys
detail::pausation paused_rd_; // paused read op
detail::pausation paused_wr_; // paused write op
@@ -509,7 +508,7 @@ public:
return wr_frag_opt_;
}
- /** Set the binary message option.
+ /** Set the binary message write option.
This controls whether or not outgoing message opcodes
are set to binary or text. The setting is only applied
@@ -536,7 +535,7 @@ public:
detail::opcode::text;
}
- /// Returns `true` if the binary message option is set.
+ /// Returns `true` if the binary message write option is set.
bool
binary() const
{
@@ -633,6 +632,37 @@ public:
return rd_msg_max_;
}
+ /** Set whether the PRNG is cryptographically secure
+
+ This controls whether or not the source of pseudo-random
+ numbers used to produce the masks required by the WebSocket
+ protocol are of cryptographic quality. When the setting is
+ `true`, a strong algorithm is used which cannot be guessed
+ by observing outputs. When the setting is `false`, a much
+ faster algorithm is used.
+ Masking is only performed by streams operating in the client
+ mode. For streams operating in the server mode, this setting
+ has no effect.
+ By default, newly constructed streams use a secure PRNG.
+
+ If the WebSocket stream is used with an encrypted SSL or TLS
+ next layer, if it is known to the application that intermediate
+ proxies are not vulnerable to cache poisoning, or if the
+ application is designed such that an attacker cannot send
+ arbitrary inputs to the stream interface, then the faster
+ algorithm may be used.
+
+ For more information please consult the WebSocket protocol RFC.
+
+ @param value `true` if the PRNG algorithm should be
+ cryptographically secure.
+ */
+ void
+ secure_prng(bool value)
+ {
+ this->secure_prng_ = value;
+ }
+
/** Set the write buffer size option.
Sets the size of the write buffer used by the implementation to
@@ -674,7 +704,7 @@ public:
return wr_buf_opt_;
}
- /** Set the text message option.
+ /** Set the text message write option.
This controls whether or not outgoing message opcodes
are set to binary or text. The setting is only applied
@@ -701,7 +731,7 @@ public:
detail::opcode::binary;
}
- /// Returns `true` if the text message option is set.
+ /// Returns `true` if the text message write option is set.
bool
text() const
{
@@ -3563,6 +3593,36 @@ private:
error_code& ec);
};
+/** Manually provide a one-time seed to initialize the PRNG
+
+ This function invokes the specified seed sequence to produce a seed
+ suitable for use with the pseudo-random number generator used to
+ create masks and perform WebSocket protocol handshakes.
+
+ If a seed is not manually provided, the implementation will
+ perform a one-time seed generation using `std::random_device`. This
+ function may be used when the application runs in an environment
+ where the random device is unreliable or does not provide sufficient
+ entropy.
+
+ @par Preconditions
+
+ This function may not be called after any websocket @ref stream objects
+ have been constructed.
+
+ @param ss A reference to a `std::seed_seq` which will be used to seed
+ the pseudo-random number generator. The seed sequence should have at
+ least 256 bits of entropy.
+
+ @see stream::secure_prng
+*/
+inline
+void
+seed_prng(std::seed_seq& ss)
+{
+ detail::stream_prng::seed(&ss);
+}
+
} // websocket
} // beast
} // boost