# HG changeset patch # User lana # Date 1322077038 28800 # Node ID bba8493895c2efdfcf94584ac8094684bfc4c235 # Parent 08b7daf5191e90ddecff0e479c081148fc89438f# Parent 4ee27839f531368853beb8cb8c4bc2aa16fb9535 Merge diff -r 08b7daf5191e -r bba8493895c2 jdk/make/docs/Makefile --- a/jdk/make/docs/Makefile Fri Nov 18 16:16:15 2011 -0800 +++ b/jdk/make/docs/Makefile Wed Nov 23 11:37:18 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 diff -r 08b7daf5191e -r bba8493895c2 jdk/src/share/classes/java/io/FileInputStream.java --- a/jdk/src/share/classes/java/io/FileInputStream.java Fri Nov 18 16:16:15 2011 -0800 +++ b/jdk/src/share/classes/java/io/FileInputStream.java Wed Nov 23 11:37:18 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(); } } } diff -r 08b7daf5191e -r bba8493895c2 jdk/src/share/classes/java/io/FileOutputStream.java --- a/jdk/src/share/classes/java/io/FileOutputStream.java Fri Nov 18 16:16:15 2011 -0800 +++ b/jdk/src/share/classes/java/io/FileOutputStream.java Wed Nov 23 11:37:18 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(); } } } diff -r 08b7daf5191e -r bba8493895c2 jdk/src/share/classes/java/io/RandomAccessFile.java --- a/jdk/src/share/classes/java/io/RandomAccessFile.java Fri Nov 18 16:16:15 2011 -0800 +++ b/jdk/src/share/classes/java/io/RandomAccessFile.java Wed Nov 23 11:37:18 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(); + } + }); } // diff -r 08b7daf5191e -r bba8493895c2 jdk/src/share/classes/java/io/Writer.java --- a/jdk/src/share/classes/java/io/Writer.java Fri Nov 18 16:16:15 2011 -0800 +++ b/jdk/src/share/classes/java/io/Writer.java Wed Nov 23 11:37:18 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. diff -r 08b7daf5191e -r bba8493895c2 jdk/src/share/classes/java/lang/AssertionError.java --- a/jdk/src/share/classes/java/lang/AssertionError.java Fri Nov 18 16:16:15 2011 -0800 +++ b/jdk/src/share/classes/java/lang/AssertionError.java Wed Nov 23 11:37:18 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)); } /** diff -r 08b7daf5191e -r bba8493895c2 jdk/src/share/classes/java/lang/Class.java --- a/jdk/src/share/classes/java/lang/Class.java Fri Nov 18 16:16:15 2011 -0800 +++ b/jdk/src/share/classes/java/lang/Class.java Wed Nov 23 11:37:18 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. * diff -r 08b7daf5191e -r bba8493895c2 jdk/src/share/classes/java/lang/Double.java --- a/jdk/src/share/classes/java/lang/Double.java Fri Nov 18 16:16:15 2011 -0800 +++ b/jdk/src/share/classes/java/lang/Double.java Wed Nov 23 11:37:18 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); } /** diff -r 08b7daf5191e -r bba8493895c2 jdk/src/share/classes/java/lang/Float.java --- a/jdk/src/share/classes/java/lang/Float.java Fri Nov 18 16:16:15 2011 -0800 +++ b/jdk/src/share/classes/java/lang/Float.java Wed Nov 23 11:37:18 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); } /** diff -r 08b7daf5191e -r bba8493895c2 jdk/src/share/classes/java/security/Policy.java --- a/jdk/src/share/classes/java/security/Policy.java Fri Nov 18 16:16:15 2011 -0800 +++ b/jdk/src/share/classes/java/security/Policy.java Wed Nov 23 11:37:18 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". * *

Once a Policy instance has been installed (either by default, or by - * calling setPolicy), - * the Java runtime invokes its implies when it needs to + * calling setPolicy), the Java runtime invokes its + * implies 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 policy = + new AtomicReference<>(new PolicyInfo(null, false)); private static final Debug debug = Debug.getInstance("policy"); // Cache mapping ProtectionDomain.Key to PermissionCollection private WeakHashMap 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() { - 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() { - 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() { + 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() { + 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(); + 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) { diff -r 08b7daf5191e -r bba8493895c2 jdk/src/share/classes/java/sql/PreparedStatement.java --- a/jdk/src/share/classes/java/sql/PreparedStatement.java Fri Nov 18 16:16:15 2011 -0800 +++ b/jdk/src/share/classes/java/sql/PreparedStatement.java Wed Nov 23 11:37:18 2011 -0800 @@ -767,7 +767,7 @@ /** - * Sets the designated paramter to the given String object. + * Sets the designated parameter to the given String object. * The driver converts this to a SQL NCHAR or * NVARCHAR or LONGNVARCHAR value * (depending on the argument's diff -r 08b7daf5191e -r bba8493895c2 jdk/src/share/classes/java/sql/Statement.java --- a/jdk/src/share/classes/java/sql/Statement.java Fri Nov 18 16:16:15 2011 -0800 +++ b/jdk/src/share/classes/java/sql/Statement.java Wed Nov 23 11:37:18 2011 -0800 @@ -991,7 +991,7 @@ /** * Requests that a Statement 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. *

