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