Make SslHandler work when autoRead is turned off

Related: #2958

Motivation:

SslHandler currently does not issue a read() request when it is
handshaking. It makes a connection with autoRead off stall, because a
user's read() request can be used to read the handshake response which
is invisible to the user.

Modifications:

- SslHandler now issues a read() request when:
  - the current handshake is in progress and channelReadComplete() is
    invoked
  - the current handshake is complete and a user issued a read() request
    during handshake
- Rename flushedBeforeHandshakeDone to flushedBeforeHandshake for
  consistency with the new variable 'readDuringHandshake'

Result:

SslHandler should work regardless whether autoRead is on or off.
This commit is contained in:
Trustin Lee 2014-12-11 17:48:45 +09:00
parent d1612f67ad
commit a0862bc5fb

View File

@ -200,7 +200,8 @@ public class SslHandler extends ByteToMessageDecoder {
private final boolean startTls;
private boolean sentFirstMessage;
private boolean flushedBeforeHandshakeDone;
private boolean flushedBeforeHandshake;
private boolean readDuringHandshake;
private PendingWriteQueue pendingUnencryptedWrites;
private Promise<Channel> handshakePromise = new LazyChannelPromise();
@ -364,6 +365,15 @@ public class SslHandler extends ByteToMessageDecoder {
closeOutboundAndChannel(ctx, promise, false);
}
@Override
public void read(ChannelHandlerContext ctx) throws Exception {
if (!handshakePromise.isDone()) {
readDuringHandshake = true;
}
ctx.read();
}
@Override
public void write(final ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
pendingUnencryptedWrites.add(msg, promise);
@ -383,7 +393,7 @@ public class SslHandler extends ByteToMessageDecoder {
pendingUnencryptedWrites.add(Unpooled.EMPTY_BUFFER, ctx.voidPromise());
}
if (!handshakePromise.isDone()) {
flushedBeforeHandshakeDone = true;
flushedBeforeHandshake = true;
}
wrap(ctx, false);
ctx.flush();
@ -840,7 +850,13 @@ public class SslHandler extends ByteToMessageDecoder {
needsFlush = false;
ctx.flush();
}
super.channelReadComplete(ctx);
// If handshake is not finished yet, we need more data.
if (!handshakePromise.isDone() && !ctx.channel().config().isAutoRead()) {
ctx.read();
}
ctx.fireChannelReadComplete();
}
/**
@ -904,11 +920,11 @@ public class SslHandler extends ByteToMessageDecoder {
wrapLater = true;
continue;
}
if (flushedBeforeHandshakeDone) {
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
flushedBeforeHandshakeDone = false;
flushedBeforeHandshake = false;
wrapLater = true;
}
@ -1012,6 +1028,11 @@ public class SslHandler extends ByteToMessageDecoder {
logger.debug(ctx.channel() + " HANDSHAKEN: " + engine.getSession().getCipherSuite());
}
ctx.fireUserEventTriggered(SslHandshakeCompletionEvent.SUCCESS);
if (readDuringHandshake && !ctx.channel().config().isAutoRead()) {
readDuringHandshake = false;
ctx.read();
}
}
/**