blob: 9da2cbfc3ac3f5f7d79a17887f4479d90c388435 [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
Austin Schuh64fab802020-09-09 22:47:47 -070067} // namespace
68
James Kuszmaula791b762023-07-13 14:56:21 -070069namespace internal {
70std::mt19937 FullySeededRandomGenerator() {
71 // Total bits that the mt19937 has internally that we could plausibly
72 // initialize with.
73 // The internal state ends up being ~1200 bytes, which is significantly more
74 // than the 128 bits we want for UUIDs, but since we should only need to
75 // generate this randomness once, it should be fine.
76 // If the performance cost ends up causing issues, then we can revisit the
77 // need to *fully* seed the twister.
78 constexpr size_t kInternalEntropy =
79 std::mt19937::state_size * sizeof(std::mt19937::result_type);
80 // Number, rounded up, of random values required.
81 constexpr size_t kSeedsRequired =
82 ((kInternalEntropy - 1) / sizeof(std::random_device::result_type)) + 1;
83 std::random_device random_device;
84// Older LLVM libstdc++'s just return 0 for the random device entropy.
85#if !defined(__clang__) || (__clang_major__ > 13)
86 CHECK_EQ(sizeof(std::random_device::result_type) * 8, random_device.entropy())
87 << ": Does your random_device actually support generating entropy?";
88#endif
89 std::array<std::random_device::result_type, kSeedsRequired> random_data;
90 std::generate(std::begin(random_data), std::end(random_data),
91 std::ref(random_device));
92 std::seed_seq seeds(std::begin(random_data), std::end(random_data));
93 return std::mt19937(seeds);
94}
95} // namespace internal
96
Austin Schuh64fab802020-09-09 22:47:47 -070097UUID UUID::Random() {
James Kuszmaul05ccb272023-07-13 10:58:14 -070098 // Note: This only provides 32 bits of randomness to each thread. However, by
99 // keeping persistent pseudo-random number generators, we can increase the
100 // overall randomness of each call to Random() (since, essentially, the
101 // randomness is coming from the combination of the initial seed + the number
102 // of times that Random() has been called in the given thread).
James Kuszmaul05ccb272023-07-13 10:58:14 -0700103 //
104 // thread_local to guarantee safe use of the generator itself.
James Kuszmaula791b762023-07-13 14:56:21 -0700105 thread_local std::mt19937 gen(internal::FullySeededRandomGenerator());
Austin Schuh64fab802020-09-09 22:47:47 -0700106
Austin Schuh5e2bfb82021-03-13 22:46:55 -0800107 std::uniform_int_distribution<> dis(0, 255);
Austin Schuh64fab802020-09-09 22:47:47 -0700108 UUID result;
Austin Schuh5e2bfb82021-03-13 22:46:55 -0800109 for (size_t i = 0; i < kDataSize; ++i) {
110 result.data_[i] = dis(gen);
111 }
Austin Schuh64fab802020-09-09 22:47:47 -0700112
Austin Schuh5e2bfb82021-03-13 22:46:55 -0800113 // Mark the reserved bits in the data that this is a uuid4, a random UUID.
114 result.data_[6] = (result.data_[6] & 0x0f) | 0x40;
115 result.data_[8] = (result.data_[6] & 0x3f) | 0x80;
Austin Schuh64fab802020-09-09 22:47:47 -0700116
117 return result;
118}
119
Austin Schuh5e2bfb82021-03-13 22:46:55 -0800120std::string UUID::ToString() const {
121 std::string out;
122 out.resize(UUID::kStringSize);
123 CopyTo(out.data());
124 return out;
125}
126
127std::ostream &operator<<(std::ostream &os, const UUID &uuid) {
128 return os << uuid.ToString();
129}
130
131flatbuffers::Offset<flatbuffers::String> UUID::PackString(
132 flatbuffers::FlatBufferBuilder *fbb) const {
133 std::array<char, kStringSize> data;
134 CopyTo(data.data());
135
136 return fbb->CreateString(data.data(), data.size());
137}
138
139flatbuffers::Offset<flatbuffers::Vector<uint8_t>> UUID::PackVector(
140 flatbuffers::FlatBufferBuilder *fbb) const {
141 return fbb->CreateVector(data_.data(), data_.size());
142}
143
144void UUID::CopyTo(char *result) const {
145 ToHex(&data_[0], result, 4);
146 result[8] = '-';
147 ToHex(&data_[4], result + 9, 2);
148 result[13] = '-';
149 ToHex(&data_[6], result + 14, 2);
150 result[18] = '-';
151 ToHex(&data_[8], result + 19, 2);
152 result[23] = '-';
153 ToHex(&data_[10], result + 24, 6);
154}
155
Austin Schuh5e2bfb82021-03-13 22:46:55 -0800156UUID UUID::FromString(const flatbuffers::String *str) {
157 return FromString(str->string_view());
158}
159
160UUID UUID::FromVector(const flatbuffers::Vector<uint8_t> *data) {
161 CHECK(data != nullptr);
162 CHECK_EQ(data->size(), kDataSize);
163
164 UUID result;
165 std::memcpy(result.data_.data(), data->Data(), kDataSize);
166 return result;
167}
Austin Schuh20ac95d2020-12-05 17:24:19 -0800168
Alexei Strots72060d62022-10-10 19:23:53 -0700169UUID UUID::FromSpan(absl::Span<const uint8_t> data) {
170 CHECK_EQ(data.size(), kDataSize);
171
172 UUID result;
173 std::copy(data.begin(), data.end(), result.data_.begin());
174 return result;
175}
176
Austin Schuh20ac95d2020-12-05 17:24:19 -0800177UUID UUID::FromString(std::string_view str) {
Austin Schuh5e2bfb82021-03-13 22:46:55 -0800178 CHECK_EQ(str.size(), kStringSize);
Austin Schuh20ac95d2020-12-05 17:24:19 -0800179
Austin Schuh5e2bfb82021-03-13 22:46:55 -0800180 UUID result;
181 FromHex(str.data(), result.data_.data(), 4);
182 CHECK(str.data()[8] == '-' && str.data()[13] == '-' &&
183 str.data()[18] == '-' && str.data()[23] == '-')
184 << ": Invalid uuid.";
185 FromHex(str.data() + 9, result.data_.data() + 4, 2);
186 FromHex(str.data() + 14, result.data_.data() + 6, 2);
187 FromHex(str.data() + 19, result.data_.data() + 8, 2);
188 FromHex(str.data() + 24, result.data_.data() + 10, 6);
Austin Schuh20ac95d2020-12-05 17:24:19 -0800189 return result;
190}
191
192UUID UUID::BootUUID() {
Austin Schuh8902fa52021-03-14 22:39:24 -0700193 if (!FLAGS_boot_uuid.empty()) {
194 return UUID::FromString(FLAGS_boot_uuid);
195 }
196
Austin Schuh20ac95d2020-12-05 17:24:19 -0800197 int fd = open("/proc/sys/kernel/random/boot_id", O_RDONLY);
198 PCHECK(fd != -1);
199
Austin Schuh5e2bfb82021-03-13 22:46:55 -0800200 std::array<char, kStringSize> data;
201 CHECK_EQ(static_cast<ssize_t>(kStringSize),
202 read(fd, data.begin(), kStringSize));
Austin Schuh20ac95d2020-12-05 17:24:19 -0800203 close(fd);
204
Austin Schuh5e2bfb82021-03-13 22:46:55 -0800205 return UUID::FromString(std::string_view(data.data(), data.size()));
Brian Silverman1f345222020-09-24 21:14:48 -0700206}
207
Austin Schuh64fab802020-09-09 22:47:47 -0700208} // namespace aos