From efcea7ffba9f3a6f38449083b791a38fd50ea5b1 Mon Sep 17 00:00:00 2001
From: Jon Sexson <Jon.Sexson@syniverse.com>
Date: Thu, 15 May 2014 12:39:59 +0300
Subject: [PATCH 1/4] Add response_window_usec option

Add "response_window_usec" - a home server configuration option adding
microsecond precision to "response_window".

This allows specifying response windows of less than a second for
low-latency links, speeding up home server failover and reducing overall
request processing time.
---
 raddb/proxy.conf     |  5 +++++
 src/include/realms.h |  2 +-
 src/main/process.c   | 13 +++++++------
 src/main/realms.c    | 31 +++++++++++++++++++++++++------
 4 files changed, 38 insertions(+), 13 deletions(-)

diff --git a/raddb/proxy.conf b/raddb/proxy.conf
index ae8fedf..c92d2ab 100644
--- a/raddb/proxy.conf
+++ b/raddb/proxy.conf
@@ -229,11 +229,16 @@ home_server localhost {
 	#  If the home server does not respond to a request within
 	#  this time, this server will initiate "zombie_period".
 	#
+	#  The time is specified with response_window and
+	#  response_window_usec for second and microsecond parts
+	#  respectively.
+	#
 	#  The response window is large because responses MAY be slow,
 	#  especially when proxying across the Internet.
 	#
 	#  Useful range of values: 5 to 60
 	response_window = 20
+	response_window_usec = 0
 
 	#
 	#  If you want the old behaviour of the server rejecting
diff --git a/src/include/realms.h b/src/include/realms.h
index 2bd7e60..f6ddd08 100644
--- a/src/include/realms.h
+++ b/src/include/realms.h
@@ -62,7 +62,7 @@ typedef struct home_server {
 	fr_event_t	*ev;
 	struct timeval	when;
 
-	int		response_window;
+	struct timeval	response_window;
 	int		max_outstanding; /* don't overload it */
 	int		currently_outstanding;
 
diff --git a/src/main/process.c b/src/main/process.c
index e21adce..e6deafd 100644
--- a/src/main/process.c
+++ b/src/main/process.c
@@ -595,7 +595,7 @@ STATE_MACHINE_DECL(request_done)
 			when.tv_sec += request->home_server->coa_mrd;
 		} else
 #endif
-		when.tv_sec += request->home_server->response_window;
+		timeradd(&when, &request->home_server->response_window, &when);
 
 		/*
 		 *	We haven't received all responses, AND there's still
@@ -3078,10 +3078,10 @@ static void mark_home_server_zombie(home_server_t *home, struct timeval *now)
 	home->num_sent_pings = 0;
 	home->num_received_pings = 0;
 
-	PROXY( "Marking home server %s port %d as zombie (it has not responded in %d seconds).",
+	PROXY( "Marking home server %s port %d as zombie (it has not responded in %d.%.6d seconds).",
 	       inet_ntop(home->ipaddr.af, &home->ipaddr.ipaddr,
 			 buffer, sizeof(buffer)),
-	       home->port, home->response_window);
+	       home->port, (int)home->response_window.tv_sec, (int)home->response_window.tv_usec);
 
 	ping_home_server(home);
 }
@@ -3280,15 +3280,16 @@ STATE_MACHINE_DECL(proxy_wait_for_reply)
 			 *	zombie if it doesn't respond to us.  It may be
 			 *	responding to other (better looking) packets.
 			 */
-			when = request->proxy->timestamp;
-			when.tv_sec += home->response_window;
+			timeradd(&request->proxy->timestamp, &home->response_window, &when);
 
 			/*
 			 *	Not at the response window.  Set the timer for
 			 *	that.
 			 */
 			if (timercmp(&when, &now, >)) {
-				RDEBUG("Expecting proxy response no later than %d seconds from now", home->response_window);
+				RDEBUG("Expecting proxy response no later than %d.%.6d seconds from now",
+					(int)home->response_window.tv_sec,
+					(int)home->response_window.tv_usec);
 				STATE_MACHINE_TIMER(FR_ACTION_TIMER);
 				return;
 			}
diff --git a/src/main/realms.c b/src/main/realms.c
index 9a40538..48d73d0 100644
--- a/src/main/realms.c
+++ b/src/main/realms.c
@@ -295,6 +295,8 @@ static char *hs_srcipaddr = NULL;
 static char *hs_type = NULL;
 static char *hs_check = NULL;
 static char *hs_virtual_server = NULL;
+static int response_window = 0;
+static int response_window_usec = 0;
 #ifdef WITH_TCP
 static char *hs_proto = NULL;
 #endif
@@ -340,7 +342,9 @@ static CONF_PARSER home_server_config[] = {
 	  0, &hs_srcipaddr,  NULL },
 
 	{ "response_window", PW_TYPE_INTEGER,
-	  offsetof(home_server_t,response_window), NULL,   "30" },
+	  0, &response_window, "30" },
+	{ "response_window_usec", PW_TYPE_INTEGER,
+	  0, &response_window_usec, "0" },
 	{ "max_outstanding", PW_TYPE_INTEGER,
 	  offsetof(home_server_t,max_outstanding), NULL,   "65536" },
 
