Skip to content

Commit 3a9288b

Browse files
committed
MSRP: improve port state access safety in talker propagation
The talker propagation logic in _onRegisterStreamIndication read port state once at the beginning of the apply loop and then used that snapshot across multiple await suspension points where concurrent operations could modify the underlying state. This was particularly problematic for _canBridgeTalker, which makes admission control decisions based on bandwidth calculations. This change addresses the race condition by reading port state twice: once for the initial pruning check (where a snapshot is acceptable) and again immediately before _canBridgeTalker (to ensure bandwidth calculations use current state), reducing the window for stale data to cause incorrect admission control decisions.
1 parent d6d8e2d commit 3a9288b

File tree

1 file changed

+10
-3
lines changed

1 file changed

+10
-3
lines changed

Sources/MRP/Applications/MSRP/MSRPApplication.swift

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -899,11 +899,13 @@ extension MSRPApplication {
899899
guard participant.port != port else { return } // don't propagate to source port
900900

901901
let port = participant.port
902-
guard let portState = try? withPortState(port: port, { $0 }) else { return }
902+
903+
// Read port state for pruning check (snapshot is acceptable for this check)
904+
guard let initialPortState = try? withPortState(port: port, { $0 }) else { return }
903905

904906
guard await !_shouldPruneTalkerDeclaration(
905907
port: port,
906-
portState: portState,
908+
portState: initialPortState,
907909
streamID: talkerValue.streamID,
908910
declarationType: declarationType,
909911
dataFrameParameters: talkerValue.dataFrameParameters,
@@ -946,9 +948,14 @@ extension MSRPApplication {
946948

947949
if declarationType.isTalkerAdvertise {
948950
do {
951+
// Re-fetch port state for admission control to ensure current bandwidth calculations
952+
guard let currentPortState = try? withPortState(port: port, { $0 }) else {
953+
throw MSRPFailure(systemID: port.systemID, failureCode: .insufficientBridgeResources)
954+
}
955+
949956
try await _canBridgeTalker(
950957
participant: participant,
951-
portState: portState,
958+
portState: currentPortState,
952959
streamID: talkerValue.streamID,
953960
declarationType: declarationType,
954961
dataFrameParameters: talkerValue.dataFrameParameters,

0 commit comments

Comments
 (0)