Skip to content

Commit

Permalink
WebSocket should only call async_close once (XRPLF#4848)
Browse files Browse the repository at this point in the history
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 XRPLF#4822.
  • Loading branch information
ximinez authored and sophiax851 committed Jun 12, 2024
1 parent b398797 commit fb5a939
Showing 1 changed file with 8 additions and 0 deletions.
8 changes: 8 additions & 0 deletions src/ripple/server/impl/BaseWSPeer.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include <boost/beast/core/multi_buffer.hpp>
#include <boost/beast/http/message.hpp>
#include <boost/beast/websocket.hpp>

#include <cassert>
#include <functional>

Expand All @@ -52,6 +53,9 @@ class BaseWSPeer : public BasePeer<Handler, Impl>, public WSSession
boost::beast::multi_buffer rb_;
boost::beast::multi_buffer wb_;
std::list<std::shared_ptr<WSMsg>> 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_;
Expand Down Expand Up @@ -256,6 +260,8 @@ BaseWSPeer<Handler, Impl>::close(
return post(strand_, [self = impl().shared_from_this(), reason] {
self->close(reason);
});
if (do_close_)
return;
do_close_ = true;
if (wq_.empty())
{
Expand Down Expand Up @@ -348,6 +354,7 @@ BaseWSPeer<Handler, Impl>::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(
Expand All @@ -356,6 +363,7 @@ BaseWSPeer<Handler, Impl>::on_write_fin(error_code const& ec)
&BaseWSPeer::on_close,
impl().shared_from_this(),
std::placeholders::_1)));
}
else if (!wq_.empty())
on_write({});
}
Expand Down

0 comments on commit fb5a939

Please sign in to comment.