BUG-1612 Remove ganymed third party ssh lib (replaced by mina ssh) 97/11997/7
authorMaros Marsalek <mmarsale@cisco.com>
Thu, 16 Oct 2014 06:10:07 +0000 (08:10 +0200)
committerTony Tkacik <ttkacik@cisco.com>
Mon, 27 Oct 2014 09:17:54 +0000 (09:17 +0000)
Change-Id: I8b1a0281161f29345f1ee1af646a5fca504ad823
Signed-off-by: Maros Marsalek <mmarsale@cisco.com>
14 files changed:
features/base/pom.xml
features/base/src/main/resources/features.xml
features/netconf/pom.xml
features/netconf/src/main/resources/features.xml
opendaylight/commons/opendaylight/pom.xml
opendaylight/distribution/opendaylight/pom.xml
opendaylight/md-sal/sal-binding-it/src/main/java/org/opendaylight/controller/test/sal/binding/it/TestHelper.java
opendaylight/netconf/netconf-netty-util/pom.xml
opendaylight/netconf/netconf-ssh/pom.xml
pom.xml
third-party/ganymed/pom.xml [deleted file]
third-party/ganymed/src/main/java/ch/ethz/ssh2/Connection.java [deleted file]
third-party/ganymed/src/main/java/ch/ethz/ssh2/channel/ChannelManager.java [deleted file]
third-party/ganymed/src/main/java/ch/ethz/ssh2/transport/TransportManager.java [deleted file]

index b7ab3ca75774c0c4e8875893adf418c619267b55..cd84eeaf3395df9718dad12e9e9c006d82d39d04 100644 (file)
       <groupId>org.opendaylight.controller</groupId>
       <artifactId>karaf-tomcat-security</artifactId>
     </dependency>
       <groupId>org.opendaylight.controller</groupId>
       <artifactId>karaf-tomcat-security</artifactId>
     </dependency>
-    <dependency>
-      <groupId>org.opendaylight.controller.thirdparty</groupId>
-      <artifactId>ganymed</artifactId>
-    </dependency>
     <dependency>
       <groupId>com.fasterxml.jackson.core</groupId>
       <artifactId>jackson-annotations</artifactId>
     <dependency>
       <groupId>com.fasterxml.jackson.core</groupId>
       <artifactId>jackson-annotations</artifactId>
index d7d8e0ddacfbbf851741dfe18312452606d4ecec..d6802acd0e909615a5009acbfc859bc8924b5404 100644 (file)
@@ -36,7 +36,6 @@
       <bundle>wrap:mvn:io.netty/netty-common/${netty.version}</bundle>
       <bundle>wrap:mvn:io.netty/netty-handler/${netty.version}</bundle>
       <bundle>wrap:mvn:io.netty/netty-codec-http/${netty.version}</bundle>
       <bundle>wrap:mvn:io.netty/netty-common/${netty.version}</bundle>
       <bundle>wrap:mvn:io.netty/netty-handler/${netty.version}</bundle>
       <bundle>wrap:mvn:io.netty/netty-codec-http/${netty.version}</bundle>
-      <bundle>mvn:org.opendaylight.controller.thirdparty/ganymed/1.2.0-SNAPSHOT</bundle>
    </feature>
    <feature name="odl-base-jersey" description="Jersey" version="${jersey.version}">
       <feature>odl-base-gemini-web</feature>
    </feature>
    <feature name="odl-base-jersey" description="Jersey" version="${jersey.version}">
       <feature>odl-base-gemini-web</feature>
index a944bb4dec86f3175ccb2ff6f501d8afb947af81..028c16b02f9058ea7fd1ecb289c133735e3bdee3 100644 (file)
       <groupId>org.opendaylight.controller</groupId>
       <artifactId>netconf-netty-util</artifactId>
     </dependency>
       <groupId>org.opendaylight.controller</groupId>
       <artifactId>netconf-netty-util</artifactId>
     </dependency>
-    <dependency>
-      <groupId>org.opendaylight.controller.thirdparty</groupId>
-      <artifactId>ganymed</artifactId>
-    </dependency>
     <dependency>
       <groupId>org.apache.sshd</groupId>
       <artifactId>sshd-core</artifactId>
     <dependency>
       <groupId>org.apache.sshd</groupId>
       <artifactId>sshd-core</artifactId>
index 444f20865b565d48d1dd2e55d6b3362db051cf76..fb668ae15adb788c1d5c718fb70968cc46f05196 100644 (file)
@@ -57,7 +57,6 @@
     <feature version='${project.version}'>odl-netconf-mapping-api</feature>
     <feature version='${project.version}'>odl-netconf-util</feature>
     <bundle>mvn:org.opendaylight.controller/netconf-netty-util/${project.version}</bundle>
     <feature version='${project.version}'>odl-netconf-mapping-api</feature>
     <feature version='${project.version}'>odl-netconf-util</feature>
     <bundle>mvn:org.opendaylight.controller/netconf-netty-util/${project.version}</bundle>
-    <bundle>mvn:org.opendaylight.controller.thirdparty/ganymed/${ganymed.version}</bundle>
     <bundle>mvn:org.apache.sshd/sshd-core/${sshd-core.version}</bundle>
     <bundle>mvn:org.openexi/nagasena/${exi.nagasena.version}</bundle>
     <bundle>mvn:io.netty/netty-codec/${netty.version}</bundle>
     <bundle>mvn:org.apache.sshd/sshd-core/${sshd-core.version}</bundle>
     <bundle>mvn:org.openexi/nagasena/${exi.nagasena.version}</bundle>
     <bundle>mvn:io.netty/netty-codec/${netty.version}</bundle>
index ffb9ef746da4118982b6ed61a715024491a00a72..4dfe7dbb4188a930234b3d868eb4484d4cfca851 100644 (file)
     <forwarding.staticrouting.northbound.version>0.5.0-SNAPSHOT</forwarding.staticrouting.northbound.version>
     <forwardingrulesmanager.implementation.version>0.5.0-SNAPSHOT</forwardingrulesmanager.implementation.version>
     <forwardingrulesmanager.version>0.7.0-SNAPSHOT</forwardingrulesmanager.version>
     <forwarding.staticrouting.northbound.version>0.5.0-SNAPSHOT</forwarding.staticrouting.northbound.version>
     <forwardingrulesmanager.implementation.version>0.5.0-SNAPSHOT</forwardingrulesmanager.implementation.version>
     <forwardingrulesmanager.version>0.7.0-SNAPSHOT</forwardingrulesmanager.version>
-    <ganymed.version>1.2.0-SNAPSHOT</ganymed.version>
     <hosttracker.api.version>0.6.0-SNAPSHOT</hosttracker.api.version>
     <hosttracker.implementation.version>0.6.0-SNAPSHOT</hosttracker.implementation.version>
     <hosttracker.northbound.version>0.5.0-SNAPSHOT</hosttracker.northbound.version>
     <hosttracker.api.version>0.6.0-SNAPSHOT</hosttracker.api.version>
     <hosttracker.implementation.version>0.6.0-SNAPSHOT</hosttracker.implementation.version>
     <hosttracker.northbound.version>0.5.0-SNAPSHOT</hosttracker.northbound.version>
     <sonar.language>java</sonar.language>
     <sonar.jacoco.reportPath>target/code-coverage/jacoco.exec</sonar.jacoco.reportPath>
     <sonar.jacoco.itReportPath>target/code-coverage/jacoco-it.exec</sonar.jacoco.itReportPath>
     <sonar.language>java</sonar.language>
     <sonar.jacoco.reportPath>target/code-coverage/jacoco.exec</sonar.jacoco.reportPath>
     <sonar.jacoco.itReportPath>target/code-coverage/jacoco-it.exec</sonar.jacoco.itReportPath>
-    <sonar.skippedModules>org.openflow.openflowj,net.sf.jung2,org.opendaylight.controller.protobuff.messages,ch.ethz.ssh2</sonar.skippedModules>
+    <sonar.skippedModules>org.openflow.openflowj,net.sf.jung2,org.opendaylight.controller.protobuff.messages</sonar.skippedModules>
     <sonar.profile>Sonar way with Findbugs</sonar.profile>
     <spifly.version>1.0.0</spifly.version>
     <spring-osgi.version>1.2.1</spring-osgi.version>
     <sonar.profile>Sonar way with Findbugs</sonar.profile>
     <spifly.version>1.0.0</spifly.version>
     <spring-osgi.version>1.2.1</spring-osgi.version>
         <artifactId>com.sun.jersey.jersey-servlet</artifactId>
         <version>${jersey-servlet.version}</version>
       </dependency>
         <artifactId>com.sun.jersey.jersey-servlet</artifactId>
         <version>${jersey-servlet.version}</version>
       </dependency>
-      <dependency>
-        <groupId>org.opendaylight.controller.thirdparty</groupId>
-        <artifactId>ganymed</artifactId>
-        <version>${ganymed.version}</version>
-      </dependency>
       <!-- Third parties from opendaylight released -->
       <dependency>
         <groupId>org.opendaylight.controller.thirdparty</groupId>
       <!-- Third parties from opendaylight released -->
       <dependency>
         <groupId>org.opendaylight.controller.thirdparty</groupId>
index e30ff05bf0fde541c3c55210bed47c5190c1b376..93be88b4ba381a7da18d3826ddca382d64079960 100644 (file)
           <artifactId>sample-toaster-provider</artifactId>
           <version>${mdsal.version}</version>
         </dependency>
           <artifactId>sample-toaster-provider</artifactId>
           <version>${mdsal.version}</version>
         </dependency>
-        <dependency>
-          <groupId>org.opendaylight.controller.thirdparty</groupId>
-          <artifactId>ganymed</artifactId>
-        </dependency>
         <dependency>
           <groupId>org.apache.sshd</groupId>
           <artifactId>sshd-core</artifactId>
         <dependency>
           <groupId>org.apache.sshd</groupId>
           <artifactId>sshd-core</artifactId>
