1919import com .mongodb .MongoInternalException ;
2020import com .mongodb .connection .SocketSettings ;
2121import com .mongodb .connection .SslSettings ;
22- import jdk .net .ExtendedSocketOptions ;
2322
2423import javax .net .ssl .SSLParameters ;
2524import javax .net .ssl .SSLSocket ;
2625import java .io .IOException ;
26+ import java .lang .reflect .InvocationTargetException ;
2727import java .lang .reflect .Method ;
2828import java .net .InetSocketAddress ;
2929import java .net .Socket ;
3030import java .net .SocketOption ;
31- import java .util .Arrays ;
3231
3332import static com .mongodb .internal .connection .SslHelper .enableHostNameVerification ;
3433import static com .mongodb .internal .connection .SslHelper .enableSni ;
3534import static java .util .concurrent .TimeUnit .MILLISECONDS ;
3635
36+ @ SuppressWarnings ({"unchecked" , "rawtypes" })
3737final 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