Path: blob/master/test/jdk/java/net/Socket/Timeouts.java
41149 views
/*1* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/*24* @test25* @bug 822148126* @library /test/lib27* @build jdk.test.lib.Utils28* @run testng/timeout=180 Timeouts29* @summary Test Socket timeouts30*/3132import java.io.Closeable;33import java.io.IOException;34import java.io.InputStream;35import java.io.OutputStream;36import java.net.ConnectException;37import java.net.InetAddress;38import java.net.InetSocketAddress;39import java.net.ServerSocket;40import java.net.Socket;41import java.net.SocketAddress;42import java.net.SocketException;43import java.net.SocketTimeoutException;44import java.util.concurrent.Executors;45import java.util.concurrent.ExecutionException;46import java.util.concurrent.ExecutorService;47import java.util.concurrent.Future;48import java.util.concurrent.ScheduledExecutorService;49import java.util.concurrent.TimeUnit;5051import org.testng.annotations.Test;52import static org.testng.Assert.*;53import jdk.test.lib.Utils;5455@Test56public class Timeouts {5758/**59* Test timed connect where connection is established60*/61public void testTimedConnect1() throws IOException {62try (ServerSocket ss = boundServerSocket()) {63try (Socket s = new Socket()) {64s.connect(ss.getLocalSocketAddress(), 2000);65}66}67}6869/**70* Test timed connect where connection is refused71*/72public void testTimedConnect2() throws IOException {73try (Socket s = new Socket()) {74SocketAddress remote = Utils.refusingEndpoint();75try {76s.connect(remote, 10000);77} catch (ConnectException expected) { }78}79}8081/**82* Test connect with a timeout of Integer.MAX_VALUE83*/84public void testTimedConnect3() throws IOException {85try (ServerSocket ss = boundServerSocket()) {86try (Socket s = new Socket()) {87s.connect(ss.getLocalSocketAddress(), Integer.MAX_VALUE);88}89}90}9192/**93* Test connect with a negative timeout.94*/95public void testTimedConnect4() throws IOException {96try (ServerSocket ss = boundServerSocket()) {97try (Socket s = new Socket()) {98expectThrows(IllegalArgumentException.class,99() -> s.connect(ss.getLocalSocketAddress(), -1));100}101}102}103104/**105* Test timed read where the read succeeds immediately106*/107public void testTimedRead1() throws IOException {108withConnection((s1, s2) -> {109s1.getOutputStream().write(99);110s2.setSoTimeout(30*1000);111int b = s2.getInputStream().read();112assertTrue(b == 99);113});114}115116/**117* Test timed read where the read succeeds after a delay118*/119public void testTimedRead2() throws IOException {120withConnection((s1, s2) -> {121scheduleWrite(s1.getOutputStream(), 99, 2000);122s2.setSoTimeout(30*1000);123int b = s2.getInputStream().read();124assertTrue(b == 99);125});126}127128/**129* Test timed read where the read times out130*/131public void testTimedRead3() throws IOException {132withConnection((s1, s2) -> {133s2.setSoTimeout(2000);134long startMillis = millisTime();135expectThrows(SocketTimeoutException.class, () -> s2.getInputStream().read());136int timeout = s2.getSoTimeout();137checkDuration(startMillis, timeout-100, timeout+2000);138});139}140141/**142* Test timed read that succeeds after a previous read has timed out143*/144public void testTimedRead4() throws IOException {145withConnection((s1, s2) -> {146s2.setSoTimeout(2000);147expectThrows(SocketTimeoutException.class, () -> s2.getInputStream().read());148s1.getOutputStream().write(99);149int b = s2.getInputStream().read();150assertTrue(b == 99);151});152}153154/**155* Test timed read that succeeds after a previous read has timed out and156* after a short delay157*/158public void testTimedRead5() throws IOException {159withConnection((s1, s2) -> {160s2.setSoTimeout(2000);161expectThrows(SocketTimeoutException.class, () -> s2.getInputStream().read());162s2.setSoTimeout(30*3000);163scheduleWrite(s1.getOutputStream(), 99, 2000);164int b = s2.getInputStream().read();165assertTrue(b == 99);166});167}168169/**170* Test untimed read that succeeds after a previous read has timed out171*/172public void testTimedRead6() throws IOException {173withConnection((s1, s2) -> {174s2.setSoTimeout(2000);175expectThrows(SocketTimeoutException.class, () -> s2.getInputStream().read());176s1.getOutputStream().write(99);177s2.setSoTimeout(0);178int b = s2.getInputStream().read();179assertTrue(b == 99);180});181}182183/**184* Test untimed read that succeeds after a previous read has timed out and185* after a short delay186*/187public void testTimedRead7() throws IOException {188withConnection((s1, s2) -> {189s2.setSoTimeout(2000);190expectThrows(SocketTimeoutException.class, () -> s2.getInputStream().read());191scheduleWrite(s1.getOutputStream(), 99, 2000);192s2.setSoTimeout(0);193int b = s2.getInputStream().read();194assertTrue(b == 99);195});196}197198/**199* Test async close of timed read200*/201public void testTimedRead8() throws IOException {202withConnection((s1, s2) -> {203s2.setSoTimeout(30*1000);204scheduleClose(s2, 2000);205expectThrows(SocketException.class, () -> s2.getInputStream().read());206});207}208209/**210* Test read with a timeout of Integer.MAX_VALUE211*/212public void testTimedRead9() throws IOException {213withConnection((s1, s2) -> {214scheduleWrite(s1.getOutputStream(), 99, 2000);215s2.setSoTimeout(Integer.MAX_VALUE);216int b = s2.getInputStream().read();217assertTrue(b == 99);218});219}220221/**222* Test writing after a timed read.223*/224public void testTimedWrite1() throws IOException {225withConnection((s1, s2) -> {226s1.getOutputStream().write(99);227s2.setSoTimeout(3000);228int b = s2.getInputStream().read();229assertTrue(b == 99);230231// schedule thread to read s1 to EOF232scheduleReadToEOF(s1.getInputStream(), 3000);233234// write a lot so that write blocks235byte[] data = new byte[128*1024];236for (int i = 0; i < 100; i++) {237s2.getOutputStream().write(data);238}239});240}241242/**243* Test async close of writer (after a timed read).244*/245public void testTimedWrite2() throws IOException {246withConnection((s1, s2) -> {247s1.getOutputStream().write(99);248s2.setSoTimeout(3000);249int b = s2.getInputStream().read();250assertTrue(b == 99);251252// schedule s2 to be be closed253scheduleClose(s2, 3000);254255// write a lot so that write blocks256byte[] data = new byte[128*1024];257try {258while (true) {259s2.getOutputStream().write(data);260}261} catch (SocketException expected) { }262});263}264265/**266* Test timed accept where a connection is established immediately267*/268public void testTimedAccept1() throws IOException {269Socket s1 = null;270Socket s2 = null;271try (ServerSocket ss = boundServerSocket()) {272s1 = new Socket();273s1.connect(ss.getLocalSocketAddress());274ss.setSoTimeout(30*1000);275s2 = ss.accept();276} finally {277if (s1 != null) s1.close();278if (s2 != null) s2.close();279}280}281282/**283* Test timed accept where a connection is established after a short delay284*/285public void testTimedAccept2() throws IOException {286try (ServerSocket ss = boundServerSocket()) {287ss.setSoTimeout(30*1000);288scheduleConnect(ss.getLocalSocketAddress(), 2000);289Socket s = ss.accept();290s.close();291}292}293294/**295* Test timed accept where the accept times out296*/297public void testTimedAccept3() throws IOException {298try (ServerSocket ss = boundServerSocket()) {299ss.setSoTimeout(2000);300long startMillis = millisTime();301try {302Socket s = ss.accept();303s.close();304fail();305} catch (SocketTimeoutException expected) {306int timeout = ss.getSoTimeout();307checkDuration(startMillis, timeout-100, timeout+2000);308}309}310}311312/**313* Test timed accept where a connection is established immediately after a314* previous accept timed out.315*/316public void testTimedAccept4() throws IOException {317try (ServerSocket ss = boundServerSocket()) {318ss.setSoTimeout(2000);319try {320Socket s = ss.accept();321s.close();322fail();323} catch (SocketTimeoutException expected) { }324try (Socket s1 = new Socket()) {325s1.connect(ss.getLocalSocketAddress());326Socket s2 = ss.accept();327s2.close();328}329}330}331332/**333* Test untimed accept where a connection is established after a previous334* accept timed out335*/336public void testTimedAccept5() throws IOException {337try (ServerSocket ss = boundServerSocket()) {338ss.setSoTimeout(2000);339try {340Socket s = ss.accept();341s.close();342fail();343} catch (SocketTimeoutException expected) { }344ss.setSoTimeout(0);345try (Socket s1 = new Socket()) {346s1.connect(ss.getLocalSocketAddress());347Socket s2 = ss.accept();348s2.close();349}350}351}352353/**354* Test untimed accept where a connection is established after a previous355* accept timed out and after a short delay356*/357public void testTimedAccept6() throws IOException {358try (ServerSocket ss = boundServerSocket()) {359ss.setSoTimeout(2000);360try {361Socket s = ss.accept();362s.close();363fail();364} catch (SocketTimeoutException expected) { }365ss.setSoTimeout(0);366scheduleConnect(ss.getLocalSocketAddress(), 2000);367Socket s = ss.accept();368s.close();369}370}371372/**373* Test async close of a timed accept374*/375public void testTimedAccept7() throws IOException {376try (ServerSocket ss = boundServerSocket()) {377ss.setSoTimeout(30*1000);378long delay = 2000;379scheduleClose(ss, delay);380long startMillis = millisTime();381try {382ss.accept().close();383fail();384} catch (SocketException expected) {385checkDuration(startMillis, delay-100, delay+2000);386}387}388}389390/**391* Test timed accept with the thread interrupt status set.392*/393public void testTimedAccept8() throws IOException {394try (ServerSocket ss = boundServerSocket()) {395ss.setSoTimeout(2000);396Thread.currentThread().interrupt();397long startMillis = millisTime();398try {399Socket s = ss.accept();400s.close();401fail();402} catch (SocketTimeoutException expected) {403// accept should have blocked for 2 seconds404int timeout = ss.getSoTimeout();405checkDuration(startMillis, timeout-100, timeout+2000);406assertTrue(Thread.currentThread().isInterrupted());407} finally {408Thread.interrupted(); // clear interrupt status409}410}411}412413/**414* Test interrupt of thread blocked in timed accept.415*/416public void testTimedAccept9() throws IOException {417try (ServerSocket ss = boundServerSocket()) {418ss.setSoTimeout(4000);419// interrupt thread after 1 second420Future<?> interrupter = scheduleInterrupt(Thread.currentThread(), 1000);421long startMillis = millisTime();422try {423Socket s = ss.accept(); // should block for 4 seconds424s.close();425fail();426} catch (SocketTimeoutException expected) {427// accept should have blocked for 4 seconds428int timeout = ss.getSoTimeout();429checkDuration(startMillis, timeout-100, timeout+2000);430assertTrue(Thread.currentThread().isInterrupted());431} finally {432interrupter.cancel(true);433Thread.interrupted(); // clear interrupt status434}435}436}437438/**439* Test two threads blocked in timed accept where no connection is established.440*/441public void testTimedAccept10() throws Exception {442ExecutorService pool = Executors.newFixedThreadPool(2);443try (ServerSocket ss = boundServerSocket()) {444ss.setSoTimeout(4000);445446long startMillis = millisTime();447448Future<Socket> result1 = pool.submit(ss::accept);449Future<Socket> result2 = pool.submit(ss::accept);450451// both tasks should complete with SocketTimeoutException452Throwable e = expectThrows(ExecutionException.class, result1::get);453assertTrue(e.getCause() instanceof SocketTimeoutException);454e = expectThrows(ExecutionException.class, result2::get);455assertTrue(e.getCause() instanceof SocketTimeoutException);456457// should get here in 4 seconds, not 8 seconds458int timeout = ss.getSoTimeout();459checkDuration(startMillis, timeout-100, timeout+2000);460} finally {461pool.shutdown();462}463}464465/**466* Test two threads blocked in timed accept where one connection is established.467*/468public void testTimedAccept11() throws Exception {469ExecutorService pool = Executors.newFixedThreadPool(2);470try (ServerSocket ss = boundServerSocket()) {471ss.setSoTimeout(4000);472473long startMillis = millisTime();474475Future<Socket> result1 = pool.submit(ss::accept);476Future<Socket> result2 = pool.submit(ss::accept);477478// establish connection after 2 seconds479scheduleConnect(ss.getLocalSocketAddress(), 2000);480481// one task should have accepted the connection, the other should482// have completed with SocketTimeoutException483Socket s1 = null;484try {485s1 = result1.get();486s1.close();487} catch (ExecutionException e) {488assertTrue(e.getCause() instanceof SocketTimeoutException);489}490Socket s2 = null;491try {492s2 = result2.get();493s2.close();494} catch (ExecutionException e) {495assertTrue(e.getCause() instanceof SocketTimeoutException);496}497assertTrue((s1 != null) ^ (s2 != null));498499// should get here in 4 seconds, not 8 seconds500int timeout = ss.getSoTimeout();501checkDuration(startMillis, timeout-100, timeout+2000);502} finally {503pool.shutdown();504}505}506507/**508* Test Socket setSoTimeout with a negative timeout.509*/510@Test(expectedExceptions = { IllegalArgumentException.class })511public void testBadTimeout1() throws IOException {512try (Socket s = new Socket()) {513s.setSoTimeout(-1);514}515}516517/**518* Test ServerSocket setSoTimeout with a negative timeout.519*/520@Test(expectedExceptions = { IllegalArgumentException.class })521public void testBadTimeout2() throws IOException {522try (ServerSocket ss = new ServerSocket()) {523ss.setSoTimeout(-1);524}525}526527/**528* Returns a ServerSocket bound to a port on the loopback address529*/530static ServerSocket boundServerSocket() throws IOException {531var loopback = InetAddress.getLoopbackAddress();532ServerSocket ss = new ServerSocket();533ss.bind(new InetSocketAddress(loopback, 0));534return ss;535}536537/**538* An operation that accepts two arguments and may throw IOException539*/540interface ThrowingBiConsumer<T, U> {541void accept(T t, U u) throws IOException;542}543544/**545* Invokes the consumer with a connected pair of sockets546*/547static void withConnection(ThrowingBiConsumer<Socket, Socket> consumer)548throws IOException549{550Socket s1 = null;551Socket s2 = null;552try (ServerSocket ss = boundServerSocket()) {553s1 = new Socket();554s1.connect(ss.getLocalSocketAddress());555s2 = ss.accept();556consumer.accept(s1, s2);557} finally {558if (s1 != null) s1.close();559if (s2 != null) s2.close();560}561}562563/**564* Schedule c to be closed after a delay565*/566static void scheduleClose(Closeable c, long delay) {567schedule(() -> {568try {569c.close();570} catch (IOException ioe) { }571}, delay);572}573574/**575* Schedule thread to be interrupted after a delay576*/577static Future<?> scheduleInterrupt(Thread thread, long delay) {578return schedule(() -> thread.interrupt(), delay);579}580581/**582* Schedule a thread to connect to the given end point after a delay583*/584static void scheduleConnect(SocketAddress remote, long delay) {585schedule(() -> {586try (Socket s = new Socket()) {587s.connect(remote);588} catch (IOException ioe) { }589}, delay);590}591592/**593* Schedule a thread to read to EOF after a delay594*/595static void scheduleReadToEOF(InputStream in, long delay) {596schedule(() -> {597byte[] bytes = new byte[8192];598try {599while (in.read(bytes) != -1) { }600} catch (IOException ioe) { }601}, delay);602}603604/**605* Schedule a thread to write after a delay606*/607static void scheduleWrite(OutputStream out, byte[] data, long delay) {608schedule(() -> {609try {610out.write(data);611} catch (IOException ioe) { }612}, delay);613}614static void scheduleWrite(OutputStream out, int b, long delay) {615scheduleWrite(out, new byte[] { (byte)b }, delay);616}617618static Future<?> schedule(Runnable task, long delay) {619ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();620try {621return executor.schedule(task, delay, TimeUnit.MILLISECONDS);622} finally {623executor.shutdown();624}625}626627/**628* Returns the current time in milliseconds.629*/630private static long millisTime() {631long now = System.nanoTime();632return TimeUnit.MILLISECONDS.convert(now, TimeUnit.NANOSECONDS);633}634635/**636* Check the duration of a task637* @param start start time, in milliseconds638* @param min minimum expected duration, in milliseconds639* @param max maximum expected duration, in milliseconds640* @return the duration (now - start), in milliseconds641*/642private static long checkDuration(long start, long min, long max) {643long duration = millisTime() - start;644assertTrue(duration >= min,645"Duration " + duration + "ms, expected >= " + min + "ms");646assertTrue(duration <= max,647"Duration " + duration + "ms, expected <= " + max + "ms");648return duration;649}650}651652653