-
Notifications
You must be signed in to change notification settings - Fork 205
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
Unclear stream close semantics #439
Comments
This is related to #175, but not #61. The current requirement is that the FIN or RST is also acknowledged. That means that you DON'T have to send a RST, you simply retransmit the FIN until you get an acknowledgment. You are right to observe that the consequences of the FIN are not obvious. If both FIN and RST are acknowledged and you don't have a timestamp for the receipt (and processing) of those packets, then you don't know which had effect first: was the whole stream delivered or not? FWIW, I have been very careful to use close to mean FIN, and reset to mean RST. A RST is reserved for error conditions (including aborts) and will not guarantee any delivery of any data. A FIN would be used under normal conditions and would result in data being delivered. Sending FIN would likely correspond to closing the write stream in a bi-directional stream API. RST corresponds to killing the read-write pair. Not sure what to do with this issue; it's the sort of thing that might have been better sent as a question to the mailing list. |
My concern was related to how you can close the READ stream from the receiving end. It is correct that FIN ACK can be used to avoid the race condition by delaying a RST, but you still need to issue a RST unless you are willing to commit state until peer sends a FIN. In other words, there is no simple way to close a read stream. |
You might be interested in #171. |
Thanks. Yes that seems to address the issue, though it still appear to me semantics could be cleaned up a bit. So I am closing this one. |
There are still unclear issues: However, now there are 1000 open streams. Even though the server has long forgotten about those streams, the client can now start sending random data on any of those server initiated streams. The server may choose consider this an error, but this is not easy because it might actually want to receive data on some recent streams anyway, say a progress stream interleaved among the images. So now, which streams are indeed closed and which are not? The server may send DISINTEREST frames on every stream used to send pictures, but that is just needless trafic and state. The application protocol may decide what should happen with each stream. But there is no simple way for the transport layer to enforce when it is reasonable to accept and buffer data on streams and when not. All of this goes away if we have uni-directional streams, or at least that seems to be case superficially. |
For this situation to exist, the server would have to be using server push AND the client would have to send data on those streams, which is not permitted, so it would be detected as an attack/error pretty quickly. Otherwise, it's the server that sends STREAM_LIMIT updates. |
Isn't that assuming HTTP2, which is just one application level use case? The HTTP application can reject this, but another higher level protocol that is not HTTP2 will need to revisit those concerns. A related concern is that is is non-trivial to remember which streams are only implicitly opened by higher ID and which are closed. With uni-directional streams and clean close semantics, the reader only needs to remember the actively open streams and update the STREAM_LIMIT as appropriate. I'm not interested in placing application level semantics in transport, just to have a clean separation of concerns so the transport can take action based on simple interactions with the application layer. |
No, I'm just using HTTP for context. The discussion in #263 covers this in more detail. The other side can only send on streams up to your stream limit, plus any streams you opened. I think that it's easy enough to remember which streams are opened. A peer can only open so many and the rules for that are clear. I agree that unidirectional streams is easier, but the rules are clear. |
OK, so an application can choose to initiate a stream as write only or as read/write even if this concept does not exist at the protocol level. The transport layer can then consider it an error if receiving data on a write only stream. |
I no longer know what this issue is. I recommend creating a new issue with a clear description of a specific issue. I'm closing this for now. If you have questions, or you aren't sure about the issue, please ask the quic@ietf.org mailing list before opening issue. |
According to life of a stream, a stream can transition from "half closed local" to "closed" by sending a "RST" or by receiving "FIN" or "RST" from peer. However, sending a "RST" may race ahead of any in-flight packets send to the peer. In fact this is likely because the stream will transmit according to a fair schedule while RST will likely be prioritised. The RST will tear down state on both ends preventing the peer from receiving and the local endpont from retransmitting (depending on implementation).
In addition to the above there is also a user aspect. QUIC does not define an API, but what does it mean to close a stream? Do you close the write stream or do you close both read and write stream? This can encoded as either sending "FIN" or "FIN+RST" but has the race condition mentioned. When cleaning up after a stream initiated locally, it appears you need to always eventually send a RST even if the peer has no interest in writing. Application protocol could agree to not require a RST, but that seems a bit roundabout.
Perhaps it is saner to handle read and write streams entirely separately.
#175
The issue may also be related to:
#61
The text was updated successfully, but these errors were encountered: