Path: blob/master/test/jdk/javax/net/ssl/SSLSession/SessionCacheSizeTests.java
41152 views
/*1* Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223//24// SunJSSE does not support dynamic system properties, no way to re-use25// system properties in samevm/agentvm mode.26//2728/*29* @test30* @bug 436680731* @summary Need new APIs to get/set session timeout and session cache size.32* @run main/othervm SessionCacheSizeTests33*/3435import java.io.*;36import java.net.*;37import javax.net.ssl.*;38import java.util.*;39import java.security.*;4041/**42* Session cache size tests cover the following cases:43* 1. Effect of system property javax.net.ssl.SessionCacheSize (this44* property is not documented for public).45* 2. Reducing the cache size, results in uncaching of sessions if #of46* sessions present exceeds the new size.47* 3. Increasing the cache size, results in accomodating new sessions if the48* number of cached sessions is the current size limit.49*50* Invairant for passing this test is, at any given time,51* #cached_sessions <= current_cache_size , for current_cache_size > 052*/5354public class SessionCacheSizeTests {5556/*57* =============================================================58* Set the various variables needed for the tests, then59* specify what tests to run on each side.60*/6162/*63* Should we run the client or server in a separate thread?64* Both sides can throw exceptions, but do you have a preference65* as to which side should be the main thread.66*/67static boolean separateServerThread = true;6869/*70* Where do we find the keystores?71*/72static String pathToStores = "../etc";73static String keyStoreFile = "keystore";74static String trustStoreFile = "truststore";75static String passwd = "passphrase";7677/*78* Is the server ready to serve?79*/80volatile static boolean serverReady = false;8182/*83* Turn on SSL debugging?84*/85static boolean debug = false;8687/*88* If the client or server is doing some kind of object creation89* that the other side depends on, and that thread prematurely90* exits, you may experience a hang. The test harness will91* terminate all hung threads after its timeout has expired,92* currently 3 minutes by default, but you might try to be93* smart about it....94*/9596/*97* Define the server side of the test.98*99* If the server prematurely exits, serverReady will be set to true100* to avoid infinite hangs.101*/102103/*104* A limit on the number of connections at any given time105*/106static int MAX_ACTIVE_CONNECTIONS = 4;107108static final int FREE_PORT = 0;109110void doServerSide(int serverConns) throws Exception {111try (SSLServerSocket sslServerSocket =112(SSLServerSocket) sslssf.createServerSocket(FREE_PORT)) {113114// timeout to accept a connection115sslServerSocket.setSoTimeout(45000);116117// make sure createdPorts++ is atomic118synchronized(serverPorts) {119int serverPort = sslServerSocket.getLocalPort();120System.out.printf("server #%d started on port %d%n",121createdPorts, serverPort);122serverPorts[createdPorts++] = serverPort;123124/*125* Signal Client, we're ready for his connect.126*/127if (createdPorts == serverPorts.length) {128serverReady = true;129}130}131int read = 0;132int nConnections = 0;133134/*135* Divide the max connections among the available server ports.136* The use of more than one server port ensures creation of more137* than one session.138*/139SSLSession sessions [] = new SSLSession [serverConns];140SSLSessionContext sessCtx = sslctx.getServerSessionContext();141142while (nConnections < serverConns) {143try (SSLSocket sslSocket =144(SSLSocket)sslServerSocket.accept()) {145sslSocket.setSoTimeout(90000); // timeout to read146InputStream sslIS = sslSocket.getInputStream();147OutputStream sslOS = sslSocket.getOutputStream();148read = sslIS.read();149sessions[nConnections] = sslSocket.getSession();150sslOS.write(85);151sslOS.flush();152nConnections++;153}154}155}156}157158/*159* Define the client side of the test.160*161* If the server prematurely exits, serverReady will be set to true162* to avoid infinite hangs.163*/164void doClientSide() throws Exception {165166/*167* Wait for server to get started.168*/169while (!serverReady) {170Thread.sleep(50);171}172173int nConnections = 0;174SSLSocket sslSockets[] = new SSLSocket [MAX_ACTIVE_CONNECTIONS];175Vector sessions = new Vector();176SSLSessionContext sessCtx = sslctx.getClientSessionContext();177sessCtx.setSessionTimeout(0); // no limit178179try {180while (nConnections < (MAX_ACTIVE_CONNECTIONS - 1)) {181// divide the connections among the available server ports182int serverPort = serverPorts [nConnections % (serverPorts.length)];183System.out.printf("client #%d connects to port %d%n",184nConnections, serverPort);185sslSockets[nConnections] = (SSLSocket) sslsf.186createSocket("localhost",187serverPort);188InputStream sslIS = sslSockets[nConnections].getInputStream();189OutputStream sslOS = sslSockets[nConnections].getOutputStream();190sslOS.write(237);191sslOS.flush();192int read = sslIS.read();193SSLSession sess = sslSockets[nConnections].getSession();194if (!sessions.contains(sess))195sessions.add(sess);196nConnections++;197}198System.out.println("Current cacheSize is set to: " +199sessCtx.getSessionCacheSize());200System.out.println();201System.out.println("Currently cached Sessions......");202System.out.println("============================================"203+ "============================");204System.out.println("Session "205+ " Session-last-accessTime");206System.out.println("============================================"207+ "============================");208checkCachedSessions(sessCtx, nConnections);209// Change session cache size210sessCtx.setSessionCacheSize(2);211System.out.println("Session cache size changed to: "212+ sessCtx.getSessionCacheSize());213System.out.println();214checkCachedSessions(sessCtx, nConnections);215216// Test the effect of increasing the cache size217sessCtx.setSessionCacheSize(3);218System.out.println("Session cache size changed to: "219+ sessCtx.getSessionCacheSize());220// create a new session221int serverPort = serverPorts [nConnections % (serverPorts.length)];222System.out.printf("client #%d connects to port %d%n",223nConnections, serverPort);224sslSockets[nConnections] = (SSLSocket) sslsf.225createSocket("localhost",226serverPort);227InputStream sslIS = sslSockets[nConnections].getInputStream();228OutputStream sslOS = sslSockets[nConnections].getOutputStream();229sslOS.write(237);230sslOS.flush();231int read = sslIS.read();232SSLSession sess = sslSockets[nConnections].getSession();233if (!sessions.contains(sess))234sessions.add(sess);235nConnections++;236237// test the number of sessions cached against the cache size238checkCachedSessions(sessCtx, nConnections);239} finally {240for (int i = 0; i < nConnections; i++) {241if (sslSockets[i] != null) {242sslSockets[i].close();243}244}245}246System.out.println("Session cache size tests passed");247}248249void checkCachedSessions(SSLSessionContext sessCtx,250int nConn) throws Exception {251int nSessions = 0;252Enumeration e = sessCtx.getIds();253int cacheSize = sessCtx.getSessionCacheSize();254SSLSession sess;255256while (e.hasMoreElements()) {257sess = sessCtx.getSession((byte[]) e.nextElement());258long lastAccessedTime = sess.getLastAccessedTime();259System.out.println(sess + " "260+ new Date(lastAccessedTime));261262nSessions++;263}264System.out.println("--------------------------------------------"265+ "----------------------------");266if ((cacheSize > 0) && (nSessions > cacheSize)) {267268// close all active connections before exiting269for (int conn = nConn; conn < MAX_ACTIVE_CONNECTIONS; conn++) {270SSLSocket s = (SSLSocket) sslsf.createSocket("localhost",271serverPorts [conn % (serverPorts.length)]);272s.close();273}274throw new Exception("Session cache size test failed,"275+ " current cache size: " + cacheSize + " #sessions cached: "276+ nSessions);277}278}279280/*281* =============================================================282* The remainder is just support stuff283*/284285/*286* #of ports > 1, guarantees creation of more than one session.287* Using four ports (one per each connection), we are able to create288* alteast four sessions.289*/290int serverPorts[] = new int[]{0, 0, 0, 0}; // MAX_ACTIVE_CONNECTIONS: 4291int createdPorts = 0;292static SSLServerSocketFactory sslssf;293static SSLSocketFactory sslsf;294static SSLContext sslctx;295296volatile Exception serverException = null;297volatile Exception clientException = null;298299public static void main(String[] args) throws Exception {300String keyFilename =301System.getProperty("test.src", "./") + "/" + pathToStores +302"/" + keyStoreFile;303String trustFilename =304System.getProperty("test.src", "./") + "/" + pathToStores +305"/" + trustStoreFile;306307System.setProperty("javax.net.ssl.keyStore", keyFilename);308System.setProperty("javax.net.ssl.keyStorePassword", passwd);309System.setProperty("javax.net.ssl.trustStore", trustFilename);310System.setProperty("javax.net.ssl.trustStorePassword", passwd);311312// test the effect of javax.net.ssl.sessionCacheSize313System.setProperty("javax.net.ssl.sessionCacheSize", String.valueOf(0));314315sslctx = SSLContext.getInstance("TLS");316KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");317KeyStore ks = KeyStore.getInstance("JKS");318try (FileInputStream fis = new FileInputStream(keyFilename)) {319ks.load(fis, passwd.toCharArray());320}321kmf.init(ks, passwd.toCharArray());322sslctx.init(kmf.getKeyManagers(), null, null);323sslssf = (SSLServerSocketFactory) sslctx.getServerSocketFactory();324sslsf = (SSLSocketFactory) sslctx.getSocketFactory();325if (debug)326System.setProperty("javax.net.debug", "all");327328/*329* Start the tests.330*/331new SessionCacheSizeTests();332}333334Thread clientThread = null;335Thread serverThread = null;336337/*338* Primary constructor, used to drive remainder of the test.339*340* Fork off the other side, then do your work.341*/342SessionCacheSizeTests() throws Exception {343/*344* create the SSLServerSocket and SSLSocket factories345*/346347/*348* Divide the max connections among the available server ports.349* The use of more than one server port ensures creation of more350* than one session.351*/352int serverConns = MAX_ACTIVE_CONNECTIONS / (serverPorts.length);353int remainingConns = MAX_ACTIVE_CONNECTIONS % (serverPorts.length);354355Exception startException = null;356try {357if (separateServerThread) {358for (int i = 0; i < serverPorts.length; i++) {359// distribute remaining connections among the360// available ports361if (i < remainingConns) {362startServer(serverConns + 1, true);363} else {364startServer(serverConns, true);365}366}367startClient(false);368} else {369startClient(true);370for (int i = 0; i < serverPorts.length; i++) {371if (i < remainingConns) {372startServer(serverConns + 1, false);373} else {374startServer(serverConns, false);375}376}377}378} catch (Exception e) {379startException = e;380}381382/*383* Wait for other side to close down.384*/385if (separateServerThread) {386if (serverThread != null) {387serverThread.join();388}389} else {390if (clientThread != null) {391clientThread.join();392}393}394395/*396* When we get here, the test is pretty much over.397*/398Exception local;399Exception remote;400401if (separateServerThread) {402remote = serverException;403local = clientException;404} else {405remote = clientException;406local = serverException;407}408409Exception exception = null;410411/*412* Check various exception conditions.413*/414if ((local != null) && (remote != null)) {415// If both failed, return the curthread's exception.416local.initCause(remote);417exception = local;418} else if (local != null) {419exception = local;420} else if (remote != null) {421exception = remote;422} else if (startException != null) {423exception = startException;424}425426/*427* If there was an exception *AND* a startException,428* output it.429*/430if (exception != null) {431if (exception != startException && startException != null) {432exception.addSuppressed(startException);433}434throw exception;435}436437// Fall-through: no exception to throw!438}439440void startServer(final int nConns, boolean newThread) throws Exception {441if (newThread) {442serverThread = new Thread() {443public void run() {444try {445doServerSide(nConns);446} catch (Exception e) {447/*448* Our server thread just died.449*450* Release the client, if not active already...451*/452System.err.println("Server died...");453e.printStackTrace();454serverReady = true;455serverException = e;456}457}458};459serverThread.start();460} else {461try {462doServerSide(nConns);463} catch (Exception e) {464serverException = e;465} finally {466serverReady = true;467}468}469}470471void startClient(boolean newThread)472throws Exception {473if (newThread) {474clientThread = new Thread() {475public void run() {476try {477doClientSide();478} catch (Exception e) {479/*480* Our client thread just died.481*/482System.err.println("Client died...");483clientException = e;484}485}486};487clientThread.start();488} else {489try {490doClientSide();491} catch (Exception e) {492clientException = e;493}494}495}496}497498499