X-Git-Url: http://git.squeep.com/?p=reservoir_sample;a=blobdiff_plain;f=randomness.c;fp=randomness.c;h=90b375aec0a0f884c848fd8856771f5c05157cb1;hp=0000000000000000000000000000000000000000;hb=c0224807bccbd7e71e312fb4151378bff4f5a5db;hpb=4fccfc8fc60e56a5c09648e3914250f0312a0b5b diff --git a/randomness.c b/randomness.c new file mode 100644 index 0000000..90b375a --- /dev/null +++ b/randomness.c @@ -0,0 +1,67 @@ +#include +#include +#include +#include +#include +#include +#include + +#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