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