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