| /* | |
| * 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.net.IPSupport; | |
| import org.testng.annotations.BeforeTest; | |
| import org.testng.annotations.DataProvider; | |
| import org.testng.annotations.Test; | |
| import java.io.IOException; | |
| import java.net.*; | |
| import java.nio.channels.*; | |
| import java.util.Arrays; | |
| import java.util.List; | |
| import java.util.LinkedList; | |
| import static java.lang.System.getProperty; | |
| import static java.lang.System.out; | |
| import static java.net.StandardProtocolFamily.INET; | |
| import static java.net.StandardProtocolFamily.INET6; | |
| import static jdk.test.lib.net.IPSupport.*; | |
| /* | |
| * @test | |
| * @summary Test SocketChannel, ServerSocketChannel and DatagramChannel | |
| * open() and connect(), taking into consideration combinations of | |
| * protocol families (INET, INET6, default), | |
| * addresses (Inet4Address, Inet6Address). | |
| * @library /test/lib | |
| * @build jdk.test.lib.NetworkConfiguration | |
| * @run testng/othervm OpenAndConnect | |
| */ | |
| public class OpenAndConnect { | |
| static final Inet4Address IA4ANYLOCAL; | |
| static final Inet6Address IA6ANYLOCAL; | |
| static final Inet4Address IA4LOOPBACK; | |
| static final Inet6Address IA6LOOPBACK; | |
| static Inet4Address IA4LOCAL = null; | |
| static Inet6Address IA6LOCAL = null; | |
| static InetAddress DONT_BIND; | |
| static { | |
| try { | |
| IA4ANYLOCAL = (Inet4Address) InetAddress.getByName("0.0.0.0"); | |
| IA6ANYLOCAL = (Inet6Address) InetAddress.getByName("::0"); | |
| IA4LOOPBACK = (Inet4Address) InetAddress.getByName("127.0.0.1"); | |
| IA6LOOPBACK = (Inet6Address) InetAddress.getByName("::1"); | |
| // Special value to tell test not to call bind (address is not used) | |
| DONT_BIND = (Inet4Address) InetAddress.getByName("127.0.0.3"); | |
| initAddrs(); | |
| } catch (Exception e) { | |
| throw new RuntimeException("Could not initialize addresses", e); | |
| } | |
| } | |
| @BeforeTest() | |
| public void setup() { | |
| NetworkConfiguration.printSystemConfiguration(out); | |
| IPSupport.printPlatformSupport(out); | |
| throwSkippedExceptionIfNonOperational(); | |
| out.println("IA4LOCAL: " + IA4LOCAL); | |
| out.println("IA6LOCAL: " + IA6LOCAL); | |
| out.println("IA4ANYLOCAL: " + IA4ANYLOCAL); | |
| out.println("IA6ANYLOCAL: " + IA6ANYLOCAL); | |
| out.println("IA4LOOPBACK: " + IA4LOOPBACK); | |
| out.println("IA6LOOPBACK: " + IA6LOOPBACK); | |
| } | |
| @DataProvider(name = "openConnect") | |
| public Object[][] openConnect() { | |
| LinkedList<Object[]> l = new LinkedList<>(); | |
| if (IPSupport.hasIPv4()) { | |
| l.addAll(openConnectV4Tests); | |
| if (IA4LOCAL != null) { | |
| l.addAll(openConnectV4LocalTests); | |
| } | |
| } | |
| if (IPSupport.hasIPv6()) { | |
| l.addAll(openConnectV6Tests); | |
| if (IA6LOCAL != null) { | |
| l.addAll(openConnectV6LocalTests); | |
| } | |
| } | |
| if (IPSupport.hasIPv4() && IPSupport.hasIPv6()) { | |
| l.addAll(openConnectV4AndV6Tests); | |
| if (IA4LOCAL != null) { | |
| l.addAll(openConnectV4LocalAndV6Tests); | |
| } | |
| } | |
| return l.toArray(new Object[][]{}); | |
| } | |
| // +----- sfam is server/first socket family | |
| // | | |
| // | +------ saddr is bind address for server/first socket | |
| // | | | |
| // | | +---- cfam is family for client/second socket | |
| // | | | | |
| // | | | +---- caddr is address client/second | |
| // | | | | socket binds to. When the server | |
| // | | | | has bound to a wildcard address | |
| // | | | | this is address used for connect | |
| // | | | | also. | |
| // | | | | | |
| // | | | | | |
| // | | | | | |
| // | | | | | |
| // + + + + | |
| // { sfam, saddr, cfam, caddr, } | |
| // Basic tests for when an IPv4 is available | |
| public static List<Object[]> openConnectV4Tests = | |
| Arrays.asList(new Object[][] { | |
| { INET, IA4LOOPBACK, INET, IA4LOOPBACK }, | |
| { INET, IA4LOOPBACK, null, IA4LOOPBACK }, | |
| { INET, IA4ANYLOCAL, null, IA4LOOPBACK }, | |
| { INET, IA4ANYLOCAL, INET, IA4LOOPBACK }, | |
| { null, IA4LOOPBACK, INET, IA4ANYLOCAL }, | |
| { null, IA4LOOPBACK, INET, IA4LOOPBACK }, | |
| { null, IA4LOOPBACK, INET, null }, | |
| { null, IA4LOOPBACK, null, null } | |
| }); | |
| // Additional tests for when an IPv4 local address is available | |
| public List<Object[]> openConnectV4LocalTests = | |
| Arrays.asList(new Object[][] { | |
| { INET, IA4LOCAL, INET, IA4LOCAL }, | |
| { INET, IA4LOCAL, null, IA4LOCAL }, | |
| { INET, IA4LOCAL, null, DONT_BIND }, | |
| { INET, IA4ANYLOCAL, INET, IA4LOCAL }, | |
| { INET, IA4ANYLOCAL, null, IA4LOCAL }, | |
| { null, IA4LOCAL, INET, IA4ANYLOCAL }, | |
| { null, IA4LOCAL, INET, IA4LOCAL }, | |
| { null, IA4LOCAL, INET, null }, | |
| { null, IA4LOCAL, null, null } | |
| }); | |
| // Basic tests for when an IPv6 is available | |
| public List<Object[]> openConnectV6Tests = | |
| Arrays.asList(new Object[][] { | |
| { INET6, IA6ANYLOCAL, null, IA6LOOPBACK }, | |
| { INET6, IA6ANYLOCAL, INET6, IA6LOOPBACK }, | |
| { INET6, IA6LOOPBACK, INET6, IA6LOOPBACK }, | |
| { INET6, IA6LOOPBACK, INET6, IA6LOOPBACK }, | |
| { null, IA6ANYLOCAL, null, IA6LOOPBACK }, | |
| { null, IA6ANYLOCAL, INET6, IA6LOOPBACK }, | |
| { null, IA6LOOPBACK, INET6, IA6LOOPBACK }, | |
| { null, IA6LOOPBACK, INET6, DONT_BIND }, | |
| { null, IA6LOOPBACK, INET6, null }, | |
| { null, IA6LOOPBACK, null, IA6LOOPBACK }, | |
| { null, IA6LOOPBACK, null, null }, | |
| { null, IA6LOOPBACK, INET6, IA6ANYLOCAL }, | |
| { null, IA6LOOPBACK, null, IA6ANYLOCAL } | |
| }); | |
| // Additional tests for when an IPv6 local address is available | |
| public List<Object[]> openConnectV6LocalTests = | |
| Arrays.asList(new Object[][] { | |
| { INET6, IA6ANYLOCAL, null, IA6LOCAL }, | |
| { INET6, IA6ANYLOCAL, INET6, IA6LOCAL }, | |
| { INET6, IA6LOCAL, INET6, IA6LOCAL }, | |
| { INET6, IA6LOCAL, null, IA6LOCAL }, | |
| { INET6, IA6LOCAL, null, DONT_BIND }, | |
| { INET6, IA6LOCAL, INET6, IA6LOCAL }, | |
| { null, IA6ANYLOCAL, null, IA6LOCAL }, | |
| { null, IA6ANYLOCAL, INET6, IA6LOCAL }, | |
| { null, IA6LOCAL, INET6, IA6LOCAL }, | |
| { null, IA6LOCAL, INET6, IA6ANYLOCAL }, | |
| { null, IA6LOCAL, null, IA6ANYLOCAL }, | |
| { null, IA6LOCAL, null, IA6LOCAL }, | |
| { null, IA6LOCAL, INET6, null }, | |
| { null, IA6LOCAL, null, null } | |
| }); | |
| // Additional tests for when IPv4 and IPv6 are available | |
| public List<Object[]> openConnectV4AndV6Tests = | |
| Arrays.asList(new Object[][] { | |
| { null, IA4LOOPBACK, INET6, IA6ANYLOCAL }, | |
| { null, IA4LOOPBACK, null, IA6ANYLOCAL }, | |
| { null, IA4LOOPBACK, INET6, DONT_BIND }, | |
| { null, IA4LOOPBACK, INET6, null } | |
| }); | |
| // Additional tests for when IPv4 local address and IPv6 are available | |
| public List<Object[]> openConnectV4LocalAndV6Tests = | |
| Arrays.asList(new Object[][] { | |
| { null, IA4LOCAL, INET6, IA6ANYLOCAL }, | |
| { null, IA4LOCAL, INET6, null }, | |
| { null, IA4LOCAL, null, IA6ANYLOCAL } | |
| }); | |
| /** | |
| * If the destination address is the wildcard, it is replaced by the alternate | |
| * using the port number from destination. Otherwise destination is returned. | |
| * Only used by dcOpenAndConnect | |
| */ | |
| static InetSocketAddress getDestinationAddress(SocketAddress destination, InetAddress alternate) { | |
| InetSocketAddress isa = (InetSocketAddress)destination; | |
| if (isa.getAddress().isAnyLocalAddress()) | |
| return new InetSocketAddress(alternate, isa.getPort()); | |
| else | |
| return isa; | |
| } | |
| @Test(dataProvider = "openConnect") | |
| public void scOpenAndConnect(ProtocolFamily sfam, | |
| InetAddress saddr, | |
| ProtocolFamily cfam, | |
| InetAddress caddr) throws IOException | |
| { | |
| out.printf("scOpenAndConnect: server bind: %s client bind: %s\n", saddr, caddr); | |
| try (ServerSocketChannel ssc = openSSC(sfam)) { | |
| ssc.bind(getSocketAddress(saddr)); | |
| InetSocketAddress ssa = (InetSocketAddress)ssc.getLocalAddress(); | |
| ssa = getDestinationAddress(ssa, caddr); | |
| out.println(ssa); | |
| try (SocketChannel csc = openSC(cfam)) { | |
| if (caddr != DONT_BIND) { | |
| csc.bind(getSocketAddress(caddr)); | |
| } | |
| csc.connect(ssa); | |
| } | |
| } | |
| } | |
| @Test(dataProvider = "openConnect") | |
| public void dcOpenAndConnect(ProtocolFamily sfam, | |
| InetAddress saddr, | |
| ProtocolFamily cfam, | |
| InetAddress caddr) throws IOException | |
| { | |
| try (DatagramChannel sdc = openDC(sfam)) { | |
| sdc.bind(getSocketAddress(saddr)); | |
| SocketAddress ssa = sdc.socket().getLocalSocketAddress(); | |
| ssa = getDestinationAddress(ssa, caddr); | |
| out.println(ssa); | |
| try (DatagramChannel dc = openDC(cfam)) { | |
| if (caddr != DONT_BIND) { | |
| dc.bind(getSocketAddress(caddr)); | |
| } | |
| dc.connect(ssa); | |
| } | |
| } | |
| } | |
| // Helper methods | |
| private static SocketChannel openSC(ProtocolFamily fam) throws IOException { | |
| return fam == null ? SocketChannel.open() : SocketChannel.open(fam); | |
| } | |
| private static ServerSocketChannel openSSC(ProtocolFamily fam) | |
| throws IOException { | |
| return fam == null ? ServerSocketChannel.open() | |
| : ServerSocketChannel.open(fam); | |
| } | |
| private static DatagramChannel openDC(ProtocolFamily fam) | |
| throws IOException { | |
| return fam == null ? DatagramChannel.open() | |
| : DatagramChannel.open(fam); | |
| } | |
| private static SocketAddress getSocketAddress(InetAddress ia) { | |
| return ia == null ? null : new InetSocketAddress(ia, 0); | |
| } | |
| private static void initAddrs() throws IOException { | |
| NetworkConfiguration cfg = NetworkConfiguration.probe(); | |
| IA4LOCAL = cfg.ip4Addresses() | |
| .filter(a -> !a.isLoopbackAddress()) | |
| .findFirst() | |
| .orElse(null); | |
| IA6LOCAL = cfg.ip6Addresses() | |
| .filter(a -> !a.isLoopbackAddress()) | |
| .findFirst() | |
| .orElse(null); | |
| } | |
| } |