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