blob: 4d3aa2605f614740ff7ffd4737ba7eab2de0862f [file] [log] [blame]
Austin Schuh4385b142021-03-14 21:31:13 -07001#include "aos/uuid.h"
Austin Schuh64fab802020-09-09 22:47:47 -07002
Austin Schuh20ac95d2020-12-05 17:24:19 -08003#include <fcntl.h>
4#include <sys/stat.h>
5#include <sys/types.h>
Austin Schuh60e77942022-05-16 17:48:24 -07006
Austin Schuh64fab802020-09-09 22:47:47 -07007#include <array>
8#include <random>
9#include <string_view>
10
Austin Schuh8902fa52021-03-14 22:39:24 -070011#include "gflags/gflags.h"
Austin Schuh20ac95d2020-12-05 17:24:19 -080012#include "glog/logging.h"
13
Austin Schuh8902fa52021-03-14 22:39:24 -070014DEFINE_string(boot_uuid, "",
15 "If set, override the boot UUID to have this value instead.");
16
Austin Schuh64fab802020-09-09 22:47:47 -070017namespace aos {
18namespace {
Austin Schuh5e2bfb82021-03-13 22:46:55 -080019void ToHex(const uint8_t *val, char *result, size_t count) {
20 while (count > 0) {
21 int upper = ((*val) >> 4) & 0xf;
22 if (upper < 10) {
23 result[0] = upper + '0';
24 } else {
25 result[0] = upper - 10 + 'a';
26 }
27
28 int lower = (*val) & 0xf;
29 if (lower < 10) {
30 result[1] = lower + '0';
31 } else {
32 result[1] = lower - 10 + 'a';
33 }
34
35 ++val;
36 result += 2;
37 --count;
Austin Schuh64fab802020-09-09 22:47:47 -070038 }
39}
Austin Schuh5e2bfb82021-03-13 22:46:55 -080040
41void FromHex(const char *val, uint8_t *result, size_t count) {
42 while (count > 0) {
43 CHECK((val[0] >= '0' && val[0] <= '9') || (val[0] >= 'a' && val[0] <= 'f'))
44 << ": Invalid hex '" << val[0] << "'";
45 CHECK((val[1] >= '0' && val[1] <= '9') || (val[1] >= 'a' && val[1] <= 'f'))
46 << ": Invalid hex '" << val[1] << "'";
47
48 uint8_t converted = 0;
49 if (val[0] < 'a') {
50 converted |= static_cast<uint8_t>(val[0] - '0') << 4;
51 } else {
52 converted |= (static_cast<uint8_t>(val[0] - 'a') + 0xa) << 4;
53 }
54 if (val[1] < 'a') {
55 converted |= static_cast<uint8_t>(val[1] - '0');
56 } else {
57 converted |= (static_cast<uint8_t>(val[1] - 'a') + 0xa);
58 }
59 *result = converted;
60
61 val += 2;
62 ++result;
63 --count;
64 }
65}
66
James Kuszmaul05ccb272023-07-13 10:58:14 -070067uint32_t RandomSeed() {
68 std::random_device rd;
69 return rd();
70}
Austin Schuh64fab802020-09-09 22:47:47 -070071} // namespace
72
73UUID UUID::Random() {
James Kuszmaul05ccb272023-07-13 10:58:14 -070074 // Note: This only provides 32 bits of randomness to each thread. However, by
75 // keeping persistent pseudo-random number generators, we can increase the
76 // overall randomness of each call to Random() (since, essentially, the
77 // randomness is coming from the combination of the initial seed + the number
78 // of times that Random() has been called in the given thread).
79 // TODO(james): Seed with a minimum of 128 bits of randomness, or even the
80 // full 624 bits of the internal mersenne twister state (see
81 // https://codereview.stackexchange.com/questions/109260/seed-stdmt19937-from-stdrandom-device/109266#109266).
82 //
83 // thread_local to guarantee safe use of the generator itself.
84 thread_local std::mt19937 gen(RandomSeed());
Austin Schuh64fab802020-09-09 22:47:47 -070085
Austin Schuh5e2bfb82021-03-13 22:46:55 -080086 std::uniform_int_distribution<> dis(0, 255);
Austin Schuh64fab802020-09-09 22:47:47 -070087 UUID result;
Austin Schuh5e2bfb82021-03-13 22:46:55 -080088 for (size_t i = 0; i < kDataSize; ++i) {
89 result.data_[i] = dis(gen);
90 }
Austin Schuh64fab802020-09-09 22:47:47 -070091
Austin Schuh5e2bfb82021-03-13 22:46:55 -080092 // Mark the reserved bits in the data that this is a uuid4, a random UUID.
93 result.data_[6] = (result.data_[6] & 0x0f) | 0x40;
94 result.data_[8] = (result.data_[6] & 0x3f) | 0x80;
Austin Schuh64fab802020-09-09 22:47:47 -070095
96 return result;
97}
98
Austin Schuh5e2bfb82021-03-13 22:46:55 -080099std::string UUID::ToString() const {
100 std::string out;
101 out.resize(UUID::kStringSize);
102 CopyTo(out.data());
103 return out;
104}
105
106std::ostream &operator<<(std::ostream &os, const UUID &uuid) {
107 return os << uuid.ToString();
108}
109
110flatbuffers::Offset<flatbuffers::String> UUID::PackString(
111 flatbuffers::FlatBufferBuilder *fbb) const {
112 std::array<char, kStringSize> data;
113 CopyTo(data.data());
114
115 return fbb->CreateString(data.data(), data.size());
116}
117
118flatbuffers::Offset<flatbuffers::Vector<uint8_t>> UUID::PackVector(
119 flatbuffers::FlatBufferBuilder *fbb) const {
120 return fbb->CreateVector(data_.data(), data_.size());
121}
122
123void UUID::CopyTo(char *result) const {
124 ToHex(&data_[0], result, 4);
125 result[8] = '-';
126 ToHex(&data_[4], result + 9, 2);
127 result[13] = '-';
128 ToHex(&data_[6], result + 14, 2);
129 result[18] = '-';
130 ToHex(&data_[8], result + 19, 2);
131 result[23] = '-';
132 ToHex(&data_[10], result + 24, 6);
133}
134
Austin Schuh5e2bfb82021-03-13 22:46:55 -0800135UUID UUID::FromString(const flatbuffers::String *str) {
136 return FromString(str->string_view());
137}
138
139UUID UUID::FromVector(const flatbuffers::Vector<uint8_t> *data) {
140 CHECK(data != nullptr);
141 CHECK_EQ(data->size(), kDataSize);
142
143 UUID result;
144 std::memcpy(result.data_.data(), data->Data(), kDataSize);
145 return result;
146}
Austin Schuh20ac95d2020-12-05 17:24:19 -0800147
Alexei Strots72060d62022-10-10 19:23:53 -0700148UUID UUID::FromSpan(absl::Span<const uint8_t> data) {
149 CHECK_EQ(data.size(), kDataSize);
150
151 UUID result;
152 std::copy(data.begin(), data.end(), result.data_.begin());
153 return result;
154}
155
Austin Schuh20ac95d2020-12-05 17:24:19 -0800156UUID UUID::FromString(std::string_view str) {
Austin Schuh5e2bfb82021-03-13 22:46:55 -0800157 CHECK_EQ(str.size(), kStringSize);
Austin Schuh20ac95d2020-12-05 17:24:19 -0800158
Austin Schuh5e2bfb82021-03-13 22:46:55 -0800159 UUID result;
160 FromHex(str.data(), result.data_.data(), 4);
161 CHECK(str.data()[8] == '-' && str.data()[13] == '-' &&
162 str.data()[18] == '-' && str.data()[23] == '-')
163 << ": Invalid uuid.";
164 FromHex(str.data() + 9, result.data_.data() + 4, 2);
165 FromHex(str.data() + 14, result.data_.data() + 6, 2);
166 FromHex(str.data() + 19, result.data_.data() + 8, 2);
167 FromHex(str.data() + 24, result.data_.data() + 10, 6);
Austin Schuh20ac95d2020-12-05 17:24:19 -0800168 return result;
169}
170
171UUID UUID::BootUUID() {
Austin Schuh8902fa52021-03-14 22:39:24 -0700172 if (!FLAGS_boot_uuid.empty()) {
173 return UUID::FromString(FLAGS_boot_uuid);
174 }
175
Austin Schuh20ac95d2020-12-05 17:24:19 -0800176 int fd = open("/proc/sys/kernel/random/boot_id", O_RDONLY);
177 PCHECK(fd != -1);
178
Austin Schuh5e2bfb82021-03-13 22:46:55 -0800179 std::array<char, kStringSize> data;
180 CHECK_EQ(static_cast<ssize_t>(kStringSize),
181 read(fd, data.begin(), kStringSize));
Austin Schuh20ac95d2020-12-05 17:24:19 -0800182 close(fd);
183
Austin Schuh5e2bfb82021-03-13 22:46:55 -0800184 return UUID::FromString(std::string_view(data.data(), data.size()));
Brian Silverman1f345222020-09-24 21:14:48 -0700185}
186
Austin Schuh64fab802020-09-09 22:47:47 -0700187} // namespace aos