jdk/test/com/sun/nio/sctp/SctpChannel/Send.java
changeset 2542 d859108aea12
child 4677 1b6ce3fbc01b
equal deleted inserted replaced
2418:15096652c4d4 2542:d859108aea12
       
     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.InetSocketAddress;
       
    31 import java.net.SocketAddress;
       
    32 import java.io.IOException;
       
    33 import java.util.concurrent.CountDownLatch;
       
    34 import java.util.concurrent.TimeUnit;
       
    35 import java.nio.ByteBuffer;
       
    36 import java.nio.channels.NotYetConnectedException;
       
    37 import java.nio.channels.ClosedChannelException;
       
    38 import com.sun.nio.sctp.AbstractNotificationHandler;
       
    39 import com.sun.nio.sctp.Association;
       
    40 import com.sun.nio.sctp.AssociationChangeNotification;
       
    41 import com.sun.nio.sctp.AssociationChangeNotification.AssocChangeEvent;
       
    42 import com.sun.nio.sctp.HandlerResult;
       
    43 import com.sun.nio.sctp.InvalidStreamException;
       
    44 import com.sun.nio.sctp.MessageInfo;
       
    45 import com.sun.nio.sctp.Notification;
       
    46 import com.sun.nio.sctp.SctpChannel;
       
    47 import com.sun.nio.sctp.SctpServerChannel;
       
    48 import static java.lang.System.out;
       
    49 import static java.lang.System.err;
       
    50 
       
    51 public class Send {
       
    52     /* Latches used to synchronize between the client and server so that
       
    53      * connections without any IO may not be closed without being accepted */
       
    54     final CountDownLatch clientFinishedLatch = new CountDownLatch(1);
       
    55     final CountDownLatch serverFinishedLatch = new CountDownLatch(1);
       
    56 
       
    57     SendNotificationHandler handler = new SendNotificationHandler();
       
    58 
       
    59     void test(String[] args) {
       
    60         SocketAddress address = null;
       
    61         Server server = null;
       
    62 
       
    63         if (!Util.isSCTPSupported()) {
       
    64             out.println("SCTP protocol is not supported");
       
    65             out.println("Test cannot be run");
       
    66             return;
       
    67         }
       
    68 
       
    69         if (args.length == 2) {
       
    70             /* requested to connecct to a specific address */
       
    71             try {
       
    72                 int port = Integer.valueOf(args[1]);
       
    73                 address = new InetSocketAddress(args[0], port);
       
    74             } catch (NumberFormatException nfe) {
       
    75                 err.println(nfe);
       
    76             }
       
    77         } else {
       
    78             /* start server on local machine, default */
       
    79             try {
       
    80                 server = new Server();
       
    81                 server.start();
       
    82                 address = server.address();
       
    83                 debug("Server started and listening on " + address);
       
    84             } catch (IOException ioe) {
       
    85                 ioe.printStackTrace();
       
    86                 return;
       
    87             }
       
    88         }
       
    89 
       
    90         doTest(address);
       
    91     }
       
    92 
       
    93     void doTest(SocketAddress peerAddress) {
       
    94         SctpChannel channel = null;
       
    95         ByteBuffer buffer = ByteBuffer.allocate(Util.LARGE_BUFFER);
       
    96         MessageInfo info = MessageInfo.createOutgoing(null, 0);
       
    97 
       
    98         try {
       
    99             channel = SctpChannel.open();
       
   100 
       
   101             /* TEST 1: Verify NotYetConnectedException thrown */
       
   102             try {
       
   103                 channel.send(buffer, info);
       
   104                 fail("should have thrown NotYetConnectedException");
       
   105             } catch (NotYetConnectedException unused) {
       
   106                 pass();
       
   107             }  catch (IOException ioe) {
       
   108                 unexpected(ioe);
       
   109             }
       
   110 
       
   111             channel.connect(peerAddress);
       
   112             /* Receive CommUp */
       
   113             channel.receive(buffer, null, handler);
       
   114 
       
   115             /* save for TEST 8 */
       
   116             Association association = channel.association();
       
   117 
       
   118             /* TEST 2: send small message */
       
   119             int streamNumber = 0;
       
   120             debug("sending on stream number: " + streamNumber);
       
   121             info = MessageInfo.createOutgoing(null, streamNumber);
       
   122             buffer.put(Util.SMALL_MESSAGE.getBytes("ISO-8859-1"));
       
   123             buffer.flip();
       
   124             int position = buffer.position();
       
   125             int remaining = buffer.remaining();
       
   126 
       
   127             debug("sending small message: " + buffer);
       
   128             int sent = channel.send(buffer, info);
       
   129 
       
   130             check(sent == remaining, "sent should be equal to remaining");
       
   131             check(buffer.position() == (position + sent),
       
   132                     "buffers position should have been incremented by sent");
       
   133 
       
   134             buffer.clear();
       
   135 
       
   136             /* TEST 3: send large message */
       
   137             streamNumber = handler.maxOutStreams() - 1;
       
   138             debug("sending on stream number: " + streamNumber);
       
   139             info = MessageInfo.createOutgoing(null, streamNumber);
       
   140             buffer.put(Util.LARGE_MESSAGE.getBytes("ISO-8859-1"));
       
   141             buffer.flip();
       
   142             position = buffer.position();
       
   143             remaining = buffer.remaining();
       
   144 
       
   145             debug("sending large message: " + buffer);
       
   146             sent = channel.send(buffer, info);
       
   147 
       
   148             check(sent == remaining, "sent should be equal to remaining");
       
   149             check(buffer.position() == (position + sent),
       
   150                     "buffers position should have been incremented by sent");
       
   151 
       
   152             /* TEST 4: InvalidStreamExcepton */
       
   153             streamNumber = handler.maxInStreams;
       
   154             info = MessageInfo.createOutgoing(null, streamNumber);
       
   155             buffer.clear();
       
   156             buffer.put(Util.SMALL_MESSAGE.getBytes("ISO-8859-1"));
       
   157             buffer.flip();
       
   158             position = buffer.position();
       
   159             remaining = buffer.remaining();
       
   160 
       
   161             debug("sending on stream number: " + streamNumber);
       
   162             debug("sending small message: " + buffer);
       
   163             try {
       
   164                 sent = channel.send(buffer, info);
       
   165                 fail("should have thrown InvalidStreamExcepton");
       
   166             } catch (InvalidStreamException ise){
       
   167                 pass();
       
   168             } catch (IOException ioe) {
       
   169                 unexpected(ioe);
       
   170             }
       
   171             check(buffer.remaining() == remaining,
       
   172                     "remaining should not be changed");
       
   173             check(buffer.position() == position,
       
   174                     "buffers position should not be changed");
       
   175 
       
   176             /* TEST 5: Non blocking send should return zero if there is
       
   177                insufficient room in the underlying output buffer */
       
   178             buffer.clear();
       
   179             channel.configureBlocking(false);
       
   180             info = MessageInfo.createOutgoing(null, 1);
       
   181             buffer.put(Util.LARGE_MESSAGE.getBytes("ISO-8859-1"));
       
   182             buffer.flip();
       
   183 
       
   184             int count = 0;  // do not loop forever
       
   185             do {
       
   186                 position = buffer.position();
       
   187                 remaining = buffer.remaining();
       
   188                 debug("sending large message: " + buffer);
       
   189                 sent = channel.send(buffer, info);
       
   190                 if (sent == 0) {
       
   191                     check(buffer.remaining() == remaining,
       
   192                           "remaining should not be changed");
       
   193                     check(buffer.position() == position,
       
   194                           "buffers position should not be changed");
       
   195                 }
       
   196                 buffer.rewind();
       
   197             } while (sent != 0 && count++ < 100);
       
   198 
       
   199             /* TEST 6: ClosedChannelException */
       
   200             channel.close();
       
   201             try {
       
   202                 channel.send(buffer, info);
       
   203                 fail("should have thrown ClosedChannelException");
       
   204             } catch (ClosedChannelException cce) {
       
   205                pass();
       
   206             } catch (IOException ioe) {
       
   207                 unexpected(ioe);
       
   208             }
       
   209 
       
   210             /* TEST 7: send without previous receive.
       
   211              * Verify that send can still throw InvalidStreamExcepton */
       
   212             debug("Opening new channel.");
       
   213             channel = SctpChannel.open(peerAddress, 0, 0);
       
   214             streamNumber = Short.MAX_VALUE - 1;
       
   215             info = MessageInfo.createOutgoing(null, streamNumber);
       
   216             buffer.clear();
       
   217             buffer.put(Util.SMALL_MESSAGE.getBytes("ISO-8859-1"));
       
   218             buffer.flip();
       
   219             position = buffer.position();
       
   220             remaining = buffer.remaining();
       
   221 
       
   222             debug("sending on stream number: " + streamNumber);
       
   223             debug("sending small message: " + buffer);
       
   224             try {
       
   225                 sent = channel.send(buffer, info);
       
   226                 fail("should have thrown InvalidStreamExcepton");
       
   227             } catch (InvalidStreamException ise){
       
   228                 pass();
       
   229             } catch (IOException ioe) {
       
   230                 unexpected(ioe);
       
   231             }
       
   232             check(buffer.remaining() == remaining,
       
   233                     "remaining should not be changed");
       
   234             check(buffer.position() == position,
       
   235                     "buffers position should not be changed");
       
   236 
       
   237             /* Receive CommUp */
       
   238             channel.receive(buffer, null, handler);
       
   239             check(handler.receivedCommUp(), "should have received COMM_UP");
       
   240 
       
   241             /* TEST 8: Send to an invalid preferred SocketAddress */
       
   242             SocketAddress addr = new InetSocketAddress("123.123.123.123", 3456);
       
   243             info = MessageInfo.createOutgoing(addr, 0);
       
   244             debug("sending to " + addr);
       
   245             debug("sending small message: " + buffer);
       
   246             try {
       
   247                 sent = channel.send(buffer, info);
       
   248                 fail("Invalid address should have thrown an Exception.");
       
   249             } catch (Exception e){
       
   250                 pass();
       
   251                 debug("OK, caught " + e);
       
   252             }
       
   253         } catch (IOException ioe) {
       
   254             unexpected(ioe);
       
   255         } finally {
       
   256             clientFinishedLatch.countDown();
       
   257             try { serverFinishedLatch.await(10L, TimeUnit.SECONDS); }
       
   258             catch (InterruptedException ie) { unexpected(ie); }
       
   259             if (channel != null) {
       
   260                 try { channel.close(); }
       
   261                 catch (IOException e) { unexpected (e);}
       
   262             }
       
   263         }
       
   264     }
       
   265 
       
   266     class Server implements Runnable
       
   267     {
       
   268         final InetSocketAddress serverAddr;
       
   269         private SctpServerChannel ssc;
       
   270 
       
   271         public Server() throws IOException {
       
   272             ssc = SctpServerChannel.open().bind(null);
       
   273             java.util.Set<SocketAddress> addrs = ssc.getAllLocalAddresses();
       
   274             if (addrs.isEmpty())
       
   275                 debug("addrs should not be empty");
       
   276 
       
   277             serverAddr = (InetSocketAddress) addrs.iterator().next();
       
   278         }
       
   279 
       
   280         public void start() {
       
   281             (new Thread(this, "Server-"  + serverAddr.getPort())).start();
       
   282         }
       
   283 
       
   284         public InetSocketAddress address() {
       
   285             return serverAddr;
       
   286         }
       
   287 
       
   288         @Override
       
   289         public void run() {
       
   290             ByteBuffer buffer = ByteBuffer.allocateDirect(Util.LARGE_BUFFER);
       
   291             SctpChannel sc1 = null, sc2 = null;
       
   292             try {
       
   293                 sc1 = ssc.accept();
       
   294 
       
   295                 /* receive a small message */
       
   296                 MessageInfo info;
       
   297                 do {
       
   298                     info = sc1.receive(buffer, null, null);
       
   299                     if (info == null) {
       
   300                         fail("Server: unexpected null from receive");
       
   301                             return;
       
   302                     }
       
   303                 } while (!info.isComplete());
       
   304 
       
   305                 buffer.flip();
       
   306                 check(info != null, "info is null");
       
   307                 check(info.streamNumber() == 0,
       
   308                         "message not sent on the correct stream");
       
   309                 check(info.bytes() == Util.SMALL_MESSAGE.getBytes("ISO-8859-1").
       
   310                       length, "bytes received not equal to message length");
       
   311                 check(info.bytes() == buffer.remaining(), "bytes != remaining");
       
   312                 check(Util.compare(buffer, Util.SMALL_MESSAGE),
       
   313                   "received message not the same as sent message");
       
   314 
       
   315                 /* receive a large message */
       
   316                 buffer.clear();
       
   317                 do {
       
   318                     info = sc1.receive(buffer, null, null);
       
   319                     if (info == null) {
       
   320                         fail("Server: unexpected null from receive");
       
   321                             return;
       
   322                     }
       
   323                 } while (!info.isComplete());
       
   324 
       
   325                 buffer.flip();
       
   326                 check(info != null, "info is null");
       
   327                 check(info.streamNumber() == handler.maxOutStreams() - 1,
       
   328                         "message not sent on the correct stream");
       
   329                 check(info.bytes() == Util.LARGE_MESSAGE.getBytes("ISO-8859-1").
       
   330                       length, "bytes received not equal to message length");
       
   331                 check(info.bytes() == buffer.remaining(), "bytes != remaining");
       
   332                 check(Util.compare(buffer, Util.LARGE_MESSAGE),
       
   333                   "received message not the same as sent message");
       
   334 
       
   335                 /* TEST 7 ++ */
       
   336                 sc2 = ssc.accept();
       
   337 
       
   338                 clientFinishedLatch.await(10L, TimeUnit.SECONDS);
       
   339                 serverFinishedLatch.countDown();
       
   340             } catch (IOException ioe) {
       
   341                 unexpected(ioe);
       
   342             } catch (InterruptedException ie) {
       
   343                 unexpected(ie);
       
   344             } finally {
       
   345                 try { if (ssc != null) ssc.close(); }
       
   346                 catch (IOException  unused) {}
       
   347                 try { if (sc1 != null) sc1.close(); }
       
   348                 catch (IOException  unused) {}
       
   349                 try { if (sc2 != null) sc2.close(); }
       
   350                 catch (IOException  unused) {}
       
   351             }
       
   352         }
       
   353     }
       
   354 
       
   355     class SendNotificationHandler extends AbstractNotificationHandler<Void>
       
   356     {
       
   357         boolean receivedCommUp;  // false
       
   358         int maxInStreams;
       
   359         int maxOutStreams;
       
   360 
       
   361         public boolean receivedCommUp() {
       
   362             return receivedCommUp;
       
   363         }
       
   364 
       
   365         public int maxInStreams() {
       
   366             return maxInStreams;
       
   367         }
       
   368 
       
   369         public int maxOutStreams(){
       
   370             return maxOutStreams;
       
   371         }
       
   372 
       
   373         @Override
       
   374         public HandlerResult handleNotification(
       
   375                 Notification notification, Void attachment) {
       
   376             fail("Unknown notification type");
       
   377             return HandlerResult.CONTINUE;
       
   378         }
       
   379 
       
   380         @Override
       
   381         public HandlerResult handleNotification(
       
   382                 AssociationChangeNotification notification, Void attachment) {
       
   383             AssocChangeEvent event = notification.event();
       
   384             Association association = notification.association();
       
   385             debug("AssociationChangeNotification");
       
   386             debug("  Association: " + notification.association());
       
   387             debug("  Event: " + event);
       
   388 
       
   389             if (event.equals(AssocChangeEvent.COMM_UP))
       
   390                 receivedCommUp = true;
       
   391 
       
   392             this.maxInStreams = association.maxInboundStreams();
       
   393             this.maxOutStreams = association.maxOutboundStreams();
       
   394 
       
   395             return HandlerResult.RETURN;
       
   396         }
       
   397     }
       
   398 
       
   399         //--------------------- Infrastructure ---------------------------
       
   400     boolean debug = true;
       
   401     volatile int passed = 0, failed = 0;
       
   402     void pass() {passed++;}
       
   403     void fail() {failed++; Thread.dumpStack();}
       
   404     void fail(String msg) {System.err.println(msg); fail();}
       
   405     void unexpected(Throwable t) {failed++; t.printStackTrace();}
       
   406     void check(boolean cond) {if (cond) pass(); else fail();}
       
   407     void check(boolean cond, String failMessage) {if (cond) pass(); else fail(failMessage);}
       
   408     void debug(String message) {if(debug) { System.out.println(message); }  }
       
   409     public static void main(String[] args) throws Throwable {
       
   410         Class<?> k = new Object(){}.getClass().getEnclosingClass();
       
   411         try {k.getMethod("instanceMain",String[].class)
       
   412                 .invoke( k.newInstance(), (Object) args);}
       
   413         catch (Throwable e) {throw e.getCause();}}
       
   414     public void instanceMain(String[] args) throws Throwable {
       
   415         try {test(args);} catch (Throwable t) {unexpected(t);}
       
   416         System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
       
   417         if (failed > 0) throw new AssertionError("Some tests failed");}
       
   418 
       
   419 }