[SSHD-192] Allow factory-injected replacement for client tcpip forward support

git-svn-id: https://svn.apache.org/repos/asf/mina/sshd/trunk@1393417 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/sshd-core/src/main/java/org/apache/sshd/ClientSession.java b/sshd-core/src/main/java/org/apache/sshd/ClientSession.java
index d0faac5..5f276a0 100644
--- a/sshd-core/src/main/java/org/apache/sshd/ClientSession.java
+++ b/sshd-core/src/main/java/org/apache/sshd/ClientSession.java
@@ -22,6 +22,7 @@
 import java.security.KeyPair;
 import java.util.Map;
 
+import org.apache.sshd.client.ClientFactoryManager;
 import org.apache.sshd.client.SshdSocketAddress;
 import org.apache.sshd.client.channel.ChannelDirectTcpip;
 import org.apache.sshd.client.channel.ChannelExec;
@@ -70,7 +71,7 @@
     AuthFuture authPassword(String username, String password) throws IOException;
 
     /**
-     * Authenticate the session with the gien username and public key.
+     * Authenticate the session with the given username and public key.
      */
     AuthFuture authPublicKey(String username, KeyPair key) throws IOException;
 
@@ -154,4 +155,9 @@
      */
     Map<Object, Object> getMetadataMap();
 
+    /**
+     * Return ClientFactoryManager for this session.
+     */
+    ClientFactoryManager getClientFactoryManager();
+
 }
diff --git a/sshd-core/src/main/java/org/apache/sshd/SshClient.java b/sshd-core/src/main/java/org/apache/sshd/SshClient.java
index 1661d38..72bf2ff 100644
--- a/sshd-core/src/main/java/org/apache/sshd/SshClient.java
+++ b/sshd-core/src/main/java/org/apache/sshd/SshClient.java
@@ -47,6 +47,8 @@
 import org.apache.sshd.client.kex.DHG14;
 import org.apache.sshd.client.session.ChannelForwardedTcpip;
 import org.apache.sshd.client.session.ClientSessionImpl;
+import org.apache.sshd.client.session.DefaultTcpipForwarderFactory;
+import org.apache.sshd.client.session.TcpipForwarderFactory;
 import org.apache.sshd.common.AbstractFactoryManager;
 import org.apache.sshd.common.Channel;
 import org.apache.sshd.common.Cipher;
@@ -133,6 +135,7 @@
     protected SessionFactory sessionFactory;
 
     private ServerKeyVerifier serverKeyVerifier;
+    private TcpipForwarderFactory tcpipForwarderFactory;
 
     public SshClient() {
     }
@@ -153,6 +156,14 @@
         this.serverKeyVerifier = serverKeyVerifier;
     }
 
+    public TcpipForwarderFactory getTcpipForwarderFactory() {
+       return tcpipForwarderFactory;
+    }
+
+    public void setTcpipForwarderFactory(TcpipForwarderFactory tcpipForwarderFactory) {
+       this.tcpipForwarderFactory = tcpipForwarderFactory;
+    }
+
     protected void checkConfig() {
         if (getKeyExchangeFactories() == null) {
             throw new IllegalArgumentException("KeyExchangeFactories not set");
@@ -281,6 +292,8 @@
                 new ChannelForwardedTcpip.Factory()));
         ForwardingAcceptorFactory faf = new DefaultForwardingAcceptorFactory();
         client.setTcpipForwardNioSocketAcceptorFactory(faf);
+        TcpipForwarderFactory tcpipForwarderFactory = new DefaultTcpipForwarderFactory();
+        client.setTcpipForwarderFactory( tcpipForwarderFactory );
         return client;
     }
 
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/ClientFactoryManager.java b/sshd-core/src/main/java/org/apache/sshd/client/ClientFactoryManager.java
index aa220d8..d9eec6f 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/ClientFactoryManager.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/ClientFactoryManager.java
@@ -18,7 +18,9 @@
  */
 package org.apache.sshd.client;
 
+import org.apache.sshd.client.session.TcpipForwarderFactory;
 import org.apache.sshd.common.FactoryManager;
+import org.apache.sshd.common.ForwardingAcceptorFactory;
 
 /**
  * The <code>ClientFactoryManager</code> enable the retrieval of additional
@@ -46,4 +48,11 @@
      */
     ServerKeyVerifier getServerKeyVerifier();
 
+    /**
+     * Retrieve the TcpipForwarder factory to be used to accept incoming connections
+     * and forward data.
+     *
+     * @return A <code>TcpipForwarderFactory</code>
+     */
+    TcpipForwarderFactory getTcpipForwarderFactory();
 }
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSessionImpl.java b/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSessionImpl.java
index a463f8f..a4a4e85 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSessionImpl.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSessionImpl.java
@@ -69,7 +69,7 @@
     private State state = State.ReceiveKexInit;
     private UserAuth userAuth;
     private AuthFuture authFuture;
