undefect. CWE-407 — 63 sites patched across 27 ecosystems

Authors: russell@unturf.com · brackishbert@gmail.com · foxhop.net · TimeHexOn.com

Patches, unit tests, benchmarks, whitepaper, and outreach briefs.
Public domain — no copyright claimed. Use freely.
This commit is contained in:
russell@unturf.com 2026-03-26 17:11:57 -04:00
commit 0a580b313d
70422 changed files with 17213626 additions and 0 deletions

View file

@ -0,0 +1,398 @@
/*
* Copyright (c) 2019, 2021, 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.
*/
/*
* @test
* @bug 8224477
* @summary Ensures that IOException is thrown after the socket is closed
* @run testng AfterClose
*/
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.DatagramSocket;
import java.net.MulticastSocket;
import java.net.NetworkInterface;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.net.SocketOption;
import java.nio.channels.DatagramChannel;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static java.lang.Boolean.*;
import static java.net.StandardSocketOptions.*;
import static org.testng.Assert.expectThrows;
public class AfterClose {
static final Class<IOException> IOE = IOException.class;
static final String RO = "READ_ONLY";
static Map<SocketOption<?>,List<Object>> OPTION_VALUES_MAP = optionValueMap();
static boolean supportsMulticast(NetworkInterface ni) {
try {
return ni.supportsMulticast();
} catch (SocketException e) {
return false;
}
}
static List<Object> listNetworkInterfaces() {
try {
return NetworkInterface.networkInterfaces()
.filter(AfterClose::supportsMulticast)
.collect(Collectors.toList());
} catch (Exception e) { }
return List.of();
}
static Map<SocketOption<?>,List<Object>> optionValueMap() {
Map<SocketOption<?>,List<Object>> map = new HashMap<>();
map.put(IP_MULTICAST_IF, listNetworkInterfaces() );
map.put(IP_MULTICAST_LOOP, listOf(TRUE, FALSE) );
map.put(IP_MULTICAST_TTL, listOf(0, 100, 255) );
map.put(IP_TOS, listOf(0, 101, 255) );
map.put(SO_BROADCAST, listOf(TRUE, FALSE) );
map.put(SO_KEEPALIVE, listOf(TRUE, FALSE) );
map.put(SO_LINGER, listOf(0, 5, 15) );
map.put(SO_RCVBUF, listOf(1, 100, 1000));
map.put(SO_REUSEADDR, listOf(TRUE, FALSE) );
map.put(SO_REUSEPORT, listOf(TRUE, FALSE) );
map.put(SO_SNDBUF, listOf(1, 100, 1000));
map.put(TCP_NODELAY, listOf(TRUE, FALSE) );
// extended options
try {
Class<?> c = Class.forName("jdk.net.ExtendedSocketOptions");
Field field = c.getField("TCP_QUICKACK");
map.put((SocketOption<?>)field.get(null), listOf(TRUE, FALSE));
field = c.getField("TCP_KEEPIDLE");
map.put((SocketOption<?>)field.get(null), listOf(10, 100));
field = c.getField("TCP_KEEPINTERVAL");
map.put((SocketOption<?>)field.get(null), listOf(10, 100));
field = c.getField("TCP_KEEPCOUNT");
map.put((SocketOption<?>)field.get(null), listOf(10, 100));
field = c.getField("SO_INCOMING_NAPI_ID");
map.put((SocketOption<?>)field.get(null), listOf(RO));
field = c.getField("IP_DONTFRAGMENT");
map.put((SocketOption<?>)field.get(null), listOf(TRUE, FALSE));
} catch (ClassNotFoundException e) {
// ignore, jdk.net module not present
} catch (ReflectiveOperationException e) {
throw new AssertionError(e);
}
return map;
}
// -- Socket
@DataProvider(name = "socketOptionValues")
public Object[][] socketOptionValues() throws Exception {
try (Socket s = new Socket()) {
return s.supportedOptions().stream()
.map(so -> new Object[] {so, OPTION_VALUES_MAP.get(so)})
.toArray(Object[][]::new);
}
}
@Test(dataProvider = "socketOptionValues")
public <T> void closedSocketImplUncreated(SocketOption<T> option, List<T> values)
throws IOException
{
Socket socket = createClosedSocketImplUncreated();
for (int i=0; i<3; i++); {
for (T value : values) {
expectThrows(IOE, () -> socket.setOption(option, value));
expectThrows(IOE, () -> socket.getOption(option));
}
}
}
@Test(dataProvider = "socketOptionValues")
public <T> void closedSocketImplCreated(SocketOption<T> option, List<T> values)
throws IOException
{
Socket socket = createClosedSocketImplCreated();
for (int i=0; i<3; i++); {
for (T value : values) {
expectThrows(IOE, () -> socket.setOption(option, value));
expectThrows(IOE, () -> socket.getOption(option));
}
}
}
@Test(dataProvider = "socketOptionValues")
public <T> void closedSocketAdapter(SocketOption<T> option, List<T> values)
throws IOException
{
Socket socket = createClosedSocketFromAdapter();
for (int i=0; i<3; i++); {
for (T value : values) {
if (!RO.equals(value)) expectThrows(IOE, () -> socket.setOption(option, value));
expectThrows(IOE, () -> socket.getOption(option));
}
}
}
// -- ServerSocket
@DataProvider(name = "serverSocketOptionValues")
public Object[][] serverSocketOptionValues() throws Exception {
try (ServerSocket ss = new ServerSocket()) {
return ss.supportedOptions().stream()
.map(so -> new Object[] {so, OPTION_VALUES_MAP.get(so)})
.toArray(Object[][]::new);
}
}
@Test(dataProvider = "serverSocketOptionValues")
public <T> void closedServerSocketImplUncreated(SocketOption<T> option, List<T> values)
throws IOException
{
ServerSocket serverSocket = createClosedServerSocketImplUncreated();
for (int i=0; i<3; i++); {
for (T value : values) {
expectThrows(IOE, () -> serverSocket.setOption(option, value));
expectThrows(IOE, () -> serverSocket.getOption(option));
}
}
}
@Test(dataProvider = "serverSocketOptionValues")
public <T> void closedServerSocketImplCreated(SocketOption<T> option, List<T> values)
throws IOException
{
ServerSocket serverSocket = createClosedServerSocketImplCreated();
for (int i=0; i<3; i++); {
for (T value : values) {
expectThrows(IOE, () -> serverSocket.setOption(option, value));
expectThrows(IOE, () -> serverSocket.getOption(option));
}
}
}
@Test(dataProvider = "serverSocketOptionValues")
public <T> void closedServerSocketAdapter(SocketOption<T> option, List<T> values)
throws IOException
{
if (option == IP_TOS)
return; // SSC does not support IP_TOS
ServerSocket serverSocket = createClosedServerSocketFromAdapter();
for (int i=0; i<3; i++); {
for (T value : values) {
if (!RO.equals(value)) expectThrows(IOE, () -> serverSocket.setOption(option, value));
expectThrows(IOE, () -> serverSocket.getOption(option));
}
}
}
// -- DatagramSocket
@DataProvider(name = "datagramSocketOptionValues")
public Object[][] datagramSocketOptionValues() throws Exception {
try (DatagramSocket ds = new DatagramSocket()) {
return ds.supportedOptions().stream()
.map(so -> new Object[] {so, OPTION_VALUES_MAP.get(so)})
.toArray(Object[][]::new);
}
}
@Test(dataProvider = "datagramSocketOptionValues")
public <T> void closedUnboundDatagramSocket(SocketOption<T> option, List<T> values)
throws IOException
{
DatagramSocket datagramSocket = createClosedUnboundDatagramSocket();
for (int i=0; i<3; i++); {
for (T value : values) {
if (!RO.equals(value)) expectThrows(IOE, () -> datagramSocket.setOption(option, value));
expectThrows(IOE, () -> datagramSocket.getOption(option));
}
}
}
@Test(dataProvider = "datagramSocketOptionValues")
public <T> void closedBoundDatagramSocket(SocketOption<T> option, List<T> values)
throws IOException
{
DatagramSocket datagramSocket = createClosedBoundDatagramSocket();
for (int i=0; i<3; i++); {
for (T value : values) {
if (!RO.equals(value)) expectThrows(IOE, () -> datagramSocket.setOption(option, value));
expectThrows(IOE, () -> datagramSocket.getOption(option));
}
}
}
@Test(dataProvider = "datagramSocketOptionValues")
public <T> void closedDatagramAdapter(SocketOption<T> option, List<T> values)
throws IOException
{
DatagramSocket datagramSocket = createClosedBoundDatagramSocket();
for (int i=0; i<3; i++); {
for (T value : values) {
if (!RO.equals(value)) expectThrows(IOE, () -> datagramSocket.setOption(option, value));
expectThrows(IOE, () -> datagramSocket.getOption(option));
}
}
}
// -- MulticastSocket
@DataProvider(name = "multicastSocketOptionValues")
public Object[][] multicastSocketOptionValues() throws Exception {
try (MulticastSocket ms = new MulticastSocket()) {
return ms.supportedOptions().stream()
.map(so -> new Object[] {so, OPTION_VALUES_MAP.get(so)})
.toArray(Object[][]::new);
}
}
@Test(dataProvider = "multicastSocketOptionValues")
public <T> void closedUnboundMulticastSocket(SocketOption<T> option, List<T> values)
throws IOException
{
MulticastSocket multicastSocket = createClosedUnboundMulticastSocket();
for (int i=0; i<3; i++); {
for (T value : values) {
if (!RO.equals(value)) expectThrows(IOE, () -> multicastSocket.setOption(option, value));
expectThrows(IOE, () -> multicastSocket.getOption(option));
}
}
}
@Test(dataProvider = "multicastSocketOptionValues")
public <T> void closedBoundMulticastSocket(SocketOption<T> option, List<T> values)
throws IOException
{
MulticastSocket multicastSocket = createClosedBoundMulticastSocket();
for (int i=0; i<3; i++); {
for (T value : values) {
if (!RO.equals(value)) expectThrows(IOE, () -> multicastSocket.setOption(option, value));
expectThrows(IOE, () -> multicastSocket.getOption(option));
}
}
}
// --
static List<Object> listOf(Object... objs) {
List<Object> l = new ArrayList<>();
Arrays.stream(objs).forEachOrdered(l::add);
return l;
}
// Returns a closed Socket that has an impl whose `create` method has NOT been invoked.
static Socket createClosedSocketImplUncreated() throws IOException {
Socket s = new Socket();
s.close();
return s;
}
// Returns a closed Socket that has an impl whose `create` method has been invoked.
static Socket createClosedSocketImplCreated() throws IOException {
Socket s = new Socket();
s.bind(null); // binding causes impl::create to be invoked
s.close();
return s;
}
// Returns a closed Socket created from a SocketChannel's adapter.
static Socket createClosedSocketFromAdapter() throws IOException {
SocketChannel sc = SocketChannel.open();
sc.close();
return sc.socket();
}
// Returns a closed ServerSocket that has an impl whose `create` method has NOT been invoked.
static ServerSocket createClosedServerSocketImplUncreated() throws IOException {
ServerSocket ss = new ServerSocket();
ss.close();
return ss;
}
// Returns a closed ServerSocket that has an impl whose `create` method has been invoked.
static ServerSocket createClosedServerSocketImplCreated() throws IOException {
ServerSocket ss = new ServerSocket();
ss.bind(null); // binding causes impl::create to be invoked
ss.close();
return ss;
}
// Returns a closed ServerSocket created from a ServerSocketChannel's adapter.
static ServerSocket createClosedServerSocketFromAdapter() throws IOException {
ServerSocketChannel ssc = ServerSocketChannel.open();
ssc.close();
return ssc.socket();
}
// Returns a closed unbound DatagramSocket.
static DatagramSocket createClosedUnboundDatagramSocket() throws IOException {
DatagramSocket ds = new DatagramSocket(null);
assert ds.isBound() == false;
ds.close();
return ds;
}
// Returns a closed bound DatagramSocket.
static DatagramSocket createClosedBoundDatagramSocket() throws IOException {
DatagramSocket ds = new DatagramSocket();
assert ds.isBound() == true;
ds.close();
return ds;
}
// Returns a closed DatagramSocket that created from a DatagramChannel's adapter.
static DatagramSocket createClosedDatagramSocketFromAdapter() throws IOException {
DatagramChannel dc = DatagramChannel.open();
dc.close();
return dc.socket();
}
// Returns a closed unbound MulticastSocket.
static MulticastSocket createClosedUnboundMulticastSocket() throws IOException {
MulticastSocket ms = new MulticastSocket(null);
assert ms.isBound() == false;
ms.close();
return ms;
}
// Returns a closed bound MulticastSocket.
static MulticastSocket createClosedBoundMulticastSocket() throws IOException {
MulticastSocket ms = new MulticastSocket();
assert ms.isBound() == true;
ms.close();
return ms;
}
}

