Reading from a closed socket: different behavior between Linux and other operating systems
Dawid Weiss
dawid.weiss at gmail.com
Sun Dec 29 21:01:12 UTC 2019
Hello,
I am a committer to the Apache Lucene project. We have been looking
into a problem in which SSL connections were handled differently in
tests on different operating systems and narrowed it down to
essentially the following scenario (full repro code at [1]):
Server side:
try (ServerSocketChannel serverChannel = ServerSocketChannel.open()) {
SocketChannel clientChannel = serverChannel.accept();
clientChannel.close();
}
Client side:
Socket socket = new Socket();
socket.connect(target);
// ... server closes the socket here.
// Queue some data for writing to the closed socket. This succeeds.
socket.getOutputStream().write("will succeed?!".getBytes("UTF-8"));
// Try to read something from the closed socket.
socket.getInputStream().read(new byte[100]);
The last line of the client results in different behavior between
operating systems.
1) Linux, JDK 11, 13, 14: succeeds with -1 (EOF).
2) Windows, JDK 11: SocketException ("recv failed") is thrown
3) Windows, JDK 13, 14: SocketException (localized message) is thrown
4) FreeBSD: SocketException (connection reset) is thrown
5) Mac OS X: SocketException (connection reset) is thrown
I admit my original thinking on the Lucene issue (see full discussion
at [2]) was that it was Windows that was off here (due to
WSAECONNRESET not being handled at all in SocketInputStream.c [3].
Since then (JDK11) the underlying socket implementation has changed
due to JEP 353 [4] (which Alan Bateman kindly pointed out to me).
But the difference in runtime behavior between Linux and other
operating systems still exists on both the old and the new
implementation. I don't know whether it's something that should be
qualified as platform-specific but it causes additional problems when
it triggers somewhere deep inside the SSL handling layer -- then the
application-level code receives a different exception depending on
where it's run (an SSLException with a suppressed SocketException or a
SocketException directly).
I don't have any ideas about what a "good" fix for this is but I'm
curious what others think.
Dawid
[1] https://issues.apache.org/jira/secure/attachment/12989538/RecvRepro.java
[2] https://issues.apache.org/jira/browse/SOLR-13778
[3] https://github.com/openjdk/jdk14/blob/f58a8cbed2ba984ceeb9a1ea59f917e3f9530f1e/src/java.base/windows/native/libnet/SocketInputStream.c#L120-L154
[4] https://openjdk.java.net/jeps/353
More information about the net-dev
mailing list