]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
[core] add uuidv7 support master
authorSeven Du <dujinfang@x-y-t.cn>
Thu, 31 Jul 2025 16:38:54 +0000 (00:38 +0800)
committerGitHub <noreply@github.com>
Thu, 31 Jul 2025 16:38:54 +0000 (19:38 +0300)
13 files changed:
Makefile.am
conf/vanilla/autoload_configs/switch.conf.xml
src/include/private/switch_core_pvt.h
src/include/private/switch_uuidv7_pvt.h [new file with mode: 0644]
src/include/switch_types.h
src/mod/applications/mod_commands/mod_commands.c
src/switch_apr.c
src/switch_core.c
src/switch_uuidv7.c [new file with mode: 0644]
tests/unit/.gitignore
tests/unit/switch_core.c
tests/unit/test_switch_core.2017.vcxproj
w32/Library/FreeSwitchCore.2017.vcxproj

index 56c52d03a1186b22a0a61b197801b2d74658b1fd..7448ee128ab946a5175ad731fffb38013c8b2114 100644 (file)
@@ -394,7 +394,8 @@ libfreeswitch_la_SOURCES = \
        libs/miniupnpc/minissdpc.c \
        libs/miniupnpc/upnperrors.c \
        libs/libnatpmp/natpmp.c \
-       libs/libnatpmp/getgateway.c
+       libs/libnatpmp/getgateway.c \
+       src/switch_uuidv7.c
 
 if ENABLE_CPP
 libfreeswitch_la_SOURCES += src/switch_cpp.cpp
index 8117d8ed9cd61d9504cfac23fd31c94ad3a6626d..29ac39976f5e685e04e74cb2cea27fc1a569d820 100644 (file)
@@ -64,6 +64,9 @@
     <!-- Default Global Log Level - value is one of debug,info,notice,warning,err,crit,alert -->
     <param name="loglevel" value="debug"/>
 
+    <!-- UUID version to use, 4 or 7 -->
+    <!-- <param name="uuid-version" value="7"/> -->
+
     <!-- Set the core DEBUG level (0-10) -->
     <!-- <param name="debug-level" value="10"/> -->
 
   </settings>
 
 </configuration>
-
index fafaae3cba9b7b359badc17a1bed5c9a0682995c..7507f5dc331b2b36746d1679ea62de1fd68ca31e 100644 (file)
@@ -287,6 +287,7 @@ struct switch_runtime {
        char *event_channel_key_separator;
        uint32_t max_audio_channels;
        switch_call_cause_t shutdown_cause;
+       uint32_t uuid_version;
 };
 
 extern struct switch_runtime runtime;
