8236464: SO_LINGER option is ignored by SSLSocket in JDK 11

Reviewed-by: ascarpino
diff --git a/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java b/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java
index c7caed8b..f2b9a22 100644
--- a/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java
+++ b/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java
@@ -619,6 +619,15 @@
             }
         }
 
+        // Deliver the user_canceled alert and the close notify alert.
+        closeNotify(useUserCanceled);
+
+        if (!isInputShutdown()) {
+            bruteForceCloseInput(hasCloseReceipt);
+        }
+    }
+
+    void closeNotify(boolean useUserCanceled) throws IOException {
         // Need a lock here so that the user_canceled alert and the
         // close_notify alert can be delivered together.
         int linger = getSoLinger();
@@ -633,7 +642,7 @@
                         conContext.outputRecord.recordLock.tryLock(
                                 linger, TimeUnit.SECONDS)) {
                     try {
-                        handleClosedNotifyAlert(useUserCanceled);
+                        deliverClosedNotify(useUserCanceled);
                     } finally {
                         conContext.outputRecord.recordLock.unlock();
                     }
@@ -687,18 +696,14 @@
         } else {
             conContext.outputRecord.recordLock.lock();
             try {
-                handleClosedNotifyAlert(useUserCanceled);
+                deliverClosedNotify(useUserCanceled);
             } finally {
                 conContext.outputRecord.recordLock.unlock();
             }
         }
-
-        if (!isInputShutdown()) {
-            bruteForceCloseInput(hasCloseReceipt);
-        }
     }
 
-    private void handleClosedNotifyAlert(
+    private void deliverClosedNotify(
             boolean useUserCanceled) throws IOException {
         try {
             // send a user_canceled alert if needed.
diff --git a/src/java.base/share/classes/sun/security/ssl/TransportContext.java b/src/java.base/share/classes/sun/security/ssl/TransportContext.java
index 78bc990..dc63b66 100644
--- a/src/java.base/share/classes/sun/security/ssl/TransportContext.java
+++ b/src/java.base/share/classes/sun/security/ssl/TransportContext.java
@@ -238,7 +238,7 @@
                 (handshakeContext instanceof PostHandshakeContext);
     }
 
-    // Note: close_notify is delivered as a warning alert.
+    // Note: Don't use this method for close_nofity, use closeNotify() instead.
     void warning(Alert alert) {
         // For initial handshaking, don't send a warning alert message to peer
         // if handshaker has not started.
@@ -254,6 +254,33 @@
         }
     }
 
+    // Note: close_notify is delivered as a warning alert.
+    void closeNotify(boolean isUserCanceled) throws IOException {
+        // Socket transport is special because of the SO_LINGER impact.
+        if (transport instanceof SSLSocketImpl) {
+            ((SSLSocketImpl)transport).closeNotify(isUserCanceled);
+        } else {
+            // Need a lock here so that the user_canceled alert and the
+            // close_notify alert can be delivered together.
+            outputRecord.recordLock.lock();
+            try {
+                try {
+                    // send a user_canceled alert if needed.
+                    if (isUserCanceled) {
+                        warning(Alert.USER_CANCELED);
+                    }
+
+                    // send a close_notify alert
+                    warning(Alert.CLOSE_NOTIFY);
+                } finally {
+                    outputRecord.close();
+                }
+            } finally {
+                outputRecord.recordLock.unlock();
+            }
+        }
+    }
+
     SSLException fatal(Alert alert,
             String diagnostic) throws SSLException {
         return fatal(alert, diagnostic, null);
@@ -501,17 +528,7 @@
             }
 
             if (needCloseNotify) {
-                outputRecord.recordLock.lock();
-                try {
-                    try {
-                        // send a close_notify alert
-                        warning(Alert.CLOSE_NOTIFY);
-                    } finally {
-                        outputRecord.close();
-                    }
-                } finally {
-                    outputRecord.recordLock.unlock();
-                }
+                closeNotify(false);
             }
         }
     }
@@ -547,24 +564,7 @@
             useUserCanceled = true;
         }
 
-        // Need a lock here so that the user_canceled alert and the
-        // close_notify alert can be delivered together.
-        outputRecord.recordLock.lock();
-        try {
-            try {
-                // send a user_canceled alert if needed.
-                if (useUserCanceled) {
-                    warning(Alert.USER_CANCELED);
-                }
-
-                // send a close_notify alert
-                warning(Alert.CLOSE_NOTIFY);
-            } finally {
-                outputRecord.close();
-            }
-        } finally {
-            outputRecord.recordLock.unlock();
-        }
+        closeNotify(useUserCanceled);
     }
 
     // Note; HandshakeStatus.FINISHED status is retrieved in other places.