Merge pull request #1892 from lucas-clemente/max-ack-delay

send and receive the max_ack_delay, use it for RTT estimation and PTO calculation
This commit is contained in:
Marten Seemann
2019-05-12 23:16:19 +08:00
committed by GitHub
15 changed files with 173 additions and 70 deletions

View File

@@ -352,6 +352,7 @@ func (c *client) createNewTLSSession(version protocol.VersionNumber) error {
IdleTimeout: c.config.IdleTimeout,
MaxBidiStreams: uint64(c.config.MaxIncomingStreams),
MaxUniStreams: uint64(c.config.MaxIncomingUniStreams),
MaxAckDelay: protocol.MaxAckDelayInclGranularity,
AckDelayExponent: protocol.AckDelayExponent,
DisableMigration: true,
}

View File

@@ -13,6 +13,7 @@ type SentPacketHandler interface {
SentPacket(packet *Packet)
SentPacketsAsRetransmission(packets []*Packet, retransmissionOf protocol.PacketNumber)
ReceivedAck(ackFrame *wire.AckFrame, withPacketNumber protocol.PacketNumber, encLevel protocol.EncryptionLevel, recvTime time.Time) error
SetMaxAckDelay(time.Duration)
SetHandshakeComplete()
ResetForRetry() error

View File

@@ -11,8 +11,6 @@ import (
)
const (
// maximum delay that can be applied to an ACK for an ack-eliciting packet
ackSendDelay = 25 * time.Millisecond
// initial maximum number of ack-eliciting packets received before sending an ack.
initialAckElicitingPacketsBeforeAck = 2
// number of ack-eliciting that an ACK is sent for
@@ -85,14 +83,21 @@ func (h *receivedPacketHandler) GetAlarmTimeout() time.Time {
}
func (h *receivedPacketHandler) GetAckFrame(encLevel protocol.EncryptionLevel) *wire.AckFrame {
var ack *wire.AckFrame
switch encLevel {
case protocol.EncryptionInitial:
return h.initialPackets.GetAckFrame()
ack = h.initialPackets.GetAckFrame()
case protocol.EncryptionHandshake:
return h.handshakePackets.GetAckFrame()
ack = h.handshakePackets.GetAckFrame()
case protocol.Encryption1RTT:
return h.oneRTTPackets.GetAckFrame()
default:
return nil
}
// For Initial and Handshake ACKs, the delay time is ignored by the receiver.
// Set it to 0 in order to save bytes.
if ack != nil {
ack.DelayTime = 0
}
return ack
}

View File

@@ -24,24 +24,27 @@ var _ = Describe("Received Packet Handler", func() {
})
It("generates ACKs for different packet number spaces", func() {
now := time.Now()
Expect(handler.ReceivedPacket(2, protocol.EncryptionInitial, now, true)).To(Succeed())
Expect(handler.ReceivedPacket(1, protocol.EncryptionHandshake, now, true)).To(Succeed())
Expect(handler.ReceivedPacket(5, protocol.Encryption1RTT, now, true)).To(Succeed())
Expect(handler.ReceivedPacket(3, protocol.EncryptionInitial, now, true)).To(Succeed())
Expect(handler.ReceivedPacket(2, protocol.EncryptionHandshake, now, true)).To(Succeed())
Expect(handler.ReceivedPacket(4, protocol.Encryption1RTT, now, true)).To(Succeed())
sendTime := time.Now().Add(-time.Second)
Expect(handler.ReceivedPacket(2, protocol.EncryptionInitial, sendTime, true)).To(Succeed())
Expect(handler.ReceivedPacket(1, protocol.EncryptionHandshake, sendTime, true)).To(Succeed())
Expect(handler.ReceivedPacket(5, protocol.Encryption1RTT, sendTime, true)).To(Succeed())
Expect(handler.ReceivedPacket(3, protocol.EncryptionInitial, sendTime, true)).To(Succeed())
Expect(handler.ReceivedPacket(2, protocol.EncryptionHandshake, sendTime, true)).To(Succeed())
Expect(handler.ReceivedPacket(4, protocol.Encryption1RTT, sendTime, true)).To(Succeed())
initialAck := handler.GetAckFrame(protocol.EncryptionInitial)
Expect(initialAck).ToNot(BeNil())
Expect(initialAck.AckRanges).To(HaveLen(1))
Expect(initialAck.AckRanges[0]).To(Equal(wire.AckRange{Smallest: 2, Largest: 3}))
Expect(initialAck.DelayTime).To(BeZero())
handshakeAck := handler.GetAckFrame(protocol.EncryptionHandshake)
Expect(handshakeAck).ToNot(BeNil())
Expect(handshakeAck.AckRanges).To(HaveLen(1))
Expect(handshakeAck.AckRanges[0]).To(Equal(wire.AckRange{Smallest: 1, Largest: 2}))
Expect(handshakeAck.DelayTime).To(BeZero())
oneRTTAck := handler.GetAckFrame(protocol.Encryption1RTT)
Expect(oneRTTAck).ToNot(BeNil())
Expect(oneRTTAck.AckRanges).To(HaveLen(1))
Expect(oneRTTAck.AckRanges[0]).To(Equal(wire.AckRange{Smallest: 4, Largest: 5}))
Expect(oneRTTAck.DelayTime).To(BeNumerically("~", time.Second, 50*time.Millisecond))
})
})

