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 +}