Skip to content

Commit 0ff4e66

Browse files
committed
Add support for UUID versioning and generation of UUIDv7.
This update introduces support for generating UUIDs with specific versions, including the newly implemented UUIDv7. The `create_uuid` API has been updated to accept optional version parameters. Additionally, a new utility function `switch_getentropy` was added to ensure secure random number generation.
1 parent ca5b327 commit 0ff4e66

File tree

5 files changed

+130
-7
lines changed

5 files changed

+130
-7
lines changed

src/include/switch_apr.h

+6-1
Original file line numberDiff line numberDiff line change
@@ -560,7 +560,12 @@ SWITCH_DECLARE(void) switch_uuid_format(char *buffer, const switch_uuid_t *uuid)
560560
* Generate and return a (new) UUID
561561
* @param uuid The resulting UUID
562562
*/
563-
SWITCH_DECLARE(void) switch_uuid_get(switch_uuid_t *uuid);
563+
#ifndef DEFAULT_UUID_VERSION
564+
#define DEFAULT_UUID_VERSION 4
565+
#endif
566+
SWITCH_DECLARE(switch_status_t) switch_uuid_generate_v4(switch_uuid_t *uuid);
567+
SWITCH_DECLARE(switch_status_t) switch_uuid_generate_version(switch_uuid_t *uuid, int version);
568+
#define switch_uuid_get(uuid) switch_uuid_generate_version(uuid, DEFAULT_UUID_VERSION);
564569

565570
/**
566571
* Parse a standard-format string into a UUID

src/include/switch_utils.h

+5-1
Original file line numberDiff line numberDiff line change
@@ -1421,7 +1421,8 @@ SWITCH_DECLARE(void *) switch_calloc(size_t nmemb, size_t size);
14211421
SWITCH_DECLARE(const char *) switch_inet_ntop(int af, void const *src, char *dst, size_t size);
14221422
#endif
14231423

1424-
SWITCH_DECLARE(char *) switch_uuid_str(char *buf, switch_size_t len);
1424+
#define switch_uuid_str(buf, len) switch_uuid_str_version(buf, len, DEFAULT_UUID_VERSION);
1425+
SWITCH_DECLARE(char *) switch_uuid_str_version(char *buf, switch_size_t len, int version);
14251426
SWITCH_DECLARE(char *) switch_format_number(const char *num);
14261427

14271428
SWITCH_DECLARE(unsigned int) switch_atoui(const char *nptr);
@@ -1518,6 +1519,9 @@ SWITCH_DECLARE(const char *) switch_memory_usage_stream(switch_stream_handle_t *
15181519
/ Compliant random number generator. Returns the value between 0 and 0x7fff (RAND_MAX).
15191520
**/
15201521
SWITCH_DECLARE(int) switch_rand(void);
1522+
SWITCH_DECLARE(int) switch_getentropy(void *buffer, switch_size_t length);
1523+
SWITCH_DECLARE(switch_status_t) switch_uuid_generate_v7(switch_uuid_t *uuid);
1524+
SWITCH_DECLARE(switch_status_t) switch_uuid_generate_v7(switch_uuid_t *uuid);
15211525

15221526
SWITCH_END_EXTERN_C
15231527
#endif

src/mod/applications/mod_commands/mod_commands.c

+7-2
Original file line numberDiff line numberDiff line change
@@ -3162,11 +3162,16 @@ SWITCH_STANDARD_API(tone_detect_session_function)
31623162
return SWITCH_STATUS_SUCCESS;
31633163
}
31643164

3165+
#define UUID_GENERATE_SYNTAX "<create_uuid> [4|7]"
31653166
SWITCH_STANDARD_API(uuid_function)
31663167
{
31673168
char uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1];
3169+
int version = DEFAULT_UUID_VERSION;
3170+
if (!zstr(cmd)) {
3171+
version = atoi(cmd);
3172+
}
31683173

3169-
switch_uuid_str(uuid_str, sizeof(uuid_str));
3174+
switch_uuid_str_version(uuid_str, sizeof(uuid_str), version);
31703175

