PageRenderTime 59ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 1ms

/handler/src/main/java/io/netty/handler/ssl/SslHandler.java

http://github.com/netty/netty
Java | 2364 lines | 1538 code | 216 blank | 610 comment | 303 complexity | a88f759a49bc67481fa6e49390a37f4e MD5 | raw file
Possible License(s): Apache-2.0

Large files files are truncated, but you can click here to view the full file

  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. import io.netty.buffer.ByteBuf;
  18. import io.netty.buffer.ByteBufAllocator;
  19. import io.netty.buffer.ByteBufUtil;
  20. import io.netty.buffer.CompositeByteBuf;
  21. import io.netty.buffer.Unpooled;
  22. import io.netty.channel.AbstractCoalescingBufferQueue;
  23. import io.netty.channel.Channel;
  24. import io.netty.channel.ChannelConfig;
  25. import io.netty.channel.ChannelException;
  26. import io.netty.channel.ChannelFuture;
  27. import io.netty.channel.ChannelFutureListener;
  28. import io.netty.channel.ChannelHandlerContext;
  29. import io.netty.channel.ChannelInboundHandler;
  30. import io.netty.channel.ChannelOption;
  31. import io.netty.channel.ChannelOutboundBuffer;
  32. import io.netty.channel.ChannelOutboundHandler;
  33. import io.netty.channel.ChannelPipeline;
  34. import io.netty.channel.ChannelPromise;
  35. import io.netty.handler.codec.ByteToMessageDecoder;
  36. import io.netty.handler.codec.DecoderException;
  37. import io.netty.handler.codec.UnsupportedMessageTypeException;
  38. import io.netty.util.ReferenceCountUtil;
  39. import io.netty.util.concurrent.DefaultPromise;
  40. import io.netty.util.concurrent.EventExecutor;
  41. import io.netty.util.concurrent.Future;
  42. import io.netty.util.concurrent.FutureListener;
  43. import io.netty.util.concurrent.ImmediateExecutor;
  44. import io.netty.util.concurrent.Promise;
  45. import io.netty.util.concurrent.PromiseNotifier;
  46. import io.netty.util.internal.ObjectUtil;
  47. import io.netty.util.internal.PlatformDependent;
  48. import io.netty.util.internal.UnstableApi;
  49. import io.netty.util.internal.logging.InternalLogger;
  50. import io.netty.util.internal.logging.InternalLoggerFactory;
  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.List;
  58. import java.util.concurrent.Executor;
  59. import java.util.concurrent.RejectedExecutionException;
  60. import java.util.concurrent.ScheduledFuture;
  61. import java.util.concurrent.TimeUnit;
  62. import java.util.regex.Pattern;
  63. import javax.net.ssl.SSLEngine;
  64. import javax.net.ssl.SSLEngineResult;
  65. import javax.net.ssl.SSLEngineResult.HandshakeStatus;
  66. import javax.net.ssl.SSLEngineResult.Status;
  67. import javax.net.ssl.SSLException;
  68. import javax.net.ssl.SSLHandshakeException;
  69. import javax.net.ssl.SSLSession;
  70. import static io.netty.buffer.ByteBufUtil.ensureWritableSuccess;
  71. import static io.netty.handler.ssl.SslUtils.getEncryptedPacketLength;
  72. import static io.netty.util.internal.ObjectUtil.checkNotNull;
  73. import static io.netty.util.internal.ObjectUtil.checkPositiveOrZero;
  74. /**
  75. * Adds <a href="https://en.wikipedia.org/wiki/Transport_Layer_Security">SSL
  76. * &middot; TLS</a> and StartTLS support to a {@link Channel}. Please refer
  77. * to the <strong>"SecureChat"</strong> example in the distribution or the web
  78. * site for the detailed usage.
  79. *
  80. * <h3>Beginning the handshake</h3>
  81. * <p>
  82. * Beside using the handshake {@link ChannelFuture} to get notified about the completion of the handshake it's
  83. * also possible to detect it by implement the
  84. * {@link ChannelInboundHandler#userEventTriggered(ChannelHandlerContext, Object)}
  85. * method and check for a {@link SslHandshakeCompletionEvent}.
  86. *
  87. * <h3>Handshake</h3>
  88. * <p>
  89. * The handshake will be automatically issued for you once the {@link Channel} is active and
  90. * {@link SSLEngine#getUseClientMode()} returns {@code true}.
  91. * So no need to bother with it by your self.
  92. *
  93. * <h3>Closing the session</h3>
  94. * <p>
  95. * To close the SSL session, the {@link #closeOutbound()} method should be
  96. * called to send the {@code close_notify} message to the remote peer. One
  97. * exception is when you close the {@link Channel} - {@link SslHandler}
  98. * intercepts the close request and send the {@code close_notify} message
  99. * before the channel closure automatically. Once the SSL session is closed,
  100. * it is not reusable, and consequently you should create a new
  101. * {@link SslHandler} with a new {@link SSLEngine} as explained in the
  102. * following section.
  103. *
  104. * <h3>Restarting the session</h3>
  105. * <p>
  106. * To restart the SSL session, you must remove the existing closed
  107. * {@link SslHandler} from the {@link ChannelPipeline}, insert a new
  108. * {@link SslHandler} with a new {@link SSLEngine} into the pipeline,
  109. * and start the handshake process as described in the first section.
  110. *
  111. * <h3>Implementing StartTLS</h3>
  112. * <p>
  113. * <a href="https://en.wikipedia.org/wiki/STARTTLS">StartTLS</a> is the
  114. * communication pattern that secures the wire in the middle of the plaintext
  115. * connection. Please note that it is different from SSL &middot; TLS, that
  116. * secures the wire from the beginning of the connection. Typically, StartTLS
  117. * is composed of three steps:
  118. * <ol>
  119. * <li>Client sends a StartTLS request to server.</li>
  120. * <li>Server sends a StartTLS response to client.</li>
  121. * <li>Client begins SSL handshake.</li>
  122. * </ol>
  123. * If you implement a server, you need to:
  124. * <ol>
  125. * <li>create a new {@link SslHandler} instance with {@code startTls} flag set
  126. * to {@code true},</li>
  127. * <li>insert the {@link SslHandler} to the {@link ChannelPipeline}, and</li>
  128. * <li>write a StartTLS response.</li>
  129. * </ol>
  130. * Please note that you must insert {@link SslHandler} <em>before</em> sending
  131. * the StartTLS response. Otherwise the client can send begin SSL handshake
  132. * before {@link SslHandler} is inserted to the {@link ChannelPipeline}, causing
  133. * data corruption.
  134. * <p>
  135. * The client-side implementation is much simpler.
  136. * <ol>
  137. * <li>Write a StartTLS request,</li>
  138. * <li>wait for the StartTLS response,</li>
  139. * <li>create a new {@link SslHandler} instance with {@code startTls} flag set
  140. * to {@code false},</li>
  141. * <li>insert the {@link SslHandler} to the {@link ChannelPipeline}, and</li>
  142. * <li>Initiate SSL handshake.</li>
  143. * </ol>
  144. *
  145. * <h3>Known issues</h3>
  146. * <p>
  147. * Because of a known issue with the current implementation of the SslEngine that comes
  148. * with Java it may be possible that you see blocked IO-Threads while a full GC is done.
  149. * <p>
  150. * So if you are affected you can workaround this problem by adjust the cache settings
  151. * like shown below:
  152. *
  153. * <pre>
  154. * SslContext context = ...;
  155. * context.getServerSessionContext().setSessionCacheSize(someSaneSize);
  156. * context.getServerSessionContext().setSessionTime(someSameTimeout);
  157. * </pre>
  158. * <p>
  159. * What values to use here depends on the nature of your application and should be set
  160. * based on monitoring and debugging of it.
  161. * For more details see
  162. * <a href="https://github.com/netty/netty/issues/832">#832</a> in our issue tracker.
  163. */
  164. public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundHandler {
  165. private static final InternalLogger logger =
  166. InternalLoggerFactory.getInstance(SslHandler.class);
  167. private static final Pattern IGNORABLE_CLASS_IN_STACK = Pattern.compile(
  168. "^.*(?:Socket|Datagram|Sctp|Udt)Channel.*$");
  169. private static final Pattern IGNORABLE_ERROR_MESSAGE = Pattern.compile(
  170. "^.*(?:connection.*(?:reset|closed|abort|broken)|broken.*pipe).*$", Pattern.CASE_INSENSITIVE);
  171. private static final int STATE_SENT_FIRST_MESSAGE = 1;
  172. private static final int STATE_FLUSHED_BEFORE_HANDSHAKE = 1 << 1;
  173. private static final int STATE_READ_DURING_HANDSHAKE = 1 << 2;
  174. private static final int STATE_HANDSHAKE_STARTED = 1 << 3;
  175. /**
  176. * Set by wrap*() methods when something is produced.
  177. * {@link #channelReadComplete(ChannelHandlerContext)} will check this flag, clear it, and call ctx.flush().
  178. */
  179. private static final int STATE_NEEDS_FLUSH = 1 << 4;
  180. private static final int STATE_OUTBOUND_CLOSED = 1 << 5;
  181. private static final int STATE_CLOSE_NOTIFY = 1 << 6;
  182. private static final int STATE_PROCESS_TASK = 1 << 7;
  183. /**
  184. * This flag is used to determine if we need to call {@link ChannelHandlerContext#read()} to consume more data
  185. * when {@link ChannelConfig#isAutoRead()} is {@code false}.
  186. */
  187. private static final int STATE_FIRE_CHANNEL_READ = 1 << 8;
  188. private static final int STATE_UNWRAP_REENTRY = 1 << 9;
  189. /**
  190. * <a href="https://tools.ietf.org/html/rfc5246#section-6.2">2^14</a> which is the maximum sized plaintext chunk
  191. * allowed by the TLS RFC.
  192. */
  193. private static final int MAX_PLAINTEXT_LENGTH = 16 * 1024;
  194. private enum SslEngineType {
  195. TCNATIVE(true, COMPOSITE_CUMULATOR) {
  196. @Override
  197. SSLEngineResult unwrap(SslHandler handler, ByteBuf in, int len, ByteBuf out) 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, out.writableBytes());
  210. result = opensslEngine.unwrap(in.nioBuffers(in.readerIndex(), len), handler.singleBuffer);
  211. } finally {
  212. handler.singleBuffer[0] = null;
  213. }
  214. } else {
  215. result = handler.engine.unwrap(toByteBuffer(in, in.readerIndex(), len),
  216. toByteBuffer(out, writerIndex, out.writableBytes()));
  217. }
  218. out.writerIndex(writerIndex + result.bytesProduced());
  219. return result;
  220. }
  221. @Override
  222. ByteBuf allocateWrapBuffer(SslHandler handler, ByteBufAllocator allocator,
  223. int pendingBytes, int numComponents) {
  224. return allocator.directBuffer(((ReferenceCountedOpenSslEngine) handler.engine)
  225. .calculateMaxLengthForWrap(pendingBytes, numComponents));
  226. }
  227. @Override
  228. int calculatePendingData(SslHandler handler, int guess) {
  229. int sslPending = ((ReferenceCountedOpenSslEngine) handler.engine).sslPending();
  230. return sslPending > 0 ? sslPending : guess;
  231. }
  232. @Override
  233. boolean jdkCompatibilityMode(SSLEngine engine) {
  234. return ((ReferenceCountedOpenSslEngine) engine).jdkCompatibilityMode;
  235. }
  236. },
  237. CONSCRYPT(true, COMPOSITE_CUMULATOR) {
  238. @Override
  239. SSLEngineResult unwrap(SslHandler handler, ByteBuf in, int len, ByteBuf out) throws SSLException {
  240. int nioBufferCount = in.nioBufferCount();
  241. int writerIndex = out.writerIndex();
  242. final SSLEngineResult result;
  243. if (nioBufferCount > 1) {
  244. /*
  245. * Use a special unwrap method without additional memory copies.
  246. */
  247. try {
  248. handler.singleBuffer[0] = toByteBuffer(out, writerIndex, out.writableBytes());
  249. result = ((ConscryptAlpnSslEngine) handler.engine).unwrap(
  250. in.nioBuffers(in.readerIndex(), len),
  251. handler.singleBuffer);
  252. } finally {
  253. handler.singleBuffer[0] = null;
  254. }
  255. } else {
  256. result = handler.engine.unwrap(toByteBuffer(in, in.readerIndex(), len),
  257. toByteBuffer(out, writerIndex, out.writableBytes()));
  258. }
  259. out.writerIndex(writerIndex + result.bytesProduced());
  260. return result;
  261. }
  262. @Override
  263. ByteBuf allocateWrapBuffer(SslHandler handler, ByteBufAllocator allocator,
  264. int pendingBytes, int numComponents) {
  265. return allocator.directBuffer(
  266. ((ConscryptAlpnSslEngine) handler.engine).calculateOutNetBufSize(pendingBytes, numComponents));
  267. }
  268. @Override
  269. int calculatePendingData(SslHandler handler, int guess) {
  270. return guess;
  271. }
  272. @Override
  273. boolean jdkCompatibilityMode(SSLEngine engine) {
  274. return true;
  275. }
  276. },
  277. JDK(false, MERGE_CUMULATOR) {
  278. @Override
  279. SSLEngineResult unwrap(SslHandler handler, ByteBuf in, int len, ByteBuf out) throws SSLException {
  280. int writerIndex = out.writerIndex();
  281. ByteBuffer inNioBuffer = toByteBuffer(in, in.readerIndex(), len);
  282. int position = inNioBuffer.position();
  283. final SSLEngineResult result = handler.engine.unwrap(inNioBuffer,
  284. toByteBuffer(out, writerIndex, out.writableBytes()));
  285. out.writerIndex(writerIndex + result.bytesProduced());
  286. // This is a workaround for a bug in Android 5.0. Android 5.0 does not correctly update the
  287. // SSLEngineResult.bytesConsumed() in some cases and just return 0.
  288. //
  289. // See:
  290. // - https://android-review.googlesource.com/c/platform/external/conscrypt/+/122080
  291. // - https://github.com/netty/netty/issues/7758
  292. if (result.bytesConsumed() == 0) {
  293. int consumed = inNioBuffer.position() - position;
  294. if (consumed != result.bytesConsumed()) {
  295. // Create a new SSLEngineResult with the correct bytesConsumed().
  296. return new SSLEngineResult(
  297. result.getStatus(), result.getHandshakeStatus(), consumed, result.bytesProduced());
  298. }
  299. }
  300. return result;
  301. }
  302. @Override
  303. ByteBuf allocateWrapBuffer(SslHandler handler, ByteBufAllocator allocator,
  304. int pendingBytes, int numComponents) {
  305. // As for the JDK SSLEngine we always need to allocate buffers of the size required by the SSLEngine
  306. // (normally ~16KB). This is required even if the amount of data to encrypt is very small. Use heap
  307. // buffers to reduce the native memory usage.
  308. //
  309. // Beside this the JDK SSLEngine also (as of today) will do an extra heap to direct buffer copy
  310. // if a direct buffer is used as its internals operate on byte[].
  311. return allocator.heapBuffer(handler.engine.getSession().getPacketBufferSize());
  312. }
  313. @Override
  314. int calculatePendingData(SslHandler handler, int guess) {
  315. return guess;
  316. }
  317. @Override
  318. boolean jdkCompatibilityMode(SSLEngine engine) {
  319. return true;
  320. }
  321. };
  322. static SslEngineType forEngine(SSLEngine engine) {
  323. return engine instanceof ReferenceCountedOpenSslEngine ? TCNATIVE :
  324. engine instanceof ConscryptAlpnSslEngine ? CONSCRYPT : JDK;
  325. }
  326. SslEngineType(boolean wantsDirectBuffer, Cumulator cumulator) {
  327. this.wantsDirectBuffer = wantsDirectBuffer;
  328. this.cumulator = cumulator;
  329. }
  330. abstract SSLEngineResult unwrap(SslHandler handler, ByteBuf in, int len, ByteBuf out) throws SSLException;
  331. abstract int calculatePendingData(SslHandler handler, int guess);
  332. abstract boolean jdkCompatibilityMode(SSLEngine engine);
  333. abstract ByteBuf allocateWrapBuffer(SslHandler handler, ByteBufAllocator allocator,
  334. int pendingBytes, int numComponents);
  335. // BEGIN Platform-dependent flags
  336. /**
  337. * {@code true} if and only if {@link SSLEngine} expects a direct buffer and so if a heap buffer
  338. * is given will make an extra memory copy.
  339. */
  340. final boolean wantsDirectBuffer;
  341. // END Platform-dependent flags
  342. /**
  343. * When using JDK {@link SSLEngine}, we use {@link #MERGE_CUMULATOR} because it works only with
  344. * one {@link ByteBuffer}.
  345. *
  346. * When using {@link OpenSslEngine}, we can use {@link #COMPOSITE_CUMULATOR} because it has
  347. * {@link OpenSslEngine#unwrap(ByteBuffer[], ByteBuffer[])} which works with multiple {@link ByteBuffer}s
  348. * and which does not need to do extra memory copies.
  349. */
  350. final Cumulator cumulator;
  351. }
  352. private volatile ChannelHandlerContext ctx;
  353. private final SSLEngine engine;
  354. private final SslEngineType engineType;
  355. private final Executor delegatedTaskExecutor;
  356. private final boolean jdkCompatibilityMode;
  357. /**
  358. * Used if {@link SSLEngine#wrap(ByteBuffer[], ByteBuffer)} and {@link SSLEngine#unwrap(ByteBuffer, ByteBuffer[])}
  359. * should be called with a {@link ByteBuf} that is only backed by one {@link ByteBuffer} to reduce the object
  360. * creation.
  361. */
  362. private final ByteBuffer[] singleBuffer = new ByteBuffer[1];
  363. private final boolean startTls;
  364. private final SslTasksRunner sslTaskRunnerForUnwrap = new SslTasksRunner(true);
  365. private final SslTasksRunner sslTaskRunner = new SslTasksRunner(false);
  366. private SslHandlerCoalescingBufferQueue pendingUnencryptedWrites;
  367. private Promise<Channel> handshakePromise = new LazyChannelPromise();
  368. private final LazyChannelPromise sslClosePromise = new LazyChannelPromise();
  369. private int packetLength;
  370. private short state;
  371. private volatile long handshakeTimeoutMillis = 10000;
  372. private volatile long closeNotifyFlushTimeoutMillis = 3000;
  373. private volatile long closeNotifyReadTimeoutMillis;
  374. volatile int wrapDataSize = MAX_PLAINTEXT_LENGTH;
  375. /**
  376. * Creates a new instance which runs all delegated tasks directly on the {@link EventExecutor}.
  377. *
  378. * @param engine the {@link SSLEngine} this handler will use
  379. */
  380. public SslHandler(SSLEngine engine) {
  381. this(engine, false);
  382. }
  383. /**
  384. * Creates a new instance which runs all delegated tasks directly on the {@link EventExecutor}.
  385. *
  386. * @param engine the {@link SSLEngine} this handler will use
  387. * @param startTls {@code true} if the first write request shouldn't be
  388. * encrypted by the {@link SSLEngine}
  389. */
  390. public SslHandler(SSLEngine engine, boolean startTls) {
  391. this(engine, startTls, ImmediateExecutor.INSTANCE);
  392. }
  393. /**
  394. * Creates a new instance.
  395. *
  396. * @param engine the {@link SSLEngine} this handler will use
  397. * @param delegatedTaskExecutor the {@link Executor} that will be used to execute tasks that are returned by
  398. * {@link SSLEngine#getDelegatedTask()}.
  399. */
  400. public SslHandler(SSLEngine engine, Executor delegatedTaskExecutor) {
  401. this(engine, false, delegatedTaskExecutor);
  402. }
  403. /**
  404. * Creates a new instance.
  405. *
  406. * @param engine the {@link SSLEngine} this handler will use
  407. * @param startTls {@code true} if the first write request shouldn't be
  408. * encrypted by the {@link SSLEngine}
  409. * @param delegatedTaskExecutor the {@link Executor} that will be used to execute tasks that are returned by
  410. * {@link SSLEngine#getDelegatedTask()}.
  411. */
  412. public SslHandler(SSLEngine engine, boolean startTls, Executor delegatedTaskExecutor) {
  413. this.engine = ObjectUtil.checkNotNull(engine, "engine");
  414. this.delegatedTaskExecutor = ObjectUtil.checkNotNull(delegatedTaskExecutor, "delegatedTaskExecutor");
  415. engineType = SslEngineType.forEngine(engine);
  416. this.startTls = startTls;
  417. this.jdkCompatibilityMode = engineType.jdkCompatibilityMode(engine);
  418. setCumulator(engineType.cumulator);
  419. }
  420. public long getHandshakeTimeoutMillis() {
  421. return handshakeTimeoutMillis;
  422. }
  423. public void setHandshakeTimeout(long handshakeTimeout, TimeUnit unit) {
  424. checkNotNull(unit, "unit");
  425. setHandshakeTimeoutMillis(unit.toMillis(handshakeTimeout));
  426. }
  427. public void setHandshakeTimeoutMillis(long handshakeTimeoutMillis) {
  428. this.handshakeTimeoutMillis = checkPositiveOrZero(handshakeTimeoutMillis, "handshakeTimeoutMillis");
  429. }
  430. /**
  431. * Sets the number of bytes to pass to each {@link SSLEngine#wrap(ByteBuffer[], int, int, ByteBuffer)} call.
  432. * <p>
  433. * This value will partition data which is passed to write
  434. * {@link #write(ChannelHandlerContext, Object, ChannelPromise)}. The partitioning will work as follows:
  435. * <ul>
  436. * <li>If {@code wrapDataSize <= 0} then we will write each data chunk as is.</li>
  437. * <li>If {@code wrapDataSize > data size} then we will attempt to aggregate multiple data chunks together.</li>
  438. * <li>If {@code wrapDataSize > data size} Else if {@code wrapDataSize <= data size} then we will divide the data
  439. * into chunks of {@code wrapDataSize} when writing.</li>
  440. * </ul>
  441. * <p>
  442. * If the {@link SSLEngine} doesn't support a gather wrap operation (e.g. {@link SslProvider#OPENSSL}) then
  443. * aggregating data before wrapping can help reduce the ratio between TLS overhead vs data payload which will lead
  444. * to better goodput. Writing fixed chunks of data can also help target the underlying transport's (e.g. TCP)
  445. * frame size. Under lossy/congested network conditions this may help the peer get full TLS packets earlier and
  446. * be able to do work sooner, as opposed to waiting for the all the pieces of the TLS packet to arrive.
  447. * @param wrapDataSize the number of bytes which will be passed to each
  448. * {@link SSLEngine#wrap(ByteBuffer[], int, int, ByteBuffer)} call.
  449. */
  450. @UnstableApi
  451. public final void setWrapDataSize(int wrapDataSize) {
  452. this.wrapDataSize = wrapDataSize;
  453. }
  454. /**
  455. * @deprecated use {@link #getCloseNotifyFlushTimeoutMillis()}
  456. */
  457. @Deprecated
  458. public long getCloseNotifyTimeoutMillis() {
  459. return getCloseNotifyFlushTimeoutMillis();
  460. }
  461. /**
  462. * @deprecated use {@link #setCloseNotifyFlushTimeout(long, TimeUnit)}
  463. */
  464. @Deprecated
  465. public void setCloseNotifyTimeout(long closeNotifyTimeout, TimeUnit unit) {
  466. setCloseNotifyFlushTimeout(closeNotifyTimeout, unit);
  467. }
  468. /**
  469. * @deprecated use {@link #setCloseNotifyFlushTimeoutMillis(long)}
  470. */
  471. @Deprecated
  472. public void setCloseNotifyTimeoutMillis(long closeNotifyFlushTimeoutMillis) {
  473. setCloseNotifyFlushTimeoutMillis(closeNotifyFlushTimeoutMillis);
  474. }
  475. /**
  476. * Gets the timeout for flushing the close_notify that was triggered by closing the
  477. * {@link Channel}. If the close_notify was not flushed in the given timeout the {@link Channel} will be closed
  478. * forcibly.
  479. */
  480. public final long getCloseNotifyFlushTimeoutMillis() {
  481. return closeNotifyFlushTimeoutMillis;
  482. }
  483. /**
  484. * Sets the timeout for flushing the close_notify that was triggered by closing the
  485. * {@link Channel}. If the close_notify was not flushed in the given timeout the {@link Channel} will be closed
  486. * forcibly.
  487. */
  488. public final void setCloseNotifyFlushTimeout(long closeNotifyFlushTimeout, TimeUnit unit) {
  489. setCloseNotifyFlushTimeoutMillis(unit.toMillis(closeNotifyFlushTimeout));
  490. }
  491. /**
  492. * See {@link #setCloseNotifyFlushTimeout(long, TimeUnit)}.
  493. */
  494. public final void setCloseNotifyFlushTimeoutMillis(long closeNotifyFlushTimeoutMillis) {
  495. this.closeNotifyFlushTimeoutMillis = checkPositiveOrZero(closeNotifyFlushTimeoutMillis,
  496. "closeNotifyFlushTimeoutMillis");
  497. }
  498. /**
  499. * Gets the timeout (in ms) for receiving the response for the close_notify that was triggered by closing the
  500. * {@link Channel}. This timeout starts after the close_notify message was successfully written to the
  501. * remote peer. Use {@code 0} to directly close the {@link Channel} and not wait for the response.
  502. */
  503. public final long getCloseNotifyReadTimeoutMillis() {
  504. return closeNotifyReadTimeoutMillis;
  505. }
  506. /**
  507. * Sets the timeout for receiving the response for the close_notify that was triggered by closing the
  508. * {@link Channel}. This timeout starts after the close_notify message was successfully written to the
  509. * remote peer. Use {@code 0} to directly close the {@link Channel} and not wait for the response.
  510. */
  511. public final void setCloseNotifyReadTimeout(long closeNotifyReadTimeout, TimeUnit unit) {
  512. setCloseNotifyReadTimeoutMillis(unit.toMillis(closeNotifyReadTimeout));
  513. }
  514. /**
  515. * See {@link #setCloseNotifyReadTimeout(long, TimeUnit)}.
  516. */
  517. public final void setCloseNotifyReadTimeoutMillis(long closeNotifyReadTimeoutMillis) {
  518. this.closeNotifyReadTimeoutMillis = checkPositiveOrZero(closeNotifyReadTimeoutMillis,
  519. "closeNotifyReadTimeoutMillis");
  520. }
  521. /**
  522. * Returns the {@link SSLEngine} which is used by this handler.
  523. */
  524. public SSLEngine engine() {
  525. return engine;
  526. }
  527. /**
  528. * Returns the name of the current application-level protocol.
  529. *
  530. * @return the protocol name or {@code null} if application-level protocol has not been negotiated
  531. */
  532. public String applicationProtocol() {
  533. SSLEngine engine = engine();
  534. if (!(engine instanceof ApplicationProtocolAccessor)) {
  535. return null;
  536. }
  537. return ((ApplicationProtocolAccessor) engine).getNegotiatedApplicationProtocol();
  538. }
  539. /**
  540. * Returns a {@link Future} that will get notified once the current TLS handshake completes.
  541. *
  542. * @return the {@link Future} for the initial TLS handshake if {@link #renegotiate()} was not invoked.
  543. * The {@link Future} for the most recent {@linkplain #renegotiate() TLS renegotiation} otherwise.
  544. */
  545. public Future<Channel> handshakeFuture() {
  546. return handshakePromise;
  547. }
  548. /**
  549. * Use {@link #closeOutbound()}
  550. */
  551. @Deprecated
  552. public ChannelFuture close() {
  553. return closeOutbound();
  554. }
  555. /**
  556. * Use {@link #closeOutbound(ChannelPromise)}
  557. */
  558. @Deprecated
  559. public ChannelFuture close(ChannelPromise promise) {
  560. return closeOutbound(promise);
  561. }
  562. /**
  563. * Sends an SSL {@code close_notify} message to the specified channel and
  564. * destroys the underlying {@link SSLEngine}. This will <strong>not</strong> close the underlying
  565. * {@link Channel}. If you want to also close the {@link Channel} use {@link Channel#close()} or
  566. * {@link ChannelHandlerContext#close()}
  567. */
  568. public ChannelFuture closeOutbound() {
  569. return closeOutbound(ctx.newPromise());
  570. }
  571. /**
  572. * Sends an SSL {@code close_notify} message to the specified channel and
  573. * destroys the underlying {@link SSLEngine}. This will <strong>not</strong> close the underlying
  574. * {@link Channel}. If you want to also close the {@link Channel} use {@link Channel#close()} or
  575. * {@link ChannelHandlerContext#close()}
  576. */
  577. public ChannelFuture closeOutbound(final ChannelPromise promise) {
  578. final ChannelHandlerContext ctx = this.ctx;
  579. if (ctx.executor().inEventLoop()) {
  580. closeOutbound0(promise);
  581. } else {
  582. ctx.executor().execute(new Runnable() {
  583. @Override
  584. public void run() {
  585. closeOutbound0(promise);
  586. }
  587. });
  588. }
  589. return promise;
  590. }
  591. private void closeOutbound0(ChannelPromise promise) {
  592. setState(STATE_OUTBOUND_CLOSED);
  593. engine.closeOutbound();
  594. try {
  595. flush(ctx, promise);
  596. } catch (Exception e) {
  597. if (!promise.tryFailure(e)) {
  598. logger.warn("{} flush() raised a masked exception.", ctx.channel(), e);
  599. }
  600. }
  601. }
  602. /**
  603. * Return the {@link Future} that will get notified if the inbound of the {@link SSLEngine} is closed.
  604. *
  605. * This method will return the same {@link Future} all the time.
  606. *
  607. * @see SSLEngine
  608. */
  609. public Future<Channel> sslCloseFuture() {
  610. return sslClosePromise;
  611. }
  612. @Override
  613. public void handlerRemoved0(ChannelHandlerContext ctx) throws Exception {
  614. try {
  615. if (!pendingUnencryptedWrites.isEmpty()) {
  616. // Check if queue is not empty first because create a new ChannelException is expensive
  617. pendingUnencryptedWrites.releaseAndFailAll(ctx,
  618. new ChannelException("Pending write on removal of SslHandler"));
  619. }
  620. pendingUnencryptedWrites = null;
  621. SSLHandshakeException cause = null;
  622. // If the handshake is not done yet we should fail the handshake promise and notify the rest of the
  623. // pipeline.
  624. if (!handshakePromise.isDone()) {
  625. cause = new SSLHandshakeException("SslHandler removed before handshake completed");
  626. if (handshakePromise.tryFailure(cause)) {
  627. ctx.fireUserEventTriggered(new SslHandshakeCompletionEvent(cause));
  628. }
  629. }
  630. if (!sslClosePromise.isDone()) {
  631. if (cause == null) {
  632. cause = new SSLHandshakeException("SslHandler removed before handshake completed");
  633. }
  634. notifyClosePromise(cause);
  635. }
  636. } finally {
  637. ReferenceCountUtil.release(engine);
  638. }
  639. }
  640. @Override
  641. public void bind(ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise) throws Exception {
  642. ctx.bind(localAddress, promise);
  643. }
  644. @Override
  645. public void connect(ChannelHandlerContext ctx, SocketAddress remoteAddress, SocketAddress localAddress,
  646. ChannelPromise promise) throws Exception {
  647. ctx.connect(remoteAddress, localAddress, promise);
  648. }
  649. @Override
  650. public void deregister(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {
  651. ctx.deregister(promise);
  652. }
  653. @Override
  654. public void disconnect(final ChannelHandlerContext ctx,
  655. final ChannelPromise promise) throws Exception {
  656. closeOutboundAndChannel(ctx, promise, true);
  657. }
  658. @Override
  659. public void close(final ChannelHandlerContext ctx,
  660. final ChannelPromise promise) throws Exception {
  661. closeOutboundAndChannel(ctx, promise, false);
  662. }
  663. @Override
  664. public void read(ChannelHandlerContext ctx) throws Exception {
  665. if (!handshakePromise.isDone()) {
  666. setState(STATE_READ_DURING_HANDSHAKE);
  667. }
  668. ctx.read();
  669. }
  670. private static IllegalStateException newPendingWritesNullException() {
  671. return new IllegalStateException("pendingUnencryptedWrites is null, handlerRemoved0 called?");
  672. }
  673. @Override
  674. public void write(final ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
  675. if (!(msg instanceof ByteBuf)) {
  676. UnsupportedMessageTypeException exception = new UnsupportedMessageTypeException(msg, ByteBuf.class);
  677. ReferenceCountUtil.safeRelease(msg);
  678. promise.setFailure(exception);
  679. } else if (pendingUnencryptedWrites == null) {
  680. ReferenceCountUtil.safeRelease(msg);
  681. promise.setFailure(newPendingWritesNullException());
  682. } else {
  683. pendingUnencryptedWrites.add((ByteBuf) msg, promise);
  684. }
  685. }
  686. @Override
  687. public void flush(ChannelHandlerContext ctx) throws Exception {
  688. // Do not encrypt the first write request if this handler is
  689. // created with startTLS flag turned on.
  690. if (startTls && !isStateSet(STATE_SENT_FIRST_MESSAGE)) {
  691. setState(STATE_SENT_FIRST_MESSAGE);
  692. pendingUnencryptedWrites.writeAndRemoveAll(ctx);
  693. forceFlush(ctx);
  694. // Explicit start handshake processing once we send the first message. This will also ensure
  695. // we will schedule the timeout if needed.
  696. startHandshakeProcessing(true);
  697. return;
  698. }
  699. if (isStateSet(STATE_PROCESS_TASK)) {
  700. return;
  701. }
  702. try {
  703. wrapAndFlush(ctx);
  704. } catch (Throwable cause) {
  705. setHandshakeFailure(ctx, cause);
  706. PlatformDependent.throwException(cause);
  707. }
  708. }
  709. private void wrapAndFlush(ChannelHandlerContext ctx) throws SSLException {
  710. if (pendingUnencryptedWrites.isEmpty()) {
  711. // It's important to NOT use a voidPromise here as the user
  712. // may want to add a ChannelFutureListener to the ChannelPromise later.
  713. //
  714. // See https://github.com/netty/netty/issues/3364
  715. pendingUnencryptedWrites.add(Unpooled.EMPTY_BUFFER, ctx.newPromise());
  716. }
  717. if (!handshakePromise.isDone()) {
  718. setState(STATE_FLUSHED_BEFORE_HANDSHAKE);
  719. }
  720. try {
  721. wrap(ctx, false);
  722. } finally {
  723. // We may have written some parts of data before an exception was thrown so ensure we always flush.
  724. // See https://github.com/netty/netty/issues/3900#issuecomment-172481830
  725. forceFlush(ctx);
  726. }
  727. }
  728. // This method will not call setHandshakeFailure(...) !
  729. private void wrap(ChannelHandlerContext ctx, boolean inUnwrap) throws SSLException {
  730. ByteBuf out = null;
  731. ByteBufAllocator alloc = ctx.alloc();
  732. try {
  733. final int wrapDataSize = this.wrapDataSize;
  734. // Only continue to loop if the handler was not removed in the meantime.
  735. // See https://github.com/netty/netty/issues/5860
  736. outer: while (!ctx.isRemoved()) {
  737. ChannelPromise promise = ctx.newPromise();
  738. ByteBuf buf = wrapDataSize > 0 ?
  739. pendingUnencryptedWrites.remove(alloc, wrapDataSize, promise) :
  740. pendingUnencryptedWrites.removeFirst(promise);
  741. if (buf == null) {
  742. break;
  743. }
  744. if (out == null) {
  745. out = allocateOutNetBuf(ctx, buf.readableBytes(), buf.nioBufferCount());
  746. }
  747. SSLEngineResult result = wrap(alloc, engine, buf, out);
  748. if (buf.isReadable()) {
  749. pendingUnencryptedWrites.addFirst(buf, promise);
  750. // When we add the buffer/promise pair back we need to be sure we don't complete the promise
  751. // later. We only complete the promise if the buffer is completely consumed.
  752. promise = null;
  753. } else {
  754. buf.release();
  755. }
  756. // We need to write any data before we invoke any methods which may trigger re-entry, otherwise
  757. // writes may occur out of order and TLS sequencing may be off (e.g. SSLV3_ALERT_BAD_RECORD_MAC).
  758. if (out.isReadable()) {
  759. final ByteBuf b = out;
  760. out = null;
  761. if (promise != null) {
  762. ctx.write(b, promise);
  763. } else {
  764. ctx.write(b);
  765. }
  766. } else if (promise != null) {
  767. ctx.write(Unpooled.EMPTY_BUFFER, promise);
  768. }
  769. // else out is not readable we can re-use it and so save an extra allocation
  770. if (result.getStatus() == Status.CLOSED) {
  771. // Make a best effort to preserve any exception that way previously encountered from the handshake
  772. // or the transport, else fallback to a general error.
  773. Throwable exception = handshakePromise.cause();
  774. if (exception == null) {
  775. exception = sslClosePromise.cause();
  776. if (exception == null) {
  777. exception = new SslClosedEngineException("SSLEngine closed already");
  778. }
  779. }
  780. pendingUnencryptedWrites.releaseAndFailAll(ctx, exception);
  781. return;
  782. } else {
  783. switch (result.getHandshakeStatus()) {
  784. case NEED_TASK:
  785. if (!runDelegatedTasks(inUnwrap)) {
  786. // We scheduled a task on the delegatingTaskExecutor, so stop processing as we will
  787. // resume once the task completes.
  788. break outer;
  789. }
  790. break;
  791. case FINISHED:
  792. case NOT_HANDSHAKING: // work around for android bug that skips the FINISHED state.
  793. setHandshakeSuccess();
  794. break;
  795. case NEED_WRAP:
  796. // If we are expected to wrap again and we produced some data we need to ensure there
  797. // is something in the queue to process as otherwise we will not try again before there
  798. // was more added. Failing to do so may fail to produce an alert that can be
  799. // consumed by the remote peer.
  800. if (result.bytesProduced() > 0 && pendingUnencryptedWrites.isEmpty()) {
  801. pendingUnencryptedWrites.add(Unpooled.EMPTY_BUFFER);
  802. }
  803. break;
  804. case NEED_UNWRAP:
  805. // The underlying engine is starving so we need to feed it with more data.
  806. // See https://github.com/netty/netty/pull/5039
  807. readIfNeeded(ctx);
  808. return;
  809. default:
  810. throw new IllegalStateException(
  811. "Unknown handshake status: " + result.getHandshakeStatus());
  812. }
  813. }
  814. }
  815. } finally {
  816. if (out != null) {
  817. out.release();
  818. }
  819. if (inUnwrap) {
  820. setState(STATE_NEEDS_FLUSH);
  821. }
  822. }
  823. }
  824. /**
  825. * This method will not call
  826. * {@link #setHandshakeFailure(ChannelHandlerContext, Throwable, boolean, boolean, boolean)} or
  827. * {@link #setHandshakeFailure(ChannelHandlerContext, Throwable)}.
  828. * @return {@code true} if this method ends on {@link SSLEngineResult.HandshakeStatus#NOT_HANDSHAKING}.
  829. */
  830. private boolean wrapNonAppData(final ChannelHandlerContext ctx, boolean inUnwrap) throws SSLException {
  831. ByteBuf out = null;
  832. ByteBufAllocator alloc = ctx.alloc();
  833. try {
  834. // Only continue to loop if the handler was not removed in the meantime.
  835. // See https://github.com/netty/netty/issues/5860
  836. outer: while (!ctx.isRemoved()) {
  837. if (out == null) {
  838. // As this is called for the handshake we have no real idea how big the buffer needs to be.
  839. // That said 2048 should give us enough room to include everything like ALPN / NPN data.
  840. // If this is not enough we will increase the buffer in wrap(...).
  841. out = allocateOutNetBuf(ctx, 2048, 1);
  842. }
  843. SSLEngineResult result = wrap(alloc, engine, Unpooled.EMPTY_BUFFER, out);
  844. if (result.bytesProduced() > 0) {
  845. ctx.write(out).addListener(new ChannelFutureListener() {
  846. @Override
  847. public void operationComplete(ChannelFuture future) {
  848. Throwable cause = future.cause();
  849. if (cause != null) {
  850. setHandshakeFailureTransportFailure(ctx, cause);
  851. }
  852. }
  853. });
  854. if (inUnwrap) {
  855. setState(STATE_NEEDS_FLUSH);
  856. }
  857. out = null;
  858. }
  859. HandshakeStatus status = result.getHandshakeStatus();
  860. switch (status) {
  861. case FINISHED:
  862. // We may be here because we read data and discovered the remote peer initiated a renegotiation
  863. // and this write is to complete the new handshake. The user may have previously done a
  864. // writeAndFlush which wasn't able to wrap data due to needing the pending handshake, so we
  865. // attempt to wrap application data here if any is pending.
  866. if (setHandshakeSuccess() && inUnwrap && !pendingUnencryptedWrites.isEmpty()) {
  867. wrap(ctx, true);
  868. }
  869. return false;
  870. case NEED_TASK:
  871. if (!runDelegatedTasks(inUnwrap)) {
  872. // We scheduled a task on the delegatingTaskExecutor, so stop processing as we will
  873. // resume once the task completes.
  874. break outer;
  875. }
  876. break;
  877. case NEED_UNWRAP:
  878. if (inUnwrap || unwrapNonAppData(ctx) <= 0) {
  879. // If we asked for a wrap, the engine requested an unwrap, and we are in unwrap there is
  880. // no use in trying to call wrap again because we have already attempted (or will after we
  881. // return) to feed more data to the engine.
  882. return false;
  883. }
  884. break;
  885. case NEED_WRAP:
  886. break;
  887. case NOT_HANDSHAKING:
  888. if (setHandshakeSuccess() && inUnwrap && !pendingUnencryptedWrites.isEmpty()) {
  889. wrap(ctx, true);
  890. }
  891. // Workaround for TLS False Start problem reported at:
  892. // https://github.com/netty/netty/issues/1108#issuecomment-14266970
  893. if (!inUnwrap) {
  894. unwrapNonAppData(ctx);
  895. }
  896. return true;
  897. default:
  898. throw new IllegalStateException("Unknown handshake status: " + result.getHandshakeStatus());
  899. }
  900. // Check if did not produce any bytes and if so break out of the loop, but only if we did not process
  901. // a task as last action. It's fine to not produce any data as part of executing a task.
  902. if (result.bytesProduced() == 0 && status != HandshakeStatus.NEED_TASK) {
  903. break;
  904. }
  905. // It should not consume empty buffers when it is not handshaking
  906. // Fix for Android, where it was encrypting empty buffers even when not handshaking
  907. if (result.bytesConsumed() == 0 && result.getHandshakeStatus() == HandshakeStatus.NOT_HANDSHAKING) {
  908. break;
  909. }
  910. }
  911. } finally {
  912. if (out != null) {
  913. out.release();
  914. }
  915. }
  916. return false;
  917. }
  918. private SSLEngineResult wrap(ByteBufAllocator alloc, SSLEngine engine, ByteBuf in, ByteBuf out)
  919. throws SSLException {
  920. ByteBuf newDirectIn = null;
  921. try {
  922. int readerIndex = in.readerIndex();
  923. int readableBytes = in.readableBytes();
  924. // We will call SslEngine.wrap(ByteBuffer[], ByteBuffer) to allow efficient handling of
  925. // CompositeByteBuf without force an extra memory copy when CompositeByteBuffer.nioBuffer() is called.
  926. final ByteBuffer[] in0;
  927. if (in.isDirect() || !engineType.wantsDirectBuffer) {
  928. // As CompositeByteBuf.nioBufferCount() can be expensive (as it needs to check all composed ByteBuf
  929. // to calculate the count) we will just assume a CompositeByteBuf contains more then 1 ByteBuf.
  930. // The worst that can happen is that we allocate an extra ByteBuffer[] in CompositeByteBuf.nioBuffers()
  931. // which is better then walking the composed ByteBuf in most cases.
  932. if (!(in instanceof CompositeByteBuf) && in.nioBufferCount() == 1) {
  933. in0 = singleBuffer;
  934. // We know its only backed by 1 ByteBuffer so use internalNioBuffer to keep object allocation
  935. // to a minimum.
  936. in0[0] = in.internalNioBuffer(readerIndex, readableBytes);
  937. } else {
  938. in0 = in.nioBuffers();
  939. }
  940. } else {
  941. // We could even go further here and check if its a CompositeByteBuf and if so try to decompose it and
  942. // only replace the ByteBuffer that are not direct. At the moment we just will replace the whole
  943. // CompositeByteBuf to keep the complexity to a minimum
  944. newDirectIn = alloc.directBuffer(readableBytes);
  945. newDirectIn.writeBytes(in, readerIndex, readableBytes);
  946. in0 = singleBuffer;
  947. in0[0] = newDirectIn.internalNioBuffer(newDirectIn.readerIndex(), readableBytes);
  948. }
  949. for (;;) {
  950. ByteBuffer out0 = out.nioBuffer(out.writerIndex(), out.writableBytes());
  951. SSLEngineResult result = engine.wrap(in0, out0);
  952. in.skipBytes(result.bytesConsumed());
  953. out.writerIndex(out.writerIndex() + result.bytesProduced());
  954. if (result.getStatus() == Status.BUFFER_OVERFLOW) {
  955. out.ensureWritable(engine.getSession().getPacketBufferSize());
  956. } else {
  957. return result;
  958. }
  959. }
  960. } finally {
  961. // Null out to allow GC of ByteBuffer
  962. singleBuffer[0] = null;
  963. if (newDirectIn != null) {
  964. newDirectIn.release();
  965. }
  966. }
  967. }
  968. @Override
  969. public void channelInactive(ChannelHandlerContext ctx) throws Exception {
  970. boolean handshakeFailed = handshakePromise.cause() != null;
  971. ClosedChannelException exception = new ClosedChannelException();
  972. // Make sure to release SSLEngine,
  973. // and notify the handshake future if the connection has been closed during handshake.
  974. setHandshakeFailure(ctx, exception, !isStateSet(STATE_OUTBOUND_CLOSED), isStateSet(STATE_HANDSHAKE_STARTED),
  975. false);
  976. // Ensure we always notify the sslClosePromise as well
  977. notifyClosePromise(exception);
  978. try {
  979. super.channelInactive(ctx);
  980. } catch (DecoderException e) {
  981. if (!handshakeFailed || !(e.getCause() instanceof SSLException)) {
  982. // We only rethrow the exception if the handshake did not fail before channelInactive(...) was called
  983. // as otherwise this may produce duplicated failures as super.channelInactive(...) will also call
  984. // channelRead(...).
  985. //
  986. // See https://github.com/netty/netty/issues/10119
  987. throw e;
  988. }
  989. }
  990. }
  991. @Override
  992. public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
  993. if (ignoreException(cause)) {
  994. // It is safe to ignore the 'connection reset by peer' or
  995. // 'broken pipe' error after sending close_notify.
  996. if (logger.isDebugEnabled()) {
  997. logger.debug(
  998. "{} Swallowing a harmless 'connection reset by peer / broken pipe' error that occurred " +
  999. "while writing close_notify in response to the peer's close_notify", ctx.channel(), cause);
  1000. }
  1001. // Close the connection explicitly just in case the transport
  1002. // did not close the connection automatically.
  1003. if (ctx.channel().isActive()) {
  1004. ctx.close();
  1005. }
  1006. } else {
  1007. ctx.fireExceptionCaught(cause);
  1008. }
  1009. }
  1010. /**
  1011. * Checks if the given {@link Throwable} can be ignore and just "swallowed"
  1012. *
  1013. * When an ssl connection is closed a close_notify message is sent.
  1014. * After that the peer also sends close_notify however, it's not mandatory to receive
  1015. * the close_notify. The party who sent the initial close_notify …

Large files files are truncated, but you can click here to view the full file