rev 52979 : 8215281: Use String.isEmpty() when applicable in java.base
Reviewed-by: TBD

   1 /*
   2  * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.security.ssl;
  27 
  28 import java.io.EOFException;
  29 import java.io.IOException;
  30 import java.io.InputStream;
  31 import java.io.InterruptedIOException;
  32 import java.io.OutputStream;
  33 import java.net.InetAddress;
  34 import java.net.InetSocketAddress;
  35 import java.net.Socket;
  36 import java.net.SocketAddress;
  37 import java.net.SocketException;
  38 import java.net.UnknownHostException;
  39 import java.nio.ByteBuffer;
  40 import java.util.List;
  41 import java.util.function.BiFunction;
  42 import javax.net.ssl.HandshakeCompletedListener;
  43 import javax.net.ssl.SSLException;
  44 import javax.net.ssl.SSLHandshakeException;
  45 import javax.net.ssl.SSLParameters;
  46 import javax.net.ssl.SSLProtocolException;
  47 import javax.net.ssl.SSLServerSocket;
  48 import javax.net.ssl.SSLSession;
  49 import javax.net.ssl.SSLSocket;
  50 import jdk.internal.access.JavaNetInetAddressAccess;
  51 import jdk.internal.access.SharedSecrets;
  52 
  53 /**
  54  * Implementation of an SSL socket.
  55  * <P>
  56  * This is a normal connection type socket, implementing SSL over some lower
  57  * level socket, such as TCP.  Because it is layered over some lower level
  58  * socket, it MUST override all default socket methods.
  59  * <P>
  60  * This API offers a non-traditional option for establishing SSL
  61  * connections.  You may first establish the connection directly, then pass
  62  * that connection to the SSL socket constructor with a flag saying which
  63  * role should be taken in the handshake protocol.  (The two ends of the
  64  * connection must not choose the same role!)  This allows setup of SSL
  65  * proxying or tunneling, and also allows the kind of "role reversal"
  66  * that is required for most FTP data transfers.
  67  *
  68  * @see javax.net.ssl.SSLSocket
  69  * @see SSLServerSocket
  70  *
  71  * @author David Brownell
  72  */
  73 public final class SSLSocketImpl
  74         extends BaseSSLSocketImpl implements SSLTransport {
  75 
  76     final SSLContextImpl            sslContext;
  77     final TransportContext          conContext;
  78 
  79     private final AppInputStream    appInput = new AppInputStream();
  80     private final AppOutputStream   appOutput = new AppOutputStream();
  81 
  82     private String                  peerHost;
  83     private boolean                 autoClose;
  84     private boolean                 isConnected = false;
  85     private volatile boolean        tlsIsClosed = false;
  86 
  87     /*
  88      * Is the local name service trustworthy?
  89      *
  90      * If the local name service is not trustworthy, reverse host name
  91      * resolution should not be performed for endpoint identification.
  92      */
  93     private static final boolean trustNameService =
  94             Utilities.getBooleanProperty("jdk.tls.trustNameService", false);
  95 
  96     /**
  97      * Package-private constructor used to instantiate an unconnected
  98      * socket.
  99      *
 100      * This instance is meant to set handshake state to use "client mode".
 101      */
 102     SSLSocketImpl(SSLContextImpl sslContext) {
 103         super();
 104         this.sslContext = sslContext;
 105         HandshakeHash handshakeHash = new HandshakeHash();
 106         this.conContext = new TransportContext(sslContext, this,
 107                 new SSLSocketInputRecord(handshakeHash),
 108                 new SSLSocketOutputRecord(handshakeHash), true);
 109     }
 110 
 111     /**
 112      * Package-private constructor used to instantiate a server socket.
 113      *
 114      * This instance is meant to set handshake state to use "server mode".
 115      */
 116     SSLSocketImpl(SSLContextImpl sslContext, SSLConfiguration sslConfig) {
 117         super();
 118         this.sslContext = sslContext;
 119         HandshakeHash handshakeHash = new HandshakeHash();
 120         this.conContext = new TransportContext(sslContext, this, sslConfig,
 121                 new SSLSocketInputRecord(handshakeHash),
 122                 new SSLSocketOutputRecord(handshakeHash));
 123     }
 124 
 125     /**
 126      * Constructs an SSL connection to a named host at a specified
 127      * port, using the authentication context provided.
 128      *
 129      * This endpoint acts as the client, and may rejoin an existing SSL session
 130      * if appropriate.
 131      */
 132     SSLSocketImpl(SSLContextImpl sslContext, String peerHost,
 133             int peerPort) throws IOException, UnknownHostException {
 134         super();
 135         this.sslContext = sslContext;
 136         HandshakeHash handshakeHash = new HandshakeHash();
 137         this.conContext = new TransportContext(sslContext, this,
 138                 new SSLSocketInputRecord(handshakeHash),
 139                 new SSLSocketOutputRecord(handshakeHash), true);
 140         this.peerHost = peerHost;
 141         SocketAddress socketAddress =
 142                peerHost != null ? new InetSocketAddress(peerHost, peerPort) :
 143                new InetSocketAddress(InetAddress.getByName(null), peerPort);
 144         connect(socketAddress, 0);
 145     }
 146 
 147     /**
 148      * Constructs an SSL connection to a server at a specified
 149      * address, and TCP port, using the authentication context
 150      * provided.
 151      *
 152      * This endpoint acts as the client, and may rejoin an existing SSL
 153      * session if appropriate.
 154      */
 155     SSLSocketImpl(SSLContextImpl sslContext,
 156             InetAddress address, int peerPort) throws IOException {
 157         super();
 158         this.sslContext = sslContext;
 159         HandshakeHash handshakeHash = new HandshakeHash();
 160         this.conContext = new TransportContext(sslContext, this,
 161                 new SSLSocketInputRecord(handshakeHash),
 162                 new SSLSocketOutputRecord(handshakeHash), true);
 163 
 164         SocketAddress socketAddress = new InetSocketAddress(address, peerPort);
 165         connect(socketAddress, 0);
 166     }
 167 
 168     /**
 169      * Constructs an SSL connection to a named host at a specified
 170      * port, using the authentication context provided.
 171      *
 172      * This endpoint acts as the client, and may rejoin an existing SSL
 173      * session if appropriate.
 174      */
 175     SSLSocketImpl(SSLContextImpl sslContext,
 176             String peerHost, int peerPort, InetAddress localAddr,
 177             int localPort) throws IOException, UnknownHostException {
 178         super();
 179         this.sslContext = sslContext;
 180         HandshakeHash handshakeHash = new HandshakeHash();
 181         this.conContext = new TransportContext(sslContext, this,
 182                 new SSLSocketInputRecord(handshakeHash),
 183                 new SSLSocketOutputRecord(handshakeHash), true);
 184         this.peerHost = peerHost;
 185 
 186         bind(new InetSocketAddress(localAddr, localPort));
 187         SocketAddress socketAddress =
 188                peerHost != null ? new InetSocketAddress(peerHost, peerPort) :
 189                new InetSocketAddress(InetAddress.getByName(null), peerPort);
 190         connect(socketAddress, 0);
 191     }
 192 
 193     /**
 194      * Constructs an SSL connection to a server at a specified
 195      * address, and TCP port, using the authentication context
 196      * provided.
 197      *
 198      * This endpoint acts as the client, and may rejoin an existing SSL
 199      * session if appropriate.
 200      */
 201     SSLSocketImpl(SSLContextImpl sslContext,
 202             InetAddress peerAddr, int peerPort,
 203             InetAddress localAddr, int localPort) throws IOException {
 204         super();
 205         this.sslContext = sslContext;
 206         HandshakeHash handshakeHash = new HandshakeHash();
 207         this.conContext = new TransportContext(sslContext, this,
 208                 new SSLSocketInputRecord(handshakeHash),
 209                 new SSLSocketOutputRecord(handshakeHash), true);
 210 
 211         bind(new InetSocketAddress(localAddr, localPort));
 212         SocketAddress socketAddress = new InetSocketAddress(peerAddr, peerPort);
 213         connect(socketAddress, 0);
 214     }
 215 
 216     /**
 217      * Creates a server mode {@link Socket} layered over an
 218      * existing connected socket, and is able to read data which has
 219      * already been consumed/removed from the {@link Socket}'s
 220      * underlying {@link InputStream}.
 221      */
 222     SSLSocketImpl(SSLContextImpl sslContext, Socket sock,
 223             InputStream consumed, boolean autoClose) throws IOException {
 224         super(sock, consumed);
 225         // We always layer over a connected socket
 226         if (!sock.isConnected()) {
 227             throw new SocketException("Underlying socket is not connected");
 228         }
 229 
 230         this.sslContext = sslContext;
 231         HandshakeHash handshakeHash = new HandshakeHash();
 232         this.conContext = new TransportContext(sslContext, this,
 233                 new SSLSocketInputRecord(handshakeHash),
 234                 new SSLSocketOutputRecord(handshakeHash), false);
 235         this.autoClose = autoClose;
 236         doneConnect();
 237     }
 238 
 239     /**
 240      * Layer SSL traffic over an existing connection, rather than
 241      * creating a new connection.
 242      *
 243      * The existing connection may be used only for SSL traffic (using this
 244      * SSLSocket) until the SSLSocket.close() call returns. However, if a
 245      * protocol error is detected, that existing connection is automatically
 246      * closed.
 247      * <p>
 248      * This particular constructor always uses the socket in the
 249      * role of an SSL client. It may be useful in cases which start
 250      * using SSL after some initial data transfers, for example in some
 251      * SSL tunneling applications or as part of some kinds of application
 252      * protocols which negotiate use of a SSL based security.
 253      */
 254     SSLSocketImpl(SSLContextImpl sslContext, Socket sock,
 255             String peerHost, int port, boolean autoClose) throws IOException {
 256         super(sock);
 257         // We always layer over a connected socket
 258         if (!sock.isConnected()) {
 259             throw new SocketException("Underlying socket is not connected");
 260         }
 261 
 262         this.sslContext = sslContext;
 263         HandshakeHash handshakeHash = new HandshakeHash();
 264         this.conContext = new TransportContext(sslContext, this,
 265                 new SSLSocketInputRecord(handshakeHash),
 266                 new SSLSocketOutputRecord(handshakeHash), true);
 267         this.peerHost = peerHost;
 268         this.autoClose = autoClose;
 269         doneConnect();
 270     }
 271 
 272     @Override
 273     public void connect(SocketAddress endpoint,
 274             int timeout) throws IOException {
 275 
 276         if (isLayered()) {
 277             throw new SocketException("Already connected");
 278         }
 279 
 280         if (!(endpoint instanceof InetSocketAddress)) {
 281             throw new SocketException(
 282                     "Cannot handle non-Inet socket addresses.");
 283         }
 284 
 285         super.connect(endpoint, timeout);
 286         doneConnect();
 287     }
 288 
 289     @Override
 290     public String[] getSupportedCipherSuites() {
 291         return CipherSuite.namesOf(sslContext.getSupportedCipherSuites());
 292     }
 293 
 294     @Override
 295     public synchronized String[] getEnabledCipherSuites() {
 296         return CipherSuite.namesOf(conContext.sslConfig.enabledCipherSuites);
 297     }
 298 
 299     @Override
 300     public synchronized void setEnabledCipherSuites(String[] suites) {
 301         conContext.sslConfig.enabledCipherSuites =
 302                 CipherSuite.validValuesOf(suites);
 303     }
 304 
 305     @Override
 306     public String[] getSupportedProtocols() {
 307         return ProtocolVersion.toStringArray(
 308                 sslContext.getSupportedProtocolVersions());
 309     }
 310 
 311     @Override
 312     public synchronized String[] getEnabledProtocols() {
 313         return ProtocolVersion.toStringArray(
 314                 conContext.sslConfig.enabledProtocols);
 315     }
 316 
 317     @Override
 318     public synchronized void setEnabledProtocols(String[] protocols) {
 319         if (protocols == null) {
 320             throw new IllegalArgumentException("Protocols cannot be null");
 321         }
 322 
 323         conContext.sslConfig.enabledProtocols =
 324                 ProtocolVersion.namesOf(protocols);
 325     }
 326 
 327     @Override
 328     public SSLSession getSession() {
 329         try {
 330             // start handshaking, if failed, the connection will be closed.
 331             ensureNegotiated();
 332         } catch (IOException ioe) {
 333             if (SSLLogger.isOn && SSLLogger.isOn("handshake")) {
 334                 SSLLogger.severe("handshake failed", ioe);
 335             }
 336 
 337             return SSLSessionImpl.nullSession;
 338         }
 339 
 340         return conContext.conSession;
 341     }
 342 
 343     @Override
 344     public synchronized SSLSession getHandshakeSession() {
 345         if (conContext.handshakeContext != null) {
 346             synchronized (this) {
 347                 if (conContext.handshakeContext != null) {
 348                     return conContext.handshakeContext.handshakeSession;
 349                 }
 350             }
 351         }
 352 
 353         return null;
 354     }
 355 
 356     @Override
 357     public synchronized void addHandshakeCompletedListener(
 358             HandshakeCompletedListener listener) {
 359         if (listener == null) {
 360             throw new IllegalArgumentException("listener is null");
 361         }
 362 
 363         conContext.sslConfig.addHandshakeCompletedListener(listener);
 364     }
 365 
 366     @Override
 367     public synchronized void removeHandshakeCompletedListener(
 368             HandshakeCompletedListener listener) {
 369         if (listener == null) {
 370             throw new IllegalArgumentException("listener is null");
 371         }
 372 
 373         conContext.sslConfig.removeHandshakeCompletedListener(listener);
 374     }
 375 
 376     @Override
 377     public void startHandshake() throws IOException {
 378         if (!isConnected) {
 379             throw new SocketException("Socket is not connected");
 380         }
 381 
 382         if (conContext.isBroken || conContext.isInboundClosed() ||
 383                 conContext.isOutboundClosed()) {
 384             throw new SocketException("Socket has been closed or broken");
 385         }
 386 
 387         synchronized (conContext) {     // handshake lock
 388             // double check the context status
 389             if (conContext.isBroken || conContext.isInboundClosed() ||
 390                     conContext.isOutboundClosed()) {
 391                 throw new SocketException("Socket has been closed or broken");
 392             }
 393 
 394             try {
 395                 conContext.kickstart();
 396 
 397                 // All initial handshaking goes through this operation until we
 398                 // have a valid SSL connection.
 399                 //
 400                 // Handle handshake messages only, need no application data.
 401                 if (!conContext.isNegotiated) {
 402                     readHandshakeRecord();
 403                 }
 404             } catch (IOException ioe) {
 405                 conContext.fatal(Alert.HANDSHAKE_FAILURE,
 406                     "Couldn't kickstart handshaking", ioe);
 407             } catch (Exception oe) {    // including RuntimeException
 408                 handleException(oe);
 409             }
 410         }
 411     }
 412 
 413     @Override
 414     public synchronized void setUseClientMode(boolean mode) {
 415         conContext.setUseClientMode(mode);
 416     }
 417 
 418     @Override
 419     public synchronized boolean getUseClientMode() {
 420         return conContext.sslConfig.isClientMode;
 421     }
 422 
 423     @Override
 424     public synchronized void setNeedClientAuth(boolean need) {
 425         conContext.sslConfig.clientAuthType =
 426                 (need ? ClientAuthType.CLIENT_AUTH_REQUIRED :
 427                         ClientAuthType.CLIENT_AUTH_NONE);
 428     }
 429 
 430     @Override
 431     public synchronized boolean getNeedClientAuth() {
 432         return (conContext.sslConfig.clientAuthType ==
 433                         ClientAuthType.CLIENT_AUTH_REQUIRED);
 434     }
 435 
 436     @Override
 437     public synchronized void setWantClientAuth(boolean want) {
 438         conContext.sslConfig.clientAuthType =
 439                 (want ? ClientAuthType.CLIENT_AUTH_REQUESTED :
 440                         ClientAuthType.CLIENT_AUTH_NONE);
 441     }
 442 
 443     @Override
 444     public synchronized boolean getWantClientAuth() {
 445         return (conContext.sslConfig.clientAuthType ==
 446                         ClientAuthType.CLIENT_AUTH_REQUESTED);
 447     }
 448 
 449     @Override
 450     public synchronized void setEnableSessionCreation(boolean flag) {
 451         conContext.sslConfig.enableSessionCreation = flag;
 452     }
 453 
 454     @Override
 455     public synchronized boolean getEnableSessionCreation() {
 456         return conContext.sslConfig.enableSessionCreation;
 457     }
 458 
 459     @Override
 460     public boolean isClosed() {
 461         return tlsIsClosed;
 462     }
 463 
 464     // Please don't synchronized this method.  Otherwise, the read and close
 465     // locks may be deadlocked.
 466     @Override
 467     public void close() throws IOException {
 468         if (tlsIsClosed) {
 469             return;
 470         }
 471 
 472         if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
 473             SSLLogger.fine("duplex close of SSLSocket");
 474         }
 475 
 476         try {
 477             // shutdown output bound, which may have been closed previously.
 478             if (!isOutputShutdown()) {
 479                 duplexCloseOutput();
 480             }
 481 
 482             // shutdown input bound, which may have been closed previously.
 483             if (!isInputShutdown()) {
 484                 duplexCloseInput();
 485             }
 486 
 487             if (!isClosed()) {
 488                 // close the connection directly
 489                 closeSocket(false);
 490             }
 491         } catch (IOException ioe) {
 492             // ignore the exception
 493             if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
 494                 SSLLogger.warning("SSLSocket duplex close failed", ioe);
 495             }
 496         } finally {
 497             tlsIsClosed = true;
 498         }
 499     }
 500 
 501     /**
 502      * Duplex close, start from closing outbound.
 503      *
 504      * For TLS 1.2 [RFC 5246], unless some other fatal alert has been
 505      * transmitted, each party is required to send a close_notify alert
 506      * before closing the write side of the connection.  The other party
 507      * MUST respond with a close_notify alert of its own and close down
 508      * the connection immediately, discarding any pending writes.  It is
 509      * not required for the initiator of the close to wait for the responding
 510      * close_notify alert before closing the read side of the connection.
 511      *
 512      * For TLS 1.3, Each party MUST send a close_notify alert before
 513      * closing its write side of the connection, unless it has already sent
 514      * some error alert.  This does not have any effect on its read side of
 515      * the connection.  Both parties need not wait to receive a close_notify
 516      * alert before closing their read side of the connection, though doing
 517      * so would introduce the possibility of truncation.
 518      *
 519      * In order to support user initiated duplex-close for TLS 1.3 connections,
 520      * the user_canceled alert is used together with the close_notify alert.
 521      */
 522     private void duplexCloseOutput() throws IOException {
 523         boolean useUserCanceled = false;
 524         boolean hasCloseReceipt = false;
 525         if (conContext.isNegotiated) {
 526             if (!conContext.protocolVersion.useTLS13PlusSpec()) {
 527                 hasCloseReceipt = true;
 528             } else {
 529                 // Use a user_canceled alert for TLS 1.3 duplex close.
 530                 useUserCanceled = true;
 531             }
 532         } else if (conContext.handshakeContext != null) {   // initial handshake
 533             // Use user_canceled alert regardless the protocol versions.
 534             useUserCanceled = true;
 535 
 536             // The protocol version may have been negotiated.
 537             ProtocolVersion pv = conContext.handshakeContext.negotiatedProtocol;
 538             if (pv == null || (!pv.useTLS13PlusSpec())) {
 539                 hasCloseReceipt = true;
 540             }
 541         }
 542 
 543         // Need a lock here so that the user_canceled alert and the
 544         // close_notify alert can be delivered together.
 545         try {
 546             synchronized (conContext.outputRecord) {
 547                 // send a user_canceled alert if needed.
 548                 if (useUserCanceled) {
 549                     conContext.warning(Alert.USER_CANCELED);
 550                 }
 551 
 552                 // send a close_notify alert
 553                 conContext.warning(Alert.CLOSE_NOTIFY);
 554             }
 555         } finally {
 556             if (!conContext.isOutboundClosed()) {
 557                 conContext.outputRecord.close();
 558             }
 559 
 560             if ((autoClose || !isLayered()) && !super.isOutputShutdown()) {
 561                 super.shutdownOutput();
 562             }
 563         }
 564 
 565         if (!isInputShutdown()) {
 566             bruteForceCloseInput(hasCloseReceipt);
 567         }
 568     }
 569 
 570     /**
 571      * Duplex close, start from closing inbound.
 572      *
 573      * This method should only be called when the outbound has been closed,
 574      * but the inbound is still open.
 575      */
 576     private void duplexCloseInput() throws IOException {
 577         boolean hasCloseReceipt = false;
 578         if (conContext.isNegotiated &&
 579                 !conContext.protocolVersion.useTLS13PlusSpec()) {
 580             hasCloseReceipt = true;
 581         }   // No close receipt if handshake has no completed.
 582 
 583         bruteForceCloseInput(hasCloseReceipt);
 584     }
 585 
 586     /**
 587      * Brute force close the input bound.
 588      *
 589      * This method should only be called when the outbound has been closed,
 590      * but the inbound is still open.
 591      */
 592     private void bruteForceCloseInput(
 593             boolean hasCloseReceipt) throws IOException {
 594         if (hasCloseReceipt) {
 595             // It is not required for the initiator of the close to wait for
 596             // the responding close_notify alert before closing the read side
 597             // of the connection.  However, if the application protocol using
 598             // TLS provides that any data may be carried over the underlying
 599             // transport after the TLS connection is closed, the TLS
 600             // implementation MUST receive a "close_notify" alert before
 601             // indicating end-of-data to the application-layer.
 602             try {
 603                 this.shutdown();
 604             } finally {
 605                 if (!isInputShutdown()) {
 606                     shutdownInput(false);
 607                 }
 608             }
 609         } else {
 610             if (!conContext.isInboundClosed()) {
 611                 conContext.inputRecord.close();
 612             }
 613 
 614             if ((autoClose || !isLayered()) && !super.isInputShutdown()) {
 615                 super.shutdownInput();
 616             }
 617         }
 618     }
 619 
 620     // Please don't synchronized this method.  Otherwise, the read and close
 621     // locks may be deadlocked.
 622     @Override
 623     public void shutdownInput() throws IOException {
 624         shutdownInput(true);
 625     }
 626 
 627     // It is not required to check the close_notify receipt unless an
 628     // application call shutdownInput() explicitly.
 629     private void shutdownInput(
 630             boolean checkCloseNotify) throws IOException {
 631         if (isInputShutdown()) {
 632             return;
 633         }
 634 
 635         if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
 636             SSLLogger.fine("close inbound of SSLSocket");
 637         }
 638 
 639         // Is it ready to close inbound?
 640         //
 641         // No need to throw exception if the initial handshake is not started.
 642         if (checkCloseNotify && !conContext.isInputCloseNotified &&
 643             (conContext.isNegotiated || conContext.handshakeContext != null)) {
 644 
 645             conContext.fatal(Alert.INTERNAL_ERROR,
 646                     "closing inbound before receiving peer's close_notify");
 647         }
 648 
 649         conContext.closeInbound();
 650         if ((autoClose || !isLayered()) && !super.isInputShutdown()) {
 651             super.shutdownInput();
 652         }
 653     }
 654 
 655     @Override
 656     public boolean isInputShutdown() {
 657         return conContext.isInboundClosed() &&
 658                 ((autoClose || !isLayered()) ? super.isInputShutdown(): true);
 659     }
 660 
 661     // Please don't synchronized this method.  Otherwise, the read and close
 662     // locks may be deadlocked.
 663     @Override
 664     public void shutdownOutput() throws IOException {
 665         if (isOutputShutdown()) {
 666             return;
 667         }
 668 
 669         if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
 670             SSLLogger.fine("close outbound of SSLSocket");
 671         }
 672         conContext.closeOutbound();
 673 
 674         if ((autoClose || !isLayered()) && !super.isOutputShutdown()) {
 675             super.shutdownOutput();
 676         }
 677     }
 678 
 679     @Override
 680     public boolean isOutputShutdown() {
 681         return conContext.isOutboundClosed() &&
 682                 ((autoClose || !isLayered()) ? super.isOutputShutdown(): true);
 683     }
 684 
 685     @Override
 686     public synchronized InputStream getInputStream() throws IOException {
 687         if (isClosed()) {
 688             throw new SocketException("Socket is closed");
 689         }
 690 
 691         if (!isConnected) {
 692             throw new SocketException("Socket is not connected");
 693         }
 694 
 695         if (conContext.isInboundClosed() || isInputShutdown()) {
 696             throw new SocketException("Socket input is already shutdown");
 697         }
 698 
 699         return appInput;
 700     }
 701 
 702     private void ensureNegotiated() throws IOException {
 703         if (conContext.isNegotiated || conContext.isBroken ||
 704                 conContext.isInboundClosed() || conContext.isOutboundClosed()) {
 705             return;
 706         }
 707 
 708         synchronized (conContext) {     // handshake lock
 709             // double check the context status
 710             if (conContext.isNegotiated || conContext.isBroken ||
 711                     conContext.isInboundClosed() ||
 712                     conContext.isOutboundClosed()) {
 713                 return;
 714             }
 715 
 716             startHandshake();
 717         }
 718     }
 719 
 720     /**
 721      * InputStream for application data as returned by
 722      * SSLSocket.getInputStream().
 723      */
 724     private class AppInputStream extends InputStream {
 725         // One element array used to implement the single byte read() method
 726         private final byte[] oneByte = new byte[1];
 727 
 728         // the temporary buffer used to read network
 729         private ByteBuffer buffer;
 730 
 731         // Is application data available in the stream?
 732         private volatile boolean appDataIsAvailable;
 733 
 734         AppInputStream() {
 735             this.appDataIsAvailable = false;
 736             this.buffer = ByteBuffer.allocate(4096);
 737         }
 738 
 739         /**
 740          * Return the minimum number of bytes that can be read
 741          * without blocking.
 742          */
 743         @Override
 744         public int available() throws IOException {
 745             // Currently not synchronized.
 746             if ((!appDataIsAvailable) || checkEOF()) {
 747                 return 0;
 748             }
 749 
 750             return buffer.remaining();
 751         }
 752 
 753         /**
 754          * Read a single byte, returning -1 on non-fault EOF status.
 755          */
 756         @Override
 757         public int read() throws IOException {
 758             int n = read(oneByte, 0, 1);
 759             if (n <= 0) {   // EOF
 760                 return -1;
 761             }
 762 
 763             return oneByte[0] & 0xFF;
 764         }
 765 
 766         /**
 767          * Reads up to {@code len} bytes of data from the input stream
 768          * into an array of bytes.
 769          *
 770          * An attempt is made to read as many as {@code len} bytes, but a
 771          * smaller number may be read. The number of bytes actually read
 772          * is returned as an integer.
 773          *
 774          * If the layer above needs more data, it asks for more, so we
 775          * are responsible only for blocking to fill at most one buffer,
 776          * and returning "-1" on non-fault EOF status.
 777          */
 778         @Override
 779         public int read(byte[] b, int off, int len)
 780                 throws IOException {
 781             if (b == null) {
 782                 throw new NullPointerException("the target buffer is null");
 783             } else if (off < 0 || len < 0 || len > b.length - off) {
 784                 throw new IndexOutOfBoundsException(
 785                         "buffer length: " + b.length + ", offset; " + off +
 786                         ", bytes to read:" + len);
 787             } else if (len == 0) {
 788                 return 0;
 789             }
 790 
 791             if (checkEOF()) {
 792                 return -1;
 793             }
 794 
 795             // start handshaking if the connection has not been negotiated.
 796             if (!conContext.isNegotiated && !conContext.isBroken &&
 797                     !conContext.isInboundClosed() &&
 798                     !conContext.isOutboundClosed()) {
 799                 ensureNegotiated();
 800             }
 801 
 802             // Check if the Socket is invalid (error or closed).
 803             if (!conContext.isNegotiated ||
 804                     conContext.isBroken || conContext.isInboundClosed()) {
 805                 throw new SocketException("Connection or inbound has closed");
 806             }
 807 
 808             // Read the available bytes at first.
 809             //
 810             // Note that the receiving and processing of post-handshake message
 811             // are also synchronized with the read lock.
 812             synchronized (this) {
 813                 int remains = available();
 814                 if (remains > 0) {
 815                     int howmany = Math.min(remains, len);
 816                     buffer.get(b, off, howmany);
 817 
 818                     return howmany;
 819                 }
 820 
 821                 appDataIsAvailable = false;
 822                 try {
 823                     ByteBuffer bb = readApplicationRecord(buffer);
 824                     if (bb == null) {   // EOF
 825                         return -1;
 826                     } else {
 827                         // The buffer may be reallocated for bigger capacity.
 828                         buffer = bb;
 829                     }
 830 
 831                     bb.flip();
 832                     int volume = Math.min(len, bb.remaining());
 833                     buffer.get(b, off, volume);
 834                     appDataIsAvailable = true;
 835 
 836                     return volume;
 837                 } catch (Exception e) {   // including RuntimeException
 838                     // shutdown and rethrow (wrapped) exception as appropriate
 839                     handleException(e);
 840 
 841                     // dummy for compiler
 842                     return -1;
 843                 }
 844             }
 845         }
 846 
 847         /**
 848          * Skip n bytes.
 849          *
 850          * This implementation is somewhat less efficient than possible, but
 851          * not badly so (redundant copy).  We reuse the read() code to keep
 852          * things simpler.
 853          */
 854         @Override
 855         public synchronized long skip(long n) throws IOException {
 856             // dummy array used to implement skip()
 857             byte[] skipArray = new byte[256];
 858 
 859             long skipped = 0;
 860             while (n > 0) {
 861                 int len = (int)Math.min(n, skipArray.length);
 862                 int r = read(skipArray, 0, len);
 863                 if (r <= 0) {
 864                     break;
 865                 }
 866                 n -= r;
 867                 skipped += r;
 868             }
 869 
 870             return skipped;
 871         }
 872 
 873         @Override
 874         public void close() throws IOException {
 875             if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
 876                 SSLLogger.finest("Closing input stream");
 877             }
 878 
 879             try {
 880                 shutdownInput(false);
 881             } catch (IOException ioe) {
 882                 // ignore the exception
 883                 if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
 884                     SSLLogger.warning("input stream close failed", ioe);
 885                 }
 886             }
 887         }
 888 
 889         /**
 890          * Return whether we have reached end-of-file.
 891          *
 892          * If the socket is not connected, has been shutdown because of an error
 893          * or has been closed, throw an Exception.
 894          */
 895         private boolean checkEOF() throws IOException {
 896             if (conContext.isInboundClosed()) {
 897                 return true;
 898             } else if (conContext.isInputCloseNotified || conContext.isBroken) {
 899                 if (conContext.closeReason == null) {
 900                     return true;
 901                 } else {
 902                     throw new SSLException(
 903                         "Connection has closed: " + conContext.closeReason,
 904                         conContext.closeReason);
 905                 }
 906             }
 907 
 908             return false;
 909         }
 910     }
 911 
 912     @Override
 913     public synchronized OutputStream getOutputStream() throws IOException {
 914         if (isClosed()) {
 915             throw new SocketException("Socket is closed");
 916         }
 917 
 918         if (!isConnected) {
 919             throw new SocketException("Socket is not connected");
 920         }
 921 
 922         if (conContext.isOutboundDone() || isOutputShutdown()) {
 923             throw new SocketException("Socket output is already shutdown");
 924         }
 925 
 926         return appOutput;
 927     }
 928 
 929 
 930     /**
 931      * OutputStream for application data as returned by
 932      * SSLSocket.getOutputStream().
 933      */
 934     private class AppOutputStream extends OutputStream {
 935         // One element array used to implement the write(byte) method
 936         private final byte[] oneByte = new byte[1];
 937 
 938         @Override
 939         public void write(int i) throws IOException {
 940             oneByte[0] = (byte)i;
 941             write(oneByte, 0, 1);
 942         }
 943 
 944         @Override
 945         public void write(byte[] b,
 946                 int off, int len) throws IOException {
 947             if (b == null) {
 948                 throw new NullPointerException("the source buffer is null");
 949             } else if (off < 0 || len < 0 || len > b.length - off) {
 950                 throw new IndexOutOfBoundsException(
 951                         "buffer length: " + b.length + ", offset; " + off +
 952                         ", bytes to read:" + len);
 953             } else if (len == 0) {
 954                 //
 955                 // Don't bother to really write empty records.  We went this
 956                 // far to drive the handshake machinery, for correctness; not
 957                 // writing empty records improves performance by cutting CPU
 958                 // time and network resource usage.  However, some protocol
 959                 // implementations are fragile and don't like to see empty
 960                 // records, so this also increases robustness.
 961                 //
 962                 return;
 963             }
 964 
 965             // Start handshaking if the connection has not been negotiated.
 966             if (!conContext.isNegotiated && !conContext.isBroken &&
 967                     !conContext.isInboundClosed() &&
 968                     !conContext.isOutboundClosed()) {
 969                 ensureNegotiated();
 970             }
 971 
 972             // Check if the Socket is invalid (error or closed).
 973             if (!conContext.isNegotiated ||
 974                     conContext.isBroken || conContext.isOutboundClosed()) {
 975                 throw new SocketException("Connection or outbound has closed");
 976             }
 977 
 978             //
 979 
 980             // Delegate the writing to the underlying socket.
 981             try {
 982                 conContext.outputRecord.deliver(b, off, len);
 983             } catch (SSLHandshakeException she) {
 984                 // may be record sequence number overflow
 985                 conContext.fatal(Alert.HANDSHAKE_FAILURE, she);
 986             } catch (IOException e) {
 987                 conContext.fatal(Alert.UNEXPECTED_MESSAGE, e);
 988             }
 989 
 990             // Is the sequence number is nearly overflow, or has the key usage
 991             // limit been reached?
 992             if (conContext.outputRecord.seqNumIsHuge() ||
 993                     conContext.outputRecord.writeCipher.atKeyLimit()) {
 994                 tryKeyUpdate();
 995             }
 996         }
 997 
 998         @Override
 999         public void close() throws IOException {
1000             if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
1001                 SSLLogger.finest("Closing output stream");
1002             }
1003 
1004             try {
1005                 shutdownOutput();
1006             } catch (IOException ioe) {
1007                 // ignore the exception
1008                 if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
1009                     SSLLogger.warning("output stream close failed", ioe);
1010                 }
1011             }
1012         }
1013     }
1014 
1015     @Override
1016     public synchronized SSLParameters getSSLParameters() {
1017         return conContext.sslConfig.getSSLParameters();
1018     }
1019 
1020     @Override
1021     public synchronized void setSSLParameters(SSLParameters params) {
1022         conContext.sslConfig.setSSLParameters(params);
1023 
1024         if (conContext.sslConfig.maximumPacketSize != 0) {
1025             conContext.outputRecord.changePacketSize(
1026                     conContext.sslConfig.maximumPacketSize);
1027         }
1028     }
1029 
1030     @Override
1031     public synchronized String getApplicationProtocol() {
1032         return conContext.applicationProtocol;
1033     }
1034 
1035     @Override
1036     public synchronized String getHandshakeApplicationProtocol() {
1037         if (conContext.handshakeContext != null) {
1038             return conContext.handshakeContext.applicationProtocol;
1039         }
1040 
1041         return null;
1042     }
1043 
1044     @Override
1045     public synchronized void setHandshakeApplicationProtocolSelector(
1046             BiFunction<SSLSocket, List<String>, String> selector) {
1047         conContext.sslConfig.socketAPSelector = selector;
1048     }
1049 
1050     @Override
1051     public synchronized BiFunction<SSLSocket, List<String>, String>
1052             getHandshakeApplicationProtocolSelector() {
1053         return conContext.sslConfig.socketAPSelector;
1054     }
1055 
1056     /**
1057      * Read the initial handshake records.
1058      */
1059     private int readHandshakeRecord() throws IOException {
1060         while (!conContext.isInboundClosed()) {
1061             try {
1062                 Plaintext plainText = decode(null);
1063                 if ((plainText.contentType == ContentType.HANDSHAKE.id) &&
1064                         conContext.isNegotiated) {
1065                     return 0;
1066                 }
1067             } catch (SSLException ssle) {
1068                 throw ssle;
1069             } catch (IOException ioe) {
1070                 if (!(ioe instanceof SSLException)) {
1071                     throw new SSLException("readHandshakeRecord", ioe);
1072                 } else {
1073                     throw ioe;
1074                 }
1075             }
1076         }
1077 
1078         return -1;
1079     }
1080 
1081     /**
1082      * Read application data record. Used by AppInputStream only, but defined
1083      * here so as to use the socket level synchronization.
1084      *
1085      * Note that the connection guarantees that handshake, alert, and change
1086      * cipher spec data streams are handled as they arrive, so we never see
1087      * them here.
1088      *
1089      * Note: Please be careful about the synchronization, and don't use this
1090      * method other than in the AppInputStream class!
1091      */
1092     private ByteBuffer readApplicationRecord(
1093             ByteBuffer buffer) throws IOException {
1094         while (!conContext.isInboundClosed()) {
1095             /*
1096              * clean the buffer and check if it is too small, e.g. because
1097              * the AppInputStream did not have the chance to see the
1098              * current packet length but rather something like that of the
1099              * handshake before. In that case we return 0 at this point to
1100              * give the caller the chance to adjust the buffer.
1101              */
1102             buffer.clear();
1103             int inLen = conContext.inputRecord.bytesInCompletePacket();
1104             if (inLen < 0) {    // EOF
1105                 handleEOF(null);
1106 
1107                 // if no exception thrown
1108                 return null;
1109             }
1110 
1111             // Is this packet bigger than SSL/TLS normally allows?
1112             if (inLen > SSLRecord.maxLargeRecordSize) {
1113                 throw new SSLProtocolException(
1114                         "Illegal packet size: " + inLen);
1115             }
1116 
1117             if (inLen > buffer.remaining()) {
1118                 buffer = ByteBuffer.allocate(inLen);
1119             }
1120 
1121             try {
1122                 Plaintext plainText;
1123                 synchronized (this) {
1124                     plainText = decode(buffer);
1125                 }
1126                 if (plainText.contentType == ContentType.APPLICATION_DATA.id &&
1127                         buffer.position() > 0) {
1128                     return buffer;
1129                 }
1130             } catch (SSLException ssle) {
1131                 throw ssle;
1132             } catch (IOException ioe) {
1133                 if (!(ioe instanceof SSLException)) {
1134                     throw new SSLException("readApplicationRecord", ioe);
1135                 } else {
1136                     throw ioe;
1137                 }
1138             }
1139         }
1140 
1141         //
1142         // couldn't read, due to some kind of error
1143         //
1144         return null;
1145     }
1146 
1147     private Plaintext decode(ByteBuffer destination) throws IOException {
1148         Plaintext plainText;
1149         try {
1150             if (destination == null) {
1151                 plainText = SSLTransport.decode(conContext,
1152                         null, 0, 0, null, 0, 0);
1153             } else {
1154                 plainText = SSLTransport.decode(conContext,
1155                         null, 0, 0, new ByteBuffer[]{destination}, 0, 1);
1156             }
1157         } catch (EOFException eofe) {
1158             // EOFException is special as it is related to close_notify.
1159             plainText = handleEOF(eofe);
1160         }
1161 
1162         // Is the sequence number is nearly overflow?
1163         if (plainText != Plaintext.PLAINTEXT_NULL &&
1164                 (conContext.inputRecord.seqNumIsHuge() ||
1165                 conContext.inputRecord.readCipher.atKeyLimit())) {
1166             tryKeyUpdate();
1167         }
1168 
1169         return plainText;
1170     }
1171 
1172     /**
1173      * Try key update for sequence number wrap or key usage limit.
1174      *
1175      * Note that in order to maintain the handshake status properly, we check
1176      * the sequence number and key usage limit after the last record
1177      * reading/writing process.
1178      *
1179      * As we request renegotiation or close the connection for wrapped sequence
1180      * number when there is enough sequence number space left to handle a few
1181      * more records, so the sequence number of the last record cannot be
1182      * wrapped.
1183      */
1184     private void tryKeyUpdate() throws IOException {
1185         // Don't bother to kickstart if handshaking is in progress, or if the
1186         // connection is not duplex-open.
1187         if ((conContext.handshakeContext == null) &&
1188                 !conContext.isOutboundClosed() &&
1189                 !conContext.isInboundClosed() &&
1190                 !conContext.isBroken) {
1191             if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
1192                 SSLLogger.finest("trigger key update");
1193             }
1194             startHandshake();
1195         }
1196     }
1197 
1198     /**
1199      * Initialize the handshaker and socket streams.
1200      *
1201      * Called by connect, the layered constructor, and SSLServerSocket.
1202      */
1203     synchronized void doneConnect() throws IOException {
1204         // In server mode, it is not necessary to set host and serverNames.
1205         // Otherwise, would require a reverse DNS lookup to get the hostname.
1206         if (peerHost == null || peerHost.isEmpty()) {
1207             boolean useNameService =
1208                     trustNameService && conContext.sslConfig.isClientMode;
1209             useImplicitHost(useNameService);
1210         } else {
1211             conContext.sslConfig.serverNames =
1212                     Utilities.addToSNIServerNameList(
1213                             conContext.sslConfig.serverNames, peerHost);
1214         }
1215 
1216         InputStream sockInput = super.getInputStream();
1217         conContext.inputRecord.setReceiverStream(sockInput);
1218 
1219         OutputStream sockOutput = super.getOutputStream();
1220         conContext.inputRecord.setDeliverStream(sockOutput);
1221         conContext.outputRecord.setDeliverStream(sockOutput);
1222 
1223         this.isConnected = true;
1224     }
1225 
1226     private void useImplicitHost(boolean useNameService) {
1227         // Note: If the local name service is not trustworthy, reverse
1228         // host name resolution should not be performed for endpoint
1229         // identification.  Use the application original specified
1230         // hostname or IP address instead.
1231 
1232         // Get the original hostname via jdk.internal.access.SharedSecrets
1233         InetAddress inetAddress = getInetAddress();
1234         if (inetAddress == null) {      // not connected
1235             return;
1236         }
1237 
1238         JavaNetInetAddressAccess jna =
1239                 SharedSecrets.getJavaNetInetAddressAccess();
1240         String originalHostname = jna.getOriginalHostName(inetAddress);
1241         if (originalHostname != null && !originalHostname.isEmpty()) {

1242 
1243             this.peerHost = originalHostname;
1244             if (conContext.sslConfig.serverNames.isEmpty() &&
1245                     !conContext.sslConfig.noSniExtension) {
1246                 conContext.sslConfig.serverNames =
1247                         Utilities.addToSNIServerNameList(
1248                                 conContext.sslConfig.serverNames, peerHost);
1249             }
1250 
1251             return;
1252         }
1253 
1254         // No explicitly specified hostname, no server name indication.
1255         if (!useNameService) {
1256             // The local name service is not trustworthy, use IP address.
1257             this.peerHost = inetAddress.getHostAddress();
1258         } else {
1259             // Use the underlying reverse host name resolution service.
1260             this.peerHost = getInetAddress().getHostName();
1261         }
1262     }
1263 
1264     // ONLY used by HttpsClient to setup the URI specified hostname
1265     //
1266     // Please NOTE that this method MUST be called before calling to
1267     // SSLSocket.setSSLParameters(). Otherwise, the {@code host} parameter
1268     // may override SNIHostName in the customized server name indication.
1269     public synchronized void setHost(String host) {
1270         this.peerHost = host;
1271         this.conContext.sslConfig.serverNames =
1272                 Utilities.addToSNIServerNameList(
1273                         conContext.sslConfig.serverNames, host);
1274     }
1275 
1276     /**
1277      * Handle an exception.
1278      *
1279      * This method is called by top level exception handlers (in read(),
1280      * write()) to make sure we always shutdown the connection correctly
1281      * and do not pass runtime exception to the application.
1282      *
1283      * This method never returns normally, it always throws an IOException.
1284      */
1285     private void handleException(Exception cause) throws IOException {
1286         if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
1287             SSLLogger.warning("handling exception", cause);
1288         }
1289 
1290         // Don't close the Socket in case of timeouts or interrupts.
1291         if (cause instanceof InterruptedIOException) {
1292             throw (IOException)cause;
1293         }
1294 
1295         // need to perform error shutdown
1296         boolean isSSLException = (cause instanceof SSLException);
1297         Alert alert;
1298         if (isSSLException) {
1299             if (cause instanceof SSLHandshakeException) {
1300                 alert = Alert.HANDSHAKE_FAILURE;
1301             } else {
1302                 alert = Alert.UNEXPECTED_MESSAGE;
1303             }
1304         } else {
1305             if (cause instanceof IOException) {
1306                 alert = Alert.UNEXPECTED_MESSAGE;
1307             } else {
1308                 // RuntimeException
1309                 alert = Alert.INTERNAL_ERROR;
1310             }
1311         }
1312         conContext.fatal(alert, cause);
1313     }
1314 
1315     private Plaintext handleEOF(EOFException eofe) throws IOException {
1316         if (requireCloseNotify || conContext.handshakeContext != null) {
1317             SSLException ssle;
1318             if (conContext.handshakeContext != null) {
1319                 ssle = new SSLHandshakeException(
1320                         "Remote host terminated the handshake");
1321             } else {
1322                 ssle = new SSLProtocolException(
1323                         "Remote host terminated the connection");
1324             }
1325 
1326             if (eofe != null) {
1327                 ssle.initCause(eofe);
1328             }
1329             throw ssle;
1330         } else {
1331             // treat as if we had received a close_notify
1332             conContext.isInputCloseNotified = true;
1333             shutdownInput();
1334 
1335             return Plaintext.PLAINTEXT_NULL;
1336         }
1337     }
1338 
1339 
1340     @Override
1341     public String getPeerHost() {
1342         return peerHost;
1343     }
1344 
1345     @Override
1346     public int getPeerPort() {
1347         return getPort();
1348     }
1349 
1350     @Override
1351     public boolean useDelegatedTask() {
1352         return false;
1353     }
1354 
1355     @Override
1356     public void shutdown() throws IOException {
1357         if (!isClosed()) {
1358             if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
1359                 SSLLogger.fine("close the underlying socket");
1360             }
1361 
1362             try {
1363                 if (conContext.isInputCloseNotified) {
1364                     // Close the connection, no wait for more peer response.
1365                     closeSocket(false);
1366                 } else {
1367                     // Close the connection, may wait for peer close_notify.
1368                     closeSocket(true);
1369                 }
1370             } finally {
1371                 tlsIsClosed = true;
1372             }
1373         }
1374     }
1375 
1376     private void closeSocket(boolean selfInitiated) throws IOException {
1377         if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
1378             SSLLogger.fine("close the SSL connection " +
1379                 (selfInitiated ? "(initiative)" : "(passive)"));
1380         }
1381 
1382         if (autoClose || !isLayered()) {
1383             super.close();
1384         } else if (selfInitiated) {
1385             if (!conContext.isInboundClosed() && !isInputShutdown()) {
1386                 // wait for close_notify alert to clear input stream.
1387                 waitForClose();
1388             }
1389         }
1390     }
1391 
1392    /**
1393     * Wait for close_notify alert for a graceful closure.
1394     *
1395     * [RFC 5246] If the application protocol using TLS provides that any
1396     * data may be carried over the underlying transport after the TLS
1397     * connection is closed, the TLS implementation must receive the responding
1398     * close_notify alert before indicating to the application layer that
1399     * the TLS connection has ended.  If the application protocol will not
1400     * transfer any additional data, but will only close the underlying
1401     * transport connection, then the implementation MAY choose to close the
1402     * transport without waiting for the responding close_notify.
1403     */
1404     private void waitForClose() throws IOException {
1405         if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
1406             SSLLogger.fine("wait for close_notify or alert");
1407         }
1408 
1409         while (!conContext.isInboundClosed()) {
1410             try {
1411                 Plaintext plainText = decode(null);
1412                 // discard and continue
1413                 if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
1414                     SSLLogger.finest(
1415                         "discard plaintext while waiting for close", plainText);
1416                 }
1417             } catch (Exception e) {   // including RuntimeException
1418                 handleException(e);
1419             }
1420         }
1421     }
1422 }
--- EOF ---