6887364: SetOutgoingIf.java fails if run on multihomed machine without PIv6 on all interfaces
authorchegar
Wed, 07 Oct 2009 17:23:02 +0100
changeset 3962 cf907ac8ca4c
parent 3961 778ecee935fa
child 3963 540aba73fd31
6887364: SetOutgoingIf.java fails if run on multihomed machine without PIv6 on all interfaces Reviewed-by: alanb
jdk/test/java/net/MulticastSocket/SetOutgoingIf.java
--- a/jdk/test/java/net/MulticastSocket/SetOutgoingIf.java	Tue Oct 06 22:01:18 2009 -0400
+++ b/jdk/test/java/net/MulticastSocket/SetOutgoingIf.java	Wed Oct 07 17:23:02 2009 +0100
@@ -27,7 +27,6 @@
  * @summary Re-test IPv6 (and specifically MulticastSocket) with latest Linux & USAGI code
  */
 import java.net.*;
-import java.util.concurrent.*;
 import java.util.*;
 
 
@@ -68,38 +67,61 @@
 
         // We need 2 or more network interfaces to run the test
         //
-        List<NetworkInterface> nics = new ArrayList<NetworkInterface>();
+        List<NetIf> netIfs = new ArrayList<NetIf>();
+        int index = 1;
         for (NetworkInterface nic : Collections.list(NetworkInterface.getNetworkInterfaces())) {
             // we should use only network interfaces with multicast support which are in "up" state
-            if (!nic.isLoopback() && nic.supportsMulticast() && nic.isUp())
-                nics.add(nic);
+            if (!nic.isLoopback() && nic.supportsMulticast() && nic.isUp()) {
+                NetIf netIf = NetIf.create(nic);
+
+                // now determine what (if any) type of addresses are assigned to this interface
+                for (InetAddress addr : Collections.list(nic.getInetAddresses())) {
+                    if (addr instanceof Inet4Address) {
+                        netIf.ipv4Address(true);
+                    } else if (addr instanceof Inet6Address) {
+                        netIf.ipv6Address(true);
+                    }
+                }
+                if (netIf.ipv4Address() || netIf.ipv6Address()) {
+                    netIf.index(index++);
+                    netIfs.add(netIf);
+                    debug("Using: " + nic);
+                }
+            }
         }
