1 /* 2 * Copyright 2013, Haiku, Inc. 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 16 static const char* const kHexChars = "0123456789abcdef"; 17 18 static const size_t kVersionByteIndex = 6; 19 static const size_t kVariantByteIndex = 8; 20 21 22 static bool 23 init_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 return true; 36 } 37 38 39 namespace BPrivate { 40 41 42 BUuid::BUuid() 43 { 44 memset(fValue, 0, sizeof(fValue)); 45 } 46 47 48 BUuid::BUuid(const BUuid& other) 49 { 50 memcpy(fValue, other.fValue, sizeof(fValue)); 51 } 52 53 54 BUuid::~BUuid() 55 { 56 } 57 58 59 bool 60 BUuid::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 71 BUuid& 72 BUuid::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 88 BString 89 BUuid::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 return BString().SetToFormat("%.8s-%.4s-%.4s-%.4s-%.12s", 97 buffer, buffer + 8, buffer + 12, buffer + 16, buffer + 20); 98 } 99 100 101 int 102 BUuid::Compare(const BUuid& other) const 103 { 104 return memcmp(fValue, other.fValue, sizeof(fValue)); 105 } 106 107 108 BUuid& 109 BUuid::operator=(const BUuid& other) 110 { 111 memcpy(fValue, other.fValue, sizeof(fValue)); 112 return *this; 113 } 114 115 116 bool 117 BUuid::_SetToDevRandom() 118 { 119 // open device 120 int fd = open("/dev/urandom", O_RDONLY); 121 if (fd < 0) { 122 fd = open("/dev/random", O_RDONLY); 123 if (fd < 0) 124 return false; 125 } 126 127 // read bytes 128 ssize_t bytesRead = read(fd, fValue, sizeof(fValue)); 129 close(fd); 130 131 return bytesRead == (ssize_t)sizeof(fValue); 132 } 133 134 135 void 136 BUuid::_SetToRandomFallback() 137 { 138 static bool sSeedInitialized = init_random_seed(); 139 (void)sSeedInitialized; 140 141 for (int32 i = 0; i < 4; i++) { 142 uint32 value = random(); 143 fValue[4 * i + 0] = uint8(value >> 24); 144 fValue[4 * i + 1] = uint8(value >> 16); 145 fValue[4 * i + 2] = uint8(value >> 8); 146 fValue[4 * i + 3] = uint8(value); 147 } 148 149 // random() returns 31 bit numbers only, so we move a few bits from where 150 // we overwrite them with the version anyway. 151 uint8 bitsToMove = fValue[kVersionByteIndex]; 152 for (int32 i = 0; i < 4; i++) 153 fValue[4 * i] |= (bitsToMove << i) & 0x80; 154 } 155 156 157 } // namespace BPrivate 158 159 160 using BPrivate::BUuid; 161