[PATCH] ServerAliveInterval doesn't work if client keeps trying to send data

J Raynor jxraynor at gmail.com
Mon May 25 08:48:49 AEST 2020


If ServerAliveInterval should work even if the client keeps trying to 
send data, then please consider this patch.


diff --git a/clientloop.c b/clientloop.c
index da396c7..358b526 100644
--- a/clientloop.c
+++ b/clientloop.c
@@ -162,6 +162,7 @@ static int connection_out;	/* Connection to server 
(output). */
  static int need_rekeying;	/* Set to non-zero if rekeying is requested. */
  static int session_closed;	/* In SSH2: login session closed. */
  static u_int x11_refuse_time;	/* If >0, refuse x11 opens after this 
time. */
+static time_t server_alive_time;	/* Time to do server_alive_check */

  static void client_init_dispatch(struct ssh *ssh);
  int	session_ident = -1;
@@ -495,7 +496,7 @@ client_wait_until_can_do_something(struct ssh *ssh,
  {
  	struct timeval tv, *tvp;
  	int timeout_secs;
-	time_t minwait_secs = 0, server_alive_time = 0, now = monotime();
+	time_t minwait_secs = 0, now = monotime();
  	int r, ret;

  	/* Add any selections by the channel mechanism. */
@@ -525,8 +526,9 @@ client_wait_until_can_do_something(struct ssh *ssh,

  	timeout_secs = INT_MAX; /* we use INT_MAX to mean no timeout */
  	if (options.server_alive_interval > 0) {
-		timeout_secs = options.server_alive_interval;
-		server_alive_time = now + options.server_alive_interval;
+		timeout_secs = server_alive_time - now;
+		if (timeout_secs < 0)
+			timeout_secs = 0;
  	}
  	if (options.rekey_interval > 0 && !rekeying)
  		timeout_secs = MINIMUM(timeout_secs,
@@ -565,13 +567,14 @@ client_wait_until_can_do_something(struct ssh *ssh,
  		    "select: %s\r\n", strerror(errno))) != 0)
  			fatal("%s: buffer error: %s", __func__, ssh_err(r));
  		quit_pending = 1;
-	} else if (ret == 0) {
-		/*
-		 * Timeout.  Could have been either keepalive or rekeying.
-		 * Keepalive we check here, rekeying is checked in clientloop.
-		 */
-		if (server_alive_time != 0 && server_alive_time <= monotime())
+	} else {
+		/* See if keepalive check needs to be done */
+		if (options.server_alive_interval > 0
+		    && ! FD_ISSET(connection_in, *readsetp)
+		    && (now = monotime()) >= server_alive_time ) {
+			server_alive_time = now + options.server_alive_interval;
  			server_alive_check(ssh);
+		}
  	}

  }
@@ -613,6 +616,8 @@ client_process_net_input(struct ssh *ssh, fd_set 
*readset)
  	 * the packet subsystem.
  	 */
  	if (FD_ISSET(connection_in, readset)) {
+		if (options.server_alive_interval > 0)
+			server_alive_time = monotime() + options.server_alive_interval;
  		/* Read as much as possible. */
  		len = read(connection_in, buf, sizeof(buf));
  		if (len == 0) {
@@ -1314,6 +1319,9 @@ client_loop(struct ssh *ssh, int have_pty, int 
escape_char_arg,
  		    client_channel_closed, 0);
  	}

+	if (options.server_alive_interval > 0)
+		server_alive_time = monotime() + options.server_alive_interval;
+
  	/* Main loop of the client for the interactive session mode. */
  	while (!quit_pending) {




On 5/23/20 4:36 PM, J Raynor wrote:
> The ServerAliveInterval option is supposed to check the connection "if
> no data has been received from the server" during the interval.
> However, if the client side keeps trying to write data, the check is
> never performed.
> 
> For example, run this command:
> 
> while true; do date ; sleep 3; done | ssh -o ServerAliveInterval=10 -o
> ServerAliveCountMax=2 YourSshServer cat
> 
> Once the connection is established, break the communication between
> the client and server.  For example, add a bad route to the client on
> YourSshServer, or take down the server's network interface, or pause
> the server if it is a VM.
> 
> Once the communication is broken, given the options listed above, the
> connection should time out in about 20 seconds.  But it won't.  It
> appears to stay alive until a tcp timeout occurs.
> 
> Is the ServerAliveInterval option only supposed to work if the client
> is idle?  Or, at least, only if the client tries to transmit data less
> often than the interval?
> 


More information about the openssh-unix-dev mailing list