1 /* 2 * Copyright (C) 2008 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 17 package android.core; 18 19 import junit.framework.Assert; 20 import junit.framework.TestCase; 21 22 import java.io.IOException; 23 import java.net.InetAddress; 24 import java.net.InetSocketAddress; 25 import java.net.ServerSocket; 26 import java.net.Socket; 27 import java.net.SocketException; 28 import java.net.SocketTimeoutException; 29 import java.nio.channels.SocketChannel; 30 import java.util.concurrent.Semaphore; 31 32 import android.test.suitebuilder.annotation.LargeTest; 33 import android.test.suitebuilder.annotation.SmallTest; 34 import android.test.suitebuilder.annotation.Suppress; 35 36 /** 37 * Regression tests for various socket related problems. And a few general 38 * socket tests. 39 */ 40 public class SocketTest extends TestCase { 41 42 private static final String NON_EXISTING_ADDRESS = "123.123.123.123"; 43 44 private static final String KNOW_GOOD_ADDRESS = "209.85.129.147"; 45 46 private static final String PACKAGE_DROPPING_ADDRESS = "191.167.0.1"; 47 48 // Test for basic bind/connect/accept behavior. 49 @SmallTest 50 public void testSocketSimple() throws Exception { 51 ServerSocket ss; 52 Socket s, s1; 53 int port; 54 55 IOException lastEx = null; 56 57 ss = new ServerSocket(); 58 59 for (port = 9900; port < 9999; port++) { 60 try { 61 ss.bind(new InetSocketAddress("127.0.0.1", port)); 62 lastEx = null; 63 break; 64 } catch (IOException ex) { 65 lastEx = ex; 66 } 67 } 68 69 if (lastEx != null) { 70 throw lastEx; 71 } 72 73 s = new Socket("127.0.0.1", port); 74 75 s1 = ss.accept(); 76 77 s.getOutputStream().write(0xa5); 78 79 assertEquals(0xa5, s1.getInputStream().read()); 80 81 s1.getOutputStream().write(0x5a); 82 assertEquals(0x5a, s.getInputStream().read()); 83 } 84 85 // Regression test for #820068: Wildcard address 86 @SmallTest 87 public void testWildcardAddress() throws Exception { 88 Socket s2 = new Socket(); 89 s2.bind(new InetSocketAddress((InetAddress) null, 12345)); 90 byte[] addr = s2.getLocalAddress().getAddress(); 91 for (int i = 0; i < 4; i++) { 92 assertEquals("Not the wildcard address", 0, addr[i]); 93 } 94 } 95 96 // Regression test for #865753: server sockets not closing properly 97 @SmallTest 98 public void testServerSocketClose() throws Exception { 99 ServerSocket s3 = new ServerSocket(23456); 100 s3.close(); 101 ServerSocket s4 = new ServerSocket(23456); 102 s4.close(); 103 } 104 105 // Regression test for #876985: SO_REUSEADDR not working properly 106 107 private Exception serverError = null; 108 109 @LargeTest 110 public void testSetReuseAddress() throws IOException { 111 InetSocketAddress addr = new InetSocketAddress(8383); 112 113 final ServerSocket serverSock = new ServerSocket(); 114 serverSock.setReuseAddress(true); 115 serverSock.bind(addr); 116 117 final Semaphore semThreadEnd = new Semaphore(0); 118 new Thread() { 119 @Override 120 public void run() { 121 try { 122 Socket sock = serverSock.accept(); 123 sock.getInputStream().read(); 124 sock.close(); 125 } catch (IOException e) { 126 serverError = e; 127 } 128 semThreadEnd.release(); 129 } 130 }.start(); 131 132 // Give the server a bit of time for startup 133 try { 134 Thread.sleep(2000); 135 } catch (InterruptedException ex) { 136 // Ignored. 137 } 138 139 Socket client = new Socket("localhost", 8383); 140 client.getOutputStream().write(1); 141 // Just leave this connection open from the client side. It will be 142 // closed from the server side so the server stays in the TIME_WAIT 143 // state for a while. setReuseAddress() should be able to handle this. 144 145 try { 146 semThreadEnd.acquire(); 147 } catch (InterruptedException e) { 148 // ignore 149 } 150 serverSock.close(); 151 152 ServerSocket serverSock2 = new ServerSocket(); 153 serverSock2.setReuseAddress(true); 154 serverSock2.bind(addr); 155 serverSock2.close(); 156 157 if (serverError != null) { 158 throw new RuntimeException("Server must complete without error", serverError); 159 } 160 } 161 162 // Regression for 916701, a wrong exception was thrown after timeout of 163 // a ServerSocket. 164 @LargeTest 165 public void testTimeoutException() throws IOException { 166 ServerSocket s = new ServerSocket(9800); 167 s.setSoTimeout(2000); 168 try { 169 s.accept(); 170 } catch (SocketTimeoutException e) { 171 // this is ok. 172 } 173 } 174 175 // Regression for issue 1001980, openening a SocketChannel threw an Exception 176 @SmallTest 177 public void testNativeSocketChannelOpen() throws IOException { 178 SocketChannel.open(); 179 } 180 181 // Regression test for issue 1018016, connecting ignored a set timeout. 182 // 183 // Disabled because test behaves differently depending on networking 184 // environment. It works fine in the emulator and one the device with 185 // WLAN, but when 3G comes into play, the possible existence of a 186 // proxy makes it fail. 187 // 188 // @LargeTest 189 // public void testSocketSetSOTimeout() throws IOException { 190 // Socket sock = new Socket(); 191 // int timeout = 5000; 192 // long start = System.currentTimeMillis(); 193 // try { 194 // sock.connect(new InetSocketAddress(NON_EXISTING_ADDRESS, 80), timeout); 195 // } catch (SocketTimeoutException e) { 196 // // expected 197 // long delay = System.currentTimeMillis() - start; 198 // if (Math.abs(delay - timeout) > 1000) { 199 // fail("timeout was not accurate. expected: " + timeout 200 // + " actual: " + delay + " miliseconds."); 201 // } 202 // } finally { 203 // try { 204 // sock.close(); 205 // } catch (IOException ioe) { 206 // // ignore 207 // } 208 // } 209 // } 210 211 /** 212 * Regression test for 1062928: Dotted IP addresses (e.g., 192.168.100.1) 213 * appear to be broken in the M5 SDK. 214 * 215 * Tests that a connection given a ip-addressv4 such as 192.168.100.100 does 216 * not fail - sdk m5 seems only to accept dns names instead of ip numbers. 217 * ip 209.85.129.147 (one address of www.google.com) on port 80 (http) is 218 * used to test the connection. 219 */ 220 221 // Commenting out this test since it is flaky, even at the best of times. See 222 // #1191317 for Info. 223 @Suppress 224 public void disable_testConnectWithIP4IPAddr() { 225 // call a Google Web server 226 InetSocketAddress scktAddrss = new InetSocketAddress(KNOW_GOOD_ADDRESS, 227 80); 228 Socket clntSckt = new Socket(); 229 try { 230 clntSckt.connect(scktAddrss, 5000); 231 } catch (Throwable e) { 232 fail("connection problem:" + e.getClass().getName() + ": " 233 + e.getMessage()); 234 } finally { 235 try { 236 clntSckt.close(); 237 } catch (Exception e) { 238 // ignore 239 } 240 } 241 } 242 243 244 // Regression test for #1058962: Socket.close() does not cause 245 // socket.connect() to return immediately. 246 private Socket client; 247 248 private Exception error; 249 250 private boolean connected; 251 252 // This test isn't working now, but really should work. 253 // TODO Enable this test again. 254 255 @Suppress 256 public void disable_testSocketConnectClose() { 257 try { 258 client = new Socket(); 259 260 new Thread() { 261 @Override 262 public void run() { 263 try { 264 client.connect(new InetSocketAddress(PACKAGE_DROPPING_ADDRESS, 1357)); 265 } catch (Exception ex) { 266 error = ex; 267 } 268 269 connected = true; 270 } 271 }.start(); 272 273 Thread.sleep(1000); 274 275 Assert.assertNull("Connect must not fail immediately. Maybe try different address.", error); 276 Assert.assertFalse("Connect must not succeed. Maybe try different address.", connected); 277 278 client.close(); 279 280 Thread.sleep(1000); 281 282 if (error == null) { 283 fail("Socket connect still ongoing"); 284 } else if (!(error instanceof SocketException)) { 285 fail("Socket connect interrupted with wrong error: " + error.toString()); 286 } 287 288 } catch (Exception ex) { 289 throw new RuntimeException(ex); 290 } 291 292 } 293 294 } 295