1 /*
   2  * Copyright (c) 2007, 2019, 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  * @library /test/lib
  28  * @summary Re-test IPv6 (and specifically MulticastSocket) with latest Linux & USAGI code
  29  */
  30 import java.util.*;
  31 import java.net.*;
  32 import jdk.test.lib.net.IPSupport;
  33 
  34 public class NoLoopbackPackets {
  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 final String MESSAGE = "hello world (" + System.nanoTime() + ")";
  44     public static void main(String[] args) throws Exception {
  45         if (isWindows()) {
  46             System.out.println("The test only run on non-Windows OS. Bye.");
  47             return;
  48         }
  49 
  50         MulticastSocket msock = null;
  51         List<SocketAddress> failedGroups = new ArrayList<SocketAddress>();
  52         Sender sender = null;
  53         Thread senderThread = null;
  54         try {
  55             msock = new MulticastSocket();
  56             int port = msock.getLocalPort();
  57 
  58             // we will send packets to three multicast groups :-
  59             // 224.1.1.1, ::ffff:224.1.1.2, and ff02::1:1
  60             //
  61             List<SocketAddress> groups = new ArrayList<SocketAddress>();
  62             if (IPSupport.hasIPv4()) {
  63                 groups.add(new InetSocketAddress(InetAddress.getByName("224.1.1.1"), port));
  64             }
  65             if (IPSupport.hasIPv6()) {
  66                 groups.add(new InetSocketAddress(InetAddress.getByName("::ffff:224.1.1.2"), port));
  67                 groups.add(new InetSocketAddress(InetAddress.getByName("ff02::1:1"), port));
  68             }
  69             if (groups.isEmpty()) {
  70                 System.err.println("Nothing to test: there are no network interfaces");
  71             }
  72 
  73             sender = new Sender(groups);
  74             senderThread = new Thread(sender);
  75             senderThread.start();
  76 
  77             // Now try to receive multicast packets. we should not see any of them
  78             // since we disable loopback mode.
  79             //
  80             msock.setSoTimeout(5000);       // 5 seconds
  81 
  82             byte[] buf = new byte[1024];
  83             for (int i = 0; i < buf.length; i++) {
  84                 buf[i] = (byte) 'z';
  85             }
  86             DatagramPacket packet = new DatagramPacket(buf, 0, buf.length);
  87             byte[] expected = MESSAGE.getBytes();
  88             assert expected.length <= buf.length;
  89             for (SocketAddress group : groups) {
  90                 System.out.println("joining group: " + group);
  91                 msock.joinGroup(group, null);
  92 
  93                 try {
  94                     do {
  95                         for (int i = 0; i < buf.length; i++) {
  96                             buf[i] = (byte) 'a';
  97                         }
  98                         msock.receive(packet);
  99                         byte[] data = packet.getData();
 100                         int len = packet.getLength();
 101 
 102                         if (expected(data, len, expected)) {
 103                             failedGroups.add(group);
 104                             break;
 105                         } else {
 106                             System.err.println("WARNING: Unexpected packet received from "
 107                                                + group + ": "
 108                                                + len + " bytes");
 109                             System.err.println("\t as text: " + new String(data, 0, len));
 110                         }
 111                     } while (true);
 112                 } catch (SocketTimeoutException e) {
 113                     // we expect this
 114                     System.out.println("Received expected exception from " + group + ": " + e);
 115                 } finally {
 116                     msock.leaveGroup(group, null);
 117                 }
 118             }
 119         } finally {
 120             if (msock != null) try { msock.close(); } catch (Exception e) {}
 121             if (sender != null) {
 122                 sender.stop();
 123             }
 124         }
 125         try {
 126             if (failedGroups.size() > 0) {
 127                 System.out.println("We should not receive anything from following groups, but we did:");
 128                 for (SocketAddress group : failedGroups)
 129                     System.out.println(group);
 130                 throw new RuntimeException("test failed.");
 131             }
 132         } finally {
 133             if (senderThread != null) {
 134                 senderThread.join();
 135             }
 136         }
 137     }
 138 
 139     static boolean expected(byte[] data, int len, byte[] expected) {
 140         if (len != expected.length) return false;
 141         for (int i = 0; i < len; i++) {
 142             if (data[i] != expected[i]) return false;
 143         }
 144         return true;
 145     }
 146 
 147     static class Sender implements Runnable {
 148         private List<SocketAddress> sendToGroups;
 149         private volatile boolean stop;
 150 
 151         public Sender(List<SocketAddress> groups) {
 152             sendToGroups = groups;
 153         }
 154 
 155         public void run() {
 156             byte[] buf = MESSAGE.getBytes();
 157             List<DatagramPacket> packets = new ArrayList<DatagramPacket>();
 158 
 159             try (MulticastSocket msock = new MulticastSocket()) {
 160                 for (SocketAddress group : sendToGroups) {
 161                     DatagramPacket packet = new DatagramPacket(buf, buf.length, group);
 162                     packets.add(packet);
 163                 }
 164 
 165                 msock.setLoopbackMode(true);    // disable loopback mode
 166                 while (!stop) {
 167                     for (DatagramPacket packet : packets) {
 168                         msock.send(packet);
 169                     }
 170 
 171                     Thread.sleep(1000);     // 1 second
 172                 }
 173             } catch (Exception e) {
 174                 throw new RuntimeException(e);
 175             }
 176         }
 177 
 178         void stop() {
 179             stop = true;
 180         }
 181     }
 182 }