8143923: java.net socket supportedOptions set depends on call order
Reviewed-by: chegar
--- a/jdk/src/java.base/share/classes/java/net/AbstractPlainDatagramSocketImpl.java Tue May 24 11:31:25 2016 +0100
+++ b/jdk/src/java.base/share/classes/java/net/AbstractPlainDatagramSocketImpl.java Tue May 24 12:31:30 2016 +0100
@@ -87,27 +87,22 @@
return isReusePortAvailable;
}
- private static volatile Set<SocketOption<?>> socketOptions;
-
/**
- * Returns a set of SocketOptions supported by this impl
- * and by this impl's socket (Socket or ServerSocket)
+ * Returns a set of SocketOptions supported by this impl and by this impl's
+ * socket (Socket or ServerSocket)
*
* @return a Set of SocketOptions
*/
@Override
protected Set<SocketOption<?>> supportedOptions() {
- Set<SocketOption<?>> options = socketOptions;
- if (options == null) {
- if (isReusePortAvailable()) {
- options = new HashSet<>();
- options.addAll(super.supportedOptions());
- options.add(StandardSocketOptions.SO_REUSEPORT);
- options = Collections.unmodifiableSet(options);
- } else {
- options = super.supportedOptions();
- }
- socketOptions = options;
+ Set<SocketOption<?>> options;
+ if (isReusePortAvailable()) {
+ options = new HashSet<>();
+ options.addAll(super.supportedOptions());
+ options.add(StandardSocketOptions.SO_REUSEPORT);
+ options = Collections.unmodifiableSet(options);
+ } else {
+ options = super.supportedOptions();
}
return options;
}
--- a/jdk/src/java.base/share/classes/java/net/AbstractPlainSocketImpl.java Tue May 24 11:31:25 2016 +0100
+++ b/jdk/src/java.base/share/classes/java/net/AbstractPlainSocketImpl.java Tue May 24 12:31:30 2016 +0100
@@ -104,27 +104,22 @@
return isReusePortAvailable;
}
- private static volatile Set<SocketOption<?>> socketOptions;
-
- /**
- * Returns a set of SocketOptions supported by this impl
- * and by this impl's socket (Socket or ServerSocket)
- *
- * @return a Set of SocketOptions
- */
+ /**
+ * Returns a set of SocketOptions supported by this impl and by this impl's
+ * socket (Socket or ServerSocket)
+ *
+ * @return a Set of SocketOptions
+ */
@Override
protected Set<SocketOption<?>> supportedOptions() {
- Set<SocketOption<?>> options = socketOptions;
- if (options == null) {
- if (isReusePortAvailable()) {
- options = new HashSet<>();
- options.addAll(super.supportedOptions());
- options.add(StandardSocketOptions.SO_REUSEPORT);
- options = Collections.unmodifiableSet(options);
- } else {
- options = super.supportedOptions();
- }
- socketOptions = options;
+ Set<SocketOption<?>> options;
+ if (isReusePortAvailable()) {
+ options = new HashSet<>();
+ options.addAll(super.supportedOptions());
+ options.add(StandardSocketOptions.SO_REUSEPORT);
+ options = Collections.unmodifiableSet(options);
+ } else {
+ options = super.supportedOptions();
}
return options;
}
--- a/jdk/src/java.base/share/classes/java/net/MulticastSocket.java Tue May 24 11:31:25 2016 +0100
+++ b/jdk/src/java.base/share/classes/java/net/MulticastSocket.java Tue May 24 12:31:30 2016 +0100
@@ -26,7 +26,9 @@
package java.net;
import java.io.IOException;
+import java.util.Collections;
import java.util.Enumeration;
+import java.util.Set;
/**
* The multicast datagram socket class is useful for sending
@@ -716,4 +718,24 @@
} // synch p
} //synch ttl
} //method
+
+ private static Set<SocketOption<?>> options;
+ private static boolean optionsSet = false;
+
+ @Override
+ public Set<SocketOption<?>> supportedOptions() {
+ synchronized (MulticastSocket.class) {
+ if (optionsSet) {
+ return options;
+ }
+ try {
+ DatagramSocketImpl impl = getImpl();
+ options = Collections.unmodifiableSet(impl.supportedOptions());
+ } catch (SocketException ex) {
+ options = Collections.emptySet();
+ }
+ optionsSet = true;
+ return options;
+ }
+ }
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/SocketOption/SupportedOptionsSet.java Tue May 24 12:31:30 2016 +0100
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2016, 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.io.IOException;
+import java.net.*;
+import java.util.Set;
+import static java.lang.System.out;
+
+/*
+ * @test
+ * @bug 8143923
+ * @summary java.net socket supportedOptions set depends on call order
+ * @run main/othervm SupportedOptionsSet first
+ * @run main/othervm SupportedOptionsSet second
+ */
+
+// Run with othervm as the implementation of the supported options sets, once
+// calculated, stores them in a private static fields.
+
+public class SupportedOptionsSet {
+
+ public static void main(String[] args) throws IOException {
+ if (args[0].equals("first"))
+ first();
+ else if (args[0].equals("second"))
+ second();
+ }
+
+ static void first() throws IOException {
+ try (Socket s = new Socket();
+ ServerSocket ss = new ServerSocket();
+ DatagramSocket ds = new DatagramSocket();
+ MulticastSocket ms = new MulticastSocket()) {
+
+ Set<?> first = s.supportedOptions();
+ Set<?> second = ss.supportedOptions();
+ assertNotEqual(first, second,
+ "Socket and ServerSocket should have different options.");
+
+ first = ds.supportedOptions();
+ second = ms.supportedOptions();
+ assertNotEqual(first, second,
+ "DatagramSocket and MulticastSocket should have different options.");
+ }
+ }
+
+ /** Tests with the order of access to supportedOptions reversed. */
+ static void second() throws IOException {
+ try (ServerSocket ss = new ServerSocket();
+ Socket s = new Socket();
+ DatagramSocket ds = new DatagramSocket();
+ MulticastSocket ms = new MulticastSocket()) {
+
+ Set<?> first = ss.supportedOptions();
+ Set<?> second = s.supportedOptions();
+ assertNotEqual(first, second,
+ "ServerSocket and Socket should have different options.");
+
+ first = ms.supportedOptions();
+ second = ds.supportedOptions();
+ assertNotEqual(first, second,
+ "MulticastSocket and DatagramSocket should have different options.");
+
+ }
+ }
+
+ static void assertNotEqual(Set<?> s1, Set<?> s2, String message) {
+ if (s1.equals(s2)) {
+ out.println("s1: " + s1);
+ out.println("s2: " + s2);
+ throw new RuntimeException(message);
+ }
+ }
+}