You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by lg...@apache.org on 2015/06/08 13:30:18 UTC

[5/6] mina-sshd git commit: [SSHD-483] Move classes from org.apache.sshd to their rightful location - common, client or server

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/9b98f342/sshd-core/src/main/java/org/apache/sshd/SshServer.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/SshServer.java b/sshd-core/src/main/java/org/apache/sshd/SshServer.java
deleted file mode 100644
index ad6d5f6..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/SshServer.java
+++ /dev/null
@@ -1,473 +0,0 @@
-/*
- * 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;
-
-import java.io.IOException;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.EnumSet;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.sshd.common.AbstractFactoryManager;
-import org.apache.sshd.common.Closeable;
-import org.apache.sshd.common.Factory;
-import org.apache.sshd.common.FactoryManagerUtils;
-import org.apache.sshd.common.ForwardingFilter;
-import org.apache.sshd.common.NamedFactory;
-import org.apache.sshd.common.io.IoAcceptor;
-import org.apache.sshd.common.io.IoServiceFactory;
-import org.apache.sshd.common.io.IoSession;
-import org.apache.sshd.common.io.mina.MinaServiceFactory;
-import org.apache.sshd.common.io.nio2.Nio2ServiceFactory;
-import org.apache.sshd.common.session.AbstractSession;
-import org.apache.sshd.common.util.GenericUtils;
-import org.apache.sshd.common.util.OsUtils;
-import org.apache.sshd.common.util.SecurityUtils;
-import org.apache.sshd.common.util.ValidateUtils;
-import org.apache.sshd.server.Command;
-import org.apache.sshd.server.CommandFactory;
-import org.apache.sshd.server.PasswordAuthenticator;
-import org.apache.sshd.server.PublickeyAuthenticator;
-import org.apache.sshd.server.ServerFactoryManager;
-import org.apache.sshd.server.UserAuth;
-import org.apache.sshd.server.auth.UserAuthKeyboardInteractive;
-import org.apache.sshd.server.auth.UserAuthPassword;
-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.command.ScpCommandFactory;
-import org.apache.sshd.server.keyprovider.PEMGeneratorHostKeyProvider;
-import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
-import org.apache.sshd.server.session.ServerConnectionService;
-import org.apache.sshd.server.session.ServerSession;
-import org.apache.sshd.server.session.ServerUserAuthService;
-import org.apache.sshd.server.session.SessionFactory;
-import org.apache.sshd.server.sftp.SftpSubsystemFactory;
-import org.apache.sshd.server.shell.ProcessShellFactory;
-
-/**
- * The SshServer class is the main entry point for the server side of the SSH protocol.
- *
- * The SshServer has to be configured before being started.  Such configuration can be
- * done either using a dependency injection mechanism (such as the Spring framework)
- * or programmatically. Basic setup is usually done using the {@link #setUpDefaultServer()}
- * method, which will known ciphers, macs, channels, etc...
- * Besides this basic setup, a few things have to be manually configured such as the
- * port number, {@link Factory}, the {@link org.apache.sshd.common.keyprovider.KeyPairProvider}
- * and the {@link PasswordAuthenticator}.
- *
- * Some properties can also be configured using the {@link #setProperties(java.util.Map)}
- * method.
- *
- * Once the SshServer instance has been configured, it can be started using the
- * {@link #start()} method and stopped using the {@link #stop()} method.
- *
- * @see ServerFactoryManager
- * @see org.apache.sshd.common.FactoryManager
- *
- *
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public class SshServer extends AbstractFactoryManager implements ServerFactoryManager, Closeable {
-
-    public static final Factory<SshServer> DEFAULT_SSH_SERVER_FACTORY = new Factory<SshServer>() {
-        @Override
-        public SshServer create() {
-            return new SshServer();
-        }
-    };
-
-    protected IoAcceptor acceptor;
-    protected String host;
-    protected int port;
-    protected List<NamedFactory<UserAuth>> userAuthFactories;
-    protected Factory<Command> shellFactory;
-    protected SessionFactory sessionFactory;
-    protected CommandFactory commandFactory;
-    protected List<NamedFactory<Command>> subsystemFactories;
-    protected PasswordAuthenticator passwordAuthenticator;
-    protected PublickeyAuthenticator publickeyAuthenticator;
-    protected GSSAuthenticator gssAuthenticator;
-
-    public SshServer() {
-    }
-
-    public String getHost() {
-        return host;
-    }
-
-    public void setHost(String host) {
-        this.host = host;
-    }
-
-    public int getPort() {
-        return port;
-    }
-
-    /**
-     * Configure the port number to use for this SSH server.
-     *
-     * @param port the port number for this SSH server
-     */
-    public void setPort(int port) {
-        this.port = port;
-    }
-
-    @Override
-    public List<NamedFactory<UserAuth>> getUserAuthFactories() {
-        return userAuthFactories;
-    }
-
-    public void setUserAuthFactories(List<NamedFactory<UserAuth>> userAuthFactories) {
-        this.userAuthFactories = userAuthFactories;
-    }
-
-    @Override
-    public Factory<Command> getShellFactory() {
-        return shellFactory;
-    }
-
-    public void setShellFactory(Factory<Command> shellFactory) {
-        this.shellFactory = shellFactory;
-    }
-
-    public SessionFactory getSessionFactory() {
-        return sessionFactory;
-    }
-
-    public void setSessionFactory(SessionFactory sessionFactory) {
-        this.sessionFactory = sessionFactory;
-    }
-
-    @Override
-    public CommandFactory getCommandFactory() {
-        return commandFactory;
-    }
-
-    public void setCommandFactory(CommandFactory commandFactory) {
-        this.commandFactory = commandFactory;
-    }
-
-    @Override
-    public List<NamedFactory<Command>> getSubsystemFactories() {
-        return subsystemFactories;
-    }
-
-    public void setSubsystemFactories(List<NamedFactory<Command>> subsystemFactories) {
-        this.subsystemFactories = subsystemFactories;
-    }
-
-    @Override
-    public PasswordAuthenticator getPasswordAuthenticator() {
-        return passwordAuthenticator;
-    }
-
-    public void setPasswordAuthenticator(PasswordAuthenticator passwordAuthenticator) {
-        this.passwordAuthenticator = passwordAuthenticator;
-    }
-
-    @Override
-    public PublickeyAuthenticator getPublickeyAuthenticator() {
-        return publickeyAuthenticator;
-    }
-
-    public void setPublickeyAuthenticator(PublickeyAuthenticator publickeyAuthenticator) {
-        this.publickeyAuthenticator = publickeyAuthenticator;
-    }
-
-    @Override
-    public GSSAuthenticator getGSSAuthenticator() {
-      return gssAuthenticator;
-    }
-
-    public void setGSSAuthenticator(GSSAuthenticator gssAuthenticator) {
-      this.gssAuthenticator = gssAuthenticator;
-    }
-
-    @Override
-    public void setTcpipForwardingFilter(ForwardingFilter forwardingFilter) {
-        this.tcpipForwardingFilter = forwardingFilter;
-    }
-
-    @Override
-    protected void checkConfig() {
-        super.checkConfig();
-
-        ValidateUtils.checkTrue(getPort() >= 0 /* zero means not set yet */, "Bad port number: %d", Integer.valueOf(getPort()));
-
-        if (GenericUtils.isEmpty(getUserAuthFactories())) {
-            List<NamedFactory<UserAuth>> factories = new ArrayList<NamedFactory<UserAuth>>();
-            if (getPasswordAuthenticator() != null) {
-                factories.add(UserAuthPassword.UserAuthPasswordFactory.INSTANCE);
-                factories.add(UserAuthKeyboardInteractive.UserAuthKeyboardInteractiveFactory.INSTANCE);
-            }
-            if (getPublickeyAuthenticator() != null) {
-                factories.add(UserAuthPublicKey.UserAuthPublicKeyFactory.INSTANCE);
-            }
-            if (getGSSAuthenticator() != null) {
-              factories.add(UserAuthGSS.UserAuthGSSFactory.INSTANCE);
-            }
-            
-            ValidateUtils.checkTrue(factories.size() > 0, "UserAuthFactories not set", GenericUtils.EMPTY_OBJECT_ARRAY); 
-            setUserAuthFactories(factories);
-        }
-
-        ValidateUtils.checkNotNullAndNotEmpty(getChannelFactories(), "ChannelFactories not set", GenericUtils.EMPTY_OBJECT_ARRAY);
-        ValidateUtils.checkNotNull(getKeyPairProvider(), "HostKeyProvider not set", GenericUtils.EMPTY_OBJECT_ARRAY);
-        ValidateUtils.checkNotNull(getFileSystemFactory(), "FileSystemFactory not set", GenericUtils.EMPTY_OBJECT_ARRAY);
-
-        if (GenericUtils.isEmpty(getServiceFactories())) {
-            setServiceFactories(Arrays.asList(
-                    new ServerUserAuthService.Factory(),
-                    new ServerConnectionService.Factory()
-            ));
-        }
-    }
-
-    /**
-     * Start the SSH server and accept incoming exceptions on the configured port.
-     * 
-     * @throws IOException
-     */
-    public void start() throws IOException {
-        checkConfig();
-        if (sessionFactory == null) {
-            sessionFactory = createSessionFactory();
-        }
-        sessionFactory.setServer(this);
-        acceptor = createAcceptor();
-
-        setupSessionTimeout(sessionFactory);
-
-        String  hostsList=getHost();
-        if (!GenericUtils.isEmpty(hostsList)) {
-            String[] hosts = GenericUtils.split(hostsList, ',');
-            for (String host : hosts) {
-                if (log.isDebugEnabled()) {
-                    log.debug("start() - resolve bind host={}", host);
-                }
-
-                InetAddress[] inetAddresses = InetAddress.getAllByName(host);
-                for (InetAddress inetAddress : inetAddresses) {
-                    if (log.isTraceEnabled()) {
-                        log.trace("start() - bind host={} / {}", host, inetAddress);
-                    }
-
-                    acceptor.bind(new InetSocketAddress(inetAddress, port));
-                    if (port == 0) {
-                        port = ((InetSocketAddress) acceptor.getBoundAddresses().iterator().next()).getPort();
-                        log.info("start() listen on auto-allocated port=" + port);
-                    }
-                }
-            }
-        } else {
-            acceptor.bind(new InetSocketAddress(port));
-            if (port == 0) {
-                port = ((InetSocketAddress) acceptor.getBoundAddresses().iterator().next()).getPort();
-                log.info("start() listen on auto-allocated port=" + port);
-            }
-        }
-    }
-
-    /**
-     * Stop the SSH server.  This method will block until all resources are actually disposed.
-     */
-    public void stop() throws InterruptedException {
-        stop(false);
-    }
-
-    public void stop(boolean immediately) throws InterruptedException {
-        close(immediately).await();
-    }
-
-    public void open() throws IOException {
-        start();
-    }
-
-    @Override
-    protected Closeable getInnerCloseable() {
-        return builder()
-                .run(new Runnable() {
-                    @SuppressWarnings("synthetic-access")
-                    @Override
-                    public void run() {
-                        removeSessionTimeout(sessionFactory);
-                    }
-                })
-                .sequential(acceptor, ioServiceFactory)
-                .run(new Runnable() {
-                    @SuppressWarnings("synthetic-access")
-                    @Override
-                    public void run() {
-                        acceptor = null;
-                        ioServiceFactory = null;
-                        if (shutdownExecutor && (executor != null) && (!executor.isShutdown())) {
-                            try {
-                                executor.shutdownNow();
-                            } finally {
-                                executor = null;
-                            }
-                        }
-                    }
-                })
-                .build();
-    }
-
-    /**
-     * Obtain the list of active sessions.
-     */
-    public List<AbstractSession> getActiveSessions() {
-        List<AbstractSession> sessions = new ArrayList<AbstractSession>();
-        for (IoSession ioSession : acceptor.getManagedSessions().values()) {
-            AbstractSession session = AbstractSession.getSession(ioSession, true);
-            if (session != null) {
-                sessions.add(session);
-            }
-        }
-        return sessions;
-    }
-
-    protected IoAcceptor createAcceptor() {
-        return getIoServiceFactory().createAcceptor(getSessionFactory());
-    }
-
-    protected SessionFactory createSessionFactory() {
-        return new SessionFactory();
-    }
-
-    @Override
-    public String toString() {
-        return "SshServer[" + Integer.toHexString(hashCode()) + "]";
-    }
-
-    public static SshServer setUpDefaultServer() {
-        return SshBuilder.server().build();
-    }
-
-    /*=================================
-          Main class implementation
-     *=================================*/
-
-    public static void main(String[] args) throws Exception {
-        int port = 8000;
-        String provider;
-        boolean error = false;
-        Map<String, String> options = new LinkedHashMap<String, String>();
-
-        for (int i = 0; i < args.length; i++) {
-            if ("-p".equals(args[i])) {
-                if (i + 1 >= args.length) {
-                    System.err.println("option requires an argument: " + args[i]);
-                    break;
-                }
-                port = Integer.parseInt(args[++i]);
-            } else if ("-io".equals(args[i])) {
-                if (i + 1 >= args.length) {
-                    System.err.println("option requires an argument: " + args[i]);
-                    break;
-                }
-                provider = args[++i];
-                if ("mina".equals(provider)) {
-                    System.setProperty(IoServiceFactory.class.getName(), MinaServiceFactory.class.getName());
-                } else if ("nio2".endsWith(provider)) {
-                    System.setProperty(IoServiceFactory.class.getName(), Nio2ServiceFactory.class.getName());
-                } else {
-                    System.err.println("provider should be mina or nio2: " + args[i]);
-                    break;
-                }
-            } else if ("-o".equals(args[i])) {
-                if (i + 1 >= args.length) {
-                    System.err.println("option requires and argument: " + args[i]);
-                    error = true;
-                    break;
-                }
-                String opt = args[++i];
-                int idx = opt.indexOf('=');
-                if (idx <= 0) {
-                    System.err.println("bad syntax for option: " + opt);
-                    error = true;
-                    break;
-                }
-                options.put(opt.substring(0, idx), opt.substring(idx + 1));
-            } else if (args[i].startsWith("-")) {
-                System.err.println("illegal option: " + args[i]);
-                error = true;
-                break;
-            } else {
-                System.err.println("extra argument: " + args[i]);
-                error = true;
-                break;
-            }
-        }
-        if (error) {
-            System.err.println("usage: sshd [-p port] [-io mina|nio2] [-o option=value]");
-            System.exit(-1);
-        }
-
-        System.err.println("Starting SSHD on port " + port);
-                                                    
-        SshServer sshd = SshServer.setUpDefaultServer();
-        Map<String,Object> props = sshd.getProperties();
-        FactoryManagerUtils.updateProperty(props, ServerFactoryManager.WELCOME_BANNER, "Welcome to SSHD\n");
-        props.putAll(options);
-        sshd.setPort(port);
-
-        if (SecurityUtils.isBouncyCastleRegistered()) {
-            sshd.setKeyPairProvider(new PEMGeneratorHostKeyProvider("key.pem"));
-        } else {
-            sshd.setKeyPairProvider(new SimpleGeneratorHostKeyProvider("key.ser"));
-        }
-        if (OsUtils.isUNIX()) {
-            sshd.setShellFactory(new ProcessShellFactory(new String[] { "/bin/sh", "-i", "-l" },
-                                 EnumSet.of(ProcessShellFactory.TtyOptions.ONlCr)));
-        } else {
-            sshd.setShellFactory(new ProcessShellFactory(new String[] { "cmd.exe "},
-                                 EnumSet.of(ProcessShellFactory.TtyOptions.Echo, ProcessShellFactory.TtyOptions.ICrNl, ProcessShellFactory.TtyOptions.ONlCr)));
-        }
-        sshd.setPasswordAuthenticator(new PasswordAuthenticator() {
-            @Override
-            public boolean authenticate(String username, String password, ServerSession session) {
-                return username != null && username.equals(password);
-            }
-        });
-        sshd.setPublickeyAuthenticator(PublickeyAuthenticator.AcceptAllPublickeyAuthenticator.INSTANCE);
-        sshd.setTcpipForwardingFilter(ForwardingFilter.AcceptAllForwardingFilter.INSTANCE);
-        sshd.setCommandFactory(new ScpCommandFactory.Builder().withDelegate(new CommandFactory() {
-            @Override
-            public Command createCommand(String command) {
-                EnumSet<ProcessShellFactory.TtyOptions> ttyOptions;
-                if (OsUtils.isUNIX()) {
-                    ttyOptions = EnumSet.of(ProcessShellFactory.TtyOptions.ONlCr);
-                } else {
-                    ttyOptions = EnumSet.of(ProcessShellFactory.TtyOptions.Echo, ProcessShellFactory.TtyOptions.ICrNl, ProcessShellFactory.TtyOptions.ONlCr);
-                }
-                return new ProcessShellFactory(command.split(" "), ttyOptions).create();
-            }
-        }).build());
-        sshd.setSubsystemFactories(Arrays.<NamedFactory<Command>>asList(new SftpSubsystemFactory()));
-        sshd.start();
-
-        Thread.sleep(Long.MAX_VALUE);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/9b98f342/sshd-core/src/main/java/org/apache/sshd/agent/SshAgentFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/agent/SshAgentFactory.java b/sshd-core/src/main/java/org/apache/sshd/agent/SshAgentFactory.java
index 7fb8ebc..ba12eaf 100644
--- a/sshd-core/src/main/java/org/apache/sshd/agent/SshAgentFactory.java
+++ b/sshd-core/src/main/java/org/apache/sshd/agent/SshAgentFactory.java
@@ -20,9 +20,9 @@ package org.apache.sshd.agent;
 
 import java.io.IOException;
 
-import org.apache.sshd.common.Channel;
 import org.apache.sshd.common.FactoryManager;
 import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.channel.Channel;
 import org.apache.sshd.common.session.ConnectionService;
 
 /**

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/9b98f342/sshd-core/src/main/java/org/apache/sshd/agent/SshAgentServer.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/agent/SshAgentServer.java b/sshd-core/src/main/java/org/apache/sshd/agent/SshAgentServer.java
index 233930e..d07a6f7 100644
--- a/sshd-core/src/main/java/org/apache/sshd/agent/SshAgentServer.java
+++ b/sshd-core/src/main/java/org/apache/sshd/agent/SshAgentServer.java
@@ -18,9 +18,9 @@
  */
 package org.apache.sshd.agent;
 
-import java.io.Closeable;
+import java.nio.channels.Channel;
 
-public interface SshAgentServer extends Closeable {
+public interface SshAgentServer extends Channel {
     /**
      * @return Agent server identifier
      */

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/9b98f342/sshd-core/src/main/java/org/apache/sshd/agent/local/AgentImpl.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/agent/local/AgentImpl.java b/sshd-core/src/main/java/org/apache/sshd/agent/local/AgentImpl.java
index 5ccea64..fffad42 100644
--- a/sshd-core/src/main/java/org/apache/sshd/agent/local/AgentImpl.java
+++ b/sshd-core/src/main/java/org/apache/sshd/agent/local/AgentImpl.java
@@ -31,9 +31,9 @@ import java.util.List;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 import org.apache.sshd.agent.SshAgent;
-import org.apache.sshd.common.Signature;
 import org.apache.sshd.common.SshException;
 import org.apache.sshd.common.signature.BuiltinSignatures;
+import org.apache.sshd.common.signature.Signature;
 
 /**
  * A local SSH agent implementation

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/9b98f342/sshd-core/src/main/java/org/apache/sshd/agent/local/AgentServerProxy.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/agent/local/AgentServerProxy.java b/sshd-core/src/main/java/org/apache/sshd/agent/local/AgentServerProxy.java
index 32ae13f..7df3f2b 100644
--- a/sshd-core/src/main/java/org/apache/sshd/agent/local/AgentServerProxy.java
+++ b/sshd-core/src/main/java/org/apache/sshd/agent/local/AgentServerProxy.java
@@ -20,21 +20,26 @@ package org.apache.sshd.agent.local;
 
 import java.io.IOException;
 import java.util.UUID;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 import org.apache.sshd.agent.SshAgent;
 import org.apache.sshd.agent.SshAgentServer;
 import org.apache.sshd.client.future.OpenFuture;
 import org.apache.sshd.common.session.ConnectionService;
+import org.apache.sshd.common.util.AbstractLoggingBean;
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.ValidateUtils;
 
 /**
  * The server side fake agent, acting as an agent, but actually forwarding the requests to the auth channel on the client side.
  */
-public class AgentServerProxy implements SshAgentServer {
+public class AgentServerProxy extends AbstractLoggingBean implements SshAgentServer {
     private final ConnectionService service;
-    private String id;
+    private final String id;
+    private final AtomicBoolean open = new AtomicBoolean(true);
 
     public AgentServerProxy(ConnectionService service) throws IOException {
-        this.service = service;
+        this.service = ValidateUtils.checkNotNull(service, "No connection service provided", GenericUtils.EMPTY_OBJECT_ARRAY);
         this.id = UUID.randomUUID().toString();
     }
 
@@ -44,16 +49,22 @@ public class AgentServerProxy implements SshAgentServer {
             this.service.registerChannel(channel);
             OpenFuture future = channel.open().await();
             Throwable t = future.getException();
-            if (t instanceof Exception) {
-                throw (Exception) t;
-            } else if (t != null) {
-                throw new Exception(t);
+            if (t != null) {
+                throw t;
             }
             return channel.getAgent();
-        } catch (IOException e) {
-            throw e;
-        } catch (Exception e) {
-            throw (IOException) new IOException().initCause(e);
+        } catch(Throwable t) {
+            if (log.isDebugEnabled()) {
+                log.debug("createClient(" + service.getSession() + ")[" + getId() + ")"
+                        + " failed (" + t.getClass().getSimpleName() + ")"
+                        + " to create client: " + t.getMessage());
+            }
+
+            if (t instanceof IOException) {
+                throw (IOException) t;
+            }
+            
+            throw (IOException) new IOException("Failed (" + t.getClass().getSimpleName() + ") to create client: " + t.getMessage()).initCause(t);
         }
     }
 
@@ -63,8 +74,16 @@ public class AgentServerProxy implements SshAgentServer {
     }
 
     @Override
-    public void close() throws IOException {
-        // nothing
+    public boolean isOpen() {
+        return open.get();
     }
 
+    @Override
+    public void close() throws IOException {
+        if (open.getAndSet(false)) {
+            if (log.isDebugEnabled()) {
+                log.debug("closed(" + service.getSession() + ")[" + getId() + "]");
+            }
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/9b98f342/sshd-core/src/main/java/org/apache/sshd/agent/local/ChannelAgentForwarding.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/agent/local/ChannelAgentForwarding.java b/sshd-core/src/main/java/org/apache/sshd/agent/local/ChannelAgentForwarding.java
index 5b59be4..6aef192 100644
--- a/sshd-core/src/main/java/org/apache/sshd/agent/local/ChannelAgentForwarding.java
+++ b/sshd-core/src/main/java/org/apache/sshd/agent/local/ChannelAgentForwarding.java
@@ -25,9 +25,9 @@ import org.apache.sshd.agent.SshAgent;
 import org.apache.sshd.agent.common.AbstractAgentClient;
 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.channel.Channel;
 import org.apache.sshd.common.channel.ChannelOutputStream;
 import org.apache.sshd.common.future.CloseFuture;
 import org.apache.sshd.common.future.SshFutureListener;

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/9b98f342/sshd-core/src/main/java/org/apache/sshd/agent/local/LocalAgentFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/agent/local/LocalAgentFactory.java b/sshd-core/src/main/java/org/apache/sshd/agent/local/LocalAgentFactory.java
index 1d68247..14eabd2 100644
--- a/sshd-core/src/main/java/org/apache/sshd/agent/local/LocalAgentFactory.java
+++ b/sshd-core/src/main/java/org/apache/sshd/agent/local/LocalAgentFactory.java
@@ -24,9 +24,9 @@ import org.apache.sshd.agent.SshAgent;
 import org.apache.sshd.agent.SshAgentFactory;
 import org.apache.sshd.agent.SshAgentServer;
 import org.apache.sshd.agent.common.AgentDelegate;
-import org.apache.sshd.common.Channel;
 import org.apache.sshd.common.FactoryManager;
 import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.channel.Channel;
 import org.apache.sshd.common.session.ConnectionService;
 
 public class LocalAgentFactory implements SshAgentFactory {

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/9b98f342/sshd-core/src/main/java/org/apache/sshd/agent/local/ProxyAgentFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/agent/local/ProxyAgentFactory.java b/sshd-core/src/main/java/org/apache/sshd/agent/local/ProxyAgentFactory.java
index 6f5e307..4b3e02a 100644
--- a/sshd-core/src/main/java/org/apache/sshd/agent/local/ProxyAgentFactory.java
+++ b/sshd-core/src/main/java/org/apache/sshd/agent/local/ProxyAgentFactory.java
@@ -21,16 +21,17 @@ package org.apache.sshd.agent.local;
 import java.io.IOException;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 import org.apache.sshd.agent.SshAgent;
 import org.apache.sshd.agent.SshAgentFactory;
 import org.apache.sshd.agent.SshAgentServer;
-import org.apache.sshd.common.Channel;
 import org.apache.sshd.common.FactoryManager;
 import org.apache.sshd.common.FactoryManagerUtils;
 import org.apache.sshd.common.NamedFactory;
-import org.apache.sshd.common.Session;
+import org.apache.sshd.common.channel.Channel;
 import org.apache.sshd.common.session.ConnectionService;
+import org.apache.sshd.common.session.Session;
 import org.apache.sshd.common.util.GenericUtils;
 import org.apache.sshd.server.session.ServerSession;
 
@@ -62,22 +63,31 @@ public class ProxyAgentFactory implements SshAgentFactory {
     public SshAgentServer createServer(ConnectionService service) throws IOException {
         Session session = service.getSession();
         if (!(session instanceof ServerSession)) {
-            throw new IllegalStateException("The session used to create an agent server proxy must be a server session");
+            throw new IllegalStateException("The session used to create an agent server proxy must be a server session: " + session);
         }
 
         final AgentServerProxy proxy = new AgentServerProxy(service);
         proxies.put(proxy.getId(), proxy);
         return new SshAgentServer() {
+            private final AtomicBoolean open = new AtomicBoolean(true);
+
             @Override
             public String getId() {
                 return proxy.getId();
             }
 
+            @Override
+            public boolean isOpen() {
+                return open.get() && proxy.isOpen();
+            }
+
             @SuppressWarnings("synthetic-access")
             @Override
             public void close() throws IOException {
-                proxies.remove(proxy.getId());
-                proxy.close();
+                if (open.getAndSet(false)) {
+                    proxies.remove(proxy.getId());
+                    proxy.close();
+                }
             }
         };
     }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/9b98f342/sshd-core/src/main/java/org/apache/sshd/agent/unix/AgentServerProxy.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/agent/unix/AgentServerProxy.java b/sshd-core/src/main/java/org/apache/sshd/agent/unix/AgentServerProxy.java
index ab84cee..0907b63 100644
--- a/sshd-core/src/main/java/org/apache/sshd/agent/unix/AgentServerProxy.java
+++ b/sshd-core/src/main/java/org/apache/sshd/agent/unix/AgentServerProxy.java
@@ -20,7 +20,6 @@ package org.apache.sshd.agent.unix;
 
 import java.io.File;
 import java.io.IOException;
-import java.nio.channels.Channel;
 import java.util.Collection;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Future;
@@ -43,7 +42,7 @@ import org.apache.tomcat.jni.Status;
 /**
  * The server side fake agent, acting as an agent, but actually forwarding the requests to the auth channel on the client side.
  */
-public class AgentServerProxy extends AbstractLoggingBean implements SshAgentServer, ExecutorServiceCarrier, Channel {
+public class AgentServerProxy extends AbstractLoggingBean implements SshAgentServer, ExecutorServiceCarrier {
     private final ConnectionService service;
     private final String authSocket;
     private final long pool;

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/9b98f342/sshd-core/src/main/java/org/apache/sshd/agent/unix/ChannelAgentForwarding.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/agent/unix/ChannelAgentForwarding.java b/sshd-core/src/main/java/org/apache/sshd/agent/unix/ChannelAgentForwarding.java
index 5f7cb15..7a38bdd 100644
--- a/sshd-core/src/main/java/org/apache/sshd/agent/unix/ChannelAgentForwarding.java
+++ b/sshd-core/src/main/java/org/apache/sshd/agent/unix/ChannelAgentForwarding.java
@@ -27,10 +27,10 @@ import java.util.concurrent.Future;
 import org.apache.sshd.agent.SshAgent;
 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.FactoryManagerUtils;
 import org.apache.sshd.common.NamedFactory;
 import org.apache.sshd.common.SshConstants;
+import org.apache.sshd.common.channel.Channel;
 import org.apache.sshd.common.channel.ChannelOutputStream;
 import org.apache.sshd.common.future.CloseFuture;
 import org.apache.sshd.common.future.SshFutureListener;

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/9b98f342/sshd-core/src/main/java/org/apache/sshd/agent/unix/UnixAgentFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/agent/unix/UnixAgentFactory.java b/sshd-core/src/main/java/org/apache/sshd/agent/unix/UnixAgentFactory.java
index 61d5a28..8e74b08 100644
--- a/sshd-core/src/main/java/org/apache/sshd/agent/unix/UnixAgentFactory.java
+++ b/sshd-core/src/main/java/org/apache/sshd/agent/unix/UnixAgentFactory.java
@@ -24,13 +24,13 @@ import java.util.concurrent.ExecutorService;
 import org.apache.sshd.agent.SshAgent;
 import org.apache.sshd.agent.SshAgentFactory;
 import org.apache.sshd.agent.SshAgentServer;
-import org.apache.sshd.common.Channel;
 import org.apache.sshd.common.FactoryManager;
 import org.apache.sshd.common.FactoryManagerUtils;
 import org.apache.sshd.common.NamedFactory;
-import org.apache.sshd.common.Session;
 import org.apache.sshd.common.SshException;
+import org.apache.sshd.common.channel.Channel;
 import org.apache.sshd.common.session.ConnectionService;
+import org.apache.sshd.common.session.Session;
 import org.apache.sshd.common.util.GenericUtils;
 import org.apache.sshd.common.util.threads.ExecutorServiceConfigurer;
 import org.apache.sshd.server.session.ServerSession;

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/9b98f342/sshd-core/src/main/java/org/apache/sshd/client/ClientBuilder.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/ClientBuilder.java b/sshd-core/src/main/java/org/apache/sshd/client/ClientBuilder.java
new file mode 100644
index 0000000..ccea2d6
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/ClientBuilder.java
@@ -0,0 +1,110 @@
+/*
+ * 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;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.sshd.client.kex.DHGClient;
+import org.apache.sshd.client.kex.DHGEXClient;
+import org.apache.sshd.client.keyverifier.AcceptAllServerKeyVerifier;
+import org.apache.sshd.common.BaseBuilder;
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.Transformer;
+import org.apache.sshd.common.channel.Channel;
+import org.apache.sshd.common.kex.BuiltinDHFactories;
+import org.apache.sshd.common.kex.DHFactory;
+import org.apache.sshd.common.kex.KeyExchange;
+import org.apache.sshd.server.forward.TcpipServerChannel;
+
+/**
+ * SshClient builder
+ */
+public class ClientBuilder extends BaseBuilder<SshClient, ClientBuilder> {
+    public static final Transformer<DHFactory,NamedFactory<KeyExchange>> DH2KEX =
+            new Transformer<DHFactory, NamedFactory<KeyExchange>>() {
+                @Override
+                public NamedFactory<KeyExchange> transform(DHFactory factory) {
+                    if (factory == null) {
+                        return null;
+                    } else if (factory.isGroupExchange()) {
+                        return DHGEXClient.newFactory(factory);
+                    } else {
+                        return DHGClient.newFactory(factory);
+                    }
+                }
+            };
+    protected ServerKeyVerifier serverKeyVerifier;
+
+    public ClientBuilder() {
+        super();
+    }
+
+    public ClientBuilder serverKeyVerifier(ServerKeyVerifier serverKeyVerifier) {
+        this.serverKeyVerifier = serverKeyVerifier;
+        return me();
+    }
+
+    @Override
+    protected ClientBuilder fillWithDefaultValues() {
+        super.fillWithDefaultValues();
+        if (keyExchangeFactories == null) {
+            keyExchangeFactories = setUpDefaultKeyExchanges(false);
+        }
+        if (channelFactories == null) {
+            channelFactories = Arrays.<NamedFactory<Channel>>asList(
+                    TcpipServerChannel.ForwardedTcpipFactory.INSTANCE);
+        }
+        if (serverKeyVerifier == null) {
+            serverKeyVerifier = AcceptAllServerKeyVerifier.INSTANCE;
+        }
+        if (factory == null) {
+            factory = SshClient.DEFAULT_SSH_CLIENT_FACTORY;
+        }
+        return me();
+    }
+
+    @Override
+    public SshClient build(boolean isFillWithDefaultValues) {
+        SshClient client = super.build(isFillWithDefaultValues);
+        client.setServerKeyVerifier(serverKeyVerifier);
+        return client;
+    }
+
+    /**
+     * @param ignoreUnsupported If {@code true} then all the default
+     * key exchanges are included, regardless of whether they are currently
+     * supported by the JCE. Otherwise, only the supported ones out of the
+     * list are included
+     * @return A {@link List} of the default {@link NamedFactory}
+     * instances of the {@link KeyExchange}s according to the preference
+     * order defined by {@link #DEFAULT_KEX_PREFERENCE}.
+     * <B>Note:</B> the list may be filtered to exclude unsupported JCE
+     * key exchanges according to the <tt>ignoreUnsupported</tt> parameter
+     * @see BuiltinDHFactories#isSupported()
+     */
+    public static List<NamedFactory<KeyExchange>> setUpDefaultKeyExchanges(boolean ignoreUnsupported) {
+        return NamedFactory.Utils.setUpTransformedFactories(ignoreUnsupported, DEFAULT_KEX_PREFERENCE, DH2KEX);
+    }
+
+    public static ClientBuilder builder() {
+        return new ClientBuilder();
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/9b98f342/sshd-core/src/main/java/org/apache/sshd/client/ClientFactoryManager.java
----------------------------------------------------------------------
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 a9014ed..8af56a2 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
@@ -22,7 +22,7 @@ import java.util.List;
 
 import org.apache.sshd.common.FactoryManager;
 import org.apache.sshd.common.NamedFactory;
-import org.apache.sshd.common.TcpipForwarderFactory;
+import org.apache.sshd.common.forward.TcpipForwarderFactory;
 
 /**
  * The <code>ClientFactoryManager</code> enable the retrieval of additional

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/9b98f342/sshd-core/src/main/java/org/apache/sshd/client/ServerKeyVerifier.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/ServerKeyVerifier.java b/sshd-core/src/main/java/org/apache/sshd/client/ServerKeyVerifier.java
index a5bec52..3465553 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/ServerKeyVerifier.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/ServerKeyVerifier.java
@@ -21,7 +21,7 @@ package org.apache.sshd.client;
 import java.net.SocketAddress;
 import java.security.PublicKey;
 
-import org.apache.sshd.ClientSession;
+import org.apache.sshd.client.session.ClientSession;
 
 /**
  * The <code>ServerKeyVerifier</code> is used on the client side

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/9b98f342/sshd-core/src/main/java/org/apache/sshd/client/SessionFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/SessionFactory.java b/sshd-core/src/main/java/org/apache/sshd/client/SessionFactory.java
index c5d011a..619894f 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/SessionFactory.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/SessionFactory.java
@@ -27,7 +27,7 @@ import org.apache.sshd.common.session.AbstractSessionFactory;
  * A factory of client sessions.
  * This class can be used as a way to customize the creation of client sessions.
  *
- * @see org.apache.sshd.SshClient#setSessionFactory(SessionFactory)
+ * @see org.apache.sshd.client.SshClient#setSessionFactory(SessionFactory)
  *
  * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
  */

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/9b98f342/sshd-core/src/main/java/org/apache/sshd/client/SshClient.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/SshClient.java b/sshd-core/src/main/java/org/apache/sshd/client/SshClient.java
new file mode 100644
index 0000000..f223119
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/SshClient.java
@@ -0,0 +1,555 @@
+/*
+ * 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;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Callable;
+import java.util.logging.ConsoleHandler;
+import java.util.logging.Formatter;
+import java.util.logging.Handler;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+import java.util.logging.Logger;
+
+import org.apache.sshd.client.auth.UserAuthKeyboardInteractive;
+import org.apache.sshd.client.auth.UserAuthPassword;
+import org.apache.sshd.client.auth.UserAuthPublicKey;
+import org.apache.sshd.client.channel.ChannelShell;
+import org.apache.sshd.client.channel.ClientChannel;
+import org.apache.sshd.client.future.ConnectFuture;
+import org.apache.sshd.client.future.DefaultConnectFuture;
+import org.apache.sshd.client.session.ClientConnectionService;
+import org.apache.sshd.client.session.ClientSession;
+import org.apache.sshd.client.session.ClientSessionImpl;
+import org.apache.sshd.client.session.ClientUserAuthService;
+import org.apache.sshd.common.AbstractFactoryManager;
+import org.apache.sshd.common.Closeable;
+import org.apache.sshd.common.Factory;
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.SshdSocketAddress;
+import org.apache.sshd.common.channel.Channel;
+import org.apache.sshd.common.config.SshConfigFileReader;
+import org.apache.sshd.common.future.SshFutureListener;
+import org.apache.sshd.common.io.IoConnectFuture;
+import org.apache.sshd.common.io.IoConnector;
+import org.apache.sshd.common.keyprovider.FileKeyPairProvider;
+import org.apache.sshd.common.keyprovider.KeyPairProvider;
+import org.apache.sshd.common.session.AbstractSession;
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.SecurityUtils;
+import org.apache.sshd.common.util.ValidateUtils;
+import org.apache.sshd.common.util.io.NoCloseInputStream;
+import org.apache.sshd.common.util.io.NoCloseOutputStream;
+import org.bouncycastle.openssl.PasswordFinder;
+
+/**
+ * Entry point for the client side of the SSH protocol.
+ *
+ * The default configured client can be created using
+ * the {@link #setUpDefaultClient()}.  The next step is to
+ * start the client using the {@link #start()} method.
+ *
+ * Sessions can then be created using on of the
+ * {@link #connect(String, String, int)} or {@link #connect(String, java.net.SocketAddress)}
+ * methods.
+ *
+ * The client can be stopped at anytime using the {@link #stop()} method.
+ *
+ * Following is an example of using the SshClient:
+ * <pre>
+ *    SshClient client = SshClient.setUpDefaultClient();
+ *    client.start();
+ *    try {
+ *        ClientSession session = client.connect(login, host, port).await().getSession();
+ *        session.addPasswordIdentity(password);
+ *        session.auth().verify();
+ *
+ *        ClientChannel channel = session.createChannel("shell");
+ *        channel.setIn(new NoCloseInputStream(System.in));
+ *        channel.setOut(new NoCloseOutputStream(System.out));
+ *        channel.setErr(new NoCloseOutputStream(System.err));
+ *        channel.open();
+ *        channel.waitFor(ClientChannel.CLOSED, 0);
+ *        session.close(false);
+ *    } finally {
+ *        client.stop();
+ *    }
+ * </pre>
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class SshClient extends AbstractFactoryManager implements ClientFactoryManager, Closeable {
+
+    public static final Factory<SshClient> DEFAULT_SSH_CLIENT_FACTORY = new Factory<SshClient>() {
+        @Override
+        public SshClient create() {
+            return new SshClient();
+        }
+    };
+
+    protected IoConnector connector;
+    protected SessionFactory sessionFactory;
+    protected UserInteraction userInteraction;
+    protected List<NamedFactory<UserAuth>> userAuthFactories;
+
+    private ServerKeyVerifier serverKeyVerifier;
+
+    public SshClient() {
+        super();
+    }
+
+    public SessionFactory getSessionFactory() {
+        return sessionFactory;
+    }
+
+    public void setSessionFactory(SessionFactory sessionFactory) {
+        this.sessionFactory = sessionFactory;
+    }
+
+    @Override
+    public ServerKeyVerifier getServerKeyVerifier() {
+        return serverKeyVerifier;
+    }
+
+    public void setServerKeyVerifier(ServerKeyVerifier serverKeyVerifier) {
+        this.serverKeyVerifier = serverKeyVerifier;
+    }
+
+    @Override
+    public UserInteraction getUserInteraction() {
+        return userInteraction;
+    }
+
+    public void setUserInteraction(UserInteraction userInteraction) {
+        this.userInteraction = userInteraction;
+    }
+
+    @Override
+    public List<NamedFactory<UserAuth>> getUserAuthFactories() {
+        return userAuthFactories;
+    }
+
+    public void setUserAuthFactories(List<NamedFactory<UserAuth>> userAuthFactories) {
+        this.userAuthFactories = userAuthFactories;
+    }
+
+    @Override
+    protected void checkConfig() {
+        super.checkConfig();
+        
+        ValidateUtils.checkNotNull(getTcpipForwarderFactory(), "TcpipForwarderFactory not set", GenericUtils.EMPTY_OBJECT_ARRAY);
+        ValidateUtils.checkNotNull(getServerKeyVerifier(), "ServerKeyVerifier not set", GenericUtils.EMPTY_OBJECT_ARRAY);
+
+        // Register the additional agent forwarding channel if needed
+        if (getAgentFactory() != null) {
+            List<NamedFactory<Channel>> factories = getChannelFactories();
+            if (GenericUtils.isEmpty(factories)) {
+                factories = new ArrayList<NamedFactory<Channel>>();
+            } else {
+                factories = new ArrayList<NamedFactory<Channel>>(factories);
+            }
+            factories.add(getAgentFactory().getChannelForwardingFactory());
+            setChannelFactories(factories);
+        }
+
+        if (GenericUtils.isEmpty(getServiceFactories())) {
+            setServiceFactories(Arrays.asList(
+                    new ClientUserAuthService.Factory(),
+                    new ClientConnectionService.Factory()
+            ));
+        }
+
+        if (GenericUtils.isEmpty(getUserAuthFactories())) {
+            setUserAuthFactories(Arrays.asList(
+                    UserAuthPublicKey.UserAuthPublicKeyFactory.INSTANCE,
+                    UserAuthKeyboardInteractive.UserAuthKeyboardInteractiveFactory.INSTANCE,
+                    UserAuthPassword.UserAuthPasswordFactory.INSTANCE
+            ));
+        }
+    }
+
+    public void start() {
+        checkConfig();
+        if (sessionFactory == null) {
+            sessionFactory = createSessionFactory();
+        }
+
+        setupSessionTimeout(sessionFactory);
+
+        sessionFactory.setClient(this);
+        connector = createConnector();
+    }
+
+    public void stop() {
+        try {
+            close(true).await();
+        } catch (InterruptedException e) {
+            log.debug("Exception caught while stopping client", e);
+        }
+    }
+
+    public void open() throws IOException {
+        start();
+    }
+
+    @Override
+    protected Closeable getInnerCloseable() {
+        return builder()
+                .run(new Runnable() {
+                    @SuppressWarnings("synthetic-access")
+                    @Override
+                    public void run() {
+                        removeSessionTimeout(sessionFactory);
+                    }
+                })
+                .sequential(connector, ioServiceFactory)
+                .run(new Runnable() {
+                    @SuppressWarnings("synthetic-access")
+                    @Override
+                    public void run() {
+                        connector = null;
+                        ioServiceFactory = null;
+                        if (shutdownExecutor && (executor != null) && (!executor.isShutdown())) {
+                            try {
+                                executor.shutdownNow();
+                            } finally {
+                                executor = null;
+                            }
+                        }
+                    }
+                })
+                .build();
+    }
+
+    public ConnectFuture connect(String username, String host, int port) throws IOException {
+        assert host != null;
+        assert port >= 0;
+        if (connector == null) {
+            throw new IllegalStateException("SshClient not started. Please call start() method before connecting to a server");
+        }
+        SocketAddress address = new InetSocketAddress(host, port);
+        return connect(username, address);
+    }
+
+    public ConnectFuture connect(final String username, SocketAddress address) {
+        assert address != null;
+        if (connector == null) {
+            throw new IllegalStateException("SshClient not started. Please call start() method before connecting to a server");
+        }
+        final ConnectFuture connectFuture = new DefaultConnectFuture(null);
+        connector.connect(address).addListener(new SshFutureListener<IoConnectFuture>() {
+            @Override
+            public void operationComplete(IoConnectFuture future) {
+                if (future.isCanceled()) {
+                    connectFuture.cancel();
+                } else if (future.getException() != null) {
+                    connectFuture.setException(future.getException());
+                } else {
+                    ClientSessionImpl session = (ClientSessionImpl) AbstractSession.getSession(future.getSession());
+                    session.setUsername(username);
+                    connectFuture.setSession(session);
+                }
+            }
+        });
+        return connectFuture;
+    }
+
+    protected IoConnector createConnector() {
+        return getIoServiceFactory().createConnector(getSessionFactory());
+    }
+
+    protected SessionFactory createSessionFactory() {
+        return new SessionFactory();
+    }
+
+    @Override
+    public String toString() {
+        return "SshClient[" + Integer.toHexString(hashCode()) + "]";
+    }
+
+    /**
+     * Setup a default client.  The client does not require any additional setup.
+     *
+     * @return a newly create SSH client
+     */
+    public static SshClient setUpDefaultClient() {
+        return ClientBuilder.builder().build();
+    }
+
+    /*=================================
+          Main class implementation
+     *=================================*/
+
+    public static void main(String[] args) throws Exception {
+        Handler fh = new ConsoleHandler();
+        fh.setLevel(Level.FINEST);
+        fh.setFormatter(new Formatter() {
+            @Override
+            public String format(LogRecord record) {
+                String message = formatMessage(record);
+                String throwable = "";
+                if (record.getThrown() != null) {
+                    StringWriter sw = new StringWriter();
+                    PrintWriter pw = new PrintWriter(sw);
+                    pw.println();
+                    record.getThrown().printStackTrace(pw);
+                    pw.close();
+                    throwable = sw.toString();
+                }
+                return String.format("%1$tY-%1$tm-%1$td: %2$-7.7s: %3$-32.32s: %4$s%5$s%n",
+                        new Date(record.getMillis()),
+                        record.getLevel().getName(),
+                        record.getLoggerName(),
+                        message,
+                        throwable);
+            }
+        });
+        Logger root = Logger.getLogger("");
+        for (Handler handler : root.getHandlers()) {
+            root.removeHandler(handler);
+        }
+        root.addHandler(fh);
+
+        int port = SshConfigFileReader.DEFAULT_PORT;
+        String host = null;
+        String login = System.getProperty("user.name");
+        boolean agentForward = false;
+        List<String> command = null;
+        int logLevel = 0;
+        int socksPort = -1;
+        boolean error = false;
+        List<String> identities = new ArrayList<String>();
+        Map<String, String> options = new LinkedHashMap<String, String>();
+
+        for (int i = 0; i < args.length; i++) {
+            if (command == null && "-p".equals(args[i])) {
+                if (i + 1 >= args.length) {
+                    System.err.println("option requires an argument: " + args[i]);
+                    error = true;
+                    break;
+                }
+                port = Integer.parseInt(args[++i]);
+            } else if (command == null && "-D".equals(args[i])) {
+                if (i + 1 >= args.length) {
+                    System.err.println("option requires an argument: " + args[i]);
+                    error = true;
+                    break;
+                }
+                socksPort = Integer.parseInt(args[++i]);
+            } else if (command == null && "-l".equals(args[i])) {
+                if (i + 1 >= args.length) {
+                    System.err.println("option requires an argument: " + args[i]);
+                    error = true;
+                    break;
+                }
+                login = args[++i];
+            } else if (command == null && "-v".equals(args[i])) {
+                logLevel += 1;
+            } else if (command == null && "-vv".equals(args[i])) {
+                logLevel += 2;
+            } else if (command == null && "-vvv".equals(args[i])) {
+                logLevel += 3;
+            } else if (command == null && "-A".equals(args[i])) {
+                agentForward = true;
+            } else if (command == null && "-a".equals(args[i])) {
+                agentForward = false;
+            } else if (command == null && "-i".equals(args[i])) {
+                if (i + 1 >= args.length) {
+                    System.err.println("option requires and argument: " + args[i]);
+                    error = true;
+                    break;
+                }
+                identities.add(args[++i]);
+            } else if (command == null && "-o".equals(args[i])) {
+                if (i + 1 >= args.length) {
+                    System.err.println("option requires and argument: " + args[i]);
+                    error = true;
+                    break;
+                }
+                String opt = args[++i];
+                int idx = opt.indexOf('=');
+                if (idx <= 0) {
+                    System.err.println("bad syntax for option: " + opt);
+                    error = true;
+                    break;
+                }
+                options.put(opt.substring(0, idx), opt.substring(idx + 1));
+            } else if (command == null && args[i].startsWith("-")) {
+                System.err.println("illegal option: " + args[i]);
+                error = true;
+                break;
+            } else {
+                if (command == null && host == null) {
+                    host = args[i];
+                } else {
+                    if (command == null) {
+                        command = new ArrayList<String>();
+                    }
+                    command.add(args[i]);
+                }
+            }
+        }
+        if (host == null) {
+            System.err.println("hostname required");
+            error = true;
+        }
+        if (error) {
+            System.err.println("usage: ssh [-A|-a] [-v[v][v]] [-D socksPort] [-l login] [-p port] [-o option=value] hostname [command]");
+            System.exit(-1);
+        }
+        if (logLevel <= 0) {
+            root.setLevel(Level.WARNING);
+        } else if (logLevel == 1) {
+            root.setLevel(Level.INFO);
+        } else if (logLevel == 2) {
+            root.setLevel(Level.FINE);
+        } else {
+            root.setLevel(Level.FINEST);
+        }
+
+        KeyPairProvider provider = null;
+        final List<String> files = new ArrayList<String>();
+        File f = new File(System.getProperty("user.home"), ".ssh/id_dsa");
+        if (f.exists() && f.isFile() && f.canRead()) {
+            files.add(f.getAbsolutePath());
+        }
+        f = new File(System.getProperty("user.home"), ".ssh/id_rsa");
+        if (f.exists() && f.isFile() && f.canRead()) {
+            files.add(f.getAbsolutePath());
+        }
+        f = new File(System.getProperty("user.home"), ".ssh/id_ecdsa");
+        if (f.exists() && f.isFile() && f.canRead()) {
+            files.add(f.getAbsolutePath());
+        }
+        if (files.size() > 0) {
+            // SSHD-292: we need to use a different class to load the FileKeyPairProvider
+            //  in order to break the link between SshClient and BouncyCastle
+            try {
+                if (SecurityUtils.isBouncyCastleRegistered()) {
+                    class KeyPairProviderLoader implements Callable<KeyPairProvider> {
+                        @Override
+                        public KeyPairProvider call() throws Exception {
+                            return new FileKeyPairProvider(files.toArray(new String[files.size()]), new PasswordFinder() {
+                                @Override
+                                public char[] getPassword() {
+                                    try {
+                                        System.out.println("Enter password for private key: ");
+                                        BufferedReader r = new BufferedReader(new InputStreamReader(System.in));
+                                        String password = r.readLine();
+                                        return password.toCharArray();
+                                    } catch (IOException e) {
+                                        return null;
+                                    }
+                                }
+                            });
+                        }
+                    }
+                    provider = new KeyPairProviderLoader().call();
+                }
+            } catch (Throwable t) {
+                System.out.println("Error loading user keys: " + t.getMessage());
+            }
+        }
+
+        SshClient client = SshClient.setUpDefaultClient();
+        Map<String,Object> props = client.getProperties();
+        props.putAll(options);
+
+        client.start();
+        client.setKeyPairProvider(provider);
+        client.setUserInteraction(new UserInteraction() {
+            @Override
+            public void welcome(String banner) {
+                System.out.println(banner);
+            }
+
+            @Override
+            public String[] interactive(String destination, String name, String instruction, String[] prompt, boolean[] echo) {
+                String[] answers = new String[prompt.length];
+                try {
+                    for (int i = 0; i < prompt.length; i++) {
+                        BufferedReader r = new BufferedReader(new InputStreamReader(System.in));
+                        System.out.print(prompt[i] + " ");
+                        answers[i] = r.readLine();
+                    }
+                } catch (IOException e) {
+                    // ignored
+                }
+                return answers;
+            }
+        });
+
+        /*
+        String authSock = System.getenv(SshAgent.SSH_AUTHSOCKET_ENV_NAME);
+        if (authSock == null && provider != null) {
+            Iterable<KeyPair> keys = provider.loadKeys();
+            AgentServer server = new AgentServer();
+            authSock = server.start();
+            SshAgent agent = new AgentClient(authSock);
+            for (KeyPair key : keys) {
+                agent.addIdentity(key, "");
+            }
+            agent.close();
+            props.put(SshAgent.SSH_AUTHSOCKET_ENV_NAME, authSock);
+        }
+        */
+
+        ClientSession session = client.connect(login, host, port).await().getSession();
+        session.auth().verify();
+
+        if (socksPort >= 0) {
+            session.startDynamicPortForwarding(new SshdSocketAddress("localhost", socksPort));
+            Thread.sleep(Long.MAX_VALUE);
+        } else {
+            ClientChannel channel;
+            if (command == null) {
+                channel = session.createChannel(ClientChannel.CHANNEL_SHELL);
+                ((ChannelShell) channel).setAgentForwarding(agentForward);
+                channel.setIn(new NoCloseInputStream(System.in));
+            } else {
+                StringWriter w = new StringWriter();
+                for (String cmd : command) {
+                    w.append(cmd).append(" ");
+                }
+                w.close();
+                channel = session.createChannel(ClientChannel.CHANNEL_EXEC, w.toString());
+            }
+            channel.setOut(new NoCloseOutputStream(System.out));
+            channel.setErr(new NoCloseOutputStream(System.err));
+            channel.open().await();
+            channel.waitFor(ClientChannel.CLOSED, 0);
+            session.close(false);
+            client.stop();
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/9b98f342/sshd-core/src/main/java/org/apache/sshd/client/UserAuth.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/UserAuth.java b/sshd-core/src/main/java/org/apache/sshd/client/UserAuth.java
index a5dd185..7e8d337 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/UserAuth.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/UserAuth.java
@@ -20,7 +20,7 @@ package org.apache.sshd.client;
 
 import java.util.Collection;
 
-import org.apache.sshd.ClientSession;
+import org.apache.sshd.client.session.ClientSession;
 import org.apache.sshd.common.util.buffer.Buffer;
 
 /**

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/9b98f342/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthKeyboardInteractive.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthKeyboardInteractive.java b/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthKeyboardInteractive.java
index ea8815b..af17b13 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthKeyboardInteractive.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthKeyboardInteractive.java
@@ -27,10 +27,10 @@ import java.util.Collection;
 import java.util.Iterator;
 import java.util.List;
 
-import org.apache.sshd.ClientSession;
 import org.apache.sshd.client.ClientFactoryManager;
 import org.apache.sshd.client.UserAuth;
 import org.apache.sshd.client.UserInteraction;
+import org.apache.sshd.client.session.ClientSession;
 import org.apache.sshd.common.NamedFactory;
 import org.apache.sshd.common.SshConstants;
 import org.apache.sshd.common.util.AbstractLoggingBean;

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/9b98f342/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPassword.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPassword.java b/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPassword.java
index 35844e3..ea3cb8a 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPassword.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPassword.java
@@ -23,8 +23,8 @@ import java.util.Collection;
 import java.util.Iterator;
 import java.util.List;
 
-import org.apache.sshd.ClientSession;
 import org.apache.sshd.client.UserAuth;
+import org.apache.sshd.client.session.ClientSession;
 import org.apache.sshd.common.NamedFactory;
 import org.apache.sshd.common.SshConstants;
 import org.apache.sshd.common.util.AbstractLoggingBean;

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/9b98f342/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPublicKey.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPublicKey.java b/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPublicKey.java
index 9a32e51..6bc90bf 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPublicKey.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPublicKey.java
@@ -28,16 +28,16 @@ import java.util.Collection;
 import java.util.Iterator;
 import java.util.List;
 
-import org.apache.sshd.ClientSession;
 import org.apache.sshd.agent.SshAgent;
 import org.apache.sshd.agent.SshAgentFactory;
 import org.apache.sshd.client.UserAuth;
+import org.apache.sshd.client.session.ClientSession;
 import org.apache.sshd.common.FactoryManager;
 import org.apache.sshd.common.NamedFactory;
-import org.apache.sshd.common.Signature;
 import org.apache.sshd.common.SshConstants;
 import org.apache.sshd.common.keyprovider.KeyPairProvider;
 import org.apache.sshd.common.session.AbstractSession;
+import org.apache.sshd.common.signature.Signature;
 import org.apache.sshd.common.util.AbstractLoggingBean;
 import org.apache.sshd.common.util.buffer.Buffer;
 import org.apache.sshd.common.util.buffer.ByteArrayBuffer;

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/9b98f342/sshd-core/src/main/java/org/apache/sshd/client/channel/AbstractClientChannel.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/channel/AbstractClientChannel.java b/sshd-core/src/main/java/org/apache/sshd/client/channel/AbstractClientChannel.java
index e690667..ddb16e3 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/channel/AbstractClientChannel.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/channel/AbstractClientChannel.java
@@ -23,17 +23,16 @@ import java.io.InputStream;
 import java.io.OutputStream;
 import java.util.concurrent.atomic.AtomicBoolean;
 
-import org.apache.sshd.ClientChannel;
 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.Closeable;
-import org.apache.sshd.common.RequestHandler;
 import org.apache.sshd.common.SshConstants;
 import org.apache.sshd.common.SshException;
 import org.apache.sshd.common.channel.AbstractChannel;
+import org.apache.sshd.common.channel.Channel;
 import org.apache.sshd.common.channel.ChannelAsyncInputStream;
 import org.apache.sshd.common.channel.ChannelAsyncOutputStream;
+import org.apache.sshd.common.channel.RequestHandler;
 import org.apache.sshd.common.io.IoInputStream;
 import org.apache.sshd.common.io.IoOutputStream;
 import org.apache.sshd.common.util.IoUtils;
@@ -68,7 +67,6 @@ public abstract class AbstractClientChannel extends AbstractChannel implements C
     protected String openFailureMsg;
     protected OpenFuture openFuture;
 
-    @SuppressWarnings("synthetic-access")
     protected AbstractClientChannel(String type) {
         this.type = type;
         this.streaming = Streaming.Sync;
@@ -331,10 +329,14 @@ public abstract class AbstractClientChannel extends AbstractChannel implements C
     }
 
     private class ExitStatusChannelRequestHandler implements RequestHandler<Channel> {
+        public ExitStatusChannelRequestHandler() {
+            super();
+        }
+
         @SuppressWarnings("synthetic-access")
         @Override
         public Result process(Channel channel, String request, boolean wantReply, Buffer buffer) throws Exception {
-            if (request.equals("exit-status")) {
+            if ("exit-status".equals(request)) {
                 exitStatus = Integer.valueOf(buffer.getInt());
                 notifyStateChanged();
                 return Result.ReplySuccess;
@@ -344,10 +346,14 @@ public abstract class AbstractClientChannel extends AbstractChannel implements C
     }
 
     private class ExitSignalChannelRequestHandler implements RequestHandler<Channel> {
+        public ExitSignalChannelRequestHandler() {
+            super();
+        }
+
         @SuppressWarnings("synthetic-access")
         @Override
         public Result process(Channel channel, String request, boolean wantReply, Buffer buffer) throws Exception {
-            if (request.equals("exit-signal")) {
+            if ("exit-signal".equals(request)) {
                 exitSignal = buffer.getString();
                 notifyStateChanged();
                 return Result.ReplySuccess;

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/9b98f342/sshd-core/src/main/java/org/apache/sshd/client/channel/ClientChannel.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/channel/ClientChannel.java b/sshd-core/src/main/java/org/apache/sshd/client/channel/ClientChannel.java
new file mode 100644
index 0000000..d897fe1
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/channel/ClientChannel.java
@@ -0,0 +1,103 @@
+/*
+ * 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.channel;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.channels.Channel;
+
+import org.apache.sshd.client.future.OpenFuture;
+import org.apache.sshd.common.future.CloseFuture;
+import org.apache.sshd.common.io.IoInputStream;
+import org.apache.sshd.common.io.IoOutputStream;
+
+/**
+ * A client channel used to communicate with
+ * the SSH server.  Client channels can be shells,
+ * simple commands or subsystems
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public interface ClientChannel extends Channel {
+
+    String CHANNEL_EXEC = "exec";
+    String CHANNEL_SHELL = "shell";
+    String CHANNEL_SUBSYSTEM = "subsystem";
+
+    int TIMEOUT =     0x0001;
+    int CLOSED =      0x0002;
+    int STDOUT_DATA = 0x0004;
+    int STDERR_DATA = 0x0008;
+    int EOF =         0x0010;
+    int EXIT_STATUS = 0x0020;
+    int EXIT_SIGNAL = 0x0040;
+    int OPENED =      0x0080;
+
+    enum Streaming {
+        Async,
+        Sync
+    }
+
+    Streaming getStreaming();
+
+    void setStreaming(Streaming streaming);
+
+    IoOutputStream getAsyncIn();
+
+    IoInputStream getAsyncOut();
+
+    IoInputStream getAsyncErr();
+
+    /**
+     * Access to an output stream to send data directly to the remote channel.
+     * This can be used instead of using {@link #setIn(java.io.InputStream)} method
+     * and having the channel polling for data in that stream.
+     *
+     * @return an OutputStream to be used to send data
+     */
+    OutputStream getInvertedIn();
+
+    InputStream getInvertedOut();
+
+    InputStream getInvertedErr();
+
+    /**
+     * Set an input stream that will be read by this channel and forwarded to
+     * the remote channel.  Note that using such a stream will create an additional
+     * thread for pumping the stream which will only be able to end when that stream
+     * is actually closed or some data is read.  It is recommended to use the
+     * {@link #getInvertedIn()} method instead and write data directly.
+     *
+     * @param in an InputStream to be polled and forwarded
+     */
+    void setIn(InputStream in);
+
+    void setOut(OutputStream out);
+
+    void setErr(OutputStream err);
+
+    OpenFuture open() throws IOException;
+
+    int waitFor(int mask, long timeout);
+
+    CloseFuture close(boolean immediately);
+
+    Integer getExitStatus();
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/9b98f342/sshd-core/src/main/java/org/apache/sshd/client/channel/PtyCapableChannelSession.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/channel/PtyCapableChannelSession.java b/sshd-core/src/main/java/org/apache/sshd/client/channel/PtyCapableChannelSession.java
index a345b8b..2c2b50b 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/channel/PtyCapableChannelSession.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/channel/PtyCapableChannelSession.java
@@ -23,10 +23,10 @@ import java.util.HashMap;
 import java.util.LinkedHashMap;
 import java.util.Map;
 
-import org.apache.sshd.common.PtyMode;
 import org.apache.sshd.common.SshConstants;
+import org.apache.sshd.common.channel.PtyMode;
+import org.apache.sshd.common.channel.SttySupport;
 import org.apache.sshd.common.util.OsUtils;
-import org.apache.sshd.common.util.SttySupport;
 import org.apache.sshd.common.util.buffer.Buffer;
 import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
 

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/9b98f342/sshd-core/src/main/java/org/apache/sshd/client/future/ConnectFuture.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/future/ConnectFuture.java b/sshd-core/src/main/java/org/apache/sshd/client/future/ConnectFuture.java
index b2f8da6..649bde8 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/future/ConnectFuture.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/future/ConnectFuture.java
@@ -18,7 +18,7 @@
  */
 package org.apache.sshd.client.future;
 
-import org.apache.sshd.ClientSession;
+import org.apache.sshd.client.session.ClientSession;
 import org.apache.sshd.common.future.SshFuture;
 
 /**

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/9b98f342/sshd-core/src/main/java/org/apache/sshd/client/future/DefaultConnectFuture.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/future/DefaultConnectFuture.java b/sshd-core/src/main/java/org/apache/sshd/client/future/DefaultConnectFuture.java
index 547890c..9dd3a12 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/future/DefaultConnectFuture.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/future/DefaultConnectFuture.java
@@ -18,7 +18,7 @@
  */
 package org.apache.sshd.client.future;
 
-import org.apache.sshd.ClientSession;
+import org.apache.sshd.client.session.ClientSession;
 import org.apache.sshd.common.RuntimeSshException;
 import org.apache.sshd.common.future.DefaultSshFuture;
 

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/9b98f342/sshd-core/src/main/java/org/apache/sshd/client/kex/DHGClient.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/kex/DHGClient.java b/sshd-core/src/main/java/org/apache/sshd/client/kex/DHGClient.java
index 6efe31a..1893a4b 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/kex/DHGClient.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/kex/DHGClient.java
@@ -18,15 +18,15 @@
  */
 package org.apache.sshd.client.kex;
 
-import org.apache.sshd.common.KeyExchange;
 import org.apache.sshd.common.NamedFactory;
-import org.apache.sshd.common.Signature;
 import org.apache.sshd.common.SshConstants;
 import org.apache.sshd.common.SshException;
 import org.apache.sshd.common.config.keys.KeyUtils;
 import org.apache.sshd.common.kex.AbstractDH;
 import org.apache.sshd.common.kex.DHFactory;
+import org.apache.sshd.common.kex.KeyExchange;
 import org.apache.sshd.common.session.AbstractSession;
+import org.apache.sshd.common.signature.Signature;
 import org.apache.sshd.common.util.buffer.Buffer;
 import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
 

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/9b98f342/sshd-core/src/main/java/org/apache/sshd/client/kex/DHGEXClient.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/kex/DHGEXClient.java b/sshd-core/src/main/java/org/apache/sshd/client/kex/DHGEXClient.java
index afe5269..12d4f08 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/kex/DHGEXClient.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/kex/DHGEXClient.java
@@ -21,15 +21,15 @@ package org.apache.sshd.client.kex;
 
 import java.math.BigInteger;
 
-import org.apache.sshd.common.KeyExchange;
 import org.apache.sshd.common.NamedFactory;
-import org.apache.sshd.common.Signature;
 import org.apache.sshd.common.SshConstants;
 import org.apache.sshd.common.SshException;
 import org.apache.sshd.common.config.keys.KeyUtils;
 import org.apache.sshd.common.kex.AbstractDH;
 import org.apache.sshd.common.kex.DHFactory;
+import org.apache.sshd.common.kex.KeyExchange;
 import org.apache.sshd.common.session.AbstractSession;
+import org.apache.sshd.common.signature.Signature;
 import org.apache.sshd.common.util.buffer.Buffer;
 import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
 

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/9b98f342/sshd-core/src/main/java/org/apache/sshd/client/keyverifier/DelegatingServerKeyVerifier.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/keyverifier/DelegatingServerKeyVerifier.java b/sshd-core/src/main/java/org/apache/sshd/client/keyverifier/DelegatingServerKeyVerifier.java
index 6bdbdc7..6c58647 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/keyverifier/DelegatingServerKeyVerifier.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/keyverifier/DelegatingServerKeyVerifier.java
@@ -22,8 +22,8 @@ import java.net.SocketAddress;
 import java.security.PublicKey;
 import java.util.Map;
 
-import org.apache.sshd.ClientSession;
 import org.apache.sshd.client.ServerKeyVerifier;
+import org.apache.sshd.client.session.ClientSession;
 import org.apache.sshd.common.util.AbstractLoggingBean;
 
 /*

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/9b98f342/sshd-core/src/main/java/org/apache/sshd/client/keyverifier/RequiredServerKeyVerifier.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/keyverifier/RequiredServerKeyVerifier.java b/sshd-core/src/main/java/org/apache/sshd/client/keyverifier/RequiredServerKeyVerifier.java
index 4543546..8342eb9 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/keyverifier/RequiredServerKeyVerifier.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/keyverifier/RequiredServerKeyVerifier.java
@@ -21,8 +21,8 @@ package org.apache.sshd.client.keyverifier;
 import java.net.SocketAddress;
 import java.security.PublicKey;
 
-import org.apache.sshd.ClientSession;
 import org.apache.sshd.client.ServerKeyVerifier;
+import org.apache.sshd.client.session.ClientSession;
 import org.apache.sshd.common.util.AbstractLoggingBean;
 import org.apache.sshd.common.util.buffer.BufferUtils;
 

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/9b98f342/sshd-core/src/main/java/org/apache/sshd/client/keyverifier/StaticServerKeyVerifier.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/keyverifier/StaticServerKeyVerifier.java b/sshd-core/src/main/java/org/apache/sshd/client/keyverifier/StaticServerKeyVerifier.java
index 9ebf0d4..f80e82b 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/keyverifier/StaticServerKeyVerifier.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/keyverifier/StaticServerKeyVerifier.java
@@ -22,8 +22,8 @@ package org.apache.sshd.client.keyverifier;
 import java.net.SocketAddress;
 import java.security.PublicKey;
 
-import org.apache.sshd.ClientSession;
 import org.apache.sshd.client.ServerKeyVerifier;
+import org.apache.sshd.client.session.ClientSession;
 import org.apache.sshd.common.config.keys.KeyUtils;
 import org.apache.sshd.common.util.AbstractLoggingBean;
 

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/9b98f342/sshd-core/src/main/java/org/apache/sshd/client/scp/DefaultScpClient.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/scp/DefaultScpClient.java b/sshd-core/src/main/java/org/apache/sshd/client/scp/DefaultScpClient.java
index c4a977a..b7d0990 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/scp/DefaultScpClient.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/scp/DefaultScpClient.java
@@ -29,8 +29,8 @@ import java.util.Collection;
 import java.util.Collections;
 import java.util.EnumSet;
 
-import org.apache.sshd.ClientSession;
 import org.apache.sshd.client.channel.ChannelExec;
+import org.apache.sshd.client.session.ClientSession;
 import org.apache.sshd.common.FactoryManager;
 import org.apache.sshd.common.file.FileSystemFactory;
 import org.apache.sshd.common.file.util.MockFileSystem;

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/9b98f342/sshd-core/src/main/java/org/apache/sshd/client/session/ClientConnectionService.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/session/ClientConnectionService.java b/sshd-core/src/main/java/org/apache/sshd/client/session/ClientConnectionService.java
index 10654d8..1ff7cb3 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/session/ClientConnectionService.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/session/ClientConnectionService.java
@@ -27,10 +27,10 @@ import org.apache.sshd.common.FactoryManager;
 import org.apache.sshd.common.FactoryManagerUtils;
 import org.apache.sshd.common.Service;
 import org.apache.sshd.common.ServiceFactory;
-import org.apache.sshd.common.Session;
 import org.apache.sshd.common.SshConstants;
 import org.apache.sshd.common.SshException;
 import org.apache.sshd.common.session.AbstractConnectionService;
+import org.apache.sshd.common.session.Session;
 import org.apache.sshd.common.util.buffer.Buffer;
 
 /**