You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by lg...@apache.org on 2020/05/22 13:00:41 UTC

[mina-sshd] 05/05: Tighter timeout limit on wait time for SFTP server response to client message

This is an automated email from the ASF dual-hosted git repository.

lgoldstein pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mina-sshd.git

commit 4c19ef04fd2dfb35699da39abe04111dbcdaa4ff
Author: Lyor Goldstein <lg...@apache.org>
AuthorDate: Fri May 22 12:30:38 2020 +0300

    Tighter timeout limit on wait time for SFTP server response to client message
---
 .../common/util/closeable/SequentialCloseable.java |  4 +-
 .../common/util/closeable/SimpleCloseable.java     |  5 +++
 .../subsystem/sftp/impl/DefaultSftpClient.java     | 15 ++++++-
 .../client/subsystem/sftp/SftpTransferTest.java    | 50 ++++++++++++----------
 4 files changed, 48 insertions(+), 26 deletions(-)

diff --git a/sshd-common/src/main/java/org/apache/sshd/common/util/closeable/SequentialCloseable.java b/sshd-common/src/main/java/org/apache/sshd/common/util/closeable/SequentialCloseable.java
index 10f18b7..2d4a65a 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/util/closeable/SequentialCloseable.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/util/closeable/SequentialCloseable.java
@@ -51,7 +51,7 @@ public class SequentialCloseable extends SimpleCloseable {
                     Closeable c = iterator.next();
                     if (c != null) {
                         if (traceEnabled) {
-                            log.trace("doClose(" + immediately + ") closing " + c);
+                            log.trace("doClose({}) closing {} immediately={}", this, c, immediately);
                         }
                         CloseFuture nextFuture = c.close(immediately);
                         nextFuture.addListener(this);
@@ -60,7 +60,7 @@ public class SequentialCloseable extends SimpleCloseable {
                 }
                 if (!iterator.hasNext()) {
                     if (log.isDebugEnabled()) {
-                        log.debug("doClose(" + immediately + ") signal close complete");
+                        log.debug("doClose({}) signal close complete immediately={}", this, immediately);
                     }
                     future.setClosed();
                 }
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/util/closeable/SimpleCloseable.java b/sshd-common/src/main/java/org/apache/sshd/common/util/closeable/SimpleCloseable.java
index f232251..c147f72 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/util/closeable/SimpleCloseable.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/util/closeable/SimpleCloseable.java
@@ -68,4 +68,9 @@ public class SimpleCloseable extends IoBaseCloseable {
     protected void doClose(boolean immediately) {
         future.setClosed();
     }
+
+    @Override
+    public String toString() {
+        return getClass().getSimpleName() + "[" + future + "]";
+    }
 }
diff --git a/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/impl/DefaultSftpClient.java b/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/impl/DefaultSftpClient.java
index 7070c8e..16c5f81 100644
--- a/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/impl/DefaultSftpClient.java
+++ b/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/impl/DefaultSftpClient.java
@@ -309,13 +309,26 @@ public class DefaultSftpClient extends AbstractSftpClient {
                 throw new SshException("Channel is being closed");
             }
 
+            long rcvStart = System.nanoTime();
             Buffer buffer = receive(id, idleTimeout);
+            long rcvEnd = System.nanoTime();
             if (buffer != null) {
                 return buffer;
             }
 
+            long rcvDuration = TimeUnit.NANOSECONDS.toMillis(rcvEnd - rcvStart);
+            if (rcvDuration <= 0L) {
+                idleTimeout--;
+            } else {
+                idleTimeout -= rcvDuration;
+            }
+
+            if (idleTimeout <= 0L) {
+                throw new SshException("Timeout expired while waiting for id=" + id);
+            }
+
             if (traceEnabled) {
-                log.trace("receive({}) check iteration #{} for id={}", this, count, id);
+                log.trace("receive({}) check iteration #{} for id={} remain time={}", this, count, id, idleTimeout);
             }
         }
     }
