Skip to content

Commit c8dd9ae

Browse files
authored
[8.3] Ensure that the extended socket options TCP_KEEPXXX are available (#88935) (#88956)
1 parent 52c7df1 commit c8dd9ae

File tree

8 files changed

+91
-83
lines changed

8 files changed

+91
-83
lines changed

distribution/tools/server-cli/src/main/java/org/elasticsearch/server/cli/ServerProcess.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,7 @@ private static Process createProcess(
220220
command.addAll(jvmOptions);
221221
command.add("--module-path");
222222
command.add(esHome.resolve("lib").toString());
223+
command.add("--add-modules=jdk.net"); // very special circumstance; explicit modules should typically not be added here
223224
command.add("-m");
224225
command.add("org.elasticsearch.server/org.elasticsearch.bootstrap.Elasticsearch");
225226

docs/changelog/88935.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
pr: 88935
2+
summary: Ensure that the extended socket options TCP_KEEPXXX are available
3+
area: Network
4+
type: bug
5+
issues:
6+
- 88897

modules/transport-netty4/src/main/java/module-info.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
*/
88

99
module org.elasticsearch.transport.netty4 {
10+
requires jdk.net;
1011
requires org.elasticsearch.base;
1112
requires org.elasticsearch.server;
1213
requires org.elasticsearch.xcontent;

modules/transport-netty4/src/main/java/org/elasticsearch/http/netty4/Netty4HttpServerTransport.java

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@
5656
import org.elasticsearch.xcontent.NamedXContentRegistry;
5757

5858
import java.net.InetSocketAddress;
59-
import java.net.SocketOption;
6059
import java.util.concurrent.TimeUnit;
6160

6261
import static org.elasticsearch.http.HttpTransportSettings.SETTING_HTTP_MAX_CHUNK_SIZE;
@@ -204,25 +203,22 @@ protected void doStart() {
204203
// Netty logs a warning if it can't set the option, so try this only on supported platforms
205204
if (IOUtils.LINUX || IOUtils.MAC_OS_X) {
206205
if (SETTING_HTTP_TCP_KEEP_IDLE.get(settings) >= 0) {
207-
final SocketOption<Integer> keepIdleOption = NetUtils.getTcpKeepIdleSocketOptionOrNull();
208-
if (keepIdleOption != null) {
209-
serverBootstrap.childOption(NioChannelOption.of(keepIdleOption), SETTING_HTTP_TCP_KEEP_IDLE.get(settings));
210-
}
206+
serverBootstrap.childOption(
207+
NioChannelOption.of(NetUtils.getTcpKeepIdleSocketOption()),
208+
SETTING_HTTP_TCP_KEEP_IDLE.get(settings)
209+
);
211210
}
212211
if (SETTING_HTTP_TCP_KEEP_INTERVAL.get(settings) >= 0) {
213-
final SocketOption<Integer> keepIntervalOption = NetUtils.getTcpKeepIntervalSocketOptionOrNull();
214-
if (keepIntervalOption != null) {
215-
serverBootstrap.childOption(
216-
NioChannelOption.of(keepIntervalOption),
217-
SETTING_HTTP_TCP_KEEP_INTERVAL.get(settings)
218-
);
219-
}
212+
serverBootstrap.childOption(
213+
NioChannelOption.of(NetUtils.getTcpKeepIntervalSocketOption()),
214+
SETTING_HTTP_TCP_KEEP_INTERVAL.get(settings)
215+
);
220216
}
221217
if (SETTING_HTTP_TCP_KEEP_COUNT.get(settings) >= 0) {
222-
final SocketOption<Integer> keepCountOption = NetUtils.getTcpKeepCountSocketOptionOrNull();
223-
if (keepCountOption != null) {
224-
serverBootstrap.childOption(NioChannelOption.of(keepCountOption), SETTING_HTTP_TCP_KEEP_COUNT.get(settings));
225-
}
218+
serverBootstrap.childOption(
219+
NioChannelOption.of(NetUtils.getTcpKeepCountSocketOption()),
220+
SETTING_HTTP_TCP_KEEP_COUNT.get(settings)
221+
);
226222
}
227223
}
228224
}

modules/transport-netty4/src/main/java/org/elasticsearch/transport/netty4/NetUtils.java

Lines changed: 25 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,15 @@
88

99
package org.elasticsearch.transport.netty4;
1010

11+
import jdk.net.ExtendedSocketOptions;
12+
13+
import org.elasticsearch.core.SuppressForbidden;
14+
1115
import java.io.IOException;
12-
import java.lang.reflect.Field;
1316
import java.net.SocketOption;
1417
import java.net.StandardSocketOptions;
1518
import java.nio.channels.NetworkChannel;
16-
import java.util.Arrays;
19+
import java.util.Objects;
1720

1821
/**
1922
* Utilities for network-related methods.
@@ -22,37 +25,31 @@ public class NetUtils {
2225

2326
private NetUtils() {}
2427

28+
// Accessors to the extended socket options reduce the proliferation of the non-portable
29+
// ExtendedSocketOptions type.
30+
2531
/**
26-
* Returns the extended TCP_KEEPIDLE socket option, if available on this JDK
32+
* Returns the extended TCP_KEEPIDLE socket option.
2733
*/
28-
public static SocketOption<Integer> getTcpKeepIdleSocketOptionOrNull() {
29-
return getExtendedSocketOptionOrNull("TCP_KEEPIDLE");
34+
@SuppressForbidden(reason = "access to non-portable socket option required")
35+
public static SocketOption<Integer> getTcpKeepIdleSocketOption() {
36+
return ExtendedSocketOptions.TCP_KEEPIDLE;
3037
}
3138

3239
/**
33-
* Returns the extended TCP_KEEPINTERVAL socket option, if available on this JDK
40+
* Returns the extended TCP_KEEPINTERVAL socket option.
3441
*/
35-
public static SocketOption<Integer> getTcpKeepIntervalSocketOptionOrNull() {
36-
return getExtendedSocketOptionOrNull("TCP_KEEPINTERVAL");
42+
@SuppressForbidden(reason = "access to non-portable socket option required")
43+
public static SocketOption<Integer> getTcpKeepIntervalSocketOption() {
44+
return ExtendedSocketOptions.TCP_KEEPINTERVAL;
3745
}
3846

3947
/**
40-
* Returns the extended TCP_KEEPCOUNT socket option, if available on this JDK
48+
* Returns the extended TCP_KEEPCOUNT socket option.
4149
*/
42-
public static SocketOption<Integer> getTcpKeepCountSocketOptionOrNull() {
43-
return getExtendedSocketOptionOrNull("TCP_KEEPCOUNT");
44-
}
45-
46-
@SuppressWarnings("unchecked")
47-
private static <T> SocketOption<T> getExtendedSocketOptionOrNull(String fieldName) {
48-
try {
49-
final Class<?> extendedSocketOptionsClass = Class.forName("jdk.net.ExtendedSocketOptions");
50-
final Field field = extendedSocketOptionsClass.getField(fieldName);
51-
return (SocketOption<T>) field.get(null);
52-
} catch (Exception t) {
53-
// ignore
54-
return null;
55-
}
50+
@SuppressForbidden(reason = "access to non-portable socket option required")
51+
public static SocketOption<Integer> getTcpKeepCountSocketOption() {
52+
return ExtendedSocketOptions.TCP_KEEPCOUNT;
5653
}
5754

5855
/**
@@ -67,13 +64,9 @@ public static void tryEnsureReasonableKeepAliveConfig(NetworkChannel socketChann
6764
if (socketChannel.supportedOptions().contains(StandardSocketOptions.SO_KEEPALIVE)) {
6865
final Boolean keepalive = socketChannel.getOption(StandardSocketOptions.SO_KEEPALIVE);
6966
assert keepalive != null;
70-
if (keepalive.booleanValue()) {
71-
for (SocketOption<Integer> option : Arrays.asList(
72-
NetUtils.getTcpKeepIdleSocketOptionOrNull(),
73-
NetUtils.getTcpKeepIntervalSocketOptionOrNull()
74-
)) {
75-
setMinValueForSocketOption(socketChannel, option, 300);
76-
}
67+
if (keepalive) {
68+
setMinValueForSocketOption(socketChannel, getTcpKeepIdleSocketOption(), 300);
69+
setMinValueForSocketOption(socketChannel, getTcpKeepIntervalSocketOption(), 300);
7770
}
7871
}
7972
} catch (Exception e) {
@@ -84,7 +77,8 @@ public static void tryEnsureReasonableKeepAliveConfig(NetworkChannel socketChann
8477
}
8578

8679
private static void setMinValueForSocketOption(NetworkChannel socketChannel, SocketOption<Integer> option, int minValue) {
87-
if (option != null && socketChannel.supportedOptions().contains(option)) {
80+
Objects.requireNonNull(option);
81+
if (socketChannel.supportedOptions().contains(option)) {
8882
try {
8983
final Integer currentIdleVal = socketChannel.getOption(option);
9084
assert currentIdleVal != null;

modules/transport-netty4/src/main/java/org/elasticsearch/transport/netty4/Netty4Transport.java

Lines changed: 15 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@
4747

4848
import java.io.IOException;
4949
import java.net.InetSocketAddress;
50-
import java.net.SocketOption;
5150
import java.util.Map;
5251

5352
import static org.elasticsearch.common.settings.Setting.byteSizeSetting;
@@ -165,22 +164,19 @@ private Bootstrap createClientBootstrap(SharedGroupFactory.SharedGroup sharedGro
165164
if (TransportSettings.TCP_KEEP_ALIVE.get(settings)) {
166165
// Note that Netty logs a warning if it can't set the option
167166
if (TransportSettings.TCP_KEEP_IDLE.get(settings) >= 0) {
168-
final SocketOption<Integer> keepIdleOption = NetUtils.getTcpKeepIdleSocketOptionOrNull();
169-
if (keepIdleOption != null) {
170-
bootstrap.option(NioChannelOption.of(keepIdleOption), TransportSettings.TCP_KEEP_IDLE.get(settings));
171-
}
167+
bootstrap.option(NioChannelOption.of(NetUtils.getTcpKeepIdleSocketOption()), TransportSettings.TCP_KEEP_IDLE.get(settings));
172168
}
173169
if (TransportSettings.TCP_KEEP_INTERVAL.get(settings) >= 0) {
174-
final SocketOption<Integer> keepIntervalOption = NetUtils.getTcpKeepIntervalSocketOptionOrNull();
175-
if (keepIntervalOption != null) {
176-
bootstrap.option(NioChannelOption.of(keepIntervalOption), TransportSettings.TCP_KEEP_INTERVAL.get(settings));
177-
}
170+
bootstrap.option(
171+
NioChannelOption.of(NetUtils.getTcpKeepIntervalSocketOption()),
172+
TransportSettings.TCP_KEEP_INTERVAL.get(settings)
173+
);
178174
}
179175
if (TransportSettings.TCP_KEEP_COUNT.get(settings) >= 0) {
180-
final SocketOption<Integer> keepCountOption = NetUtils.getTcpKeepCountSocketOptionOrNull();
181-
if (keepCountOption != null) {
182-
bootstrap.option(NioChannelOption.of(keepCountOption), TransportSettings.TCP_KEEP_COUNT.get(settings));
183-
}
176+
bootstrap.option(
177+
NioChannelOption.of(NetUtils.getTcpKeepCountSocketOption()),
178+
TransportSettings.TCP_KEEP_COUNT.get(settings)
179+
);
184180
}
185181
}
186182

@@ -236,23 +232,16 @@ private void createServerBootstrap(ProfileSettings profileSettings, SharedGroupF
236232
if (profileSettings.tcpKeepAlive) {
237233
// Note that Netty logs a warning if it can't set the option
238234
if (profileSettings.tcpKeepIdle >= 0) {
239-
final SocketOption<Integer> keepIdleOption = NetUtils.getTcpKeepIdleSocketOptionOrNull();
240-
if (keepIdleOption != null) {
241-
serverBootstrap.childOption(NioChannelOption.of(keepIdleOption), profileSettings.tcpKeepIdle);
242-
}
235+
serverBootstrap.childOption(NioChannelOption.of(NetUtils.getTcpKeepIdleSocketOption()), profileSettings.tcpKeepIdle);
243236
}
244237
if (profileSettings.tcpKeepInterval >= 0) {
245-
final SocketOption<Integer> keepIntervalOption = NetUtils.getTcpKeepIntervalSocketOptionOrNull();
246-
if (keepIntervalOption != null) {
247-
serverBootstrap.childOption(NioChannelOption.of(keepIntervalOption), profileSettings.tcpKeepInterval);
248-
}
249-
238+
serverBootstrap.childOption(
239+
NioChannelOption.of(NetUtils.getTcpKeepIntervalSocketOption()),
240+
profileSettings.tcpKeepInterval
241+
);
250242
}
251243
if (profileSettings.tcpKeepCount >= 0) {
252-
final SocketOption<Integer> keepCountOption = NetUtils.getTcpKeepCountSocketOptionOrNull();
253-
if (keepCountOption != null) {
254-
serverBootstrap.childOption(NioChannelOption.of(keepCountOption), profileSettings.tcpKeepCount);
255-
}
244+
serverBootstrap.childOption(NioChannelOption.of(NetUtils.getTcpKeepCountSocketOption()), profileSettings.tcpKeepCount);
256245
}
257246
}
258247

modules/transport-netty4/src/test/java/org/elasticsearch/transport/netty4/NetUtilsTests.java

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,38 @@
88

99
package org.elasticsearch.transport.netty4;
1010

11-
import org.apache.lucene.util.Constants;
1211
import org.elasticsearch.core.IOUtils;
1312
import org.elasticsearch.test.ESTestCase;
1413

14+
import java.io.IOException;
15+
import java.io.UncheckedIOException;
16+
import java.nio.channels.NetworkChannel;
17+
import java.nio.channels.SocketChannel;
18+
19+
import static org.hamcrest.Matchers.hasItem;
20+
1521
public class NetUtilsTests extends ESTestCase {
1622

17-
public void testExtendedSocketOptions() {
18-
assumeTrue("JDK possibly not supported", Constants.JVM_NAME.contains("HotSpot") || Constants.JVM_NAME.contains("OpenJDK"));
23+
public void testExtendedSocketOptions() throws IOException {
24+
assertTrue(
25+
"jdk.net module not resolved",
26+
ModuleLayer.boot().modules().stream().map(Module::getName).anyMatch(nm -> nm.equals("jdk.net"))
27+
);
28+
1929
assumeTrue("Platform possibly not supported", IOUtils.LINUX || IOUtils.MAC_OS_X);
20-
assertNotNull(NetUtils.getTcpKeepIdleSocketOptionOrNull());
21-
assertNotNull(NetUtils.getTcpKeepIntervalSocketOptionOrNull());
22-
assertNotNull(NetUtils.getTcpKeepCountSocketOptionOrNull());
30+
try (var channel = networkChannel()) {
31+
var options = channel.supportedOptions();
32+
assertThat(options, hasItem(NetUtils.getTcpKeepIdleSocketOption()));
33+
assertThat(options, hasItem(NetUtils.getTcpKeepIntervalSocketOption()));
34+
assertThat(options, hasItem(NetUtils.getTcpKeepCountSocketOption()));
35+
}
36+
}
37+
38+
private static NetworkChannel networkChannel() {
39+
try {
40+
return SocketChannel.open();
41+
} catch (IOException e) {
42+
throw new UncheckedIOException(e);
43+
}
2344
}
2445
}

modules/transport-netty4/src/test/java/org/elasticsearch/transport/netty4/SimpleNetty4TransportTests.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -125,12 +125,12 @@ private void checkDefaultKeepAliveOptions(TcpChannel channel) throws IOException
125125
assertThat(nettyChannel.getNettyChannel(), instanceOf(Netty4NioSocketChannel.class));
126126
Netty4NioSocketChannel netty4NioSocketChannel = (Netty4NioSocketChannel) nettyChannel.getNettyChannel();
127127
SocketChannel socketChannel = netty4NioSocketChannel.javaChannel();
128-
assertThat(socketChannel.supportedOptions(), hasItem(NetUtils.getTcpKeepIdleSocketOptionOrNull()));
129-
Integer keepIdle = socketChannel.getOption(NetUtils.getTcpKeepIdleSocketOptionOrNull());
128+
assertThat(socketChannel.supportedOptions(), hasItem(NetUtils.getTcpKeepIdleSocketOption()));
129+
Integer keepIdle = socketChannel.getOption(NetUtils.getTcpKeepIdleSocketOption());
130130
assertNotNull(keepIdle);
131131
assertThat(keepIdle, lessThanOrEqualTo(500));
132-
assertThat(socketChannel.supportedOptions(), hasItem(NetUtils.getTcpKeepIntervalSocketOptionOrNull()));
133-
Integer keepInterval = socketChannel.getOption(NetUtils.getTcpKeepIntervalSocketOptionOrNull());
132+
assertThat(socketChannel.supportedOptions(), hasItem(NetUtils.getTcpKeepIntervalSocketOption()));
133+
Integer keepInterval = socketChannel.getOption(NetUtils.getTcpKeepIntervalSocketOption());
134134
assertNotNull(keepInterval);
135135
assertThat(keepInterval, lessThanOrEqualTo(500));
136136
}

0 commit comments

Comments
 (0)