1 /*
2  * Copyright (c) 2017, 2020, 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.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 
24 /*
25  * @test
26  * @bug 8184328 8253368
27  * @summary JDK8u131-b34-socketRead0 hang at SSL read
28  * @run main/othervm SSLSocketCloseHang
29  * @run main/othervm SSLSocketCloseHang shutdownInputTest
30  */
31 
32 import java.io.*;
33 import java.net.*;
34 import java.util.*;
35 import java.security.*;
36 import javax.net.ssl.*;
37 
38 public class SSLSocketCloseHang {
39 
40     /*
41      * =============================================================
42      * Set the various variables needed for the tests, then
43      * specify what tests to run on each side.
44      */
45 
46     /*
47      * Should we run the client or server in a separate thread?
48      * Both sides can throw exceptions, but do you have a preference
49      * as to which side should be the main thread.
50      */
51     static boolean separateServerThread = true;
52 
53     /*
54      * Where do we find the keystores?
55      */
56     static String pathToStores = "../../../../javax/net/ssl/etc";
57     static String keyStoreFile = "keystore";
58     static String trustStoreFile = "truststore";
59     static String passwd = "passphrase";
60 
61     /*
62      * Is the server ready to serve?
63      */
64     volatile static boolean serverReady = false;
65 
66     /*
67      * Was the client responsible for closing the socket
68      */
69     volatile static boolean clientClosed = false;
70 
71     /*
72      * Turn on SSL debugging?
73      */
74     static boolean debug = false;
75 
76     static boolean shutdownInputTest = false;
77 
78     /*
79      * If the client or server is doing some kind of object creation
80      * that the other side depends on, and that thread prematurely
81      * exits, you may experience a hang.  The test harness will
82      * terminate all hung threads after its timeout has expired,
83      * currently 3 minutes by default, but you might try to be
84      * smart about it....
85      */
86 
87     /*
88      * Define the server side of the test.
89      *
90      * If the server prematurely exits, serverReady will be set to true
91      * to avoid infinite hangs.
92      */
doServerSide()93     void doServerSide() throws Exception {
94         SSLServerSocketFactory sslssf =
95             (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
96         SSLServerSocket sslServerSocket =
97             (SSLServerSocket) sslssf.createServerSocket(serverPort);
98 
99         serverPort = sslServerSocket.getLocalPort();
100 
101         /*
102          * Signal Client, we're ready for his connect.
103          */
104         serverReady = true;
105 
106         System.err.println("Server accepting: " + System.nanoTime());
107         SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
108         System.err.println("Server accepted: " + System.nanoTime());
109         sslSocket.startHandshake();
110         System.err.println("Server handshake complete: " + System.nanoTime());
111         while (!clientClosed) {
112             Thread.sleep(500);
113         }
114     }
115 
116     /*
117      * Define the client side of the test.
118      *
119      * If the server prematurely exits, serverReady will be set to true
120      * to avoid infinite hangs.
121      */
doClientSide()122     void doClientSide() throws Exception {
123         boolean caught = false;
124 
125         /*
126          * Wait for server to get started.
127          */
128         System.out.println("waiting on server");
129         while (!serverReady) {
130             Thread.sleep(50);
131         }
132         Thread.sleep(500);
133         System.out.println("server ready");
134 
135         Socket baseSocket = new Socket("localhost", serverPort);
136         baseSocket.setSoTimeout(1000);
137 
138         SSLSocketFactory sslsf =
139             (SSLSocketFactory) SSLSocketFactory.getDefault();
140         SSLSocket sslSocket = (SSLSocket)
141             sslsf.createSocket(baseSocket, "localhost", serverPort, false);
142 
143         // handshaking
144         System.err.println("Client starting handshake: " + System.nanoTime());
145         sslSocket.startHandshake();
146         System.err.println("Client handshake done: " + System.nanoTime());
147 
148         Thread.sleep(500);
149         System.err.println("Client closing: " + System.nanoTime());
150 
151         if (shutdownInputTest) {
152             try {
153                 sslSocket.shutdownInput();
154             } catch (SSLException e) {
155                 if (!e.getMessage().contains
156                         ("closing inbound before receiving peer's close_notify")) {
157                     throw new RuntimeException("expected different exception message. " +
158                         e.getMessage());
159                 }
160             }
161             if (!sslSocket.getSession().isValid()) {
162                 throw new RuntimeException("expected session to remain valid");
163             }
164 
165         } else {
166             sslSocket.close();
167         }
168 
169 
170 
171         clientClosed = true;
172         System.err.println("Client closed: " + System.nanoTime());
173     }
174 
175     /*
176      * =============================================================
177      * The remainder is just support stuff
178      */
179 
180     // use any free port by default
181     volatile int serverPort = 0;
182 
183     volatile Exception serverException = null;
184     volatile Exception clientException = null;
185 
186     volatile byte[] serverDigest = null;
187 
main(String[] args)188     public static void main(String[] args) throws Exception {
189         String keyFilename =
190             System.getProperty("test.src", "./") + "/" + pathToStores +
191                 "/" + keyStoreFile;
192         String trustFilename =
193             System.getProperty("test.src", "./") + "/" + pathToStores +
194                 "/" + trustStoreFile;
195 
196         System.setProperty("javax.net.ssl.keyStore", keyFilename);
197         System.setProperty("javax.net.ssl.keyStorePassword", passwd);
198         System.setProperty("javax.net.ssl.trustStore", trustFilename);
199         System.setProperty("javax.net.ssl.trustStorePassword", passwd);
200 
201         if (debug)
202             System.setProperty("javax.net.debug", "all");
203 
204         shutdownInputTest = args.length > 0 ? true : false;
205 
206         /*
207          * Start the tests.
208          */
209         new SSLSocketCloseHang();
210     }
211 
212     Thread clientThread = null;
213     Thread serverThread = null;
214 
215     /*
216      * Primary constructor, used to drive remainder of the test.
217      *
218      * Fork off the other side, then do your work.
219      */
SSLSocketCloseHang()220     SSLSocketCloseHang() throws Exception {
221         if (separateServerThread) {
222             startServer(true);
223             startClient(false);
224         } else {
225             startClient(true);
226             startServer(false);
227         }
228 
229         /*
230          * Wait for other side to close down.
231          */
232         if (separateServerThread) {
233             serverThread.join();
234         } else {
235             clientThread.join();
236         }
237 
238         /*
239          * When we get here, the test is pretty much over.
240          *
241          * If the main thread excepted, that propagates back
242          * immediately.  If the other thread threw an exception, we
243          * should report back.
244          */
245         if (serverException != null) {
246             System.out.print("Server Exception:");
247             throw serverException;
248         }
249         if (clientException != null) {
250             System.out.print("Client Exception:");
251             throw clientException;
252         }
253     }
254 
startServer(boolean newThread)255     void startServer(boolean newThread) throws Exception {
256         if (newThread) {
257             serverThread = new Thread() {
258                 public void run() {
259                     try {
260                         doServerSide();
261                     } catch (Exception e) {
262                         /*
263                          * Our server thread just died.
264                          *
265                          * Release the client, if not active already...
266                          */
267                         System.err.println("Server died...");
268                         System.err.println(e);
269                         serverReady = true;
270                         serverException = e;
271                     }
272                 }
273             };
274             serverThread.start();
275         } else {
276             doServerSide();
277         }
278     }
279 
startClient(boolean newThread)280     void startClient(boolean newThread) throws Exception {
281         if (newThread) {
282             clientThread = new Thread() {
283                 public void run() {
284                     try {
285                         doClientSide();
286                     } catch (Exception e) {
287                         /*
288                          * Our client thread just died.
289                          */
290                         System.err.println("Client died...");
291                         clientException = e;
292                     }
293                 }
294             };
295             clientThread.start();
296         } else {
297             doClientSide();
298         }
299     }
300 }
301