diff --git a/sshd-sftp/src/test/java/org/apache/sshd/client/subsystem/sftp/SftpTransferTest.java b/sshd-sftp/src/test/java/org/apache/sshd/client/subsystem/sftp/SftpTransferTest.java
index 8653ee0..05f94b4 100644
--- a/sshd-sftp/src/test/java/org/apache/sshd/client/subsystem/sftp/SftpTransferTest.java
+++ b/sshd-sftp/src/test/java/org/apache/sshd/client/subsystem/sftp/SftpTransferTest.java
@@ -44,32 +44,36 @@ public class SftpTransferTest extends AbstractSftpClientTestSupport {
 
     @Test
     public void testTransferIntegrity() throws IOException {
+        Path localRoot = detectTargetFolder().resolve("sftp");
+        Files.createDirectories(localRoot);
+
+        Path local0 = localRoot.resolve("files-0.txt");
+        Files.deleteIfExists(local0);
+
+        String data = getClass().getName() + "#" + getCurrentTestName() + "(" + new Date() + ")" + System.lineSeparator();
+        try (BufferedWriter bos = Files.newBufferedWriter(local0)) {
+            long count = 0L;
+            while (count < 1024L * 1024L * 10L) { // 10 MB
+                bos.append(data);
+                count += data.length();
+            }
+        }
+
         try (ClientSession session = createClientSession();
              SftpFileSystem fs = SftpClientFactory.instance().createSftpFileSystem(session)) {
 
-            Path localRoot = detectTargetFolder().resolve("sftp");
             Path remoteRoot = fs.getDefaultDir().resolve("target/sftp");
-
-            Path local0 = localRoot.resolve("files-0.txt");
             Path remote0 = remoteRoot.resolve("files-1.txt");
-            Path local1 = localRoot.resolve("files-2.txt");
-            Path remote1 = remoteRoot.resolve("files-3.txt");
-            Path local2 = localRoot.resolve("files-4.txt");
-            Files.deleteIfExists(local0);
             Files.deleteIfExists(remote0);
+
+            Path local1 = localRoot.resolve("files-2.txt");
             Files.deleteIfExists(local1);
+
+            Path remote1 = remoteRoot.resolve("files-3.txt");
             Files.deleteIfExists(remote1);
-            Files.deleteIfExists(local2);
 
-            Files.createDirectories(localRoot);
-            String data = getClass().getName() + "#" + getCurrentTestName() + "(" + new Date() + ")\n";
-            try (BufferedWriter bos = Files.newBufferedWriter(local0)) {
-                long count = 0;
-                while (count < 1024 * 1024 * 10) { // 10 MB
-                    bos.append(data);
-                    count += data.length();
-                }
-            }
+            Path local2 = localRoot.resolve("files-4.txt");
+            Files.deleteIfExists(local2);
 
             Files.copy(local0, remote0);
             Files.copy(remote0, local1);
@@ -93,11 +97,12 @@ public class SftpTransferTest extends AbstractSftpClientTestSupport {
         }
     }
 
-    private boolean sameContent(Path path, Path path2) throws IOException {
-        byte[] buffer1 = new byte[BUFFER_SIZE];
-        byte[] buffer2 = new byte[BUFFER_SIZE];
+    private static boolean sameContent(Path path, Path path2) throws IOException {
         try (InputStream in1 = Files.newInputStream(path);
              InputStream in2 = Files.newInputStream(path2)) {
+            byte[] buffer1 = new byte[BUFFER_SIZE];
+            byte[] buffer2 = new byte[BUFFER_SIZE];
+
             while (true) {
                 int nRead1 = readNBytes(in1, buffer1);
                 int nRead2 = readNBytes(in2, buffer2);
@@ -119,17 +124,16 @@ public class SftpTransferTest extends AbstractSftpClientTestSupport {
         }
     }
 
-    private int readNBytes(InputStream is, byte[] b) throws IOException {
+    private static int readNBytes(InputStream is, byte[] b) throws IOException {
         int n = 0;
         int len = b.length;
         while (n < len) {
             int count = is.read(b, n, len - n);
             if (count < 0) {
-                break;
+                return n;
             }
             n += count;
         }
         return n;
     }
-
 }