Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[core] Add support for UUID versioning and generation of UUIDv7. #2734

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion src/include/switch_apr.h
Original file line number Diff line number Diff line change
Expand Up @@ -560,7 +560,12 @@ SWITCH_DECLARE(void) switch_uuid_format(char *buffer, const switch_uuid_t *uuid)
* Generate and return a (new) UUID
* @param uuid The resulting UUID
*/
SWITCH_DECLARE(void) switch_uuid_get(switch_uuid_t *uuid);
#ifndef DEFAULT_UUID_VERSION
#define DEFAULT_UUID_VERSION 4
#endif
SWITCH_DECLARE(switch_status_t) switch_uuid_generate_v4(switch_uuid_t *uuid);
SWITCH_DECLARE(switch_status_t) switch_uuid_generate_version(switch_uuid_t *uuid, int version);
#define switch_uuid_get(uuid) switch_uuid_generate_version(uuid, DEFAULT_UUID_VERSION);

/**
* Parse a standard-format string into a UUID
Expand Down
5 changes: 4 additions & 1 deletion src/include/switch_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -1421,7 +1421,8 @@ SWITCH_DECLARE(void *) switch_calloc(size_t nmemb, size_t size);
SWITCH_DECLARE(const char *) switch_inet_ntop(int af, void const *src, char *dst, size_t size);
#endif

SWITCH_DECLARE(char *) switch_uuid_str(char *buf, switch_size_t len);
#define switch_uuid_str(buf, len) switch_uuid_str_version(buf, len, DEFAULT_UUID_VERSION);
SWITCH_DECLARE(char *) switch_uuid_str_version(char *buf, switch_size_t len, int version);
SWITCH_DECLARE(char *) switch_format_number(const char *num);

SWITCH_DECLARE(unsigned int) switch_atoui(const char *nptr);
Expand Down Expand Up @@ -1518,6 +1519,8 @@ SWITCH_DECLARE(const char *) switch_memory_usage_stream(switch_stream_handle_t *
/ Compliant random number generator. Returns the value between 0 and 0x7fff (RAND_MAX).
**/
SWITCH_DECLARE(int) switch_rand(void);
SWITCH_DECLARE(int) switch_getentropy(void *buffer, switch_size_t length);
SWITCH_DECLARE(switch_status_t) switch_uuid_generate_v7(switch_uuid_t *uuid);

SWITCH_END_EXTERN_C
#endif
Expand Down
9 changes: 7 additions & 2 deletions src/mod/applications/mod_commands/mod_commands.c
Original file line number Diff line number Diff line change
Expand Up @@ -3162,11 +3162,16 @@ SWITCH_STANDARD_API(tone_detect_session_function)
return SWITCH_STATUS_SUCCESS;
}

#define UUID_GENERATE_SYNTAX "<create_uuid> [4|7]"
SWITCH_STANDARD_API(uuid_function)
{
char uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1];
int version = DEFAULT_UUID_VERSION;
if (!zstr(cmd)) {
version = atoi(cmd);
}

switch_uuid_str(uuid_str, sizeof(uuid_str));
switch_uuid_str_version(uuid_str, sizeof(uuid_str), version);

stream->write_function(stream, "%s", uuid_str);
return SWITCH_STATUS_SUCCESS;
Expand Down Expand Up @@ -7598,7 +7603,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load)
SWITCH_ADD_API(commands_api_interface, "cond", "Evaluate a conditional", cond_function, "<expr> ? <true val> : <false val>");
SWITCH_ADD_API(commands_api_interface, "console_complete", "", console_complete_function, "<line>");
SWITCH_ADD_API(commands_api_interface, "console_complete_xml", "", console_complete_xml_function, "<line>");
SWITCH_ADD_API(commands_api_interface, "create_uuid", "Create a uuid", uuid_function, UUID_SYNTAX);
SWITCH_ADD_API(commands_api_interface, "create_uuid", "Create a uuid", uuid_function, UUID_GENERATE_SYNTAX);
SWITCH_ADD_API(commands_api_interface, "db_cache", "Manage db cache", db_cache_function, "status");
SWITCH_ADD_API(commands_api_interface, "domain_data", "Find domain data", domain_data_function, "<domain> [var|param|attr] <name>");
SWITCH_ADD_API(commands_api_interface, "domain_exists", "Check if a domain exists", domain_exists_function, "<domain>");
Expand Down
19 changes: 18 additions & 1 deletion src/switch_apr.c
Original file line number Diff line number Diff line change
Expand Up @@ -1149,7 +1149,7 @@ SWITCH_DECLARE(void) switch_uuid_format(char *buffer, const switch_uuid_t *uuid)
#endif
}

SWITCH_DECLARE(void) switch_uuid_get(switch_uuid_t *uuid)
SWITCH_DECLARE(switch_status_t) switch_uuid_generate_v4(switch_uuid_t *uuid)
{
switch_mutex_lock(runtime.uuid_mutex);
#ifndef WIN32
Expand All @@ -1158,6 +1158,23 @@ SWITCH_DECLARE(void) switch_uuid_get(switch_uuid_t *uuid)
UuidCreate((UUID *) uuid);
#endif
switch_mutex_unlock(runtime.uuid_mutex);

return SWITCH_STATUS_SUCCESS;
}

