Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Apply connectTimeout before SSLSocket.startHandshake to avoid infinite wait in case the connection is broken #3040

Merged
merged 2 commits into from Dec 5, 2023
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions pgjdbc/src/main/java/org/postgresql/ssl/MakeSSL.java
Expand Up @@ -36,6 +36,9 @@ public static void convert(PGStream stream, Properties info)
try {
newConnection = (SSLSocket) factory.createSocket(stream.getSocket(),
stream.getHostSpec().getHost(), stream.getHostSpec().getPort(), true);
// honour the network timeout set in the incoming stream. We have a report that SSL
// connections do not timeout.
newConnection.setSoTimeout(stream.getNetworkTimeout());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder why don't we get failures in the regular test execution. We might add tests that would configure the default db with tls and execute all tests againt it

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question, ever harder will be to test this particular scenario as you have to have a connection to get this far. Postgres doesn't use a separate port for SSL so it would be tough to only block SSL connections.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vlsi should we be using sslResponseTimeout instead ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have not checked it, however, I think we should have different settings for "connect timeout" and for "read response timeout".

The case is:

  1. You want "read response timeout" to be large enough to cover the longest query you expect in the application. For instance, there might be a reporting query taking 10min, so you might set read response timeout to 10min
  2. You want your connects fallback to the workable databases quite quickly, so you don't want to wait for 10 minutes only to recognize the host is not responding

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agreed!

However in this particular case we are connecting so sslResponseTimeout seems more appropriate.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Frankly, we have connectTimeout, and I do not see reasons to have different value here.

I suggest the following:

--- a/pgjdbc/src/main/java/org/postgresql/ssl/MakeSSL.java
+++ b/pgjdbc/src/main/java/org/postgresql/ssl/MakeSSL.java
@@ -36,6 +36,8 @@ public class MakeSSL extends ObjectFactory {
     try {
       newConnection = (SSLSocket) factory.createSocket(stream.getSocket(),
           stream.getHostSpec().getHost(), stream.getHostSpec().getPort(), true);
+      int connectTimeoutSeconds = PGProperty.CONNECT_TIMEOUT.getInt(info);
+      newConnection.setSoTimeout(connectTimeoutSeconds * 1000);
       // We must invoke manually, otherwise the exceptions are hidden
       newConnection.setUseClientMode(true);
       newConnection.startHandshake();
@@ -51,7 +53,8 @@ public class MakeSSL extends ObjectFactory {
     if (sslMode.verifyPeerName()) {
       verifyPeerName(stream, info, newConnection);
     }
+    // Zero timeout (default) means infinite
+    int socketTimeout = PGProperty.SOCKET_TIMEOUT.getInt(info);
+    newConnection.setSoTimeout(socketTimeout * 1000);
     stream.changeSocket(newConnection);
   }

// We must invoke manually, otherwise the exceptions are hidden
newConnection.setUseClientMode(true);
newConnection.startHandshake();
Expand Down