下面列出了javax.net.ssl.SSLEngineResult.Status#BUFFER_UNDERFLOW 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
private void checkResult(SSLEngineResult result, boolean wrap)
throws SSLException {
handshakeStatus = result.getHandshakeStatus();
resultStatus = result.getStatus();
if (resultStatus != Status.OK &&
(wrap || resultStatus != Status.BUFFER_UNDERFLOW)) {
throw new SSLException(
sm.getString("asyncChannelWrapperSecure.check.notOk", resultStatus));
}
if (wrap && result.bytesConsumed() != 0) {
throw new SSLException(sm.getString("asyncChannelWrapperSecure.check.wrap"));
}
if (!wrap && result.bytesProduced() != 0) {
throw new SSLException(sm.getString("asyncChannelWrapperSecure.check.unwrap"));
}
}
public SSLSocketChannel2( SocketChannel channel , SSLEngine sslEngine , ExecutorService exec , SelectionKey key ) throws IOException {
if( channel == null || sslEngine == null || exec == null )
throw new IllegalArgumentException( "parameter must not be null" );
this.socketChannel = channel;
this.sslEngine = sslEngine;
this.exec = exec;
readEngineResult = writeEngineResult = new SSLEngineResult( Status.BUFFER_UNDERFLOW, sslEngine.getHandshakeStatus(), 0, 0 ); // init to prevent NPEs
tasks = new ArrayList<Future<?>>( 3 );
if( key != null ) {
key.interestOps( key.interestOps() | SelectionKey.OP_WRITE );
this.selectionKey = key;
}
createBuffers( sslEngine.getSession() );
// kick off handshake
socketChannel.write( wrap( emptybuffer ) );// initializes res
processHandshake();
}
/**
* Returns the current status for this TLSHandler.
*
* @return the current TLSStatus
*/
public TLSStatus getStatus() {
if (tlsEngineResult != null && tlsEngineResult.getStatus() == Status.BUFFER_UNDERFLOW) {
return TLSStatus.UNDERFLOW;
} else {
if (tlsEngineResult != null && tlsEngineResult.getStatus() == Status.CLOSED) {
return TLSStatus.CLOSED;
} else {
switch (tlsEngine.getHandshakeStatus()) {
case NEED_WRAP:
return TLSStatus.NEED_WRITE;
case NEED_UNWRAP:
return TLSStatus.NEED_READ;
default:
return TLSStatus.OK;
}
}
}
}
private void checkResult(SSLEngineResult result, boolean wrap)
throws SSLException {
handshakeStatus = result.getHandshakeStatus();
resultStatus = result.getStatus();
if (resultStatus != Status.OK &&
(wrap || resultStatus != Status.BUFFER_UNDERFLOW)) {
throw new SSLException("TODO");
}
if (wrap && result.bytesConsumed() != 0) {
throw new SSLException("TODO");
}
if (!wrap && result.bytesProduced() != 0) {
throw new SSLException("TODO");
}
}
public SSLSocketChannel2( SocketChannel channel , SSLEngine sslEngine , ExecutorService exec , SelectionKey key ) throws IOException {
if( channel == null || sslEngine == null || exec == null )
throw new IllegalArgumentException( "parameter must not be null" );
this.socketChannel = channel;
this.sslEngine = sslEngine;
this.exec = exec;
readEngineResult = writeEngineResult = new SSLEngineResult( Status.BUFFER_UNDERFLOW, sslEngine.getHandshakeStatus(), 0, 0 ); // init to prevent NPEs
tasks = new ArrayList<Future<?>>( 3 );
if( key != null ) {
key.interestOps( key.interestOps() | SelectionKey.OP_WRITE );
this.selectionKey = key;
}
createBuffers( sslEngine.getSession() );
// kick off handshake
socketChannel.write( wrap( emptybuffer ) );// initializes res
processHandshake();
}
private void checkResult(SSLEngineResult result, boolean wrap)
throws SSLException {
handshakeStatus = result.getHandshakeStatus();
resultStatus = result.getStatus();
if (resultStatus != Status.OK &&
(wrap || resultStatus != Status.BUFFER_UNDERFLOW)) {
throw new SSLException("TODO");
}
if (wrap && result.bytesConsumed() != 0) {
throw new SSLException("TODO");
}
if (!wrap && result.bytesProduced() != 0) {
throw new SSLException("TODO");
}
}
private void renegotiateIfNeeded(NextFilter nextFilter, SSLEngineResult res) throws Exception {
if (res.getStatus() != Status.CLOSED && res.getStatus() != Status.BUFFER_UNDERFLOW
&& res.getHandshakeStatus() != HandshakeStatus.NOT_HANDSHAKING) {
// Renegotiation required.
handshakeComplete = false;
handshakeStatus = res.getHandshakeStatus();
handshake(nextFilter);
}
}
private static void decryptOne(final SqSSL ssl, final ByteBuffer target) throws SSLException {
ssl.buffer.flip();
final SSLEngineResult result = unwrap(ssl, ssl.buffer, target);
checkStatus("Decrypt status", result, Status.OK, Status.BUFFER_UNDERFLOW, Status.CLOSED);
if (result.getStatus() == Status.OK || result.getStatus() == Status.BUFFER_UNDERFLOW) {
ssl.buffer.compact();
}
if (result.getStatus() == Status.CLOSED) {
connectionClosed(ssl);
}
}
private void performHandshake() throws IOException {
// Generate handshake message
final byte[] emptyMessage = new byte[0];
handshaking = true;
logger.debug("{} Performing Handshake", this);
try {
while (true) {
switch (engine.getHandshakeStatus()) {
case FINISHED:
return;
case NEED_WRAP: {
final ByteBuffer appDataOut = ByteBuffer.wrap(emptyMessage);
final ByteBuffer outboundBuffer = streamOutManager.prepareForWrite(engine.getSession().getApplicationBufferSize());
final SSLEngineResult wrapHelloResult = engine.wrap(appDataOut, outboundBuffer);
if (wrapHelloResult.getStatus() == Status.BUFFER_OVERFLOW) {
streamOutManager.prepareForWrite(engine.getSession().getApplicationBufferSize());
continue;
}
if (wrapHelloResult.getStatus() != Status.OK) {
throw new SSLHandshakeException("Could not generate SSL Handshake information: SSLEngineResult: "
+ wrapHelloResult.toString());
}
logger.trace("{} Handshake response after wrapping: {}", this, wrapHelloResult);
final ByteBuffer readableStreamOut = streamOutManager.prepareForRead(1);
final int bytesToSend = readableStreamOut.remaining();
writeFully(readableStreamOut);
logger.trace("{} Sent {} bytes of wrapped data for handshake", this, bytesToSend);
streamOutManager.clear();
}
continue;
case NEED_UNWRAP: {
final ByteBuffer readableDataIn = streamInManager.prepareForRead(0);
final ByteBuffer appData = appDataManager.prepareForWrite(engine.getSession().getApplicationBufferSize());
// Read handshake response from other side
logger.trace("{} Unwrapping: {} to {}", this, readableDataIn, appData);
SSLEngineResult handshakeResponseResult = engine.unwrap(readableDataIn, appData);
logger.trace("{} Handshake response after unwrapping: {}", this, handshakeResponseResult);
if (handshakeResponseResult.getStatus() == Status.BUFFER_UNDERFLOW) {
final ByteBuffer writableDataIn = streamInManager.prepareForWrite(engine.getSession().getPacketBufferSize());
final int bytesRead = readData(writableDataIn);
if (bytesRead > 0) {
logger.trace("{} Read {} bytes for handshake", this, bytesRead);
}
if (bytesRead < 0) {
throw new SSLHandshakeException("Reached End-of-File marker while performing handshake");
}
} else if (handshakeResponseResult.getStatus() == Status.CLOSED) {
throw new IOException("Channel was closed by peer during handshake");
} else {
streamInManager.compact();
appDataManager.clear();
}
}
break;
case NEED_TASK:
performTasks();
continue;
case NOT_HANDSHAKING:
return;
}
}
} finally {
handshaking = false;
}
}
@Override
public void run() {
int read = 0;
boolean forceRead = false;
try {
while (read == 0) {
socketReadBuffer.compact();
if (forceRead) {
forceRead = false;
Future<Integer> f = socketChannel.read(socketReadBuffer);
Integer socketRead = f.get();
if (socketRead.intValue() == -1) {
throw new EOFException(sm.getString(
"asyncChannelWrapperSecure.eof"));
}
}
socketReadBuffer.flip();
if (socketReadBuffer.hasRemaining()) {
// Decrypt the data in the buffer
SSLEngineResult r =
sslEngine.unwrap(socketReadBuffer, dest);
read += r.bytesProduced();
Status s = r.getStatus();
if (s == Status.OK) {
// Bytes available for reading and there may be
// sufficient data in the socketReadBuffer to
// support further reads without reading from the
// socket
} else if (s == Status.BUFFER_UNDERFLOW) {
// There is partial data in the socketReadBuffer
if (read == 0) {
// Need more data before the partial data can be
// processed and some output generated
forceRead = true;
}
// else return the data we have and deal with the
// partial data on the next read
} else if (s == Status.BUFFER_OVERFLOW) {
// Not enough space in the destination buffer to
// store all of the data. We could use a bytes read
// value of -bufferSizeRequired to signal the new
// buffer size required but an explicit exception is
// clearer.
if (reading.compareAndSet(true, false)) {
throw new ReadBufferOverflowException(sslEngine.
getSession().getApplicationBufferSize());
} else {
future.fail(new IllegalStateException(sm.getString(
"asyncChannelWrapperSecure.wrongStateRead")));
}
} else {
// Status.CLOSED - unexpected
throw new IllegalStateException(sm.getString(
"asyncChannelWrapperSecure.statusUnwrap"));
}
// Check for tasks
if (r.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
Runnable runnable = sslEngine.getDelegatedTask();
while (runnable != null) {
runnable.run();
runnable = sslEngine.getDelegatedTask();
}
}
} else {
forceRead = true;
}
}
if (reading.compareAndSet(true, false)) {
future.complete(Integer.valueOf(read));
} else {
future.fail(new IllegalStateException(sm.getString(
"asyncChannelWrapperSecure.wrongStateRead")));
}
} catch (Exception e) {
future.fail(e);
}
}
/**
* Blocks when in blocking mode until at least one byte has been decoded.<br>
* When not in blocking mode 0 may be returned.
*
* @return the number of bytes read.
**/
@Override
public int read(ByteBuffer dst) throws IOException {
while (true) {
if (!dst.hasRemaining()) {
return 0;
}
if (!isHandShakeComplete()) {
if (isBlocking()) {
while (!isHandShakeComplete()) {
processHandshake();
}
} else {
processHandshake();
if (!isHandShakeComplete()) {
return 0;
}
}
}
// assert ( bufferallocations > 1 ); //see #190
//if( bufferallocations <= 1 ) {
// createBuffers( sslEngine.getSession() );
//}
/* 1. When "dst" is smaller than "inData" readRemaining will fill "dst" with data
decoded in a previous read call.
* 2. When "inCrypt" contains more data than "inData" has remaining space, unwrap has
* to be called on more time(readRemaining)
*/
int purged = readRemaining(dst);
if (purged != 0) {
return purged;
}
/* We only continue when we really need more data from the network.
* Thats the case if inData is empty or inCrypt holds to less data than necessary for
* decryption
*/
assert (inData.position() == 0);
inData.clear();
if (!inCrypt.hasRemaining()) {
inCrypt.clear();
} else {
inCrypt.compact();
}
if (isBlocking() || readEngineResult.getStatus() == Status.BUFFER_UNDERFLOW) {
if (socketChannel.read(inCrypt) == -1) {
return -1;
}
}
inCrypt.flip();
unwrap();
int transfered = transfereTo(inData, dst);
if (transfered == 0 && isBlocking()) {
continue;
}
return transfered;
}
}
@Override
public boolean isNeedRead() {
return inData.hasRemaining() || (inCrypt.hasRemaining()
&& readEngineResult.getStatus() != Status.BUFFER_UNDERFLOW
&& readEngineResult.getStatus() != Status.CLOSED);
}
/**
* Unwraps inbound SSL records.
*/
private void unwrap(
ChannelHandlerContext ctx, ByteBuf packet, int offset, int length) throws SSLException {
boolean wrapLater = false;
boolean notifyClosure = false;
ByteBuf decodeOut = allocate(ctx, length);
try {
for (;;) {
final SSLEngineResult result = unwrap(engine, packet, offset, length, decodeOut);
final Status status = result.getStatus();
final HandshakeStatus handshakeStatus = result.getHandshakeStatus();
final int produced = result.bytesProduced();
final int consumed = result.bytesConsumed();
// Update indexes for the next iteration
offset += consumed;
length -= consumed;
if (status == Status.CLOSED) {
// notify about the CLOSED state of the SSLEngine. See #137
notifyClosure = true;
}
switch (handshakeStatus) {
case NEED_UNWRAP:
break;
case NEED_WRAP:
wrapNonAppData(ctx, true);
break;
case NEED_TASK:
runDelegatedTasks();
break;
case FINISHED:
setHandshakeSuccess();
wrapLater = true;
continue;
case NOT_HANDSHAKING:
if (setHandshakeSuccessIfStillHandshaking()) {
wrapLater = true;
continue;
}
if (flushedBeforeHandshake) {
// We need to call wrap(...) in case there was a flush done before the handshake completed.
//
// See https://github.com/netty/netty/pull/2437
flushedBeforeHandshake = false;
wrapLater = true;
}
break;
default:
throw new IllegalStateException("unknown handshake status: " + handshakeStatus);
}
if (status == Status.BUFFER_UNDERFLOW || consumed == 0 && produced == 0) {
break;
}
}
if (wrapLater) {
wrap(ctx, true);
}
if (notifyClosure) {
sslCloseFuture.trySuccess(ctx.channel());
}
} catch (SSLException e) {
setHandshakeFailure(ctx, e);
throw e;
} finally {
if (decodeOut.isReadable()) {
ctx.fireChannelRead(decodeOut);
} else {
decodeOut.release();
}
}
}
SSLStreams.WrapperResult recvAndUnwrap(ByteBuffer dst) throws IOException {
Status status = Status.OK;
SSLStreams.WrapperResult r = SSLStreams.this.new WrapperResult();
r.buf = dst;
if (this.closed) {
throw new IOException("Engine is closed");
} else {
boolean needData;
if (this.u_remaining > 0) {
this.unwrap_src.compact();
this.unwrap_src.flip();
needData = false;
} else {
this.unwrap_src.clear();
needData = true;
}
synchronized(this.unwrapLock) {
do {
if (needData) {
int x;
do {
x = this.chan.read(this.unwrap_src);
} while(x == 0);
if (x == -1) {
throw new IOException("connection closed for reading");
}
this.unwrap_src.flip();
}
r.result = this.engine.unwrap(this.unwrap_src, r.buf);
status = r.result.getStatus();
if (status == Status.BUFFER_UNDERFLOW) {
if (this.unwrap_src.limit() == this.unwrap_src.capacity()) {
this.unwrap_src = SSLStreams.this.realloc(this.unwrap_src, false, SSLStreams.BufType.PACKET);
} else {
this.unwrap_src.position(this.unwrap_src.limit());
this.unwrap_src.limit(this.unwrap_src.capacity());
}
needData = true;
} else if (status == Status.BUFFER_OVERFLOW) {
r.buf = SSLStreams.this.realloc(r.buf, true, SSLStreams.BufType.APPLICATION);
needData = false;
} else if (status == Status.CLOSED) {
this.closed = true;
r.buf.flip();
return r;
}
} while(status != Status.OK);
}
this.u_remaining = this.unwrap_src.remaining();
return r;
}
}
/**
* 读取SSL消息到缓冲区
*
* @return 接收数据大小
* @throws IOException IO异常
*/
public synchronized int unWarpByteBufferChannel() throws IOException {
ByteBufferChannel appByteBufferChannel = session.getReadByteBufferChannel();
if(!isEnoughToUnwarp()) {
return 0;
}
int readSize = 0;
if (session.isConnected() && sslByteBufferChannel.size() > 0) {
SSLEngineResult engineResult = null;
try {
while (true) {
appData.clear();
ByteBuffer byteBuffer = sslByteBufferChannel.getByteBuffer();;
try {
engineResult = unwarpData(byteBuffer, appData);
} finally {
sslByteBufferChannel.compact();
}
if (engineResult == null) {
throw new SSLException("unWarpByteBufferChannel: Socket is disconnect");
}
appData.flip();
appByteBufferChannel.writeEnd(appData);
if (engineResult != null &&
engineResult.getStatus() == Status.OK &&
byteBuffer.remaining() == 0) {
break;
}
if (engineResult != null &&
(engineResult.getStatus() == Status.BUFFER_OVERFLOW ||
engineResult.getStatus() == Status.BUFFER_UNDERFLOW ||
engineResult.getStatus() == Status.CLOSED)
) {
break;
}
}
}catch (MemoryReleasedException e){
if(!session.isConnected()) {
throw new SSLException("unWarpByteBufferChannel ", e);
}
}
}
return readSize;
}
SSLStreams.WrapperResult recvAndUnwrap(ByteBuffer dst) throws IOException {
Status status = Status.OK;
SSLStreams.WrapperResult r = SSLStreams.this.new WrapperResult();
r.buf = dst;
if (this.closed) {
throw new IOException("Engine is closed");
} else {
boolean needData;
if (this.u_remaining > 0) {
this.unwrap_src.compact();
this.unwrap_src.flip();
needData = false;
} else {
this.unwrap_src.clear();
needData = true;
}
Object var5 = this.unwrapLock;
synchronized(this.unwrapLock) {
do {
if (needData) {
int x;
do {
x = this.chan.read(this.unwrap_src);
} while(x == 0);
if (x == -1) {
throw new IOException("connection closed for reading");
}
this.unwrap_src.flip();
}
r.result = this.engine.unwrap(this.unwrap_src, r.buf);
status = r.result.getStatus();
if (status == Status.BUFFER_UNDERFLOW) {
if (this.unwrap_src.limit() == this.unwrap_src.capacity()) {
this.unwrap_src = SSLStreams.this.realloc(this.unwrap_src, false, SSLStreams.BufType.PACKET);
} else {
this.unwrap_src.position(this.unwrap_src.limit());
this.unwrap_src.limit(this.unwrap_src.capacity());
}
needData = true;
} else if (status == Status.BUFFER_OVERFLOW) {
r.buf = SSLStreams.this.realloc(r.buf, true, SSLStreams.BufType.APPLICATION);
needData = false;
} else if (status == Status.CLOSED) {
this.closed = true;
r.buf.flip();
return r;
}
} while(status != Status.OK);
}
this.u_remaining = this.unwrap_src.remaining();
return r;
}
}
private void performHandshake() throws IOException {
// Generate handshake message
final byte[] emptyMessage = new byte[0];
handshaking = true;
logger.debug("{} Performing Handshake", this);
try {
while (true) {
switch (engine.getHandshakeStatus()) {
case FINISHED:
return;
case NEED_WRAP: {
final ByteBuffer appDataOut = ByteBuffer.wrap(emptyMessage);
final ByteBuffer outboundBuffer = streamOutManager.prepareForWrite(engine.getSession().getApplicationBufferSize());
final SSLEngineResult wrapHelloResult = engine.wrap(appDataOut, outboundBuffer);
if (wrapHelloResult.getStatus() == Status.BUFFER_OVERFLOW) {
streamOutManager.prepareForWrite(engine.getSession().getApplicationBufferSize());
continue;
}
if (wrapHelloResult.getStatus() != Status.OK) {
throw new SSLHandshakeException("Could not generate SSL Handshake information: SSLEngineResult: "
+ wrapHelloResult.toString());
}
logger.trace("{} Handshake response after wrapping: {}", this, wrapHelloResult);
final ByteBuffer readableStreamOut = streamOutManager.prepareForRead(1);
final int bytesToSend = readableStreamOut.remaining();
writeFully(readableStreamOut);
logger.trace("{} Sent {} bytes of wrapped data for handshake", this, bytesToSend);
streamOutManager.clear();
}
continue;
case NEED_UNWRAP: {
final ByteBuffer readableDataIn = streamInManager.prepareForRead(0);
final ByteBuffer appData = appDataManager.prepareForWrite(engine.getSession().getApplicationBufferSize());
// Read handshake response from other side
logger.trace("{} Unwrapping: {} to {}", this, readableDataIn, appData);
SSLEngineResult handshakeResponseResult = engine.unwrap(readableDataIn, appData);
logger.trace("{} Handshake response after unwrapping: {}", this, handshakeResponseResult);
if (handshakeResponseResult.getStatus() == Status.BUFFER_UNDERFLOW) {
final ByteBuffer writableDataIn = streamInManager.prepareForWrite(engine.getSession().getPacketBufferSize());
final int bytesRead = readData(writableDataIn);
if (bytesRead > 0) {
logger.trace("{} Read {} bytes for handshake", this, bytesRead);
}
if (bytesRead < 0) {
throw new SSLHandshakeException("Reached End-of-File marker while performing handshake");
}
} else if (handshakeResponseResult.getStatus() == Status.CLOSED) {
throw new IOException("Channel was closed by peer during handshake");
} else {
streamInManager.compact();
appDataManager.clear();
}
}
break;
case NEED_TASK:
performTasks();
continue;
case NOT_HANDSHAKING:
return;
}
}
} finally {
handshaking = false;
}
}
@Override
public boolean isNeedRead() {
return inData.hasRemaining() || ( inCrypt.hasRemaining() && readEngineResult.getStatus() != Status.BUFFER_UNDERFLOW && readEngineResult.getStatus() != Status.CLOSED );
}
@Override
public void run() {
int read = 0;
boolean forceRead = false;
try {
while (read == 0) {
socketReadBuffer.compact();
if (forceRead) {
Future<Integer> f =
socketChannel.read(socketReadBuffer);
Integer socketRead = f.get();
if (socketRead.intValue() == -1) {
throw new EOFException(sm.getString(
"asyncChannelWrapperSecure.eof"));
}
}
socketReadBuffer.flip();
if (socketReadBuffer.hasRemaining()) {
// Decrypt the data in the buffer
SSLEngineResult r =
sslEngine.unwrap(socketReadBuffer, dest);
read += r.bytesProduced();
Status s = r.getStatus();
if (s == Status.OK) {
// Bytes available for reading and there may be
// sufficient data in the socketReadBuffer to
// support further reads without reading from the
// socket
} else if (s == Status.BUFFER_UNDERFLOW) {
// There is partial data in the socketReadBuffer
if (read == 0) {
// Need more data before the partial data can be
// processed and some output generated
forceRead = true;
}
// else return the data we have and deal with the
// partial data on the next read
} else if (s == Status.BUFFER_OVERFLOW) {
// Not enough space in the destination buffer to
// store all of the data. We could use a bytes read
// value of -bufferSizeRequired to signal the new
// buffer size required but an explicit exception is
// clearer.
if (reading.compareAndSet(true, false)) {
throw new ReadBufferOverflowException(sslEngine.
getSession().getApplicationBufferSize());
} else {
future.fail(new IllegalStateException(sm.getString(
"asyncChannelWrapperSecure.wrongStateRead")));
}
} else {
// Status.CLOSED - unexpected
throw new IllegalStateException(sm.getString(
"asyncChannelWrapperSecure.statusUnwrap"));
}
// Check for tasks
if (r.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
Runnable runnable = sslEngine.getDelegatedTask();
while (runnable != null) {
runnable.run();
runnable = sslEngine.getDelegatedTask();
}
}
} else {
forceRead = true;
}
}
if (reading.compareAndSet(true, false)) {
future.complete(Integer.valueOf(read));
} else {
future.fail(new IllegalStateException(sm.getString(
"asyncChannelWrapperSecure.wrongStateRead")));
}
} catch (Exception e) {
future.fail(e);
}
}
/**
* Blocks when in blocking mode until at least one byte has been decoded.<br>
* When not in blocking mode 0 may be returned.
*
* @return the number of bytes read.
**/
public int read(ByteBuffer dst) throws IOException {
while (true) {
if (!dst.hasRemaining())
return 0;
if (!isHandShakeComplete()) {
if (isBlocking()) {
while (!isHandShakeComplete()) {
processHandshake();
}
} else {
processHandshake();
if (!isHandShakeComplete()) {
return 0;
}
}
}
// assert ( bufferallocations > 1 ); //see #190
//if( bufferallocations <= 1 ) {
// createBuffers( sslEngine.getSession() );
//}
/* 1. When "dst" is smaller than "inData" readRemaining will fill "dst" with data decoded in a previous read call.
* 2. When "inCrypt" contains more data than "inData" has remaining space, unwrap has to be called on more time(readRemaining)
*/
int purged = readRemaining(dst);
if (purged != 0)
return purged;
/* We only continue when we really need more data from the network.
* Thats the case if inData is empty or inCrypt holds to less data than necessary for decryption
*/
assert (inData.position() == 0);
inData.clear();
if (!inCrypt.hasRemaining())
inCrypt.clear();
else
inCrypt.compact();
if (isBlocking() || readEngineResult.getStatus() == Status.BUFFER_UNDERFLOW)
if (socketChannel.read(inCrypt) == -1) {
return -1;
}
inCrypt.flip();
unwrap();
int transfered = transfereTo(inData, dst);
if (transfered == 0 && isBlocking()) {
continue;
}
return transfered;
}
}