--- old/src/java.base/share/classes/java/net/DatagramSocket.java 2019-12-02 15:01:43.000000000 +0000 +++ new/src/java.base/share/classes/java/net/DatagramSocket.java 2019-12-02 15:01:43.000000000 +0000 @@ -43,24 +43,69 @@ * any order. * *

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. *

* Example: - * {@code + *

{@code
  *              DatagramSocket s = new DatagramSocket(null);
  *              s.bind(new InetSocketAddress(8888));
- * }
+ * }
* Which is equivalent to: - * {@code + *
{@code
  *              DatagramSocket s = new DatagramSocket(8888);
- * }
+ * }
* Both cases will create a DatagramSocket able to receive broadcasts on * UDP port 8888. * + *

The {@code DatagramSocket} class offers some convenience methods + * (such as {@link #setReuseAddress(boolean) setReuseAddress}) + * to get and set some commonly used options. However, socket options + * can be more generally configured using the + * {@link #setOption(SocketOption,Object) setOption} method. + * A {@code DatagramSocket} supports the following socket options: + *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Socket options
Option NameDescription
{@link java.net.StandardSocketOptions#SO_SNDBUF SO_SNDBUF} The size of the socket send buffer
{@link java.net.StandardSocketOptions#SO_RCVBUF SO_RCVBUF} The size of the socket receive buffer
{@link java.net.StandardSocketOptions#SO_REUSEADDR SO_REUSEADDR} Re-use address
{@link java.net.StandardSocketOptions#SO_BROADCAST SO_BROADCAST} Allow transmission of broadcast datagrams
{@link java.net.StandardSocketOptions#IP_TOS IP_TOS} The Type of Service (ToS) octet in the Internet Protocol (IP) header
+ *
+ * An implementation may also support additional options. In particular an implementation + * may support multicast options 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 --- old/src/java.base/share/classes/java/net/MulticastSocket.java 2019-12-02 15:01:45.000000000 +0000 +++ new/src/java.base/share/classes/java/net/MulticastSocket.java 2019-12-02 15:01:45.000000000 +0000 @@ -78,7 +78,45 @@ * Multiple MulticastSocket's may subscribe to a multicast group * and port concurrently, and they will all receive group datagrams. *

- * Currently applets are not allowed to use multicast sockets. + * + *

The {@code DatagramSocket} and {@code MulticastSocket} classes offer + * some convenience methods (such as {@link DatagramSocket#setReuseAddress(boolean) + * setReuseAddress}) to get and set some commonly used options. However, socket + * options can be more generally configured using the + * {@link #setOption(SocketOption, Object) setOption} method. + * In addition to the socket options supported by + * {@code DatagramSocket}, a + * {@code MulticastSocket} supports the following socket options: + *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Socket options
Option NameDescription
{@link java.net.StandardSocketOptions#IP_MULTICAST_IF IP_MULTICAST_IF} The network interface for Internet Protocol (IP) multicast datagrams
{@link java.net.StandardSocketOptions#IP_MULTICAST_TTL + * IP_MULTICAST_TTL} The time-to-live for Internet Protocol (IP) multicast + * datagrams
{@link java.net.StandardSocketOptions#IP_MULTICAST_LOOP + * IP_MULTICAST_LOOP} Loopback for Internet Protocol (IP) multicast datagrams
+ *
+ * Additional (implementation specific) options may also be supported. * * @author Pavani Diwanji * @since 1.1 --- old/src/java.base/share/classes/java/net/ServerSocket.java 2019-12-02 15:01:47.000000000 +0000 +++ new/src/java.base/share/classes/java/net/ServerSocket.java 2019-12-02 15:01:46.000000000 +0000 @@ -46,6 +46,35 @@ * implementation to configure itself to create sockets * appropriate to the local firewall. * + *

The {@code ServerSocket} class offers some convenience methods + * (such as {@link #setReuseAddress(boolean) setReuseAddress}) + * to get and set some commonly used options. However, socket options + * can be more generally configured using the + * {@link #setOption(SocketOption, Object) setOption} method. + * A {@code ServerSocket} supports the following options: + *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Socket options
Option NameDescription
{@link java.net.StandardSocketOptions#SO_RCVBUF SO_RCVBUF} The size of the socket receive buffer
{@link java.net.StandardSocketOptions#SO_REUSEADDR SO_REUSEADDR} Re-use address
+ *
+ * Additional (implementation specific) options may also be supported. + * * @author unascribed * @see java.net.SocketImpl * @see java.net.ServerSocket#setSocketFactory(java.net.SocketImplFactory) --- old/src/java.base/share/classes/java/net/Socket.java 2019-12-02 15:01:48.000000000 +0000 +++ new/src/java.base/share/classes/java/net/Socket.java 2019-12-02 15:01:48.000000000 +0000 @@ -50,6 +50,52 @@ * can configure itself to create sockets appropriate to the local * firewall. * + *

The {@code Socket} class offers some + * convenience methods (such as {@link #setReuseAddress(boolean) + * setReuseAddress}) to get and set some commonly used options. + * However, socket options can be more generally configured using the + * {@link #setOption(SocketOption, Object) setOption} method. + * A {@code Socket} support the following options: + *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Socket options
Option NameDescription
{@link java.net.StandardSocketOptions#SO_SNDBUF SO_SNDBUF} The size of the socket send buffer
{@link java.net.StandardSocketOptions#SO_RCVBUF SO_RCVBUF} The size of the socket receive buffer
{@link java.net.StandardSocketOptions#SO_KEEPALIVE SO_KEEPALIVE} Keep connection alive
{@link java.net.StandardSocketOptions#SO_REUSEADDR SO_REUSEADDR} Re-use address
{@link java.net.StandardSocketOptions#SO_LINGER SO_LINGER} Linger on close if data is present (when configured in blocking mode + * only)
{@link java.net.StandardSocketOptions#TCP_NODELAY TCP_NODELAY} Disable the Nagle algorithm
+ *
+ * Additional (implementation specific) options may also be supported. + * * @author unascribed * @see java.net.Socket#setSocketImplFactory(java.net.SocketImplFactory) * @see java.net.SocketImpl --- /dev/null 2019-12-02 15:01:50.000000000 +0000 +++ new/test/jdk/java/net/SocketOption/RequiredOptions.java 2019-12-02 15:01:50.000000000 +0000 @@ -0,0 +1,183 @@ +/* + * 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> DATAGRAM_OPTIONS = + Set.of(SO_BROADCAST, SO_SNDBUF, SO_RCVBUF, SO_REUSEADDR, IP_TOS); + static final Set> MULTICAST_OPTIONS = + concat(DATAGRAM_OPTIONS, Set.of(IP_MULTICAST_IF, IP_MULTICAST_LOOP, IP_MULTICAST_TTL)); + static final Set> SOCKET_OPTIONS = + Set.of(SO_KEEPALIVE, SO_LINGER, SO_SNDBUF, SO_RCVBUF, SO_REUSEADDR, TCP_NODELAY); + static final Set> SERVER_OPTIONS = + Set.of(SO_RCVBUF, SO_REUSEADDR); + + static Set> concat(Set> ...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 }, + // Channels + { Configurable.of(DatagramChannel.open()), MULTICAST_OPTIONS }, + { Configurable.of(SocketChannel.open()), SOCKET_OPTIONS }, + { Configurable.of(ServerSocketChannel.open()), 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 + void test(Configurable socket, Set> options) throws E { + try (var s = socket) { + var impl = socket.socket().getClass(); + System.out.println("Testing " + impl + " with " + options); + Set> 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 extends AutoCloseable { + R setOption(SocketOption name, T value) throws E; + T getOption(SocketOption name) throws E; + Set> supportedOptions() throws E; + R socket(); + void close() throws E; + + static Configurable of(DatagramSocket socket) { + return new ConfigurableImpl<>(socket, socket::setOption, + socket::getOption, socket::supportedOptions, socket::close); + } + static Configurable of(NetworkChannel socket) { + return new ConfigurableImpl<>(socket, socket::setOption, + socket::getOption, socket::supportedOptions, socket::close); + } + static Configurable of(Socket socket) { + return new ConfigurableImpl<>(socket, socket::setOption, + socket::getOption, socket::supportedOptions, socket::close); + } + static Configurable of(ServerSocket socket) { + return new ConfigurableImpl<>(socket, socket::setOption, + socket::getOption, socket::supportedOptions, socket::close); + } + } + + static final class ConfigurableImpl implements Configurable { + @FunctionalInterface + interface SetOption { + R setOption(SocketOption name, T value) throws E; + } + @FunctionalInterface + interface GetOption { + T getOption(SocketOption name) throws E; + } + @FunctionalInterface + interface SupportedOption { + Set> supportedOptions() throws E; + } + @FunctionalInterface + interface Closer { + void close() throws E; + } + + private final R socket; + private final SetOption setter; + private final GetOption getter; + private final SupportedOption support; + private final Closer closer; + + public ConfigurableImpl(R socket, SetOption setter, GetOption getter, + SupportedOption support, Closer closer) { + this.socket = socket; + this.setter = setter; + this.getter = getter; + this.support = support; + this.closer = closer; + } + + @Override + public R setOption(SocketOption name, T value) throws E { + return setter.setOption(name, value); + } + @Override + public T getOption(SocketOption name) throws E { + return getter.getOption(name); + } + @Override + public Set> supportedOptions() throws E { + return support.supportedOptions(); + } + @Override + public R socket() { + return socket; + } + @Override + public void close() throws E { + closer.close(); + } + } + + +}