Potential infinite waiting at JMXConnection#createConnection
KUBOTA Yuji
kubota.yuji at gmail.com
Thu Dec 10 13:40:47 UTC 2015
Hi Shanliang and all,
Sorry my reply is too late. But, finally, I reproduced this issue by
following test program! :)
Could you please review test program and my patch ?
The test program includes some files, but I do not have an account of
openjdk, so I push it on icedtea server as below.
http://icedtea.classpath.org/people/ykubota/fixLoopAtJMXConnectorFactory/file/e31044f0804f
The test program starts a simple sleep server program (JMXSSLServer)
on external jdb process with a breakpoint at
sun.security.ssl.ServerHandshaker.clientHello set. It then starts a
client process (JMXSSLCient) which tries to connect the sleep/jdb
process.
ServerHandshaker.clientHello responds to the client hello message and
sends SSL record back. By setting breakpont in that function, we can
emulate this issue in which client keeps waiting SSL record from
server.
Now, JMXConnectorFactory.connect() ignores
sun.rmi.transport.tcp.responseTimeout, so wait the response (SSL
record) from server INFINITELY. Once my patch (jdk9.patch) was added,
then the client will return 0 when the connection timeout happen by
sun.rmi.transport.tcp.responseTimeout.
And test program returns the client's return code.
You can reproduce infinite waiting by the below.
* hg clone http://icedtea.classpath.org/people/ykubota/fixLoopAtJMXConnectorFactory/
* cd fixLoopAtJMXConnectorFactory/testProgram
* set JAVA_HOME
* mvn package
* setting debugcontrol.properties if you need.
* *NOTE* This test program will stop for "debugcontroltest.stop_time" ms.
* ${JAVA_HOME}/bin/java -cp .:target/debugcontrol-1.0-SNAPSHOT.jar
debugcontrol.DebugController
* The result by JDK without my patch.
The client throws java.net.ConnectException after sending quit to jdb.
------
[INFO] Server process args
args[0] /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.65-3.b17.fc23.x86_64/bin/jdb
:
:
cli-out: [INFO] Service URL: service:jmx:rmi:///jndi/rmi://localhost:9876/jmxrmi
ser-err: Set deferred breakpoint sun.security.ssl.ServerHandshaker.clientHello
ser-out:
ser-err: Breakpoint hit: "thread=RMI TCP Connection(2)-127.0.0.1",
sun.security.ssl.ServerHandshaker.clientHello(), line=339 bci=0
ser-out:
[INFO] sending quit to jdb
ser-err: RMI TCP Connection(2)-127.0.0.1[1]
cli-err: java.rmi.ConnectException: Connection refused to host:
127.0.0.1; nested exception is:
cli-err: java.net.ConnectException: Connection refused
cli-err: at
sun.rmi.transport.tcp.TCPEndpoint.newSocket(TCPEndpoint.java:619)
cli-err: at
sun.rmi.transport.tcp.TCPChannel.createConnection(TCPChannel.java:216)
cli-err: at
sun.rmi.transport.tcp.TCPChannel.newConnection(TCPChannel.java:202)
cli-err: at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:130)
cli-err: at
javax.management.remote.rmi.RMIServerImpl_Stub.newClient(Unknown
Source)
cli-err: at
javax.management.remote.rmi.RMIConnector.getConnection(RMIConnector.java:2432)
cli-err: at
javax.management.remote.rmi.RMIConnector.connect(RMIConnector.java:308)
cli-err: at
javax.management.remote.JMXConnectorFactory.connect(JMXConnectorFactory.java:270)
cli-err: at
debugcontrol.client.JMXSSLClient.execute(JMXSSLClient.java:51)
cli-err: at debugcontrol.client.JMXSSLClient.main(JMXSSLClient.java:34)
cli-err: Caused by: java.net.ConnectException: Connection refused
cli-err: at java.net.PlainSocketImpl.socketConnect(Native Method)
cli-err: at
java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
cli-err: at
java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
cli-err: at
java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
cli-err: at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
cli-err: at java.net.Socket.connect(Socket.java:589)
cli-err: at
sun.security.ssl.SSLSocketImpl.connect(SSLSocketImpl.java:668)
cli-err: at sun.security.ssl.SSLSocketImpl.<init>(SSLSocketImpl.java:427)
cli-err: at
sun.security.ssl.SSLSocketFactoryImpl.createSocket(SSLSocketFactoryImpl.java:88)
cli-err: at
javax.rmi.ssl.SslRMIClientSocketFactory.createSocket(SslRMIClientSocketFactory.java:121)
cli-err: at
sun.rmi.transport.tcp.TCPEndpoint.newSocket(TCPEndpoint.java:613)
cli-err: ... 9 more
[INFO] Thu Dec 10 16:16:50 JST 2015 Client done. Result code: 2
[INFO] Client took 114462 msec.
* By JDK 9 with my patch.
The client got java.net.SocketTimeoutException after the connection
timeout happen, then return 0.
------
[INFO] Server process args
args[0] /workspace/jdk9-netdev-patch/build/linux-x86_64-normal-server-release/jdk/bin/jdb
args[1] -classpath
args[2] target/classes
args[3] -J-Duser.language=en
args[4] -Dcom.sun.management.jmxremote.port=9876
args[5] -Dcom.sun.management.jmxremote.password.file=jmxremote.password
args[6] -Djavax.net.ssl.keyStore=jmx-test-cert.pkcs12
args[7] -Djavax.net.ssl.keyStoreType=pkcs12
args[8] -Djavax.net.ssl.keyStorePassword=changeit
args[9] debugcontrol.server.JMXSSLServer
ser-out: Initializing jdb ...
ser-err: > Deferring breakpoint sun.security.ssl.ServerHandshaker.clientHello.
ser-out: It will be set after the class is loaded.
ser-err: > run debugcontrol.server.JMXSSLServer
ser-err: Set uncaught java.lang.Throwable
ser-out: Set deferred uncaught java.lang.Throwable
ser-err: >
ser-out: VM Started: [INFO] Server launched then sleep...
[INFO] Client process args:
args[0] /workspace/jdk9-netdev-patch/build/linux-x86_64-normal-server-release/jdk/bin/java
args[1] -classpath
args[2] target/classes
args[3] -Duser.language=en
args[4] -Djavax.net.ssl.trustStore=jmx-test-cert.pkcs12
args[5] -Djavax.net.ssl.trustStoreType=pkcs12
args[6] -Djavax.net.ssl.trustStorePassword=changeit
args[7] -Dsun.rmi.transport.tcp.responseTimeout=1000
args[8] -Dsun.rmi.transport.tcp.handshakeTimeout=1000
args[9] debugcontrol.client.JMXSSLClient
args[10] localhost
args[11] 9876
cli-out: [INFO] Service URL: service:jmx:rmi:///jndi/rmi://localhost:9876/jmxrmi
ser-err: Set deferred breakpoint sun.security.ssl.ServerHandshaker.clientHello
ser-out:
ser-err: Breakpoint hit: "thread=RMI TCP Connection(2)-127.0.0.1",
sun.security.ssl.ServerHandshaker.clientHello(), line=356 bci=0
ser-out:
cli-out: [INFO] Conglaturation. We got a timeout.
[INFO] Thu Dec 10 15:54:39 JST 2015 Client done. Result code: 0
* My patch (no change from the reported)
* http://icedtea.classpath.org/people/ykubota/fixLoopAtJMXConnectorFactory/file/e31044f0804f/jdk9.patch
------
diff --git a/src/java.rmi/share/classes/sun/rmi/transport/tcp/TCPChannel.java
b/src/java.rmi/share/classes/sun/rmi/transport/tcp/TCPChannel.java
--- a/src/java.rmi/share/classes/sun/rmi/transport/tcp/TCPChannel.java
+++ b/src/java.rmi/share/classes/sun/rmi/transport/tcp/TCPChannel.java
@@ -224,6 +224,22 @@
out.writeByte(TransportConstants.SingleOpProtocol);
} else {
out.writeByte(TransportConstants.StreamProtocol);
+
+ int usableSoTimeout = 0;
+ try {
+ /*
+ * If socket factory had set a non-zero timeout on its
+ * own, then restore it instead of using the property-
+ * configured value.
+ */
+ usableSoTimeout = sock.getSoTimeout();
+ if (usableSoTimeout == 0) {
+ usableSoTimeout = responseTimeout;
+ }
+ sock.setSoTimeout(usableSoTimeout);
+ } catch (Exception e) {
+ // if we fail to set this, ignore and proceed anyway
+ }
out.flush();
/*
@@ -231,9 +247,7 @@
* connection handshake; this also serves to guard against
* non-JRMP servers that do not respond (see 4322806).
*/
- int originalSoTimeout = 0;
try {
- originalSoTimeout = sock.getSoTimeout();
sock.setSoTimeout(handshakeTimeout);
} catch (Exception e) {
// if we fail to set this, ignore and proceed anyway
@@ -281,14 +295,7 @@
* that a remote method call is permitted to execute.
*/
try {
- /*
- * If socket factory had set a non-zero timeout on its
- * own, then restore it instead of using the property-
- * configured value.
- */
- sock.setSoTimeout((originalSoTimeout != 0 ?
- originalSoTimeout :
- responseTimeout));
+ sock.setSoTimeout(usableSoTimeout);
} catch (Exception e) {
// if we fail to set this, ignore and proceed anyway
}
Thanks,
Yuji
More information about the serviceability-dev
mailing list