View file

@ -0,0 +1,229 @@
/*
* Copyright (c) 2020, 2025, 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.
*/
/*
* @test
* @bug 8241988
* @summary Checks that the caching of options does not affect other impls
* @run testng/othervm CachedImplOptions
* @run testng/othervm -Djava.net.preferIPv4Stack=true CachedImplOptions
*/
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.DatagramSocketImpl;
import java.net.MulticastSocket;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.SocketException;
import java.net.SocketImpl;
import java.net.SocketOption;
import java.net.StandardSocketOptions;
import java.util.Set;
import org.testng.annotations.Test;
import static org.testng.Assert.*;
public class CachedImplOptions {
@Test
public void testDatagramSocket() throws IOException {
try (var impl = new DatagramSocket()) {
assertTrue(impl.supportedOptions().contains(StandardSocketOptions.SO_SNDBUF));
assertTrue(impl.supportedOptions().contains(StandardSocketOptions.SO_SNDBUF));
}
try (var impl = new DatagramSocket(new FooDatagramSocketImpl()) {}) {
assertEquals(impl.supportedOptions(), Set.of(FooDatagramSocketImpl.FOO_OPTION));
assertEquals(impl.supportedOptions(), Set.of(FooDatagramSocketImpl.FOO_OPTION));
}
try (var impl = new DatagramSocket(new BarDatagramSocketImpl()) {}) {
assertEquals(impl.supportedOptions(), Set.of(BarDatagramSocketImpl.BAR_OPTION));
assertEquals(impl.supportedOptions(), Set.of(BarDatagramSocketImpl.BAR_OPTION));
}
try (var impl = new DatagramSocket(new BazDatagramSocketImpl()) {}) {
assertEquals(impl.supportedOptions(), Set.of(BazDatagramSocketImpl.BAZ_OPTION));
assertEquals(impl.supportedOptions(), Set.of(BazDatagramSocketImpl.BAZ_OPTION));
}
try (var impl = new DatagramSocket()) {
assertTrue(impl.supportedOptions().contains(StandardSocketOptions.SO_SNDBUF));
assertTrue(impl.supportedOptions().contains(StandardSocketOptions.SO_SNDBUF));
}
}
@Test
public void testMulticastSocket() throws IOException {
try (var impl = new MulticastSocket()) {
assertTrue(impl.supportedOptions().contains(StandardSocketOptions.SO_SNDBUF));
assertTrue(impl.supportedOptions().contains(StandardSocketOptions.SO_SNDBUF));
}
// Use the factory to inject an alternative impl
DatagramSocket.setDatagramSocketImplFactory(() -> new FooDatagramSocketImpl());
try (var impl = new MulticastSocket()) {
assertEquals(impl.supportedOptions(), Set.of(FooDatagramSocketImpl.FOO_OPTION));
assertEquals(impl.supportedOptions(), Set.of(FooDatagramSocketImpl.FOO_OPTION));
}
}
static class FooDatagramSocketImpl extends AbstractDatagramSocketImpl {
public static final SocketOption<Boolean> FOO_OPTION = new SocketOption<>() {
@Override public String name() { return "FOO_OPTION"; }
@Override public Class<Boolean> type() { return Boolean.class; }
};
@Override public Set<SocketOption<?>> supportedOptions() { return Set.of(FOO_OPTION); }
}
static class BarDatagramSocketImpl extends AbstractDatagramSocketImpl {
public static final SocketOption<Integer> BAR_OPTION = new SocketOption<>() {
@Override public String name() { return "BAR_OPTION"; }
@Override public Class<Integer> type() { return Integer.class; }
};
@Override public Set<SocketOption<?>> supportedOptions() { return Set.of(BAR_OPTION); }
}
static class BazDatagramSocketImpl extends AbstractDatagramSocketImpl {
public static final SocketOption<Long> BAZ_OPTION = new SocketOption<>() {
@Override public String name() { return "BAZ_OPTION"; }
@Override public Class<Long> type() { return Long.class; }
};
@Override public Set<SocketOption<?>> supportedOptions() { return Set.of(BAZ_OPTION); }
}
static abstract class AbstractDatagramSocketImpl extends DatagramSocketImpl {
@Override public Set<SocketOption<?>> supportedOptions() { return null; }
@Override protected void create() throws SocketException { }
@Override protected void bind(int lport, InetAddress laddr){ }
@Override protected void send(DatagramPacket p) { }
@Override protected int peek(InetAddress i) { return 0; }
@Override protected int peekData(DatagramPacket p) { return 0; }
@Override protected void receive(DatagramPacket p) { }
@Override protected void setTimeToLive(int ttl) { }
@Override protected int getTimeToLive() { return 0; }
@Override protected void join(InetAddress inetaddr) { }
@Override protected void leave(InetAddress inetaddr) { }
@Override protected void joinGroup(SocketAddress x, NetworkInterface y) { }
@Override protected void leaveGroup(SocketAddress x, NetworkInterface y) { }
@Override protected void close() { }
@Override public void setOption(int optID, Object value) { }
@Override public Object getOption(int optID) { return null; }
}
// -- socket
@Test
public void testSocket() throws IOException {
try (var impl = new Socket()) {
assertTrue(impl.supportedOptions().contains(StandardSocketOptions.SO_SNDBUF));
assertTrue(impl.supportedOptions().contains(StandardSocketOptions.SO_SNDBUF));
}
try (var impl = new Socket(new LarrySocketImpl()) {}) {
assertEquals(impl.supportedOptions(), Set.of(LarrySocketImpl.LARRY_OPTION));
assertEquals(impl.supportedOptions(), Set.of(LarrySocketImpl.LARRY_OPTION));
}
try (var impl = new Socket(new CurlySocketImpl()) {}) {
assertEquals(impl.supportedOptions(), Set.of(CurlySocketImpl.CURLY_OPTION));
assertEquals(impl.supportedOptions(), Set.of(CurlySocketImpl.CURLY_OPTION));
}
try (var impl = new Socket(new MoeSocketImpl()) {}) {
assertEquals(impl.supportedOptions(), Set.of(MoeSocketImpl.MOE_OPTION));
assertEquals(impl.supportedOptions(), Set.of(MoeSocketImpl.MOE_OPTION));
}
try (var impl = new Socket()) {
assertTrue(impl.supportedOptions().contains(StandardSocketOptions.SO_SNDBUF));
assertTrue(impl.supportedOptions().contains(StandardSocketOptions.SO_SNDBUF));
}
}
@Test
public void testServerSocket() throws IOException {
try (var impl = new ServerSocket()) {
assertTrue(impl.supportedOptions().contains(StandardSocketOptions.SO_RCVBUF));
assertTrue(impl.supportedOptions().contains(StandardSocketOptions.SO_RCVBUF));
}
try (var impl = new ServerSocket(new LarrySocketImpl()) {}) {
assertEquals(impl.supportedOptions(), Set.of(LarrySocketImpl.LARRY_OPTION));
assertEquals(impl.supportedOptions(), Set.of(LarrySocketImpl.LARRY_OPTION));
}
try (var impl = new ServerSocket(new CurlySocketImpl()) {}) {
assertEquals(impl.supportedOptions(), Set.of(CurlySocketImpl.CURLY_OPTION));
assertEquals(impl.supportedOptions(), Set.of(CurlySocketImpl.CURLY_OPTION));
}
try (var impl = new ServerSocket(new MoeSocketImpl()) {}) {
assertEquals(impl.supportedOptions(), Set.of(MoeSocketImpl.MOE_OPTION));
assertEquals(impl.supportedOptions(), Set.of(MoeSocketImpl.MOE_OPTION));
}
try (var impl = new ServerSocket()) {
assertTrue(impl.supportedOptions().contains(StandardSocketOptions.SO_RCVBUF));
assertTrue(impl.supportedOptions().contains(StandardSocketOptions.SO_RCVBUF));
}
}
static class LarrySocketImpl extends AbstractSocketImpl {
public static final SocketOption<Boolean> LARRY_OPTION = new SocketOption<>() {
@Override public String name() { return "LARRY_OPTION"; }
@Override public Class<Boolean> type() { return Boolean.class; }
};
@Override public Set<SocketOption<?>> supportedOptions() { return Set.of(LARRY_OPTION); }
}
static class CurlySocketImpl extends AbstractSocketImpl {
public static final SocketOption<Integer> CURLY_OPTION = new SocketOption<>() {
@Override public String name() { return "CURLY_OPTION"; }
@Override public Class<Integer> type() { return Integer.class; }
};
@Override public Set<SocketOption<?>> supportedOptions() { return Set.of(CURLY_OPTION); }
}
static class MoeSocketImpl extends AbstractSocketImpl {
public static final SocketOption<Long> MOE_OPTION = new SocketOption<>() {
@Override public String name() { return "MOE_OPTION"; }
@Override public Class<Long> type() { return Long.class; }
};
@Override public Set<SocketOption<?>> supportedOptions() { return Set.of(MOE_OPTION); }
}
static abstract class AbstractSocketImpl extends SocketImpl {
@Override protected void create(boolean stream) { }
@Override protected void connect(String host, int port) { }
@Override protected void connect(InetAddress address, int port) { }
@Override protected void connect(SocketAddress address, int timeout) { }
@Override protected void bind(InetAddress host, int port) { }
@Override protected void listen(int backlog) { }
@Override protected void accept(SocketImpl s) { }
@Override protected InputStream getInputStream() { return null; }
@Override protected OutputStream getOutputStream() { return null; }
@Override protected int available() { return 0; }
@Override protected void close() { }
@Override protected void sendUrgentData(int data) { }
@Override public void setOption(int optID, Object value) { }
@Override public Object getOption(int optID) { return null; }
}
}

