johanhelsing / matchbox

Painless peer-to-peer WebRTC networking for rust wasm (and native!)
Apache License 2.0
869 stars 72 forks source link

`socket.channel(..).receive()` can hang infinitely #329

Closed simbleau closed 12 months ago

simbleau commented 12 months ago

If one fails to connect to a signaling server, and you have a loop/system in bevy which collects messages from channels, this instruction will hang infinitely.

You can easily test this out yourself:

Add this somewhere:

// Enter a condition where the socket was dropped
if socket.try_update_peers().is_err() {
    error!("This will be printed");
    socket.channel(0).receive();
    error!("This will never get printed.");
}

P.S. This was a nightmare to find.

simbleau commented 12 months ago

Further context:

Here is the code. The issue is that std::iter::repeat_with(F) creates a new closure that iterates infinitely with the provided closure until there are matching elements that can make up an iterator.

std::iter::repeat_with(|| self.rx.try_next())
            .map_while(Result::ok)
            .flatten()
            .collect()

In addition, we poll self.rx.try_next() which is an UnboundedReceiver. They handle things a little weird, where Ok(None) is returned when the socket is closed. NOT an Err(e). This means it loops infinitely because there's no match, ever, on an element.

image