From 8ec378a6c8a460dd0727df800419b3cf45d3c57a Mon Sep 17 00:00:00 2001 From: Daniel Fuchs Date: Fri, 28 Jun 2024 11:03:29 +0000 Subject: [PATCH] 8277949: (dc) java/nio/channels/DatagramChannel/AdaptorBasic.java failed in timeout Reviewed-by: jpai --- .../DatagramChannel/AdaptorBasic.java | 40 ++++++++++++++++--- test/jdk/java/nio/channels/TestServers.java | 31 ++++++++++++-- 2 files changed, 61 insertions(+), 10 deletions(-) diff --git a/test/jdk/java/nio/channels/DatagramChannel/AdaptorBasic.java b/test/jdk/java/nio/channels/DatagramChannel/AdaptorBasic.java index 4ac5d4b3c88..504b648dcb6 100644 --- a/test/jdk/java/nio/channels/DatagramChannel/AdaptorBasic.java +++ b/test/jdk/java/nio/channels/DatagramChannel/AdaptorBasic.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2019, 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 @@ -36,6 +36,8 @@ import java.nio.channels.*; import java.util.*; import java.lang.reflect.Field; +import jdk.test.lib.Platform; + public class AdaptorBasic { @@ -69,6 +71,8 @@ public class AdaptorBasic { for (;;) { try { ds.receive(ip); + // weed off stray datagrams + if (ip.getPort() != dst.getPort()) continue; } catch (SocketTimeoutException x) { if (shouldTimeout) { out.println("Receive timed out, as expected"); @@ -111,12 +115,36 @@ public class AdaptorBasic { // Original ds = new DatagramSocket(); } else { - DatagramChannel dc = DatagramChannel.open(); - ds = dc.socket(); - ds.bind(new InetSocketAddress(0)); + int attempts = 0; + DatagramChannel toclose = null; + while (true) { + DatagramChannel dc = DatagramChannel.open(); + ds = dc.socket(); + if (Platform.isOSX() && dst.getAddress().isLoopbackAddress()) { + // avoid binding to the wildcard on macOS if possible, in order to limit + // potential port conflict issues + ds.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0)); + } else { + ds.bind(new InetSocketAddress(0)); + } + // on some systems it may be possible to bind two sockets + // to the same port if one of them is bound to the wildcard, + // if that happens, try again... + if (ds.getLocalPort() == dst.getPort()) { + if (toclose != null) toclose.close(); + toclose = dc; + if (++attempts == 10) { + throw new AssertionError("Couldn't allocate port for client socket"); + } + continue; + } + if (toclose != null) toclose.close(); + break; + } } - out.println("socket: " + ds); + out.println("socket: " + ds + " bound to src: " + + ds.getLocalSocketAddress() + ", dst: " + dst); if (connect) { ds.connect(dst); out.println("connect: " + ds); @@ -141,7 +169,7 @@ public class AdaptorBasic { public static void main(String[] args) throws Exception { // need an UDP echo server try (TestServers.UdpEchoServer echoServer - = TestServers.UdpEchoServer.startNewServer(100)) { + = TestServers.UdpEchoServer.startNewServer(100, InetAddress.getLoopbackAddress())) { final InetSocketAddress address = new InetSocketAddress(echoServer.getAddress(), echoServer.getPort()); diff --git a/test/jdk/java/nio/channels/TestServers.java b/test/jdk/java/nio/channels/TestServers.java index e2c4151195d..4f459c439f5 100644 --- a/test/jdk/java/nio/channels/TestServers.java +++ b/test/jdk/java/nio/channels/TestServers.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -497,6 +497,7 @@ public class TestServers { implements Runnable, Closeable { protected final long linger; // #of ms to wait before responding + protected final InetAddress bindAddress; //local address to bind to; can be null. private Thread acceptThread; // thread waiting for packets private DatagramSocket serverSocket; // the server socket private boolean started = false; // whether the server is started @@ -509,7 +510,20 @@ public class TestServers { * responding to requests. */ protected AbstractUdpServer(long linger) { + this(linger, null); + } + + /** + * Creates a new abstract UDP server. + * + * @param linger the amount of time the server should wait before + * responding to requests. + * @param bindAddress the address to bind to. If {@code null}, will + * bind to InetAddress.getLocalHost(); + */ + protected AbstractUdpServer(long linger, InetAddress bindAddress) { this.linger = linger; + this.bindAddress = bindAddress; } /** @@ -574,8 +588,9 @@ public class TestServers { if (started) { return; } + InetAddress lh = bindAddress == null ? InetAddress.getLocalHost() : bindAddress; final DatagramSocket socket = - newDatagramSocket(0, InetAddress.getLocalHost()); + newDatagramSocket(0, lh); serverSocket = socket; acceptThread = new Thread(this); acceptThread.setDaemon(true); @@ -759,7 +774,11 @@ public class TestServers { } public UdpEchoServer(long linger) { - super(linger); + this(linger, null); + } + + public UdpEchoServer(long linger, InetAddress bindAddress) { + super(linger, bindAddress); } @Override @@ -795,7 +814,11 @@ public class TestServers { } public static UdpEchoServer startNewServer(long linger) throws IOException { - final UdpEchoServer echoServer = new UdpEchoServer(linger); + return startNewServer(0, InetAddress.getLocalHost()); + } + + public static UdpEchoServer startNewServer(long linger, InetAddress bindAddress) throws IOException { + final UdpEchoServer echoServer = new UdpEchoServer(linger, bindAddress); echoServer.start(); return echoServer; }