-    private final TcpipForwardSupport tcpipForward;
+    private final TcpipForwarder tcpipForward;
     private final Map<Integer, SshdSocketAddress> forwards = new HashMap<Integer, SshdSocketAddress>();
 
     /**
@@ -77,9 +77,9 @@
      */
     private Map<Object, Object> metadataMap = new HashMap<Object, Object>();
 
-    public ClientSessionImpl(FactoryManager client, IoSession session) throws Exception {
+    public ClientSessionImpl(ClientFactoryManager client, IoSession session) throws Exception {
         super(client, session);
-        tcpipForward = new TcpipForwardSupport(this);
+        tcpipForward = client.getTcpipForwarderFactory().createTcpipForwarder( this );
         log.info("Session created...");
         sendClientIdentification();
         sendKexInit();
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/session/DefaultTcpipForwarderFactory.java b/sshd-core/src/main/java/org/apache/sshd/client/session/DefaultTcpipForwarderFactory.java
new file mode 100644
index 0000000..633709c
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/session/DefaultTcpipForwarderFactory.java
@@ -0,0 +1,30 @@
+/*
+ * 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.client.session;
+
+import org.apache.sshd.ClientSession;
+
+public class DefaultTcpipForwarderFactory
+      implements TcpipForwarderFactory
+{
+   public TcpipForwarder createTcpipForwarder( ClientSession clientsession )
+   {
+      return new TcpipForwardSupport( clientsession );
+   }
+}
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/session/TcpipForwardSupport.java b/sshd-core/src/main/java/org/apache/sshd/client/session/TcpipForwardSupport.java
index 55db431..cd2ddee 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/session/TcpipForwardSupport.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/session/TcpipForwardSupport.java
@@ -32,6 +32,7 @@
 import org.apache.mina.filter.executor.ExecutorFilter;
 import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
 import org.apache.sshd.ClientChannel;
+import org.apache.sshd.ClientSession;
 import org.apache.sshd.client.SshdSocketAddress;
 import org.apache.sshd.client.channel.AbstractClientChannel;
 import org.apache.sshd.client.future.DefaultOpenFuture;
@@ -46,13 +47,13 @@
 /**
  * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
  */
-public class TcpipForwardSupport extends IoHandlerAdapter {
+public class TcpipForwardSupport extends IoHandlerAdapter implements TcpipForwarder {
 
-    private final ClientSessionImpl session;
-    private IoAcceptor acceptor;
-    private Map<Integer, SshdSocketAddress> forwards = new HashMap<Integer, SshdSocketAddress>();
+    protected final ClientSession session;
+    protected IoAcceptor acceptor;
+    protected Map<Integer, SshdSocketAddress> forwards = new HashMap<Integer, SshdSocketAddress>();
 
-    public TcpipForwardSupport(ClientSessionImpl session) {
+    public TcpipForwardSupport(ClientSession session) {
         this.session = session;
     }
 
@@ -73,7 +74,7 @@
         }
     }
 
-    synchronized void request(SshdSocketAddress local, SshdSocketAddress remote) throws IOException {
+    public synchronized void request(SshdSocketAddress local, SshdSocketAddress remote) throws IOException {
         initialize();
         boolean ok = false;
         if (forwards.get(local.getPort()) != null) {
@@ -83,7 +84,7 @@
         forwards.put(local.getPort(), remote);
     }
 
-    synchronized void cancel(SshdSocketAddress local) throws IOException {
+    public synchronized void cancel(SshdSocketAddress local) throws IOException {
         forwards.remove(local.getPort());
         if (acceptor != null) {
             acceptor.unbind(local.toInetSocketAddress());
@@ -196,5 +197,4 @@
         }
     }
 
-
 }
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/session/TcpipForwarder.java b/sshd-core/src/main/java/org/apache/sshd/client/session/TcpipForwarder.java
new file mode 100644
index 0000000..e9febd6
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/session/TcpipForwarder.java
@@ -0,0 +1,36 @@
+/*
+ * 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.client.session;
+
+import java.io.IOException;
+
+import org.apache.sshd.client.SshdSocketAddress;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public interface TcpipForwarder {
+
+   void request(SshdSocketAddress local, SshdSocketAddress remote) throws IOException;
+
+   void cancel(SshdSocketAddress local) throws IOException;
+
+   void close();
+
+}
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/session/TcpipForwarderFactory.java b/sshd-core/src/main/java/org/apache/sshd/client/session/TcpipForwarderFactory.java
new file mode 100644
index 0000000..8993323
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/session/TcpipForwarderFactory.java
@@ -0,0 +1,37 @@
+/*
+ * 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.client.session;
+
+import org.apache.sshd.ClientSession;
+
+/**
+ * A factory for creating TcpipForwarder objects for client Port forwarding
+ */
+public interface TcpipForwarderFactory {
+
+    /**
+     * Creates the TcpipForwarder to be used for TCP/IP port forwards for
+     * this ClientSession.
+     *
+     * @param clientsession the ClientSession the connections are forwarded through
+     * @return the TcpipForwarder that will listen for connections and set up forwarding
+     */
+    public TcpipForwarder createTcpipForwarder(ClientSession clientsession);
+
+}