--- old/test/java/nio/channels/DatagramChannel/AdaptDatagramSocket.java 2012-10-30 18:40:16.000000000 +0100 +++ new/test/java/nio/channels/DatagramChannel/AdaptDatagramSocket.java 2012-10-30 18:40:16.000000000 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2012, 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 @@ -27,29 +27,16 @@ * @library .. */ -import java.io.*; import java.net.*; -import java.nio.*; import java.nio.channels.*; -import java.nio.charset.*; import java.util.*; public class AdaptDatagramSocket { static java.io.PrintStream out = System.out; - static Random rand = new Random(); - static final int ECHO_PORT = 7; - static final int DISCARD_PORT = 9; - static final String REMOTE_HOST = TestUtil.HOST; - - static final InetSocketAddress echoAddress - = new InetSocketAddress(REMOTE_HOST, ECHO_PORT); - static final InetSocketAddress discardAddress - = new InetSocketAddress(REMOTE_HOST, DISCARD_PORT); - static String toString(DatagramPacket dp) { return ("DatagramPacket[off=" + dp.getOffset() + ", len=" + dp.getLength() @@ -88,10 +75,11 @@ out.println("rtt: " + (System.currentTimeMillis() - start)); out.println("post op: " + toString(op) + " ip: " + toString(ip)); - for (int i = 0; i < ip.getLength(); i++) + for (int i = 0; i < ip.getLength(); i++) { if (ip.getData()[ip.getOffset() + i] != op.getData()[op.getOffset() + i]) throw new Exception("Incorrect data received"); + } if (!(ip.getSocketAddress().equals(dst))) { throw new Exception("Incorrect sender address, expected: " + dst @@ -130,8 +118,9 @@ ds.setSoTimeout(timeout); out.println("timeout: " + ds.getSoTimeout()); - for (int i = 0; i < 5; i++) + for (int i = 0; i < 5; i++) { test(ds, dst, shouldTimeout); + } // Leave the socket open so that we don't reuse the old src address //ds.close(); @@ -139,10 +128,23 @@ } public static void main(String[] args) throws Exception { - test(echoAddress, 0, false, false); - test(echoAddress, 0, false, true); - test(echoAddress, 5000, false, false); - test(discardAddress, 10, true, false); + // need an UDP echo server + try (TestUtil.UdpEchoServer echoServer = + TestUtil.UdpEchoServer.startNewServer(100)) { + final InetSocketAddress address = + new InetSocketAddress(echoServer.getAddress(), + echoServer.getPort()); + test(address, 0, false, false); + test(address, 0, false, true); + test(address, 5000, false, false); + } + try (TestUtil.UdpDiscardServer discardServer = + TestUtil.UdpDiscardServer.startNewServer()) { + final InetSocketAddress address = + new InetSocketAddress(discardServer.getAddress(), + discardServer.getPort()); + test(address, 10, true, false); + } } } --- old/test/java/nio/channels/DatagramChannel/IsBound.java 2012-10-30 18:40:17.000000000 +0100 +++ new/test/java/nio/channels/DatagramChannel/IsBound.java 2012-10-30 18:40:17.000000000 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2012, 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 @@ -34,21 +34,24 @@ public class IsBound { public static void main(String argv[]) throws Exception { - InetSocketAddress isa = new InetSocketAddress( - InetAddress.getByName(TestUtil.HOST), 13); - ByteBuffer bb = ByteBuffer.allocateDirect(256); - bb.put("hello".getBytes()); - bb.flip(); - - DatagramChannel dc = DatagramChannel.open(); - dc.send(bb, isa); - if(!dc.socket().isBound()) - throw new Exception("Test failed"); - dc.close(); - - dc = DatagramChannel.open(); - if(dc.socket().isBound()) - throw new Exception("Test failed"); - dc.close(); + try (TestUtil.UdpDayTimeServer daytimeServer = + TestUtil.UdpDayTimeServer.startNewServer(100)) { + InetSocketAddress isa = new InetSocketAddress( + daytimeServer.getAddress(), daytimeServer.getPort()); + ByteBuffer bb = ByteBuffer.allocateDirect(256); + bb.put("hello".getBytes()); + bb.flip(); + + DatagramChannel dc = DatagramChannel.open(); + dc.send(bb, isa); + if(!dc.socket().isBound()) + throw new Exception("Test failed"); + dc.close(); + + dc = DatagramChannel.open(); + if(dc.socket().isBound()) + throw new Exception("Test failed"); + dc.close(); + } } } --- old/test/java/nio/channels/DatagramChannel/IsConnected.java 2012-10-30 18:40:18.000000000 +0100 +++ new/test/java/nio/channels/DatagramChannel/IsConnected.java 2012-10-30 18:40:18.000000000 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2012, 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 @@ -28,21 +28,23 @@ */ import java.net.*; -import java.nio.*; import java.nio.channels.*; public class IsConnected { public static void main(String argv[]) throws Exception { - InetSocketAddress isa = new InetSocketAddress( - InetAddress.getByName(TestUtil.HOST), 13); - DatagramChannel dc = DatagramChannel.open(); - dc.configureBlocking(true); - dc.connect(isa); - if (!dc.isConnected()) - throw new RuntimeException("channel.isConnected inconsistent"); - if (!dc.socket().isConnected()) - throw new RuntimeException("socket.isConnected inconsistent"); - dc.close(); + try (TestUtil.UdpDayTimeServer daytimeServer = + TestUtil.UdpDayTimeServer.startNewServer(100)) { + InetSocketAddress isa = new InetSocketAddress( + daytimeServer.getAddress(), daytimeServer.getPort()); + DatagramChannel dc = DatagramChannel.open(); + dc.configureBlocking(true); + dc.connect(isa); + if (!dc.isConnected()) + throw new RuntimeException("channel.isConnected inconsistent"); + if (!dc.socket().isConnected()) + throw new RuntimeException("socket.isConnected inconsistent"); + dc.close(); + } } } --- old/test/java/nio/channels/Selector/Alias.java 2012-10-30 18:40:20.000000000 +0100 +++ new/test/java/nio/channels/Selector/Alias.java 2012-10-30 18:40:19.000000000 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2002, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2012, 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 @@ -27,12 +27,11 @@ * @library .. */ -import java.io.*; import java.net.*; import java.nio.*; import java.nio.channels.*; -import java.util.*; import java.nio.channels.spi.SelectorProvider; +import java.util.*; public class Alias { @@ -40,18 +39,26 @@ static int LIMIT = 20; // Hangs after just 1 if problem is present public static void main(String[] args) throws Exception { - test1(); + try (TestUtil.DayTimeServer daytimeServer = + TestUtil.DayTimeServer.startNewServer(100)) { + test1(daytimeServer); + } } - public static void test1() throws Exception { + static void test1(TestUtil.DayTimeServer daytimeServer) + throws Exception { Selector selector = SelectorProvider.provider().openSelector(); - InetAddress myAddress=InetAddress.getByName(TestUtil.HOST); - InetSocketAddress isa = new InetSocketAddress(myAddress,13); + InetAddress myAddress = daytimeServer.getAddress(); + InetSocketAddress isa = new InetSocketAddress(myAddress, daytimeServer.getPort()); for (int j=0; j 0) { - Set readyKeys = connectSelector.selectedKeys(); - Iterator i = readyKeys.iterator(); - while (i.hasNext()) { - SelectionKey sk = (SelectionKey)i.next(); - i.remove(); - SocketChannel nextReady = (SocketChannel)sk.channel(); - result = nextReady.finishConnect(); - if (result) - sk.cancel(); + try (TestUtil.EchoServer echoServer = + TestUtil.EchoServer.startNewServer(100)) { + InetSocketAddress isa = new InetSocketAddress(echoServer.getAddress(), + echoServer.getPort()); + SocketChannel sc = SocketChannel.open(); + sc.configureBlocking(false); + boolean result = sc.connect(isa); + if (result) { + System.err.println("Socket immediately connected on " + + System.getProperty("os.name") + + ": " + sc); + } + while (!result) { + SelectionKey connectKey = sc.register(connectSelector, + SelectionKey.OP_CONNECT); + int keysAdded = connectSelector.select(); + if (keysAdded > 0) { + Set readyKeys = connectSelector.selectedKeys(); + Iterator i = readyKeys.iterator(); + while (i.hasNext()) { + SelectionKey sk = (SelectionKey)i.next(); + i.remove(); + SocketChannel nextReady = (SocketChannel)sk.channel(); + result = nextReady.finishConnect(); + if (result) + sk.cancel(); + } } } - } - byte[] bs = new byte[] { (byte)0xca, (byte)0xfe, - (byte)0xba, (byte)0xbe }; - ByteBuffer bb = ByteBuffer.wrap(bs); - sc.configureBlocking(true); - sc.write(bb); - bb.rewind(); - - ByteBuffer bb2 = ByteBuffer.allocateDirect(100); - int n = sc.read(bb2); - bb2.flip(); - - sc.close(); - connectSelector.close(); - - if (!bb.equals(bb2)) - throw new Exception("Echoed bytes incorrect: Sent " - + bb + ", got " + bb2); + byte[] bs = new byte[] { (byte)0xca, (byte)0xfe, + (byte)0xba, (byte)0xbe }; + ByteBuffer bb = ByteBuffer.wrap(bs); + sc.configureBlocking(true); + sc.write(bb); + bb.rewind(); + + ByteBuffer bb2 = ByteBuffer.allocateDirect(100); + int n = sc.read(bb2); + bb2.flip(); + + sc.close(); + connectSelector.close(); + + if (!bb.equals(bb2)) + throw new Exception("Echoed bytes incorrect: Sent " + + bb + ", got " + bb2); + } } - } --- old/test/java/nio/channels/Selector/Connect.java 2012-10-30 18:40:22.000000000 +0100 +++ new/test/java/nio/channels/Selector/Connect.java 2012-10-30 18:40:22.000000000 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2012, 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 @@ -27,12 +27,11 @@ * @library .. */ -import java.io.*; import java.net.*; import java.nio.*; import java.nio.channels.*; -import java.util.*; import java.nio.channels.spi.SelectorProvider; +import java.util.*; public class Connect { @@ -40,12 +39,17 @@ static int LIMIT = 100; public static void main(String[] args) throws Exception { - scaleTest(); + try (TestUtil.DayTimeServer daytimeServer = + TestUtil.DayTimeServer.startNewServer(50)) { + scaleTest(daytimeServer); + } } - public static void scaleTest() throws Exception { - InetAddress myAddress=InetAddress.getByName(TestUtil.HOST); - InetSocketAddress isa = new InetSocketAddress(myAddress,13); + static void scaleTest(TestUtil.DayTimeServer daytimeServer) + throws Exception { + InetAddress myAddress = daytimeServer.getAddress(); + InetSocketAddress isa = + new InetSocketAddress(myAddress, daytimeServer.getPort()); for (int j=0; j> NONE = Collections.emptySet(); + + // make a set of expected exception. + // calling expectedExceptions(null) will always return NONE. + static Collection> expectedExceptions(Class... expected) { + final Collection> exceptions; + if (expected == null || expected.length == 0) { + exceptions = NONE; + } else if (expected.length == 0 && expected[0] == null) { + exceptions = NONE; + } else if (expected.length == 1) { + exceptions = Collections.>singleton(expected[0]); + } else { + exceptions = new HashSet<>(Arrays.asList(expected)); + } + return exceptions; + } static abstract class Test { @@ -76,37 +97,63 @@ check(!sc.isConnectionPending(), "!isConnectionPending"); check(sc.isOpen(), "isOpen"); break; + case ST_PENDING_OR_CONNECTED: + check(sc.isConnected() || sc.isConnectionPending(), + "isConnected || isConnectionPending"); + check(sc.isOpen(), "isOpen"); + break; } } - Test(String name, Class exception, int state) throws Exception { + Test(String name, Class exception, int state) throws Exception { + this(name, expectedExceptions(exception), state); + } + + // On some architecture we may need to accept several exceptions. + // For instance on Solaris, when using a server colocated on the + // machine we cannot guarantee that we will get a ConnectionPending + // exception when connecting twice on the same non-blocking socket. + // We may get a an AlreadyConnected exception, which is also valid: it + // simply means that the first connection as been immediately accepted. + Test(String name, Collection> exceptions, int state) throws Exception { SocketChannel sc = SocketChannel.open(); - String note = null; + String note; try { try { note = go(sc); } catch (Exception x) { - if (exception != null) { + Class expectedExceptionClass = null; + for (Class exception : exceptions) { if (exception.isInstance(x)) { log.println(name + ": As expected: " + x); + expectedExceptionClass = exception; check(sc, state); - return; - } else { - throw new Exception(name + break; + } + } + if (expectedExceptionClass == null + && !exceptions.isEmpty()) { + // we had an exception, but it's not of the set of + // exceptions we expected. + throw new Exception(name + ": Incorrect exception", x); - } - } else { + } else if (exceptions.isEmpty()) { + // we didn't expect any exception throw new Exception(name + ": Unexpected exception", x); } + // if we reach here, we have our expected exception + assert expectedExceptionClass != null; + return; } - if (exception != null) + if (!exceptions.isEmpty()) { throw new Exception(name + ": Expected exception not thrown: " - + exception); + + exceptions.iterator().next()); + } check(sc, state); log.println(name + ": Returned normally" + ((note != null) ? ": " + note : "")); @@ -123,6 +170,7 @@ new Test("Read unconnected", NotYetConnectedException.class, ST_UNCONNECTED) { + @Override String go(SocketChannel sc) throws Exception { ByteBuffer b = ByteBuffer.allocateDirect(1024); sc.read(b); @@ -131,19 +179,22 @@ new Test("Write unconnected", NotYetConnectedException.class, ST_UNCONNECTED) { + @Override String go(SocketChannel sc) throws Exception { ByteBuffer b = ByteBuffer.allocateDirect(1024); sc.write(b); return null; }}; - new Test("Simple connect", null, ST_CONNECTED) { + new Test("Simple connect", NONE, ST_CONNECTED) { + @Override String go(SocketChannel sc) throws Exception { sc.connect(remote); return null; }}; - new Test("Simple connect & finish", null, ST_CONNECTED) { + new Test("Simple connect & finish", NONE, ST_CONNECTED) { + @Override String go(SocketChannel sc) throws Exception { sc.connect(remote); if (!sc.finishConnect()) @@ -153,6 +204,7 @@ new Test("Double connect", AlreadyConnectedException.class, ST_CONNECTED) { + @Override String go(SocketChannel sc) throws Exception { sc.connect(remote); sc.connect(remote); @@ -161,12 +213,16 @@ new Test("Finish w/o start", NoConnectionPendingException.class, ST_UNCONNECTED) { + @Override String go(SocketChannel sc) throws Exception { sc.finishConnect(); return null; }}; - new Test("NB simple connect", null, ST_CONNECTED) { + // Note: using our local EchoServer rather than echo on a distant + // host - we see that Tries to finish = 0 (instead of ~ 18). + new Test("NB simple connect", NONE, ST_CONNECTED) { + @Override String go(SocketChannel sc) throws Exception { sc.configureBlocking(false); sc.connect(remote); @@ -179,8 +235,16 @@ return ("Tries to finish = " + n); }}; + // Note: using our local EchoServer rather than echo on a distant + // host - we cannot guarantee that this test will get a + // a ConnectionPendingException: it may get an AlreadyConnectedException, + // so we should allow for both. new Test("NB double connect", - ConnectionPendingException.class, ST_PENDING) { + expectedExceptions( + ConnectionPendingException.class, + AlreadyConnectedException.class), + ST_PENDING_OR_CONNECTED) { + @Override String go(SocketChannel sc) throws Exception { sc.configureBlocking(false); sc.connect(remote); @@ -190,13 +254,15 @@ new Test("NB finish w/o start", NoConnectionPendingException.class, ST_UNCONNECTED) { + @Override String go(SocketChannel sc) throws Exception { sc.configureBlocking(false); sc.finishConnect(); return null; }}; - new Test("NB connect, B finish", null, ST_CONNECTED) { + new Test("NB connect, B finish", NONE, ST_CONNECTED) { + @Override String go(SocketChannel sc) throws Exception { sc.configureBlocking(false); sc.connect(remote); @@ -208,9 +274,12 @@ } public static void main(String[] args) throws Exception { - remote = new InetSocketAddress(InetAddress.getByName(REMOTE_HOST), - REMOTE_PORT); - tests(); + try (TestUtil.EchoServer echoServer = + TestUtil.EchoServer.startNewServer(500)) { + remote = new InetSocketAddress(echoServer.getAddress(), + echoServer.getPort()); + tests(); + } } } --- old/test/java/nio/channels/SocketChannel/FinishConnect.java 2012-10-30 18:40:31.000000000 +0100 +++ new/test/java/nio/channels/SocketChannel/FinishConnect.java 2012-10-30 18:40:31.000000000 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2012, 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 @@ -36,21 +36,21 @@ public class FinishConnect { - static final int DAYTIME_PORT = 13; - static final String DAYTIME_HOST = TestUtil.HOST; - public static void main(String[] args) throws Exception { - test1(true, true); - test1(true, false); - test1(false, true); - test1(false, false); - test2(); + try (TestUtil.DayTimeServer dayTimeServer = + TestUtil.DayTimeServer.startNewServer(100)) { + test1(dayTimeServer, true, true); + test1(dayTimeServer, true, false); + test1(dayTimeServer, false, true); + test1(dayTimeServer, false, false); + test2(dayTimeServer); + } } - static void test1(boolean select, boolean setBlocking) throws Exception { - InetSocketAddress isa - = new InetSocketAddress(InetAddress.getByName(DAYTIME_HOST), - DAYTIME_PORT); + static void test1(TestUtil.DayTimeServer daytimeServer, + boolean select, boolean setBlocking) throws Exception { + InetSocketAddress isa = new InetSocketAddress(daytimeServer.getAddress(), + daytimeServer.getPort()); SocketChannel sc = SocketChannel.open(); sc.configureBlocking(false); boolean connected = sc.connect(isa); @@ -109,15 +109,26 @@ sc.close(); } - static void test2() throws Exception { - InetSocketAddress isa - = new InetSocketAddress(InetAddress.getByName(DAYTIME_HOST), - DAYTIME_PORT); + static void test2(TestUtil.DayTimeServer daytimeServer) throws Exception { + InetSocketAddress isa = new InetSocketAddress(daytimeServer.getAddress(), + daytimeServer.getPort()); boolean done = false; int globalAttempts = 0; + int connectSuccess = 0; while (!done) { - if (globalAttempts++ > 50) + // When using a local daytime server it is not always possible + // to get a pending connection, as sc.connect(isa) may always + // return true. + // So we're going to throw the exception only if there was + // at least 1 case where we did not manage to connect. + if (globalAttempts++ > 50) { + if (globalAttempts == connectSuccess + 1) { + System.err.println("Can't fully test on " + + System.getProperty("os.name")); + break; + } throw new RuntimeException("Failed to connect"); + } SocketChannel sc = SocketChannel.open(); sc.configureBlocking(false); boolean connected = sc.connect(isa); @@ -132,6 +143,9 @@ } Thread.sleep(10); } + if (connected) { + connectSuccess++; + } sc.close(); } } --- old/test/java/nio/channels/SocketChannel/IsConnectable.java 2012-10-30 18:40:32.000000000 +0100 +++ new/test/java/nio/channels/SocketChannel/IsConnectable.java 2012-10-30 18:40:32.000000000 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2012, 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 @@ -28,24 +28,18 @@ */ import java.net.*; -import java.io.*; -import java.nio.*; import java.nio.channels.*; import java.nio.channels.spi.SelectorProvider; import java.util.*; public class IsConnectable { - static final int DAYTIME_PORT = 13; - static final String DAYTIME_HOST = TestUtil.HOST; - - static void test() throws Exception { - InetSocketAddress isa - = new InetSocketAddress(InetAddress.getByName(DAYTIME_HOST), - DAYTIME_PORT); + static void test(TestUtil.DayTimeServer daytimeServer) throws Exception { + InetSocketAddress isa = new InetSocketAddress(daytimeServer.getAddress(), + daytimeServer.getPort()); SocketChannel sc = SocketChannel.open(); sc.configureBlocking(false); - sc.connect(isa); + final boolean immediatelyConnected = sc.connect(isa); Selector selector = SelectorProvider.provider().openSelector(); try { @@ -67,7 +61,12 @@ throw new Exception("Test failed: 4737146 detected"); } } else { - throw new Exception("Select failed"); + if (!immediatelyConnected) { + throw new Exception("Select failed"); + } else { + System.err.println("IsConnectable couldn't be tested for " + + System.getProperty("os.name")); + } } } finally { sc.close(); @@ -76,7 +75,10 @@ } public static void main(String[] args) throws Exception { - test(); + try (TestUtil.DayTimeServer daytimeServer = + TestUtil.DayTimeServer.startNewServer(100)) { + test(daytimeServer); + } } } --- old/test/java/nio/channels/SocketChannel/LocalAddress.java 2012-10-30 18:40:33.000000000 +0100 +++ new/test/java/nio/channels/SocketChannel/LocalAddress.java 2012-10-30 18:40:33.000000000 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2012, 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 @@ -28,18 +28,22 @@ */ import java.net.*; -import java.nio.*; import java.nio.channels.*; public class LocalAddress { public static void main(String[] args) throws Exception { - test1(); + // We use an EchoServer rather than a Telnet server here - but hopefully + // it doesn't matter for the test purposes. + try (TestUtil.EchoServer echoServer = + TestUtil.EchoServer.startNewServer()) { + test1(echoServer); + } } - static void test1() throws Exception { + static void test1(TestUtil.AbstractServer server) throws Exception { InetAddress bogus = InetAddress.getByName("0.0.0.0"); InetSocketAddress saddr = new InetSocketAddress( - InetAddress.getByName(TestUtil.HOST), 23); + server.getAddress(), server.getPort()); //Test1: connect only SocketChannel sc = SocketChannel.open(); --- old/test/java/nio/channels/SocketChannel/Stream.java 2012-10-30 18:40:34.000000000 +0100 +++ new/test/java/nio/channels/SocketChannel/Stream.java 2012-10-30 18:40:34.000000000 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2012, 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 @@ -27,22 +27,16 @@ * @library .. */ -import java.net.*; import java.io.*; -import java.nio.*; +import java.net.*; import java.nio.channels.*; -import java.nio.charset.*; public class Stream { - static final int DAYTIME_PORT = 13; - static final String DAYTIME_HOST = TestUtil.HOST; - - static void test() throws Exception { - InetSocketAddress isa - = new InetSocketAddress(InetAddress.getByName(DAYTIME_HOST), - DAYTIME_PORT); + static void test(TestUtil.DayTimeServer daytimeServer) throws Exception { + InetSocketAddress isa = new InetSocketAddress(daytimeServer.getAddress(), + daytimeServer.getPort()); SocketChannel sc = SocketChannel.open(); sc.connect(isa); sc.configureBlocking(false); @@ -58,7 +52,9 @@ } public static void main(String[] args) throws Exception { - test(); + try (TestUtil.DayTimeServer dayTimeServer = + TestUtil.DayTimeServer.startNewServer(100)) { + test(dayTimeServer); + } } - } --- old/test/java/nio/channels/SocketChannel/VectorParams.java 2012-10-30 18:40:36.000000000 +0100 +++ new/test/java/nio/channels/SocketChannel/VectorParams.java 2012-10-30 18:40:35.000000000 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2012, 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 @@ -27,31 +27,31 @@ * @library .. */ -import java.net.*; import java.io.*; +import java.net.*; import java.nio.*; import java.nio.channels.*; -import java.nio.charset.*; public class VectorParams { static java.io.PrintStream out = System.out; - static final int DAYTIME_PORT = 13; - static final String DAYTIME_HOST = TestUtil.HOST; static final int testSize = 10; static ByteBuffer[] bufs = null; static InetSocketAddress isa = null; public static void main(String[] args) throws Exception { - initBufs(); - testSocketChannelVectorParams(); - testDatagramChannelVectorParams(); - testPipeVectorParams(); - testFileVectorParams(); + try (TestUtil.DayTimeServer daytimeServer = + TestUtil.DayTimeServer.startNewServer(100)) { + initBufs(daytimeServer); + testSocketChannelVectorParams(); + testDatagramChannelVectorParams(); + testPipeVectorParams(); + testFileVectorParams(); + } } - static void initBufs() throws Exception { + static void initBufs(TestUtil.DayTimeServer daytimeServer) throws Exception { bufs = new ByteBuffer[testSize]; for(int i=0; i connections = new ArrayList<>(); + private ServerSocket serverSocket; // the server socket + private boolean started = false; // whether the server is started + Throwable error = null; + + /** + * Creates a new abstract TCP server. + * + * @param linger the amount of time the server should wait before + * responding to requests. + */ + protected AbstractTcpServer(long linger) { + this.linger = linger; + } + + /** + * The local port to which the server is bound. + * + * @return The local port to which the server is bound. + * @exception IllegalStateException is thrown if the server is not + * started. + */ + @Override + public final synchronized int getPort() { + if (!started) { + throw new IllegalStateException("Not started"); + } + return serverSocket.getLocalPort(); + } + + /** + * The local address to which the server is bound. + * + * @return The local address to which the server is bound. + * @exception IllegalStateException is thrown if the server is not + * started. + */ + @Override + public final synchronized InetAddress getAddress() { + if (!started) { + throw new IllegalStateException("Not started"); + } + return serverSocket.getInetAddress(); + } + + /** + * Tells whether the server is started. + * + * @return true if the server is started. + */ + public final synchronized boolean isStarted() { + return started; + } + + /** + * Creates a new server socket. + * + * @param port local port to bind to. + * @param backlog requested maximum length of the queue of incoming + * connections. + * @param address local address to bind to. + * @return a new bound server socket ready to accept connections. + * @throws IOException if the socket cannot be created or bound. + */ + protected ServerSocket newServerSocket(int port, int backlog, + InetAddress address) + throws IOException { + return new ServerSocket(port, backlog, address); + } + + /** + * Starts listening for connections. + * + * @throws IOException if the server socket cannot be created or bound. + */ + public final synchronized void start() throws IOException { + if (started) { + return; + } + final ServerSocket socket = + newServerSocket(0, 100, InetAddress.getLocalHost()); + serverSocket = socket; + acceptThread = new Thread(this); + acceptThread.setDaemon(true); + acceptThread.start(); + started = true; + } + + /** + * Calls {@code Thread.sleep(linger);} + */ + protected final void lingerIfRequired() { + if (linger > 0) { + try { + Thread.sleep(linger); + } catch (InterruptedException x) { + Thread.interrupted(); + final ServerSocket socket = serverSocket(); + if (socket != null && !socket.isClosed()) { + System.err.println("Thread interrupted..."); + } + } + } + } + + final synchronized ServerSocket serverSocket() { + return this.serverSocket; + } + + /** + * The main accept loop. + */ + @Override + public final void run() { + final ServerSocket sSocket = serverSocket(); + try { + Socket s; + while (isStarted() && !Thread.interrupted() + && (s = sSocket.accept()) != null) { + lingerIfRequired(); + listen(s); + } + } catch (Exception x) { + error = x; + } finally { + synchronized (this) { + if (!sSocket.isClosed()) { + try { + sSocket.close(); + } catch (IOException x) { + System.err.println("Failed to close server socket"); + } + } + if (started && this.serverSocket == sSocket) { + started = false; + this.serverSocket = null; + this.acceptThread = null; + } + } + } + } + + /** + * Represents a connection accepted by the server. + */ + protected abstract class TcpConnectionThread extends Thread { + + protected final Socket socket; + + protected TcpConnectionThread(Socket socket) { + this.socket = socket; + this.setDaemon(true); + } + + public void close() throws IOException { + socket.close(); + interrupt(); + } + } + + /** + * Creates a new TcpConnnectionThread to handle the connection through + * an accepted socket. + * + * @param s the socket returned by {@code serverSocket.accept()}. + * @return a new TcpConnnectionThread to handle the connection through + * an accepted socket. + */ + protected abstract TcpConnectionThread createConnection(Socket s); + + /** + * Creates and starts a new TcpConnectionThread to handle the accepted + * socket. + * + * @param s the socket returned by {@code serverSocket.accept()}. + */ + private synchronized void listen(Socket s) { + TcpConnectionThread c = createConnection(s); + c.start(); + addConnection(c); + } + + /** + * Add the connection to the list of accepted connections. + * + * @param connection an accepted connection. + */ + protected synchronized void addConnection( + TcpConnectionThread connection) { + connections.add(connection); + } + + /** + * Remove the connection from the list of accepted connections. + * + * @param connection an accepted connection. + */ + protected synchronized void removeConnection( + TcpConnectionThread connection) { + connections.remove(connection); + } + + /** + * Close the server socket and all the connections present in the list + * of accepted connections. + * + * @throws IOException + */ + @Override + public synchronized void close() throws IOException { + if (serverSocket != null && !serverSocket.isClosed()) { + serverSocket.close(); + } + if (acceptThread != null) { + acceptThread.interrupt(); + } + int failed = 0; + for (TcpConnectionThread c : connections) { + try { + c.close(); + } catch (IOException x) { + // no matter - we're closing. + failed++; + } + } + connections.clear(); + if (failed > 0) { + throw new IOException("Failed to close some connections"); + } + } + } + + /** + * A small TCP Server that emulates the echo service for tests purposes. See + * http://en.wikipedia.org/wiki/Echo_Protocol This server uses an anonymous + * port - NOT the standard port 7. We don't guarantee that its behavior + * exactly matches the RFC - the only purpose of this server is to have + * something that responds to nio tests... + */ + static final class EchoServer extends AbstractTcpServer { + + public EchoServer() { + this(0L); + } + + public EchoServer(long linger) { + super(linger); + } + + @Override + protected TcpConnectionThread createConnection(Socket s) { + return new EchoConnection(s); + } + + private final class EchoConnection extends TcpConnectionThread { + + public EchoConnection(Socket socket) { + super(socket); + } + + @Override + public void run() { + try { + final InputStream is = socket.getInputStream(); + final OutputStream out = socket.getOutputStream(); + byte[] b = new byte[255]; + int n; + while ((n = is.read(b)) > 0) { + lingerIfRequired(); + out.write(b, 0, n); + } + } catch (IOException io) { + // fall through to finally + } finally { + if (!socket.isClosed()) { + try { + socket.close(); + } catch (IOException x) { + System.err.println( + "Failed to close echo connection socket"); + } + } + removeConnection(this); + } + } + } + + public static EchoServer startNewServer() throws IOException { + return startNewServer(0); + } + + public static EchoServer startNewServer(long linger) throws IOException { + final EchoServer echoServer = new EchoServer(linger); + echoServer.start(); + return echoServer; + } + } + + /** + * A small TCP server that emulates the Day & Time service for tests + * purposes. See http://en.wikipedia.org/wiki/Daytime_Protocol This server + * uses an anonymous port - NOT the standard port 13. We don't guarantee + * that its behavior exactly matches the RFC - the only purpose of this + * server is to have something that responds to nio tests... + */ + static final class DayTimeServer extends AbstractTcpServer { + + public DayTimeServer() { + this(0L); + } + + public DayTimeServer(long linger) { + super(linger); + } + + @Override + protected TcpConnectionThread createConnection(Socket s) { + return new DayTimeServerConnection(s); + } + + @Override + protected void addConnection(TcpConnectionThread connection) { + // do nothing - the connection just write the date and terminates. + } + + @Override + protected void removeConnection(TcpConnectionThread connection) { + // do nothing - we're not adding connections to the list... + } + + private final class DayTimeServerConnection extends TcpConnectionThread { + + public DayTimeServerConnection(Socket socket) { + super(socket); + } + + @Override + public void run() { + try { + final OutputStream out = socket.getOutputStream(); + lingerIfRequired(); + out.write(new Date(System.currentTimeMillis()) + .toString().getBytes("US-ASCII")); + out.flush(); + } catch (IOException io) { + // fall through to finally + } finally { + if (!socket.isClosed()) { + try { + socket.close(); + } catch (IOException x) { + System.err.println( + "Failed to close echo connection socket"); + } + } + } + } + } + + public static DayTimeServer startNewServer() + throws IOException { + return startNewServer(0); + } + + public static DayTimeServer startNewServer(long linger) + throws IOException { + final DayTimeServer daytimeServer = new DayTimeServer(linger); + daytimeServer.start(); + return daytimeServer; + } + } + + /** + * An abstract class for implementing small UDP Servers for the nio tests + * purposes. Disclaimer: This is a naive implementation that uses the old + * networking APIs (not those from {@code java.nio.*}) and shamelessly + * extends/creates Threads instead of using an executor service. + */ + static abstract class AbstractUdpServer extends AbstractServer + implements Runnable, Closeable { + + protected final long linger; // #of ms to wait before responding + private Thread acceptThread; // thread waiting for packets + private DatagramSocket serverSocket; // the server socket + private boolean started = false; // whether the server is started + Throwable error = null; + + /** + * Creates a new abstract UDP server. + * + * @param linger the amount of time the server should wait before + * responding to requests. + */ + protected AbstractUdpServer(long linger) { + this.linger = linger; + } + + /** + * The local port to which the server is bound. + * + * @return The local port to which the server is bound. + * @exception IllegalStateException is thrown if the server is not + * started. + */ + @Override + public final synchronized int getPort() { + if (!started) { + throw new IllegalStateException("Not started"); + } + return serverSocket.getLocalPort(); + } + + /** + * The local address to which the server is bound. + * + * @return The local address to which the server is bound. + * @exception IllegalStateException is thrown if the server is not + * started. + */ + @Override + public final synchronized InetAddress getAddress() { + if (!started) { + throw new IllegalStateException("Not started"); + } + return serverSocket.getLocalAddress(); + } + + /** + * Tells whether the server is started. + * + * @return true if the server is started. + */ + public final synchronized boolean isStarted() { + return started; + } + + /** + * Creates a new datagram socket. + * + * @param port local port to bind to. + * @param address local address to bind to. + * @return a new bound server socket ready to listen for packets. + * @throws IOException if the socket cannot be created or bound. + */ + protected DatagramSocket newDatagramSocket(int port, + InetAddress address) + throws IOException { + return new DatagramSocket(port, address); + } + + /** + * Starts listening for connections. + * + * @throws IOException if the server socket cannot be created or bound. + */ + public final synchronized void start() throws IOException { + if (started) { + return; + } + final DatagramSocket socket = + newDatagramSocket(0, InetAddress.getLocalHost()); + serverSocket = socket; + acceptThread = new Thread(this); + acceptThread.setDaemon(true); + acceptThread.start(); + started = true; + } + + /** + * Calls {@code Thread.sleep(linger);} + */ + protected final void lingerIfRequired() { + if (linger > 0) { + try { + Thread.sleep(linger); + } catch (InterruptedException x) { + Thread.interrupted(); + final DatagramSocket socket = serverSocket(); + if (socket != null && !socket.isClosed()) { + System.err.println("Thread interrupted..."); + } + } + } + } + + final synchronized DatagramSocket serverSocket() { + return this.serverSocket; + } + + final synchronized boolean send(DatagramSocket socket, + DatagramPacket response) throws IOException { + if (!socket.isClosed()) { + socket.send(response); + return true; + } else { + return false; + } + } + + /** + * The main receive loop. + */ + @Override + public final void run() { + final DatagramSocket sSocket = serverSocket(); + try { + final int size = Math.max(1024, sSocket.getReceiveBufferSize()); + if (size > sSocket.getReceiveBufferSize()) { + sSocket.setReceiveBufferSize(size); + } + while (isStarted() && !Thread.interrupted() && !sSocket.isClosed()) { + final byte[] buf = new byte[size]; + final DatagramPacket packet = + new DatagramPacket(buf, buf.length); + lingerIfRequired(); + sSocket.receive(packet); + //System.out.println("Received packet from: " + // + packet.getAddress()+":"+packet.getPort()); + handle(sSocket, packet); + } + } catch (Exception x) { + error = x; + } finally { + synchronized (this) { + if (!sSocket.isClosed()) { + sSocket.close(); + } + if (started && this.serverSocket == sSocket) { + started = false; + this.serverSocket = null; + this.acceptThread = null; + } + } + } + } + + /** + * Represents an UDP request received by the server. + */ + protected abstract class UdpRequestThread extends Thread { + + protected final DatagramPacket request; + protected final DatagramSocket socket; + + protected UdpRequestThread(DatagramSocket socket, DatagramPacket request) { + this.socket = socket; + this.request = request; + this.setDaemon(true); + } + } + + /** + * Creates a new UdpRequestThread to handle a DatagramPacket received + * through a DatagramSocket. + * + * @param socket the socket through which the request was received. + * @param request the datagram packet received through the socket. + * @return a new UdpRequestThread to handle the request received through + * a DatagramSocket. + */ + protected abstract UdpRequestThread createConnection(DatagramSocket socket, + DatagramPacket request); + + /** + * Creates and starts a new UdpRequestThread to handle the received + * datagram packet. + * + * @param socket the socket through which the request was received. + * @param request the datagram packet received through the socket. + */ + private synchronized void handle(DatagramSocket socket, + DatagramPacket request) { + UdpRequestThread c = createConnection(socket, request); + // c can be null if the request requires no response. + if (c != null) { + c.start(); + } + } + + /** + * Close the server socket. + * + * @throws IOException + */ + @Override + public synchronized void close() throws IOException { + if (serverSocket != null && !serverSocket.isClosed()) { + serverSocket.close(); + } + if (acceptThread != null) { + acceptThread.interrupt(); + } + } + } + + /** + * A small UDP Server that emulates the discard service for tests purposes. + * See http://en.wikipedia.org/wiki/Discard_Protocol This server uses an + * anonymous port - NOT the standard port 9. We don't guarantee that its + * behavior exactly matches the RFC - the only purpose of this server is to + * have something that responds to nio tests... + */ + static final class UdpDiscardServer extends AbstractUdpServer { + + public UdpDiscardServer() { + this(0L); + } + + public UdpDiscardServer(long linger) { + super(linger); + } + + @Override + protected UdpRequestThread createConnection(DatagramSocket socket, + DatagramPacket request) { + // no response required + return null; + } + + public static UdpDiscardServer startNewServer() throws IOException { + return startNewServer(0); + } + + public static UdpDiscardServer startNewServer(long linger) throws IOException { + final UdpDiscardServer discardServer = new UdpDiscardServer(linger); + discardServer.start(); + return discardServer; + } + } + + /** + * A small UDP Server that emulates the echo service for tests purposes. See + * http://en.wikipedia.org/wiki/Echo_Protocol This server uses an anonymous + * port - NOT the standard port 7. We don't guarantee that its behavior + * exactly matches the RFC - the only purpose of this server is to have + * something that responds to nio tests... + */ + static final class UdpEchoServer extends AbstractUdpServer { + + public UdpEchoServer() { + this(0L); + } + + public UdpEchoServer(long linger) { + super(linger); + } + + @Override + protected UdpEchoRequest createConnection(DatagramSocket socket, + DatagramPacket request) { + return new UdpEchoRequest(socket, request); + } + + private final class UdpEchoRequest extends UdpRequestThread { + + public UdpEchoRequest(DatagramSocket socket, DatagramPacket request) { + super(socket, request); + } + + @Override + public void run() { + try { + lingerIfRequired(); + final DatagramPacket response = + new DatagramPacket(request.getData(), + request.getOffset(), request.getLength(), + request.getAddress(), request.getPort()); + send(socket, response); + } catch (IOException io) { + System.err.println("Failed to send response: " + io); + io.printStackTrace(System.err); + } + } + } + + public static UdpEchoServer startNewServer() throws IOException { + return startNewServer(0); + } + + public static UdpEchoServer startNewServer(long linger) throws IOException { + final UdpEchoServer echoServer = new UdpEchoServer(linger); + echoServer.start(); + return echoServer; + } + } + + /** + * A small UDP server that emulates the Day & Time service for tests + * purposes. See http://en.wikipedia.org/wiki/Daytime_Protocol This server + * uses an anonymous port - NOT the standard port 13. We don't guarantee + * that its behavior exactly matches the RFC - the only purpose of this + * server is to have something that responds to nio tests... + */ + static final class UdpDayTimeServer extends AbstractUdpServer { + + public UdpDayTimeServer() { + this(0L); + } + + public UdpDayTimeServer(long linger) { + super(linger); + } + + @Override + protected UdpDayTimeRequestThread createConnection(DatagramSocket socket, + DatagramPacket request) { + return new UdpDayTimeRequestThread(socket, request); + } + + private final class UdpDayTimeRequestThread extends UdpRequestThread { + + public UdpDayTimeRequestThread(DatagramSocket socket, + DatagramPacket request) { + super(socket, request); + } + + @Override + public void run() { + try { + lingerIfRequired(); + final byte[] data = new Date(System.currentTimeMillis()) + .toString().getBytes("US-ASCII"); + final DatagramPacket response = + new DatagramPacket(data, 0, data.length, + request.getAddress(), request.getPort()); + send(socket, response); + } catch (IOException io) { + System.err.println("Failed to send response: " + io); + io.printStackTrace(System.err); + } + } + } + + public static UdpDayTimeServer startNewServer() throws IOException { + return startNewServer(0); + } + + public static UdpDayTimeServer startNewServer(long linger) + throws IOException { + final UdpDayTimeServer echoServer = new UdpDayTimeServer(linger); + echoServer.start(); + return echoServer; + } + } }