Make its state actually get seeded.
Document it more thoroughly.
Turn its state into a structure.
Fix a bug in evutil_weakrand_range_() where it could return the top of
the range.
Change its return type to ev_int32_t.
Add a quick unit test to make sure that the value of
evutil_weakrand_range_() is in range.
* to refill. */
struct event master_refill_event;
- /** Seed for weak random number generator. */
- ev_uint32_t weakrand_seed;
+ /** 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
* within every bufferevent lock: if you are holding this lock, do
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 *
bev_group_random_element_(struct bufferevent_rate_limit_group *group)
{
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;
}
/** 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;
+ /** 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 {
}
ev_uint32_t
-evutil_weakrand_(ev_uint32_t* seed)
+evutil_weakrand_seed_(struct evutil_weakrand_state *state, ev_uint32_t seed)
{
- *seed = ((*seed) * 1103515245 + 12345) & 0x7fffffff;
- return (*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
+ seed += (ev_uint32_t) _getpid();
+#else
+ seed += (ev_uint32_t) getpid();
+#endif
+ }
+ state->seed = seed;
+ return seed;
}
-ev_uint32_t
-evutil_weakrand_range_(ev_uint32_t* seed, ev_uint32_t top)
+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_uint32_t divisor, result;
+ ev_int32_t divisor, result;
- divisor = EV_INT32_MAX / top;
- do
- result = evutil_weakrand_(seed) / divisor;
- while (result > top);
+ /* 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;
}
evsig_init_(base);
+ evutil_weakrand_seed_(&base->weakrand_seed, 0);
+
return (pollop);
}
evsig_init_(base);
+ evutil_weakrand_seed_(&base->weakrand_seed, 0);
+
return (sop);
}
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;
+ struct evutil_weakrand_state seed = { 123456789U };
/* This test is highly parameterized based on substrings of its
* argument. The strings are: */
char buf2[32];
int counts[256];
int i, j, k, n=0;
- static ev_uint32_t seed = 12346789U;
+ struct evutil_weakrand_state seed = { 12346789U };
memset(buf2, 0, sizeof(buf2));
memset(counts, 0, sizeof(counts));
}
}
+ 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]); } */
end:
;
const char *evutil_getenv_(const char *name);
-ev_uint32_t evutil_weakrand_(ev_uint32_t* seed);
-ev_uint32_t evutil_weakrand_range_(ev_uint32_t* seed, ev_uint32_t top);
+/* 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
* we expect this value to be false. */
if (evsig_init_(base) < 0)
winop->signals_are_broken = 1;
+ evutil_weakrand_seed_(&base->weakrand_seed, 0);
+
return (winop);
err:
XFREE(winop->readset_in);