-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement CASESessionManager class (#11703)
* Implement CASESessionManager class - This class enables device to device communication - It extracts out relevant code from DeviceController class to a minimal implementation. The controller class is refactored to use this class internally. * fix build errors * address review comments * fix apps * cleanup * address review comments * address review comments
- Loading branch information
Showing
7 changed files
with
391 additions
and
178 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
/* | ||
* | ||
* Copyright (c) 2020-2021 Project CHIP Authors | ||
* All rights reserved. | ||
* | ||
* 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 <app/CASESessionManager.h> | ||
|
||
namespace chip { | ||
|
||
CHIP_ERROR CASESessionManager::FindOrEstablishSession(NodeId nodeId, Callback::Callback<OnDeviceConnected> * onConnection, | ||
Callback::Callback<OnDeviceConnectionFailure> * onFailure) | ||
{ | ||
Dnssd::ResolvedNodeData resolutionData; | ||
|
||
PeerId peerId = GetFabricInfo()->GetPeerIdForNode(nodeId); | ||
|
||
bool nodeIDWasResolved = (mConfig.dnsCache != nullptr && mConfig.dnsCache->Lookup(peerId, resolutionData) == CHIP_NO_ERROR); | ||
|
||
OperationalDeviceProxy * session = FindExistingSession(nodeId); | ||
if (session == nullptr) | ||
{ | ||
// TODO - Implement LRU to evict least recently used session to handle mActiveSessions pool exhaustion | ||
if (nodeIDWasResolved) | ||
{ | ||
session = mActiveSessions.CreateObject(mConfig.sessionInitParams, peerId, resolutionData); | ||
} | ||
else | ||
{ | ||
session = mActiveSessions.CreateObject(mConfig.sessionInitParams, peerId); | ||
} | ||
|
||
if (session == nullptr) | ||
{ | ||
onFailure->mCall(onFailure->mContext, nodeId, CHIP_ERROR_NO_MEMORY); | ||
return CHIP_ERROR_NO_MEMORY; | ||
} | ||
} | ||
else if (nodeIDWasResolved) | ||
{ | ||
session->OnNodeIdResolved(resolutionData); | ||
} | ||
|
||
CHIP_ERROR err = session->Connect(onConnection, onFailure); | ||
if (err != CHIP_NO_ERROR) | ||
{ | ||
ReleaseSession(session); | ||
} | ||
|
||
return err; | ||
} | ||
|
||
void CASESessionManager::ReleaseSession(NodeId nodeId) | ||
{ | ||
ReleaseSession(FindExistingSession(nodeId)); | ||
} | ||
|
||
CHIP_ERROR CASESessionManager::ResolveDeviceAddress(NodeId nodeId) | ||
{ | ||
return Dnssd::Resolver::Instance().ResolveNodeId(GetFabricInfo()->GetPeerIdForNode(nodeId), Inet::IPAddressType::kAny); | ||
} | ||
|
||
void CASESessionManager::OnNodeIdResolved(const Dnssd::ResolvedNodeData & nodeData) | ||
{ | ||
ChipLogProgress(Controller, "Address resolved for node: 0x" ChipLogFormatX64, ChipLogValueX64(nodeData.mPeerId.GetNodeId())); | ||
|
||
if (mConfig.dnsCache != nullptr) | ||
{ | ||
LogErrorOnFailure(mConfig.dnsCache->Insert(nodeData)); | ||
} | ||
|
||
OperationalDeviceProxy * session = FindExistingSession(nodeData.mPeerId.GetNodeId()); | ||
VerifyOrReturn(session != nullptr, | ||
ChipLogDetail(Controller, "OnNodeIdResolved was called for a device with no active sessions, ignoring it.")); | ||
|
||
LogErrorOnFailure(session->UpdateDeviceData( | ||
session->ToPeerAddress(nodeData), nodeData.GetMrpRetryIntervalIdle().ValueOr(CHIP_CONFIG_MRP_DEFAULT_IDLE_RETRY_INTERVAL), | ||
nodeData.GetMrpRetryIntervalActive().ValueOr(CHIP_CONFIG_MRP_DEFAULT_ACTIVE_RETRY_INTERVAL))); | ||
} | ||
|
||
void CASESessionManager::OnNodeIdResolutionFailed(const PeerId & peer, CHIP_ERROR error) | ||
{ | ||
ChipLogError(Controller, "Error resolving node id: %s", ErrorStr(error)); | ||
} | ||
|
||
CHIP_ERROR CASESessionManager::GetPeerAddress(NodeId nodeId, Transport::PeerAddress & addr) | ||
{ | ||
if (mConfig.dnsCache != nullptr) | ||
{ | ||
Dnssd::ResolvedNodeData resolutionData; | ||
ReturnErrorOnFailure(mConfig.dnsCache->Lookup(GetFabricInfo()->GetPeerIdForNode(nodeId), resolutionData)); | ||
addr = OperationalDeviceProxy::ToPeerAddress(resolutionData); | ||
return CHIP_NO_ERROR; | ||
} | ||
|
||
OperationalDeviceProxy * session = FindExistingSession(nodeId); | ||
VerifyOrReturnError(session != nullptr, CHIP_ERROR_NOT_CONNECTED); | ||
addr = session->GetPeerAddress(); | ||
return CHIP_NO_ERROR; | ||
} | ||
|
||
void CASESessionManager::OnNewConnection(SessionHandle sessionHandle, Messaging::ExchangeManager * mgr) | ||
{ | ||
// TODO Update the MRP params based on the MRP params extracted from CASE, when this is available. | ||
} | ||
|
||
void CASESessionManager::OnConnectionExpired(SessionHandle sessionHandle, Messaging::ExchangeManager * mgr) | ||
{ | ||
OperationalDeviceProxy * session = FindSession(sessionHandle); | ||
VerifyOrReturn(session != nullptr, | ||
ChipLogDetail(Controller, "OnConnectionExpired was called for unknown device, ignoring it.")); | ||
|
||
session->OnConnectionExpired(sessionHandle); | ||
} | ||
|
||
OperationalDeviceProxy * CASESessionManager::FindSession(SessionHandle session) | ||
{ | ||
OperationalDeviceProxy * foundSession = nullptr; | ||
mActiveSessions.ForEachActiveObject([&](auto * activeSession) { | ||
if (activeSession->MatchesSession(session)) | ||
{ | ||
foundSession = activeSession; | ||
return false; | ||
} | ||
return true; | ||
}); | ||
|
||
return foundSession; | ||
} | ||
|
||
OperationalDeviceProxy * CASESessionManager::FindExistingSession(NodeId id) | ||
{ | ||
OperationalDeviceProxy * foundSession = nullptr; | ||
mActiveSessions.ForEachActiveObject([&](auto * activeSession) { | ||
if (activeSession->GetDeviceId() == id) | ||
{ | ||
foundSession = activeSession; | ||
return false; | ||
} | ||
return true; | ||
}); | ||
|
||
return foundSession; | ||
} | ||
|
||
void CASESessionManager::ReleaseSession(OperationalDeviceProxy * session) | ||
{ | ||
if (session != nullptr) | ||
{ | ||
mActiveSessions.ReleaseObject(session); | ||
} | ||
} | ||
|
||
} // namespace chip |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
/* | ||
* | ||
* Copyright (c) 2020-2021 Project CHIP Authors | ||
* All rights reserved. | ||
* | ||
* 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 <app/OperationalDeviceProxy.h> | ||
#include <lib/core/CHIPConfig.h> | ||
#include <lib/core/CHIPCore.h> | ||
#include <lib/dnssd/DnssdCache.h> | ||
#include <lib/support/Pool.h> | ||
#include <messaging/ExchangeMgrDelegate.h> | ||
|
||
#include <lib/dnssd/Resolver.h> | ||
|
||
namespace chip { | ||
|
||
struct CASESessionManagerConfig | ||
{ | ||
DeviceProxyInitParams sessionInitParams; | ||
Dnssd::DnssdCache<CHIP_CONFIG_MDNS_CACHE_SIZE> * dnsCache = nullptr; | ||
}; | ||
|
||
/** | ||
* This class provides the following | ||
* 1. Manage a pool of operational device proxy objects for peer nodes that have active message exchange with the local node. | ||
* 2. The pool contains atmost one device proxy object for a given peer node. | ||
* 3. API to lookup an existing proxy object, or allocate a new one by triggering session establishment with the peer node. | ||
* 4. During session establishment, trigger node ID resolution (if needed), and update the DNS-SD cache (if resolution is | ||
* successful) | ||
*/ | ||
class CASESessionManager : public Messaging::ExchangeMgrDelegate, public Dnssd::ResolverDelegate | ||
{ | ||
public: | ||
CASESessionManager() = delete; | ||
|
||
CASESessionManager(CASESessionManagerConfig & params) | ||
{ | ||
VerifyOrReturn(params.sessionInitParams.Validate() == CHIP_NO_ERROR); | ||
|
||
mConfig = params; | ||
} | ||
|
||
virtual ~CASESessionManager() {} | ||
|
||
/** | ||
* Find an existing session for the given node ID, or trigger a new session request. | ||
* The caller can optionally provide `onConnection` and `onFailure` callback objects. If provided, | ||
* these will be used to inform the caller about successful or failed connection establishment. | ||
* If the connection is already established, the `onConnection` callback will be immediately called. | ||
*/ | ||
CHIP_ERROR FindOrEstablishSession(NodeId nodeId, Callback::Callback<OnDeviceConnected> * onConnection, | ||
Callback::Callback<OnDeviceConnectionFailure> * onFailure); | ||
|
||
OperationalDeviceProxy * FindExistingSession(NodeId nodeId); | ||
|
||
void ReleaseSession(NodeId nodeId); | ||
|
||
FabricInfo * GetFabricInfo() { return mConfig.sessionInitParams.fabricInfo; } | ||
|
||
/** | ||
* This API triggers the DNS-SD resolution for the given node ID. The node ID will be looked up | ||
* on the fabric that was configured for the CASESessionManager object. | ||
* | ||
* The results of the DNS-SD resolution request is provided to the class via `ResolverDelegate` | ||
* implementation of CASESessionManager. | ||
*/ | ||
CHIP_ERROR ResolveDeviceAddress(NodeId nodeId); | ||
|
||
/** | ||
* This API returns the address for the given node ID. | ||
* If the CASESessionManager is configured with a DNS-SD cache, the cache is looked up | ||
* for the node ID. | ||
* If the DNS-SD cache is not available, the CASESessionManager looks up the list for | ||
* an ongoing session with the peer node. If the session doesn't exist, the API will return | ||
* `CHIP_ERROR_NOT_CONNECTED` error. | ||
*/ | ||
CHIP_ERROR GetPeerAddress(NodeId nodeId, Transport::PeerAddress & addr); | ||
|
||
//////////// ExchangeMgrDelegate Implementation /////////////// | ||
void OnNewConnection(SessionHandle session, Messaging::ExchangeManager * mgr) override; | ||
void OnConnectionExpired(SessionHandle session, Messaging::ExchangeManager * mgr) override; | ||
|
||
//////////// ResolverDelegate Implementation /////////////// | ||
void OnNodeIdResolved(const Dnssd::ResolvedNodeData & nodeData) override; | ||
void OnNodeIdResolutionFailed(const PeerId & peerId, CHIP_ERROR error) override; | ||
void OnNodeDiscoveryComplete(const Dnssd::DiscoveredNodeData & nodeData) override {} | ||
|
||
private: | ||
OperationalDeviceProxy * FindSession(SessionHandle session); | ||
void ReleaseSession(OperationalDeviceProxy * device); | ||
|
||
BitMapObjectPool<OperationalDeviceProxy, CHIP_CONFIG_CONTROLLER_MAX_ACTIVE_DEVICES> mActiveSessions; | ||
|
||
CASESessionManagerConfig mConfig; | ||
}; | ||
|
||
} // namespace chip |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.