1258945Sroberto/*
2280849Scy * Copyright (C) 2004, 2005, 2007, 2009  Internet Systems Consortium, Inc. ("ISC")
3258945Sroberto * Copyright (C) 1999-2003  Internet Software Consortium.
4258945Sroberto *
5258945Sroberto * Permission to use, copy, modify, and/or distribute this software for any
6258945Sroberto * purpose with or without fee is hereby granted, provided that the above
7258945Sroberto * copyright notice and this permission notice appear in all copies.
8258945Sroberto *
9258945Sroberto * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10258945Sroberto * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11258945Sroberto * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12258945Sroberto * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13258945Sroberto * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14258945Sroberto * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15258945Sroberto * PERFORMANCE OF THIS SOFTWARE.
16258945Sroberto */
17258945Sroberto
18280849Scy/* $Id: random.c,v 1.28 2009/07/16 05:52:46 marka Exp $ */
19258945Sroberto
20258945Sroberto/*! \file */
21258945Sroberto
22258945Sroberto#include <config.h>
23258945Sroberto
24258945Sroberto#include <stdlib.h>
25258945Sroberto#include <time.h>		/* Required for time(). */
26258945Sroberto#ifdef HAVE_SYS_TYPES_H
27258945Sroberto#include <sys/types.h>
28258945Sroberto#endif
29258945Sroberto#ifdef HAVE_UNISTD_H
30258945Sroberto#include <unistd.h>
31258945Sroberto#endif
32258945Sroberto
33258945Sroberto#include <isc/mutex.h>
34258945Sroberto#include <isc/once.h>
35258945Sroberto#include <isc/random.h>
36258945Sroberto#include <isc/string.h>
37258945Sroberto#include <isc/util.h>
38258945Sroberto
39258945Srobertostatic isc_once_t once = ISC_ONCE_INIT;
40258945Sroberto
41258945Srobertostatic void
42258945Srobertoinitialize_rand(void)
43258945Sroberto{
44258945Sroberto#ifndef HAVE_ARC4RANDOM
45258945Sroberto	unsigned int pid = getpid();
46280849Scy
47258945Sroberto	/*
48258945Sroberto	 * The low bits of pid generally change faster.
49258945Sroberto	 * Xor them with the high bits of time which change slowly.
50258945Sroberto	 */
51258945Sroberto	pid = ((pid << 16) & 0xffff0000) | ((pid >> 16) & 0xffff);
52258945Sroberto
53258945Sroberto	srand(time(NULL) ^ pid);
54258945Sroberto#endif
55258945Sroberto}
56258945Sroberto
57258945Srobertostatic void
58258945Srobertoinitialize(void)
59258945Sroberto{
60258945Sroberto	RUNTIME_CHECK(isc_once_do(&once, initialize_rand) == ISC_R_SUCCESS);
61258945Sroberto}
62258945Sroberto
63258945Srobertovoid
64258945Srobertoisc_random_seed(isc_uint32_t seed)
65258945Sroberto{
66258945Sroberto	initialize();
67258945Sroberto
68258945Sroberto#ifndef HAVE_ARC4RANDOM
69258945Sroberto	srand(seed);
70258945Sroberto#else
71258945Sroberto	arc4random_addrandom((u_char *) &seed, sizeof(isc_uint32_t));
72258945Sroberto#endif
73258945Sroberto}
74258945Sroberto
75258945Srobertovoid
76258945Srobertoisc_random_get(isc_uint32_t *val)
77258945Sroberto{
78258945Sroberto	REQUIRE(val != NULL);
79258945Sroberto
80258945Sroberto	initialize();
81258945Sroberto
82258945Sroberto#ifndef HAVE_ARC4RANDOM
83258945Sroberto	/*
84258945Sroberto	 * rand()'s lower bits are not random.
85258945Sroberto	 * rand()'s upper bit is zero.
86258945Sroberto	 */
87280849Scy#if RAND_MAX >= 0xfffff
88280849Scy	/* We have at least 20 bits.  Use lower 16 excluding lower most 4 */
89258945Sroberto	*val = ((rand() >> 4) & 0xffff) | ((rand() << 12) & 0xffff0000);
90280849Scy#elif RAND_MAX >= 0x7fff
91280849Scy	/* We have at least 15 bits.  Use lower 10/11 excluding lower most 4 */
92280849Scy	*val = ((rand() >> 4) & 0x000007ff) | ((rand() << 7) & 0x003ff800) |
93280849Scy		((rand() << 18) & 0xffc00000);
94258945Sroberto#else
95280849Scy#error RAND_MAX is too small
96280849Scy#endif
97280849Scy#else
98258945Sroberto	*val = arc4random();
99258945Sroberto#endif
100258945Sroberto}
101258945Sroberto
102258945Srobertoisc_uint32_t
103258945Srobertoisc_random_jitter(isc_uint32_t max, isc_uint32_t jitter) {
104280849Scy	isc_uint32_t rnd;
105280849Scy
106280849Scy	REQUIRE(jitter < max || (jitter == 0 && max == 0));
107280849Scy
108258945Sroberto	if (jitter == 0)
109258945Sroberto		return (max);
110280849Scy
111280849Scy	isc_random_get(&rnd);
112280849Scy	return (max - rnd % jitter);
113258945Sroberto}
114