blob: 49afd51c4928ccdbc0199d462f620232027f7f1f [file] [log] [blame]
// 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