From a79fe4c30215e7f25dba1b3a8a84c4dfdc0c9475 Mon Sep 17 00:00:00 2001
From: Jon Sexson <Jon.Sexson@syniverse.com>
Date: Thu, 15 May 2014 13:05:57 +0300
Subject: [PATCH 3/4] Add max_response_timeouts option

Add "max_response_timeouts" - a home server option specifying number of
times replies are allowed to miss "response_window" before the server
enters the zombie period.

This allows more tolerance before transiting to zombie period for lower
response window configurations.
---
 raddb/proxy.conf     | 7 +++++++
 src/include/realms.h | 2 ++
 src/main/process.c   | 7 ++++++-
 src/main/realms.c    | 5 +++++
 4 files changed, 20 insertions(+), 1 deletion(-)

diff --git a/raddb/proxy.conf b/raddb/proxy.conf
index c92d2ab..1dc541b 100644
--- a/raddb/proxy.conf
+++ b/raddb/proxy.conf
@@ -228,6 +228,7 @@ home_server localhost {
 	#
 	#  If the home server does not respond to a request within
 	#  this time, this server will initiate "zombie_period".
+	#  See also "max_response_timeouts".
 	#
 	#  The time is specified with response_window and
 	#  response_window_usec for second and microsecond parts
@@ -241,6 +242,12 @@ home_server localhost {
 	response_window_usec = 0
 
 	#
+	# Ignore this many replies missing "response_window"
+	# before starting zombie period.
+	#
+	max_response_timeouts = 0
+
+	#
 	#  If you want the old behaviour of the server rejecting
 	#  proxied requests after "response_window" timeout, set
 	#  the following configuration item to "yes".
diff --git a/src/include/realms.h b/src/include/realms.h
index f6ddd08..b149b9f 100644
--- a/src/include/realms.h
+++ b/src/include/realms.h
@@ -63,6 +63,8 @@ typedef struct home_server {
 	struct timeval	when;
 
 	struct timeval	response_window;
+	int		response_timeouts;
+	int		max_response_timeouts;
 	int		max_outstanding; /* don't overload it */
 	int		currently_outstanding;
 
diff --git a/src/main/process.c b/src/main/process.c
index 91818a9..f07d377 100644
--- a/src/main/process.c
+++ b/src/main/process.c
@@ -2282,6 +2282,7 @@ int request_proxy_reply(RADIUS_PACKET *packet)
 	 */
 	if (request->home_server->state == HOME_STATE_UNKNOWN) {
 		request->home_server->state = HOME_STATE_ALIVE;
+		request->home_server->response_timeouts = 0;
 	}
 
 #ifdef WITH_STATS
@@ -2872,6 +2873,7 @@ STATE_MACHINE_DECL(request_ping)
 		 *	pings.
 		 */
 		home->state = HOME_STATE_ALIVE;
+		home->response_timeouts = 0;
 		exec_trigger(request, home->cs, "home_server.alive", false);
 		home->currently_outstanding = 0;
 		home->num_sent_pings = 0;
@@ -3118,6 +3120,7 @@ void revive_home_server(void *ctx)
 #endif
 
 	home->state = HOME_STATE_ALIVE;
+	home->response_timeouts = 0;
 	home_trigger(home, "home_server.alive");
 	home->currently_outstanding = 0;
 	gettimeofday(&home->revive_time, NULL);
@@ -3336,7 +3339,9 @@ STATE_MACHINE_DECL(proxy_wait_for_reply)
 		    && (home->proto != IPPROTO_TCP)
 #endif
 			) {
-			mark_home_server_zombie(home, &now, &response_window);
+			home->response_timeouts++;
+			if (home->response_timeouts > home->max_response_timeouts)
+				mark_home_server_zombie(home, &now, &response_window);
 		}
 
 		FR_STATS_TYPE_INC(home->stats.total_timeouts);
diff --git a/src/main/realms.c b/src/main/realms.c
index 48d73d0..eef988e 100644
--- a/src/main/realms.c
+++ b/src/main/realms.c
@@ -345,6 +345,8 @@ static CONF_PARSER home_server_config[] = {
 	  0, &response_window, "30" },
 	{ "response_window_usec", PW_TYPE_INTEGER,
 	  0, &response_window_usec, "0" },
+	{ "max_response_timeouts", PW_TYPE_INTEGER,
+	  offsetof(home_server_t,max_response_timeouts), NULL, "0" },
 	{ "max_outstanding", PW_TYPE_INTEGER,
 	  offsetof(home_server_t,max_outstanding), NULL,   "65536" },
 
@@ -747,6 +749,8 @@ static int home_server_add(realm_config_t *rc, CONF_SECTION *cs)
 	home->response_window.tv_sec = response_window;
 	home->response_window.tv_usec = response_window_usec;
 
+	FR_INTEGER_BOUND_CHECK("max_response_timeouts", home->max_response_timeouts, >=, 0);
+
 	FR_INTEGER_BOUND_CHECK("zombie_period", home->zombie_period, >=, 1);
 	FR_INTEGER_BOUND_CHECK("zombie_period", home->zombie_period, <=, 120);
 	FR_INTEGER_BOUND_CHECK("zombie_period", home->zombie_period, >=, timerceil(&home->response_window));
@@ -2385,6 +2389,7 @@ home_server_t *home_server_ldb(char const *realmname,
 			if ((home->state == HOME_STATE_IS_DEAD) &&
 			    (home->ping_check == HOME_PING_CHECK_NONE)) {
 				home->state = HOME_STATE_ALIVE;
+				home->response_timeouts = 0;
 				if (!found) found = home;
 			}
 		}
-- 
1.9.2

