diff --git a/bufferevent-internal.h b/bufferevent-internal.h index 400c6d96..ad2c25c7 100644 --- a/bufferevent-internal.h +++ b/bufferevent-internal.h @@ -104,6 +104,10 @@ struct bufferevent_rate_limit_group { /** Timeout event that goes off once a tick, when the bucket is ready * to refill. */ struct event master_refill_event; + + /** Seed for weak random number generator. */ + ev_uint32_t weakrand_seed; + /** Lock to protect the members of this group. This lock should nest * within every bufferevent lock: if you are holding this lock, do * not assume you can lock another bufferevent. */ diff --git a/bufferevent_ratelim.c b/bufferevent_ratelim.c index 02c50228..4272c0da 100644 --- a/bufferevent_ratelim.c +++ b/bufferevent_ratelim.c @@ -452,7 +452,7 @@ bev_group_random_element_(struct bufferevent_rate_limit_group *group) 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); while (which--) diff --git a/event-internal.h b/event-internal.h index f840058d..4c882056 100644 --- a/event-internal.h +++ b/event-internal.h @@ -290,6 +290,9 @@ struct event_base { struct event th_notify; /** A function used to wake up the main thread from another thread. */ int (*th_notify_fn)(struct event_base *base); + + /* Saved seed for weak random number generator. */ + ev_uint32_t weakrand_seed; }; struct event_config_entry { diff --git a/evutil.c b/evutil.c index abe15604..a87b5246 100644 --- a/evutil.c +++ b/evutil.c @@ -2273,14 +2273,23 @@ evutil_getenv_(const char *varname) return getenv(varname); } -long -evutil_weakrand_(void) +ev_uint32_t +evutil_weakrand_(ev_uint32_t* seed) { -#ifdef _WIN32 - return rand(); -#else - return random(); -#endif + *seed = ((*seed) * 1103515245 + 12345) & 0x7fffffff; + return (*seed); +} + +ev_uint32_t +evutil_weakrand_range_(ev_uint32_t* seed, ev_uint32_t top) +{ + ev_uint32_t divisor, result; + + divisor = EV_INT32_MAX / top; + do + result = evutil_weakrand_(seed) / divisor; + while (result > top); + return result; } int diff --git a/poll.c b/poll.c index 744c7141..3ac427ac 100644 --- a/poll.c +++ b/poll.c @@ -183,7 +183,7 @@ poll_dispatch(struct event_base *base, struct timeval *tv) if (res == 0 || nfds == 0) return (0); - i = random() % nfds; + i = evutil_weakrand_range_(&base->weakrand_seed, nfds); for (j = 0; j < nfds; j++) { int what; if (++i == nfds) diff --git a/select.c b/select.c index e1d4987c..f9a0c206 100644 --- a/select.c +++ b/select.c @@ -186,7 +186,7 @@ select_dispatch(struct event_base *base, struct timeval *tv) event_debug(("%s: select reports %d", __func__, res)); check_selectop(sop); - i = random() % nfds; + i = evutil_weakrand_range_(&base->weakrand_seed, nfds); for (j = 0; j < nfds; ++j) { if (++i >= nfds) i = 0; diff --git a/test/regress_buffer.c b/test/regress_buffer.c index dfb680b5..2e4ef176 100644 --- a/test/regress_buffer.c +++ b/test/regress_buffer.c @@ -699,6 +699,7 @@ test_evbuffer_add_file(void *ptr) struct event *rev=NULL, *wev=NULL; struct event_base *base = testdata->base; evutil_socket_t pair[2] = {-1, -1}; + static ev_uint32_t seed = 123456789U; /* This test is highly parameterized based on substrings of its * argument. The strings are: */ @@ -757,7 +758,7 @@ test_evbuffer_add_file(void *ptr) data = malloc(1024*512); tt_assert(data); for (i = 0; i < datalen; ++i) - data[i] = (char)evutil_weakrand_(); + data[i] = (char)evutil_weakrand_(&seed); } else { data = strdup("here is a relatively small string."); tt_assert(data); diff --git a/test/regress_util.c b/test/regress_util.c index e7662e0f..2d53ba8d 100644 --- a/test/regress_util.c +++ b/test/regress_util.c @@ -829,6 +829,7 @@ test_evutil_rand(void *arg) char buf2[32]; int counts[256]; int i, j, k, n=0; + static ev_uint32_t seed = 12346789U; memset(buf2, 0, sizeof(buf2)); memset(counts, 0, sizeof(counts)); @@ -836,8 +837,8 @@ test_evutil_rand(void *arg) for (k=0;k<32;++k) { /* Try a few different start and end points; try to catch * the various misaligned cases of arc4random_buf */ - int startpoint = evutil_weakrand_() % 4; - int endpoint = 32 - (evutil_weakrand_() % 4); + int startpoint = evutil_weakrand_(&seed) % 4; + int endpoint = 32 - (evutil_weakrand_(&seed) % 4); memset(buf2, 0, sizeof(buf2)); diff --git a/util-internal.h b/util-internal.h index 508eae92..291feb8a 100644 --- a/util-internal.h +++ b/util-internal.h @@ -254,7 +254,8 @@ int evutil_resolve_(int family, const char *hostname, struct sockaddr *sa, const char *evutil_getenv_(const char *name); -long evutil_weakrand_(void); +ev_uint32_t evutil_weakrand_(ev_uint32_t* seed); +ev_uint32_t evutil_weakrand_range_(ev_uint32_t* seed, ev_uint32_t top); /* Evaluates to the same boolean value as 'p', and hints to the compiler that * we expect this value to be false. */ diff --git a/win32select.c b/win32select.c index 441222f1..ce2d525f 100644 --- a/win32select.c +++ b/win32select.c @@ -326,7 +326,8 @@ win32_dispatch(struct event_base *base, struct timeval *tv) } 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; jreadset_out->fd_count; ++j) { if (++i >= win32op->readset_out->fd_count) i = 0; @@ -335,7 +336,8 @@ win32_dispatch(struct event_base *base, struct timeval *tv) } } 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; jexset_out->fd_count; ++j) { if (++i >= win32op->exset_out->fd_count) i = 0; @@ -345,7 +347,8 @@ win32_dispatch(struct event_base *base, struct timeval *tv) } if (win32op->writeset_out->fd_count) { SOCKET s; - i = rand() % win32op->writeset_out->fd_count; + i = evutil_weakrand_range_(&base->weakrand_seed, + win32op->writeset_out->fd_count); for (j=0; jwriteset_out->fd_count; ++j) { if (++i >= win32op->writeset_out->fd_count) i = 0;