VirtualBox

Changeset 11523 in vbox for trunk


Ignore:
Timestamp:
Aug 20, 2008 8:48:52 PM (16 years ago)
Author:
vboxsync
Message:

iprt: Implemented the /dev/urandom base random generator as a RTRAND opaque. Made the simple RTRand API just serve as a wrapper using the RTRandAdv API with a global RTRAND handle.

Location:
trunk
Files:
2 added
1 deleted
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/iprt/rand.h

    r11347 r11523  
    140140
    141141/**
     142 * Create an instance of the default non-pseudo random number generator.
     143 *
     144 * @returns IPRT status code.
     145 * @retval  VERR_NOT_SUPPORTED on platforms which doesn't have this feature
     146 *          (Windows & OS/2).
     147 * @param   phRand      Where to store the handle to the generator.
     148 *
     149 * @remarks Think /dev/urandom.
     150 */
     151RTDECL(int) RTRandAdvCreateNonPseudo(PRTRAND phRand) RT_NO_THROW;
     152
     153/**
     154 * Create an instance of the default pure non-pseudo random number generator.
     155 *
     156 * Don't use this unless you seriously need good random numbers because most
     157 * systems will have will have problems producing sufficient randomness for this
     158 * and you'll end up blocking.
     159 *
     160 * @returns IPRT status code.
     161 * @retval  VERR_NOT_SUPPORTED on platforms which doesn't have this feature
     162 *          (Windows & OS/2).
     163 * @param   phRand      Where to store the handle to the generator.
     164 *
     165 * @remarks Think /dev/random.
     166 */
     167RTDECL(int) RTRandAdvCreatePureNonPseudo(PRTRAND phRand) RT_NO_THROW;
     168
     169/**
    142170 * Destroys a random number generator.
    143171 *
     
    155183 *
    156184 * @returns IPRT status code.
     185 * @retval  VERR_NOT_SUPPORTED if it isn't a pseudo generator.
     186 *
    157187 * @param   hRand       Handle to the random number generator.
    158188 * @param   u64Seed     Seed.
    159189 */
    160190RTDECL(int) RTRandAdvSeed(RTRAND hRand, uint64_t u64Seed) RT_NO_THROW;
     191
     192/**
     193 * Save the current state of a pseudo generator.
     194 *
     195 * This can be use to save the state so it can later be resumed at the same
     196 * position.
     197 *
     198 * @returns IPRT status code.
     199 * @retval  VINF_SUCCESS on success. *pcbState contains the length of the
     200 *          returned string and pszState contains the state string.
     201 * @retval  VERR_BUFFER_OVERFLOW if the supplied buffer is too small. *pcbState
     202 *          will contain the necessary buffer size.
     203 * @retval  VERR_NOT_SUPPORTED by non-psuedo generators.
     204 *
     205 * @param   hRand       Handle to the random number generator.
     206 * @param   pszState    Where to store the state. The returned string will be
     207 *                      null terminated and printable.
     208 * @param   pcbState    The size of the buffer pszState points to on input, the
     209 *                      size required / used on return (including the
     210 *                      terminator, thus the 'cb' instead of 'cch').
     211 */
     212RTDECL(int) RTRandAdvSaveState(RTRAND hRand, char *pszState, size_t *pcbState) RT_NO_THROW;
     213
     214/**
     215 * Restores the state of a pseudo generator.
     216 *
     217 * The state must've been obtained using RTRandAdvGetState.
     218 *
     219 * @returns IPRT status code.
     220 * @retval  VERR_PARSE_ERROR if the state string is malformed.
     221 * @retval  VERR_NOT_SUPPORTED by non-psuedo generators.
     222 *
     223 * @param   hRand       Handle to the random number generator.
     224 * @param   pszState    The state to load.
     225 */
     226RTDECL(int) RTRandAdvRestoreState(RTRAND hRand, char const *pszState) RT_NO_THROW;
    161227
    162228/**
  • trunk/src/VBox/Runtime/Makefile.kmk

    r11352 r11523  
    282282
    283283RuntimeR3_SOURCES.win = \
    284         generic/rand-stubs-generic.cpp \
    285284        generic/RTDirQueryInfo-generic.cpp \
    286285        generic/RTDirSetTimes-generic.cpp \
     286        generic/RTMpGetCurFrequency-generic.cpp \
     287        generic/RTMpGetMaxFrequency-generic.cpp \
     288        generic/RTRandAdvCreateNonPseudo-generic.cpp \
     289        generic/RTRandAdvCreatePureNonPseudo-generic.cpp \
    287290        generic/semnoint-generic.cpp \
    288291        generic/semsrw-generic.cpp \
    289         generic/RTMpGetCurFrequency-generic.cpp \
    290         generic/RTMpGetMaxFrequency-generic.cpp \
    291292        nt/RTErrConvertFromNtStatus.cpp \
    292293        r3/posix/env-posix.cpp \
     
    366367RuntimeR3_SOURCES.os2   = \
    367368        generic/pathhost-generic.cpp \
    368         generic/rand-stubs-generic.cpp \
    369369        generic/RTDirQueryInfo-generic.cpp \
    370370        generic/RTDirSetTimes-generic.cpp \
    371371        generic/RTFileMove-generic.cpp \
    372372        generic/RTLogWriteDebugger-generic.cpp \
     373        generic/RTRandAdvCreateNonPseudo-generic.cpp \
     374        generic/RTRandAdvCreatePureNonPseudo-generic.cpp \
    373375        generic/RTTimeLocalNow-generic.cpp \
    374376        generic/RTTimerCreate-generic.cpp \
  • trunk/src/VBox/Runtime/common/rand/rand.cpp

    r11172 r11523  
    11/* $Id$ */
    22/** @file
    3  * IPRT - Random Number
     3 * IPRT - Random Numbers.
    44 */
    55
    66/*
    7  * Copyright (C) 2006-2007 Sun Microsystems, Inc.
     7 * Copyright (C) 2006-2008 Sun Microsystems, Inc.
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    3939#include <iprt/assert.h>
    4040#include <iprt/thread.h>
     41#include <iprt/once.h>
    4142#include "internal/rand.h"
    4243
     
    4546*   Global Variables                                                           *
    4647*******************************************************************************/
    47 /** Lazy init. */
    48 static volatile bool    g_fInitialized = false;
    49 /** The context variable for the fallback path. */
    50 static uint32_t         g_u32Ctx;
    51 
    52 
    53 /*******************************************************************************
    54 *   Internal Functions                                                         *
    55 *******************************************************************************/
    56 static uint32_t rtRandGenBytesFallbackU31(uint32_t *pCtx);
     48/** For lazily initializating of the random generator. */
     49static RTONCE g_rtRandOnce = RTONCE_INITIALIZER;
     50/** The default random generator. */
     51static RTRAND g_hRand = NIL_RTRAND;
    5752
    5853
    5954/**
    60  * Lazy initialization of the native and fallback random byte sources.
     55 * Perform lazy initialization.
    6156 *
     57 * @returns IPRT status code.
     58 * @param   pvUser1     Ignored.
     59 * @param   pvUser2     Ignored.
    6260 */
    63 static void rtRandLazyInit(void)
     61static DECLCALLBACK(int) rtRandInitOnce(void *pvUser1, void *pvUser2)
    6462{
    65     /*
    66      * Seed the fallback random code.
    67      */
    68     g_u32Ctx = (uint32_t)(ASMReadTSC() >> 8);
     63    NOREF(pvUser1);
     64    NOREF(pvUser2);
    6965
    70     /*
    71      * Call host specific init.
    72      */
    73     rtRandLazyInitNative();
    74     g_fInitialized = true;
     66    RTRAND hRand;
     67    int rc = RTRandAdvCreateNonPseudo(&hRand);
     68    if (RT_FAILURE(rc))
     69        rc = RTRandAdvCreateParkMiller(&hRand);
     70    if (RT_SUCCESS(rc))
     71    {
     72        RTRandAdvSeed(hRand, ASMReadTSC() >> 8);
     73        g_hRand = hRand;
     74    }
     75    else
     76        AssertRC(rc);
     77
     78    return rc;
    7579}
    7680
    7781
    78 /**
    79  * Internal wrapper for the native and generic random byte methods.
    80  *
    81  * @param   pv  Where to store the random bytes.
    82  * @param   cb  Number of bytes to generate.
    83  */
    84 static void rtRandGenBytes(void *pv, size_t cb)
     82RTDECL(void) RTRandBytes(void *pv, size_t cb) RT_NO_THROW
    8583{
    86     Assert(cb);
    87     if (RT_UNLIKELY(!g_fInitialized))
    88         rtRandLazyInit();
    89 
    90     int rc = rtRandGenBytesNative(pv, cb);
    91     if (RT_FAILURE(rc))
    92         rtRandGenBytesFallback(pv, cb);
     84    RTOnce(&g_rtRandOnce, rtRandInitOnce, NULL, NULL);
     85    RTRandAdvBytes(g_hRand, pv, cb);
    9386}
    9487
    9588
    96 /**
    97  * Fills a buffer with random bytes.
    98  *
    99  * @param   pv  Where to store the random bytes.
    100  * @param   cb  Number of bytes to generate.
    101  */
    102 RTDECL(void) RTRandBytes(void *pv, size_t cb) RT_NO_THROW
     89RTDECL(uint32_t) RTRandU32Ex(uint32_t u32First, uint32_t u32Last) RT_NO_THROW
    10390{
    104     if (cb)
    105         rtRandGenBytes(pv, cb);
     91    RTOnce(&g_rtRandOnce, rtRandInitOnce, NULL, NULL);
     92    return RTRandAdvU32Ex(g_hRand, u32First, u32Last);
    10693}
    10794
    10895
    109 /**
    110  * Generate a 32-bit unsigned random number in the set [u32First..u32Last].
    111  *
    112  * @returns The random number.
    113  * @param   u32First    First number in the set.
    114  * @param   u32Last     Last number in the set.
    115  */
    116 RTDECL(uint32_t) RTRandU32Ex(uint32_t u32First, uint32_t u32Last) RT_NO_THROW
     96RTDECL(uint32_t) RTRandU32(void) RT_NO_THROW
    11797{
    118     union
    119     {
    120         uint32_t    off;
    121         uint8_t     ab[5];
    122     } u;
    123 
    124     const uint32_t offLast = u32Last - u32First;
    125     if (offLast == UINT32_MAX)
    126         /* get 4 random bytes and return them raw. */
    127         rtRandGenBytes(&u.ab[0], sizeof(u.off));
    128     else if (!(offLast & UINT32_C(0xf0000000)))
    129     {
    130         /* get 4 random bytes and do simple squeeze. */
    131         rtRandGenBytes(&u.ab[0], sizeof(u.off));
    132         u.off %= offLast + 1;
    133         u.off += u32First;
    134     }
    135     else
    136     {
    137         /* get 5 random bytes and do shifted squeeze. (this ain't perfect) */
    138         rtRandGenBytes(&u.ab[0], sizeof(u.ab));
    139         u.off %= (offLast >> 4) + 1;
    140         u.off <<= 4;
    141         u.off |= u.ab[4] & 0xf;
    142         if (u.off > offLast)
    143             u.off = offLast;
    144         u.off += u32First;
    145     }
    146     return u.off;
     98    RTOnce(&g_rtRandOnce, rtRandInitOnce, NULL, NULL);
     99    return RTRandAdvU32(g_hRand);
    147100}
    148101
    149102
    150 /**
    151  * Generate a 32-bit unsigned random number.
    152  *
    153  * @returns The random number.
    154  */
    155 RTDECL(uint32_t) RTRandU32(void) RT_NO_THROW
     103RTDECL(int32_t) RTRandS32Ex(int32_t i32First, int32_t i32Last) RT_NO_THROW
    156104{
    157     return RTRandU32Ex(0, UINT32_MAX);
     105    RTOnce(&g_rtRandOnce, rtRandInitOnce, NULL, NULL);
     106    return RTRandAdvS32Ex(g_hRand, i32First, i32Last);
    158107}
    159108
    160109
    161 /**
    162  * Generate a 32-bit signed random number in the set [i32First..i32Last].
    163  *
    164  * @returns The random number.
    165  * @param   i32First    First number in the set.
    166  * @param   i32Last     Last number in the set.
    167  */
    168 RTDECL(int32_t) RTRandS32Ex(int32_t i32First, int32_t i32Last) RT_NO_THROW
     110RTDECL(int32_t) RTRandS32(void) RT_NO_THROW
    169111{
    170     if (i32First == INT32_MIN && i32Last == INT32_MAX)
    171         return (int32_t)RTRandU32Ex(0, UINT32_MAX);
    172     return RTRandU32Ex(0, i32Last - i32First) + i32First;
     112    RTOnce(&g_rtRandOnce, rtRandInitOnce, NULL, NULL);
     113    return RTRandAdvS32(g_hRand);
    173114}
    174115
    175116
    176 /**
    177  * Generate a 32-bit signed random number.
    178  *
    179  * @returns The random number.
    180  */
    181 RTDECL(int32_t) RTRandS32(void) RT_NO_THROW
     117RTDECL(uint64_t) RTRandU64Ex(uint64_t u64First, uint64_t u64Last) RT_NO_THROW
    182118{
    183     return (int32_t)RTRandU32Ex(0, UINT32_MAX);
     119    RTOnce(&g_rtRandOnce, rtRandInitOnce, NULL, NULL);
     120    return RTRandAdvU64Ex(g_hRand, u64First, u64Last);
    184121}
    185122
    186123
    187 /**
    188  * Generate a 64-bit unsigned random number in the set [u64First..u64Last].
    189  *
    190  * @returns The random number.
    191  * @param   u64First    First number in the set.
    192  * @param   u64Last     Last number in the set.
    193  */
    194 RTDECL(uint64_t) RTRandU64Ex(uint64_t u64First, uint64_t u64Last) RT_NO_THROW
     124RTDECL(uint64_t) RTRandU64(void) RT_NO_THROW
    195125{
    196     union
    197     {
    198         uint64_t    off;
    199         uint32_t    off32;
    200         uint8_t     ab[9];
    201     } u;
    202 
    203     const uint64_t offLast = u64Last - u64First;
    204     if (offLast == UINT64_MAX)
    205         /* get 8 random bytes and return them raw. */
    206         rtRandGenBytes(&u.ab[0], sizeof(u.off));
    207     else if (!(offLast & UINT64_C(0xf000000000000000)))
    208     {
    209         /* get 8 random bytes and do simple squeeze. */
    210         rtRandGenBytes(&u.ab[0], sizeof(u.off));
    211         u.off %= offLast + 1;
    212         u.off += u64First;
    213     }
    214     else
    215     {
    216         /* get 9 random bytes and do shifted squeeze. (this ain't perfect) */
    217         rtRandGenBytes(&u.ab[0], sizeof(u.ab));
    218         u.off %= (offLast >> 4) + 1;
    219         u.off <<= 4;
    220         u.off |= u.ab[8] & 0xf;
    221         if (u.off > offLast)
    222             u.off = offLast;
    223         u.off += u64First;
    224     }
    225     return u.off;
     126    RTOnce(&g_rtRandOnce, rtRandInitOnce, NULL, NULL);
     127    return RTRandAdvU64(g_hRand);
    226128}
    227129
    228130
    229 /**
    230  * Generate a 64-bit unsigned random number.
    231  *
    232  * @returns The random number.
    233  */
    234 RTDECL(uint64_t) RTRandU64(void) RT_NO_THROW
     131RTDECL(int64_t) RTRandS64Ex(int64_t i64First, int64_t i64Last) RT_NO_THROW
    235132{
    236     return RTRandU64Ex(0, UINT64_MAX);
     133    RTOnce(&g_rtRandOnce, rtRandInitOnce, NULL, NULL);
     134    return RTRandAdvS64Ex(g_hRand, i64First, i64Last);
    237135}
    238136
    239137
    240 /**
    241  * Generate a 64-bit signed random number in the set [i64First..i64Last].
    242  *
    243  * @returns The random number.
    244  * @param   i64First    First number in the set.
    245  * @param   i64Last     Last number in the set.
    246  */
    247 RTDECL(int64_t) RTRandS64Ex(int64_t i64First, int64_t i64Last) RT_NO_THROW
     138RTDECL(int64_t) RTRandS64(void) RT_NO_THROW
    248139{
    249     if (i64First == INT64_MIN && i64Last == INT64_MAX)
    250         return (int64_t)RTRandU64Ex(0, UINT64_MAX);
    251     return (int64_t)RTRandU64Ex(0, i64Last - i64First) + i64First;
     140    RTOnce(&g_rtRandOnce, rtRandInitOnce, NULL, NULL);
     141    return RTRandAdvS32(g_hRand);
    252142}
    253143
    254 
    255 /**
    256  * Generate a 64-bit signed random number.
    257  *
    258  * @returns The random number.
    259  */
    260 RTDECL(int64_t) RTRandS64(void) RT_NO_THROW
    261 {
    262     return (int64_t)RTRandU64Ex(0, UINT64_MAX);
    263 }
    264 
    265 
    266 /**
    267  * Fallback random byte source.
    268  *
    269  * @param   pv  Where to store the random bytes.
    270  * @param   cb  Number of bytes to generate.
    271  */
    272 void rtRandGenBytesFallback(void *pv, size_t cb) RT_NO_THROW
    273 {
    274     uint64_t u64Last = 0;
    275     uint8_t *pb = (uint8_t *)pv;
    276     for (unsigned i = 0;; i++)
    277     {
    278         uint32_t u32 = rtRandGenBytesFallbackU31(&g_u32Ctx);
    279 
    280         *pb++ = (uint8_t)u32;
    281         if (!--cb)
    282             break;
    283 
    284         u32 >>= 8;
    285         *pb++ = (uint8_t)u32;
    286         if (!--cb)
    287             break;
    288 
    289         u32 >>= 8;
    290         *pb++ = (uint8_t)u32;
    291         if (!--cb)
    292             break;
    293 
    294         /*
    295          * Is this really a good idea? Looks like we cannot
    296          * quite trust the lower bits here for instance...
    297          */
    298         if (!(i % 3))
    299         {
    300             uint64_t u64 = ASMReadTSC();
    301             uint64_t u64Delta = u64 - u64Last;
    302             if (u64Delta > 0xff)
    303             {
    304                 u32 >>= 8;
    305                 *pb++ = ((uint8_t)u64 >> 5) | (u32 << 3);
    306                 if (!--cb)
    307                     break;
    308                 u64Last = u64;
    309             }
    310         }
    311     }
    312 }
    313 
    314 
    315 /*-
    316  * Copyright (c) 1990, 1993
    317  *      The Regents of the University of California.  All rights reserved.
    318  *
    319  * Redistribution and use in source and binary forms, with or without
    320  * modification, are permitted provided that the following conditions
    321  * are met:
    322  * 1. Redistributions of source code must retain the above copyright
    323  *    notice, this list of conditions and the following disclaimer.
    324  * 2. Redistributions in binary form must reproduce the above copyright
    325  *    notice, this list of conditions and the following disclaimer in the
    326  *    documentation and/or other materials provided with the distribution.
    327  * 4. Neither the name of the University nor the names of its contributors
    328  *    may be used to endorse or promote products derived from this software
    329  *    without specific prior written permission.
    330  *
    331  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
    332  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    333  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    334  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
    335  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    336  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
    337  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    338  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    339  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    340  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    341  * SUCH DAMAGE.
    342  */
    343 
    344 /* The core of:
    345 __FBSDID("$FreeBSD: /repoman/r/ncvs/src/lib/libc/stdlib/rand.c,v 1.16 2007/01/09 00:28:10 imp Exp $");
    346 */
    347 
    348 /**
    349  * Generates an unsigned 31 bit pseudo random number.
    350  *
    351  * @returns pseudo random number.
    352  * @param   pCtx    The context.
    353  */
    354 static uint32_t rtRandGenBytesFallbackU31(uint32_t *pCtx)
    355 {
    356     /*
    357      * Compute x = (7^5 * x) mod (2^31 - 1)
    358      * without overflowing 31 bits:
    359      *      (2^31 - 1) = 127773 * (7^5) + 2836
    360      *
    361      * From "Random number generators: good ones are hard to find",  Park and
    362      * Miller, Communications of the ACM, vol. 31, no. 10, October 1988, p. 1195.
    363      */
    364     uint32_t Ctx = *pCtx;
    365     if (!Ctx) /* must not be zero. */
    366         Ctx = 0x20070212;
    367     uint32_t Hi = Ctx / 127773;
    368     uint32_t Lo = Ctx % 127773;
    369     int32_t x = 16807 * Lo  -  2836 * Hi;
    370     if (x < 0)
    371         x += INT32_MAX;
    372     *pCtx = x;
    373     return x % INT32_MAX;
    374 }
    375 
  • trunk/src/VBox/Runtime/common/rand/randadv.cpp

    r11380 r11523  
    6767
    6868
     69RTDECL(int) RTRandAdvSaveState(RTRAND hRand, char *pszState, size_t *pcbState) RT_NO_THROW
     70{
     71    /* Validate. */
     72    PRTRANDINT pThis = hRand;
     73    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
     74    AssertReturn(pThis->u32Magic == RTRANDINT_MAGIC, VERR_INVALID_HANDLE);
     75    AssertPtrNull(pszState);
     76    AssertPtr(pcbState);
     77
     78    /* forward the call */
     79    return pThis->pfnSaveState(pThis, pszState, pcbState);
     80}
     81
     82
     83RTDECL(int) RTRandAdvRestoreState(RTRAND hRand, char const *pszState) RT_NO_THROW
     84{
     85    /* Validate. */
     86    PRTRANDINT pThis = hRand;
     87    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
     88    AssertReturn(pThis->u32Magic == RTRANDINT_MAGIC, VERR_INVALID_HANDLE);
     89    AssertPtr(pszState);
     90
     91    /* forward the call */
     92    return pThis->pfnRestoreState(pThis, pszState);
     93}
     94
     95
    6996RTDECL(void) RTRandAdvBytes(RTRAND hRand, void *pv, size_t cb) RT_NO_THROW
    7097{
     
    338365}
    339366
     367
     368/** @copydoc RTRANDINT::pfnSeed */
     369DECLCALLBACK(int) rtRandAdvStubSeed(PRTRANDINT pThis, uint64_t u64Seed)
     370{
     371    NOREF(pThis);
     372    NOREF(u64Seed);
     373    return VERR_NOT_SUPPORTED;
     374}
     375
     376
     377/** @copydoc RTRANDINT::pfnSaveState */
     378DECLCALLBACK(int) rtRandAdvStubSaveState(PRTRANDINT pThis, char *pszState, size_t *pcbState)
     379{
     380    NOREF(pThis);
     381    NOREF(pszState);
     382    NOREF(pcbState);
     383    return VERR_NOT_SUPPORTED;
     384}
     385
     386
     387/** @copydoc RTRANDINT::pfnRestoreState */
     388DECLCALLBACK(int) rtRandAdvStubRestoreState(PRTRANDINT pThis, char const *pszState)
     389{
     390    NOREF(pThis);
     391    NOREF(pszState);
     392    return VERR_NOT_SUPPORTED;
     393}
     394
     395
     396/** @copydoc RTRANDINT::pfnDestroy */
     397DECLCALLBACK(int) rtRandAdvDefaultDestroy(PRTRANDINT pThis)
     398{
     399    pThis->u32Magic = ~RTRANDINT_MAGIC;
     400    RTMemFree(pThis);
     401    return VINF_SUCCESS;
     402}
     403
     404
  • trunk/src/VBox/Runtime/common/rand/randparkmiller.cpp

    r11347 r11523  
    3535#include <iprt/asm.h>
    3636#include <iprt/mem.h>
     37#include <iprt/string.h>
    3738#include <iprt/err.h>
    3839#include "internal/rand.h"
     
    6566
    6667/** @copydoc RTRANDINT::pfnGetU32 */
    67 static uint32_t rtRandParkMillerGetU32(PRTRANDINT pThis, uint32_t u32First, uint32_t u32Last)
     68static DECLCALLBACK(uint32_t) rtRandParkMillerGetU32(PRTRANDINT pThis, uint32_t u32First, uint32_t u32Last)
    6869{
    6970    uint32_t off;
     
    115116
    116117/** @copydoc RTRANDINT::pfnSeed */
    117 static int rtRandParkMillerSeed(PRTRANDINT pThis, uint64_t u64Seed)
     118static DECLCALLBACK(int) rtRandParkMillerSeed(PRTRANDINT pThis, uint64_t u64Seed)
    118119{
    119120    pThis->u.ParkMiller.u32Ctx = u64Seed;
     
    124125
    125126
    126 /** @copydoc RTRANDINT::pfnDestroy */
    127 static int rtRandParkMillerDestroy(PRTRANDINT pThis)
    128 {
    129     pThis->u32Magic = ~RTRANDINT_MAGIC;
    130     RTMemFree(pThis);
     127/** @copydoc RTRANDINT::pfnSaveState */
     128static DECLCALLBACK(int) rtRandParkMillerSaveState(PRTRANDINT pThis, char *pszState, size_t *pcbState)
     129{
     130#define RTRAND_PARKMILLER_STATE_SIZE (3+8+1+8+1+2+1+1)
     131
     132    if (*pcbState < RTRAND_PARKMILLER_STATE_SIZE)
     133    {
     134        *pcbState = RTRAND_PARKMILLER_STATE_SIZE;
     135        return VERR_BUFFER_OVERFLOW;
     136    }
     137    RTStrPrintf(pszState, *pcbState, "PM:%08RX32,%08RX32,%02x;",
     138                pThis->u.ParkMiller.u32Ctx,
     139                pThis->u.ParkMiller.u32Bits,
     140                pThis->u.ParkMiller.cBits);
     141    return VINF_SUCCESS;
     142}
     143
     144
     145/** @copydoc RTRANDINT::pfnRestoreState */
     146static DECLCALLBACK(int) rtRandParkMillerRestoreState(PRTRANDINT pThis, char const *pszState)
     147{
     148    /* marker */
     149    if (    pszState[0] != 'P'
     150        ||  pszState[1] != 'M'
     151        ||  pszState[2] != ':')
     152        return VERR_PARSE_ERROR;
     153    pszState += 3;
     154
     155    /* u32Ctx */
     156    char *pszNext = NULL;
     157    uint32_t u32Ctx;
     158    int rc = RTStrToUInt32Ex(pszState, &pszNext, 16, &u32Ctx);
     159    if (    rc != VWRN_TRAILING_CHARS
     160        ||  pszNext !=  pszState + 8
     161        ||  *pszNext != ',')
     162        return VERR_PARSE_ERROR;
     163    pszState += 8 + 1;
     164
     165    /* u32Bits */
     166    uint32_t u32Bits;
     167    rc = RTStrToUInt32Ex(pszState, &pszNext, 16, &u32Bits);
     168    if (    rc != VWRN_TRAILING_CHARS
     169        ||  pszNext !=  pszState + 8
     170        ||  *pszNext != ',')
     171        return VERR_PARSE_ERROR;
     172    pszState += 8 + 1;
     173
     174    /* cBits */
     175    uint32_t cBits;
     176    rc = RTStrToUInt32Ex(pszState, &pszNext, 16, &cBits);
     177    if (    rc != VWRN_TRAILING_CHARS
     178        ||  pszNext !=  pszState + 2
     179        ||  *pszNext != ';'
     180        ||  pszNext[1] != '\0')
     181        return VERR_PARSE_ERROR;
     182
     183    /* commit */
     184    pThis->u.ParkMiller.u32Ctx  = u32Ctx;
     185    pThis->u.ParkMiller.u32Bits = u32Bits;
     186    pThis->u.ParkMiller.cBits   = cBits;
    131187    return VINF_SUCCESS;
    132188}
     
    143199    pThis->pfnGetU64  = rtRandAdvSynthesizeU64FromU32;
    144200    pThis->pfnSeed    = rtRandParkMillerSeed;
    145     pThis->pfnDestroy = rtRandParkMillerDestroy;
     201    pThis->pfnSaveState = rtRandParkMillerSaveState;
     202    pThis->pfnRestoreState = rtRandParkMillerRestoreState;
     203    pThis->pfnDestroy = rtRandAdvDefaultDestroy;
    146204    pThis->u.ParkMiller.u32Ctx = 0x20080806;
    147205    pThis->u.ParkMiller.u32Bits = 0;
  • trunk/src/VBox/Runtime/include/internal/rand.h

    r11347 r11523  
    8585     *
    8686     * @returns IPRT status code.
     87     * @retval  VERR_NOT_SUPPORTED if it isn't a pseudo generator.
     88     *
    8789     * @param   pThis       Pointer to the instance data.
    8890     * @param   u64Seed     The seed.
    8991     */
    9092    DECLCALLBACKMEMBER(int, pfnSeed)(PRTRANDINT pThis, uint64_t u64Seed);
     93
     94    /**
     95     * Save the current state of a pseudo generator.
     96     *
     97     * This can be use to save the state so it can later be resumed at the same
     98     * position.
     99     *
     100     * @returns IPRT status code.
     101     * @retval  VINF_SUCCESS on success. *pcbState contains the length of the
     102     *          returned string and pszState contains the state string.
     103     * @retval  VERR_BUFFER_OVERFLOW if the supplied buffer is too small. *pcbState
     104     *          will contain the necessary buffer size.
     105     * @retval  VERR_NOT_SUPPORTED by non-psuedo generators.
     106     *
     107     * @param   hRand       Handle to the random number generator.
     108     * @param   pszState    Where to store the state. The returned string will be
     109     *                      null terminated and printable.
     110     * @param   pcbState    The size of the buffer pszState points to on input, the
     111     *                      size required / used on return (including the
     112     *                      terminator, thus the 'cb' instead of 'cch').
     113     */
     114    DECLCALLBACKMEMBER(int, pfnSaveState)(RTRAND hRand, char *pszState, size_t *pcbState);
     115
     116    /**
     117     * Restores the state of a pseudo generator.
     118     *
     119     * The state must've been obtained using pfnGetState.
     120     *
     121     * @returns IPRT status code.
     122     * @retval  VERR_PARSE_ERROR if the state string is malformed.
     123     * @retval  VERR_NOT_SUPPORTED by non-psuedo generators.
     124     *
     125     * @param   hRand       Handle to the random number generator.
     126     * @param   pszState    The state to load.
     127     */
     128    DECLCALLBACKMEMBER(int, pfnRestoreState)(RTRAND hRand, char const *pszState);
    91129
    92130    /**
     
    113151            uint32_t    cBits;
    114152        } ParkMiller;
     153
     154        struct RTRandFile
     155        {
     156            /** The file handle. */
     157            RTFILE      hFile;
     158        } File;
    115159    } u;
    116160} RTRANDINT;
     
    141185DECLCALLBACK(uint64_t)  rtRandAdvSynthesizeU64FromBytes(PRTRANDINT pThis, uint64_t u64First, uint64_t u64Last);
    142186DECLCALLBACK(uint64_t)  rtRandAdvSynthesizeU64FromU32(PRTRANDINT pThis, uint64_t u64First, uint64_t u64Last);
     187DECLCALLBACK(int)       rtRandAdvStubSeed(PRTRANDINT pThis, uint64_t u64Seed);
     188DECLCALLBACK(int)       rtRandAdvStubSaveState(PRTRANDINT pThis, char *pszState, size_t *pcbState);
     189DECLCALLBACK(int)       rtRandAdvStubRestoreState(PRTRANDINT pThis, char const *pszState);
     190DECLCALLBACK(int)       rtRandAdvDefaultDestroy(PRTRANDINT pThis);
    143191
    144192__END_DECLS
  • trunk/src/VBox/Runtime/r3/posix/rand-posix.cpp

    r8245 r11523  
    4848
    4949#include <iprt/rand.h>
     50#include <iprt/mem.h>
    5051#include <iprt/err.h>
    5152#include <iprt/assert.h>
    5253#include "internal/rand.h"
     54#include "internal/magics.h"
    5355
    5456
    55 /*******************************************************************************
    56 *   Global Variables                                                           *
    57 *******************************************************************************/
    58 /** File handle of /dev/random. */
    59 static int g_fhDevRandom = -1;
    6057
    61 
    62 void rtRandLazyInitNative(void)
     58/** @copydoc RTRANDINT::pfnGetBytes */
     59static DECLCALLBACK(void) rtRandAdvPosixGetBytes(PRTRANDINT pThis, uint8_t *pb, size_t cb)
    6360{
    64     if (g_fhDevRandom != -1)
    65         return;
    66 
    67     int fh = open("/dev/urandom", O_RDONLY);
    68     if (fh <= 0)
    69         fh = open("/dev/random", O_RDONLY | O_NONBLOCK);
    70     if (fh >= 0)
     61    ssize_t cbRead = read(pThis->u.File.hFile, pb, cb);
     62    if ((size_t)cbRead != cb)
    7163    {
    72         fcntl(fh, F_SETFD, FD_CLOEXEC);
    73         g_fhDevRandom = fh;
     64        ssize_t cTries = RT_MIN(cb, 256);
     65        do
     66        {
     67            if (cbRead > 0)
     68            {
     69                cb -= cbRead;
     70                pb += cbRead;
     71            }
     72            cbRead = read(pThis->u.File.hFile, pb, cb);
     73        } while (   (size_t)cbRead != cb
     74                 && cTries-- > 0);
     75        AssertReleaseMsg((size_t)cbRead == cb, ("%zu != %zu, cTries=%zd errno=%d\n", cbRead, cb, cTries, errno));
    7476    }
    7577}
    7678
    7779
    78 int rtRandGenBytesNative(void *pv, size_t cb)
     80/** @copydoc RTRANDINT::pfnDestroy */
     81static DECLCALLBACK(int) rtRandAdvPosixDestroy(PRTRANDINT pThis)
    7982{
    80     int fh = g_fhDevRandom;
    81     if (fh == -1)
    82         return VERR_NOT_SUPPORTED;
    83 
    84     ssize_t cbRead = read(fh, pv, cb);
    85     if ((size_t)cbRead != cb)
    86     {
    87         /*
    88          * Use the fallback for the remainder if /dev/urandom / /dev/random
    89          * is out to lunch.
    90          */
    91         if (cbRead <= 0)
    92             rtRandGenBytesFallback(pv, cb);
    93         else
    94         {
    95             AssertRelease((size_t)cbRead < cb);
    96             rtRandGenBytesFallback((uint8_t *)pv + cbRead, cb - cbRead);
    97         }
    98     }
     83    pThis->u32Magic = ~RTRANDINT_MAGIC;
     84    int fd = pThis->u.File.hFile;
     85    pThis->u.File.hFile = NIL_RTFILE;
     86    RTMemFree(pThis);
     87    close(fd);
    9988    return VINF_SUCCESS;
    10089}
    10190
     91
     92static int rtRandAdvPosixCreateNonPseudo(PRTRAND phRand, const char *pszDev) RT_NO_THROW
     93{
     94    /*
     95     * Try open it first and then setup the handle structure.
     96     */
     97    int fd = open(pszDev, O_RDONLY);
     98    if (fd < 0)
     99        return RTErrConvertFromErrno(errno);
     100    int rc;
     101    if (fcntl(fd, F_SETFD, FD_CLOEXEC) != -1)
     102    {
     103        PRTRANDINT pThis = (PRTRANDINT)RTMemAlloc(sizeof(*pThis));
     104        if (pThis)
     105        {
     106            pThis->u32Magic     = RTRANDINT_MAGIC;
     107            pThis->pfnGetBytes  = rtRandAdvPosixGetBytes;
     108            pThis->pfnGetU32    = rtRandAdvSynthesizeU32FromBytes;
     109            pThis->pfnGetU64    = rtRandAdvSynthesizeU64FromBytes;
     110            pThis->pfnSeed      = rtRandAdvStubSeed;
     111            pThis->pfnSaveState = rtRandAdvStubSaveState;
     112            pThis->pfnRestoreState = rtRandAdvStubRestoreState;
     113            pThis->pfnDestroy   = rtRandAdvPosixDestroy;
     114            pThis->u.File.hFile = fd;
     115
     116            *phRand = pThis;
     117            return VINF_SUCCESS;
     118        }
     119
     120        /* bail out */
     121        rc = VERR_NO_MEMORY;
     122    }
     123    else
     124        rc = RTErrConvertFromErrno(errno);
     125    close(fd);
     126    return rc;
     127}
     128
     129
     130RTDECL(int) RTRandAdvCreateNonPseudo(PRTRAND phRand) RT_NO_THROW
     131{
     132    return rtRandAdvPosixCreateNonPseudo(phRand, "/dev/urandom");
     133}
     134
     135
     136RTDECL(int) RTRandAdvCreatePureNonPseudo(PRTRAND phRand) RT_NO_THROW
     137{
     138    return rtRandAdvPosixCreateNonPseudo(phRand, "/dev/random");
     139}
     140
     141
  • trunk/src/VBox/Runtime/testcase/tstRand.cpp

    r11347 r11523  
    317317
    318318    /*
     319     * Test saving and restoring the state.
     320     */
     321    RTPrintf("tstRand:   TESTING RTRandAdvSave/RestoreSave\n");
     322    char szState[256];
     323    size_t cbState = sizeof(szState);
     324    int rc = RTRandAdvSaveState(hRand, szState, &cbState);
     325    if (rc != VERR_NOT_SUPPORTED)
     326    {
     327        CHECK_EXPR_MSG(rc == VINF_SUCCESS,  ("RTRandAdvSaveState(%p,,256) -> %Rrc (%d)\n", (uintptr_t)hRand, rc, rc));
     328        uint32_t const u32A1 = RTRandAdvU32(hRand);
     329        uint32_t const u32B1 = RTRandAdvU32(hRand);
     330        RTPrintf("tstRand:   state:\"%s\"  A=%RX32 B=%RX32\n", szState, u32A1, u32B1);
     331
     332        rc = RTRandAdvRestoreState(hRand, szState);
     333        CHECK_EXPR_MSG(rc == VINF_SUCCESS,  ("RTRandAdvRestoreState(%p,\"%s\") -> %Rrc (%d)\n", (uintptr_t)hRand, szState, rc, rc));
     334        uint32_t const u32A2 = RTRandAdvU32(hRand);
     335        uint32_t const u32B2 = RTRandAdvU32(hRand);
     336        CHECK_EXPR_MSG(u32A1 == u32A2, ("u32A1=%RX32 u32A2=%RX32\n", u32A1, u32A2));
     337        CHECK_EXPR_MSG(u32B1 == u32B2, ("u32B1=%RX32 u32B2=%RX32\n", u32B1, u32B2));
     338    }
     339    else
     340    {
     341        szState[0] = '\0';
     342        rc = RTRandAdvRestoreState(hRand, szState);
     343        CHECK_EXPR_MSG(rc == VERR_NOT_SUPPORTED,  ("RTRandAdvRestoreState(%p,\"\") -> %Rrc (%d)\n", (uintptr_t)hRand, rc, rc));
     344    }
     345
     346
     347    /*
    319348     * Destroy it.
    320349     */
    321     int rc = RTRandAdvDestroy(hRand);
     350    rc = RTRandAdvDestroy(hRand);
    322351    CHECK_EXPR_MSG(rc == VINF_SUCCESS,  ("RTRandAdvDestroy(%p) -> %Rrc (%d)\n", (uintptr_t)hRand, rc, rc));
    323352
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette