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