View file

@ -0,0 +1,185 @@
/*
* Copyright (c) 2016, 2025, 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.
*/
/*
* @test
* @bug 8148609
* @library /test/lib
* @summary Assert that the set of socket options are immutable
* @run testng/othervm ImmutableOptions
* @run testng/othervm -Djava.net.preferIPv4Stack=true ImmutableOptions
*/
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.*;
import java.util.Set;
import jdk.test.lib.net.IPSupport;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
public class ImmutableOptions {
@BeforeTest
void setupServerSocketFactory() throws IOException {
IPSupport.throwSkippedExceptionIfNonOperational();
ServerSocket.setSocketFactory(new ServerSocketImplFactory());
}
@Test(expectedExceptions = UnsupportedOperationException.class)
public void socketThrows() throws IOException {
CustomSocketImpl impl = new CustomSocketImpl();
Socket socket = new CustomSocket(impl);
socket.supportedOptions().clear();
}
@Test(expectedExceptions = UnsupportedOperationException.class)
public void socketImplThrows() throws IOException {
CustomSocketImpl impl = new CustomSocketImpl();
impl.supportedOptions().clear();
}
@Test(expectedExceptions = UnsupportedOperationException.class)
public void serverSocketThrows() throws IOException {
ServerSocket ss = new ServerSocket();
ss.supportedOptions().clear();
}
@Test(expectedExceptions = UnsupportedOperationException.class)
public void serverSocketImplThrows() throws IOException {
ServerSocket ss = new ServerSocket();
ServerSocketImplFactory.mostRecentlyCreated.supportedOptions().clear();
}
@Test(expectedExceptions = UnsupportedOperationException.class)
public void datagramSocketThrows() throws IOException {
CustomDatagramSocketImpl impl = new CustomDatagramSocketImpl();
DatagramSocket socket = new CustomDatagramSocket(impl);
socket.supportedOptions().clear();
}
@Test(expectedExceptions = UnsupportedOperationException.class)
public void datagramSocketImplThrows() throws IOException {
CustomDatagramSocketImpl impl = new CustomDatagramSocketImpl();
impl.supportedOptions().clear();
}
// Socket descendants
static class CustomSocket extends Socket {
public CustomSocket(SocketImpl impl) throws IOException {
super(impl);
}
}
static class CustomDatagramSocket extends DatagramSocket {
public CustomDatagramSocket(DatagramSocketImpl impl) {
super(impl);
}
}
static class ServerSocketImplFactory implements SocketImplFactory {
static volatile CustomSocketImpl mostRecentlyCreated;
@Override public SocketImpl createSocketImpl() {
return mostRecentlyCreated = new CustomSocketImpl();
}
}
// Custom impl's
static class CustomSocketImpl extends SocketImpl {
// The only method interesting to this test.
@Override public Set<SocketOption<?>> supportedOptions() {
return super.supportedOptions();
}
public void create(boolean stream) throws IOException { }
public void connect(String host, int port) throws IOException { }
public void connect(InetAddress addr, int port) throws IOException { }
public void connect(SocketAddress addr, int timeout) throws IOException { }
public void bind(InetAddress host, int port) throws IOException { }
public void listen(int backlog) throws IOException { }
public void accept(SocketImpl s) throws IOException { }
public InputStream getInputStream() throws IOException { return null; }
public OutputStream getOutputStream() throws IOException { return null; }
public int available() throws IOException { return 0; }
public void close() throws IOException { }
public void sendUrgentData(int data) throws IOException { }
public Object getOption(int i) throws SocketException { return null; }
public void setOption(int i, Object o) throws SocketException { }
}
static class CustomDatagramSocketImpl extends DatagramSocketImpl {
// The only method interesting to this test.
@Override public Set<SocketOption<?>> supportedOptions() {
return super.supportedOptions();
}
protected void create() throws SocketException { }
protected void bind(int lport, InetAddress laddr) throws SocketException { }
protected void send(DatagramPacket p) throws IOException { }
protected int peek(InetAddress i) throws IOException { return 0; }
protected int peekData(DatagramPacket p) throws IOException { return 0; }
protected void receive(DatagramPacket p) throws IOException { }
protected void setTimeToLive(int ttl) throws IOException { }
protected int getTimeToLive() throws IOException { return 0; }
protected void join(InetAddress inetaddr) throws IOException { }
protected void leave(InetAddress inetaddr) throws IOException { }
protected void joinGroup(SocketAddress x, NetworkInterface y)
throws IOException { }
protected void leaveGroup(SocketAddress x, NetworkInterface y)
throws IOException { }
protected void close() { }
public void setOption(int optID, Object value) throws SocketException { }
public Object getOption(int optID) throws SocketException { return null; }
}
}