31713176
stream->write_function(stream, "%s", uuid_str);
31723177
return SWITCH_STATUS_SUCCESS;
@@ -7598,7 +7603,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load)
75987603
SWITCH_ADD_API(commands_api_interface, "cond", "Evaluate a conditional", cond_function, "<expr> ? <true val> : <false val>");
75997604
SWITCH_ADD_API(commands_api_interface, "console_complete", "", console_complete_function, "<line>");
76007605
SWITCH_ADD_API(commands_api_interface, "console_complete_xml", "", console_complete_xml_function, "<line>");
7601-
SWITCH_ADD_API(commands_api_interface, "create_uuid", "Create a uuid", uuid_function, UUID_SYNTAX);
7606+
SWITCH_ADD_API(commands_api_interface, "create_uuid", "Create a uuid", uuid_function, UUID_GENERATE_SYNTAX);
76027607
SWITCH_ADD_API(commands_api_interface, "db_cache", "Manage db cache", db_cache_function, "status");
76037608
SWITCH_ADD_API(commands_api_interface, "domain_data", "Find domain data", domain_data_function, "<domain> [var|param|attr] <name>");
76047609
SWITCH_ADD_API(commands_api_interface, "domain_exists", "Check if a domain exists", domain_exists_function, "<domain>");

src/switch_apr.c

+16-1
Original file line numberDiff line numberDiff line change
@@ -1149,7 +1149,7 @@ SWITCH_DECLARE(void) switch_uuid_format(char *buffer, const switch_uuid_t *uuid)
11491149
#endif
11501150
}
11511151

1152-
SWITCH_DECLARE(void) switch_uuid_get(switch_uuid_t *uuid)
1152+
SWITCH_DECLARE(void) switch_uuid_generate_v4(switch_uuid_t *uuid)
11531153
{
11541154
switch_mutex_lock(runtime.uuid_mutex);
11551155
#ifndef WIN32
@@ -1160,6 +1160,21 @@ SWITCH_DECLARE(void) switch_uuid_get(switch_uuid_t *uuid)
11601160
switch_mutex_unlock(runtime.uuid_mutex);
11611161
}
11621162

