summaryrefslogtreecommitdiff
path: root/evutil.c
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2012-04-09 11:30:46 -0400
committerNick Mathewson <nickm@torproject.org>2012-04-09 11:30:46 -0400
commit3aa44159c53af1d6459a85dc1841c7c494d52464 (patch)
treebf545d67d57ab47bb0f262a3a9e78394c64162c0 /evutil.c
parente86af4b7e56ed5b7050cb4f41ae534f54748598c (diff)
downloadlibevent-3aa44159c53af1d6459a85dc1841c7c494d52464.tar.gz
Tweak the new evutil_weakrand_() code
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.
Diffstat (limited to 'evutil.c')
-rw-r--r--evutil.c49
1 files changed, 39 insertions, 10 deletions
diff --git a/evutil.c b/evutil.c
index a87b5246..9307d259 100644
--- a/evutil.c
+++ b/evutil.c
@@ -2274,21 +2274,50 @@ evutil_getenv_(const char *varname)
}
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;
}