Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/jdk17u
Path: blob/master/test/jdk/sun/security/ssl/SSLSessionImpl/NoInvalidateSocketException.java
66645 views
1
/*
2
* Copyright (c) 2021, 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
//
27
// SunJSSE does not support dynamic system properties, no way to re-use
28
// system properties in samevm/agentvm mode.
29
//
30
31
/*
32
* @test
33
* @bug 8274736
34
* @summary Concurrent read/close of SSLSockets causes SSLSessions to be
35
* invalidated unnecessarily
36
* @library /javax/net/ssl/templates
37
* @run main/othervm NoInvalidateSocketException TLSv1.3
38
* @run main/othervm NoInvalidateSocketException TLSv1.2
39
* @run main/othervm -Djdk.tls.client.enableSessionTicketExtension=false
40
* NoInvalidateSocketException TLSv1.2
41
*/
42
43
44
45
import java.io.*;
46
import javax.net.ssl.*;
47
import java.net.InetAddress;
48
import java.net.InetSocketAddress;
49
import java.net.SocketException;
50
import java.net.SocketTimeoutException;
51
import java.util.ArrayList;
52
import java.util.List;
53
import java.util.Objects;
54
import java.util.concurrent.TimeUnit;
55
56
public class NoInvalidateSocketException extends SSLSocketTemplate {
57
private static final int ITERATIONS = 10;
58
59
// This controls how long the main thread waits before closing the socket.
60
// This may need tweaking for different environments to get the timing
61
// right.
62
private static final int CLOSE_DELAY = 10;
63
64
private static SSLContext clientSSLCtx;
65
private static SSLSocket theSSLSocket;
66
private static SSLSession theSSLSession;
67
private static InputStream theInputStream;
68
private static String theSSLSocketHashCode;
69
private static SSLSession lastSSLSession;
70
private static final List<SSLSocket> serverCleanupList = new ArrayList<>();
71
private static String tlsVersion = null;
72
73
private static int invalidSessCount = 0;
74
private static volatile boolean readFromSocket = false;
75
private static volatile boolean finished = false;
76
77
public static void main(String[] args) throws Exception {
78
if (System.getProperty("javax.net.debug") == null) {
79
System.setProperty("javax.net.debug", "session");
80
}
81
82
if (args != null && args.length >= 1) {
83
tlsVersion = args[0];
84
}
85
86
new NoInvalidateSocketException(true).run();
87
if (invalidSessCount > 0) {
88
throw new RuntimeException("One or more sessions were improperly " +
89
"invalidated.");
90
}
91
}
92
93
public NoInvalidateSocketException(boolean sepSrvThread) {
94
super(sepSrvThread);
95
}
96
97
@Override
98
public boolean isCustomizedClientConnection() {
99
return true;
100
}
101
102
@Override
103
public void runClientApplication(int serverPort) {
104
Thread.currentThread().setName("Main Client Thread");
105
106
// Create the SSLContext we'll use for client sockets for the
107
// duration of the test.
108
try {
109
clientSSLCtx = createClientSSLContext();
110
} catch (Exception e) {
111
throw new RuntimeException("Failed to create client ctx", e);
112
}
113
114
// Create the reader thread
115
ReaderThread readerThread = new ReaderThread();
116
readerThread.setName("Client Reader Thread");
117
readerThread.start();
118
119
try {
120
for (int i = 0; i < ITERATIONS; i++) {
121
openSSLSocket();
122
doHandshake();
123
getInputStream();
124
getAndCompareSession();
125
126
// Perform the Close/Read MT collision
127
readCloseMultiThreaded();
128
129
// Check to make sure that the initially negotiated session
130
// remains intact.
131
isSessionValid();
132
133
lastSSLSession = theSSLSession;
134
135
// Insert a short gap between iterations
136
Thread.sleep(1000);
137
System.out.println();
138
}
139
} catch (Exception e) {
140
logToConsole("Unexpected Exception: " + e);
141
} finally {
142
// Tell the reader thread to finish
143
finished = true;
144
}
145
}
146
147
private void readCloseMultiThreaded() throws IOException,
148
InterruptedException {
149
// Tell the reader thread to start trying to read from this
150
// socket
151
readFromSocket = true;
152
153
// Short pause to give the reader thread time to start
154
// reading.
155
if (CLOSE_DELAY > 0) {
156
Thread.sleep(CLOSE_DELAY);
157
}
158
159
// The problem happens when the reader thread tries to read
160
// from the socket while this thread is in the close() call
161
closeSSLSocket();
162
163
// Pause to give the reader thread time to discover that the
164
// socket is closed and throw a SocketException
165
Thread.sleep(500);
166
}
167
168
private class ReaderThread extends Thread {
169
public void run() {
170
// This thread runs in a tight loop until
171
// readFromSocket == true
172
while (!finished) {
173
if (readFromSocket) {
174
int result = 0;
175
try {
176
// If the timing is just
177
// right, this will throw a SocketException
178
// and the SSLSession will be
179
// invalidated.
180
result = readFromSSLSocket();
181
} catch (Exception e) {
182
logToConsole("Exception reading from SSLSocket@" +
183
theSSLSocketHashCode + ": " + e);
184
e.printStackTrace(System.out);
185
186
// Stop trying to read from
187
// the socket now
188
readFromSocket = false;
189
}
190
191
if (result == -1) {
192
logToConsole("Reached end of stream reading from " +
193
"SSLSocket@" + theSSLSocketHashCode);
194
195
// Stop trying to read from
196
// the socket now
197
readFromSocket = false;
198
}
199
}
200
}
201
}
202
}
203
204
private void openSSLSocket() throws IOException {
205
theSSLSocket = (SSLSocket)clientSSLCtx.getSocketFactory().
206
createSocket(serverAddress, serverPort);
207
if (tlsVersion != null) {
208
theSSLSocket.setEnabledProtocols(new String[] { tlsVersion });
209
}
210
theSSLSocketHashCode = String.format("%08x", theSSLSocket.hashCode());
211
logToConsole("Opened SSLSocket@" + theSSLSocketHashCode);
212
}
213
214
private void doHandshake() throws IOException {
215
logToConsole("Started handshake on SSLSocket@" +
216
theSSLSocketHashCode);
217
theSSLSocket.startHandshake();
218
logToConsole("Finished handshake on SSLSocket@" +
219
theSSLSocketHashCode);
220
}
221
222
private void getInputStream() throws IOException {
223
theInputStream = theSSLSocket.getInputStream();
224
}
225
226
private void getAndCompareSession() {
227
theSSLSession = theSSLSocket.getSession();
228
229
// Have we opened a new session or re-used the last one?
230
if (lastSSLSession == null ||
231
!theSSLSession.equals(lastSSLSession)) {
232
logToConsole("*** OPENED NEW SESSION ***: " +
233
theSSLSession);
234
} else {
235
logToConsole("*** RE-USING PREVIOUS SESSION ***: " +
236
theSSLSession + ")");
237
}
238
}
239
240
private void closeSSLSocket() throws IOException {
241
logToConsole("Closing SSLSocket@" + theSSLSocketHashCode);
242
theSSLSocket.close();
243
logToConsole("Closed SSLSocket@" + theSSLSocketHashCode);
244
}
245
246
private int readFromSSLSocket() throws Exception {
247
logToConsole("Started reading from SSLSocket@" +
248
theSSLSocketHashCode);
249
int result = theInputStream.read();
250
logToConsole("Finished reading from SSLSocket@" +
251
theSSLSocketHashCode + ": result = " + result);
252
return result;
253
}
254
255
private void isSessionValid() {
256
// Is the session still valid?
257
if (theSSLSession.isValid()) {
258
logToConsole("*** " + theSSLSession + " IS VALID ***");
259
} else {
260
logToConsole("*** " + theSSLSession + " IS INVALID ***");
261
invalidSessCount++;
262
}
263
}
264
265
private static void logToConsole(String s) {
266
System.out.println(System.nanoTime() + ": " +
267
Thread.currentThread().getName() + ": " + s);
268
}
269
270
@Override
271
public void doServerSide() throws Exception {
272
Thread.currentThread().setName("Server Listener Thread");
273
SSLContext context = createServerSSLContext();
274
SSLServerSocketFactory sslssf = context.getServerSocketFactory();
275
InetAddress serverAddress = this.serverAddress;
276
SSLServerSocket sslServerSocket = serverAddress == null ?
277
(SSLServerSocket)sslssf.createServerSocket(serverPort)
278
: (SSLServerSocket)sslssf.createServerSocket();
279
if (serverAddress != null) {
280
sslServerSocket.bind(new InetSocketAddress(serverAddress,
281
serverPort));
282
}
283
configureServerSocket(sslServerSocket);
284
serverPort = sslServerSocket.getLocalPort();
285
logToConsole("Listening on " + sslServerSocket.getLocalSocketAddress());
286
287
// Signal the client, the server is ready to accept connection.
288
serverCondition.countDown();
289
290
// Try to accept a connection in 5 seconds.
291
// We will do this in a loop until the client flips the
292
// finished variable to true
293
SSLSocket sslSocket;
294
295
int timeoutCount = 0;
296
try {
297
do {
298
try {
299
sslSocket = (SSLSocket) sslServerSocket.accept();
300
timeoutCount = 0; // Reset the timeout counter;
301
logToConsole("Accepted connection from " +
302
sslSocket.getRemoteSocketAddress());
303
304
// Add the socket to the cleanup list so it can get
305
// closed at the end of the test
306
serverCleanupList.add(sslSocket);
307
308
boolean clientIsReady =
309
clientCondition.await(30L, TimeUnit.SECONDS);
310
if (clientIsReady) {
311
// Handle the connection in a new thread
312
ServerHandlerThread sht = null;
313
try {
314
sht = new ServerHandlerThread(sslSocket);
315
sht.start();
316
} finally {
317
if (sht != null) {
318
sht.join();
319
}
320
}
321
}
322
} catch (SocketTimeoutException ste) {
323
timeoutCount++;
324
// If we are finished then we can return, otherwise
325
// check if we've timed out too many times (an exception
326
// case). One way or the other we will exit eventually.
327
if (finished) {
328
return;
329
} else if (timeoutCount >= 3) {
330
logToConsole("Server accept timeout exceeded");
331
throw ste;
332
}
333
}
334
} while (!finished);
335
} finally {
336
sslServerSocket.close();
337
// run through the server cleanup list and close those sockets
338
// as well.
339
for (SSLSocket sock : serverCleanupList) {
340
try {
341
if (sock != null) {
342
sock.close();
343
}
344
} catch (IOException ioe) {
345
// Swallow these close failures as the server itself
346
// is shutting down anyway.
347
}
348
}
349
}
350
}
351
352
@Override
353
public void configureServerSocket(SSLServerSocket socket) {
354
try {
355
socket.setReuseAddress(true);
356
socket.setSoTimeout(5000);
357
} catch (SocketException se) {
358
// Rethrow as unchecked to satisfy the override signature
359
throw new RuntimeException(se);
360
}
361
}
362
363
@Override
364
public void runServerApplication(SSLSocket sslSocket) {
365
Thread.currentThread().setName("Server Reader Thread");
366
SSLSocket sock = null;
367
sock = sslSocket;
368
try {
369
BufferedReader is = new BufferedReader(
370
new InputStreamReader(sock.getInputStream()));
371
PrintWriter os = new PrintWriter(new BufferedWriter(
372
new OutputStreamWriter(sock.getOutputStream())));
373
374
// Only handle a single burst of data
375
char[] buf = new char[1024];
376
int dataRead = is.read(buf);
377
logToConsole(String.format("Received: %d bytes of data\n",
378
dataRead));
379
380
os.println("Received connection from client");
381
os.flush();
382
} catch (IOException ioe) {
383
// Swallow these exceptions for this test
384
}
385
}
386
387
private class ServerHandlerThread extends Thread {
388
SSLSocket sock;
389
ServerHandlerThread(SSLSocket socket) {
390
this.sock = Objects.requireNonNull(socket, "Illegal null socket");
391
}
392
393
@Override
394
public void run() {
395
try {
396
runServerApplication(sock);
397
} catch (Exception exc) {
398
// Wrap inside an unchecked exception to satisfy Runnable
399
throw new RuntimeException(exc);
400
}
401
}
402
403
void close() {
404
try {
405
sock.close();
406
} catch (IOException e) {
407
// swallow this exception
408
}
409
}
410
}
411
}
412
413