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