X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~mdw/git/tripe/blobdiff_plain/ff14395237fc702f35be05c0fb895bb8318f7147..a06d57a3ff9f3fec7a315a8a931acacf67bec7a4:/server/keyexch.c diff --git a/server/keyexch.c b/server/keyexch.c index c27d69fd..b1f23d73 100644 --- a/server/keyexch.c +++ b/server/keyexch.c @@ -279,6 +279,88 @@ static void settimer(keyexch *kx, struct timeval *tv) kx->f |= KXF_TIMER; } +/* --- @f2tv@ --- * + * + * Arguments: @struct timeval *tv@ = where to write the timeval + * @double t@ = a time as a floating point number + * + * Returns: --- + * + * Use: Converts a floating-point time into a timeval. + */ + +static void f2tv(struct timeval *tv, double t) +{ + tv->tv_sec = t; + tv->tv_usec = (t - tv->tv_sec)*MILLION; +} + +/* --- @wobble@ --- * + * + * Arguments: @double t@ = a time interval + * + * Returns: The same time interval, with a random error applied. + */ + +static double wobble(double t) +{ + uint32 r = rand_global.ops->word(&rand_global); + double w = (r/F_2P32) - 0.5; + return (t + t*w*T_WOBBLE); +} + +/* --- @rs_time@ --- * + * + * Arguments: @retry *rs@ = current retry state + * @struct timeval *tv@ = where to write the result + * @const struct timeval *now@ = current time, or null + * + * Returns: --- + * + * Use: Computes a time at which to retry sending a key-exchange + * packet. This algorithm is subject to change, but it's + * currently a capped exponential backoff, slightly randomized + * to try to keep clients from hammering a server that's only + * just woken up. + * + * If @now@ is null then the function works out the time for + * itself. + */ + +static void rs_time(retry *rs, struct timeval *tv, const struct timeval *now) +{ + double t; + struct timeval rtv; + + if (!rs->t) + t = SEC(2); + else { + t = (rs->t * 5)/4; + if (t > MIN(5)) t = MIN(5); + } + rs->t = t; + + if (!now) { + now = tv; + gettimeofday(tv, 0); + } + f2tv(&rtv, wobble(t)); + TV_ADD(tv, now, &rtv); +} + +/* --- @retry_reset@ --- * + * + * Arguments: @retry *rs@ = retry state + * + * Returns: -- + * + * Use: Resets a retry state to indicate that progress has been + * made. Also useful for initializing the state in the first + * place. + */ + +static void rs_reset(retry *rs) { rs->t = 0; } + /*----- Challenge management ----------------------------------------------*/ /* --- Notes on challenge management --- * @@ -363,6 +445,7 @@ static kxchal *kxc_new(keyexch *kx) kxc->kx = kx; kxc->f = 0; kx->r[i] = kxc; + rs_reset(&kxc->rs); return (kxc); } @@ -457,7 +540,7 @@ static void kxc_answer(keyexch *kx, kxchal *kxc) if (kxc->f & KXF_TIMER) sel_rmtimer(&kxc->t); gettimeofday(&tv, 0); - tv.tv_sec += T_RETRY; + rs_time(&kxc->rs, &tv, &tv); sel_addtimer(&sel, &kxc->t, &tv, kxc_timer, kxc); kxc->f |= KXF_TIMER; } @@ -768,8 +851,7 @@ static void resend(keyexch *kx) } if (kx->s < KXS_SWITCH) { - gettimeofday(&tv, 0); - tv.tv_sec += T_RETRY; + rs_time(&kx->rs, &tv, 0); settimer(kx, &tv); } } @@ -912,11 +994,12 @@ bad: static void kxfinish(keyexch *kx) { kxchal *kxc = kx->r[0]; - struct timeval tv; + struct timeval now, tv; ks_activate(kxc->ks); - gettimeofday(&tv, 0); - tv.tv_sec += T_REGEN; + gettimeofday(&now, 0); + f2tv(&tv, wobble(T_REGEN)); + TV_ADD(&tv, &now, &tv); settimer(kx, &tv); kx->s = KXS_SWITCH; a_notify("KXDONE", "?PEER", kx->p, A_END); @@ -1170,9 +1253,10 @@ void kx_message(keyexch *kx, unsigned msg, buf *b) int rc; gettimeofday(&now, 0); + rs_reset(&kx->rs); if (kx->f & KXF_CORK) { start(kx, now.tv_sec); - TV_ADDL(&tv, &now, T_RETRY, 0); + rs_time(&kx->rs, &tv, &now); settimer(kx, &tv); a_notify("KXSTART", A_END); } @@ -1282,6 +1366,7 @@ int kx_init(keyexch *kx, peer *p, keyset **ks, unsigned f) return (-1); } kx->f = KXF_DEAD | KXF_PUBKEY | f; + rs_reset(&kx->rs); if (!(kx->f & KXF_CORK)) { start(kx, time(0)); resend(kx);