//
// ========================================================================
-// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
{
@Override
public void succeeded()
- {
+ {
}
@Override
getFillInterest().onFail(x);
getWriteFlusher().onFail(x);
}
-
+
},x);
}
};
// all data could be wrapped. So either we need to write some encrypted data,
// OR if we are handshaking we need to read some encrypted data OR
// if neither then we should just try the flush again.
- boolean flush = false;
+ boolean try_again = false;
synchronized (DecryptedEndPoint.this)
{
if (DEBUG)
}
else
{
- flush = true;
+ // We can get here because the WriteFlusher might not see progress
+ // when it has just flushed the encrypted data, but not consumed anymore
+ // of the application buffers. This is mostly avoided by another iteration
+ // within DecryptedEndPoint flush(), but I cannot convince myself that
+ // this is never ever the case.
+ try_again = true;
}
}
- if (flush)
+
+
+ if (try_again)
{
// If the output is closed,
if (isOutputShutdown())
else
{
// try to flush what is pending
- getWriteFlusher().completeWrite();
+ // because this is a special case (see above) we could probably
+ // avoid the dispatch, but best to be sure
+ getExecutor().execute(_runCompletWrite);
}
}
}
// Let's unwrap even if we have no net data because in that
// case we want to fall through to the handshake handling
int pos = BufferUtil.flipToFill(app_in);
- SSLEngineResult unwrapResult = _sslEngine.unwrap(_encryptedInput, app_in);
- BufferUtil.flipToFlush(app_in, pos);
+ SSLEngineResult unwrapResult;
+ try
+ {
+ unwrapResult = _sslEngine.unwrap(_encryptedInput, app_in);
+ }
+ finally
+ {
+ BufferUtil.flipToFlush(app_in, pos);
+ }
if (DEBUG)
LOG.debug("{} unwrap {}", SslConnection.this, unwrapResult);
HandshakeStatus unwrapHandshakeStatus = unwrapResult.getHandshakeStatus();
Status unwrapResultStatus = unwrapResult.getStatus();
- _underFlown = unwrapResultStatus == Status.BUFFER_UNDERFLOW;
+ // Extra check on unwrapResultStatus == OK with zero length buffer is due
+ // to SSL client on android (see bug #454773)
+ _underFlown = unwrapResultStatus == Status.BUFFER_UNDERFLOW || unwrapResultStatus == Status.OK && unwrapResult.bytesConsumed()==0 && unwrapResult.bytesProduced()==0;
if (_underFlown)
{
// or shutting down the output.
return -1;
}
+ case NEED_UNWRAP:
+ {
+ // We expected to read more, but we got closed.
+ // Return -1 to indicate to the application to drive the close.
+ return -1;
+ }
default:
{
throw new IllegalStateException();
}
catch (Exception e)
{
- getEndPoint().close();
+ close();
throw e;
}
finally
// We call sslEngine.wrap to try to take bytes from appOut buffers and encrypt them into the _netOut buffer
BufferUtil.compact(_encryptedOutput);
int pos = BufferUtil.flipToFill(_encryptedOutput);
- SSLEngineResult wrapResult = _sslEngine.wrap(appOuts, _encryptedOutput);
+ SSLEngineResult wrapResult;
+ try
+ {
+ wrapResult=_sslEngine.wrap(appOuts, _encryptedOutput);
+ }
+ finally
+ {
+ BufferUtil.flipToFlush(_encryptedOutput, pos);
+ }
+
if (DEBUG)
LOG.debug("{} wrap {}", SslConnection.this, wrapResult);
- BufferUtil.flipToFlush(_encryptedOutput, pos);
if (wrapResult.bytesConsumed()>0)
consumed+=wrapResult.bytesConsumed();
+ Status wrapResultStatus = wrapResult.getStatus();
boolean allConsumed=true;
- // clear empty buffers to prevent position creeping up the buffer
for (ByteBuffer b : appOuts)
- {
- if (BufferUtil.isEmpty(b))
- BufferUtil.clear(b);
- else
+ if (BufferUtil.hasContent(b))
allConsumed=false;
- }
-
- Status wrapResultStatus = wrapResult.getStatus();
// and deal with the results returned from the sslEngineWrap
switch (wrapResultStatus)
{
if (DEBUG)
LOG.debug("{} renegotiation denied", SslConnection.this);
- shutdownOutput();
+ getEndPoint().shutdownOutput();
return allConsumed;
}
// if we have net bytes, let's try to flush them
if (BufferUtil.hasContent(_encryptedOutput))
- getEndPoint().flush(_encryptedOutput);
+ if (!getEndPoint().flush(_encryptedOutput))
+ getEndPoint().flush(_encryptedOutput); // one retry
// But we also might have more to do for the handshaking state.
switch (handshakeStatus)
{
case NOT_HANDSHAKING:
- // Return with the number of bytes consumed (which may be 0)
+ // If we have not consumed all and had just finished handshaking, then we may
+ // have just flushed the last handshake in the encrypted buffers, so we should
+ // try again.
+ if (!allConsumed && wrapResult.getHandshakeStatus()==HandshakeStatus.FINISHED && BufferUtil.isEmpty(_encryptedOutput))
+ continue;
+
+ // Return true if we consumed all the bytes and encrypted are all flushed
return allConsumed && BufferUtil.isEmpty(_encryptedOutput);
case NEED_TASK:
}
}
}
- catch (Exception e)
- {
- getEndPoint().close();
- throw e;
- }
finally
{
if (DEBUG)