seed srand from /dev/urandom when possible
Roderick Schertler [Wed, 9 Sep 1998 23:52:48 +0000 (19:52 -0400)]
Message-ID: <20567.905399568@eeyore.ibcinc.com>

p4raw-id: //depot/perl@1847

pod/perlfunc.pod
pp.c

index b20981d..a300f4a 100644 (file)
@@ -3618,7 +3618,8 @@ root of C<$_>.
 =item srand
 
 Sets the random number seed for the C<rand()> operator.  If EXPR is
-omitted, uses a semi-random value based on the current time and process
+omitted, uses a semi-random value supplied by the kernel (if it supports
+the F</dev/urandom> device) or based on the current time and process
 ID, among other things.  In versions of Perl prior to 5.004 the default
 seed was just the current C<time()>.  This isn't a particularly good seed,
 so many old programs supply their own seed value (often C<time ^ $$> or
diff --git a/pp.c b/pp.c
index a148341..e1c9d66 100644 (file)
--- a/pp.c
+++ b/pp.c
@@ -1638,21 +1638,50 @@ seed(void)
 #define   SEED_C5      26107
 
     dTHR;
+#ifndef PERL_NO_DEV_RANDOM
+    int fd;
+#endif
     U32 u;
 #ifdef VMS
 #  include <starlet.h>
     /* when[] = (low 32 bits, high 32 bits) of time since epoch
      * in 100-ns units, typically incremented ever 10 ms.        */
     unsigned int when[2];
+#else
+#  ifdef HAS_GETTIMEOFDAY
+    struct timeval when;
+#  else
+    Time_t when;
+#  endif
+#endif
+
+/* This test is an escape hatch, this symbol isn't set by Configure. */
+#ifndef PERL_NO_DEV_RANDOM
+#ifndef PERL_RANDOM_DEVICE
+   /* /dev/random isn't used by default because reads from it will block
+    * if there isn't enough entropy available.  You can compile with
+    * PERL_RANDOM_DEVICE to it if you'd prefer Perl to block until there
+    * is enough real entropy to fill the seed. */
+#  define PERL_RANDOM_DEVICE "/dev/urandom"
+#endif
+    fd = PerlLIO_open(PERL_RANDOM_DEVICE, 0);
+    if (fd != -1) {
+       if (PerlLIO_read(fd, &u, sizeof u) != sizeof u)
+           u = 0;
+       PerlLIO_close(fd);
+       if (u)
+           return u;
+    }
+#endif
+
+#ifdef VMS
     _ckvmssts(sys$gettim(when));
     u = (U32)SEED_C1 * when[0] + (U32)SEED_C2 * when[1];
 #else
 #  ifdef HAS_GETTIMEOFDAY
-    struct timeval when;
     gettimeofday(&when,(struct timezone *) 0);
     u = (U32)SEED_C1 * when.tv_sec + (U32)SEED_C2 * when.tv_usec;
 #  else
-    Time_t when;
     (void)time(&when);
     u = (U32)SEED_C1 * when;
 #  endif