| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328 |
- //
- // Copyright (c) 2016-2019 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_WEBSOCKET_DETAIL_PRNG_IPP
- #define BOOST_BEAST_WEBSOCKET_DETAIL_PRNG_IPP
- #include <boost/beast/websocket/detail/prng.hpp>
- #include <boost/beast/core/detail/chacha.hpp>
- #include <boost/beast/core/detail/pcg.hpp>
- #include <boost/align/aligned_alloc.hpp>
- #include <boost/throw_exception.hpp>
- #include <atomic>
- #include <cstdlib>
- #include <mutex>
- #include <new>
- #include <random>
- #include <stdexcept>
- namespace boost {
- namespace beast {
- namespace websocket {
- namespace detail {
- //------------------------------------------------------------------------------
- std::uint32_t const*
- prng_seed(std::seed_seq* ss)
- {
- struct data
- {
- std::uint32_t v[8];
- explicit
- 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);
- }
- }
- };
- static data const d(ss);
- return d.v;
- }
- //------------------------------------------------------------------------------
- template<class T>
- class prng_pool
- {
- std::mutex m_;
- T* head_ = nullptr;
- public:
- static
- prng_pool&
- instance()
- {
- static prng_pool p;
- return p;
- }
- ~prng_pool()
- {
- for(auto p = head_; p;)
- {
- auto next = p->next;
- p->~T();
- boost::alignment::aligned_free(p);
- p = next;
- }
- }
- prng::ref
- acquire()
- {
- {
- std::lock_guard<
- std::mutex> g(m_);
- if(head_)
- {
- auto p = head_;
- head_ = head_->next;
- return prng::ref(*p);
- }
- }
- auto p = boost::alignment::aligned_alloc(
- 16, sizeof(T));
- if(! p)
- BOOST_THROW_EXCEPTION(std::bad_alloc{});
- return prng::ref(*(::new(p) T()));
- }
- void
- release(T& t)
- {
- std::lock_guard<
- std::mutex> g(m_);
- t.next = head_;
- head_ = &t;
- }
- };
- prng::ref
- make_prng_no_tls(bool secure)
- {
- class fast_prng final : public prng
- {
- int refs_ = 0;
- beast::detail::pcg r_;
- public:
- fast_prng* next = nullptr;
- fast_prng()
- : r_(
- []{
- auto const pv = prng_seed();
- return
- ((static_cast<std::uint64_t>(pv[0])<<32)+pv[1]) ^
- ((static_cast<std::uint64_t>(pv[2])<<32)+pv[3]) ^
- ((static_cast<std::uint64_t>(pv[4])<<32)+pv[5]) ^
- ((static_cast<std::uint64_t>(pv[6])<<32)+pv[7]);
- }(),
- []{
- static std::atomic<
- std::uint32_t> nonce{0};
- return ++nonce;
- }())
- {
- }
- protected:
- prng&
- acquire() noexcept override
- {
- ++refs_;
- return *this;
- }
- void
- release() noexcept override
- {
- if(--refs_ == 0)
- prng_pool<fast_prng>::instance().release(*this);
- }
- value_type
- operator()() noexcept override
- {
- return r_();
- }
- };
- class secure_prng final : public prng
- {
- int refs_ = 0;
- beast::detail::chacha<20> r_;
- public:
- secure_prng* next = nullptr;
- secure_prng()
- : r_(prng_seed(), []
- {
- static std::atomic<
- std::uint64_t> nonce{0};
- return ++nonce;
- }())
- {
- }
- protected:
- prng&
- acquire() noexcept override
- {
- ++refs_;
- return *this;
- }
- void
- release() noexcept override
- {
- if(--refs_ == 0)
- prng_pool<secure_prng>::instance().release(*this);
- }
- value_type
- operator()() noexcept override
- {
- return r_();
- }
- };
- if(secure)
- return prng_pool<secure_prng>::instance().acquire();
- return prng_pool<fast_prng>::instance().acquire();
- }
- //------------------------------------------------------------------------------
- #ifndef BOOST_NO_CXX11_THREAD_LOCAL
- prng::ref
- make_prng_tls(bool secure)
- {
- class fast_prng final : public prng
- {
- beast::detail::pcg r_;
- public:
- fast_prng()
- : r_(
- []{
- auto const pv = prng_seed();
- return
- ((static_cast<std::uint64_t>(pv[0])<<32)+pv[1]) ^
- ((static_cast<std::uint64_t>(pv[2])<<32)+pv[3]) ^
- ((static_cast<std::uint64_t>(pv[4])<<32)+pv[5]) ^
- ((static_cast<std::uint64_t>(pv[6])<<32)+pv[7]);
- }(),
- []{
- static std::atomic<
- std::uint32_t> nonce{0};
- return ++nonce;
- }())
- {
- }
- protected:
- prng&
- acquire() noexcept override
- {
- return *this;
- }
- void
- release() noexcept override
- {
- }
- value_type
- operator()() noexcept override
- {
- return r_();
- }
- };
- class secure_prng final : public prng
- {
- beast::detail::chacha<20> r_;
- public:
- secure_prng()
- : r_(prng_seed(), []
- {
- static std::atomic<
- std::uint64_t> nonce{0};
- return ++nonce;
- }())
- {
- }
- protected:
- prng&
- acquire() noexcept override
- {
- return *this;
- }
- void
- release() noexcept override
- {
- }
- value_type
- operator()() noexcept override
- {
- return r_();
- }
- };
- if(secure)
- {
- thread_local secure_prng sp;
- return prng::ref(sp);
- }
- thread_local fast_prng fp;
- return prng::ref(fp);
- }
- #endif
- //------------------------------------------------------------------------------
- prng::ref
- make_prng(bool secure)
- {
- #ifdef BOOST_NO_CXX11_THREAD_LOCAL
- return make_prng_no_tls(secure);
- #else
- return make_prng_tls(secure);
- #endif
- }
- } // detail
- } // websocket
- } // beast
- } // boost
- #endif
|