You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by gn...@apache.org on 2013/01/17 14:04:14 UTC

svn commit: r1434654 [1/2] - in /mina/sshd/trunk/sshd-core/src: main/java/org/apache/sshd/ main/java/org/apache/sshd/client/ main/java/org/apache/sshd/client/channel/ main/java/org/apache/sshd/client/session/ main/java/org/apache/sshd/common/ main/java...

Author: gnodet
Date: Thu Jan 17 13:04:13 2013
New Revision: 1434654

URL: http://svn.apache.org/viewvc?rev=1434654&view=rev
Log:
[SSHD-205] Refactor tcpip forwarding support to be symmetric between client and server
Also improve tests a bit.

Added:
    mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/ForwardingFilter.java
      - copied, changed from r1434652, mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/ForwardingFilter.java
    mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/SshdSocketAddress.java
      - copied, changed from r1434652, mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/client/SshdSocketAddress.java
    mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/TcpIpForwarder.java
    mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/TcpipForwarderFactory.java
      - copied, changed from r1434652, mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/client/session/TcpipForwarderFactory.java
    mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/forward/DefaultTcpIpForwarder.java
    mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/forward/DefaultTcpipForwarderFactory.java
      - copied, changed from r1434652, mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/client/session/TcpipForwarder.java
    mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/forward/TcpIpClientChannel.java
      - copied, changed from r1434652, mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelDirectTcpip.java
    mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/forward/TcpIpServerChannel.java
      - copied, changed from r1434652, mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelDirectTcpip.java
    mina/sshd/trunk/sshd-core/src/test/java/org/apache/sshd/util/Utils.java
Removed:
    mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/client/SshdSocketAddress.java
    mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/client/session/ChannelForwardedTcpip.java
    mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/client/session/DefaultTcpipForwarderFactory.java
    mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/client/session/TcpipForwardSupport.java
    mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/client/session/TcpipForwarder.java
    mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/client/session/TcpipForwarderFactory.java
    mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/ForwardingFilter.java
    mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelDirectTcpip.java
    mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/session/TcpipForwardSupport.java
Modified:
    mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/ClientSession.java
    mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/SshClient.java
    mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/SshServer.java
    mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/client/ClientFactoryManager.java
    mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelDirectTcpip.java
    mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSessionImpl.java
    mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/AbstractFactoryManager.java
    mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/FactoryManager.java
    mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/Session.java
    mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/forward/DefaultForwardingAcceptorFactory.java
    mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/session/AbstractSession.java
    mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/ServerFactoryManager.java
    mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelSession.java
    mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/session/ServerSession.java
    mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/shell/ProcessShellFactory.java
    mina/sshd/trunk/sshd-core/src/test/java/org/apache/sshd/AgentTest.java
    mina/sshd/trunk/sshd-core/src/test/java/org/apache/sshd/ClientTest.java
    mina/sshd/trunk/sshd-core/src/test/java/org/apache/sshd/CompressionTest.java
    mina/sshd/trunk/sshd-core/src/test/java/org/apache/sshd/KeepAliveTest.java
    mina/sshd/trunk/sshd-core/src/test/java/org/apache/sshd/LoadTest.java
    mina/sshd/trunk/sshd-core/src/test/java/org/apache/sshd/PortForwardingTest.java
    mina/sshd/trunk/sshd-core/src/test/java/org/apache/sshd/ScpTest.java
    mina/sshd/trunk/sshd-core/src/test/java/org/apache/sshd/ServerTest.java
    mina/sshd/trunk/sshd-core/src/test/java/org/apache/sshd/SftpTest.java
    mina/sshd/trunk/sshd-core/src/test/java/org/apache/sshd/util/BogusForwardingFilter.java

Modified: mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/ClientSession.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/ClientSession.java?rev=1434654&r1=1434653&r2=1434654&view=diff
==============================================================================
--- mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/ClientSession.java (original)
+++ mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/ClientSession.java Thu Jan 17 13:04:13 2013
@@ -23,7 +23,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.common.SshdSocketAddress;
 import org.apache.sshd.client.channel.ChannelDirectTcpip;
 import org.apache.sshd.client.channel.ChannelExec;
 import org.apache.sshd.client.channel.ChannelShell;
@@ -109,7 +109,7 @@ public interface ClientSession extends S
     /**
      * Start forwarding the given local address on the client to the given address on the server.
      */
-    void startLocalPortForwarding(SshdSocketAddress local, SshdSocketAddress remote) throws Exception;
+    SshdSocketAddress startLocalPortForwarding(SshdSocketAddress local, SshdSocketAddress remote) throws Exception;
 
     /**
      * Stop forwarding the given local address.
@@ -133,7 +133,7 @@ public interface ClientSession extends S
      * </ul>
      *
      */
-    void startRemotePortForwarding(SshdSocketAddress remote, SshdSocketAddress local) throws Exception;
+    SshdSocketAddress startRemotePortForwarding(SshdSocketAddress remote, SshdSocketAddress local) throws Exception;
 
     /**
      * Stop forwarding of the given remote address.

Modified: mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/SshClient.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/SshClient.java?rev=1434654&r1=1434653&r2=1434654&view=diff
==============================================================================
--- mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/SshClient.java (original)
+++ mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/SshClient.java Thu Jan 17 13:04:13 2013
@@ -45,10 +45,9 @@ import org.apache.sshd.client.future.Con
 import org.apache.sshd.client.future.DefaultConnectFuture;
 import org.apache.sshd.client.kex.DHG1;
 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.forward.DefaultTcpipForwarderFactory;
+import org.apache.sshd.common.TcpipForwarderFactory;
 import org.apache.sshd.common.AbstractFactoryManager;
 import org.apache.sshd.common.Channel;
 import org.apache.sshd.common.Cipher;
@@ -69,6 +68,7 @@ import org.apache.sshd.common.cipher.Blo
 import org.apache.sshd.common.cipher.TripleDESCBC;
 import org.apache.sshd.common.compression.CompressionNone;
 import org.apache.sshd.common.forward.DefaultForwardingAcceptorFactory;
+import org.apache.sshd.common.forward.TcpipServerChannel;
 import org.apache.sshd.common.mac.HMACMD5;
 import org.apache.sshd.common.mac.HMACMD596;
 import org.apache.sshd.common.mac.HMACSHA1;
@@ -135,7 +135,6 @@ public class SshClient extends AbstractF
     protected SessionFactory sessionFactory;
 
     private ServerKeyVerifier serverKeyVerifier;
-    private TcpipForwarderFactory tcpipForwarderFactory;
 
     public SshClient() {
     }
@@ -156,14 +155,6 @@ public class SshClient extends AbstractF
         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");
@@ -183,6 +174,9 @@ public class SshClient extends AbstractF
         if (getRandomFactory() == null) {
             throw new IllegalArgumentException("RandomFactory not set");
         }
+        if (getTcpipForwarderFactory() == null) {
+            throw new IllegalArgumentException("TcpipForwarderFactory not set");
+        }
         if (getTcpipForwardingAcceptorFactory() == null) {
             throw new IllegalArgumentException("TcpipForwardingAcceptorFactory not set");
         }
@@ -289,9 +283,9 @@ public class SshClient extends AbstractF
                 new SignatureDSA.Factory(),
                 new SignatureRSA.Factory()));
         client.setChannelFactories(Arrays.<NamedFactory<Channel>>asList(
-                new ChannelForwardedTcpip.Factory()));
+                new TcpipServerChannel.ForwardedTcpipFactory()));
         ForwardingAcceptorFactory faf = new DefaultForwardingAcceptorFactory();
-        client.setTcpipForwardNioSocketAcceptorFactory(faf);
+        client.setTcpipForwardingAcceptorFactory(faf);
         TcpipForwarderFactory tcpipForwarderFactory = new DefaultTcpipForwarderFactory();
         client.setTcpipForwarderFactory( tcpipForwarderFactory );
         return client;

Modified: mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/SshServer.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/SshServer.java?rev=1434654&r1=1434653&r2=1434654&view=diff
==============================================================================
--- mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/SshServer.java (original)
+++ mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/SshServer.java Thu Jan 17 13:04:13 2013
@@ -37,15 +37,8 @@ import org.apache.mina.core.service.IoAc
 import org.apache.mina.core.session.IoSession;
 import org.apache.mina.core.session.IoSessionConfig;
 import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
-import org.apache.sshd.common.AbstractFactoryManager;
-import org.apache.sshd.common.Channel;
-import org.apache.sshd.common.Cipher;
-import org.apache.sshd.common.Compression;
-import org.apache.sshd.common.Factory;
-import org.apache.sshd.common.KeyExchange;
-import org.apache.sshd.common.Mac;
-import org.apache.sshd.common.NamedFactory;
-import org.apache.sshd.common.Signature;
+import org.apache.sshd.common.SshdSocketAddress;
+import org.apache.sshd.common.*;
 import org.apache.sshd.common.cipher.AES128CBC;
 import org.apache.sshd.common.cipher.AES128CTR;
 import org.apache.sshd.common.cipher.AES192CBC;
@@ -56,6 +49,8 @@ import org.apache.sshd.common.cipher.ARC
 import org.apache.sshd.common.cipher.BlowfishCBC;
 import org.apache.sshd.common.cipher.TripleDESCBC;
 import org.apache.sshd.common.compression.CompressionNone;
+import org.apache.sshd.common.forward.DefaultTcpipForwarderFactory;
+import org.apache.sshd.common.forward.TcpipServerChannel;
 import org.apache.sshd.common.future.CloseFuture;
 import org.apache.sshd.common.future.SshFutureListener;
 import org.apache.sshd.common.mac.HMACMD5;
@@ -73,8 +68,7 @@ import org.apache.sshd.common.util.Secur
 import org.apache.sshd.server.Command;
 import org.apache.sshd.server.CommandFactory;
 import org.apache.sshd.server.FileSystemFactory;
-import org.apache.sshd.common.ForwardingAcceptorFactory;
-import org.apache.sshd.server.ForwardingFilter;
+import org.apache.sshd.common.ForwardingFilter;
 import org.apache.sshd.server.PasswordAuthenticator;
 import org.apache.sshd.server.PublickeyAuthenticator;
 import org.apache.sshd.server.ServerFactoryManager;
@@ -83,7 +77,6 @@ import org.apache.sshd.server.auth.UserA
 import org.apache.sshd.server.auth.UserAuthPublicKey;
 import org.apache.sshd.server.auth.gss.GSSAuthenticator;
 import org.apache.sshd.server.auth.gss.UserAuthGSS;
-import org.apache.sshd.server.channel.ChannelDirectTcpip;
 import org.apache.sshd.server.channel.ChannelSession;
 import org.apache.sshd.server.filesystem.NativeFileSystemFactory;
 import org.apache.sshd.server.kex.DHG1;
@@ -139,7 +132,6 @@ public class SshServer extends AbstractF
     protected PasswordAuthenticator passwordAuthenticator;
     protected PublickeyAuthenticator publickeyAuthenticator;
     protected GSSAuthenticator gssAuthenticator;
-    protected ForwardingFilter forwardingFilter;
     protected ForwardingAcceptorFactory x11ForwardingAcceptorFactory;
 
     public SshServer() {
@@ -262,10 +254,6 @@ public class SshServer extends AbstractF
       this.gssAuthenticator = gssAuthenticator;
     }
 
-    public ForwardingFilter getForwardingFilter() {
-        return forwardingFilter;
-    }
-
     public void setX11ForwardNioSocketAcceptorFactory(ForwardingAcceptorFactory f) {
         x11ForwardingAcceptorFactory = f;
     }
@@ -274,8 +262,8 @@ public class SshServer extends AbstractF
         return x11ForwardingAcceptorFactory;
     }
 
-    public void setForwardingFilter(ForwardingFilter forwardingFilter) {
-        this.forwardingFilter = forwardingFilter;
+    public void setTcpipForwardingFilter(ForwardingFilter forwardingFilter) {
+        this.tcpipForwardingFilter = forwardingFilter;
     }
 
     protected void checkConfig() {
@@ -487,14 +475,15 @@ public class SshServer extends AbstractF
                 new HMACSHA196.Factory()));
         sshd.setChannelFactories(Arrays.<NamedFactory<Channel>>asList(
                 new ChannelSession.Factory(),
-                new ChannelDirectTcpip.Factory()));
+                new TcpipServerChannel.DirectTcpipFactory()));
         sshd.setSignatureFactories(Arrays.<NamedFactory<Signature>>asList(
                 new SignatureDSA.Factory(),
                 new SignatureRSA.Factory()));
         sshd.setFileSystemFactory(new NativeFileSystemFactory());
-        
+
+        sshd.setTcpipForwarderFactory(new DefaultTcpipForwarderFactory());
         ForwardingAcceptorFactory faf = new DefaultForwardingAcceptorFactory();
-        sshd.setTcpipForwardNioSocketAcceptorFactory(faf);
+        sshd.setTcpipForwardingAcceptorFactory(faf);
         sshd.setX11ForwardNioSocketAcceptorFactory(faf);
         
         return sshd;
@@ -585,20 +574,17 @@ public class SshServer extends AbstractF
                 return true;
             }
         });
-        sshd.setForwardingFilter(new ForwardingFilter() {
-            public boolean canForwardAgent(ServerSession session) {
+        sshd.setTcpipForwardingFilter(new ForwardingFilter() {
+            public boolean canForwardAgent(Session session) {
                 return true;
             }
-
-            public boolean canForwardX11(ServerSession session) {
+            public boolean canForwardX11(Session session) {
                 return true;
             }
-
-            public boolean canListen(InetSocketAddress address, ServerSession session) {
+            public boolean canListen(SshdSocketAddress address, Session session) {
                 return true;
             }
-
-            public boolean canConnect(InetSocketAddress address, ServerSession session) {
+            public boolean canConnect(SshdSocketAddress address, Session session) {
                 return true;
             }
         });

Modified: mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/client/ClientFactoryManager.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/client/ClientFactoryManager.java?rev=1434654&r1=1434653&r2=1434654&view=diff
==============================================================================
--- mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/client/ClientFactoryManager.java (original)
+++ mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/client/ClientFactoryManager.java Thu Jan 17 13:04:13 2013
@@ -18,9 +18,8 @@
  */
 package org.apache.sshd.client;
 
