Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement CASESessionManager class #11703

Merged
merged 7 commits into from
Nov 16, 2021
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/app/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ static_library("app") {
"AttributePathExpandIterator.h",
"AttributePathParams.cpp",
"AttributePathParams.h",
"CASESessionManager.cpp",
"CASESessionManager.h",
"Command.cpp",
"Command.h",
"CommandHandler.cpp",
Expand Down
166 changes: 166 additions & 0 deletions src/app/CASESessionManager.cpp
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>
pan-apple marked this conversation as resolved.
Show resolved Hide resolved

namespace chip {

CHIP_ERROR CASESessionManager::FindOrEstablishSession(NodeId nodeId, Callback::Callback<OnDeviceConnected> * onConnection,
Callback::Callback<OnDeviceConnectionFailure> * onFailure)
{
VerifyOrReturnError(mInitialized, CHIP_ERROR_INCORRECT_STATE);

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);
pan-apple marked this conversation as resolved.
Show resolved Hide resolved
if (err != CHIP_NO_ERROR)
{
ReleaseSession(session);
}

return err;
}

void CASESessionManager::ReleaseSession(NodeId nodeId)
{
ReleaseSession(FindExistingSession(nodeId));
}

CHIP_ERROR CASESessionManager::ResolveDeviceAddress(NodeId nodeId)
{
VerifyOrReturnError(mInitialized, CHIP_ERROR_INCORRECT_STATE);
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()));
VerifyOrReturn(mInitialized, ChipLogError(Controller, "OnNodeIdResolved was called in uninitialized state"));

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::GetDeviceAddressAndPort(NodeId nodeId, Inet::IPAddress & addr, uint16_t & port)
{
VerifyOrReturnError(mInitialized, CHIP_ERROR_INCORRECT_STATE);

OperationalDeviceProxy * session = FindExistingSession(nodeId);
VerifyOrReturnError(session != nullptr, CHIP_ERROR_NOT_CONNECTED);
VerifyOrReturnError(session->GetAddress(addr, port), CHIP_ERROR_NOT_CONNECTED);
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)
{
VerifyOrReturn(mInitialized, ChipLogError(Controller, "OnConnectionExpired was called in uninitialized state"));

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
120 changes: 120 additions & 0 deletions src/app/CASESessionManager.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
/*
*
* 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(CASESessionManagerConfig & params)
{
VerifyOrReturn(params.sessionInitParams.Validate() == CHIP_NO_ERROR);

mConfig = params;
mInitialized = true;
pan-apple marked this conversation as resolved.
Show resolved Hide resolved
}

virtual ~CASESessionManager() {}

void Shutdown() { mInitialized = false; }
pan-apple marked this conversation as resolved.
Show resolved Hide resolved

/**
* Find an existing session for the given node ID, or trigger a new session request.
pan-apple marked this conversation as resolved.
Show resolved Hide resolved
* 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()
{
if (!mInitialized)
{
return nullptr;
}

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);
pan-apple marked this conversation as resolved.
Show resolved Hide resolved

/**
* This API returns the address and port for the given node ID. It is expected that there is
* an ongoing session with the peer node. If the session doesn't exist, the API will return
* `CHIP_ERROR_NOT_CONNECTED` error.
*/
CHIP_ERROR GetDeviceAddressAndPort(NodeId nodeId, Inet::IPAddress & addr, uint16_t & port);
pan-apple marked this conversation as resolved.
Show resolved Hide resolved

//////////// 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;

bool mInitialized = false;
};

} // namespace chip
7 changes: 4 additions & 3 deletions src/app/OperationalDeviceProxy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,11 @@
* messages to and from the corresponding CHIP devices.
*/

#include <app/OperationalDeviceProxy.h>
#include "OperationalDeviceProxy.h"

#include "CommandSender.h"
#include "ReadPrepareParams.h"

#include <app/CommandSender.h>
#include <app/ReadPrepareParams.h>
#include <lib/core/CHIPCore.h>
#include <lib/core/CHIPEncoding.h>
#include <lib/dnssd/Resolver.h>
Expand Down
Loading