2009-05-28 3 views
2

Я реализовал вспомогательный модуль, который позволяет мне получать чистые данные из канала, используемого с SSL, и записывать в него зашифрованные данные: это соответствующий интерфейс (у меня также есть некоторые не абстрактные методы в этом классе , поэтому не говорит мне, что «DataProvider должен быть интерфейс»;)):SSLEngine и close

public abstract class DataProvider { 
    // Notify the bytes read from the net 
    public abstract void readFromNet(ByteBuffer b); 
    // Gets the bytes to write into the net 
    public abstract void writeToNet(ByteBuffer b); 
    // Add a message to send 
    public abstract boolean addMessage(byte[] data); 
    // Obtains the application data received 
    public abstract byte[] getReceivedApplicationData(); 
    // True if there is something to actually send over the wire 
    public abstract boolean dataToSend(); 
    // True if we should close the channel 
    public abstract boolean shouldClose(); 
    // Notify our intention to shut down the connection 
    public abstract void shutDown(SelectionKey sk); 
    // Set the interest op set for the channel 
    public abstract void setInterestOps(SelectionKey sk); 
} 

Я реализацию этого абстрактного базового класса для SSL. При тестировании этой реализации я написал две функции: в одном я получаю сообщение с SocketChannel, а SSLSocket, используемый для отправки данных, закрывает соединение, а в другом я отправляю сообщение с SocketChannel, инициируя его закрытие. Теперь проблема в том, что SSLSocket используется для получения данных не закрывается, даже если я издал эти шаги:

  1. engine.closeOutbound()
  2. engine.wrap()
  3. channel.write (данные) (да, я уверен, что я послал все данные, полученные с обручем()
  4. отборный канала для чтения входящих close_notify

проблема заключается в том, что селектор застрял на 4-м шаге.

В другом тесте (SSLSocket закрывает соединение) У меня нет проблем.

Обратите внимание, что я реализовал shouldClose как:

return engine.isOutboundDone() && engine.isInboundDone(); 

так мне нужен входящий close_notify, чтобы закрыть, даже если я инициализирован близко (я не знаю, если это правильно : в конце концов, я могу изменить его с return engine.isOutboundDone())

Это моя SSLSocket сторона кода:

Socket toRead = socket.accept(); 
toRead.setSoTimeout(0); 
InputStream is = toRead.getInputStream(); 
ByteArrayOutputStream bos = new ByteArrayOutputStream(); 
String read = ""; 
byte[] barray = new byte[1024]; 
while (read.length() < toSend.length() * 2) { 
    int bytesRead = is.read(barray); 
    bos.write(barray, 0, bytesRead); 
    read = new String(bos.toByteArray()); 
} 
assertEquals(toSend + toSend, read); 
assertTrue(toRead.isClosed()); 

Последние утверждают, нарушается.

Первоначально я подумал, что это связано с тем, что поток «background», связанный с toRead, отсутствует, поэтому я должен делать с ним чтение/запись, чтобы потреблять входящий close_notify, а затем, наконец, закрыть сокет, но даже это не помогает.

Любая идея?

+0

Я серьезно рекомендую использовать фреймворк, например, Grizzly или Apache MINA. Вы смешиваете разные парадигмы программирования. –

+2

Что это за разные парадигмы программирования Я смешиваю вместе? – akappa

ответ

1

Я предлагаю добавить is.close(); перед утверждением кулака.

Обратите внимание, что этот крошечный кусок кода, который я предложил, не закрывает сокет. Он должен закрыть InputStream.

+0

Я не могу закрыть сокет: я должен получить notify_end SSL. – akappa

+0

Если вы закроете InputStream of Socket, вы закроете канал. Поскольку документация SSLSocket не «переопределяет» эту информацию, я предполагаю, что эффект тот же. Учитывая тот факт, что я хочу проверить, правильно ли я реализовал SSL-соединение, я не могу закрыть SSLSocket, потому что просто хочу, чтобы он закрывал «для себя» при получении ssl_close. Мне интересно, почему этого не происходит: это действительно мой вопрос. – akappa

3

Очень поздний ответ, но вам не нужно ждать close_notify, если вы уже отправили его, см. RFC 2246. Однако вы должны его получить. Вы не говорите, как именно вы выбираете на close_notify.

NB Ваш код не имеет смысла. Розетка будет только закрыта, если вы закройте ее. isClosed() относится к сокету, а не к соединению.