Fabric removal should only sync-deliver events for that fabric. (#21760)
* Fabric removal should only sync-deliver events for that fabric.
We were running into an issue where fabric removal would do sync event
delivery on other fabrics, and then removal of _those_ fabrics could
not deliver events (because there was a Report Data outstanding that
had not gotten a Status Response yet).
The fix is to only sync-deliver events for the fabric about to be
removed when a fabric is removed.
Fixes https://github.com/project-chip/connectedhomeip/issues/21744
* Address review comment.
diff --git a/src/app/clusters/operational-credentials-server/operational-credentials-server.cpp b/src/app/clusters/operational-credentials-server/operational-credentials-server.cpp
index 2c53a69..ab0b3f8 100644
--- a/src/app/clusters/operational-credentials-server/operational-credentials-server.cpp
+++ b/src/app/clusters/operational-credentials-server/operational-credentials-server.cpp
@@ -364,13 +364,13 @@
}
}
- // Try to send the queued events as soon as possible. If the just emitted leave event won't
+ // Try to send the queued events as soon as possible for this fabric. If the just emitted leave event won't
// be sent this time, it will likely not be delivered at all for the following reasons:
// - removing the fabric expires all associated ReadHandlers, so all subscriptions to
// the leave event will be cancelled.
// - removing the fabric removes all associated access control entries, so generating
// subsequent reports containing the leave event will fail the access control check.
- InteractionModelEngine::GetInstance()->GetReportingEngine().ScheduleUrgentEventDeliverySync();
+ InteractionModelEngine::GetInstance()->GetReportingEngine().ScheduleUrgentEventDeliverySync(MakeOptional(fabricIndex));
}
// Gets called when a fabric is deleted
diff --git a/src/app/reporting/Engine.cpp b/src/app/reporting/Engine.cpp
index 55527a5..792631f 100644
--- a/src/app/reporting/Engine.cpp
+++ b/src/app/reporting/Engine.cpp
@@ -981,14 +981,19 @@
return ScheduleBufferPressureEventDelivery(aBytesWritten);
}
-void Engine::ScheduleUrgentEventDeliverySync()
+void Engine::ScheduleUrgentEventDeliverySync(Optional<FabricIndex> fabricIndex)
{
- InteractionModelEngine::GetInstance()->mReadHandlers.ForEachActiveObject([](ReadHandler * handler) {
+ InteractionModelEngine::GetInstance()->mReadHandlers.ForEachActiveObject([fabricIndex](ReadHandler * handler) {
if (handler->IsType(ReadHandler::InteractionType::Read))
{
return Loop::Continue;
}
+ if (fabricIndex.HasValue() && fabricIndex.Value() != handler->GetAccessingFabricIndex())
+ {
+ return Loop::Continue;
+ }
+
handler->UnblockUrgentEventDelivery();
return Loop::Continue;
diff --git a/src/app/reporting/Engine.h b/src/app/reporting/Engine.h
index 620cecf..dc6b6f5 100644
--- a/src/app/reporting/Engine.h
+++ b/src/app/reporting/Engine.h
@@ -119,7 +119,13 @@
uint64_t GetDirtySetGeneration() const { return mDirtyGeneration; }
- void ScheduleUrgentEventDeliverySync();
+ /**
+ * Schedule event delivery to happen immediately and run reporting to get
+ * those reports into messages and on the wire. This can be done either for
+ * a specific fabric, identified by the provided FabricIndex, or across all
+ * fabrics if no FabricIndex is provided.
+ */
+ void ScheduleUrgentEventDeliverySync(Optional<FabricIndex> fabricIndex = NullOptional);
#if CONFIG_BUILD_FOR_HOST_UNIT_TEST
size_t GetGlobalDirtySetSize() { return mGlobalDirtySet.Allocated(); }