test/jdk/java/net/MulticastSocket/PromiscuousIPv6.java
changeset 55375 96c7427456f9
equal deleted inserted replaced
55374:5c4f1b7c753b 55375:96c7427456f9
       
     1 /*
       
     2  * Copyright (c) 2018, 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 8215294
       
    27  * @requires os.family == "linux"
       
    28  * @library /test/lib
       
    29  * @build jdk.test.lib.NetworkConfiguration
       
    30  *        PromiscuousIPv6
       
    31  * @run main/othervm PromiscuousIPv6
       
    32  * @key randomness
       
    33  */
       
    34 
       
    35 import java.io.IOException;
       
    36 import java.net.DatagramPacket;
       
    37 import java.net.DatagramSocket;
       
    38 import java.net.InetAddress;
       
    39 import java.net.Inet6Address;
       
    40 import java.net.InetSocketAddress;
       
    41 import java.net.MulticastSocket;
       
    42 import java.net.NetworkInterface;
       
    43 import java.net.SocketTimeoutException;
       
    44 import java.net.StandardSocketOptions;
       
    45 import java.util.List;
       
    46 import java.util.Random;
       
    47 import jdk.test.lib.NetworkConfiguration;
       
    48 import jtreg.SkippedException;
       
    49 import static java.lang.System.out;
       
    50 import static java.nio.charset.StandardCharsets.UTF_8;
       
    51 import static java.util.stream.Collectors.toList;
       
    52 
       
    53 /*
       
    54  * This test was created as a clone of the Promiscuous test and adapted for
       
    55  * IPv6 node-local and link-local multicast addresses on Linux.
       
    56  */
       
    57 public class PromiscuousIPv6 {
       
    58 
       
    59     static final Random rand = new Random();
       
    60 
       
    61     static final int TIMEOUT =  5 * 1000; // 5 secs
       
    62 
       
    63     static int sendDatagram(NetworkInterface nif, InetAddress group, int port)
       
    64         throws IOException
       
    65     {
       
    66         try (MulticastSocket mc = new MulticastSocket()) {
       
    67             mc.setOption(StandardSocketOptions.IP_MULTICAST_IF, nif);
       
    68 
       
    69             int id = rand.nextInt();
       
    70             byte[] msg = Integer.toString(id).getBytes(UTF_8);
       
    71             DatagramPacket p = new DatagramPacket(msg, msg.length);
       
    72             p.setAddress(group);
       
    73             p.setPort(port);
       
    74 
       
    75             out.printf("Sending datagram to: %s/%d\n", group, port);
       
    76             mc.send(p);
       
    77             return id;
       
    78         }
       
    79     }
       
    80 
       
    81     static void receiveDatagram(DatagramSocket mc, boolean datagramExpected, int id)
       
    82         throws IOException
       
    83     {
       
    84         byte[] ba = new byte[100];
       
    85         DatagramPacket p = new DatagramPacket(ba, ba.length);
       
    86         try {
       
    87             mc.receive(p);
       
    88             int recvId = Integer.parseInt(
       
    89                     new String(p.getData(), 0, p.getLength(), UTF_8));
       
    90             if (datagramExpected) {
       
    91                 if (recvId != id)
       
    92                     throw new RuntimeException("Unexpected id, got " + recvId
       
    93                                                        + ", expected: " + id);
       
    94                 out.printf("Received message as expected, %s\n", p.getAddress());
       
    95             } else {
       
    96                 throw new RuntimeException("Unexpected message received, "
       
    97                                                    + p.getAddress());
       
    98             }
       
    99         } catch (SocketTimeoutException e) {
       
   100             if (datagramExpected)
       
   101                 throw new RuntimeException("Expected message not received, "
       
   102                                                    + e.getMessage());
       
   103             else
       
   104                 out.printf("Message not received, as expected\n");
       
   105         }
       
   106     }
       
   107 
       
   108     static void test(NetworkInterface nif, InetAddress group1, InetAddress group2)
       
   109         throws IOException
       
   110     {
       
   111         // Bind addresses should include the same network interface / scope, so
       
   112         // as to not reply on the default route when there are multiple interfaces
       
   113         InetAddress bindAddr1 = Inet6Address.getByAddress(null, group1.getAddress(), nif);
       
   114         InetAddress bindAddr2 = Inet6Address.getByAddress(null, group2.getAddress(), nif);
       
   115 
       
   116         try (MulticastSocket mc1 = new MulticastSocket(new InetSocketAddress(bindAddr1, 0));
       
   117              MulticastSocket mc2 = new MulticastSocket(new InetSocketAddress(bindAddr2, mc1.getLocalPort()))) {
       
   118 
       
   119             final int port = mc1.getLocalPort();
       
   120             out.printf("Using port: %d\n", port);
       
   121 
       
   122             mc1.setSoTimeout(TIMEOUT);
       
   123             mc2.setSoTimeout(TIMEOUT);
       
   124 
       
   125             mc1.joinGroup(new InetSocketAddress(group1, 0), nif);
       
   126             out.printf("mc1 joined the MC group: %s\n", group1);
       
   127             mc2.joinGroup(new InetSocketAddress(group2, 0), nif);
       
   128             out.printf("mc2 joined the MC group: %s\n", group2);
       
   129 
       
   130             out.printf("Sending datagram to: %s/%d\n", group1, port);
       
   131             int id = sendDatagram(nif, group1, port);
       
   132 
       
   133             // the packet should be received by mc1 only
       
   134             receiveDatagram(mc1, true, id);
       
   135             receiveDatagram(mc2, false, 0);
       
   136 
       
   137 
       
   138             out.printf("Sending datagram to: %s/%d\n", group2, port);
       
   139             id = sendDatagram(nif, group2, port);
       
   140 
       
   141             // the packet should be received by mc2 only
       
   142             receiveDatagram(mc2, true, id);
       
   143             receiveDatagram(mc1, false, 0);
       
   144 
       
   145             mc1.leaveGroup(new InetSocketAddress(group1, 0), nif);
       
   146             mc2.leaveGroup(new InetSocketAddress(group2, 0), nif);
       
   147         }
       
   148     }
       
   149 
       
   150     public static void main(String args[]) throws IOException {
       
   151         String os = System.getProperty("os.name");
       
   152 
       
   153         if (!os.equals("Linux")) {
       
   154             throw new SkippedException("This test should be run only on Linux");
       
   155         } else {
       
   156             String osVersion = System.getProperty("os.version");
       
   157             String prefix = "3.10.0";
       
   158             if (osVersion.startsWith(prefix)) {
       
   159                 throw new SkippedException(
       
   160                         String.format("The behavior under test is known NOT to work on '%s' kernels", prefix));
       
   161             }
       
   162         }
       
   163 
       
   164         NetworkConfiguration.printSystemConfiguration(System.out);
       
   165         List<NetworkInterface> nifs = NetworkConfiguration.probe()
       
   166               .ip6MulticastInterfaces()
       
   167               .collect(toList());
       
   168 
       
   169         if (nifs.size() == 0) {
       
   170             throw new SkippedException(
       
   171                  "No IPv6 interfaces that support multicast found");
       
   172         }
       
   173 
       
   174         InetAddress interfaceLocal1 = InetAddress.getByName("ff11::3.4.5.6");
       
   175         InetAddress interfaceLocal2 = InetAddress.getByName("ff11::5.6.7.8");
       
   176 
       
   177         InetAddress linkLocal1 = InetAddress.getByName("ff12::4.5.6.7");
       
   178         InetAddress linkLocal2 = InetAddress.getByName("ff12::7.8.9.10");
       
   179 
       
   180         for (NetworkInterface nif : nifs) {
       
   181             test(nif, interfaceLocal1, interfaceLocal2);
       
   182             test(nif, linkLocal1, linkLocal2);
       
   183         }
       
   184     }
       
   185 }