Skip to content

Commit

Permalink
[ICD] Send Check-In messages (#30526)
Browse files Browse the repository at this point in the history
* Send Check-in messages

* Fix comments

* fix comments

* fix comments
  • Loading branch information
jepenven-silabs authored and pull[bot] committed May 3, 2024
1 parent 3f174a7 commit 1176879
Show file tree
Hide file tree
Showing 9 changed files with 252 additions and 13 deletions.
3 changes: 2 additions & 1 deletion examples/lit-icd-app/linux/args.gni
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ chip_system_project_config_include = "<SystemProjectConfig.h>"

chip_project_config_include_dirs =
[ "${chip_root}/examples/lit-icd-app/linux/include" ]
chip_project_config_include_dirs += [ "${chip_root}/config/standalone" ]
chip_project_config_include_dirs +=
[ "${chip_root}/examples/lit-icd-app/linux/config/" ]
matter_enable_tracing_support = true

# ICD configurations
Expand Down
91 changes: 91 additions & 0 deletions examples/lit-icd-app/linux/config/CHIPProjectConfig.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
*
* Copyright (c) 2020-2022 Project CHIP Authors
* Copyright (c) 2016-2017 Nest Labs, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/**
* @file
* CHIP project configuration for standalone builds on Linux and OS X.
*
*/
#ifndef CHIPPROJECTCONFIG_H
#define CHIPPROJECTCONFIG_H

// TODO Cleanup this file, as most of it is irrelevant
// Issue #30616

#define CHIP_CONFIG_EVENT_LOGGING_NUM_EXTERNAL_CALLBACKS 2

// Uncomment this for a large Tunnel MTU.
// #define CHIP_CONFIG_TUNNEL_INTERFACE_MTU (9000)

// Enable support functions for parsing command-line arguments
#define CHIP_CONFIG_ENABLE_ARG_PARSER 1

// Enable use of test setup parameters for testing purposes only.
//
// WARNING: This option makes it possible to circumvent basic chip security functionality.
// Because of this it SHOULD NEVER BE ENABLED IN PRODUCTION BUILDS.
//
#ifndef CHIP_DEVICE_CONFIG_ENABLE_TEST_SETUP_PARAMS
#define CHIP_DEVICE_CONFIG_ENABLE_TEST_SETUP_PARAMS 1
#endif

// Enable reading DRBG seed data from /dev/(u)random.
// This is needed for test applications and the CHIP device manager to function
// properly when CHIP_CONFIG_RNG_IMPLEMENTATION_CHIPDRBG is enabled.
#define CHIP_CONFIG_DEV_RANDOM_DRBG_SEED 1

// For convenience, Chip Security Test Mode can be enabled and the
// requirement for authentication in various protocols can be disabled.
//
// WARNING: These options make it possible to circumvent basic Chip security functionality,
// including message encryption. Because of this they MUST NEVER BE ENABLED IN PRODUCTION BUILDS.
//
// To build with this flag, pass 'treat_warnings_as_errors=false' to gn/ninja.
//
#define CHIP_CONFIG_SECURITY_TEST_MODE 0

#define CHIP_CONFIG_ENABLE_UPDATE 1

#define CHIP_SYSTEM_CONFIG_PACKETBUFFER_POOL_SIZE 0

#define CHIP_CONFIG_DATA_MANAGEMENT_CLIENT_EXPERIMENTAL 1

#ifndef CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT
#define CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT 4
#endif

#ifndef CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION
#define CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION 1
#endif

#ifndef CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING
#define CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING "1.0"
#endif

//
// Default of 8 ECs is not sufficient for some of the unit tests
// that try to validate multiple simultaneous interactions.
// In tests like TestReadHandler_MultipleSubscriptions, we are trying to issue as many read / subscription requests as possible in
// parallel. Since the default config says we support 16 fabrics, and we will have 4 read handlers for each fabric (3 subscriptions
// + 1 reserved for read) that is read transactions in parallel. Since the report handlers are allocated on the heap, we will issue
// 65 requests (the TestReadHandler_MultipleSubscriptions will issue CHIP_IM_MAX_NUM_READ_HANDLER + 1 subscriptions to verify heap
// allocation logic) in total and that is 130 ECs. Round this up to 150 ECs
//
#define CHIP_CONFIG_MAX_EXCHANGE_CONTEXTS 150

#endif /* CHIPPROJECTCONFIG_H */
35 changes: 35 additions & 0 deletions examples/lit-icd-app/linux/config/SystemProjectConfig.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
*
* Copyright (c) 2020 Project CHIP Authors
* Copyright (c) 2018 Nest Labs, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/**
* @file
* chip::System project configuration for standalone builds on Linux and OS X.
*
*/
#ifndef SYSTEMPROJECTCONFIG_H
#define SYSTEMPROJECTCONFIG_H

// TODO Cleanup this file, as most of it is irrelevant
// Issue #30616

#if CHIP_SYSTEM_CONFIG_USE_SOCKETS
// Uncomment this for larger buffers (e.g. to support a bigger CHIP_CONFIG_TUNNEL_INTERFACE_MTU).
// #define CHIP_SYSTEM_CONFIG_PACKETBUFFER_CAPACITY_MAX 9050
#endif

#endif /* SYSTEMPROJECTCONFIG_H */
37 changes: 37 additions & 0 deletions src/app/InteractionModelEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,43 @@ void InteractionModelEngine::ShutdownMatchingSubscriptions(const Optional<Fabric
}
#endif // CHIP_CONFIG_ENABLE_READ_CLIENT

bool InteractionModelEngine::SubjectHasActiveSubscription(const FabricIndex aFabricIndex, const NodeId & subjectID)
{
bool isActive = false;
mReadHandlers.ForEachActiveObject([aFabricIndex, subjectID, &isActive](ReadHandler * handler) {
if (!handler->IsType(ReadHandler::InteractionType::Subscribe))
{
return Loop::Continue;
}

Access::SubjectDescriptor subject = handler->GetSubjectDescriptor();
if (subject.fabricIndex != aFabricIndex)
{
return Loop::Continue;
}

if (subject.authMode == Access::AuthMode::kCase)
{
if (subject.cats.CheckSubjectAgainstCATs(subjectID) || subjectID == subject.subject)
{
isActive = handler->IsActiveSubscription();

// Exit loop only if isActive is set to true
// Otherwise keep looking for another subscription that could
// match the subject
if (isActive)
{
return Loop::Break;
}
}
}

return Loop::Continue;
});

return isActive;
}

void InteractionModelEngine::OnDone(CommandHandler & apCommandObj)
{
mCommandHandlerObjs.ReleaseObject(&apCommandObj);
Expand Down
3 changes: 3 additions & 0 deletions src/app/InteractionModelEngine.h
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,9 @@ class InteractionModelEngine : public Messaging::UnsolicitedMessageHandler,

CHIP_ERROR ResumeSubscriptions();

// Check if a given subject (CAT or NodeId) has at least 1 active subscription
bool SubjectHasActiveSubscription(const FabricIndex aFabricIndex, const NodeId & subject);

#if CONFIG_BUILD_FOR_HOST_UNIT_TEST
//
// Get direct access to the underlying read handler pool
Expand Down
69 changes: 68 additions & 1 deletion src/app/icd/ICDManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
#include <platform/internal/CHIPDeviceLayerInternal.h>
#include <stdlib.h>

#include <app/InteractionModelEngine.h>

#ifndef ICD_ENFORCE_SIT_SLOW_POLL_LIMIT
// Set to 1 to enforce SIT Slow Polling Max value to 15seconds (spec 9.16.1.5)
#define ICD_ENFORCE_SIT_SLOW_POLL_LIMIT 0
Expand All @@ -44,11 +46,13 @@ using namespace chip::app::Clusters::IcdManagement;
static_assert(UINT8_MAX >= CHIP_CONFIG_MAX_EXCHANGE_CONTEXTS,
"ICDManager::mOpenExchangeContextCount cannot hold count for the max exchange count");

void ICDManager::Init(PersistentStorageDelegate * storage, FabricTable * fabricTable, Crypto::SymmetricKeystore * symmetricKeystore)
void ICDManager::Init(PersistentStorageDelegate * storage, FabricTable * fabricTable, Crypto::SymmetricKeystore * symmetricKeystore,
Messaging::ExchangeManager * exchangeManager)
{
VerifyOrDie(storage != nullptr);
VerifyOrDie(fabricTable != nullptr);
VerifyOrDie(symmetricKeystore != nullptr);
VerifyOrDie(exchangeManager != nullptr);

bool supportLIT = SupportsFeature(Feature::kLongIdleTimeSupport);
VerifyOrDieWithMsg((supportLIT == false) || SupportsFeature(Feature::kCheckInProtocolSupport), AppServer,
Expand All @@ -64,6 +68,7 @@ void ICDManager::Init(PersistentStorageDelegate * storage, FabricTable * fabricT
mFabricTable = fabricTable;
VerifyOrDie(ICDNotifier::GetInstance().Subscribe(this) == CHIP_NO_ERROR);
mSymmetricKeystore = symmetricKeystore;
mExchangeManager = exchangeManager;

ICDManagementServer::GetInstance().SetSymmetricKeystore(mSymmetricKeystore);

Expand All @@ -88,6 +93,7 @@ void ICDManager::Shutdown()
mStorage = nullptr;
mFabricTable = nullptr;
mStateObserverPool.ReleaseAll();
mICDSenderPool.ReleaseAll();
}

bool ICDManager::SupportsFeature(Feature feature)
Expand All @@ -102,6 +108,59 @@ bool ICDManager::SupportsFeature(Feature feature)
#endif // !CONFIG_BUILD_FOR_HOST_UNIT_TEST
}

void ICDManager::SendCheckInMsgs()
{
#if !CONFIG_BUILD_FOR_HOST_UNIT_TEST
VerifyOrDie(mStorage != nullptr);
VerifyOrDie(mFabricTable != nullptr);
for (const auto & fabricInfo : *mFabricTable)
{
uint16_t supported_clients = ICDManagementServer::GetInstance().GetClientsSupportedPerFabric();

ICDMonitoringTable table(*mStorage, fabricInfo.GetFabricIndex(), supported_clients /*Table entry limit*/,
mSymmetricKeystore);
if (table.IsEmpty())
{
continue;
}

for (uint16_t i = 0; i < table.Limit(); i++)
{
ICDMonitoringEntry entry(mSymmetricKeystore);
CHIP_ERROR err = table.Get(i, entry);
if (err == CHIP_ERROR_NOT_FOUND)
{
break;
}

if (err != CHIP_NO_ERROR)
{
// Try to fetch the next entry upon failure (should not happen).
ChipLogError(AppServer, "Failed to retrieved ICDMonitoring entry for Check-In msg, will try next entry.");
continue;
}

bool active =
InteractionModelEngine::GetInstance()->SubjectHasActiveSubscription(entry.fabricIndex, entry.monitoredSubject);
if (active)
{
continue;
}

// SenderPool will be released upon transition from active to idle state
// This will happen when all ICD Check-In messages are sent on the network
ICDCheckInSender * sender = mICDSenderPool.CreateObject(mExchangeManager);
VerifyOrReturn(sender != nullptr, ChipLogError(AppServer, "Failed to allocate ICDCheckinSender"));

if (CHIP_NO_ERROR != sender->RequestResolve(entry, mFabricTable))
{
ChipLogError(AppServer, "Failed to send ICD Check-In");
}
}
}
#endif // CONFIG_BUILD_FOR_HOST_UNIT_TEST
}

void ICDManager::UpdateICDMode()
{
assertChipStackLockedByCurrentThread();
Expand Down Expand Up @@ -167,6 +226,9 @@ void ICDManager::UpdateOperationState(OperationalState state)
}
#endif

// Going back to Idle, all Check-In messages are sent
mICDSenderPool.ReleaseAll();

CHIP_ERROR err = DeviceLayer::ConnectivityMgr().SetPollingInterval(slowPollInterval);
if (err != CHIP_NO_ERROR)
{
Expand Down Expand Up @@ -203,6 +265,11 @@ void ICDManager::UpdateOperationState(OperationalState state)
ChipLogError(AppServer, "Failed to set Fast Polling Interval: err %" CHIP_ERROR_FORMAT, err.Format());
}

if (SupportsFeature(Feature::kCheckInProtocolSupport))
{
SendCheckInMsgs();
}

postObserverEvent(ObserverEventType::EnterActiveMode);
}
else
Expand Down
7 changes: 6 additions & 1 deletion src/app/icd/ICDManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#pragma once

#include <app-common/zap-generated/cluster-enums.h>
#include <app/icd/ICDCheckInSender.h>
#include <app/icd/ICDMonitoringTable.h>
#include <app/icd/ICDNotifier.h>
#include <app/icd/ICDStateObserver.h>
Expand Down Expand Up @@ -69,7 +70,8 @@ class ICDManager : public ICDListener
};

ICDManager() {}
void Init(PersistentStorageDelegate * storage, FabricTable * fabricTable, Crypto::SymmetricKeystore * symmetricKeyStore);
void Init(PersistentStorageDelegate * storage, FabricTable * fabricTable, Crypto::SymmetricKeystore * symmetricKeyStore,
Messaging::ExchangeManager * exchangeManager);
void Shutdown();
void UpdateICDMode();
void UpdateOperationState(OperationalState state);
Expand Down Expand Up @@ -97,6 +99,7 @@ class ICDManager : public ICDListener
void postObserverEvent(ObserverEventType event);
ICDMode GetICDMode() { return mICDMode; }
OperationalState GetOperationalState() { return mOperationalState; }
void SendCheckInMsgs();

static System::Clock::Milliseconds32 GetSITPollingThreshold() { return kSITPollingThreshold; }
static System::Clock::Milliseconds32 GetFastPollingInterval() { return kFastPollingInterval; }
Expand Down Expand Up @@ -148,9 +151,11 @@ class ICDManager : public ICDListener
ICDMode mICDMode = ICDMode::SIT;
PersistentStorageDelegate * mStorage = nullptr;
FabricTable * mFabricTable = nullptr;
Messaging::ExchangeManager * mExchangeManager = nullptr;
bool mTransitionToIdleCalled = false;
Crypto::SymmetricKeystore * mSymmetricKeystore = nullptr;
ObjectPool<ObserverPointer, CHIP_CONFIG_ICD_OBSERVERS_POOL_SIZE> mStateObserverPool;
ObjectPool<ICDCheckInSender, (CHIP_CONFIG_ICD_CLIENTS_SUPPORTED_PER_FABRIC * CHIP_CONFIG_MAX_FABRICS)> mICDSenderPool;

#ifdef CONFIG_BUILD_FOR_HOST_UNIT_TEST
// feature map that can be changed at runtime for testing purposes
Expand Down
18 changes: 9 additions & 9 deletions src/app/server/Server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -255,15 +255,6 @@ CHIP_ERROR Server::Init(const ServerInitParams & initParams)
// This initializes clusters, so should come after lower level initialization.
InitDataModelHandler();

// ICD Init needs to be after data model init
#if CHIP_CONFIG_ENABLE_ICD_SERVER
mICDManager.Init(mDeviceStorage, &GetFabricTable(), mSessionKeystore);
// Register the ICDStateObservers. All observers are released at mICDManager.Shutdown()
// They can be released individually with ReleaseObserver
mICDManager.RegisterObserver(mReportScheduler);
mICDManager.RegisterObserver(&app::DnssdServer::Instance());
#endif // CHIP_CONFIG_ENABLE_ICD_SERVER

#if defined(CHIP_APP_USE_ECHO)
err = InitEchoHandler(&mExchangeMgr);
SuccessOrExit(err);
Expand Down Expand Up @@ -328,6 +319,15 @@ CHIP_ERROR Server::Init(const ServerInitParams & initParams)
&mCASESessionManager, mSubscriptionResumptionStorage);
SuccessOrExit(err);

