|
1 /* |
|
2 * Copyright 2007-2008 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
|
20 * CA 95054 USA or visit www.sun.com if you need additional information or |
|
21 * have any questions. |
|
22 */ |
|
23 |
|
24 /* @test |
|
25 * @bug 4527345 |
|
26 * @summary Unit test for DatagramChannel's multicast support |
|
27 * @build MulticastSendReceiveTests NetworkConfiguration |
|
28 */ |
|
29 |
|
30 import java.nio.ByteBuffer; |
|
31 import java.nio.channels.*; |
|
32 import java.net.*; |
|
33 import java.util.*; |
|
34 import java.io.IOException; |
|
35 |
|
36 public class MulticastSendReceiveTests { |
|
37 |
|
38 static Random rand = new Random(); |
|
39 |
|
40 /** |
|
41 * Send datagram from given local address to given multicast |
|
42 * group. |
|
43 */ |
|
44 static int sendDatagram(InetAddress local, |
|
45 NetworkInterface nif, |
|
46 InetAddress group, |
|
47 int port) |
|
48 throws IOException |
|
49 { |
|
50 ProtocolFamily family = (group instanceof Inet6Address) ? |
|
51 StandardProtocolFamily.INET6 : StandardProtocolFamily.INET; |
|
52 DatagramChannel dc = DatagramChannel.open(family) |
|
53 .bind(new InetSocketAddress(local, 0)) |
|
54 .setOption(StandardSocketOption.IP_MULTICAST_IF, nif); |
|
55 int id = rand.nextInt(); |
|
56 byte[] msg = Integer.toString(id).getBytes("UTF-8"); |
|
57 ByteBuffer buf = ByteBuffer.wrap(msg); |
|
58 System.out.format("Send message from %s -> group %s (id=0x%x)\n", |
|
59 local.getHostAddress(), group.getHostAddress(), id); |
|
60 dc.send(buf, new InetSocketAddress(group, port)); |
|
61 dc.close(); |
|
62 return id; |
|
63 } |
|
64 |
|
65 /** |
|
66 * Wait (with timeout) for datagram. |
|
67 * |
|
68 * @param expectedSender - expected sender address, or |
|
69 * null if no datagram expected |
|
70 * @param id - expected id of datagram |
|
71 */ |
|
72 static void receiveDatagram(DatagramChannel dc, |
|
73 InetAddress expectedSender, |
|
74 int id) |
|
75 throws IOException |
|
76 { |
|
77 Selector sel = Selector.open(); |
|
78 dc.configureBlocking(false); |
|
79 dc.register(sel, SelectionKey.OP_READ); |
|
80 ByteBuffer buf = ByteBuffer.allocateDirect(100); |
|
81 |
|
82 try { |
|
83 for (;;) { |
|
84 System.out.println("Waiting to receive message"); |
|
85 sel.select(5*1000); |
|
86 SocketAddress sa = dc.receive(buf); |
|
87 |
|
88 // no datagram received |
|
89 if (sa == null) { |
|
90 if (expectedSender != null) { |
|
91 throw new RuntimeException("Expected message not recieved"); |
|
92 } |
|
93 System.out.println("No message received (correct)"); |
|
94 return; |
|
95 } |
|
96 |
|
97 // datagram received |
|
98 |
|
99 InetAddress sender = ((InetSocketAddress)sa).getAddress(); |
|
100 buf.flip(); |
|
101 byte[] bytes = new byte[buf.remaining()]; |
|
102 buf.get(bytes); |
|
103 int receivedId = Integer.parseInt(new String(bytes)); |
|
104 |
|
105 System.out.format("Received message from %s (id=0x%x)\n", |
|
106 sender, receivedId); |
|
107 |
|
108 if (expectedSender == null) { |
|
109 if (receivedId == id) |
|
110 throw new RuntimeException("Message not expected"); |
|
111 System.out.println("Message ignored (has wrong id)"); |
|
112 } else { |
|
113 if (sender.equals(expectedSender)) { |
|
114 System.out.println("Message expected"); |
|
115 return; |
|
116 } |
|
117 System.out.println("Message ignored (wrong sender)"); |
|
118 } |
|
119 |
|
120 sel.selectedKeys().clear(); |
|
121 buf.rewind(); |
|
122 } |
|
123 } finally { |
|
124 sel.close(); |
|
125 } |
|
126 } |
|
127 |
|
128 |
|
129 /** |
|
130 * Exercise multicast send/receive on given group/interface |
|
131 */ |
|
132 static void test(NetworkInterface nif, InetAddress group, InetAddress source) |
|
133 throws IOException |
|
134 { |
|
135 ProtocolFamily family = (group instanceof Inet6Address) ? |
|
136 StandardProtocolFamily.INET6 : StandardProtocolFamily.INET; |
|
137 System.out.format("create channel to %s socket\n", family.name()); |
|
138 DatagramChannel dc = DatagramChannel.open(family) |
|
139 .setOption(StandardSocketOption.SO_REUSEADDR, true) |
|
140 .bind(new InetSocketAddress(0)); |
|
141 |
|
142 // join group |
|
143 System.out.format("join %s @ %s\n", group.getHostAddress(), |
|
144 nif.getName()); |
|
145 MembershipKey key = dc.join(group, nif); |
|
146 |
|
147 // send message to group |
|
148 int port = ((InetSocketAddress)dc.getLocalAddress()).getPort(); |
|
149 int id = sendDatagram(source, nif, group, port); |
|
150 |
|
151 // receive message and check id matches |
|
152 receiveDatagram(dc, source, id); |
|
153 |
|
154 // exclude-mode filtering |
|
155 |
|
156 try { |
|
157 System.out.format("block %s\n", source.getHostAddress()); |
|
158 |
|
159 // may throw UOE |
|
160 key.block(source); |
|
161 id = sendDatagram(source, nif, group, port); |
|
162 receiveDatagram(dc, null, id); |
|
163 |
|
164 // unblock source, send message, message should be received |
|
165 System.out.format("unblock %s\n", source.getHostAddress()); |
|
166 key.unblock(source); |
|
167 id = sendDatagram(source, nif, group, port); |
|
168 receiveDatagram(dc, source, id); |
|
169 } catch (UnsupportedOperationException x) { |
|
170 System.out.println("Exclude-mode filtering not supported!"); |
|
171 } |
|
172 |
|
173 key.drop(); |
|
174 |
|
175 // include-mode filtering |
|
176 |
|
177 InetAddress bogus = (group instanceof Inet6Address) ? |
|
178 InetAddress.getByName("fe80::1234") : |
|
179 InetAddress.getByName("1.2.3.4"); |
|
180 System.out.format("join %s @ %s only-source %s\n", group.getHostAddress(), |
|
181 nif.getName(), bogus.getHostAddress()); |
|
182 try { |
|
183 // may throw UOE |
|
184 key = dc.join(group, nif, bogus); |
|
185 |
|
186 id = sendDatagram(source, nif, group, port); |
|
187 receiveDatagram(dc, null, id); |
|
188 |
|
189 System.out.format("join %s @ %s only-source %s\n", group.getHostAddress(), |
|
190 nif.getName(), source.getHostAddress()); |
|
191 key = dc.join(group, nif, source); |
|
192 |
|
193 id = sendDatagram(source, nif, group, port); |
|
194 receiveDatagram(dc, source, id); |
|
195 } catch (UnsupportedOperationException x) { |
|
196 System.out.println("Include-mode filtering not supported!"); |
|
197 } |
|
198 |
|
199 // done |
|
200 dc.close(); |
|
201 } |
|
202 |
|
203 public static void main(String[] args) throws IOException { |
|
204 NetworkConfiguration config = NetworkConfiguration.probe(); |
|
205 |
|
206 // multicast groups used for the test |
|
207 InetAddress ip4Group = InetAddress.getByName("225.4.5.6"); |
|
208 InetAddress ip6Group = InetAddress.getByName("ff02::a"); |
|
209 |
|
210 for (NetworkInterface nif: config.ip4Interfaces()) { |
|
211 InetAddress source = config.ip4Addresses(nif).iterator().next(); |
|
212 test(nif, ip4Group, source); |
|
213 } |
|
214 |
|
215 for (NetworkInterface nif: config.ip6Interfaces()) { |
|
216 InetAddress source = config.ip6Addresses(nif).iterator().next(); |
|
217 test(nif, ip6Group, source); |
|
218 } |
|
219 } |
|
220 } |