-import org.apache.sshd.client.session.TcpipForwarderFactory;
+import org.apache.sshd.common.TcpipForwarderFactory;
 import org.apache.sshd.common.FactoryManager;
-import org.apache.sshd.common.ForwardingAcceptorFactory;
 
 /**
  * The <code>ClientFactoryManager</code> enable the retrieval of additional

Modified: mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelDirectTcpip.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelDirectTcpip.java?rev=1434654&r1=1434653&r2=1434654&view=diff
==============================================================================
--- mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelDirectTcpip.java (original)
+++ mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelDirectTcpip.java Thu Jan 17 13:04:13 2013
@@ -24,7 +24,7 @@ import java.io.PipedOutputStream;
 import java.net.InetAddress;
 import java.net.UnknownHostException;
 
-import org.apache.sshd.client.SshdSocketAddress;
+import org.apache.sshd.common.SshdSocketAddress;
 import org.apache.sshd.client.future.DefaultOpenFuture;
 import org.apache.sshd.client.future.OpenFuture;
 import org.apache.sshd.common.SshConstants;

Modified: mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSessionImpl.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSessionImpl.java?rev=1434654&r1=1434653&r2=1434654&view=diff
==============================================================================
--- mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSessionImpl.java (original)
+++ mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSessionImpl.java Thu Jan 17 13:04:13 2013
@@ -30,7 +30,7 @@ import org.apache.sshd.ClientChannel;
 import org.apache.sshd.ClientSession;
 import org.apache.sshd.client.ClientFactoryManager;
 import org.apache.sshd.client.ServerKeyVerifier;
-import org.apache.sshd.client.SshdSocketAddress;
+import org.apache.sshd.common.SshdSocketAddress;
 import org.apache.sshd.client.UserAuth;
 import org.apache.sshd.client.auth.UserAuthAgent;
 import org.apache.sshd.client.auth.UserAuthPassword;
@@ -43,7 +43,6 @@ import org.apache.sshd.client.future.Aut
 import org.apache.sshd.client.future.DefaultAuthFuture;
 import org.apache.sshd.client.future.OpenFuture;
 import org.apache.sshd.common.Channel;
-import org.apache.sshd.common.FactoryManager;
 import org.apache.sshd.common.KeyExchange;
 import org.apache.sshd.common.KeyPairProvider;
 import org.apache.sshd.common.NamedFactory;
@@ -64,8 +63,6 @@ public class ClientSessionImpl extends A
 
     private UserAuth userAuth;
     private AuthFuture authFuture;
-    private final TcpipForwarder tcpipForward;
-    private final Map<Integer, SshdSocketAddress> forwards = new HashMap<Integer, SshdSocketAddress>();
 
     /**
      * For clients to store their own metadata
@@ -74,7 +71,6 @@ public class ClientSessionImpl extends A
 
     public ClientSessionImpl(ClientFactoryManager client, IoSession session) throws Exception {
         super(client, session);
-        tcpipForward = client.getTcpipForwarderFactory().createTcpipForwarder( this );
         log.info("Session created...");
         sendClientIdentification();
         sendKexInit();
@@ -245,46 +241,20 @@ public class ClientSessionImpl extends A
         return channel;
     }
 
-    public void startLocalPortForwarding(SshdSocketAddress local, SshdSocketAddress remote) throws Exception {
-        tcpipForward.request(local, remote);
+    public SshdSocketAddress startLocalPortForwarding(SshdSocketAddress local, SshdSocketAddress remote) throws Exception {
+        return getTcpipForwarder().startLocalPortForwarding(local, remote);
     }
 
     public void stopLocalPortForwarding(SshdSocketAddress local) throws Exception {
-        tcpipForward.cancel(local);
+        getTcpipForwarder().stopLocalPortForwarding(local);
     }
 
-    SshdSocketAddress getForwardedPort(int remotePort) {
-        return forwards.get(remotePort);
-    }
-
-    public void startRemotePortForwarding(SshdSocketAddress remote, SshdSocketAddress local) throws Exception {
-        forwards.put(remote.getPort(), local);
-        try {
-            Buffer buffer = createBuffer(SshConstants.Message.SSH_MSG_GLOBAL_REQUEST, 0);
-            buffer.putString("tcpip-forward");
-            buffer.putBoolean(true);
-            String host = remote.getHostName();
-
-            buffer.putString(remote.getHostName());
-            buffer.putInt(remote.getPort());
-            boolean res = request(buffer);
-            if (!res) {
-                throw new SshException("Tcpip forwarding request denied by server");
-            }
-        } catch (Exception e) {
-            forwards.remove(remote);
-            throw e;
-        }
+    public SshdSocketAddress startRemotePortForwarding(SshdSocketAddress remote, SshdSocketAddress local) throws Exception {
+        return getTcpipForwarder().startRemotePortForwarding(remote, local);
     }
 
     public void stopRemotePortForwarding(SshdSocketAddress remote) throws Exception {
-        forwards.remove(remote);
-        Buffer buffer = createBuffer(SshConstants.Message.SSH_MSG_GLOBAL_REQUEST, 0);
-        buffer.putString("cancel-tcpip-forward");
-        buffer.putBoolean(false);
-        buffer.putString(remote.getHostName());
-        buffer.putInt(remote.getPort());
-        writePacket(buffer);
+        getTcpipForwarder().stopRemotePortForwarding(remote);
     }
 
     @Override

Modified: mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/AbstractFactoryManager.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/AbstractFactoryManager.java?rev=1434654&r1=1434653&r2=1434654&view=diff
==============================================================================
--- mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/AbstractFactoryManager.java (original)
+++ mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/AbstractFactoryManager.java Thu Jan 17 13:04:13 2013
@@ -26,7 +26,6 @@ import java.util.Properties;
 import java.util.concurrent.ScheduledExecutorService;
 
 import org.apache.sshd.agent.SshAgentFactory;
-import org.apache.sshd.common.ForwardingAcceptorFactory;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -52,7 +51,9 @@ public abstract class AbstractFactoryMan
     protected SshAgentFactory agentFactory;
     protected ScheduledExecutorService executor;
     protected boolean shutdownExecutor;
+    protected TcpipForwarderFactory tcpipForwarderFactory;
     protected ForwardingAcceptorFactory tcpipForwardingAcceptorFactory;
+    protected ForwardingFilter tcpipForwardingFilter;
 
     protected AbstractFactoryManager() {
         loadVersion();
@@ -190,11 +191,27 @@ public abstract class AbstractFactoryMan
         this.shutdownExecutor = shutdownExecutor;
     }
 
+    public TcpipForwarderFactory getTcpipForwarderFactory() {
+        return tcpipForwarderFactory;
+    }
+
+    public void setTcpipForwarderFactory(TcpipForwarderFactory tcpipForwarderFactory) {
+        this.tcpipForwarderFactory = tcpipForwarderFactory;
+    }
+
     public ForwardingAcceptorFactory getTcpipForwardingAcceptorFactory() {
         return tcpipForwardingAcceptorFactory;
     }
 
-    public void setTcpipForwardNioSocketAcceptorFactory(ForwardingAcceptorFactory f) {
+    public void setTcpipForwardingAcceptorFactory(ForwardingAcceptorFactory f) {
         tcpipForwardingAcceptorFactory = f;
     }
+
+    public ForwardingFilter getTcpipForwardingFilter() {
+        return tcpipForwardingFilter;
+    }
+
+    public void setTcpipForwardingFilter(ForwardingFilter tcpipForwardingFilter) {
+        this.tcpipForwardingFilter = tcpipForwardingFilter;
+    }
 }

Modified: mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/FactoryManager.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/FactoryManager.java?rev=1434654&r1=1434653&r2=1434654&view=diff
==============================================================================
--- mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/FactoryManager.java (original)
+++ mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/FactoryManager.java Thu Jan 17 13:04:13 2013
@@ -23,7 +23,6 @@ import java.util.Map;
 import java.util.concurrent.ScheduledExecutorService;
 
 import org.apache.sshd.agent.SshAgentFactory;
-import org.apache.sshd.common.ForwardingAcceptorFactory;
 
 /**
  * This interface allows retrieving all the <code>NamedFactory</code> used
@@ -155,4 +154,20 @@ public interface FactoryManager {
      * @return A <code>ForwardNioAcceptorFactory</code>
      */
     ForwardingAcceptorFactory getTcpipForwardingAcceptorFactory();
