]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
random code cleaned up.
authorWouter Wijngaards <wouter@nlnetlabs.nl>
Fri, 23 Feb 2007 16:27:10 +0000 (16:27 +0000)
committerWouter Wijngaards <wouter@nlnetlabs.nl>
Fri, 23 Feb 2007 16:27:10 +0000 (16:27 +0000)
git-svn-id: file:///svn/unbound/trunk@143 be551aaa-1e26-0410-a405-d3ace91eadb9

util/random.c
util/random.h [new file with mode: 0644]

index f54c06f551289ca75dbcb734216e1c2e48a507aa..76ae5a6a45004a80bfe3b9228363096230c55790 100644 (file)
@@ -3,6 +3,9 @@
  * BSD licensed, taken from binutils 2.17.
  */
 
+#include "config.h"
+#include "util/random.h"
+
 /*
  * Copyright (c) 1983 Regents of the University of California.
  * All rights reserved.
  * It was reworked for the GNU C Library by Roland McGrath.
  */
 
-/*
-
-@deftypefn Supplement {long int} random (void)
-@deftypefnx Supplement void srandom (unsigned int @var{seed})
-@deftypefnx Supplement void* initstate (unsigned int @var{seed}, void *@var{arg_state}, unsigned long @var{n})
-@deftypefnx Supplement void* setstate (void *@var{arg_state})
-
-Random number functions.  @code{random} returns a random number in the
-range 0 to @code{LONG_MAX}.  @code{srandom} initializes the random
-number generator to some starting point determined by @var{seed}
-(else, the values returned by @code{random} are always the same for each
-run of the program).  @code{initstate} and @code{setstate} allow fine-grained
-control over the state of the random number generator.
-
-@end deftypefn
-
-*/
+/**
+ * \file
+ * Thread safe random functions. Similar to random(3) and initstate(3).
+ */
 
 #include <errno.h>
 
-#if 0
-
-#include <ansidecl.h>
-#include <limits.h>
-#include <stddef.h>
-#include <stdlib.h>
-
-#else
-
+#ifndef ULONG_MAX
 #define        ULONG_MAX  ((unsigned long)(~0L))     /* 0xFFFFFFFF for 32-bits */
-#define        LONG_MAX   ((long)(ULONG_MAX >> 1))   /* 0x7FFFFFFF for 32-bits*/
-
-#ifdef __STDC__
-#  define PTR void *
-#  ifndef NULL
-#    define NULL (void *) 0
-#  endif
-#else
-#  define PTR char *
-#  ifndef NULL
-#    define NULL (void *) 0
-#  endif
 #endif
-
+#ifndef LONG_MAX
+#define        LONG_MAX   ((long)(ULONG_MAX >> 1))   /* 0x7FFFFFFF for 32-bits*/
 #endif
 
-long int random (void);
 
 /* An improved random number generation package.  In addition to the standard
    rand()/srand() like interface, this package also has a special state info
@@ -164,9 +134,10 @@ long int random (void);
 
 #define        MAX_TYPES       5       /* Max number of types above.  */
 
+/*
 static int degrees[MAX_TYPES] = { DEG_0, DEG_1, DEG_2, DEG_3, DEG_4 };
 static int seps[MAX_TYPES] = { SEP_0, SEP_1, SEP_2, SEP_3, SEP_4 };
-
+*/
 
 
 /* Initially, everything is set up as if from:
@@ -178,6 +149,7 @@ static int seps[MAX_TYPES] = { SEP_0, SEP_1, SEP_2, SEP_3, SEP_4 };
    position of the rear pointer is just
        (MAX_TYPES * (rptr - state)) + TYPE_3 == TYPE_3.  */
 
+/*
 static long int randtbl[DEG_3 + 1] =
   { TYPE_3,
       0x9a319039, 0x32d9c024, 0x9b663182, 0x5da1f342,
@@ -189,6 +161,7 @@ static long int randtbl[DEG_3 + 1] =
       0x36413f93, 0xc622c298, 0xf5a42ab8, 0x8a88d77b,
       0xf5ad9d0e, 0x8999220b, 0x27fb47b9
     };
+*/
 
 /* FPTR and RPTR are two pointers into the state info, a front and a rear
    pointer.  These two pointers are always rand_sep places aparts, as they
@@ -200,9 +173,10 @@ static long int randtbl[DEG_3 + 1] =
    in the initialization of randtbl) because the state table pointer is set
    to point to randtbl[1] (as explained below).)  */
 
+/*
 static long int *fptr = &randtbl[SEP_3 + 1];
 static long int *rptr = &randtbl[1];
-
+*/
 
 
 /* The following things are the pointer to the state information table,
@@ -215,6 +189,7 @@ static long int *rptr = &randtbl[1];
    indexing every time to find the address of the last element to see if
    the front and rear pointers have wrapped.  */
 
+/*
 static long int *state = &randtbl[1];
 
 static int rand_type = TYPE_3;
@@ -222,6 +197,7 @@ static int rand_deg = DEG_3;
 static int rand_sep = SEP_3;
 
 static long int *end_ptr = &randtbl[sizeof(randtbl) / sizeof(randtbl[0])];
+*/
 
 /* Initialize the random number generator based on the given seed.  If the
    type is the trivial no-state-information type, just remember the seed.
@@ -231,19 +207,19 @@ static long int *end_ptr = &randtbl[sizeof(randtbl) / sizeof(randtbl[0])];
    information a given number of times to get rid of any initial dependencies
    introduced by the L.C.R.N.G.  Note that the initialization of randtbl[]
    for default usage relies on values produced by this routine.  */
-void
-srandom (unsigned int x)
+static void
+ub_srandom (struct ub_randstate* s, unsigned int x)
 {
-  state[0] = x;
-  if (rand_type != TYPE_0)
+  s->state[0] = x;
+  if (s->rand_type != TYPE_0)
     {
       register long int i;
-      for (i = 1; i < rand_deg; ++i)
-       state[i] = (1103515145 * state[i - 1]) + 12345;
-      fptr = &state[rand_sep];
-      rptr = &state[0];
-      for (i = 0; i < 10 * rand_deg; ++i)
-       random();
+      for (i = 1; i < s->rand_deg; ++i)
+       s->state[i] = (1103515145 * s->state[i - 1]) + 12345;
+      s->fptr = &s->state[s->rand_sep];
+      s->rptr = &s->state[0];
+      for (i = 0; i < 10 * s->rand_deg; ++i)
+       ub_random(s);
     }
 }
 
@@ -258,112 +234,61 @@ srandom (unsigned int x)
    Note: The first thing we do is save the current state, if any, just like
    setstate so that it doesn't matter when initstate is called.
    Returns a pointer to the old state.  */
