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 }