MulticastSendReceiveTests.java revision 6073:cea72c2bf071
1199714Srnoland/*
2199714Srnoland * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
3199714Srnoland * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4199714Srnoland *
5199714Srnoland * This code is free software; you can redistribute it and/or modify it
6212066Sdelphij * under the terms of the GNU General Public License version 2 only, as
7199714Srnoland * published by the Free Software Foundation.
8199714Srnoland *
9276486Sngie * This code is distributed in the hope that it will be useful, but WITHOUT
10199714Srnoland * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11199714Srnoland * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12199714Srnoland * 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/* @test
25 * @bug 4527345 7026376 6633549
26 * @summary Unit test for DatagramChannel's multicast support
27 * @build MulticastSendReceiveTests NetworkConfiguration
28 * @run main MulticastSendReceiveTests
29 * @run main/othervm -Djava.net.preferIPv4Stack=true MulticastSendReceiveTests
30 */
31
32import java.nio.ByteBuffer;
33import java.nio.channels.*;
34import java.net.*;
35import static java.net.StandardProtocolFamily.*;
36import java.util.*;
37import java.io.IOException;
38
39public class MulticastSendReceiveTests {
40
41    static final Random rand = new Random();
42
43    static final ProtocolFamily UNSPEC = new ProtocolFamily() {
44        public String name() {
45            return "UNSPEC";
46        }
47    };
48
49    /**
50     * Send datagram from given local address to given multicast
51     * group.
52     */
53    static int sendDatagram(InetAddress local,
54                            NetworkInterface nif,
55                            InetAddress group,
56                            int port)
57        throws IOException
58    {
59        ProtocolFamily family = (group instanceof Inet6Address) ?
60            StandardProtocolFamily.INET6 : StandardProtocolFamily.INET;
61        DatagramChannel dc = DatagramChannel.open(family)
62            .bind(new InetSocketAddress(local, 0))
63            .setOption(StandardSocketOptions.IP_MULTICAST_IF, nif);
64        int id = rand.nextInt();
65        byte[] msg = Integer.toString(id).getBytes("UTF-8");
66        ByteBuffer buf = ByteBuffer.wrap(msg);
67        System.out.format("Send message from %s -> group %s (id=0x%x)\n",
68            local.getHostAddress(), group.getHostAddress(), id);
69        dc.send(buf, new InetSocketAddress(group, port));
70        dc.close();
71        return id;
72    }
73
74    /**
75     * Wait (with timeout) for datagram.
76     *
77     * @param   expectedSender - expected sender address, or
78     *                           null if no datagram expected
79     * @param   id - expected id of datagram
80     */
81    static void receiveDatagram(DatagramChannel dc,
82                                InetAddress expectedSender,
83                                int id)
84        throws IOException
85    {
86        Selector sel = Selector.open();
87        dc.configureBlocking(false);
88        dc.register(sel, SelectionKey.OP_READ);
89        ByteBuffer buf = ByteBuffer.allocateDirect(100);
90
91        try {
92            for (;;) {
93                System.out.println("Waiting to receive message");
94                sel.select(5*1000);
95                SocketAddress sa = dc.receive(buf);
96
97                // no datagram received
98                if (sa == null) {
99                    if (expectedSender != null) {
100                        throw new RuntimeException("Expected message not recieved");
101                    }
102                    System.out.println("No message received (correct)");
103                    return;
104                }
105
106                // datagram received
107
108                InetAddress sender = ((InetSocketAddress)sa).getAddress();
109                buf.flip();
110                byte[] bytes = new byte[buf.remaining()];
111                buf.get(bytes);
112                int receivedId = Integer.parseInt(new String(bytes));
113
114                System.out.format("Received message from %s (id=0x%x)\n",
115                    sender, receivedId);
116
117                if (expectedSender == null) {
118                    if (receivedId == id)
119                        throw new RuntimeException("Message not expected");
120                    System.out.println("Message ignored (has wrong id)");
121                } else {
122                    if (sender.equals(expectedSender)) {
123                        System.out.println("Message expected");
124                        return;
125                    }
126                    System.out.println("Message ignored (wrong sender)");
127                }
128
129                sel.selectedKeys().clear();
130                buf.rewind();
131            }
132        } finally {
133            sel.close();
134        }
135    }
136
137
138    /**
139     * Exercise multicast send/receive on given group/interface
140     */
141    static void test(ProtocolFamily family,
142                     NetworkInterface nif,
143                     InetAddress group,
144                     InetAddress source)
145        throws IOException
146    {
147        System.out.format("\nTest DatagramChannel to %s socket\n", family.name());
148        try (DatagramChannel dc = (family == UNSPEC) ?
149                DatagramChannel.open() : DatagramChannel.open(family)) {
150            dc.setOption(StandardSocketOptions.SO_REUSEADDR, true)
151              .bind(new InetSocketAddress(0));
152
153            // join group
154            System.out.format("join %s @ %s\n", group.getHostAddress(),
155                nif.getName());
156            MembershipKey key;
157            try {
158                key = dc.join(group, nif);
159            } catch (IllegalArgumentException iae) {
160                if (family == UNSPEC) {
161                    System.out.println("Not supported");
162                    return;
163                }
164                throw iae;
165            }
166
167            // send message to group
168            int port = ((InetSocketAddress)dc.getLocalAddress()).getPort();
169            int id = sendDatagram(source, nif, group, port);
170
171            // receive message and check id matches
172            receiveDatagram(dc, source, id);
173
174            // exclude-mode filtering
175
176            try {
177                System.out.format("block %s\n", source.getHostAddress());
178
179                // may throw UOE
180                key.block(source);
181                id = sendDatagram(source, nif, group, port);
182                receiveDatagram(dc, null, id);
183
184                // unblock source, send message, message should be received
185                System.out.format("unblock %s\n", source.getHostAddress());
186                key.unblock(source);
187                id = sendDatagram(source, nif, group, port);
188                receiveDatagram(dc, source, id);
189            } catch (UnsupportedOperationException x) {
190                String os = System.getProperty("os.name");
191                // Exclude-mode filtering supported on these platforms so UOE should never be thrown
192                if (os.equals("SunOS") || os.equals("Linux"))
193                    throw x;
194                System.out.println("Exclude-mode filtering not supported!");
195            }
196
197            key.drop();
198
199            // include-mode filtering
200
201            InetAddress bogus = (group instanceof Inet6Address) ?
202                InetAddress.getByName("fe80::1234") :
203                InetAddress.getByName("1.2.3.4");
204            System.out.format("join %s @ %s only-source %s\n", group.getHostAddress(),
205                nif.getName(), bogus.getHostAddress());
206            try {
207                // may throw UOE
208                key = dc.join(group, nif, bogus);
209
210                id = sendDatagram(source, nif, group, port);
211                receiveDatagram(dc, null, id);
212
213                System.out.format("join %s @ %s only-source %s\n", group.getHostAddress(),
214                    nif.getName(), source.getHostAddress());
215                key = dc.join(group, nif, source);
216
217                id = sendDatagram(source, nif, group, port);
218                receiveDatagram(dc, source, id);
219            } catch (UnsupportedOperationException x) {
220                String os = System.getProperty("os.name");
221                // Include-mode filtering supported on these platforms so UOE should never be thrown
222                if (os.equals("SunOS") || os.equals("Linux"))
223                    throw x;
224                System.out.println("Include-mode filtering not supported!");
225            }
226        }
227    }
228
229    public static void main(String[] args) throws IOException {
230        NetworkConfiguration config = NetworkConfiguration.probe();
231
232        // multicast groups used for the test
233        InetAddress ip4Group = InetAddress.getByName("225.4.5.6");
234        InetAddress ip6Group = InetAddress.getByName("ff02::a");
235
236        for (NetworkInterface nif: config.ip4Interfaces()) {
237            InetAddress source = config.ip4Addresses(nif).iterator().next();
238            test(INET,   nif, ip4Group, source);
239            test(UNSPEC, nif, ip4Group, source);
240        }
241
242        for (NetworkInterface nif: config.ip6Interfaces()) {
243            InetAddress source = config.ip6Addresses(nif).iterator().next();
244            test(INET6,  nif, ip6Group, source);
245            test(UNSPEC, nif, ip6Group, source);
246        }
247    }
248}
249