+
+    /**
+     * Retrieve the <code>ForwardingFilter</code> to be used by the SSH server.
+     * If no filter has been configured (i.e. this method returns
+     * <code>null</code>), then all forwarding requests will be rejected.
+     *
+     * @return the <code>ForwardingFilter</code> or <code>null</code>
+     */
+    ForwardingFilter getTcpipForwardingFilter();
+
+    /**
+     * Retrieve the tcpip forwarder factory used to support tcpip forwarding.
+     *
+     * @return the <code>TcpipForwarderFactory</code>
+     */
+    TcpipForwarderFactory getTcpipForwarderFactory();
 }

Copied: mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/ForwardingFilter.java (from r1434652, mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/ForwardingFilter.java)
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/ForwardingFilter.java?p2=mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/ForwardingFilter.java&p1=mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/ForwardingFilter.java&r1=1434652&r2=1434654&rev=1434654&view=diff
==============================================================================
--- mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/ForwardingFilter.java (original)
+++ mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/ForwardingFilter.java Thu Jan 17 13:04:13 2013
@@ -16,12 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.sshd.server;
+package org.apache.sshd.common;
 
 import org.apache.sshd.agent.SshAgent;
-import org.apache.sshd.server.session.ServerSession;
-
-import java.net.InetSocketAddress;
 
 /**
  * Determines if a forwarding request will be permitted.
@@ -39,7 +36,7 @@ public interface ForwardingFilter {
      * @param session session requesting permission to forward the agent.
      * @return true if the agent forwarding is permitted, false if denied.
      */
-    boolean canForwardAgent(ServerSession session);
+    boolean canForwardAgent(Session session);
 
     /**
      * Determine if the session may arrange for X11 forwarding.
@@ -51,7 +48,7 @@ public interface ForwardingFilter {
      * @param session session requesting permission to forward X11 connections.
      * @return true if the X11 forwarding is permitted, false if denied.
      */
-    boolean canForwardX11(ServerSession session);
+    boolean canForwardX11(Session session);
 
     /**
      * Determine if the session may listen for inbound connections.
@@ -67,7 +64,7 @@ public interface ForwardingFilter {
      * @param session session requesting permission to listen for connections.
      * @return true if the socket is permitted; false if it must be denied.
      */
-    boolean canListen(InetSocketAddress address, ServerSession session);
+    boolean canListen(SshdSocketAddress address, Session session);
 
     /**
      * Determine if the session may create an outbound connection.
@@ -82,5 +79,5 @@ public interface ForwardingFilter {
      * @param session session requesting permission to listen for connections.
      * @return true if the socket is permitted; false if it must be denied.
      */
-    boolean canConnect(InetSocketAddress address, ServerSession session);
+    boolean canConnect(SshdSocketAddress address, Session session);
 }

Modified: mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/Session.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/Session.java?rev=1434654&r1=1434653&r2=1434654&view=diff
==============================================================================
--- mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/Session.java (original)
+++ mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/Session.java Thu Jan 17 13:04:13 2013
@@ -104,6 +104,17 @@ public interface Session {
     WriteFuture writePacket(Buffer buffer) throws IOException;
 
     /**
+     * Send a global request and wait for the response.
+     * This must only be used when sending a SSH_MSG_GLOBAL_REQUEST with a result expected,
+     * else it will wait forever.
+     *
+     * @param buffer the buffer containing the global request
+     * @return the return buffer if the request was successful, <code>null</code> otherwise.
+     * @throws java.io.IOException if an error occurred when encoding sending the packet
+     */
+    Buffer request(Buffer buffer) throws IOException;
+
+    /**
      * Handle any exceptions that occured on this session.
      * The session will be closed and a disconnect packet will be
      * sent before if the given exception is an
@@ -145,6 +156,12 @@ public interface Session {
     void removeListener(SessionListener listener);
 
     /**
+     * Retrieve the tcpip forwarder
+     * @return
+     */
+    TcpipForwarder getTcpipForwarder();
+
+    /**
      * Type safe key for storage within the user attributes of {@link org.apache.sshd.common.session.AbstractSession}.
      * Typically it is used as a static variable that is shared between the producer
      * and the consumer. To further restrict access the setting or getting it from

Copied: mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/SshdSocketAddress.java (from r1434652, mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/client/SshdSocketAddress.java)
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/SshdSocketAddress.java?p2=mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/SshdSocketAddress.java&p1=mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/client/SshdSocketAddress.java&r1=1434652&r2=1434654&rev=1434654&view=diff
==============================================================================
--- mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/client/SshdSocketAddress.java (original)
+++ mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/SshdSocketAddress.java Thu Jan 17 13:04:13 2013
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.sshd.client;
+package org.apache.sshd.common;
 
 import java.net.InetSocketAddress;
 import java.net.SocketAddress;
@@ -32,6 +32,12 @@ public class SshdSocketAddress extends S
     private final int port;
 
     public SshdSocketAddress(String hostName, int port) {
+        if (hostName == null) {
+            throw new IllegalArgumentException("HostName can not be null");
+        }
+        if (port < 0) {
+            throw new IllegalArgumentException("Port must be >= 0");
+        }
         this.hostName = hostName;
         this.port = port;
     }
@@ -45,6 +51,28 @@ public class SshdSocketAddress extends S
     }
 
     public InetSocketAddress toInetSocketAddress() {
-        return new InetSocketAddress(hostName, port);
+        return new InetSocketAddress(hostName.length() == 0 ? "0.0.0.0" : hostName, port);
+    }
+
+    @Override
+    public String toString() {
+        return hostName + ":" + port;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        SshdSocketAddress that = (SshdSocketAddress) o;
+        if (port != that.port) return false;
+        if (!hostName.equals(that.hostName)) return false;
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = hostName.hashCode();
+        result = 31 * result + port;
+        return result;
     }
 }

Added: mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/TcpIpForwarder.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/TcpIpForwarder.java?rev=1434654&view=auto
==============================================================================
--- mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/TcpIpForwarder.java (added)
+++ mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/TcpIpForwarder.java Thu Jan 17 13:04:13 2013
@@ -0,0 +1,84 @@
+/*
+ * 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;
+
+
+public interface TcpipForwarder {
+
+    /**
+     * Start forwarding the given local address on the client to the given address on the server.
+     */
+    SshdSocketAddress startLocalPortForwarding(SshdSocketAddress local, SshdSocketAddress remote) throws Exception;
+
+    /**
+     * Stop forwarding the given local address.
+     */
+    void stopLocalPortForwarding(SshdSocketAddress local) throws Exception;
+
+    /**
+     * Start forwarding tcpip from the given remote address to the
+     * given local address.
+     *
+     * The remote host name is the address to bind to on the server:
+     * <ul>
+     *    <li>"" means that connections are to be accepted on all protocol families
+     *              supported by the SSH implementation</li>
+     *    <li>"0.0.0.0" means to listen on all IPv4 addresses</li>
+     *    <li>"::" means to listen on all IPv6 addresses</li>
+     *    <li>"localhost" means to listen on all protocol families supported by the SSH
+     *              implementation on loopback addresses only, [RFC3330] and RFC3513]</li>
+     *    <li>"127.0.0.1" and "::1" indicate listening on the loopback interfaces for
+     *              IPv4 and IPv6 respectively</li>
+     * </ul>
+     *
+     */
+    SshdSocketAddress startRemotePortForwarding(SshdSocketAddress remote, SshdSocketAddress local) throws Exception;
+
+    /**
+     * Stop forwarding of the given remote address.
+     */
+    void stopRemotePortForwarding(SshdSocketAddress remote) throws Exception;
+
+    /**
+     * Retrieve the local address that the remote port is forwarded to
+     * @param remotePort
+     * @return
+     */
+    SshdSocketAddress getForwardedPort(int remotePort);
+
+    /**
+     * Called when the other side requested a remote port forward.
+     * @param local
+     * @return the list of bound local addresses
+     * @throws Exception
+     */
+    SshdSocketAddress localPortForwardingRequested(SshdSocketAddress local) throws Exception;
+
+    /**
+     * Called when the other side cancelled a remote port forward.
+     * @param local
+     * @throws Exception
+     */
+    void localPortForwardingCancelled(SshdSocketAddress local) throws Exception;
+
+    /**
+     * Close the forwarder
+     */
+    void close();
+}

