8221481: Reimplement the Legacy Socket API

Reviewed-by: michaelm, chegar
This commit is contained in:
Alan Bateman 2019-05-30 07:19:19 +01:00
parent 23be0f0c2a
commit 7e14aeb133
16 changed files with 2442 additions and 159 deletions

View File

@ -25,33 +25,63 @@
package java.net;
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.FileDescriptor;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Objects;
import java.util.Set;
import sun.net.NetProperties;
import sun.net.PlatformSocketImpl;
import sun.nio.ch.NioSocketImpl;
/**
* The abstract class {@code SocketImpl} is a common superclass
* of all classes that actually implement sockets. It is used to
* create both client and server sockets.
* <p>
* A "plain" socket implements these methods exactly as
* described, without attempting to go through a firewall or proxy.
*
* @implNote Client and server sockets created with the {@code Socket} and
* {@code SocketServer} public constructors create a system-default
* {@code SocketImpl}. The JDK historically used a {@code SocketImpl}
* implementation type named "PlainSocketImpl" that has since been replaced by a
* newer implementation. The JDK continues to ship with the older implementation
* to allow code to run that depends on unspecified behavior that differs between
* the old and new implementations. The old implementation will be used if the
* Java virtual machine is started with the system property {@systemProperty
* jdk.net.usePlainSocketImpl} set to use the old implementation. It may also be
* set in the JDK's network configuration file, located in {@code
* ${java.home}/conf/net.properties}. The value of the property is the string
* representation of a boolean. If set without a value then it defaults to {@code
* true}, hence running with {@code -Djdk.net.usePlainSocketImpl} or {@code
* -Djdk.net.usePlainSocketImpl=true} will configure the Java virtual machine
* to use the old implementation. The property and old implementation will be
* removed in a future version.
*
* @author unascribed
* @since 1.0
*/
public abstract class SocketImpl implements SocketOptions {
private static final boolean USE_PLAINSOCKETIMPL = usePlainSocketImpl();
private static boolean usePlainSocketImpl() {
PrivilegedAction<String> pa = () -> NetProperties.get("jdk.net.usePlainSocketImpl");
String s = AccessController.doPrivileged(pa);
return (s != null) && !s.equalsIgnoreCase("false");
}
/**
* Creates an instance of platform's SocketImpl
*/
@SuppressWarnings("unchecked")
static <S extends SocketImpl & PlatformSocketImpl> S createPlatformSocketImpl(boolean server) {
return (S) new PlainSocketImpl(server);
if (USE_PLAINSOCKETIMPL) {
return (S) new PlainSocketImpl(server);
} else {
return (S) new NioSocketImpl(server);
}
}
/**

File diff suppressed because it is too large Load Diff

View File

@ -600,6 +600,9 @@ java/net/DatagramSocket/SendDatagramToBadAddress.java 7143960 macosx-a
java/net/ServerSocket/AcceptInheritHandle.java 8211854 aix-ppc64
java/net/Inet6Address/B6206527.java 8216417 macosx-all
java/net/ipv6tests/B6521014.java 8216417 macosx-all
############################################################################
# jdk_nio
@ -862,6 +865,7 @@ javax/rmi/ssl/SSLSocketParametersTest.sh 8162906 generic-
jdk/jfr/event/io/TestInstrumentation.java 8202142 generic-all
jdk/jfr/api/recording/event/TestPeriod.java 8215890 generic-all
jdk/jfr/event/io/EvilInstrument.java 8221331 generic-all
############################################################################

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 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
@ -27,6 +27,7 @@
* @library /test/lib
* @build jdk.test.lib.net.SimpleSSLContext
* @run main/othervm Test1
* @run main/othervm -Djdk.net.usePlainSocketImpl Test1
* @run main/othervm -Dsun.net.httpserver.maxReqTime=10 Test1
* @run main/othervm -Dsun.net.httpserver.nodelay=true Test1
* @summary Light weight HTTP server

View File

@ -38,6 +38,7 @@
* jdk.test.lib.process.*
* AcceptCauseFileDescriptorLeak
* @run main/othervm AcceptCauseFileDescriptorLeak root
* @run main/othervm -Djdk.net.usePlainSocketImpl AcceptCauseFileDescriptorLeak root
*/
import java.io.IOException;

View File

@ -27,6 +27,7 @@
* @modules java.management java.base/java.io:+open java.base/java.net:+open
* @run main/othervm UnreferencedSockets
* @run main/othervm -Djava.net.preferIPv4Stack=true UnreferencedSockets
* @run main/othervm -Djdk.net.usePlainSocketImpl UnreferencedSockets
* @summary Check that unreferenced sockets are closed
*/

View File

@ -25,6 +25,7 @@
* @test
* @requires os.family != "solaris"
* @run testng ConnectionReset
* @run testng/othervm -Djdk.net.usePlainSocketImpl ConnectionReset
* @summary Test behavior of read and available when a connection is reset
*/

View File

@ -23,9 +23,10 @@
/*
* @test
* @bug 8221481
* @library /test/lib
* @build jdk.test.lib.Utils
* @run testng Timeouts
* @run testng/timeout=180 Timeouts
* @summary Test Socket timeouts
*/
@ -34,12 +35,17 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ConnectException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
@ -54,7 +60,7 @@ public class Timeouts {
* Test timed connect where connection is established
*/
public void testTimedConnect1() throws IOException {
try (ServerSocket ss = new ServerSocket(0)) {
try (ServerSocket ss = boundServerSocket()) {
try (Socket s = new Socket()) {
s.connect(ss.getLocalSocketAddress(), 2000);
}
@ -77,7 +83,7 @@ public class Timeouts {
* Test connect with a timeout of Integer.MAX_VALUE
*/
public void testTimedConnect3() throws IOException {
try (ServerSocket ss = new ServerSocket(0)) {
try (ServerSocket ss = boundServerSocket()) {
try (Socket s = new Socket()) {
s.connect(ss.getLocalSocketAddress(), Integer.MAX_VALUE);
}
@ -88,12 +94,10 @@ public class Timeouts {
* Test connect with a negative timeout.
*/
public void testTimedConnect4() throws IOException {
try (ServerSocket ss = new ServerSocket(0)) {
try (ServerSocket ss = boundServerSocket()) {
try (Socket s = new Socket()) {
try {
s.connect(ss.getLocalSocketAddress(), -1);
assertTrue(false);
} catch (IllegalArgumentException expected) { }
expectThrows(IllegalArgumentException.class,
() -> s.connect(ss.getLocalSocketAddress(), -1));
}
}
}
@ -128,10 +132,10 @@ public class Timeouts {
public void testTimedRead3() throws IOException {
withConnection((s1, s2) -> {
s2.setSoTimeout(2000);
try {
s2.getInputStream().read();
assertTrue(false);
} catch (SocketTimeoutException expected) { }
long startMillis = millisTime();
expectThrows(SocketTimeoutException.class, () -> s2.getInputStream().read());
int timeout = s2.getSoTimeout();
checkDuration(startMillis, timeout-100, timeout+2000);
});
}
@ -141,10 +145,7 @@ public class Timeouts {
public void testTimedRead4() throws IOException {
withConnection((s1, s2) -> {
s2.setSoTimeout(2000);
try {
s2.getInputStream().read();
assertTrue(false);
} catch (SocketTimeoutException e) { }
expectThrows(SocketTimeoutException.class, () -> s2.getInputStream().read());
s1.getOutputStream().write(99);
int b = s2.getInputStream().read();
assertTrue(b == 99);
@ -158,10 +159,7 @@ public class Timeouts {
public void testTimedRead5() throws IOException {
withConnection((s1, s2) -> {
s2.setSoTimeout(2000);
try {
s2.getInputStream().read();
assertTrue(false);
} catch (SocketTimeoutException e) { }
expectThrows(SocketTimeoutException.class, () -> s2.getInputStream().read());
s2.setSoTimeout(30*3000);
scheduleWrite(s1.getOutputStream(), 99, 2000);
int b = s2.getInputStream().read();
@ -175,10 +173,7 @@ public class Timeouts {
public void testTimedRead6() throws IOException {
withConnection((s1, s2) -> {
s2.setSoTimeout(2000);
try {
s2.getInputStream().read();
assertTrue(false);
} catch (SocketTimeoutException e) { }
expectThrows(SocketTimeoutException.class, () -> s2.getInputStream().read());
s1.getOutputStream().write(99);
s2.setSoTimeout(0);
int b = s2.getInputStream().read();
@ -193,10 +188,7 @@ public class Timeouts {
public void testTimedRead7() throws IOException {
withConnection((s1, s2) -> {
s2.setSoTimeout(2000);
try {
s2.getInputStream().read();
assertTrue(false);
} catch (SocketTimeoutException e) { }
expectThrows(SocketTimeoutException.class, () -> s2.getInputStream().read());
scheduleWrite(s1.getOutputStream(), 99, 2000);
s2.setSoTimeout(0);
int b = s2.getInputStream().read();
@ -211,10 +203,7 @@ public class Timeouts {
withConnection((s1, s2) -> {
s2.setSoTimeout(30*1000);
scheduleClose(s2, 2000);
try {
s2.getInputStream().read();
assertTrue(false);
} catch (SocketException expected) { }
expectThrows(SocketException.class, () -> s2.getInputStream().read());
});
}
@ -280,7 +269,7 @@ public class Timeouts {
public void testTimedAccept1() throws IOException {
Socket s1 = null;
Socket s2 = null;
try (ServerSocket ss = new ServerSocket(0)) {
try (ServerSocket ss = boundServerSocket()) {
s1 = new Socket();
s1.connect(ss.getLocalSocketAddress());
ss.setSoTimeout(30*1000);
@ -295,7 +284,7 @@ public class Timeouts {
* Test timed accept where a connection is established after a short delay
*/
public void testTimedAccept2() throws IOException {
try (ServerSocket ss = new ServerSocket(0)) {
try (ServerSocket ss = boundServerSocket()) {
ss.setSoTimeout(30*1000);
scheduleConnect(ss.getLocalSocketAddress(), 2000);
Socket s = ss.accept();
@ -307,13 +296,17 @@ public class Timeouts {
* Test timed accept where the accept times out
*/
public void testTimedAccept3() throws IOException {
try (ServerSocket ss = new ServerSocket(0)) {
try (ServerSocket ss = boundServerSocket()) {
ss.setSoTimeout(2000);
long startMillis = millisTime();
try {
Socket s = ss.accept();
s.close();
assertTrue(false);
} catch (SocketTimeoutException expected) { }
fail();
} catch (SocketTimeoutException expected) {
int timeout = ss.getSoTimeout();
checkDuration(startMillis, timeout-100, timeout+2000);
}
}
}
@ -322,12 +315,12 @@ public class Timeouts {
* previous accept timed out.
*/
public void testTimedAccept4() throws IOException {
try (ServerSocket ss = new ServerSocket(0)) {
try (ServerSocket ss = boundServerSocket()) {
ss.setSoTimeout(2000);
try {
Socket s = ss.accept();
s.close();
assertTrue(false);
fail();
} catch (SocketTimeoutException expected) { }
try (Socket s1 = new Socket()) {
s1.connect(ss.getLocalSocketAddress());
@ -342,12 +335,12 @@ public class Timeouts {
* accept timed out
*/
public void testTimedAccept5() throws IOException {
try (ServerSocket ss = new ServerSocket(0)) {
try (ServerSocket ss = boundServerSocket()) {
ss.setSoTimeout(2000);
try {
Socket s = ss.accept();
s.close();
assertTrue(false);
fail();
} catch (SocketTimeoutException expected) { }
ss.setSoTimeout(0);
try (Socket s1 = new Socket()) {
@ -363,12 +356,12 @@ public class Timeouts {
* accept timed out and after a short delay
*/
public void testTimedAccept6() throws IOException {
try (ServerSocket ss = new ServerSocket(0)) {
try (ServerSocket ss = boundServerSocket()) {
ss.setSoTimeout(2000);
try {
Socket s = ss.accept();
s.close();
assertTrue(false);
fail();
} catch (SocketTimeoutException expected) { }
ss.setSoTimeout(0);
scheduleConnect(ss.getLocalSocketAddress(), 2000);
@ -381,13 +374,134 @@ public class Timeouts {
* Test async close of a timed accept
*/
public void testTimedAccept7() throws IOException {
try (ServerSocket ss = new ServerSocket(0)) {
try (ServerSocket ss = boundServerSocket()) {
ss.setSoTimeout(30*1000);
scheduleClose(ss, 2000);
long delay = 2000;
scheduleClose(ss, delay);
long startMillis = millisTime();
try {
ss.accept().close();
assertTrue(false);
} catch (SocketException expected) { }
fail();
} catch (SocketException expected) {
checkDuration(startMillis, delay-100, delay+2000);
}
}
}
/**
* Test timed accept with the thread interrupt status set.
*/
public void testTimedAccept8() throws IOException {
try (ServerSocket ss = boundServerSocket()) {
ss.setSoTimeout(2000);
Thread.currentThread().interrupt();
long startMillis = millisTime();
try {
Socket s = ss.accept();
s.close();
fail();
} catch (SocketTimeoutException expected) {
// accept should have blocked for 2 seconds
int timeout = ss.getSoTimeout();
checkDuration(startMillis, timeout-100, timeout+2000);
assertTrue(Thread.currentThread().isInterrupted());
} finally {
Thread.interrupted(); // clear interrupt status
}
}
}
/**
* Test interrupt of thread blocked in timed accept.
*/
public void testTimedAccept9() throws IOException {
try (ServerSocket ss = boundServerSocket()) {
ss.setSoTimeout(4000);
// interrupt thread after 1 second
Future<?> interrupter = scheduleInterrupt(Thread.currentThread(), 1000);
long startMillis = millisTime();
try {
Socket s = ss.accept(); // should block for 4 seconds
s.close();
fail();
} catch (SocketTimeoutException expected) {
// accept should have blocked for 4 seconds
int timeout = ss.getSoTimeout();
checkDuration(startMillis, timeout-100, timeout+2000);
assertTrue(Thread.currentThread().isInterrupted());
} finally {
interrupter.cancel(true);
Thread.interrupted(); // clear interrupt status
}
}
}
/**
* Test two threads blocked in timed accept where no connection is established.
*/
public void testTimedAccept10() throws Exception {
ExecutorService pool = Executors.newFixedThreadPool(2);
try (ServerSocket ss = boundServerSocket()) {
ss.setSoTimeout(4000);
long startMillis = millisTime();
Future<Socket> result1 = pool.submit(ss::accept);
Future<Socket> result2 = pool.submit(ss::accept);
// both tasks should complete with SocketTimeoutException
Throwable e = expectThrows(ExecutionException.class, result1::get);
assertTrue(e.getCause() instanceof SocketTimeoutException);
e = expectThrows(ExecutionException.class, result2::get);
assertTrue(e.getCause() instanceof SocketTimeoutException);
// should get here in 4 seconds, not 8 seconds
int timeout = ss.getSoTimeout();
checkDuration(startMillis, timeout-100, timeout+2000);
} finally {
pool.shutdown();
}
}
/**
* Test two threads blocked in timed accept where one connection is established.
*/
public void testTimedAccept11() throws Exception {
ExecutorService pool = Executors.newFixedThreadPool(2);
try (ServerSocket ss = boundServerSocket()) {
ss.setSoTimeout(4000);
long startMillis = millisTime();
Future<Socket> result1 = pool.submit(ss::accept);
Future<Socket> result2 = pool.submit(ss::accept);
// establish connection after 2 seconds
scheduleConnect(ss.getLocalSocketAddress(), 2000);
// one task should have accepted the connection, the other should
// have completed with SocketTimeoutException
Socket s1 = null;
try {
s1 = result1.get();
s1.close();
} catch (ExecutionException e) {
assertTrue(e.getCause() instanceof SocketTimeoutException);
}
Socket s2 = null;
try {
s2 = result2.get();
s2.close();
} catch (ExecutionException e) {
assertTrue(e.getCause() instanceof SocketTimeoutException);
}
assertTrue((s1 != null) ^ (s2 != null));
// should get here in 4 seconds, not 8 seconds
int timeout = ss.getSoTimeout();
checkDuration(startMillis, timeout-100, timeout+2000);
} finally {
pool.shutdown();
}
}
@ -411,6 +525,19 @@ public class Timeouts {
}
}
/**
* Returns a ServerSocket bound to a port on the loopback address
*/
static ServerSocket boundServerSocket() throws IOException {
var loopback = InetAddress.getLoopbackAddress();
ServerSocket ss = new ServerSocket();
ss.bind(new InetSocketAddress(loopback, 0));
return ss;
}
/**
* An operation that accepts two arguments and may throw IOException
*/
interface ThrowingBiConsumer<T, U> {
void accept(T t, U u) throws IOException;
}
@ -423,7 +550,7 @@ public class Timeouts {
{
Socket s1 = null;
Socket s2 = null;
try (ServerSocket ss = new ServerSocket(0)) {
try (ServerSocket ss = boundServerSocket()) {
s1 = new Socket();
s1.connect(ss.getLocalSocketAddress());
s2 = ss.accept();
@ -445,6 +572,13 @@ public class Timeouts {
}, delay);
}
/**
* Schedule thread to be interrupted after a delay
*/
static Future<?> scheduleInterrupt(Thread thread, long delay) {
return schedule(() -> thread.interrupt(), delay);
}
/**
* Schedule a thread to connect to the given end point after a delay
*/
@ -482,12 +616,36 @@ public class Timeouts {
scheduleWrite(out, new byte[] { (byte)b }, delay);
}
static void schedule(Runnable task, long delay) {
static Future<?> schedule(Runnable task, long delay) {
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
try {
executor.schedule(task, delay, TimeUnit.MILLISECONDS);
return executor.schedule(task, delay, TimeUnit.MILLISECONDS);
} finally {
executor.shutdown();
}
}
/**
* Returns the current time in milliseconds.
*/
private static long millisTime() {
long now = System.nanoTime();
return TimeUnit.MILLISECONDS.convert(now, TimeUnit.NANOSECONDS);
}
/**
* Check the duration of a task
* @param start start time, in milliseconds
* @param min minimum expected duration, in milliseconds
* @param max maximum expected duration, in milliseconds
* @return the duration (now - start), in milliseconds
*/
private static long checkDuration(long start, long min, long max) {
long duration = millisTime() - start;
assertTrue(duration >= min,
"Duration " + duration + "ms, expected >= " + min + "ms");
assertTrue(duration <= max,
"Duration " + duration + "ms, expected <= " + max + "ms");
return duration;
}
}

View File

@ -23,24 +23,36 @@
/**
* @test
* @run main UdpSocket
* @run testng/othervm -Dsun.net.maxDatagramSockets=32 UdpSocket
* @summary Basic test for a Socket to a UDP socket
*/
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.security.Permission;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.ArrayDeque;
import java.util.Deque;
import org.testng.annotations.Test;
import static org.testng.Assert.*;
@Test
public class UdpSocket {
static final String MESSAGE = "hello";
/**
* Test using the Socket API to send/receive datagrams
*/
public void testSendReceive() throws IOException {
final String MESSAGE = "hello";
public static void main(String[] args) throws IOException {
try (DatagramChannel dc = DatagramChannel.open()) {
var loopback = InetAddress.getLoopbackAddress();
dc.bind(new InetSocketAddress(loopback, 0));
@ -56,8 +68,7 @@ public class UdpSocket {
var buf = ByteBuffer.allocate(100);
SocketAddress remote = dc.receive(buf);
buf.flip();
if (buf.remaining() != MESSAGE.length())
throw new RuntimeException("Unexpected size");
assertTrue(buf.remaining() == MESSAGE.length(), "Unexpected size");
// echo the datagram
dc.send(buf, remote);
@ -65,11 +76,71 @@ public class UdpSocket {
// receive datagram with the socket input stream
byte[] array2 = new byte[100];
int n = s.getInputStream().read(array2);
if (n != MESSAGE.length())
throw new RuntimeException("Unexpected size");
if (!Arrays.equals(array1, 0, n, array2, 0, n))
throw new RuntimeException("Unexpected contents");
assertTrue(n == MESSAGE.length(), "Unexpected size");
assertEquals(Arrays.copyOf(array1, n), Arrays.copyOf(array2, n),
"Unexpected contents");
}
}
}
/**
* Test that the number of UDP sockets is limited when running with a
* security manager.
*/
public void testMaxSockets() throws Exception {
int limit = Integer.getInteger("sun.net.maxDatagramSockets");
// security manager grants all permissions
var securityManager = new SecurityManager() {
@Override public void checkPermission(Permission perm) { }
};
System.setSecurityManager(securityManager);
Deque<Socket> sockets = new ArrayDeque<>();
try {
// create the maximum number of sockets
for (int i=0; i<limit; i++) {
sockets.offer(newUdpSocket());
}
// try to create another socket - should fail
try {
Socket s = newUdpSocket();
s.close();
assertTrue(false);
} catch (IOException expected) { }
// close one socket
sockets.pop().close();
// try to create another socket - should succeed
Socket s = newUdpSocket();
// unreference the socket and wait for it to be closed by the cleaner
var ref = new WeakReference<>(s);
s = null;
while (ref.get() != null) {
System.gc();
Thread.sleep(100);
}
// try to create another socket - should succeed
s = newUdpSocket();
s.close();
} finally {
closeAll(sockets);
System.setSecurityManager(null);
}
}
private Socket newUdpSocket() throws IOException {
return new Socket(InetAddress.getLoopbackAddress(), 8000, false);
}
private void closeAll(Deque<Socket> sockets) throws IOException {
Socket s;
while ((s = sockets.poll()) != null) {
s.close();
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 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
@ -35,6 +35,7 @@ import static java.util.concurrent.CompletableFuture.*;
* cause any thread blocked on the socket to throw a SocketException.
* @run main AsyncClose
* @run main/othervm -Djava.net.preferIPv4Stack=true AsyncClose
* @run main/othervm -Djdk.net.usePlainSocketImpl AsyncClose
*/
public class AsyncClose {

View File

@ -0,0 +1,490 @@
/*
* 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.
*/
/*
* @test
* @bug 8221481
* @compile/module=java.base java/net/PlatformSocketImpl.java
* @run testng/othervm BadUsages
* @summary Test the platform SocketImpl when used in unintended ways
*/
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.SocketAddress;
import java.net.SocketException;
import java.net.SocketImpl;
import java.net.SocketOption;
import java.net.SocketOptions;
import java.net.StandardSocketOptions;
import java.util.Set;
import java.net.PlatformSocketImpl; // test helper
import org.testng.annotations.Test;
import static org.testng.Assert.*;
/**
* SocketImpl does not specify how the SocketImpl behaves when used in ways
* that are not intended, e.g. invoking socket operations before the socket is
* created or trying to establish a connection after the socket is connected or
* closed.
*
* This test exercises the platform SocketImpl to test that it is reliable, and
* throws reasonable exceptions, for these scenarios.
*/
@Test
public class BadUsages {
/**
* Test create when already created.
*/
public void testCreate1() throws IOException {
try (var impl = new PlatformSocketImpl(false)) {
impl.create(true);
expectThrows(IOException.class, () -> impl.create(true));
}
}
/**
* Test create when closed.
*/
public void testCreate2() throws IOException {
var impl = new PlatformSocketImpl(false);
impl.close();
expectThrows(IOException.class, () -> impl.create(true));
}
/**
* Test connect when not created.
*/
public void testConnect1() throws IOException {
try (var ss = new ServerSocket(0)) {
var impl = new PlatformSocketImpl(false);
var address = ss.getInetAddress();
int port = ss.getLocalPort();
expectThrows(IOException.class, () -> impl.connect(address, port));
}
}
/**
* Test connect with unsupported address type.
*/
public void testConnect2() throws IOException {
try (var impl = new PlatformSocketImpl(false)) {
impl.create(true);
var remote = new SocketAddress() { };
expectThrows(IOException.class, () -> impl.connect(remote, 0));
}
}
/**
* Test connect with an unresolved address.
*/
public void testConnect3() throws IOException {
try (var impl = new PlatformSocketImpl(false)) {
impl.create(true);
var remote = new InetSocketAddress("blah-blah.blah-blah", 80);
expectThrows(IOException.class, () -> impl.connect(remote, 0));
}
}
/**
* Test connect when already connected.
*/
public void testConnect4() throws IOException {
try (var ss = new ServerSocket();
var impl = new PlatformSocketImpl(false)) {
var loopback = InetAddress.getLoopbackAddress();
ss.bind(new InetSocketAddress(loopback, 0));
impl.create(true);
int port = ss.getLocalPort();
impl.connect(loopback, port);
expectThrows(IOException.class, () -> impl.connect(loopback, port));
}
}
/**
* Test connect when closed.
*/
public void testConnect5() throws IOException {
try (var ss = new ServerSocket(0)) {
var impl = new PlatformSocketImpl(false);
impl.close();
String host = ss.getInetAddress().getHostAddress();
int port = ss.getLocalPort();
expectThrows(IOException.class, () -> impl.connect(host, port));
}
}
/**
* Test bind when not created.
*/
public void testBind1() throws IOException {
var impl = new PlatformSocketImpl(false);
var loopback = InetAddress.getLoopbackAddress();
expectThrows(IOException.class, () -> impl.bind(loopback, 0));
}
/**
* Test bind when already bound.
*/
public void testBind2() throws IOException {
try (var impl = new PlatformSocketImpl(false)) {
impl.create(true);
var loopback = InetAddress.getLoopbackAddress();
impl.bind(loopback, 0);
expectThrows(IOException.class, () -> impl.bind(loopback, 0));
}
}
/**
* Test bind when connected.
*/
public void testBind3() throws IOException {
try (var ss = new ServerSocket();
var impl = new PlatformSocketImpl(false)) {
var loopback = InetAddress.getLoopbackAddress();
ss.bind(new InetSocketAddress(loopback, 0));
impl.create(true);
impl.connect(ss.getLocalSocketAddress(), 0);
expectThrows(IOException.class, () -> impl.bind(loopback, 0));
}
}
/**
* Test bind when closed.
*/
public void testBind4() throws IOException {
var impl = new PlatformSocketImpl(false);
impl.close();
var loopback = InetAddress.getLoopbackAddress();
expectThrows(IOException.class, () -> impl.bind(loopback, 0));
}
/**
* Test listen when not created.
*/
public void testListen1() {
var impl = new PlatformSocketImpl(false);
expectThrows(IOException.class, () -> impl.listen(16));
}
/**
* Test listen when not bound.
*/
public void testListen2() throws IOException {
try (var impl = new PlatformSocketImpl(false)) {
impl.create(true);
expectThrows(IOException.class, () -> impl.listen(16));
}
}
/**
* Test listen when closed.
*/
public void testListen3() throws IOException {
var impl = new PlatformSocketImpl(false);
impl.close();
expectThrows(IOException.class, () -> impl.listen(16));
}
/**
* Test accept when not created.
*/
public void testAccept1() throws IOException {
var impl = new PlatformSocketImpl(true);
var si = new PlatformSocketImpl(false);
expectThrows(IOException.class, () -> impl.accept(si));
}
/**
* Test accept when not bound.
*/
public void testAccept2() throws IOException {
try (var impl = new PlatformSocketImpl(true)) {
impl.create(true);
var si = new PlatformSocketImpl(false);
expectThrows(IOException.class, () -> impl.accept(si));
}
}
/**
* Test accept when not a stream socket.
*/
public void testAccept3() throws IOException {
try (var impl = new PlatformSocketImpl(false)) {
impl.create(false);
impl.bind(InetAddress.getLoopbackAddress(), 0);
var si = new PlatformSocketImpl(false);
expectThrows(IOException.class, () -> impl.accept(si));
}
}
/**
* Test accept when closed.
*/
public void testAccept4() throws IOException {
var impl = new PlatformSocketImpl(true);
impl.close();
var si = new PlatformSocketImpl(false);
expectThrows(IOException.class, () -> impl.accept(si));
}
/**
* Test accept with SocketImpl that is already created.
*/
public void testAccept5() throws IOException {
try (var impl = new PlatformSocketImpl(true);
var si = new PlatformSocketImpl(false)) {
impl.create(true);
impl.bind(InetAddress.getLoopbackAddress(), 0);
si.create(true);
expectThrows(IOException.class, () -> impl.accept(si));
}
}
/**
* Test accept with SocketImpl that is closed.
*/
public void testAccept6() throws IOException {
try (var impl = new PlatformSocketImpl(true);
var si = new PlatformSocketImpl(false)) {
impl.create(true);
impl.bind(InetAddress.getLoopbackAddress(), 0);
si.create(true);
si.close();
expectThrows(IOException.class, () -> impl.accept(si));
}
}
/**
* Test available when not created.
*/
public void testAvailable1() throws IOException {
var impl = new PlatformSocketImpl(false);
expectThrows(IOException.class, () -> impl.available());
}
/**
* Test available when created but not connected.
*/
public void testAvailable2() throws IOException {
try (var impl = new PlatformSocketImpl(false)) {
impl.create(true);
expectThrows(IOException.class, () -> impl.available());
}
}
/**
* Test available when closed.
*/
public void testAvailable3() throws IOException {
var impl = new PlatformSocketImpl(false);
impl.close();
expectThrows(IOException.class, () -> impl.available());
}
/**
* Test setOption when not created.
*/
public void testSetOption1() throws IOException {
var impl = new PlatformSocketImpl(false);
expectThrows(IOException.class,
() -> impl.setOption(StandardSocketOptions.SO_REUSEADDR, true));
// legacy
expectThrows(SocketException.class,
() -> impl.setOption(SocketOptions.SO_REUSEADDR, true));
}
/**
* Test setOption when closed.
*/
public void testSetOption2() throws IOException {
var impl = new PlatformSocketImpl(false);
impl.close();
expectThrows(IOException.class,
() -> impl.setOption(StandardSocketOptions.SO_REUSEADDR, true));
// legacy
expectThrows(SocketException.class,
() -> impl.setOption(SocketOptions.SO_REUSEADDR, true));
}
/**
* Test setOption with unsupported option.
*/
public void testSetOption3() throws IOException {
try (var impl = new PlatformSocketImpl(false)) {
impl.create(true);
var opt = new SocketOption<String>() {
@Override public String name() { return "birthday"; }
@Override public Class<String> type() { return String.class; }
};
expectThrows(UnsupportedOperationException.class, () -> impl.setOption(opt, ""));
// legacy
expectThrows(SocketException.class, () -> impl.setOption(-1, ""));
}
}
/**
* Test setOption(int, Object) with invalid values.
*/
public void testSetOption4() throws IOException {
try (var impl = new PlatformSocketImpl(false)) {
impl.create(true);
expectThrows(SocketException.class,
() -> impl.setOption(SocketOptions.SO_REUSEADDR, -1));
expectThrows(SocketException.class,
() -> impl.setOption(SocketOptions.SO_TIMEOUT, -1));
expectThrows(SocketException.class,
() -> impl.setOption(SocketOptions.SO_SNDBUF, -1));
expectThrows(SocketException.class,
() -> impl.setOption(SocketOptions.SO_RCVBUF, -1));
}
}
/**
* Test getOption when not created.
*/
public void testGetOption1() throws IOException {
var impl = new PlatformSocketImpl(false);
expectThrows(IOException.class,
() -> impl.getOption(StandardSocketOptions.SO_REUSEADDR));
expectThrows(SocketException.class,
() -> impl.getOption(-1));
}
/**
* Test getOption when closed.
*/
public void testGetOption2() throws IOException {
var impl = new PlatformSocketImpl(false);
impl.close();
expectThrows(IOException.class,
() -> impl.getOption(StandardSocketOptions.SO_REUSEADDR));
expectThrows(SocketException.class,
() -> impl.getOption(SocketOptions.SO_REUSEADDR));
}
/**
* Test getOption with unsupported option.
*/
public void testGetOption3() throws IOException {
try (var impl = new PlatformSocketImpl(false)) {
impl.create(true);
var opt = new SocketOption<String>() {
@Override public String name() { return "birthday"; }
@Override public Class<String> type() { return String.class; }
};
expectThrows(UnsupportedOperationException.class, () -> impl.getOption(opt));
expectThrows(SocketException.class, () -> impl.getOption(-1));
}
}
/**
* Test shutdownInput when not created.
*/
public void testShutdownInput1() throws IOException {
var impl = new PlatformSocketImpl(false);
expectThrows(IOException.class, () -> impl.shutdownInput());
}
/**
* Test shutdownInput when not connected.
*/
public void testShutdownInput2() throws IOException {
try (var impl = new PlatformSocketImpl(false)) {
impl.create(true);
expectThrows(IOException.class, () -> impl.shutdownInput());
}
}
/**
* Test shutdownInput when closed.
*/
public void testShutdownInput3() throws IOException {
var impl = new PlatformSocketImpl(false);
impl.close();
expectThrows(IOException.class, () -> impl.shutdownInput());
}
/**
* Test shutdownOutput when not created.
*/
public void testShutdownOutput1() throws IOException {
var impl = new PlatformSocketImpl(false);
expectThrows(IOException.class, () -> impl.shutdownOutput());
}
/**
* Test shutdownOutput when not connected.
*/
public void testShutdownOutput2() throws IOException {
try (var impl = new PlatformSocketImpl(false)) {
impl.create(true);
expectThrows(IOException.class, () -> impl.shutdownOutput());
}
}
/**
* Test shutdownOutput when closed.
*/
public void testShutdownOutput3() throws IOException {
var impl = new PlatformSocketImpl(false);
impl.close();
expectThrows(IOException.class, () -> impl.shutdownOutput());
}
/**
* Test sendUrgentData when not created.
*/
public void testSendUrgentData1() throws IOException {
var impl = new PlatformSocketImpl(false);
expectThrows(IOException.class, () -> impl.sendUrgentData(0));
}
/**
* Test sendUrgentData when not connected.
*/
public void testSendUrgentData2() throws IOException {
try (var impl = new PlatformSocketImpl(false)) {
impl.create(true);
expectThrows(IOException.class, () -> impl.sendUrgentData(0));
}
}
/**
* Test sendUrgentData when closed.
*/
public void testSendUrgentData3() throws IOException {
var impl = new PlatformSocketImpl(false);
impl.close();
expectThrows(IOException.class, () -> impl.sendUrgentData(0));
}
}

View File

@ -0,0 +1,81 @@
/*
* 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.
*/
/*
* @test
* @bug 8221481
* @modules java.base/java.net:+open java.base/sun.nio.ch:+open
* @run testng CompareSocketOptions
* @summary Compare the set of socket options supported by the old and new SocketImpls
*/
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketImpl;
import org.testng.annotations.Test;
import static org.testng.Assert.*;
@Test
public class CompareSocketOptions {
/**
* Test that the old and new platform SocketImpl support the same set of
* client socket options.
*/
public void testClientSocketSupportedOptions() throws IOException {
Socket s1 = new Socket(createOldSocketImpl(false)) { };
Socket s2 = new Socket(createNewSocketImpl(false)) { };
assertEquals(s1.supportedOptions(), s2.supportedOptions());
}
/**
* Test that the old and new platform SocketImpl support the same set of
* server socket options.
*/
public void testServerSocketSupportedOptions() throws IOException {
ServerSocket ss1 = new ServerSocket(createOldSocketImpl(true)) { };
ServerSocket ss2 = new ServerSocket(createNewSocketImpl(true)) { };
assertEquals(ss1.supportedOptions(), ss2.supportedOptions());
}
private static SocketImpl createOldSocketImpl(boolean server) {
return newPlatformSocketImpl("java.net.PlainSocketImpl", server);
}
private static SocketImpl createNewSocketImpl(boolean server) {
return newPlatformSocketImpl("sun.nio.ch.NioSocketImpl", server);
}
private static SocketImpl newPlatformSocketImpl(String name, boolean server) {
try {
var ctor = Class.forName(name).getDeclaredConstructor(boolean.class);
ctor.setAccessible(true);
return (SocketImpl) ctor.newInstance(server);
} catch (Exception e) {
fail("Should not get here", e);
return null;
}
}
}

View File

@ -0,0 +1,143 @@
/*
* 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.
*/
package java.net;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.IOException;
import java.util.Set;
/**
* A SocketImpl that delegates all operations to a platform SocketImpl. It also
* overrides all methods with public methods and implements AutoCloseable to make
* it easy to write tests.
*/
public class PlatformSocketImpl extends SocketImpl implements AutoCloseable {
private final SocketImpl impl;
public PlatformSocketImpl(boolean server) {
impl = new sun.nio.ch.NioSocketImpl(server);
}
@Override
public void close() throws IOException {
impl.close();
}
@Override
public void create(boolean stream) throws IOException {
impl.create(stream);
}
@Override
public void connect(SocketAddress remote, int millis) throws IOException {
impl.connect(remote, millis);
}
@Override
public void connect(String host, int port) throws IOException {
impl.connect(host, port);
}
@Override
public void connect(InetAddress address, int port) throws IOException {
impl.connect(address, port);
}
@Override
public void bind(InetAddress address, int port) throws IOException {
impl.bind(address, port);
}
@Override
public void listen(int backlog) throws IOException {
impl.listen(backlog);
}
@Override
public void accept(SocketImpl si) throws IOException {
impl.accept(((PlatformSocketImpl) si).impl);
}
@Override
public InputStream getInputStream() throws IOException {
return impl.getInputStream();
}
@Override
public OutputStream getOutputStream() throws IOException {
return impl.getOutputStream();
}
@Override
public int available() throws IOException {
return impl.available();
}
@Override
public Set<SocketOption<?>> supportedOptions() {
return impl.supportedOptions();
}
@Override
public <T> void setOption(SocketOption<T> opt, T value) throws IOException {
impl.setOption(opt, value);
}
@Override
public <T> T getOption(SocketOption<T> opt) throws IOException {
return impl.getOption(opt);
}
@Override
public void setOption(int opt, Object value) throws SocketException {
impl.setOption(opt, value);
}
@Override
public Object getOption(int opt) throws SocketException {
return impl.getOption(opt);
}
@Override
public void shutdownInput() throws IOException {
impl.shutdownInput();
}
@Override
public void shutdownOutput() throws IOException {
impl.shutdownOutput();
}
@Override
public boolean supportsUrgentData() {
return impl.supportsUrgentData();
}
@Override
public void sendUrgentData(int data) throws IOException {
impl.sendUrgentData(data);
}
}

View File

@ -38,23 +38,24 @@ import jdk.test.lib.net.IPSupport;
public class OptionsTest {
static class Test {
Test(SocketOption<?> option, Object testValue) {
static class Test<T> {
final SocketOption<T> option;
final T value;
Test(SocketOption<T> option, T value) {
this.option = option;
this.testValue = testValue;
this.value = value;
}
static Test create (SocketOption<?> option, Object testValue) {
return new Test(option, testValue);
static <T> Test<T> create(SocketOption<T> option, T value) {
return new Test<T>(option, value);
}
Object option;
Object testValue;
}
// The tests set the option using the new API, read back the set value
// which could be diferent, and then use the legacy get API to check
// these values are the same
static Test[] socketTests = new Test[] {
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)),
@ -66,7 +67,7 @@ public class OptionsTest {
Test.create(StandardSocketOptions.IP_TOS, Integer.valueOf(255)) //upper-bound
};
static Test[] serverSocketTests = new Test[] {
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),
@ -75,7 +76,7 @@ public class OptionsTest {
Test.create(StandardSocketOptions.IP_TOS, Integer.valueOf(255)) //upper-bound
};
static Test[] dgSocketTests = new Test[] {
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),
@ -85,7 +86,7 @@ public class OptionsTest {
Test.create(StandardSocketOptions.IP_TOS, Integer.valueOf(255)) //upper-bound
};
static Test[] mcSocketTests = new Test[] {
static Test<?>[] multicastSocketTests = new Test<?>[] {
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)),
@ -97,7 +98,7 @@ public class OptionsTest {
try {
Enumeration<NetworkInterface> nifs = NetworkInterface.getNetworkInterfaces();
while (nifs.hasMoreElements()) {
NetworkInterface ni = (NetworkInterface)nifs.nextElement();
NetworkInterface ni = nifs.nextElement();
if (ni.supportsMulticast()) {
return ni;
}
@ -107,99 +108,110 @@ public class OptionsTest {
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);
}
@SuppressWarnings("try")
static void doSocketTests() throws Exception {
try (
ServerSocket srv = new ServerSocket(0, 50, InetAddress.getLoopbackAddress());
Socket c = new Socket(InetAddress.getLoopbackAddress(), srv.getLocalPort());
Socket s = srv.accept();
) {
Set<SocketOption<?>> options = c.supportedOptions();
boolean reuseport = options.contains(StandardSocketOptions.SO_REUSEPORT);
for (int i=0; i<socketTests.length; i++) {
Test test = socketTests[i];
if (!(test.option == StandardSocketOptions.SO_REUSEPORT && !reuseport)) {
c.setOption((SocketOption)test.option, test.testValue);
Object getval = c.getOption((SocketOption)test.option);
Object legacyget = legacyGetOption(Socket.class, c,test.option);
if (!getval.equals(legacyget)) {
Formatter f = new Formatter();
f.format("S Err %d: %s/%s", i, getval, legacyget);
throw new RuntimeException(f.toString());
}
// unconnected socket
try (Socket s = new Socket()) {
for (Test<?> test : socketTests) {
if (okayToTest(s, test.option)) {
test(s, test);
}
}
}
}
static void doDgSocketTests() throws Exception {
try (
DatagramSocket c = new DatagramSocket(0);
) {
Set<SocketOption<?>> options = c.supportedOptions();
boolean reuseport = options.contains(StandardSocketOptions.SO_REUSEPORT);
for (int i=0; i<dgSocketTests.length; i++) {
Test test = dgSocketTests[i];
if (!(test.option == StandardSocketOptions.SO_REUSEPORT && !reuseport)) {
c.setOption((SocketOption)test.option, test.testValue);
Object getval = c.getOption((SocketOption)test.option);
Object legacyget = legacyGetOption(DatagramSocket.class, c,test.option);
if (!getval.equals(legacyget)) {
Formatter f = new Formatter();
f.format("DG Err %d: %s/%s", i, getval, legacyget);
throw new RuntimeException(f.toString());
// 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);
}
}
}
}
}
}
static void doMcSocketTests() throws Exception {
try (
MulticastSocket c = new MulticastSocket(0);
) {
for (int i=0; i<mcSocketTests.length; i++) {
Test test = mcSocketTests[i];
c.setOption((SocketOption)test.option, test.testValue);
Object getval = c.getOption((SocketOption)test.option);
Object legacyget = legacyGetOption(MulticastSocket.class, c,test.option);
if (!getval.equals(legacyget)) {
Formatter f = new Formatter();
f.format("MC Err %d: %s/%s", i, getval, legacyget);
throw new RuntimeException(f.toString());
}
}
}
}
static void doServerSocketTests() throws Exception {
try (
ServerSocket c = new ServerSocket(0);
) {
Set<SocketOption<?>> options = c.supportedOptions();
try (ServerSocket ss = new ServerSocket(0)) {
Set<SocketOption<?>> options = ss.supportedOptions();
boolean reuseport = options.contains(StandardSocketOptions.SO_REUSEPORT);
for (int i=0; i<serverSocketTests.length; i++) {
Test test = serverSocketTests[i];
for (Test<?> test : serverSocketTests) {
if (!(test.option == StandardSocketOptions.SO_REUSEPORT && !reuseport)) {
c.setOption((SocketOption)test.option, test.testValue);
Object getval = c.getOption((SocketOption)test.option);
Object legacyget = legacyGetOption(
ServerSocket.class, c, test.option
);
if (!getval.equals(legacyget)) {
Formatter f = new Formatter();
f.format("SS Err %d: %s/%s", i, getval, legacyget);
throw new RuntimeException(f.toString());
}
test(ss, test);
}
}
}
}
static Object legacyGetOption(
Class<?> type, Object s, Object option)
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);
}
}
}
}
throws Exception
{
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();
@ -291,8 +303,8 @@ public class OptionsTest {
IPSupport.throwSkippedExceptionIfNonOperational();
doSocketTests();
doServerSocketTests();
doDgSocketTests();
doMcSocketTests();
doDatagramSocketTests();
doMulticastSocketTests();
}
// Reflectively access jdk.net.Sockets.getOption so that the test can run

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 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
@ -32,6 +32,7 @@
* @build jdk.test.lib.NetworkConfiguration
* jdk.test.lib.Platform
* @run main TcpTest -d
* @run main/othervm -Djdk.net.usePlainSocketImpl TcpTest -d
*/
import java.net.*;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 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
@ -197,14 +197,19 @@ public class NewSocketMethods {
/**
* test some new methods of java.net.Socket added to merlin.
*/
socket.setTrafficClass(8);
socket.setReuseAddress(true);
System.out.println("Client getTrafficClass(): "
+ socket.getTrafficClass());
System.out.println("Client isInputShutdown() "
+ socket.isInputShutdown());
socket.setReuseAddress(true);
System.out.println("Client getReuseAddress(): "
+ socket.getReuseAddress());
// Solaris does not support set/get of IPV6_TCLASS when connected
if (!"SunOS".equals(System.getProperty("os.name"))) {
socket.setTrafficClass(8);
System.out.println("Client getTrafficClass(): "
+ socket.getTrafficClass());
}
os.write(237);
os.flush();
System.out.println("Client read: " + is.read());