Skip to content

Commit eb84a9d

Browse files
authored
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
1 parent 1aecc69 commit eb84a9d

7 files changed

+391
-178
lines changed

src/app/BUILD.gn

+2
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ static_library("app") {
3939
"AttributePathExpandIterator.h",
4040
"AttributePathParams.cpp",
4141
"AttributePathParams.h",
42+
"CASESessionManager.cpp",
43+
"CASESessionManager.h",
4244
"Command.cpp",
4345
"Command.h",
4446
"CommandHandler.cpp",

src/app/CASESessionManager.cpp

+166
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
/*
2+
*
3+
* Copyright (c) 2020-2021 Project CHIP Authors
4+
* All rights reserved.
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
#include <app/CASESessionManager.h>
20+
21+
namespace chip {
22+
23+
CHIP_ERROR CASESessionManager::FindOrEstablishSession(NodeId nodeId, Callback::Callback<OnDeviceConnected> * onConnection,
24+
Callback::Callback<OnDeviceConnectionFailure> * onFailure)
25+
{
26+
Dnssd::ResolvedNodeData resolutionData;
27+
28+
PeerId peerId = GetFabricInfo()->GetPeerIdForNode(nodeId);
29+
30+
bool nodeIDWasResolved = (mConfig.dnsCache != nullptr && mConfig.dnsCache->Lookup(peerId, resolutionData) == CHIP_NO_ERROR);
31+
32+
OperationalDeviceProxy * session = FindExistingSession(nodeId);
33+
if (session == nullptr)
34+
{
35+
// TODO - Implement LRU to evict least recently used session to handle mActiveSessions pool exhaustion
36+
if (nodeIDWasResolved)
37+
{
38+
session = mActiveSessions.CreateObject(mConfig.sessionInitParams, peerId, resolutionData);
39+
}
40+
else
41+
{
42+
session = mActiveSessions.CreateObject(mConfig.sessionInitParams, peerId);
43+
}
44+
45+
if (session == nullptr)
46+
{
47+
onFailure->mCall(onFailure->mContext, nodeId, CHIP_ERROR_NO_MEMORY);
48+
return CHIP_ERROR_NO_MEMORY;
49+
}
50+
}
51+
else if (nodeIDWasResolved)
52+
{
53+
session->OnNodeIdResolved(resolutionData);
54+
}
55+
56+
CHIP_ERROR err = session->Connect(onConnection, onFailure);
57+
if (err != CHIP_NO_ERROR)
58+
{
59+
ReleaseSession(session);
60+
}
61+
62+
return err;
63+
}
64+
65+
void CASESessionManager::ReleaseSession(NodeId nodeId)
66+
{
67+
ReleaseSession(FindExistingSession(nodeId));
68+
}
69+
70+
CHIP_ERROR CASESessionManager::ResolveDeviceAddress(NodeId nodeId)
71+
{
72+
return Dnssd::Resolver::Instance().ResolveNodeId(GetFabricInfo()->GetPeerIdForNode(nodeId), Inet::IPAddressType::kAny);
73+
}
74+
75+
void CASESessionManager::OnNodeIdResolved(const Dnssd::ResolvedNodeData & nodeData)
76+
{
77+
ChipLogProgress(Controller, "Address resolved for node: 0x" ChipLogFormatX64, ChipLogValueX64(nodeData.mPeerId.GetNodeId()));
78+
79+
if (mConfig.dnsCache != nullptr)
80+
{
81+
LogErrorOnFailure(mConfig.dnsCache->Insert(nodeData));
82+
}
83+
84+
OperationalDeviceProxy * session = FindExistingSession(nodeData.mPeerId.GetNodeId());
85+
VerifyOrReturn(session != nullptr,
86+
ChipLogDetail(Controller, "OnNodeIdResolved was called for a device with no active sessions, ignoring it."));
87+
88+
LogErrorOnFailure(session->UpdateDeviceData(
89+
session->ToPeerAddress(nodeData), nodeData.GetMrpRetryIntervalIdle().ValueOr(CHIP_CONFIG_MRP_DEFAULT_IDLE_RETRY_INTERVAL),
90+
nodeData.GetMrpRetryIntervalActive().ValueOr(CHIP_CONFIG_MRP_DEFAULT_ACTIVE_RETRY_INTERVAL)));
91+
}
92+
93+
void CASESessionManager::OnNodeIdResolutionFailed(const PeerId & peer, CHIP_ERROR error)
94+
{
95+
ChipLogError(Controller, "Error resolving node id: %s", ErrorStr(error));
96+
}
97+
98+
CHIP_ERROR CASESessionManager::GetPeerAddress(NodeId nodeId, Transport::PeerAddress & addr)
99+
{
100+
if (mConfig.dnsCache != nullptr)
101+
{
102+
Dnssd::ResolvedNodeData resolutionData;
103+
ReturnErrorOnFailure(mConfig.dnsCache->Lookup(GetFabricInfo()->GetPeerIdForNode(nodeId), resolutionData));
104+
addr = OperationalDeviceProxy::ToPeerAddress(resolutionData);
105+
return CHIP_NO_ERROR;
106+
}
107+
108+
OperationalDeviceProxy * session = FindExistingSession(nodeId);
109+
VerifyOrReturnError(session != nullptr, CHIP_ERROR_NOT_CONNECTED);
110+
addr = session->GetPeerAddress();
111+
return CHIP_NO_ERROR;
112+
}
113+
114+
void CASESessionManager::OnNewConnection(SessionHandle sessionHandle, Messaging::ExchangeManager * mgr)
115+
{
116+
// TODO Update the MRP params based on the MRP params extracted from CASE, when this is available.
117+
}
118+
119+
void CASESessionManager::OnConnectionExpired(SessionHandle sessionHandle, Messaging::ExchangeManager * mgr)
120+
{
121+
OperationalDeviceProxy * session = FindSession(sessionHandle);
122+
VerifyOrReturn(session != nullptr,
123+
ChipLogDetail(Controller, "OnConnectionExpired was called for unknown device, ignoring it."));
124+
125+
session->OnConnectionExpired(sessionHandle);
126+
}
127+
128+
OperationalDeviceProxy * CASESessionManager::FindSession(SessionHandle session)
129+
{
130+
OperationalDeviceProxy * foundSession = nullptr;
131+
mActiveSessions.ForEachActiveObject([&](auto * activeSession) {
132+
if (activeSession->MatchesSession(session))
133+
{
134+
foundSession = activeSession;
135+
return false;
136+
}
137+
return true;
138+
});
139+
140+
return foundSession;
141+
}
142+
143+
OperationalDeviceProxy * CASESessionManager::FindExistingSession(NodeId id)
144+
{
145+
OperationalDeviceProxy * foundSession = nullptr;
146+
mActiveSessions.ForEachActiveObject([&](auto * activeSession) {
147+
if (activeSession->GetDeviceId() == id)
148+
{
149+
foundSession = activeSession;
150+
return false;
151+
}
152+
return true;
153+
});
154+
155+
return foundSession;
156+
}
157+
158+
void CASESessionManager::ReleaseSession(OperationalDeviceProxy * session)
159+
{
160+
if (session != nullptr)
161+
{
162+
mActiveSessions.ReleaseObject(session);
163+
}
164+
}
165+
166+
} // namespace chip

src/app/CASESessionManager.h

+112
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
/*
2+
*
3+
* Copyright (c) 2020-2021 Project CHIP Authors
4+
* All rights reserved.
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
#pragma once
20+
21+
#include <app/OperationalDeviceProxy.h>
22+
#include <lib/core/CHIPConfig.h>
23+
#include <lib/core/CHIPCore.h>
24+
#include <lib/dnssd/DnssdCache.h>
25+
#include <lib/support/Pool.h>
26+
#include <messaging/ExchangeMgrDelegate.h>
27+
28+
#include <lib/dnssd/Resolver.h>
29+
30+
namespace chip {
31+
32+
struct CASESessionManagerConfig
33+
{
34+
DeviceProxyInitParams sessionInitParams;
35+
Dnssd::DnssdCache<CHIP_CONFIG_MDNS_CACHE_SIZE> * dnsCache = nullptr;
36+
};
37+
38+
/**
39+
* This class provides the following
40+
* 1. Manage a pool of operational device proxy objects for peer nodes that have active message exchange with the local node.
41+
* 2. The pool contains atmost one device proxy object for a given peer node.
42+
* 3. API to lookup an existing proxy object, or allocate a new one by triggering session establishment with the peer node.
43+
* 4. During session establishment, trigger node ID resolution (if needed), and update the DNS-SD cache (if resolution is
44+
* successful)
45+
*/
46+
class CASESessionManager : public Messaging::ExchangeMgrDelegate, public Dnssd::ResolverDelegate
47+
{
48+
public:
49+
CASESessionManager() = delete;
50+
51+
CASESessionManager(CASESessionManagerConfig & params)
52+
{
53+
VerifyOrReturn(params.sessionInitParams.Validate() == CHIP_NO_ERROR);
54+
55+
mConfig = params;
56+
}
57+
58+
virtual ~CASESessionManager() {}
59+
60+
/**
61+
* Find an existing session for the given node ID, or trigger a new session request.
62+
* The caller can optionally provide `onConnection` and `onFailure` callback objects. If provided,
63+
* these will be used to inform the caller about successful or failed connection establishment.
64+
* If the connection is already established, the `onConnection` callback will be immediately called.
65+
*/
66+
CHIP_ERROR FindOrEstablishSession(NodeId nodeId, Callback::Callback<OnDeviceConnected> * onConnection,
67+
Callback::Callback<OnDeviceConnectionFailure> * onFailure);
68+
69+
OperationalDeviceProxy * FindExistingSession(NodeId nodeId);
70+
71+
void ReleaseSession(NodeId nodeId);
72+
73+
FabricInfo * GetFabricInfo() { return mConfig.sessionInitParams.fabricInfo; }
74+
75+
/**
76+
* This API triggers the DNS-SD resolution for the given node ID. The node ID will be looked up
77+
* on the fabric that was configured for the CASESessionManager object.
78+
*
79+
* The results of the DNS-SD resolution request is provided to the class via `ResolverDelegate`
80+
* implementation of CASESessionManager.
81+
*/
82+
CHIP_ERROR ResolveDeviceAddress(NodeId nodeId);
83+
84+
/**
85+
* This API returns the address for the given node ID.
86+
* If the CASESessionManager is configured with a DNS-SD cache, the cache is looked up
87+
* for the node ID.
88+
* If the DNS-SD cache is not available, the CASESessionManager looks up the list for
89+
* an ongoing session with the peer node. If the session doesn't exist, the API will return
90+
* `CHIP_ERROR_NOT_CONNECTED` error.
91+
*/
92+
CHIP_ERROR GetPeerAddress(NodeId nodeId, Transport::PeerAddress & addr);
93+
94+
//////////// ExchangeMgrDelegate Implementation ///////////////
95+
void OnNewConnection(SessionHandle session, Messaging::ExchangeManager * mgr) override;
96+
void OnConnectionExpired(SessionHandle session, Messaging::ExchangeManager * mgr) override;
97+
98+
//////////// ResolverDelegate Implementation ///////////////
99+
void OnNodeIdResolved(const Dnssd::ResolvedNodeData & nodeData) override;
100+
void OnNodeIdResolutionFailed(const PeerId & peerId, CHIP_ERROR error) override;
101+
void OnNodeDiscoveryComplete(const Dnssd::DiscoveredNodeData & nodeData) override {}
102+
103+
private:
104+
OperationalDeviceProxy * FindSession(SessionHandle session);
105+
void ReleaseSession(OperationalDeviceProxy * device);
106+
107+
BitMapObjectPool<OperationalDeviceProxy, CHIP_CONFIG_CONTROLLER_MAX_ACTIVE_DEVICES> mActiveSessions;
108+
109+
CASESessionManagerConfig mConfig;
110+
};
111+
112+
} // namespace chip

src/app/OperationalDeviceProxy.cpp

+4-3
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,11 @@
2424
* messages to and from the corresponding CHIP devices.
2525
*/
2626

27-
#include <app/OperationalDeviceProxy.h>
27+
#include "OperationalDeviceProxy.h"
28+
29+
#include "CommandSender.h"
30+
#include "ReadPrepareParams.h"
2831

29-
#include <app/CommandSender.h>
30-
#include <app/ReadPrepareParams.h>
3132
#include <lib/core/CHIPCore.h>
3233
#include <lib/core/CHIPEncoding.h>
3334
#include <lib/dnssd/Resolver.h>

0 commit comments

Comments
 (0)