diff --git a/src/include/private/switch_uuidv7_pvt.h b/src/include/private/switch_uuidv7_pvt.h
new file mode 100644 (file)
index 0000000..8526190
--- /dev/null
@@ -0,0 +1,310 @@
+/**
+ * switch_uuidv7.h UUIDv7 generation functions, copied AS IS from https://github.com/LiosK/uuidv7-h
+ * with minor fixes to make it compile with FreeSWITCH.
+ *
+ * @file
+ *
+ * uuidv7.h - Single-file C/C++ UUIDv7 Library
+ *
+ * @version   v0.1.6
+ * @author    LiosK
+ * @copyright Licensed under the Apache License, Version 2.0
+ * @see       https://github.com/LiosK/uuidv7-h
+ */
+/*
+ * Copyright 2022 LiosK
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef UUIDV7_H_BAEDKYFQ
+#define UUIDV7_H_BAEDKYFQ
+
+#include <stddef.h>
+#include <stdint.h>
+
+/**
+ * @name Status codes returned by uuidv7_generate()
+ *
+ * @{
+ */
+
+/**
+ * Indicates that the `unix_ts_ms` passed was used because no preceding UUID was
+ * specified.
+ */
+#define UUIDV7_STATUS_UNPRECEDENTED (0)
+
+/**
+ * Indicates that the `unix_ts_ms` passed was used because it was greater than
+ * the previous one.
+ */
+#define UUIDV7_STATUS_NEW_TIMESTAMP (1)
+
+/**
+ * Indicates that the counter was incremented because the `unix_ts_ms` passed
+ * was no greater than the previous one.
+ */
+#define UUIDV7_STATUS_COUNTER_INC (2)
+
+/**
+ * Indicates that the previous `unix_ts_ms` was incremented because the counter
+ * reached its maximum value.
+ */
+#define UUIDV7_STATUS_TIMESTAMP_INC (3)
+
+/**
+ * Indicates that the monotonic order of generated UUIDs was broken because the
+ * `unix_ts_ms` passed was less than the previous one by more than ten seconds.
+ */
+#define UUIDV7_STATUS_CLOCK_ROLLBACK (4)
+
+/** Indicates that an invalid `unix_ts_ms` is passed. */
+#define UUIDV7_STATUS_ERR_TIMESTAMP (-1)
+
+/**
+ * Indicates that the attempt to increment the previous `unix_ts_ms` failed
+ * because it had reached its maximum value.
+ */
+#define UUIDV7_STATUS_ERR_TIMESTAMP_OVERFLOW (-2)
+
+/** @} */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @name Low-level primitives
+ *
+ * @{
+ */
+
+/**
+ * Generates a new UUIDv7 from the given Unix time, random bytes, and previous
+ * UUID.
+ *
+ * @param uuid_out    16-byte byte array where the generated UUID is stored.
+ * @param unix_ts_ms  Current Unix time in milliseconds.
+ * @param rand_bytes  At least 10-byte byte array filled with random bytes. This
+ *                    function consumes the leading 4 bytes or the whole 10
+ *                    bytes per call depending on the conditions.
+ *                    `uuidv7_status_n_rand_consumed()` maps the return value of
+ *                    this function to the number of random bytes consumed.
+ * @param uuid_prev   16-byte byte array representing the immediately preceding
+ *                    UUID, from which the previous timestamp and counter are
+ *                    extracted. This may be NULL if the caller does not care
+ *                    the ascending order of UUIDs within the same timestamp.
+ *                    This may point to the same location as `uuid_out`; this
+ *                    function reads the value before writing.
+ * @return            One of the `UUIDV7_STATUS_*` codes that describe the
+ *                    characteristics of generated UUIDs. Callers can usually
+ *                    ignore the status unless they need to guarantee the
+ *                    monotonic order of UUIDs or fine-tune the generation
+ *                    process.
+ */
+static inline int8_t uuidv7_generate(uint8_t *uuid_out, uint64_t unix_ts_ms,
+                                     const uint8_t *rand_bytes,
+                                     const uint8_t *uuid_prev) {
+  static const uint64_t MAX_TIMESTAMP = ((uint64_t)1 << 48) - 1;
+  static const uint64_t MAX_COUNTER = ((uint64_t)1 << 42) - 1;
+  int8_t status;
+  uint64_t timestamp = 0;
+
+  if (unix_ts_ms > MAX_TIMESTAMP) {
+    return UUIDV7_STATUS_ERR_TIMESTAMP;
+  }
+
+  if (uuid_prev == NULL) {
+    status = UUIDV7_STATUS_UNPRECEDENTED;
+    timestamp = unix_ts_ms;
+  } else {
+    for (int i = 0; i < 6; i++) {
+      timestamp = (timestamp << 8) | uuid_prev[i];
+    }
+
+    if (unix_ts_ms > timestamp) {
+      status = UUIDV7_STATUS_NEW_TIMESTAMP;
+      timestamp = unix_ts_ms;
+    } else if (unix_ts_ms + 10000 < timestamp) {
+      // ignore prev if clock moves back by more than ten seconds
+      status = UUIDV7_STATUS_CLOCK_ROLLBACK;
+      timestamp = unix_ts_ms;
+    } else {
+      // increment prev counter
+      uint64_t counter = uuid_prev[6] & 0x0f; // skip ver
+      counter = (counter << 8) | uuid_prev[7];
+      counter = (counter << 6) | (uuid_prev[8] & 0x3f); // skip var
+      counter = (counter << 8) | uuid_prev[9];
+      counter = (counter << 8) | uuid_prev[10];
+      counter = (counter << 8) | uuid_prev[11];
+
+      if (counter++ < MAX_COUNTER) {
+        status = UUIDV7_STATUS_COUNTER_INC;
+        uuid_out[6] = counter >> 38; // ver + bits 0-3
+        uuid_out[7] = counter >> 30; // bits 4-11
+        uuid_out[8] = counter >> 24; // var + bits 12-17
+        uuid_out[9] = counter >> 16; // bits 18-25
+        uuid_out[10] = counter >> 8; // bits 26-33
+        uuid_out[11] = counter;      // bits 34-41
+      } else {
+        // increment prev timestamp at counter overflow
+        status = UUIDV7_STATUS_TIMESTAMP_INC;
+        timestamp++;
+        if (timestamp > MAX_TIMESTAMP) {
+          return UUIDV7_STATUS_ERR_TIMESTAMP_OVERFLOW;
+        }
+      }
+    }
+  }
+
+  uuid_out[0] = timestamp >> 40;
+  uuid_out[1] = timestamp >> 32;
+  uuid_out[2] = timestamp >> 24;
+  uuid_out[3] = timestamp >> 16;
+  uuid_out[4] = timestamp >> 8;
+  uuid_out[5] = timestamp;
+
+  for (int i = (status == UUIDV7_STATUS_COUNTER_INC) ? 12 : 6; i < 16; i++) {
+    uuid_out[i] = *rand_bytes++;
+  }
+
+  uuid_out[6] = 0x70 | (uuid_out[6] & 0x0f); // set ver
+  uuid_out[8] = 0x80 | (uuid_out[8] & 0x3f); // set var
+
+  return status;
+}
+
+/**
+ * Determines the number of random bytes consumsed by `uuidv7_generate()` from
+ * the `UUIDV7_STATUS_*` code returned.
+ *
+ * @param status  `UUIDV7_STATUS_*` code returned by `uuidv7_generate()`.
+ * @return        `4` if `status` is `UUIDV7_STATUS_COUNTER_INC` or `10`
+ *                otherwise.
+ */
+static inline int uuidv7_status_n_rand_consumed(int8_t status) {
+  return status == UUIDV7_STATUS_COUNTER_INC ? 4 : 10;
+}
+
+/**
+ * Encodes a UUID in the 8-4-4-4-12 hexadecimal string representation.
+ *
+ * @param uuid        16-byte byte array representing the UUID to encode.
+ * @param string_out  Character array where the encoded string is stored. Its
+ *                    length must be 37 (36 digits + NUL) or longer.
+ */
+static inline void uuidv7_to_string(const uint8_t *uuid, char *string_out) {
+  static const char DIGITS[] = "0123456789abcdef";
+  for (int i = 0; i < 16; i++) {
+    uint_fast8_t e = uuid[i];
+    *string_out++ = DIGITS[e >> 4];
+    *string_out++ = DIGITS[e & 15];
+    if (i == 3 || i == 5 || i == 7 || i == 9) {
+      *string_out++ = '-';
+    }
+  }
+  *string_out = '\0';
+}
+
+/**
+ * Decodes the 8-4-4-4-12 hexadecimal string representation of a UUID.
+ *
+ * @param string    37-byte (36 digits + NUL) character array representing the
+ *                  8-4-4-4-12 hexadecimal string representation.
+ * @param uuid_out  16-byte byte array where the decoded UUID is stored.
+ * @return          Zero on success or non-zero integer on failure.
+ */
+static inline int uuidv7_from_string(const char *string, uint8_t *uuid_out) {
+  for (int i = 0; i < 32; i++) {
+    char c = *string++;
+    // clang-format off
+    uint8_t x = c == '0' ?  0 : c == '1' ?  1 : c == '2' ?  2 : c == '3' ?  3
+              : c == '4' ?  4 : c == '5' ?  5 : c == '6' ?  6 : c == '7' ?  7
+              : c == '8' ?  8 : c == '9' ?  9 : c == 'a' ? 10 : c == 'b' ? 11
+              : c == 'c' ? 12 : c == 'd' ? 13 : c == 'e' ? 14 : c == 'f' ? 15
+              : c == 'A' ? 10 : c == 'B' ? 11 : c == 'C' ? 12 : c == 'D' ? 13
+              : c == 'E' ? 14 : c == 'F' ? 15 : 0xff;
+    // clang-format on
+    if (x == 0xff) {
+      return -1; // invalid digit
+    }
+
+    if ((i & 1) == 0) {
+      uuid_out[i >> 1] = x << 4; // even i => hi 4 bits
+    } else {
+      uuid_out[i >> 1] |= x; // odd i => lo 4 bits
+    }
+
+    if ((i == 7 || i == 11 || i == 15 || i == 19) && (*string++ != '-')) {
+      return -1; // invalid format
+    }
+  }
+  if (*string != '\0') {
+    return -1; // invalid length
+  }
+  return 0; // success
+}
+
+/** @} */
+
+/**
+ * @name High-level APIs that require platform integration
+ *
+ * @{
+ */
+
+/**
+ * Generates a new UUIDv7 with the current Unix time.
+ *
+ * This declaration defines the interface to generate a new UUIDv7 with the
+ * current time, default random number generator, and global shared state
+ * holding the previously generated UUID. Since this single-file library does
+ * not provide platform-specific implementations, users need to prepare a
+ * concrete implementation (if necessary) by integrating a real-time clock,
+ * cryptographically strong random number generator, and shared state storage
+ * available in the target platform.
+ *
+ * @param uuid_out  16-byte byte array where the generated UUID is stored.
+ * @return          One of the `UUIDV7_STATUS_*` codes that describe the
+ *                  characteristics of generated UUIDs or an
+ *                  implementation-dependent code. Callers can usually ignore
+ *                  the `UUIDV7_STATUS_*` code unless they need to guarantee the
+ *                  monotonic order of UUIDs or fine-tune the generation
+ *                  process. The implementation-dependent code must be out of
+ *                  the range of `int8_t` and negative if it reports an error.
+ */
+int uuidv7_new(uint8_t *uuid_out);
+
+/**
+ * Generates an 8-4-4-4-12 hexadecimal string representation of new UUIDv7.
+ *
+ * @param string_out  Character array where the encoded string is stored. Its
+ *                    length must be 37 (36 digits + NUL) or longer.
+ * @return            Return value of `uuidv7_new()`.
+ * @note              Provide a concrete `uuidv7_new()` implementation to enable
+ *                    this function.
+ */
+static inline int uuidv7_new_string(char *string_out) {
+  uint8_t uuid[16];
+  int result = uuidv7_new(uuid);
+  uuidv7_to_string(uuid, string_out);
+  return result;
+}
+
+/** @} */
+
+#ifdef __cplusplus
+} /* extern "C" { */
+#endif
+
+#endif /* #ifndef UUIDV7_H_BAEDKYFQ */
index e71570c21d4b0e5e1326f8b455a840f5f0a62041..294c64ee3f1772db90b5229301e8221808f5631a 100644 (file)
@@ -2310,7 +2310,8 @@ typedef enum {
        SCSC_SESSIONS_PEAK,
        SCSC_SESSIONS_PEAK_FIVEMIN,
        SCSC_MDNS_RESOLVE,
-       SCSC_SHUTDOWN_CAUSE
+       SCSC_SHUTDOWN_CAUSE,
+       SCSC_UUID_VERSION
 } switch_session_ctl_t;
 
 typedef enum {
index 970fa356bee467f08680ad7f03e2ba8f81fc195a..9184a78b93b4679207850dd291bb7f1eda37798e 100644 (file)
@@ -2418,7 +2418,7 @@ SWITCH_STANDARD_API(uptime_function)
        return SWITCH_STATUS_SUCCESS;
 }
 
