mirror of
https://github.com/golang/net.git
synced 2026-03-31 02:17:08 +09:00
quic: send ECN feedback to peers
Track the total number of ECT(0), ECT(1), and ECN-CE state of packets we process in each packet number space. Send it back to the peer in each ACK frame (unless it's all zeros). "Even if an endpoint does not set an ECT field in packets it sends, the endpoint MUST provide feedback about ECN markings it receives, if these are accessible." https://www.rfc-editor.org/rfc/rfc9000#section-13.4.1-2 For golang/go#58547 Change-Id: I3ce5be6c536198eaa711f527402503b0567fc7a5 Reviewed-on: https://go-review.googlesource.com/c/net/+/712280 Reviewed-by: Damien Neil <dneil@google.com> Reviewed-by: Dmitri Shuralyov <dmitshur@google.com> Auto-Submit: Rhys Hiltner <rhys.hiltner@gmail.com> Auto-Submit: Damien Neil <dneil@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
This commit is contained in:
committed by
Gopher Robot
parent
c296fafc21
commit
98daa2e33a
@@ -95,6 +95,9 @@ func main() {
|
||||
basicTest(ctx, config, urls)
|
||||
return
|
||||
}
|
||||
case "ecn":
|
||||
// TODO: We give ECN feedback to the sender, but we don't add our own
|
||||
// ECN marks to outgoing packets.
|
||||
case "transfer":
|
||||
// "The client should use small initial flow control windows
|
||||
// for both stream- and connection-level flow control
|
||||
|
||||
30
quic/acks.go
30
quic/acks.go
@@ -25,6 +25,15 @@ type ackState struct {
|
||||
|
||||
// The number of ack-eliciting packets in seen that we have not yet acknowledged.
|
||||
unackedAckEliciting int
|
||||
|
||||
// Total ECN counters for this packet number space.
|
||||
ecn ecnCounts
|
||||
}
|
||||
|
||||
type ecnCounts struct {
|
||||
t0 int
|
||||
t1 int
|
||||
ce int
|
||||
}
|
||||
|
||||
// shouldProcess reports whether a packet should be handled or discarded.
|
||||
@@ -43,10 +52,10 @@ func (acks *ackState) shouldProcess(num packetNumber) bool {
|
||||
}
|
||||
|
||||
// receive records receipt of a packet.
|
||||
func (acks *ackState) receive(now time.Time, space numberSpace, num packetNumber, ackEliciting bool) {
|
||||
func (acks *ackState) receive(now time.Time, space numberSpace, num packetNumber, ackEliciting bool, ecn ecnBits) {
|
||||
if ackEliciting {
|
||||
acks.unackedAckEliciting++
|
||||
if acks.mustAckImmediately(space, num) {
|
||||
if acks.mustAckImmediately(space, num, ecn) {
|
||||
acks.nextAck = now
|
||||
} else if acks.nextAck.IsZero() {
|
||||
// This packet does not need to be acknowledged immediately,
|
||||
@@ -70,6 +79,15 @@ func (acks *ackState) receive(now time.Time, space numberSpace, num packetNumber
|
||||
acks.maxRecvTime = now
|
||||
}
|
||||
|
||||
switch ecn {
|
||||
case ecnECT0:
|
||||
acks.ecn.t0++
|
||||
case ecnECT1:
|
||||
acks.ecn.t1++
|
||||
case ecnCE:
|
||||
acks.ecn.ce++
|
||||
}
|
||||
|
||||
// Limit the total number of ACK ranges by dropping older ranges.
|
||||
//
|
||||
// Remembering more ranges results in larger ACK frames.
|
||||
@@ -92,7 +110,7 @@ func (acks *ackState) receive(now time.Time, space numberSpace, num packetNumber
|
||||
|
||||
// mustAckImmediately reports whether an ack-eliciting packet must be acknowledged immediately,
|
||||
// or whether the ack may be deferred.
|
||||
func (acks *ackState) mustAckImmediately(space numberSpace, num packetNumber) bool {
|
||||
func (acks *ackState) mustAckImmediately(space numberSpace, num packetNumber, ecn ecnBits) bool {
|
||||
// https://www.rfc-editor.org/rfc/rfc9000.html#section-13.2.1
|
||||
if space != appDataSpace {
|
||||
// "[...] all ack-eliciting Initial and Handshake packets [...]"
|
||||
@@ -128,6 +146,12 @@ func (acks *ackState) mustAckImmediately(space numberSpace, num packetNumber) bo
|
||||
// there are no gaps. If it does not, there must be a gap.
|
||||
return true
|
||||
}
|
||||
// "[...] packets marked with the ECN Congestion Experienced (CE) codepoint
|
||||
// in the IP header SHOULD be acknowledged immediately [...]"
|
||||
// https://www.rfc-editor.org/rfc/rfc9000.html#section-13.2.1-9
|
||||
if ecn == ecnCE {
|
||||
return true
|
||||
}
|
||||
// "[...] SHOULD send an ACK frame after receiving at least two ack-eliciting packets."
|
||||
// https://www.rfc-editor.org/rfc/rfc9000.html#section-13.2.2
|
||||
//
|
||||
|
||||
@@ -17,7 +17,7 @@ func TestAcksDisallowDuplicate(t *testing.T) {
|
||||
receive := []packetNumber{0, 1, 2, 4, 7, 6, 9}
|
||||
seen := map[packetNumber]bool{}
|
||||
for i, pnum := range receive {
|
||||
acks.receive(now, appDataSpace, pnum, true)
|
||||
acks.receive(now, appDataSpace, pnum, true, ecnNotECT)
|
||||
seen[pnum] = true
|
||||
for ppnum := packetNumber(0); ppnum < 11; ppnum++ {
|
||||
if got, want := acks.shouldProcess(ppnum), !seen[ppnum]; got != want {
|
||||
@@ -32,7 +32,7 @@ func TestAcksDisallowDiscardedAckRanges(t *testing.T) {
|
||||
acks := ackState{}
|
||||
now := time.Now()
|
||||
for pnum := packetNumber(0); ; pnum += 2 {
|
||||
acks.receive(now, appDataSpace, pnum, true)
|
||||
acks.receive(now, appDataSpace, pnum, true, ecnNotECT)
|
||||
send, _ := acks.acksToSend(now)
|
||||
for ppnum := packetNumber(0); ppnum < packetNumber(send.min()); ppnum++ {
|
||||
if acks.shouldProcess(ppnum) {
|
||||
@@ -158,13 +158,13 @@ func TestAcksSent(t *testing.T) {
|
||||
start := time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC)
|
||||
for _, p := range test.ackedPackets {
|
||||
t.Logf("receive %v.%v, ack-eliciting=%v", test.space, p.pnum, p.ackEliciting)
|
||||
acks.receive(start, test.space, p.pnum, p.ackEliciting)
|
||||
acks.receive(start, test.space, p.pnum, p.ackEliciting, ecnNotECT)
|
||||
}
|
||||
t.Logf("send an ACK frame")
|
||||
acks.sentAck()
|
||||
for _, p := range test.packets {
|
||||
t.Logf("receive %v.%v, ack-eliciting=%v", test.space, p.pnum, p.ackEliciting)
|
||||
acks.receive(start, test.space, p.pnum, p.ackEliciting)
|
||||
acks.receive(start, test.space, p.pnum, p.ackEliciting, ecnNotECT)
|
||||
}
|
||||
switch {
|
||||
case len(test.wantAcks) == 0:
|
||||
@@ -208,13 +208,13 @@ func TestAcksSent(t *testing.T) {
|
||||
func TestAcksDiscardAfterAck(t *testing.T) {
|
||||
acks := ackState{}
|
||||
now := time.Now()
|
||||
acks.receive(now, appDataSpace, 0, true)
|
||||
acks.receive(now, appDataSpace, 2, true)
|
||||
acks.receive(now, appDataSpace, 4, true)
|
||||
acks.receive(now, appDataSpace, 5, true)
|
||||
acks.receive(now, appDataSpace, 6, true)
|
||||
acks.receive(now, appDataSpace, 0, true, ecnNotECT)
|
||||
acks.receive(now, appDataSpace, 2, true, ecnNotECT)
|
||||
acks.receive(now, appDataSpace, 4, true, ecnNotECT)
|
||||
acks.receive(now, appDataSpace, 5, true, ecnNotECT)
|
||||
acks.receive(now, appDataSpace, 6, true, ecnNotECT)
|
||||
acks.handleAck(6) // discards all ranges prior to the one containing packet 6
|
||||
acks.receive(now, appDataSpace, 7, true)
|
||||
acks.receive(now, appDataSpace, 7, true, ecnNotECT)
|
||||
got, _ := acks.acksToSend(now)
|
||||
if len(got) != 1 {
|
||||
t.Errorf("acks.acksToSend contains ranges prior to last acknowledged ack; got %v, want 1 range", got)
|
||||
@@ -224,9 +224,9 @@ func TestAcksDiscardAfterAck(t *testing.T) {
|
||||
func TestAcksLargestSeen(t *testing.T) {
|
||||
acks := ackState{}
|
||||
now := time.Now()
|
||||
acks.receive(now, appDataSpace, 0, true)
|
||||
acks.receive(now, appDataSpace, 4, true)
|
||||
acks.receive(now, appDataSpace, 1, true)
|
||||
acks.receive(now, appDataSpace, 0, true, ecnNotECT)
|
||||
acks.receive(now, appDataSpace, 4, true, ecnNotECT)
|
||||
acks.receive(now, appDataSpace, 1, true, ecnNotECT)
|
||||
if got, want := acks.largestSeen(), packetNumber(4); got != want {
|
||||
t.Errorf("acks.largestSeen() = %v, want %v", got, want)
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ func (c *Conn) handleAckOrLoss(space numberSpace, sent *sentPacket, fate packetF
|
||||
switch f := sent.next(); f {
|
||||
default:
|
||||
panic(fmt.Sprintf("BUG: unhandled acked/lost frame type %x", f))
|
||||
case frameTypeAck:
|
||||
case frameTypeAck, frameTypeAckECN:
|
||||
// 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.
|
||||
|
||||
@@ -124,7 +124,7 @@ func (c *Conn) handleLongHeader(now time.Time, dgram *datagram, ptype packetType
|
||||
}
|
||||
c.connIDState.handlePacket(c, p.ptype, p.srcConnID)
|
||||
ackEliciting := c.handleFrames(now, dgram, ptype, space, p.payload)
|
||||
c.acks[space].receive(now, space, p.num, ackEliciting)
|
||||
c.acks[space].receive(now, space, p.num, ackEliciting, dgram.ecn)
|
||||
if p.ptype == packetTypeHandshake && c.side == serverSide {
|
||||
c.loss.validateClientAddress()
|
||||
|
||||
@@ -174,7 +174,7 @@ func (c *Conn) handle1RTT(now time.Time, dgram *datagram, buf []byte) int {
|
||||
c.log1RTTPacketReceived(p, buf)
|
||||
}
|
||||
ackEliciting := c.handleFrames(now, dgram, packetType1RTT, appDataSpace, p.payload)
|
||||
c.acks[appDataSpace].receive(now, appDataSpace, p.num, ackEliciting)
|
||||
c.acks[appDataSpace].receive(now, appDataSpace, p.num, ackEliciting, dgram.ecn)
|
||||
return len(buf)
|
||||
}
|
||||
|
||||
@@ -420,12 +420,15 @@ func (c *Conn) handleFrames(now time.Time, dgram *datagram, ptype packetType, sp
|
||||
|
||||
func (c *Conn) handleAckFrame(now time.Time, space numberSpace, payload []byte) int {
|
||||
c.loss.receiveAckStart()
|
||||
largest, ackDelay, n := consumeAckFrame(payload, func(rangeIndex int, start, end packetNumber) {
|
||||
largest, ackDelay, ecn, n := consumeAckFrame(payload, func(rangeIndex int, start, end packetNumber) {
|
||||
if err := c.loss.receiveAckRange(now, space, rangeIndex, start, end, c.handleAckOrLoss); err != nil {
|
||||
c.abort(now, err)
|
||||
return
|
||||
}
|
||||
})
|
||||
// TODO: Make use of ECN feedback.
|
||||
// https://www.rfc-editor.org/rfc/rfc9000.html#section-19.3.2
|
||||
_ = ecn
|
||||
// Prior to receiving the peer's transport parameters, we cannot
|
||||
// interpret the ACK Delay field because we don't know the ack_delay_exponent
|
||||
// to apply.
|
||||
|
||||
@@ -374,7 +374,7 @@ func (c *Conn) appendAckFrame(now time.Time, space numberSpace) bool {
|
||||
return false
|
||||
}
|
||||
d := unscaledAckDelayFromDuration(delay, ackDelayExponent)
|
||||
return c.w.appendAckFrame(seen, d)
|
||||
return c.w.appendAckFrame(seen, d, c.acks[space].ecn)
|
||||
}
|
||||
|
||||
func (c *Conn) appendConnectionCloseFrame(now time.Time, space numberSpace, err error) {
|
||||
|
||||
@@ -136,11 +136,12 @@ func (f debugFramePing) LogValue() slog.Value {
|
||||
type debugFrameAck struct {
|
||||
ackDelay unscaledAckDelay
|
||||
ranges []i64range[packetNumber]
|
||||
ecn ecnCounts
|
||||
}
|
||||
|
||||
func parseDebugFrameAck(b []byte) (f debugFrameAck, n int) {
|
||||
f.ranges = nil
|
||||
_, f.ackDelay, n = consumeAckFrame(b, func(_ int, start, end packetNumber) {
|
||||
_, f.ackDelay, f.ecn, n = consumeAckFrame(b, func(_ int, start, end packetNumber) {
|
||||
f.ranges = append(f.ranges, i64range[packetNumber]{
|
||||
start: start,
|
||||
end: end,
|
||||
@@ -159,11 +160,15 @@ func (f debugFrameAck) String() string {
|
||||
for _, r := range f.ranges {
|
||||
s += fmt.Sprintf(" [%v,%v)", r.start, r.end)
|
||||
}
|
||||
|
||||
if (f.ecn != ecnCounts{}) {
|
||||
s += fmt.Sprintf(" ECN=[%d,%d,%d]", f.ecn.t0, f.ecn.t1, f.ecn.ce)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (f debugFrameAck) write(w *packetWriter) bool {
|
||||
return w.appendAckFrame(rangeset[packetNumber](f.ranges), f.ackDelay)
|
||||
return w.appendAckFrame(rangeset[packetNumber](f.ranges), f.ackDelay, f.ecn)
|
||||
}
|
||||
|
||||
func (f debugFrameAck) LogValue() slog.Value {
|
||||
|
||||
@@ -263,6 +263,65 @@ func TestFrameEncodeDecode(t *testing.T) {
|
||||
0x0f, // Gap (i)
|
||||
0x0e, // ACK Range Length (i)
|
||||
},
|
||||
}, {
|
||||
s: "ACK Delay=10 [0,16) [17,32) ECN=[1,2,3]",
|
||||
j: `"error: debugFrameAck should not appear as a slog Value"`,
|
||||
f: debugFrameAck{
|
||||
ackDelay: 10,
|
||||
ranges: []i64range[packetNumber]{
|
||||
{0x00, 0x10},
|
||||
{0x11, 0x20},
|
||||
},
|
||||
ecn: ecnCounts{1, 2, 3},
|
||||
},
|
||||
b: []byte{
|
||||
0x03, // TYPE (i) = 0x3
|
||||
0x1f, // Largest Acknowledged (i)
|
||||
10, // ACK Delay (i)
|
||||
0x01, // ACK Range Count (i)
|
||||
0x0e, // First ACK Range (i)
|
||||
0x00, // Gap (i)
|
||||
0x0f, // ACK Range Length (i)
|
||||
0x01, // ECT0 Count (i)
|
||||
0x02, // ECT1 Count (i)
|
||||
0x03, // ECN-CE Count (i)
|
||||
},
|
||||
truncated: []byte{
|
||||
0x03, // TYPE (i) = 0x3
|
||||
0x1f, // Largest Acknowledged (i)
|
||||
10, // ACK Delay (i)
|
||||
0x00, // ACK Range Count (i)
|
||||
0x0e, // First ACK Range (i)
|
||||
0x01, // ECT0 Count (i)
|
||||
0x02, // ECT1 Count (i)
|
||||
0x03, // ECN-CE Count (i)
|
||||
},
|
||||
}, {
|
||||
s: "ACK Delay=10 [17,32) ECN=[1,2,3]",
|
||||
j: `"error: debugFrameAck should not appear as a slog Value"`,
|
||||
f: debugFrameAck{
|
||||
ackDelay: 10,
|
||||
ranges: []i64range[packetNumber]{
|
||||
{0x11, 0x20},
|
||||
},
|
||||
ecn: ecnCounts{1, 2, 3},
|
||||
},
|
||||
b: []byte{
|
||||
0x03, // TYPE (i) = 0x3
|
||||
0x1f, // Largest Acknowledged (i)
|
||||
10, // ACK Delay (i)
|
||||
0x00, // ACK Range Count (i)
|
||||
0x0e, // First ACK Range (i)
|
||||
0x01, // ECT0 Count (i)
|
||||
0x02, // ECT1 Count (i)
|
||||
0x03, // ECN-CE Count (i)
|
||||
},
|
||||
// Downgrading to a type 0x2 ACK frame is not allowed: "Even if an
|
||||
// endpoint does not set an ECT field in packets it sends, the endpoint
|
||||
// MUST provide feedback about ECN markings it receives, if these are
|
||||
// accessible."
|
||||
// https://www.rfc-editor.org/rfc/rfc9000.html#section-13.4.1-2
|
||||
truncated: nil,
|
||||
}, {
|
||||
s: "RESET_STREAM ID=1 Code=2 FinalSize=3",
|
||||
j: `{"frame_type":"reset_stream","stream_id":1,"final_size":3}`,
|
||||
@@ -675,6 +734,7 @@ func TestFrameDecode(t *testing.T) {
|
||||
ranges: []i64range[packetNumber]{
|
||||
{0, 1},
|
||||
},
|
||||
ecn: ecnCounts{1, 2, 3},
|
||||
},
|
||||
b: []byte{
|
||||
0x03, // TYPE (i) = 0x02..0x03
|
||||
|
||||
@@ -157,25 +157,25 @@ func parse1RTTPacket(pkt []byte, k *updatingKeyPair, dstConnIDLen int, pnumMax p
|
||||
// which includes both general parse failures and specific violations of frame
|
||||
// constraints.
|
||||
|
||||
func consumeAckFrame(frame []byte, f func(rangeIndex int, start, end packetNumber)) (largest packetNumber, ackDelay unscaledAckDelay, n int) {
|
||||
func consumeAckFrame(frame []byte, f func(rangeIndex int, start, end packetNumber)) (largest packetNumber, ackDelay unscaledAckDelay, ecn ecnCounts, n int) {
|
||||
b := frame[1:] // type
|
||||
|
||||
largestAck, n := quicwire.ConsumeVarint(b)
|
||||
if n < 0 {
|
||||
return 0, 0, -1
|
||||
return 0, 0, ecnCounts{}, -1
|
||||
}
|
||||
b = b[n:]
|
||||
|
||||
v, n := quicwire.ConsumeVarintInt64(b)
|
||||
if n < 0 {
|
||||
return 0, 0, -1
|
||||
return 0, 0, ecnCounts{}, -1
|
||||
}
|
||||
b = b[n:]
|
||||
ackDelay = unscaledAckDelay(v)
|
||||
|
||||
ackRangeCount, n := quicwire.ConsumeVarint(b)
|
||||
if n < 0 {
|
||||
return 0, 0, -1
|
||||
return 0, 0, ecnCounts{}, -1
|
||||
}
|
||||
b = b[n:]
|
||||
|
||||
@@ -183,12 +183,12 @@ func consumeAckFrame(frame []byte, f func(rangeIndex int, start, end packetNumbe
|
||||
for i := uint64(0); ; i++ {
|
||||
rangeLen, n := quicwire.ConsumeVarint(b)
|
||||
if n < 0 {
|
||||
return 0, 0, -1
|
||||
return 0, 0, ecnCounts{}, -1
|
||||
}
|
||||
b = b[n:]
|
||||
rangeMin := rangeMax - packetNumber(rangeLen)
|
||||
if rangeMin < 0 || rangeMin > rangeMax {
|
||||
return 0, 0, -1
|
||||
return 0, 0, ecnCounts{}, -1
|
||||
}
|
||||
f(int(i), rangeMin, rangeMax+1)
|
||||
|
||||
@@ -198,7 +198,7 @@ func consumeAckFrame(frame []byte, f func(rangeIndex int, start, end packetNumbe
|
||||
|
||||
gap, n := quicwire.ConsumeVarint(b)
|
||||
if n < 0 {
|
||||
return 0, 0, -1
|
||||
return 0, 0, ecnCounts{}, -1
|
||||
}
|
||||
b = b[n:]
|
||||
|
||||
@@ -206,32 +206,30 @@ func consumeAckFrame(frame []byte, f func(rangeIndex int, start, end packetNumbe
|
||||
}
|
||||
|
||||
if frame[0] != frameTypeAckECN {
|
||||
return packetNumber(largestAck), ackDelay, len(frame) - len(b)
|
||||
return packetNumber(largestAck), ackDelay, ecnCounts{}, len(frame) - len(b)
|
||||
}
|
||||
|
||||
ect0Count, n := quicwire.ConsumeVarint(b)
|
||||
if n < 0 {
|
||||
return 0, 0, -1
|
||||
return 0, 0, ecnCounts{}, -1
|
||||
}
|
||||
b = b[n:]
|
||||
ect1Count, n := quicwire.ConsumeVarint(b)
|
||||
if n < 0 {
|
||||
return 0, 0, -1
|
||||
return 0, 0, ecnCounts{}, -1
|
||||
}
|
||||
b = b[n:]
|
||||
ecnCECount, n := quicwire.ConsumeVarint(b)
|
||||
if n < 0 {
|
||||
return 0, 0, -1
|
||||
return 0, 0, ecnCounts{}, -1
|
||||
}
|
||||
b = b[n:]
|
||||
|
||||
// TODO: Make use of ECN feedback.
|
||||
// https://www.rfc-editor.org/rfc/rfc9000.html#section-19.3.2
|
||||
_ = ect0Count
|
||||
_ = ect1Count
|
||||
_ = ecnCECount
|
||||
ecn.t0 = int(ect0Count)
|
||||
ecn.t1 = int(ect1Count)
|
||||
ecn.ce = int(ecnCECount)
|
||||
|
||||
return packetNumber(largestAck), ackDelay, len(frame) - len(b)
|
||||
return packetNumber(largestAck), ackDelay, ecn, len(frame) - len(b)
|
||||
}
|
||||
|
||||
func consumeResetStreamFrame(b []byte) (id streamID, code uint64, finalSize int64, n int) {
|
||||
|
||||
@@ -262,7 +262,7 @@ func (w *packetWriter) appendPingFrame() (added bool) {
|
||||
// to the peer potentially failing to receive an acknowledgement
|
||||
// for an older packet during a period of high packet loss or
|
||||
// reordering. This may result in unnecessary retransmissions.
|
||||
func (w *packetWriter) appendAckFrame(seen rangeset[packetNumber], delay unscaledAckDelay) (added bool) {
|
||||
func (w *packetWriter) appendAckFrame(seen rangeset[packetNumber], delay unscaledAckDelay, ecn ecnCounts) (added bool) {
|
||||
if len(seen) == 0 {
|
||||
return false
|
||||
}
|
||||
@@ -270,10 +270,20 @@ func (w *packetWriter) appendAckFrame(seen rangeset[packetNumber], delay unscale
|
||||
largest = uint64(seen.max())
|
||||
firstRange = uint64(seen[len(seen)-1].size() - 1)
|
||||
)
|
||||
if w.avail() < 1+quicwire.SizeVarint(largest)+quicwire.SizeVarint(uint64(delay))+1+quicwire.SizeVarint(firstRange) {
|
||||
var ecnLen int
|
||||
ackType := byte(frameTypeAck)
|
||||
if (ecn != ecnCounts{}) {
|
||||
// "Even if an endpoint does not set an ECT field in packets it sends,
|
||||
// the endpoint MUST provide feedback about ECN markings it receives, if
|
||||
// these are accessible."
|
||||
// https://www.rfc-editor.org/rfc/rfc9000.html#section-13.4.1-2
|
||||
ecnLen = quicwire.SizeVarint(uint64(ecn.ce)) + quicwire.SizeVarint(uint64(ecn.t0)) + quicwire.SizeVarint(uint64(ecn.t1))
|
||||
ackType = frameTypeAckECN
|
||||
}
|
||||
if w.avail() < 1+quicwire.SizeVarint(largest)+quicwire.SizeVarint(uint64(delay))+1+quicwire.SizeVarint(firstRange)+ecnLen {
|
||||
return false
|
||||
}
|
||||
w.b = append(w.b, frameTypeAck)
|
||||
w.b = append(w.b, ackType)
|
||||
w.b = quicwire.AppendVarint(w.b, largest)
|
||||
w.b = quicwire.AppendVarint(w.b, uint64(delay))
|
||||
// The range count is technically a varint, but we'll reserve a single byte for it
|
||||
@@ -285,7 +295,7 @@ func (w *packetWriter) appendAckFrame(seen rangeset[packetNumber], delay unscale
|
||||
for i := len(seen) - 2; i >= 0; i-- {
|
||||
gap := uint64(seen[i+1].start - seen[i].end - 1)
|
||||
size := uint64(seen[i].size() - 1)
|
||||
if w.avail() < quicwire.SizeVarint(gap)+quicwire.SizeVarint(size) || rangeCount > 62 {
|
||||
if w.avail() < quicwire.SizeVarint(gap)+quicwire.SizeVarint(size)+ecnLen || rangeCount > 62 {
|
||||
break
|
||||
}
|
||||
w.b = quicwire.AppendVarint(w.b, gap)
|
||||
@@ -293,7 +303,12 @@ func (w *packetWriter) appendAckFrame(seen rangeset[packetNumber], delay unscale
|
||||
rangeCount++
|
||||
}
|
||||
w.b[rangeCountOff] = rangeCount
|
||||
w.sent.appendNonAckElicitingFrame(frameTypeAck)
|
||||
if ackType == frameTypeAckECN {
|
||||
w.b = quicwire.AppendVarint(w.b, uint64(ecn.t0))
|
||||
w.b = quicwire.AppendVarint(w.b, uint64(ecn.t1))
|
||||
w.b = quicwire.AppendVarint(w.b, uint64(ecn.ce))
|
||||
}
|
||||
w.sent.appendNonAckElicitingFrame(ackType)
|
||||
w.sent.appendInt(uint64(seen.max()))
|
||||
return true
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user