Android SSLEngine BUFFER_UNDERFLOW после разворачивания при чтении

Я не знаю почему, но половина сайтов, которые проходят через ssl, получают buffer_underflow во время моего чтения.

Когда моя программа связана для последовательного вызова разных ssl-сайтов, она не работает на половине ссылок, но если я звоню по одной по отдельности, они работают. Например, я использовал инструменты разработчика Chrome для вызова https://www.facebook.com на своем планшете Nexus 7. Когда я вижу запросы, вызываемые ссылки:

Если я свяжу их вместе (для имитации вызова https://www.facebook.com из браузера), Я получаю, что половина ссылок получает опустошение буфера, пока в конце концов мне не придется закрыть их соединения (чтение 0 байтов). Однако, если я вызываю их один за другим по отдельности, они всегда в порядке. Вот мой код для чтения:

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;
}

Спасибо.


person Juan Acevedo    schedule 06.12.2013    source источник
comment
Я не совсем понял вашу проблему, но я написал что-то, что упрощает использование sslengine java - почему бы вам не взглянуть на это - Фасад SSL   -  person keios    schedule 30.12.2013
comment
Спасибо kashif, на самом деле я уже скачал ваш проект, но у меня не было времени его посмотреть. Основная проблема, с которой я сталкиваюсь, и которую я не могу легко решить, заключается в том, что иногда во время развертывания я получаю сообщение об исключении. Наконец-то я обнаружил, что причина в том, что в ByteBuffers не хватает места для некоторых запросов. Те запросы, у которых есть эта проблема, в конечном итоге представляют собой страницы размером 300 КБ (например, страницу .js), а мой ByteBuffer - это только packageSizeBuffer(), который намного меньше этого, поэтому я могу только частично развернуть страницу, но я обязательно посмотрю в вашем проекте.   -  person Juan Acevedo    schedule 02.01.2014


Ответы (1)


Опустошение буфера допустимо во время распаковки и происходит часто. Это происходит, когда у вас есть неполная запись TLS (‹16 КБ). Это может произойти в двух случаях: 1) Когда у вас меньше 16 КБ, поэтому вы не получаете результата при распаковке - просто кэшируйте все эти данные и подождите, пока прибудет остаток, чтобы распаковать его. 2) Когда у вас есть более 16 КБ, но последний пакет TLS не завершен, например 20 КБ или 36 КБ. В этом случае первые 16 КБ / 32 КБ дадут вам результат во время распаковки, а вам нужно кэшировать оставшиеся 4 КБ и просто дождаться остальных 12 КБ, которые завершат этот пакет TLS, прежде чем вы сможете развернуть.

Я надеюсь, что это поможет, попробуйте мой код и посмотрите, работает ли он для вас.

Извините, это не поместилось в комментарий, поэтому вместо этого я ответил ответом.

person keios    schedule 03.01.2014