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
init_random_seed()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
BUuid()42 BUuid::BUuid()
43 {
44 memset(fValue, 0, sizeof(fValue));
45 }
46
47
BUuid(const BUuid & other)48 BUuid::BUuid(const BUuid& other)
49 {
50 memcpy(fValue, other.fValue, sizeof(fValue));
51 }
52
53
~BUuid()54 BUuid::~BUuid()
55 {
56 }
57
58
59 bool
IsNil() const60 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&
SetToRandom()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
ToString() const89 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
Compare(const BUuid & other) const103 BUuid::Compare(const BUuid& other) const
104 {
105 return memcmp(fValue, other.fValue, sizeof(fValue));
106 }
107
108
109 BUuid&
operator =(const BUuid & other)110 BUuid::operator=(const BUuid& other)
111 {
112 memcpy(fValue, other.fValue, sizeof(fValue));
113
114 return *this;
115 }
116
117
118 bool
_SetToDevRandom()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
_SetToRandomFallback()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