use of javax.net.ssl.SSLEngineResult in project h2o-3 by h2oai.
the class SSLSocketChannel method unwrap.
private synchronized int unwrap(ByteBuffer dst) throws IOException {
int read = 0;
// We have outstanding data in our incoming decrypted buffer, use that data first to fill dst
if (!dst.hasRemaining()) {
return 0;
}
if (peerAppData.position() != 0) {
read += copy(peerAppData, dst);
return read;
}
if (netInBuffer.position() == 0) {
channel.read(netInBuffer);
}
while (netInBuffer.position() != 0) {
netInBuffer.flip();
// We still might have left data here if dst was smaller than the amount of data in peerAppData
if (peerAppData.position() != 0) {
peerAppData.compact();
}
SSLEngineResult unwrapResult = sslEngine.unwrap(netInBuffer, peerAppData);
switch(unwrapResult.getStatus()) {
case OK:
{
unwrapResult.bytesProduced();
if (unwrapResult.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_TASK)
tasks();
break;
}
case BUFFER_OVERFLOW:
{
int applicationBufferSize = sslEngine.getSession().getApplicationBufferSize();
if (applicationBufferSize > peerAppData.capacity()) {
int appSize = applicationBufferSize;
ByteBuffer b = ByteBuffer.allocate(appSize + peerAppData.position());
peerAppData.flip();
b.put(peerAppData);
peerAppData = b;
} else {
// We tried to unwrap data into peerAppData which means there's leftover in netInBuffer
// the upcoming read should read int potential new data after the leftover
netInBuffer.position(netInBuffer.limit());
netInBuffer.limit(netInBuffer.capacity());
peerAppData.compact();
if (!dst.hasRemaining()) {
return read;
}
}
break;
}
case BUFFER_UNDERFLOW:
{
int packetBufferSize = sslEngine.getSession().getPacketBufferSize();
if (packetBufferSize > netInBuffer.capacity()) {
int netSize = packetBufferSize;
if (netSize > netInBuffer.capacity()) {
ByteBuffer b = ByteBuffer.allocate(netSize);
netInBuffer.flip();
b.put(netInBuffer);
netInBuffer = b;
}
} else {
// We have some leftover data from unwrap but no enough.
// We need to read in more data from the socket AFTER the current data.
netInBuffer.position(netInBuffer.limit());
netInBuffer.limit(netInBuffer.capacity());
channel.read(netInBuffer);
continue;
}
break;
}
default:
throw new IOException("Failed to SSL unwrap with status " + unwrapResult.getStatus());
}
if (peerAppData != dst && dst.hasRemaining()) {
peerAppData.flip();
read += copy(peerAppData, dst);
if (!dst.hasRemaining()) {
netInBuffer.compact();
return read;
}
}
netInBuffer.compact();
}
return read;
}
use of javax.net.ssl.SSLEngineResult in project tomcat by apache.
the class SecureNioChannel method close.
/**
* Sends a SSL close message, will not physically close the connection here.
* <br>To close the connection, you could do something like
* <pre><code>
* close();
* while (isOpen() && !myTimeoutFunction()) Thread.sleep(25);
* if ( isOpen() ) close(true); //forces a close if you timed out
* </code></pre>
* @throws IOException if an I/O error occurs
* @throws IOException if there is data on the outgoing network buffer and
* we are unable to flush it
*/
@Override
public void close() throws IOException {
if (closing)
return;
closing = true;
sslEngine.closeOutbound();
if (!flush(netOutBuffer)) {
throw new IOException(sm.getString("channel.nio.ssl.remainingDataDuringClose"));
}
//prep the buffer for the close message
netOutBuffer.clear();
//perform the close, since we called sslEngine.closeOutbound
SSLEngineResult handshake = sslEngine.wrap(getEmptyBuf(), netOutBuffer);
//we should be in a close state
if (handshake.getStatus() != SSLEngineResult.Status.CLOSED) {
throw new IOException(sm.getString("channel.nio.ssl.invalidCloseState"));
}
//prepare the buffer for writing
netOutBuffer.flip();
//if there is data to be written
flush(netOutBuffer);
//is the channel closed?
closed = (!netOutBuffer.hasRemaining() && (handshake.getHandshakeStatus() != HandshakeStatus.NEED_WRAP));
}
use of javax.net.ssl.SSLEngineResult in project tomcat by apache.
the class SecureNio2Channel method close.
/**
* Sends a SSL close message, will not physically close the connection here.<br>
* To close the connection, you could do something like
* <pre><code>
* close();
* while (isOpen() && !myTimeoutFunction()) Thread.sleep(25);
* if ( isOpen() ) close(true); //forces a close if you timed out
* </code></pre>
* @throws IOException if an I/O error occurs
* @throws IOException if there is data on the outgoing network buffer and we are unable to flush it
*/
@Override
public void close() throws IOException {
if (closing)
return;
closing = true;
sslEngine.closeOutbound();
try {
if (!flush().get(endpoint.getConnectionTimeout(), TimeUnit.MILLISECONDS).booleanValue()) {
throw new IOException(sm.getString("channel.nio.ssl.remainingDataDuringClose"));
}
} catch (InterruptedException | ExecutionException | TimeoutException e) {
throw new IOException(sm.getString("channel.nio.ssl.remainingDataDuringClose"), e);
} catch (WritePendingException e) {
throw new IOException(sm.getString("channel.nio.ssl.pendingWriteDuringClose"), e);
}
//prep the buffer for the close message
netOutBuffer.clear();
//perform the close, since we called sslEngine.closeOutbound
SSLEngineResult handshake = sslEngine.wrap(getEmptyBuf(), netOutBuffer);
//we should be in a close state
if (handshake.getStatus() != SSLEngineResult.Status.CLOSED) {
throw new IOException(sm.getString("channel.nio.ssl.invalidCloseState"));
}
//prepare the buffer for writing
netOutBuffer.flip();
//if there is data to be written
try {
if (!flush().get(endpoint.getConnectionTimeout(), TimeUnit.MILLISECONDS).booleanValue()) {
throw new IOException(sm.getString("channel.nio.ssl.remainingDataDuringClose"));
}
} catch (InterruptedException | ExecutionException | TimeoutException e) {
throw new IOException(sm.getString("channel.nio.ssl.remainingDataDuringClose"), e);
} catch (WritePendingException e) {
throw new IOException(sm.getString("channel.nio.ssl.pendingWriteDuringClose"), e);
}
//is the channel closed?
closed = (!netOutBuffer.hasRemaining() && (handshake.getHandshakeStatus() != HandshakeStatus.NEED_WRAP));
}
use of javax.net.ssl.SSLEngineResult in project tomcat by apache.
the class SecureNio2Channel method read.
@Override
public <A> void read(final ByteBuffer[] dsts, final int offset, final int length, final long timeout, final TimeUnit unit, final A attachment, final CompletionHandler<Long, ? super A> handler) {
if (offset < 0 || dsts == null || (offset + length) > dsts.length) {
throw new IllegalArgumentException();
}
if (closing || closed) {
handler.completed(Long.valueOf(-1), attachment);
return;
}
if (!handshakeComplete) {
throw new IllegalStateException(sm.getString("channel.nio.ssl.incompleteHandshake"));
}
CompletionHandler<Integer, A> readCompletionHandler = new CompletionHandler<Integer, A>() {
@Override
public void completed(Integer nBytes, A attach) {
if (nBytes.intValue() < 0) {
failed(new EOFException(), attach);
} else {
try {
//the data read
long read = 0;
//the SSL engine result
SSLEngineResult unwrap;
do {
//prepare the buffer
netInBuffer.flip();
//unwrap the data
unwrap = sslEngine.unwrap(netInBuffer, dsts, offset, length);
//compact the buffer
netInBuffer.compact();
if (unwrap.getStatus() == Status.OK || unwrap.getStatus() == Status.BUFFER_UNDERFLOW) {
//we did receive some data, add it to our total
read += unwrap.bytesProduced();
//perform any tasks if needed
if (unwrap.getHandshakeStatus() == HandshakeStatus.NEED_TASK)
tasks();
//if we need more network data, then bail out for now.
if (unwrap.getStatus() == Status.BUFFER_UNDERFLOW) {
if (read == 0) {
sc.read(netInBuffer, timeout, unit, attachment, this);
return;
} else {
break;
}
}
} else if (unwrap.getStatus() == Status.BUFFER_OVERFLOW && read > 0) {
//empty out the dst buffer before we do another read
break;
} else {
//in the constructor
throw new IOException(sm.getString("channel.nio.ssl.unwrapFail", unwrap.getStatus()));
}
} while (//continue to unwrapping as long as the input buffer has stuff
netInBuffer.position() != 0);
int capacity = 0;
final int endOffset = offset + length;
for (int i = offset; i < endOffset; i++) {
capacity += dsts[i].remaining();
}
if (capacity == 0) {
unwrapBeforeRead = true;
} else {
unwrapBeforeRead = false;
}
// If everything is OK, so complete
handler.completed(Long.valueOf(read), attach);
} catch (Exception e) {
failed(e, attach);
}
}
}
@Override
public void failed(Throwable exc, A attach) {
handler.failed(exc, attach);
}
};
if (unwrapBeforeRead || netInBuffer.position() > 0) {
readCompletionHandler.completed(Integer.valueOf(netInBuffer.position()), attachment);
} else {
sc.read(netInBuffer, timeout, unit, attachment, readCompletionHandler);
}
}
use of javax.net.ssl.SSLEngineResult in project tomcat by apache.
the class SecureNio2Channel method write.
@Override
public <A> void write(final ByteBuffer[] srcs, final int offset, final int length, final long timeout, final TimeUnit unit, final A attachment, final CompletionHandler<Long, ? super A> handler) {
if ((offset < 0) || (length < 0) || (offset > srcs.length - length)) {
throw new IndexOutOfBoundsException();
}
// Check state
if (closing || closed) {
handler.failed(new IOException(sm.getString("channel.nio.ssl.closing")), attachment);
return;
}
try {
// Prepare the output buffer
netOutBuffer.clear();
// Wrap the source data into the internal buffer
SSLEngineResult result = sslEngine.wrap(srcs, offset, length, netOutBuffer);
final int written = result.bytesConsumed();
netOutBuffer.flip();
if (result.getStatus() == Status.OK) {
if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
tasks();
}
// Write data to the channel
sc.write(netOutBuffer, timeout, unit, attachment, new CompletionHandler<Integer, A>() {
@Override
public void completed(Integer nBytes, A attach) {
if (nBytes.intValue() < 0) {
failed(new EOFException(), attach);
} else if (netOutBuffer.hasRemaining()) {
sc.write(netOutBuffer, timeout, unit, attachment, this);
} else if (written == 0) {
// Special case, start over to avoid code duplication
write(srcs, offset, length, timeout, unit, attachment, handler);
} else {
// Call the handler completed method with the
// consumed bytes number
handler.completed(Long.valueOf(written), attach);
}
}
@Override
public void failed(Throwable exc, A attach) {
handler.failed(exc, attach);
}
});
} else {
throw new IOException(sm.getString("channel.nio.ssl.wrapFail", result.getStatus()));
}
} catch (Exception e) {
handler.failed(e, attachment);
}
}
Aggregations