View file

@ -0,0 +1,62 @@
/*
* Copyright (c) 2016, 2018, 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.
*/
/*
* @test
* @library /test/lib
* @bug 8170920
* @run main MinimumRcvBufferSize
* @run main/othervm -Djava.net.preferIPv4Stack=true MinimumRcvBufferSize
*/
import java.nio.channels.*;
import java.net.*;
import jdk.test.lib.net.IPSupport;
public class MinimumRcvBufferSize {
public static void main(String args[]) throws Exception {
IPSupport.throwSkippedExceptionIfNonOperational();
boolean error = false;
ServerSocketChannel channel = ServerSocketChannel.open();
int before = channel.getOption(StandardSocketOptions.SO_RCVBUF);
channel.setOption(StandardSocketOptions.SO_RCVBUF, Integer.MAX_VALUE);
int after = channel.getOption(StandardSocketOptions.SO_RCVBUF);
if (before > after) {
System.err.println("Test failed: SO_RCVBUF");
error = true;
}
SocketChannel channel1 = SocketChannel.open();
before = channel1.getOption(StandardSocketOptions.SO_SNDBUF);
channel1.setOption(StandardSocketOptions.SO_SNDBUF, Integer.MAX_VALUE);
after = channel1.getOption(StandardSocketOptions.SO_SNDBUF);
if (before > after) {
System.err.println("Test failed: SO_SNDBUF");
error = true;
}
if (error)
throw new RuntimeException("Test failed");
}
}

View file

