1 /*
   2  * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /*
  25  * @test
  26  * @bug 4742177
  27  * @summary Re-test IPv6 (and specifically MulticastSocket) with latest Linux & USAGI code
  28  */
  29 import java.net.*;
  30 import java.util.*;
  31 
  32 
  33 public class SetOutgoingIf {
  34     private static int PORT = 9001;
  35     private static String osname;
  36 
  37     static boolean isWindows() {
  38         if (osname == null)
  39             osname = System.getProperty("os.name");
  40         return osname.contains("Windows");
  41     }
  42 
  43     private static boolean hasIPv6() throws Exception {
  44         List<NetworkInterface> nics = Collections.list(
  45                                         NetworkInterface.getNetworkInterfaces());
  46         for (NetworkInterface nic : nics) {
  47             List<InetAddress> addrs = Collections.list(nic.getInetAddresses());
  48             for (InetAddress addr : addrs) {
  49                 if (addr instanceof Inet6Address)
  50                     return true;
  51             }
  52         }
  53 
  54         return false;
  55     }
  56 
  57     public static void main(String[] args) throws Exception {
  58         if (isWindows()) {
  59             System.out.println("The test only run on non-Windows OS. Bye.");
  60             return;
  61         }
  62 
  63         if (!hasIPv6()) {
  64             System.out.println("No IPv6 available. Bye.");
  65             return;
  66         }
  67 
  68         // We need 2 or more network interfaces to run the test
  69         //
  70         List<NetworkInterface> nics = new ArrayList<NetworkInterface>();
  71         for (NetworkInterface nic : Collections.list(NetworkInterface.getNetworkInterfaces())) {
  72             // we should use only network interfaces with multicast support which are in "up" state
  73             if (!nic.isLoopback() && nic.supportsMulticast() && nic.isUp())
  74                 nics.add(nic);
  75         }
  76         if (nics.size() <= 1) {
  77             System.out.println("Need 2 or more network interfaces to run. Bye.");
  78             return;
  79         }
  80 
  81         // We will send packets to one ipv4, one ipv4-mapped, and one ipv6
  82         // multicast group using each network interface :-
  83         //      224.1.1.1        --|
  84         //      ::ffff:224.1.1.2 -----> using network interface #1
  85         //      ff02::1:1        --|
  86         //      224.1.2.1        --|
  87         //      ::ffff:224.1.2.2 -----> using network interface #2
  88         //      ff02::1:2        --|
  89         // and so on.
  90         //
  91         List<InetAddress> groups = new ArrayList<InetAddress>();
  92         for (int i = 0; i < nics.size(); i++) {
  93             InetAddress groupv4 = InetAddress.getByName("224.1." + (i+1) + ".1");
  94             InetAddress groupv4mapped = InetAddress.getByName("::ffff:224.1." + (i+1) + ".2");
  95             InetAddress groupv6 = InetAddress.getByName("ff02::1:" + (i+1));
  96             groups.add(groupv4);
  97             groups.add(groupv4mapped);
  98             groups.add(groupv6);
  99 
 100             // use a separated thread to send to those 3 groups
 101             Thread sender = new Thread(new Sender(nics.get(i), groupv4, groupv4mapped, groupv6, PORT));
 102             sender.setDaemon(true); // we want sender to stop when main thread exits
 103             sender.start();
 104         }
 105 
 106         // try to receive on each group, then check if the packet comes
 107         // from the expected network interface
 108         //
 109         byte[] buf = new byte[1024];
 110         for (InetAddress group : groups) {
 111         MulticastSocket mcastsock = new MulticastSocket(PORT);
 112         mcastsock.setSoTimeout(5000);   // 5 second
 113             DatagramPacket packet = new DatagramPacket(buf, 0, buf.length);
 114 
 115             mcastsock.joinGroup(new InetSocketAddress(group, PORT), nics.get(groups.indexOf(group) / 3));
 116 
 117             try {
 118                 mcastsock.receive(packet);
 119             } catch (Exception e) {
 120                 // test failed if any exception
 121                 throw new RuntimeException(e);
 122             }
 123 
 124             // now check which network interface this packet comes from
 125             NetworkInterface from = NetworkInterface.getByInetAddress(packet.getAddress());
 126             NetworkInterface shouldbe = nics.get(groups.indexOf(group) / 3);
 127             if (!from.equals(shouldbe)) {
 128                 System.out.println("Packets on group "
 129                                     + group + " should come from "
 130                                     + shouldbe.getName() + ", but came from "
 131                                     + from.getName());
 132                 //throw new RuntimeException("Test failed.");
 133             }
 134 
 135             mcastsock.leaveGroup(new InetSocketAddress(group, PORT), nics.get(groups.indexOf(group) / 3));
 136         }
 137     }
 138 }
 139 
 140 class Sender implements Runnable {
 141     private NetworkInterface nic;
 142     private InetAddress group1;
 143     private InetAddress group2;
 144     private InetAddress group3;
 145     private int port;
 146 
 147     public Sender(NetworkInterface nic,
 148                     InetAddress groupv4, InetAddress groupv4mapped, InetAddress groupv6,
 149                     int port) {
 150         this.nic = nic;
 151         group1 = groupv4;
 152         group2 = groupv4mapped;
 153         group3 = groupv6;
 154         this.port = port;
 155     }
 156 
 157     public void run() {
 158         try {
 159             MulticastSocket mcastsock = new MulticastSocket();
 160             mcastsock.setNetworkInterface(nic);
 161 
 162             byte[] buf = "hello world".getBytes();
 163             DatagramPacket packet1 = new DatagramPacket(buf, buf.length,
 164                                         new InetSocketAddress(group1, port));
 165             DatagramPacket packet2 = new DatagramPacket(buf, buf.length,
 166                                         new InetSocketAddress(group2, port));
 167             DatagramPacket packet3 = new DatagramPacket(buf, buf.length,
 168                                         new InetSocketAddress(group3, port));
 169 
 170             for (;;) {
 171                 mcastsock.send(packet1);
 172                 mcastsock.send(packet2);
 173                 mcastsock.send(packet3);
 174 
 175                 Thread.sleep(1000);   // sleep 1 second
 176             }
 177         } catch (Exception e) {
 178             throw new RuntimeException(e);
 179         }
 180     }
 181 }