private int processDataFromSocket(byte[] b, int off, int len) throws IOException {
            Platform.blockGuardOnNetwork();
            checkOpen();

            // Make sure the input stream has been created.
            init();

            for (;;) {
                // Serve any remaining data from the engine first.
                if (fromEngine.remaining() > 0) {
                    int readFromEngine = Math.min(fromEngine.remaining(), len);
                    fromEngine.get(b, off, readFromEngine);
                    return readFromEngine;
                }

                // Try to unwrap any data already in the socket buffer.
                boolean needMoreDataFromSocket = true;

                // Unwrap the unencrypted bytes into the engine buffer.
                fromSocket.flip();
                fromEngine.clear();

                boolean engineHandshaking = isHandshaking(engine.getHandshakeStatus());
                SSLEngineResult engineResult = engine.unwrap(fromSocket, fromEngine);

                // Shift any remaining data to the beginning of the buffer so that
                // we can accommodate the next full packet. After this is called,
                // limit will be restored to capacity and position will point just
                // past the end of the data.
                fromSocket.compact();
                fromEngine.flip();

                switch (engineResult.getStatus()) {
                    case BUFFER_UNDERFLOW: {
                        if (engineResult.bytesProduced() == 0) {
                            // Need to read more data from the socket.
                            break;
                        }
                        // Also serve the data that was produced.
                        needMoreDataFromSocket = false;
                        break;
                    }
                    case OK: {
                        // We processed the entire packet successfully...

                        if (!engineHandshaking && isHandshaking(engineResult.getHandshakeStatus())
                            && isHandshakeFinished()) {
                            // The received packet is the beginning of a renegotiation handshake.
                            // Perform another handshake.
                            renegotiate();
                            return 0;
                        }

                        needMoreDataFromSocket = false;
                        break;
                    }
                    case CLOSED: {
                        // EOF
                        return -1;
                    }
                    default: {
                        // Anything else is an error.
                        throw new SSLException(
                                "Unexpected engine result " + engineResult.getStatus());
                    }
                }

                if (!needMoreDataFromSocket && engineResult.bytesProduced() == 0) {
                    // Read successfully, but produced no data. Possibly part of a
                    // handshake.
                    return 0;
                }

                // Read more data from the socket.
                if (needMoreDataFromSocket && readFromSocket() == -1) {
                    // Failed to read the next encrypted packet before reaching EOF.
                    return -1;
                }

                // Continue the loop and return the data from the engine buffer.
            }
        }
Unwrap bytes read from the underlying socket.
common/src/main/java/org/conscrypt/ConscryptEngineSocket.java