@@ -9,6 +9,7 @@ package quic
99import  (
1010	"bytes" 
1111	"crypto/rand" 
12+ 	"slices" 
1213)
1314
1415// connIDState is a conn's connection IDs. 
@@ -25,8 +26,16 @@ type connIDState struct {
2526	remote  []remoteConnID 
2627
2728	nextLocalSeq           int64 
28- 	retireRemotePriorTo    int64  // largest Retire Prior To value sent by the peer 
29- 	peerActiveConnIDLimit  int64  // peer's active_connection_id_limit transport parameter 
29+ 	peerActiveConnIDLimit  int64  // peer's active_connection_id_limit 
30+ 
31+ 	// Handling of retirement of remote connection IDs. 
32+ 	// The rangesets track ID sequence numbers. 
33+ 	// IDs in need of retirement are added to remoteRetiring, 
34+ 	// moved to remoteRetiringSent once we send a RETIRE_CONECTION_ID frame, 
35+ 	// and removed from the set once retirement completes. 
36+ 	retireRemotePriorTo  int64            // largest Retire Prior To value sent by the peer 
37+ 	remoteRetiring       rangeset [int64 ] // remote IDs in need of retirement 
38+ 	remoteRetiringSent   rangeset [int64 ] // remote IDs waiting for ack of retirement 
3039
3140	originalDstConnID  []byte  // expected original_destination_connection_id param 
3241	retrySrcConnID     []byte  // expected retry_source_connection_id param 
@@ -45,9 +54,6 @@ type connID struct {
4554	// For the transient destination ID in a client's Initial packet, this is -1. 
4655	seq  int64 
4756
48- 	// retired is set when the connection ID is retired. 
49- 	retired  bool 
50- 
5157	// send is set when the connection ID's state needs to be sent to the peer. 
5258	// 
5359	// For local IDs, this indicates a new ID that should be sent 
@@ -144,24 +150,20 @@ func (s *connIDState) srcConnID() []byte {
144150// dstConnID is the Destination Connection ID to use in a sent packet. 
145151func  (s  * connIDState ) dstConnID () (cid  []byte , ok  bool ) {
146152	for  i  :=  range  s .remote  {
147- 		if  ! s .remote [i ].retired  {
148- 			return  s .remote [i ].cid , true 
149- 		}
153+ 		return  s .remote [i ].cid , true 
150154	}
151155	return  nil , false 
152156}
153157
154158// isValidStatelessResetToken reports whether the given reset token is 
155159// associated with a non-retired connection ID which we have used. 
156160func  (s  * connIDState ) isValidStatelessResetToken (resetToken  statelessResetToken ) bool  {
157- 	for  i  :=  range  s .remote  {
158- 		// We currently only use the first available remote connection ID, 
159- 		// so any other reset token is not valid. 
160- 		if  ! s .remote [i ].retired  {
161- 			return  s .remote [i ].resetToken  ==  resetToken 
162- 		}
161+ 	if  len (s .remote ) ==  0  {
162+ 		return  false 
163163	}
164- 	return  false 
164+ 	// We currently only use the first available remote connection ID, 
165+ 	// so any other reset token is not valid. 
166+ 	return  s .remote [0 ].resetToken  ==  resetToken 
165167}
166168
167169// setPeerActiveConnIDLimit sets the active_connection_id_limit 
@@ -174,7 +176,7 @@ func (s *connIDState) setPeerActiveConnIDLimit(c *Conn, lim int64) error {
174176func  (s  * connIDState ) issueLocalIDs (c  * Conn ) error  {
175177	toIssue  :=  min (int (s .peerActiveConnIDLimit ), maxPeerActiveConnIDLimit )
176178	for  i  :=  range  s .local  {
177- 		if  s .local [i ].seq  !=  - 1  &&   ! s . local [ i ]. retired   {
179+ 		if  s .local [i ].seq  !=  - 1  {
178180			toIssue -- 
179181		}
180182	}
@@ -271,7 +273,7 @@ func (s *connIDState) handlePacket(c *Conn, ptype packetType, srcConnID []byte)
271273			}
272274		}
273275	case  ptype  ==  packetTypeHandshake  &&  c .side  ==  serverSide :
274- 		if  len (s .local ) >  0  &&  s .local [0 ].seq  ==  - 1  &&   ! s . local [ 0 ]. retired   {
276+ 		if  len (s .local ) >  0  &&  s .local [0 ].seq  ==  - 1  {
275277			// We're a server connection processing the first Handshake packet from 
276278			// the client. Discard the transient, client-chosen connection ID used 
277279			// for Initial packets; the client will never send it again. 
@@ -304,23 +306,29 @@ func (s *connIDState) handleNewConnID(c *Conn, seq, retire int64, cid []byte, re
304306		}
305307	}
306308
309+ 	if  seq  <  s .retireRemotePriorTo  {
310+ 		// This ID was already retired by a previous NEW_CONNECTION_ID frame. 
311+ 		// Nothing to do. 
312+ 		return  nil 
313+ 	}
314+ 
307315	if  retire  >  s .retireRemotePriorTo  {
316+ 		// Add newly-retired connection IDs to the set we need to send 
317+ 		// RETIRE_CONNECTION_ID frames for, and remove them from s.remote. 
318+ 		// 
319+ 		// (This might cause us to send a RETIRE_CONNECTION_ID for an ID we've 
320+ 		// never seen. That's fine.) 
321+ 		s .remoteRetiring .add (s .retireRemotePriorTo , retire )
308322		s .retireRemotePriorTo  =  retire 
323+ 		s .needSend  =  true 
324+ 		s .remote  =  slices .DeleteFunc (s .remote , func (rcid  remoteConnID ) bool  {
325+ 			return  rcid .seq  <  s .retireRemotePriorTo 
326+ 		})
309327	}
310328
311329	have  :=  false  // do we already have this connection ID? 
312- 	active  :=  0 
313330	for  i  :=  range  s .remote  {
314331		rcid  :=  & s .remote [i ]
315- 		if  ! rcid .retired  &&  rcid .seq  >=  0  &&  rcid .seq  <  s .retireRemotePriorTo  {
316- 			s .retireRemote (rcid )
317- 			c .endpoint .connsMap .updateConnIDs (func (conns  * connsMap ) {
318- 				conns .retireResetToken (c , rcid .resetToken )
319- 			})
320- 		}
321- 		if  ! rcid .retired  {
322- 			active ++ 
323- 		}
324332		if  rcid .seq  ==  seq  {
325333			if  ! bytes .Equal (rcid .cid , cid ) {
326334				return  localTransportError {
@@ -329,6 +337,7 @@ func (s *connIDState) handleNewConnID(c *Conn, seq, retire int64, cid []byte, re
329337				}
330338			}
331339			have  =  true  // yes, we've seen this sequence number 
340+ 			break 
332341		}
333342	}
334343
@@ -345,18 +354,12 @@ func (s *connIDState) handleNewConnID(c *Conn, seq, retire int64, cid []byte, re
345354			},
346355			resetToken : resetToken ,
347356		})
348- 		if  seq  <  s .retireRemotePriorTo  {
349- 			// This ID was already retired by a previous NEW_CONNECTION_ID frame. 
350- 			s .retireRemote (& s .remote [len (s .remote )- 1 ])
351- 		} else  {
352- 			active ++ 
353- 			c .endpoint .connsMap .updateConnIDs (func (conns  * connsMap ) {
354- 				conns .addResetToken (c , resetToken )
355- 			})
356- 		}
357+ 		c .endpoint .connsMap .updateConnIDs (func (conns  * connsMap ) {
358+ 			conns .addResetToken (c , resetToken )
359+ 		})
357360	}
358361
359- 	if  active  >  activeConnIDLimit  {
362+ 	if  len ( s . remote )  >  activeConnIDLimit  {
360363		// Retired connection IDs (including newly-retired ones) do not count 
361364		// against the limit. 
362365		// https://www.rfc-editor.org/rfc/rfc9000.html#section-5.1.1-5 
@@ -370,25 +373,18 @@ func (s *connIDState) handleNewConnID(c *Conn, seq, retire int64, cid []byte, re
370373	// for which RETIRE_CONNECTION_ID frames have not yet been acknowledged." 
371374	// https://www.rfc-editor.org/rfc/rfc9000#section-5.1.2-6 
372375	// 
373- 	// Set a limit of four  times the active_connection_id_limit for 
374- 	// the total number of remote connection IDs we keep state for locally . 
375- 	if  len ( s . remote ) >  4 * activeConnIDLimit  {
376+ 	// Set a limit of three  times the active_connection_id_limit for 
377+ 	// the total number of remote connection IDs we keep retirement  state for. 
378+ 	if  s . remoteRetiring . size () + s . remoteRetiringSent . size ( ) >  3 * activeConnIDLimit  {
376379		return  localTransportError {
377380			code :   errConnectionIDLimit ,
378- 			reason : "too many unacknowledged RETIRE_CONNECTION_ID frames " ,
381+ 			reason : "too many unacknowledged retired connection ids " ,
379382		}
380383	}
381384
382385	return  nil 
383386}
384387
385- // retireRemote marks a remote connection ID as retired. 
386- func  (s  * connIDState ) retireRemote (rcid  * remoteConnID ) {
387- 	rcid .retired  =  true 
388- 	rcid .send .setUnsent ()
389- 	s .needSend  =  true 
390- }
391- 
392388func  (s  * connIDState ) handleRetireConnID (c  * Conn , seq  int64 ) error  {
393389	if  seq  >=  s .nextLocalSeq  {
394390		return  localTransportError {
@@ -424,20 +420,11 @@ func (s *connIDState) ackOrLossNewConnectionID(pnum packetNumber, seq int64, fat
424420}
425421
426422func  (s  * connIDState ) ackOrLossRetireConnectionID (pnum  packetNumber , seq  int64 , fate  packetFate ) {
427- 	for  i  :=  0 ; i  <  len (s .remote ); i ++  {
428- 		if  s .remote [i ].seq  !=  seq  {
429- 			continue 
430- 		}
431- 		if  fate  ==  packetAcked  {
432- 			// We have retired this connection ID, and the peer has acked. 
433- 			// Discard its state completely. 
434- 			s .remote  =  append (s .remote [:i ], s .remote [i + 1 :]... )
435- 		} else  {
436- 			// RETIRE_CONNECTION_ID frame was lost, mark for retransmission. 
437- 			s .needSend  =  true 
438- 			s .remote [i ].send .ackOrLoss (pnum , fate )
439- 		}
440- 		return 
423+ 	s .remoteRetiringSent .sub (seq , seq + 1 )
424+ 	if  fate  ==  packetLost  {
425+ 		// RETIRE_CONNECTION_ID frame was lost, mark for retransmission. 
426+ 		s .remoteRetiring .add (seq , seq + 1 )
427+ 		s .needSend  =  true 
441428	}
442429}
443430
@@ -469,14 +456,22 @@ func (s *connIDState) appendFrames(c *Conn, pnum packetNumber, pto bool) bool {
469456		}
470457		s .local [i ].send .setSent (pnum )
471458	}
472- 	for  i  :=  range  s .remote  {
473- 		if  ! s .remote [i ].send .shouldSendPTO (pto ) {
474- 			continue 
459+ 	if  pto  {
460+ 		for  _ , r  :=  range  s .remoteRetiringSent  {
461+ 			for  cid  :=  r .start ; cid  <  r .end ; cid ++  {
462+ 				if  ! c .w .appendRetireConnectionIDFrame (cid ) {
463+ 					return  false 
464+ 				}
465+ 			}
475466		}
476- 		if  ! c .w .appendRetireConnectionIDFrame (s .remote [i ].seq ) {
467+ 	}
468+ 	for  s .remoteRetiring .numRanges () >  0  {
469+ 		cid  :=  s .remoteRetiring .min ()
470+ 		if  ! c .w .appendRetireConnectionIDFrame (cid ) {
477471			return  false 
478472		}
479- 		s .remote [i ].send .setSent (pnum )
473+ 		s .remoteRetiring .sub (cid , cid + 1 )
474+ 		s .remoteRetiringSent .add (cid , cid + 1 )
480475	}
481476	s .needSend  =  false 
482477	return  true 
0 commit comments