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:
norman 2012-05-18 08:10:34 +02:00 committed by Trustin Lee
parent 14b2a0db99
commit ed357181c0

View File

@ -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
* &middot; TLS</a> and StartTLS support to a {@link Channel}. Please refer * &middot; 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;