summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeil Fuller <nfuller@google.com>2014-02-11 15:52:27 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2014-02-11 15:52:27 +0000
commit58ac1fd09dddd681504868831909c5185b183582 (patch)
tree59b8f3014f69cebc2bc811f540a1820cfae0b680
parent2b4e2469730e1341980ef79e2f5566c54403bded (diff)
parent47ae0b5a1d96c8030e0963ccc5b44c3ee66aaec3 (diff)
downloadlibcore-58ac1fd09dddd681504868831909c5185b183582.zip
libcore-58ac1fd09dddd681504868831909c5185b183582.tar.gz
libcore-58ac1fd09dddd681504868831909c5185b183582.tar.bz2
Merge "Implementing bind() and getLocalAddress() for NIO2."
-rw-r--r--expectations/brokentests.txt8
-rw-r--r--harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/channels/DatagramChannelTest.java167
-rw-r--r--harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/channels/ServerSocketChannelTest.java233
-rw-r--r--harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/channels/SocketChannelTest.java161
-rw-r--r--luni/src/main/java/java/net/DatagramSocket.java9
-rw-r--r--luni/src/main/java/java/net/ServerSocket.java14
-rw-r--r--luni/src/main/java/java/net/Socket.java16
-rw-r--r--luni/src/main/java/java/nio/DatagramChannelImpl.java64
-rw-r--r--luni/src/main/java/java/nio/ServerSocketChannelImpl.java31
-rw-r--r--luni/src/main/java/java/nio/SocketChannelImpl.java47
-rw-r--r--luni/src/main/java/java/nio/channels/AlreadyBoundException.java31
-rw-r--r--luni/src/main/java/java/nio/channels/DatagramChannel.java18
-rw-r--r--luni/src/main/java/java/nio/channels/NetworkChannel.java68
-rw-r--r--luni/src/main/java/java/nio/channels/ServerSocketChannel.java50
-rw-r--r--luni/src/main/java/java/nio/channels/SocketChannel.java18
-rw-r--r--luni/src/test/java/libcore/java/net/DatagramSocketTest.java58
-rw-r--r--luni/src/test/java/libcore/java/net/ServerSocketTest.java32
-rw-r--r--luni/src/test/java/libcore/java/net/SocketTest.java71
-rw-r--r--luni/src/test/java/libcore/java/nio/channels/DatagramChannelTest.java26
-rw-r--r--luni/src/test/java/libcore/java/nio/channels/ServerSocketChannelTest.java98
-rw-r--r--luni/src/test/java/libcore/java/nio/channels/SocketChannelTest.java88
21 files changed, 1129 insertions, 179 deletions
diff --git a/expectations/brokentests.txt b/expectations/brokentests.txt
index 93c9a5c..3412e1c 100644
--- a/expectations/brokentests.txt
+++ b/expectations/brokentests.txt
@@ -875,5 +875,13 @@
"org.apache.harmony.tests.java.util.jar.ManifestTest#testRead",
"org.apache.harmony.tests.java.util.jar.ManifestTest#testStreamConstructor"
]
+},
+{
+ description: "Potentially flakey because they rely on a specific local TCP port being free.",
+ result: EXEC_FAILED,
+ names: [
+ "org.apache.harmony.tests.java.nio.channels.ServerSocketChannelTest#test_bind_explicitPort",
+ "org.apache.harmony.tests.java.nio.channels.SocketChannelTest#testBind_ExplicitFreePort"
+ ]
}
]
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/channels/DatagramChannelTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/channels/DatagramChannelTest.java
index 0b8b26f..731e907 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/channels/DatagramChannelTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/channels/DatagramChannelTest.java
@@ -25,6 +25,7 @@ import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.SocketException;
import java.nio.ByteBuffer;
+import java.nio.channels.AlreadyBoundException;
import java.nio.channels.AsynchronousCloseException;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.DatagramChannel;
@@ -71,11 +72,11 @@ public class DatagramChannelTest extends TestCase {
channel1 = DatagramChannel.open();
channel2 = DatagramChannel.open();
- channel1.socket().bind(new InetSocketAddress(Inet6Address.LOOPBACK, 0));
- channel2.socket().bind(new InetSocketAddress(Inet6Address.LOOPBACK, 0));
+ channel1.bind(new InetSocketAddress(Inet6Address.LOOPBACK, 0));
+ channel2.bind(new InetSocketAddress(Inet6Address.LOOPBACK, 0));
- channel1Address = (InetSocketAddress) channel1.socket().getLocalSocketAddress();
- channel2Address = (InetSocketAddress) channel2.socket().getLocalSocketAddress();
+ channel1Address = (InetSocketAddress) channel1.getLocalAddress();
+ channel2Address = (InetSocketAddress) channel2.getLocalAddress();
this.datagramSocket1 = new DatagramSocket(0, Inet6Address.LOOPBACK);
this.datagramSocket2 = new DatagramSocket(0, Inet6Address.LOOPBACK);
@@ -379,7 +380,8 @@ public class DatagramChannelTest extends TestCase {
try {
s.connect(datagramSocket2Address);
fail();
- } catch (IllegalStateException expected) {}
+ } catch (IllegalStateException expected) {
+ }
assertTrue(this.channel1.isConnected());
assertTrue(s.isConnected());
@@ -1253,8 +1255,7 @@ public class DatagramChannelTest extends TestCase {
Thread.sleep(TIME_UNIT);
channel2.send(ByteBuffer.wrap(str.getBytes()), datagramSocket1Address);
fail("Should throw SocketException!");
- } catch (SocketException e) {
- //expected
+ } catch (SocketException expected) {
}
}
@@ -1942,7 +1943,7 @@ public class DatagramChannelTest extends TestCase {
sourceArray[i] = (byte) i;
}
- this.channel1.connect(channel1.socket().getLocalSocketAddress());
+ this.channel1.connect(channel1.getLocalAddress());
this.channel2.connect(datagramSocket1Address); // the different addr
// write
@@ -1972,7 +1973,7 @@ public class DatagramChannelTest extends TestCase {
assertEquals(CAPACITY_NORMAL, dc.write(sourceBuf));
// Connect channel2 after data has been written.
- channel2.connect(dc.socket().getLocalSocketAddress());
+ channel2.connect(dc.getLocalAddress());
// read
ByteBuffer targetBuf = ByteBuffer.wrap(targetArray);
@@ -2164,7 +2165,7 @@ public class DatagramChannelTest extends TestCase {
assertEquals(CAPACITY_NORMAL, dc.write(sourceBuf));
// Connect channel2 after data has been written.
- channel2.connect(dc.socket().getLocalSocketAddress());
+ channel2.connect(dc.getLocalAddress());
// read
ByteBuffer targetBuf = ByteBuffer.wrap(targetArray);
@@ -2382,8 +2383,8 @@ public class DatagramChannelTest extends TestCase {
public void test_bounded_harmony6493() throws IOException {
DatagramChannel server = DatagramChannel.open();
InetSocketAddress addr = new InetSocketAddress("localhost", 0);
- server.socket().bind(addr);
- SocketAddress boundedAddress = server.socket().getLocalSocketAddress();
+ server.bind(addr);
+ SocketAddress boundedAddress = server.getLocalAddress();
DatagramChannel client = DatagramChannel.open();
ByteBuffer sent = ByteBuffer.allocate(1024);
@@ -2395,4 +2396,146 @@ public class DatagramChannelTest extends TestCase {
server.close();
client.close();
}
+
+ public void test_bind_null() throws Exception {
+ DatagramChannel dc = DatagramChannel.open();
+ try {
+ assertNull(dc.getLocalAddress());
+
+ dc.bind(null);
+
+ InetSocketAddress localAddress = (InetSocketAddress) dc.getLocalAddress();
+ assertTrue(localAddress.getAddress().isAnyLocalAddress());
+ assertTrue(localAddress.getPort() > 0);
+ } finally {
+ dc.close();
+ }
+ }
+
+ public void test_bind_failure() throws Exception {
+ DatagramChannel dc = DatagramChannel.open();
+ try {
+ // Bind to a local address that is in use
+ dc.bind(channel1Address);
+ fail();
+ } catch (IOException expected) {
+ } finally {
+ dc.close();
+ }
+ }
+
+ public void test_bind_closed() throws Exception {
+ DatagramChannel dc = DatagramChannel.open();
+ dc.close();
+
+ try {
+ dc.bind(null);
+ fail();
+ } catch (ClosedChannelException expected) {
+ } finally {
+ dc.close();
+ }
+ }
+
+ public void test_bind_twice() throws Exception {
+ DatagramChannel dc = DatagramChannel.open();
+ dc.bind(null);
+
+ try {
+ dc.bind(null);
+ fail();
+ } catch (AlreadyBoundException expected) {
+ } finally {
+ dc.close();
+ }
+ }
+
+ public void test_bind_explicitPort() throws Exception {
+ InetSocketAddress address = (InetSocketAddress) channel1.getLocalAddress();
+ assertTrue(address.getPort() > 0);
+
+ DatagramChannel dc = DatagramChannel.open();
+ // Allow the socket to bind to a port we know is already in use.
+ dc.socket().setReuseAddress(true);
+ InetSocketAddress bindAddress = new InetSocketAddress("localhost", address.getPort());
+ dc.bind(bindAddress);
+
+ InetSocketAddress boundAddress = (InetSocketAddress) dc.getLocalAddress();
+ assertEquals(bindAddress.getHostName(), boundAddress.getHostName());
+ assertEquals(bindAddress.getPort(), boundAddress.getPort());
+
+ dc.close();
+ channel1.close();
+ }
+
+ /** Checks that the SocketChannel and associated Socket agree on the socket state. */
+ public void test_bind_socketSync() throws IOException {
+ DatagramChannel dc = DatagramChannel.open();
+ assertNull(dc.getLocalAddress());
+
+ DatagramSocket socket = dc.socket();
+ assertNull(socket.getLocalSocketAddress());
+ assertFalse(socket.isBound());
+
+ InetSocketAddress bindAddr = new InetSocketAddress("localhost", 0);
+ dc.bind(bindAddr);
+
+ InetSocketAddress actualAddr = (InetSocketAddress) dc.getLocalAddress();
+ assertEquals(actualAddr, socket.getLocalSocketAddress());
+ assertEquals(bindAddr.getHostName(), actualAddr.getHostName());
+ assertTrue(socket.isBound());
+ assertFalse(socket.isConnected());
+ assertFalse(socket.isClosed());
+
+ dc.close();
+
+ assertFalse(dc.isOpen());
+ assertTrue(socket.isClosed());
+ }
+
+ /**
+ * Checks that the SocketChannel and associated Socket agree on the socket state, even if
+ * the Socket object is requested/created after bind().
+ */
+ public void test_bind_socketSyncAfterBind() throws IOException {
+ DatagramChannel dc = DatagramChannel.open();
+ assertNull(dc.getLocalAddress());
+
+ InetSocketAddress bindAddr = new InetSocketAddress("localhost", 0);
+ dc.bind(bindAddr);
+
+ // Socket creation after bind().
+ DatagramSocket socket = dc.socket();
+ InetSocketAddress actualAddr = (InetSocketAddress) dc.getLocalAddress();
+ assertEquals(actualAddr, socket.getLocalSocketAddress());
+ assertEquals(bindAddr.getHostName(), actualAddr.getHostName());
+ assertTrue(socket.isBound());
+ assertFalse(socket.isConnected());
+ assertFalse(socket.isClosed());
+
+ dc.close();
+
+ assertFalse(dc.isOpen());
+ assertTrue(socket.isClosed());
+ }
+
+ public void test_getLocalSocketAddress_afterClose() throws IOException {
+ DatagramChannel dc = DatagramChannel.open();
+ assertNull(dc.getLocalAddress());
+
+ InetSocketAddress bindAddr = new InetSocketAddress("localhost", 0);
+ dc.bind(bindAddr);
+
+ assertNotNull(dc.getLocalAddress());
+
+ dc.close();
+
+ assertFalse(dc.isOpen());
+
+ try {
+ dc.getLocalAddress();
+ fail();
+ } catch (ClosedChannelException expected) {
+ }
+ }
}
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/channels/ServerSocketChannelTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/channels/ServerSocketChannelTest.java
index 828ab30..b417adc 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/channels/ServerSocketChannelTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/channels/ServerSocketChannelTest.java
@@ -24,6 +24,7 @@ import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.ByteBuffer;
+import java.nio.channels.AlreadyBoundException;
import java.nio.channels.AsynchronousCloseException;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.IllegalBlockingModeException;
@@ -108,6 +109,157 @@ public class ServerSocketChannelTest extends TestCase {
}
// -------------------------------------------------------------------
+ // Tests for bind()
+ // -------------------------------------------------------------------
+
+ public void test_bind_null() throws Exception {
+ ServerSocketChannel ssc = ServerSocketChannel.open();
+ try {
+ assertNull(ssc.getLocalAddress());
+
+ ssc.bind(null);
+
+ InetSocketAddress localAddress = (InetSocketAddress) ssc.getLocalAddress();
+ assertTrue(localAddress.getAddress().isAnyLocalAddress());
+ assertTrue(localAddress.getPort() > 0);
+ } finally {
+ ssc.close();
+ }
+ }
+
+ public void test_bind_failure() throws Exception {
+ ServerSocketChannel portHog = ServerSocketChannel.open();
+ portHog.bind(null);
+
+ ServerSocketChannel ssc = ServerSocketChannel.open();
+ try {
+ // Bind to a local address that is in use
+ ssc.bind(portHog.getLocalAddress());
+ fail();
+ } catch (IOException expected) {
+ } finally {
+ ssc.close();
+ portHog.close();
+ }
+ }
+
+ public void test_bind_closed() throws Exception {
+ ServerSocketChannel ssc = ServerSocketChannel.open();
+ ssc.close();
+
+ try {
+ ssc.bind(null);
+ fail();
+ } catch (ClosedChannelException expected) {
+ } finally {
+ ssc.close();
+ }
+ }
+
+ public void test_bind_twice() throws Exception {
+ ServerSocketChannel ssc = ServerSocketChannel.open();
+ ssc.bind(null);
+
+ try {
+ ssc.bind(null);
+ fail();
+ } catch (AlreadyBoundException expected) {
+ } finally {
+ ssc.close();
+ }
+ }
+
+ public void test_bind_explicitPort() throws Exception {
+ ServerSocketChannel portPickingChannel = ServerSocketChannel.open();
+ // Have the OS find a free port.
+ portPickingChannel.bind(null);
+
+ InetSocketAddress address = (InetSocketAddress) portPickingChannel.getLocalAddress();
+ assertTrue(address.getPort() > 0);
+ portPickingChannel.close();
+
+ // There is a risk of flakiness here if the port is allocated to something else between
+ // close() and bind().
+ ServerSocketChannel ssc = ServerSocketChannel.open();
+ InetSocketAddress bindAddress = new InetSocketAddress("localhost", address.getPort());
+ ssc.bind(bindAddress);
+
+ InetSocketAddress boundAddress = (InetSocketAddress) ssc.getLocalAddress();
+ assertEquals(bindAddress.getHostName(), boundAddress.getHostName());
+ assertEquals(bindAddress.getPort(), boundAddress.getPort());
+
+ ssc.close();
+ }
+
+ public void test_bind_socketSync() throws IOException {
+ ServerSocketChannel ssc = ServerSocketChannel.open();
+ assertNull(ssc.getLocalAddress());
+
+ ServerSocket socket = ssc.socket();
+ assertNull(socket.getLocalSocketAddress());
+ assertFalse(socket.isBound());
+
+ InetSocketAddress bindAddr = new InetSocketAddress("localhost", 0);
+ ssc.bind(bindAddr);
+
+ InetSocketAddress actualAddr = (InetSocketAddress) ssc.getLocalAddress();
+ assertEquals(actualAddr, socket.getLocalSocketAddress());
+ assertEquals(bindAddr.getHostName(), actualAddr.getHostName());
+ assertTrue(socket.isBound());
+ assertFalse(socket.isClosed());
+
+ ssc.close();
+
+ assertFalse(ssc.isOpen());
+ assertTrue(socket.isClosed());
+ }
+
+ public void test_bind_socketSyncAfterBind() throws IOException {
+ ServerSocketChannel ssc = ServerSocketChannel.open();
+ assertNull(ssc.getLocalAddress());
+
+ InetSocketAddress bindAddr = new InetSocketAddress("localhost", 0);
+ ssc.bind(bindAddr);
+
+ // Socket creation after bind().
+ ServerSocket socket = ssc.socket();
+ InetSocketAddress actualAddr = (InetSocketAddress) ssc.getLocalAddress();
+ assertEquals(actualAddr, socket.getLocalSocketAddress());
+ assertEquals(bindAddr.getHostName(), actualAddr.getHostName());
+ assertTrue(socket.isBound());
+ assertFalse(socket.isClosed());
+
+ ssc.close();
+
+ assertFalse(ssc.isOpen());
+ assertTrue(socket.isClosed());
+ }
+
+ // -------------------------------------------------------------------
+ // Test for getLocalSocketAddress()
+ // -------------------------------------------------------------------
+
+ public void test_getLocalSocketAddress_afterClose() throws IOException {
+ ServerSocketChannel ssc = ServerSocketChannel.open();
+ assertNull(ssc.getLocalAddress());
+
+ InetSocketAddress bindAddr = new InetSocketAddress("localhost", 0);
+ ssc.bind(bindAddr);
+
+ assertNotNull(ssc.getLocalAddress());
+
+ ssc.close();
+
+ assertFalse(ssc.isOpen());
+
+ try {
+ ssc.getLocalAddress();
+ fail();
+ } catch (ClosedChannelException expected) {
+ }
+ }
+
+ // -------------------------------------------------------------------
// Test for socket()
// -------------------------------------------------------------------
@@ -235,8 +387,7 @@ public class ServerSocketChannelTest extends TestCase {
public void testAccept_Block_NoConnect() throws IOException {
assertTrue(this.serverChannel.isBlocking());
- ServerSocket gotSocket = this.serverChannel.socket();
- gotSocket.bind(null);
+ serverChannel.bind(null);
// blocking mode , will block and wait for ever...
// so must close the server channel with another thread.
new Thread() {
@@ -259,8 +410,7 @@ public class ServerSocketChannelTest extends TestCase {
}
public void testAccept_NonBlock_NoConnect() throws IOException {
- ServerSocket gotSocket = this.serverChannel.socket();
- gotSocket.bind(null);
+ this.serverChannel.bind(null);
this.serverChannel.configureBlocking(false);
// non-blocking mode , will immediately return
assertNull(this.serverChannel.accept());
@@ -270,13 +420,13 @@ public class ServerSocketChannelTest extends TestCase {
* @tests ServerSocketChannel#accept().socket()
*/
public void test_read_Blocking_RealData() throws IOException {
- serverChannel.socket().bind(null);
+ serverChannel.bind(null);
ByteBuffer buf = ByteBuffer.allocate(CAPACITY_NORMAL);
for (int i = 0; i < CAPACITY_NORMAL; i++) {
buf.put((byte) i);
}
- clientChannel.connect(serverChannel.socket().getLocalSocketAddress());
+ clientChannel.connect(serverChannel.getLocalAddress());
Socket serverSocket = serverChannel.accept().socket();
InputStream in = serverSocket.getInputStream();
buf.flip();
@@ -309,13 +459,13 @@ public class ServerSocketChannelTest extends TestCase {
*/
public void test_read_NonBlocking_RealData() throws Exception {
serverChannel.configureBlocking(false);
- serverChannel.socket().bind(null);
+ serverChannel.bind(null);
ByteBuffer buf = ByteBuffer.allocate(CAPACITY_NORMAL);
for (int i = 0; i < CAPACITY_NORMAL; i++) {
buf.put((byte) i);
}
buf.flip();
- clientChannel.connect(serverChannel.socket().getLocalSocketAddress());
+ clientChannel.connect(serverChannel.getLocalAddress());
Socket serverSocket = serverChannel.accept().socket();
InputStream in = serverSocket.getInputStream();
clientChannel.write(buf);
@@ -328,14 +478,13 @@ public class ServerSocketChannelTest extends TestCase {
*/
public void test_write_Blocking_RealData() throws IOException {
assertTrue(serverChannel.isBlocking());
- ServerSocket serverSocket = serverChannel.socket();
- serverSocket.bind(null);
+ serverChannel.bind(null);
byte[] writeContent = new byte[CAPACITY_NORMAL];
for (int i = 0; i < writeContent.length; i++) {
writeContent[i] = (byte) i;
}
- clientChannel.connect(serverChannel.socket().getLocalSocketAddress());
+ clientChannel.connect(serverChannel.getLocalAddress());
Socket socket = serverChannel.accept().socket();
OutputStream out = socket.getOutputStream();
out.write(writeContent);
@@ -350,14 +499,13 @@ public class ServerSocketChannelTest extends TestCase {
*/
public void test_write_NonBlocking_RealData() throws Exception {
serverChannel.configureBlocking(false);
- ServerSocket serverSocket = serverChannel.socket();
- serverSocket.bind(null);
+ serverChannel.bind(null);
byte[] writeContent = new byte[CAPACITY_NORMAL];
for (int i = 0; i < CAPACITY_NORMAL; i++) {
writeContent[i] = (byte) i;
}
- clientChannel.connect(serverSocket.getLocalSocketAddress());
+ clientChannel.connect(serverChannel.getLocalAddress());
Socket clientSocket = serverChannel.accept().socket();
OutputStream out = clientSocket.getOutputStream();
out.write(writeContent);
@@ -371,13 +519,13 @@ public class ServerSocketChannelTest extends TestCase {
*/
public void test_read_LByteBuffer_Blocking_ReadWriteRealLargeData()
throws IOException, InterruptedException {
- serverChannel.socket().bind(null);
+ serverChannel.bind(null);
ByteBuffer buf = ByteBuffer.allocate(CAPACITY_64KB);
for (int i = 0; i < CAPACITY_64KB; i++) {
buf.put((byte) i);
}
buf.flip();
- clientChannel.connect(serverChannel.socket().getLocalSocketAddress());
+ clientChannel.connect(serverChannel.getLocalAddress());
WriteChannelThread writeThread = new WriteChannelThread(clientChannel, buf);
writeThread.start();
Socket socket = serverChannel.accept().socket();
@@ -416,13 +564,13 @@ public class ServerSocketChannelTest extends TestCase {
public void test_read_LByteBuffer_NonBlocking_ReadWriteRealLargeData()
throws Exception {
serverChannel.configureBlocking(false);
- serverChannel.socket().bind(null);
+ serverChannel.bind(null);
ByteBuffer buf = ByteBuffer.allocate(CAPACITY_64KB);
for (int i = 0; i < CAPACITY_64KB; i++) {
buf.put((byte) i);
}
buf.flip();
- clientChannel.connect(serverChannel.socket().getLocalSocketAddress());
+ clientChannel.connect(serverChannel.getLocalAddress());
WriteChannelThread writeThread = new WriteChannelThread(clientChannel, buf);
writeThread.start();
Socket socket = serverChannel.accept().socket();
@@ -441,12 +589,12 @@ public class ServerSocketChannelTest extends TestCase {
public void test_write_LByteBuffer_NonBlocking_ReadWriteRealLargeData()
throws Exception {
serverChannel.configureBlocking(false);
- serverChannel.socket().bind(null);
+ serverChannel.bind(null);
byte[] writeContent = new byte[CAPACITY_64KB];
for (int i = 0; i < writeContent.length; i++) {
writeContent[i] = (byte) i;
}
- clientChannel.connect(serverChannel.socket().getLocalSocketAddress());
+ clientChannel.connect(serverChannel.getLocalAddress());
Socket socket = serverChannel.accept().socket();
WriteSocketThread writeThread = new WriteSocketThread(socket, writeContent);
writeThread.start();
@@ -484,12 +632,12 @@ public class ServerSocketChannelTest extends TestCase {
*/
public void test_write_LByteBuffer_Blocking_ReadWriteRealLargeData()
throws Exception {
- serverChannel.socket().bind(null);
+ serverChannel.bind(null);
byte[] writeContent = new byte[CAPACITY_64KB];
for (int i = 0; i < writeContent.length; i++) {
writeContent[i] = (byte) i;
}
- clientChannel.connect(serverChannel.socket().getLocalSocketAddress());
+ clientChannel.connect(serverChannel.getLocalAddress());
Socket socket = serverChannel.accept().socket();
WriteSocketThread writeThread = new WriteSocketThread(socket, writeContent);
writeThread.start();
@@ -531,9 +679,9 @@ public class ServerSocketChannelTest extends TestCase {
final int SO_TIMEOUT = 10;
ServerSocketChannel sc = ServerSocketChannel.open();
try {
- ServerSocket ss = sc.socket();
- ss.bind(null);
+ sc.bind(null);
sc.configureBlocking(false);
+ ServerSocket ss = sc.socket();
ss.setSoTimeout(SO_TIMEOUT);
SocketChannel client = sc.accept();
// non blocking mode, returns null since there are no pending connections.
@@ -556,15 +704,13 @@ public class ServerSocketChannelTest extends TestCase {
try {
gotSocket.accept();
fail("Should throw an IllegalBlockingModeException");
- } catch (IllegalBlockingModeException e) {
- // expected
+ } catch (IllegalBlockingModeException expected) {
}
serverChannel.close();
try {
gotSocket.accept();
fail("Should throw an IllegalBlockingModeException");
- } catch (IllegalBlockingModeException e) {
- // expected
+ } catch (IllegalBlockingModeException expected) {
}
}
@@ -578,15 +724,13 @@ public class ServerSocketChannelTest extends TestCase {
try {
gotSocket.accept();
fail("Should throw an IllegalBlockingModeException");
- } catch (IllegalBlockingModeException e) {
- // expected
+ } catch (IllegalBlockingModeException expected) {
}
serverChannel.close();
try {
gotSocket.accept();
fail("Should throw an IllegalBlockingModeException");
- } catch (IllegalBlockingModeException e) {
- // expected
+ } catch (IllegalBlockingModeException expected) {
}
}
@@ -596,20 +740,18 @@ public class ServerSocketChannelTest extends TestCase {
public void test_socket_accept_Nonblocking_Bound() throws IOException {
// regression test for Harmony-748
serverChannel.configureBlocking(false);
+ serverChannel.bind(null);
ServerSocket gotSocket = serverChannel.socket();
- gotSocket.bind(null);
try {
gotSocket.accept();
fail("Should throw an IllegalBlockingModeException");
- } catch (IllegalBlockingModeException e) {
- // expected
+ } catch (IllegalBlockingModeException expected) {
}
serverChannel.close();
try {
gotSocket.accept();
fail("Should throw a ClosedChannelException");
- } catch (ClosedChannelException e) {
- // expected
+ } catch (ClosedChannelException expected) {
}
}
@@ -619,22 +761,20 @@ public class ServerSocketChannelTest extends TestCase {
public void test_socket_accept_Blocking_Bound() throws IOException {
// regression test for Harmony-748
serverChannel.configureBlocking(true);
- ServerSocket gotSocket = serverChannel.socket();
- gotSocket.bind(null);
+ serverChannel.bind(null);
serverChannel.close();
try {
- gotSocket.accept();
+ serverChannel.socket().accept();
fail("Should throw a ClosedChannelException");
- } catch (ClosedChannelException e) {
- // expected
+ } catch (ClosedChannelException expected) {
}
}
/**
* Regression test for HARMONY-4961
*/
public void test_socket_getLocalPort() throws IOException {
- serverChannel.socket().bind(null);
- clientChannel.connect(serverChannel.socket().getLocalSocketAddress());
+ serverChannel.bind(null);
+ clientChannel.connect(serverChannel.getLocalAddress());
SocketChannel myChannel = serverChannel.accept();
int port = myChannel.socket().getLocalPort();
assertEquals(serverChannel.socket().getLocalPort(), port);
@@ -648,7 +788,7 @@ public class ServerSocketChannelTest extends TestCase {
*/
public void test_accept_configureBlocking() throws Exception {
InetSocketAddress localAddr = new InetSocketAddress("localhost", 0);
- serverChannel.socket().bind(localAddr);
+ serverChannel.bind(localAddr);
// configure the channel non-blocking
// when it is accepting in main thread
@@ -667,8 +807,7 @@ public class ServerSocketChannelTest extends TestCase {
try {
serverChannel.accept();
fail("should throw AsynchronousCloseException");
- } catch (AsynchronousCloseException e) {
- // expected
+ } catch (AsynchronousCloseException expected) {
}
serverChannel.close();
}
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/channels/SocketChannelTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/channels/SocketChannelTest.java
index 2d52bc5..52dff79 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/channels/SocketChannelTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/channels/SocketChannelTest.java
@@ -30,6 +30,7 @@ import java.net.SocketAddress;
import java.net.SocketException;
import java.nio.Buffer;
import java.nio.ByteBuffer;
+import java.nio.channels.AlreadyBoundException;
import java.nio.channels.AlreadyConnectedException;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.ConnectionPendingException;
@@ -153,6 +154,87 @@ public class SocketChannelTest extends TestCase {
}
}
+ public void testBind_Null() throws Exception {
+ assertNull(channel1.getLocalAddress());
+
+ channel1.bind(null);
+
+ InetSocketAddress localAddress = (InetSocketAddress) channel1.getLocalAddress();
+ assertTrue(localAddress.getAddress().isAnyLocalAddress());
+ assertTrue(localAddress.getPort() > 0);
+ }
+
+ public void testBind_Failure() throws Exception {
+ assertNull(channel1.getLocalAddress());
+
+ try {
+ // Bind to a local address that is in use
+ channel1.bind(localAddr1);
+ fail();
+ } catch (IOException expected) {
+ }
+ }
+
+ public void testBind_Closed() throws Exception {
+ channel1.close();
+
+ try {
+ channel1.bind(null);
+ fail();
+ } catch (ClosedChannelException expected) {
+ }
+ }
+
+ public void testBind_Twice() throws Exception {
+ channel1.bind(null);
+
+ try {
+ channel1.bind(null);
+ fail();
+ } catch (AlreadyBoundException expected) {
+ }
+ }
+
+ public void testBind_explicitPort() throws Exception {
+ ServerSocketChannel portPickingChannel = ServerSocketChannel.open();
+ // Have the OS find a free port.
+ portPickingChannel.bind(null);
+ InetSocketAddress address = (InetSocketAddress) portPickingChannel.getLocalAddress();
+ assertTrue(address.getPort() > 0);
+ portPickingChannel.close();
+
+ // There is a risk of flakiness here if the port is allocated to something else between
+ // close() and bind().
+ InetSocketAddress bindAddress = new InetSocketAddress("localhost", address.getPort());
+ // Allow the socket to bind to a port we know is already in use.
+ channel1.socket().setReuseAddress(true);
+ channel1.bind(bindAddress);
+
+ InetSocketAddress boundAddress = (InetSocketAddress) channel1.getLocalAddress();
+ assertEquals(bindAddress.getHostName(), boundAddress.getHostName());
+ assertEquals(bindAddress.getPort(), boundAddress.getPort());
+ }
+
+ public void test_getLocalSocketAddress_afterClose() throws IOException {
+ SocketChannel sc = SocketChannel.open();
+ assertNull(sc.getLocalAddress());
+
+ InetSocketAddress bindAddr = new InetSocketAddress("localhost", 0);
+ sc.bind(bindAddr);
+
+ assertNotNull(sc.getLocalAddress());
+
+ sc.close();
+
+ assertFalse(sc.isOpen());
+
+ try {
+ sc.getLocalAddress();
+ fail();
+ } catch (ClosedChannelException expected) {
+ }
+ }
+
/*
* Test method for 'java.nio.channels.SocketChannel.read(ByteBuffer[])'
*/
@@ -1800,7 +1882,7 @@ public class SocketChannelTest extends TestCase {
ServerSocket serversocket = theServerChannel.socket();
serversocket.setReuseAddress(true);
// Bind the socket
- serversocket.bind(address);
+ theServerChannel.bind(address);
boolean doneNonBlockingConnect = false;
// Loop so that we make sure we're definitely testing finishConnect()
@@ -2121,8 +2203,7 @@ public class SocketChannelTest extends TestCase {
ByteBuffer buffer = ByteBuffer.allocateDirect(128);
ServerSocketChannel server = ServerSocketChannel.open();
- server.socket().bind(
- new InetSocketAddress(InetAddress.getLocalHost(), 0), 5);
+ server.bind(new InetSocketAddress(InetAddress.getLocalHost(), 0), 5);
Socket client = new Socket(InetAddress.getLocalHost(), server.socket()
.getLocalPort());
client.setTcpNoDelay(false);
@@ -2740,9 +2821,9 @@ public class SocketChannelTest extends TestCase {
*/
public void test_writev() throws Exception {
ServerSocketChannel ssc = ServerSocketChannel.open();
- ssc.socket().bind(null);
+ ssc.bind(null);
SocketChannel sc = SocketChannel.open();
- sc.connect(ssc.socket().getLocalSocketAddress());
+ sc.connect(ssc.getLocalAddress());
SocketChannel sock = ssc.accept();
ByteBuffer[] buf = { ByteBuffer.allocate(10), ByteBuffer.allocateDirect(20) };
@@ -2767,10 +2848,10 @@ public class SocketChannelTest extends TestCase {
public void test_writev2() throws Exception {
ServerSocketChannel ssc = ServerSocketChannel.open();
ssc.configureBlocking(false);
- ssc.socket().bind(null);
+ ssc.bind(null);
SocketChannel sc = SocketChannel.open();
sc.configureBlocking(false);
- boolean connected = sc.connect(ssc.socket().getLocalSocketAddress());
+ boolean connected = sc.connect(ssc.getLocalAddress());
SocketChannel sock = ssc.accept();
if (!connected) {
sc.finishConnect();
@@ -2805,10 +2886,10 @@ public class SocketChannelTest extends TestCase {
public void test_write$NonBlockingException() throws Exception {
ServerSocketChannel ssc = ServerSocketChannel.open();
ssc.configureBlocking(false);
- ssc.socket().bind(null);
+ ssc.bind(null);
SocketChannel sc = SocketChannel.open();
sc.configureBlocking(false);
- boolean connected = sc.connect(ssc.socket().getLocalSocketAddress());
+ boolean connected = sc.connect(ssc.getLocalAddress());
SocketChannel sock = ssc.accept();
if (!connected) {
sc.finishConnect();
@@ -2841,9 +2922,9 @@ public class SocketChannelTest extends TestCase {
public void test_write$LByteBuffer2() throws IOException {
// Set-up
ServerSocketChannel server = ServerSocketChannel.open();
- server.socket().bind(null);
+ server.bind(null);
SocketChannel client = SocketChannel.open();
- client.connect(server.socket().getLocalSocketAddress());
+ client.connect(server.getLocalAddress());
SocketChannel worker = server.accept();
// Test overlapping buffers
@@ -2873,9 +2954,9 @@ public class SocketChannelTest extends TestCase {
public void test_write$LByteBuffer_buffers() throws IOException {
// Set-up
ServerSocketChannel server = ServerSocketChannel.open();
- server.socket().bind(null);
+ server.bind(null);
SocketChannel client = SocketChannel.open();
- client.connect(server.socket().getLocalSocketAddress());
+ client.connect(server.getLocalAddress());
SocketChannel worker = server.accept();
// A variety of buffer types to write
@@ -2915,9 +2996,9 @@ public class SocketChannelTest extends TestCase {
public void test_write$LByteBuffer_writes() throws IOException {
// Set-up
ServerSocketChannel server = ServerSocketChannel.open();
- server.socket().bind(null);
+ server.bind(null);
SocketChannel client = SocketChannel.open();
- client.connect(server.socket().getLocalSocketAddress());
+ client.connect(server.getLocalAddress());
SocketChannel worker = server.accept();
// Data to write
@@ -2942,7 +3023,7 @@ public class SocketChannelTest extends TestCase {
// Read what we wrote and check it
ByteBuffer readBuffer = ByteBuffer.allocate(1024);
- while (EOF != worker.read(readBuffer)) {};
+ while (EOF != worker.read(readBuffer)) {}
readBuffer.flip();
assertEquals(ByteBuffer.wrap(data), readBuffer);
@@ -2957,10 +3038,10 @@ public class SocketChannelTest extends TestCase {
public void test_write$LByteBuffer_invalid() throws IOException {
// Set-up
ServerSocketChannel server = ServerSocketChannel.open();
- server.socket().bind(null);
+ server.bind(null);
SocketChannel client = SocketChannel.open();
- client.connect(server.socket().getLocalSocketAddress());
+ client.connect(server.getLocalAddress());
SocketChannel worker = server.accept();
@@ -2968,32 +3049,27 @@ public class SocketChannelTest extends TestCase {
try {
client.write((ByteBuffer[]) null);
fail("Should throw a NPE");
- } catch (NullPointerException e) {
- // expected
+ } catch (NullPointerException expected) {
}
try {
client.write((ByteBuffer[]) null, 0, 0);
fail("Should throw a NPE");
- } catch (NullPointerException e) {
- // expected
+ } catch (NullPointerException expected) {
}
try {
client.write((ByteBuffer[]) null, 1, 0);
fail("Should throw a NPE");
- } catch (NullPointerException e) {
- // expected
+ } catch (NullPointerException expected) {
}
try {
client.write((ByteBuffer[]) null, 0, 1);
fail("Should throw a NPE");
- } catch (NullPointerException e) {
- // expected
+ } catch (NullPointerException expected) {
}
try {
client.write((ByteBuffer[]) null, 1, 1);
fail("Should throw a NPE");
- } catch (NullPointerException e) {
- // expected
+ } catch (NullPointerException expected) {
}
ByteBuffer[] buffers = new ByteBuffer[1];
@@ -3065,9 +3141,9 @@ public class SocketChannelTest extends TestCase {
throws Exception {
// regression 1 for HARMONY-549
ServerSocketChannel ssc = ServerSocketChannel.open();
- ssc.socket().bind(null);
+ ssc.bind(null);
SocketChannel sc = SocketChannel.open();
- sc.connect(ssc.socket().getLocalSocketAddress());
+ sc.connect(ssc.getLocalAddress());
ssc.accept().close();
ByteBuffer[] buf = { ByteBuffer.allocate(10) };
assertEquals(-1, sc.read(buf, 0, 1));
@@ -3081,16 +3157,15 @@ public class SocketChannelTest extends TestCase {
public void test_socketChannel_write_ByteBufferII() throws Exception {
// regression 2 for HARMONY-549
ServerSocketChannel ssc = ServerSocketChannel.open();
- ssc.socket().bind(null);
+ ssc.bind(null);
SocketChannel sc = SocketChannel.open();
- sc.connect(ssc.socket().getLocalSocketAddress());
+ sc.connect(ssc.getLocalAddress());
SocketChannel sock = ssc.accept();
ByteBuffer[] buf = { ByteBuffer.allocate(10), null };
try {
sc.write(buf, 0, 2);
fail("should throw NPE");
- } catch (NullPointerException e) {
- // expected
+ } catch (NullPointerException expected) {
}
ssc.close();
sc.close();
@@ -3104,9 +3179,9 @@ public class SocketChannelTest extends TestCase {
public void test_socketChannel_read_ByteBufferII_bufNULL() throws Exception {
// regression 3 for HARMONY-549
ServerSocketChannel ssc = ServerSocketChannel.open();
- ssc.socket().bind(null);
+ ssc.bind(null);
SocketChannel sc = SocketChannel.open();
- sc.connect(ssc.socket().getLocalSocketAddress());
+ sc.connect(ssc.getLocalAddress());
ssc.accept();
ByteBuffer[] buf = new ByteBuffer[2];
buf[0] = ByteBuffer.allocate(1);
@@ -3114,8 +3189,7 @@ public class SocketChannelTest extends TestCase {
try {
sc.read(buf, 0, 2);
fail("should throw NullPointerException");
- } catch (NullPointerException e) {
- // expected
+ } catch (NullPointerException expected) {
}
ssc.close();
sc.close();
@@ -3127,9 +3201,9 @@ public class SocketChannelTest extends TestCase {
public void test_socketChannel_write_close() throws Exception {
// regression 4 for HARMONY-549
ServerSocketChannel ssc = ServerSocketChannel.open();
- ssc.socket().bind(null);
+ ssc.bind(null);
SocketChannel sc = SocketChannel.open();
- sc.connect(ssc.socket().getLocalSocketAddress());
+ sc.connect(ssc.getLocalAddress());
SocketChannel sock = ssc.accept();
ByteBuffer buf = null;
ssc.close();
@@ -3137,8 +3211,7 @@ public class SocketChannelTest extends TestCase {
try {
sc.write(buf);
fail("should throw NPE");
- } catch (NullPointerException e) {
- // expected
+ } catch (NullPointerException expected) {
}
sock.close();
}
@@ -3153,9 +3226,9 @@ public class SocketChannelTest extends TestCase {
ByteBuffer readBuf = ByteBuffer.allocate(11);
ByteBuffer buf = ByteBuffer.wrap(testStr.getBytes());
ServerSocketChannel ssc = ServerSocketChannel.open();
- ssc.socket().bind(null);
+ ssc.bind(null);
SocketChannel sc = SocketChannel.open();
- sc.connect(ssc.socket().getLocalSocketAddress());
+ sc.connect(ssc.getLocalAddress());
buf.position(2);
ssc.accept().write(buf);
assertEquals(9, sc.read(readBuf));
diff --git a/luni/src/main/java/java/net/DatagramSocket.java b/luni/src/main/java/java/net/DatagramSocket.java
index e2acac7..26825d2 100644
--- a/luni/src/main/java/java/net/DatagramSocket.java
+++ b/luni/src/main/java/java/net/DatagramSocket.java
@@ -176,8 +176,8 @@ public class DatagramSocket implements Closeable {
}
/**
- * Returns the local address to which this socket is bound,
- * or {@code null} if this socket is closed.
+ * Returns the local address to which this socket is bound, a wildcard address if this
+ * socket is not yet bound, or {@code null} if this socket is closed.
*/
public InetAddress getLocalAddress() {
try {
@@ -588,10 +588,11 @@ public class DatagramSocket implements Closeable {
}
/**
- * Returns the {@code SocketAddress} this socket is bound to, or null for an unbound socket.
+ * Returns the {@code SocketAddress} this socket is bound to, or {@code null} for an unbound or
+ * closed socket.
*/
public SocketAddress getLocalSocketAddress() {
- if (!isBound()) {
+ if (isClosed() || !isBound()) {
return null;
}
return new InetSocketAddress(getLocalAddress(), getLocalPort());
diff --git a/luni/src/main/java/java/net/ServerSocket.java b/luni/src/main/java/java/net/ServerSocket.java
index 8b56ca1..72b197f 100644
--- a/luni/src/main/java/java/net/ServerSocket.java
+++ b/luni/src/main/java/java/net/ServerSocket.java
@@ -164,8 +164,8 @@ public class ServerSocket implements Closeable {
}
/**
- * Gets the local IP address of this server socket or {@code null} if the
- * socket is unbound. This is useful for multihomed hosts.
+ * Gets the local IP address of this server socket if this socket has ever been bound,
+ * {@code null} otherwise. This is useful for multihomed hosts.
*
* @return the local address of this server socket.
*/
@@ -177,8 +177,9 @@ public class ServerSocket implements Closeable {
}
/**
- * Gets the local port of this server socket or {@code -1} if the socket is
- * unbound.
+ * Gets the local port of this server socket or {@code -1} if the socket is not bound.
+ * If the socket has ever been bound this method will return the local port it was bound to,
+ * even after it has been closed.
*
* @return the local port this server is listening on.
*/
@@ -342,8 +343,9 @@ public class ServerSocket implements Closeable {
}
/**
- * Gets the local socket address of this server socket or {@code null} if
- * the socket is unbound. This is useful on multihomed hosts.
+ * Gets the local socket address of this server socket or {@code null} if the socket is unbound.
+ * This is useful on multihomed hosts. If the socket has ever been bound this method will return
+ * the local address it was bound to, even after it has been closed.
*
* @return the local socket address and port this socket is bound to.
*/
diff --git a/luni/src/main/java/java/net/Socket.java b/luni/src/main/java/java/net/Socket.java
index 517571d..5dd350a 100644
--- a/luni/src/main/java/java/net/Socket.java
+++ b/luni/src/main/java/java/net/Socket.java
@@ -312,6 +312,7 @@ public class Socket implements Closeable {
*/
public synchronized void close() throws IOException {
isClosed = true;
+ isConnected = false;
// RI compatibility: the RI returns the any address (but the original local port) after
// close.
localAddress = Inet4Address.ANY;
@@ -326,6 +327,7 @@ public class Socket implements Closeable {
*/
public void onClose() {
isClosed = true;
+ isConnected = false;
// RI compatibility: the RI returns the any address (but the original local port) after
// close.
localAddress = Inet4Address.ANY;
@@ -371,14 +373,15 @@ public class Socket implements Closeable {
/**
* Returns the local IP address this socket is bound to, or an address for which
- * {@link InetAddress#isAnyLocalAddress()} returns true if the socket is unbound.
+ * {@link InetAddress#isAnyLocalAddress()} returns true if the socket is closed or unbound.
*/
public InetAddress getLocalAddress() {
return localAddress;
}
/**
- * Returns the local port this socket is bound to, or -1 if the socket is unbound.
+ * Returns the local port this socket is bound to, or -1 if the socket is unbound. If the socket
+ * has been closed this method will still return the local port the socket was bound to.
*/
public int getLocalPort() {
if (!isBound()) {
@@ -583,6 +586,7 @@ public class Socket implements Closeable {
impl.bind(addr, localPort);
}
isBound = true;
+ cacheLocalAddress();
impl.connect(dstAddress, dstPort);
isConnected = true;
cacheLocalAddress();
@@ -691,9 +695,10 @@ public class Socket implements Closeable {
}
/**
- * Returns the local address and port of this socket as a SocketAddress or
- * null if the socket is unbound. This is useful on multihomed
- * hosts.
+ * Returns the local address and port of this socket as a SocketAddress or null if the socket
+ * has never been bound. If the socket is closed but has previously been bound then an address
+ * for which {@link InetAddress#isAnyLocalAddress()} returns true will be returned with the
+ * previously-bound port. This is useful on multihomed hosts.
*/
public SocketAddress getLocalSocketAddress() {
if (!isBound()) {
@@ -800,6 +805,7 @@ public class Socket implements Closeable {
*/
public void onBind(InetAddress localAddress, int localPort) {
isBound = true;
+ this.localAddress = localAddress;
impl.onBind(localAddress, localPort);
}
diff --git a/luni/src/main/java/java/nio/DatagramChannelImpl.java b/luni/src/main/java/java/nio/DatagramChannelImpl.java
index 5f74bdc..3c4a980 100644
--- a/luni/src/main/java/java/nio/DatagramChannelImpl.java
+++ b/luni/src/main/java/java/nio/DatagramChannelImpl.java
@@ -24,16 +24,19 @@ import java.net.ConnectException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.DatagramSocketImpl;
+import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.PlainDatagramSocketImpl;
import java.net.SocketAddress;
import java.net.SocketException;
+import java.nio.channels.AlreadyBoundException;
import java.nio.channels.AlreadyConnectedException;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.DatagramChannel;
import java.nio.channels.IllegalBlockingModeException;
import java.nio.channels.NotYetConnectedException;
+import java.nio.channels.UnsupportedAddressTypeException;
import java.nio.channels.spi.SelectorProvider;
import java.util.Arrays;
import libcore.io.ErrnoException;
@@ -100,6 +103,26 @@ class DatagramChannelImpl extends DatagramChannel implements FileDescriptorChann
return socket;
}
+ /** @hide Until ready for a public API change */
+ @Override
+ synchronized public DatagramChannel bind(SocketAddress local) throws IOException {
+ checkOpen();
+ if (isBound) {
+ throw new AlreadyBoundException();
+ }
+
+ if (local == null) {
+ local = new InetSocketAddress(Inet4Address.ANY, 0);
+ } else if (!(local instanceof InetSocketAddress)) {
+ throw new UnsupportedAddressTypeException();
+ }
+
+ InetSocketAddress localAddress = (InetSocketAddress) local;
+ IoBridge.bind(fd, localAddress.getAddress(), localAddress.getPort());
+ onBind(true /* updateSocketState */);
+ return this;
+ }
+
/**
* Initialise the isBound, localAddress and localPort state from the file descriptor. Used when
* some or all of the bound state has been left to the OS to decide, or when the Socket handled
@@ -125,6 +148,13 @@ class DatagramChannelImpl extends DatagramChannel implements FileDescriptorChann
}
}
+ /** @hide Until ready for a public API change */
+ @Override
+ synchronized public SocketAddress getLocalAddress() throws IOException {
+ checkOpen();
+ return isBound ? new InetSocketAddress(localAddress, localPort) : null;
+ }
+
@Override
synchronized public boolean isConnected() {
return connected;
@@ -547,40 +577,6 @@ class DatagramChannelImpl extends DatagramChannel implements FileDescriptorChann
}
@Override
- public boolean isBound() {
- return channelImpl.isBound;
- }
-
- @Override
- public boolean isConnected() {
- return channelImpl.isConnected();
- }
-
- @Override
- public InetAddress getInetAddress() {
- if (channelImpl.connectAddress == null) {
- return null;
- }
- return channelImpl.connectAddress.getAddress();
- }
-
- @Override public InetAddress getLocalAddress() {
- try {
- return IoBridge.getSocketLocalAddress(channelImpl.fd);
- } catch (SocketException ex) {
- return null;
- }
- }
-
- @Override
- public int getPort() {
- if (channelImpl.connectAddress == null) {
- return -1;
- }
- return channelImpl.connectAddress.getPort();
- }
-
- @Override
public void bind(SocketAddress localAddr) throws SocketException {
if (channelImpl.isConnected()) {
throw new AlreadyConnectedException();
diff --git a/luni/src/main/java/java/nio/ServerSocketChannelImpl.java b/luni/src/main/java/java/nio/ServerSocketChannelImpl.java
index 92bc419..9ae282e 100644
--- a/luni/src/main/java/java/nio/ServerSocketChannelImpl.java
+++ b/luni/src/main/java/java/nio/ServerSocketChannelImpl.java
@@ -22,12 +22,15 @@ import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
+import java.net.SocketAddress;
import java.net.SocketTimeoutException;
+import java.nio.channels.AlreadyBoundException;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.IllegalBlockingModeException;
import java.nio.channels.NotYetBoundException;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
+import java.nio.channels.UnsupportedAddressTypeException;
import java.nio.channels.spi.SelectorProvider;
import libcore.io.ErrnoException;
import libcore.io.IoUtils;
@@ -51,6 +54,32 @@ final class ServerSocketChannelImpl extends ServerSocketChannel implements FileD
return socket;
}
+ /** @hide Until ready for a public API change */
+ @Override
+ public final ServerSocketChannel bind(SocketAddress localAddr, int backlog) throws IOException {
+ if (!isOpen()) {
+ throw new ClosedChannelException();
+ }
+ if (socket.isBound()) {
+ throw new AlreadyBoundException();
+ }
+ if (localAddr != null && !(localAddr instanceof InetSocketAddress)) {
+ throw new UnsupportedAddressTypeException();
+ }
+
+ socket.bind(localAddr, backlog);
+ return this;
+ }
+
+ /** @hide Until ready for a public API change */
+ @Override
+ public SocketAddress getLocalAddress() throws IOException {
+ if (!isOpen()) {
+ throw new ClosedChannelException();
+ }
+ return socket.getLocalSocketAddress();
+ }
+
@Override
public SocketChannel accept() throws IOException {
if (!isOpen()) {
@@ -60,7 +89,7 @@ final class ServerSocketChannelImpl extends ServerSocketChannel implements FileD
throw new NotYetBoundException();
}
- // Create an empty socket channel. This will be populated by ServerSocketAdapter.accept.
+ // Create an empty socket channel. This will be populated by ServerSocketAdapter.implAccept.
SocketChannelImpl result = new SocketChannelImpl(provider(), false);
try {
begin();
diff --git a/luni/src/main/java/java/nio/SocketChannelImpl.java b/luni/src/main/java/java/nio/SocketChannelImpl.java
index 6af9f9f..977c433 100644
--- a/luni/src/main/java/java/nio/SocketChannelImpl.java
+++ b/luni/src/main/java/java/nio/SocketChannelImpl.java
@@ -32,6 +32,7 @@ import java.net.Socket;
import java.net.SocketAddress;
import java.net.SocketException;
import java.net.SocketUtils;
+import java.nio.channels.AlreadyBoundException;
import java.nio.channels.AlreadyConnectedException;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.ConnectionPendingException;
@@ -135,6 +136,28 @@ class SocketChannelImpl extends SocketChannel implements FileDescriptorChannel {
return socket;
}
+ /** @hide Until ready for a public API change */
+ @Override
+ synchronized public final SocketChannel bind(SocketAddress local) throws IOException {
+ if (!isOpen()) {
+ throw new ClosedChannelException();
+ }
+ if (isBound) {
+ throw new AlreadyBoundException();
+ }
+
+ if (local == null) {
+ local = new InetSocketAddress(Inet4Address.ANY, 0);
+ } else if (!(local instanceof InetSocketAddress)) {
+ throw new UnsupportedAddressTypeException();
+ }
+
+ InetSocketAddress localAddress = (InetSocketAddress) local;
+ IoBridge.bind(fd, localAddress.getAddress(), localAddress.getPort());
+ onBind(true /* updateSocketState */);
+ return this;
+ }
+
/**
* Initialise the isBound, localAddress and localPort state from the file descriptor. Used when
* some or all of the bound state has been left to the OS to decide, or when the Socket handled
@@ -160,6 +183,15 @@ class SocketChannelImpl extends SocketChannel implements FileDescriptorChannel {
}
}
+ /** @hide Until ready for a public API change */
+ @Override
+ synchronized public SocketAddress getLocalAddress() throws IOException {
+ if (!isOpen()) {
+ throw new ClosedChannelException();
+ }
+ return isBound ? new InetSocketAddress(localAddress, localPort) : null;
+ }
+
@Override
synchronized public boolean isConnected() {
return status == SOCKET_STATUS_CONNECTED;
@@ -526,21 +558,6 @@ class SocketChannelImpl extends SocketChannel implements FileDescriptorChannel {
}
@Override
- public boolean isBound() {
- return channel.isBound;
- }
-
- @Override
- public boolean isConnected() {
- return channel.isConnected();
- }
-
- @Override
- public InetAddress getLocalAddress() {
- return channel.localAddress != null ? channel.localAddress : Inet4Address.ANY;
- }
-
- @Override
public void connect(SocketAddress remoteAddr, int timeout) throws IOException {
if (!channel.isBlocking()) {
throw new IllegalBlockingModeException();
diff --git a/luni/src/main/java/java/nio/channels/AlreadyBoundException.java b/luni/src/main/java/java/nio/channels/AlreadyBoundException.java
new file mode 100644
index 0000000..0a35fc3
--- /dev/null
+++ b/luni/src/main/java/java/nio/channels/AlreadyBoundException.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2014 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 java.nio.channels;
+
+/**
+ * An {@code AlreadyBoundException} is thrown when an attempt is made to bind a NetworkChannel that
+ * is already bound.
+ *
+ * @hide Until ready for a public API change
+ */
+public class AlreadyBoundException extends IllegalStateException {
+
+ private static final long serialVersionUID = 6796072983322737592L;
+
+ public AlreadyBoundException() {
+ }
+}
diff --git a/luni/src/main/java/java/nio/channels/DatagramChannel.java b/luni/src/main/java/java/nio/channels/DatagramChannel.java
index 486b168..2040b8e 100644
--- a/luni/src/main/java/java/nio/channels/DatagramChannel.java
+++ b/luni/src/main/java/java/nio/channels/DatagramChannel.java
@@ -40,7 +40,7 @@ import java.nio.channels.spi.SelectorProvider;
* same time.
*/
public abstract class DatagramChannel extends AbstractSelectableChannel
- implements ByteChannel, ScatteringByteChannel, GatheringByteChannel {
+ implements ByteChannel, ScatteringByteChannel, GatheringByteChannel, NetworkChannel {
/**
* Constructs a new {@code DatagramChannel}.
@@ -88,6 +88,22 @@ public abstract class DatagramChannel extends AbstractSelectableChannel
*/
public abstract DatagramSocket socket();
+ /** @hide Until ready for a public API change */
+ @Override
+ public DatagramChannel bind(SocketAddress local) throws IOException {
+ // This method was added for interoperability with Java 7, where it is abstract. It is
+ // concrete here to avoid breaking existing Android applications that extend this class.
+ throw new UnsupportedOperationException("Subclasses must override this method");
+ }
+
+ /** @hide Until ready for a public API change */
+ @Override
+ public SocketAddress getLocalAddress() throws IOException {
+ // This method was added for interoperability with Java 7, where it is abstract. It is
+ // concrete here to avoid breaking existing Android applications that extend this class.
+ throw new UnsupportedOperationException("Subclasses must override this method");
+ }
+
/**
* Returns whether this channel's socket is connected or not.
*
diff --git a/luni/src/main/java/java/nio/channels/NetworkChannel.java b/luni/src/main/java/java/nio/channels/NetworkChannel.java
new file mode 100644
index 0000000..b3505b9
--- /dev/null
+++ b/luni/src/main/java/java/nio/channels/NetworkChannel.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2014 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 java.nio.channels;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.net.SocketAddress;
+
+/**
+ * A common interface for channels that are backed by network sockets.
+ *
+ * @since 1.7
+ * @hide Until ready for a public API change
+ */
+public interface NetworkChannel extends AutoCloseable, Channel, Closeable {
+
+ /**
+ * Binds this channel to the given local socket address. If the {@code localAddr} is set
+ * to {@code null} the socket will be bound to an available local address on any free port of
+ * the system.
+ *
+ * @param local
+ * the local machine address and port to bind on.
+ * @return this channel.
+ * @throws UnsupportedAddressTypeException
+ * if the {@code SocketAddress} is not supported.
+ * @throws ClosedChannelException
+ * if the channel is closed.
+ * @throws AlreadyBoundException
+ * if the channel is already bound.
+ * @throws IOException
+ * if another I/O error occurs.
+ * @hide Until ready for a public API change
+ */
+ NetworkChannel bind(SocketAddress local) throws IOException;
+
+ /**
+ * Returns the local socket address the channel is bound to. The socket may be bound explicitly
+ * via {@link #bind(java.net.SocketAddress)} or similar methods, or as a side-effect when other
+ * methods are called, depending on the implementation. If the channel is not bound {@code null}
+ * is returned.
+ *
+ * <p>If IP is being used, the returned object will be a subclass of
+ * {@link java.net.InetSocketAddress}
+ *
+ * @return the local socket address, or {@code null} if the socket is not bound
+ * @throws ClosedChannelException
+ * if the channel is closed.
+ * @throws IOException
+ * if another I/O error occurs.
+ * @hide Until ready for a public API change
+ */
+ SocketAddress getLocalAddress() throws IOException;
+}
diff --git a/luni/src/main/java/java/nio/channels/ServerSocketChannel.java b/luni/src/main/java/java/nio/channels/ServerSocketChannel.java
index f3c3390..aeb6d8f 100644
--- a/luni/src/main/java/java/nio/channels/ServerSocketChannel.java
+++ b/luni/src/main/java/java/nio/channels/ServerSocketChannel.java
@@ -19,6 +19,7 @@ package java.nio.channels;
import java.io.IOException;
import java.net.ServerSocket;
+import java.net.SocketAddress;
import java.nio.channels.spi.AbstractSelectableChannel;
import java.nio.channels.spi.SelectorProvider;
@@ -34,7 +35,8 @@ import java.nio.channels.spi.SelectorProvider;
* {@link NotYetBoundException}. It can be bound by calling the bind method of a
* related {@code ServerSocket} instance.
*/
-public abstract class ServerSocketChannel extends AbstractSelectableChannel {
+public abstract class ServerSocketChannel extends AbstractSelectableChannel
+ implements NetworkChannel {
/**
* Constructs a new {@link ServerSocketChannel}.
@@ -82,6 +84,52 @@ public abstract class ServerSocketChannel extends AbstractSelectableChannel {
public abstract ServerSocket socket();
/**
+ * {@inheritDoc}
+ *
+ * <p>This is equivalent to {@code bind(local, 0)}.
+ * @hide Until ready for a public API change
+ */
+ @Override
+ public final ServerSocketChannel bind(SocketAddress local) throws IOException {
+ return bind(local, 0);
+ }
+
+ /**
+ * Binds this server channel to the given local socket address. If the {@code localAddr} is set
+ * to {@code null} the socket will be bound to an available local address on any free port of
+ * the system.
+ *
+ * @param localAddr
+ * the local machine address and port to bind on.
+ * @param backlog the maximum number of unaccepted connections. Passing 0 or
+ * a negative value yields the default backlog of 50.
+ * @return this {@code ServerSocketChannel}.
+ * @throws UnsupportedAddressTypeException
+ * if the {@code SocketAddress} is not supported.
+ * @throws ClosedChannelException
+ * if the channel is closed.
+ * @throws AlreadyBoundException
+ * if the channel is already bound.
+ * @throws IOException
+ * if another I/O error occurs.
+ * @since 1.7
+ * @hide Until ready for a public API change
+ */
+ public ServerSocketChannel bind(SocketAddress localAddr, int backlog) throws IOException {
+ // This method was added for interoperability with Java 7, where it is abstract. It is
+ // concrete here to avoid breaking existing Android applications that extend this class.
+ throw new UnsupportedOperationException("Subclasses must override this method");
+ }
+
+ /** @hide Until ready for a public API change */
+ @Override
+ public SocketAddress getLocalAddress() throws IOException {
+ // This method was added for interoperability with Java 7, where it is abstract. It is
+ // concrete here to avoid breaking existing Android applications that extend this class.
+ throw new UnsupportedOperationException("Subclasses must override this method");
+ }
+
+ /**
* Accepts a connection to this server-socket channel.
* <p>
* This method returns {@code null} when this channel is non-blocking and no
diff --git a/luni/src/main/java/java/nio/channels/SocketChannel.java b/luni/src/main/java/java/nio/channels/SocketChannel.java
index da5b7ea..12dfe38 100644
--- a/luni/src/main/java/java/nio/channels/SocketChannel.java
+++ b/luni/src/main/java/java/nio/channels/SocketChannel.java
@@ -62,7 +62,7 @@ import java.nio.channels.spi.SelectorProvider;
* processing, calls to {@link #read} and {@link #write} will block.
*/
public abstract class SocketChannel extends AbstractSelectableChannel implements
- ByteChannel, ScatteringByteChannel, GatheringByteChannel {
+ ByteChannel, ScatteringByteChannel, GatheringByteChannel, NetworkChannel {
/**
* Constructs a new {@code SocketChannel}.
@@ -140,6 +140,22 @@ public abstract class SocketChannel extends AbstractSelectableChannel implements
*/
public abstract Socket socket();
+ /** @hide Until ready for a public API change */
+ @Override
+ public SocketChannel bind(SocketAddress local) throws IOException {
+ // This method was added for interoperability with Java 7, where it is abstract. It is
+ // concrete here to avoid breaking existing Android applications that extend this class.
+ throw new UnsupportedOperationException("Subclasses must override this method");
+ }
+
+ /** @hide Until ready for a public API change */
+ @Override
+ public SocketAddress getLocalAddress() throws IOException {
+ // This method was added for interoperability with Java 7, where it is abstract. It is
+ // concrete here to avoid breaking existing Android applications that extend this class.
+ throw new UnsupportedOperationException("Subclasses must override this method");
+ }
+
/**
* Indicates whether this channel's socket is connected.
*
diff --git a/luni/src/test/java/libcore/java/net/DatagramSocketTest.java b/luni/src/test/java/libcore/java/net/DatagramSocketTest.java
new file mode 100644
index 0000000..86e47ec
--- /dev/null
+++ b/luni/src/test/java/libcore/java/net/DatagramSocketTest.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2014 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 libcore.java.net;
+
+import junit.framework.TestCase;
+
+import java.net.DatagramSocket;
+import java.net.InetSocketAddress;
+
+public class DatagramSocketTest extends TestCase {
+
+ public void testInitialState() throws Exception {
+ DatagramSocket ds = new DatagramSocket();
+ try {
+ assertTrue(ds.isBound());
+ assertTrue(ds.getBroadcast()); // The RI starts DatagramSocket in broadcast mode.
+ assertFalse(ds.isClosed());
+ assertFalse(ds.isConnected());
+ assertTrue(ds.getLocalPort() > 0);
+ assertTrue(ds.getLocalAddress().isAnyLocalAddress());
+ InetSocketAddress socketAddress = (InetSocketAddress) ds.getLocalSocketAddress();
+ assertEquals(ds.getLocalPort(), socketAddress.getPort());
+ assertEquals(ds.getLocalAddress(), socketAddress.getAddress());
+ assertNull(ds.getInetAddress());
+ assertEquals(-1, ds.getPort());
+ assertNull(ds.getRemoteSocketAddress());
+ assertFalse(ds.getReuseAddress());
+ assertNull(ds.getChannel());
+ } finally {
+ ds.close();
+ }
+ }
+
+ public void testStateAfterClose() throws Exception {
+ DatagramSocket ds = new DatagramSocket();
+ ds.close();
+ assertTrue(ds.isBound());
+ assertTrue(ds.isClosed());
+ assertFalse(ds.isConnected());
+ assertNull(ds.getLocalAddress());
+ assertEquals(-1, ds.getLocalPort());
+ assertNull(ds.getLocalSocketAddress());
+ }
+}
diff --git a/luni/src/test/java/libcore/java/net/ServerSocketTest.java b/luni/src/test/java/libcore/java/net/ServerSocketTest.java
index fe9d423..d82e934 100644
--- a/luni/src/test/java/libcore/java/net/ServerSocketTest.java
+++ b/luni/src/test/java/libcore/java/net/ServerSocketTest.java
@@ -17,6 +17,8 @@
package libcore.java.net;
import java.io.IOException;
+import java.net.Inet4Address;
+import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
@@ -43,4 +45,34 @@ public class ServerSocketTest extends junit.framework.TestCase {
t.join();
assertEquals(0, result[0].getSoTimeout());
}
+
+ public void testInitialState() throws Exception {
+ ServerSocket ss = new ServerSocket();
+ try {
+ assertFalse(ss.isBound());
+ assertFalse(ss.isClosed());
+ assertEquals(-1, ss.getLocalPort());
+ assertNull(ss.getLocalSocketAddress());
+ assertNull(ss.getInetAddress());
+ assertTrue(ss.getReuseAddress());
+ assertNull(ss.getChannel());
+ } finally {
+ ss.close();
+ }
+ }
+
+ public void testStateAfterClose() throws Exception {
+ ServerSocket ss = new ServerSocket();
+ ss.bind(new InetSocketAddress(Inet4Address.getLocalHost(), 0));
+ InetSocketAddress boundAddress = (InetSocketAddress) ss.getLocalSocketAddress();
+ ss.close();
+
+ assertTrue(ss.isBound());
+ assertTrue(ss.isClosed());
+ assertEquals(boundAddress.getAddress(), ss.getInetAddress());
+ assertEquals(boundAddress.getPort(), ss.getLocalPort());
+
+ InetSocketAddress localAddressAfterClose = (InetSocketAddress) ss.getLocalSocketAddress();
+ assertEquals(boundAddress, localAddressAfterClose);
+ }
}
diff --git a/luni/src/test/java/libcore/java/net/SocketTest.java b/luni/src/test/java/libcore/java/net/SocketTest.java
index 42b7250..b9ed99c 100644
--- a/luni/src/test/java/libcore/java/net/SocketTest.java
+++ b/luni/src/test/java/libcore/java/net/SocketTest.java
@@ -20,6 +20,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ConnectException;
+import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
@@ -89,7 +90,7 @@ public class SocketTest extends junit.framework.TestCase {
// Open a local server port.
ServerSocketChannel ssc = ServerSocketChannel.open();
InetSocketAddress listenAddr = new InetSocketAddress(host, 0);
- ssc.socket().bind(listenAddr, 0);
+ ssc.bind(listenAddr, 0);
ServerSocket ss = ssc.socket();
// Open a socket to the local port.
@@ -109,10 +110,12 @@ public class SocketTest extends junit.framework.TestCase {
in.socket().setTcpNoDelay(false);
}
+ InetSocketAddress listenAddress = (InetSocketAddress) in.getLocalAddress();
InetSocketAddress outRemoteAddress = (InetSocketAddress) out.socket().getRemoteSocketAddress();
InetSocketAddress outLocalAddress = (InetSocketAddress) out.socket().getLocalSocketAddress();
InetSocketAddress inLocalAddress = (InetSocketAddress) in.socket().getLocalSocketAddress();
InetSocketAddress inRemoteAddress = (InetSocketAddress) in.socket().getRemoteSocketAddress();
+ System.err.println("listenAddress: " + listenAddr);
System.err.println("inLocalAddress: " + inLocalAddress);
System.err.println("inRemoteAddress: " + inRemoteAddress);
System.err.println("outLocalAddress: " + outLocalAddress);
@@ -127,14 +130,42 @@ public class SocketTest extends junit.framework.TestCase {
assertEquals(outLocalAddress.getAddress(), ss.getInetAddress());
assertEquals(outRemoteAddress.getAddress(), ss.getInetAddress());
+ assertFalse(ssc.socket().isClosed());
+ assertTrue(ssc.socket().isBound());
+ assertTrue(in.isConnected());
+ assertTrue(in.socket().isConnected());
+ assertTrue(out.socket().isConnected());
+ assertTrue(out.isConnected());
+
in.close();
out.close();
ssc.close();
+ assertTrue(ssc.socket().isClosed());
+ assertTrue(ssc.socket().isBound());
+ assertFalse(in.isConnected());
+ assertFalse(in.socket().isConnected());
+ assertFalse(out.socket().isConnected());
+ assertFalse(out.isConnected());
+
assertNull(in.socket().getRemoteSocketAddress());
assertNull(out.socket().getRemoteSocketAddress());
- assertEquals(in.socket().getLocalSocketAddress(), ss.getLocalSocketAddress());
+ // As per docs and RI - server socket local address methods continue to return the bind()
+ // addresses even after close().
+ assertEquals(listenAddress, ssc.socket().getLocalSocketAddress());
+
+ // As per docs and RI - socket local address methods return the wildcard address before
+ // bind() and after close(), but the port will be the same as it was before close().
+ InetSocketAddress inLocalAddressAfterClose =
+ (InetSocketAddress) in.socket().getLocalSocketAddress();
+ assertTrue(inLocalAddressAfterClose.getAddress().isAnyLocalAddress());
+ assertEquals(inLocalAddress.getPort(), inLocalAddressAfterClose.getPort());
+
+ InetSocketAddress outLocalAddressAfterClose =
+ (InetSocketAddress) out.socket().getLocalSocketAddress();
+ assertTrue(outLocalAddressAfterClose.getAddress().isAnyLocalAddress());
+ assertEquals(outLocalAddress.getPort(), outLocalAddressAfterClose.getPort());
}
// SocketOptions.setOption has weird behavior for setSoLinger/SO_LINGER.
@@ -286,6 +317,42 @@ public class SocketTest extends junit.framework.TestCase {
serverSocket.close();
}
+ public void testInitialState() throws Exception {
+ Socket s = new Socket();
+ try {
+ assertFalse(s.isBound());
+ assertFalse(s.isClosed());
+ assertFalse(s.isConnected());
+ assertEquals(-1, s.getLocalPort());
+ assertTrue(s.getLocalAddress().isAnyLocalAddress());
+ assertNull(s.getLocalSocketAddress());
+ assertNull(s.getInetAddress());
+ assertEquals(0, s.getPort());
+ assertNull(s.getRemoteSocketAddress());
+ assertFalse(s.getReuseAddress());
+ assertNull(s.getChannel());
+ } finally {
+ s.close();
+ }
+ }
+
+ public void testStateAfterClose() throws Exception {
+ Socket s = new Socket();
+ s.bind(new InetSocketAddress(Inet4Address.getLocalHost(), 0));
+ InetSocketAddress boundAddress = (InetSocketAddress) s.getLocalSocketAddress();
+ s.close();
+
+ assertTrue(s.isBound());
+ assertTrue(s.isClosed());
+ assertFalse(s.isConnected());
+ assertTrue(s.getLocalAddress().isAnyLocalAddress());
+ assertEquals(boundAddress.getPort(), s.getLocalPort());
+
+ InetSocketAddress localAddressAfterClose = (InetSocketAddress) s.getLocalSocketAddress();
+ assertTrue(localAddressAfterClose.getAddress().isAnyLocalAddress());
+ assertEquals(boundAddress.getPort(), localAddressAfterClose.getPort());
+ }
+
static class MockServer {
private ExecutorService executor;
private ServerSocket serverSocket;
diff --git a/luni/src/test/java/libcore/java/nio/channels/DatagramChannelTest.java b/luni/src/test/java/libcore/java/nio/channels/DatagramChannelTest.java
index 13757d2..a0092d0 100644
--- a/luni/src/test/java/libcore/java/nio/channels/DatagramChannelTest.java
+++ b/luni/src/test/java/libcore/java/nio/channels/DatagramChannelTest.java
@@ -48,11 +48,35 @@ public class DatagramChannelTest extends junit.framework.TestCase {
DatagramChannel dc = DatagramChannel.open();
try {
dc.configureBlocking(false);
- dc.socket().bind(null);
+ dc.bind(null);
// Should return immediately, since we're non-blocking.
assertNull(dc.receive(ByteBuffer.allocate(2048)));
} finally {
dc.close();
}
}
+
+ public void testInitialState() throws Exception {
+ DatagramChannel dc = DatagramChannel.open();
+ try {
+ assertNull(dc.getLocalAddress());
+
+ DatagramSocket socket = dc.socket();
+ assertFalse(socket.isBound());
+ assertFalse(socket.getBroadcast());
+ assertFalse(socket.isClosed());
+ assertFalse(socket.isConnected());
+ assertEquals(0, socket.getLocalPort());
+ assertTrue(socket.getLocalAddress().isAnyLocalAddress());
+ assertNull(socket.getLocalSocketAddress());
+ assertNull(socket.getInetAddress());
+ assertEquals(-1, socket.getPort());
+ assertNull(socket.getRemoteSocketAddress());
+ assertFalse(socket.getReuseAddress());
+
+ assertSame(dc, socket.getChannel());
+ } finally {
+ dc.close();
+ }
+ }
}
diff --git a/luni/src/test/java/libcore/java/nio/channels/ServerSocketChannelTest.java b/luni/src/test/java/libcore/java/nio/channels/ServerSocketChannelTest.java
index e66096c..bceb759 100644
--- a/luni/src/test/java/libcore/java/nio/channels/ServerSocketChannelTest.java
+++ b/luni/src/test/java/libcore/java/nio/channels/ServerSocketChannelTest.java
@@ -16,7 +16,14 @@
package libcore.java.nio.channels;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.NetworkInterface;
+import java.net.ServerSocket;
import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.SocketChannel;
+import java.util.Enumeration;
public class ServerSocketChannelTest extends junit.framework.TestCase {
// http://code.google.com/p/android/issues/detail?id=16579
@@ -24,11 +31,100 @@ public class ServerSocketChannelTest extends junit.framework.TestCase {
ServerSocketChannel ssc = ServerSocketChannel.open();
try {
ssc.configureBlocking(false);
- ssc.socket().bind(null);
+ ssc.bind(null);
// Should return immediately, since we're non-blocking.
assertNull(ssc.accept());
} finally {
ssc.close();
}
}
+
+ /** Checks the state of the ServerSocketChannel and associated ServerSocket after open() */
+ public void test_open_initialState() throws Exception {
+ ServerSocketChannel ssc = ServerSocketChannel.open();
+ try {
+ assertNull(ssc.getLocalAddress());
+
+ ServerSocket socket = ssc.socket();
+ assertFalse(socket.isBound());
+ assertFalse(socket.isClosed());
+ assertEquals(-1, socket.getLocalPort());
+ assertNull(socket.getLocalSocketAddress());
+ assertNull(socket.getInetAddress());
+ assertTrue(socket.getReuseAddress());
+
+ assertSame(ssc, socket.getChannel());
+ } finally {
+ ssc.close();
+ }
+ }
+
+ public void test_bind_nullBindsToAll() throws Exception {
+ ServerSocketChannel ssc = ServerSocketChannel.open();
+ ssc.bind(null);
+ InetSocketAddress boundAddress = (InetSocketAddress) ssc.getLocalAddress();
+ assertTrue(boundAddress.getAddress().isAnyLocalAddress());
+ assertFalse(boundAddress.getAddress().isLinkLocalAddress());
+ assertFalse(boundAddress.getAddress().isLoopbackAddress());
+
+ // Attempt to connect to the "any" address.
+ assertTrue(canConnect(boundAddress));
+
+ // Go through all local IPs and try to connect to each in turn - all should succeed.
+ Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
+ while (interfaces.hasMoreElements()) {
+ NetworkInterface nic = interfaces.nextElement();
+ Enumeration<InetAddress> inetAddresses = nic.getInetAddresses();
+ while (inetAddresses.hasMoreElements()) {
+ InetSocketAddress address =
+ new InetSocketAddress(inetAddresses.nextElement(), boundAddress.getPort());
+ assertTrue(canConnect(address));
+ }
+ }
+
+ ssc.close();
+ }
+
+ public void test_bind_loopback() throws Exception {
+ ServerSocketChannel ssc = ServerSocketChannel.open();
+ ssc.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0));
+ InetSocketAddress boundAddress = (InetSocketAddress) ssc.getLocalAddress();
+ assertFalse(boundAddress.getAddress().isAnyLocalAddress());
+ assertFalse(boundAddress.getAddress().isLinkLocalAddress());
+ assertTrue(boundAddress.getAddress().isLoopbackAddress());
+
+ // Attempt to connect to the "loopback" address. Note: There can be several loopback
+ // addresses, such as 127.0.0.1 (IPv4) and 0:0:0:0:0:0:0:1 (IPv6) and only one will be
+ // bound.
+ InetSocketAddress loopbackAddress =
+ new InetSocketAddress(InetAddress.getLoopbackAddress(), boundAddress.getPort());
+ assertTrue(canConnect(loopbackAddress));
+
+ // Go through all local IPs and try to connect to each in turn - all should fail except
+ // for the loopback.
+ Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
+ while (interfaces.hasMoreElements()) {
+ NetworkInterface nic = interfaces.nextElement();
+ Enumeration<InetAddress> inetAddresses = nic.getInetAddresses();
+ while (inetAddresses.hasMoreElements()) {
+ InetSocketAddress address =
+ new InetSocketAddress(inetAddresses.nextElement(), boundAddress.getPort());
+ if (!address.equals(loopbackAddress)) {
+ assertFalse(canConnect(address));
+ }
+ }
+ }
+
+ ssc.close();
+ }
+
+ private static boolean canConnect(InetSocketAddress address) {
+ try {
+ SocketChannel socketChannel = SocketChannel.open(address);
+ socketChannel.close();
+ return true;
+ } catch (IOException e) {
+ return false;
+ }
+ }
}
diff --git a/luni/src/test/java/libcore/java/nio/channels/SocketChannelTest.java b/luni/src/test/java/libcore/java/nio/channels/SocketChannelTest.java
index fbb2d8d..553e20c 100644
--- a/luni/src/test/java/libcore/java/nio/channels/SocketChannelTest.java
+++ b/luni/src/test/java/libcore/java/nio/channels/SocketChannelTest.java
@@ -16,29 +16,34 @@
package libcore.java.nio.channels;
+import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ConnectException;
+import java.net.Socket;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
-import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
+import java.nio.channels.SocketChannel;
import java.nio.channels.Selector;
import java.nio.channels.SelectionKey;
-import java.nio.channels.SocketChannel;
import tests.io.MockOs;
+
import static libcore.io.OsConstants.*;
public class SocketChannelTest extends junit.framework.TestCase {
+
private final MockOs mockOs = new MockOs();
- @Override public void setUp() throws Exception {
+ @Override
+ public void setUp() throws Exception {
mockOs.install();
}
- @Override protected void tearDown() throws Exception {
+ @Override
+ protected void tearDown() throws Exception {
mockOs.uninstall();
}
@@ -129,6 +134,81 @@ public class SocketChannelTest extends junit.framework.TestCase {
ss.close();
}
+ /** Checks the state of the SocketChannel and associated Socket after open() */
+ public void test_open_initialState() throws Exception {
+ SocketChannel sc = SocketChannel.open();
+ try {
+ assertNull(sc.getLocalAddress());
+
+ Socket socket = sc.socket();
+ assertFalse(socket.isBound());
+ assertFalse(socket.isClosed());
+ assertFalse(socket.isConnected());
+ assertEquals(-1, socket.getLocalPort());
+ assertTrue(socket.getLocalAddress().isAnyLocalAddress());
+ assertNull(socket.getLocalSocketAddress());
+ assertNull(socket.getInetAddress());
+ assertEquals(0, socket.getPort());
+ assertNull(socket.getRemoteSocketAddress());
+ assertFalse(socket.getReuseAddress());
+
+ assertSame(sc, socket.getChannel());
+ } finally {
+ sc.close();
+ }
+ }
+
+ /** Checks that the SocketChannel and associated Socket agree on the socket state. */
+ public void test_bind_socketStateSync() throws IOException {
+ SocketChannel sc = SocketChannel.open();
+ assertNull(sc.getLocalAddress());
+
+ Socket socket = sc.socket();
+ assertNull(socket.getLocalSocketAddress());
+ assertFalse(socket.isBound());
+
+ InetSocketAddress bindAddr = new InetSocketAddress("localhost", 0);
+ sc.bind(bindAddr);
+
+ InetSocketAddress actualAddr = (InetSocketAddress) sc.getLocalAddress();
+ assertEquals(actualAddr, socket.getLocalSocketAddress());
+ assertEquals(bindAddr.getHostName(), actualAddr.getHostName());
+ assertTrue(socket.isBound());
+ assertFalse(socket.isConnected());
+ assertFalse(socket.isClosed());
+
+ sc.close();
+
+ assertFalse(sc.isOpen());
+ assertTrue(socket.isClosed());
+ }
+
+ /**
+ * Checks that the SocketChannel and associated Socket agree on the socket state, even if
+ * the Socket object is requested/created after bind().
+ */
+ public void test_bind_socketObjectCreationAfterBind() throws IOException {
+ SocketChannel sc = SocketChannel.open();
+ assertNull(sc.getLocalAddress());
+
+ InetSocketAddress bindAddr = new InetSocketAddress("localhost", 0);
+ sc.bind(bindAddr);
+
+ // Socket object creation after bind().
+ Socket socket = sc.socket();
+ InetSocketAddress actualAddr = (InetSocketAddress) sc.getLocalAddress();
+ assertEquals(actualAddr, socket.getLocalSocketAddress());
+ assertEquals(bindAddr.getHostName(), actualAddr.getHostName());
+ assertTrue(socket.isBound());
+ assertFalse(socket.isConnected());
+ assertFalse(socket.isClosed());
+
+ sc.close();
+
+ assertFalse(sc.isOpen());
+ assertTrue(socket.isClosed());
+ }
+
/**
* Tests connect() and object state for a blocking SocketChannel. Blocking mode is the default.
*/