1package quic
2
3import (
4	"github.com/lucas-clemente/quic-go/internal/protocol"
5	"github.com/lucas-clemente/quic-go/internal/qerr"
6	"github.com/lucas-clemente/quic-go/internal/wire"
7
8	. "github.com/onsi/ginkgo"
9	. "github.com/onsi/gomega"
10)
11
12var _ = Describe("Connection ID Manager", func() {
13	var (
14		m             *connIDManager
15		frameQueue    []wire.Frame
16		tokenAdded    *protocol.StatelessResetToken
17		removedTokens []protocol.StatelessResetToken
18	)
19	initialConnID := protocol.ConnectionID{0, 0, 0, 0}
20
21	BeforeEach(func() {
22		frameQueue = nil
23		tokenAdded = nil
24		removedTokens = nil
25		m = newConnIDManager(
26			initialConnID,
27			func(token protocol.StatelessResetToken) { tokenAdded = &token },
28			func(token protocol.StatelessResetToken) { removedTokens = append(removedTokens, token) },
29			func(f wire.Frame,
30			) {
31				frameQueue = append(frameQueue, f)
32			})
33	})
34
35	get := func() (protocol.ConnectionID, protocol.StatelessResetToken) {
36		if m.queue.Len() == 0 {
37			return nil, protocol.StatelessResetToken{}
38		}
39		val := m.queue.Remove(m.queue.Front())
40		return val.ConnectionID, val.StatelessResetToken
41	}
42
43	It("returns the initial connection ID", func() {
44		Expect(m.Get()).To(Equal(initialConnID))
45	})
46
47	It("changes the initial connection ID", func() {
48		m.ChangeInitialConnID(protocol.ConnectionID{1, 2, 3, 4, 5})
49		Expect(m.Get()).To(Equal(protocol.ConnectionID{1, 2, 3, 4, 5}))
50	})
51
52	It("sets the token for the first connection ID", func() {
53		token := protocol.StatelessResetToken{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}
54		m.SetStatelessResetToken(token)
55		Expect(*m.activeStatelessResetToken).To(Equal(token))
56		Expect(*tokenAdded).To(Equal(token))
57	})
58
59	It("adds and gets connection IDs", func() {
60		Expect(m.Add(&wire.NewConnectionIDFrame{
61			SequenceNumber:      10,
62			ConnectionID:        protocol.ConnectionID{2, 3, 4, 5},
63			StatelessResetToken: protocol.StatelessResetToken{0xe, 0xd, 0xc, 0xb, 0xa, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0},
64		})).To(Succeed())
65		Expect(m.Add(&wire.NewConnectionIDFrame{
66			SequenceNumber:      4,
67			ConnectionID:        protocol.ConnectionID{1, 2, 3, 4},
68			StatelessResetToken: protocol.StatelessResetToken{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe},
69		})).To(Succeed())
70		c1, rt1 := get()
71		Expect(c1).To(Equal(protocol.ConnectionID{1, 2, 3, 4}))
72		Expect(rt1).To(Equal(protocol.StatelessResetToken{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe}))
73		c2, rt2 := get()
74		Expect(c2).To(Equal(protocol.ConnectionID{2, 3, 4, 5}))
75		Expect(rt2).To(Equal(protocol.StatelessResetToken{0xe, 0xd, 0xc, 0xb, 0xa, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}))
76		c3, _ := get()
77		Expect(c3).To(BeNil())
78	})
79
80	It("accepts duplicates", func() {
81		f1 := &wire.NewConnectionIDFrame{
82			SequenceNumber:      1,
83			ConnectionID:        protocol.ConnectionID{1, 2, 3, 4},
84			StatelessResetToken: protocol.StatelessResetToken{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe},
85		}
86		f2 := &wire.NewConnectionIDFrame{
87			SequenceNumber:      1,
88			ConnectionID:        protocol.ConnectionID{1, 2, 3, 4},
89			StatelessResetToken: protocol.StatelessResetToken{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe},
90		}
91		Expect(m.Add(f1)).To(Succeed())
92		Expect(m.Add(f2)).To(Succeed())
93		c1, rt1 := get()
94		Expect(c1).To(Equal(protocol.ConnectionID{1, 2, 3, 4}))
95		Expect(rt1).To(Equal(protocol.StatelessResetToken{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe}))
96		c2, _ := get()
97		Expect(c2).To(BeNil())
98	})
99
100	It("ignores duplicates for the currently used connection ID", func() {
101		f := &wire.NewConnectionIDFrame{
102			SequenceNumber:      1,
103			ConnectionID:        protocol.ConnectionID{1, 2, 3, 4},
104			StatelessResetToken: protocol.StatelessResetToken{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe},
105		}
106		m.SetHandshakeComplete()
107		Expect(m.Add(f)).To(Succeed())
108		Expect(m.Get()).To(Equal(protocol.ConnectionID{1, 2, 3, 4}))
109		c, _ := get()
110		Expect(c).To(BeNil())
111		// Now send the same connection ID again. It should not be queued.
112		Expect(m.Add(f)).To(Succeed())
113		c, _ = get()
114		Expect(c).To(BeNil())
115	})
116
117	It("rejects duplicates with different connection IDs", func() {
118		Expect(m.Add(&wire.NewConnectionIDFrame{
119			SequenceNumber: 42,
120			ConnectionID:   protocol.ConnectionID{1, 2, 3, 4},
121		})).To(Succeed())
122		Expect(m.Add(&wire.NewConnectionIDFrame{
123			SequenceNumber: 42,
124			ConnectionID:   protocol.ConnectionID{2, 3, 4, 5},
125		})).To(MatchError("received conflicting connection IDs for sequence number 42"))
126	})
127
128	It("rejects duplicates with different connection IDs", func() {
129		Expect(m.Add(&wire.NewConnectionIDFrame{
130			SequenceNumber:      42,
131			ConnectionID:        protocol.ConnectionID{1, 2, 3, 4},
132			StatelessResetToken: protocol.StatelessResetToken{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe},
133		})).To(Succeed())
134		Expect(m.Add(&wire.NewConnectionIDFrame{
135			SequenceNumber:      42,
136			ConnectionID:        protocol.ConnectionID{1, 2, 3, 4},
137			StatelessResetToken: protocol.StatelessResetToken{0xe, 0xd, 0xc, 0xb, 0xa, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0},
138		})).To(MatchError("received conflicting stateless reset tokens for sequence number 42"))
139	})
140
141	It("retires connection IDs", func() {
142		Expect(m.Add(&wire.NewConnectionIDFrame{
143			SequenceNumber: 10,
144			ConnectionID:   protocol.ConnectionID{1, 2, 3, 4},
145		})).To(Succeed())
146		Expect(m.Add(&wire.NewConnectionIDFrame{
147			SequenceNumber: 13,
148			ConnectionID:   protocol.ConnectionID{2, 3, 4, 5},
149		})).To(Succeed())
150		Expect(frameQueue).To(BeEmpty())
151		Expect(m.Add(&wire.NewConnectionIDFrame{
152			RetirePriorTo:  14,
153			SequenceNumber: 17,
154			ConnectionID:   protocol.ConnectionID{3, 4, 5, 6},
155		})).To(Succeed())
156		Expect(frameQueue).To(HaveLen(3))
157		Expect(frameQueue[0].(*wire.RetireConnectionIDFrame).SequenceNumber).To(BeEquivalentTo(10))
158		Expect(frameQueue[1].(*wire.RetireConnectionIDFrame).SequenceNumber).To(BeEquivalentTo(13))
159		Expect(frameQueue[2].(*wire.RetireConnectionIDFrame).SequenceNumber).To(BeZero())
160		Expect(m.Get()).To(Equal(protocol.ConnectionID{3, 4, 5, 6}))
161	})
162
163	It("ignores reordered connection IDs, if their sequence number was already retired", func() {
164		Expect(m.Add(&wire.NewConnectionIDFrame{
165			SequenceNumber: 10,
166			ConnectionID:   protocol.ConnectionID{1, 2, 3, 4},
167			RetirePriorTo:  5,
168		})).To(Succeed())
169		Expect(frameQueue).To(HaveLen(1))
170		Expect(frameQueue[0].(*wire.RetireConnectionIDFrame).SequenceNumber).To(BeZero())
171		frameQueue = nil
172		// If this NEW_CONNECTION_ID frame hadn't been reordered, we would have retired it before.
173		// Make sure it gets retired immediately now.
174		Expect(m.Add(&wire.NewConnectionIDFrame{
175			SequenceNumber: 4,
176			ConnectionID:   protocol.ConnectionID{4, 3, 2, 1},
177		})).To(Succeed())
178		Expect(frameQueue).To(HaveLen(1))
179		Expect(frameQueue[0].(*wire.RetireConnectionIDFrame).SequenceNumber).To(BeEquivalentTo(4))
180	})
181
182	It("ignores reordered connection IDs, if their sequence number was already retired or less than active", func() {
183		Expect(m.Add(&wire.NewConnectionIDFrame{
184			SequenceNumber: 10,
185			ConnectionID:   protocol.ConnectionID{0xde, 0xad, 0xbe, 0xef},
186			RetirePriorTo:  5,
187		})).To(Succeed())
188		Expect(frameQueue).To(HaveLen(1))
189		Expect(frameQueue[0].(*wire.RetireConnectionIDFrame).SequenceNumber).To(BeZero())
190		frameQueue = nil
191		Expect(m.Get()).To(Equal(protocol.ConnectionID{0xde, 0xad, 0xbe, 0xef}))
192
193		Expect(m.Add(&wire.NewConnectionIDFrame{
194			SequenceNumber: 9,
195			ConnectionID:   protocol.ConnectionID{0xde, 0xca, 0xfb, 0xad},
196			RetirePriorTo:  5,
197		})).To(Succeed())
198		Expect(frameQueue).To(HaveLen(1))
199		Expect(frameQueue[0].(*wire.RetireConnectionIDFrame).SequenceNumber).To(BeEquivalentTo(9))
200	})
201
202	It("accepts retransmissions for the connection ID that is in use", func() {
203		connID := protocol.ConnectionID{1, 2, 3, 4}
204
205		Expect(m.Add(&wire.NewConnectionIDFrame{
206			SequenceNumber: 1,
207			ConnectionID:   connID,
208		})).To(Succeed())
209		m.SetHandshakeComplete()
210		Expect(frameQueue).To(BeEmpty())
211		Expect(m.Get()).To(Equal(connID))
212		Expect(frameQueue).To(HaveLen(1))
213		Expect(frameQueue[0]).To(BeAssignableToTypeOf(&wire.RetireConnectionIDFrame{}))
214		Expect(frameQueue[0].(*wire.RetireConnectionIDFrame).SequenceNumber).To(BeZero())
215		frameQueue = nil
216
217		Expect(m.Add(&wire.NewConnectionIDFrame{
218			SequenceNumber: 1,
219			ConnectionID:   connID,
220		})).To(Succeed())
221		Expect(frameQueue).To(BeEmpty())
222	})
223
224	It("errors when the peer sends too connection IDs", func() {
225		for i := uint8(1); i < protocol.MaxActiveConnectionIDs; i++ {
226			Expect(m.Add(&wire.NewConnectionIDFrame{
227				SequenceNumber:      uint64(i),
228				ConnectionID:        protocol.ConnectionID{i, i, i, i},
229				StatelessResetToken: protocol.StatelessResetToken{i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i},
230			})).To(Succeed())
231		}
232		Expect(m.Add(&wire.NewConnectionIDFrame{
233			SequenceNumber:      uint64(9999),
234			ConnectionID:        protocol.ConnectionID{1, 2, 3, 4},
235			StatelessResetToken: protocol.StatelessResetToken{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16},
236		})).To(MatchError(&qerr.TransportError{ErrorCode: qerr.ConnectionIDLimitError}))
237	})
238
239	It("initiates the first connection ID update as soon as possible", func() {
240		Expect(m.Get()).To(Equal(initialConnID))
241		m.SetHandshakeComplete()
242		Expect(m.Add(&wire.NewConnectionIDFrame{
243			SequenceNumber:      1,
244			ConnectionID:        protocol.ConnectionID{1, 2, 3, 4},
245			StatelessResetToken: protocol.StatelessResetToken{16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1},
246		})).To(Succeed())
247		Expect(m.Get()).To(Equal(protocol.ConnectionID{1, 2, 3, 4}))
248	})
249
250	It("waits until handshake completion before initiating a connection ID update", func() {
251		Expect(m.Get()).To(Equal(initialConnID))
252		Expect(m.Add(&wire.NewConnectionIDFrame{
253			SequenceNumber:      1,
254			ConnectionID:        protocol.ConnectionID{1, 2, 3, 4},
255			StatelessResetToken: protocol.StatelessResetToken{16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1},
256		})).To(Succeed())
257		Expect(m.Get()).To(Equal(initialConnID))
258		m.SetHandshakeComplete()
259		Expect(m.Get()).To(Equal(protocol.ConnectionID{1, 2, 3, 4}))
260	})
261
262	It("initiates subsequent updates when enough packets are sent", func() {
263		var s uint8
264		for s = uint8(1); s < protocol.MaxActiveConnectionIDs; s++ {
265			Expect(m.Add(&wire.NewConnectionIDFrame{
266				SequenceNumber:      uint64(s),
267				ConnectionID:        protocol.ConnectionID{s, s, s, s},
268				StatelessResetToken: protocol.StatelessResetToken{s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s},
269			})).To(Succeed())
270		}
271
272		m.SetHandshakeComplete()
273		lastConnID := m.Get()
274		Expect(lastConnID).To(Equal(protocol.ConnectionID{1, 1, 1, 1}))
275
276		var counter int
277		for i := 0; i < 50*protocol.PacketsPerConnectionID; i++ {
278			m.SentPacket()
279
280			connID := m.Get()
281			if !connID.Equal(lastConnID) {
282				counter++
283				lastConnID = connID
284				Expect(removedTokens).To(HaveLen(1))
285				removedTokens = nil
286				Expect(m.Add(&wire.NewConnectionIDFrame{
287					SequenceNumber:      uint64(s),
288					ConnectionID:        protocol.ConnectionID{s, s, s, s},
289					StatelessResetToken: protocol.StatelessResetToken{s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s},
290				})).To(Succeed())
291				s++
292			}
293		}
294		Expect(counter).To(BeNumerically("~", 50, 10))
295	})
296
297	It("retires delayed connection IDs that arrive after a higher connection ID was already retired", func() {
298		for s := uint8(10); s <= 10+protocol.MaxActiveConnectionIDs/2; s++ {
299			Expect(m.Add(&wire.NewConnectionIDFrame{
300				SequenceNumber:      uint64(s),
301				ConnectionID:        protocol.ConnectionID{s, s, s, s},
302				StatelessResetToken: protocol.StatelessResetToken{s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s},
303			})).To(Succeed())
304		}
305		m.SetHandshakeComplete()
306		Expect(m.Get()).To(Equal(protocol.ConnectionID{10, 10, 10, 10}))
307		for {
308			m.SentPacket()
309			if m.Get().Equal(protocol.ConnectionID{11, 11, 11, 11}) {
310				break
311			}
312		}
313		// The active conn ID is now {11, 11, 11, 11}
314		Expect(m.queue.Front().Value.ConnectionID).To(Equal(protocol.ConnectionID{12, 12, 12, 12}))
315		// Add a delayed connection ID. It should just be ignored now.
316		frameQueue = nil
317		Expect(m.Add(&wire.NewConnectionIDFrame{
318			SequenceNumber:      uint64(5),
319			ConnectionID:        protocol.ConnectionID{5, 5, 5, 5},
320			StatelessResetToken: protocol.StatelessResetToken{5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5},
321		})).To(Succeed())
322		Expect(m.queue.Front().Value.ConnectionID).To(Equal(protocol.ConnectionID{12, 12, 12, 12}))
323		Expect(frameQueue).To(HaveLen(1))
324		Expect(frameQueue[0].(*wire.RetireConnectionIDFrame).SequenceNumber).To(BeEquivalentTo(5))
325	})
326
327	It("only initiates subsequent updates when enough if enough connection IDs are queued", func() {
328		for i := uint8(1); i <= protocol.MaxActiveConnectionIDs/2; i++ {
329			Expect(m.Add(&wire.NewConnectionIDFrame{
330				SequenceNumber:      uint64(i),
331				ConnectionID:        protocol.ConnectionID{i, i, i, i},
332				StatelessResetToken: protocol.StatelessResetToken{i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i},
333			})).To(Succeed())
334		}
335		m.SetHandshakeComplete()
336		Expect(m.Get()).To(Equal(protocol.ConnectionID{1, 1, 1, 1}))
337		for i := 0; i < 2*protocol.PacketsPerConnectionID; i++ {
338			m.SentPacket()
339		}
340		Expect(m.Get()).To(Equal(protocol.ConnectionID{1, 1, 1, 1}))
341		Expect(m.Add(&wire.NewConnectionIDFrame{
342			SequenceNumber: 1337,
343			ConnectionID:   protocol.ConnectionID{1, 3, 3, 7},
344		})).To(Succeed())
345		Expect(m.Get()).To(Equal(protocol.ConnectionID{2, 2, 2, 2}))
346		Expect(removedTokens).To(HaveLen(1))
347		Expect(removedTokens[0]).To(Equal(protocol.StatelessResetToken{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}))
348	})
349
350	It("removes the currently active stateless reset token when it is closed", func() {
351		m.Close()
352		Expect(removedTokens).To(BeEmpty())
353		Expect(m.Add(&wire.NewConnectionIDFrame{
354			SequenceNumber:      1,
355			ConnectionID:        protocol.ConnectionID{1, 2, 3, 4},
356			StatelessResetToken: protocol.StatelessResetToken{16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1},
357		})).To(Succeed())
358		m.SetHandshakeComplete()
359		Expect(m.Get()).To(Equal(protocol.ConnectionID{1, 2, 3, 4}))
360		m.Close()
361		Expect(removedTokens).To(HaveLen(1))
362		Expect(removedTokens[0]).To(Equal(protocol.StatelessResetToken{16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1}))
363	})
364})
365