private void doHandshake()

in httpcore5/src/main/java/org/apache/hc/core5/reactor/ssl/SSLIOSession.java [349:458]


    private void doHandshake(final IOSession protocolSession) throws IOException {
        boolean handshaking = true;

        SSLEngineResult result = null;
        while (handshaking) {
             HandshakeStatus handshakeStatus = this.sslEngine.getHandshakeStatus();

            // Work-around for what appears to be a bug in Conscrypt SSLEngine that does not
            // transition into the handshaking state upon #closeOutbound() call but still
            // has some handshake data stuck in its internal buffer.
            if (handshakeStatus == HandshakeStatus.NOT_HANDSHAKING && outboundClosedCount.get() > 0) {
                handshakeStatus = HandshakeStatus.NEED_WRAP;
            }

            switch (handshakeStatus) {
            case NEED_WRAP:
                // Generate outgoing handshake data

                this.session.getLock().lock();
                try {
                    // Acquire buffers
                    final ByteBuffer outEncryptedBuf = this.outEncrypted.acquire();

                    // Just wrap an empty buffer because there is no data to write.
                    result = doWrap(EMPTY_BUFFER, outEncryptedBuf);

                    if (result.getStatus() != SSLEngineResult.Status.OK || result.getHandshakeStatus() == HandshakeStatus.NEED_WRAP) {
                        handshaking = false;
                    }
                    break;
                } finally {
                    this.session.getLock().unlock();
                }
            case NEED_UNWRAP:
                // Process incoming handshake data

                // Acquire buffers
                final ByteBuffer inEncryptedBuf = this.inEncrypted.acquire();
                final ByteBuffer inPlainBuf = this.inPlain.acquire();

                // Perform operations
                inEncryptedBuf.flip();
                try {
                    result = doUnwrap(inEncryptedBuf, inPlainBuf);
                } finally {
                    inEncryptedBuf.compact();
                }

                try {
                    if (!inEncryptedBuf.hasRemaining() && result.getHandshakeStatus() == HandshakeStatus.NEED_UNWRAP) {
                        throw new SSLException("Input buffer is full");
                    }
                } finally {
                    // Release inEncrypted if empty
                    if (inEncryptedBuf.position() == 0) {
                        this.inEncrypted.release();
                    }
                }

                if (this.status.compareTo(Status.CLOSING) >= 0) {
                    this.inPlain.release();
                }
                if (result.getStatus() != SSLEngineResult.Status.OK) {
                    handshaking = false;
                }
                break;
            case NEED_TASK:
                doRunTask();
                break;
            case NOT_HANDSHAKING:
                handshaking = false;
                break;
            }
        }

        // The SSLEngine has just finished handshaking. This value is only generated by a call
        // to SSLEngine.wrap()/unwrap() when that call finishes a handshake.
        // It is never generated by SSLEngine.getHandshakeStatus().
        if (result != null && result.getHandshakeStatus() == HandshakeStatus.FINISHED) {
            this.handshakeStateRef.set(TLSHandShakeState.COMPLETE);
            this.session.setSocketTimeout(this.socketTimeout);
            if (this.verifier != null) {
                this.tlsDetails = this.verifier.verify(this.targetEndpoint, this.sslEngine);
            }
            String applicationProtocol;
            if (this.tlsDetails == null) {
                final SSLSession sslSession = this.sslEngine.getSession();
                try {
                    applicationProtocol = this.sslEngine.getApplicationProtocol();
                } catch (final UnsupportedOperationException e) {
                    // If the underlying provider does not support the operation, the getApplicationProtocol() method throws an UnsupportedOperationException.
                    // In this case, we fall back to "http/1.1" as the application protocol.
                    // This is a workaround to allow older applications that do not support the getApplicationProtocol() method to continue working.
                    // This workaround is temporary and is meant to maintain compatibility with older systems.
                    applicationProtocol = "http/1.1";
                }
                this.tlsDetails = new TlsDetails(sslSession, applicationProtocol);
            }

            ensureHandler().connected(protocolSession);

            if (this.sessionStartCallback != null) {
                this.sessionStartCallback.execute(this);
            }
            final FutureCallback<SSLSession> resultCallback = handshakeCallbackRef.getAndSet(null);
            if (resultCallback != null) {
                resultCallback.completed(sslEngine.getSession());
            }
        }
    }