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

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