blob: d09fb936232ce9f64edd63aff2d56d4b2c6e8da1 [file] [log] [blame]
/**
* @file rand.c Random generator
*
* Copyright (C) 2010 Creytiv.com
*/
#include <stdlib.h>
#ifdef USE_OPENSSL
#include <openssl/rand.h>
#include <openssl/err.h>
#endif
#include <re_types.h>
#include <re_mbuf.h>
#include <re_list.h>
#include <re_tmr.h>
#include <re_sys.h>
#define DEBUG_MODULE "rand"
#define DEBUG_LEVEL 5
#include <re_dbg.h>
#ifndef RELEASE
#define RAND_DEBUG 1 /**< Enable random debugging */
#endif
static const char alphanum[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789";
#if RAND_DEBUG
static bool inited = false;
/** Check random state */
#define RAND_CHECK \
if (!inited) { \
DEBUG_WARNING("%s: random not inited\n", __REFUNC__); \
}
#else
#define RAND_CHECK if (0) {}
#endif
/**
* Initialise random number generator
*/
void rand_init(void)
{
#ifndef USE_OPENSSL
srand((uint32_t) tmr_jiffies());
#endif
#if RAND_DEBUG
inited = true;
#endif
}
/**
* Generate an unsigned 16-bit random value
*
* @return 16-bit random value
*/
uint16_t rand_u16(void)
{
RAND_CHECK;
/* Use higher-order bits (see man 3 rand) */
return rand_u32() >> 16;
}
/**
* Generate an unsigned 32-bit random value
*
* @return 32-bit random value
*/
uint32_t rand_u32(void)
{
uint32_t v;
RAND_CHECK;
#ifdef USE_OPENSSL
v = 0;
if (RAND_bytes((unsigned char *)&v, sizeof(v)) <= 0) {
DEBUG_WARNING("RAND_bytes() error: %i\n",
ERR_GET_REASON(ERR_get_error()));
ERR_clear_error();
}
#elif defined(HAVE_ARC4RANDOM)
v = arc4random();
#elif defined(WIN32)
v = (rand() << 16) + rand(); /* note: 16-bit rand */
#else
v = rand();
#endif
return v;
}
/**
* Generate an unsigned 64-bit random value
*
* @return 64-bit random value
*/
uint64_t rand_u64(void)
{
RAND_CHECK;
return (uint64_t)rand_u32()<<32 | rand_u32();
}
/**
* Generate a random printable character
*
* @return Random printable character
*/
char rand_char(void)
{
char s[2];
RAND_CHECK;
rand_str(s, sizeof(s));
return s[0];
}
/**
* Generate a string of random characters
*
* @param str Pointer to string
* @param size Size of string
*/
void rand_str(char *str, size_t size)
{
size_t i;
if (!str || !size)
return;
RAND_CHECK;
--size;
rand_bytes((uint8_t *)str, size);
for (i=0; i<size; i++)
str[i] = alphanum[((uint8_t)str[i]) % (sizeof(alphanum)-1)];
str[size] = '\0';
}
/**
* Generate a set of random bytes
*
* @param p Pointer to buffer
* @param size Size of buffer
*/
void rand_bytes(uint8_t *p, size_t size)
{
#ifdef USE_OPENSSL
if (RAND_bytes(p, (int)size) <= 0) {
DEBUG_WARNING("RAND_bytes() error: %i\n",
ERR_GET_REASON(ERR_get_error()));
ERR_clear_error();
}
#elif defined (HAVE_ARC4RANDOM)
arc4random_buf(p, size);
#else
while (size--) {
p[size] = rand_u32();
}
#endif
}