-        if (nics.size() <= 1) {
+        if (netIfs.size() <= 1) {
             System.out.println("Need 2 or more network interfaces to run. Bye.");
             return;
         }
 
-        // We will send packets to one ipv4, one ipv4-mapped, and one ipv6
+        // We will send packets to one ipv4, and one ipv6
         // multicast group using each network interface :-
         //      224.1.1.1        --|
-        //      ::ffff:224.1.1.2 -----> using network interface #1
-        //      ff02::1:1        --|
+        //      ff02::1:1        --|--> using network interface #1
         //      224.1.2.1        --|
-        //      ::ffff:224.1.2.2 -----> using network interface #2
-        //      ff02::1:2        --|
+        //      ff02::1:2        --|--> using network interface #2
         // and so on.
         //
-        List<InetAddress> groups = new ArrayList<InetAddress>();
-        for (int i = 0; i < nics.size(); i++) {
-            InetAddress groupv4 = InetAddress.getByName("224.1." + (i+1) + ".1");
-            InetAddress groupv4mapped = InetAddress.getByName("::ffff:224.1." + (i+1) + ".2");
-            InetAddress groupv6 = InetAddress.getByName("ff02::1:" + (i+1));
-            groups.add(groupv4);
-            groups.add(groupv4mapped);
-            groups.add(groupv6);
+        for (NetIf netIf : netIfs) {
+            int NetIfIndex = netIf.index();
+            List<InetAddress> groups = new ArrayList<InetAddress>();
 
-            // use a separated thread to send to those 3 groups
-            Thread sender = new Thread(new Sender(nics.get(i), groupv4, groupv4mapped, groupv6, PORT));
+            if (netIf.ipv4Address()) {
+                InetAddress groupv4 = InetAddress.getByName("224.1." + NetIfIndex + ".1");
+                groups.add(groupv4);
+            }
+            if (netIf.ipv6Address()) {
+                InetAddress groupv6 = InetAddress.getByName("ff02::1:" + NetIfIndex);
+                groups.add(groupv6);
+            }
+
+            debug("Adding " + groups + " groups for " + netIf.nic().getName());
+            netIf.groups(groups);
+
+            // use a separated thread to send to those 2 groups
+            Thread sender = new Thread(new Sender(netIf,
+                                                  groups,
+                                                  PORT));
             sender.setDaemon(true); // we want sender to stop when main thread exits
             sender.start();
         }
@@ -108,75 +130,135 @@
         // from the expected network interface
         //
         byte[] buf = new byte[1024];
-        for (InetAddress group : groups) {
-        MulticastSocket mcastsock = new MulticastSocket(PORT);
-        mcastsock.setSoTimeout(5000);   // 5 second
-            DatagramPacket packet = new DatagramPacket(buf, 0, buf.length);
-
-            mcastsock.joinGroup(new InetSocketAddress(group, PORT), nics.get(groups.indexOf(group) / 3));
+        for (NetIf netIf : netIfs) {
+            NetworkInterface nic = netIf.nic();
+            for (InetAddress group : netIf.groups()) {
+                MulticastSocket mcastsock = new MulticastSocket(PORT);
+                mcastsock.setSoTimeout(5000);   // 5 second
+                DatagramPacket packet = new DatagramPacket(buf, 0, buf.length);
 
-            try {
-                mcastsock.receive(packet);
-            } catch (Exception e) {
-                // test failed if any exception
-                throw new RuntimeException(e);
-            }
+                // the interface supports the IP multicast group
+                debug("Joining " + group + " on " + nic.getName());
+                mcastsock.joinGroup(new InetSocketAddress(group, PORT), nic);
+
+                try {
+                    mcastsock.receive(packet);
+                    debug("received packet on " + packet.getAddress());
+                } catch (Exception e) {
+                    // test failed if any exception
+                    throw new RuntimeException(e);
+                }
 
-            // now check which network interface this packet comes from
-            NetworkInterface from = NetworkInterface.getByInetAddress(packet.getAddress());
-            NetworkInterface shouldbe = nics.get(groups.indexOf(group) / 3);
-            if (!from.equals(shouldbe)) {
-                System.out.println("Packets on group "
-                                    + group + " should come from "
-                                    + shouldbe.getName() + ", but came from "
-                                    + from.getName());
-                //throw new RuntimeException("Test failed.");
+                // now check which network interface this packet comes from
+                NetworkInterface from = NetworkInterface.getByInetAddress(packet.getAddress());
+                NetworkInterface shouldbe = nic;
+                if (!from.equals(shouldbe)) {
+                    System.out.println("Packets on group "
+                                        + group + " should come from "
+                                        + shouldbe.getName() + ", but came from "
+                                        + from.getName());
+                    //throw new RuntimeException("Test failed.");
+                }
+
+                mcastsock.leaveGroup(new InetSocketAddress(group, PORT), nic);
             }
+        }
+    }
 
-            mcastsock.leaveGroup(new InetSocketAddress(group, PORT), nics.get(groups.indexOf(group) / 3));
-        }
+    private static boolean debug = true;
+
+    static void debug(String message) {
+        if (debug)
+            System.out.println(message);
     }
 }
 
 class Sender implements Runnable {
-    private NetworkInterface nic;
-    private InetAddress group1;
-    private InetAddress group2;
-    private InetAddress group3;
+    private NetIf netIf;
+    private List<InetAddress> groups;
     private int port;
 
-    public Sender(NetworkInterface nic,
-                    InetAddress groupv4, InetAddress groupv4mapped, InetAddress groupv6,
-                    int port) {
-        this.nic = nic;
-        group1 = groupv4;
-        group2 = groupv4mapped;
-        group3 = groupv6;
+    public Sender(NetIf netIf,
+                  List<InetAddress> groups,
+                  int port) {
+        this.netIf = netIf;
+        this.groups = groups;
         this.port = port;
     }
 
     public void run() {
         try {
             MulticastSocket mcastsock = new MulticastSocket();
-            mcastsock.setNetworkInterface(nic);
+            mcastsock.setNetworkInterface(netIf.nic());
+            List<DatagramPacket> packets = new LinkedList<DatagramPacket>();
 
             byte[] buf = "hello world".getBytes();
-            DatagramPacket packet1 = new DatagramPacket(buf, buf.length,
-                                        new InetSocketAddress(group1, port));
-            DatagramPacket packet2 = new DatagramPacket(buf, buf.length,
-                                        new InetSocketAddress(group2, port));
-            DatagramPacket packet3 = new DatagramPacket(buf, buf.length,
-                                        new InetSocketAddress(group3, port));
+            for (InetAddress group : groups) {
+                packets.add(new DatagramPacket(buf, buf.length, new InetSocketAddress(group, port)));
+            }
 
             for (;;) {
-                mcastsock.send(packet1);
-                mcastsock.send(packet2);
-                mcastsock.send(packet3);
+                for (DatagramPacket packet : packets)
+                    mcastsock.send(packet);
 
-                Thread.currentThread().sleep(1000);   // sleep 1 second
+                Thread.sleep(1000);   // sleep 1 second
             }
         } catch (Exception e) {
             throw new RuntimeException(e);
         }
     }
 }
+
+@SuppressWarnings("unchecked")
+class NetIf {
+    private boolean ipv4Address; //false
+    private boolean ipv6Address; //false
+    private int index;
+    List<InetAddress> groups = Collections.EMPTY_LIST;
+    private final NetworkInterface nic;
+
+    private NetIf(NetworkInterface nic) {
+        this.nic = nic;
+    }
+
+    static NetIf create(NetworkInterface nic) {
+        return new NetIf(nic);
+    }
+
+    NetworkInterface nic() {
+        return nic;
+    }
+
+    boolean ipv4Address() {
+        return ipv4Address;
+    }
+
+    void ipv4Address(boolean ipv4Address) {
+        this.ipv4Address = ipv4Address;
+    }
+
+    boolean ipv6Address() {
+        return ipv6Address;
+    }
+
+    void ipv6Address(boolean ipv6Address) {
+        this.ipv6Address = ipv6Address;
+    }
+
+    int index() {
+        return index;
+    }
+
+    void index(int index) {
+        this.index = index;
+    }
+
+    List<InetAddress> groups() {
+        return groups;
+    }
+
+    void groups(List<InetAddress> groups) {
+        this.groups = groups;
+    }
+}
+