Added JavaDoc to handler.ssl package

This commit is contained in:
Trustin Lee 2008-09-04 04:55:32 +00:00
parent 5a1f62f419
commit f0c2c95c32
3 changed files with 173 additions and 9 deletions

View File

@ -24,12 +24,26 @@ package org.jboss.netty.handler.ssl;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import javax.net.ssl.SSLEngine;
/** /**
* A {@link ByteBuffer} pool dedicated for {@link SslHandler} performance
* improvement.
* <p>
* In most cases, you won't need to create a new pool instance because
* {@link SslHandler} has a default pool instance internally.
* <p>
* The reason why {@link SslHandler} requires a buffer pool is because the
* current {@link SSLEngine} implementation always requires a 17KiB buffer for
* the 'wrap' and 'unwrap' operation. In most cases, the size of the required
* buffer is much smaller than that, and therefore allocating a 17KiB buffer
* for every 'wrap' and 'unwrap' operation wastes a lot of memory bandwidth,
* resulting in the application performance degradation.
*
* @author The Netty Project (netty-dev@lists.jboss.org) * @author The Netty Project (netty-dev@lists.jboss.org)
* @author Trustin Lee (tlee@redhat.com) * @author Trustin Lee (tlee@redhat.com)
* *
* @version $Rev$, $Date$ * @version $Rev$, $Date$
*
*/ */
public class SslBufferPool { public class SslBufferPool {
@ -41,29 +55,49 @@ public class SslBufferPool {
private final int maxBufferCount; private final int maxBufferCount;
private int index; private int index;
/**
* Creates a new buffer pool whose size is {@code 18113536}, which can
* hold {@code 1024} buffers.
*/
public SslBufferPool() { public SslBufferPool() {
this(DEFAULT_POOL_SIZE); this(DEFAULT_POOL_SIZE);
} }
public SslBufferPool(int poolSize) { /**
if (poolSize <= 0) { * Creates a new buffer pool.
throw new IllegalArgumentException("poolSize: " + poolSize); *
* @param maxPoolSize the maximum number of bytes that this pool can hold
*/
public SslBufferPool(int maxPoolSize) {
if (maxPoolSize <= 0) {
throw new IllegalArgumentException("maxPoolSize: " + maxPoolSize);
} }
int maxBufferCount = poolSize / MAX_PACKET_SIZE; int maxBufferCount = maxPoolSize / MAX_PACKET_SIZE;
if (poolSize % MAX_PACKET_SIZE != 0) { if (maxPoolSize % MAX_PACKET_SIZE != 0) {
maxBufferCount ++; maxBufferCount ++;
} }
poolSize = maxBufferCount * MAX_PACKET_SIZE; maxPoolSize = maxBufferCount * MAX_PACKET_SIZE;
pool = new ByteBuffer[maxBufferCount]; pool = new ByteBuffer[maxBufferCount];
this.maxBufferCount = maxBufferCount; this.maxBufferCount = maxBufferCount;
} }
/**
* Returns the maximum size of this pool in byte unit. The returned value
* can be somewhat different from what was specified in the constructor.
*/
public int getMaxPoolSize() { public int getMaxPoolSize() {
return maxBufferCount * MAX_PACKET_SIZE; return maxBufferCount * MAX_PACKET_SIZE;
} }
/**
* Returns the number of bytes which were allocated but not acquired yet.
* You can estimate how optimal the specified maximum pool size is from
* this value. If it keeps returning {@code 0}, it means the pool is
* getting exhausted. If it keeps returns a unnecessarily big value, it
* means the pool is wasting the heap space.
*/
public synchronized int getUnacquiredPoolSize() { public synchronized int getUnacquiredPoolSize() {
return index * MAX_PACKET_SIZE; return index * MAX_PACKET_SIZE;
} }

View File

@ -44,6 +44,7 @@ import org.jboss.netty.channel.ChannelEvent;
import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.ChannelFutureListener; import org.jboss.netty.channel.ChannelFutureListener;
import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.ChannelStateEvent;
import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.Channels;
import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.MessageEvent;
@ -51,6 +52,42 @@ import org.jboss.netty.handler.codec.frame.FrameDecoder;
import org.jboss.netty.util.ImmediateExecutor; import org.jboss.netty.util.ImmediateExecutor;
/** /**
* Adds <a href="http://en.wikipedia.org/wiki/Transport_Layer_Security">SSL
* &middot; TLS</a> and StartTLS support to a {@link Channel}. Please refer
* to the <strong>"SecureChat"</strong> example in the distribution or the web
* site for the detailed usage.
*
* <h3>Beginning the handshake</h3>
* <p>
* A user should make sure not to write a message while the
* {@linkplain #handshake(Channel) handshake} is in progress unless it's a
* renegotiation. You will be notified by the {@link ChannelFuture} which is
* returned by the {@link #handshake(Channel)} method when the handshake
* process succeeds or fails.
*
* <h3>Renegotiation</h3>
* <p>
* Once the initial handshake is done successfully. You can always call
* {@link #handshake(Channel)} again to renegotiate the SSL session parameters.
*
* <h3>Closing the session</h3>
* <p>
* To close the SSL session, the {@link #close(Channel)} method should be
* called to send the {@code close_notify} message to the remote peer. One
* exception is when you close the {@link Channel} - {@link SslHandler}
* intercepts the close request and send the {@code close_notify} message
* before the channel closure automatically. Once the SSL session is closed,
* it's not reusable, and consequently you should create a new
* {@link SslHandler} with a new {@link SSLEngine} as explained in the
* following section.
*
* <h3>Restarting the session</h3>
* <p>
* To restart the SSL session, you must remove the existing closed
* {@link SslHandler} from the {@link ChannelPipeline}, insert a new
* {@link SslHandler} with a new {@link SSLEngine} into the pipeline,
* and start the handshake process as described in the first section.
*
* @author The Netty Project (netty-dev@lists.jboss.org) * @author The Netty Project (netty-dev@lists.jboss.org)
* @author Trustin Lee (tlee@redhat.com) * @author Trustin Lee (tlee@redhat.com)
* *
@ -65,7 +102,11 @@ public class SslHandler extends FrameDecoder implements ChannelDownstreamHandler
private static SslBufferPool defaultBufferPool; private static SslBufferPool defaultBufferPool;
private static synchronized SslBufferPool getDefaultBufferPool() { /**
* Returns the default {@link SslBufferPool} used when no pool is
* specified in the constructor.
*/
public static synchronized SslBufferPool getDefaultBufferPool() {
if (defaultBufferPool == null) { if (defaultBufferPool == null) {
defaultBufferPool = new SslBufferPool(); defaultBufferPool = new SslBufferPool();
} }
@ -88,34 +129,110 @@ public class SslHandler extends FrameDecoder implements ChannelDownstreamHandler
private final Queue<PendingWrite> pendingUnencryptedWrites = new LinkedList<PendingWrite>(); private final Queue<PendingWrite> pendingUnencryptedWrites = new LinkedList<PendingWrite>();
private final Queue<MessageEvent> pendingEncryptedWrites = new LinkedList<MessageEvent>(); private final Queue<MessageEvent> pendingEncryptedWrites = new LinkedList<MessageEvent>();
/**
* Creates a new instance.
*
* @param engine the {@link SSLEngine} this handler will use
*/
public SslHandler(SSLEngine engine) { public SslHandler(SSLEngine engine) {
this(engine, getDefaultBufferPool(), ImmediateExecutor.INSTANCE); this(engine, getDefaultBufferPool(), ImmediateExecutor.INSTANCE);
} }
/**
* Creates a new instance.
*
* @param engine the {@link SSLEngine} this handler will use
* @param bufferPool the {@link SslBufferPool} where this handler will
* acquire the buffers required by the {@link SSLEngine}
*/
public SslHandler(SSLEngine engine, SslBufferPool bufferPool) { public SslHandler(SSLEngine engine, SslBufferPool bufferPool) {
this(engine, bufferPool, ImmediateExecutor.INSTANCE); this(engine, bufferPool, ImmediateExecutor.INSTANCE);
} }
/**
* Creates a new instance.
*
* @param engine the {@link SSLEngine} this handler will use
* @param startTls {@code true} if the first write request shouldn't be
* encrypted by the {@link SSLEngine}
*/
public SslHandler(SSLEngine engine, boolean startTls) { public SslHandler(SSLEngine engine, boolean startTls) {
this(engine, getDefaultBufferPool(), startTls); this(engine, getDefaultBufferPool(), startTls);
} }
/**
* Creates a new instance.
*
* @param engine the {@link SSLEngine} this handler will use
* @param bufferPool the {@link SslBufferPool} where this handler will
* acquire the buffers required by the {@link SSLEngine}
* @param startTls {@code true} if the first write request shouldn't be
* encrypted by the {@link SSLEngine}
*/
public SslHandler(SSLEngine engine, SslBufferPool bufferPool, boolean startTls) { public SslHandler(SSLEngine engine, SslBufferPool bufferPool, boolean startTls) {
this(engine, bufferPool, startTls, ImmediateExecutor.INSTANCE); this(engine, bufferPool, startTls, ImmediateExecutor.INSTANCE);
} }
/**
* Creates a new instance.
*
* @param engine
* the {@link SSLEngine} this handler will use
* @param delegatedTaskExecutor
* the {@link Executor} which will execute the delegated task
* that {@link SSLEngine#getDelegatedTask()} will return
*/
public SslHandler(SSLEngine engine, Executor delegatedTaskExecutor) { public SslHandler(SSLEngine engine, Executor delegatedTaskExecutor) {
this(engine, getDefaultBufferPool(), delegatedTaskExecutor); this(engine, getDefaultBufferPool(), delegatedTaskExecutor);
} }
/**
* Creates a new instance.
*
* @param engine
* the {@link SSLEngine} this handler will use
* @param bufferPool
* the {@link SslBufferPool} where this handler will acquire
* the buffers required by the {@link SSLEngine}
* @param delegatedTaskExecutor
* the {@link Executor} which will execute the delegated task
* that {@link SSLEngine#getDelegatedTask()} will return
*/
public SslHandler(SSLEngine engine, SslBufferPool bufferPool, Executor delegatedTaskExecutor) { public SslHandler(SSLEngine engine, SslBufferPool bufferPool, Executor delegatedTaskExecutor) {
this(engine, bufferPool, false, delegatedTaskExecutor); this(engine, bufferPool, false, delegatedTaskExecutor);
} }
/**
* Creates a new instance.
*
* @param engine
* the {@link SSLEngine} this handler will use
* @param startTls
* {@code true} if the first write request shouldn't be encrypted
* by the {@link SSLEngine}
* @param delegatedTaskExecutor
* the {@link Executor} which will execute the delegated task
* that {@link SSLEngine#getDelegatedTask()} will return
*/
public SslHandler(SSLEngine engine, boolean startTls, Executor delegatedTaskExecutor) { public SslHandler(SSLEngine engine, boolean startTls, Executor delegatedTaskExecutor) {
this(engine, getDefaultBufferPool(), startTls, delegatedTaskExecutor); this(engine, getDefaultBufferPool(), startTls, delegatedTaskExecutor);
} }
/**
* Creates a new instance.
*
* @param engine
* the {@link SSLEngine} this handler will use
* @param bufferPool
* the {@link SslBufferPool} where this handler will acquire
* the buffers required by the {@link SSLEngine}
* @param startTls
* {@code true} if the first write request shouldn't be encrypted
* by the {@link SSLEngine}
* @param delegatedTaskExecutor
* the {@link Executor} which will execute the delegated task
* that {@link SSLEngine#getDelegatedTask()} will return
*/
public SslHandler(SSLEngine engine, SslBufferPool bufferPool, boolean startTls, Executor delegatedTaskExecutor) { public SslHandler(SSLEngine engine, SslBufferPool bufferPool, boolean startTls, Executor delegatedTaskExecutor) {
if (engine == null) { if (engine == null) {
throw new NullPointerException("engine"); throw new NullPointerException("engine");
@ -132,10 +249,19 @@ public class SslHandler extends FrameDecoder implements ChannelDownstreamHandler
this.startTls = startTls; this.startTls = startTls;
} }
/**
* Returns the {@link SSLEngine} which is used by this handler.
*/
public SSLEngine getEngine() { public SSLEngine getEngine() {
return engine; return engine;
} }
/**
* Starts SSL / TLS handshake for the specified channel.
*
* @return a {@link ChannelFuture} which is notified when the handshake
* succeeds or fails.
*/
public ChannelFuture handshake(Channel channel) throws SSLException { public ChannelFuture handshake(Channel channel) throws SSLException {
ChannelFuture handshakeFuture; ChannelFuture handshakeFuture;
synchronized (handshakeLock) { synchronized (handshakeLock) {
@ -153,6 +279,10 @@ public class SslHandler extends FrameDecoder implements ChannelDownstreamHandler
return handshakeFuture; return handshakeFuture;
} }
/**
* Sends a SSL {@code close_notify} message to the specified channel and
* destroys the underlying {@link SSLEngine}.
*/
public ChannelFuture close(Channel channel) throws SSLException { public ChannelFuture close(Channel channel) throws SSLException {
ChannelHandlerContext ctx = context(channel); ChannelHandlerContext ctx = context(channel);
engine.closeOutbound(); engine.closeOutbound();

View File

@ -23,6 +23,6 @@
/** /**
* <a href="http://en.wikipedia.org/wiki/Transport_Layer_Security">SSL &middot; * <a href="http://en.wikipedia.org/wiki/Transport_Layer_Security">SSL &middot;
* TLS</a> implementation. * TLS</a> implementation based on {@link javax.net.ssl.SSLEngine}
*/ */
package org.jboss.netty.handler.ssl; package org.jboss.netty.handler.ssl;