-#define CTL_SYNTAX "[api_expansion [on|off]|recover|send_sighup|hupall|pause [inbound|outbound]|resume [inbound|outbound]|shutdown [cancel|elegant|asap|now|restart]|sps|sps_peak_reset|sync_clock|sync_clock_when_idle|reclaim_mem|max_sessions|min_dtmf_duration [num]|max_dtmf_duration [num]|default_dtmf_duration [num]|min_idle_cpu|loglevel [level]|debug_level [level]|mdns_resolve [enable|disable]]"
+#define CTL_SYNTAX "[api_expansion [on|off]|recover|send_sighup|hupall|pause [inbound|outbound]|resume [inbound|outbound]|shutdown [cancel|elegant|asap|now|restart]|uuid_version [4|7]|sps|sps_peak_reset|sync_clock|sync_clock_when_idle|reclaim_mem|max_sessions|min_dtmf_duration [num]|max_dtmf_duration [num]|default_dtmf_duration [num]|min_idle_cpu|loglevel [level]|debug_level [level]|mdns_resolve [enable|disable]]"
 SWITCH_STANDARD_API(ctl_function)
 {
        int argc;
@@ -2660,8 +2660,18 @@ SWITCH_STANDARD_API(ctl_function)
                        } else {
                                arg = 0;
                        }
