2019-01-16 05:48:15 -05:00
package ackhandler
import (
"time"
2019-01-17 09:33:18 -05:00
"v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/congestion"
"v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol"
"v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/utils"
"v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/wire"
2019-01-16 05:48:15 -05:00
)
type receivedPacketTracker struct {
largestObserved protocol . PacketNumber
ignoreBelow protocol . PacketNumber
largestObservedReceivedTime time . Time
packetHistory * receivedPacketHistory
ackSendDelay time . Duration
rttStats * congestion . RTTStats
packetsReceivedSinceLastAck int
retransmittablePacketsReceivedSinceLastAck int
ackQueued bool
ackAlarm time . Time
lastAck * wire . AckFrame
logger utils . Logger
version protocol . VersionNumber
}
func newReceivedPacketTracker (
rttStats * congestion . RTTStats ,
logger utils . Logger ,
version protocol . VersionNumber ,
) * receivedPacketTracker {
return & receivedPacketTracker {
packetHistory : newReceivedPacketHistory ( ) ,
ackSendDelay : ackSendDelay ,
rttStats : rttStats ,
logger : logger ,
version : version ,
}
}
func ( h * receivedPacketTracker ) ReceivedPacket ( packetNumber protocol . PacketNumber , rcvTime time . Time , shouldInstigateAck bool ) error {
if packetNumber < h . ignoreBelow {
return nil
}
isMissing := h . isMissing ( packetNumber )
if packetNumber >= h . largestObserved {
h . largestObserved = packetNumber
h . largestObservedReceivedTime = rcvTime
}
if err := h . packetHistory . ReceivedPacket ( packetNumber ) ; err != nil {
return err
}
h . maybeQueueAck ( packetNumber , rcvTime , shouldInstigateAck , isMissing )
return nil
}
// IgnoreBelow sets a lower limit for acking packets.
// Packets with packet numbers smaller than p will not be acked.
func ( h * receivedPacketTracker ) IgnoreBelow ( p protocol . PacketNumber ) {
if p <= h . ignoreBelow {
return
}
h . ignoreBelow = p
h . packetHistory . DeleteBelow ( p )
if h . logger . Debug ( ) {
h . logger . Debugf ( "\tIgnoring all packets below %#x." , p )
}
}
// isMissing says if a packet was reported missing in the last ACK.
func ( h * receivedPacketTracker ) isMissing ( p protocol . PacketNumber ) bool {
if h . lastAck == nil || p < h . ignoreBelow {
return false
}
return p < h . lastAck . LargestAcked ( ) && ! h . lastAck . AcksPacket ( p )
}
func ( h * receivedPacketTracker ) hasNewMissingPackets ( ) bool {
if h . lastAck == nil {
return false
}
highestRange := h . packetHistory . GetHighestAckRange ( )
return highestRange . Smallest >= h . lastAck . LargestAcked ( ) && highestRange . Len ( ) <= maxPacketsAfterNewMissing
}
// maybeQueueAck queues an ACK, if necessary.
// It is implemented analogously to Chrome's QuicConnection::MaybeQueueAck()
// in ACK_DECIMATION_WITH_REORDERING mode.
func ( h * receivedPacketTracker ) maybeQueueAck ( packetNumber protocol . PacketNumber , rcvTime time . Time , shouldInstigateAck , wasMissing bool ) {
h . packetsReceivedSinceLastAck ++
// always ack the first packet
if h . lastAck == nil {
h . logger . Debugf ( "\tQueueing ACK because the first packet should be acknowledged." )
h . ackQueued = true
return
}
// Send an ACK if this packet was reported missing in an ACK sent before.
// Ack decimation with reordering relies on the timer to send an ACK, but if
// missing packets we reported in the previous ack, send an ACK immediately.
if wasMissing {
if h . logger . Debug ( ) {
h . logger . Debugf ( "\tQueueing ACK because packet %#x was missing before." , packetNumber )
}
h . ackQueued = true
}
if ! h . ackQueued && shouldInstigateAck {
h . retransmittablePacketsReceivedSinceLastAck ++
if packetNumber > minReceivedBeforeAckDecimation {
// ack up to 10 packets at once
if h . retransmittablePacketsReceivedSinceLastAck >= retransmittablePacketsBeforeAck {
h . ackQueued = true
if h . logger . Debug ( ) {
h . logger . Debugf ( "\tQueueing ACK because packet %d packets were received after the last ACK (using threshold: %d)." , h . retransmittablePacketsReceivedSinceLastAck , retransmittablePacketsBeforeAck )
}
} else if h . ackAlarm . IsZero ( ) {
// wait for the minimum of the ack decimation delay or the delayed ack time before sending an ack
ackDelay := utils . MinDuration ( ackSendDelay , time . Duration ( float64 ( h . rttStats . MinRTT ( ) ) * float64 ( ackDecimationDelay ) ) )
h . ackAlarm = rcvTime . Add ( ackDelay )
if h . logger . Debug ( ) {
h . logger . Debugf ( "\tSetting ACK timer to min(1/4 min-RTT, max ack delay): %s (%s from now)" , ackDelay , time . Until ( h . ackAlarm ) )
}
}
} else {
// send an ACK every 2 retransmittable packets
if h . retransmittablePacketsReceivedSinceLastAck >= initialRetransmittablePacketsBeforeAck {
if h . logger . Debug ( ) {
h . logger . Debugf ( "\tQueueing ACK because packet %d packets were received after the last ACK (using initial threshold: %d)." , h . retransmittablePacketsReceivedSinceLastAck , initialRetransmittablePacketsBeforeAck )
}
h . ackQueued = true
} else if h . ackAlarm . IsZero ( ) {
if h . logger . Debug ( ) {
h . logger . Debugf ( "\tSetting ACK timer to max ack delay: %s" , ackSendDelay )
}
h . ackAlarm = rcvTime . Add ( ackSendDelay )
}
}
// If there are new missing packets to report, set a short timer to send an ACK.
if h . hasNewMissingPackets ( ) {
// wait the minimum of 1/8 min RTT and the existing ack time
ackDelay := time . Duration ( float64 ( h . rttStats . MinRTT ( ) ) * float64 ( shortAckDecimationDelay ) )
ackTime := rcvTime . Add ( ackDelay )
if h . ackAlarm . IsZero ( ) || h . ackAlarm . After ( ackTime ) {
h . ackAlarm = ackTime
if h . logger . Debug ( ) {
h . logger . Debugf ( "\tSetting ACK timer to 1/8 min-RTT: %s (%s from now)" , ackDelay , time . Until ( h . ackAlarm ) )
}
}
}
}
if h . ackQueued {
// cancel the ack alarm
h . ackAlarm = time . Time { }
}
}
func ( h * receivedPacketTracker ) GetAckFrame ( ) * wire . AckFrame {
now := time . Now ( )
if ! h . ackQueued && ( h . ackAlarm . IsZero ( ) || h . ackAlarm . After ( now ) ) {
return nil
}
if h . logger . Debug ( ) && ! h . ackQueued && ! h . ackAlarm . IsZero ( ) {
h . logger . Debugf ( "Sending ACK because the ACK timer expired." )
}
ack := & wire . AckFrame {
AckRanges : h . packetHistory . GetAckRanges ( ) ,
DelayTime : now . Sub ( h . largestObservedReceivedTime ) ,
}
h . lastAck = ack
h . ackAlarm = time . Time { }
h . ackQueued = false
h . packetsReceivedSinceLastAck = 0
h . retransmittablePacketsReceivedSinceLastAck = 0
return ack
}
func ( h * receivedPacketTracker ) GetAlarmTimeout ( ) time . Time { return h . ackAlarm }