@ -0,0 +1,331 @@
/*
* Copyright (c) 2019, 2021, 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.
*/
/*
* @test
* @bug 8224477
* @summary Basic test for NPE, UOE, and IAE for get/setOption
* @run testng NullsAndBadValues
* @run testng/othervm -Dsun.net.useExclusiveBind=false NullsAndBadValues
*/
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.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static java.lang.Boolean.*;
import static java.net.StandardSocketOptions.*;
import static org.testng.Assert.expectThrows;
public class NullsAndBadValues {
static final Class<NullPointerException> NPE = NullPointerException.class;
static final Class<IllegalArgumentException> IAE = IllegalArgumentException.class;
static final Class<UnsupportedOperationException> UOE = UnsupportedOperationException.class;
@Test
public void nulls() throws Exception {
try (Socket s = new Socket()) {
expectThrows(NPE, () -> s.setOption(null, null));
expectThrows(NPE, () -> s.setOption(null, ""));
expectThrows(NPE, () -> s.setOption(null, 1));
expectThrows(NPE, () -> s.getOption(null));
}
try (ServerSocket ss = new ServerSocket()) {
expectThrows(NPE, () -> ss.setOption(null, null));
expectThrows(NPE, () -> ss.setOption(null, ""));
expectThrows(NPE, () -> ss.setOption(null, 1));
expectThrows(NPE, () -> ss.getOption(null));
}
try (DatagramSocket ds = new DatagramSocket()) {
expectThrows(NPE, () -> ds.setOption(null, null));
expectThrows(NPE, () -> ds.setOption(null, ""));
expectThrows(NPE, () -> ds.setOption(null, 1));
expectThrows(NPE, () -> ds.getOption(null));
}
try (MulticastSocket ms = new MulticastSocket()) {
expectThrows(NPE, () -> ms.setOption(null, null));
expectThrows(NPE, () -> ms.setOption(null, ""));
expectThrows(NPE, () -> ms.setOption(null, 1));
expectThrows(NPE, () -> ms.getOption(null));
}
try (Socket sa = SocketChannel.open().socket()) {
expectThrows(NPE, () -> sa.setOption(null, null));
expectThrows(NPE, () -> sa.setOption(null, ""));
expectThrows(NPE, () -> sa.setOption(null, 1));
expectThrows(NPE, () -> sa.getOption(null));
}
try (ServerSocket ssa = ServerSocketChannel.open().socket()) {
expectThrows(NPE, () -> ssa.setOption(null, null));
expectThrows(NPE, () -> ssa.setOption(null, ""));
expectThrows(NPE, () -> ssa.setOption(null, 1));
expectThrows(NPE, () -> ssa.getOption(null));
}
try (DatagramSocket dsa = DatagramChannel.open().socket()) {
expectThrows(NPE, () -> dsa.setOption(null, null));
expectThrows(NPE, () -> dsa.setOption(null, ""));
expectThrows(NPE, () -> dsa.setOption(null, 1));
expectThrows(NPE, () -> dsa.getOption(null));
}
}
static final SocketOption<Boolean> FAKE_SOCK_OPT = new SocketOption<>() {
@Override public String name() { return "FAKE_SOCK_OPT"; }
@Override public Class<Boolean> type() { return Boolean.class; }
};
static final SocketOption RAW_SOCK_OPT = new SocketOption() {
@Override public String name() { return "RAW_SOCK_OPT"; }
@Override public Class type() { return Boolean.class; }
};
@Test
public void uoe() throws Exception {
try (Socket s = new Socket()) {
expectThrows(UOE, () -> s.setOption(FAKE_SOCK_OPT, null));
expectThrows(UOE, () -> s.setOption(FAKE_SOCK_OPT, TRUE));
expectThrows(UOE, () -> s.setOption(FAKE_SOCK_OPT, FALSE));
expectThrows(UOE, () -> s.setOption(RAW_SOCK_OPT, ""));
expectThrows(UOE, () -> s.setOption(RAW_SOCK_OPT, 1));
expectThrows(UOE, () -> s.getOption(FAKE_SOCK_OPT));
expectThrows(UOE, () -> s.getOption(RAW_SOCK_OPT));
}
try (ServerSocket ss = new ServerSocket()) {
expectThrows(UOE, () -> ss.setOption(FAKE_SOCK_OPT, null));
expectThrows(UOE, () -> ss.setOption(FAKE_SOCK_OPT, TRUE));
expectThrows(UOE, () -> ss.setOption(FAKE_SOCK_OPT, FALSE));
expectThrows(UOE, () -> ss.setOption(RAW_SOCK_OPT, ""));
expectThrows(UOE, () -> ss.setOption(RAW_SOCK_OPT, 1));
expectThrows(UOE, () -> ss.getOption(FAKE_SOCK_OPT));
expectThrows(UOE, () -> ss.getOption(RAW_SOCK_OPT));
}
try (DatagramSocket ds = new DatagramSocket()) {
expectThrows(UOE, () -> ds.setOption(FAKE_SOCK_OPT, null));
expectThrows(UOE, () -> ds.setOption(FAKE_SOCK_OPT, TRUE));
expectThrows(UOE, () -> ds.setOption(FAKE_SOCK_OPT, FALSE));
expectThrows(UOE, () -> ds.setOption(RAW_SOCK_OPT, ""));
expectThrows(UOE, () -> ds.setOption(RAW_SOCK_OPT, 1));
expectThrows(UOE, () -> ds.getOption(FAKE_SOCK_OPT));
expectThrows(UOE, () -> ds.getOption(RAW_SOCK_OPT));
}
try (MulticastSocket ms = new MulticastSocket()) {
expectThrows(UOE, () -> ms.setOption(FAKE_SOCK_OPT, null));
expectThrows(UOE, () -> ms.setOption(FAKE_SOCK_OPT, TRUE));
expectThrows(UOE, () -> ms.setOption(FAKE_SOCK_OPT, FALSE));
expectThrows(UOE, () -> ms.setOption(RAW_SOCK_OPT, ""));
expectThrows(UOE, () -> ms.setOption(RAW_SOCK_OPT, 1));
expectThrows(UOE, () -> ms.getOption(FAKE_SOCK_OPT));
expectThrows(UOE, () -> ms.getOption(RAW_SOCK_OPT));
}
try (Socket sa = SocketChannel.open().socket()) {
expectThrows(UOE, () -> sa.setOption(FAKE_SOCK_OPT, null));
expectThrows(UOE, () -> sa.setOption(FAKE_SOCK_OPT, TRUE));
expectThrows(UOE, () -> sa.setOption(FAKE_SOCK_OPT, FALSE));
expectThrows(UOE, () -> sa.setOption(RAW_SOCK_OPT, ""));
expectThrows(UOE, () -> sa.setOption(RAW_SOCK_OPT, 1));
expectThrows(UOE, () -> sa.getOption(FAKE_SOCK_OPT));
expectThrows(UOE, () -> sa.getOption(RAW_SOCK_OPT));
}
try (ServerSocket ssa = ServerSocketChannel.open().socket()) {
expectThrows(UOE, () -> ssa.setOption(FAKE_SOCK_OPT, null));
expectThrows(UOE, () -> ssa.setOption(FAKE_SOCK_OPT, TRUE));
expectThrows(UOE, () -> ssa.setOption(FAKE_SOCK_OPT, FALSE));
expectThrows(UOE, () -> ssa.setOption(RAW_SOCK_OPT, ""));
expectThrows(UOE, () -> ssa.setOption(RAW_SOCK_OPT, 1));
expectThrows(UOE, () -> ssa.getOption(FAKE_SOCK_OPT));
expectThrows(UOE, () -> ssa.getOption(RAW_SOCK_OPT));
}
try (DatagramSocket dsa = DatagramChannel.open().socket()) {
expectThrows(UOE, () -> dsa.setOption(FAKE_SOCK_OPT, null));
expectThrows(UOE, () -> dsa.setOption(FAKE_SOCK_OPT, TRUE));
expectThrows(UOE, () -> dsa.setOption(FAKE_SOCK_OPT, FALSE));
expectThrows(UOE, () -> dsa.setOption(RAW_SOCK_OPT, ""));
expectThrows(UOE, () -> dsa.setOption(RAW_SOCK_OPT, 1));
expectThrows(UOE, () -> dsa.getOption(FAKE_SOCK_OPT));
expectThrows(UOE, () -> dsa.getOption(RAW_SOCK_OPT));
}
}
static Map<SocketOption<?>,List<Object>> BAD_OPTION_VALUES = badOptionValues();
static Map<SocketOption<?>,List<Object>> badOptionValues() {
Map<SocketOption<?>,List<Object>> map = new HashMap<>();
map.put(IP_MULTICAST_IF, listOf(null) );
map.put(IP_MULTICAST_LOOP, listOf(null) );
map.put(IP_MULTICAST_TTL, listOf(null, -1, 256));
map.put(IP_TOS, listOf(null, -1, 256));
map.put(SO_BROADCAST, listOf(null) );
map.put(SO_KEEPALIVE, listOf(null) );
map.put(SO_LINGER, listOf(null) );
map.put(SO_RCVBUF, listOf(null, -1) );
map.put(SO_REUSEADDR, listOf(null) );
map.put(SO_REUSEPORT, listOf(null) );
map.put(SO_SNDBUF, listOf(null, -1) );
map.put(TCP_NODELAY, listOf(null) );
// extended options, not in the map, will get a null value
return map;
}
// -- Socket
@DataProvider(name = "socketBadOptionValues")
public Object[][] socketBadOptionValues() throws Exception {
try (Socket s = new Socket()) {
return s.supportedOptions().stream()
.flatMap(NullsAndBadValues::socketOptionToBadValues)
.toArray(Object[][]::new);
}
}
@Test(dataProvider = "socketBadOptionValues")
public <T> void socket(SocketOption<T> option, T value)
throws Exception
{
try (Socket s = new Socket()) {
expectThrows(IAE, () -> s.setOption(option, value));
}
}
@Test(dataProvider = "socketBadOptionValues")
public <T> void socketAdapter(SocketOption<T> option, T value)
throws Exception
{
try (Socket s = SocketChannel.open().socket()) {
expectThrows(IAE, () -> s.setOption(option, value));
}
}
// -- ServerSocket
@DataProvider(name = "serverSocketBadOptionValues")
public Object[][] serverSocketBadOptionValues() throws Exception {
try (ServerSocket ss = new ServerSocket()) {
return ss.supportedOptions().stream()
.flatMap(NullsAndBadValues::socketOptionToBadValues)
.toArray(Object[][]::new);
}
}
@Test(dataProvider = "serverSocketBadOptionValues")
public <T> void serverSocket(SocketOption<T> option, T value)
throws Exception
{
try (ServerSocket ss = new ServerSocket()) {
expectThrows(IAE, () -> ss.setOption(option, value));
}
}
@Test(dataProvider = "serverSocketBadOptionValues")
public <T> void serverSocketAdapter(SocketOption<T> option, T value)
throws Exception
{
if (option == IP_TOS)
return; // SSC does not support IP_TOS
try (ServerSocket ss = ServerSocketChannel.open().socket()) {
expectThrows(IAE, () -> ss.setOption(option, value));
}
}
// -- DatagramSocket
@DataProvider(name = "datagramSocketBadOptionValues")
public Object[][] datagramSocketBadOptionValues() throws Exception {
try (DatagramSocket ds = new DatagramSocket()) {
return ds.supportedOptions().stream()
.flatMap(NullsAndBadValues::socketOptionToBadValues)
.toArray(Object[][]::new);
}
}
@Test(dataProvider = "datagramSocketBadOptionValues")
public <T> void datagramSocket(SocketOption<T> option, T value)
throws Exception
{
try (DatagramSocket ds = new DatagramSocket()) {
expectThrows(IAE, () -> ds.setOption(option, value));
}
}
@Test(dataProvider = "datagramSocketBadOptionValues")
public <T> void datagramSocketAdapter(SocketOption<T> option, T value)
throws Exception
{
try (DatagramSocket ds = DatagramChannel.open().socket()) {
expectThrows(IAE, () -> ds.setOption(option, value));
}
}
// -- MulticastSocket
@DataProvider(name = "multicastSocketBadOptionValues")
public Object[][] multicastSocketBadOptionValues() throws Exception {
try (MulticastSocket ms = new MulticastSocket()) {
return ms.supportedOptions().stream()
.flatMap(NullsAndBadValues::socketOptionToBadValues)
.toArray(Object[][]::new);
}
}
@Test(dataProvider = "multicastSocketBadOptionValues")
public <T> void multicastSocket(SocketOption<T> option, T value)
throws Exception
{
try (MulticastSocket ms = new MulticastSocket()) {
expectThrows(IAE, () -> ms.setOption(option, value));
}
}
// --
static List<Object> listOf(Object... objs) {
List<Object> l = new ArrayList<>();
if (objs == null)
l.add(null);
else
Arrays.stream(objs).forEachOrdered(l::add);
return l;
}
static Stream<Object[]> socketOptionToBadValues(SocketOption<?> socketOption) {
List<Object> values = BAD_OPTION_VALUES.get(socketOption);
if (values == null) {
Object[][] a = new Object[][] { new Object[] { socketOption, null } };
return Stream.of(a);
}
return values.stream()
.flatMap(v -> Stream.of(new Object[][] { new Object[] { socketOption, v } }) );
}
}

