akappa
akappa

Reputation: 10490

SSLEngine and close

I've implemented an helper module that lets me obtain clean data from a channel used with SSL and write encrypted data into it: this is the relevant interface (I've also some non-abstract methods in that class, so doesn't say to me that "DataProvider should be an interface" ;)):

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

I've an implementation of that abstract base class for SSL. While testing that implementation, I've wrote two function: in one I receive a message with a SocketChannel and the SSLSocket used to send data closes the connection, in the other I send a message with the SocketChannel initiate the closing with that. Now, the problem is that the SSLSocket used to receive the data doesn't close, even if I've issued those steps:

  1. engine.closeOutbound()
  2. engine.wrap()
  3. channel.write(data) (yes, I'm sure I've sent all the data obtained with the wrap()
  4. a select of the channel for reading the inbound close_notify

The problem is that the selector is stuck in the 4th step.

In the other test (SSLSocket closes the connection) I don't have a problem.

Note that I've implemented the shouldClose as:

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

so I need an incoming close_notify in order to close, even if I've initialized the close (I don't know if this is correct: eventually I can change it with return engine.isOutboundDone())

This is my SSLSocket side of the code:

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());

The last assert is violated.

Initially I've thinked that this is because there is no "background" thread associated with toRead, so I should do a read/write with it in order to consume the incoming close_notify and then finally get the socket close, but even that doesn't help.

Any idea?

Upvotes: 2

Views: 2346

Answers (2)

user207421
user207421

Reputation: 310915

Very late answer but you don't need wait for the close_notify if you have already sent one, see RFC 2246. However you should get one. You don't say how exactly you are selecting on close_notify.

NB Your code doesn't make sense. The socket will only be closed if you close it. isClosed() refers to the socket, not the connection.

Upvotes: 3

michael aubert
michael aubert

Reputation: 6826

I would suggest adding is.close(); before the fist assert.

Please note that this tiny piece of code I suggested doesn't close the socket. It's supposed to close the InputStream.

Upvotes: 1

Related Questions