/* * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ /* @test * @bug 4927640 * @summary Tests the SCTP protocol implementation * @author chegar */ import java.net.*; import java.io.*; import java.util.List; import java.util.Set; import java.util.Iterator; import java.nio.ByteBuffer; import java.nio.channels.AlreadyBoundException; import java.nio.channels.AlreadyConnectedException; import java.nio.channels.ClosedChannelException; import java.nio.channels.UnsupportedAddressTypeException; import com.sun.nio.sctp.AssociationChangeNotification; import com.sun.nio.sctp.AbstractNotificationHandler; import com.sun.nio.sctp.HandlerResult; import com.sun.nio.sctp.IllegalUnbindException; import com.sun.nio.sctp.MessageInfo; import com.sun.nio.sctp.PeerAddressChangeNotification; import com.sun.nio.sctp.SctpChannel; import com.sun.nio.sctp.SctpServerChannel; import com.sun.nio.sctp.ShutdownNotification; import static java.lang.System.out; /** * Tests bind, bindAddress, unbindAddress, getLocalAddress, and * getAllLocalAddresses. */ public class Bind { void test(String[] args) { if (!Util.isSCTPSupported()) { out.println("SCTP protocol is not supported"); out.println("Test cannot be run"); return; } /* Simply bind tests */ testBind(); /* Test unconnected */ testBindUnbind(false); /* Test connected */ /* Adding/Removing addresses from a connected association is optional. * This test can be run on systems that support dynamic address * reconfiguration */ //testBindUnbind(true); } void testBind() { SctpChannel channel = null; try { channel = SctpChannel.open(); /* TEST 1: empty set if channel is not bound */ check(channel.getAllLocalAddresses().isEmpty(), "getAllLocalAddresses returned non empty set for unbound channel"); /* TEST 2: null to bind the channel to an automatically assigned * socket address */ channel.bind(null); /* TEST 3: non empty set if the channel is bound */ check(!channel.getAllLocalAddresses().isEmpty(), "getAllLocalAddresses returned empty set for bound channel"); debug("getAllLocalAddresses on channel bound to the wildcard:\n" + channel.getAllLocalAddresses()); /* TEST 4: AlreadyBoundException if this channel is already bound */ try { channel.bind(null); } catch (AlreadyBoundException unused) { pass(); } catch (IOException ioe) { unexpected(ioe); } /* TEST 5: UnsupportedAddressTypeException */ try { channel.close(); /* open a new unbound channel for test */ channel = SctpChannel.open(); channel.bind(new UnsupportedSocketAddress()); fail("UnsupportedSocketAddress expected"); } catch (UnsupportedAddressTypeException unused) { pass(); } catch (IOException ioe) { unexpected(ioe); } /* TEST 6: AlreadyConnectedException */ try { channel.close(); /* open a new unbound channel for test */ channel = SctpChannel.open(); connectChannel(channel); channel.bind(null); fail("AlreadyConnectedException expected"); } catch (AlreadyConnectedException unused) { pass(); } catch (IOException ioe) { unexpected(ioe); } /* TEST 7: ClosedChannelException - If this channel is closed */ try { channel.close(); /* open a new unbound channel for test */ channel = SctpChannel.open(); channel.close(); channel.bind(null); fail("ClosedChannelException expected"); } catch (ClosedChannelException unused) { pass(); } catch (IOException ioe) { unexpected(ioe); } /* TEST 8: ClosedChannelException if channel is closed */ try { channel.getAllLocalAddresses(); fail("should have thrown ClosedChannelException"); } catch (ClosedChannelException cce) { pass(); } catch (Exception ioe) { unexpected(ioe); } } catch (IOException ioe) { unexpected(ioe); } finally { try { channel.close(); } catch (IOException ioe) { unexpected(ioe); } } } void testBindUnbind(boolean connected) { SctpChannel channel = null; SctpChannel peerChannel = null; debug("testBindUnbind, connected: " + connected); try { channel = SctpChannel.open(); List<InetAddress> addresses = Util.getAddresses(true, false); Iterator iterator = addresses.iterator(); InetSocketAddress a = new InetSocketAddress((InetAddress)iterator.next(), 0); debug("channel.bind( " + a + ")"); channel.bind(a); while (iterator.hasNext()) { InetAddress ia = (InetAddress)iterator.next(); debug("channel.bindAddress(" + ia + ")"); channel.bindAddress(ia); } if (debug) {Util.dumpAddresses(channel, out);} if (connected) { /* Test with connected channel */ peerChannel = connectChannel(channel); } /* TEST 1: bind/unbindAddresses on the system addresses */ debug("bind/unbindAddresses on the system addresses"); List<InetAddress> addrs = Util.getAddresses(true, false); for (InetAddress addr : addrs) { try { debug("unbindAddress: " + addr); check(boundAddress(channel, addr), "trying to remove address that is not bound"); channel.unbindAddress(addr); if (debug) {Util.dumpAddresses(channel, out);} check(!boundAddress(channel, addr), "address was not removed"); debug("bindAddress: " + addr); channel.bindAddress(addr); if (debug) {Util.dumpAddresses(channel, out);} check(boundAddress(channel, addr), "address is not bound"); } catch (IOException ioe) { unexpected(ioe); } } /* TEST 2: bindAddress - already bound address. */ InetAddress againAddress = addrs.get(0); try { debug("bind already bound address " + againAddress); channel.bindAddress(againAddress); } catch (AlreadyBoundException unused) { debug("Caught AlreadyBoundException - OK"); pass(); } catch (IOException ioe) { unexpected(ioe); } /* TEST 3: bind non local address */ try { InetAddress nla = InetAddress.getByName("123.123.123.123"); debug("bind non local address " + nla); channel.bindAddress(nla); } catch (IOException ioe) { debug("Informative only " + ioe); } /* TEST 4: unbind address that is not bound */ try { debug("unbind address that is not bound " + againAddress); /* remove address first then again */ channel.unbindAddress(againAddress); channel.unbindAddress(againAddress); } catch (IllegalUnbindException unused) { debug("Caught IllegalUnbindException - OK"); pass(); } catch (IOException ioe) { unexpected(ioe); } /* TEST 5: unbind address that is not bound */ try { InetAddress nla = InetAddress.getByName("123.123.123.123"); debug("unbind address that is not bound " + nla); channel.unbindAddress(nla); } catch (IllegalUnbindException unused) { debug("Caught IllegalUnbindException - OK"); pass(); } catch (IOException ioe) { unexpected(ioe); } if (connected) { channel.shutdown(); BindNotificationHandler handler = new BindNotificationHandler(); ByteBuffer buffer = ByteBuffer.allocate(10); MessageInfo info; while((info = peerChannel.receive(buffer, null, handler)) != null) { if (info != null) { if (info.bytes() == -1) { debug("peerChannel Reached EOF"); break; } } } while((info = channel.receive(buffer, null, handler)) != null) { if (info != null) { if (info.bytes() == -1) { debug("channel Reached EOF"); break; } } } } } catch (IOException ioe) { ioe.printStackTrace(); } finally { try { if (channel != null) channel.close(); } catch (IOException ioe) { unexpected(ioe); } } } boolean boundAddress(SctpChannel channel, InetAddress addr) throws IOException { for (SocketAddress boundAddr : channel.getAllLocalAddresses()) { if (((InetSocketAddress) boundAddr).getAddress().equals(addr)) return true; } return false; } SctpChannel connectChannel(SctpChannel channel) throws IOException { debug("connecting channel..."); try { SctpServerChannel ssc = SctpServerChannel.open(); ssc.bind(null); Set<SocketAddress> addrs = ssc.getAllLocalAddresses(); Iterator<SocketAddress> iterator = addrs.iterator(); SocketAddress addr = iterator.next(); debug("using " + addr + "..."); channel.connect(addr); SctpChannel peerChannel = ssc.accept(); ssc.close(); debug("connected"); return peerChannel; } catch (IOException ioe) { debug("Cannot connect channel"); unexpected(ioe); throw ioe; } } class BindNotificationHandler extends AbstractNotificationHandler<Object> { @Override public HandlerResult handleNotification( AssociationChangeNotification acn, Object unused) { debug("AssociationChangeNotification: " + acn); return HandlerResult.CONTINUE; } @Override public HandlerResult handleNotification( PeerAddressChangeNotification pacn, Object unused) { debug("PeerAddressChangeNotification: " + pacn); return HandlerResult.CONTINUE; } @Override public HandlerResult handleNotification( ShutdownNotification sn, Object unused) { debug("ShutdownNotification: " + sn); return HandlerResult.CONTINUE; } } class UnsupportedSocketAddress extends SocketAddress { } //--------------------- Infrastructure --------------------------- boolean debug = true; volatile int passed = 0, failed = 0; void pass() {passed++;} void fail() {failed++; Thread.dumpStack();} void fail(String msg) {System.err.println(msg); fail();} void unexpected(Throwable t) {failed++; t.printStackTrace();} void check(boolean cond) {if (cond) pass(); else fail();} void check(boolean cond, String failMessage) {if (cond) pass(); else fail(failMessage);} void debug(String message) {if(debug) { System.out.println(message); } } public static void main(String[] args) throws Throwable { Class<?> k = new Object(){}.getClass().getEnclosingClass(); try {k.getMethod("instanceMain",String[].class) .invoke( k.newInstance(), (Object) args);} catch (Throwable e) {throw e.getCause();}} public void instanceMain(String[] args) throws Throwable { try {test(args);} catch (Throwable t) {unexpected(t);} System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed); if (failed > 0) throw new AssertionError("Some tests failed");} }