8335771: Improve stability of java/nio/channels/DatagramChannel tests

Reviewed-by: alanb
This commit is contained in:
Daniel Fuchs 2024-08-19 13:47:40 +00:00
parent 2766b09e29
commit 3ca359ad22
11 changed files with 365 additions and 112 deletions

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 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
@ -48,6 +48,7 @@ import java.util.List;
import java.util.stream.Collectors;
import static java.net.StandardSocketOptions.*;
import static java.net.StandardProtocolFamily.*;
import static jdk.test.lib.NetworkConfiguration.isSameInterface;
import jdk.test.lib.NetworkConfiguration;
import jdk.test.lib.net.IPSupport;
@ -295,8 +296,8 @@ public class AdaptorMulticasting {
// setNetworkInterface
s.setNetworkInterface(ni);
assertTrue(s.getNetworkInterface().equals(ni));
assertTrue(s.getOption(IP_MULTICAST_IF).equals(ni));
assertTrue(isSameInterface(s.getNetworkInterface(), ni));
assertTrue(isSameInterface(s.getOption(IP_MULTICAST_IF), ni));
InetAddress address = s.getInterface();
assertTrue(ni.inetAddresses().filter(address::equals).findAny().isPresent());
@ -315,8 +316,8 @@ public class AdaptorMulticasting {
// setOption(IP_MULTICAST_IF)
s.setOption(IP_MULTICAST_IF, ni);
assertTrue(s.getOption(IP_MULTICAST_IF).equals(ni));
assertTrue(s.getNetworkInterface().equals(ni));
assertTrue(isSameInterface(s.getOption(IP_MULTICAST_IF), ni));
assertTrue(isSameInterface(s.getNetworkInterface(), ni));
// bad values for IP_MULTICAST_IF
assertThrows(IllegalArgumentException.class,
@ -412,7 +413,8 @@ public class AdaptorMulticasting {
assertTrue(s.getOption(IP_MULTICAST_IF) != null);
SocketAddress target = new InetSocketAddress(group, s.getLocalPort());
byte[] message = "hello".getBytes("UTF-8");
String msg = "AdaptorMulticasting: " + System.nanoTime();
byte[] message = msg.getBytes("UTF-8");
// send message to multicast group
DatagramPacket p = new DatagramPacket(message, message.length);
@ -421,8 +423,22 @@ public class AdaptorMulticasting {
// receive message
s.setSoTimeout(0);
p = new DatagramPacket(new byte[1024], 100);
s.receive(p);
while (true) {
p = new DatagramPacket(new byte[1024], 100);
s.receive(p);
if (p.getPort() == s.getLocalPort()) {
String str = new String(p.getData(), p.getOffset(), p.getLength(), "UTF-8");
if (Arrays.equals(p.getData(), p.getOffset(), p.getLength(), message, 0, message.length)) {
System.out.format("Got expected message \"%s\" from %s%n", str, p.getSocketAddress());
break;
}
System.out.println("Unexpected message received. Expected: " + msg);
System.out.println("Received message doesn't match - skipping: " + str);
} else {
System.out.println("Unexpected message received. Expected message from: " + s.getLocalAddress());
System.out.println("Received message sender doesn't match - skipping: " + p.getSocketAddress());
}
}
assertTrue(p.getLength() == message.length);
assertTrue(p.getPort() == s.getLocalPort());

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* 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
@ -31,6 +31,7 @@
*/
import java.io.IOException;
import java.net.BindException;
import java.net.InetAddress;
import java.net.Inet6Address;
import java.net.InetSocketAddress;
@ -46,6 +47,7 @@ import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Predicate;
import org.testng.annotations.Test;
import static org.testng.Assert.*;
@ -54,6 +56,38 @@ import jdk.test.lib.net.IPSupport;
public class AfterDisconnect {
interface RetryableTest<T extends Exception> {
public void runTest() throws T;
}
// retry the given lambda (RetryableTest) if an exception
// that satisfies the predicate (retryOn) is caught.
<T extends Exception> void testWithRetry(RetryableTest<T> test,
Predicate<Throwable> retryOn,
int max) throws T {
for (int i=0; i < max; i++) {
try {
test.runTest();
break;
} catch (Throwable t) {
if (i < max -1 && retryOn.test(t)) {
System.out.println("Got " + t + "; will retry");
} else throw t;
}
}
}
/**
* When calling {@link DatagramChannel#disconnect()} a {@link BindException}
* may occur. In which case we want to retry the test.
*/
class BindExceptionOnDisconnect extends BindException {
BindExceptionOnDisconnect(BindException x) {
super(x.getMessage());
initCause(x);
}
}
@Test
public void execute() throws IOException {
IPSupport.throwSkippedExceptionIfNonOperational();
@ -61,34 +95,41 @@ public class AfterDisconnect {
InetAddress lb = InetAddress.getLoopbackAddress();
// test with default protocol family
try (DatagramChannel dc = DatagramChannel.open()) {
System.out.println("Test with default");
dc.bind(new InetSocketAddress(lb, 0));
test(dc);
test(dc);
}
// test with IPv6 socket
if (IPSupport.hasIPv6()) {
System.out.println("Test with IPv6 socket");
try (DatagramChannel dc = DatagramChannel.open(StandardProtocolFamily.INET6)) {
System.out.println("Test with default");
testWithRetry(() -> {
try (DatagramChannel dc = DatagramChannel.open()) {
dc.bind(new InetSocketAddress(lb, 0));
test(dc);
test(dc);
}
}, BindExceptionOnDisconnect.class::isInstance, 5);
// test with IPv6 socket
if (IPSupport.hasIPv6()) {
System.out.println("Test with IPv6 socket");
testWithRetry(() -> {
try (DatagramChannel dc = DatagramChannel.open(StandardProtocolFamily.INET6)) {
dc.bind(new InetSocketAddress(lb, 0));
test(dc);
test(dc);
}
}, BindExceptionOnDisconnect.class::isInstance, 5);
}
// test with IPv4 socket
if (IPSupport.hasIPv4() && !preferIPv6) {
System.out.println("Test with IPv4 socket");
try (DatagramChannel dc = DatagramChannel.open(StandardProtocolFamily.INET)) {
dc.bind(new InetSocketAddress(lb, 0));
test(dc);
test(dc);
}
testWithRetry(() -> {
try (DatagramChannel dc = DatagramChannel.open(StandardProtocolFamily.INET)) {
dc.bind(new InetSocketAddress(lb, 0));
test(dc);
test(dc);
}
}, BindExceptionOnDisconnect.class::isInstance, 5);
}
}
void test(DatagramChannel dc) throws IOException {
testLocalAddress(dc);
testSocketOptions(dc);
@ -111,7 +152,11 @@ public class AfterDisconnect {
assertEquals(dc.getLocalAddress(), local);
assertEquals(dc.getRemoteAddress(), remote);
dc.disconnect();
try {
dc.disconnect();
} catch (BindException x) {
throw new BindExceptionOnDisconnect(x);
}
assertFalse(dc.isConnected());
assertEquals(dc.getLocalAddress(), local);
assertTrue(dc.getRemoteAddress() == null);
@ -134,7 +179,11 @@ public class AfterDisconnect {
Map<SocketOption<?>, Object> map = options(dc);
dc.connect(dc.getLocalAddress());
dc.disconnect();
try {
dc.disconnect();
} catch (BindException x) {
throw new BindExceptionOnDisconnect(x);
}
// check socket options have not changed
assertEquals(map, options(dc));
@ -168,7 +217,11 @@ public class AfterDisconnect {
sel.selectNow();
dc.connect(dc.getLocalAddress());
dc.disconnect();
try {
dc.disconnect();
} catch (BindException x) {
throw new BindExceptionOnDisconnect(x);
}
// selection key should still be valid
assertTrue(key.isValid());
@ -210,7 +263,11 @@ public class AfterDisconnect {
MembershipKey key = dc.join(group, ni);
dc.connect(dc.getLocalAddress());
dc.disconnect();
try {
dc.disconnect();
} catch (BindException x) {
throw new BindExceptionOnDisconnect(x);
}
// membership key should still be valid
assertTrue(key.isValid());

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 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
@ -23,6 +23,8 @@
/* @test
* @bug 4313882 7183800
* @library /test/lib
* @build jdk.test.lib.Platform Connect
* @run main/othervm Connect
* @summary Test DatagramChannel's send and receive methods
*/
@ -38,6 +40,8 @@ import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.stream.Stream;
import jdk.test.lib.Platform;
import static java.nio.charset.StandardCharsets.US_ASCII;
public class Connect {
@ -114,9 +118,21 @@ public class Connect {
ByteBuffer bb = ByteBuffer.allocateDirect(MAX);
bb.put(bytes);
bb.flip();
// When connecting an unbound datagram channel, the underlying
// socket will first be bound to the wildcard address. On macOS,
// the system may allocate the same port on which another socket
// is already bound with a more specific address. This may prevent
// datagrams directed at the connected socket to reach it.
// To avoid this, when on macOS, we preemptively bind `dc` to the
// specific address instead of letting it bind to the wildcard.
if (Platform.isOSX()) {
dc.bind(new InetSocketAddress(((InetSocketAddress)connectSocketAddress).getAddress(), 0));
err.println("Initiator bound to: " + connectSocketAddress);
}
err.println("Initiator connecting to: " + connectSocketAddress);
dc.connect(connectSocketAddress);
err.println("Initiator bound to: " + dc.getLocalAddress());
assert !connectSocketAddress.equals(dc.getLocalAddress());
// Send a message
err.println("Initiator attempting to write to Responder at " + connectSocketAddress);

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* 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
@ -24,7 +24,7 @@
/* @test
* @bug 8234805 8235193
* @summary Test DatagramChannel send/receive and that receive returns the expected
* sender address
* sender address.
* @run main/othervm ManySourcesAndTargets
* @run main/othervm -Djava.net.preferIPv4Stack=true ManySourcesAndTargets
*/
@ -63,6 +63,7 @@ public class ManySourcesAndTargets {
try (DatagramChannel reader = DatagramChannel.open()) {
// bind reader to wildcard address so it can receive from any address
reader.bind(new InetSocketAddress(0));
System.out.println("\nReader bound to: " + reader.getLocalAddress());
for (InetAddress address : addresses) {
System.out.format("%n-- %s --%n", address.getHostAddress());
@ -75,6 +76,7 @@ public class ManySourcesAndTargets {
try (DatagramChannel sender = DatagramChannel.open()) {
// bind sender to wildcard address so it can send to any address
sender.bind(new InetSocketAddress(0));
System.out.println("\nSender bound to: " + sender.getLocalAddress());
for (InetAddress address : addresses) {
System.out.format("%n-- %s --%n", address.getHostAddress());
@ -97,6 +99,11 @@ public class ManySourcesAndTargets {
sender.bind(new InetSocketAddress(address, 0));
SocketAddress local = sender.getLocalAddress();
System.out.println("Sender bound to: " + local);
if (((InetSocketAddress)local).getPort() == remotePort) {
System.out.println("testSend: Sender and reader have same port: skipping");
return;
}
byte[] bytes = serialize(local);
SocketAddress previousSource = null;
@ -105,6 +112,8 @@ public class ManySourcesAndTargets {
sender.send(ByteBuffer.wrap(bytes), remote);
ByteBuffer bb = ByteBuffer.allocate(1000);
System.out.format("testSend: reader waiting to receive at: %s%n",
reader.getLocalAddress());
SocketAddress source = reader.receive(bb);
System.out.format("received datagram from %s%n", source);
@ -138,11 +147,18 @@ public class ManySourcesAndTargets {
SocketAddress remote = reader.getLocalAddress();
System.out.println("Reader bound to: " + remote);
if (((InetSocketAddress)local).getPort() == ((InetSocketAddress)remote).getPort()) {
System.out.println("testReceive: Sender and reader have same port: skipping");
return;
}
for (int i = 0; i < count; i++) {
System.out.format("send %s -> %s%n", local, remote);
sender.send(ByteBuffer.allocate(32), remote);
ByteBuffer bb = ByteBuffer.allocate(1000);
System.out.format("testReceive: reader waiting to receive at: %s%n",
reader.getLocalAddress());
SocketAddress source = reader.receive(bb);
System.out.format("received datagram from %s%n", source);
}
@ -165,7 +181,12 @@ public class ManySourcesAndTargets {
private static Optional<NetworkInterface> networkInterface(InetAddress ia) {
try {
return Optional.ofNullable(NetworkInterface.getByInetAddress(ia));
NetworkInterface nif = NetworkInterface.getByInetAddress(ia);
if (nif != null) {
System.out.format("Selecting interface %s[%d]%n\twith addresses:%n\t%s%n",
nif.getDisplayName(), nif.getIndex(), nif.inetAddresses().toList());
}
return Optional.ofNullable(nif);
} catch (SocketException e) {
return Optional.empty();
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2007, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2007, 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
@ -99,15 +99,25 @@ public class MulticastSendReceiveTests {
ByteBuffer buf = ByteBuffer.allocateDirect(100);
try {
long elapsed = 0;
for (;;) {
System.out.println("Waiting to receive message");
long start = System.nanoTime();
sel.select(5*1000);
long waited = (System.nanoTime() - start) / 1000_000;
elapsed += waited;
buf.clear();
SocketAddress sa = dc.receive(buf);
// no datagram received
if (sa == null) {
if (expectedSender != null) {
throw new RuntimeException("Expected message not received");
if (elapsed > 4800) {
throw new RuntimeException("Expected message not received");
} else {
sel.selectedKeys().clear();
continue;
}
}
System.out.println("No message received (correct)");
return;
@ -123,8 +133,8 @@ public class MulticastSendReceiveTests {
int receivedId = -1;
try {
receivedId = Integer.parseInt(s);
System.out.format("Received message from %s (id=0x%x)\n",
sender, receivedId);
System.out.format("Received message from %s (id=0x%x, length=%s)\n",
sender, receivedId, bytes.length);
} catch (NumberFormatException x) {
System.out.format("Received message from %s (msg=%s)\n", sender, s);
}
@ -142,7 +152,6 @@ public class MulticastSendReceiveTests {
}
sel.selectedKeys().clear();
buf.rewind();
}
} finally {
sel.close();
@ -160,6 +169,8 @@ public class MulticastSendReceiveTests {
throws IOException
{
System.out.format("\nTest DatagramChannel to %s socket\n", family.name());
System.out.format("With interface=%s[%s]%n\twith bound addresses:%n\t%s%n",
nif.getDisplayName(), nif.getIndex(), nif.inetAddresses().toList());
try (DatagramChannel dc = (family == UNSPEC) ?
DatagramChannel.open() : DatagramChannel.open(family)) {
dc.setOption(StandardSocketOptions.SO_REUSEADDR, true)

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2002, 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
@ -24,19 +24,26 @@
/* @test
* @bug 4512723 6621689
* @summary Test that connect/send/receive with unbound DatagramChannel causes
* the channel's socket to be bound to a local address
* the channel's socket to be bound to a local address.
* @run main/othervm NotBound
*/
import java.net.*;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
public class NotBound {
static final CountDownLatch received = new CountDownLatch(1);
static void checkBound(DatagramChannel dc) throws IOException {
if (dc.getLocalAddress() == null)
throw new RuntimeException("Not bound??");
System.out.println("Bound to: " + dc.getLocalAddress());
}
// starts a thread to send a datagram to the given channel once the channel
@ -51,19 +58,44 @@ public class NotBound {
Thread.sleep(50);
local = (InetSocketAddress)dc.getLocalAddress();
} while (local == null);
System.out.format("receiver bound to: %s%n", local);
// send message to channel to wakeup receiver
DatagramChannel sender = DatagramChannel.open();
try {
ByteBuffer bb = ByteBuffer.wrap("hello".getBytes());
InetAddress lh = InetAddress.getLocalHost();
SocketAddress target =
new InetSocketAddress(lh, local.getPort());
sender.send(bb, target);
} finally {
sender.close();
boolean isAnyLocal = local.getAddress().isAnyLocalAddress();
int maxAttempts = 5;
int localPort = 0;
List<InetAddress> llh = isAnyLocal
? List.of(InetAddress.getLocalHost(), InetAddress.getLoopbackAddress())
: List.of(local.getAddress());
SocketAddress target = null;
for (int i = 0 ; i < maxAttempts ; i++) {
InetAddress lh = llh.get(i % llh.size());
target = new InetSocketAddress(lh, local.getPort());
// send message to channel to wakeup receiver
try (DatagramChannel sender = DatagramChannel.open()) {
ByteBuffer bb = ByteBuffer.wrap("NotBound: hello".getBytes());
sender.send(bb, target);
System.out.format("Woke up receiver: sent datagram to %s from %s%n",
target, sender.getLocalAddress());
localPort = ((InetSocketAddress)sender.getLocalAddress()).getPort();
}
if (received.await(250, TimeUnit.MILLISECONDS)) {
// The datagram has been received: no need to continue
// sending
break;
}
// if sender port and destination port were identical, which
// could happen on some systems, the receiver might not receive
// the datagram. So in that case we try again, bailing out if
// we had to retry too many times
if (localPort == local.getPort()) {
System.out.println("Local port and peer port are identical. Retrying...");
} else {
System.out.println("Datagram not received after 250ms. Retrying...");
}
}
if (localPort == local.getPort()) {
System.out.println("Couldn't find a port to send to " + target);
}
} catch (Exception x) {
x.printStackTrace();
}
@ -77,14 +109,12 @@ public class NotBound {
// connect
dc = DatagramChannel.open();
try {
DatagramChannel peer = DatagramChannel.open()
.bind(new InetSocketAddress(0));
int peerPort = ((InetSocketAddress)(peer.getLocalAddress())).getPort();
try {
System.out.println("Check that connect() binds the socket");
try (DatagramChannel peer = DatagramChannel.open()) {
peer.bind(new InetSocketAddress(0));
int peerPort = ((InetSocketAddress)(peer.getLocalAddress())).getPort();
dc.connect(new InetSocketAddress(InetAddress.getLocalHost(), peerPort));
checkBound(dc);
} finally {
peer.close();
}
} finally {
dc.close();
@ -93,7 +123,8 @@ public class NotBound {
// send
dc = DatagramChannel.open();
try {
ByteBuffer bb = ByteBuffer.wrap("ignore this".getBytes());
System.out.println("Check that send() binds the socket");
ByteBuffer bb = ByteBuffer.wrap("NotBound: ignore this".getBytes());
SocketAddress target =
new InetSocketAddress(InetAddress.getLocalHost(), 5000);
dc.send(bb, target);
@ -105,9 +136,11 @@ public class NotBound {
// receive (blocking)
dc = DatagramChannel.open();
try {
System.out.println("Check that blocking receive() binds the socket");
ByteBuffer bb = ByteBuffer.allocateDirect(128);
wakeupWhenBound(dc);
SocketAddress sender = dc.receive(bb);
received.countDown();
if (sender == null)
throw new RuntimeException("Sender should not be null");
checkBound(dc);
@ -118,6 +151,7 @@ public class NotBound {
// receive (non-blocking)
dc = DatagramChannel.open();
try {
System.out.println("Check that non-blocking receive() binds the socket");
dc.configureBlocking(false);
ByteBuffer bb = ByteBuffer.allocateDirect(128);
SocketAddress sender = dc.receive(bb);

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 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
@ -71,9 +71,11 @@ public class Promiscuous {
dc.setOption(StandardSocketOptions.IP_MULTICAST_IF, nif);
byte[] msg = Integer.toString(id).getBytes("UTF-8");
ByteBuffer buf = ByteBuffer.wrap(msg);
System.out.format("Send message -> group %s (id=0x%x)\n",
group.getHostAddress(), id);
System.out.format("Send message -> group [%s]:%d (id=0x%x) nif:%s[%s]%n",
group.getHostAddress(), port, id, nif.getDisplayName(), nif.getIndex());
System.out.format("bound address before send: %s%n", dc.getLocalAddress());
dc.send(buf, new InetSocketAddress(group, port));
System.out.format("bound address after send: %s%n", dc.getLocalAddress());
}
return id;
}
@ -97,15 +99,26 @@ public class Promiscuous {
ByteBuffer buf = ByteBuffer.allocateDirect(100);
try {
long elapsed = 0;
for (;;) {
System.out.println("Waiting to receive message");
long start = System.nanoTime();
sel.select(5*1000);
long waited = (System.nanoTime() - start) / 1000_000;
elapsed += waited;
buf.clear();
SocketAddress sa = dc.receive(buf);
// no datagram received
if (sa == null) {
if (datagramExpected) {
throw new RuntimeException("Expected message not received");
if (elapsed > 4800) {
throw new RuntimeException("Expected message not received");
} else {
sel.selectedKeys().clear();
// We haven't waited long enough,
continue;
}
}
System.out.println("No message received (correct)");
return;
@ -121,8 +134,8 @@ public class Promiscuous {
int receivedId = -1;
try {
receivedId = Integer.parseInt(s);
System.out.format("Received message from %s (id=0x%x)\n",
sender, receivedId);
System.out.format("Received message from %s (id=0x%x, length=%s)\n",
sender, receivedId, bytes.length);
} catch (NumberFormatException x) {
System.out.format("Received message from %s (msg=%s)\n", sender, s);
}
@ -140,7 +153,6 @@ public class Promiscuous {
}
sel.selectedKeys().clear();
buf.rewind();
}
} finally {
sel.close();
@ -155,13 +167,14 @@ public class Promiscuous {
{
System.out.format("%nTest family=%s%n", family.name());
System.out.format("With interface=%s[%s]%n\twith bound addresses:%n\t%s%n",
nif.getDisplayName(), nif.getIndex(), nif.inetAddresses().toList());
DatagramChannel dc1 = (family == UNSPEC) ?
DatagramChannel.open() : DatagramChannel.open(family);
DatagramChannel dc2 = (family == UNSPEC) ?
DatagramChannel.open() : DatagramChannel.open(family);
try (DatagramChannel dc1 = (family == UNSPEC) ?
DatagramChannel.open() : DatagramChannel.open(family);
DatagramChannel dc2 = (family == UNSPEC) ?
DatagramChannel.open() : DatagramChannel.open(family)) {
try {
dc1.setOption(StandardSocketOptions.SO_REUSEADDR, true);
dc2.setOption(StandardSocketOptions.SO_REUSEADDR, true);
@ -184,12 +197,8 @@ public class Promiscuous {
id = sendDatagram(nif, group2, port);
receiveDatagram(dc1, "dc1", false, id);
receiveDatagram(dc2, "dc2", true, id);
} finally {
dc1.close();
dc2.close();
receiveDatagram(dc1, "dc1", false, id);
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 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
@ -27,10 +27,19 @@
* @summary Check that DatagramChannel.receive returns a new SocketAddress
* when it receives a packet from the same source address but
* different endpoint.
* @library /test/lib
* @build jdk.test.lib.NetworkConfiguration
* jdk.test.lib.Platform
* ReceiveISA
* @run main/othervm ReceiveISA
*
*/
import java.nio.*;
import java.nio.channels.*;
import java.net.*;
import jdk.test.lib.Platform;
import static java.lang.System.out;
public class ReceiveISA {
@ -44,10 +53,13 @@ public class ReceiveISA {
DatagramChannel dc3 = DatagramChannel.open();
DatagramChannel dc4 = DatagramChannel.open()) { // client
dc3.socket().bind((SocketAddress) null); // bind server to any port
InetAddress lh = InetAddress.getLocalHost();
InetSocketAddress dest = Platform.isOSX()
? new InetSocketAddress(lh, 0)
: null;
dc3.socket().bind(dest); // bind server to any port
// get server address
InetAddress lh = InetAddress.getLocalHost();
InetSocketAddress isa = new InetSocketAddress(lh, dc3.socket().getLocalPort());
ByteBuffer bb = ByteBuffer.allocateDirect(100);

@ -39,8 +39,8 @@ import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
public class SelectWhenRefused {
static final int MAX_TRIES = 3;
static final String GREETINGS_MESSAGE = "Greetings from SelectWhenRefused!";
static final int MAX_TRIES = 10;
static final String GREETINGS_MESSAGE = System.nanoTime() + ": Greetings from SelectWhenRefused!";
@Test
public void test() throws IOException {
@ -49,9 +49,39 @@ public class SelectWhenRefused {
// datagram sent to this address should be refused
SocketAddress refuser = new InetSocketAddress(InetAddress.getLocalHost(), port);
System.err.println("Refuser is: " + refuser);
DatagramChannel dc = DatagramChannel.open().bind(new InetSocketAddress(0));
DatagramChannel dc = null;
for (int i=0; i < MAX_TRIES; i++) {
dc = DatagramChannel.open();
try {
dc.bind(new InetSocketAddress(0));
} catch (Throwable t) {
dc.close();
throw t;
}
// check the port assigned to dc
if (((InetSocketAddress)dc.getLocalAddress()).getPort() != port) {
// We got a good port. Do not retry
break;
}
// We bound to the same port that the refuser is using, This will not
// work. Retry binding if possible.
if (i < MAX_TRIES - 1) {
// we will retry...
System.err.format("Refuser port has been reused by dc: %s, retrying...%n",
dc.getLocalAddress());
} else {
// that was the last attempt... Skip the test
System.err.format("Skipping test: refuser port has been reused by dc: %s%n",
dc.getLocalAddress());
return;
}
}
dc1.close();
assert dc != null;
Selector sel = Selector.open();
try {
@ -88,7 +118,7 @@ public class SelectWhenRefused {
}
} catch (BindException e) {
// Do nothing, some other test has used this port
System.out.println("Skipping test: refuser port has been reused: " + e);
System.err.println("Skipping test: refuser port has been reused: " + e);
} finally {
sel.close();
dc.close();
@ -119,7 +149,9 @@ public class SelectWhenRefused {
// BindException will be thrown if another service is using
// our expected refuser port, cannot run just exit.
DatagramChannel.open().bind(refuser).close();
try (DatagramChannel dc2 = DatagramChannel.open()) {
dc2.bind(refuser);
}
throw new RuntimeException("Unexpected wakeup");
}
return true; // test passed
@ -151,7 +183,7 @@ public class SelectWhenRefused {
byte[] bytes = new byte[buf.remaining()];
buf.get(bytes);
String message = new String(bytes);
System.out.format("received %s at %s from %s%n", message, dc.getLocalAddress(), sa);
System.err.format("received %s at %s from %s%n", message, dc.getLocalAddress(), sa);
// If any received data contains the message from sendDatagram then throw exception
if (message.contains(GREETINGS_MESSAGE)) {
@ -166,10 +198,12 @@ public class SelectWhenRefused {
// BindException will be thrown if another service is using
// our expected refuser port, cannot run just exit.
DatagramChannel.open().bind(refuser).close();
try (DatagramChannel dc2 = DatagramChannel.open()) {
dc2.bind(refuser);
}
throw new RuntimeException("PortUnreachableException not raised");
} catch (PortUnreachableException pue) {
System.out.println("Got expected PortUnreachableException " + pue);
System.err.println("Got expected PortUnreachableException " + pue);
}
}
return true; // test passed
@ -215,16 +249,16 @@ public class SelectWhenRefused {
*
*/
static boolean checkUnexpectedWakeup(Set<SelectionKey> selectedKeys) {
System.out.format("Received %d keys%n", selectedKeys.size());
System.err.format("Received %d keys%n", selectedKeys.size());
for (SelectionKey key : selectedKeys) {
if (!key.isValid() || !key.isReadable()) {
System.out.println("Invalid or unreadable key: " + key);
System.err.println("Invalid or unreadable key: " + key);
continue;
}
try {
System.out.println("Attempting to read datagram from key: " + key);
System.err.println("Attempting to read datagram from key: " + key);
DatagramChannel datagramChannel = (DatagramChannel) key.channel();
ByteBuffer buf = ByteBuffer.allocate(100);
SocketAddress sa = datagramChannel.receive(buf);
@ -234,7 +268,7 @@ public class SelectWhenRefused {
byte[] bytes = new byte[buf.remaining()];
buf.get(bytes);
String message = new String(bytes);
System.out.format("received %s at %s from %s%n", message, datagramChannel.getLocalAddress(), sa);
System.err.format("received %s at %s from %s%n", message, datagramChannel.getLocalAddress(), sa);
// If any received data contains the message from sendDatagram then return false
if (message.contains(GREETINGS_MESSAGE)) {
@ -243,7 +277,7 @@ public class SelectWhenRefused {
}
} catch (IOException io) {
System.out.println("Unable to read from datagram " + io);
System.err.println("Unable to read from datagram " + io);
}
}
return true;

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 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
@ -37,6 +37,7 @@ import jdk.test.lib.RandomFactory;
import jdk.test.lib.NetworkConfiguration;
import jdk.test.lib.Platform;
import jdk.test.lib.net.IPSupport;
import org.testng.Assert;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
@ -46,6 +47,7 @@ import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.util.ArrayList;
@ -139,7 +141,9 @@ public class SendReceiveMaxSize {
var addr = new InetSocketAddress(host, port);
try (var sender = supplier.open()) {
sender.bind(null);
sender.bind(new InetSocketAddress(host, 0));
System.out.format("testSendReceiveMaxSize: sender: %s -> receiver: %s%n",
sender.getLocalAddress(), receiver.getLocalAddress());
if (!Platform.isOSX()) {
if (sender.getOption(SO_SNDBUF) < capacity)
sender.setOption(SO_SNDBUF, capacity);
@ -150,7 +154,18 @@ public class SendReceiveMaxSize {
var sendBuf = ByteBuffer.wrap(testData);
sender.send(sendBuf, addr);
var receiveBuf = ByteBuffer.allocate(capacity);
receiver.receive(receiveBuf);
SocketAddress src;
int count = 0;
do {
receiveBuf.clear();
src = receiver.receive(receiveBuf);
if (sender.getLocalAddress().equals(src)) break;
System.out.println("step1: received unexpected datagram from: " + src);
System.out.println("\texpected: " + sender.getLocalAddress());
if (++count > 10) {
throw new AssertionError("too many unexpected messages");
}
} while (true);
sendBuf.flip();
receiveBuf.flip();
@ -167,7 +182,17 @@ public class SendReceiveMaxSize {
sendBuf = ByteBuffer.wrap(testData);
sender.send(sendBuf, addr);
receiveBuf = ByteBuffer.allocate(capacity - 1);
receiver.receive(receiveBuf);
count = 0;
do {
receiveBuf.clear();
src = receiver.receive(receiveBuf);
if (sender.getLocalAddress().equals(src)) break;
System.out.println("step1: received unexpected datagram from: " + src);
System.out.println("\texpected: " + sender.getLocalAddress());
if (++count > 10) {
throw new AssertionError("too many unexpected messages");
}
} while (true);
sendBuf.flip();
receiveBuf.flip();

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2002, 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
@ -24,6 +24,9 @@
/* @test
* @bug 4669040 8130394
* @summary Test DatagramChannel subsequent receives with no datagram ready
* @library /test/lib
* @build jdk.test.lib.Platform Sender
* @run main Sender
* @author Mike McCloskey
*/
@ -36,6 +39,8 @@ import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.channels.DatagramChannel;
import jdk.test.lib.Platform;
public class Sender {
static PrintStream log = System.err;
@ -46,25 +51,26 @@ public class Sender {
}
static void test() throws Exception {
Server server = new Server();
Client client = new Client(server.port());
try (Server server = new Server()) {
Client client = new Client(server.port());
Thread serverThread = new Thread(server);
serverThread.start();
Thread serverThread = new Thread(server);
serverThread.start();
Thread clientThread = new Thread(client);
clientThread.start();
Thread clientThread = new Thread(client);
clientThread.start();
serverThread.join();
clientThread.join();
serverThread.join();
clientThread.join();
server.throwException();
client.throwException();
server.throwException();
client.throwException();
}
}
public static class Client implements Runnable {
final int port;
Exception e = null;
volatile Exception e = null;
Client(int port) {
this.port = port;
@ -76,14 +82,17 @@ public class Sender {
}
public void run() {
try {
DatagramChannel dc = DatagramChannel.open();
try (DatagramChannel dc = DatagramChannel.open()) {
ByteBuffer bb = ByteBuffer.allocateDirect(12);
bb.order(ByteOrder.BIG_ENDIAN);
bb.putInt(1).putLong(1);
bb.flip();
InetAddress address = InetAddress.getLocalHost();
InetSocketAddress isa = new InetSocketAddress(address, port);
if (Platform.isOSX()) {
// avoid binding on wildcard on macOS
dc.bind(new InetSocketAddress(address, 0));
}
dc.connect(isa);
clientISA = dc.getLocalAddress();
dc.write(bb);
@ -93,12 +102,16 @@ public class Sender {
}
}
public static class Server implements Runnable {
public static class Server implements Runnable, AutoCloseable {
final DatagramChannel dc;
Exception e = null;
volatile Exception e = null;
Server() throws IOException {
dc = DatagramChannel.open().bind(new InetSocketAddress(0));
// avoid binding to wildcard address on macOS
InetSocketAddress lo = Platform.isOSX()
? new InetSocketAddress(InetAddress.getLocalHost(), 0)
: new InetSocketAddress(0);
dc = DatagramChannel.open().bind(lo);
}
int port() {
@ -149,6 +162,11 @@ public class Sender {
e = ex;
}
}
@Override
public void close() throws IOException {
dc.close();
}
}
}