From f44b737fcec42857bbc5bd7a60717a01b2cd3339 Mon Sep 17 00:00:00 2001 From: Ed Hennis Date: Thu, 19 Feb 2026 18:06:20 +0900 Subject: [PATCH] WebSocket should only call async_close once (#4848) Prevent WebSocket connections from trying to close twice. The issue only occurs in debug builds (assertions are disabled in release builds, including published packages), and when the WebSocket connections are unprivileged. The assert (and WRN log) occurs when a client drives up the resource balance enough to be forcibly disconnected while there are still messages pending to be sent. Thanks to @lathanbritz for discovering this issue in #4822. --- src/ripple/server/impl/BaseWSPeer.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/ripple/server/impl/BaseWSPeer.h b/src/ripple/server/impl/BaseWSPeer.h index 688e0f693..fd1722df0 100644 --- a/src/ripple/server/impl/BaseWSPeer.h +++ b/src/ripple/server/impl/BaseWSPeer.h @@ -29,6 +29,7 @@ #include #include #include + #include #include @@ -52,6 +53,9 @@ private: boost::beast::multi_buffer rb_; boost::beast::multi_buffer wb_; std::list> wq_; + /// The socket has been closed, or will close after the next write + /// finishes. Do not do any more writes, and don't try to close + /// again. bool do_close_ = false; boost::beast::websocket::close_reason cr_; waitable_timer timer_; @@ -350,6 +354,7 @@ BaseWSPeer::on_write_fin(error_code const& ec) return fail(ec, "write_fin"); wq_.pop_front(); if (do_close_) + { impl().ws_.async_close( cr_, bind_executor( @@ -358,6 +363,7 @@ BaseWSPeer::on_write_fin(error_code const& ec) &BaseWSPeer::on_close, impl().shared_from_this(), std::placeholders::_1))); + } else if (!wq_.empty()) on_write({}); }