index efd35ccfa606d298834cb0eaa05a4d5d393a825a..f7313f4ce703cab84da3b23503615b3c4e2d86c3 100644 (file)
@@ -76,7 +76,6 @@ public class TestHelper {
                 mavenBundle("org.apache.sshd", "sshd-core").versionAsInProject(), //
                 mavenBundle("org.openexi", "nagasena").versionAsInProject(), //
                 mavenBundle("org.openexi", "nagasena-rta").versionAsInProject(), //
                 mavenBundle("org.apache.sshd", "sshd-core").versionAsInProject(), //
                 mavenBundle("org.openexi", "nagasena").versionAsInProject(), //
                 mavenBundle("org.openexi", "nagasena-rta").versionAsInProject(), //
-                mavenBundle(CONTROLLER + ".thirdparty", "ganymed").versionAsInProject(), //
                 mavenBundle(CONTROLLER, "netconf-mapping-api").versionAsInProject(), //
 
                 mavenBundle(CONTROLLER, "config-persister-impl").versionAsInProject(), //
                 mavenBundle(CONTROLLER, "netconf-mapping-api").versionAsInProject(), //
 
                 mavenBundle(CONTROLLER, "config-persister-impl").versionAsInProject(), //
index e2afcc42f54f317d19490a7f9edfe864e9907acf..a9c1e8336d62419a79f6d320cd0784ecc8dc37cb 100644 (file)
       <groupId>org.opendaylight.controller</groupId>
       <artifactId>protocol-framework</artifactId>
     </dependency>
       <groupId>org.opendaylight.controller</groupId>
       <artifactId>protocol-framework</artifactId>
     </dependency>
-    <dependency>
-      <groupId>org.opendaylight.controller.thirdparty</groupId>
-      <artifactId>ganymed</artifactId>
-    </dependency>
     <dependency>
       <groupId>org.apache.sshd</groupId>
       <artifactId>sshd-core</artifactId>
     <dependency>
       <groupId>org.apache.sshd</groupId>
       <artifactId>sshd-core</artifactId>
@@ -89,7 +85,7 @@
         <artifactId>maven-bundle-plugin</artifactId>
         <configuration>
           <instructions>
         <artifactId>maven-bundle-plugin</artifactId>
         <configuration>
           <instructions>
-            <Import-Package>org.apache.sshd.*, ch.ethz.ssh2, com.google.common.base, com.google.common.collect, io.netty.buffer,
+            <Import-Package>org.apache.sshd.*, com.google.common.base, com.google.common.collect, io.netty.buffer,
               io.netty.channel, io.netty.channel.socket, io.netty.handler.codec, io.netty.handler.ssl, io.netty.util,
               io.netty.util.concurrent, javax.xml.transform, javax.xml.transform.dom, javax.xml.transform.sax,
               javax.xml.transform.stream, org.opendaylight.controller.netconf.api,
               io.netty.channel, io.netty.channel.socket, io.netty.handler.codec, io.netty.handler.ssl, io.netty.util,
               io.netty.util.concurrent, javax.xml.transform, javax.xml.transform.dom, javax.xml.transform.sax,
               javax.xml.transform.stream, org.opendaylight.controller.netconf.api,
index 78453b177037d88b91945e8138bf0bdcd541d8b9..e0c7dba4fa4945f555f5271f0bef8ab096aa8c1d 100644 (file)
       <groupId>org.bouncycastle</groupId>
       <artifactId>bcprov-jdk15on</artifactId>
     </dependency>
       <groupId>org.bouncycastle</groupId>
       <artifactId>bcprov-jdk15on</artifactId>
     </dependency>
-    <dependency>
-      <groupId>org.opendaylight.controller.thirdparty</groupId>
-      <artifactId>ganymed</artifactId>
-    </dependency>
     <dependency>
       <groupId>org.apache.sshd</groupId>
       <artifactId>sshd-core</artifactId>
     <dependency>
       <groupId>org.apache.sshd</groupId>
       <artifactId>sshd-core</artifactId>
diff --git a/pom.xml b/pom.xml
index bb8ad1dbeba6459a1b9e5acb90070febc1b5a72a..53ef5601bb357de5ed1c8061a9433ef9211e4769 100644 (file)
--- a/pom.xml
+++ b/pom.xml
@@ -53,8 +53,7 @@
     <!-- <module>third-party/net.sf.jung2</module> -->
     <!-- <module>third-party/jersey-servlet</module> -->
     <!-- <module>third-party/org.apache.catalina.filters.CorsFilter</module> -->
     <!-- <module>third-party/net.sf.jung2</module> -->
     <!-- <module>third-party/jersey-servlet</module> -->
     <!-- <module>third-party/org.apache.catalina.filters.CorsFilter</module> -->
-    <module>third-party/ganymed</module>
-
+    
     <module>third-party/commons/thirdparty</module>
 
     <!-- SAL bundles -->
     <module>third-party/commons/thirdparty</module>
 
     <!-- SAL bundles -->
diff --git a/third-party/ganymed/pom.xml b/third-party/ganymed/pom.xml
deleted file mode 100644 (file)
index 676e2a2..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-    <modelVersion>4.0.0</modelVersion>
-
-    <parent>
-        <groupId>org.opendaylight.controller</groupId>
-        <artifactId>commons.thirdparty</artifactId>
-        <version>1.2.0-SNAPSHOT</version>
-        <relativePath>../commons/thirdparty</relativePath>
-    </parent>
-
-    <groupId>org.opendaylight.controller.thirdparty</groupId>
-    <artifactId>ganymed</artifactId>
-    <version>1.2.0-SNAPSHOT</version>
-    <packaging>bundle</packaging>
-
-    <dependencies>
-        <dependency>
-            <groupId>org.osgi</groupId>
-            <artifactId>org.osgi.core</artifactId>
-            <version>5.0.0</version>
-        </dependency>
-        <dependency>
-            <groupId>ch.ethz.ganymed</groupId>
-            <artifactId>ganymed-ssh2</artifactId>
-            <version>261</version>
-        </dependency>
-    </dependencies>
-
-    <build>
-        <plugins>
-            <plugin>
-                <groupId>org.apache.felix</groupId>
-                <artifactId>maven-bundle-plugin</artifactId>
-                <extensions>true</extensions>
-                <configuration>
-                    <instructions>
-                        <Export-Package>ch.ethz.ssh2.*</Export-Package>
-                        <Embed-Dependency>ganymed-ssh2;scope=compile</Embed-Dependency>
-                        <Embed-Transitive>true</Embed-Transitive>
-                    </instructions>
-                </configuration>
-            </plugin>
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-enforcer-plugin</artifactId>
-                <version>${enforcer.version}</version>
-                <executions>
-                    <execution>
-                        <id>enforce-no-snapshots</id>
-                        <goals>
-                            <goal>enforce</goal>
-                        </goals>
-                        <configuration>
-                            <rules>
-                                <bannedDependencies>
-                                    <excludes>
-                                        <exclude>ch.ethz.ganymed:ganymed-ssh2:*</exclude>
-                                    </excludes>
-                                    <includes>
-                                        <include>ch.ethz.ganymed:ganymed-ssh2:[261]</include>
-                                    </includes>
-                                </bannedDependencies>
-                            </rules>
-                        </configuration>
-                    </execution>
-                </executions>
-            </plugin>
-        </plugins>
-    </build>
-</project>
-
-
diff --git a/third-party/ganymed/src/main/java/ch/ethz/ssh2/Connection.java b/third-party/ganymed/src/main/java/ch/ethz/ssh2/Connection.java
deleted file mode 100644 (file)
index aa13c40..0000000
+++ /dev/null
@@ -1,1424 +0,0 @@
-/*
- * Copyright (c) 2006-2011 Christian Plattner. All rights reserved.
- * Please refer to the LICENSE.txt for licensing details.
- */
-
-package ch.ethz.ssh2;
-
-import java.io.CharArrayWriter;
-import java.io.File;
-import java.net.Socket;
-import java.io.FileReader;
-import java.io.IOException;
-import java.net.InetSocketAddress;
-import java.net.SocketTimeoutException;
-import java.security.SecureRandom;
-import java.util.List;
-import java.util.Vector;
-
-import ch.ethz.ssh2.auth.AuthenticationManager;
-import ch.ethz.ssh2.channel.ChannelManager;
-import ch.ethz.ssh2.crypto.CryptoWishList;
-import ch.ethz.ssh2.crypto.cipher.BlockCipherFactory;
-import ch.ethz.ssh2.crypto.digest.MAC;
-import ch.ethz.ssh2.packets.PacketIgnore;
-import ch.ethz.ssh2.transport.KexManager;
-import ch.ethz.ssh2.transport.TransportManager;
-import ch.ethz.ssh2.util.TimeoutService;
-import ch.ethz.ssh2.util.TimeoutService.TimeoutToken;
-
-/**
- * A <code>Connection</code> is used to establish an encrypted TCP/IP
- * connection to a SSH-2 server.
- * <p>
- * Typically, one
- * <ol>
- * <li>creates a {@link #Connection(String) Connection} object.</li>
- * <li>calls the {@link #connect() connect()} method.</li>
- * <li>calls some of the authentication methods (e.g., {@link #authenticateWithPublicKey(String, File, String) authenticateWithPublicKey()}).</li>
- * <li>calls one or several times the {@link #openSession() openSession()} method.</li>
- * <li>finally, one must close the connection and release resources with the {@link #close() close()} method.</li>
- * </ol>
- *
- * @author Christian Plattner
- * @version $Id: Connection.java 69 2013-08-09 06:39:56Z dkocher@sudo.ch $
- */
-
-public class Connection
-{
-    /**
-     * The identifier presented to the SSH-2 server. This is the same
-     * as the "softwareversion" defined in RFC 4253.
-     * <p/>
-     * <b>NOTE: As per the RFC, the "softwareversion" string MUST consist of printable
-     * US-ASCII characters, with the exception of whitespace characters and the minus sign (-).</b>
-     */
-    private String softwareversion = String.format("Ganymed_%s", Version.getSpecification());
-
-       /* Will be used to generate all random data needed for the current connection.
-        * Note: SecureRandom.nextBytes() is thread safe.
-        */
-
-    private SecureRandom generator;
-
-    private Socket precreatedSocket;
-
-    public Connection(Socket socket) {
-        this.precreatedSocket = socket;
-        this.hostname = socket.getInetAddress().getHostName();
-        this.port = socket.getPort();
-    }
-
-    /**
-     * Unless you know what you are doing, you will never need this.
-     *
-     * @return The list of supported cipher algorithms by this implementation.
-     */
-    public static synchronized String[] getAvailableCiphers()
-    {
-        return BlockCipherFactory.getDefaultCipherList();
-    }
-
-    /**
-     * Unless you know what you are doing, you will never need this.
-     *
-     * @return The list of supported MAC algorthims by this implementation.
-     */
-    public static synchronized String[] getAvailableMACs()
-    {
-        return MAC.getMacList();
-    }
-
-    /**
-     * Unless you know what you are doing, you will never need this.
-     *
-     * @return The list of supported server host key algorthims by this implementation.
-     */
-    public static synchronized String[] getAvailableServerHostKeyAlgorithms()
-    {
-        return KexManager.getDefaultServerHostkeyAlgorithmList();
-    }
-
-    private AuthenticationManager am;
-
-    private boolean authenticated = false;
-    private ChannelManager cm;
-
-    private CryptoWishList cryptoWishList = new CryptoWishList();
-
-    private DHGexParameters dhgexpara = new DHGexParameters();
-
-    private final String hostname;
-
-    private final int port;
-
-    private TransportManager tm;
-
-    private boolean tcpNoDelay = false;
-
-    private ProxyData proxyData = null;
-
-    private List<ConnectionMonitor> connectionMonitors = new Vector<ConnectionMonitor>();
-
-    /**
-     * Prepares a fresh <code>Connection</code> object which can then be used
-     * to establish a connection to the specified SSH-2 server.
-     * <p>
-     * Same as {@link #Connection(String, int) Connection(hostname, 22)}.
-     *
-     * @param hostname the hostname of the SSH-2 server.
-     */
-    public Connection(String hostname)
-    {
-        this(hostname, 22);
-    }
-
-    /**
-     * Prepares a fresh <code>Connection</code> object which can then be used
-     * to establish a connection to the specified SSH-2 server.
-     *
-     * @param hostname
-     *            the host where we later want to connect to.
-     * @param port
-     *            port on the server, normally 22.
-     */
-    public Connection(String hostname, int port)
-    {
-        this.hostname = hostname;
-        this.port = port;
-    }
-
-    /**
-     * Prepares a fresh <code>Connection</code> object which can then be used
-     * to establish a connection to the specified SSH-2 server.
-     *
-     * @param hostname
-     *            the host where we later want to connect to.
-     * @param port
-     *            port on the server, normally 22.
-     * @param softwareversion
-     *                         Allows you to set a custom "softwareversion" string as defined in RFC 4253.
-     *                         <b>NOTE: As per the RFC, the "softwareversion" string MUST consist of printable
-     *          US-ASCII characters, with the exception of whitespace characters and the minus sign (-).</b>
-     */
-    public Connection(String hostname, int port, String softwareversion)
-    {
-        this.hostname = hostname;
-        this.port = port;
-        this.softwareversion = softwareversion;
-    }
-
-    /**
-     * After a successful connect, one has to authenticate oneself. This method
-     * is based on DSA (it uses DSA to sign a challenge sent by the server).
-     * <p>
-     * If the authentication phase is complete, <code>true</code> will be
-     * returned. If the server does not accept the request (or if further
-     * authentication steps are needed), <code>false</code> is returned and
-     * one can retry either by using this or any other authentication method
-     * (use the <code>getRemainingAuthMethods</code> method to get a list of
-     * the remaining possible methods).
-     *
-     * @param user
-     *            A <code>String</code> holding the username.
-     * @param pem
-     *            A <code>String</code> containing the DSA private key of the
-     *            user in OpenSSH key format (PEM, you can't miss the
-     *            "-----BEGIN DSA PRIVATE KEY-----" tag). The string may contain
-     *            linefeeds.
-     * @param password
-     *            If the PEM string is 3DES encrypted ("DES-EDE3-CBC"), then you
-     *            must specify the password. Otherwise, this argument will be
-     *            ignored and can be set to <code>null</code>.
-     *
-     * @return whether the connection is now authenticated.
-     * @throws IOException
-     *
-     * @deprecated You should use one of the {@link #authenticateWithPublicKey(String, File, String) authenticateWithPublicKey()}
-     *                       methods, this method is just a wrapper for it and will
-     *            disappear in future builds.
-     *
-     */
-    public synchronized boolean authenticateWithDSA(String user, String pem, String password) throws IOException
-    {
-        if (tm == null)
-            throw new IllegalStateException("Connection is not established!");
-
-        if (authenticated)
-            throw new IllegalStateException("Connection is already authenticated!");
-
-        if (am == null)
-            am = new AuthenticationManager(tm);
-
-        if (cm == null)
-            cm = new ChannelManager(tm);
-
-        if (user == null)
-            throw new IllegalArgumentException("user argument is null");
-
-        if (pem == null)
-            throw new IllegalArgumentException("pem argument is null");
-
-        authenticated = am.authenticatePublicKey(user, pem.toCharArray(), password, getOrCreateSecureRND());
-
-        return authenticated;
-    }
-
-    /**
-     * A wrapper that calls {@link #authenticateWithKeyboardInteractive(String, String[], InteractiveCallback)
-     * authenticateWithKeyboardInteractivewith} a <code>null</code> submethod list.
-     *
-     * @param user
-     *            A <code>String</code> holding the username.
-     * @param cb
-     *            An <code>InteractiveCallback</code> which will be used to
-     *            determine the responses to the questions asked by the server.
-     * @return whether the connection is now authenticated.
-     * @throws IOException
-     */
-    public synchronized boolean authenticateWithKeyboardInteractive(String user, InteractiveCallback cb)
-            throws IOException
-    {
-        return authenticateWithKeyboardInteractive(user, null, cb);
-    }
-
-    /**
-     * After a successful connect, one has to authenticate oneself. This method
-     * is based on "keyboard-interactive", specified in
-     * draft-ietf-secsh-auth-kbdinteract-XX. Basically, you have to define a
-     * callback object which will be feeded with challenges generated by the
-     * server. Answers are then sent back to the server. It is possible that the
-     * callback will be called several times during the invocation of this
-     * method (e.g., if the server replies to the callback's answer(s) with
-     * another challenge...)
-     * <p>
-     * If the authentication phase is complete, <code>true</code> will be
-     * returned. If the server does not accept the request (or if further
-     * authentication steps are needed), <code>false</code> is returned and
-     * one can retry either by using this or any other authentication method
-     * (use the <code>getRemainingAuthMethods</code> method to get a list of
-     * the remaining possible methods).
-     * <p>
-     * Note: some SSH servers advertise "keyboard-interactive", however, any
-     * interactive request will be denied (without having sent any challenge to
-     * the client).
-     *
-     * @param user
-     *            A <code>String</code> holding the username.
-     * @param submethods
-     *            An array of submethod names, see
-     *            draft-ietf-secsh-auth-kbdinteract-XX. May be <code>null</code>
-     *            to indicate an empty list.
-     * @param cb
-     *            An <code>InteractiveCallback</code> which will be used to
-     *            determine the responses to the questions asked by the server.
-     *
-     * @return whether the connection is now authenticated.
-     * @throws IOException
-     */
-    public synchronized boolean authenticateWithKeyboardInteractive(String user, String[] submethods,
-                                                                    InteractiveCallback cb) throws IOException
-    {
-        if (cb == null)
-            throw new IllegalArgumentException("Callback may not ne NULL!");
-
-        if (tm == null)
-            throw new IllegalStateException("Connection is not established!");
-
-        if (authenticated)
-            throw new IllegalStateException("Connection is already authenticated!");
-
-        if (am == null)
-            am = new AuthenticationManager(tm);
-
-        if (cm == null)
-            cm = new ChannelManager(tm);
-
-        if (user == null)
-            throw new IllegalArgumentException("user argument is null");
-
-        authenticated = am.authenticateInteractive(user, submethods, cb);
-
-        return authenticated;
-    }
-
-    /**
-     * After a successful connect, one has to authenticate oneself. This method
-     * sends username and password to the server.
-     * <p>
-     * If the authentication phase is complete, <code>true</code> will be
-     * returned. If the server does not accept the request (or if further
-     * authentication steps are needed), <code>false</code> is returned and
-     * one can retry either by using this or any other authentication method
-     * (use the <code>getRemainingAuthMethods</code> method to get a list of
-     * the remaining possible methods).
-     * <p>
-     * Note: if this method fails, then please double-check that it is actually
-     * offered by the server (use {@link #getRemainingAuthMethods(String) getRemainingAuthMethods()}.
-     * <p>
-     * Often, password authentication is disabled, but users are not aware of it.
-     * Many servers only offer "publickey" and "keyboard-interactive". However,
-     * even though "keyboard-interactive" *feels* like password authentication
-     * (e.g., when using the putty or openssh clients) it is *not* the same mechanism.
-     *
-     * @param user
-     * @param password
-     * @return if the connection is now authenticated.
-     * @throws IOException
-     */
-    public synchronized boolean authenticateWithPassword(String user, String password) throws IOException
-    {
-        if (tm == null)
-            throw new IllegalStateException("Connection is not established!");
-
-        if (authenticated)
-            throw new IllegalStateException("Connection is already authenticated!");
-
-        if (am == null)
-            am = new AuthenticationManager(tm);
-
-        if (cm == null)
-            cm = new ChannelManager(tm);
-
-        if (user == null)
-            throw new IllegalArgumentException("user argument is null");
-
-        if (password == null)
-            throw new IllegalArgumentException("password argument is null");
-
-        authenticated = am.authenticatePassword(user, password);
-
-        return authenticated;
-    }
-
-    /**
-     * After a successful connect, one has to authenticate oneself.
-     * This method can be used to explicitly use the special "none"
-     * authentication method (where only a username has to be specified).
-     * <p>
-     * Note 1: The "none" method may always be tried by clients, however as by
-     * the specs, the server will not explicitly announce it. In other words,
-     * the "none" token will never show up in the list returned by
-     * {@link #getRemainingAuthMethods(String)}.
-     * <p>
-     * Note 2: no matter which one of the authenticateWithXXX() methods
-     * you call, the library will always issue exactly one initial "none"
-     * authentication request to retrieve the initially allowed list of
-     * authentication methods by the server. Please read RFC 4252 for the
-     * details.
-     * <p>
-     * If the authentication phase is complete, <code>true</code> will be
-     * returned. If further authentication steps are needed, <code>false</code>
-     * is returned and one can retry by any other authentication method
-     * (use the <code>getRemainingAuthMethods</code> method to get a list of
-     * the remaining possible methods).
-     *
-     * @param user
-     * @return if the connection is now authenticated.
-     * @throws IOException
-     */
-    public synchronized boolean authenticateWithNone(String user) throws IOException
-    {
-        if (tm == null)
-            throw new IllegalStateException("Connection is not established!");
-
-        if (authenticated)
-            throw new IllegalStateException("Connection is already authenticated!");
-
-        if (am == null)
-            am = new AuthenticationManager(tm);
-
-        if (cm == null)
-            cm = new ChannelManager(tm);
-
-        if (user == null)
-            throw new IllegalArgumentException("user argument is null");
-
-               /* Trigger the sending of the PacketUserauthRequestNone packet */
-               /* (if not already done)                                       */
-
-        authenticated = am.authenticateNone(user);
-
-        return authenticated;
-    }
-
-    /**
-     * After a successful connect, one has to authenticate oneself.
-     * The authentication method "publickey" works by signing a challenge
-     * sent by the server. The signature is either DSA or RSA based - it
-     * just depends on the type of private key you specify, either a DSA
-     * or RSA private key in PEM format. And yes, this is may seem to be a
-     * little confusing, the method is called "publickey" in the SSH-2 protocol
-     * specification, however since we need to generate a signature, you
-     * actually have to supply a private key =).
-     * <p>
-     * The private key contained in the PEM file may also be encrypted ("Proc-Type: 4,ENCRYPTED").
-     * The library supports DES-CBC and DES-EDE3-CBC encryption, as well
-     * as the more exotic PEM encrpytions AES-128-CBC, AES-192-CBC and AES-256-CBC.
-     * <p>
-     * If the authentication phase is complete, <code>true</code> will be
-     * returned. If the server does not accept the request (or if further
-     * authentication steps are needed), <code>false</code> is returned and
-     * one can retry either by using this or any other authentication method
-     * (use the <code>getRemainingAuthMethods</code> method to get a list of
-     * the remaining possible methods).
-     * <p>
-     * NOTE PUTTY USERS: Event though your key file may start with "-----BEGIN..."
-     * it is not in the expected format. You have to convert it to the OpenSSH
-     * key format by using the "puttygen" tool (can be downloaded from the Putty
-     * website). Simply load your key and then use the "Conversions/Export OpenSSH key"
-     * functionality to get a proper PEM file.
-     *
-     * @param user
-     *            A <code>String</code> holding the username.
-     * @param pemPrivateKey
-     *            A <code>char[]</code> containing a DSA or RSA private key of the
-     *            user in OpenSSH key format (PEM, you can't miss the
-     *            "-----BEGIN DSA PRIVATE KEY-----" or "-----BEGIN RSA PRIVATE KEY-----"
-     *            tag). The char array may contain linebreaks/linefeeds.
-     * @param password
-     *            If the PEM structure is encrypted ("Proc-Type: 4,ENCRYPTED") then
-     *            you must specify a password. Otherwise, this argument will be ignored
-     *            and can be set to <code>null</code>.
-     *
-     * @return whether the connection is now authenticated.
-     * @throws IOException
-     */
-    public synchronized boolean authenticateWithPublicKey(String user, char[] pemPrivateKey, String password)
-            throws IOException
-    {
-        if (tm == null)
-            throw new IllegalStateException("Connection is not established!");
-
-        if (authenticated)
-            throw new IllegalStateException("Connection is already authenticated!");
-
-        if (am == null)
-            am = new AuthenticationManager(tm);
-
-        if (cm == null)
-            cm = new ChannelManager(tm);
-
-        if (user == null)
-            throw new IllegalArgumentException("user argument is null");
-
-        if (pemPrivateKey == null)
-            throw new IllegalArgumentException("pemPrivateKey argument is null");
-
-        authenticated = am.authenticatePublicKey(user, pemPrivateKey, password, getOrCreateSecureRND());
-
-        return authenticated;
-    }
-
-    /**
-     * A convenience wrapper function which reads in a private key (PEM format, either DSA or RSA)
-     * and then calls <code>authenticateWithPublicKey(String, char[], String)</code>.
-     * <p>
-     * NOTE PUTTY USERS: Event though your key file may start with "-----BEGIN..."
-     * it is not in the expected format. You have to convert it to the OpenSSH
-     * key format by using the "puttygen" tool (can be downloaded from the Putty
-     * website). Simply load your key and then use the "Conversions/Export OpenSSH key"
-     * functionality to get a proper PEM file.
-     *
-     * @param user
-     *            A <code>String</code> holding the username.
-     * @param pemFile
-     *            A <code>File</code> object pointing to a file containing a DSA or RSA
-     *            private key of the user in OpenSSH key format (PEM, you can't miss the
-     *            "-----BEGIN DSA PRIVATE KEY-----" or "-----BEGIN RSA PRIVATE KEY-----"
-     *            tag).
-     * @param password
-     *            If the PEM file is encrypted then you must specify the password.
-     *            Otherwise, this argument will be ignored and can be set to <code>null</code>.
-     *
-     * @return whether the connection is now authenticated.
-     * @throws IOException
-     */
-    public synchronized boolean authenticateWithPublicKey(String user, File pemFile, String password)
-            throws IOException
-    {
-        if (pemFile == null)
-            throw new IllegalArgumentException("pemFile argument is null");
-
-        char[] buff = new char[256];
-
-        CharArrayWriter cw = new CharArrayWriter();
-
-        FileReader fr = new FileReader(pemFile);
-
-        while (true)
-        {
-            int len = fr.read(buff);
-            if (len < 0)
-                break;
-            cw.write(buff, 0, len);
-        }
-
-        fr.close();
-
-        return authenticateWithPublicKey(user, cw.toCharArray(), password);
-    }
-
-    /**
-     * Add a {@link ConnectionMonitor} to this connection. Can be invoked at any time,
-     * but it is best to add connection monitors before invoking
-     * <code>connect()</code> to avoid glitches (e.g., you add a connection monitor after
-     * a successful connect(), but the connection has died in the mean time. Then,
-     * your connection monitor won't be notified.)
-     * <p>
-     * You can add as many monitors as you like. If a monitor has already been added, then
-     * this method does nothing.
-     *
-     * @see ConnectionMonitor
-     *
-     * @param cmon An object implementing the {@link ConnectionMonitor} interface.
-     */
-    public synchronized void addConnectionMonitor(ConnectionMonitor cmon)
-    {
-        if (cmon == null)
-            throw new IllegalArgumentException("cmon argument is null");
-
-        if (!connectionMonitors.contains(cmon))
-        {
-            connectionMonitors.add(cmon);
-
-            if (tm != null)
-                tm.setConnectionMonitors(connectionMonitors);
-        }
-    }
-
-    /**
-     * Remove a {@link ConnectionMonitor} from this connection.
-     *
-     * @param cmon
-     * @return whether the monitor could be removed
-     */
-    public synchronized boolean removeConnectionMonitor(ConnectionMonitor cmon)
-    {
-        if (cmon == null)
-            throw new IllegalArgumentException("cmon argument is null");
-
-        boolean existed = connectionMonitors.remove(cmon);
-
-        if (tm != null)
-            tm.setConnectionMonitors(connectionMonitors);
-
-        return existed;
-    }
-
-    /**
-     * Close the connection to the SSH-2 server. All assigned sessions will be
-     * closed, too. Can be called at any time. Don't forget to call this once
-     * you don't need a connection anymore - otherwise the receiver thread may
-     * run forever.
-     */
-    public synchronized void close()
-    {
-        Throwable t = new Throwable("Closed due to user request.");
-        close(t, false);
-    }
-
-    public synchronized void close(Throwable t, boolean hard)
-    {
-        if (cm != null)
-            cm.closeAllChannels();
-
-        if (tm != null)
-        {
-            tm.close(t, hard == false);
-            tm = null;
-        }
-        am = null;
-        cm = null;
-        authenticated = false;
-    }
-
-    /**
-     * Same as {@link #connect(ServerHostKeyVerifier, int, int) connect(null, 0, 0)}.
-     *
-     * @return see comments for the {@link #connect(ServerHostKeyVerifier, int, int) connect(ServerHostKeyVerifier, int, int)} method.
-     * @throws IOException
-     */
-    public synchronized ConnectionInfo connect() throws IOException
-    {
-        return connect(null, 0, 0);
-    }
-
-    /**
-     * Same as {@link #connect(ServerHostKeyVerifier, int, int) connect(verifier, 0, 0)}.
-     *
-     * @return see comments for the {@link #connect(ServerHostKeyVerifier, int, int) connect(ServerHostKeyVerifier, int, int)} method.
-     * @throws IOException
-     */
-    public synchronized ConnectionInfo connect(ServerHostKeyVerifier verifier) throws IOException
-    {
-        return connect(verifier, 0, 0);
-    }
-
-    /**
-     * Connect to the SSH-2 server and, as soon as the server has presented its
-     * host key, use the {@link ServerHostKeyVerifier#verifyServerHostKey(String,
-     * int, String, byte[]) ServerHostKeyVerifier.verifyServerHostKey()}
-     * method of the <code>verifier</code> to ask for permission to proceed.
-     * If <code>verifier</code> is <code>null</code>, then any host key will be
-     * accepted - this is NOT recommended, since it makes man-in-the-middle attackes
-     * VERY easy (somebody could put a proxy SSH server between you and the real server).
-     * <p>
-     * Note: The verifier will be called before doing any crypto calculations
-     * (i.e., diffie-hellman). Therefore, if you don't like the presented host key then
-     * no CPU cycles are wasted (and the evil server has less information about us).
-     * <p>
-     * However, it is still possible that the server presented a fake host key: the server
-     * cheated (typically a sign for a man-in-the-middle attack) and is not able to generate
-     * a signature that matches its host key. Don't worry, the library will detect such
-     * a scenario later when checking the signature (the signature cannot be checked before
-     * having completed the diffie-hellman exchange).
-     * <p>
-     * Note 2: The  {@link ServerHostKeyVerifier#verifyServerHostKey(String,
-     * int, String, byte[]) ServerHostKeyVerifier.verifyServerHostKey()} method
-     * will *NOT* be called from the current thread, the call is being made from a
-     * background thread (there is a background dispatcher thread for every
-     * established connection).
-     * <p>
-     * Note 3: This method will block as long as the key exchange of the underlying connection
-     * has not been completed (and you have not specified any timeouts).
-     * <p>
-     * Note 4: If you want to re-use a connection object that was successfully connected,
-     * then you must call the {@link #close()} method before invoking <code>connect()</code> again.
-     *
-     * @param verifier
-     *            An object that implements the
-     *            {@link ServerHostKeyVerifier} interface. Pass <code>null</code>
-     *            to accept any server host key - NOT recommended.
-     *
-     * @param connectTimeout
-     *            Connect the underlying TCP socket to the server with the given timeout
-     *            value (non-negative, in milliseconds). Zero means no timeout. If a proxy is being
-     *            used (see {@link #setProxyData(ProxyData)}), then this timeout is used for the
-     *            connection establishment to the proxy.
-     *
-     * @param kexTimeout
-     *            Timeout for complete connection establishment (non-negative,
-     *            in milliseconds). Zero means no timeout. The timeout counts from the
-     *            moment you invoke the connect() method and is cancelled as soon as the
-     *            first key-exchange round has finished. It is possible that
-     *            the timeout event will be fired during the invocation of the
-     *            <code>verifier</code> callback, but it will only have an effect after
-     *            the <code>verifier</code> returns.
-     *
-     * @return A {@link ConnectionInfo} object containing the details of
-     *            the established connection.
-     *
-     * @throws IOException
-     *            If any problem occurs, e.g., the server's host key is not
-     *            accepted by the <code>verifier</code> or there is problem during
-     *            the initial crypto setup (e.g., the signature sent by the server is wrong).
-     *            <p>
-     *            In case of a timeout (either connectTimeout or kexTimeout)
-     *            a SocketTimeoutException is thrown.
-     *            <p>
-     *            An exception may also be thrown if the connection was already successfully
-     *            connected (no matter if the connection broke in the mean time) and you invoke
-     *            <code>connect()</code> again without having called {@link #close()} first.
-     *            <p>
-     *            If a HTTP proxy is being used and the proxy refuses the connection,
-     *            then a {@link HTTPProxyException} may be thrown, which
-     *            contains the details returned by the proxy. If the proxy is buggy and does
-     *            not return a proper HTTP response, then a normal IOException is thrown instead.
-     */
-    public synchronized ConnectionInfo connect(ServerHostKeyVerifier verifier, int connectTimeout, int kexTimeout)
-            throws IOException
-    {
-        final class TimeoutState
-        {
-            boolean isCancelled = false;
-            boolean timeoutSocketClosed = false;
-        }
-
-        if (tm != null)
-            throw new IOException("Connection to " + hostname + " is already in connected state!");
-
-        if (connectTimeout < 0)
-            throw new IllegalArgumentException("connectTimeout must be non-negative!");
-
-        if (kexTimeout < 0)
-            throw new IllegalArgumentException("kexTimeout must be non-negative!");
-
-        final TimeoutState state = new TimeoutState();
-
-        tm = new TransportManager();
-        tm.setSoTimeout(connectTimeout);
-        tm.setConnectionMonitors(connectionMonitors);
-
-               /* Make sure that the runnable below will observe the new value of "tm"
-                * and "state" (the runnable will be executed in a different thread, which
-                * may be already running, that is why we need a memory barrier here).
-                * See also the comment in Channel.java if you
-                * are interested in the details.
-                * 
-                * OKOK, this is paranoid since adding the runnable to the todo list
-                * of the TimeoutService will ensure that all writes have been flushed
-                * before the Runnable reads anything
-                * (there is a synchronized block in TimeoutService.addTimeoutHandler).
-                */
-
-        synchronized (tm)
-        {
-                       /* We could actually synchronize on anything. */
-        }
-
-        try
-        {
-            TimeoutToken token = null;
-
-            if (kexTimeout > 0)
-            {
-                final Runnable timeoutHandler = new Runnable()
-                {
-                    public void run()
-                    {
-                        synchronized (state)
-                        {
-                            if (state.isCancelled)
-                                return;
-                            state.timeoutSocketClosed = true;
-                            tm.close(new SocketTimeoutException("The connect timeout expired"), false);
-                        }
-                    }
-                };
-
-                long timeoutHorizont = System.currentTimeMillis() + kexTimeout;
-
-                token = TimeoutService.addTimeoutHandler(timeoutHorizont, timeoutHandler);
-            }
-
-            try
-            {
-
-                if (precreatedSocket != null) {
-                    tm.clientInit(precreatedSocket, softwareversion, cryptoWishList, verifier, dhgexpara,
-                            getOrCreateSecureRND());
-                } else {
-                    tm.clientInit(hostname, port, softwareversion, cryptoWishList, verifier, dhgexpara, connectTimeout,
-                            getOrCreateSecureRND(), proxyData);
-                }
-            }
-            catch (SocketTimeoutException se)
-            {
-                throw (SocketTimeoutException) new SocketTimeoutException(
-                        "The connect() operation on the socket timed out.").initCause(se);
-            }
-
-            tm.setTcpNoDelay(tcpNoDelay);
-
-                       /* Wait until first KEX has finished */
-
-            ConnectionInfo ci = tm.getConnectionInfo(1);
-
-                       /* Now try to cancel the timeout, if needed */
-
-            if (token != null)
-            {
-                TimeoutService.cancelTimeoutHandler(token);
-
-                               /* Were we too late? */
-
-                synchronized (state)
-                {
-                    if (state.timeoutSocketClosed)
-                        throw new IOException("This exception will be replaced by the one below =)");
-                                       /* Just in case the "cancelTimeoutHandler" invocation came just a little bit
-                                        * too late but the handler did not enter the semaphore yet - we can
-                                        * still stop it.
-                                        */
-                    state.isCancelled = true;
-                }
-            }
-
-            return ci;
-        }
-        catch (SocketTimeoutException ste)
-        {
-            throw ste;
-        }
-        catch (IOException e1)
-        {
-                       /* This will also invoke any registered connection monitors */
-            close(new Throwable("There was a problem during connect."), false);
-
-            synchronized (state)
-            {
-                               /* Show a clean exception, not something like "the socket is closed!?!" */
-                if (state.timeoutSocketClosed)
-                    throw new SocketTimeoutException("The kexTimeout (" + kexTimeout + " ms) expired.");
-            }
-
-                       /* Do not wrap a HTTPProxyException */
-            if (e1 instanceof HTTPProxyException)
-                throw e1;
-
-            throw (IOException) new IOException("There was a problem while connecting to " + hostname + ":" + port)
-                    .initCause(e1);
-        }
-    }
-
-    /**
-     * Creates a new {@link LocalPortForwarder}.
-     * A <code>LocalPortForwarder</code> forwards TCP/IP connections that arrive at a local
-     * port via the secure tunnel to another host (which may or may not be
-     * identical to the remote SSH-2 server).
-     * <p>
-     * This method must only be called after one has passed successfully the authentication step.
-     * There is no limit on the number of concurrent forwardings.
-     *
-     * @param local_port the local port the LocalPortForwarder shall bind to.
-     * @param host_to_connect target address (IP or hostname)
-     * @param port_to_connect target port
-     * @return A {@link LocalPortForwarder} object.
-     * @throws IOException
-     */
-    public synchronized LocalPortForwarder createLocalPortForwarder(int local_port, String host_to_connect,
-                                                                    int port_to_connect) throws IOException
-    {
-        if (tm == null)
-            throw new IllegalStateException("Cannot forward ports, you need to establish a connection first.");
-
-        if (!authenticated)
-            throw new IllegalStateException("Cannot forward ports, connection is not authenticated.");
-
-        return new LocalPortForwarder(cm, local_port, host_to_connect, port_to_connect);
-    }
-
-    /**
-     * Creates a new {@link LocalPortForwarder}.
-     * A <code>LocalPortForwarder</code> forwards TCP/IP connections that arrive at a local
-     * port via the secure tunnel to another host (which may or may not be
-     * identical to the remote SSH-2 server).
-     * <p>
-     * This method must only be called after one has passed successfully the authentication step.
-     * There is no limit on the number of concurrent forwardings.
-     *
-     * @param addr specifies the InetSocketAddress where the local socket shall be bound to.
-     * @param host_to_connect target address (IP or hostname)
-     * @param port_to_connect target port
-     * @return A {@link LocalPortForwarder} object.
-     * @throws IOException
-     */
-    public synchronized LocalPortForwarder createLocalPortForwarder(InetSocketAddress addr, String host_to_connect,
-                                                                    int port_to_connect) throws IOException
-    {
-        if (tm == null)
-            throw new IllegalStateException("Cannot forward ports, you need to establish a connection first.");
-
-        if (!authenticated)
-            throw new IllegalStateException("Cannot forward ports, connection is not authenticated.");
-
-        return new LocalPortForwarder(cm, addr, host_to_connect, port_to_connect);
-    }
-
-    /**
-     * Creates a new {@link LocalStreamForwarder}.
-     * A <code>LocalStreamForwarder</code> manages an Input/Outputstream pair
-     * that is being forwarded via the secure tunnel into a TCP/IP connection to another host
-     * (which may or may not be identical to the remote SSH-2 server).
-     *
-     * @param host_to_connect
-     * @param port_to_connect
-     * @return A {@link LocalStreamForwarder} object.
-     * @throws IOException
-     */
-    public synchronized LocalStreamForwarder createLocalStreamForwarder(String host_to_connect, int port_to_connect)
-            throws IOException
-    {
-        if (tm == null)
-            throw new IllegalStateException("Cannot forward, you need to establish a connection first.");
-
-        if (!authenticated)
-            throw new IllegalStateException("Cannot forward, connection is not authenticated.");
-
-        return new LocalStreamForwarder(cm, host_to_connect, port_to_connect);
-    }
-
-    /**
-     * Create a very basic {@link SCPClient} that can be used to copy
-     * files from/to the SSH-2 server.
-     * <p>
-     * Works only after one has passed successfully the authentication step.
-     * There is no limit on the number of concurrent SCP clients.
-     * <p>
-     * Note: This factory method will probably disappear in the future.
-     *
-     * @return A {@link SCPClient} object.
-     * @throws IOException
-     */
-    public synchronized SCPClient createSCPClient() throws IOException
-    {
-        if (tm == null)
-            throw new IllegalStateException("Cannot create SCP client, you need to establish a connection first.");
-
-        if (!authenticated)
-            throw new IllegalStateException("Cannot create SCP client, connection is not authenticated.");
-
-        return new SCPClient(this);
-    }
-
-    /**
-     * Force an asynchronous key re-exchange (the call does not block). The
-     * latest values set for MAC, Cipher and DH group exchange parameters will
-     * be used. If a key exchange is currently in progress, then this method has
-     * the only effect that the so far specified parameters will be used for the
-     * next (server driven) key exchange.
-     * <p>
-     * Note: This implementation will never start a key exchange (other than the initial one)
-     * unless you or the SSH-2 server ask for it.
-     *
-     * @throws IOException
-     *             In case of any failure behind the scenes.
-     */
-    public synchronized void forceKeyExchange() throws IOException
-    {
-        if (tm == null)
-            throw new IllegalStateException("You need to establish a connection first.");
-
-        tm.forceKeyExchange(cryptoWishList, dhgexpara, null, null);
-    }
-
-    /**
-     * Returns the hostname that was passed to the constructor.
-     *
-     * @return the hostname
-     */
-    public synchronized String getHostname()
-    {
-        return hostname;
-    }
-
-    /**
-     * Returns the port that was passed to the constructor.
-     *
-     * @return the TCP port
-     */
-    public synchronized int getPort()
-    {
-        return port;
-    }
-
-    /**
-     * Returns a {@link ConnectionInfo} object containing the details of
-     * the connection. Can be called as soon as the connection has been
-     * established (successfully connected).
-     *
-     * @return A {@link ConnectionInfo} object.
-     * @throws IOException
-     *             In case of any failure behind the scenes.
-     */
-    public synchronized ConnectionInfo getConnectionInfo() throws IOException
-    {
-        if (tm == null)
-            throw new IllegalStateException(
-                    "Cannot get details of connection, you need to establish a connection first.");
-        return tm.getConnectionInfo(1);
-    }
-
-    /**
-     * After a successful connect, one has to authenticate oneself. This method
-     * can be used to tell which authentication methods are supported by the
-     * server at a certain stage of the authentication process (for the given
-     * username).
-     * <p>
-     * Note 1: the username will only be used if no authentication step was done
-     * so far (it will be used to ask the server for a list of possible
-     * authentication methods by sending the initial "none" request). Otherwise,
-     * this method ignores the user name and returns a cached method list
-     * (which is based on the information contained in the last negative server response).
-     * <p>
-     * Note 2: the server may return method names that are not supported by this
-     * implementation.
-     * <p>
-     * After a successful authentication, this method must not be called
-     * anymore.
-     *
-     * @param user
-     *            A <code>String</code> holding the username.
-     *
-     * @return a (possibly emtpy) array holding authentication method names.
-     * @throws IOException
-     */
-    public synchronized String[] getRemainingAuthMethods(String user) throws IOException
-    {
-        if (user == null)
-            throw new IllegalArgumentException("user argument may not be NULL!");
-
-        if (tm == null)
-            throw new IllegalStateException("Connection is not established!");
-
-        if (authenticated)
-            throw new IllegalStateException("Connection is already authenticated!");
-
-        if (am == null)
-            am = new AuthenticationManager(tm);
-
-        if (cm == null)
-            cm = new ChannelManager(tm);
-
-        return am.getRemainingMethods(user);
-    }
-
-    /**
-     * Determines if the authentication phase is complete. Can be called at any
-     * time.
-     *
-     * @return <code>true</code> if no further authentication steps are
-     *         needed.
-     */
-    public synchronized boolean isAuthenticationComplete()
-    {
-        return authenticated;
-    }
-
-    /**
-     * Returns true if there was at least one failed authentication request and
-     * the last failed authentication request was marked with "partial success"
-     * by the server. This is only needed in the rare case of SSH-2 server setups
-     * that cannot be satisfied with a single successful authentication request
-     * (i.e., multiple authentication steps are needed.)
-     * <p>
-     * If you are interested in the details, then have a look at RFC4252.
-     *
-     * @return if the there was a failed authentication step and the last one
-     *         was marked as a "partial success".
-     */
-    public synchronized boolean isAuthenticationPartialSuccess()
-    {
-        if (am == null)
-            return false;
-
-        return am.getPartialSuccess();
-    }
-
-    /**
-     * Checks if a specified authentication method is available. This method is
-     * actually just a wrapper for {@link #getRemainingAuthMethods(String)
-     * getRemainingAuthMethods()}.
-     *
-     * @param user
-     *            A <code>String</code> holding the username.
-     * @param method
-     *            An authentication method name (e.g., "publickey", "password",
-     *            "keyboard-interactive") as specified by the SSH-2 standard.
-     * @return if the specified authentication method is currently available.
-     * @throws IOException
-     */
-    public synchronized boolean isAuthMethodAvailable(String user, String method) throws IOException
-    {
-        if (method == null)
-            throw new IllegalArgumentException("method argument may not be NULL!");
-
-        String methods[] = getRemainingAuthMethods(user);
-
-        for (int i = 0; i < methods.length; i++)
-        {
-            if (methods[i].compareTo(method) == 0)
-                return true;
-        }
-
-        return false;
-    }
-
-    private SecureRandom getOrCreateSecureRND()
-    {
-        if (generator == null)
-            generator = new SecureRandom();
-
-        return generator;
-    }
-
-    /**
-     * Open a new {@link Session} on this connection. Works only after one has passed
-     * successfully the authentication step. There is no limit on the number of
-     * concurrent sessions.
-     *
-     * @return A {@link Session} object.
-     * @throws IOException
-     */
-    public synchronized Session openSession() throws IOException
-    {
-        if (tm == null)
-            throw new IllegalStateException("Cannot open session, you need to establish a connection first.");
-
-        if (!authenticated)
-            throw new IllegalStateException("Cannot open session, connection is not authenticated.");
-
-        return new Session(cm, getOrCreateSecureRND());
-    }
-
-    /**
-     * Send an SSH_MSG_IGNORE packet. This method will generate a random data attribute
-     * (length between 0 (invlusive) and 16 (exclusive) bytes, contents are random bytes).
-     * <p>
-     * This method must only be called once the connection is established.
-     *
-     * @throws IOException
-     */
-    public synchronized void sendIgnorePacket() throws IOException
-    {
-        SecureRandom rnd = getOrCreateSecureRND();
-
-        byte[] data = new byte[rnd.nextInt(16)];
-        rnd.nextBytes(data);
-
-        sendIgnorePacket(data);
-    }
-
-    /**
-     * Send an SSH_MSG_IGNORE packet with the given data attribute.
-     * <p>
-     * This method must only be called once the connection is established.
-     *
-     * @throws IOException
-     */
-    public synchronized void sendIgnorePacket(byte[] data) throws IOException
-    {
-        if (data == null)
-            throw new IllegalArgumentException("data argument must not be null.");
-
-        if (tm == null)
-            throw new IllegalStateException(
-                    "Cannot send SSH_MSG_IGNORE packet, you need to establish a connection first.");
-
-        PacketIgnore pi = new PacketIgnore();
-        pi.setData(data);
-
-        tm.sendMessage(pi.getPayload());
-    }
-
-    /**
-     * Removes duplicates from a String array, keeps only first occurence
-     * of each element. Does not destroy order of elements; can handle nulls.
-     * Uses a very efficient O(N^2) algorithm =)
-     *
-     * @param list a String array.
-     * @return a cleaned String array.
-     */
-    private String[] removeDuplicates(String[] list)
-    {
-        if ((list == null) || (list.length < 2))
-            return list;
-
-        String[] list2 = new String[list.length];
-
-        int count = 0;
-
-        for (int i = 0; i < list.length; i++)
-        {
-            boolean duplicate = false;
-
-            String element = list[i];
-
-            for (int j = 0; j < count; j++)
-            {
-                if (((element == null) && (list2[j] == null)) || ((element != null) && (element.equals(list2[j]))))
-                {
-                    duplicate = true;
-                    break;
-                }
-            }
-
-            if (duplicate)
-                continue;
-
-            list2[count++] = list[i];
-        }
-
-        if (count == list2.length)
-            return list2;
-
-        String[] tmp = new String[count];
-        System.arraycopy(list2, 0, tmp, 0, count);
-
-        return tmp;
-    }
-
-    /**
-     * Unless you know what you are doing, you will never need this.
-     *
-     * @param ciphers
-     */
-    public synchronized void setClient2ServerCiphers(String[] ciphers)
-    {
-        if ((ciphers == null) || (ciphers.length == 0))
-            throw new IllegalArgumentException();
-        ciphers = removeDuplicates(ciphers);
-        BlockCipherFactory.checkCipherList(ciphers);
-        cryptoWishList.c2s_enc_algos = ciphers;
-    }
-
-    /**
-     * Unless you know what you are doing, you will never need this.
-     *
-     * @param macs
-     */
-    public synchronized void setClient2ServerMACs(String[] macs)
-    {
-        if ((macs == null) || (macs.length == 0))
-            throw new IllegalArgumentException();
-        macs = removeDuplicates(macs);
-        MAC.checkMacList(macs);
-        cryptoWishList.c2s_mac_algos = macs;
-    }
-
-    /**
-     * Sets the parameters for the diffie-hellman group exchange. Unless you
-     * know what you are doing, you will never need this. Default values are
-     * defined in the {@link DHGexParameters} class.
-     *
-     * @param dgp {@link DHGexParameters}, non null.
-     *
-     */
-    public synchronized void setDHGexParameters(DHGexParameters dgp)
-    {
-        if (dgp == null)
-            throw new IllegalArgumentException();
-
-        dhgexpara = dgp;
-    }
-
-    /**
-     * Unless you know what you are doing, you will never need this.
-     *
-     * @param ciphers
-     */
-    public synchronized void setServer2ClientCiphers(String[] ciphers)
-    {
-        if ((ciphers == null) || (ciphers.length == 0))
-            throw new IllegalArgumentException();
-        ciphers = removeDuplicates(ciphers);
-        BlockCipherFactory.checkCipherList(ciphers);
-        cryptoWishList.s2c_enc_algos = ciphers;
-    }
-
-    /**
-     * Unless you know what you are doing, you will never need this.
-     *
-     * @param macs
-     */
-    public synchronized void setServer2ClientMACs(String[] macs)
-    {
-        if ((macs == null) || (macs.length == 0))
-            throw new IllegalArgumentException();
-
-        macs = removeDuplicates(macs);
-        MAC.checkMacList(macs);
-        cryptoWishList.s2c_mac_algos = macs;
-    }
-
-    /**
-     * Define the set of allowed server host key algorithms to be used for
-     * the following key exchange operations.
-     * <p>
-     * Unless you know what you are doing, you will never need this.
-     *
-     * @param algos An array of allowed server host key algorithms.
-     *         SSH-2 defines <code>ssh-dss</code> and <code>ssh-rsa</code>.
-     *         The entries of the array must be ordered after preference, i.e.,
-     *  the entry at index 0 is the most preferred one. You must specify
-     *  at least one entry.
-     */
-    public synchronized void setServerHostKeyAlgorithms(String[] algos)
-    {
-        if ((algos == null) || (algos.length == 0))
-            throw new IllegalArgumentException();
-
-        algos = removeDuplicates(algos);
-        KexManager.checkServerHostkeyAlgorithmsList(algos);
-        cryptoWishList.serverHostKeyAlgorithms = algos;
-    }
-
-    /**
-     * Enable/disable TCP_NODELAY (disable/enable Nagle's algorithm) on the underlying socket.
-     * <p>
-     * Can be called at any time. If the connection has not yet been established
-     * then the passed value will be stored and set after the socket has been set up.
-     * The default value that will be used is <code>false</code>.
-     *
-     * @param enable the argument passed to the <code>Socket.setTCPNoDelay()</code> method.
-     * @throws IOException
-     */
-    public synchronized void setTCPNoDelay(boolean enable) throws IOException
-    {
-        tcpNoDelay = enable;
-
-        if (tm != null)
-            tm.setTcpNoDelay(enable);
-    }
-
-    /**
-     * Used to tell the library that the connection shall be established through a proxy server.
-     * It only makes sense to call this method before calling the {@link #connect() connect()}
-     * method.
-     * <p>
-     * At the moment, only HTTP proxies are supported.
-     * <p>
-     * Note: This method can be called any number of times. The {@link #connect() connect()}
-     * method will use the value set in the last preceding invocation of this method.
-     *
-     * @see HTTPProxyData
-     *
-     * @param proxyData Connection information about the proxy. If <code>null</code>, then
-     *                  no proxy will be used (non surprisingly, this is also the default).
-     */
-    public synchronized void setProxyData(ProxyData proxyData)
-    {
-        this.proxyData = proxyData;
-    }
-
-    /**
-     * Request a remote port forwarding.
-     * If successful, then forwarded connections will be redirected to the given target address.
-     * You can cancle a requested remote port forwarding by calling
-     * {@link #cancelRemotePortForwarding(int) cancelRemotePortForwarding()}.
-     * <p>
-     * A call of this method will block until the peer either agreed or disagreed to your request-
-     * <p>
-     * Note 1: this method typically fails if you
-     * <ul>
-     * <li>pass a port number for which the used remote user has not enough permissions (i.e., port
-     * &lt; 1024)</li>
-     * <li>or pass a port number that is already in use on the remote server</li>
-     * <li>or if remote port forwarding is disabled on the server.</li>
-     * </ul>
-     * <p>
-     * Note 2: (from the openssh man page): By default, the listening socket on the server will be
-     * bound to the loopback interface only. This may be overriden by specifying a bind address.
-     * Specifying a remote bind address will only succeed if the server's <b>GatewayPorts</b> option
-     * is enabled (see sshd_config(5)).
-     *
-     * @param bindAddress 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>
-     * @param bindPort port number to bind on the server (must be &gt; 0)
-     * @param targetAddress the target address (IP or hostname)
-     * @param targetPort the target port
-     * @throws IOException
-     */
-    public synchronized void requestRemotePortForwarding(String bindAddress, int bindPort, String targetAddress,
-                                                         int targetPort) throws IOException
-    {
-        if (tm == null)
-            throw new IllegalStateException("You need to establish a connection first.");
-
-        if (!authenticated)
-            throw new IllegalStateException("The connection is not authenticated.");
-
-        if ((bindAddress == null) || (targetAddress == null) || (bindPort <= 0) || (targetPort <= 0))
-            throw new IllegalArgumentException();
-
-        cm.requestGlobalForward(bindAddress, bindPort, targetAddress, targetPort);
-    }
-
-    /**
-     * Cancel an earlier requested remote port forwarding.
-     * Currently active forwardings will not be affected (e.g., disrupted).
-     * Note that further connection forwarding requests may be received until
-     * this method has returned.
-     *
-     * @param bindPort the allocated port number on the server
-     * @throws IOException if the remote side refuses the cancel request or another low
-     *         level error occurs (e.g., the underlying connection is closed)
-     */
-    public synchronized void cancelRemotePortForwarding(int bindPort) throws IOException
-    {
-        if (tm == null)
-            throw new IllegalStateException("You need to establish a connection first.");
-
-        if (!authenticated)
-            throw new IllegalStateException("The connection is not authenticated.");
-
-        cm.requestCancelGlobalForward(bindPort);
-    }
-
-    /**
-     * Provide your own instance of SecureRandom. Can be used, e.g., if you
-     * want to seed the used SecureRandom generator manually.
-     * <p>
-     * The SecureRandom instance is used during key exchanges, public key authentication,
-     * x11 cookie generation and the like.
-     *
-     * @param rnd a SecureRandom instance
-     */
-    public synchronized void setSecureRandom(SecureRandom rnd)
-    {
-        if (rnd == null)
-            throw new IllegalArgumentException();
-
-        this.generator = rnd;
-    }
-}
diff --git a/third-party/ganymed/src/main/java/ch/ethz/ssh2/channel/ChannelManager.java b/third-party/ganymed/src/main/java/ch/ethz/ssh2/channel/ChannelManager.java
deleted file mode 100644 (file)
index 8fec9a0..0000000
+++ /dev/null
@@ -1,1845 +0,0 @@
-/*
- * Copyright (c) 2006-2013 Christian Plattner. All rights reserved.
- * Please refer to the LICENSE.txt for licensing details.
- */
-
-package ch.ethz.ssh2.channel;
-
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Vector;
-
-import ch.ethz.ssh2.ChannelCondition;
-import ch.ethz.ssh2.PtySettings;
-import ch.ethz.ssh2.ServerConnectionCallback;
-import ch.ethz.ssh2.ServerSessionCallback;
-import ch.ethz.ssh2.log.Logger;
-import ch.ethz.ssh2.packets.PacketChannelFailure;
-import ch.ethz.ssh2.packets.PacketChannelOpenConfirmation;
-import ch.ethz.ssh2.packets.PacketChannelOpenFailure;
-import ch.ethz.ssh2.packets.PacketChannelSuccess;
-import ch.ethz.ssh2.packets.PacketGlobalCancelForwardRequest;
-import ch.ethz.ssh2.packets.PacketGlobalForwardRequest;
-import ch.ethz.ssh2.packets.PacketOpenDirectTCPIPChannel;
-import ch.ethz.ssh2.packets.PacketOpenSessionChannel;
-import ch.ethz.ssh2.packets.PacketSessionExecCommand;
-import ch.ethz.ssh2.packets.PacketSessionPtyRequest;
-import ch.ethz.ssh2.packets.PacketSessionStartShell;
-import ch.ethz.ssh2.packets.PacketSessionSubsystemRequest;
-import ch.ethz.ssh2.packets.PacketSessionX11Request;
-import ch.ethz.ssh2.packets.Packets;
-import ch.ethz.ssh2.packets.TypesReader;
-import ch.ethz.ssh2.server.ServerConnectionState;
-import ch.ethz.ssh2.transport.MessageHandler;
-import ch.ethz.ssh2.transport.TransportManager;
-
-/**
- * ChannelManager. Please read the comments in Channel.java.
- * <p/>
- * Besides the crypto part, this is the core of the library.
- *
- * @author Christian Plattner
- * @version $Id: ChannelManager.java 48 2013-08-01 12:22:33Z cleondris@gmail.com $
- */
-public class ChannelManager implements MessageHandler
-{
-    private static final Logger log = Logger.getLogger(ChannelManager.class);
-
-    private final ServerConnectionState server_state;
-    private final TransportManager tm;
-
-    private final HashMap<String, X11ServerData> x11_magic_cookies = new HashMap<String, X11ServerData>();
-
-    private final List<Channel> channels = new Vector<Channel>();
-    private int nextLocalChannel = 100;
-    private boolean shutdown = false;
-    private int globalSuccessCounter = 0;
-    private int globalFailedCounter = 0;
-
-    private final HashMap<Integer, RemoteForwardingData> remoteForwardings = new HashMap<Integer, RemoteForwardingData>();
-
-    private final List<IChannelWorkerThread> listenerThreads = new Vector<IChannelWorkerThread>();
-
-    private boolean listenerThreadsAllowed = true;
-
-    /**
-     * Constructor for client-mode.
-     * @param tm
-     */
-    public ChannelManager(TransportManager tm)
-    {
-        this.server_state = null;
-        this.tm = tm;
-        tm.registerMessageHandler(this, 80, 100);
-    }
-
-    /**
-     * Constructor for server-mode.
-     * @param state
-     */
-    public ChannelManager(ServerConnectionState state)
-    {
-        this.server_state = state;
-        this.tm = state.tm;
-        tm.registerMessageHandler(this, 80, 100);
-    }
-
-    private Channel getChannel(int id)
-    {
-        synchronized (channels)
-        {
-            for (Channel c : channels)
-            {
-                if (c.localID == id)
-                    return c;
-            }
-        }
-        return null;
-    }
-
-    private void removeChannel(int id)
-    {
-        synchronized (channels)
-        {
-            for (Channel c : channels)
-            {
-                if (c.localID == id)
-                {
-                    channels.remove(c);
-                    break;
-                }
-            }
-        }
-    }
-
-    private int addChannel(Channel c)
-    {
-        synchronized (channels)
-        {
-            channels.add(c);
-            return nextLocalChannel++;
-        }
-    }
-
-    private void waitUntilChannelOpen(Channel c) throws IOException
-    {
-        boolean wasInterrupted = false;
-
-        synchronized (c)
-        {
-            while (c.state == Channel.STATE_OPENING)
-            {
-                try
-                {
-                    c.wait();
-                }
-                catch (InterruptedException ignore)
-                {
-                    wasInterrupted = true;
-                }
-            }
-
-            if (c.state != Channel.STATE_OPEN)
-            {
-                removeChannel(c.localID);
-
-                String detail = c.getReasonClosed();
-
-                if (detail == null)
-                    detail = "state: " + c.state;
-
-                throw new IOException("Could not open channel (" + detail + ")");
-            }
-        }
-
-        if (wasInterrupted)
-            Thread.currentThread().interrupt();
-    }
-
-    private void waitForGlobalSuccessOrFailure() throws IOException
-    {
-        boolean wasInterrupted = false;
-
-        try
-        {
-            synchronized (channels)
-            {
-                while ((globalSuccessCounter == 0) && (globalFailedCounter == 0))
-                {
-                    if (shutdown)
-                    {
-                        throw new IOException("The connection is being shutdown");
-                    }
-
-                    try
-                    {
-                        channels.wait();
-                    }
-                    catch (InterruptedException ignore)
-                    {
-                        wasInterrupted = true;
-                    }
-                }
-
-                if (globalFailedCounter != 0)
-                {
-                    throw new IOException("The server denied the request (did you enable port forwarding?)");
-                }
-
-                if (globalSuccessCounter == 0)
-                {
-                    throw new IOException("Illegal state.");
-                }
-            }
-        }
-        finally
-        {
-            if (wasInterrupted)
-                Thread.currentThread().interrupt();
-        }
-    }
-
-    private void waitForChannelSuccessOrFailure(Channel c) throws IOException
-    {
-        boolean wasInterrupted = false;
-
-        try
-        {
-            synchronized (c)
-            {
-                while ((c.successCounter == 0) && (c.failedCounter == 0))
-                {
-                    if (c.state != Channel.STATE_OPEN)
-                    {
-                        String detail = c.getReasonClosed();
-
-                        if (detail == null)
-                            detail = "state: " + c.state;
-
-                        throw new IOException("This SSH2 channel is not open (" + detail + ")");
-                    }
-
-                    try
-                    {
-                        c.wait();
-                    }
-                    catch (InterruptedException ignore)
-                    {
-                        wasInterrupted = true;
-                    }
-                }
-
-                if (c.failedCounter != 0)
-                {
-                    throw new IOException("The server denied the request.");
-                }
-            }
-        }
-        finally
-        {
-            if (wasInterrupted)
-                Thread.currentThread().interrupt();
-        }
-    }
-
-    public void registerX11Cookie(String hexFakeCookie, X11ServerData data)
-    {
-        synchronized (x11_magic_cookies)
-        {
-            x11_magic_cookies.put(hexFakeCookie, data);
-        }
-    }
-
-    public void unRegisterX11Cookie(String hexFakeCookie, boolean killChannels)
-    {
-        if (hexFakeCookie == null)
-            throw new IllegalStateException("hexFakeCookie may not be null");
-
-        synchronized (x11_magic_cookies)
-        {
-            x11_magic_cookies.remove(hexFakeCookie);
-        }
-
-        if (killChannels == false)
-            return;
-
-        log.debug("Closing all X11 channels for the given fake cookie");
-
-        List<Channel> channel_copy = new Vector<Channel>();
-
-        synchronized (channels)
-        {
-            channel_copy.addAll(channels);
-        }
-
-        for (Channel c : channel_copy)
-        {
-            synchronized (c)
-            {
-                if (hexFakeCookie.equals(c.hexX11FakeCookie) == false)
-                    continue;
-            }
-
-            try
-            {
-                closeChannel(c, "Closing X11 channel since the corresponding session is closing", true);
-            }
-            catch (IOException ignored)
-            {
-            }
-        }
-    }
-
-    public X11ServerData checkX11Cookie(String hexFakeCookie)
-    {
-        synchronized (x11_magic_cookies)
-        {
-            if (hexFakeCookie != null)
-                return x11_magic_cookies.get(hexFakeCookie);
-        }
-        return null;
-    }
-
-    public void closeAllChannels()
-    {
-        log.debug("Closing all channels");
-
-        List<Channel> channel_copy = new Vector<Channel>();
-
-        synchronized (channels)
-        {
-            channel_copy.addAll(channels);
-        }
-
-        for (Channel c : channel_copy)
-        {
-            try
-            {
-                closeChannel(c, "Closing all channels", true);
-            }
-            catch (IOException ignored)
-            {
-            }
-        }
-    }
-
-    public void closeChannel(Channel c, String reason, boolean force) throws IOException
-    {
-        byte msg[] = new byte[5];
-
-        synchronized (c)
-        {
-            if (force)
-            {
-                c.state = Channel.STATE_CLOSED;
-                c.EOF = true;
-            }
-
-            c.setReasonClosed(reason);
-
-            msg[0] = Packets.SSH_MSG_CHANNEL_CLOSE;
-            msg[1] = (byte) (c.remoteID >> 24);
-            msg[2] = (byte) (c.remoteID >> 16);
-            msg[3] = (byte) (c.remoteID >> 8);
-            msg[4] = (byte) (c.remoteID);
-
-            c.notifyAll();
-        }
-
-        synchronized (c.channelSendLock)
-        {
-            if (c.closeMessageSent == true)
-                return;
-            tm.sendMessage(msg);
-            c.closeMessageSent = true;
-        }
-
-        log.debug("Sent SSH_MSG_CHANNEL_CLOSE (channel " + c.localID + ")");
-    }
-
-    public void sendEOF(Channel c) throws IOException
-    {
-        byte[] msg = new byte[5];
-
-        synchronized (c)
-        {
-            if (c.state != Channel.STATE_OPEN)
-                return;
-
-            msg[0] = Packets.SSH_MSG_CHANNEL_EOF;
-            msg[1] = (byte) (c.remoteID >> 24);
-            msg[2] = (byte) (c.remoteID >> 16);
-            msg[3] = (byte) (c.remoteID >> 8);
-            msg[4] = (byte) (c.remoteID);
-        }
-
-        synchronized (c.channelSendLock)
-        {
-            if (c.closeMessageSent == true)
-                return;
-            tm.sendMessage(msg);
-        }
-
-
-        log.debug("Sent EOF (Channel " + c.localID + "/" + c.remoteID + ")");
-    }
-
-    public void sendOpenConfirmation(Channel c) throws IOException
-    {
-        PacketChannelOpenConfirmation pcoc = null;
-
-        synchronized (c)
-        {
-            if (c.state != Channel.STATE_OPENING)
-                return;
-
-            c.state = Channel.STATE_OPEN;
-
-            pcoc = new PacketChannelOpenConfirmation(c.remoteID, c.localID, c.localWindow, c.localMaxPacketSize);
-        }
-
-        synchronized (c.channelSendLock)
-        {
-            if (c.closeMessageSent == true)
-                return;
-            tm.sendMessage(pcoc.getPayload());
-        }
-    }
-
-    public void sendData(Channel c, byte[] buffer, int pos, int len) throws IOException
-    {
-        boolean wasInterrupted = false;
-
-        try
-        {
-            while (len > 0)
-            {
-                int thislen = 0;
-                byte[] msg;
-
-                synchronized (c)
-                {
-                    while (true)
-                    {
-                        if (c.state == Channel.STATE_CLOSED)
-                            throw new ChannelClosedException("SSH channel is closed. (" + c.getReasonClosed() + ")");
-
-                        if (c.state != Channel.STATE_OPEN)
-                            throw new ChannelClosedException("SSH channel in strange state. (" + c.state + ")");
-
-                        if (c.remoteWindow != 0)
-                            break;
-
-                        try
-                        {
-                            c.wait();
-                        }
-                        catch (InterruptedException ignore)
-                        {
-                            wasInterrupted = true;
-                        }
-                    }
-
-                    /* len > 0, no sign extension can happen when comparing */
-
-                    thislen = (c.remoteWindow >= len) ? len : (int) c.remoteWindow;
-
-                    int estimatedMaxDataLen = c.remoteMaxPacketSize - (tm.getPacketOverheadEstimate() + 9);
-
-                    /* The worst case scenario =) a true bottleneck */
-
-                    if (estimatedMaxDataLen <= 0)
-                    {
-                        estimatedMaxDataLen = 1;
-                    }
-
-                    if (thislen > estimatedMaxDataLen)
-                        thislen = estimatedMaxDataLen;
-
-                    c.remoteWindow -= thislen;
-
-                    msg = new byte[1 + 8 + thislen];
-
-                    msg[0] = Packets.SSH_MSG_CHANNEL_DATA;
-                    msg[1] = (byte) (c.remoteID >> 24);
-                    msg[2] = (byte) (c.remoteID >> 16);
-                    msg[3] = (byte) (c.remoteID >> 8);
-                    msg[4] = (byte) (c.remoteID);
-                    msg[5] = (byte) (thislen >> 24);
-                    msg[6] = (byte) (thislen >> 16);
-                    msg[7] = (byte) (thislen >> 8);
-                    msg[8] = (byte) (thislen);
-
-                    System.arraycopy(buffer, pos, msg, 9, thislen);
-                }
-
-                synchronized (c.channelSendLock)
-                {
-                    if (c.closeMessageSent == true)
-                        throw new ChannelClosedException("SSH channel is closed. (" + c.getReasonClosed() + ")");
-
-                    tm.sendMessage(msg);
-                }
-
-                pos += thislen;
-                len -= thislen;
-            }
-        }
-        finally
-        {
-            if (wasInterrupted)
-                Thread.currentThread().interrupt();
-        }
-    }
-
-    public int requestGlobalForward(String bindAddress, int bindPort, String targetAddress, int targetPort)
-            throws IOException
-    {
-        RemoteForwardingData rfd = new RemoteForwardingData();
-
-        rfd.bindAddress = bindAddress;
-        rfd.bindPort = bindPort;
-        rfd.targetAddress = targetAddress;
-        rfd.targetPort = targetPort;
-
-        synchronized (remoteForwardings)
-        {
-            Integer key = new Integer(bindPort);
-
-            if (remoteForwardings.get(key) != null)
-            {
-                throw new IOException("There is already a forwarding for remote port " + bindPort);
-            }
-
-            remoteForwardings.put(key, rfd);
-        }
-
-        synchronized (channels)
-        {
-            globalSuccessCounter = globalFailedCounter = 0;
-        }
-
-        PacketGlobalForwardRequest pgf = new PacketGlobalForwardRequest(true, bindAddress, bindPort);
-        tm.sendMessage(pgf.getPayload());
-
-        log.debug("Requesting a remote forwarding ('" + bindAddress + "', " + bindPort + ")");
-
-        try
-        {
-            waitForGlobalSuccessOrFailure();
-        }
-        catch (IOException e)
-        {
-            synchronized (remoteForwardings)
-            {
-                remoteForwardings.remove(rfd);
-            }
-            throw e;
-        }
-
-        return bindPort;
-    }
-
-    public void requestCancelGlobalForward(int bindPort) throws IOException
-    {
-        RemoteForwardingData rfd = null;
-
-        synchronized (remoteForwardings)
-        {
-            rfd = remoteForwardings.get(new Integer(bindPort));
-
-            if (rfd == null)
-                throw new IOException("Sorry, there is no known remote forwarding for remote port " + bindPort);
-        }
-
-        synchronized (channels)
-        {
-            globalSuccessCounter = globalFailedCounter = 0;
-        }
-
-        PacketGlobalCancelForwardRequest pgcf = new PacketGlobalCancelForwardRequest(true, rfd.bindAddress,
-                rfd.bindPort);
-        tm.sendMessage(pgcf.getPayload());
-
-        log.debug("Requesting cancelation of remote forward ('" + rfd.bindAddress + "', " + rfd.bindPort + ")");
-
-        waitForGlobalSuccessOrFailure();
-
-        /* Only now we are sure that no more forwarded connections will arrive */
-
-        synchronized (remoteForwardings)
-        {
-            remoteForwardings.remove(rfd);
-        }
-    }
-
-    public void registerThread(IChannelWorkerThread thr) throws IOException
-    {
-        synchronized (listenerThreads)
-        {
-            if (listenerThreadsAllowed == false)
-                throw new IOException("Too late, this connection is closed.");
-            listenerThreads.add(thr);
-        }
-    }
-
-    public Channel openDirectTCPIPChannel(String host_to_connect, int port_to_connect, String originator_IP_address,
-                                          int originator_port) throws IOException
-    {
-        Channel c = new Channel(this);
-
-        synchronized (c)
-        {
-            c.localID = addChannel(c);
-            // end of synchronized block forces writing out to main memory
-        }
-
-        PacketOpenDirectTCPIPChannel dtc = new PacketOpenDirectTCPIPChannel(c.localID, c.localWindow,
-                c.localMaxPacketSize, host_to_connect, port_to_connect, originator_IP_address, originator_port);
-
-        tm.sendMessage(dtc.getPayload());
-
-        waitUntilChannelOpen(c);
-
-        return c;
-    }
-
-    public Channel openSessionChannel() throws IOException
-    {
-        Channel c = new Channel(this);
-
-        synchronized (c)
-        {
-            c.localID = addChannel(c);
-            // end of synchronized block forces the writing out to main memory
-        }
-
-        log.debug("Sending SSH_MSG_CHANNEL_OPEN (Channel " + c.localID + ")");
-
-        PacketOpenSessionChannel smo = new PacketOpenSessionChannel(c.localID, c.localWindow, c.localMaxPacketSize);
-        tm.sendMessage(smo.getPayload());
-
-        waitUntilChannelOpen(c);
-
-        return c;
-    }
-
-    public void requestPTY(Channel c, String term, int term_width_characters, int term_height_characters,
-                           int term_width_pixels, int term_height_pixels, byte[] terminal_modes) throws IOException
-    {
-        PacketSessionPtyRequest spr;
-
-        synchronized (c)
-        {
-            if (c.state != Channel.STATE_OPEN)
-                throw new IOException("Cannot request PTY on this channel (" + c.getReasonClosed() + ")");
-
-            spr = new PacketSessionPtyRequest(c.remoteID, true, term, term_width_characters, term_height_characters,
-                    term_width_pixels, term_height_pixels, terminal_modes);
-
-            c.successCounter = c.failedCounter = 0;
-        }
-
-        synchronized (c.channelSendLock)
-        {
-            if (c.closeMessageSent)
-                throw new IOException("Cannot request PTY on this channel (" + c.getReasonClosed() + ")");
-            tm.sendMessage(spr.getPayload());
-        }
-
-        try
-        {
-            waitForChannelSuccessOrFailure(c);
-        }
-        catch (IOException e)
-        {
-            throw (IOException) new IOException("PTY request failed").initCause(e);
-        }
-    }
-
-    public void requestX11(Channel c, boolean singleConnection, String x11AuthenticationProtocol,
-                           String x11AuthenticationCookie, int x11ScreenNumber) throws IOException
-    {
-        PacketSessionX11Request psr;
-
-        synchronized (c)
-        {
-            if (c.state != Channel.STATE_OPEN)
-                throw new IOException("Cannot request X11 on this channel (" + c.getReasonClosed() + ")");
-
-            psr = new PacketSessionX11Request(c.remoteID, true, singleConnection, x11AuthenticationProtocol,
-                    x11AuthenticationCookie, x11ScreenNumber);
-
-            c.successCounter = c.failedCounter = 0;
-        }
-
-        synchronized (c.channelSendLock)
-        {
-            if (c.closeMessageSent)
-                throw new IOException("Cannot request X11 on this channel (" + c.getReasonClosed() + ")");
-            tm.sendMessage(psr.getPayload());
-        }
-
-        log.debug("Requesting X11 forwarding (Channel " + c.localID + "/" + c.remoteID + ")");
-
-        try
-        {
-            waitForChannelSuccessOrFailure(c);
-        }
-        catch (IOException e)
-        {
-            throw (IOException) new IOException("The X11 request failed.").initCause(e);
-        }
-    }
-
-    public void requestSubSystem(Channel c, String subSystemName) throws IOException
-    {
-        PacketSessionSubsystemRequest ssr;
-
-        synchronized (c)
-        {
-            if (c.state != Channel.STATE_OPEN)
-                throw new IOException("Cannot request subsystem on this channel (" + c.getReasonClosed() + ")");
-
-            ssr = new PacketSessionSubsystemRequest(c.remoteID, true, subSystemName);
-
-            c.successCounter = c.failedCounter = 0;
-        }
-
-        synchronized (c.channelSendLock)
-        {
-            if (c.closeMessageSent)
-                throw new IOException("Cannot request subsystem on this channel (" + c.getReasonClosed() + ")");
-            tm.sendMessage(ssr.getPayload());
-        }
-
-        try
-        {
-            waitForChannelSuccessOrFailure(c);
-        }
-        catch (IOException e)
-        {
-            throw (IOException) new IOException("The subsystem request failed.").initCause(e);
-        }
-    }
-
-    public void requestExecCommand(Channel c, String cmd) throws IOException
-    {
-        this.requestExecCommand(c, cmd, null);
-    }
-
-    /**
-     * @param charsetName The charset used to convert between Java Unicode Strings and byte encodings
-     */
-    public void requestExecCommand(Channel c, String cmd, String charsetName) throws IOException
-    {
-        PacketSessionExecCommand sm;
-
-        synchronized (c)
-        {
-            if (c.state != Channel.STATE_OPEN)
-                throw new IOException("Cannot execute command on this channel (" + c.getReasonClosed() + ")");
-
-            sm = new PacketSessionExecCommand(c.remoteID, true, cmd);
-
-            c.successCounter = c.failedCounter = 0;
-        }
-
-        synchronized (c.channelSendLock)
-        {
-            if (c.closeMessageSent)
-                throw new IOException("Cannot execute command on this channel (" + c.getReasonClosed() + ")");
-            tm.sendMessage(sm.getPayload(charsetName));
-        }
-
-        log.debug("Executing command (channel " + c.localID + ", '" + cmd + "')");
-
-        try
-        {
-            waitForChannelSuccessOrFailure(c);
-        }
-        catch (IOException e)
-        {
-            throw (IOException) new IOException("The execute request failed.").initCause(e);
-        }
-    }
-
-    public void requestShell(Channel c) throws IOException
-    {
-        PacketSessionStartShell sm;
-
-        synchronized (c)
-        {
-            if (c.state != Channel.STATE_OPEN)
-                throw new IOException("Cannot start shell on this channel (" + c.getReasonClosed() + ")");
-
-            sm = new PacketSessionStartShell(c.remoteID, true);
-
-            c.successCounter = c.failedCounter = 0;
-        }
-
-        synchronized (c.channelSendLock)
-        {
-            if (c.closeMessageSent)
-                throw new IOException("Cannot start shell on this channel (" + c.getReasonClosed() + ")");
-            tm.sendMessage(sm.getPayload());
-        }
-
-        try
-        {
-            waitForChannelSuccessOrFailure(c);
-        }
-        catch (IOException e)
-        {
-            throw (IOException) new IOException("The shell request failed.").initCause(e);
-        }
-    }
-
-    public void msgChannelExtendedData(byte[] msg, int msglen) throws IOException
-    {
-        if (msglen <= 13)
-            throw new IOException("SSH_MSG_CHANNEL_EXTENDED_DATA message has wrong size (" + msglen + ")");
-
-        int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff);
-        int dataType = ((msg[5] & 0xff) << 24) | ((msg[6] & 0xff) << 16) | ((msg[7] & 0xff) << 8) | (msg[8] & 0xff);
-        int len = ((msg[9] & 0xff) << 24) | ((msg[10] & 0xff) << 16) | ((msg[11] & 0xff) << 8) | (msg[12] & 0xff);
-
-        Channel c = getChannel(id);
-
-        if (c == null)
-            throw new IOException("Unexpected SSH_MSG_CHANNEL_EXTENDED_DATA message for non-existent channel " + id);
-
-        if (dataType != Packets.SSH_EXTENDED_DATA_STDERR)
-            throw new IOException("SSH_MSG_CHANNEL_EXTENDED_DATA message has unknown type (" + dataType + ")");
-
-        if (len != (msglen - 13))
-            throw new IOException("SSH_MSG_CHANNEL_EXTENDED_DATA message has wrong len (calculated " + (msglen - 13)
-                    + ", got " + len + ")");
-
-        log.debug("Got SSH_MSG_CHANNEL_EXTENDED_DATA (channel " + id + ", " + len + ")");
-
-        synchronized (c)
-        {
-            if (c.state == Channel.STATE_CLOSED)
-                return; // ignore
-
-            if (c.state != Channel.STATE_OPEN)
-                throw new IOException("Got SSH_MSG_CHANNEL_EXTENDED_DATA, but channel is not in correct state ("
-                        + c.state + ")");
-
-            if (c.localWindow < len)
-                throw new IOException("Remote sent too much data, does not fit into window.");
-
-            c.localWindow -= len;
-
-            System.arraycopy(msg, 13, c.stderrBuffer, c.stderrWritepos, len);
-            c.stderrWritepos += len;
-
-            c.notifyAll();
-        }
-    }
-
-    /**
-     * Wait until for a condition.
-     *
-     * @param c Channel
-     * @param timeout in ms, 0 means no timeout.
-     * @param condition_mask minimum event mask (at least one of the conditions must be fulfilled)
-     * @return all current events
-     */
-    public int waitForCondition(Channel c, long timeout, int condition_mask)
-    {
-        boolean wasInterrupted = false;
-
-        try
-        {
-            long end_time = 0;
-            boolean end_time_set = false;
-
-            synchronized (c)
-            {
-                while (true)
-                {
-                    int current_cond = 0;
-
-                    int stdoutAvail = c.stdoutWritepos - c.stdoutReadpos;
-                    int stderrAvail = c.stderrWritepos - c.stderrReadpos;
-
-                    if (stdoutAvail > 0)
-                        current_cond = current_cond | ChannelCondition.STDOUT_DATA;
-
-                    if (stderrAvail > 0)
-                        current_cond = current_cond | ChannelCondition.STDERR_DATA;
-
-                    if (c.EOF)
-                        current_cond = current_cond | ChannelCondition.EOF;
-
-                    if (c.getExitStatus() != null)
-                        current_cond = current_cond | ChannelCondition.EXIT_STATUS;
-
-                    if (c.getExitSignal() != null)
-                        current_cond = current_cond | ChannelCondition.EXIT_SIGNAL;
-
-                    if (c.state == Channel.STATE_CLOSED)
-                        return current_cond | ChannelCondition.CLOSED | ChannelCondition.EOF;
-
-                    if ((current_cond & condition_mask) != 0)
-                        return current_cond;
-
-                    if (timeout > 0)
-                    {
-                        if (!end_time_set)
-                        {
-                            end_time = System.currentTimeMillis() + timeout;
-                            end_time_set = true;
-                        }
-                        else
-                        {
-                            timeout = end_time - System.currentTimeMillis();
-
-                            if (timeout <= 0)
-                                return current_cond | ChannelCondition.TIMEOUT;
-                        }
-                    }
-
-                    try
-                    {
-                        if (timeout > 0)
-                            c.wait(timeout);
-                        else
-                            c.wait();
-                    }
-                    catch (InterruptedException e)
-                    {
-                        wasInterrupted = true;
-                    }
-                }
-            }
-        }
-        finally
-        {
-            if (wasInterrupted)
-                Thread.currentThread().interrupt();
-        }
-    }
-
-    public int getAvailable(Channel c, boolean extended) throws IOException
-    {
-        synchronized (c)
-        {
-            int avail;
-
-            if (extended)
-                avail = c.stderrWritepos - c.stderrReadpos;
-            else
-                avail = c.stdoutWritepos - c.stdoutReadpos;
-
-            return ((avail > 0) ? avail : (c.EOF ? -1 : 0));
-        }
-    }
-
-    public int getChannelData(Channel c, boolean extended, byte[] target, int off, int len) throws IOException
-    {
-        boolean wasInterrupted = false;
-
-        try
-        {
-            int copylen = 0;
-            int increment = 0;
-            int remoteID = 0;
-            int localID = 0;
-
-            synchronized (c)
-            {
-                int stdoutAvail = 0;
-                int stderrAvail = 0;
-
-                while (true)
-                {
-                    /*
-                     * Data available? We have to return remaining data even if the
-                     * channel is already closed.
-                     */
-
-                    stdoutAvail = c.stdoutWritepos - c.stdoutReadpos;
-                    stderrAvail = c.stderrWritepos - c.stderrReadpos;
-
-                    if ((!extended) && (stdoutAvail != 0))
-                        break;
-
-                    if ((extended) && (stderrAvail != 0))
-                        break;
-
-                    /* Do not wait if more data will never arrive (EOF or CLOSED) */
-
-                    if ((c.EOF) || (c.state != Channel.STATE_OPEN))
-                        return -1;
-
-                    try
-                    {
-                        c.wait();
-                    }
-                    catch (InterruptedException ignore)
-                    {
-                        wasInterrupted = true;
-                    }
-                }
-
-                /* OK, there is some data. Return it. */
-
-                if (!extended)
-                {
-                    copylen = (stdoutAvail > len) ? len : stdoutAvail;
-                    System.arraycopy(c.stdoutBuffer, c.stdoutReadpos, target, off, copylen);
-                    c.stdoutReadpos += copylen;
-
-                    if (c.stdoutReadpos != c.stdoutWritepos)
-
-                        System.arraycopy(c.stdoutBuffer, c.stdoutReadpos, c.stdoutBuffer, 0, c.stdoutWritepos
-                                - c.stdoutReadpos);
-
-                    c.stdoutWritepos -= c.stdoutReadpos;
-                    c.stdoutReadpos = 0;
-                }
-                else
-                {
-                    copylen = (stderrAvail > len) ? len : stderrAvail;
-                    System.arraycopy(c.stderrBuffer, c.stderrReadpos, target, off, copylen);
-                    c.stderrReadpos += copylen;
-
-                    if (c.stderrReadpos != c.stderrWritepos)
-
-                        System.arraycopy(c.stderrBuffer, c.stderrReadpos, c.stderrBuffer, 0, c.stderrWritepos
-                                - c.stderrReadpos);
-
-                    c.stderrWritepos -= c.stderrReadpos;
-                    c.stderrReadpos = 0;
-                }
-
-                if (c.state != Channel.STATE_OPEN)
-                    return copylen;
-
-                if (c.localWindow < ((Channel.CHANNEL_BUFFER_SIZE + 1) / 2))
-                {
-                    int minFreeSpace = Math.min(Channel.CHANNEL_BUFFER_SIZE - c.stdoutWritepos,
-                            Channel.CHANNEL_BUFFER_SIZE - c.stderrWritepos);
-
-                    increment = minFreeSpace - c.localWindow;
-                    c.localWindow = minFreeSpace;
-                }
-
-                remoteID = c.remoteID; /* read while holding the lock */
-                localID = c.localID; /* read while holding the lock */
-            }
-
-            /*
-             * If a consumer reads stdout and stdin in parallel, we may end up with
-             * sending two msgWindowAdjust messages. Luckily, it
-             * does not matter in which order they arrive at the server.
-             */
-
-            if (increment > 0)
-            {
-                log.debug("Sending SSH_MSG_CHANNEL_WINDOW_ADJUST (channel " + localID + ", " + increment + ")");
-
-                synchronized (c.channelSendLock)
-                {
-                    byte[] msg = c.msgWindowAdjust;
-
-                    msg[0] = Packets.SSH_MSG_CHANNEL_WINDOW_ADJUST;
-                    msg[1] = (byte) (remoteID >> 24);
-                    msg[2] = (byte) (remoteID >> 16);
-                    msg[3] = (byte) (remoteID >> 8);
-                    msg[4] = (byte) (remoteID);
-                    msg[5] = (byte) (increment >> 24);
-                    msg[6] = (byte) (increment >> 16);
-                    msg[7] = (byte) (increment >> 8);
-                    msg[8] = (byte) (increment);
-
-                    if (c.closeMessageSent == false)
-                        tm.sendMessage(msg);
-                }
-            }
-
-            return copylen;
-        }
-        finally
-        {
-            if (wasInterrupted)
-                Thread.currentThread().interrupt();
-        }
-
-    }
-
-    public void msgChannelData(byte[] msg, int msglen) throws IOException
-    {
-        if (msglen <= 9)
-            throw new IOException("SSH_MSG_CHANNEL_DATA message has wrong size (" + msglen + ")");
-
-        int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff);
-        int len = ((msg[5] & 0xff) << 24) | ((msg[6] & 0xff) << 16) | ((msg[7] & 0xff) << 8) | (msg[8] & 0xff);
-
-        Channel c = getChannel(id);
-
-        if (c == null)
-            throw new IOException("Unexpected SSH_MSG_CHANNEL_DATA message for non-existent channel " + id);
-
-        if (len != (msglen - 9))
-            throw new IOException("SSH_MSG_CHANNEL_DATA message has wrong len (calculated " + (msglen - 9) + ", got "
-                    + len + ")");
-
-        log.debug("Got SSH_MSG_CHANNEL_DATA (channel " + id + ", " + len + ")");
-
-        synchronized (c)
-        {
-            if (c.state == Channel.STATE_CLOSED)
-                return; // ignore
-
-            if (c.state != Channel.STATE_OPEN)
-                throw new IOException("Got SSH_MSG_CHANNEL_DATA, but channel is not in correct state (" + c.state + ")");
-
-            if (c.localWindow < len)
-                throw new IOException("Remote sent too much data, does not fit into window.");
-
-            c.localWindow -= len;
-
-            System.arraycopy(msg, 9, c.stdoutBuffer, c.stdoutWritepos, len);
-            c.stdoutWritepos += len;
-
-            c.notifyAll();
-        }
-    }
-
-    public void msgChannelWindowAdjust(byte[] msg, int msglen) throws IOException
-    {
-        if (msglen != 9)
-            throw new IOException("SSH_MSG_CHANNEL_WINDOW_ADJUST message has wrong size (" + msglen + ")");
-
-        int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff);
-        int windowChange = ((msg[5] & 0xff) << 24) | ((msg[6] & 0xff) << 16) | ((msg[7] & 0xff) << 8) | (msg[8] & 0xff);
-
-        Channel c = getChannel(id);
-
-        if (c == null)
-            throw new IOException("Unexpected SSH_MSG_CHANNEL_WINDOW_ADJUST message for non-existent channel " + id);
-
-        synchronized (c)
-        {
-            final long huge = 0xFFFFffffL; /* 2^32 - 1 */
-
-            c.remoteWindow += (windowChange & huge); /* avoid sign extension */
-
-            /* TODO - is this a good heuristic? */
-
-            if ((c.remoteWindow > huge))
-                c.remoteWindow = huge;
-
-            c.notifyAll();
-        }
-
-
-        log.debug("Got SSH_MSG_CHANNEL_WINDOW_ADJUST (channel " + id + ", " + windowChange + ")");
-    }
-
-    public void msgChannelOpen(byte[] msg, int msglen) throws IOException
-    {
-        TypesReader tr = new TypesReader(msg, 0, msglen);
-
-        tr.readByte(); // skip packet type
-        String channelType = tr.readString();
-        int remoteID = tr.readUINT32(); /* sender channel */
-        int remoteWindow = tr.readUINT32(); /* initial window size */
-        int remoteMaxPacketSize = tr.readUINT32(); /* maximum packet size */
-
-        if ("x11".equals(channelType))
-        {
-            synchronized (x11_magic_cookies)
-            {
-                /* If we did not request X11 forwarding, then simply ignore this bogus request. */
-
-                if (x11_magic_cookies.size() == 0)
-                {
-                    PacketChannelOpenFailure pcof = new PacketChannelOpenFailure(remoteID,
-                            Packets.SSH_OPEN_ADMINISTRATIVELY_PROHIBITED, "X11 forwarding not activated", "");
-
-                    tm.sendAsynchronousMessage(pcof.getPayload());
-
-                    log.warning("Unexpected X11 request, denying it!");
-
-                    return;
-                }
-            }
-
-            String remoteOriginatorAddress = tr.readString();
-            int remoteOriginatorPort = tr.readUINT32();
-
-            Channel c = new Channel(this);
-
-            synchronized (c)
-            {
-                c.remoteID = remoteID;
-                c.remoteWindow = remoteWindow & 0xFFFFffffL; /* properly convert UINT32 to long */
-                c.remoteMaxPacketSize = remoteMaxPacketSize;
-                c.localID = addChannel(c);
-            }
-
-            /*
-             * The open confirmation message will be sent from another thread
-             */
-
-            RemoteX11AcceptThread rxat = new RemoteX11AcceptThread(c, remoteOriginatorAddress, remoteOriginatorPort);
-            rxat.setDaemon(true);
-            rxat.start();
-
-            return;
-        }
-
-        if ("forwarded-tcpip".equals(channelType))
-        {
-            String remoteConnectedAddress = tr.readString(); /* address that was connected */
-            int remoteConnectedPort = tr.readUINT32(); /* port that was connected */
-            String remoteOriginatorAddress = tr.readString(); /* originator IP address */
-            int remoteOriginatorPort = tr.readUINT32(); /* originator port */
-
-            RemoteForwardingData rfd = null;
-
-            synchronized (remoteForwardings)
-            {
-                rfd = remoteForwardings.get(new Integer(remoteConnectedPort));
-            }
-
-            if (rfd == null)
-            {
-                PacketChannelOpenFailure pcof = new PacketChannelOpenFailure(remoteID,
-                        Packets.SSH_OPEN_ADMINISTRATIVELY_PROHIBITED,
-                        "No thanks, unknown port in forwarded-tcpip request", "");
-
-                /* Always try to be polite. */
-
-                tm.sendAsynchronousMessage(pcof.getPayload());
-
-                log.debug("Unexpected forwarded-tcpip request, denying it!");
-
-                return;
-            }
-
-            Channel c = new Channel(this);
-
-            synchronized (c)
-            {
-                c.remoteID = remoteID;
-                c.remoteWindow = remoteWindow & 0xFFFFffffL; /* convert UINT32 to long */
-                c.remoteMaxPacketSize = remoteMaxPacketSize;
-                c.localID = addChannel(c);
-            }
-
-            /*
-             * The open confirmation message will be sent from another thread.
-             */
-
-            RemoteAcceptThread rat = new RemoteAcceptThread(c, remoteConnectedAddress, remoteConnectedPort,
-                    remoteOriginatorAddress, remoteOriginatorPort, rfd.targetAddress, rfd.targetPort);
-
-            rat.setDaemon(true);
-            rat.start();
-
-            return;
-        }
-
-        if ((server_state != null) && ("session".equals(channelType)))
-        {
-            ServerConnectionCallback cb = null;
-            
-            synchronized (server_state)
-            {
-                cb = server_state.cb_conn;
-            }
-            
-            if (cb == null)
-            {
-                tm.sendAsynchronousMessage(new PacketChannelOpenFailure(remoteID, Packets.SSH_OPEN_ADMINISTRATIVELY_PROHIBITED,
-                        "Sessions are currently not enabled", "en").getPayload());
-                
-                return;
-            }
-            
-            final Channel c = new Channel(this);
-
-            synchronized (c)
-            {
-                c.remoteID = remoteID;
-                c.remoteWindow = remoteWindow & 0xFFFFffffL; /* convert UINT32 to long */
-                c.remoteMaxPacketSize = remoteMaxPacketSize;
-                c.localID = addChannel(c);
-                c.state = Channel.STATE_OPEN;
-                c.ss = new ServerSessionImpl(c);
-            }
-
-            PacketChannelOpenConfirmation pcoc = new PacketChannelOpenConfirmation(c.remoteID, c.localID,
-                    c.localWindow, c.localMaxPacketSize);
-
-            tm.sendAsynchronousMessage(pcoc.getPayload());
-
-            c.ss.sscb = cb.acceptSession(c.ss);
-
-            return;
-        }
-
-        /* Tell the server that we have no idea what it is talking about */
-
-        PacketChannelOpenFailure pcof = new PacketChannelOpenFailure(remoteID, Packets.SSH_OPEN_UNKNOWN_CHANNEL_TYPE,
-                "Unknown channel type", "");
-
-        tm.sendAsynchronousMessage(pcof.getPayload());
-
-
-        log.warning("The peer tried to open an unsupported channel type (" + channelType + ")");
-    }
-
-    /* Starts the given runnable in a foreground (non-daemon) thread */
-    private void runAsync(Runnable r)
-    {
-        Thread t = new Thread(r);
-        t.start();        
-    }
-    
-    public void msgChannelRequest(byte[] msg, int msglen) throws IOException
-    {
-        TypesReader tr = new TypesReader(msg, 0, msglen);
-
-        tr.readByte(); // skip packet type
-        int id = tr.readUINT32();
-
-        Channel c = getChannel(id);
-
-        if (c == null)
-            throw new IOException("Unexpected SSH_MSG_CHANNEL_REQUEST message for non-existent channel " + id);
-
-        ServerSessionImpl server_session = null;
-
-        if (server_state != null)
-        {
-            synchronized (c)
-            {
-                server_session = c.ss;
-            }
-        }
-
-        String type = tr.readString("US-ASCII");
-        boolean wantReply = tr.readBoolean();
-
-        log.debug("Got SSH_MSG_CHANNEL_REQUEST (channel " + id + ", '" + type + "')");
-
-        if (type.equals("exit-status"))
-        {
-            if (wantReply != false)
-                throw new IOException(
-                        "Badly formatted SSH_MSG_CHANNEL_REQUEST exit-status message, 'want reply' is true");
-
-            int exit_status = tr.readUINT32();
-
-            if (tr.remain() != 0)
-                throw new IOException("Badly formatted SSH_MSG_CHANNEL_REQUEST message");
-
-            synchronized (c)
-            {
-                c.exit_status = new Integer(exit_status);
-                c.notifyAll();
-            }
-
-            log.debug("Got EXIT STATUS (channel " + id + ", status " + exit_status + ")");
-
-            return;
-        }
-
-        if ((server_state == null) && (type.equals("exit-signal")))
-        {
-            if (wantReply != false)
-                throw new IOException(
-                        "Badly formatted SSH_MSG_CHANNEL_REQUEST exit-signal message, 'want reply' is true");
-
-            String signame = tr.readString("US-ASCII");
-            tr.readBoolean();
-            tr.readString();
-            tr.readString();
-
-            if (tr.remain() != 0)
-                throw new IOException("Badly formatted SSH_MSG_CHANNEL_REQUEST message");
-
-            synchronized (c)
-            {
-                c.exit_signal = signame;
-                c.notifyAll();
-            }
-
-            log.debug("Got EXIT SIGNAL (channel " + id + ", signal " + signame + ")");
-
-            return;
-        }
-
-        if ((server_session != null) && (type.equals("pty-req")))
-        {
-            PtySettings pty = new PtySettings();
-
-            pty.term = tr.readString();
-            pty.term_width_characters = tr.readUINT32();
-            pty.term_height_characters = tr.readUINT32();
-            pty.term_width_pixels = tr.readUINT32();
-            pty.term_height_pixels = tr.readUINT32();
-            pty.terminal_modes = tr.readByteString();
-
-            if (tr.remain() != 0)
-                throw new IOException("Badly formatted SSH_MSG_CHANNEL_REQUEST message");
-            
-            Runnable run_after_sending_success = null;
-            
-            ServerSessionCallback sscb = server_session.getServerSessionCallback();
-
-            if (sscb != null)
-                run_after_sending_success = sscb.requestPtyReq(server_session, pty);
-
-            if (wantReply)
-            {
-                if (run_after_sending_success != null)
-                {
-                    tm.sendAsynchronousMessage(new PacketChannelSuccess(c.remoteID).getPayload());
-                }
-                else
-                {
-                    tm.sendAsynchronousMessage(new PacketChannelFailure(c.remoteID).getPayload());
-                }            
-            }
-            
-            if (run_after_sending_success != null)
-            {
-                runAsync(run_after_sending_success);
-            }
-            
-            return;
-        }
-        
-        if ((server_session != null) && (type.equals("subsystem")))
-        {
-            String command = tr.readString();
-            if (tr.remain() != 0)
-                throw new IOException("Badly formatted SSH_MSG_CHANNEL_REQUEST message");
-            
-            Runnable run_after_sending_success = null;
-            ServerSessionCallback sscb = server_session.getServerSessionCallback();
-
-            if (sscb != null)
-                run_after_sending_success = sscb.requestSubsystem(server_session, command);
-
-            if (wantReply)
-            {
-                if (run_after_sending_success != null)
-                {
-                    tm.sendAsynchronousMessage(new PacketChannelSuccess(c.remoteID).getPayload());
-                }
-                else
-                {
-                    tm.sendAsynchronousMessage(new PacketChannelFailure(c.remoteID).getPayload());
-                }
-            }
-            
-            if (run_after_sending_success != null)
-            {
-                runAsync(run_after_sending_success);
-            }
-            
-            return;
-        }
-
-        if ((server_session != null) && (type.equals("shell")))
-        {
-            if (tr.remain() != 0)
-                throw new IOException("Badly formatted SSH_MSG_CHANNEL_REQUEST message");
-            
-            Runnable run_after_sending_success = null;
-            ServerSessionCallback sscb = server_session.getServerSessionCallback();
-
-            if (sscb != null)
-                run_after_sending_success = sscb.requestShell(server_session);
-
-            if (wantReply)
-            {
-                if (run_after_sending_success != null)
-                {
-                    tm.sendAsynchronousMessage(new PacketChannelSuccess(c.remoteID).getPayload());
-                }
-                else
-                {
-                    tm.sendAsynchronousMessage(new PacketChannelFailure(c.remoteID).getPayload());
-                }
-            }
-            
-            if (run_after_sending_success != null)
-            {
-                runAsync(run_after_sending_success);
-            }
-            
-            return;
-        }
-        
-        if ((server_session != null) && (type.equals("exec")))
-        {
-            String command = tr.readString();
-            
-            if (tr.remain() != 0)
-                throw new IOException("Badly formatted SSH_MSG_CHANNEL_REQUEST message");
-            
-            Runnable run_after_sending_success = null;
-            ServerSessionCallback sscb = server_session.getServerSessionCallback();
-
-            if (sscb != null)
-                run_after_sending_success = sscb.requestExec(server_session, command);
-
-            if (wantReply)
-            {
-                if (run_after_sending_success != null)
-                {
-                    tm.sendAsynchronousMessage(new PacketChannelSuccess(c.remoteID).getPayload());
-                }
-                else
-                {
-                    tm.sendAsynchronousMessage(new PacketChannelFailure(c.remoteID).getPayload());
-                }
-            }
-            
-            if (run_after_sending_success != null)
-            {
-                runAsync(run_after_sending_success);
-            }
-            
-            return;
-        }
-
-        /* We simply ignore unknown channel requests, however, if the server wants a reply,
-         * then we signal that we have no idea what it is about.
-         */
-
-        if (wantReply)
-        {
-            tm.sendAsynchronousMessage(new PacketChannelFailure(c.remoteID).getPayload());
-        }
-
-        log.debug("Channel request '" + type + "' is not known, ignoring it");
-    }
-
-    public void msgChannelEOF(byte[] msg, int msglen) throws IOException
-    {
-        if (msglen != 5)
-            throw new IOException("SSH_MSG_CHANNEL_EOF message has wrong size (" + msglen + ")");
-
-        int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff);
-
-        Channel c = getChannel(id);
-
-        if (c == null)
-            throw new IOException("Unexpected SSH_MSG_CHANNEL_EOF message for non-existent channel " + id);
-
-        synchronized (c)
-        {
-            c.EOF = true;
-            c.notifyAll();
-        }
-
-        log.debug("Got SSH_MSG_CHANNEL_EOF (channel " + id + ")");
-    }
-
-    public void msgChannelClose(byte[] msg, int msglen) throws IOException
-    {
-        if (msglen != 5)
-            throw new IOException("SSH_MSG_CHANNEL_CLOSE message has wrong size (" + msglen + ")");
-
-        int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff);
-
-        Channel c = getChannel(id);
-
-        if (c == null)
-            throw new IOException("Unexpected SSH_MSG_CHANNEL_CLOSE message for non-existent channel " + id);
-
-        synchronized (c)
-        {
-            c.EOF = true;
-            c.state = Channel.STATE_CLOSED;
-            c.setReasonClosed("Close requested by remote");
-            c.closeMessageRecv = true;
-
-            removeChannel(c.localID);
-
-            c.notifyAll();
-        }
-
-        log.debug("Got SSH_MSG_CHANNEL_CLOSE (channel " + id + ")");
-    }
-
-    public void msgChannelSuccess(byte[] msg, int msglen) throws IOException
-    {
-        if (msglen != 5)
-            throw new IOException("SSH_MSG_CHANNEL_SUCCESS message has wrong size (" + msglen + ")");
-
-        int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff);
-
-        Channel c = getChannel(id);
-
-        if (c == null)
-            throw new IOException("Unexpected SSH_MSG_CHANNEL_SUCCESS message for non-existent channel " + id);
-
-        synchronized (c)
-        {
-            c.successCounter++;
-            c.notifyAll();
-        }
-
-        log.debug("Got SSH_MSG_CHANNEL_SUCCESS (channel " + id + ")");
-    }
-
-    public void msgChannelFailure(byte[] msg, int msglen) throws IOException
-    {
-        if (msglen != 5)
-            throw new IOException("SSH_MSG_CHANNEL_FAILURE message has wrong size (" + msglen + ")");
-
-        int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff);
-
-        Channel c = getChannel(id);
-
-        if (c == null)
-            throw new IOException("Unexpected SSH_MSG_CHANNEL_FAILURE message for non-existent channel " + id);
-
-        synchronized (c)
-        {
-            c.failedCounter++;
-            c.notifyAll();
-        }
-
-        log.debug("Got SSH_MSG_CHANNEL_FAILURE (channel " + id + ")");
-    }
-
-    public void msgChannelOpenConfirmation(byte[] msg, int msglen) throws IOException
-    {
-        PacketChannelOpenConfirmation sm = new PacketChannelOpenConfirmation(msg, 0, msglen);
-
-        Channel c = getChannel(sm.recipientChannelID);
-
-        if (c == null)
-            throw new IOException("Unexpected SSH_MSG_CHANNEL_OPEN_CONFIRMATION message for non-existent channel "
-                    + sm.recipientChannelID);
-
-        synchronized (c)
-        {
-            if (c.state != Channel.STATE_OPENING)
-                throw new IOException("Unexpected SSH_MSG_CHANNEL_OPEN_CONFIRMATION message for channel "
-                        + sm.recipientChannelID);
-
-            c.remoteID = sm.senderChannelID;
-            c.remoteWindow = sm.initialWindowSize & 0xFFFFffffL; /* convert UINT32 to long */
-            c.remoteMaxPacketSize = sm.maxPacketSize;
-            c.state = Channel.STATE_OPEN;
-            c.notifyAll();
-        }
-
-        log.debug("Got SSH_MSG_CHANNEL_OPEN_CONFIRMATION (channel " + sm.recipientChannelID + " / remote: "
-                + sm.senderChannelID + ")");
-    }
-
-    public void msgChannelOpenFailure(byte[] msg, int msglen) throws IOException
-    {
-        if (msglen < 5)
-            throw new IOException("SSH_MSG_CHANNEL_OPEN_FAILURE message has wrong size (" + msglen + ")");
-
-        TypesReader tr = new TypesReader(msg, 0, msglen);
-
-        tr.readByte(); // skip packet type
-        int id = tr.readUINT32(); /* sender channel */
-
-        Channel c = getChannel(id);
-
-        if (c == null)
-            throw new IOException("Unexpected SSH_MSG_CHANNEL_OPEN_FAILURE message for non-existent channel " + id);
-
-        int reasonCode = tr.readUINT32();
-        String description = tr.readString("UTF-8");
-
-        String reasonCodeSymbolicName = null;
-
-        switch (reasonCode)
-        {
-            case 1:
-                reasonCodeSymbolicName = "SSH_OPEN_ADMINISTRATIVELY_PROHIBITED";
-                break;
-            case 2:
-                reasonCodeSymbolicName = "SSH_OPEN_CONNECT_FAILED";
-                break;
-            case 3:
-                reasonCodeSymbolicName = "SSH_OPEN_UNKNOWN_CHANNEL_TYPE";
-                break;
-            case 4:
-                reasonCodeSymbolicName = "SSH_OPEN_RESOURCE_SHORTAGE";
-                break;
-            default:
-                reasonCodeSymbolicName = "UNKNOWN REASON CODE (" + reasonCode + ")";
-        }
-
-        StringBuilder descriptionBuffer = new StringBuilder();
-        descriptionBuffer.append(description);
-
-        for (int i = 0; i < descriptionBuffer.length(); i++)
-        {
-            char cc = descriptionBuffer.charAt(i);
-
-            if ((cc >= 32) && (cc <= 126))
-                continue;
-            descriptionBuffer.setCharAt(i, '\uFFFD');
-        }
-
-        synchronized (c)
-        {
-            c.EOF = true;
-            c.state = Channel.STATE_CLOSED;
-            c.setReasonClosed("The server refused to open the channel (" + reasonCodeSymbolicName + ", '"
-                    + descriptionBuffer.toString() + "')");
-            c.notifyAll();
-        }
-
-        log.debug("Got SSH_MSG_CHANNEL_OPEN_FAILURE (channel " + id + ")");
-    }
-
-    public void msgGlobalRequest(byte[] msg, int msglen) throws IOException
-    {
-        /* Currently we do not support any kind of global request */
-
-        TypesReader tr = new TypesReader(msg, 0, msglen);
-
-        tr.readByte(); // skip packet type
-        String requestName = tr.readString();
-        boolean wantReply = tr.readBoolean();
-
-        if (wantReply)
-        {
-            byte[] reply_failure = new byte[1];
-            reply_failure[0] = Packets.SSH_MSG_REQUEST_FAILURE;
-
-            tm.sendAsynchronousMessage(reply_failure);
-        }
-
-        /* We do not clean up the requestName String - that is OK for debug */
-
-        log.debug("Got SSH_MSG_GLOBAL_REQUEST (" + requestName + ")");
-    }
-
-    public void msgGlobalSuccess() throws IOException
-    {
-        synchronized (channels)
-        {
-            globalSuccessCounter++;
-            channels.notifyAll();
-        }
-
-        log.debug("Got SSH_MSG_REQUEST_SUCCESS");
-    }
-
-    public void msgGlobalFailure() throws IOException
-    {
-        synchronized (channels)
-        {
-            globalFailedCounter++;
-            channels.notifyAll();
-        }
-
-        log.debug("Got SSH_MSG_REQUEST_FAILURE");
-    }
-
-    public void handleMessage(byte[] msg, int msglen) throws IOException
-    {
-        if (msg == null)
-        {
-
-            log.debug("HandleMessage: got shutdown");
-
-            synchronized (listenerThreads)
-            {
-                for (IChannelWorkerThread lat : listenerThreads)
-                {
-                    lat.stopWorking();
-                }
-                listenerThreadsAllowed = false;
-            }
-
-            synchronized (channels)
-            {
-                shutdown = true;
-
-                for (Channel c : channels)
-                {
-                    synchronized (c)
-                    {
-                        c.EOF = true;
-                        c.state = Channel.STATE_CLOSED;
-                        c.setReasonClosed("The connection is being shutdown");
-                        c.closeMessageRecv = true; /*
-                                                    * You never know, perhaps
-                                                    * we are waiting for a
-                                                    * pending close message
-                                                    * from the server...
-                                                    */
-                        c.notifyAll();
-                    }
-                }
-
-                channels.clear();
-                channels.notifyAll(); /* Notify global response waiters */
-                return;
-            }
-        }
-
-        switch (msg[0])
-        {
-            case Packets.SSH_MSG_CHANNEL_OPEN_CONFIRMATION:
-                msgChannelOpenConfirmation(msg, msglen);
-                break;
-            case Packets.SSH_MSG_CHANNEL_WINDOW_ADJUST:
-                msgChannelWindowAdjust(msg, msglen);
-                break;
-            case Packets.SSH_MSG_CHANNEL_DATA:
-                msgChannelData(msg, msglen);
-                break;
-            case Packets.SSH_MSG_CHANNEL_EXTENDED_DATA:
-                msgChannelExtendedData(msg, msglen);
-                break;
-            case Packets.SSH_MSG_CHANNEL_REQUEST:
-                msgChannelRequest(msg, msglen);
-                break;
-            case Packets.SSH_MSG_CHANNEL_EOF:
-                msgChannelEOF(msg, msglen);
-                break;
-            case Packets.SSH_MSG_CHANNEL_OPEN:
-                msgChannelOpen(msg, msglen);
-                break;
-            case Packets.SSH_MSG_CHANNEL_CLOSE:
-                msgChannelClose(msg, msglen);
-                break;
-            case Packets.SSH_MSG_CHANNEL_SUCCESS:
-                msgChannelSuccess(msg, msglen);
-                break;
-            case Packets.SSH_MSG_CHANNEL_FAILURE:
-                msgChannelFailure(msg, msglen);
-                break;
-            case Packets.SSH_MSG_CHANNEL_OPEN_FAILURE:
-                msgChannelOpenFailure(msg, msglen);
-                break;
-            case Packets.SSH_MSG_GLOBAL_REQUEST:
-                msgGlobalRequest(msg, msglen);
-                break;
-            case Packets.SSH_MSG_REQUEST_SUCCESS:
-                msgGlobalSuccess();
-                break;
-            case Packets.SSH_MSG_REQUEST_FAILURE:
-                msgGlobalFailure();
-                break;
-            default:
-                throw new IOException("Cannot handle unknown channel message " + (msg[0] & 0xff));
-        }
-    }
-}
diff --git a/third-party/ganymed/src/main/java/ch/ethz/ssh2/transport/TransportManager.java b/third-party/ganymed/src/main/java/ch/ethz/ssh2/transport/TransportManager.java
deleted file mode 100644 (file)
index 9632670..0000000
+++ /dev/null
@@ -1,990 +0,0 @@
-/*
- * Copyright (c) 2006-2013 Christian Plattner. All rights reserved.
- * Please refer to the LICENSE.txt for licensing details.
- */
-
-package ch.ethz.ssh2.transport;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.Socket;
-import java.net.SocketTimeoutException;
-import java.net.UnknownHostException;
-import java.security.SecureRandom;
-import java.util.List;
-import java.util.Vector;
-
-import ch.ethz.ssh2.ConnectionInfo;
-import ch.ethz.ssh2.ConnectionMonitor;
-import ch.ethz.ssh2.DHGexParameters;
-import ch.ethz.ssh2.HTTPProxyData;
-import ch.ethz.ssh2.HTTPProxyException;
-import ch.ethz.ssh2.ProxyData;
-import ch.ethz.ssh2.ServerHostKeyVerifier;
-import ch.ethz.ssh2.crypto.Base64;
-import ch.ethz.ssh2.crypto.CryptoWishList;
-import ch.ethz.ssh2.crypto.cipher.BlockCipher;
-import ch.ethz.ssh2.crypto.digest.MAC;
-import ch.ethz.ssh2.log.Logger;
-import ch.ethz.ssh2.packets.PacketDisconnect;
-import ch.ethz.ssh2.packets.Packets;
-import ch.ethz.ssh2.packets.TypesReader;
-import ch.ethz.ssh2.server.ServerConnectionState;
-import ch.ethz.ssh2.signature.DSAPrivateKey;
-import ch.ethz.ssh2.signature.RSAPrivateKey;
-import ch.ethz.ssh2.util.StringEncoder;
-import ch.ethz.ssh2.util.Tokenizer;
-
-/*
- * Yes, the "standard" is a big mess. On one side, the say that arbitary channel
- * packets are allowed during kex exchange, on the other side we need to blindly
- * ignore the next _packet_ if the KEX guess was wrong. Where do we know from that
- * the next packet is not a channel data packet? Yes, we could check if it is in
- * the KEX range. But the standard says nothing about this. The OpenSSH guys
- * block local "normal" traffic during KEX. That's fine - however, they assume
- * that the other side is doing the same. During re-key, if they receive traffic
- * other than KEX, they become horribly irritated and kill the connection. Since
- * we are very likely going to communicate with OpenSSH servers, we have to play
- * the same game - even though we could do better.
- * 
- * btw: having stdout and stderr on the same channel, with a shared window, is
- * also a VERY good idea... =(
- */
-
-/**
- * TransportManager.
- *
- * @author Christian Plattner
- * @version $Id: TransportManager.java 47 2013-07-31 23:59:52Z cleondris@gmail.com $
- */
-public class TransportManager
-{
-    private static final Logger log = Logger.getLogger(TransportManager.class);
-
-    private static class HandlerEntry
-    {
-        MessageHandler mh;
-        int low;
-        int high;
-    }
-
-    private final List<AsynchronousEntry> asynchronousQueue = new Vector<AsynchronousEntry>();
-    private Thread asynchronousThread = null;
-    private boolean asynchronousPending = false;
-
-    class AsynchronousEntry
-    {
-        public byte[] msg;
-        public Runnable run;
-
-        public AsynchronousEntry(byte[] msg, Runnable run)
-        {
-            this.msg = msg;
-            this.run = run;
-        }
-    }
-
-    class AsynchronousWorker extends Thread
-    {
-        @Override
-        public void run()
-        {
-            while (true)
-            {
-                AsynchronousEntry item = null;
-
-                synchronized (asynchronousQueue)
-                {
-                    if (asynchronousQueue.size() == 0)
-                    {
-                                               /* Only now we may reset the flag, since we are sure that all queued items
-                                                * have been sent (there is a slight delay between de-queuing and sending,
-                                                * this is why we need this flag! See code below. Sending takes place outside
-                                                * of this lock, this is why a test for size()==0 (from another thread) does not ensure
-                                                * that all messages have been sent.
-                                                */
-
-                        asynchronousPending = false;
-
-                                               /* Notify any senders that they can proceed, all async messages have been delivered */
-
-                        asynchronousQueue.notifyAll();
-
-                                               /* After the queue is empty for about 2 seconds, stop this thread */
-
-                        try
-                        {
-                            asynchronousQueue.wait(2000);
-                        }
-                        catch (InterruptedException ignore)
-                        {
-                        }
-
-                        if (asynchronousQueue.size() == 0)
-                        {
-                            asynchronousThread = null;
-                            return;
-                        }
-                    }
-
-                    item = asynchronousQueue.remove(0);
-                }
-
-                               /* The following invocation may throw an IOException.
-                                * There is no point in handling it - it simply means
-                                * that the connection has a problem and we should stop
-                                * sending asynchronously messages. We do not need to signal that
-                                * we have exited (asynchronousThread = null): further
-                                * messages in the queue cannot be sent by this or any
-                                * other thread.
-                                * Other threads will sooner or later (when receiving or
-                                * sending the next message) get the same IOException and
-                                * get to the same conclusion.
-                                */
-
-                try
-                {
-                    sendMessageImmediate(item.msg);
-                }
-                catch (IOException e)
-                {
-                    return;
-                }
-
-                if (item.run != null)
-                {
-                    try
-                    {
-                        item.run.run();
-                    }
-                    catch (Exception ignore)
-                    {
-                    }
-
-                }
-            }
-        }
-    }
-
-    private Socket sock = new Socket();
-
-    private final Object connectionSemaphore = new Object();
-
-    private boolean flagKexOngoing = false;
-    private boolean connectionClosed = false;
-
-    private Throwable reasonClosedCause = null;
-
-    private TransportConnection tc;
-    private KexManager km;
-
-    private final List<HandlerEntry> messageHandlers = new Vector<HandlerEntry>();
-
-    private Thread receiveThread;
-
-    private List<ConnectionMonitor> connectionMonitors = new Vector<ConnectionMonitor>();
-    private boolean monitorsWereInformed = false;
-
-    /**
-     * There were reports that there are JDKs which use
-     * the resolver even though one supplies a dotted IP
-     * address in the Socket constructor. That is why we
-     * try to generate the InetAdress "by hand".
-     *
-     * @param host
-     * @return the InetAddress
-     * @throws UnknownHostException
-     */
-    private static InetAddress createInetAddress(String host) throws UnknownHostException
-    {
-               /* Check if it is a dotted IP4 address */
-
-        InetAddress addr = parseIPv4Address(host);
-
-        if (addr != null)
-        {
-            return addr;
-        }
-
-        return InetAddress.getByName(host);
-    }
-
-    private static InetAddress parseIPv4Address(String host) throws UnknownHostException
-    {
-        if (host == null)
-        {
-            return null;
-        }
-
-        String[] quad = Tokenizer.parseTokens(host, '.');
-
-        if ((quad == null) || (quad.length != 4))
-        {
-            return null;
-        }
-
-        byte[] addr = new byte[4];
-
-        for (int i = 0; i < 4; i++)
-        {
-            int part = 0;
-
-            if ((quad[i].length() == 0) || (quad[i].length() > 3))
-            {
-                return null;
-            }
-
-            for (int k = 0; k < quad[i].length(); k++)
-            {
-                char c = quad[i].charAt(k);
-
-                               /* No, Character.isDigit is not the same */
-                if ((c < '0') || (c > '9'))
-                {
-                    return null;
-                }
-
-                part = part * 10 + (c - '0');
-            }
-
-            if (part > 255) /* 300.1.2.3 is invalid =) */
-            {
-                return null;
-            }
-
-            addr[i] = (byte) part;
-        }
-
-        return InetAddress.getByAddress(host, addr);
-    }
-
-    public int getPacketOverheadEstimate()
-    {
-        return tc.getPacketOverheadEstimate();
-    }
-
-    public void setTcpNoDelay(boolean state) throws IOException
-    {
-        sock.setTcpNoDelay(state);
-    }
-
-    public void setSoTimeout(int timeout) throws IOException
-    {
-        sock.setSoTimeout(timeout);
-    }
-
-    public ConnectionInfo getConnectionInfo(int kexNumber) throws IOException
-    {
-        return km.getOrWaitForConnectionInfo(kexNumber);
-    }
-
-    public Throwable getReasonClosedCause()
-    {
-        synchronized (connectionSemaphore)
-        {
-            return reasonClosedCause;
-        }
-    }
-
-    public byte[] getSessionIdentifier()
-    {
-        return km.sessionId;
-    }
-
-    public void close(Throwable cause, boolean useDisconnectPacket)
-    {
-        if (useDisconnectPacket == false)
-        {
-                       /* OK, hard shutdown - do not aquire the semaphore,
-                        * perhaps somebody is inside (and waits until the remote
-                        * side is ready to accept new data). */
-
-            try
-            {
-                sock.close();
-            }
-            catch (IOException ignore)
-            {
-            }
-
-                       /* OK, whoever tried to send data, should now agree that
-                        * there is no point in further waiting =)
-                        * It is safe now to aquire the semaphore.
-                        */
-        }
-
-        synchronized (connectionSemaphore)
-        {
-            if (connectionClosed == false)
-            {
-                if (useDisconnectPacket == true)
-                {
-                    try
-                    {
-                        byte[] msg = new PacketDisconnect(Packets.SSH_DISCONNECT_BY_APPLICATION, cause.getMessage(), "")
-                                .getPayload();
-                        if (tc != null)
-                        {
-                            tc.sendMessage(msg);
-                        }
-                    }
-                    catch (IOException ignore)
-                    {
-                    }
-
-                    try
-                    {
-                        sock.close();
-                    }
-                    catch (IOException ignore)
-                    {
-                    }
-                }
-
-                connectionClosed = true;
-                reasonClosedCause = cause; /* may be null */
-            }
-            connectionSemaphore.notifyAll();
-        }
-
-               /* No check if we need to inform the monitors */
-
-        List<ConnectionMonitor> monitors = new Vector<ConnectionMonitor>();
-
-        synchronized (this)
-        {
-                       /* Short term lock to protect "connectionMonitors"
-                        * and "monitorsWereInformed"
-                        * (they may be modified concurrently)
-                        */
-
-            if (monitorsWereInformed == false)
-            {
-                monitorsWereInformed = true;
-                monitors.addAll(connectionMonitors);
-            }
-        }
-
-        for (ConnectionMonitor cmon : monitors)
-        {
-            try
-            {
-                cmon.connectionLost(reasonClosedCause);
-            }
-            catch (Exception ignore)
-            {
-            }
-        }
-    }
-
-    private static Socket establishConnection(String hostname, int port, ProxyData proxyData, int connectTimeout)
-            throws IOException
-    {
-               /* See the comment for createInetAddress() */
-
-        if (proxyData == null)
-        {
-            InetAddress addr = createInetAddress(hostname);
-            Socket s = new Socket();
-            s.connect(new InetSocketAddress(addr, port), connectTimeout);
-            return s;
-        }
-
-        if (proxyData instanceof HTTPProxyData)
-        {
-            HTTPProxyData pd = (HTTPProxyData) proxyData;
-
-                       /* At the moment, we only support HTTP proxies */
-
-            InetAddress addr = createInetAddress(pd.proxyHost);
-            Socket s = new Socket();
-            s.connect(new InetSocketAddress(addr, pd.proxyPort), connectTimeout);
-
-                       /* OK, now tell the proxy where we actually want to connect to */
-
-            StringBuilder sb = new StringBuilder();
-
-            sb.append("CONNECT ");
-            sb.append(hostname);
-            sb.append(':');
-            sb.append(port);
-            sb.append(" HTTP/1.0\r\n");
-
-            if ((pd.proxyUser != null) && (pd.proxyPass != null))
-            {
-                String credentials = pd.proxyUser + ":" + pd.proxyPass;
-                char[] encoded = Base64.encode(StringEncoder.GetBytes(credentials));
-                sb.append("Proxy-Authorization: Basic ");
-                sb.append(encoded);
-                sb.append("\r\n");
-            }
-
-            if (pd.requestHeaderLines != null)
-            {
-                for (int i = 0; i < pd.requestHeaderLines.length; i++)
-                {
-                    if (pd.requestHeaderLines[i] != null)
-                    {
-                        sb.append(pd.requestHeaderLines[i]);
-                        sb.append("\r\n");
-                    }
-                }
-            }
-
-            sb.append("\r\n");
-
-            OutputStream out = s.getOutputStream();
-
-            out.write(StringEncoder.GetBytes(sb.toString()));
-            out.flush();
-
-                       /* Now parse the HTTP response */
-
-            byte[] buffer = new byte[1024];
-            InputStream in = s.getInputStream();
-
-            int len = ClientServerHello.readLineRN(in, buffer);
-
-            String httpReponse = StringEncoder.GetString(buffer, 0, len);
-
-            if (httpReponse.startsWith("HTTP/") == false)
-            {
-                throw new IOException("The proxy did not send back a valid HTTP response.");
-            }
-
-                       /* "HTTP/1.X XYZ X" => 14 characters minimum */
-
-            if ((httpReponse.length() < 14) || (httpReponse.charAt(8) != ' ') || (httpReponse.charAt(12) != ' '))
-            {
-                throw new IOException("The proxy did not send back a valid HTTP response.");
-            }
-
-            int errorCode = 0;
-
-            try
-            {
-                errorCode = Integer.parseInt(httpReponse.substring(9, 12));
-            }
-            catch (NumberFormatException ignore)
-            {
-                throw new IOException("The proxy did not send back a valid HTTP response.");
-            }
-
-            if ((errorCode < 0) || (errorCode > 999))
-            {
-                throw new IOException("The proxy did not send back a valid HTTP response.");
-            }
-
-            if (errorCode != 200)
-            {
-                throw new HTTPProxyException(httpReponse.substring(13), errorCode);
-            }
-
-                       /* OK, read until empty line */
-
-            while (true)
-            {
-                len = ClientServerHello.readLineRN(in, buffer);
-                if (len == 0)
-                {
-                    break;
-                }
-            }
-            return s;
-        }
-
-        throw new IOException("Unsupported ProxyData");
-    }
-
-    private void startReceiver() throws IOException
-    {
-        receiveThread = new Thread(new Runnable()
-        {
-            public void run()
-            {
-                try
-                {
-                    receiveLoop();
-                }
-                catch (Exception e)
-                {
-                    close(e, false);
-
-                    log.warning("Receive thread: error in receiveLoop: " + e.getMessage());
-                }
-
-                if (log.isDebugEnabled())
-                {
-                    log.debug("Receive thread: back from receiveLoop");
-                }
-
-                               /* Tell all handlers that it is time to say goodbye */
-
-                if (km != null)
-                {
-                    try
-                    {
-                        km.handleMessage(null, 0);
-                    }
-                    catch (IOException ignored)
-                    {
-                    }
-                }
-
-                for (HandlerEntry he : messageHandlers)
-                {
-                    try
-                    {
-                        he.mh.handleMessage(null, 0);
-                    }
-                    catch (Exception ignore)
-                    {
-                    }
-                }
-            }
-        });
-
-        receiveThread.setDaemon(true);
-        receiveThread.start();
-    }
-
-    public void clientInit(Socket socket, String softwareversion, CryptoWishList cwl,
-                           ServerHostKeyVerifier verifier, DHGexParameters dhgex, SecureRandom rnd) throws IOException
-    {
-               /* First, establish the TCP connection to the SSH-2 server */
-
-        sock = socket;
-
-               /* Parse the server line and say hello - important: this information is later needed for the
-                * key exchange (to stop man-in-the-middle attacks) - that is why we wrap it into an object
-                * for later use.
-                */
-
-        ClientServerHello csh = ClientServerHello.clientHello(softwareversion, sock.getInputStream(),
-                sock.getOutputStream());
-
-        tc = new TransportConnection(sock.getInputStream(), sock.getOutputStream(), rnd);
-        String hostname = sock.getInetAddress().getHostName();
-        int port = sock.getPort();
-
-        km = new ClientKexManager(this, csh, cwl, hostname, port, verifier, rnd);
-        km.initiateKEX(cwl, dhgex, null, null);
-
-        startReceiver();
-    }
-
-    public void clientInit(String hostname, int port, String softwareversion, CryptoWishList cwl,
-                           ServerHostKeyVerifier verifier, DHGexParameters dhgex, int connectTimeout, SecureRandom rnd,
-                           ProxyData proxyData) throws IOException
-    {
-               /* First, establish the TCP connection to the SSH-2 server */
-
-        sock = establishConnection(hostname, port, proxyData, connectTimeout);
-
-               /* Parse the server line and say hello - important: this information is later needed for the
-                * key exchange (to stop man-in-the-middle attacks) - that is why we wrap it into an object
-                * for later use.
-                */
-
-        ClientServerHello csh = ClientServerHello.clientHello(softwareversion, sock.getInputStream(),
-                sock.getOutputStream());
-
-        tc = new TransportConnection(sock.getInputStream(), sock.getOutputStream(), rnd);
-
-        km = new ClientKexManager(this, csh, cwl, hostname, port, verifier, rnd);
-        km.initiateKEX(cwl, dhgex, null, null);
-
-        startReceiver();
-    }
-
-    public void serverInit(ServerConnectionState state) throws IOException
-    {
-               /* TCP connection is already established */
-
-        this.sock = state.s;
-
-               /* Parse the client line and say hello - important: this information is later needed for the
-                * key exchange (to stop man-in-the-middle attacks) - that is why we wrap it into an object
-                * for later use.
-                */
-
-        state.csh = ClientServerHello.serverHello(state.softwareversion, sock.getInputStream(), sock.getOutputStream());
-
-        tc = new TransportConnection(sock.getInputStream(), sock.getOutputStream(), state.generator);
-
-        km = new ServerKexManager(state);
-        km.initiateKEX(state.next_cryptoWishList, null, state.next_dsa_key, state.next_rsa_key);
-
-        startReceiver();
-    }
-
-    public void registerMessageHandler(MessageHandler mh, int low, int high)
-    {
-        HandlerEntry he = new HandlerEntry();
-        he.mh = mh;
-        he.low = low;
-        he.high = high;
-
-        synchronized (messageHandlers)
-        {
-            messageHandlers.add(he);
-        }
-    }
-
-    public void removeMessageHandler(MessageHandler mh, int low, int high)
-    {
-        synchronized (messageHandlers)
-        {
-            for (int i = 0; i < messageHandlers.size(); i++)
-            {
-                HandlerEntry he = messageHandlers.get(i);
-                if ((he.mh == mh) && (he.low == low) && (he.high == high))
-                {
-                    messageHandlers.remove(i);
-                    break;
-                }
-            }
-        }
-    }
-
-    public void sendKexMessage(byte[] msg) throws IOException
-    {
-        synchronized (connectionSemaphore)
-        {
-            if (connectionClosed)
-            {
-                throw (IOException) new IOException("Sorry, this connection is closed.").initCause(reasonClosedCause);
-            }
-
-            flagKexOngoing = true;
-
-            try
-            {
-                tc.sendMessage(msg);
-            }
-            catch (IOException e)
-            {
-                close(e, false);
-                throw e;
-            }
-        }
-    }
-
-    public void kexFinished() throws IOException
-    {
-        synchronized (connectionSemaphore)
-        {
-            flagKexOngoing = false;
-            connectionSemaphore.notifyAll();
-        }
-    }
-
-    /**
-     *
-     * @param cwl
-     * @param dhgex
-     * @param dsa may be null if this is a client connection
-     * @param rsa may be null if this is a client connection
-     * @throws IOException
-     */
-    public void forceKeyExchange(CryptoWishList cwl, DHGexParameters dhgex, DSAPrivateKey dsa, RSAPrivateKey rsa)
-            throws IOException
-    {
-        synchronized (connectionSemaphore)
-        {
-            if (connectionClosed)
-                               /* Inform the caller that there is no point in triggering a new kex */
-                throw (IOException) new IOException("Sorry, this connection is closed.").initCause(reasonClosedCause);
-        }
-
-        km.initiateKEX(cwl, dhgex, dsa, rsa);
-    }
-
-    public void changeRecvCipher(BlockCipher bc, MAC mac)
-    {
-        tc.changeRecvCipher(bc, mac);
-    }
-
-    public void changeSendCipher(BlockCipher bc, MAC mac)
-    {
-        tc.changeSendCipher(bc, mac);
-    }
-
-    public void sendAsynchronousMessage(byte[] msg) throws IOException
-    {
-        sendAsynchronousMessage(msg, null);
-    }
-
-    public void sendAsynchronousMessage(byte[] msg, Runnable run) throws IOException
-    {
-        synchronized (asynchronousQueue)
-        {
-            asynchronousQueue.add(new AsynchronousEntry(msg, run));
-            asynchronousPending = true;
-
-                       /* This limit should be flexible enough. We need this, otherwise the peer
-                        * can flood us with global requests (and other stuff where we have to reply
-                        * with an asynchronous message) and (if the server just sends data and does not
-                        * read what we send) this will probably put us in a low memory situation
-                        * (our send queue would grow and grow and...) */
-
-            if (asynchronousQueue.size() > 100)
-            {
-                throw new IOException("Error: the peer is not consuming our asynchronous replies.");
-            }
-
-                       /* Check if we have an asynchronous sending thread */
-
-            if (asynchronousThread == null)
-            {
-                asynchronousThread = new AsynchronousWorker();
-                asynchronousThread.setDaemon(true);
-                asynchronousThread.start();
-
-                               /* The thread will stop after 2 seconds of inactivity (i.e., empty queue) */
-            }
-
-            asynchronousQueue.notifyAll();
-        }
-    }
-
-    public void setConnectionMonitors(List<ConnectionMonitor> monitors)
-    {
-        synchronized (this)
-        {
-            connectionMonitors = new Vector<ConnectionMonitor>();
-            connectionMonitors.addAll(monitors);
-        }
-    }
-
-    /**
-     * True if no response message expected.
-     */
-    private boolean idle;
-
-    /**
-     * Send a message but ensure that all queued messages are being sent first.
-     *
-     * @param msg
-     * @throws IOException
-     */
-    public void sendMessage(byte[] msg) throws IOException
-    {
-        synchronized (asynchronousQueue)
-        {
-            while (asynchronousPending)
-            {
-                try
-                {
-                    asynchronousQueue.wait(1000);
-                }
-                catch (InterruptedException e)
-                {
-                }
-            }
-        }
-
-        sendMessageImmediate(msg);
-    }
-
-    /**
-     * Send message, ignore queued async messages that have not been delivered yet.
-     * Will be called directly from the asynchronousThread thread.
-     *
-     * @param msg
-     * @throws IOException
-     */
-    public void sendMessageImmediate(byte[] msg) throws IOException
-    {
-        if (Thread.currentThread() == receiveThread)
-        {
-            throw new IOException("Assertion error: sendMessage may never be invoked by the receiver thread!");
-        }
-
-        boolean wasInterrupted = false;
-
-        try
-        {
-            synchronized (connectionSemaphore)
-            {
-                while (true)
-                {
-                    if (connectionClosed)
-                    {
-                        throw (IOException) new IOException("Sorry, this connection is closed.")
-                                .initCause(reasonClosedCause);
-                    }
-
-                    if (flagKexOngoing == false)
-                    {
-                        break;
-                    }
-
-                    try
-                    {
-                        connectionSemaphore.wait();
-                    }
-                    catch (InterruptedException e)
-                    {
-                        wasInterrupted = true;
-                    }
-                }
-
-                try
-                {
-                    tc.sendMessage(msg);
-                    idle = false;
-                }
-                catch (IOException e)
-                {
-                    close(e, false);
-                    throw e;
-                }
-            }
-        }
-        finally
-        {
-            if (wasInterrupted)
-                Thread.currentThread().interrupt();
-        }
-    }
-
-    public void receiveLoop() throws IOException
-    {
-        byte[] msg = new byte[35000];
-
-        while (true)
-        {
-            int msglen;
-            try
-            {
-                msglen = tc.receiveMessage(msg, 0, msg.length);
-            }
-            catch (SocketTimeoutException e)
-            {
-                // Timeout in read
-                if (idle)
-                {
-                    log.debug("Ignoring socket timeout");
-                    continue;
-                }
-                throw e;
-            }
-            idle = true;
-
-            int type = msg[0] & 0xff;
-
-            if (type == Packets.SSH_MSG_IGNORE)
-            {
-                continue;
-            }
-
-            if (type == Packets.SSH_MSG_DEBUG)
-            {
-                if (log.isDebugEnabled())
-                {
-                    TypesReader tr = new TypesReader(msg, 0, msglen);
-                    tr.readByte();
-                    tr.readBoolean();
-                    StringBuilder debugMessageBuffer = new StringBuilder();
-                    debugMessageBuffer.append(tr.readString("UTF-8"));
-
-                    for (int i = 0; i < debugMessageBuffer.length(); i++)
-                    {
-                        char c = debugMessageBuffer.charAt(i);
-
-                        if ((c >= 32) && (c <= 126))
-                        {
-                            continue;
-                        }
-                        debugMessageBuffer.setCharAt(i, '\uFFFD');
-                    }
-
-                    log.debug("DEBUG Message from remote: '" + debugMessageBuffer.toString() + "'");
-                }
-                continue;
-            }
-
-            if (type == Packets.SSH_MSG_UNIMPLEMENTED)
-            {
-                throw new IOException("Peer sent UNIMPLEMENTED message, that should not happen.");
-            }
-
-            if (type == Packets.SSH_MSG_DISCONNECT)
-            {
-                TypesReader tr = new TypesReader(msg, 0, msglen);
-                tr.readByte();
-                int reason_code = tr.readUINT32();
-                StringBuilder reasonBuffer = new StringBuilder();
-                reasonBuffer.append(tr.readString("UTF-8"));
-
-                               /*
-                                * Do not get fooled by servers that send abnormal long error
-                                * messages
-                                */
-
-                if (reasonBuffer.length() > 255)
-                {
-                    reasonBuffer.setLength(255);
-                    reasonBuffer.setCharAt(254, '.');
-                    reasonBuffer.setCharAt(253, '.');
-                    reasonBuffer.setCharAt(252, '.');
-                }
-
-                               /*
-                                * Also, check that the server did not send characters that may
-                                * screw up the receiver -> restrict to reasonable US-ASCII
-                                * subset -> "printable characters" (ASCII 32 - 126). Replace
-                                * all others with 0xFFFD (UNICODE replacement character).
-                                */
-
-                for (int i = 0; i < reasonBuffer.length(); i++)
-                {
-                    char c = reasonBuffer.charAt(i);
-
-                    if ((c >= 32) && (c <= 126))
-                    {
-                        continue;
-                    }
-                    reasonBuffer.setCharAt(i, '\uFFFD');
-                }
-
-                throw new IOException("Peer sent DISCONNECT message (reason code " + reason_code + "): "
-                        + reasonBuffer.toString());
-            }
-
-                       /*
-                        * Is it a KEX Packet?
-                        */
-
-            if ((type == Packets.SSH_MSG_KEXINIT) || (type == Packets.SSH_MSG_NEWKEYS)
-                    || ((type >= 30) && (type <= 49)))
-            {
-                km.handleMessage(msg, msglen);
-                continue;
-            }
-
-            MessageHandler mh = null;
-
-            for (int i = 0; i < messageHandlers.size(); i++)
-            {
-                HandlerEntry he = messageHandlers.get(i);
-                if ((he.low <= type) && (type <= he.high))
-                {
-                    mh = he.mh;
-                    break;
-                }
-            }
-
-            if (mh == null)
-            {
-                throw new IOException("Unexpected SSH message (type " + type + ")");
-            }
-
-            mh.handleMessage(msg, msglen);
-        }
-    }
-}