11/*
2- * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
2+ * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved.
33 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44 *
55 * This code is free software; you can redistribute it and/or modify it
2929/*
3030 * @test
3131 * @bug 8224829
32- * @summary AsyncSSLSocketClose.java has timing issue
32+ * @summary AsyncSSLSocketClose.java has timing issue.
33+ * @library /javax/net/ssl/templates
3334 * @run main/othervm BlockedAsyncClose
3435 */
3536
3839import java .net .SocketException ;
3940import java .net .InetAddress ;
4041import java .net .InetSocketAddress ;
42+ import java .util .Arrays ;
4143import java .util .concurrent .CountDownLatch ;
4244import java .util .concurrent .TimeUnit ;
45+ import java .util .concurrent .locks .Lock ;
46+ import java .util .concurrent .locks .ReentrantLock ;
4347
44- public class BlockedAsyncClose implements Runnable {
48+ /*
49+ * To manually verify that the write thread was blocked when socket.close() is called,
50+ * run the test with -Djavax.net.debug=ssl. You should see the message
51+ * "SSLSocket output duplex close failed: SO_LINGER timeout, close_notify message cannot be sent."
52+ */
53+ public class BlockedAsyncClose extends SSLContextTemplate implements Runnable {
4554 SSLSocket socket ;
4655 SSLServerSocket ss ;
4756
4857 // Is the socket ready to close?
4958 private final CountDownLatch closeCondition = new CountDownLatch (1 );
50-
51- // Where do we find the keystores?
52- static String pathToStores = "../../../../javax/net/ssl/etc" ;
53- static String keyStoreFile = "keystore" ;
54- static String trustStoreFile = "truststore" ;
55- static String passwd = "passphrase" ;
59+ private final Lock writeLock = new ReentrantLock ();
5660
5761 public static void main (String [] args ) throws Exception {
58- String keyFilename =
59- System .getProperty ("test.src" , "./" ) + "/" + pathToStores +
60- "/" + keyStoreFile ;
61- String trustFilename =
62- System .getProperty ("test.src" , "./" ) + "/" + pathToStores +
63- "/" + trustStoreFile ;
64-
65- System .setProperty ("javax.net.ssl.keyStore" , keyFilename );
66- System .setProperty ("javax.net.ssl.keyStorePassword" , passwd );
67- System .setProperty ("javax.net.ssl.trustStore" , trustFilename );
68- System .setProperty ("javax.net.ssl.trustStorePassword" , passwd );
69-
70- new BlockedAsyncClose ();
62+ new BlockedAsyncClose ().runTest ();
7163 }
7264
73- public BlockedAsyncClose () throws Exception {
74- SSLServerSocketFactory sslssf =
75- (SSLServerSocketFactory )SSLServerSocketFactory .getDefault ();
65+ public void runTest () throws Exception {
66+ SSLServerSocketFactory sslssf = createServerSSLContext ().getServerSocketFactory ();
7667 InetAddress loopback = InetAddress .getLoopbackAddress ();
7768 ss = (SSLServerSocket )sslssf .createServerSocket ();
7869 ss .bind (new InetSocketAddress (loopback , 0 ));
7970
80- SSLSocketFactory sslsf =
81- (SSLSocketFactory )SSLSocketFactory .getDefault ();
71+ SSLSocketFactory sslsf = createClientSSLContext ().getSocketFactory ();
8272 socket = (SSLSocket )sslsf .createSocket (loopback , ss .getLocalPort ());
8373 SSLSocket serverSoc = (SSLSocket )ss .accept ();
8474 ss .close ();
8575
86- ( new Thread (this ) ).start ();
76+ new Thread (this ).start ();
8777 serverSoc .startHandshake ();
8878
8979 boolean closeIsReady = closeCondition .await (90L , TimeUnit .SECONDS );
@@ -94,23 +84,22 @@ public BlockedAsyncClose() throws Exception {
9484 }
9585
9686 socket .setSoLinger (true , 10 );
97- System .out .println ("Calling Socket.close" );
9887
99- // Sleep for a while so that the write thread blocks by hitting the
100- // output stream buffer limit.
101- Thread .sleep (1000 );
88+ // if the writeLock is not released by the other thread within 10
89+ // seconds it is probably blocked, and we can try to close the socket
90+ while (writeLock .tryLock (10 , TimeUnit .SECONDS )) {
91+ writeLock .unlock ();
92+ }
10293
94+ System .out .println ("Calling socket.close()" );
10395 socket .close ();
104- System .out .println ("ssl socket get closed" );
10596 System .out .flush ();
10697 }
10798
10899 // block in write
109100 public void run () {
110101 byte [] ba = new byte [1024 ];
111- for (int i = 0 ; i < ba .length ; i ++) {
112- ba [i ] = 0x7A ;
113- }
102+ Arrays .fill (ba , (byte ) 0x7A );
114103
115104 try {
116105 OutputStream os = socket .getOutputStream ();
@@ -128,8 +117,16 @@ public void run() {
128117 // write more
129118 while (true ) {
130119 count += ba .length ;
120+
131121 System .out .println (count + " bytes to be written" );
122+
123+ writeLock .lock ();
132124 os .write (ba );
125+ // This isn't in a try/finally. If an exception is thrown
126+ // and the lock is released, the main thread will
127+ // loop until the test times out. So don't release it.
128+ writeLock .unlock ();
129+
133130 System .out .println (count + " bytes written" );
134131 }
135132 } catch (SocketException se ) {
@@ -144,4 +141,3 @@ public void run() {
144141 }
145142 }
146143}
147-
0 commit comments