524N/A/*
3909N/A * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
524N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
524N/A *
524N/A * This code is free software; you can redistribute it and/or modify it
524N/A * under the terms of the GNU General Public License version 2 only, as
524N/A * published by the Free Software Foundation.
524N/A *
524N/A * This code is distributed in the hope that it will be useful, but WITHOUT
524N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
524N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
524N/A * version 2 for more details (a copy is included in the LICENSE file that
524N/A * accompanied this code).
524N/A *
524N/A * You should have received a copy of the GNU General Public License version
524N/A * 2 along with this work; if not, write to the Free Software Foundation,
524N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
524N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
524N/A */
524N/A
524N/A/* @test
5317N/A * @bug 4527345 7026376 6633549
524N/A * @summary Unit test for DatagramChannel's multicast support
524N/A * @build MulticastSendReceiveTests NetworkConfiguration
1477N/A * @run main MulticastSendReceiveTests
5317N/A * @run main/othervm -Djava.net.preferIPv4Stack=true MulticastSendReceiveTests
524N/A */
524N/A
524N/Aimport java.nio.ByteBuffer;
524N/Aimport java.nio.channels.*;
524N/Aimport java.net.*;
3759N/Aimport static java.net.StandardProtocolFamily.*;
524N/Aimport java.util.*;
524N/Aimport java.io.IOException;
524N/A
524N/Apublic class MulticastSendReceiveTests {
524N/A
3759N/A static final Random rand = new Random();
3759N/A
3759N/A static final ProtocolFamily UNSPEC = new ProtocolFamily() {
3759N/A public String name() {
3759N/A return "UNSPEC";
3759N/A }
3759N/A };
524N/A
524N/A /**
524N/A * Send datagram from given local address to given multicast
524N/A * group.
524N/A */
524N/A static int sendDatagram(InetAddress local,
524N/A NetworkInterface nif,
524N/A InetAddress group,
524N/A int port)
524N/A throws IOException
524N/A {
524N/A ProtocolFamily family = (group instanceof Inet6Address) ?
524N/A StandardProtocolFamily.INET6 : StandardProtocolFamily.INET;
524N/A DatagramChannel dc = DatagramChannel.open(family)
524N/A .bind(new InetSocketAddress(local, 0))
4216N/A .setOption(StandardSocketOptions.IP_MULTICAST_IF, nif);
524N/A int id = rand.nextInt();
524N/A byte[] msg = Integer.toString(id).getBytes("UTF-8");
524N/A ByteBuffer buf = ByteBuffer.wrap(msg);
524N/A System.out.format("Send message from %s -> group %s (id=0x%x)\n",
524N/A local.getHostAddress(), group.getHostAddress(), id);
524N/A dc.send(buf, new InetSocketAddress(group, port));
524N/A dc.close();
524N/A return id;
524N/A }
524N/A
524N/A /**
524N/A * Wait (with timeout) for datagram.
524N/A *
524N/A * @param expectedSender - expected sender address, or
524N/A * null if no datagram expected
524N/A * @param id - expected id of datagram
524N/A */
524N/A static void receiveDatagram(DatagramChannel dc,
524N/A InetAddress expectedSender,
524N/A int id)
524N/A throws IOException
524N/A {
524N/A Selector sel = Selector.open();
524N/A dc.configureBlocking(false);
524N/A dc.register(sel, SelectionKey.OP_READ);
524N/A ByteBuffer buf = ByteBuffer.allocateDirect(100);
524N/A
524N/A try {
524N/A for (;;) {
524N/A System.out.println("Waiting to receive message");
524N/A sel.select(5*1000);
524N/A SocketAddress sa = dc.receive(buf);
524N/A
524N/A // no datagram received
524N/A if (sa == null) {
524N/A if (expectedSender != null) {
524N/A throw new RuntimeException("Expected message not recieved");
524N/A }
524N/A System.out.println("No message received (correct)");
524N/A return;
524N/A }
524N/A
524N/A // datagram received
524N/A
524N/A InetAddress sender = ((InetSocketAddress)sa).getAddress();
524N/A buf.flip();
524N/A byte[] bytes = new byte[buf.remaining()];
524N/A buf.get(bytes);
524N/A int receivedId = Integer.parseInt(new String(bytes));
524N/A
524N/A System.out.format("Received message from %s (id=0x%x)\n",
524N/A sender, receivedId);
524N/A
524N/A if (expectedSender == null) {
524N/A if (receivedId == id)
524N/A throw new RuntimeException("Message not expected");
524N/A System.out.println("Message ignored (has wrong id)");
524N/A } else {
524N/A if (sender.equals(expectedSender)) {
524N/A System.out.println("Message expected");
524N/A return;
524N/A }
524N/A System.out.println("Message ignored (wrong sender)");
524N/A }
524N/A
524N/A sel.selectedKeys().clear();
524N/A buf.rewind();
524N/A }
524N/A } finally {
524N/A sel.close();
524N/A }
524N/A }
524N/A
524N/A
524N/A /**
524N/A * Exercise multicast send/receive on given group/interface
524N/A */
3759N/A static void test(ProtocolFamily family,
3759N/A NetworkInterface nif,
3759N/A InetAddress group,
3759N/A InetAddress source)
524N/A throws IOException
524N/A {
3759N/A System.out.format("\nTest DatagramChannel to %s socket\n", family.name());
3759N/A try (DatagramChannel dc = (family == UNSPEC) ?
3759N/A DatagramChannel.open() : DatagramChannel.open(family)) {
4216N/A dc.setOption(StandardSocketOptions.SO_REUSEADDR, true)
3759N/A .bind(new InetSocketAddress(0));
524N/A
3759N/A // join group
3759N/A System.out.format("join %s @ %s\n", group.getHostAddress(),
3759N/A nif.getName());
3759N/A MembershipKey key;
3759N/A try {
3759N/A key = dc.join(group, nif);
3759N/A } catch (IllegalArgumentException iae) {
3759N/A if (family == UNSPEC) {
3759N/A System.out.println("Not supported");
3759N/A return;
3759N/A }
3759N/A throw iae;
3759N/A }
524N/A
3759N/A // send message to group
3759N/A int port = ((InetSocketAddress)dc.getLocalAddress()).getPort();
3759N/A int id = sendDatagram(source, nif, group, port);
524N/A
3759N/A // receive message and check id matches
3759N/A receiveDatagram(dc, source, id);
3759N/A
3759N/A // exclude-mode filtering
3759N/A
3759N/A try {
3759N/A System.out.format("block %s\n", source.getHostAddress());
524N/A
3759N/A // may throw UOE
3759N/A key.block(source);
3759N/A id = sendDatagram(source, nif, group, port);
3759N/A receiveDatagram(dc, null, id);
524N/A
3759N/A // unblock source, send message, message should be received
3759N/A System.out.format("unblock %s\n", source.getHostAddress());
3759N/A key.unblock(source);
3759N/A id = sendDatagram(source, nif, group, port);
3759N/A receiveDatagram(dc, source, id);
3759N/A } catch (UnsupportedOperationException x) {
5317N/A String os = System.getProperty("os.name");
5317N/A // Exclude-mode filtering supported on these platforms so UOE should never be thrown
5317N/A if (os.equals("SunOS") || os.equals("Linux"))
5317N/A throw x;
3759N/A System.out.println("Exclude-mode filtering not supported!");
3759N/A }
524N/A
3759N/A key.drop();
3759N/A
3759N/A // include-mode filtering
524N/A
3759N/A InetAddress bogus = (group instanceof Inet6Address) ?
3759N/A InetAddress.getByName("fe80::1234") :
3759N/A InetAddress.getByName("1.2.3.4");
3759N/A System.out.format("join %s @ %s only-source %s\n", group.getHostAddress(),
3759N/A nif.getName(), bogus.getHostAddress());
3759N/A try {
3759N/A // may throw UOE
3759N/A key = dc.join(group, nif, bogus);
524N/A
3759N/A id = sendDatagram(source, nif, group, port);
3759N/A receiveDatagram(dc, null, id);
3759N/A
3759N/A System.out.format("join %s @ %s only-source %s\n", group.getHostAddress(),
3759N/A nif.getName(), source.getHostAddress());
3759N/A key = dc.join(group, nif, source);
524N/A
3759N/A id = sendDatagram(source, nif, group, port);
3759N/A receiveDatagram(dc, source, id);
3759N/A } catch (UnsupportedOperationException x) {
5317N/A String os = System.getProperty("os.name");
5317N/A // Include-mode filtering supported on these platforms so UOE should never be thrown
5317N/A if (os.equals("SunOS") || os.equals("Linux"))
5317N/A throw x;
3759N/A System.out.println("Include-mode filtering not supported!");
3759N/A }
524N/A }
524N/A }
524N/A
524N/A public static void main(String[] args) throws IOException {
524N/A NetworkConfiguration config = NetworkConfiguration.probe();
524N/A
524N/A // multicast groups used for the test
524N/A InetAddress ip4Group = InetAddress.getByName("225.4.5.6");
524N/A InetAddress ip6Group = InetAddress.getByName("ff02::a");
524N/A
524N/A for (NetworkInterface nif: config.ip4Interfaces()) {
524N/A InetAddress source = config.ip4Addresses(nif).iterator().next();
3759N/A test(INET, nif, ip4Group, source);
3759N/A test(UNSPEC, nif, ip4Group, source);
524N/A }
524N/A
524N/A for (NetworkInterface nif: config.ip6Interfaces()) {
524N/A InetAddress source = config.ip6Addresses(nif).iterator().next();
3759N/A test(INET6, nif, ip6Group, source);
3759N/A test(UNSPEC, nif, ip6Group, source);
524N/A }
524N/A }
524N/A}