--- /dev/null
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "randomness.h"
+#include "notify.h"
+
+static int randomness_fd_ = -1;
+
+int randomness_init(const char *filename) {
+ if (filename != NULL) {
+ randomness_fd_ = open(filename, O_RDONLY);
+ if (randomness_fd_ == -1) {
+ NOTIFY_ERROR("%s('%s'):%s", "open", filename, strerror(errno));
+ return -1;
+ }
+ NOTIFY_DEBUG("reading randomness from '%s', fd:%d", filename, randomness_fd_);
+ } else {
+ if (randomness_fd_ != -1) {
+ close(randomness_fd_);
+ randomness_fd_ = -1;
+ }
+ srand48(time(NULL) ^ getpid());
+ NOTIFY_DEBUG("reading randomness from system PRNG");
+ }
+
+ return 0;
+}
+
+/*
+ Room for improvement: constrain bits of randomness consumed, based on #limit
+ Also maybe read chunks of randomness at a time
+ */
+unsigned long randomness_upto_inclusive(unsigned long limit) {
+ unsigned long randomness;
+
+ if (limit == 0)
+ return 0;
+
+ if (randomness_fd_ != -1) {
+ ssize_t len;
+
+ do {
+ len = read(randomness_fd_, &randomness, sizeof randomness);
+ } while (len == -1 && (errno == EINTR || errno == EAGAIN));
+ if (len == sizeof randomness) {
+ randomness %= limit + 1;
+ NOTIFY_DEBUG("randomness:%lu", randomness);
+ return randomness;
+ }
+ NOTIFY_ERROR("%s(%d, %zu):%zd:%s",
+ "read", randomness_fd_, sizeof randomness, len,
+ (len < 0) ? strerror(errno) : ( (len == 0) ? "EOF" : "not enough read" )
+ );
+ }
+
+ /* fall back to pseudo-randomness if read failed */
+ randomness = mrand48();
+ randomness %= limit + 1;
+
+ NOTIFY_DEBUG("randomness:%lu", randomness);
+ return randomness;
+}
\ No newline at end of file