8143923: java.net socket supportedOptions set depends on call order
authorvtewari
Tue, 24 May 2016 12:31:30 +0100
changeset 38477 f462865d453d
parent 38476 c491c24d34a9
child 38478 c4c94ae846e7
8143923: java.net socket supportedOptions set depends on call order Reviewed-by: chegar
jdk/src/java.base/share/classes/java/net/AbstractPlainDatagramSocketImpl.java
jdk/src/java.base/share/classes/java/net/AbstractPlainSocketImpl.java
jdk/src/java.base/share/classes/java/net/MulticastSocket.java
jdk/test/java/net/SocketOption/SupportedOptionsSet.java
--- 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);
+        }
+    }
+}