/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.harmony.tests.java.nio.channels; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket; import java.nio.ByteBuffer; import java.nio.channels.AsynchronousCloseException; import java.nio.channels.ClosedChannelException; import java.nio.channels.IllegalBlockingModeException; import java.nio.channels.NotYetBoundException; import java.nio.channels.SelectionKey; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.nio.channels.spi.SelectorProvider; import junit.framework.TestCase; /* * test for ServerSocketChannel */ public class ServerSocketChannelTest extends TestCase { private static final int CAPACITY_NORMAL = 200; private static final int CAPACITY_64KB = 65536; private static final int TIME_UNIT = 200; private ServerSocketChannel serverChannel; private SocketChannel clientChannel; protected void setUp() throws Exception { super.setUp(); this.serverChannel = ServerSocketChannel.open(); this.clientChannel = SocketChannel.open(); } protected void tearDown() throws Exception { if (null != this.serverChannel) { try { this.serverChannel.close(); } catch (Exception e) { //ignore } } if (null != this.clientChannel) { try { this.clientChannel.close(); } catch (Exception e) { //ignore } } super.tearDown(); } // ------------------------------------------------------------------- // Test for methods in abstract class. // ------------------------------------------------------------------- /* * Test method for 'java.nio.channels.ServerSocketChannel.validOps()' */ public void testValidOps() { MockServerSocketChannel testMSChnlnull = new MockServerSocketChannel( null); MockServerSocketChannel testMSChnl = new MockServerSocketChannel( SelectorProvider.provider()); assertEquals(SelectionKey.OP_ACCEPT, this.serverChannel.validOps()); assertEquals(SelectionKey.OP_ACCEPT, testMSChnl.validOps()); assertEquals(SelectionKey.OP_ACCEPT, testMSChnlnull.validOps()); } /* * Test method for 'java.nio.channels.ServerSocketChannel.open()' */ public void testOpen() { MockServerSocketChannel testMSChnl = new MockServerSocketChannel(null); MockServerSocketChannel testMSChnlnotnull = new MockServerSocketChannel( SelectorProvider.provider()); assertEquals(SelectionKey.OP_ACCEPT, testMSChnlnotnull.validOps()); assertNull(testMSChnl.provider()); assertNotNull(testMSChnlnotnull.provider()); assertNotNull(this.serverChannel.provider()); assertEquals(testMSChnlnotnull.provider(), this.serverChannel .provider()); } // ------------------------------------------------------------------- // Tests for bind() // ------------------------------------------------------------------- public void test_bind_null() throws Exception { ServerSocketChannel ssc = ServerSocketChannel.open(); try { assertNull(ssc.socket().getLocalSocketAddress()); ssc.socket().bind(null); InetSocketAddress localAddress = (InetSocketAddress) ssc.socket().getLocalSocketAddress(); assertTrue(localAddress.getAddress().isAnyLocalAddress()); assertTrue(localAddress.getPort() > 0); } finally { ssc.close(); } } public void test_bind_failure() throws Exception { ServerSocketChannel portHog = ServerSocketChannel.open(); portHog.socket().bind(null); ServerSocketChannel ssc = ServerSocketChannel.open(); try { // Bind to a local address that is in use ssc.socket().bind(portHog.socket().getLocalSocketAddress()); fail(); } catch (IOException expected) { } finally { ssc.close(); portHog.close(); } } public void test_bind_closed() throws Exception { ServerSocketChannel ssc = ServerSocketChannel.open(); ssc.close(); try { ssc.socket().bind(null); fail(); } catch (IOException expected) { } finally { ssc.close(); } } public void test_bind_explicitPort() throws Exception { ServerSocketChannel portPickingChannel = ServerSocketChannel.open(); // Have the OS find a free port. portPickingChannel.socket().bind(null); InetSocketAddress address = (InetSocketAddress) portPickingChannel.socket().getLocalSocketAddress(); 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.socket().bind(bindAddress); InetSocketAddress boundAddress = (InetSocketAddress) ssc.socket().getLocalSocketAddress(); 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.socket().getLocalSocketAddress()); ServerSocket socket = ssc.socket(); assertNull(socket.getLocalSocketAddress()); assertFalse(socket.isBound()); InetSocketAddress bindAddr = new InetSocketAddress("localhost", 0); ssc.socket().bind(bindAddr); InetSocketAddress actualAddr = (InetSocketAddress) ssc.socket().getLocalSocketAddress(); 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.socket().getLocalSocketAddress()); InetSocketAddress bindAddr = new InetSocketAddress("localhost", 0); ssc.socket().bind(bindAddr); // Socket creation after bind(). ServerSocket socket = ssc.socket(); InetSocketAddress actualAddr = (InetSocketAddress) ssc.socket().getLocalSocketAddress(); 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.socket().getLocalSocketAddress()); InetSocketAddress bindAddr = new InetSocketAddress("localhost", 0); ssc.socket().bind(bindAddr); assertNotNull(ssc.socket().getLocalSocketAddress()); ssc.close(); assertFalse(ssc.isOpen()); ssc.socket().getLocalSocketAddress(); } // ------------------------------------------------------------------- // Test for socket() // ------------------------------------------------------------------- /* * Test method for 'java.nio.channels.ServerSocketChannel.socket()' */ public void testSocket_Block_BeforeClose() throws Exception { assertTrue(this.serverChannel.isOpen()); assertTrue(this.serverChannel.isBlocking()); ServerSocket s1 = this.serverChannel.socket(); assertFalse(s1.isClosed()); assertSocketNotAccepted(s1); ServerSocket s2 = this.serverChannel.socket(); // same assertSame(s1, s2); // socket close makes the channel close s1.close(); assertFalse(this.serverChannel.isOpen()); } public void testSocket_NonBlock_BeforeClose() throws Exception { assertTrue(this.serverChannel.isOpen()); this.serverChannel.configureBlocking(false); ServerSocket s1 = this.serverChannel.socket(); assertFalse(s1.isClosed()); assertSocketNotAccepted(s1); ServerSocket s2 = this.serverChannel.socket(); // same assertSame(s1, s2); // socket close makes the channel close s1.close(); assertFalse(this.serverChannel.isOpen()); } public void testSocket_Block_Closed() throws Exception { this.serverChannel.close(); assertFalse(this.serverChannel.isOpen()); assertTrue(this.serverChannel.isBlocking()); ServerSocket s1 = this.serverChannel.socket(); assertTrue(s1.isClosed()); assertSocketNotAccepted(s1); ServerSocket s2 = this.serverChannel.socket(); // same assertSame(s1, s2); } public void testSocket_NonBlock_Closed() throws Exception { this.serverChannel.configureBlocking(false); this.serverChannel.close(); assertFalse(this.serverChannel.isBlocking()); assertFalse(this.serverChannel.isOpen()); ServerSocket s1 = this.serverChannel.socket(); assertTrue(s1.isClosed()); assertSocketNotAccepted(s1); ServerSocket s2 = this.serverChannel.socket(); // same assertSame(s1, s2); } private void assertSocketNotAccepted(ServerSocket s) throws IOException { assertFalse(s.isBound()); assertNull(s.getInetAddress()); assertEquals(-1, s.getLocalPort()); assertNull(s.getLocalSocketAddress()); try { assertEquals(0, s.getSoTimeout()); } catch (IOException expected) { // Android doesn't cache the timeout, so the getsockopt(2) fails and throws. } } public void testChannelBasicStatus() { ServerSocket gotSocket = this.serverChannel.socket(); assertFalse(gotSocket.isClosed()); assertTrue(this.serverChannel.isBlocking()); assertFalse(this.serverChannel.isRegistered()); assertEquals(SelectionKey.OP_ACCEPT, this.serverChannel.validOps()); assertEquals(SelectorProvider.provider(), this.serverChannel.provider()); } // ------------------------------------------------------------------- // Test for accept() // ------------------------------------------------------------------- /* * Test method for 'java.nio.channels.ServerSocketChannel.accept()' */ public void testAccept_Block_NotYetBound() throws IOException { assertTrue(this.serverChannel.isOpen()); assertTrue(this.serverChannel.isBlocking()); try { this.serverChannel.accept(); fail("Should throw NotYetBoundException"); } catch (NotYetBoundException e) { // correct } } public void testAccept_NonBlock_NotYetBound() throws IOException { assertTrue(this.serverChannel.isOpen()); this.serverChannel.configureBlocking(false); try { this.serverChannel.accept(); fail("Should throw NotYetBoundException"); } catch (NotYetBoundException e) { // correct } } public void testAccept_ClosedChannel() throws Exception { this.serverChannel.close(); assertFalse(this.serverChannel.isOpen()); try { this.serverChannel.accept(); fail("Should throw ClosedChannelException"); } catch (ClosedChannelException e) { // OK. } } public void testAccept_Block_NoConnect() throws IOException { assertTrue(this.serverChannel.isBlocking()); serverChannel.socket().bind(null); // blocking mode , will block and wait for ever... // so must close the server channel with another thread. new Thread() { public void run() { try { Thread.sleep(TIME_UNIT); ServerSocketChannelTest.this.serverChannel.close(); } catch (Exception e) { fail("Fail to close the server channel because of" + e.getClass().getName()); } } }.start(); try { this.serverChannel.accept(); fail("Should throw a AsynchronousCloseException"); } catch (AsynchronousCloseException e) { // OK. } } public void testAccept_NonBlock_NoConnect() throws IOException { this.serverChannel.socket().bind(null); this.serverChannel.configureBlocking(false); // non-blocking mode , will immediately return assertNull(this.serverChannel.accept()); } /** * @tests ServerSocketChannel#accept().socket() */ public void test_read_Blocking_RealData() throws IOException { serverChannel.socket().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()); Socket serverSocket = serverChannel.accept().socket(); InputStream in = serverSocket.getInputStream(); buf.flip(); clientChannel.write(buf); clientChannel.close(); assertReadResult(in,CAPACITY_NORMAL); } /** * Asserts read content. The read content should contain <code>size</code> * bytes, and the value should be a sequence from 0 to size-1 * ([0,1,...size-1]). Otherwise, the method throws Exception. * */ private void assertReadResult(InputStream in, int size) throws IOException{ byte[] readContent = new byte[size + 1]; int count = 0; int total = 0; while ((count = in.read(readContent, total, size + 1 - total)) != -1) { total = total + count; } assertEquals(size, total); for (int i = 0; i < size; i++) { assertEquals((byte) i, readContent[i]); } } /** * @tests ServerSocketChannel#accept().socket() */ public void test_read_NonBlocking_RealData() throws Exception { serverChannel.configureBlocking(false); serverChannel.socket().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()); Socket serverSocket = serverChannel.accept().socket(); InputStream in = serverSocket.getInputStream(); clientChannel.write(buf); clientChannel.close(); assertReadResult(in,CAPACITY_NORMAL); } /** * @tests ServerSocketChannel#accept().socket() */ public void test_write_Blocking_RealData() throws IOException { assertTrue(serverChannel.isBlocking()); serverChannel.socket().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()); Socket socket = serverChannel.accept().socket(); OutputStream out = socket.getOutputStream(); out.write(writeContent); out.flush(); socket.close(); assertWriteResult(CAPACITY_NORMAL); } /** * @tests ServerSocketChannel#accept().socket() */ public void test_write_NonBlocking_RealData() throws Exception { serverChannel.configureBlocking(false); serverChannel.socket().bind(null); byte[] writeContent = new byte[CAPACITY_NORMAL]; for (int i = 0; i < CAPACITY_NORMAL; i++) { writeContent[i] = (byte) i; } clientChannel.connect(serverChannel.socket().getLocalSocketAddress()); Socket clientSocket = serverChannel.accept().socket(); OutputStream out = clientSocket.getOutputStream(); out.write(writeContent); clientSocket.close(); assertWriteResult(CAPACITY_NORMAL); } /** * @throws InterruptedException * @tests ServerSocketChannel#accept().socket() */ public void test_read_LByteBuffer_Blocking_ReadWriteRealLargeData() throws IOException, InterruptedException { serverChannel.socket().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()); WriteChannelThread writeThread = new WriteChannelThread(clientChannel, buf); writeThread.start(); Socket socket = serverChannel.accept().socket(); InputStream in = socket.getInputStream(); assertReadResult(in,CAPACITY_64KB); writeThread.join(); // check if the thread threw any exceptions if (writeThread.exception != null) { throw writeThread.exception; } } class WriteChannelThread extends Thread { SocketChannel channel; ByteBuffer buffer; IOException exception; public WriteChannelThread(SocketChannel channel, ByteBuffer buffer) { this.channel = channel; this.buffer = buffer; } public void run() { try { channel.write(buffer); channel.close(); } catch (IOException e) { exception = e; } } } /** * @tests ServerSocketChannel#accept().socket() */ public void test_read_LByteBuffer_NonBlocking_ReadWriteRealLargeData() throws Exception { serverChannel.configureBlocking(false); serverChannel.socket().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()); WriteChannelThread writeThread = new WriteChannelThread(clientChannel, buf); writeThread.start(); Socket socket = serverChannel.accept().socket(); InputStream in = socket.getInputStream(); assertReadResult(in,CAPACITY_64KB); writeThread.join(); // check if the thread threw any exceptions if (writeThread.exception != null) { throw writeThread.exception; } } /** * @tests ServerSocketChannel#accept().socket() */ public void test_write_LByteBuffer_NonBlocking_ReadWriteRealLargeData() throws Exception { serverChannel.configureBlocking(false); serverChannel.socket().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()); Socket socket = serverChannel.accept().socket(); WriteSocketThread writeThread = new WriteSocketThread(socket, writeContent); writeThread.start(); assertWriteResult(CAPACITY_64KB); writeThread.join(); // check if the thread threw any exceptions if (writeThread.exception != null) { throw writeThread.exception; } } class WriteSocketThread extends Thread { Socket socket; byte[] buffer; IOException exception; public WriteSocketThread(Socket socket, byte[] buffer) { this.socket = socket; this.buffer = buffer; } public void run() { try { OutputStream out = socket.getOutputStream(); out.write(buffer); socket.close(); } catch (IOException e) { exception = e; } } } /** * @tests ServerSocketChannel#accept().socket() */ public void test_write_LByteBuffer_Blocking_ReadWriteRealLargeData() throws Exception { serverChannel.socket().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()); Socket socket = serverChannel.accept().socket(); WriteSocketThread writeThread = new WriteSocketThread(socket, writeContent); writeThread.start(); assertWriteResult(CAPACITY_64KB); writeThread.join(); // check if the thread threw any exceptions if (writeThread.exception != null) { throw writeThread.exception; } } /** * Uses SocketChannel.read(ByteBuffer) to verify write result. */ private void assertWriteResult(int size) throws IOException{ ByteBuffer buf = ByteBuffer.allocate(size + 1); int count = 0; int total = 0; long beginTime = System.currentTimeMillis(); while ((count = clientChannel.read(buf)) != -1) { total = total + count; // 10s timeout to avoid dead loop if (System.currentTimeMillis() - beginTime > 10000){ break; } } assertEquals(total, size); buf.flip(); for (int i = 0; i < count; i++) { assertEquals((byte) i, buf.get(i)); } } /** * @tests ServerSocketChannel#socket().getSoTimeout() */ public void test_accept_SOTIMEOUT() throws IOException { // Regression test for Harmony-707 // The timeout actually used may be different from the one set due to // rounding by the Linux Kernel (see sock_set_timeout() in net/core/sock.c). // getSoTimeout() can return a different value from the one set with // setSoTimeout(). Consequently we do not check for equality with what was // set. ServerSocketChannel sc = ServerSocketChannel.open(); try { sc.socket().bind(null); // Non blocking mode, accept() will return NULL since there are no pending connections. sc.configureBlocking(false); ServerSocket ss = sc.socket(); int defaultTimeout = ss.getSoTimeout(); assertEquals(0, defaultTimeout); // The timeout value is unimportant, providing it is large enough to be accepted // by the Kernel as distinct from the default. final int SO_TIMEOUT = 200; ss.setSoTimeout(SO_TIMEOUT); int nonDefaultTimeout = ss.getSoTimeout(); assertTrue(nonDefaultTimeout != defaultTimeout); SocketChannel client = sc.accept(); assertNull(client); // Confirm the timeout was unchanged. assertEquals(nonDefaultTimeout, ss.getSoTimeout()); } finally { sc.close(); } } /** * @tests ServerSocket#socket().accept() */ public void test_socket_accept_Blocking_NotBound() throws IOException { // regression test for Harmony-748 ServerSocket gotSocket = serverChannel.socket(); serverChannel.configureBlocking(true); try { gotSocket.accept(); fail("Should throw an IllegalBlockingModeException"); } catch (IllegalBlockingModeException expected) { } serverChannel.close(); try { gotSocket.accept(); fail("Should throw an IllegalBlockingModeException"); } catch (IllegalBlockingModeException expected) { } } /** * @tests ServerSocket#socket().accept() */ public void test_socket_accept_Nonblocking_NotBound() throws IOException { // regression test for Harmony-748 ServerSocket gotSocket = serverChannel.socket(); serverChannel.configureBlocking(false); try { gotSocket.accept(); fail("Should throw an IllegalBlockingModeException"); } catch (IllegalBlockingModeException expected) { } serverChannel.close(); try { gotSocket.accept(); fail("Should throw an IllegalBlockingModeException"); } catch (IllegalBlockingModeException expected) { } } /** * @tests ServerSocket#socket().accept() */ public void test_socket_accept_Nonblocking_Bound() throws IOException { // regression test for Harmony-748 serverChannel.configureBlocking(false); serverChannel.socket().bind(null); ServerSocket gotSocket = serverChannel.socket(); try { gotSocket.accept(); fail("Should throw an IllegalBlockingModeException"); } catch (IllegalBlockingModeException expected) { } serverChannel.close(); try { gotSocket.accept(); fail("Should throw a ClosedChannelException"); } catch (ClosedChannelException expected) { } } /** * @tests ServerSocket#socket().accept() */ public void test_socket_accept_Blocking_Bound() throws IOException { // regression test for Harmony-748 serverChannel.configureBlocking(true); serverChannel.socket().bind(null); serverChannel.close(); try { serverChannel.socket().accept(); fail("Should throw a ClosedChannelException"); } catch (ClosedChannelException expected) { } } /** * Regression test for HARMONY-4961 */ public void test_socket_getLocalPort() throws IOException { serverChannel.socket().bind(null); clientChannel.connect(serverChannel.socket().getLocalSocketAddress()); SocketChannel myChannel = serverChannel.accept(); int port = myChannel.socket().getLocalPort(); assertEquals(serverChannel.socket().getLocalPort(), port); myChannel.close(); clientChannel.close(); serverChannel.close(); } /** * Regression test for HARMONY-6375 */ public void test_accept_configureBlocking() throws Exception { InetSocketAddress localAddr = new InetSocketAddress("localhost", 0); serverChannel.socket().bind(localAddr); // configure the channel non-blocking // when it is accepting in main thread new Thread() { public void run() { try { Thread.sleep(TIME_UNIT); serverChannel.configureBlocking(false); serverChannel.close(); } catch (Exception e) { e.printStackTrace(); } } }.start(); try { serverChannel.accept(); fail("should throw AsynchronousCloseException"); } catch (AsynchronousCloseException expected) { } serverChannel.close(); } }