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 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 36 return true; 37 } 38 39 40 namespace BPrivate { 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 97 return BString().SetToFormat("%.8s-%.4s-%.4s-%.4s-%.12s", 98 buffer, buffer + 8, buffer + 12, buffer + 16, buffer + 20); 99 } 100 101 102 int 103 BUuid::Compare(const BUuid& other) const 104 { 105 return memcmp(fValue, other.fValue, sizeof(fValue)); 106 } 107 108 109 BUuid& 110 BUuid::operator=(const BUuid& other) 111 { 112 memcpy(fValue, other.fValue, sizeof(fValue)); 113 114 return *this; 115 } 116 117 118 bool 119 BUuid::_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 137 void 138 BUuid::_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 161 using BPrivate::BUuid; 162