Skip to content

Commit

Permalink
Merge pull request #5183 from aksabg/feature-5163-configurable-socket…
Browse files Browse the repository at this point in the history
…-keepalive-interval

Feature 5163 configurable socket keepalive interval
  • Loading branch information
vietj committed Sep 20, 2024
2 parents d1fee49 + 9d1d539 commit f9ab03b
Show file tree
Hide file tree
Showing 5 changed files with 164 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,21 @@ static void fromJson(Iterable<java.util.Map.Entry<String, Object>> json, EventBu
obj.setTcpKeepAlive((Boolean)member.getValue());
}
break;
case "tcpKeepAliveCount":
if (member.getValue() instanceof Number) {
obj.setTcpKeepAliveCount(((Number)member.getValue()).intValue());
}
break;
case "tcpKeepAliveIdleSeconds":
if (member.getValue() instanceof Number) {
obj.setTcpKeepAliveIdleSeconds(((Number)member.getValue()).intValue());
}
break;
case "tcpKeepAliveIntervalSeconds":
if (member.getValue() instanceof Number) {
obj.setTcpKeepAliveIntervalSeconds(((Number)member.getValue()).intValue());
}
break;
case "tcpNoDelay":
if (member.getValue() instanceof Boolean) {
obj.setTcpNoDelay((Boolean)member.getValue());
Expand Down Expand Up @@ -361,6 +376,9 @@ static void toJson(EventBusOptions obj, java.util.Map<String, Object> json) {
json.put("tcpCork", obj.isTcpCork());
json.put("tcpFastOpen", obj.isTcpFastOpen());
json.put("tcpKeepAlive", obj.isTcpKeepAlive());
json.put("tcpKeepAliveCount", obj.getTcpKeepAliveCount());
json.put("tcpKeepAliveIdleSeconds", obj.getTcpKeepAliveIdleSeconds());
json.put("tcpKeepAliveIntervalSeconds", obj.getTcpKeepAliveIntervalSeconds());
json.put("tcpNoDelay", obj.isTcpNoDelay());
json.put("tcpQuickAck", obj.isTcpQuickAck());
json.put("tcpUserTimeout", obj.getTcpUserTimeout());
Expand Down
18 changes: 18 additions & 0 deletions src/main/generated/io/vertx/core/net/TCPSSLOptionsConverter.java
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,21 @@ static void fromJson(Iterable<java.util.Map.Entry<String, Object>> json, TCPSSLO
obj.setTcpKeepAlive((Boolean)member.getValue());
}
break;
case "tcpKeepAliveCount":
if (member.getValue() instanceof Number) {
obj.setTcpKeepAliveCount(((Number)member.getValue()).intValue());
}
break;
case "tcpKeepAliveIdleSeconds":
if (member.getValue() instanceof Number) {
obj.setTcpKeepAliveIdleSeconds(((Number)member.getValue()).intValue());
}
break;
case "tcpKeepAliveIntervalSeconds":
if (member.getValue() instanceof Number) {
obj.setTcpKeepAliveIntervalSeconds(((Number)member.getValue()).intValue());
}
break;
case "tcpNoDelay":
if (member.getValue() instanceof Boolean) {
obj.setTcpNoDelay((Boolean)member.getValue());
Expand Down Expand Up @@ -233,6 +248,9 @@ static void toJson(TCPSSLOptions obj, java.util.Map<String, Object> json) {
json.put("tcpCork", obj.isTcpCork());
json.put("tcpFastOpen", obj.isTcpFastOpen());
json.put("tcpKeepAlive", obj.isTcpKeepAlive());
json.put("tcpKeepAliveCount", obj.getTcpKeepAliveCount());
json.put("tcpKeepAliveIdleSeconds", obj.getTcpKeepAliveIdleSeconds());
json.put("tcpKeepAliveIntervalSeconds", obj.getTcpKeepAliveIntervalSeconds());
json.put("tcpNoDelay", obj.isTcpNoDelay());
json.put("tcpQuickAck", obj.isTcpQuickAck());
json.put("tcpUserTimeout", obj.getTcpUserTimeout());
Expand Down
10 changes: 10 additions & 0 deletions src/main/java/io/vertx/core/impl/transports/EpollTransport.java
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,16 @@ public void configure(NetServerOptions options, boolean domainSocket, ServerBoot
}
bootstrap.childOption(EpollChannelOption.TCP_QUICKACK, options.isTcpQuickAck());
bootstrap.childOption(EpollChannelOption.TCP_CORK, options.isTcpCork());

if (options.isTcpKeepAlive() && options.getTcpKeepAliveIdleSeconds() != -1) {
bootstrap.childOption(EpollChannelOption.TCP_KEEPIDLE, options.getTcpKeepAliveIdleSeconds());
}
if (options.isTcpKeepAlive() && options.getTcpKeepAliveCount() != -1) {
bootstrap.childOption(EpollChannelOption.TCP_KEEPCNT, options.getTcpKeepAliveCount());
}
if (options.isTcpKeepAlive() && options.getTcpKeepAliveIntervalSeconds() != -1) {
bootstrap.childOption(EpollChannelOption.TCP_KEEPINTVL, options.getTcpKeepAliveIntervalSeconds());
}
}
Transport.super.configure(options, domainSocket, bootstrap);
}
Expand Down
81 changes: 81 additions & 0 deletions src/main/java/io/vertx/core/net/TCPSSLOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import io.vertx.codegen.annotations.GenIgnore;
import io.vertx.codegen.json.annotations.JsonGen;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.impl.Arguments;
import io.vertx.core.json.JsonObject;
import io.netty.handler.logging.ByteBufFormat;

Expand All @@ -40,6 +41,21 @@ public abstract class TCPSSLOptions extends NetworkOptions {
*/
public static final boolean DEFAULT_TCP_KEEP_ALIVE = false;

/**
* Default value for tcp keepalive idle time -1 defaults to OS settings
*/
public static final int DEFAULT_TCP_KEEPALIVE_IDLE_SECONDS = -1;

/**
* Default value for tcp keepalive count -1 defaults to OS settings
*/
public static final int DEFAULT_TCP_KEEPALIVE_COUNT = -1;

/**
* Default value for tcp keepalive interval -1 defaults to OS settings
*/
public static final int DEFAULT_TCP_KEEAPLIVE_INTERVAL_SECONDS = -1;

/**
* The default value of SO_linger = -1
*/
Expand Down Expand Up @@ -119,6 +135,9 @@ public abstract class TCPSSLOptions extends NetworkOptions {

private boolean tcpNoDelay;
private boolean tcpKeepAlive;
private int tcpKeepAliveIdleSeconds;
private int tcpKeepAliveCount;
private int tcpKeepAliveIntervalSeconds;
private int soLinger;
private int idleTimeout;
private int readIdleTimeout;
Expand Down Expand Up @@ -149,6 +168,9 @@ public TCPSSLOptions(TCPSSLOptions other) {
super(other);
this.tcpNoDelay = other.isTcpNoDelay();
this.tcpKeepAlive = other.isTcpKeepAlive();
this.tcpKeepAliveIdleSeconds = other.getTcpKeepAliveIdleSeconds();
this.tcpKeepAliveCount = other.getTcpKeepAliveCount();
this.tcpKeepAliveIntervalSeconds = other.getTcpKeepAliveIntervalSeconds();
this.soLinger = other.getSoLinger();
this.idleTimeout = other.getIdleTimeout();
this.idleTimeoutUnit = other.getIdleTimeoutUnit() != null ? other.getIdleTimeoutUnit() : DEFAULT_IDLE_TIMEOUT_TIME_UNIT;
Expand Down Expand Up @@ -188,6 +210,9 @@ public JsonObject toJson() {
private void init() {
tcpNoDelay = DEFAULT_TCP_NO_DELAY;
tcpKeepAlive = DEFAULT_TCP_KEEP_ALIVE;
tcpKeepAliveIdleSeconds = DEFAULT_TCP_KEEPALIVE_IDLE_SECONDS;
tcpKeepAliveCount = DEFAULT_TCP_KEEPALIVE_COUNT;
tcpKeepAliveIntervalSeconds = DEFAULT_TCP_KEEAPLIVE_INTERVAL_SECONDS;
soLinger = DEFAULT_SO_LINGER;
idleTimeout = DEFAULT_IDLE_TIMEOUT;
readIdleTimeout = DEFAULT_READ_IDLE_TIMEOUT;
Expand Down Expand Up @@ -243,6 +268,62 @@ public TCPSSLOptions setTcpKeepAlive(boolean tcpKeepAlive) {
return this;
}

/**
* @return the time in seconds the connection needs to remain idle before TCP starts sending keepalive probes
*/
public int getTcpKeepAliveIdleSeconds() {
return tcpKeepAliveIdleSeconds;
}

/**
* The time in seconds the connection needs to remain idle before TCP starts sending keepalive probes,
* if the socket option keepalive has been set.
*
* @param tcpKeepAliveIdleSeconds
* @return a reference to this, so the API can be used fluently
*/
public TCPSSLOptions setTcpKeepAliveIdleSeconds(int tcpKeepAliveIdleSeconds) {
Arguments.require(tcpKeepAliveIdleSeconds > 0 || tcpKeepAliveIdleSeconds == DEFAULT_TCP_KEEPALIVE_IDLE_SECONDS, "tcpKeepAliveIdleSeconds must be > 0");
this.tcpKeepAliveIdleSeconds = tcpKeepAliveIdleSeconds;
return this;
}

/**
* @return the maximum number of keepalive probes TCP should send before dropping the connection.
*/
public int getTcpKeepAliveCount() {
return tcpKeepAliveCount;
}

/**
* The maximum number of keepalive probes TCP should send before dropping the connection.
* @param tcpKeepAliveCount
* @return a reference to this, so the API can be used fluently
*/
public TCPSSLOptions setTcpKeepAliveCount(int tcpKeepAliveCount) {
Arguments.require(tcpKeepAliveCount > 0 || tcpKeepAliveCount == DEFAULT_TCP_KEEPALIVE_COUNT, "tcpKeepAliveCount must be > 0");
this.tcpKeepAliveCount = tcpKeepAliveCount;
return this;
}

/**
* @return the time in seconds between individual keepalive probes.
*/
public int getTcpKeepAliveIntervalSeconds() {
return tcpKeepAliveIntervalSeconds;
}

/**
* The time in seconds between individual keepalive probes.
* @param tcpKeepAliveIntervalSeconds
* @return
*/
public TCPSSLOptions setTcpKeepAliveIntervalSeconds(int tcpKeepAliveIntervalSeconds) {
Arguments.require(tcpKeepAliveIntervalSeconds > 0 || tcpKeepAliveIntervalSeconds == DEFAULT_TCP_KEEAPLIVE_INTERVAL_SECONDS, "tcpKeepAliveIntervalSeconds must be > 0");
this.tcpKeepAliveIntervalSeconds = tcpKeepAliveIntervalSeconds;
return this;
}

/**
*
* @return is SO_linger enabled
Expand Down
38 changes: 37 additions & 1 deletion src/test/java/io/vertx/core/net/NetTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,27 @@ public void testServerOptions() {
assertEquals(randomProxyTimeout, options.getProxyProtocolTimeout());
assertIllegalArgumentException(() -> options.setProxyProtocolTimeout(-123));

assertEquals(NetServerOptions.DEFAULT_TCP_KEEPALIVE_IDLE_SECONDS, options.getTcpKeepAliveIdleSeconds());
rand = TestUtils.randomPositiveInt();
assertEquals(options, options.setTcpKeepAliveIdleSeconds(rand));
assertEquals(rand, options.getTcpKeepAliveIdleSeconds());
assertIllegalArgumentException(() -> options.setTcpKeepAliveIdleSeconds(0));
assertIllegalArgumentException(() -> options.setTcpKeepAliveIdleSeconds(-123));

assertEquals(NetServerOptions.DEFAULT_TCP_KEEPALIVE_COUNT, options.getTcpKeepAliveCount());
rand = TestUtils.randomPositiveInt();
assertEquals(options, options.setTcpKeepAliveCount(rand));
assertEquals(rand, options.getTcpKeepAliveCount());
assertIllegalArgumentException(() -> options.setTcpKeepAliveCount(0));
assertIllegalArgumentException(() -> options.setTcpKeepAliveCount(-123));

assertEquals(NetServerOptions.DEFAULT_TCP_KEEAPLIVE_INTERVAL_SECONDS, options.getTcpKeepAliveIntervalSeconds());
rand = TestUtils.randomPositiveInt();
assertEquals(options, options.setTcpKeepAliveIntervalSeconds(rand));
assertEquals(rand, options.getTcpKeepAliveIntervalSeconds());
assertIllegalArgumentException(() -> options.setTcpKeepAliveIntervalSeconds(0));
assertIllegalArgumentException(() -> options.setTcpKeepAliveIntervalSeconds(-123));

testComplete();
}

Expand Down Expand Up @@ -638,6 +659,9 @@ public void testCopyServerOptions() {
long sslHandshakeTimeout = TestUtils.randomPositiveLong();
boolean useProxyProtocol = TestUtils.randomBoolean();
long proxyProtocolTimeout = TestUtils.randomPositiveLong();
int tcpKeepAliveIdleSeconds = TestUtils.randomPositiveInt();
int tcpKeepAliveCount = TestUtils.randomPositiveInt();
int tcpKeepAliveIntervalSeconds = TestUtils.randomPositiveInt();

options.setSendBufferSize(sendBufferSize);
options.setReceiveBufferSize(receiverBufferSize);
Expand All @@ -662,6 +686,9 @@ public void testCopyServerOptions() {
options.setSslHandshakeTimeout(sslHandshakeTimeout);
options.setUseProxyProtocol(useProxyProtocol);
options.setProxyProtocolTimeout(proxyProtocolTimeout);
options.setTcpKeepAliveIdleSeconds(tcpKeepAliveIdleSeconds);
options.setTcpKeepAliveCount(tcpKeepAliveCount);
options.setTcpKeepAliveIntervalSeconds(tcpKeepAliveIntervalSeconds);

NetServerOptions copy = new NetServerOptions(options);
assertEquals(options.toJson(), copy.toJson());
Expand Down Expand Up @@ -731,6 +758,9 @@ public void testServerOptionsJson() {
long sslHandshakeTimeout = TestUtils.randomPositiveLong();
boolean useProxyProtocol = TestUtils.randomBoolean();
long proxyProtocolTimeout = TestUtils.randomPositiveLong();
int tcpKeepAliveIdleSeconds = TestUtils.randomPositiveInt();
int tcpKeepAliveCount = TestUtils.randomPositiveInt();
int tcpKeepAliveIntervalSeconds = TestUtils.randomPositiveInt();

JsonObject json = new JsonObject();
json.put("sendBufferSize", sendBufferSize)
Expand All @@ -756,7 +786,10 @@ public void testServerOptionsJson() {
.put("sni", sni)
.put("sslHandshakeTimeout", sslHandshakeTimeout)
.put("useProxyProtocol", useProxyProtocol)
.put("proxyProtocolTimeout", proxyProtocolTimeout);
.put("proxyProtocolTimeout", proxyProtocolTimeout)
.put("tcpKeepAliveIdleSeconds", tcpKeepAliveIdleSeconds)
.put("tcpKeepAliveCount", tcpKeepAliveCount)
.put("tcpKeepAliveIntervalSeconds", tcpKeepAliveIntervalSeconds);

NetServerOptions options = new NetServerOptions(json);
assertEquals(sendBufferSize, options.getSendBufferSize());
Expand Down Expand Up @@ -797,6 +830,9 @@ public void testServerOptionsJson() {
assertEquals(sni, options.isSni());
assertEquals(useProxyProtocol, options.isUseProxyProtocol());
assertEquals(proxyProtocolTimeout, options.getProxyProtocolTimeout());
assertEquals(tcpKeepAliveIdleSeconds, options.getTcpKeepAliveIdleSeconds());
assertEquals(tcpKeepAliveCount, options.getTcpKeepAliveCount());
assertEquals(tcpKeepAliveIntervalSeconds, options.getTcpKeepAliveIntervalSeconds());

// Test other keystore/truststore types
json.remove("keyStoreOptions");
Expand Down

0 comments on commit f9ab03b

Please sign in to comment.