1238106Sdes/*
2238106Sdes * util/rtt.c - UDP round trip time estimator for resend timeouts.
3238106Sdes *
4238106Sdes * Copyright (c) 2007, NLnet Labs. All rights reserved.
5238106Sdes *
6238106Sdes * This software is open source.
7238106Sdes *
8238106Sdes * Redistribution and use in source and binary forms, with or without
9238106Sdes * modification, are permitted provided that the following conditions
10238106Sdes * are met:
11238106Sdes *
12238106Sdes * Redistributions of source code must retain the above copyright notice,
13238106Sdes * this list of conditions and the following disclaimer.
14238106Sdes *
15238106Sdes * Redistributions in binary form must reproduce the above copyright notice,
16238106Sdes * this list of conditions and the following disclaimer in the documentation
17238106Sdes * and/or other materials provided with the distribution.
18238106Sdes *
19238106Sdes * Neither the name of the NLNET LABS nor the names of its contributors may
20238106Sdes * be used to endorse or promote products derived from this software without
21238106Sdes * specific prior written permission.
22238106Sdes *
23238106Sdes * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24269257Sdes * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25269257Sdes * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26269257Sdes * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27269257Sdes * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28269257Sdes * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29269257Sdes * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30269257Sdes * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31269257Sdes * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32269257Sdes * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33269257Sdes * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34238106Sdes */
35238106Sdes
36238106Sdes/**
37238106Sdes * \file
38238106Sdes *
39238106Sdes * This file contains a data type and functions to help estimate good
40238106Sdes * round trip times for UDP resend timeout values.
41238106Sdes */
42238106Sdes#include "config.h"
43238106Sdes#include "util/rtt.h"
44238106Sdes
45238106Sdes/** calculate RTO from rtt information */
46238106Sdesstatic int
47238106Sdescalc_rto(const struct rtt_info* rtt)
48238106Sdes{
49238106Sdes	/* From Stevens, Unix Network Programming, Vol1, 3rd ed., p.598 */
50238106Sdes	int rto = rtt->srtt + 4*rtt->rttvar;
51238106Sdes	if(rto < RTT_MIN_TIMEOUT)
52238106Sdes		rto = RTT_MIN_TIMEOUT;
53238106Sdes	if(rto > RTT_MAX_TIMEOUT)
54238106Sdes		rto = RTT_MAX_TIMEOUT;
55238106Sdes	return rto;
56238106Sdes}
57238106Sdes
58238106Sdesvoid
59238106Sdesrtt_init(struct rtt_info* rtt)
60238106Sdes{
61238106Sdes	rtt->srtt = 0;
62238106Sdes	rtt->rttvar = 94;
63238106Sdes	rtt->rto = calc_rto(rtt);
64238106Sdes	/* default value from the book is 0 + 4*0.75 = 3 seconds */
65238106Sdes	/* first RTO is 0 + 4*0.094 = 0.376 seconds */
66238106Sdes}
67238106Sdes
68238106Sdesint
69238106Sdesrtt_timeout(const struct rtt_info* rtt)
70238106Sdes{
71238106Sdes	return rtt->rto;
72238106Sdes}
73238106Sdes
74238106Sdesint
75238106Sdesrtt_unclamped(const struct rtt_info* rtt)
76238106Sdes{
77238106Sdes	if(calc_rto(rtt) != rtt->rto) {
78238106Sdes		/* timeout fallback has happened */
79238106Sdes		return rtt->rto;
80238106Sdes	}
81238106Sdes	/* return unclamped value */
82238106Sdes	return rtt->srtt + 4*rtt->rttvar;
83238106Sdes}
84238106Sdes
85238106Sdesvoid
86238106Sdesrtt_update(struct rtt_info* rtt, int ms)
87238106Sdes{
88238106Sdes	int delta = ms - rtt->srtt;
89238106Sdes	rtt->srtt += delta / 8; /* g = 1/8 */
90238106Sdes	if(delta < 0)
91238106Sdes		delta = -delta; /* |delta| */
92238106Sdes	rtt->rttvar += (delta - rtt->rttvar) / 4; /* h = 1/4 */
93238106Sdes	rtt->rto = calc_rto(rtt);
94238106Sdes}
95238106Sdes
96238106Sdesvoid
97238106Sdesrtt_lost(struct rtt_info* rtt, int orig)
98238106Sdes{
99238106Sdes	/* exponential backoff */
100238106Sdes
101238106Sdes	/* if a query succeeded and put down the rto meanwhile, ignore this */
102238106Sdes	if(rtt->rto < orig)
103238106Sdes		return;
104238106Sdes
105238106Sdes	/* the original rto is doubled, not the current one to make sure
106238106Sdes	 * that the values in the cache are not increased by lots of
107238106Sdes	 * queries simultaneously as they time out at the same time */
108238106Sdes	orig *= 2;
109238106Sdes	if(rtt->rto <= orig) {
110238106Sdes		rtt->rto = orig;
111238106Sdes		if(rtt->rto > RTT_MAX_TIMEOUT)
112238106Sdes			rtt->rto = RTT_MAX_TIMEOUT;
113238106Sdes	}
114238106Sdes}
115238106Sdes
116238106Sdesint rtt_notimeout(const struct rtt_info* rtt)
117238106Sdes{
118238106Sdes	return calc_rto(rtt);
119238106Sdes}
120