+// initialise the random generator
+static void initrandom(char *source)
+{
+ static char path[sizeof(config->random_device)] = "*undefined*";
+
+ // reinitialise only if we are forced to do so or if the config has changed
+ if (source && !strncmp(path, source, sizeof(path)))
+ return;
+
+ // close previous source, if any
+ if (rand_fd >= 0) close(rand_fd);
+
+ rand_fd = -1;
+
+ if (source)
+ {
+ // register changes
+ snprintf(path, sizeof(path), "%s", source);
+
+ if (*path == '/')
+ {
+ rand_fd = open(path, O_RDONLY|O_NONBLOCK);
+ if (rand_fd < 0)
+ LOG(0, 0, 0, "Error opening the random device %s: %s\n",
+ path, strerror(errno));
+ }
+ }
+
+ // no source: seed prng
+ {
+ unsigned seed = time_now ^ getpid();
+ LOG(4, 0, 0, "Seeding the pseudo random generator: %u\n", seed);
+ srand(seed);
+ }
+}
+
+// fill buffer with random data
+void random_data(uint8_t *buf, int len)
+{
+ int n = 0;
+
+ CSTAT(random_data);
+ if (rand_fd >= 0)
+ {
+ n = read(rand_fd, buf, len);
+ if (n >= len) return;
+ if (n < 0)
+ {
+ if (errno != EAGAIN)
+ {
+ LOG(0, 0, 0, "Error reading from random source: %s\n",
+ strerror(errno));
+
+ // fall back to rand()
+ initrandom(0);
+ }
+
+ n = 0;
+ }
+ }
+
+ // append missing data
+ while (n < len)
+ // not using the low order bits from the prng stream
+ buf[n++] = (rand() >> 4) & 0xff;
+}