You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I have a client application that creates many streams, and sends small amounts of data with an immediate fin on them. Sometimes it gets stuck, and stream_capacity returns InvalidStreamState for a stream that was previously written to. This issue looks similar to #1695, perhaps they have the same underlying cause.
Background
My application creates streams in a loop and sends a small amount of data on them (128 bytes), with an immediate fin. It always completes writing on one stream before starting a new stream.
The application is structured as a loop as follows:
If is_established(), while peer_streams_left_uni() allows (and while there is data), call stream_send.
Call conn.send in a loop until Error::Done, sends those packets.
Waits for new received packets or a deadline.
If packets were received, call recv() for them.
There are a few more things going on, but I believe these are the relevant parts. If in step 1 a write is partial (it wrote fewer bytes than provided, or returned Err::Done), then we stop stream_sending for that interation, and resume that write as the first thing in the next iteration.
Details
Almost always this works fine, but sometimes it would get stuck in a situation where stream_send returns Err::Done forever. This happens nondeterministically. Sometimes it happens in the first few milliseconds, sometimes my application runs fine for minutes until it hits this case, but eventually it gets stuck.
To debug this further, I added calls to stream_capacity before any stream_send that is resuming a previous partial write. Because we already wrote more than zero bytes to this stream, it exists. Because we never complete the full write, the stream is not completed. My server application does sometimes call stream_shutdown(Shutdown::Read), and every time my sender got stuck, the server did call stream_shutdown on the stream id that the sender got stuck on.
From the sender side, it makes the following calls:
stream_send, which returns a positive number of bytes written, but less than the size requested.
Sending packages, step 2–4 in the loop above. No new packets were received.
At this point, stream_capacity returns Ok(0). We call stream_send, this time it returns Error::Done.
Send/recv again, we received 46 bytes. (This number is not always the same.)
stream_capacity still returns Ok(0), stream_send still returns Error::Done.
Send/recv again, we received 59 bytes and then 42.
Now stream_capacity returns InvalidStreamState. stream_send returns Error::Done. Here my application gets stuck forever trying to complete the same write.
The details vary from run to run, but there are always two packets received before stream_capacity returns InvalidStreamState, and they are always 50-something and 40-something bytes (but not always the exact same size). The stream id at which it happens also varies, but it doesn’t seem completely random, in particular it commonly happens at stream id 3682. (This might just be due to the way my application writes, that that is the point where it goes over some limit?)
If I understand the documentation correctly, if I ever wrote to the stream and got an Ok(n>0), but didn’t finish, then stream_capacity might return StreamStopped, but it should not return InvalidStreamState, right?
The text was updated successfully, but these errors were encountered:
Thanks for the report. Are you able to provide logs? It would help to see what frames the server is actually sending. You could provide quiche trace logging (emabled in the example apps via RUST_LOG=trace) or qlogs (enabled in the example apps via the QLOGDIR environment variable).
Summary
I have a client application that creates many streams, and sends small amounts of data with an immediate fin on them. Sometimes it gets stuck, and
stream_capacity
returnsInvalidStreamState
for a stream that was previously written to. This issue looks similar to #1695, perhaps they have the same underlying cause.Background
My application creates streams in a loop and sends a small amount of data on them (128 bytes), with an immediate fin. It always completes writing on one stream before starting a new stream.
The application is structured as a loop as follows:
is_established()
, whilepeer_streams_left_uni()
allows (and while there is data), callstream_send
.conn.send
in a loop untilError::Done
, sends those packets.recv()
for them.There are a few more things going on, but I believe these are the relevant parts. If in step 1 a write is partial (it wrote fewer bytes than provided, or returned
Err::Done
), then we stopstream_send
ing for that interation, and resume that write as the first thing in the next iteration.Details
Almost always this works fine, but sometimes it would get stuck in a situation where
stream_send
returnsErr::Done
forever. This happens nondeterministically. Sometimes it happens in the first few milliseconds, sometimes my application runs fine for minutes until it hits this case, but eventually it gets stuck.To debug this further, I added calls to
stream_capacity
before anystream_send
that is resuming a previous partial write. Because we already wrote more than zero bytes to this stream, it exists. Because we never complete the full write, the stream is not completed. My server application does sometimes callstream_shutdown(Shutdown::Read)
, and every time my sender got stuck, the server did callstream_shutdown
on the stream id that the sender got stuck on.From the sender side, it makes the following calls:
stream_send
, which returns a positive number of bytes written, but less than the size requested.stream_capacity
returnsOk(0)
. We callstream_send
, this time it returnsError::Done
.stream_capacity
still returnsOk(0)
,stream_send
still returnsError::Done
.stream_capacity
returnsInvalidStreamState
.stream_send
returnsError::Done
. Here my application gets stuck forever trying to complete the same write.The details vary from run to run, but there are always two packets received before
stream_capacity
returnsInvalidStreamState
, and they are always 50-something and 40-something bytes (but not always the exact same size). The stream id at which it happens also varies, but it doesn’t seem completely random, in particular it commonly happens at stream id 3682. (This might just be due to the way my application writes, that that is the point where it goes over some limit?)If I understand the documentation correctly, if I ever wrote to the stream and got an
Ok(n>0)
, but didn’t finish, thenstream_capacity
might returnStreamStopped
, but it should not returnInvalidStreamState
, right?The text was updated successfully, but these errors were encountered: