blocxx

RandomNumber.cpp

Go to the documentation of this file.
00001 /*******************************************************************************
00002 * Copyright (C) 2005, Vintela, Inc. All rights reserved.
00003 * Copyright (C) 2006, Novell, Inc. All rights reserved.
00004 * 
00005 * Redistribution and use in source and binary forms, with or without
00006 * modification, are permitted provided that the following conditions are met:
00007 * 
00008 *     * Redistributions of source code must retain the above copyright notice,
00009 *       this list of conditions and the following disclaimer.
00010 *     * Redistributions in binary form must reproduce the above copyright
00011 *       notice, this list of conditions and the following disclaimer in the
00012 *       documentation and/or other materials provided with the distribution.
00013 *     * Neither the name of 
00014 *       Vintela, Inc., 
00015 *       nor Novell, Inc., 
00016 *       nor the names of its contributors or employees may be used to 
00017 *       endorse or promote products derived from this software without 
00018 *       specific prior written permission.
00019 * 
00020 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00021 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00022 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00023 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00024 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00025 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00026 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00027 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00028 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00029 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00030 * POSSIBILITY OF SUCH DAMAGE.
00031 *******************************************************************************/
00032 
00033 
00039 #include "blocxx/BLOCXX_config.h"
00040 #include "blocxx/RandomNumber.hpp"
00041 #include "blocxx/Assertion.hpp"
00042 #include "blocxx/ThreadOnce.hpp"
00043 #include "blocxx/Mutex.hpp"
00044 #include "blocxx/MutexLock.hpp"
00045 #include "blocxx/GlobalMutex.hpp"
00046 #include <fstream>
00047 #include <sys/types.h>
00048 
00049 #ifdef BLOCXX_HAVE_UNISTD_H
00050 #include <unistd.h>
00051 #endif
00052 
00053 #ifdef BLOCXX_HAVE_SYS_TIME_H
00054 #include <sys/time.h>
00055 #endif
00056 
00057 #include <stdlib.h>
00058 #include <time.h>
00059 
00060 namespace BLOCXX_NAMESPACE
00061 {
00062 
00064 namespace
00065 {
00066 OnceFlag guard = BLOCXX_ONCE_INIT;
00067 unsigned int seed = 0;
00068 }
00069 
00071 RandomNumber::RandomNumber(Int32 lowVal, Int32 highVal)
00072 : m_lowVal(lowVal), m_highVal(highVal)
00073 {
00074    if (lowVal > highVal)
00075    {
00076       m_lowVal = highVal;
00077       m_highVal = lowVal;
00078    }
00079    callOnce(guard, &initRandomness);
00080 }
00081    
00083 void
00084 RandomNumber::initRandomness()
00085 {
00086 #ifdef BLOCXX_WIN32
00087    time_t timeval = ::time(NULL);
00088    seed = timeval;
00089 #else
00090    // use the time as part of the seed
00091    struct timeval tv;
00092    gettimeofday(&tv, 0);
00093    // try to get something from the kernel
00094    std::ifstream infile("/dev/urandom", std::ios::in);
00095    if (!infile)
00096    {
00097       infile.open("/dev/random", std::ios::in);
00098    }
00099    // don't initialize this, we may get random stack
00100    // junk in case infile isn't usable.
00101    unsigned int dev_rand_input;
00102    if (infile)
00103    {
00104       infile.read(reinterpret_cast<char*>(&dev_rand_input), sizeof(dev_rand_input));
00105       infile.close();
00106    }
00107    // Build the seed. Take into account our pid and uid.
00108    seed = dev_rand_input ^ (getpid() << 16) ^ getuid() ^ tv.tv_sec ^ tv.tv_usec;
00109 #endif
00110 #ifdef BLOCXX_HAVE_SRANDOM
00111    srandom(seed);
00112 #else
00113    srand(seed);
00114 #endif
00115 }
00116 
00118 void
00119 RandomNumber::saveRandomState()
00120 {
00121    // Do nothing. This function is so that RandomNumber has the same interface as CryptographicRandomNumber
00122 }
00123 
00124 namespace
00125 {
00126 GlobalMutex g_guard = BLOCXX_GLOBAL_MUTEX_INIT();
00127 }
00129 Int32
00130 RandomNumber::getNextNumber()
00131 {
00132    MutexLock lock(g_guard);
00133 #ifdef BLOCXX_HAVE_RANDOM
00134    return m_lowVal + (random() % (m_highVal - m_lowVal + 1));
00135 #else
00136    return m_lowVal + (rand() % (m_highVal - m_lowVal + 1));
00137 #endif
00138 }
00139 
00140 } // end namespace BLOCXX_NAMESPACE
00141