diff --git a/make/docs/Makefile b/make/docs/Makefile index 8517654153da8192cebf9ff9303e0641c592cbe5..61756eab7e99eb067c73ebe035a8c5c6116877ea 100644 --- a/make/docs/Makefile +++ b/make/docs/Makefile @@ -71,7 +71,7 @@ include $(BUILDDIR)/common/internal/ImportComponents.gmk 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 --git a/src/share/classes/java/io/FileInputStream.java b/src/share/classes/java/io/FileInputStream.java index 9dc19557e546c2694a5d41f3c788ad23a54fb4ce..d796bf090f04d7411aca056fcfa8ccc858983cac 100644 --- a/src/share/classes/java/io/FileInputStream.java +++ b/src/share/classes/java/io/FileInputStream.java @@ -124,7 +124,7 @@ class FileInputStream extends InputStream throw new NullPointerException(); } fd = new FileDescriptor(); - fd.incrementAndGetUseCount(); + fd.attach(this); open(name); } @@ -164,10 +164,9 @@ class FileInputStream extends InputStream /* * 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 @@ class FileInputStream extends InputStream 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 @@ class FileInputStream extends InputStream * @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 @@ class FileInputStream extends InputStream 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 @@ class FileInputStream extends InputStream */ 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 --git a/src/share/classes/java/io/FileOutputStream.java b/src/share/classes/java/io/FileOutputStream.java index 4a8a724ba15e658e80cb5b2e435cd29a70f400f0..50bd29bef5f46911f4566c1506c2849047716553 100644 --- a/src/share/classes/java/io/FileOutputStream.java +++ b/src/share/classes/java/io/FileOutputStream.java @@ -197,9 +197,9 @@ class FileOutputStream extends OutputStream throw new NullPointerException(); } this.fd = new FileDescriptor(); + fd.attach(this); this.append = append; - fd.incrementAndGetUseCount(); open(name, append); } @@ -237,12 +237,7 @@ class FileOutputStream extends OutputStream 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 @@ class FileOutputStream extends OutputStream } 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 @@ class FileOutputStream extends OutputStream * @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 @@ class FileOutputStream extends OutputStream 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 @@ class FileOutputStream extends OutputStream 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 --git a/src/share/classes/java/io/RandomAccessFile.java b/src/share/classes/java/io/RandomAccessFile.java index a2863c59a088a6d179c772fb110fceb0d6a4a618..65bfbf46c795545fa0c00a381f19d73b861b5ea1 100644 --- a/src/share/classes/java/io/RandomAccessFile.java +++ b/src/share/classes/java/io/RandomAccessFile.java @@ -229,7 +229,7 @@ public class RandomAccessFile implements DataOutput, DataInput, Closeable { throw new NullPointerException(); } fd = new FileDescriptor(); - fd.incrementAndGetUseCount(); + fd.attach(this); open(name, imode); } @@ -242,7 +242,9 @@ public class RandomAccessFile implements DataOutput, DataInput, Closeable { * @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 @@ public class RandomAccessFile implements DataOutput, DataInput, Closeable { 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 @@ public class RandomAccessFile implements DataOutput, DataInput, Closeable { 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 --git a/src/share/classes/java/io/Writer.java b/src/share/classes/java/io/Writer.java index f0c6db46319f318de0e59cf18453a81ce13c9a8c..fcab562d76b5f4ad73b14e5b30bbfef11e4ed3af 100644 --- a/src/share/classes/java/io/Writer.java +++ b/src/share/classes/java/io/Writer.java @@ -57,7 +57,7 @@ public abstract class Writer implements Appendable, Closeable, Flushable { /** * 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 abstract class Writer implements Appendable, Closeable, Flushable { 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 abstract class Writer implements Appendable, Closeable, Flushable { 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 --git a/src/share/classes/java/lang/AssertionError.java b/src/share/classes/java/lang/AssertionError.java index 984c3e4f00bdf39faf5c6df99571851e2b30757f..926f71141cd3855df87298a4231c6bc08f218bfb 100644 --- a/src/share/classes/java/lang/AssertionError.java +++ b/src/share/classes/java/lang/AssertionError.java @@ -71,7 +71,7 @@ public class AssertionError extends Error { * @see Throwable#getCause() */ public AssertionError(Object detailMessage) { - this("" + detailMessage); + this(String.valueOf(detailMessage)); if (detailMessage instanceof Throwable) initCause((Throwable) detailMessage); } @@ -85,7 +85,7 @@ public class AssertionError extends Error { * @param detailMessage value to be used in constructing detail message */ public AssertionError(boolean detailMessage) { - this("" + detailMessage); + this(String.valueOf(detailMessage)); } /** @@ -97,7 +97,7 @@ public class AssertionError extends Error { * @param detailMessage value to be used in constructing detail message */ public AssertionError(char detailMessage) { - this("" + detailMessage); + this(String.valueOf(detailMessage)); } /** @@ -109,7 +109,7 @@ public class AssertionError extends Error { * @param detailMessage value to be used in constructing detail message */ public AssertionError(int detailMessage) { - this("" + detailMessage); + this(String.valueOf(detailMessage)); } /** @@ -121,7 +121,7 @@ public class AssertionError extends Error { * @param detailMessage value to be used in constructing detail message */ public AssertionError(long detailMessage) { - this("" + detailMessage); + this(String.valueOf(detailMessage)); } /** @@ -133,7 +133,7 @@ public class AssertionError extends Error { * @param detailMessage value to be used in constructing detail message */ public AssertionError(float detailMessage) { - this("" + detailMessage); + this(String.valueOf(detailMessage)); } /** @@ -145,7 +145,7 @@ public class AssertionError extends Error { * @param detailMessage value to be used in constructing detail message */ public AssertionError(double detailMessage) { - this("" + detailMessage); + this(String.valueOf(detailMessage)); } /** diff --git a/src/share/classes/java/lang/Class.java b/src/share/classes/java/lang/Class.java index 01e21b9a03078e66b57d4e72808a5e5f369f5b2d..ca7f1be7927ae4710e38c4bf77240501bfc0cff7 100644 --- a/src/share/classes/java/lang/Class.java +++ b/src/share/classes/java/lang/Class.java @@ -3008,7 +3008,7 @@ public final /** * 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 --git a/src/share/classes/java/lang/Double.java b/src/share/classes/java/lang/Double.java index 7d426180c5db9ece6e9412b5d0d16213573f3a75..70e6a7c60f321834e3adedfc572907bd3fbb3d21 100644 --- a/src/share/classes/java/lang/Double.java +++ b/src/share/classes/java/lang/Double.java @@ -607,8 +607,7 @@ public final class Double extends Number implements Comparable { * @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 --git a/src/share/classes/java/lang/Float.java b/src/share/classes/java/lang/Float.java index 6aa381ccebdfd2750e38a8cd51bf92237b4b2908..bd32e366a3d9f1df3c5212d95dc5a1bba615ee5a 100644 --- a/src/share/classes/java/lang/Float.java +++ b/src/share/classes/java/lang/Float.java @@ -529,8 +529,7 @@ public final class Float extends Number implements Comparable { * @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 --git a/src/share/classes/java/security/Policy.java b/src/share/classes/java/security/Policy.java index 7ed0ce235401e54649bca6de0cd18970a5aa4b08..b402c766f914885701821a918c9ed69eef5091d0 100644 --- a/src/share/classes/java/security/Policy.java +++ b/src/share/classes/java/security/Policy.java @@ -28,6 +28,7 @@ package java.security; 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 @@ import sun.security.util.SecurityConstants; * 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 abstract class Policy { 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 @@ public abstract class Policy { /** * 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"); + 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 (policy_class == null) { + policy_class = "sun.security.provider.PolicyFile"; } - }); - 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(); + 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; } - 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); } - }); - /* - * 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"); } + policy.set(pinfo); } + return pinfo.policy; } } - return policy; + return pi.policy; } /** @@ -245,7 +273,7 @@ public abstract class Policy { initPolicy(p); } synchronized (Policy.class) { - Policy.policy = p; + policy.set(new PolicyInfo(p, p != null)); } } @@ -292,14 +320,14 @@ public abstract class Policy { 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 @@ public abstract class Policy { type, params); } catch (NoSuchAlgorithmException nsae) { - return handleException (nsae); + return handleException(nsae); } } @@ -494,7 +522,7 @@ public abstract class Policy { type, params); } catch (NoSuchAlgorithmException nsae) { - return handleException (nsae); + return handleException(nsae); } } @@ -808,7 +836,7 @@ public abstract class Policy { * * @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 --git a/src/share/classes/java/sql/PreparedStatement.java b/src/share/classes/java/sql/PreparedStatement.java index 1d32c3dd0b9a84d5b90464763055f5d7b95c1741..8d6ca60360cca60f77bae3cf91202d849f054cd0 100644 --- a/src/share/classes/java/sql/PreparedStatement.java +++ b/src/share/classes/java/sql/PreparedStatement.java @@ -767,7 +767,7 @@ public interface PreparedStatement extends Statement { /** - * 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 --git a/src/share/classes/java/sql/Statement.java b/src/share/classes/java/sql/Statement.java index da7285e5f3f3b6f1abc3891498ed920de581bbcd..0b467fb7e02421cc5c862d1c35764f2afb562207 100644 --- a/src/share/classes/java/sql/Statement.java +++ b/src/share/classes/java/sql/Statement.java @@ -991,7 +991,7 @@ public interface Statement extends Wrapper, AutoCloseable { /** * 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 --git a/src/share/classes/java/util/concurrent/LinkedBlockingDeque.java b/src/share/classes/java/util/concurrent/LinkedBlockingDeque.java index c1978c8e3313999284636ef17bcb323a133e5c3e..60a18d0dba32a683f3d6fb7f847e6adc37cb8502 100644 --- a/src/share/classes/java/util/concurrent/LinkedBlockingDeque.java +++ b/src/share/classes/java/util/concurrent/LinkedBlockingDeque.java @@ -742,6 +742,8 @@ public class LinkedBlockingDeque throw new NullPointerException(); if (c == this) throw new IllegalArgumentException(); + if (maxElements <= 0) + return 0; final ReentrantLock lock = this.lock; lock.lock(); try { diff --git a/src/share/classes/java/util/concurrent/LinkedBlockingQueue.java b/src/share/classes/java/util/concurrent/LinkedBlockingQueue.java index ae4d43594dd5b590f5263a458be3f8c427c76d82..d1a6d5a0b580be263beb1f269ea9206105fcbbbc 100644 --- a/src/share/classes/java/util/concurrent/LinkedBlockingQueue.java +++ b/src/share/classes/java/util/concurrent/LinkedBlockingQueue.java @@ -332,7 +332,7 @@ public class LinkedBlockingQueue extends AbstractQueue // 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 @@ public class LinkedBlockingQueue extends AbstractQueue 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 @@ public class LinkedBlockingQueue extends AbstractQueue 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 --git a/src/share/classes/java/util/jar/Attributes.java b/src/share/classes/java/util/jar/Attributes.java index 58856420035e1b997e47be5f3df172a42210a12a..e09071172b6bbf8c1dd03d8a6fd53dcebdf2575f 100644 --- a/src/share/classes/java/util/jar/Attributes.java +++ b/src/share/classes/java/util/jar/Attributes.java @@ -629,7 +629,7 @@ public class Attributes implements Map, Cloneable { 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 --git a/src/share/classes/sun/net/httpserver/ServerImpl.java b/src/share/classes/sun/net/httpserver/ServerImpl.java index cce9c136e8a65e7ad97fc1fd543927caa85af69c..69a9e6586ecfb37a4ace0664b2ee73cf034356bb 100644 --- a/src/share/classes/sun/net/httpserver/ServerImpl.java +++ b/src/share/classes/sun/net/httpserver/ServerImpl.java @@ -402,10 +402,10 @@ class ServerImpl implements TimeSource { } 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 --git a/src/share/classes/sun/rmi/registry/RegistryImpl.java b/src/share/classes/sun/rmi/registry/RegistryImpl.java index db18eb3364dab05f1920d98268198500816ac5fb..1257132ae16e18ac155998d40c8c797982d7244c 100644 --- a/src/share/classes/sun/rmi/registry/RegistryImpl.java +++ b/src/share/classes/sun/rmi/registry/RegistryImpl.java @@ -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.Enumeration; 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.server.UnicastServerRef2; 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 @@ public class RegistryImpl extends java.rmi.server.RemoteServer 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 class RegistryImpl extends java.rmi.server.RemoteServer public RegistryImpl run() throws RemoteException { return new RegistryImpl(regPort); } - }, getAccessControlContext(codebaseURLs)); + }, getAccessControlContext()); } catch (PrivilegedActionException ex) { throw (RemoteException) ex.getException(); } @@ -391,11 +378,11 @@ public class RegistryImpl extends java.rmi.server.RemoteServer } /** - * 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 @@ public class RegistryImpl extends java.rmi.server.RemoteServer 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 --git a/src/share/classes/sun/rmi/server/LoaderHandler.java b/src/share/classes/sun/rmi/server/LoaderHandler.java index 52d9ee55172e157c2a0aff87a4f2da0c1111e863..e7db8c869fc305a34a8144ed3e49c64dfe2d8511 100644 --- a/src/share/classes/sun/rmi/server/LoaderHandler.java +++ b/src/share/classes/sun/rmi/server/LoaderHandler.java @@ -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 @@ public final class LoaderHandler { * 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 --git a/src/share/classes/sun/security/krb5/internal/KerberosTime.java b/src/share/classes/sun/security/krb5/internal/KerberosTime.java index eae48e173ed6b295f07b32903341490719f19b97..1ad85ec50bdd7887bfa56f2d147f76740e935707 100644 --- a/src/share/classes/sun/security/krb5/internal/KerberosTime.java +++ b/src/share/classes/sun/security/krb5/internal/KerberosTime.java @@ -68,8 +68,8 @@ public class KerberosTime implements Cloneable { 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 class KerberosTime implements Cloneable { } 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 --git a/src/share/classes/sun/security/krb5/internal/ccache/CCacheInputStream.java b/src/share/classes/sun/security/krb5/internal/ccache/CCacheInputStream.java index 4f387b99f96c35d67388ea48a9090322e618c33e..ef7088f371b09419d885e285187fc6237d2daecc 100644 --- a/src/share/classes/sun/security/krb5/internal/ccache/CCacheInputStream.java +++ b/src/share/classes/sun/security/krb5/internal/ccache/CCacheInputStream.java @@ -375,7 +375,7 @@ public class CCacheInputStream extends KrbDataInputStream implements FileCCacheC } AuthorizationDataEntry[] auDataEntry = readAuth(); AuthorizationData auData = null; - if (auData != null) { + if (auDataEntry != null) { auData = new AuthorizationData(auDataEntry); } byte[] ticketData = readData(); diff --git a/src/share/classes/sun/security/krb5/internal/ccache/Credentials.java b/src/share/classes/sun/security/krb5/internal/ccache/Credentials.java index b02cc6de787f3606d2041bec435215f4afdd0ba2..e040788c68ec5fa47adbbcbd513eb09cb8e69ac7 100644 --- a/src/share/classes/sun/security/krb5/internal/ccache/Credentials.java +++ b/src/share/classes/sun/security/krb5/internal/ccache/Credentials.java @@ -209,10 +209,24 @@ public class Credentials { } 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 @@ public class Credentials { return endtime; } + public KerberosTime getRenewTill() { + return renewTill; + } + public TicketFlags getTicketFlags() { return flags; } @@ -228,4 +246,8 @@ public class Credentials { public int getEType() { return key.getEType(); } + + public int getTktEType() { + return ticket.encPart.getEType(); + } } diff --git a/src/share/classes/sun/security/ssl/SSLContextImpl.java b/src/share/classes/sun/security/ssl/SSLContextImpl.java index b80260407caa545e61d716fdd71e0615f8d70201..a5da2f759602123770f3e2bbc771e058ae92e8dd 100644 --- a/src/share/classes/sun/security/ssl/SSLContextImpl.java +++ b/src/share/classes/sun/security/ssl/SSLContextImpl.java @@ -771,10 +771,15 @@ public abstract class SSLContextImpl extends SSLContextSpi { 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 @@ final class AbstractTrustManagerWrapper extends X509ExtendedTrustManager 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 @@ final class AbstractTrustManagerWrapper extends X509ExtendedTrustManager constraints = new SSLAlgorithmConstraints(engine, true); } - AlgorithmChecker checker = new AlgorithmChecker(constraints); - try { - checker.init(false); + checkAlgorithmConstraints(chain, constraints); + } + } - // A forward checker, need to check from trust to target - for (int i = chain.length - 1; i >= 0; i--) { + 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); + 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 --git a/src/share/classes/sun/security/ssl/SSLSocketImpl.java b/src/share/classes/sun/security/ssl/SSLSocketImpl.java index 814f7d2933adbb0000e16aca5ae20573a76b8f6b..db11db8a195b654b750f6a50286f7718f857e4f1 100644 --- a/src/share/classes/sun/security/ssl/SSLSocketImpl.java +++ b/src/share/classes/sun/security/ssl/SSLSocketImpl.java @@ -1485,7 +1485,8 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl { 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 --git a/src/share/classes/sun/security/tools/CertAndKeyGen.java b/src/share/classes/sun/security/tools/CertAndKeyGen.java index 4c32a33b4f74b03c6d09a92c6c9ee7ab8422055f..fad412e9f9ac000e106334a0bf0f669e06371dea 100644 --- a/src/share/classes/sun/security/tools/CertAndKeyGen.java +++ b/src/share/classes/sun/security/tools/CertAndKeyGen.java @@ -33,18 +33,7 @@ import java.security.*; 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 @@ public final class CertAndKeyGen { 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 @@ public final class CertAndKeyGen { 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 @@ public final class CertAndKeyGen { return privateKey; } - /** * Returns a self-signed X.509v3 certificate for the public key. * The certificate is immediately valid. No extensions. @@ -224,6 +229,15 @@ public final class CertAndKeyGen { X500Name myname, Date firstDate, long validity) 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 @@ public final class CertAndKeyGen { 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 --git a/src/share/classes/sun/security/tools/KeyTool.java b/src/share/classes/sun/security/tools/KeyTool.java index 0d928209807406a1f4c81602ec61f9570d845c5f..3125f6f54c7a20a0ca01409222708e0cc7cb88ed 100644 --- a/src/share/classes/sun/security/tools/KeyTool.java +++ b/src/share/classes/sun/security/tools/KeyTool.java @@ -1518,9 +1518,16 @@ public final class KeyTool { 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 @@ public final class KeyTool { keyPass = promptForKeyPass(alias, null, storePass); } keyStore.setKeyEntry(alias, privKey, keyPass, chain); - - // resign so that -ext are applied. - doSelfCert(alias, null, sigAlgName); } /** diff --git a/src/share/native/sun/awt/medialib/mlib_types.h b/src/share/native/sun/awt/medialib/mlib_types.h index b917b7e9aeebb7a7b2ac909da6a14619dc1d27c4..b35375bda73fd20c7ce51dbadbf1de20b4a83608 100644 --- a/src/share/native/sun/awt/medialib/mlib_types.h +++ b/src/share/native/sun/awt/medialib/mlib_types.h @@ -59,13 +59,8 @@ typedef double mlib_d64; #if defined(__SUNPRO_C) || defined(__SUNPRO_CC) || defined(__GNUC__) -#if defined(__linux__) -#include /* for uintptr_t */ -#include /* for ptrdiff_t */ -#else -#include /* for uintptr_t */ -#include /* for ptrdiff_t */ -#endif /* __linux__ */ +#include +#include #ifdef MLIB_OS64BIT diff --git a/src/solaris/classes/java/io/FileDescriptor.java b/src/solaris/classes/java/io/FileDescriptor.java index 9e7390d8548ce126b5ed78a4833fd704ae40db19..1f0d086d7455aaec5ca2d3fc9ced6345915ed0c0 100644 --- a/src/solaris/classes/java/io/FileDescriptor.java +++ b/src/solaris/classes/java/io/FileDescriptor.java @@ -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 @@ public final class FileDescriptor { 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 final class FileDescriptor { */ public /**/ FileDescriptor() { fd = -1; - useCount = new AtomicInteger(); } private /* */ FileDescriptor(int fd) { this.fd = fd; - useCount = new AtomicInteger(); } /** @@ -164,13 +160,67 @@ public final class FileDescriptor { ); } - // 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 --git a/src/solaris/native/java/net/Inet4AddressImpl.c b/src/solaris/native/java/net/Inet4AddressImpl.c index 9a5b78e77238b00ed3036f7015960e9356b88674..ea68408efec0d8d5cab7ff95cfd421d1983d1e70 100644 --- a/src/solaris/native/java/net/Inet4AddressImpl.c +++ b/src/solaris/native/java/net/Inet4AddressImpl.c @@ -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; - - // ensure null-terminated - hostname[MAXHOSTNAMELEN] = '\0'; - -#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); - } + struct addrinfo hints, *res; + int error; + + 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); + + 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 @@ Java_java_net_Inet4AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this, 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 @@ Java_java_net_Inet4AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this, 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 @@ Java_java_net_Inet4AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this, } #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); - /* 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; + 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; + + 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 @@ JNIEXPORT jstring JNICALL 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 --git a/src/solaris/native/java/net/Inet6AddressImpl.c b/src/solaris/native/java/net/Inet6AddressImpl.c index bb5bae7810459252e58d5c9b5a49758d5709e92b..4f3f5869ca0a3a2f0700e4b381818e42a5f4937a 100644 --- a/src/solaris/native/java/net/Inet6AddressImpl.c +++ b/src/solaris/native/java/net/Inet6AddressImpl.c @@ -82,31 +82,29 @@ Java_java_net_Inet6AddressImpl_getLocalHostName(JNIEnv *env, jobject this) { * We use thread-safe system calls. */ #ifdef AF_INET6 - if (NET_addrtransAvailable()) { - struct addrinfo hints, *res; - int error; - - bzero(&hints, sizeof(hints)); - hints.ai_flags = AI_CANONNAME; - hints.ai_family = AF_UNSPEC; - - error = (*getaddrinfo_ptr)(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 getnameinfo fails hostname is still the value - from gethostname */ - - (*freeaddrinfo_ptr)(res); - } + struct addrinfo hints, *res; + int error; + + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = AI_CANONNAME; + hints.ai_family = AF_UNSPEC; + + error = getaddrinfo(hostname, NULL, &hints, &res); + + 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 */ + + freeaddrinfo(res); } #endif /* AF_INET6 */ #endif /* __linux__ */ @@ -173,193 +171,191 @@ Java_java_net_Inet6AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this, CHECK_NULL_RETURN(hostname, NULL); #ifdef AF_INET6 - if (NET_addrtransAvailable()) { - static jfieldID ia_preferIPv6AddressID; + 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) { - 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; - } + JNU_ReleaseStringPlatformChars(env, host, hostname); + return NULL; } - /* get the address preference */ - preferIPv6Address - = (*env)->GetStaticBooleanField(env, ia_class, ia_preferIPv6AddressID); + } + /* 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; + /* 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; - } + /* + * 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; + 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 { - 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; - break; - } + skip = 1; + 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; + } 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; - } - 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 ++; - } + 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; + iterator = iterator->ai_next; + } + retLen = i; + iterator = resNew; - ret = (*env)->NewObjectArray(env, retLen, ni_iacls, NULL); + 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 (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; - } + 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) { + 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 @@ cleanupAndReturn: JNU_ReleaseStringPlatformChars(env, host, hostname); } - if (NET_addrtransAvailable()) - (*freeaddrinfo_ptr)(res); + freeaddrinfo(res); #endif /* AF_INET6 */ return ret; @@ -393,44 +388,42 @@ Java_java_net_Inet6AddressImpl_getHostByAddr(JNIEnv *env, jobject this, 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 --git a/src/solaris/native/java/net/net_util_md.c b/src/solaris/native/java/net/net_util_md.c index 25b58f67c2a4d80f288b7470feeba56f9bb4d8a2..b542f4187bc2728f78a9e5d219b75099fe2cd0e8 100644 --- a/src/solaris/native/java/net/net_util_md.c +++ b/src/solaris/native/java/net/net_util_md.c @@ -377,37 +377,12 @@ jint IPv6_supported() * 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 @@ NET_IsEqual(jbyte* caddr1, jbyte* caddr2) { 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 --git a/src/solaris/native/java/net/net_util_md.h b/src/solaris/native/java/net/net_util_md.h index 5df589403ed0ee9f2a054a7d964103586be571da..28664ab6acb61a807b5c16938cc3107d430899f6 100644 --- a/src/solaris/native/java/net/net_util_md.h +++ b/src/solaris/native/java/net/net_util_md.h @@ -102,10 +102,6 @@ void ThrowUnknownHostExceptionWithGaiError(JNIEnv *env, 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 --git a/src/windows/classes/java/io/FileDescriptor.java b/src/windows/classes/java/io/FileDescriptor.java index 606d080989e9d0c4bec238aec754975fb3d24e35..bfcda5b497e5fa5872c07df734251477aa47d651 100644 --- a/src/windows/classes/java/io/FileDescriptor.java +++ b/src/windows/classes/java/io/FileDescriptor.java @@ -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 @@ public final class FileDescriptor { 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 final class FileDescriptor { public /**/ FileDescriptor() { fd = -1; handle = -1; - useCount = new AtomicInteger(); } static { @@ -168,13 +164,67 @@ public final class FileDescriptor { 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 --git a/src/windows/classes/java/net/PlainSocketImpl.java b/src/windows/classes/java/net/PlainSocketImpl.java index ea11fa609d8e4a19992c8e3f5372c6c15713cbcd..bcb01f1846be53d69602b0695ea8da1b728f7cd7 100644 --- a/src/windows/classes/java/net/PlainSocketImpl.java +++ b/src/windows/classes/java/net/PlainSocketImpl.java @@ -314,7 +314,7 @@ class PlainSocketImpl extends AbstractPlainSocketImpl 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 --git a/src/windows/classes/sun/security/krb5/internal/tools/Klist.java b/src/windows/classes/sun/security/krb5/internal/tools/Klist.java index ddfe95cd2ff4131ae072e91c4f54e0871e752269..e892353c482015fe597533cbc4eff067dcae5675 100644 --- a/src/windows/classes/sun/security/krb5/internal/tools/Klist.java +++ b/src/windows/classes/sun/security/krb5/internal/tools/Klist.java @@ -207,7 +207,7 @@ public class Klist { } if (options[2] == 't') { System.out.println("\t Time stamp: " + - reformat(entries[i].getTimeStamp().toDate().toString())); + format(entries[i].getTimeStamp())); } } } @@ -234,30 +234,39 @@ public class Klist { 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 @@ public class Klist { * 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 --git a/src/windows/lib/tzmappings b/src/windows/lib/tzmappings index 7f6f0d36052fc4ab7f514482cb944c1205a1d391..2f34a639b64a284f18670cecb5ba52aa55a84fff 100644 --- a/src/windows/lib/tzmappings +++ b/src/windows/lib/tzmappings @@ -167,7 +167,7 @@ Greenwich Standard Time:88,89::GMT: 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 @@ UTC-11:921,921::GMT-1100: 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 --git a/test/java/io/FileDescriptor/FileChannelFDTest.java b/test/java/io/FileDescriptor/FileChannelFDTest.java deleted file mode 100644 index 8a44859079bf1f2c0f7f71ad450f5ee70945486a..0000000000000000000000000000000000000000 --- a/test/java/io/FileDescriptor/FileChannelFDTest.java +++ /dev/null @@ -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 --git a/test/java/io/etc/FileDescriptorSharing.java b/test/java/io/FileDescriptor/Sharing.java similarity index 72% rename from test/java/io/etc/FileDescriptorSharing.java rename to test/java/io/FileDescriptor/Sharing.java index d46f61a52826db75dfbb3092c0418fe088fa598f..c340a983ebe15dea9f213d165968a2938b924038 100644 --- a/test/java/io/etc/FileDescriptorSharing.java +++ b/test/java/io/FileDescriptor/Sharing.java @@ -23,10 +23,9 @@ /* * @test - * @bug 6322678 7082769 - * @summary FileInputStream/FileOutputStream/RandomAccessFile allow file descriptor - * to be closed while still in use. - * @run main/othervm FileDescriptorSharing + * @bug 7105952 6322678 7082769 + * @summary Improve finalisation for FileInputStream/FileOutputStream/RandomAccessFile + * @run main/othervm Sharing */ import java.io.*; @@ -34,7 +33,7 @@ import java.nio.channels.FileChannel; import java.nio.channels.FileLock; import java.util.concurrent.CountDownLatch; -public class FileDescriptorSharing { +public class Sharing { final static int numFiles = 10; volatile static boolean fail; @@ -44,11 +43,12 @@ public class FileDescriptorSharing { TestMultipleFD(); TestIsValid(); MultiThreadedFD(); + TestCloseAll(); } /** - * We shouldn't discard a file descriptor until all streams have - * finished with it + * Finalizer shouldn't discard a file descriptor until all streams have + * finished with it. */ private static void TestFinalizer() throws Exception { FileDescriptor fd = null; @@ -96,9 +96,6 @@ public class FileDescriptorSharing { System.out.print("."); ret = fis3.read(); } - if(!fd.valid()) { - throw new RuntimeException("TestFinalizer() : FileDescriptor should be valid"); - } } finally { testFinalizerFile.delete(); } @@ -194,23 +191,19 @@ public class FileDescriptorSharing { } 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"); + throw new RuntimeException("[FIS close()] FileDescriptor shouldn't be valid"); } - } finally { + if (fos != null) fos.close(); if (raf != null) raf.close(); + } finally { test1.delete(); } } /* - * Close out in different order to ensure FD is not - * closed out too early + * Close out in different order to ensure FD is + * closed correctly. */ File test2 = new File("test2"); try { @@ -221,14 +214,11 @@ public class FileDescriptorSharing { } 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"); + throw new RuntimeException("[RAF close()] FileDescriptor shouldn't be valid"); } + if (fos != null) fos.close(); + if (fis != null) fis.close(); } finally { test2.delete(); } @@ -244,14 +234,11 @@ public class FileDescriptorSharing { } 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"); + throw new RuntimeException("[FOS close()] FileDescriptor shouldn't be valid"); } + if (raf != null) raf.close(); + if (fis != null) fis.close(); } finally { test3.delete(); } @@ -259,7 +246,7 @@ public class FileDescriptorSharing { } /** - * Test concurrent access to the same fd.useCount field + * Test concurrent access to the same FileDescriptor */ private static void MultiThreadedFD() throws Exception { RandomAccessFile raf = null; @@ -293,6 +280,68 @@ public class FileDescriptorSharing { } } + /** + * Test closeAll handling in FileDescriptor + */ + private static void TestCloseAll() throws Exception { + File testFile = new File("test"); + testFile.deleteOnExit(); + RandomAccessFile raf = new RandomAccessFile(testFile, "rw"); + FileInputStream fis = new FileInputStream(raf.getFD()); + fis.close(); + if (raf.getFD().valid()) { + throw new RuntimeException("FD should not be valid."); + } + + // Test the suppressed exception handling - FileInputStream + + raf = new RandomAccessFile(testFile, "rw"); + fis = new FileInputStream(raf.getFD()); + BadFileInputStream bfis1 = new BadFileInputStream(raf.getFD()); + BadFileInputStream bfis2 = new BadFileInputStream(raf.getFD()); + BadFileInputStream bfis3 = new BadFileInputStream(raf.getFD()); + // extra test - set bfis3 to null + bfis3 = null; + try { + fis.close(); + } catch (IOException ioe) { + ioe.printStackTrace(); + if (ioe.getSuppressed().length != 2) { + throw new RuntimeException("[FIS]Incorrect number of suppressed " + + "exceptions received : " + ioe.getSuppressed().length); + } + } + if (raf.getFD().valid()) { + // we should still have closed the FD + // even with the exception. + throw new RuntimeException("[FIS]TestCloseAll : FD still valid."); + } + + // Now test with FileOutputStream + + raf = new RandomAccessFile(testFile, "rw"); + FileOutputStream fos = new FileOutputStream(raf.getFD()); + BadFileOutputStream bfos1 = new BadFileOutputStream(raf.getFD()); + BadFileOutputStream bfos2 = new BadFileOutputStream(raf.getFD()); + BadFileOutputStream bfos3 = new BadFileOutputStream(raf.getFD()); + // extra test - set bfos3 to null + bfos3 = null; + try { + fos.close(); + } catch (IOException ioe) { + ioe.printStackTrace(); + if (ioe.getSuppressed().length != 2) { + throw new RuntimeException("[FOS]Incorrect number of suppressed " + + "exceptions received : " + ioe.getSuppressed().length); + } + } + if (raf.getFD().valid()) { + // we should still have closed the FD + // even with the exception. + throw new RuntimeException("[FOS]TestCloseAll : FD still valid."); + } + } + /** * A thread which will open and close a number of FileInputStreams and * FileOutputStreams referencing the same native file descriptor. @@ -325,12 +374,35 @@ public class FileDescriptorSharing { System.out.println("OpenClose encountered IO issue :" + ioe); fail = true; } finally { - if (!fd.valid()) { // fd should still be valid given RAF reference - System.out.println("OpenClose: FileDescriptor should be valid"); + if (fd.valid()) { // fd should not be valid after first close() call + System.out.println("OpenClose: FileDescriptor shouldn't be valid"); fail = true; } done.countDown(); } } } + + private static class BadFileInputStream extends FileInputStream { + + BadFileInputStream(FileDescriptor fd) { + super(fd); + } + + public void close() throws IOException { + throw new IOException("Bad close operation"); + } + } + + private static class BadFileOutputStream extends FileOutputStream { + + BadFileOutputStream(FileDescriptor fd) { + super(fd); + } + + public void close() throws IOException { + throw new IOException("Bad close operation"); + } + } + } diff --git a/test/java/lang/Runtime/exec/StreamsSurviveDestroy.java b/test/java/lang/Runtime/exec/StreamsSurviveDestroy.java index 82d9f9fc0ade90f8b19e5ce1b04387f52f765d29..3b51171fd1cf8045b5229330697046a7d5e7343e 100644 --- a/test/java/lang/Runtime/exec/StreamsSurviveDestroy.java +++ b/test/java/lang/Runtime/exec/StreamsSurviveDestroy.java @@ -28,6 +28,7 @@ */ import java.io.*; +import java.util.concurrent.*; public class StreamsSurviveDestroy { @@ -40,15 +41,17 @@ public class StreamsSurviveDestroy { boolean wantInterrupt; boolean acceptException; Exception exc = null; + CountDownLatch latch; Copier(String name, InputStream in, OutputStream out, - boolean ae, boolean wi) + boolean ae, boolean wi, CountDownLatch l) { this.name = name; this.in = in; this.out = out; this.acceptException = ae; this.wantInterrupt = wi; + this.latch = l; setName(name); start(); } @@ -59,6 +62,7 @@ public class StreamsSurviveDestroy { public void run() { byte[] buf = new byte[4242]; + latch.countDown(); for (;;) { try { int n = in.read(buf); @@ -95,13 +99,17 @@ public class StreamsSurviveDestroy { } static void test() throws Exception { + CountDownLatch latch = new CountDownLatch(2); + System.err.println("test"); Process p = Runtime.getRuntime().exec("/bin/cat"); Copier cp1 = new Copier("out", p.getInputStream(), System.err, - false, false); + false, false, latch); Copier cp2 = new Copier("err", p.getErrorStream(), System.err, - false, false); - Thread.sleep(100); + false, false, latch); + latch.await(); // Wait till both Copiers about to read + Thread.sleep(100);// Give both Copiers a chance to start read + p.destroy(); System.err.println(" exit: " + p.waitFor()); cp1.join(); @@ -111,13 +119,17 @@ public class StreamsSurviveDestroy { } static void testCloseBeforeDestroy() throws Exception { + CountDownLatch latch = new CountDownLatch(2); + System.err.println("testCloseBeforeDestroy"); Process p = Runtime.getRuntime().exec("/bin/cat"); Copier cp1 = new Copier("out", p.getInputStream(), System.err, - true, false); + true, false, latch); Copier cp2 = new Copier("err", p.getErrorStream(), System.err, - true, false); - Thread.sleep(100); + true, false, latch); + latch.await(); // Wait till both Copiers about to read + Thread.sleep(100);// Give both Copiers a chance to start read + p.getInputStream().close(); p.getErrorStream().close(); p.destroy(); @@ -129,13 +141,17 @@ public class StreamsSurviveDestroy { } static void testCloseAfterDestroy() throws Exception { + CountDownLatch latch = new CountDownLatch(2); System.err.println("testCloseAfterDestroy"); Process p = Runtime.getRuntime().exec("/bin/cat"); Copier cp1 = new Copier("out", p.getInputStream(), System.err, - true, false); + true, false,latch); Copier cp2 = new Copier("err", p.getErrorStream(), System.err, - true, false); - Thread.sleep(100); + true, false, latch); + + latch.await(); // Wait till both Copiers about to read + Thread.sleep(100);// Give both Copiers a chance to start read + p.destroy(); p.getInputStream().close(); p.getErrorStream().close(); @@ -147,13 +163,16 @@ public class StreamsSurviveDestroy { } static void testInterrupt() throws Exception { + CountDownLatch latch = new CountDownLatch(2); System.err.println("testInterrupt"); Process p = Runtime.getRuntime().exec("/bin/cat"); Copier cp1 = new Copier("out", p.getInputStream(), System.err, - false, true); + false, true, latch); Copier cp2 = new Copier("err", p.getErrorStream(), System.err, - false, true); - Thread.sleep(100); + false, true, latch); + latch.await(); // Wait till both Copiers about to read + Thread.sleep(100);// Give both Copiers a chance to start read + cp1.interrupt(); cp2.interrupt(); Thread.sleep(100); @@ -176,7 +195,5 @@ public class StreamsSurviveDestroy { testCloseBeforeDestroy(); testCloseAfterDestroy(); testInterrupt(); - } - } diff --git a/test/java/lang/ThreadGroup/NullThreadName.java b/test/java/lang/ThreadGroup/NullThreadName.java index 4d847c6e254e6af2d2ae38a54c704117afdf686a..4179b22446d4e9ec53e4561326965cc3331481b3 100644 --- a/test/java/lang/ThreadGroup/NullThreadName.java +++ b/test/java/lang/ThreadGroup/NullThreadName.java @@ -24,7 +24,6 @@ /* * @test * @bug 6576763 - * @ignore until hotspot 6776144 bug is resolved * @summary (thread) Thread constructors throw undocumented NPE for null name */ @@ -64,8 +63,8 @@ public class NullThreadName try { Thread.sleep(2000); } catch (InterruptedException unused) {} - /* do not wait forever */ - if (count++ > 5) + /* do not wait forever - allow 120 seconds same as jtreg default timeout. */ + if (count++ > 60) throw new AssertionError("GoodThread is still alive!"); } diff --git a/test/java/lang/ThreadGroup/Stop.java b/test/java/lang/ThreadGroup/Stop.java index 9c663c31241950896dbe276878188c1862de72d1..4763acc80361aa945e2ee38a1e7266a3258a40d5 100644 --- a/test/java/lang/ThreadGroup/Stop.java +++ b/test/java/lang/ThreadGroup/Stop.java @@ -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 --git a/test/java/lang/management/PlatformLoggingMXBean/LoggingMXBeanTest.java b/test/java/lang/management/PlatformLoggingMXBean/LoggingMXBeanTest.java index 17569b4cec1d010ac45db98cd859d73e1d86eb80..26b3b6615310f3a72b64b167ed7915c0ffce462f 100644 --- a/test/java/lang/management/PlatformLoggingMXBean/LoggingMXBeanTest.java +++ b/test/java/lang/management/PlatformLoggingMXBean/LoggingMXBeanTest.java @@ -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 @@ public class LoggingMXBeanTest 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 @@ public class LoggingMXBeanTest 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 @@ public class LoggingMXBeanTest // 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 @@ public class LoggingMXBeanTest // 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 @@ public class LoggingMXBeanTest 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 --git a/test/java/lang/management/PlatformLoggingMXBean/PlatformLoggingMXBeanTest.java b/test/java/lang/management/PlatformLoggingMXBean/PlatformLoggingMXBeanTest.java index 3694641351dc8adeef742b52520c5253e7c8817d..9d13b954c149e11610e269ea9c98ca58610f4c31 100644 --- a/test/java/lang/management/PlatformLoggingMXBean/PlatformLoggingMXBeanTest.java +++ b/test/java/lang/management/PlatformLoggingMXBean/PlatformLoggingMXBeanTest.java @@ -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 @@ import java.util.List; 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 @@ public class PlatformLoggingMXBeanTest 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 @@ public class PlatformLoggingMXBeanTest 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 --git a/test/java/rmi/registry/readTest/readTest.java b/test/java/rmi/registry/readTest/readTest.java new file mode 100644 index 0000000000000000000000000000000000000000..8942b0c0e5e89b66790bbf0be9807e9fc10da6dc --- /dev/null +++ b/test/java/rmi/registry/readTest/readTest.java @@ -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 --git a/test/java/rmi/registry/readTest/readTest.sh b/test/java/rmi/registry/readTest/readTest.sh new file mode 100644 index 0000000000000000000000000000000000000000..54be1d79911ffd4013a883e1a3b4b10614a9d4dc --- /dev/null +++ b/test/java/rmi/registry/readTest/readTest.sh @@ -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 --git a/test/java/rmi/registry/readTest/testPkg/Client.java b/test/java/rmi/registry/readTest/testPkg/Client.java new file mode 100644 index 0000000000000000000000000000000000000000..c569ae47d7c11222797ebac09b4f2db5f48081dd --- /dev/null +++ b/test/java/rmi/registry/readTest/testPkg/Client.java @@ -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 --git a/test/java/rmi/registry/readTest/testPkg/Hello.java b/test/java/rmi/registry/readTest/testPkg/Hello.java new file mode 100644 index 0000000000000000000000000000000000000000..c2f38b1d75b9ebdb37236cff18ec52804441c8e1 --- /dev/null +++ b/test/java/rmi/registry/readTest/testPkg/Hello.java @@ -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 --git a/test/java/rmi/registry/readTest/testPkg/Server.java b/test/java/rmi/registry/readTest/testPkg/Server.java new file mode 100644 index 0000000000000000000000000000000000000000..b76e97813c97f01abe19f8ad7d5ddfb4db8959a6 --- /dev/null +++ b/test/java/rmi/registry/readTest/testPkg/Server.java @@ -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 --git a/test/java/util/Timer/Args.java b/test/java/util/Timer/Args.java index ca3077d3a32fb79c8548907faa55c6c8c737e149..ab8065c8670fdfdff164f76c9713ab1a5ec22a7f 100644 --- a/test/java/util/Timer/Args.java +++ b/test/java/util/Timer/Args.java @@ -92,19 +92,22 @@ public class Args { 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 --git a/test/java/util/Timer/KillThread.java b/test/java/util/Timer/KillThread.java index 386e569719e1a621d6bd8aef1f9169acb24e3982..dee5eeea208ffc84cf3f0dd4f71d7f146d8540dd 100644 --- a/test/java/util/Timer/KillThread.java +++ b/test/java/util/Timer/KillThread.java @@ -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 --git a/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLContextImpl/MD2InTrustAnchor.java b/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLContextImpl/MD2InTrustAnchor.java new file mode 100644 index 0000000000000000000000000000000000000000..0a25f7f21ced07ea6de86ef074a1deef0ea112a3 --- /dev/null +++ b/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLContextImpl/MD2InTrustAnchor.java @@ -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 --git a/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLContextImpl/TrustTrustedCert.java b/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLContextImpl/TrustTrustedCert.java new file mode 100644 index 0000000000000000000000000000000000000000..3aeeb081b3468e53bca9974d70470d6c9e17002e --- /dev/null +++ b/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLContextImpl/TrustTrustedCert.java @@ -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; + } + } + } +}