blob: 85bda314ecc93c5a7fe86993229b07c3d9938c91 [file] [log] [blame] [edit]
// Copyright 2023 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build go1.21
package quic
import "fmt"
// handleAckOrLoss deals with the final fate of a packet we sent:
// Either the peer acknowledges it, or we declare it lost.
//
// In order to handle packet loss, we must retain any information sent to the peer
// until the peer has acknowledged it.
//
// When information is acknowledged, we can discard it.
//
// When information is lost, we mark it for retransmission.
// See RFC 9000, Section 13.3 for a complete list of information which is retransmitted on loss.
// https://www.rfc-editor.org/rfc/rfc9000#section-13.3
func (c *Conn) handleAckOrLoss(space numberSpace, sent *sentPacket, fate packetFate) {
// The list of frames in a sent packet is marshaled into a buffer in the sentPacket
// by the packetWriter. Unmarshal that buffer here. This code must be kept in sync with
// packetWriter.append*.
//
// A sent packet meets its fate (acked or lost) only once, so it's okay to consume
// the sentPacket's buffer here.
for !sent.done() {
switch f := sent.next(); f {
default:
panic(fmt.Sprintf("BUG: unhandled acked/lost frame type %x", f))
case frameTypeAck:
// Unlike most information, loss of an ACK frame does not trigger
// retransmission. ACKs are sent in response to ack-eliciting packets,
// and always contain the latest information available.
//
// Acknowledgement of an ACK frame may allow us to discard information
// about older packets.
largest := packetNumber(sent.nextInt())
if fate == packetAcked {
c.acks[space].handleAck(largest)
}
case frameTypeCrypto:
start, end := sent.nextRange()
c.crypto[space].ackOrLoss(start, end, fate)
case frameTypeMaxData:
c.ackOrLossMaxData(sent.num, fate)
case frameTypeResetStream,
frameTypeStopSending,
frameTypeMaxStreamData,
frameTypeStreamDataBlocked:
id := streamID(sent.nextInt())
s := c.streamForID(id)
if s == nil {
continue
}
s.ackOrLoss(sent.num, f, fate)
case frameTypeStreamBase,
frameTypeStreamBase | streamFinBit:
id := streamID(sent.nextInt())
start, end := sent.nextRange()
s := c.streamForID(id)
if s == nil {
continue
}
fin := f&streamFinBit != 0
s.ackOrLossData(sent.num, start, end, fin, fate)
case frameTypeMaxStreamsBidi:
c.streams.remoteLimit[bidiStream].sendMax.ackLatestOrLoss(sent.num, fate)
case frameTypeMaxStreamsUni:
c.streams.remoteLimit[uniStream].sendMax.ackLatestOrLoss(sent.num, fate)
case frameTypeNewConnectionID:
seq := int64(sent.nextInt())
c.connIDState.ackOrLossNewConnectionID(sent.num, seq, fate)
case frameTypeRetireConnectionID:
seq := int64(sent.nextInt())
c.connIDState.ackOrLossRetireConnectionID(sent.num, seq, fate)
case frameTypeHandshakeDone:
c.handshakeConfirmed.ackOrLoss(sent.num, fate)
}
}
}