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;
2347ae0b5a1d96c8030e0963ccc5b44c3ee66aaec3Neil Fullerimport java.net.Inet4Address;
244557728efb66c455a52b7669a8eefef7a9e54854Jesse Wilsonimport java.net.InetAddress;
254557728efb66c455a52b7669a8eefef7a9e54854Jesse Wilsonimport java.net.InetSocketAddress;
264557728efb66c455a52b7669a8eefef7a9e54854Jesse Wilsonimport java.net.ServerSocket;
274557728efb66c455a52b7669a8eefef7a9e54854Jesse Wilsonimport java.net.Socket;
284557728efb66c455a52b7669a8eefef7a9e54854Jesse Wilsonimport java.net.SocketAddress;
294557728efb66c455a52b7669a8eefef7a9e54854Jesse Wilsonimport java.net.SocketException;
304557728efb66c455a52b7669a8eefef7a9e54854Jesse Wilsonimport java.net.SocketImpl;
318cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughesimport java.nio.channels.ServerSocketChannel;
328cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughesimport java.nio.channels.SocketChannel;
33ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilsonimport java.util.concurrent.Callable;
34d4348724908290a8c09918a35587f1f6836c08efNeil Fullerimport java.util.concurrent.CountDownLatch;
35ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilsonimport java.util.concurrent.ExecutorService;
36ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilsonimport java.util.concurrent.Executors;
37ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilsonimport java.util.concurrent.Future;
38d4348724908290a8c09918a35587f1f6836c08efNeil Fullerimport java.util.concurrent.TimeUnit;
398cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes
40a9a57f2581773484d13e160fd3407692e825971aElliott Hughespublic class SocketTest extends junit.framework.TestCase {
41c390acc2461cce9edb3209caca28d95ed6aabd90Elliott Hughes    // See http://b/2980559.
42c390acc2461cce9edb3209caca28d95ed6aabd90Elliott Hughes    public void test_close() throws Exception {
43c390acc2461cce9edb3209caca28d95ed6aabd90Elliott Hughes        Socket s = new Socket();
44c390acc2461cce9edb3209caca28d95ed6aabd90Elliott Hughes        s.close();
45c390acc2461cce9edb3209caca28d95ed6aabd90Elliott Hughes        // Closing a closed socket does nothing.
46c390acc2461cce9edb3209caca28d95ed6aabd90Elliott Hughes        s.close();
47c390acc2461cce9edb3209caca28d95ed6aabd90Elliott Hughes    }
48c390acc2461cce9edb3209caca28d95ed6aabd90Elliott Hughes
49a9a57f2581773484d13e160fd3407692e825971aElliott Hughes    /**
50a9a57f2581773484d13e160fd3407692e825971aElliott Hughes     * Our getLocalAddress and getLocalPort currently use getsockname(3).
51a9a57f2581773484d13e160fd3407692e825971aElliott Hughes     * This means they give incorrect results on closed sockets (as well
52a9a57f2581773484d13e160fd3407692e825971aElliott Hughes     * as requiring an unnecessary call into native code).
53a9a57f2581773484d13e160fd3407692e825971aElliott Hughes     */
54a9a57f2581773484d13e160fd3407692e825971aElliott Hughes    public void test_getLocalAddress_after_close() throws Exception {
55a9a57f2581773484d13e160fd3407692e825971aElliott Hughes        Socket s = new Socket();
56a9a57f2581773484d13e160fd3407692e825971aElliott Hughes        try {
57a9a57f2581773484d13e160fd3407692e825971aElliott Hughes            // Bind to an ephemeral local port.
58a9a57f2581773484d13e160fd3407692e825971aElliott Hughes            s.bind(new InetSocketAddress("localhost", 0));
59da15009528cc8300a6251f1d0931ac8657c9fc31Elliott Hughes            assertTrue(s.getLocalAddress().toString(), s.getLocalAddress().isLoopbackAddress());
60a9a57f2581773484d13e160fd3407692e825971aElliott Hughes            // What local port did we get?
61a9a57f2581773484d13e160fd3407692e825971aElliott Hughes            int localPort = s.getLocalPort();
62a9a57f2581773484d13e160fd3407692e825971aElliott Hughes            assertTrue(localPort > 0);
63a9a57f2581773484d13e160fd3407692e825971aElliott Hughes            // Now close the socket...
64a9a57f2581773484d13e160fd3407692e825971aElliott Hughes            s.close();
65a9a57f2581773484d13e160fd3407692e825971aElliott Hughes            // The RI returns the ANY address but the original local port after close.
66a9a57f2581773484d13e160fd3407692e825971aElliott Hughes            assertTrue(s.getLocalAddress().isAnyLocalAddress());
67a9a57f2581773484d13e160fd3407692e825971aElliott Hughes            assertEquals(localPort, s.getLocalPort());
68a9a57f2581773484d13e160fd3407692e825971aElliott Hughes        } finally {
69a9a57f2581773484d13e160fd3407692e825971aElliott Hughes            s.close();
70a9a57f2581773484d13e160fd3407692e825971aElliott Hughes        }
71a9a57f2581773484d13e160fd3407692e825971aElliott Hughes    }
72ad4718b11db66d197b14cd0ec3ed17905bbedd34Elliott Hughes
73ad4718b11db66d197b14cd0ec3ed17905bbedd34Elliott Hughes    // http://code.google.com/p/android/issues/detail?id=7935
74ad4718b11db66d197b14cd0ec3ed17905bbedd34Elliott Hughes    public void test_newSocket_connection_refused() throws Exception {
75ad4718b11db66d197b14cd0ec3ed17905bbedd34Elliott Hughes        try {
76ad4718b11db66d197b14cd0ec3ed17905bbedd34Elliott Hughes            new Socket("localhost", 80);
77ad4718b11db66d197b14cd0ec3ed17905bbedd34Elliott Hughes            fail("connection should have been refused");
78ad4718b11db66d197b14cd0ec3ed17905bbedd34Elliott Hughes        } catch (ConnectException expected) {
79ad4718b11db66d197b14cd0ec3ed17905bbedd34Elliott Hughes        }
80ad4718b11db66d197b14cd0ec3ed17905bbedd34Elliott Hughes    }
818cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes
828cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes    // http://code.google.com/p/android/issues/detail?id=3123
838cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes    // http://code.google.com/p/android/issues/detail?id=1933
848cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes    public void test_socketLocalAndRemoteAddresses() throws Exception {
858cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        checkSocketLocalAndRemoteAddresses(false);
868cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        checkSocketLocalAndRemoteAddresses(true);
878cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes    }
888cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes
898cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes    public void checkSocketLocalAndRemoteAddresses(boolean setOptions) throws Exception {
908cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        InetAddress host = InetAddress.getLocalHost();
918cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes
928cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        // Open a local server port.
938cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        ServerSocketChannel ssc = ServerSocketChannel.open();
948cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        InetSocketAddress listenAddr = new InetSocketAddress(host, 0);
9563744c884dd4b4f4307f2b021fb894af164972afElliott Hughes        ssc.socket().bind(listenAddr, 0);
968cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        ServerSocket ss = ssc.socket();
978cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes
988cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        // Open a socket to the local port.
998cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        SocketChannel out = SocketChannel.open();
1008cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        out.configureBlocking(false);
1018cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        if (setOptions) {
1028cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes            out.socket().setTcpNoDelay(false);
1038cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        }
1048cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        InetSocketAddress addr = new InetSocketAddress(host, ssc.socket().getLocalPort());
1058cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        out.connect(addr);
1068cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        while (!out.finishConnect()) {
1078cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes            Thread.sleep(1);
1088cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        }
1098cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes
1108cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        SocketChannel in = ssc.accept();
1118cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        if (setOptions) {
1128cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes            in.socket().setTcpNoDelay(false);
1138cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        }
1148cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes
11563744c884dd4b4f4307f2b021fb894af164972afElliott Hughes        InetSocketAddress listenAddress = (InetSocketAddress) in.socket().getLocalSocketAddress();
1168cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        InetSocketAddress outRemoteAddress = (InetSocketAddress) out.socket().getRemoteSocketAddress();
1178cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        InetSocketAddress outLocalAddress = (InetSocketAddress) out.socket().getLocalSocketAddress();
1188cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        InetSocketAddress inLocalAddress = (InetSocketAddress) in.socket().getLocalSocketAddress();
1198cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        InetSocketAddress inRemoteAddress = (InetSocketAddress) in.socket().getRemoteSocketAddress();
12047ae0b5a1d96c8030e0963ccc5b44c3ee66aaec3Neil Fuller        System.err.println("listenAddress: " + listenAddr);
1218cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        System.err.println("inLocalAddress: " + inLocalAddress);
1228cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        System.err.println("inRemoteAddress: " + inRemoteAddress);
1238cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        System.err.println("outLocalAddress: " + outLocalAddress);
1248cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        System.err.println("outRemoteAddress: " + outRemoteAddress);
1258cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes
1268cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        assertEquals(outRemoteAddress.getPort(), ss.getLocalPort());
1278cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        assertEquals(inLocalAddress.getPort(), ss.getLocalPort());
1288cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        assertEquals(inRemoteAddress.getPort(), outLocalAddress.getPort());
1298cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes
1308cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        assertEquals(inLocalAddress.getAddress(), ss.getInetAddress());
1318cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        assertEquals(inRemoteAddress.getAddress(), ss.getInetAddress());
1328cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        assertEquals(outLocalAddress.getAddress(), ss.getInetAddress());
1338cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        assertEquals(outRemoteAddress.getAddress(), ss.getInetAddress());
1348cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes
13547ae0b5a1d96c8030e0963ccc5b44c3ee66aaec3Neil Fuller        assertFalse(ssc.socket().isClosed());
13647ae0b5a1d96c8030e0963ccc5b44c3ee66aaec3Neil Fuller        assertTrue(ssc.socket().isBound());
13747ae0b5a1d96c8030e0963ccc5b44c3ee66aaec3Neil Fuller        assertTrue(in.isConnected());
13847ae0b5a1d96c8030e0963ccc5b44c3ee66aaec3Neil Fuller        assertTrue(in.socket().isConnected());
13947ae0b5a1d96c8030e0963ccc5b44c3ee66aaec3Neil Fuller        assertTrue(out.socket().isConnected());
14047ae0b5a1d96c8030e0963ccc5b44c3ee66aaec3Neil Fuller        assertTrue(out.isConnected());
14147ae0b5a1d96c8030e0963ccc5b44c3ee66aaec3Neil Fuller
1428cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        in.close();
1438cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        out.close();
1448cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        ssc.close();
1458cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes
14647ae0b5a1d96c8030e0963ccc5b44c3ee66aaec3Neil Fuller        assertTrue(ssc.socket().isClosed());
14747ae0b5a1d96c8030e0963ccc5b44c3ee66aaec3Neil Fuller        assertTrue(ssc.socket().isBound());
14847ae0b5a1d96c8030e0963ccc5b44c3ee66aaec3Neil Fuller        assertFalse(in.isConnected());
14947ae0b5a1d96c8030e0963ccc5b44c3ee66aaec3Neil Fuller        assertFalse(in.socket().isConnected());
15047ae0b5a1d96c8030e0963ccc5b44c3ee66aaec3Neil Fuller        assertFalse(out.socket().isConnected());
15147ae0b5a1d96c8030e0963ccc5b44c3ee66aaec3Neil Fuller        assertFalse(out.isConnected());
15247ae0b5a1d96c8030e0963ccc5b44c3ee66aaec3Neil Fuller
1538cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        assertNull(in.socket().getRemoteSocketAddress());
1548cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        assertNull(out.socket().getRemoteSocketAddress());
1558cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes
15647ae0b5a1d96c8030e0963ccc5b44c3ee66aaec3Neil Fuller        // As per docs and RI - server socket local address methods continue to return the bind()
15747ae0b5a1d96c8030e0963ccc5b44c3ee66aaec3Neil Fuller        // addresses even after close().
15847ae0b5a1d96c8030e0963ccc5b44c3ee66aaec3Neil Fuller        assertEquals(listenAddress, ssc.socket().getLocalSocketAddress());
15947ae0b5a1d96c8030e0963ccc5b44c3ee66aaec3Neil Fuller
16047ae0b5a1d96c8030e0963ccc5b44c3ee66aaec3Neil Fuller        // As per docs and RI - socket local address methods return the wildcard address before
16147ae0b5a1d96c8030e0963ccc5b44c3ee66aaec3Neil Fuller        // bind() and after close(), but the port will be the same as it was before close().
16247ae0b5a1d96c8030e0963ccc5b44c3ee66aaec3Neil Fuller        InetSocketAddress inLocalAddressAfterClose =
16347ae0b5a1d96c8030e0963ccc5b44c3ee66aaec3Neil Fuller                (InetSocketAddress) in.socket().getLocalSocketAddress();
16447ae0b5a1d96c8030e0963ccc5b44c3ee66aaec3Neil Fuller        assertTrue(inLocalAddressAfterClose.getAddress().isAnyLocalAddress());
16547ae0b5a1d96c8030e0963ccc5b44c3ee66aaec3Neil Fuller        assertEquals(inLocalAddress.getPort(), inLocalAddressAfterClose.getPort());
16647ae0b5a1d96c8030e0963ccc5b44c3ee66aaec3Neil Fuller
16747ae0b5a1d96c8030e0963ccc5b44c3ee66aaec3Neil Fuller        InetSocketAddress outLocalAddressAfterClose =
16847ae0b5a1d96c8030e0963ccc5b44c3ee66aaec3Neil Fuller                (InetSocketAddress) out.socket().getLocalSocketAddress();
16947ae0b5a1d96c8030e0963ccc5b44c3ee66aaec3Neil Fuller        assertTrue(outLocalAddressAfterClose.getAddress().isAnyLocalAddress());
17047ae0b5a1d96c8030e0963ccc5b44c3ee66aaec3Neil Fuller        assertEquals(outLocalAddress.getPort(), outLocalAddressAfterClose.getPort());
1718cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes    }
1720371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes
1730371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes    // SocketOptions.setOption has weird behavior for setSoLinger/SO_LINGER.
1740371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes    // This test ensures we do what the RI does.
1750371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes    public void test_SocketOptions_setOption() throws Exception {
1760371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes        class MySocketImpl extends SocketImpl {
1770371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes            public int option;
1780371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes            public Object value;
1790371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes
1800371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes            public boolean createCalled;
1810371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes            public boolean createStream;
1820371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes
1830371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes            public MySocketImpl() { super(); }
1840371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes            @Override protected void accept(SocketImpl arg0) throws IOException { }
1850371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes            @Override protected int available() throws IOException { return 0; }
1860371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes            @Override protected void bind(InetAddress arg0, int arg1) throws IOException { }
1870371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes            @Override protected void close() throws IOException { }
1880371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes            @Override protected void connect(String arg0, int arg1) throws IOException { }
1890371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes            @Override protected void connect(InetAddress arg0, int arg1) throws IOException { }
1900371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes            @Override protected void connect(SocketAddress arg0, int arg1) throws IOException { }
1910371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes            @Override protected InputStream getInputStream() throws IOException { return null; }
1920371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes            @Override protected OutputStream getOutputStream() throws IOException { return null; }
1930371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes            @Override protected void listen(int arg0) throws IOException { }
1940371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes            @Override protected void sendUrgentData(int arg0) throws IOException { }
1950371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes            public Object getOption(int arg0) throws SocketException { return null; }
1960371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes
1970371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes            @Override protected void create(boolean isStream) throws IOException {
1980371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes                this.createCalled = true;
1990371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes                this.createStream = isStream;
2000371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes            }
2010371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes
2020371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes            public void setOption(int option, Object value) throws SocketException {
2030371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes                this.option = option;
2040371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes                this.value = value;
2050371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes            }
2060371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes        }
2070371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes
2080371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes        class MySocket extends Socket {
2090371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes            public MySocket(SocketImpl impl) throws SocketException {
2100371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes                super(impl);
2110371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes            }
2120371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes        }
2130371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes
2140371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes        MySocketImpl impl = new MySocketImpl();
2150371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes        Socket s = new MySocket(impl);
2160371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes
2170371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes        // Check that, as per the SocketOptions.setOption documentation, we pass false rather
2180371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes        // than -1 to the SocketImpl when setSoLinger is called with the first argument false.
2190371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes        s.setSoLinger(false, -1);
2200371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes        assertEquals(Boolean.FALSE, (Boolean) impl.value);
2210371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes        // We also check that SocketImpl.create was called. SocketChannelImpl.SocketAdapter
2220371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes        // subclasses Socket, and whether or not to call SocketImpl.create is the main behavioral
2230371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes        // difference.
2240371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes        assertEquals(true, impl.createCalled);
2250371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes        s.setSoLinger(false, 0);
2260371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes        assertEquals(Boolean.FALSE, (Boolean) impl.value);
2270371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes        s.setSoLinger(false, 1);
2280371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes        assertEquals(Boolean.FALSE, (Boolean) impl.value);
2290371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes
2300371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes        // Check that otherwise, we pass down an Integer.
2310371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes        s.setSoLinger(true, 0);
2320371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes        assertEquals(Integer.valueOf(0), (Integer) impl.value);
2330371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes        s.setSoLinger(true, 1);
2340371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes        assertEquals(Integer.valueOf(1), (Integer) impl.value);
2350371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes    }
2360371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes
2370371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes    public void test_setTrafficClass() throws Exception {
2380371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes        Socket s = new Socket();
2390371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes        s.setTrafficClass(123);
2400371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes        assertEquals(123, s.getTrafficClass());
2410371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes    }
242ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson
243ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson    public void testReadAfterClose() throws Exception {
244ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        MockServer server = new MockServer();
245ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        server.enqueue(new byte[]{5, 3}, 0);
246ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        Socket socket = new Socket("localhost", server.port);
247ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        InputStream in = socket.getInputStream();
248ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        assertEquals(5, in.read());
249ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        assertEquals(3, in.read());
250ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        assertEquals(-1, in.read());
251ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        assertEquals(-1, in.read());
252ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        socket.close();
253ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        in.close();
254ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson
255ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        /*
256ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson         * Rather astonishingly, read() doesn't throw even though the stream is
257ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson         * closed. This is consistent with the RI's behavior.
258ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson         */
259ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        assertEquals(-1, in.read());
260ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        assertEquals(-1, in.read());
261ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson
262ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        server.shutdown();
263ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson    }
264ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson
265ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson    public void testWriteAfterClose() throws Exception {
266ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        MockServer server = new MockServer();
267ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        server.enqueue(new byte[0], 3);
268ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        Socket socket = new Socket("localhost", server.port);
269ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        OutputStream out = socket.getOutputStream();
270ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        out.write(5);
271ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        out.write(3);
272ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        socket.close();
273ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        out.close();
274ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson
275ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        try {
276ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson            out.write(9);
277ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson            fail();
278ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        } catch (IOException expected) {
279ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        }
280ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson
281ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        server.shutdown();
282ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson    }
283ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson
284b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson    // http://b/5534202
285b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson    public void testAvailable() throws Exception {
286b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson        for (int i = 0; i < 100; i++) {
287b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson            assertAvailableReturnsZeroAfterSocketReadsAllData();
288b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson            System.out.println("Success on rep " + i);
289b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson        }
290b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson    }
291b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson
292b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson    private void assertAvailableReturnsZeroAfterSocketReadsAllData() throws Exception {
293b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson        final byte[] data = "foo".getBytes();
294b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson        final ServerSocket serverSocket = new ServerSocket(0);
295b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson
296b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson        new Thread() {
297b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson            @Override public void run() {
298b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson                try {
299b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson                    Socket socket = serverSocket.accept();
300b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson                    socket.getOutputStream().write(data);
301b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson                    socket.close();
302b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson                } catch (IOException e) {
303b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson                    e.printStackTrace();
304b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson                }
305b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson            }
306b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson        }.start();
307b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson
308b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson        Socket socket = new Socket("localhost", serverSocket.getLocalPort());
309b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson        byte[] readBuffer = new byte[128];
310b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson        InputStream in = socket.getInputStream();
311b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson        int total = 0;
312b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson        // to prevent available() from cheating after EOF, stop reading before -1 is returned
313b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson        while (total < data.length) {
314b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson            total += in.read(readBuffer);
315b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson        }
316b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson        assertEquals(0, in.available());
317b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson
318b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson        socket.close();
319b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson        serverSocket.close();
320b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson    }
321b1c31fbbba0ff96366b35ab40fd49cce55c9f489Jesse Wilson
32247ae0b5a1d96c8030e0963ccc5b44c3ee66aaec3Neil Fuller    public void testInitialState() throws Exception {
32347ae0b5a1d96c8030e0963ccc5b44c3ee66aaec3Neil Fuller        Socket s = new Socket();
32447ae0b5a1d96c8030e0963ccc5b44c3ee66aaec3Neil Fuller        try {
32547ae0b5a1d96c8030e0963ccc5b44c3ee66aaec3Neil Fuller            assertFalse(s.isBound());
32647ae0b5a1d96c8030e0963ccc5b44c3ee66aaec3Neil Fuller            assertFalse(s.isClosed());
32747ae0b5a1d96c8030e0963ccc5b44c3ee66aaec3Neil Fuller            assertFalse(s.isConnected());
32847ae0b5a1d96c8030e0963ccc5b44c3ee66aaec3Neil Fuller            assertEquals(-1, s.getLocalPort());
32947ae0b5a1d96c8030e0963ccc5b44c3ee66aaec3Neil Fuller            assertTrue(s.getLocalAddress().isAnyLocalAddress());
33047ae0b5a1d96c8030e0963ccc5b44c3ee66aaec3Neil Fuller            assertNull(s.getLocalSocketAddress());
33147ae0b5a1d96c8030e0963ccc5b44c3ee66aaec3Neil Fuller            assertNull(s.getInetAddress());
33247ae0b5a1d96c8030e0963ccc5b44c3ee66aaec3Neil Fuller            assertEquals(0, s.getPort());
33347ae0b5a1d96c8030e0963ccc5b44c3ee66aaec3Neil Fuller            assertNull(s.getRemoteSocketAddress());
33447ae0b5a1d96c8030e0963ccc5b44c3ee66aaec3Neil Fuller            assertFalse(s.getReuseAddress());
33547ae0b5a1d96c8030e0963ccc5b44c3ee66aaec3Neil Fuller            assertNull(s.getChannel());
33647ae0b5a1d96c8030e0963ccc5b44c3ee66aaec3Neil Fuller        } finally {
33747ae0b5a1d96c8030e0963ccc5b44c3ee66aaec3Neil Fuller            s.close();
33847ae0b5a1d96c8030e0963ccc5b44c3ee66aaec3Neil Fuller        }
33947ae0b5a1d96c8030e0963ccc5b44c3ee66aaec3Neil Fuller    }
34047ae0b5a1d96c8030e0963ccc5b44c3ee66aaec3Neil Fuller
34147ae0b5a1d96c8030e0963ccc5b44c3ee66aaec3Neil Fuller    public void testStateAfterClose() throws Exception {
34247ae0b5a1d96c8030e0963ccc5b44c3ee66aaec3Neil Fuller        Socket s = new Socket();
34347ae0b5a1d96c8030e0963ccc5b44c3ee66aaec3Neil Fuller        s.bind(new InetSocketAddress(Inet4Address.getLocalHost(), 0));
34447ae0b5a1d96c8030e0963ccc5b44c3ee66aaec3Neil Fuller        InetSocketAddress boundAddress = (InetSocketAddress) s.getLocalSocketAddress();
34547ae0b5a1d96c8030e0963ccc5b44c3ee66aaec3Neil Fuller        s.close();
34647ae0b5a1d96c8030e0963ccc5b44c3ee66aaec3Neil Fuller
34747ae0b5a1d96c8030e0963ccc5b44c3ee66aaec3Neil Fuller        assertTrue(s.isBound());
34847ae0b5a1d96c8030e0963ccc5b44c3ee66aaec3Neil Fuller        assertTrue(s.isClosed());
34947ae0b5a1d96c8030e0963ccc5b44c3ee66aaec3Neil Fuller        assertFalse(s.isConnected());
35047ae0b5a1d96c8030e0963ccc5b44c3ee66aaec3Neil Fuller        assertTrue(s.getLocalAddress().isAnyLocalAddress());
35147ae0b5a1d96c8030e0963ccc5b44c3ee66aaec3Neil Fuller        assertEquals(boundAddress.getPort(), s.getLocalPort());
35247ae0b5a1d96c8030e0963ccc5b44c3ee66aaec3Neil Fuller
35347ae0b5a1d96c8030e0963ccc5b44c3ee66aaec3Neil Fuller        InetSocketAddress localAddressAfterClose = (InetSocketAddress) s.getLocalSocketAddress();
35447ae0b5a1d96c8030e0963ccc5b44c3ee66aaec3Neil Fuller        assertTrue(localAddressAfterClose.getAddress().isAnyLocalAddress());
35547ae0b5a1d96c8030e0963ccc5b44c3ee66aaec3Neil Fuller        assertEquals(boundAddress.getPort(), localAddressAfterClose.getPort());
35647ae0b5a1d96c8030e0963ccc5b44c3ee66aaec3Neil Fuller    }
35747ae0b5a1d96c8030e0963ccc5b44c3ee66aaec3Neil Fuller
358d4348724908290a8c09918a35587f1f6836c08efNeil Fuller    public void testCloseDuringConnect() throws Exception {
359d4348724908290a8c09918a35587f1f6836c08efNeil Fuller        final CountDownLatch signal = new CountDownLatch(1);
360d4348724908290a8c09918a35587f1f6836c08efNeil Fuller
361d4348724908290a8c09918a35587f1f6836c08efNeil Fuller        final Socket s = new Socket();
362d4348724908290a8c09918a35587f1f6836c08efNeil Fuller        new Thread() {
363d4348724908290a8c09918a35587f1f6836c08efNeil Fuller            @Override
364d4348724908290a8c09918a35587f1f6836c08efNeil Fuller            public void run() {
365d4348724908290a8c09918a35587f1f6836c08efNeil Fuller                try {
366d4348724908290a8c09918a35587f1f6836c08efNeil Fuller                    // This address is reserved for documentation: should never be reachable.
367d4348724908290a8c09918a35587f1f6836c08efNeil Fuller                    InetSocketAddress unreachableIp = new InetSocketAddress("192.0.2.0", 80);
368d4348724908290a8c09918a35587f1f6836c08efNeil Fuller                    // This should never return.
369d4348724908290a8c09918a35587f1f6836c08efNeil Fuller                    s.connect(unreachableIp, 0 /* infinite */);
370d4348724908290a8c09918a35587f1f6836c08efNeil Fuller                    fail("Connect returned unexpectedly for: " + unreachableIp);
371d4348724908290a8c09918a35587f1f6836c08efNeil Fuller                } catch (SocketException expected) {
372d4348724908290a8c09918a35587f1f6836c08efNeil Fuller                    assertTrue(expected.getMessage().contains("Socket closed"));
373d4348724908290a8c09918a35587f1f6836c08efNeil Fuller                    signal.countDown();
374d4348724908290a8c09918a35587f1f6836c08efNeil Fuller                } catch (IOException e) {
375d4348724908290a8c09918a35587f1f6836c08efNeil Fuller                    fail("Unexpected exception: " + e);
376d4348724908290a8c09918a35587f1f6836c08efNeil Fuller                }
377d4348724908290a8c09918a35587f1f6836c08efNeil Fuller            }
378d4348724908290a8c09918a35587f1f6836c08efNeil Fuller        }.start();
379d4348724908290a8c09918a35587f1f6836c08efNeil Fuller
380d4348724908290a8c09918a35587f1f6836c08efNeil Fuller        // Wait for the connect() thread to run and start connect()
381d4348724908290a8c09918a35587f1f6836c08efNeil Fuller        Thread.sleep(2000);
382d4348724908290a8c09918a35587f1f6836c08efNeil Fuller
383d4348724908290a8c09918a35587f1f6836c08efNeil Fuller        s.close();
384d4348724908290a8c09918a35587f1f6836c08efNeil Fuller
385d4348724908290a8c09918a35587f1f6836c08efNeil Fuller        boolean connectUnblocked = signal.await(2000, TimeUnit.MILLISECONDS);
386d4348724908290a8c09918a35587f1f6836c08efNeil Fuller        assertTrue(connectUnblocked);
387d4348724908290a8c09918a35587f1f6836c08efNeil Fuller    }
388d4348724908290a8c09918a35587f1f6836c08efNeil Fuller
389ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson    static class MockServer {
390ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        private ExecutorService executor;
391ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        private ServerSocket serverSocket;
392ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        private int port = -1;
393ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson
394ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        MockServer() throws IOException {
395ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson            executor = Executors.newCachedThreadPool();
396ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson            serverSocket = new ServerSocket(0);
397ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson            serverSocket.setReuseAddress(true);
398ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson            port = serverSocket.getLocalPort();
399ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        }
400ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson
401ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        public Future<byte[]> enqueue(final byte[] sendBytes, final int receiveByteCount)
402ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson                throws IOException {
403ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson            return executor.submit(new Callable<byte[]>() {
404ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson                @Override public byte[] call() throws Exception {
405ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson                    Socket socket = serverSocket.accept();
406ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson                    OutputStream out = socket.getOutputStream();
407ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson                    out.write(sendBytes);
408ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson
409ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson                    InputStream in = socket.getInputStream();
410ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson                    byte[] result = new byte[receiveByteCount];
411ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson                    int total = 0;
412ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson                    while (total < receiveByteCount) {
413ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson                        total += in.read(result, total, result.length - total);
414ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson                    }
415ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson                    socket.close();
416ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson                    return result;
417ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson                }
418ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson            });
419ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        }
420ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson
421ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        public void shutdown() throws IOException {
422ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson            serverSocket.close();
423ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson            executor.shutdown();
424ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson        }
425ac41d7fe545831906171e3e86e1d18e201fd7739Jesse Wilson    }
426a9a57f2581773484d13e160fd3407692e825971aElliott Hughes}
427