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 io.netty.handler.ssl;
17  
18  import io.netty.buffer.ByteBuf;
19  import io.netty.buffer.ByteBufAllocator;
20  import io.netty.buffer.ByteBufUtil;
21  import io.netty.buffer.CompositeByteBuf;
22  import io.netty.buffer.Unpooled;
23  import io.netty.channel.AbstractCoalescingBufferQueue;
24  import io.netty.channel.Channel;
25  import io.netty.channel.ChannelConfig;
26  import io.netty.channel.ChannelException;
27  import io.netty.channel.ChannelFuture;
28  import io.netty.channel.ChannelFutureListener;
29  import io.netty.channel.ChannelHandlerContext;
30  import io.netty.channel.ChannelInboundHandler;
31  import io.netty.channel.ChannelOutboundHandler;
32  import io.netty.channel.ChannelPipeline;
33  import io.netty.channel.ChannelPromise;
34  import io.netty.channel.ChannelPromiseNotifier;
35  import io.netty.handler.codec.ByteToMessageDecoder;
36  import io.netty.handler.codec.DecoderException;
37  import io.netty.handler.codec.UnsupportedMessageTypeException;
38  import io.netty.util.ReferenceCountUtil;
39  import io.netty.util.ReferenceCounted;
40  import io.netty.util.concurrent.DefaultPromise;
41  import io.netty.util.concurrent.EventExecutor;
42  import io.netty.util.concurrent.Future;
43  import io.netty.util.concurrent.FutureListener;
44  import io.netty.util.concurrent.ImmediateExecutor;
45  import io.netty.util.concurrent.Promise;
46  import io.netty.util.concurrent.PromiseNotifier;
47  import io.netty.util.internal.ObjectUtil;
48  import io.netty.util.internal.PlatformDependent;
49  import io.netty.util.internal.UnstableApi;
50  import io.netty.util.internal.logging.InternalLogger;
51  import io.netty.util.internal.logging.InternalLoggerFactory;
52  
53  import java.io.IOException;
54  import java.net.SocketAddress;
55  import java.nio.ByteBuffer;
56  import java.nio.channels.ClosedChannelException;
57  import java.nio.channels.DatagramChannel;
58  import java.nio.channels.SocketChannel;
59  import java.util.List;
60  import java.util.concurrent.Executor;
61  import java.util.concurrent.RejectedExecutionException;
62  import java.util.concurrent.ScheduledFuture;
63  import java.util.concurrent.TimeUnit;
64  import java.util.regex.Pattern;
65  
66  import javax.net.ssl.SSLEngine;
67  import javax.net.ssl.SSLEngineResult;
68  import javax.net.ssl.SSLEngineResult.HandshakeStatus;
69  import javax.net.ssl.SSLEngineResult.Status;
70  import javax.net.ssl.SSLException;
71  import javax.net.ssl.SSLHandshakeException;
72  import javax.net.ssl.SSLSession;
73  
74  import static io.netty.buffer.ByteBufUtil.ensureWritableSuccess;
75  import static io.netty.handler.ssl.SslUtils.getEncryptedPacketLength;
76  
77  /**
78   * Adds <a href="http://en.wikipedia.org/wiki/Transport_Layer_Security">SSL
79   * &middot; TLS</a> and StartTLS support to a {@link Channel}.  Please refer
80   * to the <strong>"SecureChat"</strong> example in the distribution or the web
81   * site for the detailed usage.
82   *
83   * <h3>Beginning the handshake</h3>
84   * <p>
85   * Beside using the handshake {@link ChannelFuture} to get notified about the completion of the handshake it's
86   * also possible to detect it by implement the
87   * {@link ChannelInboundHandler#userEventTriggered(ChannelHandlerContext, Object)}
88   * method and check for a {@link SslHandshakeCompletionEvent}.
89   *
90   * <h3>Handshake</h3>
91   * <p>
92   * The handshake will be automatically issued for you once the {@link Channel} is active and
93   * {@link SSLEngine#getUseClientMode()} returns {@code true}.
94   * So no need to bother with it by your self.
95   *
96   * <h3>Closing the session</h3>
97   * <p>
98   * To close the SSL session, the {@link #closeOutbound()} method should be
99   * called to send the {@code close_notify} message to the remote peer. One
100  * exception is when you close the {@link Channel} - {@link SslHandler}
101  * intercepts the close request and send the {@code close_notify} message
102  * before the channel closure automatically.  Once the SSL session is closed,
103  * it is not reusable, and consequently you should create a new
104  * {@link SslHandler} with a new {@link SSLEngine} as explained in the
105  * following section.
106  *
107  * <h3>Restarting the session</h3>
108  * <p>
109  * To restart the SSL session, you must remove the existing closed
110  * {@link SslHandler} from the {@link ChannelPipeline}, insert a new
111  * {@link SslHandler} with a new {@link SSLEngine} into the pipeline,
112  * and start the handshake process as described in the first section.
113  *
114  * <h3>Implementing StartTLS</h3>
115  * <p>
116  * <a href="http://en.wikipedia.org/wiki/STARTTLS">StartTLS</a> is the
117  * communication pattern that secures the wire in the middle of the plaintext
118  * connection.  Please note that it is different from SSL &middot; TLS, that
119  * secures the wire from the beginning of the connection.  Typically, StartTLS
120  * is composed of three steps:
121  * <ol>
122  * <li>Client sends a StartTLS request to server.</li>
123  * <li>Server sends a StartTLS response to client.</li>
124  * <li>Client begins SSL handshake.</li>
125  * </ol>
126  * If you implement a server, you need to:
127  * <ol>
128  * <li>create a new {@link SslHandler} instance with {@code startTls} flag set
129  *     to {@code true},</li>
130  * <li>insert the {@link SslHandler} to the {@link ChannelPipeline}, and</li>
131  * <li>write a StartTLS response.</li>
132  * </ol>
133  * Please note that you must insert {@link SslHandler} <em>before</em> sending
134  * the StartTLS response.  Otherwise the client can send begin SSL handshake
135  * before {@link SslHandler} is inserted to the {@link ChannelPipeline}, causing
136  * data corruption.
137  * <p>
138  * The client-side implementation is much simpler.
139  * <ol>
140  * <li>Write a StartTLS request,</li>
141  * <li>wait for the StartTLS response,</li>
142  * <li>create a new {@link SslHandler} instance with {@code startTls} flag set
143  *     to {@code false},</li>
144  * <li>insert the {@link SslHandler} to the {@link ChannelPipeline}, and</li>
145  * <li>Initiate SSL handshake.</li>
146  * </ol>
147  *
148  * <h3>Known issues</h3>
149  * <p>
150  * Because of a known issue with the current implementation of the SslEngine that comes
151  * with Java it may be possible that you see blocked IO-Threads while a full GC is done.
152  * <p>
153  * So if you are affected you can workaround this problem by adjust the cache settings
154  * like shown below:
155  *
156  * <pre>
157  *     SslContext context = ...;
158  *     context.getServerSessionContext().setSessionCacheSize(someSaneSize);
159  *     context.getServerSessionContext().setSessionTime(someSameTimeout);
160  * </pre>
161  * <p>
162  * What values to use here depends on the nature of your application and should be set
163  * based on monitoring and debugging of it.
164  * For more details see
165  * <a href="https://github.com/netty/netty/issues/832">#832</a> in our issue tracker.
166  */
167 public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundHandler {
168 
169     private static final InternalLogger logger =
170             InternalLoggerFactory.getInstance(SslHandler.class);
171 
172     private static final Pattern IGNORABLE_CLASS_IN_STACK = Pattern.compile(
173             "^.*(?:Socket|Datagram|Sctp|Udt)Channel.*$");
174     private static final Pattern IGNORABLE_ERROR_MESSAGE = Pattern.compile(
175             "^.*(?:connection.*(?:reset|closed|abort|broken)|broken.*pipe).*$", Pattern.CASE_INSENSITIVE);
176 
177     /**
178      * <a href="https://tools.ietf.org/html/rfc5246#section-6.2">2^14</a> which is the maximum sized plaintext chunk
179      * allowed by the TLS RFC.
180      */
181     private static final int MAX_PLAINTEXT_LENGTH = 16 * 1024;
182 
183     private enum SslEngineType {
184         TCNATIVE(true, COMPOSITE_CUMULATOR) {
185             @Override
186             SSLEngineResult unwrap(SslHandler handler, ByteBuf in, int readerIndex, int len, ByteBuf out)
187                     throws SSLException {
188                 int nioBufferCount = in.nioBufferCount();
189                 int writerIndex = out.writerIndex();
190                 final SSLEngineResult result;
191                 if (nioBufferCount > 1) {
192                     /*
193                      * If {@link OpenSslEngine} is in use,
194                      * we can use a special {@link OpenSslEngine#unwrap(ByteBuffer[], ByteBuffer[])} method
195                      * that accepts multiple {@link ByteBuffer}s without additional memory copies.
196                      */
197                     ReferenceCountedOpenSslEngine opensslEngine = (ReferenceCountedOpenSslEngine) handler.engine;
198                     try {
199                         handler.singleBuffer[0] = toByteBuffer(out, writerIndex,
200                             out.writableBytes());
201                         result = opensslEngine.unwrap(in.nioBuffers(readerIndex, len), handler.singleBuffer);
202                     } finally {
203                         handler.singleBuffer[0] = null;
204                     }
205                 } else {
206                     result = handler.engine.unwrap(toByteBuffer(in, readerIndex, len),
207                         toByteBuffer(out, writerIndex, out.writableBytes()));
208                 }
209                 out.writerIndex(writerIndex + result.bytesProduced());
210                 return result;
211             }
212 
213             @Override
214             ByteBuf allocateWrapBuffer(SslHandler handler, ByteBufAllocator allocator,
215                                        int pendingBytes, int numComponents) {
216                 return allocator.directBuffer(((ReferenceCountedOpenSslEngine) handler.engine)
217                         .calculateMaxLengthForWrap(pendingBytes, numComponents));
218             }
219 
220             @Override
221             int calculatePendingData(SslHandler handler, int guess) {
222                 int sslPending = ((ReferenceCountedOpenSslEngine) handler.engine).sslPending();
223                 return sslPending > 0 ? sslPending : guess;
224             }
225 
226             @Override
227             boolean jdkCompatibilityMode(SSLEngine engine) {
228                 return ((ReferenceCountedOpenSslEngine) engine).jdkCompatibilityMode;
229             }
230         },
231         CONSCRYPT(true, COMPOSITE_CUMULATOR) {
232             @Override
233             SSLEngineResult unwrap(SslHandler handler, ByteBuf in, int readerIndex, int len, ByteBuf out)
234                     throws SSLException {
235                 int nioBufferCount = in.nioBufferCount();
236                 int writerIndex = out.writerIndex();
237                 final SSLEngineResult result;
238                 if (nioBufferCount > 1) {
239                     /*
240                      * Use a special unwrap method without additional memory copies.
241                      */
242                     try {
243                         handler.singleBuffer[0] = toByteBuffer(out, writerIndex, out.writableBytes());
244                         result = ((ConscryptAlpnSslEngine) handler.engine).unwrap(
245                                 in.nioBuffers(readerIndex, len),
246                                 handler.singleBuffer);
247                     } finally {
248                         handler.singleBuffer[0] = null;
249                     }
250                 } else {
251                     result = handler.engine.unwrap(toByteBuffer(in, readerIndex, len),
252                             toByteBuffer(out, writerIndex, out.writableBytes()));
253                 }
254                 out.writerIndex(writerIndex + result.bytesProduced());
255                 return result;
256             }
257 
258             @Override
259             ByteBuf allocateWrapBuffer(SslHandler handler, ByteBufAllocator allocator,
260                                        int pendingBytes, int numComponents) {
261                 return allocator.directBuffer(
262                         ((ConscryptAlpnSslEngine) handler.engine).calculateOutNetBufSize(pendingBytes, numComponents));
263             }
264 
265             @Override
266             int calculatePendingData(SslHandler handler, int guess) {
267                 return guess;
268             }
269 
270             @Override
271             boolean jdkCompatibilityMode(SSLEngine engine) {
272                 return true;
273             }
274         },
275         JDK(false, MERGE_CUMULATOR) {
276             @Override
277             SSLEngineResult unwrap(SslHandler handler, ByteBuf in, int readerIndex, int len, ByteBuf out)
278                     throws SSLException {
279                 int writerIndex = out.writerIndex();
280                 ByteBuffer inNioBuffer = toByteBuffer(in, readerIndex, len);
281                 int position = inNioBuffer.position();
282                 final SSLEngineResult result = handler.engine.unwrap(inNioBuffer,
283                     toByteBuffer(out, writerIndex, out.writableBytes()));
284                 out.writerIndex(writerIndex + result.bytesProduced());
285 
286                 // This is a workaround for a bug in Android 5.0. Android 5.0 does not correctly update the
287                 // SSLEngineResult.bytesConsumed() in some cases and just return 0.
288                 //
289                 // See:
290                 //     - https://android-review.googlesource.com/c/platform/external/conscrypt/+/122080
291                 //     - https://github.com/netty/netty/issues/7758
292                 if (result.bytesConsumed() == 0) {
293                     int consumed = inNioBuffer.position() - position;
294                     if (consumed != result.bytesConsumed()) {
295                         // Create a new SSLEngineResult with the correct bytesConsumed().
296                         return new SSLEngineResult(
297                                 result.getStatus(), result.getHandshakeStatus(), consumed, result.bytesProduced());
298                     }
299                 }
300                 return result;
301             }
302 
303             @Override
304             ByteBuf allocateWrapBuffer(SslHandler handler, ByteBufAllocator allocator,
305                                        int pendingBytes, int numComponents) {
306                 // As for the JDK SSLEngine we always need to allocate buffers of the size required by the SSLEngine
307                 // (normally ~16KB). This is required even if the amount of data to encrypt is very small. Use heap
308                 // buffers to reduce the native memory usage.
309                 //
310                 // Beside this the JDK SSLEngine also (as of today) will do an extra heap to direct buffer copy
311                 // if a direct buffer is used as its internals operate on byte[].
312                 return allocator.heapBuffer(handler.engine.getSession().getPacketBufferSize());
313             }
314 
315             @Override
316             int calculatePendingData(SslHandler handler, int guess) {
317                 return guess;
318             }
319 
320             @Override
321             boolean jdkCompatibilityMode(SSLEngine engine) {
322                 return true;
323             }
324         };
325 
326         static SslEngineType forEngine(SSLEngine engine) {
327             return engine instanceof ReferenceCountedOpenSslEngine ? TCNATIVE :
328                    engine instanceof ConscryptAlpnSslEngine ? CONSCRYPT : JDK;
329         }
330 
331         SslEngineType(boolean wantsDirectBuffer, Cumulator cumulator) {
332             this.wantsDirectBuffer = wantsDirectBuffer;
333             this.cumulator = cumulator;
334         }
335 
336         abstract SSLEngineResult unwrap(SslHandler handler, ByteBuf in, int readerIndex, int len, ByteBuf out)
337                 throws SSLException;
338 
339         abstract int calculatePendingData(SslHandler handler, int guess);
340 
341         abstract boolean jdkCompatibilityMode(SSLEngine engine);
342 
343         abstract ByteBuf allocateWrapBuffer(SslHandler handler, ByteBufAllocator allocator,
344                                             int pendingBytes, int numComponents);
345 
346         // BEGIN Platform-dependent flags
347 
348         /**
349          * {@code true} if and only if {@link SSLEngine} expects a direct buffer and so if a heap buffer
350          * is given will make an extra memory copy.
351          */
352         final boolean wantsDirectBuffer;
353 
354         // END Platform-dependent flags
355 
356         /**
357          * When using JDK {@link SSLEngine}, we use {@link #MERGE_CUMULATOR} because it works only with
358          * one {@link ByteBuffer}.
359          *
360          * When using {@link OpenSslEngine}, we can use {@link #COMPOSITE_CUMULATOR} because it has
361          * {@link OpenSslEngine#unwrap(ByteBuffer[], ByteBuffer[])} which works with multiple {@link ByteBuffer}s
362          * and which does not need to do extra memory copies.
363          */
364         final Cumulator cumulator;
365     }
366 
367     private volatile ChannelHandlerContext ctx;
368     private final SSLEngine engine;
369     private final SslEngineType engineType;
370     private final Executor delegatedTaskExecutor;
371     private final boolean jdkCompatibilityMode;
372 
373     /**
374      * Used if {@link SSLEngine#wrap(ByteBuffer[], ByteBuffer)} and {@link SSLEngine#unwrap(ByteBuffer, ByteBuffer[])}
375      * should be called with a {@link ByteBuf} that is only backed by one {@link ByteBuffer} to reduce the object
376      * creation.
377      */
378     private final ByteBuffer[] singleBuffer = new ByteBuffer[1];
379 
380     private final boolean startTls;
381     private boolean sentFirstMessage;
382     private boolean flushedBeforeHandshake;
383     private boolean readDuringHandshake;
384     private boolean handshakeStarted;
385 
386     private SslHandlerCoalescingBufferQueue pendingUnencryptedWrites;
387     private Promise<Channel> handshakePromise = new LazyChannelPromise();
388     private final LazyChannelPromise sslClosePromise = new LazyChannelPromise();
389 
390     /**
391      * Set by wrap*() methods when something is produced.
392      * {@link #channelReadComplete(ChannelHandlerContext)} will check this flag, clear it, and call ctx.flush().
393      */
394     private boolean needsFlush;
395 
396     private boolean outboundClosed;
397     private boolean closeNotify;
398     private boolean processTask;
399 
400     private int packetLength;
401 
402     /**
403      * This flag is used to determine if we need to call {@link ChannelHandlerContext#read()} to consume more data
404      * when {@link ChannelConfig#isAutoRead()} is {@code false}.
405      */
406     private boolean firedChannelRead;
407 
408     private volatile long handshakeTimeoutMillis = 10000;
409     private volatile long closeNotifyFlushTimeoutMillis = 3000;
410     private volatile long closeNotifyReadTimeoutMillis;
411     volatile int wrapDataSize = MAX_PLAINTEXT_LENGTH;
412 
413     /**
414      * Creates a new instance which runs all delegated tasks directly on the {@link EventExecutor}.
415      *
416      * @param engine  the {@link SSLEngine} this handler will use
417      */
418     public SslHandler(SSLEngine engine) {
419         this(engine, false);
420     }
421 
422     /**
423      * Creates a new instance which runs all delegated tasks directly on the {@link EventExecutor}.
424      *
425      * @param engine    the {@link SSLEngine} this handler will use
426      * @param startTls  {@code true} if the first write request shouldn't be
427      *                  encrypted by the {@link SSLEngine}
428      */
429     public SslHandler(SSLEngine engine, boolean startTls) {
430         this(engine, startTls, ImmediateExecutor.INSTANCE);
431     }
432 
433     /**
434      * Creates a new instance.
435      *
436      * @param engine  the {@link SSLEngine} this handler will use
437      * @param delegatedTaskExecutor the {@link Executor} that will be used to execute tasks that are returned by
438      *                              {@link SSLEngine#getDelegatedTask()}.
439      */
440     public SslHandler(SSLEngine engine, Executor delegatedTaskExecutor) {
441         this(engine, false, delegatedTaskExecutor);
442     }
443 
444     /**
445      * Creates a new instance.
446      *
447      * @param engine  the {@link SSLEngine} this handler will use
448      * @param startTls  {@code true} if the first write request shouldn't be
449      *                  encrypted by the {@link SSLEngine}
450      * @param delegatedTaskExecutor the {@link Executor} that will be used to execute tasks that are returned by
451      *                              {@link SSLEngine#getDelegatedTask()}.
452      */
453     public SslHandler(SSLEngine engine, boolean startTls, Executor delegatedTaskExecutor) {
454         this.engine = ObjectUtil.checkNotNull(engine, "engine");
455         this.delegatedTaskExecutor = ObjectUtil.checkNotNull(delegatedTaskExecutor, "delegatedTaskExecutor");
456         engineType = SslEngineType.forEngine(engine);
457         this.startTls = startTls;
458         this.jdkCompatibilityMode = engineType.jdkCompatibilityMode(engine);
459         setCumulator(engineType.cumulator);
460     }
461 
462     public long getHandshakeTimeoutMillis() {
463         return handshakeTimeoutMillis;
464     }
465 
466     public void setHandshakeTimeout(long handshakeTimeout, TimeUnit unit) {
467         ObjectUtil.checkNotNull(unit, "unit");
468         setHandshakeTimeoutMillis(unit.toMillis(handshakeTimeout));
469     }
470 
471     public void setHandshakeTimeoutMillis(long handshakeTimeoutMillis) {
472         if (handshakeTimeoutMillis < 0) {
473             throw new IllegalArgumentException(
474                     "handshakeTimeoutMillis: " + handshakeTimeoutMillis + " (expected: >= 0)");
475         }
476         this.handshakeTimeoutMillis = handshakeTimeoutMillis;
477     }
478 
479     /**
480      * Sets the number of bytes to pass to each {@link SSLEngine#wrap(ByteBuffer[], int, int, ByteBuffer)} call.
481      * <p>
482      * This value will partition data which is passed to write
483      * {@link #write(ChannelHandlerContext, Object, ChannelPromise)}. The partitioning will work as follows:
484      * <ul>
485      * <li>If {@code wrapDataSize <= 0} then we will write each data chunk as is.</li>
486      * <li>If {@code wrapDataSize > data size} then we will attempt to aggregate multiple data chunks together.</li>
487      * <li>If {@code wrapDataSize > data size}  Else if {@code wrapDataSize <= data size} then we will divide the data
488      * into chunks of {@code wrapDataSize} when writing.</li>
489      * </ul>
490      * <p>
491      * If the {@link SSLEngine} doesn't support a gather wrap operation (e.g. {@link SslProvider#OPENSSL}) then
492      * aggregating data before wrapping can help reduce the ratio between TLS overhead vs data payload which will lead
493      * to better goodput. Writing fixed chunks of data can also help target the underlying transport's (e.g. TCP)
494      * frame size. Under lossy/congested network conditions this may help the peer get full TLS packets earlier and
495      * be able to do work sooner, as opposed to waiting for the all the pieces of the TLS packet to arrive.
496      * @param wrapDataSize the number of bytes which will be passed to each
497      *      {@link SSLEngine#wrap(ByteBuffer[], int, int, ByteBuffer)} call.
498      */
499     @UnstableApi
500     public final void setWrapDataSize(int wrapDataSize) {
501         this.wrapDataSize = wrapDataSize;
502     }
503 
504     /**
505      * @deprecated use {@link #getCloseNotifyFlushTimeoutMillis()}
506      */
507     @Deprecated
508     public long getCloseNotifyTimeoutMillis() {
509         return getCloseNotifyFlushTimeoutMillis();
510     }
511 
512     /**
513      * @deprecated use {@link #setCloseNotifyFlushTimeout(long, TimeUnit)}
514      */
515     @Deprecated
516     public void setCloseNotifyTimeout(long closeNotifyTimeout, TimeUnit unit) {
517         setCloseNotifyFlushTimeout(closeNotifyTimeout, unit);
518     }
519 
520     /**
521      * @deprecated use {@link #setCloseNotifyFlushTimeoutMillis(long)}
522      */
523     @Deprecated
524     public void setCloseNotifyTimeoutMillis(long closeNotifyFlushTimeoutMillis) {
525         setCloseNotifyFlushTimeoutMillis(closeNotifyFlushTimeoutMillis);
526     }
527 
528     /**
529      * Gets the timeout for flushing the close_notify that was triggered by closing the
530      * {@link Channel}. If the close_notify was not flushed in the given timeout the {@link Channel} will be closed
531      * forcibly.
532      */
533     public final long getCloseNotifyFlushTimeoutMillis() {
534         return closeNotifyFlushTimeoutMillis;
535     }
536 
537     /**
538      * Sets the timeout for flushing the close_notify that was triggered by closing the
539      * {@link Channel}. If the close_notify was not flushed in the given timeout the {@link Channel} will be closed
540      * forcibly.
541      */
542     public final void setCloseNotifyFlushTimeout(long closeNotifyFlushTimeout, TimeUnit unit) {
543         setCloseNotifyFlushTimeoutMillis(unit.toMillis(closeNotifyFlushTimeout));
544     }
545 
546     /**
547      * See {@link #setCloseNotifyFlushTimeout(long, TimeUnit)}.
548      */
549     public final void setCloseNotifyFlushTimeoutMillis(long closeNotifyFlushTimeoutMillis) {
550         if (closeNotifyFlushTimeoutMillis < 0) {
551             throw new IllegalArgumentException(
552                     "closeNotifyFlushTimeoutMillis: " + closeNotifyFlushTimeoutMillis + " (expected: >= 0)");
553         }
554         this.closeNotifyFlushTimeoutMillis = closeNotifyFlushTimeoutMillis;
555     }
556 
557     /**
558      * Gets the timeout (in ms) for receiving the response for the close_notify that was triggered by closing the
559      * {@link Channel}. This timeout starts after the close_notify message was successfully written to the
560      * remote peer. Use {@code 0} to directly close the {@link Channel} and not wait for the response.
561      */
562     public final long getCloseNotifyReadTimeoutMillis() {
563         return closeNotifyReadTimeoutMillis;
564     }
565 
566     /**
567      * Sets the timeout  for receiving the response for the close_notify that was triggered by closing the
568      * {@link Channel}. This timeout starts after the close_notify message was successfully written to the
569      * remote peer. Use {@code 0} to directly close the {@link Channel} and not wait for the response.
570      */
571     public final void setCloseNotifyReadTimeout(long closeNotifyReadTimeout, TimeUnit unit) {
572         setCloseNotifyReadTimeoutMillis(unit.toMillis(closeNotifyReadTimeout));
573     }
574 
575     /**
576      * See {@link #setCloseNotifyReadTimeout(long, TimeUnit)}.
577      */
578     public final void setCloseNotifyReadTimeoutMillis(long closeNotifyReadTimeoutMillis) {
579         if (closeNotifyReadTimeoutMillis < 0) {
580             throw new IllegalArgumentException(
581                     "closeNotifyReadTimeoutMillis: " + closeNotifyReadTimeoutMillis + " (expected: >= 0)");
582         }
583         this.closeNotifyReadTimeoutMillis = closeNotifyReadTimeoutMillis;
584     }
585 
586     /**
587      * Returns the {@link SSLEngine} which is used by this handler.
588      */
589     public SSLEngine engine() {
590         return engine;
591     }
592 
593     /**
594      * Returns the name of the current application-level protocol.
595      *
596      * @return the protocol name or {@code null} if application-level protocol has not been negotiated
597      */
598     public String applicationProtocol() {
599         SSLEngine engine = engine();
600         if (!(engine instanceof ApplicationProtocolAccessor)) {
601             return null;
602         }
603 
604         return ((ApplicationProtocolAccessor) engine).getNegotiatedApplicationProtocol();
605     }
606 
607     /**
608      * Returns a {@link Future} that will get notified once the current TLS handshake completes.
609      *
610      * @return the {@link Future} for the initial TLS handshake if {@link #renegotiate()} was not invoked.
611      *         The {@link Future} for the most recent {@linkplain #renegotiate() TLS renegotiation} otherwise.
612      */
613     public Future<Channel> handshakeFuture() {
614         return handshakePromise;
615     }
616 
617     /**
618      * Use {@link #closeOutbound()}
619      */
620     @Deprecated
621     public ChannelFuture close() {
622         return closeOutbound();
623     }
624 
625     /**
626      * Use {@link #closeOutbound(ChannelPromise)}
627      */
628     @Deprecated
629     public ChannelFuture close(ChannelPromise promise) {
630         return closeOutbound(promise);
631     }
632 
633     /**
634      * Sends an SSL {@code close_notify} message to the specified channel and
635      * destroys the underlying {@link SSLEngine}. This will <strong>not</strong> close the underlying
636      * {@link Channel}. If you want to also close the {@link Channel} use {@link Channel#close()} or
637      * {@link ChannelHandlerContext#close()}
638      */
639     public ChannelFuture closeOutbound() {
640         return closeOutbound(ctx.newPromise());
641     }
642 
643     /**
644      * Sends an SSL {@code close_notify} message to the specified channel and
645      * destroys the underlying {@link SSLEngine}. This will <strong>not</strong> close the underlying
646      * {@link Channel}. If you want to also close the {@link Channel} use {@link Channel#close()} or
647      * {@link ChannelHandlerContext#close()}
648      */
649     public ChannelFuture closeOutbound(final ChannelPromise promise) {
650         final ChannelHandlerContext ctx = this.ctx;
651         if (ctx.executor().inEventLoop()) {
652             closeOutbound0(promise);
653         } else {
654             ctx.executor().execute(new Runnable() {
655                 @Override
656                 public void run() {
657                     closeOutbound0(promise);
658                 }
659             });
660         }
661         return promise;
662     }
663 
664     private void closeOutbound0(ChannelPromise promise) {
665         outboundClosed = true;
666         engine.closeOutbound();
667         try {
668             flush(ctx, promise);
669         } catch (Exception e) {
670             if (!promise.tryFailure(e)) {
671                 logger.warn("{} flush() raised a masked exception.", ctx.channel(), e);
672             }
673         }
674     }
675 
676     /**
677      * Return the {@link Future} that will get notified if the inbound of the {@link SSLEngine} is closed.
678      *
679      * This method will return the same {@link Future} all the time.
680      *
681      * @see SSLEngine
682      */
683     public Future<Channel> sslCloseFuture() {
684         return sslClosePromise;
685     }
686 
687     @Override
688     public void handlerRemoved0(ChannelHandlerContext ctx) throws Exception {
689         if (!pendingUnencryptedWrites.isEmpty()) {
690             // Check if queue is not empty first because create a new ChannelException is expensive
691             pendingUnencryptedWrites.releaseAndFailAll(ctx,
692                     new ChannelException("Pending write on removal of SslHandler"));
693         }
694         pendingUnencryptedWrites = null;
695 
696         SSLHandshakeException cause = null;
697 
698         // If the handshake is not done yet we should fail the handshake promise and notify the rest of the
699         // pipeline.
700         if (!handshakePromise.isDone()) {
701             cause = new SSLHandshakeException("SslHandler removed before handshake completed");
702             if (handshakePromise.tryFailure(cause)) {
703                 ctx.fireUserEventTriggered(new SslHandshakeCompletionEvent(cause));
704             }
705         }
706         if (!sslClosePromise.isDone()) {
707             if (cause == null) {
708                 cause = new SSLHandshakeException("SslHandler removed before handshake completed");
709             }
710             notifyClosePromise(cause);
711         }
712 
713         if (engine instanceof ReferenceCounted) {
714             ((ReferenceCounted) engine).release();
715         }
716     }
717 
718     @Override
719     public void bind(ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise) throws Exception {
720         ctx.bind(localAddress, promise);
721     }
722 
723     @Override
724     public void connect(ChannelHandlerContext ctx, SocketAddress remoteAddress, SocketAddress localAddress,
725                         ChannelPromise promise) throws Exception {
726         ctx.connect(remoteAddress, localAddress, promise);
727     }
728 
729     @Override
730     public void deregister(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {
731         ctx.deregister(promise);
732     }
733 
734     @Override
735     public void disconnect(final ChannelHandlerContext ctx,
736                            final ChannelPromise promise) throws Exception {
737         closeOutboundAndChannel(ctx, promise, true);
738     }
739 
740     @Override
741     public void close(final ChannelHandlerContext ctx,
742                       final ChannelPromise promise) throws Exception {
743         closeOutboundAndChannel(ctx, promise, false);
744     }
745 
746     @Override
747     public void read(ChannelHandlerContext ctx) throws Exception {
748         if (!handshakePromise.isDone()) {
749             readDuringHandshake = true;
750         }
751 
752         ctx.read();
753     }
754 
755     private static IllegalStateException newPendingWritesNullException() {
756         return new IllegalStateException("pendingUnencryptedWrites is null, handlerRemoved0 called?");
757     }
758 
759     @Override
760     public void write(final ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
761         if (!(msg instanceof ByteBuf)) {
762             UnsupportedMessageTypeException exception = new UnsupportedMessageTypeException(msg, ByteBuf.class);
763             ReferenceCountUtil.safeRelease(msg);
764             promise.setFailure(exception);
765         } else if (pendingUnencryptedWrites == null) {
766             ReferenceCountUtil.safeRelease(msg);
767             promise.setFailure(newPendingWritesNullException());
768         } else {
769             pendingUnencryptedWrites.add((ByteBuf) msg, promise);
770         }
771     }
772 
773     @Override
774     public void flush(ChannelHandlerContext ctx) throws Exception {
775         // Do not encrypt the first write request if this handler is
776         // created with startTLS flag turned on.
777         if (startTls && !sentFirstMessage) {
778             sentFirstMessage = true;
779             pendingUnencryptedWrites.writeAndRemoveAll(ctx);
780             forceFlush(ctx);
781             // Explicit start handshake processing once we send the first message. This will also ensure
782             // we will schedule the timeout if needed.
783             startHandshakeProcessing();
784             return;
785         }
786 
787         if (processTask) {
788             return;
789         }
790 
791         try {
792             wrapAndFlush(ctx);
793         } catch (Throwable cause) {
794             setHandshakeFailure(ctx, cause);
795             PlatformDependent.throwException(cause);
796         }
797     }
798 
799     private void wrapAndFlush(ChannelHandlerContext ctx) throws SSLException {
800         if (pendingUnencryptedWrites.isEmpty()) {
801             // It's important to NOT use a voidPromise here as the user
802             // may want to add a ChannelFutureListener to the ChannelPromise later.
803             //
804             // See https://github.com/netty/netty/issues/3364
805             pendingUnencryptedWrites.add(Unpooled.EMPTY_BUFFER, ctx.newPromise());
806         }
807         if (!handshakePromise.isDone()) {
808             flushedBeforeHandshake = true;
809         }
810         try {
811             wrap(ctx, false);
812         } finally {
813             // We may have written some parts of data before an exception was thrown so ensure we always flush.
814             // See https://github.com/netty/netty/issues/3900#issuecomment-172481830
815             forceFlush(ctx);
816         }
817     }
818 
819     // This method will not call setHandshakeFailure(...) !
820     private void wrap(ChannelHandlerContext ctx, boolean inUnwrap) throws SSLException {
821         ByteBuf out = null;
822         ChannelPromise promise = null;
823         ByteBufAllocator alloc = ctx.alloc();
824         boolean needUnwrap = false;
825         ByteBuf buf = null;
826         try {
827             final int wrapDataSize = this.wrapDataSize;
828             // Only continue to loop if the handler was not removed in the meantime.
829             // See https://github.com/netty/netty/issues/5860
830             outer: while (!ctx.isRemoved()) {
831                 promise = ctx.newPromise();
832                 buf = wrapDataSize > 0 ?
833                         pendingUnencryptedWrites.remove(alloc, wrapDataSize, promise) :
834                         pendingUnencryptedWrites.removeFirst(promise);
835                 if (buf == null) {
836                     break;
837                 }
838 
839                 if (out == null) {
840                     out = allocateOutNetBuf(ctx, buf.readableBytes(), buf.nioBufferCount());
841                 }
842 
843                 SSLEngineResult result = wrap(alloc, engine, buf, out);
844 
845                 if (result.getStatus() == Status.CLOSED) {
846                     buf.release();
847                     buf = null;
848                     // Make a best effort to preserve any exception that way previously encountered from the handshake
849                     // or the transport, else fallback to a general error.
850                     Throwable exception = handshakePromise.cause();
851                     if (exception == null) {
852                         exception = sslClosePromise.cause();
853                         if (exception == null) {
854                             exception = new SSLException("SSLEngine closed already");
855                         }
856                     }
857                     promise.tryFailure(exception);
858                     promise = null;
859                     // SSLEngine has been closed already.
860                     // Any further write attempts should be denied.
861                     pendingUnencryptedWrites.releaseAndFailAll(ctx, exception);
862                     return;
863                 } else {
864                     if (buf.isReadable()) {
865                         pendingUnencryptedWrites.addFirst(buf, promise);
866                         // When we add the buffer/promise pair back we need to be sure we don't complete the promise
867                         // later in finishWrap. We only complete the promise if the buffer is completely consumed.
868                         promise = null;
869                     } else {
870                         buf.release();
871                     }
872                     buf = null;
873 
874                     switch (result.getHandshakeStatus()) {
875                         case NEED_TASK:
876                             if (!runDelegatedTasks(inUnwrap)) {
877                                 // We scheduled a task on the delegatingTaskExecutor, so stop processing as we will
878                                 // resume once the task completes.
879                                 break outer;
880                             }
881                             break;
882                         case FINISHED:
883                             setHandshakeSuccess();
884                             // deliberate fall-through
885                         case NOT_HANDSHAKING:
886                             setHandshakeSuccessIfStillHandshaking();
887                             // deliberate fall-through
888                         case NEED_WRAP: {
889                             ChannelPromise p = promise;
890 
891                             // Null out the promise so it is not reused in the finally block in the cause of
892                             // finishWrap(...) throwing.
893                             promise = null;
894                             final ByteBuf b;
895 
896                             if (out.isReadable()) {
897                                 // There is something in the out buffer. Ensure we null it out so it is not re-used.
898                                 b = out;
899                                 out = null;
900                             } else {
901                                 // If out is not readable we can re-use it and so save an extra allocation
902                                 b = null;
903                             }
904                             finishWrap(ctx, b, p, inUnwrap, false);
905                             break;
906                         }
907                         case NEED_UNWRAP:
908                             needUnwrap = true;
909                             return;
910                         default:
911                             throw new IllegalStateException(
912                                     "Unknown handshake status: " + result.getHandshakeStatus());
913                     }
914                 }
915             }
916         } finally {
917             // Ownership of buffer was not transferred, release it.
918             if (buf != null) {
919                 buf.release();
920             }
921             finishWrap(ctx, out, promise, inUnwrap, needUnwrap);
922         }
923     }
924 
925     private void finishWrap(ChannelHandlerContext ctx, ByteBuf out, ChannelPromise promise, boolean inUnwrap,
926             boolean needUnwrap) {
927         if (out == null) {
928             out = Unpooled.EMPTY_BUFFER;
929         } else if (!out.isReadable()) {
930             out.release();
931             out = Unpooled.EMPTY_BUFFER;
932         }
933 
934         if (promise != null) {
935             ctx.write(out, promise);
936         } else {
937             ctx.write(out);
938         }
939 
940         if (inUnwrap) {
941             needsFlush = true;
942         }
943 
944         if (needUnwrap) {
945             // The underlying engine is starving so we need to feed it with more data.
946             // See https://github.com/netty/netty/pull/5039
947             readIfNeeded(ctx);
948         }
949     }
950 
951     /**
952      * This method will not call
953      * {@link #setHandshakeFailure(ChannelHandlerContext, Throwable, boolean, boolean, boolean)} or
954      * {@link #setHandshakeFailure(ChannelHandlerContext, Throwable)}.
955      * @return {@code true} if this method ends on {@link SSLEngineResult.HandshakeStatus#NOT_HANDSHAKING}.
956      */
957     private boolean wrapNonAppData(final ChannelHandlerContext ctx, boolean inUnwrap) throws SSLException {
958         ByteBuf out = null;
959         ByteBufAllocator alloc = ctx.alloc();
960         try {
961             // Only continue to loop if the handler was not removed in the meantime.
962             // See https://github.com/netty/netty/issues/5860
963             outer: while (!ctx.isRemoved()) {
964                 if (out == null) {
965                     // As this is called for the handshake we have no real idea how big the buffer needs to be.
966                     // That said 2048 should give us enough room to include everything like ALPN / NPN data.
967                     // If this is not enough we will increase the buffer in wrap(...).
968                     out = allocateOutNetBuf(ctx, 2048, 1);
969                 }
970                 SSLEngineResult result = wrap(alloc, engine, Unpooled.EMPTY_BUFFER, out);
971 
972                 if (result.bytesProduced() > 0) {
973                     ctx.write(out).addListener(new ChannelFutureListener() {
974                         @Override
975                         public void operationComplete(ChannelFuture future) {
976                             Throwable cause = future.cause();
977                             if (cause != null) {
978                                 setHandshakeFailureTransportFailure(ctx, cause);
979                             }
980                         }
981                     });
982                     if (inUnwrap) {
983                         needsFlush = true;
984                     }
985                     out = null;
986                 }
987 
988                 HandshakeStatus status = result.getHandshakeStatus();
989                 switch (status) {
990                     case FINISHED:
991                         setHandshakeSuccess();
992                         return false;
993                     case NEED_TASK:
994                         if (!runDelegatedTasks(inUnwrap)) {
995                             // We scheduled a task on the delegatingTaskExecutor, so stop processing as we will
996                             // resume once the task completes.
997                             break outer;
998                         }
999                         break;
1000                     case NEED_UNWRAP:
1001                         if (inUnwrap) {
1002                             // If we asked for a wrap, the engine requested an unwrap, and we are in unwrap there is
1003                             // no use in trying to call wrap again because we have already attempted (or will after we
1004                             // return) to feed more data to the engine.
1005                             return false;
1006                         }
1007 
1008                         unwrapNonAppData(ctx);
1009                         break;
1010                     case NEED_WRAP:
1011                         break;
1012                     case NOT_HANDSHAKING:
1013                         setHandshakeSuccessIfStillHandshaking();
1014                         // Workaround for TLS False Start problem reported at:
1015                         // https://github.com/netty/netty/issues/1108#issuecomment-14266970
1016                         if (!inUnwrap) {
1017                             unwrapNonAppData(ctx);
1018                         }
1019                         return true;
1020                     default:
1021                         throw new IllegalStateException("Unknown handshake status: " + result.getHandshakeStatus());
1022                 }
1023 
1024                 // Check if did not produce any bytes and if so break out of the loop, but only if we did not process
1025                 // a task as last action. It's fine to not produce any data as part of executing a task.
1026                 if (result.bytesProduced() == 0 && status != HandshakeStatus.NEED_TASK) {
1027                     break;
1028                 }
1029 
1030                 // It should not consume empty buffers when it is not handshaking
1031                 // Fix for Android, where it was encrypting empty buffers even when not handshaking
1032                 if (result.bytesConsumed() == 0 && result.getHandshakeStatus() == HandshakeStatus.NOT_HANDSHAKING) {
1033                     break;
1034                 }
1035             }
1036         }  finally {
1037             if (out != null) {
1038                 out.release();
1039             }
1040         }
1041         return false;
1042     }
1043 
1044     private SSLEngineResult wrap(ByteBufAllocator alloc, SSLEngine engine, ByteBuf in, ByteBuf out)
1045             throws SSLException {
1046         ByteBuf newDirectIn = null;
1047         try {
1048             int readerIndex = in.readerIndex();
1049             int readableBytes = in.readableBytes();
1050 
1051             // We will call SslEngine.wrap(ByteBuffer[], ByteBuffer) to allow efficient handling of
1052             // CompositeByteBuf without force an extra memory copy when CompositeByteBuffer.nioBuffer() is called.
1053             final ByteBuffer[] in0;
1054             if (in.isDirect() || !engineType.wantsDirectBuffer) {
1055                 // As CompositeByteBuf.nioBufferCount() can be expensive (as it needs to check all composed ByteBuf
1056                 // to calculate the count) we will just assume a CompositeByteBuf contains more then 1 ByteBuf.
1057                 // The worst that can happen is that we allocate an extra ByteBuffer[] in CompositeByteBuf.nioBuffers()
1058                 // which is better then walking the composed ByteBuf in most cases.
1059                 if (!(in instanceof CompositeByteBuf) && in.nioBufferCount() == 1) {
1060                     in0 = singleBuffer;
1061                     // We know its only backed by 1 ByteBuffer so use internalNioBuffer to keep object allocation
1062                     // to a minimum.
1063                     in0[0] = in.internalNioBuffer(readerIndex, readableBytes);
1064                 } else {
1065                     in0 = in.nioBuffers();
1066                 }
1067             } else {
1068                 // We could even go further here and check if its a CompositeByteBuf and if so try to decompose it and
1069                 // only replace the ByteBuffer that are not direct. At the moment we just will replace the whole
1070                 // CompositeByteBuf to keep the complexity to a minimum
1071                 newDirectIn = alloc.directBuffer(readableBytes);
1072                 newDirectIn.writeBytes(in, readerIndex, readableBytes);
1073                 in0 = singleBuffer;
1074                 in0[0] = newDirectIn.internalNioBuffer(newDirectIn.readerIndex(), readableBytes);
1075             }
1076 
1077             for (;;) {
1078                 ByteBuffer out0 = out.nioBuffer(out.writerIndex(), out.writableBytes());
1079                 SSLEngineResult result = engine.wrap(in0, out0);
1080                 in.skipBytes(result.bytesConsumed());
1081                 out.writerIndex(out.writerIndex() + result.bytesProduced());
1082 
1083                 switch (result.getStatus()) {
1084                 case BUFFER_OVERFLOW:
1085                     out.ensureWritable(engine.getSession().getPacketBufferSize());
1086                     break;
1087                 default:
1088                     return result;
1089                 }
1090             }
1091         } finally {
1092             // Null out to allow GC of ByteBuffer
1093             singleBuffer[0] = null;
1094 
1095             if (newDirectIn != null) {
1096                 newDirectIn.release();
1097             }
1098         }
1099     }
1100 
1101     @Override
1102     public void channelInactive(ChannelHandlerContext ctx) throws Exception {
1103         boolean handshakeFailed = handshakePromise.cause() != null;
1104 
1105         ClosedChannelException exception = new ClosedChannelException();
1106         // Make sure to release SSLEngine,
1107         // and notify the handshake future if the connection has been closed during handshake.
1108         setHandshakeFailure(ctx, exception, !outboundClosed, handshakeStarted, false);
1109 
1110         // Ensure we always notify the sslClosePromise as well
1111         notifyClosePromise(exception);
1112 
1113         try {
1114             super.channelInactive(ctx);
1115         } catch (DecoderException e) {
1116             if (!handshakeFailed || !(e.getCause() instanceof SSLException)) {
1117                 // We only rethrow the exception if the handshake did not fail before channelInactive(...) was called
1118                 // as otherwise this may produce duplicated failures as super.channelInactive(...) will also call
1119                 // channelRead(...).
1120                 //
1121                 // See https://github.com/netty/netty/issues/10119
1122                 throw e;
1123             }
1124         }
1125     }
1126 
1127     @Override
1128     public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
1129         if (ignoreException(cause)) {
1130             // It is safe to ignore the 'connection reset by peer' or
1131             // 'broken pipe' error after sending close_notify.
1132             if (logger.isDebugEnabled()) {
1133                 logger.debug(
1134                         "{} Swallowing a harmless 'connection reset by peer / broken pipe' error that occurred " +
1135                         "while writing close_notify in response to the peer's close_notify", ctx.channel(), cause);
1136             }
1137 
1138             // Close the connection explicitly just in case the transport
1139             // did not close the connection automatically.
1140             if (ctx.channel().isActive()) {
1141                 ctx.close();
1142             }
1143         } else {
1144             ctx.fireExceptionCaught(cause);
1145         }
1146     }
1147 
1148     /**
1149      * Checks if the given {@link Throwable} can be ignore and just "swallowed"
1150      *
1151      * When an ssl connection is closed a close_notify message is sent.
1152      * After that the peer also sends close_notify however, it's not mandatory to receive
1153      * the close_notify. The party who sent the initial close_notify can close the connection immediately
1154      * then the peer will get connection reset error.
1155      *
1156      */
1157     private boolean ignoreException(Throwable t) {
1158         if (!(t instanceof SSLException) && t instanceof IOException && sslClosePromise.isDone()) {
1159             String message = t.getMessage();
1160 
1161             // first try to match connection reset / broke peer based on the regex. This is the fastest way
1162             // but may fail on different jdk impls or OS's
1163             if (message != null && IGNORABLE_ERROR_MESSAGE.matcher(message).matches()) {
1164                 return true;
1165             }
1166 
1167             // Inspect the StackTraceElements to see if it was a connection reset / broken pipe or not
1168             StackTraceElement[] elements = t.getStackTrace();
1169             for (StackTraceElement element: elements) {
1170                 String classname = element.getClassName();
1171                 String methodname = element.getMethodName();
1172 
1173                 // skip all classes that belong to the io.netty package
1174                 if (classname.startsWith("io.netty.")) {
1175                     continue;
1176                 }
1177 
1178                 // check if the method name is read if not skip it
1179                 if (!"read".equals(methodname)) {
1180                     continue;
1181                 }
1182 
1183                 // This will also match against SocketInputStream which is used by openjdk 7 and maybe
1184                 // also others
1185                 if (IGNORABLE_CLASS_IN_STACK.matcher(classname).matches()) {
1186                     return true;
1187                 }
1188 
1189                 try {
1190                     // No match by now.. Try to load the class via classloader and inspect it.
1191                     // This is mainly done as other JDK implementations may differ in name of
1192                     // the impl.
1193                     Class<?> clazz = PlatformDependent.getClassLoader(getClass()).loadClass(classname);
1194 
1195                     if (SocketChannel.class.isAssignableFrom(clazz)
1196                             || DatagramChannel.class.isAssignableFrom(clazz)) {
1197                         return true;
1198                     }
1199 
1200                     // also match against SctpChannel via String matching as it may not present.
1201                     if (PlatformDependent.javaVersion() >= 7
1202                             && "com.sun.nio.sctp.SctpChannel".equals(clazz.getSuperclass().getName())) {
1203                         return true;
1204                     }
1205                 } catch (Throwable cause) {
1206                     if (logger.isDebugEnabled()) {
1207                         logger.debug("Unexpected exception while loading class {} classname {}",
1208                                 getClass(), classname, cause);
1209                     }
1210                 }
1211             }
1212         }
1213 
1214         return false;
1215     }
1216 
1217     /**
1218      * Returns {@code true} if the given {@link ByteBuf} is encrypted. Be aware that this method
1219      * will not increase the readerIndex of the given {@link ByteBuf}.
1220      *
1221      * @param   buffer
1222      *                  The {@link ByteBuf} to read from. Be aware that it must have at least 5 bytes to read,
1223      *                  otherwise it will throw an {@link IllegalArgumentException}.
1224      * @return encrypted
1225      *                  {@code true} if the {@link ByteBuf} is encrypted, {@code false} otherwise.
1226      * @throws IllegalArgumentException
1227      *                  Is thrown if the given {@link ByteBuf} has not at least 5 bytes to read.
1228      */
1229     public static boolean isEncrypted(ByteBuf buffer) {
1230         if (buffer.readableBytes() < SslUtils.SSL_RECORD_HEADER_LENGTH) {
1231             throw new IllegalArgumentException(
1232                     "buffer must have at least " + SslUtils.SSL_RECORD_HEADER_LENGTH + " readable bytes");
1233         }
1234         return getEncryptedPacketLength(buffer, buffer.readerIndex()) != SslUtils.NOT_ENCRYPTED;
1235     }
1236 
1237     private void decodeJdkCompatible(ChannelHandlerContext ctx, ByteBuf in) throws NotSslRecordException {
1238         int packetLength = this.packetLength;
1239         // If we calculated the length of the current SSL record before, use that information.
1240         if (packetLength > 0) {
1241             if (in.readableBytes() < packetLength) {
1242                 return;
1243             }
1244         } else {
1245             // Get the packet length and wait until we get a packets worth of data to unwrap.
1246             final int readableBytes = in.readableBytes();
1247             if (readableBytes < SslUtils.SSL_RECORD_HEADER_LENGTH) {
1248                 return;
1249             }
1250             packetLength = getEncryptedPacketLength(in, in.readerIndex());
1251             if (packetLength == SslUtils.NOT_ENCRYPTED) {
1252                 // Not an SSL/TLS packet
1253                 NotSslRecordException e = new NotSslRecordException(
1254                         "not an SSL/TLS record: " + ByteBufUtil.hexDump(in));
1255                 in.skipBytes(in.readableBytes());
1256 
1257                 // First fail the handshake promise as we may need to have access to the SSLEngine which may
1258                 // be released because the user will remove the SslHandler in an exceptionCaught(...) implementation.
1259                 setHandshakeFailure(ctx, e);
1260 
1261                 throw e;
1262             }
1263             assert packetLength > 0;
1264             if (packetLength > readableBytes) {
1265                 // wait until the whole packet can be read
1266                 this.packetLength = packetLength;
1267                 return;
1268             }
1269         }
1270 
1271         // Reset the state of this class so we can get the length of the next packet. We assume the entire packet will
1272         // be consumed by the SSLEngine.
1273         this.packetLength = 0;
1274         try {
1275             int bytesConsumed = unwrap(ctx, in, in.readerIndex(), packetLength);
1276             assert bytesConsumed == packetLength || engine.isInboundDone() :
1277                     "we feed the SSLEngine a packets worth of data: " + packetLength + " but it only consumed: " +
1278                             bytesConsumed;
1279             in.skipBytes(bytesConsumed);
1280         } catch (Throwable cause) {
1281             handleUnwrapThrowable(ctx, cause);
1282         }
1283     }
1284 
1285     private void decodeNonJdkCompatible(ChannelHandlerContext ctx, ByteBuf in) {
1286         try {
1287             in.skipBytes(unwrap(ctx, in, in.readerIndex(), in.readableBytes()));
1288         } catch (Throwable cause) {
1289             handleUnwrapThrowable(ctx, cause);
1290         }
1291     }
1292 
1293     private void handleUnwrapThrowable(ChannelHandlerContext ctx, Throwable cause) {
1294         try {
1295             // We should attempt to notify the handshake failure before writing any pending data. If we are in unwrap
1296             // and failed during the handshake process, and we attempt to wrap, then promises will fail, and if
1297             // listeners immediately close the Channel then we may end up firing the handshake event after the Channel
1298             // has been closed.
1299             if (handshakePromise.tryFailure(cause)) {
1300                 ctx.fireUserEventTriggered(new SslHandshakeCompletionEvent(cause));
1301             }
1302 
1303             // We need to flush one time as there may be an alert that we should send to the remote peer because
1304             // of the SSLException reported here.
1305             wrapAndFlush(ctx);
1306         } catch (SSLException ex) {
1307             logger.debug("SSLException during trying to call SSLEngine.wrap(...)" +
1308                     " because of an previous SSLException, ignoring...", ex);
1309         } finally {
1310             // ensure we always flush and close the channel.
1311             setHandshakeFailure(ctx, cause, true, false, true);
1312         }
1313         PlatformDependent.throwException(cause);
1314     }
1315 
1316     @Override
1317     protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws SSLException {
1318         if (processTask) {
1319             return;
1320         }
1321         if (jdkCompatibilityMode) {
1322             decodeJdkCompatible(ctx, in);
1323         } else {
1324             decodeNonJdkCompatible(ctx, in);
1325         }
1326     }
1327 
1328     @Override
1329     public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
1330         channelReadComplete0(ctx);
1331     }
1332 
1333     private void channelReadComplete0(ChannelHandlerContext ctx) {
1334         // Discard bytes of the cumulation buffer if needed.
1335         discardSomeReadBytes();
1336 
1337         flushIfNeeded(ctx);
1338         readIfNeeded(ctx);
1339 
1340         firedChannelRead = false;
1341         ctx.fireChannelReadComplete();
1342     }
1343 
1344     private void readIfNeeded(ChannelHandlerContext ctx) {
1345         // If handshake is not finished yet, we need more data.
1346         if (!ctx.channel().config().isAutoRead() && (!firedChannelRead || !handshakePromise.isDone())) {
1347             // No auto-read used and no message passed through the ChannelPipeline or the handshake was not complete
1348             // yet, which means we need to trigger the read to ensure we not encounter any stalls.
1349             ctx.read();
1350         }
1351     }
1352 
1353     private void flushIfNeeded(ChannelHandlerContext ctx) {
1354         if (needsFlush) {
1355             forceFlush(ctx);
1356         }
1357     }
1358 
1359     /**
1360      * Calls {@link SSLEngine#unwrap(ByteBuffer, ByteBuffer)} with an empty buffer to handle handshakes, etc.
1361      */
1362     private void unwrapNonAppData(ChannelHandlerContext ctx) throws SSLException {
1363         unwrap(ctx, Unpooled.EMPTY_BUFFER, 0, 0);
1364     }
1365 
1366     /**
1367      * Unwraps inbound SSL records.
1368      */
1369     private int unwrap(
1370             ChannelHandlerContext ctx, ByteBuf packet, int offset, int length) throws SSLException {
1371         final int originalLength = length;
1372         boolean wrapLater = false;
1373         boolean notifyClosure = false;
1374         int overflowReadableBytes = -1;
1375         ByteBuf decodeOut = allocate(ctx, length);
1376         try {
1377             // Only continue to loop if the handler was not removed in the meantime.
1378             // See https://github.com/netty/netty/issues/5860
1379             unwrapLoop: while (!ctx.isRemoved()) {
1380                 final SSLEngineResult result = engineType.unwrap(this, packet, offset, length, decodeOut);
1381                 final Status status = result.getStatus();
1382                 final HandshakeStatus handshakeStatus = result.getHandshakeStatus();
1383                 final int produced = result.bytesProduced();
1384                 final int consumed = result.bytesConsumed();
1385 
1386                 // Update indexes for the next iteration
1387                 offset += consumed;
1388                 length -= consumed;
1389 
1390                 switch (status) {
1391                 case BUFFER_OVERFLOW:
1392                     final int readableBytes = decodeOut.readableBytes();
1393                     final int previousOverflowReadableBytes = overflowReadableBytes;
1394                     overflowReadableBytes = readableBytes;
1395                     int bufferSize = engine.getSession().getApplicationBufferSize() - readableBytes;
1396                     if (readableBytes > 0) {
1397                         firedChannelRead = true;
1398                         ctx.fireChannelRead(decodeOut);
1399 
1400                         // This buffer was handled, null it out.
1401                         decodeOut = null;
1402                         if (bufferSize <= 0) {
1403                             // It may happen that readableBytes >= engine.getSession().getApplicationBufferSize()
1404                             // while there is still more to unwrap, in this case we will just allocate a new buffer
1405                             // with the capacity of engine.getSession().getApplicationBufferSize() and call unwrap
1406                             // again.
1407                             bufferSize = engine.getSession().getApplicationBufferSize();
1408                         }
1409                     } else {
1410                         // This buffer was handled, null it out.
1411                         decodeOut.release();
1412                         decodeOut = null;
1413                     }
1414                     if (readableBytes == 0 && previousOverflowReadableBytes == 0) {
1415                         // If there is two consecutive loops where we overflow and are not able to consume any data,
1416                         // assume the amount of data exceeds the maximum amount for the engine and bail
1417                         throw new IllegalStateException("Two consecutive overflows but no content was consumed. " +
1418                                  SSLSession.class.getSimpleName() + " getApplicationBufferSize: " +
1419                                  engine.getSession().getApplicationBufferSize() + " maybe too small.");
1420                     }
1421                     // Allocate a new buffer which can hold all the rest data and loop again.
1422                     // TODO: We may want to reconsider how we calculate the length here as we may
1423                     // have more then one ssl message to decode.
1424                     decodeOut = allocate(ctx, engineType.calculatePendingData(this, bufferSize));
1425                     continue;
1426                 case CLOSED:
1427                     // notify about the CLOSED state of the SSLEngine. See #137
1428                     notifyClosure = true;
1429                     overflowReadableBytes = -1;
1430                     break;
1431                 default:
1432                     overflowReadableBytes = -1;
1433                     break;
1434                 }
1435 
1436                 switch (handshakeStatus) {
1437                     case NEED_UNWRAP:
1438                         break;
1439                     case NEED_WRAP:
1440                         // If the wrap operation transitions the status to NOT_HANDSHAKING and there is no more data to
1441                         // unwrap then the next call to unwrap will not produce any data. We can avoid the potentially
1442                         // costly unwrap operation and break out of the loop.
1443                         if (wrapNonAppData(ctx, true) && length == 0) {
1444                             break unwrapLoop;
1445                         }
1446                         break;
1447                     case NEED_TASK:
1448                         if (!runDelegatedTasks(true)) {
1449                             // We scheduled a task on the delegatingTaskExecutor, so stop processing as we will
1450                             // resume once the task completes.
1451                             //
1452                             // We break out of the loop only and do NOT return here as we still may need to notify
1453                             // about the closure of the SSLEngine.
1454                             //
1455                             wrapLater = false;
1456                             break unwrapLoop;
1457                         }
1458                         break;
1459                     case FINISHED:
1460                         setHandshakeSuccess();
1461                         wrapLater = true;
1462 
1463                         // We 'break' here and NOT 'continue' as android API version 21 has a bug where they consume
1464                         // data from the buffer but NOT correctly set the SSLEngineResult.bytesConsumed().
1465                         // Because of this it will raise an exception on the next iteration of the for loop on android
1466                         // API version 21. Just doing a break will work here as produced and consumed will both be 0
1467                         // and so we break out of the complete for (;;) loop and so call decode(...) again later on.
1468                         // On other platforms this will have no negative effect as we will just continue with the
1469                         // for (;;) loop if something was either consumed or produced.
1470                         //
1471                         // See:
1472                         //  - https://github.com/netty/netty/issues/4116
1473                         //  - https://code.google.com/p/android/issues/detail?id=198639&thanks=198639&ts=1452501203
1474                         break;
1475                     case NOT_HANDSHAKING:
1476                         if (setHandshakeSuccessIfStillHandshaking()) {
1477                             wrapLater = true;
1478                             continue;
1479                         }
1480 
1481                         // If we are not handshaking and there is no more data to unwrap then the next call to unwrap
1482                         // will not produce any data. We can avoid the potentially costly unwrap operation and break
1483                         // out of the loop.
1484                         if (length == 0) {
1485                             break unwrapLoop;
1486                         }
1487                         break;
1488                     default:
1489                         throw new IllegalStateException("unknown handshake status: " + handshakeStatus);
1490                 }
1491 
1492                 if (status == Status.BUFFER_UNDERFLOW ||
1493                         // If we processed NEED_TASK we should try again even we did not consume or produce anything.
1494                         handshakeStatus != HandshakeStatus.NEED_TASK && consumed == 0 && produced == 0) {
1495                     if (handshakeStatus == HandshakeStatus.NEED_UNWRAP) {
1496                         // The underlying engine is starving so we need to feed it with more data.
1497                         // See https://github.com/netty/netty/pull/5039
1498                         readIfNeeded(ctx);
1499                     }
1500 
1501                     break;
1502                 }
1503             }
1504 
1505             if (flushedBeforeHandshake && handshakePromise.isDone()) {
1506                 // We need to call wrap(...) in case there was a flush done before the handshake completed to ensure
1507                 // we do not stale.
1508                 //
1509                 // See https://github.com/netty/netty/pull/2437
1510                 flushedBeforeHandshake = false;
1511                 wrapLater = true;
1512             }
1513 
1514             if (wrapLater) {
1515                 wrap(ctx, true);
1516             }
1517 
1518             if (notifyClosure) {
1519                 notifyClosePromise(null);
1520             }
1521         } finally {
1522             if (decodeOut != null) {
1523                 if (decodeOut.isReadable()) {
1524                     firedChannelRead = true;
1525 
1526                     ctx.fireChannelRead(decodeOut);
1527                 } else {
1528                     decodeOut.release();
1529                 }
1530             }
1531         }
1532         return originalLength - length;
1533     }
1534 
1535     private static ByteBuffer toByteBuffer(ByteBuf out, int index, int len) {
1536         return out.nioBufferCount() == 1 ? out.internalNioBuffer(index, len) :
1537                 out.nioBuffer(index, len);
1538     }
1539 
1540     private static boolean inEventLoop(Executor executor) {
1541         return executor instanceof EventExecutor && ((EventExecutor) executor).inEventLoop();
1542     }
1543 
1544     private static void runAllDelegatedTasks(SSLEngine engine) {
1545         for (;;) {
1546             Runnable task = engine.getDelegatedTask();
1547             if (task == null) {
1548                 return;
1549             }
1550             task.run();
1551         }
1552     }
1553 
1554     /**
1555      * Will either run the delegated task directly calling {@link Runnable#run()} and return {@code true} or will
1556      * offload the delegated task using {@link Executor#execute(Runnable)} and return {@code false}.
1557      *
1558      * If the task is offloaded it will take care to resume its work on the {@link EventExecutor} once there are no
1559      * more tasks to process.
1560      */
1561     private boolean runDelegatedTasks(boolean inUnwrap) {
1562         if (delegatedTaskExecutor == ImmediateExecutor.INSTANCE || inEventLoop(delegatedTaskExecutor)) {
1563             // We should run the task directly in the EventExecutor thread and not offload at all.
1564             runAllDelegatedTasks(engine);
1565             return true;
1566         } else {
1567             executeDelegatedTasks(inUnwrap);
1568             return false;
1569         }
1570     }
1571 
1572     private void executeDelegatedTasks(boolean inUnwrap) {
1573         processTask = true;
1574         try {
1575             delegatedTaskExecutor.execute(new SslTasksRunner(inUnwrap));
1576         } catch (RejectedExecutionException e) {
1577             processTask = false;
1578             throw e;
1579         }
1580     }
1581 
1582     /**
1583      * {@link Runnable} that will be scheduled on the {@code delegatedTaskExecutor} and will take care
1584      * of resume work on the {@link EventExecutor} once the task was executed.
1585      */
1586     private final class SslTasksRunner implements Runnable {
1587         private final boolean inUnwrap;
1588 
1589         SslTasksRunner(boolean inUnwrap) {
1590             this.inUnwrap = inUnwrap;
1591         }
1592 
1593         // Handle errors which happened during task processing.
1594         private void taskError(Throwable e) {
1595             if (inUnwrap) {
1596                 // As the error happened while the task was scheduled as part of unwrap(...) we also need to ensure
1597                 // we fire it through the pipeline as inbound error to be consistent with what we do in decode(...).
1598                 //
1599                 // This will also ensure we fail the handshake future and flush all produced data.
1600                 try {
1601                     handleUnwrapThrowable(ctx, e);
1602                 } catch (Throwable cause) {
1603                     safeExceptionCaught(cause);
1604                 }
1605             } else {
1606                 setHandshakeFailure(ctx, e);
1607                 forceFlush(ctx);
1608             }
1609         }
1610 
1611         // Try to call exceptionCaught(...)
1612         private void safeExceptionCaught(Throwable cause) {
1613             try {
1614                 exceptionCaught(ctx, wrapIfNeeded(cause));
1615             } catch (Throwable error) {
1616                 ctx.fireExceptionCaught(error);
1617             }
1618         }
1619 
1620         private Throwable wrapIfNeeded(Throwable cause) {
1621             if (!inUnwrap) {
1622                 // If we are not in unwrap(...) we can just rethrow without wrapping at all.
1623                 return cause;
1624             }
1625             // As the exception would have been triggered by an inbound operation we will need to wrap it in a
1626             // DecoderException to mimic what a decoder would do when decode(...) throws.
1627             return cause instanceof DecoderException ? cause : new DecoderException(cause);
1628         }
1629 
1630         private void tryDecodeAgain() {
1631             try {
1632                 channelRead(ctx, Unpooled.EMPTY_BUFFER);
1633             } catch (Throwable cause) {
1634                 safeExceptionCaught(cause);
1635             } finally {
1636                 // As we called channelRead(...) we also need to call channelReadComplete(...) which
1637                 // will ensure we either call ctx.fireChannelReadComplete() or will trigger a ctx.read() if
1638                 // more data is needed.
1639                 channelReadComplete0(ctx);
1640             }
1641         }
1642 
1643         /**
1644          * Executed after the wrapped {@code task} was executed via {@code delegatedTaskExecutor} to resume work
1645          * on the {@link EventExecutor}.
1646          */
1647         private void resumeOnEventExecutor() {
1648             assert ctx.executor().inEventLoop();
1649 
1650             processTask = false;
1651 
1652             try {
1653                 HandshakeStatus status = engine.getHandshakeStatus();
1654                 switch (status) {
1655                     // There is another task that needs to be executed and offloaded to the delegatingTaskExecutor.
1656                     case NEED_TASK:
1657                         executeDelegatedTasks(inUnwrap);
1658 
1659                         break;
1660 
1661                     // The handshake finished, lets notify about the completion of it and resume processing.
1662                     case FINISHED:
1663                         setHandshakeSuccess();
1664 
1665                         // deliberate fall-through
1666 
1667                     // Not handshaking anymore, lets notify about the completion if not done yet and resume processing.
1668                     case NOT_HANDSHAKING:
1669                         setHandshakeSuccessIfStillHandshaking();
1670                         try {
1671                             // Lets call wrap to ensure we produce the alert if there is any pending and also to
1672                             // ensure we flush any queued data..
1673                             wrap(ctx, inUnwrap);
1674                         } catch (Throwable e) {
1675                             taskError(e);
1676                             return;
1677                         }
1678                         if (inUnwrap) {
1679                             // If we were in the unwrap call when the task was processed we should also try to unwrap
1680                             // non app data first as there may not anything left in the inbound buffer to process.
1681                             unwrapNonAppData(ctx);
1682                         }
1683 
1684                         // Flush now as we may have written some data as part of the wrap call.
1685                         forceFlush(ctx);
1686 
1687                         tryDecodeAgain();
1688                         break;
1689 
1690                     // We need more data so lets try to unwrap first and then call decode again which will feed us
1691                     // with buffered data (if there is any).
1692                     case NEED_UNWRAP:
1693                         try {
1694                             unwrapNonAppData(ctx);
1695                         } catch (SSLException e) {
1696                             handleUnwrapThrowable(ctx, e);
1697                             return;
1698                         }
1699                         tryDecodeAgain();
1700                         break;
1701 
1702                     // To make progress we need to call SSLEngine.wrap(...) which may produce more output data
1703                     // that will be written to the Channel.
1704                     case NEED_WRAP:
1705                         try {
1706                             if (!wrapNonAppData(ctx, false) && inUnwrap) {
1707                                 // The handshake finished in wrapNonAppData(...), we need to try call
1708                                 // unwrapNonAppData(...) as we may have some alert that we should read.
1709                                 //
1710                                 // This mimics what we would do when we are calling this method while in unwrap(...).
1711                                 unwrapNonAppData(ctx);
1712                             }
1713 
1714                             // Flush now as we may have written some data as part of the wrap call.
1715                             forceFlush(ctx);
1716                         } catch (Throwable e) {
1717                             taskError(e);
1718                             return;
1719                         }
1720 
1721                         // Now try to feed in more data that we have buffered.
1722                         tryDecodeAgain();
1723                         break;
1724 
1725                     default:
1726                         // Should never reach here as we handle all cases.
1727                         throw new AssertionError();
1728                 }
1729             } catch (Throwable cause) {
1730                 safeExceptionCaught(cause);
1731             }
1732         }
1733 
1734         @Override
1735         public void run() {
1736             try {
1737                 runAllDelegatedTasks(engine);
1738 
1739                 // All tasks were processed.
1740                 assert engine.getHandshakeStatus() != HandshakeStatus.NEED_TASK;
1741 
1742                 // Jump back on the EventExecutor.
1743                 ctx.executor().execute(new Runnable() {
1744                     @Override
1745                     public void run() {
1746                         resumeOnEventExecutor();
1747                     }
1748                 });
1749             } catch (final Throwable cause) {
1750                 handleException(cause);
1751             }
1752         }
1753 
1754         private void handleException(final Throwable cause) {
1755             if (ctx.executor().inEventLoop()) {
1756                 processTask = false;
1757                 safeExceptionCaught(cause);
1758             } else {
1759                 try {
1760                     ctx.executor().execute(new Runnable() {
1761                         @Override
1762                         public void run() {
1763                             processTask = false;
1764                             safeExceptionCaught(cause);
1765                         }
1766                     });
1767                 } catch (RejectedExecutionException ignore) {
1768                     processTask = false;
1769                     // the context itself will handle the rejected exception when try to schedule the operation so
1770                     // ignore the RejectedExecutionException
1771                     ctx.fireExceptionCaught(cause);
1772                 }
1773             }
1774         }
1775     }
1776 
1777     /**
1778      * Works around some Android {@link SSLEngine} implementations that skip {@link HandshakeStatus#FINISHED} and
1779      * go straight into {@link HandshakeStatus#NOT_HANDSHAKING} when handshake is finished.
1780      *
1781      * @return {@code true} if and only if the workaround has been applied and thus {@link #handshakeFuture} has been
1782      *         marked as success by this method
1783      */
1784     private boolean setHandshakeSuccessIfStillHandshaking() {
1785         if (!handshakePromise.isDone()) {
1786             setHandshakeSuccess();
1787             return true;
1788         }
1789         return false;
1790     }
1791 
1792     /**
1793      * Notify all the handshake futures about the successfully handshake
1794      */
1795     private void setHandshakeSuccess() {
1796         handshakePromise.trySuccess(ctx.channel());
1797 
1798         if (logger.isDebugEnabled()) {
1799             SSLSession session = engine.getSession();
1800             logger.debug(
1801               "{} HANDSHAKEN: protocol:{} cipher suite:{}",
1802               ctx.channel(),
1803               session.getProtocol(),
1804               session.getCipherSuite());
1805         }
1806         ctx.fireUserEventTriggered(SslHandshakeCompletionEvent.SUCCESS);
1807 
1808         if (readDuringHandshake && !ctx.channel().config().isAutoRead()) {
1809             readDuringHandshake = false;
1810             ctx.read();
1811         }
1812     }
1813 
1814     /**
1815      * Notify all the handshake futures about the failure during the handshake.
1816      */
1817     private void setHandshakeFailure(ChannelHandlerContext ctx, Throwable cause) {
1818         setHandshakeFailure(ctx, cause, true, true, false);
1819     }
1820 
1821     /**
1822      * Notify all the handshake futures about the failure during the handshake.
1823      */
1824     private void setHandshakeFailure(ChannelHandlerContext ctx, Throwable cause, boolean closeInbound,
1825                                      boolean notify, boolean alwaysFlushAndClose) {
1826         try {
1827             // Release all resources such as internal buffers that SSLEngine
1828             // is managing.
1829             outboundClosed = true;
1830             engine.closeOutbound();
1831 
1832             if (closeInbound) {
1833                 try {
1834                     engine.closeInbound();
1835                 } catch (SSLException e) {
1836                     if (logger.isDebugEnabled()) {
1837                         // only log in debug mode as it most likely harmless and latest chrome still trigger
1838                         // this all the time.
1839                         //
1840                         // See https://github.com/netty/netty/issues/1340
1841                         String msg = e.getMessage();
1842                         if (msg == null || !(msg.contains("possible truncation attack") ||
1843                                 msg.contains("closing inbound before receiving peer's close_notify"))) {
1844                             logger.debug("{} SSLEngine.closeInbound() raised an exception.", ctx.channel(), e);
1845                         }
1846                     }
1847                 }
1848             }
1849             if (handshakePromise.tryFailure(cause) || alwaysFlushAndClose) {
1850                 SslUtils.handleHandshakeFailure(ctx, cause, notify);
1851             }
1852         } finally {
1853             // Ensure we remove and fail all pending writes in all cases and so release memory quickly.
1854             releaseAndFailAll(ctx, cause);
1855         }
1856     }
1857 
1858     private void setHandshakeFailureTransportFailure(ChannelHandlerContext ctx, Throwable cause) {
1859         // If TLS control frames fail to write we are in an unknown state and may become out of
1860         // sync with our peer. We give up and close the channel. This will also take care of
1861         // cleaning up any outstanding state (e.g. handshake promise, queued unencrypted data).
1862         try {
1863             SSLException transportFailure = new SSLException("failure when writing TLS control frames", cause);
1864             releaseAndFailAll(ctx, transportFailure);
1865             if (handshakePromise.tryFailure(transportFailure)) {
1866                 ctx.fireUserEventTriggered(new SslHandshakeCompletionEvent(transportFailure));
1867             }
1868         } finally {
1869             ctx.close();
1870         }
1871     }
1872 
1873     private void releaseAndFailAll(ChannelHandlerContext ctx, Throwable cause) {
1874         if (pendingUnencryptedWrites != null) {
1875             pendingUnencryptedWrites.releaseAndFailAll(ctx, cause);
1876         }
1877     }
1878 
1879     private void notifyClosePromise(Throwable cause) {
1880         if (cause == null) {
1881             if (sslClosePromise.trySuccess(ctx.channel())) {
1882                 ctx.fireUserEventTriggered(SslCloseCompletionEvent.SUCCESS);
1883             }
1884         } else {
1885             if (sslClosePromise.tryFailure(cause)) {
1886                 ctx.fireUserEventTriggered(new SslCloseCompletionEvent(cause));
1887             }
1888         }
1889     }
1890 
1891     private void closeOutboundAndChannel(
1892             final ChannelHandlerContext ctx, final ChannelPromise promise, boolean disconnect) throws Exception {
1893         outboundClosed = true;
1894         engine.closeOutbound();
1895 
1896         if (!ctx.channel().isActive()) {
1897             if (disconnect) {
1898                 ctx.disconnect(promise);
1899             } else {
1900                 ctx.close(promise);
1901             }
1902             return;
1903         }
1904 
1905         ChannelPromise closeNotifyPromise = ctx.newPromise();
1906         try {
1907             flush(ctx, closeNotifyPromise);
1908         } finally {
1909             if (!closeNotify) {
1910                 closeNotify = true;
1911                 // It's important that we do not pass the original ChannelPromise to safeClose(...) as when flush(....)
1912                 // throws an Exception it will be propagated to the AbstractChannelHandlerContext which will try
1913                 // to fail the promise because of this. This will then fail as it was already completed by
1914                 // safeClose(...). We create a new ChannelPromise and try to notify the original ChannelPromise
1915                 // once it is complete. If we fail to do so we just ignore it as in this case it was failed already
1916                 // because of a propagated Exception.
1917                 //
1918                 // See https://github.com/netty/netty/issues/5931
1919                 safeClose(ctx, closeNotifyPromise, ctx.newPromise().addListener(
1920                         new ChannelPromiseNotifier(false, promise)));
1921             } else {
1922                 /// We already handling the close_notify so just attach the promise to the sslClosePromise.
1923                 sslClosePromise.addListener(new FutureListener<Channel>() {
1924                     @Override
1925                     public void operationComplete(Future<Channel> future) {
1926                         promise.setSuccess();
1927                     }
1928                 });
1929             }
1930         }
1931     }
1932 
1933     private void flush(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {
1934         if (pendingUnencryptedWrites != null) {
1935             pendingUnencryptedWrites.add(Unpooled.EMPTY_BUFFER, promise);
1936         } else {
1937             promise.setFailure(newPendingWritesNullException());
1938         }
1939         flush(ctx);
1940     }
1941 
1942     @Override
1943     public void handlerAdded(final ChannelHandlerContext ctx) throws Exception {
1944         this.ctx = ctx;
1945 
1946         pendingUnencryptedWrites = new SslHandlerCoalescingBufferQueue(ctx.channel(), 16);
1947         if (ctx.channel().isActive()) {
1948             startHandshakeProcessing();
1949         }
1950     }
1951 
1952     private void startHandshakeProcessing() {
1953         if (!handshakeStarted) {
1954             handshakeStarted = true;
1955             if (engine.getUseClientMode()) {
1956                 // Begin the initial handshake.
1957                 // channelActive() event has been fired already, which means this.channelActive() will
1958                 // not be invoked. We have to initialize here instead.
1959                 handshake();
1960             }
1961             applyHandshakeTimeout();
1962         }
1963     }
1964 
1965     /**
1966      * Performs TLS renegotiation.
1967      */
1968     public Future<Channel> renegotiate() {
1969         ChannelHandlerContext ctx = this.ctx;
1970         if (ctx == null) {
1971             throw new IllegalStateException();
1972         }
1973 
1974         return renegotiate(ctx.executor().<Channel>newPromise());
1975     }
1976 
1977     /**
1978      * Performs TLS renegotiation.
1979      */
1980     public Future<Channel> renegotiate(final Promise<Channel> promise) {
1981         ObjectUtil.checkNotNull(promise, "promise");
1982 
1983         ChannelHandlerContext ctx = this.ctx;
1984         if (ctx == null) {
1985             throw new IllegalStateException();
1986         }
1987 
1988         EventExecutor executor = ctx.executor();
1989         if (!executor.inEventLoop()) {
1990             executor.execute(new Runnable() {
1991                 @Override
1992                 public void run() {
1993                     renegotiateOnEventLoop(promise);
1994                 }
1995             });
1996             return promise;
1997         }
1998 
1999         renegotiateOnEventLoop(promise);
2000         return promise;
2001     }
2002 
2003     private void renegotiateOnEventLoop(final Promise<Channel> newHandshakePromise) {
2004         final Promise<Channel> oldHandshakePromise = handshakePromise;
2005         if (!oldHandshakePromise.isDone()) {
2006             // There's no need to handshake because handshake is in progress already.
2007             // Merge the new promise into the old one.
2008             oldHandshakePromise.addListener(new PromiseNotifier<Channel, Future<Channel>>(newHandshakePromise));
2009         } else {
2010             handshakePromise = newHandshakePromise;
2011             handshake();
2012             applyHandshakeTimeout();
2013         }
2014     }
2015 
2016     /**
2017      * Performs TLS (re)negotiation.
2018      */
2019     private void handshake() {
2020         if (engine.getHandshakeStatus() != HandshakeStatus.NOT_HANDSHAKING) {
2021             // Not all SSLEngine implementations support calling beginHandshake multiple times while a handshake
2022             // is in progress. See https://github.com/netty/netty/issues/4718.
2023             return;
2024         } else {
2025             if (handshakePromise.isDone()) {
2026                 // If the handshake is done already lets just return directly as there is no need to trigger it again.
2027                 // This can happen if the handshake(...) was triggered before we called channelActive(...) by a
2028                 // flush() that was triggered by a ChannelFutureListener that was added to the ChannelFuture returned
2029                 // from the connect(...) method. In this case we will see the flush() happen before we had a chance to
2030                 // call fireChannelActive() on the pipeline.
2031                 return;
2032             }
2033         }
2034 
2035         // Begin handshake.
2036         final ChannelHandlerContext ctx = this.ctx;
2037         try {
2038             engine.beginHandshake();
2039             wrapNonAppData(ctx, false);
2040         } catch (Throwable e) {
2041             setHandshakeFailure(ctx, e);
2042         } finally {
2043             forceFlush(ctx);
2044         }
2045     }
2046 
2047     private void applyHandshakeTimeout() {
2048         final Promise<Channel> localHandshakePromise = this.handshakePromise;
2049 
2050         // Set timeout if necessary.
2051         final long handshakeTimeoutMillis = this.handshakeTimeoutMillis;
2052         if (handshakeTimeoutMillis <= 0 || localHandshakePromise.isDone()) {
2053             return;
2054         }
2055 
2056         final ScheduledFuture<?> timeoutFuture = ctx.executor().schedule(new Runnable() {
2057             @Override
2058             public void run() {
2059                 if (localHandshakePromise.isDone()) {
2060                     return;
2061                 }
2062                 SSLException exception =
2063                         new SslHandshakeTimeoutException("handshake timed out after " + handshakeTimeoutMillis + "ms");
2064                 try {
2065                     if (localHandshakePromise.tryFailure(exception)) {
2066                         SslUtils.handleHandshakeFailure(ctx, exception, true);
2067                     }
2068                 } finally {
2069                     releaseAndFailAll(ctx, exception);
2070                 }
2071             }
2072         }, handshakeTimeoutMillis, TimeUnit.MILLISECONDS);
2073 
2074         // Cancel the handshake timeout when handshake is finished.
2075         localHandshakePromise.addListener(new FutureListener<Channel>() {
2076             @Override
2077             public void operationComplete(Future<Channel> f) throws Exception {
2078                 timeoutFuture.cancel(false);
2079             }
2080         });
2081     }
2082 
2083     private void forceFlush(ChannelHandlerContext ctx) {
2084         needsFlush = false;
2085         ctx.flush();
2086     }
2087 
2088     /**
2089      * Issues an initial TLS handshake once connected when used in client-mode
2090      */
2091     @Override
2092     public void channelActive(final ChannelHandlerContext ctx) throws Exception {
2093         if (!startTls) {
2094             startHandshakeProcessing();
2095         }
2096         ctx.fireChannelActive();
2097     }
2098 
2099     private void safeClose(
2100             final ChannelHandlerContext ctx, final ChannelFuture flushFuture,
2101             final ChannelPromise promise) {
2102         if (!ctx.channel().isActive()) {
2103             ctx.close(promise);
2104             return;
2105         }
2106 
2107         final ScheduledFuture<?> timeoutFuture;
2108         if (!flushFuture.isDone()) {
2109             long closeNotifyTimeout = closeNotifyFlushTimeoutMillis;
2110             if (closeNotifyTimeout > 0) {
2111                 // Force-close the connection if close_notify is not fully sent in time.
2112                 timeoutFuture = ctx.executor().schedule(new Runnable() {
2113                     @Override
2114                     public void run() {
2115                         // May be done in the meantime as cancel(...) is only best effort.
2116                         if (!flushFuture.isDone()) {
2117                             logger.warn("{} Last write attempt timed out; force-closing the connection.",
2118                                     ctx.channel());
2119                             addCloseListener(ctx.close(ctx.newPromise()), promise);
2120                         }
2121                     }
2122                 }, closeNotifyTimeout, TimeUnit.MILLISECONDS);
2123             } else {
2124                 timeoutFuture = null;
2125             }
2126         } else {
2127             timeoutFuture = null;
2128         }
2129 
2130         // Close the connection if close_notify is sent in time.
2131         flushFuture.addListener(new ChannelFutureListener() {
2132             @Override
2133             public void operationComplete(ChannelFuture f)
2134                     throws Exception {
2135                 if (timeoutFuture != null) {
2136                     timeoutFuture.cancel(false);
2137                 }
2138                 final long closeNotifyReadTimeout = closeNotifyReadTimeoutMillis;
2139                 if (closeNotifyReadTimeout <= 0) {
2140                     // Trigger the close in all cases to make sure the promise is notified
2141                     // See https://github.com/netty/netty/issues/2358
2142                     addCloseListener(ctx.close(ctx.newPromise()), promise);
2143                 } else {
2144                     final ScheduledFuture<?> closeNotifyReadTimeoutFuture;
2145 
2146                     if (!sslClosePromise.isDone()) {
2147                         closeNotifyReadTimeoutFuture = ctx.executor().schedule(new Runnable() {
2148                             @Override
2149                             public void run() {
2150                                 if (!sslClosePromise.isDone()) {
2151                                     logger.debug(
2152                                             "{} did not receive close_notify in {}ms; force-closing the connection.",
2153                                             ctx.channel(), closeNotifyReadTimeout);
2154 
2155                                     // Do the close now...
2156                                     addCloseListener(ctx.close(ctx.newPromise()), promise);
2157                                 }
2158                             }
2159                         }, closeNotifyReadTimeout, TimeUnit.MILLISECONDS);
2160                     } else {
2161                         closeNotifyReadTimeoutFuture = null;
2162                     }
2163 
2164                     // Do the close once the we received the close_notify.
2165                     sslClosePromise.addListener(new FutureListener<Channel>() {
2166                         @Override
2167                         public void operationComplete(Future<Channel> future) throws Exception {
2168                             if (closeNotifyReadTimeoutFuture != null) {
2169                                 closeNotifyReadTimeoutFuture.cancel(false);
2170                             }
2171                             addCloseListener(ctx.close(ctx.newPromise()), promise);
2172                         }
2173                     });
2174                 }
2175             }
2176         });
2177     }
2178 
2179     private static void addCloseListener(ChannelFuture future, ChannelPromise promise) {
2180         // We notify the promise in the ChannelPromiseNotifier as there is a "race" where the close(...) call
2181         // by the timeoutFuture and the close call in the flushFuture listener will be called. Because of
2182         // this we need to use trySuccess() and tryFailure(...) as otherwise we can cause an
2183         // IllegalStateException.
2184         // Also we not want to log if the notification happens as this is expected in some cases.
2185         // See https://github.com/netty/netty/issues/5598
2186         future.addListener(new ChannelPromiseNotifier(false, promise));
2187     }
2188 
2189     /**
2190      * Always prefer a direct buffer when it's pooled, so that we reduce the number of memory copies
2191      * in {@link OpenSslEngine}.
2192      */
2193     private ByteBuf allocate(ChannelHandlerContext ctx, int capacity) {
2194         ByteBufAllocator alloc = ctx.alloc();
2195         if (engineType.wantsDirectBuffer) {
2196             return alloc.directBuffer(capacity);
2197         } else {
2198             return alloc.buffer(capacity);
2199         }
2200     }
2201 
2202     /**
2203      * Allocates an outbound network buffer for {@link SSLEngine#wrap(ByteBuffer, ByteBuffer)} which can encrypt
2204      * the specified amount of pending bytes.
2205      */
2206     private ByteBuf allocateOutNetBuf(ChannelHandlerContext ctx, int pendingBytes, int numComponents) {
2207         return engineType.allocateWrapBuffer(this, ctx.alloc(), pendingBytes, numComponents);
2208     }
2209 
2210     /**
2211      * Each call to SSL_write will introduce about ~100 bytes of overhead. This coalescing queue attempts to increase
2212      * goodput by aggregating the plaintext in chunks of {@link #wrapDataSize}. If many small chunks are written
2213      * this can increase goodput, decrease the amount of calls to SSL_write, and decrease overall encryption operations.
2214      */
2215     private final class SslHandlerCoalescingBufferQueue extends AbstractCoalescingBufferQueue {
2216 
2217         SslHandlerCoalescingBufferQueue(Channel channel, int initSize) {
2218             super(channel, initSize);
2219         }
2220 
2221         @Override
2222         protected ByteBuf compose(ByteBufAllocator alloc, ByteBuf cumulation, ByteBuf next) {
2223             final int wrapDataSize = SslHandler.this.wrapDataSize;
2224             if (cumulation instanceof CompositeByteBuf) {
2225                 CompositeByteBuf composite = (CompositeByteBuf) cumulation;
2226                 int numComponents = composite.numComponents();
2227                 if (numComponents == 0 ||
2228                         !attemptCopyToCumulation(composite.internalComponent(numComponents - 1), next, wrapDataSize)) {
2229                     composite.addComponent(true, next);
2230                 }
2231                 return composite;
2232             }
2233             return attemptCopyToCumulation(cumulation, next, wrapDataSize) ? cumulation :
2234                     copyAndCompose(alloc, cumulation, next);
2235         }
2236 
2237         @Override
2238         protected ByteBuf composeFirst(ByteBufAllocator allocator, ByteBuf first) {
2239             if (first instanceof CompositeByteBuf) {
2240                 CompositeByteBuf composite = (CompositeByteBuf) first;
2241                 if (engineType.wantsDirectBuffer) {
2242                     first = allocator.directBuffer(composite.readableBytes());
2243                 } else {
2244                     first = allocator.heapBuffer(composite.readableBytes());
2245                 }
2246                 try {
2247                     first.writeBytes(composite);
2248                 } catch (Throwable cause) {
2249                     first.release();
2250                     PlatformDependent.throwException(cause);
2251                 }
2252                 composite.release();
2253             }
2254             return first;
2255         }
2256 
2257         @Override
2258         protected ByteBuf removeEmptyValue() {
2259             return null;
2260         }
2261     }
2262 
2263     private static boolean attemptCopyToCumulation(ByteBuf cumulation, ByteBuf next, int wrapDataSize) {
2264         final int inReadableBytes = next.readableBytes();
2265         final int cumulationCapacity = cumulation.capacity();
2266         if (wrapDataSize - cumulation.readableBytes() >= inReadableBytes &&
2267                 // Avoid using the same buffer if next's data would make cumulation exceed the wrapDataSize.
2268                 // Only copy if there is enough space available and the capacity is large enough, and attempt to
2269                 // resize if the capacity is small.
2270                 (cumulation.isWritable(inReadableBytes) && cumulationCapacity >= wrapDataSize ||
2271                         cumulationCapacity < wrapDataSize &&
2272                                 ensureWritableSuccess(cumulation.ensureWritable(inReadableBytes, false)))) {
2273             cumulation.writeBytes(next);
2274             next.release();
2275             return true;
2276         }
2277         return false;
2278     }
2279 
2280     private final class LazyChannelPromise extends DefaultPromise<Channel> {
2281 
2282         @Override
2283         protected EventExecutor executor() {
2284             if (ctx == null) {
2285                 throw new IllegalStateException();
2286             }
2287             return ctx.executor();
2288         }
2289 
2290         @Override
2291         protected void checkDeadLock() {
2292             if (ctx == null) {
2293                 // If ctx is null the handlerAdded(...) callback was not called, in this case the checkDeadLock()
2294                 // method was called from another Thread then the one that is used by ctx.executor(). We need to
2295                 // guard against this as a user can see a race if handshakeFuture().sync() is called but the
2296                 // handlerAdded(..) method was not yet as it is called from the EventExecutor of the
2297                 // ChannelHandlerContext. If we not guard against this super.checkDeadLock() would cause an
2298                 // IllegalStateException when trying to call executor().
2299                 return;
2300             }
2301             super.checkDeadLock();
2302         }
2303     }
2304 }