WSJT-X/lib/init_random_seed.c

83 lines
1.8 KiB
C
Raw Normal View History

#include "init_random_seed.h"
#include <stdlib.h>
#include <stdint.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/time.h>
#include <unistd.h>
/* basic PRNG to use for improving the basic seed selection */
static unsigned lcg (uint64_t seed)
{
if (0 ==seed)
{
seed = UINT64_C(104729);
}
else
{
seed %= UINT64_C(4294967296);
}
seed = (seed * UINT64_C(279470273)) % UINT64_C(4294967291);
return seed % UINT64_MAX;
}
/* Generate a good PRNG seed value */
void init_random_seed(void)
{
unsigned seed = 0u;
int have_seed = 0;
// try /dev/urandom for an initial seed
int random_source;
if ((random_source = open ("/dev/urandom", O_RDONLY)) >= 0)
{
size_t random_data_length = 0;
have_seed = -1;
while (random_data_length < sizeof seed)
{
ssize_t result = read (random_source, &seed + random_data_length, (sizeof seed) - random_data_length);
if (result < 0)
{
// error, unable to read /dev/random
have_seed = 0;
}
random_data_length += result;
}
close (random_source);
}
if (!have_seed)
{
// fallback to combining the time and PID in a fairly random way
pid_t pid = getpid ();
struct timeval tv;
gettimeofday (&tv, NULL);
seed = (unsigned)(((unsigned)pid << 16)
^ (unsigned)pid
^ (unsigned)tv.tv_sec
^ (unsigned)tv.tv_usec);
seed = lcg (seed);
}
srand (seed);
}
#ifdef TEST
#include <stdio.h>
int main (int argc, char * argv[])
{
init_random_seed ();
int i, j;
int r[10][4];
for (i = 0; i < 10; ++i)
{
for (j = 0; j < 4; ++j)
{
printf ("%10d ", rand ());
}
printf ("\n");
}
return 0;
}
#endif