Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Websocket should only call async_close once #4848

Merged
merged 3 commits into from
Jan 12, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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_)
{
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should do_close_ be reset to false here? What if on_write_fin is called again?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, it doesn't look like it's needed since write() is not going to be called in on_write_fin() if do_close_ is true and send() is not going to call write() because closing_ is true. Then I don't think two flags are needed. Can keep do_close_ and have the check on line 264 and remove do_close_ on line 280. The check on line 264 prevents from initiating async_close again in close(). And do_close_ set to true will allow async_close in on_write_fin() if the queue was not empty when close() was called.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great question. I don't think that setting do_close_ to false is a good idea, though. Then, if wq_ is not empty we'd call on_write(). We're trying to shut things down.

If it's a problem that we need to address, and it feels like maybe it is, we could add yet another data member bool closed_ and set it true just as soon as we're inside this if. That would make this if look like...

    if (do_close_ && !closed)
    {
        closed = true;
        assert(closing_);
        ...
    }
    else if (!wq_.empty() && !closed)

But I don't like the idea of adding yet another bool. Perhaps it would work better with an enum for a state machine?

enum class Finish {
    not_closing,
    closing,
    do_close,
    closed
};

Just a thought...

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the feedback. Coincidentally, I had the realization about not needing closing_ while having dinner, and came in to fix it before I even saw your comments. 😀

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