Skip to content

Commit

Permalink
support ExtendedSocketOption in HttpRequester, HttpServer, RequestLis…
Browse files Browse the repository at this point in the history
…tener
  • Loading branch information
kkewwei committed Aug 4, 2024
1 parent 11cc527 commit 711332a
Show file tree
Hide file tree
Showing 6 changed files with 125 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,14 @@
import org.apache.hc.core5.pool.PoolEntry;
import org.apache.hc.core5.pool.PoolStats;
import org.apache.hc.core5.util.Args;
import org.apache.hc.core5.util.ReflectionUtils;
import org.apache.hc.core5.util.TimeValue;
import org.apache.hc.core5.util.Timeout;

import static org.apache.hc.core5.reactor.SingleCoreIOReactor.TCP_KEEPCOUNT;
import static org.apache.hc.core5.reactor.SingleCoreIOReactor.TCP_KEEPIDLE;
import static org.apache.hc.core5.reactor.SingleCoreIOReactor.TCP_KEEPINTERVAL;

/**
* HTTP/1.1 client side message exchange initiator.
*
Expand Down Expand Up @@ -249,6 +254,15 @@ private HttpClientConnection createConnection(final Socket sock, final HttpHost
if (socketConfig.getSndBufSize() > 0) {
sock.setSendBufferSize(socketConfig.getSndBufSize());
}
if (this.socketConfig.getTcpKeepIdle() > 0) {
ReflectionUtils.setOption(sock, TCP_KEEPIDLE, this.socketConfig.getTcpKeepIdle());
}
if (this.socketConfig.getTcpKeepInterval() > 0) {
ReflectionUtils.setOption(sock, TCP_KEEPINTERVAL, this.socketConfig.getTcpKeepInterval());
}
if (this.socketConfig.getTcpKeepCount() > 0) {
ReflectionUtils.setOption(sock, TCP_KEEPCOUNT, this.socketConfig.getTcpKeepCount());
}
final int linger = socketConfig.getSoLinger().toMillisecondsIntBound();
if (linger >= 0) {
sock.setSoLinger(true, linger);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,14 @@
import org.apache.hc.core5.io.Closer;
import org.apache.hc.core5.io.ModalCloseable;
import org.apache.hc.core5.util.Args;
import org.apache.hc.core5.util.ReflectionUtils;
import org.apache.hc.core5.util.TimeValue;
import org.apache.hc.core5.util.Timeout;

import static org.apache.hc.core5.reactor.SingleCoreIOReactor.TCP_KEEPCOUNT;
import static org.apache.hc.core5.reactor.SingleCoreIOReactor.TCP_KEEPIDLE;
import static org.apache.hc.core5.reactor.SingleCoreIOReactor.TCP_KEEPINTERVAL;

/**
* HTTP/1.1 server side message exchange handler.
*
Expand Down Expand Up @@ -145,6 +150,15 @@ public void start() throws IOException {
if (this.socketConfig.getRcvBufSize() > 0) {
this.serverSocket.setReceiveBufferSize(this.socketConfig.getRcvBufSize());
}
if (this.socketConfig.getTcpKeepIdle() > 0) {
ReflectionUtils.setOption(this.serverSocket, TCP_KEEPIDLE, this.socketConfig.getTcpKeepIdle());
}
if (this.socketConfig.getTcpKeepInterval() > 0) {
ReflectionUtils.setOption(this.serverSocket, TCP_KEEPINTERVAL, this.socketConfig.getTcpKeepInterval());
}
if (this.socketConfig.getTcpKeepCount() > 0) {
ReflectionUtils.setOption(this.serverSocket, TCP_KEEPCOUNT, this.socketConfig.getTcpKeepCount());
}
if (this.sslSetupHandler != null && this.serverSocket instanceof SSLServerSocket) {
final SSLServerSocket sslServerSocket = (SSLServerSocket) this.serverSocket;
final SSLParameters sslParameters = sslServerSocket.getSSLParameters();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@
import org.apache.hc.core5.http.io.HttpServerConnection;
import org.apache.hc.core5.http.io.SocketConfig;
import org.apache.hc.core5.io.Closer;
import org.apache.hc.core5.util.ReflectionUtils;

import static org.apache.hc.core5.reactor.SingleCoreIOReactor.TCP_KEEPCOUNT;
import static org.apache.hc.core5.reactor.SingleCoreIOReactor.TCP_KEEPIDLE;
import static org.apache.hc.core5.reactor.SingleCoreIOReactor.TCP_KEEPINTERVAL;

class RequestListener implements Runnable {

Expand Down Expand Up @@ -91,6 +96,15 @@ private HttpServerConnection createConnection(final Socket socket) throws IOExce
if (this.socketConfig.getSoLinger().toSeconds() >= 0) {
socket.setSoLinger(true, this.socketConfig.getSoLinger().toSecondsIntBound());
}
if (this.socketConfig.getTcpKeepIdle() > 0) {
ReflectionUtils.setOption(this.serverSocket, TCP_KEEPIDLE, this.socketConfig.getTcpKeepIdle());
}
if (this.socketConfig.getTcpKeepInterval() > 0) {
ReflectionUtils.setOption(this.serverSocket, TCP_KEEPINTERVAL, this.socketConfig.getTcpKeepInterval());
}
if (this.socketConfig.getTcpKeepCount() > 0) {
ReflectionUtils.setOption(this.serverSocket, TCP_KEEPCOUNT, this.socketConfig.getTcpKeepCount());
}
if (!(socket instanceof SSLSocket) && sslSocketFactory != null) {
final SSLSocket sslSocket = (SSLSocket) sslSocketFactory.createSocket(socket, null, -1, false);
sslSocket.setUseClientMode(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,20 +150,23 @@ public int getBacklogSize() {

/**
* @see Builder#setTcpKeepIdle(int)
* @since 5.3
*/
public int getTcpKeepInterval() {
return this.tcpKeepInterval;
}