View file

@ -0,0 +1,351 @@
/*
* Copyright (c) 2014, 2024, 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.
*/
/*
* @test
* @bug 8036979 8072384 8044773 8225214 8233296 8234083
* @library /test/lib
* @requires !vm.graal.enabled
* @run main/othervm -Xcheck:jni OptionsTest
* @run main/othervm -Xcheck:jni -Djava.net.preferIPv4Stack=true OptionsTest
* @run main/othervm --limit-modules=java.base OptionsTest
*/
import java.lang.reflect.Method;
import java.net.*;
import java.util.*;
import jdk.test.lib.NetworkConfiguration;
import jdk.test.lib.net.IPSupport;
public class OptionsTest {
static class Test<T> {
final SocketOption<T> option;
final T value;
Test(SocketOption<T> option, T value) {
this.option = option;
this.value = value;
}
static <T> Test<T> create(SocketOption<T> option, T value) {
return new Test<T>(option, value);
}
}
// The tests set the option using the new API, read back the set value
// which could be different, and then use the legacy get API to check
// these values are the same
static Test<?>[] socketTests = new Test<?>[] {
Test.create(StandardSocketOptions.SO_KEEPALIVE, Boolean.TRUE),
Test.create(StandardSocketOptions.SO_SNDBUF, Integer.valueOf(10 * 100)),
Test.create(StandardSocketOptions.SO_RCVBUF, Integer.valueOf(8 * 100)),
Test.create(StandardSocketOptions.SO_REUSEADDR, Boolean.FALSE),
Test.create(StandardSocketOptions.SO_REUSEPORT, Boolean.FALSE),
Test.create(StandardSocketOptions.SO_LINGER, Integer.valueOf(-1)),
Test.create(StandardSocketOptions.SO_LINGER, Integer.valueOf(0)),
Test.create(StandardSocketOptions.SO_LINGER, Integer.valueOf(80)),
Test.create(StandardSocketOptions.IP_TOS, Integer.valueOf(0)), // lower-bound
Test.create(StandardSocketOptions.IP_TOS, Integer.valueOf(100)),
Test.create(StandardSocketOptions.IP_TOS, Integer.valueOf(255)) //upper-bound
};
static Test<?>[] serverSocketTests = new Test<?>[] {
Test.create(StandardSocketOptions.SO_RCVBUF, Integer.valueOf(8 * 100)),
Test.create(StandardSocketOptions.SO_REUSEADDR, Boolean.FALSE),
Test.create(StandardSocketOptions.SO_REUSEPORT, Boolean.FALSE),
Test.create(StandardSocketOptions.IP_TOS, Integer.valueOf(0)), // lower-bound
Test.create(StandardSocketOptions.IP_TOS, Integer.valueOf(100)),
Test.create(StandardSocketOptions.IP_TOS, Integer.valueOf(255)) //upper-bound
};
static Test<?>[] datagramSocketTests = new Test<?>[] {
Test.create(StandardSocketOptions.SO_SNDBUF, Integer.valueOf(10 * 100)),
Test.create(StandardSocketOptions.SO_RCVBUF, Integer.valueOf(8 * 100)),
Test.create(StandardSocketOptions.SO_REUSEADDR, Boolean.FALSE),
Test.create(StandardSocketOptions.SO_REUSEPORT, Boolean.FALSE),
Test.create(StandardSocketOptions.SO_BROADCAST, Boolean.FALSE),
Test.create(StandardSocketOptions.SO_BROADCAST, Boolean.TRUE),
Test.create(StandardSocketOptions.IP_TOS, Integer.valueOf(0)), // lower-bound
Test.create(StandardSocketOptions.IP_TOS, Integer.valueOf(100)),
Test.create(StandardSocketOptions.IP_TOS, Integer.valueOf(255)) //upper-bound
};
static Test<?>[] multicastSocketTests = new Test<?>[] {
Test.create(StandardSocketOptions.SO_BROADCAST, Boolean.FALSE),
Test.create(StandardSocketOptions.SO_BROADCAST, Boolean.TRUE),
Test.create(StandardSocketOptions.IP_MULTICAST_IF, getNetworkInterface()),
Test.create(StandardSocketOptions.IP_MULTICAST_TTL, Integer.valueOf(0)), // lower-bound
Test.create(StandardSocketOptions.IP_MULTICAST_TTL, Integer.valueOf(10)),
Test.create(StandardSocketOptions.IP_MULTICAST_TTL, Integer.valueOf(255)), //upper-bound
Test.create(StandardSocketOptions.IP_MULTICAST_LOOP, Boolean.TRUE)
};
static NetworkInterface getNetworkInterface() {
try {
NetworkConfiguration nc = NetworkConfiguration.probe();
return nc.multicastInterfaces(true).findAny().orElse(null);
} catch (Exception e) {
}
return null;
}
static boolean okayToTest(Socket s, SocketOption<?> option) {
if (option == StandardSocketOptions.SO_REUSEPORT) {
// skip SO_REUSEPORT if option is not supported
return s.supportedOptions().contains(StandardSocketOptions.SO_REUSEPORT);
}
if (option == StandardSocketOptions.IP_TOS && s.isConnected()) {
// skip IP_TOS if connected
return false;
}
return true;
}
static <T> void testEqual(SocketOption<T> option, T value1, T value2) {
if (!value1.equals(value2)) {
throw new RuntimeException("Test of " + option.name() + " failed: "
+ value1 + " != " + value2);
}
}
static <T> void test(Socket s, Test<T> test) throws Exception {
SocketOption<T> option = test.option;
s.setOption(option, test.value);
T value1 = s.getOption(test.option);
T value2 = (T) legacyGetOption(Socket.class, s, test.option);
testEqual(option, value1, value2);
}
static <T> void test(ServerSocket ss, Test<T> test) throws Exception {
SocketOption<T> option = test.option;
ss.setOption(option, test.value);
T value1 = ss.getOption(test.option);
T value2 = (T) legacyGetOption(ServerSocket.class, ss, test.option);
testEqual(option, value1, value2);
}
static <T> void test(DatagramSocket ds, Test<T> test) throws Exception {
SocketOption<T> option = test.option;
ds.setOption(option, test.value);
T value1 = ds.getOption(test.option);
T value2 = (T) legacyGetOption(ds.getClass(), ds, test.option);
testEqual(option, value1, value2);
}
// Tests default and negative values of SO_LINGER. All negative values should
// retrieve as -1.
static void testSoLingerValues() throws Exception {
try (Socket s = new Socket()) {
// retrieve without set
int defaultValue = s.getOption(StandardSocketOptions.SO_LINGER);
testEqual(StandardSocketOptions.SO_LINGER, -1, defaultValue);
for (int v : List.of(-1, -2, -100, -65534, -65535, -65536, -100000)) {
System.out.println("Testing SO_LINGER with:" + v);
s.setOption(StandardSocketOptions.SO_LINGER, v);
int value = s.getOption(StandardSocketOptions.SO_LINGER);
testEqual(StandardSocketOptions.SO_LINGER, -1, value);
}
}
}
@SuppressWarnings("try")
static void doSocketTests() throws Exception {
// unconnected socket
try (Socket s = new Socket()) {
for (Test<?> test : socketTests) {
if (okayToTest(s, test.option)) {
test(s, test);
}
}
}
// connected socket
try (ServerSocket ss = new ServerSocket()) {
var loopback = InetAddress.getLoopbackAddress();
ss.bind(new InetSocketAddress(loopback, 0));
try (Socket s1 = new Socket()) {
s1.connect(ss.getLocalSocketAddress());
try (Socket s2 = ss.accept()) {
for (Test<?> test : socketTests) {
if (okayToTest(s1, test.option)) {
test(s1, test);
}
}
}
}
}
testSoLingerValues();
}
static void doServerSocketTests() throws Exception {
try (ServerSocket ss = new ServerSocket(0)) {
Set<SocketOption<?>> options = ss.supportedOptions();
boolean reuseport = options.contains(StandardSocketOptions.SO_REUSEPORT);
for (Test<?> test : serverSocketTests) {
if (!(test.option == StandardSocketOptions.SO_REUSEPORT && !reuseport)) {
test(ss, test);
}
}
}
}
static void doDatagramSocketTests() throws Exception {
try (DatagramSocket ds = new DatagramSocket(0)) {
Set<SocketOption<?>> options = ds.supportedOptions();
boolean reuseport = options.contains(StandardSocketOptions.SO_REUSEPORT);
for (Test<?> test : datagramSocketTests) {
if (!(test.option == StandardSocketOptions.SO_REUSEPORT && !reuseport)) {
test(ds, test);
}
}
}
}
static void doMulticastSocketTests() throws Exception {
try (MulticastSocket ms = new MulticastSocket(0)) {
for (Test<?> test : multicastSocketTests) {
test(ms, test);
}
}
}
static Object legacyGetOption(Class<?> type, Object s, Object option) throws Exception {
if (type.equals(Socket.class)) {
Socket socket = (Socket)s;
Set<SocketOption<?>> options = socket.supportedOptions();
boolean reuseport = options.contains(StandardSocketOptions.SO_REUSEPORT);
if (option.equals(StandardSocketOptions.SO_KEEPALIVE)) {
return Boolean.valueOf(socket.getKeepAlive());
} else if (option.equals(StandardSocketOptions.SO_SNDBUF)) {
return Integer.valueOf(socket.getSendBufferSize());
} else if (option.equals(StandardSocketOptions.SO_RCVBUF)) {
return Integer.valueOf(socket.getReceiveBufferSize());
} else if (option.equals(StandardSocketOptions.SO_REUSEADDR)) {
return Boolean.valueOf(socket.getReuseAddress());
} else if (option.equals(StandardSocketOptions.SO_REUSEPORT) && reuseport) {
return Boolean.valueOf(socket.getOption(StandardSocketOptions.SO_REUSEPORT));
} else if (option.equals(StandardSocketOptions.SO_LINGER)) {
return Integer.valueOf(socket.getSoLinger());
} else if (option.equals(StandardSocketOptions.IP_TOS)) {
return Integer.valueOf(socket.getTrafficClass());
} else if (option.equals(StandardSocketOptions.TCP_NODELAY)) {
return Boolean.valueOf(socket.getTcpNoDelay());
} else {
throw new RuntimeException("unexpected socket option");
}
} else if (type.equals(ServerSocket.class)) {
ServerSocket socket = (ServerSocket)s;
Set<SocketOption<?>> options = socket.supportedOptions();
boolean reuseport = options.contains(StandardSocketOptions.SO_REUSEPORT);
if (option.equals(StandardSocketOptions.SO_RCVBUF)) {
return Integer.valueOf(socket.getReceiveBufferSize());
} else if (option.equals(StandardSocketOptions.SO_REUSEADDR)) {
return Boolean.valueOf(socket.getReuseAddress());
} else if (option.equals(StandardSocketOptions.SO_REUSEPORT) && reuseport) {
return Boolean.valueOf(socket.getOption(StandardSocketOptions.SO_REUSEPORT));
} else if (option.equals(StandardSocketOptions.IP_TOS)) {
return getServerSocketTrafficClass(socket);
} else {
throw new RuntimeException("unexpected socket option");
}
} else if (type.equals(DatagramSocket.class)) {
DatagramSocket socket = (DatagramSocket)s;
Set<SocketOption<?>> options = socket.supportedOptions();
boolean reuseport = options.contains(StandardSocketOptions.SO_REUSEPORT);
if (option.equals(StandardSocketOptions.SO_SNDBUF)) {
return Integer.valueOf(socket.getSendBufferSize());
} else if (option.equals(StandardSocketOptions.SO_RCVBUF)) {
return Integer.valueOf(socket.getReceiveBufferSize());
} else if (option.equals(StandardSocketOptions.SO_REUSEADDR)) {
return Boolean.valueOf(socket.getReuseAddress());
} else if (option.equals(StandardSocketOptions.SO_BROADCAST)) {
return Boolean.valueOf(socket.getBroadcast());
} else if (option.equals(StandardSocketOptions.SO_REUSEPORT) && reuseport) {
return Boolean.valueOf(socket.getOption(StandardSocketOptions.SO_REUSEPORT));
} else if (option.equals(StandardSocketOptions.IP_TOS)) {
return Integer.valueOf(socket.getTrafficClass());
} else {
throw new RuntimeException("unexpected socket option");
}
} else if (type.equals(MulticastSocket.class)) {
MulticastSocket socket = (MulticastSocket)s;
Set<SocketOption<?>> options = socket.supportedOptions();
boolean reuseport = options.contains(StandardSocketOptions.SO_REUSEPORT);
if (option.equals(StandardSocketOptions.SO_SNDBUF)) {
return Integer.valueOf(socket.getSendBufferSize());
} else if (option.equals(StandardSocketOptions.SO_RCVBUF)) {
return Integer.valueOf(socket.getReceiveBufferSize());
} else if (option.equals(StandardSocketOptions.SO_REUSEADDR)) {
return Boolean.valueOf(socket.getReuseAddress());
} else if (option.equals(StandardSocketOptions.SO_BROADCAST)) {
return Boolean.valueOf(socket.getBroadcast());
} else if (option.equals(StandardSocketOptions.SO_REUSEPORT) && reuseport) {
return Boolean.valueOf(socket.getOption(StandardSocketOptions.SO_REUSEPORT));
} else if (option.equals(StandardSocketOptions.IP_TOS)) {
return Integer.valueOf(socket.getTrafficClass());
} else if (option.equals(StandardSocketOptions.IP_MULTICAST_IF)) {
return socket.getNetworkInterface();
} else if (option.equals(StandardSocketOptions.IP_MULTICAST_TTL)) {
return Integer.valueOf(socket.getTimeToLive());
} else if (option.equals(StandardSocketOptions.IP_MULTICAST_LOOP)) {
return !Boolean.valueOf(socket.getLoopbackMode());
} else {
throw new RuntimeException("unexpected socket option");
}
}
throw new RuntimeException("unexpected socket type");
}
public static void main(String args[]) throws Exception {
IPSupport.throwSkippedExceptionIfNonOperational();
doSocketTests();
doServerSocketTests();
doDatagramSocketTests();
doMulticastSocketTests();
}
// Reflectively access jdk.net.Sockets.getOption so that the test can run
// without the jdk.net module.
static Object getServerSocketTrafficClass(ServerSocket ss) throws Exception {
try {
Class<?> c = Class.forName("jdk.net.Sockets");
Method m = c.getMethod("getOption", ServerSocket.class, SocketOption.class);
return m.invoke(null, ss, StandardSocketOptions.IP_TOS);
} catch (ClassNotFoundException e) {
// Ok, jdk.net module not present, just fall back
System.out.println("jdk.net module not present, falling back.");
return Integer.valueOf(ss.getOption(StandardSocketOptions.IP_TOS));
} catch (ReflectiveOperationException e) {
throw new AssertionError(e);
}
}
}

