diff common-session.c @ 1140:f6d3a16ecc71

set timeouts to time remaining rather than timeout duration
author Matt Johnston <matt@ucc.asn.au>
date Mon, 03 Aug 2015 23:05:43 +0800
parents 43a8ea69b24c
children 924ff1b959a2
line wrap: on
line diff
--- a/common-session.c	Mon Aug 03 21:59:40 2015 +0800
+++ b/common-session.c	Mon Aug 03 23:05:43 2015 +0800
@@ -532,20 +532,39 @@
 	}
 }
 
+static void update_timeout(long limit, long now, long last_event, long * timeout) {
+	TRACE(("update_timeout limit %ld, now %ld, last %ld, timeout %ld",
+		limit, now, last_event, *timeout))
+	if (last_event > 0 && limit > 0) {
+		*timeout = MIN(*timeout, last_event+limit-now);
+		TRACE(("update to %ld", *timeout))
+	}
+}
+
 static long select_timeout() {
 	/* determine the minimum timeout that might be required, so
 	as to avoid waking when unneccessary */
-	long ret = LONG_MAX;
-	if (KEX_REKEY_TIMEOUT > 0)
-		ret = MIN(KEX_REKEY_TIMEOUT, ret);
-	/* AUTH_TIMEOUT is only relevant before authdone */
-	if (ses.authstate.authdone != 1 && AUTH_TIMEOUT > 0)
-		ret = MIN(AUTH_TIMEOUT, ret);
-	if (opts.keepalive_secs > 0)
-		ret = MIN(opts.keepalive_secs, ret);
-	if (opts.idle_timeout_secs > 0)
-		ret = MIN(opts.idle_timeout_secs, ret);
-	return ret;
+	long timeout = LONG_MAX;
+	long now = monotonic_now();
+
+	update_timeout(KEX_REKEY_TIMEOUT, now, ses.kexstate.lastkextime, &timeout);
+
+	if (ses.authstate.authdone != 1 && IS_DROPBEAR_SERVER) {
+		/* AUTH_TIMEOUT is only relevant before authdone */
+		update_timeout(AUTH_TIMEOUT, now, ses.connect_time, &timeout);
+	}
+
+	update_timeout(opts.keepalive_secs, now, 
+		MAX(ses.last_packet_time_keepalive_recv, ses.last_packet_time_keepalive_sent),
+		&timeout);
+
+	update_timeout(opts.idle_timeout_secs, now, ses.last_packet_time_idle,
+		&timeout);
+
+	TRACE(("timeout %ld", timeout))
+
+	/* clamp negative timeouts to zero - event has already triggered */
+	return MAX(timeout, 0);
 }
 
 const char* get_user_shell() {