// ICD Init needs to be after data model init and InteractionModel Init
#if CHIP_CONFIG_ENABLE_ICD_SERVER
mICDManager.Init(mDeviceStorage, &GetFabricTable(), mSessionKeystore, &mExchangeMgr);
// Register the ICDStateObservers. All observers are released at mICDManager.Shutdown()
// They can be released individually with ReleaseObserver
mICDManager.RegisterObserver(mReportScheduler);
mICDManager.RegisterObserver(&app::DnssdServer::Instance());
#endif // CHIP_CONFIG_ENABLE_ICD_SERVER

// This code is necessary to restart listening to existing groups after a reboot
// Each manufacturer needs to validate that they can rejoin groups by placing this code at the appropriate location for them
//
Expand Down
2 changes: 1 addition & 1 deletion src/app/tests/TestICDManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ class TestContext : public Test::AppContext
{
return FAILURE;
}
ctx->mICDManager.Init(&ctx->testStorage, &ctx->GetFabricTable(), &(ctx->mKeystore));
ctx->mICDManager.Init(&ctx->testStorage, &ctx->GetFabricTable(), &(ctx->mKeystore), &(ctx->GetExchangeManager()));
ctx->mICDManager.RegisterObserver(&mICDStateObserver);
return SUCCESS;
}
Expand Down

0 comments on commit 1176879

Please sign in to comment.