Skip to content

Commit

Permalink
Add lock timeout for remote action (fixes #466) (#468)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
ben-manes authored and hierynomus committed Nov 16, 2018
1 parent 8134696 commit 971ccf6
Show file tree
Hide file tree
Showing 2 changed files with 12 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
12 changes: 10 additions & 2 deletions src/main/java/net/schmizz/sshj/connection/channel/Window.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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) && ((System.nanoTime() - end) > 0)) {
throw new ConnectionException("Timeout when trying to expand the window size");
}
} catch (InterruptedException ie) {
throw new ConnectionException(ie);
}
Expand Down

0 comments on commit 971ccf6

Please sign in to comment.