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