[Core] Add new switch_rand() a compliant random number generator API. Add a unit-test.
* [Core] Add new switch_rand() a compliant random number generator API. Add a unit-test. * Fall back to rand() on unsupported platforms compile time.
This commit is contained in:
parent
b84b7cbf71
commit
c7e793c345
|
@ -1514,6 +1514,11 @@ SWITCH_DECLARE(switch_status_t) switch_digest_string(const char *digest_name, ch
|
|||
SWITCH_DECLARE(char *) switch_must_strdup(const char *_s);
|
||||
SWITCH_DECLARE(const char *) switch_memory_usage_stream(switch_stream_handle_t *stream);
|
||||
|
||||
/**
|
||||
/ Compliant random number generator. Returns the value between 0 and 0x7fff (RAND_MAX).
|
||||
**/
|
||||
SWITCH_DECLARE(int) switch_rand(void);
|
||||
|
||||
SWITCH_END_EXTERN_C
|
||||
#endif
|
||||
/* For Emacs:
|
||||
|
|
|
@ -4811,6 +4811,63 @@ done:
|
|||
return status;
|
||||
}
|
||||
|
||||
SWITCH_DECLARE(int) switch_rand(void)
|
||||
{
|
||||
uint32_t random_number = 0;
|
||||
#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);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
status = BCryptGenRandom(hAlgorithm, (PUCHAR)&random_number, sizeof(random_number), 0);
|
||||
if (!BCRYPT_SUCCESS(status)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "BCryptGenRandom failed with status %d\n", status);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
BCryptCloseAlgorithmProvider(hAlgorithm, 0);
|
||||
|
||||
/* Make sure we return from 0 to RAND_MAX */
|
||||
return (random_number & 0x7FFF);
|
||||
#elif defined(__unix__) || defined(__APPLE__)
|
||||
int random_fd = open("/dev/urandom", O_RDONLY);
|
||||
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);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
result = read(random_fd, &random_number, sizeof(random_number));
|
||||
if (result < 0) {
|
||||
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);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
close(random_fd);
|
||||
|
||||
/* Make sure we return from 0 to RAND_MAX */
|
||||
return (random_number & 0x7FFF);
|
||||
#else
|
||||
return rand();
|
||||
#endif
|
||||
}
|
||||
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
|
|
|
@ -53,6 +53,27 @@ FST_CORE_BEGIN("./conf")
|
|||
}
|
||||
FST_TEARDOWN_END()
|
||||
|
||||
FST_TEST_BEGIN(test_switch_rand)
|
||||
{
|
||||
int i, c = 0;
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "\nLet's generate a few random numbers.\n");
|
||||
|
||||
for (i = 0; i < 10; i++) {
|
||||
uint32_t rnd = switch_rand();
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Random number %d\n", rnd);
|
||||
|
||||
if (rnd == 1) {
|
||||
c++;
|
||||
}
|
||||
}
|
||||
|
||||
/* We do not expect all random numbers to be 1 all 10 times. That would mean we have an error OR we are lucky to have 10 random ones! */
|
||||
fst_check(c < 10);
|
||||
}
|
||||
FST_TEST_END()
|
||||
|
||||
FST_TEST_BEGIN(test_switch_uint31_t_overflow)
|
||||
{
|
||||
switch_uint31_t x;
|
||||
|
|
Loading…
Reference in New Issue