0

理由はわかりませんが、ssl を通過するサイトの半分で、読み取り中に buffer_underflow が発生します。

異なる SSL サイトを連続して呼び出すようにプログラムを連鎖させた場合、リンクの半分では機能しませんが、1 つずつ個別に呼び出すと機能します。たとえば、Chrome の開発者ツールを使用して、nexus 7 タブレットでhttps://www.facebook.comを呼び出しました。リクエストを見ると、呼び出されるリンクは次のとおりです。

それらをチェーン化すると (ブラウザからhttps://www.facebook.comへの呼び出しをシミュレートするために)、リンクの半分がバッファ アンダーフローを取得し、最終的にそれらの接続を閉じる必要があります (0 バイトの読み取り)。ただし、1つずつ個別に呼び出すと、常に問題ありません。読むための私のコードは次のとおりです。

public int readSSLFrom(SelectionKey key, SecureIO session) throws IOException{
    int result = 0;
    String TAG = "readSSLFrom";
    Log.i(TAG,"Hanshake status: "+session.sslEngine.getHandshakeStatus().toString());
    synchronized (buffer){
        ByteBuffer sslIn = ByteBuffer.allocate(session.getApplicationSizeBuffer());
        ByteBuffer tmp = ByteBuffer.allocate(session.getApplicationSizeBuffer());
        ReadableByteChannel channel = (ReadableByteChannel) key.channel();
        if (buffer.remaining() < session.getPacketBufferSize()){
            increaseSize(session.getPacketBufferSize());
        }
        int read = 0;
        while (((read = channel.read(sslIn)) > 0) &&
                buffer.remaining() >= session.getApplicationSizeBuffer()){
            if (read < 0){
                session.sslEngine.closeInbound();
                return -1;
            }
            inner: while (sslIn.position() > 0){ 
                sslIn.flip();
                tmp.clear();
                SSLEngineResult res = session.sslEngine.unwrap(sslIn, tmp);
                result = result + res.bytesProduced();
                sslIn.compact();
                tmp.flip();
                if (tmp.hasRemaining()){
                    buffer.put(tmp);
                }
                switch (res.getStatus()){
                case BUFFER_OVERFLOW:
                    Log.i(TAG,"Buffer overflow");
                    throw new Error();
                case BUFFER_UNDERFLOW:
                    Log.i(TAG,"Buffer underflow");
                    if (session.getPacketBufferSize() > tmp.capacity()){
                        Log.i(TAG,"increasing capacity");
                        ByteBuffer b = ByteBuffer.allocate(session.getPacketBufferSize());
                        sslIn.flip();
                        b.put(sslIn);
                        sslIn = b;
                    }
                    break inner;
                case CLOSED:
                    Log.i(TAG,"Closed");
                    if (sslIn.position() == 0){
                        break inner;
                    } else{
                        return -1;
                    }
                case OK:
                    Log.i(TAG,"OK");
                    session.checkHandshake(key);
                    break;
                default:
                    break;
                }
            }
        }
        if (read < 0){
            //session.sslEngine.closeInbound();
            return -1;
        }
    }
    dataEnd = buffer.position();
    return result;
}

ありがとうございました。

4

1 に答える 1

0

アンラップ中はバッファ アンダーフローが許容され、頻繁に発生します。これは、部分的な TLS レコード (<16KB) がある場合に発生します。これは 2 つのケースで発生する可能性があります。1) 16KB 未満の場合、ラップを解除しても結果が得られません。このデータをすべてキャッシュし、ラップを解除するために残りが到着するのを待ちます。2) 16KB を超えているが、最後の TLS パケットが完全ではない場合 (20KB または 36KB など)。この場合、ラップ解除中に最初の 16KB/32KB で結果が得られ、残りの 4KB をキャッシュし、残りの 12KB がこの TLS パケットを完了するのを待つだけで、ラップ解除することができます。

これがお役に立てば幸いです。私のコードを試して、うまくいくかどうかを確認してください。

申し訳ありませんが、これはコメントに収まらなかったため、代わりに回答を返信しました。

于 2014-01-03T06:49:29.570 に答える