From c504b1383cf0702c04e36aa7348ef8a5678a1207 Mon Sep 17 00:00:00 2001 From: Gabriel Fukushima Date: Thu, 27 Oct 2022 15:43:23 +1100 Subject: [PATCH 01/12] Add method to check port availability Signed-off-by: Gabriel Fukushima --- .../hyperledger/besu/util/NetworkUtility.java | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/util/src/main/java/org/hyperledger/besu/util/NetworkUtility.java b/util/src/main/java/org/hyperledger/besu/util/NetworkUtility.java index 22d57a71f5f..26ca5c8073f 100644 --- a/util/src/main/java/org/hyperledger/besu/util/NetworkUtility.java +++ b/util/src/main/java/org/hyperledger/besu/util/NetworkUtility.java @@ -14,20 +14,26 @@ */ package org.hyperledger.besu.util; +import java.io.IOException; import java.net.Inet6Address; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.NetworkInterface; +import java.net.ServerSocket; import java.net.SocketException; import java.net.UnknownHostException; import java.util.function.Supplier; import com.google.common.base.Suppliers; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class NetworkUtility { public static final String INADDR_ANY = "0.0.0.0"; public static final String INADDR6_ANY = "0:0:0:0:0:0:0:0"; + private static final Logger LOG = LoggerFactory.getLogger(NetworkUtility.class); + private NetworkUtility() {} private static final Supplier ipv6Available = @@ -98,4 +104,23 @@ public static void checkPort(final int port, final String portTypeName) { "%s port requires a value between 1 and 65535. Got %d.", portTypeName, port)); } } + + public static boolean isPortAvailableForTcp(final int port) { + try (final ServerSocket serverSocket = new ServerSocket()) { + serverSocket.setReuseAddress(true); + serverSocket.bind(new InetSocketAddress(port)); + return true; + } catch (IOException ex) { + LOG.trace(String.format("Failed to open port %d for TCP", port), ex); + } + return false; + } + + public static void checkPortsAvailable(final int tcpPort) { + if (!isPortAvailableForTcp(tcpPort)) { + throw new InvalidConfigurationException( + String.format( + "Port %d is already in use. Check for other processes using this port.", tcpPort)); + } + } } From 3ec630ee420c3c12371c92d79d66310385a1ca09 Mon Sep 17 00:00:00 2001 From: Gabriel Fukushima Date: Thu, 27 Oct 2022 15:43:41 +1100 Subject: [PATCH 02/12] Check port availability Signed-off-by: Gabriel Fukushima --- .../besu/ethereum/api/jsonrpc/JsonRpcHttpService.java | 2 ++ .../hyperledger/besu/ethereum/api/jsonrpc/JsonRpcService.java | 1 + .../besu/ethereum/api/jsonrpc/websocket/WebSocketService.java | 3 ++- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpService.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpService.java index 874919bac52..c8233dd2152 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpService.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpService.java @@ -219,6 +219,8 @@ public CompletableFuture start() { final CompletableFuture resultFuture = new CompletableFuture<>(); try { + NetworkUtility.checkPortsAvailable(config.getPort()); + // Create the HTTP server and a router object. httpServer = vertx.createHttpServer(getHttpServerOptions()); diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcService.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcService.java index 8c92093e607..3afa26da5cf 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcService.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcService.java @@ -219,6 +219,7 @@ public CompletableFuture start() { final CompletableFuture resultFuture = new CompletableFuture<>(); try { + NetworkUtility.checkPortsAvailable(config.getPort()); // Create the HTTP server and a router object. httpServer = vertx.createHttpServer(getHttpServerOptions()); httpServer.webSocketHandler(webSocketHandler()); diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketService.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketService.java index f6131339cc3..b918ad88302 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketService.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketService.java @@ -23,6 +23,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.SubscriptionManager; import org.hyperledger.besu.metrics.BesuMetricCategory; import org.hyperledger.besu.plugin.services.MetricsSystem; +import org.hyperledger.besu.util.NetworkUtility; import java.net.InetSocketAddress; import java.util.Optional; @@ -104,7 +105,7 @@ public CompletableFuture start() { "Starting Websocket service on {}:{}", configuration.getHost(), configuration.getPort()); final CompletableFuture resultFuture = new CompletableFuture<>(); - + NetworkUtility.checkPortsAvailable(configuration.getPort()); httpServer = vertx .createHttpServer( From de1afc7c3efca3ed5c9914b17dc5315c5f42efa7 Mon Sep 17 00:00:00 2001 From: Gabriel Fukushima Date: Thu, 27 Oct 2022 15:44:01 +1100 Subject: [PATCH 03/12] Add tests to check port availability Signed-off-by: Gabriel Fukushima --- .../api/jsonrpc/JsonRpcHttpServiceTest.java | 16 ++++++++++++++++ .../jsonrpc/websocket/WebSocketServiceTest.java | 15 +++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTest.java index 58743ba11a7..3ff86c598c7 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTest.java @@ -15,6 +15,7 @@ package org.hyperledger.besu.ethereum.api.jsonrpc; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; @@ -2083,4 +2084,19 @@ public void handleResponseWithOptionalExistingValue() throws Exception { rpcMethods.remove(method.getName()); } } + + @Test + public void failWhenPortIsAlreadyInUse() throws Exception { + final JsonRpcConfiguration config = createJsonRpcConfig(); + config.setHost("0.0.0.0"); + config.setPort(8545); + final JsonRpcHttpService firstServiceToAllocatePort = createJsonRpcHttpService(config); + final JsonRpcHttpService secondServiceToAllocatePort = createJsonRpcHttpService(config); + firstServiceToAllocatePort.start().join(); + + assertThatIllegalArgumentException() + .isThrownBy(() -> secondServiceToAllocatePort.start()) + .withMessageContaining( + "Port 8545 is already in use. Check for other processes using this port."); + } } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketServiceTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketServiceTest.java index 6f26c513266..5a147aae015 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketServiceTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketServiceTest.java @@ -15,6 +15,7 @@ package org.hyperledger.besu.ethereum.api.jsonrpc.websocket; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.spy; @@ -385,4 +386,18 @@ public void handleResponseWithOptionalExistingValue(final TestContext context) { async.awaitSuccess(VERTX_AWAIT_TIMEOUT_MILLIS); async.handler((result) -> websocketMethods.remove(method.getName())); } + + @Test + public void failWhenPortIsAlreadyInUse() { + websocketConfiguration = WebSocketConfiguration.createDefault(); + // firstWebsocketService is created using @Before + final WebSocketService secondWebSocketService = + new WebSocketService( + vertx, websocketConfiguration, webSocketMessageHandlerSpy, new NoOpMetricsSystem()); + + assertThatIllegalArgumentException() + .isThrownBy(() -> secondWebSocketService.start()) + .withMessageContaining( + "Port 8546 is already in use. Check for other processes using this port."); + } } From feeaf2a7141aed895c5b561d3cd7861ca4f9d684 Mon Sep 17 00:00:00 2001 From: Gabriel Fukushima Date: Thu, 27 Oct 2022 18:56:44 +1100 Subject: [PATCH 04/12] Fix broken test Signed-off-by: Gabriel Fukushima --- .../api/jsonrpc/websocket/WebSocketServiceTest.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketServiceTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketServiceTest.java index 5a147aae015..a06f6f0f9b2 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketServiceTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketServiceTest.java @@ -388,9 +388,16 @@ public void handleResponseWithOptionalExistingValue(final TestContext context) { } @Test - public void failWhenPortIsAlreadyInUse() { + public void failWhenPortIsAlreadyInUse() { websocketConfiguration = WebSocketConfiguration.createDefault(); - // firstWebsocketService is created using @Before + websocketConfiguration.setHost("0.0.0.0"); + websocketConfiguration.setPort(8546); + final WebSocketService firstWebSocketService = + new WebSocketService( + vertx, websocketConfiguration, webSocketMessageHandlerSpy, new NoOpMetricsSystem()); + + firstWebSocketService.start().join(); + final WebSocketService secondWebSocketService = new WebSocketService( vertx, websocketConfiguration, webSocketMessageHandlerSpy, new NoOpMetricsSystem()); From b91487f561157a5f18ce423c8bf98247ae445e82 Mon Sep 17 00:00:00 2001 From: Gabriel Fukushima Date: Thu, 27 Oct 2022 18:57:42 +1100 Subject: [PATCH 05/12] Spotless Signed-off-by: Gabriel Fukushima --- .../api/jsonrpc/websocket/WebSocketServiceTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketServiceTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketServiceTest.java index a06f6f0f9b2..24d93b24a0b 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketServiceTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketServiceTest.java @@ -388,10 +388,10 @@ public void handleResponseWithOptionalExistingValue(final TestContext context) { } @Test - public void failWhenPortIsAlreadyInUse() { + public void failWhenPortIsAlreadyInUse() { websocketConfiguration = WebSocketConfiguration.createDefault(); - websocketConfiguration.setHost("0.0.0.0"); - websocketConfiguration.setPort(8546); + websocketConfiguration.setHost("0.0.0.0"); + websocketConfiguration.setPort(8546); final WebSocketService firstWebSocketService = new WebSocketService( vertx, websocketConfiguration, webSocketMessageHandlerSpy, new NoOpMetricsSystem()); From b7497336663918b998a21a909c7e38b031a02b5b Mon Sep 17 00:00:00 2001 From: Gabriel Fukushima Date: Fri, 28 Oct 2022 13:27:40 +1100 Subject: [PATCH 06/12] Rename method Signed-off-by: Gabriel Fukushima --- .../besu/ethereum/api/jsonrpc/JsonRpcHttpService.java | 2 +- .../hyperledger/besu/ethereum/api/jsonrpc/JsonRpcService.java | 2 +- .../besu/ethereum/api/jsonrpc/websocket/WebSocketService.java | 2 +- .../src/main/java/org/hyperledger/besu/util/NetworkUtility.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpService.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpService.java index c8233dd2152..e9d53ba0c0c 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpService.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpService.java @@ -219,7 +219,7 @@ public CompletableFuture start() { final CompletableFuture resultFuture = new CompletableFuture<>(); try { - NetworkUtility.checkPortsAvailable(config.getPort()); + NetworkUtility.checkIfPortIsAvailable(config.getPort()); // Create the HTTP server and a router object. httpServer = vertx.createHttpServer(getHttpServerOptions()); diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcService.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcService.java index 3afa26da5cf..d4293191712 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcService.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcService.java @@ -219,7 +219,7 @@ public CompletableFuture start() { final CompletableFuture resultFuture = new CompletableFuture<>(); try { - NetworkUtility.checkPortsAvailable(config.getPort()); + NetworkUtility.checkIfPortIsAvailable(config.getPort()); // Create the HTTP server and a router object. httpServer = vertx.createHttpServer(getHttpServerOptions()); httpServer.webSocketHandler(webSocketHandler()); diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketService.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketService.java index b918ad88302..150c1630892 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketService.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketService.java @@ -105,7 +105,7 @@ public CompletableFuture start() { "Starting Websocket service on {}:{}", configuration.getHost(), configuration.getPort()); final CompletableFuture resultFuture = new CompletableFuture<>(); - NetworkUtility.checkPortsAvailable(configuration.getPort()); + NetworkUtility.checkIfPortIsAvailable(configuration.getPort()); httpServer = vertx .createHttpServer( diff --git a/util/src/main/java/org/hyperledger/besu/util/NetworkUtility.java b/util/src/main/java/org/hyperledger/besu/util/NetworkUtility.java index 26ca5c8073f..6d1ac6653df 100644 --- a/util/src/main/java/org/hyperledger/besu/util/NetworkUtility.java +++ b/util/src/main/java/org/hyperledger/besu/util/NetworkUtility.java @@ -116,7 +116,7 @@ public static boolean isPortAvailableForTcp(final int port) { return false; } - public static void checkPortsAvailable(final int tcpPort) { + public static void checkIfPortIsAvailable(final int tcpPort) { if (!isPortAvailableForTcp(tcpPort)) { throw new InvalidConfigurationException( String.format( From 8752282635bd9043ccdb5226f480ae7c9cb5f0c5 Mon Sep 17 00:00:00 2001 From: Gabriel Fukushima Date: Fri, 28 Oct 2022 17:24:49 +1100 Subject: [PATCH 07/12] Rollback changes Signed-off-by: Gabriel Fukushima --- .../api/jsonrpc/JsonRpcHttpService.java | 1 - .../ethereum/api/jsonrpc/JsonRpcService.java | 1 - .../jsonrpc/websocket/WebSocketService.java | 2 -- .../api/jsonrpc/JsonRpcHttpServiceTest.java | 16 -------------- .../websocket/WebSocketServiceTest.java | 22 ------------------- 5 files changed, 42 deletions(-) diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpService.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpService.java index e9d53ba0c0c..b19963980af 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpService.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpService.java @@ -219,7 +219,6 @@ public CompletableFuture start() { final CompletableFuture resultFuture = new CompletableFuture<>(); try { - NetworkUtility.checkIfPortIsAvailable(config.getPort()); // Create the HTTP server and a router object. httpServer = vertx.createHttpServer(getHttpServerOptions()); diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcService.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcService.java index d4293191712..8c92093e607 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcService.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcService.java @@ -219,7 +219,6 @@ public CompletableFuture start() { final CompletableFuture resultFuture = new CompletableFuture<>(); try { - NetworkUtility.checkIfPortIsAvailable(config.getPort()); // Create the HTTP server and a router object. httpServer = vertx.createHttpServer(getHttpServerOptions()); httpServer.webSocketHandler(webSocketHandler()); diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketService.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketService.java index 150c1630892..4b4e0db92b3 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketService.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketService.java @@ -23,7 +23,6 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.SubscriptionManager; import org.hyperledger.besu.metrics.BesuMetricCategory; import org.hyperledger.besu.plugin.services.MetricsSystem; -import org.hyperledger.besu.util.NetworkUtility; import java.net.InetSocketAddress; import java.util.Optional; @@ -105,7 +104,6 @@ public CompletableFuture start() { "Starting Websocket service on {}:{}", configuration.getHost(), configuration.getPort()); final CompletableFuture resultFuture = new CompletableFuture<>(); - NetworkUtility.checkIfPortIsAvailable(configuration.getPort()); httpServer = vertx .createHttpServer( diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTest.java index 3ff86c598c7..58743ba11a7 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTest.java @@ -15,7 +15,6 @@ package org.hyperledger.besu.ethereum.api.jsonrpc; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; @@ -2084,19 +2083,4 @@ public void handleResponseWithOptionalExistingValue() throws Exception { rpcMethods.remove(method.getName()); } } - - @Test - public void failWhenPortIsAlreadyInUse() throws Exception { - final JsonRpcConfiguration config = createJsonRpcConfig(); - config.setHost("0.0.0.0"); - config.setPort(8545); - final JsonRpcHttpService firstServiceToAllocatePort = createJsonRpcHttpService(config); - final JsonRpcHttpService secondServiceToAllocatePort = createJsonRpcHttpService(config); - firstServiceToAllocatePort.start().join(); - - assertThatIllegalArgumentException() - .isThrownBy(() -> secondServiceToAllocatePort.start()) - .withMessageContaining( - "Port 8545 is already in use. Check for other processes using this port."); - } } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketServiceTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketServiceTest.java index 24d93b24a0b..6f26c513266 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketServiceTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketServiceTest.java @@ -15,7 +15,6 @@ package org.hyperledger.besu.ethereum.api.jsonrpc.websocket; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.spy; @@ -386,25 +385,4 @@ public void handleResponseWithOptionalExistingValue(final TestContext context) { async.awaitSuccess(VERTX_AWAIT_TIMEOUT_MILLIS); async.handler((result) -> websocketMethods.remove(method.getName())); } - - @Test - public void failWhenPortIsAlreadyInUse() { - websocketConfiguration = WebSocketConfiguration.createDefault(); - websocketConfiguration.setHost("0.0.0.0"); - websocketConfiguration.setPort(8546); - final WebSocketService firstWebSocketService = - new WebSocketService( - vertx, websocketConfiguration, webSocketMessageHandlerSpy, new NoOpMetricsSystem()); - - firstWebSocketService.start().join(); - - final WebSocketService secondWebSocketService = - new WebSocketService( - vertx, websocketConfiguration, webSocketMessageHandlerSpy, new NoOpMetricsSystem()); - - assertThatIllegalArgumentException() - .isThrownBy(() -> secondWebSocketService.start()) - .withMessageContaining( - "Port 8546 is already in use. Check for other processes using this port."); - } } From 817286eef9de7b0d99f6078defb434e0e7350823 Mon Sep 17 00:00:00 2001 From: Gabriel Fukushima Date: Fri, 28 Oct 2022 17:32:42 +1100 Subject: [PATCH 08/12] Add general port verification Signed-off-by: Gabriel Fukushima --- .../org/hyperledger/besu/cli/BesuCommand.java | 22 ++++++++++++++++++- .../hyperledger/besu/cli/BesuCommandTest.java | 14 ++++++++++++ .../hyperledger/besu/util/NetworkUtility.java | 19 +++++++++++----- 3 files changed, 49 insertions(+), 6 deletions(-) diff --git a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java index f9e3c1e9701..50ba0968ce3 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java @@ -180,6 +180,7 @@ import org.hyperledger.besu.services.SecurityModuleServiceImpl; import org.hyperledger.besu.services.StorageServiceImpl; import org.hyperledger.besu.services.kvstore.InMemoryStoragePlugin; +import org.hyperledger.besu.util.InvalidConfigurationException; import org.hyperledger.besu.util.Log4j2ConfiguratorUtil; import org.hyperledger.besu.util.NetworkUtility; import org.hyperledger.besu.util.PermissioningConfigurationValidator; @@ -1972,7 +1973,7 @@ private void issueOptionWarnings() { private void configure() throws Exception { checkPortClash(); - + checkIfRequiredPortsAreAvailable(); syncMode = getDefaultSyncModeIfNotSet(syncMode); ethNetworkConfig = updateNetworkConfig(network); @@ -3126,6 +3127,25 @@ private void checkPortClash() { }); } + private void checkIfRequiredPortsAreAvailable() { + List unavailablePorts = new ArrayList<>(); + getEffectivePorts().stream() + .filter(Objects::nonNull) + .filter(port -> port > 0) + .forEach( + port -> { + if (!NetworkUtility.isPortAvailable(port)) { + unavailablePorts.add(port); + } + }); + if (!unavailablePorts.isEmpty()) { + throw new InvalidConfigurationException( + "Port(s) '" + + unavailablePorts.toString() + + "' already in use. Check for other processes using the port(s)."); + } + } + /** * * Gets the list of effective ports (ports that are enabled). * diff --git a/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java b/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java index dd6a5136335..d6c67bfe486 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java @@ -100,6 +100,7 @@ import java.io.File; import java.io.IOException; import java.math.BigInteger; +import java.net.ServerSocket; import java.net.URI; import java.net.URL; import java.nio.file.Files; @@ -5371,4 +5372,17 @@ public void posBlockCreationMaxTimeOutOfAllowedRange() { assertThat(commandErrorOutput.toString(UTF_8)) .contains("--Xpos-block-creation-max-time must be positive and ≤ 12000"); } + + @Test + public void portInUseReportsError() throws IOException { + final ServerSocket serverSocket = new ServerSocket(8545); + + parseCommand("--rpc-http-enabled"); + + assertThat(commandOutput.toString(UTF_8)).isEmpty(); + assertThat(commandErrorOutput.toString(UTF_8)) + .contains("Port(s) '[8545]' already in use. Check for other processes using this port."); + + serverSocket.close(); + } } diff --git a/util/src/main/java/org/hyperledger/besu/util/NetworkUtility.java b/util/src/main/java/org/hyperledger/besu/util/NetworkUtility.java index 6d1ac6653df..635db55913f 100644 --- a/util/src/main/java/org/hyperledger/besu/util/NetworkUtility.java +++ b/util/src/main/java/org/hyperledger/besu/util/NetworkUtility.java @@ -15,6 +15,7 @@ package org.hyperledger.besu.util; import java.io.IOException; +import java.net.DatagramSocket; import java.net.Inet6Address; import java.net.InetAddress; import java.net.InetSocketAddress; @@ -116,11 +117,19 @@ public static boolean isPortAvailableForTcp(final int port) { return false; } - public static void checkIfPortIsAvailable(final int tcpPort) { - if (!isPortAvailableForTcp(tcpPort)) { - throw new InvalidConfigurationException( - String.format( - "Port %d is already in use. Check for other processes using this port.", tcpPort)); + public static boolean isPortAvailableForUdp(final int port) { + try (final DatagramSocket datagramSocket = new DatagramSocket(null)) { + datagramSocket.setReuseAddress(true); + datagramSocket.bind(new InetSocketAddress(port)); + return true; + } catch (IOException ex) { + LOG.trace(String.format("failed to open port %d for UDP", port), ex); } + return false; + } + + public static boolean isPortAvailable(final int port) { + if (isPortAvailableForTcp(port) && isPortAvailableForUdp(port)) return true; + return false; } } From d1cb28cc1d8ec23ffcf458d30ac50153f9606b92 Mon Sep 17 00:00:00 2001 From: Gabriel Fukushima Date: Fri, 28 Oct 2022 17:54:01 +1100 Subject: [PATCH 09/12] Fix test Signed-off-by: Gabriel Fukushima --- .../src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java b/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java index d6c67bfe486..6ce11e83ca1 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java @@ -5381,7 +5381,7 @@ public void portInUseReportsError() throws IOException { assertThat(commandOutput.toString(UTF_8)).isEmpty(); assertThat(commandErrorOutput.toString(UTF_8)) - .contains("Port(s) '[8545]' already in use. Check for other processes using this port."); + .contains("Port(s) '[8545]' already in use. Check for other processes using the port(s)."); serverSocket.close(); } From 7ba61a743c8c7ac679cfa6e6506f7d8fa2bdcd72 Mon Sep 17 00:00:00 2001 From: Gabriel Fukushima Date: Tue, 1 Nov 2022 00:35:02 +1100 Subject: [PATCH 10/12] Add unit test Signed-off-by: Gabriel Fukushima --- .../org/hyperledger/besu/util/NetworkUtilityTest.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/util/src/test/java/org/hyperledger/besu/util/NetworkUtilityTest.java b/util/src/test/java/org/hyperledger/besu/util/NetworkUtilityTest.java index 95068aeee3d..6b0ac19466e 100644 --- a/util/src/test/java/org/hyperledger/besu/util/NetworkUtilityTest.java +++ b/util/src/test/java/org/hyperledger/besu/util/NetworkUtilityTest.java @@ -16,7 +16,9 @@ import static org.assertj.core.api.Assertions.assertThat; +import java.io.IOException; import java.net.InetSocketAddress; +import java.net.ServerSocket; import org.junit.Test; @@ -31,4 +33,11 @@ public void urlForSocketAddressHandlesIPv6() { final InetSocketAddress ipv6 = new InetSocketAddress("1:2:3:4:5:6:7:8", 80); assertThat(NetworkUtility.urlForSocketAddress("http", ipv6)).contains("[1:2:3:4:5:6:7:8]"); } + + @Test + public void assertPortIsNotAvailable() throws IOException { + final ServerSocket serverSocket = new ServerSocket(8541); + assertThat(!NetworkUtility.isPortAvailable(8541)).isEqualTo(true); + serverSocket.close(); + } } From 489ce6f457e506518c1590b104246afca93a2e13 Mon Sep 17 00:00:00 2001 From: Gabriel Fukushima Date: Tue, 1 Nov 2022 00:35:26 +1100 Subject: [PATCH 11/12] Refactor method Signed-off-by: Gabriel Fukushima --- .../main/java/org/hyperledger/besu/util/NetworkUtility.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/util/src/main/java/org/hyperledger/besu/util/NetworkUtility.java b/util/src/main/java/org/hyperledger/besu/util/NetworkUtility.java index 635db55913f..7e9560a03ab 100644 --- a/util/src/main/java/org/hyperledger/besu/util/NetworkUtility.java +++ b/util/src/main/java/org/hyperledger/besu/util/NetworkUtility.java @@ -117,7 +117,7 @@ public static boolean isPortAvailableForTcp(final int port) { return false; } - public static boolean isPortAvailableForUdp(final int port) { + private static boolean isPortAvailableForUdp(final int port) { try (final DatagramSocket datagramSocket = new DatagramSocket(null)) { datagramSocket.setReuseAddress(true); datagramSocket.bind(new InetSocketAddress(port)); @@ -129,7 +129,6 @@ public static boolean isPortAvailableForUdp(final int port) { } public static boolean isPortAvailable(final int port) { - if (isPortAvailableForTcp(port) && isPortAvailableForUdp(port)) return true; - return false; + return isPortAvailableForTcp(port) && isPortAvailableForUdp(port); } } From 49555f59977dea7f545aeb7876fa8f326b4b4f99 Mon Sep 17 00:00:00 2001 From: Gabriel Fukushima Date: Tue, 1 Nov 2022 00:36:04 +1100 Subject: [PATCH 12/12] Add more specific validation for ports/services Signed-off-by: Gabriel Fukushima --- .../java/org/hyperledger/besu/cli/BesuCommand.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java index 50ba0968ce3..7c008d4fc95 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java @@ -3128,20 +3128,25 @@ private void checkPortClash() { } private void checkIfRequiredPortsAreAvailable() { - List unavailablePorts = new ArrayList<>(); + final List unavailablePorts = new ArrayList<>(); getEffectivePorts().stream() .filter(Objects::nonNull) .filter(port -> port > 0) .forEach( port -> { - if (!NetworkUtility.isPortAvailable(port)) { + if (port.equals(p2PDiscoveryOptionGroup.p2pPort) + && !NetworkUtility.isPortAvailable(port)) { + unavailablePorts.add(port); + } + if (!port.equals(p2PDiscoveryOptionGroup.p2pPort) + && !NetworkUtility.isPortAvailableForTcp(port)) { unavailablePorts.add(port); } }); if (!unavailablePorts.isEmpty()) { throw new InvalidConfigurationException( "Port(s) '" - + unavailablePorts.toString() + + unavailablePorts + "' already in use. Check for other processes using the port(s)."); } }