diff options
author | lloyd <[email protected]> | 2013-11-06 00:01:04 +0000 |
---|---|---|
committer | lloyd <[email protected]> | 2013-11-06 00:01:04 +0000 |
commit | 68a49885774fa0a78edbfeb92cb3ee608b413bc0 (patch) | |
tree | a05c042923765281e2ba62719df09251b64f491d /src | |
parent | bc25c9f1fec9945ac25492c1966fec0137f8993d (diff) |
Poll all randomness devices instead of breaking out early
Diffstat (limited to 'src')
-rw-r--r-- | src/entropy/dev_random/dev_random.cpp | 100 | ||||
-rw-r--r-- | src/entropy/dev_random/dev_random.h | 23 |
2 files changed, 38 insertions, 85 deletions
diff --git a/src/entropy/dev_random/dev_random.cpp b/src/entropy/dev_random/dev_random.cpp index 3090f9510..bfa0d76f3 100644 --- a/src/entropy/dev_random/dev_random.cpp +++ b/src/entropy/dev_random/dev_random.cpp @@ -1,6 +1,6 @@ /* -* /dev/random EntropySource -* (C) 1999-2009 Jack Lloyd +* Reader of /dev/random and company +* (C) 1999-2009,2013 Jack Lloyd * * Distributed under the terms of the Botan license */ @@ -16,53 +16,9 @@ namespace Botan { -/** -Close the device, if open -*/ -void Device_EntropySource::Device_Reader::close() - { - if(fd > 0) { ::close(fd); fd = -1; } - } +namespace { -/** -Read bytes from a device file -*/ -size_t Device_EntropySource::Device_Reader::get(byte out[], size_t length, - size_t ms_wait_time) - { - if(fd < 0) - return 0; - - if(fd >= FD_SETSIZE) - return 0; - - fd_set read_set; - FD_ZERO(&read_set); - FD_SET(fd, &read_set); - - struct ::timeval timeout; - - timeout.tv_sec = (ms_wait_time / 1000); - timeout.tv_usec = (ms_wait_time % 1000) * 1000; - - if(::select(fd + 1, &read_set, nullptr, nullptr, &timeout) < 0) - return 0; - - if(!(FD_ISSET(fd, &read_set))) - return 0; - - const ssize_t got = ::read(fd, out, length); - if(got <= 0) - return 0; - - return static_cast<size_t>(got); - } - -/** -Attempt to open a device -*/ -Device_EntropySource::Device_Reader::fd_type -Device_EntropySource::Device_Reader::open(const std::string& pathname) +int open_nonblocking(const char* pathname) { #ifndef O_NONBLOCK #define O_NONBLOCK 0 @@ -73,21 +29,22 @@ Device_EntropySource::Device_Reader::open(const std::string& pathname) #endif const int flags = O_RDONLY | O_NONBLOCK | O_NOCTTY; - return ::open(pathname.c_str(), flags); + return ::open(pathname, flags); } +} + /** Device_EntropySource constructor Open a file descriptor to each (available) device in fsnames */ -Device_EntropySource::Device_EntropySource( - const std::vector<std::string>& fsnames) +Device_EntropySource::Device_EntropySource(const std::vector<std::string>& fsnames) { for(size_t i = 0; i != fsnames.size(); ++i) { - Device_Reader::fd_type fd = Device_Reader::open(fsnames[i]); - if(fd > 0) - devices.push_back(Device_Reader(fd)); + fd_type fd = open_nonblocking(fsnames[i].c_str()); + if(fd >= 0 && fd < FD_SETSIZE) + devices.push_back(fd); } } @@ -97,7 +54,7 @@ Device_EntropySource destructor: close all open devices Device_EntropySource::~Device_EntropySource() { for(size_t i = 0; i != devices.size(); ++i) - devices[i].close(); + ::close(devices[i]); } /** @@ -105,23 +62,38 @@ Device_EntropySource::~Device_EntropySource() */ void Device_EntropySource::poll(Entropy_Accumulator& accum) { - const size_t ENTROPY_BITS_PER_BYTE = 7; + if(devices.empty()) + return; - const size_t go_get = std::min<size_t>( - accum.desired_remaining_bits() / ENTROPY_BITS_PER_BYTE, 32); + const size_t ENTROPY_BITS_PER_BYTE = 8; + const size_t MS_WAIT_TIME = 32; + const size_t READ_ATTEMPT = accum.desired_remaining_bits() / 4; - const size_t read_wait_ms = std::max<size_t>(go_get, 100); - secure_vector<byte>& io_buffer = accum.get_io_buffer(go_get); + secure_vector<byte>& io_buffer = accum.get_io_buffer(READ_ATTEMPT); + int max_fd = devices[0]; + fd_set read_set; + FD_ZERO(&read_set); for(size_t i = 0; i != devices.size(); ++i) { - size_t got = devices[i].get(&io_buffer[0], io_buffer.size(), - read_wait_ms); + FD_SET(devices[i], &read_set); + max_fd = std::max(devices[i], max_fd); + } + + struct ::timeval timeout; - if(got) + timeout.tv_sec = (MS_WAIT_TIME / 1000); + timeout.tv_usec = (MS_WAIT_TIME % 1000) * 1000; + + if(::select(max_fd + 1, &read_set, 0, 0, &timeout) < 0) + return; + + for(size_t i = 0; i != devices.size(); ++i) + { + if(FD_ISSET(devices[i], &read_set)) { + const ssize_t got = ::read(devices[i], &io_buffer[0], io_buffer.size()); accum.add(&io_buffer[0], got, ENTROPY_BITS_PER_BYTE); - break; } } } diff --git a/src/entropy/dev_random/dev_random.h b/src/entropy/dev_random/dev_random.h index 171adcc76..4386db7fe 100644 --- a/src/entropy/dev_random/dev_random.h +++ b/src/entropy/dev_random/dev_random.h @@ -27,28 +27,9 @@ class Device_EntropySource : public EntropySource Device_EntropySource(const std::vector<std::string>& fsnames); ~Device_EntropySource(); private: + typedef int fd_type; - /** - A class handling reading from a Unix character device - */ - class Device_Reader - { - public: - typedef int fd_type; - - // Does not own fd, a transient class - Device_Reader(fd_type device_fd) : fd(device_fd) {} - - void close(); - - size_t get(byte out[], size_t length, size_t ms_wait_time); - - static fd_type open(const std::string& pathname); - private: - fd_type fd; - }; - - std::vector<Device_Reader> devices; + std::vector<fd_type> devices; }; } |