Search in sources :

Example 1 with TimeoutToken

use of com.trilead.ssh2.util.TimeoutService.TimeoutToken in project intellij-community by JetBrains.

the class Connection method connect.

/**
	 * 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(hostname, port);
    tm.setConnectionMonitors(connectionMonitors);
    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 {
            tm.initialize(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);
        if (token != null) {
            TimeoutService.cancelTimeoutHandler(token);
            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);
    }
}
Also used : SocketTimeoutException(java.net.SocketTimeoutException) TimeoutToken(com.trilead.ssh2.util.TimeoutService.TimeoutToken) IOException(java.io.IOException) TransportManager(com.trilead.ssh2.transport.TransportManager)

Aggregations

TransportManager (com.trilead.ssh2.transport.TransportManager)1 TimeoutToken (com.trilead.ssh2.util.TimeoutService.TimeoutToken)1 IOException (java.io.IOException)1 SocketTimeoutException (java.net.SocketTimeoutException)1