Path: blob/master/test/jdk/java/net/MulticastSocket/SetOutgoingIf.java
41149 views
/*1* Copyright (c) 2007, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/*24* @test25* @bug 4742177 824178626* @library /test/lib27* @run main/othervm SetOutgoingIf28* @run main/othervm -Djdk.net.usePlainDatagramSocketImpl SetOutgoingIf29* @summary Re-test IPv6 (and specifically MulticastSocket) with latest Linux & USAGI code30*/31import java.io.IOException;32import java.net.*;33import java.util.*;34import java.util.concurrent.ConcurrentHashMap;35import jdk.test.lib.NetworkConfiguration;363738public class SetOutgoingIf implements AutoCloseable {39private static String osname;40private final MulticastSocket SOCKET;41private final int PORT;42private final Map<NetIf, MulticastSender> sendersMap = new ConcurrentHashMap<>();43private SetOutgoingIf() {44try {45SOCKET = new MulticastSocket();46PORT = SOCKET.getLocalPort();47} catch (IOException io) {48throw new ExceptionInInitializerError(io);49}50}5152static boolean isWindows() {53if (osname == null)54osname = System.getProperty("os.name");55return osname.contains("Windows");56}5758static boolean isMacOS() {59return System.getProperty("os.name").contains("OS X");60}6162private static boolean hasIPv6() throws Exception {63return NetworkConfiguration.probe()64.ip6Addresses()65.findAny()66.isPresent();67}6869public static void main(String[] args) throws Exception {70try (var test = new SetOutgoingIf()) {71test.run();72}73}7475@Override76public void close() {77try {78SOCKET.close();79} finally {80sendersMap.values().stream().forEach(MulticastSender::close);81}82}8384public void run() throws Exception {85if (isWindows()) {86System.out.println("The test only run on non-Windows OS. Bye.");87return;88}8990if (!hasIPv6()) {91System.out.println("No IPv6 available. Bye.");92return;93}9495// We need 2 or more network interfaces to run the test96//97List<NetIf> netIfs = new ArrayList<NetIf>();98int index = 1;99for (NetworkInterface nic : Collections.list(NetworkInterface.getNetworkInterfaces())) {100// we should use only network interfaces with multicast support which are in "up" state101if (!nic.isLoopback() && nic.supportsMulticast() && nic.isUp() && !isTestExcludedInterface(nic)) {102NetIf netIf = NetIf.create(nic);103104// now determine what (if any) type of addresses are assigned to this interface105for (InetAddress addr : Collections.list(nic.getInetAddresses())) {106if (addr.isAnyLocalAddress())107continue;108109System.out.println(" addr " + addr);110if (addr instanceof Inet4Address) {111netIf.ipv4Address(true);112} else if (addr instanceof Inet6Address) {113netIf.ipv6Address(true);114}115}116if (netIf.ipv4Address() || netIf.ipv6Address()) {117netIf.index(index++);118netIfs.add(netIf);119debug("Using: " + nic);120}121} else {122System.out.println("Ignore NetworkInterface nic == " + nic);123}124}125Collections.reverse(netIfs);126if (netIfs.size() <= 1) {127System.out.println("Need 2 or more network interfaces to run. Bye.");128return;129}130131System.out.println("Using PORT: " + PORT);132133// We will send packets to one ipv4, and one ipv6134// multicast group using each network interface :-135// 224.1.1.1 --|136// ff02::1:1 --|--> using network interface #1137// 224.1.2.1 --|138// ff02::1:2 --|--> using network interface #2139// and so on.140//141for (NetIf netIf : netIfs) {142int NetIfIndex = netIf.index();143List<InetAddress> groups = new ArrayList<InetAddress>();144145if (netIf.ipv4Address()) {146InetAddress groupv4 = InetAddress.getByName("224.1." + NetIfIndex + ".1");147groups.add(groupv4);148}149if (netIf.ipv6Address()) {150InetAddress groupv6 = InetAddress.getByName("ff02::1:" + NetIfIndex);151groups.add(groupv6);152}153154debug("Adding " + groups + " groups for " + netIf.nic().getName());155netIf.groups(groups);156157// use a separated thread to send to those 2 groups158var multicastSender = new MulticastSender(netIf, groups, PORT);159sendersMap.put(netIf, multicastSender);160Thread sender = new Thread(multicastSender);161sender.setDaemon(true); // we want sender to stop when main thread exits162sender.start();163}164165// try to receive on each group, then check if the packet comes166// from the expected network interface167//168byte[] buf = new byte[1024];169for (NetIf netIf : netIfs) {170NetworkInterface nic = netIf.nic();171for (InetAddress group : netIf.groups()) {172try (MulticastSocket mcastsock = new MulticastSocket(PORT)) {173mcastsock.setSoTimeout(5000); // 5 second174DatagramPacket packet = new DatagramPacket(buf, 0, buf.length);175176// the interface supports the IP multicast group177debug("Joining " + group + " on " + nic.getName());178mcastsock.joinGroup(new InetSocketAddress(group, PORT), nic);179180try {181mcastsock.receive(packet);182debug("received packet on " + packet.getAddress());183} catch (Exception e) {184// test failed if any exception185throw new RuntimeException(e);186}187188// now check which network interface this packet comes from189NetworkInterface from = NetworkInterface.getByInetAddress(packet.getAddress());190NetworkInterface shouldbe = nic;191if (from != null) {192if (!from.equals(shouldbe)) {193System.out.println("Packets on group "194+ group + " should come from "195+ shouldbe.getName() + ", but came from "196+ from.getName());197}198}199200mcastsock.leaveGroup(new InetSocketAddress(group, PORT), nic);201}202}203}204}205206private static boolean isTestExcludedInterface(NetworkInterface nif) {207return !NetworkConfiguration.isTestable(nif)208|| isMacOS() && nif.getName().startsWith("utun")209|| !NetworkConfiguration.hasNonLinkLocalAddress(nif);210}211212private static boolean debug = true;213214static void debug(String message) {215if (debug)216System.out.println(message);217}218}219220class MulticastSender implements Runnable, AutoCloseable {221private final NetIf netIf;222private final List<InetAddress> groups;223private final int port;224private volatile boolean closed;225private long count;226227public MulticastSender(NetIf netIf,228List<InetAddress> groups,229int port) {230this.netIf = netIf;231this.groups = groups;232this.port = port;233}234235@Override236public void close() {237closed = true;238}239240public void run() {241var nic = netIf.nic();242try (MulticastSocket mcastsock = new MulticastSocket()) {243mcastsock.setNetworkInterface(nic);244List<DatagramPacket> packets = new LinkedList<DatagramPacket>();245246byte[] buf = "hello world".getBytes();247for (InetAddress group : groups) {248packets.add(new DatagramPacket(buf, buf.length, new InetSocketAddress(group, port)));249}250251while (!closed) {252for (DatagramPacket packet : packets) {253mcastsock.send(packet);254count++;255}256System.out.printf("Sent %d packets from %s\n", count, nic.getName());257Thread.sleep(1000); // sleep 1 second258}259} catch (Exception e) {260if (!closed) {261System.err.println("Unexpected exception for MulticastSender("262+ nic.getName() + "): " + e);263e.printStackTrace();264throw new RuntimeException(e);265}266} finally {267System.out.printf("Sent %d packets from %s\n", count, nic.getName());268}269}270}271272@SuppressWarnings("unchecked")273class NetIf {274private boolean ipv4Address; //false275private boolean ipv6Address; //false276private int index;277List<InetAddress> groups = Collections.EMPTY_LIST;278private final NetworkInterface nic;279280private NetIf(NetworkInterface nic) {281this.nic = nic;282}283284static NetIf create(NetworkInterface nic) {285return new NetIf(nic);286}287288NetworkInterface nic() {289return nic;290}291292boolean ipv4Address() {293return ipv4Address;294}295296void ipv4Address(boolean ipv4Address) {297this.ipv4Address = ipv4Address;298}299300boolean ipv6Address() {301return ipv6Address;302}303304void ipv6Address(boolean ipv6Address) {305this.ipv6Address = ipv6Address;306}307308int index() {309return index;310}311312void index(int index) {313this.index = index;314}315316List<InetAddress> groups() {317return groups;318}319320void groups(List<InetAddress> groups) {321this.groups = groups;322}323}324325326