1/* 2 * Copyright 2013 Haiku, Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7#include <Uuid.h> 8 9#include <fcntl.h> 10#include <stdlib.h> 11#include <string.h> 12#include <time.h> 13#include <unistd.h> 14 15 16static const char* const kHexChars = "0123456789abcdef"; 17 18static const size_t kVersionByteIndex = 6; 19static const size_t kVariantByteIndex = 8; 20 21 22static bool 23init_random_seed() 24{ 25 // set a time-based seed 26 timespec time; 27 clock_gettime(CLOCK_REALTIME, &time); 28 uint32 seed = (uint32)time.tv_sec ^ (uint32)time.tv_nsec; 29 30 // factor in a stack address -- with address space layout randomization 31 // that adds a bit of additional randomness 32 seed ^= (uint32)(addr_t)&time; 33 34 srandom(seed); 35 36 return true; 37} 38 39 40namespace BPrivate { 41 42BUuid::BUuid() 43{ 44 memset(fValue, 0, sizeof(fValue)); 45} 46 47 48BUuid::BUuid(const BUuid& other) 49{ 50 memcpy(fValue, other.fValue, sizeof(fValue)); 51} 52 53 54BUuid::~BUuid() 55{ 56} 57 58 59bool 60BUuid::IsNil() const 61{ 62 for (size_t i = 0; i < sizeof(fValue); i++) { 63 if (fValue[i] != 0) 64 return false; 65 } 66 67 return true; 68} 69 70 71BUuid& 72BUuid::SetToRandom() 73{ 74 if (!BUuid::_SetToDevRandom()) 75 BUuid::_SetToRandomFallback(); 76 77 // set variant and version 78 fValue[kVariantByteIndex] &= 0x3f; 79 fValue[kVariantByteIndex] |= 0x80; 80 fValue[kVersionByteIndex] &= 0x0f; 81 fValue[kVersionByteIndex] |= 4 << 4; 82 // version 4 83 84 return *this; 85} 86 87 88BString 89BUuid::ToString() const 90{ 91 char buffer[32]; 92 for (size_t i = 0; i < 16; i++) { 93 buffer[2 * i] = kHexChars[fValue[i] >> 4]; 94 buffer[2 * i + 1] = kHexChars[fValue[i] & 0xf]; 95 } 96 97 return BString().SetToFormat("%.8s-%.4s-%.4s-%.4s-%.12s", 98 buffer, buffer + 8, buffer + 12, buffer + 16, buffer + 20); 99} 100 101 102int 103BUuid::Compare(const BUuid& other) const 104{ 105 return memcmp(fValue, other.fValue, sizeof(fValue)); 106} 107 108 109BUuid& 110BUuid::operator=(const BUuid& other) 111{ 112 memcpy(fValue, other.fValue, sizeof(fValue)); 113 114 return *this; 115} 116 117 118bool 119BUuid::_SetToDevRandom() 120{ 121 // open device 122 int fd = open("/dev/urandom", O_RDONLY); 123 if (fd < 0) { 124 fd = open("/dev/random", O_RDONLY); 125 if (fd < 0) 126 return false; 127 } 128 129 // read bytes 130 ssize_t bytesRead = read(fd, fValue, sizeof(fValue)); 131 close(fd); 132 133 return bytesRead == (ssize_t)sizeof(fValue); 134} 135 136 137void 138BUuid::_SetToRandomFallback() 139{ 140 static bool sSeedInitialized = init_random_seed(); 141 (void)sSeedInitialized; 142 143 for (int32 i = 0; i < 4; i++) { 144 uint32 value = random(); 145 fValue[4 * i + 0] = uint8(value >> 24); 146 fValue[4 * i + 1] = uint8(value >> 16); 147 fValue[4 * i + 2] = uint8(value >> 8); 148 fValue[4 * i + 3] = uint8(value); 149 } 150 151 // random() returns 31 bit numbers only, so we move a few bits from where 152 // we overwrite them with the version anyway. 153 uint8 bitsToMove = fValue[kVersionByteIndex]; 154 for (int32 i = 0; i < 4; i++) 155 fValue[4 * i] |= (bitsToMove << i) & 0x80; 156} 157 158} // namespace BPrivate 159 160 161using BPrivate::BUuid; 162