Skip to content

Commit 10919d9

Browse files
committed
[core] add uuidv7 support
squash me: update to latest upstream
1 parent 6a25584 commit 10919d9

File tree

11 files changed

+512
-8
lines changed

11 files changed

+512
-8
lines changed

Makefile.am

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,7 @@ library_include_HEADERS = \
300300
libs/libteletone/src/libteletone_detect.h \
301301
libs/libteletone/src/libteletone_generate.h \
302302
libs/libteletone/src/libteletone.h \
303+
src/include/switch_uuidv7.h \
303304
src/include/switch_limit.h \
304305
src/include/switch_odbc.h \
305306
src/include/switch_hashtable.h \
@@ -394,7 +395,8 @@ libfreeswitch_la_SOURCES = \
394395
libs/miniupnpc/minissdpc.c \
395396
libs/miniupnpc/upnperrors.c \
396397
libs/libnatpmp/natpmp.c \
397-
libs/libnatpmp/getgateway.c
398+
libs/libnatpmp/getgateway.c \
399+
src/switch_uuidv7.c
398400

399401
if ENABLE_CPP
400402
libfreeswitch_la_SOURCES += src/switch_cpp.cpp
@@ -810,4 +812,3 @@ support:
810812
@cp support-d/.screenrc ~
811813
@cp support-d/.bashrc ~
812814
@test -f ~/.cc-mode-installed || sh support-d/install-cc-mode.sh && touch ~/.cc-mode-installed
813-

conf/vanilla/autoload_configs/switch.conf.xml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@
6464
<!-- Default Global Log Level - value is one of debug,info,notice,warning,err,crit,alert -->
6565
<param name="loglevel" value="debug"/>
6666

67+
<!-- UUID version to use, 4 or 7 -->
68+
<!-- <param name="uuid-version" value="7"/> -->
69+
6770
<!-- Set the core DEBUG level (0-10) -->
6871
<!-- <param name="debug-level" value="10"/> -->
6972

@@ -206,4 +209,3 @@
206209
</settings>
207210

208211
</configuration>
209-

src/include/private/switch_core_pvt.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,7 @@ struct switch_runtime {
287287
char *event_channel_key_separator;
288288
uint32_t max_audio_channels;
289289
switch_call_cause_t shutdown_cause;
290+
uint32_t uuid_version;
290291
};
291292

292293
extern struct switch_runtime runtime;

src/include/switch_types.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2310,7 +2310,8 @@ typedef enum {
23102310
SCSC_SESSIONS_PEAK,
23112311
SCSC_SESSIONS_PEAK_FIVEMIN,
23122312
SCSC_MDNS_RESOLVE,
2313-
SCSC_SHUTDOWN_CAUSE
2313+
SCSC_SHUTDOWN_CAUSE,
2314+
SCSC_UUID_VERSION
23142315
} switch_session_ctl_t;
23152316

