View Javadoc

1   /*
2    * Copyright 2012 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  package org.jboss.netty.handler.ssl;
17  
18  import org.jboss.netty.buffer.ChannelBuffer;
19  import org.jboss.netty.buffer.ChannelBuffers;
20  import org.jboss.netty.channel.Channel;
21  import org.jboss.netty.channel.ChannelDownstreamHandler;
22  import org.jboss.netty.channel.ChannelEvent;
23  import org.jboss.netty.channel.ChannelFuture;
24  import org.jboss.netty.channel.ChannelFutureListener;
25  import org.jboss.netty.channel.ChannelHandlerContext;
26  import org.jboss.netty.channel.ChannelPipeline;
27  import org.jboss.netty.channel.ChannelStateEvent;
28  import org.jboss.netty.channel.Channels;
29  import org.jboss.netty.channel.DefaultChannelFuture;
30  import org.jboss.netty.channel.DownstreamMessageEvent;
31  import org.jboss.netty.channel.ExceptionEvent;
32  import org.jboss.netty.channel.MessageEvent;
33  import org.jboss.netty.handler.codec.frame.FrameDecoder;
34  import org.jboss.netty.logging.InternalLogger;
35  import org.jboss.netty.logging.InternalLoggerFactory;
36  import org.jboss.netty.util.Timeout;
37  import org.jboss.netty.util.Timer;
38  import org.jboss.netty.util.TimerTask;
39  import org.jboss.netty.util.internal.DetectionUtil;
40  import org.jboss.netty.util.internal.NonReentrantLock;
41  
42  import javax.net.ssl.SSLEngine;
43  import javax.net.ssl.SSLEngineResult;
44  import javax.net.ssl.SSLEngineResult.HandshakeStatus;
45  import javax.net.ssl.SSLEngineResult.Status;
46  import javax.net.ssl.SSLException;
47  import java.io.IOException;
48  import java.nio.ByteBuffer;
49  import java.nio.channels.ClosedChannelException;
50  import java.nio.channels.DatagramChannel;
51  import java.nio.channels.SocketChannel;
52  import java.util.LinkedList;
53  import java.util.Queue;
54  import java.util.concurrent.ConcurrentLinkedQueue;
55  import java.util.concurrent.Executor;
56  import java.util.concurrent.TimeUnit;
57  import java.util.concurrent.atomic.AtomicBoolean;
58  import java.util.regex.Pattern;
59  
60  import static org.jboss.netty.channel.Channels.*;
61  
62  /**
63   * Adds <a href="http://en.wikipedia.org/wiki/Transport_Layer_Security">SSL
64   * &middot; TLS</a> and StartTLS support to a {@link Channel}.  Please refer
65   * to the <strong>"SecureChat"</strong> example in the distribution or the web
66   * site for the detailed usage.
67   *
68   * <h3>Beginning the handshake</h3>
69   * <p>
70   * You must make sure not to write a message while the
71   * {@linkplain #handshake() handshake} is in progress unless you are
72   * renegotiating.  You will be notified by the {@link ChannelFuture} which is
73   * returned by the {@link #handshake()} method when the handshake
74   * process succeeds or fails.
75   *
76   * <h3>Handshake</h3>
77   * <p>
78   * If {@link #isIssueHandshake()} is {@code false}
79   * (default) you will need to take care of calling {@link #handshake()} by your own. In most
80   * situations were {@link SslHandler} is used in 'client mode' you want to issue a handshake once
81   * the connection was established. if {@link #setIssueHandshake(boolean)} is set to {@code true}
82   * you don't need to worry about this as the {@link SslHandler} will take care of it.
83   * <p>
84   *
85   * <h3>Renegotiation</h3>
86   * <p>
87   * If {@link #isEnableRenegotiation() enableRenegotiation} is {@code true}
88   * (default) and the initial handshake has been done successfully, you can call
89   * {@link #handshake()} to trigger the renegotiation.
90   * <p>
91   * If {@link #isEnableRenegotiation() enableRenegotiation} is {@code false},
92   * an attempt to trigger renegotiation will result in the connection closure.
93   * <p>
94   * Please note that TLS renegotiation had a security issue before.  If your
95   * runtime environment did not fix it, please make sure to disable TLS
96   * renegotiation by calling {@link #setEnableRenegotiation(boolean)} with
97   * {@code false}.  For more information, please refer to the following documents:
98   * <ul>
99   *   <li><a href="http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2009-3555">CVE-2009-3555</a></li>
100  *   <li><a href="http://www.ietf.org/rfc/rfc5746.txt">RFC5746</a></li>
101  *   <li><a href="http://www.oracle.com/technetwork/java/javase/documentation/tlsreadme2-176330.html">Phased
102  *       Approach to Fixing the TLS Renegotiation Issue</a></li>
103  * </ul>
104  *
105  * <h3>Closing the session</h3>
106  * <p>
107  * To close the SSL session, the {@link #close()} method should be
108  * called to send the {@code close_notify} message to the remote peer.  One
109  * exception is when you close the {@link Channel} - {@link SslHandler}
110  * intercepts the close request and send the {@code close_notify} message
111  * before the channel closure automatically.  Once the SSL session is closed,
112  * it is not reusable, and consequently you should create a new
113  * {@link SslHandler} with a new {@link SSLEngine} as explained in the
114  * following section.
115  *
116  * <h3>Restarting the session</h3>
117  * <p>
118  * To restart the SSL session, you must remove the existing closed
119  * {@link SslHandler} from the {@link ChannelPipeline}, insert a new
120  * {@link SslHandler} with a new {@link SSLEngine} into the pipeline,
121  * and start the handshake process as described in the first section.
122  *
123  * <h3>Implementing StartTLS</h3>
124  * <p>
125  * <a href="http://en.wikipedia.org/wiki/STARTTLS">StartTLS</a> is the
126  * communication pattern that secures the wire in the middle of the plaintext
127  * connection.  Please note that it is different from SSL &middot; TLS, that
128  * secures the wire from the beginning of the connection.  Typically, StartTLS
129  * is composed of three steps:
130  * <ol>
131  * <li>Client sends a StartTLS request to server.</li>
132  * <li>Server sends a StartTLS response to client.</li>
133  * <li>Client begins SSL handshake.</li>
134  * </ol>
135  * If you implement a server, you need to:
136  * <ol>
137  * <li>create a new {@link SslHandler} instance with {@code startTls} flag set
138  *     to {@code true},</li>
139  * <li>insert the {@link SslHandler} to the {@link ChannelPipeline}, and</li>
140  * <li>write a StartTLS response.</li>
141  * </ol>
142  * Please note that you must insert {@link SslHandler} <em>before</em> sending
143  * the StartTLS response.  Otherwise the client can send begin SSL handshake
144  * before {@link SslHandler} is inserted to the {@link ChannelPipeline}, causing
145  * data corruption.
146  * <p>
147  * The client-side implementation is much simpler.
148  * <ol>
149  * <li>Write a StartTLS request,</li>
150  * <li>wait for the StartTLS response,</li>
151  * <li>create a new {@link SslHandler} instance with {@code startTls} flag set
152  *     to {@code false},</li>
153  * <li>insert the {@link SslHandler} to the {@link ChannelPipeline}, and</li>
154  * <li>Initiate SSL handshake by calling {@link SslHandler#handshake()}.</li>
155  * </ol>
156  *
157  * <h3>Known issues</h3>
158  * <p>
159  * Because of a known issue with the current implementation of the SslEngine that comes
160  * with Java it may be possible that you see blocked IO-Threads while a full GC is done.
161  * <p>
162  * So if you are affected you can workaround this problem by adjust the cache settings
163  * like shown below:
164  *
165  * <pre>
166  *     SslContext context = ...;
167  *     context.getServerSessionContext().setSessionCacheSize(someSaneSize);
168  *     context.getServerSessionContext().setSessionTime(someSameTimeout);
169  * </pre>
170  * <p>
171  * What values to use here depends on the nature of your application and should be set
172  * based on monitoring and debugging of it.
173  * For more details see
174  * <a href="https://github.com/netty/netty/issues/832">#832</a> in our issue tracker.
175  * @apiviz.landmark
176  * @apiviz.uses org.jboss.netty.handler.ssl.SslBufferPool
177  */
178 public class SslHandler extends FrameDecoder
179                         implements ChannelDownstreamHandler {
180 
181     private static final InternalLogger logger =
182         InternalLoggerFactory.getInstance(SslHandler.class);
183 
184     private static final ByteBuffer EMPTY_BUFFER = ByteBuffer.allocate(0);
185 
186     private static final Pattern IGNORABLE_CLASS_IN_STACK = Pattern.compile(
187             "^.*(Socket|DatagramChannel|SctpChannel).*$");
188     private static final Pattern IGNORABLE_ERROR_MESSAGE = Pattern.compile(
189             "^.*(?:connection.*reset|connection.*closed|broken.*pipe).*$",
190             Pattern.CASE_INSENSITIVE);
191 
192     private static SslBufferPool defaultBufferPool;
193 
194     /**
195      * Returns the default {@link SslBufferPool} used when no pool is
196      * specified in the constructor.
197      */
198     public static synchronized SslBufferPool getDefaultBufferPool() {
199         if (defaultBufferPool == null) {
200             defaultBufferPool = new SslBufferPool();
201         }
202         return defaultBufferPool;
203     }
204 
205     private volatile ChannelHandlerContext ctx;
206     private final SSLEngine engine;
207     private final SslBufferPool bufferPool;
208     private final Executor delegatedTaskExecutor;
209     private final boolean startTls;
210 
211     private volatile boolean enableRenegotiation = true;
212 
213     final Object handshakeLock = new Object();
214     private boolean handshaking;
215     private volatile boolean handshaken;
216     private volatile ChannelFuture handshakeFuture;
217 
218     private final AtomicBoolean sentFirstMessage = new AtomicBoolean();
219     private final AtomicBoolean sentCloseNotify = new AtomicBoolean();
220     int ignoreClosedChannelException;
221     final Object ignoreClosedChannelExceptionLock = new Object();
222     private final Queue<PendingWrite> pendingUnencryptedWrites = new LinkedList<PendingWrite>();
223     private final Queue<MessageEvent> pendingEncryptedWrites = new ConcurrentLinkedQueue<MessageEvent>();
224     private final NonReentrantLock pendingEncryptedWritesLock = new NonReentrantLock();
225 
226     private volatile boolean issueHandshake;
227 
228     private final SSLEngineInboundCloseFuture sslEngineCloseFuture = new SSLEngineInboundCloseFuture();
229 
230     private boolean closeOnSSLException;
231 
232     private int packetLength = Integer.MIN_VALUE;
233 
234     private final Timer timer;
235     private final long handshakeTimeoutInMillis;
236     private Timeout handshakeTimeout;
237 
238     /**
239      * Creates a new instance.
240      *
241      * @param engine  the {@link SSLEngine} this handler will use
242      */
243     public SslHandler(SSLEngine engine) {
244         this(engine, getDefaultBufferPool(), ImmediateExecutor.INSTANCE);
245     }
246 
247     /**
248      * Creates a new instance.
249      *
250      * @param engine      the {@link SSLEngine} this handler will use
251      * @param bufferPool  the {@link SslBufferPool} where this handler will
252      *                    acquire the buffers required by the {@link SSLEngine}
253      */
254     public SslHandler(SSLEngine engine, SslBufferPool bufferPool) {
255         this(engine, bufferPool, ImmediateExecutor.INSTANCE);
256     }
257 
258     /**
259      * Creates a new instance.
260      *
261      * @param engine    the {@link SSLEngine} this handler will use
262      * @param startTls  {@code true} if the first write request shouldn't be
263      *                  encrypted by the {@link SSLEngine}
264      */
265     public SslHandler(SSLEngine engine, boolean startTls) {
266         this(engine, getDefaultBufferPool(), startTls);
267     }
268 
269     /**
270      * Creates a new instance.
271      *
272      * @param engine      the {@link SSLEngine} this handler will use
273      * @param bufferPool  the {@link SslBufferPool} where this handler will
274      *                    acquire the buffers required by the {@link SSLEngine}
275      * @param startTls    {@code true} if the first write request shouldn't be
276      *                    encrypted by the {@link SSLEngine}
277      */
278     public SslHandler(SSLEngine engine, SslBufferPool bufferPool, boolean startTls) {
279         this(engine, bufferPool, startTls, ImmediateExecutor.INSTANCE);
280     }
281 
282     /**
283      * Creates a new instance.
284      *
285      * @param engine
286      *        the {@link SSLEngine} this handler will use
287      * @param delegatedTaskExecutor
288      *        the {@link Executor} which will execute the delegated task
289      *        that {@link SSLEngine#getDelegatedTask()} will return
290      */
291     public SslHandler(SSLEngine engine, Executor delegatedTaskExecutor) {
292         this(engine, getDefaultBufferPool(), delegatedTaskExecutor);
293     }
294 
295     /**
296      * Creates a new instance.
297      *
298      * @param engine
299      *        the {@link SSLEngine} this handler will use
300      * @param bufferPool
301      *        the {@link SslBufferPool} where this handler will acquire
302      *        the buffers required by the {@link SSLEngine}
303      * @param delegatedTaskExecutor
304      *        the {@link Executor} which will execute the delegated task
305      *        that {@link SSLEngine#getDelegatedTask()} will return
306      */
307     public SslHandler(SSLEngine engine, SslBufferPool bufferPool, Executor delegatedTaskExecutor) {
308         this(engine, bufferPool, false, delegatedTaskExecutor);
309     }
310 
311     /**
312      * Creates a new instance.
313      *
314      * @param engine
315      *        the {@link SSLEngine} this handler will use
316      * @param startTls
317      *        {@code true} if the first write request shouldn't be encrypted
318      *        by the {@link SSLEngine}
319      * @param delegatedTaskExecutor
320      *        the {@link Executor} which will execute the delegated task
321      *        that {@link SSLEngine#getDelegatedTask()} will return
322      */
323     public SslHandler(SSLEngine engine, boolean startTls, Executor delegatedTaskExecutor) {
324         this(engine, getDefaultBufferPool(), startTls, delegatedTaskExecutor);
325     }
326 
327     /**
328      * Creates a new instance.
329      *
330      * @param engine
331      *        the {@link SSLEngine} this handler will use
332      * @param bufferPool
333      *        the {@link SslBufferPool} where this handler will acquire
334      *        the buffers required by the {@link SSLEngine}
335      * @param startTls
336      *        {@code true} if the first write request shouldn't be encrypted
337      *        by the {@link SSLEngine}
338      * @param delegatedTaskExecutor
339      *        the {@link Executor} which will execute the delegated task
340      *        that {@link SSLEngine#getDelegatedTask()} will return
341      */
342     public SslHandler(SSLEngine engine, SslBufferPool bufferPool, boolean startTls, Executor delegatedTaskExecutor) {
343         this(engine, bufferPool, startTls, delegatedTaskExecutor, null, 0);
344     }
345 
346     /**
347      * Creates a new instance.
348      *
349      * @param engine
350      *        the {@link SSLEngine} this handler will use
351      * @param bufferPool
352      *        the {@link SslBufferPool} where this handler will acquire
353      *        the buffers required by the {@link SSLEngine}
354      * @param startTls
355      *        {@code true} if the first write request shouldn't be encrypted
356      *        by the {@link SSLEngine}
357      * @param delegatedTaskExecutor
358      *        the {@link Executor} which will execute the delegated task
359      *        that {@link SSLEngine#getDelegatedTask()} will return
360      * @param timer
361      *        the {@link Timer} which will be used to process the timeout of the {@link #handshake()}.
362      *        Be aware that the given {@link Timer} will not get stopped automaticly, so it is up to you to cleanup
363      *        once you not need it anymore
364      * @param handshakeTimeoutInMillis
365      *        the time in milliseconds after whic the {@link #handshake()}  will be failed, and so the future notified
366      *
367      */
368     public SslHandler(SSLEngine engine, SslBufferPool bufferPool, boolean startTls, Executor delegatedTaskExecutor,
369                       Timer timer, long handshakeTimeoutInMillis) {
370         if (engine == null) {
371             throw new NullPointerException("engine");
372         }
373         if (bufferPool == null) {
374             throw new NullPointerException("bufferPool");
375         }
376         if (delegatedTaskExecutor == null) {
377             throw new NullPointerException("delegatedTaskExecutor");
378         }
379         if (timer == null && handshakeTimeoutInMillis > 0) {
380             throw new IllegalArgumentException("No Timer was given but a handshakeTimeoutInMillis, need both or none");
381         }
382 
383         this.engine = engine;
384         this.bufferPool = bufferPool;
385         this.delegatedTaskExecutor = delegatedTaskExecutor;
386         this.startTls = startTls;
387         this.timer = timer;
388         this.handshakeTimeoutInMillis = handshakeTimeoutInMillis;
389     }
390 
391     /**
392      * Returns the {@link SSLEngine} which is used by this handler.
393      */
394     public SSLEngine getEngine() {
395         return engine;
396     }
397 
398     /**
399      * Starts an SSL / TLS handshake for the specified channel.
400      *
401      * @return a {@link ChannelFuture} which is notified when the handshake
402      *         succeeds or fails.
403      */
404     public ChannelFuture handshake() {
405         synchronized (handshakeLock) {
406             if (handshaken && !isEnableRenegotiation()) {
407                 throw new IllegalStateException("renegotiation disabled");
408             }
409 
410             final ChannelHandlerContext ctx = this.ctx;
411             final Channel channel = ctx.getChannel();
412             ChannelFuture handshakeFuture;
413             Exception exception = null;
414 
415             if (handshaking) {
416                 return this.handshakeFuture;
417             }
418 
419             handshaking = true;
420             try {
421                 engine.beginHandshake();
422                 runDelegatedTasks();
423                 handshakeFuture = this.handshakeFuture = future(channel);
424                 if (handshakeTimeoutInMillis > 0) {
425                     handshakeTimeout = timer.newTimeout(new TimerTask() {
426                             public void run(Timeout timeout) throws Exception {
427                             ChannelFuture future = SslHandler.this.handshakeFuture;
428                             if (future != null && future.isDone()) {
429                                 return;
430                             }
431 
432                             setHandshakeFailure(channel, new SSLException("Handshake did not complete within " +
433                                             handshakeTimeoutInMillis + "ms"));
434                         }
435                         }, handshakeTimeoutInMillis, TimeUnit.MILLISECONDS);
436                 }
437             } catch (Exception e) {
438                 handshakeFuture = this.handshakeFuture = failedFuture(channel, e);
439                 exception = e;
440             }
441 
442             if (exception == null) { // Began handshake successfully.
443                 try {
444                     final ChannelFuture hsFuture = handshakeFuture;
445                     wrapNonAppData(ctx, channel).addListener(new ChannelFutureListener() {
446                         public void operationComplete(ChannelFuture future) throws Exception {
447                             if (!future.isSuccess()) {
448                                 Throwable cause = future.getCause();
449                                 hsFuture.setFailure(cause);
450 
451                                 fireExceptionCaught(ctx, cause);
452                                 if (closeOnSSLException) {
453                                     Channels.close(ctx, future(channel));
454                                 }
455                             }
456                         }
457                     });
458                 } catch (SSLException e) {
459                     handshakeFuture.setFailure(e);
460 
461                     fireExceptionCaught(ctx, e);
462                     if (closeOnSSLException) {
463                         Channels.close(ctx, future(channel));
464                     }
465                 }
466             } else { // Failed to initiate handshake.
467                 fireExceptionCaught(ctx, exception);
468                 if (closeOnSSLException) {
469                     Channels.close(ctx, future(channel));
470                 }
471             }
472             return handshakeFuture;
473         }
474     }
475 
476     /**
477      * @deprecated Use {@link #handshake()} instead.
478      */
479     @Deprecated
480     public ChannelFuture handshake(@SuppressWarnings("unused") Channel channel) {
481         return handshake();
482     }
483 
484     /**
485      * Sends an SSL {@code close_notify} message to the specified channel and
486      * destroys the underlying {@link SSLEngine}.
487      */
488     public ChannelFuture close() {
489         ChannelHandlerContext ctx = this.ctx;
490         Channel channel = ctx.getChannel();
491         try {
492             engine.closeOutbound();
493             return wrapNonAppData(ctx, channel);
494         } catch (SSLException e) {
495             fireExceptionCaught(ctx, e);
496             if (closeOnSSLException) {
497                 Channels.close(ctx, future(channel));
498             }
499             return failedFuture(channel, e);
500         }
501     }
502 
503     /**
504      * @deprecated Use {@link #close()} instead.
505      */
506     @Deprecated
507     public ChannelFuture close(@SuppressWarnings("unused") Channel channel) {
508         return close();
509     }
510 
511     /**
512      * Returns {@code true} if and only if TLS renegotiation is enabled.
513      */
514     public boolean isEnableRenegotiation() {
515         return enableRenegotiation;
516     }
517 
518     /**
519      * Enables or disables TLS renegotiation.
520      */
521     public void setEnableRenegotiation(boolean enableRenegotiation) {
522         this.enableRenegotiation = enableRenegotiation;
523     }
524 
525     /**
526      * Enables or disables the automatic handshake once the {@link Channel} is
527      * connected. The value will only have affect if its set before the
528      * {@link Channel} is connected.
529      */
530     public void setIssueHandshake(boolean issueHandshake) {
531         this.issueHandshake = issueHandshake;
532     }
533 
534     /**
535      * Returns {@code true} if the automatic handshake is enabled
536      */
537     public boolean isIssueHandshake() {
538         return issueHandshake;
539     }
540 
541     /**
542      * Return the {@link ChannelFuture} that will get notified if the inbound of the {@link SSLEngine} will get closed.
543      *
544      * This method will return the same {@link ChannelFuture} all the time.
545      *
546      * For more informations see the apidocs of {@link SSLEngine}
547      *
548      */
549     public ChannelFuture getSSLEngineInboundCloseFuture() {
550         return sslEngineCloseFuture;
551     }
552 
553     /**
554      * Return the timeout (in ms) after which the {@link ChannelFuture} of {@link #handshake()} will be failed, while
555      * a handshake is in progress
556      */
557     public long getHandshakeTimeout() {
558         return handshakeTimeoutInMillis;
559     }
560 
561     /**
562      * If set to {@code true}, the {@link Channel} will automatically get closed
563      * one a {@link SSLException} was caught. This is most times what you want, as after this
564      * its almost impossible to recover.
565      *
566      * Anyway the default is {@code false} to not break compatibility with older releases. This
567      * will be changed to {@code true} in the next major release.
568      *
569      */
570     public void setCloseOnSSLException(boolean closeOnSslException) {
571         if (ctx != null) {
572             throw new IllegalStateException("Can only get changed before attached to ChannelPipeline");
573         }
574         closeOnSSLException = closeOnSslException;
575     }
576 
577     public boolean getCloseOnSSLException() {
578         return closeOnSSLException;
579     }
580 
581     public void handleDownstream(
582             final ChannelHandlerContext context, final ChannelEvent evt) throws Exception {
583         if (evt instanceof ChannelStateEvent) {
584             ChannelStateEvent e = (ChannelStateEvent) evt;
585             switch (e.getState()) {
586             case OPEN:
587             case CONNECTED:
588             case BOUND:
589                 if (Boolean.FALSE.equals(e.getValue()) || e.getValue() == null) {
590                     closeOutboundAndChannel(context, e);
591                     return;
592                 }
593             }
594         }
595         if (!(evt instanceof MessageEvent)) {
596             context.sendDownstream(evt);
597             return;
598         }
599 
600         MessageEvent e = (MessageEvent) evt;
601         if (!(e.getMessage() instanceof ChannelBuffer)) {
602             context.sendDownstream(evt);
603             return;
604         }
605 
606         // Do not encrypt the first write request if this handler is
607         // created with startTLS flag turned on.
608         if (startTls && sentFirstMessage.compareAndSet(false, true)) {
609             context.sendDownstream(evt);
610             return;
611         }
612 
613         // Otherwise, all messages are encrypted.
614         ChannelBuffer msg = (ChannelBuffer) e.getMessage();
615         PendingWrite pendingWrite;
616 
617         if (msg.readable()) {
618             pendingWrite = new PendingWrite(evt.getFuture(), msg.toByteBuffer(msg.readerIndex(), msg.readableBytes()));
619         } else {
620             pendingWrite = new PendingWrite(evt.getFuture(), null);
621         }
622         synchronized (pendingUnencryptedWrites) {
623             boolean offered = pendingUnencryptedWrites.offer(pendingWrite);
624             assert offered;
625         }
626 
627         wrap(context, evt.getChannel());
628     }
629 
630     private void cancelHandshakeTimeout() {
631         if (handshakeTimeout != null) {
632             // cancel the task as we will fail the handshake future now
633             handshakeTimeout.cancel();
634         }
635     }
636 
637     @Override
638     public void channelDisconnected(ChannelHandlerContext ctx,
639             ChannelStateEvent e) throws Exception {
640 
641         // Make sure the handshake future is notified when a connection has
642         // been closed during handshake.
643         synchronized (handshakeLock) {
644             if (handshaking) {
645                 cancelHandshakeTimeout();
646                 handshakeFuture.setFailure(new ClosedChannelException());
647             }
648         }
649 
650         try {
651             super.channelDisconnected(ctx, e);
652         } finally {
653             unwrap(ctx, e.getChannel(), ChannelBuffers.EMPTY_BUFFER, 0, 0);
654             engine.closeOutbound();
655             if (!sentCloseNotify.get() && handshaken) {
656                 try {
657                     engine.closeInbound();
658                 } catch (SSLException ex) {
659                     if (logger.isDebugEnabled()) {
660                         logger.debug("Failed to clean up SSLEngine.", ex);
661                     }
662                 }
663             }
664         }
665     }
666     @Override
667     public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e)
668             throws Exception {
669 
670         Throwable cause = e.getCause();
671         if (cause instanceof IOException) {
672             if (cause instanceof ClosedChannelException) {
673                 synchronized (ignoreClosedChannelExceptionLock) {
674                     if (ignoreClosedChannelException > 0) {
675                         ignoreClosedChannelException --;
676                         if (logger.isDebugEnabled()) {
677                             logger.debug(
678                                     "Swallowing an exception raised while " +
679                                     "writing non-app data", cause);
680                         }
681 
682                         return;
683                     }
684                 }
685             } else {
686                 if (ignoreException(cause)) {
687                     return;
688                 }
689             }
690         }
691 
692         ctx.sendUpstream(e);
693     }
694 
695     /**
696      * Checks if the given {@link Throwable} can be ignore and just "swallowed"
697      *
698      * When an ssl connection is closed a close_notify message is sent.
699      * After that the peer also sends close_notify however, it's not mandatory to receive
700      * the close_notify. The party who sent the initial close_notify can close the connection immediately
701      * then the peer will get connection reset error.
702      *
703      */
704     private boolean ignoreException(Throwable t) {
705         if (!(t instanceof SSLException) && t instanceof IOException && engine.isOutboundDone()) {
706             String message = String.valueOf(t.getMessage()).toLowerCase();
707 
708             // first try to match connection reset / broke peer based on the regex. This is the fastest way
709             // but may fail on different jdk impls or OS's
710             if (IGNORABLE_ERROR_MESSAGE.matcher(message).matches()) {
711                 return true;
712             }
713 
714             // Inspect the StackTraceElements to see if it was a connection reset / broken pipe or not
715             StackTraceElement[] elements = t.getStackTrace();
716             for (StackTraceElement element: elements) {
717                 String classname = element.getClassName();
718                 String methodname = element.getMethodName();
719 
720                 // skip all classes that belong to the io.netty package
721                 if (classname.startsWith("org.jboss.netty.")) {
722                     continue;
723                 }
724 
725                 // check if the method name is read if not skip it
726                 if (!"read".equals(methodname)) {
727                     continue;
728                 }
729 
730                 // This will also match against SocketInputStream which is used by openjdk 7 and maybe
731                 // also others
732                 if (IGNORABLE_CLASS_IN_STACK.matcher(classname).matches()) {
733                     return true;
734                 }
735 
736                 try {
737                     // No match by now.. Try to load the class via classloader and inspect it.
738                     // This is mainly done as other JDK implementations may differ in name of
739                     // the impl.
740                     Class<?> clazz = getClass().getClassLoader().loadClass(classname);
741 
742                     if (SocketChannel.class.isAssignableFrom(clazz)
743                             || DatagramChannel.class.isAssignableFrom(clazz)) {
744                         return true;
745                     }
746 
747                     // also match against SctpChannel via String matching as it may not present.
748                     if (DetectionUtil.javaVersion() >= 7
749                             && "com.sun.nio.sctp.SctpChannel".equals(clazz.getSuperclass().getName())) {
750                         return true;
751                     }
752                 } catch (ClassNotFoundException e) {
753                     // This should not happen just ignore
754                 }
755             }
756         }
757 
758         return false;
759     }
760 
761     /**
762      * Returns {@code true} if the given {@link ChannelBuffer} is encrypted. Be aware that this method
763      * will not increase the readerIndex of the given {@link ChannelBuffer}.
764      *
765      * @param   buffer
766      *                  The {@link ChannelBuffer} to read from. Be aware that it must have at least 5 bytes to read,
767      *                  otherwise it will throw an {@link IllegalArgumentException}.
768      * @return encrypted
769      *                  {@code true} if the {@link ChannelBuffer} is encrypted, {@code false} otherwise.
770      * @throws IllegalArgumentException
771      *                  Is thrown if the given {@link ChannelBuffer} has not at least 5 bytes to read.
772      */
773     public static boolean isEncrypted(ChannelBuffer buffer) {
774         return getEncryptedPacketLength(buffer) != -1;
775     }
776 
777     /**
778      * Return how much bytes can be read out of the encrypted data. Be aware that this method will not increase
779      * the readerIndex of the given {@link ChannelBuffer}.
780      *
781      * @param   buffer
782      *                  The {@link ChannelBuffer} to read from. Be aware that it must have at least 5 bytes to read,
783      *                  otherwise it will throw an {@link IllegalArgumentException}.
784      * @return length
785      *                  The length of the encrypted packet that is included in the buffer. This will
786      *                  return {@code -1} if the given {@link ChannelBuffer} is not encrypted at all.
787      * @throws IllegalArgumentException
788      *                  Is thrown if the given {@link ChannelBuffer} has not at least 5 bytes to read.
789      */
790     private static int getEncryptedPacketLength(ChannelBuffer buffer) {
791         if (buffer.readableBytes() < 5) {
792             throw new IllegalArgumentException("buffer must have at least 5 readable bytes");
793         }
794 
795         int packetLength = 0;
796 
797         // SSLv3 or TLS - Check ContentType
798         boolean tls;
799         switch (buffer.getUnsignedByte(buffer.readerIndex())) {
800         case 20:  // change_cipher_spec
801         case 21:  // alert
802         case 22:  // handshake
803         case 23:  // application_data
804             tls = true;
805             break;
806         default:
807             // SSLv2 or bad data
808             tls = false;
809         }
810 
811         if (tls) {
812             // SSLv3 or TLS - Check ProtocolVersion
813             int majorVersion = buffer.getUnsignedByte(buffer.readerIndex() + 1);
814             if (majorVersion == 3) {
815                 // SSLv3 or TLS
816                 packetLength = (getShort(buffer, buffer.readerIndex() + 3) & 0xFFFF) + 5;
817                 if (packetLength <= 5) {
818                     // Neither SSLv3 or TLSv1 (i.e. SSLv2 or bad data)
819                     tls = false;
820                 }
821             } else {
822                 // Neither SSLv3 or TLSv1 (i.e. SSLv2 or bad data)
823                 tls = false;
824             }
825         }
826 
827         if (!tls) {
828             // SSLv2 or bad data - Check the version
829             boolean sslv2 = true;
830             int headerLength = (buffer.getUnsignedByte(
831                     buffer.readerIndex()) & 0x80) != 0 ? 2 : 3;
832             int majorVersion = buffer.getUnsignedByte(
833                     buffer.readerIndex() + headerLength + 1);
834             if (majorVersion == 2 || majorVersion == 3) {
835                 // SSLv2
836                 if (headerLength == 2) {
837                     packetLength = (getShort(buffer, buffer.readerIndex()) & 0x7FFF) + 2;
838                 } else {
839                     packetLength = (getShort(buffer, buffer.readerIndex()) & 0x3FFF) + 3;
840                 }
841                 if (packetLength <= headerLength) {
842                     sslv2 = false;
843                 }
844             } else {
845                 sslv2 = false;
846             }
847 
848             if (!sslv2) {
849                 return -1;
850             }
851         }
852         return packetLength;
853     }
854 
855     @Override
856     protected Object decode(
857             final ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) throws Exception {
858 
859         // Check if the packet length was parsed yet, if so we can skip the parsing
860         if (packetLength == Integer.MIN_VALUE) {
861             if (buffer.readableBytes() < 5) {
862                 return null;
863             }
864             int packetLength = getEncryptedPacketLength(buffer);
865 
866             if (packetLength == -1) {
867                 // Bad data - discard the buffer and raise an exception.
868                 NotSslRecordException e = new NotSslRecordException(
869                         "not an SSL/TLS record: " + ChannelBuffers.hexDump(buffer));
870                 buffer.skipBytes(buffer.readableBytes());
871 
872                 if (closeOnSSLException) {
873                     // first trigger the exception and then close the channel
874                     fireExceptionCaught(ctx, e);
875                     Channels.close(ctx, future(channel));
876 
877                     // just return null as we closed the channel before, that
878                     // will take care of cleanup etc
879                     return null;
880                 } else {
881                     throw e;
882                 }
883             }
884 
885             assert packetLength > 0;
886             this.packetLength = packetLength;
887         }
888 
889         if (buffer.readableBytes() < packetLength) {
890             return null;
891         }
892 
893         // We advance the buffer's readerIndex before calling unwrap() because
894         // unwrap() can trigger FrameDecoder call decode(), this method, recursively.
895         // The recursive call results in decoding the same packet twice if
896         // the readerIndex is advanced *after* decode().
897         //
898         // Here's an example:
899         // 1) An SSL packet is received from the wire.
900         // 2) SslHandler.decode() deciphers the packet and calls the user code.
901         // 3) The user closes the channel in the same thread.
902         // 4) The same thread triggers a channelDisconnected() event.
903         // 5) FrameDecoder.cleanup() is called, and it calls SslHandler.decode().
904         // 6) SslHandler.decode() will feed the same packet with what was
905         //    deciphered at the step 2 again if the readerIndex was not advanced
906         //    before calling the user code.
907         final int packetOffset = buffer.readerIndex();
908         buffer.skipBytes(packetLength);
909         try {
910             return unwrap(ctx, channel, buffer, packetOffset, packetLength);
911         } finally {
912             // reset the packet length so it will be parsed again on the next call
913             packetLength = Integer.MIN_VALUE;
914         }
915     }
916 
917     /**
918      * Reads a big-endian short integer from the buffer.  Please note that we do not use
919      * {@link ChannelBuffer#getShort(int)} because it might be a little-endian buffer.
920      */
921     private static short getShort(ChannelBuffer buf, int offset) {
922         return (short) (buf.getByte(offset) << 8 | buf.getByte(offset + 1) & 0xFF);
923     }
924 
925     private void wrap(ChannelHandlerContext context, Channel channel)
926             throws SSLException {
927 
928         ChannelBuffer msg;
929         ByteBuffer outNetBuf = bufferPool.acquireBuffer();
930         boolean success = true;
931         boolean offered = false;
932         boolean needsUnwrap = false;
933         PendingWrite pendingWrite = null;
934 
935         try {
936             loop:
937             for (;;) {
938                 // Acquire a lock to make sure unencrypted data is polled
939                 // in order and their encrypted counterpart is offered in
940                 // order.
941                 synchronized (pendingUnencryptedWrites) {
942                     pendingWrite = pendingUnencryptedWrites.peek();
943                     if (pendingWrite == null) {
944                         break;
945                     }
946 
947                     ByteBuffer outAppBuf = pendingWrite.outAppBuf;
948                     if (outAppBuf == null) {
949                         // A write request with an empty buffer
950                         pendingUnencryptedWrites.remove();
951                         offerEncryptedWriteRequest(
952                                 new DownstreamMessageEvent(
953                                         channel, pendingWrite.future,
954                                         ChannelBuffers.EMPTY_BUFFER,
955                                         channel.getRemoteAddress()));
956                         offered = true;
957                     } else {
958                         synchronized (handshakeLock) {
959                             SSLEngineResult result = null;
960                             try {
961                                 result = engine.wrap(outAppBuf, outNetBuf);
962                             } finally {
963                                 if (!outAppBuf.hasRemaining()) {
964                                     pendingUnencryptedWrites.remove();
965                                 }
966                             }
967 
968                             if (result.bytesProduced() > 0) {
969                                 outNetBuf.flip();
970                                 int remaining = outNetBuf.remaining();
971                                 msg = ctx.getChannel().getConfig().getBufferFactory().getBuffer(remaining);
972 
973                                 // Transfer the bytes to the new ChannelBuffer using some safe method that will also
974                                 // work with "non" heap buffers
975                                 //
976                                 // See https://github.com/netty/netty/issues/329
977                                 msg.writeBytes(outNetBuf);
978                                 outNetBuf.clear();
979 
980                                 ChannelFuture future;
981                                 if (pendingWrite.outAppBuf.hasRemaining()) {
982                                     // pendingWrite's future shouldn't be notified if
983                                     // only partial data is written.
984                                     future = succeededFuture(channel);
985                                 } else {
986                                     future = pendingWrite.future;
987                                 }
988 
989                                 MessageEvent encryptedWrite = new DownstreamMessageEvent(
990                                         channel, future, msg, channel.getRemoteAddress());
991                                 offerEncryptedWriteRequest(encryptedWrite);
992                                 offered = true;
993                             } else if (result.getStatus() == Status.CLOSED) {
994                                 // SSLEngine has been closed already.
995                                 // Any further write attempts should be denied.
996                                 success = false;
997                                 break;
998                             } else {
999                                 final HandshakeStatus handshakeStatus = result.getHandshakeStatus();
1000                                 handleRenegotiation(handshakeStatus);
1001                                 switch (handshakeStatus) {
1002                                 case NEED_WRAP:
1003                                     if (outAppBuf.hasRemaining()) {
1004                                         break;
1005                                     } else {
1006                                         break loop;
1007                                     }
1008                                 case NEED_UNWRAP:
1009                                     needsUnwrap = true;
1010                                     break loop;
1011                                 case NEED_TASK:
1012                                     runDelegatedTasks();
1013                                     break;
1014                                 case FINISHED:
1015                                 case NOT_HANDSHAKING:
1016                                     if (handshakeStatus == HandshakeStatus.FINISHED) {
1017                                         setHandshakeSuccess(channel);
1018                                     }
1019                                     if (result.getStatus() == Status.CLOSED) {
1020                                         success = false;
1021                                     }
1022                                     break loop;
1023                                 default:
1024                                     throw new IllegalStateException(
1025                                             "Unknown handshake status: " +
1026                                             handshakeStatus);
1027                                 }
1028                             }
1029                         }
1030                     }
1031                 }
1032             }
1033         } catch (SSLException e) {
1034             success = false;
1035             setHandshakeFailure(channel, e);
1036             throw e;
1037         } finally {
1038             bufferPool.releaseBuffer(outNetBuf);
1039 
1040             if (offered) {
1041                 flushPendingEncryptedWrites(context);
1042             }
1043 
1044             if (!success) {
1045                 IllegalStateException cause =
1046                     new IllegalStateException("SSLEngine already closed");
1047 
1048                 // Check if we had a pendingWrite in process, if so we need to also notify as otherwise
1049                 // the ChannelFuture will never get notified
1050                 if (pendingWrite != null) {
1051                     pendingWrite.future.setFailure(cause);
1052                 }
1053 
1054                 // Mark all remaining pending writes as failure if anything
1055                 // wrong happened before the write requests are wrapped.
1056                 // Please note that we do not call setFailure while a lock is
1057                 // acquired, to avoid a potential dead lock.
1058                 for (;;) {
1059                     synchronized (pendingUnencryptedWrites) {
1060                         pendingWrite = pendingUnencryptedWrites.poll();
1061                         if (pendingWrite == null) {
1062                             break;
1063                         }
1064                     }
1065 
1066                     pendingWrite.future.setFailure(cause);
1067                 }
1068             }
1069         }
1070 
1071         if (needsUnwrap) {
1072             unwrap(context, channel, ChannelBuffers.EMPTY_BUFFER, 0, 0);
1073         }
1074     }
1075 
1076     private void offerEncryptedWriteRequest(MessageEvent encryptedWrite) {
1077         final boolean locked = pendingEncryptedWritesLock.tryLock();
1078         try {
1079             pendingEncryptedWrites.offer(encryptedWrite);
1080         } finally {
1081             if (locked) {
1082                 pendingEncryptedWritesLock.unlock();
1083             }
1084         }
1085     }
1086 
1087     private void flushPendingEncryptedWrites(ChannelHandlerContext ctx) {
1088         while (!pendingEncryptedWrites.isEmpty()) {
1089             // Avoid possible dead lock and data integrity issue
1090             // which is caused by cross communication between more than one channel
1091             // in the same VM.
1092             if (!pendingEncryptedWritesLock.tryLock()) {
1093                 return;
1094             }
1095 
1096             try {
1097                 MessageEvent e;
1098                 while ((e = pendingEncryptedWrites.poll()) != null) {
1099                     ctx.sendDownstream(e);
1100                 }
1101             } finally {
1102                 pendingEncryptedWritesLock.unlock();
1103             }
1104 
1105             // Other thread might have added more elements at this point, so we loop again if the queue got unempty.
1106         }
1107     }
1108 
1109     private ChannelFuture wrapNonAppData(ChannelHandlerContext ctx, Channel channel) throws SSLException {
1110         ChannelFuture future = null;
1111         ByteBuffer outNetBuf = bufferPool.acquireBuffer();
1112 
1113         SSLEngineResult result;
1114         try {
1115             for (;;) {
1116                 synchronized (handshakeLock) {
1117                     result = engine.wrap(EMPTY_BUFFER, outNetBuf);
1118                 }
1119 
1120                 if (result.bytesProduced() > 0) {
1121                     outNetBuf.flip();
1122                     ChannelBuffer msg =
1123                             ctx.getChannel().getConfig().getBufferFactory().getBuffer(outNetBuf.remaining());
1124 
1125                     // Transfer the bytes to the new ChannelBuffer using some safe method that will also
1126                     // work with "non" heap buffers
1127                     //
1128                     // See https://github.com/netty/netty/issues/329
1129                     msg.writeBytes(outNetBuf);
1130                     outNetBuf.clear();
1131 
1132                     future = future(channel);
1133                     future.addListener(new ChannelFutureListener() {
1134                         public void operationComplete(ChannelFuture future)
1135                                 throws Exception {
1136                             if (future.getCause() instanceof ClosedChannelException) {
1137                                 synchronized (ignoreClosedChannelExceptionLock) {
1138                                     ignoreClosedChannelException ++;
1139                                 }
1140                             }
1141                         }
1142                     });
1143 
1144                     write(ctx, future, msg);
1145                 }
1146 
1147                 final HandshakeStatus handshakeStatus = result.getHandshakeStatus();
1148                 handleRenegotiation(handshakeStatus);
1149                 switch (handshakeStatus) {
1150                 case FINISHED:
1151                     setHandshakeSuccess(channel);
1152                     runDelegatedTasks();
1153                     break;
1154                 case NEED_TASK:
1155                     runDelegatedTasks();
1156                     break;
1157                 case NEED_UNWRAP:
1158                     if (!Thread.holdsLock(handshakeLock)) {
1159                         // unwrap shouldn't be called when this method was
1160                         // called by unwrap - unwrap will keep running after
1161                         // this method returns.
1162                         unwrap(ctx, channel, ChannelBuffers.EMPTY_BUFFER, 0, 0);
1163                     }
1164                     break;
1165                 case NOT_HANDSHAKING:
1166                 case NEED_WRAP:
1167                     break;
1168                 default:
1169                     throw new IllegalStateException(
1170                             "Unexpected handshake status: " + handshakeStatus);
1171                 }
1172 
1173                 if (result.bytesProduced() == 0) {
1174                     break;
1175                 }
1176             }
1177         } catch (SSLException e) {
1178             setHandshakeFailure(channel, e);
1179             throw e;
1180         } finally {
1181             bufferPool.releaseBuffer(outNetBuf);
1182         }
1183 
1184         if (future == null) {
1185             future = succeededFuture(channel);
1186         }
1187 
1188         return future;
1189     }
1190 
1191     private ChannelBuffer unwrap(
1192             ChannelHandlerContext ctx, Channel channel,
1193             ChannelBuffer buffer, int offset, int length) throws SSLException {
1194         ByteBuffer inNetBuf = buffer.toByteBuffer(offset, length);
1195         ByteBuffer outAppBuf = bufferPool.acquireBuffer();
1196 
1197         try {
1198             boolean needsWrap = false;
1199             loop:
1200             for (;;) {
1201                 SSLEngineResult result;
1202                 boolean needsHandshake = false;
1203                 synchronized (handshakeLock) {
1204                     if (!handshaken && !handshaking &&
1205                         !engine.getUseClientMode() &&
1206                         !engine.isInboundDone() && !engine.isOutboundDone()) {
1207                         needsHandshake = true;
1208                     }
1209                 }
1210 
1211                 if (needsHandshake) {
1212                     handshake();
1213                 }
1214 
1215                 synchronized (handshakeLock) {
1216                     result = engine.unwrap(inNetBuf, outAppBuf);
1217 
1218                     // notify about the CLOSED state of the SSLEngine. See #137
1219                     if (result.getStatus() == Status.CLOSED) {
1220                         sslEngineCloseFuture.setClosed();
1221                     }
1222 
1223                     final HandshakeStatus handshakeStatus = result.getHandshakeStatus();
1224                     handleRenegotiation(handshakeStatus);
1225                     switch (handshakeStatus) {
1226                     case NEED_UNWRAP:
1227                         if (inNetBuf.hasRemaining() && !engine.isInboundDone()) {
1228                             break;
1229                         } else {
1230                             break loop;
1231                         }
1232                     case NEED_WRAP:
1233                         wrapNonAppData(ctx, channel);
1234                         break;
1235                     case NEED_TASK:
1236                         runDelegatedTasks();
1237                         break;
1238                     case FINISHED:
1239                         setHandshakeSuccess(channel);
1240                         needsWrap = true;
1241                         break loop;
1242                     case NOT_HANDSHAKING:
1243                         needsWrap = true;
1244                         break loop;
1245                     default:
1246                         throw new IllegalStateException(
1247                                 "Unknown handshake status: " + handshakeStatus);
1248                     }
1249                 }
1250             }
1251             if (needsWrap) {
1252                 // wrap() acquires pendingUnencryptedWrites first and then
1253                 // handshakeLock.  If handshakeLock is already hold by the
1254                 // current thread, calling wrap() will lead to a dead lock
1255                 // i.e. pendingUnencryptedWrites -> handshakeLock vs.
1256                 //      handshakeLock -> pendingUnencryptedLock -> handshakeLock
1257                 //
1258                 // There is also a same issue between pendingEncryptedWrites
1259                 // and pendingUnencryptedWrites.
1260                 if (!Thread.holdsLock(handshakeLock) &&
1261                         !pendingEncryptedWritesLock.isHeldByCurrentThread()) {
1262                     wrap(ctx, channel);
1263                 }
1264             }
1265             outAppBuf.flip();
1266 
1267             if (outAppBuf.hasRemaining()) {
1268                 ChannelBuffer frame = ctx.getChannel().getConfig().getBufferFactory().getBuffer(outAppBuf.remaining());
1269                 // Transfer the bytes to the new ChannelBuffer using some safe method that will also
1270                 // work with "non" heap buffers
1271                 //
1272                 // See https://github.com/netty/netty/issues/329
1273                 frame.writeBytes(outAppBuf);
1274 
1275                 return frame;
1276             } else {
1277                 return null;
1278             }
1279         } catch (SSLException e) {
1280             setHandshakeFailure(channel, e);
1281             throw e;
1282         } finally {
1283             bufferPool.releaseBuffer(outAppBuf);
1284         }
1285     }
1286 
1287     private void handleRenegotiation(HandshakeStatus handshakeStatus) {
1288         synchronized (handshakeLock) {
1289             if (handshakeStatus == HandshakeStatus.NOT_HANDSHAKING ||
1290                 handshakeStatus == HandshakeStatus.FINISHED) {
1291                 // Not handshaking
1292                 return;
1293             }
1294 
1295             if (!handshaken) {
1296                 // Not renegotiation
1297                 return;
1298             }
1299 
1300             final boolean renegotiate;
1301             if (handshaking) {
1302                 // Renegotiation in progress or failed already.
1303                 // i.e. Renegotiation check has been done already below.
1304                 return;
1305             }
1306 
1307             if (engine.isInboundDone() || engine.isOutboundDone()) {
1308                 // Not handshaking but closing.
1309                 return;
1310             }
1311 
1312             if (isEnableRenegotiation()) {
1313                 // Continue renegotiation.
1314                 renegotiate = true;
1315             } else {
1316                 // Do not renegotiate.
1317                 renegotiate = false;
1318                 // Prevent reentrance of this method.
1319                 handshaking = true;
1320             }
1321 
1322             if (renegotiate) {
1323                 // Renegotiate.
1324                 handshake();
1325             } else {
1326                 // Raise an exception.
1327                 fireExceptionCaught(
1328                         ctx, new SSLException(
1329                                 "renegotiation attempted by peer; " +
1330                                 "closing the connection"));
1331 
1332                 // Close the connection to stop renegotiation.
1333                 Channels.close(ctx, succeededFuture(ctx.getChannel()));
1334             }
1335         }
1336     }
1337 
1338     private void runDelegatedTasks() {
1339         for (;;) {
1340             final Runnable task;
1341             synchronized (handshakeLock) {
1342                 task = engine.getDelegatedTask();
1343             }
1344 
1345             if (task == null) {
1346                 break;
1347             }
1348 
1349             delegatedTaskExecutor.execute(new Runnable() {
1350                 public void run() {
1351                     synchronized (handshakeLock) {
1352                         task.run();
1353                     }
1354                 }
1355             });
1356         }
1357     }
1358 
1359     private void setHandshakeSuccess(Channel channel) {
1360         synchronized (handshakeLock) {
1361             handshaking = false;
1362             handshaken = true;
1363 
1364             if (handshakeFuture == null) {
1365                 handshakeFuture = future(channel);
1366             }
1367             cancelHandshakeTimeout();
1368         }
1369 
1370         handshakeFuture.setSuccess();
1371     }
1372 
1373     private void setHandshakeFailure(Channel channel, SSLException cause) {
1374         synchronized (handshakeLock) {
1375             if (!handshaking) {
1376                 return;
1377             }
1378             handshaking = false;
1379             handshaken = false;
1380 
1381             if (handshakeFuture == null) {
1382                 handshakeFuture = future(channel);
1383             }
1384 
1385             // cancel the timeout now
1386             cancelHandshakeTimeout();
1387 
1388             // Release all resources such as internal buffers that SSLEngine
1389             // is managing.
1390 
1391             engine.closeOutbound();
1392 
1393             try {
1394                 engine.closeInbound();
1395             } catch (SSLException e) {
1396                 if (logger.isDebugEnabled()) {
1397                     logger.debug(
1398                             "SSLEngine.closeInbound() raised an exception after " +
1399                             "a handshake failure.", e);
1400                 }
1401             }
1402         }
1403 
1404         handshakeFuture.setFailure(cause);
1405         if (closeOnSSLException) {
1406             Channels.close(ctx, future(channel));
1407         }
1408     }
1409 
1410     private void closeOutboundAndChannel(
1411             final ChannelHandlerContext context, final ChannelStateEvent e) {
1412         if (!e.getChannel().isConnected()) {
1413             context.sendDownstream(e);
1414             return;
1415         }
1416 
1417         boolean success = false;
1418         try {
1419             try {
1420                 unwrap(context, e.getChannel(), ChannelBuffers.EMPTY_BUFFER, 0, 0);
1421             } catch (SSLException ex) {
1422                 if (logger.isDebugEnabled()) {
1423                     logger.debug("Failed to unwrap before sending a close_notify message", ex);
1424                 }
1425             }
1426 
1427             if (!engine.isInboundDone()) {
1428                 if (sentCloseNotify.compareAndSet(false, true)) {
1429                     engine.closeOutbound();
1430                     try {
1431                         ChannelFuture closeNotifyFuture = wrapNonAppData(context, e.getChannel());
1432                         closeNotifyFuture.addListener(
1433                                 new ClosingChannelFutureListener(context, e));
1434                         success = true;
1435                     } catch (SSLException ex) {
1436                         if (logger.isDebugEnabled()) {
1437                             logger.debug("Failed to encode a close_notify message", ex);
1438                         }
1439                     }
1440                 }
1441             } else {
1442                 success = true;
1443             }
1444         } finally {
1445             if (!success) {
1446                 context.sendDownstream(e);
1447             }
1448         }
1449     }
1450 
1451     private static final class PendingWrite {
1452         final ChannelFuture future;
1453         final ByteBuffer outAppBuf;
1454 
1455         PendingWrite(ChannelFuture future, ByteBuffer outAppBuf) {
1456             this.future = future;
1457             this.outAppBuf = outAppBuf;
1458         }
1459     }
1460 
1461     private static final class ClosingChannelFutureListener implements ChannelFutureListener {
1462 
1463         private final ChannelHandlerContext context;
1464         private final ChannelStateEvent e;
1465 
1466         ClosingChannelFutureListener(
1467                 ChannelHandlerContext context, ChannelStateEvent e) {
1468             this.context = context;
1469             this.e = e;
1470         }
1471 
1472         public void operationComplete(ChannelFuture closeNotifyFuture) throws Exception {
1473             if (!(closeNotifyFuture.getCause() instanceof ClosedChannelException)) {
1474                 Channels.close(context, e.getFuture());
1475             } else {
1476                 e.getFuture().setSuccess();
1477             }
1478         }
1479     }
1480 
1481     @Override
1482     public void beforeAdd(ChannelHandlerContext ctx) throws Exception {
1483         super.beforeAdd(ctx);
1484         this.ctx = ctx;
1485     }
1486 
1487     /**
1488      * Fail all pending writes which we were not able to flush out
1489      */
1490     @Override
1491     public void afterRemove(ChannelHandlerContext ctx) throws Exception {
1492 
1493         // there is no need for synchronization here as we do not receive downstream events anymore
1494         Throwable cause = null;
1495         for (;;) {
1496             PendingWrite pw = pendingUnencryptedWrites.poll();
1497             if (pw == null) {
1498                 break;
1499             }
1500             if (cause == null) {
1501                 cause = new IOException("Unable to write data");
1502             }
1503             pw.future.setFailure(cause);
1504         }
1505 
1506         for (;;) {
1507             MessageEvent ev = pendingEncryptedWrites.poll();
1508             if (ev == null) {
1509                 break;
1510             }
1511             if (cause == null) {
1512                 cause = new IOException("Unable to write data");
1513             }
1514             ev.getFuture().setFailure(cause);
1515         }
1516 
1517         if (cause != null) {
1518             fireExceptionCaughtLater(ctx, cause);
1519         }
1520     }
1521 
1522     /**
1523      * Calls {@link #handshake()} once the {@link Channel} is connected
1524      */
1525     @Override
1526     public void channelConnected(final ChannelHandlerContext ctx, final ChannelStateEvent e) throws Exception {
1527         if (issueHandshake) {
1528             // issue and handshake and add a listener to it which will fire an exception event if
1529             // an exception was thrown while doing the handshake
1530             handshake().addListener(new ChannelFutureListener() {
1531 
1532                 public void operationComplete(ChannelFuture future) throws Exception {
1533                     if (!future.isSuccess()) {
1534                         fireExceptionCaught(future.getChannel(), future.getCause());
1535                     } else {
1536                         // Send the event upstream after the handshake was completed without an error.
1537                         //
1538                         // See https://github.com/netty/netty/issues/358
1539                         ctx.sendUpstream(e);
1540                     }
1541                 }
1542             });
1543         } else {
1544             super.channelConnected(ctx, e);
1545         }
1546     }
1547 
1548     /**
1549      * Loop over all the pending writes and fail them.
1550      *
1551      * See <a href="https://github.com/netty/netty/issues/305">#305</a> for more details.
1552      */
1553     @Override
1554     public void channelClosed(final ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
1555         // Move the fail of the writes to the IO-Thread to prevent possible deadlock
1556         // See https://github.com/netty/netty/issues/989
1557         ctx.getPipeline().execute(new Runnable() {
1558             public void run() {
1559                 Throwable cause = null;
1560                 synchronized (pendingUnencryptedWrites) {
1561                     for (;;) {
1562                         PendingWrite pw = pendingUnencryptedWrites.poll();
1563                         if (pw == null) {
1564                             break;
1565                         }
1566                         if (cause == null) {
1567                             cause = new ClosedChannelException();
1568                         }
1569                         pw.future.setFailure(cause);
1570                     }
1571 
1572                     for (;;) {
1573                         MessageEvent ev = pendingEncryptedWrites.poll();
1574                         if (ev == null) {
1575                             break;
1576                         }
1577                         if (cause == null) {
1578                             cause = new ClosedChannelException();
1579                         }
1580                         ev.getFuture().setFailure(cause);
1581                     }
1582                 }
1583 
1584                 if (cause != null) {
1585                     fireExceptionCaught(ctx, cause);
1586                 }
1587             }
1588         });
1589 
1590         super.channelClosed(ctx, e);
1591     }
1592 
1593     private final class SSLEngineInboundCloseFuture extends DefaultChannelFuture {
1594         public SSLEngineInboundCloseFuture() {
1595             super(null, true);
1596         }
1597 
1598         void setClosed() {
1599             super.setSuccess();
1600         }
1601 
1602         @Override
1603         public Channel getChannel() {
1604             if (ctx == null) {
1605                 // Maybe we should better throw an IllegalStateException() ?
1606                 return null;
1607             } else {
1608                 return ctx.getChannel();
1609             }
1610         }
1611 
1612         @Override
1613         public boolean setSuccess() {
1614             return false;
1615         }
1616 
1617         @Override
1618         public boolean setFailure(Throwable cause) {
1619             return false;
1620         }
1621     }
1622 }