forked from quic-go/quic-go
Merge pull request #2203 from lucas-clemente/randomize-conn-id-change
randomize the number of packets sent with the same connection ID
This commit is contained in:
@@ -1,7 +1,10 @@
|
||||
package quic
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
mrand "math/rand"
|
||||
|
||||
"github.com/lucas-clemente/quic-go/internal/protocol"
|
||||
"github.com/lucas-clemente/quic-go/internal/utils"
|
||||
@@ -15,7 +18,12 @@ type connIDManager struct {
|
||||
activeConnectionID protocol.ConnectionID
|
||||
activeStatelessResetToken *[16]byte
|
||||
|
||||
// We change the connection ID after sending on average
|
||||
// protocol.PacketsPerConnectionID packets. The actual value is randomized
|
||||
// hide the packet loss rate from on-path observers.
|
||||
packetsSinceLastChange uint64
|
||||
rand *mrand.Rand
|
||||
packetsPerConnectionID uint64
|
||||
|
||||
addStatelessResetToken func([16]byte)
|
||||
removeStatelessResetToken func([16]byte)
|
||||
@@ -30,12 +38,16 @@ func newConnIDManager(
|
||||
retireStatelessResetToken func([16]byte),
|
||||
queueControlFrame func(wire.Frame),
|
||||
) *connIDManager {
|
||||
b := make([]byte, 8)
|
||||
_, _ = rand.Read(b) // ignore the error here. Nothing bad will happen if the seed is not perfectly random.
|
||||
seed := int64(binary.BigEndian.Uint64(b))
|
||||
return &connIDManager{
|
||||
activeConnectionID: initialDestConnID,
|
||||
addStatelessResetToken: addStatelessResetToken,
|
||||
removeStatelessResetToken: removeStatelessResetToken,
|
||||
retireStatelessResetToken: retireStatelessResetToken,
|
||||
queueControlFrame: queueControlFrame,
|
||||
rand: mrand.New(mrand.NewSource(seed)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,6 +126,7 @@ func (h *connIDManager) updateConnectionID() {
|
||||
h.activeConnectionID = front.ConnectionID
|
||||
h.activeStatelessResetToken = front.StatelessResetToken
|
||||
h.packetsSinceLastChange = 0
|
||||
h.packetsPerConnectionID = protocol.PacketsPerConnectionID/2 + uint64(h.rand.Int63n(protocol.PacketsPerConnectionID))
|
||||
h.addStatelessResetToken(*h.activeStatelessResetToken)
|
||||
}
|
||||
|
||||
@@ -154,7 +167,7 @@ func (h *connIDManager) shouldUpdateConnID() bool {
|
||||
// 1. The queue of connection IDs is filled more than 50%.
|
||||
// 2. We sent at least PacketsPerConnectionID packets
|
||||
return 2*h.queue.Len() >= protocol.MaxActiveConnectionIDs &&
|
||||
h.packetsSinceLastChange >= protocol.PacketsPerConnectionID
|
||||
h.packetsSinceLastChange >= h.packetsPerConnectionID
|
||||
}
|
||||
|
||||
func (h *connIDManager) Get() protocol.ConnectionID {
|
||||
|
||||
@@ -175,20 +175,37 @@ var _ = Describe("Connection ID Manager", func() {
|
||||
})
|
||||
|
||||
It("initiates subsequent updates when enough packets are sent", func() {
|
||||
for i := uint8(1); i <= protocol.MaxActiveConnectionIDs; i++ {
|
||||
var s uint8
|
||||
for s = uint8(1); s <= protocol.MaxActiveConnectionIDs; s++ {
|
||||
Expect(m.Add(&wire.NewConnectionIDFrame{
|
||||
SequenceNumber: uint64(i),
|
||||
ConnectionID: protocol.ConnectionID{i, i, i, i},
|
||||
StatelessResetToken: [16]byte{i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i},
|
||||
SequenceNumber: uint64(s),
|
||||
ConnectionID: protocol.ConnectionID{s, s, s, s},
|
||||
StatelessResetToken: [16]byte{s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s},
|
||||
})).To(Succeed())
|
||||
}
|
||||
Expect(m.Get()).To(Equal(protocol.ConnectionID{1, 1, 1, 1}))
|
||||
for i := 0; i < protocol.PacketsPerConnectionID; i++ {
|
||||
|
||||
lastConnID := m.Get()
|
||||
Expect(lastConnID).To(Equal(protocol.ConnectionID{1, 1, 1, 1}))
|
||||
|
||||
var counter int
|
||||
for i := 0; i < 50*protocol.PacketsPerConnectionID; i++ {
|
||||
m.SentPacket()
|
||||
|
||||
connID := m.Get()
|
||||
if !connID.Equal(lastConnID) {
|
||||
counter++
|
||||
lastConnID = connID
|
||||
Expect(retiredTokens).To(HaveLen(1))
|
||||
retiredTokens = nil
|
||||
Expect(m.Add(&wire.NewConnectionIDFrame{
|
||||
SequenceNumber: uint64(s),
|
||||
ConnectionID: protocol.ConnectionID{s, s, s, s},
|
||||
StatelessResetToken: [16]byte{s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s},
|
||||
})).To(Succeed())
|
||||
s++
|
||||
}
|
||||
}
|
||||
Expect(m.Get()).To(Equal(protocol.ConnectionID{2, 2, 2, 2}))
|
||||
Expect(retiredTokens).To(HaveLen(1))
|
||||
Expect(retiredTokens[0]).To(Equal([16]byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}))
|
||||
Expect(counter).To(BeNumerically("~", 50, 10))
|
||||
})
|
||||
|
||||
It("only initiates subsequent updates when enough if enough connection IDs are queued", func() {
|
||||
|
||||
Reference in New Issue
Block a user