diff --git a/jdk/src/share/classes/sun/security/ssl/AppInputStream.java b/jdk/src/share/classes/sun/security/ssl/AppInputStream.java
index d638b8f46e9..2ca889593c0 100644
--- a/jdk/src/share/classes/sun/security/ssl/AppInputStream.java
+++ b/jdk/src/share/classes/sun/security/ssl/AppInputStream.java
@@ -1,5 +1,5 @@
/*
- * Copyright 1996-2007 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 1996-2009 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
@@ -81,6 +81,14 @@ class AppInputStream extends InputStream {
*/
public synchronized int read(byte b[], int off, int len)
throws IOException {
+ if (b == null) {
+ throw new NullPointerException();
+ } else if (off < 0 || len < 0 || len > b.length - off) {
+ throw new IndexOutOfBoundsException();
+ } else if (len == 0) {
+ return 0;
+ }
+
if (c.checkEOF()) {
return -1;
}
diff --git a/jdk/src/share/classes/sun/security/ssl/AppOutputStream.java b/jdk/src/share/classes/sun/security/ssl/AppOutputStream.java
index d039cacb8b2..d8c78a8eb50 100644
--- a/jdk/src/share/classes/sun/security/ssl/AppOutputStream.java
+++ b/jdk/src/share/classes/sun/security/ssl/AppOutputStream.java
@@ -1,5 +1,5 @@
/*
- * Copyright 1996-2007 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 1996-2009 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
@@ -58,18 +58,25 @@ class AppOutputStream extends OutputStream {
*/
synchronized public void write(byte b[], int off, int len)
throws IOException {
+ if (b == null) {
+ throw new NullPointerException();
+ } else if (off < 0 || len < 0 || len > b.length - off) {
+ throw new IndexOutOfBoundsException();
+ } else if (len == 0) {
+ return;
+ }
+
// check if the Socket is invalid (error or closed)
c.checkWrite();
- //
+
// Always flush at the end of each application level record.
// This lets application synchronize read and write streams
// however they like; if we buffered here, they couldn't.
- //
- // NOTE: *must* call c.writeRecord() even for len == 0
try {
do {
int howmuch = Math.min(len, r.availableDataBytes());
+ // NOTE: *must* call c.writeRecord() even for howmuch == 0
if (howmuch > 0) {
r.write(b, off, howmuch);
off += howmuch;
diff --git a/jdk/src/share/classes/sun/security/ssl/ByteBufferInputStream.java b/jdk/src/share/classes/sun/security/ssl/ByteBufferInputStream.java
index 9c484d87ed3..d69e2bfdc54 100644
--- a/jdk/src/share/classes/sun/security/ssl/ByteBufferInputStream.java
+++ b/jdk/src/share/classes/sun/security/ssl/ByteBufferInputStream.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2003-2009 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
@@ -89,8 +89,7 @@ class ByteBufferInputStream extends InputStream {
if (b == null) {
throw new NullPointerException();
- } else if ((off < 0) || (off > b.length) || (len < 0) ||
- ((off + len) > b.length) || ((off + len) < 0)) {
+ } else if (off < 0 || len < 0 || len > b.length - off) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return 0;
diff --git a/jdk/src/share/classes/sun/security/ssl/SSLSessionContextImpl.java b/jdk/src/share/classes/sun/security/ssl/SSLSessionContextImpl.java
index c98f1cc2c26..3aeef2d8eee 100644
--- a/jdk/src/share/classes/sun/security/ssl/SSLSessionContextImpl.java
+++ b/jdk/src/share/classes/sun/security/ssl/SSLSessionContextImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright 1999-2007 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 1999-2009 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
@@ -41,88 +41,112 @@ import javax.net.ssl.SSLSessionBindingEvent;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSession;
-import sun.misc.Cache;
+import sun.security.util.Cache;
-final class SSLSessionContextImpl implements SSLSessionContext
-{
- private Cache sessionCache = new Cache();
- private Cache sessionHostPortCache = new Cache();
- private int cacheLimit;
- private long timeoutMillis;
+final class SSLSessionContextImpl implements SSLSessionContext {
+ private Cache sessionCache; // session cache, session id as key
+ private Cache sessionHostPortCache; // session cache, "host:port" as key
+ private int cacheLimit; // the max cache size
+ private int timeout; // timeout in seconds
+
private static final Debug debug = Debug.getInstance("ssl");
- // file private
- SSLSessionContextImpl()
- {
- cacheLimit = getCacheLimit();
- timeoutMillis = 86400000; // default, 24 hours
+ // package private
+ SSLSessionContextImpl() {
+ cacheLimit = getDefaultCacheLimit(); // default cache size
+ timeout = 86400; // default, 24 hours
+
+ // use soft reference
+ sessionCache = Cache.newSoftMemoryCache(cacheLimit, timeout);
+ sessionHostPortCache = Cache.newSoftMemoryCache(cacheLimit, timeout);
}
/**
- * Returns the SSL session object associated with the
- * specific session ID passed.
+ * Returns the SSLSession bound to the specified session id.
*/
- public SSLSession getSession(byte[] id)
- {
- SSLSession sess = (SSLSession) sessionCache.get(
- new SessionId(id));
- return checkTimeValidity(sess);
+ public SSLSession getSession(byte[] sessionId) {
+ if (sessionId == null) {
+ throw new NullPointerException("session id cannot be null");
+ }
+
+ SSLSessionImpl sess =
+ (SSLSessionImpl)sessionCache.get(new SessionId(sessionId));
+ if (!isTimedout(sess)) {
+ return sess;
+ }
+
+ return null;
}
/**
* Returns an enumeration of the active SSL sessions.
*/
public Enumeration getIds() {
- Vector v = new Vector(sessionCache.size());
- SessionId sessId;
+ SessionCacheVisitor scVisitor = new SessionCacheVisitor();
+ sessionCache.accept(scVisitor);
- for (Enumeration e = sessionCache.keys(); e.hasMoreElements(); ) {
- sessId = (SessionId) e.nextElement();
- if (!isTimedout((SSLSession)sessionCache.get(sessId)))
- v.addElement(sessId.getId());
- }
- return v.elements();
+ return scVisitor.getSessionIds();
}
+ /**
+ * Sets the timeout limit for cached SSLSession objects
+ *
+ * Note that after reset the timeout, the cached session before
+ * should be timed within the shorter one of the old timeout and the
+ * new timeout.
+ */
public void setSessionTimeout(int seconds)
throws IllegalArgumentException {
- if (seconds < 0)
+ if (seconds < 0) {
throw new IllegalArgumentException();
- timeoutMillis = seconds * 1000L;
+ }
+
+ if (timeout != seconds) {
+ sessionCache.setTimeout(seconds);
+ sessionHostPortCache.setTimeout(seconds);
+ timeout = seconds;
+ }
}
+ /**
+ * Gets the timeout limit for cached SSLSession objects
+ */
public int getSessionTimeout() {
- return (int) (timeoutMillis / 1000);
+ return timeout;
}
+ /**
+ * Sets the size of the cache used for storing
+ * SSLSession objects.
+ */
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);
+ if (cacheLimit != size) {
+ sessionCache.setCapacity(size);
+ sessionHostPortCache.setCapacity(size);
+ cacheLimit = size;
+ }
}
+ /**
+ * Gets the size of the cache used for storing
+ * SSLSession objects.
+ */
public int getSessionCacheSize() {
return cacheLimit;
}
+
+ // package-private method, used ONLY by ServerHandshaker
SSLSessionImpl get(byte[] id) {
- return (SSLSessionImpl) getSession(id);
+ return (SSLSessionImpl)getSession(id);
}
- /**
- * Returns the SSL session object associated with the
- * specific host name and port number passed.
- */
+ // package-private method, used ONLY by ClientHandshaker
SSLSessionImpl get(String hostname, int port) {
/*
* If no session caching info is available, we won't
@@ -131,96 +155,51 @@ final class SSLSessionContextImpl implements SSLSessionContext
if (hostname == null && port == -1) {
return null;
}
- SSLSession sess = (SSLSessionImpl) sessionHostPortCache
- .get(getKey(hostname, port));
- return (SSLSessionImpl) checkTimeValidity(sess);
+
+ SSLSessionImpl sess =
+ (SSLSessionImpl)sessionHostPortCache.get(getKey(hostname, port));
+ if (!isTimedout(sess)) {
+ return sess;
+ }
+
+ return null;
}
private String getKey(String hostname, int port) {
- return (hostname + ":" + String.valueOf(port))
- .toLowerCase();
+ return (hostname + ":" + String.valueOf(port)).toLowerCase();
}
+ // cache a SSLSession
+ //
+ // In SunJSSE implementation, a session is created while getting a
+ // client hello or a server hello message, and cached while the
+ // handshaking finished.
+ // Here we time the session from the time it cached instead of the
+ // time it created, which is a little longer than the expected. So
+ // please do check isTimedout() while getting entry from the cache.
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 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;
+ // package-private method, remove a cached SSLSession
+ void remove(SessionId key) {
+ SSLSessionImpl s = (SSLSessionImpl)sessionCache.get(key);
+ if (s != null) {
+ sessionCache.remove(key);
+ sessionHostPortCache.remove(
+ getKey(s.getPeerHost(), s.getPeerPort()));
}
}
- // 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() {
+ private int getDefaultCacheLimit() {
int cacheLimit = 0;
try {
String s = java.security.AccessController.doPrivileged(
@@ -237,21 +216,40 @@ final class SSLSessionContextImpl implements SSLSessionContext
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)
+ if (timeout == 0) {
return false;
- if ((sess != null) &&
- ((sess.getCreationTime() + timeoutMillis)
- <= (System.currentTimeMillis())))
+ }
+
+ if ((sess != null) && ((sess.getCreationTime() + timeout * 1000L)
+ <= (System.currentTimeMillis()))) {
+ sess.invalidate();
return true;
+ }
+
return false;
}
+
+ final class SessionCacheVisitor
+ implements sun.security.util.Cache.CacheVisitor {
+ Vector ids = null;
+
+ // public void visit(java.util.Map