1/* 2 * Copyright (c) 2001, 2011, 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 4404399 27 * @summary When a layered SSL socket is closed, it should wait for close_notify 28 * @run main/othervm NonAutoClose 29 * 30 * SunJSSE does not support dynamic system properties, no way to re-use 31 * system properties in samevm/agentvm mode. 32 * @author Brad Wetmore 33 */ 34 35import java.io.*; 36import java.net.ServerSocket; 37import java.net.Socket; 38import javax.net.ssl.*; 39import java.security.cert.X509Certificate; 40import java.security.cert.CertificateException; 41 42 43public class NonAutoClose { 44 /* 45 * ============================================================= 46 * Set the various variables needed for the tests, then 47 * specify what tests to run on each side. 48 */ 49 50 /* 51 * Should we run the client or server in a separate thread? 52 * Both sides can throw exceptions, but do you have a preference 53 * as to which side should be the main thread. 54 */ 55 private static boolean separateServerThread = true; 56 57 /* 58 * Where do we find the keystores? 59 */ 60 private final static String pathToStores = "../../../../javax/net/ssl/etc"; 61 private final static String keyStoreFile = "keystore"; 62 private final static String trustStoreFile = "truststore"; 63 private final static String passwd = "passphrase"; 64 private final static char[] cpasswd = "passphrase".toCharArray(); 65 66 /* 67 * Is the server ready to serve? 68 */ 69 volatile static boolean serverReady = false; 70 71 /* 72 * Turn on SSL debugging? 73 */ 74 private final static boolean DEBUG = false; 75 private final static boolean VERBOSE = false; 76 private final static int NUM_ITERATIONS = 10; 77 private final static int PLAIN_SERVER_VAL = 1; 78 private final static int PLAIN_CLIENT_VAL = 2; 79 private final static int TLS_SERVER_VAL = 3; 80 private final static int TLS_CLIENT_VAL = 4; 81 82 /* 83 * If the client or server is doing some kind of object creation 84 * that the other side depends on, and that thread prematurely 85 * exits, you may experience a hang. The test harness will 86 * terminate all hung threads after its timeout has expired, 87 * currently 3 minutes by default, but you might try to be 88 * smart about it.... 89 */ 90 91 void expectValue(int got, int expected, String msg) throws IOException { 92 if (VERBOSE) { 93 System.out.println(msg + ": read (" + got + ")"); 94 } 95 if (got != expected) { 96 throw new IOException(msg + ": read (" + got 97 + ") but expecting(" + expected + ")"); 98 } 99 } 100 101 102 /* 103 * Define the server side of the test. 104 * 105 * If the server prematurely exits, serverReady will be set to true 106 * to avoid infinite hangs. 107 */ 108 109 void doServerSide() throws Exception { 110 if (VERBOSE) { 111 System.out.println("Starting server"); 112 } 113 114 /* 115 * Setup the SSL stuff 116 */ 117 SSLSocketFactory sslsf = 118 (SSLSocketFactory) SSLSocketFactory.getDefault(); 119 120 ServerSocket serverSocket = new ServerSocket(SERVER_PORT); 121 122 SERVER_PORT = serverSocket.getLocalPort(); 123 124 /* 125 * Signal Client, we're ready for his connect. 126 */ 127 serverReady = true; 128 129 Socket plainSocket = serverSocket.accept(); 130 InputStream is = plainSocket.getInputStream(); 131 OutputStream os = plainSocket.getOutputStream(); 132 133 expectValue(is.read(), PLAIN_CLIENT_VAL, "Server"); 134 135 os.write(PLAIN_SERVER_VAL); 136 os.flush(); 137 138 for (int i = 1; i <= NUM_ITERATIONS; i++) { 139 if (VERBOSE) { 140 System.out.println("================================="); 141 System.out.println("Server Iteration #" + i); 142 } 143 144 SSLSocket ssls = (SSLSocket) sslsf.createSocket(plainSocket, 145 SERVER_NAME, plainSocket.getPort(), false); 146 147 ssls.setUseClientMode(false); 148 InputStream sslis = ssls.getInputStream(); 149 OutputStream sslos = ssls.getOutputStream(); 150 151 expectValue(sslis.read(), TLS_CLIENT_VAL, "Server"); 152 153 sslos.write(TLS_SERVER_VAL); 154 sslos.flush(); 155 156 sslis.close(); 157 sslos.close(); 158 ssls.close(); 159 160 if (VERBOSE) { 161 System.out.println("TLS socket is closed"); 162 } 163 } 164 165 expectValue(is.read(), PLAIN_CLIENT_VAL, "Server"); 166 167 os.write(PLAIN_SERVER_VAL); 168 os.flush(); 169 170 is.close(); 171 os.close(); 172 plainSocket.close(); 173 174 if (VERBOSE) { 175 System.out.println("Server plain socket is closed"); 176 } 177 } 178 179 /* 180 * Define the client side of the test. 181 * 182 * If the server prematurely exits, serverReady will be set to true 183 * to avoid infinite hangs. 184 */ 185 private void doClientSide() throws Exception { 186 /* 187 * Wait for server to get started. 188 */ 189 while (!serverReady) { 190 Thread.sleep(50); 191 } 192 193 if (VERBOSE) { 194 System.out.println("Starting client"); 195 } 196 197 /* 198 * Setup the SSL stuff 199 */ 200 SSLSocketFactory sslsf = 201 (SSLSocketFactory) SSLSocketFactory.getDefault(); 202 203 Socket plainSocket = new Socket(SERVER_NAME, SERVER_PORT); 204 InputStream is = plainSocket.getInputStream(); 205 OutputStream os = plainSocket.getOutputStream(); 206 207 os.write(PLAIN_CLIENT_VAL); 208 os.flush(); 209 210 expectValue(is.read(), PLAIN_SERVER_VAL, "Client"); 211 212 for (int i = 1; i <= NUM_ITERATIONS; i++) { 213 if (VERBOSE) { 214 System.out.println("==================================="); 215 System.out.println("Client Iteration #" + i); 216 } 217 218 SSLSocket ssls = (SSLSocket) sslsf.createSocket(plainSocket, 219 SERVER_NAME, plainSocket.getPort(), false); 220 221 ssls.setUseClientMode(true); 222 223 InputStream sslis = ssls.getInputStream(); 224 OutputStream sslos = ssls.getOutputStream(); 225 226 sslos.write(TLS_CLIENT_VAL); 227 sslos.flush(); 228 229 expectValue(sslis.read(), TLS_SERVER_VAL, "Client"); 230 231 sslis.close(); 232 sslos.close(); 233 ssls.close(); 234 235 if (VERBOSE) { 236 System.out.println("Client TLS socket is closed"); 237 } 238 } 239 240 os.write(PLAIN_CLIENT_VAL); 241 os.flush(); 242 243 expectValue(is.read(), PLAIN_SERVER_VAL, "Client"); 244 245 is.close(); 246 os.close(); 247 plainSocket.close(); 248 249 if (VERBOSE) { 250 System.out.println("Client plain socket is closed"); 251 } 252 } 253 254 /* 255 * ============================================================= 256 * The remainder is just support stuff 257 */ 258 259 private volatile int SERVER_PORT = 0; 260 private final static String SERVER_NAME = "localhost"; 261 262 private volatile Exception serverException = null; 263 private volatile Exception clientException = null; 264 265 private final static String keyFilename = 266 System.getProperty("test.src", ".") + "/" + pathToStores + 267 "/" + keyStoreFile; 268 private final static String trustFilename = 269 System.getProperty("test.src", ".") + "/" + pathToStores + 270 "/" + trustStoreFile; 271 272 273 // Used for running test standalone 274 public static void main(String[] args) throws Exception { 275 System.setProperty("javax.net.ssl.keyStore", keyFilename); 276 System.setProperty("javax.net.ssl.keyStorePassword", passwd); 277 System.setProperty("javax.net.ssl.trustStore", trustFilename); 278 System.setProperty("javax.net.ssl.trustStorePassword", passwd); 279 280 if (DEBUG) 281 System.setProperty("javax.net.debug", "all"); 282 283 /* 284 * Start the tests. 285 */ 286 new NonAutoClose(); 287 } 288 289 private Thread clientThread = null; 290 private Thread serverThread = null; 291 292 /* 293 * Primary constructor, used to drive remainder of the test. 294 * 295 * Fork off the other side, then do your work. 296 */ 297 NonAutoClose() throws Exception { 298 if (separateServerThread) { 299 startServer(true); 300 startClient(false); 301 } else { 302 startClient(true); 303 startServer(false); 304 } 305 306 /* 307 * Wait for other side to close down. 308 */ 309 if (separateServerThread) { 310 serverThread.join(); 311 } else { 312 clientThread.join(); 313 } 314 315 /* 316 * When we get here, the test is pretty much over. 317 * 318 * If the main thread excepted, that propagates back 319 * immediately. If the other thread threw an exception, we 320 * should report back. 321 */ 322 if (serverException != null) { 323 System.err.print("Server Exception:"); 324 throw serverException; 325 } 326 if (clientException != null) { 327 System.err.print("Client Exception:"); 328 throw clientException; 329 } 330 } 331 332 private void startServer(boolean newThread) throws Exception { 333 if (newThread) { 334 serverThread = new Thread() { 335 public void run() { 336 try { 337 doServerSide(); 338 } catch (Exception e) { 339 /* 340 * Our server thread just died. 341 * 342 * Release the client, if not active already... 343 */ 344 System.err.println("Server died..."); 345 serverReady = true; 346 serverException = e; 347 } 348 } 349 }; 350 serverThread.start(); 351 } else { 352 doServerSide(); 353 } 354 } 355 356 private void startClient(boolean newThread) throws Exception { 357 if (newThread) { 358 clientThread = new Thread() { 359 public void run() { 360 try { 361 doClientSide(); 362 } catch (Exception e) { 363 /* 364 * Our client thread just died. 365 */ 366 System.err.println("Client died..."); 367 clientException = e; 368 } 369 } 370 }; 371 clientThread.start(); 372 } else { 373 doClientSide(); 374 } 375 } 376} 377