mirror of
https://github.com/libevent/libevent.git
synced 2025-01-31 09:12:55 +08:00
Merge branch '21_weakrand'
This commit is contained in:
commit
0af23d5911
@ -104,6 +104,10 @@ struct bufferevent_rate_limit_group {
|
|||||||
/** Timeout event that goes off once a tick, when the bucket is ready
|
/** Timeout event that goes off once a tick, when the bucket is ready
|
||||||
* to refill. */
|
* to refill. */
|
||||||
struct event master_refill_event;
|
struct event master_refill_event;
|
||||||
|
|
||||||
|
/** Seed for weak random number generator. Protected by 'lock' */
|
||||||
|
struct evutil_weakrand_state weakrand_seed;
|
||||||
|
|
||||||
/** Lock to protect the members of this group. This lock should nest
|
/** Lock to protect the members of this group. This lock should nest
|
||||||
* within every bufferevent lock: if you are holding this lock, do
|
* within every bufferevent lock: if you are holding this lock, do
|
||||||
* not assume you can lock another bufferevent. */
|
* not assume you can lock another bufferevent. */
|
||||||
|
@ -438,7 +438,10 @@ bev_refill_callback_(evutil_socket_t fd, short what, void *arg)
|
|||||||
BEV_UNLOCK(&bev->bev);
|
BEV_UNLOCK(&bev->bev);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Helper: grab a random element from a bufferevent group. */
|
/** Helper: grab a random element from a bufferevent group.
|
||||||
|
*
|
||||||
|
* Requires that we hold the lock on the group.
|
||||||
|
*/
|
||||||
static struct bufferevent_private *
|
static struct bufferevent_private *
|
||||||
bev_group_random_element_(struct bufferevent_rate_limit_group *group)
|
bev_group_random_element_(struct bufferevent_rate_limit_group *group)
|
||||||
{
|
{
|
||||||
@ -452,7 +455,7 @@ bev_group_random_element_(struct bufferevent_rate_limit_group *group)
|
|||||||
|
|
||||||
EVUTIL_ASSERT(! LIST_EMPTY(&group->members));
|
EVUTIL_ASSERT(! LIST_EMPTY(&group->members));
|
||||||
|
|
||||||
which = evutil_weakrand_() % group->n_members;
|
which = evutil_weakrand_range_(&group->weakrand_seed, group->n_members);
|
||||||
|
|
||||||
bev = LIST_FIRST(&group->members);
|
bev = LIST_FIRST(&group->members);
|
||||||
while (which--)
|
while (which--)
|
||||||
@ -660,6 +663,9 @@ bufferevent_rate_limit_group_new(struct event_base *base,
|
|||||||
|
|
||||||
bufferevent_rate_limit_group_set_min_share(g, 64);
|
bufferevent_rate_limit_group_set_min_share(g, 64);
|
||||||
|
|
||||||
|
evutil_weakrand_seed_(&g->weakrand_seed,
|
||||||
|
(ev_uint32_t) ((now.tv_sec + now.tv_usec) + (ev_intptr_t)g));
|
||||||
|
|
||||||
return g;
|
return g;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -290,6 +290,10 @@ struct event_base {
|
|||||||
struct event th_notify;
|
struct event th_notify;
|
||||||
/** A function used to wake up the main thread from another thread. */
|
/** A function used to wake up the main thread from another thread. */
|
||||||
int (*th_notify_fn)(struct event_base *base);
|
int (*th_notify_fn)(struct event_base *base);
|
||||||
|
|
||||||
|
/** Saved seed for weak random number generator. Some backends use
|
||||||
|
* this to produce fairness among sockets. Protected by th_base_lock. */
|
||||||
|
struct evutil_weakrand_state weakrand_seed;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct event_config_entry {
|
struct event_config_entry {
|
||||||
|
46
evutil.c
46
evutil.c
@ -2273,15 +2273,53 @@ evutil_getenv_(const char *varname)
|
|||||||
return getenv(varname);
|
return getenv(varname);
|
||||||
}
|
}
|
||||||
|
|
||||||
long
|
ev_uint32_t
|
||||||
evutil_weakrand_(void)
|
evutil_weakrand_seed_(struct evutil_weakrand_state *state, ev_uint32_t seed)
|
||||||
{
|
{
|
||||||
|
if (seed == 0) {
|
||||||
|
struct timeval tv;
|
||||||
|
evutil_gettimeofday(&tv, NULL);
|
||||||
|
seed = (ev_uint32_t)tv.tv_sec + (ev_uint32_t)tv.tv_usec;
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
return rand();
|
seed += (ev_uint32_t) _getpid();
|
||||||
#else
|
#else
|
||||||
return random();
|
seed += (ev_uint32_t) getpid();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
state->seed = seed;
|
||||||
|
return seed;
|
||||||
|
}
|
||||||
|
|
||||||
|
ev_int32_t
|
||||||
|
evutil_weakrand_(struct evutil_weakrand_state *state)
|
||||||
|
{
|
||||||
|
/* This RNG implementation is a linear congruential generator, with
|
||||||
|
* modulus 2^31, multiplier 1103515245, and addend 12345. It's also
|
||||||
|
* used by OpenBSD, and by Glibc's TYPE_0 RNG.
|
||||||
|
*
|
||||||
|
* The linear congruential generator is not an industrial-strength
|
||||||
|
* RNG! It's fast, but it can have higher-order patterns. Notably,
|
||||||
|
* the low bits tend to have periodicity.
|
||||||
|
*/
|
||||||
|
state->seed = ((state->seed) * 1103515245 + 12345) & 0x7fffffff;
|
||||||
|
return (ev_int32_t)(state->seed);
|
||||||
|
}
|
||||||
|
|
||||||
|
ev_int32_t
|
||||||
|
evutil_weakrand_range_(struct evutil_weakrand_state *state, ev_int32_t top)
|
||||||
|
{
|
||||||
|
ev_int32_t divisor, result;
|
||||||
|
|
||||||
|
/* We can't just do weakrand() % top, since the low bits of the LCG
|
||||||
|
* are less random than the high ones. (Specifically, since the LCG
|
||||||
|
* modulus is 2^N, every 2^m for m<N will divide the modulus, and so
|
||||||
|
* therefore the low m bits of the LCG will have period 2^m.) */
|
||||||
|
divisor = EVUTIL_WEAKRAND_MAX / top;
|
||||||
|
do {
|
||||||
|
result = evutil_weakrand_(state) / divisor;
|
||||||
|
} while (result >= top);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
evutil_sockaddr_is_loopback_(const struct sockaddr *addr)
|
evutil_sockaddr_is_loopback_(const struct sockaddr *addr)
|
||||||
|
4
poll.c
4
poll.c
@ -93,6 +93,8 @@ poll_init(struct event_base *base)
|
|||||||
|
|
||||||
evsig_init_(base);
|
evsig_init_(base);
|
||||||
|
|
||||||
|
evutil_weakrand_seed_(&base->weakrand_seed, 0);
|
||||||
|
|
||||||
return (pollop);
|
return (pollop);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -183,7 +185,7 @@ poll_dispatch(struct event_base *base, struct timeval *tv)
|
|||||||
if (res == 0 || nfds == 0)
|
if (res == 0 || nfds == 0)
|
||||||
return (0);
|
return (0);
|
||||||
|
|
||||||
i = random() % nfds;
|
i = evutil_weakrand_range_(&base->weakrand_seed, nfds);
|
||||||
for (j = 0; j < nfds; j++) {
|
for (j = 0; j < nfds; j++) {
|
||||||
int what;
|
int what;
|
||||||
if (++i == nfds)
|
if (++i == nfds)
|
||||||
|
4
select.c
4
select.c
@ -121,6 +121,8 @@ select_init(struct event_base *base)
|
|||||||
|
|
||||||
evsig_init_(base);
|
evsig_init_(base);
|
||||||
|
|
||||||
|
evutil_weakrand_seed_(&base->weakrand_seed, 0);
|
||||||
|
|
||||||
return (sop);
|
return (sop);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -186,7 +188,7 @@ select_dispatch(struct event_base *base, struct timeval *tv)
|
|||||||
event_debug(("%s: select reports %d", __func__, res));
|
event_debug(("%s: select reports %d", __func__, res));
|
||||||
|
|
||||||
check_selectop(sop);
|
check_selectop(sop);
|
||||||
i = random() % nfds;
|
i = evutil_weakrand_range_(&base->weakrand_seed, nfds);
|
||||||
for (j = 0; j < nfds; ++j) {
|
for (j = 0; j < nfds; ++j) {
|
||||||
if (++i >= nfds)
|
if (++i >= nfds)
|
||||||
i = 0;
|
i = 0;
|
||||||
|
@ -699,6 +699,7 @@ test_evbuffer_add_file(void *ptr)
|
|||||||
struct event *rev=NULL, *wev=NULL;
|
struct event *rev=NULL, *wev=NULL;
|
||||||
struct event_base *base = testdata->base;
|
struct event_base *base = testdata->base;
|
||||||
evutil_socket_t pair[2] = {-1, -1};
|
evutil_socket_t pair[2] = {-1, -1};
|
||||||
|
struct evutil_weakrand_state seed = { 123456789U };
|
||||||
|
|
||||||
/* This test is highly parameterized based on substrings of its
|
/* This test is highly parameterized based on substrings of its
|
||||||
* argument. The strings are: */
|
* argument. The strings are: */
|
||||||
@ -757,7 +758,7 @@ test_evbuffer_add_file(void *ptr)
|
|||||||
data = malloc(1024*512);
|
data = malloc(1024*512);
|
||||||
tt_assert(data);
|
tt_assert(data);
|
||||||
for (i = 0; i < datalen; ++i)
|
for (i = 0; i < datalen; ++i)
|
||||||
data[i] = (char)evutil_weakrand_();
|
data[i] = (char)evutil_weakrand_(&seed);
|
||||||
} else {
|
} else {
|
||||||
data = strdup("here is a relatively small string.");
|
data = strdup("here is a relatively small string.");
|
||||||
tt_assert(data);
|
tt_assert(data);
|
||||||
|
@ -829,6 +829,7 @@ test_evutil_rand(void *arg)
|
|||||||
char buf2[32];
|
char buf2[32];
|
||||||
int counts[256];
|
int counts[256];
|
||||||
int i, j, k, n=0;
|
int i, j, k, n=0;
|
||||||
|
struct evutil_weakrand_state seed = { 12346789U };
|
||||||
|
|
||||||
memset(buf2, 0, sizeof(buf2));
|
memset(buf2, 0, sizeof(buf2));
|
||||||
memset(counts, 0, sizeof(counts));
|
memset(counts, 0, sizeof(counts));
|
||||||
@ -836,8 +837,8 @@ test_evutil_rand(void *arg)
|
|||||||
for (k=0;k<32;++k) {
|
for (k=0;k<32;++k) {
|
||||||
/* Try a few different start and end points; try to catch
|
/* Try a few different start and end points; try to catch
|
||||||
* the various misaligned cases of arc4random_buf */
|
* the various misaligned cases of arc4random_buf */
|
||||||
int startpoint = evutil_weakrand_() % 4;
|
int startpoint = evutil_weakrand_(&seed) % 4;
|
||||||
int endpoint = 32 - (evutil_weakrand_() % 4);
|
int endpoint = 32 - (evutil_weakrand_(&seed) % 4);
|
||||||
|
|
||||||
memset(buf2, 0, sizeof(buf2));
|
memset(buf2, 0, sizeof(buf2));
|
||||||
|
|
||||||
@ -868,6 +869,13 @@ test_evutil_rand(void *arg)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
evutil_weakrand_seed_(&seed, 0);
|
||||||
|
for (i = 0; i < 10000; ++i) {
|
||||||
|
ev_int32_t r = evutil_weakrand_range_(&seed, 9999);
|
||||||
|
tt_int_op(0, <=, r);
|
||||||
|
tt_int_op(r, <, 9999);
|
||||||
|
}
|
||||||
|
|
||||||
/* for (i=0;i<256;++i) { printf("%3d %2d\n", i, counts[i]); } */
|
/* for (i=0;i<256;++i) { printf("%3d %2d\n", i, counts[i]); } */
|
||||||
end:
|
end:
|
||||||
;
|
;
|
||||||
|
@ -254,7 +254,33 @@ int evutil_resolve_(int family, const char *hostname, struct sockaddr *sa,
|
|||||||
|
|
||||||
const char *evutil_getenv_(const char *name);
|
const char *evutil_getenv_(const char *name);
|
||||||
|
|
||||||
long evutil_weakrand_(void);
|
/* Structure to hold the state of our weak random number generator.
|
||||||
|
*/
|
||||||
|
struct evutil_weakrand_state {
|
||||||
|
ev_uint32_t seed;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define EVUTIL_WEAKRAND_MAX EV_INT32_MAX
|
||||||
|
|
||||||
|
/* Initialize the state of a week random number generator based on 'seed'. If
|
||||||
|
* the seed is 0, construct a new seed based on not-very-strong platform
|
||||||
|
* entropy, like the PID and the time of day.
|
||||||
|
*
|
||||||
|
* This function, and the other evutil_weakrand* functions, are meant for
|
||||||
|
* speed, not security or statistical strength. If you need a RNG which an
|
||||||
|
* attacker can't predict, or which passes strong statistical tests, use the
|
||||||
|
* evutil_secure_rng* functions instead.
|
||||||
|
*/
|
||||||
|
ev_uint32_t evutil_weakrand_seed_(struct evutil_weakrand_state *state, ev_uint32_t seed);
|
||||||
|
/* Return a pseudorandom value between 0 and EVUTIL_WEAKRAND_MAX inclusive.
|
||||||
|
* Updates the state in 'seed' as needed -- this value must be protected by a
|
||||||
|
* lock.
|
||||||
|
*/
|
||||||
|
ev_int32_t evutil_weakrand_(struct evutil_weakrand_state *seed);
|
||||||
|
/* Return a pseudorandom value x such that 0 <= x < top. top must be no more
|
||||||
|
* than EVUTIL_WEAKRAND_MAX. Updates the state in 'seed' as needed -- this
|
||||||
|
* value must be proteced by a lock */
|
||||||
|
ev_int32_t evutil_weakrand_range_(struct evutil_weakrand_state *seed, ev_int32_t top);
|
||||||
|
|
||||||
/* Evaluates to the same boolean value as 'p', and hints to the compiler that
|
/* Evaluates to the same boolean value as 'p', and hints to the compiler that
|
||||||
* we expect this value to be false. */
|
* we expect this value to be false. */
|
||||||
|
@ -202,6 +202,8 @@ win32_init(struct event_base *base)
|
|||||||
if (evsig_init_(base) < 0)
|
if (evsig_init_(base) < 0)
|
||||||
winop->signals_are_broken = 1;
|
winop->signals_are_broken = 1;
|
||||||
|
|
||||||
|
evutil_weakrand_seed_(&base->weakrand_seed, 0);
|
||||||
|
|
||||||
return (winop);
|
return (winop);
|
||||||
err:
|
err:
|
||||||
XFREE(winop->readset_in);
|
XFREE(winop->readset_in);
|
||||||
@ -326,7 +328,8 @@ win32_dispatch(struct event_base *base, struct timeval *tv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (win32op->readset_out->fd_count) {
|
if (win32op->readset_out->fd_count) {
|
||||||
i = rand() % win32op->readset_out->fd_count;
|
i = evutil_weakrand_range_(&base->weakrand_seed,
|
||||||
|
win32op->readset_out->fd_count);
|
||||||
for (j=0; j<win32op->readset_out->fd_count; ++j) {
|
for (j=0; j<win32op->readset_out->fd_count; ++j) {
|
||||||
if (++i >= win32op->readset_out->fd_count)
|
if (++i >= win32op->readset_out->fd_count)
|
||||||
i = 0;
|
i = 0;
|
||||||
@ -335,7 +338,8 @@ win32_dispatch(struct event_base *base, struct timeval *tv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (win32op->exset_out->fd_count) {
|
if (win32op->exset_out->fd_count) {
|
||||||
i = rand() % win32op->exset_out->fd_count;
|
i = evutil_weakrand_range_(&base->weakrand_seed,
|
||||||
|
win32op->exset_out->fd_count);
|
||||||
for (j=0; j<win32op->exset_out->fd_count; ++j) {
|
for (j=0; j<win32op->exset_out->fd_count; ++j) {
|
||||||
if (++i >= win32op->exset_out->fd_count)
|
if (++i >= win32op->exset_out->fd_count)
|
||||||
i = 0;
|
i = 0;
|
||||||
@ -345,7 +349,8 @@ win32_dispatch(struct event_base *base, struct timeval *tv)
|
|||||||
}
|
}
|
||||||
if (win32op->writeset_out->fd_count) {
|
if (win32op->writeset_out->fd_count) {
|
||||||
SOCKET s;
|
SOCKET s;
|
||||||
i = rand() % win32op->writeset_out->fd_count;
|
i = evutil_weakrand_range_(&base->weakrand_seed,
|
||||||
|
win32op->writeset_out->fd_count);
|
||||||
for (j=0; j<win32op->writeset_out->fd_count; ++j) {
|
for (j=0; j<win32op->writeset_out->fd_count; ++j) {
|
||||||
if (++i >= win32op->writeset_out->fd_count)
|
if (++i >= win32op->writeset_out->fd_count)
|
||||||
i = 0;
|
i = 0;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user