xpcom/base/nsUUIDGenerator.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/xpcom/base/nsUUIDGenerator.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,160 @@
     1.4 +/* -*- Mode: C++; tab-width: 50; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#if defined(XP_WIN)
    1.10 +#include <windows.h>
    1.11 +#include <objbase.h>
    1.12 +#elif defined(XP_MACOSX)
    1.13 +#include <CoreFoundation/CoreFoundation.h>
    1.14 +#else
    1.15 +#include <stdlib.h>
    1.16 +#include "prrng.h"
    1.17 +#endif
    1.18 +
    1.19 +#include "nsUUIDGenerator.h"
    1.20 +
    1.21 +using namespace mozilla;
    1.22 +
    1.23 +NS_IMPL_ISUPPORTS(nsUUIDGenerator, nsIUUIDGenerator)
    1.24 +
    1.25 +nsUUIDGenerator::nsUUIDGenerator()
    1.26 +    : mLock("nsUUIDGenerator.mLock")
    1.27 +{
    1.28 +}
    1.29 +
    1.30 +nsUUIDGenerator::~nsUUIDGenerator()
    1.31 +{
    1.32 +}
    1.33 +
    1.34 +nsresult
    1.35 +nsUUIDGenerator::Init()
    1.36 +{
    1.37 +    // We're a service, so we're guaranteed that Init() is not going
    1.38 +    // to be reentered while we're inside Init().
    1.39 +    
    1.40 +#if !defined(XP_WIN) && !defined(XP_MACOSX) && !defined(ANDROID)
    1.41 +    /* initialize random number generator using NSPR random noise */
    1.42 +    unsigned int seed;
    1.43 +
    1.44 +    size_t bytes = 0;
    1.45 +    while (bytes < sizeof(seed)) {
    1.46 +        size_t nbytes = PR_GetRandomNoise(((unsigned char *)&seed)+bytes,
    1.47 +                                          sizeof(seed)-bytes);
    1.48 +        if (nbytes == 0) {
    1.49 +            return NS_ERROR_FAILURE;
    1.50 +        }
    1.51 +        bytes += nbytes;
    1.52 +    }
    1.53 +
    1.54 +    /* Initialize a new RNG state, and immediately switch
    1.55 +     * back to the previous one -- we want to use mState
    1.56 +     * only for our own calls to random().
    1.57 +     */
    1.58 +    mSavedState = initstate(seed, mState, sizeof(mState));
    1.59 +    setstate(mSavedState);
    1.60 +
    1.61 +    mRBytes = 4;
    1.62 +#ifdef RAND_MAX
    1.63 +    if ((unsigned long) RAND_MAX < (unsigned long)0xffffffff)
    1.64 +        mRBytes = 3;
    1.65 +    if ((unsigned long) RAND_MAX < (unsigned long)0x00ffffff)
    1.66 +        mRBytes = 2;
    1.67 +    if ((unsigned long) RAND_MAX < (unsigned long)0x0000ffff)
    1.68 +        mRBytes = 1;
    1.69 +    if ((unsigned long) RAND_MAX < (unsigned long)0x000000ff)
    1.70 +        return NS_ERROR_FAILURE;
    1.71 +#endif
    1.72 +
    1.73 +#endif /* non XP_WIN and non XP_MACOSX */
    1.74 +
    1.75 +    return NS_OK;
    1.76 +}
    1.77 +
    1.78 +NS_IMETHODIMP
    1.79 +nsUUIDGenerator::GenerateUUID(nsID** ret)
    1.80 +{
    1.81 +    nsID *id = static_cast<nsID*>(NS_Alloc(sizeof(nsID)));
    1.82 +    if (id == nullptr)
    1.83 +        return NS_ERROR_OUT_OF_MEMORY;
    1.84 +
    1.85 +    nsresult rv = GenerateUUIDInPlace(id);
    1.86 +    if (NS_FAILED(rv)) {
    1.87 +        NS_Free(id);
    1.88 +        return rv;
    1.89 +    }
    1.90 +
    1.91 +    *ret = id;
    1.92 +    return rv;
    1.93 +}
    1.94 +
    1.95 +NS_IMETHODIMP
    1.96 +nsUUIDGenerator::GenerateUUIDInPlace(nsID* id)
    1.97 +{
    1.98 +    // The various code in this method is probably not threadsafe, so lock
    1.99 +    // across the whole method.
   1.100 +    MutexAutoLock lock(mLock);
   1.101 +
   1.102 +#if defined(XP_WIN)
   1.103 +    HRESULT hr = CoCreateGuid((GUID*)id);
   1.104 +    if (FAILED(hr))
   1.105 +        return NS_ERROR_FAILURE;
   1.106 +#elif defined(XP_MACOSX)
   1.107 +    CFUUIDRef uuid = CFUUIDCreate(kCFAllocatorDefault);
   1.108 +    if (!uuid)
   1.109 +        return NS_ERROR_FAILURE;
   1.110 +
   1.111 +    CFUUIDBytes bytes = CFUUIDGetUUIDBytes(uuid);
   1.112 +    memcpy(id, &bytes, sizeof(nsID));
   1.113 +
   1.114 +    CFRelease(uuid);
   1.115 +#else /* not windows or OS X; generate randomness using random(). */
   1.116 +    /* XXX we should be saving the return of setstate here and switching
   1.117 +     * back to it; instead, we use the value returned when we called
   1.118 +     * initstate, since older glibc's have broken setstate() return values
   1.119 +     */
   1.120 +#ifndef ANDROID
   1.121 +    setstate(mState);
   1.122 +#endif
   1.123 +
   1.124 +    size_t bytesLeft = sizeof(nsID);
   1.125 +    while (bytesLeft > 0) {
   1.126 +#ifdef ANDROID
   1.127 +        long rval = arc4random();
   1.128 +        const size_t mRBytes = 4;
   1.129 +#else
   1.130 +        long rval = random();
   1.131 +#endif
   1.132 +
   1.133 +
   1.134 +        uint8_t *src = (uint8_t*)&rval;
   1.135 +        // We want to grab the mRBytes least significant bytes of rval, since
   1.136 +        // mRBytes less than sizeof(rval) means the high bytes are 0.
   1.137 +#ifdef IS_BIG_ENDIAN
   1.138 +        src += sizeof(rval) - mRBytes;
   1.139 +#endif
   1.140 +        uint8_t *dst = ((uint8_t*) id) + (sizeof(nsID) - bytesLeft);
   1.141 +        size_t toWrite = (bytesLeft < mRBytes ? bytesLeft : mRBytes);
   1.142 +        for (size_t i = 0; i < toWrite; i++)
   1.143 +            dst[i] = src[i];
   1.144 +
   1.145 +        bytesLeft -= toWrite;
   1.146 +    }
   1.147 +
   1.148 +    /* Put in the version */
   1.149 +    id->m2 &= 0x0fff;
   1.150 +    id->m2 |= 0x4000;
   1.151 +
   1.152 +    /* Put in the variant */
   1.153 +    id->m3[0] &= 0x3f;
   1.154 +    id->m3[0] |= 0x80;
   1.155 +
   1.156 +#ifndef ANDROID
   1.157 +    /* Restore the previous RNG state */
   1.158 +    setstate(mSavedState);
   1.159 +#endif
   1.160 +#endif
   1.161 +
   1.162 +    return NS_OK;
   1.163 +}

mercurial