Skip to content

Commit a75be45

Browse files
committed
Remove assumption that jdk.net package is available
This commit removes any assumptions that jdk.net.ExtendedSocketOptions is available at all at runtime, since the jdk.net package is not actually part of the standard library (though in practice it is usually available). If it's not available, no TCP keep-alive options will be set, but socket creation will proceed instead of failing with a ClassNotFoundException. JAVA-4005
1 parent c069f2c commit a75be45

File tree

1 file changed

+45
-14
lines changed

1 file changed

+45
-14
lines changed

driver-core/src/main/com/mongodb/internal/connection/SocketStreamHelper.java

Lines changed: 45 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,21 +19,21 @@
1919
import com.mongodb.MongoInternalException;
2020
import com.mongodb.connection.SocketSettings;
2121
import com.mongodb.connection.SslSettings;
22-
import jdk.net.ExtendedSocketOptions;
2322

2423
import javax.net.ssl.SSLParameters;
2524
import javax.net.ssl.SSLSocket;
2625
import java.io.IOException;
26+
import java.lang.reflect.InvocationTargetException;
2727
import java.lang.reflect.Method;
2828
import java.net.InetSocketAddress;
2929
import java.net.Socket;
3030
import java.net.SocketOption;
31-
import java.util.Arrays;
3231

3332
import static com.mongodb.internal.connection.SslHelper.enableHostNameVerification;
3433
import static com.mongodb.internal.connection.SslHelper.enableSni;
3534
import static java.util.concurrent.TimeUnit.MILLISECONDS;
3635

36+
@SuppressWarnings({"unchecked", "rawtypes"})
3737
final class SocketStreamHelper {
3838
// Keep alive options and their values for Java 11+
3939
private static final String TCP_KEEPIDLE = "TCP_KEEPIDLE";
@@ -43,6 +43,35 @@ final class SocketStreamHelper {
4343
private static final String TCP_KEEPINTERVAL = "TCP_KEEPINTERVAL";
4444
private static final int TCP_KEEPINTERVAL_DURATION = 10;
4545

46+
private static final SocketOption<Integer> KEEP_COUNT_OPTION;
47+
private static final SocketOption<Integer> KEEP_IDLE_OPTION;
48+
private static final SocketOption<Integer> KEEP_INTERVAL_OPTION;
49+
50+
private static final Method SET_OPTION_METHOD;
51+
52+
static {
53+
SocketOption<Integer> keepCountOption = null;
54+
SocketOption<Integer> keepIdleOption = null;
55+
SocketOption<Integer> keepIntervalOption = null;
56+
Method setOptionMethod = null;
57+
58+
try {
59+
setOptionMethod = Socket.class.getMethod("setOption", SocketOption.class, Object.class);
60+
61+
Class extendedSocketOptionsClass = Class.forName("jdk.net.ExtendedSocketOptions");
62+
keepCountOption = (SocketOption<Integer>) extendedSocketOptionsClass.getDeclaredField(TCP_KEEPCOUNT).get(null);
63+
keepIdleOption = (SocketOption<Integer>) extendedSocketOptionsClass.getDeclaredField(TCP_KEEPIDLE).get(null);
64+
keepIntervalOption = (SocketOption<Integer>) extendedSocketOptionsClass.getDeclaredField(TCP_KEEPINTERVAL).get(null);
65+
} catch (ClassNotFoundException | NoSuchMethodException | NoSuchFieldException | IllegalAccessException e) {
66+
// ignore: this is expected on JDKs < 11 and some deployments that don't include the jdk.net package
67+
}
68+
69+
KEEP_COUNT_OPTION = keepCountOption;
70+
KEEP_IDLE_OPTION = keepIdleOption;
71+
KEEP_INTERVAL_OPTION = keepIntervalOption;
72+
SET_OPTION_METHOD = setOptionMethod;
73+
}
74+
4675
static void initialize(final Socket socket, final InetSocketAddress inetSocketAddress, final SocketSettings settings,
4776
final SslSettings sslSettings) throws IOException {
4877
socket.setTcpNoDelay(true);
@@ -78,19 +107,21 @@ static void initialize(final Socket socket, final InetSocketAddress inetSocketAd
78107
socket.connect(inetSocketAddress, settings.getConnectTimeout(MILLISECONDS));
79108
}
80109

81-
@SuppressWarnings("unchecked")
82-
private static void setExtendedSocketOptions(final Socket socket) {
83-
if (Arrays.stream(ExtendedSocketOptions.class.getDeclaredFields()).anyMatch(f -> f.getName().equals(TCP_KEEPCOUNT))) {
84-
try {
85-
Method setOptionMethod = Socket.class.getMethod("setOption", SocketOption.class, Object.class);
86-
setOptionMethod.invoke(socket, ExtendedSocketOptions.class.getDeclaredField(TCP_KEEPCOUNT).get(null),
87-
TCP_KEEPCOUNT_LIMIT);
88-
setOptionMethod.invoke(socket, ExtendedSocketOptions.class.getDeclaredField(TCP_KEEPIDLE).get(null),
89-
TCP_KEEPIDLE_DURATION);
90-
setOptionMethod.invoke(socket, ExtendedSocketOptions.class.getDeclaredField(TCP_KEEPINTERVAL).get(null),
91-
TCP_KEEPINTERVAL_DURATION);
92-
} catch (Throwable t) {
110+
static void setExtendedSocketOptions(final Socket socket) {
111+
try {
112+
if (SET_OPTION_METHOD != null) {
113+
if (KEEP_COUNT_OPTION != null) {
114+
SET_OPTION_METHOD.invoke(socket, KEEP_COUNT_OPTION, TCP_KEEPCOUNT_LIMIT);
115+
}
116+
if (KEEP_IDLE_OPTION != null) {
117+
SET_OPTION_METHOD.invoke(socket, KEEP_IDLE_OPTION, TCP_KEEPIDLE_DURATION);
118+
}
119+
if (KEEP_INTERVAL_OPTION != null) {
120+
SET_OPTION_METHOD.invoke(socket, KEEP_INTERVAL_OPTION, TCP_KEEPINTERVAL_DURATION);
121+
}
93122
}
123+
} catch (IllegalAccessException | InvocationTargetException e) {
124+
// ignore failures, as this is best effort
94125
}
95126
}
96127

0 commit comments

Comments
 (0)