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