8241072: Reimplement the Legacy DatagramSocket API

Replace the underlying implementations of the java.net.DatagramSocket and java.net.MulticastSocket APIs with simpler and more modern implementations that are easy to maintain and debug.

Co-authored-by: Alan Bateman <alan.bateman@oracle.com>
Co-authored-by: Chris Hegarty <chris.hegarty@oracle.com>
Co-authored-by: Daniel Fuchs <daniel.fuchs@oracle.com>
Reviewed-by: alanb, chegar, dfuchs
This commit is contained in:
Patrick Concannon 2020-05-12 21:51:53 +01:00
parent 3930460af5
commit fad2cf51ba
34 changed files with 1478 additions and 909 deletions

View file

@ -25,6 +25,8 @@
* @test
* @bug 6427403
* @summary java.net.MulticastSocket.joinGroup() reports 'socket closed'
* @run main B6427403
* @run main/othervm -Djdk.net.usePlainDatagramSocketImpl B6427403
*/
import java.net.*;
import java.io.*;

View file

@ -27,6 +27,8 @@
* @library /test/lib
* @summary Test that MutlicastSocket.joinGroup is working for
* various multicast and non-multicast addresses.
* @run main MulticastAddresses
* @run main/othervm -Djdk.net.usePlainDatagramSocketImpl MulticastAddresses
*/
import jdk.test.lib.NetworkConfiguration;

View file

@ -28,6 +28,7 @@
* @run main/othervm NoSetNetworkInterface
* @run main/othervm -Djava.net.preferIPv4Stack=true NoSetNetworkInterface
* @run main/othervm -Djava.net.preferIPv6Addresses=true NoSetNetworkInterface
* @run main/othervm -Djdk.net.usePlainDatagramSocketImpl NoSetNetworkInterface
* @summary Check that methods that are used to set and get the NetworkInterface
* for a MulticastSocket work as expected. This test also checks that getOption
* returns null correctly when a NetworkInterface has not been set

View file

@ -26,6 +26,7 @@
* @library /test/lib
* @summary Test for interference when two sockets are bound to the same
* port but joined to different multicast groups
* @run main/othervm -Djdk.net.usePlainDatagramSocketImpl Promiscuous
* @run main Promiscuous
* @run main/othervm -Djava.net.preferIPv4Stack=true Promiscuous
*/

View file

