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    *   http://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.ChannelOutboundHandler;
32  import io.netty.channel.ChannelPipeline;
33  import io.netty.channel.ChannelPromise;
34  import io.netty.channel.ChannelPromiseNotifier;
35  import io.netty.handler.codec.ByteToMessageDecoder;
36  import io.netty.handler.codec.UnsupportedMessageTypeException;
37  import io.netty.util.ReferenceCountUtil;
38  import io.netty.util.ReferenceCounted;
39  import io.netty.util.concurrent.DefaultPromise;
40  import io.netty.util.concurrent.EventExecutor;
41  import io.netty.util.concurrent.Future;
42  import io.netty.util.concurrent.FutureListener;
43  import io.netty.util.concurrent.ImmediateExecutor;
44  import io.netty.util.concurrent.Promise;
45  import io.netty.util.internal.PlatformDependent;
46  import io.netty.util.internal.ThrowableUtil;
47  import io.netty.util.internal.UnstableApi;
48  import io.netty.util.internal.logging.InternalLogger;
49  import io.netty.util.internal.logging.InternalLoggerFactory;
50  
51  import java.io.IOException;
52  import java.net.SocketAddress;
53  import java.nio.ByteBuffer;
54  import java.nio.channels.ClosedChannelException;
55  import java.nio.channels.DatagramChannel;
56  import java.nio.channels.SocketChannel;
57  import java.util.ArrayList;
58  import java.util.List;
59  import java.util.concurrent.CountDownLatch;
60  import java.util.concurrent.Executor;
61  import java.util.concurrent.ScheduledFuture;
62  import java.util.concurrent.TimeUnit;
63  import java.util.regex.Pattern;
64  
65  import javax.net.ssl.SSLEngine;
66  import javax.net.ssl.SSLEngineResult;
67  import javax.net.ssl.SSLEngineResult.HandshakeStatus;
68  import javax.net.ssl.SSLEngineResult.Status;
69  import javax.net.ssl.SSLException;
70  import javax.net.ssl.SSLSession;
71  
72  import static io.netty.buffer.ByteBufUtil.ensureWritableSuccess;
73  import static io.netty.handler.ssl.SslUtils.getEncryptedPacketLength;
74  
75  /**
76   * Adds <a href="http://en.wikipedia.org/wiki/Transport_Layer_Security">SSL
77   * &middot; TLS</a> and StartTLS support to a {@link Channel}.  Please refer
78   * to the <strong>"SecureChat"</strong> example in the distribution or the web
79   * site for the detailed usage.
80   *
81   * <h3>Beginning the handshake</h3>
82   * <p>
83   * Beside using the handshake {@link ChannelFuture} to get notified about the completion of the handshake it's
84   * also possible to detect it by implement the
85   * {@link ChannelInboundHandler#userEventTriggered(ChannelHandlerContext, Object)}
86   * method and check for a {@link SslHandshakeCompletionEvent}.
87   *
88   * <h3>Handshake</h3>
89   * <p>
90   * The handshake will be automatically issued for you once the {@link Channel} is active and
91   * {@link SSLEngine#getUseClientMode()} returns {@code true}.
92   * So no need to bother with it by your self.
93   *
94   * <h3>Closing the session</h3>
95   * <p>
96   * To close the SSL session, the {@link #close()} method should be
97   * called to send the {@code close_notify} message to the remote peer.  One
98   * exception is when you close the {@link Channel} - {@link SslHandler}
99   * intercepts the close request and send the {@code close_notify} message
100  * before the channel closure automatically.  Once the SSL session is closed,
101  * it is not reusable, and consequently you should create a new
102  * {@link SslHandler} with a new {@link SSLEngine} as explained in the
103  * following section.
104  *
105  * <h3>Restarting the session</h3>
106  * <p>
107  * To restart the SSL session, you must remove the existing closed
108  * {@link SslHandler} from the {@link ChannelPipeline}, insert a new
109  * {@link SslHandler} with a new {@link SSLEngine} into the pipeline,
110  * and start the handshake process as described in the first section.
111  *
112  * <h3>Implementing StartTLS</h3>
113  * <p>
114  * <a href="http://en.wikipedia.org/wiki/STARTTLS">StartTLS</a> is the
115  * communication pattern that secures the wire in the middle of the plaintext
116  * connection.  Please note that it is different from SSL &middot; TLS, that
117  * secures the wire from the beginning of the connection.  Typically, StartTLS
118  * is composed of three steps:
119  * <ol>
120  * <li>Client sends a StartTLS request to server.</li>
121  * <li>Server sends a StartTLS response to client.</li>
122  * <li>Client begins SSL handshake.</li>
123  * </ol>
124  * If you implement a server, you need to:
125  * <ol>
126  * <li>create a new {@link SslHandler} instance with {@code startTls} flag set
127  *     to {@code true},</li>
128  * <li>insert the {@link SslHandler} to the {@link ChannelPipeline}, and</li>
129  * <li>write a StartTLS response.</li>
130  * </ol>
131  * Please note that you must insert {@link SslHandler} <em>before</em> sending
132  * the StartTLS response.  Otherwise the client can send begin SSL handshake
133  * before {@link SslHandler} is inserted to the {@link ChannelPipeline}, causing
134  * data corruption.
135  * <p>
136  * The client-side implementation is much simpler.
137  * <ol>
138  * <li>Write a StartTLS request,</li>
139  * <li>wait for the StartTLS response,</li>
140  * <li>create a new {@link SslHandler} instance with {@code startTls} flag set
141  *     to {@code false},</li>
142  * <li>insert the {@link SslHandler} to the {@link ChannelPipeline}, and</li>
143  * <li>Initiate SSL handshake.</li>
144  * </ol>
145  *
146  * <h3>Known issues</h3>
147  * <p>
148  * Because of a known issue with the current implementation of the SslEngine that comes
149  * with Java it may be possible that you see blocked IO-Threads while a full GC is done.
150  * <p>
151  * So if you are affected you can workaround this problem by adjust the cache settings
152  * like shown below:
153  *
154  * <pre>
155  *     SslContext context = ...;
156  *     context.getServerSessionContext().setSessionCacheSize(someSaneSize);
157  *     context.getServerSessionContext().setSessionTime(someSameTimeout);
158  * </pre>
159  * <p>
160  * What values to use here depends on the nature of your application and should be set
161  * based on monitoring and debugging of it.
162  * For more details see
163  * <a href="https://github.com/netty/netty/issues/832">#832</a> in our issue tracker.
164  */
165 public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundHandler {
166 
167     private static final InternalLogger logger =
168             InternalLoggerFactory.getInstance(SslHandler.class);
169 
170     private static final Pattern IGNORABLE_CLASS_IN_STACK = Pattern.compile(
171             "^.*(?:Socket|Datagram|Sctp|Udt)Channel.*$");
172     private static final Pattern IGNORABLE_ERROR_MESSAGE = Pattern.compile(
173             "^.*(?:connection.*(?:reset|closed|abort|broken)|broken.*pipe).*$", Pattern.CASE_INSENSITIVE);
174 
175     /**
176      * Used in {@link #unwrapNonAppData(ChannelHandlerContext)} as input for
177      * {@link #unwrap(ChannelHandlerContext, ByteBuf, int,  int)}.  Using this static instance reduce object
178      * creation as {@link Unpooled#EMPTY_BUFFER#nioBuffer()} creates a new {@link ByteBuffer} everytime.
179      */
180     private static final SSLException SSLENGINE_CLOSED = ThrowableUtil.unknownStackTrace(
181             new SSLException("SSLEngine closed already"), SslHandler.class, "wrap(...)");
182     private static final SSLException HANDSHAKE_TIMED_OUT = ThrowableUtil.unknownStackTrace(
183             new SSLException("handshake timed out"), SslHandler.class, "handshake(...)");
184     private static final ClosedChannelException CHANNEL_CLOSED = ThrowableUtil.unknownStackTrace(
185             new ClosedChannelException(), SslHandler.class, "channelInactive(...)");
186 
187     /**
188      * <a href="https://tools.ietf.org/html/rfc5246#section-6.2">2^14</a> which is the maximum sized plaintext chunk
189      * allowed by the TLS RFC.
190      */
191     private static final int MAX_PLAINTEXT_LENGTH = 16 * 1024;
192 
193     private enum SslEngineType {
194         TCNATIVE(true, COMPOSITE_CUMULATOR) {
195             @Override
196             SSLEngineResult unwrap(SslHandler handler, ByteBuf in, int readerIndex, int len, ByteBuf out)
197                     throws SSLException {
198                 int nioBufferCount = in.nioBufferCount();
199                 int writerIndex = out.writerIndex();
200                 final SSLEngineResult result;
201                 if (nioBufferCount > 1) {
202                     /*
203                      * If {@link OpenSslEngine} is in use,
204                      * we can use a special {@link OpenSslEngine#unwrap(ByteBuffer[], ByteBuffer[])} method
205                      * that accepts multiple {@link ByteBuffer}s without additional memory copies.
206                      */
207                     ReferenceCountedOpenSslEngine opensslEngine = (ReferenceCountedOpenSslEngine) handler.engine;
208                     try {
209                         handler.singleBuffer[0] = toByteBuffer(out, writerIndex,
210                             out.writableBytes());
211                         result = opensslEngine.unwrap(in.nioBuffers(readerIndex, len), handler.singleBuffer);
212                     } finally {
213                         handler.singleBuffer[0] = null;
214                     }
215                 } else {
216                     result = handler.engine.unwrap(toByteBuffer(in, readerIndex, len),
217                         toByteBuffer(out, writerIndex, out.writableBytes()));
218                 }
219                 out.writerIndex(writerIndex + result.bytesProduced());
220                 return result;
221             }
222 
223             @Override
224             int getPacketBufferSize(SslHandler handler) {
225                 return ((ReferenceCountedOpenSslEngine) handler.engine).maxEncryptedPacketLength0();
226             }
227 
228             @Override
229             int calculateWrapBufferCapacity(SslHandler handler, int pendingBytes, int numComponents) {
230                 return ((ReferenceCountedOpenSslEngine) handler.engine).calculateMaxLengthForWrap(pendingBytes,
231                                                                                                   numComponents);
232             }
233 
234             @Override
235             int calculatePendingData(SslHandler handler, int guess) {
236                 int sslPending = ((ReferenceCountedOpenSslEngine) handler.engine).sslPending();
237                 return sslPending > 0 ? sslPending : guess;
238             }
239 
240             @Override
241             boolean jdkCompatibilityMode(SSLEngine engine) {
242                 return ((ReferenceCountedOpenSslEngine) engine).jdkCompatibilityMode;
243             }
244         },
245         CONSCRYPT(true, COMPOSITE_CUMULATOR) {
246             @Override
247             SSLEngineResult unwrap(SslHandler handler, ByteBuf in, int readerIndex, int len, ByteBuf out)
248                     throws SSLException {
249                 int nioBufferCount = in.nioBufferCount();
250                 int writerIndex = out.writerIndex();
251                 final SSLEngineResult result;
252                 if (nioBufferCount > 1) {
253                     /*
254                      * Use a special unwrap method without additional memory copies.
255                      */
256                     try {
257                         handler.singleBuffer[0] = toByteBuffer(out, writerIndex, out.writableBytes());
258                         result = ((ConscryptAlpnSslEngine) handler.engine).unwrap(
259                                 in.nioBuffers(readerIndex, len),
260                                 handler.singleBuffer);
261                     } finally {
262                         handler.singleBuffer[0] = null;
263                     }
264                 } else {
265                     result = handler.engine.unwrap(toByteBuffer(in, readerIndex, len),
266                             toByteBuffer(out, writerIndex, out.writableBytes()));
267                 }
268                 out.writerIndex(writerIndex + result.bytesProduced());
269                 return result;
270             }
271 
272             @Override
273             int calculateWrapBufferCapacity(SslHandler handler, int pendingBytes, int numComponents) {
274                 return ((ConscryptAlpnSslEngine) handler.engine).calculateOutNetBufSize(pendingBytes, numComponents);
275             }
276 
277             @Override
278             int calculatePendingData(SslHandler handler, int guess) {
279                 return guess;
280             }
281 
282             @Override
283             boolean jdkCompatibilityMode(SSLEngine engine) {
284                 return true;
285             }
286         },
287         JDK(false, MERGE_CUMULATOR) {
288             @Override
289             SSLEngineResult unwrap(SslHandler handler, ByteBuf in, int readerIndex, int len, ByteBuf out)
290                     throws SSLException {
291                 int writerIndex = out.writerIndex();
292                 final SSLEngineResult result = handler.engine.unwrap(toByteBuffer(in, readerIndex, len),
293                     toByteBuffer(out, writerIndex, out.writableBytes()));
294                 out.writerIndex(writerIndex + result.bytesProduced());
295                 return result;
296             }
297 
298             @Override
299             int calculateWrapBufferCapacity(SslHandler handler, int pendingBytes, int numComponents) {
300                 return handler.engine.getSession().getPacketBufferSize();
301             }
302 
303             @Override
304             int calculatePendingData(SslHandler handler, int guess) {
305                 return guess;
306             }
307 
308             @Override
309             boolean jdkCompatibilityMode(SSLEngine engine) {
310                 return true;
311             }
312         };
313 
314         static SslEngineType forEngine(SSLEngine engine) {
315             return engine instanceof ReferenceCountedOpenSslEngine ? TCNATIVE :
316                    engine instanceof ConscryptAlpnSslEngine ? CONSCRYPT : JDK;
317         }
318 
319         SslEngineType(boolean wantsDirectBuffer, Cumulator cumulator) {
320             this.wantsDirectBuffer = wantsDirectBuffer;
321             this.cumulator = cumulator;
322         }
323 
324         int getPacketBufferSize(SslHandler handler) {
325             return handler.engine.getSession().getPacketBufferSize();
326         }
327 
328         abstract SSLEngineResult unwrap(SslHandler handler, ByteBuf in, int readerIndex, int len, ByteBuf out)
329                 throws SSLException;
330 
331         abstract int calculateWrapBufferCapacity(SslHandler handler, int pendingBytes, int numComponents);
332 
333         abstract int calculatePendingData(SslHandler handler, int guess);
334 
335         abstract boolean jdkCompatibilityMode(SSLEngine engine);
336 
337         // BEGIN Platform-dependent flags
338 
339         /**
340          * {@code true} if and only if {@link SSLEngine} expects a direct buffer.
341          */
342         final boolean wantsDirectBuffer;
343 
344         // END Platform-dependent flags
345 
346         /**
347          * When using JDK {@link SSLEngine}, we use {@link #MERGE_CUMULATOR} because it works only with
348          * one {@link ByteBuffer}.
349          *
350          * When using {@link OpenSslEngine}, we can use {@link #COMPOSITE_CUMULATOR} because it has
351          * {@link OpenSslEngine#unwrap(ByteBuffer[], ByteBuffer[])} which works with multiple {@link ByteBuffer}s
352          * and which does not need to do extra memory copies.
353          */
354         final Cumulator cumulator;
355     }
356 
357     private volatile ChannelHandlerContext ctx;
358     private final SSLEngine engine;
359     private final SslEngineType engineType;
360     private final Executor delegatedTaskExecutor;
361     private final boolean jdkCompatibilityMode;
362 
363     /**
364      * Used if {@link SSLEngine#wrap(ByteBuffer[], ByteBuffer)} and {@link SSLEngine#unwrap(ByteBuffer, ByteBuffer[])}
365      * should be called with a {@link ByteBuf} that is only backed by one {@link ByteBuffer} to reduce the object
366      * creation.
367      */
368     private final ByteBuffer[] singleBuffer = new ByteBuffer[1];
369 
370     private final boolean startTls;
371     private boolean sentFirstMessage;
372     private boolean flushedBeforeHandshake;
373     private boolean readDuringHandshake;
374     private boolean handshakeStarted;
375     private SslHandlerCoalescingBufferQueue pendingUnencryptedWrites;
376     private Promise<Channel> handshakePromise = new LazyChannelPromise();
377     private final LazyChannelPromise sslClosePromise = new LazyChannelPromise();
378 
379     /**
380      * Set by wrap*() methods when something is produced.
381      * {@link #channelReadComplete(ChannelHandlerContext)} will check this flag, clear it, and call ctx.flush().
382      */
383     private boolean needsFlush;
384 
385     private boolean outboundClosed;
386 
387     private int packetLength;
388 
389     /**
390      * This flag is used to determine if we need to call {@link ChannelHandlerContext#read()} to consume more data
391      * when {@link ChannelConfig#isAutoRead()} is {@code false}.
392      */
393     private boolean firedChannelRead;
394 
395     private volatile long handshakeTimeoutMillis = 10000;
396     private volatile long closeNotifyFlushTimeoutMillis = 3000;
397     private volatile long closeNotifyReadTimeoutMillis;
398     volatile int wrapDataSize = MAX_PLAINTEXT_LENGTH;
399 
400     /**
401      * Creates a new instance.
402      *
403      * @param engine  the {@link SSLEngine} this handler will use
404      */
405     public SslHandler(SSLEngine engine) {
406         this(engine, false);
407     }
408 
409     /**
410      * Creates a new instance.
411      *
412      * @param engine    the {@link SSLEngine} this handler will use
413      * @param startTls  {@code true} if the first write request shouldn't be
414      *                  encrypted by the {@link SSLEngine}
415      */
416     @SuppressWarnings("deprecation")
417     public SslHandler(SSLEngine engine, boolean startTls) {
418         this(engine, startTls, ImmediateExecutor.INSTANCE);
419     }
420 
421     /**
422      * @deprecated Use {@link #SslHandler(SSLEngine)} instead.
423      */
424     @Deprecated
425     public SslHandler(SSLEngine engine, Executor delegatedTaskExecutor) {
426         this(engine, false, delegatedTaskExecutor);
427     }
428 
429     /**
430      * @deprecated Use {@link #SslHandler(SSLEngine, boolean)} instead.
431      */
432     @Deprecated
433     public SslHandler(SSLEngine engine, boolean startTls, Executor delegatedTaskExecutor) {
434         if (engine == null) {
435             throw new NullPointerException("engine");
436         }
437         if (delegatedTaskExecutor == null) {
438             throw new NullPointerException("delegatedTaskExecutor");
439         }
440         this.engine = engine;
441         engineType = SslEngineType.forEngine(engine);
442         this.delegatedTaskExecutor = delegatedTaskExecutor;
443         this.startTls = startTls;
444         this.jdkCompatibilityMode = engineType.jdkCompatibilityMode(engine);
445         setCumulator(engineType.cumulator);
446     }
447 
448     public long getHandshakeTimeoutMillis() {
449         return handshakeTimeoutMillis;
450     }
451 
452     public void setHandshakeTimeout(long handshakeTimeout, TimeUnit unit) {
453         if (unit == null) {
454             throw new NullPointerException("unit");
455         }
456 
457         setHandshakeTimeoutMillis(unit.toMillis(handshakeTimeout));
458     }
459 
460     public void setHandshakeTimeoutMillis(long handshakeTimeoutMillis) {
461         if (handshakeTimeoutMillis < 0) {
462             throw new IllegalArgumentException(
463                     "handshakeTimeoutMillis: " + handshakeTimeoutMillis + " (expected: >= 0)");
464         }
465         this.handshakeTimeoutMillis = handshakeTimeoutMillis;
466     }
467 
468     /**
469      * Sets the number of bytes to pass to each {@link SSLEngine#wrap(ByteBuffer[], int, int, ByteBuffer)} call.
470      * <p>
471      * This value will partition data which is passed to write
472      * {@link #write(ChannelHandlerContext, Object, ChannelPromise)}. The partitioning will work as follows:
473      * <ul>
474      * <li>If {@code wrapDataSize <= 0} then we will write each data chunk as is.</li>
475      * <li>If {@code wrapDataSize > data size} then we will attempt to aggregate multiple data chunks together.</li>
476      * <li>If {@code wrapDataSize > data size}  Else if {@code wrapDataSize <= data size} then we will divide the data
477      * into chunks of {@code wrapDataSize} when writing.</li>
478      * </ul>
479      * <p>
480      * If the {@link SSLEngine} doesn't support a gather wrap operation (e.g. {@link SslProvider#OPENSSL}) then
481      * aggregating data before wrapping can help reduce the ratio between TLS overhead vs data payload which will lead
482      * to better goodput. Writing fixed chunks of data can also help target the underlying transport's (e.g. TCP)
483      * frame size. Under lossy/congested network conditions this may help the peer get full TLS packets earlier and
484      * be able to do work sooner, as opposed to waiting for the all the pieces of the TLS packet to arrive.
485      * @param wrapDataSize the number of bytes which will be passed to each
486      *      {@link SSLEngine#wrap(ByteBuffer[], int, int, ByteBuffer)} call.
487      */
488     @UnstableApi
489     public final void setWrapDataSize(int wrapDataSize) {
490         this.wrapDataSize = wrapDataSize;
491     }
492 
493     /**
494      * @deprecated use {@link #getCloseNotifyFlushTimeoutMillis()}
495      */
496     @Deprecated
497     public long getCloseNotifyTimeoutMillis() {
498         return getCloseNotifyFlushTimeoutMillis();
499     }
500 
501     /**
502      * @deprecated use {@link #setCloseNotifyFlushTimeout(long, TimeUnit)}
503      */
504     @Deprecated
505     public void setCloseNotifyTimeout(long closeNotifyTimeout, TimeUnit unit) {
506         setCloseNotifyFlushTimeout(closeNotifyTimeout, unit);
507     }
508 
509     /**
510      * @deprecated use {@link #setCloseNotifyFlushTimeoutMillis(long)}
511      */
512     @Deprecated
513     public void setCloseNotifyTimeoutMillis(long closeNotifyFlushTimeoutMillis) {
514         setCloseNotifyFlushTimeoutMillis(closeNotifyFlushTimeoutMillis);
515     }
516 
517     /**
518      * Gets the timeout for flushing the close_notify that was triggered by closing the
519      * {@link Channel}. If the close_notify was not flushed in the given timeout the {@link Channel} will be closed
520      * forcibly.
521      */
522     public final long getCloseNotifyFlushTimeoutMillis() {
523         return closeNotifyFlushTimeoutMillis;
524     }
525 
526     /**
527      * Sets the timeout for flushing the close_notify that was triggered by closing the
528      * {@link Channel}. If the close_notify was not flushed in the given timeout the {@link Channel} will be closed
529      * forcibly.
530      */
531     public final void setCloseNotifyFlushTimeout(long closeNotifyFlushTimeout, TimeUnit unit) {
532         setCloseNotifyFlushTimeoutMillis(unit.toMillis(closeNotifyFlushTimeout));
533     }
534 
535     /**
536      * See {@link #setCloseNotifyFlushTimeout(long, TimeUnit)}.
537      */
538     public final void setCloseNotifyFlushTimeoutMillis(long closeNotifyFlushTimeoutMillis) {
539         if (closeNotifyFlushTimeoutMillis < 0) {
540             throw new IllegalArgumentException(
541                     "closeNotifyFlushTimeoutMillis: " + closeNotifyFlushTimeoutMillis + " (expected: >= 0)");
542         }
543         this.closeNotifyFlushTimeoutMillis = closeNotifyFlushTimeoutMillis;
544     }
545 
546     /**
547      * Gets the timeout (in ms) for receiving the response for the close_notify that was triggered by closing the
548      * {@link Channel}. This timeout starts after the close_notify message was successfully written to the
549      * remote peer. Use {@code 0} to directly close the {@link Channel} and not wait for the response.
550      */
551     public final long getCloseNotifyReadTimeoutMillis() {
552         return closeNotifyReadTimeoutMillis;
553     }
554 
555     /**
556      * Sets the timeout  for receiving the response for the close_notify that was triggered by closing the
557      * {@link Channel}. This timeout starts after the close_notify message was successfully written to the
558      * remote peer. Use {@code 0} to directly close the {@link Channel} and not wait for the response.
559      */
560     public final void setCloseNotifyReadTimeout(long closeNotifyReadTimeout, TimeUnit unit) {
561         setCloseNotifyReadTimeoutMillis(unit.toMillis(closeNotifyReadTimeout));
562     }
563 
564     /**
565      * See {@link #setCloseNotifyReadTimeout(long, TimeUnit)}.
566      */
567     public final void setCloseNotifyReadTimeoutMillis(long closeNotifyReadTimeoutMillis) {
568         if (closeNotifyReadTimeoutMillis < 0) {
569             throw new IllegalArgumentException(
570                     "closeNotifyReadTimeoutMillis: " + closeNotifyReadTimeoutMillis + " (expected: >= 0)");
571         }
572         this.closeNotifyReadTimeoutMillis = closeNotifyReadTimeoutMillis;
573     }
574 
575     /**
576      * Returns the {@link SSLEngine} which is used by this handler.
577      */
578     public SSLEngine engine() {
579         return engine;
580     }
581 
582     /**
583      * Returns the name of the current application-level protocol.
584      *
585      * @return the protocol name or {@code null} if application-level protocol has not been negotiated
586      */
587     public String applicationProtocol() {
588         SSLEngine engine = engine();
589         if (!(engine instanceof ApplicationProtocolAccessor)) {
590             return null;
591         }
592 
593         return ((ApplicationProtocolAccessor) engine).getNegotiatedApplicationProtocol();
594     }
595 
596     /**
597      * Returns a {@link Future} that will get notified once the current TLS handshake completes.
598      *
599      * @return the {@link Future} for the initial TLS handshake if {@link #renegotiate()} was not invoked.
600      *         The {@link Future} for the most recent {@linkplain #renegotiate() TLS renegotiation} otherwise.
601      */
602     public Future<Channel> handshakeFuture() {
603         return handshakePromise;
604     }
605 
606     /**
607      * Sends an SSL {@code close_notify} message to the specified channel and
608      * destroys the underlying {@link SSLEngine}.
609      *
610      * @deprecated use {@link Channel#close()} or {@link ChannelHandlerContext#close()}
611      */
612     @Deprecated
613     public ChannelFuture close() {
614         return close(ctx.newPromise());
615     }
616 
617     /**
618      * See {@link #close()}
619      *
620      * @deprecated use {@link Channel#close()} or {@link ChannelHandlerContext#close()}
621      */
622     @Deprecated
623     public ChannelFuture close(final ChannelPromise promise) {
624         final ChannelHandlerContext ctx = this.ctx;
625         ctx.executor().execute(new Runnable() {
626             @Override
627             public void run() {
628                 outboundClosed = true;
629                 engine.closeOutbound();
630                 try {
631                     flush(ctx, promise);
632                 } catch (Exception e) {
633                     if (!promise.tryFailure(e)) {
634                         logger.warn("{} flush() raised a masked exception.", ctx.channel(), e);
635                     }
636                 }
637             }
638         });
639 
640         return promise;
641     }
642 
643     /**
644      * Return the {@link Future} that will get notified if the inbound of the {@link SSLEngine} is closed.
645      *
646      * This method will return the same {@link Future} all the time.
647      *
648      * @see SSLEngine
649      */
650     public Future<Channel> sslCloseFuture() {
651         return sslClosePromise;
652     }
653 
654     @Override
655     public void handlerRemoved0(ChannelHandlerContext ctx) throws Exception {
656         if (!pendingUnencryptedWrites.isEmpty()) {
657             // Check if queue is not empty first because create a new ChannelException is expensive
658             pendingUnencryptedWrites.releaseAndFailAll(ctx,
659                     new ChannelException("Pending write on removal of SslHandler"));
660         }
661         pendingUnencryptedWrites = null;
662         if (engine instanceof ReferenceCounted) {
663             ((ReferenceCounted) engine).release();
664         }
665     }
666 
667     @Override
668     public void bind(ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise) throws Exception {
669         ctx.bind(localAddress, promise);
670     }
671 
672     @Override
673     public void connect(ChannelHandlerContext ctx, SocketAddress remoteAddress, SocketAddress localAddress,
674                         ChannelPromise promise) throws Exception {
675         ctx.connect(remoteAddress, localAddress, promise);
676     }
677 
678     @Override
679     public void deregister(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {
680         ctx.deregister(promise);
681     }
682 
683     @Override
684     public void disconnect(final ChannelHandlerContext ctx,
685                            final ChannelPromise promise) throws Exception {
686         closeOutboundAndChannel(ctx, promise, true);
687     }
688 
689     @Override
690     public void close(final ChannelHandlerContext ctx,
691                       final ChannelPromise promise) throws Exception {
692         closeOutboundAndChannel(ctx, promise, false);
693     }
694 
695     @Override
696     public void read(ChannelHandlerContext ctx) throws Exception {
697         if (!handshakePromise.isDone()) {
698             readDuringHandshake = true;
699         }
700 
701         ctx.read();
702     }
703 
704     private static IllegalStateException newPendingWritesNullException() {
705         return new IllegalStateException("pendingUnencryptedWrites is null, handlerRemoved0 called?");
706     }
707 
708     @Override
709     public void write(final ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
710         if (!(msg instanceof ByteBuf)) {
711             UnsupportedMessageTypeException exception = new UnsupportedMessageTypeException(msg, ByteBuf.class);
712             ReferenceCountUtil.safeRelease(msg);
713             promise.setFailure(exception);
714         } else if (pendingUnencryptedWrites == null) {
715             ReferenceCountUtil.safeRelease(msg);
716             promise.setFailure(newPendingWritesNullException());
717         } else {
718             pendingUnencryptedWrites.add((ByteBuf) msg, promise);
719         }
720     }
721 
722     @Override
723     public void flush(ChannelHandlerContext ctx) throws Exception {
724         // Do not encrypt the first write request if this handler is
725         // created with startTLS flag turned on.
726         if (startTls && !sentFirstMessage) {
727             sentFirstMessage = true;
728             pendingUnencryptedWrites.writeAndRemoveAll(ctx);
729             forceFlush(ctx);
730             return;
731         }
732 
733         try {
734             wrapAndFlush(ctx);
735         } catch (Throwable cause) {
736             setHandshakeFailure(ctx, cause);
737             PlatformDependent.throwException(cause);
738         }
739     }
740 
741     private void wrapAndFlush(ChannelHandlerContext ctx) throws SSLException {
742         if (pendingUnencryptedWrites.isEmpty()) {
743             // It's important to NOT use a voidPromise here as the user
744             // may want to add a ChannelFutureListener to the ChannelPromise later.
745             //
746             // See https://github.com/netty/netty/issues/3364
747             pendingUnencryptedWrites.add(Unpooled.EMPTY_BUFFER, ctx.newPromise());
748         }
749         if (!handshakePromise.isDone()) {
750             flushedBeforeHandshake = true;
751         }
752         try {
753             wrap(ctx, false);
754         } finally {
755             // We may have written some parts of data before an exception was thrown so ensure we always flush.
756             // See https://github.com/netty/netty/issues/3900#issuecomment-172481830
757             forceFlush(ctx);
758         }
759     }
760 
761     // This method will not call setHandshakeFailure(...) !
762     private void wrap(ChannelHandlerContext ctx, boolean inUnwrap) throws SSLException {
763         ByteBuf out = null;
764         ChannelPromise promise = null;
765         ByteBufAllocator alloc = ctx.alloc();
766         boolean needUnwrap = false;
767         ByteBuf buf = null;
768         try {
769             final int wrapDataSize = this.wrapDataSize;
770             // Only continue to loop if the handler was not removed in the meantime.
771             // See https://github.com/netty/netty/issues/5860
772             while (!ctx.isRemoved()) {
773                 promise = ctx.newPromise();
774                 buf = wrapDataSize > 0 ?
775                         pendingUnencryptedWrites.remove(alloc, wrapDataSize, promise) :
776                         pendingUnencryptedWrites.removeFirst(promise);
777                 if (buf == null) {
778                     break;
779                 }
780 
781                 if (out == null) {
782                     out = allocateOutNetBuf(ctx, buf.readableBytes(), buf.nioBufferCount());
783                 }
784 
785                 SSLEngineResult result = wrap(alloc, engine, buf, out);
786 
787                 if (result.getStatus() == Status.CLOSED) {
788                     buf.release();
789                     buf = null;
790                     promise.tryFailure(SSLENGINE_CLOSED);
791                     promise = null;
792                     // SSLEngine has been closed already.
793                     // Any further write attempts should be denied.
794                     pendingUnencryptedWrites.releaseAndFailAll(ctx, SSLENGINE_CLOSED);
795                     return;
796                 } else {
797                     if (buf.isReadable()) {
798                         pendingUnencryptedWrites.addFirst(buf, promise);
799                         // When we add the buffer/promise pair back we need to be sure we don't complete the promise
800                         // later in finishWrap. We only complete the promise if the buffer is completely consumed.
801                         promise = null;
802                     } else {
803                         buf.release();
804                     }
805                     buf = null;
806 
807                     switch (result.getHandshakeStatus()) {
808                         case NEED_TASK:
809                             runDelegatedTasks();
810                             break;
811                         case FINISHED:
812                             setHandshakeSuccess();
813                             // deliberate fall-through
814                         case NOT_HANDSHAKING:
815                             setHandshakeSuccessIfStillHandshaking();
816                             // deliberate fall-through
817                         case NEED_WRAP:
818                             finishWrap(ctx, out, promise, inUnwrap, false);
819                             promise = null;
820                             out = null;
821                             break;
822                         case NEED_UNWRAP:
823                             needUnwrap = true;
824                             return;
825                         default:
826                             throw new IllegalStateException(
827                                     "Unknown handshake status: " + result.getHandshakeStatus());
828                     }
829                 }
830             }
831         } finally {
832             // Ownership of buffer was not transferred, release it.
833             if (buf != null) {
834                 buf.release();
835             }
836             finishWrap(ctx, out, promise, inUnwrap, needUnwrap);
837         }
838     }
839 
840     private void finishWrap(ChannelHandlerContext ctx, ByteBuf out, ChannelPromise promise, boolean inUnwrap,
841             boolean needUnwrap) {
842         if (out == null) {
843             out = Unpooled.EMPTY_BUFFER;
844         } else if (!out.isReadable()) {
845             out.release();
846             out = Unpooled.EMPTY_BUFFER;
847         }
848 
849         if (promise != null) {
850             ctx.write(out, promise);
851         } else {
852             ctx.write(out);
853         }
854 
855         if (inUnwrap) {
856             needsFlush = true;
857         }
858 
859         if (needUnwrap) {
860             // The underlying engine is starving so we need to feed it with more data.
861             // See https://github.com/netty/netty/pull/5039
862             readIfNeeded(ctx);
863         }
864     }
865 
866     /**
867      * This method will not call
868      * {@link #setHandshakeFailure(ChannelHandlerContext, Throwable, boolean, boolean)} or
869      * {@link #setHandshakeFailure(ChannelHandlerContext, Throwable)}.
870      * @return {@code true} if this method ends on {@link SSLEngineResult.HandshakeStatus#NOT_HANDSHAKING}.
871      */
872     private boolean wrapNonAppData(ChannelHandlerContext ctx, boolean inUnwrap) throws SSLException {
873         ByteBuf out = null;
874         ByteBufAllocator alloc = ctx.alloc();
875         try {
876             // Only continue to loop if the handler was not removed in the meantime.
877             // See https://github.com/netty/netty/issues/5860
878             while (!ctx.isRemoved()) {
879                 if (out == null) {
880                     // As this is called for the handshake we have no real idea how big the buffer needs to be.
881                     // That said 2048 should give us enough room to include everything like ALPN / NPN data.
882                     // If this is not enough we will increase the buffer in wrap(...).
883                     out = allocateOutNetBuf(ctx, 2048, 1);
884                 }
885                 SSLEngineResult result = wrap(alloc, engine, Unpooled.EMPTY_BUFFER, out);
886 
887                 if (result.bytesProduced() > 0) {
888                     ctx.write(out);
889                     if (inUnwrap) {
890                         needsFlush = true;
891                     }
892                     out = null;
893                 }
894 
895                 switch (result.getHandshakeStatus()) {
896                     case FINISHED:
897                         setHandshakeSuccess();
898                         return false;
899                     case NEED_TASK:
900                         runDelegatedTasks();
901                         break;
902                     case NEED_UNWRAP:
903                         if (inUnwrap) {
904                             // If we asked for a wrap, the engine requested an unwrap, and we are in unwrap there is
905                             // no use in trying to call wrap again because we have already attempted (or will after we
906                             // return) to feed more data to the engine.
907                             return false;
908                         }
909 
910                         unwrapNonAppData(ctx);
911                         break;
912                     case NEED_WRAP:
913                         break;
914                     case NOT_HANDSHAKING:
915                         setHandshakeSuccessIfStillHandshaking();
916                         // Workaround for TLS False Start problem reported at:
917                         // https://github.com/netty/netty/issues/1108#issuecomment-14266970
918                         if (!inUnwrap) {
919                             unwrapNonAppData(ctx);
920                         }
921                         return true;
922                     default:
923                         throw new IllegalStateException("Unknown handshake status: " + result.getHandshakeStatus());
924                 }
925 
926                 if (result.bytesProduced() == 0) {
927                     break;
928                 }
929 
930                 // It should not consume empty buffers when it is not handshaking
931                 // Fix for Android, where it was encrypting empty buffers even when not handshaking
932                 if (result.bytesConsumed() == 0 && result.getHandshakeStatus() == HandshakeStatus.NOT_HANDSHAKING) {
933                     break;
934                 }
935             }
936         }  finally {
937             if (out != null) {
938                 out.release();
939             }
940         }
941         return false;
942     }
943 
944     private SSLEngineResult wrap(ByteBufAllocator alloc, SSLEngine engine, ByteBuf in, ByteBuf out)
945             throws SSLException {
946         ByteBuf newDirectIn = null;
947         try {
948             int readerIndex = in.readerIndex();
949             int readableBytes = in.readableBytes();
950 
951             // We will call SslEngine.wrap(ByteBuffer[], ByteBuffer) to allow efficient handling of
952             // CompositeByteBuf without force an extra memory copy when CompositeByteBuffer.nioBuffer() is called.
953             final ByteBuffer[] in0;
954             if (in.isDirect() || !engineType.wantsDirectBuffer) {
955                 // As CompositeByteBuf.nioBufferCount() can be expensive (as it needs to check all composed ByteBuf
956                 // to calculate the count) we will just assume a CompositeByteBuf contains more then 1 ByteBuf.
957                 // The worst that can happen is that we allocate an extra ByteBuffer[] in CompositeByteBuf.nioBuffers()
958                 // which is better then walking the composed ByteBuf in most cases.
959                 if (!(in instanceof CompositeByteBuf) && in.nioBufferCount() == 1) {
960                     in0 = singleBuffer;
961                     // We know its only backed by 1 ByteBuffer so use internalNioBuffer to keep object allocation
962                     // to a minimum.
963                     in0[0] = in.internalNioBuffer(readerIndex, readableBytes);
964                 } else {
965                     in0 = in.nioBuffers();
966                 }
967             } else {
968                 // We could even go further here and check if its a CompositeByteBuf and if so try to decompose it and
969                 // only replace the ByteBuffer that are not direct. At the moment we just will replace the whole
970                 // CompositeByteBuf to keep the complexity to a minimum
971                 newDirectIn = alloc.directBuffer(readableBytes);
972                 newDirectIn.writeBytes(in, readerIndex, readableBytes);
973                 in0 = singleBuffer;
974                 in0[0] = newDirectIn.internalNioBuffer(newDirectIn.readerIndex(), readableBytes);
975             }
976 
977             for (;;) {
978                 ByteBuffer out0 = out.nioBuffer(out.writerIndex(), out.writableBytes());
979                 SSLEngineResult result = engine.wrap(in0, out0);
980                 in.skipBytes(result.bytesConsumed());
981                 out.writerIndex(out.writerIndex() + result.bytesProduced());
982 
983                 switch (result.getStatus()) {
984                 case BUFFER_OVERFLOW:
985                     out.ensureWritable(engine.getSession().getPacketBufferSize());
986                     break;
987                 default:
988                     return result;
989                 }
990             }
991         } finally {
992             // Null out to allow GC of ByteBuffer
993             singleBuffer[0] = null;
994 
995             if (newDirectIn != null) {
996                 newDirectIn.release();
997             }
998         }
999     }
1000 
1001     @Override
1002     public void channelInactive(ChannelHandlerContext ctx) throws Exception {
1003         // Make sure to release SSLEngine,
1004         // and notify the handshake future if the connection has been closed during handshake.
1005         setHandshakeFailure(ctx, CHANNEL_CLOSED, !outboundClosed, handshakeStarted);
1006 
1007         // Ensure we always notify the sslClosePromise as well
1008         notifyClosePromise(CHANNEL_CLOSED);
1009 
1010         super.channelInactive(ctx);
1011     }
1012 
1013     @Override
1014     public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
1015         if (ignoreException(cause)) {
1016             // It is safe to ignore the 'connection reset by peer' or
1017             // 'broken pipe' error after sending close_notify.
1018             if (logger.isDebugEnabled()) {
1019                 logger.debug(
1020                         "{} Swallowing a harmless 'connection reset by peer / broken pipe' error that occurred " +
1021                         "while writing close_notify in response to the peer's close_notify", ctx.channel(), cause);
1022             }
1023 
1024             // Close the connection explicitly just in case the transport
1025             // did not close the connection automatically.
1026             if (ctx.channel().isActive()) {
1027                 ctx.close();
1028             }
1029         } else {
1030             ctx.fireExceptionCaught(cause);
1031         }
1032     }
1033 
1034     /**
1035      * Checks if the given {@link Throwable} can be ignore and just "swallowed"
1036      *
1037      * When an ssl connection is closed a close_notify message is sent.
1038      * After that the peer also sends close_notify however, it's not mandatory to receive
1039      * the close_notify. The party who sent the initial close_notify can close the connection immediately
1040      * then the peer will get connection reset error.
1041      *
1042      */
1043     private boolean ignoreException(Throwable t) {
1044         if (!(t instanceof SSLException) && t instanceof IOException && sslClosePromise.isDone()) {
1045             String message = t.getMessage();
1046 
1047             // first try to match connection reset / broke peer based on the regex. This is the fastest way
1048             // but may fail on different jdk impls or OS's
1049             if (message != null && IGNORABLE_ERROR_MESSAGE.matcher(message).matches()) {
1050                 return true;
1051             }
1052 
1053             // Inspect the StackTraceElements to see if it was a connection reset / broken pipe or not
1054             StackTraceElement[] elements = t.getStackTrace();
1055             for (StackTraceElement element: elements) {
1056                 String classname = element.getClassName();
1057                 String methodname = element.getMethodName();
1058 
1059                 // skip all classes that belong to the io.netty package
1060                 if (classname.startsWith("io.netty.")) {
1061                     continue;
1062                 }
1063 
1064                 // check if the method name is read if not skip it
1065                 if (!"read".equals(methodname)) {
1066                     continue;
1067                 }
1068 
1069                 // This will also match against SocketInputStream which is used by openjdk 7 and maybe
1070                 // also others
1071                 if (IGNORABLE_CLASS_IN_STACK.matcher(classname).matches()) {
1072                     return true;
1073                 }
1074 
1075                 try {
1076                     // No match by now.. Try to load the class via classloader and inspect it.
1077                     // This is mainly done as other JDK implementations may differ in name of
1078                     // the impl.
1079                     Class<?> clazz = PlatformDependent.getClassLoader(getClass()).loadClass(classname);
1080 
1081                     if (SocketChannel.class.isAssignableFrom(clazz)
1082                             || DatagramChannel.class.isAssignableFrom(clazz)) {
1083                         return true;
1084                     }
1085 
1086                     // also match against SctpChannel via String matching as it may not present.
1087                     if (PlatformDependent.javaVersion() >= 7
1088                             && "com.sun.nio.sctp.SctpChannel".equals(clazz.getSuperclass().getName())) {
1089                         return true;
1090                     }
1091                 } catch (Throwable cause) {
1092                     logger.debug("Unexpected exception while loading class {} classname {}",
1093                                  getClass(), classname, cause);
1094                 }
1095             }
1096         }
1097 
1098         return false;
1099     }
1100 
1101     /**
1102      * Returns {@code true} if the given {@link ByteBuf} is encrypted. Be aware that this method
1103      * will not increase the readerIndex of the given {@link ByteBuf}.
1104      *
1105      * @param   buffer
1106      *                  The {@link ByteBuf} to read from. Be aware that it must have at least 5 bytes to read,
1107      *                  otherwise it will throw an {@link IllegalArgumentException}.
1108      * @return encrypted
1109      *                  {@code true} if the {@link ByteBuf} is encrypted, {@code false} otherwise.
1110      * @throws IllegalArgumentException
1111      *                  Is thrown if the given {@link ByteBuf} has not at least 5 bytes to read.
1112      */
1113     public static boolean isEncrypted(ByteBuf buffer) {
1114         if (buffer.readableBytes() < SslUtils.SSL_RECORD_HEADER_LENGTH) {
1115             throw new IllegalArgumentException(
1116                     "buffer must have at least " + SslUtils.SSL_RECORD_HEADER_LENGTH + " readable bytes");
1117         }
1118         return getEncryptedPacketLength(buffer, buffer.readerIndex()) != SslUtils.NOT_ENCRYPTED;
1119     }
1120 
1121     private void decodeJdkCompatible(ChannelHandlerContext ctx, ByteBuf in) throws NotSslRecordException {
1122         int packetLength = this.packetLength;
1123         // If we calculated the length of the current SSL record before, use that information.
1124         if (packetLength > 0) {
1125             if (in.readableBytes() < packetLength) {
1126                 return;
1127             }
1128         } else {
1129             // Get the packet length and wait until we get a packets worth of data to unwrap.
1130             final int readableBytes = in.readableBytes();
1131             if (readableBytes < SslUtils.SSL_RECORD_HEADER_LENGTH) {
1132                 return;
1133             }
1134             packetLength = getEncryptedPacketLength(in, in.readerIndex());
1135             if (packetLength == SslUtils.NOT_ENCRYPTED) {
1136                 // Not an SSL/TLS packet
1137                 NotSslRecordException e = new NotSslRecordException(
1138                         "not an SSL/TLS record: " + ByteBufUtil.hexDump(in));
1139                 in.skipBytes(in.readableBytes());
1140 
1141                 // First fail the handshake promise as we may need to have access to the SSLEngine which may
1142                 // be released because the user will remove the SslHandler in an exceptionCaught(...) implementation.
1143                 setHandshakeFailure(ctx, e);
1144 
1145                 throw e;
1146             }
1147             assert packetLength > 0;
1148             if (packetLength > readableBytes) {
1149                 // wait until the whole packet can be read
1150                 this.packetLength = packetLength;
1151                 return;
1152             }
1153         }
1154 
1155         // Reset the state of this class so we can get the length of the next packet. We assume the entire packet will
1156         // be consumed by the SSLEngine.
1157         this.packetLength = 0;
1158         try {
1159             int bytesConsumed = unwrap(ctx, in, in.readerIndex(), packetLength);
1160             assert bytesConsumed == packetLength || engine.isInboundDone() :
1161                     "we feed the SSLEngine a packets worth of data: " + packetLength + " but it only consumed: " +
1162                             bytesConsumed;
1163             in.skipBytes(bytesConsumed);
1164         } catch (Throwable cause) {
1165             handleUnwrapThrowable(ctx, cause);
1166         }
1167     }
1168 
1169     private void decodeNonJdkCompatible(ChannelHandlerContext ctx, ByteBuf in) {
1170         try {
1171             in.skipBytes(unwrap(ctx, in, in.readerIndex(), in.readableBytes()));
1172         } catch (Throwable cause) {
1173             handleUnwrapThrowable(ctx, cause);
1174         }
1175     }
1176 
1177     private void handleUnwrapThrowable(ChannelHandlerContext ctx, Throwable cause) {
1178         try {
1179             // We need to flush one time as there may be an alert that we should send to the remote peer because
1180             // of the SSLException reported here.
1181             wrapAndFlush(ctx);
1182         } catch (SSLException ex) {
1183             logger.debug("SSLException during trying to call SSLEngine.wrap(...)" +
1184                     " because of an previous SSLException, ignoring...", ex);
1185         } finally {
1186             setHandshakeFailure(ctx, cause);
1187         }
1188         PlatformDependent.throwException(cause);
1189     }
1190 
1191     @Override
1192     protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws SSLException {
1193         if (jdkCompatibilityMode) {
1194             decodeJdkCompatible(ctx, in);
1195         } else {
1196             decodeNonJdkCompatible(ctx, in);
1197         }
1198     }
1199 
1200     @Override
1201     public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
1202         // Discard bytes of the cumulation buffer if needed.
1203         discardSomeReadBytes();
1204 
1205         flushIfNeeded(ctx);
1206         readIfNeeded(ctx);
1207 
1208         firedChannelRead = false;
1209         ctx.fireChannelReadComplete();
1210     }
1211 
1212     private void readIfNeeded(ChannelHandlerContext ctx) {
1213         // If handshake is not finished yet, we need more data.
1214         if (!ctx.channel().config().isAutoRead() && (!firedChannelRead || !handshakePromise.isDone())) {
1215             // No auto-read used and no message passed through the ChannelPipeline or the handshake was not complete
1216             // yet, which means we need to trigger the read to ensure we not encounter any stalls.
1217             ctx.read();
1218         }
1219     }
1220 
1221     private void flushIfNeeded(ChannelHandlerContext ctx) {
1222         if (needsFlush) {
1223             forceFlush(ctx);
1224         }
1225     }
1226 
1227     /**
1228      * Calls {@link SSLEngine#unwrap(ByteBuffer, ByteBuffer)} with an empty buffer to handle handshakes, etc.
1229      */
1230     private void unwrapNonAppData(ChannelHandlerContext ctx) throws SSLException {
1231         unwrap(ctx, Unpooled.EMPTY_BUFFER, 0, 0);
1232     }
1233 
1234     /**
1235      * Unwraps inbound SSL records.
1236      */
1237     private int unwrap(
1238             ChannelHandlerContext ctx, ByteBuf packet, int offset, int length) throws SSLException {
1239         final int originalLength = length;
1240         boolean wrapLater = false;
1241         boolean notifyClosure = false;
1242         int overflowReadableBytes = -1;
1243         ByteBuf decodeOut = allocate(ctx, length);
1244         try {
1245             // Only continue to loop if the handler was not removed in the meantime.
1246             // See https://github.com/netty/netty/issues/5860
1247             unwrapLoop: while (!ctx.isRemoved()) {
1248                 final SSLEngineResult result = engineType.unwrap(this, packet, offset, length, decodeOut);
1249                 final Status status = result.getStatus();
1250                 final HandshakeStatus handshakeStatus = result.getHandshakeStatus();
1251                 final int produced = result.bytesProduced();
1252                 final int consumed = result.bytesConsumed();
1253 
1254                 // Update indexes for the next iteration
1255                 offset += consumed;
1256                 length -= consumed;
1257 
1258                 switch (status) {
1259                 case BUFFER_OVERFLOW:
1260                     final int readableBytes = decodeOut.readableBytes();
1261                     final int previousOverflowReadableBytes = overflowReadableBytes;
1262                     overflowReadableBytes = readableBytes;
1263                     int bufferSize = engine.getSession().getApplicationBufferSize() - readableBytes;
1264                     if (readableBytes > 0) {
1265                         firedChannelRead = true;
1266                         ctx.fireChannelRead(decodeOut);
1267 
1268                         // This buffer was handled, null it out.
1269                         decodeOut = null;
1270                         if (bufferSize <= 0) {
1271                             // It may happen that readableBytes >= engine.getSession().getApplicationBufferSize()
1272                             // while there is still more to unwrap, in this case we will just allocate a new buffer
1273                             // with the capacity of engine.getSession().getApplicationBufferSize() and call unwrap
1274                             // again.
1275                             bufferSize = engine.getSession().getApplicationBufferSize();
1276                         }
1277                     } else {
1278                         // This buffer was handled, null it out.
1279                         decodeOut.release();
1280                         decodeOut = null;
1281                     }
1282                     if (readableBytes == 0 && previousOverflowReadableBytes == 0) {
1283                         // If there is two consecutive loops where we overflow and are not able to consume any data,
1284                         // assume the amount of data exceeds the maximum amount for the engine and bail
1285                         throw new IllegalStateException("Two consecutive overflows but no content was consumed. " +
1286                                  SSLSession.class.getSimpleName() + " getApplicationBufferSize: " +
1287                                  engine.getSession().getApplicationBufferSize() + " maybe too small.");
1288                     }
1289                     // Allocate a new buffer which can hold all the rest data and loop again.
1290                     // TODO: We may want to reconsider how we calculate the length here as we may
1291                     // have more then one ssl message to decode.
1292                     decodeOut = allocate(ctx, engineType.calculatePendingData(this, bufferSize));
1293                     continue;
1294                 case CLOSED:
1295                     // notify about the CLOSED state of the SSLEngine. See #137
1296                     notifyClosure = true;
1297                     overflowReadableBytes = -1;
1298                     break;
1299                 default:
1300                     overflowReadableBytes = -1;
1301                     break;
1302                 }
1303 
1304                 switch (handshakeStatus) {
1305                     case NEED_UNWRAP:
1306                         break;
1307                     case NEED_WRAP:
1308                         // If the wrap operation transitions the status to NOT_HANDSHAKING and there is no more data to
1309                         // unwrap then the next call to unwrap will not produce any data. We can avoid the potentially
1310                         // costly unwrap operation and break out of the loop.
1311                         if (wrapNonAppData(ctx, true) && length == 0) {
1312                             break unwrapLoop;
1313                         }
1314                         break;
1315                     case NEED_TASK:
1316                         runDelegatedTasks();
1317                         break;
1318                     case FINISHED:
1319                         setHandshakeSuccess();
1320                         wrapLater = true;
1321 
1322                         // We 'break' here and NOT 'continue' as android API version 21 has a bug where they consume
1323                         // data from the buffer but NOT correctly set the SSLEngineResult.bytesConsumed().
1324                         // Because of this it will raise an exception on the next iteration of the for loop on android
1325                         // API version 21. Just doing a break will work here as produced and consumed will both be 0
1326                         // and so we break out of the complete for (;;) loop and so call decode(...) again later on.
1327                         // On other platforms this will have no negative effect as we will just continue with the
1328                         // for (;;) loop if something was either consumed or produced.
1329                         //
1330                         // See:
1331                         //  - https://github.com/netty/netty/issues/4116
1332                         //  - https://code.google.com/p/android/issues/detail?id=198639&thanks=198639&ts=1452501203
1333                         break;
1334                     case NOT_HANDSHAKING:
1335                         if (setHandshakeSuccessIfStillHandshaking()) {
1336                             wrapLater = true;
1337                             continue;
1338                         }
1339                         if (flushedBeforeHandshake) {
1340                             // We need to call wrap(...) in case there was a flush done before the handshake completed.
1341                             //
1342                             // See https://github.com/netty/netty/pull/2437
1343                             flushedBeforeHandshake = false;
1344                             wrapLater = true;
1345                         }
1346                         // If we are not handshaking and there is no more data to unwrap then the next call to unwrap
1347                         // will not produce any data. We can avoid the potentially costly unwrap operation and break
1348                         // out of the loop.
1349                         if (length == 0) {
1350                             break unwrapLoop;
1351                         }
1352                         break;
1353                     default:
1354                         throw new IllegalStateException("unknown handshake status: " + handshakeStatus);
1355                 }
1356 
1357                 if (status == Status.BUFFER_UNDERFLOW || consumed == 0 && produced == 0) {
1358                     if (handshakeStatus == HandshakeStatus.NEED_UNWRAP) {
1359                         // The underlying engine is starving so we need to feed it with more data.
1360                         // See https://github.com/netty/netty/pull/5039
1361                         readIfNeeded(ctx);
1362                     }
1363 
1364                     break;
1365                 }
1366             }
1367 
1368             if (wrapLater) {
1369                 wrap(ctx, true);
1370             }
1371 
1372             if (notifyClosure) {
1373                 notifyClosePromise(null);
1374             }
1375         } finally {
1376             if (decodeOut != null) {
1377                 if (decodeOut.isReadable()) {
1378                     firedChannelRead = true;
1379 
1380                     ctx.fireChannelRead(decodeOut);
1381                 } else {
1382                     decodeOut.release();
1383                 }
1384             }
1385         }
1386         return originalLength - length;
1387     }
1388 
1389     private static ByteBuffer toByteBuffer(ByteBuf out, int index, int len) {
1390         return out.nioBufferCount() == 1 ? out.internalNioBuffer(index, len) :
1391                 out.nioBuffer(index, len);
1392     }
1393 
1394     /**
1395      * Fetches all delegated tasks from the {@link SSLEngine} and runs them via the {@link #delegatedTaskExecutor}.
1396      * If the {@link #delegatedTaskExecutor} is {@link ImmediateExecutor}, just call {@link Runnable#run()} directly
1397      * instead of using {@link Executor#execute(Runnable)}.  Otherwise, run the tasks via
1398      * the {@link #delegatedTaskExecutor} and wait until the tasks are finished.
1399      */
1400     private void runDelegatedTasks() {
1401         if (delegatedTaskExecutor == ImmediateExecutor.INSTANCE) {
1402             for (;;) {
1403                 Runnable task = engine.getDelegatedTask();
1404                 if (task == null) {
1405                     break;
1406                 }
1407 
1408                 task.run();
1409             }
1410         } else {
1411             final List<Runnable> tasks = new ArrayList<Runnable>(2);
1412             for (;;) {
1413                 final Runnable task = engine.getDelegatedTask();
1414                 if (task == null) {
1415                     break;
1416                 }
1417 
1418                 tasks.add(task);
1419             }
1420 
1421             if (tasks.isEmpty()) {
1422                 return;
1423             }
1424 
1425             final CountDownLatch latch = new CountDownLatch(1);
1426             delegatedTaskExecutor.execute(new Runnable() {
1427                 @Override
1428                 public void run() {
1429                     try {
1430                         for (Runnable task: tasks) {
1431                             task.run();
1432                         }
1433                     } catch (Exception e) {
1434                         ctx.fireExceptionCaught(e);
1435                     } finally {
1436                         latch.countDown();
1437                     }
1438                 }
1439             });
1440 
1441             boolean interrupted = false;
1442             while (latch.getCount() != 0) {
1443                 try {
1444                     latch.await();
1445                 } catch (InterruptedException e) {
1446                     // Interrupt later.
1447                     interrupted = true;
1448                 }
1449             }
1450 
1451             if (interrupted) {
1452                 Thread.currentThread().interrupt();
1453             }
1454         }
1455     }
1456 
1457     /**
1458      * Works around some Android {@link SSLEngine} implementations that skip {@link HandshakeStatus#FINISHED} and
1459      * go straight into {@link HandshakeStatus#NOT_HANDSHAKING} when handshake is finished.
1460      *
1461      * @return {@code true} if and only if the workaround has been applied and thus {@link #handshakeFuture} has been
1462      *         marked as success by this method
1463      */
1464     private boolean setHandshakeSuccessIfStillHandshaking() {
1465         if (!handshakePromise.isDone()) {
1466             setHandshakeSuccess();
1467             return true;
1468         }
1469         return false;
1470     }
1471 
1472     /**
1473      * Notify all the handshake futures about the successfully handshake
1474      */
1475     private void setHandshakeSuccess() {
1476         handshakePromise.trySuccess(ctx.channel());
1477 
1478         if (logger.isDebugEnabled()) {
1479             logger.debug("{} HANDSHAKEN: {}", ctx.channel(), engine.getSession().getCipherSuite());
1480         }
1481         ctx.fireUserEventTriggered(SslHandshakeCompletionEvent.SUCCESS);
1482 
1483         if (readDuringHandshake && !ctx.channel().config().isAutoRead()) {
1484             readDuringHandshake = false;
1485             ctx.read();
1486         }
1487     }
1488 
1489     /**
1490      * Notify all the handshake futures about the failure during the handshake.
1491      */
1492     private void setHandshakeFailure(ChannelHandlerContext ctx, Throwable cause) {
1493         setHandshakeFailure(ctx, cause, true, true);
1494     }
1495 
1496     /**
1497      * Notify all the handshake futures about the failure during the handshake.
1498      */
1499     private void setHandshakeFailure(ChannelHandlerContext ctx, Throwable cause, boolean closeInbound, boolean notify) {
1500         try {
1501             // Release all resources such as internal buffers that SSLEngine
1502             // is managing.
1503             engine.closeOutbound();
1504 
1505             if (closeInbound) {
1506                 try {
1507                     engine.closeInbound();
1508                 } catch (SSLException e) {
1509                     if (logger.isDebugEnabled()) {
1510                         // only log in debug mode as it most likely harmless and latest chrome still trigger
1511                         // this all the time.
1512                         //
1513                         // See https://github.com/netty/netty/issues/1340
1514                         String msg = e.getMessage();
1515                         if (msg == null || !msg.contains("possible truncation attack")) {
1516                             logger.debug("{} SSLEngine.closeInbound() raised an exception.", ctx.channel(), e);
1517                         }
1518                     }
1519                 }
1520             }
1521             notifyHandshakeFailure(cause, notify);
1522         } finally {
1523             // Ensure we remove and fail all pending writes in all cases and so release memory quickly.
1524             releaseAndFailAll(cause);
1525         }
1526     }
1527 
1528     private void releaseAndFailAll(Throwable cause) {
1529         if (pendingUnencryptedWrites != null) {
1530             pendingUnencryptedWrites.releaseAndFailAll(ctx, cause);
1531         }
1532     }
1533 
1534     private void notifyHandshakeFailure(Throwable cause, boolean notify) {
1535         if (handshakePromise.tryFailure(cause)) {
1536             SslUtils.notifyHandshakeFailure(ctx, cause, notify);
1537         }
1538     }
1539 
1540     private void notifyClosePromise(Throwable cause) {
1541         if (cause == null) {
1542             if (sslClosePromise.trySuccess(ctx.channel())) {
1543                 ctx.fireUserEventTriggered(SslCloseCompletionEvent.SUCCESS);
1544             }
1545         } else {
1546             if (sslClosePromise.tryFailure(cause)) {
1547                 ctx.fireUserEventTriggered(new SslCloseCompletionEvent(cause));
1548             }
1549         }
1550     }
1551 
1552     private void closeOutboundAndChannel(
1553             final ChannelHandlerContext ctx, final ChannelPromise promise, boolean disconnect) throws Exception {
1554         if (!ctx.channel().isActive()) {
1555             if (disconnect) {
1556                 ctx.disconnect(promise);
1557             } else {
1558                 ctx.close(promise);
1559             }
1560             return;
1561         }
1562 
1563         outboundClosed = true;
1564         engine.closeOutbound();
1565 
1566         ChannelPromise closeNotifyPromise = ctx.newPromise();
1567         try {
1568             flush(ctx, closeNotifyPromise);
1569         } finally {
1570             // It's important that we do not pass the original ChannelPromise to safeClose(...) as when flush(....)
1571             // throws an Exception it will be propagated to the AbstractChannelHandlerContext which will try
1572             // to fail the promise because of this. This will then fail as it was already completed by safeClose(...).
1573             // We create a new ChannelPromise and try to notify the original ChannelPromise
1574             // once it is complete. If we fail to do so we just ignore it as in this case it was failed already
1575             // because of a propagated Exception.
1576             //
1577             // See https://github.com/netty/netty/issues/5931
1578             safeClose(ctx, closeNotifyPromise, ctx.newPromise().addListener(
1579                     new ChannelPromiseNotifier(false, promise)));
1580         }
1581     }
1582 
1583     private void flush(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {
1584         if (pendingUnencryptedWrites != null) {
1585             pendingUnencryptedWrites.add(Unpooled.EMPTY_BUFFER, promise);
1586         } else {
1587             promise.setFailure(newPendingWritesNullException());
1588         }
1589         flush(ctx);
1590     }
1591 
1592     @Override
1593     public void handlerAdded(final ChannelHandlerContext ctx) throws Exception {
1594         this.ctx = ctx;
1595 
1596         pendingUnencryptedWrites = new SslHandlerCoalescingBufferQueue(ctx.channel(), 16);
1597         if (ctx.channel().isActive()) {
1598             startHandshakeProcessing();
1599         }
1600     }
1601 
1602     private void startHandshakeProcessing() {
1603         handshakeStarted = true;
1604         if (engine.getUseClientMode()) {
1605             // Begin the initial handshake.
1606             // channelActive() event has been fired already, which means this.channelActive() will
1607             // not be invoked. We have to initialize here instead.
1608             handshake(null);
1609         } else {
1610             applyHandshakeTimeout(null);
1611         }
1612     }
1613 
1614     /**
1615      * Performs TLS renegotiation.
1616      */
1617     public Future<Channel> renegotiate() {
1618         ChannelHandlerContext ctx = this.ctx;
1619         if (ctx == null) {
1620             throw new IllegalStateException();
1621         }
1622 
1623         return renegotiate(ctx.executor().<Channel>newPromise());
1624     }
1625 
1626     /**
1627      * Performs TLS renegotiation.
1628      */
1629     public Future<Channel> renegotiate(final Promise<Channel> promise) {
1630         if (promise == null) {
1631             throw new NullPointerException("promise");
1632         }
1633 
1634         ChannelHandlerContext ctx = this.ctx;
1635         if (ctx == null) {
1636             throw new IllegalStateException();
1637         }
1638 
1639         EventExecutor executor = ctx.executor();
1640         if (!executor.inEventLoop()) {
1641             executor.execute(new Runnable() {
1642                 @Override
1643                 public void run() {
1644                     handshake(promise);
1645                 }
1646             });
1647             return promise;
1648         }
1649 
1650         handshake(promise);
1651         return promise;
1652     }
1653 
1654     /**
1655      * Performs TLS (re)negotiation.
1656      *
1657      * @param newHandshakePromise if {@code null}, use the existing {@link #handshakePromise},
1658      *                            assuming that the current negotiation has not been finished.
1659      *                            Currently, {@code null} is expected only for the initial handshake.
1660      */
1661     private void handshake(final Promise<Channel> newHandshakePromise) {
1662         final Promise<Channel> p;
1663         if (newHandshakePromise != null) {
1664             final Promise<Channel> oldHandshakePromise = handshakePromise;
1665             if (!oldHandshakePromise.isDone()) {
1666                 // There's no need to handshake because handshake is in progress already.
1667                 // Merge the new promise into the old one.
1668                 oldHandshakePromise.addListener(new FutureListener<Channel>() {
1669                     @Override
1670                     public void operationComplete(Future<Channel> future) throws Exception {
1671                         if (future.isSuccess()) {
1672                             newHandshakePromise.setSuccess(future.getNow());
1673                         } else {
1674                             newHandshakePromise.setFailure(future.cause());
1675                         }
1676                     }
1677                 });
1678                 return;
1679             }
1680 
1681             handshakePromise = p = newHandshakePromise;
1682         } else if (engine.getHandshakeStatus() != HandshakeStatus.NOT_HANDSHAKING) {
1683             // Not all SSLEngine implementations support calling beginHandshake multiple times while a handshake
1684             // is in progress. See https://github.com/netty/netty/issues/4718.
1685             return;
1686         } else {
1687             // Forced to reuse the old handshake.
1688             p = handshakePromise;
1689             assert !p.isDone();
1690         }
1691 
1692         // Begin handshake.
1693         final ChannelHandlerContext ctx = this.ctx;
1694         try {
1695             engine.beginHandshake();
1696             wrapNonAppData(ctx, false);
1697         } catch (Throwable e) {
1698             setHandshakeFailure(ctx, e);
1699         } finally {
1700            forceFlush(ctx);
1701         }
1702         applyHandshakeTimeout(p);
1703     }
1704 
1705     private void applyHandshakeTimeout(Promise<Channel> p) {
1706         final Promise<Channel> promise = p == null ? handshakePromise : p;
1707         // Set timeout if necessary.
1708         final long handshakeTimeoutMillis = this.handshakeTimeoutMillis;
1709         if (handshakeTimeoutMillis <= 0 || promise.isDone()) {
1710             return;
1711         }
1712 
1713         final ScheduledFuture<?> timeoutFuture = ctx.executor().schedule(new Runnable() {
1714             @Override
1715             public void run() {
1716                 if (promise.isDone()) {
1717                     return;
1718                 }
1719                 try {
1720                     notifyHandshakeFailure(HANDSHAKE_TIMED_OUT, true);
1721                 } finally {
1722                     releaseAndFailAll(HANDSHAKE_TIMED_OUT);
1723                 }
1724             }
1725         }, handshakeTimeoutMillis, TimeUnit.MILLISECONDS);
1726 
1727         // Cancel the handshake timeout when handshake is finished.
1728         promise.addListener(new FutureListener<Channel>() {
1729             @Override
1730             public void operationComplete(Future<Channel> f) throws Exception {
1731                 timeoutFuture.cancel(false);
1732             }
1733         });
1734     }
1735 
1736     private void forceFlush(ChannelHandlerContext ctx) {
1737         needsFlush = false;
1738         ctx.flush();
1739     }
1740 
1741     /**
1742      * Issues an initial TLS handshake once connected when used in client-mode
1743      */
1744     @Override
1745     public void channelActive(final ChannelHandlerContext ctx) throws Exception {
1746         if (!startTls) {
1747             startHandshakeProcessing();
1748         }
1749         ctx.fireChannelActive();
1750     }
1751 
1752     private void safeClose(
1753             final ChannelHandlerContext ctx, final ChannelFuture flushFuture,
1754             final ChannelPromise promise) {
1755         if (!ctx.channel().isActive()) {
1756             ctx.close(promise);
1757             return;
1758         }
1759 
1760         final ScheduledFuture<?> timeoutFuture;
1761         if (!flushFuture.isDone()) {
1762             long closeNotifyTimeout = closeNotifyFlushTimeoutMillis;
1763             if (closeNotifyTimeout > 0) {
1764                 // Force-close the connection if close_notify is not fully sent in time.
1765                 timeoutFuture = ctx.executor().schedule(new Runnable() {
1766                     @Override
1767                     public void run() {
1768                         // May be done in the meantime as cancel(...) is only best effort.
1769                         if (!flushFuture.isDone()) {
1770                             logger.warn("{} Last write attempt timed out; force-closing the connection.",
1771                                     ctx.channel());
1772                             addCloseListener(ctx.close(ctx.newPromise()), promise);
1773                         }
1774                     }
1775                 }, closeNotifyTimeout, TimeUnit.MILLISECONDS);
1776             } else {
1777                 timeoutFuture = null;
1778             }
1779         } else {
1780             timeoutFuture = null;
1781         }
1782 
1783         // Close the connection if close_notify is sent in time.
1784         flushFuture.addListener(new ChannelFutureListener() {
1785             @Override
1786             public void operationComplete(ChannelFuture f)
1787                     throws Exception {
1788                 if (timeoutFuture != null) {
1789                     timeoutFuture.cancel(false);
1790                 }
1791                 final long closeNotifyReadTimeout = closeNotifyReadTimeoutMillis;
1792                 if (closeNotifyReadTimeout <= 0) {
1793                     // Trigger the close in all cases to make sure the promise is notified
1794                     // See https://github.com/netty/netty/issues/2358
1795                     addCloseListener(ctx.close(ctx.newPromise()), promise);
1796                 } else {
1797                     final ScheduledFuture<?> closeNotifyReadTimeoutFuture;
1798 
1799                     if (!sslClosePromise.isDone()) {
1800                         closeNotifyReadTimeoutFuture = ctx.executor().schedule(new Runnable() {
1801                             @Override
1802                             public void run() {
1803                                 if (!sslClosePromise.isDone()) {
1804                                     logger.debug(
1805                                             "{} did not receive close_notify in {}ms; force-closing the connection.",
1806                                             ctx.channel(), closeNotifyReadTimeout);
1807 
1808                                     // Do the close now...
1809                                     addCloseListener(ctx.close(ctx.newPromise()), promise);
1810                                 }
1811                             }
1812                         }, closeNotifyReadTimeout, TimeUnit.MILLISECONDS);
1813                     } else {
1814                         closeNotifyReadTimeoutFuture = null;
1815                     }
1816 
1817                     // Do the close once the we received the close_notify.
1818                     sslClosePromise.addListener(new FutureListener<Channel>() {
1819                         @Override
1820                         public void operationComplete(Future<Channel> future) throws Exception {
1821                             if (closeNotifyReadTimeoutFuture != null) {
1822                                 closeNotifyReadTimeoutFuture.cancel(false);
1823                             }
1824                             addCloseListener(ctx.close(ctx.newPromise()), promise);
1825                         }
1826                     });
1827                 }
1828             }
1829         });
1830     }
1831 
1832     private static void addCloseListener(ChannelFuture future, ChannelPromise promise) {
1833         // We notify the promise in the ChannelPromiseNotifier as there is a "race" where the close(...) call
1834         // by the timeoutFuture and the close call in the flushFuture listener will be called. Because of
1835         // this we need to use trySuccess() and tryFailure(...) as otherwise we can cause an
1836         // IllegalStateException.
1837         // Also we not want to log if the notification happens as this is expected in some cases.
1838         // See https://github.com/netty/netty/issues/5598
1839         future.addListener(new ChannelPromiseNotifier(false, promise));
1840     }
1841 
1842     /**
1843      * Always prefer a direct buffer when it's pooled, so that we reduce the number of memory copies
1844      * in {@link OpenSslEngine}.
1845      */
1846     private ByteBuf allocate(ChannelHandlerContext ctx, int capacity) {
1847         ByteBufAllocator alloc = ctx.alloc();
1848         if (engineType.wantsDirectBuffer) {
1849             return alloc.directBuffer(capacity);
1850         } else {
1851             return alloc.buffer(capacity);
1852         }
1853     }
1854 
1855     /**
1856      * Allocates an outbound network buffer for {@link SSLEngine#wrap(ByteBuffer, ByteBuffer)} which can encrypt
1857      * the specified amount of pending bytes.
1858      */
1859     private ByteBuf allocateOutNetBuf(ChannelHandlerContext ctx, int pendingBytes, int numComponents) {
1860         return allocate(ctx, engineType.calculateWrapBufferCapacity(this, pendingBytes, numComponents));
1861     }
1862 
1863     /**
1864      * Each call to SSL_write will introduce about ~100 bytes of overhead. This coalescing queue attempts to increase
1865      * goodput by aggregating the plaintext in chunks of {@link #wrapDataSize}. If many small chunks are written
1866      * this can increase goodput, decrease the amount of calls to SSL_write, and decrease overall encryption operations.
1867      */
1868     private final class SslHandlerCoalescingBufferQueue extends AbstractCoalescingBufferQueue {
1869 
1870         SslHandlerCoalescingBufferQueue(Channel channel, int initSize) {
1871             super(channel, initSize);
1872         }
1873 
1874         @Override
1875         protected ByteBuf compose(ByteBufAllocator alloc, ByteBuf cumulation, ByteBuf next) {
1876             final int wrapDataSize = SslHandler.this.wrapDataSize;
1877             if (cumulation instanceof CompositeByteBuf) {
1878                 CompositeByteBuf composite = (CompositeByteBuf) cumulation;
1879                 int numComponents = composite.numComponents();
1880                 if (numComponents == 0 ||
1881                         !attemptCopyToCumulation(composite.internalComponent(numComponents - 1), next, wrapDataSize)) {
1882                     composite.addComponent(true, next);
1883                 }
1884                 return composite;
1885             }
1886             return attemptCopyToCumulation(cumulation, next, wrapDataSize) ? cumulation :
1887                     copyAndCompose(alloc, cumulation, next);
1888         }
1889 
1890         @Override
1891         protected ByteBuf composeFirst(ByteBufAllocator allocator, ByteBuf first) {
1892             if (first instanceof CompositeByteBuf) {
1893                 CompositeByteBuf composite = (CompositeByteBuf) first;
1894                 first = allocator.directBuffer(composite.readableBytes());
1895                 try {
1896                     first.writeBytes(composite);
1897                 } catch (Throwable cause) {
1898                     first.release();
1899                     PlatformDependent.throwException(cause);
1900                 }
1901                 composite.release();
1902             }
1903             return first;
1904         }
1905 
1906         @Override
1907         protected ByteBuf removeEmptyValue() {
1908             return null;
1909         }
1910     }
1911 
1912     private static boolean attemptCopyToCumulation(ByteBuf cumulation, ByteBuf next, int wrapDataSize) {
1913         final int inReadableBytes = next.readableBytes();
1914         final int cumulationCapacity = cumulation.capacity();
1915         if (wrapDataSize - cumulation.readableBytes() >= inReadableBytes &&
1916                 // Avoid using the same buffer if next's data would make cumulation exceed the wrapDataSize.
1917                 // Only copy if there is enough space available and the capacity is large enough, and attempt to
1918                 // resize if the capacity is small.
1919                 (cumulation.isWritable(inReadableBytes) && cumulationCapacity >= wrapDataSize ||
1920                         cumulationCapacity < wrapDataSize &&
1921                                 ensureWritableSuccess(cumulation.ensureWritable(inReadableBytes, false)))) {
1922             cumulation.writeBytes(next);
1923             next.release();
1924             return true;
1925         }
1926         return false;
1927     }
1928 
1929     private final class LazyChannelPromise extends DefaultPromise<Channel> {
1930 
1931         @Override
1932         protected EventExecutor executor() {
1933             if (ctx == null) {
1934                 throw new IllegalStateException();
1935             }
1936             return ctx.executor();
1937         }
1938 
1939         @Override
1940         protected void checkDeadLock() {
1941             if (ctx == null) {
1942                 // If ctx is null the handlerAdded(...) callback was not called, in this case the checkDeadLock()
1943                 // method was called from another Thread then the one that is used by ctx.executor(). We need to
1944                 // guard against this as a user can see a race if handshakeFuture().sync() is called but the
1945                 // handlerAdded(..) method was not yet as it is called from the EventExecutor of the
1946                 // ChannelHandlerContext. If we not guard against this super.checkDeadLock() would cause an
1947                 // IllegalStateException when trying to call executor().
1948                 return;
1949             }
1950             super.checkDeadLock();
1951         }
1952     }
1953 }