Repository: mina-sshd
Updated Branches:
  refs/heads/master 92c24d13c -> 77af61d35


[SSHD-85] Port Forward closes connection before all bytes are sent


Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/77af61d3
Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/77af61d3
Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/77af61d3

Branch: refs/heads/master
Commit: 77af61d35d0fda4c8179c074088eb46fe1a3fbbe
Parents: 92c24d1
Author: Bill Kuker <bku...@martellotech.com>
Authored: Thu Jun 22 23:15:00 2017 +0300
Committer: Goldstein Lyor <l...@c-b4.com>
Committed: Sun Jun 25 07:46:57 2017 +0300

----------------------------------------------------------------------
 .../sshd/common/config/keys/PublicKeyEntry.java |   4 +-
 .../apache/sshd/common/io/nio2/Nio2Session.java |  10 +-
 .../forward/AbstractServerCloseTestSupport.java | 233 +++++++++++++++++++
 .../forward/ApacheServerApacheClientTest.java   | 114 +++++++++
 .../forward/ApacheServerJSchClientTest.java     | 121 ++++++++++
 .../common/forward/NoServerNoClientTest.java    |  42 ++++
 6 files changed, 521 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/77af61d3/sshd-core/src/main/java/org/apache/sshd/common/config/keys/PublicKeyEntry.java
----------------------------------------------------------------------
diff --git 
a/sshd-core/src/main/java/org/apache/sshd/common/config/keys/PublicKeyEntry.java
 
b/sshd-core/src/main/java/org/apache/sshd/common/config/keys/PublicKeyEntry.java
index 41e7b42..acbd71a 100644
--- 
a/sshd-core/src/main/java/org/apache/sshd/common/config/keys/PublicKeyEntry.java
+++ 
b/sshd-core/src/main/java/org/apache/sshd/common/config/keys/PublicKeyEntry.java
@@ -167,8 +167,8 @@ public class PublicKeyEntry implements Serializable {
     }
 
     /**
-     * @param data Assumed to contain at least {@code key-type base64-data} 
(anything
-     *             beyond the BASE64 data is ignored) - ignored if {@code 
null}/empty
+     * @param encData Assumed to contain at least {@code key-type base64-data}
+     * (anything beyond the BASE64 data is ignored) - ignored if {@code 
null}/empty
      * @return A {@link PublicKeyEntry} or {@code null} if no data
      * @throws IllegalArgumentException if bad format found
      * @see #parsePublicKeyEntry(PublicKeyEntry, String)

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/77af61d3/sshd-core/src/main/java/org/apache/sshd/common/io/nio2/Nio2Session.java
----------------------------------------------------------------------
diff --git 
a/sshd-core/src/main/java/org/apache/sshd/common/io/nio2/Nio2Session.java 
b/sshd-core/src/main/java/org/apache/sshd/common/io/nio2/Nio2Session.java
index 32d39b5..1384092 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/io/nio2/Nio2Session.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/io/nio2/Nio2Session.java
@@ -179,7 +179,15 @@ public class Nio2Session extends AbstractCloseable 
implements IoSession {
 
     @Override
     protected CloseFuture doCloseGracefully() {
-        return builder().when(writes).build().close(false);
+        return builder().when(writes).run(() -> {
+            try {
+                AsynchronousSocketChannel socket = getSocket();
+                socket.shutdownOutput();
+            } catch (IOException e) {
+                log.info("doCloseGracefully({}) {} while shutting down output: 
{}",
+                         this, e.getClass().getSimpleName(), e.getMessage());
+            }
+        }).build().close(false);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/77af61d3/sshd-core/src/test/java/org/apache/sshd/common/forward/AbstractServerCloseTestSupport.java
----------------------------------------------------------------------
diff --git 
a/sshd-core/src/test/java/org/apache/sshd/common/forward/AbstractServerCloseTestSupport.java
 
b/sshd-core/src/test/java/org/apache/sshd/common/forward/AbstractServerCloseTestSupport.java
new file mode 100644
index 0000000..33a7c94
--- /dev/null
+++ 
b/sshd-core/src/test/java/org/apache/sshd/common/forward/AbstractServerCloseTestSupport.java
@@ -0,0 +1,233 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sshd.common.forward;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.nio.ByteBuffer;
+import java.nio.channels.AsynchronousServerSocketChannel;
+import java.nio.channels.AsynchronousSocketChannel;
+import java.nio.channels.CompletionHandler;
+import java.nio.charset.StandardCharsets;
+import java.util.Collections;
+
+import org.apache.sshd.util.test.BaseTestSupport;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Port forwarding tests
+ */
+public abstract class AbstractServerCloseTestSupport extends BaseTestSupport {
+    private static final String PAYLOAD = String.join("", 
Collections.nCopies(200, "This is significantly longer Test Data."));
+
+    protected int testServerPort;
+    private final Logger log;
+    private AsynchronousServerSocketChannel testServerSock;
+
+    protected AbstractServerCloseTestSupport() {
+        log = LoggerFactory.getLogger(getClass());
+    }
+
+    /*
+     * Start a server to forward to.
+     *
+     * This server sends PAYLOAD and then closes.
+     */
+    @Before
+    public void startTestServer() throws Exception {
+        InetSocketAddress sockAddr = new InetSocketAddress(TEST_LOCALHOST, 0);
+        testServerSock = AsynchronousServerSocketChannel.open().bind(sockAddr);
+        InetSocketAddress boundAddress = (InetSocketAddress) 
testServerSock.getLocalAddress();
+        testServerPort = boundAddress.getPort();
+        log.info("Listening on port {}", testServerPort);
+        // Accept a connection
+        testServerSock.accept(testServerSock,
+                new CompletionHandler<AsynchronousSocketChannel, 
AsynchronousServerSocketChannel>() {
+                    @Override
+                    @SuppressWarnings("synthetic-access")
+                    public void completed(AsynchronousSocketChannel 
sockChannel, AsynchronousServerSocketChannel serverSock) {
+                        // a connection is accepted, start to accept next 
connection
+                        serverSock.accept(serverSock, this);
+                        log.info("Accepted new incoming connection");
+
+                        ByteBuffer buf = 
ByteBuffer.wrap(PAYLOAD.getBytes(StandardCharsets.UTF_8));
+                        // start to write payload to client
+                        sockChannel.write(buf, sockChannel,
+                                new CompletionHandler<Integer, 
AsynchronousSocketChannel>() {
+                                    @Override
+                                    public void completed(Integer result, 
AsynchronousSocketChannel channel) {
+                                        // Write has been completed, close the
+                                        // connection to the client
+                                        try {
+                                            channel.close();
+                                        } catch (IOException e) {
+                                            log.warn("Failed ({}) to close 
channel after write complete: {}",
+                                                     
e.getClass().getSimpleName(), e.getMessage());
+                                        }
+                                    }
+
+                                    @Override
+                                    public void failed(Throwable exc, 
AsynchronousSocketChannel channel) {
+                                        log.error("Failed ({}) to write 
message to client: {}", exc.getClass().getSimpleName(), exc.getMessage());
+                                    }
+                                });
+                    }
+
+                    @Override
+                    @SuppressWarnings("synthetic-access")
+                    public void failed(Throwable exc, 
AsynchronousServerSocketChannel serverSock) {
+                        log.error("Failed ({}) to accept incoming connection: 
{}", exc.getClass().getSimpleName(), exc.getMessage());
+                    }
+                });
+    }
+
+    @After
+    public void stopTestServer() throws Exception {
+        testServerSock.close();
+    }
+
+    private void readInLoop(int serverPort) throws Exception {
+        outputDebugMessage("readInLoop(port=%d)", serverPort);
+
+        StringBuilder sb = new StringBuilder(PAYLOAD.length());
+        try (Socket s = new Socket(TEST_LOCALHOST, serverPort)) {
+            s.setSoTimeout(300);
+
+            try (InputStream inputStream = s.getInputStream()) {
+                byte b[] = new byte[PAYLOAD.length() / 10];
+                while (true) {
+                    int readLen = inputStream.read(b);
+                    if (readLen == -1) {
+                        break;
+                    }
+                    outputDebugMessage("readInLoop(port=%d) read %d bytes", 
serverPort, readLen);
+
+                    String fragment = new String(b, 0, readLen, 
StandardCharsets.UTF_8);
+                    sb.append(fragment);
+                    Thread.sleep(25L);
+                }
+            }
+        } catch (IOException e) {
+            String readData = sb.toString();
+            assertEquals("Mismatched data length", PAYLOAD.length(), 
readData.length());
+            assertEquals("Mismatched read data", PAYLOAD, readData);
+        }
+    }
+
+    private void readInOneBuffer(int serverPort) throws Exception {
+        outputDebugMessage("readInOneBuffer(port=%d)", serverPort);
+        try (Socket s = new Socket(TEST_LOCALHOST, serverPort)) {
+            s.setSoTimeout(300);
+
+            byte buf[] = new byte[PAYLOAD.length()];
+            try (InputStream inputStream = s.getInputStream()) {
+                int readCount = inputStream.read(buf);
+                outputDebugMessage("readInOneBuffer(port=%d) - Got %d bytes 
from the server", serverPort, readCount);
+
+                String actual = new String(buf, 0, readCount, 
StandardCharsets.UTF_8);
+                assertEquals("Mismatched read data", PAYLOAD, actual);
+            }
+        }
+    }
+
+    private void readInTwoBuffersWithPause(int serverPort) throws Exception {
+        outputDebugMessage("readInTwoBuffersWithPause(port=%d)", serverPort);
+        try (Socket s = new Socket(TEST_LOCALHOST, serverPort)) {
+            s.setSoTimeout(300);
+            byte b1[] = new byte[PAYLOAD.length() / 2];
+            byte b2[] = new byte[PAYLOAD.length()];
+
+            try (InputStream inputStream = s.getInputStream()) {
+                int read1 = inputStream.read(b1);
+                outputDebugMessage("readInTwoBuffersWithPause(port=%d) - 1st 
half is %d bytes", serverPort, read1);
+                String half1 = new String(b1, 0, read1, 
StandardCharsets.UTF_8);
+
+                Thread.sleep(50L);
+                try {
+                    int read2 = inputStream.read(b2);
+                    outputDebugMessage("readInTwoBuffersWithPause(port=%d) - 
2nd half is %d bytes", serverPort, read2);
+
+                    String half2 = new String(b2, 0, read2, 
StandardCharsets.UTF_8);
+                    assertEquals("Mismatched read data", PAYLOAD, half1 + 
half2);
+                } catch (IOException e) {
+                    log.error("Disconnected ({}) before all data read: {}", 
e.getClass().getSimpleName(), e.getMessage());
+                    throw e;
+                }
+            }
+        }
+    }
+
+    protected abstract int startRemotePF() throws Exception;
+
+    protected abstract int startLocalPF() throws Exception;
+
+    /*
+     * Connect to test server via port forward and read real quick with one big
+     * buffer.
+     *
+     * PROVIDED AS TEST THAT HAS ALWAYS PASSED
+     */
+    @Test
+    public void testRemotePortForwardOneBuffer() throws Exception {
+        readInOneBuffer(startRemotePF());
+    }
+
+    /*
+     * Connect to test server via port forward and read real quick with one big
+     * buffer.
+     *
+     * THIS IS THE TEST OF SSHD-85
+     */
+    @Test
+    public void testRemotePortForwardTwoBuffers() throws Exception {
+        readInTwoBuffersWithPause(startRemotePF());
+    }
+
+    @Test
+    public void testRemotePortForwardLoop() throws Exception {
+        readInLoop(startRemotePF());
+    }
+
+    @Test
+    public void testLocalPortForwardOneBuffer() throws Exception {
+        readInOneBuffer(startLocalPF());
+    }
+
+    /*
+     * Connect to test server via port forward and read with 2 buffers and a
+     * pause in between.
+     *
+     * THIS IS THE TEST OF SSHD-85
+     */
+    @Test
+    public void testLocalPortForwardTwoBuffers() throws Exception {
+        readInTwoBuffersWithPause(startLocalPF());
+    }
+
+    @Test
+    public void testLocalPortForwardLoop() throws Exception {
+        readInLoop(startLocalPF());
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/77af61d3/sshd-core/src/test/java/org/apache/sshd/common/forward/ApacheServerApacheClientTest.java
----------------------------------------------------------------------
diff --git 
a/sshd-core/src/test/java/org/apache/sshd/common/forward/ApacheServerApacheClientTest.java
 
b/sshd-core/src/test/java/org/apache/sshd/common/forward/ApacheServerApacheClientTest.java
new file mode 100644
index 0000000..f6ac886
--- /dev/null
+++ 
b/sshd-core/src/test/java/org/apache/sshd/common/forward/ApacheServerApacheClientTest.java
@@ -0,0 +1,114 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sshd.common.forward;
+
+import java.io.IOException;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.sshd.client.SshClient;
+import org.apache.sshd.client.session.ClientSession;
+import org.apache.sshd.common.util.net.SshdSocketAddress;
+import org.apache.sshd.server.SshServer;
+import org.apache.sshd.server.forward.AcceptAllForwardingFilter;
+import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.FixMethodOrder;
+import org.junit.runners.MethodSorters;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Port forwarding tests, Apache server & client
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class ApacheServerApacheClientTest extends 
AbstractServerCloseTestSupport {
+    private static final Logger LOG = 
LoggerFactory.getLogger(ApacheServerApacheClientTest.class);
+
+    private static final long TIMEOUT = TimeUnit.SECONDS.toMillis(10L);
+
+    private static int sshServerPort;
+    private static SshServer server;
+
+    private ClientSession session;
+
+    public ApacheServerApacheClientTest() {
+        super();
+    }
+
+    @BeforeClass
+    public static void startSshServer() throws IOException {
+        LOG.info("Starting SSHD...");
+        server = SshServer.setUpDefaultServer();
+        server.setPasswordAuthenticator((u, p, s) -> true);
+        server.setTcpipForwardingFilter(AcceptAllForwardingFilter.INSTANCE);
+        server.setKeyPairProvider(new SimpleGeneratorHostKeyProvider());
+        server.start();
+        sshServerPort = server.getPort();
+        LOG.info("SSHD Running on port {}", server.getPort());
+    }
+
+    @AfterClass
+    public static void stopServer() throws IOException {
+        if (!server.close(true).await(TIMEOUT)) {
+            LOG.warn("Failed to close server within {} sec.", 
TimeUnit.MILLISECONDS.toSeconds(TIMEOUT));
+        }
+    }
+
+    @Before
+    public void createClient() throws IOException {
+        SshClient client = SshClient.setUpDefaultClient();
+        client.setTcpipForwardingFilter(AcceptAllForwardingFilter.INSTANCE);
+        client.start();
+        LOG.info("Connecting...");
+        session = client.connect("user", TEST_LOCALHOST, 
sshServerPort).verify(TIMEOUT).getSession();
+        LOG.info("Authenticating...");
+        session.addPasswordIdentity("foo");
+        session.auth().verify(TIMEOUT);
+        LOG.info("Authenticated");
+    }
+
+    @After
+    public void stopClient() throws Exception {
+        LOG.info("Disconnecting Client");
+        try {
+            assertTrue("Failed to close session", 
session.close(true).await(TIMEOUT));
+        } finally {
+            session = null;
+        }
+    }
+
+    @Override
+    protected int startRemotePF() throws Exception {
+        SshdSocketAddress remote = new SshdSocketAddress(TEST_LOCALHOST, 0);
+        SshdSocketAddress local = new SshdSocketAddress(TEST_LOCALHOST, 
testServerPort);
+        SshdSocketAddress bound = session.startRemotePortForwarding(remote, 
local);
+        return bound.getPort();
+    }
+
+    @Override
+    protected int startLocalPF() throws Exception {
+        SshdSocketAddress remote = new SshdSocketAddress(TEST_LOCALHOST, 0);
+        SshdSocketAddress local = new SshdSocketAddress(TEST_LOCALHOST, 
testServerPort);
+        SshdSocketAddress bound = session.startLocalPortForwarding(remote, 
local);
+        return bound.getPort();
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/77af61d3/sshd-core/src/test/java/org/apache/sshd/common/forward/ApacheServerJSchClientTest.java
----------------------------------------------------------------------
diff --git 
a/sshd-core/src/test/java/org/apache/sshd/common/forward/ApacheServerJSchClientTest.java
 
b/sshd-core/src/test/java/org/apache/sshd/common/forward/ApacheServerJSchClientTest.java
new file mode 100644
index 0000000..3f15a91
--- /dev/null
+++ 
b/sshd-core/src/test/java/org/apache/sshd/common/forward/ApacheServerJSchClientTest.java
@@ -0,0 +1,121 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sshd.common.forward;
+
+import java.io.IOException;
+import java.net.ServerSocket;
+import java.util.concurrent.TimeUnit;
+
+import com.jcraft.jsch.JSch;
+import com.jcraft.jsch.Session;
+
+import org.apache.sshd.server.SshServer;
+import org.apache.sshd.server.forward.AcceptAllForwardingFilter;
+import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
+import org.apache.sshd.util.test.JSchLogger;
+import org.apache.sshd.util.test.SimpleUserInfo;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.FixMethodOrder;
+import org.junit.runners.MethodSorters;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Port forwarding tests - Apache server, JSch client
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class ApacheServerJSchClientTest extends AbstractServerCloseTestSupport 
{
+    private static final long TIMEOUT = TimeUnit.SECONDS.toMillis(10L);
+    private static final Logger LOG = 
LoggerFactory.getLogger(ApacheServerJSchClientTest.class);
+
+    private static int sshServerPort;
+    private static SshServer server;
+
+    private Session session;
+
+    public ApacheServerJSchClientTest() {
+        super();
+    }
+
+    private static int findFreePort() throws IOException {
+        try (ServerSocket socket = new ServerSocket(0)) {
+            return socket.getLocalPort();
+        }
+    }
+
+    /*
+     * Starts an SSH Server
+     */
+    @BeforeClass
+    public static void startSshServer() throws IOException {
+        LOG.info("Starting SSHD...");
+        server = SshServer.setUpDefaultServer();
+        server.setPasswordAuthenticator((u, p, s) -> true);
+        server.setTcpipForwardingFilter(AcceptAllForwardingFilter.INSTANCE);
+        server.setKeyPairProvider(new SimpleGeneratorHostKeyProvider());
+        server.start();
+        sshServerPort = server.getPort();
+        LOG.info("SSHD Running on port {}", server.getPort());
+    }
+
+    @BeforeClass
+    public static void jschInit() {
+        JSchLogger.init();
+    }
+
+    @AfterClass
+    public static void stopServer() throws IOException {
+        if (!server.close(true).await(TIMEOUT)) {
+            LOG.warn("Failed to close server within {} sec.", 
TimeUnit.MILLISECONDS.toSeconds(TIMEOUT));
+        }
+    }
+
+    @Before
+    public void createClient() throws Exception {
+        JSch client = new JSch();
+        session = client.getSession("user", TEST_LOCALHOST, sshServerPort);
+        session.setUserInfo(new SimpleUserInfo("password"));
+        LOG.trace("Connecting session...");
+        session.connect();
+        LOG.trace("Client is running now...");
+    }
+
+    @After
+    public void stopClient() throws Exception {
+        LOG.info("Disconnecting Client");
+        session.disconnect();
+    }
+
+    @Override
+    protected int startRemotePF() throws Exception {
+        int port = findFreePort();
+        session.setPortForwardingR(TEST_LOCALHOST, port, TEST_LOCALHOST, 
testServerPort);
+        return port;
+    }
+
+    @Override
+    protected int startLocalPF() throws Exception {
+        int port = findFreePort();
+        session.setPortForwardingL(TEST_LOCALHOST, port, TEST_LOCALHOST, 
testServerPort);
+        return port;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/77af61d3/sshd-core/src/test/java/org/apache/sshd/common/forward/NoServerNoClientTest.java
----------------------------------------------------------------------
diff --git 
a/sshd-core/src/test/java/org/apache/sshd/common/forward/NoServerNoClientTest.java
 
b/sshd-core/src/test/java/org/apache/sshd/common/forward/NoServerNoClientTest.java
new file mode 100644
index 0000000..712114c
--- /dev/null
+++ 
b/sshd-core/src/test/java/org/apache/sshd/common/forward/NoServerNoClientTest.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sshd.common.forward;
+
+import org.junit.FixMethodOrder;
+import org.junit.runners.MethodSorters;
+
+/**
+ * Port forwarding tests - Control, direct connect. No SSH
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class NoServerNoClientTest extends AbstractServerCloseTestSupport {
+    public NoServerNoClientTest() {
+        super();
+    }
+
+    @Override
+    protected int startRemotePF() throws Exception {
+        return testServerPort;
+    }
+
+    @Override
+    protected int startLocalPF() throws Exception {
+        return testServerPort;
+    }
+}
\ No newline at end of file

Reply via email to