@Override
    public final void startHandshake() throws IOException {
        checkOpen();
        synchronized (ssl) {
            if (state == STATE_NEW) {
                transitionTo(STATE_HANDSHAKE_STARTED);
            } else {
                // We've either started the handshake already or have been closed.
                // Do nothing in both cases.
                return;
            }
        }

        boolean releaseResources = true;
        try {
            Platform.closeGuardOpen(guard, "close");

            // Prepare the SSL object for the handshake.
            ssl.initialize(getHostname(), channelIdPrivateKey);

            // For clients, offer to resume a previously cached session to avoid the
            // full TLS handshake.
            if (getUseClientMode()) {
                NativeSslSession cachedSession = clientSessionContext().getCachedSession(
                        getHostnameOrIP(), getPort(), sslParameters);
                if (cachedSession != null) {
                    cachedSession.offerToResume(ssl);
                }
            }

            // Temporarily use a different timeout for the handshake process
            int savedReadTimeoutMilliseconds = getSoTimeout();
            int savedWriteTimeoutMilliseconds = getSoWriteTimeout();
            if (handshakeTimeoutMilliseconds >= 0) {
                setSoTimeout(handshakeTimeoutMilliseconds);
                setSoWriteTimeout(handshakeTimeoutMilliseconds);
            }

            synchronized (ssl) {
                if (state == STATE_CLOSED) {
                    return;
                }
            }

            try {
                ssl.doHandshake(Platform.getFileDescriptor(socket), getSoTimeout());

                // Update the session from the current state of the SSL object.
                activeSession.onPeerCertificateAvailable(getHostnameOrIP(), getPort());
            } catch (CertificateException e) {
                SSLHandshakeException wrapper = new SSLHandshakeException(e.getMessage());
                wrapper.initCause(e);
                throw wrapper;
            } catch (SSLException e) {
                // Swallow this exception if it's thrown as the result of an interruption.
                //
                // TODO: SSL_read and SSL_write return -1 when interrupted, but SSL_do_handshake
                // will throw the last sslError that it saw before sslSelect, usually SSL_WANT_READ
                // (or WANT_WRITE). Catching that exception here doesn't seem much worse than
                // changing the native code to return a "special" native pointer value when that
                // happens.
                synchronized (ssl) {
                    if (state == STATE_CLOSED) {
                        return;
                    }
                }
                throw e;
            }

            synchronized (ssl) {
                if (state == STATE_CLOSED) {
                    return;
                }
            }

            // Restore the original timeout now that the handshake is complete
            if (handshakeTimeoutMilliseconds >= 0) {
                setSoTimeout(savedReadTimeoutMilliseconds);
                setSoWriteTimeout(savedWriteTimeoutMilliseconds);
            }

            synchronized (ssl) {
                releaseResources = (state == STATE_CLOSED);

                if (state == STATE_HANDSHAKE_STARTED) {
                    transitionTo(STATE_READY_HANDSHAKE_CUT_THROUGH);
                } else {
                    transitionTo(STATE_READY);
                }

                if (!releaseResources) {
                    // Unblock threads that are waiting for our state to transition
                    // into STATE_READY or STATE_READY_HANDSHAKE_CUT_THROUGH.
                    ssl.notifyAll();
                }
            }
        } catch (SSLProtocolException e) {
            throw(SSLHandshakeException) new SSLHandshakeException("Handshake failed").initCause(e);
        } finally {
            // on exceptional exit, treat the socket as closed
            if (releaseResources) {
                synchronized (ssl) {
                    // Mark the socket as closed since we might have reached this as
                    // a result on an exception thrown by the handshake process.
                    //
                    // The state will already be set to closed if we reach this as a result of
                    // an early return or an interruption due to a concurrent call to close().
                    transitionTo(STATE_CLOSED);
                    ssl.notifyAll();
                }

                try {
                    shutdownAndFreeSslNative();
                } catch (IOException ignored) {
                    // Ignored.
                }
            }
        }
    }
Starts a TLS/SSL handshake on this connection using some native methods
from the OpenSSL library. It can negotiate new encryption keys, change
cipher suites, or initiate a new session. The certificate chain is
verified if the correspondent property in java.Security is set. All
listeners are notified at the end of the TLS/SSL handshake.
common/src/main/java/org/conscrypt/ConscryptFileDescriptorSocket.java