aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorlloyd <[email protected]>2013-11-06 00:01:04 +0000
committerlloyd <[email protected]>2013-11-06 00:01:04 +0000
commit68a49885774fa0a78edbfeb92cb3ee608b413bc0 (patch)
treea05c042923765281e2ba62719df09251b64f491d /src
parentbc25c9f1fec9945ac25492c1966fec0137f8993d (diff)
Poll all randomness devices instead of breaking out early
Diffstat (limited to 'src')
-rw-r--r--src/entropy/dev_random/dev_random.cpp100
-rw-r--r--src/entropy/dev_random/dev_random.h23
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;
};
}