changeset 57314:32d978ba562f

8235141: Specify the required standard socket options for the socket types in the java.net package Reviewed-by: alanb, chegar
author dfuchs
date Tue, 10 Dec 2019 13:22:52 +0000
parents d56c192d967d
children 3c8af950e849
files src/java.base/share/classes/java/net/DatagramSocket.java src/java.base/share/classes/java/net/MulticastSocket.java src/java.base/share/classes/java/net/ServerSocket.java src/java.base/share/classes/java/net/Socket.java test/jdk/java/net/SocketOption/RequiredOptions.java
diffstat 5 files changed, 340 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/src/java.base/share/classes/java/net/DatagramSocket.java	Tue Dec 10 08:15:45 2019 -0500
+++ b/src/java.base/share/classes/java/net/DatagramSocket.java	Tue Dec 10 13:22:52 2019 +0000
@@ -43,24 +43,69 @@
  * any order.
  *
  * <p> Where possible, a newly constructed {@code DatagramSocket} has the
- * {@link SocketOptions#SO_BROADCAST SO_BROADCAST} socket option enabled so as
+ * {@link StandardSocketOptions#SO_BROADCAST SO_BROADCAST} socket option enabled so as
  * to allow the transmission of broadcast datagrams. In order to receive
  * broadcast packets a DatagramSocket should be bound to the wildcard address.
  * In some implementations, broadcast packets may also be received when
  * a DatagramSocket is bound to a more specific address.
  * <p>
  * Example:
- * {@code
+ * <pre>{@code
  *              DatagramSocket s = new DatagramSocket(null);
  *              s.bind(new InetSocketAddress(8888));
- * }
+ * }</pre>
  * Which is equivalent to:
- * {@code
+ * <pre>{@code
  *              DatagramSocket s = new DatagramSocket(8888);
- * }
+ * }</pre>
  * Both cases will create a DatagramSocket able to receive broadcasts on
  * UDP port 8888.
  *
+ * <p> The {@code DatagramSocket} class defines convenience
+ * methods to set and get several socket options. This class also
+ * defines the {@link #setOption(SocketOption,Object) setOption}
+ * and {@link #getOption(SocketOption) getOption} methods to set
+ * and query socket options.
+ * A {@code DatagramSocket} supports the following socket options:
+ * <blockquote>
+ * <a id="SocketOptions"></a>
+ * <table class="striped">
+ * <caption style="display:none">Socket options</caption>
+ * <thead>
+ *   <tr>
+ *     <th scope="col">Option Name</th>
+ *     <th scope="col">Description</th>
+ *   </tr>
+ * </thead>
+ * <tbody>
+ *   <tr>
+ *     <th scope="row"> {@link java.net.StandardSocketOptions#SO_SNDBUF SO_SNDBUF} </th>
+ *     <td> The size of the socket send buffer </td>
+ *   </tr>
+ *   <tr>
+ *     <th scope="row"> {@link java.net.StandardSocketOptions#SO_RCVBUF SO_RCVBUF} </th>
+ *     <td> The size of the socket receive buffer </td>
+ *   </tr>
+ *   <tr>
+ *     <th scope="row"> {@link java.net.StandardSocketOptions#SO_REUSEADDR SO_REUSEADDR} </th>
+ *     <td> Re-use address </td>
+ *   </tr>
+ *   <tr>
+ *     <th scope="row"> {@link java.net.StandardSocketOptions#SO_BROADCAST SO_BROADCAST} </th>
+ *     <td> Allow transmission of broadcast datagrams </td>
+ *   </tr>
+ *   <tr>
+ *     <th scope="row"> {@link java.net.StandardSocketOptions#IP_TOS IP_TOS} </th>
+ *     <td> The Type of Service (ToS) octet in the Internet Protocol (IP) header </td>
+ *   </tr>
+ * </tbody>
+ * </table>
+ * </blockquote>
+ * An implementation may also support additional options. In particular an implementation
+ * may support <a href="MulticastSocket.html#MulticastOptions">multicast options</a> which
+ * can be useful when using a plain {@code DatagramSocket} to send datagrams to a
+ * multicast group.
+ *
  * @author  Pavani Diwanji
  * @see     java.net.DatagramPacket
  * @see     java.nio.channels.DatagramChannel
--- a/src/java.base/share/classes/java/net/MulticastSocket.java	Tue Dec 10 08:15:45 2019 -0500
+++ b/src/java.base/share/classes/java/net/MulticastSocket.java	Tue Dec 10 13:22:52 2019 +0000
@@ -80,6 +80,46 @@
  * <B>Multiple MulticastSockets</B> may subscribe to a multicast group
  * and port concurrently, and they will all receive group datagrams.
  *
+ * <p> The {@code DatagramSocket} and {@code MulticastSocket}
+ * classes define convenience methods to set and get several
+ * socket options. Like {@code DatagramSocket} this class also
+ * supports the {@link #setOption(SocketOption, Object) setOption}
+ * and {@link #getOption(SocketOption) getOption} methods to set
+ * and query socket options.
+ * In addition to the socket options supported by
+ * <a href="DatagramSocket.html#SocketOptions">{@code DatagramSocket}</a>, a
+ * {@code MulticastSocket} supports the following socket options:
+ * <blockquote>
+ * <a id="MulticastOptions"></a>
+ * <table class="striped">
+ * <caption style="display:none">Socket options</caption>
+ * <thead>
+ *   <tr>
+ *     <th scope="col">Option Name</th>
+ *     <th scope="col">Description</th>
+ *   </tr>
+ * </thead>
+ * <tbody>
+ *   <tr>
+ *     <th scope="row"> {@link java.net.StandardSocketOptions#IP_MULTICAST_IF IP_MULTICAST_IF} </th>
+ *     <td> The network interface for Internet Protocol (IP) multicast datagrams </td>
+ *   </tr>
+ *   <tr>
+ *     <th scope="row"> {@link java.net.StandardSocketOptions#IP_MULTICAST_TTL
+ *       IP_MULTICAST_TTL} </th>
+ *     <td> The <em>time-to-live</em> for Internet Protocol (IP) multicast
+ *       datagrams </td>
+ *   </tr>
+ *   <tr>
+ *     <th scope="row"> {@link java.net.StandardSocketOptions#IP_MULTICAST_LOOP
+ *       IP_MULTICAST_LOOP} </th>
+ *     <td> Loopback for Internet Protocol (IP) multicast datagrams </td>
+ *   </tr>
+ * </tbody>
+ * </table>
+ * </blockquote>
+ * Additional (implementation specific) options may also be supported.
+ *
  * @author Pavani Diwanji
  * @since 1.1
  */
--- a/src/java.base/share/classes/java/net/ServerSocket.java	Tue Dec 10 08:15:45 2019 -0500
+++ b/src/java.base/share/classes/java/net/ServerSocket.java	Tue Dec 10 13:22:52 2019 +0000
@@ -46,6 +46,35 @@
  * implementation to configure itself to create sockets
  * appropriate to the local firewall.
  *
+ * <p> The {@code ServerSocket} class defines convenience
+ * methods to set and get several socket options. This class also
+ * defines the {@link #setOption(SocketOption, Object) setOption}
+ * and {@link #getOption(SocketOption) getOption} methods to set
+ * and query socket options.
+ * A {@code ServerSocket} supports the following options:
+ * <blockquote>
+ * <table class="striped">
+ * <caption style="display:none">Socket options</caption>
+ * <thead>
+ *   <tr>
+ *     <th scope="col">Option Name</th>
+ *     <th scope="col">Description</th>
+ *   </tr>
+ * </thead>
+ * <tbody>
+ *   <tr>
+ *     <th scope="row"> {@link java.net.StandardSocketOptions#SO_RCVBUF SO_RCVBUF} </th>
+ *     <td> The size of the socket receive buffer </td>
+ *   </tr>
+ *   <tr>
+ *     <th scope="row"> {@link java.net.StandardSocketOptions#SO_REUSEADDR SO_REUSEADDR} </th>
+ *     <td> Re-use address </td>
+ *   </tr>
+ * </tbody>
+ * </table>
+ * </blockquote>
+ * Additional (implementation specific) options may also be supported.
+ *
  * @author  unascribed
  * @see     java.net.SocketImpl
  * @see     java.net.ServerSocket#setSocketFactory(java.net.SocketImplFactory)
--- a/src/java.base/share/classes/java/net/Socket.java	Tue Dec 10 08:15:45 2019 -0500
+++ b/src/java.base/share/classes/java/net/Socket.java	Tue Dec 10 13:22:52 2019 +0000
@@ -50,6 +50,52 @@
  * can configure itself to create sockets appropriate to the local
  * firewall.
  *
+ * <p> The {@code Socket} class defines convenience
+ * methods to set and get several socket options. This class also
+ * defines the {@link #setOption(SocketOption, Object) setOption}
+ * and {@link #getOption(SocketOption) getOption} methods to set
+ * and query socket options.
+ * A {@code Socket} support the following options:
+ * <blockquote>
+ * <table class="striped">
+ * <caption style="display:none">Socket options</caption>
+ * <thead>
+ *   <tr>
+ *     <th scope="col">Option Name</th>
+ *     <th scope="col">Description</th>
+ *   </tr>
+ * </thead>
+ * <tbody>
+ *   <tr>
+ *     <th scope="row"> {@link java.net.StandardSocketOptions#SO_SNDBUF SO_SNDBUF} </th>
+ *     <td> The size of the socket send buffer </td>
+ *   </tr>
+ *   <tr>
+ *     <th scope="row"> {@link java.net.StandardSocketOptions#SO_RCVBUF SO_RCVBUF} </th>
+ *     <td> The size of the socket receive buffer </td>
+ *   </tr>
+ *   <tr>
+ *     <th scope="row"> {@link java.net.StandardSocketOptions#SO_KEEPALIVE SO_KEEPALIVE} </th>
+ *     <td> Keep connection alive </td>
+ *   </tr>
+ *   <tr>
+ *     <th scope="row"> {@link java.net.StandardSocketOptions#SO_REUSEADDR SO_REUSEADDR} </th>
+ *     <td> Re-use address </td>
+ *   </tr>
+ *   <tr>
+ *     <th scope="row"> {@link java.net.StandardSocketOptions#SO_LINGER SO_LINGER} </th>
+ *     <td> Linger on close if data is present (when configured in blocking mode
+ *          only) </td>
+ *   </tr>
+ *   <tr>
+ *     <th scope="row"> {@link java.net.StandardSocketOptions#TCP_NODELAY TCP_NODELAY} </th>
+ *     <td> Disable the Nagle algorithm </td>
+ *   </tr>
+ * </tbody>
+ * </table>
+ * </blockquote>
+ * Additional (implementation specific) options may also be supported.
+ *
  * @author  unascribed
  * @see     java.net.Socket#setSocketImplFactory(java.net.SocketImplFactory)
  * @see     java.net.SocketImpl
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/SocketOption/RequiredOptions.java	Tue Dec 10 13:22:52 2019 +0000
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2019, 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.DatagramSocket;
+import java.net.MulticastSocket;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketOption;
+import java.nio.channels.DatagramChannel;
+import java.nio.channels.NetworkChannel;
+import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.SocketChannel;
+import java.util.Set;
+import java.util.stream.Stream;
+import org.testng.annotations.Test;
+import org.testng.annotations.DataProvider;
+
+import static java.net.StandardSocketOptions.*;
+
+/*
+ * @test
+ * @bug 8235141
+ * @summary verifies that our implementation supports the set
+ *          of SocketOptions that are required by the API documentation.
+ * @run testng/othervm -Djdk.net.usePlainSocketImpl RequiredOptions
+ * @run testng/othervm RequiredOptions
+ */
+public class RequiredOptions {
+
+    static final Set<SocketOption<?>> DATAGRAM_OPTIONS =
+            Set.of(SO_BROADCAST, SO_SNDBUF, SO_RCVBUF, SO_REUSEADDR, IP_TOS);
+    static final Set<SocketOption<?>> MULTICAST_OPTIONS =
+            concat(DATAGRAM_OPTIONS, Set.of(IP_MULTICAST_IF, IP_MULTICAST_LOOP, IP_MULTICAST_TTL));
+    static final Set<SocketOption<?>> SOCKET_OPTIONS =
+            Set.of(SO_KEEPALIVE, SO_LINGER, SO_SNDBUF, SO_RCVBUF, SO_REUSEADDR, TCP_NODELAY);
+    static final Set<SocketOption<?>> SERVER_OPTIONS =
+            Set.of(SO_RCVBUF, SO_REUSEADDR);
+
+    static Set<SocketOption<?>> concat(Set<SocketOption<?>> ...options) {
+        return Set.of(Stream.of(options).flatMap(Set::stream).distinct().toArray(SocketOption[]::new));
+    }
+
+    @DataProvider(name = "sockets")
+    static Object[][] provider() throws IOException {
+        return new Object[][] {
+                // UDP
+                { Configurable.of(new DatagramSocket(null)), DATAGRAM_OPTIONS },
+                { Configurable.of(new MulticastSocket(null)), MULTICAST_OPTIONS },
+                // TCP
+                { Configurable.of(new Socket()), SOCKET_OPTIONS },
+                { Configurable.of(new ServerSocket()), SERVER_OPTIONS },
+                // Adaptors
+                { Configurable.of(DatagramChannel.open().socket()), MULTICAST_OPTIONS },
+                { Configurable.of(SocketChannel.open().socket()), SOCKET_OPTIONS },
+                { Configurable.of(ServerSocketChannel.open().socket()), SERVER_OPTIONS },
+        };
+    }
+
+    @Test(dataProvider = "sockets")
+    public <R, E extends Exception>
+    void test(Configurable<R,E> socket, Set<SocketOption<?>> options) throws E {
+        try (var s = socket) {
+            var impl = socket.socket().getClass();
+            System.out.println("Testing " + impl + " with " + options);
+            Set<SocketOption<?>> supported = socket.supportedOptions();
+            if (!supported.containsAll(options)) {
+                for (var option : options) {
+                    if (!supported.contains(option)) {
+                        System.err.println("Option " + option + " not supported by " + impl);
+                    }
+                }
+                throw new AssertionError("Not all documented options are supported by " + impl);
+            }
+        }
+    }
+
+    static interface Configurable<R, E extends Exception> extends AutoCloseable {
+        <T> R setOption(SocketOption<T> name, T value) throws E;
+        <T> T getOption(SocketOption<T> name) throws E;
+        Set<SocketOption<?>> supportedOptions() throws E;
+        R socket();
+        void close() throws E;
+
+        static Configurable<DatagramSocket, IOException> of(DatagramSocket socket) {
+            return new ConfigurableImpl<>(socket, socket::setOption,
+                    socket::getOption, socket::supportedOptions, socket::close);
+        }
+        static Configurable<Socket, IOException> of(Socket socket) {
+            return new ConfigurableImpl<>(socket, socket::setOption,
+                    socket::getOption, socket::supportedOptions, socket::close);
+        }
+        static Configurable<ServerSocket, IOException> of(ServerSocket socket) {
+            return new ConfigurableImpl<>(socket, socket::setOption,
+                    socket::getOption, socket::supportedOptions, socket::close);
+        }
+    }
+
+    static final class ConfigurableImpl<R, E extends Exception> implements Configurable<R, E> {
+        @FunctionalInterface
+        interface SetOption<R, E extends Exception> {
+            <T> R setOption(SocketOption<T> name, T value) throws E;
+        }
+        @FunctionalInterface
+        interface GetOption<E extends Exception> {
+            <T> T getOption(SocketOption<T> name) throws E;
+        }
+        @FunctionalInterface
+        interface SupportedOption<E extends Exception> {
+            Set<SocketOption<?>> supportedOptions() throws E;
+        }
+        @FunctionalInterface
+        interface Closer<E extends Exception> {
+            void close() throws E;
+        }
+
+        private final R socket;
+        private final SetOption<R, E> setter;
+        private final GetOption<E> getter;
+        private final SupportedOption<E> support;
+        private final Closer<E> closer;
+
+        public ConfigurableImpl(R socket, SetOption<R, E> setter, GetOption<E> getter,
+                                SupportedOption<E> support, Closer<E> closer) {
+            this.socket = socket;
+            this.setter = setter;
+            this.getter = getter;
+            this.support = support;
+            this.closer = closer;
+        }
+
+        @Override
+        public <T> R setOption(SocketOption<T> name, T value) throws E {
+            return setter.setOption(name, value);
+        }
+        @Override
+        public <T> T getOption(SocketOption<T> name) throws E {
+            return getter.getOption(name);
+        }
+        @Override
+        public Set<SocketOption<?>> supportedOptions() throws E {
+            return support.supportedOptions();
+        }
+        @Override
+        public R socket() {
+            return socket;
+        }
+        @Override
+        public void close() throws E {
+            closer.close();
+        }
+    }
+
+
+}