Ensure SslHandler.sslCloseFuture() is notified in all cases.

Motivation:

The SslHandler.sslCloseFuture() may not be notified when the Channel is closed before a closify_notify is received.

Modifications:

Ensure we try to fail the sslCloseFuture() when the Channel is closed.

Result:

Correctly notify the ssl close future.
This commit is contained in:
Norman Maurer 2017-01-11 14:31:53 +01:00
parent 91951a51ad
commit d37702aa69
2 changed files with 20 additions and 4 deletions

View File

@ -277,7 +277,7 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH
private PendingWriteQueue pendingUnencryptedWrites; private PendingWriteQueue pendingUnencryptedWrites;
private Promise<Channel> handshakePromise = new LazyChannelPromise(); private Promise<Channel> handshakePromise = new LazyChannelPromise();
private final LazyChannelPromise sslCloseFuture = new LazyChannelPromise(); private final LazyChannelPromise sslClosePromise = new LazyChannelPromise();
/** /**
* Set by wrap*() methods when something is produced. * Set by wrap*() methods when something is produced.
@ -456,7 +456,7 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH
* @see SSLEngine * @see SSLEngine
*/ */
public Future<Channel> sslCloseFuture() { public Future<Channel> sslCloseFuture() {
return sslCloseFuture; return sslClosePromise;
} }
@Override @Override
@ -770,6 +770,9 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH
// Make sure to release SSLEngine, // Make sure to release SSLEngine,
// and notify the handshake future if the connection has been closed during handshake. // and notify the handshake future if the connection has been closed during handshake.
setHandshakeFailure(ctx, CHANNEL_CLOSED, !outboundClosed); setHandshakeFailure(ctx, CHANNEL_CLOSED, !outboundClosed);
// Ensure we always notify the sslClosePromise as well
sslClosePromise.tryFailure(CHANNEL_CLOSED);
super.channelInactive(ctx); super.channelInactive(ctx);
} }
@ -804,7 +807,7 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH
* *
*/ */
private boolean ignoreException(Throwable t) { private boolean ignoreException(Throwable t) {
if (!(t instanceof SSLException) && t instanceof IOException && sslCloseFuture.isDone()) { if (!(t instanceof SSLException) && t instanceof IOException && sslClosePromise.isDone()) {
String message = String.valueOf(t.getMessage()).toLowerCase(); String message = String.valueOf(t.getMessage()).toLowerCase();
// first try to match connection reset / broke peer based on the regex. This is the fastest way // first try to match connection reset / broke peer based on the regex. This is the fastest way
@ -1129,7 +1132,7 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH
} }
if (notifyClosure) { if (notifyClosure) {
sslCloseFuture.trySuccess(ctx.channel()); sslClosePromise.trySuccess(ctx.channel());
} }
} finally { } finally {
if (decodeOut != null) { if (decodeOut != null) {

View File

@ -62,6 +62,7 @@ import io.netty.util.ReferenceCounted;
import java.io.File; import java.io.File;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.nio.channels.ClosedChannelException;
import java.security.KeyStore; import java.security.KeyStore;
import java.security.cert.CertificateException; import java.security.cert.CertificateException;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
@ -371,4 +372,16 @@ public class SslHandlerTest {
ReferenceCountUtil.release(sslClientCtx); ReferenceCountUtil.release(sslClientCtx);
} }
} }
@Test
public void testCloseFutureNotified() throws Exception {
SslHandler handler = new SslHandler(SSLContext.getDefault().createSSLEngine());
EmbeddedChannel ch = new EmbeddedChannel(handler);
// Closing the Channel will also produce a close_notify so it is expected to return true.
assertTrue(ch.finishAndReleaseAll());
assertTrue(handler.handshakeFuture().cause() instanceof ClosedChannelException);
assertTrue(handler.sslCloseFuture().cause() instanceof ClosedChannelException);
}
} }