23162317
typedef enum {

src/include/switch_uuidv7.h

Lines changed: 310 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,310 @@
1+
/**
2+
* switch_uuidv7.h UUIDv7 generation functions, copied AS IS from https://github.com/LiosK/uuidv7-h
3+
* with minor fixes to make it compile with FreeSWITCH.
4+
*
5+
* @file
6+
*
7+
* uuidv7.h - Single-file C/C++ UUIDv7 Library
8+
*
9+
* @version v0.1.6
10+
* @author LiosK
11+
* @copyright Licensed under the Apache License, Version 2.0
12+
* @see https://github.com/LiosK/uuidv7-h
13+
*/
14+
/*
15+
* Copyright 2022 LiosK
16+
*
17+
* Licensed under the Apache License, Version 2.0 (the "License");
18+
* you may not use this file except in compliance with the License.
19+
* You may obtain a copy of the License at
20+
*
21+
* http://www.apache.org/licenses/LICENSE-2.0
22+
*
23+
* Unless required by applicable law or agreed to in writing, software
24+
* distributed under the License is distributed on an "AS IS" BASIS,
25+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
26+
* See the License for the specific language governing permissions and
27+
* limitations under the License.
28+
*/
29+
#ifndef UUIDV7_H_BAEDKYFQ
30+
#define UUIDV7_H_BAEDKYFQ
31+
32+
#include <stddef.h>
33+
#include <stdint.h>
34+
35+
/**
36+
* @name Status codes returned by uuidv7_generate()
37+
*
38+
* @{
39+
*/
40+
41+
/**
42+
* Indicates that the `unix_ts_ms` passed was used because no preceding UUID was
43+
* specified.
44+
*/
45+
#define UUIDV7_STATUS_UNPRECEDENTED (0)
46+
47+
/**
48+
* Indicates that the `unix_ts_ms` passed was used because it was greater than
49+
* the previous one.
50+
*/
51+
#define UUIDV7_STATUS_NEW_TIMESTAMP (1)
52+
53+
/**
54+
* Indicates that the counter was incremented because the `unix_ts_ms` passed
55+
* was no greater than the previous one.
56+
*/
57+
#define UUIDV7_STATUS_COUNTER_INC (2)
58+
59+
/**
60+
* Indicates that the previous `unix_ts_ms` was incremented because the counter
61+
* reached its maximum value.
62+
*/
63+
#define UUIDV7_STATUS_TIMESTAMP_INC (3)
64+
65+
/**
66+
* Indicates that the monotonic order of generated UUIDs was broken because the
67+
* `unix_ts_ms` passed was less than the previous one by more than ten seconds.
68+
*/
69+
#define UUIDV7_STATUS_CLOCK_ROLLBACK (4)
70+
71+
/** Indicates that an invalid `unix_ts_ms` is passed. */
72+
#define UUIDV7_STATUS_ERR_TIMESTAMP (-1)
73+
74+
/**
75+
* Indicates that the attempt to increment the previous `unix_ts_ms` failed
76+
* because it had reached its maximum value.
77+
*/
78+
#define UUIDV7_STATUS_ERR_TIMESTAMP_OVERFLOW (-2)
79+
80+
/** @} */
81+
82+
#ifdef __cplusplus
83+
extern "C" {
84+
#endif
85+
86+
/**
87+
* @name Low-level primitives
88+
*
89+
* @{
90+
*/
91+
92+
/**
93+
* Generates a new UUIDv7 from the given Unix time, random bytes, and previous
94+
* UUID.
95+
*
96+
* @param uuid_out 16-byte byte array where the generated UUID is stored.
97+
* @param unix_ts_ms Current Unix time in milliseconds.
98+
* @param rand_bytes At least 10-byte byte array filled with random bytes. This
99+
* function consumes the leading 4 bytes or the whole 10
100+
* bytes per call depending on the conditions.
101+
* `uuidv7_status_n_rand_consumed()` maps the return value of
102+
* this function to the number of random bytes consumed.
103+
* @param uuid_prev 16-byte byte array representing the immediately preceding
104+
* UUID, from which the previous timestamp and counter are
105+
* extracted. This may be NULL if the caller does not care
106+
* the ascending order of UUIDs within the same timestamp.
107+
* This may point to the same location as `uuid_out`; this
108+
* function reads the value before writing.
109+
* @return One of the `UUIDV7_STATUS_*` codes that describe the
110+
* characteristics of generated UUIDs. Callers can usually
111+
* ignore the status unless they need to guarantee the
112+
* monotonic order of UUIDs or fine-tune the generation
113+
* process.
114+
*/
115+
static inline int8_t uuidv7_generate(uint8_t *uuid_out, uint64_t unix_ts_ms,
116+
const uint8_t *rand_bytes,
117+
const uint8_t *uuid_prev) {
118+
static const uint64_t MAX_TIMESTAMP = ((uint64_t)1 << 48) - 1;
119+
static const uint64_t MAX_COUNTER = ((uint64_t)1 << 42) - 1;
120+
int8_t status;
121+
uint64_t timestamp = 0;
122+
123+
if (unix_ts_ms > MAX_TIMESTAMP) {
124+
return UUIDV7_STATUS_ERR_TIMESTAMP;
125+
}
126+
127+
if (uuid_prev == NULL) {
128+
status = UUIDV7_STATUS_UNPRECEDENTED;
129+
timestamp = unix_ts_ms;
130+
} else {
131+
for (int i = 0; i < 6; i++) {
132+
timestamp = (timestamp << 8) | uuid_prev[i];
133+
}
134+
135+
if (unix_ts_ms > timestamp) {
136+
status = UUIDV7_STATUS_NEW_TIMESTAMP;
137+
timestamp = unix_ts_ms;
138+
} else if (unix_ts_ms + 10000 < timestamp) {
139+
// ignore prev if clock moves back by more than ten seconds
140+
status = UUIDV7_STATUS_CLOCK_ROLLBACK;
141+
timestamp = unix_ts_ms;
142+
} else {
143+
// increment prev counter
144+
uint64_t counter = uuid_prev[6] & 0x0f; // skip ver
145+
counter = (counter << 8) | uuid_prev[7];
146+
counter = (counter << 6) | (uuid_prev[8] & 0x3f); // skip var
147+
counter = (counter << 8) | uuid_prev[9];
148+
counter = (counter << 8) | uuid_prev[10];
149+
counter = (counter << 8) | uuid_prev[11];
150+
151+
if (counter++ < MAX_COUNTER) {
152+
status = UUIDV7_STATUS_COUNTER_INC;
153+
uuid_out[6] = counter >> 38; // ver + bits 0-3
154+
uuid_out[7] = counter >> 30; // bits 4-11
155+
uuid_out[8] = counter >> 24; // var + bits 12-17
156+
uuid_out[9] = counter >> 16; // bits 18-25
157+
uuid_out[10] = counter >> 8; // bits 26-33
158+
uuid_out[11] = counter; // bits 34-41
159+
} else {
160+
// increment prev timestamp at counter overflow
161+
status = UUIDV7_STATUS_TIMESTAMP_INC;
162+
timestamp++;
163+
if (timestamp > MAX_TIMESTAMP) {
164+
return UUIDV7_STATUS_ERR_TIMESTAMP_OVERFLOW;
165+
}
166+
}
167+
}
168+
}
169+
170+
uuid_out[0] = timestamp >> 40;
171+
uuid_out[1] = timestamp >> 32;
172+
uuid_out[2] = timestamp >> 24;
173+
uuid_out[3] = timestamp >> 16;
174+
uuid_out[4] = timestamp >> 8;
175+
uuid_out[5] = timestamp;
176+
177+
for (int i = (status == UUIDV7_STATUS_COUNTER_INC) ? 12 : 6; i < 16; i++) {
178+
uuid_out[i] = *rand_bytes++;
179+
}
180+
181+
uuid_out[6] = 0x70 | (uuid_out[6] & 0x0f); // set ver
182+
uuid_out[8] = 0x80 | (uuid_out[8] & 0x3f); // set var
183+
184+
return status;
185+
}
186+
187+
/**
188+
* Determines the number of random bytes consumsed by `uuidv7_generate()` from
189+
* the `UUIDV7_STATUS_*` code returned.
190+
*
191+
* @param status `UUIDV7_STATUS_*` code returned by `uuidv7_generate()`.
192+
* @return `4` if `status` is `UUIDV7_STATUS_COUNTER_INC` or `10`
193+
* otherwise.
194+
*/
195+
static inline int uuidv7_status_n_rand_consumed(int8_t status) {
196+
return status == UUIDV7_STATUS_COUNTER_INC ? 4 : 10;
197+
}
198+
199+
/**
200+
* Encodes a UUID in the 8-4-4-4-12 hexadecimal string representation.
201+
*
202+
* @param uuid 16-byte byte array representing the UUID to encode.
203+
* @param string_out Character array where the encoded string is stored. Its
204+
* length must be 37 (36 digits + NUL) or longer.
205+
*/
206+
static inline void uuidv7_to_string(const uint8_t *uuid, char *string_out) {
207+
static const char DIGITS[] = "0123456789abcdef";
208+
for (int i = 0; i < 16; i++) {
209+
uint_fast8_t e = uuid[i];
210+
*string_out++ = DIGITS[e >> 4];
211+
*string_out++ = DIGITS[e & 15];
212+
if (i == 3 || i == 5 || i == 7 || i == 9) {
213+
*string_out++ = '-';
214+
}
215+
}
216+
*string_out = '\0';
217+
}
218+
219+
/**
220+
* Decodes the 8-4-4-4-12 hexadecimal string representation of a UUID.
221+
*
222+
* @param string 37-byte (36 digits + NUL) character array representing the
223+
* 8-4-4-4-12 hexadecimal string representation.
224+
* @param uuid_out 16-byte byte array where the decoded UUID is stored.
225+
* @return Zero on success or non-zero integer on failure.
226+
*/
227+
static inline int uuidv7_from_string(const char *string, uint8_t *uuid_out) {
228+
for (int i = 0; i < 32; i++) {
229+
char c = *string++;
230+
// clang-format off
231+
uint8_t x = c == '0' ? 0 : c == '1' ? 1 : c == '2' ? 2 : c == '3' ? 3
232+
: c == '4' ? 4 : c == '5' ? 5 : c == '6' ? 6 : c == '7' ? 7
233+
: c == '8' ? 8 : c == '9' ? 9 : c == 'a' ? 10 : c == 'b' ? 11
234+
: c == 'c' ? 12 : c == 'd' ? 13 : c == 'e' ? 14 : c == 'f' ? 15
235+
: c == 'A' ? 10 : c == 'B' ? 11 : c == 'C' ? 12 : c == 'D' ? 13
236+
: c == 'E' ? 14 : c == 'F' ? 15 : 0xff;
237+
// clang-format on
238+
if (x == 0xff) {
239+
return -1; // invalid digit
240+
}
241+
242+
if ((i & 1) == 0) {
243+
uuid_out[i >> 1] = x << 4; // even i => hi 4 bits
244+
} else {
245+
uuid_out[i >> 1] |= x; // odd i => lo 4 bits
246+
}
247+
248+
if ((i == 7 || i == 11 || i == 15 || i == 19) && (*string++ != '-')) {
249+
return -1; // invalid format
250+
}
251+
}
252+
if (*string != '\0') {
253+
return -1; // invalid length
254+
}
255+
return 0; // success
256+
}
257+
258+
/** @} */
259+
260+
/**
261+
* @name High-level APIs that require platform integration
262+
*
263+
* @{
264+
*/
265+
266+
/**
267+
* Generates a new UUIDv7 with the current Unix time.
268+
*
269+
* This declaration defines the interface to generate a new UUIDv7 with the
270+
* current time, default random number generator, and global shared state
271+
* holding the previously generated UUID. Since this single-file library does
272+
* not provide platform-specific implementations, users need to prepare a
273+
* concrete implementation (if necessary) by integrating a real-time clock,
274+
* cryptographically strong random number generator, and shared state storage
275+
* available in the target platform.
276+
*
277+
* @param uuid_out 16-byte byte array where the generated UUID is stored.
278+
* @return One of the `UUIDV7_STATUS_*` codes that describe the
279+
* characteristics of generated UUIDs or an
280+
* implementation-dependent code. Callers can usually ignore
281+
* the `UUIDV7_STATUS_*` code unless they need to guarantee the
282+
* monotonic order of UUIDs or fine-tune the generation
283+
* process. The implementation-dependent code must be out of
284+
* the range of `int8_t` and negative if it reports an error.
285+
*/
286+
int uuidv7_new(uint8_t *uuid_out);
287+
288+
/**
289+
* Generates an 8-4-4-4-12 hexadecimal string representation of new UUIDv7.
290+
*
291+
* @param string_out Character array where the encoded string is stored. Its
292+
* length must be 37 (36 digits + NUL) or longer.
293+
* @return Return value of `uuidv7_new()`.
294+
* @note Provide a concrete `uuidv7_new()` implementation to enable
295+
* this function.
296+
*/
297+
static inline int uuidv7_new_string(char *string_out) {
298+
uint8_t uuid[16];
299+
int result = uuidv7_new(uuid);
300+
uuidv7_to_string(uuid, string_out);
301+
return result;
302+
}
303+
304+
/** @} */
305+
306+
#ifdef __cplusplus
307+
} /* extern "C" { */
308+
#endif
309+
310+
#endif /* #ifndef UUIDV7_H_BAEDKYFQ */

0 commit comments

Comments
 (0)