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