Split code into modules, handle USR1, minor fixes.
[reservoir_sample] / randomness.c
diff --git a/randomness.c b/randomness.c
new file mode 100644 (file)
index 0000000..90b375a
--- /dev/null
@@ -0,0 +1,67 @@
+#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