* The poolable value of a statement is applicable to both internal diff -r 08b7daf5191e -r bba8493895c2 jdk/src/share/classes/java/util/concurrent/LinkedBlockingDeque.java --- a/jdk/src/share/classes/java/util/concurrent/LinkedBlockingDeque.java Fri Nov 18 16:16:15 2011 -0800 +++ b/jdk/src/share/classes/java/util/concurrent/LinkedBlockingDeque.java Wed Nov 23 11:37:18 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 { diff -r 08b7daf5191e -r bba8493895c2 jdk/src/share/classes/java/util/concurrent/LinkedBlockingQueue.java --- a/jdk/src/share/classes/java/util/concurrent/LinkedBlockingQueue.java Fri Nov 18 16:16:15 2011 -0800 +++ b/jdk/src/share/classes/java/util/concurrent/LinkedBlockingQueue.java Wed Nov 23 11:37:18 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 node = new Node(e); + Node node = new Node(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 node = new Node(e); + Node node = new Node(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(); diff -r 08b7daf5191e -r bba8493895c2 jdk/src/share/classes/java/util/jar/Attributes.java --- a/jdk/src/share/classes/java/util/jar/Attributes.java Fri Nov 18 16:16:15 2011 -0800 +++ b/jdk/src/share/classes/java/util/jar/Attributes.java Wed Nov 23 11:37:18 2011 -0800 @@ -629,7 +629,7 @@ public static final Name IMPLEMENTATION_VENDOR_ID = new Name("Implementation-Vendor-Id"); /** - * Name object for Implementation-Vendor-URL + * Name object for Implementation-URL * manifest attribute used for package versioning. * @see * Java Product Versioning Specification diff -r 08b7daf5191e -r bba8493895c2 jdk/src/share/classes/sun/net/httpserver/ServerImpl.java --- a/jdk/src/share/classes/sun/net/httpserver/ServerImpl.java Fri Nov 18 16:16:15 2011 -0800 +++ b/jdk/src/share/classes/sun/net/httpserver/ServerImpl.java Wed Nov 23 11:37:18 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) { diff -r 08b7daf5191e -r bba8493895c2 jdk/src/share/classes/sun/rmi/registry/RegistryImpl.java --- a/jdk/src/share/classes/sun/rmi/registry/RegistryImpl.java Fri Nov 18 16:16:15 2011 -0800 +++ b/jdk/src/share/classes/sun/rmi/registry/RegistryImpl.java Wed Nov 23 11:37:18 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() { @@ -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("<>", "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 }); } } diff -r 08b7daf5191e -r bba8493895c2 jdk/src/share/classes/sun/rmi/server/LoaderHandler.java --- a/jdk/src/share/classes/sun/rmi/server/LoaderHandler.java Fri Nov 18 16:16:15 2011 -0800 +++ b/jdk/src/share/classes/sun/rmi/server/LoaderHandler.java Wed Nov 23 11:37:18 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) { diff -r 08b7daf5191e -r bba8493895c2 jdk/src/share/classes/sun/security/krb5/internal/KerberosTime.java --- a/jdk/src/share/classes/sun/security/krb5/internal/KerberosTime.java Fri Nov 18 16:16:15 2011 -0800 +++ b/jdk/src/share/classes/sun/security/krb5/internal/KerberosTime.java Wed Nov 23 11:37:18 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() { diff -r 08b7daf5191e -r bba8493895c2 jdk/src/share/classes/sun/security/krb5/internal/ccache/CCacheInputStream.java --- a/jdk/src/share/classes/sun/security/krb5/internal/ccache/CCacheInputStream.java Fri Nov 18 16:16:15 2011 -0800 +++ b/jdk/src/share/classes/sun/security/krb5/internal/ccache/CCacheInputStream.java Wed Nov 23 11:37:18 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(); diff -r 08b7daf5191e -r bba8493895c2 jdk/src/share/classes/sun/security/krb5/internal/ccache/Credentials.java --- a/jdk/src/share/classes/sun/security/krb5/internal/ccache/Credentials.java Fri Nov 18 16:16:15 2011 -0800 +++ b/jdk/src/share/classes/sun/security/krb5/internal/ccache/Credentials.java Wed Nov 23 11:37:18 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(); + } } diff -r 08b7daf5191e -r bba8493895c2 jdk/src/share/classes/sun/security/ssl/SSLContextImpl.java --- a/jdk/src/share/classes/sun/security/ssl/SSLContextImpl.java Fri Nov 18 16:16:15 2011 -0800 +++ b/jdk/src/share/classes/sun/security/ssl/SSLContextImpl.java Wed Nov 23 11:37:18 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 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.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.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"); } } } diff -r 08b7daf5191e -r bba8493895c2 jdk/src/share/classes/sun/security/ssl/SSLSocketImpl.java --- a/jdk/src/share/classes/sun/security/ssl/SSLSocketImpl.java Fri Nov 18 16:16:15 2011 -0800 +++ b/jdk/src/share/classes/sun/security/ssl/SSLSocketImpl.java Wed Nov 23 11:37:18 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(); diff -r 08b7daf5191e -r bba8493895c2 jdk/src/share/classes/sun/security/tools/CertAndKeyGen.java --- a/jdk/src/share/classes/sun/security/tools/CertAndKeyGen.java Fri Nov 18 16:16:15 2011 -0800 +++ b/jdk/src/share/classes/sun/security/tools/CertAndKeyGen.java Wed Nov 23 11:37:18 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); diff -r 08b7daf5191e -r bba8493895c2 jdk/src/share/classes/sun/security/tools/KeyTool.java --- a/jdk/src/share/classes/sun/security/tools/KeyTool.java Fri Nov 18 16:16:15 2011 -0800 +++ b/jdk/src/share/classes/sun/security/tools/KeyTool.java Wed Nov 23 11:37:18 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); } /** diff -r 08b7daf5191e -r bba8493895c2 jdk/src/solaris/classes/java/io/FileDescriptor.java --- a/jdk/src/solaris/classes/java/io/FileDescriptor.java Fri Nov 18 16:16:15 2011 -0800 +++ b/jdk/src/solaris/classes/java/io/FileDescriptor.java Wed Nov 23 11:37:18 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 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; + } + } } } diff -r 08b7daf5191e -r bba8493895c2 jdk/src/solaris/native/java/net/Inet4AddressImpl.c --- a/jdk/src/solaris/native/java/net/Inet4AddressImpl.c Fri Nov 18 16:16:15 2011 -0800 +++ b/jdk/src/solaris/native/java/net/Inet4AddressImpl.c Wed Nov 23 11:37:18 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; } diff -r 08b7daf5191e -r bba8493895c2 jdk/src/solaris/native/java/net/Inet6AddressImpl.c --- a/jdk/src/solaris/native/java/net/Inet6AddressImpl.c Fri Nov 18 16:16:15 2011 -0800 +++ b/jdk/src/solaris/native/java/net/Inet6AddressImpl.c Wed Nov 23 11:37:18 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 */ diff -r 08b7daf5191e -r bba8493895c2 jdk/src/solaris/native/java/net/net_util_md.c --- a/jdk/src/solaris/native/java/net/net_util_md.c Fri Nov 18 16:16:15 2011 -0800 +++ b/jdk/src/solaris/native/java/net/net_util_md.c Wed Nov 23 11:37:18 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. diff -r 08b7daf5191e -r bba8493895c2 jdk/src/solaris/native/java/net/net_util_md.h --- a/jdk/src/solaris/native/java/net/net_util_md.h Fri Nov 18 16:16:15 2011 -0800 +++ b/jdk/src/solaris/native/java/net/net_util_md.h Wed Nov 23 11:37:18 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 diff -r 08b7daf5191e -r bba8493895c2 jdk/src/windows/classes/java/io/FileDescriptor.java --- a/jdk/src/windows/classes/java/io/FileDescriptor.java Fri Nov 18 16:16:15 2011 -0800 +++ b/jdk/src/windows/classes/java/io/FileDescriptor.java Wed Nov 23 11:37:18 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 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; + } + } } } diff -r 08b7daf5191e -r bba8493895c2 jdk/src/windows/classes/java/net/PlainSocketImpl.java --- a/jdk/src/windows/classes/java/net/PlainSocketImpl.java Fri Nov 18 16:16:15 2011 -0800 +++ b/jdk/src/windows/classes/java/net/PlainSocketImpl.java Wed Nov 23 11:37:18 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 { diff -r 08b7daf5191e -r bba8493895c2 jdk/src/windows/classes/sun/security/krb5/internal/tools/Klist.java --- a/jdk/src/windows/classes/sun/security/krb5/internal/tools/Klist.java Fri Nov 18 16:16:15 2011 -0800 +++ b/jdk/src/windows/classes/sun/security/krb5/internal/tools/Klist.java Wed Nov 23 11:37:18 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 " + diff -r 08b7daf5191e -r bba8493895c2 jdk/src/windows/lib/tzmappings --- a/jdk/src/windows/lib/tzmappings Fri Nov 18 16:16:15 2011 -0800 +++ b/jdk/src/windows/lib/tzmappings Wed Nov 23 11:37:18 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: diff -r 08b7daf5191e -r bba8493895c2 jdk/test/java/io/FileDescriptor/FileChannelFDTest.java --- a/jdk/test/java/io/FileDescriptor/FileChannelFDTest.java Fri Nov 18 16:16:15 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(); - } -} diff -r 08b7daf5191e -r bba8493895c2 jdk/test/java/io/FileDescriptor/Sharing.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/io/FileDescriptor/Sharing.java Wed Nov 23 11:37:18 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= 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 5) + /* do not wait forever - allow 120 seconds same as jtreg default timeout. */ + if (count++ > 60) throw new AssertionError("GoodThread is still alive!"); } diff -r 08b7daf5191e -r bba8493895c2 jdk/test/java/lang/ThreadGroup/Stop.java --- a/jdk/test/java/lang/ThreadGroup/Stop.java Fri Nov 18 16:16:15 2011 -0800 +++ b/jdk/test/java/lang/ThreadGroup/Stop.java Wed Nov 23 11:37:18 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."); } diff -r 08b7daf5191e -r bba8493895c2 jdk/test/java/lang/management/PlatformLoggingMXBean/LoggingMXBeanTest.java --- a/jdk/test/java/lang/management/PlatformLoggingMXBean/LoggingMXBeanTest.java Fri Nov 18 16:16:15 2011 -0800 +++ b/jdk/test/java/lang/management/PlatformLoggingMXBean/LoggingMXBeanTest.java Wed Nov 23 11:37:18 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 loggers1 = mxbean1.getLoggerNames(); List loggers2 = mxbean2.getLoggerNames(); + if (loggers1.size() != loggers2.size()) throw new RuntimeException("LoggerNames: unmatched number of entries"); List 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( diff -r 08b7daf5191e -r bba8493895c2 jdk/test/java/lang/management/PlatformLoggingMXBean/PlatformLoggingMXBeanTest.java --- a/jdk/test/java/lang/management/PlatformLoggingMXBean/PlatformLoggingMXBeanTest.java Fri Nov 18 16:16:15 2011 -0800 +++ b/jdk/test/java/lang/management/PlatformLoggingMXBean/PlatformLoggingMXBeanTest.java Wed Nov 23 11:37:18 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]; diff -r 08b7daf5191e -r bba8493895c2 jdk/test/java/rmi/registry/readTest/readTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/rmi/registry/readTest/readTest.java Wed Nov 23 11:37:18 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(); + } + + } +} diff -r 08b7daf5191e -r bba8493895c2 jdk/test/java/rmi/registry/readTest/readTest.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/rmi/registry/readTest/readTest.sh Wed Nov 23 11:37:18 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} + + diff -r 08b7daf5191e -r bba8493895c2 jdk/test/java/rmi/registry/readTest/testPkg/Client.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/rmi/registry/readTest/testPkg/Client.java Wed Nov 23 11:37:18 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; + } + } + } + diff -r 08b7daf5191e -r bba8493895c2 jdk/test/java/rmi/registry/readTest/testPkg/Hello.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/rmi/registry/readTest/testPkg/Hello.java Wed Nov 23 11:37:18 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; +} diff -r 08b7daf5191e -r bba8493895c2 jdk/test/java/rmi/registry/readTest/testPkg/Server.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/rmi/registry/readTest/testPkg/Server.java Wed Nov 23 11:37:18 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; + } + +} diff -r 08b7daf5191e -r bba8493895c2 jdk/test/java/util/Timer/Args.java --- a/jdk/test/java/util/Timer/Args.java Fri Nov 18 16:16:15 2011 -0800 +++ b/jdk/test/java/util/Timer/Args.java Wed Nov 23 11:37:18 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(); diff -r 08b7daf5191e -r bba8493895c2 jdk/test/java/util/Timer/KillThread.java --- a/jdk/test/java/util/Timer/KillThread.java Fri Nov 18 16:16:15 2011 -0800 +++ b/jdk/test/java/util/Timer/KillThread.java Wed Nov 23 11:37:18 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 { diff -r 08b7daf5191e -r bba8493895c2 jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLContextImpl/MD2InTrustAnchor.java --- /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 Wed Nov 23 11:37:18 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; + } + } + } +} diff -r 08b7daf5191e -r bba8493895c2 jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLContextImpl/TrustTrustedCert.java --- /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 Wed Nov 23 11:37:18 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; + } + } + } +}