// 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 // A sentVal tracks sending some piece of information to the peer. // It tracks whether the information has been sent, acked, and // (when in-flight) the most recent packet to carry it. // // For example, a sentVal can track sending of a RESET_STREAM frame. // // - unset: stream is active, no need to send RESET_STREAM // - unsent: we should send a RESET_STREAM, but have not yet // - sent: we have sent a RESET_STREAM, but have not received an ack // - received: we have sent a RESET_STREAM, and the peer has acked the packet that contained it // // In the "sent" state, a sentVal also tracks the latest packet number to carry // the information. (QUIC packet numbers are always at most 62 bits in size, // so the sentVal keeps the number in the low 62 bits and the state in the high 2 bits.) type sentVal uint64 const ( sentValUnset = 0 // unset sentValUnsent = 1 << 62 // set, not sent to the peer sentValSent = 2 << 62 // set, sent to the peer but not yet acked; pnum is set sentValReceived = 3 << 62 // set, peer acked receipt sentValStateMask = 3 << 62 ) // isSet reports whether the value is set. func (s sentVal) isSet() bool { return s != 0 } // shouldSend reports whether the value is set and has not been sent to the peer. func (s sentVal) shouldSend() bool { return s.state() == sentValUnsent } // shouldSend reports whether the value needs to be sent to the peer. // The value needs to be sent if it is set and has not been sent. // If pto is true, indicating that we are sending a PTO probe, the value // should also be sent if it is set and has not been acknowledged. func (s sentVal) shouldSendPTO(pto bool) bool { st := s.state() return st == sentValUnsent || (pto && st == sentValSent) } // isReceived reports whether the value has been received by the peer. func (s sentVal) isReceived() bool { return s == sentValReceived } // set sets the value and records that it should be sent to the peer. // If the value has already been sent, it is not resent. func (s *sentVal) set() { if *s == 0 { *s = sentValUnsent } } // reset sets the value to the unsent state. func (s *sentVal) setUnsent() { *s = sentValUnsent } // clear sets the value to the unset state. func (s *sentVal) clear() { *s = sentValUnset } // setSent sets the value to the send state and records the number of the most recent // packet containing the value. func (s *sentVal) setSent(pnum packetNumber) { *s = sentValSent | sentVal(pnum) } // setReceived sets the value to the received state. func (s *sentVal) setReceived() { *s = sentValReceived } // ackOrLoss reports that an acknowledgement has been received for the value, // or that the packet carrying the value has been lost. func (s *sentVal) ackOrLoss(pnum packetNumber, fate packetFate) { if fate == packetAcked { *s = sentValReceived } else if *s == sentVal(pnum)|sentValSent { *s = sentValUnsent } } // ackLatestOrLoss reports that an acknowledgement has been received for the value, // or that the packet carrying the value has been lost. // The value is set to the acked state only if pnum is the latest packet containing it. // // We use this to handle acks for data that varies every time it is sent. // For example, if we send a MAX_DATA frame followed by an updated MAX_DATA value in a // second packet, we consider the data sent only upon receiving an ack for the most // recent value. func (s *sentVal) ackLatestOrLoss(pnum packetNumber, fate packetFate) { if fate == packetAcked { if *s == sentVal(pnum)|sentValSent { *s = sentValReceived } } else { if *s == sentVal(pnum)|sentValSent { *s = sentValUnsent } } } func (s sentVal) state() uint64 { return uint64(s) & sentValStateMask }