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