mirror of
https://github.com/refraction-networking/uquic.git
synced 2025-03-31 10:47:35 +03:00
uTLS is not yet bumped to the new version, so this commit breaks the dependencies relationship by getting rid of the local replace.
364 lines
15 KiB
Go
364 lines
15 KiB
Go
package quic
|
|
|
|
import (
|
|
"github.com/refraction-networking/uquic/internal/protocol"
|
|
"github.com/refraction-networking/uquic/internal/qerr"
|
|
"github.com/refraction-networking/uquic/internal/wire"
|
|
|
|
. "github.com/onsi/ginkgo/v2"
|
|
. "github.com/onsi/gomega"
|
|
)
|
|
|
|
var _ = Describe("Connection ID Manager", func() {
|
|
var (
|
|
m *connIDManager
|
|
frameQueue []wire.Frame
|
|
tokenAdded *protocol.StatelessResetToken
|
|
removedTokens []protocol.StatelessResetToken
|
|
)
|
|
initialConnID := protocol.ParseConnectionID([]byte{0, 0, 0, 0})
|
|
|
|
BeforeEach(func() {
|
|
frameQueue = nil
|
|
tokenAdded = nil
|
|
removedTokens = nil
|
|
m = newConnIDManager(
|
|
initialConnID,
|
|
func(token protocol.StatelessResetToken) { tokenAdded = &token },
|
|
func(token protocol.StatelessResetToken) { removedTokens = append(removedTokens, token) },
|
|
func(f wire.Frame,
|
|
) {
|
|
frameQueue = append(frameQueue, f)
|
|
})
|
|
})
|
|
|
|
get := func() (protocol.ConnectionID, protocol.StatelessResetToken) {
|
|
if m.queue.Len() == 0 {
|
|
return protocol.ConnectionID{}, protocol.StatelessResetToken{}
|
|
}
|
|
val := m.queue.Remove(m.queue.Front())
|
|
return val.ConnectionID, val.StatelessResetToken
|
|
}
|
|
|
|
It("returns the initial connection ID", func() {
|
|
Expect(m.Get()).To(Equal(initialConnID))
|
|
})
|
|
|
|
It("changes the initial connection ID", func() {
|
|
m.ChangeInitialConnID(protocol.ParseConnectionID([]byte{1, 2, 3, 4, 5}))
|
|
Expect(m.Get()).To(Equal(protocol.ParseConnectionID([]byte{1, 2, 3, 4, 5})))
|
|
})
|
|
|
|
It("sets the token for the first connection ID", func() {
|
|
token := protocol.StatelessResetToken{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}
|
|
m.SetStatelessResetToken(token)
|
|
Expect(*m.activeStatelessResetToken).To(Equal(token))
|
|
Expect(*tokenAdded).To(Equal(token))
|
|
})
|
|
|
|
It("adds and gets connection IDs", func() {
|
|
Expect(m.Add(&wire.NewConnectionIDFrame{
|
|
SequenceNumber: 10,
|
|
ConnectionID: protocol.ParseConnectionID([]byte{2, 3, 4, 5}),
|
|
StatelessResetToken: protocol.StatelessResetToken{0xe, 0xd, 0xc, 0xb, 0xa, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0},
|
|
})).To(Succeed())
|
|
Expect(m.Add(&wire.NewConnectionIDFrame{
|
|
SequenceNumber: 4,
|
|
ConnectionID: protocol.ParseConnectionID([]byte{1, 2, 3, 4}),
|
|
StatelessResetToken: protocol.StatelessResetToken{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe},
|
|
})).To(Succeed())
|
|
c1, rt1 := get()
|
|
Expect(c1).To(Equal(protocol.ParseConnectionID([]byte{1, 2, 3, 4})))
|
|
Expect(rt1).To(Equal(protocol.StatelessResetToken{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe}))
|
|
c2, rt2 := get()
|
|
Expect(c2).To(Equal(protocol.ParseConnectionID([]byte{2, 3, 4, 5})))
|
|
Expect(rt2).To(Equal(protocol.StatelessResetToken{0xe, 0xd, 0xc, 0xb, 0xa, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}))
|
|
c3, _ := get()
|
|
Expect(c3).To(BeZero())
|
|
})
|
|
|
|
It("accepts duplicates", func() {
|
|
f1 := &wire.NewConnectionIDFrame{
|
|
SequenceNumber: 1,
|
|
ConnectionID: protocol.ParseConnectionID([]byte{1, 2, 3, 4}),
|
|
StatelessResetToken: protocol.StatelessResetToken{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe},
|
|
}
|
|
f2 := &wire.NewConnectionIDFrame{
|
|
SequenceNumber: 1,
|
|
ConnectionID: protocol.ParseConnectionID([]byte{1, 2, 3, 4}),
|
|
StatelessResetToken: protocol.StatelessResetToken{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe},
|
|
}
|
|
Expect(m.Add(f1)).To(Succeed())
|
|
Expect(m.Add(f2)).To(Succeed())
|
|
c1, rt1 := get()
|
|
Expect(c1).To(Equal(protocol.ParseConnectionID([]byte{1, 2, 3, 4})))
|
|
Expect(rt1).To(Equal(protocol.StatelessResetToken{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe}))
|
|
c2, _ := get()
|
|
Expect(c2).To(BeZero())
|
|
})
|
|
|
|
It("ignores duplicates for the currently used connection ID", func() {
|
|
f := &wire.NewConnectionIDFrame{
|
|
SequenceNumber: 1,
|
|
ConnectionID: protocol.ParseConnectionID([]byte{1, 2, 3, 4}),
|
|
StatelessResetToken: protocol.StatelessResetToken{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe},
|
|
}
|
|
m.SetHandshakeComplete()
|
|
Expect(m.Add(f)).To(Succeed())
|
|
Expect(m.Get()).To(Equal(protocol.ParseConnectionID([]byte{1, 2, 3, 4})))
|
|
c, _ := get()
|
|
Expect(c).To(BeZero())
|
|
// Now send the same connection ID again. It should not be queued.
|
|
Expect(m.Add(f)).To(Succeed())
|
|
c, _ = get()
|
|
Expect(c).To(BeZero())
|
|
})
|
|
|
|
It("rejects duplicates with different connection IDs", func() {
|
|
Expect(m.Add(&wire.NewConnectionIDFrame{
|
|
SequenceNumber: 42,
|
|
ConnectionID: protocol.ParseConnectionID([]byte{1, 2, 3, 4}),
|
|
})).To(Succeed())
|
|
Expect(m.Add(&wire.NewConnectionIDFrame{
|
|
SequenceNumber: 42,
|
|
ConnectionID: protocol.ParseConnectionID([]byte{2, 3, 4, 5}),
|
|
})).To(MatchError("received conflicting connection IDs for sequence number 42"))
|
|
})
|
|
|
|
It("rejects duplicates with different connection IDs", func() {
|
|
Expect(m.Add(&wire.NewConnectionIDFrame{
|
|
SequenceNumber: 42,
|
|
ConnectionID: protocol.ParseConnectionID([]byte{1, 2, 3, 4}),
|
|
StatelessResetToken: protocol.StatelessResetToken{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe},
|
|
})).To(Succeed())
|
|
Expect(m.Add(&wire.NewConnectionIDFrame{
|
|
SequenceNumber: 42,
|
|
ConnectionID: protocol.ParseConnectionID([]byte{1, 2, 3, 4}),
|
|
StatelessResetToken: protocol.StatelessResetToken{0xe, 0xd, 0xc, 0xb, 0xa, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0},
|
|
})).To(MatchError("received conflicting stateless reset tokens for sequence number 42"))
|
|
})
|
|
|
|
It("retires connection IDs", func() {
|
|
Expect(m.Add(&wire.NewConnectionIDFrame{
|
|
SequenceNumber: 10,
|
|
ConnectionID: protocol.ParseConnectionID([]byte{1, 2, 3, 4}),
|
|
})).To(Succeed())
|
|
Expect(m.Add(&wire.NewConnectionIDFrame{
|
|
SequenceNumber: 13,
|
|
ConnectionID: protocol.ParseConnectionID([]byte{2, 3, 4, 5}),
|
|
})).To(Succeed())
|
|
Expect(frameQueue).To(BeEmpty())
|
|
Expect(m.Add(&wire.NewConnectionIDFrame{
|
|
RetirePriorTo: 14,
|
|
SequenceNumber: 17,
|
|
ConnectionID: protocol.ParseConnectionID([]byte{3, 4, 5, 6}),
|
|
})).To(Succeed())
|
|
Expect(frameQueue).To(HaveLen(3))
|
|
Expect(frameQueue[0].(*wire.RetireConnectionIDFrame).SequenceNumber).To(BeEquivalentTo(10))
|
|
Expect(frameQueue[1].(*wire.RetireConnectionIDFrame).SequenceNumber).To(BeEquivalentTo(13))
|
|
Expect(frameQueue[2].(*wire.RetireConnectionIDFrame).SequenceNumber).To(BeZero())
|
|
Expect(m.Get()).To(Equal(protocol.ParseConnectionID([]byte{3, 4, 5, 6})))
|
|
})
|
|
|
|
It("ignores reordered connection IDs, if their sequence number was already retired", func() {
|
|
Expect(m.Add(&wire.NewConnectionIDFrame{
|
|
SequenceNumber: 10,
|
|
ConnectionID: protocol.ParseConnectionID([]byte{1, 2, 3, 4}),
|
|
RetirePriorTo: 5,
|
|
})).To(Succeed())
|
|
Expect(frameQueue).To(HaveLen(1))
|
|
Expect(frameQueue[0].(*wire.RetireConnectionIDFrame).SequenceNumber).To(BeZero())
|
|
frameQueue = nil
|
|
// If this NEW_CONNECTION_ID frame hadn't been reordered, we would have retired it before.
|
|
// Make sure it gets retired immediately now.
|
|
Expect(m.Add(&wire.NewConnectionIDFrame{
|
|
SequenceNumber: 4,
|
|
ConnectionID: protocol.ParseConnectionID([]byte{4, 3, 2, 1}),
|
|
})).To(Succeed())
|
|
Expect(frameQueue).To(HaveLen(1))
|
|
Expect(frameQueue[0].(*wire.RetireConnectionIDFrame).SequenceNumber).To(BeEquivalentTo(4))
|
|
})
|
|
|
|
It("ignores reordered connection IDs, if their sequence number was already retired or less than active", func() {
|
|
Expect(m.Add(&wire.NewConnectionIDFrame{
|
|
SequenceNumber: 10,
|
|
ConnectionID: protocol.ParseConnectionID([]byte{0xde, 0xad, 0xbe, 0xef}),
|
|
RetirePriorTo: 5,
|
|
})).To(Succeed())
|
|
Expect(frameQueue).To(HaveLen(1))
|
|
Expect(frameQueue[0].(*wire.RetireConnectionIDFrame).SequenceNumber).To(BeZero())
|
|
frameQueue = nil
|
|
Expect(m.Get()).To(Equal(protocol.ParseConnectionID([]byte{0xde, 0xad, 0xbe, 0xef})))
|
|
|
|
Expect(m.Add(&wire.NewConnectionIDFrame{
|
|
SequenceNumber: 9,
|
|
ConnectionID: protocol.ParseConnectionID([]byte{0xde, 0xca, 0xfb, 0xad}),
|
|
RetirePriorTo: 5,
|
|
})).To(Succeed())
|
|
Expect(frameQueue).To(HaveLen(1))
|
|
Expect(frameQueue[0].(*wire.RetireConnectionIDFrame).SequenceNumber).To(BeEquivalentTo(9))
|
|
})
|
|
|
|
It("accepts retransmissions for the connection ID that is in use", func() {
|
|
connID := protocol.ParseConnectionID([]byte{1, 2, 3, 4})
|
|
|
|
Expect(m.Add(&wire.NewConnectionIDFrame{
|
|
SequenceNumber: 1,
|
|
ConnectionID: connID,
|
|
})).To(Succeed())
|
|
m.SetHandshakeComplete()
|
|
Expect(frameQueue).To(BeEmpty())
|
|
Expect(m.Get()).To(Equal(connID))
|
|
Expect(frameQueue).To(HaveLen(1))
|
|
Expect(frameQueue[0]).To(BeAssignableToTypeOf(&wire.RetireConnectionIDFrame{}))
|
|
Expect(frameQueue[0].(*wire.RetireConnectionIDFrame).SequenceNumber).To(BeZero())
|
|
frameQueue = nil
|
|
|
|
Expect(m.Add(&wire.NewConnectionIDFrame{
|
|
SequenceNumber: 1,
|
|
ConnectionID: connID,
|
|
})).To(Succeed())
|
|
Expect(frameQueue).To(BeEmpty())
|
|
})
|
|
|
|
It("errors when the peer sends too connection IDs", func() {
|
|
for i := uint8(1); i < protocol.MaxActiveConnectionIDs; i++ {
|
|
Expect(m.Add(&wire.NewConnectionIDFrame{
|
|
SequenceNumber: uint64(i),
|
|
ConnectionID: protocol.ParseConnectionID([]byte{i, i, i, i}),
|
|
StatelessResetToken: protocol.StatelessResetToken{i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i},
|
|
})).To(Succeed())
|
|
}
|
|
Expect(m.Add(&wire.NewConnectionIDFrame{
|
|
SequenceNumber: uint64(9999),
|
|
ConnectionID: protocol.ParseConnectionID([]byte{1, 2, 3, 4}),
|
|
StatelessResetToken: protocol.StatelessResetToken{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16},
|
|
})).To(MatchError(&qerr.TransportError{ErrorCode: qerr.ConnectionIDLimitError}))
|
|
})
|
|
|
|
It("initiates the first connection ID update as soon as possible", func() {
|
|
Expect(m.Get()).To(Equal(initialConnID))
|
|
m.SetHandshakeComplete()
|
|
Expect(m.Add(&wire.NewConnectionIDFrame{
|
|
SequenceNumber: 1,
|
|
ConnectionID: protocol.ParseConnectionID([]byte{1, 2, 3, 4}),
|
|
StatelessResetToken: protocol.StatelessResetToken{16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1},
|
|
})).To(Succeed())
|
|
Expect(m.Get()).To(Equal(protocol.ParseConnectionID([]byte{1, 2, 3, 4})))
|
|
})
|
|
|
|
It("waits until handshake completion before initiating a connection ID update", func() {
|
|
Expect(m.Get()).To(Equal(initialConnID))
|
|
Expect(m.Add(&wire.NewConnectionIDFrame{
|
|
SequenceNumber: 1,
|
|
ConnectionID: protocol.ParseConnectionID([]byte{1, 2, 3, 4}),
|
|
StatelessResetToken: protocol.StatelessResetToken{16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1},
|
|
})).To(Succeed())
|
|
Expect(m.Get()).To(Equal(initialConnID))
|
|
m.SetHandshakeComplete()
|
|
Expect(m.Get()).To(Equal(protocol.ParseConnectionID([]byte{1, 2, 3, 4})))
|
|
})
|
|
|
|
It("initiates subsequent updates when enough packets are sent", func() {
|
|
var s uint8
|
|
for s = uint8(1); s < protocol.MaxActiveConnectionIDs; s++ {
|
|
Expect(m.Add(&wire.NewConnectionIDFrame{
|
|
SequenceNumber: uint64(s),
|
|
ConnectionID: protocol.ParseConnectionID([]byte{s, s, s, s}),
|
|
StatelessResetToken: protocol.StatelessResetToken{s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s},
|
|
})).To(Succeed())
|
|
}
|
|
|
|
m.SetHandshakeComplete()
|
|
lastConnID := m.Get()
|
|
Expect(lastConnID).To(Equal(protocol.ParseConnectionID([]byte{1, 1, 1, 1})))
|
|
|
|
var counter int
|
|
for i := 0; i < 50*protocol.PacketsPerConnectionID; i++ {
|
|
m.SentPacket()
|
|
|
|
connID := m.Get()
|
|
if connID != lastConnID {
|
|
counter++
|
|
lastConnID = connID
|
|
Expect(removedTokens).To(HaveLen(1))
|
|
removedTokens = nil
|
|
Expect(m.Add(&wire.NewConnectionIDFrame{
|
|
SequenceNumber: uint64(s),
|
|
ConnectionID: protocol.ParseConnectionID([]byte{s, s, s, s}),
|
|
StatelessResetToken: protocol.StatelessResetToken{s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s},
|
|
})).To(Succeed())
|
|
s++
|
|
}
|
|
}
|
|
Expect(counter).To(BeNumerically("~", 50, 10))
|
|
})
|
|
|
|
It("retires delayed connection IDs that arrive after a higher connection ID was already retired", func() {
|
|
for s := uint8(10); s <= 10+protocol.MaxActiveConnectionIDs/2; s++ {
|
|
Expect(m.Add(&wire.NewConnectionIDFrame{
|
|
SequenceNumber: uint64(s),
|
|
ConnectionID: protocol.ParseConnectionID([]byte{s, s, s, s}),
|
|
StatelessResetToken: protocol.StatelessResetToken{s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s},
|
|
})).To(Succeed())
|
|
}
|
|
m.SetHandshakeComplete()
|
|
Expect(m.Get()).To(Equal(protocol.ParseConnectionID([]byte{10, 10, 10, 10})))
|
|
for {
|
|
m.SentPacket()
|
|
if m.Get() == protocol.ParseConnectionID([]byte{11, 11, 11, 11}) {
|
|
break
|
|
}
|
|
}
|
|
// The active conn ID is now {11, 11, 11, 11}
|
|
Expect(m.queue.Front().Value.ConnectionID).To(Equal(protocol.ParseConnectionID([]byte{12, 12, 12, 12})))
|
|
// Add a delayed connection ID. It should just be ignored now.
|
|
frameQueue = nil
|
|
Expect(m.Add(&wire.NewConnectionIDFrame{
|
|
SequenceNumber: uint64(5),
|
|
ConnectionID: protocol.ParseConnectionID([]byte{5, 5, 5, 5}),
|
|
StatelessResetToken: protocol.StatelessResetToken{5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5},
|
|
})).To(Succeed())
|
|
Expect(m.queue.Front().Value.ConnectionID).To(Equal(protocol.ParseConnectionID([]byte{12, 12, 12, 12})))
|
|
Expect(frameQueue).To(HaveLen(1))
|
|
Expect(frameQueue[0].(*wire.RetireConnectionIDFrame).SequenceNumber).To(BeEquivalentTo(5))
|
|
})
|
|
|
|
It("only initiates subsequent updates when enough if enough connection IDs are queued", func() {
|
|
for i := uint8(1); i <= protocol.MaxActiveConnectionIDs/2; i++ {
|
|
Expect(m.Add(&wire.NewConnectionIDFrame{
|
|
SequenceNumber: uint64(i),
|
|
ConnectionID: protocol.ParseConnectionID([]byte{i, i, i, i}),
|
|
StatelessResetToken: protocol.StatelessResetToken{i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i},
|
|
})).To(Succeed())
|
|
}
|
|
m.SetHandshakeComplete()
|
|
Expect(m.Get()).To(Equal(protocol.ParseConnectionID([]byte{1, 1, 1, 1})))
|
|
for i := 0; i < 2*protocol.PacketsPerConnectionID; i++ {
|
|
m.SentPacket()
|
|
}
|
|
Expect(m.Get()).To(Equal(protocol.ParseConnectionID([]byte{1, 1, 1, 1})))
|
|
Expect(m.Add(&wire.NewConnectionIDFrame{
|
|
SequenceNumber: 1337,
|
|
ConnectionID: protocol.ParseConnectionID([]byte{1, 3, 3, 7}),
|
|
})).To(Succeed())
|
|
Expect(m.Get()).To(Equal(protocol.ParseConnectionID([]byte{2, 2, 2, 2})))
|
|
Expect(removedTokens).To(HaveLen(1))
|
|
Expect(removedTokens[0]).To(Equal(protocol.StatelessResetToken{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}))
|
|
})
|
|
|
|
It("removes the currently active stateless reset token when it is closed", func() {
|
|
m.Close()
|
|
Expect(removedTokens).To(BeEmpty())
|
|
Expect(m.Add(&wire.NewConnectionIDFrame{
|
|
SequenceNumber: 1,
|
|
ConnectionID: protocol.ParseConnectionID([]byte{1, 2, 3, 4}),
|
|
StatelessResetToken: protocol.StatelessResetToken{16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1},
|
|
})).To(Succeed())
|
|
m.SetHandshakeComplete()
|
|
Expect(m.Get()).To(Equal(protocol.ParseConnectionID([]byte{1, 2, 3, 4})))
|
|
m.Close()
|
|
Expect(removedTokens).To(HaveLen(1))
|
|
Expect(removedTokens[0]).To(Equal(protocol.StatelessResetToken{16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1}))
|
|
})
|
|
})
|