|
reSIProcate/rutil
9694
|
A static class that wraps the random-number generation code of your platform. More...
#include <Random.hxx>

Public Types | |
| enum | { maxLength = 512 } |
Static Public Member Functions | |
| static unsigned | getSimpleSeed () |
| Key goal is to make sure that each thread has distinct seed. | |
| static void | initialize () |
| static Data | getRandom (unsigned int numBytes) |
| static Data | getRandomHex (unsigned int numBytes) |
| static Data | getRandomBase64 (unsigned int numBytes) |
| static Data | getCryptoRandom (unsigned int numBytes) |
| static Data | getCryptoRandomHex (unsigned int numBytes) |
| static Data | getCryptoRandomBase64 (unsigned int numBytes) |
| static void | getCryptoRandom (unsigned char *buf, unsigned int numBytes) |
| static Data | getVersion4UuidUrn () |
| Returns a version 4 (random) UUID as defined in RFC 4122. | |
| static int | getRandom () |
| Returns a postive integer (31 bits) of randomness. | |
| static int | getCryptoRandom () |
| static const char * | getImplName () |
Static Private Attributes | |
| static Mutex | mMutex |
| static bool | mIsInitialized = false |
A static class that wraps the random-number generation code of your platform.
Definition at line 49 of file Random.hxx.
| anonymous enum |
| Data Random::getCryptoRandom | ( | unsigned int | numBytes | ) | [static] |
Definition at line 355 of file Random.cxx.
References getCryptoRandom(), and resip::Data::Take.
{
unsigned char* buf = new unsigned char[len];
getCryptoRandom(buf, len); // USE_SSL check is in here
return Data(Data::Take, (char*)buf, len);
}

| void Random::getCryptoRandom | ( | unsigned char * | buf, |
| unsigned int | numBytes | ||
| ) | [static] |
Definition at line 444 of file Random.cxx.
References resip::Data::data(), ErrLog, getRandom(), initialize(), and maxLength.
{
assert(numBytes < Random::maxLength+1);
#if USE_OPENSSL
initialize();
int e = RAND_bytes( (unsigned char*)buf , numBytes );
if ( e < 0 )
{
// error of some type - likely not enough rendomness to dod this
long err = ERR_get_error();
char buf[1024];
ERR_error_string_n(err,buf,sizeof(buf));
ErrLog( << buf );
assert(0);
}
#else
// !bwc! Should optimize this.
Data temp=Random::getRandom(numBytes);
memcpy(buf, temp.data(), numBytes);
#endif
}

| int Random::getCryptoRandom | ( | ) | [static] |
Definition at line 311 of file Random.cxx.
References ErrLog, getRandom(), and initialize().
Referenced by getCryptoRandom(), getCryptoRandomBase64(), getCryptoRandomHex(), and getVersion4UuidUrn().
{
initialize();
#if USE_OPENSSL
int ret;
int e = RAND_bytes( (unsigned char*)&ret , sizeof(ret) );
if ( e < 0 )
{
// error of some type - likely not enough rendomness to dod this
long err = ERR_get_error();
char buf[1024];
ERR_error_string_n(err,buf,sizeof(buf));
ErrLog( << buf );
assert(0);
}
return ret;
#else
return getRandom();
#endif
}

| Data Random::getCryptoRandomBase64 | ( | unsigned int | numBytes | ) | [static] |
Definition at line 381 of file Random.cxx.
References getCryptoRandom().
{
return Random::getCryptoRandom(numBytes).base64encode();
}

| Data Random::getCryptoRandomHex | ( | unsigned int | numBytes | ) | [static] |
Definition at line 375 of file Random.cxx.
References getCryptoRandom().
Referenced by getVersion4UuidUrn().
{
return Random::getCryptoRandom(numBytes).hex();
}

| const char * Random::getImplName | ( | ) | [static] |
Definition at line 69 of file Random.cxx.
{
#ifdef WIN32
#if defined(RESIP_RANDOM_WIN32_RTL)
return "win32_rtl";
#else
return "win32_rand";
#endif
#else // WIN32
#if defined(RESIP_RANDOM_THREAD_LOCAL)
return "posix_thread_local";
#elif defined(RESIP_RANDOM_THREAD_MUTEX)
return "posix_thread_mutex";
#else
return "posix_random";
#endif
#endif // not WIN32
}
| Data Random::getRandom | ( | unsigned int | numBytes | ) | [static] |
Definition at line 336 of file Random.cxx.
References getRandom(), initialize(), and maxLength.
{
initialize();
assert(len < Random::maxLength+1);
union
{
char cbuf[Random::maxLength+1];
unsigned int ibuf[(Random::maxLength+1)/sizeof(int)];
};
for (unsigned int count=0; count<(len+sizeof(int)-1)/sizeof(int); ++count)
{
ibuf[count] = Random::getRandom();
}
return Data(cbuf, len);
}