SWITCH_DECLARE(switch_status_t) switch_uuid_generate_version(switch_uuid_t *uuid, int version)
{
switch(version) {
case 4:
return switch_uuid_generate_v4(uuid);
break;
case 7:
return switch_uuid_generate_v7(uuid);
break;
default:
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ERROR: Unsupported UUID version %d\n", version);
return SWITCH_STATUS_FALSE;
}
}

SWITCH_DECLARE(switch_status_t) switch_uuid_parse(switch_uuid_t *uuid, const char *uuid_str)
Expand Down
104 changes: 102 additions & 2 deletions src/switch_utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -4110,14 +4110,15 @@ SWITCH_DECLARE(int) switch_split_user_domain(char *in, char **user, char **domai
}


SWITCH_DECLARE(char *) switch_uuid_str(char *buf, switch_size_t len)
SWITCH_DECLARE(char *) switch_uuid_str_version(char *buf, switch_size_t len, int version)
{
switch_uuid_t uuid;

if (len < (SWITCH_UUID_FORMATTED_LENGTH + 1)) {
switch_snprintf(buf, len, "INVALID");
} else if (switch_uuid_generate_version(&uuid, version) != SWITCH_STATUS_SUCCESS) {
switch_snprintf(buf, len, "INVALID");
} else {
switch_uuid_get(&uuid);
switch_uuid_format(buf, &uuid);
}

Expand Down Expand Up @@ -4872,6 +4873,105 @@ SWITCH_DECLARE(int) switch_rand(void)
#endif
}


static int _switch_getentropy(void *buffer, switch_size_t length)
{
#ifdef WIN32
BCRYPT_ALG_HANDLE hAlgorithm = NULL;
NTSTATUS status = BCryptOpenAlgorithmProvider(&hAlgorithm, BCRYPT_RNG_ALGORITHM, NULL, 0);

if (!BCRYPT_SUCCESS(status)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "BCryptOpenAlgorithmProvider failed with status %d\n", status);
errno = EIO; // Input/Output error
return -1;
}

status = BCryptGenRandom(hAlgorithm, (PUCHAR)buffer, (ULONG)length, 0);
if (!BCRYPT_SUCCESS(status)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "BCryptGenRandom failed with status %d\n", status);
BCryptCloseAlgorithmProvider(hAlgorithm, 0);
errno = EIO; // Input/Output error
return -1;
}

BCryptCloseAlgorithmProvider(hAlgorithm, 0);
return 0;

#elif defined(__unix__) || defined(__APPLE__)
int random_fd = open("/dev/urandom", O_RDONLY);
switch_ssize_t result;
char error_msg[100];

if (random_fd == -1) {
strncpy(error_msg, strerror(errno), sizeof(error_msg) - 1);
error_msg[sizeof(error_msg) - 1] = '\0';

switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "open failed: %s\n", error_msg);
errno = EIO; // Input/Output error
return -1;
}

result = read(random_fd, buffer, length);
if (result < 0 || (switch_size_t)result != length) {
strncpy(error_msg, strerror(errno), sizeof(error_msg) - 1);
error_msg[sizeof(error_msg) - 1] = '\0';

switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "read failed: %s\n", error_msg);
close(random_fd);
errno = EIO; // Input/Output error
return -1;
}

close(random_fd);
return 0;

#else
// Fallback: Use rand() for platforms that do not support secure randomness
unsigned char *buf = (unsigned char *)buffer;
for (switch_size_t i = 0; i < length; i++) {
buf[i] = (unsigned char)(rand() & 0xFF); // Generate byte-wise randomness
}
return 0;
#endif
}


SWITCH_DECLARE(int) switch_getentropy(void *buffer, switch_size_t length)
{
if (!buffer || length > 256) { // Enforce same limit as `getentropy`
errno = EIO; // Input/Output error
return -1;
}
return _switch_getentropy(buffer, length);
}


SWITCH_DECLARE(switch_status_t) switch_uuid_generate_v7(switch_uuid_t *uuid) {
/* random bytes */
unsigned char *value = uuid->data;

/* current timestamp in ms */
switch_time_t timestamp = switch_time_now() / 1000;

if (switch_getentropy(value, 16) != 0) {
return -1;
}

// timestamp
value[0] = (timestamp >> 40) & 0xFF;
value[1] = (timestamp >> 32) & 0xFF;
value[2] = (timestamp >> 24) & 0xFF;
value[3] = (timestamp >> 16) & 0xFF;
value[4] = (timestamp >> 8) & 0xFF;
value[5] = timestamp & 0xFF;

// version and variant
value[6] = (value[6] & 0x0F) | 0x70;
value[8] = (value[8] & 0x3F) | 0x80;

return SWITCH_STATUS_SUCCESS;
}

/* For Emacs:
* Local Variables:
* mode:c
Expand Down