github.com/MerlinKodo/quic-go@v0.39.2/internal/flowcontrol/connection_flow_controller.go (about)

     1  package flowcontrol
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"time"
     7  
     8  	"github.com/MerlinKodo/quic-go/internal/protocol"
     9  	"github.com/MerlinKodo/quic-go/internal/qerr"
    10  	"github.com/MerlinKodo/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 := utils.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  }