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.
This commit is contained in:
Ed Hennis
2024-01-11 20:11:09 -05:00
committed by tequ
parent 8f30d8dcfc
commit a124e54f6b

View File

@@ -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>
@@ -52,6 +53,9 @@ private:
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_;
@@ -350,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(
@@ -358,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({});
}