1/* 2 * Copyright (c) 2001, 2016, 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 * @summary Test behavior related to finalize 27 * @run main/othervm SSLSessionFinalizeTest 28 * @run main/othervm/policy=security.policy SSLSessionFinalizeTest 29 */ 30 31import java.io.InputStream; 32import java.io.OutputStream; 33import java.lang.ref.Reference; 34import java.lang.ref.WeakReference; 35import java.util.concurrent.ArrayBlockingQueue; 36 37import javax.net.ssl.SSLServerSocket; 38import javax.net.ssl.SSLServerSocketFactory; 39import javax.net.ssl.SSLSession; 40import javax.net.ssl.SSLSessionBindingEvent; 41import javax.net.ssl.SSLSessionBindingListener; 42import javax.net.ssl.SSLSocket; 43import javax.net.ssl.SSLSocketFactory; 44 45public class SSLSessionFinalizeTest { 46 47 /* 48 * ============================================================= 49 * Set the various variables needed for the tests, then 50 * specify what tests to run on each side. 51 */ 52 53 /* 54 * Should we run the client or server in a separate thread? 55 * Both sides can throw exceptions, but do you have a preference 56 * as to which side should be the main thread. 57 */ 58 static boolean separateServerThread = true; 59 60 /* 61 * Where do we find the keystores? 62 */ 63 static String pathToStores = "../etc"; 64 static String keyStoreFile = "keystore"; 65 static String trustStoreFile = "truststore"; 66 static String passwd = "passphrase"; 67 68 /* 69 * Is the server ready to serve? 70 */ 71 volatile static boolean serverReady = false; 72 73 /* 74 * Turn on SSL debugging? 75 */ 76 static boolean debug = 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 */ 93 void doServerSide() throws Exception { 94 SSLServerSocketFactory sslssf = 95 (SSLServerSocketFactory) SSLServerSocketFactory.getDefault(); 96 SSLServerSocket sslServerSocket = 97 (SSLServerSocket) sslssf.createServerSocket(serverPort); 98 serverPort = sslServerSocket.getLocalPort(); 99 100 /* 101 * Signal Client, we're ready for his connect. 102 */ 103 serverReady = true; 104 105 while (serverReady) { 106 SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept(); 107// System.out.printf(" accept: %s%n", sslSocket); 108 InputStream sslIS = sslSocket.getInputStream(); 109 OutputStream sslOS = sslSocket.getOutputStream(); 110 111 sslIS.read(); 112 sslOS.write(85); 113 sslOS.flush(); 114 115 sslSocket.close(); 116 } 117 } 118 119 /* 120 * Define the client side of the test. 121 * 122 * If the server prematurely exits, serverReady will be set to true 123 * to avoid infinite hangs. 124 */ 125 SBListener doClientSide() throws Exception { 126 127 /* 128 * Wait for server to get started. 129 */ 130 while (!serverReady) { 131 Thread.sleep(50); 132 } 133 134 SSLSocketFactory sslsf = 135 (SSLSocketFactory) SSLSocketFactory.getDefault(); 136 137 try { 138 SSLSocket sslSocket = (SSLSocket) 139 sslsf.createSocket("localhost", serverPort); 140 InputStream sslIS = sslSocket.getInputStream(); 141 OutputStream sslOS = sslSocket.getOutputStream(); 142 143 sslOS.write(280); 144 sslOS.flush(); 145 sslIS.read(); 146 147 sslOS.close(); 148 sslIS.close(); 149 150 SSLSession sslSession = sslSocket.getSession(); 151 System.out.printf(" sslSession: %s %n %s%n", sslSession, sslSession.getClass()); 152 SBListener sbListener = new SBListener(sslSession); 153 154 sslSession.putValue("x", sbListener); 155 156 sslSession.invalidate(); 157 158 sslSocket.close(); 159 160 sslOS = null; 161 sslIS = null; 162 sslSession = null; 163 sslSocket = null; 164 Reference.reachabilityFence(sslOS); 165 Reference.reachabilityFence(sslIS); 166 Reference.reachabilityFence(sslSession); 167 Reference.reachabilityFence(sslSocket); 168 169 return sbListener; 170 } catch (Exception ex) { 171 ex.printStackTrace(); 172 throw ex; 173 } 174 } 175 176 /* 177 * ============================================================= 178 * The remainder is just support stuff 179 */ 180 181 // use any free port by default 182 volatile int serverPort = 0; 183 184 volatile Exception serverException = null; 185 volatile Exception clientException = null; 186 187 public static void main(String[] args) throws Exception { 188 String keyFilename = 189 System.getProperty("test.src", "./") + "/" + pathToStores + 190 "/" + keyStoreFile; 191 String trustFilename = 192 System.getProperty("test.src", "./") + "/" + pathToStores + 193 "/" + trustStoreFile; 194 195 System.setProperty("javax.net.ssl.keyStore", keyFilename); 196 System.setProperty("javax.net.ssl.keyStorePassword", passwd); 197 System.setProperty("javax.net.ssl.trustStore", trustFilename); 198 System.setProperty("javax.net.ssl.trustStorePassword", passwd); 199 200 if (debug) 201 System.setProperty("javax.net.debug", "all"); 202 203 /* 204 * Start the tests. 205 */ 206 new SSLSessionFinalizeTest(); 207 } 208 209 ArrayBlockingQueue<Thread> threads = new ArrayBlockingQueue<Thread>(100); 210 211 ArrayBlockingQueue<SBListener> sbListeners = new ArrayBlockingQueue<>(100); 212 213 /* 214 * Primary constructor, used to drive remainder of the test. 215 * 216 * Fork off the other side, then do your work. 217 */ 218 SSLSessionFinalizeTest() throws Exception { 219 final int count = 1; 220 if (separateServerThread) { 221 startServer(true); 222 startClients(true, count); 223 } else { 224 startClients(true, count); 225 startServer(true); 226 } 227 228 /* 229 * Wait for other side to close down. 230 */ 231 Thread t; 232 while ((t = threads.take()) != Thread.currentThread()) { 233 System.out.printf(" joining: %s%n", t); 234 t.join(1000L); 235 } 236 serverReady = false; 237 System.gc(); 238 System.gc(); 239 240 241 SBListener listener = null; 242 while ((listener = sbListeners.poll()) != null) { 243 if (!listener.check()) { 244 System.out.printf(" sbListener not called on finalize: %s%n", 245 listener); 246 } 247 } 248 249 /* 250 * When we get here, the test is pretty much over. 251 * 252 * If the main thread excepted, that propagates back 253 * immediately. If the other thread threw an exception, we 254 * should report back. 255 */ 256 if (serverException != null) { 257 System.out.print("Server Exception:"); 258 throw serverException; 259 } 260 if (clientException != null) { 261 System.out.print("Client Exception:"); 262 throw clientException; 263 } 264 } 265 266 void startServer(boolean newThread) throws Exception { 267 if (newThread) { 268 Thread t = new Thread("Server") { 269 public void run() { 270 try { 271 doServerSide(); 272 } catch (Exception e) { 273 /* 274 * Our server thread just died. 275 * 276 * Release the client, if not active already... 277 */ 278 System.err.println("Server died..." + e); 279 serverReady = true; 280 serverException = e; 281 } 282 } 283 }; 284 threads.add(t); 285 t.setDaemon(true); 286 t.start(); 287 } else { 288 doServerSide(); 289 } 290 } 291 292 void startClients(boolean newThread, int count) throws Exception { 293 for (int i = 0; i < count; i++) { 294 System.out.printf(" newClient: %d%n", i); 295 startClient(newThread); 296 } 297 serverReady = false; 298 299 threads.add(Thread.currentThread()); // add ourselves at the 'end' 300 } 301 void startClient(boolean newThread) throws Exception { 302 if (newThread) { 303 Thread t = new Thread("Client") { 304 public void run() { 305 try { 306 sbListeners.add(doClientSide()); 307 } catch (Exception e) { 308 /* 309 * Our client thread just died. 310 */ 311 System.err.println("Client died..." + e); 312 clientException = e; 313 } 314 } 315 }; 316 System.out.printf(" starting: %s%n", t); 317 threads.add(t); 318 t.start(); 319 } else { 320 sbListeners.add(doClientSide()); 321 } 322 } 323 324 325 static class SBListener implements SSLSessionBindingListener { 326 private volatile int unboundNotified; 327 private final WeakReference<SSLSession> session; 328 329 SBListener(SSLSession session) { 330 this.unboundNotified = 0; 331 this.session = new WeakReference<SSLSession>(session); 332 } 333 334 boolean check() { 335 System.out.printf(" check: %s%n", this); 336 return unboundNotified > 0 && session.get() == null; 337 } 338 339 @Override 340 public void valueBound(SSLSessionBindingEvent event) { 341 System.out.printf(" valueBound: %s%n", event.getName()); 342 } 343 344 @Override 345 public void valueUnbound(SSLSessionBindingEvent event) { 346 System.out.printf(" valueUnbound: %s%n", event.getName()); 347 unboundNotified++; 348 } 349 350 public String toString() { 351 return "count: " + unboundNotified + 352 ", ref: " + session.get(); 353 } 354 } 355} 356