8235141: Specify the required standard socket options for the socket types in the java.net package
Reviewed-by: alanb, chegar
This commit is contained in:
parent
2c772c7887
commit
7135b5dd9c
@ -43,24 +43,69 @@ import java.util.Collections;
|
||||
* 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
|
||||
|
@ -80,6 +80,46 @@ import java.util.Set;
|
||||
* <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
|
||||
*/
|
||||
|
@ -46,6 +46,35 @@ import sun.net.PlatformSocketImpl;
|
||||
* 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)
|
||||
|
@ -50,6 +50,52 @@ import java.util.Collections;
|
||||
* 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
|
||||
|
175
test/jdk/java/net/SocketOption/RequiredOptions.java
Normal file
175
test/jdk/java/net/SocketOption/RequiredOptions.java
Normal file
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user