blob: 9db6077476a0280621acaeed01e47699bc54b9a4 [file] [log] [blame]
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.core;
import junit.framework.Assert;
import junit.framework.TestCase;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.nio.channels.SocketChannel;
import java.util.concurrent.Semaphore;
import android.test.suitebuilder.annotation.LargeTest;
import android.test.suitebuilder.annotation.SmallTest;
import android.test.suitebuilder.annotation.Suppress;
/**
* Regression tests for various socket related problems. And a few general
* socket tests.
*/
public class SocketTest extends TestCase {
private static final String NON_EXISTING_ADDRESS = "123.123.123.123";
private static final String KNOW_GOOD_ADDRESS = "209.85.129.147";
private static final String PACKAGE_DROPPING_ADDRESS = "191.167.0.1";
// Test for basic bind/connect/accept behavior.
@SmallTest
public void testSocketSimple() throws Exception {
ServerSocket ss;
Socket s, s1;
int port;
IOException lastEx = null;
ss = new ServerSocket();
for (port = 9900; port < 9999; port++) {
try {
ss.bind(new InetSocketAddress("127.0.0.1", port));
lastEx = null;
break;
} catch (IOException ex) {
lastEx = ex;
}
}
if (lastEx != null) {
throw lastEx;
}
s = new Socket("127.0.0.1", port);
s1 = ss.accept();
s.getOutputStream().write(0xa5);
assertEquals(0xa5, s1.getInputStream().read());
s1.getOutputStream().write(0x5a);
assertEquals(0x5a, s.getInputStream().read());
}
// Regression test for #820068: Wildcard address
@SmallTest
public void testWildcardAddress() throws Exception {
Socket s2 = new Socket();
s2.bind(new InetSocketAddress((InetAddress) null, 12345));
byte[] addr = s2.getLocalAddress().getAddress();
for (int i = 0; i < 4; i++) {
assertEquals("Not the wildcard address", 0, addr[i]);
}
}
// Regression test for #865753: server sockets not closing properly
@SmallTest
public void testServerSocketClose() throws Exception {
ServerSocket s3 = new ServerSocket(23456);
s3.close();
ServerSocket s4 = new ServerSocket(23456);
s4.close();
}
// Regression test for #876985: SO_REUSEADDR not working properly
private Exception serverError = null;
@LargeTest
public void testSetReuseAddress() throws IOException {
InetSocketAddress addr = new InetSocketAddress(8383);
final ServerSocket serverSock = new ServerSocket();
serverSock.setReuseAddress(true);
serverSock.bind(addr);
final Semaphore semThreadEnd = new Semaphore(0);
new Thread() {
@Override
public void run() {
try {
Socket sock = serverSock.accept();
sock.getInputStream().read();
sock.close();
} catch (IOException e) {
serverError = e;
}
semThreadEnd.release();
}
}.start();
// Give the server a bit of time for startup
try {
Thread.sleep(2000);
} catch (InterruptedException ex) {
// Ignored.
}
Socket client = new Socket("localhost", 8383);
client.getOutputStream().write(1);
// Just leave this connection open from the client side. It will be
// closed from the server side so the server stays in the TIME_WAIT
// state for a while. setReuseAddress() should be able to handle this.
try {
semThreadEnd.acquire();
} catch (InterruptedException e) {
// ignore
}
serverSock.close();
ServerSocket serverSock2 = new ServerSocket();
serverSock2.setReuseAddress(true);
serverSock2.bind(addr);
serverSock2.close();
if (serverError != null) {
throw new RuntimeException("Server must complete without error", serverError);
}
}
// Regression for 916701, a wrong exception was thrown after timeout of
// a ServerSocket.
@LargeTest
public void testTimeoutException() throws IOException {
ServerSocket s = new ServerSocket(9800);
s.setSoTimeout(2000);
try {
s.accept();
} catch (SocketTimeoutException e) {
// this is ok.
}
}
// Regression for issue 1001980, openening a SocketChannel threw an Exception
@SmallTest
public void testNativeSocketChannelOpen() throws IOException {
SocketChannel.open();
}
// Regression test for issue 1018016, connecting ignored a set timeout.
//
// Disabled because test behaves differently depending on networking
// environment. It works fine in the emulator and one the device with
// WLAN, but when 3G comes into play, the possible existence of a
// proxy makes it fail.
//
// @LargeTest
// public void testSocketSetSOTimeout() throws IOException {
// Socket sock = new Socket();
// int timeout = 5000;
// long start = System.currentTimeMillis();
// try {
// sock.connect(new InetSocketAddress(NON_EXISTING_ADDRESS, 80), timeout);
// } catch (SocketTimeoutException e) {
// // expected
// long delay = System.currentTimeMillis() - start;
// if (Math.abs(delay - timeout) > 1000) {
// fail("timeout was not accurate. expected: " + timeout
// + " actual: " + delay + " miliseconds.");
// }
// } finally {
// try {
// sock.close();
// } catch (IOException ioe) {
// // ignore
// }
// }
// }
/**
* Regression test for 1062928: Dotted IP addresses (e.g., 192.168.100.1)
* appear to be broken in the M5 SDK.
*
* Tests that a connection given a ip-addressv4 such as 192.168.100.100 does
* not fail - sdk m5 seems only to accept dns names instead of ip numbers.
* ip 209.85.129.147 (one address of www.google.com) on port 80 (http) is
* used to test the connection.
*/
// Commenting out this test since it is flaky, even at the best of times. See
// #1191317 for Info.
@Suppress
public void disable_testConnectWithIP4IPAddr() {
// call a Google Web server
InetSocketAddress scktAddrss = new InetSocketAddress(KNOW_GOOD_ADDRESS,
80);
Socket clntSckt = new Socket();
try {
clntSckt.connect(scktAddrss, 5000);
} catch (Throwable e) {
fail("connection problem:" + e.getClass().getName() + ": "
+ e.getMessage());
} finally {
try {
clntSckt.close();
} catch (Exception e) {
// ignore
}
}
}
// Regression test for #1058962: Socket.close() does not cause
// socket.connect() to return immediately.
private Socket client;
private Exception error;
private boolean connected;
// This test isn't working now, but really should work.
// TODO Enable this test again.
@Suppress
public void disable_testSocketConnectClose() {
try {
client = new Socket();
new Thread() {
@Override
public void run() {
try {
client.connect(new InetSocketAddress(PACKAGE_DROPPING_ADDRESS, 1357));
} catch (Exception ex) {
error = ex;
}
connected = true;
}
}.start();
Thread.sleep(1000);
Assert.assertNull("Connect must not fail immediately. Maybe try different address.", error);
Assert.assertFalse("Connect must not succeed. Maybe try different address.", connected);
client.close();
Thread.sleep(1000);
if (error == null) {
fail("Socket connect still ongoing");
} else if (!(error instanceof SocketException)) {
fail("Socket connect interrupted with wrong error: " + error.toString());
}
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
}