From 57121604d36dd56562e619ea8dca3099be1c1bdd Mon Sep 17 00:00:00 2001 From: Gary Russell Date: Fri, 14 Oct 2011 22:39:33 -0400 Subject: [PATCH] INT-1872 Allow Indefinite Socket Timeout Previously, for single-use server sockets, and for client sockets that have a collaborating inbound adapter, the socket timeout was set to 10 seconds, with no way to set to infinity. The work around was to set it to Integer.MAX_VALUE. The intent was to avoid DoS attacks and mis-behaved clients, but some users have expressed a desire to be able to set an infinite timeout in both scenarios. A future release may remove the 10 second default from the client socket that has a collaborating inbound adapter, and default to infinity. For this reason, that case now emits a warning. The default 10 second timeout on single-use server sockets will likely remain. INT-1872 Remove WARN Log We decided to eliminate the log message regarding a possible future change to the default timeout for client sockets used for request/reply. --- docs/src/reference/docbook/ip.xml | 11 ++++------- .../connection/AbstractClientConnectionFactory.java | 7 ++++++- .../ip/tcp/connection/AbstractConnectionFactory.java | 2 +- .../connection/AbstractServerConnectionFactory.java | 7 ++++--- .../tcp/connection/TcpNioClientConnectionFactory.java | 3 ++- .../tcp/connection/TcpNioServerConnectionFactory.java | 3 ++- 6 files changed, 19 insertions(+), 14 deletions(-) diff --git a/docs/src/reference/docbook/ip.xml b/docs/src/reference/docbook/ip.xml index 6891402580..848ff17fd0 100644 --- a/docs/src/reference/docbook/ip.xml +++ b/docs/src/reference/docbook/ip.xml @@ -725,12 +725,7 @@ factory. - It is not currently possible to set this to an infinite value - (0); the maximum value can be set using a SpEL expression as - follows. - - so-timeout="#{T(java.lang.Integer).MAX_VALUE}" - + Setting the attribute to 0 will enable an infinite timeout. @@ -867,7 +862,9 @@ Y Defaults to 0 (infinity), except when the connection - factory is used by collaborating adapters, where it + factory is used by collaborating adapters, and for + server connection factories with single-use="true". + In those cases, it defaults to the default reply timeout (10 seconds). See the section about collaborating adapters above and java.net.Socket. setSoTimeout(). diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/AbstractClientConnectionFactory.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/AbstractClientConnectionFactory.java index c1d3d14ac1..7b4252fe8b 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/AbstractClientConnectionFactory.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/AbstractClientConnectionFactory.java @@ -74,8 +74,13 @@ public abstract class AbstractClientConnectionFactory extends AbstractConnection connection.registerListener(listener); } if (listener != null || this.isSingleUse()) { - if (this.getSoTimeout() <= 0) { + if (this.getSoTimeout() < 0) { try { + /* Default so-timeout, when we have a collaborating inbound adapter, + * may go to infinity in a future release; currently it's 10 seconds. + * While it makes sense in a request/reply scenario, it doesn't + * really for completely asynchronous communication between peers. + */ socket.setSoTimeout(DEFAULT_REPLY_TIMEOUT); } catch (SocketException e) { logger.error("Error setting default reply timeout", e); diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/AbstractConnectionFactory.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/AbstractConnectionFactory.java index 181e6477ac..27e1280e98 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/AbstractConnectionFactory.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/AbstractConnectionFactory.java @@ -67,7 +67,7 @@ public abstract class AbstractConnectionFactory extends IntegrationObjectSupport private volatile TcpSender sender; - private volatile int soTimeout; + private volatile int soTimeout = -1; private volatile int soSendBufferSize; diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/AbstractServerConnectionFactory.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/AbstractServerConnectionFactory.java index 8bb5e3726d..d981334c33 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/AbstractServerConnectionFactory.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/AbstractServerConnectionFactory.java @@ -84,11 +84,12 @@ public abstract class AbstractServerConnectionFactory extends AbstractConnection connection.setSerializer(this.getSerializer()); connection.setSingleUse(this.isSingleUse()); /* - * If we have a collaborating outbound channel adapter and we are configured + * If we are configured * for single use; need to enforce a timeout on the socket so we will close - * it some period after the response was sent (timeout on the next read). + * if the client connects, but sends nothing. (Protect against DoS). + * Behavior can be overridden by explicitly setting the timeout to zero. */ - if (this.isSingleUse() && this.getSoTimeout() <= 0 && listener != null) { + if (this.isSingleUse() && this.getSoTimeout() < 0) { try { socket.setSoTimeout(DEFAULT_REPLY_TIMEOUT); } catch (SocketException e) { diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpNioClientConnectionFactory.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpNioClientConnectionFactory.java index 4bb7e0fa6a..1763387e7b 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpNioClientConnectionFactory.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpNioClientConnectionFactory.java @@ -122,7 +122,8 @@ public class TcpNioClientConnectionFactory extends this.selector = Selector.open(); while (this.isActive()) { SocketChannel newChannel; - int selectionCount = selector.select(this.getSoTimeout()); + int soTimeout = this.getSoTimeout(); + int selectionCount = selector.select(soTimeout < 0 ? 0 : soTimeout); while ((newChannel = newChannels.poll()) != null) { newChannel.register(this.selector, SelectionKey.OP_READ, connections.get(newChannel)); } diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpNioServerConnectionFactory.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpNioServerConnectionFactory.java index 24c549bc60..806a07df5c 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpNioServerConnectionFactory.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpNioServerConnectionFactory.java @@ -113,7 +113,8 @@ public class TcpNioServerConnectionFactory extends AbstractServerConnectionFacto private void doSelect(ServerSocketChannel server, final Selector selector) throws IOException, ClosedChannelException, SocketException { while (this.isActive()) { - int selectionCount = selector.select(this.getSoTimeout()); + int soTimeout = this.getSoTimeout(); + int selectionCount = selector.select(soTimeout < 0 ? 0 : soTimeout); this.processNioSelections(selectionCount, selector, server, this.connections); } }