From 5765d274c26705082774036d4eb20c67a6e98716 Mon Sep 17 00:00:00 2001 From: Ben Manes Date: Tue, 13 Nov 2018 12:28:48 -0800 Subject: [PATCH] Add lock timeout for remote action (fixes #466) When the remove window size is expanded, a condition is waited on until the remote server acknowledges and completes the action. If the server does not respond, e.g. due to a connectivity issue, then this blocks the client indefinitely. Instead the client waits up to the connection's timeout (500 min default) and fails. This allows users to set a reasonable timeout, fail their operations, and retry accordingly. --- .../sshj/connection/channel/AbstractChannel.java | 3 ++- .../net/schmizz/sshj/connection/channel/Window.java | 12 ++++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/main/java/net/schmizz/sshj/connection/channel/AbstractChannel.java b/src/main/java/net/schmizz/sshj/connection/channel/AbstractChannel.java index 922018102..e31d0f4ee 100644 --- a/src/main/java/net/schmizz/sshj/connection/channel/AbstractChannel.java +++ b/src/main/java/net/schmizz/sshj/connection/channel/AbstractChannel.java @@ -102,7 +102,8 @@ protected AbstractChannel(Connection conn, String type, Charset remoteCharset) { protected void init(int recipient, long remoteWinSize, long remoteMaxPacketSize) { this.recipient = recipient; - rwin = new Window.Remote(remoteWinSize, (int) Math.min(remoteMaxPacketSize, REMOTE_MAX_PACKET_SIZE_CEILING), loggerFactory); + rwin = new Window.Remote(remoteWinSize, (int) Math.min(remoteMaxPacketSize, REMOTE_MAX_PACKET_SIZE_CEILING), + conn.getTimeoutMs(), loggerFactory); out = new ChannelOutputStream(this, trans, rwin); log.debug("Initialized - {}", this); } diff --git a/src/main/java/net/schmizz/sshj/connection/channel/Window.java b/src/main/java/net/schmizz/sshj/connection/channel/Window.java index 0d6faa12b..5292cea3d 100644 --- a/src/main/java/net/schmizz/sshj/connection/channel/Window.java +++ b/src/main/java/net/schmizz/sshj/connection/channel/Window.java @@ -20,6 +20,8 @@ import net.schmizz.sshj.connection.ConnectionException; import org.slf4j.Logger; +import java.util.concurrent.TimeUnit; + public abstract class Window { protected final Logger log; @@ -73,17 +75,23 @@ public String toString() { /** Controls how much data we can send before an adjustment notification from remote end is required. */ public static final class Remote extends Window { + private final long timeoutMs; - public Remote(long initialWinSize, int maxPacketSize, LoggerFactory loggerFactory) { + public Remote(long initialWinSize, int maxPacketSize, long timeoutMs, LoggerFactory loggerFactory) { super(initialWinSize, maxPacketSize, loggerFactory); + this.timeoutMs = timeoutMs; } public long awaitExpansion(long was) throws ConnectionException { synchronized (lock) { + long end = System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(timeoutMs); while (size <= was) { log.debug("Waiting, need size to grow from {} bytes", was); try { - lock.wait(); + lock.wait(timeoutMs); + if ((size <= was) && (end < System.nanoTime())) { + throw new ConnectionException("Timeout when trying to expand the window size"); + } } catch (InterruptedException ie) { throw new ConnectionException(ie); }