Deprecate --gfe2_reloadable_flag_quic_session_map_consistency_check PiperOrigin-RevId: 477725360
diff --git a/quiche/quic/core/quic_dispatcher.cc b/quiche/quic/core/quic_dispatcher.cc index be05103..acce420 100644 --- a/quiche/quic/core/quic_dispatcher.cc +++ b/quiche/quic/core/quic_dispatcher.cc
@@ -1099,10 +1099,38 @@ } closed_session_list_.push_back(std::move(it->second)); CleanUpSession(it->first, connection, error, error_details, source); + bool session_removed = false; for (const QuicConnectionId& cid : connection->GetActiveServerConnectionIds()) { - reference_counted_session_map_.erase(cid); + auto it1 = reference_counted_session_map_.find(cid); + if (it1 != reference_counted_session_map_.end()) { + const QuicSession* session2 = it1->second.get(); + // For cid == server_connection_id, session2 is a nullptr (and hence + // session2 != session) now since we have std::move the session into + // closed_session_list_ above. + if (session2 == session || cid == server_connection_id) { + reference_counted_session_map_.erase(it1); + session_removed = true; + } else { + // Leave this session in the map. + QUIC_BUG(quic_dispatcher_session_mismatch) + << "Session is mismatched in the map. server_connection_id: " + << server_connection_id << ". Current cid: " << cid + << ". Cid of the other session " + << (session2 == nullptr + ? "null" + : session2->connection()->connection_id().ToString()); + } + } else { + // GetActiveServerConnectionIds might return the original destination + // ID, which is not contained in the session map. + QUIC_BUG_IF(quic_dispatcher_session_not_found, + cid != connection->GetOriginalDestinationConnectionId()) + << "Missing session for cid " << cid + << ". server_connection_id: " << server_connection_id; + } } + QUIC_BUG_IF(quic_session_is_not_removed, !session_removed); --num_sessions_in_session_map_; }
diff --git a/quiche/quic/core/quic_dispatcher_test.cc b/quiche/quic/core/quic_dispatcher_test.cc index 8d14a8c..0382fdb 100644 --- a/quiche/quic/core/quic_dispatcher_test.cc +++ b/quiche/quic/core/quic_dispatcher_test.cc
@@ -2281,6 +2281,82 @@ } TEST_P(QuicDispatcherSupportMultipleConnectionIdPerConnectionTest, + TryAddNewConnectionIdWithCollision) { + AddConnection1(); + AddConnection2(); + ASSERT_EQ(dispatcher_->NumSessions(), 2u); + ASSERT_THAT(session1_, testing::NotNull()); + ASSERT_THAT(session2_, testing::NotNull()); + MockServerConnection* mock_server_connection1 = + reinterpret_cast<MockServerConnection*>(connection1()); + MockServerConnection* mock_server_connection2 = + reinterpret_cast<MockServerConnection*>(connection2()); + + { + // TestConnectionId(2) is already claimed by connection2 but connection1 + // still thinks it owns it. + mock_server_connection1->UnconditionallyAddNewConnectionIdForTest( + TestConnectionId(2)); + EXPECT_EQ(dispatcher_->NumSessions(), 2u); + auto* session = + QuicDispatcherPeer::FindSession(dispatcher_.get(), TestConnectionId(2)); + ASSERT_EQ(session, session2_); + EXPECT_THAT(mock_server_connection1->GetActiveServerConnectionIds(), + testing::ElementsAre(TestConnectionId(1), TestConnectionId(2))); + } + + { + mock_server_connection2->AddNewConnectionId(TestConnectionId(3)); + EXPECT_EQ(dispatcher_->NumSessions(), 2u); + auto* session = + QuicDispatcherPeer::FindSession(dispatcher_.get(), TestConnectionId(3)); + ASSERT_EQ(session, session2_); + EXPECT_THAT(mock_server_connection2->GetActiveServerConnectionIds(), + testing::ElementsAre(TestConnectionId(2), TestConnectionId(3))); + } + + // Connection2 removes both TestConnectionId(2) & TestConnectionId(3) from the + // session map. + dispatcher_->OnConnectionClosed(TestConnectionId(2), + QuicErrorCode::QUIC_NO_ERROR, "detail", + quic::ConnectionCloseSource::FROM_SELF); + // QUICHE_BUG fires when connection1 tries to remove TestConnectionId(2) + // again from the session_map. + EXPECT_QUICHE_BUG(dispatcher_->OnConnectionClosed( + TestConnectionId(1), QuicErrorCode::QUIC_NO_ERROR, + "detail", quic::ConnectionCloseSource::FROM_SELF), + "Missing session for cid"); +} + +TEST_P(QuicDispatcherSupportMultipleConnectionIdPerConnectionTest, + MismatchedSessionAfterAddingCollidedConnectionId) { + AddConnection1(); + AddConnection2(); + MockServerConnection* mock_server_connection1 = + reinterpret_cast<MockServerConnection*>(connection1()); + + { + // TestConnectionId(2) is already claimed by connection2 but connection1 + // still thinks it owns it. + mock_server_connection1->UnconditionallyAddNewConnectionIdForTest( + TestConnectionId(2)); + EXPECT_EQ(dispatcher_->NumSessions(), 2u); + auto* session = + QuicDispatcherPeer::FindSession(dispatcher_.get(), TestConnectionId(2)); + ASSERT_EQ(session, session2_); + EXPECT_THAT(mock_server_connection1->GetActiveServerConnectionIds(), + testing::ElementsAre(TestConnectionId(1), TestConnectionId(2))); + } + + // Connection1 tries to remove both Cid1 & Cid2, but they point to different + // sessions. + EXPECT_QUIC_BUG(dispatcher_->OnConnectionClosed( + TestConnectionId(1), QuicErrorCode::QUIC_NO_ERROR, + "detail", quic::ConnectionCloseSource::FROM_SELF), + "Session is mismatched in the map"); +} + +TEST_P(QuicDispatcherSupportMultipleConnectionIdPerConnectionTest, RetireConnectionIdFromSingleConnection) { AddConnection1(); ASSERT_EQ(dispatcher_->NumSessions(), 1u);