SocketTest.java revision da15009528cc8300a6251f1d0931ac8657c9fc31
1/* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package libcore.java.net; 18 19import java.io.IOException; 20import java.io.InputStream; 21import java.io.OutputStream; 22import java.net.ConnectException; 23import java.net.InetAddress; 24import java.net.InetSocketAddress; 25import java.net.ServerSocket; 26import java.net.Socket; 27import java.net.SocketAddress; 28import java.net.SocketException; 29import java.net.SocketImpl; 30import java.nio.channels.ServerSocketChannel; 31import java.nio.channels.SocketChannel; 32import java.util.concurrent.Callable; 33import java.util.concurrent.ExecutorService; 34import java.util.concurrent.Executors; 35import java.util.concurrent.Future; 36 37public class SocketTest extends junit.framework.TestCase { 38 // See http://b/2980559. 39 public void test_close() throws Exception { 40 Socket s = new Socket(); 41 s.close(); 42 // Closing a closed socket does nothing. 43 s.close(); 44 } 45 46 /** 47 * Our getLocalAddress and getLocalPort currently use getsockname(3). 48 * This means they give incorrect results on closed sockets (as well 49 * as requiring an unnecessary call into native code). 50 */ 51 public void test_getLocalAddress_after_close() throws Exception { 52 Socket s = new Socket(); 53 try { 54 // Bind to an ephemeral local port. 55 s.bind(new InetSocketAddress("localhost", 0)); 56 assertTrue(s.getLocalAddress().toString(), s.getLocalAddress().isLoopbackAddress()); 57 // What local port did we get? 58 int localPort = s.getLocalPort(); 59 assertTrue(localPort > 0); 60 // Now close the socket... 61 s.close(); 62 // The RI returns the ANY address but the original local port after close. 63 assertTrue(s.getLocalAddress().isAnyLocalAddress()); 64 assertEquals(localPort, s.getLocalPort()); 65 } finally { 66 s.close(); 67 } 68 } 69 70 // http://code.google.com/p/android/issues/detail?id=7935 71 public void test_newSocket_connection_refused() throws Exception { 72 try { 73 new Socket("localhost", 80); 74 fail("connection should have been refused"); 75 } catch (ConnectException expected) { 76 } 77 } 78 79 // http://code.google.com/p/android/issues/detail?id=3123 80 // http://code.google.com/p/android/issues/detail?id=1933 81 public void test_socketLocalAndRemoteAddresses() throws Exception { 82 checkSocketLocalAndRemoteAddresses(false); 83 checkSocketLocalAndRemoteAddresses(true); 84 } 85 86 public void checkSocketLocalAndRemoteAddresses(boolean setOptions) throws Exception { 87 InetAddress host = InetAddress.getLocalHost(); 88 89 // Open a local server port. 90 ServerSocketChannel ssc = ServerSocketChannel.open(); 91 InetSocketAddress listenAddr = new InetSocketAddress(host, 0); 92 ssc.socket().bind(listenAddr, 0); 93 ServerSocket ss = ssc.socket(); 94 95 // Open a socket to the local port. 96 SocketChannel out = SocketChannel.open(); 97 out.configureBlocking(false); 98 if (setOptions) { 99 out.socket().setTcpNoDelay(false); 100 } 101 InetSocketAddress addr = new InetSocketAddress(host, ssc.socket().getLocalPort()); 102 out.connect(addr); 103 while (!out.finishConnect()) { 104 Thread.sleep(1); 105 } 106 107 SocketChannel in = ssc.accept(); 108 if (setOptions) { 109 in.socket().setTcpNoDelay(false); 110 } 111 112 InetSocketAddress outRemoteAddress = (InetSocketAddress) out.socket().getRemoteSocketAddress(); 113 InetSocketAddress outLocalAddress = (InetSocketAddress) out.socket().getLocalSocketAddress(); 114 InetSocketAddress inLocalAddress = (InetSocketAddress) in.socket().getLocalSocketAddress(); 115 InetSocketAddress inRemoteAddress = (InetSocketAddress) in.socket().getRemoteSocketAddress(); 116 System.err.println("inLocalAddress: " + inLocalAddress); 117 System.err.println("inRemoteAddress: " + inRemoteAddress); 118 System.err.println("outLocalAddress: " + outLocalAddress); 119 System.err.println("outRemoteAddress: " + outRemoteAddress); 120 121 assertEquals(outRemoteAddress.getPort(), ss.getLocalPort()); 122 assertEquals(inLocalAddress.getPort(), ss.getLocalPort()); 123 assertEquals(inRemoteAddress.getPort(), outLocalAddress.getPort()); 124 125 assertEquals(inLocalAddress.getAddress(), ss.getInetAddress()); 126 assertEquals(inRemoteAddress.getAddress(), ss.getInetAddress()); 127 assertEquals(outLocalAddress.getAddress(), ss.getInetAddress()); 128 assertEquals(outRemoteAddress.getAddress(), ss.getInetAddress()); 129 130 in.close(); 131 out.close(); 132 ssc.close(); 133 134 assertNull(in.socket().getRemoteSocketAddress()); 135 assertNull(out.socket().getRemoteSocketAddress()); 136 137 assertEquals(in.socket().getLocalSocketAddress(), ss.getLocalSocketAddress()); 138 } 139 140 // SocketOptions.setOption has weird behavior for setSoLinger/SO_LINGER. 141 // This test ensures we do what the RI does. 142 public void test_SocketOptions_setOption() throws Exception { 143 class MySocketImpl extends SocketImpl { 144 public int option; 145 public Object value; 146 147 public boolean createCalled; 148 public boolean createStream; 149 150 public MySocketImpl() { super(); } 151 @Override protected void accept(SocketImpl arg0) throws IOException { } 152 @Override protected int available() throws IOException { return 0; } 153 @Override protected void bind(InetAddress arg0, int arg1) throws IOException { } 154 @Override protected void close() throws IOException { } 155 @Override protected void connect(String arg0, int arg1) throws IOException { } 156 @Override protected void connect(InetAddress arg0, int arg1) throws IOException { } 157 @Override protected void connect(SocketAddress arg0, int arg1) throws IOException { } 158 @Override protected InputStream getInputStream() throws IOException { return null; } 159 @Override protected OutputStream getOutputStream() throws IOException { return null; } 160 @Override protected void listen(int arg0) throws IOException { } 161 @Override protected void sendUrgentData(int arg0) throws IOException { } 162 public Object getOption(int arg0) throws SocketException { return null; } 163 164 @Override protected void create(boolean isStream) throws IOException { 165 this.createCalled = true; 166 this.createStream = isStream; 167 } 168 169 public void setOption(int option, Object value) throws SocketException { 170 this.option = option; 171 this.value = value; 172 } 173 } 174 175 class MySocket extends Socket { 176 public MySocket(SocketImpl impl) throws SocketException { 177 super(impl); 178 } 179 } 180 181 MySocketImpl impl = new MySocketImpl(); 182 Socket s = new MySocket(impl); 183 184 // Check that, as per the SocketOptions.setOption documentation, we pass false rather 185 // than -1 to the SocketImpl when setSoLinger is called with the first argument false. 186 s.setSoLinger(false, -1); 187 assertEquals(Boolean.FALSE, (Boolean) impl.value); 188 // We also check that SocketImpl.create was called. SocketChannelImpl.SocketAdapter 189 // subclasses Socket, and whether or not to call SocketImpl.create is the main behavioral 190 // difference. 191 assertEquals(true, impl.createCalled); 192 s.setSoLinger(false, 0); 193 assertEquals(Boolean.FALSE, (Boolean) impl.value); 194 s.setSoLinger(false, 1); 195 assertEquals(Boolean.FALSE, (Boolean) impl.value); 196 197 // Check that otherwise, we pass down an Integer. 198 s.setSoLinger(true, 0); 199 assertEquals(Integer.valueOf(0), (Integer) impl.value); 200 s.setSoLinger(true, 1); 201 assertEquals(Integer.valueOf(1), (Integer) impl.value); 202 } 203 204 public void test_setTrafficClass() throws Exception { 205 Socket s = new Socket(); 206 s.setTrafficClass(123); 207 assertEquals(123, s.getTrafficClass()); 208 } 209 210 public void testReadAfterClose() throws Exception { 211 MockServer server = new MockServer(); 212 server.enqueue(new byte[]{5, 3}, 0); 213 Socket socket = new Socket("localhost", server.port); 214 InputStream in = socket.getInputStream(); 215 assertEquals(5, in.read()); 216 assertEquals(3, in.read()); 217 assertEquals(-1, in.read()); 218 assertEquals(-1, in.read()); 219 socket.close(); 220 in.close(); 221 222 /* 223 * Rather astonishingly, read() doesn't throw even though the stream is 224 * closed. This is consistent with the RI's behavior. 225 */ 226 assertEquals(-1, in.read()); 227 assertEquals(-1, in.read()); 228 229 server.shutdown(); 230 } 231 232 public void testWriteAfterClose() throws Exception { 233 MockServer server = new MockServer(); 234 server.enqueue(new byte[0], 3); 235 Socket socket = new Socket("localhost", server.port); 236 OutputStream out = socket.getOutputStream(); 237 out.write(5); 238 out.write(3); 239 socket.close(); 240 out.close(); 241 242 try { 243 out.write(9); 244 fail(); 245 } catch (IOException expected) { 246 } 247 248 server.shutdown(); 249 } 250 251 static class MockServer { 252 private ExecutorService executor; 253 private ServerSocket serverSocket; 254 private int port = -1; 255 256 MockServer() throws IOException { 257 executor = Executors.newCachedThreadPool(); 258 serverSocket = new ServerSocket(0); 259 serverSocket.setReuseAddress(true); 260 port = serverSocket.getLocalPort(); 261 } 262 263 public Future<byte[]> enqueue(final byte[] sendBytes, final int receiveByteCount) 264 throws IOException { 265 return executor.submit(new Callable<byte[]>() { 266 @Override public byte[] call() throws Exception { 267 Socket socket = serverSocket.accept(); 268 OutputStream out = socket.getOutputStream(); 269 out.write(sendBytes); 270 271 InputStream in = socket.getInputStream(); 272 byte[] result = new byte[receiveByteCount]; 273 int total = 0; 274 while (total < receiveByteCount) { 275 total += in.read(result, total, result.length - total); 276 } 277 socket.close(); 278 return result; 279 } 280 }); 281 } 282 283 public void shutdown() throws IOException { 284 serverSocket.close(); 285 executor.shutdown(); 286 } 287 } 288} 289