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,57 @@
/*
* Copyright (c) 2006, 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 6425815
*
* @summary java.net.MulticastSocket.setTimeToLive(255) reports 'Socket closed' (WinXP, IPv6)
*
*/
import java.net.*;
import java.io.IOException;
public class B6425815 {
public static void main(String[] args) throws Exception {
InetAddress ia;
MulticastSocket ms;
try {
ia = InetAddress.getByName("::1");
ms = new MulticastSocket(new InetSocketAddress(ia, 1234));
} catch (Exception e) {
// If this fails, it means the system doesn't have IPV6
// support, therefore this test shouldn't be run.
ia = null;
ms = null;
}
if (ms != null) {
ms.setTimeToLive(254);
if (ms.getTimeToLive() != 254) {
throw new RuntimeException("time to live is incorrect!");
}
ms.close();
}
}
}

View file

@ -0,0 +1,40 @@
/*
* Copyright (c) 2006, 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 6427403
* @summary java.net.MulticastSocket.joinGroup() reports 'socket closed'
* @run main B6427403
*/
import java.net.*;
import java.io.*;
public class B6427403 {
public static void main( String[] args ) throws IOException {
InetAddress lh = InetAddress.getLocalHost();
MulticastSocket ms = new MulticastSocket( new InetSocketAddress(lh, 0) );
ms.joinGroup( InetAddress.getByName("224.80.80.80") );
ms.close();
}
}

View file

@ -0,0 +1,48 @@
/*
* Copyright (c) 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.
*/
/* @test
* @bug 8243999
* @summary Checks to ensure that Multicast constructors behave as expected
* @run testng Constructor
*/
import org.testng.annotations.Test;
import java.io.IOException;
import java.net.MulticastSocket;
import static org.testng.Assert.assertTrue;
public class Constructor {
@Test
public void testMSNullAddress() throws IOException {
try (var ms = new MulticastSocket()) {
assertTrue(ms.getLocalAddress().isAnyLocalAddress());
}
try (var ms1 = new MulticastSocket(null)) {
assertTrue(ms1.getLocalAddress().isAnyLocalAddress());
}
}
}

View file

@ -0,0 +1,190 @@
/*
* Copyright (c) 2019, 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.
*/
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.MulticastSocket;
import java.net.NetworkInterface;
import java.util.ArrayList;
import java.util.List;
import jdk.test.lib.NetworkConfiguration;
import jdk.test.lib.net.IPSupport;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static java.lang.String.format;
import static java.lang.System.out;
import static java.net.StandardSocketOptions.IP_MULTICAST_IF;
import static java.util.stream.Collectors.toList;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
/**
* @test
* @bug 8236441
* @summary Bound MulticastSocket fails when setting outbound interface on Windows
* @library /test/lib
* @run testng IPMulticastIF
* @run testng/othervm -Djava.net.preferIPv4Stack=true IPMulticastIF
* @run testng/othervm -Djava.net.preferIPv6Addresses=true IPMulticastIF
* @run testng/othervm -Djava.net.preferIPv6Addresses=true -Djava.net.preferIPv4Stack=true IPMulticastIF
*/
public class IPMulticastIF {
@BeforeTest
public void sanity() {
IPSupport.throwSkippedExceptionIfNonOperational();
NetworkConfiguration.printSystemConfiguration(out);
}
@DataProvider(name = "scenarios")
public Object[][] positive() throws Exception {
List<InetAddress> addrs = List.of(InetAddress.getLocalHost(),
InetAddress.getLoopbackAddress());
List<Object[]> list = new ArrayList<>();
NetworkConfiguration nc = NetworkConfiguration.probe();
// retains only network interface whose bound addresses match
addrs.stream().forEach(a -> nc.multicastInterfaces(true)
.filter(nif -> nif.inetAddresses().toList().contains(a))
.map(nif -> new Object[] { new InetSocketAddress(a, 0), nif })
.forEach(list::add) );
// any network interface should work with the wildcard address
nc.multicastInterfaces(true)
.map(nif -> new Object[] {new InetSocketAddress(0), nif})
.forEach(list::add);
return list.stream().toArray(Object[][]::new);
}
@DataProvider(name = "interfaces")
public Object[][] interfaces() throws Exception {
List<Object[]> list = new ArrayList<>();
NetworkConfiguration nc = NetworkConfiguration.probe();
nc.multicastInterfaces(true)
.map(nif -> new Object[] {nif})
.forEach(list::add);
return list.stream().toArray(Object[][]::new);
}
@Test(dataProvider = "scenarios")
public void testSetGetInterfaceBound(InetSocketAddress bindAddr, NetworkInterface nif)
throws Exception
{
out.println(format("\n\n--- testSetGetInterfaceBound bindAddr=[%s], nif=[%s]", bindAddr, nif));
try (MulticastSocket ms = new MulticastSocket(bindAddr)) {
ms.setNetworkInterface(nif);
NetworkInterface msNetIf = ms.getNetworkInterface();
assertEquals(msNetIf, nif);
}
}
@Test(dataProvider = "interfaces")
public void testSetGetInterfaceUnbound(NetworkInterface nif)
throws Exception
{
out.println(format("\n\n--- testSetGetInterfaceUnbound nif=[%s]", nif));
try (MulticastSocket ms = new MulticastSocket()) {
ms.setNetworkInterface(nif);
NetworkInterface msNetIf = ms.getNetworkInterface();
assertEquals(msNetIf, nif);
}
}
@Test(dataProvider = "scenarios")
public void testSetGetOptionBound(InetSocketAddress bindAddr, NetworkInterface nif)
throws Exception
{
out.println(format("\n\n--- testSetGetOptionBound bindAddr=[%s], nif=[%s]", bindAddr, nif));
try (MulticastSocket ms = new MulticastSocket(bindAddr)) {
ms.setOption(IP_MULTICAST_IF, nif);
NetworkInterface msNetIf = ms.getOption(IP_MULTICAST_IF);
assertEquals(msNetIf, nif);
}
}
@Test(dataProvider = "interfaces")
public void testSetGetOptionUnbound(NetworkInterface nif)
throws Exception
{
out.println(format("\n\n--- testSetGetOptionUnbound nif=[%s]", nif));
try (MulticastSocket ms = new MulticastSocket()) {
ms.setOption(IP_MULTICAST_IF, nif);
NetworkInterface msNetIf = ms.getOption(IP_MULTICAST_IF);
assertEquals(msNetIf, nif);
}
}
// -- get without set
@DataProvider(name = "bindAddresses")
public Object[][] bindAddresses() throws Exception {
return new Object[][] {
{ new InetSocketAddress(InetAddress.getLocalHost(), 0) },
{ new InetSocketAddress(InetAddress.getLoopbackAddress(), 0) },
};
}
@Test(dataProvider = "bindAddresses")
public void testGetInterfaceBound(InetSocketAddress bindAddr)
throws Exception
{
out.println(format("\n\n--- testGetInterfaceBound bindAddr=[%s]", bindAddr));
try (MulticastSocket ms = new MulticastSocket(bindAddr)) {
assertPlaceHolder(ms.getNetworkInterface());
}
}
@Test
public void testGetInterfaceUnbound() throws Exception {
out.println("\n\n--- testGetInterfaceUnbound ");
try (MulticastSocket ms = new MulticastSocket()) {
assertPlaceHolder(ms.getNetworkInterface());
}
}
@Test(dataProvider = "bindAddresses")
public void testGetOptionBound(InetSocketAddress bindAddr)
throws Exception
{
out.println(format("\n\n--- testGetOptionBound bindAddr=[%s]", bindAddr));
try (MulticastSocket ms = new MulticastSocket(bindAddr)) {
assertEquals(ms.getOption(IP_MULTICAST_IF), null);
}
}
@Test
public void testGetOptionUnbound() throws Exception {
out.println("\n\n--- testGetOptionUnbound ");
try (MulticastSocket ms = new MulticastSocket()) {
assertEquals(ms.getOption(IP_MULTICAST_IF), null);
}
}
// Asserts that the placeholder NetworkInterface has a single InetAddress
// that represent any local address.
static void assertPlaceHolder(NetworkInterface nif) {
List<InetAddress> addrs = nif.inetAddresses().collect(toList());
assertEquals(addrs.size(), 1);
assertTrue(addrs.get(0).isAnyLocalAddress());
}
}

View file

