Skip to content

Commit 8d76a2c

Browse files
neildgopherbot
authored andcommitted
quic: don't defer MAX_STREAMS frames indefinitely
Avoid a state where we can have a MAX_STREAMS frame to send, but do not send the frame for an indefinite amount of time. Conn.appendStreamFrames writes stream-related frames to the current packet. It also handles removing streams from the Conn when we no longer need to track their state. Removing streams can affect the frames we want to send. In particular, we may want to send a MAX_STREAMS to the peer indicating that it can open more streams because we've closed out some of the existing ones. Add MAX_STREAMS after removing streams, to ensure we pick up any changes to the sent value before adding it. This case doesn't show up in tests, because the test harness's idleness detection causes the Conn's event loop to run and notice the pending MAX_STREAMS frame. Changing tests to use testing/synctest (a followup CL) causes the problem to appear, because the event loop isn't run while the Conn is idle. Change-Id: Ia7394891317dae6ecfd529a9b3501ac082cb453e Reviewed-on: https://go-review.googlesource.com/c/net/+/714481 LUCI-TryBot-Result: Go LUCI <[email protected]> Auto-Submit: Damien Neil <[email protected]> Reviewed-by: Nicholas Husin <[email protected]> Reviewed-by: Nicholas Husin <[email protected]>
1 parent 027f8b7 commit 8d76a2c

File tree

1 file changed

+24
-10
lines changed

1 file changed

+24
-10
lines changed

quic/conn_streams.go

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -283,19 +283,14 @@ func (c *Conn) appendStreamFrames(w *packetWriter, pnum packetNumber, pto bool)
283283
return false
284284
}
285285

286-
// MAX_STREAM_DATA
287-
if !c.streams.remoteLimit[uniStream].appendFrame(w, uniStream, pnum, pto) {
288-
return false
289-
}
290-
if !c.streams.remoteLimit[bidiStream].appendFrame(w, bidiStream, pnum, pto) {
291-
return false
292-
}
293-
294286
if pto {
295287
return c.appendStreamFramesPTO(w, pnum)
296288
}
297289
if !c.streams.needSend.Load() {
298-
return true
290+
// If queueMeta includes newly-finished streams, we may extend the peer's
291+
// stream limits. When there are no streams to process, add MAX_STREAMS
292+
// frames here. Otherwise, wait until after we've processed queueMeta.
293+
return c.appendMaxStreams(w, pnum, pto)
299294
}
300295
c.streams.sendMu.Lock()
301296
defer c.streams.sendMu.Unlock()
@@ -354,6 +349,12 @@ func (c *Conn) appendStreamFrames(w *packetWriter, pnum packetNumber, pto bool)
354349
// If so, put the stream back on a queue.
355350
c.queueStreamForSendLocked(s, state)
356351
}
352+
353+
// MAX_STREAMS (possibly triggered by finalization of remote streams above).
354+
if !c.appendMaxStreams(w, pnum, pto) {
355+
return false
356+
}
357+
357358
// queueData contains streams with flow-controlled frames.
358359
for c.streams.queueData.head != nil {
359360
avail := c.streams.outflow.avail()
@@ -408,9 +409,12 @@ func (c *Conn) appendStreamFrames(w *packetWriter, pnum packetNumber, pto bool)
408409
// It returns true if no more frames need appending,
409410
// false if not everything fit in the current packet.
410411
func (c *Conn) appendStreamFramesPTO(w *packetWriter, pnum packetNumber) bool {
412+
const pto = true
413+
if !c.appendMaxStreams(w, pnum, pto) {
414+
return false
415+
}
411416
c.streams.sendMu.Lock()
412417
defer c.streams.sendMu.Unlock()
413-
const pto = true
414418
for _, ms := range c.streams.streams {
415419
s := ms.s
416420
if s == nil {
@@ -434,6 +438,16 @@ func (c *Conn) appendStreamFramesPTO(w *packetWriter, pnum packetNumber) bool {
434438
return true
435439
}
436440

441+
func (c *Conn) appendMaxStreams(w *packetWriter, pnum packetNumber, pto bool) bool {
442+
if !c.streams.remoteLimit[uniStream].appendFrame(w, uniStream, pnum, pto) {
443+
return false
444+
}
445+
if !c.streams.remoteLimit[bidiStream].appendFrame(w, bidiStream, pnum, pto) {
446+
return false
447+
}
448+
return true
449+
}
450+
437451
// A streamRing is a circular linked list of streams.
438452
type streamRing struct {
439453
head *Stream

0 commit comments

Comments
 (0)