Line data Source code
1 : /**
2 : Copyright (c) 2019-2022 Roman Katuntsev <sbkarr@stappler.org>
3 : Copyright (c) 2023 Stappler LLC <admin@stappler.dev>
4 :
5 : Permission is hereby granted, free of charge, to any person obtaining a copy
6 : of this software and associated documentation files (the "Software"), to deal
7 : in the Software without restriction, including without limitation the rights
8 : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 : copies of the Software, and to permit persons to whom the Software is
10 : furnished to do so, subject to the following conditions:
11 :
12 : The above copyright notice and this permission notice shall be included in
13 : all copies or substantial portions of the Software.
14 :
15 : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 : THE SOFTWARE.
22 : **/
23 :
24 : #include "SPMemUuid.h"
25 : #include "SPString.h"
26 : #include "SPTime.h"
27 :
28 : #include "SPPlatformUnistd.h"
29 :
30 : #if WIN32
31 : #include <winsock.h>
32 : #endif
33 :
34 : namespace STAPPLER_VERSIONIZED stappler::memory {
35 :
36 : struct UuidState {
37 25 : UuidState() {
38 : struct {
39 : pid_t pid;
40 : size_t threadId;
41 : uint64_t time;
42 : char hostname[257];
43 : } r;
44 :
45 : #if WIN32
46 : r.pid = GetCurrentProcessId();
47 : #else
48 25 : r.pid = getpid();
49 : #endif
50 25 : r.time = Time::now().toMicros();
51 :
52 : std::hash<std::thread::id> hasher;
53 25 : r.threadId = hasher(std::this_thread::get_id());
54 :
55 25 : gethostname(r.hostname, 256);
56 25 : node = stappler::string::Sha256().update(CoderSource((const uint8_t*) &r, sizeof(r))).final();
57 25 : }
58 :
59 : int seqnum = 0;
60 : stappler::string::Sha256::Buf node;
61 : };
62 :
63 : static thread_local UuidState tl_uuidState;
64 :
65 25 : static uint64_t getCurrentTime() {
66 : // time magic to convert from epoch to UUID UTC
67 25 : uint64_t time_now = (Time::now().toMicros() * 10) + 0x01B21DD213814000ULL;
68 :
69 : thread_local uint64_t time_last = 0;
70 : thread_local uint64_t fudge = 0;
71 :
72 25 : if (time_last != time_now) {
73 25 : if (time_last + fudge > time_now) {
74 0 : fudge = time_last + fudge - time_now + 1;
75 : } else {
76 25 : fudge = 0;
77 : }
78 25 : time_last = time_now;
79 : } else {
80 0 : ++fudge;
81 : }
82 :
83 25 : return time_now + fudge;
84 : }
85 :
86 25 : uuid uuid::generate() {
87 : uuid_t d;
88 25 : uint64_t timestamp = getCurrentTime();
89 :
90 : /* time_low, uint32 */
91 25 : d[3] = (unsigned char)timestamp;
92 25 : d[2] = (unsigned char)(timestamp >> 8);
93 25 : d[1] = (unsigned char)(timestamp >> 16);
94 25 : d[0] = (unsigned char)(timestamp >> 24);
95 : /* time_mid, uint16 */
96 25 : d[5] = (unsigned char)(timestamp >> 32);
97 25 : d[4] = (unsigned char)(timestamp >> 40);
98 : /* time_hi_and_version, uint16 */
99 25 : d[7] = (unsigned char)(timestamp >> 48);
100 25 : d[6] = (unsigned char)(((timestamp >> 56) & 0x0F) | 0x50);
101 : /* clock_seq_hi_and_reserved, uint8 */
102 25 : d[8] = (unsigned char)(((tl_uuidState.seqnum >> 8) & 0x3F) | 0x80);
103 : /* clock_seq_low, uint8 */
104 25 : d[9] = (unsigned char)tl_uuidState.seqnum;
105 : /* node, byte[6] */
106 25 : memcpy(&d[10], tl_uuidState.node.data(), 6);
107 :
108 50 : return uuid(d);
109 : }
110 :
111 0 : void uuid::format(char *buf, const uuid_t &d) {
112 0 : snprintf(buf, 37, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
113 0 : d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15]);
114 0 : }
115 :
116 0 : static uint8_t parse_hexpair(const char *s) {
117 : int result;
118 : int temp;
119 :
120 0 : result = s[0] - '0';
121 0 : if (result > 48) {
122 0 : result = (result - 39) << 4;
123 0 : } else if (result > 16) {
124 0 : result = (result - 7) << 4;
125 : } else {
126 0 : result = result << 4;
127 : }
128 :
129 0 : temp = s[1] - '0';
130 0 : if (temp > 48) {
131 0 : result |= temp - 39;
132 0 : } else if (temp > 16) {
133 0 : result |= temp - 7;
134 : } else {
135 0 : result |= temp;
136 : }
137 :
138 0 : return (uint8_t)result;
139 : }
140 :
141 0 : bool uuid::parse(uuid_t &d, const char *uuid_str) {
142 : int i;
143 :
144 0 : for (i = 0; i < 36; ++i) {
145 0 : char c = uuid_str[i];
146 0 : if (!isxdigit(c) && !(c == '-' && (i == 8 || i == 13 || i == 18 || i == 23))) {
147 0 : return false;
148 : }
149 : }
150 :
151 0 : if (uuid_str[36] != '\0') {
152 0 : return false;
153 : }
154 :
155 0 : d[0] = base16::hexToChar(uuid_str[0], uuid_str[1]);
156 0 : d[1] = base16::hexToChar(uuid_str[2], uuid_str[3]);
157 0 : d[2] = base16::hexToChar(uuid_str[4], uuid_str[5]);
158 0 : d[3] = base16::hexToChar(uuid_str[6], uuid_str[7]);
159 :
160 0 : d[4] = base16::hexToChar(uuid_str[9], uuid_str[10]);
161 0 : d[5] = base16::hexToChar(uuid_str[11], uuid_str[12]);
162 :
163 0 : d[6] = base16::hexToChar(uuid_str[14], uuid_str[15]);
164 0 : d[7] = base16::hexToChar(uuid_str[16], uuid_str[17]);
165 :
166 0 : d[8] = base16::hexToChar(uuid_str[19], uuid_str[20]);
167 0 : d[9] = base16::hexToChar(uuid_str[21], uuid_str[22]);
168 :
169 0 : for (i = 6; i--;) {
170 0 : d[10 + i] = parse_hexpair(&uuid_str[i*2+24]);
171 : }
172 :
173 0 : return true;
174 : }
175 :
176 : }
|