+
                        switch_core_session_ctl(SCSC_SPS, &arg);
                        stream->write_function(stream, "+OK sessions per second: %d\n", arg);
+               } else if (!strcasecmp(argv[0], "uuid_version")) {
+                       if (argc > 1) {
+                               arg = atoi(argv[1]);
+                       } else {
+                               arg = 0;
+                       }
+
+                       switch_core_session_ctl(SCSC_UUID_VERSION, &arg);
+                       stream->write_function(stream, "+OK set uuid version: %d\n", arg);
                } else if (!strcasecmp(argv[0], "sync_clock")) {
                        arg = 0;
                        switch_core_session_ctl(SCSC_SYNC_CLOCK, &arg);
@@ -7809,6 +7819,9 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load)
        switch_console_set_complete("add fsctl send_sighup");
        switch_console_set_complete("add fsctl mdns_resolve disable");
        switch_console_set_complete("add fsctl mdns_resolve enable");
+       switch_console_set_complete("add fsctl uuid_version");
+       switch_console_set_complete("add fsctl uuid_version 4");
+       switch_console_set_complete("add fsctl uuid_version 7");
        switch_console_set_complete("add interface_ip auto ::console::list_interfaces");
        switch_console_set_complete("add interface_ip ipv4 ::console::list_interfaces");
        switch_console_set_complete("add interface_ip ipv6 ::console::list_interfaces");
