From 6ff7e2ae37ef529fe2160715bc7309f1a1a8b6fa Mon Sep 17 00:00:00 2001 From: Andrew Lu Date: Mon, 8 Jul 2024 02:07:23 +0000 Subject: [PATCH] 8334297: (so) java/nio/channels/SocketChannel/OpenLeak.java should not depend on SecurityManager Backport-of: 50bed6c67b1edd7736bdf79308d135a4e1047ff0 --- .../nio/channels/SocketChannel/OpenLeak.java | 104 ++++++++++++++++-- 1 file changed, 93 insertions(+), 11 deletions(-) diff --git a/test/jdk/java/nio/channels/SocketChannel/OpenLeak.java b/test/jdk/java/nio/channels/SocketChannel/OpenLeak.java index 8d8673355ef..c7eed1f27a0 100644 --- a/test/jdk/java/nio/channels/SocketChannel/OpenLeak.java +++ b/test/jdk/java/nio/channels/SocketChannel/OpenLeak.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2010, 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 @@ -25,28 +25,110 @@ * @bug 6548464 * @summary SocketChannel.open(SocketAddress) leaks file descriptor if * connection cannot be established + * @requires vm.flagless * @build OpenLeak - * @run main/othervm -Djava.security.manager=allow OpenLeak + * @run junit/othervm OpenLeak */ +import java.io.IOException; +import java.net.ConnectException; import java.net.InetAddress; import java.net.InetSocketAddress; +import java.net.SocketAddress; import java.nio.channels.SocketChannel; +import java.nio.channels.UnresolvedAddressException; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import static org.junit.jupiter.api.Assertions.assertThrows; + public class OpenLeak { - public static void main(String[] args) throws Exception { - InetAddress lh = InetAddress.getLocalHost(); - InetSocketAddress isa = new InetSocketAddress(lh, 12345); + static final String OS_NAME = System.getProperty("os.name").toLowerCase(Locale.ROOT); + static final boolean IS_WINDOWS_2016 = OS_NAME.contains("windows") && OS_NAME.contains("2016"); + + // On Windows Server 2016 trying to connect to port 47 consumes the + // whole connect timeout - which makes the test fail in timeout. + // We skip this part of the test on Windows Server 2016 + static final boolean TEST_WITH_RESERVED_PORT = !IS_WINDOWS_2016; + + private static final int MAX_LOOP = 250000; - System.setSecurityManager( new SecurityManager() ); - for (int i=0; i<100000; i++) { - try { - SocketChannel.open(isa); - throw new RuntimeException("This should not happen"); - } catch (SecurityException x) { } + + // Try to find a suitable port to provoke a "Connection Refused" + // error. + private static InetSocketAddress findSuitableRefusedAddress(InetSocketAddress isa) + throws IOException { + if (!TEST_WITH_RESERVED_PORT) return null; + var addr = isa.getAddress(); + try (SocketChannel sc1 = SocketChannel.open(isa)) { + // If we manage to connect, let's try to use some other + // port. + // port 51 is reserved too - there should be nothing there... + isa = new InetSocketAddress(addr, 51); + try (SocketChannel sc2 = SocketChannel.open(isa)) { + } + // OK, last attempt... + // port 61 is reserved too - there should be nothing there... + isa = new InetSocketAddress(addr, 61); + try (SocketChannel sc3 = SocketChannel.open(isa)) { + } + System.err.println("Could not find a suitable port"); + return null; + } catch (ConnectException x) { } + return isa; + } + + private static InetSocketAddress createUnresolved(InetSocketAddress isa, InetSocketAddress def) { + var sa = isa == null ? def : isa; + return InetSocketAddress.createUnresolved(sa.getHostString(), sa.getPort()); + } + + // Builds a list of test cases + static List testCases() throws Exception { + InetAddress lo = InetAddress.getLoopbackAddress(); + + // Try to find a suitable port that will cause a + // Connection Refused exception + // port 47 is reserved - there should be nothing there... + InetSocketAddress def = new InetSocketAddress(lo, 47); + InetSocketAddress isa = findSuitableRefusedAddress(def); + InetSocketAddress sa = createUnresolved(isa, def); + + final List cases = new ArrayList<>(); + cases.add(new Object[]{sa, UnresolvedAddressException.class}); + if (isa != null) { + cases.add(new Object[]{isa, ConnectException.class}); + } + return cases; + } + + @ParameterizedTest + @MethodSource("testCases") + public void test(SocketAddress sa, Class expectedException) throws Exception { + System.err.printf("%nExpecting %s for %s%n", expectedException, sa); + + int i = 0; + try { + for (i = 0; i < MAX_LOOP; i++) { + Throwable x = + assertThrows(expectedException, () -> SocketChannel.open(sa)); + if (i < 5 || i >= MAX_LOOP - 5) { + // print a message for the first five and last 5 exceptions + System.err.println(x); + } + } + } catch (Throwable t) { + System.err.println("Failed at " + i + " with " + t); + throw t; + } } }