View file

@ -0,0 +1,174 @@
/*
* Copyright (c) 2019, 2021, 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 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();
}
}
}

View file

@ -0,0 +1,86 @@
/*
* Copyright (c) 2016, 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.ServerSocket;
import java.net.Socket;
import java.util.Set;
import static java.lang.System.out;
import jdk.test.lib.net.IPSupport;
/*
* @test
* @bug 8143923
* @library /test/lib
* @summary java.net socket supportedOptions set depends on call order
* @run main/othervm SupportedOptionsSet first
* @run main/othervm SupportedOptionsSet second
* @run main/othervm -Djava.net.preferIPv4Stack=true SupportedOptionsSet first
* @run main/othervm -Djava.net.preferIPv4Stack=true 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 {
IPSupport.throwSkippedExceptionIfNonOperational();
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())
{
Set<?> first = s.supportedOptions();
Set<?> second = ss.supportedOptions();
assertNotEqual(first, second,
"Socket and ServerSocket 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())
{
Set<?> first = ss.supportedOptions();
Set<?> second = s.supportedOptions();
assertNotEqual(first, second,
"ServerSocket and Socket 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);
}
}
}

View file

@ -0,0 +1,121 @@
/*
* Copyright (c) 2018, 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.
*/
/*
* @test
* @bug 8194298
* @summary Add support for per Socket configuration of TCP keepalive
* @modules jdk.net
* @run main TcpKeepAliveTest
*/
import java.io.IOException;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.MulticastSocket;
import java.net.ServerSocket;
import java.net.Socket;
import jdk.net.ExtendedSocketOptions;
public class TcpKeepAliveTest {
private static final int DEFAULT_KEEP_ALIVE_PROBES = 7;
private static final int DEFAULT_KEEP_ALIVE_TIME = 1973;
private static final int DEFAULT_KEEP_ALIVE_INTVL = 53;
public static void main(String args[]) throws IOException {
var loopback = InetAddress.getLoopbackAddress();
try (ServerSocket ss = boundServer(loopback);
Socket s = new Socket(loopback, ss.getLocalPort());
DatagramSocket ds = new DatagramSocket(0);
MulticastSocket mc = new MulticastSocket(0)) {
if (ss.supportedOptions().contains(ExtendedSocketOptions.TCP_KEEPIDLE)) {
ss.setOption(ExtendedSocketOptions.TCP_KEEPIDLE, DEFAULT_KEEP_ALIVE_TIME);
if (ss.getOption(ExtendedSocketOptions.TCP_KEEPIDLE) != DEFAULT_KEEP_ALIVE_TIME) {
throw new RuntimeException("Test failed, TCP_KEEPIDLE should have been " + DEFAULT_KEEP_ALIVE_TIME);
}
}
if (ss.supportedOptions().contains(ExtendedSocketOptions.TCP_KEEPCOUNT)) {
ss.setOption(ExtendedSocketOptions.TCP_KEEPCOUNT, DEFAULT_KEEP_ALIVE_PROBES);
if (ss.getOption(ExtendedSocketOptions.TCP_KEEPCOUNT) != DEFAULT_KEEP_ALIVE_PROBES) {
throw new RuntimeException("Test failed, TCP_KEEPCOUNT should have been " + DEFAULT_KEEP_ALIVE_PROBES);
}
}
if (ss.supportedOptions().contains(ExtendedSocketOptions.TCP_KEEPINTERVAL)) {
ss.setOption(ExtendedSocketOptions.TCP_KEEPINTERVAL, DEFAULT_KEEP_ALIVE_INTVL);
if (ss.getOption(ExtendedSocketOptions.TCP_KEEPINTERVAL) != DEFAULT_KEEP_ALIVE_INTVL) {
throw new RuntimeException("Test failed, TCP_KEEPINTERVAL should have been " + DEFAULT_KEEP_ALIVE_INTVL);
}
}
if (s.supportedOptions().contains(ExtendedSocketOptions.TCP_KEEPIDLE)) {
s.setOption(ExtendedSocketOptions.TCP_KEEPIDLE, DEFAULT_KEEP_ALIVE_TIME);
if (s.getOption(ExtendedSocketOptions.TCP_KEEPIDLE) != DEFAULT_KEEP_ALIVE_TIME) {
throw new RuntimeException("Test failed, TCP_KEEPIDLE should have been " + DEFAULT_KEEP_ALIVE_TIME);
}
}
if (s.supportedOptions().contains(ExtendedSocketOptions.TCP_KEEPCOUNT)) {
s.setOption(ExtendedSocketOptions.TCP_KEEPCOUNT, DEFAULT_KEEP_ALIVE_PROBES);
if (s.getOption(ExtendedSocketOptions.TCP_KEEPCOUNT) != DEFAULT_KEEP_ALIVE_PROBES) {
throw new RuntimeException("Test failed, TCP_KEEPCOUNT should have been " + DEFAULT_KEEP_ALIVE_PROBES);
}
}
if (s.supportedOptions().contains(ExtendedSocketOptions.TCP_KEEPINTERVAL)) {
s.setOption(ExtendedSocketOptions.TCP_KEEPINTERVAL, DEFAULT_KEEP_ALIVE_INTVL);
if (s.getOption(ExtendedSocketOptions.TCP_KEEPINTERVAL) != DEFAULT_KEEP_ALIVE_INTVL) {
throw new RuntimeException("Test failed, TCP_KEEPINTERVAL should have been " + DEFAULT_KEEP_ALIVE_INTVL);
}
}
if (ds.supportedOptions().contains(ExtendedSocketOptions.TCP_KEEPCOUNT)) {
throw new RuntimeException("Test failed, TCP_KEEPCOUNT is applicable"
+ " for TCP Sockets only.");
}
if (ds.supportedOptions().contains(ExtendedSocketOptions.TCP_KEEPIDLE)) {
throw new RuntimeException("Test failed, TCP_KEEPIDLE is applicable"
+ " for TCP Sockets only.");
}
if (ds.supportedOptions().contains(ExtendedSocketOptions.TCP_KEEPINTERVAL)) {
throw new RuntimeException("Test failed, TCP_KEEPINTERVAL is applicable"
+ " for TCP Sockets only.");
}
if (mc.supportedOptions().contains(ExtendedSocketOptions.TCP_KEEPCOUNT)) {
throw new RuntimeException("Test failed, TCP_KEEPCOUNT is applicable"
+ " for TCP Sockets only");
}
if (mc.supportedOptions().contains(ExtendedSocketOptions.TCP_KEEPIDLE)) {
throw new RuntimeException("Test failed, TCP_KEEPIDLE is applicable"
+ " for TCP Sockets only");
}
if (mc.supportedOptions().contains(ExtendedSocketOptions.TCP_KEEPINTERVAL)) {
throw new RuntimeException("Test failed, TCP_KEEPINTERVAL is applicable"
+ " for TCP Sockets only");
}
}
}
private static ServerSocket boundServer(InetAddress address) throws IOException {
var socketAddress = new InetSocketAddress(address, 0);
var server = new ServerSocket();
server.bind(socketAddress);
return server;
}
}

