From d63413754eb42f4e371ee5163e103e569762172f Mon Sep 17 00:00:00 2001 From: Trustin Lee Date: Fri, 17 Oct 2014 15:01:51 +0900 Subject: [PATCH] Make TestUtils.getFreePort() check both TCP and UDP Motivation: We see occational failures in the datagram tests saying 'address already in use' when we attempt to bind on a port returned by TestUtils.getFreePort(). It turns out that TestUtils.getFreePort() only checks if TCP port is available. Modifications: Also check if UDP port is available, so that the datagram tests do not fail because of the 'address already in use' error during a bind attempt. Result: Less chance of datagram test failures --- .../io/netty/testsuite/util/TestUtils.java | 68 +++++++++++++++---- 1 file changed, 53 insertions(+), 15 deletions(-) diff --git a/testsuite/src/test/java/io/netty/testsuite/util/TestUtils.java b/testsuite/src/test/java/io/netty/testsuite/util/TestUtils.java index d323152f62..f00e7ee4fb 100644 --- a/testsuite/src/test/java/io/netty/testsuite/util/TestUtils.java +++ b/testsuite/src/test/java/io/netty/testsuite/util/TestUtils.java @@ -19,6 +19,7 @@ import io.netty.util.NetUtil; import org.junit.rules.TestName; import java.io.IOException; +import java.net.DatagramSocket; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.nio.channels.Channel; @@ -58,29 +59,66 @@ public final class TestUtils { */ public static int getFreePort() { for (int i = 0; i < NUM_CANDIDATES; i ++) { - int port = nextCandidatePort(); - try { - // Ensure it is possible to bind on both wildcard and loopback. - ServerSocket ss; - ss = new ServerSocket(); - ss.setReuseAddress(false); - ss.bind(new InetSocketAddress(port)); - ss.close(); - - ss = new ServerSocket(); - ss.setReuseAddress(false); - ss.bind(new InetSocketAddress(NetUtil.LOCALHOST, port)); - ss.close(); + final int port = nextCandidatePort(); + final InetSocketAddress wildcardAddr = new InetSocketAddress(port); + final InetSocketAddress loopbackAddr = new InetSocketAddress(NetUtil.LOCALHOST4, port); + // Ensure it is possible to bind on wildcard/loopback and tcp/udp. + if (isTcpPortAvailable(wildcardAddr) && + isTcpPortAvailable(loopbackAddr) && + isUdpPortAvailable(wildcardAddr) && + isUdpPortAvailable(loopbackAddr)) { return port; - } catch (IOException e) { - // ignore } } throw new RuntimeException("unable to find a free port"); } + private static boolean isTcpPortAvailable(InetSocketAddress localAddress) { + ServerSocket ss = null; + try { + ss = new ServerSocket(); + ss.setReuseAddress(false); + ss.bind(localAddress); + ss.close(); + ss = null; + return true; + } catch (Exception ignore) { + // Unavailable + } finally { + if (ss != null) { + try { + ss.close(); + } catch (IOException ignore) { + // Ignore + } + } + } + + return false; + } + + private static boolean isUdpPortAvailable(InetSocketAddress localAddress) { + DatagramSocket ds = null; + try { + ds = new DatagramSocket(null); + ds.setReuseAddress(false); + ds.bind(localAddress); + ds.close(); + ds = null; + return true; + } catch (Exception ignore) { + // Unavailable + } finally { + if (ds != null) { + ds.close(); + } + } + + return false; + } + /** * Return {@code true} if SCTP is supported by the running os. *