diff --git a/rskj-core/src/main/java/co/rsk/RskContext.java b/rskj-core/src/main/java/co/rsk/RskContext.java index e55316fb6f5..4c7337612ea 100644 --- a/rskj-core/src/main/java/co/rsk/RskContext.java +++ b/rskj-core/src/main/java/co/rsk/RskContext.java @@ -1600,7 +1600,8 @@ private Web3WebSocketServer getWeb3WebSocketServer() { rskSystemProperties.rpcWebSocketBindAddress(), rskSystemProperties.rpcWebSocketPort(), jsonRpcHandler, - getJsonRpcWeb3ServerHandler() + getJsonRpcWeb3ServerHandler(), + rskSystemProperties.rpcWebSocketServerWriteTimeout() ); } diff --git a/rskj-core/src/main/java/co/rsk/rpc/netty/Web3WebSocketServer.java b/rskj-core/src/main/java/co/rsk/rpc/netty/Web3WebSocketServer.java index cf5e64b9945..d2bd916d48f 100644 --- a/rskj-core/src/main/java/co/rsk/rpc/netty/Web3WebSocketServer.java +++ b/rskj-core/src/main/java/co/rsk/rpc/netty/Web3WebSocketServer.java @@ -38,7 +38,6 @@ public class Web3WebSocketServer implements InternalService { private static final Logger logger = LoggerFactory.getLogger(Web3WebSocketServer.class); - public static final int WRITE_TIMEOUT_SECONDS = 30; private final InetAddress host; private final int port; @@ -47,18 +46,21 @@ public class Web3WebSocketServer implements InternalService { private final EventLoopGroup bossGroup; private final EventLoopGroup workerGroup; private @Nullable ChannelFuture webSocketChannel; + private final int serverWriteTimeout; public Web3WebSocketServer( InetAddress host, int port, RskWebSocketJsonRpcHandler webSocketJsonRpcHandler, - JsonRpcWeb3ServerHandler web3ServerHandler) { + JsonRpcWeb3ServerHandler web3ServerHandler, + int serverWriteTimeout) { this.host = host; this.port = port; this.webSocketJsonRpcHandler = webSocketJsonRpcHandler; this.web3ServerHandler = web3ServerHandler; this.bossGroup = new NioEventLoopGroup(); this.workerGroup = new NioEventLoopGroup(); + this.serverWriteTimeout = serverWriteTimeout; } @Override @@ -73,7 +75,7 @@ protected void initChannel(SocketChannel ch) throws Exception { ChannelPipeline p = ch.pipeline(); p.addLast(new HttpServerCodec()); p.addLast(new HttpObjectAggregator(1024 * 1024 * 5)); - p.addLast(new WriteTimeoutHandler(WRITE_TIMEOUT_SECONDS, TimeUnit.SECONDS)); + p.addLast(new WriteTimeoutHandler(serverWriteTimeout, TimeUnit.SECONDS)); p.addLast(new RskWebSocketServerProtocolHandler("/websocket")); p.addLast(webSocketJsonRpcHandler); p.addLast(web3ServerHandler); diff --git a/rskj-core/src/main/java/org/ethereum/config/SystemProperties.java b/rskj-core/src/main/java/org/ethereum/config/SystemProperties.java index 0c0b19eeda3..509a46054ee 100644 --- a/rskj-core/src/main/java/org/ethereum/config/SystemProperties.java +++ b/rskj-core/src/main/java/org/ethereum/config/SystemProperties.java @@ -82,6 +82,7 @@ public abstract class SystemProperties { private static final String PROPERTY_RPC_WEBSOCKET_ENABLED = "rpc.providers.web.ws.enabled"; private static final String PROPERTY_RPC_WEBSOCKET_ADDRESS = "rpc.providers.web.ws.bind_address"; private static final String PROPERTY_RPC_WEBSOCKET_PORT = "rpc.providers.web.ws.port"; + private static final String PROPERTY_RPC_WEBSOCKET_SERVER_WRITE_TIMEOUT = "rpc.providers.web.ws.server_write_timeout"; public static final String PROPERTY_PUBLIC_IP = "public.ip"; public static final String PROPERTY_BIND_ADDRESS = "bind_address"; @@ -612,6 +613,10 @@ public int rpcWebSocketPort() { return configFromFiles.getInt(PROPERTY_RPC_WEBSOCKET_PORT); } + public int rpcWebSocketServerWriteTimeout() { + return configFromFiles.getInt(PROPERTY_RPC_WEBSOCKET_SERVER_WRITE_TIMEOUT); + } + public InetAddress rpcHttpBindAddress() { return getWebBindAddress(PROPERTY_RPC_HTTP_ADDRESS); } diff --git a/rskj-core/src/main/resources/expected.conf b/rskj-core/src/main/resources/expected.conf index c639bb6473c..c3d1c806623 100644 --- a/rskj-core/src/main/resources/expected.conf +++ b/rskj-core/src/main/resources/expected.conf @@ -219,6 +219,7 @@ rpc = { enabled = bind_address = port = + server_write_timeout = } } } diff --git a/rskj-core/src/main/resources/reference.conf b/rskj-core/src/main/resources/reference.conf index f63e4f1ab4e..d35f883228d 100644 --- a/rskj-core/src/main/resources/reference.conf +++ b/rskj-core/src/main/resources/reference.conf @@ -281,6 +281,8 @@ rpc { enabled = false bind_address = localhost port = 4445 + # Shuts down the server when it's not able to write a response after a certain period (expressed in seconds) + server_write_timeout = 30 } } } diff --git a/rskj-core/src/test/java/co/rsk/rpc/netty/Web3WebSocketServerTest.java b/rskj-core/src/test/java/co/rsk/rpc/netty/Web3WebSocketServerTest.java index 0bb87149b03..9a184bd2a21 100644 --- a/rskj-core/src/test/java/co/rsk/rpc/netty/Web3WebSocketServerTest.java +++ b/rskj-core/src/test/java/co/rsk/rpc/netty/Web3WebSocketServerTest.java @@ -17,6 +17,7 @@ */ package co.rsk.rpc.netty; +import co.rsk.config.TestSystemProperties; import co.rsk.rpc.JacksonBasedRpcSerializer; import co.rsk.rpc.ModuleDescription; import com.fasterxml.jackson.core.JsonProcessingException; @@ -30,6 +31,7 @@ import okio.Buffer; import org.ethereum.rpc.Web3; import org.junit.After; +import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -46,14 +48,14 @@ import java.util.concurrent.atomic.AtomicReference; import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.fail; +import static org.junit.Assert.*; import static org.mockito.Mockito.*; public class Web3WebSocketServerTest { private static JsonNodeFactory JSON_NODE_FACTORY = JsonNodeFactory.instance; private static ObjectMapper OBJECT_MAPPER = new ObjectMapper(); + private static final int DEFAULT_WRITE_TIMEOUT = 30; private ExecutorService wsExecutor; @@ -68,13 +70,24 @@ public void smokeTest() throws Exception { String mockResult = "output"; when(web3Mock.web3_sha3(anyString())).thenReturn(mockResult); - int randomPort = 9998;//new ServerSocket(0).getLocalPort(); + int randomPort = 9998; + + TestSystemProperties testSystemProperties = new TestSystemProperties(); List filteredModules = Collections.singletonList(new ModuleDescription("web3", "1.0", true, Collections.emptyList(), Collections.emptyList())); RskWebSocketJsonRpcHandler handler = new RskWebSocketJsonRpcHandler(null, new JacksonBasedRpcSerializer()); JsonRpcWeb3ServerHandler serverHandler = new JsonRpcWeb3ServerHandler(web3Mock, filteredModules); + int serverWriteTimout = testSystemProperties.rpcWebSocketServerWriteTimeout(); + + assertEquals(DEFAULT_WRITE_TIMEOUT, serverWriteTimout); - Web3WebSocketServer websocketServer = new Web3WebSocketServer(InetAddress.getLoopbackAddress(), randomPort, handler, serverHandler); + Web3WebSocketServer websocketServer = new Web3WebSocketServer( + InetAddress.getLoopbackAddress(), + randomPort, + handler, + serverHandler, + serverWriteTimout + ); websocketServer.start(); OkHttpClient wsClient = new OkHttpClient();