83 lines
		
	
	
		
			1.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			83 lines
		
	
	
		
			1.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
|   | #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
 |