index bd6cfdec5607370658b06d78f1df5fcd2175c477..60660d6e2ebe748a597c7749cf751e81798f9ef5 100644 (file)
@@ -90,6 +90,8 @@
 #include <uuid/uuid.h>
 #endif
 
+#include <private/switch_uuidv7_pvt.h>
+
 /* apr stubs */
 
 SWITCH_DECLARE(int) switch_status_is_timeup(int status)
@@ -1152,11 +1154,16 @@ SWITCH_DECLARE(void) switch_uuid_format(char *buffer, const switch_uuid_t *uuid)
 SWITCH_DECLARE(void) switch_uuid_get(switch_uuid_t *uuid)
 {
        switch_mutex_lock(runtime.uuid_mutex);
+       if (runtime.uuid_version == 7) {
+               uuidv7_new(uuid->data);
+       } else {
 #ifndef WIN32
-       uuid_generate(uuid->data);
+               uuid_generate(uuid->data);
 #else
-       UuidCreate((UUID *) uuid);
+               UuidCreate((UUID *)uuid);
 #endif
+       }
+
        switch_mutex_unlock(runtime.uuid_mutex);
 }
 
index 7ec10d88856ae3b9118867b10123e055876971e0..515bab35d699628bc62ed555166a9ec88c481fc8 100644 (file)
@@ -1904,6 +1904,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_init(switch_core_flag_t flags, switc
        load_mime_types();
        runtime.flags |= flags;
        runtime.sps_total = 30;
+       runtime.uuid_version = 4;
 
        *err = NULL;
 
@@ -2212,6 +2213,8 @@ static void switch_load_core_config(const char *file)
                                        switch_time_set_use_system_time(switch_true(val));
                                } else if (!strcasecmp(var, "enable-monotonic-timing")) {
                                        switch_time_set_monotonic(switch_true(val));
+                               } else if (!strcasecmp(var, "uuid-version") && !zstr(val)) {
+                                       runtime.uuid_version = atoi(val);
                                } else if (!strcasecmp(var, "enable-softtimer-timerfd")) {
                                        int ival = 0;
                                        if (val) {
@@ -2960,10 +2963,17 @@ SWITCH_DECLARE(int32_t) switch_core_session_ctl(switch_session_ctl_t cmd, void *
                if (oldintval > 0) {
                        runtime.sps_total = oldintval;
                }
+
                newintval = runtime.sps_total;
                switch_mutex_unlock(runtime.throttle_mutex);
                break;
+       case SCSC_UUID_VERSION:
+               if(oldintval > 0){
+                       runtime.uuid_version = oldintval;
+               }
 
+               newintval = runtime.uuid_version;
+               break;
        case SCSC_RECLAIM:
                switch_core_memory_reclaim_all();
                newintval = 0;
diff --git a/src/switch_uuidv7.c b/src/switch_uuidv7.c
new file mode 100644 (file)
index 0000000..09e074e
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2025-2025, Anthony Minessale II <anthm@freeswitch.org>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Seven Du <dujinfang@gmail.com>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Seven Du <dujinfang@gmail.com>
+ *
+ * switch_uuidv7.c -- UUIDv7 generation functions
+ *
+ */
+
+#include <switch.h>
+#include "private/switch_uuidv7_pvt.h"
+#ifdef __APPLE__
+#include <sys/random.h> /* for macOS getentropy() */
+#endif
+#ifdef _MSC_VER
+#include <bcrypt.h> /* for BCryptGenRandom */
+#endif
+
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)
+       #define SWITCH_THREAD_LOCAL static _Thread_local
+#else
+       /* Fallback to compiler-specific or other methods */
+       #ifdef _MSC_VER
+               #define SWITCH_THREAD_LOCAL __declspec(thread)
+       #elif defined(__GNUC__)
+               #define SWITCH_THREAD_LOCAL static __thread
+       #else
+               // #error "Compiler does not support thread-local storage"
+               #define SWITCH_THREAD_LOCAL static
+               #define SWITCH_THREAD_LOCAL_NOT_SUPPORTED
+       #endif
+#endif
+
+#ifndef SWITCH_THREAD_LOCAL_NOT_SUPPORTED
+SWITCH_THREAD_LOCAL uint8_t uuid_prev[16] = {0};
+SWITCH_THREAD_LOCAL uint8_t rand_bytes[10] = {0};
+SWITCH_THREAD_LOCAL size_t n_rand_consumed = 10;
+#endif
+
+static void switch_getentropy(unsigned char *rand_bytes, size_t n_rand_consumed) {
+#ifdef _MSC_VER
+       NTSTATUS status = BCryptGenRandom(
+               NULL,                          /* Algorithm handle (NULL for system-preferred RNG) */
+               rand_bytes,                    /* Buffer to receive random bytes */
+               (ULONG)n_rand_consumed,        /* Size of buffer in bytes */
+               BCRYPT_USE_SYSTEM_PREFERRED_RNG  /* Flag for system RNG */
+       );
+       if (status != 0) {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error generating random bytes: 0x%lx\n", status);
+       }
+#else
+       if (getentropy(rand_bytes, n_rand_consumed) != 0) {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "getentropy failed");
+       }
+#endif
+}
+
+int uuidv7_new(uint8_t *uuid_out)
+{
+       int8_t status;
+       uint64_t unix_ts_ms = switch_time_now() / 1000;
+
+#ifdef SWITCH_THREAD_LOCAL_NOT_SUPPORTED
+       size_t n_rand_consumed = 10;
+       uint8_t rand_bytes[10] = {0};
+#endif
+
+       switch_getentropy(rand_bytes, n_rand_consumed);
+#ifdef SWITCH_THREAD_LOCAL_NOT_SUPPORTED
+       status = uuidv7_generate(uuid_out, unix_ts_ms, rand_bytes, NULL);
+#else
+       status = uuidv7_generate(uuid_prev, unix_ts_ms, rand_bytes, uuid_prev);
+#endif
+       if (status < 0) {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "uuidv7_generate failed: %d\n", status);
+       } else if (status == UUIDV7_STATUS_CLOCK_ROLLBACK) {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "uuidv7_generate: clock rollback detected\n");
+       }
+
+#ifdef SWITCH_THREAD_LOCAL_NOT_SUPPORTED
+       return status;
+#else
+       n_rand_consumed = uuidv7_status_n_rand_consumed(status);
+       memcpy(uuid_out, uuid_prev, 16);
+
+       return status;
+#endif
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
+ */
index 470c5ded12a76ba3f0a9ac99fcaf4c3231500673..966fc80eb950aefc635a25a829cf9b81ca5e43d2 100644 (file)
@@ -43,6 +43,11 @@ switch_xml
 switch_estimators
 switch_jitter_buffer
 test_sofia
