jdk/src/share/classes/sun/security/ssl/SSLSessionContextImpl.java
changeset 2 90ce3da70b43
child 2060 75e464ce81af
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/security/ssl/SSLSessionContextImpl.java	Sat Dec 01 00:00:00 2007 +0000
@@ -0,0 +1,257 @@
+/*
+ * Copyright 1999-2007 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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.
+     */
+    public SSLSession   getSession(byte[] id)
+    {
+        SSLSession sess = (SSLSession) sessionCache.get(
+                                new SessionId(id));
+        return checkTimeValidity(sess);
+    }
+
+    /**
+     * 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.
+     */
+    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;
+    }
+}