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

User issued pong messages should probably be kept separate from replies to pings. #78

Open
najamelan opened this issue Sep 14, 2019 · 3 comments

Comments

@najamelan
Copy link
Contributor

The RFC describes two uses for pong messages:

  • reply to ping
  • unidirectional heartbeat

Tungstenite automatically replies to pings, and since the RFC defines that the application data should be identical to the ping, so there's not much the user can add to that. For that reason afaict a user should never manually respond to ping.

However the user can send pongs as unidirectional heartbeats. The problem is that right now by storing these on self.pong, they can override replies to ping, and potentially have different application data inside, so not constitute a valid response to ping.

It's pretty unwieldy for client code to avoid this problem. If using tungstenite directly it can be avoided by following the reception of a ping by calling write_pending until it doesn't return wouldblock to be sure the ping has been answered and only then send a manual pong.

If using through tokio-tungstenite or other code that splits reader and writer tasks, things become complicated, because now you have to communicate from your reader that received the ping that your writer should call write_pending before sending the next pong, and through tokio-tungstenite write_pending isn't exactly accessible.

I feel it would be better to document that a user should never respond to ping manually and consider user created pong messages like any other message to be queued. It doesn't need to jump the queue. The RFC only says replies to pings should be sent as fast as practical.

That would avoid this problem all together.

@daniel-abramov
Copy link
Member

Makes sense.

Indeed, previously we "did not notice" this problem as first versions of tungstenite-rs did not allow to construct ping and pong messages directly.

@cong-or
Copy link

cong-or commented Sep 29, 2021

@application-developer-DA are there any examples of how to manually construct a pong response? My use case requires that a pong is sent back with an internal message. From my understanding, this lib automatically returns an empty pong? Can it be overridden? thanks

@modestmicha
Copy link

modestmicha commented Sep 29, 2021

@mycorrhizas

To send a custom pong message instead of the default pong message as a reply to a ping you can simply:

match socket.read_message()? {
    Message::Ping(payload) => {
        socket.write_message(Message::Pong(your_custom_pong_payload_vec_u8))?;
    }
    _ => {}
}

However, if you wish to keep sending the default pong message and send an additional pong you'd have to:

match socket.read_message()? {
    Message::Ping(payload) => {
        // Make sure default pong messages are not overwritten.
        socket.write_pending()?;
        // Additional pong here or anywhere else.
        socket.write_message(Message::Pong(your_custom_pong_payload_vec_u8))?;
    }
    _ => {}
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants