下面列出了javax.net.ssl.SSLEngineResult.HandshakeStatus#NEED_TASK 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
private static void runDelegatedTasks(SSLEngineResult result,
SSLEngine engine) throws Exception {
if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
Runnable runnable;
while ((runnable = engine.getDelegatedTask()) != null) {
log("\trunning delegated task...");
runnable.run();
}
HandshakeStatus hsStatus = engine.getHandshakeStatus();
if (hsStatus == HandshakeStatus.NEED_TASK) {
throw new Exception("handshake shouldn't need additional tasks");
}
log("\tnew HandshakeStatus: " + hsStatus);
}
}
/**
* Perform handshake unwrap
* @return the result
* @throws IOException An IO error occurred
*/
protected SSLEngineResult handshakeUnwrap() throws IOException {
SSLEngineResult result;
boolean cont = false;
//loop while we can perform pure SSLEngine data
do {
//prepare the buffer with the incoming data
netInBuffer.flip();
//call unwrap
getBufHandler().configureReadBufferForWrite();
result = sslEngine.unwrap(netInBuffer, getBufHandler().getReadBuffer());
//compact the buffer, this is an optional method, wonder what would happen if we didn't
netInBuffer.compact();
//read in the status
handshakeStatus = result.getHandshakeStatus();
if (result.getStatus() == SSLEngineResult.Status.OK &&
result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
//execute tasks if we need to
handshakeStatus = tasks();
}
//perform another unwrap?
cont = result.getStatus() == SSLEngineResult.Status.OK &&
handshakeStatus == HandshakeStatus.NEED_UNWRAP;
} while (cont);
return result;
}
HandshakeStatus getHandshakeStatus() {
if (!outputRecord.isEmpty()) {
// If no handshaking, special case to wrap alters or
// post-handshake messages.
return HandshakeStatus.NEED_WRAP;
} else if (isOutboundClosed() && isInboundClosed()) {
return HandshakeStatus.NOT_HANDSHAKING;
} else if (handshakeContext != null) {
if (!handshakeContext.delegatedActions.isEmpty()) {
return HandshakeStatus.NEED_TASK;
} else if (!isInboundClosed()) {
if (sslContext.isDTLS() &&
!inputRecord.isEmpty()) {
return HandshakeStatus.NEED_UNWRAP_AGAIN;
} else {
return HandshakeStatus.NEED_UNWRAP;
}
} else if (!isOutboundClosed()) {
// Special case that the inbound was closed, but outbound open.
return HandshakeStatus.NEED_WRAP;
} // Otherwise, both inbound and outbound are closed.
}
return HandshakeStatus.NOT_HANDSHAKING;
}
/**
* Perform handshake unwrap
* @param doread boolean
* @return the result
* @throws IOException An IO error occurred
*/
protected SSLEngineResult handshakeUnwrap(boolean doread) throws IOException {
if (netInBuffer.position() == netInBuffer.limit()) {
//clear the buffer if we have emptied it out on data
netInBuffer.clear();
}
if (doread) {
//if we have data to read, read it
int read = sc.read(netInBuffer);
if (read == -1) {
throw new IOException(sm.getString("channel.nio.ssl.eofDuringHandshake"));
}
}
SSLEngineResult result;
boolean cont = false;
//loop while we can perform pure SSLEngine data
do {
//prepare the buffer with the incoming data
netInBuffer.flip();
//call unwrap
getBufHandler().configureReadBufferForWrite();
result = sslEngine.unwrap(netInBuffer, getBufHandler().getReadBuffer());
//compact the buffer, this is an optional method, wonder what would happen if we didn't
netInBuffer.compact();
//read in the status
handshakeStatus = result.getHandshakeStatus();
if ( result.getStatus() == SSLEngineResult.Status.OK &&
result.getHandshakeStatus() == HandshakeStatus.NEED_TASK ) {
//execute tasks if we need to
handshakeStatus = tasks();
}
//perform another unwrap?
cont = result.getStatus() == SSLEngineResult.Status.OK &&
handshakeStatus == HandshakeStatus.NEED_UNWRAP;
}while ( cont );
return result;
}
HandshakeStatus getHandshakeStatus() {
if (!outputRecord.isEmpty()) {
// If no handshaking, special case to wrap alters or
// post-handshake messages.
return HandshakeStatus.NEED_WRAP;
} else if (isOutboundClosed() && isInboundClosed()) {
return HandshakeStatus.NOT_HANDSHAKING;
} else if (handshakeContext != null) {
if (!handshakeContext.delegatedActions.isEmpty()) {
return HandshakeStatus.NEED_TASK;
} else if (!isInboundClosed()) {
//JDK8 NEED_UNWRAP returnned for NEED_UNWRAP_AGAIN status
// needUnwrapAgain should be used to determine NEED_UNWRAP_AGAIN
return HandshakeStatus.NEED_UNWRAP;
} else if (!isOutboundClosed()) {
// Special case that the inbound was closed, but outbound open.
return HandshakeStatus.NEED_WRAP;
}
} else if (isOutboundClosed() && !isInboundClosed()) {
// Special case that the outbound was closed, but inbound open.
return HandshakeStatus.NEED_UNWRAP;
} else if (!isOutboundClosed() && isInboundClosed()) {
// Special case that the inbound was closed, but outbound open.
return HandshakeStatus.NEED_WRAP;
}
return HandshakeStatus.NOT_HANDSHAKING;
}
private static void runDelegatedTasks(SSLEngineResult result,
SSLEngine engine) throws Exception {
if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
Runnable runnable;
while ((runnable = engine.getDelegatedTask()) != null) {
runnable.run();
}
HandshakeStatus hsStatus = engine.getHandshakeStatus();
if (hsStatus == HandshakeStatus.NEED_TASK) {
throw new Exception(
"handshake shouldn't need additional tasks");
}
}
}
/**
* Try to flush out any existing outbound data, then try to wrap
* anything new contained in the src buffer.
* <p>
* Return the number of bytes actually consumed from the buffer,
* but the data may actually be still sitting in the output buffer,
* waiting to be flushed.
*/
private int doWrite(ByteBuffer src) throws IOException {
int retValue = 0;
if (outNetBB.hasRemaining() && !tryFlush(outNetBB)) {
return retValue;
}
/*
* The data buffer is empty, we can reuse the entire buffer.
*/
outNetBB.clear();
SSLEngineResult result = sslEngine.wrap(src, outNetBB);
retValue = result.bytesConsumed();
outNetBB.flip();
if (result.getStatus() == Status.OK) {
if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
doTasks();
}
} else {
throw new IOException("sslEngine error during data write: " +
result.getStatus());
}
/*
* Try to flush the data, regardless of whether or not
* it's been selected. Odds of a write buffer being full
* is less than a read buffer being empty.
*/
tryFlush(src);
if (outNetBB.hasRemaining()) {
tryFlush(outNetBB);
}
return retValue;
}
/**
* Perform handshake unwrap
* @param doread boolean
* @return SSLEngineResult
* @throws IOException
*/
protected SSLEngineResult handshakeUnwrap(boolean doread) throws IOException {
if (netInBuffer.position() == netInBuffer.limit()) {
//clear the buffer if we have emptied it out on data
netInBuffer.clear();
}
if ( doread ) {
//if we have data to read, read it
int read = sc.read(netInBuffer);
if (read == -1) throw new IOException("EOF encountered during handshake.");
}
SSLEngineResult result;
boolean cont = false;
//loop while we can perform pure SSLEngine data
do {
//prepare the buffer with the incoming data
netInBuffer.flip();
//call unwrap
result = sslEngine.unwrap(netInBuffer, bufHandler.getReadBuffer());
//compact the buffer, this is an optional method, wonder what would happen if we didn't
netInBuffer.compact();
//read in the status
handshakeStatus = result.getHandshakeStatus();
if ( result.getStatus() == SSLEngineResult.Status.OK &&
result.getHandshakeStatus() == HandshakeStatus.NEED_TASK ) {
//execute tasks if we need to
handshakeStatus = tasks();
}
//perform another unwrap?
cont = result.getStatus() == SSLEngineResult.Status.OK &&
handshakeStatus == HandshakeStatus.NEED_UNWRAP;
}while ( cont );
return result;
}
/**
* Encrypt provided buffer. Encrypted data returned by getOutNetBuffer().
*
* @param src data to encrypt
* @throws SSLException on errors
*/
void encrypt(ByteBuffer src) throws SSLException {
if (!handshakeComplete)
throw new IllegalStateException();
if (!src.hasRemaining()) {
if (outNetBuffer == null)
outNetBuffer = IoBuffer.allocate(0);
return;
}
createOutNetBuffer(src.remaining());
// Loop until there is no more data in src
while (src.hasRemaining()) {
SSLEngineResult result = sslEngine.wrap(src, outNetBuffer.buf());
if (result.getStatus() == Status.OK) {
if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK)
doTasks();
} else if (result.getStatus() == Status.BUFFER_OVERFLOW) {
outNetBuffer = IoBuffer.reallocate(outNetBuffer, outNetBuffer.capacity() << 1);
outNetBuffer.limit(outNetBuffer.capacity());
} else
throw new SSLException("SSLEngine error during encrypt: " + result.getStatus() + " src: " + src + "outNetBuffer: " + outNetBuffer);
}
outNetBuffer.flip();
}
/**
* Attempts to decode SSL/TLS network data into a subsequence of plaintext application data
* buffers. Depending on the state of the TLSWrapper, this method may consume network data
* without producing any application data (for example, it may consume handshake data.)
*
* If this TLSWrapper has not yet started its initial handshake, this method will automatically
* start the handshake.
*
* @param net a ByteBuffer containing inbound network data
* @param app a ByteBuffer to hold inbound application data
* @return a ByteBuffer containing inbound application data
* @throws SSLException A problem was encountered while processing the data that caused the
* TLSHandler to abort.
*/
public ByteBuffer unwrap(ByteBuffer net, ByteBuffer app) throws SSLException {
ByteBuffer out = app;
out = resizeApplicationBuffer(out);// guarantees enough room for unwrap
// Record a hex dump of the buffer, but only when logging on level 'debug'.
// Create the dump before the buffer is being passed to tlsEngine, to ensure
// that the original content of the buffer is logged.
String hexDump = null;
if ( Log.isDebugEnabled() )
{
final ByteBuffer bb = net.duplicate();
final byte[] data = Arrays.copyOf( bb.array(), bb.limit() );
hexDump = StringUtils.encodeHex( data );
}
try {
tlsEngineResult = tlsEngine.unwrap( net, out );
} catch ( SSLException e ) {
if ( e.getMessage().startsWith( "Unsupported record version Unknown-" ) ) {
Log.debug( "Buffer that wasn't TLS: {}", hexDump );
throw new SSLException( "We appear to have received plain text data where we expected encrypted data. A common cause for this is a peer sending us a plain-text error message when it shouldn't send a message, but close the socket instead).", e );
}
else {
throw e;
}
}
log("server unwrap: ", tlsEngineResult);
if (tlsEngineResult.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
// If the result indicates that we have outstanding tasks to do, go
// ahead and run them in this thread.
doTasks();
}
return out;
}
private static void runDelegatedTasks(SSLEngine engine) {
Runnable runnable;
System.out.println("Running delegated tasks...");
while ((runnable = engine.getDelegatedTask()) != null) {
runnable.run();
}
HandshakeStatus hs = engine.getHandshakeStatus();
if (hs == HandshakeStatus.NEED_TASK) {
throw new Error("Handshake shouldn't need additional tasks.");
}
}
private static void runDelegatedTasks(SSLEngineResult result,
SSLEngine engine) throws Exception {
if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
Runnable runnable;
while ((runnable = engine.getDelegatedTask()) != null) {
runnable.run();
}
HandshakeStatus hsStatus = engine.getHandshakeStatus();
if (hsStatus == HandshakeStatus.NEED_TASK) {
throw new Exception(
"handshake shouldn't need additional tasks");
}
}
}
@Override
public void run() {
long written = 0;
try {
for (int i = offset; i < offset + length; i++) {
ByteBuffer src = srcs[i];
while (src.hasRemaining()) {
socketWriteBuffer.clear();
// Encrypt the data
SSLEngineResult r = sslEngine.wrap(src, socketWriteBuffer);
written += r.bytesConsumed();
Status s = r.getStatus();
if (s == Status.OK || s == Status.BUFFER_OVERFLOW) {
// Need to write out the bytes and may need to read from
// the source again to empty it
} else {
// Status.BUFFER_UNDERFLOW - only happens on unwrap
// Status.CLOSED - unexpected
throw new IllegalStateException(sm.getString(
"asyncChannelWrapperSecure.statusWrap"));
}
// Check for tasks
if (r.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
Runnable runnable = sslEngine.getDelegatedTask();
while (runnable != null) {
runnable.run();
runnable = sslEngine.getDelegatedTask();
}
}
socketWriteBuffer.flip();
// Do the write
int toWrite = r.bytesProduced();
while (toWrite > 0) {
Future<Integer> f =
socketChannel.write(socketWriteBuffer);
Integer socketWrite = f.get();
toWrite -= socketWrite.intValue();
}
}
}
if (writing.compareAndSet(true, false)) {
future.complete(Long.valueOf(written));
} else {
future.fail(new IllegalStateException(sm.getString(
"asyncChannelWrapperSecure.wrongStateWrite")));
}
} catch (Exception e) {
writing.set(false);
future.fail(e);
}
}
@Override
public void run() {
long written = 0;
try {
for (int i = offset; i < offset + length; i++) {
ByteBuffer src = srcs[i];
while (src.hasRemaining()) {
socketWriteBuffer.clear();
// Encrypt the data
SSLEngineResult r = sslEngine.wrap(src, socketWriteBuffer);
written += r.bytesConsumed();
Status s = r.getStatus();
if (s == Status.OK || s == Status.BUFFER_OVERFLOW) {
// Need to write out the bytes and may need to read from
// the source again to empty it
} else {
// Status.BUFFER_UNDERFLOW - only happens on unwrap
// Status.CLOSED - unexpected
throw new IllegalStateException(sm.getString(
"asyncChannelWrapperSecure.statusWrap"));
}
// Check for tasks
if (r.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
Runnable runnable = sslEngine.getDelegatedTask();
while (runnable != null) {
runnable.run();
runnable = sslEngine.getDelegatedTask();
}
}
socketWriteBuffer.flip();
// Do the write
int toWrite = r.bytesProduced();
while (toWrite > 0) {
Future<Integer> f =
socketChannel.write(socketWriteBuffer);
Integer socketWrite = f.get();
toWrite -= socketWrite.intValue();
}
}
}
if (writing.compareAndSet(true, false)) {
future.complete(Long.valueOf(written));
} else {
future.fail(new IllegalStateException(sm.getString(
"asyncChannelWrapperSecure.wrongStateWrite")));
}
} catch (Exception e) {
future.fail(e);
}
}
/**
* Read the channel for more information, then unwrap the
* (hopefully application) data we get.
* <p>
* If we run out of data, we'll return to our caller (possibly using
* a Selector) to get notification that more is available.
* <p>
* Each call to this method will perform at most one underlying read().
*/
@Override
public ByteBuffer handleRead() throws IOException {
readLock.lock();
try {
checkRequestBB();
SSLEngineResult result;
if (!initialHSComplete) {
throw new IllegalStateException();
}
int pos = requestBB.position();
if (sc.read(inNetBB) == -1) {
// probably throws exception
sslEngine.closeInbound();
throw new EOFException();
}
do {
// guarantees enough room for unwrap
resizeRequestBB(inNetBB.remaining());
inNetBB.flip();
result = sslEngine.unwrap(inNetBB, requestBB);
inNetBB.compact();
/*
* Could check here for a renegotation, but we're only
* doing a simple read/write, and won't have enough state
* transitions to do a complete handshake, so ignore that
* possibility.
*/
switch (result.getStatus()) {
case BUFFER_UNDERFLOW:
case OK:
if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
doTasks();
}
break;
default:
throw new IOException("sslEngine error during data read: " +
result.getStatus());
}
} while ((inNetBB.position() != 0) &&
result.getStatus() != Status.BUFFER_UNDERFLOW);
int readLength = requestBB.position() - pos;
ByteBuffer byteBuffer = ByteBuffer.allocate(readLength);
byteBuffer.put(BytesUtil.subBytes(requestBB.array(), pos, readLength));
return byteBuffer;
} catch (IOException e) {
close();
throw e;
} finally {
readLock.unlock();
}
}
public synchronized int read(ByteBuffer dst) throws IOException
{
if (socketChannel.socket().isInputShutdown())
{
throw new ClosedChannelException();
}
else if (initialized != 0)
{
handshake(SelectionKey.OP_READ);
return 0;
}
else if (shutdown)
{
shutdown();
return 0;
}
else if (sslEngine.isInboundDone())
{
return -1;
}
else if ((fill(inputBuffer[0]) < 0) && (inputBuffer[0].position() == 0))
{
return -1;
}
SSLEngineResult result;
Status status;
do
{
if (!prepare(inputCache, minCacheSize))
{
// Overflow!
break;
}
inputBuffer[0].flip();
try
{
result = sslEngine.unwrap(inputBuffer[0], inputCache[0]);
}
finally
{
inputBuffer[0].compact();
inputCache[0].flip();
}
status = result.getStatus();
if ((status == Status.OK) || (status == Status.BUFFER_UNDERFLOW))
{
if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK)
{
runTasks();
}
}
else
{
if (status == Status.CLOSED)
{
shutdown();
}
throw new IOException("Read error '" + result.getStatus()
+ '\'');
}
} while ((inputBuffer[0].position() != 0)
&& (status != Status.BUFFER_UNDERFLOW));
int n = inputCache[0].remaining();
if (n > 0)
{
if (n > dst.remaining())
{
n = dst.remaining();
}
for (int i = 0; i < n; i++)
{
dst.put(inputCache[0].get());
}
}
return n;
}
public synchronized int write(ByteBuffer src) throws IOException
{
if (socketChannel.socket().isOutputShutdown())
{
throw new ClosedChannelException();
}
else if (initialized != 0)
{
handshake(SelectionKey.OP_WRITE);
return 0;
}
else if (shutdown)
{
shutdown();
return 0;
}
// Check how much to write.
int t = src.remaining();
int n = 0;
// Write as much as we can.
SSLEngineResult result;
Status status;
do
{
if (!prepare(outputBuffer, minBufferSize))
{
// Overflow!
break;
}
inputBuffer[0].flip();
try
{
result = sslEngine.wrap(src, outputBuffer[0]);
}
finally
{
outputBuffer[0].flip();
}
n += result.bytesConsumed();
status = result.getStatus();
if (status == Status.OK)
{
if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK)
{
runTasks();
}
}
else
{
if (status == Status.CLOSED)
{
shutdown();
}
throw new IOException("Write error '" + result.getStatus() + '\'');
}
} while (n < t);
// Try to flush what we got.
flush();
return n;
}
/**
* Handshake unwrap.
*
* @param ops the current ready operations set.
* @return the interest set to continue or 0 if finished.
* @throws IOException on I/O errors.
*/
private synchronized int unwrap(int ops) throws IOException
{
// Fill the buffer, if applicable.
if ((ops & SelectionKey.OP_READ) != 0)
{
fill(inputBuffer[0]);
}
// Unwrap the buffer.
SSLEngineResult result;
Status status;
do
{
// Prepare the input cache, although no app
// data should be produced during handshake.
prepare(inputCache, minCacheSize);
inputBuffer[0].flip();
try
{
result = sslEngine.unwrap(inputBuffer[0], inputCache[0]);
}
finally
{
inputBuffer[0].compact();
inputCache[0].flip();
}
handshake = result.getHandshakeStatus();
status = result.getStatus();
if (status == Status.OK)
{
if (handshake == HandshakeStatus.NEED_TASK)
{
handshake = runTasks();
}
}
else if (status == Status.BUFFER_UNDERFLOW)
{
return SelectionKey.OP_READ;
}
else
{
// BUFFER_OVERFLOW/CLOSED
throw new IOException("Handshake failed '" + status + '\'');
}
} while (handshake == HandshakeStatus.NEED_UNWRAP);
return 0;
}
/**
* Handshake wrap.
*
* @param ops the current ready operations set.
* @return the interest set to continue or 0 if finished.
* @throws IOException on I/O errors.
*/
private synchronized int wrap(int ops) throws IOException
{
// Prepare the buffer.
if (prepare(outputBuffer, minBufferSize))
{
// Wrap the buffer.
SSLEngineResult result;
Status status;
try
{
result = sslEngine.wrap(emptyBuffer, outputBuffer[0]);
}
finally
{
outputBuffer[0].flip();
}
handshake = result.getHandshakeStatus();
status = result.getStatus();
if (status == Status.OK)
{
if (handshake == HandshakeStatus.NEED_TASK)
{
handshake = runTasks();
}
}
else
{
// BUFFER_OVERFLOW/BUFFER_UNDERFLOW/CLOSED
throw new IOException("Handshake failed '" + status + '\'');
}
}
// Flush the buffer, if applicable.
if ((ops & SelectionKey.OP_WRITE) != 0)
{
flush(outputBuffer[0]);
}
return outputBuffer[0].hasRemaining() ? SelectionKey.OP_WRITE : 0;
}
@Override
public void run() {
long written = 0;
try {
for (int i = offset; i < offset + length; i++) {
ByteBuffer src = srcs[i];
while (src.hasRemaining()) {
socketWriteBuffer.clear();
// Encrypt the data
SSLEngineResult r = sslEngine.wrap(src, socketWriteBuffer);
written += r.bytesConsumed();
Status s = r.getStatus();
if (s == Status.OK || s == Status.BUFFER_OVERFLOW) {
// Need to write out the bytes and may need to read from
// the source again to empty it
} else {
// Status.BUFFER_UNDERFLOW - only happens on unwrap
// Status.CLOSED - unexpected
throw new IllegalStateException(sm.getString(
"asyncChannelWrapperSecure.statusWrap"));
}
// Check for tasks
if (r.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
Runnable runnable = sslEngine.getDelegatedTask();
while (runnable != null) {
runnable.run();
runnable = sslEngine.getDelegatedTask();
}
}
socketWriteBuffer.flip();
// Do the write
int toWrite = r.bytesProduced();
while (toWrite > 0) {
Future<Integer> f =
socketChannel.write(socketWriteBuffer);
Integer socketWrite = f.get();
toWrite -= socketWrite.intValue();
}
}
}
if (writing.compareAndSet(true, false)) {
future.complete(Long.valueOf(written));
} else {
future.fail(new IllegalStateException(sm.getString(
"asyncChannelWrapperSecure.wrongStateWrite")));
}
} catch (Exception e) {
future.fail(e);
}
}