From: Wouter Wijngaards Date: Fri, 23 Feb 2007 16:27:10 +0000 (+0000) Subject: random code cleaned up. X-Git-Tag: release-0.1~28 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=64f8b35c9eb250a0630316a53f8b166b78575f9b;p=thirdparty%2Funbound.git random code cleaned up. git-svn-id: file:///svn/unbound/trunk@143 be551aaa-1e26-0410-a405-d3ace91eadb9 --- diff --git a/util/random.c b/util/random.c index f54c06f55..76ae5a6a4 100644 --- a/util/random.c +++ b/util/random.c @@ -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. @@ -39,53 +42,20 @@ * 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 -#if 0 - -#include -#include -#include -#include - -#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 index 000000000..ef3e0499c --- /dev/null +++ b/util/random.h @@ -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 */