Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 36 additions & 10 deletions Sources/SwiftNetwork/QUIC/Migration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ struct Migration: ~Copyable {
return
}

let oldPath = connection.currentPath
connection.log.notice("Migrating to path \(path.identifier)")
connection.currentPath = path
path.spinValue = connection.initialSpinValue
Expand All @@ -128,6 +129,10 @@ struct Migration: ~Copyable {
}
// TODO: Handle preferred address migration

// Remove the path we just migrated away from.
if let oldPath, oldPath != path {
connection.tearDownMigratedPath(oldPath)
}
}

func probingPathCount(_ connection: QUICConnection) -> Int {
Expand Down Expand Up @@ -197,16 +202,7 @@ extension QUICConnection {
}
break
case .unavailable:
if path.isOpenForSending, let dcid = path.dcid,
let sequence = remoteCIDs.retire(connectionID: dcid)
{
withPendingItems(
for: .applicationData,
block: {
$0.addRetireConnectionID(FrameRetireConnectionID(sequence: sequence))
}
)
}
retireOutboundCID(forPathGoingAway: path)
path.changeState(to: .routeUnavailable)
break
}
Expand All @@ -225,5 +221,35 @@ extension QUICConnection {
sendFrames(on: path)
}
}

// Retires a path's outbound CID and queues a RETIRE_CONNECTION_ID frame for it.
func retireOutboundCID(forPathGoingAway path: QUICPath) {
guard path.isOpenForSending, !path.hasPreAssignedCIDs, let dcid = path.dcid,
let sequence = remoteCIDs.retire(connectionID: dcid)
else {
return
}
withPendingItems(for: .applicationData) {
$0.addRetireConnectionID(FrameRetireConnectionID(sequence: sequence))
}
}

// Removes a path we migrated away from.
func tearDownMigratedPath(_ oldPath: QUICPath) {
guard oldPath !== currentPath else {
log.fault("Refusing to tear down the current path \(oldPath.identifier)")
return
}
log.notice("Tearing down old path \(oldPath.identifier) after migration")

retireOutboundCID(forPathGoingAway: oldPath)

if oldPath.state.isValidStateChange(to: .routeUnavailable) {
oldPath.changeState(to: .routeUnavailable)
}
oldPath.tearDownLowerStack()
multiplexingPaths.removeValue(forKey: oldPath.identifier)
sendFrames()
}
}
#endif
4 changes: 4 additions & 0 deletions Sources/SwiftNetwork/QUIC/QUICPath.swift
Original file line number Diff line number Diff line change
Expand Up @@ -623,6 +623,10 @@ public final class QUICPath: MultiplexingDatagramPath<QUICConnection>, Equatable
parentProtocol.migration.migrate(to: self, connection: parentProtocol)
}
}

func tearDownLowerStack() {
try? lower.invokeDetach(self.reference)
}
}

// Congestion Control access
Expand Down
Loading