Add lock timeout for remote action (fixes #466) (#468)

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.
This commit is contained in:
Ben Manes
2018-11-16 00:33:48 -08:00
committed by Jeroen van Erp
parent 813469646e
commit 971ccf6273
2 changed files with 12 additions and 3 deletions

View File

@@ -102,7 +102,8 @@ public abstract class AbstractChannel
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);
}

View File

@@ -20,6 +20,8 @@ import net.schmizz.sshj.common.SSHRuntimeException;
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 abstract class Window {
/** 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) && ((System.nanoTime() - end) > 0)) {
throw new ConnectionException("Timeout when trying to expand the window size");
}
} catch (InterruptedException ie) {
throw new ConnectionException(ie);
}