@ -48,7 +48,8 @@ import static org.testng.Assert.assertThrows;
* @bug 8243408
* @summary Check that MulticastSocket throws expected
* Exception when sending a DatagramPacket with port 0
* @run testng/othervm SendPortZero
* @run testng SendPortZero
* @run testng/othervm -Djdk.net.usePlainDatagramSocketImpl SendPortZero
*/
public class SendPortZero {

View file

@ -30,6 +30,7 @@
* @build jdk.test.lib.NetworkConfiguration
* jdk.test.lib.Platform
* @run main/othervm SetLoopbackMode
* @run main/othervm -Djdk.net.usePlainDatagramSocketImpl SetLoopbackMode
*/
import java.lang.reflect.Method;
@ -53,6 +54,8 @@ public class SetLoopbackMode {
System.out.println("Loopback mode is enabled.");
}
System.out.println(mc.getLocalSocketAddress());
byte b[] = "hello".getBytes();
DatagramPacket p = new DatagramPacket(b, b.length, grp,
mc.getLocalPort());

View file

@ -32,6 +32,8 @@
* SetLoopbackMode
* SetLoopbackModeIPv4
* @run main/othervm -Djava.net.preferIPv4Stack=true SetLoopbackModeIPv4
* @run main/othervm -Djava.net.preferIPv4Stack=true
* -Djdk.net.usePlainDatagramSocketImpl SetLoopbackModeIPv4
*/
import jdk.test.lib.net.IPSupport;

View file

@ -31,6 +31,7 @@
* @run testng/othervm SetLoopbackOption
* @run testng/othervm -Djava.net.preferIPv4Stack=true SetLoopbackOption
* @run testng/othervm -Djava.net.preferIPv6Addresses=true SetLoopbackOption
* @run testng/othervm -Djdk.net.usePlainDatagramSocketImpl SetLoopbackOption
*/
import java.io.FileDescriptor;

View file

@ -26,6 +26,7 @@
* @bug 4742177 8241786
* @library /test/lib
* @run main/othervm SetOutgoingIf
* @run main/othervm -Djdk.net.usePlainDatagramSocketImpl SetOutgoingIf
* @summary Re-test IPv6 (and specifically MulticastSocket) with latest Linux & USAGI code
*/
import java.io.IOException;

View file

@ -24,6 +24,8 @@
/* @test
* @bug 4189640
* @summary Make setTTL/getTTL works
* @run main SetTTLAndGetTTL
* @run main/othervm -Djdk.net.usePlainDatagramSocketImpl SetTTLAndGetTTL
*/
import java.net.*;

View file

@ -24,6 +24,8 @@
/* @test
* @bug 4148757
* @summary Make sure TTL can be set to 0
* @run main SetTTLTo0
* @run main/othervm -Djdk.net.usePlainDatagramSocketImpl SetTTLTo0
*/
import java.net.*;

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 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
@ -25,7 +25,9 @@
* @test
* @library /test/lib
* @modules java.management java.base/java.io:+open java.base/java.net:+open
* java.base/sun.net
* @run main/othervm -Djava.net.preferIPv4Stack=true UnreferencedMulticastSockets
* @run main/othervm -Djdk.net.usePlainDatagramSocketImpl UnreferencedMulticastSockets
* @run main/othervm UnreferencedMulticastSockets
* @summary Check that unreferenced multicast sockets are closed
*/
@ -37,6 +39,7 @@ import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.DatagramSocketImpl;
@ -44,9 +47,12 @@ import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.MulticastSocket;
import java.net.UnknownHostException;
import java.nio.channels.DatagramChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayDeque;
import java.util.List;
import java.util.Optional;
@ -56,6 +62,7 @@ import java.util.concurrent.TimeUnit;
import jdk.test.lib.net.IPSupport;
import com.sun.management.UnixOperatingSystemMXBean;
import sun.net.NetProperties;
public class UnreferencedMulticastSockets {
@ -223,32 +230,62 @@ public class UnreferencedMulticastSockets {
: -1L;
}
// Reflect to find references in the socket implementation that will be gc'd
private static void extractRefs(MulticastSocket s, String name) {
private static boolean usePlainDatagramSocketImpl() {
PrivilegedAction<String> pa = () -> NetProperties.get("jdk.net.usePlainDatagramSocketImpl");
String s = AccessController.doPrivileged(pa);
return (s != null) && (s.isEmpty() || s.equalsIgnoreCase("true"));
}
// Reflect to find references in the datagram implementation that will be gc'd
private static void extractRefs(DatagramSocket s, String name) {
try {
Field datagramSocketField = DatagramSocket.class.getDeclaredField("delegate");
datagramSocketField.setAccessible(true);
Field socketImplField = DatagramSocket.class.getDeclaredField("impl");
socketImplField.setAccessible(true);
Object socketImpl = socketImplField.get(s);
if (!usePlainDatagramSocketImpl()) {
// MulticastSocket using DatagramSocketAdaptor
Object MulticastSocket = datagramSocketField.get(s);
Field fileDescriptorField = DatagramSocketImpl.class.getDeclaredField("fd");
fileDescriptorField.setAccessible(true);
FileDescriptor fileDescriptor = (FileDescriptor) fileDescriptorField.get(socketImpl);
extractRefs(fileDescriptor, name);
Method m = DatagramSocket.class.getDeclaredMethod("getChannel");
m.setAccessible(true);
DatagramChannel datagramChannel = (DatagramChannel) m.invoke(MulticastSocket);
Class<?> socketImplClass = socketImpl.getClass();
System.out.printf("socketImplClass: %s%n", socketImplClass);
if (socketImplClass.getName().equals("java.net.TwoStacksPlainDatagramSocketImpl")) {
Field fileDescriptor1Field = socketImplClass.getDeclaredField("fd1");
fileDescriptor1Field.setAccessible(true);
FileDescriptor fileDescriptor1 = (FileDescriptor) fileDescriptor1Field.get(socketImpl);
extractRefs(fileDescriptor1, name + "::twoStacksFd1");
assert datagramChannel.getClass() == Class.forName("sun.nio.ch.DatagramChannelImpl");
Field fileDescriptorField = datagramChannel.getClass().getDeclaredField("fd");
fileDescriptorField.setAccessible(true);
FileDescriptor fileDescriptor = (FileDescriptor) fileDescriptorField.get(datagramChannel);
extractRefs(fileDescriptor, name);
} else {
System.out.printf("socketImpl class name not matched: %s != %s%n",
socketImplClass.getName(), "java.net.TwoStacksPlainDatagramSocketImpl");
// MulticastSocket using PlainDatagramSocketImpl
Object MulticastSocket = datagramSocketField.get(s);
assert MulticastSocket.getClass() == Class.forName("java.net.NetMulticastSocket");
Method m = MulticastSocket.getClass().getDeclaredMethod("getImpl");
m.setAccessible(true);
DatagramSocketImpl datagramSocketImpl = (DatagramSocketImpl) m.invoke(MulticastSocket);
Field fileDescriptorField = DatagramSocketImpl.class.getDeclaredField("fd");
fileDescriptorField.setAccessible(true);
FileDescriptor fileDescriptor = (FileDescriptor) fileDescriptorField.get(datagramSocketImpl);
extractRefs(fileDescriptor, name);
Class<?> socketImplClass = datagramSocketImpl.getClass();
System.out.printf("socketImplClass: %s%n", socketImplClass);
if (socketImplClass.getName().equals("java.net.TwoStacksPlainDatagramSocketImpl")) {
Field fileDescriptor1Field = socketImplClass.getDeclaredField("fd1");
fileDescriptor1Field.setAccessible(true);
FileDescriptor fileDescriptor1 = (FileDescriptor) fileDescriptor1Field.get(datagramSocketImpl);
extractRefs(fileDescriptor1, name + "::twoStacksFd1");
} else {
System.out.printf("socketImpl class name not matched: %s != %s%n",
socketImplClass.getName(), "java.net.TwoStacksPlainDatagramSocketImpl");
}
}
} catch (NoSuchFieldException | IllegalAccessException ex) {
} catch (Exception ex) {
ex.printStackTrace();
throw new AssertionError("missing field", ex);
}