Subject: [quicwg/base-drafts] Rework draining period into two (or three) states (#899)

From: Martin Thomson <[email-masked]>
Date: Tue, 24 Oct 2017 22:20:38 -0700

As @ekr points out, there was definitely more than one closing state.  I've
modified this to the following three:

1. draining - when you know that the other side is closing, this is just to
   absorb stray packets

2. closing - when you have initiated the close and you need to re-send the
   close in addition to absorbing stray packets (this could be longer than the
   3RTO period if we like, but I've opted for keeping a shared timer)

3. timed out - when you timed out, and you are willing to revive the connection
   if new packets arrive; this one being optional

In the process I realized that we needed greater clarity about how to respond
to a closing frame (thanks to @huitema for the prompting).  I allow the
recipient to generate one closing frame, but no more than that.  They enter the
draining period thereafter and can't send any more packets.  Having two peers
in the closing state could result in a constant back-and-forth.

Editorial: I added the term "closing frame" to cover CONNECTION_CLOSE and
APPLICATION_CLOSE collectively, which were getting cumbersome.

Closes #871.
You can view, comment on, or merge this pull request online at:

  https://github.com/quicwg/base-drafts/pull/899

-- Commit Summary --

  * Rework draining period into two (or three) states

-- File Changes --

    M draft-ietf-quic-transport.md (104)

-- Patch Links --

https://github.com/quicwg/base-drafts/pull/899.patch
https://github.com/quicwg/base-drafts/pull/899.diff

-- 
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/pull/899

---

From: Christian Huitema <[email-masked]>
Date: Wed, 25 Oct 2017 14:11:27 -0700

huitema commented on this pull request.

Good idea, but we need to scrub this a bit, and clearly distinguish:

* Closing: MUST move to "draining" if closing packet is received. MAY respond with closing packet if some other frames are received. 
* Draining: MUST remain strictly silent until end of period. No connection close packet, no stateless reset packet. Just absorb the traffic and drop it.

> -endpoint maintains in this case, it MAY send the exact same packet.  However,
-endpoints SHOULD limit the number of packets they generate containing either
-close frame.  For instance, an endpoint could progressively increase the number
-of packets that it receives before sending additional packets.
+An endpoint sends a closing frame, either CONNECTION_CLOSE or APPLICATION_CLOSE,
+to terminate the connection immediately.  Either closing frame causes all open
+streams to immediately become closed; open streams can be assumed to be
+implicitly reset.
+
+After sending a closing frame, endpoints immediately enter a closing period.
+After receiving a closing frame, endpoints enter a draining period.  An endpoint
+that receives a closing frame MAY send a single closing frame before entering a
+draining period, but MUST NOT send further packets, which could result in a
+constant exchange of closing frames until the closing period on either peer
+ended.
+

"An endpoint may send a closing frame..." Can we not be a bit more specific? APPLICATION_CLOSE is supposedly only sent at the application request. We are discussing here a frame that is sent automatically by the transport. One can argue that it should be a CONNECTION_CLOSE frame.

As for the Ping-Pong effect, how about having a specific reason code, "Connection closed by peer"?  

> +implicitly reset.
+
+After sending a closing frame, endpoints immediately enter a closing period.
+After receiving a closing frame, endpoints enter a draining period.  An endpoint
+that receives a closing frame MAY send a single closing frame before entering a
+draining period, but MUST NOT send further packets, which could result in a
+constant exchange of closing frames until the closing period on either peer
+ended.
+
+During the draining period, an endpoint that sends a closing frame SHOULD
+respond to any subsequent packet that it receives with another packet containing
+either closing frame.  To reduce the state that an endpoint maintains in this
+case, it MAY send the exact same packet.  However, endpoints SHOULD limit the
+number of packets they generate containing a closing frame.  For instance, an
+endpoint could progressively increase the number of packets that it receives
+before sending additional packets.

Are we confusing draining and closing in this paragraph? This looks like the suggested behavior during the "closing" period, not the draining period. During the draining period, the application is supposed to just ignore any incoming packet and not respond at all, including not responding with a closing packet or a stateless reset packet.

-Different treatment is given to packets that are received while a connection is
-in the draining period depending on how the connection was closed.  An endpoint
-that is in a draining period MUST NOT send packets unless they contain a
-CONNECTION_CLOSE or APPLICATION_CLOSE frame.
+Disposing of connection state prior to the end of the draining period could
+result in delayed or reordered packets to be handled poorly.  Endpoints that
+have some alternative means to ensure that late-arriving packets on the
+connection do not create QUIC state, such as by closing the UDP socket, MAY use
+an abbreviated draining period which can allow for faster resource recovery.
+Servers that retain an open socket for accepting new connections SHOULD NOT exit
+the draining period early.

We may want to be a bit more specific about what connection state can be disposed of when entering the closing period. Implementations can probably just drop all information about unacknowledged packets, received packets or streams, but they need to be able to receive packets and decrypt them. If they don't do that, they won't be able to parse the incoming packet and notice arrival of a closing frame.

As for the draining period, state management becomes simpler with the new definition. The implementation just needs to remember the old connection ID, and guarantee that it won't send any packet for that connection ID until the end of the draining -- including not sending any stateless reset packet.

-- 
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/pull/899#pullrequestreview-72008409