1 /* 2 * Copyright (c) 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 // Please run in othervm mode. SunJSSE does not support dynamic system 25 // properties, no way to re-use system properties in samevm/agentvm mode. 26 27 /* 28 * @test 29 * @bug 8161106 30 * @summary Improve SSLSocket test template 31 * @run main/othervm SSLSocketSample 32 */ 33 34 import java.io.*; 35 import javax.net.ssl.*; 36 import java.net.*; 37 import java.util.concurrent.CountDownLatch; 38 import java.util.concurrent.TimeUnit; 39 40 /** 41 * Template to help speed your client/server tests. 42 */ 43 public final class SSLSocketSample { 44 45 /* 46 * ============================================================= 47 * Set the various variables needed for the tests, then 48 * specify what tests to run on each side. 49 */ 50 51 /* 52 * Should we run the client or server in a separate thread? 53 * Both sides can throw exceptions, but do you have a preference 54 * as to which side should be the main thread. 55 */ 56 private static final boolean separateServerThread = false; 57 58 /* 59 * Where do we find the keystores? 60 */ 61 private static final String pathToStores = "../etc"; 62 private static final String keyStoreFile = "keystore"; 63 private static final String trustStoreFile = "truststore"; 64 private static final String passwd = "passphrase"; 65 66 /* 67 * Turn on SSL debugging? 68 */ 69 private static final boolean debug = false; 70 71 /* 72 * Is the server ready to serve? 73 */ 74 private static final CountDownLatch serverCondition = new CountDownLatch(1); 75 76 /* 77 * Is the client ready to handshake? 78 */ 79 private static final CountDownLatch clientCondition = new CountDownLatch(1); 80 81 /* 82 * What's the server port? Use any free port by default 83 */ 84 private volatile int serverPort = 0; 85 86 /* 87 * If the client or server is doing some kind of object creation 88 * that the other side depends on, and that thread prematurely 89 * exits, you may experience a hang. The test harness will 90 * terminate all hung threads after its timeout has expired, 91 * currently 3 minutes by default, but you might try to be 92 * smart about it.... 93 */ 94 95 /* 96 * Define the server side of the test. 97 */ 98 void doServerSide() throws Exception { 99 SSLServerSocket sslServerSocket; 100 101 // kick start the server side service 102 SSLServerSocketFactory sslssf = 103 (SSLServerSocketFactory)SSLServerSocketFactory.getDefault(); 104 sslServerSocket = 105 (SSLServerSocket)sslssf.createServerSocket(serverPort); 106 107 serverPort = sslServerSocket.getLocalPort(); 108 109 // Signal the client, the server is ready to accept connection. 110 serverCondition.countDown(); 111 112 113 // Try to accept a connection in 30 seconds. 114 SSLSocket sslSocket; 115 try { 116 sslServerSocket.setSoTimeout(30000); 117 sslSocket = (SSLSocket)sslServerSocket.accept(); 118 } catch (SocketTimeoutException ste) { 119 sslServerSocket.close(); 120 121 // Ignore the test case if no connection within 30 seconds. 122 System.out.println( 123 "No incoming client connection in 30 seconds. " + 124 "Ignore in server side."); 125 return; 126 } 127 128 // handle the connection 129 try { 130 // Is it the expected client connection? 131 // 132 // Naughty test cases or third party routines may try to 133 // connection to this server port unintentionally. In 134 // order to mitigate the impact of unexpected client 135 // connections and avoid intermittent failure, it should 136 // be checked that the accepted connection is really linked 137 // to the expected client. 138 boolean clientIsReady = 139 clientCondition.await(30L, TimeUnit.SECONDS); 140 141 if (clientIsReady) { 142 // Run the application in server side. 143 runServerApplication(sslSocket); 144 } else { // Otherwise, ignore 145 // We don't actually care about plain socket connections 146 // for TLS communication testing generally. Just ignore 147 // the test if the accepted connection is not linked to 148 // the expected client or the client connection timeout 149 // in 30 seconds. 150 System.out.println( 151 "The client is not the expected one or timeout. " + 152 "Ignore in server side."); 153 } 154 } finally { 155 sslSocket.close(); 156 sslServerSocket.close(); 157 } 158 } 159 160 /* 161 * Define the server side application of the test for the specified socket. 162 */ 163 void runServerApplication(SSLSocket socket) throws Exception { 164 // here comes the test logic 165 InputStream sslIS = socket.getInputStream(); 166 OutputStream sslOS = socket.getOutputStream(); 167 168 sslIS.read(); 169 sslOS.write(85); 170 sslOS.flush(); 171 } 172 173 /* 174 * Define the client side of the test. 175 */ 176 void doClientSide() throws Exception { 177 178 // Wait for server to get started. 179 // 180 // The server side takes care of the issue if the server cannot 181 // get started in 90 seconds. The client side would just ignore 182 // the test case if the serer is not ready. 183 boolean serverIsReady = 184 serverCondition.await(90L, TimeUnit.SECONDS); 185 if (!serverIsReady) { 186 System.out.println( 187 "The server is not ready yet in 90 seconds. " + 188 "Ignore in client side."); 189 return; 190 } 191 192 SSLSocketFactory sslsf = 193 (SSLSocketFactory)SSLSocketFactory.getDefault(); 194 try (SSLSocket sslSocket = (SSLSocket)sslsf.createSocket()) { 195 try { 196 sslSocket.connect( 197 new InetSocketAddress("localhost", serverPort), 15000); 198 } catch (IOException ioe) { 199 // The server side may be impacted by naughty test cases or 200 // third party routines, and cannot accept connections. 201 // 202 // Just ignore the test if the connection cannot be 203 // established. 204 System.out.println( 205 "Cannot make a connection in 15 seconds. " + 206 "Ignore in client side."); 207 return; 208 } 209 210 // OK, here the client and server get connected. 211 212 // Signal the server, the client is ready to communicate. 213 clientCondition.countDown(); 214 215 // There is still a chance in theory that the server thread may 216 // wait client-ready timeout and then quit. The chance should 217 // be really rare so we don't consider it until it becomes a 218 // real problem. 219 220 // Run the application in client side. 221 runClientApplication(sslSocket); 222 } 223 } 224 225 /* 226 * Define the server side application of the test for the specified socket. 227 */ 228 void runClientApplication(SSLSocket socket) throws Exception { 229 InputStream sslIS = socket.getInputStream(); 230 OutputStream sslOS = socket.getOutputStream(); 231 232 sslOS.write(280); 233 sslOS.flush(); 234 sslIS.read(); 235 } 236 237 /* 238 * ============================================================= 239 * The remainder is just support stuff 240 */ 241 242 private volatile Exception serverException = null; 243 private volatile Exception clientException = null; 244 245 public static void main(String[] args) throws Exception { 246 String keyFilename = 247 System.getProperty("test.src", ".") + "/" + pathToStores + 248 "/" + keyStoreFile; 249 String trustFilename = 250 System.getProperty("test.src", ".") + "/" + pathToStores + 251 "/" + trustStoreFile; 252 253 System.setProperty("javax.net.ssl.keyStore", keyFilename); 254 System.setProperty("javax.net.ssl.keyStorePassword", passwd); 255 System.setProperty("javax.net.ssl.trustStore", trustFilename); 256 System.setProperty("javax.net.ssl.trustStorePassword", passwd); 257 258 if (debug) { 259 System.setProperty("javax.net.debug", "all"); 260 } 261 262 /* 263 * Start the tests. 264 */ 265 new SSLSocketSample(); 266 } 267 268 private Thread clientThread = null; 269 private Thread serverThread = null; 270 271 /* 272 * Primary constructor, used to drive remainder of the test. 273 * 274 * Fork off the other side, then do your work. 275 */ 276 SSLSocketSample() throws Exception { 277 Exception startException = null; 278 try { 279 if (separateServerThread) { 280 startServer(true); 281 startClient(false); 282 } else { 283 startClient(true); 284 startServer(false); 285 } 286 } catch (Exception e) { 287 startException = e; 288 } 289 290 /* 291 * Wait for other side to close down. 292 */ 293 if (separateServerThread) { 294 if (serverThread != null) { 295 serverThread.join(); 296 } 297 } else { 298 if (clientThread != null) { 299 clientThread.join(); 300 } 301 } 302 303 /* 304 * When we get here, the test is pretty much over. 305 * Which side threw the error? 306 */ 307 Exception local; 308 Exception remote; 309 310 if (separateServerThread) { 311 remote = serverException; 312 local = clientException; 313 } else { 314 remote = clientException; 315 local = serverException; 316 } 317 318 Exception exception = null; 319 320 /* 321 * Check various exception conditions. 322 */ 323 if ((local != null) && (remote != null)) { 324 // If both failed, return the curthread's exception. 325 local.initCause(remote); 326 exception = local; 327 } else if (local != null) { 328 exception = local; 329 } else if (remote != null) { 330 exception = remote; 331 } else if (startException != null) { 332 exception = startException; 333 } 334 335 /* 336 * If there was an exception *AND* a startException, 337 * output it. 338 */ 339 if (exception != null) { 340 if (exception != startException && startException != null) { 341 exception.addSuppressed(startException); 342 } 343 throw exception; 344 } 345 346 // Fall-through: no exception to throw! 347 } 348 349 void startServer(boolean newThread) throws Exception { 350 if (newThread) { 351 serverThread = new Thread() { 352 @Override 353 public void run() { 354 try { 355 doServerSide(); 356 } catch (Exception e) { 357 /* 358 * Our server thread just died. 359 * 360 * Release the client, if not active already... 361 */ 362 System.out.println("Server died: " + e); 363 serverException = e; 364 } 365 } 366 }; 367 serverThread.start(); 368 } else { 369 try { 370 doServerSide(); 371 } catch (Exception e) { 372 System.out.println("Server failed: " + e); 373 serverException = e; 374 } 375 } 376 } 377 378 void startClient(boolean newThread) throws Exception { 379 if (newThread) { 380 clientThread = new Thread() { 381 @Override 382 public void run() { 383 try { 384 doClientSide(); 385 } catch (Exception e) { 386 /* 387 * Our client thread just died. 388 */ 389 System.out.println("Client died: " + e); 390 clientException = e; 391 } 392 } 393 }; 394 clientThread.start(); 395 } else { 396 try { 397 doClientSide(); 398 } catch (Exception e) { 399 System.out.println("Client failed: " + e); 400 clientException = e; 401 } 402 } 403 } 404 }