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 }