+switch_core_asr
+switch_core_media
+switch_sip
+switch_rtp_pcap
+test_tts_format
 .deps/
 Makefile
 conf/*/
@@ -50,4 +55,5 @@ conf_playsay/*/
 conf_async/*/
 x64
 win32
-*.vcxproj.user
\ No newline at end of file
+*.vcxproj.user
+
index 61b1cfb349c12a9276aae2f5bc25b8ab4d690320..6b4ba12e04685732b6ed8d9881f7060263b7802a 100644 (file)
 #include <switch.h>
 #include <test/switch_test.h>
 
+#include <string.h>
+#include <../../src/switch_uuidv7.c>
+
 #if defined(HAVE_OPENSSL)
 #include <openssl/ssl.h>
 #endif
 
 #define ENABLE_SNPRINTFV_TESTS 0 /* Do not turn on for CI as this requires a lot of RAM */
 
+static void *SWITCH_THREAD_FUNC test_create_uuid_thread_run(switch_thread_t *thread, void *obj)
+{
+       int *tid = (int *)obj;
+       switch_uuid_t uuid;
+       char uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1] = { 0 };
+       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "test_create_uuid: #%d\n", *tid);
+       for (int i = 0; i < 10; i++) {
+               uint8_t status = uuidv7_new(uuid.data);
+               switch_uuid_format(uuid_str, &uuid);
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "uuidv7: %s status=%d #%d thread=%lu\n", uuid_str, status, *tid, (unsigned long)switch_thread_self());
+               switch_cond_next();
+       }
+
+       return NULL;
+}
+
 FST_CORE_BEGIN("./conf")
 {
        FST_SUITE_BEGIN(switch_core)
@@ -596,6 +615,79 @@ FST_CORE_BEGIN("./conf")
                        fst_check(switch_channel_get_variable_buf(channel, "test_var_does_not_exist", buf, sizeof(buf)) == SWITCH_STATUS_FALSE);
                }
                FST_SESSION_END()
