2013-12-06 2 views
0

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

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

Если бы я приковать их вместе (для имитации вызова https://www.facebook.com из браузера), я получаю половину ссылки получать буфер обнуляется, пока в конце концов, я не должен закрывать соединения (Reading 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; 
} 

Спасибо.

+0

Я не понял вашу проблему четко, но я написал что-то, что упрощает использование sslengine java - почему бы вам не взглянуть на него - [SSLFacade] (https://github.com/kashifrazzaqui/ sslfacade) – kashif

+0

Спасибо, kashif, на самом деле я уже скачал ваш проект, но у меня не было времени посмотреть на него. Основная проблема, с которой я сталкиваюсь, и я не могу легко решить, так это то, что иногда во время разворота я получаю сообщение об исключении. Я, наконец, нашел причину, потому что у ByteBuffers заканчивается пространство с некоторыми запросами. Те запросы, у которых эта проблема заканчиваются, составляют 300 КБ страниц (например, страница .js), а мой ByteBuffer - это только пакетSizeBuffer(), который намного меньше, поэтому я могу только частично распаковать страницу, но я обязательно посмотрю в вашем проекте. –

ответ

0

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

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

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