From 83b545aceb407c845cae18511576ac2188102f89 Mon Sep 17 00:00:00 2001 From: lupin012 <58134934+lupin012@users.noreply.github.com> Date: Mon, 29 Jan 2024 13:24:06 +0100 Subject: [PATCH] rpcdaemon: add --websocket option to enable websocket (#1780) --- cmd/common/rpcdaemon_options.cpp | 4 ++++ silkworm/rpc/daemon.cpp | 4 ++-- silkworm/rpc/http/connection.cpp | 16 ++++++++++++---- silkworm/rpc/http/connection.hpp | 5 ++++- silkworm/rpc/http/server.cpp | 8 +++++--- silkworm/rpc/http/server.hpp | 5 ++++- silkworm/rpc/settings.hpp | 1 + 7 files changed, 32 insertions(+), 11 deletions(-) diff --git a/cmd/common/rpcdaemon_options.cpp b/cmd/common/rpcdaemon_options.cpp index 5a297cafa7..bc9dbce089 100644 --- a/cmd/common/rpcdaemon_options.cpp +++ b/cmd/common/rpcdaemon_options.cpp @@ -107,6 +107,10 @@ void add_rpcdaemon_options(CLI::App& cli, silkworm::rpc::DaemonSettings& setting cli.add_flag("--erigon_compatibility", settings.erigon_json_rpc_compatibility) ->description("Flag indicating if strict compatibility with Erigon RpcDaemon is enabled") ->capture_default_str(); + + cli.add_flag("--websocket", settings.use_websocket) + ->description("Enable WebSocket protocol for Execution Layer and Engine JSON RPC API, same port as HTTP(S)") + ->capture_default_str(); } } // namespace silkworm::cmd::common diff --git a/silkworm/rpc/daemon.cpp b/silkworm/rpc/daemon.cpp index cbba649361..ce79bafb79 100644 --- a/silkworm/rpc/daemon.cpp +++ b/silkworm/rpc/daemon.cpp @@ -302,12 +302,12 @@ void Daemon::start() { if (not settings_.eth_end_point.empty()) { rpc_services_.emplace_back( std::make_unique( - settings_.eth_end_point, settings_.eth_api_spec, ioc, worker_pool_, settings_.cors_domain, /*jwt_secret=*/std::nullopt)); + settings_.eth_end_point, settings_.eth_api_spec, ioc, worker_pool_, settings_.cors_domain, /*jwt_secret=*/std::nullopt, settings_.use_websocket)); } if (not settings_.engine_end_point.empty()) { rpc_services_.emplace_back( std::make_unique( - settings_.engine_end_point, kDefaultEth2ApiSpec, ioc, worker_pool_, settings_.cors_domain, jwt_secret_)); + settings_.engine_end_point, kDefaultEth2ApiSpec, ioc, worker_pool_, settings_.cors_domain, jwt_secret_, settings_.use_websocket)); } } diff --git a/silkworm/rpc/http/connection.cpp b/silkworm/rpc/http/connection.cpp index 8225e26251..b5390fc322 100644 --- a/silkworm/rpc/http/connection.cpp +++ b/silkworm/rpc/http/connection.cpp @@ -37,13 +37,15 @@ Connection::Connection(boost::asio::io_context& io_context, commands::RpcApi& api, commands::RpcApiTable& handler_table, const std::vector& allowed_origins, - std::optional jwt_secret) + std::optional jwt_secret, + bool use_websocket) : socket_{io_context}, api_{api}, handler_table_{handler_table}, request_handler_{this, api, handler_table}, allowed_origins_{allowed_origins}, - jwt_secret_{std ::move(jwt_secret)} { + jwt_secret_{std ::move(jwt_secret)}, + use_websocket_{use_websocket} { SILK_TRACE << "Connection::Connection socket " << &socket_ << " created"; } @@ -80,8 +82,14 @@ Task Connection::do_read() { request_http_version_ = parser.get().version(); if (boost::beast::websocket::is_upgrade(parser.get())) { - co_await do_upgrade(parser.release()); - co_return false; + if (use_websocket_) { + co_await do_upgrade(parser.release()); + co_return false; + } else { + // If it does not (or cannot) upgrade the connection, it ignores the Upgrade header and sends back a regular response (OK) + co_await do_write("", boost::beast::http::status::ok); + } + co_return true; } co_await handle_request(parser.release()); co_return true; diff --git a/silkworm/rpc/http/connection.hpp b/silkworm/rpc/http/connection.hpp index 8fb4cdad0d..c6a94b4db9 100644 --- a/silkworm/rpc/http/connection.hpp +++ b/silkworm/rpc/http/connection.hpp @@ -47,7 +47,8 @@ class Connection : public Channel { commands::RpcApi& api, commands::RpcApiTable& handler_table, const std::vector& allowed_origins, - std::optional jwt_secret); + std::optional jwt_secret, + bool use_websocket); ~Connection() override; boost::asio::ip::tcp::socket& socket() { return socket_; } @@ -97,6 +98,8 @@ class Connection : public Channel { unsigned int request_http_version_{11}; boost::beast::flat_buffer data_; + + bool use_websocket_; }; } // namespace silkworm::rpc::http diff --git a/silkworm/rpc/http/server.cpp b/silkworm/rpc/http/server.cpp index 2a0e555dd2..2edf6b4589 100644 --- a/silkworm/rpc/http/server.cpp +++ b/silkworm/rpc/http/server.cpp @@ -46,13 +46,15 @@ Server::Server(const std::string& end_point, boost::asio::io_context& io_context, boost::asio::thread_pool& workers, std::vector allowed_origins, - std::optional jwt_secret) + std::optional jwt_secret, + bool use_websocket) : rpc_api_{io_context, workers}, handler_table_{api_spec}, io_context_(io_context), acceptor_{io_context}, allowed_origins_{std::move(allowed_origins)}, - jwt_secret_(std::move(jwt_secret)) { + jwt_secret_(std::move(jwt_secret)), + use_websocket_{use_websocket} { const auto [host, port] = parse_endpoint(end_point); // Open the acceptor with the option to reuse the address (i.e. SO_REUSEADDR). @@ -77,7 +79,7 @@ Task Server::run() { while (acceptor_.is_open()) { SILK_DEBUG << "Server::run accepting using io_context " << &io_context_ << "..."; - auto new_connection = std::make_shared(io_context_, rpc_api_, handler_table_, allowed_origins_, jwt_secret_); + auto new_connection = std::make_shared(io_context_, rpc_api_, handler_table_, allowed_origins_, jwt_secret_, use_websocket_); co_await acceptor_.async_accept(new_connection->socket(), boost::asio::use_awaitable); if (!acceptor_.is_open()) { SILK_TRACE << "Server::run returning..."; diff --git a/silkworm/rpc/http/server.hpp b/silkworm/rpc/http/server.hpp index 81826658e8..64a570a2df 100644 --- a/silkworm/rpc/http/server.hpp +++ b/silkworm/rpc/http/server.hpp @@ -50,7 +50,8 @@ class Server { boost::asio::io_context& io_context, boost::asio::thread_pool& workers, std::vector allowed_origins, - std::optional jwt_secret); + std::optional jwt_secret, + bool use_websocket); void start(); @@ -78,6 +79,8 @@ class Server { //! The JSON Web Token (JWT) secret for secure channel communication std::optional jwt_secret_; + + bool use_websocket_; }; } // namespace silkworm::rpc::http diff --git a/silkworm/rpc/settings.hpp b/silkworm/rpc/settings.hpp index 259aac49eb..629f19a384 100644 --- a/silkworm/rpc/settings.hpp +++ b/silkworm/rpc/settings.hpp @@ -39,6 +39,7 @@ struct DaemonSettings { std::optional jwt_secret_file; bool skip_protocol_check{false}; bool erigon_json_rpc_compatibility{false}; + bool use_websocket{false}; }; } // namespace silkworm::rpc