View File

@@ -16,8 +16,8 @@ type receivedPacketTracker struct {
packetHistory *receivedPacketHistory
ackSendDelay time.Duration
rttStats *congestion.RTTStats
maxAckDelay time.Duration
rttStats *congestion.RTTStats
packetsReceivedSinceLastAck int
ackElicitingPacketsReceivedSinceLastAck int
@@ -37,7 +37,7 @@ func newReceivedPacketTracker(
) *receivedPacketTracker {
return &receivedPacketTracker{
packetHistory: newReceivedPacketHistory(),
ackSendDelay: ackSendDelay,
maxAckDelay: protocol.MaxAckDelay,
rttStats: rttStats,
logger: logger,
version: version,
@@ -126,7 +126,7 @@ func (h *receivedPacketTracker) maybeQueueAck(packetNumber protocol.PacketNumber
}
} else if h.ackAlarm.IsZero() {
// wait for the minimum of the ack decimation delay or the delayed ack time before sending an ack
ackDelay := utils.MinDuration(ackSendDelay, time.Duration(float64(h.rttStats.MinRTT())*float64(ackDecimationDelay)))
ackDelay := utils.MinDuration(h.maxAckDelay, time.Duration(float64(h.rttStats.MinRTT())*float64(ackDecimationDelay)))
h.ackAlarm = rcvTime.Add(ackDelay)
if h.logger.Debug() {
h.logger.Debugf("\tSetting ACK timer to min(1/4 min-RTT, max ack delay): %s (%s from now)", ackDelay, time.Until(h.ackAlarm))
@@ -141,9 +141,9 @@ func (h *receivedPacketTracker) maybeQueueAck(packetNumber protocol.PacketNumber
h.ackQueued = true
} else if h.ackAlarm.IsZero() {
if h.logger.Debug() {
h.logger.Debugf("\tSetting ACK timer to max ack delay: %s", ackSendDelay)
h.logger.Debugf("\tSetting ACK timer to max ack delay: %s", h.maxAckDelay)
}
h.ackAlarm = rcvTime.Add(ackSendDelay)
h.ackAlarm = rcvTime.Add(h.maxAckDelay)
}
}
// If there are new missing packets to report, set a short timer to send an ACK.

View File

@@ -151,7 +151,7 @@ var _ = Describe("Received Packet Tracker", func() {
err = tracker.ReceivedPacket(12, rcvTime, true)
Expect(err).ToNot(HaveOccurred())
Expect(tracker.ackQueued).To(BeFalse())
Expect(tracker.GetAlarmTimeout()).To(Equal(rcvTime.Add(ackSendDelay)))
Expect(tracker.GetAlarmTimeout()).To(Equal(rcvTime.Add(protocol.MaxAckDelay)))
})
It("queues an ACK if it was reported missing before", func() {

View File

@@ -17,8 +17,6 @@ const (
// Maximum reordering in time space before time based loss detection considers a packet lost.
// Specified as an RTT multiplier.
timeThreshold = 9.0 / 8
// Timer granularity. The timer will not be set to a value smaller than granularity.
granularity = time.Millisecond
)
type packetNumberSpace struct {
@@ -60,6 +58,7 @@ type sentPacketHandler struct {
rttStats *congestion.RTTStats
handshakeComplete bool
maxAckDelay time.Duration
// The number of times the crypto packets have been retransmitted without receiving an ack.
cryptoCount uint32
@@ -124,6 +123,10 @@ func (h *sentPacketHandler) SetHandshakeComplete() {
h.handshakeComplete = true
}
func (h *sentPacketHandler) SetMaxAckDelay(mad time.Duration) {
h.maxAckDelay = mad
}
func (h *sentPacketHandler) SentPacket(packet *Packet) {
if isAckEliciting := h.sentPacketImpl(packet); isAckEliciting {
h.getPacketNumberSpace(packet.EncryptionLevel).history.SentPacket(packet)
@@ -207,7 +210,12 @@ func (h *sentPacketHandler) ReceivedAck(ackFrame *wire.AckFrame, withPacketNumbe
// maybe update the RTT
if p := pnSpace.history.GetPacket(ackFrame.LargestAcked()); p != nil {
h.rttStats.UpdateRTT(rcvTime.Sub(p.SendTime), ackFrame.DelayTime, rcvTime)
// don't use the ack delay for Initial and Handshake packets
var ackDelay time.Duration
if encLevel == protocol.Encryption1RTT {
ackDelay = utils.MinDuration(ackFrame.DelayTime, h.maxAckDelay)
}
h.rttStats.UpdateRTT(rcvTime.Sub(p.SendTime), ackDelay, rcvTime)
if h.logger.Debug() {
h.logger.Debugf("\tupdated RTT: %s (σ: %s)", h.rttStats.SmoothedRTT(), h.rttStats.MeanDeviation())
}
@@ -341,7 +349,7 @@ func (h *sentPacketHandler) detectLostPackets(
lossDelay := time.Duration(timeThreshold * maxRTT)
// Minimum time of granularity before packets are deemed lost.
lossDelay = utils.MaxDuration(lossDelay, granularity)
lossDelay = utils.MaxDuration(lossDelay, protocol.TimerGranularity)
var lostPackets []*Packet
pnSpace.history.Iterate(func(packet *Packet) (bool, error) {
@@ -616,15 +624,14 @@ func (h *sentPacketHandler) queuePacketForRetransmission(p *Packet, pnSpace *pac
}
func (h *sentPacketHandler) computeCryptoTimeout() time.Duration {
duration := utils.MaxDuration(2*h.rttStats.SmoothedOrInitialRTT(), granularity)
duration := utils.MaxDuration(2*h.rttStats.SmoothedOrInitialRTT(), protocol.TimerGranularity)
// exponential backoff
// There's an implicit limit to this set by the crypto timeout.
return duration << h.cryptoCount
}
func (h *sentPacketHandler) computePTOTimeout() time.Duration {
// TODO(#1236): include the max_ack_delay
duration := utils.MaxDuration(h.rttStats.SmoothedOrInitialRTT()+4*h.rttStats.MeanDeviation(), granularity)
duration := h.rttStats.SmoothedOrInitialRTT() + utils.MaxDuration(4*h.rttStats.MeanDeviation(), protocol.TimerGranularity) + h.maxAckDelay
return duration << h.ptoCount
}

View File

@@ -292,19 +292,45 @@ var _ = Describe("SentPacketHandler", func() {
Expect(handler.rttStats.LatestRTT()).To(BeNumerically("~", 1*time.Minute, 1*time.Second))
})
It("uses the DelayTime in the ACK frame", func() {
now := time.Now()
It("ignores the DelayTime for Initial and Handshake packets", func() {
handler.SentPacket(cryptoPacket(&Packet{PacketNumber: 1}))
handler.SetMaxAckDelay(time.Hour)
// make sure the rttStats have a min RTT, so that the delay is used
handler.rttStats.UpdateRTT(5*time.Minute, 0, time.Now())
getPacket(1, protocol.Encryption1RTT).SendTime = now.Add(-10 * time.Minute)
getPacket(1, protocol.EncryptionInitial).SendTime = time.Now().Add(-10 * time.Minute)
ack := &wire.AckFrame{
AckRanges: []wire.AckRange{{Smallest: 1, Largest: 1}},
DelayTime: 5 * time.Minute,
}
err := handler.ReceivedAck(ack, 1, protocol.Encryption1RTT, time.Now())
Expect(err).NotTo(HaveOccurred())
Expect(handler.ReceivedAck(ack, 1, protocol.EncryptionInitial, time.Now())).To(Succeed())
Expect(handler.rttStats.LatestRTT()).To(BeNumerically("~", 10*time.Minute, 1*time.Second))
})
It("uses the DelayTime in the ACK frame", func() {
handler.SetMaxAckDelay(time.Hour)
// make sure the rttStats have a min RTT, so that the delay is used
handler.rttStats.UpdateRTT(5*time.Minute, 0, time.Now())
getPacket(1, protocol.Encryption1RTT).SendTime = time.Now().Add(-10 * time.Minute)
ack := &wire.AckFrame{
AckRanges: []wire.AckRange{{Smallest: 1, Largest: 1}},
DelayTime: 5 * time.Minute,
}
Expect(handler.ReceivedAck(ack, 1, protocol.Encryption1RTT, time.Now())).To(Succeed())
Expect(handler.rttStats.LatestRTT()).To(BeNumerically("~", 5*time.Minute, 1*time.Second))
})
It("limits the DelayTime in the ACK frame to max_ack_delay", func() {
handler.SetMaxAckDelay(time.Minute)
// make sure the rttStats have a min RTT, so that the delay is used
handler.rttStats.UpdateRTT(5*time.Minute, 0, time.Now())
getPacket(1, protocol.Encryption1RTT).SendTime = time.Now().Add(-10 * time.Minute)
ack := &wire.AckFrame{
AckRanges: []wire.AckRange{{Smallest: 1, Largest: 1}},
DelayTime: 5 * time.Minute,
}
Expect(handler.ReceivedAck(ack, 1, protocol.Encryption1RTT, time.Now())).To(Succeed())
Expect(handler.rttStats.LatestRTT()).To(BeNumerically("~", 9*time.Minute, 1*time.Second))
})
})
Context("determining which ACKs we have received an ACK for", func() {
@@ -593,7 +619,7 @@ var _ = Describe("SentPacketHandler", func() {
It("uses the granularity for short RTTs", func() {
rtt := time.Microsecond
updateRTT(rtt)
Expect(handler.computePTOTimeout()).To(Equal(granularity))
Expect(handler.computePTOTimeout()).To(Equal(rtt + protocol.TimerGranularity))
})
It("implements exponential backoff", func() {

View File

@@ -31,9 +31,10 @@ var _ = Describe("Transport Parameters", func() {
IdleTimeout: 42 * time.Second,
OriginalConnectionID: protocol.ConnectionID{0xde, 0xad, 0xbe, 0xef},
AckDelayExponent: 14,
MaxAckDelay: 37 * time.Millisecond,
StatelessResetToken: &[16]byte{0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00},
}
Expect(p.String()).To(Equal("&handshake.TransportParameters{OriginalConnectionID: 0xdeadbeef, InitialMaxStreamDataBidiLocal: 0x1234, InitialMaxStreamDataBidiRemote: 0x2345, InitialMaxStreamDataUni: 0x3456, InitialMaxData: 0x4567, MaxBidiStreams: 1337, MaxUniStreams: 7331, IdleTimeout: 42s, AckDelayExponent: 14, StatelessResetToken: 0x112233445566778899aabbccddeeff00}"))
Expect(p.String()).To(Equal("&handshake.TransportParameters{OriginalConnectionID: 0xdeadbeef, InitialMaxStreamDataBidiLocal: 0x1234, InitialMaxStreamDataBidiRemote: 0x2345, InitialMaxStreamDataUni: 0x3456, InitialMaxData: 0x4567, MaxBidiStreams: 1337, MaxUniStreams: 7331, IdleTimeout: 42s, AckDelayExponent: 14, MaxAckDelay: 37ms, StatelessResetToken: 0x112233445566778899aabbccddeeff00}"))
})
It("has a string representation, if there's no stateless reset token", func() {
@@ -47,17 +48,18 @@ var _ = Describe("Transport Parameters", func() {
IdleTimeout: 42 * time.Second,
OriginalConnectionID: protocol.ConnectionID{0xde, 0xad, 0xbe, 0xef},
AckDelayExponent: 14,
MaxAckDelay: 37 * time.Second,
}
Expect(p.String()).To(Equal("&handshake.TransportParameters{OriginalConnectionID: 0xdeadbeef, InitialMaxStreamDataBidiLocal: 0x1234, InitialMaxStreamDataBidiRemote: 0x2345, InitialMaxStreamDataUni: 0x3456, InitialMaxData: 0x4567, MaxBidiStreams: 1337, MaxUniStreams: 7331, IdleTimeout: 42s, AckDelayExponent: 14}"))
Expect(p.String()).To(Equal("&handshake.TransportParameters{OriginalConnectionID: 0xdeadbeef, InitialMaxStreamDataBidiLocal: 0x1234, InitialMaxStreamDataBidiRemote: 0x2345, InitialMaxStreamDataUni: 0x3456, InitialMaxData: 0x4567, MaxBidiStreams: 1337, MaxUniStreams: 7331, IdleTimeout: 42s, AckDelayExponent: 14, MaxAckDelay: 37s}"))
})
getRandomValue := func() uint64 {
maxVals := []int64{math.MaxUint8 / 4, math.MaxUint16 / 4, math.MaxUint32 / 4, math.MaxUint64 / 4}
rand.Seed(GinkgoRandomSeed())
return uint64(rand.Int63n(maxVals[int(rand.Int31n(4))]))
}
It("marshals and unmarshals", func() {
rand.Seed(GinkgoRandomSeed())
getRandomValue := func() uint64 {
maxVals := []int64{math.MaxUint8 / 4, math.MaxUint16 / 4, math.MaxUint32 / 4, math.MaxUint64 / 4}
return uint64(rand.Int63n(maxVals[int(rand.Int31n(4))]))
}
var token [16]byte
rand.Read(token[:])
params := &TransportParameters{
@@ -72,6 +74,7 @@ var _ = Describe("Transport Parameters", func() {
StatelessResetToken: &token,
OriginalConnectionID: protocol.ConnectionID{0xde, 0xad, 0xbe, 0xef},
AckDelayExponent: 13,
MaxAckDelay: 42 * time.Millisecond,
}
data := params.Marshal()
@@ -88,6 +91,7 @@ var _ = Describe("Transport Parameters", func() {
Expect(p.StatelessResetToken).To(Equal(params.StatelessResetToken))
Expect(p.OriginalConnectionID).To(Equal(protocol.ConnectionID{0xde, 0xad, 0xbe, 0xef}))
Expect(p.AckDelayExponent).To(Equal(uint8(13)))
Expect(p.MaxAckDelay).To(Equal(42 * time.Millisecond))
})
It("errors if the transport parameters are too short to contain the length", func() {
@@ -128,6 +132,19 @@ var _ = Describe("Transport Parameters", func() {
Expect(p.Unmarshal(prependLength(b.Bytes()), protocol.PerspectiveServer)).To(MatchError("wrong length for disable_migration: 6 (expected empty)"))
})
It("errors when the max_ack_delay is too large", func() {
data := (&TransportParameters{MaxAckDelay: 1 << 14 * time.Millisecond}).Marshal()
p := &TransportParameters{}
Expect(p.Unmarshal(data, protocol.PerspectiveServer)).To(MatchError("invalid value for max_ack_delay: 16384ms (maximum 16383ms)"))
})
It("doesn't send the max_ack_delay, if it has the default value", func() {
dataDefault := (&TransportParameters{MaxAckDelay: protocol.DefaultMaxAckDelay}).Marshal()
defaultLen := len(dataDefault)
data := (&TransportParameters{MaxAckDelay: protocol.DefaultMaxAckDelay + time.Millisecond}).Marshal()
Expect(len(data)).To(Equal(defaultLen + 2 /* parameter ID */ + 2 /* length field */ + 1 /* value */))
})
It("errors when the ack_delay_exponenent is too large", func() {
data := (&TransportParameters{AckDelayExponent: 21}).Marshal()
p := &TransportParameters{}

View File

@@ -27,6 +27,7 @@ const (
initialMaxStreamsBidiParameterID transportParameterID = 0x8
initialMaxStreamsUniParameterID transportParameterID = 0x9
ackDelayExponentParameterID transportParameterID = 0xa
maxAckDelayParameterID transportParameterID = 0xb
disableMigrationParameterID transportParameterID = 0xc
)
@@ -37,6 +38,7 @@ type TransportParameters struct {
InitialMaxStreamDataUni protocol.ByteCount
InitialMaxData protocol.ByteCount
MaxAckDelay time.Duration
AckDelayExponent uint8
MaxPacketSize protocol.ByteCount
@@ -65,6 +67,7 @@ func (p *TransportParameters) Unmarshal(data []byte, sentBy protocol.Perspective
var parameterIDs []transportParameterID
var readAckDelayExponent bool
var readMaxAckDelay bool
r := bytes.NewReader(data[2:])
for r.Len() >= 4 {
@@ -75,7 +78,14 @@ func (p *TransportParameters) Unmarshal(data []byte, sentBy protocol.Perspective
switch paramID {
case ackDelayExponentParameterID:
readAckDelayExponent = true
fallthrough
if err := p.readNumericTransportParameter(r, paramID, int(paramLen)); err != nil {
return err
}
case maxAckDelayParameterID:
readMaxAckDelay = true
if err := p.readNumericTransportParameter(r, paramID, int(paramLen)); err != nil {
return err
}
case initialMaxStreamDataBidiLocalParameterID,
initialMaxStreamDataBidiRemoteParameterID,
initialMaxStreamDataUniParameterID,
@@ -121,6 +131,9 @@ func (p *TransportParameters) Unmarshal(data []byte, sentBy protocol.Perspective
if !readAckDelayExponent {
p.AckDelayExponent = protocol.DefaultAckDelayExponent
}
if !readMaxAckDelay {
p.MaxAckDelay = protocol.DefaultMaxAckDelay
}
// check that every transport parameter was sent at most once
sort.Slice(parameterIDs, func(i, j int) bool { return parameterIDs[i] < parameterIDs[j] })
@@ -174,6 +187,12 @@ func (p *TransportParameters) readNumericTransportParameter(
return fmt.Errorf("invalid value for ack_delay_exponent: %d (maximum %d)", val, protocol.MaxAckDelayExponent)
}
p.AckDelayExponent = uint8(val)
case maxAckDelayParameterID:
maxAckDelay := time.Duration(val) * time.Millisecond
if maxAckDelay >= protocol.MaxMaxAckDelay {
return fmt.Errorf("invalid value for max_ack_delay: %dms (maximum %dms)", maxAckDelay/time.Millisecond, (protocol.MaxMaxAckDelay-time.Millisecond)/time.Millisecond)
}
p.MaxAckDelay = maxAckDelay
default:
return fmt.Errorf("TransportParameter BUG: transport parameter %d not found", paramID)
}
@@ -186,44 +205,30 @@ func (p *TransportParameters) Marshal() []byte {
b.Write([]byte{0, 0}) // length. Will be replaced later
// initial_max_stream_data_bidi_local
utils.BigEndian.WriteUint16(b, uint16(initialMaxStreamDataBidiLocalParameterID))
utils.BigEndian.WriteUint16(b, uint16(utils.VarIntLen(uint64(p.InitialMaxStreamDataBidiLocal))))
utils.WriteVarInt(b, uint64(p.InitialMaxStreamDataBidiLocal))
p.marshalVarintParam(b, initialMaxStreamDataBidiLocalParameterID, uint64(p.InitialMaxStreamDataBidiLocal))
// initial_max_stream_data_bidi_remote
utils.BigEndian.WriteUint16(b, uint16(initialMaxStreamDataBidiRemoteParameterID))
utils.BigEndian.WriteUint16(b, uint16(utils.VarIntLen(uint64(p.InitialMaxStreamDataBidiRemote))))
utils.WriteVarInt(b, uint64(p.InitialMaxStreamDataBidiRemote))
p.marshalVarintParam(b, initialMaxStreamDataBidiRemoteParameterID, uint64(p.InitialMaxStreamDataBidiRemote))
// initial_max_stream_data_uni
utils.BigEndian.WriteUint16(b, uint16(initialMaxStreamDataUniParameterID))
utils.BigEndian.WriteUint16(b, uint16(utils.VarIntLen(uint64(p.InitialMaxStreamDataUni))))
utils.WriteVarInt(b, uint64(p.InitialMaxStreamDataUni))
p.marshalVarintParam(b, initialMaxStreamDataUniParameterID, uint64(p.InitialMaxStreamDataUni))
// initial_max_data
utils.BigEndian.WriteUint16(b, uint16(initialMaxDataParameterID))
utils.BigEndian.WriteUint16(b, uint16(utils.VarIntLen(uint64(p.InitialMaxData))))
utils.WriteVarInt(b, uint64(p.InitialMaxData))
p.marshalVarintParam(b, initialMaxDataParameterID, uint64(p.InitialMaxData))
// initial_max_bidi_streams
utils.BigEndian.WriteUint16(b, uint16(initialMaxStreamsBidiParameterID))
utils.BigEndian.WriteUint16(b, uint16(utils.VarIntLen(p.MaxBidiStreams)))
utils.WriteVarInt(b, p.MaxBidiStreams)
p.marshalVarintParam(b, initialMaxStreamsBidiParameterID, p.MaxBidiStreams)
// initial_max_uni_streams
utils.BigEndian.WriteUint16(b, uint16(initialMaxStreamsUniParameterID))
utils.BigEndian.WriteUint16(b, uint16(utils.VarIntLen(p.MaxUniStreams)))
utils.WriteVarInt(b, p.MaxUniStreams)
p.marshalVarintParam(b, initialMaxStreamsUniParameterID, p.MaxUniStreams)
// idle_timeout
idleTimeout := uint64(p.IdleTimeout / time.Millisecond)
utils.BigEndian.WriteUint16(b, uint16(idleTimeoutParameterID))
utils.BigEndian.WriteUint16(b, uint16(utils.VarIntLen(idleTimeout)))
utils.WriteVarInt(b, idleTimeout)
p.marshalVarintParam(b, idleTimeoutParameterID, uint64(p.IdleTimeout/time.Millisecond))
// max_packet_size
utils.BigEndian.WriteUint16(b, uint16(maxPacketSizeParameterID))
utils.BigEndian.WriteUint16(b, uint16(utils.VarIntLen(uint64(protocol.MaxReceivePacketSize))))
utils.WriteVarInt(b, uint64(protocol.MaxReceivePacketSize))
p.marshalVarintParam(b, maxPacketSizeParameterID, uint64(protocol.MaxReceivePacketSize))
// max_ack_delay
// Only send it if is different from the default value.
if p.MaxAckDelay != protocol.DefaultMaxAckDelay {
p.marshalVarintParam(b, maxAckDelayParameterID, uint64(p.MaxAckDelay/time.Millisecond))
}
// ack_delay_exponent
// Only send it if is different from the default value.
if p.AckDelayExponent != protocol.DefaultAckDelayExponent {
utils.BigEndian.WriteUint16(b, uint16(ackDelayExponentParameterID))
utils.BigEndian.WriteUint16(b, uint16(utils.VarIntLen(uint64(p.AckDelayExponent))))
utils.WriteVarInt(b, uint64(p.AckDelayExponent))
p.marshalVarintParam(b, ackDelayExponentParameterID, uint64(p.AckDelayExponent))
}
// disable_migration
if p.DisableMigration {
@@ -247,10 +252,16 @@ func (p *TransportParameters) Marshal() []byte {
return data
}
func (p *TransportParameters) marshalVarintParam(b *bytes.Buffer, id transportParameterID, val uint64) {
utils.BigEndian.WriteUint16(b, uint16(id))
utils.BigEndian.WriteUint16(b, uint16(utils.VarIntLen(val)))
utils.WriteVarInt(b, val)
}
// String returns a string representation, intended for logging.
func (p *TransportParameters) String() string {
logString := "&handshake.TransportParameters{OriginalConnectionID: %s, InitialMaxStreamDataBidiLocal: %#x, InitialMaxStreamDataBidiRemote: %#x, InitialMaxStreamDataUni: %#x, InitialMaxData: %#x, MaxBidiStreams: %d, MaxUniStreams: %d, IdleTimeout: %s, AckDelayExponent: %d"
logParams := []interface{}{p.OriginalConnectionID, p.InitialMaxStreamDataBidiLocal, p.InitialMaxStreamDataBidiRemote, p.InitialMaxStreamDataUni, p.InitialMaxData, p.MaxBidiStreams, p.MaxUniStreams, p.IdleTimeout, p.AckDelayExponent}
logString := "&handshake.TransportParameters{OriginalConnectionID: %s, InitialMaxStreamDataBidiLocal: %#x, InitialMaxStreamDataBidiRemote: %#x, InitialMaxStreamDataUni: %#x, InitialMaxData: %#x, MaxBidiStreams: %d, MaxUniStreams: %d, IdleTimeout: %s, AckDelayExponent: %d, MaxAckDelay: %s"
logParams := []interface{}{p.OriginalConnectionID, p.InitialMaxStreamDataBidiLocal, p.InitialMaxStreamDataBidiRemote, p.InitialMaxStreamDataUni, p.InitialMaxData, p.MaxBidiStreams, p.MaxUniStreams, p.IdleTimeout, p.AckDelayExponent, p.MaxAckDelay}
if p.StatelessResetToken != nil { // the client never sends a stateless reset token
logString += ", StatelessResetToken: %#x"
logParams = append(logParams, *p.StatelessResetToken)

View File

@@ -215,6 +215,18 @@ func (mr *MockSentPacketHandlerMockRecorder) SetHandshakeComplete() *gomock.Call
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetHandshakeComplete", reflect.TypeOf((*MockSentPacketHandler)(nil).SetHandshakeComplete))
}
// SetMaxAckDelay mocks base method
func (m *MockSentPacketHandler) SetMaxAckDelay(arg0 time.Duration) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "SetMaxAckDelay", arg0)
}
// SetMaxAckDelay indicates an expected call of SetMaxAckDelay
func (mr *MockSentPacketHandlerMockRecorder) SetMaxAckDelay(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetMaxAckDelay", reflect.TypeOf((*MockSentPacketHandler)(nil).SetMaxAckDelay), arg0)
}
// ShouldSendNumPackets mocks base method
func (m *MockSentPacketHandler) ShouldSendNumPackets() int {
m.ctrl.T.Helper()

View File

@@ -125,3 +125,14 @@ const DefaultConnectionIDLength = 4
// AckDelayExponent is the ack delay exponent used when sending ACKs.
const AckDelayExponent = 3
// Estimated timer granularity.
// The loss detection timer will not be set to a value smaller than granularity.
const TimerGranularity = time.Millisecond
// MaxAckDelay is the maximum time by which we delay sending ACKs.
const MaxAckDelay = 25 * time.Millisecond
// MaxAckDelayInclGranularity is the max_ack_delay including the timer granularity.
// This is the value that should be advertised to the peer.
const MaxAckDelayInclGranularity = MaxAckDelay + TimerGranularity

View File

@@ -2,6 +2,7 @@ package protocol
import (
"fmt"
"time"
)
// A PacketNumber in QUIC
@@ -73,3 +74,9 @@ const DefaultAckDelayExponent = 3
// MaxAckDelayExponent is the maximum ack delay exponent
const MaxAckDelayExponent = 20
// DefaultMaxAckDelay is the default max_ack_delay
const DefaultMaxAckDelay = 25 * time.Millisecond
// MaxMaxAckDelay is the maximum max_ack_delay
const MaxMaxAckDelay = 1 << 14 * time.Millisecond

View File

@@ -442,6 +442,7 @@ func (s *server) createNewSession(
IdleTimeout: s.config.IdleTimeout,
MaxBidiStreams: uint64(s.config.MaxIncomingStreams),
MaxUniStreams: uint64(s.config.MaxIncomingUniStreams),
MaxAckDelay: protocol.MaxAckDelayInclGranularity,
AckDelayExponent: protocol.AckDelayExponent,
DisableMigration: true,
StatelessResetToken: &token,

View File

@@ -939,6 +939,7 @@ func (s *session) processTransportParameters(data []byte) {
s.packer.HandleTransportParameters(params)
s.frameParser.SetAckDelayExponent(params.AckDelayExponent)
s.connFlowController.UpdateSendWindow(params.InitialMaxData)
s.sentPacketHandler.SetMaxAckDelay(params.MaxAckDelay)
if params.StatelessResetToken != nil {
s.sessionRunner.AddResetToken(*params.StatelessResetToken, s)
}