@ -0,0 +1,65 @@
/*
* Copyright (c) 1998, 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.io.UncheckedIOException;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.net.NetworkInterface;
import jdk.test.lib.NetworkConfiguration;
import jdk.test.lib.net.IPSupport;
/**
* @test
* @bug 4091811 4148753 4102731
* @summary Test java.net.MulticastSocket joinGroup and leaveGroup
* @library /test/lib
* @build jdk.test.lib.NetworkConfiguration
* jdk.test.lib.Platform
* @run main JoinLeave
* @run main/othervm -Djava.net.preferIPv4Stack=true JoinLeave
*/
public class JoinLeave {
public static void main(String args[]) throws IOException {
IPSupport.throwSkippedExceptionIfNonOperational();
InetAddress ip4Group = InetAddress.getByName("224.80.80.80");
InetAddress ip6Group = InetAddress.getByName("ff02::a");
NetworkConfiguration nc = NetworkConfiguration.probe();
nc.ip4MulticastInterfaces().forEach(nic -> joinLeave(ip4Group, nic));
nc.ip6MulticastInterfaces().forEach(nic -> joinLeave(ip6Group, nic));
}
static void joinLeave(InetAddress group, NetworkInterface nif) {
System.out.println("Joining:" + group + " on " + nif);
try (MulticastSocket soc = new MulticastSocket()) {
soc.setNetworkInterface(nif);
soc.joinGroup(group);
soc.leaveGroup(group);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
}

View file

@ -0,0 +1,127 @@
/*
* Copyright (c) 2015, 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
* @bug 8072466
* @summary Deadlock when initializing MulticastSocket and DatagramSocket
* @library /test/lib
* @run main/othervm MultiDead
*/
import java.net.DatagramSocket;
import java.net.MulticastSocket;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.CountDownLatch;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import jdk.test.lib.JDKToolLauncher;
import jdk.test.lib.Utils;
public class MultiDead {
private static final int THREAD_PAIR_COUNT = 4;
private static final int CHILDREN_COUNT = 20;
// at least 2.5 seconds for a child to complete
private static final long CHILD_TIMEOUT = 2500;
private static final long TIMEOUT =
Utils.adjustTimeout(CHILDREN_COUNT * CHILD_TIMEOUT * 2);
public static void main(String[] args) throws Throwable {
if (args.length == 0 || args[0].equals("parent")) {
parentProcess();
}
if (args.length > 0 && args[0].equals("child")) {
childProcess();
}
}
private static void parentProcess() throws Throwable {
JDKToolLauncher launcher = JDKToolLauncher
.createUsingTestJDK("java")
.addToolArg("MultiDead")
.addToolArg("child");
ProcessBuilder pb = new ProcessBuilder(launcher.getCommand());
AtomicReference<Process> child = new AtomicReference<>();
AtomicBoolean stopFlag = new AtomicBoolean(false);
Thread th = new Thread(() -> {
for (int i = 0; i < CHILDREN_COUNT; ++i) {
System.out.println("child #" + (i + 1) + " of " +
CHILDREN_COUNT);
long start = System.nanoTime();
try {
child.set(pb.start());
child.get().waitFor();
if (stopFlag.get()) {
break;
}
} catch (Exception e) {
throw new RuntimeException(e);
}
if (System.nanoTime() - start >
MILLISECONDS.toNanos(CHILD_TIMEOUT)) {
System.err.println("Machine is too slow, " +
"skipping the test...");
break;
}
}
});
th.start();
th.join(TIMEOUT);
stopFlag.set(true);
if (th.isAlive()) {
if (child.get() != null) {
child.get().destroyForcibly();
}
throw new RuntimeException("Failed to complete on time.");
}
}
private static void childProcess() {
CountDownLatch latch = new CountDownLatch(1);
for (int i = 0; i < THREAD_PAIR_COUNT; ++i) {
new Thread(() -> {
try {
latch.await();
try (MulticastSocket a = new MulticastSocket(6000)) {
}
} catch (Exception ignore) {
}
}).start();
new Thread(() -> {
try {
latch.await();
try (DatagramSocket b = new DatagramSocket(6000)) {
}
} catch (Exception ignore) {
}
}).start();
}
latch.countDown();
}
}

View file

@ -0,0 +1,140 @@
/*
* Copyright (c) 2001, 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 4488458
* @library /test/lib
* @summary Test that MutlicastSocket.joinGroup is working for
* various multicast and non-multicast addresses.
* @run main MulticastAddresses
*/
import jdk.test.lib.NetworkConfiguration;
import java.net.*;
import java.io.IOException;
import java.util.stream.Collectors;
public class MulticastAddresses {
public static void runTest(NetworkInterface ni,
String[] multicasts,
String[] nonMulticasts) throws Exception {
int failures = 0;
MulticastSocket s = new MulticastSocket();
/* test valid multicast addresses */
for (int i = 0; i < multicasts.length; i++) {
InetAddress ia = InetAddress.getByName(multicasts[i]);
System.out.println("Test: " + ia + " " + " ni: " + ni);
try {
System.out.print(" joinGroup(InetAddress) ");
s.joinGroup(ia);
s.leaveGroup(ia);
System.out.println(" Passed.");
System.out.print(" joinGroup(InetAddress,NetworkInterface) ");
s.joinGroup(new InetSocketAddress(ia, 0), ni);
s.leaveGroup(new InetSocketAddress(ia, 0), ni);
System.out.println(" Passed.");
} catch (IOException e) {
failures++;
System.out.println("Failed: " + e.getMessage());
}
}
/* test non-multicast addresses */
for (int i = 0; i < nonMulticasts.length; i++) {
InetAddress ia = InetAddress.getByName(nonMulticasts[i]);
boolean failed = false;
System.out.println("Test: " + ia + " ");
try {
System.out.println(" joinGroup(InetAddress) ");
s.joinGroup(ia);
System.out.println("Failed!! -- incorrectly joined group");
failed = true;
} catch (IOException e) {
System.out.println(" Passed: " + e.getMessage());
}
if (failed) {
s.leaveGroup(ia);
failures++;
}
}
s.close();
if (failures > 0) {
throw new Exception(failures + " test(s) failed - see log file.");
}
}
public static void main(String args[]) throws Exception {
String[] multicastIPv4 = {
"224.80.80.80",
};
String[] multicastIPv6 = {
"ff01::1",
"ff02::1234",
"ff05::a",
"ff0e::1234:a"};
String[] nonMulticastIPv4 = {
"129.1.1.1"
};
String[] nonMulticastIPv6 = {
"::1",
"::129.1.1.1",
"fe80::a00:20ff:fee5:bc02"};
/*
* Examine the network interfaces and determine :-
*
* 1. If host has IPv6 support
* 2. Get reference to a non-loopback interface
*/
NetworkConfiguration nc = NetworkConfiguration.probe();
var ipv6List = nc.ip6MulticastInterfaces(false)
.collect(Collectors.toList());
var ipv4List = nc.ip4MulticastInterfaces(false)
.collect(Collectors.toList());
if (ipv6List.retainAll(ipv4List)) {
runTest(ipv6List.get(0), multicastIPv4, nonMulticastIPv4);
runTest(ipv6List.get(0), multicastIPv6, nonMulticastIPv6);
} else {
if (!ipv4List.isEmpty())
runTest(ipv4List.get(0), multicastIPv4, nonMulticastIPv4);
if (!ipv6List.isEmpty())
runTest(ipv6List.get(0), multicastIPv6, nonMulticastIPv6);
}
}
}

View file

@ -0,0 +1,76 @@
/*
* Copyright (c) 2017, 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 8175325
* @summary test NetworkInterface getInterfaceAddresses method on the NetworkInterface returned
* from the getNetworkInterface invocation on a MulticastSocket bound to a wildcard address.
*
*/
import java.net.MulticastSocket;
import java.net.NetworkInterface;
import java.net.SocketException;
public class NetworkInterfaceEmptyGetInetAddressesTest {
static int exceptionCount = 0;
public static void testMethods(NetworkInterface netIf) throws Exception {
testNetworkInterface_getInterfaceAddresses(netIf);
if (exceptionCount > 0) {
throw new RuntimeException("Unexpected Exceptions in test");
}
}
private static void testNetworkInterface_getInterfaceAddresses(
NetworkInterface netIf) {
try {
netIf.getInterfaceAddresses();
} catch (Exception ex) {
ex.printStackTrace();
incrementExceptionCount();
}
}
private static void incrementExceptionCount() {
exceptionCount++;
}
public static void main(String[] args) throws Exception {
MulticastSocket mcastSock = null;
try {
mcastSock = new MulticastSocket();
System.out.println("macst socket address == "
+ mcastSock.getLocalAddress());
NetworkInterface netIf = mcastSock.getNetworkInterface();
testMethods(netIf);
} finally {
if (mcastSock != null) {
mcastSock.close();
}
}
}
}

View file

@ -0,0 +1,176 @@
/*
* Copyright (c) 2007, 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 4742177
* @summary Re-test IPv6 (and specifically MulticastSocket) with latest Linux & USAGI code
* @requires os.family != "windows"
* @library /test/lib
*/
import java.util.*;
import java.net.*;
import jdk.test.lib.NetworkConfiguration;
import jdk.test.lib.net.IPSupport;
public class NoLoopbackPackets {
private static final String MESSAGE = "hello world (" + System.nanoTime() + ")";
public static void main(String[] args) throws Exception {
MulticastSocket msock = null;
List<SocketAddress> failedGroups = new ArrayList<SocketAddress>();
Sender sender = null;
Thread senderThread = null;
try {
msock = new MulticastSocket();
int port = msock.getLocalPort();
// we will send packets to three multicast groups :-
// 224.1.1.1, ::ffff:224.1.1.2, and ff02::1:1
//
List<SocketAddress> groups = new ArrayList<SocketAddress>();
if (IPSupport.hasIPv4()) {
groups.add(new InetSocketAddress(InetAddress.getByName("224.1.1.1"), port));
}
NetworkConfiguration nc = NetworkConfiguration.probe();
if (IPSupport.hasIPv6() && nc.hasTestableIPv6Address()) {
groups.add(new InetSocketAddress(InetAddress.getByName("::ffff:224.1.1.2"), port));
groups.add(new InetSocketAddress(InetAddress.getByName("ff02::1:1"), port));
}
if (groups.isEmpty()) {
System.err.println("Nothing to test: there are no network interfaces");
}
sender = new Sender(groups);
senderThread = new Thread(sender);
senderThread.start();
// Now try to receive multicast packets. we should not see any of them
// since we disable loopback mode.
//
msock.setSoTimeout(5000); // 5 seconds
byte[] buf = new byte[1024];
for (int i = 0; i < buf.length; i++) {
buf[i] = (byte) 'z';
}
DatagramPacket packet = new DatagramPacket(buf, 0, buf.length);
byte[] expected = MESSAGE.getBytes();
assert expected.length <= buf.length;
for (SocketAddress group : groups) {
System.out.println("joining group: " + group);
msock.joinGroup(group, null);
try {
do {
for (int i = 0; i < buf.length; i++) {
buf[i] = (byte) 'a';
}
msock.receive(packet);
byte[] data = packet.getData();
int len = packet.getLength();
if (expected(data, len, expected)) {
failedGroups.add(group);
break;
} else {
System.err.println("WARNING: Unexpected packet received from "
+ group + ": "
+ len + " bytes");
System.err.println("\t as text: " + new String(data, 0, len));
}
} while (true);
} catch (SocketTimeoutException e) {
// we expect this
System.out.println("Received expected exception from " + group + ": " + e);
} finally {
msock.leaveGroup(group, null);
}
}
} finally {
if (msock != null) try { msock.close(); } catch (Exception e) {}
if (sender != null) {
sender.stop();
}
}
try {
if (failedGroups.size() > 0) {
System.out.println("We should not receive anything from following groups, but we did:");
for (SocketAddress group : failedGroups)
System.out.println(group);
throw new RuntimeException("test failed.");
}
} finally {
if (senderThread != null) {
senderThread.join();
}
}
}
static boolean expected(byte[] data, int len, byte[] expected) {
if (len != expected.length) return false;
for (int i = 0; i < len; i++) {
if (data[i] != expected[i]) return false;
}
return true;
}
static class Sender implements Runnable {
private List<SocketAddress> sendToGroups;
private volatile boolean stop;
public Sender(List<SocketAddress> groups) {
sendToGroups = groups;
}
public void run() {
byte[] buf = MESSAGE.getBytes();
List<DatagramPacket> packets = new ArrayList<DatagramPacket>();
try (MulticastSocket msock = new MulticastSocket()) {
for (SocketAddress group : sendToGroups) {
DatagramPacket packet = new DatagramPacket(buf, buf.length, group);
packets.add(packet);
}
msock.setLoopbackMode(true); // disable loopback mode
while (!stop) {
for (DatagramPacket packet : packets) {
msock.send(packet);
}
Thread.sleep(1000); // 1 second
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
void stop() {
stop = true;
}
}
}

View file

@ -0,0 +1,147 @@
/*
* 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 8233307
* @library /test/lib
* @run main/othervm NoSetNetworkInterface
* @run main/othervm -Djava.net.preferIPv4Stack=true NoSetNetworkInterface
* @run main/othervm -Djava.net.preferIPv6Addresses=true 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
*/
import jdk.test.lib.NetworkConfiguration;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.net.NetworkInterface;
import java.net.StandardSocketOptions;
import java.util.Optional;
import java.util.function.Predicate;
public class NoSetNetworkInterface {
public static void main(String[] args) throws Exception {
NetworkConfiguration nc = NetworkConfiguration.probe();
// check set and get methods work as expected
nc.multicastInterfaces(true).forEach(ni -> {
checkSetInterface(ni);
checkSetNetworkInterface(ni);
checkSetOption(ni);
});
// Check that dummy NetworkInterface is returned when not set
checkDummyNetworkInterface();
}
public static void checkSetInterface(NetworkInterface ni) {
try (MulticastSocket ms = new MulticastSocket()) {
Optional<InetAddress> iAddr = ni.inetAddresses()
.filter(Predicate.not(InetAddress::isAnyLocalAddress))
.findFirst();
if (iAddr.isPresent()) {
ms.setInterface(iAddr.get());
checkForCorrectNetworkInterface("setInterface", ms, ni);
}
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
public static void checkSetNetworkInterface(NetworkInterface ni) {
try (MulticastSocket ms = new MulticastSocket()) {
ms.setNetworkInterface(ni);
checkForCorrectNetworkInterface("setNetworkInterface", ms, ni);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
public static void checkSetOption(NetworkInterface ni) {
try (MulticastSocket ms = new MulticastSocket()) {
ms.setOption(StandardSocketOptions.IP_MULTICAST_IF, ni);
checkForCorrectNetworkInterface("setOption", ms, ni);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
public static void checkForCorrectNetworkInterface(String setterMethod,
MulticastSocket ms,
NetworkInterface ni) throws IOException {
// getInterface
InetAddress testAddr = ms.getInterface();
if (!ni.inetAddresses().anyMatch(i -> i.equals(testAddr))) {
throw new RuntimeException(setterMethod + " != getInterface");
}
// getNetworkInterface
if (!ni.equals(ms.getNetworkInterface())) {
throw new RuntimeException(setterMethod + " != getNetworkInterface");
}
// getOption
if (!ni.equals(ms.getOption(StandardSocketOptions.IP_MULTICAST_IF))) {
throw new RuntimeException(setterMethod + " != getOption");
}
}
public static void checkDummyNetworkInterface() throws IOException {
try(MulticastSocket ms = new MulticastSocket()) {
// getOption with no Network Interface set
NetworkInterface n0 = ms.getOption(StandardSocketOptions.IP_MULTICAST_IF);
if (n0 != null) {
throw new RuntimeException("NetworkInterface should be null");
}
// getNetworkInterface with no Network Interface set
NetworkInterface n1 = ms.getNetworkInterface();
if (n1 == null) {
throw new RuntimeException("getNetworkInterface() should not return null");
} else if (!((n1.getName().equals("0.0.0.0") || n1.getName().equals("::"))
&& (n1.getIndex() == 0)
&& (n1.inetAddresses().count() == 1))) {
throw new RuntimeException("Dummy NetworkInterface not returned as expected");
}
// getInterface with no Network Interface set
InetAddress iaddr = ms.getInterface();
if (iaddr == null) {
throw new RuntimeException("getInterface() should not return null");
} else if (!iaddr.isAnyLocalAddress()) {
throw new RuntimeException("getInterface() should return anyLocalAddress");
}
}
}
}

View file

@ -0,0 +1,196 @@
/*
* Copyright (c) 2013, 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 8014499 8219804
* @library /test/lib
* @summary Test for interference when two sockets are bound to the same
* port but joined to different multicast groups
* @run main Promiscuous
* @run main/othervm -Djava.net.preferIPv4Stack=true Promiscuous
*/
import java.io.IOException;
import static java.lang.System.out;
import java.io.UncheckedIOException;
import java.net.*;
import jdk.test.lib.NetworkConfiguration;
import jdk.test.lib.net.IPSupport;
public class Promiscuous {
static final int TIMEOUT = 5 * 1000; // 5 secs
static int id = 1000;
static void receive(MulticastSocket mc, boolean datagramExpected, int id)
throws IOException
{
byte[] ba = new byte[100];
DatagramPacket p;
try {
String data = null;
while (true) {
p = new DatagramPacket(ba, ba.length);
mc.receive(p);
data = new String(p.getData(), 0, p.getLength(), "UTF-8");
if (data.length() > UUID.length() && data.startsWith(UUID)) {
data = data.substring(UUID.length());
break;
}
logUnexpected(p);
}
int recvId = Integer.parseInt(data);
if (datagramExpected) {
if (recvId != id)
throw new RuntimeException("Unexpected id, got " + recvId
+ ", expected: " + id);
out.printf("Received message as expected, %s\n", p.getAddress());
} else {
throw new RuntimeException("Unexpected message received, "
+ p.getAddress());
}
} catch (SocketTimeoutException e) {
if (datagramExpected)
throw new RuntimeException(mc.getLocalSocketAddress()
+ ": Expected message not received, "
+ e.getMessage());
else
out.printf("Message not received, as expected\n");
}
}
static void logUnexpected(DatagramPacket p) {
byte[] ba = p.getData();
System.out.printf("Unexpected packet: length: %d. First three bytes: %d, %d, %d\n",
p.getLength(), ba[0], ba[1], ba[2]);
}
static final String UUID; // process-id : currentTimeMillis
static {
String s1 = Long.toString(ProcessHandle.current().pid());
String s2 = Long.toString(System.currentTimeMillis());
UUID = "<" + s1 + s2 + ">";
}
static SocketAddress toSocketAddress(InetAddress group) {
return new InetSocketAddress(group, 0);
}
static void test(InetAddress group1, InetAddress group2)
throws IOException
{
try (MulticastSocket mc1 = new MulticastSocket();
MulticastSocket mc2 = new MulticastSocket(mc1.getLocalPort());
DatagramSocket ds = new DatagramSocket()) {
final int port = mc1.getLocalPort();
out.printf("Using port: %d\n", port);
mc1.setSoTimeout(TIMEOUT);
mc2.setSoTimeout(TIMEOUT);
int nextId = id;
byte[] msg = (UUID + Integer.toString(nextId)).getBytes("UTF-8");
DatagramPacket p = new DatagramPacket(msg, msg.length);
p.setAddress(group1);
p.setPort(port);
// join groups on all network interfaces
NetworkConfiguration.probe()
.ip4MulticastInterfaces(false)
.forEach((nic) -> {
try {
mc1.joinGroup(toSocketAddress(group1), nic);
out.printf("mc1 joined the MC group on %s: %s\n",
nic.getDisplayName(), group1);
mc2.joinGroup(toSocketAddress(group2), nic);
out.printf("mc2 joined the MC group on %s: %s\n",
nic.getDisplayName(), group2);
} catch (IOException io) {
throw new UncheckedIOException(io);
}
});
out.printf("Sending datagram to: %s/%d\n", group1, port);
ds.send(p);
// the packet should be received by mc1 only
receive(mc1, true, nextId);
receive(mc2, false, 0);
nextId = ++id;
msg = (UUID + Integer.toString(nextId)).getBytes("UTF-8");
p = new DatagramPacket(msg, msg.length);
p.setAddress(group2);
p.setPort(port);
out.printf("Sending datagram to: %s/%d\n", group2, port);
ds.send(p);
// the packet should be received by mc2 only
receive(mc2, true, nextId);
receive(mc1, false, 0);
// leave groups on all network interfaces
NetworkConfiguration.probe()
.ip4MulticastInterfaces(false)
.forEach((nic) -> {
try {
mc1.leaveGroup(toSocketAddress(group1), nic);
out.printf("mc1 left the MC group on %s: %s\n",
nic.getDisplayName(), group1);
mc2.leaveGroup(toSocketAddress(group2), nic);
out.printf("mc2 left the MC group on %s: %s\n",
nic.getDisplayName(), group2);
} catch (IOException io) {
throw new UncheckedIOException(io);
}
});
}
}
public static void main(String args[]) throws IOException {
IPSupport.throwSkippedExceptionIfNonOperational();
String os = System.getProperty("os.name");
// Requires IP_MULTICAST_ALL on Linux (new since 2.6.31) so skip
// on older kernels. Note that we skip on <= version 3 to keep the
// parsing simple
if (os.equals("Linux")) {
String osversion = System.getProperty("os.version");
String[] vers = osversion.split("\\.", 0);
int major = Integer.parseInt(vers[0]);
if (major < 3) {
System.out.format("Kernel version is %s, test skipped%n", osversion);
return;
}
}
// multicast groups used for the test
InetAddress ip4Group1 = InetAddress.getByName("224.1.1.120");
InetAddress ip4Group2 = InetAddress.getByName("224.1.1.121");
test(ip4Group1, ip4Group2);
}
}

View file

@ -0,0 +1,175 @@
/*
* Copyright (c) 2018, 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 8215294
* @requires os.family == "linux" & !(os.version ~= "3\\.10\\.0.*")
* @comment This test should only be run on Linux.
* The behavior under test is known NOT to work on Linux 3.10.0* kernels.
* @library /test/lib
* @build jdk.test.lib.NetworkConfiguration
* PromiscuousIPv6
* @run main/othervm PromiscuousIPv6
* @key randomness
*/
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.Inet6Address;
import java.net.InetSocketAddress;
import java.net.MulticastSocket;
import java.net.NetworkInterface;
import java.net.SocketTimeoutException;
import java.net.StandardSocketOptions;
import java.util.List;
import java.util.Random;
import jdk.test.lib.NetworkConfiguration;
import jtreg.SkippedException;
import static java.lang.System.out;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.stream.Collectors.toList;
/*
* This test was created as a clone of the Promiscuous test and adapted for
* IPv6 node-local and link-local multicast addresses on Linux.
*/
public class PromiscuousIPv6 {
static final Random rand = new Random();
static final int TIMEOUT = 5 * 1000; // 5 secs
static int sendDatagram(NetworkInterface nif, InetAddress group, int port)
throws IOException
{
try (MulticastSocket mc = new MulticastSocket()) {
mc.setOption(StandardSocketOptions.IP_MULTICAST_IF, nif);
int id = rand.nextInt();
byte[] msg = Integer.toString(id).getBytes(UTF_8);
DatagramPacket p = new DatagramPacket(msg, msg.length);
p.setAddress(group);
p.setPort(port);
out.printf("Sending datagram to: %s/%d\n", group, port);
mc.send(p);
return id;
}
}
static void receiveDatagram(DatagramSocket mc, boolean datagramExpected, int id)
throws IOException
{
byte[] ba = new byte[100];
DatagramPacket p = new DatagramPacket(ba, ba.length);
try {
mc.receive(p);
int recvId = Integer.parseInt(
new String(p.getData(), 0, p.getLength(), UTF_8));
if (datagramExpected) {
if (recvId != id)
throw new RuntimeException("Unexpected id, got " + recvId
+ ", expected: " + id);
out.printf("Received message as expected, %s\n", p.getAddress());
} else {
throw new RuntimeException("Unexpected message received, "
+ p.getAddress());
}
} catch (SocketTimeoutException e) {
if (datagramExpected)
throw new RuntimeException("Expected message not received, "
+ e.getMessage());
else
out.printf("Message not received, as expected\n");
}
}
static void test(NetworkInterface nif, InetAddress group1, InetAddress group2)
throws IOException
{
// Bind addresses should include the same network interface / scope, so
// as to not reply on the default route when there are multiple interfaces
InetAddress bindAddr1 = Inet6Address.getByAddress(null, group1.getAddress(), nif);
InetAddress bindAddr2 = Inet6Address.getByAddress(null, group2.getAddress(), nif);
try (MulticastSocket mc1 = new MulticastSocket(new InetSocketAddress(bindAddr1, 0));
MulticastSocket mc2 = new MulticastSocket(new InetSocketAddress(bindAddr2, mc1.getLocalPort()))) {
final int port = mc1.getLocalPort();
out.printf("Using port: %d\n", port);
mc1.setSoTimeout(TIMEOUT);
mc2.setSoTimeout(TIMEOUT);
mc1.joinGroup(new InetSocketAddress(group1, 0), nif);
out.printf("mc1 joined the MC group: %s\n", group1);
mc2.joinGroup(new InetSocketAddress(group2, 0), nif);
out.printf("mc2 joined the MC group: %s\n", group2);
out.printf("Sending datagram to: %s/%d\n", group1, port);
int id = sendDatagram(nif, group1, port);
// the packet should be received by mc1 only
receiveDatagram(mc1, true, id);
receiveDatagram(mc2, false, 0);
out.printf("Sending datagram to: %s/%d\n", group2, port);
id = sendDatagram(nif, group2, port);
// the packet should be received by mc2 only
receiveDatagram(mc2, true, id);
receiveDatagram(mc1, false, 0);
mc1.leaveGroup(new InetSocketAddress(group1, 0), nif);
mc2.leaveGroup(new InetSocketAddress(group2, 0), nif);
}
}
public static void main(String args[]) throws IOException {
NetworkConfiguration.printSystemConfiguration(System.out);
List<NetworkInterface> nifs = NetworkConfiguration.probe()
.ip6MulticastInterfaces()
.collect(toList());
if (nifs.size() == 0) {
throw new SkippedException(
"No IPv6 interfaces that support multicast found");
}
InetAddress interfaceLocal1 = InetAddress.getByName("ff11::3.4.5.6");
InetAddress interfaceLocal2 = InetAddress.getByName("ff11::5.6.7.8");
InetAddress linkLocal1 = InetAddress.getByName("ff12::4.5.6.7");
InetAddress linkLocal2 = InetAddress.getByName("ff12::7.8.9.10");
for (NetworkInterface nif : nifs) {
test(nif, interfaceLocal1, interfaceLocal2);
test(nif, linkLocal1, linkLocal2);
}
}
}

View file

@ -0,0 +1,45 @@
/*
* Copyright (c) 2000, 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.net.MulticastSocket;
import java.net.BindException;
/*
* @test
* @summary Check if MulticastSocket sets SO_REUSEADDR
*/
public class Reuse {
public static void main(String[] args) throws Exception {
MulticastSocket s1, s2;
try {
s1 = new MulticastSocket(4160);
s2 = new MulticastSocket(4160);
s1.close();
s2.close();
} catch (BindException e) {
throw new RuntimeException("MulticastSocket do no set SO_REUSEADDR");
}
}
}

View file

@ -0,0 +1,102 @@
/*
* 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.
*/
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.MulticastSocket;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.MulticastSocket;
import java.net.SocketException;
import java.nio.channels.DatagramChannel;
import static org.testng.Assert.assertThrows;
/*
* @test
* @bug 8243408
* @summary Check that MulticastSocket throws expected
* Exception when sending a DatagramPacket with port 0
* @run testng/othervm SendPortZero
*/
public class SendPortZero {
private InetAddress loopbackAddr, wildcardAddr;
private MulticastSocket multicastSocket;
private DatagramPacket loopbackZeroPkt, wildcardZeroPkt, wildcardValidPkt;
private static final Class<SocketException> SE = SocketException.class;
@BeforeTest
public void setUp() throws IOException {
multicastSocket = new MulticastSocket();
byte[] buf = "test".getBytes();
// Addresses
loopbackAddr = InetAddress.getLoopbackAddress();
wildcardAddr = new InetSocketAddress(0).getAddress();
// Packets
// loopback w/port 0
loopbackZeroPkt = new DatagramPacket(buf, 0, buf.length);
loopbackZeroPkt.setAddress(loopbackAddr);
loopbackZeroPkt.setPort(0);
// wildcard w/port 0
wildcardZeroPkt = new DatagramPacket(buf, 0, buf.length);
wildcardZeroPkt.setAddress(wildcardAddr);
wildcardZeroPkt.setPort(0);
// wildcard addr w/valid port
// Not currently tested. See JDK-8236807
wildcardValidPkt = new DatagramPacket(buf, 0, buf.length);
wildcardValidPkt.setAddress(wildcardAddr);
wildcardValidPkt.setPort(multicastSocket.getLocalPort());
}
@DataProvider(name = "data")
public Object[][] variants() {
return new Object[][]{
{ multicastSocket, loopbackZeroPkt },
{ multicastSocket, wildcardZeroPkt },
// Not currently tested. See JDK-8236807
//{ multicastSocket, wildcardValidPkt }
};
}
@Test(dataProvider = "data")
public void testSend(MulticastSocket ms, DatagramPacket pkt) {
assertThrows(SE, () -> ms.send(pkt));
}
@AfterTest
public void tearDown() {
multicastSocket.close();
}
}

View file

@ -0,0 +1,72 @@
/*
* Copyright (c) 2013, 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.io.UncheckedIOException;
import java.net.MulticastSocket;
import java.net.NetworkInterface;
import jdk.test.lib.NetworkConfiguration;
import jdk.test.lib.net.IPSupport;
/**
* @test
* @bug 6458027
* @summary Disabling IPv6 on a specific network interface causes problems.
* @library /test/lib
* @build jdk.test.lib.NetworkConfiguration
* jdk.test.lib.Platform
* @run main SetGetNetworkInterfaceTest
* @run main/othervm -Djava.net.preferIPv4Stack=true SetGetNetworkInterfaceTest
*/
public class SetGetNetworkInterfaceTest {
public static void main(String[] args) throws Exception {
IPSupport.throwSkippedExceptionIfNonOperational();
NetworkConfiguration nc = NetworkConfiguration.probe();
try (MulticastSocket ms = new MulticastSocket()) {
nc.multicastInterfaces(true).forEach(nif -> setGetNetworkInterface(ms, nif));
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("Test passed.");
}
static void setGetNetworkInterface(MulticastSocket ms, NetworkInterface nif) {
try {
System.out.println(NetworkConfiguration.interfaceInformation(nif));
ms.setNetworkInterface(nif);
NetworkInterface msNetIf = ms.getNetworkInterface();
if (nif.equals(msNetIf)) {
System.out.println(" OK");
} else {
System.out.println("FAILED!!!");
System.out.println(NetworkConfiguration.interfaceInformation(msNetIf));
throw new RuntimeException("Test Fail");
}
System.out.println("------------------");
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
}

View file

@ -0,0 +1,178 @@
/*
* Copyright (c) 2001, 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 4686717
* @summary Test MulticastSocket.setLoopbackMode
* @library /test/lib
* @modules java.base/java.net:+open
* @build jdk.test.lib.NetworkConfiguration
* jdk.test.lib.Platform
* @run main/othervm SetLoopbackMode
*/
import java.lang.reflect.Method;
import java.lang.reflect.UndeclaredThrowableException;
import java.net.*;
import java.io.IOException;
import jdk.test.lib.NetworkConfiguration;
public class SetLoopbackMode {
static final boolean FAILED = true;
static final boolean PASSED = false;
static boolean test(MulticastSocket mc, InetAddress grp) throws IOException {
boolean disabled = mc.getLoopbackMode();
if (disabled) {
System.out.println("Loopback mode is disabled.");
} else {
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());
mc.send(p);
boolean gotPacket = false;
mc.setSoTimeout(1000);
try {
b = new byte[16];
p = new DatagramPacket(b, b.length);
mc.receive(p);
gotPacket = true;
/* purge any additional copies of the packet */
for (;;) {
mc.receive(p);
}
} catch (SocketTimeoutException x) {
}
if (gotPacket && disabled) {
System.out.println("Packet received (unexpected as loopback is disabled)");
return FAILED;
}
if (!gotPacket && !disabled) {
System.out.println
("Packet not received (packet excepted as loopback is enabled)");
return FAILED;
}
if (gotPacket && !disabled) {
System.out.println("Packet received - correct.");
} else {
System.out.println("Packet not received - correct.");
}
return PASSED;
}
private static boolean canUseIPv6(NetworkConfiguration nc) {
return nc.ip6MulticastInterfaces().toArray().length > 0;
}
public static void main (String args[]) throws Exception {
int failures = 0;
NetworkConfiguration nc = NetworkConfiguration.probe();
try (MulticastSocket mc = new MulticastSocket()) {
InetAddress grp = InetAddress.getByName("224.80.80.80");
/*
* If IPv6 is available then use IPv6 multicast group - needed
* to workaround Linux IPv6 bug whereby !IPV6_MULTICAST_LOOP
* doesn't prevent loopback of IPv4 multicast packets.
*/
if (canUseIPv6(nc)) {
System.out.println("IPv6 can be used");
grp = InetAddress.getByName("ff01::1");
} else {
System.out.println("IPv6 cannot be used: using IPv4");
}
System.out.println("Default network interface: " + DefaultInterface.getDefaultName());
System.out.println("\nTest will use multicast group: " + grp);
try {
System.out.println("NetworkInterface.getByInetAddress(grp): "
+ getName(NetworkInterface.getByInetAddress(grp)));
} catch (Exception x) {
// OK
}
mc.joinGroup(grp);
System.out.println("\n******************\n");
mc.setLoopbackMode(true);
if (test(mc, grp) == FAILED) failures++;
System.out.println("\n******************\n");
mc.setLoopbackMode(false);
if (test(mc, grp) == FAILED) failures++;
System.out.println("\n******************\n");
if (failures > 0) {
throw new RuntimeException("Test failed");
}
}
}
static String getName(NetworkInterface nif) {
return nif == null ? null : nif.getName();
}
static class DefaultInterface {
static final Method GET_DEFAULT;
static {
try {
GET_DEFAULT = Class.forName("java.net.DefaultInterface")
.getDeclaredMethod("getDefault");
GET_DEFAULT.setAccessible(true);
} catch (Exception x) {
throw new ExceptionInInitializerError(x);
}
}
static NetworkInterface getDefault() {
try {
return (NetworkInterface) GET_DEFAULT
.invoke(null);
} catch (Exception x) {
throw new UndeclaredThrowableException(x);
}
}
static String getDefaultName() {
return getName(getDefault());
}
}
}

View file

@ -0,0 +1,44 @@
/*
* Copyright (c) 2001, 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 4686717 8241786
* @summary Test MulticastSocket.setLoopbackMode with IPv4 addresses
* @library /test/lib
* @modules java.base/java.net:+open
* @build jdk.test.lib.NetworkConfiguration
* jdk.test.lib.Platform
* SetLoopbackMode
* SetLoopbackModeIPv4
* @run main/othervm -Djava.net.preferIPv4Stack=true SetLoopbackModeIPv4
*/
import jdk.test.lib.net.IPSupport;
public class SetLoopbackModeIPv4 {
public static void main(String[] args) throws Exception {
IPSupport.throwSkippedExceptionIfNonOperational();
SetLoopbackMode.main(args);
}
}

View file

@ -0,0 +1,303 @@
/*
* Copyright (c) 2019, 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 8233296
* @summary Check that MulticastSocket::setOption and MulticastSocket::getOption
* return the correct result for StandardSocketOptions.IP_MULTICAST_LOOP.
* The test sets a DatagramSocketImplFactory and needs to run in /othervm
* mode.
* @run testng/othervm SetLoopbackOption
* @run testng/othervm -Djava.net.preferIPv4Stack=true SetLoopbackOption
* @run testng/othervm -Djava.net.preferIPv6Addresses=true SetLoopbackOption
*/
import java.io.FileDescriptor;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.DatagramSocketImpl;
import java.net.DatagramSocketImplFactory;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.MulticastSocket;
import java.net.NetworkInterface;
import java.net.SocketAddress;
import java.net.SocketException;
import java.net.SocketOption;
import java.net.SocketOptions;
import java.net.StandardSocketOptions;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.testng.annotations.Test;
import static org.testng.Assert.*;
import static java.lang.System.out;
public class SetLoopbackOption {
final InetAddress loopbackAddress = InetAddress.getLoopbackAddress();
@Test
public void run() throws Exception {
var bindAddress = new InetSocketAddress(loopbackAddress, 0);
try (MulticastSocket sock = new MulticastSocket(null)) {
out.println("Testing unbound socket");
test(sock, null);
out.printf("\nBinding socket to %s and testing again%n", bindAddress);
sock.bind(bindAddress);
test(sock, null);
}
TestDatagramSocketImplFactory factory = new TestDatagramSocketImplFactory();
DatagramSocket.setDatagramSocketImplFactory(factory);
try (MulticastSocket sock = new MulticastSocket(null)) {
out.println("\nTesting unbound socket with custom impl");
TestDatagramSocketImpl impl = factory.last;
test(sock, impl);
out.printf("\nBinding socket to %s and testing again%n", bindAddress);
sock.bind(new InetSocketAddress(loopbackAddress, 0));
test(sock, impl);
}
}
private void test(MulticastSocket sock, TestDatagramSocketImpl impl) throws Exception {
out.println("Testing with " + sock.getClass() + (impl == null ? "" : ", " + impl.getClass()));
var op = StandardSocketOptions.IP_MULTICAST_LOOP;
var opId = SocketOptions.IP_MULTICAST_LOOP;
boolean enable = sock.getOption(op);
assertTrue(enable, "Initial Value for " + op);
boolean disable = sock.getLoopbackMode();
assertFalse(disable, "Initial Value for getLoopbackMode()");
if (impl != null) {
assertFalse((Boolean)impl.getOption(opId));
assertTrue((Boolean)impl.getOption(op));
}
out.println("Setting " + op + " to " + false);
if (impl != null) {
// allows setOption(SocketOption, Object) to be called
impl.allowAllSetOptions(true);
}
sock.setOption(op, false);
enable = sock.getOption(op);
assertFalse(enable, "Value for " + op);
disable = sock.getLoopbackMode();
assertTrue(disable, "Value for getLoopbackMode()");
if (impl != null) {
assertTrue((Boolean)impl.getOption(opId));
assertFalse((Boolean)impl.getOption(op));
}
out.println("Setting " + op + " to " + true);
sock.setOption(op, true);
enable = sock.getOption(op);
assertTrue(enable, "Value for " + op);
disable = sock.getLoopbackMode();
assertFalse(disable, "Value for getLoopbackMode()");
if (impl != null) {
assertFalse((Boolean)impl.getOption(opId));
assertTrue((Boolean)impl.getOption(op));
}
out.println("Calling setLoopbackMode(true)");
if (impl != null) {
// for backward compatibility reason, setLoopbackMode
// should call setOption(int, Object), not setOption(SocketOption, Object)
// Make sure that an exception is thrown if the latter is ever called.
impl.allowAllSetOptions(false);
}
sock.setLoopbackMode(true);
enable = sock.getOption(op);
assertFalse(enable, "Value for " + op);
disable = sock.getLoopbackMode();
assertTrue(disable, "Value for getLoopbackMode()");
if (impl != null) {
assertTrue((Boolean)impl.getOption(opId));
assertFalse((Boolean)impl.getOption(op));
}
out.println("Calling setLoopbackMode(false)");
sock.setLoopbackMode(false);
enable = sock.getOption(op);
assertTrue(enable, "Value for " + op);
disable = sock.getLoopbackMode();
assertFalse(disable, "Value for getLoopbackMode()");
if (impl != null) {
assertFalse((Boolean)impl.getOption(opId));
assertTrue((Boolean)impl.getOption(op));
}
}
// Used to attempt to control what is called/passed to the impl.
static class TestDatagramSocketImplFactory implements DatagramSocketImplFactory {
TestDatagramSocketImpl last;
public synchronized DatagramSocketImpl createDatagramSocketImpl() {
TestDatagramSocketImpl last = this.last;
if (last == null) {
return (last = this.last = new TestDatagramSocketImpl());
} else {
throw new AssertionError("Only one instance should be created");
}
}
}
// Used to attempt to control what is called/passed to the impl.
static class TestDatagramSocketImpl extends DatagramSocketImpl {
InetAddress address;
private boolean allowAllSetOptions;
@Override
protected void create() throws SocketException {
legacyOptions.put(SocketOptions.IP_MULTICAST_LOOP, false);
options.put(StandardSocketOptions.IP_MULTICAST_LOOP, true);
}
final Map<Integer, Object> legacyOptions = new HashMap<>();
final Map<SocketOption<?>, Object> options = new HashMap<>();
static <T> T shouldNotComeHere() {
throw new AssertionError("should not come here");
}
@Override
protected void bind(int lport, InetAddress laddr) throws SocketException {
this.localPort = (lport == 0 ? 6789 : lport);
this.address = laddr;
}
@Override
protected void send(DatagramPacket p) throws IOException {
shouldNotComeHere();
}
@Override
protected int peek(InetAddress i) throws IOException {
return shouldNotComeHere();
}
@Override
protected int peekData(DatagramPacket p) throws IOException {
return shouldNotComeHere();
}
@Override
protected void receive(DatagramPacket p) throws IOException {
shouldNotComeHere();
}
@Override
protected void setTimeToLive(int ttl) throws IOException {
shouldNotComeHere();
}
@Override
protected int getTimeToLive() throws IOException {
return shouldNotComeHere();
}
@Override
protected void join(InetAddress inetaddr) throws IOException {
shouldNotComeHere();
}
@Override
protected void leave(InetAddress inetaddr) throws IOException {
shouldNotComeHere();
}
@Override
protected void joinGroup(SocketAddress mcastaddr, NetworkInterface netIf)
throws IOException {
shouldNotComeHere();
}
@Override
protected void leaveGroup(SocketAddress mcastaddr, NetworkInterface netIf)
throws IOException {
shouldNotComeHere();
}
@Override
protected void close() {
}
@Override
public void setOption(int optID, Object value) throws SocketException {
legacyOptions.put(optID, value);
if (optID == SocketOptions.IP_MULTICAST_LOOP) {
boolean disable = (Boolean) value;
options.put(StandardSocketOptions.IP_MULTICAST_LOOP, !disable);
}
}
@Override
public Object getOption(int optID) throws SocketException {
return legacyOptions.get(optID);
}
@Override
protected Set<SocketOption<?>> supportedOptions() {
return Set.of(StandardSocketOptions.IP_MULTICAST_LOOP);
}
@Override
protected void connect(InetAddress address, int port) throws SocketException {
shouldNotComeHere();
}
@Override
protected void disconnect() {
shouldNotComeHere();
}
@Override
protected FileDescriptor getFileDescriptor() {
return super.getFileDescriptor();
}
@Override
protected <T> void setOption(SocketOption<T> name, T value) throws IOException {
if (!allowAllSetOptions) shouldNotComeHere();
options.put(name, value);
if (name.equals(StandardSocketOptions.IP_MULTICAST_LOOP)) {
boolean enable = (Boolean)value;
legacyOptions.put(SocketOptions.IP_MULTICAST_LOOP, !enable);
}
}
@Override
protected <T> T getOption(SocketOption<T> name) throws IOException {
return (T) options.get(name);
}
public void allowAllSetOptions(boolean allow) {
this.allowAllSetOptions = allow;
}
}
public static void main (String args[]) throws Exception {
new SetLoopbackOption().run();
}
}

View file

@ -0,0 +1,314 @@
/*
* Copyright (c) 2007, 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 4742177 8241786
* @summary Re-test IPv6 (and specifically MulticastSocket) with latest Linux & USAGI code
* @requires os.family != "windows"
* @library /test/lib
* @run main/othervm SetOutgoingIf
*/
import java.io.IOException;
import java.net.*;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import jdk.test.lib.NetworkConfiguration;
public class SetOutgoingIf implements AutoCloseable {
private final MulticastSocket SOCKET;
private final int PORT;
private final Map<NetIf, MulticastSender> sendersMap = new ConcurrentHashMap<>();
private SetOutgoingIf() {
try {
SOCKET = new MulticastSocket();
PORT = SOCKET.getLocalPort();
} catch (IOException io) {
throw new ExceptionInInitializerError(io);
}
}
static boolean isMacOS() {
return System.getProperty("os.name").contains("OS X");
}
private static boolean hasIPv6() throws Exception {
return NetworkConfiguration.probe()
.ip6Addresses()
.findAny()
.isPresent();
}
public static void main(String[] args) throws Exception {
try (var test = new SetOutgoingIf()) {
test.run();
}
}
@Override
public void close() {
try {
SOCKET.close();
} finally {
sendersMap.values().stream().forEach(MulticastSender::close);
}
}
public void run() throws Exception {
if (!hasIPv6()) {
System.out.println("No IPv6 available. Bye.");
return;
}
// We need 2 or more network interfaces to run the test
//
List<NetIf> netIfs = new ArrayList<NetIf>();
int index = 1;
for (NetworkInterface nic : Collections.list(NetworkInterface.getNetworkInterfaces())) {
// we should use only network interfaces with multicast support which are in "up" state
if (!nic.isLoopback() && nic.supportsMulticast() && nic.isUp() && !isTestExcludedInterface(nic)) {
NetIf netIf = NetIf.create(nic);
// now determine what (if any) type of addresses are assigned to this interface
for (InetAddress addr : Collections.list(nic.getInetAddresses())) {
if (addr.isAnyLocalAddress())
continue;
System.out.println(" addr " + addr);
if (addr instanceof Inet4Address) {
netIf.ipv4Address(true);
} else if (addr instanceof Inet6Address) {
netIf.ipv6Address(true);
}
}
if (netIf.ipv4Address() || netIf.ipv6Address()) {
netIf.index(index++);
netIfs.add(netIf);
debug("Using: " + nic);
}
} else {
System.out.println("Ignore NetworkInterface nic == " + nic);
}
}
Collections.reverse(netIfs);
if (netIfs.size() <= 1) {
System.out.println("Need 2 or more network interfaces to run. Bye.");
return;
}
System.out.println("Using PORT: " + PORT);
// We will send packets to one ipv4, and one ipv6
// multicast group using each network interface :-
// 224.1.1.1 --|
// ff02::1:1 --|--> using network interface #1
// 224.1.2.1 --|
// ff02::1:2 --|--> using network interface #2
// and so on.
//
for (NetIf netIf : netIfs) {
int NetIfIndex = netIf.index();
List<InetAddress> groups = new ArrayList<InetAddress>();
if (netIf.ipv4Address()) {
InetAddress groupv4 = InetAddress.getByName("224.1." + NetIfIndex + ".1");
groups.add(groupv4);
}
if (netIf.ipv6Address()) {
InetAddress groupv6 = InetAddress.getByName("ff02::1:" + NetIfIndex);
groups.add(groupv6);
}
debug("Adding " + groups + " groups for " + netIf.nic().getName());
netIf.groups(groups);
// use a separated thread to send to those 2 groups
var multicastSender = new MulticastSender(netIf, groups, PORT);
sendersMap.put(netIf, multicastSender);
Thread sender = new Thread(multicastSender);
sender.setDaemon(true); // we want sender to stop when main thread exits
sender.start();
}
// try to receive on each group, then check if the packet comes
// from the expected network interface
//
byte[] buf = new byte[1024];
for (NetIf netIf : netIfs) {
NetworkInterface nic = netIf.nic();
for (InetAddress group : netIf.groups()) {
try (MulticastSocket mcastsock = new MulticastSocket(PORT)) {
mcastsock.setSoTimeout(5000); // 5 second
DatagramPacket packet = new DatagramPacket(buf, 0, buf.length);
// the interface supports the IP multicast group
debug("Joining " + group + " on " + nic.getName());
mcastsock.joinGroup(new InetSocketAddress(group, PORT), nic);
try {
mcastsock.receive(packet);
debug("received packet on " + packet.getAddress());
} catch (Exception e) {
// test failed if any exception
throw new RuntimeException(e);
}
// now check which network interface this packet comes from
NetworkInterface from = NetworkInterface.getByInetAddress(packet.getAddress());
NetworkInterface shouldbe = nic;
if (from != null) {
if (!from.equals(shouldbe)) {
System.out.println("Packets on group "
+ group + " should come from "
+ shouldbe.getName() + ", but came from "
+ from.getName());
}
}
mcastsock.leaveGroup(new InetSocketAddress(group, PORT), nic);
}
}
}
}
private static boolean isTestExcludedInterface(NetworkInterface nif) {
return !NetworkConfiguration.isTestable(nif)
|| isMacOS() && nif.getName().startsWith("utun")
|| !NetworkConfiguration.hasNonLinkLocalAddress(nif);
}
private static boolean debug = true;
static void debug(String message) {
if (debug)
System.out.println(message);
}
}
class MulticastSender implements Runnable, AutoCloseable {
private final NetIf netIf;
private final List<InetAddress> groups;
private final int port;
private volatile boolean closed;
private long count;
public MulticastSender(NetIf netIf,
List<InetAddress> groups,
int port) {
this.netIf = netIf;
this.groups = groups;
this.port = port;
}
@Override
public void close() {
closed = true;
}
public void run() {
var nic = netIf.nic();
try (MulticastSocket mcastsock = new MulticastSocket()) {
mcastsock.setNetworkInterface(nic);
List<DatagramPacket> packets = new LinkedList<DatagramPacket>();
byte[] buf = "hello world".getBytes();
for (InetAddress group : groups) {
packets.add(new DatagramPacket(buf, buf.length, new InetSocketAddress(group, port)));
}
while (!closed) {
for (DatagramPacket packet : packets) {
mcastsock.send(packet);
count++;
}
System.out.printf("Sent %d packets from %s\n", count, nic.getName());
Thread.sleep(1000); // sleep 1 second
}
} catch (Exception e) {
if (!closed) {
System.err.println("Unexpected exception for MulticastSender("
+ nic.getName() + "): " + e);
e.printStackTrace();
throw new RuntimeException(e);
}
} finally {
System.out.printf("Sent %d packets from %s\n", count, nic.getName());
}
}
}
@SuppressWarnings("unchecked")
class NetIf {
private boolean ipv4Address; //false
private boolean ipv6Address; //false
private int index;
List<InetAddress> groups = Collections.EMPTY_LIST;
private final NetworkInterface nic;
private NetIf(NetworkInterface nic) {
this.nic = nic;
}
static NetIf create(NetworkInterface nic) {
return new NetIf(nic);
}
NetworkInterface nic() {
return nic;
}
boolean ipv4Address() {
return ipv4Address;
}
void ipv4Address(boolean ipv4Address) {
this.ipv4Address = ipv4Address;
}
boolean ipv6Address() {
return ipv6Address;
}
void ipv6Address(boolean ipv6Address) {
this.ipv6Address = ipv6Address;
}
int index() {
return index;
}
void index(int index) {
this.index = index;
}
List<InetAddress> groups() {
return groups;
}
void groups(List<InetAddress> groups) {
this.groups = groups;
}
}

View file

@ -0,0 +1,46 @@
/*
* Copyright (c) 1998, 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 4148757
* @summary Make sure TTL can be set to 0
* @run main SetTTLTo0
*/
import java.net.*;
public class SetTTLTo0 {
public static void main(String args[]) throws Exception {
MulticastSocket soc = null;
try {
soc = new MulticastSocket();
} catch(Exception e) {
throw new Exception("Unexpected Exception");
}
soc.setTimeToLive(0);
}
}

View file

@ -0,0 +1,182 @@
/*
* 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
* 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.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.net.SocketTimeoutException;
import jdk.test.lib.NetworkConfiguration;
import jdk.test.lib.net.IPSupport;
/**
* @test
* @bug 4488458
* @summary IPv4 and IPv6 multicasting broken on Linux
* @library /test/lib
* @build jdk.test.lib.NetworkConfiguration
* jdk.test.lib.Platform
* @run main Test
* @run main/othervm -Djava.net.preferIPv4Stack=true Test
*/
public class Test {
static int count = 0;
static int failures = 0;
void doTest(String address) throws IOException {
boolean failed = false;
InetAddress ia = InetAddress.getByName(address);
count++;
System.out.println("**********************");
System.out.println("Test " + count + ": " + ia);
MulticastSocket mc = new MulticastSocket();
int port = mc.getLocalPort();
DatagramSocket s1 = new DatagramSocket();
byte msg[] = "Hello".getBytes();
DatagramPacket p = new DatagramPacket(msg, msg.length);
mc.setSoTimeout(2000);
try {
for (int i=0; i<2; i++) {
System.out.println("Join: " + ia);
mc.joinGroup(ia);
/* packets should be received */
for (int j = 0; j < 2; j++) {
p.setAddress(ia);
p.setPort(port);
System.out.println("Send packet to: " + ia);
s1.send(p);
try {
mc.receive(p);
System.out.println("Got packet! - Good.");
} catch (SocketTimeoutException e) {
failed = true;
System.out.println("Failed: No packet received within timeout!!!");
}
}
System.out.println("Leave: " + ia);
mc.leaveGroup(ia);
/*
* If there are multiple interface we might be a couple of
* copies still in our queue
*/
try {
while (true) {
mc.receive(p);
}
} catch (SocketTimeoutException e) { }
/* packets should not be received */
p.setAddress(ia);
p.setPort(port);
s1.send(p);
try {
mc.receive(p);
System.out.println("Failed: Got packet after leaving group!!!");
failed = true;
} catch (SocketTimeoutException e) {
System.out.println("No packet received within timeout! - Good.");
}
}
} catch (IOException ioe) {
System.out.println("Failed: Unexpected exception thrown: ");
ioe.printStackTrace();
failed = true;
}
mc.close();
s1.close();
if (failed) {
failures++;
System.out.println("Test failed!!");
} else {
System.out.println("Test passed.");
}
}
void allTests() throws IOException {
NetworkConfiguration nc = NetworkConfiguration.probe();
// unconditionally test IPv4 address
doTest("224.80.80.80");
// If IPv6 is enabled perform multicast tests with various scopes
if (nc.hasTestableIPv6Address()) {
doTest("ff01::a");
}
if (nc.hasLinkLocalAddress()) {
doTest("ff02::a");
}
if (nc.hasSiteLocalAddress()) {
doTest("ff05::a");
}
if (nc.has_globaladdress()) {
doTest("ff0e::a");
}
}
public static void main(String args[]) throws Exception {
IPSupport.throwSkippedExceptionIfNonOperational();
Test t = new Test();
if (args.length == 0) {
t.allTests();
} else {
for (int i = 0; i < args.length; i++) {
t.doTest(args[i]);
}
}
System.out.println("**********************");
System.out.println(count + " test(s) executed. " + failures +
" test(s) failed.");
if (failures > 0) {
throw new Exception("Test failed - see log file for details");
}
}
}

View file

@ -0,0 +1,52 @@
/*
* Copyright (c) 2001, 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 4488458
* @summary Test that MutlicastSocket.getInterface, getTimeToLive, and
* getLoopbackMode work as expected on Linux 2.2 kernel
* if IPv6 is enabled.
*/
import java.net.*;
public class TestDefaults {
public static void main(String args[]) throws Exception {
MulticastSocket mc = new MulticastSocket();
int ttl = mc.getTimeToLive();
InetAddress ia = mc.getInterface();
boolean mode = mc.getLoopbackMode();
System.out.println("Default multicast settings:");
System.out.println(" ttl: " + ttl);
System.out.println("interface: " + ia);
System.out.println(" loopback: " + mode);
if (ttl != 1) {
throw new Exception("Default ttl != 1 -- test failed!!!");
}
}
}

View file

@ -0,0 +1,154 @@
/*
* Copyright (c) 2001, 2017, 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 4422122
* @summary Test that MulticastSocket.getInterface returns the
* same InetAddress set by MulticastSocket.setInterface
* @library /test/lib
* @build jdk.test.lib.NetworkConfiguration
* jdk.test.lib.Platform
* @run main TestInterfaces
*/
import jdk.test.lib.NetworkConfiguration;
import java.net.*;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.io.IOException;
public class TestInterfaces {
static final boolean isWindows = System.getProperty("os.name").startsWith("Windows");
public static void main(String args[]) throws Exception {
int failures = 0;
MulticastSocket soc = new MulticastSocket();
Enumeration nifs = NetworkInterface.getNetworkInterfaces();
while (nifs.hasMoreElements()) {
NetworkInterface ni = (NetworkInterface)nifs.nextElement();
// JDK-8022963, Skip (Windows) Teredo Tunneling Pseudo-Interface
String dName = ni.getDisplayName();
if (isWindows && dName != null && dName.contains("Teredo"))
continue;
// Skip those interfaces not up or not support multicast
if (!ni.isUp() || !ni.supportsMulticast())
continue;
/*
* Test MulticastSocket.getInterface
*/
System.out.println("Testing network interface " + ni);
Enumeration addrs = ni.getInetAddresses();
while (addrs.hasMoreElements()) {
InetAddress ia = (InetAddress)addrs.nextElement();
System.out.println("********************************");
System.out.println("MulticastSocket.setInterface(" + ia + ")");
try {
soc.setInterface(ia);
} catch (IOException ioe) {
System.err.println("Can't set interface to: " + ia
+ " " + ioe.getMessage());
continue;
}
InetAddress curr = soc.getInterface();
if (!curr.equals(ia)) {
System.err.println("NetworkInterface under test " + ni);
displayInterfaceInformation(ni);
System.err.println("MulticastSocket.getInterface returned: " + curr);
System.err.println("Failed! Expected: " + ia);
failures++;
} else {
System.out.println("Passed.");
}
}
/*
* Test MulticastSocket.getNetworkInterface
*/
System.out.println("********************************");
System.out.println("MulticastSocket.setNetworkInterface(" +
ni.getName() + ")");
try {
soc.setNetworkInterface(ni);
} catch (IOException ioe) {
System.err.println("Can't set interface to: " + ni.getName()
+ " " + ioe.getMessage());
continue;
}
NetworkInterface curr = soc.getNetworkInterface();
if (!curr.equals(ni)) {
System.err.println("MulticastSocket.getNetworkInterface returned: " + curr);
System.err.println("Failed! Expected: " + ni);
System.err.println("NetworkInterface details for curr variable ");
displayInterfaceInformation(curr);
System.err.println("NetworkInterface details for ni variable ");
displayInterfaceInformation(ni) ;
failures++;
} else {
System.out.println("Passed.");
}
}
if (failures > 0) {
System.err.println("********************************");
NetworkConfiguration.printSystemConfiguration(System.err);
System.out.println("********************************");
throw new Exception(failures + " test(s) failed!!!");
}
}
static void displayInterfaceInformation(NetworkInterface netint) throws SocketException {
System.err.println("Display name: " + netint.getDisplayName());
System.err.println("Name: " + netint.getName());
Enumeration<InetAddress> inetAddresses = netint.getInetAddresses();
for (InetAddress inetAddress : Collections.list(inetAddresses))
System.err.println("InetAddress: " + inetAddress);
System.err.println("Up? " + netint.isUp());
System.err.println("Loopback? " + netint.isLoopback());
System.err.println("PointToPoint? " + netint.isPointToPoint());
System.err.println("Supports multicast? " + netint.supportsMulticast());
System.err.println("Virtual? " + netint.isVirtual());
System.err.println("Hardware address: " +
Arrays.toString(netint.getHardwareAddress()));
System.err.println("MTU: " + netint.getMTU());
System.err.println("Index: " + netint.getIndex());
System.err.println();
}
}

View file

@ -0,0 +1,64 @@
/*
* Copyright (c) 1998, 2016, 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 4091012
*
* @summary Tests MulticastSocket send for new set/getTimeToLived
*
*/
import java.net.*;
public class TimeToLive {
static int[] new_ttls = { 0, 1, 127, 254, 255 };
static int[] bad_ttls = { -1, 256 };
public static void main(String[] args) throws Exception {
try (MulticastSocket socket = new MulticastSocket()) {
int ttl = socket.getTimeToLive();
System.out.println("default ttl: " + ttl);
for (int i = 0; i < new_ttls.length; i++) {
socket.setTimeToLive(new_ttls[i]);
if (!(new_ttls[i] == socket.getTimeToLive())) {
throw new RuntimeException("test failure, set/get differ: " +
new_ttls[i] + " / " +
socket.getTimeToLive());
}
}
for (int j = 0; j < bad_ttls.length; j++) {
boolean exception = false;
try {
socket.setTimeToLive(bad_ttls[j]);
} catch (IllegalArgumentException e) {
exception = true;
}
if (!exception) {
throw new RuntimeException("bad argument accepted: " + bad_ttls[j]);
}
}
}
}
}

View file

@ -0,0 +1,318 @@
/*
* Copyright (c) 2018, 2026, 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
* @modules java.management java.base/java.io:+open java.base/java.net:+open
* java.base/sun.nio.ch:+open
* @run main/othervm/timeout=480 -Djava.net.preferIPv4Stack=true UnreferencedMulticastSockets
* @run main/othervm/timeout=480 UnreferencedMulticastSockets
* @summary Check that unreferenced multicast sockets are closed
*/
import java.io.FileDescriptor;
import java.lang.management.ManagementFactory;
import java.lang.management.OperatingSystemMXBean;
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.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.util.ArrayDeque;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.Phaser;
import java.util.concurrent.TimeUnit;
import jdk.test.lib.net.IPSupport;
import com.sun.management.UnixOperatingSystemMXBean;
public class UnreferencedMulticastSockets {
/**
* The set of sockets we have to check up on.
*/
final static ArrayDeque<NamedWeak> pendingSockets = new ArrayDeque<>(5);
/**
* Queued objects when they are unreferenced.
*/
final static ReferenceQueue<Object> pendingQueue = new ReferenceQueue<>();
// Server to echo a datagram packet
static class Server implements Runnable {
MulticastSocket ss;
final int port;
final Phaser phaser = new Phaser(2);
Server() throws IOException {
InetAddress loopback = InetAddress.getLoopbackAddress();
InetSocketAddress serverAddress =
new InetSocketAddress(loopback, 0);
ss = new MulticastSocket(serverAddress);
port = ss.getLocalPort();
System.out.printf(" DatagramServer addr: %s: %d%n",
this.getHost(), this.getPort());
pendingSockets.add(new NamedWeak(ss, pendingQueue, "serverMulticastSocket"));
extractRefs(ss, "serverMulticastSocket");
}
InetAddress getHost() throws UnknownHostException {
InetAddress localhost = InetAddress.getLoopbackAddress();
return localhost;
}
int getPort() {
return port;
}
// Receive a byte and send back a byte
public void run() {
try {
byte[] buffer = new byte[50];
DatagramPacket p = new DatagramPacket(buffer, buffer.length);
ss.receive(p);
System.out.printf("Server: ping received from: %s%n", p.getSocketAddress());
phaser.arriveAndAwaitAdvance(); // await the client...
buffer[0] += 1;
System.out.printf("Server: sending echo to: %s%n", p.getSocketAddress());
ss.send(p); // send back +1
System.out.printf("Server: awaiting client%n");
phaser.arriveAndAwaitAdvance(); // await the client...
// do NOT close but 'forget' the socket reference
System.out.printf("Server: forgetting socket...%n");
ss = null;
} catch (Throwable ioe) {
ioe.printStackTrace();
}
}
}
public static void main(String args[]) throws Exception {
IPSupport.throwSkippedExceptionIfNonOperational();
InetSocketAddress clientAddress =
new InetSocketAddress(InetAddress.getLoopbackAddress(), 0);
// Create and close a MulticastSocket to warm up the FD count for side effects.
try (MulticastSocket s = new MulticastSocket(clientAddress)) {
// no-op; close immediately
s.getLocalPort(); // no-op
}
long fdCount0 = getFdCount();
listProcFD();
// start a server
Server svr = new Server();
Thread thr = new Thread(svr);
thr.start();
// It is possible under some circumstances that the client
// might get bound to the same port than the server: this
// would make the test fail - so if this happen we try to
// bind to a specific port by incrementing the server port.
MulticastSocket client = null;
int serverPort = svr.getPort();
int maxtries = 20;
for (int i = 0; i < maxtries; i++) {
try {
System.out.printf("Trying to bind client to: %s%n", clientAddress);
client = new MulticastSocket(clientAddress);
if (client.getLocalPort() != svr.getPort()) break;
client.close();
} catch (IOException x) {
System.out.printf("Couldn't create client after %d attempts: %s%n", i, x);
if (i == maxtries) throw x;
}
if (i == maxtries) {
String msg = String.format("Couldn't create client after %d attempts", i);
System.out.println(msg);
throw new AssertionError(msg);
}
clientAddress = new InetSocketAddress(clientAddress.getAddress(), serverPort + i);
}
System.out.printf(" client bound port: %s:%d%n",
client.getLocalAddress(), client.getLocalPort());
client.connect(svr.getHost(), svr.getPort());
pendingSockets.add(new NamedWeak(client, pendingQueue, "clientMulticastSocket"));
extractRefs(client, "clientMulticastSocket");
byte[] msg = new byte[1];
msg[0] = 1;
DatagramPacket p = new DatagramPacket(msg, msg.length, svr.getHost(), svr.getPort());
client.send(p);
System.out.printf(" ping sent to: %s:%d%n", svr.getHost(), svr.getPort());
svr.phaser.arriveAndAwaitAdvance(); // wait until the server has received its packet
p = new DatagramPacket(msg, msg.length);
client.receive(p);
System.out.printf(" echo received from: %s%n", p.getSocketAddress());
if (msg[0] != 2) {
throw new AssertionError("incorrect data received: expected: 2, actual: " + msg[0]);
}
svr.phaser.arriveAndAwaitAdvance(); // let the server null out its socket
// Do NOT close the MulticastSocket; forget it
Object ref;
int loops = 20;
while (!pendingSockets.isEmpty() && loops-- > 0) {
ref = pendingQueue.remove(1000L);
if (ref != null) {
pendingSockets.remove(ref);
System.out.printf(" ref freed: %s, remaining: %d%n", ref, pendingSockets.size());
} else {
client = null;
p = null;
msg = null;
System.gc();
}
}
thr.join();
// List the open file descriptors
long fdCount = getFdCount();
System.out.printf("Initial fdCount: %d, final fdCount: %d%n", fdCount0, fdCount);
listProcFD();
if (loops == 0) {
throw new AssertionError("Not all references reclaimed");
}
}
// Get the count of open file descriptors, or -1 if not available
private static long getFdCount() {
OperatingSystemMXBean mxBean = ManagementFactory.getOperatingSystemMXBean();
return (mxBean instanceof UnixOperatingSystemMXBean)
? ((UnixOperatingSystemMXBean) mxBean).getOpenFileDescriptorCount()
: -1L;
}
// 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);
// MulticastSocket using DatagramSocketAdaptor
Object MulticastSocket = datagramSocketField.get(s);
Method m = DatagramSocket.class.getDeclaredMethod("getChannel");
m.setAccessible(true);
DatagramChannel datagramChannel = (DatagramChannel) m.invoke(MulticastSocket);
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);
} catch (Exception ex) {
ex.printStackTrace();
throw new AssertionError("missing field", ex);
}
}
private static void extractRefs(FileDescriptor fileDescriptor, String name) {
Object cleanup = null;
int rawfd = -1;
try {
if (fileDescriptor != null) {
Field fd1Field = FileDescriptor.class.getDeclaredField("fd");
fd1Field.setAccessible(true);
rawfd = fd1Field.getInt(fileDescriptor);
Field cleanupfdField = FileDescriptor.class.getDeclaredField("cleanup");
cleanupfdField.setAccessible(true);
cleanup = cleanupfdField.get(fileDescriptor);
pendingSockets.add(new NamedWeak(fileDescriptor, pendingQueue,
name + "::fileDescriptor: " + rawfd));
pendingSockets.add(new NamedWeak(cleanup, pendingQueue, name + "::fdCleanup: " + rawfd));
}
} catch (NoSuchFieldException | IllegalAccessException ex) {
ex.printStackTrace();
throw new AssertionError("missing field", ex);
} finally {
System.out.print(String.format(" %s:: fd: %s, fd: %d, cleanup: %s%n",
name, fileDescriptor, rawfd, cleanup));
}
}
/**
* Method to list the open file descriptors (if supported by the 'lsof' command).
*/
static void listProcFD() {
List<String> lsofDirs = List.of("/usr/bin", "/usr/sbin");
Optional<Path> lsof = lsofDirs.stream()
.map(s -> Paths.get(s, "lsof"))
.filter(f -> Files.isExecutable(f))
.findFirst();
lsof.ifPresent(exe -> {
try {
System.out.printf("Open File Descriptors:%n");
long pid = ProcessHandle.current().pid();
ProcessBuilder pb = new ProcessBuilder(exe.toString(), "-p", Integer.toString((int) pid));
pb.inheritIO();
Process p = pb.start();
p.waitFor(10, TimeUnit.SECONDS);
} catch (IOException | InterruptedException ie) {
ie.printStackTrace();
}
});
}
// Simple class to identify which refs have been queued
static class NamedWeak extends WeakReference<Object> {
private final String name;
NamedWeak(Object o, ReferenceQueue<Object> queue, String name) {
super(o, queue);
this.name = name;
}
public String toString() {
return name + "; " + super.toString();
}
}
}