1177162Sjkoshy/*
2145256Sjkoshy * Copyright 2013 Haiku, Inc. All rights reserved.
3145256Sjkoshy * Distributed under the terms of the MIT License.
4145256Sjkoshy */
5145256Sjkoshy
6145256Sjkoshy
7145256Sjkoshy#include <Uuid.h>
8145256Sjkoshy
9145256Sjkoshy#include <fcntl.h>
10145256Sjkoshy#include <stdlib.h>
11145256Sjkoshy#include <string.h>
12232151Sbrueffer#include <time.h>
13232151Sbrueffer#include <unistd.h>
14232151Sbrueffer
15232151Sbrueffer
16232151Sbruefferstatic const char* const kHexChars = "0123456789abcdef";
17232151Sbrueffer
18232151Sbruefferstatic const size_t kVersionByteIndex = 6;
19232151Sbruefferstatic const size_t kVariantByteIndex = 8;
20232151Sbrueffer
21232151Sbrueffer
22232151Sbruefferstatic bool
23145256Sjkoshyinit_random_seed()
24145256Sjkoshy{
25145256Sjkoshy	// set a time-based seed
26183595Sjkoshy	timespec time;
27206622Suqs	clock_gettime(CLOCK_REALTIME, &time);
28145256Sjkoshy	uint32 seed = (uint32)time.tv_sec ^ (uint32)time.tv_nsec;
29145256Sjkoshy
30183084Sjkoshy	// factor in a stack address -- with address space layout randomization
31183084Sjkoshy	// that adds a bit of additional randomness
32183084Sjkoshy	seed ^= (uint32)(addr_t)&time;
33183084Sjkoshy
34183084Sjkoshy	srandom(seed);
35183084Sjkoshy
36145256Sjkoshy	return true;
37145256Sjkoshy}
38145256Sjkoshy
39145256Sjkoshy
40145256Sjkoshynamespace BPrivate {
41145256Sjkoshy
42145256SjkoshyBUuid::BUuid()
43145256Sjkoshy{
44145256Sjkoshy	memset(fValue, 0, sizeof(fValue));
45183084Sjkoshy}
46183084Sjkoshy
47183084Sjkoshy
48183084SjkoshyBUuid::BUuid(const BUuid& other)
49145256Sjkoshy{
50145256Sjkoshy	memcpy(fValue, other.fValue, sizeof(fValue));
51145256Sjkoshy}
52145256Sjkoshy
53145256Sjkoshy
54145256SjkoshyBUuid::~BUuid()
55145256Sjkoshy{
56145256Sjkoshy}
57145256Sjkoshy
58145256Sjkoshy
59145256Sjkoshybool
60145256SjkoshyBUuid::IsNil() const
61145256Sjkoshy{
62145256Sjkoshy	for (size_t i = 0; i < sizeof(fValue); i++) {
63145256Sjkoshy		if (fValue[i] != 0)
64145440Sjkoshy			return false;
65145440Sjkoshy	}
66145440Sjkoshy
67147586Sru	return true;
68145440Sjkoshy}
69145440Sjkoshy
70145440Sjkoshy
71183084SjkoshyBUuid&
72183084SjkoshyBUuid::SetToRandom()
73183084Sjkoshy{
74183084Sjkoshy	if (!BUuid::_SetToDevRandom())
75183084Sjkoshy		BUuid::_SetToRandomFallback();
76183084Sjkoshy
77183084Sjkoshy	// set variant and version
78183084Sjkoshy	fValue[kVariantByteIndex] &= 0x3f;
79183084Sjkoshy	fValue[kVariantByteIndex] |= 0x80;
80183084Sjkoshy	fValue[kVersionByteIndex] &= 0x0f;
81183084Sjkoshy	fValue[kVersionByteIndex] |= 4 << 4;
82183084Sjkoshy		// version 4
83183084Sjkoshy
84183084Sjkoshy	return *this;
85183084Sjkoshy}
86183084Sjkoshy
87183084Sjkoshy
88183084SjkoshyBString
89183084SjkoshyBUuid::ToString() const
90183084Sjkoshy{
91183084Sjkoshy	char buffer[32];
92183084Sjkoshy	for (size_t i = 0; i < 16; i++) {
93145256Sjkoshy		buffer[2 * i] = kHexChars[fValue[i] >> 4];
94145256Sjkoshy		buffer[2 * i + 1] = kHexChars[fValue[i] & 0xf];
95145256Sjkoshy	}
96145256Sjkoshy
97145256Sjkoshy	return BString().SetToFormat("%.8s-%.4s-%.4s-%.4s-%.12s",
98145256Sjkoshy		buffer, buffer + 8, buffer + 12, buffer + 16, buffer + 20);
99145256Sjkoshy}
100145256Sjkoshy
101145256Sjkoshy
102145256Sjkoshyint
103147586SruBUuid::Compare(const BUuid& other) const
104145256Sjkoshy{
105145256Sjkoshy	return memcmp(fValue, other.fValue, sizeof(fValue));
106145256Sjkoshy}
107145256Sjkoshy
108145256Sjkoshy
109145256SjkoshyBUuid&
110145256SjkoshyBUuid::operator=(const BUuid& other)
111145256Sjkoshy{
112145256Sjkoshy	memcpy(fValue, other.fValue, sizeof(fValue));
113145256Sjkoshy
114147586Sru	return *this;
115145256Sjkoshy}
116147586Sru
117145256Sjkoshy
118145256Sjkoshybool
119145256SjkoshyBUuid::_SetToDevRandom()
120145256Sjkoshy{
121145256Sjkoshy	// open device
122145256Sjkoshy	int fd = open("/dev/urandom", O_RDONLY);
123145256Sjkoshy	if (fd < 0) {
124196446Sjkoshy		fd = open("/dev/random", O_RDONLY);
125145256Sjkoshy		if (fd < 0)
126145256Sjkoshy			return false;
127145256Sjkoshy	}
128145256Sjkoshy
129145256Sjkoshy	// read bytes
130145256Sjkoshy	ssize_t bytesRead = read(fd, fValue, sizeof(fValue));
131145256Sjkoshy	close(fd);
132145256Sjkoshy
133145256Sjkoshy	return bytesRead == (ssize_t)sizeof(fValue);
134145256Sjkoshy}
135145256Sjkoshy
136145256Sjkoshy
137145256Sjkoshyvoid
138145256SjkoshyBUuid::_SetToRandomFallback()
139145256Sjkoshy{
140145256Sjkoshy	static bool sSeedInitialized = init_random_seed();
141145256Sjkoshy	(void)sSeedInitialized;
142145256Sjkoshy
143145256Sjkoshy	for (int32 i = 0; i < 4; i++) {
144145256Sjkoshy		uint32 value = random();
145145256Sjkoshy		fValue[4 * i + 0] = uint8(value >> 24);
146145256Sjkoshy		fValue[4 * i + 1] = uint8(value >> 16);
147145256Sjkoshy		fValue[4 * i + 2] = uint8(value >> 8);
148145256Sjkoshy		fValue[4 * i + 3] = uint8(value);
149145256Sjkoshy	}
150145256Sjkoshy
151145256Sjkoshy	// random() returns 31 bit numbers only, so we move a few bits from where
152145256Sjkoshy	// we overwrite them with the version anyway.
153147586Sru	uint8 bitsToMove = fValue[kVersionByteIndex];
154145256Sjkoshy	for (int32 i = 0; i < 4; i++)
155147586Sru		fValue[4 * i] |= (bitsToMove << i) & 0x80;
156145256Sjkoshy}
157147586Sru
158145256Sjkoshy}	// namespace BPrivate
159145256Sjkoshy
160145256Sjkoshy
161145256Sjkoshyusing BPrivate::BUuid;
162147586Sru