github.com/apernet/quic-go@v0.43.1-0.20240515053213-5e9e635fd9f0/internal/flowcontrol/connection_flow_controller.go (about) 1 package flowcontrol 2 3 import ( 4 "errors" 5 "fmt" 6 "time" 7 8 "github.com/apernet/quic-go/internal/protocol" 9 "github.com/apernet/quic-go/internal/qerr" 10 "github.com/apernet/quic-go/internal/utils" 11 ) 12 13 type connectionFlowController struct { 14 baseFlowController 15 16 queueWindowUpdate func() 17 } 18 19 var _ ConnectionFlowController = &connectionFlowController{} 20 21 // NewConnectionFlowController gets a new flow controller for the connection 22 // It is created before we receive the peer's transport parameters, thus it starts with a sendWindow of 0. 23 func NewConnectionFlowController( 24 receiveWindow protocol.ByteCount, 25 maxReceiveWindow protocol.ByteCount, 26 queueWindowUpdate func(), 27 allowWindowIncrease func(size protocol.ByteCount) bool, 28 rttStats *utils.RTTStats, 29 logger utils.Logger, 30 ) ConnectionFlowController { 31 return &connectionFlowController{ 32 baseFlowController: baseFlowController{ 33 rttStats: rttStats, 34 receiveWindow: receiveWindow, 35 receiveWindowSize: receiveWindow, 36 maxReceiveWindowSize: maxReceiveWindow, 37 allowWindowIncrease: allowWindowIncrease, 38 logger: logger, 39 }, 40 queueWindowUpdate: queueWindowUpdate, 41 } 42 } 43 44 func (c *connectionFlowController) SendWindowSize() protocol.ByteCount { 45 return c.baseFlowController.sendWindowSize() 46 } 47 48 // IncrementHighestReceived adds an increment to the highestReceived value 49 func (c *connectionFlowController) IncrementHighestReceived(increment protocol.ByteCount) error { 50 c.mutex.Lock() 51 defer c.mutex.Unlock() 52 53 c.highestReceived += increment 54 if c.checkFlowControlViolation() { 55 return &qerr.TransportError{ 56 ErrorCode: qerr.FlowControlError, 57 ErrorMessage: fmt.Sprintf("received %d bytes for the connection, allowed %d bytes", c.highestReceived, c.receiveWindow), 58 } 59 } 60 return nil 61 } 62 63 func (c *connectionFlowController) AddBytesRead(n protocol.ByteCount) { 64 c.mutex.Lock() 65 c.baseFlowController.addBytesRead(n) 66 shouldQueueWindowUpdate := c.hasWindowUpdate() 67 c.mutex.Unlock() 68 if shouldQueueWindowUpdate { 69 c.queueWindowUpdate() 70 } 71 } 72 73 func (c *connectionFlowController) GetWindowUpdate() protocol.ByteCount { 74 c.mutex.Lock() 75 oldWindowSize := c.receiveWindowSize 76 offset := c.baseFlowController.getWindowUpdate() 77 if oldWindowSize < c.receiveWindowSize { 78 c.logger.Debugf("Increasing receive flow control window for the connection to %d kB", c.receiveWindowSize/(1<<10)) 79 } 80 c.mutex.Unlock() 81 return offset 82 } 83 84 // EnsureMinimumWindowSize sets a minimum window size 85 // it should make sure that the connection-level window is increased when a stream-level window grows 86 func (c *connectionFlowController) EnsureMinimumWindowSize(inc protocol.ByteCount) { 87 c.mutex.Lock() 88 if inc > c.receiveWindowSize { 89 c.logger.Debugf("Increasing receive flow control window for the connection to %d kB, in response to stream flow control window increase", c.receiveWindowSize/(1<<10)) 90 newSize := min(inc, c.maxReceiveWindowSize) 91 if delta := newSize - c.receiveWindowSize; delta > 0 && c.allowWindowIncrease(delta) { 92 c.receiveWindowSize = newSize 93 } 94 c.startNewAutoTuningEpoch(time.Now()) 95 } 96 c.mutex.Unlock() 97 } 98 99 // Reset rests the flow controller. This happens when 0-RTT is rejected. 100 // All stream data is invalidated, it's if we had never opened a stream and never sent any data. 101 // At that point, we only have sent stream data, but we didn't have the keys to open 1-RTT keys yet. 102 func (c *connectionFlowController) Reset() error { 103 c.mutex.Lock() 104 defer c.mutex.Unlock() 105 106 if c.bytesRead > 0 || c.highestReceived > 0 || !c.epochStartTime.IsZero() { 107 return errors.New("flow controller reset after reading data") 108 } 109 c.bytesSent = 0 110 c.lastBlockedAt = 0 111 return nil 112 }