Make sure SslHandler also works if SslBufferPool use non heap ByteBuffers. See #329
Conflicts: handler/src/main/java/io/netty/handler/ssl/SslHandler.java
This commit is contained in:
parent
14b2a0db99
commit
ed357181c0
@ -15,10 +15,22 @@
|
|||||||
*/
|
*/
|
||||||
package io.netty.handler.ssl;
|
package io.netty.handler.ssl;
|
||||||
|
|
||||||
import static io.netty.channel.Channels.*;
|
import io.netty.buffer.ChannelBuffer;
|
||||||
|
import io.netty.buffer.ChannelBuffers;
|
||||||
|
import io.netty.channel.Channel;
|
||||||
|
import io.netty.channel.ChannelFuture;
|
||||||
|
import io.netty.channel.ChannelFutureListener;
|
||||||
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
|
import io.netty.channel.ChannelPipeline;
|
||||||
|
import io.netty.channel.DefaultChannelFuture;
|
||||||
|
import io.netty.logging.InternalLogger;
|
||||||
|
import io.netty.logging.InternalLoggerFactory;
|
||||||
|
import io.netty.util.internal.NonReentrantLock;
|
||||||
|
import io.netty.util.internal.QueueFactory;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.channels.Channels;
|
||||||
import java.nio.channels.ClosedChannelException;
|
import java.nio.channels.ClosedChannelException;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
@ -32,28 +44,6 @@ import javax.net.ssl.SSLEngineResult.HandshakeStatus;
|
|||||||
import javax.net.ssl.SSLEngineResult.Status;
|
import javax.net.ssl.SSLEngineResult.Status;
|
||||||
import javax.net.ssl.SSLException;
|
import javax.net.ssl.SSLException;
|
||||||
|
|
||||||
import io.netty.buffer.ChannelBuffer;
|
|
||||||
import io.netty.buffer.ChannelBuffers;
|
|
||||||
import io.netty.channel.Channel;
|
|
||||||
import io.netty.channel.ChannelDownstreamHandler;
|
|
||||||
import io.netty.channel.ChannelEvent;
|
|
||||||
import io.netty.channel.ChannelFuture;
|
|
||||||
import io.netty.channel.ChannelFutureListener;
|
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
|
||||||
import io.netty.channel.ChannelPipeline;
|
|
||||||
import io.netty.channel.ChannelStateEvent;
|
|
||||||
import io.netty.channel.Channels;
|
|
||||||
import io.netty.channel.DefaultChannelFuture;
|
|
||||||
import io.netty.channel.DownstreamMessageEvent;
|
|
||||||
import io.netty.channel.ExceptionEvent;
|
|
||||||
import io.netty.channel.LifeCycleAwareChannelHandler;
|
|
||||||
import io.netty.channel.MessageEvent;
|
|
||||||
import io.netty.handler.codec.FrameDecoder;
|
|
||||||
import io.netty.logging.InternalLogger;
|
|
||||||
import io.netty.logging.InternalLoggerFactory;
|
|
||||||
import io.netty.util.internal.NonReentrantLock;
|
|
||||||
import io.netty.util.internal.QueueFactory;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds <a href="http://en.wikipedia.org/wiki/Transport_Layer_Security">SSL
|
* Adds <a href="http://en.wikipedia.org/wiki/Transport_Layer_Security">SSL
|
||||||
* · TLS</a> and StartTLS support to a {@link Channel}. Please refer
|
* · TLS</a> and StartTLS support to a {@link Channel}. Please refer
|
||||||
@ -72,10 +62,10 @@ import io.netty.util.internal.QueueFactory;
|
|||||||
* <p>
|
* <p>
|
||||||
* If {@link #isIssueHandshake()} is {@code false}
|
* If {@link #isIssueHandshake()} is {@code false}
|
||||||
* (default) you will need to take care of calling {@link #handshake()} by your own. In most situations were {@link SslHandler} is used in 'client mode'
|
* (default) you will need to take care of calling {@link #handshake()} by your own. In most situations were {@link SslHandler} is used in 'client mode'
|
||||||
* you want to issue a handshake once the connection was established. if {@link #setIssueHandshake(boolean)} is set to <code>true</code> you don't need to
|
* you want to issue a handshake once the connection was established. if {@link #setIssueHandshake(boolean)} is set to <code>true</code> you don't need to
|
||||||
* worry about this as the {@link SslHandler} will take care of it.
|
* worry about this as the {@link SslHandler} will take care of it.
|
||||||
* <p>
|
* <p>
|
||||||
*
|
*
|
||||||
* <h3>Renegotiation</h3>
|
* <h3>Renegotiation</h3>
|
||||||
* <p>
|
* <p>
|
||||||
* If {@link #isEnableRenegotiation() enableRenegotiation} is {@code true}
|
* If {@link #isEnableRenegotiation() enableRenegotiation} is {@code true}
|
||||||
@ -196,7 +186,7 @@ public class SslHandler extends FrameDecoder
|
|||||||
private final Queue<MessageEvent> pendingEncryptedWrites = QueueFactory.createQueue(MessageEvent.class);
|
private final Queue<MessageEvent> pendingEncryptedWrites = QueueFactory.createQueue(MessageEvent.class);
|
||||||
private final NonReentrantLock pendingEncryptedWritesLock = new NonReentrantLock();
|
private final NonReentrantLock pendingEncryptedWritesLock = new NonReentrantLock();
|
||||||
private volatile boolean issueHandshake;
|
private volatile boolean issueHandshake;
|
||||||
|
|
||||||
private static final ChannelFutureListener HANDSHAKE_LISTENER = new ChannelFutureListener() {
|
private static final ChannelFutureListener HANDSHAKE_LISTENER = new ChannelFutureListener() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -205,11 +195,11 @@ public class SslHandler extends FrameDecoder
|
|||||||
Channels.fireExceptionCaught(future.channel(), future.cause());
|
Channels.fireExceptionCaught(future.channel(), future.cause());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private final SSLEngineInboundCloseFuture sslEngineCloseFuture = new SSLEngineInboundCloseFuture();
|
private final SSLEngineInboundCloseFuture sslEngineCloseFuture = new SSLEngineInboundCloseFuture();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new instance.
|
* Creates a new instance.
|
||||||
*
|
*
|
||||||
@ -413,29 +403,29 @@ public class SslHandler extends FrameDecoder
|
|||||||
this.enableRenegotiation = enableRenegotiation;
|
this.enableRenegotiation = enableRenegotiation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enables or disables the automatic handshake once the {@link Channel} is connected. The value will only have affect if its set before the
|
* Enables or disables the automatic handshake once the {@link Channel} is connected. The value will only have affect if its set before the
|
||||||
* {@link Channel} is connected.
|
* {@link Channel} is connected.
|
||||||
*/
|
*/
|
||||||
public void setIssueHandshake(boolean issueHandshake) {
|
public void setIssueHandshake(boolean issueHandshake) {
|
||||||
this.issueHandshake = issueHandshake;
|
this.issueHandshake = issueHandshake;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns <code>true</code> if the automatic handshake is enabled
|
* Returns <code>true</code> if the automatic handshake is enabled
|
||||||
*/
|
*/
|
||||||
public boolean isIssueHandshake() {
|
public boolean isIssueHandshake() {
|
||||||
return issueHandshake;
|
return issueHandshake;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the {@link ChannelFuture} that will get notified if the inbound of the {@link SSLEngine} will get closed.
|
* Return the {@link ChannelFuture} that will get notified if the inbound of the {@link SSLEngine} will get closed.
|
||||||
*
|
*
|
||||||
* This method will return the same {@link ChannelFuture} all the time.
|
* This method will return the same {@link ChannelFuture} all the time.
|
||||||
*
|
*
|
||||||
* For more informations see the apidocs of {@link SSLEngine}
|
* For more informations see the apidocs of {@link SSLEngine}
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public ChannelFuture getSSLEngineInboundCloseFuture() {
|
public ChannelFuture getSSLEngineInboundCloseFuture() {
|
||||||
return sslEngineCloseFuture;
|
return sslEngineCloseFuture;
|
||||||
@ -535,7 +525,7 @@ public class SslHandler extends FrameDecoder
|
|||||||
"Swallowing an exception raised while " +
|
"Swallowing an exception raised while " +
|
||||||
"writing non-app data", cause);
|
"writing non-app data", cause);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -710,8 +700,14 @@ public class SslHandler extends FrameDecoder
|
|||||||
|
|
||||||
if (result.bytesProduced() > 0) {
|
if (result.bytesProduced() > 0) {
|
||||||
outNetBuf.flip();
|
outNetBuf.flip();
|
||||||
msg = ChannelBuffers.buffer(outNetBuf.remaining());
|
int remaining = outNetBuf.remaining();
|
||||||
msg.writeBytes(outNetBuf.array(), 0, msg.capacity());
|
msg = ChannelBuffers.buffer(remaining);
|
||||||
|
|
||||||
|
// Transfer the bytes to the new ChannelBuffer using some safe method that will also
|
||||||
|
// work with "non" heap buffers
|
||||||
|
//
|
||||||
|
// See https://github.com/netty/netty/issues/329
|
||||||
|
msg.writeBytes(outNetBuf);
|
||||||
outNetBuf.clear();
|
outNetBuf.clear();
|
||||||
|
|
||||||
if (pendingWrite.outAppBuf.hasRemaining()) {
|
if (pendingWrite.outAppBuf.hasRemaining()) {
|
||||||
@ -850,7 +846,12 @@ public class SslHandler extends FrameDecoder
|
|||||||
if (result.bytesProduced() > 0) {
|
if (result.bytesProduced() > 0) {
|
||||||
outNetBuf.flip();
|
outNetBuf.flip();
|
||||||
ChannelBuffer msg = ChannelBuffers.buffer(outNetBuf.remaining());
|
ChannelBuffer msg = ChannelBuffers.buffer(outNetBuf.remaining());
|
||||||
msg.writeBytes(outNetBuf.array(), 0, msg.capacity());
|
|
||||||
|
// Transfer the bytes to the new ChannelBuffer using some safe method that will also
|
||||||
|
// work with "non" heap buffers
|
||||||
|
//
|
||||||
|
// See https://github.com/netty/netty/issues/329
|
||||||
|
msg.writeBytes(outNetBuf);
|
||||||
outNetBuf.clear();
|
outNetBuf.clear();
|
||||||
|
|
||||||
future = future(channel);
|
future = future(channel);
|
||||||
@ -929,7 +930,7 @@ public class SslHandler extends FrameDecoder
|
|||||||
!engine.getUseClientMode() &&
|
!engine.getUseClientMode() &&
|
||||||
!engine.isInboundDone() && !engine.isOutboundDone()) {
|
!engine.isInboundDone() && !engine.isOutboundDone()) {
|
||||||
needsHandshake = true;
|
needsHandshake = true;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (needsHandshake) {
|
if (needsHandshake) {
|
||||||
@ -939,12 +940,12 @@ public class SslHandler extends FrameDecoder
|
|||||||
synchronized (handshakeLock) {
|
synchronized (handshakeLock) {
|
||||||
result = engine.unwrap(inNetBuf, outAppBuf);
|
result = engine.unwrap(inNetBuf, outAppBuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
// notify about the CLOSED state of the SSLEngine. See #137
|
// notify about the CLOSED state of the SSLEngine. See #137
|
||||||
if (result.getStatus() == Status.CLOSED) {
|
if (result.getStatus() == Status.CLOSED) {
|
||||||
sslEngineCloseFuture.setClosed();
|
sslEngineCloseFuture.setClosed();
|
||||||
}
|
}
|
||||||
|
|
||||||
final HandshakeStatus handshakeStatus = result.getHandshakeStatus();
|
final HandshakeStatus handshakeStatus = result.getHandshakeStatus();
|
||||||
handleRenegotiation(handshakeStatus);
|
handleRenegotiation(handshakeStatus);
|
||||||
switch (handshakeStatus) {
|
switch (handshakeStatus) {
|
||||||
@ -971,7 +972,7 @@ public class SslHandler extends FrameDecoder
|
|||||||
throw new IllegalStateException(
|
throw new IllegalStateException(
|
||||||
"Unknown handshake status: " + handshakeStatus);
|
"Unknown handshake status: " + handshakeStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needsWrap) {
|
if (needsWrap) {
|
||||||
@ -992,8 +993,12 @@ public class SslHandler extends FrameDecoder
|
|||||||
outAppBuf.flip();
|
outAppBuf.flip();
|
||||||
|
|
||||||
if (outAppBuf.hasRemaining()) {
|
if (outAppBuf.hasRemaining()) {
|
||||||
ChannelBuffer frame = ctx.channel().getConfig().getBufferFactory().getBuffer(outAppBuf.remaining());
|
ChannelBuffer frame = ctx.getChannel().getConfig().getBufferFactory().getBuffer(outAppBuf.remaining());
|
||||||
frame.writeBytes(outAppBuf.array(), 0, frame.capacity());
|
// Transfer the bytes to the new ChannelBuffer using some safe method that will also
|
||||||
|
// work with "non" heap buffers
|
||||||
|
//
|
||||||
|
// See https://github.com/netty/netty/issues/329
|
||||||
|
frame.writeBytes(outAppBuf);
|
||||||
return frame;
|
return frame;
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
@ -1108,7 +1113,7 @@ public class SslHandler extends FrameDecoder
|
|||||||
// is managing.
|
// is managing.
|
||||||
|
|
||||||
engine.closeOutbound();
|
engine.closeOutbound();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
engine.closeInbound();
|
engine.closeInbound();
|
||||||
} catch (SSLException e) {
|
} catch (SSLException e) {
|
||||||
@ -1120,7 +1125,7 @@ public class SslHandler extends FrameDecoder
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handshakeFuture.setFailure(cause);
|
handshakeFuture.setFailure(cause);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1216,7 +1221,7 @@ public class SslHandler extends FrameDecoder
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void afterRemove(ChannelHandlerContext ctx) throws Exception {
|
public void afterRemove(ChannelHandlerContext ctx) throws Exception {
|
||||||
|
|
||||||
// there is no need for synchronization here as we do not receive downstream events anymore
|
// there is no need for synchronization here as we do not receive downstream events anymore
|
||||||
Throwable cause = null;
|
Throwable cause = null;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
@ -1247,7 +1252,7 @@ public class SslHandler extends FrameDecoder
|
|||||||
fireExceptionCaughtLater(ctx, cause);
|
fireExceptionCaughtLater(ctx, cause);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calls {@link #handshake()} once the {@link Channel} is connected
|
* Calls {@link #handshake()} once the {@link Channel} is connected
|
||||||
@ -1259,9 +1264,9 @@ public class SslHandler extends FrameDecoder
|
|||||||
// while doing the handshake
|
// while doing the handshake
|
||||||
handshake().addListener(HANDSHAKE_LISTENER);
|
handshake().addListener(HANDSHAKE_LISTENER);
|
||||||
}
|
}
|
||||||
super.channelConnected(ctx, e);
|
super.channelConnected(ctx, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loop over all the pending writes and fail them.
|
* Loop over all the pending writes and fail them.
|
||||||
*
|
*
|
||||||
@ -1280,10 +1285,10 @@ public class SslHandler extends FrameDecoder
|
|||||||
cause = new ClosedChannelException();
|
cause = new ClosedChannelException();
|
||||||
}
|
}
|
||||||
pw.future.setFailure(cause);
|
pw.future.setFailure(cause);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
MessageEvent ev = pendingEncryptedWrites.poll();
|
MessageEvent ev = pendingEncryptedWrites.poll();
|
||||||
if (ev == null) {
|
if (ev == null) {
|
||||||
@ -1293,26 +1298,26 @@ public class SslHandler extends FrameDecoder
|
|||||||
cause = new ClosedChannelException();
|
cause = new ClosedChannelException();
|
||||||
}
|
}
|
||||||
ev.getFuture().setFailure(cause);
|
ev.getFuture().setFailure(cause);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cause != null) {
|
if (cause != null) {
|
||||||
fireExceptionCaught(ctx, cause);
|
fireExceptionCaught(ctx, cause);
|
||||||
}
|
}
|
||||||
|
|
||||||
super.channelClosed(ctx, e);
|
super.channelClosed(ctx, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final class SSLEngineInboundCloseFuture extends DefaultChannelFuture {
|
private final class SSLEngineInboundCloseFuture extends DefaultChannelFuture {
|
||||||
public SSLEngineInboundCloseFuture() {
|
public SSLEngineInboundCloseFuture() {
|
||||||
super(null, true);
|
super(null, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setClosed() {
|
void setClosed() {
|
||||||
super.setSuccess();
|
super.setSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Channel getChannel() {
|
public Channel getChannel() {
|
||||||
if (ctx == null) {
|
if (ctx == null) {
|
||||||
@ -1322,12 +1327,12 @@ public class SslHandler extends FrameDecoder
|
|||||||
return ctx.getChannel();
|
return ctx.getChannel();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean setSuccess() {
|
public boolean setSuccess() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean setFailure(Throwable cause) {
|
public boolean setFailure(Throwable cause) {
|
||||||
return false;
|
return false;
|
||||||
|
Loading…
Reference in New Issue
Block a user