forked from apernet/quic-go
-
Notifications
You must be signed in to change notification settings - Fork 10
/
conn_id_generator_test.go
187 lines (168 loc) · 7.24 KB
/
conn_id_generator_test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
package quic
import (
"fmt"
"github.com/metacubex/quic-go/internal/protocol"
"github.com/metacubex/quic-go/internal/qerr"
"github.com/metacubex/quic-go/internal/wire"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)
var _ = Describe("Connection ID Generator", func() {
var (
addedConnIDs []protocol.ConnectionID
retiredConnIDs []protocol.ConnectionID
removedConnIDs []protocol.ConnectionID
replacedWithClosed []protocol.ConnectionID
queuedFrames []wire.Frame
g *connIDGenerator
)
initialConnID := protocol.ParseConnectionID([]byte{1, 2, 3, 4, 5, 6, 7})
initialClientDestConnID := protocol.ParseConnectionID([]byte{0xa, 0xb, 0xc, 0xd, 0xe})
connIDToToken := func(c protocol.ConnectionID) protocol.StatelessResetToken {
b := c.Bytes()[0]
return protocol.StatelessResetToken{b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b}
}
BeforeEach(func() {
addedConnIDs = nil
retiredConnIDs = nil
removedConnIDs = nil
queuedFrames = nil
replacedWithClosed = nil
g = newConnIDGenerator(
initialConnID,
&initialClientDestConnID,
func(c protocol.ConnectionID) { addedConnIDs = append(addedConnIDs, c) },
connIDToToken,
func(c protocol.ConnectionID) { removedConnIDs = append(removedConnIDs, c) },
func(c protocol.ConnectionID) { retiredConnIDs = append(retiredConnIDs, c) },
func(cs []protocol.ConnectionID, _ []byte) { replacedWithClosed = append(replacedWithClosed, cs...) },
func(f wire.Frame) { queuedFrames = append(queuedFrames, f) },
&protocol.DefaultConnectionIDGenerator{ConnLen: initialConnID.Len()},
)
})
It("issues new connection IDs", func() {
Expect(g.SetMaxActiveConnIDs(4)).To(Succeed())
Expect(retiredConnIDs).To(BeEmpty())
Expect(addedConnIDs).To(HaveLen(3))
for i := 0; i < len(addedConnIDs)-1; i++ {
Expect(addedConnIDs[i]).ToNot(Equal(addedConnIDs[i+1]))
}
Expect(queuedFrames).To(HaveLen(3))
for i := 0; i < 3; i++ {
f := queuedFrames[i]
Expect(f).To(BeAssignableToTypeOf(&wire.NewConnectionIDFrame{}))
nf := f.(*wire.NewConnectionIDFrame)
Expect(nf.SequenceNumber).To(BeEquivalentTo(i + 1))
Expect(nf.ConnectionID.Len()).To(Equal(7))
Expect(nf.StatelessResetToken).To(Equal(connIDToToken(nf.ConnectionID)))
}
})
It("limits the number of connection IDs that it issues", func() {
Expect(g.SetMaxActiveConnIDs(9999999)).To(Succeed())
Expect(retiredConnIDs).To(BeEmpty())
Expect(addedConnIDs).To(HaveLen(protocol.MaxIssuedConnectionIDs - 1))
Expect(queuedFrames).To(HaveLen(protocol.MaxIssuedConnectionIDs - 1))
})
// SetMaxActiveConnIDs is called twice when dialing a 0-RTT connection:
// once for the restored from the old connections, once when we receive the transport parameters
Context("dealing with 0-RTT", func() {
It("doesn't issue new connection IDs when SetMaxActiveConnIDs is called with the same value", func() {
Expect(g.SetMaxActiveConnIDs(4)).To(Succeed())
Expect(queuedFrames).To(HaveLen(3))
queuedFrames = nil
Expect(g.SetMaxActiveConnIDs(4)).To(Succeed())
Expect(queuedFrames).To(BeEmpty())
})
It("issues more connection IDs if the server allows a higher limit on the resumed connection", func() {
Expect(g.SetMaxActiveConnIDs(3)).To(Succeed())
Expect(queuedFrames).To(HaveLen(2))
queuedFrames = nil
Expect(g.SetMaxActiveConnIDs(6)).To(Succeed())
Expect(queuedFrames).To(HaveLen(3))
})
It("issues more connection IDs if the server allows a higher limit on the resumed connection, when connection IDs were retired in between", func() {
Expect(g.SetMaxActiveConnIDs(3)).To(Succeed())
Expect(queuedFrames).To(HaveLen(2))
queuedFrames = nil
g.Retire(1, protocol.ConnectionID{})
Expect(queuedFrames).To(HaveLen(1))
queuedFrames = nil
Expect(g.SetMaxActiveConnIDs(6)).To(Succeed())
Expect(queuedFrames).To(HaveLen(3))
})
})
It("errors if the peers tries to retire a connection ID that wasn't yet issued", func() {
Expect(g.Retire(1, protocol.ConnectionID{})).To(MatchError(&qerr.TransportError{
ErrorCode: qerr.ProtocolViolation,
ErrorMessage: "retired connection ID 1 (highest issued: 0)",
}))
})
It("errors if the peers tries to retire a connection ID in a packet with that connection ID", func() {
Expect(g.SetMaxActiveConnIDs(4)).To(Succeed())
Expect(queuedFrames).ToNot(BeEmpty())
Expect(queuedFrames[0]).To(BeAssignableToTypeOf(&wire.NewConnectionIDFrame{}))
f := queuedFrames[0].(*wire.NewConnectionIDFrame)
Expect(g.Retire(f.SequenceNumber, f.ConnectionID)).To(MatchError(&qerr.TransportError{
ErrorCode: qerr.ProtocolViolation,
ErrorMessage: fmt.Sprintf("retired connection ID %d (%s), which was used as the Destination Connection ID on this packet", f.SequenceNumber, f.ConnectionID),
}))
})
It("issues new connection IDs, when old ones are retired", func() {
Expect(g.SetMaxActiveConnIDs(5)).To(Succeed())
queuedFrames = nil
Expect(retiredConnIDs).To(BeEmpty())
Expect(g.Retire(3, protocol.ConnectionID{})).To(Succeed())
Expect(queuedFrames).To(HaveLen(1))
Expect(queuedFrames[0]).To(BeAssignableToTypeOf(&wire.NewConnectionIDFrame{}))
nf := queuedFrames[0].(*wire.NewConnectionIDFrame)
Expect(nf.SequenceNumber).To(BeEquivalentTo(5))
Expect(nf.ConnectionID.Len()).To(Equal(7))
})
It("retires the initial connection ID", func() {
Expect(g.Retire(0, protocol.ConnectionID{})).To(Succeed())
Expect(removedConnIDs).To(BeEmpty())
Expect(retiredConnIDs).To(HaveLen(1))
Expect(retiredConnIDs[0]).To(Equal(initialConnID))
Expect(addedConnIDs).To(BeEmpty())
})
It("handles duplicate retirements", func() {
Expect(g.SetMaxActiveConnIDs(11)).To(Succeed())
queuedFrames = nil
Expect(retiredConnIDs).To(BeEmpty())
Expect(g.Retire(5, protocol.ConnectionID{})).To(Succeed())
Expect(retiredConnIDs).To(HaveLen(1))
Expect(queuedFrames).To(HaveLen(1))
Expect(g.Retire(5, protocol.ConnectionID{})).To(Succeed())
Expect(retiredConnIDs).To(HaveLen(1))
Expect(queuedFrames).To(HaveLen(1))
})
It("retires the client's initial destination connection ID when the handshake completes", func() {
g.SetHandshakeComplete()
Expect(retiredConnIDs).To(HaveLen(1))
Expect(retiredConnIDs[0]).To(Equal(initialClientDestConnID))
})
It("removes all connection IDs", func() {
Expect(g.SetMaxActiveConnIDs(5)).To(Succeed())
Expect(queuedFrames).To(HaveLen(4))
g.RemoveAll()
Expect(removedConnIDs).To(HaveLen(6)) // initial conn ID, initial client dest conn id, and newly issued ones
Expect(removedConnIDs).To(ContainElement(initialConnID))
Expect(removedConnIDs).To(ContainElement(initialClientDestConnID))
for _, f := range queuedFrames {
nf := f.(*wire.NewConnectionIDFrame)
Expect(removedConnIDs).To(ContainElement(nf.ConnectionID))
}
})
It("replaces with a closed connection for all connection IDs", func() {
Expect(g.SetMaxActiveConnIDs(5)).To(Succeed())
Expect(queuedFrames).To(HaveLen(4))
g.ReplaceWithClosed([]byte("foobar"))
Expect(replacedWithClosed).To(HaveLen(6)) // initial conn ID, initial client dest conn id, and newly issued ones
Expect(replacedWithClosed).To(ContainElement(initialClientDestConnID))
Expect(replacedWithClosed).To(ContainElement(initialConnID))
for _, f := range queuedFrames {
nf := f.(*wire.NewConnectionIDFrame)
Expect(replacedWithClosed).To(ContainElement(nf.ConnectionID))
}
})
})