rapiz1 / rathole

A lightweight and high-performance reverse proxy for NAT traversal, written in Rust. An alternative to frp and ngrok.
Apache License 2.0
8.82k stars 441 forks source link

Data channel commands aren't flushed, so the check to see if the connection is healthy doesn't always work #317

Open RyanAD opened 6 months ago

RyanAD commented 6 months ago

I've run into issues where the data channel was unhealthy, but it wasn't detected with this check:

if ch.write_all(&cmd).await.is_ok() {
    tokio::spawn(async move {
        let _ = copy_bidirectional(&mut ch, &mut visitor).await;
    });
    break;
} else {
    // Current data channel is broken. Request for a new one
    if data_ch_req_tx.send(true).is_err() {
        break 'pool;
    }
}

Ultimately it was because the ch.write_all(&cmd) may not cause the buffer to be flushed. The cause of this is that the connection is assumed healthy, but then fails during copy_bidirectional. It also means the TCP connection pool won't always be the correct size.

I've implemented the fix that is working for me in this PR: https://github.com/rapiz1/rathole/pull/316