]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
[Core] Add new switch_rand() a compliant random number generator API. Add a unit... 2478/head
authorAndrey Volk <andywolk@gmail.com>
Thu, 6 Jun 2024 18:05:33 +0000 (21:05 +0300)
committerAndrey Volk <andywolk@gmail.com>
Thu, 6 Jun 2024 18:14:36 +0000 (21:14 +0300)
* [Core] Add new switch_rand() a compliant random number generator API. Add a unit-test.

* Fall back to rand() on unsupported platforms compile time.

src/include/switch_utils.h
src/switch_utils.c
tests/unit/switch_core.c

index 1d33939f4c38d73358b654618b3eb3200de09dfe..a0c91e6384f34cc9018aa7caa838225180a16a49 100644 (file)
@@ -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:
index faffc1cc0482aa4fa09b5d932e861ac64c11caf9..25d0bf76eef5309dee1d4a0176e5a9af30f7a70c 100644 (file)
@@ -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
index 2f06966582f94f1528eea1f7e0ee150f9a1353a7..295e4e0ff159afd9b38c8813fda7e5e72a357189 100644 (file)
@@ -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;