Work around an Android SSLEngine issue

Motivation:

Some Android SSLEngine implementations skip FINISHED handshake status
and go straightly into NOT_HANDSHAKING.  This behavior blocks SslHandler
from notifying its handshakeFuture, because we do the notification when
SSLEngine enters the FINISHED state.

Modification:

When the current handshake state is NOT_HANDSHAKING and the
handshakeFuture is not fulfilled yet, treat NOT_HANDSHAKING as FINISHED.

Result:

Better Android compatibility - fixes #1823
This commit is contained in:
Trustin Lee 2014-04-18 17:59:48 +09:00
parent 9e02a9bbee
commit e9161147a5

View File

@ -470,6 +470,8 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH
setHandshakeSuccess();
// deliberate fall-through
case NOT_HANDSHAKING:
setHandshakeSuccessIfStillHandshaking();
// deliberate fall-through
case NEED_WRAP:
finishWrap(ctx, out, promise, inUnwrap);
promise = null;
@ -541,6 +543,7 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH
case NEED_WRAP:
break;
case NOT_HANDSHAKING:
setHandshakeSuccessIfStillHandshaking();
// Workaround for TLS False Start problem reported at:
// https://github.com/netty/netty/issues/1108#issuecomment-14266970
if (!inUnwrap) {
@ -895,6 +898,10 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH
wrapLater = true;
continue;
case NOT_HANDSHAKING:
if (setHandshakeSuccessIfStillHandshaking()) {
wrapLater = true;
continue;
}
break;
default:
throw new IllegalStateException("Unknown handshake status: " + handshakeStatus);
@ -1006,6 +1013,21 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH
}
}
/**
* Works around some Android {@link SSLEngine} implementations that skip {@link HandshakeStatus#FINISHED} and
* go straight into {@link HandshakeStatus#NOT_HANDSHAKING} when handshake is finished.
*
* @return {@code true} if and only if the workaround has been applied and thus {@link #handshakeFuture} has been
* marked as success by this method
*/
private boolean setHandshakeSuccessIfStillHandshaking() {
if (!handshakePromise.isDone()) {
setHandshakeSuccess();
return true;
}
return false;
}
/**
* Notify all the handshake futures about the successfully handshake
*/