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 30 import java.net.InetSocketAddress; 31 import java.net.SocketAddress; 32 import java.io.IOException; 33 import java.util.concurrent.CountDownLatch; 34 import java.nio.ByteBuffer; 35 import java.nio.channels.ClosedChannelException; 36 import java.nio.channels.NotYetConnectedException; 37 import com.sun.nio.sctp.AbstractNotificationHandler; 38 import com.sun.nio.sctp.HandlerResult; 39 import com.sun.nio.sctp.MessageInfo; 40 import com.sun.nio.sctp.SctpChannel; 41 import com.sun.nio.sctp.SctpServerChannel; 42 import com.sun.nio.sctp.ShutdownNotification; 43 import static java.lang.System.out; 44 import static java.lang.System.err; 45 46 public class Shutdown { 47 static CountDownLatch finishedLatch = new CountDownLatch(1); 48 static CountDownLatch sentLatch = new CountDownLatch(1); 49 test(String[] args)50 void test(String[] args) { 51 SocketAddress address = null; 52 ShutdownServer server = null; 53 54 if (!Util.isSCTPSupported()) { 55 out.println("SCTP protocol is not supported"); 56 out.println("Test cannot be run"); 57 return; 58 } 59 60 if (args.length == 2) { 61 /* requested to connecct to a specific address */ 62 try { 63 int port = Integer.valueOf(args[1]); 64 address = new InetSocketAddress(args[0], port); 65 } catch (NumberFormatException nfe) { 66 err.println(nfe); 67 } 68 } else { 69 /* start server on local machine, default */ 70 try { 71 server = new ShutdownServer(); 72 server.start(); 73 address = server.address(); 74 debug("Server started and listening on " + address); 75 } catch (IOException ioe) { 76 ioe.printStackTrace(); 77 return; 78 } 79 } 80 81 doTest(address); 82 } 83 doTest(SocketAddress peerAddress)84 void doTest(SocketAddress peerAddress) { 85 SctpChannel channel = null; 86 ByteBuffer buffer = ByteBuffer.allocate(Util.SMALL_BUFFER); 87 MessageInfo info; 88 89 try { 90 channel = SctpChannel.open(); 91 92 /* TEST 1: Verify NotYetConnectedException thrown */ 93 debug("Test 1: NotYetConnectedException"); 94 try { 95 channel.shutdown(); 96 fail("shutdown not throwing expected NotYetConnectedException"); 97 } catch (NotYetConnectedException unused) { 98 pass(); 99 } catch (IOException ioe) { 100 unexpected(ioe); 101 } 102 103 channel.connect(peerAddress); 104 sentLatch.await(); 105 channel.shutdown(); 106 107 /* TEST 2: receive data sent before shutdown */ 108 do { 109 debug("Test 2: invoking receive"); 110 info = channel.receive(buffer, null, null); 111 if (info == null) { 112 fail("unexpected null from receive"); 113 return; 114 } 115 } while (!info.isComplete()); 116 117 buffer.flip(); 118 check(info != null, "info is null"); 119 check(info.bytes() == Util.SMALL_MESSAGE.getBytes("ISO-8859-1"). 120 length, "bytes received not equal to message length"); 121 check(info.bytes() == buffer.remaining(), "bytes != remaining"); 122 check(Util.compare(buffer, Util.SMALL_MESSAGE), 123 "received message not the same as sent message"); 124 125 buffer.clear(); 126 127 /* TEST 3: receive notifications on the SCTP stack */ 128 debug("Test 3: receive notifications"); 129 while ((info = channel.receive(buffer, null, null )) != null && 130 info.bytes() != -1 ); 131 132 133 /* TEST 4: If the channel is already shutdown then invoking this 134 * method has no effect. */ 135 debug("Test 4: no-op"); 136 try { 137 channel.shutdown(); 138 pass(); 139 } catch (IOException ioe) { 140 unexpected(ioe); 141 } 142 143 /* TEST 5: Further sends will throw ClosedChannelException */ 144 debug("Test 5: ClosedChannelException"); 145 info = MessageInfo.createOutgoing(null, 1); 146 try { 147 channel.send(buffer, info); 148 fail("shutdown not throwing expected ClosedChannelException"); 149 } catch (ClosedChannelException unused) { 150 pass(); 151 } catch (IOException ioe) { 152 unexpected(ioe); 153 } 154 155 /* TEST 6: getRemoteAddresses */ 156 debug("Test 6: getRemoteAddresses"); 157 try { 158 java.util.Set<SocketAddress> remoteAddrs = channel.getRemoteAddresses(); 159 check(remoteAddrs.isEmpty(), 160 "A shutdown channel should not have remote addresses"); 161 } catch (IOException ioe) { 162 unexpected(ioe); 163 } 164 } catch (IOException ioe) { 165 unexpected(ioe); 166 } catch (InterruptedException ie) { 167 unexpected(ie); 168 }finally { 169 finishedLatch.countDown(); 170 try { if (channel != null) channel.close(); } 171 catch (IOException e) { unexpected(e);} 172 } 173 } 174 175 class ShutdownServer implements Runnable 176 { 177 final InetSocketAddress serverAddr; 178 private SctpServerChannel ssc; 179 ShutdownServer()180 public ShutdownServer() throws IOException { 181 ssc = SctpServerChannel.open().bind(null); 182 //serverAddr = (InetSocketAddress)(ssc.getAllLocalAddresses().iterator().next()); 183 184 java.util.Set<SocketAddress> addrs = ssc.getAllLocalAddresses(); 185 if (addrs.isEmpty()) 186 debug("addrs should not be empty"); 187 188 serverAddr = (InetSocketAddress) addrs.iterator().next(); 189 190 } 191 start()192 public void start() { 193 (new Thread(this, "ShutdownServer-" + serverAddr.getPort())).start(); 194 } 195 address()196 public InetSocketAddress address() { 197 return serverAddr; 198 } 199 200 @Override run()201 public void run() { 202 SctpChannel sc = null; 203 try { 204 sc = ssc.accept(); 205 206 /* send a message */ 207 MessageInfo info = MessageInfo.createOutgoing(null, 1); 208 ByteBuffer buf = ByteBuffer.allocateDirect(Util.SMALL_BUFFER); 209 buf.put(Util.SMALL_MESSAGE.getBytes("ISO-8859-1")); 210 buf.flip(); 211 sc.send(buf, info); 212 213 /* notify client that the data has been sent */ 214 sentLatch.countDown(); 215 216 /* wait until after the client has finished its tests */ 217 finishedLatch.await(); 218 219 buf.clear(); 220 ShutdownNotificationHandler handler = 221 new ShutdownNotificationHandler(); 222 BooleanWrapper bool = new BooleanWrapper(); 223 sc.configureBlocking(false); 224 sc.receive(buf, bool, handler); 225 check(bool.booleanValue(), "SHUTDOWN not received on Server"); 226 227 } catch (IOException ioe) { 228 ioe.printStackTrace(); 229 } catch (InterruptedException ie) { 230 ie.printStackTrace(); 231 } finally { 232 try { if (ssc != null) ssc.close(); } 233 catch (IOException ioe) { unexpected(ioe); } 234 try { if (sc != null) sc.close(); } 235 catch (IOException ioe) { unexpected(ioe); } 236 } 237 } 238 } 239 240 class BooleanWrapper { 241 boolean bool; 242 booleanValue()243 boolean booleanValue() { 244 return bool; 245 } 246 booleanValue(boolean value)247 void booleanValue(boolean value) { 248 bool = value; 249 } 250 } 251 252 class ShutdownNotificationHandler extends AbstractNotificationHandler<BooleanWrapper> 253 { 254 @Override handleNotification( ShutdownNotification sn, BooleanWrapper bool)255 public HandlerResult handleNotification( 256 ShutdownNotification sn, BooleanWrapper bool) 257 { 258 bool.booleanValue(true); 259 debug(sn.toString()); 260 return HandlerResult.RETURN; 261 } 262 } 263 264 //--------------------- Infrastructure --------------------------- 265 boolean debug = true; 266 volatile int passed = 0, failed = 0; pass()267 void pass() {passed++;} fail()268 void fail() {failed++; Thread.dumpStack();} fail(String msg)269 void fail(String msg) {System.err.println(msg); fail();} unexpected(Throwable t)270 void unexpected(Throwable t) {failed++; t.printStackTrace();} check(boolean cond)271 void check(boolean cond) {if (cond) pass(); else fail();} check(boolean cond, String failMessage)272 void check(boolean cond, String failMessage) {if (cond) pass(); else fail(failMessage);} debug(String message)273 void debug(String message) {if(debug) { System.out.println(message); } } main(String[] args)274 public static void main(String[] args) throws Throwable { 275 Class<?> k = new Object(){}.getClass().getEnclosingClass(); 276 try {k.getMethod("instanceMain",String[].class) 277 .invoke( k.newInstance(), (Object) args);} 278 catch (Throwable e) {throw e.getCause();}} instanceMain(String[] args)279 public void instanceMain(String[] args) throws Throwable { 280 try {test(args);} catch (Throwable t) {unexpected(t);} 281 System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed); 282 if (failed > 0) throw new AssertionError("Some tests failed");} 283 284 } 285