21 * questions. |
21 * questions. |
22 */ |
22 */ |
23 |
23 |
24 /* |
24 /* |
25 * @test |
25 * @test |
|
26 * @bug 8221481 |
26 * @library /test/lib |
27 * @library /test/lib |
27 * @build jdk.test.lib.Utils |
28 * @build jdk.test.lib.Utils |
28 * @run testng Timeouts |
29 * @run testng/timeout=180 Timeouts |
29 * @summary Test Socket timeouts |
30 * @summary Test Socket timeouts |
30 */ |
31 */ |
31 |
32 |
32 import java.io.Closeable; |
33 import java.io.Closeable; |
33 import java.io.IOException; |
34 import java.io.IOException; |
34 import java.io.InputStream; |
35 import java.io.InputStream; |
35 import java.io.OutputStream; |
36 import java.io.OutputStream; |
36 import java.net.ConnectException; |
37 import java.net.ConnectException; |
|
38 import java.net.InetAddress; |
|
39 import java.net.InetSocketAddress; |
37 import java.net.ServerSocket; |
40 import java.net.ServerSocket; |
38 import java.net.Socket; |
41 import java.net.Socket; |
39 import java.net.SocketAddress; |
42 import java.net.SocketAddress; |
40 import java.net.SocketException; |
43 import java.net.SocketException; |
41 import java.net.SocketTimeoutException; |
44 import java.net.SocketTimeoutException; |
42 import java.util.concurrent.Executors; |
45 import java.util.concurrent.Executors; |
|
46 import java.util.concurrent.ExecutionException; |
|
47 import java.util.concurrent.ExecutorService; |
|
48 import java.util.concurrent.Future; |
43 import java.util.concurrent.ScheduledExecutorService; |
49 import java.util.concurrent.ScheduledExecutorService; |
44 import java.util.concurrent.TimeUnit; |
50 import java.util.concurrent.TimeUnit; |
45 |
51 |
46 import org.testng.annotations.Test; |
52 import org.testng.annotations.Test; |
47 import static org.testng.Assert.*; |
53 import static org.testng.Assert.*; |
75 |
81 |
76 /** |
82 /** |
77 * Test connect with a timeout of Integer.MAX_VALUE |
83 * Test connect with a timeout of Integer.MAX_VALUE |
78 */ |
84 */ |
79 public void testTimedConnect3() throws IOException { |
85 public void testTimedConnect3() throws IOException { |
80 try (ServerSocket ss = new ServerSocket(0)) { |
86 try (ServerSocket ss = boundServerSocket()) { |
81 try (Socket s = new Socket()) { |
87 try (Socket s = new Socket()) { |
82 s.connect(ss.getLocalSocketAddress(), Integer.MAX_VALUE); |
88 s.connect(ss.getLocalSocketAddress(), Integer.MAX_VALUE); |
83 } |
89 } |
84 } |
90 } |
85 } |
91 } |
86 |
92 |
87 /** |
93 /** |
88 * Test connect with a negative timeout. |
94 * Test connect with a negative timeout. |
89 */ |
95 */ |
90 public void testTimedConnect4() throws IOException { |
96 public void testTimedConnect4() throws IOException { |
91 try (ServerSocket ss = new ServerSocket(0)) { |
97 try (ServerSocket ss = boundServerSocket()) { |
92 try (Socket s = new Socket()) { |
98 try (Socket s = new Socket()) { |
93 try { |
99 expectThrows(IllegalArgumentException.class, |
94 s.connect(ss.getLocalSocketAddress(), -1); |
100 () -> s.connect(ss.getLocalSocketAddress(), -1)); |
95 assertTrue(false); |
|
96 } catch (IllegalArgumentException expected) { } |
|
97 } |
101 } |
98 } |
102 } |
99 } |
103 } |
100 |
104 |
101 /** |
105 /** |
126 * Test timed read where the read times out |
130 * Test timed read where the read times out |
127 */ |
131 */ |
128 public void testTimedRead3() throws IOException { |
132 public void testTimedRead3() throws IOException { |
129 withConnection((s1, s2) -> { |
133 withConnection((s1, s2) -> { |
130 s2.setSoTimeout(2000); |
134 s2.setSoTimeout(2000); |
131 try { |
135 long startMillis = millisTime(); |
132 s2.getInputStream().read(); |
136 expectThrows(SocketTimeoutException.class, () -> s2.getInputStream().read()); |
133 assertTrue(false); |
137 int timeout = s2.getSoTimeout(); |
134 } catch (SocketTimeoutException expected) { } |
138 checkDuration(startMillis, timeout-100, timeout+2000); |
135 }); |
139 }); |
136 } |
140 } |
137 |
141 |
138 /** |
142 /** |
139 * Test timed read that succeeds after a previous read has timed out |
143 * Test timed read that succeeds after a previous read has timed out |
140 */ |
144 */ |
141 public void testTimedRead4() throws IOException { |
145 public void testTimedRead4() throws IOException { |
142 withConnection((s1, s2) -> { |
146 withConnection((s1, s2) -> { |
143 s2.setSoTimeout(2000); |
147 s2.setSoTimeout(2000); |
144 try { |
148 expectThrows(SocketTimeoutException.class, () -> s2.getInputStream().read()); |
145 s2.getInputStream().read(); |
|
146 assertTrue(false); |
|
147 } catch (SocketTimeoutException e) { } |
|
148 s1.getOutputStream().write(99); |
149 s1.getOutputStream().write(99); |
149 int b = s2.getInputStream().read(); |
150 int b = s2.getInputStream().read(); |
150 assertTrue(b == 99); |
151 assertTrue(b == 99); |
151 }); |
152 }); |
152 } |
153 } |
156 * after a short delay |
157 * after a short delay |
157 */ |
158 */ |
158 public void testTimedRead5() throws IOException { |
159 public void testTimedRead5() throws IOException { |
159 withConnection((s1, s2) -> { |
160 withConnection((s1, s2) -> { |
160 s2.setSoTimeout(2000); |
161 s2.setSoTimeout(2000); |
161 try { |
162 expectThrows(SocketTimeoutException.class, () -> s2.getInputStream().read()); |
162 s2.getInputStream().read(); |
|
163 assertTrue(false); |
|
164 } catch (SocketTimeoutException e) { } |
|
165 s2.setSoTimeout(30*3000); |
163 s2.setSoTimeout(30*3000); |
166 scheduleWrite(s1.getOutputStream(), 99, 2000); |
164 scheduleWrite(s1.getOutputStream(), 99, 2000); |
167 int b = s2.getInputStream().read(); |
165 int b = s2.getInputStream().read(); |
168 assertTrue(b == 99); |
166 assertTrue(b == 99); |
169 }); |
167 }); |
305 |
294 |
306 /** |
295 /** |
307 * Test timed accept where the accept times out |
296 * Test timed accept where the accept times out |
308 */ |
297 */ |
309 public void testTimedAccept3() throws IOException { |
298 public void testTimedAccept3() throws IOException { |
310 try (ServerSocket ss = new ServerSocket(0)) { |
299 try (ServerSocket ss = boundServerSocket()) { |
311 ss.setSoTimeout(2000); |
300 ss.setSoTimeout(2000); |
|
301 long startMillis = millisTime(); |
312 try { |
302 try { |
313 Socket s = ss.accept(); |
303 Socket s = ss.accept(); |
314 s.close(); |
304 s.close(); |
315 assertTrue(false); |
305 fail(); |
316 } catch (SocketTimeoutException expected) { } |
306 } catch (SocketTimeoutException expected) { |
|
307 int timeout = ss.getSoTimeout(); |
|
308 checkDuration(startMillis, timeout-100, timeout+2000); |
|
309 } |
317 } |
310 } |
318 } |
311 } |
319 |
312 |
320 /** |
313 /** |
321 * Test timed accept where a connection is established immediately after a |
314 * Test timed accept where a connection is established immediately after a |
322 * previous accept timed out. |
315 * previous accept timed out. |
323 */ |
316 */ |
324 public void testTimedAccept4() throws IOException { |
317 public void testTimedAccept4() throws IOException { |
325 try (ServerSocket ss = new ServerSocket(0)) { |
318 try (ServerSocket ss = boundServerSocket()) { |
326 ss.setSoTimeout(2000); |
319 ss.setSoTimeout(2000); |
327 try { |
320 try { |
328 Socket s = ss.accept(); |
321 Socket s = ss.accept(); |
329 s.close(); |
322 s.close(); |
330 assertTrue(false); |
323 fail(); |
331 } catch (SocketTimeoutException expected) { } |
324 } catch (SocketTimeoutException expected) { } |
332 try (Socket s1 = new Socket()) { |
325 try (Socket s1 = new Socket()) { |
333 s1.connect(ss.getLocalSocketAddress()); |
326 s1.connect(ss.getLocalSocketAddress()); |
334 Socket s2 = ss.accept(); |
327 Socket s2 = ss.accept(); |
335 s2.close(); |
328 s2.close(); |
340 /** |
333 /** |
341 * Test untimed accept where a connection is established after a previous |
334 * Test untimed accept where a connection is established after a previous |
342 * accept timed out |
335 * accept timed out |
343 */ |
336 */ |
344 public void testTimedAccept5() throws IOException { |
337 public void testTimedAccept5() throws IOException { |
345 try (ServerSocket ss = new ServerSocket(0)) { |
338 try (ServerSocket ss = boundServerSocket()) { |
346 ss.setSoTimeout(2000); |
339 ss.setSoTimeout(2000); |
347 try { |
340 try { |
348 Socket s = ss.accept(); |
341 Socket s = ss.accept(); |
349 s.close(); |
342 s.close(); |
350 assertTrue(false); |
343 fail(); |
351 } catch (SocketTimeoutException expected) { } |
344 } catch (SocketTimeoutException expected) { } |
352 ss.setSoTimeout(0); |
345 ss.setSoTimeout(0); |
353 try (Socket s1 = new Socket()) { |
346 try (Socket s1 = new Socket()) { |
354 s1.connect(ss.getLocalSocketAddress()); |
347 s1.connect(ss.getLocalSocketAddress()); |
355 Socket s2 = ss.accept(); |
348 Socket s2 = ss.accept(); |
361 /** |
354 /** |
362 * Test untimed accept where a connection is established after a previous |
355 * Test untimed accept where a connection is established after a previous |
363 * accept timed out and after a short delay |
356 * accept timed out and after a short delay |
364 */ |
357 */ |
365 public void testTimedAccept6() throws IOException { |
358 public void testTimedAccept6() throws IOException { |
366 try (ServerSocket ss = new ServerSocket(0)) { |
359 try (ServerSocket ss = boundServerSocket()) { |
367 ss.setSoTimeout(2000); |
360 ss.setSoTimeout(2000); |
368 try { |
361 try { |
369 Socket s = ss.accept(); |
362 Socket s = ss.accept(); |
370 s.close(); |
363 s.close(); |
371 assertTrue(false); |
364 fail(); |
372 } catch (SocketTimeoutException expected) { } |
365 } catch (SocketTimeoutException expected) { } |
373 ss.setSoTimeout(0); |
366 ss.setSoTimeout(0); |
374 scheduleConnect(ss.getLocalSocketAddress(), 2000); |
367 scheduleConnect(ss.getLocalSocketAddress(), 2000); |
375 Socket s = ss.accept(); |
368 Socket s = ss.accept(); |
376 s.close(); |
369 s.close(); |
379 |
372 |
380 /** |
373 /** |
381 * Test async close of a timed accept |
374 * Test async close of a timed accept |
382 */ |
375 */ |
383 public void testTimedAccept7() throws IOException { |
376 public void testTimedAccept7() throws IOException { |
384 try (ServerSocket ss = new ServerSocket(0)) { |
377 try (ServerSocket ss = boundServerSocket()) { |
385 ss.setSoTimeout(30*1000); |
378 ss.setSoTimeout(30*1000); |
386 scheduleClose(ss, 2000); |
379 long delay = 2000; |
|
380 scheduleClose(ss, delay); |
|
381 long startMillis = millisTime(); |
387 try { |
382 try { |
388 ss.accept().close(); |
383 ss.accept().close(); |
389 assertTrue(false); |
384 fail(); |
390 } catch (SocketException expected) { } |
385 } catch (SocketException expected) { |
|
386 checkDuration(startMillis, delay-100, delay+2000); |
|
387 } |
|
388 } |
|
389 } |
|
390 |
|
391 /** |
|
392 * Test timed accept with the thread interrupt status set. |
|
393 */ |
|
394 public void testTimedAccept8() throws IOException { |
|
395 try (ServerSocket ss = boundServerSocket()) { |
|
396 ss.setSoTimeout(2000); |
|
397 Thread.currentThread().interrupt(); |
|
398 long startMillis = millisTime(); |
|
399 try { |
|
400 Socket s = ss.accept(); |
|
401 s.close(); |
|
402 fail(); |
|
403 } catch (SocketTimeoutException expected) { |
|
404 // accept should have blocked for 2 seconds |
|
405 int timeout = ss.getSoTimeout(); |
|
406 checkDuration(startMillis, timeout-100, timeout+2000); |
|
407 assertTrue(Thread.currentThread().isInterrupted()); |
|
408 } finally { |
|
409 Thread.interrupted(); // clear interrupt status |
|
410 } |
|
411 } |
|
412 } |
|
413 |
|
414 /** |
|
415 * Test interrupt of thread blocked in timed accept. |
|
416 */ |
|
417 public void testTimedAccept9() throws IOException { |
|
418 try (ServerSocket ss = boundServerSocket()) { |
|
419 ss.setSoTimeout(4000); |
|
420 // interrupt thread after 1 second |
|
421 Future<?> interrupter = scheduleInterrupt(Thread.currentThread(), 1000); |
|
422 long startMillis = millisTime(); |
|
423 try { |
|
424 Socket s = ss.accept(); // should block for 4 seconds |
|
425 s.close(); |
|
426 fail(); |
|
427 } catch (SocketTimeoutException expected) { |
|
428 // accept should have blocked for 4 seconds |
|
429 int timeout = ss.getSoTimeout(); |
|
430 checkDuration(startMillis, timeout-100, timeout+2000); |
|
431 assertTrue(Thread.currentThread().isInterrupted()); |
|
432 } finally { |
|
433 interrupter.cancel(true); |
|
434 Thread.interrupted(); // clear interrupt status |
|
435 } |
|
436 } |
|
437 } |
|
438 |
|
439 /** |
|
440 * Test two threads blocked in timed accept where no connection is established. |
|
441 */ |
|
442 public void testTimedAccept10() throws Exception { |
|
443 ExecutorService pool = Executors.newFixedThreadPool(2); |
|
444 try (ServerSocket ss = boundServerSocket()) { |
|
445 ss.setSoTimeout(4000); |
|
446 |
|
447 long startMillis = millisTime(); |
|
448 |
|
449 Future<Socket> result1 = pool.submit(ss::accept); |
|
450 Future<Socket> result2 = pool.submit(ss::accept); |
|
451 |
|
452 // both tasks should complete with SocketTimeoutException |
|
453 Throwable e = expectThrows(ExecutionException.class, result1::get); |
|
454 assertTrue(e.getCause() instanceof SocketTimeoutException); |
|
455 e = expectThrows(ExecutionException.class, result2::get); |
|
456 assertTrue(e.getCause() instanceof SocketTimeoutException); |
|
457 |
|
458 // should get here in 4 seconds, not 8 seconds |
|
459 int timeout = ss.getSoTimeout(); |
|
460 checkDuration(startMillis, timeout-100, timeout+2000); |
|
461 } finally { |
|
462 pool.shutdown(); |
|
463 } |
|
464 } |
|
465 |
|
466 /** |
|
467 * Test two threads blocked in timed accept where one connection is established. |
|
468 */ |
|
469 public void testTimedAccept11() throws Exception { |
|
470 ExecutorService pool = Executors.newFixedThreadPool(2); |
|
471 try (ServerSocket ss = boundServerSocket()) { |
|
472 ss.setSoTimeout(4000); |
|
473 |
|
474 long startMillis = millisTime(); |
|
475 |
|
476 Future<Socket> result1 = pool.submit(ss::accept); |
|
477 Future<Socket> result2 = pool.submit(ss::accept); |
|
478 |
|
479 // establish connection after 2 seconds |
|
480 scheduleConnect(ss.getLocalSocketAddress(), 2000); |
|
481 |
|
482 // one task should have accepted the connection, the other should |
|
483 // have completed with SocketTimeoutException |
|
484 Socket s1 = null; |
|
485 try { |
|
486 s1 = result1.get(); |
|
487 s1.close(); |
|
488 } catch (ExecutionException e) { |
|
489 assertTrue(e.getCause() instanceof SocketTimeoutException); |
|
490 } |
|
491 Socket s2 = null; |
|
492 try { |
|
493 s2 = result2.get(); |
|
494 s2.close(); |
|
495 } catch (ExecutionException e) { |
|
496 assertTrue(e.getCause() instanceof SocketTimeoutException); |
|
497 } |
|
498 assertTrue((s1 != null) ^ (s2 != null)); |
|
499 |
|
500 // should get here in 4 seconds, not 8 seconds |
|
501 int timeout = ss.getSoTimeout(); |
|
502 checkDuration(startMillis, timeout-100, timeout+2000); |
|
503 } finally { |
|
504 pool.shutdown(); |
391 } |
505 } |
392 } |
506 } |
393 |
507 |
394 /** |
508 /** |
395 * Test Socket setSoTimeout with a negative timeout. |
509 * Test Socket setSoTimeout with a negative timeout. |
480 } |
614 } |
481 static void scheduleWrite(OutputStream out, int b, long delay) { |
615 static void scheduleWrite(OutputStream out, int b, long delay) { |
482 scheduleWrite(out, new byte[] { (byte)b }, delay); |
616 scheduleWrite(out, new byte[] { (byte)b }, delay); |
483 } |
617 } |
484 |
618 |
485 static void schedule(Runnable task, long delay) { |
619 static Future<?> schedule(Runnable task, long delay) { |
486 ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(); |
620 ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(); |
487 try { |
621 try { |
488 executor.schedule(task, delay, TimeUnit.MILLISECONDS); |
622 return executor.schedule(task, delay, TimeUnit.MILLISECONDS); |
489 } finally { |
623 } finally { |
490 executor.shutdown(); |
624 executor.shutdown(); |
491 } |
625 } |
492 } |
626 } |
|
627 |
|
628 /** |
|
629 * Returns the current time in milliseconds. |
|
630 */ |
|
631 private static long millisTime() { |
|
632 long now = System.nanoTime(); |
|
633 return TimeUnit.MILLISECONDS.convert(now, TimeUnit.NANOSECONDS); |
|
634 } |
|
635 |
|
636 /** |
|
637 * Check the duration of a task |
|
638 * @param start start time, in milliseconds |
|
639 * @param min minimum expected duration, in milliseconds |
|
640 * @param max maximum expected duration, in milliseconds |
|
641 * @return the duration (now - start), in milliseconds |
|
642 */ |
|
643 private static long checkDuration(long start, long min, long max) { |
|
644 long duration = millisTime() - start; |
|
645 assertTrue(duration >= min, |
|
646 "Duration " + duration + "ms, expected >= " + min + "ms"); |
|
647 assertTrue(duration <= max, |
|
648 "Duration " + duration + "ms, expected <= " + max + "ms"); |
|
649 return duration; |
|
650 } |
493 } |
651 } |