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