test/jdk/java/nio/channels/DatagramChannel/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 PromiscuousIPv6
       
    32  * @key randomness
       
    33  */
       
    34 
       
    35 import java.nio.ByteBuffer;
       
    36 import java.nio.channels.*;
       
    37 import java.net.*;
       
    38 import java.util.*;
       
    39 import java.io.IOException;
       
    40 import jdk.test.lib.NetworkConfiguration;
       
    41 import jtreg.SkippedException;
       
    42 import static java.net.StandardProtocolFamily.*;
       
    43 import static java.nio.charset.StandardCharsets.UTF_8;
       
    44 import static java.util.stream.Collectors.toList;
       
    45 
       
    46 /*
       
    47  * This test was created as a copy of the Promiscuous test and adapted for
       
    48  * IPv6 node-local and link-local multicast addresses on Linux.
       
    49  */
       
    50 public class PromiscuousIPv6 {
       
    51 
       
    52     static final Random rand = new Random();
       
    53 
       
    54     static final ProtocolFamily UNSPEC = () -> "UNSPEC";
       
    55 
       
    56     /**
       
    57      * Sends a datagram to the given multicast group
       
    58      */
       
    59     static int sendDatagram(NetworkInterface nif,
       
    60                             InetAddress group,
       
    61                             int port)
       
    62             throws IOException
       
    63     {
       
    64         ProtocolFamily family = (group instanceof Inet6Address) ? INET6 : INET;
       
    65         DatagramChannel dc = DatagramChannel.open(family)
       
    66                 .setOption(StandardSocketOptions.IP_MULTICAST_IF, nif);
       
    67         int id = rand.nextInt();
       
    68         byte[] msg = Integer.toString(id).getBytes(UTF_8);
       
    69         ByteBuffer buf = ByteBuffer.wrap(msg);
       
    70         System.out.format("Send message -> group %s (id=0x%x)\n",
       
    71                           group.getHostAddress(), id);
       
    72         dc.send(buf, new InetSocketAddress(group, port));
       
    73         dc.close();
       
    74         return id;
       
    75     }
       
    76 
       
    77     /**
       
    78      * Waits (with timeout) for datagram. The {@code datagramExpected}
       
    79      * parameter indicates whether a datagram is expected, and if
       
    80      * {@code true} then {@code id} is the identifier in the payload.
       
    81      */
       
    82     static void receiveDatagram(DatagramChannel dc,
       
    83                                 String name,
       
    84                                 boolean datagramExpected,
       
    85                                 int id)
       
    86         throws IOException
       
    87     {
       
    88         System.out.println("Checking if received by " + name);
       
    89 
       
    90         Selector sel = Selector.open();
       
    91         dc.configureBlocking(false);
       
    92         dc.register(sel, SelectionKey.OP_READ);
       
    93         ByteBuffer buf = ByteBuffer.allocateDirect(100);
       
    94 
       
    95         try {
       
    96             for (;;) {
       
    97                 System.out.println("Waiting to receive message");
       
    98                 sel.select(5*1000);
       
    99                 SocketAddress sa = dc.receive(buf);
       
   100 
       
   101                 // no datagram received
       
   102                 if (sa == null) {
       
   103                     if (datagramExpected) {
       
   104                         throw new RuntimeException("Expected message not received");
       
   105                     }
       
   106                     System.out.println("No message received (correct)");
       
   107                     return;
       
   108                 }
       
   109 
       
   110                 // datagram received
       
   111 
       
   112                 InetAddress sender = ((InetSocketAddress)sa).getAddress();
       
   113                 buf.flip();
       
   114                 byte[] bytes = new byte[buf.remaining()];
       
   115                 buf.get(bytes);
       
   116                 String s = new String(bytes, "UTF-8");
       
   117                 int receivedId = -1;
       
   118                 try {
       
   119                     receivedId = Integer.parseInt(s);
       
   120                     System.out.format("Received message from %s (id=0x%x)\n",
       
   121                                       sender, receivedId);
       
   122                 } catch (NumberFormatException x) {
       
   123                     System.out.format("Received message from %s (msg=%s)\n", sender, s);
       
   124                 }
       
   125 
       
   126                 if (!datagramExpected) {
       
   127                     if (receivedId == id)
       
   128                         throw new RuntimeException("Message not expected");
       
   129                     System.out.println("Message ignored (has wrong id)");
       
   130                 } else {
       
   131                     if (receivedId == id) {
       
   132                         System.out.println("Message expected");
       
   133                         return;
       
   134                     }
       
   135                     System.out.println("Message ignored (wrong sender)");
       
   136                 }
       
   137 
       
   138                 sel.selectedKeys().clear();
       
   139                 buf.rewind();
       
   140             }
       
   141         } finally {
       
   142             sel.close();
       
   143         }
       
   144     }
       
   145 
       
   146     static void test(ProtocolFamily family,
       
   147                      NetworkInterface nif,
       
   148                      InetAddress group1,
       
   149                      InetAddress group2)
       
   150             throws IOException
       
   151     {
       
   152 
       
   153         System.out.format("%nTest family=%s%n", family.name());
       
   154 
       
   155         // Bind addresses should include the same network interface / scope, so
       
   156         // as to not reply on the default route when there are multiple interfaces
       
   157         InetAddress bindAddr1 = Inet6Address.getByAddress(null, group1.getAddress(), nif);
       
   158         InetAddress bindAddr2 = Inet6Address.getByAddress(null, group2.getAddress(), nif);
       
   159 
       
   160         DatagramChannel dc1 = (family == UNSPEC) ?
       
   161                 DatagramChannel.open() : DatagramChannel.open(family);
       
   162         DatagramChannel dc2 = (family == UNSPEC) ?
       
   163                 DatagramChannel.open() : DatagramChannel.open(family);
       
   164 
       
   165         try {
       
   166             dc1.setOption(StandardSocketOptions.SO_REUSEADDR, true);
       
   167             dc2.setOption(StandardSocketOptions.SO_REUSEADDR, true);
       
   168 
       
   169             dc1.bind(new InetSocketAddress(bindAddr1, 0));
       
   170             int port = dc1.socket().getLocalPort();
       
   171             dc2.bind(new InetSocketAddress(bindAddr2, port));
       
   172 
       
   173             System.out.format("dc1 joining [%s]:%d @ %s\n",
       
   174                               group1.getHostAddress(), port, nif.getName());
       
   175             System.out.format("dc2 joining [%s]:%d @ %s\n",
       
   176                               group2.getHostAddress(), port, nif.getName());
       
   177 
       
   178             dc1.join(group1, nif);
       
   179             dc2.join(group2, nif);
       
   180 
       
   181             int id = sendDatagram(nif, group1, port);
       
   182 
       
   183             receiveDatagram(dc1, "dc1", true, id);
       
   184             receiveDatagram(dc2, "dc2", false, id);
       
   185 
       
   186             id = sendDatagram(nif, group2, port);
       
   187 
       
   188             receiveDatagram(dc1, "dc1", false, id);
       
   189             receiveDatagram(dc2, "dc2", true, id);
       
   190 
       
   191         } finally {
       
   192             dc1.close();
       
   193             dc2.close();
       
   194         }
       
   195     }
       
   196 
       
   197     public static void main(String[] args) throws IOException {
       
   198 
       
   199         String os = System.getProperty("os.name");
       
   200 
       
   201         if (!os.equals("Linux")) {
       
   202             throw new SkippedException("This test should be run only on Linux");
       
   203         } else {
       
   204             String osVersion = System.getProperty("os.version");
       
   205             String prefix = "3.10.0";
       
   206             if (osVersion.startsWith(prefix)) {
       
   207                 throw new SkippedException(
       
   208                         String.format("The behavior under test is known NOT to work on '%s' kernels", prefix));
       
   209             }
       
   210         }
       
   211 
       
   212         NetworkConfiguration.printSystemConfiguration(System.out);
       
   213         List<NetworkInterface> nifs = NetworkConfiguration.probe()
       
   214                 .ip6MulticastInterfaces()
       
   215                 .collect(toList());
       
   216 
       
   217         if (nifs.size() == 0) {
       
   218             throw new SkippedException(
       
   219                     "No IPv6 interfaces that support multicast found");
       
   220         }
       
   221 
       
   222         InetAddress interfaceLocal1 = InetAddress.getByName("ff11::2.3.4.5");
       
   223         InetAddress interfaceLocal2 = InetAddress.getByName("ff11::6.7.8.9");
       
   224 
       
   225         InetAddress linkLocal1 = InetAddress.getByName("ff12::2.3.4.5");
       
   226         InetAddress linkLocal2 = InetAddress.getByName("ff12::6.7.8.9");
       
   227 
       
   228         for (NetworkInterface nif : nifs) {
       
   229             test(INET6, nif, interfaceLocal1, interfaceLocal2);
       
   230             test(INET6, nif, linkLocal1, linkLocal2);
       
   231         }
       
   232     }
       
   233 }