/**
* @see Builder#setTcpKeepInterval(int)
* @since 5.3
*/
public int getTcpKeepIdle() {
return this.tcpKeepIdle;
}

/**
* @see Builder#setTcpKeepCount(int)
* @since 5.3
*/
public int getTcpKeepCount() {
return this.tcpKeepCount;
Expand Down Expand Up @@ -388,6 +391,8 @@ public Builder setBacklogSize(final int backlogSize) {
* <p>
* Default: {@code -1} (system default)
* </p>
* @return the time (in seconds) the connection needs to remain idle before TCP starts
* @since 5.3
*/
public Builder setTcpKeepIdle(final int tcpKeepIdle) {
this.tcpKeepIdle = tcpKeepIdle;
Expand All @@ -399,6 +404,8 @@ public Builder setTcpKeepIdle(final int tcpKeepIdle) {
* <p>
* Default: {@code -1} (system default)
* </p>
* @return the time (in seconds) between individual keepalive probes.
* @since 5.3
*/
public Builder setTcpKeepInterval(final int tcpKeepInterval) {
this.tcpKeepInterval = tcpKeepInterval;
Expand All @@ -410,6 +417,8 @@ public Builder setTcpKeepInterval(final int tcpKeepInterval) {
* <p>
* Default: {@code -1} (system default)
* </p>
* @return the maximum number of keepalive probes TCP should send before dropping the connection.
* @since 5.3
*/
public Builder setTcpKeepCount(final int tcpKeepCount) {
this.tcpKeepCount = tcpKeepCount;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,13 @@ public static void callSetter(final Object object, final String setterName, fina
}
}

public static <T> T callGetter(final Object object, final String getterName, final Class<T> resultType) {
public static <T> T callGetter(final Object object, final String getterName, final Object arg, final Class argType, final Class<T> resultType) {
try {
final Class<?> clazz = object.getClass();
final Method method = clazz.getMethod("get" + getterName);
final Method method;
method = clazz.getMethod("get" + getterName, argType);
method.setAccessible(true);
return resultType.cast(method.invoke(object));
return resultType.cast(method.invoke(object, arg));
} catch (final Exception ignore) {
return null;
}
Expand Down Expand Up @@ -86,4 +87,23 @@ public static <T> SocketOption<T> getExtendedSocketOptionOrNull(final String fie
return null;
}
}

/**
* object can be ServerSocket or Socket
*
* @since 5.3
*/
public static <T> void setOption(final T object, final String fieldName, final T value) {
try {
final Class<?> serverSocketClass = object.getClass();
final Method setOptionMethod = serverSocketClass.getMethod("setOption", SocketOption.class, Object.class);
final SocketOption<Integer> tcpKeepIdle = getExtendedSocketOptionOrNull(fieldName);
if (tcpKeepIdle == null) {
throw new UnsupportedOperationException(fieldName + " is not supported in the current jdk");
}
setOptionMethod.invoke(object, tcpKeepIdle, value);
} catch (final Exception ignore) {
throw new UnsupportedOperationException(fieldName + " is not supported in the current jdk");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,18 @@
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

import javax.net.ServerSocketFactory;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketOption;

import static org.apache.hc.core5.reactor.SingleCoreIOReactor.TCP_KEEPCOUNT;
import static org.apache.hc.core5.reactor.SingleCoreIOReactor.TCP_KEEPIDLE;
import static org.apache.hc.core5.reactor.SingleCoreIOReactor.TCP_KEEPINTERVAL;
import static org.apache.hc.core5.util.ReflectionUtils.callGetter;
import static org.apache.hc.core5.util.ReflectionUtils.determineJRELevel;
import static org.apache.hc.core5.util.ReflectionUtils.setOption;
import static org.apache.hc.core5.util.ReflectionUtils.getExtendedSocketOptionOrNull;

public class TestReflectionUtils {
Expand All @@ -56,6 +62,51 @@ private void testGetExtendedSocketOption(final String option) {
}
}

@Test
public void testSetOption() throws IOException {
if (determineJRELevel() > 8 && isWindows() == false) {
{
// test Socket
final Socket sock = new Socket();
setOption(sock, TCP_KEEPIDLE, 20);
setOption(sock, TCP_KEEPINTERVAL, 21);
setOption(sock, TCP_KEEPCOUNT, 22);

final SocketOption<Integer> tcpKeepIdle = getExtendedSocketOptionOrNull(TCP_KEEPIDLE);
assert tcpKeepIdle != null;
Assertions.assertEquals(20, callGetter(sock, "Option", tcpKeepIdle, SocketOption.class, Integer.class));

final SocketOption<Integer> tcpKeepInterval = getExtendedSocketOptionOrNull(TCP_KEEPINTERVAL);
assert tcpKeepInterval != null;
Assertions.assertEquals(21, callGetter(sock, "Option", tcpKeepInterval, SocketOption.class, Integer.class));

final SocketOption<Integer> tcpKeepCount = getExtendedSocketOptionOrNull(TCP_KEEPCOUNT);
assert tcpKeepCount != null;
Assertions.assertEquals(22, callGetter(sock, "Option", tcpKeepCount, SocketOption.class, Integer.class));
}

{
// test ServerSocket
final ServerSocket serverSocket = ServerSocketFactory.getDefault().createServerSocket();
setOption(serverSocket, TCP_KEEPIDLE, 20);
setOption(serverSocket, TCP_KEEPINTERVAL, 21);
setOption(serverSocket, TCP_KEEPCOUNT, 22);

final SocketOption<Integer> tcpKeepIdle = getExtendedSocketOptionOrNull(TCP_KEEPIDLE);
assert tcpKeepIdle != null;
Assertions.assertEquals(20, callGetter(serverSocket, "Option", tcpKeepIdle, SocketOption.class, Integer.class));

final SocketOption<Integer> tcpKeepInterval = getExtendedSocketOptionOrNull(TCP_KEEPINTERVAL);
assert tcpKeepInterval != null;
Assertions.assertEquals(21, callGetter(serverSocket, "Option", tcpKeepInterval, SocketOption.class, Integer.class));

final SocketOption<Integer> tcpKeepCount = getExtendedSocketOptionOrNull(TCP_KEEPCOUNT);
assert tcpKeepCount != null;
Assertions.assertEquals(22, callGetter(serverSocket, "Option", tcpKeepCount, SocketOption.class, Integer.class));
}
}
}

public static boolean isWindows() {
return System.getProperty("os.name").contains("Windows");
}
Expand Down

0 comments on commit 711332a

Please sign in to comment.