golang.org/x/net@v0.25.1-0.20240516223405-c87a5b62e243/quic/conn_flow.go (about)

     1  // Copyright 2023 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  //go:build go1.21
     6  
     7  package quic
     8  
     9  import (
    10  	"sync/atomic"
    11  	"time"
    12  )
    13  
    14  // connInflow tracks connection-level flow control for data sent by the peer to us.
    15  //
    16  // There are four byte offsets of significance in the stream of data received from the peer,
    17  // each >= to the previous:
    18  //
    19  //   - bytes read by the user
    20  //   - bytes received from the peer
    21  //   - limit sent to the peer in a MAX_DATA frame
    22  //   - potential new limit to sent to the peer
    23  //
    24  // We maintain a flow control window, so as bytes are read by the user
    25  // the potential limit is extended correspondingly.
    26  //
    27  // We keep an atomic counter of bytes read by the user and not yet applied to the
    28  // potential limit (credit). When this count grows large enough, we update the
    29  // new limit to send and mark that we need to send a new MAX_DATA frame.
    30  type connInflow struct {
    31  	sent      sentVal // set when we need to send a MAX_DATA update to the peer
    32  	usedLimit int64   // total bytes sent by the peer, must be less than sentLimit
    33  	sentLimit int64   // last MAX_DATA sent to the peer
    34  	newLimit  int64   // new MAX_DATA to send
    35  
    36  	credit atomic.Int64 // bytes read but not yet applied to extending the flow-control window
    37  }
    38  
    39  func (c *Conn) inflowInit() {
    40  	// The initial MAX_DATA limit is sent as a transport parameter.
    41  	c.streams.inflow.sentLimit = c.config.maxConnReadBufferSize()
    42  	c.streams.inflow.newLimit = c.streams.inflow.sentLimit
    43  }
    44  
    45  // handleStreamBytesReadOffLoop records that the user has consumed bytes from a stream.
    46  // We may extend the peer's flow control window.
    47  //
    48  // This is called indirectly by the user, via Read or CloseRead.
    49  func (c *Conn) handleStreamBytesReadOffLoop(n int64) {
    50  	if n == 0 {
    51  		return
    52  	}
    53  	if c.shouldUpdateFlowControl(c.streams.inflow.credit.Add(n)) {
    54  		// We should send a MAX_DATA update to the peer.
    55  		// Record this on the Conn's main loop.
    56  		c.sendMsg(func(now time.Time, c *Conn) {
    57  			// A MAX_DATA update may have already happened, so check again.
    58  			if c.shouldUpdateFlowControl(c.streams.inflow.credit.Load()) {
    59  				c.sendMaxDataUpdate()
    60  			}
    61  		})
    62  	}
    63  }
    64  
    65  // handleStreamBytesReadOnLoop extends the peer's flow control window after
    66  // data has been discarded due to a RESET_STREAM frame.
    67  //
    68  // This is called on the conn's loop.
    69  func (c *Conn) handleStreamBytesReadOnLoop(n int64) {
    70  	if c.shouldUpdateFlowControl(c.streams.inflow.credit.Add(n)) {
    71  		c.sendMaxDataUpdate()
    72  	}
    73  }
    74  
    75  func (c *Conn) sendMaxDataUpdate() {
    76  	c.streams.inflow.sent.setUnsent()
    77  	// Apply current credit to the limit.
    78  	// We don't strictly need to do this here
    79  	// since appendMaxDataFrame will do so as well,
    80  	// but this avoids redundant trips down this path
    81  	// if the MAX_DATA frame doesn't go out right away.
    82  	c.streams.inflow.newLimit += c.streams.inflow.credit.Swap(0)
    83  }
    84  
    85  func (c *Conn) shouldUpdateFlowControl(credit int64) bool {
    86  	return shouldUpdateFlowControl(c.config.maxConnReadBufferSize(), credit)
    87  }
    88  
    89  // handleStreamBytesReceived records that the peer has sent us stream data.
    90  func (c *Conn) handleStreamBytesReceived(n int64) error {
    91  	c.streams.inflow.usedLimit += n
    92  	if c.streams.inflow.usedLimit > c.streams.inflow.sentLimit {
    93  		return localTransportError{
    94  			code:   errFlowControl,
    95  			reason: "stream exceeded flow control limit",
    96  		}
    97  	}
    98  	return nil
    99  }
   100  
   101  // appendMaxDataFrame appends a MAX_DATA frame to the current packet.
   102  //
   103  // It returns true if no more frames need appending,
   104  // false if it could not fit a frame in the current packet.
   105  func (c *Conn) appendMaxDataFrame(w *packetWriter, pnum packetNumber, pto bool) bool {
   106  	if c.streams.inflow.sent.shouldSendPTO(pto) {
   107  		// Add any unapplied credit to the new limit now.
   108  		c.streams.inflow.newLimit += c.streams.inflow.credit.Swap(0)
   109  		if !w.appendMaxDataFrame(c.streams.inflow.newLimit) {
   110  			return false
   111  		}
   112  		c.streams.inflow.sentLimit += c.streams.inflow.newLimit
   113  		c.streams.inflow.sent.setSent(pnum)
   114  	}
   115  	return true
   116  }
   117  
   118  // ackOrLossMaxData records the fate of a MAX_DATA frame.
   119  func (c *Conn) ackOrLossMaxData(pnum packetNumber, fate packetFate) {
   120  	c.streams.inflow.sent.ackLatestOrLoss(pnum, fate)
   121  }
   122  
   123  // connOutflow tracks connection-level flow control for data sent by us to the peer.
   124  type connOutflow struct {
   125  	max  int64 // largest MAX_DATA received from peer
   126  	used int64 // total bytes of STREAM data sent to peer
   127  }
   128  
   129  // setMaxData updates the connection-level flow control limit
   130  // with the initial limit conveyed in transport parameters
   131  // or an update from a MAX_DATA frame.
   132  func (f *connOutflow) setMaxData(maxData int64) {
   133  	f.max = max(f.max, maxData)
   134  }
   135  
   136  // avail returns the number of connection-level flow control bytes available.
   137  func (f *connOutflow) avail() int64 {
   138  	return f.max - f.used
   139  }
   140  
   141  // consume records consumption of n bytes of flow.
   142  func (f *connOutflow) consume(n int64) {
   143  	f.used += n
   144  }