Use poll() when possible to gather Unix randomness entropy
authorRichard Levitte <levitte@openssl.org>
Tue, 27 Jun 2006 06:31:34 +0000 (06:31 +0000)
committerRichard Levitte <levitte@openssl.org>
Tue, 27 Jun 2006 06:31:34 +0000 (06:31 +0000)
CHANGES
crypto/rand/rand_unix.c

diff --git a/CHANGES b/CHANGES
index 8e7cf61..92f912b 100644 (file)
--- a/CHANGES
+++ b/CHANGES
 
  Changes between 0.9.7j and 0.9.7k  [xx XXX xxxx]
 
+  *) Change the Unix randomness entropy gathering to use poll() when
+     possible instead of select(), since the latter has some
+     undesirable limitations.
+     [Darryl Miles via Richard Levitte]
+
   *) Disable rogue ciphersuites:
 
       - SSLv2 0x08 0x00 0x80 ("RC4-64-MD5")
index c4838b6..bf0bfa7 100644 (file)
 #include <unistd.h>
 #include <time.h>
 
+#if defined(OPENSSL_SYS_LINUX)
+ /* lets use poll() */
+# include <sys/poll.h>
+# define IOWAIT_VARS           struct pollfd pset; struct timeval t
+# define IOWAIT_INIT(f, t)     do {                                    \
+                                       pset.fd = (f);                  \
+                                       pset.events = POLLIN;           \
+                                       pset.revents = 0;               \
+                                       (t)->tv_sec = 0;                \
+                                       (t)->tv_usec = 10*1000;         \
+                                       /* Spend 10ms on each file. */  \
+                               } while(0)
+# define IOWAIT_FUNC(f, t)     poll(&pset, 1, ((t)->tv_sec * 1000) + ((t)->tv_usec / 1000))
+# define IOWAIT_CHECK(f)       ((pset.revents & POLLIN) != 0)
+#else
+ /* lets use select() */
+
+ /* For each platform we could do with making a guess at
+  *  how many FDs we support.  With glibc/Linux its possible
+  *  to use FD_SETSIZE directly, but this may not be very
+  *  portable. Another options was to use _POSIX_OPEN_MAX
+  *  but that value is a tad dull on modern hardware.  So
+  *  I ended up trying sizeof(fd_set)*8 which should be
+  *  closer to the real value.
+  * If this causes a problem on your platform because we
+  *  can not guess correctly then set it to zero.
+  */
+# if defined(FD_SETSIZE)
+#  define IOWAIT_FD_SETSIZE    (FD_SETSIZE)
+# else
+  /* fallback method */
+#  define IOWAIT_FD_SETSIZE    (sizeof(fd_set) * 8)
+# endif
+# define IOWAIT_VARS           fd_set fset; struct timeval t
+# define IOWAIT_INIT(f, t)     do {                                    \
+                                       FD_ZERO(&fset);                 \
+                                       if(IOWAIT_FD_SETSIZE > 0        \
+                                          && (f) >= IOWAIT_FD_SETSIZE) \
+                                               { break; }              \
+                                       FD_SET((f), &fset);             \
+                                       (t)->tv_sec = 0;                \
+                                       (t)->tv_usec = 10*1000;         \
+                                       /* Spend 10ms on each file. */  \
+                               } while(0)
+# define IOWAIT_FUNC(f, t)     select((f)+1,&fset,NULL,NULL,(t))
+# define IOWAIT_CHECK(f)       FD_ISSET((f), &fset)
+#endif
+
 #ifdef __OpenBSD__
 int RAND_poll(void)
 {
@@ -185,11 +233,9 @@ int RAND_poll(void)
 #endif
                        )) >= 0)
                        {
-                       struct timeval t = { 0, 10*1000 }; /* Spend 10ms on
-                                                             each file. */
                        int r;
                        unsigned int j;
-                       fd_set fset;
+                       IOWAIT_VARS;
                        struct stat *st=&randomstats[i];
 
                        /* Avoid using same input... Used to be O_NOFOLLOW
@@ -215,13 +261,12 @@ int RAND_poll(void)
                                else if (r == 0)
                                        snooze(t.tv_usec);
 #else
-                               FD_ZERO(&fset);
-                               FD_SET(fd, &fset);
+                               IOWAIT_INIT(fd, &t);
                                r = -1;
 
-                               if (select(fd+1,&fset,NULL,NULL,&t) < 0)
+                               if (IOWAIT_FUNC(fd, &t) < 0)
                                        t.tv_usec=0;
-                               else if (FD_ISSET(fd, &fset))
+                               else if (IOWAIT_CHECK(fd))
                                        {
                                        r=read(fd,(unsigned char *)tmpbuf+n,
                                               ENTROPY_NEEDED-n);