+
+               FST_TEST_BEGIN(test_create_uuid_v4_v7)
+               {
+                       switch_uuid_t uuid;
+                       char uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1] = { 0 };
+                       int version = 7;
+
+                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "test_create_uuid:\n");
+                       switch_core_session_ctl(SCSC_UUID_VERSION, &version);
+                       for (int i = 0; i < 100; i++) {
+                               uint8_t status = uuidv7_new(uuid.data);
+                               switch_uuid_format(uuid_str, &uuid);
+                               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "uuidv7: %s\n", uuid_str);
+                               fst_check(status >=0 && status < 4);
+                       }
+
+                       version = 4;
+                       switch_core_session_ctl(SCSC_UUID_VERSION, &version);
+                       switch_uuid_get(&uuid);
+                       switch_uuid_format(uuid_str, &uuid);
+                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "uuidv4: %s\n", uuid_str);
+               }
+               FST_TEST_END()
+
+               FST_TEST_BEGIN(test_create_uuid_thread)
+               {
+                       int n[10] = {0};
+                       switch_thread_t *thread[10] = {0};
+                       switch_threadattr_t *thd_attr = NULL;
+                       switch_status_t status;
+                       int version = 7;
+
+                       switch_core_session_ctl(SCSC_UUID_VERSION, &version);
+                       switch_threadattr_create(&thd_attr, fst_pool);
+                       switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
+
+                       for (int i = 0; i < sizeof(thread) / sizeof(thread[0]); i++) {
+                               n[i] = i;
+                               switch_thread_create(&thread[i], thd_attr, test_create_uuid_thread_run, &n[i], fst_pool);
+                       }
+                       for (int i = 0; i < sizeof(thread) / sizeof(thread[0]); i++) {
+                               switch_thread_join(&status, thread[i]);
+                       }
+               }
+               FST_TEST_END()
+
+               FST_TEST_BEGIN(test_create_uuid_speed)
+               {
+                       int n;
+                       int version = 4;
+
+                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "test_create_uuid_speed:\n");
+                       switch_core_session_ctl(SCSC_UUID_VERSION, &version);
+                       for (n = 1; n < 4; n++) {
+                               switch_time_t started_at = switch_time_now();
+                               double delta = 0;
+                               switch_uuid_t uuid;
+
+                               for (int i = 0; i < 1000 * pow(10, n); i++) {
+                                       uuidv7_new(uuid.data);
+                               }
+                               delta = (switch_time_now() - started_at) / 1000000.0;
+                               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%d uuidv7_new used: %f seconds\n", 1000 * (int)pow(10, n), delta);
+                               
+                               started_at = switch_time_now();
+                               for (long long int i = 0; i < 1000 * pow(10, n); i++) {
+                                       switch_uuid_get(&uuid);
+                               }
+                               delta = (switch_time_now() - started_at) / 1000000.0;
+                               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%d uuid_generate used: %f seconds\n", 1000 * (int)pow(10, n), delta);
+                       }
+               }
+               FST_TEST_END()
        }
        FST_SUITE_END()
 }
