| // Boost seed_rng.hpp header file ----------------------------------------------// |
| |
| // Copyright 2007 Andy Tompkins. |
| // 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) |
| |
| // Revision History |
| // 09 Nov 2007 - Initial Revision |
| // 25 Feb 2008 - moved to namespace boost::uuids::detail |
| // 28 Nov 2009 - disabled deprecated warnings for MSVC |
| |
| // seed_rng models a UniformRandomNumberGenerator (see Boost.Random). |
| // Random number generators are hard to seed well. This is intended to provide |
| // good seed values for random number generators. |
| // It creates random numbers from a sha1 hash of data from a variary of sources, |
| // all of which are standard function calls. It produces random numbers slowly. |
| // Peter Dimov provided the details of sha1_random_digest_(). |
| // see http://archives.free.net.ph/message/20070507.175609.4c4f503a.en.html |
| |
| #ifndef BOOST_UUID_SEED_RNG_HPP |
| #define BOOST_UUID_SEED_RNG_HPP |
| |
| #include <boost/config.hpp> |
| #include <cstring> // for memcpy |
| #include <limits> |
| #include <memory.h> |
| #include <ctime> // for time_t, time, clock_t, clock |
| #include <cstdlib> // for rand |
| #include <cstdio> // for FILE, fopen, fread, fclose |
| #include <boost/uuid/sha1.hpp> |
| //#include <boost/nondet_random.hpp> //forward declare boost::random_device |
| |
| // can't use boost::generator_iterator since boost::random number seed(Iter&, Iter) |
| // functions need a last iterator |
| //#include <boost/generator_iterator.hpp> |
| # include <boost/iterator/iterator_facade.hpp> |
| |
| #if defined(_MSC_VER) |
| #pragma warning(push) // Save warning settings. |
| #pragma warning(disable : 4996) // Disable deprecated std::fopen |
| #endif |
| |
| #ifdef BOOST_NO_STDC_NAMESPACE |
| namespace std { |
| using ::memcpy; |
| using ::time_t; |
| using ::time; |
| using ::clock_t; |
| using ::clock; |
| using ::rand; |
| using ::FILE; |
| using ::fopen; |
| using ::fread; |
| using ::fclose; |
| } //namespace std |
| #endif |
| |
| // forward declare random number generators |
| namespace boost { |
| class random_device; |
| } //namespace boost |
| |
| namespace boost { |
| namespace uuids { |
| namespace detail { |
| |
| // should this be part of Boost.Random? |
| class seed_rng |
| { |
| public: |
| typedef unsigned int result_type; |
| BOOST_STATIC_CONSTANT(bool, has_fixed_range = false); |
| //BOOST_STATIC_CONSTANT(unsigned int, min_value = 0); |
| //BOOST_STATIC_CONSTANT(unsigned int, max_value = UINT_MAX); |
| |
| public: |
| // note: rd_ intentionally left uninitialized |
| seed_rng() |
| : rd_index_(5) |
| , random_(std::fopen( "/dev/urandom", "rb" )) |
| {} |
| |
| ~seed_rng() |
| { |
| if (random_) { |
| std::fclose(random_); |
| } |
| } |
| |
| result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const |
| { |
| return (std::numeric_limits<result_type>::min)(); |
| } |
| result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const |
| { |
| return (std::numeric_limits<result_type>::max)(); |
| } |
| |
| result_type operator()() |
| { |
| if (rd_index_ >= 5) { |
| //get new digest |
| sha1_random_digest_(); |
| |
| rd_index_ = 0; |
| } |
| |
| return rd_[rd_index_++]; |
| } |
| |
| private: |
| static unsigned int * sha1_random_digest_state_() |
| { |
| // intentionally left uninitialized |
| static unsigned int state[ 5 ]; |
| return state; |
| } |
| |
| void sha1_random_digest_() |
| { |
| boost::uuids::detail::sha1 sha; |
| |
| unsigned int * ps = sha1_random_digest_state_(); |
| |
| unsigned int state[ 5 ]; |
| std::memcpy( state, ps, sizeof( state ) ); // harmless data race |
| |
| sha.process_bytes( (unsigned char const*)state, sizeof( state ) ); |
| sha.process_bytes( (unsigned char const*)&ps, sizeof( ps ) ); |
| |
| { |
| std::time_t tm = std::time( 0 ); |
| sha.process_bytes( (unsigned char const*)&tm, sizeof( tm ) ); |
| } |
| |
| { |
| std::clock_t ck = std::clock(); |
| sha.process_bytes( (unsigned char const*)&ck, sizeof( ck ) ); |
| } |
| |
| { |
| unsigned int rn[] = { std::rand(), std::rand(), std::rand() }; |
| sha.process_bytes( (unsigned char const*)rn, sizeof( rn ) ); |
| } |
| |
| { |
| // intentionally left uninitialized |
| unsigned char buffer[ 20 ]; |
| |
| if(random_) |
| { |
| std::fread( buffer, 1, 20, random_ ); |
| } |
| |
| // using an uninitialized buffer[] if fopen fails |
| // intentional, we rely on its contents being random |
| sha.process_bytes( buffer, sizeof( buffer ) ); |
| } |
| |
| { |
| // *p is intentionally left uninitialized |
| unsigned int * p = new unsigned int; |
| |
| sha.process_bytes( (unsigned char const*)p, sizeof( *p ) ); |
| sha.process_bytes( (unsigned char const*)&p, sizeof( p ) ); |
| |
| delete p; |
| } |
| |
| sha.process_bytes( (unsigned char const*)rd_, sizeof( rd_ ) ); |
| |
| unsigned int digest[ 5 ]; |
| sha.get_digest( digest ); |
| |
| for( int i = 0; i < 5; ++i ) |
| { |
| // harmless data race |
| ps[ i ] ^= digest[ i ]; |
| rd_[ i ] ^= digest[ i ]; |
| } |
| } |
| |
| private: |
| unsigned int rd_[5]; |
| int rd_index_; |
| std::FILE * random_; |
| |
| private: // make seed_rng noncopyable |
| seed_rng(seed_rng const&); |
| seed_rng& operator=(seed_rng const&); |
| }; |
| |
| // almost a copy of boost::generator_iterator |
| // but default constructor sets m_g to NULL |
| template <class Generator> |
| class generator_iterator |
| : public iterator_facade< |
| generator_iterator<Generator> |
| , typename Generator::result_type |
| , single_pass_traversal_tag |
| , typename Generator::result_type const& |
| > |
| { |
| typedef iterator_facade< |
| generator_iterator<Generator> |
| , typename Generator::result_type |
| , single_pass_traversal_tag |
| , typename Generator::result_type const& |
| > super_t; |
| |
| public: |
| generator_iterator() : m_g(NULL) {} |
| generator_iterator(Generator* g) : m_g(g), m_value((*m_g)()) {} |
| |
| void increment() |
| { |
| m_value = (*m_g)(); |
| } |
| |
| const typename Generator::result_type& |
| dereference() const |
| { |
| return m_value; |
| } |
| |
| bool equal(generator_iterator const& y) const |
| { |
| return this->m_g == y.m_g && this->m_value == y.m_value; |
| } |
| |
| private: |
| Generator* m_g; |
| typename Generator::result_type m_value; |
| }; |
| |
| // seed() seeds a random number generator with good seed values |
| |
| template <typename UniformRandomNumberGenerator> |
| inline void seed(UniformRandomNumberGenerator& rng) |
| { |
| seed_rng seed_gen; |
| generator_iterator<seed_rng> begin(&seed_gen); |
| generator_iterator<seed_rng> end; |
| rng.seed(begin, end); |
| } |
| |
| // random_device does not / can not be seeded |
| template <> |
| inline void seed<boost::random_device>(boost::random_device&) {} |
| |
| // random_device does not / can not be seeded |
| template <> |
| inline void seed<seed_rng>(seed_rng&) {} |
| |
| }}} //namespace boost::uuids::detail |
| |
| #if defined(_MSC_VER) |
| #pragma warning(pop) // Restore warnings to previous state. |
| #endif |
| |
| #endif |