8143554: UnsupportedOperationException is not thrown for unsupported options
authorkshefov
Sat, 16 Jan 2016 00:27:53 +0300
changeset 34968 93b315c61ca3
parent 34967 5921e8a0ff14
child 34969 d496b67b8c52
8143554: UnsupportedOperationException is not thrown for unsupported options Reviewed-by: alanb Contributed-by: Svetlana Nikandrova <svetlana.nikandrova@oracle.com>
jdk/src/java.base/share/classes/java/net/SocketImpl.java
jdk/src/java.base/unix/classes/java/net/PlainDatagramSocketImpl.java
jdk/src/java.base/unix/classes/java/net/PlainSocketImpl.java
jdk/test/java/net/SocketOption/UnsupportedOptionsTest.java
--- a/jdk/src/java.base/share/classes/java/net/SocketImpl.java	Fri Jan 15 10:30:56 2016 -0800
+++ b/jdk/src/java.base/share/classes/java/net/SocketImpl.java	Sat Jan 16 00:27:53 2016 +0300
@@ -376,19 +376,23 @@
      * @since 1.9
      */
     protected <T> void setOption(SocketOption<T> name, T value) throws IOException {
-        if (name == StandardSocketOptions.SO_KEEPALIVE) {
+        if (name == StandardSocketOptions.SO_KEEPALIVE &&
+                (getSocket() != null)) {
             setOption(SocketOptions.SO_KEEPALIVE, value);
-        } else if (name == StandardSocketOptions.SO_SNDBUF) {
+        } else if (name == StandardSocketOptions.SO_SNDBUF &&
+                (getSocket() != null)) {
             setOption(SocketOptions.SO_SNDBUF, value);
         } else if (name == StandardSocketOptions.SO_RCVBUF) {
             setOption(SocketOptions.SO_RCVBUF, value);
         } else if (name == StandardSocketOptions.SO_REUSEADDR) {
             setOption(SocketOptions.SO_REUSEADDR, value);
-        } else if (name == StandardSocketOptions.SO_LINGER) {
+        } else if (name == StandardSocketOptions.SO_LINGER &&
+                (getSocket() != null)) {
             setOption(SocketOptions.SO_LINGER, value);
         } else if (name == StandardSocketOptions.IP_TOS) {
             setOption(SocketOptions.IP_TOS, value);
-        } else if (name == StandardSocketOptions.TCP_NODELAY) {
+        } else if (name == StandardSocketOptions.TCP_NODELAY &&
+                (getSocket() != null)) {
             setOption(SocketOptions.TCP_NODELAY, value);
         } else {
             throw new UnsupportedOperationException("unsupported option");
@@ -412,19 +416,23 @@
      */
     @SuppressWarnings("unchecked")
     protected <T> T getOption(SocketOption<T> name) throws IOException {
-        if (name == StandardSocketOptions.SO_KEEPALIVE) {
+        if (name == StandardSocketOptions.SO_KEEPALIVE &&
+                (getSocket() != null)) {
             return (T)getOption(SocketOptions.SO_KEEPALIVE);
-        } else if (name == StandardSocketOptions.SO_SNDBUF) {
+        } else if (name == StandardSocketOptions.SO_SNDBUF &&
+                (getSocket() != null)) {
             return (T)getOption(SocketOptions.SO_SNDBUF);
         } else if (name == StandardSocketOptions.SO_RCVBUF) {
             return (T)getOption(SocketOptions.SO_RCVBUF);
         } else if (name == StandardSocketOptions.SO_REUSEADDR) {
             return (T)getOption(SocketOptions.SO_REUSEADDR);
-        } else if (name == StandardSocketOptions.SO_LINGER) {
+        } else if (name == StandardSocketOptions.SO_LINGER &&
+                (getSocket() != null)) {
             return (T)getOption(SocketOptions.SO_LINGER);
         } else if (name == StandardSocketOptions.IP_TOS) {
             return (T)getOption(SocketOptions.IP_TOS);
-        } else if (name == StandardSocketOptions.TCP_NODELAY) {
+        } else if (name == StandardSocketOptions.TCP_NODELAY &&
+                (getSocket() != null)) {
             return (T)getOption(SocketOptions.TCP_NODELAY);
         } else {
             throw new UnsupportedOperationException("unsupported option");
--- a/jdk/src/java.base/unix/classes/java/net/PlainDatagramSocketImpl.java	Fri Jan 15 10:30:56 2016 -0800
+++ b/jdk/src/java.base/unix/classes/java/net/PlainDatagramSocketImpl.java	Sat Jan 16 00:27:53 2016 +0300
@@ -47,6 +47,9 @@
         if (!name.equals(ExtendedSocketOptions.SO_FLOW_SLA)) {
             super.setOption(name, value);
         } else {
+            if (!flowSupported()) {
+                throw new UnsupportedOperationException("unsupported option");
+            }
             if (isClosed()) {
                 throw new SocketException("Socket closed");
             }
@@ -61,6 +64,9 @@
         if (!name.equals(ExtendedSocketOptions.SO_FLOW_SLA)) {
             return super.getOption(name);
         }
+        if (!flowSupported()) {
+            throw new UnsupportedOperationException("unsupported option");
+        }
         if (isClosed()) {
             throw new SocketException("Socket closed");
         }
--- a/jdk/src/java.base/unix/classes/java/net/PlainSocketImpl.java	Fri Jan 15 10:30:56 2016 -0800
+++ b/jdk/src/java.base/unix/classes/java/net/PlainSocketImpl.java	Sat Jan 16 00:27:53 2016 +0300
@@ -61,6 +61,9 @@
         if (!name.equals(ExtendedSocketOptions.SO_FLOW_SLA)) {
             super.setOption(name, value);
         } else {
+            if (getSocket() == null || !flowSupported()) {
+                throw new UnsupportedOperationException("unsupported option");
+            }
             if (isClosedOrPending()) {
                 throw new SocketException("Socket closed");
             }
@@ -75,6 +78,9 @@
         if (!name.equals(ExtendedSocketOptions.SO_FLOW_SLA)) {
             return super.getOption(name);
         }
+        if (getSocket() == null || !flowSupported()) {
+            throw new UnsupportedOperationException("unsupported option");
+        }
         if (isClosedOrPending()) {
             throw new SocketException("Socket closed");
         }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/SocketOption/UnsupportedOptionsTest.java	Sat Jan 16 00:27:53 2016 +0300
@@ -0,0 +1,141 @@
+/*
+ * 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 jdk.net.ExtendedSocketOptions;
+
+import java.io.IOException;
+import java.net.*;
+
+/*
+ * @test
+ * @bug 8143554
+ * @run main UnsupportedOptionsTest
+ * @summary Test checks that UnsupportedOperationException for unsupported
+ * SOCKET_OPTIONS is thrown by both getOption() and setOption() methods.
+ */
+public class UnsupportedOptionsTest {
+
+    private static final SocketOption[] SOCKET_OPTIONS = {
+            StandardSocketOptions.IP_MULTICAST_IF,
+            StandardSocketOptions.IP_MULTICAST_LOOP,
+            StandardSocketOptions.IP_MULTICAST_TTL,
+            StandardSocketOptions.IP_TOS,
+            StandardSocketOptions.SO_BROADCAST,
+            StandardSocketOptions.SO_KEEPALIVE,
+            StandardSocketOptions.SO_LINGER,
+            StandardSocketOptions.SO_RCVBUF,
+            StandardSocketOptions.SO_REUSEADDR,
+            StandardSocketOptions.SO_SNDBUF,
+            StandardSocketOptions.TCP_NODELAY,
+            ExtendedSocketOptions.SO_FLOW_SLA
+    };
+
+    public static void main(String[] args) throws IOException {
+        Socket s = new Socket();
+        ServerSocket ss = new ServerSocket();
+        DatagramSocket ds = new DatagramSocket();
+        MulticastSocket ms = new MulticastSocket();
+
+        for (SocketOption option : SOCKET_OPTIONS) {
+            if (!s.supportedOptions().contains(option)) {
+                testUnsupportedSocketOption(s, option);
+            }
+
+            if (!ss.supportedOptions().contains(option)) {
+                testUnsupportedSocketOption(ss, option);
+            }
+
+            if (!ms.supportedOptions().contains(option)) {
+                testUnsupportedSocketOption(ms, option);
+            }
+
+            if (!ds.supportedOptions().contains(option)) {
+                testUnsupportedSocketOption(ds, option);
+            }
+        }
+    }
+
+    /*
+     * Check that UnsupportedOperationException for unsupported option is
+     * thrown from both getOption() and setOption() methods.
+     */
+    private static void testUnsupportedSocketOption(Object socket,
+                                                    SocketOption option) {
+        testSet(socket, option);
+        testGet(socket, option);
+    }
+
+    private static void testSet(Object socket, SocketOption option) {
+        try {
+            setOption(socket, option);
+        } catch (UnsupportedOperationException e) {
+            System.out.println("UnsupportedOperationException was throw " +
+                    "as expected. Socket: " + socket + " Option: " + option);
+            return;
+        } catch (Exception e) {
+            throw new RuntimeException("FAIL. Unexpected exception.", e);
+        }
+        throw new RuntimeException("FAIL. UnsupportedOperationException " +
+                "hasn't been thrown. Socket: " + socket + " Option: " + option);
+    }
+
+    private static void testGet(Object socket, SocketOption option) {
+        try {
+            getOption(socket, option);
+        } catch (UnsupportedOperationException e) {
+            System.out.println("UnsupportedOperationException was throw " +
+                    "as expected. Socket: " + socket + " Option: " + option);
+            return;
+        } catch (Exception e) {
+            throw new RuntimeException("FAIL. Unexpected exception.", e);
+        }
+        throw new RuntimeException("FAIL. UnsupportedOperationException " +
+                "hasn't been thrown. Socket: " + socket + " Option: " + option);
+    }
+
+    private static void getOption(Object socket,
+                                  SocketOption option) throws IOException {
+        if (socket instanceof Socket) {
+            ((Socket) socket).getOption(option);
+        } else if (socket instanceof ServerSocket) {
+            ((ServerSocket) socket).getOption(option);
+        } else if (socket instanceof DatagramSocket) {
+            ((DatagramSocket) socket).getOption(option);
+        } else {
+            throw new RuntimeException("Unsupported socket type");
+        }
+    }
+
+    private static void setOption(Object socket,
+                                  SocketOption option) throws IOException {
+        if (socket instanceof Socket) {
+            ((Socket) socket).setOption(option, null);
+        } else if (socket instanceof ServerSocket) {
+            ((ServerSocket) socket).setOption(option, null);
+        } else if (socket instanceof DatagramSocket) {
+            ((DatagramSocket) socket).setOption(option, null);
+        } else {
+            throw new RuntimeException("Unsupported socket type");
+        }
+    }
+}