@@ -386,6 +390,8 @@ static void null_free(UNUSED void *data)
 {
 }
 
+#define timerceil(ptv) ((int)(ptv)->tv_sec + ((ptv)->tv_usec ? 1 : 0))
+
 static int home_server_add(realm_config_t *rc, CONF_SECTION *cs)
 {
 	char const *name2;
@@ -725,13 +731,25 @@ static int home_server_add(realm_config_t *rc, CONF_SECTION *cs)
 	FR_INTEGER_BOUND_CHECK("ping_interval", home->ping_interval, >=, 6);
 	FR_INTEGER_BOUND_CHECK("ping_interval", home->ping_interval, <=, 120);
 
-	FR_INTEGER_BOUND_CHECK("response_window", home->response_window, >=, 1);
-	FR_INTEGER_BOUND_CHECK("response_window", home->response_window, <=, 60);
-	FR_INTEGER_BOUND_CHECK("response_window", home->response_window, <=, main_config.max_request_time);
+	FR_INTEGER_BOUND_CHECK("response_window", response_window, >=, 0);
+	FR_INTEGER_BOUND_CHECK("response_window", response_window, <=, 60);
+	FR_INTEGER_BOUND_CHECK("response_window", response_window, <=, main_config.max_request_time);
+	FR_INTEGER_BOUND_CHECK("response_window_usec", response_window_usec, >=, 0);
+	FR_INTEGER_BOUND_CHECK("response_window_usec", response_window_usec, <=, 999999);
+	FR_INTEGER_COND_CHECK("response_window_usec", response_window_usec,
+			      response_window < 60 &&
+					response_window < main_config.max_request_time,
+			      0);
+	FR_INTEGER_COND_CHECK("response_window_usec", response_window_usec,
+			      response_window > 0 || response_window_usec > 0,
+			      1);
+
+	home->response_window.tv_sec = response_window;
+	home->response_window.tv_usec = response_window_usec;
 
 	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, >=, home->response_window);
+	FR_INTEGER_BOUND_CHECK("zombie_period", home->zombie_period, >=, timerceil(&home->response_window));
 
 	FR_INTEGER_BOUND_CHECK("num_pings_to_alive", home->num_pings_to_alive, >=, 3);
 	FR_INTEGER_BOUND_CHECK("num_pings_to_alive", home->num_pings_to_alive, <=, 10);
@@ -1242,7 +1260,8 @@ static int old_server_add(realm_config_t *rc, CONF_SECTION *cs,
 		home->max_outstanding = 65535*16;
 		home->zombie_period = rc->retry_delay * rc->retry_count;
 		if (home->zombie_period == 0) home->zombie_period =30;
-		home->response_window = home->zombie_period - 1;
+		home->response_window.tv_sec = home->zombie_period - 1;
+		home->response_window.tv_usec = 0;
 
 		home->ping_check = HOME_PING_CHECK_NONE;
 
-- 
1.9.2

