mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-01-03 10:30:22 +01:00
glib-aux: add nm_random_u64_range() helper
(cherry picked from commit fb1d2da979)
This commit is contained in:
parent
5d95c20787
commit
f12ad37c36
3 changed files with 135 additions and 0 deletions
|
|
@ -447,3 +447,53 @@ again_getrandom:
|
|||
|
||||
return nm_utils_fd_read_loop_exact(fd, p, n, FALSE);
|
||||
}
|
||||
|
||||
guint64
|
||||
nm_random_u64_range_full(guint64 begin, guint64 end, gboolean crypto_bytes)
|
||||
{
|
||||
gboolean bad_crypto_bytes = FALSE;
|
||||
guint64 remainder;
|
||||
guint64 maxvalue;
|
||||
guint64 x;
|
||||
guint64 m;
|
||||
|
||||
/* Returns a random #guint64 equally distributed in the range [@begin..@end-1].
|
||||
*
|
||||
* The function always set errno. It either sets it to zero or to EAGAIN
|
||||
* (if crypto_bytes were requested but not obtained). In any case, the function
|
||||
* will always return a random number in the requested range (worst case, it's
|
||||
* not crypto_bytes despite being requested). Check errno if you care. */
|
||||
|
||||
if (begin >= end) {
|
||||
/* systemd's random_u64_range(0) is an alias for random_u64_range((uint64_t)-1).
|
||||
* Not for us. It's a caller error to request an element from an empty range. */
|
||||
return nm_assert_unreachable_val(begin);
|
||||
}
|
||||
|
||||
m = end - begin;
|
||||
|
||||
if (m == 1) {
|
||||
x = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
remainder = G_MAXUINT64 % m;
|
||||
maxvalue = G_MAXUINT64 - remainder;
|
||||
|
||||
do
|
||||
if (crypto_bytes) {
|
||||
if (nm_random_get_crypto_bytes(&x, sizeof(x)) < 0) {
|
||||
/* Cannot get good crypto numbers. We will try our best, but fail
|
||||
* and set errno below. */
|
||||
crypto_bytes = FALSE;
|
||||
bad_crypto_bytes = TRUE;
|
||||
continue;
|
||||
}
|
||||
} else
|
||||
nm_random_get_bytes(&x, sizeof(x));
|
||||
while (x >= maxvalue);
|
||||
|
||||
out:
|
||||
errno = bad_crypto_bytes ? EAGAIN : 0;
|
||||
return begin + (x % m);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,4 +16,39 @@ nm_random_get_bytes(void *p, size_t n)
|
|||
|
||||
int nm_random_get_crypto_bytes(void *p, size_t n);
|
||||
|
||||
static inline guint32
|
||||
nm_random_u32(void)
|
||||
{
|
||||
guint32 v;
|
||||
|
||||
nm_random_get_bytes(&v, sizeof(v));
|
||||
return v;
|
||||
}
|
||||
|
||||
static inline guint64
|
||||
nm_random_u64(void)
|
||||
{
|
||||
guint64 v;
|
||||
|
||||
nm_random_get_bytes(&v, sizeof(v));
|
||||
return v;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
nm_random_bool(void)
|
||||
{
|
||||
guint8 ch;
|
||||
|
||||
nm_random_get_bytes(&ch, sizeof(ch));
|
||||
return ch % 2u;
|
||||
}
|
||||
|
||||
guint64 nm_random_u64_range_full(guint64 begin, guint64 end, gboolean crypto_bytes);
|
||||
|
||||
static inline guint64
|
||||
nm_random_u64_range(guint64 end)
|
||||
{
|
||||
return nm_random_u64_range_full(0, end, FALSE);
|
||||
}
|
||||
|
||||
#endif /* __NM_RANDOM_UTILS_H__ */
|
||||
|
|
|
|||
|
|
@ -137,6 +137,55 @@ test_nmhash(void)
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
test_nm_random(void)
|
||||
{
|
||||
int i_run;
|
||||
|
||||
for (i_run = 0; i_run < 1000; i_run++) {
|
||||
guint64 begin;
|
||||
guint64 end;
|
||||
guint64 m;
|
||||
guint64 x;
|
||||
|
||||
m = nmtst_get_rand_uint64();
|
||||
m = m >> (nmtst_get_rand_uint32() % 64);
|
||||
|
||||
if (m == 0)
|
||||
continue;
|
||||
|
||||
switch (nmtst_get_rand_uint32() % 4) {
|
||||
case 0:
|
||||
begin = 0;
|
||||
break;
|
||||
case 1:
|
||||
begin = nmtst_get_rand_uint64() % 1000;
|
||||
break;
|
||||
case 2:
|
||||
begin = ((G_MAXUINT64 - m) - 500) + (nmtst_get_rand_uint64() % 1000);
|
||||
break;
|
||||
default:
|
||||
begin = nmtst_get_rand_uint64() % (G_MAXUINT64 - m);
|
||||
break;
|
||||
}
|
||||
|
||||
end = (begin + m) - 10 + (nmtst_get_rand_uint64() % 5);
|
||||
|
||||
if (begin >= end)
|
||||
continue;
|
||||
|
||||
if (begin == 0 && nmtst_get_rand_bool())
|
||||
x = nm_random_u64_range(end);
|
||||
else
|
||||
x = nm_random_u64_range_full(begin, end, nmtst_get_rand_bool());
|
||||
|
||||
g_assert_cmpuint(x, >=, begin);
|
||||
g_assert_cmpuint(x, <, end);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static const char *
|
||||
_make_strv_foo(void)
|
||||
{
|
||||
|
|
@ -2417,6 +2466,7 @@ main(int argc, char **argv)
|
|||
g_test_add_func("/general/test_inet_utils", test_inet_utils);
|
||||
g_test_add_func("/general/test_garray", test_garray);
|
||||
g_test_add_func("/general/test_nm_prioq", test_nm_prioq);
|
||||
g_test_add_func("/general/test_nm_random", test_nm_random);
|
||||
|
||||
return g_test_run();
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue