1/* 2 * Copyright (c) 2009, 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/* @test 25 * @bug 4927640 26 * @summary Tests the SCTP protocol implementation 27 * @author chegar 28 */ 29 30import java.net.*; 31import java.io.*; 32import java.util.List; 33import java.util.Set; 34import java.util.Iterator; 35import java.nio.ByteBuffer; 36import java.nio.channels.AlreadyBoundException; 37import java.nio.channels.AlreadyConnectedException; 38import java.nio.channels.ClosedChannelException; 39import java.nio.channels.UnsupportedAddressTypeException; 40import com.sun.nio.sctp.AssociationChangeNotification; 41import com.sun.nio.sctp.AbstractNotificationHandler; 42import com.sun.nio.sctp.HandlerResult; 43import com.sun.nio.sctp.IllegalUnbindException; 44import com.sun.nio.sctp.MessageInfo; 45import com.sun.nio.sctp.PeerAddressChangeNotification; 46import com.sun.nio.sctp.SctpChannel; 47import com.sun.nio.sctp.SctpServerChannel; 48import com.sun.nio.sctp.ShutdownNotification; 49import static java.lang.System.out; 50 51/** 52 * Tests bind, bindAddress, unbindAddress, getLocalAddress, and 53 * getAllLocalAddresses. 54 */ 55public 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} 351