/* * 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. */ import jdk.test.lib.NetworkConfiguration; import jdk.test.lib.Platform; import jdk.test.lib.net.IPSupport; import org.testng.annotations.BeforeTest; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import org.testng.Assert.ThrowingRunnable; import java.io.IOException; import java.net.*; import java.nio.channels.*; import java.nio.channels.spi.AbstractSelector; import java.nio.channels.spi.SelectorProvider; import static java.lang.System.out; import static java.lang.System.getProperty; import static java.lang.Boolean.parseBoolean; import static java.net.StandardProtocolFamily.INET; import static java.net.StandardProtocolFamily.INET6; import static jdk.test.lib.net.IPSupport.*; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertThrows; /* * @test * @summary Test SocketChannel, ServerSocketChannel and DatagramChannel * with various ProtocolFamily combinations * @library /test/lib * @build jdk.test.lib.NetworkConfiguration * @run testng ProtocolFamilies * @run testng/othervm -Djava.net.preferIPv4Stack=true ProtocolFamilies */ public class ProtocolFamilies { static final boolean hasIPv6 = hasIPv6(); static final boolean preferIPv4 = preferIPv4Stack(); static Inet4Address ia4; static Inet6Address ia6; @BeforeTest() public void setup() throws Exception { NetworkConfiguration.printSystemConfiguration(out); IPSupport.printPlatformSupport(out); throwSkippedExceptionIfNonOperational(); ia4 = getLocalIPv4Address(); ia6 = getLocalIPv6Address(); out.println("ia4: " + ia4); out.println("ia6: " + ia6 + "\n"); } static final Class UATE = UnsupportedAddressTypeException.class; static final Class UOE = UnsupportedOperationException.class; @DataProvider(name = "open") public Object[][] open() { if (hasIPv6 && !preferIPv4) { return new Object[][]{ { INET, null }, { INET6, null } }; } else { return new Object[][]{ { INET, null }, { INET6, UOE } }; } } @Test(dataProvider = "open") public void scOpen(StandardProtocolFamily family, Class expectedException) throws Throwable { SocketChannel sc = null; try { if (expectedException == UOE) { try { sc = openSC(family); } catch (UnsupportedOperationException e) {} } else { sc = openSC(family); } } finally { if (sc != null) sc.close(); } } @Test(dataProvider = "open") public void sscOpen(StandardProtocolFamily family, Class expectedException) throws Throwable { ServerSocketChannel ssc = null; try { if (expectedException == UOE) { try { ssc = openSSC(family); } catch (UnsupportedOperationException e) {} } else { openSSC(family); } } finally { if (ssc != null) ssc.close(); } } @Test(dataProvider = "open") public void dcOpen(StandardProtocolFamily family, Class expectedException) throws Throwable { DatagramChannel dc = null; try { if (expectedException == UOE) { try { dc = openDC(family); } catch (UnsupportedOperationException e) {} } else { openDC(family); } } finally { if (dc != null) dc.close(); } } @DataProvider(name = "openBind") public Object[][] openBind() { if (hasIPv6 && !preferIPv4) { return new Object[][]{ { INET, INET, null }, { INET, INET6, UATE }, { INET, null, null }, { INET6, INET, null }, { INET6, INET6, null }, { INET6, null, null }, { null, INET, null }, { null, INET6, null }, { null, null, null } }; } else { return new Object[][]{ { INET, INET, null }, { INET, INET6, UATE }, { INET, null, null }, { null, INET, null }, { null, INET6, UATE }, { null, null, null } }; } } // SocketChannel open - INET, INET6, default // SocketChannel bind - INET, INET6, null @Test(dataProvider = "openBind") public void scOpenBind(StandardProtocolFamily ofamily, StandardProtocolFamily bfamily, Class expectedException) throws Throwable { try (SocketChannel sc = openSC(ofamily)) { SocketAddress addr = getSocketAddress(bfamily); ThrowingRunnable bindOp = () -> sc.bind(addr); if (expectedException == null) bindOp.run(); else assertThrows(expectedException, bindOp); } } // ServerSocketChannel open - INET, INET6, default // ServerSocketChannel bind - INET, INET6, null @Test(dataProvider = "openBind") public void sscOpenBind(StandardProtocolFamily ofamily, StandardProtocolFamily bfamily, Class expectedException) throws Throwable { try (ServerSocketChannel ssc = openSSC(ofamily)) { SocketAddress addr = getSocketAddress(bfamily); ThrowingRunnable bindOp = () -> ssc.bind(addr); if (expectedException == null) bindOp.run(); else assertThrows(expectedException, bindOp); } } // DatagramChannel open - INET, INET6, default // DatagramChannel bind - INET, INET6, null @Test(dataProvider = "openBind") public void dcOpenBind(StandardProtocolFamily ofamily, StandardProtocolFamily bfamily, Class expectedException) throws Throwable { try (DatagramChannel dc = openDC(ofamily)) { SocketAddress addr = getSocketAddress(bfamily); ThrowingRunnable bindOp = () -> dc.bind(addr); if (expectedException == null) bindOp.run(); else assertThrows(expectedException, bindOp); } } // SocketChannel open - INET, INET6, default // SocketChannel connect - INET, INET6, default @DataProvider(name = "openConnect") public Object[][] openConnect() { if (hasIPv6 && !preferIPv4) { return new Object[][]{ { INET, INET, null }, { INET, INET6, null }, { INET, null, null }, { INET6, INET, UATE }, { INET6, INET6, null }, { INET6, null, null }, { null, INET, UATE }, { null, INET6, null }, { null, null, null } }; } else { // INET6 channels cannot be created - UOE - tested elsewhere return new Object[][]{ { INET, INET, null }, { INET, null, null }, { null, INET, null }, { null, null, null } }; } } @Test(dataProvider = "openConnect") public void scOpenConnect(StandardProtocolFamily sfamily, StandardProtocolFamily cfamily, Class expectedException) throws Throwable { try (ServerSocketChannel ssc = openSSC(sfamily)) { ssc.bind(null); SocketAddress saddr = ssc.getLocalAddress(); try (SocketChannel sc = openSC(cfamily)) { if (expectedException == null) sc.connect(saddr); else assertThrows(expectedException, () -> sc.connect(saddr)); } } } static final Class NPE = NullPointerException.class; // Tests null handling @Test public void testNulls() { assertThrows(NPE, () -> SocketChannel.open((ProtocolFamily)null)); assertThrows(NPE, () -> ServerSocketChannel.open(null)); assertThrows(NPE, () -> DatagramChannel.open(null)); assertThrows(NPE, () -> SelectorProvider.provider().openSocketChannel(null)); assertThrows(NPE, () -> SelectorProvider.provider().openServerSocketChannel(null)); assertThrows(NPE, () -> SelectorProvider.provider().openDatagramChannel(null)); } static final ProtocolFamily BAD_PF = () -> "BAD_PROTOCOL_FAMILY"; // Tests UOE handling @Test public void testUoe() { assertThrows(UOE, () -> SocketChannel.open(BAD_PF)); assertThrows(UOE, () -> ServerSocketChannel.open(BAD_PF)); assertThrows(UOE, () -> DatagramChannel.open(BAD_PF)); assertThrows(UOE, () -> SelectorProvider.provider().openSocketChannel(BAD_PF)); assertThrows(UOE, () -> SelectorProvider.provider().openServerSocketChannel(BAD_PF)); assertThrows(UOE, () -> SelectorProvider.provider().openDatagramChannel(BAD_PF)); } // A concrete subclass of SelectorProvider, in order to test implSpec static final SelectorProvider customerSelectorProvider = new SelectorProvider() { @Override public DatagramChannel openDatagramChannel() { return null; } @Override public DatagramChannel openDatagramChannel(ProtocolFamily family) { return null; } @Override public Pipe openPipe() { return null; } @Override public AbstractSelector openSelector() { return null; } @Override public ServerSocketChannel openServerSocketChannel() { return null; } @Override public SocketChannel openSocketChannel() { return null; } }; // Tests the specified default implementation of SelectorProvider @Test public void testCustomProvider() { assertThrows(NPE, () -> customerSelectorProvider.openSocketChannel(null)); assertThrows(NPE, () -> customerSelectorProvider.openServerSocketChannel(null)); assertThrows(UOE, () -> customerSelectorProvider.openSocketChannel(BAD_PF)); assertThrows(UOE, () -> customerSelectorProvider.openServerSocketChannel(BAD_PF)); } // Helper methods private static StandardProtocolFamily expectedFamily(StandardProtocolFamily family) { if (family == null) { return preferIPv4 ? INET : INET6; } else { return family; } } private static SocketChannel openSC(StandardProtocolFamily family) throws IOException { SocketChannel chan = family == null ? SocketChannel.open() : SocketChannel.open(family); return chan; } private static ServerSocketChannel openSSC(StandardProtocolFamily family) throws IOException { ServerSocketChannel chan = family == null ? ServerSocketChannel.open() : ServerSocketChannel.open(family); return chan; } private static DatagramChannel openDC(StandardProtocolFamily family) throws IOException { DatagramChannel chan = family == null ? DatagramChannel.open() : DatagramChannel.open(family); return chan; } private static SocketAddress getSocketAddress(StandardProtocolFamily family) { return family == null ? null : switch (family) { case INET -> new InetSocketAddress(ia4, 0); case INET6 -> new InetSocketAddress(ia6, 0); default -> throw new RuntimeException("Unexpected protocol family"); }; } private static SocketAddress getLoopback(StandardProtocolFamily family, int port) throws UnknownHostException { if ((family == null || family == INET6) && hasIPv6) { return new InetSocketAddress(InetAddress.getByName("::1"), port); } else { return new InetSocketAddress(InetAddress.getByName("127.0.0.1"), port); } } private static Inet4Address getLocalIPv4Address() throws Exception { return NetworkConfiguration.probe() .ip4Addresses() .filter(a -> !a.isLoopbackAddress()) .findFirst() .orElse((Inet4Address)InetAddress.getByName("0.0.0.0")); } private static Inet6Address getLocalIPv6Address() throws Exception { return NetworkConfiguration.probe() .ip6Addresses() .filter(a -> !a.isLoopbackAddress()) .findFirst() .orElse((Inet6Address) InetAddress.getByName("::0")); } }