github.com/metacubex/quic-go@v0.44.1-0.20240520163451-20b689a59136/conn_id_manager_test.go (about) 1 package quic 2 3 import ( 4 "github.com/metacubex/quic-go/internal/protocol" 5 "github.com/metacubex/quic-go/internal/qerr" 6 "github.com/metacubex/quic-go/internal/wire" 7 8 . "github.com/onsi/ginkgo/v2" 9 . "github.com/onsi/gomega" 10 ) 11 12 var _ = 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.ParseConnectionID([]byte{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 protocol.ConnectionID{}, 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.ParseConnectionID([]byte{1, 2, 3, 4, 5})) 49 Expect(m.Get()).To(Equal(protocol.ParseConnectionID([]byte{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.ParseConnectionID([]byte{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.ParseConnectionID([]byte{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.ParseConnectionID([]byte{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.ParseConnectionID([]byte{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(BeZero()) 78 }) 79 80 It("accepts duplicates", func() { 81 f1 := &wire.NewConnectionIDFrame{ 82 SequenceNumber: 1, 83 ConnectionID: protocol.ParseConnectionID([]byte{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.ParseConnectionID([]byte{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.ParseConnectionID([]byte{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(BeZero()) 98 }) 99 100 It("ignores duplicates for the currently used connection ID", func() { 101 f := &wire.NewConnectionIDFrame{ 102 SequenceNumber: 1, 103 ConnectionID: protocol.ParseConnectionID([]byte{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.ParseConnectionID([]byte{1, 2, 3, 4}))) 109 c, _ := get() 110 Expect(c).To(BeZero()) 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(BeZero()) 115 }) 116 117 It("rejects duplicates with different connection IDs", func() { 118 Expect(m.Add(&wire.NewConnectionIDFrame{ 119 SequenceNumber: 42, 120 ConnectionID: protocol.ParseConnectionID([]byte{1, 2, 3, 4}), 121 })).To(Succeed()) 122 Expect(m.Add(&wire.NewConnectionIDFrame{ 123 SequenceNumber: 42, 124 ConnectionID: protocol.ParseConnectionID([]byte{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.ParseConnectionID([]byte{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.ParseConnectionID([]byte{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.ParseConnectionID([]byte{1, 2, 3, 4}), 145 })).To(Succeed()) 146 Expect(m.Add(&wire.NewConnectionIDFrame{ 147 SequenceNumber: 13, 148 ConnectionID: protocol.ParseConnectionID([]byte{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.ParseConnectionID([]byte{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.ParseConnectionID([]byte{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.ParseConnectionID([]byte{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.ParseConnectionID([]byte{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.ParseConnectionID([]byte{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.ParseConnectionID([]byte{0xde, 0xad, 0xbe, 0xef}))) 192 193 Expect(m.Add(&wire.NewConnectionIDFrame{ 194 SequenceNumber: 9, 195 ConnectionID: protocol.ParseConnectionID([]byte{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.ParseConnectionID([]byte{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.ParseConnectionID([]byte{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.ParseConnectionID([]byte{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.ParseConnectionID([]byte{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.ParseConnectionID([]byte{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.ParseConnectionID([]byte{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.ParseConnectionID([]byte{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.ParseConnectionID([]byte{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.ParseConnectionID([]byte{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 != 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.ParseConnectionID([]byte{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.ParseConnectionID([]byte{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.ParseConnectionID([]byte{10, 10, 10, 10}))) 307 for { 308 m.SentPacket() 309 if m.Get() == protocol.ParseConnectionID([]byte{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.ParseConnectionID([]byte{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.ParseConnectionID([]byte{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.ParseConnectionID([]byte{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.ParseConnectionID([]byte{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.ParseConnectionID([]byte{1, 1, 1, 1}))) 337 for i := 0; i < 2*protocol.PacketsPerConnectionID; i++ { 338 m.SentPacket() 339 } 340 Expect(m.Get()).To(Equal(protocol.ParseConnectionID([]byte{1, 1, 1, 1}))) 341 Expect(m.Add(&wire.NewConnectionIDFrame{ 342 SequenceNumber: 1337, 343 ConnectionID: protocol.ParseConnectionID([]byte{1, 3, 3, 7}), 344 })).To(Succeed()) 345 Expect(m.Get()).To(Equal(protocol.ParseConnectionID([]byte{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.ParseConnectionID([]byte{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.ParseConnectionID([]byte{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 })