diff --git a/src/Context.cc b/src/Context.cc index d0b67d18..7cda18da 100644 --- a/src/Context.cc +++ b/src/Context.cc @@ -161,7 +161,7 @@ Context::Context(bool standalone, throw DL_ABORT_EX("Option processing failed"); } } - SimpleRandomizer::init(); + SimpleRandomizer::getInstance()->init(); #ifdef ENABLE_BITTORRENT bittorrent::generateStaticPeerId(op->get(PREF_PEER_ID_PREFIX)); #endif // ENABLE_BITTORRENT diff --git a/src/SimpleRandomizer.cc b/src/SimpleRandomizer.cc index 9754d6cb..89e0ffd1 100644 --- a/src/SimpleRandomizer.cc +++ b/src/SimpleRandomizer.cc @@ -38,6 +38,7 @@ #include #include #include +#include #include "a2time.h" @@ -56,7 +57,8 @@ const std::unique_ptr& SimpleRandomizer::getInstance() void SimpleRandomizer::init() { #ifndef __MINGW32__ - srandom(time(nullptr)^getpid()); + // Just in case std::random_device() is fixed, add time and pid too. + eng_.seed(std::random_device()()^time(nullptr)^getpid()); #endif // !__MINGW32__ } @@ -90,7 +92,7 @@ long int SimpleRandomizer::getRandomNumber() } return val; #else // !__MINGW32__ - return random(); + return eng_(); #endif // !__MINGW32__ } @@ -99,15 +101,18 @@ long int SimpleRandomizer::getMaxRandomNumber() #ifdef __MINGW32__ return INT32_MAX; #else // !__MINGW32__ - // TODO Warning: The maximum value of random() in some sytems (e.g., - // Solaris and openbsd) is (2**31)-1. - return RAND_MAX; + return eng_.max(); #endif // !__MINGW32__ } long int SimpleRandomizer::getRandomNumber(long int to) { + assert(to > 0); +#ifdef __MINGW32__ return getRandomNumber() % to; +#else // !__MINGW32__ + return std::uniform_int_distribution(0, to - 1)(eng_); +#endif // !__MINGW32__ } long int SimpleRandomizer::operator()(long int to) @@ -122,16 +127,19 @@ void SimpleRandomizer::getRandomBytes(unsigned char *buf, size_t len) throw std::bad_alloc(); } #else - while (len) { - // If RAND_MAX is less than 2**16-1, we are in trouble. - union { - uint16_t r; - uint8_t b[2]; - } r = { (uint16_t)(random() & 0xffffu) }; - for (auto i = 0; i < 2 && len; ++i, --len) { - *buf++ = r.b[i]; - } + uint32_t val; + size_t q = len / sizeof(val); + size_t r = len % sizeof(val); + auto gen = std::bind(std::uniform_int_distribution + (0, std::numeric_limits::max()), + eng_); + for(; q > 0; --q) { + val = gen(); + memcpy(buf, &val, sizeof(val)); + buf += sizeof(val); } + val = gen(); + memcpy(buf, &val, r); #endif } diff --git a/src/SimpleRandomizer.h b/src/SimpleRandomizer.h index 7e0afad9..fce68696 100644 --- a/src/SimpleRandomizer.h +++ b/src/SimpleRandomizer.h @@ -38,6 +38,7 @@ #include "Randomizer.h" #include +#include #ifdef __MINGW32__ # include @@ -51,17 +52,19 @@ private: #ifdef __MINGW32__ HCRYPTPROV cryProvider_; -#endif //__MINGW32__ +#else // !__MINGW32__ + std::minstd_rand eng_; +#endif //!__MINGW32__ SimpleRandomizer(); public: static const std::unique_ptr& getInstance(); - static void init(); - virtual ~SimpleRandomizer(); + void init(); + virtual long int getRandomNumber() CXX11_OVERRIDE; virtual long int getMaxRandomNumber() CXX11_OVERRIDE;