/*
 * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */


package sun.security.ssl;

import java.io.*;
import java.net.*;
import java.util.Date;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.NoSuchElementException;
import java.util.Vector;

import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSessionContext;
import javax.net.ssl.SSLSessionBindingListener;
import javax.net.ssl.SSLSessionBindingEvent;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSession;

import sun.misc.Cache;


final class SSLSessionContextImpl implements SSLSessionContext
{
    private Cache       sessionCache = new Cache();
    private Cache       sessionHostPortCache = new Cache();
    private int         cacheLimit;
    private long        timeoutMillis;
    private static final Debug debug = Debug.getInstance("ssl");

    // file private
    SSLSessionContextImpl()
    {
        cacheLimit = getCacheLimit();
        timeoutMillis = 86400000; // default, 24 hours
    }

    
Returns the SSL session object associated with the specific session ID passed.
/** * Returns the SSL session object associated with the * specific session ID passed. */
public SSLSession getSession(byte[] id) { SSLSession sess = (SSLSession) sessionCache.get( new SessionId(id)); return checkTimeValidity(sess); }
Returns an enumeration of the active SSL sessions.
/** * Returns an enumeration of the active SSL sessions. */
public Enumeration<byte[]> getIds() { Vector<byte[]> v = new Vector<byte[]>(sessionCache.size()); SessionId sessId; for (Enumeration e = sessionCache.keys(); e.hasMoreElements(); ) { sessId = (SessionId) e.nextElement(); if (!isTimedout((SSLSession)sessionCache.get(sessId))) v.addElement(sessId.getId()); } return v.elements(); } public void setSessionTimeout(int seconds) throws IllegalArgumentException { if (seconds < 0) throw new IllegalArgumentException(); timeoutMillis = seconds * 1000L; } public int getSessionTimeout() { return (int) (timeoutMillis / 1000); } public void setSessionCacheSize(int size) throws IllegalArgumentException { if (size < 0) throw new IllegalArgumentException(); cacheLimit = size; /** * If cache size limit is reduced, when the cache is full to its * previous limit, trim the cache before its contents * are used. */ if ((cacheLimit != 0) && (sessionCache.size() > cacheLimit)) adjustCacheSizeTo(cacheLimit); } public int getSessionCacheSize() { return cacheLimit; } SSLSessionImpl get(byte[] id) { return (SSLSessionImpl) getSession(id); }
Returns the SSL session object associated with the specific host name and port number passed.
/** * Returns the SSL session object associated with the * specific host name and port number passed. */
SSLSessionImpl get(String hostname, int port) { /* * If no session caching info is available, we won't * get one, so exit before doing a lookup. */ if (hostname == null && port == -1) { return null; } SSLSession sess = (SSLSessionImpl) sessionHostPortCache .get(getKey(hostname, port)); return (SSLSessionImpl) checkTimeValidity(sess); } private String getKey(String hostname, int port) { return (hostname + ":" + String.valueOf(port)) .toLowerCase(); } void put(SSLSessionImpl s) { // make space for the new session to be added if ((cacheLimit != 0) && (sessionCache.size() >= cacheLimit)) adjustCacheSizeTo(cacheLimit - 1); /* * Can always add the session id. */ sessionCache.put(s.getSessionId(), s); /* * If no hostname/port info is available, don't add this one. */ if ((s.getPeerHost() != null) && (s.getPeerPort() != -1)) { sessionHostPortCache.put( getKey(s.getPeerHost(), s.getPeerPort()), s); } s.setContext(this); } private void adjustCacheSizeTo(int targetSize) { int cacheSize = sessionCache.size(); if (targetSize < 0) return; while (cacheSize > targetSize) { SSLSessionImpl lru = null; SSLSessionImpl s = null; Enumeration e; if (debug != null && Debug.isOn("sessioncache")) { System.out.println("exceeded cache limit of " + cacheLimit); } /* * Count the number of elements in the cache. The size() method * does not reflect the cache entries that are no longer available, * i.e entries that are garbage collected (the cache entries are * held using soft references and are garbage collected when not * in use). */ int count; for (count = 0, e = sessionCache.elements(); e.hasMoreElements(); count++) { try { s = (SSLSessionImpl)e.nextElement(); } catch (NoSuchElementException nsee) { break; } if (isTimedout(s)) { lru = s; break; } else if ((lru == null) || (s.getLastAccessedTime() < lru.getLastAccessedTime())) { lru = s; } } if ((lru != null) && (count > targetSize)) { if (debug != null && Debug.isOn("sessioncache")) { System.out.println("uncaching " + lru); } lru.invalidate(); count--; // element removed from the cache } cacheSize = count; } } // file private void remove(SessionId key) { SSLSessionImpl s = (SSLSessionImpl) sessionCache.get(key); sessionCache.remove(key); sessionHostPortCache.remove(getKey(s.getPeerHost(), s.getPeerPort())); } private int getCacheLimit() { int cacheLimit = 0; try { String s = java.security.AccessController.doPrivileged( new java.security.PrivilegedAction<String>() { public String run() { return System.getProperty( "javax.net.ssl.sessionCacheSize"); } }); cacheLimit = (s != null) ? Integer.valueOf(s).intValue() : 0; } catch (Exception e) { } return (cacheLimit > 0) ? cacheLimit : 0; } SSLSession checkTimeValidity(SSLSession sess) { if (isTimedout(sess)) { sess.invalidate(); return null; } else return sess; } boolean isTimedout(SSLSession sess) { if (timeoutMillis == 0) return false; if ((sess != null) && ((sess.getCreationTime() + timeoutMillis) <= (System.currentTimeMillis()))) return true; return false; } }