Skip to content

Commit afb6a0c

Browse files
author
Alan Bateman
committed
8372958: SocketInputStream.read throws SocketException instead of returning -1 when input shutdown
Reviewed-by: djelinski, michaelm
1 parent abb75ba commit afb6a0c

File tree

4 files changed

+168
-230
lines changed

4 files changed

+168
-230
lines changed

src/java.base/share/classes/sun/nio/ch/NioSocketImpl.java

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,7 @@ private int timedRead(FileDescriptor fd, byte[] b, int off, int len, long nanos)
289289
*/
290290
private int implRead(byte[] b, int off, int len, long remainingNanos) throws IOException {
291291
int n = 0;
292+
SocketException ex = null;
292293
FileDescriptor fd = beginRead();
293294
try {
294295
if (connectionReset)
@@ -307,18 +308,24 @@ private int implRead(byte[] b, int off, int len, long remainingNanos) throws IOE
307308
n = tryRead(fd, b, off, len);
308309
}
309310
}
310-
return n;
311311
} catch (InterruptedIOException e) {
312312
throw e;
313313
} catch (ConnectionResetException e) {
314314
connectionReset = true;
315315
throw new SocketException("Connection reset");
316316
} catch (IOException ioe) {
317-
// throw SocketException to maintain compatibility
318-
throw asSocketException(ioe);
317+
// translate to SocketException to maintain compatibility
318+
ex = asSocketException(ioe);
319319
} finally {
320320
endRead(n > 0);
321321
}
322+
if (n <= 0 && isInputClosed) {
323+
return -1;
324+
}
325+
if (ex != null) {
326+
throw ex;
327+
}
328+
return n;
322329
}
323330

324331
/**
@@ -411,6 +418,7 @@ private int tryWrite(FileDescriptor fd, byte[] b, int off, int len)
411418
*/
412419
private int implWrite(byte[] b, int off, int len) throws IOException {
413420
int n = 0;
421+
SocketException ex = null;
414422
FileDescriptor fd = beginWrite();
415423
try {
416424
configureNonBlockingIfNeeded(fd, false);
@@ -419,15 +427,18 @@ private int implWrite(byte[] b, int off, int len) throws IOException {
419427
park(fd, Net.POLLOUT);
420428
n = tryWrite(fd, b, off, len);
421429
}
422-
return n;
423430
} catch (InterruptedIOException e) {
424431
throw e;
425432
} catch (IOException ioe) {
426-
// throw SocketException to maintain compatibility
427-
throw asSocketException(ioe);
433+
// translate to SocketException to maintain compatibility
434+
ex = asSocketException(ioe);
428435
} finally {
429436
endWrite(n > 0);
430437
}
438+
if (ex != null) {
439+
throw ex;
440+
}
441+
return n;
431442
}
432443

433444
/**

test/jdk/java/net/Socket/AsyncShutdown.java

Lines changed: 27 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -24,11 +24,13 @@
2424
/*
2525
* @test
2626
* @requires (os.family == "linux" | os.family == "mac")
27-
* @run testng AsyncShutdown
2827
* @summary Test shutdownInput/shutdownOutput with threads blocked in read/write
28+
* @run junit AsyncShutdown
2929
*/
3030

3131
import java.io.IOException;
32+
import java.io.InputStream;
33+
import java.io.OutputStream;
3234
import java.net.InetAddress;
3335
import java.net.InetSocketAddress;
3436
import java.net.ServerSocket;
@@ -38,54 +40,56 @@
3840
import java.util.concurrent.ScheduledExecutorService;
3941
import java.util.concurrent.TimeUnit;
4042

41-
import org.testng.annotations.Test;
42-
import static org.testng.Assert.*;
43+
import org.junit.jupiter.api.Test;
44+
import org.junit.jupiter.params.ParameterizedTest;
45+
import org.junit.jupiter.params.provider.ValueSource;
46+
import static org.junit.jupiter.api.Assertions.*;
4347

44-
@Test
45-
public class AsyncShutdown {
48+
class AsyncShutdown {
4649

47-
public void testShutdownInput1() throws IOException {
50+
@ParameterizedTest
51+
@ValueSource(booleans = { false, true })
52+
void testShutdownInput(boolean timed) throws IOException {
4853
withConnection((s1, s2) -> {
54+
InputStream in = s1.getInputStream();
4955
scheduleShutdownInput(s1, 2000);
50-
int n = s1.getInputStream().read();
51-
assertTrue(n == -1);
56+
if (timed) {
57+
s1.setSoTimeout(30*1000);
58+
}
59+
assertEquals(-1, in.read());
60+
assertEquals(0, in.available());
5261
});
5362
}
5463

55-
public void testShutdownInput2() throws IOException {
56-
withConnection((s1, s2) -> {
57-
scheduleShutdownInput(s1, 2000);
58-
s1.setSoTimeout(30*1000);
59-
int n = s1.getInputStream().read();
60-
assertTrue(n == -1);
61-
});
62-
}
63-
64-
public void testShutdownOutput1() throws IOException {
64+
@Test
65+
void testShutdownOutput1() throws IOException {
6566
withConnection((s1, s2) -> {
67+
OutputStream out = s1.getOutputStream();
6668
scheduleShutdownOutput(s1, 2000);
6769
byte[] data = new byte[128*1024];
6870
try {
6971
while (true) {
70-
s1.getOutputStream().write(data);
72+
out.write(data);
7173
}
7274
} catch (IOException expected) { }
7375
});
7476
}
7577

76-
public void testShutdownOutput2() throws IOException {
78+
@Test
79+
void testShutdownOutput2() throws IOException {
7780
withConnection((s1, s2) -> {
7881
s1.setSoTimeout(100);
7982
try {
8083
s1.getInputStream().read();
81-
assertTrue(false);
84+
fail();
8285
} catch (SocketTimeoutException e) { }
8386

87+
OutputStream out = s1.getOutputStream();
8488
scheduleShutdownOutput(s1, 2000);
8589
byte[] data = new byte[128*1024];
8690
try {
8791
while (true) {
88-
s1.getOutputStream().write(data);
92+
out.write(data);
8993
}
9094
} catch (IOException expected) { }
9195
});

0 commit comments

Comments
 (0)