@@ -106,6 +106,7 @@ struct Migration: ~Copyable {
106106 return
107107 }
108108
109+ let oldPath = connection. currentPath
109110 connection. log. notice ( " Migrating to path \( path. identifier) " )
110111 connection. currentPath = path
111112 path. spinValue = connection. initialSpinValue
@@ -128,6 +129,10 @@ struct Migration: ~Copyable {
128129 }
129130 // TODO: Handle preferred address migration
130131
132+ // Remove the path we just migrated away from.
133+ if let oldPath, oldPath != path {
134+ connection. tearDownMigratedPath ( oldPath)
135+ }
131136 }
132137
133138 func probingPathCount( _ connection: QUICConnection ) -> Int {
@@ -197,16 +202,7 @@ extension QUICConnection {
197202 }
198203 break
199204 case . unavailable:
200- if path. isOpenForSending, let dcid = path. dcid,
201- let sequence = remoteCIDs. retire ( connectionID: dcid)
202- {
203- withPendingItems (
204- for: . applicationData,
205- block: {
206- $0. addRetireConnectionID ( FrameRetireConnectionID ( sequence: sequence) )
207- }
208- )
209- }
205+ retireOutboundCID ( forPathGoingAway: path)
210206 path. changeState ( to: . routeUnavailable)
211207 break
212208 }
@@ -225,5 +221,35 @@ extension QUICConnection {
225221 sendFrames ( on: path)
226222 }
227223 }
224+
225+ // Retires a path's outbound CID and queues a RETIRE_CONNECTION_ID frame for it.
226+ func retireOutboundCID( forPathGoingAway path: QUICPath ) {
227+ guard path. isOpenForSending, !path. hasPreAssignedCIDs, let dcid = path. dcid,
228+ let sequence = remoteCIDs. retire ( connectionID: dcid)
229+ else {
230+ return
231+ }
232+ withPendingItems ( for: . applicationData) {
233+ $0. addRetireConnectionID ( FrameRetireConnectionID ( sequence: sequence) )
234+ }
235+ }
236+
237+ // Removes a path we migrated away from.
238+ func tearDownMigratedPath( _ oldPath: QUICPath ) {
239+ guard oldPath !== currentPath else {
240+ log. fault ( " Refusing to tear down the current path \( oldPath. identifier) " )
241+ return
242+ }
243+ log. notice ( " Tearing down old path \( oldPath. identifier) after migration " )
244+
245+ retireOutboundCID ( forPathGoingAway: oldPath)
246+
247+ if oldPath. state. isValidStateChange ( to: . routeUnavailable) {
248+ oldPath. changeState ( to: . routeUnavailable)
249+ }
250+ oldPath. tearDownLowerStack ( )
251+ multiplexingPaths. removeValue ( forKey: oldPath. identifier)
252+ sendFrames ( )
253+ }
228254}
229255#endif
0 commit comments