| int Random::getRandom | ( | ) | [static] |
Returns a postive integer (31 bits) of randomness.
Implementation is platform dependent.
Definition at line 244 of file Random.cxx.
References getSimpleSeed(), initialize(), mMutex, RANDOM_STATE_SIZE, resip::ThreadIf::tlsGetValue(), and resip::ThreadIf::tlsSetValue().
Referenced by getCryptoRandom(), getRandom(), getRandomBase64(), resip::ResipClock::getRandomFutureTimeMs(), and getRandomHex().
{
initialize();
#ifdef WIN32
int ret = 0;
#ifdef RESIP_RANDOM_WIN32_RTL
// see comment in initialize()
if (Random::RtlGenRandom)
{
unsigned long buff[1];
ULONG ulCbBuff = sizeof(buff);
if (Random::RtlGenRandom(buff,ulCbBuff))
{
// .kw. all other impls here return positive number, so do the same...
ret = buff[0] & (~(1<<31));
return ret;
}
}
// fallback to using rand() if this is a Windows version previous to XP
#endif // RESIP_RANDOM_WIN32_RTL
{
// rand() returns [0,RAND_MAX], which on Windows is 15 bits and positive
// code below gets 30bits of randomness; with bit31 and bit15
// always zero; result is always positive
assert( RAND_MAX == 0x7fff );
// WATCHOUT: on Linux, rand() returns 31bits, and assert above will fail
int r1 = rand();
int r2 = rand();
ret = (r1<<16) + r2;
}
return ret;
#else // WIN32
#if defined(RESIP_RANDOM_THREAD_LOCAL)
struct random_data *buf = (struct random_data*) ThreadIf::tlsGetValue(sRandomStateKey);
if ( buf==NULL ) {
size_t sz = sizeof(*buf)+RANDOM_STATE_SIZE;
buf = (struct random_data*) ::malloc(sz);
memset( buf, 0, sz); // .kw. strange segfaults without this
unsigned seed = getSimpleSeed();
initstate_r(seed, ((char*)buf)+sizeof(*buf), RANDOM_STATE_SIZE, buf);
ThreadIf::tlsSetValue(sRandomStateKey, buf);
}
int32_t ret;
random_r(buf, &ret);
return ret;
#elif defined(RESIP_RANDOM_THREAD_MUTEX)
int32_t ret;
{
Lock statelock(mMutex);
random_r(sRandomState, &ret);
}
return ret;
#else
// random returns [0,RAN_MAX]. On Linux, this is 31 bits and positive.
// On some platforms it might be on 15 bits, and will need to do something.
// assert( RAND_MAX == ((1<<31)-1) ); // ?slg? commented out assert since, RAND_MAX is not used in random(), it applies to rand() only
return random();
#endif // THREAD_LOCAL
#endif // WIN32
}

| Data Random::getRandomBase64 | ( | unsigned int | numBytes | ) | [static] |
Definition at line 369 of file Random.cxx.
References getRandom().
{
return Random::getRandom(numBytes).base64encode();
}

| Data Random::getRandomHex | ( | unsigned int | numBytes | ) | [static] |
Definition at line 363 of file Random.cxx.
References getRandom().
Referenced by main().
{
return Random::getRandom(numBytes).hex();
}

| unsigned Random::getSimpleSeed | ( | ) | [static] |
Key goal is to make sure that each thread has distinct seed.
Definition at line 92 of file Random.cxx.
References resip::ResipClock::getTimeMicroSec(), resip::Data::hash(), and resip::ThreadIf::selfId().
Referenced by getRandom(), and initialize().
{
// !cj! need to find a better way - use pentium random commands?
Data buffer;
{
DataStream strm(buffer);
#ifdef WIN32
strm << GetTickCount() << ":";
strm << GetCurrentProcessId() << ":";
strm << GetCurrentThreadId();
#else
// .kw. previously just used the lower 32bits of getTimeMs()
strm << ResipClock::getTimeMicroSec() << ":";
strm << getpid();
#if defined(RESIP_RANDOM_THREAD_LOCAL)
strm << ":" << ThreadIf::selfId();
#endif
#endif
}
return (unsigned int)buffer.hash();
}

| Data Random::getVersion4UuidUrn | ( | ) | [static] |
Returns a version 4 (random) UUID as defined in RFC 4122.
Definition at line 417 of file Random.cxx.
References getCryptoRandom(), getCryptoRandomHex(), and resip::Data::hex().
{
Data urn ("urn:uuid:");
urn += getCryptoRandomHex(4); // time-low
urn += "-";
urn += getCryptoRandomHex(2); // time-mid
urn += "-";
Data time_hi_and_version = Random::getCryptoRandom(2);
time_hi_and_version[0] &= 0x0f;
time_hi_and_version[0] |= 0x40;
urn += time_hi_and_version.hex();
urn += "-";
Data clock_seq_hi_and_reserved = Random::getCryptoRandom(1);
clock_seq_hi_and_reserved[0] &= 0x3f;
clock_seq_hi_and_reserved[0] |= 0x40;
urn += clock_seq_hi_and_reserved.hex();
urn += getCryptoRandomHex(1); // clock-seq-low
urn += "-";
urn += getCryptoRandomHex(6); // node
return urn;
}