1163+
SWITCH_DECLARE(switch_status_t) switch_uuid_generate_version(switch_uuid_t *uuid, int version)
1164+
{
1165+
switch(version) {
1166+
case 4:
1167+
switch_uuid_generate_v4(uuid);
1168+
break;
1169+
case 7:
1170+
switch_uuid_generate_v7(uuid);
1171+
break;
1172+
default:
1173+
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ERROR: Unsupported UUID version %d\n", version);
1174+
return SWITCH_STATUS_FALSE;
1175+
}
1176+
}
1177+
11631178
SWITCH_DECLARE(switch_status_t) switch_uuid_parse(switch_uuid_t *uuid, const char *uuid_str)
11641179
{
11651180
#ifndef WIN32

src/switch_utils.c

+96-2
Original file line numberDiff line numberDiff line change
@@ -4110,14 +4110,14 @@ SWITCH_DECLARE(int) switch_split_user_domain(char *in, char **user, char **domai
41104110
}
41114111

41124112

4113-
SWITCH_DECLARE(char *) switch_uuid_str(char *buf, switch_size_t len)
4113+
SWITCH_DECLARE(char *) switch_uuid_str_version(char *buf, switch_size_t len, int version)
41144114
{
41154115
switch_uuid_t uuid;
41164116

41174117
if (len < (SWITCH_UUID_FORMATTED_LENGTH + 1)) {
41184118
switch_snprintf(buf, len, "INVALID");
41194119
} else {
4120-
switch_uuid_get(&uuid);
4120+
switch_uuid_generate_version(&uuid, version);
41214121
switch_uuid_format(buf, &uuid);
41224122
}
41234123

@@ -4872,6 +4872,100 @@ SWITCH_DECLARE(int) switch_rand(void)
48724872
#endif
48734873
}
48744874

4875+
4876+
SWITCH_DECLARE(int) switch_getentropy(void *buffer, switch_size_t length)
4877+
{
4878+
if (!buffer || length > 256) { // Enforce same limit as `getentropy`
4879+
errno = EIO; // Input/Output error
4880+
return -1;
4881+
}
4882+
4883+
#ifdef WIN32
4884+
BCRYPT_ALG_HANDLE hAlgorithm = NULL;
4885+
NTSTATUS status = BCryptOpenAlgorithmProvider(&hAlgorithm, BCRYPT_RNG_ALGORITHM, NULL, 0);
4886+
4887+
if (!BCRYPT_SUCCESS(status)) {
4888+
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "BCryptOpenAlgorithmProvider failed with status %d\n", status);
4889+
errno = EIO; // Input/Output error
4890+
return -1;
4891+
}
4892+
4893+
status = BCryptGenRandom(hAlgorithm, (PUCHAR)buffer, (ULONG)length, 0);
4894+
if (!BCRYPT_SUCCESS(status)) {
4895+
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "BCryptGenRandom failed with status %d\n", status);
4896+
BCryptCloseAlgorithmProvider(hAlgorithm, 0);
4897+
errno = EIO; // Input/Output error
4898+
return -1;
4899+
}
4900+
4901+
BCryptCloseAlgorithmProvider(hAlgorithm, 0);
4902+
return 0;
4903+
4904+
#elif defined(__unix__) || defined(__APPLE__)
4905+
int random_fd = open("/dev/urandom", O_RDONLY);
4906+
switch_ssize_t result;
4907+
char error_msg[100];
4908+
4909+
if (random_fd == -1) {
4910+
strncpy(error_msg, strerror(errno), sizeof(error_msg) - 1);
4911+
error_msg[sizeof(error_msg) - 1] = '\0';
4912+
4913+
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "open failed: %s\n", error_msg);
4914+
errno = EIO; // Input/Output error
4915+
return -1;
4916+
}
4917+
4918+
result = read(random_fd, buffer, length);
4919+
if (result < 0 || (switch_size_t)result != length) {
4920+
strncpy(error_msg, strerror(errno), sizeof(error_msg) - 1);
4921+
error_msg[sizeof(error_msg) - 1] = '\0';
4922+
4923+
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "read failed: %s\n", error_msg);
4924+
close(random_fd);
4925+
errno = EIO; // Input/Output error
4926+
return -1;
4927+
}
4928+
4929+
close(random_fd);
4930+
return 0;
4931+
4932+
#else
4933+
// Fallback: Use rand() for platforms that do not support secure randomness
4934+
unsigned char *buf = (unsigned char *)buffer;
4935+
for (switch_size_t i = 0; i < length; i++) {
4936+
buf[i] = (unsigned char)(rand() & 0xFF); // Generate byte-wise randomness
4937+
}
4938+
return 0;
4939+
#endif
4940+
}
4941+
4942+
4943+
SWITCH_DECLARE(switch_status_t) switch_uuid_generate_v7(switch_uuid_t *uuid) {
4944+
/* random bytes */
4945+
unsigned char *value = uuid->data;
4946+
4947+
if (switch_getentropy(value, 16) != 0) {
4948+
return -1;
4949+
}
4950+
4951+
/* current timestamp in ms */
4952+
switch_time_t timestamp = switch_time_now() / 1000;
4953+
4954+
// timestamp
4955+
value[0] = (timestamp >> 40) & 0xFF;
4956+
value[1] = (timestamp >> 32) & 0xFF;
4957+
value[2] = (timestamp >> 24) & 0xFF;
4958+
value[3] = (timestamp >> 16) & 0xFF;
4959+
value[4] = (timestamp >> 8) & 0xFF;
4960+
value[5] = timestamp & 0xFF;
4961+
4962+
// version and variant
4963+
value[6] = (value[6] & 0x0F) | 0x70;
4964+
value[8] = (value[8] & 0x3F) | 0x80;
4965+
4966+
return SWITCH_STATUS_SUCCESS;
4967+
}
4968+
48754969
/* For Emacs:
48764970
* Local Variables:
48774971
* mode:c

0 commit comments

Comments
 (0)