--- a/jdk/make/docs/Makefile Fri Nov 18 16:57:01 2011 -0800
+++ b/jdk/make/docs/Makefile Mon Nov 28 15:15:50 2011 -0800
@@ -71,7 +71,7 @@
ifeq ($(ARCH_DATA_MODEL),64)
MAX_VM_MEMORY = 1024
else
- MAX_VM_MEMORY = 512
+ MAX_VM_MEMORY = 612
endif
# List of all possible directories for javadoc to look for sources
--- a/jdk/src/share/classes/java/io/FileInputStream.java Fri Nov 18 16:57:01 2011 -0800
+++ b/jdk/src/share/classes/java/io/FileInputStream.java Mon Nov 28 15:15:50 2011 -0800
@@ -124,7 +124,7 @@
throw new NullPointerException();
}
fd = new FileDescriptor();
- fd.incrementAndGetUseCount();
+ fd.attach(this);
open(name);
}
@@ -164,10 +164,9 @@
/*
* FileDescriptor is being shared by streams.
- * Ensure that it's GC'ed only when all the streams/channels are done
- * using it.
+ * Register this stream with FileDescriptor tracker.
*/
- fd.incrementAndGetUseCount();
+ fd.attach(this);
}
/**
@@ -294,27 +293,14 @@
closed = true;
}
if (channel != null) {
- /*
- * Decrement the FD use count associated with the channel
- * The use count is incremented whenever a new channel
- * is obtained from this stream.
- */
- fd.decrementAndGetUseCount();
channel.close();
}
- /*
- * Decrement the FD use count associated with this stream
- */
- int useCount = fd.decrementAndGetUseCount();
-
- /*
- * If FileDescriptor is still in use by another stream, we
- * will not close it.
- */
- if (useCount <= 0) {
- close0();
- }
+ fd.closeAll(new Closeable() {
+ public void close() throws IOException {
+ close0();
+ }
+ });
}
/**
@@ -328,7 +314,9 @@
* @see java.io.FileDescriptor
*/
public final FileDescriptor getFD() throws IOException {
- if (fd != null) return fd;
+ if (fd != null) {
+ return fd;
+ }
throw new IOException();
}
@@ -352,13 +340,6 @@
synchronized (this) {
if (channel == null) {
channel = FileChannelImpl.open(fd, true, false, this);
-
- /*
- * Increment fd's use count. Invoking the channel's close()
- * method will result in decrementing the use count set for
- * the channel.
- */
- fd.incrementAndGetUseCount();
}
return channel;
}
@@ -381,7 +362,12 @@
*/
protected void finalize() throws IOException {
if ((fd != null) && (fd != FileDescriptor.in)) {
- close();
+ /* if fd is shared, the references in FileDescriptor
+ * will ensure that finalizer is only called when
+ * safe to do so. All references using the fd have
+ * become unreachable. We can call close()
+ */
+ close();
}
}
}
--- a/jdk/src/share/classes/java/io/FileOutputStream.java Fri Nov 18 16:57:01 2011 -0800
+++ b/jdk/src/share/classes/java/io/FileOutputStream.java Mon Nov 28 15:15:50 2011 -0800
@@ -197,9 +197,9 @@
throw new NullPointerException();
}
this.fd = new FileDescriptor();
+ fd.attach(this);
this.append = append;
- fd.incrementAndGetUseCount();
open(name, append);
}
@@ -237,12 +237,7 @@
this.fd = fdObj;
this.append = false;
- /*
- * FileDescriptor is being shared by streams.
- * Ensure that it's GC'ed only when all the streams/channels are done
- * using it.
- */
- fd.incrementAndGetUseCount();
+ fd.attach(this);
}
/**
@@ -331,27 +326,14 @@
}
if (channel != null) {
- /*
- * Decrement FD use count associated with the channel
- * The use count is incremented whenever a new channel
- * is obtained from this stream.
- */
- fd.decrementAndGetUseCount();
channel.close();
}
- /*
- * Decrement FD use count associated with this stream
- */
- int useCount = fd.decrementAndGetUseCount();
-
- /*
- * If FileDescriptor is still in use by another stream, we
- * will not close it.
- */
- if (useCount <= 0) {
- close0();
- }
+ fd.closeAll(new Closeable() {
+ public void close() throws IOException {
+ close0();
+ }
+ });
}
/**
@@ -365,7 +347,9 @@
* @see java.io.FileDescriptor
*/
public final FileDescriptor getFD() throws IOException {
- if (fd != null) return fd;
+ if (fd != null) {
+ return fd;
+ }
throw new IOException();
}
@@ -390,13 +374,6 @@
synchronized (this) {
if (channel == null) {
channel = FileChannelImpl.open(fd, false, true, append, this);
-
- /*
- * Increment fd's use count. Invoking the channel's close()
- * method will result in decrementing the use count set for
- * the channel.
- */
- fd.incrementAndGetUseCount();
}
return channel;
}
@@ -415,7 +392,12 @@
if (fd == FileDescriptor.out || fd == FileDescriptor.err) {
flush();
} else {
- close();
+ /* if fd is shared, the references in FileDescriptor
+ * will ensure that finalizer is only called when
+ * safe to do so. All references using the fd have
+ * become unreachable. We can call close()
+ */
+ close();
}
}
}
--- a/jdk/src/share/classes/java/io/RandomAccessFile.java Fri Nov 18 16:57:01 2011 -0800
+++ b/jdk/src/share/classes/java/io/RandomAccessFile.java Mon Nov 28 15:15:50 2011 -0800
@@ -229,7 +229,7 @@
throw new NullPointerException();
}
fd = new FileDescriptor();
- fd.incrementAndGetUseCount();
+ fd.attach(this);
open(name, imode);
}
@@ -242,7 +242,9 @@
* @see java.io.FileDescriptor
*/
public final FileDescriptor getFD() throws IOException {
- if (fd != null) return fd;
+ if (fd != null) {
+ return fd;
+ }
throw new IOException();
}
@@ -268,17 +270,6 @@
synchronized (this) {
if (channel == null) {
channel = FileChannelImpl.open(fd, true, rw, this);
-
- /*
- * FileDescriptor could be shared by FileInputStream or
- * FileOutputStream.
- * Ensure that FD is GC'ed only when all the streams/channels
- * are done using it.
- * Increment fd's use count. Invoking the channel's close()
- * method will result in decrementing the use count set for
- * the channel.
- */
- fd.incrementAndGetUseCount();
}
return channel;
}
@@ -577,28 +568,14 @@
closed = true;
}
if (channel != null) {
- /*
- * Decrement FD use count associated with the channel. The FD use
- * count is incremented whenever a new channel is obtained from
- * this stream.
- */
- fd.decrementAndGetUseCount();
channel.close();
}
- /*
- * Decrement FD use count associated with this stream.
- * The count got incremented by FileDescriptor during its construction.
- */
- int useCount = fd.decrementAndGetUseCount();
-
- /*
- * If FileDescriptor is still in use by another stream, we
- * will not close it.
- */
- if (useCount <= 0) {
- close0();
- }
+ fd.closeAll(new Closeable() {
+ public void close() throws IOException {
+ close0();
+ }
+ });
}
//
--- a/jdk/src/share/classes/java/io/Writer.java Fri Nov 18 16:57:01 2011 -0800
+++ b/jdk/src/share/classes/java/io/Writer.java Mon Nov 28 15:15:50 2011 -0800
@@ -57,7 +57,7 @@
/**
* Size of writeBuffer, must be >= 1
*/
- private final int writeBufferSize = 1024;
+ private static final int WRITE_BUFFER_SIZE = 1024;
/**
* The object used to synchronize operations on this stream. For
@@ -107,7 +107,7 @@
public void write(int c) throws IOException {
synchronized (lock) {
if (writeBuffer == null){
- writeBuffer = new char[writeBufferSize];
+ writeBuffer = new char[WRITE_BUFFER_SIZE];
}
writeBuffer[0] = (char) c;
write(writeBuffer, 0, 1);
@@ -180,9 +180,9 @@
public void write(String str, int off, int len) throws IOException {
synchronized (lock) {
char cbuf[];
- if (len <= writeBufferSize) {
+ if (len <= WRITE_BUFFER_SIZE) {
if (writeBuffer == null) {
- writeBuffer = new char[writeBufferSize];
+ writeBuffer = new char[WRITE_BUFFER_SIZE];
}
cbuf = writeBuffer;
} else { // Don't permanently allocate very large buffers.
--- a/jdk/src/share/classes/java/lang/AssertionError.java Fri Nov 18 16:57:01 2011 -0800
+++ b/jdk/src/share/classes/java/lang/AssertionError.java Mon Nov 28 15:15:50 2011 -0800
@@ -71,7 +71,7 @@
* @see Throwable#getCause()
*/
public AssertionError(Object detailMessage) {
- this("" + detailMessage);
+ this(String.valueOf(detailMessage));
if (detailMessage instanceof Throwable)
initCause((Throwable) detailMessage);
}
@@ -85,7 +85,7 @@
* @param detailMessage value to be used in constructing detail message
*/
public AssertionError(boolean detailMessage) {
- this("" + detailMessage);
+ this(String.valueOf(detailMessage));
}
/**
@@ -97,7 +97,7 @@
* @param detailMessage value to be used in constructing detail message
*/
public AssertionError(char detailMessage) {
- this("" + detailMessage);
+ this(String.valueOf(detailMessage));
}
/**
@@ -109,7 +109,7 @@
* @param detailMessage value to be used in constructing detail message
*/
public AssertionError(int detailMessage) {
- this("" + detailMessage);
+ this(String.valueOf(detailMessage));
}
/**
@@ -121,7 +121,7 @@
* @param detailMessage value to be used in constructing detail message
*/
public AssertionError(long detailMessage) {
- this("" + detailMessage);
+ this(String.valueOf(detailMessage));
}
/**
@@ -133,7 +133,7 @@
* @param detailMessage value to be used in constructing detail message
*/
public AssertionError(float detailMessage) {
- this("" + detailMessage);
+ this(String.valueOf(detailMessage));
}
/**
@@ -145,7 +145,7 @@
* @param detailMessage value to be used in constructing detail message
*/
public AssertionError(double detailMessage) {
- this("" + detailMessage);
+ this(String.valueOf(detailMessage));
}
/**
--- a/jdk/src/share/classes/java/lang/Class.java Fri Nov 18 16:57:01 2011 -0800
+++ b/jdk/src/share/classes/java/lang/Class.java Mon Nov 28 15:15:50 2011 -0800
@@ -3008,7 +3008,7 @@
/**
* Casts this {@code Class} object to represent a subclass of the class
- * represented by the specified class object. Checks that that the cast
+ * represented by the specified class object. Checks that the cast
* is valid, and throws a {@code ClassCastException} if it is not. If
* this method succeeds, it always returns a reference to this class object.
*
--- a/jdk/src/share/classes/java/lang/Double.java Fri Nov 18 16:57:01 2011 -0800
+++ b/jdk/src/share/classes/java/lang/Double.java Mon Nov 28 15:15:50 2011 -0800
@@ -607,8 +607,7 @@
* @see java.lang.Double#valueOf(java.lang.String)
*/
public Double(String s) throws NumberFormatException {
- // REMIND: this is inefficient
- this(valueOf(s).doubleValue());
+ value = parseDouble(s);
}
/**
--- a/jdk/src/share/classes/java/lang/Float.java Fri Nov 18 16:57:01 2011 -0800
+++ b/jdk/src/share/classes/java/lang/Float.java Mon Nov 28 15:15:50 2011 -0800
@@ -529,8 +529,7 @@
* @see java.lang.Float#valueOf(java.lang.String)
*/
public Float(String s) throws NumberFormatException {
- // REMIND: this is inefficient
- this(valueOf(s).floatValue());
+ value = parseFloat(s);
}
/**
--- a/jdk/src/share/classes/java/security/Policy.java Fri Nov 18 16:57:01 2011 -0800
+++ b/jdk/src/share/classes/java/security/Policy.java Mon Nov 28 15:15:50 2011 -0800
@@ -28,6 +28,7 @@
import java.util.Enumeration;
import java.util.WeakHashMap;
+import java.util.concurrent.atomic.AtomicReference;
import sun.security.jca.GetInstance;
import sun.security.util.Debug;
import sun.security.util.SecurityConstants;
@@ -60,8 +61,8 @@
* with a standard type. The default policy type is "JavaPolicy".
*
* <p> Once a Policy instance has been installed (either by default, or by
- * calling <code>setPolicy</code>),
- * the Java runtime invokes its <code>implies</code> when it needs to
+ * calling <code>setPolicy</code>), the Java runtime invokes its
+ * <code>implies</code> method when it needs to
* determine whether executing code (encapsulated in a ProtectionDomain)
* can perform SecurityManager-protected operations. How a Policy object
* retrieves its policy data is up to the Policy implementation itself.
@@ -94,18 +95,33 @@
public static final PermissionCollection UNSUPPORTED_EMPTY_COLLECTION =
new UnsupportedEmptyCollection();
- /** the system-wide policy. */
- private static Policy policy; // package private for AccessControlContext
+ // Information about the system-wide policy.
+ private static class PolicyInfo {
+ // the system-wide policy
+ final Policy policy;
+ // a flag indicating if the system-wide policy has been initialized
+ final boolean initialized;
+
+ PolicyInfo(Policy policy, boolean initialized) {
+ this.policy = policy;
+ this.initialized = initialized;
+ }
+ }
+
+ // PolicyInfo is stored in an AtomicReference
+ private static AtomicReference<PolicyInfo> policy =
+ new AtomicReference<>(new PolicyInfo(null, false));
private static final Debug debug = Debug.getInstance("policy");
// Cache mapping ProtectionDomain.Key to PermissionCollection
private WeakHashMap<ProtectionDomain.Key, PermissionCollection> pdMapping;
- /** package private for AccessControlContext */
+ /** package private for AccessControlContext and ProtectionDomain */
static boolean isSet()
{
- return policy != null;
+ PolicyInfo pi = policy.get();
+ return pi.policy != null && pi.initialized == true;
}
private static void checkPermission(String type) {
@@ -143,80 +159,92 @@
/**
* Returns the installed Policy object, skipping the security check.
- * Used by SecureClassLoader and getPolicy.
+ * Used by ProtectionDomain and getPolicy.
*
* @return the installed Policy.
- *
*/
- static synchronized Policy getPolicyNoCheck()
+ static Policy getPolicyNoCheck()
{
- if (policy == null) {
- String policy_class = null;
- policy_class = AccessController.doPrivileged(
- new PrivilegedAction<String>() {
- public String run() {
- return Security.getProperty("policy.provider");
- }
- });
- if (policy_class == null) {
- policy_class = "sun.security.provider.PolicyFile";
- }
-
- try {
- policy = (Policy)
- Class.forName(policy_class).newInstance();
- } catch (Exception e) {
- /*
- * The policy_class seems to be an extension
- * so we have to bootstrap loading it via a policy
- * provider that is on the bootclasspath
- * If it loads then shift gears to using the configured
- * provider.
- */
-
- // install the bootstrap provider to avoid recursion
- policy = new sun.security.provider.PolicyFile();
-
- final String pc = policy_class;
- Policy p = AccessController.doPrivileged(
- new PrivilegedAction<Policy>() {
- public Policy run() {
- try {
- ClassLoader cl =
- ClassLoader.getSystemClassLoader();
- // we want the extension loader
- ClassLoader extcl = null;
- while (cl != null) {
- extcl = cl;
- cl = cl.getParent();
- }
- return (extcl != null ? (Policy)Class.forName(
- pc, true, extcl).newInstance() : null);
- } catch (Exception e) {
- if (debug != null) {
- debug.println("policy provider " +
- pc +
- " not available");
- e.printStackTrace();
- }
- return null;
- }
+ PolicyInfo pi = policy.get();
+ // Use double-check idiom to avoid locking if system-wide policy is
+ // already initialized
+ if (pi.initialized == false || pi.policy == null) {
+ synchronized (Policy.class) {
+ PolicyInfo pinfo = policy.get();
+ if (pinfo.policy == null) {
+ String policy_class = AccessController.doPrivileged(
+ new PrivilegedAction<String>() {
+ public String run() {
+ return Security.getProperty("policy.provider");
}
});
- /*
- * if it loaded install it as the policy provider. Otherwise
- * continue to use the system default implementation
- */
- if (p != null) {
- policy = p;
- } else {
- if (debug != null) {
- debug.println("using sun.security.provider.PolicyFile");
+ if (policy_class == null) {
+ policy_class = "sun.security.provider.PolicyFile";
}
+
+ try {
+ pinfo = new PolicyInfo(
+ (Policy) Class.forName(policy_class).newInstance(),
+ true);
+ } catch (Exception e) {
+ /*
+ * The policy_class seems to be an extension
+ * so we have to bootstrap loading it via a policy
+ * provider that is on the bootclasspath.
+ * If it loads then shift gears to using the configured
+ * provider.
+ */
+
+ // install the bootstrap provider to avoid recursion
+ Policy polFile = new sun.security.provider.PolicyFile();
+ pinfo = new PolicyInfo(polFile, false);
+ policy.set(pinfo);
+
+ final String pc = policy_class;
+ Policy pol = AccessController.doPrivileged(
+ new PrivilegedAction<Policy>() {
+ public Policy run() {
+ try {
+ ClassLoader cl =
+ ClassLoader.getSystemClassLoader();
+ // we want the extension loader
+ ClassLoader extcl = null;
+ while (cl != null) {
+ extcl = cl;
+ cl = cl.getParent();
+ }
+ return (extcl != null ? (Policy)Class.forName(
+ pc, true, extcl).newInstance() : null);
+ } catch (Exception e) {
+ if (debug != null) {
+ debug.println("policy provider " +
+ pc +
+ " not available");
+ e.printStackTrace();
+ }
+ return null;
+ }
+ }
+ });
+ /*
+ * if it loaded install it as the policy provider. Otherwise
+ * continue to use the system default implementation
+ */
+ if (pol != null) {
+ pinfo = new PolicyInfo(pol, true);
+ } else {
+ if (debug != null) {
+ debug.println("using sun.security.provider.PolicyFile");
+ }
+ pinfo = new PolicyInfo(polFile, true);
+ }
+ }
+ policy.set(pinfo);
}
+ return pinfo.policy;
}
}
- return policy;
+ return pi.policy;
}
/**
@@ -245,7 +273,7 @@
initPolicy(p);
}
synchronized (Policy.class) {
- Policy.policy = p;
+ policy.set(new PolicyInfo(p, p != null));
}
}
@@ -292,14 +320,14 @@
PermissionCollection policyPerms = null;
synchronized (p) {
if (p.pdMapping == null) {
- p.pdMapping =
- new WeakHashMap<ProtectionDomain.Key, PermissionCollection>();
+ p.pdMapping = new WeakHashMap<>();
}
}
if (policyDomain.getCodeSource() != null) {
- if (Policy.isSet()) {
- policyPerms = policy.getPermissions(policyDomain);
+ Policy pol = policy.get().policy;
+ if (pol != null) {
+ policyPerms = pol.getPermissions(policyDomain);
}
if (policyPerms == null) { // assume it has all
@@ -434,7 +462,7 @@
type,
params);
} catch (NoSuchAlgorithmException nsae) {
- return handleException (nsae);
+ return handleException(nsae);
}
}
@@ -494,7 +522,7 @@
type,
params);
} catch (NoSuchAlgorithmException nsae) {
- return handleException (nsae);
+ return handleException(nsae);
}
}
@@ -808,7 +836,7 @@
*
* @param permission the Permission object to compare.
*
- * @return true if "permission" is implied by the permissions in
+ * @return true if "permission" is implied by the permissions in
* the collection, false if not.
*/
@Override public boolean implies(Permission permission) {
--- a/jdk/src/share/classes/java/sql/PreparedStatement.java Fri Nov 18 16:57:01 2011 -0800
+++ b/jdk/src/share/classes/java/sql/PreparedStatement.java Mon Nov 28 15:15:50 2011 -0800
@@ -767,7 +767,7 @@
/**
- * Sets the designated paramter to the given <code>String</code> object.
+ * Sets the designated parameter to the given <code>String</code> object.
* The driver converts this to a SQL <code>NCHAR</code> or
* <code>NVARCHAR</code> or <code>LONGNVARCHAR</code> value
* (depending on the argument's
--- a/jdk/src/share/classes/java/sql/Statement.java Fri Nov 18 16:57:01 2011 -0800
+++ b/jdk/src/share/classes/java/sql/Statement.java Mon Nov 28 15:15:50 2011 -0800
@@ -991,7 +991,7 @@
/**
* Requests that a <code>Statement</code> be pooled or not pooled. The value
* specified is a hint to the statement pool implementation indicating
- * whether the applicaiton wants the statement to be pooled. It is up to
+ * whether the application wants the statement to be pooled. It is up to
* the statement pool manager as to whether the hint is used.
* <p>
* The poolable value of a statement is applicable to both internal
--- a/jdk/src/share/classes/java/util/concurrent/LinkedBlockingDeque.java Fri Nov 18 16:57:01 2011 -0800
+++ b/jdk/src/share/classes/java/util/concurrent/LinkedBlockingDeque.java Mon Nov 28 15:15:50 2011 -0800
@@ -742,6 +742,8 @@
throw new NullPointerException();
if (c == this)
throw new IllegalArgumentException();
+ if (maxElements <= 0)
+ return 0;
final ReentrantLock lock = this.lock;
lock.lock();
try {
--- a/jdk/src/share/classes/java/util/concurrent/LinkedBlockingQueue.java Fri Nov 18 16:57:01 2011 -0800
+++ b/jdk/src/share/classes/java/util/concurrent/LinkedBlockingQueue.java Mon Nov 28 15:15:50 2011 -0800
@@ -332,7 +332,7 @@
// Note: convention in all put/take/etc is to preset local var
// holding count negative to indicate failure unless set.
int c = -1;
- Node<E> node = new Node(e);
+ Node<E> node = new Node<E>(e);
final ReentrantLock putLock = this.putLock;
final AtomicInteger count = this.count;
putLock.lockInterruptibly();
@@ -412,7 +412,7 @@
if (count.get() == capacity)
return false;
int c = -1;
- Node<E> node = new Node(e);
+ Node<E> node = new Node<E>(e);
final ReentrantLock putLock = this.putLock;
putLock.lock();
try {
@@ -728,6 +728,8 @@
throw new NullPointerException();
if (c == this)
throw new IllegalArgumentException();
+ if (maxElements <= 0)
+ return 0;
boolean signalNotFull = false;
final ReentrantLock takeLock = this.takeLock;
takeLock.lock();
--- a/jdk/src/share/classes/java/util/jar/Attributes.java Fri Nov 18 16:57:01 2011 -0800
+++ b/jdk/src/share/classes/java/util/jar/Attributes.java Mon Nov 28 15:15:50 2011 -0800
@@ -629,7 +629,7 @@
public static final Name IMPLEMENTATION_VENDOR_ID = new Name("Implementation-Vendor-Id");
/**
- * <code>Name</code> object for <code>Implementation-Vendor-URL</code>
+ * <code>Name</code> object for <code>Implementation-URL</code>
* manifest attribute used for package versioning.
* @see <a href="../../../../technotes/guides/versioning/spec/versioning2.html#wp90779">
* Java Product Versioning Specification</a>
--- a/jdk/src/share/classes/sun/net/httpserver/ServerImpl.java Fri Nov 18 16:57:01 2011 -0800
+++ b/jdk/src/share/classes/sun/net/httpserver/ServerImpl.java Mon Nov 28 15:15:50 2011 -0800
@@ -402,10 +402,10 @@
} catch (IOException e) {
logger.log (Level.FINER, "Dispatcher (4)", e);
} catch (Exception e) {
- e.printStackTrace();
logger.log (Level.FINER, "Dispatcher (7)", e);
}
}
+ try {selector.close(); } catch (Exception e) {}
}
private void handleException (SelectionKey key, Exception e) {
--- a/jdk/src/share/classes/sun/rmi/registry/RegistryImpl.java Fri Nov 18 16:57:01 2011 -0800
+++ b/jdk/src/share/classes/sun/rmi/registry/RegistryImpl.java Mon Nov 28 15:15:50 2011 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2011, 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
@@ -29,6 +29,7 @@
import java.util.Hashtable;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
+import java.io.FilePermission;
import java.io.IOException;
import java.net.*;
import java.rmi.*;
@@ -54,7 +55,6 @@
import sun.rmi.transport.LiveRef;
import sun.rmi.transport.ObjectTable;
import sun.rmi.transport.Target;
-import sun.security.action.GetPropertyAction;
/**
* A "registry" exists on every node that allows RMI connections to
@@ -335,19 +335,6 @@
URL[] urls = sun.misc.URLClassPath.pathToURLs(envcp);
ClassLoader cl = new URLClassLoader(urls);
- String codebaseProperty = null;
- String prop = java.security.AccessController.doPrivileged(
- new GetPropertyAction("java.rmi.server.codebase"));
- if (prop != null && prop.trim().length() > 0) {
- codebaseProperty = prop;
- }
- URL[] codebaseURLs = null;
- if (codebaseProperty != null) {
- codebaseURLs = sun.misc.URLClassPath.pathToURLs(codebaseProperty);
- } else {
- codebaseURLs = new URL[0];
- }
-
/*
* Fix bugid 4242317: Classes defined by this class loader should
* be annotated with the value of the "java.rmi.server.codebase"
@@ -365,7 +352,7 @@
public RegistryImpl run() throws RemoteException {
return new RegistryImpl(regPort);
}
- }, getAccessControlContext(codebaseURLs));
+ }, getAccessControlContext());
} catch (PrivilegedActionException ex) {
throw (RemoteException) ex.getException();
}
@@ -391,11 +378,11 @@
}
/**
- * Generates an AccessControlContext from several URLs.
+ * Generates an AccessControlContext with minimal permissions.
* The approach used here is taken from the similar method
* getAccessControlContext() in the sun.applet.AppletPanel class.
*/
- private static AccessControlContext getAccessControlContext(URL[] urls) {
+ private static AccessControlContext getAccessControlContext() {
// begin with permissions granted to all code in current policy
PermissionCollection perms = AccessController.doPrivileged(
new java.security.PrivilegedAction<PermissionCollection>() {
@@ -420,17 +407,15 @@
perms.add(new RuntimePermission("accessClassInPackage.sun.*"));
- // add permissions required to load from codebase URL path
- LoaderHandler.addPermissionsForURLs(urls, perms, false);
+ perms.add(new FilePermission("<<ALL FILES>>", "read"));
/*
* Create an AccessControlContext that consists of a single
* protection domain with only the permissions calculated above.
*/
ProtectionDomain pd = new ProtectionDomain(
- new CodeSource((urls.length > 0 ? urls[0] : null),
- (java.security.cert.Certificate[]) null),
- perms);
+ new CodeSource(null,
+ (java.security.cert.Certificate[]) null), perms);
return new AccessControlContext(new ProtectionDomain[] { pd });
}
}
--- a/jdk/src/share/classes/sun/rmi/server/LoaderHandler.java Fri Nov 18 16:57:01 2011 -0800
+++ b/jdk/src/share/classes/sun/rmi/server/LoaderHandler.java Mon Nov 28 15:15:50 2011 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2011, 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
@@ -1031,7 +1031,7 @@
* loader. A given permission is only added to the collection if
* it is not already implied by the collection.
*/
- public static void addPermissionsForURLs(URL[] urls,
+ private static void addPermissionsForURLs(URL[] urls,
PermissionCollection perms,
boolean forLoader)
{
--- a/jdk/src/share/classes/sun/security/krb5/internal/KerberosTime.java Fri Nov 18 16:57:01 2011 -0800
+++ b/jdk/src/share/classes/sun/security/krb5/internal/KerberosTime.java Mon Nov 28 15:15:50 2011 -0800
@@ -68,8 +68,8 @@
private int microSeconds; // the last three digits of the microsecond value
// The time when this class is loaded. Used in setNow()
- private static final long initMilli = System.currentTimeMillis();
- private static final long initMicro = System.nanoTime() / 1000;
+ private static long initMilli = System.currentTimeMillis();
+ private static long initMicro = System.nanoTime() / 1000;
private static long syncTime;
private static boolean DEBUG = Krb5.DEBUG;
@@ -212,9 +212,22 @@
}
public void setNow() {
- long microElapsed = System.nanoTime() / 1000 - initMicro;
- setTime(initMilli + microElapsed/1000);
- microSeconds = (int)(microElapsed % 1000);
+ long newMilli = System.currentTimeMillis();
+ long newMicro = System.nanoTime() / 1000;
+ long microElapsed = newMicro - initMicro;
+ long calcMilli = initMilli + microElapsed/1000;
+ if (calcMilli - newMilli > 100 || newMilli - calcMilli > 100) {
+ if (DEBUG) {
+ System.out.println("System time adjusted");
+ }
+ initMilli = newMilli;
+ initMicro = newMicro;
+ setTime(newMilli);
+ microSeconds = 0;
+ } else {
+ setTime(calcMilli);
+ microSeconds = (int)(microElapsed % 1000);
+ }
}
public int getMicroSeconds() {
--- a/jdk/src/share/classes/sun/security/krb5/internal/ccache/CCacheInputStream.java Fri Nov 18 16:57:01 2011 -0800
+++ b/jdk/src/share/classes/sun/security/krb5/internal/ccache/CCacheInputStream.java Mon Nov 28 15:15:50 2011 -0800
@@ -375,7 +375,7 @@
}
AuthorizationDataEntry[] auDataEntry = readAuth();
AuthorizationData auData = null;
- if (auData != null) {
+ if (auDataEntry != null) {
auData = new AuthorizationData(auDataEntry);
}
byte[] ticketData = readData();
--- a/jdk/src/share/classes/sun/security/krb5/internal/ccache/Credentials.java Fri Nov 18 16:57:01 2011 -0800
+++ b/jdk/src/share/classes/sun/security/krb5/internal/ccache/Credentials.java Mon Nov 28 15:15:50 2011 -0800
@@ -209,10 +209,24 @@
}
public sun.security.krb5.Credentials setKrbCreds() {
+ // Note: We will not pass authorizationData to s.s.k.Credentials. The
+ // field in that class will be passed to Krb5Context as the return
+ // value of ExtendedGSSContext.inquireSecContext(KRB5_GET_AUTHZ_DATA),
+ // which is documented as the authData in the service ticket. That
+ // is on the acceptor side.
+ //
+ // This class is for the initiator side. Also, authdata inside a ccache
+ // is most likely to be the one in Authenticator in PA-TGS-REQ encoded
+ // in TGS-REQ, therefore only stored with a service ticket. Currently
+ // in Java, we only reads TGTs.
return new sun.security.krb5.Credentials(ticket,
cname, sname, key, flags, authtime, starttime, endtime, renewTill, caddr);
}
+ public KerberosTime getStartTime() {
+ return starttime;
+ }
+
public KerberosTime getAuthTime() {
return authtime;
}
@@ -221,6 +235,10 @@
return endtime;
}
+ public KerberosTime getRenewTill() {
+ return renewTill;
+ }
+
public TicketFlags getTicketFlags() {
return flags;
}
@@ -228,4 +246,8 @@
public int getEType() {
return key.getEType();
}
+
+ public int getTktEType() {
+ return ticket.encPart.getEType();
+ }
}
--- a/jdk/src/share/classes/sun/security/ssl/SSLContextImpl.java Fri Nov 18 16:57:01 2011 -0800
+++ b/jdk/src/share/classes/sun/security/ssl/SSLContextImpl.java Mon Nov 28 15:15:50 2011 -0800
@@ -771,10 +771,15 @@
final class AbstractTrustManagerWrapper extends X509ExtendedTrustManager
implements X509TrustManager {
+ // the delegated trust manager
private final X509TrustManager tm;
+ // Cache the trusted certificate to optimize the performance.
+ private final Collection<X509Certificate> trustedCerts = new HashSet<>();
+
AbstractTrustManagerWrapper(X509TrustManager tm) {
this.tm = tm;
+ Collections.addAll(trustedCerts, tm.getAcceptedIssuers());
}
@Override
@@ -863,20 +868,7 @@
constraints = new SSLAlgorithmConstraints(sslSocket, true);
}
- AlgorithmChecker checker = new AlgorithmChecker(constraints);
- try {
- checker.init(false);
-
- // a forward checker, need to check from trust to target
- for (int i = chain.length - 1; i >= 0; i--) {
- Certificate cert = chain[i];
- // We don't care about the unresolved critical extensions.
- checker.check(cert, Collections.<String>emptySet());
- }
- } catch (CertPathValidatorException cpve) {
- throw new CertificateException(
- "Certificates does not conform to algorithm constraints");
- }
+ checkAlgorithmConstraints(chain, constraints);
}
}
@@ -918,20 +910,33 @@
constraints = new SSLAlgorithmConstraints(engine, true);
}
- AlgorithmChecker checker = new AlgorithmChecker(constraints);
- try {
+ checkAlgorithmConstraints(chain, constraints);
+ }
+ }
+
+ private void checkAlgorithmConstraints(X509Certificate[] chain,
+ AlgorithmConstraints constraints) throws CertificateException {
+
+ try {
+ // Does the certificate chain end with a trusted certificate?
+ int checkedLength = chain.length - 1;
+ if (trustedCerts.contains(chain[checkedLength])) {
+ checkedLength--;
+ }
+
+ // A forward checker, need to check from trust to target
+ if (checkedLength >= 0) {
+ AlgorithmChecker checker = new AlgorithmChecker(constraints);
checker.init(false);
-
- // A forward checker, need to check from trust to target
- for (int i = chain.length - 1; i >= 0; i--) {
+ for (int i = checkedLength; i >= 0; i--) {
Certificate cert = chain[i];
// We don't care about the unresolved critical extensions.
checker.check(cert, Collections.<String>emptySet());
}
- } catch (CertPathValidatorException cpve) {
- throw new CertificateException(
- "Certificates does not conform to algorithm constraints");
}
+ } catch (CertPathValidatorException cpve) {
+ throw new CertificateException(
+ "Certificates does not conform to algorithm constraints");
}
}
}
--- a/jdk/src/share/classes/sun/security/ssl/SSLSocketImpl.java Fri Nov 18 16:57:01 2011 -0800
+++ b/jdk/src/share/classes/sun/security/ssl/SSLSocketImpl.java Mon Nov 28 15:15:50 2011 -0800
@@ -1485,7 +1485,8 @@
private void closeSocket(boolean selfInitiated) throws IOException {
if ((debug != null) && Debug.isOn("ssl")) {
- System.out.println(threadName() + ", called closeSocket(selfInitiated)");
+ System.out.println(threadName() +
+ ", called closeSocket(" + selfInitiated + ")");
}
if (self == this) {
super.close();
--- a/jdk/src/share/classes/sun/security/tools/CertAndKeyGen.java Fri Nov 18 16:57:01 2011 -0800
+++ b/jdk/src/share/classes/sun/security/tools/CertAndKeyGen.java Mon Nov 28 15:15:50 2011 -0800
@@ -33,18 +33,7 @@
import java.util.Date;
import sun.security.pkcs10.PKCS10;
-import sun.security.x509.AlgorithmId;
-import sun.security.x509.CertificateAlgorithmId;
-import sun.security.x509.CertificateIssuerName;
-import sun.security.x509.CertificateSerialNumber;
-import sun.security.x509.CertificateSubjectName;
-import sun.security.x509.CertificateValidity;
-import sun.security.x509.CertificateVersion;
-import sun.security.x509.CertificateX509Key;
-import sun.security.x509.X500Name;
-import sun.security.x509.X509CertImpl;
-import sun.security.x509.X509CertInfo;
-import sun.security.x509.X509Key;
+import sun.security.x509.*;
/**
@@ -165,6 +154,13 @@
publicKey = pair.getPublic();
privateKey = pair.getPrivate();
+
+ // publicKey's format must be X.509 otherwise
+ // the whole CertGen part of this class is broken.
+ if (!"X.509".equalsIgnoreCase(publicKey.getFormat())) {
+ throw new IllegalArgumentException("publicKey's is not X.509, but "
+ + publicKey.getFormat());
+ }
}
@@ -186,6 +182,16 @@
return (X509Key)publicKey;
}
+ /**
+ * Always returns the public key of the generated key pair. Used
+ * by KeyTool only.
+ *
+ * The publicKey is not necessarily to be an instance of
+ * X509Key in some JCA/JCE providers, for example SunPKCS11.
+ */
+ public PublicKey getPublicKeyAnyway() {
+ return publicKey;
+ }
/**
* Returns the private key of the generated key pair.
@@ -200,7 +206,6 @@
return privateKey;
}
-
/**
* Returns a self-signed X.509v3 certificate for the public key.
* The certificate is immediately valid. No extensions.
@@ -225,6 +230,15 @@
throws CertificateException, InvalidKeyException, SignatureException,
NoSuchAlgorithmException, NoSuchProviderException
{
+ return getSelfCertificate(myname, firstDate, validity, null);
+ }
+
+ // Like above, plus a CertificateExtensions argument, which can be null.
+ public X509Certificate getSelfCertificate (X500Name myname, Date firstDate,
+ long validity, CertificateExtensions ext)
+ throws CertificateException, InvalidKeyException, SignatureException,
+ NoSuchAlgorithmException, NoSuchProviderException
+ {
X509CertImpl cert;
Date lastDate;
@@ -248,6 +262,7 @@
info.set(X509CertInfo.KEY, new CertificateX509Key(publicKey));
info.set(X509CertInfo.VALIDITY, interval);
info.set(X509CertInfo.ISSUER, new CertificateIssuerName(myname));
+ if (ext != null) info.set(X509CertInfo.EXTENSIONS, ext);
cert = new X509CertImpl(info);
cert.sign(privateKey, this.sigAlg);
--- a/jdk/src/share/classes/sun/security/tools/KeyTool.java Fri Nov 18 16:57:01 2011 -0800
+++ b/jdk/src/share/classes/sun/security/tools/KeyTool.java Mon Nov 28 15:15:50 2011 -0800
@@ -1518,9 +1518,16 @@
keypair.generate(keysize);
PrivateKey privKey = keypair.getPrivateKey();
+ CertificateExtensions ext = createV3Extensions(
+ null,
+ null,
+ v3ext,
+ keypair.getPublicKeyAnyway(),
+ null);
+
X509Certificate[] chain = new X509Certificate[1];
chain[0] = keypair.getSelfCertificate(
- x500Name, getStartDate(startDate), validity*24L*60L*60L);
+ x500Name, getStartDate(startDate), validity*24L*60L*60L, ext);
if (verbose) {
MessageFormat form = new MessageFormat(rb.getString
@@ -1537,9 +1544,6 @@
keyPass = promptForKeyPass(alias, null, storePass);
}
keyStore.setKeyEntry(alias, privKey, keyPass, chain);
-
- // resign so that -ext are applied.
- doSelfCert(alias, null, sigAlgName);
}
/**
--- a/jdk/src/share/native/sun/awt/medialib/mlib_types.h Fri Nov 18 16:57:01 2011 -0800
+++ b/jdk/src/share/native/sun/awt/medialib/mlib_types.h Mon Nov 28 15:15:50 2011 -0800
@@ -59,13 +59,8 @@
#if defined(__SUNPRO_C) || defined(__SUNPRO_CC) || defined(__GNUC__)
-#if defined(__linux__)
-#include <stdint.h> /* for uintptr_t */
-#include <malloc.h> /* for ptrdiff_t */
-#else
-#include <link.h> /* for uintptr_t */
-#include <stddef.h> /* for ptrdiff_t */
-#endif /* __linux__ */
+#include <stdint.h>
+#include <stddef.h>
#ifdef MLIB_OS64BIT
--- a/jdk/src/solaris/classes/java/io/FileDescriptor.java Fri Nov 18 16:57:01 2011 -0800
+++ b/jdk/src/solaris/classes/java/io/FileDescriptor.java Mon Nov 28 15:15:50 2011 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 2011, 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
@@ -25,7 +25,8 @@
package java.io;
-import java.util.concurrent.atomic.AtomicInteger;
+import java.util.ArrayList;
+import java.util.List;
/**
* Instances of the file descriptor class serve as an opaque handle
@@ -46,12 +47,9 @@
private int fd;
- /**
- * A counter for tracking the FIS/FOS/RAF instances that
- * use this FileDescriptor. The FIS/FOS.finalize() will not release
- * the FileDescriptor if it is still under user by a stream.
- */
- private AtomicInteger useCount;
+ private Closeable parent;
+ private List<Closeable> otherParents;
+ private boolean closed;
/**
* Constructs an (invalid) FileDescriptor
@@ -59,12 +57,10 @@
*/
public /**/ FileDescriptor() {
fd = -1;
- useCount = new AtomicInteger();
}
private /* */ FileDescriptor(int fd) {
this.fd = fd;
- useCount = new AtomicInteger();
}
/**
@@ -164,13 +160,67 @@
);
}
- // package private methods used by FIS, FOS and RAF
+ /*
+ * Package private methods to track referents.
+ * If multiple streams point to the same FileDescriptor, we cycle
+ * through the list of all referents and call close()
+ */
- int incrementAndGetUseCount() {
- return useCount.incrementAndGet();
+ /**
+ * Attach a Closeable to this FD for tracking.
+ * parent reference is added to otherParents when
+ * needed to make closeAll simpler.
+ */
+ synchronized void attach(Closeable c) {
+ if (parent == null) {
+ // first caller gets to do this
+ parent = c;
+ } else if (otherParents == null) {
+ otherParents = new ArrayList<>();
+ otherParents.add(parent);
+ otherParents.add(c);
+ } else {
+ otherParents.add(c);
+ }
}
- int decrementAndGetUseCount() {
- return useCount.decrementAndGet();
+ /**
+ * Cycle through all Closeables sharing this FD and call
+ * close() on each one.
+ *
+ * The caller closeable gets to call close0().
+ */
+ @SuppressWarnings("try")
+ synchronized void closeAll(Closeable releaser) throws IOException {
+ if (!closed) {
+ closed = true;
+ IOException ioe = null;
+ try (Closeable c = releaser) {
+ if (otherParents != null) {
+ for (Closeable referent : otherParents) {
+ try {
+ referent.close();
+ } catch(IOException x) {
+ if (ioe == null) {
+ ioe = x;
+ } else {
+ ioe.addSuppressed(x);
+ }
+ }
+ }
+ }
+ } catch(IOException ex) {
+ /*
+ * If releaser close() throws IOException
+ * add other exceptions as suppressed.
+ */
+ if (ioe != null)
+ ex.addSuppressed(ioe);
+ ioe = ex;
+ } finally {
+ if (ioe != null)
+ throw ioe;
+ }
+ }
}
}
--- a/jdk/src/solaris/native/java/net/Inet4AddressImpl.c Fri Nov 18 16:57:01 2011 -0800
+++ b/jdk/src/solaris/native/java/net/Inet4AddressImpl.c Mon Nov 28 15:15:50 2011 -0800
@@ -43,8 +43,9 @@
#include "java_net_Inet4AddressImpl.h"
/* the initial size of our hostent buffers */
-#define HENT_BUF_SIZE 1024
-#define BIG_HENT_BUF_SIZE 10240 /* a jumbo-sized one */
+#ifndef NI_MAXHOST
+#define NI_MAXHOST 1025
+#endif
/************************************************************************
* Inet4AddressImpl
@@ -57,60 +58,36 @@
*/
JNIEXPORT jstring JNICALL
Java_java_net_Inet4AddressImpl_getLocalHostName(JNIEnv *env, jobject this) {
- char hostname[MAXHOSTNAMELEN+1];
+ char hostname[NI_MAXHOST+1];
hostname[0] = '\0';
if (JVM_GetHostName(hostname, sizeof(hostname))) {
/* Something went wrong, maybe networking is not setup? */
strcpy(hostname, "localhost");
} else {
-#ifdef __linux__
- /* On Linux gethostname() says "host.domain.sun.com". On
- * Solaris gethostname() says "host", so extra work is needed.
- */
-#else
- /* Solaris doesn't want to give us a fully qualified domain name.
- * We do a reverse lookup to try and get one. This works
- * if DNS occurs before NIS in /etc/resolv.conf, but fails
- * if NIS comes first (it still gets only a partial name).
- * We use thread-safe system calls.
- */
-#endif /* __linux__ */
- struct hostent res, res2, *hp;
- // these buffers must be pointer-aligned so they are declared
- // with pointer type
- char *buf[HENT_BUF_SIZE/(sizeof (char *))];
- char *buf2[HENT_BUF_SIZE/(sizeof (char *))];
- int h_error=0;
+ struct addrinfo hints, *res;
+ int error;
- // ensure null-terminated
- hostname[MAXHOSTNAMELEN] = '\0';
+ hostname[NI_MAXHOST] = '\0';
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_flags = AI_CANONNAME;
+ hints.ai_family = AF_INET;
+
+ error = getaddrinfo(hostname, NULL, &hints, &res);
-#ifdef __GLIBC__
- gethostbyname_r(hostname, &res, (char*)buf, sizeof(buf), &hp, &h_error);
-#else
- hp = gethostbyname_r(hostname, &res, (char*)buf, sizeof(buf), &h_error);
-#endif
- if (hp) {
-#ifdef __GLIBC__
- gethostbyaddr_r(hp->h_addr, hp->h_length, AF_INET,
- &res2, (char*)buf2, sizeof(buf2), &hp, &h_error);
-#else
- hp = gethostbyaddr_r(hp->h_addr, hp->h_length, AF_INET,
- &res2, (char*)buf2, sizeof(buf2), &h_error);
-#endif
- if (hp) {
- /*
- * If gethostbyaddr_r() found a fully qualified host name,
- * returns that name. Otherwise, returns the hostname
- * found by gethostname().
- */
- char *p = hp->h_name;
- if ((strlen(hp->h_name) > strlen(hostname))
- && (strncmp(hostname, hp->h_name, strlen(hostname)) == 0)
- && (*(p + strlen(hostname)) == '.'))
- strcpy(hostname, hp->h_name);
- }
+ if (error == 0) {/* host is known to name service */
+ getnameinfo(res->ai_addr,
+ res->ai_addrlen,
+ hostname,
+ NI_MAXHOST,
+ NULL,
+ 0,
+ NI_NAMEREQD);
+
+ /* if getnameinfo fails hostname is still the value
+ from gethostname */
+
+ freeaddrinfo(res);
}
}
return (*env)->NewStringUTF(env, hostname);
@@ -140,14 +117,9 @@
jstring host) {
const char *hostname;
jobjectArray ret = 0;
- struct hostent res, *hp = 0;
- // this buffer must be pointer-aligned so is declared
- // with pointer type
- char *buf[HENT_BUF_SIZE/(sizeof (char *))];
-
- /* temporary buffer, on the off chance we need to expand */
- char *tmp = NULL;
- int h_error=0;
+ int retLen = 0;
+ int error = 0;
+ struct addrinfo hints, *res, *resNew = NULL;
if (!initialized) {
ni_iacls = (*env)->FindClass(env, "java/net/InetAddress");
@@ -168,6 +140,11 @@
hostname = JNU_GetStringPlatformChars(env, host, JNI_FALSE);
CHECK_NULL_RETURN(hostname, NULL);
+ /* Try once, with our static buffer. */
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_flags = AI_CANONNAME;
+ hints.ai_family = AF_INET;
+
#ifdef __solaris__
/*
* Workaround for Solaris bug 4160367 - if a hostname contains a
@@ -181,69 +158,93 @@
}
#endif
- /* Try once, with our static buffer. */
-#ifdef __GLIBC__
- gethostbyname_r(hostname, &res, (char*)buf, sizeof(buf), &hp, &h_error);
-#else
- hp = gethostbyname_r(hostname, &res, (char*)buf, sizeof(buf), &h_error);
-#endif
+ error = getaddrinfo(hostname, NULL, &hints, &res);
+
+ if (error) {
+ /* report error */
+ ThrowUnknownHostExceptionWithGaiError(env, hostname, error);
+ JNU_ReleaseStringPlatformChars(env, host, hostname);
+ return NULL;
+ } else {
+ int i = 0;
+ struct addrinfo *itr, *last = NULL, *iterator = res;
- /* With the re-entrant system calls, it's possible that the buffer
- * we pass to it is not large enough to hold an exceptionally
- * large DNS entry. This is signaled by errno->ERANGE. We try once
- * more, with a very big size.
- */
- if (hp == NULL && errno == ERANGE) {
- if ((tmp = (char*)malloc(BIG_HENT_BUF_SIZE))) {
-#ifdef __GLIBC__
- gethostbyname_r(hostname, &res, tmp, BIG_HENT_BUF_SIZE,
- &hp, &h_error);
-#else
- hp = gethostbyname_r(hostname, &res, tmp, BIG_HENT_BUF_SIZE,
- &h_error);
-#endif
- }
- }
- if (hp != NULL) {
- struct in_addr **addrp = (struct in_addr **) hp->h_addr_list;
- int i = 0;
+ while (iterator != NULL) {
+ // remove the duplicate one
+ int skip = 0;
+ itr = resNew;
+ while (itr != NULL) {
+ struct sockaddr_in *addr1, *addr2;
+ addr1 = (struct sockaddr_in *)iterator->ai_addr;
+ addr2 = (struct sockaddr_in *)itr->ai_addr;
+ if (addr1->sin_addr.s_addr ==
+ addr2->sin_addr.s_addr) {
+ skip = 1;
+ break;
+ }
+ itr = itr->ai_next;
+ }
- while (*addrp != (struct in_addr *) 0) {
- i++;
- addrp++;
+ if (!skip) {
+ struct addrinfo *next
+ = (struct addrinfo*) malloc(sizeof(struct addrinfo));
+ if (!next) {
+ JNU_ThrowOutOfMemoryError(env, "heap allocation failed");
+ ret = NULL;
+ goto cleanupAndReturn;
+ }
+ memcpy(next, iterator, sizeof(struct addrinfo));
+ next->ai_next = NULL;
+ if (resNew == NULL) {
+ resNew = next;
+ } else {
+ last->ai_next = next;
+ }
+ last = next;
+ i++;
+ }
+ iterator = iterator->ai_next;
}
- ret = (*env)->NewObjectArray(env, i, ni_iacls, NULL);
+ retLen = i;
+ iterator = resNew;
+
+ ret = (*env)->NewObjectArray(env, retLen, ni_iacls, NULL);
+
if (IS_NULL(ret)) {
/* we may have memory to free at the end of this */
goto cleanupAndReturn;
}
- addrp = (struct in_addr **) hp->h_addr_list;
+
i = 0;
- while (*addrp) {
- jobject iaObj = (*env)->NewObject(env, ni_ia4cls, ni_ia4ctrID);
- if (IS_NULL(iaObj)) {
- ret = NULL;
- goto cleanupAndReturn;
- }
- (*env)->SetIntField(env, iaObj, ni_iaaddressID,
- ntohl((*addrp)->s_addr));
- (*env)->SetObjectField(env, iaObj, ni_iahostID, host);
- (*env)->SetObjectArrayElement(env, ret, i, iaObj);
- addrp++;
- i++;
+ while (iterator != NULL) {
+ jobject iaObj = (*env)->NewObject(env, ni_ia4cls, ni_ia4ctrID);
+ if (IS_NULL(iaObj)) {
+ ret = NULL;
+ goto cleanupAndReturn;
+ }
+ (*env)->SetIntField(env, iaObj, ni_iaaddressID,
+ ntohl(((struct sockaddr_in*)iterator->ai_addr)->sin_addr.s_addr));
+ (*env)->SetObjectField(env, iaObj, ni_iahostID, host);
+ (*env)->SetObjectArrayElement(env, ret, i++, iaObj);
+ iterator = iterator->ai_next;
}
- } else {
- JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException",
- (char *)hostname);
- ret = NULL;
}
-cleanupAndReturn:
- JNU_ReleaseStringPlatformChars(env, host, hostname);
- if (tmp != NULL) {
- free(tmp);
+ cleanupAndReturn:
+ {
+ struct addrinfo *iterator, *tmp;
+ iterator = resNew;
+ while (iterator != NULL) {
+ tmp = iterator;
+ iterator = iterator->ai_next;
+ free(tmp);
+ }
+ JNU_ReleaseStringPlatformChars(env, host, hostname);
}
+
+ freeaddrinfo(res);
+
return ret;
}
@@ -256,63 +257,38 @@
Java_java_net_Inet4AddressImpl_getHostByAddr(JNIEnv *env, jobject this,
jbyteArray addrArray) {
jstring ret = NULL;
- jint addr;
- struct hostent hent, *hp = 0;
- // this buffer must be pointer-aligned so is declared
- // with pointer type
- char *buf[HENT_BUF_SIZE/(sizeof (char *))];
- int h_error = 0;
- char *tmp = NULL;
- /*
- * We are careful here to use the reentrant version of
- * gethostbyname because at the Java level this routine is not
- * protected by any synchronization.
- *
- * Still keeping the reentrant platform dependent calls temporarily
- * We should probably conform to one interface later.
- *
- */
+ char host[NI_MAXHOST+1];
+ int error = 0;
+ int len = 0;
jbyte caddr[4];
+
+ struct sockaddr_in him4;
+ struct sockaddr *sa;
+
+ jint addr;
(*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr);
addr = ((caddr[0]<<24) & 0xff000000);
addr |= ((caddr[1] <<16) & 0xff0000);
addr |= ((caddr[2] <<8) & 0xff00);
addr |= (caddr[3] & 0xff);
- addr = htonl(addr);
-#ifdef __GLIBC__
- gethostbyaddr_r((char *)&addr, sizeof(addr), AF_INET, &hent,
- (char*)buf, sizeof(buf), &hp, &h_error);
-#else
- hp = gethostbyaddr_r((char *)&addr, sizeof(addr), AF_INET, &hent,
- (char*)buf, sizeof(buf), &h_error);
-#endif
- /* With the re-entrant system calls, it's possible that the buffer
- * we pass to it is not large enough to hold an exceptionally
- * large DNS entry. This is signaled by errno->ERANGE. We try once
- * more, with a very big size.
- */
- if (hp == NULL && errno == ERANGE) {
- if ((tmp = (char*)malloc(BIG_HENT_BUF_SIZE))) {
-#ifdef __GLIBC__
- gethostbyaddr_r((char *)&addr, sizeof(addr), AF_INET,
- &hent, tmp, BIG_HENT_BUF_SIZE, &hp, &h_error);
-#else
- hp = gethostbyaddr_r((char *)&addr, sizeof(addr), AF_INET,
- &hent, tmp, BIG_HENT_BUF_SIZE, &h_error);
-#endif
- } else {
- JNU_ThrowOutOfMemoryError(env, "getHostByAddr");
- }
+ memset((void *) &him4, 0, sizeof(him4));
+ him4.sin_addr.s_addr = (uint32_t) htonl(addr);
+ him4.sin_family = AF_INET;
+ sa = (struct sockaddr *) &him4;
+ len = sizeof(him4);
+
+ error = getnameinfo(sa, len, host, NI_MAXHOST, NULL, 0,
+ NI_NAMEREQD);
+
+ if (!error) {
+ ret = (*env)->NewStringUTF(env, host);
}
- if (hp == NULL) {
+
+ if (ret == NULL) {
JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException", NULL);
- } else {
- ret = (*env)->NewStringUTF(env, hp->h_name);
}
- if (tmp) {
- free(tmp);
- }
+
return ret;
}
--- a/jdk/src/solaris/native/java/net/Inet6AddressImpl.c Fri Nov 18 16:57:01 2011 -0800
+++ b/jdk/src/solaris/native/java/net/Inet6AddressImpl.c Mon Nov 28 15:15:50 2011 -0800
@@ -82,31 +82,29 @@
* We use thread-safe system calls.
*/
#ifdef AF_INET6
- if (NET_addrtransAvailable()) {
- struct addrinfo hints, *res;
- int error;
+ struct addrinfo hints, *res;
+ int error;
- bzero(&hints, sizeof(hints));
- hints.ai_flags = AI_CANONNAME;
- hints.ai_family = AF_UNSPEC;
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_flags = AI_CANONNAME;
+ hints.ai_family = AF_UNSPEC;
- error = (*getaddrinfo_ptr)(hostname, NULL, &hints, &res);
+ error = getaddrinfo(hostname, NULL, &hints, &res);
- if (error == 0) {
- /* host is known to name service */
- error = (*getnameinfo_ptr)(res->ai_addr,
- res->ai_addrlen,
- hostname,
- NI_MAXHOST,
- NULL,
- 0,
- NI_NAMEREQD);
+ if (error == 0) {
+ /* host is known to name service */
+ error = getnameinfo(res->ai_addr,
+ res->ai_addrlen,
+ hostname,
+ NI_MAXHOST,
+ NULL,
+ 0,
+ NI_NAMEREQD);
- /* if getnameinfo fails hostname is still the value
- from gethostname */
+ /* if getnameinfo fails hostname is still the value
+ from gethostname */
- (*freeaddrinfo_ptr)(res);
- }
+ freeaddrinfo(res);
}
#endif /* AF_INET6 */
#endif /* __linux__ */
@@ -173,193 +171,191 @@
CHECK_NULL_RETURN(hostname, NULL);
#ifdef AF_INET6
- if (NET_addrtransAvailable()) {
- static jfieldID ia_preferIPv6AddressID;
- if (ia_preferIPv6AddressID == NULL) {
- jclass c = (*env)->FindClass(env,"java/net/InetAddress");
- if (c) {
- ia_preferIPv6AddressID =
- (*env)->GetStaticFieldID(env, c, "preferIPv6Address", "Z");
- }
- if (ia_preferIPv6AddressID == NULL) {
- JNU_ReleaseStringPlatformChars(env, host, hostname);
- return NULL;
- }
+ static jfieldID ia_preferIPv6AddressID;
+ if (ia_preferIPv6AddressID == NULL) {
+ jclass c = (*env)->FindClass(env,"java/net/InetAddress");
+ if (c) {
+ ia_preferIPv6AddressID =
+ (*env)->GetStaticFieldID(env, c, "preferIPv6Address", "Z");
}
- /* get the address preference */
- preferIPv6Address
- = (*env)->GetStaticBooleanField(env, ia_class, ia_preferIPv6AddressID);
-
- /* Try once, with our static buffer. */
- bzero(&hints, sizeof(hints));
- hints.ai_flags = AI_CANONNAME;
- hints.ai_family = AF_UNSPEC;
-
-#ifdef __solaris__
- /*
- * Workaround for Solaris bug 4160367 - if a hostname contains a
- * white space then 0.0.0.0 is returned
- */
- if (isspace((unsigned char)hostname[0])) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException",
- hostname);
+ if (ia_preferIPv6AddressID == NULL) {
JNU_ReleaseStringPlatformChars(env, host, hostname);
return NULL;
}
+ }
+ /* get the address preference */
+ preferIPv6Address
+ = (*env)->GetStaticBooleanField(env, ia_class, ia_preferIPv6AddressID);
+
+ /* Try once, with our static buffer. */
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_flags = AI_CANONNAME;
+ hints.ai_family = AF_UNSPEC;
+
+#ifdef __solaris__
+ /*
+ * Workaround for Solaris bug 4160367 - if a hostname contains a
+ * white space then 0.0.0.0 is returned
+ */
+ if (isspace((unsigned char)hostname[0])) {
+ JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException",
+ hostname);
+ JNU_ReleaseStringPlatformChars(env, host, hostname);
+ return NULL;
+ }
#endif
- error = (*getaddrinfo_ptr)(hostname, NULL, &hints, &res);
+ error = getaddrinfo(hostname, NULL, &hints, &res);
- if (error) {
- /* report error */
- ThrowUnknownHostExceptionWithGaiError(env, hostname, error);
- JNU_ReleaseStringPlatformChars(env, host, hostname);
- return NULL;
- } else {
- int i = 0;
- int inetCount = 0, inet6Count = 0, inetIndex, inet6Index;
- struct addrinfo *itr, *last = NULL, *iterator = res;
- while (iterator != NULL) {
- int skip = 0;
- itr = resNew;
- while (itr != NULL) {
- if (iterator->ai_family == itr->ai_family &&
- iterator->ai_addrlen == itr->ai_addrlen) {
- if (itr->ai_family == AF_INET) { /* AF_INET */
- struct sockaddr_in *addr1, *addr2;
- addr1 = (struct sockaddr_in *)iterator->ai_addr;
- addr2 = (struct sockaddr_in *)itr->ai_addr;
- if (addr1->sin_addr.s_addr ==
- addr2->sin_addr.s_addr) {
- skip = 1;
- break;
- }
- } else {
- int t;
- struct sockaddr_in6 *addr1, *addr2;
- addr1 = (struct sockaddr_in6 *)iterator->ai_addr;
- addr2 = (struct sockaddr_in6 *)itr->ai_addr;
+ if (error) {
+ /* report error */
+ ThrowUnknownHostExceptionWithGaiError(env, hostname, error);
+ JNU_ReleaseStringPlatformChars(env, host, hostname);
+ return NULL;
+ } else {
+ int i = 0;
+ int inetCount = 0, inet6Count = 0, inetIndex, inet6Index;
+ struct addrinfo *itr, *last = NULL, *iterator = res;
+ while (iterator != NULL) {
+ int skip = 0;
+ itr = resNew;
+ while (itr != NULL) {
+ if (iterator->ai_family == itr->ai_family &&
+ iterator->ai_addrlen == itr->ai_addrlen) {
+ if (itr->ai_family == AF_INET) { /* AF_INET */
+ struct sockaddr_in *addr1, *addr2;
+ addr1 = (struct sockaddr_in *)iterator->ai_addr;
+ addr2 = (struct sockaddr_in *)itr->ai_addr;
+ if (addr1->sin_addr.s_addr ==
+ addr2->sin_addr.s_addr) {
+ skip = 1;
+ break;
+ }
+ } else {
+ int t;
+ struct sockaddr_in6 *addr1, *addr2;
+ addr1 = (struct sockaddr_in6 *)iterator->ai_addr;
+ addr2 = (struct sockaddr_in6 *)itr->ai_addr;
- for (t = 0; t < 16; t++) {
- if (addr1->sin6_addr.s6_addr[t] !=
- addr2->sin6_addr.s6_addr[t]) {
- break;
- }
- }
- if (t < 16) {
- itr = itr->ai_next;
- continue;
- } else {
- skip = 1;
+ for (t = 0; t < 16; t++) {
+ if (addr1->sin6_addr.s6_addr[t] !=
+ addr2->sin6_addr.s6_addr[t]) {
break;
}
}
- } else if (iterator->ai_family != AF_INET &&
- iterator->ai_family != AF_INET6) {
- /* we can't handle other family types */
- skip = 1;
- break;
- }
- itr = itr->ai_next;
- }
-
- if (!skip) {
- struct addrinfo *next
- = (struct addrinfo*) malloc(sizeof(struct addrinfo));
- if (!next) {
- JNU_ThrowOutOfMemoryError(env, "heap allocation failed");
- ret = NULL;
- goto cleanupAndReturn;
+ if (t < 16) {
+ itr = itr->ai_next;
+ continue;
+ } else {
+ skip = 1;
+ break;
+ }
}
- memcpy(next, iterator, sizeof(struct addrinfo));
- next->ai_next = NULL;
- if (resNew == NULL) {
- resNew = next;
- } else {
- last->ai_next = next;
- }
- last = next;
- i++;
- if (iterator->ai_family == AF_INET) {
- inetCount ++;
- } else if (iterator->ai_family == AF_INET6) {
- inet6Count ++;
- }
+ } else if (iterator->ai_family != AF_INET &&
+ iterator->ai_family != AF_INET6) {
+ /* we can't handle other family types */
+ skip = 1;
+ break;
}
- iterator = iterator->ai_next;
- }
- retLen = i;
- iterator = resNew;
-
- ret = (*env)->NewObjectArray(env, retLen, ni_iacls, NULL);
-
- if (IS_NULL(ret)) {
- /* we may have memory to free at the end of this */
- goto cleanupAndReturn;
+ itr = itr->ai_next;
}
- if (preferIPv6Address) {
- /* AF_INET addresses will be offset by inet6Count */
- inetIndex = inet6Count;
- inet6Index = 0;
- } else {
- /* AF_INET6 addresses will be offset by inetCount */
- inetIndex = 0;
- inet6Index = inetCount;
+ if (!skip) {
+ struct addrinfo *next
+ = (struct addrinfo*) malloc(sizeof(struct addrinfo));
+ if (!next) {
+ JNU_ThrowOutOfMemoryError(env, "heap allocation failed");
+ ret = NULL;
+ goto cleanupAndReturn;
+ }
+ memcpy(next, iterator, sizeof(struct addrinfo));
+ next->ai_next = NULL;
+ if (resNew == NULL) {
+ resNew = next;
+ } else {
+ last->ai_next = next;
+ }
+ last = next;
+ i++;
+ if (iterator->ai_family == AF_INET) {
+ inetCount ++;
+ } else if (iterator->ai_family == AF_INET6) {
+ inet6Count ++;
+ }
}
+ iterator = iterator->ai_next;
+ }
+ retLen = i;
+ iterator = resNew;
- while (iterator != NULL) {
- if (iterator->ai_family == AF_INET) {
+ ret = (*env)->NewObjectArray(env, retLen, ni_iacls, NULL);
+
+ if (IS_NULL(ret)) {
+ /* we may have memory to free at the end of this */
+ goto cleanupAndReturn;
+ }
+
+ if (preferIPv6Address) {
+ /* AF_INET addresses will be offset by inet6Count */
+ inetIndex = inet6Count;
+ inet6Index = 0;
+ } else {
+ /* AF_INET6 addresses will be offset by inetCount */
+ inetIndex = 0;
+ inet6Index = inetCount;
+ }
+
+ while (iterator != NULL) {
+ if (iterator->ai_family == AF_INET) {
jobject iaObj = (*env)->NewObject(env, ni_ia4cls, ni_ia4ctrID);
if (IS_NULL(iaObj)) {
- ret = NULL;
- goto cleanupAndReturn;
+ ret = NULL;
+ goto cleanupAndReturn;
}
(*env)->SetIntField(env, iaObj, ni_iaaddressID,
ntohl(((struct sockaddr_in*)iterator->ai_addr)->sin_addr.s_addr));
(*env)->SetObjectField(env, iaObj, ni_iahostID, host);
(*env)->SetObjectArrayElement(env, ret, inetIndex, iaObj);
inetIndex++;
- } else if (iterator->ai_family == AF_INET6) {
+ } else if (iterator->ai_family == AF_INET6) {
jint scope = 0;
jbyteArray ipaddress;
jobject iaObj = (*env)->NewObject(env, ni_ia6cls, ni_ia6ctrID);
if (IS_NULL(iaObj)) {
- ret = NULL;
- goto cleanupAndReturn;
+ ret = NULL;
+ goto cleanupAndReturn;
}
ipaddress = (*env)->NewByteArray(env, 16);
if (IS_NULL(ipaddress)) {
- ret = NULL;
- goto cleanupAndReturn;
+ ret = NULL;
+ goto cleanupAndReturn;
}
(*env)->SetByteArrayRegion(env, ipaddress, 0, 16,
(jbyte *)&(((struct sockaddr_in6*)iterator->ai_addr)->sin6_addr));
#ifdef __linux__
if (!kernelIsV22()) {
- scope = ((struct sockaddr_in6*)iterator->ai_addr)->sin6_scope_id;
+ scope = ((struct sockaddr_in6*)iterator->ai_addr)->sin6_scope_id;
}
#else
scope = ((struct sockaddr_in6*)iterator->ai_addr)->sin6_scope_id;
#endif
if (scope != 0) { /* zero is default value, no need to set */
- (*env)->SetIntField(env, iaObj, ia6_scopeidID, scope);
- (*env)->SetBooleanField(env, iaObj, ia6_scopeidsetID, JNI_TRUE);
+ (*env)->SetIntField(env, iaObj, ia6_scopeidID, scope);
+ (*env)->SetBooleanField(env, iaObj, ia6_scopeidsetID, JNI_TRUE);
}
(*env)->SetObjectField(env, iaObj, ni_ia6ipaddressID, ipaddress);
(*env)->SetObjectField(env, iaObj, ni_iahostID, host);
(*env)->SetObjectArrayElement(env, ret, inet6Index, iaObj);
inet6Index++;
- }
- iterator = iterator->ai_next;
}
+ iterator = iterator->ai_next;
}
}
-cleanupAndReturn:
+ cleanupAndReturn:
{
- struct addrinfo *iterator, *tmp;
+ struct addrinfo *iterator, *tmp;
iterator = resNew;
while (iterator != NULL) {
tmp = iterator;
@@ -369,8 +365,7 @@
JNU_ReleaseStringPlatformChars(env, host, hostname);
}
- if (NET_addrtransAvailable())
- (*freeaddrinfo_ptr)(res);
+ freeaddrinfo(res);
#endif /* AF_INET6 */
return ret;
@@ -393,44 +388,42 @@
int len = 0;
jbyte caddr[16];
- if (NET_addrtransAvailable()) {
- struct sockaddr_in him4;
- struct sockaddr_in6 him6;
- struct sockaddr *sa;
+ struct sockaddr_in him4;
+ struct sockaddr_in6 him6;
+ struct sockaddr *sa;
+ /*
+ * For IPv4 addresses construct a sockaddr_in structure.
+ */
+ if ((*env)->GetArrayLength(env, addrArray) == 4) {
+ jint addr;
+ (*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr);
+ addr = ((caddr[0]<<24) & 0xff000000);
+ addr |= ((caddr[1] <<16) & 0xff0000);
+ addr |= ((caddr[2] <<8) & 0xff00);
+ addr |= (caddr[3] & 0xff);
+ memset((void *) &him4, 0, sizeof(him4));
+ him4.sin_addr.s_addr = (uint32_t) htonl(addr);
+ him4.sin_family = AF_INET;
+ sa = (struct sockaddr *) &him4;
+ len = sizeof(him4);
+ } else {
/*
- * For IPv4 addresses construct a sockaddr_in structure.
+ * For IPv6 address construct a sockaddr_in6 structure.
*/
- if ((*env)->GetArrayLength(env, addrArray) == 4) {
- jint addr;
- (*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr);
- addr = ((caddr[0]<<24) & 0xff000000);
- addr |= ((caddr[1] <<16) & 0xff0000);
- addr |= ((caddr[2] <<8) & 0xff00);
- addr |= (caddr[3] & 0xff);
- memset((void *) &him4, 0, sizeof(him4));
- him4.sin_addr.s_addr = (uint32_t) htonl(addr);
- him4.sin_family = AF_INET;
- sa = (struct sockaddr *) &him4;
- len = sizeof(him4);
- } else {
- /*
- * For IPv6 address construct a sockaddr_in6 structure.
- */
- (*env)->GetByteArrayRegion(env, addrArray, 0, 16, caddr);
- memset((void *) &him6, 0, sizeof(him6));
- memcpy((void *)&(him6.sin6_addr), caddr, sizeof(struct in6_addr) );
- him6.sin6_family = AF_INET6;
- sa = (struct sockaddr *) &him6 ;
- len = sizeof(him6) ;
- }
+ (*env)->GetByteArrayRegion(env, addrArray, 0, 16, caddr);
+ memset((void *) &him6, 0, sizeof(him6));
+ memcpy((void *)&(him6.sin6_addr), caddr, sizeof(struct in6_addr) );
+ him6.sin6_family = AF_INET6;
+ sa = (struct sockaddr *) &him6 ;
+ len = sizeof(him6) ;
+ }
- error = (*getnameinfo_ptr)(sa, len, host, NI_MAXHOST, NULL, 0,
- NI_NAMEREQD);
+ error = getnameinfo(sa, len, host, NI_MAXHOST, NULL, 0,
+ NI_NAMEREQD);
- if (!error) {
- ret = (*env)->NewStringUTF(env, host);
- }
+ if (!error) {
+ ret = (*env)->NewStringUTF(env, host);
}
#endif /* AF_INET6 */
--- a/jdk/src/solaris/native/java/net/net_util_md.c Fri Nov 18 16:57:01 2011 -0800
+++ b/jdk/src/solaris/native/java/net/net_util_md.c Mon Nov 28 15:15:50 2011 -0800
@@ -377,37 +377,12 @@
* we should also check if the APIs are available.
*/
ipv6_fn = JVM_FindLibraryEntry(RTLD_DEFAULT, "inet_pton");
+ close(fd);
if (ipv6_fn == NULL ) {
- close(fd);
return JNI_FALSE;
+ } else {
+ return JNI_TRUE;
}
-
- /*
- * We've got the library, let's get the pointers to some
- * IPV6 specific functions. We have to do that because, at least
- * on Solaris we may build on a system without IPV6 networking
- * libraries, therefore we can't have a hard link to these
- * functions.
- */
- getaddrinfo_ptr = (getaddrinfo_f)
- JVM_FindLibraryEntry(RTLD_DEFAULT, "getaddrinfo");
-
- freeaddrinfo_ptr = (freeaddrinfo_f)
- JVM_FindLibraryEntry(RTLD_DEFAULT, "freeaddrinfo");
-
- gai_strerror_ptr = (gai_strerror_f)
- JVM_FindLibraryEntry(RTLD_DEFAULT, "gai_strerror");
-
- getnameinfo_ptr = (getnameinfo_f)
- JVM_FindLibraryEntry(RTLD_DEFAULT, "getnameinfo");
-
- if (freeaddrinfo_ptr == NULL || getnameinfo_ptr == NULL) {
- /* We need all 3 of them */
- getaddrinfo_ptr = NULL;
- }
-
- close(fd);
- return JNI_TRUE;
#endif /* AF_INET6 */
}
@@ -920,10 +895,6 @@
return 1;
}
-jboolean NET_addrtransAvailable() {
- return (jboolean)(getaddrinfo_ptr != NULL);
-}
-
/*
* Map the Java level socket option to the platform specific
* level and option name.
--- a/jdk/src/solaris/native/java/net/net_util_md.h Fri Nov 18 16:57:01 2011 -0800
+++ b/jdk/src/solaris/native/java/net/net_util_md.h Mon Nov 28 15:15:50 2011 -0800
@@ -102,10 +102,6 @@
const char* hostname,
int gai_error);
-/* do we have address translation support */
-
-extern jboolean NET_addrtransAvailable();
-
#define NET_WAIT_READ 0x01
#define NET_WAIT_WRITE 0x02
#define NET_WAIT_CONNECT 0x04
--- a/jdk/src/windows/classes/java/io/FileDescriptor.java Fri Nov 18 16:57:01 2011 -0800
+++ b/jdk/src/windows/classes/java/io/FileDescriptor.java Mon Nov 28 15:15:50 2011 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2011, 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
@@ -25,7 +25,8 @@
package java.io;
-import java.util.concurrent.atomic.AtomicInteger;
+import java.util.ArrayList;
+import java.util.List;
/**
* Instances of the file descriptor class serve as an opaque handle
@@ -45,13 +46,9 @@
private long handle;
- /**
- * A use counter for tracking the FIS/FOS/RAF instances that
- * use this FileDescriptor. The FIS/FOS.finalize() will not release
- * the FileDescriptor if it is still under use by any stream.
- */
- private AtomicInteger useCount;
-
+ private Closeable parent;
+ private List<Closeable> otherParents;
+ private boolean closed;
/**
* Constructs an (invalid) FileDescriptor
@@ -60,7 +57,6 @@
public /**/ FileDescriptor() {
fd = -1;
handle = -1;
- useCount = new AtomicInteger();
}
static {
@@ -168,13 +164,67 @@
return desc;
}
- // package private methods used by FIS, FOS and RAF.
+ /*
+ * Package private methods to track referents.
+ * If multiple streams point to the same FileDescriptor, we cycle
+ * through the list of all referents and call close()
+ */
- int incrementAndGetUseCount() {
- return useCount.incrementAndGet();
+ /**
+ * Attach a Closeable to this FD for tracking.
+ * parent reference is added to otherParents when
+ * needed to make closeAll simpler.
+ */
+ synchronized void attach(Closeable c) {
+ if (parent == null) {
+ // first caller gets to do this
+ parent = c;
+ } else if (otherParents == null) {
+ otherParents = new ArrayList<>();
+ otherParents.add(parent);
+ otherParents.add(c);
+ } else {
+ otherParents.add(c);
+ }
}
- int decrementAndGetUseCount() {
- return useCount.decrementAndGet();
+ /**
+ * Cycle through all Closeables sharing this FD and call
+ * close() on each one.
+ *
+ * The caller closeable gets to call close0().
+ */
+ @SuppressWarnings("try")
+ synchronized void closeAll(Closeable releaser) throws IOException {
+ if (!closed) {
+ closed = true;
+ IOException ioe = null;
+ try (Closeable c = releaser) {
+ if (otherParents != null) {
+ for (Closeable referent : otherParents) {
+ try {
+ referent.close();
+ } catch(IOException x) {
+ if (ioe == null) {
+ ioe = x;
+ } else {
+ ioe.addSuppressed(x);
+ }
+ }
+ }
+ }
+ } catch(IOException ex) {
+ /*
+ * If releaser close() throws IOException
+ * add other exceptions as suppressed.
+ */
+ if (ioe != null)
+ ex.addSuppressed(ioe);
+ ioe = ex;
+ } finally {
+ if (ioe != null)
+ throw ioe;
+ }
+ }
}
}
--- a/jdk/src/windows/classes/java/net/PlainSocketImpl.java Fri Nov 18 16:57:01 2011 -0800
+++ b/jdk/src/windows/classes/java/net/PlainSocketImpl.java Mon Nov 28 15:15:50 2011 -0800
@@ -314,7 +314,7 @@
void socketSetOption(int cmd, boolean on, Object value)
throws SocketException {
- socketSetOption(cmd, on, value);
+ impl.socketSetOption(cmd, on, value);
}
int socketGetOption(int opt, Object iaContainerObj) throws SocketException {
--- a/jdk/src/windows/classes/sun/security/krb5/internal/tools/Klist.java Fri Nov 18 16:57:01 2011 -0800
+++ b/jdk/src/windows/classes/sun/security/krb5/internal/tools/Klist.java Mon Nov 28 15:15:50 2011 -0800
@@ -207,7 +207,7 @@
}
if (options[2] == 't') {
System.out.println("\t Time stamp: " +
- reformat(entries[i].getTimeStamp().toDate().toString()));
+ format(entries[i].getTimeStamp()));
}
}
}
@@ -234,30 +234,39 @@
System.out.println("\nDefault principal: " +
defaultPrincipal + ", " +
creds.length + " entries found.\n");
- String starttime = null;
- String endtime = null;
- String servicePrincipal = null;
- String etype = null;
if (creds != null) {
for (int i = 0; i < creds.length; i++) {
try {
- starttime =
- reformat(creds[i].getAuthTime().toDate().toString());
- endtime =
- reformat(creds[i].getEndTime().toDate().toString());
+ String starttime;
+ String endtime;
+ String renewTill;
+ String servicePrincipal;
+ if (creds[i].getStartTime() != null) {
+ starttime = format(creds[i].getStartTime());
+ } else {
+ starttime = format(creds[i].getAuthTime());
+ }
+ endtime = format(creds[i].getEndTime());
servicePrincipal =
creds[i].getServicePrincipal().toString();
System.out.println("[" + (i + 1) + "] " +
" Service Principal: " +
servicePrincipal);
- System.out.println(" Valid starting: " + starttime);
- System.out.println(" Expires: " + endtime);
+ System.out.println(" Valid starting: " + starttime);
+ System.out.println(" Expires: " + endtime);
+ if (creds[i].getRenewTill() != null) {
+ renewTill = format(creds[i].getRenewTill());
+ System.out.println(
+ " Renew until: " + renewTill);
+ }
if (options[0] == 'e') {
- etype = EType.toString(creds[i].getEType());
- System.out.println(" Encryption type: " + etype);
+ String eskey = EType.toString(creds[i].getEType());
+ String etkt = EType.toString(creds[i].getTktEType());
+ System.out.println(" EType (skey, tkt): "
+ + eskey + ", " + etkt);
}
if (options[1] == 'f') {
- System.out.println(" Flags: " +
+ System.out.println(" Flags: " +
creds[i].getTicketFlags().toString());
}
if (options[2] == 'a') {
@@ -312,13 +321,14 @@
* and yyyy is the year.
* @param date the string form of Date object.
*/
- String reformat(String date) {
+ private String format(KerberosTime kt) {
+ String date = kt.toDate().toString();
return (date.substring(4, 7) + " " + date.substring(8, 10) +
", " + date.substring(24)
- + " " + date.substring(11, 16));
+ + " " + date.substring(11, 19));
}
/**
- * Printes out the help information.
+ * Prints out the help information.
*/
void printHelp() {
System.out.println("\nUsage: klist " +
--- a/jdk/src/windows/lib/tzmappings Fri Nov 18 16:57:01 2011 -0800
+++ b/jdk/src/windows/lib/tzmappings Mon Nov 28 15:15:50 2011 -0800
@@ -167,7 +167,7 @@
Argentina Standard Time:900,900::America/Buenos_Aires:
Azerbaijan Standard Time:901,901:AZ:Asia/Baku:
Bangladesh Standard Time:902,902::Asia/Dhaka:
-Central Brazilian Standard Time:903,903:BR:America/Manaus:
+Central Brazilian Standard Time:903,903:BR:America/Cuiaba:
Central Standard Time (Mexico):904,904::America/Mexico_City:
Georgian Standard Time:905,905:GE:Asia/Tbilisi:
Jordan Standard Time:906,906:JO:Asia/Amman:
@@ -189,5 +189,7 @@
Ulaanbaatar Standard Time:922,922::Asia/Ulaanbaatar:
Venezuela Standard Time:923,923::America/Caracas:
Magadan Standard Time:924,924::Asia/Magadan:
-Western Brazilian Standard Time:925,925:BR:America/Rio_Branco:
-Armenian Standard Time:926,926:AM:Asia/Yerevan:
+Kaliningrad Standard Time:925,925:RU:Europe/Kaliningrad:
+Turkey Standard Time:926,926::Asia/Istanbul:
+Western Brazilian Standard Time:927,927:BR:America/Rio_Branco:
+Armenian Standard Time:928,928:AM:Asia/Yerevan:
--- a/jdk/test/java/io/FileDescriptor/FileChannelFDTest.java Fri Nov 18 16:57:01 2011 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,92 +0,0 @@
-/*
- * Copyright (c) 2006, 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.
- *
- * 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.
- */
-
-/**
- *
- * @test
- * @bug 6322678
- * @summary Test for making sure that fd is closed during
- * finalization of a stream, when an associated
- * file channel is not available
- */
-
-import java.io.*;
-import java.nio.*;
-import java.nio.channels.*;
-
-public class FileChannelFDTest {
-
- static byte data[] = new byte[] {48, 49, 50, 51, 52, 53, 54, 55, 56, 57,};
- static String inFileName = "fd-in-test.txt";
- static String outFileName = "fd-out-test.txt";
- static File inFile;
- static File outFile;
-
- private static void writeToInFile() throws IOException {
- FileOutputStream out = new FileOutputStream(inFile);
- out.write(data);
- out.close();
- }
-
- public static void main(String[] args)
- throws Exception {
-
- inFile= new File(System.getProperty("test.dir", "."),
- inFileName);
- inFile.createNewFile();
- inFile.deleteOnExit();
- writeToInFile();
-
- outFile = new File(System.getProperty("test.dir", "."),
- outFileName);
- outFile.createNewFile();
- outFile.deleteOnExit();
-
- doFileChannel();
- }
-
- private static void doFileChannel() throws Exception {
-
- FileInputStream fis = new FileInputStream(inFile);
- FileDescriptor fd = fis.getFD();
- FileChannel fc = fis.getChannel();
- System.out.println("Created fis:" + fis);
-
- /**
- * Encourage the GC
- */
- fis = null;
- fc = null;
- System.gc();
- Thread.sleep(500);
-
- if (fd.valid()) {
- throw new Exception("Finalizer either didn't run --" +
- "try increasing the Thread's sleep time after System.gc();" +
- "or the finalizer didn't close the file");
- }
-
- System.out.println("File Closed successfully");
- System.out.println();
- }
-}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/io/FileDescriptor/Sharing.java Mon Nov 28 15:15:50 2011 -0800
@@ -0,0 +1,408 @@
+/*
+ * Copyright (c) 2011, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 7105952 6322678 7082769
+ * @summary Improve finalisation for FileInputStream/FileOutputStream/RandomAccessFile
+ * @run main/othervm Sharing
+ */
+
+import java.io.*;
+import java.nio.channels.FileChannel;
+import java.nio.channels.FileLock;
+import java.util.concurrent.CountDownLatch;
+
+public class Sharing {
+
+ final static int numFiles = 10;
+ volatile static boolean fail;
+
+ public static void main(String[] args) throws Exception {
+ TestFinalizer();
+ TestMultipleFD();
+ TestIsValid();
+ MultiThreadedFD();
+ TestCloseAll();
+ }
+
+ /**
+ * Finalizer shouldn't discard a file descriptor until all streams have
+ * finished with it.
+ */
+ private static void TestFinalizer() throws Exception {
+ FileDescriptor fd = null;
+ File tempFile = new File("TestFinalizer1.txt");
+ tempFile.deleteOnExit();
+ try (Writer writer = new FileWriter(tempFile)) {
+ for (int i=0; i<5; i++) {
+ writer.write("test file content test file content");
+ }
+ }
+
+ FileInputStream fis1 = new FileInputStream(tempFile);
+ fd = fis1.getFD();
+ // Create a new FIS based on the existing FD (so the two FIS's share the same native fd)
+ try (FileInputStream fis2 = new FileInputStream(fd)) {
+ // allow fis1 to be gc'ed
+ fis1 = null;
+ int ret = 0;
+ while(ret >= 0) {
+ // encourage gc
+ System.gc();
+ // read from fis2 - when fis1 is gc'ed and finalizer is run, read will fail
+ System.out.print(".");
+ ret = fis2.read();
+ }
+ }
+
+ // variation of above. Use RandomAccessFile to obtain a filedescriptor
+ File testFinalizerFile = new File("TestFinalizer");
+ RandomAccessFile raf = new RandomAccessFile(testFinalizerFile, "rw");
+ raf.writeBytes("test file content test file content");
+ raf.seek(0L);
+ fd = raf.getFD();
+ try (FileInputStream fis3 = new FileInputStream(fd)) {
+ // allow raf to be gc'ed
+ raf = null;
+ int ret = 0;
+ while (ret >= 0) {
+ // encourage gc
+ System.gc();
+ /*
+ * read from fis3 - when raf is gc'ed and finalizer is run,
+ * fd should still be valid.
+ */
+ System.out.print(".");
+ ret = fis3.read();
+ }
+ } finally {
+ testFinalizerFile.delete();
+ }
+ }
+
+ /**
+ * Exercise FileDispatcher close()/preClose()
+ */
+ private static void TestMultipleFD() throws Exception {
+ RandomAccessFile raf = null;
+ FileOutputStream fos = null;
+ FileInputStream fis = null;
+ FileChannel fc = null;
+ FileLock fileLock = null;
+
+ File test1 = new File("test1");
+ try {
+ raf = new RandomAccessFile(test1, "rw");
+ fos = new FileOutputStream(raf.getFD());
+ fis = new FileInputStream(raf.getFD());
+ fc = raf.getChannel();
+ fileLock = fc.lock();
+ raf.setLength(0L);
+ fos.flush();
+ fos.write("TEST".getBytes());
+ } finally {
+ if (fileLock != null) fileLock.release();
+ if (fis != null) fis.close();
+ if (fos != null) fos.close();
+ if (raf != null) raf.close();
+ test1.delete();
+ }
+
+ /*
+ * Close out in different order to ensure FD is not
+ * closed out too early
+ */
+ File test2 = new File("test2");
+ try {
+ raf = new RandomAccessFile(test2, "rw");
+ fos = new FileOutputStream(raf.getFD());
+ fis = new FileInputStream(raf.getFD());
+ fc = raf.getChannel();
+ fileLock = fc.lock();
+ raf.setLength(0L);
+ fos.flush();
+ fos.write("TEST".getBytes());
+ } finally {
+ if (fileLock != null) fileLock.release();
+ if (raf != null) raf.close();
+ if (fos != null) fos.close();
+ if (fis != null) fis.close();
+ test2.delete();
+ }
+
+ // one more time, fos first this time
+ File test3 = new File("test3");
+ try {
+ raf = new RandomAccessFile(test3, "rw");
+ fos = new FileOutputStream(raf.getFD());
+ fis = new FileInputStream(raf.getFD());
+ fc = raf.getChannel();
+ fileLock = fc.lock();
+ raf.setLength(0L);
+ fos.flush();
+ fos.write("TEST".getBytes());
+ } finally {
+ if (fileLock != null) fileLock.release();
+ if (fos != null) fos.close();
+ if (raf != null) raf.close();
+ if (fis != null) fis.close();
+ test3.delete();
+ }
+ }
+
+ /**
+ * Similar to TestMultipleFD() but this time we
+ * just get and use FileDescriptor.valid() for testing.
+ */
+ private static void TestIsValid() throws Exception {
+ FileDescriptor fd = null;
+ RandomAccessFile raf = null;
+ FileOutputStream fos = null;
+ FileInputStream fis = null;
+ FileChannel fc = null;
+
+ File test1 = new File("test1");
+ try {
+ raf = new RandomAccessFile(test1, "rw");
+ fd = raf.getFD();
+ fos = new FileOutputStream(fd);
+ fis = new FileInputStream(fd);
+ } finally {
+ try {
+ if (fis != null) fis.close();
+ if (fd.valid()) {
+ throw new RuntimeException("[FIS close()] FileDescriptor shouldn't be valid");
+ }
+ if (fos != null) fos.close();
+ if (raf != null) raf.close();
+ } finally {
+ test1.delete();
+ }
+ }
+
+ /*
+ * Close out in different order to ensure FD is
+ * closed correctly.
+ */
+ File test2 = new File("test2");
+ try {
+ raf = new RandomAccessFile(test2, "rw");
+ fd = raf.getFD();
+ fos = new FileOutputStream(fd);
+ fis = new FileInputStream(fd);
+ } finally {
+ try {
+ if (raf != null) raf.close();
+ if (fd.valid()) {
+ throw new RuntimeException("[RAF close()] FileDescriptor shouldn't be valid");
+ }
+ if (fos != null) fos.close();
+ if (fis != null) fis.close();
+ } finally {
+ test2.delete();
+ }
+ }
+
+ // one more time, fos first this time
+ File test3 = new File("test3");
+ try {
+ raf = new RandomAccessFile(test3, "rw");
+ fd = raf.getFD();
+ fos = new FileOutputStream(fd);
+ fis = new FileInputStream(fd);
+ } finally {
+ try {
+ if (fos != null) fos.close();
+ if (fd.valid()) {
+ throw new RuntimeException("[FOS close()] FileDescriptor shouldn't be valid");
+ }
+ if (raf != null) raf.close();
+ if (fis != null) fis.close();
+ } finally {
+ test3.delete();
+ }
+ }
+ }
+
+ /**
+ * Test concurrent access to the same FileDescriptor
+ */
+ private static void MultiThreadedFD() throws Exception {
+ RandomAccessFile raf = null;
+ FileDescriptor fd = null;
+ int numThreads = 2;
+ CountDownLatch done = new CountDownLatch(numThreads);
+ OpenClose[] fileOpenClose = new OpenClose[numThreads];
+ File MultipleThreadedFD = new File("MultipleThreadedFD");
+ try {
+ raf = new RandomAccessFile(MultipleThreadedFD, "rw");
+ fd = raf.getFD();
+ for(int count=0;count<numThreads;count++) {
+ fileOpenClose[count] = new OpenClose(fd, done);
+ fileOpenClose[count].start();
+ }
+ done.await();
+ } finally {
+ try {
+ if(raf != null) raf.close();
+ // fd should now no longer be valid
+ if(fd.valid()) {
+ throw new RuntimeException("FileDescriptor should not be valid");
+ }
+ // OpenClose thread tests failed
+ if(fail) {
+ throw new RuntimeException("OpenClose thread tests failed.");
+ }
+ } finally {
+ MultipleThreadedFD.delete();
+ }
+ }
+ }
+
+ /**
+ * Test closeAll handling in FileDescriptor
+ */
+ private static void TestCloseAll() throws Exception {
+ File testFile = new File("test");
+ testFile.deleteOnExit();
+ RandomAccessFile raf = new RandomAccessFile(testFile, "rw");
+ FileInputStream fis = new FileInputStream(raf.getFD());
+ fis.close();
+ if (raf.getFD().valid()) {
+ throw new RuntimeException("FD should not be valid.");
+ }
+
+ // Test the suppressed exception handling - FileInputStream
+
+ raf = new RandomAccessFile(testFile, "rw");
+ fis = new FileInputStream(raf.getFD());
+ BadFileInputStream bfis1 = new BadFileInputStream(raf.getFD());
+ BadFileInputStream bfis2 = new BadFileInputStream(raf.getFD());
+ BadFileInputStream bfis3 = new BadFileInputStream(raf.getFD());
+ // extra test - set bfis3 to null
+ bfis3 = null;
+ try {
+ fis.close();
+ } catch (IOException ioe) {
+ ioe.printStackTrace();
+ if (ioe.getSuppressed().length != 2) {
+ throw new RuntimeException("[FIS]Incorrect number of suppressed " +
+ "exceptions received : " + ioe.getSuppressed().length);
+ }
+ }
+ if (raf.getFD().valid()) {
+ // we should still have closed the FD
+ // even with the exception.
+ throw new RuntimeException("[FIS]TestCloseAll : FD still valid.");
+ }
+
+ // Now test with FileOutputStream
+
+ raf = new RandomAccessFile(testFile, "rw");
+ FileOutputStream fos = new FileOutputStream(raf.getFD());
+ BadFileOutputStream bfos1 = new BadFileOutputStream(raf.getFD());
+ BadFileOutputStream bfos2 = new BadFileOutputStream(raf.getFD());
+ BadFileOutputStream bfos3 = new BadFileOutputStream(raf.getFD());
+ // extra test - set bfos3 to null
+ bfos3 = null;
+ try {
+ fos.close();
+ } catch (IOException ioe) {
+ ioe.printStackTrace();
+ if (ioe.getSuppressed().length != 2) {
+ throw new RuntimeException("[FOS]Incorrect number of suppressed " +
+ "exceptions received : " + ioe.getSuppressed().length);
+ }
+ }
+ if (raf.getFD().valid()) {
+ // we should still have closed the FD
+ // even with the exception.
+ throw new RuntimeException("[FOS]TestCloseAll : FD still valid.");
+ }
+ }
+
+ /**
+ * A thread which will open and close a number of FileInputStreams and
+ * FileOutputStreams referencing the same native file descriptor.
+ */
+ private static class OpenClose extends Thread {
+ private FileDescriptor fd = null;
+ private CountDownLatch done;
+ FileInputStream[] fisArray = new FileInputStream[numFiles];
+ FileOutputStream[] fosArray = new FileOutputStream[numFiles];
+
+ OpenClose(FileDescriptor filedescriptor, CountDownLatch done) {
+ this.fd = filedescriptor;
+ this.done = done;
+ }
+
+ public void run() {
+ try {
+ for(int i=0;i<numFiles;i++) {
+ fisArray[i] = new FileInputStream(fd);
+ fosArray[i] = new FileOutputStream(fd);
+ }
+
+ // Now close out
+ for(int i=0;i<numFiles;i++) {
+ if(fisArray[i] != null) fisArray[i].close();
+ if(fosArray[i] != null) fosArray[i].close();
+ }
+
+ } catch(IOException ioe) {
+ System.out.println("OpenClose encountered IO issue :" + ioe);
+ fail = true;
+ } finally {
+ if (fd.valid()) { // fd should not be valid after first close() call
+ System.out.println("OpenClose: FileDescriptor shouldn't be valid");
+ fail = true;
+ }
+ done.countDown();
+ }
+ }
+ }
+
+ private static class BadFileInputStream extends FileInputStream {
+
+ BadFileInputStream(FileDescriptor fd) {
+ super(fd);
+ }
+
+ public void close() throws IOException {
+ throw new IOException("Bad close operation");
+ }
+ }
+
+ private static class BadFileOutputStream extends FileOutputStream {
+
+ BadFileOutputStream(FileDescriptor fd) {
+ super(fd);
+ }
+
+ public void close() throws IOException {
+ throw new IOException("Bad close operation");
+ }
+ }
+
+}
--- a/jdk/test/java/io/etc/FileDescriptorSharing.java Fri Nov 18 16:57:01 2011 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,336 +0,0 @@
-/*
- * Copyright (c) 2011, 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.
- *
- * 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.
- */
-
-/*
- * @test
- * @bug 6322678 7082769
- * @summary FileInputStream/FileOutputStream/RandomAccessFile allow file descriptor
- * to be closed while still in use.
- * @run main/othervm FileDescriptorSharing
- */
-
-import java.io.*;
-import java.nio.channels.FileChannel;
-import java.nio.channels.FileLock;
-import java.util.concurrent.CountDownLatch;
-
-public class FileDescriptorSharing {
-
- final static int numFiles = 10;
- volatile static boolean fail;
-
- public static void main(String[] args) throws Exception {
- TestFinalizer();
- TestMultipleFD();
- TestIsValid();
- MultiThreadedFD();
- }
-
- /**
- * We shouldn't discard a file descriptor until all streams have
- * finished with it
- */
- private static void TestFinalizer() throws Exception {
- FileDescriptor fd = null;
- File tempFile = new File("TestFinalizer1.txt");
- tempFile.deleteOnExit();
- try (Writer writer = new FileWriter(tempFile)) {
- for (int i=0; i<5; i++) {
- writer.write("test file content test file content");
- }
- }
-
- FileInputStream fis1 = new FileInputStream(tempFile);
- fd = fis1.getFD();
- // Create a new FIS based on the existing FD (so the two FIS's share the same native fd)
- try (FileInputStream fis2 = new FileInputStream(fd)) {
- // allow fis1 to be gc'ed
- fis1 = null;
- int ret = 0;
- while(ret >= 0) {
- // encourage gc
- System.gc();
- // read from fis2 - when fis1 is gc'ed and finalizer is run, read will fail
- System.out.print(".");
- ret = fis2.read();
- }
- }
-
- // variation of above. Use RandomAccessFile to obtain a filedescriptor
- File testFinalizerFile = new File("TestFinalizer");
- RandomAccessFile raf = new RandomAccessFile(testFinalizerFile, "rw");
- raf.writeBytes("test file content test file content");
- raf.seek(0L);
- fd = raf.getFD();
- try (FileInputStream fis3 = new FileInputStream(fd)) {
- // allow raf to be gc'ed
- raf = null;
- int ret = 0;
- while (ret >= 0) {
- // encourage gc
- System.gc();
- /*
- * read from fis3 - when raf is gc'ed and finalizer is run,
- * fd should still be valid.
- */
- System.out.print(".");
- ret = fis3.read();
- }
- if(!fd.valid()) {
- throw new RuntimeException("TestFinalizer() : FileDescriptor should be valid");
- }
- } finally {
- testFinalizerFile.delete();
- }
- }
-
- /**
- * Exercise FileDispatcher close()/preClose()
- */
- private static void TestMultipleFD() throws Exception {
- RandomAccessFile raf = null;
- FileOutputStream fos = null;
- FileInputStream fis = null;
- FileChannel fc = null;
- FileLock fileLock = null;
-
- File test1 = new File("test1");
- try {
- raf = new RandomAccessFile(test1, "rw");
- fos = new FileOutputStream(raf.getFD());
- fis = new FileInputStream(raf.getFD());
- fc = raf.getChannel();
- fileLock = fc.lock();
- raf.setLength(0L);
- fos.flush();
- fos.write("TEST".getBytes());
- } finally {
- if (fileLock != null) fileLock.release();
- if (fis != null) fis.close();
- if (fos != null) fos.close();
- if (raf != null) raf.close();
- test1.delete();
- }
-
- /*
- * Close out in different order to ensure FD is not
- * closed out too early
- */
- File test2 = new File("test2");
- try {
- raf = new RandomAccessFile(test2, "rw");
- fos = new FileOutputStream(raf.getFD());
- fis = new FileInputStream(raf.getFD());
- fc = raf.getChannel();
- fileLock = fc.lock();
- raf.setLength(0L);
- fos.flush();
- fos.write("TEST".getBytes());
- } finally {
- if (fileLock != null) fileLock.release();
- if (raf != null) raf.close();
- if (fos != null) fos.close();
- if (fis != null) fis.close();
- test2.delete();
- }
-
- // one more time, fos first this time
- File test3 = new File("test3");
- try {
- raf = new RandomAccessFile(test3, "rw");
- fos = new FileOutputStream(raf.getFD());
- fis = new FileInputStream(raf.getFD());
- fc = raf.getChannel();
- fileLock = fc.lock();
- raf.setLength(0L);
- fos.flush();
- fos.write("TEST".getBytes());
- } finally {
- if (fileLock != null) fileLock.release();
- if (fos != null) fos.close();
- if (raf != null) raf.close();
- if (fis != null) fis.close();
- test3.delete();
- }
- }
-
- /**
- * Similar to TestMultipleFD() but this time we
- * just get and use FileDescriptor.valid() for testing.
- */
- private static void TestIsValid() throws Exception {
- FileDescriptor fd = null;
- RandomAccessFile raf = null;
- FileOutputStream fos = null;
- FileInputStream fis = null;
- FileChannel fc = null;
-
- File test1 = new File("test1");
- try {
- raf = new RandomAccessFile(test1, "rw");
- fd = raf.getFD();
- fos = new FileOutputStream(fd);
- fis = new FileInputStream(fd);
- } finally {
- try {
- if (fis != null) fis.close();
- if (fos != null) fos.close();
- if (!fd.valid()) {
- throw new RuntimeException("FileDescriptor should be valid");
- }
- if (raf != null) raf.close();
- if (fd.valid()) {
- throw new RuntimeException("close() called and FileDescriptor still valid");
- }
- } finally {
- if (raf != null) raf.close();
- test1.delete();
- }
- }
-
- /*
- * Close out in different order to ensure FD is not
- * closed out too early
- */
- File test2 = new File("test2");
- try {
- raf = new RandomAccessFile(test2, "rw");
- fd = raf.getFD();
- fos = new FileOutputStream(fd);
- fis = new FileInputStream(fd);
- } finally {
- try {
- if (raf != null) raf.close();
- if (fos != null) fos.close();
- if (!fd.valid()) {
- throw new RuntimeException("FileDescriptor should be valid");
- }
- if (fis != null) fis.close();
- if (fd.valid()) {
- throw new RuntimeException("close() called and FileDescriptor still valid");
- }
- } finally {
- test2.delete();
- }
- }
-
- // one more time, fos first this time
- File test3 = new File("test3");
- try {
- raf = new RandomAccessFile(test3, "rw");
- fd = raf.getFD();
- fos = new FileOutputStream(fd);
- fis = new FileInputStream(fd);
- } finally {
- try {
- if (fos != null) fos.close();
- if (raf != null) raf.close();
- if (!fd.valid()) {
- throw new RuntimeException("FileDescriptor should be valid");
- }
- if (fis != null) fis.close();
- if (fd.valid()) {
- throw new RuntimeException("close() called and FileDescriptor still valid");
- }
- } finally {
- test3.delete();
- }
- }
- }
-
- /**
- * Test concurrent access to the same fd.useCount field
- */
- private static void MultiThreadedFD() throws Exception {
- RandomAccessFile raf = null;
- FileDescriptor fd = null;
- int numThreads = 2;
- CountDownLatch done = new CountDownLatch(numThreads);
- OpenClose[] fileOpenClose = new OpenClose[numThreads];
- File MultipleThreadedFD = new File("MultipleThreadedFD");
- try {
- raf = new RandomAccessFile(MultipleThreadedFD, "rw");
- fd = raf.getFD();
- for(int count=0;count<numThreads;count++) {
- fileOpenClose[count] = new OpenClose(fd, done);
- fileOpenClose[count].start();
- }
- done.await();
- } finally {
- try {
- if(raf != null) raf.close();
- // fd should now no longer be valid
- if(fd.valid()) {
- throw new RuntimeException("FileDescriptor should not be valid");
- }
- // OpenClose thread tests failed
- if(fail) {
- throw new RuntimeException("OpenClose thread tests failed.");
- }
- } finally {
- MultipleThreadedFD.delete();
- }
- }
- }
-
- /**
- * A thread which will open and close a number of FileInputStreams and
- * FileOutputStreams referencing the same native file descriptor.
- */
- private static class OpenClose extends Thread {
- private FileDescriptor fd = null;
- private CountDownLatch done;
- FileInputStream[] fisArray = new FileInputStream[numFiles];
- FileOutputStream[] fosArray = new FileOutputStream[numFiles];
-
- OpenClose(FileDescriptor filedescriptor, CountDownLatch done) {
- this.fd = filedescriptor;
- this.done = done;
- }
-
- public void run() {
- try {
- for(int i=0;i<numFiles;i++) {
- fisArray[i] = new FileInputStream(fd);
- fosArray[i] = new FileOutputStream(fd);
- }
-
- // Now close out
- for(int i=0;i<numFiles;i++) {
- if(fisArray[i] != null) fisArray[i].close();
- if(fosArray[i] != null) fosArray[i].close();
- }
-
- } catch(IOException ioe) {
- System.out.println("OpenClose encountered IO issue :" + ioe);
- fail = true;
- } finally {
- if (!fd.valid()) { // fd should still be valid given RAF reference
- System.out.println("OpenClose: FileDescriptor should be valid");
- fail = true;
- }
- done.countDown();
- }
- }
- }
-}
--- a/jdk/test/java/lang/Runtime/exec/StreamsSurviveDestroy.java Fri Nov 18 16:57:01 2011 -0800
+++ b/jdk/test/java/lang/Runtime/exec/StreamsSurviveDestroy.java Mon Nov 28 15:15:50 2011 -0800
@@ -28,6 +28,7 @@
*/
import java.io.*;
+import java.util.concurrent.*;
public class StreamsSurviveDestroy {
@@ -40,15 +41,17 @@
boolean wantInterrupt;
boolean acceptException;
Exception exc = null;
+ CountDownLatch latch;
Copier(String name, InputStream in, OutputStream out,
- boolean ae, boolean wi)
+ boolean ae, boolean wi, CountDownLatch l)
{
this.name = name;
this.in = in;
this.out = out;
this.acceptException = ae;
this.wantInterrupt = wi;
+ this.latch = l;
setName(name);
start();
}
@@ -59,6 +62,7 @@
public void run() {
byte[] buf = new byte[4242];
+ latch.countDown();
for (;;) {
try {
int n = in.read(buf);
@@ -95,13 +99,17 @@
}
static void test() throws Exception {
+ CountDownLatch latch = new CountDownLatch(2);
+
System.err.println("test");
Process p = Runtime.getRuntime().exec("/bin/cat");
Copier cp1 = new Copier("out", p.getInputStream(), System.err,
- false, false);
+ false, false, latch);
Copier cp2 = new Copier("err", p.getErrorStream(), System.err,
- false, false);
- Thread.sleep(100);
+ false, false, latch);
+ latch.await(); // Wait till both Copiers about to read
+ Thread.sleep(100);// Give both Copiers a chance to start read
+
p.destroy();
System.err.println(" exit: " + p.waitFor());
cp1.join();
@@ -111,13 +119,17 @@
}
static void testCloseBeforeDestroy() throws Exception {
+ CountDownLatch latch = new CountDownLatch(2);
+
System.err.println("testCloseBeforeDestroy");
Process p = Runtime.getRuntime().exec("/bin/cat");
Copier cp1 = new Copier("out", p.getInputStream(), System.err,
- true, false);
+ true, false, latch);
Copier cp2 = new Copier("err", p.getErrorStream(), System.err,
- true, false);
- Thread.sleep(100);
+ true, false, latch);
+ latch.await(); // Wait till both Copiers about to read
+ Thread.sleep(100);// Give both Copiers a chance to start read
+
p.getInputStream().close();
p.getErrorStream().close();
p.destroy();
@@ -129,13 +141,17 @@
}
static void testCloseAfterDestroy() throws Exception {
+ CountDownLatch latch = new CountDownLatch(2);
System.err.println("testCloseAfterDestroy");
Process p = Runtime.getRuntime().exec("/bin/cat");
Copier cp1 = new Copier("out", p.getInputStream(), System.err,
- true, false);
+ true, false,latch);
Copier cp2 = new Copier("err", p.getErrorStream(), System.err,
- true, false);
- Thread.sleep(100);
+ true, false, latch);
+
+ latch.await(); // Wait till both Copiers about to read
+ Thread.sleep(100);// Give both Copiers a chance to start read
+
p.destroy();
p.getInputStream().close();
p.getErrorStream().close();
@@ -147,13 +163,16 @@
}
static void testInterrupt() throws Exception {
+ CountDownLatch latch = new CountDownLatch(2);
System.err.println("testInterrupt");
Process p = Runtime.getRuntime().exec("/bin/cat");
Copier cp1 = new Copier("out", p.getInputStream(), System.err,
- false, true);
+ false, true, latch);
Copier cp2 = new Copier("err", p.getErrorStream(), System.err,
- false, true);
- Thread.sleep(100);
+ false, true, latch);
+ latch.await(); // Wait till both Copiers about to read
+ Thread.sleep(100);// Give both Copiers a chance to start read
+
cp1.interrupt();
cp2.interrupt();
Thread.sleep(100);
@@ -176,7 +195,5 @@
testCloseBeforeDestroy();
testCloseAfterDestroy();
testInterrupt();
-
}
-
}
--- a/jdk/test/java/lang/ThreadGroup/NullThreadName.java Fri Nov 18 16:57:01 2011 -0800
+++ b/jdk/test/java/lang/ThreadGroup/NullThreadName.java Mon Nov 28 15:15:50 2011 -0800
@@ -24,7 +24,6 @@
/*
* @test
* @bug 6576763
- * @ignore until hotspot 6776144 bug is resolved
* @summary (thread) Thread constructors throw undocumented NPE for null name
*/
@@ -64,8 +63,8 @@
try { Thread.sleep(2000); }
catch (InterruptedException unused) {}
- /* do not wait forever */
- if (count++ > 5)
+ /* do not wait forever - allow 120 seconds same as jtreg default timeout. */
+ if (count++ > 60)
throw new AssertionError("GoodThread is still alive!");
}
--- a/jdk/test/java/lang/ThreadGroup/Stop.java Fri Nov 18 16:57:01 2011 -0800
+++ b/jdk/test/java/lang/ThreadGroup/Stop.java Mon Nov 28 15:15:50 2011 -0800
@@ -29,37 +29,58 @@
*/
public class Stop implements Runnable {
- private static Thread first=null;
- private static Thread second=null;
- private static ThreadGroup group = new ThreadGroup("");
+ private static boolean groupStopped = false ;
+ private static final Object lock = new Object();
- Stop() {
- Thread thread = new Thread(group, this);
- if (first == null)
- first = thread;
- else
- second = thread;
-
- thread.start();
- }
+ private static final ThreadGroup group = new ThreadGroup("");
+ private static final Thread first = new Thread(group, new Stop());
+ private static final Thread second = new Thread(group, new Stop());
public void run() {
while (true) {
+ // Give the other thread a chance to start
try {
- Thread.sleep(1000); // Give other thread a chance to start
- if (Thread.currentThread() == first)
- group.stop();
- } catch(InterruptedException e){
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ }
+
+ // When the first thread runs, it will stop the group.
+ if (Thread.currentThread() == first) {
+ synchronized (lock) {
+ try {
+ group.stop();
+ } finally {
+ // Signal the main thread it is time to check
+ // that the stopped thread group was successful
+ groupStopped = true;
+ lock.notifyAll();
+ }
+ }
}
}
}
public static void main(String[] args) throws Exception {
- for (int i=0; i<2; i++)
- new Stop();
- Thread.sleep(3000);
+ // Launch two threads as part of the same thread group
+ first.start();
+ second.start();
+
+ // Wait for the thread group stop to be issued
+ synchronized(lock){
+ while (!groupStopped) {
+ lock.wait();
+ // Give the other thread a chance to stop
+ Thread.sleep(1000);
+ }
+ }
+
+ // Check that the second thread is terminated when the
+ // first thread terminates the thread group.
boolean failed = second.isAlive();
- first.stop(); second.stop();
+
+ // Clean up any threads that may have not been terminated
+ first.stop();
+ second.stop();
if (failed)
throw new RuntimeException("Failure.");
}
--- a/jdk/test/java/lang/management/PlatformLoggingMXBean/LoggingMXBeanTest.java Fri Nov 18 16:57:01 2011 -0800
+++ b/jdk/test/java/lang/management/PlatformLoggingMXBean/LoggingMXBeanTest.java Mon Nov 28 15:15:50 2011 -0800
@@ -23,7 +23,7 @@
/*
* @test
- * @bug 7024172
+ * @bug 7024172 7067691
* @summary Test if proxy for PlatformLoggingMXBean is equivalent
* to proxy for LoggingMXBean
*
@@ -43,6 +43,13 @@
static String LOGGER_NAME_2 = "com.sun.management.Logger.Logger2";
static String UNKNOWN_LOGGER_NAME = "com.sun.management.Unknown";
+ // These instance variables prevent premature logger garbage collection
+ // See getLogger() weak reference warnings.
+ Logger logger1;
+ Logger logger2;
+
+ static LoggingMXBeanTest test;
+
public static void main(String[] argv) throws Exception {
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
LoggingMXBean proxy =
@@ -51,7 +58,7 @@
LoggingMXBean.class);
// test LoggingMXBean proxy
- LoggingMXBeanTest p = new LoggingMXBeanTest(proxy);
+ test = new LoggingMXBeanTest(proxy);
// check if the attributes implemented by PlatformLoggingMXBean
// and LoggingMXBean return the same value
@@ -64,9 +71,9 @@
// same verification as in java/util/logging/LoggingMXBeanTest2
public LoggingMXBeanTest(LoggingMXBean mbean) throws Exception {
- Logger logger1 = Logger.getLogger( LOGGER_NAME_1 );
+ logger1 = Logger.getLogger( LOGGER_NAME_1 );
logger1.setLevel(Level.FINE);
- Logger logger2 = Logger.getLogger( LOGGER_NAME_2 );
+ logger2 = Logger.getLogger( LOGGER_NAME_2 );
logger2.setLevel(null);
/*
@@ -207,6 +214,7 @@
// verify logger names
List<String> loggers1 = mxbean1.getLoggerNames();
List<String> loggers2 = mxbean2.getLoggerNames();
+
if (loggers1.size() != loggers2.size())
throw new RuntimeException("LoggerNames: unmatched number of entries");
List<String> loggers3 = new ArrayList<>(loggers1);
@@ -219,7 +227,10 @@
if (!mxbean1.getLoggerLevel(logger)
.equals(mxbean2.getLoggerLevel(logger)))
throw new RuntimeException(
- "LoggerLevel: unmatched level for " + logger);
+ "LoggerLevel: unmatched level for " + logger
+ + ", " + mxbean1.getLoggerLevel(logger)
+ + ", " + mxbean2.getLoggerLevel(logger));
+
if (!mxbean1.getParentLoggerName(logger)
.equals(mxbean2.getParentLoggerName(logger)))
throw new RuntimeException(
--- a/jdk/test/java/lang/management/PlatformLoggingMXBean/PlatformLoggingMXBeanTest.java Fri Nov 18 16:57:01 2011 -0800
+++ b/jdk/test/java/lang/management/PlatformLoggingMXBean/PlatformLoggingMXBeanTest.java Mon Nov 28 15:15:50 2011 -0800
@@ -23,7 +23,7 @@
/*
* @test
- * @bug 6876135 7024172
+ * @bug 6876135 7024172 7067691
*
* @summary Test PlatformLoggingMXBean
* This test performs similar testing as
@@ -41,11 +41,15 @@
public class PlatformLoggingMXBeanTest
{
-
ObjectName objectName = null;
static String LOGGER_NAME_1 = "com.sun.management.Logger1";
static String LOGGER_NAME_2 = "com.sun.management.Logger2";
+ // Use Logger instance variables to prevent premature garbage collection
+ // of weak references.
+ Logger logger1;
+ Logger logger2;
+
public PlatformLoggingMXBeanTest() throws Exception {
}
@@ -135,8 +139,8 @@
System.out.println( "*********** Phase 3 ***********" );
System.out.println( "*******************************" );
System.out.println( " Create and test new Loggers" );
- Logger logger1 = Logger.getLogger( LOGGER_NAME_1 );
- Logger logger2 = Logger.getLogger( LOGGER_NAME_2 );
+ logger1 = Logger.getLogger( LOGGER_NAME_1 );
+ logger2 = Logger.getLogger( LOGGER_NAME_2 );
// check that Level object are returned properly
try {
@@ -187,6 +191,7 @@
System.out.println( " Set and Check the Logger Level" );
log1 = false;
log2 = false;
+
try {
// Set the level of logger1 to ALL
params = new Object[2];
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/rmi/registry/readTest/readTest.java Mon Nov 28 15:15:50 2011 -0800
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2011, 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.
+ *
+ * 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.
+ */
+
+import java.rmi.registry.Registry;
+import java.rmi.registry.LocateRegistry;
+import java.rmi.RemoteException;
+import java.rmi.server.UnicastRemoteObject;
+
+public class readTest {
+
+ public static void main(String args[]) throws Exception {
+ int port = 7491;
+ try {
+ testPkg.Server obj = new testPkg.Server();
+ testPkg.Hello stub = (testPkg.Hello) UnicastRemoteObject.exportObject(obj, 0);
+ // Bind the remote object's stub in the registry
+ Registry registry = LocateRegistry.getRegistry(port);
+ registry.bind("Hello", stub);
+
+ System.err.println("Server ready");
+
+ // now, let's test client
+ testPkg.Client client = new testPkg.Client(port);
+ String testStubReturn = client.testStub();
+ if(!testStubReturn.equals(obj.hello)) {
+ throw new RuntimeException("Test Fails : unexpected string from stub call");
+ } else {
+ System.out.println("Test passed");
+ }
+ registry.unbind("Hello");
+
+ } catch (Exception e) {
+ System.err.println("Server exception: " + e.toString());
+ e.printStackTrace();
+ }
+
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/rmi/registry/readTest/readTest.sh Mon Nov 28 15:15:50 2011 -0800
@@ -0,0 +1,95 @@
+#
+# Copyright (c) 2011, 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.
+#
+# 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.
+#
+
+# @test
+# @bug 7102369 7094468 7100592
+# @summary remove java.rmi.server.codebase property parsing from registyimpl
+# @run shell readTest.sh
+
+OS=`uname -s`
+case "$OS" in
+ SunOS | Linux )
+ PS=":"
+ FS="/"
+ FILEURL="file:"
+ ;;
+ Windows* | CYGWIN* )
+ PS=";"
+ FS="\\"
+ FILEURL="file:/"
+ ;;
+ * )
+ echo "Unrecognized system!"
+ exit 1;
+ ;;
+esac
+
+cp -r ${TESTSRC}${FS}* .
+${TESTJAVA}${FS}bin${FS}javac testPkg${FS}*java
+${TESTJAVA}${FS}bin${FS}javac readTest.java
+
+mkdir rmi_tmp
+RMIREG_OUT=rmi.out
+#start rmiregistry without any local classes on classpath
+cd rmi_tmp
+${TESTJAVA}${FS}bin${FS}rmiregistry 7491 > ..${FS}${RMIREG_OUT} 2>&1 &
+RMIREG_PID=$!
+# allow some time to start
+sleep 3
+cd ..
+
+# trailing / after code base is important for rmi codebase property.
+${TESTJAVA}${FS}bin${FS}java -Djava.rmi.server.codebase=${FILEURL}`pwd`/ readTest > OUT.TXT 2>&1 &
+TEST_PID=$!
+#bulk of testcase - let it run for a while
+sleep 5
+
+#we're done, kill processes first
+kill -9 ${RMIREG_PID} ${TEST_PID}
+sleep 3
+
+echo "Test output : "
+
+cat OUT.TXT
+echo "=============="
+echo "rmiregistry output : "
+cat ${RMIREG_OUT}
+echo "=============="
+
+grep "Server ready" OUT.TXT
+result1=$?
+grep "Test passed" OUT.TXT
+result2=$?
+
+if [ $result1 -eq 0 -a $result2 -eq 0 ]
+then
+ echo "Passed"
+ exitCode=0;
+else
+ echo "Failed"
+ exitCode=1
+fi
+rm -rf OUT.TXT ${RMIREG_OUT} rmi_tmp
+exit ${exitCode}
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/rmi/registry/readTest/testPkg/Client.java Mon Nov 28 15:15:50 2011 -0800
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2011, 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.
+ *
+ * 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 testPkg;
+
+import java.rmi.registry.LocateRegistry;
+import java.rmi.registry.Registry;
+
+public class Client {
+ int port;
+
+ public Client(int p) {
+ port = p;
+ }
+
+ public String testStub() throws Exception {
+ try {
+ Registry registry = LocateRegistry.getRegistry(port);
+ Hello stub = (Hello) registry.lookup("Hello");
+ String response = stub.sayHello();
+ return response;
+ } catch (Exception e) {
+ System.err.println("Client exception: " + e.toString());
+ throw e;
+ }
+ }
+ }
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/rmi/registry/readTest/testPkg/Hello.java Mon Nov 28 15:15:50 2011 -0800
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2011, 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.
+ *
+ * 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 testPkg;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+
+public interface Hello extends Remote {
+ String sayHello() throws RemoteException;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/rmi/registry/readTest/testPkg/Server.java Mon Nov 28 15:15:50 2011 -0800
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2011, 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.
+ *
+ * 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 testPkg;
+
+public class Server implements Hello {
+
+ public String hello = "Hello, world!";
+
+ public Server() {}
+
+ public String sayHello() {
+ return hello;
+ }
+
+}
--- a/jdk/test/java/util/Timer/Args.java Fri Nov 18 16:57:01 2011 -0800
+++ b/jdk/test/java/util/Timer/Args.java Mon Nov 28 15:15:50 2011 -0800
@@ -92,19 +92,22 @@
new F(){void f(){ t.scheduleAtFixedRate(x, (Date)null, 42); }}
);
- final long start = System.currentTimeMillis();
- final Date past = new Date(start - 10500);
final CountDownLatch y1 = new CountDownLatch(1);
final CountDownLatch y2 = new CountDownLatch(1);
final CountDownLatch y3 = new CountDownLatch(11);
+ final long start = System.currentTimeMillis();
+ final Date past = new Date(start - 10500);
+
schedule( t, counter(y1), past);
schedule( t, counter(y2), past, 1000);
scheduleAtFixedRate(t, counter(y3), past, 1000);
y3.await();
y1.await();
y2.await();
- System.out.printf("elapsed=%d%n", System.currentTimeMillis() - start);
- check(System.currentTimeMillis() - start < 500);
+
+ final long elapsed = System.currentTimeMillis() - start;
+ System.out.printf("elapsed=%d%n", elapsed);
+ check(elapsed < 500);
t.cancel();
--- a/jdk/test/java/util/Timer/KillThread.java Fri Nov 18 16:57:01 2011 -0800
+++ b/jdk/test/java/util/Timer/KillThread.java Mon Nov 28 15:15:50 2011 -0800
@@ -31,21 +31,26 @@
import java.util.*;
public class KillThread {
+ static volatile Thread tdThread;
public static void main (String[] args) throws Exception {
Timer t = new Timer();
// Start a mean event that kills the timer thread
t.schedule(new TimerTask() {
public void run() {
+ tdThread = Thread.currentThread();
throw new ThreadDeath();
}
}, 0);
// Wait for mean event to do the deed and thread to die.
try {
- Thread.sleep(100);
+ do {
+ Thread.sleep(100);
+ } while(tdThread == null);
} catch(InterruptedException e) {
}
+ tdThread.join();
// Try to start another event
try {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLContextImpl/MD2InTrustAnchor.java Mon Nov 28 15:15:50 2011 -0800
@@ -0,0 +1,423 @@
+/*
+ * Copyright (c) 2011, 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.
+ */
+
+/*
+ * @test
+ * @bug 7113275
+ * @summary compatibility issue with MD2 trust anchor and old X509TrustManager
+ *
+ * SunJSSE does not support dynamic system properties, no way to re-use
+ * system properties in samevm/agentvm mode.
+ * @run main/othervm MD2InTrustAnchor PKIX TLSv1.1
+ * @run main/othervm MD2InTrustAnchor SunX509 TLSv1.1
+ * @run main/othervm MD2InTrustAnchor PKIX TLSv1.2
+ * @run main/othervm MD2InTrustAnchor SunX509 TLSv1.2
+ */
+
+import java.net.*;
+import java.util.*;
+import java.io.*;
+import javax.net.ssl.*;
+import java.security.KeyStore;
+import java.security.KeyFactory;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateFactory;
+import java.security.spec.*;
+import java.security.interfaces.*;
+import sun.misc.BASE64Decoder;
+
+
+public class MD2InTrustAnchor {
+
+ /*
+ * =============================================================
+ * Set the various variables needed for the tests, then
+ * specify what tests to run on each side.
+ */
+
+ /*
+ * Should we run the client or server in a separate thread?
+ * Both sides can throw exceptions, but do you have a preference
+ * as to which side should be the main thread.
+ */
+ static boolean separateServerThread = false;
+
+ /*
+ * Certificates and key used in the test.
+ */
+
+ // It's a trust anchor signed with MD2 hash function.
+ static String trustedCertStr =
+ "-----BEGIN CERTIFICATE-----\n" +
+ "MIICkjCCAfugAwIBAgIBADANBgkqhkiG9w0BAQIFADA7MQswCQYDVQQGEwJVUzEN\n" +
+ "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" +
+ "MTExMTE4MTExNDA0WhcNMzIxMDI4MTExNDA0WjA7MQswCQYDVQQGEwJVUzENMAsG\n" +
+ "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwgZ8wDQYJ\n" +
+ "KoZIhvcNAQEBBQADgY0AMIGJAoGBAPGyB9tugUGgxtdeqe0qJEwf9x1Gy4BOi1yR\n" +
+ "wzDZY4H5LquvIfQ2V3J9X1MQENVsFvkvp65ZcFcy+ObOucXUUPFcd/iw2DVb5QXA\n" +
+ "ffyeVqWD56GPi8Qe37wrJO3L6fBhN9oxp/BbdRLgjU81zx8qLEyPODhPMxV4OkcA\n" +
+ "SDwZTSxxAgMBAAGjgaUwgaIwHQYDVR0OBBYEFLOAtr/YrYj9H04EDLA0fd14jisF\n" +
+ "MGMGA1UdIwRcMFqAFLOAtr/YrYj9H04EDLA0fd14jisFoT+kPTA7MQswCQYDVQQG\n" +
+ "EwJVUzENMAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2\n" +
+ "Y2WCAQAwDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAQYwDQYJKoZIhvcNAQEC\n" +
+ "BQADgYEAr8ExpXu/FTIRiMzPm0ubqwME4lniilwQUiEOD/4DbksNjEIcUyS2hIk1\n" +
+ "qsmjJz3SHBnwhxl9dhJVwk2tZLkPGW86Zn0TPVRsttK4inTgCC9GFGeqQBdrU/uf\n" +
+ "lipBzXWljrfbg4N/kK8m2LabtKUMMnGysM8rN0Fx2PYm5xxGvtM=\n" +
+ "-----END CERTIFICATE-----";
+
+ // The certificate issued by above trust anchor, signed with MD5
+ static String targetCertStr =
+ "-----BEGIN CERTIFICATE-----\n" +
+ "MIICeDCCAeGgAwIBAgIBAjANBgkqhkiG9w0BAQQFADA7MQswCQYDVQQGEwJVUzEN\n" +
+ "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" +
+ "MTExMTE4MTExNDA2WhcNMzEwODA1MTExNDA2WjBPMQswCQYDVQQGEwJVUzENMAsG\n" +
+ "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UxEjAQBgNV\n" +
+ "BAMTCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwDnm96mw\n" +
+ "fXCH4bgXk1US0VcJsQVxUtGMyncAveMuzBzNzOmKZPeqyYX1Fuh4q+cuza03WTJd\n" +
+ "G9nOkNr364e3Rn1aaHjCMcBmFflObnGnhhufNmIGYogJ9dJPmhUVPEVAXrMG+Ces\n" +
+ "NKy2E8woGnLMrqu6yiuTClbLBPK8fWzTXrECAwEAAaN4MHYwCwYDVR0PBAQDAgPo\n" +
+ "MB0GA1UdDgQWBBSdRrpocLPJXyGfDmMWJrcEf29WGDAfBgNVHSMEGDAWgBSzgLa/\n" +
+ "2K2I/R9OBAywNH3deI4rBTAnBgNVHSUEIDAeBggrBgEFBQcDAQYIKwYBBQUHAwIG\n" +
+ "CCsGAQUFBwMDMA0GCSqGSIb3DQEBBAUAA4GBAKJ71ZiCUykkJrCLYUxlFlhvUcr9\n" +
+ "sTcOc67QdroW5f412NI15SXWDiley/JOasIiuIFPjaJBjOKoHOvTjG/snVu9wEgq\n" +
+ "YNR8dPsO+NM8r79C6jO+Jx5fYAC7os2XxS75h3NX0ElJcbwIXGBJ6xRrsFh/BGYH\n" +
+ "yvudOlX4BkVR0l1K\n" +
+ "-----END CERTIFICATE-----";
+
+ // Private key in the format of PKCS#8.
+ static String targetPrivateKey =
+ "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAMA55vepsH1wh+G4\n" +
+ "F5NVEtFXCbEFcVLRjMp3AL3jLswczczpimT3qsmF9RboeKvnLs2tN1kyXRvZzpDa\n" +
+ "9+uHt0Z9Wmh4wjHAZhX5Tm5xp4YbnzZiBmKICfXST5oVFTxFQF6zBvgnrDSsthPM\n" +
+ "KBpyzK6rusorkwpWywTyvH1s016xAgMBAAECgYEAn9bF3oRkdDoBU0i/mcww5I+K\n" +
+ "SH9tFt+WQbiojjz9ac49trkvUfu7MO1Jui2+QbrvaSkyj+HYGFOJd1wMsPXeB7ck\n" +
+ "5mOIYV4uZK8jfNMSQ8v0tFEeIPp5lKdw1XnrQfSe+abo2eL5Lwso437Y4s3w37+H\n" +
+ "aY3d76hR5qly+Ys+Ww0CQQDjeOoX89d/xhRqGXKjCx8ImE/dPmsI8O27cwtKrDYJ\n" +
+ "6t0v/xryVIdvOYcRBvKnqEogOH7T1kI+LnWKUTJ2ehJ7AkEA2FVloPVqCehXcc7e\n" +
+ "z3TDpU9w1B0JXklcV5HddYsRqp9RukN/VK4szKE7F1yoarIUtfE9Lr9082Jwyp3M\n" +
+ "L11xwwJBAKsZ+Hur3x0tUY29No2Nf/pnFyvEF57SGwA0uPmiL8Ol9lpz+UDudDEl\n" +
+ "hIM6Rqv12kwCMuQE9i7vo1o3WU3k5KECQEqhg1L49yD935TqiiFFpe0Ur9btQXse\n" +
+ "kdXAA4d2d5zGI7q/aGD9SYU6phkUJSHR16VA2RuUfzMrpb+wmm1IrmMCQFtLoKRT\n" +
+ "A5kokFb+E3Gplu29tJvCUpfwgBFRS+wmkvtiaU/tiyDcVgDO+An5DwedxxdVzqiE\n" +
+ "njWHoKY3axDQ8OU=\n";
+
+
+ static char passphrase[] = "passphrase".toCharArray();
+
+ /*
+ * Is the server ready to serve?
+ */
+ volatile static boolean serverReady = false;
+
+ /*
+ * Turn on SSL debugging?
+ */
+ static boolean debug = false;
+
+ /*
+ * Define the server side of the test.
+ *
+ * If the server prematurely exits, serverReady will be set to true
+ * to avoid infinite hangs.
+ */
+ void doServerSide() throws Exception {
+ SSLContext context = generateSSLContext(trustedCertStr, targetCertStr,
+ targetPrivateKey);
+ SSLServerSocketFactory sslssf = context.getServerSocketFactory();
+ SSLServerSocket sslServerSocket =
+ (SSLServerSocket)sslssf.createServerSocket(serverPort);
+ sslServerSocket.setNeedClientAuth(true);
+ serverPort = sslServerSocket.getLocalPort();
+
+ /*
+ * Signal Client, we're ready for his connect.
+ */
+ serverReady = true;
+
+ SSLSocket sslSocket = (SSLSocket)sslServerSocket.accept();
+ InputStream sslIS = sslSocket.getInputStream();
+ OutputStream sslOS = sslSocket.getOutputStream();
+
+ sslIS.read();
+ sslOS.write('A');
+ sslOS.flush();
+
+ sslSocket.close();
+ }
+
+ /*
+ * Define the client side of the test.
+ *
+ * If the server prematurely exits, serverReady will be set to true
+ * to avoid infinite hangs.
+ */
+ void doClientSide() throws Exception {
+
+ /*
+ * Wait for server to get started.
+ */
+ while (!serverReady) {
+ Thread.sleep(50);
+ }
+
+ SSLContext context = generateSSLContext(trustedCertStr, targetCertStr,
+ targetPrivateKey);
+ SSLSocketFactory sslsf = context.getSocketFactory();
+
+ SSLSocket sslSocket =
+ (SSLSocket)sslsf.createSocket("localhost", serverPort);
+
+ // enable the specified TLS protocol
+ sslSocket.setEnabledProtocols(new String[] {tlsProtocol});
+
+ InputStream sslIS = sslSocket.getInputStream();
+ OutputStream sslOS = sslSocket.getOutputStream();
+
+ sslOS.write('B');
+ sslOS.flush();
+ sslIS.read();
+
+ sslSocket.close();
+ }
+
+ /*
+ * =============================================================
+ * The remainder is just support stuff
+ */
+ private static String tmAlgorithm; // trust manager
+ private static String tlsProtocol; // trust manager
+
+ private static void parseArguments(String[] args) {
+ tmAlgorithm = args[0];
+ tlsProtocol = args[1];
+ }
+
+ private static SSLContext generateSSLContext(String trustedCertStr,
+ String keyCertStr, String keySpecStr) throws Exception {
+
+ // generate certificate from cert string
+ CertificateFactory cf = CertificateFactory.getInstance("X.509");
+
+ // create a key store
+ KeyStore ks = KeyStore.getInstance("JKS");
+ ks.load(null, null);
+
+ // import the trused cert
+ Certificate trusedCert = null;
+ ByteArrayInputStream is = null;
+ if (trustedCertStr != null) {
+ is = new ByteArrayInputStream(trustedCertStr.getBytes());
+ trusedCert = cf.generateCertificate(is);
+ is.close();
+
+ ks.setCertificateEntry("RSA Export Signer", trusedCert);
+ }
+
+ if (keyCertStr != null) {
+ // generate the private key.
+ PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec(
+ new BASE64Decoder().decodeBuffer(keySpecStr));
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPrivateKey priKey =
+ (RSAPrivateKey)kf.generatePrivate(priKeySpec);
+
+ // generate certificate chain
+ is = new ByteArrayInputStream(keyCertStr.getBytes());
+ Certificate keyCert = cf.generateCertificate(is);
+ is.close();
+
+ // It's not allowed to send MD2 signed certificate to peer,
+ // even it may be a trusted certificate. Then we will not
+ // place the trusted certficate in the chain.
+ Certificate[] chain = new Certificate[1];
+ chain[0] = keyCert;
+
+ // import the key entry.
+ ks.setKeyEntry("Whatever", priKey, passphrase, chain);
+ }
+
+ // create SSL context
+ TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmAlgorithm);
+ tmf.init(ks);
+
+ SSLContext ctx = SSLContext.getInstance(tlsProtocol);
+ if (keyCertStr != null && !keyCertStr.isEmpty()) {
+ KeyManagerFactory kmf = KeyManagerFactory.getInstance("NewSunX509");
+ kmf.init(ks, passphrase);
+
+ ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+ ks = null;
+ } else {
+ ctx.init(null, tmf.getTrustManagers(), null);
+ }
+
+ return ctx;
+ }
+
+
+ // use any free port by default
+ volatile int serverPort = 0;
+
+ volatile Exception serverException = null;
+ volatile Exception clientException = null;
+
+ public static void main(String[] args) throws Exception {
+ if (debug)
+ System.setProperty("javax.net.debug", "all");
+
+ /*
+ * Get the customized arguments.
+ */
+ parseArguments(args);
+
+ /*
+ * Start the tests.
+ */
+ new MD2InTrustAnchor();
+ }
+
+ Thread clientThread = null;
+ Thread serverThread = null;
+
+ /*
+ * Primary constructor, used to drive remainder of the test.
+ *
+ * Fork off the other side, then do your work.
+ */
+ MD2InTrustAnchor() throws Exception {
+ try {
+ if (separateServerThread) {
+ startServer(true);
+ startClient(false);
+ } else {
+ startClient(true);
+ startServer(false);
+ }
+ } catch (Exception e) {
+ // swallow for now. Show later
+ }
+
+ /*
+ * Wait for other side to close down.
+ */
+ if (separateServerThread) {
+ serverThread.join();
+ } else {
+ clientThread.join();
+ }
+
+ /*
+ * When we get here, the test is pretty much over.
+ * Which side threw the error?
+ */
+ Exception local;
+ Exception remote;
+ String whichRemote;
+
+ if (separateServerThread) {
+ remote = serverException;
+ local = clientException;
+ whichRemote = "server";
+ } else {
+ remote = clientException;
+ local = serverException;
+ whichRemote = "client";
+ }
+
+ /*
+ * If both failed, return the curthread's exception, but also
+ * print the remote side Exception
+ */
+ if ((local != null) && (remote != null)) {
+ System.out.println(whichRemote + " also threw:");
+ remote.printStackTrace();
+ System.out.println();
+ throw local;
+ }
+
+ if (remote != null) {
+ throw remote;
+ }
+
+ if (local != null) {
+ throw local;
+ }
+ }
+
+ void startServer(boolean newThread) throws Exception {
+ if (newThread) {
+ serverThread = new Thread() {
+ public void run() {
+ try {
+ doServerSide();
+ } catch (Exception e) {
+ /*
+ * Our server thread just died.
+ *
+ * Release the client, if not active already...
+ */
+ System.err.println("Server died...");
+ serverReady = true;
+ serverException = e;
+ }
+ }
+ };
+ serverThread.start();
+ } else {
+ try {
+ doServerSide();
+ } catch (Exception e) {
+ serverException = e;
+ } finally {
+ serverReady = true;
+ }
+ }
+ }
+
+ void startClient(boolean newThread) throws Exception {
+ if (newThread) {
+ clientThread = new Thread() {
+ public void run() {
+ try {
+ doClientSide();
+ } catch (Exception e) {
+ /*
+ * Our client thread just died.
+ */
+ System.err.println("Client died...");
+ clientException = e;
+ }
+ }
+ };
+ clientThread.start();
+ } else {
+ try {
+ doClientSide();
+ } catch (Exception e) {
+ clientException = e;
+ }
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLContextImpl/TrustTrustedCert.java Mon Nov 28 15:15:50 2011 -0800
@@ -0,0 +1,475 @@
+/*
+ * Copyright (c) 2011, 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.
+ */
+
+/*
+ * @test
+ * @bug 7113275
+ * @summary compatibility issue with MD2 trust anchor and old X509TrustManager
+ *
+ * SunJSSE does not support dynamic system properties, no way to re-use
+ * system properties in samevm/agentvm mode.
+ * @run main/othervm TrustTrustedCert PKIX TLSv1.1
+ * @run main/othervm TrustTrustedCert SunX509 TLSv1.1
+ * @run main/othervm TrustTrustedCert PKIX TLSv1.2
+ * @run main/othervm TrustTrustedCert SunX509 TLSv1.2
+ */
+
+import java.net.*;
+import java.util.*;
+import java.io.*;
+import javax.net.ssl.*;
+import java.security.*;
+import java.security.cert.*;
+import java.security.spec.*;
+import java.security.interfaces.*;
+import sun.misc.BASE64Decoder;
+
+
+public class TrustTrustedCert {
+
+ /*
+ * =============================================================
+ * Set the various variables needed for the tests, then
+ * specify what tests to run on each side.
+ */
+
+ /*
+ * Should we run the client or server in a separate thread?
+ * Both sides can throw exceptions, but do you have a preference
+ * as to which side should be the main thread.
+ */
+ static boolean separateServerThread = false;
+
+ /*
+ * Certificates and key used in the test.
+ */
+
+ // It's a trust anchor signed with MD2 hash function.
+ static String trustedCertStr =
+ "-----BEGIN CERTIFICATE-----\n" +
+ "MIICkjCCAfugAwIBAgIBADANBgkqhkiG9w0BAQIFADA7MQswCQYDVQQGEwJVUzEN\n" +
+ "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" +
+ "MTExMTE4MTExNDA0WhcNMzIxMDI4MTExNDA0WjA7MQswCQYDVQQGEwJVUzENMAsG\n" +
+ "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwgZ8wDQYJ\n" +
+ "KoZIhvcNAQEBBQADgY0AMIGJAoGBAPGyB9tugUGgxtdeqe0qJEwf9x1Gy4BOi1yR\n" +
+ "wzDZY4H5LquvIfQ2V3J9X1MQENVsFvkvp65ZcFcy+ObOucXUUPFcd/iw2DVb5QXA\n" +
+ "ffyeVqWD56GPi8Qe37wrJO3L6fBhN9oxp/BbdRLgjU81zx8qLEyPODhPMxV4OkcA\n" +
+ "SDwZTSxxAgMBAAGjgaUwgaIwHQYDVR0OBBYEFLOAtr/YrYj9H04EDLA0fd14jisF\n" +
+ "MGMGA1UdIwRcMFqAFLOAtr/YrYj9H04EDLA0fd14jisFoT+kPTA7MQswCQYDVQQG\n" +
+ "EwJVUzENMAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2\n" +
+ "Y2WCAQAwDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAQYwDQYJKoZIhvcNAQEC\n" +
+ "BQADgYEAr8ExpXu/FTIRiMzPm0ubqwME4lniilwQUiEOD/4DbksNjEIcUyS2hIk1\n" +
+ "qsmjJz3SHBnwhxl9dhJVwk2tZLkPGW86Zn0TPVRsttK4inTgCC9GFGeqQBdrU/uf\n" +
+ "lipBzXWljrfbg4N/kK8m2LabtKUMMnGysM8rN0Fx2PYm5xxGvtM=\n" +
+ "-----END CERTIFICATE-----";
+
+ // The certificate issued by above trust anchor, signed with MD5
+ static String targetCertStr =
+ "-----BEGIN CERTIFICATE-----\n" +
+ "MIICeDCCAeGgAwIBAgIBAjANBgkqhkiG9w0BAQQFADA7MQswCQYDVQQGEwJVUzEN\n" +
+ "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" +
+ "MTExMTE4MTExNDA2WhcNMzEwODA1MTExNDA2WjBPMQswCQYDVQQGEwJVUzENMAsG\n" +
+ "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UxEjAQBgNV\n" +
+ "BAMTCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwDnm96mw\n" +
+ "fXCH4bgXk1US0VcJsQVxUtGMyncAveMuzBzNzOmKZPeqyYX1Fuh4q+cuza03WTJd\n" +
+ "G9nOkNr364e3Rn1aaHjCMcBmFflObnGnhhufNmIGYogJ9dJPmhUVPEVAXrMG+Ces\n" +
+ "NKy2E8woGnLMrqu6yiuTClbLBPK8fWzTXrECAwEAAaN4MHYwCwYDVR0PBAQDAgPo\n" +
+ "MB0GA1UdDgQWBBSdRrpocLPJXyGfDmMWJrcEf29WGDAfBgNVHSMEGDAWgBSzgLa/\n" +
+ "2K2I/R9OBAywNH3deI4rBTAnBgNVHSUEIDAeBggrBgEFBQcDAQYIKwYBBQUHAwIG\n" +
+ "CCsGAQUFBwMDMA0GCSqGSIb3DQEBBAUAA4GBAKJ71ZiCUykkJrCLYUxlFlhvUcr9\n" +
+ "sTcOc67QdroW5f412NI15SXWDiley/JOasIiuIFPjaJBjOKoHOvTjG/snVu9wEgq\n" +
+ "YNR8dPsO+NM8r79C6jO+Jx5fYAC7os2XxS75h3NX0ElJcbwIXGBJ6xRrsFh/BGYH\n" +
+ "yvudOlX4BkVR0l1K\n" +
+ "-----END CERTIFICATE-----";
+
+ // Private key in the format of PKCS#8.
+ static String targetPrivateKey =
+ "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAMA55vepsH1wh+G4\n" +
+ "F5NVEtFXCbEFcVLRjMp3AL3jLswczczpimT3qsmF9RboeKvnLs2tN1kyXRvZzpDa\n" +
+ "9+uHt0Z9Wmh4wjHAZhX5Tm5xp4YbnzZiBmKICfXST5oVFTxFQF6zBvgnrDSsthPM\n" +
+ "KBpyzK6rusorkwpWywTyvH1s016xAgMBAAECgYEAn9bF3oRkdDoBU0i/mcww5I+K\n" +
+ "SH9tFt+WQbiojjz9ac49trkvUfu7MO1Jui2+QbrvaSkyj+HYGFOJd1wMsPXeB7ck\n" +
+ "5mOIYV4uZK8jfNMSQ8v0tFEeIPp5lKdw1XnrQfSe+abo2eL5Lwso437Y4s3w37+H\n" +
+ "aY3d76hR5qly+Ys+Ww0CQQDjeOoX89d/xhRqGXKjCx8ImE/dPmsI8O27cwtKrDYJ\n" +
+ "6t0v/xryVIdvOYcRBvKnqEogOH7T1kI+LnWKUTJ2ehJ7AkEA2FVloPVqCehXcc7e\n" +
+ "z3TDpU9w1B0JXklcV5HddYsRqp9RukN/VK4szKE7F1yoarIUtfE9Lr9082Jwyp3M\n" +
+ "L11xwwJBAKsZ+Hur3x0tUY29No2Nf/pnFyvEF57SGwA0uPmiL8Ol9lpz+UDudDEl\n" +
+ "hIM6Rqv12kwCMuQE9i7vo1o3WU3k5KECQEqhg1L49yD935TqiiFFpe0Ur9btQXse\n" +
+ "kdXAA4d2d5zGI7q/aGD9SYU6phkUJSHR16VA2RuUfzMrpb+wmm1IrmMCQFtLoKRT\n" +
+ "A5kokFb+E3Gplu29tJvCUpfwgBFRS+wmkvtiaU/tiyDcVgDO+An5DwedxxdVzqiE\n" +
+ "njWHoKY3axDQ8OU=\n";
+
+
+ static char passphrase[] = "passphrase".toCharArray();
+
+ /*
+ * Is the server ready to serve?
+ */
+ volatile static boolean serverReady = false;
+
+ /*
+ * Turn on SSL debugging?
+ */
+ static boolean debug = false;
+
+ /*
+ * Define the server side of the test.
+ *
+ * If the server prematurely exits, serverReady will be set to true
+ * to avoid infinite hangs.
+ */
+ void doServerSide() throws Exception {
+ SSLContext context = generateSSLContext();
+ SSLServerSocketFactory sslssf = context.getServerSocketFactory();
+ SSLServerSocket sslServerSocket =
+ (SSLServerSocket)sslssf.createServerSocket(serverPort);
+ sslServerSocket.setNeedClientAuth(true);
+ serverPort = sslServerSocket.getLocalPort();
+
+ /*
+ * Signal Client, we're ready for his connect.
+ */
+ serverReady = true;
+
+ SSLSocket sslSocket = (SSLSocket)sslServerSocket.accept();
+ InputStream sslIS = sslSocket.getInputStream();
+ OutputStream sslOS = sslSocket.getOutputStream();
+
+ sslIS.read();
+ sslOS.write('A');
+ sslOS.flush();
+
+ sslSocket.close();
+ }
+
+ /*
+ * Define the client side of the test.
+ *
+ * If the server prematurely exits, serverReady will be set to true
+ * to avoid infinite hangs.
+ */
+ void doClientSide() throws Exception {
+
+ /*
+ * Wait for server to get started.
+ */
+ while (!serverReady) {
+ Thread.sleep(50);
+ }
+
+ SSLContext context = generateSSLContext();
+ SSLSocketFactory sslsf = context.getSocketFactory();
+
+ SSLSocket sslSocket =
+ (SSLSocket)sslsf.createSocket("localhost", serverPort);
+
+ // enable the specified TLS protocol
+ sslSocket.setEnabledProtocols(new String[] {tlsProtocol});
+
+ InputStream sslIS = sslSocket.getInputStream();
+ OutputStream sslOS = sslSocket.getOutputStream();
+
+ sslOS.write('B');
+ sslOS.flush();
+ sslIS.read();
+
+ sslSocket.close();
+ }
+
+ /*
+ * =============================================================
+ * The remainder is just support stuff
+ */
+ private static String tmAlgorithm; // trust manager
+ private static String tlsProtocol; // trust manager
+
+ private static void parseArguments(String[] args) {
+ tmAlgorithm = args[0];
+ tlsProtocol = args[1];
+ }
+
+ private static SSLContext generateSSLContext() throws Exception {
+
+ // generate certificate from cert string
+ CertificateFactory cf = CertificateFactory.getInstance("X.509");
+
+ // create a key store
+ KeyStore ks = KeyStore.getInstance("JKS");
+ ks.load(null, null);
+
+ // import the trused cert
+ X509Certificate trusedCert = null;
+ ByteArrayInputStream is =
+ new ByteArrayInputStream(trustedCertStr.getBytes());
+ trusedCert = (X509Certificate)cf.generateCertificate(is);
+ is.close();
+
+ ks.setCertificateEntry("Trusted RSA Signer", trusedCert);
+
+ // generate the private key.
+ PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec(
+ new BASE64Decoder().decodeBuffer(targetPrivateKey));
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPrivateKey priKey =
+ (RSAPrivateKey)kf.generatePrivate(priKeySpec);
+
+ // generate certificate chain
+ is = new ByteArrayInputStream(targetCertStr.getBytes());
+ X509Certificate keyCert = (X509Certificate)cf.generateCertificate(is);
+ is.close();
+
+ X509Certificate[] chain = new X509Certificate[2];
+ chain[0] = keyCert;
+ chain[1] = trusedCert;
+
+ // import the key entry and the chain
+ ks.setKeyEntry("TheKey", priKey, passphrase, chain);
+
+ // create SSL context
+ TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmAlgorithm);
+ tmf.init(ks);
+
+ // create the customized KM and TM
+ NoneExtendedX509TM myTM =
+ new NoneExtendedX509TM(tmf.getTrustManagers()[0]);
+ NoneExtendedX509KM myKM =
+ new NoneExtendedX509KM("TheKey", chain, priKey);
+
+ SSLContext ctx = SSLContext.getInstance(tlsProtocol);
+ // KeyManagerFactory kmf = KeyManagerFactory.getInstance("NewSunX509");
+ // kmf.init(ks, passphrase);
+ // ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+ ctx.init(new KeyManager[]{myKM}, new TrustManager[]{myTM}, null);
+ ks = null;
+
+ return ctx;
+ }
+
+ static class NoneExtendedX509TM implements X509TrustManager {
+ X509TrustManager tm;
+
+ NoneExtendedX509TM(TrustManager tm) {
+ this.tm = (X509TrustManager)tm;
+ }
+
+ public void checkClientTrusted(X509Certificate chain[], String authType)
+ throws CertificateException {
+ tm.checkClientTrusted(chain, authType);
+ }
+
+ public void checkServerTrusted(X509Certificate chain[], String authType)
+ throws CertificateException {
+ tm.checkServerTrusted(chain, authType);
+ }
+
+ public X509Certificate[] getAcceptedIssuers() {
+ return tm.getAcceptedIssuers();
+ }
+ }
+
+ static class NoneExtendedX509KM implements X509KeyManager {
+ private String keyAlias;
+ private X509Certificate[] chain;
+ private PrivateKey privateKey;
+
+ NoneExtendedX509KM(String keyAlias, X509Certificate[] chain,
+ PrivateKey privateKey) {
+ this.keyAlias = keyAlias;
+ this.chain = chain;
+ this.privateKey = privateKey;
+ }
+
+ public String[] getClientAliases(String keyType, Principal[] issuers) {
+ return new String[] {keyAlias};
+ }
+
+ public String chooseClientAlias(String[] keyType, Principal[] issuers,
+ Socket socket) {
+ return keyAlias;
+ }
+
+ public String[] getServerAliases(String keyType, Principal[] issuers) {
+ return new String[] {keyAlias};
+ }
+
+ public String chooseServerAlias(String keyType, Principal[] issuers,
+ Socket socket) {
+ return keyAlias;
+ }
+
+ public X509Certificate[] getCertificateChain(String alias) {
+ return chain;
+ }
+
+ public PrivateKey getPrivateKey(String alias) {
+ return privateKey;
+ }
+ }
+
+
+ // use any free port by default
+ volatile int serverPort = 0;
+
+ volatile Exception serverException = null;
+ volatile Exception clientException = null;
+
+ public static void main(String[] args) throws Exception {
+ if (debug)
+ System.setProperty("javax.net.debug", "all");
+
+ /*
+ * Get the customized arguments.
+ */
+ parseArguments(args);
+
+ /*
+ * Start the tests.
+ */
+ new TrustTrustedCert();
+ }
+
+ Thread clientThread = null;
+ Thread serverThread = null;
+
+ /*
+ * Primary constructor, used to drive remainder of the test.
+ *
+ * Fork off the other side, then do your work.
+ */
+ TrustTrustedCert() throws Exception {
+ try {
+ if (separateServerThread) {
+ startServer(true);
+ startClient(false);
+ } else {
+ startClient(true);
+ startServer(false);
+ }
+ } catch (Exception e) {
+ // swallow for now. Show later
+ }
+
+ /*
+ * Wait for other side to close down.
+ */
+ if (separateServerThread) {
+ serverThread.join();
+ } else {
+ clientThread.join();
+ }
+
+ /*
+ * When we get here, the test is pretty much over.
+ * Which side threw the error?
+ */
+ Exception local;
+ Exception remote;
+ String whichRemote;
+
+ if (separateServerThread) {
+ remote = serverException;
+ local = clientException;
+ whichRemote = "server";
+ } else {
+ remote = clientException;
+ local = serverException;
+ whichRemote = "client";
+ }
+
+ /*
+ * If both failed, return the curthread's exception, but also
+ * print the remote side Exception
+ */
+ if ((local != null) && (remote != null)) {
+ System.out.println(whichRemote + " also threw:");
+ remote.printStackTrace();
+ System.out.println();
+ throw local;
+ }
+
+ if (remote != null) {
+ throw remote;
+ }
+
+ if (local != null) {
+ throw local;
+ }
+ }
+
+ void startServer(boolean newThread) throws Exception {
+ if (newThread) {
+ serverThread = new Thread() {
+ public void run() {
+ try {
+ doServerSide();
+ } catch (Exception e) {
+ /*
+ * Our server thread just died.
+ *
+ * Release the client, if not active already...
+ */
+ System.err.println("Server died...");
+ serverReady = true;
+ serverException = e;
+ }
+ }
+ };
+ serverThread.start();
+ } else {
+ try {
+ doServerSide();
+ } catch (Exception e) {
+ serverException = e;
+ } finally {
+ serverReady = true;
+ }
+ }
+ }
+
+ void startClient(boolean newThread) throws Exception {
+ if (newThread) {
+ clientThread = new Thread() {
+ public void run() {
+ try {
+ doClientSide();
+ } catch (Exception e) {
+ /*
+ * Our client thread just died.
+ */
+ System.err.println("Client died...");
+ clientException = e;
+ }
+ }
+ };
+ clientThread.start();
+ } else {
+ try {
+ doClientSide();
+ } catch (Exception e) {
+ clientException = e;
+ }
+ }
+ }
+}