Subject: [quicwg/base-drafts] Unclear stream close semantics (#439)

From: MikkelFJ <[email-masked]>
Date: Sun, 16 Apr 2017 01:22:02 -0700

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.
https://github.com/quicwg/base-drafts/issues/175

The issue may also be related to:
https://github.com/quicwg/base-drafts/issues/61

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/439

---

From: Martin Thomson <[email-masked]>
Date: Mon, 17 Apr 2017 22:29:09 -0700

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](mailto:[email-masked]).

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/439#issuecomment-294687351

---

From: MikkelFJ <[email-masked]>
Date: Tue, 18 Apr 2017 01:03:39 -0700

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 are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/439#issuecomment-294721608

---

From: Martin Thomson <[email-masked]>
Date: Tue, 18 Apr 2017 01:09:29 -0700

You might be interested in #171.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/439#issuecomment-294722959

---

From: MikkelFJ <[email-masked]>
Date: Tue, 18 Apr 2017 03:29:57 -0700

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.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/439#issuecomment-294771077

---

From: MikkelFJ <[email-masked]>
Date: Tue, 18 Apr 2017 03:29:57 -0700

Closed #439.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/439#event-1046386451

---

From: MikkelFJ <[email-masked]>
Date: Tue, 18 Apr 2017 06:46:14 -0700

There are still unclear issues:
For example, a server may send 1000 images with client gradually sending STREAM_LIMIT updates so it never receives more than 20 images at time. The server is not interested in data from the client at all, so it never updates STREAM_LIMIT towards the client.

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.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/439#issuecomment-294849141

---

From: MikkelFJ <[email-masked]>
Date: Tue, 18 Apr 2017 06:46:14 -0700

Reopened #439.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/439#event-1046693351

---

From: Martin Thomson <[email-masked]>
Date: Tue, 18 Apr 2017 17:36:57 -0700

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.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/439#issuecomment-295026196

---

From: MikkelFJ <[email-masked]>
Date: Tue, 18 Apr 2017 22:55:32 -0700

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.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/439#issuecomment-295107294

---

From: Martin Thomson <[email-masked]>
Date: Tue, 18 Apr 2017 23:48:40 -0700

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.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/439#issuecomment-295125643

---

From: MikkelFJ <[email-masked]>
Date: Wed, 19 Apr 2017 00:18:51 -0700

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 read only stream.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/439#issuecomment-295135173

---

From: Martin Thomson <[email-masked]>
Date: Thu, 27 Apr 2017 19:05:07 -0700

Closed #439.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/439#event-1061436838

---

From: Martin Thomson <[email-masked]>
Date: Thu, 27 Apr 2017 19:05:07 -0700

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 [email-masked] mailing list before opening issue.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/439#issuecomment-297887587