1a9a57f2581773484d13e160fd3407692e825971aElliott Hughes/*
2a9a57f2581773484d13e160fd3407692e825971aElliott Hughes * Copyright (C) 2009 The Android Open Source Project
3f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes *
4a9a57f2581773484d13e160fd3407692e825971aElliott Hughes * Licensed under the Apache License, Version 2.0 (the "License");
5a9a57f2581773484d13e160fd3407692e825971aElliott Hughes * you may not use this file except in compliance with the License.
6a9a57f2581773484d13e160fd3407692e825971aElliott Hughes * You may obtain a copy of the License at
7f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes *
8a9a57f2581773484d13e160fd3407692e825971aElliott Hughes *      http://www.apache.org/licenses/LICENSE-2.0
9f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes *
10a9a57f2581773484d13e160fd3407692e825971aElliott Hughes * Unless required by applicable law or agreed to in writing, software
11a9a57f2581773484d13e160fd3407692e825971aElliott Hughes * distributed under the License is distributed on an "AS IS" BASIS,
12a9a57f2581773484d13e160fd3407692e825971aElliott Hughes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13a9a57f2581773484d13e160fd3407692e825971aElliott Hughes * See the License for the specific language governing permissions and
14a9a57f2581773484d13e160fd3407692e825971aElliott Hughes * limitations under the License.
15a9a57f2581773484d13e160fd3407692e825971aElliott Hughes */
16a9a57f2581773484d13e160fd3407692e825971aElliott Hughes
174557728efb66c455a52b7669a8eefef7a9e54854Jesse Wilsonpackage libcore.java.net;
18a9a57f2581773484d13e160fd3407692e825971aElliott Hughes
190371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughesimport java.io.IOException;
200371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughesimport java.io.InputStream;
210371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughesimport java.io.OutputStream;
224557728efb66c455a52b7669a8eefef7a9e54854Jesse Wilsonimport java.net.ConnectException;
234557728efb66c455a52b7669a8eefef7a9e54854Jesse Wilsonimport java.net.InetAddress;
244557728efb66c455a52b7669a8eefef7a9e54854Jesse Wilsonimport java.net.InetSocketAddress;
254557728efb66c455a52b7669a8eefef7a9e54854Jesse Wilsonimport java.net.ServerSocket;
264557728efb66c455a52b7669a8eefef7a9e54854Jesse Wilsonimport java.net.Socket;
274557728efb66c455a52b7669a8eefef7a9e54854Jesse Wilsonimport java.net.SocketAddress;
284557728efb66c455a52b7669a8eefef7a9e54854Jesse Wilsonimport java.net.SocketException;
294557728efb66c455a52b7669a8eefef7a9e54854Jesse Wilsonimport java.net.SocketImpl;
308cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughesimport java.nio.channels.ServerSocketChannel;
318cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughesimport java.nio.channels.SocketChannel;
32ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilsonimport java.util.concurrent.Callable;
33ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilsonimport java.util.concurrent.ExecutorService;
34ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilsonimport java.util.concurrent.Executors;
35ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilsonimport java.util.concurrent.Future;
368cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes
37a9a57f2581773484d13e160fd3407692e825971aElliott Hughespublic class SocketTest extends junit.framework.TestCase {
38c390acc2461cce9edb3209caca28d95ed6aabd90Elliott Hughes    // See http://b/2980559.
39c390acc2461cce9edb3209caca28d95ed6aabd90Elliott Hughes    public void test_close() throws Exception {
40c390acc2461cce9edb3209caca28d95ed6aabd90Elliott Hughes        Socket s = new Socket();
41c390acc2461cce9edb3209caca28d95ed6aabd90Elliott Hughes        s.close();
42c390acc2461cce9edb3209caca28d95ed6aabd90Elliott Hughes        // Closing a closed socket does nothing.
43c390acc2461cce9edb3209caca28d95ed6aabd90Elliott Hughes        s.close();
44c390acc2461cce9edb3209caca28d95ed6aabd90Elliott Hughes    }
45c390acc2461cce9edb3209caca28d95ed6aabd90Elliott Hughes
46a9a57f2581773484d13e160fd3407692e825971aElliott Hughes    /**
47a9a57f2581773484d13e160fd3407692e825971aElliott Hughes     * Our getLocalAddress and getLocalPort currently use getsockname(3).
48a9a57f2581773484d13e160fd3407692e825971aElliott Hughes     * This means they give incorrect results on closed sockets (as well
49a9a57f2581773484d13e160fd3407692e825971aElliott Hughes     * as requiring an unnecessary call into native code).
50a9a57f2581773484d13e160fd3407692e825971aElliott Hughes     */
51a9a57f2581773484d13e160fd3407692e825971aElliott Hughes    public void test_getLocalAddress_after_close() throws Exception {
52a9a57f2581773484d13e160fd3407692e825971aElliott Hughes        Socket s = new Socket();
53a9a57f2581773484d13e160fd3407692e825971aElliott Hughes        try {
54a9a57f2581773484d13e160fd3407692e825971aElliott Hughes            // Bind to an ephemeral local port.
55a9a57f2581773484d13e160fd3407692e825971aElliott Hughes            s.bind(new InetSocketAddress("localhost", 0));
56da15009528cc8300a6251f1d0931ac8657c9fc31Elliott Hughes            assertTrue(s.getLocalAddress().toString(), s.getLocalAddress().isLoopbackAddress());
57a9a57f2581773484d13e160fd3407692e825971aElliott Hughes            // What local port did we get?
58a9a57f2581773484d13e160fd3407692e825971aElliott Hughes            int localPort = s.getLocalPort();
59a9a57f2581773484d13e160fd3407692e825971aElliott Hughes            assertTrue(localPort > 0);
60a9a57f2581773484d13e160fd3407692e825971aElliott Hughes            // Now close the socket...
61a9a57f2581773484d13e160fd3407692e825971aElliott Hughes            s.close();
62a9a57f2581773484d13e160fd3407692e825971aElliott Hughes            // The RI returns the ANY address but the original local port after close.
63a9a57f2581773484d13e160fd3407692e825971aElliott Hughes            assertTrue(s.getLocalAddress().isAnyLocalAddress());
64a9a57f2581773484d13e160fd3407692e825971aElliott Hughes            assertEquals(localPort, s.getLocalPort());
65a9a57f2581773484d13e160fd3407692e825971aElliott Hughes        } finally {
66a9a57f2581773484d13e160fd3407692e825971aElliott Hughes            s.close();
67a9a57f2581773484d13e160fd3407692e825971aElliott Hughes        }
68a9a57f2581773484d13e160fd3407692e825971aElliott Hughes    }
69ad4718b11db66d197b14cd0ec3ed17905bbedd34Elliott Hughes
70ad4718b11db66d197b14cd0ec3ed17905bbedd34Elliott Hughes    // http://code.google.com/p/android/issues/detail?id=7935
71ad4718b11db66d197b14cd0ec3ed17905bbedd34Elliott Hughes    public void test_newSocket_connection_refused() throws Exception {
72ad4718b11db66d197b14cd0ec3ed17905bbedd34Elliott Hughes        try {
73ad4718b11db66d197b14cd0ec3ed17905bbedd34Elliott Hughes            new Socket("localhost", 80);
74ad4718b11db66d197b14cd0ec3ed17905bbedd34Elliott Hughes            fail("connection should have been refused");
75ad4718b11db66d197b14cd0ec3ed17905bbedd34Elliott Hughes        } catch (ConnectException expected) {
76ad4718b11db66d197b14cd0ec3ed17905bbedd34Elliott Hughes        }
77ad4718b11db66d197b14cd0ec3ed17905bbedd34Elliott Hughes    }
788cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes
798cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes    // http://code.google.com/p/android/issues/detail?id=3123
808cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes    // http://code.google.com/p/android/issues/detail?id=1933
818cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes    public void test_socketLocalAndRemoteAddresses() throws Exception {
828cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        checkSocketLocalAndRemoteAddresses(false);
838cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        checkSocketLocalAndRemoteAddresses(true);
848cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes    }
858cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes
868cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes    public void checkSocketLocalAndRemoteAddresses(boolean setOptions) throws Exception {
878cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        InetAddress host = InetAddress.getLocalHost();
888cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes
898cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        // Open a local server port.
908cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        ServerSocketChannel ssc = ServerSocketChannel.open();
918cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        InetSocketAddress listenAddr = new InetSocketAddress(host, 0);
928cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        ssc.socket().bind(listenAddr, 0);
938cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        ServerSocket ss = ssc.socket();
948cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes
958cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        // Open a socket to the local port.
968cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        SocketChannel out = SocketChannel.open();
978cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        out.configureBlocking(false);
988cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        if (setOptions) {
998cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes            out.socket().setTcpNoDelay(false);
1008cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        }
1018cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        InetSocketAddress addr = new InetSocketAddress(host, ssc.socket().getLocalPort());
1028cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        out.connect(addr);
1038cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        while (!out.finishConnect()) {
1048cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes            Thread.sleep(1);
1058cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        }
1068cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes
1078cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        SocketChannel in = ssc.accept();
1088cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        if (setOptions) {
1098cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes            in.socket().setTcpNoDelay(false);
1108cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        }
1118cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes
1128cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        InetSocketAddress outRemoteAddress = (InetSocketAddress) out.socket().getRemoteSocketAddress();
1138cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        InetSocketAddress outLocalAddress = (InetSocketAddress) out.socket().getLocalSocketAddress();
1148cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        InetSocketAddress inLocalAddress = (InetSocketAddress) in.socket().getLocalSocketAddress();
1158cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        InetSocketAddress inRemoteAddress = (InetSocketAddress) in.socket().getRemoteSocketAddress();
1168cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        System.err.println("inLocalAddress: " + inLocalAddress);
1178cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        System.err.println("inRemoteAddress: " + inRemoteAddress);
1188cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        System.err.println("outLocalAddress: " + outLocalAddress);
1198cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        System.err.println("outRemoteAddress: " + outRemoteAddress);
1208cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes
1218cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        assertEquals(outRemoteAddress.getPort(), ss.getLocalPort());
1228cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        assertEquals(inLocalAddress.getPort(), ss.getLocalPort());
1238cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        assertEquals(inRemoteAddress.getPort(), outLocalAddress.getPort());
1248cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes
1258cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        assertEquals(inLocalAddress.getAddress(), ss.getInetAddress());
1268cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        assertEquals(inRemoteAddress.getAddress(), ss.getInetAddress());
1278cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        assertEquals(outLocalAddress.getAddress(), ss.getInetAddress());
1288cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        assertEquals(outRemoteAddress.getAddress(), ss.getInetAddress());
1298cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes
1308cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        in.close();
1318cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        out.close();
1328cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        ssc.close();
1338cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes
1348cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        assertNull(in.socket().getRemoteSocketAddress());
1358cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        assertNull(out.socket().getRemoteSocketAddress());
1368cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes
1378cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        assertEquals(in.socket().getLocalSocketAddress(), ss.getLocalSocketAddress());
1388cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes    }
1390371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes
1400371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes    // SocketOptions.setOption has weird behavior for setSoLinger/SO_LINGER.
1410371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes    // This test ensures we do what the RI does.
1420371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes    public void test_SocketOptions_setOption() throws Exception {
1430371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes        class MySocketImpl extends SocketImpl {
1440371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes            public int option;
1450371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes            public Object value;
1460371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes
1470371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes            public boolean createCalled;
1480371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes            public boolean createStream;
1490371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes
1500371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes            public MySocketImpl() { super(); }
1510371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes            @Override protected void accept(SocketImpl arg0) throws IOException { }
1520371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes            @Override protected int available() throws IOException { return 0; }
1530371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes            @Override protected void bind(InetAddress arg0, int arg1) throws IOException { }
1540371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes            @Override protected void close() throws IOException { }
1550371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes            @Override protected void connect(String arg0, int arg1) throws IOException { }
1560371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes            @Override protected void connect(InetAddress arg0, int arg1) throws IOException { }
1570371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes            @Override protected void connect(SocketAddress arg0, int arg1) throws IOException { }
1580371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes            @Override protected InputStream getInputStream() throws IOException { return null; }
1590371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes            @Override protected OutputStream getOutputStream() throws IOException { return null; }
1600371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes            @Override protected void listen(int arg0) throws IOException { }
1610371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes            @Override protected void sendUrgentData(int arg0) throws IOException { }
1620371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes            public Object getOption(int arg0) throws SocketException { return null; }
1630371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes
1640371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes            @Override protected void create(boolean isStream) throws IOException {
1650371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes                this.createCalled = true;
1660371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes                this.createStream = isStream;
1670371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes            }
1680371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes
1690371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes            public void setOption(int option, Object value) throws SocketException {
1700371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes                this.option = option;
1710371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes                this.value = value;
1720371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes            }
1730371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes        }
1740371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes
1750371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes        class MySocket extends Socket {
1760371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes            public MySocket(SocketImpl impl) throws SocketException {
1770371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes                super(impl);
1780371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes            }
1790371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes        }
1800371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes
1810371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes        MySocketImpl impl = new MySocketImpl();
1820371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes        Socket s = new MySocket(impl);
1830371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes
1840371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes        // Check that, as per the SocketOptions.setOption documentation, we pass false rather
1850371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes        // than -1 to the SocketImpl when setSoLinger is called with the first argument false.
1860371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes        s.setSoLinger(false, -1);
1870371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes        assertEquals(Boolean.FALSE, (Boolean) impl.value);
1880371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes        // We also check that SocketImpl.create was called. SocketChannelImpl.SocketAdapter
1890371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes        // subclasses Socket, and whether or not to call SocketImpl.create is the main behavioral
1900371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes        // difference.
1910371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes        assertEquals(true, impl.createCalled);
1920371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes        s.setSoLinger(false, 0);
1930371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes        assertEquals(Boolean.FALSE, (Boolean) impl.value);
1940371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes        s.setSoLinger(false, 1);
1950371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes        assertEquals(Boolean.FALSE, (Boolean) impl.value);
1960371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes
1970371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes        // Check that otherwise, we pass down an Integer.
1980371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes        s.setSoLinger(true, 0);
1990371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes        assertEquals(Integer.valueOf(0), (Integer) impl.value);
2000371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes        s.setSoLinger(true, 1);
2010371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes        assertEquals(Integer.valueOf(1), (Integer) impl.value);
2020371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes    }
2030371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes
2040371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes    public void test_setTrafficClass() throws Exception {
2050371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes        Socket s = new Socket();
2060371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes        s.setTrafficClass(123);
2070371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes        assertEquals(123, s.getTrafficClass());
2080371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes    }
209ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson
210ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson    public void testReadAfterClose() throws Exception {
211ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        MockServer server = new MockServer();
212ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        server.enqueue(new byte[]{5, 3}, 0);
213ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        Socket socket = new Socket("localhost", server.port);
214ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        InputStream in = socket.getInputStream();
215ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        assertEquals(5, in.read());
216ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        assertEquals(3, in.read());
217ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        assertEquals(-1, in.read());
218ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        assertEquals(-1, in.read());
219ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        socket.close();
220ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        in.close();
221ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson
222ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        /*
223ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson         * Rather astonishingly, read() doesn't throw even though the stream is
224ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson         * closed. This is consistent with the RI's behavior.
225ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson         */
226ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        assertEquals(-1, in.read());
227ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        assertEquals(-1, in.read());
228ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson
229ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        server.shutdown();
230ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson    }
231ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson
232ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson    public void testWriteAfterClose() throws Exception {
233ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        MockServer server = new MockServer();
234ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        server.enqueue(new byte[0], 3);
235ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        Socket socket = new Socket("localhost", server.port);
236ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        OutputStream out = socket.getOutputStream();
237ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        out.write(5);
238ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        out.write(3);
239ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        socket.close();
240ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        out.close();
241ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson
242ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        try {
243ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson            out.write(9);
244ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson            fail();
245ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        } catch (IOException expected) {
246ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        }
247ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson
248ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        server.shutdown();
249ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson    }
250ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson
251b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson    // http://b/5534202
252b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson    public void testAvailable() throws Exception {
253b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson        for (int i = 0; i < 100; i++) {
254b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson            assertAvailableReturnsZeroAfterSocketReadsAllData();
255b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson            System.out.println("Success on rep " + i);
256b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson        }
257b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson    }
258b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson
259b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson    private void assertAvailableReturnsZeroAfterSocketReadsAllData() throws Exception {
260b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson        final byte[] data = "foo".getBytes();
261b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson        final ServerSocket serverSocket = new ServerSocket(0);
262b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson
263b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson        new Thread() {
264b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson            @Override public void run() {
265b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson                try {
266b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson                    Socket socket = serverSocket.accept();
267b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson                    socket.getOutputStream().write(data);
268b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson                    socket.close();
269b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson                } catch (IOException e) {
270b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson                    e.printStackTrace();
271b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson                }
272b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson            }
273b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson        }.start();
274b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson
275b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson        Socket socket = new Socket("localhost", serverSocket.getLocalPort());
276b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson        byte[] readBuffer = new byte[128];
277b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson        InputStream in = socket.getInputStream();
278b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson        int total = 0;
279b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson        // to prevent available() from cheating after EOF, stop reading before -1 is returned
280b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson        while (total < data.length) {
281b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson            total += in.read(readBuffer);
282b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson        }
283b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson        assertEquals(0, in.available());
284b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson
285b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson        socket.close();
286b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson        serverSocket.close();
287b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson    }
288b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson
289ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson    static class MockServer {
290ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        private ExecutorService executor;
291ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        private ServerSocket serverSocket;
292ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        private int port = -1;
293ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson
294ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        MockServer() throws IOException {
295ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson            executor = Executors.newCachedThreadPool();
296ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson            serverSocket = new ServerSocket(0);
297ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson            serverSocket.setReuseAddress(true);
298ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson            port = serverSocket.getLocalPort();
299ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        }
300ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson
301ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        public Future<byte[]> enqueue(final byte[] sendBytes, final int receiveByteCount)
302ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson                throws IOException {
303ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson            return executor.submit(new Callable<byte[]>() {
304ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson                @Override public byte[] call() throws Exception {
305ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson                    Socket socket = serverSocket.accept();
306ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson                    OutputStream out = socket.getOutputStream();
307ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson                    out.write(sendBytes);
308ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson
309ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson                    InputStream in = socket.getInputStream();
310ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson                    byte[] result = new byte[receiveByteCount];
311ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson                    int total = 0;
312ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson                    while (total < receiveByteCount) {
313ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson                        total += in.read(result, total, result.length - total);
314ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson                    }
315ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson                    socket.close();
316ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson                    return result;
317ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson                }
318ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson            });
319ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        }
320ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson
321ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        public void shutdown() throws IOException {
322ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson            serverSocket.close();
323ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson            executor.shutdown();
324ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        }
325ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson    }
326a9a57f2581773484d13e160fd3407692e825971aElliott Hughes}
327