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