View file

@ -0,0 +1,169 @@
/*
* Copyright (c) 2016, 2020, 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.lang.reflect.Field;
import java.net.*;
import java.util.ArrayList;
import java.util.List;
import jdk.test.lib.net.IPSupport;
/*
* @test
* @bug 8143554 8044773
* @library /test/lib
* @summary Test checks that UnsupportedOperationException for unsupported
* SOCKET_OPTIONS is thrown by both getOption() and setOption() methods.
* @requires !vm.graal.enabled
* @run main UnsupportedOptionsTest
* @run main/othervm -Djava.net.preferIPv4Stack=true UnsupportedOptionsTest
* @run main/othervm --limit-modules=java.base UnsupportedOptionsTest
*/
public class UnsupportedOptionsTest {
private static final List<SocketOption<?>> socketOptions = new ArrayList<>();
static {
socketOptions.add(StandardSocketOptions.IP_MULTICAST_IF);
socketOptions.add(StandardSocketOptions.IP_MULTICAST_LOOP);
socketOptions.add(StandardSocketOptions.IP_MULTICAST_TTL);
socketOptions.add(StandardSocketOptions.IP_TOS);
socketOptions.add(StandardSocketOptions.SO_BROADCAST);
socketOptions.add(StandardSocketOptions.SO_KEEPALIVE);
socketOptions.add(StandardSocketOptions.SO_LINGER);
socketOptions.add(StandardSocketOptions.SO_RCVBUF);
socketOptions.add(StandardSocketOptions.SO_REUSEADDR);
socketOptions.add(StandardSocketOptions.SO_SNDBUF);
socketOptions.add(StandardSocketOptions.TCP_NODELAY);
try {
Class<?> c = Class.forName("jdk.net.ExtendedSocketOptions");
Field field = c.getField("TCP_QUICKACK");
socketOptions.add((SocketOption<?>)field.get(null));
field = c.getField("TCP_KEEPIDLE");
socketOptions.add((SocketOption<?>)field.get(null));
field = c.getField("TCP_KEEPINTERVAL");
socketOptions.add((SocketOption<?>)field.get(null));
field = c.getField("TCP_KEEPCOUNT");
socketOptions.add((SocketOption<?>)field.get(null));
} catch (ClassNotFoundException e) {
// ignore, jdk.net module not present
} catch (ReflectiveOperationException e) {
throw new AssertionError(e);
}
}
public static void main(String[] args) throws IOException {
IPSupport.throwSkippedExceptionIfNonOperational();
Socket s = new Socket();
ServerSocket ss = new ServerSocket();
DatagramSocket ds = new DatagramSocket();
MulticastSocket ms = new MulticastSocket();
for (SocketOption option : socketOptions) {
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");
}
}
}