RandomDeviceCombined (string path) : fd(0), pos(0), rseed(0) { fd = TRI_OPEN(path.c_str(), O_RDONLY); if (fd < 0) { THROW_INTERNAL_ERROR("cannot open random source '" + path + "'"); } // .............................................................................. // Set the random number generator file to be non-blocking (not for windows) // .............................................................................. { #ifdef _WIN32 abort(); #else long flags = fcntl(fd, F_GETFL, 0); bool ok = (flags >= 0); if (ok) { flags = fcntl(fd, F_SETFL, flags | O_NONBLOCK); ok = (flags >= 0); } if (! ok) { THROW_INTERNAL_ERROR("cannot switch random source '" + path + "' to non-blocking"); } #endif } fillBuffer(); }
void fillBuffer () { size_t n = sizeof(buffer); char* ptr = reinterpret_cast<char*>(&buffer); while (0 < n) { ssize_t r = TRI_READ(fd, ptr, n); if (r == 0) { LOGGER_FATAL << "read on random device failed: nothing read"; THROW_INTERNAL_ERROR("read on random device failed"); } else if (errno == EWOULDBLOCK) { LOGGER_INFO << "not enough entropy (got " << (sizeof(buffer) - n) << " bytes), switching to pseudo-random"; break; } else if (r < 0) { LOGGER_FATAL << "read on random device failed: " << strerror(errno); THROW_INTERNAL_ERROR("read on random device failed"); } ptr += r; n -= r; rseed = buffer[0]; LOGGER_TRACE << "using seed " << rseed; } if (0 < n) { unsigned long seed = (unsigned long) time(0); #ifdef TRI_HAVE_GETTIMEOFDAY struct timeval tv; int result = gettimeofday(&tv, 0); seed ^= static_cast<unsigned long>(tv.tv_sec); seed ^= static_cast<unsigned long>(tv.tv_usec); seed ^= static_cast<unsigned long>(result); #endif seed ^= static_cast<unsigned long>(Thread::currentProcessId()); mersenneDevice.seed(rseed ^ (uint32_t) seed); while (0 < n) { *ptr++ = randomGenerator(); --n; } } pos = 0; }
RandomDeviceWin32 () : cryptoHandle(0), pos(0) { BOOL result; result = CryptAcquireContext(&cryptoHandle, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT); if (cryptoHandle == 0 || result == FALSE) { THROW_INTERNAL_ERROR("cannot create cryptographic windows handle"); } fillBuffer(); }
int32_t interval (int32_t left, int32_t right) { MUTEX_LOCKER(RandomLock); if (uniformInteger == 0) { THROW_INTERNAL_ERROR("unknown random generator"); } return uniformInteger->random(left, right); }
RandomDeviceCombined (string path) : interval(0, UINT32_MAX), randomGenerator(mersenneDevice, interval), fd(0), pos(0), rseed(0) { fd = TRI_OPEN(path.c_str(), O_RDONLY); if (fd < 0) { THROW_INTERNAL_ERROR("cannot open random source '" + path + "'"); } if (! TRI_SetNonBlockingSocket(fd)) { THROW_INTERNAL_ERROR("cannot switch random source '" + path + "' to non-blocking"); } fillBuffer(); }
RandomDeviceDirect (string path) : fd(1), pos(0) { fd = TRI_OPEN(path.c_str(), O_RDONLY); if (fd < 0) { THROW_INTERNAL_ERROR("cannot open random source '" + path + "'"); } fillBuffer(); }
uint32_t interval (uint32_t left, uint32_t right) { MUTEX_LOCKER(RandomLock); if (uniformInteger == 0) { THROW_INTERNAL_ERROR("unknown random generator"); } int32_t l = left + INT32_MIN; int32_t r = right + INT32_MIN; return uniformInteger->random(l, r) - INT32_MIN; }
void fillBuffer () { size_t n = sizeof(buffer); char* ptr = reinterpret_cast<char*>(&buffer); while (0 < n) { ssize_t r = TRI_READ(fd, ptr, n); if (r == 0) { LOGGER_FATAL << "read on random device failed: nothing read"; THROW_INTERNAL_ERROR("read on random device failed"); } else if (r < 0) { LOGGER_FATAL << "read on random device failed: " << strerror(errno); THROW_INTERNAL_ERROR("read on random device failed"); } ptr += r; n -= r; } pos = 0; }
random_e selectVersion (random_e newVersion) { MUTEX_LOCKER(RandomLock); random_e oldVersion = version; version = newVersion; if (uniformInteger != 0) { delete uniformInteger; uniformInteger = 0; } switch (version) { case RAND_MERSENNE: uniformInteger = new UniformIntegerMersenne; break; case RAND_RANDOM: if (RandomHelper::randomDevice == 0) { RandomHelper::randomDevice = new RandomHelper::RandomDeviceDirect<1024>("/dev/random"); } uniformInteger = new UniformIntegerRandom(RandomHelper::randomDevice); break; case RAND_URANDOM: if (RandomHelper::urandomDevice == 0) { RandomHelper::urandomDevice = new RandomHelper::RandomDeviceDirect<1024>("/dev/urandom"); } uniformInteger = new UniformIntegerRandom(RandomHelper::urandomDevice); break; case RAND_COMBINED: if (RandomHelper::combinedDevice == 0) { RandomHelper::combinedDevice = new RandomHelper::RandomDeviceCombined<600>("/dev/random"); } uniformInteger = new UniformIntegerRandom(RandomHelper::combinedDevice); break; default: THROW_INTERNAL_ERROR("unknown random generator"); } return oldVersion; }