-PTR
-initstate (unsigned int seed, PTR arg_state, unsigned long n)
+int
+ub_initstate (unsigned int seed, struct ub_randstate* state, unsigned long n)
 {
-  PTR ostate = (PTR) &state[-1];
+  memset(state, 0, sizeof(state));
+  state->state = calloc(1, n);
+  if(!state->state)
+         return 0;
 
-  if (rand_type == TYPE_0)
-    state[-1] = rand_type;
-  else
-    state[-1] = (MAX_TYPES * (rptr - state)) + rand_type;
   if (n < BREAK_1)
     {
       if (n < BREAK_0)
        {
          errno = EINVAL;
-         return NULL;
+         return 0;
        }
-      rand_type = TYPE_0;
-      rand_deg = DEG_0;
-      rand_sep = SEP_0;
+      state->rand_type = TYPE_0;
+      state->rand_deg = DEG_0;
+      state->rand_sep = SEP_0;
     }
   else if (n < BREAK_2)
     {
-      rand_type = TYPE_1;
-      rand_deg = DEG_1;
-      rand_sep = SEP_1;
+      state->rand_type = TYPE_1;
+      state->rand_deg = DEG_1;
+      state->rand_sep = SEP_1;
     }
   else if (n < BREAK_3)
     {
-      rand_type = TYPE_2;
-      rand_deg = DEG_2;
-      rand_sep = SEP_2;
+      state->rand_type = TYPE_2;
+      state->rand_deg = DEG_2;
+      state->rand_sep = SEP_2;
     }
   else if (n < BREAK_4)
     {
-      rand_type = TYPE_3;
-      rand_deg = DEG_3;
-      rand_sep = SEP_3;
+      state->rand_type = TYPE_3;
+      state->rand_deg = DEG_3;
+      state->rand_sep = SEP_3;
     }
   else
     {
-      rand_type = TYPE_4;
-      rand_deg = DEG_4;
-      rand_sep = SEP_4;
+      state->rand_type = TYPE_4;
+      state->rand_deg = DEG_4;
+      state->rand_sep = SEP_4;
     }
 
-  state = &((long int *) arg_state)[1];        /* First location.  */
   /* Must set END_PTR before srandom.  */
-  end_ptr = &state[rand_deg];
-  srandom(seed);
-  if (rand_type == TYPE_0)
-    state[-1] = rand_type;
+  state->end_ptr = &state->state[state->rand_deg];
+  ub_srandom(state, seed);
+  /*
+  if (state->rand_type == TYPE_0)
+    state->state[-1] = state->rand_type;
   else
-    state[-1] = (MAX_TYPES * (rptr - state)) + rand_type;
-
-  return ostate;
-}
-
-/* Restore the state from the given state array.
-   Note: It is important that we also remember the locations of the pointers
-   in the current state information, and restore the locations of the pointers
-   from the old state information.  This is done by multiplexing the pointer
-   location into the zeroeth word of the state information. Note that due
-   to the order in which things are done, it is OK to call setstate with the
-   same state as the current state
-   Returns a pointer to the old state information.  */
-
-PTR
-setstate (PTR arg_state)
-{
-  register long int *new_state = (long int *) arg_state;
-  register int type = new_state[0] % MAX_TYPES;
-  register int rear = new_state[0] / MAX_TYPES;
-  PTR ostate = (PTR) &state[-1];
-
-  if (rand_type == TYPE_0)
-    state[-1] = rand_type;
-  else
-    state[-1] = (MAX_TYPES * (rptr - state)) + rand_type;
-
-  switch (type)
-    {
-    case TYPE_0:
-    case TYPE_1:
-    case TYPE_2:
-    case TYPE_3:
-    case TYPE_4:
-      rand_type = type;
-      rand_deg = degrees[type];
-      rand_sep = seps[type];
-      break;
-    default:
-      /* State info munged.  */
-      errno = EINVAL;
-      return NULL;
-    }
-
-  state = &new_state[1];
-  if (rand_type != TYPE_0)
-    {
-      rptr = &state[rear];
-      fptr = &state[(rear + rand_sep) % rand_deg];
-    }
-  /* Set end_ptr too.  */
-  end_ptr = &state[rand_deg];
+    state->state[-1] = (MAX_TYPES * (state->rptr - state->state)) + state->rand_type;
+    */
 
-  return ostate;
+  return 1;
 }
 
 /* If we are using the trivial TYPE_0 R.N.G., just do the old linear
@@ -378,30 +303,30 @@ setstate (PTR arg_state)
    pointer if the front one has wrapped.  Returns a 31-bit random number.  */
 
 long int
-random (void)
+ub_random (struct ub_randstate* s)
 {
-  if (rand_type == TYPE_0)
+  if (s->rand_type == TYPE_0)
     {
-      state[0] = ((state[0] * 1103515245) + 12345) & LONG_MAX;
-      return state[0];
+      s->state[0] = ((s->state[0] * 1103515245) + 12345) & LONG_MAX;
+      return s->state[0];
     }
   else
     {
       long int i;
-      *fptr += *rptr;
+      *s->fptr += *s->rptr;
       /* Chucking least random bit.  */
-      i = (*fptr >> 1) & LONG_MAX;
-      ++fptr;
-      if (fptr >= end_ptr)
+      i = (*s->fptr >> 1) & LONG_MAX;
+      ++s->fptr;
+      if (s->fptr >= s->end_ptr)
        {
-         fptr = state;
-         ++rptr;
+         s->fptr = s->state;
+         ++s->rptr;
        }
       else
        {
-         ++rptr;
-         if (rptr >= end_ptr)
-           rptr = state;
+         ++s->rptr;
+         if (s->rptr >= s->end_ptr)
+           s->rptr = s->state;
        }
       return i;
     }
diff --git a/util/random.h b/util/random.h
new file mode 100644 (file)
index 0000000..ef3e049
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * util/random.h - thread safe random generator, which is reasonably secure.
+ * 
+ * Copyright (c) 2007, NLnet Labs. All rights reserved.
+ * 
+ * This software is open source.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 
+ * Neither the name of the NLNET LABS nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef UTIL_RANDOM_H
+#define UTIL_RANDOM_H
+
+/**
+ * \file
+ * Thread safe random functions. Similar to random(3) and initstate(3).
+ */
+
+/**
+ * random state structure.
+ */
+struct ub_randstate {
+       long int* state;
+       long int* fptr;
+       long int* rptr;
+       int rand_type;
+       int rand_deg;
+       int rand_sep;
+       long int* end_ptr;
+};
+
+/**
+ * Initialize a random generator state for use 
+ * @param seed: seed value to create state contents.
+ * @param state: struct allocated by caller.
+ * @param n: size of state->state. 8, 32, 64, 128, or 256 bytes.
+ * @return false alloc failure.
+ */
+int ub_initstate(unsigned int seed, struct ub_randstate* state, 
+       unsigned long n);
+
+/**
+ * Generate next random number from the state passed along.
+ * Thread safe, so random numbers are repeatable.
+ * @param state: must have been initialised with ub_initstate.
+ * @return: random 31 bit value.
+ */
+long int ub_random(struct ub_randstate* state);
+
+#endif /* UTIL_RANDOM_H */