| void Random::initialize | ( | ) | [static] |
ah! blocks if /dev/random on embedded sys
Definition at line 115 of file Random.cxx.
References ErrLog, getSimpleSeed(), mIsInitialized, mMutex, RANDOM_STATE_SIZE, resip::Timer::setupTimeOffsets(), resip::ThreadIf::tlsKeyCreate(), and WarningLog.
Referenced by getCryptoRandom(), and getRandom().
{
#ifdef WIN32
//#if defined(USE_SSL)
#if 0 //!dcm! - this shouldn't be per thread for win32, and this is slow. Going
//to re-work openssl initialization
if ( !Random::mIsInitialized)
{
Lock lock(mMutex);
if (!Random::mIsInitialized)
{
mIsInitialized = true;
RAND_screen ();
}
}
#else
if (!Random::mInitializer.isInitialized())
{
Lock lock(mMutex);
if (!Random::mInitializer.isInitialized())
{
Random::mInitializer.setInitialized();
unsigned seed = getSimpleSeed();
srand(seed);
#ifdef RESIP_RANDOM_WIN32_RTL
// .jjg. from http://blogs.msdn.com/michael_howard/archive/2005/01/14/353379.aspx
// srand(..) and rand() have proven to be insufficient sources of randomness,
// leading to transaction id collisions in resip.
// SystemFunction036 maps to RtlGenRandom, which is used by rand_s() (which is available
// only with the VC 8.0 runtime or later) and is the Microsoft-recommended way of getting
// a random number. This code allows that functionality to be accessed even from VC 7.1.
// However, SystemFunction036 only exists in Windows XP and later, so we may need to fallback
// to the old method using rand().
HMODULE hLib = LoadLibrary("ADVAPI32.DLL");
if (hLib)
{
Random::RtlGenRandom =
(BOOLEAN (APIENTRY *)(void*,ULONG))GetProcAddress(hLib,"SystemFunction036");
if (!Random::RtlGenRandom)
{
WarningLog(<< "Using srand(..) and rand() for random numbers");
}
}
#endif // RESIP_RANDOM_WIN32_RTL
mIsInitialized = true;
}
}
#endif // not dead code
#else // WIN32
// ?dcm? -- OpenSSL will transparently initialize PRNG if /dev/urandom is
// present. In any case, will move into OpenSSLInit
if ( !Random::mIsInitialized)
{
Lock lock(mMutex);
if (!Random::mIsInitialized)
{
mIsInitialized = true;
Timer::setupTimeOffsets();
unsigned seed = getSimpleSeed();
#if defined(RESIP_RANDOM_THREAD_LOCAL)
ThreadIf::tlsKeyCreate(sRandomStateKey, ::free);
#elif defined(RESIP_RANDOM_THREAD_MUTEX)
struct random_data *buf;
size_t sz = sizeof(*buf)+RANDOM_STATE_SIZE;
buf = (struct random_data*) ::malloc(sz);
memset( buf, 0, sz); // .kw. strange segfaults without this
initstate_r(seed, ((char*)buf)+sizeof(*buf), RANDOM_STATE_SIZE, buf);
sRandomState = buf;
#else
srandom(seed);
#endif
int fd = open("/dev/urandom", O_RDONLY);
// !ah! blocks on embedded devices -- not enough entropy.
if ( fd != -1 )
{
int s = read( fd,&seed,sizeof(seed) );
if ( s != sizeof(seed) )
{
ErrLog( << "System is short of randomness" ); // !ah! never prints
}
}
else
{
ErrLog( << "Could not open /dev/urandom" );
}
#if defined(USE_SSL)
if (fd == -1 )
{
// really bad sign - /dev/random does not exist so need to intialize
// OpenSSL some other way
// !cj! need to fix assert(0);
}
else
{
char buf[1024/8]; // size is number byes used for OpenSSL init
int s = read( fd,&buf,sizeof(buf) );
if ( s != sizeof(buf) )
{
ErrLog( << "System is short of randomness" );
}
RAND_add(buf,sizeof(buf),double(s*8));
}
#endif // SSL
if (fd != -1 )
{
::close(fd);
}
}
}
#endif // not WIN32
}

bool Random::mIsInitialized = false [static, private] |
Definition at line 91 of file Random.hxx.
Referenced by initialize().
Mutex Random::mMutex [static, private] |
Definition at line 90 of file Random.hxx.
Referenced by getRandom(), and initialize().
1.7.5.1