Skip to content

Commit

Permalink
Merge branch 'master' into feature/update_docker_image
Browse files Browse the repository at this point in the history
  • Loading branch information
andy31415 authored Aug 15, 2024
2 parents 2ed0676 + 9d8587d commit 837e872
Show file tree
Hide file tree
Showing 20 changed files with 456 additions and 38 deletions.
4 changes: 4 additions & 0 deletions examples/fabric-admin/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,12 @@ static_library("fabric-admin-utils") {
"commands/common/Commands.h",
"commands/common/CredentialIssuerCommands.h",
"commands/common/HexConversion.h",
"commands/common/IcdManager.cpp",
"commands/common/IcdManager.h",
"commands/common/RemoteDataModelLogger.cpp",
"commands/common/RemoteDataModelLogger.h",
"commands/common/StayActiveSender.cpp",
"commands/common/StayActiveSender.h",
"commands/fabric-sync/FabricSyncCommand.cpp",
"commands/pairing/DeviceSynchronization.cpp",
"commands/pairing/DeviceSynchronization.h",
Expand Down
6 changes: 3 additions & 3 deletions examples/fabric-admin/commands/common/CHIPCommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

#include "CHIPCommand.h"

#include "IcdManager.h"
#include <controller/CHIPDeviceControllerFactory.h>
#include <credentials/attestation_verifier/FileAttestationTrustStore.h>
#include <lib/core/CHIPConfig.h>
Expand Down Expand Up @@ -52,7 +53,6 @@ chip::Credentials::GroupDataProviderImpl CHIPCommand::sGroupDataProvider{ kMaxGr
// All fabrics share the same ICD client storage.
chip::app::DefaultICDClientStorage CHIPCommand::sICDClientStorage;
chip::Crypto::RawKeySessionKeystore CHIPCommand::sSessionKeystore;
chip::app::DefaultCheckInDelegate CHIPCommand::sCheckInDelegate;
chip::app::CheckInHandler CHIPCommand::sCheckInHandler;

namespace {
Expand Down Expand Up @@ -148,9 +148,9 @@ CHIP_ERROR CHIPCommand::MaybeSetUpStack()

auto engine = chip::app::InteractionModelEngine::GetInstance();
VerifyOrReturnError(engine != nullptr, CHIP_ERROR_INCORRECT_STATE);
ReturnLogErrorOnFailure(sCheckInDelegate.Init(&sICDClientStorage, engine));
ReturnLogErrorOnFailure(IcdManager::Instance().Init(&sICDClientStorage, engine));
ReturnLogErrorOnFailure(sCheckInHandler.Init(DeviceControllerFactory::GetInstance().GetSystemState()->ExchangeMgr(),
&sICDClientStorage, &sCheckInDelegate, engine));
&sICDClientStorage, &IcdManager::Instance(), engine));

CommissionerIdentity nullIdentity{ kIdentityNull, chip::kUndefinedNodeId };
ReturnLogErrorOnFailure(InitializeCommissioner(nullIdentity, kIdentityNullFabricId));
Expand Down
1 change: 0 additions & 1 deletion examples/fabric-admin/commands/common/CHIPCommand.h
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,6 @@ class CHIPCommand : public Command

static chip::Credentials::GroupDataProviderImpl sGroupDataProvider;
static chip::app::DefaultICDClientStorage sICDClientStorage;
static chip::app::DefaultCheckInDelegate sCheckInDelegate;
static chip::app::CheckInHandler sCheckInHandler;
CredentialIssuerCommands * mCredIssuerCmds;

Expand Down
47 changes: 47 additions & 0 deletions examples/fabric-admin/commands/common/IcdManager.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Copyright (c) 2024 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 "IcdManager.h"

IcdManager IcdManager::sInstance;

IcdManager & IcdManager::Instance()
{
return sInstance;
}

void IcdManager::OnCheckInComplete(const chip::app::ICDClientInfo & clientInfo)
{
DefaultCheckInDelegate::OnCheckInComplete(clientInfo);
if (mDelegate)
{
mDelegate->OnCheckInCompleted(clientInfo);
}
}

void IcdManager::SetDelegate(Delegate * delegate)
{
// To keep IcdManager simple, there is an assumption that there is only ever
// one delegate set and it's lifetime is identical to IcdManager. In the
// future this assumption can change should there be a need, but that will
// require code changes to IcdManager. For now we will crash if someone tries
// to call SetDelegate for a second time or if delegate is non-null.
VerifyOrDie(delegate);
VerifyOrDie(!mDelegate);
mDelegate = delegate;
}
51 changes: 51 additions & 0 deletions examples/fabric-admin/commands/common/IcdManager.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Copyright (c) 2024 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/icd/client/DefaultCheckInDelegate.h>

/**
* @brief Manages check-ins from ICD devices.
*
* Intended to be used as a thin CheckInDelegate. This allows a delegate register
* themselves so they can be aware when ICD device checks-in allowing the
* delegate to interact with the ICD device during the short window that it is
* awake.
*/
class IcdManager : public chip::app::DefaultCheckInDelegate
{
public:
class Delegate
{
public:
virtual ~Delegate() = default;
virtual void OnCheckInCompleted(const chip::app::ICDClientInfo & clientInfo) = 0;
};

static IcdManager & Instance();
void OnCheckInComplete(const chip::app::ICDClientInfo & clientInfo) override;

// There is an assumption delegate assigned only happens once and that it lives
// for the entirety of the lifetime of fabric admin.
void SetDelegate(Delegate * delegate);

private:
static IcdManager sInstance;
Delegate * mDelegate = nullptr;
};
99 changes: 99 additions & 0 deletions examples/fabric-admin/commands/common/StayActiveSender.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/*
* Copyright (c) 2024 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 "StayActiveSender.h"

#include <app-common/zap-generated/cluster-objects.h>
#include <app/ConcreteCommandPath.h>
#include <controller/InvokeInteraction.h>
#include <support/CHIPMem.h>

CHIP_ERROR StayActiveSender::SendStayActiveCommand(uint32_t stayActiveDurationMs, const chip::ScopedNodeId & peerNode,
chip::app::InteractionModelEngine * engine, OnDoneCallbackType onDone)
{
ConstructorOnlyInternallyCallable internal;
auto stayActiveSender = chip::Platform::New<StayActiveSender>(internal, stayActiveDurationMs, peerNode,
chip::app::InteractionModelEngine::GetInstance(), onDone);
VerifyOrReturnError(stayActiveSender != nullptr, CHIP_ERROR_NO_MEMORY);
CHIP_ERROR err = stayActiveSender->EstablishSessionToPeer();
if (CHIP_NO_ERROR != err)
{
chip::Platform::Delete(stayActiveSender);
}
return err;
}

StayActiveSender::StayActiveSender(const ConstructorOnlyInternallyCallable & _, uint32_t stayActiveDurationMs,
const chip::ScopedNodeId & peerNode, chip::app::InteractionModelEngine * engine,
OnDoneCallbackType onDone) :
mStayActiveDurationMs(stayActiveDurationMs),
mPeerNode(peerNode), mpImEngine(engine), mOnDone(onDone), mOnConnectedCallback(HandleDeviceConnected, this),
mOnConnectionFailureCallback(HandleDeviceConnectionFailure, this)
{}

CHIP_ERROR StayActiveSender::SendStayActiveCommand(chip::Messaging::ExchangeManager & exchangeMgr,
const chip::SessionHandle & sessionHandle)
{
auto onSuccess = [&](const chip::app::ConcreteCommandPath & commandPath, const chip::app::StatusIB & status,
const auto & dataResponse) {
uint32_t promisedActiveDurationMs = dataResponse.promisedActiveDuration;
ChipLogProgress(ICD, "StayActive command succeeded with promised duration %u", promisedActiveDurationMs);
mOnDone(promisedActiveDurationMs);
chip::Platform::Delete(this);
};

auto onFailure = [&](CHIP_ERROR error) {
ChipLogError(ICD, "StayActive command failed: %" CHIP_ERROR_FORMAT, error.Format());
chip::Platform::Delete(this);
};

chip::EndpointId endpointId = 0;
chip::app::Clusters::IcdManagement::Commands::StayActiveRequest::Type request;
request.stayActiveDuration = mStayActiveDurationMs;
return chip::Controller::InvokeCommandRequest(&exchangeMgr, sessionHandle, endpointId, request, onSuccess, onFailure);
}

CHIP_ERROR StayActiveSender::EstablishSessionToPeer()
{
ChipLogProgress(ICD, "Trying to establish a CASE session to extend the active period for lit icd device");
auto * caseSessionManager = mpImEngine->GetCASESessionManager();
VerifyOrReturnError(caseSessionManager != nullptr, CHIP_ERROR_INVALID_CASE_PARAMETER);
caseSessionManager->FindOrEstablishSession(mPeerNode, &mOnConnectedCallback, &mOnConnectionFailureCallback);
return CHIP_NO_ERROR;
}

void StayActiveSender::HandleDeviceConnected(void * context, chip::Messaging::ExchangeManager & exchangeMgr,
const chip::SessionHandle & sessionHandle)
{
StayActiveSender * const _this = static_cast<StayActiveSender *>(context);
VerifyOrDie(_this != nullptr);

CHIP_ERROR err = _this->SendStayActiveCommand(exchangeMgr, sessionHandle);
if (CHIP_NO_ERROR != err)
{
ChipLogError(ICD, "Failed to send stay active command");
chip::Platform::Delete(_this);
}
}

void StayActiveSender::HandleDeviceConnectionFailure(void * context, const chip::ScopedNodeId & peerId, CHIP_ERROR err)
{
StayActiveSender * const _this = static_cast<StayActiveSender *>(context);
VerifyOrDie(_this != nullptr);
ChipLogError(ICD, "Failed to establish CASE for stay active command with error '%" CHIP_ERROR_FORMAT "'", err.Format());
chip::Platform::Delete(_this);
}
107 changes: 107 additions & 0 deletions examples/fabric-admin/commands/common/StayActiveSender.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/*
*
* Copyright (c) 2024 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 <stddef.h>

#include <app/InteractionModelEngine.h>
#include <lib/core/ScopedNodeId.h>
#include <messaging/ExchangeMgr.h>

/**
* @brief StayActiveSender contains all the data and methods needed for active period extension of an ICD client.
*
* Lifetime of instance of StayActiveSender is entirely self managed.
*/
class StayActiveSender
{
private:
// Ideally StayActiveSender would be a private constructor, unfortunately that is not possible as Platform::New
// does not have access to private constructors. As a workaround we have defined this private struct that can
// be forwarded by Platform::New that allows us to enforce that the only way StayActiveSender is constructed is
// if SendStayActiveCommand is called.
struct ConstructorOnlyInternallyCallable
{
};

public:
using OnDoneCallbackType = std::function<void(uint32_t promisedActiveDurationMs)>;

/**
* @brief Attempts to send a StayActiveRequest command
*
* @param[in] stayActiveDurationMs StayActiveRequest command parameter.
* @param[in] peerNode Peer node we sending StayActiveRequest command to
* @param[in] engine Interaction Model Engine instance for sending command.
* @param[in] onDone Upon this function returning success, it is expected that onDone will be called after we
* have successfully recieved a response
*
* @return CHIP_ERROR CHIP_NO_ERROR on success, or corresponding error code.
*/
static CHIP_ERROR SendStayActiveCommand(uint32_t stayActiveDurationMs, const chip::ScopedNodeId & peerNode,
chip::app::InteractionModelEngine * engine, OnDoneCallbackType onDone);

// Ideally this would be a private constructor, unfortunately that is not possible as Platform::New does not
// have access to private constructors. As a workaround we have defined a private struct that can be forwarded
// by Platform::New that allows us to enforce that the only way this is constructed is if SendStayActiveCommand
// is called.
StayActiveSender(const ConstructorOnlyInternallyCallable & _, uint32_t stayActiveDurationMs,
const chip::ScopedNodeId & peerNode, chip::app::InteractionModelEngine * engine, OnDoneCallbackType onDone);

private:
/**
* @brief Sets up a CASE session with the peer to extend the client's active period with that peer.
* Returns error if we did not even manage to kick off a CASE attempt.
*/
CHIP_ERROR EstablishSessionToPeer();

// CASE session callbacks
/**
*@brief Callback received on successfully establishing a CASE session in order to keep the 'lit icd device' active
*
* @param[in] context - context of the client establishing the CASE session
* @param[in] exchangeMgr - exchange manager to use for the re-registration
* @param[in] sessionHandle - session handle to use for the re-registration
*/
static void HandleDeviceConnected(void * context, chip::Messaging::ExchangeManager & exchangeMgr,
const chip::SessionHandle & sessionHandle);
/**
* @brief Callback received on failure to establish a CASE session
*
* @param[in] context - context of the client establishing the CASE session
* @param[in] peerId - Scoped Node ID of the peer node
* @param[in] err - failure reason
*/
static void HandleDeviceConnectionFailure(void * context, const chip::ScopedNodeId & peerId, CHIP_ERROR err);

/**
* @brief Used to send a stayActive command to the peer
*
* @param[in] exchangeMgr - exchange manager to use for the re-registration
* @param[in] sessionHandle - session handle to use for the re-registration
*/
CHIP_ERROR SendStayActiveCommand(chip::Messaging::ExchangeManager & exchangeMgr, const chip::SessionHandle & sessionHandle);

uint32_t mStayActiveDurationMs = 0;
chip::ScopedNodeId mPeerNode;
chip::app::InteractionModelEngine * mpImEngine = nullptr;
OnDoneCallbackType mOnDone;

chip::Callback::Callback<chip::OnDeviceConnected> mOnConnectedCallback;
chip::Callback::Callback<chip::OnDeviceConnectionFailure> mOnConnectionFailureCallback;
};
2 changes: 1 addition & 1 deletion examples/fabric-admin/commands/pairing/PairingCommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -464,7 +464,7 @@ void PairingCommand::OnICDRegistrationComplete(ScopedNodeId nodeId, uint32_t icd
sizeof(icdSymmetricKeyHex), chip::Encoding::HexFlags::kNullTerminate);

app::ICDClientInfo clientInfo;
clientInfo.peer_node = chip::ScopedNodeId(mICDCheckInNodeId.Value(), nodeId.GetFabricIndex());
clientInfo.peer_node = nodeId;
clientInfo.monitored_subject = mICDMonitoredSubject.Value();
clientInfo.start_icd_counter = icdCounter;

Expand Down
Loading

0 comments on commit 837e872

Please sign in to comment.