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