quinn-rs / quinn

Async-friendly QUIC implementation in Rust
Apache License 2.0
3.76k stars 380 forks source link

uni stream can't be cleaned up if closed while data in flight #1421

Closed Haplo79 closed 1 year ago

Haplo79 commented 1 year ago

Scenario (run on loopback):

Server

async fn drain_uni_stream(mut recv_stream: quinn::RecvStream) -> anyhow::Result<()> {
    let result = recv_stream.read_u8().await;
    if let Ok(byte) = result {
        println!("got u8: {}", byte);
    } else {
        println!("error: {:?}", result);
    }

    println!("leaving");
    Ok(())
}

Client

async fn create_stream_and_write(connection: quinn::Connection) -> anyhow::Result<()> { println!("creating new stream"); let mut uni = connection.open_uni().await?; println!("new stream created");

let result = writes(&mut uni).await;

println!("leaving");
result

}

async fn writes(uni: &mut quinn::SendStream) -> anyhow::Result<()> { for _ in 0..500 { println!("writing"); uni.write_u8(245).await.context("write failure")?; }

Ok(())

}


The client output is this:
``` text
creating new stream
new stream created
writing
writing
... about 15 more "writing"
writing
leaving
write to stream write failure

Caused by:
    sending stopped by peer: error 0
creating new stream

Notes:

Ralith commented 1 year ago

Thanks for the report! I agree that this looks fishy. New flow control credit should be issued after both peers drop their handles to the stream. Can you share a complete runnable repro?

Haplo79 commented 1 year ago

@Ralith Let me know if the attached source counts as a runnable repro. I'm not quite sure the best way to share that in a forum like this, maybe I should create a repo?

quinn_issue.zip

Ralith commented 1 year ago

That's perfect, thanks! Behavior is as described. I'll investigate this week.

Ralith commented 1 year ago

This turned out to be pretty simple. The I/O on the connection is not specifically significant: the issue is that we don't immediately update stream ID flow control when a stream that has been stopped is reset. Do you want a backport for 0.8?

Haplo79 commented 1 year ago

As to backport - am prepared to jump on .9 as soon as its released, and that would probably be the best way to get this fix. If .9 is more than a couple of weeks away, I certainly would not refuse a backport if its easy. :) Thanks.