Hi,
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:
- engine.closeOutbound()
- engine.wrap()
- channel.write(data) (yes, I'm sure I've sent all the data obtained with the wrap()
- 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?