Copied: mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/TcpipForwarderFactory.java (from r1434652, mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/client/session/TcpipForwarderFactory.java)
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/TcpipForwarderFactory.java?p2=mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/TcpipForwarderFactory.java&p1=mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/client/session/TcpipForwarderFactory.java&r1=1434652&r2=1434654&rev=1434654&view=diff
==============================================================================
--- mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/client/session/TcpipForwarderFactory.java (original)
+++ mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/TcpipForwarderFactory.java Thu Jan 17 13:04:13 2013
@@ -16,9 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.sshd.client.session;
-
-import org.apache.sshd.ClientSession;
+package org.apache.sshd.common;
 
 /**
  * A factory for creating TcpipForwarder objects for client Port forwarding
@@ -29,9 +27,9 @@ 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
+     * @param session the Session the connections are forwarded through
      * @return the TcpipForwarder that will listen for connections and set up forwarding
      */
-    public TcpipForwarder createTcpipForwarder(ClientSession clientsession);
+    public TcpipForwarder create(Session session);
 
 }

Modified: mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/forward/DefaultForwardingAcceptorFactory.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/forward/DefaultForwardingAcceptorFactory.java?rev=1434654&r1=1434653&r2=1434654&view=diff
==============================================================================
--- mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/forward/DefaultForwardingAcceptorFactory.java (original)
+++ mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/forward/DefaultForwardingAcceptorFactory.java Thu Jan 17 13:04:13 2013
@@ -60,8 +60,7 @@ public class DefaultForwardingAcceptorFa
         final Socket s = new Socket();
         try {
             try {
-                nio.getSessionConfig().setReceiveBufferSize(
-                        s.getReceiveBufferSize());
+                nio.getSessionConfig().setReceiveBufferSize(s.getReceiveBufferSize());
             } finally {
                 s.close();
             }

Added: mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/forward/DefaultTcpIpForwarder.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/forward/DefaultTcpIpForwarder.java?rev=1434654&view=auto
==============================================================================
--- mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/forward/DefaultTcpIpForwarder.java (added)
+++ mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/forward/DefaultTcpIpForwarder.java Thu Jan 17 13:04:13 2013
@@ -0,0 +1,240 @@
+/*
+ * 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.apache.mina.core.buffer.IoBuffer;
+import org.apache.mina.core.service.IoAcceptor;
+import org.apache.mina.core.service.IoHandlerAdapter;
+import org.apache.mina.core.session.IoEventType;
+import org.apache.mina.core.session.IoSession;
+import org.apache.mina.filter.executor.ExecutorFilter;
+import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
+import org.apache.sshd.ClientChannel;
+import org.apache.sshd.common.SshdSocketAddress;
+import org.apache.sshd.client.future.OpenFuture;
+import org.apache.sshd.common.*;
+import org.apache.sshd.common.future.SshFutureListener;
+import org.apache.sshd.common.util.Buffer;
+
+import java.io.IOException;
+import java.net.Inet4Address;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.util.*;
+
+/**
+ * TODO Add javadoc
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class DefaultTcpipForwarder extends IoHandlerAdapter implements TcpipForwarder {
+
+    private final Session session;
+    private final Map<Integer, SshdSocketAddress> localToRemote = new HashMap<Integer, SshdSocketAddress>();
+    private final Map<Integer, SshdSocketAddress> remoteToLocal = new HashMap<Integer, SshdSocketAddress>();
+    private final Set<SshdSocketAddress> localForwards = new HashSet<SshdSocketAddress>();
+    protected IoAcceptor acceptor;
+
+    public DefaultTcpipForwarder(Session session) {
+        this.session = session;
+    }
+
+    //
+    // TcpIpForwarder implementation
+    //
+
+    public synchronized SshdSocketAddress startLocalPortForwarding(SshdSocketAddress local, SshdSocketAddress remote) throws Exception {
+        if (local == null) {
+            throw new IllegalArgumentException("Local address is null");
+        }
+        if (remote == null) {
+            throw new IllegalArgumentException("Remote address is null");
+        }
+        if (local.getPort() < 0) {
+            throw new IllegalArgumentException("Invalid local port: " + local.getPort());
+        }
+        SshdSocketAddress bound = doBind(local);
+        localToRemote.put(bound.getPort(), remote);
+        return bound;
+    }
+
+    public synchronized void stopLocalPortForwarding(SshdSocketAddress local) throws Exception {
+        if (localToRemote.remove(local.getPort()) != null && acceptor != null) {
+            acceptor.unbind(local.toInetSocketAddress());
+            if (acceptor.getLocalAddresses().isEmpty()) {
+                close();
+            }
+        }
+    }
+
+    public synchronized SshdSocketAddress startRemotePortForwarding(SshdSocketAddress remote, SshdSocketAddress local) throws Exception {
+        Buffer buffer = session.createBuffer(SshConstants.Message.SSH_MSG_GLOBAL_REQUEST, 0);
+        buffer.putString("tcpip-forward");
+        buffer.putBoolean(true);
+        buffer.putString(remote.getHostName());
+        buffer.putInt(remote.getPort());
+        Buffer result = session.request(buffer);
+        if (result == null) {
+            throw new SshException("Tcpip forwarding request denied by server");
+        }
+        int port = result.getInt();
+        // TODO: Is it really safe to only store the local address after the request ?
+        remoteToLocal.put(port, local);
+        return new SshdSocketAddress(remote.getHostName(), port);
+    }
+
+    public synchronized void stopRemotePortForwarding(SshdSocketAddress remote) throws Exception {
+        if (remoteToLocal.remove(remote.getPort()) != null) {
+            Buffer buffer = session.createBuffer(SshConstants.Message.SSH_MSG_GLOBAL_REQUEST, 0);
+            buffer.putString("cancel-tcpip-forward");
+            buffer.putBoolean(false);
+            buffer.putString(remote.getHostName());
+            buffer.putInt(remote.getPort());
+            session.writePacket(buffer);
+        }
+    }
+
+    public synchronized SshdSocketAddress getForwardedPort(int remotePort) {
+        return remoteToLocal.get(remotePort);
+    }
+
+    public synchronized SshdSocketAddress localPortForwardingRequested(SshdSocketAddress local) throws Exception {
+        if (local == null) {
+            throw new IllegalArgumentException("Local address is null");
+        }
+        if (local.getPort() < 0) {
+            throw new IllegalArgumentException("Invalid local port: " + local.getPort());
+        }
+        final ForwardingFilter filter = session.getFactoryManager().getTcpipForwardingFilter();
+        if (filter == null || !filter.canListen(local, session)) {
+            throw new IOException("Rejected address: " + local);
+        }
+        SshdSocketAddress bound = doBind(local);
+        localForwards.add(bound);
+        return bound;
+    }
+
+    public synchronized void localPortForwardingCancelled(SshdSocketAddress local) throws Exception {
+        if (localForwards.remove(local) && acceptor != null) {
+            acceptor.unbind(local.toInetSocketAddress());
+            if (acceptor.getLocalAddresses().isEmpty()) {
+                close();
+            }
+        }
+    }
+
+    public synchronized void initialize() {
+        if (this.acceptor == null) {
+            NioSocketAcceptor acceptor = session.getFactoryManager().getTcpipForwardingAcceptorFactory().createNioSocketAcceptor(session);
+            acceptor.setHandler(this);
+            acceptor.setReuseAddress(true);
+            acceptor.getFilterChain().addLast("executor", new ExecutorFilter(EnumSet.complementOf(EnumSet.of(IoEventType.SESSION_CREATED)).toArray(new IoEventType[0])));
+            this.acceptor = acceptor;
+        }
+    }
+
+    public synchronized void close() {
+        if (acceptor != null) {
+            acceptor.dispose();
+            acceptor = null;
+        }
+    }
+
+    //
+    // IoHandler implementation
+    //
+
+    @Override
+    public void sessionCreated(final IoSession session) throws Exception {
+        final TcpipClientChannel channel;
+        int localPort = ((InetSocketAddress) session.getLocalAddress()).getPort();
+        if (localToRemote.containsKey(localPort)) {
+            SshdSocketAddress remote = localToRemote.get(localPort);
+            channel = new TcpipClientChannel(TcpipClientChannel.Type.Direct, session, remote);
+        } else {
+            channel = new TcpipClientChannel(TcpipClientChannel.Type.Forwarded, session, null);
+        }
+        session.setAttribute(TcpipClientChannel.class, channel);
+        this.session.registerChannel(channel);
+        channel.open().addListener(new SshFutureListener<OpenFuture>() {
+            public void operationComplete(OpenFuture future) {
+                Throwable t = future.getException();
+                if (t != null) {
+                    DefaultTcpipForwarder.this.session.unregisterChannel(channel);
+                    channel.close(false);
+                }
+            }
+        });
+    }
+
+    @Override
+    public void sessionClosed(IoSession session) throws Exception {
+        TcpipClientChannel channel = (TcpipClientChannel) session.getAttribute(TcpipClientChannel.class);
+        if (channel != null) {
+            channel.close(false);
+        }
+    }
+
+    @Override
+    public void messageReceived(IoSession session, Object message) throws Exception {
+        TcpipClientChannel channel = (TcpipClientChannel) session.getAttribute(TcpipClientChannel.class);
+        IoBuffer ioBuffer = (IoBuffer) message;
+        int r = ioBuffer.remaining();
+        byte[] b = new byte[r];
+        ioBuffer.get(b, 0, r);
+        channel.waitFor(ClientChannel.OPENED | ClientChannel.CLOSED, Long.MAX_VALUE);
+        channel.getOut().write(b, 0, r);
+        channel.getOut().flush();
+    }
+
+    @Override
+    public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
+        cause.printStackTrace();
+        session.close(false);
+    }
+
+    //
+    // Private methods
+    //
+
+    private SshdSocketAddress doBind(SshdSocketAddress address) throws IOException {
+        initialize();
+        Set<SocketAddress> before = acceptor.getLocalAddresses();
+        try {
+            acceptor.bind(address.toInetSocketAddress());
+            Set<SocketAddress> after = acceptor.getLocalAddresses();
+            after.removeAll(before);
+            if (after.isEmpty()) {
+                throw new IOException("Error binding to " + address + ": no local addresses bound");
+            }
+            if (after.size() > 1) {
+                throw new IOException("Multiple local addresses have been bound for " + address);
+            }
+            InetSocketAddress result = (InetSocketAddress) after.iterator().next();
+            return new SshdSocketAddress(address.getHostName(), result.getPort());
+        } catch (IOException bindErr) {
+            if (acceptor.getLocalAddresses().isEmpty()) {
+                close();
+            }
+            throw bindErr;
+        }
+    }
+
+}

Copied: mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/forward/DefaultTcpipForwarderFactory.java (from r1434652, mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/client/session/TcpipForwarder.java)
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/forward/DefaultTcpipForwarderFactory.java?p2=mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/forward/DefaultTcpipForwarderFactory.java&p1=mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/client/session/TcpipForwarder.java&r1=1434652&r2=1434654&rev=1434654&view=diff
==============================================================================
--- mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/client/session/TcpipForwarder.java (original)
+++ mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/forward/DefaultTcpipForwarderFactory.java Thu Jan 17 13:04:13 2013
@@ -16,21 +16,22 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.sshd.client.session;
+package org.apache.sshd.common.forward;
 
-import java.io.IOException;
-
-import org.apache.sshd.client.SshdSocketAddress;
+import org.apache.sshd.common.Session;
+import org.apache.sshd.common.TcpipForwarder;
+import org.apache.sshd.common.TcpipForwarderFactory;
 
 /**
+ * The default {link TcpipForwarderFactory} implementation.
+ *
+ * @see DefaultTcpipForwarder
  * @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();
-
+public class DefaultTcpipForwarderFactory implements TcpipForwarderFactory
+{
+   public TcpipForwarder create( Session session )
+   {
+      return new DefaultTcpipForwarder( session );
+   }
 }

Copied: mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/forward/TcpIpClientChannel.java (from r1434652, mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelDirectTcpip.java)
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/forward/TcpIpClientChannel.java?p2=mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/forward/TcpIpClientChannel.java&p1=mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelDirectTcpip.java&r1=1434652&r2=1434654&rev=1434654&view=diff
==============================================================================
--- mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelDirectTcpip.java (original)
+++ mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/forward/TcpIpClientChannel.java Thu Jan 17 13:04:13 2013
@@ -16,15 +16,12 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.sshd.client.channel;
+package org.apache.sshd.common.forward;
 
-import java.io.IOException;
-import java.io.PipedInputStream;
-import java.io.PipedOutputStream;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-
-import org.apache.sshd.client.SshdSocketAddress;
+import org.apache.mina.core.buffer.IoBuffer;
+import org.apache.mina.core.session.IoSession;
+import org.apache.sshd.common.SshdSocketAddress;
+import org.apache.sshd.client.channel.AbstractClientChannel;
 import org.apache.sshd.client.future.DefaultOpenFuture;
 import org.apache.sshd.client.future.OpenFuture;
 import org.apache.sshd.common.SshConstants;
@@ -32,35 +29,49 @@ import org.apache.sshd.common.SshExcepti
 import org.apache.sshd.common.channel.ChannelOutputStream;
 import org.apache.sshd.common.util.Buffer;
 
+import java.io.IOException;
+import java.net.InetSocketAddress;
+
 /**
  * TODO Add javadoc
  *
  * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
  */
-public class ChannelDirectTcpip extends AbstractClientChannel {
+public class TcpipClientChannel extends AbstractClientChannel {
 
-    private final SshdSocketAddress local;
+    public enum Type {
+        Direct,
+        Forwarded
+    }
+
+    private final Type typeEnum;
+    private final IoSession serverSession;
     private final SshdSocketAddress remote;
-    private final PipedOutputStream pipe = new PipedOutputStream();
 
-    public ChannelDirectTcpip(SshdSocketAddress local, SshdSocketAddress remote) {
-        super("direct-tcpip");
-        if (local == null) {
-            try {
-                local = new SshdSocketAddress(InetAddress.getLocalHost().getHostName(), 0);
-            } catch (UnknownHostException e) {
-                throw new IllegalStateException("Unable to retrieve local host name");
-            }
-        }
-        if (remote == null) {
-            throw new IllegalArgumentException("Remote address must not be null");
-        }
-        this.local = local;
+    public TcpipClientChannel(Type type, IoSession serverSession, SshdSocketAddress remote) {
+        super(type == Type.Direct ? "direct-tcpip" : "forwarded-tcpip");
+        this.typeEnum = type;
+        this.serverSession = serverSession;
         this.remote = remote;
     }
 
-    @Override
-    protected OpenFuture internalOpen() throws Exception {
+
+    public OpenFuture getOpenFuture() {
+        return openFuture;
+    }
+
+    public synchronized OpenFuture open() throws Exception {
+        InetSocketAddress src = null, dst = null;
+        switch (typeEnum) {
+            case Direct:
+                src = (InetSocketAddress) serverSession.getRemoteAddress();
+                dst = this.remote.toInetSocketAddress();
+                break;
+            case Forwarded:
+                src = (InetSocketAddress) serverSession.getRemoteAddress();
+                dst = (InetSocketAddress) serverSession.getLocalAddress();
+                break;
+        }
         if (closeFuture.isClosed()) {
             throw new SshException("Session has been closed");
         }
@@ -71,29 +82,36 @@ public class ChannelDirectTcpip extends 
         buffer.putInt(id);
         buffer.putInt(localWindow.getSize());
         buffer.putInt(localWindow.getPacketSize());
-        buffer.putString(remote.getHostName());
-        buffer.putInt(remote.getPort());
-        buffer.putString(local.getHostName());
-        buffer.putInt(local.getPort());
+        buffer.putString(dst.getAddress().getHostAddress());
+        buffer.putInt(dst.getPort());
+        buffer.putString(src.getAddress().getHostAddress());
+        buffer.putInt(src.getPort());
         session.writePacket(buffer);
         return openFuture;
     }
 
     @Override
-    protected void doOpen() throws Exception {
+    protected synchronized void doOpen() throws Exception {
         out = new ChannelOutputStream(this, remoteWindow, log, SshConstants.Message.SSH_MSG_CHANNEL_DATA);
-        in = new PipedInputStream(pipe);
     }
 
-    public OpenFuture open() throws Exception {
-        return internalOpen();
+    @Override
+    protected synchronized void doClose() {
+        serverSession.close(false);
+        super.doClose();
     }
 
-    @Override
-    protected void doWriteData(byte[] data, int off, int len) throws IOException {
-        pipe.write(data, off, len);
-        pipe.flush();
+    protected synchronized void doWriteData(byte[] data, int off, int len) throws IOException {
+        IoBuffer buf = IoBuffer.allocate(len);
+        buf.put(data, off, len);
+        buf.flip();
         localWindow.consumeAndCheck(len);
+        serverSession.write(buf);
     }
 
+    @Override
+    public void handleEof() throws IOException {
+        super.handleEof();
+        serverSession.close(false);
+    }
 }

Copied: mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/forward/TcpIpServerChannel.java (from r1434652, mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelDirectTcpip.java)
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/forward/TcpIpServerChannel.java?p2=mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/forward/TcpIpServerChannel.java&p1=mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelDirectTcpip.java&r1=1434652&r2=1434654&rev=1434654&view=diff
==============================================================================
--- mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelDirectTcpip.java (original)
+++ mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/forward/TcpIpServerChannel.java Thu Jan 17 13:04:13 2013
@@ -16,12 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.sshd.server.channel;
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.net.ConnectException;
-import java.net.InetSocketAddress;
+package org.apache.sshd.common.forward;
 
 import org.apache.mina.core.buffer.IoBuffer;
 import org.apache.mina.core.future.ConnectFuture;
@@ -33,40 +28,60 @@ import org.apache.mina.core.session.IoSe
 import org.apache.mina.transport.socket.nio.NioSocketConnector;
 import org.apache.sshd.client.future.DefaultOpenFuture;
 import org.apache.sshd.client.future.OpenFuture;
-import org.apache.sshd.common.Channel;
-import org.apache.sshd.common.NamedFactory;
-import org.apache.sshd.common.SshConstants;
+import org.apache.sshd.common.*;
 import org.apache.sshd.common.channel.ChannelOutputStream;
 import org.apache.sshd.common.future.CloseFuture;
 import org.apache.sshd.common.future.SshFuture;
 import org.apache.sshd.common.future.SshFutureListener;
 import org.apache.sshd.common.util.Buffer;
-import org.apache.sshd.server.ForwardingFilter;
-import org.apache.sshd.server.session.ServerSession;
+import org.apache.sshd.server.channel.AbstractServerChannel;
+import org.apache.sshd.server.channel.OpenChannelException;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.ConnectException;
 
 /**
  * TODO Add javadoc
  *
  * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
  */
-public class ChannelDirectTcpip extends AbstractServerChannel {
+public class TcpipServerChannel extends AbstractServerChannel {
 
-    public static class Factory implements NamedFactory<Channel> {
+    public static class DirectTcpipFactory implements NamedFactory<Channel> {
 
         public String getName() {
             return "direct-tcpip";
         }
 
         public Channel create() {
-            return new ChannelDirectTcpip();
+            return new TcpipServerChannel(Type.Direct);
         }
     }
 
+    public static class ForwardedTcpipFactory implements NamedFactory<Channel> {
+
+        public String getName() {
+            return "forwarded-tcpip";
+        }
+
+        public Channel create() {
+            return new TcpipServerChannel(Type.Forwarded);
+        }
+    }
+
+    private enum Type {
+        Direct,
+        Forwarded
+    }
+
+    private final Type type;
     private IoConnector connector;
     private IoSession ioSession;
     private OutputStream out;
 
-    public ChannelDirectTcpip() {
+    public TcpipServerChannel(Type type) {
+        this.type = type;
     }
 
     protected OpenFuture doInit(Buffer buffer) {
@@ -79,21 +94,20 @@ public class ChannelDirectTcpip extends 
         log.info("Receiving request for direct tcpip: hostToConnect={}, portToConnect={}, originatorIpAddress={}, originatorPort={}",
                 new Object[] { hostToConnect, portToConnect, originatorIpAddress, originatorPort });
 
-        InetSocketAddress address;
-        try {
-            address = new InetSocketAddress(hostToConnect, portToConnect);
-        } catch (RuntimeException e) {
-            address = null;
-        }
 
-        final ServerSession serverSession = (ServerSession)getSession();
-        final ForwardingFilter filter = serverSession.getServerFactoryManager().getForwardingFilter();
-        if (address == null || filter == null || !filter.canConnect(address, serverSession)) {
+        SshdSocketAddress address = null;
+        switch (type) {
+            case Direct:    address = new SshdSocketAddress(hostToConnect, portToConnect); break;
+            case Forwarded: address = getSession().getTcpipForwarder().getForwardedPort(portToConnect); break;
+        }
+        final ForwardingFilter filter = getSession().getFactoryManager().getTcpipForwardingFilter();
+        if (address == null || filter == null || !filter.canConnect(address, getSession())) {
             super.close(true);
-            f.setException(new OpenChannelException(SshConstants.SSH_OPEN_ADMINISTRATIVELY_PROHIBITED, "connect denied"));
+            f.setException(new OpenChannelException(SshConstants.SSH_OPEN_ADMINISTRATIVELY_PROHIBITED, "Connection denied"));
             return f;
         }
 
+
         connector = new NioSocketConnector();
         out = new ChannelOutputStream(this, remoteWindow, log, SshConstants.Message.SSH_MSG_CHANNEL_DATA);
         IoHandler handler = new IoHandlerAdapter() {
@@ -115,7 +129,7 @@ public class ChannelDirectTcpip extends 
             }
         };
         connector.setHandler(handler);
-        ConnectFuture future = connector.connect(address);
+        ConnectFuture future = connector.connect(address.toInetSocketAddress());
         future.addListener(new IoFutureListener<ConnectFuture>() {
             public void operationComplete(ConnectFuture future) {
                 if (future.isConnected()) {
@@ -151,7 +165,7 @@ public class ChannelDirectTcpip extends 
         // causes deadlock.  Instead create a new thread to dispose of the
         // connector in the background.
         //
-        new Thread("ChannelDirectTcpip-ConnectorCleanup") {
+        new Thread("TcpIpServerChannel-ConnectorCleanup") {
             @Override
             public void run() {
                 connector.dispose();
@@ -181,7 +195,7 @@ public class ChannelDirectTcpip extends 
     }
 
     protected void doWriteExtendedData(byte[] data, int off, int len) throws IOException {
-        throw new UnsupportedOperationException("DirectTcpip channel does not support extended data");
+        throw new UnsupportedOperationException(type + "Tcpip channel does not support extended data");
     }
 
     public void handleRequest(Buffer buffer) throws IOException {

Modified: mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/session/AbstractSession.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/session/AbstractSession.java?rev=1434654&r1=1434653&r2=1434654&view=diff
==============================================================================
--- mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/session/AbstractSession.java (original)
+++ mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/common/session/AbstractSession.java Thu Jan 17 13:04:13 2013
@@ -26,6 +26,7 @@ import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
 
 import org.apache.mina.core.buffer.IoBuffer;
 import org.apache.mina.core.future.IoFuture;
@@ -46,6 +47,8 @@ import org.apache.sshd.common.Session;
 import org.apache.sshd.common.SessionListener;
 import org.apache.sshd.common.SshConstants;
 import org.apache.sshd.common.SshException;
+import org.apache.sshd.common.forward.DefaultTcpipForwarder;
+import org.apache.sshd.common.TcpipForwarder;
 import org.apache.sshd.common.future.CloseFuture;
 import org.apache.sshd.common.future.DefaultCloseFuture;
 import org.apache.sshd.common.future.SshFuture;
@@ -84,6 +87,8 @@ public abstract class AbstractSession im
     protected final IoSession ioSession;
     /** The pseudo random generator */
     protected final Random random;
+    /** The tcpip forwarder */
+    protected final TcpipForwarder tcpipForwarder;
     /** Lock object for this session state */
     protected final Object lock = new Object();
     /**
@@ -136,7 +141,7 @@ public abstract class AbstractSession im
     protected final Object encodeLock = new Object();
     protected final Object decodeLock = new Object();
     protected final Object requestLock = new Object();
-    protected final AtomicBoolean requestResult = new AtomicBoolean();
+    protected final AtomicReference<Buffer> requestResult = new AtomicReference<Buffer>();
     protected final Map<AttributeKey<?>, Object> attributes = new ConcurrentHashMap<AttributeKey<?>, Object>();
     protected String username;
 
@@ -152,6 +157,7 @@ public abstract class AbstractSession im
         this.factoryManager = factoryManager;
         this.ioSession = ioSession;
         this.random = factoryManager.getRandomFactory().create();
+        this.tcpipForwarder = factoryManager.getTcpipForwarderFactory().create(this);
     }
 
     /**
@@ -313,6 +319,7 @@ public abstract class AbstractSession im
                 }
             }
         }
+        tcpipForwarder.close();
         synchronized (lock) {
             if (!closing) {
                 try {
@@ -373,7 +380,7 @@ public abstract class AbstractSession im
      * @return <code>true</code> if the request was successful, <code>false</code> otherwise.
      * @throws java.io.IOException if an error occured when encoding sending the packet
      */
-    public boolean request(Buffer buffer) throws IOException {
+    public Buffer request(Buffer buffer) throws IOException {
         synchronized (requestLock) {
             try {
                 synchronized (requestResult) {
@@ -947,14 +954,14 @@ public abstract class AbstractSession im
 
     protected void requestSuccess(Buffer buffer) throws Exception{
         synchronized (requestResult) {
-            requestResult.set(true);
+            requestResult.set(new Buffer(buffer.getCompactData()));
             requestResult.notify();
         }
     }
 
     protected void requestFailure(Buffer buffer) throws Exception{
         synchronized (requestResult) {
-            requestResult.set(false);
+            requestResult.set(null);
             requestResult.notify();
         }
     }
@@ -1165,4 +1172,11 @@ public abstract class AbstractSession im
             this.listeners.remove(listener);
         }
     }
+
+    /**
+     * {@inheritDoc}
+     */
+    public TcpipForwarder getTcpipForwarder() {
+        return this.tcpipForwarder;
+    }
 }

Modified: mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/ServerFactoryManager.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/ServerFactoryManager.java?rev=1434654&r1=1434653&r2=1434654&view=diff
==============================================================================
--- mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/ServerFactoryManager.java (original)
+++ mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/ServerFactoryManager.java Thu Jan 17 13:04:13 2013
@@ -105,15 +105,6 @@ public interface ServerFactoryManager ex
     GSSAuthenticator getGSSAuthenticator();
 
     /**
-     * Retrieve the <code>ForwardingFilter</code> to be used by the SSH server.
-     * If no filter has been configured (i.e. this method returns
-     * <code>null</code>), then all forwarding requests will be rejected.
-     *
-     * @return the <code>ForwardingFilter</code> or <code>null</code>
-     */
-    ForwardingFilter getForwardingFilter();
-
-    /**
      * Retrieve the <code>ShellFactory</code> object to be used to create shells.
      *
      * @return a valid <code>ShellFactory</code> object or <code>null</code> if shells

Modified: mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelSession.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelSession.java?rev=1434654&r1=1434653&r2=1434654&view=diff
==============================================================================
--- mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelSession.java (original)
+++ mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelSession.java Thu Jan 17 13:04:13 2013
@@ -30,13 +30,8 @@ import java.util.concurrent.CopyOnWriteA
 
 import org.apache.sshd.agent.SshAgent;
 import org.apache.sshd.agent.SshAgentFactory;
-import org.apache.sshd.common.Channel;
-import org.apache.sshd.common.NamedFactory;
-import org.apache.sshd.common.PtyMode;
-import org.apache.sshd.common.SshConstants;
+import org.apache.sshd.common.*;
 import org.apache.sshd.common.channel.ChannelOutputStream;
-import org.apache.sshd.common.channel.ChannelPipedInputStream;
-import org.apache.sshd.common.channel.ChannelPipedOutputStream;
 import org.apache.sshd.common.future.CloseFuture;
 import org.apache.sshd.common.future.SshFuture;
 import org.apache.sshd.common.future.SshFutureListener;
@@ -474,7 +469,7 @@ public class ChannelSession extends Abst
         boolean wantReply = buffer.getBoolean();
 
         final ServerSession server = (ServerSession) session;
-        final ForwardingFilter filter = server.getServerFactoryManager().getForwardingFilter();
+        final ForwardingFilter filter = server.getServerFactoryManager().getTcpipForwardingFilter();
         final SshAgentFactory factory = server.getServerFactoryManager().getAgentFactory();
         if (factory == null || (filter != null && !filter.canForwardAgent(server))) {
             if (wantReply) {
@@ -500,7 +495,7 @@ public class ChannelSession extends Abst
         boolean wantReply = buffer.getBoolean();
 
         final ServerSession server = (ServerSession) session;
-        final ForwardingFilter filter = server.getServerFactoryManager().getForwardingFilter();
+        final ForwardingFilter filter = server.getServerFactoryManager().getTcpipForwardingFilter();
         if (filter == null || !filter.canForwardX11(server)) {
             if (wantReply) {
                 buffer = session.createBuffer(SshConstants.Message.SSH_MSG_CHANNEL_FAILURE, 0);

Modified: mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/session/ServerSession.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/session/ServerSession.java?rev=1434654&r1=1434653&r2=1434654&view=diff
==============================================================================
--- mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/session/ServerSession.java (original)
+++ mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/session/ServerSession.java Thu Jan 17 13:04:13 2013
@@ -19,9 +19,12 @@
 package org.apache.sshd.server.session;
 
 import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
 import java.security.KeyPair;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Set;
 import java.util.concurrent.Future;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.TimeUnit;
@@ -29,12 +32,7 @@ import java.util.concurrent.TimeUnit;
 import org.apache.mina.core.session.IoSession;
 import org.apache.sshd.agent.common.AgentForwardSupport;
 import org.apache.sshd.client.future.OpenFuture;
-import org.apache.sshd.common.Channel;
-import org.apache.sshd.common.FactoryManager;
-import org.apache.sshd.common.KeyExchange;
-import org.apache.sshd.common.NamedFactory;
-import org.apache.sshd.common.SshConstants;
-import org.apache.sshd.common.SshException;
+import org.apache.sshd.common.*;
 import org.apache.sshd.common.future.CloseFuture;
 import org.apache.sshd.common.future.SshFutureListener;
 import org.apache.sshd.common.session.AbstractSession;
@@ -66,7 +64,6 @@ public class ServerSession extends Abstr
     private int authTimeout = 10 * 60 * 1000; // 10 minutes in milliseconds
     private int idleTimeout = 10 * 60 * 1000; // 10 minutes in milliseconds
     private boolean allowMoreSessions = true;
-    private final TcpipForwardSupport tcpipForward;
     private final AgentForwardSupport agentForward;
     private final X11ForwardSupport x11Forward;
     private String welcomeBanner = null;
@@ -80,7 +77,6 @@ public class ServerSession extends Abstr
         maxAuthRequests = getIntProperty(ServerFactoryManager.MAX_AUTH_REQUESTS, maxAuthRequests);
         authTimeout = getIntProperty(ServerFactoryManager.AUTH_TIMEOUT, authTimeout);
         idleTimeout = getIntProperty(ServerFactoryManager.IDLE_TIMEOUT, idleTimeout);
-        tcpipForward = new TcpipForwardSupport(this);
         agentForward = new AgentForwardSupport(this);
         x11Forward = new X11ForwardSupport(this);
         welcomeBanner = factoryManager.getProperties().get(ServerFactoryManager.WELCOME_BANNER);
@@ -93,7 +89,6 @@ public class ServerSession extends Abstr
     public CloseFuture close(boolean immediately) {
         unscheduleAuthTimer();
         unscheduleIdleTimer();
-        tcpipForward.close();
         agentForward.close();
         x11Forward.close();
         return super.close(immediately);
@@ -575,10 +570,31 @@ public class ServerSession extends Abstr
         } else if (req.equals("no-more-sessions@openssh.com")) {
             allowMoreSessions = false;
         } else if (req.equals("tcpip-forward")) {
-            tcpipForward.request(buffer, wantReply);
+            String address = buffer.getString();
+            int port = buffer.getInt();
+            try {
+                SshdSocketAddress bound = getTcpipForwarder().localPortForwardingRequested(new SshdSocketAddress(address, port));
+                port = bound.getPort();
+                if (wantReply){
+                    buffer = createBuffer(SshConstants.Message.SSH_MSG_REQUEST_SUCCESS, 0);
+                    buffer.putInt(port);
+                    writePacket(buffer);
+                }
+            } catch (Exception e) {
+                if (wantReply) {
+                    buffer = createBuffer(SshConstants.Message.SSH_MSG_REQUEST_FAILURE, 0);
+                    writePacket(buffer);
+                }
+            }
             return;
         } else if (req.equals("cancel-tcpip-forward")) {
-            tcpipForward.cancel(buffer, wantReply);
+            String address = buffer.getString();
+            int port = buffer.getInt();
+            getTcpipForwarder().localPortForwardingCancelled(new SshdSocketAddress(address, port));
+            if (wantReply){
+                buffer = createBuffer(SshConstants.Message.SSH_MSG_REQUEST_SUCCESS, 0);
+                writePacket(buffer);
+            }
             return;
         } else {
             log.debug("Received SSH_MSG_GLOBAL_REQUEST {}", req);

Modified: mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/shell/ProcessShellFactory.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/shell/ProcessShellFactory.java?rev=1434654&r1=1434653&r2=1434654&view=diff
==============================================================================
--- mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/shell/ProcessShellFactory.java (original)
+++ mina/sshd/trunk/sshd-core/src/main/java/org/apache/sshd/server/shell/ProcessShellFactory.java Thu Jan 17 13:04:13 2013
@@ -130,7 +130,11 @@ public class ProcessShellFactory impleme
         }
 
         public int exitValue() {
-            return process.exitValue();
+            try {
+                return process.waitFor();
+            } catch (InterruptedException e) {
+                throw new RuntimeException(e);
+            }
         }
 
         public void destroy() {

Modified: mina/sshd/trunk/sshd-core/src/test/java/org/apache/sshd/AgentTest.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/sshd-core/src/test/java/org/apache/sshd/AgentTest.java?rev=1434654&r1=1434653&r2=1434654&view=diff
==============================================================================
--- mina/sshd/trunk/sshd-core/src/test/java/org/apache/sshd/AgentTest.java (original)
+++ mina/sshd/trunk/sshd-core/src/test/java/org/apache/sshd/AgentTest.java Thu Jan 17 13:04:13 2013
@@ -22,7 +22,6 @@ import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.PipedInputStream;
 import java.io.PipedOutputStream;
-import java.net.ServerSocket;
 import java.security.KeyPair;
 import java.security.PublicKey;
 import java.util.List;
@@ -34,15 +33,13 @@ import org.apache.sshd.agent.unix.AgentC
 import org.apache.sshd.agent.unix.AgentServer;
 import org.apache.sshd.client.channel.ChannelShell;
 import org.apache.sshd.common.KeyPairProvider;
-import org.apache.sshd.common.keyprovider.FileKeyPairProvider;
 import org.apache.sshd.server.Command;
 import org.apache.sshd.server.Environment;
-import org.apache.sshd.util.BogusPasswordAuthenticator;
-import org.apache.sshd.util.BogusPublickeyAuthenticator;
-import org.apache.sshd.util.EchoShellFactory;
-import org.apache.sshd.util.TeePipedOutputStream;
+import org.apache.sshd.util.*;
 import org.junit.Test;
 
+import static org.apache.sshd.util.Utils.createTestKeyPairProvider;
+import static org.apache.sshd.util.Utils.getFreePort;
 import static org.hamcrest.CoreMatchers.notNullValue;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
@@ -68,7 +65,7 @@ public class AgentTest {
         assertNotNull(keys);
         assertEquals(0, keys.size());
 
-        KeyPair[] k = new FileKeyPairProvider(new String[] { "src/test/resources/hostkey.pem"}).loadKeys();
+        KeyPair[] k = Utils.createTestHostKeyProvider().loadKeys();
         client.addIdentity(k[0], "");
         keys = client.getIdentities();
         assertNotNull(keys);
@@ -96,12 +93,12 @@ public class AgentTest {
         ProxyAgentFactory agentFactory = new ProxyAgentFactory();
         LocalAgentFactory localAgentFactory = new LocalAgentFactory();
 
-        KeyPair pair = new FileKeyPairProvider(new String[] { "src/test/resources/dsaprivkey.pem" }).loadKey(KeyPairProvider.SSH_DSS);
+        KeyPair pair = createTestKeyPairProvider("dsaprivkey.pem").loadKey(KeyPairProvider.SSH_DSS);
         localAgentFactory.getAgent().addIdentity(pair, "smx");
 
         SshServer sshd1 = SshServer.setUpDefaultServer();
         sshd1.setPort(port1);
-        sshd1.setKeyPairProvider(new FileKeyPairProvider(new String[]{"src/test/resources/hostkey.pem"}));
+        sshd1.setKeyPairProvider(Utils.createTestHostKeyProvider());
         sshd1.setShellFactory(shellFactory);
         sshd1.setPasswordAuthenticator(new BogusPasswordAuthenticator());
         sshd1.setPublickeyAuthenticator(new BogusPublickeyAuthenticator());
@@ -110,7 +107,7 @@ public class AgentTest {
 
         SshServer sshd2 = SshServer.setUpDefaultServer();
         sshd2.setPort(port2);
-        sshd2.setKeyPairProvider(new FileKeyPairProvider(new String[]{"src/test/resources/hostkey.pem"}));
+        sshd2.setKeyPairProvider(Utils.createTestHostKeyProvider());
         sshd2.setShellFactory(new TestEchoShellFactory());
         sshd2.setPasswordAuthenticator(new BogusPasswordAuthenticator());
         sshd2.setPublickeyAuthenticator(new BogusPublickeyAuthenticator());
@@ -180,10 +177,4 @@ public class AgentTest {
         }
     }
 
-    private static int getFreePort() throws IOException {
-        ServerSocket s = new ServerSocket(0);
-        int port = s.getLocalPort();
-        s.close();
-        return port;
-    }
 }

Modified: mina/sshd/trunk/sshd-core/src/test/java/org/apache/sshd/ClientTest.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/sshd-core/src/test/java/org/apache/sshd/ClientTest.java?rev=1434654&r1=1434653&r2=1434654&view=diff
==============================================================================
--- mina/sshd/trunk/sshd-core/src/test/java/org/apache/sshd/ClientTest.java (original)
+++ mina/sshd/trunk/sshd-core/src/test/java/org/apache/sshd/ClientTest.java Thu Jan 17 13:04:13 2013
@@ -33,16 +33,13 @@ import org.apache.sshd.common.KeyPairPro
 import org.apache.sshd.common.SshConstants;
 import org.apache.sshd.common.SshException;
 import org.apache.sshd.common.future.CloseFuture;
-import org.apache.sshd.common.keyprovider.FileKeyPairProvider;
 import org.apache.sshd.common.session.AbstractSession;
 import org.apache.sshd.common.util.Buffer;
 import org.apache.sshd.common.util.BufferUtils;
 import org.apache.sshd.server.Command;
-import org.apache.sshd.util.BogusPasswordAuthenticator;
-import org.apache.sshd.util.BogusPublickeyAuthenticator;
-import org.apache.sshd.util.EchoShellFactory;
-import org.apache.sshd.util.TeePipedOutputStream;
+import org.apache.sshd.util.*;
 import org.junit.After;
+
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
@@ -67,7 +64,7 @@ public class ClientTest {
 
         sshd = SshServer.setUpDefaultServer();
         sshd.setPort(port);
-        sshd.setKeyPairProvider(new FileKeyPairProvider(new String[] { "src/test/resources/hostkey.pem" }));
+        sshd.setKeyPairProvider(Utils.createTestHostKeyProvider());
         sshd.setShellFactory(new TestEchoShellFactory());
         sshd.setPasswordAuthenticator(new BogusPasswordAuthenticator());
         sshd.setPublickeyAuthenticator(new BogusPublickeyAuthenticator());
@@ -283,7 +280,7 @@ public class ClientTest {
         client.start();
         ClientSession session = client.connect("localhost", port).await().getSession();
 
-        KeyPair pair = new FileKeyPairProvider(new String[] { "src/test/resources/hostkey.pem" }).loadKey(KeyPairProvider.SSH_RSA);
+        KeyPair pair = Utils.createTestHostKeyProvider().loadKey(KeyPairProvider.SSH_RSA);
 
         assertTrue(session.authPublicKey("smx", pair).await().isSuccess());
     }

Modified: mina/sshd/trunk/sshd-core/src/test/java/org/apache/sshd/CompressionTest.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/sshd-core/src/test/java/org/apache/sshd/CompressionTest.java?rev=1434654&r1=1434653&r2=1434654&view=diff
==============================================================================
--- mina/sshd/trunk/sshd-core/src/test/java/org/apache/sshd/CompressionTest.java (original)
+++ mina/sshd/trunk/sshd-core/src/test/java/org/apache/sshd/CompressionTest.java Thu Jan 17 13:04:13 2013
@@ -29,10 +29,11 @@ import org.apache.sshd.common.NamedFacto
 import org.apache.sshd.common.compression.CompressionDelayedZlib;
 import org.apache.sshd.common.compression.CompressionNone;
 import org.apache.sshd.common.compression.CompressionZlib;
-import org.apache.sshd.common.keyprovider.FileKeyPairProvider;
 import org.apache.sshd.util.BogusPasswordAuthenticator;
 import org.apache.sshd.util.EchoShellFactory;
+import org.apache.sshd.util.Utils;
 import org.junit.After;
+
 import static org.junit.Assert.assertEquals;
 import org.junit.Test;
 
@@ -67,7 +68,7 @@ public class CompressionTest {
     protected void setUp(NamedFactory<org.apache.sshd.common.Compression> compression) throws Exception {
         sshd = SshServer.setUpDefaultServer();
         sshd.setPort(8000);
-        sshd.setKeyPairProvider(new FileKeyPairProvider(new String[] { "src/test/resources/hostkey.pem" }));
+        sshd.setKeyPairProvider(Utils.createTestHostKeyProvider());
         sshd.setCompressionFactories(Arrays.<NamedFactory<org.apache.sshd.common.Compression>>asList(compression));
         sshd.setShellFactory(new EchoShellFactory());
         sshd.setPasswordAuthenticator(new BogusPasswordAuthenticator());

Modified: mina/sshd/trunk/sshd-core/src/test/java/org/apache/sshd/KeepAliveTest.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/sshd-core/src/test/java/org/apache/sshd/KeepAliveTest.java?rev=1434654&r1=1434653&r2=1434654&view=diff
==============================================================================
--- mina/sshd/trunk/sshd-core/src/test/java/org/apache/sshd/KeepAliveTest.java (original)
+++ mina/sshd/trunk/sshd-core/src/test/java/org/apache/sshd/KeepAliveTest.java Thu Jan 17 13:04:13 2013
@@ -25,13 +25,9 @@ import java.net.ServerSocket;
 import java.util.concurrent.CountDownLatch;
 
 import org.apache.sshd.client.ClientFactoryManager;
-import org.apache.sshd.common.keyprovider.FileKeyPairProvider;
 import org.apache.sshd.server.Command;
 import org.apache.sshd.server.ServerFactoryManager;
-import org.apache.sshd.util.BogusPasswordAuthenticator;
-import org.apache.sshd.util.BogusPublickeyAuthenticator;
-import org.apache.sshd.util.EchoShellFactory;
-import org.apache.sshd.util.TeePipedOutputStream;
+import org.apache.sshd.util.*;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -57,7 +53,7 @@ public class KeepAliveTest {
         sshd = SshServer.setUpDefaultServer();
         sshd.getProperties().put(ServerFactoryManager.IDLE_TIMEOUT, "1000");
         sshd.setPort(port);
-        sshd.setKeyPairProvider(new FileKeyPairProvider(new String[] { "src/test/resources/hostkey.pem" }));
+        sshd.setKeyPairProvider(Utils.createTestHostKeyProvider());
         sshd.setShellFactory(new TestEchoShellFactory());
         sshd.setPasswordAuthenticator(new BogusPasswordAuthenticator());
         sshd.setPublickeyAuthenticator(new BogusPublickeyAuthenticator());

Modified: mina/sshd/trunk/sshd-core/src/test/java/org/apache/sshd/LoadTest.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/sshd-core/src/test/java/org/apache/sshd/LoadTest.java?rev=1434654&r1=1434653&r2=1434654&view=diff
==============================================================================
--- mina/sshd/trunk/sshd-core/src/test/java/org/apache/sshd/LoadTest.java (original)
+++ mina/sshd/trunk/sshd-core/src/test/java/org/apache/sshd/LoadTest.java Thu Jan 17 13:04:13 2013
@@ -32,11 +32,12 @@ import org.apache.sshd.common.Cipher;
 import org.apache.sshd.common.KeyExchange;
 import org.apache.sshd.common.NamedFactory;
 import org.apache.sshd.common.cipher.BlowfishCBC;
-import org.apache.sshd.common.keyprovider.FileKeyPairProvider;
 import org.apache.sshd.util.BogusPasswordAuthenticator;
 import org.apache.sshd.util.EchoShellFactory;
 import org.apache.sshd.util.TeePipedOutputStream;
+import org.apache.sshd.util.Utils;
 import org.junit.After;
+
 import static org.junit.Assert.assertArrayEquals;
 import org.junit.Before;
 import org.junit.Test;
@@ -54,7 +55,7 @@ public class LoadTest {
 
         sshd = SshServer.setUpDefaultServer();
         sshd.setPort(port);
-        sshd.setKeyPairProvider(new FileKeyPairProvider(new String[] { "src/test/resources/hostkey.pem" }));
+        sshd.setKeyPairProvider(Utils.createTestHostKeyProvider());
         sshd.setShellFactory(new EchoShellFactory());
         sshd.setPasswordAuthenticator(new BogusPasswordAuthenticator());
         sshd.start();