diff --git a/distribution/tools/server-cli/src/main/java/org/elasticsearch/server/cli/ServerProcess.java b/distribution/tools/server-cli/src/main/java/org/elasticsearch/server/cli/ServerProcess.java index ecb5bd89a694f..59152f0550f89 100644 --- a/distribution/tools/server-cli/src/main/java/org/elasticsearch/server/cli/ServerProcess.java +++ b/distribution/tools/server-cli/src/main/java/org/elasticsearch/server/cli/ServerProcess.java @@ -216,6 +216,7 @@ private static Process createProcess( command.addAll(jvmOptions); command.add("--module-path"); command.add(esHome.resolve("lib").toString()); + command.add("--add-modules=jdk.net"); // very special circumstance; explicit modules should typically not be added here command.add("-m"); command.add("org.elasticsearch.server/org.elasticsearch.bootstrap.Elasticsearch"); diff --git a/docs/changelog/88935.yaml b/docs/changelog/88935.yaml new file mode 100644 index 0000000000000..f81b4838a4aa1 --- /dev/null +++ b/docs/changelog/88935.yaml @@ -0,0 +1,6 @@ +pr: 88935 +summary: Ensure that the extended socket options TCP_KEEPXXX are available +area: Network +type: bug +issues: + - 88897 diff --git a/modules/transport-netty4/src/main/java/module-info.java b/modules/transport-netty4/src/main/java/module-info.java index cb718539d0f11..92217b419c666 100644 --- a/modules/transport-netty4/src/main/java/module-info.java +++ b/modules/transport-netty4/src/main/java/module-info.java @@ -7,6 +7,7 @@ */ module org.elasticsearch.transport.netty4 { + requires jdk.net; requires org.elasticsearch.base; requires org.elasticsearch.server; requires org.elasticsearch.xcontent; diff --git a/modules/transport-netty4/src/main/java/org/elasticsearch/http/netty4/Netty4HttpServerTransport.java b/modules/transport-netty4/src/main/java/org/elasticsearch/http/netty4/Netty4HttpServerTransport.java index 7fa8ca28aa31b..5f49e2505cbf6 100644 --- a/modules/transport-netty4/src/main/java/org/elasticsearch/http/netty4/Netty4HttpServerTransport.java +++ b/modules/transport-netty4/src/main/java/org/elasticsearch/http/netty4/Netty4HttpServerTransport.java @@ -57,7 +57,6 @@ import org.elasticsearch.xcontent.NamedXContentRegistry; import java.net.InetSocketAddress; -import java.net.SocketOption; import java.util.concurrent.TimeUnit; import static org.elasticsearch.http.HttpTransportSettings.SETTING_HTTP_MAX_CHUNK_SIZE; @@ -215,25 +214,22 @@ protected void doStart() { // Netty logs a warning if it can't set the option, so try this only on supported platforms if (IOUtils.LINUX || IOUtils.MAC_OS_X) { if (SETTING_HTTP_TCP_KEEP_IDLE.get(settings) >= 0) { - final SocketOption keepIdleOption = NetUtils.getTcpKeepIdleSocketOptionOrNull(); - if (keepIdleOption != null) { - serverBootstrap.childOption(NioChannelOption.of(keepIdleOption), SETTING_HTTP_TCP_KEEP_IDLE.get(settings)); - } + serverBootstrap.childOption( + NioChannelOption.of(NetUtils.getTcpKeepIdleSocketOption()), + SETTING_HTTP_TCP_KEEP_IDLE.get(settings) + ); } if (SETTING_HTTP_TCP_KEEP_INTERVAL.get(settings) >= 0) { - final SocketOption keepIntervalOption = NetUtils.getTcpKeepIntervalSocketOptionOrNull(); - if (keepIntervalOption != null) { - serverBootstrap.childOption( - NioChannelOption.of(keepIntervalOption), - SETTING_HTTP_TCP_KEEP_INTERVAL.get(settings) - ); - } + serverBootstrap.childOption( + NioChannelOption.of(NetUtils.getTcpKeepIntervalSocketOption()), + SETTING_HTTP_TCP_KEEP_INTERVAL.get(settings) + ); } if (SETTING_HTTP_TCP_KEEP_COUNT.get(settings) >= 0) { - final SocketOption keepCountOption = NetUtils.getTcpKeepCountSocketOptionOrNull(); - if (keepCountOption != null) { - serverBootstrap.childOption(NioChannelOption.of(keepCountOption), SETTING_HTTP_TCP_KEEP_COUNT.get(settings)); - } + serverBootstrap.childOption( + NioChannelOption.of(NetUtils.getTcpKeepCountSocketOption()), + SETTING_HTTP_TCP_KEEP_COUNT.get(settings) + ); } } } diff --git a/modules/transport-netty4/src/main/java/org/elasticsearch/transport/netty4/NetUtils.java b/modules/transport-netty4/src/main/java/org/elasticsearch/transport/netty4/NetUtils.java index ffd423a7b092a..6c93b6036578d 100644 --- a/modules/transport-netty4/src/main/java/org/elasticsearch/transport/netty4/NetUtils.java +++ b/modules/transport-netty4/src/main/java/org/elasticsearch/transport/netty4/NetUtils.java @@ -8,12 +8,15 @@ package org.elasticsearch.transport.netty4; +import jdk.net.ExtendedSocketOptions; + +import org.elasticsearch.core.SuppressForbidden; + import java.io.IOException; -import java.lang.reflect.Field; import java.net.SocketOption; import java.net.StandardSocketOptions; import java.nio.channels.NetworkChannel; -import java.util.Arrays; +import java.util.Objects; /** * Utilities for network-related methods. @@ -22,37 +25,31 @@ public class NetUtils { private NetUtils() {} + // Accessors to the extended socket options reduce the proliferation of the non-portable + // ExtendedSocketOptions type. + /** - * Returns the extended TCP_KEEPIDLE socket option, if available on this JDK + * Returns the extended TCP_KEEPIDLE socket option. */ - public static SocketOption getTcpKeepIdleSocketOptionOrNull() { - return getExtendedSocketOptionOrNull("TCP_KEEPIDLE"); + @SuppressForbidden(reason = "access to non-portable socket option required") + public static SocketOption getTcpKeepIdleSocketOption() { + return ExtendedSocketOptions.TCP_KEEPIDLE; } /** - * Returns the extended TCP_KEEPINTERVAL socket option, if available on this JDK + * Returns the extended TCP_KEEPINTERVAL socket option. */ - public static SocketOption getTcpKeepIntervalSocketOptionOrNull() { - return getExtendedSocketOptionOrNull("TCP_KEEPINTERVAL"); + @SuppressForbidden(reason = "access to non-portable socket option required") + public static SocketOption getTcpKeepIntervalSocketOption() { + return ExtendedSocketOptions.TCP_KEEPINTERVAL; } /** - * Returns the extended TCP_KEEPCOUNT socket option, if available on this JDK + * Returns the extended TCP_KEEPCOUNT socket option. */ - public static SocketOption getTcpKeepCountSocketOptionOrNull() { - return getExtendedSocketOptionOrNull("TCP_KEEPCOUNT"); - } - - @SuppressWarnings("unchecked") - private static SocketOption getExtendedSocketOptionOrNull(String fieldName) { - try { - final Class extendedSocketOptionsClass = Class.forName("jdk.net.ExtendedSocketOptions"); - final Field field = extendedSocketOptionsClass.getField(fieldName); - return (SocketOption) field.get(null); - } catch (Exception t) { - // ignore - return null; - } + @SuppressForbidden(reason = "access to non-portable socket option required") + public static SocketOption getTcpKeepCountSocketOption() { + return ExtendedSocketOptions.TCP_KEEPCOUNT; } /** @@ -67,13 +64,9 @@ public static void tryEnsureReasonableKeepAliveConfig(NetworkChannel socketChann if (socketChannel.supportedOptions().contains(StandardSocketOptions.SO_KEEPALIVE)) { final Boolean keepalive = socketChannel.getOption(StandardSocketOptions.SO_KEEPALIVE); assert keepalive != null; - if (keepalive.booleanValue()) { - for (SocketOption option : Arrays.asList( - NetUtils.getTcpKeepIdleSocketOptionOrNull(), - NetUtils.getTcpKeepIntervalSocketOptionOrNull() - )) { - setMinValueForSocketOption(socketChannel, option, 300); - } + if (keepalive) { + setMinValueForSocketOption(socketChannel, getTcpKeepIdleSocketOption(), 300); + setMinValueForSocketOption(socketChannel, getTcpKeepIntervalSocketOption(), 300); } } } catch (Exception e) { @@ -84,7 +77,8 @@ public static void tryEnsureReasonableKeepAliveConfig(NetworkChannel socketChann } private static void setMinValueForSocketOption(NetworkChannel socketChannel, SocketOption option, int minValue) { - if (option != null && socketChannel.supportedOptions().contains(option)) { + Objects.requireNonNull(option); + if (socketChannel.supportedOptions().contains(option)) { try { final Integer currentIdleVal = socketChannel.getOption(option); assert currentIdleVal != null; diff --git a/modules/transport-netty4/src/main/java/org/elasticsearch/transport/netty4/Netty4Transport.java b/modules/transport-netty4/src/main/java/org/elasticsearch/transport/netty4/Netty4Transport.java index 37c87d19e811f..0241669d15b8e 100644 --- a/modules/transport-netty4/src/main/java/org/elasticsearch/transport/netty4/Netty4Transport.java +++ b/modules/transport-netty4/src/main/java/org/elasticsearch/transport/netty4/Netty4Transport.java @@ -47,7 +47,6 @@ import java.io.IOException; import java.net.InetSocketAddress; -import java.net.SocketOption; import java.util.Map; import static org.elasticsearch.common.settings.Setting.byteSizeSetting; @@ -165,22 +164,19 @@ private Bootstrap createClientBootstrap(SharedGroupFactory.SharedGroup sharedGro if (TransportSettings.TCP_KEEP_ALIVE.get(settings)) { // Note that Netty logs a warning if it can't set the option if (TransportSettings.TCP_KEEP_IDLE.get(settings) >= 0) { - final SocketOption keepIdleOption = NetUtils.getTcpKeepIdleSocketOptionOrNull(); - if (keepIdleOption != null) { - bootstrap.option(NioChannelOption.of(keepIdleOption), TransportSettings.TCP_KEEP_IDLE.get(settings)); - } + bootstrap.option(NioChannelOption.of(NetUtils.getTcpKeepIdleSocketOption()), TransportSettings.TCP_KEEP_IDLE.get(settings)); } if (TransportSettings.TCP_KEEP_INTERVAL.get(settings) >= 0) { - final SocketOption keepIntervalOption = NetUtils.getTcpKeepIntervalSocketOptionOrNull(); - if (keepIntervalOption != null) { - bootstrap.option(NioChannelOption.of(keepIntervalOption), TransportSettings.TCP_KEEP_INTERVAL.get(settings)); - } + bootstrap.option( + NioChannelOption.of(NetUtils.getTcpKeepIntervalSocketOption()), + TransportSettings.TCP_KEEP_INTERVAL.get(settings) + ); } if (TransportSettings.TCP_KEEP_COUNT.get(settings) >= 0) { - final SocketOption keepCountOption = NetUtils.getTcpKeepCountSocketOptionOrNull(); - if (keepCountOption != null) { - bootstrap.option(NioChannelOption.of(keepCountOption), TransportSettings.TCP_KEEP_COUNT.get(settings)); - } + bootstrap.option( + NioChannelOption.of(NetUtils.getTcpKeepCountSocketOption()), + TransportSettings.TCP_KEEP_COUNT.get(settings) + ); } } @@ -236,23 +232,16 @@ private void createServerBootstrap(ProfileSettings profileSettings, SharedGroupF if (profileSettings.tcpKeepAlive) { // Note that Netty logs a warning if it can't set the option if (profileSettings.tcpKeepIdle >= 0) { - final SocketOption keepIdleOption = NetUtils.getTcpKeepIdleSocketOptionOrNull(); - if (keepIdleOption != null) { - serverBootstrap.childOption(NioChannelOption.of(keepIdleOption), profileSettings.tcpKeepIdle); - } + serverBootstrap.childOption(NioChannelOption.of(NetUtils.getTcpKeepIdleSocketOption()), profileSettings.tcpKeepIdle); } if (profileSettings.tcpKeepInterval >= 0) { - final SocketOption keepIntervalOption = NetUtils.getTcpKeepIntervalSocketOptionOrNull(); - if (keepIntervalOption != null) { - serverBootstrap.childOption(NioChannelOption.of(keepIntervalOption), profileSettings.tcpKeepInterval); - } - + serverBootstrap.childOption( + NioChannelOption.of(NetUtils.getTcpKeepIntervalSocketOption()), + profileSettings.tcpKeepInterval + ); } if (profileSettings.tcpKeepCount >= 0) { - final SocketOption keepCountOption = NetUtils.getTcpKeepCountSocketOptionOrNull(); - if (keepCountOption != null) { - serverBootstrap.childOption(NioChannelOption.of(keepCountOption), profileSettings.tcpKeepCount); - } + serverBootstrap.childOption(NioChannelOption.of(NetUtils.getTcpKeepCountSocketOption()), profileSettings.tcpKeepCount); } } diff --git a/modules/transport-netty4/src/test/java/org/elasticsearch/transport/netty4/NetUtilsTests.java b/modules/transport-netty4/src/test/java/org/elasticsearch/transport/netty4/NetUtilsTests.java index 6cea1296f2e7a..1a4e7b3fc1565 100644 --- a/modules/transport-netty4/src/test/java/org/elasticsearch/transport/netty4/NetUtilsTests.java +++ b/modules/transport-netty4/src/test/java/org/elasticsearch/transport/netty4/NetUtilsTests.java @@ -8,17 +8,38 @@ package org.elasticsearch.transport.netty4; -import org.apache.lucene.util.Constants; import org.elasticsearch.core.IOUtils; import org.elasticsearch.test.ESTestCase; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.channels.NetworkChannel; +import java.nio.channels.SocketChannel; + +import static org.hamcrest.Matchers.hasItem; + public class NetUtilsTests extends ESTestCase { - public void testExtendedSocketOptions() { - assumeTrue("JDK possibly not supported", Constants.JVM_NAME.contains("HotSpot") || Constants.JVM_NAME.contains("OpenJDK")); + public void testExtendedSocketOptions() throws IOException { + assertTrue( + "jdk.net module not resolved", + ModuleLayer.boot().modules().stream().map(Module::getName).anyMatch(nm -> nm.equals("jdk.net")) + ); + assumeTrue("Platform possibly not supported", IOUtils.LINUX || IOUtils.MAC_OS_X); - assertNotNull(NetUtils.getTcpKeepIdleSocketOptionOrNull()); - assertNotNull(NetUtils.getTcpKeepIntervalSocketOptionOrNull()); - assertNotNull(NetUtils.getTcpKeepCountSocketOptionOrNull()); + try (var channel = networkChannel()) { + var options = channel.supportedOptions(); + assertThat(options, hasItem(NetUtils.getTcpKeepIdleSocketOption())); + assertThat(options, hasItem(NetUtils.getTcpKeepIntervalSocketOption())); + assertThat(options, hasItem(NetUtils.getTcpKeepCountSocketOption())); + } + } + + private static NetworkChannel networkChannel() { + try { + return SocketChannel.open(); + } catch (IOException e) { + throw new UncheckedIOException(e); + } } } diff --git a/modules/transport-netty4/src/test/java/org/elasticsearch/transport/netty4/SimpleNetty4TransportTests.java b/modules/transport-netty4/src/test/java/org/elasticsearch/transport/netty4/SimpleNetty4TransportTests.java index 253758e378856..91a31f19f0e3b 100644 --- a/modules/transport-netty4/src/test/java/org/elasticsearch/transport/netty4/SimpleNetty4TransportTests.java +++ b/modules/transport-netty4/src/test/java/org/elasticsearch/transport/netty4/SimpleNetty4TransportTests.java @@ -125,12 +125,12 @@ private void checkDefaultKeepAliveOptions(TcpChannel channel) throws IOException assertThat(nettyChannel.getNettyChannel(), instanceOf(Netty4NioSocketChannel.class)); Netty4NioSocketChannel netty4NioSocketChannel = (Netty4NioSocketChannel) nettyChannel.getNettyChannel(); SocketChannel socketChannel = netty4NioSocketChannel.javaChannel(); - assertThat(socketChannel.supportedOptions(), hasItem(NetUtils.getTcpKeepIdleSocketOptionOrNull())); - Integer keepIdle = socketChannel.getOption(NetUtils.getTcpKeepIdleSocketOptionOrNull()); + assertThat(socketChannel.supportedOptions(), hasItem(NetUtils.getTcpKeepIdleSocketOption())); + Integer keepIdle = socketChannel.getOption(NetUtils.getTcpKeepIdleSocketOption()); assertNotNull(keepIdle); assertThat(keepIdle, lessThanOrEqualTo(500)); - assertThat(socketChannel.supportedOptions(), hasItem(NetUtils.getTcpKeepIntervalSocketOptionOrNull())); - Integer keepInterval = socketChannel.getOption(NetUtils.getTcpKeepIntervalSocketOptionOrNull()); + assertThat(socketChannel.supportedOptions(), hasItem(NetUtils.getTcpKeepIntervalSocketOption())); + Integer keepInterval = socketChannel.getOption(NetUtils.getTcpKeepIntervalSocketOption()); assertNotNull(keepInterval); assertThat(keepInterval, lessThanOrEqualTo(500)); }