File: conn_loss.go

package info (click to toggle)
golang-golang-x-net 1%3A0.27.0-2
  • links: PTS, VCS
  • area: main
  • in suites: experimental, sid, trixie
  • size: 8,636 kB
  • sloc: asm: 18; makefile: 12; sh: 7
file content (87 lines) | stat: -rw-r--r-- 3,061 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
// 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) {
	if fate == packetLost && c.logEnabled(QLogLevelPacket) {
		c.logPacketLost(space, sent)
	}

	// 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)
		}
	}
}