|
1 /* |
|
2 * Copyright 2009 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 4927640 |
|
26 * @summary Tests the SCTP protocol implementation |
|
27 * @author chegar |
|
28 */ |
|
29 |
|
30 import java.net.*; |
|
31 import java.io.*; |
|
32 import java.util.List; |
|
33 import java.util.Set; |
|
34 import java.util.Iterator; |
|
35 import java.nio.ByteBuffer; |
|
36 import java.nio.channels.AlreadyBoundException; |
|
37 import java.nio.channels.AlreadyConnectedException; |
|
38 import java.nio.channels.ClosedChannelException; |
|
39 import java.nio.channels.UnsupportedAddressTypeException; |
|
40 import com.sun.nio.sctp.AssociationChangeNotification; |
|
41 import com.sun.nio.sctp.AbstractNotificationHandler; |
|
42 import com.sun.nio.sctp.HandlerResult; |
|
43 import com.sun.nio.sctp.IllegalUnbindException; |
|
44 import com.sun.nio.sctp.MessageInfo; |
|
45 import com.sun.nio.sctp.PeerAddressChangeNotification; |
|
46 import com.sun.nio.sctp.SctpChannel; |
|
47 import com.sun.nio.sctp.SctpServerChannel; |
|
48 import com.sun.nio.sctp.ShutdownNotification; |
|
49 import static java.lang.System.out; |
|
50 |
|
51 /** |
|
52 * Tests bind, bindAddress, unbindAddress, getLocalAddress, and |
|
53 * getAllLocalAddresses. |
|
54 */ |
|
55 public class Bind { |
|
56 void test(String[] args) { |
|
57 if (!Util.isSCTPSupported()) { |
|
58 out.println("SCTP protocol is not supported"); |
|
59 out.println("Test cannot be run"); |
|
60 return; |
|
61 } |
|
62 |
|
63 /* Simply bind tests */ |
|
64 testBind(); |
|
65 |
|
66 /* Test unconnected */ |
|
67 testBindUnbind(false); |
|
68 |
|
69 /* Test connected */ |
|
70 /* Adding/Removing addresses from a connected association is optional. |
|
71 * This test can be run on systems that support dynamic address |
|
72 * reconfiguration */ |
|
73 //testBindUnbind(true); |
|
74 } |
|
75 |
|
76 void testBind() { |
|
77 SctpChannel channel = null; |
|
78 try { |
|
79 channel = SctpChannel.open(); |
|
80 |
|
81 /* TEST 1: empty set if channel is not bound */ |
|
82 check(channel.getAllLocalAddresses().isEmpty(), |
|
83 "getAllLocalAddresses returned non empty set for unbound channel"); |
|
84 |
|
85 /* TEST 2: null to bind the channel to an automatically assigned |
|
86 * socket address */ |
|
87 channel.bind(null); |
|
88 |
|
89 /* TEST 3: non empty set if the channel is bound */ |
|
90 check(!channel.getAllLocalAddresses().isEmpty(), |
|
91 "getAllLocalAddresses returned empty set for bound channel"); |
|
92 debug("getAllLocalAddresses on channel bound to the wildcard:\n" |
|
93 + channel.getAllLocalAddresses()); |
|
94 |
|
95 /* TEST 4: AlreadyBoundException if this channel is already bound */ |
|
96 try { channel.bind(null); } |
|
97 catch (AlreadyBoundException unused) { pass(); } |
|
98 catch (IOException ioe) { unexpected(ioe); } |
|
99 |
|
100 /* TEST 5: UnsupportedAddressTypeException */ |
|
101 try { |
|
102 channel.close(); /* open a new unbound channel for test */ |
|
103 channel = SctpChannel.open(); |
|
104 channel.bind(new UnsupportedSocketAddress()); |
|
105 fail("UnsupportedSocketAddress expected"); |
|
106 } catch (UnsupportedAddressTypeException unused) { pass(); |
|
107 } catch (IOException ioe) { unexpected(ioe); } |
|
108 |
|
109 /* TEST 6: AlreadyConnectedException */ |
|
110 try { |
|
111 channel.close(); /* open a new unbound channel for test */ |
|
112 channel = SctpChannel.open(); |
|
113 connectChannel(channel); |
|
114 channel.bind(null); |
|
115 fail("AlreadyConnectedException expected"); |
|
116 } catch (AlreadyConnectedException unused) { pass(); |
|
117 } catch (IOException ioe) { unexpected(ioe); } |
|
118 |
|
119 /* TEST 7: ClosedChannelException - If this channel is closed */ |
|
120 try { |
|
121 channel.close(); /* open a new unbound channel for test */ |
|
122 channel = SctpChannel.open(); |
|
123 channel.close(); |
|
124 channel.bind(null); |
|
125 fail("ClosedChannelException expected"); |
|
126 } catch (ClosedChannelException unused) { pass(); |
|
127 } catch (IOException ioe) { unexpected(ioe); } |
|
128 |
|
129 /* TEST 8: ClosedChannelException if channel is closed */ |
|
130 try { |
|
131 channel.getAllLocalAddresses(); |
|
132 fail("should have thrown ClosedChannelException"); |
|
133 } catch (ClosedChannelException cce) { |
|
134 pass(); |
|
135 } catch (Exception ioe) { |
|
136 unexpected(ioe); |
|
137 } |
|
138 } catch (IOException ioe) { |
|
139 unexpected(ioe); |
|
140 } finally { |
|
141 try { channel.close(); } |
|
142 catch (IOException ioe) { unexpected(ioe); } |
|
143 } |
|
144 } |
|
145 |
|
146 void testBindUnbind(boolean connected) { |
|
147 SctpChannel channel = null; |
|
148 SctpChannel peerChannel = null; |
|
149 |
|
150 debug("testBindUnbind, connected: " + connected); |
|
151 try { |
|
152 channel = SctpChannel.open(); |
|
153 |
|
154 List<InetAddress> addresses = Util.getAddresses(true, false); |
|
155 Iterator iterator = addresses.iterator(); |
|
156 InetSocketAddress a = new InetSocketAddress((InetAddress)iterator.next(), 0); |
|
157 debug("channel.bind( " + a + ")"); |
|
158 channel.bind(a); |
|
159 while (iterator.hasNext()) { |
|
160 InetAddress ia = (InetAddress)iterator.next(); |
|
161 debug("channel.bindAddress(" + ia + ")"); |
|
162 channel.bindAddress(ia); |
|
163 } |
|
164 if (debug) {Util.dumpAddresses(channel, out);} |
|
165 |
|
166 if (connected) { |
|
167 /* Test with connected channel */ |
|
168 peerChannel = connectChannel(channel); |
|
169 } |
|
170 |
|
171 /* TEST 1: bind/unbindAddresses on the system addresses */ |
|
172 debug("bind/unbindAddresses on the system addresses"); |
|
173 List<InetAddress> addrs = Util.getAddresses(true, false); |
|
174 for (InetAddress addr : addrs) { |
|
175 try { |
|
176 debug("unbindAddress: " + addr); |
|
177 check(boundAddress(channel, addr), "trying to remove address that is not bound"); |
|
178 channel.unbindAddress(addr); |
|
179 if (debug) {Util.dumpAddresses(channel, out);} |
|
180 check(!boundAddress(channel, addr), "address was not removed"); |
|
181 |
|
182 debug("bindAddress: " + addr); |
|
183 channel.bindAddress(addr); |
|
184 if (debug) {Util.dumpAddresses(channel, out);} |
|
185 check(boundAddress(channel, addr), "address is not bound"); |
|
186 } catch (IOException ioe) { |
|
187 unexpected(ioe); |
|
188 } |
|
189 } |
|
190 |
|
191 /* TEST 2: bindAddress - already bound address. */ |
|
192 InetAddress againAddress = addrs.get(0); |
|
193 try { |
|
194 debug("bind already bound address " + againAddress); |
|
195 channel.bindAddress(againAddress); |
|
196 } catch (AlreadyBoundException unused) { |
|
197 debug("Caught AlreadyBoundException - OK"); |
|
198 pass(); |
|
199 } catch (IOException ioe) { |
|
200 unexpected(ioe); |
|
201 } |
|
202 |
|
203 /* TEST 3: bind non local address */ |
|
204 try { |
|
205 InetAddress nla = InetAddress.getByName("123.123.123.123"); |
|
206 debug("bind non local address " + nla); |
|
207 channel.bindAddress(nla); |
|
208 } catch (IOException ioe) { |
|
209 debug("Informative only " + ioe); |
|
210 } |
|
211 |
|
212 /* TEST 4: unbind address that is not bound */ |
|
213 try { |
|
214 debug("unbind address that is not bound " + againAddress); |
|
215 /* remove address first then again */ |
|
216 channel.unbindAddress(againAddress); |
|
217 channel.unbindAddress(againAddress); |
|
218 } catch (IllegalUnbindException unused) { |
|
219 debug("Caught IllegalUnbindException - OK"); |
|
220 pass(); |
|
221 } catch (IOException ioe) { |
|
222 unexpected(ioe); |
|
223 } |
|
224 |
|
225 /* TEST 5: unbind address that is not bound */ |
|
226 try { |
|
227 InetAddress nla = InetAddress.getByName("123.123.123.123"); |
|
228 debug("unbind address that is not bound " + nla); |
|
229 channel.unbindAddress(nla); |
|
230 |
|
231 } catch (IllegalUnbindException unused) { |
|
232 debug("Caught IllegalUnbindException - OK"); |
|
233 pass(); |
|
234 } catch (IOException ioe) { |
|
235 unexpected(ioe); |
|
236 } |
|
237 |
|
238 if (connected) { |
|
239 channel.shutdown(); |
|
240 |
|
241 BindNotificationHandler handler = new BindNotificationHandler(); |
|
242 ByteBuffer buffer = ByteBuffer.allocate(10); |
|
243 MessageInfo info; |
|
244 while((info = peerChannel.receive(buffer, null, handler)) != null) { |
|
245 if (info != null) { |
|
246 if (info.bytes() == -1) { |
|
247 debug("peerChannel Reached EOF"); |
|
248 break; |
|
249 } |
|
250 } |
|
251 } |
|
252 |
|
253 while((info = channel.receive(buffer, null, handler)) != null) { |
|
254 if (info != null) { |
|
255 if (info.bytes() == -1) { |
|
256 debug("channel Reached EOF"); |
|
257 break; |
|
258 } |
|
259 } |
|
260 } |
|
261 } |
|
262 } catch (IOException ioe) { |
|
263 ioe.printStackTrace(); |
|
264 } finally { |
|
265 try { if (channel != null) channel.close(); } |
|
266 catch (IOException ioe) { unexpected(ioe); } |
|
267 } |
|
268 } |
|
269 |
|
270 boolean boundAddress(SctpChannel channel, InetAddress addr) |
|
271 throws IOException { |
|
272 for (SocketAddress boundAddr : channel.getAllLocalAddresses()) { |
|
273 if (((InetSocketAddress) boundAddr).getAddress().equals(addr)) |
|
274 return true; |
|
275 } |
|
276 return false; |
|
277 } |
|
278 |
|
279 SctpChannel connectChannel(SctpChannel channel) |
|
280 throws IOException { |
|
281 debug("connecting channel..."); |
|
282 try { |
|
283 SctpServerChannel ssc = SctpServerChannel.open(); |
|
284 ssc.bind(null); |
|
285 Set<SocketAddress> addrs = ssc.getAllLocalAddresses(); |
|
286 Iterator<SocketAddress> iterator = addrs.iterator(); |
|
287 SocketAddress addr = iterator.next(); |
|
288 debug("using " + addr + "..."); |
|
289 channel.connect(addr); |
|
290 SctpChannel peerChannel = ssc.accept(); |
|
291 ssc.close(); |
|
292 debug("connected"); |
|
293 return peerChannel; |
|
294 } catch (IOException ioe) { |
|
295 debug("Cannot connect channel"); |
|
296 unexpected(ioe); |
|
297 throw ioe; |
|
298 } |
|
299 } |
|
300 |
|
301 class BindNotificationHandler extends AbstractNotificationHandler<Object> |
|
302 { |
|
303 @Override |
|
304 public HandlerResult handleNotification( |
|
305 AssociationChangeNotification acn, Object unused) |
|
306 { |
|
307 debug("AssociationChangeNotification: " + acn); |
|
308 return HandlerResult.CONTINUE; |
|
309 } |
|
310 |
|
311 @Override |
|
312 public HandlerResult handleNotification( |
|
313 PeerAddressChangeNotification pacn, Object unused) |
|
314 { |
|
315 debug("PeerAddressChangeNotification: " + pacn); |
|
316 return HandlerResult.CONTINUE; |
|
317 } |
|
318 |
|
319 @Override |
|
320 public HandlerResult handleNotification( |
|
321 ShutdownNotification sn, Object unused) |
|
322 { |
|
323 debug("ShutdownNotification: " + sn); |
|
324 return HandlerResult.CONTINUE; |
|
325 } |
|
326 } |
|
327 |
|
328 class UnsupportedSocketAddress extends SocketAddress { } |
|
329 |
|
330 //--------------------- Infrastructure --------------------------- |
|
331 boolean debug = true; |
|
332 volatile int passed = 0, failed = 0; |
|
333 void pass() {passed++;} |
|
334 void fail() {failed++; Thread.dumpStack();} |
|
335 void fail(String msg) {System.err.println(msg); fail();} |
|
336 void unexpected(Throwable t) {failed++; t.printStackTrace();} |
|
337 void check(boolean cond) {if (cond) pass(); else fail();} |
|
338 void check(boolean cond, String failMessage) {if (cond) pass(); else fail(failMessage);} |
|
339 void debug(String message) {if(debug) { System.out.println(message); } } |
|
340 public static void main(String[] args) throws Throwable { |
|
341 Class<?> k = new Object(){}.getClass().getEnclosingClass(); |
|
342 try {k.getMethod("instanceMain",String[].class) |
|
343 .invoke( k.newInstance(), (Object) args);} |
|
344 catch (Throwable e) {throw e.getCause();}} |
|
345 public void instanceMain(String[] args) throws Throwable { |
|
346 try {test(args);} catch (Throwable t) {unexpected(t);} |
|
347 System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed); |
|
348 if (failed > 0) throw new AssertionError("Some tests failed");} |
|
349 |
|
350 } |