diff src/ch/ethz/ssh2/ServerConnection.java @ 308:42b15aaa7ac7 ganymed

merge
author Carl Byington <carl@five-ten-sg.com>
date Wed, 30 Jul 2014 14:21:50 -0700
parents 071eccdff8ea
children c19b24adf6c9
line wrap: on
line diff
--- a/src/ch/ethz/ssh2/ServerConnection.java	Wed Jul 30 13:38:04 2014 -0700
+++ b/src/ch/ethz/ssh2/ServerConnection.java	Wed Jul 30 14:21:50 2014 -0700
@@ -29,30 +29,28 @@
  * @author Christian
  *
  */
-public class ServerConnection
-{
-	/**
-	 * The softwareversion presented to the SSH-2 client.
-	 */
-	private String softwareversion = String.format("Ganymed_SSHD_%s", Version.getSpecification());
+public class ServerConnection {
+    /**
+     * The softwareversion presented to the SSH-2 client.
+     */
+    private String softwareversion = String.format("Ganymed_SSHD_%s", Version.getSpecification());
 
-	private final ServerConnectionState state = new ServerConnectionState(this);
+    private final ServerConnectionState state = new ServerConnectionState(this);
 
-	/**
-	 * Creates a new <code>ServerConnection</code> that will communicate
-	 * with the client over the given <code>Socket</code>.
-	 * <p>
-	 * Note: you need to call {@link #connect()} or {@link #connect(int)} to
-	 * perform the initial handshake and establish the encrypted communication.
-	 *
-	 * @see #connect(int)
-	 *
-	 * @param s The socket
-	 */
-	public ServerConnection(Socket s)
-	{
-		this(s, null, null, null);
-	}
+    /**
+     * Creates a new <code>ServerConnection</code> that will communicate
+     * with the client over the given <code>Socket</code>.
+     * <p>
+     * Note: you need to call {@link #connect()} or {@link #connect(int)} to
+     * perform the initial handshake and establish the encrypted communication.
+     *
+     * @see #connect(int)
+     *
+     * @param s The socket
+     */
+    public ServerConnection(Socket s) {
+        this(s, null, null, null);
+    }
 
     public ServerConnection(Socket s, String softwareversion) {
         this(s, null, null, null);
@@ -60,340 +58,323 @@
     }
 
     /**
-	 * Creates a new <code>ServerConnection</code> that will communicate
-	 * with the client over the given <code>Socket</code>.
-	 * <p>
-	 * Note: you need to call {@link #connect()} or {@link #connect(int)} to
-	 * perform the initial handshake and establish the encrypted communication.
-	 * <p>
-	 * Please read the javadoc for the {@link #connect(int)} method.
-	 *
-	 * @see #connect(int)
-	 *
-	 * @param s The socket
-	 * @param dsa_key The DSA hostkey, may be <code>NULL</code>
-	 * @param rsa_key The RSA hostkey, may be <code>NULL</code>
-	 * @param ec_key  The EC  hostkey, may be <code>NULL</code>
-	 */
-	public ServerConnection(Socket s, KeyPair dsa_key, KeyPair rsa_key, KeyPair ec_key)
-	{
-		state.s = s;
-		state.softwareversion = softwareversion;
-		state.next_dsa_key = dsa_key;
-		state.next_rsa_key = rsa_key;
-		state.next_ec_key  = ec_key;
-		fixCryptoWishList(state.next_cryptoWishList, state.next_dsa_key, state.next_rsa_key, state.next_ec_key);
-	}
+     * Creates a new <code>ServerConnection</code> that will communicate
+     * with the client over the given <code>Socket</code>.
+     * <p>
+     * Note: you need to call {@link #connect()} or {@link #connect(int)} to
+     * perform the initial handshake and establish the encrypted communication.
+     * <p>
+     * Please read the javadoc for the {@link #connect(int)} method.
+     *
+     * @see #connect(int)
+     *
+     * @param s The socket
+     * @param dsa_key The DSA hostkey, may be <code>NULL</code>
+     * @param rsa_key The RSA hostkey, may be <code>NULL</code>
+     * @param ec_key  The EC  hostkey, may be <code>NULL</code>
+     */
+    public ServerConnection(Socket s, KeyPair dsa_key, KeyPair rsa_key, KeyPair ec_key) {
+        state.s = s;
+        state.softwareversion = softwareversion;
+        state.next_dsa_key = dsa_key;
+        state.next_rsa_key = rsa_key;
+        state.next_ec_key  = ec_key;
+        fixCryptoWishList(state.next_cryptoWishList, state.next_dsa_key, state.next_rsa_key, state.next_ec_key);
+    }
 
-	/**
-	 * Establish the connection and block until the first handshake has completed.
-	 * <p>
-	 * Note: this is a wrapper that calls <code>connect(0)</code> (i.e., connect with no timeout).
-	 * <p>
-	 * Please read the javadoc for the {@link #connect(int)} method.
-	 *
-	 * @see #connect(int)
-	 *
-	 * @throws IOException
-	 */
-	public synchronized void connect() throws IOException
-	{
-		connect(0);
-	}
+    /**
+     * Establish the connection and block until the first handshake has completed.
+     * <p>
+     * Note: this is a wrapper that calls <code>connect(0)</code> (i.e., connect with no timeout).
+     * <p>
+     * Please read the javadoc for the {@link #connect(int)} method.
+     *
+     * @see #connect(int)
+     *
+     * @throws IOException
+     */
+
+    public synchronized void connect() throws IOException {
+        connect(0);
+    }
 
-	/**
-	 * Establish the connection and block until the first handshake has completed.
-	 * <p>
-	 * Note 1: at least one DSA, RSA or EC hostkey must be set before calling this method.
-	 * <p>
-	 * Note 2: You must set the callbacks for authentication ({@link #setAuthenticationCallback(ServerAuthenticationCallback)})
-	 * and connection events ({@link #setServerConnectionCallback(ServerConnectionCallback)}).
-	 *
-	 * @see #setPEMHostKey(char[], String)
-	 * @see #setPEMHostKey(File, String)
-	 * @see #setRsaHostKey(RSAPrivateKey)
-	 * @see #setDsaHostKey(DSAPrivateKey)
-	 *
-	 * @param timeout_milliseconds Timeout in milliseconds, <code>0</code> means no timeout.
-	 * @throws IOException
-	 */
-	public synchronized void connect(int timeout_milliseconds) throws IOException
-	{
-		synchronized (state)
-		{
-			if (state.cb_conn == null)
-				throw new IllegalStateException("The callback for connection events has not been set.");
+    /**
+     * Establish the connection and block until the first handshake has completed.
+     * <p>
+     * Note 1: at least one DSA, RSA or EC hostkey must be set before calling this method.
+     * <p>
+     * Note 2: You must set the callbacks for authentication ({@link #setAuthenticationCallback(ServerAuthenticationCallback)})
+     * and connection events ({@link #setServerConnectionCallback(ServerConnectionCallback)}).
+     *
+     * @see #setPEMHostKey(char[], String)
+     * @see #setPEMHostKey(File, String)
+     * @see #setRsaHostKey(RSAPrivateKey)
+     * @see #setDsaHostKey(DSAPrivateKey)
+     *
+     * @param timeout_milliseconds Timeout in milliseconds, <code>0</code> means no timeout.
+     * @throws IOException
+     */
 
-			if (state.cb_auth == null)
-				throw new IllegalStateException("The callback for authentication events has not been set.");
+    public synchronized void connect(int timeout_milliseconds) throws IOException {
+        synchronized (state) {
+            if (state.cb_conn == null)
+                throw new IllegalStateException("The callback for connection events has not been set.");
+
+            if (state.cb_auth == null)
+                throw new IllegalStateException("The callback for authentication events has not been set.");
+
+            if (state.tm != null)
+                throw new IllegalStateException("The initial handshake has already been started.");
+
+            if ((state.next_dsa_key == null) && (state.next_rsa_key == null) && (state.next_ec_key == null))
+                throw new IllegalStateException("Neither an RSA nor a DSA nor an EC host key has been specified!");
 
-			if (state.tm != null)
-				throw new IllegalStateException("The initial handshake has already been started.");
-
-			if ((state.next_dsa_key == null) && (state.next_rsa_key == null) && (state.next_ec_key == null))
-				throw new IllegalStateException("Neither an RSA nor a DSA nor an EC host key has been specified!");
+            state.tm = new ServerTransportManager(state.s);
+        }
 
-			state.tm = new ServerTransportManager(state.s);
-		}
-
-		state.tm.connect(state);
-
-		/* Wait until first KEX has finished */
+        state.tm.connect(state);
+        /* Wait until first KEX has finished */
+        state.tm.getConnectionInfo(1);
+    }
 
-		state.tm.getConnectionInfo(1);
-	}
+    /**
+     * Retrieve the underlying socket.
+     *
+     * @return the socket that has been passed to the constructor.
+     */
+    public Socket getSocket() {
+        return state.s;
+    }
 
-	/**
-	 * Retrieve the underlying socket.
-	 *
-	 * @return the socket that has been passed to the constructor.
-	 */
-	public Socket getSocket()
-	{
-		return state.s;
-	}
+    /**
+     * 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 (client driven) key exchange. You may call this method only after
+     * the initial key exchange has been established.
+     * <p>
+     * Note: This implementation will never start automatically a key exchange (other than the initial one)
+     * unless you or the connected SSH-2 client ask for it.
+     *
+     * @throws IOException
+     *             In case of any failure behind the scenes.
+     */
 
-	/**
-	 * 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 (client driven) key exchange. You may call this method only after
-	 * the initial key exchange has been established.
-	 * <p>
-	 * Note: This implementation will never start automatically a key exchange (other than the initial one)
-	 * unless you or the connected SSH-2 client ask for it.
-	 *
-	 * @throws IOException
-	 *             In case of any failure behind the scenes.
-	 */
-	public synchronized void forceKeyExchange() throws IOException
-	{
-		synchronized (state)
-		{
-			if (state.tm == null)
-				throw new IllegalStateException(
-						"Cannot force another key exchange, you need to start the key exchange first.");
+    public synchronized void forceKeyExchange() throws IOException {
+        synchronized (state) {
+            if (state.tm == null)
+                throw new IllegalStateException(
+                    "Cannot force another key exchange, you need to start the key exchange first.");
+
+            state.tm.forceKeyExchange(state.next_cryptoWishList, null, state.next_dsa_key, state.next_rsa_key, state.next_ec_key);
+        }
+    }
+
+    /**
+     * Returns a {@link ConnectionInfo} object containing the details of
+     * the connection. May be called as soon as the first key exchange has been
+     * started. The method blocks in case the first key exchange has not been completed.
+     * <p>
+     * Note: upon return of this method, authentication may still be pending.
+     *
+     * @return A {@link ConnectionInfo} object.
+     * @throws IOException
+     *             In case of any failure behind the scenes; e.g., first key exchange was aborted.
+     */
 
-			state.tm.forceKeyExchange(state.next_cryptoWishList, null, state.next_dsa_key, state.next_rsa_key, state.next_ec_key);
-		}
-	}
+    public synchronized ConnectionInfo getConnectionInfo() throws IOException {
+        synchronized (state) {
+            if (state.tm == null)
+                throw new IllegalStateException(
+                    "Cannot get details of connection, you need to start the key exchange first.");
+        }
+
+        return state.tm.getConnectionInfo(1);
+    }
 
-	/**
-	 * Returns a {@link ConnectionInfo} object containing the details of
-	 * the connection. May be called as soon as the first key exchange has been
-	 * started. The method blocks in case the first key exchange has not been completed.
-	 * <p>
-	 * Note: upon return of this method, authentication may still be pending.
-	 *
-	 * @return A {@link ConnectionInfo} object.
-	 * @throws IOException
-	 *             In case of any failure behind the scenes; e.g., first key exchange was aborted.
-	 */
-	public synchronized ConnectionInfo getConnectionInfo() throws IOException
-	{
-		synchronized (state)
-		{
-			if (state.tm == null)
-				throw new IllegalStateException(
-						"Cannot get details of connection, you need to start the key exchange first.");
-		}
+    /**
+     * Change the current DSA hostkey. Either a DSA or RSA or EC private key must be set for a successful handshake with
+     * the client.
+     * <p>
+     * Note: You can change an existing DSA hostkey after the initial kex exchange (the new value will
+     * be used during the next server initiated key exchange), but you cannot remove (i.e., set to <code>null</code>) the
+     * current DSA key, otherwise the next key exchange may fail in case the client supports only DSA hostkeys.
+     *
+     * @param dsa_hostkey
+     */
 
-		return state.tm.getConnectionInfo(1);
-	}
+    public synchronized void setDsaHostKey(KeyPair dsa_hostkey) {
+        synchronized (state) {
+            if ((dsa_hostkey == null) && (state.next_dsa_key != null) && (state.tm != null))
+                throw new IllegalStateException("Cannot remove DSA hostkey after first key exchange.");
+
+            state.next_dsa_key = dsa_hostkey;
+            fixCryptoWishList(state.next_cryptoWishList, state.next_dsa_key, state.next_rsa_key, state.next_ec_key);
+        }
+    }
 
-	/**
-	 * Change the current DSA hostkey. Either a DSA or RSA or EC private key must be set for a successful handshake with
-	 * the client.
-	 * <p>
-	 * Note: You can change an existing DSA hostkey after the initial kex exchange (the new value will
-	 * be used during the next server initiated key exchange), but you cannot remove (i.e., set to <code>null</code>) the
-	 * current DSA key, otherwise the next key exchange may fail in case the client supports only DSA hostkeys.
-	 *
-	 * @param dsa_hostkey
-	 */
-	public synchronized void setDsaHostKey(KeyPair dsa_hostkey)
-	{
-		synchronized (state)
-		{
-			if ((dsa_hostkey == null) && (state.next_dsa_key != null) && (state.tm != null))
-				throw new IllegalStateException("Cannot remove DSA hostkey after first key exchange.");
+    /**
+     * Change the current RSA hostkey. Either a DSA or RSA or EC private key must be set for a successful handshake with
+     * the client.
+     * <p>
+     * Note: You can change an existing RSA hostkey after the initial kex exchange (the new value will
+     * be used during the next server initiated key exchange), but you cannot remove (i.e., set to <code>null</code>) the
+     * current RSA key, otherwise the next key exchange may fail in case the client supports only RSA hostkeys.
+     *
+     * @param rsa_hostkey
+     */
 
-			state.next_dsa_key = dsa_hostkey;
-			fixCryptoWishList(state.next_cryptoWishList, state.next_dsa_key, state.next_rsa_key, state.next_ec_key);
-		}
-	}
+    public synchronized void setRsaHostKey(KeyPair rsa_hostkey) {
+        synchronized (state) {
+            if ((rsa_hostkey == null) && (state.next_rsa_key != null) && (state.tm != null))
+                throw new IllegalStateException("Cannot remove RSA hostkey after first key exchange.");
 
-	/**
-	 * Change the current RSA hostkey. Either a DSA or RSA or EC private key must be set for a successful handshake with
-	 * the client.
-	 * <p>
-	 * Note: You can change an existing RSA hostkey after the initial kex exchange (the new value will
-	 * be used during the next server initiated key exchange), but you cannot remove (i.e., set to <code>null</code>) the
-	 * current RSA key, otherwise the next key exchange may fail in case the client supports only RSA hostkeys.
-	 *
-	 * @param rsa_hostkey
-	 */
-	public synchronized void setRsaHostKey(KeyPair rsa_hostkey)
-	{
-		synchronized (state)
-		{
-			if ((rsa_hostkey == null) && (state.next_rsa_key != null) && (state.tm != null))
-				throw new IllegalStateException("Cannot remove RSA hostkey after first key exchange.");
+            state.next_rsa_key = rsa_hostkey;
+            fixCryptoWishList(state.next_cryptoWishList, state.next_dsa_key, state.next_rsa_key, state.next_ec_key);
+        }
+    }
 
-			state.next_rsa_key = rsa_hostkey;
-			fixCryptoWishList(state.next_cryptoWishList, state.next_dsa_key, state.next_rsa_key, state.next_ec_key);
-		}
-	}
+    /**
+     * Change the current EC hostkey. Either a DSA or RSA or EC private key must be set for a successful handshake with
+     * the client.
+     * <p>
+     * Note: You can change an existing EC hostkey after the initial kex exchange (the new value will
+     * be used during the next server initiated key exchange), but you cannot remove (i.e., set to <code>null</code>) the
+     * current EC key, otherwise the next key exchange may fail in case the client supports only EC hostkeys.
+     *
+     * @param rsa_hostkey
+     */
+
+    public synchronized void setEcHostKey(KeyPair ec_hostkey) {
+        synchronized (state) {
+            if ((ec_hostkey == null) && (state.next_ec_key != null) && (state.tm != null))
+                throw new IllegalStateException("Cannot remove EC hostkey after first key exchange.");
 
-	/**
-	 * Change the current EC hostkey. Either a DSA or RSA or EC private key must be set for a successful handshake with
-	 * the client.
-	 * <p>
-	 * Note: You can change an existing EC hostkey after the initial kex exchange (the new value will
-	 * be used during the next server initiated key exchange), but you cannot remove (i.e., set to <code>null</code>) the
-	 * current EC key, otherwise the next key exchange may fail in case the client supports only EC hostkeys.
-	 *
-	 * @param rsa_hostkey
-	 */
-	public synchronized void setEcHostKey(KeyPair ec_hostkey)
-	{
-		synchronized (state)
-		{
-			if ((ec_hostkey == null) && (state.next_ec_key != null) && (state.tm != null))
-				throw new IllegalStateException("Cannot remove EC hostkey after first key exchange.");
+            state.next_ec_key = ec_hostkey;
+            fixCryptoWishList(state.next_cryptoWishList, state.next_dsa_key, state.next_rsa_key, state.next_ec_key);
+        }
+    }
 
-			state.next_ec_key = ec_hostkey;
-			fixCryptoWishList(state.next_cryptoWishList, state.next_dsa_key, state.next_rsa_key, state.next_ec_key);
-		}
-	}
-
-	/**
-	 * Utility method that loads a PEM based hostkey (either RSA or DSA based) and
-	 * calls either <code>setRsaHostKey()</code> or <code>setDsaHostKey()</code>.
-	 *
-	 * @param pemdata The PEM data
-	 * @param password Password, may be null in case the PEM data is not password protected
-	 * @throws IOException In case of any error.
-	 */
-	public void setPEMHostKey(char[] pemdata, String password) throws IOException
-	{
-		KeyPair pair = PEMDecoder.decode(pemdata, password);
+    /**
+     * Utility method that loads a PEM based hostkey (either RSA or DSA based) and
+     * calls either <code>setRsaHostKey()</code> or <code>setDsaHostKey()</code>.
+     *
+     * @param pemdata The PEM data
+     * @param password Password, may be null in case the PEM data is not password protected
+     * @throws IOException In case of any error.
+     */
+    public void setPEMHostKey(char[] pemdata, String password) throws IOException {
+        KeyPair pair = PEMDecoder.decode(pemdata, password);
         PrivateKey key = pair.getPrivate();
 
-		if (key instanceof DSAPrivateKey) setDsaHostKey(pair);
+        if (key instanceof DSAPrivateKey) setDsaHostKey(pair);
 
-		if (key instanceof RSAPrivateKey) setRsaHostKey(pair);
+        if (key instanceof RSAPrivateKey) setRsaHostKey(pair);
 
         if (key instanceof ECPrivateKey) setEcHostKey(pair);
-	}
+    }
 
-	/**
-	 * Utility method that loads a hostkey from a PEM file (either RSA or DSA based) and
-	 * calls either <code>setRsaHostKey()</code> or <code>setDsaHostKey()</code>.
-	 *
-	 * @param pemFile The PEM file
-	 * @param password Password, may be null in case the PEM file is not password protected
-	 * @throws IOException
-	 */
-	public void setPEMHostKey(File pemFile, String password) throws IOException
-	{
-		if (pemFile == null)
-			throw new IllegalArgumentException("pemfile argument is null");
+    /**
+     * Utility method that loads a hostkey from a PEM file (either RSA or DSA based) and
+     * calls either <code>setRsaHostKey()</code> or <code>setDsaHostKey()</code>.
+     *
+     * @param pemFile The PEM file
+     * @param password Password, may be null in case the PEM file is not password protected
+     * @throws IOException
+     */
+    public void setPEMHostKey(File pemFile, String password) throws IOException {
+        if (pemFile == null)
+            throw new IllegalArgumentException("pemfile argument is null");
 
-		char[] buff = new char[256];
+        char[] buff = new char[256];
+        CharArrayWriter cw = new CharArrayWriter();
+        FileReader fr = new FileReader(pemFile);
 
-		CharArrayWriter cw = new CharArrayWriter();
+        while (true) {
+            int len = fr.read(buff);
 
-		FileReader fr = new FileReader(pemFile);
+            if (len < 0)
+                break;
 
-		while (true)
-		{
-			int len = fr.read(buff);
-			if (len < 0)
-				break;
-			cw.write(buff, 0, len);
-		}
+            cw.write(buff, 0, len);
+        }
 
-		fr.close();
+        fr.close();
+        setPEMHostKey(cw.toCharArray(), password);
+    }
+
+    private void fixCryptoWishList(CryptoWishList next_cryptoWishList, KeyPair next_dsa_key, KeyPair next_rsa_key, KeyPair next_ec_key) {
+        List<String> algos = new ArrayList<String>();
+
+        if (next_ec_key != null)  algos.add("ecdsa-sha2-nistp521");
 
-		setPEMHostKey(cw.toCharArray(), password);
-	}
+        if (next_ec_key != null)  algos.add("ecdsa-sha2-nistp384");
+
+        if (next_ec_key != null)  algos.add("ecdsa-sha2-nistp256");
+
+        if (next_dsa_key != null) algos.add("ssh-dss");
 
-	private void fixCryptoWishList(CryptoWishList next_cryptoWishList, KeyPair next_dsa_key, KeyPair next_rsa_key, KeyPair next_ec_key)
-	{
-        List<String> algos = new ArrayList<String>();
-		if (next_ec_key != null)  algos.add("ecdsa-sha2-nistp521");
-		if (next_ec_key != null)  algos.add("ecdsa-sha2-nistp384");
-		if (next_ec_key != null)  algos.add("ecdsa-sha2-nistp256");
-		if (next_dsa_key != null) algos.add("ssh-dss");
-		if (next_rsa_key != null) algos.add("ssh-rsa");
- 	    next_cryptoWishList.serverHostKeyAlgorithms = new String[algos.size()];
+        if (next_rsa_key != null) algos.add("ssh-rsa");
+
+        next_cryptoWishList.serverHostKeyAlgorithms = new String[algos.size()];
         algos.toArray(next_cryptoWishList.serverHostKeyAlgorithms);
-	}
+    }
 
-	/**
-	 * Callback interface with methods that will be called upon events
-	 * generated by the client (e.g., client opens a new Session which results in a <code>ServerSession</code>).
-	 * <p>
-	 * Note: This must be set before the first handshake.
-	 *
-	 * @param cb The callback implementation
-	 */
-	public synchronized void setServerConnectionCallback(ServerConnectionCallback cb)
-	{
-		synchronized (state)
-		{
-			state.cb_conn = cb;
-		}
-	}
+    /**
+     * Callback interface with methods that will be called upon events
+     * generated by the client (e.g., client opens a new Session which results in a <code>ServerSession</code>).
+     * <p>
+     * Note: This must be set before the first handshake.
+     *
+     * @param cb The callback implementation
+     */
 
-	/**
-	 * Callback interface with methods that will be called upon authentication events.
-	 * <p>
-	 * Note: This must be set before the first handshake.
-	 *
-	 * @param cb The callback implementation
-	 */
-	public synchronized void setAuthenticationCallback(ServerAuthenticationCallback cb)
-	{
-		synchronized (state)
-		{
-			state.cb_auth = cb;
-		}
-	}
+    public synchronized void setServerConnectionCallback(ServerConnectionCallback cb) {
+        synchronized (state) {
+            state.cb_conn = cb;
+        }
+    }
+
+    /**
+     * Callback interface with methods that will be called upon authentication events.
+     * <p>
+     * Note: This must be set before the first handshake.
+     *
+     * @param cb The callback implementation
+     */
+
+    public synchronized void setAuthenticationCallback(ServerAuthenticationCallback cb) {
+        synchronized (state) {
+            state.cb_auth = cb;
+        }
+    }
 
-	/**
-	 * 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 void close()
-	{
-        synchronized (state)
-      		{
-      			if (state.cm != null)
-      				state.cm.closeAllChannels();
+    /**
+     * 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 void close() {
+        synchronized (state) {
+            if (state.cm != null)
+                state.cm.closeAllChannels();
 
-      			if (state.tm != null)
-      			{
-      				state.tm.close();
-      			}
-      		}
-	}
+            if (state.tm != null) {
+                state.tm.close();
+            }
+        }
+    }
 
-	public void close(IOException t)
-	{
-		synchronized (state)
-		{
-			if (state.cm != null)
-				state.cm.closeAllChannels();
+    public void close(IOException t) {
+        synchronized (state) {
+            if (state.cm != null)
+                state.cm.closeAllChannels();
 
-			if (state.tm != null)
-			{
-				state.tm.close(t);
-			}
-		}
-	}
+            if (state.tm != null) {
+                state.tm.close(t);
+            }
+        }
+    }
 }