JDK-8230528 : Socket.connect() inconsistently throws ConnectException or SocketTimeoutException
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.net
  • Affected Version: 11,12,13,14
  • Priority: P4
  • Status: Open
  • Resolution: Unresolved
  • OS: linux
  • CPU: x86_64
  • Submitted: 2019-08-29
  • Updated: 2024-01-31
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
tbdUnresolved
Description
ADDITIONAL SYSTEM INFORMATION :
- Oracle JDK
java version "12.0.2" 2019-07-16
Java(TM) SE Runtime Environment (build 12.0.2+10)
Java HotSpot(TM) 64-Bit Server VM (build 12.0.2+10, mixed mode, sharing)

- Linux 64-bit

A DESCRIPTION OF THE PROBLEM :
When the connection times out, Socket.connect() sometimes throws SocketTimeoutException (for low timeouts set and triggered at the JVM level) but other times ConnectException (for timeouts by the kernel).

When the timeout is set to a low value (e.g., 3 seconds), it throws SocketTimeoutException with the message "connect timed out". But when the timeout is not set or set a high value and the connection times out at the network level (on my machine, it is set to 15 seconds), it throws ConnectException with the message "Connection timed out (Connection timed out)".

Note:
- In both cases, the exception messages clearly indicates it is the connection timeout.
- ConnectException does not extend SocketTimeoutException or vice versa

In both cases, it show throw SocketTimeoutException consistently.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Set connect timeout to a value that is greater than the timeout configured at the kernel level. See the executable test code below to reproduce.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
java.net.SocketTimeoutException: connect timed out
    at java.net.PlainSocketImpl.socketConnect (Native Method)
    at java.net.AbstractPlainSocketImpl.doConnect (AbstractPlainSocketImpl.java:399)
    at java.net.AbstractPlainSocketImpl.connectToAddress (AbstractPlainSocketImpl.java:242)
    at java.net.AbstractPlainSocketImpl.connect (AbstractPlainSocketImpl.java:224)
    at java.net.SocksSocketImpl.connect (SocksSocketImpl.java:403)
    at java.net.Socket.connect (Socket.java:591)
    at com.example.ApacheHttpClient2.main (ApacheHttpClient2.java:17)
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0 (Native Method)
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:62)
    at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke (Method.java:567)
    at org.codehaus.mojo.exec.ExecJavaMojo$1.run (ExecJavaMojo.java:282)
    at java.lang.Thread.run (Thread.java:835)
ACTUAL -
java.net.ConnectException: Connection timed out (Connection timed out)
    at java.net.PlainSocketImpl.socketConnect (Native Method)
    at java.net.AbstractPlainSocketImpl.doConnect (AbstractPlainSocketImpl.java:399)
    at java.net.AbstractPlainSocketImpl.connectToAddress (AbstractPlainSocketImpl.java:242)
    at java.net.AbstractPlainSocketImpl.connect (AbstractPlainSocketImpl.java:224)
    at java.net.SocksSocketImpl.connect (SocksSocketImpl.java:403)
    at java.net.Socket.connect (Socket.java:591)
    at com.example.ApacheHttpClient2.main (ApacheHttpClient2.java:17)
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0 (Native Method)
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:62)
    at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke (Method.java:567)
    at org.codehaus.mojo.exec.ExecJavaMojo$1.run (ExecJavaMojo.java:282)
    at java.lang.Thread.run (Thread.java:835)

---------- BEGIN SOURCE ----------
    long started = System.nanoTime();
    try (Socket socket = new Socket()) {
      socket.connect(new InetSocketAddress("example.com", 81), 50000); /** 50 seconds */
    } finally {
      System.out.println("timed out after (sec): " + (System.nanoTime() - started) / 1000000000L);
    }
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
User applications may catch ConnectException in addition to SocketTImeoutException and examine the exception message to determine if the connection failed due to connection timeout.

FREQUENCY : always



Comments
The "Connection timed out" error is a low-level error that occurs during the initial handshake when establishing the connection. It's nothing to do with the timeout set via the setSoTimeout option.
31-08-2019