index 60a2a5049f0e2d0518340e82c2f3ba30feb260bb..d0fad221621ef25b1882da2d29ee719a971fb02c 100644 (file)
@@ -87,6 +87,9 @@
       <AdditionalIncludeDirectories>$(SolutionDir)src\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <PreprocessorDefinitions>SWITCH_TEST_BASE_DIR_FOR_CONF="..\\..\\tests\\unit\\";%(PreprocessorDefinitions)</PreprocessorDefinitions>
     </ClCompile>
+    <Link>
+      <AdditionalDependencies>Bcrypt.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
   </ItemDefinitionGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
     <BuildLog />
index dbb0d5b7d182e7d94148d33a0e76f287b73b0954..88d76d41a75cf2483e120852f1f9521e5b53038c 100644 (file)
@@ -412,6 +412,7 @@ if not exist "$(OutDir)fonts" xcopy "$(SolutionDir)fonts\*.*" "$(OutDir)fonts\"
     <ClCompile Include="..\..\src\switch_stun.c" />\r
     <ClCompile Include="..\..\src\switch_time.c" />\r
     <ClCompile Include="..\..\src\switch_utils.c" />\r
+    <ClCompile Include="..\..\src\switch_uuidv7.c" />\r
     <ClCompile Include="..\..\src\switch_vad.c" />\r
     <ClCompile Include="..\..\src\switch_version.c" />\r
     <ClCompile Include="..\..\src\switch_vpx.c" />\r
@@ -748,6 +749,7 @@ if not exist "$(OutDir)fonts" xcopy "$(SolutionDir)fonts\*.*" "$(OutDir)fonts\"
     <ClInclude Include="..\..\src\include\switch_stun.h" />\r
     <ClInclude Include="..\..\src\include\switch_types.h" />\r
     <ClInclude Include="..\..\src\include\switch_utils.h" />\r
+    <ClInclude Include="..\..\src\include\private\switch_uuidv7_pvt.h" />\r
     <ClInclude Include="..\..\src\include\switch_vad.h" />\r
     <ClInclude Include="..\..\src\include\switch_version.h" />\r
     <ClInclude Include="..\..\src\include\switch_vpx.h" />\r