2017-12-12 02:51:45 +00:00
package ackhandler
import (
"errors"
"fmt"
"time"
"github.com/lucas-clemente/quic-go/congestion"
2018-01-03 19:19:49 +00:00
"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/utils"
"github.com/lucas-clemente/quic-go/internal/wire"
2017-12-12 02:51:45 +00:00
"github.com/lucas-clemente/quic-go/qerr"
)
const (
// Maximum reordering in time space before time based loss detection considers a packet lost.
// In fraction of an RTT.
timeReorderingFraction = 1.0 / 8
2018-01-03 19:19:49 +00:00
// The default RTT used before an RTT sample is taken.
// Note: This constant is also defined in the congestion package.
defaultInitialRTT = 100 * time . Millisecond
2017-12-12 02:51:45 +00:00
// defaultRTOTimeout is the RTO time on new connections
defaultRTOTimeout = 500 * time . Millisecond
2018-01-03 19:19:49 +00:00
// Minimum time in the future a tail loss probe alarm may be set for.
minTPLTimeout = 10 * time . Millisecond
2017-12-12 02:51:45 +00:00
// Minimum time in the future an RTO alarm may be set for.
minRTOTimeout = 200 * time . Millisecond
// maxRTOTimeout is the maximum RTO time
maxRTOTimeout = 60 * time . Second
)
2018-01-03 19:19:49 +00:00
// ErrDuplicateOrOutOfOrderAck occurs when a duplicate or an out-of-order ACK is received
var ErrDuplicateOrOutOfOrderAck = errors . New ( "SentPacketHandler: Duplicate or out-of-order ACK" )
2017-12-12 02:51:45 +00:00
type sentPacketHandler struct {
lastSentPacketNumber protocol . PacketNumber
skippedPackets [ ] protocol . PacketNumber
2018-01-03 19:19:49 +00:00
numNonRetransmittablePackets int // number of non-retransmittable packets since the last retransmittable packet
2017-12-12 02:51:45 +00:00
2018-01-03 19:19:49 +00:00
largestAcked protocol . PacketNumber
2017-12-12 02:51:45 +00:00
largestReceivedPacketWithAck protocol . PacketNumber
2018-01-20 18:07:01 +00:00
// lowestPacketNotConfirmedAcked is the lowest packet number that we sent an ACK for, but haven't received confirmation, that this ACK actually arrived
// example: we send an ACK for packets 90-100 with packet number 20
// once we receive an ACK from the peer for packet 20, the lowestPacketNotConfirmedAcked is 101
lowestPacketNotConfirmedAcked protocol . PacketNumber
2017-12-12 02:51:45 +00:00
packetHistory * PacketList
stopWaitingManager stopWaitingManager
retransmissionQueue [ ] * Packet
bytesInFlight protocol . ByteCount
congestion congestion . SendAlgorithm
rttStats * congestion . RTTStats
2018-01-03 19:19:49 +00:00
handshakeComplete bool
// The number of times the handshake packets have been retransmitted without receiving an ack.
handshakeCount uint32
2017-12-12 02:51:45 +00:00
// The number of times an RTO has been sent without receiving an ack.
rtoCount uint32
// The time at which the next packet will be considered lost based on early transmit or exceeding the reordering window in time.
lossTime time . Time
// The alarm timeout
alarm time . Time
}
// NewSentPacketHandler creates a new sentPacketHandler
func NewSentPacketHandler ( rttStats * congestion . RTTStats ) SentPacketHandler {
congestion := congestion . NewCubicSender (
congestion . DefaultClock { } ,
rttStats ,
false , /* don't use reno since chromium doesn't (why?) */
protocol . InitialCongestionWindow ,
protocol . DefaultMaxCongestionWindow ,
)
return & sentPacketHandler {
packetHistory : NewPacketList ( ) ,
stopWaitingManager : stopWaitingManager { } ,
rttStats : rttStats ,
congestion : congestion ,
}
}
2018-01-03 19:19:49 +00:00
func ( h * sentPacketHandler ) lowestUnacked ( ) protocol . PacketNumber {
2017-12-12 02:51:45 +00:00
if f := h . packetHistory . Front ( ) ; f != nil {
2018-01-03 19:19:49 +00:00
return f . Value . PacketNumber
2017-12-12 02:51:45 +00:00
}
2018-01-03 19:19:49 +00:00
return h . largestAcked + 1
2017-12-12 02:51:45 +00:00
}
2018-01-03 19:19:49 +00:00
func ( h * sentPacketHandler ) ShouldSendRetransmittablePacket ( ) bool {
return h . numNonRetransmittablePackets >= protocol . MaxNonRetransmittablePackets
}
func ( h * sentPacketHandler ) SetHandshakeComplete ( ) {
2018-01-20 18:07:01 +00:00
var queue [ ] * Packet
for _ , packet := range h . retransmissionQueue {
if packet . EncryptionLevel == protocol . EncryptionForwardSecure {
queue = append ( queue , packet )
}
}
h . retransmissionQueue = queue
2018-01-03 19:19:49 +00:00
h . handshakeComplete = true
}
2017-12-12 02:51:45 +00:00
2018-01-03 19:19:49 +00:00
func ( h * sentPacketHandler ) SentPacket ( packet * Packet ) error {
2017-12-12 02:51:45 +00:00
if protocol . PacketNumber ( len ( h . retransmissionQueue ) + h . packetHistory . Len ( ) + 1 ) > protocol . MaxTrackedSentPackets {
2018-01-03 19:19:49 +00:00
return errors . New ( "Too many outstanding non-acked and non-retransmitted packets" )
2017-12-12 02:51:45 +00:00
}
for p := h . lastSentPacketNumber + 1 ; p < packet . PacketNumber ; p ++ {
h . skippedPackets = append ( h . skippedPackets , p )
if len ( h . skippedPackets ) > protocol . MaxTrackedSkippedPackets {
h . skippedPackets = h . skippedPackets [ 1 : ]
}
}
2018-01-03 19:19:49 +00:00
h . lastSentPacketNumber = packet . PacketNumber
2017-12-12 02:51:45 +00:00
now := time . Now ( )
2018-01-20 18:07:01 +00:00
var largestAcked protocol . PacketNumber
if len ( packet . Frames ) > 0 {
if ackFrame , ok := packet . Frames [ 0 ] . ( * wire . AckFrame ) ; ok {
largestAcked = ackFrame . LargestAcked
}
}
2018-01-03 19:19:49 +00:00
packet . Frames = stripNonRetransmittableFrames ( packet . Frames )
isRetransmittable := len ( packet . Frames ) != 0
if isRetransmittable {
2018-01-20 18:07:01 +00:00
packet . sendTime = now
packet . largestAcked = largestAcked
2018-01-03 19:19:49 +00:00
h . bytesInFlight += packet . Length
h . packetHistory . PushBack ( * packet )
h . numNonRetransmittablePackets = 0
} else {
h . numNonRetransmittablePackets ++
}
2017-12-12 02:51:45 +00:00
h . congestion . OnPacketSent (
now ,
h . bytesInFlight ,
packet . PacketNumber ,
packet . Length ,
2018-01-03 19:19:49 +00:00
isRetransmittable ,
2017-12-12 02:51:45 +00:00
)
2018-01-20 18:07:01 +00:00
h . updateLossDetectionAlarm ( now )
2017-12-12 02:51:45 +00:00
return nil
}
2018-01-03 19:19:49 +00:00
func ( h * sentPacketHandler ) ReceivedAck ( ackFrame * wire . AckFrame , withPacketNumber protocol . PacketNumber , encLevel protocol . EncryptionLevel , rcvTime time . Time ) error {
2017-12-12 02:51:45 +00:00
if ackFrame . LargestAcked > h . lastSentPacketNumber {
2018-01-03 19:19:49 +00:00
return qerr . Error ( qerr . InvalidAckData , "Received ACK for an unsent package" )
2017-12-12 02:51:45 +00:00
}
// duplicate or out-of-order ACK
2018-01-03 19:19:49 +00:00
// if withPacketNumber <= h.largestReceivedPacketWithAck && withPacketNumber != 0 {
2017-12-12 02:51:45 +00:00
if withPacketNumber <= h . largestReceivedPacketWithAck {
return ErrDuplicateOrOutOfOrderAck
}
h . largestReceivedPacketWithAck = withPacketNumber
// ignore repeated ACK (ACKs that don't have a higher LargestAcked than the last ACK)
2018-01-03 19:19:49 +00:00
if ackFrame . LargestAcked < h . lowestUnacked ( ) {
2017-12-12 02:51:45 +00:00
return nil
}
2018-01-03 19:19:49 +00:00
h . largestAcked = ackFrame . LargestAcked
2017-12-12 02:51:45 +00:00
if h . skippedPacketsAcked ( ackFrame ) {
2018-01-03 19:19:49 +00:00
return qerr . Error ( qerr . InvalidAckData , "Received an ACK for a skipped packet number" )
2017-12-12 02:51:45 +00:00
}
rttUpdated := h . maybeUpdateRTT ( ackFrame . LargestAcked , ackFrame . DelayTime , rcvTime )
if rttUpdated {
h . congestion . MaybeExitSlowStart ( )
}
ackedPackets , err := h . determineNewlyAckedPackets ( ackFrame )
if err != nil {
return err
}
if len ( ackedPackets ) > 0 {
for _ , p := range ackedPackets {
2018-01-03 19:19:49 +00:00
if encLevel < p . Value . EncryptionLevel {
return fmt . Errorf ( "Received ACK with encryption level %s that acks a packet %d (encryption level %s)" , encLevel , p . Value . PacketNumber , p . Value . EncryptionLevel )
}
2018-01-20 18:07:01 +00:00
// largestAcked == 0 either means that the packet didn't contain an ACK, or it just acked packet 0
// It is safe to ignore the corner case of packets that just acked packet 0, because
// the lowestPacketNotConfirmedAcked is only used to limit the number of ACK ranges we will send.
if p . Value . largestAcked != 0 {
h . lowestPacketNotConfirmedAcked = utils . MaxPacketNumber ( h . lowestPacketNotConfirmedAcked , p . Value . largestAcked + 1 )
}
2017-12-12 02:51:45 +00:00
h . onPacketAcked ( p )
h . congestion . OnPacketAcked ( p . Value . PacketNumber , p . Value . Length , h . bytesInFlight )
}
}
2018-01-20 18:07:01 +00:00
h . detectLostPackets ( rcvTime )
h . updateLossDetectionAlarm ( rcvTime )
2017-12-12 02:51:45 +00:00
h . garbageCollectSkippedPackets ( )
h . stopWaitingManager . ReceivedAck ( ackFrame )
return nil
}
2018-01-20 18:07:01 +00:00
func ( h * sentPacketHandler ) GetLowestPacketNotConfirmedAcked ( ) protocol . PacketNumber {
return h . lowestPacketNotConfirmedAcked
}
2018-01-03 19:19:49 +00:00
func ( h * sentPacketHandler ) determineNewlyAckedPackets ( ackFrame * wire . AckFrame ) ( [ ] * PacketElement , error ) {
2017-12-12 02:51:45 +00:00
var ackedPackets [ ] * PacketElement
ackRangeIndex := 0
for el := h . packetHistory . Front ( ) ; el != nil ; el = el . Next ( ) {
packet := el . Value
packetNumber := packet . PacketNumber
// Ignore packets below the LowestAcked
if packetNumber < ackFrame . LowestAcked {
continue
}
// Break after LargestAcked is reached
if packetNumber > ackFrame . LargestAcked {
break
}
if ackFrame . HasMissingRanges ( ) {
ackRange := ackFrame . AckRanges [ len ( ackFrame . AckRanges ) - 1 - ackRangeIndex ]
2018-01-03 19:19:49 +00:00
for packetNumber > ackRange . Last && ackRangeIndex < len ( ackFrame . AckRanges ) - 1 {
2017-12-12 02:51:45 +00:00
ackRangeIndex ++
ackRange = ackFrame . AckRanges [ len ( ackFrame . AckRanges ) - 1 - ackRangeIndex ]
}
2018-01-03 19:19:49 +00:00
if packetNumber >= ackRange . First { // packet i contained in ACK range
if packetNumber > ackRange . Last {
return nil , fmt . Errorf ( "BUG: ackhandler would have acked wrong packet 0x%x, while evaluating range 0x%x -> 0x%x" , packetNumber , ackRange . First , ackRange . Last )
2017-12-12 02:51:45 +00:00
}
ackedPackets = append ( ackedPackets , el )
}
} else {
ackedPackets = append ( ackedPackets , el )
}
}
return ackedPackets , nil
}
func ( h * sentPacketHandler ) maybeUpdateRTT ( largestAcked protocol . PacketNumber , ackDelay time . Duration , rcvTime time . Time ) bool {
for el := h . packetHistory . Front ( ) ; el != nil ; el = el . Next ( ) {
packet := el . Value
if packet . PacketNumber == largestAcked {
2018-01-20 18:07:01 +00:00
h . rttStats . UpdateRTT ( rcvTime . Sub ( packet . sendTime ) , ackDelay , rcvTime )
2017-12-12 02:51:45 +00:00
return true
}
// Packets are sorted by number, so we can stop searching
if packet . PacketNumber > largestAcked {
break
}
}
return false
}
2018-01-20 18:07:01 +00:00
func ( h * sentPacketHandler ) updateLossDetectionAlarm ( now time . Time ) {
2017-12-12 02:51:45 +00:00
// Cancel the alarm if no packets are outstanding
if h . packetHistory . Len ( ) == 0 {
h . alarm = time . Time { }
return
}
// TODO(#497): TLP
2018-01-03 19:19:49 +00:00
if ! h . handshakeComplete {
2018-01-20 18:07:01 +00:00
h . alarm = now . Add ( h . computeHandshakeTimeout ( ) )
2018-01-03 19:19:49 +00:00
} else if ! h . lossTime . IsZero ( ) {
2017-12-12 02:51:45 +00:00
// Early retransmit timer or time loss detection.
h . alarm = h . lossTime
} else {
// RTO
2018-01-20 18:07:01 +00:00
h . alarm = now . Add ( h . computeRTOTimeout ( ) )
2017-12-12 02:51:45 +00:00
}
}
2018-01-20 18:07:01 +00:00
func ( h * sentPacketHandler ) detectLostPackets ( now time . Time ) {
2017-12-12 02:51:45 +00:00
h . lossTime = time . Time { }
maxRTT := float64 ( utils . MaxDuration ( h . rttStats . LatestRTT ( ) , h . rttStats . SmoothedRTT ( ) ) )
delayUntilLost := time . Duration ( ( 1.0 + timeReorderingFraction ) * maxRTT )
var lostPackets [ ] * PacketElement
for el := h . packetHistory . Front ( ) ; el != nil ; el = el . Next ( ) {
packet := el . Value
2018-01-03 19:19:49 +00:00
if packet . PacketNumber > h . largestAcked {
2017-12-12 02:51:45 +00:00
break
}
2018-01-20 18:07:01 +00:00
timeSinceSent := now . Sub ( packet . sendTime )
2017-12-12 02:51:45 +00:00
if timeSinceSent > delayUntilLost {
lostPackets = append ( lostPackets , el )
} else if h . lossTime . IsZero ( ) {
// Note: This conditional is only entered once per call
h . lossTime = now . Add ( delayUntilLost - timeSinceSent )
}
}
if len ( lostPackets ) > 0 {
for _ , p := range lostPackets {
h . queuePacketForRetransmission ( p )
h . congestion . OnPacketLost ( p . Value . PacketNumber , p . Value . Length , h . bytesInFlight )
}
}
}
func ( h * sentPacketHandler ) OnAlarm ( ) {
2018-01-20 18:07:01 +00:00
now := time . Now ( )
2017-12-12 02:51:45 +00:00
// TODO(#497): TLP
2018-01-03 19:19:49 +00:00
if ! h . handshakeComplete {
h . queueHandshakePacketsForRetransmission ( )
h . handshakeCount ++
} else if ! h . lossTime . IsZero ( ) {
2017-12-12 02:51:45 +00:00
// Early retransmit or time loss detection
2018-01-20 18:07:01 +00:00
h . detectLostPackets ( now )
2017-12-12 02:51:45 +00:00
} else {
// RTO
h . retransmitOldestTwoPackets ( )
h . rtoCount ++
}
2018-01-20 18:07:01 +00:00
h . updateLossDetectionAlarm ( now )
2017-12-12 02:51:45 +00:00
}
func ( h * sentPacketHandler ) GetAlarmTimeout ( ) time . Time {
return h . alarm
}
func ( h * sentPacketHandler ) onPacketAcked ( packetElement * PacketElement ) {
h . bytesInFlight -= packetElement . Value . Length
h . rtoCount = 0
2018-01-03 19:19:49 +00:00
h . handshakeCount = 0
2017-12-12 02:51:45 +00:00
// TODO(#497): h.tlpCount = 0
h . packetHistory . Remove ( packetElement )
}
func ( h * sentPacketHandler ) DequeuePacketForRetransmission ( ) * Packet {
if len ( h . retransmissionQueue ) == 0 {
return nil
}
2018-01-03 19:19:49 +00:00
packet := h . retransmissionQueue [ 0 ]
// Shift the slice and don't retain anything that isn't needed.
copy ( h . retransmissionQueue , h . retransmissionQueue [ 1 : ] )
h . retransmissionQueue [ len ( h . retransmissionQueue ) - 1 ] = nil
h . retransmissionQueue = h . retransmissionQueue [ : len ( h . retransmissionQueue ) - 1 ]
2017-12-12 02:51:45 +00:00
return packet
}
func ( h * sentPacketHandler ) GetLeastUnacked ( ) protocol . PacketNumber {
2018-01-03 19:19:49 +00:00
return h . lowestUnacked ( )
2017-12-12 02:51:45 +00:00
}
2018-01-03 19:19:49 +00:00
func ( h * sentPacketHandler ) GetStopWaitingFrame ( force bool ) * wire . StopWaitingFrame {
2017-12-12 02:51:45 +00:00
return h . stopWaitingManager . GetStopWaitingFrame ( force )
}
func ( h * sentPacketHandler ) SendingAllowed ( ) bool {
2018-01-20 18:07:01 +00:00
cwnd := h . congestion . GetCongestionWindow ( )
congestionLimited := h . bytesInFlight > cwnd
2017-12-12 02:51:45 +00:00
maxTrackedLimited := protocol . PacketNumber ( len ( h . retransmissionQueue ) + h . packetHistory . Len ( ) ) >= protocol . MaxTrackedSentPackets
2018-01-03 19:19:49 +00:00
if congestionLimited {
2018-01-20 18:07:01 +00:00
utils . Debugf ( "Congestion limited: bytes in flight %d, window %d" , h . bytesInFlight , cwnd )
2018-01-03 19:19:49 +00:00
}
// Workaround for #555:
// Always allow sending of retransmissions. This should probably be limited
// to RTOs, but we currently don't have a nice way of distinguishing them.
haveRetransmissions := len ( h . retransmissionQueue ) > 0
return ! maxTrackedLimited && ( ! congestionLimited || haveRetransmissions )
2017-12-12 02:51:45 +00:00
}
func ( h * sentPacketHandler ) retransmitOldestTwoPackets ( ) {
if p := h . packetHistory . Front ( ) ; p != nil {
h . queueRTO ( p )
}
if p := h . packetHistory . Front ( ) ; p != nil {
h . queueRTO ( p )
}
}
func ( h * sentPacketHandler ) queueRTO ( el * PacketElement ) {
packet := & el . Value
2018-01-03 19:19:49 +00:00
utils . Debugf (
"\tQueueing packet 0x%x for retransmission (RTO), %d outstanding" ,
packet . PacketNumber ,
h . packetHistory . Len ( ) ,
)
2017-12-12 02:51:45 +00:00
h . queuePacketForRetransmission ( el )
h . congestion . OnPacketLost ( packet . PacketNumber , packet . Length , h . bytesInFlight )
h . congestion . OnRetransmissionTimeout ( true )
}
2018-01-03 19:19:49 +00:00
func ( h * sentPacketHandler ) queueHandshakePacketsForRetransmission ( ) {
var handshakePackets [ ] * PacketElement
for el := h . packetHistory . Front ( ) ; el != nil ; el = el . Next ( ) {
if el . Value . EncryptionLevel < protocol . EncryptionForwardSecure {
handshakePackets = append ( handshakePackets , el )
}
}
for _ , el := range handshakePackets {
h . queuePacketForRetransmission ( el )
}
}
2017-12-12 02:51:45 +00:00
func ( h * sentPacketHandler ) queuePacketForRetransmission ( packetElement * PacketElement ) {
packet := & packetElement . Value
h . bytesInFlight -= packet . Length
h . retransmissionQueue = append ( h . retransmissionQueue , packet )
h . packetHistory . Remove ( packetElement )
h . stopWaitingManager . QueuedRetransmissionForPacketNumber ( packet . PacketNumber )
}
2018-01-03 19:19:49 +00:00
func ( h * sentPacketHandler ) computeHandshakeTimeout ( ) time . Duration {
duration := 2 * h . rttStats . SmoothedRTT ( )
if duration == 0 {
duration = 2 * defaultInitialRTT
}
duration = utils . MaxDuration ( duration , minTPLTimeout )
// exponential backoff
// There's an implicit limit to this set by the handshake timeout.
return duration << h . handshakeCount
}
2017-12-12 02:51:45 +00:00
func ( h * sentPacketHandler ) computeRTOTimeout ( ) time . Duration {
rto := h . congestion . RetransmissionDelay ( )
if rto == 0 {
rto = defaultRTOTimeout
}
rto = utils . MaxDuration ( rto , minRTOTimeout )
// Exponential backoff
rto = rto << h . rtoCount
return utils . MinDuration ( rto , maxRTOTimeout )
}
2018-01-03 19:19:49 +00:00
func ( h * sentPacketHandler ) skippedPacketsAcked ( ackFrame * wire . AckFrame ) bool {
2017-12-12 02:51:45 +00:00
for _ , p := range h . skippedPackets {
if ackFrame . AcksPacket ( p ) {
return true
}
}
return false
}
func ( h * sentPacketHandler ) garbageCollectSkippedPackets ( ) {
2018-01-03 19:19:49 +00:00
lowestUnacked := h . lowestUnacked ( )
2017-12-12 02:51:45 +00:00
deleteIndex := 0
for i , p := range h . skippedPackets {
2018-01-03 19:19:49 +00:00
if p < lowestUnacked {
2017-12-12 02:51:45 +00:00
deleteIndex = i + 1
}
}
h . skippedPackets = h . skippedPackets [ deleteIndex : ]
}