Commit cea33d0e authored by Gaston Dombiak's avatar Gaston Dombiak Committed by gato

Fixed many problems.

git-svn-id: http://svn.igniterealtime.org/svn/repos/messenger/trunk@2803 b35dd754-fafc-0310-a699-88a17e54d16e
parent b76cea25
......@@ -18,8 +18,6 @@ import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import org.jivesoftware.util.Log;
/**
* A <code>TLSStreamReader</code> that returns a special InputStream that hides the ByteBuffers
* used by the underlying Channels.
......@@ -45,7 +43,9 @@ public class TLSStreamReader {
*/
private ByteBuffer inAppBB;
public TLSStreamReader(TLSWrapper tlsWrapper, Socket socket) throws IOException {
private TLSStatus lastStatus;
public TLSStreamReader(TLSWrapper tlsWrapper, Socket socket) throws IOException {
wrapper = tlsWrapper;
rbc = Channels.newChannel(socket.getInputStream());
inNetBB = ByteBuffer.allocate(wrapper.getNetBuffSize());
......@@ -56,15 +56,37 @@ public class TLSStreamReader {
* Read TLS encrpyted data from SocketChannel, and use <code>decrypt</code> method to decypt.
*/
private void doRead() throws IOException {
inNetBB.clear();
inAppBB.clear();
final int cnt = rbc.read(inNetBB);
if (cnt > 0) {
ByteBuffer tlsInput = inNetBB;
//System.out.println("doRead inNet position: " + inNetBB.position() + " capacity: " + inNetBB.capacity() + " (before read)");
inAppBB = decrypt(tlsInput, inAppBB);
inAppBB.flip();
} else {
// Read from the channel and fill inNetBB with the encrypted data
final int cnt = rbc.read(inNetBB);
if (cnt > 0) {
//System.out.println("doRead inNet position: " + inNetBB.position() + " capacity: " + inNetBB.capacity() + " (after read)");
//System.out.println("doRead inAppBB (before decrypt) position: " + inAppBB.position() + " limit: " + inAppBB.limit() + " capacity: " + inAppBB.capacity());
// Decode encrypted data
inAppBB = decrypt(inNetBB, inAppBB);
///System.out.println("doRead inAppBB (after decrypt) position: " + inAppBB.position() + " limit: " + inAppBB.limit() + " capacity: " + inAppBB.capacity() + " lastStatus: " + lastStatus);
if (lastStatus == TLSStatus.OK) {
// All the data contained in inNetBB was read and decrypted so we can safely
// set the position of inAppBB to 0 to process it.
inAppBB.flip();
}
else {
// Some data in inNetBB was not decrypted since it is not complete. A
// bufferunderflow was detected since the TLS packet is not complete to be
// decrypted. We need to read more data from the channel to decrypt the whole
// TLS packet. The inNetBB byte buffer has been compacted so the read and
// decrypted is discarded and only the unread and encrypted data is left in the
// buffer. The inAppBB has been completed with the decrypted data and we must
// leave the position at the end of the written so that in the next doRead the
// decrypted data is appended to the end of the buffer.
//System.out.println("Reading more data from the channel (UNDERFLOW state)");
doRead();
}
} else {
if (cnt == -1) {
rbc.close();
}
......@@ -74,25 +96,29 @@ public class TLSStreamReader {
/*
* This method uses <code>TLSWrapper</code> to decrypt TLS encrypted data.
*/
private ByteBuffer decrypt(final ByteBuffer input, final ByteBuffer output) throws IOException {
TLSStatus stat = null;
private ByteBuffer decrypt(ByteBuffer input, ByteBuffer output) throws IOException {
ByteBuffer out = output;
do {
input.flip();
input.flip();
do {
// Decode SSL/TLS network data and place it in the app buffer
out = wrapper.unwrap(input, out);
if (input.hasRemaining()) {
input.compact();
}
stat = wrapper.getStatus();
} while ((stat == TLSStatus.NEED_READ || stat == TLSStatus.OK) && input.hasRemaining());
if (input.hasRemaining()) {
input.rewind();
lastStatus = wrapper.getStatus();
}
while ((lastStatus == TLSStatus.NEED_READ || lastStatus == TLSStatus.OK) &&
input.hasRemaining());
if (input.hasRemaining()) {
// Complete TLS packets have been read, decrypted and written to the output buffer.
// However, the input buffer contains incomplete TLS packets that cannot be decrpted.
// Discard the read data and keep the unread data in the input buffer. The channel will
// be read again to obtain the missing data to complete the TLS packet. So in the next
// round the TLS packet will be decrypted and written to the output buffer
input.compact();
} else {
input.clear();
// All the encrypted data in the inpu buffer was decrypted so we can clear
// the input buffer.
input.clear();
}
return out;
......@@ -117,9 +143,42 @@ public class TLSStreamReader {
}
public synchronized int read(byte[] bytes, int off, int len) throws IOException {
doRead();
// Check if in the previous read the inAppBB ByteBuffer remained with unread data.
// If all the data was consumed then read from the socket channel. Otherwise,
// consume the data contained in the buffer.
if (inAppBB.position() == 0) {
// Read from the channel the encrypted data, decrypt it and load it
// into inAppBB
doRead();
}
else {
//System.out.println("#createInputStream. Detected previously unread data. position: " + inAppBB.position());
// The inAppBB contains data from a previous read so set the position to 0
// to consume it
inAppBB.flip();
}
len = Math.min(len, inAppBB.remaining());
inAppBB.get(bytes, off, len);
if (len == 0) {
// Nothing was read so the end of stream should have been reached.
return -1;
}
inAppBB.get(bytes, off, len);
// If the requested length is less than the limit of inAppBB then all the data
// inside inAppBB was not read. In that case we need to discard the read data and
// keep only the unread data to be consume the next time this method is called
if (inAppBB.hasRemaining()) {
// Discard read data and move unread data to the begining of the buffer. Leave
// the position at the end of the buffer as a way to indicate that there is
// unread data
inAppBB.compact();
//System.out.println("#createInputStream. Data left unread. inAppBB compacted. position: " + inAppBB.position() + " limit: " + inAppBB.limit());
}
else {
// Everything was read so reset the buffer
inAppBB.clear();
}
return len;
}
};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment