diff --git a/src/app/BUILD.gn b/src/app/BUILD.gn index 72ea5a92025beb..60ff26ea660c86 100644 --- a/src/app/BUILD.gn +++ b/src/app/BUILD.gn @@ -40,6 +40,9 @@ static_library("app") { "AttributePathExpandIterator.h", "AttributePathParams.h", "BufferedReadCallback.cpp", + "CASEClient.cpp", + "CASEClient.h", + "CASEClientPool.h", "CASESessionManager.cpp", "CASESessionManager.h", "Command.cpp", @@ -121,6 +124,7 @@ static_library("app") { "MessageDef/WriteResponseMessage.cpp", "OperationalDeviceProxy.cpp", "OperationalDeviceProxy.h", + "OperationalDeviceProxyPool.h", "ReadClient.cpp", "ReadHandler.cpp", "StatusResponse.cpp", diff --git a/src/app/CASEClient.cpp b/src/app/CASEClient.cpp new file mode 100644 index 00000000000000..c0fe3c4b89090b --- /dev/null +++ b/src/app/CASEClient.cpp @@ -0,0 +1,92 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * + * 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. + */ + +#include + +namespace chip { + +CASEClient::CASEClient(const CASEClientInitParams & params) : mInitParams(params) {} + +void CASEClient::SetMRPIntervals(const ReliableMessageProtocolConfig & mrpConfig) +{ + mCASESession.SetMRPConfig(mrpConfig); +} + +CHIP_ERROR CASEClient::EstablishSession(PeerId peer, const Transport::PeerAddress & peerAddress, + const ReliableMessageProtocolConfig & mrpConfig, OnCASEConnected onConnection, + OnCASEConnectionFailure onFailure, void * context) +{ + // Create a UnauthenticatedSession for CASE pairing. + // Don't use mSecureSession here, because mSecureSession is for encrypted communication. + Optional session = mInitParams.sessionManager->CreateUnauthenticatedSession(peerAddress, mrpConfig); + VerifyOrReturnError(session.HasValue(), CHIP_ERROR_NO_MEMORY); + + Messaging::ExchangeContext * exchange = mInitParams.exchangeMgr->NewContext(session.Value(), &mCASESession); + VerifyOrReturnError(exchange != nullptr, CHIP_ERROR_INTERNAL); + + ReturnErrorOnFailure(mCASESession.MessageDispatch().Init(mInitParams.sessionManager)); + + uint16_t keyID = 0; + ReturnErrorOnFailure(mInitParams.idAllocator->Allocate(keyID)); + + ReturnErrorOnFailure( + mCASESession.EstablishSession(peerAddress, mInitParams.fabricInfo, peer.GetNodeId(), keyID, exchange, this)); + mConnectionSuccessCallback = onConnection; + mConnectionFailureCallback = onFailure; + mConectionContext = context; + mPeerId = peer; + mPeerAddress = peerAddress; + + return CHIP_NO_ERROR; +} + +void CASEClient::OnSessionEstablishmentError(CHIP_ERROR error) +{ + mInitParams.idAllocator->Free(mCASESession.GetLocalSessionId()); + + if (mConnectionFailureCallback) + { + mConnectionFailureCallback(mConectionContext, this, error); + } +} + +void CASEClient::OnSessionEstablished() +{ + // On successfull CASE connection, the local session ID will be used for the derived secure session. + if (mConnectionSuccessCallback) + { + mConnectionSuccessCallback(mConectionContext, this); + } +} + +CHIP_ERROR CASEClient::DeriveSecureSessionHandle(Optional & handle) +{ + CHIP_ERROR err = mInitParams.sessionManager->NewPairing( + Optional::Value(mPeerAddress), mPeerId.GetNodeId(), &mCASESession, + CryptoContext::SessionRole::kInitiator, mInitParams.fabricInfo->GetFabricIndex()); + if (err != CHIP_NO_ERROR) + { + ChipLogError(Controller, "Failed in setting up CASE secure channel: err %s", ErrorStr(err)); + return err; + } + handle.SetValue(SessionHandle(mPeerId.GetNodeId(), mCASESession.GetLocalSessionId(), mCASESession.GetPeerSessionId(), + mInitParams.fabricInfo->GetFabricIndex())); + + return CHIP_NO_ERROR; +} + +}; // namespace chip diff --git a/src/app/CASEClient.h b/src/app/CASEClient.h new file mode 100644 index 00000000000000..22b68ecfde34c2 --- /dev/null +++ b/src/app/CASEClient.h @@ -0,0 +1,70 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * + * 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. + */ + +#pragma once + +#include +#include +#include +#include + +namespace chip { + +class CASEClient; + +typedef void (*OnCASEConnected)(void * context, CASEClient * client); +typedef void (*OnCASEConnectionFailure)(void * context, CASEClient * client, CHIP_ERROR error); + +struct CASEClientInitParams +{ + SessionManager * sessionManager = nullptr; + Messaging::ExchangeManager * exchangeMgr = nullptr; + SessionIDAllocator * idAllocator = nullptr; + FabricInfo * fabricInfo = nullptr; +}; + +class DLL_EXPORT CASEClient : public SessionEstablishmentDelegate +{ +public: + CASEClient(const CASEClientInitParams & params); + + void SetMRPIntervals(const ReliableMessageProtocolConfig & mrpConfig); + + CHIP_ERROR EstablishSession(PeerId peer, const Transport::PeerAddress & peerAddress, + const ReliableMessageProtocolConfig & mrpConfig, OnCASEConnected onConnection, + OnCASEConnectionFailure onFailure, void * context); + + // Implementation of SessionEstablishmentDelegate + void OnSessionEstablishmentError(CHIP_ERROR error) override; + + void OnSessionEstablished() override; + + CHIP_ERROR DeriveSecureSessionHandle(Optional & handle); + +private: + CASEClientInitParams mInitParams; + + CASESession mCASESession; + PeerId mPeerId; + Transport::PeerAddress mPeerAddress; + + OnCASEConnected mConnectionSuccessCallback = nullptr; + OnCASEConnectionFailure mConnectionFailureCallback = nullptr; + void * mConectionContext = nullptr; +}; + +} // namespace chip diff --git a/src/app/CASEClientPool.h b/src/app/CASEClientPool.h new file mode 100644 index 00000000000000..15c9f2a985ff44 --- /dev/null +++ b/src/app/CASEClientPool.h @@ -0,0 +1,47 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * + * 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. + */ + +#pragma once + +#include +#include + +namespace chip { + +class CASEClientPoolDelegate +{ +public: + virtual CASEClient * Allocate(CASEClientInitParams params) = 0; + + virtual void Release(CASEClient * client) = 0; + + virtual ~CASEClientPoolDelegate() {} +}; + +template +class CASEClientPool : public CASEClientPoolDelegate +{ +public: + CASEClient * Allocate(CASEClientInitParams params) override { return mClientPool.CreateObject(params); } + + void Release(CASEClient * client) override { mClientPool.ReleaseObject(client); } + +private: + BitMapObjectPool mClientPool; +}; + +}; // namespace chip diff --git a/src/app/CASESessionManager.cpp b/src/app/CASESessionManager.cpp index 19cc27dc31c4fd..559ae13fde2979 100644 --- a/src/app/CASESessionManager.cpp +++ b/src/app/CASESessionManager.cpp @@ -35,11 +35,11 @@ CHIP_ERROR CASESessionManager::FindOrEstablishSession(NodeId nodeId, Callback::C // TODO - Implement LRU to evict least recently used session to handle mActiveSessions pool exhaustion if (nodeIDWasResolved) { - session = mActiveSessions.CreateObject(mConfig.sessionInitParams, peerId, resolutionData); + session = mConfig.devicePool->Allocate(mConfig.sessionInitParams, peerId, resolutionData); } else { - session = mActiveSessions.CreateObject(mConfig.sessionInitParams, peerId); + session = mConfig.devicePool->Allocate(mConfig.sessionInitParams, peerId); } if (session == nullptr) @@ -120,39 +120,19 @@ void CASESessionManager::OnSessionReleased(SessionHandle sessionHandle) OperationalDeviceProxy * CASESessionManager::FindSession(SessionHandle session) { - OperationalDeviceProxy * foundSession = nullptr; - mActiveSessions.ForEachActiveObject([&](auto * activeSession) { - if (activeSession->MatchesSession(session)) - { - foundSession = activeSession; - return Loop::Break; - } - return Loop::Continue; - }); - - return foundSession; + return mConfig.devicePool->FindDevice(session); } OperationalDeviceProxy * CASESessionManager::FindExistingSession(NodeId id) { - OperationalDeviceProxy * foundSession = nullptr; - mActiveSessions.ForEachActiveObject([&](auto * activeSession) { - if (activeSession->GetDeviceId() == id) - { - foundSession = activeSession; - return Loop::Break; - } - return Loop::Continue; - }); - - return foundSession; + return mConfig.devicePool->FindDevice(id); } void CASESessionManager::ReleaseSession(OperationalDeviceProxy * session) { if (session != nullptr) { - mActiveSessions.ReleaseObject(session); + mConfig.devicePool->Release(session); } } diff --git a/src/app/CASESessionManager.h b/src/app/CASESessionManager.h index 65253af176c766..cbad650c0886c7 100644 --- a/src/app/CASESessionManager.h +++ b/src/app/CASESessionManager.h @@ -18,7 +18,9 @@ #pragma once +#include #include +#include #include #include #include @@ -33,6 +35,7 @@ struct CASESessionManagerConfig { DeviceProxyInitParams sessionInitParams; Dnssd::DnssdCache * dnsCache = nullptr; + OperationalDeviceProxyPoolDelegate * devicePool = nullptr; }; /** @@ -50,7 +53,7 @@ class CASESessionManager : public SessionReleaseDelegate, public Dnssd::Resolver CASESessionManager(CASESessionManagerConfig & params) { - VerifyOrReturn(params.sessionInitParams.Validate() == CHIP_NO_ERROR); + VerifyOrDie(params.sessionInitParams.Validate() == CHIP_NO_ERROR); mConfig = params; } @@ -103,10 +106,6 @@ class CASESessionManager : public SessionReleaseDelegate, public Dnssd::Resolver OperationalDeviceProxy * FindSession(SessionHandle session); void ReleaseSession(OperationalDeviceProxy * device); - BitMapObjectPool - mActiveSessions; - CASESessionManagerConfig mConfig; }; diff --git a/src/app/OperationalDeviceProxy.cpp b/src/app/OperationalDeviceProxy.cpp index b308764ea065cd..81e0b29ab7d20f 100644 --- a/src/app/OperationalDeviceProxy.cpp +++ b/src/app/OperationalDeviceProxy.cpp @@ -26,6 +26,7 @@ #include "OperationalDeviceProxy.h" +#include "CASEClient.h" #include "CommandSender.h" #include "ReadPrepareParams.h" @@ -35,6 +36,7 @@ #include #include #include +#include using namespace chip::Callback; @@ -98,7 +100,10 @@ CHIP_ERROR OperationalDeviceProxy::UpdateDeviceData(const Transport::PeerAddress // Initialize CASE session state with any MRP parameters that DNS-SD has provided. // It can be overridden by CASE session protocol messages that include MRP parameters. - mCASESession.SetMRPConfig(mMRPConfig); + if (mCASEClient) + { + mCASEClient->SetMRPIntervals(mMRPConfig); + } if (mState == State::NeedsAddress) { @@ -144,21 +149,12 @@ bool OperationalDeviceProxy::GetAddress(Inet::IPAddress & addr, uint16_t & port) CHIP_ERROR OperationalDeviceProxy::EstablishConnection() { - // Create a UnauthenticatedSession for CASE pairing. - // Don't use mSecureSession here, because mSecureSession is for encrypted communication. - Optional session = mInitParams.sessionManager->CreateUnauthenticatedSession(mDeviceAddress, mMRPConfig); - VerifyOrReturnError(session.HasValue(), CHIP_ERROR_NO_MEMORY); - - Messaging::ExchangeContext * exchange = mInitParams.exchangeMgr->NewContext(session.Value(), &mCASESession); - VerifyOrReturnError(exchange != nullptr, CHIP_ERROR_INTERNAL); - - ReturnErrorOnFailure(mCASESession.MessageDispatch().Init(mInitParams.sessionManager)); - - uint16_t keyID = 0; - ReturnErrorOnFailure(mInitParams.idAllocator->Allocate(keyID)); - - ReturnErrorOnFailure( - mCASESession.EstablishSession(mDeviceAddress, mInitParams.fabricInfo, mPeerId.GetNodeId(), keyID, exchange, this)); + mCASEClient = mInitParams.clientPool->Allocate(CASEClientInitParams{ mInitParams.sessionManager, mInitParams.exchangeMgr, + mInitParams.idAllocator, mInitParams.fabricInfo }); + ReturnErrorCodeIf(mCASEClient == nullptr, CHIP_ERROR_NO_MEMORY); + CHIP_ERROR err = + mCASEClient->EstablishSession(mPeerId, mDeviceAddress, mMRPConfig, HandleCASEConnected, HandleCASEConnectionFailure, this); + ReturnErrorOnFailure(err); mState = State::Connecting; @@ -212,39 +208,40 @@ void OperationalDeviceProxy::DequeueConnectionFailureCallbacks(CHIP_ERROR error, } } -void OperationalDeviceProxy::OnSessionEstablishmentError(CHIP_ERROR error) +void OperationalDeviceProxy::HandleCASEConnectionFailure(void * context, CASEClient * client, CHIP_ERROR error) { - VerifyOrReturn(mState != State::Uninitialized && mState != State::NeedsAddress, - ChipLogError(Controller, "OnSessionEstablishmentError was called while the device was not initialized")); + OperationalDeviceProxy * device = static_cast(context); + VerifyOrReturn(device->mState != State::Uninitialized && device->mState != State::NeedsAddress, + ChipLogError(Controller, "HandleCASEConnectionFailure was called while the device was not initialized")); + VerifyOrReturn(client == device->mCASEClient, ChipLogError(Controller, "HandleCASEConnectionFailure for unknown CASEClient")); - mState = State::Initialized; - mInitParams.idAllocator->Free(mCASESession.GetLocalSessionId()); + device->mState = State::Initialized; - DequeueConnectionSuccessCallbacks(/* executeCallback */ false); - DequeueConnectionFailureCallbacks(error, /* executeCallback */ true); + device->DequeueConnectionSuccessCallbacks(/* executeCallback */ false); + device->DequeueConnectionFailureCallbacks(error, /* executeCallback */ true); + device->DeferCloseCASESession(); } -void OperationalDeviceProxy::OnSessionEstablished() +void OperationalDeviceProxy::HandleCASEConnected(void * context, CASEClient * client) { - VerifyOrReturn(mState != State::Uninitialized, - ChipLogError(Controller, "OnSessionEstablished was called while the device was not initialized")); + OperationalDeviceProxy * device = static_cast(context); + VerifyOrReturn(device->mState != State::Uninitialized, + ChipLogError(Controller, "HandleCASEConnected was called while the device was not initialized")); + VerifyOrReturn(client == device->mCASEClient, ChipLogError(Controller, "HandleCASEConnected for unknown CASEClient")); - CHIP_ERROR err = mInitParams.sessionManager->NewPairing( - Optional::Value(mDeviceAddress), mPeerId.GetNodeId(), &mCASESession, - CryptoContext::SessionRole::kInitiator, mInitParams.fabricInfo->GetFabricIndex()); + CHIP_ERROR err = client->DeriveSecureSessionHandle(device->mSecureSession); if (err != CHIP_NO_ERROR) { - ChipLogError(Controller, "Failed in setting up CASE secure channel: err %s", ErrorStr(err)); - OnSessionEstablishmentError(err); - return; + device->HandleCASEConnectionFailure(context, client, err); } - mSecureSession.SetValue(SessionHandle(mPeerId.GetNodeId(), mCASESession.GetLocalSessionId(), mCASESession.GetPeerSessionId(), - mInitParams.fabricInfo->GetFabricIndex())); - - mState = State::SecureConnected; + else + { + device->mState = State::SecureConnected; - DequeueConnectionFailureCallbacks(CHIP_NO_ERROR, /* executeCallback */ false); - DequeueConnectionSuccessCallbacks(/* executeCallback */ true); + device->DequeueConnectionFailureCallbacks(CHIP_NO_ERROR, /* executeCallback */ false); + device->DequeueConnectionSuccessCallbacks(/* executeCallback */ true); + device->DeferCloseCASESession(); + } } CHIP_ERROR OperationalDeviceProxy::Disconnect() @@ -255,18 +252,42 @@ CHIP_ERROR OperationalDeviceProxy::Disconnect() mInitParams.sessionManager->ExpirePairing(mSecureSession.Value()); } mState = State::Initialized; - mCASESession.Clear(); + if (mCASEClient) + { + mInitParams.clientPool->Release(mCASEClient); + mCASEClient = nullptr; + } return CHIP_NO_ERROR; } void OperationalDeviceProxy::Clear() { - mCASESession.Clear(); + if (mCASEClient) + { + mInitParams.clientPool->Release(mCASEClient); + mCASEClient = nullptr; + } mState = State::Uninitialized; mInitParams = DeviceProxyInitParams(); } +void OperationalDeviceProxy::CloseCASESessionTask(System::Layer * layer, void * context) +{ + OperationalDeviceProxy * device = static_cast(context); + if (device->mCASEClient) + { + device->mInitParams.clientPool->Release(device->mCASEClient); + device->mCASEClient = nullptr; + } +} + +void OperationalDeviceProxy::DeferCloseCASESession() +{ + // Defer the release for the pending Ack to be sent + mSystemLayer->ScheduleWork(CloseCASESessionTask, this); +} + void OperationalDeviceProxy::OnSessionReleased(SessionHandle session) { VerifyOrReturn(mSecureSession.HasValue() && mSecureSession.Value() == session, diff --git a/src/app/OperationalDeviceProxy.h b/src/app/OperationalDeviceProxy.h index 5e60c30e9aec32..3ff7c4967e83eb 100644 --- a/src/app/OperationalDeviceProxy.h +++ b/src/app/OperationalDeviceProxy.h @@ -26,6 +26,8 @@ #pragma once +#include +#include #include #include #include @@ -35,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -50,6 +53,7 @@ struct DeviceProxyInitParams Messaging::ExchangeManager * exchangeMgr = nullptr; SessionIDAllocator * idAllocator = nullptr; FabricInfo * fabricInfo = nullptr; + CASEClientPoolDelegate * clientPool = nullptr; Controller::DeviceControllerInteractionModelDelegate * imDelegate = nullptr; @@ -59,6 +63,7 @@ struct DeviceProxyInitParams ReturnErrorCodeIf(exchangeMgr == nullptr, CHIP_ERROR_INCORRECT_STATE); ReturnErrorCodeIf(idAllocator == nullptr, CHIP_ERROR_INCORRECT_STATE); ReturnErrorCodeIf(fabricInfo == nullptr, CHIP_ERROR_INCORRECT_STATE); + ReturnErrorCodeIf(clientPool == nullptr, CHIP_ERROR_INCORRECT_STATE); return CHIP_NO_ERROR; } @@ -77,8 +82,9 @@ class DLL_EXPORT OperationalDeviceProxy : public DeviceProxy, SessionReleaseDele { VerifyOrReturn(params.Validate() == CHIP_NO_ERROR); - mInitParams = params; - mPeerId = peerId; + mSystemLayer = params.exchangeMgr->GetSessionManager()->SystemLayer(); + mInitParams = params; + mPeerId = peerId; mState = State::NeedsAddress; } @@ -150,12 +156,6 @@ class DLL_EXPORT OperationalDeviceProxy : public DeviceProxy, SessionReleaseDele CHIP_ERROR ShutdownSubscriptions() override; - //////////// SessionEstablishmentDelegate Implementation /////////////// - void OnSessionEstablishmentError(CHIP_ERROR error) override; - void OnSessionEstablished() override; - - CASESession & GetCASESession() { return mCASESession; } - Controller::DeviceControllerInteractionModelDelegate * GetInteractionModelDelegate() override { return mInitParams.imDelegate; } Messaging::ExchangeManager * GetExchangeManager() const override { return mInitParams.exchangeMgr; } @@ -194,8 +194,9 @@ class DLL_EXPORT OperationalDeviceProxy : public DeviceProxy, SessionReleaseDele }; DeviceProxyInitParams mInitParams; + System::Layer * mSystemLayer; - CASESession mCASESession; + CASEClient * mCASEClient = nullptr; PeerId mPeerId; @@ -214,6 +215,13 @@ class DLL_EXPORT OperationalDeviceProxy : public DeviceProxy, SessionReleaseDele bool IsSecureConnected() const override { return mState == State::SecureConnected; } + static void HandleCASEConnected(void * context, CASEClient * client); + static void HandleCASEConnectionFailure(void * context, CASEClient * client, CHIP_ERROR error); + + static void CloseCASESessionTask(System::Layer * layer, void * context); + + void DeferCloseCASESession(); + void EnqueueConnectionCallbacks(Callback::Callback * onConnection, Callback::Callback * onFailure); diff --git a/src/app/OperationalDeviceProxyPool.h b/src/app/OperationalDeviceProxyPool.h new file mode 100644 index 00000000000000..ee920c3544efff --- /dev/null +++ b/src/app/OperationalDeviceProxyPool.h @@ -0,0 +1,94 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * + * 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. + */ + +#pragma once + +#include +#include +#include + +namespace chip { + +class OperationalDeviceProxyPoolDelegate +{ +public: + virtual OperationalDeviceProxy * Allocate(DeviceProxyInitParams & params, PeerId peerId) = 0; + + virtual OperationalDeviceProxy * Allocate(DeviceProxyInitParams & params, PeerId peerId, + const Dnssd::ResolvedNodeData & nodeResolutionData) = 0; + + virtual void Release(OperationalDeviceProxy * device) = 0; + + virtual OperationalDeviceProxy * FindDevice(SessionHandle session) = 0; + + virtual OperationalDeviceProxy * FindDevice(NodeId id) = 0; + + virtual ~OperationalDeviceProxyPoolDelegate() {} +}; + +template +class OperationalDeviceProxyPool : public OperationalDeviceProxyPoolDelegate +{ +public: + OperationalDeviceProxy * Allocate(DeviceProxyInitParams & params, PeerId peerId) override + { + return mDevicePool.CreateObject(params, peerId); + } + + OperationalDeviceProxy * Allocate(DeviceProxyInitParams & params, PeerId peerId, + const Dnssd::ResolvedNodeData & nodeResolutionData) override + { + return mDevicePool.CreateObject(params, peerId, nodeResolutionData); + } + + void Release(OperationalDeviceProxy * device) override { mDevicePool.ReleaseObject(device); } + + OperationalDeviceProxy * FindDevice(SessionHandle session) override + { + OperationalDeviceProxy * foundDevice = nullptr; + mDevicePool.ForEachActiveObject([&](auto * activeDevice) { + if (activeDevice->MatchesSession(session)) + { + foundDevice = activeDevice; + return Loop::Break; + } + return Loop::Continue; + }); + + return foundDevice; + } + + OperationalDeviceProxy * FindDevice(NodeId id) override + { + OperationalDeviceProxy * foundDevice = nullptr; + mDevicePool.ForEachActiveObject([&](auto * activeDevice) { + if (activeDevice->GetDeviceId() == id) + { + foundDevice = activeDevice; + return Loop::Break; + } + return Loop::Continue; + }); + + return foundDevice; + } + +private: + BitMapObjectPool mDevicePool; +}; + +}; // namespace chip diff --git a/src/controller/CHIPDeviceController.cpp b/src/controller/CHIPDeviceController.cpp index 365dd0472c0008..8944c8484fad1c 100644 --- a/src/controller/CHIPDeviceController.cpp +++ b/src/controller/CHIPDeviceController.cpp @@ -151,12 +151,14 @@ CHIP_ERROR DeviceController::Init(ControllerInitParams params) .exchangeMgr = params.systemState->ExchangeMgr(), .idAllocator = &mIDAllocator, .fabricInfo = params.systemState->Fabrics()->FindFabricWithIndex(mFabricIndex), + .clientPool = &mCASEClientPool, .imDelegate = params.systemState->IMDelegate(), }; CASESessionManagerConfig sessionManagerConfig = { .sessionInitParams = deviceInitParams, .dnsCache = &mDNSCache, + .devicePool = &mDevicePool, }; mCASESessionManager = chip::Platform::New(sessionManagerConfig); diff --git a/src/controller/CHIPDeviceController.h b/src/controller/CHIPDeviceController.h index fa13ea82c6c22f..17597334dfabd0 100644 --- a/src/controller/CHIPDeviceController.h +++ b/src/controller/CHIPDeviceController.h @@ -28,10 +28,12 @@ #pragma once +#include #include #include #include #include +#include #include #include #include @@ -352,6 +354,8 @@ class DLL_EXPORT DeviceController : public SessionReleaseDelegate, CASESessionManager * mCASESessionManager = nullptr; Dnssd::DnssdCache mDNSCache; + CASEClientPool mCASEClientPool; + OperationalDeviceProxyPool mDevicePool; SerializableU64Set mPairedDevices; bool mPairedDevicesInitialized; diff --git a/src/lib/core/CHIPConfig.h b/src/lib/core/CHIPConfig.h index e0696be2be640b..990ec285ee397f 100644 --- a/src/lib/core/CHIPConfig.h +++ b/src/lib/core/CHIPConfig.h @@ -2561,6 +2561,15 @@ extern const char CHIP_NON_PRODUCTION_MARKER[]; #define CHIP_CONFIG_CONTROLLER_MAX_ACTIVE_DEVICES 64 #endif +/** + * @def CHIP_CONFIG_CONTROLLER_MAX_ACTIVE_CASE_CLIENTS + * + * @brief Number of outgoing CASE sessions can be simutaneously negotiated. + */ +#ifndef CHIP_CONFIG_CONTROLLER_MAX_ACTIVE_CASE_CLIENTS +#define CHIP_CONFIG_CONTROLLER_MAX_ACTIVE_CASE_CLIENTS 16 +#endif + /** * @def CHIP_CONFIG_MAX_GROUPS_PER_FABRIC *