diff --git a/go.mod b/go.mod index 9ce928ce..86e34b49 100644 --- a/go.mod +++ b/go.mod @@ -24,12 +24,12 @@ require ( github.com/metacubex/fswatch v0.1.1 github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 github.com/metacubex/kcp-go v0.0.0-20250923001605-1ba6f691c45b - github.com/metacubex/quic-go v0.54.1-0.20250926001022-e2a3ce003b3a + github.com/metacubex/quic-go v0.55.1-0.20251004050223-450bd9e32033 github.com/metacubex/randv2 v0.2.0 github.com/metacubex/restls-client-go v0.1.7 github.com/metacubex/sing v0.5.6 github.com/metacubex/sing-mux v0.3.4 - github.com/metacubex/sing-quic v0.0.0-20250909002258-06122df8f231 + github.com/metacubex/sing-quic v0.0.0-20251004051927-c45ee18473bb github.com/metacubex/sing-shadowsocks v0.2.12 github.com/metacubex/sing-shadowsocks2 v0.2.7 github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2 @@ -105,7 +105,6 @@ require ( github.com/vishvananda/netns v0.0.4 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec // indirect - go.uber.org/mock v0.4.0 // indirect golang.org/x/mod v0.20.0 // indirect golang.org/x/text v0.22.0 // indirect golang.org/x/time v0.7.0 // indirect diff --git a/go.sum b/go.sum index 7a00f211..d22b475c 100644 --- a/go.sum +++ b/go.sum @@ -112,8 +112,8 @@ github.com/metacubex/kcp-go v0.0.0-20250923001605-1ba6f691c45b h1:z7JLKjugnQ1qvD github.com/metacubex/kcp-go v0.0.0-20250923001605-1ba6f691c45b/go.mod h1:HIJZW4QMhbBqXuqC1ly6Hn0TEYT2SzRw58ns1yGhXTs= github.com/metacubex/nftables v0.0.0-20250503052935-30a69ab87793 h1:1Qpuy+sU3DmyX9HwI+CrBT/oLNJngvBorR2RbajJcqo= github.com/metacubex/nftables v0.0.0-20250503052935-30a69ab87793/go.mod h1:RjRNb4G52yAgfR+Oe/kp9G4PJJ97Fnj89eY1BFO3YyA= -github.com/metacubex/quic-go v0.54.1-0.20250926001022-e2a3ce003b3a h1:l7BWjOifmqM2zMi+AMrgIx1z4KJt0oY/6cHW11kA9IQ= -github.com/metacubex/quic-go v0.54.1-0.20250926001022-e2a3ce003b3a/go.mod h1:1lktQFtCD17FZliVypbrDHwbsFSsmz2xz2TRXydvB5c= +github.com/metacubex/quic-go v0.55.1-0.20251004050223-450bd9e32033 h1:LEzvR5AmHEatqE6IWgMBUJHnaiz9VJfZeDGOiHFuWZU= +github.com/metacubex/quic-go v0.55.1-0.20251004050223-450bd9e32033/go.mod h1:1lktQFtCD17FZliVypbrDHwbsFSsmz2xz2TRXydvB5c= github.com/metacubex/randv2 v0.2.0 h1:uP38uBvV2SxYfLj53kuvAjbND4RUDfFJjwr4UigMiLs= github.com/metacubex/randv2 v0.2.0/go.mod h1:kFi2SzrQ5WuneuoLLCMkABtiBu6VRrMrWFqSPyj2cxY= github.com/metacubex/restls-client-go v0.1.7 h1:eCwiXCTQb5WJu9IlgYvDBA1OgrINv58dEe7hcN5H15k= @@ -123,8 +123,8 @@ github.com/metacubex/sing v0.5.6 h1:mEPDCadsCj3DB8gn+t/EtposlYuALEkExa/LUguw6/c= github.com/metacubex/sing v0.5.6/go.mod h1:ypf0mjwlZm0sKdQSY+yQvmsbWa0hNPtkeqyRMGgoN+w= github.com/metacubex/sing-mux v0.3.4 h1:tf4r27CIkzaxq9kBlAXQkgMXq2HPp5Mta60Kb4RCZF0= github.com/metacubex/sing-mux v0.3.4/go.mod h1:SEJfAuykNj/ozbPqngEYqyggwSr81+L7Nu09NRD5mh4= -github.com/metacubex/sing-quic v0.0.0-20250909002258-06122df8f231 h1:dGvo7UahC/gYBQNBoictr14baJzBjAKUAorP63QFFtg= -github.com/metacubex/sing-quic v0.0.0-20250909002258-06122df8f231/go.mod h1:B60FxaPHjR1SeQB0IiLrgwgvKsaoASfOWdiqhLjmMGA= +github.com/metacubex/sing-quic v0.0.0-20251004051927-c45ee18473bb h1:gxrJmnxuEAel+kh3V7ntqkHjURif0xKDu76nzr/BF5Y= +github.com/metacubex/sing-quic v0.0.0-20251004051927-c45ee18473bb/go.mod h1:JK4+PYUKps6pnlicKjsSUAjAcvIUjhorIjdNZGg930M= github.com/metacubex/sing-shadowsocks v0.2.12 h1:Wqzo8bYXrK5aWqxu/TjlTnYZzAKtKsaFQBdr6IHFaBE= github.com/metacubex/sing-shadowsocks v0.2.12/go.mod h1:2e5EIaw0rxKrm1YTRmiMnDulwbGxH9hAFlrwQLQMQkU= github.com/metacubex/sing-shadowsocks2 v0.2.7 h1:hSuuc0YpsfiqYqt1o+fP4m34BQz4e6wVj3PPBVhor3A= @@ -219,7 +219,6 @@ gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec/go.mod h1:BZ1RAo go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs= go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8= go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU= -go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M= go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= diff --git a/transport/hysteria/congestion/brutal.go b/transport/hysteria/congestion/brutal.go index 601949de..737bc1fb 100644 --- a/transport/hysteria/congestion/brutal.go +++ b/transport/hysteria/congestion/brutal.go @@ -2,6 +2,8 @@ package congestion import ( "github.com/metacubex/quic-go/congestion" + "github.com/metacubex/quic-go/monotime" + "time" ) @@ -47,11 +49,11 @@ func (b *BrutalSender) SetRTTStatsProvider(rttStats congestion.RTTStatsProvider) b.rttStats = rttStats } -func (b *BrutalSender) TimeUntilSend(bytesInFlight congestion.ByteCount) time.Time { +func (b *BrutalSender) TimeUntilSend(bytesInFlight congestion.ByteCount) monotime.Time { return b.pacer.TimeUntilSend() } -func (b *BrutalSender) HasPacingBudget(now time.Time) bool { +func (b *BrutalSender) HasPacingBudget(now monotime.Time) bool { return b.pacer.Budget(now) >= b.maxDatagramSize } @@ -67,13 +69,13 @@ func (b *BrutalSender) GetCongestionWindow() congestion.ByteCount { return congestion.ByteCount(float64(b.bps) * rtt.Seconds() * 1.5 / b.ackRate) } -func (b *BrutalSender) OnPacketSent(sentTime time.Time, bytesInFlight congestion.ByteCount, +func (b *BrutalSender) OnPacketSent(sentTime monotime.Time, bytesInFlight congestion.ByteCount, packetNumber congestion.PacketNumber, bytes congestion.ByteCount, isRetransmittable bool) { b.pacer.SentPacket(sentTime, bytes) } func (b *BrutalSender) OnPacketAcked(number congestion.PacketNumber, ackedBytes congestion.ByteCount, - priorInFlight congestion.ByteCount, eventTime time.Time) { + priorInFlight congestion.ByteCount, eventTime monotime.Time) { // Stub } @@ -82,8 +84,8 @@ func (b *BrutalSender) OnCongestionEvent(number congestion.PacketNumber, lostByt // Stub } -func (b *BrutalSender) OnCongestionEventEx(priorInFlight congestion.ByteCount, eventTime time.Time, ackedPackets []congestion.AckedPacketInfo, lostPackets []congestion.LostPacketInfo) { - currentTimestamp := eventTime.Unix() +func (b *BrutalSender) OnCongestionEventEx(priorInFlight congestion.ByteCount, eventTime monotime.Time, ackedPackets []congestion.AckedPacketInfo, lostPackets []congestion.LostPacketInfo) { + currentTimestamp := int64(eventTime) slot := currentTimestamp % pktInfoSlotCount if b.pktInfoSlots[slot].Timestamp == currentTimestamp { b.pktInfoSlots[slot].LossCount += uint64(len(lostPackets)) diff --git a/transport/hysteria/congestion/pacer.go b/transport/hysteria/congestion/pacer.go index 2dff5300..83c93228 100644 --- a/transport/hysteria/congestion/pacer.go +++ b/transport/hysteria/congestion/pacer.go @@ -2,6 +2,8 @@ package congestion import ( "github.com/metacubex/quic-go/congestion" + "github.com/metacubex/quic-go/monotime" + "math" "time" ) @@ -15,7 +17,7 @@ const ( type pacer struct { budgetAtLastSent congestion.ByteCount maxDatagramSize congestion.ByteCount - lastSentTime time.Time + lastSentTime monotime.Time getBandwidth func() congestion.ByteCount // in bytes/s } @@ -28,7 +30,7 @@ func newPacer(getBandwidth func() congestion.ByteCount) *pacer { return p } -func (p *pacer) SentPacket(sendTime time.Time, size congestion.ByteCount) { +func (p *pacer) SentPacket(sendTime monotime.Time, size congestion.ByteCount) { budget := p.Budget(sendTime) if size > budget { p.budgetAtLastSent = 0 @@ -38,7 +40,7 @@ func (p *pacer) SentPacket(sendTime time.Time, size congestion.ByteCount) { p.lastSentTime = sendTime } -func (p *pacer) Budget(now time.Time) congestion.ByteCount { +func (p *pacer) Budget(now monotime.Time) congestion.ByteCount { if p.lastSentTime.IsZero() { return p.maxBurstSize() } @@ -54,10 +56,10 @@ func (p *pacer) maxBurstSize() congestion.ByteCount { } // TimeUntilSend returns when the next packet should be sent. -// It returns the zero value of time.Time if a packet can be sent immediately. -func (p *pacer) TimeUntilSend() time.Time { +// It returns the zero value of monotime.Time if a packet can be sent immediately. +func (p *pacer) TimeUntilSend() monotime.Time { if p.budgetAtLastSent >= p.maxDatagramSize { - return time.Time{} + return monotime.Time(0) } return p.lastSentTime.Add(maxDuration( minPacingDelay, diff --git a/transport/tuic/congestion/bandwidth_sampler.go b/transport/tuic/congestion/bandwidth_sampler.go index e415fe7a..ed7ce072 100644 --- a/transport/tuic/congestion/bandwidth_sampler.go +++ b/transport/tuic/congestion/bandwidth_sampler.go @@ -5,6 +5,7 @@ import ( "time" "github.com/metacubex/quic-go/congestion" + "github.com/metacubex/quic-go/monotime" ) var ( @@ -36,7 +37,7 @@ type SendTimeState struct { type ConnectionStateOnSentPacket struct { packetNumber congestion.PacketNumber // Time at which the packet is sent. - sendTime time.Time + sendTime monotime.Time // Size of the packet. size congestion.ByteCount // The value of |totalBytesSentAtLastAckedPacket| at the time the @@ -44,10 +45,10 @@ type ConnectionStateOnSentPacket struct { totalBytesSentAtLastAckedPacket congestion.ByteCount // The value of |lastAckedPacketSentTime| at the time the packet was // sent. - lastAckedPacketSentTime time.Time + lastAckedPacketSentTime monotime.Time // The value of |lastAckedPacketAckTime| at the time the packet was // sent. - lastAckedPacketAckTime time.Time + lastAckedPacketAckTime monotime.Time // Send time states that are returned to the congestion controller when the // packet is acked or lost. sendTimeState SendTimeState @@ -166,9 +167,9 @@ type BandwidthSampler struct { totalBytesSentAtLastAckedPacket congestion.ByteCount // The time at which the last acknowledged packet was sent. Set to // QuicTime::Zero() if no valid timestamp is available. - lastAckedPacketSentTime time.Time + lastAckedPacketSentTime monotime.Time // The time at which the most recent packet was acknowledged. - lastAckedPacketAckTime time.Time + lastAckedPacketAckTime monotime.Time // The most recently sent packet. lastSendPacket congestion.PacketNumber // Indicates whether the bandwidth sampler is currently in an app-limited @@ -194,7 +195,7 @@ func NewBandwidthSampler() *BandwidthSampler { // packets are sent in order. The information about the packet will not be // released from the sampler until it the packet is either acknowledged or // declared lost. -func (s *BandwidthSampler) OnPacketSent(sentTime time.Time, lastSentPacket congestion.PacketNumber, sentBytes, bytesInFlight congestion.ByteCount, hasRetransmittableData bool) { +func (s *BandwidthSampler) OnPacketSent(sentTime monotime.Time, lastSentPacket congestion.PacketNumber, sentBytes, bytesInFlight congestion.ByteCount, hasRetransmittableData bool) { s.lastSendPacket = lastSentPacket if !hasRetransmittableData { @@ -224,7 +225,7 @@ func (s *BandwidthSampler) OnPacketSent(sentTime time.Time, lastSentPacket conge // OnPacketAcked Notifies the sampler that the |lastAckedPacket| is acknowledged. Returns a // bandwidth sample. If no bandwidth sample is available, // QuicBandwidth::Zero() is returned. -func (s *BandwidthSampler) OnPacketAcked(ackTime time.Time, lastAckedPacket congestion.PacketNumber) *BandwidthSample { +func (s *BandwidthSampler) OnPacketAcked(ackTime monotime.Time, lastAckedPacket congestion.PacketNumber) *BandwidthSample { sentPacketState := s.connectionStats.Get(lastAckedPacket) if sentPacketState == nil { return NewBandwidthSample() @@ -238,7 +239,7 @@ func (s *BandwidthSampler) OnPacketAcked(ackTime time.Time, lastAckedPacket cong // onPacketAckedInner Handles the actual bandwidth calculations, whereas the outer method handles // retrieving and removing |sentPacket|. -func (s *BandwidthSampler) onPacketAckedInner(ackTime time.Time, lastAckedPacket congestion.PacketNumber, sentPacket *ConnectionStateOnSentPacket) *BandwidthSample { +func (s *BandwidthSampler) onPacketAckedInner(ackTime monotime.Time, lastAckedPacket congestion.PacketNumber, sentPacket *ConnectionStateOnSentPacket) *BandwidthSample { s.totalBytesAcked += sentPacket.size s.totalBytesSentAtLastAckedPacket = sentPacket.sendTimeState.totalBytesSent @@ -336,7 +337,7 @@ type ConnectionStates struct { stats map[congestion.PacketNumber]*ConnectionStateOnSentPacket } -func (s *ConnectionStates) Insert(packetNumber congestion.PacketNumber, sentTime time.Time, bytes congestion.ByteCount, sampler *BandwidthSampler) bool { +func (s *ConnectionStates) Insert(packetNumber congestion.PacketNumber, sentTime monotime.Time, bytes congestion.ByteCount, sampler *BandwidthSampler) bool { if _, ok := s.stats[packetNumber]; ok { return false } @@ -357,7 +358,7 @@ func (s *ConnectionStates) Remove(packetNumber congestion.PacketNumber) (bool, * return ok, state } -func NewConnectionStateOnSentPacket(packetNumber congestion.PacketNumber, sentTime time.Time, bytes congestion.ByteCount, sampler *BandwidthSampler) *ConnectionStateOnSentPacket { +func NewConnectionStateOnSentPacket(packetNumber congestion.PacketNumber, sentTime monotime.Time, bytes congestion.ByteCount, sampler *BandwidthSampler) *ConnectionStateOnSentPacket { return &ConnectionStateOnSentPacket{ packetNumber: packetNumber, sendTime: sentTime, diff --git a/transport/tuic/congestion/bbr_sender.go b/transport/tuic/congestion/bbr_sender.go index 93f90ba8..7f41d5be 100644 --- a/transport/tuic/congestion/bbr_sender.go +++ b/transport/tuic/congestion/bbr_sender.go @@ -9,6 +9,7 @@ import ( "github.com/metacubex/quic-go" "github.com/metacubex/quic-go/congestion" + "github.com/metacubex/quic-go/monotime" "github.com/metacubex/randv2" ) @@ -121,13 +122,13 @@ type bbrSender struct { // Tracks the maximum number of bytes acked faster than the sending rate. maxAckHeight *WindowedFilter // The time this aggregation started and the number of bytes acked during it. - aggregationEpochStartTime time.Time + aggregationEpochStartTime monotime.Time aggregationEpochBytes congestion.ByteCount // Minimum RTT estimate. Automatically expires within 10 seconds (and // triggers PROBE_RTT mode) if no new value is sampled during that period. minRtt time.Duration // The time at which the current value of |min_rtt_| was assigned. - minRttTimestamp time.Time + minRttTimestamp monotime.Time // The maximum allowed number of bytes in flight. congestionWindow congestion.ByteCount // The initial value of the |congestion_window_|. @@ -160,7 +161,7 @@ type bbrSender struct { // pacing gain cycle. cycleCurrentOffset int // The time at which the last pacing gain cycle was started. - lastCycleStart time.Time + lastCycleStart monotime.Time // Indicates whether the connection has reached the full bandwidth mode. isAtFullBandwidth bool // Number of rounds during which there was no significant bandwidth increase. @@ -172,7 +173,7 @@ type bbrSender struct { // Time at which PROBE_RTT has to be exited. Setting it to zero indicates // that the time is yet unknown as the number of packets in flight has not // reached the required value. - exitProbeRttAt time.Time + exitProbeRttAt monotime.Time // Indicates whether a round-trip has passed since PROBE_RTT became active. probeRttRoundPassed bool // Indicates whether the most recent bandwidth sample was marked as @@ -277,12 +278,12 @@ func (b *bbrSender) GetBytesInFlight() congestion.ByteCount { } // TimeUntilSend returns when the next packet should be sent. -func (b *bbrSender) TimeUntilSend(bytesInFlight congestion.ByteCount) time.Time { +func (b *bbrSender) TimeUntilSend(bytesInFlight congestion.ByteCount) monotime.Time { b.bytesInFlight = bytesInFlight return b.pacer.TimeUntilSend() } -func (b *bbrSender) HasPacingBudget(now time.Time) bool { +func (b *bbrSender) HasPacingBudget(now monotime.Time) bool { return b.pacer.Budget(now) >= b.maxDatagramSize } @@ -298,7 +299,7 @@ func (b *bbrSender) SetMaxDatagramSize(s congestion.ByteCount) { b.pacer.SetMaxDatagramSize(s) } -func (b *bbrSender) OnPacketSent(sentTime time.Time, bytesInFlight congestion.ByteCount, packetNumber congestion.PacketNumber, bytes congestion.ByteCount, isRetransmittable bool) { +func (b *bbrSender) OnPacketSent(sentTime monotime.Time, bytesInFlight congestion.ByteCount, packetNumber congestion.PacketNumber, bytes congestion.ByteCount, isRetransmittable bool) { b.pacer.SentPacket(sentTime, bytes) b.lastSendPacket = packetNumber @@ -335,7 +336,7 @@ func (b *bbrSender) MaybeExitSlowStart() { } -func (b *bbrSender) OnPacketAcked(number congestion.PacketNumber, ackedBytes congestion.ByteCount, priorInFlight congestion.ByteCount, eventTime time.Time) { +func (b *bbrSender) OnPacketAcked(number congestion.PacketNumber, ackedBytes congestion.ByteCount, priorInFlight congestion.ByteCount, eventTime monotime.Time) { // Stub } @@ -343,7 +344,7 @@ func (b *bbrSender) OnCongestionEvent(number congestion.PacketNumber, lostBytes // Stub } -func (b *bbrSender) OnCongestionEventEx(priorInFlight congestion.ByteCount, eventTime time.Time, ackedPackets []congestion.AckedPacketInfo, lostPackets []congestion.LostPacketInfo) { +func (b *bbrSender) OnCongestionEventEx(priorInFlight congestion.ByteCount, eventTime monotime.Time, ackedPackets []congestion.AckedPacketInfo, lostPackets []congestion.LostPacketInfo) { totalBytesAckedBefore := b.sampler.totalBytesAcked isRoundStart, minRttExpired := false, false @@ -490,7 +491,7 @@ func (b *bbrSender) UpdateRoundTripCounter(lastAckedPacket congestion.PacketNumb return false } -func (b *bbrSender) UpdateBandwidthAndMinRtt(now time.Time, ackedPackets []congestion.AckedPacketInfo) bool { +func (b *bbrSender) UpdateBandwidthAndMinRtt(now monotime.Time, ackedPackets []congestion.AckedPacketInfo) bool { sampleMinRtt := InfiniteRTT for _, packet := range ackedPackets { @@ -610,7 +611,7 @@ func (b *bbrSender) UpdateRecoveryState(hasLosses, isRoundStart bool) { } } -func (b *bbrSender) UpdateAckAggregationBytes(ackTime time.Time, ackedBytes congestion.ByteCount) congestion.ByteCount { +func (b *bbrSender) UpdateAckAggregationBytes(ackTime monotime.Time, ackedBytes congestion.ByteCount) congestion.ByteCount { // Compute how many bytes are expected to be delivered, assuming max bandwidth // is correct. expectedAckedBytes := congestion.ByteCount(b.maxBandwidth.GetBest()) * @@ -630,7 +631,7 @@ func (b *bbrSender) UpdateAckAggregationBytes(ackTime time.Time, ackedBytes cong return b.aggregationEpochBytes - expectedAckedBytes } -func (b *bbrSender) UpdateGainCyclePhase(now time.Time, priorInFlight congestion.ByteCount, hasLosses bool) { +func (b *bbrSender) UpdateGainCyclePhase(now monotime.Time, priorInFlight congestion.ByteCount, hasLosses bool) { bytesInFlight := b.GetBytesInFlight() // In most cases, the cycle is advanced after an RTT passes. shouldAdvanceGainCycling := now.Sub(b.lastCycleStart) > b.GetMinRtt() @@ -697,7 +698,7 @@ func (b *bbrSender) CheckIfFullBandwidthReached() { } } -func (b *bbrSender) MaybeExitStartupOrDrain(now time.Time) { +func (b *bbrSender) MaybeExitStartupOrDrain(now monotime.Time) { if b.mode == STARTUP && b.isAtFullBandwidth { b.OnExitStartup(now) b.mode = DRAIN @@ -709,7 +710,7 @@ func (b *bbrSender) MaybeExitStartupOrDrain(now time.Time) { } } -func (b *bbrSender) EnterProbeBandwidthMode(now time.Time) { +func (b *bbrSender) EnterProbeBandwidthMode(now monotime.Time) { b.mode = PROBE_BW b.congestionWindowGain = b.congestionWindowGainConst @@ -725,7 +726,7 @@ func (b *bbrSender) EnterProbeBandwidthMode(now time.Time) { b.pacingGain = PacingGain[b.cycleCurrentOffset] } -func (b *bbrSender) MaybeEnterOrExitProbeRtt(now time.Time, isRoundStart, minRttExpired bool) { +func (b *bbrSender) MaybeEnterOrExitProbeRtt(now monotime.Time, isRoundStart, minRttExpired bool) { if minRttExpired && !b.exitingQuiescence && b.mode != PROBE_RTT { if b.InSlowStart() { b.OnExitStartup(now) @@ -734,7 +735,7 @@ func (b *bbrSender) MaybeEnterOrExitProbeRtt(now time.Time, isRoundStart, minRtt b.pacingGain = 1.0 // Do not decide on the time to exit PROBE_RTT until the |bytes_in_flight| // is at the target small value. - b.exitProbeRttAt = time.Time{} + b.exitProbeRttAt = monotime.Time(0) } if b.mode == PROBE_RTT { @@ -773,7 +774,7 @@ func (b *bbrSender) ProbeRttCongestionWindow() congestion.ByteCount { } } -func (b *bbrSender) EnterStartupMode(now time.Time) { +func (b *bbrSender) EnterStartupMode(now monotime.Time) { // if b.rttStats != nil { // TODO: slow start. // } @@ -782,7 +783,7 @@ func (b *bbrSender) EnterStartupMode(now time.Time) { b.congestionWindowGain = b.highCwndGain } -func (b *bbrSender) OnExitStartup(now time.Time) { +func (b *bbrSender) OnExitStartup(now monotime.Time) { if b.rttStats == nil { return } diff --git a/transport/tuic/congestion/cubic.go b/transport/tuic/congestion/cubic.go index a9bed43a..35c3f0cb 100644 --- a/transport/tuic/congestion/cubic.go +++ b/transport/tuic/congestion/cubic.go @@ -5,6 +5,7 @@ import ( "time" "github.com/metacubex/quic-go/congestion" + "github.com/metacubex/quic-go/monotime" ) // This cubic implementation is based on the one found in Chromiums's QUIC @@ -42,7 +43,7 @@ type Cubic struct { numConnections int // Time when this cycle started, after last loss event. - epoch time.Time + epoch monotime.Time // Max congestion window used just before last loss event. // Note: to improve fairness to other streams an additional back off is @@ -77,7 +78,7 @@ func NewCubic(clock Clock) *Cubic { // Reset is called after a timeout to reset the cubic state func (c *Cubic) Reset() { - c.epoch = time.Time{} + c.epoch = monotime.Time(0) c.lastMaxCongestionWindow = 0 c.ackedBytesCount = 0 c.estimatedTCPcongestionWindow = 0 @@ -121,7 +122,7 @@ func (c *Cubic) OnApplicationLimited() { // in such a period. This reset effectively freezes congestion window growth // through application-limited periods and allows Cubic growth to continue // when the entire window is being used. - c.epoch = time.Time{} + c.epoch = monotime.Time(0) } // CongestionWindowAfterPacketLoss computes a new congestion window to use after @@ -135,7 +136,7 @@ func (c *Cubic) CongestionWindowAfterPacketLoss(currentCongestionWindow congesti } else { c.lastMaxCongestionWindow = currentCongestionWindow } - c.epoch = time.Time{} // Reset time. + c.epoch = monotime.Time(0) // Reset time. return congestion.ByteCount(float32(currentCongestionWindow) * c.beta()) } @@ -147,7 +148,7 @@ func (c *Cubic) CongestionWindowAfterAck( ackedBytes congestion.ByteCount, currentCongestionWindow congestion.ByteCount, delayMin time.Duration, - eventTime time.Time, + eventTime monotime.Time, ) congestion.ByteCount { c.ackedBytesCount += ackedBytes diff --git a/transport/tuic/congestion/cubic_sender.go b/transport/tuic/congestion/cubic_sender.go index f544cd74..dcf63a0a 100644 --- a/transport/tuic/congestion/cubic_sender.go +++ b/transport/tuic/congestion/cubic_sender.go @@ -2,9 +2,9 @@ package congestion import ( "fmt" - "time" "github.com/metacubex/quic-go/congestion" + "github.com/metacubex/quic-go/monotime" ) const ( @@ -103,11 +103,11 @@ func (c *cubicSender) SetRTTStatsProvider(provider congestion.RTTStatsProvider) } // TimeUntilSend returns when the next packet should be sent. -func (c *cubicSender) TimeUntilSend(_ congestion.ByteCount) time.Time { +func (c *cubicSender) TimeUntilSend(_ congestion.ByteCount) monotime.Time { return c.pacer.TimeUntilSend() } -func (c *cubicSender) HasPacingBudget(now time.Time) bool { +func (c *cubicSender) HasPacingBudget(now monotime.Time) bool { return c.pacer.Budget(now) >= c.maxDatagramSize } @@ -120,7 +120,7 @@ func (c *cubicSender) minCongestionWindow() congestion.ByteCount { } func (c *cubicSender) OnPacketSent( - sentTime time.Time, + sentTime monotime.Time, _ congestion.ByteCount, packetNumber congestion.PacketNumber, bytes congestion.ByteCount, @@ -162,7 +162,7 @@ func (c *cubicSender) OnPacketAcked( ackedPacketNumber congestion.PacketNumber, ackedBytes congestion.ByteCount, priorInFlight congestion.ByteCount, - eventTime time.Time, + eventTime monotime.Time, ) { c.largestAckedPacketNumber = Max(ackedPacketNumber, c.largestAckedPacketNumber) if c.InRecovery() { @@ -197,7 +197,7 @@ func (c *cubicSender) OnCongestionEvent(packetNumber congestion.PacketNumber, lo c.numAckedPackets = 0 } -func (b *cubicSender) OnCongestionEventEx(priorInFlight congestion.ByteCount, eventTime time.Time, ackedPackets []congestion.AckedPacketInfo, lostPackets []congestion.LostPacketInfo) { +func (b *cubicSender) OnCongestionEventEx(priorInFlight congestion.ByteCount, eventTime monotime.Time, ackedPackets []congestion.AckedPacketInfo, lostPackets []congestion.LostPacketInfo) { // Stub } @@ -207,7 +207,7 @@ func (c *cubicSender) maybeIncreaseCwnd( _ congestion.PacketNumber, ackedBytes congestion.ByteCount, priorInFlight congestion.ByteCount, - eventTime time.Time, + eventTime monotime.Time, ) { // Do not increase the congestion window unless the sender is close to using // the current window. diff --git a/transport/tuic/congestion/pacer.go b/transport/tuic/congestion/pacer.go index f60ef5fe..598f9dac 100644 --- a/transport/tuic/congestion/pacer.go +++ b/transport/tuic/congestion/pacer.go @@ -5,6 +5,7 @@ import ( "time" "github.com/metacubex/quic-go/congestion" + "github.com/metacubex/quic-go/monotime" ) const initialMaxDatagramSize = congestion.ByteCount(1252) @@ -16,7 +17,7 @@ const maxBurstSizePackets = 10 type pacer struct { budgetAtLastSent congestion.ByteCount maxDatagramSize congestion.ByteCount - lastSentTime time.Time + lastSentTime monotime.Time getAdjustedBandwidth func() uint64 // in bytes/s } @@ -37,7 +38,7 @@ func newPacer(getBandwidth func() Bandwidth) *pacer { return p } -func (p *pacer) SentPacket(sendTime time.Time, size congestion.ByteCount) { +func (p *pacer) SentPacket(sendTime monotime.Time, size congestion.ByteCount) { budget := p.Budget(sendTime) if size > budget { p.budgetAtLastSent = 0 @@ -47,7 +48,7 @@ func (p *pacer) SentPacket(sendTime time.Time, size congestion.ByteCount) { p.lastSentTime = sendTime } -func (p *pacer) Budget(now time.Time) congestion.ByteCount { +func (p *pacer) Budget(now monotime.Time) congestion.ByteCount { if p.lastSentTime.IsZero() { return p.maxBurstSize() } @@ -63,10 +64,10 @@ func (p *pacer) maxBurstSize() congestion.ByteCount { } // TimeUntilSend returns when the next packet should be sent. -// It returns the zero value of time.Time if a packet can be sent immediately. -func (p *pacer) TimeUntilSend() time.Time { +// It returns the zero value of monotime.Time if a packet can be sent immediately. +func (p *pacer) TimeUntilSend() monotime.Time { if p.budgetAtLastSent >= p.maxDatagramSize { - return time.Time{} + return monotime.Time(0) } return p.lastSentTime.Add(Max( MinPacingDelay, diff --git a/transport/tuic/congestion_v2/bandwidth_sampler.go b/transport/tuic/congestion_v2/bandwidth_sampler.go index 9028df64..d546aec5 100644 --- a/transport/tuic/congestion_v2/bandwidth_sampler.go +++ b/transport/tuic/congestion_v2/bandwidth_sampler.go @@ -5,6 +5,7 @@ import ( "time" "github.com/metacubex/quic-go/congestion" + "github.com/metacubex/quic-go/monotime" ) const ( @@ -103,7 +104,7 @@ type maxAckHeightTracker struct { // bandwidth. maxAckHeightFilter *WindowedFilter[extraAckedEvent, roundTripCount] // The time this aggregation started and the number of bytes acked during it. - aggregationEpochStartTime time.Time + aggregationEpochStartTime monotime.Time aggregationEpochBytes congestion.ByteCount // The last sent packet number before the current aggregation epoch started. lastSentPacketNumberBeforeEpoch congestion.PacketNumber @@ -133,7 +134,7 @@ func (m *maxAckHeightTracker) Update( roundTripCount roundTripCount, lastSentPacketNumber congestion.PacketNumber, lastAckedPacketNumber congestion.PacketNumber, - ackTime time.Time, + ackTime monotime.Time, bytesAcked congestion.ByteCount, ) congestion.ByteCount { forceNewEpoch := false @@ -241,7 +242,7 @@ func (m *maxAckHeightTracker) NumAckAggregationEpochs() uint64 { // AckPoint represents a point on the ack line. type ackPoint struct { - ackTime time.Time + ackTime monotime.Time totalBytesAcked congestion.ByteCount } @@ -250,7 +251,7 @@ type recentAckPoints struct { ackPoints [2]ackPoint } -func (r *recentAckPoints) Update(ackTime time.Time, totalBytesAcked congestion.ByteCount) { +func (r *recentAckPoints) Update(ackTime monotime.Time, totalBytesAcked congestion.ByteCount) { if ackTime.Before(r.ackPoints[1].ackTime) { r.ackPoints[1].ackTime = ackTime } else if ackTime.After(r.ackPoints[1].ackTime) { @@ -284,7 +285,7 @@ func (r *recentAckPoints) LessRecentPoint() *ackPoint { // that moment. type connectionStateOnSentPacket struct { // Time at which the packet is sent. - sentTime time.Time + sentTime monotime.Time // Size of the packet. size congestion.ByteCount // The value of |totalBytesSentAtLastAckedPacket| at the time the @@ -292,10 +293,10 @@ type connectionStateOnSentPacket struct { totalBytesSentAtLastAckedPacket congestion.ByteCount // The value of |lastAckedPacketSentTime| at the time the packet was // sent. - lastAckedPacketSentTime time.Time + lastAckedPacketSentTime monotime.Time // The value of |lastAckedPacketAckTime| at the time the packet was // sent. - lastAckedPacketAckTime time.Time + lastAckedPacketAckTime monotime.Time // Send time states that are returned to the congestion controller when the // packet is acked or lost. sendTimeState sendTimeState @@ -305,7 +306,7 @@ type connectionStateOnSentPacket struct { // sampler. // |bytes_in_flight| is the bytes in flight right after the packet is sent. func newConnectionStateOnSentPacket( - sentTime time.Time, + sentTime monotime.Time, size congestion.ByteCount, bytesInFlight congestion.ByteCount, sampler *bandwidthSampler, @@ -456,10 +457,10 @@ type bandwidthSampler struct { // The time at which the last acknowledged packet was sent. Set to // QuicTime::Zero() if no valid timestamp is available. - lastAckedPacketSentTime time.Time + lastAckedPacketSentTime monotime.Time // The time at which the most recent packet was acknowledged. - lastAckedPacketAckTime time.Time + lastAckedPacketAckTime monotime.Time // The most recently sent packet. lastSentPacket congestion.PacketNumber @@ -551,7 +552,7 @@ func (b *bandwidthSampler) IsOverestimateAvoidanceEnabled() bool { } func (b *bandwidthSampler) OnPacketSent( - sentTime time.Time, + sentTime monotime.Time, packetNumber congestion.PacketNumber, bytes congestion.ByteCount, bytesInFlight congestion.ByteCount, @@ -595,7 +596,7 @@ func (b *bandwidthSampler) OnPacketSent( } func (b *bandwidthSampler) OnCongestionEvent( - ackTime time.Time, + ackTime monotime.Time, ackedPackets []congestion.AckedPacketInfo, lostPackets []congestion.LostPacketInfo, maxBandwidth Bandwidth, @@ -758,7 +759,7 @@ func (b *bandwidthSampler) chooseA0Point(totalBytesAcked congestion.ByteCount, a return true } -func (b *bandwidthSampler) onPacketAcknowledged(ackTime time.Time, packetNumber congestion.PacketNumber) bandwidthSample { +func (b *bandwidthSampler) onPacketAcknowledged(ackTime monotime.Time, packetNumber congestion.PacketNumber) bandwidthSample { sample := newBandwidthSample() b.lastAckedPacket = packetNumber sentPacketPointer := b.connectionStateMap.GetEntry(packetNumber) diff --git a/transport/tuic/congestion_v2/bbr_sender.go b/transport/tuic/congestion_v2/bbr_sender.go index a515c2cc..6020ab39 100644 --- a/transport/tuic/congestion_v2/bbr_sender.go +++ b/transport/tuic/congestion_v2/bbr_sender.go @@ -8,6 +8,7 @@ import ( "github.com/metacubex/quic-go" "github.com/metacubex/quic-go/congestion" + "github.com/metacubex/quic-go/monotime" "github.com/metacubex/randv2" ) @@ -127,7 +128,7 @@ type bbrSender struct { // triggers PROBE_RTT mode) if no new value is sampled during that period. minRtt time.Duration // The time at which the current value of |min_rtt_| was assigned. - minRttTimestamp time.Time + minRttTimestamp monotime.Time // The maximum allowed number of bytes in flight. congestionWindow congestion.ByteCount @@ -168,7 +169,7 @@ type bbrSender struct { // pacing gain cycle. cycleCurrentOffset int // The time at which the last pacing gain cycle was started. - lastCycleStart time.Time + lastCycleStart monotime.Time // Indicates whether the connection has reached the full bandwidth mode. isAtFullBandwidth bool @@ -183,7 +184,7 @@ type bbrSender struct { // Time at which PROBE_RTT has to be exited. Setting it to zero indicates // that the time is yet unknown as the number of packets in flight has not // reached the required value. - exitProbeRttAt time.Time + exitProbeRttAt monotime.Time // Indicates whether a round-trip has passed since PROBE_RTT became active. probeRttRoundPassed bool @@ -307,18 +308,18 @@ func (b *bbrSender) SetRTTStatsProvider(provider congestion.RTTStatsProvider) { } // TimeUntilSend implements the SendAlgorithm interface. -func (b *bbrSender) TimeUntilSend(bytesInFlight congestion.ByteCount) time.Time { +func (b *bbrSender) TimeUntilSend(bytesInFlight congestion.ByteCount) monotime.Time { return b.pacer.TimeUntilSend() } // HasPacingBudget implements the SendAlgorithm interface. -func (b *bbrSender) HasPacingBudget(now time.Time) bool { +func (b *bbrSender) HasPacingBudget(now monotime.Time) bool { return b.pacer.Budget(now) >= b.maxDatagramSize } // OnPacketSent implements the SendAlgorithm interface. func (b *bbrSender) OnPacketSent( - sentTime time.Time, + sentTime monotime.Time, bytesInFlight congestion.ByteCount, packetNumber congestion.PacketNumber, bytes congestion.ByteCount, @@ -349,7 +350,7 @@ func (b *bbrSender) MaybeExitSlowStart() { } // OnPacketAcked implements the SendAlgorithm interface. -func (b *bbrSender) OnPacketAcked(number congestion.PacketNumber, ackedBytes, priorInFlight congestion.ByteCount, eventTime time.Time) { +func (b *bbrSender) OnPacketAcked(number congestion.PacketNumber, ackedBytes, priorInFlight congestion.ByteCount, eventTime monotime.Time) { // Do nothing. } @@ -403,7 +404,7 @@ func (b *bbrSender) OnCongestionEvent(number congestion.PacketNumber, lostBytes, // Do nothing. } -func (b *bbrSender) OnCongestionEventEx(priorInFlight congestion.ByteCount, eventTime time.Time, ackedPackets []congestion.AckedPacketInfo, lostPackets []congestion.LostPacketInfo) { +func (b *bbrSender) OnCongestionEventEx(priorInFlight congestion.ByteCount, eventTime monotime.Time, ackedPackets []congestion.AckedPacketInfo, lostPackets []congestion.LostPacketInfo) { totalBytesAckedBefore := b.sampler.TotalBytesAcked() totalBytesLostBefore := b.sampler.TotalBytesLost() @@ -592,7 +593,7 @@ func (b *bbrSender) probeRttCongestionWindow() congestion.ByteCount { return b.minCongestionWindow } -func (b *bbrSender) maybeUpdateMinRtt(now time.Time, sampleMinRtt time.Duration) bool { +func (b *bbrSender) maybeUpdateMinRtt(now monotime.Time, sampleMinRtt time.Duration) bool { // Do not expire min_rtt if none was ever available. minRttExpired := b.minRtt != 0 && now.After(b.minRttTimestamp.Add(minRttExpiry)) if minRttExpired || sampleMinRtt < b.minRtt || b.minRtt == 0 { @@ -604,7 +605,7 @@ func (b *bbrSender) maybeUpdateMinRtt(now time.Time, sampleMinRtt time.Duration) } // Enters the STARTUP mode. -func (b *bbrSender) enterStartupMode(now time.Time) { +func (b *bbrSender) enterStartupMode(now monotime.Time) { b.mode = bbrModeStartup // b.maybeTraceStateChange(logging.CongestionStateStartup) b.pacingGain = b.highGain @@ -612,7 +613,7 @@ func (b *bbrSender) enterStartupMode(now time.Time) { } // Enters the PROBE_BW mode. -func (b *bbrSender) enterProbeBandwidthMode(now time.Time) { +func (b *bbrSender) enterProbeBandwidthMode(now monotime.Time) { b.mode = bbrModeProbeBw // b.maybeTraceStateChange(logging.CongestionStateProbeBw) b.congestionWindowGain = b.congestionWindowGainConstant @@ -641,7 +642,7 @@ func (b *bbrSender) updateRoundTripCounter(lastAckedPacket congestion.PacketNumb } // Updates the current gain used in PROBE_BW mode. -func (b *bbrSender) updateGainCyclePhase(now time.Time, priorInFlight congestion.ByteCount, hasLosses bool) { +func (b *bbrSender) updateGainCyclePhase(now monotime.Time, priorInFlight congestion.ByteCount, hasLosses bool) { // In most cases, the cycle is advanced after an RTT passes. shouldAdvanceGainCycling := now.After(b.lastCycleStart.Add(b.getMinRtt())) // If the pacing gain is above 1.0, the connection is trying to probe the @@ -713,7 +714,7 @@ func (b *bbrSender) maybeAppLimited(bytesInFlight congestion.ByteCount) { // Transitions from STARTUP to DRAIN and from DRAIN to PROBE_BW if // appropriate. -func (b *bbrSender) maybeExitStartupOrDrain(now time.Time) { +func (b *bbrSender) maybeExitStartupOrDrain(now monotime.Time) { if b.mode == bbrModeStartup && b.isAtFullBandwidth { b.mode = bbrModeDrain // b.maybeTraceStateChange(logging.CongestionStateDrain) @@ -726,14 +727,14 @@ func (b *bbrSender) maybeExitStartupOrDrain(now time.Time) { } // Decides whether to enter or exit PROBE_RTT. -func (b *bbrSender) maybeEnterOrExitProbeRtt(now time.Time, isRoundStart, minRttExpired bool) { +func (b *bbrSender) maybeEnterOrExitProbeRtt(now monotime.Time, isRoundStart, minRttExpired bool) { if minRttExpired && !b.exitingQuiescence && b.mode != bbrModeProbeRtt { b.mode = bbrModeProbeRtt // b.maybeTraceStateChange(logging.CongestionStateProbRtt) b.pacingGain = 1.0 // Do not decide on the time to exit PROBE_RTT until the |bytes_in_flight| // is at the target small value. - b.exitProbeRttAt = time.Time{} + b.exitProbeRttAt = monotime.Time(0) } if b.mode == bbrModeProbeRtt { diff --git a/transport/tuic/congestion_v2/clock.go b/transport/tuic/congestion_v2/clock.go index 405fae70..e6ea35db 100644 --- a/transport/tuic/congestion_v2/clock.go +++ b/transport/tuic/congestion_v2/clock.go @@ -1,10 +1,12 @@ package congestion -import "time" +import ( + "github.com/metacubex/quic-go/monotime" +) // A Clock returns the current time type Clock interface { - Now() time.Time + Now() monotime.Time } // DefaultClock implements the Clock interface using the Go stdlib clock. @@ -13,6 +15,6 @@ type DefaultClock struct{} var _ Clock = DefaultClock{} // Now gets the current time -func (DefaultClock) Now() time.Time { - return time.Now() +func (DefaultClock) Now() monotime.Time { + return monotime.Now() } diff --git a/transport/tuic/congestion_v2/pacer.go b/transport/tuic/congestion_v2/pacer.go index 174b3dbe..6158bf58 100644 --- a/transport/tuic/congestion_v2/pacer.go +++ b/transport/tuic/congestion_v2/pacer.go @@ -5,6 +5,7 @@ import ( "time" "github.com/metacubex/quic-go/congestion" + "github.com/metacubex/quic-go/monotime" ) const ( @@ -15,7 +16,7 @@ const ( type Pacer struct { budgetAtLastSent congestion.ByteCount maxDatagramSize congestion.ByteCount - lastSentTime time.Time + lastSentTime monotime.Time getBandwidth func() congestion.ByteCount // in bytes/s } @@ -28,7 +29,7 @@ func NewPacer(getBandwidth func() congestion.ByteCount) *Pacer { return p } -func (p *Pacer) SentPacket(sendTime time.Time, size congestion.ByteCount) { +func (p *Pacer) SentPacket(sendTime monotime.Time, size congestion.ByteCount) { budget := p.Budget(sendTime) if size > budget { p.budgetAtLastSent = 0 @@ -38,7 +39,7 @@ func (p *Pacer) SentPacket(sendTime time.Time, size congestion.ByteCount) { p.lastSentTime = sendTime } -func (p *Pacer) Budget(now time.Time) congestion.ByteCount { +func (p *Pacer) Budget(now monotime.Time) congestion.ByteCount { if p.lastSentTime.IsZero() { return p.maxBurstSize() } @@ -57,10 +58,10 @@ func (p *Pacer) maxBurstSize() congestion.ByteCount { } // TimeUntilSend returns when the next packet should be sent. -// It returns the zero value of time.Time if a packet can be sent immediately. -func (p *Pacer) TimeUntilSend() time.Time { +// It returns the zero value of monotime.Time if a packet can be sent immediately. +func (p *Pacer) TimeUntilSend() monotime.Time { if p.budgetAtLastSent >= p.maxDatagramSize { - return time.Time{} + return monotime.Time(0) } return p.lastSentTime.Add(Max( congestion.MinPacingDelay,