github.com/inazumav/sing-box@v0.0.0-20230926072359-ab51429a14f1/transport/hysteria2/congestion/brutal.go (about)

     1  package congestion
     2  
     3  import (
     4  	"time"
     5  
     6  	"github.com/sagernet/quic-go/congestion"
     7  )
     8  
     9  const (
    10  	initMaxDatagramSize = 1252
    11  
    12  	pktInfoSlotCount = 4
    13  	minSampleCount   = 50
    14  	minAckRate       = 0.8
    15  )
    16  
    17  var _ congestion.CongestionControl = &BrutalSender{}
    18  
    19  type BrutalSender struct {
    20  	rttStats        congestion.RTTStatsProvider
    21  	bps             congestion.ByteCount
    22  	maxDatagramSize congestion.ByteCount
    23  	pacer           *pacer
    24  
    25  	pktInfoSlots [pktInfoSlotCount]pktInfo
    26  	ackRate      float64
    27  }
    28  
    29  type pktInfo struct {
    30  	Timestamp int64
    31  	AckCount  uint64
    32  	LossCount uint64
    33  }
    34  
    35  func NewBrutalSender(bps uint64) *BrutalSender {
    36  	bs := &BrutalSender{
    37  		bps:             congestion.ByteCount(bps),
    38  		maxDatagramSize: initMaxDatagramSize,
    39  		ackRate:         1,
    40  	}
    41  	bs.pacer = newPacer(func() congestion.ByteCount {
    42  		return congestion.ByteCount(float64(bs.bps) / bs.ackRate)
    43  	})
    44  	return bs
    45  }
    46  
    47  func (b *BrutalSender) SetRTTStatsProvider(rttStats congestion.RTTStatsProvider) {
    48  	b.rttStats = rttStats
    49  }
    50  
    51  func (b *BrutalSender) TimeUntilSend(bytesInFlight congestion.ByteCount) time.Time {
    52  	return b.pacer.TimeUntilSend()
    53  }
    54  
    55  func (b *BrutalSender) HasPacingBudget(now time.Time) bool {
    56  	return b.pacer.Budget(now) >= b.maxDatagramSize
    57  }
    58  
    59  func (b *BrutalSender) CanSend(bytesInFlight congestion.ByteCount) bool {
    60  	return bytesInFlight < b.GetCongestionWindow()
    61  }
    62  
    63  func (b *BrutalSender) GetCongestionWindow() congestion.ByteCount {
    64  	rtt := b.rttStats.SmoothedRTT()
    65  	if rtt <= 0 {
    66  		return 10240
    67  	}
    68  	return congestion.ByteCount(float64(b.bps) * rtt.Seconds() * 1.5 / b.ackRate)
    69  }
    70  
    71  func (b *BrutalSender) OnPacketSent(sentTime time.Time, bytesInFlight congestion.ByteCount,
    72  	packetNumber congestion.PacketNumber, bytes congestion.ByteCount, isRetransmittable bool,
    73  ) {
    74  	b.pacer.SentPacket(sentTime, bytes)
    75  }
    76  
    77  func (b *BrutalSender) OnPacketAcked(number congestion.PacketNumber, ackedBytes congestion.ByteCount,
    78  	priorInFlight congestion.ByteCount, eventTime time.Time,
    79  ) {
    80  	currentTimestamp := eventTime.Unix()
    81  	slot := currentTimestamp % pktInfoSlotCount
    82  	if b.pktInfoSlots[slot].Timestamp == currentTimestamp {
    83  		b.pktInfoSlots[slot].AckCount++
    84  	} else {
    85  		// uninitialized slot or too old, reset
    86  		b.pktInfoSlots[slot].Timestamp = currentTimestamp
    87  		b.pktInfoSlots[slot].AckCount = 1
    88  		b.pktInfoSlots[slot].LossCount = 0
    89  	}
    90  	b.updateAckRate(currentTimestamp)
    91  }
    92  
    93  func (b *BrutalSender) OnPacketLost(number congestion.PacketNumber, lostBytes congestion.ByteCount,
    94  	priorInFlight congestion.ByteCount,
    95  ) {
    96  	currentTimestamp := time.Now().Unix()
    97  	slot := currentTimestamp % pktInfoSlotCount
    98  	if b.pktInfoSlots[slot].Timestamp == currentTimestamp {
    99  		b.pktInfoSlots[slot].LossCount++
   100  	} else {
   101  		// uninitialized slot or too old, reset
   102  		b.pktInfoSlots[slot].Timestamp = currentTimestamp
   103  		b.pktInfoSlots[slot].AckCount = 0
   104  		b.pktInfoSlots[slot].LossCount = 1
   105  	}
   106  	b.updateAckRate(currentTimestamp)
   107  }
   108  
   109  func (b *BrutalSender) SetMaxDatagramSize(size congestion.ByteCount) {
   110  	b.maxDatagramSize = size
   111  	b.pacer.SetMaxDatagramSize(size)
   112  }
   113  
   114  func (b *BrutalSender) updateAckRate(currentTimestamp int64) {
   115  	minTimestamp := currentTimestamp - pktInfoSlotCount
   116  	var ackCount, lossCount uint64
   117  	for _, info := range b.pktInfoSlots {
   118  		if info.Timestamp < minTimestamp {
   119  			continue
   120  		}
   121  		ackCount += info.AckCount
   122  		lossCount += info.LossCount
   123  	}
   124  	if ackCount+lossCount < minSampleCount {
   125  		b.ackRate = 1
   126  	}
   127  	rate := float64(ackCount) / float64(ackCount+lossCount)
   128  	if rate < minAckRate {
   129  		b.ackRate = minAckRate
   130  	}
   131  	b.ackRate = rate
   132  }
   133  
   134  func (b *BrutalSender) InSlowStart() bool {
   135  	return false
   136  }
   137  
   138  func (b *BrutalSender) InRecovery() bool {
   139  	return false
   140  }
   141  
   142  func (b *BrutalSender) MaybeExitSlowStart() {}
   143  
   144  func (b *BrutalSender) OnRetransmissionTimeout(packetsRetransmitted bool) {}
   145  
   146  func maxDuration(a, b time.Duration) time.Duration {
   147  	if a > b {
   148  		return a
   149  	}
   150  	return b
   151  }